2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 // $XConsortium: CanvasRenderer.C /main/61 1996/12/03 18:21:46 rcs $
24 /* Copyright (c) 1994,1995,1996 FUJITSU LIMITED */
25 /* All Rights Reserved */
28 #define C_NodeViewInfo
35 #define C_WindowSystem
38 #define C_PixmapGraphic
43 #define C_NodeViewInfo
47 #include "Managers/WString.hh"
49 #include <utility/funcs.h>
52 #include "Attribute.h"
53 #include "CanvasRenderer.hh"
55 #include "FeatureValue.h"
57 // stylesheet spec states default leading to be 2
58 #define DEFAULT_CONTAINER_LEADING 2
60 #if defined(UseWideChars) && defined(sun) && !defined(SVR4)
61 #define mbstowcs(a,b,c) Xmbstowcs(a,b,c)
62 #define wcstombs(a,b,c) Xwcstombs(a,b,c)
65 #include <DtI/LinkMgrP.h>
68 #include <DtI/DisplayAreaP.h>
69 #include <DtI/FontI.h>
70 #include <DtI/FontAttrI.h>
71 #include <DtI/RegionI.h>
73 // information to be passed back
74 NodeViewInfo *gNodeViewInfo ;
76 // avoid HardCopy hack
77 Renderer *gRenderer = 0 ;
79 DtHelpDispAreaStruct *gHelpDisplayArea = 0;
88 struct s_entry symbols[] =
90 GRAPHIC_attr, "GRAPHIC",
91 INLGRAPHIC, "INLGRAPHIC",
100 LINEBREAK, "LINEBREAK",
106 FONTCATALOG, "FONTCATALOG",
107 FONTFAMILY, "FONTFAMILY",
108 HIGHLIGHT, "HIGHLIGHT",
119 OVERLINE, "OVERLINE",
120 STRIKETHROUGH,"STRIKETHROUGH",
121 UNDERLINE, "UNDERLINE",
124 GRAPHIC_feature,"GRAPHIC",
130 REVERSEVIDEO, "REVERSE-VIDEO",
133 POSITION, "POSITION",
145 VJUSTIFY, "VJUSTIFY",
147 THICKNESS, "THICKNESS",
150 COLFORMAT, "COLFORMAT",
151 CHARALIGN, "CHARALIGN",
152 SPANCOLS, "SPANCOLS",
153 MOREROWS, "MOREROWS",
156 FALLBACK, "FALLBACK",
161 SUBSUPER, "POSITION",
167 PAGEBREAK, "PAGEBREAK",
170 ORIENTATION, "ORIENTATION"
172 // supported features
174 // these are last resorts, hard-coded
175 const char* const CanvasRenderer::f_hcf_sans = "sans";
176 const char* const CanvasRenderer::f_hcf_serif = "*";
177 const char* const CanvasRenderer::f_hcf_mono = "*";
178 const char* const CanvasRenderer::f_hcf_symbol = "*";
180 const char* const CanvasRenderer::f_hcf_weight = "*";
181 const char* const CanvasRenderer::f_hcf_slant = "*";
182 const char* const CanvasRenderer::f_hcf_fallback = "*";
183 const int CanvasRenderer::f_hcf_size = -1;
185 static _DtCvSegment *insert_break (_DtCvSegment *container,
187 static _DtCvSegment *new_segment (unsigned long type);
188 static void insert_segment (_DtCvSegment *container, _DtCvSegment *segment);
190 #ifdef CONTAINER_DEBUG
193 print_justify (unsigned value)
198 case _DtCvJUSTIFY_LEFT:
199 rvalue = "_DtCvJUSTIFY_LEFT" ;
201 case _DtCvJUSTIFY_RIGHT:
202 rvalue = "_DtCvJUSTIFY_RIGHT" ;
204 case _DtCvJUSTIFY_CENTER:
205 rvalue = "_DtCvJUSTIFY_CENTER" ;
207 case _DtCvJUSTIFY_TOP:
208 rvalue = "_DtCvJUSTIFY_TOP" ;
210 case _DtCvJUSTIFY_BOTTOM:
211 rvalue = "_DtCvJUSTIFY_BOTTOM" ;
213 case _DtCvJUSTIFY_LEFT_CORNER:
214 rvalue = "_DtCvJUSTIFY_LEFT_CORNER" ;
216 case _DtCvJUSTIFY_LEFT_MARGIN:
217 rvalue = "_DtCvJUSTIFY_MARGIN" ;
219 case _DtCvJUSTIFY_RIGHT_CORNER:
220 rvalue = "_DtCvJUSTIFY_RIGHT_CORNER" ;
222 case _DtCvJUSTIFY_RIGHT_MARGIN:
223 rvalue = "_DtCvJUSTIFY_RIGHT_MARGIN" ;
232 CanvasRenderer::CanvasRenderer(int font_scale)
234 fBogusSymbol(gElemSymTab->intern("%BOGUS")),
235 f_font_scale(font_scale),
238 f_current_tgroup (0),
242 for ( int i=0; i < REND_SYMBOLS; i++)
243 f_symbols[symbols[i].index] = new
244 Symbol(gSymTab->intern(symbols[i].name));
246 f_sans = window_system().get_string_default("FontSans");
247 f_serif = window_system().get_string_default("FontSerif");
248 f_mono = window_system().get_string_default("FontMono");
249 f_symbol = window_system().get_string_default("FontSymbol");
250 if (! (f_sans && *f_sans)) f_sans = f_hcf_sans;
251 if (! (f_serif && *f_serif)) f_serif = f_hcf_serif;
252 if (! (f_mono && *f_mono)) f_mono = f_hcf_mono;
253 if (! (f_symbol && *f_symbol)) f_symbol = f_hcf_symbol;
255 // determine default border width
256 f_border_width = window_system().get_int_default("BorderWidth");
257 if (! f_border_width)
261 CanvasRenderer::~CanvasRenderer()
263 for (int i = 0 ; i < REND_SYMBOLS; i++)
264 delete f_symbols[i] ;
270 CanvasRenderer::initialize()
272 f_default_features = new FeatureSet ;
274 FeatureSet *font_set = new FeatureSet ;
276 font_set->add(new Feature(*f_symbols[WEIGHT], new FeatureValueString(f_hcf_weight)));
277 font_set->add(new Feature(*f_symbols[SLANT], new FeatureValueString(f_hcf_slant)));
278 font_set->add(new Feature(*f_symbols[SIZE], new FeatureValueInt(f_hcf_size)));
279 font_set->add (new Feature (*f_symbols[FALLBACK], new FeatureValueString (f_hcf_fallback)));
281 f_default_features->add(new Feature(*f_symbols[FONT], new FeatureValueFeatureSet(font_set)));
284 FeatureSet* layout = new FeatureSet;
286 layout->add(new Feature(*f_symbols[LEADING],
287 new FeatureValueInt(DEFAULT_CONTAINER_LEADING)));
289 f_default_features->add(new Feature(*f_symbols[LAYOUT],
290 new FeatureValueFeatureSet(layout)));
293 // other default features
294 FeatureSet *margin = new FeatureSet;
295 margin->add (new Feature(*f_symbols[LEFT], new FeatureValueInt (20)));
296 f_default_features->add(new Feature(*f_symbols[MARGIN],
297 new FeatureValueFeatureSet(margin)));
300 f_default_features->add(new Feature(*f_symbols[WRAP],
301 new FeatureValueString("word")));
302 f_default_features->add(new Feature(*f_symbols[BREAK],
303 new FeatureValueString("line")));
305 return f_default_features;
309 CanvasRenderer::Begin()
311 // pre document initialization...called before document is processed
312 _DtCvTopicInfo *topic = new _DtCvTopicInfo ;
314 topic->link_data = _DtLinkDbCreate() ;
315 topic->seg_list = new_segment(_DtCvCONTAINER);
316 topic->id_str = NULL ;
317 topic->mark_list = NULL ;
320 gNodeViewInfo->topic(topic); // NOTE: was after do_features...
322 f_current_container = topic->seg_list ;
323 f_current_displayable = 0 ;
326 // set up initial parameters
327 ElementFeatures features(this) ;
329 do_features(features, *f_default_features, *f_default_features,
332 f_leading_stack.push(features.layout().leading());
333 f_leading_level_stack.push(f_level);
335 setup_container(f_current_container, features);
338 have to apply the features here
343 f_stack.push (f_current_container);
347 CanvasRenderer::End()
349 // post processing...called after document ends
350 #ifdef HIERARCHY_DEBUG
351 void print_hierarchy(_DtCvTopicInfo*);
352 print_hierarchy(gNodeViewInfo->topic());
355 while (f_leading_level_stack.entries())
356 f_leading_level_stack.pop();
357 while (f_leading_stack.entries())
358 f_leading_stack.pop();
361 static unsigned is_literal = 0 ;
363 // returns non-zero value if element is to be ignored
365 CanvasRenderer::BeginElement(const Element &element,
366 const FeatureSet &local,
367 const FeatureSet &complete,
368 const FeatureSet &parentComplete)
370 // at this point, f_current_container contains the
371 // parent of the element we are about to process
373 #ifdef BEGIN_ELEMENT_DEBUG
374 cerr << '<' << element.gi() << '>' << endl;
377 assert(f_current_container->type == _DtCvCONTAINER);
379 // have to do some VCC counting here
383 cerr << element.gi() << ": \t" << local << endl;
384 cerr << element.gi() << "=>\t" << complete << endl;
387 // now process styles
389 f_fstack.push (f_font);
390 f_stack.push(f_current_container);
391 f_link_stack.push (f_link_idx);
392 f_tgroup_stack.push (f_current_tgroup);
395 cerr << "pushed link_index: " << f_link_idx << endl;
398 #ifdef DEBUG_USE_NAMES
399 _DtCvSegment *hold_segment = f_current_container ;
402 ElementFeatures features(this) ;
404 do_features(features, local, complete, f_symbols);
406 if (features.ignore()) {
407 if (f_tgroup_stack.entries()) f_tgroup_stack.pop();
408 if (f_link_stack.entries()) f_link_stack.pop();
409 if (f_stack.entries()) f_stack.pop();
410 if (f_subsuper_stack.entries()) f_subsuper_stack.pop();
412 return features.ignore();
417 if (features.ignore_linebreak(False)) {
418 // disable linebreak features beforehand here if linebreak
419 // should be ignored for this element
421 if (features.prefix().linebreak() & LINEBREAK_BEFORE)
422 features.prefix().linebreak(
423 features.prefix().linebreak() & ~LINEBREAK_BEFORE);
425 if (features.suffix().linebreak() & LINEBREAK_AFTER)
426 features.suffix().linebreak(
427 features.suffix().linebreak() & ~LINEBREAK_AFTER);
429 features.linebreak(LINEBREAK_NONE);
433 SegClientData scd(_DtCvSTRING);
435 scd.hilite_type(features.highlight().overline() |
436 features.highlight().strikethrough() |
437 features.highlight().underline());
438 UAS_String& bg_color(features.highlight().bg_color());
439 UAS_String& fg_color(features.highlight().fg_color());
440 if ((char*)bg_color && *(char*)bg_color)
441 scd.bg_color(strdup((char*)bg_color));
442 if ((char*)fg_color && *(char*)fg_color)
443 scd.fg_color(strdup((char*)fg_color));
445 f_scd_stack.push(new SegClientData(scd));
448 f_subsuper_stack.push(features.subsuper());
450 if (features.table() == NULL && f_table_stack.entries()) {
451 // semantics: f_table_stack.top should always be the current.
452 // need special care on the other end as well.
453 f_table_stack.push(f_table_stack.top());
456 f_table_stack.push(features.table());
458 if (features.layout().has_layout(False) &&
459 current_leading() != features.layout().leading())
461 f_leading_stack.push(features.layout().leading());
462 f_leading_level_stack.push(f_level);
465 // get info on special olias stuff like links etc
466 handle_olias_attributes(features, element,
467 local, complete, parentComplete);
469 // if we are not already in a link, see if we start one
470 if (f_link_idx == -1)
472 f_link_idx = features.link_idx();
475 if (features.tgroup())
477 _DtCvSegment *tableseg = new_segment(_DtCvTABLE);
479 // NOTE: have to delete this guy when he pops out the other end !
480 f_current_tgroup = features.tgroup();
481 f_current_tgroup->set_segment(tableseg);
483 // associate tgroup with the surrounding table
484 f_current_tgroup->table(f_table_stack.top());
486 if (f_current_tgroup->table() &&
487 f_current_tgroup->table()->frame() != TableDefn::table_frame_none)
489 _DtCvSegment* former_current_container = f_current_container;
491 // NOTE: the purpose of the new container is just for
492 // drawing a border around a tgroup
493 f_current_container = create_container(f_current_container);
495 setup_cascaded_tgroup_container(former_current_container,
496 f_current_container);
499 insert_segment(f_current_container, tableseg);
503 if (features.col_format()) {
506 ColFormat *colf = features.col_format();
507 fprintf(stderr, "(DEBUG) ColFormat justify=%d, cols=%d, name=\"%s\", width=%d\n",
508 colf->justify(), colf->cols(), colf->name(), colf->width());
511 f_current_tgroup->add (features.col_format());
514 if (features.row()) {
515 f_current_tgroup->add_row(features.row());
518 if (features.requires_container(False) ||
519 (features.prefix().text() && features.prefix().requires_container(True)) ||
520 (features.suffix().text() && features.suffix().requires_container(True)))
523 if (features.cell().has_cell())
525 f_current_container = create_container (NULL);
527 ColDefn* coldef = new ColDefn(f_current_container, NULL,
528 features.cell().spanrows(),
529 features.cell().colref(),
530 features.cell().colstart(),
531 features.cell().colend(),
532 features.cell().justify(),
533 features.cell().vjustify(),
534 features.cell().colsep(),
535 features.cell().rowsep(),
536 features.cell().char_align());
538 f_current_tgroup->add(coldef);
542 f_current_container = create_container(f_current_container);
543 setup_container (f_current_container, features);
547 #ifdef CONTAINER_DEBUG
548 cerr << "Container: " <<
549 "\tjustify: " << print_justify(f_current_container->handle.container.justify) <<
550 "\tvjustify: " << print_justify(f_current_container->handle.container.vjustify) <<
551 "\torient: " << print_justify(f_current_container->handle.container.orient) <<
552 "\tvorient: " << print_justify(f_current_container->handle.container.vorient) <<
553 "\tflow: " << f_current_container->handle.container.flow <<
557 f_current_container->handle.container.id = features.locator();
559 if (f_link_idx != -1)
561 f_current_container->link_idx = f_link_idx ;
562 f_current_container->type |= _DtCvHYPER_TEXT ;
568 // may have to build a marker segment
569 if (features.locator())
571 _DtCvSegment *marker = new_segment (_DtCvMARKER);
572 marker->handle.marker = features.locator();
573 insert_segment (f_current_container, marker);
576 const char *font = features.font();
578 f_font = features.font();
581 // NOTE: pagebreak implicitly adds a linebreak before the pagebreak.
582 if (features.pagebreak() & PAGEBREAK_BEFORE) {
583 insert_break (f_current_container, _DtCvNEW_LINE);
584 insert_break (f_current_container, _DtCvPAGE_BREAK);
586 else if (features.linebreak() & LINEBREAK_BEFORE) {
587 insert_break (f_current_container, _DtCvNEW_LINE);
590 // check for prefix text, because if there is no text, then we are
591 // not really doing a prefix, and we just ignore it...possible
592 // exception, if an <HR> is required as a prefix item
594 if (features.prefix().text())
596 _DtCvSegment *container = f_current_container ;
598 if (features.prefix().requires_container(True))
600 const char *font = f_font ;
601 container = create_container (f_current_container);
602 setup_container (container, features.prefix(), True);
604 #ifdef CONTAINER_DEBUG
605 cerr << "Prefix Container: " <<
606 "\tjustify: " << f_current_container->handle.container.justify <<
607 "\tvjustify: " << f_current_container->handle.container.vjustify <<
608 "\torient: " << f_current_container->handle.container.orient <<
609 "\tvorient: " << f_current_container->handle.container.vorient <<
610 "\tflow: " << f_current_container->handle.container.flow <<
613 // create a container for the element content
614 f_current_container = create_container(f_current_container);
617 if (features.prefix().linebreak() & LINEBREAK_BEFORE)
618 insert_break (container, _DtCvNEW_LINE);
620 const char *font = features.prefix().font() ;
621 if (font == NULL || *font == '\0')
625 _DtCvSegment *segment = insert_string (container,
627 features.prefix().text(),
628 strlen(features.prefix().text()),
631 // indicate that this is added information
632 segment->type |= _DtCvAPP_FLAG1 ;
634 if (features.prefix().requires_container(True))
635 f_current_displayable = 0;
637 if (features.prefix().linebreak() & LINEBREAK_AFTER) {
638 if (! features.prefix().ignore_linebreak(True))
639 segment->type |= _DtCvNEW_LINE ;
642 else if (features.prefix().linebreak() & LINEBREAK_AFTER) {
643 if (! features.prefix().ignore_linebreak(True))
644 insert_break(f_current_container, _DtCvNEW_LINE);
647 // do graphics handling
648 if (features.graphic())
650 _DtCvSegment *grseg = features.graphic();
651 insert_segment(f_current_container, grseg);
652 grseg->link_idx = features.link_idx();
654 if (f_current_displayable)
655 f_current_displayable->next_disp = grseg;
656 f_current_displayable = grseg;
659 // I have no idea what the next 2 lines are intended for.
660 // Why should prefix's linebreak take effect on the element's
661 // flow-break? --- kamiya@chistech.com
662 if (features.prefix().linebreak() & LINEBREAK_AFTER)
663 grseg->type |= _DtCvNEW_LINE ;
667 PartialElementFeatures *suffixFeatures = 0;
668 if (features.suffix().text())
670 // have to stack this guy and add it to the data during
672 suffixFeatures = new PartialElementFeatures(features.suffix());
674 if ((features.linebreak() & LINEBREAK_AFTER) ||
675 (features.pagebreak() & PAGEBREAK_AFTER))
677 // Add linebreak/pagebreak info to suffix; create empty suffix
679 if (suffixFeatures == 0)
680 suffixFeatures = new PartialElementFeatures(this);
682 // if our element had a linebreak after, then include it in the suffix
683 // while preserving potential suffix linebreak settings.
684 if (features.linebreak() & LINEBREAK_AFTER)
685 suffixFeatures->linebreak(suffixFeatures->linebreak() |
688 // if our element had a pagebreak after, then include it in the suffix;
689 // suffixes cannot have pagebreaks, so don't worry about preserving.
690 if (features.pagebreak() & PAGEBREAK_AFTER)
691 suffixFeatures->pagebreak(PAGEBREAK_AFTER);
693 f_suffixes.push (suffixFeatures);
695 is_literal = f_current_container->handle.container.type == _DtCvLITERAL;
697 if (features.xref()) {
700 if (g_xref_subsection && window_system().dtinfo_font()) {
702 extern UAS_String f_dtinfo_font_name;
704 UAS_String swapped_out = f_font;
705 f_font = f_dtinfo_font_name;
711 _data(buf, 2, False);
713 f_font = swapped_out;
717 _data(features.xref(), strlen(features.xref()), False);
720 return 0 ; // not do not ignore content
724 CanvasRenderer::EndElement(const Symbol& /*name*/)
726 #ifdef END_ELEMENT_DEBUG
727 cerr << "</" << name << '>' << endl;
730 // take care of suffix stuff here
731 PartialElementFeatures *suffix = f_suffixes.pop();
737 _DtCvSegment *container = f_current_container ;
739 if (suffix->requires_container(True))
741 container = create_container (f_current_container);
742 setup_container (container, *suffix, True);
746 if (! suffix->ignore_linebreak(True)) {
747 if (suffix->linebreak() & LINEBREAK_BEFORE) {
748 insert_break (container, _DtCvNEW_LINE);
752 const char *font = suffix->font() ;
753 if (font == NULL || *font == '\0')
756 _DtCvSegment *segment = insert_string (container,
759 strlen(suffix->text()),
762 // indicate that this is added information
763 segment->type |= _DtCvAPP_FLAG1 ;
765 if (suffix->linebreak() & LINEBREAK_AFTER) {
766 segment->type |= _DtCvNEW_LINE ;
769 if (suffix->requires_container(True))
770 f_current_displayable = 0;
772 else if (suffix->linebreak() & LINEBREAK_AFTER)
774 // Element had a LINEBREAK_AFTER
776 if (f_current_displayable != 0)
778 f_current_displayable->type |= _DtCvNEW_LINE ;
782 insert_break (f_current_container, _DtCvNEW_LINE);
786 if (suffix->pagebreak() & PAGEBREAK_AFTER) {
787 // Put page break after suffix segment.
788 // NOTE: insert linebreak first if not already added.
789 if (!(suffix->linebreak() & LINEBREAK_AFTER))
790 insert_break (f_current_container, _DtCvNEW_LINE);
791 insert_break (f_current_container, _DtCvPAGE_BREAK);
796 // pop the stacks, returning state to that of current element
797 f_font = f_fstack.pop();
798 f_current_container = f_stack.pop ();
799 f_link_idx = f_link_stack.pop();
800 if (f_scd_stack.top())
801 delete f_scd_stack.pop();
802 if (f_subsuper_stack.entries())
803 f_subsuper_stack.pop();
805 // pop the table stack
806 // if the table that we pop is not the one we are working on, then
807 // we have finished with the current table, and can build it then
808 // dispose of the memory used
810 TGDefn *next_tgroup = f_tgroup_stack.pop();
812 if (f_current_tgroup != next_tgroup)
814 // convert the data we have accumulated into the _DtCvTable
815 // segment that represents this table
816 f_current_tgroup->build();
817 delete f_current_tgroup ;
819 f_current_tgroup = next_tgroup ;
821 if (f_table_stack.entries()) {
822 TableDefn* table = f_table_stack.pop();
824 if (f_table_stack.entries() == 0 || table != f_table_stack.top())
829 if (f_leading_stack.entries() && f_leading_level_stack.entries())
831 if (f_leading_level_stack.top() == f_level)
833 f_leading_stack.pop();
834 f_leading_level_stack.pop();
842 CanvasRenderer::data(const char *data, unsigned int size)
844 _data(data, size, True);
848 CanvasRenderer::_data(const char *data, unsigned int size, Boolean count_vcc)
850 _DtCvSegment *segment ;
855 cerr << "literal: " << data << endl;
857 segment = insert_literal(f_current_container, f_font, data, size);
861 segment = insert_string (f_current_container,
862 f_font, data, size, count_vcc);
865 if (f_link_idx != -1)
867 segment->link_idx = f_link_idx ;
868 segment->type |= _DtCvHYPER_TEXT ;
870 cerr << "data:( " << f_link_idx << ") " << data << endl;
876 CanvasRenderer::handle_olias_attributes(ElementFeatures &features,
877 const Element &element,
878 const FeatureSet & /* local */,
879 const FeatureSet &complete,
880 const FeatureSet & /*parentComplete*/
883 // check for specific olias attributes
885 // NOTE: more efficient to iterate over attributes than to check each
886 // attribute on every element (when I have time) - jbm
888 const Attribute *olxref =
889 element.get_olias_attribute(gSymTab->intern("OL-XREF"));
891 UAS_String locator = olxref->value();
893 UAS_Pointer<UAS_Common> target =
894 gNodeViewInfo->node_ptr()->create_relative(locator);
897 extern char* g_mmdb_section_label;
900 if (g_mmdb_section_label && *g_mmdb_section_label)
901 title = g_mmdb_section_label;
903 title = target->title();
905 if ((char*)title && *(char*)title)
906 features.xref(strdup((char*)title));
909 cerr << '<' << element.gi() << " xref=" << (char*)locator << '>'
910 << " target=" << (char*) (char*)target->id() << endl;
915 /* -------- Locators -------- */
916 const Attribute *locator = element.get_olias_attribute(*f_symbols[OLID]);
920 cerr << '<' << element.gi() << " locator=" << locator->value() << '>' << endl;
922 const char *locator_value = locator->value();
924 // Need to place the locator value as an ID in the Container
925 features.locator (strdup (locator_value));
930 /* -------- Links -------- */
931 const Attribute *olidref = element.get_olias_attribute(*f_symbols[OLIDREF]);
934 // enter this segment into the link db
936 UAS_String locator = (char*)olidref->value();
938 if ((char*)locator && *(char*)locator && gNodeViewInfo) {
940 // We should not really use gNodeViewInfo. CanvasRenderer should
941 // a member of type UAS_Pointer<UAS_Common>
943 UAS_Pointer<UAS_Common> target =
944 gNodeViewInfo->node_ptr()->create_relative(locator);
946 if (target) // create link only when resolved
948 // hack - currently, a hint of 0 is a hypertext link and a hint
949 // of 1 is a graphic. this should really be co-ordinated with
950 // the constants used by the Canvas
954 gNodeViewInfo->topic()->link_data, // link db
956 (char *)(olidref->value()), // spec
957 _DtCvLinkType_AppDefine, // type
964 cerr << "idref: " << olidref->value() << " --> " << features.link_idx() << endl;
967 /* -------- see if it is remote -------- */
969 // Can we mark this anymore?
972 const Attribute *remote =
973 element.get_olias_attribute(*f_symbols[REMOTE]);
976 // keep track of it somehow
977 // remote is only used to check for valid links at initial display
978 // time and is not used at actual link following time
979 ON_DEBUG(cerr << "remote link: " << b_node->target() << endl);
980 b_node->remote_target(true);
983 cerr << "link (" << b_node->target() << ") placed on: " << (void*)b_node
989 /* -------- Graphics -------- */
991 const Attribute *grattr =
992 element.get_olias_attribute(*f_symbols[GRAPHIC_attr]);
996 const Feature *graphic_display_type =
997 complete.deep_lookup("GRAPHIC", "ALIGN", 0);
1000 cerr << "GRAPHIC" << endl;
1002 cerr << "Graphic( " << element.gi() << "): (" ;
1003 if (graphic_display_type)
1004 cerr << *graphic_display_type ;
1007 cerr << ")" << endl;
1009 cerr << "graphic id: " << grattr->value() << endl;
1013 const char *graphicid = grattr->value();
1014 UAS_Pointer<Graphic> gr(graphics_mgr().get(gNodeViewInfo->node_ptr(), graphicid));
1015 PixmapGraphic *graphic = gr->graphic();
1017 gNodeViewInfo->add_graphic (gr); // preserve the Graphic and Pixmap objects
1019 // inform the PixmapGraphic that we are going to keep its pixmap
1020 //graphic->set_type (PixmapGraphic::PRESERVE);
1022 // Set up DtHelp graphic representation
1023 DtHelpGraphicStruct *pGS ;
1024 _DtHelpDARegion *pReg ;
1026 pGS = new DtHelpGraphicStruct ;
1027 pReg = new _DtHelpDARegion ;
1029 pGS->pix = graphic->pixmap();
1030 pGS->width = graphic->width() ;
1031 pGS->height = graphic->height();
1033 pGS->pixels = NULL ;
1034 pGS->num_pixels = 0 ;
1036 #ifdef GRAPHIC_DEBUG
1037 cerr << "pixmap ( " << pGS->width << ", " << pGS->height <<
1038 ") is: " << (void*)pGS->pix << " ==>" << (unsigned)pGS->pix << endl;
1041 pReg->inited = True ;
1042 pReg->type = _DtHelpDAGraphic ;
1043 pReg->handle = (_DtCvPointer)pGS ;
1045 _DtCvSegment *segment = new_segment (_DtCvREGION);
1046 segment->handle.region.info = (_DtCvPointer)pReg ;
1047 segment->handle.region.width = pGS->width ;
1048 segment->handle.region.height = pGS->height ;
1049 segment->handle.region.ascent = -1 ;
1051 SegClientData scd(_DtCvREGION);
1052 scd.GraphicHandle((void*)(Graphic*)gr);
1053 // for detaching purposes
1054 segment->client_use = new SegClientData(scd);
1056 #ifdef GRAPHIC_TRAVERSAL
1057 // if graphic is detachable, then it must be traversible
1058 // hack - currently, a hint of 0 is a hypertext link and a hint
1059 // of 1 is a graphic. this should really be co-ordinated with
1060 // the constants used by the Canvas
1061 segment->type |= _DtCvHYPER_TEXT ;
1063 _DtLinkDbAddLink (gNodeViewInfo->topic()->link_data, // link_db
1065 grattr->value(), // spec
1066 _DtCvLinkType_AppDefine, // type
1071 // place this segment into our structure for later insertion
1072 // into the Canvas segment tree
1073 features.graphic (segment);
1081 // now see if style sheet wants it inlined
1082 const Feature *graphic_display_type =
1083 complete.deep_lookup("GRAPHIC", "ALIGN", 0);
1084 #ifdef IGRAPHIC_DEBUG
1085 cout << "Graphic( " << element.gi() << "): (" ;
1086 if (graphic_display_type)
1087 cout << *graphic_display_type ;
1090 cout << ")" << endl;
1093 if (graphic_display_type &&
1094 !strcasecmp("inline", *graphic_display_type->value()))
1098 // NOTE: there may be tree problems, because graphic objects have no
1099 // content, and it looks as though the tag was empty, so the tree may be
1100 // built wrong after processing a graphic (especially an inline
1101 // graphic). We may have to drop a branch to put this on?
1103 // see if it is an ismap graphic
1104 const Attribute *ismap = element.get_olias_attribute(*f_symbols[ISMAP]);
1106 const char *graphicid = grattr->value();
1107 Pointer<Graphic> gr(graphics_mgr().get(gNodeViewInfo->node_ptr(), graphicid));
1108 PixmapGraphic *graphic = gr->graphic();
1110 if (graphic->pixmap() != XtUnspecifiedPixmap)
1112 gNodeViewInfo->add_graphic(gr);
1113 #ifdef TML_NO_THIS_ASSIGNMENT
1114 model* to_model = f_current_node->get_model();
1115 igfxnode *ignode = new(to_model) igfxnode(to_model);
1117 igfxnode *ignode = new igfxnode(to_model);
1120 ignode->set_ismap();
1121 ignode->set_graphic_handle((Graphic*)gr);
1122 ignode->set_graphic_dimensions(graphic->width(),
1124 f_current_node->connect_node(ignode, f_connect_dir);
1125 f_current_node = ignode ;
1126 f_connect_dir = n_right ;
1132 // This routine puts the graphic as a child of a child of the
1134 // when we exit, current node is the new bnode, but connect dir is
1135 // to the right in case there are siblings.
1137 #ifdef TML_NO_THIS_ASSIGNMENT
1138 model* to_model = f_current_node->get_model();
1139 node *current_node = new(to_model) bnode(to_model);
1141 node *current_node = new bnode(to_model);
1143 b_node->connect_node(current_node, n_down);
1144 current_node->vcc(f_vcc) ;
1146 node_dir connect_dir = n_down ;
1148 // space above graphic
1150 const Feature *spacefp = complete.deep_lookup(f_symbols[MARGIN],
1156 spacing = point2pixel(*spacefp->value());
1158 model *the_model = current_node->get_model();
1159 #ifdef TML_NO_THIS_ASSIGNMENT
1160 space_node *spnode = new (the_model) space_node(spacing, the_model);
1162 space_node *spnode = new space_node(spacing, the_model);
1164 current_node->connect_node(spnode, connect_dir);
1168 const char *graphicid = grattr->value();
1170 // create a gnode with one blank, so we have somewhere to attach marks
1171 #ifdef TML_NO_THIS_ASSIGNMENT
1172 gnode *new_gnode = new (the_model) gnode(the_model);
1174 gnode *new_gnode = new gnode(the_model);
1176 new_gnode->vcc(f_vcc);
1178 wchar_t tml_blankStr[2];
1179 *tml_blankStr = (wchar_t)' ';
1180 *(tml_blankStr + 1) = (wchar_t)'\0';
1181 new_gnode->attach_data(tml_blankStr,1);
1183 new_gnode->attach_data(" ",1);
1185 spnode->connect_node(new_gnode, n_right);
1188 Pointer<Graphic> gr(graphics_mgr().get(gNodeViewInfo->node_ptr(), graphicid));
1189 PixmapGraphic *graphic = gr->graphic();
1191 if (graphic->pixmap() != XtUnspecifiedPixmap)
1193 gNodeViewInfo->add_graphic(gr);
1195 #ifdef TML_NO_THIS_ASSIGNMENT
1196 gfxnode *new_gfxnode = new (the_model) gfxnode(the_model);
1198 gfxnode *new_gfxnode = new gfxnode(the_model);
1201 new_gnode->connect_node(new_gfxnode, n_right);
1204 // NOTE: passing in REAL Graphic object
1205 // this is ok because it is tracked via the node_view_info
1206 new_gfxnode->set_graphic_handle((Graphic*)gr);
1207 new_gfxnode->set_graphic_dimensions(graphic->width(),
1209 new_gfxnode->vcc(f_vcc);
1211 // insert another blank to attach end of marks
1212 #ifdef TML_NO_THIS_ASSIGNMENT
1213 gnode *tgnode = new (the_model) gnode(the_model);
1215 gnode *tgnode = new gnode(the_model);
1217 new_gfxnode->connect_node(tgnode, n_right);
1219 tgnode->attach_data(tml_blankStr,1);
1221 tgnode->attach_data(" ", 1);
1223 current_node = tgnode ;
1228 sprintf(buf, "Graphic \"%s\" unavailable", graphic);
1229 #ifdef TML_NO_THIS_ASSIGNMENT
1230 new_gnode = new (the_model) gnode(the_model);
1232 new_gnode = new gnode(the_model);
1234 new_gnode->vcc(f_vcc);
1236 wchar_t* buffer = new wchar_t[ strlen(buf) + 1 ];
1237 int nc = mbstowcs(buffer, buf, strlen(buf) + 1);
1239 new_gnode->attach_data(buffer, nc);
1242 new_gnode->attach_data(buf, strlen(buf));
1244 spnode->connect_node(new_gnode, n_right);
1245 current_node = new_gnode;
1247 // more spacing at end of graphic
1248 #ifdef TML_NO_THIS_ASSIGNMENT
1249 spnode = new (the_model) space_node(spacing, the_model);
1251 spnode = new space_node(spacing, the_model);
1254 current_node->connect_node(spnode, n_right);
1256 // set current node to child of bnode so that EndElement knows that node
1257 // had content, and sets the next node to be connected to the right
1259 f_current_node = b_node->get_node(n_down) ;
1260 f_connect_dir = n_right ;
1266 // Terms must come last, otherwise vcc will be screwed up for above items
1268 /* -------- Terms -------- */
1269 const Attribute *terms = element.get_olias_attribute(*f_symbols[TERMS]);
1273 const char *p = terms->value();
1276 int mb_len = mblen(p, MB_CUR_MAX);
1277 assert( mb_len > 0 );
1279 const unsigned char ch = (unsigned char)*p++;
1280 if (ch == ' ' || // space
1281 ch == '\t' || // tab
1282 ch == '\n' || // newline
1294 if (!((*p == ' ') || // space
1295 (*p == ' ') || // tab
1296 (*p == '\n') || // newline
1297 (*p == (char)0xA0))) // nbsp
1310 insert_break (_DtCvSegment *container, unsigned long type)
1312 _DtCvSegment *segment = new_segment (_DtCvNOOP);
1313 segment->type |= type;
1314 insert_segment (container, segment) ;
1319 CanvasRenderer::setup_cascaded_tgroup_container(_DtCvSegment* parent,
1320 _DtCvSegment* child)
1322 if (! (parent && child))
1324 if (! (parent->type & _DtCvCONTAINER && child->type & _DtCvCONTAINER))
1327 // orient,...,flow (controller specific) are irrelevant
1328 child->handle.container.type = parent->handle.container.type;
1329 child->handle.container.leading = parent->handle.container.leading;
1330 child->handle.container.fmargin = 0;
1331 child->handle.container.rmargin = 0;
1332 child->handle.container.tmargin = 0;
1333 child->handle.container.bmargin = 0;
1334 child->handle.container.bdr_info = parent->handle.container.bdr_info;
1335 child->handle.container.justify = _DtCvINHERIT;
1336 child->handle.container.vjustify = _DtCvINHERIT;
1338 TableDefn::table_frame_t frame = f_current_tgroup->table()->frame();
1341 case TableDefn::table_frame_top:
1342 child->handle.container.border = _DtCvBORDER_TOP;
1344 case TableDefn::table_frame_bottom:
1345 child->handle.container.border = _DtCvBORDER_BOTTOM;
1347 case TableDefn::table_frame_topbot:
1348 child->handle.container.border = _DtCvBORDER_HORZ;
1350 case TableDefn::table_frame_sides:
1351 child->handle.container.border = _DtCvBORDER_VERT;
1353 case TableDefn::table_frame_all:
1355 child->handle.container.border = _DtCvBORDER_FULL;
1361 CanvasRenderer::setup_cascaded_container(_DtCvSegment*)
1365 CanvasRenderer::create_cascaded_container(_DtCvSegment*)
1372 new_segment(unsigned long type)
1374 _DtCvSegment *segment = new _DtCvSegment ;
1376 { // zero-out fields
1377 unsigned size = sizeof(segment->handle);
1378 //cerr << "Handle size = " << size << endl;
1379 char *p = (char *)&(segment->handle) ;
1380 for (int i = 0; i < size; i++, p++)
1384 segment->type = type ;
1385 segment->link_idx = -1 ;
1386 segment->next_seg = NULL ;
1387 segment->next_disp = NULL ;
1388 segment->client_use = NULL ;
1389 segment->internal_use = NULL ;
1393 case _DtCvCONTAINER:
1394 segment->handle.container.id = 0 ;
1395 segment->handle.container.type = _DtCvDYNAMIC ;
1396 segment->handle.container.border = _DtCvBORDER_NONE ;
1397 segment->handle.container.justify = _DtCvJUSTIFY_LEFT ;
1398 segment->handle.container.vjustify= _DtCvJUSTIFY_TOP;
1399 segment->handle.container.orient = _DtCvJUSTIFY_LEFT_CORNER ;
1400 segment->handle.container.vorient = _DtCvJUSTIFY_CENTER ;
1401 segment->handle.container.flow = _DtCvWRAP;
1402 segment->handle.container.percent = 0 ;
1403 segment->handle.container.leading = DEFAULT_CONTAINER_LEADING ;
1404 segment->handle.container.fmargin = 0 ;
1405 segment->handle.container.lmargin = 0 ;
1406 segment->handle.container.rmargin = 0 ;
1407 segment->handle.container.tmargin = 0 ;
1408 segment->handle.container.bmargin = 0 ;
1409 segment->handle.container.justify_char = NULL ;
1411 segment->handle.container.bdr_info.width = 1 ;
1413 segment->handle.container.bdr_info.width = 0 ;
1415 segment->handle.container.bdr_info.data = NULL ;
1416 segment->handle.container.seg_list = 0;
1421 segment->type |= _DtCvWIDE_CHAR;
1422 segment->handle.string.string = NULL;
1423 segment->handle.string.font = NULL;
1427 segment->type |= _DtCvIN_LINE;
1438 CanvasRenderer::create_container(_DtCvSegment *parent)
1440 _DtCvSegment *container = new_segment(_DtCvCONTAINER);
1444 _DtCvSegment *tseg = parent->handle.container.seg_list ;
1448 while (tseg->next_seg)
1449 tseg = tseg->next_seg ;
1451 tseg->next_seg = container ;
1454 parent->handle.container.seg_list = container ;
1458 f_current_displayable = 0 ;
1462 CanvasRenderer::insert_literal(_DtCvSegment *container,
1463 const char *font, const char *data,
1466 // We have a literal element. This has to be broken down into
1467 // individual string segments, separated by DtCvNEW_LINE segments
1469 char *start = (char *) data; // start of current substring
1472 // replace all <CR> with newlines
1473 while ((cr = strchr(start, '\015')))
1475 *cr = '\n'; // replace with newline
1477 start++ ; // advancd beyond the newline
1480 return insert_string(container, font, data, size);
1484 CanvasRenderer::insert_string (_DtCvSegment *container,
1485 const char *font, const char *data,
1486 unsigned int /*size*/, Boolean count_vcc)
1488 _DtCvSegment *seg = NULL ;
1490 char *start = (char *)data;
1493 // find the newlines, and make a string segment up to that point,
1494 // then advance our start pointer beyond that point
1496 for (; newline = strchr(start, '\n'); start = newline + 1) {
1498 seg = really_insert_string(container, font, start, (newline - start), count_vcc);
1499 _DtCvSegment *lbseg = insert_break(container, _DtCvNEW_LINE);
1501 f_current_displayable->next_disp = lbseg ;
1502 f_current_displayable = lbseg ;
1506 // at end of data now
1507 if (strlen(start) > 0)
1508 seg = really_insert_string(container, font, start, strlen(start), count_vcc);
1514 CanvasRenderer::really_insert_string (_DtCvSegment *container,
1515 const char *font, const char *data,
1516 unsigned int size, Boolean count_vcc)
1518 // put data into a string segment
1520 _DtCvSegment *strseg = new_segment(_DtCvSTRING);
1522 insert_segment (container, strseg);
1524 // set sub/super script attribute to the segment
1525 if (f_subsuper_stack.entries() &&
1526 f_subsuper_stack.top() > PartialElementFeatures::baseline) {
1528 if (f_subsuper_stack.top() == PartialElementFeatures::subscript)
1529 strseg->type |= _DtCvSUB_SCRIPT;
1530 else if (f_subsuper_stack.top() == PartialElementFeatures::superscript)
1531 strseg->type |= _DtCvSUPER_SCRIPT;
1532 #ifdef SUBSUPER_DEBUG
1534 cerr << "(WARNING) unknown value specified as sub/super script."
1539 if (f_current_displayable)
1540 f_current_displayable->next_disp = strseg ;
1542 f_current_displayable = strseg ;
1545 // calculate dthelp font index
1547 // WARNING: this routine keeps the ptr to the xlfd_spec
1548 // should be ok unless they try to delete it
1549 // as it is a const and therefore static to us
1551 /* resolve current language (order of precedence : LC_ALL,LC_TYPE,LANG) */
1553 if ((lang = getenv("LC_ALL")) == NULL)
1554 if ((lang = getenv("LC_CTYPE")) == NULL)
1555 if ((lang = getenv("LANG")) == NULL)
1558 _DtHelpGetExactFontIndex(gHelpDisplayArea, // Display Area Structure
1561 (char*) font, // xlfd_spec
1562 &ret_indx // returned index
1564 #ifdef FONT_INDEX_DEBUG
1565 cerr << " indx: " << ret_indx << " " << font << endl;
1568 strseg->handle.string.font = (_DtCvPointer)(size_t) ret_indx ;
1570 // copy data into new memory to hand over to the canvas
1571 char *string = new char[size + 1];
1572 memcpy(string, data, size);
1573 string[size] = '\0';
1575 unsigned int offset;
1577 strcmp((char*)gNodeViewInfo->node_ptr()->locale(), "ja_JP.EUC-JP") == 0)
1580 cerr << "<CR> is being processed for Japanese." << endl;
1581 cerr << "string=" << string << endl;
1583 unsigned char* strp;
1585 while (strp = (unsigned char*)strchr(string, '\015')) {
1587 cerr << "<CR> found...";
1589 unsigned char *last = NULL, *next = NULL;
1592 (char*)last >= string && *last <= (unsigned char)' ';
1595 (char*)next < string + size && *next <= (unsigned char)' ';
1598 // check for boundary violation
1599 if ((char*)last < string || (char*)next == string) {
1601 cerr << "replaced with a space" << endl;
1607 if (*last < 128 || *next < 128) { // between asciis
1609 cerr << "replaced with a space" << endl;
1615 cerr << "marked as 0x90" << endl;
1617 *strp = 0x90; // mark to be removed later (works only for EUC)
1621 char *buf = new char[size + 1], *bufp;
1623 for (bufp = buf, offset = 0; offset < size && string[offset]; offset++)
1625 unsigned char& c = (unsigned char &)string[offset];
1637 for (offset = 0; offset < size && string[offset]; offset++)
1639 char& pos = string[offset];
1640 pos = (pos != '\015') ? pos : ' ';
1642 // no need for string termination here
1645 #ifdef DEBUG_R_INPUT_STRING
1649 SegClientData scd(_DtCvSTRING);
1652 if (strseg->type & _DtCvWIDE_CHAR)
1655 WString wstring(string, size);
1656 #ifdef CRE_I18N_DEBUG
1657 fprintf(stderr, "(DEBUG) wstring=\"%s\"\n", wstring.get_mbstr());
1659 if ((wchar_t*)wstring == NULL || *(wchar_t*)wstring == 0) {
1660 strseg->type &= ~_DtCvWIDE_CHAR;
1664 string = (char*)wstring.get_wstr();
1667 else { // single font being used, do not use wchar_t
1668 strseg->type &= ~_DtCvWIDE_CHAR;
1672 // account for vcc for this string
1674 if (strseg->type & _DtCvWIDE_CHAR) {
1676 for (p = (wchar_t*)string; *p; p++) {
1677 if (*p != ' ' && *p != '\t' && *p != '\n')
1681 else { // also need to exclude nbsp
1683 for (p = (unsigned char*)string; *p; p++) {
1684 if (*p != ' ' && *p != '\t' && *p != '\n' && *p != 0xA0)
1689 // setup highlight info
1690 strseg->client_use = new SegClientData(*f_scd_stack.top());
1692 f_vcc += scd.vclen();
1693 ((SegClientData*)strseg->client_use)->vcc (scd.vcc());
1694 ((SegClientData*)strseg->client_use)->vclen(scd.vclen());
1697 strseg->handle.string.string = string ;
1701 _DtCvStringClientData* pSCD = (_DtCvStringClientData*)strseg->client_use;
1703 fprintf(stderr, "(DEBUG) vcc=%d vclen=%d, type=0x%x\n",
1704 pSCD->vcc, pSCD->vclen, pSCD->hilite_type);
1712 CanvasRenderer::setup_container(_DtCvSegment *container,
1713 PartialElementFeatures &features,
1716 const char* font = (char*)features.font();
1718 f_font = features.font();
1721 if (features.position().horiz() != _DtCvOPTION_BAD)
1723 container->handle.container.orient = features.position().horiz();
1724 container->type |= _DtCvCONTROLLER ;
1727 if (features.position().vert() != _DtCvOPTION_BAD)
1729 container->handle.container.vorient = features.position().vert();
1730 container->type |= _DtCvCONTROLLER ;
1734 if (features.layout().has_layout(affix))
1736 Layout &layout = features.layout();
1738 container->handle.container.fmargin = layout.findent();
1739 container->handle.container.lmargin = layout.lindent();
1740 container->handle.container.rmargin = layout.rindent();
1741 container->handle.container.tmargin = layout.aspace();
1742 container->handle.container.bmargin = layout.bspace();
1744 if (layout.flow() != _DtCvOPTION_BAD)
1746 // NOTE: container is not a controller just because this
1747 // flag gets set, otherwise you will see all the objects
1748 // grouped together off to one side (upper left by default)
1749 container->handle.container.type = layout.flow();
1751 if (layout.wrap() != _DtCvOPTION_BAD)
1753 container->handle.container.flow = layout.wrap();
1754 container->type |= _DtCvCONTROLLER ;
1756 if (layout.justify() != _DtCvOPTION_BAD)
1758 container->handle.container.justify = layout.justify();
1762 if (features.layout().has_layout(affix)) {
1763 container->handle.container.leading = features.layout().leading();
1765 else if (f_leading_stack.entries()) {
1766 container->handle.container.leading = f_leading_stack.top();
1769 container->handle.container.leading = DEFAULT_CONTAINER_LEADING;
1774 CanvasRenderer::setup_container(_DtCvSegment *container, ElementFeatures &features)
1776 setup_container (container, *(PartialElementFeatures*)&features, False);
1778 // for online use, set the margins for the container
1779 // when printing, the margins will be set on the form
1781 if (!window_system().printing()) {
1784 container->handle.container.fmargin += features.margin().first() ;
1785 container->handle.container.lmargin += features.margin().left() ;
1786 container->handle.container.rmargin += features.margin().right();
1787 container->handle.container.tmargin += features.margin().top();
1788 container->handle.container.bmargin += features.margin().bottom();
1792 container->handle.container.border = features.border();
1793 if (features.border_width() < 0)
1794 container->handle.container.bdr_info.width = f_border_width;
1796 container->handle.container.bdr_info.width = features.border_width();
1800 PartialElementFeatures::PartialElementFeatures(CanvasRenderer* renderer)
1804 f_pagebreak(PAGEBREAK_NONE),
1806 f_subsuper(baseline),
1809 f_orientation("portrait")
1814 PartialElementFeatures::PartialElementFeatures (PartialElementFeatures &features)
1815 : f_text (features.f_text),
1816 f_font (features.f_font),
1817 f_highlight (features.f_highlight),
1818 f_linebreak (features.f_linebreak),
1819 f_pagebreak (features.f_pagebreak),
1820 f_position (features.f_position),
1821 f_layout (features.f_layout),
1822 f_graphic (features.f_graphic),
1823 f_subsuper (features.f_subsuper),
1824 f_ignore (features.f_ignore),
1825 f_orientation (features.f_orientation)
1830 PartialElementFeatures::~PartialElementFeatures()
1834 ElementFeatures::ElementFeatures(CanvasRenderer* renderer)
1835 : PartialElementFeatures(renderer),
1837 f_border (_DtCvBORDER_NONE),
1844 f_border_width(-1), // invalid border width
1850 ElementFeatures::~ElementFeatures()
1852 if (f_xref) free(f_xref);
1856 PartialElementFeatures::ignore_linebreak(int affix)
1858 return (layout().has_layout(affix) ||
1859 position().has_position());
1863 ElementFeatures::ignore_linebreak(int)
1865 if (prefix().text() && prefix().ignore_linebreak(True))
1868 if (suffix().text() && suffix().ignore_linebreak(True))
1871 return (PartialElementFeatures::ignore_linebreak(False) ||
1872 margin().has_margins());
1876 PartialElementFeatures::requires_container(int affix)
1878 return (layout().has_layout(affix) ||
1879 position().has_position());
1883 ElementFeatures::requires_container(int)
1885 return (PartialElementFeatures::requires_container(False) ||
1886 margin().has_margins() ||
1887 (border() != _DtCvBORDER_NONE) ||
1902 Margins::has_margins()
1904 // returns a non zero (true) value if any margin setting
1906 return f_first | f_left | f_right | f_top | f_bottom ;
1909 Layout::Layout(CanvasRenderer* renderer)
1910 : f_renderer(renderer),
1911 f_aspace (0), f_bspace (0), f_leading (-1),
1912 f_findent (0), f_rindent(0), f_lindent (0),
1913 f_flow (_DtCvOPTION_BAD),
1914 f_wrap (_DtCvOPTION_BAD),
1915 f_justify (_DtCvOPTION_BAD)
1919 Layout::Layout (Layout &layout)
1920 : f_renderer(layout.f_renderer),
1921 f_aspace (layout.f_aspace),
1922 f_bspace (layout.f_bspace),
1923 f_leading (layout.f_leading),
1924 f_findent (layout.f_findent),
1925 f_lindent (layout.f_lindent),
1926 f_rindent (layout.f_rindent),
1927 f_flow (layout.f_flow),
1928 f_wrap (layout.f_wrap),
1929 f_justify (layout.f_justify)
1934 Layout::has_layout(int affix)
1939 if (f_renderer->current_leading() != f_leading)
1943 if (f_renderer->f_level == f_renderer->f_leading_level_stack.top() ||
1944 f_renderer->current_leading() != f_leading)
1949 return f_aspace || f_bspace || f_findent || f_rindent || f_lindent ||
1950 (f_flow != _DtCvOPTION_BAD) ||
1951 (f_wrap != _DtCvOPTION_BAD) ||
1952 (f_justify != _DtCvOPTION_BAD) ;
1956 CanvasRenderer::current_leading()
1958 if (f_leading_stack.entries() == 0)
1961 return f_leading_stack.top();
1966 insert_segment (_DtCvSegment *container, _DtCvSegment *segment)
1969 if (container == segment)
1970 cerr << "ERROR: Containing ourself" << endl;
1971 cerr << (void*)container << " <-- " << (void*)segment << endl;
1973 _DtCvSegment *child =
1974 container->handle.container.seg_list ;
1978 // first data in this segment
1979 container->handle.container.seg_list = segment ;
1983 while (child->next_seg)
1984 child = child->next_seg ;
1986 child->next_seg = segment ;
1991 RowDefn::RowDefn() : f_vjustify(_DtCvOPTION_BAD), f_rowsep(CRSEP_NOT_SPECIFIED)
1996 f_columns.clearAndDestroy ();
1999 TableDefn::TableDefn(const char* frame_str, int colsep, int rowsep) :
2000 f_frame(table_frame_default), f_colsep(colsep), f_rowsep(rowsep)
2003 f_frame = string_to_token(frame_str);
2006 TableDefn::~TableDefn()
2010 TableDefn::frame(const char* frame_str)
2013 f_frame = string_to_token(frame_str);
2015 f_frame = table_frame_default;
2018 TableDefn::table_frame_t
2019 TableDefn::string_to_token(const char* frame_str)
2021 if (frame_str == NULL)
2022 return table_frame_default;
2024 table_frame_t token;
2026 if (! strcasecmp(frame_str, "none"))
2027 token = table_frame_none;
2028 else if (! strcasecmp(frame_str, "top"))
2029 token = table_frame_top;
2030 else if (! strcasecmp(frame_str, "bottom"))
2031 token = table_frame_bottom;
2032 else if (! strcasecmp(frame_str, "topbot"))
2033 token = table_frame_topbot;
2034 else if (! strcasecmp(frame_str, "sides"))
2035 token = table_frame_sides;
2036 else if (! strcasecmp(frame_str, "all"))
2037 token = table_frame_all;
2039 token = table_frame_default;
2044 TGDefn::TGDefn(_DtCvFrmtOption justify, _DtCvFrmtOption vjustify) :
2045 f_numcols (1),f_segment (0), f_justify(justify), f_vjustify(vjustify),
2046 f_colsep(CRSEP_NOT_SPECIFIED), f_rowsep(CRSEP_NOT_SPECIFIED),
2047 f_char_align('\0'), f_table(NULL)
2052 f_colformats.clearAndDestroy();
2053 f_rows.clearAndDestroy();
2057 TGDefn::add_row(RowDefn *rd)
2064 TGDefn::add (ColFormat *cf)
2067 f_colformats.append (cf);
2072 TGDefn::add (ColDefn *cd)
2074 if (f_rows.entries() > 0) {
2075 f_rows.last()->append (cd);
2080 add_id(char **cell_ids, unsigned row, unsigned number, _DtCvSegment *segment)
2082 char *id = segment->handle.container.id;
2086 sprintf(idstr,"id%d", number);
2089 segment->handle.container.id = strdup (id);
2091 if (cell_ids[row] == NULL)
2093 cell_ids[row] = strdup (id) ;
2097 char *orig = cell_ids[row] ;
2098 cell_ids[row] = new char [ strlen (orig) + 1 + strlen (id) + 1 ] ;
2099 sprintf(cell_ids[row], "%s %s", orig, id);
2104 ColFormat::ColFormat()
2105 : f_char_align ('.'),
2106 f_justify (_DtCvOPTION_BAD),
2109 f_colsep(CRSEP_NOT_SPECIFIED),
2110 f_rowsep(CRSEP_NOT_SPECIFIED)
2114 ColFormat::~ColFormat()
2121 ColFormat::name(const char *string)
2123 f_name = strdup (string);
2128 _DtCvSegment *ensure_id(_DtCvSegment *segment)
2130 static unsigned id_count = 0;
2131 // in a table, an id cannot contain a space, so if it does
2132 // we wrap it in a new container
2133 if ((segment->handle.container.id != NULL) &&
2134 strchr(segment->handle.container.id, ' '))
2136 _DtCvSegment *new_container = new_segment (_DtCvCONTAINER);
2137 new_container->handle.container.seg_list = segment ;
2138 segment = new_container ;
2141 // generate an id if the segment does not have one
2142 if (segment->handle.container.id == NULL)
2145 sprintf(buffer, "id%d", id_count++);
2146 segment->handle.container.id = strdup (buffer);
2153 TGDefn::find_format(const char *name, int* index)
2155 if (name == NULL || *name == '\0')
2158 ColFormat* format = NULL;
2160 CC_TPtrSlistIterator<ColFormat> cf_cursor (f_colformats);
2163 for (nth = 0; ++cf_cursor; nth++)
2165 if (cf_cursor.key()->name() == NULL)
2168 #ifdef TABLE_DEBUG_X
2169 cerr << "\tname: " << cf_cursor.key()->name() << endl;
2170 cerr << "\tchar: " << cf_cursor.key()->char_align() << endl;
2171 cerr << "\tjustify: " << cf_cursor.key()->justify() << endl;
2172 cerr << "\twidth: " << cf_cursor.key()->width() << endl;
2175 if (!strcmp(name, cf_cursor.key()->name())) {
2176 format = cf_cursor.key();
2181 if (format && index) // if found, return the index to the format
2192 unsigned num_cells = 0; // # of virtual cells
2193 unsigned num_rows = 0; // # of physical rows
2194 unsigned num_columns = 0; // # of physical columns
2196 // calculate the actual number of items we have to distribute
2197 // throughout the table, as well as the widest row (in terms of
2198 // number of columns)
2200 // calculate the number of rows we really have
2201 // NOTE: Here we calculate the physically accurate number of
2202 // rows, not # of <row>s. Some cells can have rowspan > 1
2203 // which means more rows may be required than # of <row>s.
2205 CC_TPtrSlistIterator<RowDefn> row_cursor(f_rows) ;
2208 for (current_row = 0; ++row_cursor; current_row++)
2210 CC_TPtrSlistIterator<ColDefn> col_cursor (row_cursor.key()->columns());
2211 while (++col_cursor)
2213 // extent the number of rows if this columns spans below
2214 // the last row calculated so far
2215 unsigned rowspan = col_cursor.key()->spanrows();
2217 unsigned potential_last_row = current_row + rowspan ;
2218 if (num_rows < potential_last_row)
2219 num_rows = potential_last_row ;
2223 fprintf(stderr, "(DEBUG) # of physical rows = %d\n", num_rows);
2226 // find out how many virtual cells we actually have, and the number
2227 // of columns in the table
2228 // NOTE: Here we calculate the physically accurate number of
2229 // columns, instead of using numcols of <tgroup>.
2231 unsigned *col_count = new unsigned[num_rows] ;
2232 for (i = 0 ; i < num_rows; i++)
2237 for (current_row = 0; ++row_cursor; current_row++)
2239 unsigned entries = row_cursor.key()->columns().entries() ;
2240 num_cells += entries ;
2242 // now find out how many columns we span
2243 CC_TPtrSlistIterator<ColDefn> col_cursor (row_cursor.key()->columns());
2246 // adding up the spans of each column in the row
2247 // if we rowspan, include our count in the spanned rows
2249 while (++col_cursor)
2251 ColDefn *col = col_cursor.key() ;
2255 if (find_format(col->colstart(), &mth)) {
2257 if (find_format(col->colend(), &nth)) {
2263 spancols += nth - mth;
2267 for (i = 0; i < col->spanrows(); i++)
2268 col_count[current_row + i] += spancols;
2272 for ( i = 0 ; i < num_rows; i++)
2273 if (num_columns < col_count[i])
2274 num_columns = col_count[i] ;
2279 fprintf(stderr, "(DEBUG) # of physical columns = %d\n", num_columns);
2280 fprintf(stderr, "(DEBUG) # of virtual cells = %d\n", num_cells);
2283 // create a grid of our table, then populate each box in the grid
2284 // we then walk the grid to build our DtCvTable structure
2286 // allocate row memory
2287 _DtCvSegment* **grid = new _DtCvSegment **[num_rows] ;
2289 // allocate column memory
2290 for (i = 0 ; i < num_rows ; i++)
2292 grid[i] = new _DtCvSegment *[num_columns] ;
2293 for (int c = 0 ; c < num_columns; c++)
2297 // allocate space in _DtCvTable for storing the segments
2298 f_segment->handle.table.cells = new _DtCvSegment* [num_rows*num_columns + 1];
2299 for (i = 0; i <= num_rows*num_columns; i++)
2300 f_segment->handle.table.cells[i] = NULL ; // initialize list
2303 if (f_colformats.entries() < num_columns) {
2304 int i, deficit = num_columns - f_colformats.entries();
2306 for (i = 0; i < deficit; i++)
2307 f_colformats.append(new ColFormat());
2310 // print warning message if num_columns exceeds # of colformat
2311 cerr << "(WARNING) # of physical cols exceeds that of colformats" << endl;
2312 cerr << "# of cols = " << num_columns << ", # of colformats = "
2313 << f_colformats.entries() << endl;
2317 // now walk the structure that we built up during parsing, and fill
2320 unsigned cell_counter = 0 ;
2322 for (current_row = 0; ++row_cursor; current_row++)
2324 CC_TPtrSlist<ColDefn> columns(row_cursor.key()->columns());
2326 int vc, kept, count = columns.entries();
2327 for (vc = 0, kept = 0; vc < count; vc++) { // iterate for virtual cells
2329 fprintf(stderr, "(vc,kept,count)=(%d,%d,%d)\n", vc, kept, count);
2334 colcell = columns.at(kept);
2337 abort(); // consider it as fatal
2343 ColFormat* msformat; // most significant format
2344 ColFormat* lsformat; // least significant format
2345 if (msformat = find_format(colcell->colstart(), &start_index)) {
2347 if (lsformat = find_format(colcell->colend(), &end_index)) {
2348 if (start_index > end_index) {
2349 int anonym = start_index;
2350 start_index = end_index;
2353 spancols += end_index - start_index;
2356 lsformat = msformat;
2358 else if (! (msformat = find_format(colcell->colref(), &start_index))) {
2359 // neither colstart nor colref are specified.
2360 // Handle implicitly later.
2365 lsformat = msformat;
2367 // make sure the segment has a valid id and add it into the
2368 // _DtCvTable list of cells
2369 _DtCvSegment *segment = ensure_id(colcell->parseg());
2370 setup_cell(segment, colcell, row_cursor.key(), msformat, lsformat);
2372 for (int i = 0 ; i < spancols; i++) {
2373 for (int j = 0; j < colcell->spanrows(); j++) {
2374 // if there's entrenchment from above rows, skip it.
2375 if (grid[current_row + j][start_index + i])
2377 grid[current_row + j][start_index + i] = segment;
2381 f_segment->handle.table.cells[cell_counter++] = segment ;
2383 columns.removeAt(kept);
2386 unsigned current_column = 0 ;
2387 count = columns.entries();
2388 for (vc = 0, kept = 0; vc < count; vc++) // iterate for virtual cells
2390 // stick the item into each grid of the table that it
2391 // occupies, including spanning rows and columns
2393 fprintf(stderr, "[vc,kept,count]=[%d,%d,%d]\n", vc, kept, count);
2397 colcell = columns.at(kept);
2405 for (i = 0; i < num_columns; i++) {
2406 if (grid[current_row][i] == NULL) {
2411 if (i == num_columns) { // all columns occupied
2416 ColFormat* msformat = f_colformats.at(start_index);
2417 ColFormat* lsformat = msformat;
2419 // make sure the segment has a valid id and add it into the
2420 // _DtCvTable list of cells
2421 _DtCvSegment *segment = ensure_id(colcell->parseg());
2423 setup_cell(segment, colcell, row_cursor.key(), msformat, lsformat);
2425 f_segment->handle.table.cells[cell_counter++] = segment ;
2427 for (i = 0; i < colcell->spanrows(); i++) {
2428 // if there's entrenchment from above rows, skip it.
2429 if (grid[current_row + i][start_index])
2431 grid[current_row + i][start_index] = segment;
2434 columns.removeAt(kept);
2437 for (int c = 0; c < num_columns; c++)
2439 if (grid[current_row][c] == NULL)
2441 _DtCvSegment* seg = ensure_id(new_segment(_DtCvCONTAINER));
2442 setup_cell(seg, NULL, row_cursor.key(), f_colformats.at(c),
2443 f_colformats.at(c));
2445 grid[current_row][c] =
2446 f_segment->handle.table.cells[cell_counter++] = seg;
2451 // temp for now deal with blank spots in the table
2453 for (r = 0 ; r < num_rows ; r++)
2454 for (unsigned c = 0; c < num_columns ; c++)
2456 if (grid[r][c] == NULL)
2459 fprintf(stderr, "(DEBUG) blank spot found in the table.\n");
2465 // look for a meaningful grid
2466 for (col = 0; col < num_columns && grid[r][col] == NULL; col++);
2468 if (col == num_columns) // not found
2472 _DtCvSegment* filler = grid[r][col];
2474 for (int i = c; i < col; i++)
2475 grid[r][i] = filler;
2480 while (grid[r][col] == NULL)
2483 _DtCvSegment* filler = grid[r][col] ;
2486 grid[r][col++] = filler ;
2491 // now create the _DtCvTable layout information
2492 _DtCvTable *table = &f_segment->handle.table ;
2494 table->num_cols = num_columns ;
2496 table->cell_ids = new char *[num_rows + 1] ;
2497 table->cell_ids[num_rows] = NULL;
2499 // walk the grid and insert the segment id information
2500 // into the cell_ids strings
2502 for (r = 0 ; r < num_rows ; r++)
2504 for (int c = 0 ; c < num_columns ; c++)
2508 // first item in row
2509 table->cell_ids[r] = strdup(grid[r][c]->handle.container.id);
2513 // subsequent items, append space separated id
2515 unsigned len = strlen (table->cell_ids[r]) + strlen (grid[r][c]->handle.container.id);
2516 char *new_ids = new char [len + 2] ;
2517 strcpy(new_ids, table->cell_ids[r]) ;
2518 strcat(new_ids, " ");
2519 strcat(new_ids, grid[r][c]->handle.container.id);
2520 delete table->cell_ids[r] ;
2521 table->cell_ids[r] = new_ids ;
2524 delete grid[r] ; // clean up column memory
2529 // now apply the formats to the _DtCvTable
2531 _DtCvFrmtOption *justify = new _DtCvFrmtOption[num_columns] ;
2532 char **col_widths = new char *[num_columns] ;
2533 char *justify_chars = new char [num_columns + 1] ;
2535 justify_chars[0] = 0 ;
2537 for (int i = 0 ; i < num_columns ; i++)
2539 justify[i] = _DtCvOPTION_BAD;
2540 col_widths[i] = NULL;
2541 justify_chars[i] = 0;
2544 ColFormat *format = f_colformats.at(i);
2546 if (format == NULL) continue;
2548 justify[i] = format->justify();
2550 sprintf(buffer, "%d", format->width());
2551 col_widths[i] = strdup(buffer);
2553 if (format->justify() == _DtCvJUSTIFY_CHAR)
2556 buf[0] = format->char_align() ;
2558 strcat(justify_chars, buf);
2561 table->col_justify = justify ;
2562 #ifdef COLSPEC_DEBUG
2563 for (i = 0; i < num_columns; i++)
2564 fprintf(stderr, "col%d=%d\n", i, table->col_justify[i]);
2566 table->col_w = col_widths ;
2567 table->justify_chars = justify_chars ;
2572 cerr << "widths: " << endl;
2573 for (int i = 0; i < num_columns; i++)
2574 cerr << table->col_w[i] << endl;
2578 #ifdef TABLE_DEBUG_X
2581 while (table->cell_ids[i])
2582 cerr << table->cell_ids[i++] << endl;
2588 #ifdef HIERARCHY_DEBUG
2590 static char* seg_type_to_string(unsigned long seg_type)
2594 case _DtCvCONTAINER:
2622 static void print_hierarchy_traversal(_DtCvSegment* seg, int depth, ostream& ostr)
2627 unsigned long seg_ptype = seg->type & _DtCvPRIMARY_MASK;
2630 for (i = 0; i < depth; ostr << ' ', i++);
2632 if (seg_ptype != _DtCvCONTAINER)
2633 ostr << seg_type_to_string(seg_ptype) << '\n';
2635 ostr << seg_type_to_string(seg_ptype);
2637 if (seg_ptype == _DtCvCONTAINER) {
2638 if (seg->handle.container.border != _DtCvBORDER_NONE)
2640 ostr << " leading=" << seg->handle.container.leading;
2643 _DtCvSegment* subordinates = seg->handle.container.seg_list;
2645 print_hierarchy_traversal(subordinates, depth+1, ostr);
2647 if (seg_ptype == _DtCvTABLE) {
2648 _DtCvTable *table = &seg->handle.table;
2649 _DtCvSegment** cells = table->cells;
2651 print_hierarchy_traversal(*cells++, depth+1, ostr);
2653 else if (seg_ptype == _DtCvSTRING) {
2654 for (i = 0; i < depth+1; ostr << ' ', i++);
2655 ostr << (char*)seg->handle.string.string << '\n';
2658 // traverse siblings
2659 _DtCvSegment* siblings;
2660 if (siblings = seg->next_seg)
2661 print_hierarchy_traversal(siblings, depth, ostr);
2664 static void print_hierarchy(_DtCvTopicInfo* topic)
2666 _DtCvSegment* top = topic->seg_list;
2670 ofstream ostr("SegmentStructure");
2671 print_hierarchy_traversal(top, depth, ostr);
2678 // colcell can be NULL where cell-related values are not taken
2681 TGDefn::setup_cell(_DtCvSegment* segment, ColDefn* colcell,
2682 RowDefn* row, ColFormat* msformat, ColFormat* lsformat)
2684 _DtCvSegment* parseg;
2686 // segment is optional, but if it's specified it'll be used
2687 // instead of colcell->parseg().
2691 parseg = colcell->parseg();
2693 if (colcell && colcell->justify() != _DtCvOPTION_BAD)
2695 parseg->handle.container.justify = colcell->justify();
2697 if (colcell->justify() == _DtCvJUSTIFY_CHAR)
2699 char charalign = '\0';
2701 if (colcell->char_align()) {
2702 charalign = colcell->char_align();
2704 else if (msformat && msformat->char_align()) {
2705 charalign = msformat->char_align();
2707 else { // always available here thanks to dtd
2708 charalign = char_align();
2711 char *align = new char[2];
2712 align[0] = charalign;
2715 // need to deallocate container.justify_char later
2716 parseg->handle.container.justify_char = align;
2719 else if (msformat && msformat->justify() != _DtCvOPTION_BAD)
2721 parseg->handle.container.justify = _DtCvINHERIT;
2723 else if (justify() != _DtCvOPTION_BAD)
2725 if (justify() == _DtCvJUSTIFY_CHAR)
2727 char charalign = '\0';
2729 if (colcell && colcell->char_align()) {
2730 charalign = colcell->char_align();
2732 else if (msformat && msformat->char_align()) {
2733 charalign = msformat->char_align();
2735 else { // always available here due to dtd
2736 charalign = char_align();
2739 char *align = new char[2];
2740 align[0] = charalign;
2743 // need to deallocate container.justify_char later
2744 parseg->handle.container.justify_char = align;
2747 parseg->handle.container.justify = justify();
2750 if (colcell && colcell->vjustify() != _DtCvOPTION_BAD) {
2751 parseg->handle.container.vjustify = colcell->vjustify();
2753 else if (row->vjustify() != _DtCvOPTION_BAD) {
2754 parseg->handle.container.vjustify = row->vjustify();
2756 else if (vjustify() != _DtCvOPTION_BAD) {
2757 parseg->handle.container.vjustify = vjustify();
2760 int col_sep = CRSEP_NOT_SPECIFIED;
2761 // colsep does not apply to the last column
2762 if (lsformat != f_colformats.last())
2764 // Precedence: col->colformat->tgroup->table
2765 if (colcell && colcell->colsep() != CRSEP_NOT_SPECIFIED) {
2766 col_sep = colcell->colsep();
2768 else if (msformat && msformat->colsep() != CRSEP_NOT_SPECIFIED) {
2769 col_sep = msformat->colsep();
2771 else if (colsep() != CRSEP_NOT_SPECIFIED) {
2774 else if (table() && table()->colsep() != CRSEP_NOT_SPECIFIED) {
2775 col_sep = table()->colsep();
2779 int row_sep = CRSEP_NOT_SPECIFIED;
2780 // rowsep does not apply to the last row
2781 if (f_rows.last() != row) {
2782 // Precedence: col->row->colformat->tgroup->table
2783 if (colcell && colcell->rowsep() != CRSEP_NOT_SPECIFIED) {
2784 row_sep = colcell->rowsep();
2786 else if (row->rowsep() != CRSEP_NOT_SPECIFIED) {
2787 row_sep = row->rowsep();
2789 else if (msformat && msformat->rowsep() != CRSEP_NOT_SPECIFIED) {
2790 row_sep = msformat->rowsep();
2792 else if (rowsep() != CRSEP_NOT_SPECIFIED) {
2795 else if (table() && table()->rowsep() != CRSEP_NOT_SPECIFIED) {
2796 row_sep = table()->rowsep();
2800 if (col_sep == CRSEP_YES && row_sep == CRSEP_YES)
2801 parseg->handle.container.border = _DtCvBORDER_BOTTOM_RIGHT;
2802 else if (col_sep == CRSEP_YES)
2803 parseg->handle.container.border = _DtCvBORDER_RIGHT;
2804 else if (row_sep == CRSEP_YES)
2805 parseg->handle.container.border = _DtCvBORDER_BOTTOM;
2807 // respect border feature of cell, do not overwrite here.