Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtinfo / dtinfo / src / OnlineRender / FeatureSupport.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
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
22  */
23 /*
24  *  $XConsortium: FeatureSupport.C /main/43 1996/12/03 18:22:13 rcs $
25  *
26  * (c) Copyright 1996 Digital Equipment Corporation.
27  * (c) Copyright 1996 Hewlett-Packard Company.
28  * (c) Copyright 1996 International Business Machines Corp.
29  * (c) Copyright 1996 Sun Microsystems, Inc.
30  * (c) Copyright 1996 Novell, Inc. 
31  * (c) Copyright 1996 FUJITSU LIMITED.
32  * (c) Copyright 1996 Hitachi.
33  *
34  */
35
36
37 #define C_Stack
38 #define L_Support
39
40 #define C_TOC_Element
41 #define L_Basic
42
43 #define C_NodeMgr
44 #define L_Managers
45 #define C_WindowSystem
46 #define L_Other
47
48 #include <Prelude.h>
49
50 #include <limits.h>
51 #include "Feature.h"
52 #include "FeatureValue.h"
53 #include "StyleSheetExceptions.h"
54 #include <utility/funcs.h>
55 #include <stream.h>
56
57 #include <Dt/CanvasP.h>
58 #include "CanvasRenderer.hh"
59
60 #ifdef DEBUG
61 #define HIGHLIGHT_DEBUG
62 #endif
63
64 #if defined(UseWideChars) && defined(sun) && !defined(SVR4)
65 #define mbstowcs(a,b,c) Xmbstowcs(a,b,c)
66 #define wcstombs(a,b,c) Xwcstombs(a,b,c)
67 #endif
68
69 int left_margin = 0;
70 int right_margin = 0;
71 int top_margin = 0;
72 int bottom_margin = 0;
73
74 int point2pixel(int size) {
75     return(XmConvertUnits(window_system().toplevel(), XmHORIZONTAL, XmPOINTS,
76                    size, XmPIXELS));  
77 }
78
79 void
80 CanvasRenderer::dofontlist(ElementFeatures&, const FeatureSet&, Symbol**) 
81 {
82   // This member function needs to be removed from header and herein.
83 }
84
85 void
86 CanvasRenderer::dofont(PartialElementFeatures   &return_features,
87                        const FeatureSet &complete,
88                        Symbol **symbols)
89 {
90     const Feature *fontfeature = complete.lookup(symbols[FONT]);
91     if (fontfeature == NULL)
92         return;
93     
94     const FeatureValue* fv = fontfeature->value();
95     assert( fv->type() == FeatureValue::featureset );
96     
97     const FeatureSet* fs = ((FeatureValueFeatureSet*)fv)->value();
98     char* xlfd = _dofont(*fs, symbols);
99     
100     if (xlfd)
101     {
102         return_features.set_font (xlfd);
103         delete[] xlfd;
104         xlfd = NULL;
105     }
106 #ifndef NDEBUG
107     else
108         cerr << "(WARNING) could not resolve font\n";
109 #endif
110     
111     const Feature *subsuperF = fs->lookup(symbols[SUBSUPER]);
112     if (subsuperF) {
113         const char* subsuper = (const char *)*subsuperF->value();
114         if (subsuper) {
115             if (strcasecmp(subsuper, "sub") == 0 ||
116                 strcasecmp(subsuper, "subscript") == 0)
117             {
118                 return_features.subsuper(PartialElementFeatures::subscript);
119             }
120             else if (strcasecmp(subsuper, "super") == 0 ||
121                      strcasecmp(subsuper, "superscript") == 0)
122             {
123                 return_features.subsuper(PartialElementFeatures::superscript);
124             }
125             else
126                 return_features.subsuper(PartialElementFeatures::baseline);
127         }
128     }
129 }
130
131 const char *
132 CanvasRenderer::get_pattern(const char *fallback, const char *weight, const char *slant, int size)
133 {
134     const char *ptr;
135     const char *foundry_str = "*";
136     const char *family_str = "*";
137     const char *weight_str = weight;
138     const char *slant_str = slant;
139     const char *setwidth_name_str = "*";
140     const char *style_str = "*";
141     int  point_size = size;
142     const char *spacing_str = "*";
143     const char *charset_str = "*-*";
144     const char *xlfd;
145
146     Display *display;
147
148     // set the display variable based on if we are printing or displaying online
149
150     if (window_system().printing() == TRUE) {
151         display = window_system().printDisplay();
152     }
153     else {
154         display = window_system().display();
155     }
156     
157
158
159 #ifdef FONT_DEBUG
160     fprintf(stderr, "(DEBUG) fallback=\"%s\" is being tried...",
161             fallback);
162 #endif
163     char *dupfallback = strdup(fallback);
164     if (!dupfallback) {
165         goto pattern_done;
166     }
167     
168     // sample font: 
169     // -dt-application-medium-r-normal-sans-8-80-75-75-p-46-iso8859-1
170     
171     //  hack the foundry name from the front of the xlfd
172     ptr = strtok(dupfallback, "-");
173     if (!ptr) {
174         goto pattern_done;
175     }
176     else {
177         foundry_str = ptr;
178     }
179 #ifdef FONT_DEBUG
180     fprintf(stderr, "(DEBUG)foundry = %s.\n", foundry_str);
181     fflush(stderr);
182 #endif
183     
184     // get family name
185     ptr = strtok(NULL, "-");
186     if (!ptr) {
187         goto pattern_done;
188     }   
189     else {
190         family_str = ptr;
191     }
192 #ifdef FONT_DEBUG
193     fprintf(stderr, "(DEBUG)family = %s.\n", family_str);
194     fflush(stderr);
195 #endif
196     
197     // get weight from fallback string if not specified by
198     // style sheet element
199     ptr = strtok(NULL, "-");
200     
201     // if no more token in fallback pattern is done
202     if (!ptr) {
203         goto pattern_done;
204     }
205     
206     // if the string is a wildcard then no style sheet weight 
207     // was specified so use xlfd field
208     if (weight_str && (strcmp(weight_str, "*") == 0)) {
209         weight_str = ptr;
210     }
211 #ifdef FONT_DEBUG
212     fprintf(stderr, "(DEBUG)weight = %s.\n", weight_str);
213     fflush(stderr);
214 #endif
215     
216     //  get the slant from the fallback string if not specified
217     // by the style sheet element
218     ptr = strtok(NULL, "-");
219     
220     // if no more tokens in fallback then the pattern is done
221     if (!ptr) {
222         goto pattern_done;
223     }
224     
225     // if the string is a wildcard then no style sheet weight 
226     // was specified so use xlfd field
227     if (slant_str && (strcmp(slant_str, "*") == 0)) {
228         slant_str = ptr;
229     }
230 #ifdef FONT_DEBUG
231     fprintf(stderr, "(DEBUG)slant = %s.\n", slant_str);
232     fflush(stderr);
233 #endif
234     
235     // if slant is specified as ROMAN or ITALIC change to "i" or "r"
236     if (strcasecmp(slant_str, "roman") == 0) {
237         slant_str = "r";
238     }
239     else if (strcasecmp(slant_str, "italic") == 0) {
240         slant_str = "i";
241     }
242     
243     //  get the setwidth name from the front of the xlfd
244     ptr = strtok(NULL, "-");
245     // if no more tokens in fallback then the pattern is done
246     if (!ptr) {
247         goto pattern_done;
248     }
249 #ifdef FONT_DEBUG
250     fprintf(stderr, "(DEBUG)setwidth = %s.\n", ptr);
251     fflush(stderr);
252 #endif
253     
254     //  get the add style name from the front of the xlfd
255     ptr = strtok(NULL, "-");
256     // if no more tokens in fallback then the pattern is done
257     if (!ptr) {
258         goto pattern_done;
259     }
260     else {
261         style_str = ptr;
262     }
263 #ifdef FONT_DEBUG
264     fprintf(stderr, "(DEBUG)style_str = %s.\n", style_str);
265     fflush(stderr);
266 #endif
267     
268     //  get the pixel size from the front of the xlfd
269     ptr = strtok(NULL, "-");
270     // if no more tokens in fallback then the pattern is done
271     if (!ptr) {
272         goto pattern_done;
273     }
274 #ifdef FONT_DEBUG
275     fprintf(stderr, "(DEBUG)pixel size = %s.\n", ptr);
276     fflush(stderr);
277 #endif
278     
279     //  get the point size from the front of the xlfd
280     ptr = strtok(NULL, "-");
281     
282     // make sure there is a token
283     if (ptr) {
284         
285         // a point size of -1 indicates that no style sheet size
286         // was specified.  in this case, we'll convert the
287         // xlfd field and use that size
288         
289         // ??? should put a check here to make sure ptr is an integer value
290         if (point_size == -1) {
291             point_size = atoi(ptr);
292         }
293         point_size = 10 * point_size;
294         
295 #ifdef FONT_DEBUG
296         fprintf(stderr, "(DEBUG)point size = %d.\n", point_size);
297         fflush(stderr);
298 #endif
299     }
300     // else no more tokens in fallback then the pattern is done
301     else {      
302         // make sure we replace default of -1 with something
303         // before making the pattern
304         if (point_size == -1) {
305             point_size = 140 + (20 * f_font_scale);;
306         }
307         goto pattern_done;
308     }       
309     
310     // apply scaling factor
311     point_size = point_size + (20 * f_font_scale);
312     
313     //  get the resolution x from the front of the xlfd
314     ptr = strtok(NULL, "-");
315     // if no more tokens in fallback then the pattern is done
316     if (!ptr) {
317         goto pattern_done;
318     }
319 #ifdef FONT_DEBUG
320     fprintf(stderr, "(DEBUG)x resolution = %s.\n", ptr);
321     fflush(stderr);
322 #endif
323     
324     //  get the resolution y from the front of the xlfd
325     ptr = strtok(NULL, "-");
326     // if no more tokens in fallback then the pattern is done
327     if (!ptr) {
328         goto pattern_done;
329     }
330 #ifdef FONT_DEBUG
331     fprintf(stderr, "(DEBUG)y resolution = %s.\n", ptr);
332     fflush(stderr);
333 #endif
334     
335     //  get the spacing from the front of the xlfd
336     ptr = strtok(NULL, "-");
337     // if no more tokens in fallback then the pattern is done
338     if (!ptr) {
339         goto pattern_done;
340     }
341     else {
342         spacing_str = ptr;
343     }
344 #ifdef FONT_DEBUG
345     fprintf(stderr, "(DEBUG)setwidth = %s.\n", ptr);
346     fflush(stderr);
347 #endif
348     
349     //  get the average width from the front of the xlfd
350     ptr = strtok(NULL, "-");
351     // if no more tokens in fallback then the pattern is done
352     if (!ptr) {
353         goto pattern_done;
354     }
355 #ifdef FONT_DEBUG
356     fprintf(stderr, "(DEBUG)average width = %s.\n", ptr);
357     fflush(stderr);
358 #endif
359     
360     //  get the charset registery and encoding 
361     //  if a font really does include a $ i'm screwed
362     
363     ptr = strtok(NULL, "$");
364     // if no more tokens in fallback then the pattern is done
365     if (!ptr) {
366         goto pattern_done;
367     }
368     else {
369         charset_str = ptr;
370     }
371     
372 #ifdef FONT_DEBUG
373     fprintf(stderr, "(DEBUG)charset = %s.\n", charset_str);
374     fflush(stderr);
375 #endif
376 pattern_done:
377     
378     char pattern[256];
379     // -dt-application-medium-r-normal-sans-8-80-75-75-p-46-iso8859-1
380     sprintf (
381         pattern, 
382         "-%s-%s-%s-%s-normal-%s-*-%d-*-*-%s-*-%s", 
383         foundry_str ? foundry_str : "*",
384         family_str  ? family_str  : "*",
385         weight_str  ? weight_str  : "*",
386         slant_str   ? slant_str   : "*",
387         style_str   ? style_str   : "*",
388         point_size,
389         spacing_str ? spacing_str : "*",
390         charset_str ? charset_str : "*-*"
391         );
392     
393     
394     //  If the font exists, return a copy
395     if (XLoadQueryFont(display, pattern)) {
396 #ifdef FONT_DEBUG
397         printf("pattern = %s.\n", pattern);
398 #endif
399         xlfd = strdup(pattern);
400         return(xlfd);
401     }
402     
403     // determine if the font is a standard application font name
404     if ( (strcmp(foundry_str, "dt") == 0) &&  
405          (strcmp(family_str, "application") == 0)) {
406         
407         // round the point size to the nearest match
408         if (point_size < 90 ) point_size = 80;
409         else if (point_size < 110) point_size = 100;
410         else if (point_size < 130) point_size = 120;
411         else if (point_size < 160) point_size = 140;
412         else if (point_size < 210) point_size = 180;
413         else point_size = 240;
414
415 #ifdef FONT_DEBUG
416         printf("point size = %d.\n", point_size);
417 #endif
418         
419         sprintf (
420             pattern, 
421             "-%s-%s-%s-%s-normal-%s-*-%d-*-*-%s-*-%s", 
422             foundry_str ? foundry_str : "*",
423             family_str  ? family_str  : "*",
424             weight_str  ? weight_str  : "*",
425             slant_str   ? slant_str   : "*",
426             style_str   ? style_str   : "*",
427             point_size,
428             spacing_str ? spacing_str : "*",
429             charset_str ? charset_str : "*-*"
430             );
431         
432         //  If font does not exist, try using the font cache 
433         if (XLoadQueryFont(display, pattern)) {
434 #ifdef FONT_DEBUG
435             printf("pattern = %s.\n", pattern);
436 #endif
437             xlfd = strdup(pattern);
438             return(xlfd);       
439         }
440     } // end if desktop font
441             
442         
443     // if still not found,  lookup string in cache.  
444     // point_size and scale are extracted first.
445
446     xlfd = f_fontcache.lookup(family_str,
447                               weight_str,
448                               slant_str,
449                               (point_size - (20 * f_font_scale)) / 10,
450                               charset_str,
451                               f_font_scale, 
452                               fallback);    
453
454 #ifdef FONT_DEBUG
455     printf("xlfd = %s.\n", xlfd);
456 #endif
457     return(xlfd);
458                               
459 }
460
461 char*
462 CanvasRenderer::_dofont(const FeatureSet &fs, Symbol** symbols)
463 {
464     const char *fallback = NULL;
465     
466     const Feature *fallbackF = fs.lookup(symbols[FALLBACK]);
467     if (fallbackF) {
468         if (fallback = *fallbackF->value()) {
469             if (strcasecmp(fallback, "sans") == 0)
470                 fallback = f_sans ;
471             else if (strcasecmp(fallback, "serif") == 0)
472                 fallback = f_serif ;
473             else if (strcasecmp(fallback, "mono") == 0)
474                 fallback = f_mono ;
475             else if (strcasecmp(fallback, "symbol") == 0)
476                 fallback = f_symbol ;
477             else 
478                 fallback = f_sans;
479         }
480         
481 #ifdef FONT_DEBUG
482         if (fallback)
483             fprintf(stderr, "(DEBUG) fallback=\"%s\"\n", fallback);
484         else
485             cerr << "(WARNING) invalid fallback \"" << fallback <<
486                 "\" specified." << endl;
487 #endif
488     }
489     
490     const Feature *weightF      = fs.lookup(symbols[WEIGHT]);
491     const Feature *slantF       = fs.lookup(symbols[SLANT]);
492     const Feature *sizeF        = fs.lookup(symbols[SIZE]);
493     
494     const char *name = NULL, *foundry = NULL, *charset = NULL;
495     
496     // need to add something for spacing here
497     //const Feature *spacingF   = fs.lookup(symbols[SPACING]);
498     const char* font;    
499     char* xlfd = NULL;
500     
501     int i;
502     for (i = 0; i < fs.entries(); i++) {
503         
504         Feature* entry;
505         if ((entry = fs.at(i)) == NULL)
506             continue;
507         
508         if (entry->name() == *symbols[FAMILY]) {
509             
510             const FeatureSet* familyFS;
511             if ((familyFS = *entry->value()) == NULL)
512                 continue;
513             
514             // resolve name,foundry,charset
515             const Feature* nameF = familyFS->lookup(symbols[NAME]);
516             if (nameF) {
517                 name = *nameF->value();
518             }
519             else {
520 #ifdef FONT_DEBUG
521                 cerr << "(WARNING) You need to specify either family name "
522                     "or font fallback in stylesheet." << endl;
523 #endif
524                 continue;
525             }
526             
527             const Feature* foundryF = familyFS->lookup(symbols[FOUNDRY]);
528             if (foundryF) {
529                 foundry = *foundryF->value();
530             }
531             const Feature* charsetF = familyFS->lookup(symbols[CHARSET]);
532             if (charsetF)
533                 charset = *charsetF->value();
534             else {
535 #ifdef FONT_DEBUG
536                 cerr << "(WARNING) You need to specify charset if you "
537                     "specify family name in stylesheet." << endl;
538 #endif
539                 continue;
540             }
541             
542             assert( name && charset );
543             
544             font = f_fontcache.lookup(name,
545                                       (const char *)*weightF->value(),
546                                       (const char *)*slantF->value(),
547                                       (int)*sizeF->value(),
548                                       charset,
549                                       f_font_scale); // scale factor 
550             
551             if (font == NULL && fallback) {
552                 
553                 name = fallback;
554                 
555                 if ((font = f_fontcache.lookup(name,
556                                                (const char *)*weightF->value(),
557                                                (const char *)*slantF->value(),
558                                                (int)*sizeF->value(),
559                                                charset,
560                                                f_font_scale) // scale factor 
561                     ) == NULL) {
562                     continue;
563                 }
564             }
565             
566             // if xlfd already defined, create a font list
567             if (xlfd) {
568                 xlfd = (char*)realloc(xlfd, strlen(xlfd) + strlen(font) + 3);
569                 strcat(xlfd, ",");
570                 strcat(xlfd, font);
571             }
572             // otherwise, just dup the font streing
573             else {
574                 xlfd = strdup(font);
575             }
576             
577         }  // end if entry name is a font family
578
579     } // end for each feature support entry
580     
581     //  if we have a font definition at this point where almost home
582     
583     if (xlfd) {
584         
585         //  if a comma appears in the xlfd string, then then it is a font
586         //  list so append a colon to the end of the font list string
587         
588         if (strchr(xlfd, ',')) {
589             strcat(xlfd, ":");
590         }
591     }
592     
593     // if no font families were specified, just use what we have from 
594     // the fallback and whatever font attributes were specified
595     
596     else if (fallback) {
597         
598         font = get_pattern(fallback, 
599                            (const char *)*weightF->value(), 
600                            (const char *)*slantF->value(),
601                            (int)*sizeF->value());
602
603         if (font && *font) {
604             xlfd = strdup(font);
605         }
606
607         // if we still can't find one go with whatever.
608
609         else {
610             xlfd = "-*-*-*-*-*-*-*-*-*-*-*-*-*";
611         }
612 #ifdef FONT_DEBUG
613         fprintf(stderr, "resulting in \"%s\".\n", xlfd);
614 #endif
615         
616     } // else if fallback
617
618
619         
620 #ifdef JBM
621         // see if we have a 2 part font family (separated by comma)
622         const char *family = *familyF->value();
623         const char *p = family ;
624     while (*p && (*p != ','))
625         p++ ;
626     char *fallback = 0;
627     
628     // p points to comma or end of string 
629     if (*p == ',')
630     {
631         int len = p - family ;
632         fallback = new char[len + 1] ;
633         strncpy(fallback, family, len);
634         fallback[len] = 0 ;
635         
636         do p++; while (isspace(*p));
637         family = p ;
638     }
639     
640 #endif
641     
642 #ifdef JBM_FONT_DEBUG
643     cerr << "name:     " << name << endl;
644     cerr << "foundry:  " << foundry << endl;
645     cerr << "charset:  " << charset << endl;
646     if (familyF)
647         cerr << "family:   (yes)" << endl;
648     else
649         cerr << "family:   (no)" << endl;
650     
651     if (weightF)
652         cerr << "weight:   " << (const char *)*weightF->value() << endl;
653     else
654         cerr << "weight:   (no)" << endl;
655     
656     if (slantF)
657         cerr << "slant:    " << (const char *)*slantF->value() << endl;
658     else
659         cerr << "slant:    (no)" << endl;
660     
661     if (sizeF)
662         cerr << "size:     " << (int)*sizeF->value() << endl;
663     else
664         cerr << "size:     (no)" << endl;
665     
666     cerr << "scale:    " << f_font_scale << endl;
667     cerr << "fallback: " << fallback << endl;
668 #endif
669     
670 #if defined FONT_DEBUG || defined FONT_DEBUG_XLFD
671     if (xlfd)
672         cerr << "xlfd: " << xlfd << endl;
673     else
674         cerr << "xlfd: (nil)" << endl;
675 #endif
676     
677     return xlfd;
678 }
679
680 void
681 CanvasRenderer::dounderline(ElementFeatures&, const FeatureSet&, Symbol**)
682 {
683   cerr << "dounderline: called " << endl;
684 }
685
686 #ifdef NOTIMPLEMENTED
687 void
688 CanvasRenderer::dofooter(ElementFeatures&, const FeatureSet&, Symbol**)
689 {
690   cerr << "dofooter: called " << endl;
691 }
692
693 void
694 CanvasRenderer::doheader(ElementFeatures&, const FeatureSet&, Symbol**)
695 {
696   cerr << "doheader: called " << endl;
697 }
698 #endif
699
700 void
701 CanvasRenderer::domedia(ElementFeatures &return_features, 
702                         const FeatureSet &complete, Symbol **symbols)
703 {
704   cerr << "domedia: called " << endl;
705
706   const FeatureSet *mset = *complete.lookup(symbols[MEDIA])->value();
707
708   const Feature *orient = mset->lookup(symbols[ORIENTATION]);
709
710   if (orient)  {
711
712       const char *orientation =  *orient->value();
713
714       if (strcasecmp(orientation, "portrait") == 0) {
715           return_features.orientation("portrait");
716       }
717       else if (strcasecmp(orientation, "landscape") == 0) {
718           return_features.orientation("landscape");
719       }
720   } // end if orientation feature
721
722 }
723
724 void
725 CanvasRenderer::dobreak(PartialElementFeatures  &return_features,
726                         const FeatureSet &local,
727                         const FeatureSet& /*complete*/, Symbol **symbols)
728 {
729   const char *breakvalue =  *local.lookup (*symbols[LINEBREAK])->value();
730
731 #ifdef BREAK_DEBUG
732   cerr << "linebreak: " << breakvalue << endl;
733 #endif  
734   if (strcasecmp (breakvalue, "before") == 0)
735     return_features.linebreak (LINEBREAK_BEFORE);
736   else
737     if (strcasecmp (breakvalue, "after") == 0)
738       return_features.linebreak (LINEBREAK_AFTER);
739   else
740     if (strcasecmp (breakvalue, "both") == 0)
741       return_features.linebreak (LINEBREAK_BOTH);
742
743
744 #ifdef JBM
745   node *new_spnode = 0 ;
746   const char *breakvalue = *local.lookup(*symbols[BREAK])->value();
747   
748   if (strcasecmp(breakvalue, "line") == 0)
749     {
750       // get interparagraph spacing 
751       const Feature *spacefp = complete.deep_lookup(symbols[MARGIN],
752                                                     symbols[TOP], 0); 
753
754       int spacing = 10 ;        // default value 
755
756       if (spacefp)
757         spacing = point2pixel(*spacefp->value());
758
759 #ifdef DEBUG
760       cerr << "break: spacing = " << spacing << endl ;
761 #endif
762
763       // insert a space between paragraphs 
764 #ifdef TML_NO_THIS_ASSIGNMENT
765       model* to_model = current_node->get_model();
766       new_spnode = new(to_model) space_node(spacing, to_model);
767 #else
768       new_spnode = new space_node(spacing, current_node->get_model());
769 #endif
770       new_spnode->vcc(current_node->vcc());
771     }
772   return new_spnode ;
773 #endif
774 }
775
776
777 void
778 CanvasRenderer::dopage(PartialElementFeatures   &return_features,
779                         const FeatureSet &local,
780                        const FeatureSet& /*complete*/, Symbol **symbols)
781 {
782     const char *breakvalue =  *local.lookup (*symbols[PAGEBREAK])->value();
783     
784     cerr << "pagebreak: " << breakvalue << endl;
785
786     if (strcasecmp (breakvalue, "before") == 0) {
787         return_features.pagebreak (PAGEBREAK_BEFORE);
788     }
789     else {
790         if (strcasecmp (breakvalue, "after") == 0) {
791             return_features.pagebreak (PAGEBREAK_AFTER);
792         }
793         else {
794             if (strcasecmp (breakvalue, "both") == 0) {
795                 return_features.pagebreak(PAGEBREAK_BOTH);
796             }
797         }
798     }
799 }
800
801 void
802 CanvasRenderer::domargin(ElementFeatures        &return_features,
803                          const FeatureSet &complete,
804                          Symbol **symbols)
805 {
806   const FeatureSet *marginset = *complete.lookup(symbols[MARGIN])->value();  
807
808   int first = 0;
809   int left  = 0;
810   int right = 0;
811   int top   = 0;
812   int bottom= 0;
813
814   try
815   {
816     //const Feature *f = marginset->lookup(symbols[FIRST]);
817     const Feature *l = marginset->lookup(symbols[LEFT]);
818     const Feature *r = marginset->lookup(symbols[RIGHT]);
819     const Feature *t = marginset->lookup(symbols[TOP]);
820     const Feature *b = marginset->lookup(symbols[BOTTOM]);
821
822
823     if (l) left = point2pixel(*l->value());
824     if (r) right = point2pixel(*r->value());
825     if (t) top = point2pixel(*t->value());
826     if (b) bottom = point2pixel(*b->value());
827
828     // external systems for print form
829
830     left_margin = left;
831     right_margin = right;
832     top_margin = top;
833     bottom_margin = bottom;
834
835   }
836   catch_noarg (StyleSheetException &)
837     {
838 #ifdef DEBUG
839       cerr << "MarginFPtml: style sheet exception" << endl;
840 #endif
841     }
842   end_try ;
843
844 #ifdef DEBUG_MARGINS
845   cout << "[ " << left <<  ", " << right << "] [ " 
846        << top << ", " << bottom << "]" << endl; 
847
848 #endif
849
850   return_features.margin().first (first);
851   return_features.margin().left (left);
852   return_features.margin().right (right);
853   return_features.margin().top (top);
854   return_features.margin().bottom (bottom);
855
856
857 #ifdef JBM
858 #ifdef TML_NO_THIS_ASSIGNMENT
859   model* to_model = current_node->get_model();
860   prop_vec *pvec = new(to_model) prop_vec(to_model) ;
861 #else
862   prop_vec *pvec = new prop_vec(current_node->get_model()) ;
863 #endif
864   
865   pvec->attach(make_margin_prop(left, right, top, bottom,
866                                 current_node->get_model())); 
867   
868   current_node->prop_attach(pvec);
869
870 #endif
871 }
872
873 void
874 CanvasRenderer::doborder (ElementFeatures &return_features,
875                           const FeatureSet &local,
876                           Symbol **symbols)
877 {
878   const Feature *feature = local.lookup(symbols[BORDER]);
879   if (feature == NULL)
880     return ;
881
882   const FeatureValue *fv = feature->value();
883
884   assert (fv->type() == FeatureValue::featureset);
885
886   if (fv->type() == FeatureValue::featureset)
887     {
888       const FeatureSet *fs = ((FeatureValueFeatureSet*)fv)->value();
889
890       const Feature *display_feature = fs->lookup(symbols[DISPLAY]);
891
892       if (display_feature) {
893         const char *border  = *display_feature->value();
894
895         // valid values are one of:
896         // All Bottom Horiz Left Right Top Vert
897
898         if (strcasecmp (border, "all") == 0)
899           return_features.border (_DtCvBORDER_FULL);
900         else if (strcasecmp (border, "bottom") == 0)
901           return_features.border (_DtCvBORDER_BOTTOM);
902         else if (strcasecmp (border, "horiz") == 0)
903           return_features.border (_DtCvBORDER_HORZ);
904         else if (strcasecmp (border, "left") == 0)
905           return_features.border (_DtCvBORDER_LEFT);
906         else if (strcasecmp (border, "right") == 0)
907           return_features.border (_DtCvBORDER_RIGHT);
908         else if (strcasecmp (border, "top") == 0)
909           return_features.border (_DtCvBORDER_TOP);
910         else if (strcasecmp (border, "vert") == 0)
911           return_features.border (_DtCvBORDER_VERT);
912       }
913       else { // default to _DtCvBORDER_FULL (hard-coded default)
914           return_features.border (_DtCvBORDER_FULL);
915       }
916
917       const Feature *width_feature = fs->lookup(symbols[THICKNESS]);
918
919       if (width_feature)
920         return_features.border_width(point2pixel(*width_feature->value()));
921     }  
922 }
923
924
925 void
926 CanvasRenderer::doposition(PartialElementFeatures  &return_features,
927                            const FeatureSet &local, 
928                            Symbol **symbols)
929
930 {
931   const FeatureSet *pset = *local.lookup(symbols[POSITION])->value();
932
933   const Feature *horiz = pset->lookup(symbols[HORIZ]);
934   const Feature *vert  = pset->lookup(symbols[VERT]);
935
936   if (horiz)
937     {
938       const char *hvalue = *horiz->value();
939       if (strcasecmp (hvalue, "lcorner") == 0)
940         return_features.position().horiz(_DtCvJUSTIFY_LEFT_CORNER) ;
941       else
942       if (strcasecmp (hvalue, "left") == 0)
943         return_features.position().horiz(_DtCvJUSTIFY_LEFT) ;
944       else
945       if (strcasecmp (hvalue, "lmargin") == 0)
946         return_features.position().horiz(_DtCvJUSTIFY_LEFT_MARGIN) ;
947       else
948       if (strcasecmp (hvalue, "rcorner") == 0)
949         return_features.position().horiz(_DtCvJUSTIFY_RIGHT_CORNER) ;
950       else
951       if (strcasecmp (hvalue, "right") == 0)
952         return_features.position().horiz(_DtCvJUSTIFY_RIGHT) ;
953       else
954       if (strcasecmp (hvalue, "rmargin") == 0)
955         return_features.position().horiz(_DtCvJUSTIFY_RIGHT_MARGIN) ;
956       else
957       if (strcasecmp (hvalue, "center") == 0)
958         return_features.position().horiz(_DtCvJUSTIFY_CENTER) ;
959     }
960
961   if (vert)
962   {
963       const char *vvalue = *vert->value();
964       if (strcasecmp (vvalue, "top") == 0)
965         return_features.position().vert(_DtCvJUSTIFY_TOP) ;
966       else
967       if (strcasecmp (vvalue, "bottom") == 0)
968         return_features.position().vert(_DtCvJUSTIFY_BOTTOM) ;
969       else
970       if (strcasecmp (vvalue, "middle") == 0)
971         return_features.position().vert(_DtCvJUSTIFY_CENTER) ;
972     }
973
974 }
975
976 void
977 CanvasRenderer::dolayout(PartialElementFeatures  &return_features,
978                          const FeatureSet &local,
979                          const FeatureSet &complete, 
980                          Symbol **symbols)
981 {
982   const FeatureSet *locallayoutset = *local.lookup (symbols[LAYOUT])->value();
983   const FeatureSet *layoutset = *complete.lookup (symbols[LAYOUT])->value();
984
985   Layout &layout = return_features.layout() ;
986
987   const Feature *feature ;
988
989   feature = locallayoutset->lookup (symbols[ASPACE]) ;
990   if (feature != NULL)
991     layout.aspace(point2pixel(*feature->value()));
992
993   feature = locallayoutset->lookup (symbols[BSPACE]) ;
994   if (feature != NULL)
995     layout.bspace(point2pixel(*feature->value()));
996
997   feature = layoutset->lookup (symbols[LEADING]) ;
998   if (feature != NULL)
999     layout.leading(point2pixel(*feature->value()));
1000
1001   feature = locallayoutset->lookup (symbols[FINDENT]) ;
1002   if (feature != NULL)
1003     layout.findent(point2pixel(*feature->value()));
1004
1005   feature = locallayoutset->lookup (symbols[LINDENT]) ;
1006   if (feature != NULL)
1007     layout.lindent(point2pixel(*feature->value()));
1008
1009   feature = locallayoutset->lookup (symbols[RINDENT]) ;
1010   if (feature != NULL)
1011     layout.rindent(point2pixel(*feature->value()));
1012
1013   // type
1014
1015   feature = layoutset->lookup (symbols[FLOW]);
1016   if (feature)
1017     {
1018       const char *flow = *feature->value();
1019       if (flow)
1020         {
1021           if (strcasecmp (flow, "verbatim") == 0)
1022             layout.flow (_DtCvLITERAL);
1023           else if (strcasecmp (flow, "filled") == 0) 
1024             layout.flow (_DtCvDYNAMIC);
1025         }
1026     }
1027   // justify
1028   feature = layoutset->lookup (symbols[JUSTIFY]);
1029   if (feature)
1030     {
1031       const char *justify = *feature->value();
1032       if (justify)
1033         {
1034           if (strcasecmp (justify, "left") == 0)
1035             layout.justify (_DtCvJUSTIFY_LEFT);
1036           else if (strcasecmp (justify, "right") == 0)
1037             layout.justify (_DtCvJUSTIFY_RIGHT);
1038           else if (strcasecmp (justify, "center") == 0)
1039             layout.justify (_DtCvJUSTIFY_CENTER);
1040         }
1041     }
1042   // wrap
1043   feature = layoutset->lookup (symbols[WRAP]) ;
1044   if (feature)
1045     {
1046       const char *wrap = *feature->value();
1047       if (wrap)
1048         {
1049           if (strcasecmp (wrap, "block") == 0)
1050             layout.wrap (_DtCvWRAP);
1051           else if (strcasecmp (wrap, "join") == 0)
1052             layout.wrap (_DtCvWRAP_JOIN);
1053           else if (strcasecmp (wrap, "none") == 0)
1054             layout.wrap(_DtCvWRAP_NONE);
1055         }
1056     }
1057
1058 }
1059
1060 void
1061 CanvasRenderer::dowrap(ElementFeatures &, const FeatureSet &, Symbol **) 
1062 {}
1063
1064 void
1065 CanvasRenderer::dohighlight(ElementFeatures     &return_features,
1066                             const FeatureSet &complete,
1067                             Symbol **symbols) 
1068 {
1069   const FeatureSet *hiliteset = *complete.lookup(symbols[HIGHLIGHT])->value();
1070 #ifdef HILITE_DEBUG
1071   cerr << "HIGHLIGHT feature";
1072   CC_TPtrSlistIterator<Feature> iter(*(FeatureSet*)hiliteset);
1073   Feature* item;
1074   for(; item = iter(); ) {
1075     cerr << ' ' << (const char*)item->name().name();
1076   }
1077   cerr << " found" << endl;
1078 #endif
1079
1080   const Feature *underlineF = hiliteset->lookup(symbols[UNDERLINE]);
1081   int underline = 0;
1082   if (underlineF)
1083     underline = *underlineF->value();
1084   if (underline)
1085     return_features.highlight().underline(True);
1086   else
1087     return_features.highlight().underline(False);
1088     
1089   const Feature *strikethroughF = hiliteset->lookup(symbols[STRIKETHROUGH]);
1090   int strikethrough = 0;
1091   if (strikethroughF)
1092     strikethrough = *strikethroughF->value();
1093   if (strikethrough)
1094     return_features.highlight().strikethrough(True);
1095   else
1096     return_features.highlight().strikethrough(False);
1097
1098   const Feature *overlineF = hiliteset->lookup(symbols[OVERLINE]);
1099   int overline = 0;
1100   if (overlineF)
1101     overline = *overlineF->value();
1102   if (overline)
1103     return_features.highlight().overline(True);
1104   else
1105     return_features.highlight().overline(False);
1106
1107   const Feature *bgcolorF = hiliteset->lookup(symbols[BGCOLOR]);
1108   if (bgcolorF)
1109     return_features.highlight().bg_color(*bgcolorF->value());
1110
1111   const Feature *fgcolorF = hiliteset->lookup(symbols[FGCOLOR]);
1112   if (fgcolorF)
1113     return_features.highlight().fg_color(*fgcolorF->value());
1114 }
1115
1116 void
1117 CanvasRenderer::doprefix(ElementFeatures  &return_features,
1118                          const FeatureSet &local,
1119                          const FeatureSet &complete,
1120                          Symbol **symbols)
1121 {
1122   // NOTE: need to inform find_search_hits that vcc counting is to skip this
1123   // node...perhaps because vcc is 0 or maybe set a flag?
1124
1125 #ifdef PREFIX_TESTING
1126   cerr << "doprefix(): " <<  endl;
1127 #endif
1128
1129   const Feature *prefix_text = local.deep_lookup(symbols[PREFIX],
1130                                                  symbols[CONTENT],0);
1131   if (prefix_text)
1132     {
1133       const char *text = *prefix_text->value();
1134
1135       if (text)
1136         {
1137           PartialElementFeatures &features = return_features.prefix();
1138
1139           features.text (text);
1140
1141           const Feature    *prefixF = local.lookup(*symbols[PREFIX]);
1142           const FeatureSet *prefix_set = ((FeatureValueFeatureSet*)prefixF->value())->value () ;
1143           FeatureSet *merged = new FeatureSet(complete, *prefix_set);
1144   
1145 #ifdef PREFIX_DEBUG
1146           cerr << "Prefix Set: " << *prefix_set << endl;
1147 #endif
1148
1149           CC_TPtrSlistIterator<Feature> next(*(FeatureSet*)prefix_set);
1150           while (++next)
1151             {
1152               // for each feature, look up the id in the local symbol table, and use
1153               // that id as an index into a the table of processing objects which
1154               // handle each feature
1155               
1156               // get id and do lookup 
1157               
1158               const Symbol &feature = next.key()->name();
1159               
1160 #ifdef FEATURE_DEBUG
1161               cerr << "\tfeature = " << feature.name() << endl;
1162 #endif        
1163               
1164               if (feature == *symbols[LINEBREAK]) 
1165                 dobreak(features, *prefix_set, complete, symbols);
1166               else 
1167                 if (feature == *symbols[FONT])
1168                   dofont(features, *merged, symbols); 
1169               else if (feature == *symbols[POSITION])
1170                 doposition (features, *prefix_set, symbols);
1171               else if (feature == *symbols[LAYOUT])
1172                 dolayout (features, *prefix_set, *merged, symbols);
1173             }
1174           delete merged ;
1175         }
1176     }
1177 }
1178
1179 void
1180 CanvasRenderer::dosuffix(ElementFeatures        &return_features,
1181                          const FeatureSet &local,
1182                          const FeatureSet &complete,
1183                          Symbol **symbols)
1184 {
1185   
1186   const Feature *suffix_text = local.deep_lookup(symbols[SUFFIX],
1187                                                  symbols[CONTENT],0);
1188   if (suffix_text)
1189     {
1190       const char *text = *suffix_text->value();
1191       
1192       if (text)
1193         {
1194           PartialElementFeatures &features = return_features.suffix();
1195           
1196           const Feature    *suffixF = local.lookup(*symbols[SUFFIX]);
1197           const FeatureSet *suffix_set = ((FeatureValueFeatureSet*)suffixF->value())->value () ;
1198           FeatureSet *merged = new FeatureSet(complete, *suffix_set);
1199           
1200           CC_TPtrSlistIterator<Feature> next(*(FeatureSet*)suffix_set);
1201           while (++next)
1202             {
1203               // for each feature, look up the id in the local symbol table, and use
1204               // that id as an index into a the table of processing objects which
1205               // handle each feature
1206               
1207               // get id and do lookup 
1208               
1209               const Symbol &feature = next.key()->name();
1210               
1211 #ifdef FEATURE_DEBUG
1212               cerr << "\tfeature = " << feature.name() << endl;
1213 #endif        
1214               
1215               if (feature == *symbols[LINEBREAK]) 
1216                 dobreak(features, *suffix_set, complete, symbols);
1217               else 
1218                 if (feature == *symbols[FONT])
1219                   dofont(features, *merged, symbols); 
1220               else if (feature == *symbols[POSITION])
1221                 doposition (features, *suffix_set, symbols);
1222               else if (feature == *symbols[LAYOUT])
1223                 dolayout (features, *suffix_set, *merged, symbols);
1224             }
1225           delete merged ;
1226           
1227           features.text (text);
1228         }
1229     }
1230 #ifdef JBM
1231   // NOTE: need to inform find_search_hits that vcc counting is to skip this
1232   // node...perhaps because vcc is 0 or maybe set a flag?
1233   
1234   // NOTE: need to handle other suffix things too
1235   // (space, font, wrap, tab, margins, highlight, underline, color)
1236   
1237   node *suffix_node = 0 ;
1238   gnode *new_gnode = 0;
1239   const Feature *suffix_text = local.deep_lookup(symbols[SUFFIX],
1240                                                  symbols[CONTENT],0);
1241   if (suffix_text)
1242     {
1243       const char *text = *suffix_text->value();
1244 #ifdef TML_NO_THIS_ASSIGNMENT
1245       model* to_model = current_node->get_model();
1246       new_gnode = new(to_model) gnode(to_model);
1247 #else
1248       new_gnode = new gnode(current_node->get_model());
1249 #endif
1250 #ifdef UseWideChars
1251       int size = strlen(text);
1252       TML_CHAR_TYPE* buffer = new TML_CHAR_TYPE[ size + 1 ];
1253       int nc = mbstowcs(buffer, text, size + 1);
1254       assert( nc >= 0 );
1255       new_gnode->attach_data(buffer, nc);
1256       delete[] buffer;
1257 #else 
1258       new_gnode->attach_data((void*)text, strlen(text));
1259 #endif
1260       
1261       // process suffix features recursively
1262       const Feature *suffixF = local.lookup(*symbols[SUFFIX]);
1263       
1264       const FeatureSet *suffix_set = ((FeatureValueFeatureSet*)suffixF->value())->value();
1265       
1266 #ifdef TML_NO_THIS_ASSIGNMENT
1267       to_model = current_node->get_model();
1268       suffix_node = new(to_model) bnode(to_model) ;
1269 #else
1270       suffix_node = new bnode(current_node->get_model()) ;
1271 #endif
1272       
1273       // set vcc to ULONG_MAX. When looking for search hits, if we are down
1274       // this branch then the main trunk (actual data) contains the vcc we are
1275       // looking for. This large vcc prevents the search from continuing to
1276       // the right into any prefix nodes.
1277       
1278       suffix_node->vcc(ULONG_MAX); 
1279       
1280       node_dir dir = n_down ;
1281       node *root = suffix_node;
1282       
1283       // NOTE: ordering of merge parameters counts 
1284       FeatureSet *merged = new FeatureSet(complete, *suffix_set);
1285       do_features(root, dir, *suffix_set, *merged, symbols); // recursive call 
1286       delete merged ;
1287       
1288       root->connect_node(new_gnode, dir);
1289     }
1290   return suffix_node ;
1291 #endif
1292 }
1293
1294 void
1295 CanvasRenderer::docolor(ElementFeatures &, const FeatureSet &, Symbol **)
1296 {}
1297
1298 void
1299 CanvasRenderer::do_unsupported_feature(const Symbol &feature_name)
1300 {
1301   // NOTE: maybe give warning in Author mode 
1302 #ifdef TRUE
1303   cerr << "Unsupported feature: " << feature_name << endl;
1304 #endif  
1305 }
1306
1307 void
1308 CanvasRenderer::do_features(ElementFeatures     &return_features,
1309                             const FeatureSet    &local,
1310                             const FeatureSet    &complete,
1311                             Symbol             **symbols)
1312 {
1313   // NOTE: notice args passed by reference 
1314   // this routine modifies the calling arguments current_node and connect_dir
1315   // in the calling routine if breaks, prefix or suffix occur in the feature
1316   // set  
1317 #ifdef JBM
1318   node *break_node = 0;
1319   node *prefix_node = 0;
1320   node *suffix_node = 0;
1321 #endif
1322   
1323   CC_TPtrSlistIterator<Feature> next(*(FeatureSet*)&local);
1324   while (++next)
1325     {
1326       // for each feature, look up the id in the local symbol table, and use
1327       // that id as an index into a the table of processing objects which
1328       // handle each feature
1329       
1330       // get id and do lookup 
1331       
1332 #ifdef JBM_IGNORE
1333       // check for ignore symbol 
1334       // NOTE: special hack - jbm - needs to be fixed to do proper vcc counting 
1335       if (next.key()->name() == *f_symbols[IGNORE])
1336         {
1337           connect_dir = n_right ;
1338           return 1 ;
1339         }
1340 #endif
1341       const Symbol &feature = next.key()->name();
1342
1343 #ifdef FEATURE_DEBUG      
1344       cerr << "feature = " << feature.name() << endl;
1345 #endif      
1346       
1347       if (feature == *symbols[LINEBREAK]) 
1348         dobreak(return_features, local, complete, symbols);
1349       else if (feature == *symbols[FONT])
1350         dofont(return_features, complete, symbols); 
1351       else if (feature == *symbols[MARGIN])
1352         domargin(return_features, complete, symbols);
1353       else if (feature == *symbols[POSITION])
1354         doposition (return_features, local, symbols);
1355       else if (feature == *symbols[LAYOUT])
1356         dolayout (return_features, local, complete, symbols);
1357       else if (feature == *symbols[BORDER])
1358         doborder (return_features, local, symbols);
1359       else if (feature == *symbols[TABLE])
1360         dotable (return_features, local, symbols);
1361       else if (feature == *symbols[TGROUP])
1362         dotgroup (return_features, local, symbols);
1363       else if (feature == *symbols[COLFORMAT])
1364         docolformat (return_features, local, symbols);
1365       else if (feature == *symbols[CELL])
1366         docell (return_features, local, symbols);
1367       else if (feature == *symbols[ROW])
1368         dorow (return_features, local, symbols);
1369       else if (feature == *symbols[PREFIX])
1370         doprefix(return_features, local, complete, symbols);
1371       else if (feature == *symbols[SUFFIX])
1372         dosuffix(return_features, local, complete, symbols);
1373 #ifdef JBM
1374       /*
1375          else if (feature == *symbols[UNDERLINE])
1376          dounderline(return_features, current_node, local, symbols);
1377          */
1378       else if (feature == *symbols[WRAP])
1379         dowrap(return_features, current_node, local, symbols);
1380       
1381       /*
1382          else if (feature == *symbols[COLOR])
1383          docolor(return_features, current_node, local, symbols);
1384          */
1385 #endif
1386       else {
1387
1388           // if printing in progress, check for print features
1389           if (window_system().printing()) {
1390
1391               // media
1392               if (feature == *symbols[MEDIA]) {
1393                   domedia(return_features, complete, symbols); 
1394               }
1395
1396               // page break
1397               else if (feature == *symbols[PAGEBREAK]) {
1398                   dopage(return_features, local, complete, symbols);
1399               }
1400               // otherwise features are unsupported
1401               else {
1402                   do_unsupported_feature(feature);
1403               }
1404           }
1405       }
1406     }
1407
1408     CC_TPtrSlistIterator<Feature> iter(*(FeatureSet*)&complete);
1409     while (++iter) {
1410       const Symbol &feature = iter.key()->name();
1411       if (feature == *symbols[HIGHLIGHT])
1412         dohighlight(return_features, complete, symbols);
1413       else if (feature == *symbols[IGNORE]) {
1414         Feature *ignore = iter.key();
1415 #ifdef IGNORE_DEBUG
1416         fprintf(stderr, "IGNORE value=%d\n", (int)*(ignore->value()));
1417 #endif
1418         return_features.ignore((int)*(ignore->value()));
1419       }
1420     }
1421   
1422 #ifdef JBM
1423   if (prefix_node)
1424     {
1425       current_node->connect_node(prefix_node, connect_dir);
1426       current_node = prefix_node ;
1427       connect_dir  = n_right ;
1428     }
1429   if (break_node)
1430     {
1431       current_node->connect_node(break_node, connect_dir);
1432       current_node = break_node ;
1433       connect_dir  = n_right ;
1434     }
1435   if (suffix_node)
1436     {
1437       current_node->connect_node(suffix_node, connect_dir);
1438       current_node = suffix_node ;
1439       connect_dir  = n_left ;
1440     }
1441   
1442 #endif
1443 }
1444
1445 void
1446 CanvasRenderer::dotable (ElementFeatures  &return_features,
1447                          const FeatureSet &local, 
1448                          Symbol **symbols)
1449 {
1450 #ifdef TABLE_DEBUG
1451   cerr << "dotable" << endl;
1452 #endif
1453
1454   const FeatureSet *tset = *local.lookup (symbols[TABLE])->value();
1455
1456   const Feature* frame_feature = tset->lookup(symbols[FRAME]);
1457
1458   TableDefn* table;
1459
1460   if (frame_feature)
1461     table = new TableDefn((const char*)(*frame_feature->value()));    
1462   else
1463     table = new TableDefn((TableDefn::table_frame_t)
1464                                 TableDefn::table_frame_default);
1465
1466   const Feature *colsep_feature = tset->lookup(symbols[COLSEP]);
1467   if (colsep_feature) {
1468     int colsep = point2pixel(*colsep_feature->value());
1469     table->colsep(colsep);
1470 #ifdef COLSEP_DEBUG
1471     cerr << "COLSEP specified in table, number=" << colsep << endl;
1472 #endif
1473   }
1474   
1475   const Feature *rowsep_feature = tset->lookup(symbols[ROWSEP]);
1476   if (rowsep_feature) {
1477     int rowsep = point2pixel(*rowsep_feature->value());
1478     table->rowsep(rowsep);
1479 #ifdef COLSEP_DEBUG
1480     cerr << "ROWSEP specified in table, number=" << rowsep << endl;
1481 #endif
1482   }
1483
1484   return_features.table(table);
1485 }
1486
1487 void
1488 CanvasRenderer::dotgroup (ElementFeatures  &return_features,
1489                           const FeatureSet &local, 
1490                           Symbol **symbols)
1491 {
1492 #ifdef TABLE_DEBUG
1493   cerr << "dotgroup" << endl;
1494 #endif
1495
1496   const FeatureSet *tset = *local.lookup (symbols[TGROUP])->value();
1497
1498   const Feature* justify_feature = tset->lookup(symbols[JUSTIFY]);
1499
1500   _DtCvFrmtOption justify = _DtCvOPTION_BAD;
1501
1502   if (justify_feature) {
1503     const char *str = *justify_feature->value();
1504
1505     if (str && *str) {
1506       if (strcasecmp(str, "left") == 0)
1507         justify = _DtCvJUSTIFY_LEFT;
1508       else if (strcasecmp(str, "right") == 0)
1509         justify = _DtCvJUSTIFY_RIGHT;
1510       else if (strcasecmp(str, "center") == 0)
1511         justify = _DtCvJUSTIFY_CENTER;
1512     }
1513   }
1514
1515   const Feature* vjustify_feature = tset->lookup(symbols[VJUSTIFY]);
1516
1517   _DtCvFrmtOption vjustify = _DtCvOPTION_BAD;
1518   
1519   if (vjustify_feature) {
1520     const char *str = *vjustify_feature->value();
1521
1522     if (str && *str) {
1523       if (strcasecmp(str, "top") == 0)
1524         vjustify = _DtCvJUSTIFY_TOP;
1525       else if (strcasecmp(str, "bottom") == 0)
1526         vjustify = _DtCvJUSTIFY_BOTTOM;
1527       else if (strcasecmp(str, "middle") == 0)
1528         vjustify = _DtCvJUSTIFY_CENTER;
1529     }
1530   }
1531
1532   TGDefn *tgroup = new TGDefn(justify, vjustify);
1533
1534   const Feature *colsepF = tset->lookup(symbols[COLSEP]);
1535   if (colsepF) {
1536     int colsep = point2pixel(*colsepF->value());
1537     tgroup->colsep(colsep);
1538 #ifdef COLSEP_DEBUG
1539     cerr << "COLSEP specified in tgroup, number=" << colsep << endl;
1540 #endif
1541   }
1542
1543   const Feature *rowsepF = tset->lookup(symbols[ROWSEP]);
1544   if (rowsepF) {
1545     int rowsep = point2pixel(*rowsepF->value());
1546     tgroup->rowsep(rowsep);
1547 #ifdef COLSEP_DEBUG
1548     cerr << "ROWSEP specified in tgroup, number=" << rowsep << endl;
1549 #endif
1550   }
1551
1552   return_features.tgroup(tgroup);
1553
1554   const Feature *char_alignF = tset->lookup(symbols[CHARALIGN]);
1555   if (char_alignF)
1556     tgroup->char_align(*char_alignF->value());
1557 }
1558
1559 void
1560 CanvasRenderer::docolformat(ElementFeatures     &return_features,
1561                             const FeatureSet    &local,
1562                             Symbol **symbols)
1563 {
1564 #ifdef TABLE_DEBUG
1565   cerr << "docolformat" << endl;
1566 #endif
1567   // have to iterate over colformat attributes
1568   
1569   const Feature *feature = local.lookup(symbols[COLFORMAT]);
1570   const FeatureValue *fv = feature->value();
1571   
1572   const FeatureSet *set = ((FeatureValueFeatureSet*)fv)->value();
1573   ColFormat *colf = new ColFormat ;
1574   
1575
1576   try
1577     {
1578       const Feature *widthF = set->lookup (symbols[WIDTH]) ;
1579       if (widthF)
1580         colf->width(point2pixel(*widthF->value()));
1581
1582       const Feature *nameF = set->lookup (symbols[NAME]) ;
1583       if (nameF)
1584         colf->name (*nameF->value());
1585   
1586       const Feature *justifyF = set->lookup(symbols[JUSTIFY]); 
1587       if (justifyF)
1588         {
1589           _DtCvFrmtOption justify = _DtCvOPTION_BAD ;
1590           const char *justify_name = *justifyF->value();
1591
1592           if (!strcasecmp (justify_name, "left"))
1593             {
1594               justify = _DtCvJUSTIFY_LEFT;
1595             }
1596           else
1597           if (!strcasecmp (justify_name, "right"))
1598             {
1599               justify = _DtCvJUSTIFY_RIGHT ;
1600             }
1601           else
1602           if (!strcasecmp (justify_name, "center"))
1603             {
1604               justify = _DtCvJUSTIFY_CENTER ;
1605             }
1606           else
1607           if (!strcasecmp (justify_name, "char"))
1608             {
1609               justify = _DtCvJUSTIFY_CHAR ;
1610
1611               // CharAlign is effective only for _DtCvJUSTIFY_CHAR
1612               const Feature *char_alignF = set->lookup (symbols[CHARALIGN]);
1613               if (char_alignF)
1614                 colf->char_align (*char_alignF->value()) ;
1615             }
1616           colf->justify (justify);
1617         }
1618     }
1619   catch_any()
1620     {
1621       abort();
1622     }
1623   end_try ;
1624
1625   const Feature *colsepF = set->lookup(symbols[COLSEP]);
1626   if (colsepF) {
1627     int colsep = point2pixel(*colsepF->value());
1628     colf->colsep(colsep);
1629 #ifdef COLSEP_DEBUG
1630     cerr << "COLSEP specified in colformat, number=" << colsep << endl;
1631 #endif
1632   }
1633
1634   const Feature *rowsepF = set->lookup(symbols[ROWSEP]);
1635   if (rowsepF) {
1636     int rowsep = point2pixel(*rowsepF->value());
1637     colf->rowsep(rowsep);
1638 #ifdef COLSEP_DEBUG
1639     cerr << "ROWSEP specified in colformat, number=" << rowsep << endl;
1640 #endif
1641   }
1642
1643   return_features.col_format (colf);    // remember to add into table
1644 }
1645 void
1646 CanvasRenderer::docell (ElementFeatures  &return_features,
1647                         const FeatureSet &local, 
1648                         Symbol **symbols)
1649 {
1650 #ifdef TABLE_DEBUG_X
1651   static int cell_count = 0 ;
1652   cerr << "docell: " << cell_count << endl;
1653   cell_count++ ;
1654 #endif  
1655   const FeatureSet *cset = *local.lookup (symbols[CELL])->value() ;
1656   
1657   const Feature *mr = cset->lookup (symbols[MOREROWS]);
1658   
1659   if (mr)
1660     return_features.cell().spanrows (int(point2pixel(*mr->value())) + 1);
1661
1662   const Feature *cref = cset->lookup (symbols[COLREF]);
1663   if (cref)
1664     return_features.cell().colref (strdup (*cref->value()));
1665
1666   const Feature *vjustify_feature = cset->lookup(symbols[VJUSTIFY]);
1667   if (vjustify_feature) {
1668     const char *vjustify = *vjustify_feature->value();
1669
1670     if (vjustify && *vjustify) {
1671 #ifdef VJUSTIFY_DEBUG
1672       cerr << "cell vjustify = " << vjustify << endl;
1673 #endif
1674       if (strcasecmp(vjustify, "top") == 0)
1675         return_features.cell().vjustify(_DtCvJUSTIFY_TOP);
1676       else if (strcasecmp(vjustify, "middle") == 0)
1677         return_features.cell().vjustify(_DtCvJUSTIFY_CENTER);
1678       else if (strcasecmp(vjustify, "bottom") == 0)
1679         return_features.cell().vjustify(_DtCvJUSTIFY_BOTTOM);
1680       else
1681         return_features.cell().vjustify(_DtCvOPTION_BAD);
1682     }
1683   }
1684
1685   const Feature *justify_feature = cset->lookup(symbols[JUSTIFY]);
1686   if (justify_feature) {
1687     const char *justify = *justify_feature->value();
1688
1689     if (strcasecmp(justify, "left") == 0)
1690       return_features.cell().justify(_DtCvJUSTIFY_LEFT);
1691     else if (strcasecmp(justify, "right") == 0)
1692       return_features.cell().justify(_DtCvJUSTIFY_RIGHT);
1693     else if (strcasecmp(justify, "center") == 0)
1694       return_features.cell().justify(_DtCvJUSTIFY_CENTER);
1695     else if (strcasecmp(justify, "char") == 0) {
1696       return_features.cell().justify(_DtCvJUSTIFY_CHAR);
1697
1698       // CharAlign is effective only for _DtCvJUSTIFY_CHAR
1699       const Feature *char_alignF = cset->lookup (symbols[CHARALIGN]);
1700       if (char_alignF) {
1701         return_features.cell().char_align(*char_alignF->value());
1702       }
1703     }
1704     else
1705       return_features.cell().justify(_DtCvOPTION_BAD);
1706   }
1707
1708   const Feature *colsepF = cset->lookup(symbols[COLSEP]);
1709   if (colsepF) {
1710     int colsep = point2pixel(*colsepF->value());
1711     return_features.cell().colsep(colsep);
1712 #ifdef COLSEP_DEBUG
1713     cerr << "COLSEP specified in cell, number=" << colsep << endl;
1714 #endif
1715   }
1716
1717   const Feature *rowsepF = cset->lookup(symbols[ROWSEP]);
1718   if (rowsepF) {
1719     int rowsep = point2pixel(*rowsepF->value());
1720     return_features.cell().rowsep(rowsep);
1721 #ifdef COLSEP_DEBUG
1722     cerr << "ROWSEP specified in cell, number=" << rowsep << endl;
1723 #endif
1724   }
1725
1726   return_features.cell().has_cell(True);
1727 }
1728 void
1729 CanvasRenderer::dorow (ElementFeatures  &return_features,
1730                        const FeatureSet &local, 
1731                        Symbol **symbols)
1732 {
1733 #ifdef TABLE_DEBUG
1734   cerr << "dorow" << endl;
1735 #endif
1736
1737   RowDefn* rowdefn = new RowDefn;
1738
1739   const FeatureSet* features;
1740
1741   try
1742     {
1743       features = *local.lookup(symbols[ROW])->value();
1744     }
1745   catch_any()
1746     {
1747       features = NULL;
1748     }
1749   end_try;
1750
1751   if (features) {
1752
1753     const Feature *vjustify_feature = features->lookup(symbols[VJUSTIFY]);
1754
1755     if (vjustify_feature) {
1756       const char *vjustify = *vjustify_feature->value();
1757
1758       if (vjustify && *vjustify) {
1759 #ifdef VJUSTIFY_DEBUG
1760         cerr << "vjustify = " << vjustify << endl;
1761 #endif
1762         if (strcasecmp(vjustify, "top") == 0)
1763           rowdefn->vjustify(_DtCvJUSTIFY_TOP);
1764         else if (strcasecmp(vjustify, "middle") == 0)
1765           rowdefn->vjustify(_DtCvJUSTIFY_CENTER);
1766         else if (strcasecmp(vjustify, "bottom") == 0)
1767           rowdefn->vjustify(_DtCvJUSTIFY_BOTTOM);
1768         else
1769           rowdefn->vjustify(_DtCvOPTION_BAD);
1770       }
1771     }
1772
1773     const Feature *rowsepF = features->lookup(symbols[ROWSEP]);
1774     if (rowsepF) {
1775       int rowsep = point2pixel(*rowsepF->value());
1776       rowdefn->rowsep(rowsep);
1777 #ifdef COLSEP_DEBUG
1778       cerr << "ROWSEP specified in row, number=" << rowsep << endl;
1779 #endif
1780     }
1781   }
1782
1783   return_features.row (rowdefn) ;
1784 }