Initial commit
[profile/ivi/openjade.git] / style / FlowObj.cxx
1 // Copyright (c) 1996 James Clark
2 // See the file copying.txt for copying permission.
3
4 #include "stylelib.h"
5 #include "ProcessContext.h"
6 #include "Interpreter.h"
7 #include "InterpreterMessages.h"
8 #include "SosofoObj.h"
9 #include "macros.h"
10
11 #ifdef DSSSL_NAMESPACE
12 namespace DSSSL_NAMESPACE {
13 #endif
14
15 FlowObj::FlowObj()
16 : style_(0)
17 {
18   hasSubObjects_ = 1;
19 }
20
21 void FlowObj::process(ProcessContext &context)
22 {
23   context.startFlowObj();
24   unsigned flags = 0;
25   pushStyle(context, flags);
26   processInner(context);
27   popStyle(context, flags);
28   context.endFlowObj();
29 }
30
31 void FlowObj::pushStyle(ProcessContext &context, unsigned &)
32 {
33   if (style_)
34     context.currentStyleStack().push(style_, context.vm(), context.currentFOTBuilder());
35   else
36     context.currentStyleStack().pushEmpty();
37 }
38
39 void FlowObj::popStyle(ProcessContext &context, unsigned)
40 {
41   if (style_)
42     context.currentStyleStack().pop();
43   else
44     context.currentStyleStack().popEmpty();
45 }
46
47 void FlowObj::traceSubObjects(Collector &c) const
48 {
49   c.trace(style_);
50 }
51
52 CompoundFlowObj *FlowObj::asCompoundFlowObj()
53 {
54   return 0;
55 }
56
57 bool FlowObj::hasNonInheritedC(const Identifier *) const
58 {
59   return 0;
60 }
61
62 bool FlowObj::hasPseudoNonInheritedC(const Identifier *) const
63 {
64   return 0;
65 }
66
67 void FlowObj::setNonInheritedC(const Identifier *, ELObj *, const Location &, Interpreter &)
68 {
69   CANNOT_HAPPEN();
70 }
71
72 bool FlowObj::isDisplayNIC(const Identifier *ident)
73 {
74   Identifier::SyntacticKey key;
75   if (ident->syntacticKey(key)) {
76     switch (key) {
77     case Identifier::keyPositionPreference:
78     case Identifier::keyIsKeepWithPrevious:
79     case Identifier::keyIsKeepWithNext:
80     case Identifier::keyKeep:
81     case Identifier::keyBreakBefore:
82     case Identifier::keyBreakAfter:
83     case Identifier::keyIsMayViolateKeepBefore:
84     case Identifier::keyIsMayViolateKeepAfter:
85     case Identifier::keySpaceBefore:
86     case Identifier::keySpaceAfter:
87       return 1;
88     default:
89       break;
90     }
91   }
92   return 0;
93 }
94
95 bool FlowObj::setDisplayNIC(FOTBuilder::DisplayNIC &nic,
96                             const Identifier *ident, ELObj *obj,
97                             const Location &loc, Interpreter &interp)
98 {
99   static FOTBuilder::Symbol breakVals[] = {
100     FOTBuilder::symbolFalse,
101     FOTBuilder::symbolPage,
102     FOTBuilder::symbolColumnSet,
103     FOTBuilder::symbolColumn
104   };
105   Identifier::SyntacticKey key;
106   if (ident->syntacticKey(key)) {
107     switch (key) {
108     case Identifier::keyPositionPreference:
109       {
110         static FOTBuilder::Symbol vals[] = {
111           FOTBuilder::symbolFalse,
112           FOTBuilder::symbolTop,
113           FOTBuilder::symbolBottom,
114         };
115         interp.convertEnumC(vals, SIZEOF(vals), obj, ident, loc, nic.positionPreference);
116       }
117       return 1;
118     case Identifier::keyIsKeepWithPrevious:
119       interp.convertBooleanC(obj, ident, loc, nic.keepWithPrevious);
120       return 1;
121     case Identifier::keyIsKeepWithNext:
122       interp.convertBooleanC(obj, ident, loc, nic.keepWithNext);
123       return 1;
124     case Identifier::keyKeep:
125       {
126         static FOTBuilder::Symbol vals[] = {
127           FOTBuilder::symbolFalse,
128           FOTBuilder::symbolTrue,
129           FOTBuilder::symbolPage,
130           FOTBuilder::symbolColumnSet,
131           FOTBuilder::symbolColumn
132         };
133         interp.convertEnumC(vals, SIZEOF(vals), obj, ident, loc, nic.keep);
134       }
135       return 1;
136     case Identifier::keyBreakBefore:
137       interp.convertEnumC(breakVals, SIZEOF(breakVals), obj, ident, loc, nic.breakBefore);
138       return 1;
139     case Identifier::keyBreakAfter:
140        interp.convertEnumC(breakVals, SIZEOF(breakVals), obj, ident, loc, nic.breakAfter);
141      return 1;
142     case Identifier::keyIsMayViolateKeepBefore:
143       interp.convertBooleanC(obj, ident, loc, nic.mayViolateKeepBefore);
144       return 1;
145     case Identifier::keyIsMayViolateKeepAfter:
146       interp.convertBooleanC(obj, ident, loc, nic.mayViolateKeepAfter);
147       return 1;
148     case Identifier::keySpaceBefore:
149     case Identifier::keySpaceAfter:
150       {
151         FOTBuilder::DisplaySpace &ds = (key == Identifier::keySpaceBefore
152                                         ? nic.spaceBefore
153                                         : nic.spaceAfter);
154         DisplaySpaceObj *dso = obj->asDisplaySpace();
155         if (dso)
156           ds = dso->displaySpace();
157         else if (interp.convertLengthSpecC(obj, ident, loc, ds.nominal)) {
158           ds.max = ds.nominal;
159           ds.min = ds.nominal;
160         }
161       }
162       return 1;
163     default:
164       break;
165     }
166   }
167   return 0;
168 }
169
170
171 void CompoundFlowObj::processInner(ProcessContext &context)
172 {
173   if (content_)
174     content_->process(context);
175   else
176     context.processChildren(context.vm().interp->initialProcessingMode());
177 }
178
179 void CompoundFlowObj::traceSubObjects(Collector &c) const
180 {
181   c.trace(content_);
182   FlowObj::traceSubObjects(c);
183 }
184
185 CompoundFlowObj *CompoundFlowObj::asCompoundFlowObj()
186 {
187   return this;
188 }
189
190 class DisplayGroupFlowObj : public CompoundFlowObj {
191 public:
192   void *operator new(size_t, Collector &c) {
193     return c.allocateObject(1);
194   }
195   DisplayGroupFlowObj();
196   DisplayGroupFlowObj(const DisplayGroupFlowObj &);
197   void processInner(ProcessContext &);
198   FlowObj *copy(Collector &) const;
199   void setNonInheritedC(const Identifier *, ELObj *,
200                         const Location &, Interpreter &);
201   bool hasNonInheritedC(const Identifier *) const;
202 protected:
203   Owner<FOTBuilder::DisplayGroupNIC> nic_;
204 };
205
206 DisplayGroupFlowObj::DisplayGroupFlowObj()
207 : nic_(new FOTBuilder::DisplayGroupNIC)
208 {
209 }
210
211 DisplayGroupFlowObj::DisplayGroupFlowObj(const DisplayGroupFlowObj &fo)
212 : CompoundFlowObj(fo), nic_(new FOTBuilder::DisplayGroupNIC(*fo.nic_))
213 {
214 }
215
216 void DisplayGroupFlowObj::processInner(ProcessContext &context)
217 {
218   FOTBuilder &fotb = context.currentFOTBuilder();
219   fotb.startDisplayGroup(*nic_);
220   CompoundFlowObj::processInner(context);
221   fotb.endDisplayGroup();
222 }
223
224 bool DisplayGroupFlowObj::hasNonInheritedC(const Identifier *ident) const
225 {
226   Identifier::SyntacticKey key;
227   if (ident->syntacticKey(key) && key == Identifier::keyCoalesceId)
228     return 1;
229   return isDisplayNIC(ident);
230 }
231
232 void DisplayGroupFlowObj::setNonInheritedC(const Identifier *ident, ELObj *obj,
233                                            const Location &loc, Interpreter &interp)
234 {
235   if (!setDisplayNIC(*nic_, ident, obj, loc, interp)) {
236     const Char *s;
237     size_t n;
238     if (!obj->stringData(s, n)) {
239       interp.setNextLocation(loc);
240       interp.message(InterpreterMessages::invalidCharacteristicValue,
241                      StringMessageArg(ident->name()));
242     }
243     nic_->hasCoalesceId = 1;
244     nic_->coalesceId.assign(s, n);
245   }
246 }
247
248 FlowObj *DisplayGroupFlowObj::copy(Collector &c) const
249 {
250   return new (c) DisplayGroupFlowObj(*this);
251 }
252
253 class ParagraphFlowObj : public CompoundFlowObj {
254 public:
255   void *operator new(size_t, Collector &c) {
256     return c.allocateObject(1);
257   }
258   ParagraphFlowObj();
259   ParagraphFlowObj(const ParagraphFlowObj &);
260   void processInner(ProcessContext &);
261   FlowObj *copy(Collector &) const;
262   void setNonInheritedC(const Identifier *, ELObj *,
263                         const Location &, Interpreter &);
264   bool hasNonInheritedC(const Identifier *) const;
265 private:
266   Owner<FOTBuilder::ParagraphNIC> nic_;
267 };
268
269
270 ParagraphFlowObj::ParagraphFlowObj()
271 : nic_(new FOTBuilder::ParagraphNIC)
272 {
273 }
274
275 ParagraphFlowObj::ParagraphFlowObj(const ParagraphFlowObj &fo)
276 : CompoundFlowObj(fo), nic_(new FOTBuilder::ParagraphNIC(*fo.nic_))
277 {
278 }
279
280 void ParagraphFlowObj::processInner(ProcessContext &context)
281 {
282   FOTBuilder &fotb = context.currentFOTBuilder();
283   fotb.startParagraph(*nic_);
284   CompoundFlowObj::processInner(context);
285   fotb.endParagraph();
286 }
287
288 void ParagraphFlowObj::setNonInheritedC(const Identifier *ident, ELObj *obj,
289                                         const Location &loc, Interpreter &interp)
290 {
291   setDisplayNIC(*nic_, ident, obj, loc, interp);
292 }
293
294 bool ParagraphFlowObj::hasNonInheritedC(const Identifier *ident) const
295 {
296   return isDisplayNIC(ident);
297 }
298
299 FlowObj *ParagraphFlowObj::copy(Collector &c) const
300 {
301   return new (c) ParagraphFlowObj(*this);
302 }
303
304 class ParagraphBreakFlowObj : public FlowObj {
305 public:
306   void *operator new(size_t, Collector &c) {
307     return c.allocateObject(1);
308   }
309   ParagraphBreakFlowObj();
310   ParagraphBreakFlowObj(const ParagraphBreakFlowObj &);
311   FlowObj *copy(Collector &) const;
312   void processInner(ProcessContext &);
313   void setNonInheritedC(const Identifier *, ELObj *,
314                         const Location &, Interpreter &);
315   bool hasNonInheritedC(const Identifier *) const;
316 private:
317   Owner<FOTBuilder::ParagraphNIC> nic_;
318 };
319
320
321 ParagraphBreakFlowObj::ParagraphBreakFlowObj()
322 : nic_(new FOTBuilder::ParagraphNIC)
323 {
324 }
325
326 ParagraphBreakFlowObj::ParagraphBreakFlowObj(const ParagraphBreakFlowObj &fo)
327 : FlowObj(fo), nic_(new FOTBuilder::ParagraphNIC(*fo.nic_))
328 {
329 }
330
331 FlowObj *ParagraphBreakFlowObj::copy(Collector &c) const
332 {
333   return new (c) ParagraphBreakFlowObj(*this);
334 }
335
336 void ParagraphBreakFlowObj::processInner(ProcessContext &context)
337 {
338   context.currentFOTBuilder().paragraphBreak(*nic_);
339 }
340
341 void ParagraphBreakFlowObj::setNonInheritedC(const Identifier *ident, ELObj *obj,
342                                              const Location &loc, Interpreter &interp)
343 {
344   setDisplayNIC(*nic_, ident, obj, loc, interp);
345 }
346
347 bool ParagraphBreakFlowObj::hasNonInheritedC(const Identifier *ident) const
348 {
349   return isDisplayNIC(ident);
350 }
351
352 class ExternalGraphicFlowObj : public FlowObj {
353 public:
354   void *operator new(size_t, Collector &c) {
355     return c.allocateObject(1);
356   }
357   ExternalGraphicFlowObj();
358   ExternalGraphicFlowObj(const ExternalGraphicFlowObj &);
359   void processInner(ProcessContext &);
360   FlowObj *copy(Collector &) const;
361   void setNonInheritedC(const Identifier *, ELObj *,
362                         const Location &, Interpreter &);
363   bool hasNonInheritedC(const Identifier *) const;
364 private:
365   Owner<FOTBuilder::ExternalGraphicNIC> nic_;
366 };
367
368
369 ExternalGraphicFlowObj::ExternalGraphicFlowObj()
370 : nic_(new FOTBuilder::ExternalGraphicNIC)
371 {
372 }
373
374 ExternalGraphicFlowObj::ExternalGraphicFlowObj(const ExternalGraphicFlowObj &fo)
375 : FlowObj(fo), nic_(new FOTBuilder::ExternalGraphicNIC(*fo.nic_))
376 {
377 }
378
379 void ExternalGraphicFlowObj::processInner(ProcessContext &context)
380 {
381   context.currentFOTBuilder().externalGraphic(*nic_);
382 }
383
384 void ExternalGraphicFlowObj::setNonInheritedC(const Identifier *ident, ELObj *obj,
385                                               const Location &loc, Interpreter &interp)
386 {
387   if (!setDisplayNIC(*nic_, ident, obj, loc, interp)) {
388     Identifier::SyntacticKey key;
389     if (ident->syntacticKey(key)) {
390       switch (key) {
391       case Identifier::keyIsDisplay:
392         interp.convertBooleanC(obj, ident, loc, nic_->isDisplay);
393         return;
394       case Identifier::keyScale:
395         {
396           double d;
397           if (obj->realValue(d)) {
398             nic_->scaleType = FOTBuilder::symbolFalse;
399             nic_->scale[0] = nic_->scale[1] = d;
400           }
401           else if (obj->asSymbol()) {
402             static FOTBuilder::Symbol vals[] = {
403               FOTBuilder::symbolMax,
404               FOTBuilder::symbolMaxUniform
405             };
406             interp.convertEnumC(vals, 2, obj, ident, loc, nic_->scaleType);
407           }
408           else {
409             PairObj *pair = obj->asPair();
410             if (pair
411                 && pair->car()->realValue(nic_->scale[0])
412                 && (pair = pair->cdr()->asPair()) != 0
413                 && pair->car()->realValue(nic_->scale[1])
414                 && pair->cdr()->isNil()) {
415               nic_->scaleType = FOTBuilder::symbolFalse;
416             }
417             else
418               interp.invalidCharacteristicValue(ident, loc);
419           }
420         }
421         return;
422       case Identifier::keyMaxWidth:
423         if (interp.convertLengthSpecC(obj, ident, loc, nic_->maxWidth))
424           nic_->hasMaxWidth = 1;
425         return;
426       case Identifier::keyMaxHeight:
427         if (interp.convertLengthSpecC(obj, ident, loc, nic_->maxHeight))
428           nic_->hasMaxHeight = 1;
429         return;
430       case Identifier::keyEntitySystemId:
431         interp.convertStringC(obj, ident, loc, nic_->entitySystemId);
432         return;
433       case Identifier::keyNotationSystemId:
434         interp.convertStringC(obj, ident, loc, nic_->notationSystemId);
435         return;
436       case Identifier::keyPositionPointX:
437         interp.convertLengthSpecC(obj, ident, loc, nic_->positionPointX);
438         return;
439       case Identifier::keyPositionPointY:
440         interp.convertLengthSpecC(obj, ident, loc, nic_->positionPointY);
441         return;
442       case Identifier::keyEscapementDirection:
443         {
444           static FOTBuilder::Symbol vals[] = {
445             FOTBuilder::symbolTopToBottom,
446             FOTBuilder::symbolLeftToRight,
447             FOTBuilder::symbolBottomToTop,
448             FOTBuilder::symbolRightToLeft
449           };
450           interp.convertEnumC(vals, SIZEOF(vals), obj, ident, loc, nic_->escapementDirection);
451         }
452         return;
453       case Identifier::keyBreakBeforePriority:
454         interp.convertIntegerC(obj, ident, loc, nic_->breakBeforePriority);
455         return;
456       case Identifier::keyBreakAfterPriority:
457         interp.convertIntegerC(obj, ident, loc, nic_->breakAfterPriority);
458         return;
459       default:
460         break;
461       }
462     }
463     CANNOT_HAPPEN();
464   }
465 }
466
467 bool ExternalGraphicFlowObj::hasNonInheritedC(const Identifier *ident) const
468 {
469   Identifier::SyntacticKey key;
470   if (ident->syntacticKey(key)) {
471     switch (key) {
472     case Identifier::keyIsDisplay:
473     case Identifier::keyScale:
474     case Identifier::keyMaxWidth:
475     case Identifier::keyMaxHeight:
476     case Identifier::keyEntitySystemId:
477     case Identifier::keyNotationSystemId:
478     case Identifier::keyPositionPointX:
479     case Identifier::keyPositionPointY:
480     case Identifier::keyEscapementDirection:
481     case Identifier::keyBreakBeforePriority:
482     case Identifier::keyBreakAfterPriority:
483       return 1;
484     default:
485       break;
486     }
487   }
488   return isDisplayNIC(ident);
489 }
490
491 FlowObj *ExternalGraphicFlowObj::copy(Collector &c) const
492 {
493   return new (c) ExternalGraphicFlowObj(*this);
494 }
495
496 class RuleFlowObj : public FlowObj {
497 public:
498   void *operator new(size_t, Collector &c) {
499     return c.allocateObject(1);
500   }
501   RuleFlowObj();
502   RuleFlowObj(const RuleFlowObj &);
503   void processInner(ProcessContext &);
504   FlowObj *copy(Collector &) const;
505   void setNonInheritedC(const Identifier *, ELObj *,
506                         const Location &, Interpreter &);
507   bool hasNonInheritedC(const Identifier *) const;
508   bool ruleStyle(ProcessContext &, StyleObj *&style) {
509     style = style_;
510     return 1;
511   }
512   bool isRule() { return 1; }
513 private:
514   Owner<FOTBuilder::RuleNIC> nic_;
515 };
516
517 RuleFlowObj::RuleFlowObj()
518 : nic_(new FOTBuilder::RuleNIC)
519 {
520 }
521
522 RuleFlowObj::RuleFlowObj(const RuleFlowObj &fo)
523 : FlowObj(fo), nic_(new FOTBuilder::RuleNIC(*fo.nic_))
524 {
525 }
526
527 void RuleFlowObj::processInner(ProcessContext &context)
528 {
529   context.currentFOTBuilder().rule(*nic_);
530 }
531
532 void RuleFlowObj::setNonInheritedC(const Identifier *ident, ELObj *obj,
533                                               const Location &loc, Interpreter &interp)
534 {
535   if (setDisplayNIC(*nic_, ident, obj, loc, interp))
536     return;
537   Identifier::SyntacticKey key;
538   if (ident->syntacticKey(key)) {
539     switch (key) {
540     case Identifier::keyOrientation:
541       {
542         static FOTBuilder::Symbol vals[] = {
543           FOTBuilder::symbolHorizontal,
544           FOTBuilder::symbolVertical,
545           FOTBuilder::symbolEscapement,
546           FOTBuilder::symbolLineProgression
547         };
548         interp.convertEnumC(vals, SIZEOF(vals), obj, ident, loc, nic_->orientation);
549       }
550       return;
551     case Identifier::keyLength:
552       if (interp.convertLengthSpecC(obj, ident, loc, nic_->length))
553         nic_->hasLength = 1;
554       return;
555     case Identifier::keyBreakBeforePriority:
556       interp.convertIntegerC(obj, ident, loc, nic_->breakBeforePriority);
557       return;
558     case Identifier::keyBreakAfterPriority:
559       interp.convertIntegerC(obj, ident, loc, nic_->breakAfterPriority);
560       return;
561     default:
562       break;
563     }
564   }
565   CANNOT_HAPPEN();
566 }
567
568 bool RuleFlowObj::hasNonInheritedC(const Identifier *ident) const
569 {
570   Identifier::SyntacticKey key;
571   if (ident->syntacticKey(key)) {
572     switch (key) {
573     case Identifier::keyOrientation:
574     case Identifier::keyLength:
575     case Identifier::keyBreakBeforePriority:
576     case Identifier::keyBreakAfterPriority:
577       return 1;
578     default:
579       break;
580     }
581   }
582   return isDisplayNIC(ident);
583 }
584
585 FlowObj *RuleFlowObj::copy(Collector &c) const
586 {
587   return new (c) RuleFlowObj(*this);
588 }
589
590 class AlignmentPointFlowObj : public FlowObj {
591 public:
592   AlignmentPointFlowObj() { }
593   FlowObj *copy(Collector &) const;
594   void processInner(ProcessContext &);
595 };
596
597 FlowObj *AlignmentPointFlowObj::copy(Collector &c) const
598 {
599   return new (c) AlignmentPointFlowObj(*this);
600 }
601
602 void AlignmentPointFlowObj::processInner(ProcessContext &context)
603 {
604   context.currentFOTBuilder().alignmentPoint();
605 }
606
607 class SidelineFlowObj : public CompoundFlowObj {
608 public:
609   SidelineFlowObj() { }
610   FlowObj *copy(Collector &) const;
611   void processInner(ProcessContext &);
612 };
613
614 FlowObj *SidelineFlowObj::copy(Collector &c) const
615 {
616   return new (c) SidelineFlowObj(*this);
617 }
618
619 void SidelineFlowObj::processInner(ProcessContext &context)
620 {
621   FOTBuilder &fotb = context.currentFOTBuilder();
622   fotb.startSideline();
623   CompoundFlowObj::processInner(context);
624   fotb.endSideline();
625 }
626 void SequenceFlowObj::processInner(ProcessContext &context)
627 {
628   FOTBuilder &fotb = context.currentFOTBuilder();
629   fotb.startSequence();
630   CompoundFlowObj::processInner(context);
631   fotb.endSequence();
632 }
633
634 FlowObj *SequenceFlowObj::copy(Collector &c) const
635 {
636   return new (c) SequenceFlowObj(*this);
637 }
638
639 class LineFieldFlowObj : public CompoundFlowObj {
640 public:
641   void *operator new(size_t, Collector &c) {
642     return c.allocateObject(1);
643   }
644   LineFieldFlowObj() : nic_(new FOTBuilder::LineFieldNIC) { }
645   LineFieldFlowObj(const LineFieldFlowObj &fo)
646     : CompoundFlowObj(fo), nic_(new FOTBuilder::LineFieldNIC(*fo.nic_)) { }
647   void processInner(ProcessContext &);
648   FlowObj *copy(Collector &) const;
649   bool hasNonInheritedC(const Identifier *ident) const;
650   void setNonInheritedC(const Identifier *ident, ELObj *obj,
651                         const Location &loc, Interpreter &interp);
652 private:
653   Owner<FOTBuilder::LineFieldNIC> nic_;
654 };
655
656 FlowObj *LineFieldFlowObj::copy(Collector &c) const
657 {
658   return new (c) LineFieldFlowObj(*this);
659 }
660
661 void LineFieldFlowObj::processInner(ProcessContext &context)
662 {
663   FOTBuilder &fotb = context.currentFOTBuilder();
664   fotb.startLineField(*nic_);
665   CompoundFlowObj::processInner(context);
666   fotb.endLineField();
667 }
668
669 void LineFieldFlowObj::setNonInheritedC(const Identifier *ident, ELObj *obj,
670                                         const Location &loc, Interpreter &interp)
671 {
672   Identifier::SyntacticKey key;
673   if (ident->syntacticKey(key)) {
674     switch (key) {
675     case Identifier::keyBreakBeforePriority:
676       interp.convertIntegerC(obj, ident, loc, nic_->breakBeforePriority);
677       return;
678     case Identifier::keyBreakAfterPriority:
679       interp.convertIntegerC(obj, ident, loc, nic_->breakAfterPriority);
680       return;
681     default:
682       break;
683     }
684   }
685   CANNOT_HAPPEN();
686 }
687
688 bool LineFieldFlowObj::hasNonInheritedC(const Identifier *ident) const
689 {
690   Identifier::SyntacticKey key;
691   if (ident->syntacticKey(key)) {
692     switch (key) {
693     case Identifier::keyBreakBeforePriority:
694     case Identifier::keyBreakAfterPriority:
695       return 1;
696     default:
697       break;
698     }
699   }
700   return 0;
701 }
702
703 class SimplePageSequenceFlowObj : public CompoundFlowObj {
704 public:
705   void *operator new(size_t, Collector &c) {
706     return c.allocateObject(1);
707   }
708   struct HeaderFooter {
709     enum { nParts = 6 };
710     HeaderFooter();
711     SosofoObj *part[nParts];
712   };
713   SimplePageSequenceFlowObj();
714   SimplePageSequenceFlowObj(const SimplePageSequenceFlowObj &);
715   void processInner(ProcessContext &);
716   FlowObj *copy(Collector &) const;
717   bool hasNonInheritedC(const Identifier *) const;
718   void setNonInheritedC(const Identifier *, ELObj *,
719                         const Location &, Interpreter &);
720   void traceSubObjects(Collector &) const;
721 private:
722   enum { nPageTypeBits = 2 };
723   Owner<HeaderFooter> hf_;
724 };
725
726
727 SimplePageSequenceFlowObj::SimplePageSequenceFlowObj()
728 : hf_(new HeaderFooter)
729 {
730   hasSubObjects_ = 1;
731 }
732
733 SimplePageSequenceFlowObj::SimplePageSequenceFlowObj(const SimplePageSequenceFlowObj &fo)
734 : CompoundFlowObj(fo), hf_(new HeaderFooter(*fo.hf_))
735 {
736 }
737
738 void SimplePageSequenceFlowObj::traceSubObjects(Collector &c) const
739 {
740   for (int i = 0; i < HeaderFooter::nParts; i++)
741     c.trace(hf_->part[i]);
742   CompoundFlowObj::traceSubObjects(c);
743 }
744
745 void SimplePageSequenceFlowObj::processInner(ProcessContext &context)
746 {
747   FOTBuilder &fotb = context.currentFOTBuilder();
748   FOTBuilder* hf_fotb[FOTBuilder::nHF];
749   fotb.startSimplePageSequence(hf_fotb);
750   for (int i = 0; i < (1 << nPageTypeBits); i++) {
751     context.setPageType(i);
752     for (int j = 0; j < HeaderFooter::nParts; j++) {
753       if (hf_->part[j]) {
754         context.pushPrincipalPort(hf_fotb[i | (j << nPageTypeBits)]);
755         hf_->part[j]->process(context);
756         context.popPrincipalPort();
757     }
758   }
759   }
760   fotb.endSimplePageSequenceHeaderFooter();
761   CompoundFlowObj::processInner(context);
762   fotb.endSimplePageSequence();
763 }
764
765 void SimplePageSequenceFlowObj::setNonInheritedC(const Identifier *ident,
766                                                  ELObj *obj,
767                                                  const Location &loc,
768                                                  Interpreter &interp)
769 {
770   SosofoObj *sosofo = obj->asSosofo();
771   if (!sosofo) {
772     interp.setNextLocation(loc);
773     interp.message(InterpreterMessages::invalidCharacteristicValue,
774                    StringMessageArg(ident->name()));
775     return;
776   }
777   Identifier::SyntacticKey key;
778   if (ident->syntacticKey(key)) {
779     switch (key) {
780     case Identifier::keyLeftHeader:
781       hf_->part[(FOTBuilder::leftHF | FOTBuilder::headerHF) >> nPageTypeBits] = sosofo;
782       return;
783     case Identifier::keyCenterHeader:
784       hf_->part[(FOTBuilder::centerHF | FOTBuilder::headerHF) >> nPageTypeBits] = sosofo;
785       return;
786     case Identifier::keyRightHeader:
787       hf_->part[(FOTBuilder::rightHF | FOTBuilder::headerHF) >> nPageTypeBits] = sosofo;
788       return;
789     case Identifier::keyLeftFooter:
790       hf_->part[(FOTBuilder::leftHF | FOTBuilder::footerHF) >> nPageTypeBits] = sosofo;
791       return;
792     case Identifier::keyCenterFooter:
793       hf_->part[(FOTBuilder::centerHF | FOTBuilder::footerHF) >> nPageTypeBits] = sosofo;
794       return;
795     case Identifier::keyRightFooter:
796       hf_->part[(FOTBuilder::rightHF | FOTBuilder::footerHF) >> nPageTypeBits] = sosofo;
797       return;
798     default:
799       break;
800     }
801   }
802   CANNOT_HAPPEN();
803 }
804
805 bool SimplePageSequenceFlowObj::hasNonInheritedC(const Identifier *ident) const
806 {
807   Identifier::SyntacticKey key;
808   if (ident->syntacticKey(key)) {
809     switch (key) {
810     case Identifier::keyLeftHeader:
811     case Identifier::keyCenterHeader:
812     case Identifier::keyRightHeader:
813     case Identifier::keyLeftFooter:
814     case Identifier::keyCenterFooter:
815     case Identifier::keyRightFooter:
816       return 1;
817     default:
818       break;
819     }
820   }
821   return 0;
822 }
823
824 FlowObj *SimplePageSequenceFlowObj::copy(Collector &c) const
825 {
826   return new (c) SimplePageSequenceFlowObj(*this);
827 }
828
829 SimplePageSequenceFlowObj::HeaderFooter::HeaderFooter()
830 {
831   for (int i = 0; i < nParts; i++)
832     part[i] = 0;
833 }
834
835 class LinkFlowObj : public CompoundFlowObj {
836 public:
837   LinkFlowObj();
838   FlowObj *copy(Collector &) const;
839   void processInner(ProcessContext &);
840   void traceSubObjects(Collector &) const;
841   bool hasNonInheritedC(const Identifier *) const;
842   void setNonInheritedC(const Identifier *, ELObj *,
843                         const Location &, Interpreter &);
844 private:
845   AddressObj *addressObj_;
846 };
847
848 LinkFlowObj::LinkFlowObj()
849 : addressObj_(0)
850 {
851 }
852
853 void LinkFlowObj::processInner(ProcessContext &context)
854 {
855   FOTBuilder &fotb = context.currentFOTBuilder();
856   if (!addressObj_) {
857     FOTBuilder::Address addr;
858     addr.type = FOTBuilder::Address::none;
859     fotb.startLink(addr);
860   }
861   else
862     fotb.startLink(addressObj_->address());
863   CompoundFlowObj::processInner(context);
864   fotb.endLink();
865 }
866
867 FlowObj *LinkFlowObj::copy(Collector &c) const
868 {
869   return new (c) LinkFlowObj(*this);
870 }
871
872 void LinkFlowObj::traceSubObjects(Collector &c) const
873 {
874   CompoundFlowObj::traceSubObjects(c);
875   c.trace(addressObj_);
876 }
877
878 bool LinkFlowObj::hasNonInheritedC(const Identifier *ident) const
879 {
880   Identifier::SyntacticKey key;
881   return ident->syntacticKey(key) && key == Identifier::keyDestination;
882 }
883
884 void LinkFlowObj::setNonInheritedC(const Identifier *ident, ELObj *obj,
885                                    const Location &loc, Interpreter &interp)
886 {
887   AddressObj *address = obj->asAddress();
888   if (!address) {
889     if (obj != interp.makeFalse()) {
890       interp.setNextLocation(loc);
891       interp.message(InterpreterMessages::invalidCharacteristicValue,
892                      StringMessageArg(ident->name()));
893     }
894     else
895       address = interp.makeAddressNone();
896   }
897   addressObj_ = address;
898 }
899
900 class ScrollFlowObj : public CompoundFlowObj {
901 public:
902   ScrollFlowObj() { }
903   void processInner(ProcessContext &);
904   FlowObj *copy(Collector &) const;
905 };
906
907 void ScrollFlowObj::processInner(ProcessContext &context)
908 {
909   FOTBuilder &fotb = context.currentFOTBuilder();
910   fotb.startScroll();
911   CompoundFlowObj::processInner(context);
912   fotb.endScroll();
913 }
914
915 FlowObj *ScrollFlowObj::copy(Collector &c) const
916 {
917   return new (c) ScrollFlowObj(*this);
918 }
919
920 class MarginaliaFlowObj : public CompoundFlowObj {
921 public:
922   MarginaliaFlowObj() { }
923   void processInner(ProcessContext &);
924   FlowObj *copy(Collector &) const;
925 };
926
927 void MarginaliaFlowObj::processInner(ProcessContext &context)
928 {
929   FOTBuilder &fotb = context.currentFOTBuilder();
930   fotb.startMarginalia();
931   CompoundFlowObj::processInner(context);
932   fotb.endMarginalia();
933 }
934
935 FlowObj *MarginaliaFlowObj::copy(Collector &c) const
936 {
937   return new (c) MarginaliaFlowObj(*this);
938 }
939
940 class MultiModeFlowObj : public CompoundFlowObj {
941 public:
942   void *operator new(size_t, Collector &c) {
943     return c.allocateObject(1);
944   }
945   MultiModeFlowObj();
946   MultiModeFlowObj(const MultiModeFlowObj &);
947   void processInner(ProcessContext &);
948   FlowObj *copy(Collector &) const;
949   bool hasNonInheritedC(const Identifier *) const;
950   void setNonInheritedC(const Identifier *, ELObj *,
951                         const Location &, Interpreter &);
952   struct NIC {
953     NIC() : hasPrincipalMode(0) { }
954     bool hasPrincipalMode;
955     FOTBuilder::MultiMode principalMode;
956     Vector<FOTBuilder::MultiMode> namedModes;
957   };
958 private:
959   bool handleMultiModesMember(const Identifier *, ELObj *obj,
960                               const Location &, Interpreter &);
961   Owner<NIC> nic_;
962 };
963
964 MultiModeFlowObj::MultiModeFlowObj()
965 : nic_(new NIC)
966 {
967 }
968
969 MultiModeFlowObj::MultiModeFlowObj(const MultiModeFlowObj &fo)
970 : CompoundFlowObj(fo), nic_(new NIC(*fo.nic_))
971 {
972 }
973
974 void MultiModeFlowObj::processInner(ProcessContext &context)
975 {
976   FOTBuilder &fotb = context.currentFOTBuilder();
977   Vector<FOTBuilder *> fotbs(nic_->namedModes.size());
978   fotb.startMultiMode(nic_->hasPrincipalMode ? &nic_->principalMode : 0,
979                       nic_->namedModes,
980                       fotbs);
981   Vector<SymbolObj *> portSyms(nic_->namedModes.size());
982   for (size_t i = 0; i < portSyms.size(); i++)
983     portSyms[i] = context.vm().interp->makeSymbol(nic_->namedModes[i].name);
984   context.pushPorts(nic_->hasPrincipalMode, portSyms, fotbs);
985   CompoundFlowObj::processInner(context);
986   context.popPorts();
987   fotb.endMultiMode();
988 }
989
990 FlowObj *MultiModeFlowObj::copy(Collector &c) const
991 {
992   return new (c) MultiModeFlowObj(*this);
993 }
994
995 bool MultiModeFlowObj::hasNonInheritedC(const Identifier *ident) const
996 {
997   Identifier::SyntacticKey key;
998   return ident->syntacticKey(key) && key == Identifier::keyMultiModes;
999 }
1000
1001 void MultiModeFlowObj::setNonInheritedC(const Identifier *ident, ELObj *obj,
1002                                         const Location &loc, Interpreter &interp)
1003 {
1004   while (!obj->isNil()) {
1005     PairObj *pair = obj->asPair();
1006     if (!pair || !handleMultiModesMember(ident, pair->car(), loc, interp)) {
1007       interp.setNextLocation(loc);
1008       interp.message(InterpreterMessages::invalidCharacteristicValue,
1009                      StringMessageArg(ident->name()));
1010       return;
1011     }
1012     obj = pair->cdr();
1013   }
1014 }
1015
1016 bool MultiModeFlowObj::handleMultiModesMember(const Identifier *, ELObj *obj,
1017                                               const Location &loc, Interpreter &interp)
1018 {
1019   if (obj == interp.makeFalse()) {
1020     nic_->hasPrincipalMode = 1;
1021     return 1;
1022   }
1023   SymbolObj *sym = obj->asSymbol();
1024   if (sym) {
1025     nic_->namedModes.resize(nic_->namedModes.size() + 1);
1026     nic_->namedModes.back().name = *sym->name();
1027     return 1;
1028   }
1029   PairObj *pair = obj->asPair();
1030   if (!pair)
1031     return 0;
1032   ELObj *spec = pair->car();
1033   pair = pair->cdr()->asPair();
1034   if (!pair || !pair->cdr()->isNil())
1035     return 0;
1036   const Char *s;
1037   size_t n;
1038   if (!pair->car()->stringData(s, n))
1039     return 0;
1040   if (spec == interp.makeFalse()) {
1041     nic_->hasPrincipalMode = 1;
1042     nic_->principalMode.hasDesc = 1;
1043     nic_->principalMode.desc.assign(s, n);
1044     return 1;
1045   }
1046   sym = spec->asSymbol();
1047   if (!sym)
1048     return 0;
1049   nic_->namedModes.resize(nic_->namedModes.size() + 1);
1050   nic_->namedModes.back().name = *sym->name();
1051   nic_->namedModes.back().desc.assign(s, n);
1052   nic_->namedModes.back().hasDesc = 1;
1053   return 1;
1054 }
1055
1056
1057 class ScoreFlowObj : public CompoundFlowObj {
1058 public:
1059   void *operator new(size_t, Collector &c) {
1060     return c.allocateObject(1);
1061   }
1062   ScoreFlowObj();
1063   FlowObj *copy(Collector &) const;
1064   void processInner(ProcessContext &);
1065   bool hasNonInheritedC(const Identifier *) const;
1066   void setNonInheritedC(const Identifier *, ELObj *,
1067                         const Location &, Interpreter &);
1068   class Type {
1069   public:
1070     virtual ~Type();
1071     virtual void start(FOTBuilder &) = 0;
1072     virtual Type *copy() const = 0;
1073   };
1074 private:
1075   class SymbolType : public Type {
1076   public:
1077     SymbolType(FOTBuilder::Symbol type) : type_(type) { }
1078     void start(FOTBuilder &);
1079     Type *copy() const;
1080   private:
1081     FOTBuilder::Symbol type_;
1082   };
1083   class LengthSpecType : public Type {
1084   public:
1085     LengthSpecType(long n) : len_(n) { }
1086     void start(FOTBuilder &);
1087     Type *copy() const;
1088   private:
1089     FOTBuilder::LengthSpec len_;
1090   };
1091   class CharType : public Type {
1092   public:
1093     CharType(Char c) : c_(c) { }
1094     void start(FOTBuilder &);
1095     Type *copy() const;
1096   private:
1097     Char c_;
1098   };
1099   CopyOwner<Type> type_;
1100 };
1101
1102 ScoreFlowObj::ScoreFlowObj()
1103 {
1104 }
1105
1106 FlowObj *ScoreFlowObj::copy(Collector &c) const
1107 {
1108   return new (c) ScoreFlowObj(*this);
1109 }
1110
1111 void ScoreFlowObj::processInner(ProcessContext &context)
1112 {
1113   FOTBuilder &fotb = context.currentFOTBuilder();
1114   if (type_)
1115     type_->start(fotb);
1116   else
1117     fotb.startSequence();
1118   CompoundFlowObj::processInner(context);
1119   if (type_)
1120     fotb.endScore();
1121   else
1122     fotb.endSequence();
1123 }
1124
1125 bool ScoreFlowObj::hasNonInheritedC(const Identifier *ident) const
1126 {
1127   Identifier::SyntacticKey key;
1128   return ident->syntacticKey(key) && key == Identifier::keyType;
1129 }
1130
1131 void ScoreFlowObj::setNonInheritedC(const Identifier *ident, ELObj *obj,
1132                                     const Location &loc, Interpreter &interp)
1133 {
1134   Char c;
1135   if (obj->charValue(c)) {
1136     type_ = new CharType(c);
1137     return;
1138   }
1139   double d;
1140   long n;
1141   int dim;
1142   switch (obj->quantityValue(n, d, dim)) {
1143   case longQuantity:
1144     if (dim == 1) {
1145       type_ = new LengthSpecType(n);
1146       return;
1147     }
1148     break;
1149   case doubleQuantity:
1150     if (dim == 1) {
1151       type_ = new LengthSpecType(long(d));
1152       return;
1153     }
1154     break;
1155   default:
1156     break;
1157   }
1158   static FOTBuilder::Symbol vals[] = {
1159     FOTBuilder::symbolBefore,
1160     FOTBuilder::symbolThrough,
1161     FOTBuilder::symbolAfter
1162   };
1163   FOTBuilder::Symbol sym;
1164   if (interp.convertEnumC(vals, SIZEOF(vals), obj, ident, loc, sym))
1165     type_ = new SymbolType(sym);
1166 }
1167
1168 ScoreFlowObj::Type::~Type()
1169 {
1170 }
1171
1172 void ScoreFlowObj::SymbolType::start(FOTBuilder &fotb)
1173 {
1174   fotb.startScore(type_);
1175 }
1176
1177 void ScoreFlowObj::CharType::start(FOTBuilder &fotb)
1178 {
1179   fotb.startScore(c_);
1180 }
1181
1182 void ScoreFlowObj::LengthSpecType::start(FOTBuilder &fotb)
1183 {
1184   fotb.startScore(len_);
1185 }
1186
1187 ScoreFlowObj::Type *ScoreFlowObj::SymbolType::copy() const
1188 {
1189   return new SymbolType(*this);
1190 }
1191
1192 ScoreFlowObj::Type *ScoreFlowObj::LengthSpecType::copy() const
1193 {
1194   return new LengthSpecType(*this);
1195 }
1196
1197 ScoreFlowObj::Type *ScoreFlowObj::CharType::copy() const
1198 {
1199   return new CharType(*this);
1200 }
1201
1202 class BoxFlowObj : public CompoundFlowObj {
1203 public:
1204   void *operator new(size_t, Collector &c) {
1205     return c.allocateObject(1);
1206   }
1207   BoxFlowObj();
1208   BoxFlowObj(const BoxFlowObj &);
1209   FlowObj *copy(Collector &) const;
1210   void processInner(ProcessContext &);
1211   bool hasNonInheritedC(const Identifier *) const;
1212   void setNonInheritedC(const Identifier *, ELObj *,
1213                         const Location &, Interpreter &);
1214 private:
1215   Owner<FOTBuilder::BoxNIC> nic_;
1216 };
1217
1218 BoxFlowObj::BoxFlowObj()
1219 : nic_(new FOTBuilder::BoxNIC)
1220 {
1221 }
1222
1223 BoxFlowObj::BoxFlowObj(const BoxFlowObj &fo)
1224 : CompoundFlowObj(fo), nic_(new FOTBuilder::BoxNIC(*fo.nic_))
1225 {
1226 }
1227
1228 void BoxFlowObj::processInner(ProcessContext &context)
1229 {
1230   FOTBuilder &fotb = context.currentFOTBuilder();
1231   fotb.startBox(*nic_);
1232   CompoundFlowObj::processInner(context);
1233   fotb.endBox();
1234 }
1235
1236 void BoxFlowObj::setNonInheritedC(const Identifier *ident, ELObj *obj,
1237                                               const Location &loc, Interpreter &interp)
1238 {
1239   if (setDisplayNIC(*nic_, ident, obj, loc, interp))
1240     return;
1241   Identifier::SyntacticKey key;
1242   if (ident->syntacticKey(key)) {
1243     switch (key) {
1244     case Identifier::keyIsDisplay:
1245       interp.convertBooleanC(obj, ident, loc, nic_->isDisplay);
1246       return;
1247     case Identifier::keyBreakBeforePriority:
1248       interp.convertIntegerC(obj, ident, loc, nic_->breakBeforePriority);
1249       return;
1250     case Identifier::keyBreakAfterPriority:
1251       interp.convertIntegerC(obj, ident, loc, nic_->breakAfterPriority);
1252       return;
1253     default:
1254       break;
1255     }
1256   }
1257   CANNOT_HAPPEN();
1258 }
1259
1260 bool BoxFlowObj::hasNonInheritedC(const Identifier *ident) const
1261 {
1262   Identifier::SyntacticKey key;
1263   if (ident->syntacticKey(key)) {
1264     switch (key) {
1265     case Identifier::keyIsDisplay:
1266     case Identifier::keyBreakBeforePriority:
1267     case Identifier::keyBreakAfterPriority:
1268       return 1;
1269     default:
1270       break;
1271     }
1272   }
1273   return isDisplayNIC(ident);
1274 }
1275
1276 FlowObj *BoxFlowObj::copy(Collector &c) const
1277 {
1278   return new (c) BoxFlowObj(*this);
1279 }
1280
1281 class LeaderFlowObj : public CompoundFlowObj {
1282 public:
1283   void *operator new(size_t, Collector &c) {
1284     return c.allocateObject(1);
1285   }
1286   LeaderFlowObj();
1287   LeaderFlowObj(const LeaderFlowObj &);
1288   void processInner(ProcessContext &);
1289   FlowObj *copy(Collector &) const;
1290   void setNonInheritedC(const Identifier *, ELObj *,
1291                         const Location &, Interpreter &);
1292   bool hasNonInheritedC(const Identifier *) const;
1293 private:
1294   Owner<FOTBuilder::LeaderNIC> nic_;
1295 };
1296
1297 LeaderFlowObj::LeaderFlowObj()
1298 : nic_(new FOTBuilder::LeaderNIC)
1299 {
1300 }
1301
1302 LeaderFlowObj::LeaderFlowObj(const LeaderFlowObj &fo)
1303 : CompoundFlowObj(fo), nic_(new FOTBuilder::LeaderNIC(*fo.nic_))
1304 {
1305 }
1306
1307 void LeaderFlowObj::processInner(ProcessContext &context)
1308 {
1309   FOTBuilder &fotb = context.currentFOTBuilder();
1310   fotb.startLeader(*nic_);
1311   CompoundFlowObj::processInner(context);
1312   fotb.endLeader();
1313 }
1314
1315 void LeaderFlowObj::setNonInheritedC(const Identifier *ident, ELObj *obj,
1316                                      const Location &loc, Interpreter &interp)
1317 {
1318   Identifier::SyntacticKey key;
1319   if (ident->syntacticKey(key)) {
1320     switch (key) {
1321     case Identifier::keyLength:
1322       if (interp.convertLengthSpecC(obj, ident, loc, nic_->length))
1323         nic_->hasLength = 1;
1324       return;
1325     case Identifier::keyBreakBeforePriority:
1326       interp.convertIntegerC(obj, ident, loc, nic_->breakBeforePriority);
1327       return;
1328     case Identifier::keyBreakAfterPriority:
1329       interp.convertIntegerC(obj, ident, loc, nic_->breakAfterPriority);
1330       return;
1331     default:
1332       break;
1333     }
1334   }
1335   CANNOT_HAPPEN();
1336 }
1337
1338 bool LeaderFlowObj::hasNonInheritedC(const Identifier *ident) const
1339 {
1340   Identifier::SyntacticKey key;
1341   if (ident->syntacticKey(key)) {
1342     switch (key) {
1343     case Identifier::keyLength:
1344     case Identifier::keyBreakBeforePriority:
1345     case Identifier::keyBreakAfterPriority:
1346       return 1;
1347     default:
1348       break;
1349     }
1350   }
1351   return 0;
1352 }
1353
1354 FlowObj *LeaderFlowObj::copy(Collector &c) const
1355 {
1356   return new (c) LeaderFlowObj(*this);
1357 }
1358
1359 class CharacterFlowObj : public FlowObj {
1360 public:
1361   void *operator new(size_t, Collector &c) {
1362     return c.allocateObject(1);
1363   }
1364   CharacterFlowObj();
1365   CharacterFlowObj(const CharacterFlowObj &);
1366   void processInner(ProcessContext &);
1367   FlowObj *copy(Collector &) const;
1368   void setNonInheritedC(const Identifier *, ELObj *,
1369                         const Location &, Interpreter &);
1370   bool setImplicitChar(ELObj *, const Location &, Interpreter &);
1371   bool hasNonInheritedC(const Identifier *) const;
1372   bool characterStyle(ProcessContext &, StyleObj *&style, FOTBuilder::CharacterNIC &nic) {
1373     style = style_;
1374     nic = *nic_;
1375     return 1;
1376   }
1377   bool isCharacter() { return 1; }
1378 private:
1379   Owner<FOTBuilder::CharacterNIC> nic_;
1380 };
1381
1382 CharacterFlowObj::CharacterFlowObj()
1383 : nic_(new FOTBuilder::CharacterNIC)
1384 {
1385 }
1386
1387 CharacterFlowObj::CharacterFlowObj(const CharacterFlowObj &fo)
1388 : FlowObj(fo), nic_(new FOTBuilder::CharacterNIC(*fo.nic_))
1389 {
1390 }
1391
1392 void CharacterFlowObj::processInner(ProcessContext &context)
1393 {
1394   context.currentFOTBuilder().character(*nic_);
1395 }
1396
1397 bool FlowObj::setImplicitChar(ELObj *obj, const Location &loc, 
1398                                        Interpreter &interp)
1399 {
1400   CANNOT_HAPPEN();
1401   return false;
1402 }
1403
1404
1405 bool CharacterFlowObj::setImplicitChar(ELObj *obj, const Location &loc, 
1406                                        Interpreter &interp)
1407 {
1408   Identifier *ident = interp.lookup(interp.makeStringC("char")); 
1409   if (!(nic_->specifiedC & (1 << FOTBuilder::CharacterNIC::cChar))
1410       && interp.convertCharC(obj, ident, loc, nic_->ch)) {
1411     nic_->valid = 1;
1412     
1413     if (!(nic_->specifiedC & (1 << FOTBuilder::CharacterNIC::cIsSpace)))  
1414       interp.convertBooleanC(
1415                              interp.charProperty(interp.makeStringC("space?"), 
1416                                                  nic_->ch, loc, 0),  
1417                              ident, loc, nic_->isSpace);
1418     
1419     if (!(nic_->specifiedC & (1 << FOTBuilder::CharacterNIC::cIsRecordEnd)))  
1420       interp.convertBooleanC(
1421                              interp.charProperty(interp.makeStringC("record-end?"), 
1422                                                  nic_->ch, loc, 0),
1423                              ident, loc, nic_->isRecordEnd);
1424     
1425     if (!(nic_->specifiedC & (1 << FOTBuilder::CharacterNIC::cIsInputTab))) 
1426       interp.convertBooleanC(
1427                              interp.charProperty(interp.makeStringC("input-tab?"), 
1428                                                  nic_->ch, loc, 0),
1429                              ident, loc, nic_->isInputTab);
1430     
1431     if (!(nic_->specifiedC & (1 << FOTBuilder::CharacterNIC::cIsInputWhitespace)))  
1432       interp.convertBooleanC(
1433                              interp.charProperty(interp.makeStringC("input-whitespace?"), 
1434                                                  nic_->ch, loc, 0),
1435                              ident, loc, nic_->isInputWhitespace);
1436     
1437     if (!(nic_->specifiedC & (1 << FOTBuilder::CharacterNIC::cIsPunct)))  
1438       interp.convertBooleanC(
1439                              interp.charProperty(interp.makeStringC("punct?"), 
1440                                                  nic_->ch, loc, 0),
1441                              ident, loc, nic_->isPunct);
1442     
1443     if (!(nic_->specifiedC & (1 << FOTBuilder::CharacterNIC::cIsDropAfterLineBreak)))  
1444       interp.convertBooleanC(
1445                              interp.charProperty(interp.makeStringC("drop-after-line-break?"), 
1446                                                  nic_->ch, loc, 0),
1447                              ident, loc, nic_->isDropAfterLineBreak); 
1448     
1449     if (!(nic_->specifiedC & (1 << FOTBuilder::CharacterNIC::cIsDropUnlessBeforeLineBreak)))  
1450       interp.convertBooleanC(
1451                              interp.charProperty(interp.makeStringC("drop-unless-before-line-break?"), 
1452                                                  nic_->ch, loc, 0),
1453                              ident, loc, nic_->isDropUnlessBeforeLineBreak); 
1454     
1455     if (!(nic_->specifiedC & (1 << FOTBuilder::CharacterNIC::cBreakBeforePriority))) 
1456       interp.convertIntegerC(
1457                              interp.charProperty(interp.makeStringC("break-before-priority"), 
1458                                                  nic_->ch, loc, 0),
1459                              ident, loc, nic_->breakBeforePriority);  
1460     
1461     if (!(nic_->specifiedC & (1 << FOTBuilder::CharacterNIC::cBreakAfterPriority))) 
1462       interp.convertIntegerC(
1463                              interp.charProperty(interp.makeStringC("break-after-priority"), 
1464                                                  nic_->ch, loc, 0),
1465                              ident, loc, nic_->breakAfterPriority);  
1466     
1467     if (!(nic_->specifiedC & (1 << FOTBuilder::CharacterNIC::cScript))) {
1468       ELObj *prop = interp.charProperty(interp.makeStringC("script"), 
1469                                         nic_->ch, loc, 0);
1470       if (prop == interp.makeFalse())
1471         nic_->script = 0;
1472       else {
1473         StringC tem;
1474         if (interp.convertStringC(prop, ident, loc, tem))
1475           nic_->script = interp.storePublicId(tem.data(), tem.size(), loc);
1476       }
1477     }
1478     
1479     if (!(nic_->specifiedC & (1 << FOTBuilder::CharacterNIC::cGlyphId))) {
1480       ELObj *prop = interp.charProperty(interp.makeStringC("glyph-id"), 
1481                                         nic_->ch, loc, 0);
1482       if (prop == interp.makeFalse()) 
1483         nic_->glyphId = FOTBuilder::GlyphId();
1484       else {
1485         const FOTBuilder::GlyphId *p = prop->glyphId();
1486         if (p) 
1487           nic_->glyphId = *p;
1488       }
1489     }
1490     
1491     if (!(nic_->specifiedC & (1 << FOTBuilder::CharacterNIC::cMathFontPosture))) {
1492       ELObj *prop = interp.charProperty(interp.makeStringC("math-font-posture"), 
1493                                         nic_->ch, loc, 0);
1494       static FOTBuilder::Symbol vals[] = {
1495         FOTBuilder::symbolFalse,
1496         FOTBuilder::symbolNotApplicable,
1497         FOTBuilder::symbolUpright,
1498         FOTBuilder::symbolOblique,
1499         FOTBuilder::symbolBackSlantedOblique,
1500         FOTBuilder::symbolItalic,
1501         FOTBuilder::symbolBackSlantedItalic,
1502       };
1503       interp.convertEnumC(vals, SIZEOF(vals), prop, ident, loc, nic_->mathFontPosture);
1504     }
1505     
1506     if (!(nic_->specifiedC & (1 << FOTBuilder::CharacterNIC::cMathClass))) {
1507       ELObj *prop = interp.charProperty(interp.makeStringC("math-class"), 
1508                                         nic_->ch, loc, 0);
1509       static FOTBuilder::Symbol vals[] = {
1510         FOTBuilder::symbolOrdinary,
1511         FOTBuilder::symbolOperator,
1512         FOTBuilder::symbolBinary,
1513         FOTBuilder::symbolRelation,
1514         FOTBuilder::symbolOpening,
1515         FOTBuilder::symbolClosing,
1516         FOTBuilder::symbolPunctuation,
1517         FOTBuilder::symbolInner,
1518         FOTBuilder::symbolSpace,
1519       };
1520       interp.convertEnumC(vals, SIZEOF(vals), prop, ident, loc, nic_->mathClass);
1521     }
1522     
1523     return 1;
1524   }
1525   else 
1526     return 0; 
1527 }
1528
1529 void CharacterFlowObj::setNonInheritedC(const Identifier *ident, ELObj *obj,
1530                                         const Location &loc, Interpreter &interp)
1531 {
1532   Identifier::SyntacticKey key;
1533   if (ident->syntacticKey(key)) {
1534     switch (key) {
1535     case Identifier::keyIsSpace:
1536       if (interp.convertBooleanC(obj, ident, loc, nic_->isSpace))
1537         nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cIsSpace);
1538       return;
1539     case Identifier::keyIsRecordEnd:
1540       if (interp.convertBooleanC(obj, ident, loc, nic_->isRecordEnd))
1541         nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cIsRecordEnd);
1542       return;
1543     case Identifier::keyIsInputTab:
1544       if (interp.convertBooleanC(obj, ident, loc, nic_->isInputTab))
1545         nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cIsInputTab);
1546       return;
1547     case Identifier::keyIsInputWhitespace:
1548       if (interp.convertBooleanC(obj, ident, loc, nic_->isInputWhitespace))
1549         nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cIsInputWhitespace);
1550       return;
1551     case Identifier::keyIsPunct:
1552       if (interp.convertBooleanC(obj, ident, loc, nic_->isPunct))
1553         nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cIsPunct);
1554       return;
1555     case Identifier::keyIsDropAfterLineBreak:
1556       if (interp.convertBooleanC(obj, ident, loc, nic_->isDropAfterLineBreak))
1557         nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cIsDropAfterLineBreak);
1558       return;
1559     case Identifier::keyIsDropUnlessBeforeLineBreak:
1560       if (interp.convertBooleanC(obj, ident, loc, nic_->isDropUnlessBeforeLineBreak))
1561         nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cIsDropUnlessBeforeLineBreak);
1562       return;
1563     case Identifier::keyBreakBeforePriority:
1564       if (interp.convertIntegerC(obj, ident, loc, nic_->breakBeforePriority))
1565         nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cBreakBeforePriority);
1566       return;
1567     case Identifier::keyBreakAfterPriority:
1568       if (interp.convertIntegerC(obj, ident, loc, nic_->breakAfterPriority))
1569         nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cBreakAfterPriority);
1570       return;
1571     case Identifier::keyScript:
1572       {
1573         if (obj == interp.makeFalse())
1574           nic_->script = 0;
1575         else {
1576           StringC tem;
1577           if (!interp.convertStringC(obj, ident, loc, tem))
1578             return;
1579           nic_->script = interp.storePublicId(tem.data(), tem.size(), loc);
1580         }
1581         nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cScript);
1582       }
1583       return;
1584     case Identifier::keyChar:
1585       if (setImplicitChar(obj, loc, interp)) { 
1586         nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cChar);
1587         if (!(nic_->specifiedC & (1 << FOTBuilder::CharacterNIC::cIsInputTab))) 
1588           nic_->isInputTab = 0;
1589         if (!(nic_->specifiedC & (1 << FOTBuilder::CharacterNIC::cIsInputWhitespace))) 
1590           nic_->isInputWhitespace = 0;
1591       }
1592       return;
1593     case Identifier::keyGlyphId:
1594       {
1595         if (obj == interp.makeFalse()) {
1596           nic_->glyphId = FOTBuilder::GlyphId();
1597           nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cGlyphId);
1598           return;
1599         }
1600         const FOTBuilder::GlyphId *p = obj->glyphId();
1601         if (!p) {
1602           interp.setNextLocation(loc);
1603           interp.message(InterpreterMessages::invalidCharacteristicValue,
1604                          StringMessageArg(ident->name()));
1605           return;
1606         }
1607         nic_->glyphId = *p;
1608         nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cGlyphId);
1609       }
1610       return;
1611     case Identifier::keyMathFontPosture:
1612       {
1613         static FOTBuilder::Symbol vals[] = {
1614           FOTBuilder::symbolFalse,
1615           FOTBuilder::symbolNotApplicable,
1616           FOTBuilder::symbolUpright,
1617           FOTBuilder::symbolOblique,
1618           FOTBuilder::symbolBackSlantedOblique,
1619           FOTBuilder::symbolItalic,
1620           FOTBuilder::symbolBackSlantedItalic,
1621         };
1622         if (interp.convertEnumC(vals, SIZEOF(vals), obj, ident, loc, nic_->mathFontPosture))
1623           nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cMathFontPosture);
1624       }
1625       return;
1626     case Identifier::keyMathClass:
1627       {
1628         static FOTBuilder::Symbol vals[] = {
1629           FOTBuilder::symbolOrdinary,
1630           FOTBuilder::symbolOperator,
1631           FOTBuilder::symbolBinary,
1632           FOTBuilder::symbolRelation,
1633           FOTBuilder::symbolOpening,
1634           FOTBuilder::symbolClosing,
1635           FOTBuilder::symbolPunctuation,
1636           FOTBuilder::symbolInner,
1637           FOTBuilder::symbolSpace,
1638         };
1639         if (interp.convertEnumC(vals, SIZEOF(vals), obj, ident, loc, nic_->mathClass))
1640           nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cMathClass);
1641       }
1642       return;
1643     case Identifier::keyStretchFactor:
1644       interp.convertRealC(obj, ident, loc, nic_->stretchFactor);
1645       return;
1646     default:
1647       break;
1648     }
1649   }
1650   else {
1651     unsigned part;
1652     Location loc;
1653     if (ident->charNICDefined(part, loc))
1654       return;
1655   }
1656   CANNOT_HAPPEN();
1657 }
1658
1659 bool CharacterFlowObj::hasNonInheritedC(const Identifier *ident) const
1660 {
1661   Identifier::SyntacticKey key;
1662   if (ident->syntacticKey(key)) {
1663     switch (key) {
1664     case Identifier::keyChar:
1665     case Identifier::keyGlyphId:
1666     case Identifier::keyIsSpace:
1667     case Identifier::keyIsRecordEnd:
1668     case Identifier::keyIsInputTab:
1669     case Identifier::keyIsInputWhitespace:
1670     case Identifier::keyIsPunct:
1671     case Identifier::keyIsDropAfterLineBreak:
1672     case Identifier::keyIsDropUnlessBeforeLineBreak:
1673     case Identifier::keyScript:
1674     case Identifier::keyMathClass:
1675     case Identifier::keyMathFontPosture:
1676     case Identifier::keyStretchFactor:
1677     case Identifier::keyBreakBeforePriority:
1678     case Identifier::keyBreakAfterPriority:
1679       return 1;
1680     default:
1681       break;
1682     }
1683   } 
1684   unsigned part;
1685   Location loc;
1686   if (ident->charNICDefined(part, loc))
1687     return 1;
1688   return 0;
1689 }
1690
1691 FlowObj *CharacterFlowObj::copy(Collector &c) const
1692 {
1693   return new (c) CharacterFlowObj(*this);
1694 }
1695
1696 class MathSequenceFlowObj : public CompoundFlowObj {
1697 public:
1698   MathSequenceFlowObj() { }
1699   void processInner(ProcessContext &context) {
1700     FOTBuilder &fotb = context.currentFOTBuilder();
1701     fotb.startMathSequence();
1702     CompoundFlowObj::processInner(context);
1703     fotb.endMathSequence();
1704   }
1705   FlowObj *copy(Collector &c) const {
1706     return new (c) MathSequenceFlowObj(*this);
1707   }
1708 };
1709
1710 class FractionFlowObj : public CompoundFlowObj {
1711 public:
1712   FractionFlowObj() { }
1713   void processInner(ProcessContext &);
1714   FlowObj *copy(Collector &) const;
1715 };
1716
1717 void FractionFlowObj::processInner(ProcessContext &context)
1718 {
1719   FOTBuilder &fotb = context.currentFOTBuilder();
1720   Vector<FOTBuilder *> fotbs(2);
1721   fotb.startFraction(fotbs[0], fotbs[1]);
1722   Vector<size_t> dep;
1723   StyleObj *fractionBarStyle = 0;
1724   SosofoObj *sosofo
1725     = context.currentStyleStack().actual(context.vm().interp->fractionBarC(),
1726                                          *context.vm().interp, dep)->asSosofo();
1727   if (sosofo)
1728     sosofo->ruleStyle(context, fractionBarStyle);
1729   if (fractionBarStyle)
1730     context.currentStyleStack().push(fractionBarStyle, context.vm(), fotb);
1731   fotb.fractionBar();
1732   if (fractionBarStyle)
1733     context.currentStyleStack().pop();
1734   Vector<SymbolObj *> labels(2);
1735   labels[0] = context.vm().interp->portName(Interpreter::portNumerator);
1736   labels[1] = context.vm().interp->portName(Interpreter::portDenominator);
1737   context.pushPorts(0, labels, fotbs);
1738   // Fraction flow object doesn't have principal port,
1739   // so clear the current connection.
1740   CompoundFlowObj::processInner(context);
1741   context.popPorts();
1742   fotb.endFraction();
1743 }
1744
1745 FlowObj *FractionFlowObj::copy(Collector &c) const
1746 {
1747   return new (c) FractionFlowObj(*this);
1748 }
1749
1750 class UnmathFlowObj : public CompoundFlowObj {
1751 public:
1752   UnmathFlowObj() { }
1753   void processInner(ProcessContext &context) {
1754     FOTBuilder &fotb = context.currentFOTBuilder();
1755     fotb.startUnmath();
1756     CompoundFlowObj::processInner(context);
1757     fotb.endUnmath();
1758   }
1759   FlowObj *copy(Collector &c) const {
1760     return new (c) UnmathFlowObj(*this);
1761   }
1762 };
1763
1764 class SuperscriptFlowObj : public CompoundFlowObj {
1765 public:
1766   SuperscriptFlowObj() { }
1767   void processInner(ProcessContext &context) {
1768     FOTBuilder &fotb = context.currentFOTBuilder();
1769     fotb.startSuperscript();
1770     CompoundFlowObj::processInner(context);
1771     fotb.endSuperscript();
1772   }
1773   FlowObj *copy(Collector &c) const {
1774     return new (c) SuperscriptFlowObj(*this);
1775   }
1776 };
1777
1778 class SubscriptFlowObj : public CompoundFlowObj {
1779 public:
1780   SubscriptFlowObj() { }
1781   void processInner(ProcessContext &context) {
1782     FOTBuilder &fotb = context.currentFOTBuilder();
1783     fotb.startSubscript();
1784     CompoundFlowObj::processInner(context);
1785     fotb.endSubscript();
1786   }
1787   FlowObj *copy(Collector &c) const {
1788     return new (c) SubscriptFlowObj(*this);
1789   }
1790 };
1791
1792 class ScriptFlowObj : public CompoundFlowObj {
1793 public:
1794   ScriptFlowObj() { }
1795   void processInner(ProcessContext &);
1796   FlowObj *copy(Collector &c) const {
1797     return new (c) ScriptFlowObj(*this);
1798   }
1799
1800 };
1801
1802 void ScriptFlowObj::processInner(ProcessContext &context)
1803 {
1804   FOTBuilder &fotb = context.currentFOTBuilder();
1805   Vector<FOTBuilder *> fotbs(6);
1806   fotb.startScript(fotbs[0], fotbs[1], fotbs[2], fotbs[3],
1807                    fotbs[4], fotbs[5]);
1808   Vector<SymbolObj *> labels(6);
1809   labels[0] = context.vm().interp->portName(Interpreter::portPreSup);
1810   labels[1] = context.vm().interp->portName(Interpreter::portPreSub);
1811   labels[2] = context.vm().interp->portName(Interpreter::portPostSup);
1812   labels[3] = context.vm().interp->portName(Interpreter::portPostSub);
1813   labels[4] = context.vm().interp->portName(Interpreter::portMidSup);
1814   labels[5] = context.vm().interp->portName(Interpreter::portMidSub);
1815   context.pushPorts(1, labels, fotbs);
1816   CompoundFlowObj::processInner(context);
1817   context.popPorts();
1818   fotb.endScript();
1819 }
1820
1821 class MarkFlowObj : public CompoundFlowObj {
1822 public:
1823   MarkFlowObj() { }
1824   void processInner(ProcessContext &);
1825   FlowObj *copy(Collector &c) const {
1826     return new (c) MarkFlowObj(*this);
1827   }
1828 };
1829
1830 void MarkFlowObj::processInner(ProcessContext &context)
1831 {
1832   FOTBuilder &fotb = context.currentFOTBuilder();
1833   Vector<FOTBuilder *> fotbs(2);
1834   fotb.startMark(fotbs[0], fotbs[1]);
1835   Vector<SymbolObj *> labels(2);
1836   labels[0] = context.vm().interp->portName(Interpreter::portOverMark);
1837   labels[1] = context.vm().interp->portName(Interpreter::portUnderMark);
1838   context.pushPorts(1, labels, fotbs);
1839   CompoundFlowObj::processInner(context);
1840   context.popPorts();
1841   fotb.endMark();
1842 }
1843
1844 class FenceFlowObj : public CompoundFlowObj {
1845 public:
1846   FenceFlowObj() { }
1847   void processInner(ProcessContext &);
1848   FlowObj *copy(Collector &c) const {
1849     return new (c) FenceFlowObj(*this);
1850   }
1851 };
1852
1853 void FenceFlowObj::processInner(ProcessContext &context)
1854 {
1855   FOTBuilder &fotb = context.currentFOTBuilder();
1856   Vector<FOTBuilder *> fotbs(2);
1857   fotb.startFence(fotbs[0], fotbs[1]);
1858   Vector<SymbolObj *> labels(2);
1859   labels[0] = context.vm().interp->portName(Interpreter::portOpen);
1860   labels[1] = context.vm().interp->portName(Interpreter::portClose);
1861   context.pushPorts(1, labels, fotbs);
1862   CompoundFlowObj::processInner(context);
1863   context.popPorts();
1864   fotb.endFence();
1865 }
1866
1867 class RadicalFlowObj : public CompoundFlowObj {
1868 public:
1869   RadicalFlowObj() : radical_(0) { }
1870   void processInner(ProcessContext &);
1871   FlowObj *copy(Collector &c) const {
1872     return new (c) RadicalFlowObj(*this);
1873   }
1874   void setNonInheritedC(const Identifier *, ELObj *,
1875                         const Location &, Interpreter &);
1876   bool hasNonInheritedC(const Identifier *) const;
1877   void traceSubObjects(Collector &c) const {
1878     c.trace(radical_);
1879     CompoundFlowObj::traceSubObjects(c);
1880   }
1881 private:
1882   SosofoObj *radical_;
1883 };
1884
1885 void RadicalFlowObj::processInner(ProcessContext &context)
1886 {
1887   FOTBuilder &fotb = context.currentFOTBuilder();
1888   Vector<FOTBuilder *> fotbs(1);
1889   fotb.startRadical(fotbs[0]);
1890   StyleObj *style;
1891   FOTBuilder::CharacterNIC nic;
1892   if (radical_ && radical_->characterStyle(context, style, nic)) {
1893     if (style)
1894       context.currentStyleStack().push(style, context.vm(), fotb);
1895     fotb.radicalRadical(nic);
1896     if (style)
1897       context.currentStyleStack().pop();
1898   }
1899   else 
1900     fotb.radicalRadicalDefaulted();
1901   Vector<SymbolObj *> labels(1);
1902   labels[0] = context.vm().interp->portName(Interpreter::portDegree);
1903   context.pushPorts(1, labels, fotbs);
1904   CompoundFlowObj::processInner(context);
1905   context.popPorts();
1906   fotb.endRadical();
1907 }
1908
1909 bool RadicalFlowObj::hasNonInheritedC(const Identifier *ident) const
1910 {
1911   Identifier::SyntacticKey key;
1912   return ident->syntacticKey(key) && key == Identifier::keyRadical;
1913 }
1914
1915 void RadicalFlowObj::setNonInheritedC(const Identifier *ident, ELObj *obj,
1916                                       const Location &loc, Interpreter &interp)
1917 {
1918   radical_ = obj->asSosofo();
1919   if (!radical_ || !radical_->isCharacter()) {
1920     interp.setNextLocation(loc);
1921     interp.message(InterpreterMessages::invalidCharacteristicValue,
1922                    StringMessageArg(ident->name()));
1923   }
1924 }
1925
1926 class MathOperatorFlowObj : public CompoundFlowObj {
1927 public:
1928   MathOperatorFlowObj() { }
1929   void processInner(ProcessContext &);
1930   FlowObj *copy(Collector &c) const {
1931     return new (c) MathOperatorFlowObj(*this);
1932   }
1933 };
1934
1935 void MathOperatorFlowObj::processInner(ProcessContext &context)
1936 {
1937   FOTBuilder &fotb = context.currentFOTBuilder();
1938   Vector<FOTBuilder *> fotbs(3);
1939   fotb.startMathOperator(fotbs[0], fotbs[1], fotbs[2]);
1940   Vector<SymbolObj *> labels(3);
1941   labels[0] = context.vm().interp->portName(Interpreter::portOperator);
1942   labels[1] = context.vm().interp->portName(Interpreter::portLowerLimit);
1943   labels[2] = context.vm().interp->portName(Interpreter::portUpperLimit);
1944   context.pushPorts(1, labels, fotbs);
1945   CompoundFlowObj::processInner(context);
1946   context.popPorts();
1947   fotb.endMathOperator();
1948 }
1949
1950 class GridFlowObj : public CompoundFlowObj {
1951 public:
1952   void *operator new(size_t, Collector &c) {
1953     return c.allocateObject(1);
1954   }
1955   GridFlowObj();
1956   GridFlowObj(const GridFlowObj &);
1957   void processInner(ProcessContext &);
1958   FlowObj *copy(Collector &c) const {
1959     return new (c) GridFlowObj(*this);
1960   }
1961   void setNonInheritedC(const Identifier *, ELObj *,
1962                         const Location &, Interpreter &);
1963   bool hasNonInheritedC(const Identifier *) const;
1964 private:
1965   Owner<FOTBuilder::GridNIC> nic_;
1966 };
1967
1968 GridFlowObj::GridFlowObj()
1969 : nic_(new FOTBuilder::GridNIC)
1970 {
1971 }
1972
1973 GridFlowObj::GridFlowObj(const GridFlowObj &fo)
1974 : CompoundFlowObj(fo), nic_(new FOTBuilder::GridNIC(*fo.nic_))
1975 {
1976 }
1977
1978 void GridFlowObj::processInner(ProcessContext &context)
1979 {
1980   FOTBuilder &fotb = context.currentFOTBuilder();
1981   fotb.startGrid(*nic_);
1982   CompoundFlowObj::processInner(context);
1983   fotb.endGrid();
1984 }
1985
1986 void GridFlowObj::setNonInheritedC(const Identifier *ident, ELObj *obj,
1987                                         const Location &loc, Interpreter &interp)
1988 {
1989   long tem;
1990   if (!interp.convertIntegerC(obj, ident, loc, tem))
1991     return;
1992   if (tem <= 0) {
1993     interp.setNextLocation(loc);
1994     interp.message(InterpreterMessages::invalidCharacteristicValue,
1995                    StringMessageArg(ident->name()));
1996     return;
1997   }
1998   Identifier::SyntacticKey key;
1999   if (ident->syntacticKey(key)) {
2000     switch (key) {
2001     case Identifier::keyGridNColumns:
2002       nic_->nColumns = tem;
2003       return;
2004     case Identifier::keyGridNRows:
2005       nic_->nRows = tem;
2006       return;
2007     default:
2008       break;
2009     }
2010   }
2011   CANNOT_HAPPEN();
2012 }
2013
2014 bool GridFlowObj::hasNonInheritedC(const Identifier *ident) const
2015 {
2016   Identifier::SyntacticKey key;
2017   if (ident->syntacticKey(key)) {
2018     switch (key) {
2019     case Identifier::keyGridNColumns:
2020     case Identifier::keyGridNRows:
2021       return 1;
2022     default:
2023       break;
2024     }
2025   }
2026   return 0;
2027 }
2028
2029 class GridCellFlowObj : public CompoundFlowObj {
2030 public:
2031   void *operator new(size_t, Collector &c) {
2032     return c.allocateObject(1);
2033   }
2034   GridCellFlowObj();
2035   GridCellFlowObj(const GridCellFlowObj &);
2036   void processInner(ProcessContext &);
2037   FlowObj *copy(Collector &c) const {
2038     return new (c) GridCellFlowObj(*this);
2039   }
2040   void setNonInheritedC(const Identifier *, ELObj *,
2041                         const Location &, Interpreter &);
2042   bool hasNonInheritedC(const Identifier *) const;
2043 private:
2044   Owner<FOTBuilder::GridCellNIC> nic_;
2045 };
2046
2047 GridCellFlowObj::GridCellFlowObj()
2048 : nic_(new FOTBuilder::GridCellNIC)
2049 {
2050 }
2051
2052 GridCellFlowObj::GridCellFlowObj(const GridCellFlowObj &fo)
2053 : CompoundFlowObj(fo), nic_(new FOTBuilder::GridCellNIC(*fo.nic_))
2054 {
2055 }
2056
2057 void GridCellFlowObj::processInner(ProcessContext &context)
2058 {
2059   FOTBuilder &fotb = context.currentFOTBuilder();
2060   fotb.startGridCell(*nic_);
2061   CompoundFlowObj::processInner(context);
2062   fotb.endGridCell();
2063 }
2064
2065 void GridCellFlowObj::setNonInheritedC(const Identifier *ident, ELObj *obj,
2066                                        const Location &loc, Interpreter &interp)
2067 {
2068   long tem;
2069   if (!interp.convertIntegerC(obj, ident, loc, tem))
2070     return;
2071   if (tem <= 0) {
2072     interp.setNextLocation(loc);
2073     interp.message(InterpreterMessages::invalidCharacteristicValue,
2074                    StringMessageArg(ident->name()));
2075     return;
2076   }
2077   Identifier::SyntacticKey key;
2078   if (ident->syntacticKey(key)) {
2079     switch (key) {
2080     case Identifier::keyColumnNumber:
2081       nic_->columnNumber = tem;
2082       return;
2083     case Identifier::keyRowNumber:
2084       nic_->rowNumber = tem;
2085       return;
2086     default:
2087       break;
2088     }
2089   }
2090   CANNOT_HAPPEN();
2091 }
2092
2093 bool GridCellFlowObj::hasNonInheritedC(const Identifier *ident) const
2094 {
2095   Identifier::SyntacticKey key;
2096   if (ident->syntacticKey(key)) {
2097     switch (key) {
2098     case Identifier::keyColumnNumber:
2099     case Identifier::keyRowNumber:
2100       return 1;
2101     default:
2102       break;
2103     }
2104   }
2105   return 0;
2106 }
2107
2108 class TableFlowObj : public CompoundFlowObj {
2109 public:
2110   void *operator new(size_t, Collector &c) {
2111     return c.allocateObject(1);
2112   }
2113   struct NIC : public FOTBuilder::TableNIC {
2114     NIC() : beforeRowBorder(0), afterRowBorder(0),
2115             beforeColumnBorder(0), afterColumnBorder(0) { }
2116     StyleObj *beforeRowBorder;
2117     StyleObj *afterRowBorder;
2118     StyleObj *beforeColumnBorder;
2119     StyleObj *afterColumnBorder;
2120   };
2121   TableFlowObj() : nic_(new NIC) { }
2122   TableFlowObj(const TableFlowObj &fo) : CompoundFlowObj(fo), nic_(new NIC(*fo.nic_)) { }
2123   void processInner(ProcessContext &context) {
2124     context.startTable();
2125     FOTBuilder &fotb = context.currentFOTBuilder();
2126     fotb.startTable(*nic_);
2127     Interpreter &interp = *context.vm().interp;
2128     Vector<size_t> dep;
2129     ELObj *obj = context.currentStyleStack().actual(interp.tableBorderC(), interp, dep);
2130     StyleObj *borderStyle;
2131     if (obj == interp.makeFalse())
2132       borderStyle = interp.borderFalseStyle();
2133     else if (obj == interp.makeTrue())
2134       borderStyle = interp.borderTrueStyle();
2135     else {
2136       SosofoObj *sosofo = obj->asSosofo();
2137       if (!sosofo || !sosofo->tableBorderStyle(borderStyle))
2138         borderStyle = 0;
2139     }
2140     border(nic_->beforeRowBorder, borderStyle, &FOTBuilder::tableBeforeRowBorder, context);
2141     border(nic_->afterRowBorder, borderStyle, &FOTBuilder::tableAfterRowBorder, context);
2142     border(nic_->beforeColumnBorder, borderStyle, &FOTBuilder::tableBeforeColumnBorder, context);
2143     border(nic_->afterColumnBorder, borderStyle, &FOTBuilder::tableAfterColumnBorder, context);
2144     CompoundFlowObj::processInner(context);
2145     if (context.inTableRow())
2146       context.endTableRow();
2147     context.endTable();
2148     fotb.endTable();
2149   }
2150   FlowObj *copy(Collector &c) const {
2151     return new (c) TableFlowObj(*this);
2152   }
2153   bool hasNonInheritedC(const Identifier *ident) const {
2154     Identifier::SyntacticKey key;
2155     if (ident->syntacticKey(key)) {
2156       switch (key) {
2157       case Identifier::keyBeforeRowBorder:
2158       case Identifier::keyAfterRowBorder:
2159       case Identifier::keyBeforeColumnBorder:
2160       case Identifier::keyAfterColumnBorder:
2161       case Identifier::keyTableWidth:
2162         return 1;
2163       default:
2164         break;
2165       }
2166     }
2167     return isDisplayNIC(ident);
2168   }
2169   void setNonInheritedC(const Identifier *ident, ELObj *obj,
2170                         const Location &loc, Interpreter &interp) {
2171     if (setDisplayNIC(*nic_, ident, obj, loc, interp))
2172       return;
2173     Identifier::SyntacticKey key;
2174     if (!ident->syntacticKey(key))
2175       CANNOT_HAPPEN();
2176     if (key == Identifier::keyTableWidth) {
2177       if (obj == interp.makeFalse())
2178         nic_->widthType = FOTBuilder::TableNIC::widthMinimum;
2179       else if (interp.convertLengthSpecC(obj, ident, loc, nic_->width))
2180         nic_->widthType = FOTBuilder::TableNIC::widthExplicit;
2181       return;
2182     }
2183     StyleObj *style;
2184     SosofoObj *sosofo = obj->asSosofo();
2185     if (!sosofo || !sosofo->tableBorderStyle(style)) {
2186       Boolean b;
2187       if (!interp.convertBooleanC(obj, ident, loc, b))
2188         return;
2189       style = b ? interp.borderTrueStyle() : interp.borderFalseStyle();
2190     }
2191     switch (key) {
2192     case Identifier::keyBeforeRowBorder:
2193       nic_->beforeRowBorder = style;
2194       break;
2195     case Identifier::keyAfterRowBorder:
2196       nic_->afterRowBorder = style;
2197       break;
2198     case Identifier::keyBeforeColumnBorder:
2199       nic_->beforeColumnBorder = style;
2200       break;
2201     case Identifier::keyAfterColumnBorder:
2202       nic_->afterColumnBorder = style;
2203       break;
2204     default:
2205       CANNOT_HAPPEN();
2206     }
2207   }
2208 private:
2209   void border(StyleObj *style, StyleObj *style2,
2210               void (FOTBuilder::*setter)(), ProcessContext &context) {
2211     FOTBuilder &fotb = context.currentFOTBuilder();
2212     if (!style)
2213       style = style2;
2214     if (style)
2215       context.currentStyleStack().push(style, context.vm(), fotb);
2216     (fotb.*setter)();
2217     if (style)
2218       context.currentStyleStack().pop();
2219   }
2220   Owner<NIC> nic_;
2221 };
2222
2223 class TablePartFlowObj : public CompoundFlowObj {
2224 public:
2225   void *operator new(size_t, Collector &c) {
2226     return c.allocateObject(1);
2227   }
2228   TablePartFlowObj() : nic_(new FOTBuilder::TablePartNIC) { }
2229   TablePartFlowObj(const TablePartFlowObj &fo)
2230     : CompoundFlowObj(fo), nic_(new FOTBuilder::TablePartNIC(*fo.nic_)) { }
2231   void processInner(ProcessContext &context) {
2232     context.startTablePart();
2233     FOTBuilder &fotb = context.currentFOTBuilder();
2234     Vector<FOTBuilder *> fotbs(2);
2235     fotb.startTablePart(*nic_, fotbs[0], fotbs[1]);
2236     Vector<SymbolObj *> labels(2);
2237     labels[0] = context.vm().interp->portName(Interpreter::portHeader);
2238     labels[1] = context.vm().interp->portName(Interpreter::portFooter);
2239     context.pushPorts(1, labels, fotbs);
2240     CompoundFlowObj::processInner(context);
2241     context.popPorts();
2242     if (context.inTableRow())
2243       context.endTableRow();
2244     context.endTablePart();
2245     fotb.endTablePart();
2246   }
2247   FlowObj *copy(Collector &c) const {
2248     return new (c) TablePartFlowObj(*this);
2249   }
2250   void setNonInheritedC(const Identifier *ident, ELObj *obj,
2251                         const Location &loc, Interpreter &interp) {
2252     setDisplayNIC(*nic_, ident, obj, loc, interp);
2253   }
2254   bool hasNonInheritedC(const Identifier *ident) const {
2255     if (!isDisplayNIC(ident))
2256       return 0;
2257     Identifier::SyntacticKey key;
2258     ident->syntacticKey(key);
2259     if (key == Identifier::keyPositionPreference)
2260       return 0;
2261     return 1;
2262   }
2263 private:
2264   Owner<FOTBuilder::TablePartNIC> nic_;
2265 };
2266
2267 class TableColumnFlowObj : public FlowObj {
2268 public:
2269   void *operator new(size_t, Collector &c) {
2270     return c.allocateObject(1);
2271   }
2272   struct NIC : public FOTBuilder::TableColumnNIC {
2273     NIC() : hasColumnNumber(0) { }
2274     bool hasColumnNumber;
2275   };
2276   TableColumnFlowObj() : nic_(new NIC) { }
2277   TableColumnFlowObj(const TableColumnFlowObj &fo) : FlowObj(fo), nic_(new NIC(*fo.nic_)) { }
2278   void processInner(ProcessContext &context) {
2279     if (nic_->hasColumnNumber) {
2280       context.currentFOTBuilder().tableColumn(*nic_);
2281       context.addTableColumn(nic_->columnIndex, nic_->nColumnsSpanned, style_);
2282     }
2283     else {
2284       FOTBuilder::TableColumnNIC nic(*nic_);
2285       nic.columnIndex = context.currentTableColumn();
2286       context.currentFOTBuilder().tableColumn(nic);
2287       context.addTableColumn(nic.columnIndex, nic_->nColumnsSpanned, style_);
2288     }
2289   }
2290   FlowObj *copy(Collector &c) const {
2291     return new (c) TableColumnFlowObj(*this);
2292   }
2293   bool hasNonInheritedC(const Identifier *ident) const {
2294     Identifier::SyntacticKey key;
2295     if (ident->syntacticKey(key)) {
2296       switch (key) {
2297       case Identifier::keyColumnNumber:
2298       case Identifier::keyNColumnsSpanned:
2299       case Identifier::keyWidth:
2300         return 1;
2301       default:
2302         break;
2303       }
2304     }
2305     return 0;
2306   }
2307   void setNonInheritedC(const Identifier *ident, ELObj *obj,
2308                         const Location &loc, Interpreter &interp) {
2309     Identifier::SyntacticKey key;
2310     if (ident->syntacticKey(key)) {
2311       switch (key) {
2312       case Identifier::keyColumnNumber:
2313       case Identifier::keyNColumnsSpanned:
2314         {
2315           long n;
2316           if (!interp.convertIntegerC(obj, ident, loc, n))
2317             return;
2318           if (n <= 0) {
2319             interp.setNextLocation(loc);
2320             interp.message(InterpreterMessages::invalidCharacteristicValue,
2321                            StringMessageArg(ident->name()));
2322             return;
2323           }
2324           if (key == Identifier::keyColumnNumber) {
2325             nic_->columnIndex = n - 1;
2326             nic_->hasColumnNumber = 1;
2327           }
2328           else
2329             nic_->nColumnsSpanned = n;
2330         }
2331         return;
2332       case Identifier::keyWidth:
2333         {
2334           const LengthSpec *ls = obj->lengthSpec();
2335           if (ls) {
2336             // width is a TableLengthSpec not just a LengthSpec
2337             if (ls->convert(nic_->width))
2338               nic_->hasWidth = 1;
2339             else
2340               interp.invalidCharacteristicValue(ident, loc);
2341           }
2342           else if (interp.convertLengthSpecC(obj, ident, loc, nic_->width))
2343             nic_->hasWidth = 1;
2344         }
2345         return;
2346       default:
2347         break;
2348       }
2349     }
2350     CANNOT_HAPPEN();
2351   }
2352 private:
2353   Owner<NIC> nic_;
2354 };
2355
2356 class TableRowFlowObj : public CompoundFlowObj {
2357 public:
2358   TableRowFlowObj() { }
2359   void pushStyle(ProcessContext &, unsigned &) {  }
2360   void popStyle(ProcessContext &, unsigned) {  }
2361   void processInner(ProcessContext &context) {
2362     if (!context.inTable()) {
2363       // FIXME location
2364       context.vm().interp->message(InterpreterMessages::tableRowOutsideTable);
2365       CompoundFlowObj::processInner(context);
2366       return;
2367     }
2368     if (context.inTableRow())
2369       context.endTableRow();
2370     context.startTableRow(style_);
2371     CompoundFlowObj::processInner(context);
2372     if (context.inTableRow())
2373       context.endTableRow();
2374     // else FIXME give an error
2375     // must have used ends-row? in a table-row
2376   }
2377   FlowObj *copy(Collector &c) const {
2378     return new (c) TableRowFlowObj(*this);
2379   }
2380 };
2381
2382 class TableCellFlowObj : public CompoundFlowObj {
2383 public:
2384   void *operator new(size_t, Collector &c) {
2385     return c.allocateObject(1);
2386   }
2387   struct NIC : FOTBuilder::TableCellNIC {
2388     NIC() : startsRow(0), endsRow(0), hasColumnNumber(0) { }
2389     bool hasColumnNumber;
2390     bool startsRow;
2391     bool endsRow;
2392   };
2393   TableCellFlowObj(bool missing = 0) : nic_(new NIC) {
2394     if (missing)
2395       nic_->missing = 1;
2396   }
2397   TableCellFlowObj(const TableCellFlowObj &fo) : CompoundFlowObj(fo), nic_(new NIC(*fo.nic_)) { }
2398   void pushStyle(ProcessContext &context, unsigned &nPush) {
2399     if (context.inTableRow()) {
2400       if (nic_->startsRow) {
2401         context.endTableRow();
2402         context.startTableRow(0);
2403       }
2404     }
2405     else
2406       context.startTableRow(0);
2407     unsigned columnNumber
2408       = nic_->hasColumnNumber ? nic_->columnIndex : context.currentTableColumn();
2409     StyleObj *columnStyle = context.tableColumnStyle(columnNumber, nic_->nColumnsSpanned);
2410     if (columnStyle) {
2411       context.currentStyleStack().push(columnStyle, context.vm(), context.currentFOTBuilder());
2412       context.currentFOTBuilder().startSequence();
2413       nPush++;
2414     }
2415     StyleObj *rowStyle = context.tableRowStyle();
2416     if (rowStyle) {
2417       context.currentStyleStack().push(rowStyle, context.vm(), context.currentFOTBuilder());
2418       context.currentFOTBuilder().startSequence();
2419       nPush++;
2420     }
2421     CompoundFlowObj::pushStyle(context, nPush);
2422   }
2423   void popStyle(ProcessContext &context, unsigned nPush) {
2424     CompoundFlowObj::popStyle(context, nPush);
2425     for (unsigned i = 0; i < nPush; i++) {
2426       context.currentFOTBuilder().endSequence();
2427       context.currentStyleStack().pop();
2428     }
2429     if (nic_->endsRow)
2430       context.endTableRow();
2431   }
2432   void processInner(ProcessContext &context) {
2433     if (!context.inTable()) {
2434       // FIXME location
2435       context.vm().interp->message(InterpreterMessages::tableCellOutsideTable);
2436       CompoundFlowObj::processInner(context);
2437       return;
2438     }
2439     FOTBuilder &fotb = context.currentFOTBuilder();
2440     if (!nic_->hasColumnNumber) {
2441       FOTBuilder::TableCellNIC nic(*nic_);
2442       nic.columnIndex = context.currentTableColumn();
2443       fotb.startTableCell(nic);
2444       if (!nic_->missing)
2445         context.noteTableCell(nic.columnIndex, nic.nColumnsSpanned, nic.nRowsSpanned);
2446     }
2447     else {
2448       fotb.startTableCell(*nic_);
2449       if (!nic_->missing)
2450         context.noteTableCell(nic_->columnIndex, nic_->nColumnsSpanned, nic_->nRowsSpanned);
2451     }
2452     Interpreter &interp = *context.vm().interp;
2453     border(interp.cellBeforeRowBorderC(), &FOTBuilder::tableCellBeforeRowBorder, context);
2454     border(interp.cellAfterRowBorderC(), &FOTBuilder::tableCellAfterRowBorder, context);
2455     border(interp.cellBeforeColumnBorderC(), &FOTBuilder::tableCellBeforeColumnBorder, context);
2456     border(interp.cellAfterColumnBorderC(), &FOTBuilder::tableCellAfterColumnBorder, context);
2457     CompoundFlowObj::processInner(context);
2458     fotb.endTableCell();
2459   }
2460   FlowObj *copy(Collector &c) const {
2461     return new (c) TableCellFlowObj(*this);
2462   }
2463   bool hasNonInheritedC(const Identifier *ident) const {
2464     Identifier::SyntacticKey key;
2465     if (ident->syntacticKey(key)) {
2466       switch (key) {
2467       case Identifier::keyNRowsSpanned:
2468         return 1;
2469       default:
2470         break;
2471       }
2472     }
2473     return 0;
2474   }
2475   bool hasPseudoNonInheritedC(const Identifier *ident) const {
2476     Identifier::SyntacticKey key;
2477     if (ident->syntacticKey(key)) {
2478       switch (key) {
2479       case Identifier::keyColumnNumber:
2480       case Identifier::keyNColumnsSpanned:
2481       case Identifier::keyIsStartsRow:
2482       case Identifier::keyIsEndsRow:
2483         return 1;
2484       default:
2485         break;
2486       }
2487     }
2488     return 0;
2489   }
2490   void setNonInheritedC(const Identifier *ident, ELObj *obj,
2491                         const Location &loc, Interpreter &interp) {
2492     Identifier::SyntacticKey key;
2493     if (ident->syntacticKey(key)) {
2494       switch (key) {
2495       case Identifier::keyIsStartsRow:
2496         interp.convertBooleanC(obj, ident, loc, nic_->startsRow);
2497         return;
2498       case Identifier::keyIsEndsRow:
2499         interp.convertBooleanC(obj, ident, loc, nic_->endsRow);
2500         return;
2501       case Identifier::keyColumnNumber:
2502       case Identifier::keyNColumnsSpanned:
2503       case Identifier::keyNRowsSpanned:
2504         {
2505           long n;
2506           if (!interp.convertIntegerC(obj, ident, loc, n))
2507             return;
2508           if (n <= 0) {
2509             interp.setNextLocation(loc);
2510             interp.message(InterpreterMessages::invalidCharacteristicValue,
2511                            StringMessageArg(ident->name()));
2512             return;
2513           }
2514           if (key == Identifier::keyColumnNumber) {
2515             nic_->columnIndex = n - 1;
2516             nic_->hasColumnNumber = 1;
2517           }
2518           else if (key == Identifier::keyNColumnsSpanned)
2519             nic_->nColumnsSpanned = n;
2520           else
2521             nic_->nRowsSpanned = n;
2522         }
2523         return;
2524       default:
2525         break;
2526       }
2527     }
2528     CANNOT_HAPPEN();
2529   }
2530 private:
2531   void border(const ConstPtr<InheritedC> &ic, void (FOTBuilder::*setter)(),
2532               ProcessContext &context) {
2533     Interpreter &interp = *context.vm().interp;
2534     Vector<size_t> dep;
2535     ELObj *obj = context.currentStyleStack().actual(ic, interp, dep);
2536     StyleObj *style;
2537     if (obj == interp.makeFalse())
2538       style = interp.borderFalseStyle();
2539     else if (obj == interp.makeTrue())
2540       style = interp.borderTrueStyle();
2541     else {
2542       SosofoObj *sosofo = obj->asSosofo();
2543       if (!sosofo || !sosofo->tableBorderStyle(style))
2544         style = 0;
2545     }
2546     FOTBuilder &fotb = context.currentFOTBuilder();
2547     if (style)
2548       context.currentStyleStack().push(style, context.vm(), fotb);
2549     (fotb.*setter)();
2550     if (style)
2551       context.currentStyleStack().pop();
2552   }
2553   Owner<NIC> nic_;
2554 };
2555
2556 class TableBorderFlowObj : public FlowObj {
2557 public:
2558   TableBorderFlowObj() { }
2559   void process(ProcessContext &) { }
2560   void processInner(ProcessContext &) { }
2561   bool tableBorderStyle(StyleObj *&style) {
2562     style = style_;
2563     return 1;
2564   }
2565   FlowObj *copy(Collector &c) const {
2566     return new (c) TableBorderFlowObj(*this);
2567   }
2568 };
2569
2570
2571 void ProcessContext::startTable()
2572 {
2573   tableStack_.insert(new Table);
2574 }
2575
2576 void ProcessContext::endTable()
2577 {
2578   coverSpannedRows();
2579   delete tableStack_.get();
2580 }
2581
2582 void ProcessContext::coverSpannedRows()
2583 {
2584   // Generate empty cells to cover any remaining vertical spans
2585   Table *table = tableStack_.head();
2586   if (!table)
2587     return;
2588   unsigned n = 0;
2589   for (size_t i = 0; i < table->covered.size(); i++)
2590     if (table->covered[i] > n)
2591       n = table->covered[i];
2592   for (; n > 0; n--) {
2593     SosofoObj *content = new (*vm().interp) EmptySosofoObj;
2594     ELObjDynamicRoot protect(*vm().interp, content);
2595     TableRowFlowObj *row = new (*vm().interp) TableRowFlowObj;
2596     row->setContent(content);
2597     protect = row;
2598     row->process(*this);
2599   }
2600 }
2601
2602 void ProcessContext::startTablePart()
2603 {
2604   Table *table = tableStack_.head();
2605   if (table) {
2606     table->currentColumn = 0;
2607     table->rowStyle = 0;
2608     table->columnStyles.clear();
2609     table->covered.clear();
2610     table->nColumns = 0;
2611   }
2612 }
2613
2614 void ProcessContext::endTablePart()
2615 {
2616   coverSpannedRows();
2617 }
2618
2619 void ProcessContext::addTableColumn(unsigned columnIndex, unsigned span, StyleObj *style)
2620 {
2621   Table *table = tableStack_.head();
2622   if (table) {
2623     table->currentColumn = columnIndex + span;
2624     if (columnIndex >= table->columnStyles.size())
2625       table->columnStyles.resize(columnIndex + 1);
2626     Vector<StyleObj *> &tem = table->columnStyles[columnIndex];
2627     if (span > 0) {
2628       while (tem.size() < span)
2629         tem.push_back((StyleObj *)0);
2630       tem[span - 1] = style;
2631     }
2632   }
2633 }
2634
2635 unsigned ProcessContext::currentTableColumn()
2636 {
2637   Table *table = tableStack_.head();
2638   if (table)
2639     return table->currentColumn;
2640   return 0;
2641 }
2642
2643 void ProcessContext::noteTableCell(unsigned colIndex, unsigned colSpan, unsigned rowSpan)
2644 {
2645   Table *table = tableStack_.head();
2646   if (!table)
2647     return;
2648   table->currentColumn = colIndex + colSpan;
2649   Vector<unsigned> &covered = table->covered;
2650   for (size_t i = covered.size(); i < colIndex + colSpan; i++)
2651     covered.push_back(0);
2652   for (size_t i = 0; i < colSpan; i++)
2653     covered[colIndex + i] = rowSpan;
2654   if (colIndex + colSpan > table->nColumns)
2655     table->nColumns = colIndex + colSpan;
2656 }
2657
2658 StyleObj *ProcessContext::tableColumnStyle(unsigned columnIndex, unsigned span)
2659 {
2660   Table *table = tableStack_.head();
2661   if (table) {
2662     if (columnIndex < table->columnStyles.size()) {
2663       Vector<StyleObj *> &tem = table->columnStyles[columnIndex];
2664       if (span > 0 && span <= tem.size())
2665         return tem[span - 1];
2666     }
2667   }
2668   return 0;
2669 }
2670  
2671 StyleObj *ProcessContext::tableRowStyle()
2672 {
2673   Table *table = tableStack_.head();
2674   if (table)
2675     return table->rowStyle;
2676   return 0;
2677 }
2678
2679 void ProcessContext::startTableRow(StyleObj *style)
2680 {
2681   Table *table = tableStack_.head();
2682   if (table) {
2683     table->rowStyle = style;
2684     table->currentColumn = 0;
2685     table->inTableRow = 1;
2686     table->rowConnectableLevel = connectionStack_.head()->connectableLevel;
2687   }
2688   currentFOTBuilder().startTableRow();
2689 }
2690
2691 void ProcessContext::endTableRow()
2692 {
2693   Table *table = tableStack_.head();
2694   if (table) {
2695     // Fill in blank cells
2696     Vector<unsigned> &covered = table->covered;
2697     for (size_t i = 0; i < table->nColumns + 1; i++) {
2698       if (i >= covered.size() || !covered[i]) {
2699         table->currentColumn = i;
2700         SosofoObj *content = new (*vm().interp) EmptySosofoObj;
2701         ELObjDynamicRoot protect(*vm().interp, content);
2702         // The last cell is a dummy one
2703         TableCellFlowObj *cell = new (*vm().interp) TableCellFlowObj(i >= table->nColumns);
2704         cell->setContent(content);
2705         protect = cell;
2706         cell->process(*this);
2707       }
2708       // cell->process() will cover it
2709       if (i < table->nColumns)
2710         covered[i] -= 1;
2711     }
2712     table->inTableRow = 0;
2713   }
2714   currentFOTBuilder().endTableRow();
2715 }
2716
2717 bool ProcessContext::inTableRow()
2718 {
2719   Table *table = tableStack_.head();
2720   if (table)
2721     return table->inTableRow;
2722   return 0;
2723 }
2724
2725 ProcessContext::Table::Table()
2726 : rowStyle(0), currentColumn(0), inTableRow(0), nColumns(0)
2727 {
2728 }
2729
2730
2731 // Flow object classes declared with declare-flow-object-class
2732 // that we don't know about are assumed to have one principal port
2733 // and accept any non-inherited characteristic.
2734
2735 class UnknownFlowObj : public CompoundFlowObj {
2736 public:
2737   UnknownFlowObj() { }
2738   FlowObj *copy(Collector &c) const {
2739     return new (c) UnknownFlowObj(*this);
2740   }
2741   void setNonInheritedC(const Identifier *, ELObj *,
2742                         const Location &, Interpreter &) { }
2743   bool hasNonInheritedC(const Identifier *ident) const {
2744     Identifier::SyntacticKey syn;
2745     if (ident->syntacticKey(syn)
2746         && (syn == Identifier::keyLabel || syn == Identifier::keyContentMap))
2747       return 0;
2748     if (!ident->inheritedC().isNull())
2749       return 0;
2750     return 1;
2751   }
2752 };
2753
2754 class FormattingInstructionFlowObj : public FlowObj {
2755 public:
2756   void *operator new(size_t, Collector &c) {
2757     return c.allocateObject(1);
2758   }
2759   FormattingInstructionFlowObj() { }
2760   void processInner(ProcessContext &context) {
2761     context.currentFOTBuilder().formattingInstruction(data_);
2762   }
2763   FlowObj *copy(Collector &c) const {
2764     return new (c) FormattingInstructionFlowObj(*this);
2765   }
2766   void setNonInheritedC(const Identifier *ident, ELObj *obj,
2767                         const Location &loc, Interpreter &interp) {
2768     interp.convertStringC(obj, ident, loc, data_);
2769   }
2770   bool hasNonInheritedC(const Identifier *ident) const {
2771     Identifier::SyntacticKey key;
2772     return ident->syntacticKey(key) && key == Identifier::keyData;
2773   }
2774 private:
2775   StringC data_;
2776 };
2777
2778 class ELObjExtensionFlowObjValue : public FOTBuilder::ExtensionFlowObj::Value {
2779 public:
2780   ELObjExtensionFlowObjValue(const Identifier *ident, ELObj *obj,
2781                              const Location &loc, Interpreter &interp)
2782   : ident_(ident), obj_(obj), loc_(&loc), interp_(&interp) { }
2783   bool convertString(StringC &result) const {
2784     return interp_->convertStringC(obj_, ident_, *loc_, result);
2785   }
2786   bool convertStringPairList(Vector<StringC> &v) const {
2787     ELObj *obj = obj_;
2788     for (;;) {
2789       if (obj->isNil())
2790         return 1;       
2791       PairObj *pair = obj->asPair();
2792       if (!pair)
2793         break;
2794       obj = pair->cdr();
2795       PairObj *att = pair->car()->asPair();
2796       if (!att)
2797         break;
2798       const Char *s;
2799       size_t n;
2800       if (!att->car()->stringData(s, n))
2801         break;
2802       v.resize(v.size() + 1);
2803       v.back().assign(s, n);
2804       att = att->cdr()->asPair();
2805       if (!att || !att->car()->stringData(s, n) || !att->cdr()->isNil()) {
2806         v.resize(v.size() - 1);
2807         break;
2808       }
2809       v.resize(v.size() + 1);
2810       v.back().assign(s, n);
2811     }
2812     interp_->setNextLocation(*loc_);
2813     interp_->message(InterpreterMessages::invalidCharacteristicValue,
2814                      StringMessageArg(ident_->name()));
2815     return 0;
2816   }
2817   bool convertStringList(Vector<StringC> &v) const {
2818     ELObj *obj = obj_;
2819     for (;;) {
2820       if (obj->isNil())
2821         return 1;       
2822       PairObj *pair = obj->asPair();
2823       if (!pair)
2824         break;
2825       const Char *s;
2826       size_t n;
2827       if (!pair->car()->stringData(s, n))
2828         break;
2829       v.resize(v.size() + 1);
2830       v.back().assign(s, n);
2831       obj = pair->cdr();
2832     }
2833     interp_->setNextLocation(*loc_);
2834     interp_->message(InterpreterMessages::invalidCharacteristicValue,
2835                      StringMessageArg(ident_->name()));
2836     return 0;
2837   } 
2838   bool convertBoolean(bool &result) const {
2839     return interp_->convertBooleanC(obj_, ident_, *loc_, result);
2840   }
2841 private:
2842   ELObj *obj_;
2843   const Identifier *ident_;
2844   const Location *loc_;
2845   Interpreter *interp_;
2846 };
2847
2848 class ExtensionFlowObj : public FlowObj {
2849 public:
2850   void *operator new(size_t, Collector &c) {
2851     return c.allocateObject(1);
2852   }
2853   ExtensionFlowObj(const FOTBuilder::ExtensionFlowObj &);
2854   ExtensionFlowObj(const ExtensionFlowObj &);
2855   void processInner(ProcessContext &);
2856   FlowObj *copy(Collector &) const;
2857   bool hasNonInheritedC(const Identifier *) const;
2858   void setNonInheritedC(const Identifier *, ELObj *,
2859                         const Location &, Interpreter &);
2860 private:
2861   Owner<FOTBuilder::ExtensionFlowObj> fo_;
2862 };
2863
2864 ExtensionFlowObj::ExtensionFlowObj(const FOTBuilder::ExtensionFlowObj &fo)
2865 : fo_(fo.copy())
2866 {
2867 }
2868
2869 ExtensionFlowObj::ExtensionFlowObj(const ExtensionFlowObj &fo)
2870 : FlowObj(fo), fo_(fo.fo_->copy())
2871 {
2872 }
2873
2874 void ExtensionFlowObj::processInner(ProcessContext &context)
2875 {
2876   context.currentFOTBuilder().extension(*fo_, context.vm().currentNode);
2877 }
2878
2879 void ExtensionFlowObj::setNonInheritedC(const Identifier *ident,
2880                                         ELObj *obj,
2881                                         const Location &loc,
2882                                         Interpreter &interp)
2883 {
2884   fo_->setNIC(ident->name(), ELObjExtensionFlowObjValue(ident, obj, loc, interp));
2885 }
2886
2887 bool ExtensionFlowObj::hasNonInheritedC(const Identifier *ident) const
2888 {
2889   return fo_->hasNIC(ident->name());
2890 }
2891
2892 FlowObj *ExtensionFlowObj::copy(Collector &c) const
2893 {
2894   return new (c) ExtensionFlowObj(*this);
2895 }
2896
2897 class CompoundExtensionFlowObj : public CompoundFlowObj {
2898 public:
2899   void *operator new(size_t, Collector &c) {
2900     return c.allocateObject(1);
2901   }
2902   CompoundExtensionFlowObj(const FOTBuilder::CompoundExtensionFlowObj &);
2903   CompoundExtensionFlowObj(const CompoundExtensionFlowObj &);
2904   void processInner(ProcessContext &);
2905   FlowObj *copy(Collector &) const;
2906   bool hasNonInheritedC(const Identifier *) const;
2907   void setNonInheritedC(const Identifier *, ELObj *,
2908                         const Location &, Interpreter &);
2909 private:
2910   Owner<FOTBuilder::CompoundExtensionFlowObj> fo_;
2911 };
2912
2913 CompoundExtensionFlowObj::CompoundExtensionFlowObj(const FOTBuilder::CompoundExtensionFlowObj &fo)
2914 : fo_(fo.copy()->asCompoundExtensionFlowObj())
2915 {
2916 }
2917
2918 CompoundExtensionFlowObj::CompoundExtensionFlowObj(const CompoundExtensionFlowObj &fo)
2919 : CompoundFlowObj(fo), fo_(fo.fo_->copy()->asCompoundExtensionFlowObj())
2920 {
2921 }
2922
2923 void CompoundExtensionFlowObj::processInner(ProcessContext &context)
2924 {
2925   FOTBuilder &fotb = context.currentFOTBuilder();
2926   Vector<StringC> portNames;
2927   fo_->portNames(portNames);
2928   Vector<FOTBuilder *> fotbs(portNames.size());
2929   fotb.startExtension(*fo_, context.vm().currentNode, fotbs);
2930   if (portNames.size()) {
2931     Vector<SymbolObj *> portSyms(portNames.size());
2932     for (size_t i = 0; i < portSyms.size(); i++)
2933       portSyms[i] = context.vm().interp->makeSymbol(portNames[i]);
2934     context.pushPorts(fo_->hasPrincipalPort(), portSyms, fotbs);
2935     CompoundFlowObj::processInner(context);
2936     context.popPorts();
2937   }
2938   else
2939     CompoundFlowObj::processInner(context);
2940   fotb.endExtension(*fo_);
2941 }
2942
2943 void CompoundExtensionFlowObj::setNonInheritedC(const Identifier *ident,
2944                                                 ELObj *obj,
2945                                                 const Location &loc,
2946                                                 Interpreter &interp)
2947 {
2948   fo_->setNIC(ident->name(), ELObjExtensionFlowObjValue(ident, obj, loc, interp));
2949 }
2950
2951 bool CompoundExtensionFlowObj::hasNonInheritedC(const Identifier *ident) const
2952 {
2953   return fo_->hasNIC(ident->name());
2954 }
2955
2956 FlowObj *CompoundExtensionFlowObj::copy(Collector &c) const
2957 {
2958   return new (c) CompoundExtensionFlowObj(*this);
2959 }
2960
2961 #define FLOW_OBJ(name, string) \
2962 { FlowObj *tem = new (*this) name; \
2963   lookup(makeStringC(string))->setFlowObj(tem); \
2964   makePermanent(tem); }
2965
2966 void Interpreter::installFlowObjs()
2967 {
2968   FLOW_OBJ(SequenceFlowObj, "sequence");
2969   FLOW_OBJ(DisplayGroupFlowObj, "display-group");
2970   FLOW_OBJ(ParagraphFlowObj, "paragraph");
2971   FLOW_OBJ(ParagraphBreakFlowObj, "paragraph-break");
2972   FLOW_OBJ(LineFieldFlowObj, "line-field");
2973   FLOW_OBJ(ScoreFlowObj, "score");
2974   FLOW_OBJ(ExternalGraphicFlowObj, "external-graphic");
2975   FLOW_OBJ(RuleFlowObj, "rule");
2976   FLOW_OBJ(LeaderFlowObj, "leader");
2977   FLOW_OBJ(CharacterFlowObj, "character");
2978   FLOW_OBJ(BoxFlowObj, "box");
2979   FLOW_OBJ(AlignmentPointFlowObj, "alignment-point");
2980   FLOW_OBJ(SidelineFlowObj, "sideline");
2981   // simple-page
2982   FLOW_OBJ(SimplePageSequenceFlowObj, "simple-page-sequence");
2983   // tables
2984   FLOW_OBJ(TableFlowObj, "table");
2985   FLOW_OBJ(TablePartFlowObj, "table-part");
2986   FLOW_OBJ(TableColumnFlowObj, "table-column");
2987   FLOW_OBJ(TableRowFlowObj, "table-row");
2988   FLOW_OBJ(TableCellFlowObj, "table-cell");
2989   FLOW_OBJ(TableBorderFlowObj, "table-border");
2990   // online
2991   FLOW_OBJ(LinkFlowObj, "link");
2992   FLOW_OBJ(ScrollFlowObj, "scroll");
2993   FLOW_OBJ(MarginaliaFlowObj, "marginalia");
2994   FLOW_OBJ(MultiModeFlowObj, "multi-mode");
2995   // math
2996   FLOW_OBJ(MathSequenceFlowObj, "math-sequence");
2997   FLOW_OBJ(FractionFlowObj, "fraction");
2998   FLOW_OBJ(UnmathFlowObj, "unmath");
2999   FLOW_OBJ(SuperscriptFlowObj, "superscript");
3000   FLOW_OBJ(SubscriptFlowObj, "subscript");
3001   FLOW_OBJ(ScriptFlowObj, "script");
3002   FLOW_OBJ(MarkFlowObj, "mark");
3003   FLOW_OBJ(FenceFlowObj, "fence");
3004   FLOW_OBJ(RadicalFlowObj, "radical");
3005   FLOW_OBJ(MathOperatorFlowObj, "math-operator");
3006   FLOW_OBJ(GridFlowObj, "grid");
3007   FLOW_OBJ(GridCellFlowObj, "grid-cell");
3008 }
3009
3010 void Interpreter::installExtensionFlowObjectClass(Identifier *ident,
3011                                                   const StringC &pubid,
3012                                                   const Location &loc)
3013 {
3014   FlowObj *tem = 0;
3015   if (extensionTable_) {
3016     for (const FOTBuilder::Extension *ep = extensionTable_; ep->pubid; ep++) {
3017       if (pubid == ep->pubid) {
3018         if (ep->flowObj) {
3019           const FOTBuilder::CompoundExtensionFlowObj *cFlowObj
3020             = ep->flowObj->asCompoundExtensionFlowObj();
3021           if (cFlowObj)
3022             tem = new (*this) CompoundExtensionFlowObj(*cFlowObj);
3023           else
3024             tem = new (*this) ExtensionFlowObj(*ep->flowObj);
3025         }
3026         break;
3027       }
3028     }
3029   }
3030   if (!tem) {
3031     if (pubid
3032         == "UNREGISTERED::James Clark//Flow Object Class::"
3033            "formatting-instruction")
3034       tem = new (*this) FormattingInstructionFlowObj;
3035     else
3036       tem = new (*this) UnknownFlowObj;
3037   }
3038   makePermanent(tem);
3039   ident->setFlowObj(tem, currentPartIndex(), loc);
3040 }
3041
3042 #ifdef DSSSL_NAMESPACE
3043 }
3044 #endif
3045
3046 #include "FlowObj_inst.cxx"