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 libraries 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" },
94 { OLIDREF, "OL-IDREF" },
100 { LINEBREAK, "LINEBREAK" },
101 { CHARSETS, "CHARSET" },
103 { BGCOLOR, "BGCOLOR" },
104 { FGCOLOR, "FGCOLOR" },
106 { FONTCATALOG, "FONTCATALOG" },
107 { FONTFAMILY, "FONTFAMILY" },
108 { HIGHLIGHT, "HIGHLIGHT" },
109 { IGNORE, "IGNORE" },
111 { MARGIN, "MARGIN" },
112 { SUFFIX, "SUFFIX" },
113 { PREFIX, "PREFIX" },
114 { PREVIEW, "PREVIEW" },
116 { TABSTOPS, "TABSTOP" },
117 { CONTENT, "CONTENT" },
119 { OVERLINE, "OVERLINE" },
120 { STRIKETHROUGH,"STRIKETHROUGH" },
121 { UNDERLINE, "UNDERLINE" },
124 { GRAPHIC_feature,"GRAPHIC" },
125 { FAMILY, "FAMILY" },
126 { WEIGHT, "WEIGHT" },
129 { CHARSET, "CHARSET" },
130 { REVERSEVIDEO, "REVERSE-VIDEO" },
133 { POSITION, "POSITION" },
136 { LAYOUT, "LAYOUT" },
137 { ASPACE, "ASPACE" },
138 { BSPACE, "BSPACE" },
139 { LEADING, "LEADING" },
140 { FINDENT, "FINDENT" },
141 { LINDENT, "LINDENT" },
142 { RINDENT, "RINDENT" },
144 { JUSTIFY, "JUSTIFY" },
145 { VJUSTIFY, "VJUSTIFY" },
146 { BORDER, "BORDER" },
147 { THICKNESS, "THICKNESS" },
150 { COLFORMAT, "COLFORMAT" },
151 { CHARALIGN, "CHARALIGN" },
152 { SPANCOLS, "SPANCOLS" },
153 { MOREROWS, "MOREROWS" },
156 { FALLBACK, "FALLBACK" },
157 { FOUNDRY, "FOUNDRY" },
159 { DISPLAY, "DISPLAY" },
160 { COLREF, "COLREF" },
161 { SUBSUPER, "POSITION" },
162 { COLSEP, "COLSEP" },
163 { ROWSEP, "ROWSEP" },
164 { TGROUP, "TGROUP" },
167 { PAGEBREAK, "PAGEBREAK" },
168 { FOOTERS, "FOOTERS" },
169 { HEADERS, "HEADERS" },
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 f_current_tgroup (0),
237 f_font_scale(font_scale),
238 fBogusSymbol(gElemSymTab->intern("%BOGUS")),
241 f_current_container(NULL),
242 f_current_displayable(NULL),
243 f_default_features(NULL)
246 for ( int i=0; i < REND_SYMBOLS; i++)
247 f_symbols[symbols[i].index] = new
248 Symbol(gSymTab->intern(symbols[i].name));
250 f_sans = window_system().get_string_default("FontSans");
251 f_serif = window_system().get_string_default("FontSerif");
252 f_mono = window_system().get_string_default("FontMono");
253 f_symbol = window_system().get_string_default("FontSymbol");
254 if (! (f_sans && *f_sans)) f_sans = f_hcf_sans;
255 if (! (f_serif && *f_serif)) f_serif = f_hcf_serif;
256 if (! (f_mono && *f_mono)) f_mono = f_hcf_mono;
257 if (! (f_symbol && *f_symbol)) f_symbol = f_hcf_symbol;
259 // determine default border width
260 f_border_width = window_system().get_int_default("BorderWidth");
261 if (! f_border_width)
265 CanvasRenderer::~CanvasRenderer()
267 for (int i = 0 ; i < REND_SYMBOLS; i++)
268 delete f_symbols[i] ;
274 CanvasRenderer::initialize()
276 f_default_features = new FeatureSet ;
278 FeatureSet *font_set = new FeatureSet ;
280 font_set->add(new Feature(*f_symbols[WEIGHT], new FeatureValueString(f_hcf_weight)));
281 font_set->add(new Feature(*f_symbols[SLANT], new FeatureValueString(f_hcf_slant)));
282 font_set->add(new Feature(*f_symbols[SIZE], new FeatureValueInt(f_hcf_size)));
283 font_set->add (new Feature (*f_symbols[FALLBACK], new FeatureValueString (f_hcf_fallback)));
285 f_default_features->add(new Feature(*f_symbols[FONT], new FeatureValueFeatureSet(font_set)));
288 FeatureSet* layout = new FeatureSet;
290 layout->add(new Feature(*f_symbols[LEADING],
291 new FeatureValueInt(DEFAULT_CONTAINER_LEADING)));
293 f_default_features->add(new Feature(*f_symbols[LAYOUT],
294 new FeatureValueFeatureSet(layout)));
297 // other default features
298 FeatureSet *margin = new FeatureSet;
299 margin->add (new Feature(*f_symbols[LEFT], new FeatureValueInt (20)));
300 f_default_features->add(new Feature(*f_symbols[MARGIN],
301 new FeatureValueFeatureSet(margin)));
304 f_default_features->add(new Feature(*f_symbols[WRAP],
305 new FeatureValueString("word")));
306 f_default_features->add(new Feature(*f_symbols[BREAK],
307 new FeatureValueString("line")));
309 return f_default_features;
313 CanvasRenderer::Begin()
315 // pre document initialization...called before document is processed
316 _DtCvTopicInfo *topic = new _DtCvTopicInfo ;
318 topic->link_data = _DtLinkDbCreate() ;
319 topic->seg_list = new_segment(_DtCvCONTAINER);
320 topic->id_str = NULL ;
321 topic->mark_list = NULL ;
324 gNodeViewInfo->topic(topic); // NOTE: was after do_features...
326 f_current_container = topic->seg_list ;
327 f_current_displayable = 0 ;
330 // set up initial parameters
331 ElementFeatures features(this) ;
333 do_features(features, *f_default_features, *f_default_features,
336 f_leading_stack.push(features.layout().leading());
337 f_leading_level_stack.push(f_level);
339 setup_container(f_current_container, features);
342 have to apply the features here
347 f_stack.push (f_current_container);
351 CanvasRenderer::End()
353 // post processing...called after document ends
354 #ifdef HIERARCHY_DEBUG
355 void print_hierarchy(_DtCvTopicInfo*);
356 print_hierarchy(gNodeViewInfo->topic());
359 while (f_leading_level_stack.entries())
360 f_leading_level_stack.pop();
361 while (f_leading_stack.entries())
362 f_leading_stack.pop();
365 static unsigned is_literal = 0 ;
367 // returns non-zero value if element is to be ignored
369 CanvasRenderer::BeginElement(const Element &element,
370 const FeatureSet &local,
371 const FeatureSet &complete,
372 const FeatureSet &parentComplete)
374 // at this point, f_current_container contains the
375 // parent of the element we are about to process
377 #ifdef BEGIN_ELEMENT_DEBUG
378 cerr << '<' << element.gi() << '>' << endl;
381 assert(f_current_container->type == _DtCvCONTAINER);
383 // have to do some VCC counting here
387 cerr << element.gi() << ": \t" << local << endl;
388 cerr << element.gi() << "=>\t" << complete << endl;
391 // now process styles
393 f_fstack.push (f_font);
394 f_stack.push(f_current_container);
395 f_link_stack.push (f_link_idx);
396 f_tgroup_stack.push (f_current_tgroup);
399 cerr << "pushed link_index: " << f_link_idx << endl;
402 #ifdef DEBUG_USE_NAMES
403 _DtCvSegment *hold_segment = f_current_container ;
406 ElementFeatures features(this) ;
408 do_features(features, local, complete, f_symbols);
410 if (features.ignore()) {
411 if (f_tgroup_stack.entries()) f_tgroup_stack.pop();
412 if (f_link_stack.entries()) f_link_stack.pop();
413 if (f_stack.entries()) f_stack.pop();
414 if (f_subsuper_stack.entries()) f_subsuper_stack.pop();
416 return features.ignore();
421 if (features.ignore_linebreak(False)) {
422 // disable linebreak features beforehand here if linebreak
423 // should be ignored for this element
425 if (features.prefix().linebreak() & LINEBREAK_BEFORE)
426 features.prefix().linebreak(
427 features.prefix().linebreak() & ~LINEBREAK_BEFORE);
429 if (features.suffix().linebreak() & LINEBREAK_AFTER)
430 features.suffix().linebreak(
431 features.suffix().linebreak() & ~LINEBREAK_AFTER);
433 features.linebreak(LINEBREAK_NONE);
437 SegClientData scd(_DtCvSTRING);
439 scd.hilite_type(features.highlight().overline() |
440 features.highlight().strikethrough() |
441 features.highlight().underline());
442 UAS_String& bg_color(features.highlight().bg_color());
443 UAS_String& fg_color(features.highlight().fg_color());
444 if ((char*)bg_color && *(char*)bg_color)
445 scd.bg_color(strdup((char*)bg_color));
446 if ((char*)fg_color && *(char*)fg_color)
447 scd.fg_color(strdup((char*)fg_color));
449 f_scd_stack.push(new SegClientData(scd));
452 f_subsuper_stack.push(features.subsuper());
454 if (features.table() == NULL && f_table_stack.entries()) {
455 // semantics: f_table_stack.top should always be the current.
456 // need special care on the other end as well.
457 f_table_stack.push(f_table_stack.top());
460 f_table_stack.push(features.table());
462 if (features.layout().has_layout(False) &&
463 current_leading() != features.layout().leading())
465 f_leading_stack.push(features.layout().leading());
466 f_leading_level_stack.push(f_level);
469 // get info on special olias stuff like links etc
470 handle_olias_attributes(features, element,
471 local, complete, parentComplete);
473 // if we are not already in a link, see if we start one
474 if (f_link_idx == -1)
476 f_link_idx = features.link_idx();
479 if (features.tgroup())
481 _DtCvSegment *tableseg = new_segment(_DtCvTABLE);
483 // NOTE: have to delete this guy when he pops out the other end !
484 f_current_tgroup = features.tgroup();
485 f_current_tgroup->set_segment(tableseg);
487 // associate tgroup with the surrounding table
488 f_current_tgroup->table(f_table_stack.top());
490 if (f_current_tgroup->table() &&
491 f_current_tgroup->table()->frame() != TableDefn::table_frame_none)
493 _DtCvSegment* former_current_container = f_current_container;
495 // NOTE: the purpose of the new container is just for
496 // drawing a border around a tgroup
497 f_current_container = create_container(f_current_container);
499 setup_cascaded_tgroup_container(former_current_container,
500 f_current_container);
503 insert_segment(f_current_container, tableseg);
507 if (features.col_format()) {
510 ColFormat *colf = features.col_format();
511 fprintf(stderr, "(DEBUG) ColFormat justify=%d, cols=%d, name=\"%s\", width=%d\n",
512 colf->justify(), colf->cols(), colf->name(), colf->width());
515 f_current_tgroup->add (features.col_format());
518 if (features.row()) {
519 f_current_tgroup->add_row(features.row());
522 if (features.requires_container(False) ||
523 (features.prefix().text() && features.prefix().requires_container(True)) ||
524 (features.suffix().text() && features.suffix().requires_container(True)))
527 if (features.cell().has_cell())
529 f_current_container = create_container (NULL);
531 ColDefn* coldef = new ColDefn(f_current_container, NULL,
532 features.cell().spanrows(),
533 features.cell().colref(),
534 features.cell().colstart(),
535 features.cell().colend(),
536 features.cell().justify(),
537 features.cell().vjustify(),
538 features.cell().colsep(),
539 features.cell().rowsep(),
540 features.cell().char_align());
542 f_current_tgroup->add(coldef);
546 f_current_container = create_container(f_current_container);
547 setup_container (f_current_container, features);
551 #ifdef CONTAINER_DEBUG
552 cerr << "Container: " <<
553 "\tjustify: " << print_justify(f_current_container->handle.container.justify) <<
554 "\tvjustify: " << print_justify(f_current_container->handle.container.vjustify) <<
555 "\torient: " << print_justify(f_current_container->handle.container.orient) <<
556 "\tvorient: " << print_justify(f_current_container->handle.container.vorient) <<
557 "\tflow: " << f_current_container->handle.container.flow <<
561 f_current_container->handle.container.id = features.locator();
563 if (f_link_idx != -1)
565 f_current_container->link_idx = f_link_idx ;
566 f_current_container->type |= _DtCvHYPER_TEXT ;
572 // may have to build a marker segment
573 if (features.locator())
575 _DtCvSegment *marker = new_segment (_DtCvMARKER);
576 marker->handle.marker = features.locator();
577 insert_segment (f_current_container, marker);
580 const char *font = features.font();
582 f_font = features.font();
585 // NOTE: pagebreak implicitly adds a linebreak before the pagebreak.
586 if (features.pagebreak() & PAGEBREAK_BEFORE) {
587 insert_break (f_current_container, _DtCvNEW_LINE);
588 insert_break (f_current_container, _DtCvPAGE_BREAK);
590 else if (features.linebreak() & LINEBREAK_BEFORE) {
591 insert_break (f_current_container, _DtCvNEW_LINE);
594 // check for prefix text, because if there is no text, then we are
595 // not really doing a prefix, and we just ignore it...possible
596 // exception, if an <HR> is required as a prefix item
598 if (features.prefix().text())
600 _DtCvSegment *container = f_current_container ;
602 if (features.prefix().requires_container(True))
604 const char *font = f_font ;
605 container = create_container (f_current_container);
606 setup_container (container, features.prefix(), True);
608 #ifdef CONTAINER_DEBUG
609 cerr << "Prefix Container: " <<
610 "\tjustify: " << f_current_container->handle.container.justify <<
611 "\tvjustify: " << f_current_container->handle.container.vjustify <<
612 "\torient: " << f_current_container->handle.container.orient <<
613 "\tvorient: " << f_current_container->handle.container.vorient <<
614 "\tflow: " << f_current_container->handle.container.flow <<
617 // create a container for the element content
618 f_current_container = create_container(f_current_container);
621 if (features.prefix().linebreak() & LINEBREAK_BEFORE)
622 insert_break (container, _DtCvNEW_LINE);
624 const char *font = features.prefix().font() ;
625 if (font == NULL || *font == '\0')
629 _DtCvSegment *segment = insert_string (container,
631 features.prefix().text(),
632 strlen(features.prefix().text()),
635 // indicate that this is added information
636 segment->type |= _DtCvAPP_FLAG1 ;
638 if (features.prefix().requires_container(True))
639 f_current_displayable = 0;
641 if (features.prefix().linebreak() & LINEBREAK_AFTER) {
642 if (! features.prefix().ignore_linebreak(True))
643 segment->type |= _DtCvNEW_LINE ;
646 else if (features.prefix().linebreak() & LINEBREAK_AFTER) {
647 if (! features.prefix().ignore_linebreak(True))
648 insert_break(f_current_container, _DtCvNEW_LINE);
651 // do graphics handling
652 if (features.graphic())
654 _DtCvSegment *grseg = features.graphic();
655 insert_segment(f_current_container, grseg);
656 grseg->link_idx = features.link_idx();
658 if (f_current_displayable)
659 f_current_displayable->next_disp = grseg;
660 f_current_displayable = grseg;
663 // I have no idea what the next 2 lines are intended for.
664 // Why should prefix's linebreak take effect on the element's
665 // flow-break? --- kamiya@chistech.com
666 if (features.prefix().linebreak() & LINEBREAK_AFTER)
667 grseg->type |= _DtCvNEW_LINE ;
671 PartialElementFeatures *suffixFeatures = 0;
672 if (features.suffix().text())
674 // have to stack this guy and add it to the data during
676 suffixFeatures = new PartialElementFeatures(features.suffix());
678 if ((features.linebreak() & LINEBREAK_AFTER) ||
679 (features.pagebreak() & PAGEBREAK_AFTER))
681 // Add linebreak/pagebreak info to suffix; create empty suffix
683 if (suffixFeatures == 0)
684 suffixFeatures = new PartialElementFeatures(this);
686 // if our element had a linebreak after, then include it in the suffix
687 // while preserving potential suffix linebreak settings.
688 if (features.linebreak() & LINEBREAK_AFTER)
689 suffixFeatures->linebreak(suffixFeatures->linebreak() |
692 // if our element had a pagebreak after, then include it in the suffix;
693 // suffixes cannot have pagebreaks, so don't worry about preserving.
694 if (features.pagebreak() & PAGEBREAK_AFTER)
695 suffixFeatures->pagebreak(PAGEBREAK_AFTER);
697 f_suffixes.push (suffixFeatures);
699 is_literal = f_current_container->handle.container.type == _DtCvLITERAL;
701 if (features.xref()) {
704 if (g_xref_subsection && window_system().dtinfo_font()) {
706 extern UAS_String f_dtinfo_font_name;
708 UAS_String swapped_out = f_font;
709 f_font = f_dtinfo_font_name;
715 _data(buf, 2, False);
717 f_font = swapped_out;
721 _data(features.xref(), strlen(features.xref()), False);
724 return 0 ; // not do not ignore content
728 CanvasRenderer::EndElement(const Symbol& /*name*/)
730 #ifdef END_ELEMENT_DEBUG
731 cerr << "</" << name << '>' << endl;
734 // take care of suffix stuff here
735 PartialElementFeatures *suffix = f_suffixes.pop();
741 _DtCvSegment *container = f_current_container ;
743 if (suffix->requires_container(True))
745 container = create_container (f_current_container);
746 setup_container (container, *suffix, True);
750 if (! suffix->ignore_linebreak(True)) {
751 if (suffix->linebreak() & LINEBREAK_BEFORE) {
752 insert_break (container, _DtCvNEW_LINE);
756 const char *font = suffix->font() ;
757 if (font == NULL || *font == '\0')
760 _DtCvSegment *segment = insert_string (container,
763 strlen(suffix->text()),
766 // indicate that this is added information
767 segment->type |= _DtCvAPP_FLAG1 ;
769 if (suffix->linebreak() & LINEBREAK_AFTER) {
770 segment->type |= _DtCvNEW_LINE ;
773 if (suffix->requires_container(True))
774 f_current_displayable = 0;
776 else if (suffix->linebreak() & LINEBREAK_AFTER)
778 // Element had a LINEBREAK_AFTER
780 if (f_current_displayable != 0)
782 f_current_displayable->type |= _DtCvNEW_LINE ;
786 insert_break (f_current_container, _DtCvNEW_LINE);
790 if (suffix->pagebreak() & PAGEBREAK_AFTER) {
791 // Put page break after suffix segment.
792 // NOTE: insert linebreak first if not already added.
793 if (!(suffix->linebreak() & LINEBREAK_AFTER))
794 insert_break (f_current_container, _DtCvNEW_LINE);
795 insert_break (f_current_container, _DtCvPAGE_BREAK);
800 // pop the stacks, returning state to that of current element
801 f_font = f_fstack.pop();
802 f_current_container = f_stack.pop ();
803 f_link_idx = f_link_stack.pop();
804 if (f_scd_stack.top())
805 delete f_scd_stack.pop();
806 if (f_subsuper_stack.entries())
807 f_subsuper_stack.pop();
809 // pop the table stack
810 // if the table that we pop is not the one we are working on, then
811 // we have finished with the current table, and can build it then
812 // dispose of the memory used
814 TGDefn *next_tgroup = f_tgroup_stack.pop();
816 if (f_current_tgroup != next_tgroup)
818 // convert the data we have accumulated into the _DtCvTable
819 // segment that represents this table
820 f_current_tgroup->build();
821 delete f_current_tgroup ;
823 f_current_tgroup = next_tgroup ;
825 if (f_table_stack.entries()) {
826 TableDefn* table = f_table_stack.pop();
828 if (f_table_stack.entries() == 0 || table != f_table_stack.top())
833 if (f_leading_stack.entries() && f_leading_level_stack.entries())
835 if (f_leading_level_stack.top() == f_level)
837 f_leading_stack.pop();
838 f_leading_level_stack.pop();
846 CanvasRenderer::data(const char *data, unsigned int size)
848 _data(data, size, True);
852 CanvasRenderer::_data(const char *data, unsigned int size, Boolean count_vcc)
854 _DtCvSegment *segment ;
859 cerr << "literal: " << data << endl;
861 segment = insert_literal(f_current_container, f_font, data, size);
865 segment = insert_string (f_current_container,
866 f_font, data, size, count_vcc);
869 if (f_link_idx != -1)
871 segment->link_idx = f_link_idx ;
872 segment->type |= _DtCvHYPER_TEXT ;
874 cerr << "data:( " << f_link_idx << ") " << data << endl;
880 CanvasRenderer::handle_olias_attributes(ElementFeatures &features,
881 const Element &element,
882 const FeatureSet & /* local */,
883 const FeatureSet &complete,
884 const FeatureSet & /*parentComplete*/
887 // check for specific olias attributes
889 // NOTE: more efficient to iterate over attributes than to check each
890 // attribute on every element (when I have time) - jbm
892 const Attribute *olxref =
893 element.get_olias_attribute(gSymTab->intern("OL-XREF"));
895 UAS_String locator = olxref->value();
897 UAS_Pointer<UAS_Common> target =
898 gNodeViewInfo->node_ptr()->create_relative(locator);
901 extern char* g_mmdb_section_label;
904 if (g_mmdb_section_label && *g_mmdb_section_label)
905 title = g_mmdb_section_label;
907 title = target->title();
909 if ((char*)title && *(char*)title)
910 features.xref(strdup((char*)title));
913 cerr << '<' << element.gi() << " xref=" << (char*)locator << '>'
914 << " target=" << (char*) (char*)target->id() << endl;
919 /* -------- Locators -------- */
920 const Attribute *locator = element.get_olias_attribute(*f_symbols[OLID]);
924 cerr << '<' << element.gi() << " locator=" << locator->value() << '>' << endl;
926 const char *locator_value = locator->value();
928 // Need to place the locator value as an ID in the Container
929 features.locator (strdup (locator_value));
934 /* -------- Links -------- */
935 const Attribute *olidref = element.get_olias_attribute(*f_symbols[OLIDREF]);
938 // enter this segment into the link db
940 UAS_String locator = (char*)olidref->value();
942 if ((char*)locator && *(char*)locator && gNodeViewInfo) {
944 // We should not really use gNodeViewInfo. CanvasRenderer should
945 // a member of type UAS_Pointer<UAS_Common>
947 UAS_Pointer<UAS_Common> target =
948 gNodeViewInfo->node_ptr()->create_relative(locator);
950 if (target) // create link only when resolved
952 // hack - currently, a hint of 0 is a hypertext link and a hint
953 // of 1 is a graphic. this should really be co-ordinated with
954 // the constants used by the Canvas
958 gNodeViewInfo->topic()->link_data, // link db
960 (char *)(olidref->value()), // spec
961 _DtCvLinkType_AppDefine, // type
968 cerr << "idref: " << olidref->value() << " --> " << features.link_idx() << endl;
971 /* -------- see if it is remote -------- */
973 // Can we mark this anymore?
976 const Attribute *remote =
977 element.get_olias_attribute(*f_symbols[REMOTE]);
980 // keep track of it somehow
981 // remote is only used to check for valid links at initial display
982 // time and is not used at actual link following time
983 ON_DEBUG(cerr << "remote link: " << b_node->target() << endl);
984 b_node->remote_target(true);
987 cerr << "link (" << b_node->target() << ") placed on: " << (void*)b_node
993 /* -------- Graphics -------- */
995 const Attribute *grattr =
996 element.get_olias_attribute(*f_symbols[GRAPHIC_attr]);
1000 #ifdef GRAPHIC_DEBUG
1001 const Feature *graphic_display_type =
1002 complete.deep_lookup("GRAPHIC", "ALIGN", 0);
1004 cerr << "GRAPHIC" << endl;
1006 cerr << "Graphic( " << element.gi() << "): (" ;
1007 if (graphic_display_type)
1008 cerr << *graphic_display_type ;
1011 cerr << ")" << endl;
1013 cerr << "graphic id: " << grattr->value() << endl;
1017 const char *graphicid = grattr->value();
1018 UAS_Pointer<Graphic> gr(graphics_mgr().get(gNodeViewInfo->node_ptr(), graphicid));
1019 PixmapGraphic *graphic = gr->graphic();
1021 gNodeViewInfo->add_graphic (gr); // preserve the Graphic and Pixmap objects
1023 // inform the PixmapGraphic that we are going to keep its pixmap
1024 //graphic->set_type (PixmapGraphic::PRESERVE);
1026 // Set up DtHelp graphic representation
1027 DtHelpGraphicStruct *pGS ;
1028 _DtHelpDARegion *pReg ;
1030 pGS = new DtHelpGraphicStruct ;
1031 pReg = new _DtHelpDARegion ;
1033 pGS->pix = graphic->pixmap();
1034 pGS->width = graphic->width() ;
1035 pGS->height = graphic->height();
1037 pGS->pixels = NULL ;
1038 pGS->num_pixels = 0 ;
1040 #ifdef GRAPHIC_DEBUG
1041 cerr << "pixmap ( " << pGS->width << ", " << pGS->height <<
1042 ") is: " << (void*)pGS->pix << " ==>" << (unsigned)pGS->pix << endl;
1045 pReg->inited = True ;
1046 pReg->type = _DtHelpDAGraphic ;
1047 pReg->handle = (_DtCvPointer)pGS ;
1049 _DtCvSegment *segment = new_segment (_DtCvREGION);
1050 segment->handle.region.info = (_DtCvPointer)pReg ;
1051 segment->handle.region.width = pGS->width ;
1052 segment->handle.region.height = pGS->height ;
1053 segment->handle.region.ascent = -1 ;
1055 SegClientData scd(_DtCvREGION);
1056 scd.GraphicHandle((void*)(Graphic*)gr);
1057 // for detaching purposes
1058 segment->client_use = new SegClientData(scd);
1060 #ifdef GRAPHIC_TRAVERSAL
1061 // if graphic is detachable, then it must be traversible
1062 // hack - currently, a hint of 0 is a hypertext link and a hint
1063 // of 1 is a graphic. this should really be co-ordinated with
1064 // the constants used by the Canvas
1065 segment->type |= _DtCvHYPER_TEXT ;
1067 _DtLinkDbAddLink (gNodeViewInfo->topic()->link_data, // link_db
1069 grattr->value(), // spec
1070 _DtCvLinkType_AppDefine, // type
1075 // place this segment into our structure for later insertion
1076 // into the Canvas segment tree
1077 features.graphic (segment);
1085 // now see if style sheet wants it inlined
1086 const Feature *graphic_display_type =
1087 complete.deep_lookup("GRAPHIC", "ALIGN", 0);
1088 #ifdef IGRAPHIC_DEBUG
1089 cout << "Graphic( " << element.gi() << "): (" ;
1090 if (graphic_display_type)
1091 cout << *graphic_display_type ;
1094 cout << ")" << endl;
1097 if (graphic_display_type &&
1098 !strcasecmp("inline", *graphic_display_type->value()))
1102 // NOTE: there may be tree problems, because graphic objects have no
1103 // content, and it looks as though the tag was empty, so the tree may be
1104 // built wrong after processing a graphic (especially an inline
1105 // graphic). We may have to drop a branch to put this on?
1107 // see if it is an ismap graphic
1108 const Attribute *ismap = element.get_olias_attribute(*f_symbols[ISMAP]);
1110 const char *graphicid = grattr->value();
1111 Pointer<Graphic> gr(graphics_mgr().get(gNodeViewInfo->node_ptr(), graphicid));
1112 PixmapGraphic *graphic = gr->graphic();
1114 if (graphic->pixmap() != XtUnspecifiedPixmap)
1116 gNodeViewInfo->add_graphic(gr);
1117 #ifdef TML_NO_THIS_ASSIGNMENT
1118 model* to_model = f_current_node->get_model();
1119 igfxnode *ignode = new(to_model) igfxnode(to_model);
1121 igfxnode *ignode = new igfxnode(to_model);
1124 ignode->set_ismap();
1125 ignode->set_graphic_handle((Graphic*)gr);
1126 ignode->set_graphic_dimensions(graphic->width(),
1128 f_current_node->connect_node(ignode, f_connect_dir);
1129 f_current_node = ignode ;
1130 f_connect_dir = n_right ;
1136 // This routine puts the graphic as a child of a child of the
1138 // when we exit, current node is the new bnode, but connect dir is
1139 // to the right in case there are siblings.
1141 #ifdef TML_NO_THIS_ASSIGNMENT
1142 model* to_model = f_current_node->get_model();
1143 node *current_node = new(to_model) bnode(to_model);
1145 node *current_node = new bnode(to_model);
1147 b_node->connect_node(current_node, n_down);
1148 current_node->vcc(f_vcc) ;
1150 node_dir connect_dir = n_down ;
1152 // space above graphic
1154 const Feature *spacefp = complete.deep_lookup(f_symbols[MARGIN],
1160 spacing = point2pixel(*spacefp->value());
1162 model *the_model = current_node->get_model();
1163 #ifdef TML_NO_THIS_ASSIGNMENT
1164 space_node *spnode = new (the_model) space_node(spacing, the_model);
1166 space_node *spnode = new space_node(spacing, the_model);
1168 current_node->connect_node(spnode, connect_dir);
1172 const char *graphicid = grattr->value();
1174 // create a gnode with one blank, so we have somewhere to attach marks
1175 #ifdef TML_NO_THIS_ASSIGNMENT
1176 gnode *new_gnode = new (the_model) gnode(the_model);
1178 gnode *new_gnode = new gnode(the_model);
1180 new_gnode->vcc(f_vcc);
1182 wchar_t tml_blankStr[2];
1183 *tml_blankStr = (wchar_t)' ';
1184 *(tml_blankStr + 1) = (wchar_t)'\0';
1185 new_gnode->attach_data(tml_blankStr,1);
1187 new_gnode->attach_data(" ",1);
1189 spnode->connect_node(new_gnode, n_right);
1192 Pointer<Graphic> gr(graphics_mgr().get(gNodeViewInfo->node_ptr(), graphicid));
1193 PixmapGraphic *graphic = gr->graphic();
1195 if (graphic->pixmap() != XtUnspecifiedPixmap)
1197 gNodeViewInfo->add_graphic(gr);
1199 #ifdef TML_NO_THIS_ASSIGNMENT
1200 gfxnode *new_gfxnode = new (the_model) gfxnode(the_model);
1202 gfxnode *new_gfxnode = new gfxnode(the_model);
1205 new_gnode->connect_node(new_gfxnode, n_right);
1208 // NOTE: passing in REAL Graphic object
1209 // this is ok because it is tracked via the node_view_info
1210 new_gfxnode->set_graphic_handle((Graphic*)gr);
1211 new_gfxnode->set_graphic_dimensions(graphic->width(),
1213 new_gfxnode->vcc(f_vcc);
1215 // insert another blank to attach end of marks
1216 #ifdef TML_NO_THIS_ASSIGNMENT
1217 gnode *tgnode = new (the_model) gnode(the_model);
1219 gnode *tgnode = new gnode(the_model);
1221 new_gfxnode->connect_node(tgnode, n_right);
1223 tgnode->attach_data(tml_blankStr,1);
1225 tgnode->attach_data(" ", 1);
1227 current_node = tgnode ;
1232 snprintf(buf, sizeof(buf),
1233 "Graphic \"%s\" unavailable", graphic);
1234 #ifdef TML_NO_THIS_ASSIGNMENT
1235 new_gnode = new (the_model) gnode(the_model);
1237 new_gnode = new gnode(the_model);
1239 new_gnode->vcc(f_vcc);
1241 wchar_t* buffer = new wchar_t[ strlen(buf) + 1 ];
1242 int nc = mbstowcs(buffer, buf, strlen(buf) + 1);
1244 new_gnode->attach_data(buffer, nc);
1247 new_gnode->attach_data(buf, strlen(buf));
1249 spnode->connect_node(new_gnode, n_right);
1250 current_node = new_gnode;
1252 // more spacing at end of graphic
1253 #ifdef TML_NO_THIS_ASSIGNMENT
1254 spnode = new (the_model) space_node(spacing, the_model);
1256 spnode = new space_node(spacing, the_model);
1259 current_node->connect_node(spnode, n_right);
1261 // set current node to child of bnode so that EndElement knows that node
1262 // had content, and sets the next node to be connected to the right
1264 f_current_node = b_node->get_node(n_down) ;
1265 f_connect_dir = n_right ;
1271 // Terms must come last, otherwise vcc will be screwed up for above items
1273 /* -------- Terms -------- */
1274 const Attribute *terms = element.get_olias_attribute(*f_symbols[TERMS]);
1278 const char *p = terms->value();
1281 int mb_len = mblen(p, MB_CUR_MAX);
1282 assert( mb_len > 0 );
1284 const unsigned char ch = (unsigned char)*p++;
1285 if (ch == ' ' || // space
1286 ch == '\t' || // tab
1287 ch == '\n' || // newline
1299 if (!((*p == ' ') || // space
1300 (*p == ' ') || // tab
1301 (*p == '\n') || // newline
1302 (*p == (char)0xA0))) // nbsp
1315 insert_break (_DtCvSegment *container, unsigned long type)
1317 _DtCvSegment *segment = new_segment (_DtCvNOOP);
1318 segment->type |= type;
1319 insert_segment (container, segment) ;
1324 CanvasRenderer::setup_cascaded_tgroup_container(_DtCvSegment* parent,
1325 _DtCvSegment* child)
1327 if (! (parent && child))
1329 if (! (parent->type & _DtCvCONTAINER && child->type & _DtCvCONTAINER))
1332 // orient,...,flow (controller specific) are irrelevant
1333 child->handle.container.type = parent->handle.container.type;
1334 child->handle.container.leading = parent->handle.container.leading;
1335 child->handle.container.fmargin = 0;
1336 child->handle.container.rmargin = 0;
1337 child->handle.container.tmargin = 0;
1338 child->handle.container.bmargin = 0;
1339 child->handle.container.bdr_info = parent->handle.container.bdr_info;
1340 child->handle.container.justify = _DtCvINHERIT;
1341 child->handle.container.vjustify = _DtCvINHERIT;
1343 TableDefn::table_frame_t frame = f_current_tgroup->table()->frame();
1346 case TableDefn::table_frame_top:
1347 child->handle.container.border = _DtCvBORDER_TOP;
1349 case TableDefn::table_frame_bottom:
1350 child->handle.container.border = _DtCvBORDER_BOTTOM;
1352 case TableDefn::table_frame_topbot:
1353 child->handle.container.border = _DtCvBORDER_HORZ;
1355 case TableDefn::table_frame_sides:
1356 child->handle.container.border = _DtCvBORDER_VERT;
1358 case TableDefn::table_frame_all:
1360 child->handle.container.border = _DtCvBORDER_FULL;
1366 CanvasRenderer::setup_cascaded_container(_DtCvSegment*)
1370 CanvasRenderer::create_cascaded_container(_DtCvSegment*)
1377 new_segment(unsigned long type)
1379 _DtCvSegment *segment = new _DtCvSegment ;
1381 { // zero-out fields
1382 unsigned size = sizeof(segment->handle);
1383 //cerr << "Handle size = " << size << endl;
1384 char *p = (char *)&(segment->handle) ;
1385 for (unsigned int i = 0; i < size; i++, p++)
1389 segment->type = type ;
1390 segment->link_idx = -1 ;
1391 segment->next_seg = NULL ;
1392 segment->next_disp = NULL ;
1393 segment->client_use = NULL ;
1394 segment->internal_use = NULL ;
1398 case _DtCvCONTAINER:
1399 segment->handle.container.id = 0 ;
1400 segment->handle.container.type = _DtCvDYNAMIC ;
1401 segment->handle.container.border = _DtCvBORDER_NONE ;
1402 segment->handle.container.justify = _DtCvJUSTIFY_LEFT ;
1403 segment->handle.container.vjustify= _DtCvJUSTIFY_TOP;
1404 segment->handle.container.orient = _DtCvJUSTIFY_LEFT_CORNER ;
1405 segment->handle.container.vorient = _DtCvJUSTIFY_CENTER ;
1406 segment->handle.container.flow = _DtCvWRAP;
1407 segment->handle.container.percent = 0 ;
1408 segment->handle.container.leading = DEFAULT_CONTAINER_LEADING ;
1409 segment->handle.container.fmargin = 0 ;
1410 segment->handle.container.lmargin = 0 ;
1411 segment->handle.container.rmargin = 0 ;
1412 segment->handle.container.tmargin = 0 ;
1413 segment->handle.container.bmargin = 0 ;
1414 segment->handle.container.justify_char = NULL ;
1416 segment->handle.container.bdr_info.width = 1 ;
1418 segment->handle.container.bdr_info.width = 0 ;
1420 segment->handle.container.bdr_info.data = NULL ;
1421 segment->handle.container.seg_list = 0;
1426 segment->type |= _DtCvWIDE_CHAR;
1427 segment->handle.string.string = NULL;
1428 segment->handle.string.font = NULL;
1432 segment->type |= _DtCvIN_LINE;
1443 CanvasRenderer::create_container(_DtCvSegment *parent)
1445 _DtCvSegment *container = new_segment(_DtCvCONTAINER);
1449 _DtCvSegment *tseg = parent->handle.container.seg_list ;
1453 while (tseg->next_seg)
1454 tseg = tseg->next_seg ;
1456 tseg->next_seg = container ;
1459 parent->handle.container.seg_list = container ;
1463 f_current_displayable = 0 ;
1467 CanvasRenderer::insert_literal(_DtCvSegment *container,
1468 const char *font, const char *data,
1471 // We have a literal element. This has to be broken down into
1472 // individual string segments, separated by DtCvNEW_LINE segments
1474 char *start = (char *) data; // start of current substring
1477 // replace all <CR> with newlines
1478 while ((cr = strchr(start, '\015')))
1480 *cr = '\n'; // replace with newline
1482 start++ ; // advancd beyond the newline
1485 return insert_string(container, font, data, size);
1489 CanvasRenderer::insert_string (_DtCvSegment *container,
1490 const char *font, const char *data,
1491 unsigned int /*size*/, Boolean count_vcc)
1493 _DtCvSegment *seg = NULL ;
1495 char *start = (char *)data;
1498 // find the newlines, and make a string segment up to that point,
1499 // then advance our start pointer beyond that point
1501 for (; (newline = strchr(start, '\n')); start = newline + 1) {
1503 seg = really_insert_string(container, font, start, (newline - start), count_vcc);
1504 _DtCvSegment *lbseg = insert_break(container, _DtCvNEW_LINE);
1506 f_current_displayable->next_disp = lbseg ;
1507 f_current_displayable = lbseg ;
1511 // at end of data now
1512 if (strlen(start) > 0)
1513 seg = really_insert_string(container, font, start, strlen(start), count_vcc);
1519 CanvasRenderer::really_insert_string (_DtCvSegment *container,
1520 const char *font, const char *data,
1521 unsigned int size, Boolean count_vcc)
1523 // put data into a string segment
1525 _DtCvSegment *strseg = new_segment(_DtCvSTRING);
1527 insert_segment (container, strseg);
1529 // set sub/super script attribute to the segment
1530 if (f_subsuper_stack.entries() &&
1531 f_subsuper_stack.top() > PartialElementFeatures::baseline) {
1533 if (f_subsuper_stack.top() == PartialElementFeatures::subscript)
1534 strseg->type |= _DtCvSUB_SCRIPT;
1535 else if (f_subsuper_stack.top() == PartialElementFeatures::superscript)
1536 strseg->type |= _DtCvSUPER_SCRIPT;
1537 #ifdef SUBSUPER_DEBUG
1539 cerr << "(WARNING) unknown value specified as sub/super script."
1544 if (f_current_displayable)
1545 f_current_displayable->next_disp = strseg ;
1547 f_current_displayable = strseg ;
1550 // calculate dthelp font index
1552 // WARNING: this routine keeps the ptr to the xlfd_spec
1553 // should be ok unless they try to delete it
1554 // as it is a const and therefore static to us
1556 /* resolve current language (order of precedence : LC_ALL,LC_TYPE,LANG) */
1558 if ((lang = getenv("LC_ALL")) == NULL)
1559 if ((lang = getenv("LC_CTYPE")) == NULL)
1560 if ((lang = getenv("LANG")) == NULL)
1563 _DtHelpGetExactFontIndex(gHelpDisplayArea, // Display Area Structure
1566 (char*) font, // xlfd_spec
1567 &ret_indx // returned index
1569 #ifdef FONT_INDEX_DEBUG
1570 cerr << " indx: " << ret_indx << " " << font << endl;
1573 strseg->handle.string.font = (_DtCvPointer)(size_t) ret_indx ;
1575 // copy data into new memory to hand over to the canvas
1576 char *string = new char[size + 1];
1577 memcpy(string, data, size);
1578 string[size] = '\0';
1580 unsigned int offset;
1582 strcmp((char*)gNodeViewInfo->node_ptr()->locale(), "ja_JP.EUC-JP") == 0)
1585 cerr << "<CR> is being processed for Japanese." << endl;
1586 cerr << "string=" << string << endl;
1588 unsigned char* strp;
1590 while ((strp = (unsigned char*)strchr(string, '\015'))) {
1592 cerr << "<CR> found...";
1594 unsigned char *last = NULL, *next = NULL;
1597 (char*)last >= string && *last <= (unsigned char)' ';
1600 (char*)next < string + size && *next <= (unsigned char)' ';
1603 // check for boundary violation
1604 if ((char*)last < string || (char*)next == string) {
1606 cerr << "replaced with a space" << endl;
1612 if (*last < 128 || *next < 128) { // between asciis
1614 cerr << "replaced with a space" << endl;
1620 cerr << "marked as 0x90" << endl;
1622 *strp = 0x90; // mark to be removed later (works only for EUC)
1626 char *buf = new char[size + 1], *bufp;
1628 for (bufp = buf, offset = 0; offset < size && string[offset]; offset++)
1630 unsigned char& c = (unsigned char &)string[offset];
1642 for (offset = 0; offset < size && string[offset]; offset++)
1644 char& pos = string[offset];
1645 pos = (pos != '\015') ? pos : ' ';
1647 // no need for string termination here
1650 #ifdef DEBUG_R_INPUT_STRING
1654 SegClientData scd(_DtCvSTRING);
1657 if (strseg->type & _DtCvWIDE_CHAR)
1660 WString wstring(string, size);
1661 #ifdef CRE_I18N_DEBUG
1662 fprintf(stderr, "(DEBUG) wstring=\"%s\"\n", wstring.get_mbstr());
1664 if ((wchar_t*)wstring == NULL || *(wchar_t*)wstring == 0) {
1665 strseg->type &= ~_DtCvWIDE_CHAR;
1669 string = (char*)wstring.get_wstr();
1672 else { // single font being used, do not use wchar_t
1673 strseg->type &= ~_DtCvWIDE_CHAR;
1677 // account for vcc for this string
1679 if (strseg->type & _DtCvWIDE_CHAR) {
1681 for (p = (wchar_t*)string; *p; p++) {
1682 if (*p != ' ' && *p != '\t' && *p != '\n')
1686 else { // also need to exclude nbsp
1688 for (p = (unsigned char*)string; *p; p++) {
1689 if (*p != ' ' && *p != '\t' && *p != '\n' && *p != 0xA0)
1694 // setup highlight info
1695 strseg->client_use = new SegClientData(*f_scd_stack.top());
1697 f_vcc += scd.vclen();
1698 ((SegClientData*)strseg->client_use)->vcc (scd.vcc());
1699 ((SegClientData*)strseg->client_use)->vclen(scd.vclen());
1702 strseg->handle.string.string = string ;
1706 _DtCvStringClientData* pSCD = (_DtCvStringClientData*)strseg->client_use;
1708 fprintf(stderr, "(DEBUG) vcc=%d vclen=%d, type=0x%x\n",
1709 pSCD->vcc, pSCD->vclen, pSCD->hilite_type);
1717 CanvasRenderer::setup_container(_DtCvSegment *container,
1718 PartialElementFeatures &features,
1721 const char* font = (char*)features.font();
1723 f_font = features.font();
1726 if (features.position().horiz() != _DtCvOPTION_BAD)
1728 container->handle.container.orient = features.position().horiz();
1729 container->type |= _DtCvCONTROLLER ;
1732 if (features.position().vert() != _DtCvOPTION_BAD)
1734 container->handle.container.vorient = features.position().vert();
1735 container->type |= _DtCvCONTROLLER ;
1739 if (features.layout().has_layout(affix))
1741 Layout &layout = features.layout();
1743 container->handle.container.fmargin = layout.findent();
1744 container->handle.container.lmargin = layout.lindent();
1745 container->handle.container.rmargin = layout.rindent();
1746 container->handle.container.tmargin = layout.aspace();
1747 container->handle.container.bmargin = layout.bspace();
1749 if (layout.flow() != _DtCvOPTION_BAD)
1751 // NOTE: container is not a controller just because this
1752 // flag gets set, otherwise you will see all the objects
1753 // grouped together off to one side (upper left by default)
1754 container->handle.container.type = layout.flow();
1756 if (layout.wrap() != _DtCvOPTION_BAD)
1758 container->handle.container.flow = layout.wrap();
1759 container->type |= _DtCvCONTROLLER ;
1761 if (layout.justify() != _DtCvOPTION_BAD)
1763 container->handle.container.justify = layout.justify();
1767 if (features.layout().has_layout(affix)) {
1768 container->handle.container.leading = features.layout().leading();
1770 else if (f_leading_stack.entries()) {
1771 container->handle.container.leading = f_leading_stack.top();
1774 container->handle.container.leading = DEFAULT_CONTAINER_LEADING;
1779 CanvasRenderer::setup_container(_DtCvSegment *container, ElementFeatures &features)
1781 setup_container (container, *(PartialElementFeatures*)&features, False);
1783 // for online use, set the margins for the container
1784 // when printing, the margins will be set on the form
1786 if (!window_system().printing()) {
1789 container->handle.container.fmargin += features.margin().first() ;
1790 container->handle.container.lmargin += features.margin().left() ;
1791 container->handle.container.rmargin += features.margin().right();
1792 container->handle.container.tmargin += features.margin().top();
1793 container->handle.container.bmargin += features.margin().bottom();
1797 container->handle.container.border = features.border();
1798 if (features.border_width() < 0)
1799 container->handle.container.bdr_info.width = f_border_width;
1801 container->handle.container.bdr_info.width = features.border_width();
1805 PartialElementFeatures::PartialElementFeatures(CanvasRenderer* renderer)
1808 f_subsuper(baseline),
1810 f_pagebreak(PAGEBREAK_NONE),
1814 f_orientation("portrait")
1819 PartialElementFeatures::PartialElementFeatures (PartialElementFeatures &features)
1820 : f_text (features.f_text),
1821 f_font (features.f_font),
1822 f_subsuper (features.f_subsuper),
1823 f_highlight (features.f_highlight),
1824 f_linebreak (features.f_linebreak),
1825 f_pagebreak (features.f_pagebreak),
1826 f_position (features.f_position),
1827 f_layout (features.f_layout),
1828 f_graphic (features.f_graphic),
1829 f_ignore (features.f_ignore),
1830 f_orientation (features.f_orientation)
1835 PartialElementFeatures::~PartialElementFeatures()
1839 ElementFeatures::ElementFeatures(CanvasRenderer* renderer)
1840 : PartialElementFeatures(renderer),
1842 f_border (_DtCvBORDER_NONE),
1843 f_border_width(-1), // invalid border width
1854 ElementFeatures::~ElementFeatures()
1856 if (f_xref) free(f_xref);
1860 PartialElementFeatures::ignore_linebreak(int affix)
1862 return (layout().has_layout(affix) ||
1863 position().has_position());
1867 ElementFeatures::ignore_linebreak(int)
1869 if (prefix().text() && prefix().ignore_linebreak(True))
1872 if (suffix().text() && suffix().ignore_linebreak(True))
1875 return (PartialElementFeatures::ignore_linebreak(False) ||
1876 margin().has_margins());
1880 PartialElementFeatures::requires_container(int affix)
1882 return (layout().has_layout(affix) ||
1883 position().has_position());
1887 ElementFeatures::requires_container(int)
1889 return (PartialElementFeatures::requires_container(False) ||
1890 margin().has_margins() ||
1891 (border() != _DtCvBORDER_NONE) ||
1906 Margins::has_margins()
1908 // returns a non zero (true) value if any margin setting
1910 return f_first | f_left | f_right | f_top | f_bottom ;
1913 Layout::Layout(CanvasRenderer* renderer)
1914 : f_renderer(renderer),
1915 f_aspace (0), f_bspace (0), f_leading (-1),
1916 f_findent (0), f_rindent(0), f_lindent (0),
1917 f_flow (_DtCvOPTION_BAD),
1918 f_justify (_DtCvOPTION_BAD),
1919 f_wrap (_DtCvOPTION_BAD)
1923 Layout::Layout (Layout &layout)
1924 : f_renderer(layout.f_renderer),
1925 f_aspace (layout.f_aspace),
1926 f_bspace (layout.f_bspace),
1927 f_leading (layout.f_leading),
1928 f_findent (layout.f_findent),
1929 f_rindent (layout.f_rindent),
1930 f_lindent (layout.f_lindent),
1931 f_flow (layout.f_flow),
1932 f_justify (layout.f_justify),
1933 f_wrap (layout.f_wrap)
1938 Layout::has_layout(int affix)
1943 if (f_renderer->current_leading() != f_leading)
1947 if (f_renderer->f_level == f_renderer->f_leading_level_stack.top() ||
1948 f_renderer->current_leading() != f_leading)
1953 return f_aspace || f_bspace || f_findent || f_rindent || f_lindent ||
1954 (f_flow != _DtCvOPTION_BAD) ||
1955 (f_wrap != _DtCvOPTION_BAD) ||
1956 (f_justify != _DtCvOPTION_BAD) ;
1960 CanvasRenderer::current_leading()
1962 if (f_leading_stack.entries() == 0)
1965 return f_leading_stack.top();
1970 insert_segment (_DtCvSegment *container, _DtCvSegment *segment)
1973 if (container == segment)
1974 cerr << "ERROR: Containing ourself" << endl;
1975 cerr << (void*)container << " <-- " << (void*)segment << endl;
1977 _DtCvSegment *child =
1978 container->handle.container.seg_list ;
1982 // first data in this segment
1983 container->handle.container.seg_list = segment ;
1987 while (child->next_seg)
1988 child = child->next_seg ;
1990 child->next_seg = segment ;
1995 RowDefn::RowDefn() : f_vjustify(_DtCvOPTION_BAD), f_rowsep(CRSEP_NOT_SPECIFIED)
2000 f_columns.clearAndDestroy ();
2003 TableDefn::TableDefn(const char* frame_str, int colsep, int rowsep) :
2004 f_frame(table_frame_default), f_colsep(colsep), f_rowsep(rowsep)
2007 f_frame = string_to_token(frame_str);
2010 TableDefn::~TableDefn()
2014 TableDefn::frame(const char* frame_str)
2017 f_frame = string_to_token(frame_str);
2019 f_frame = table_frame_default;
2022 TableDefn::table_frame_t
2023 TableDefn::string_to_token(const char* frame_str)
2025 if (frame_str == NULL)
2026 return table_frame_default;
2028 table_frame_t token;
2030 if (! strcasecmp(frame_str, "none"))
2031 token = table_frame_none;
2032 else if (! strcasecmp(frame_str, "top"))
2033 token = table_frame_top;
2034 else if (! strcasecmp(frame_str, "bottom"))
2035 token = table_frame_bottom;
2036 else if (! strcasecmp(frame_str, "topbot"))
2037 token = table_frame_topbot;
2038 else if (! strcasecmp(frame_str, "sides"))
2039 token = table_frame_sides;
2040 else if (! strcasecmp(frame_str, "all"))
2041 token = table_frame_all;
2043 token = table_frame_default;
2048 TGDefn::TGDefn(_DtCvFrmtOption justify, _DtCvFrmtOption vjustify) :
2049 f_numcols (1),f_segment (0), f_justify(justify), f_vjustify(vjustify),
2050 f_colsep(CRSEP_NOT_SPECIFIED), f_rowsep(CRSEP_NOT_SPECIFIED),
2051 f_char_align('\0'), f_table(NULL)
2056 f_colformats.clearAndDestroy();
2057 f_rows.clearAndDestroy();
2061 TGDefn::add_row(RowDefn *rd)
2068 TGDefn::add (ColFormat *cf)
2071 f_colformats.append (cf);
2076 TGDefn::add (ColDefn *cd)
2078 if (f_rows.entries() > 0) {
2079 f_rows.last()->append (cd);
2085 add_id(char **cell_ids, unsigned row, unsigned number, _DtCvSegment *segment)
2087 char *id = segment->handle.container.id;
2093 snprintf(idstr, sizeof(idstr), "id%d", number);
2096 segment->handle.container.id = strdup (id);
2098 if (cell_ids[row] == NULL)
2100 cell_ids[row] = strdup (id) ;
2104 char *orig = cell_ids[row] ;
2105 cell_idslen = strlen (orig) + 1 + strlen (id) + 1 ;
2106 cell_ids[row] = new char [ cell_idslen ] ;
2107 snprintf(cell_ids[row], cell_idslen, "%s %s", orig, id);
2113 ColFormat::ColFormat()
2114 : f_char_align ('.'),
2116 f_justify (_DtCvOPTION_BAD),
2118 f_colsep(CRSEP_NOT_SPECIFIED),
2119 f_rowsep(CRSEP_NOT_SPECIFIED)
2123 ColFormat::~ColFormat()
2130 ColFormat::name(const char *string)
2132 f_name = strdup (string);
2137 _DtCvSegment *ensure_id(_DtCvSegment *segment)
2139 static unsigned id_count = 0;
2140 // in a table, an id cannot contain a space, so if it does
2141 // we wrap it in a new container
2142 if ((segment->handle.container.id != NULL) &&
2143 strchr(segment->handle.container.id, ' '))
2145 _DtCvSegment *new_container = new_segment (_DtCvCONTAINER);
2146 new_container->handle.container.seg_list = segment ;
2147 segment = new_container ;
2150 // generate an id if the segment does not have one
2151 if (segment->handle.container.id == NULL)
2154 snprintf(buffer, sizeof(buffer), "id%d", id_count++);
2155 segment->handle.container.id = strdup (buffer);
2162 TGDefn::find_format(const char *name, int* index)
2164 if (name == NULL || *name == '\0')
2167 ColFormat* format = NULL;
2169 CC_TPtrSlistIterator<ColFormat> cf_cursor (f_colformats);
2172 for (nth = 0; ++cf_cursor; nth++)
2174 if (cf_cursor.key()->name() == NULL)
2177 #ifdef TABLE_DEBUG_X
2178 cerr << "\tname: " << cf_cursor.key()->name() << endl;
2179 cerr << "\tchar: " << cf_cursor.key()->char_align() << endl;
2180 cerr << "\tjustify: " << cf_cursor.key()->justify() << endl;
2181 cerr << "\twidth: " << cf_cursor.key()->width() << endl;
2184 if (!strcmp(name, cf_cursor.key()->name())) {
2185 format = cf_cursor.key();
2190 if (format && index) // if found, return the index to the format
2200 unsigned i, len, slen, lent, leng;
2201 unsigned num_cells = 0; // # of virtual cells
2202 unsigned num_rows = 0; // # of physical rows
2203 unsigned num_columns = 0; // # of physical columns
2205 // calculate the actual number of items we have to distribute
2206 // throughout the table, as well as the widest row (in terms of
2207 // number of columns)
2209 // calculate the number of rows we really have
2210 // NOTE: Here we calculate the physically accurate number of
2211 // rows, not # of <row>s. Some cells can have rowspan > 1
2212 // which means more rows may be required than # of <row>s.
2214 CC_TPtrSlistIterator<RowDefn> row_cursor(f_rows) ;
2217 for (current_row = 0; ++row_cursor; current_row++)
2219 CC_TPtrSlistIterator<ColDefn> col_cursor (row_cursor.key()->columns());
2220 while (++col_cursor)
2222 // extent the number of rows if this columns spans below
2223 // the last row calculated so far
2224 unsigned rowspan = col_cursor.key()->spanrows();
2226 unsigned potential_last_row = current_row + rowspan ;
2227 if (num_rows < potential_last_row)
2228 num_rows = potential_last_row ;
2232 fprintf(stderr, "(DEBUG) # of physical rows = %d\n", num_rows);
2235 // find out how many virtual cells we actually have, and the number
2236 // of columns in the table
2237 // NOTE: Here we calculate the physically accurate number of
2238 // columns, instead of using numcols of <tgroup>.
2240 unsigned *col_count = new unsigned[num_rows] ;
2241 for (i = 0 ; i < num_rows; i++)
2246 for (current_row = 0; ++row_cursor; current_row++)
2248 unsigned entries = row_cursor.key()->columns().entries() ;
2249 num_cells += entries ;
2251 // now find out how many columns we span
2252 CC_TPtrSlistIterator<ColDefn> col_cursor (row_cursor.key()->columns());
2255 // adding up the spans of each column in the row
2256 // if we rowspan, include our count in the spanned rows
2258 while (++col_cursor)
2260 ColDefn *col = col_cursor.key() ;
2264 if (find_format(col->colstart(), &mth)) {
2266 if (find_format(col->colend(), &nth)) {
2272 spancols += nth - mth;
2276 for (i = 0; i < col->spanrows(); i++)
2277 col_count[current_row + i] += spancols;
2281 for ( i = 0 ; i < num_rows; i++)
2282 if (num_columns < col_count[i])
2283 num_columns = col_count[i] ;
2288 fprintf(stderr, "(DEBUG) # of physical columns = %d\n", num_columns);
2289 fprintf(stderr, "(DEBUG) # of virtual cells = %d\n", num_cells);
2292 // create a grid of our table, then populate each box in the grid
2293 // we then walk the grid to build our DtCvTable structure
2295 // allocate row memory
2296 _DtCvSegment* **grid = new _DtCvSegment **[num_rows] ;
2298 // allocate column memory
2299 for (i = 0 ; i < num_rows ; i++)
2301 grid[i] = new _DtCvSegment *[num_columns] ;
2302 for (unsigned int c = 0 ; c < num_columns; c++)
2306 // allocate space in _DtCvTable for storing the segments
2307 f_segment->handle.table.cells = new _DtCvSegment* [num_rows*num_columns + 1];
2308 for (i = 0; i <= num_rows*num_columns; i++)
2309 f_segment->handle.table.cells[i] = NULL ; // initialize list
2312 if (f_colformats.entries() < num_columns) {
2313 int i, deficit = num_columns - f_colformats.entries();
2315 for (i = 0; i < deficit; i++)
2316 f_colformats.append(new ColFormat());
2319 // print warning message if num_columns exceeds # of colformat
2320 cerr << "(WARNING) # of physical cols exceeds that of colformats" << endl;
2321 cerr << "# of cols = " << num_columns << ", # of colformats = "
2322 << f_colformats.entries() << endl;
2326 // now walk the structure that we built up during parsing, and fill
2329 unsigned cell_counter = 0 ;
2331 for (current_row = 0; ++row_cursor; current_row++)
2333 CC_TPtrSlist<ColDefn> columns(row_cursor.key()->columns());
2335 int vc, kept, count = columns.entries();
2336 for (vc = 0, kept = 0; vc < count; vc++) { // iterate for virtual cells
2338 fprintf(stderr, "(vc,kept,count)=(%d,%d,%d)\n", vc, kept, count);
2343 colcell = columns.at(kept);
2346 abort(); // consider it as fatal
2352 ColFormat* msformat; // most significant format
2353 ColFormat* lsformat; // least significant format
2354 if ((msformat = find_format(colcell->colstart(), &start_index))) {
2356 if ((lsformat = find_format(colcell->colend(), &end_index))) {
2357 if (start_index > end_index) {
2358 int anonym = start_index;
2359 start_index = end_index;
2362 spancols += end_index - start_index;
2365 lsformat = msformat;
2367 else if (! (msformat = find_format(colcell->colref(), &start_index))) {
2368 // neither colstart nor colref are specified.
2369 // Handle implicitly later.
2374 lsformat = msformat;
2376 // make sure the segment has a valid id and add it into the
2377 // _DtCvTable list of cells
2378 _DtCvSegment *segment = ensure_id(colcell->parseg());
2379 setup_cell(segment, colcell, row_cursor.key(), msformat, lsformat);
2381 for (int i = 0 ; i < spancols; i++) {
2382 for (unsigned int j = 0; j < colcell->spanrows(); j++) {
2383 // if there's entrenchment from above rows, skip it.
2384 if (grid[current_row + j][start_index + i])
2386 grid[current_row + j][start_index + i] = segment;
2390 f_segment->handle.table.cells[cell_counter++] = segment ;
2392 columns.removeAt(kept);
2395 count = columns.entries();
2396 for (vc = 0, kept = 0; vc < count; vc++) // iterate for virtual cells
2398 // stick the item into each grid of the table that it
2399 // occupies, including spanning rows and columns
2401 fprintf(stderr, "[vc,kept,count]=[%d,%d,%d]\n", vc, kept, count);
2405 colcell = columns.at(kept);
2412 unsigned int i, start_index = 0;
2413 for (i = 0; i < num_columns; i++) {
2414 if (grid[current_row][i] == NULL) {
2419 if (i == num_columns) { // all columns occupied
2424 ColFormat* msformat = f_colformats.at(start_index);
2425 ColFormat* lsformat = msformat;
2427 // make sure the segment has a valid id and add it into the
2428 // _DtCvTable list of cells
2429 _DtCvSegment *segment = ensure_id(colcell->parseg());
2431 setup_cell(segment, colcell, row_cursor.key(), msformat, lsformat);
2433 f_segment->handle.table.cells[cell_counter++] = segment ;
2435 for (i = 0; i < colcell->spanrows(); i++) {
2436 // if there's entrenchment from above rows, skip it.
2437 if (grid[current_row + i][start_index])
2439 grid[current_row + i][start_index] = segment;
2442 columns.removeAt(kept);
2445 for (unsigned int c = 0; c < num_columns; c++)
2447 if (grid[current_row][c] == NULL)
2449 _DtCvSegment* seg = ensure_id(new_segment(_DtCvCONTAINER));
2450 setup_cell(seg, NULL, row_cursor.key(), f_colformats.at(c),
2451 f_colformats.at(c));
2453 grid[current_row][c] =
2454 f_segment->handle.table.cells[cell_counter++] = seg;
2459 // temp for now deal with blank spots in the table
2461 for (r = 0 ; r < num_rows ; r++)
2462 for (unsigned c = 0; c < num_columns ; c++)
2464 if (grid[r][c] == NULL)
2467 fprintf(stderr, "(DEBUG) blank spot found in the table.\n");
2473 // look for a meaningful grid
2474 for (col = 0; col < num_columns && grid[r][col] == NULL; col++);
2476 if (col == num_columns) // not found
2480 _DtCvSegment* filler = grid[r][col];
2482 for (unsigned int i = c; i < col; i++)
2483 grid[r][i] = filler;
2488 while (grid[r][col] == NULL)
2491 _DtCvSegment* filler = grid[r][col] ;
2494 grid[r][col++] = filler ;
2499 // now create the _DtCvTable layout information
2500 _DtCvTable *table = &f_segment->handle.table ;
2502 table->num_cols = num_columns ;
2504 table->cell_ids = new char *[num_rows + 1] ;
2505 table->cell_ids[num_rows] = NULL;
2507 // walk the grid and insert the segment id information
2508 // into the cell_ids strings
2510 for (r = 0 ; r < num_rows ; r++)
2512 for (unsigned int c = 0 ; c < num_columns ; c++)
2516 // first item in row
2517 table->cell_ids[r] = strdup(grid[r][c]->handle.container.id);
2521 // subsequent items, append space separated id
2523 lent = strlen (table->cell_ids[r]);
2524 leng = strlen (grid[r][c]->handle.container.id);
2525 char *new_ids = new char [lent + leng + 2] ;
2526 *((char *) memcpy(new_ids, table->cell_ids[r], lent) +lent) ='\0';
2527 *((char *) memcpy(new_ids + lent, " ", 1) + 1) = '\0';
2528 *((char *) memcpy(new_ids + lent + 1,
2529 grid[r][c]->handle.container.id, leng) + leng) = '\0';
2530 delete table->cell_ids[r] ;
2531 table->cell_ids[r] = new_ids ;
2534 delete grid[r] ; // clean up column memory
2539 // now apply the formats to the _DtCvTable
2541 _DtCvFrmtOption *justify = new _DtCvFrmtOption[num_columns] ;
2542 char **col_widths = new char *[num_columns] ;
2543 char *justify_chars = new char [num_columns + 1] ;
2545 justify_chars[0] = 0 ;
2547 for (unsigned int i = 0 ; i < num_columns ; i++)
2549 justify[i] = _DtCvOPTION_BAD;
2550 col_widths[i] = NULL;
2551 justify_chars[i] = 0;
2554 ColFormat *format = f_colformats.at(i);
2556 if (format == NULL) continue;
2558 justify[i] = format->justify();
2560 snprintf(buffer, sizeof(buffer), "%d", format->width());
2561 col_widths[i] = strdup(buffer);
2563 if (format->justify() == _DtCvJUSTIFY_CHAR)
2566 buf[0] = format->char_align() ;
2569 len = MIN(strlen(buf), num_columns - slen);
2570 *((char *) memcpy(justify_chars + slen, buf, len) + len) = '\0';
2573 table->col_justify = justify ;
2574 #ifdef COLSPEC_DEBUG
2575 for (i = 0; i < num_columns; i++)
2576 fprintf(stderr, "col%d=%d\n", i, table->col_justify[i]);
2578 table->col_w = col_widths ;
2579 table->justify_chars = justify_chars ;
2584 cerr << "widths: " << endl;
2585 for (int i = 0; i < num_columns; i++)
2586 cerr << table->col_w[i] << endl;
2590 #ifdef TABLE_DEBUG_X
2593 while (table->cell_ids[i])
2594 cerr << table->cell_ids[i++] << endl;
2600 #ifdef HIERARCHY_DEBUG
2602 static char* seg_type_to_string(unsigned long seg_type)
2606 case _DtCvCONTAINER:
2634 static void print_hierarchy_traversal(_DtCvSegment* seg, int depth, ostream& ostr)
2639 unsigned long seg_ptype = seg->type & _DtCvPRIMARY_MASK;
2642 for (i = 0; i < depth; ostr << ' ', i++);
2644 if (seg_ptype != _DtCvCONTAINER)
2645 ostr << seg_type_to_string(seg_ptype) << '\n';
2647 ostr << seg_type_to_string(seg_ptype);
2649 if (seg_ptype == _DtCvCONTAINER) {
2650 if (seg->handle.container.border != _DtCvBORDER_NONE)
2652 ostr << " leading=" << seg->handle.container.leading;
2655 _DtCvSegment* subordinates = seg->handle.container.seg_list;
2657 print_hierarchy_traversal(subordinates, depth+1, ostr);
2659 if (seg_ptype == _DtCvTABLE) {
2660 _DtCvTable *table = &seg->handle.table;
2661 _DtCvSegment** cells = table->cells;
2663 print_hierarchy_traversal(*cells++, depth+1, ostr);
2665 else if (seg_ptype == _DtCvSTRING) {
2666 for (i = 0; i < depth+1; ostr << ' ', i++);
2667 ostr << (char*)seg->handle.string.string << '\n';
2670 // traverse siblings
2671 _DtCvSegment* siblings;
2672 if (siblings = seg->next_seg)
2673 print_hierarchy_traversal(siblings, depth, ostr);
2676 static void print_hierarchy(_DtCvTopicInfo* topic)
2678 _DtCvSegment* top = topic->seg_list;
2682 ofstream ostr("SegmentStructure");
2683 print_hierarchy_traversal(top, depth, ostr);
2690 // colcell can be NULL where cell-related values are not taken
2693 TGDefn::setup_cell(_DtCvSegment* segment, ColDefn* colcell,
2694 RowDefn* row, ColFormat* msformat, ColFormat* lsformat)
2696 _DtCvSegment* parseg;
2698 // segment is optional, but if it's specified it'll be used
2699 // instead of colcell->parseg().
2703 parseg = colcell->parseg();
2705 if (colcell && colcell->justify() != _DtCvOPTION_BAD)
2707 parseg->handle.container.justify = colcell->justify();
2709 if (colcell->justify() == _DtCvJUSTIFY_CHAR)
2711 char charalign = '\0';
2713 if (colcell->char_align()) {
2714 charalign = colcell->char_align();
2716 else if (msformat && msformat->char_align()) {
2717 charalign = msformat->char_align();
2719 else { // always available here thanks to dtd
2720 charalign = char_align();
2723 char *align = new char[2];
2724 align[0] = charalign;
2727 // need to deallocate container.justify_char later
2728 parseg->handle.container.justify_char = align;
2731 else if (msformat && msformat->justify() != _DtCvOPTION_BAD)
2733 parseg->handle.container.justify = _DtCvINHERIT;
2735 else if (justify() != _DtCvOPTION_BAD)
2737 if (justify() == _DtCvJUSTIFY_CHAR)
2739 char charalign = '\0';
2741 if (colcell && colcell->char_align()) {
2742 charalign = colcell->char_align();
2744 else if (msformat && msformat->char_align()) {
2745 charalign = msformat->char_align();
2747 else { // always available here due to dtd
2748 charalign = char_align();
2751 char *align = new char[2];
2752 align[0] = charalign;
2755 // need to deallocate container.justify_char later
2756 parseg->handle.container.justify_char = align;
2759 parseg->handle.container.justify = justify();
2762 if (colcell && colcell->vjustify() != _DtCvOPTION_BAD) {
2763 parseg->handle.container.vjustify = colcell->vjustify();
2765 else if (row->vjustify() != _DtCvOPTION_BAD) {
2766 parseg->handle.container.vjustify = row->vjustify();
2768 else if (vjustify() != _DtCvOPTION_BAD) {
2769 parseg->handle.container.vjustify = vjustify();
2772 int col_sep = CRSEP_NOT_SPECIFIED;
2773 // colsep does not apply to the last column
2774 if (lsformat != f_colformats.last())
2776 // Precedence: col->colformat->tgroup->table
2777 if (colcell && colcell->colsep() != CRSEP_NOT_SPECIFIED) {
2778 col_sep = colcell->colsep();
2780 else if (msformat && msformat->colsep() != CRSEP_NOT_SPECIFIED) {
2781 col_sep = msformat->colsep();
2783 else if (colsep() != CRSEP_NOT_SPECIFIED) {
2786 else if (table() && table()->colsep() != CRSEP_NOT_SPECIFIED) {
2787 col_sep = table()->colsep();
2791 int row_sep = CRSEP_NOT_SPECIFIED;
2792 // rowsep does not apply to the last row
2793 if (f_rows.last() != row) {
2794 // Precedence: col->row->colformat->tgroup->table
2795 if (colcell && colcell->rowsep() != CRSEP_NOT_SPECIFIED) {
2796 row_sep = colcell->rowsep();
2798 else if (row->rowsep() != CRSEP_NOT_SPECIFIED) {
2799 row_sep = row->rowsep();
2801 else if (msformat && msformat->rowsep() != CRSEP_NOT_SPECIFIED) {
2802 row_sep = msformat->rowsep();
2804 else if (rowsep() != CRSEP_NOT_SPECIFIED) {
2807 else if (table() && table()->rowsep() != CRSEP_NOT_SPECIFIED) {
2808 row_sep = table()->rowsep();
2812 if (col_sep == CRSEP_YES && row_sep == CRSEP_YES)
2813 parseg->handle.container.border = _DtCvBORDER_BOTTOM_RIGHT;
2814 else if (col_sep == CRSEP_YES)
2815 parseg->handle.container.border = _DtCvBORDER_RIGHT;
2816 else if (row_sep == CRSEP_YES)
2817 parseg->handle.container.border = _DtCvBORDER_BOTTOM;
2819 // respect border feature of cell, do not overwrite here.