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 
FlowObj()15 FlowObj::FlowObj()
16 : style_(0)
17 {
18   hasSubObjects_ = 1;
19 }
20 
process(ProcessContext & context)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 
pushStyle(ProcessContext & context,unsigned &)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 
popStyle(ProcessContext & context,unsigned)39 void FlowObj::popStyle(ProcessContext &context, unsigned)
40 {
41   if (style_)
42     context.currentStyleStack().pop();
43   else
44     context.currentStyleStack().popEmpty();
45 }
46 
traceSubObjects(Collector & c) const47 void FlowObj::traceSubObjects(Collector &c) const
48 {
49   c.trace(style_);
50 }
51 
asCompoundFlowObj()52 CompoundFlowObj *FlowObj::asCompoundFlowObj()
53 {
54   return 0;
55 }
56 
hasNonInheritedC(const Identifier *) const57 bool FlowObj::hasNonInheritedC(const Identifier *) const
58 {
59   return 0;
60 }
61 
hasPseudoNonInheritedC(const Identifier *) const62 bool FlowObj::hasPseudoNonInheritedC(const Identifier *) const
63 {
64   return 0;
65 }
66 
setNonInheritedC(const Identifier *,ELObj *,const Location &,Interpreter &)67 void FlowObj::setNonInheritedC(const Identifier *, ELObj *, const Location &, Interpreter &)
68 {
69   CANNOT_HAPPEN();
70 }
71 
isDisplayNIC(const Identifier * ident)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 
setDisplayNIC(FOTBuilder::DisplayNIC & nic,const Identifier * ident,ELObj * obj,const Location & loc,Interpreter & interp)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 
processInner(ProcessContext & context)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 
traceSubObjects(Collector & c) const179 void CompoundFlowObj::traceSubObjects(Collector &c) const
180 {
181   c.trace(content_);
182   FlowObj::traceSubObjects(c);
183 }
184 
asCompoundFlowObj()185 CompoundFlowObj *CompoundFlowObj::asCompoundFlowObj()
186 {
187   return this;
188 }
189 
190 class DisplayGroupFlowObj : public CompoundFlowObj {
191 public:
operator new(size_t,Collector & c)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 
DisplayGroupFlowObj()206 DisplayGroupFlowObj::DisplayGroupFlowObj()
207 : nic_(new FOTBuilder::DisplayGroupNIC)
208 {
209 }
210 
DisplayGroupFlowObj(const DisplayGroupFlowObj & fo)211 DisplayGroupFlowObj::DisplayGroupFlowObj(const DisplayGroupFlowObj &fo)
212 : CompoundFlowObj(fo), nic_(new FOTBuilder::DisplayGroupNIC(*fo.nic_))
213 {
214 }
215 
processInner(ProcessContext & context)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 
hasNonInheritedC(const Identifier * ident) const224 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 
setNonInheritedC(const Identifier * ident,ELObj * obj,const Location & loc,Interpreter & interp)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 
copy(Collector & c) const248 FlowObj *DisplayGroupFlowObj::copy(Collector &c) const
249 {
250   return new (c) DisplayGroupFlowObj(*this);
251 }
252 
253 class ParagraphFlowObj : public CompoundFlowObj {
254 public:
operator new(size_t,Collector & c)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 
ParagraphFlowObj()270 ParagraphFlowObj::ParagraphFlowObj()
271 : nic_(new FOTBuilder::ParagraphNIC)
272 {
273 }
274 
ParagraphFlowObj(const ParagraphFlowObj & fo)275 ParagraphFlowObj::ParagraphFlowObj(const ParagraphFlowObj &fo)
276 : CompoundFlowObj(fo), nic_(new FOTBuilder::ParagraphNIC(*fo.nic_))
277 {
278 }
279 
processInner(ProcessContext & context)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 
setNonInheritedC(const Identifier * ident,ELObj * obj,const Location & loc,Interpreter & interp)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 
hasNonInheritedC(const Identifier * ident) const294 bool ParagraphFlowObj::hasNonInheritedC(const Identifier *ident) const
295 {
296   return isDisplayNIC(ident);
297 }
298 
copy(Collector & c) const299 FlowObj *ParagraphFlowObj::copy(Collector &c) const
300 {
301   return new (c) ParagraphFlowObj(*this);
302 }
303 
304 class ParagraphBreakFlowObj : public FlowObj {
305 public:
operator new(size_t,Collector & c)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 
ParagraphBreakFlowObj()321 ParagraphBreakFlowObj::ParagraphBreakFlowObj()
322 : nic_(new FOTBuilder::ParagraphNIC)
323 {
324 }
325 
ParagraphBreakFlowObj(const ParagraphBreakFlowObj & fo)326 ParagraphBreakFlowObj::ParagraphBreakFlowObj(const ParagraphBreakFlowObj &fo)
327 : FlowObj(fo), nic_(new FOTBuilder::ParagraphNIC(*fo.nic_))
328 {
329 }
330 
copy(Collector & c) const331 FlowObj *ParagraphBreakFlowObj::copy(Collector &c) const
332 {
333   return new (c) ParagraphBreakFlowObj(*this);
334 }
335 
processInner(ProcessContext & context)336 void ParagraphBreakFlowObj::processInner(ProcessContext &context)
337 {
338   context.currentFOTBuilder().paragraphBreak(*nic_);
339 }
340 
setNonInheritedC(const Identifier * ident,ELObj * obj,const Location & loc,Interpreter & interp)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 
hasNonInheritedC(const Identifier * ident) const347 bool ParagraphBreakFlowObj::hasNonInheritedC(const Identifier *ident) const
348 {
349   return isDisplayNIC(ident);
350 }
351 
352 class ExternalGraphicFlowObj : public FlowObj {
353 public:
operator new(size_t,Collector & c)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 
ExternalGraphicFlowObj()369 ExternalGraphicFlowObj::ExternalGraphicFlowObj()
370 : nic_(new FOTBuilder::ExternalGraphicNIC)
371 {
372 }
373 
ExternalGraphicFlowObj(const ExternalGraphicFlowObj & fo)374 ExternalGraphicFlowObj::ExternalGraphicFlowObj(const ExternalGraphicFlowObj &fo)
375 : FlowObj(fo), nic_(new FOTBuilder::ExternalGraphicNIC(*fo.nic_))
376 {
377 }
378 
processInner(ProcessContext & context)379 void ExternalGraphicFlowObj::processInner(ProcessContext &context)
380 {
381   context.currentFOTBuilder().externalGraphic(*nic_);
382 }
383 
setNonInheritedC(const Identifier * ident,ELObj * obj,const Location & loc,Interpreter & interp)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 
hasNonInheritedC(const Identifier * ident) const467 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 
copy(Collector & c) const491 FlowObj *ExternalGraphicFlowObj::copy(Collector &c) const
492 {
493   return new (c) ExternalGraphicFlowObj(*this);
494 }
495 
496 class RuleFlowObj : public FlowObj {
497 public:
operator new(size_t,Collector & c)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;
ruleStyle(ProcessContext &,StyleObj * & style)508   bool ruleStyle(ProcessContext &, StyleObj *&style) {
509     style = style_;
510     return 1;
511   }
isRule()512   bool isRule() { return 1; }
513 private:
514   Owner<FOTBuilder::RuleNIC> nic_;
515 };
516 
RuleFlowObj()517 RuleFlowObj::RuleFlowObj()
518 : nic_(new FOTBuilder::RuleNIC)
519 {
520 }
521 
RuleFlowObj(const RuleFlowObj & fo)522 RuleFlowObj::RuleFlowObj(const RuleFlowObj &fo)
523 : FlowObj(fo), nic_(new FOTBuilder::RuleNIC(*fo.nic_))
524 {
525 }
526 
processInner(ProcessContext & context)527 void RuleFlowObj::processInner(ProcessContext &context)
528 {
529   context.currentFOTBuilder().rule(*nic_);
530 }
531 
setNonInheritedC(const Identifier * ident,ELObj * obj,const Location & loc,Interpreter & interp)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 
hasNonInheritedC(const Identifier * ident) const568 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 
copy(Collector & c) const585 FlowObj *RuleFlowObj::copy(Collector &c) const
586 {
587   return new (c) RuleFlowObj(*this);
588 }
589 
590 class AlignmentPointFlowObj : public FlowObj {
591 public:
AlignmentPointFlowObj()592   AlignmentPointFlowObj() { }
593   FlowObj *copy(Collector &) const;
594   void processInner(ProcessContext &);
595 };
596 
copy(Collector & c) const597 FlowObj *AlignmentPointFlowObj::copy(Collector &c) const
598 {
599   return new (c) AlignmentPointFlowObj(*this);
600 }
601 
processInner(ProcessContext & context)602 void AlignmentPointFlowObj::processInner(ProcessContext &context)
603 {
604   context.currentFOTBuilder().alignmentPoint();
605 }
606 
607 class SidelineFlowObj : public CompoundFlowObj {
608 public:
SidelineFlowObj()609   SidelineFlowObj() { }
610   FlowObj *copy(Collector &) const;
611   void processInner(ProcessContext &);
612 };
613 
copy(Collector & c) const614 FlowObj *SidelineFlowObj::copy(Collector &c) const
615 {
616   return new (c) SidelineFlowObj(*this);
617 }
618 
processInner(ProcessContext & context)619 void SidelineFlowObj::processInner(ProcessContext &context)
620 {
621   FOTBuilder &fotb = context.currentFOTBuilder();
622   fotb.startSideline();
623   CompoundFlowObj::processInner(context);
624   fotb.endSideline();
625 }
processInner(ProcessContext & context)626 void SequenceFlowObj::processInner(ProcessContext &context)
627 {
628   FOTBuilder &fotb = context.currentFOTBuilder();
629   fotb.startSequence();
630   CompoundFlowObj::processInner(context);
631   fotb.endSequence();
632 }
633 
copy(Collector & c) const634 FlowObj *SequenceFlowObj::copy(Collector &c) const
635 {
636   return new (c) SequenceFlowObj(*this);
637 }
638 
639 class LineFieldFlowObj : public CompoundFlowObj {
640 public:
operator new(size_t,Collector & c)641   void *operator new(size_t, Collector &c) {
642     return c.allocateObject(1);
643   }
LineFieldFlowObj()644   LineFieldFlowObj() : nic_(new FOTBuilder::LineFieldNIC) { }
LineFieldFlowObj(const LineFieldFlowObj & fo)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 
copy(Collector & c) const656 FlowObj *LineFieldFlowObj::copy(Collector &c) const
657 {
658   return new (c) LineFieldFlowObj(*this);
659 }
660 
processInner(ProcessContext & context)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 
setNonInheritedC(const Identifier * ident,ELObj * obj,const Location & loc,Interpreter & interp)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 
hasNonInheritedC(const Identifier * ident) const688 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:
operator new(size_t,Collector & c)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 
SimplePageSequenceFlowObj()727 SimplePageSequenceFlowObj::SimplePageSequenceFlowObj()
728 : hf_(new HeaderFooter)
729 {
730   hasSubObjects_ = 1;
731 }
732 
SimplePageSequenceFlowObj(const SimplePageSequenceFlowObj & fo)733 SimplePageSequenceFlowObj::SimplePageSequenceFlowObj(const SimplePageSequenceFlowObj &fo)
734 : CompoundFlowObj(fo), hf_(new HeaderFooter(*fo.hf_))
735 {
736 }
737 
traceSubObjects(Collector & c) const738 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 
processInner(ProcessContext & context)745 void SimplePageSequenceFlowObj::processInner(ProcessContext &context)
746 {
747   FOTBuilder &fotb = context.currentFOTBuilder();
748   fotb.startSimplePageSequence();
749   for (int i = 0; i < (1 << nPageTypeBits); i++) {
750     context.setPageType(i);
751     for (int j = 0; j < HeaderFooter::nParts; j++) {
752       fotb.startSimplePageSequenceHeaderFooter(i | (j << nPageTypeBits));
753       if (hf_->part[j])
754 	hf_->part[j]->process(context);
755       fotb.endSimplePageSequenceHeaderFooter(i | (j << nPageTypeBits));
756     }
757   }
758   fotb.endAllSimplePageSequenceHeaderFooter();
759   context.clearPageType();
760   CompoundFlowObj::processInner(context);
761   fotb.endSimplePageSequence();
762 }
763 
setNonInheritedC(const Identifier * ident,ELObj * obj,const Location & loc,Interpreter & interp)764 void SimplePageSequenceFlowObj::setNonInheritedC(const Identifier *ident,
765 						 ELObj *obj,
766 						 const Location &loc,
767 						 Interpreter &interp)
768 {
769   SosofoObj *sosofo = obj->asSosofo();
770   if (!sosofo) {
771     interp.setNextLocation(loc);
772     interp.message(InterpreterMessages::invalidCharacteristicValue,
773 		   StringMessageArg(ident->name()));
774     return;
775   }
776   Identifier::SyntacticKey key;
777   if (ident->syntacticKey(key)) {
778     switch (key) {
779     case Identifier::keyLeftHeader:
780       hf_->part[(FOTBuilder::leftHF | FOTBuilder::headerHF) >> nPageTypeBits] = sosofo;
781       return;
782     case Identifier::keyCenterHeader:
783       hf_->part[(FOTBuilder::centerHF | FOTBuilder::headerHF) >> nPageTypeBits] = sosofo;
784       return;
785     case Identifier::keyRightHeader:
786       hf_->part[(FOTBuilder::rightHF | FOTBuilder::headerHF) >> nPageTypeBits] = sosofo;
787       return;
788     case Identifier::keyLeftFooter:
789       hf_->part[(FOTBuilder::leftHF | FOTBuilder::footerHF) >> nPageTypeBits] = sosofo;
790       return;
791     case Identifier::keyCenterFooter:
792       hf_->part[(FOTBuilder::centerHF | FOTBuilder::footerHF) >> nPageTypeBits] = sosofo;
793       return;
794     case Identifier::keyRightFooter:
795       hf_->part[(FOTBuilder::rightHF | FOTBuilder::footerHF) >> nPageTypeBits] = sosofo;
796       return;
797     default:
798       break;
799     }
800   }
801   CANNOT_HAPPEN();
802 }
803 
hasNonInheritedC(const Identifier * ident) const804 bool SimplePageSequenceFlowObj::hasNonInheritedC(const Identifier *ident) const
805 {
806   Identifier::SyntacticKey key;
807   if (ident->syntacticKey(key)) {
808     switch (key) {
809     case Identifier::keyLeftHeader:
810     case Identifier::keyCenterHeader:
811     case Identifier::keyRightHeader:
812     case Identifier::keyLeftFooter:
813     case Identifier::keyCenterFooter:
814     case Identifier::keyRightFooter:
815       return 1;
816     default:
817       break;
818     }
819   }
820   return 0;
821 }
822 
copy(Collector & c) const823 FlowObj *SimplePageSequenceFlowObj::copy(Collector &c) const
824 {
825   return new (c) SimplePageSequenceFlowObj(*this);
826 }
827 
HeaderFooter()828 SimplePageSequenceFlowObj::HeaderFooter::HeaderFooter()
829 {
830   for (int i = 0; i < nParts; i++)
831     part[i] = 0;
832 }
833 
834 class LinkFlowObj : public CompoundFlowObj {
835 public:
836   LinkFlowObj();
837   FlowObj *copy(Collector &) const;
838   void processInner(ProcessContext &);
839   void traceSubObjects(Collector &) const;
840   bool hasNonInheritedC(const Identifier *) const;
841   void setNonInheritedC(const Identifier *, ELObj *,
842 			const Location &, Interpreter &);
843 private:
844   AddressObj *addressObj_;
845 };
846 
LinkFlowObj()847 LinkFlowObj::LinkFlowObj()
848 : addressObj_(0)
849 {
850 }
851 
processInner(ProcessContext & context)852 void LinkFlowObj::processInner(ProcessContext &context)
853 {
854   FOTBuilder &fotb = context.currentFOTBuilder();
855   if (!addressObj_) {
856     FOTBuilder::Address addr;
857     addr.type = FOTBuilder::Address::none;
858     fotb.startLink(addr);
859   }
860   else
861     fotb.startLink(addressObj_->address());
862   CompoundFlowObj::processInner(context);
863   fotb.endLink();
864 }
865 
copy(Collector & c) const866 FlowObj *LinkFlowObj::copy(Collector &c) const
867 {
868   return new (c) LinkFlowObj(*this);
869 }
870 
traceSubObjects(Collector & c) const871 void LinkFlowObj::traceSubObjects(Collector &c) const
872 {
873   CompoundFlowObj::traceSubObjects(c);
874   c.trace(addressObj_);
875 }
876 
hasNonInheritedC(const Identifier * ident) const877 bool LinkFlowObj::hasNonInheritedC(const Identifier *ident) const
878 {
879   Identifier::SyntacticKey key;
880   return ident->syntacticKey(key) && key == Identifier::keyDestination;
881 }
882 
setNonInheritedC(const Identifier * ident,ELObj * obj,const Location & loc,Interpreter & interp)883 void LinkFlowObj::setNonInheritedC(const Identifier *ident, ELObj *obj,
884 				   const Location &loc, Interpreter &interp)
885 {
886   AddressObj *address = obj->asAddress();
887   if (!address) {
888     if (obj != interp.makeFalse()) {
889       interp.setNextLocation(loc);
890       interp.message(InterpreterMessages::invalidCharacteristicValue,
891                      StringMessageArg(ident->name()));
892     }
893     else
894       address = interp.makeAddressNone();
895   }
896   addressObj_ = address;
897 }
898 
899 class ScrollFlowObj : public CompoundFlowObj {
900 public:
ScrollFlowObj()901   ScrollFlowObj() { }
902   void processInner(ProcessContext &);
903   FlowObj *copy(Collector &) const;
904 };
905 
processInner(ProcessContext & context)906 void ScrollFlowObj::processInner(ProcessContext &context)
907 {
908   FOTBuilder &fotb = context.currentFOTBuilder();
909   fotb.startScroll();
910   CompoundFlowObj::processInner(context);
911   fotb.endScroll();
912 }
913 
copy(Collector & c) const914 FlowObj *ScrollFlowObj::copy(Collector &c) const
915 {
916   return new (c) ScrollFlowObj(*this);
917 }
918 
919 class MarginaliaFlowObj : public CompoundFlowObj {
920 public:
MarginaliaFlowObj()921   MarginaliaFlowObj() { }
922   void processInner(ProcessContext &);
923   FlowObj *copy(Collector &) const;
924 };
925 
processInner(ProcessContext & context)926 void MarginaliaFlowObj::processInner(ProcessContext &context)
927 {
928   FOTBuilder &fotb = context.currentFOTBuilder();
929   fotb.startMarginalia();
930   CompoundFlowObj::processInner(context);
931   fotb.endMarginalia();
932 }
933 
copy(Collector & c) const934 FlowObj *MarginaliaFlowObj::copy(Collector &c) const
935 {
936   return new (c) MarginaliaFlowObj(*this);
937 }
938 
939 class MultiModeFlowObj : public CompoundFlowObj {
940 public:
operator new(size_t,Collector & c)941   void *operator new(size_t, Collector &c) {
942     return c.allocateObject(1);
943   }
944   MultiModeFlowObj();
945   MultiModeFlowObj(const MultiModeFlowObj &);
946   void processInner(ProcessContext &);
947   FlowObj *copy(Collector &) const;
948   bool hasNonInheritedC(const Identifier *) const;
949   void setNonInheritedC(const Identifier *, ELObj *,
950 			const Location &, Interpreter &);
951   struct NIC {
NICDSSSL_NAMESPACE::MultiModeFlowObj::NIC952     NIC() : hasPrincipalMode(0) { }
953     bool hasPrincipalMode;
954     FOTBuilder::MultiMode principalMode;
955     Vector<FOTBuilder::MultiMode> namedModes;
956   };
957 private:
958   bool handleMultiModesMember(const Identifier *, ELObj *obj,
959 			      const Location &, Interpreter &);
960   Owner<NIC> nic_;
961 };
962 
MultiModeFlowObj()963 MultiModeFlowObj::MultiModeFlowObj()
964 : nic_(new NIC)
965 {
966 }
967 
MultiModeFlowObj(const MultiModeFlowObj & fo)968 MultiModeFlowObj::MultiModeFlowObj(const MultiModeFlowObj &fo)
969 : CompoundFlowObj(fo), nic_(new NIC(*fo.nic_))
970 {
971 }
972 
processInner(ProcessContext & context)973 void MultiModeFlowObj::processInner(ProcessContext &context)
974 {
975   FOTBuilder &fotb = context.currentFOTBuilder();
976   Vector<FOTBuilder *> fotbs(nic_->namedModes.size());
977   fotb.startMultiMode(nic_->hasPrincipalMode ? &nic_->principalMode : 0,
978 		      nic_->namedModes,
979 		      fotbs);
980   Vector<SymbolObj *> portSyms(nic_->namedModes.size());
981   for (size_t i = 0; i < portSyms.size(); i++)
982     portSyms[i] = context.vm().interp->makeSymbol(nic_->namedModes[i].name);
983   context.pushPorts(nic_->hasPrincipalMode, portSyms, fotbs);
984   CompoundFlowObj::processInner(context);
985   context.popPorts();
986   fotb.endMultiMode();
987 }
988 
copy(Collector & c) const989 FlowObj *MultiModeFlowObj::copy(Collector &c) const
990 {
991   return new (c) MultiModeFlowObj(*this);
992 }
993 
hasNonInheritedC(const Identifier * ident) const994 bool MultiModeFlowObj::hasNonInheritedC(const Identifier *ident) const
995 {
996   Identifier::SyntacticKey key;
997   return ident->syntacticKey(key) && key == Identifier::keyMultiModes;
998 }
999 
setNonInheritedC(const Identifier * ident,ELObj * obj,const Location & loc,Interpreter & interp)1000 void MultiModeFlowObj::setNonInheritedC(const Identifier *ident, ELObj *obj,
1001 					const Location &loc, Interpreter &interp)
1002 {
1003   while (!obj->isNil()) {
1004     PairObj *pair = obj->asPair();
1005     if (!pair || !handleMultiModesMember(ident, pair->car(), loc, interp)) {
1006       interp.setNextLocation(loc);
1007       interp.message(InterpreterMessages::invalidCharacteristicValue,
1008   		     StringMessageArg(ident->name()));
1009       return;
1010     }
1011     obj = pair->cdr();
1012   }
1013 }
1014 
handleMultiModesMember(const Identifier *,ELObj * obj,const Location & loc,Interpreter & interp)1015 bool MultiModeFlowObj::handleMultiModesMember(const Identifier *, ELObj *obj,
1016 					      const Location &loc, Interpreter &interp)
1017 {
1018   if (obj == interp.makeFalse()) {
1019     nic_->hasPrincipalMode = 1;
1020     return 1;
1021   }
1022   SymbolObj *sym = obj->asSymbol();
1023   if (sym) {
1024     nic_->namedModes.resize(nic_->namedModes.size() + 1);
1025     nic_->namedModes.back().name = *sym->name();
1026     return 1;
1027   }
1028   PairObj *pair = obj->asPair();
1029   if (!pair)
1030     return 0;
1031   ELObj *spec = pair->car();
1032   pair = pair->cdr()->asPair();
1033   if (!pair || !pair->cdr()->isNil())
1034     return 0;
1035   const Char *s;
1036   size_t n;
1037   if (!pair->car()->stringData(s, n))
1038     return 0;
1039   if (spec == interp.makeFalse()) {
1040     nic_->hasPrincipalMode = 1;
1041     nic_->principalMode.hasDesc = 1;
1042     nic_->principalMode.desc.assign(s, n);
1043     return 1;
1044   }
1045   sym = spec->asSymbol();
1046   if (!sym)
1047     return 0;
1048   nic_->namedModes.resize(nic_->namedModes.size() + 1);
1049   nic_->namedModes.back().name = *sym->name();
1050   nic_->namedModes.back().desc.assign(s, n);
1051   nic_->namedModes.back().hasDesc = 1;
1052   return 1;
1053 }
1054 
1055 
1056 class ScoreFlowObj : public CompoundFlowObj {
1057 public:
operator new(size_t,Collector & c)1058   void *operator new(size_t, Collector &c) {
1059     return c.allocateObject(1);
1060   }
1061   ScoreFlowObj();
1062   FlowObj *copy(Collector &) const;
1063   void processInner(ProcessContext &);
1064   bool hasNonInheritedC(const Identifier *) const;
1065   void setNonInheritedC(const Identifier *, ELObj *,
1066 			const Location &, Interpreter &);
1067   class Type {
1068   public:
1069     virtual ~Type();
1070     virtual void start(FOTBuilder &) = 0;
1071     virtual Type *copy() const = 0;
1072   };
1073 private:
1074   class SymbolType : public Type {
1075   public:
SymbolType(FOTBuilder::Symbol type)1076     SymbolType(FOTBuilder::Symbol type) : type_(type) { }
1077     void start(FOTBuilder &);
1078     Type *copy() const;
1079   private:
1080     FOTBuilder::Symbol type_;
1081   };
1082   class LengthSpecType : public Type {
1083   public:
LengthSpecType(long n)1084     LengthSpecType(long n) : len_(n) { }
1085     void start(FOTBuilder &);
1086     Type *copy() const;
1087   private:
1088     FOTBuilder::LengthSpec len_;
1089   };
1090   class CharType : public Type {
1091   public:
CharType(Char c)1092     CharType(Char c) : c_(c) { }
1093     void start(FOTBuilder &);
1094     Type *copy() const;
1095   private:
1096     Char c_;
1097   };
1098   CopyOwner<Type> type_;
1099 };
1100 
ScoreFlowObj()1101 ScoreFlowObj::ScoreFlowObj()
1102 {
1103 }
1104 
copy(Collector & c) const1105 FlowObj *ScoreFlowObj::copy(Collector &c) const
1106 {
1107   return new (c) ScoreFlowObj(*this);
1108 }
1109 
processInner(ProcessContext & context)1110 void ScoreFlowObj::processInner(ProcessContext &context)
1111 {
1112   FOTBuilder &fotb = context.currentFOTBuilder();
1113   if (type_)
1114     type_->start(fotb);
1115   else
1116     fotb.startSequence();
1117   CompoundFlowObj::processInner(context);
1118   if (type_)
1119     fotb.endScore();
1120   else
1121     fotb.endSequence();
1122 }
1123 
hasNonInheritedC(const Identifier * ident) const1124 bool ScoreFlowObj::hasNonInheritedC(const Identifier *ident) const
1125 {
1126   Identifier::SyntacticKey key;
1127   return ident->syntacticKey(key) && key == Identifier::keyType;
1128 }
1129 
setNonInheritedC(const Identifier * ident,ELObj * obj,const Location & loc,Interpreter & interp)1130 void ScoreFlowObj::setNonInheritedC(const Identifier *ident, ELObj *obj,
1131 				    const Location &loc, Interpreter &interp)
1132 {
1133   Char c;
1134   if (obj->charValue(c)) {
1135     type_ = new CharType(c);
1136     return;
1137   }
1138   double d;
1139   long n;
1140   int dim;
1141   switch (obj->quantityValue(n, d, dim)) {
1142   case longQuantity:
1143     if (dim == 1) {
1144       type_ = new LengthSpecType(n);
1145       return;
1146     }
1147     break;
1148   case doubleQuantity:
1149     if (dim == 1) {
1150       type_ = new LengthSpecType(long(d));
1151       return;
1152     }
1153     break;
1154   default:
1155     break;
1156   }
1157   static FOTBuilder::Symbol vals[] = {
1158     FOTBuilder::symbolBefore,
1159     FOTBuilder::symbolThrough,
1160     FOTBuilder::symbolAfter
1161   };
1162   FOTBuilder::Symbol sym;
1163   if (interp.convertEnumC(vals, SIZEOF(vals), obj, ident, loc, sym))
1164     type_ = new SymbolType(sym);
1165 }
1166 
~Type()1167 ScoreFlowObj::Type::~Type()
1168 {
1169 }
1170 
start(FOTBuilder & fotb)1171 void ScoreFlowObj::SymbolType::start(FOTBuilder &fotb)
1172 {
1173   fotb.startScore(type_);
1174 }
1175 
start(FOTBuilder & fotb)1176 void ScoreFlowObj::CharType::start(FOTBuilder &fotb)
1177 {
1178   fotb.startScore(c_);
1179 }
1180 
start(FOTBuilder & fotb)1181 void ScoreFlowObj::LengthSpecType::start(FOTBuilder &fotb)
1182 {
1183   fotb.startScore(len_);
1184 }
1185 
copy() const1186 ScoreFlowObj::Type *ScoreFlowObj::SymbolType::copy() const
1187 {
1188   return new SymbolType(*this);
1189 }
1190 
copy() const1191 ScoreFlowObj::Type *ScoreFlowObj::LengthSpecType::copy() const
1192 {
1193   return new LengthSpecType(*this);
1194 }
1195 
copy() const1196 ScoreFlowObj::Type *ScoreFlowObj::CharType::copy() const
1197 {
1198   return new CharType(*this);
1199 }
1200 
1201 class BoxFlowObj : public CompoundFlowObj {
1202 public:
operator new(size_t,Collector & c)1203   void *operator new(size_t, Collector &c) {
1204     return c.allocateObject(1);
1205   }
1206   BoxFlowObj();
1207   BoxFlowObj(const BoxFlowObj &);
1208   FlowObj *copy(Collector &) const;
1209   void processInner(ProcessContext &);
1210   bool hasNonInheritedC(const Identifier *) const;
1211   void setNonInheritedC(const Identifier *, ELObj *,
1212 			const Location &, Interpreter &);
1213 private:
1214   Owner<FOTBuilder::BoxNIC> nic_;
1215 };
1216 
BoxFlowObj()1217 BoxFlowObj::BoxFlowObj()
1218 : nic_(new FOTBuilder::BoxNIC)
1219 {
1220 }
1221 
BoxFlowObj(const BoxFlowObj & fo)1222 BoxFlowObj::BoxFlowObj(const BoxFlowObj &fo)
1223 : CompoundFlowObj(fo), nic_(new FOTBuilder::BoxNIC(*fo.nic_))
1224 {
1225 }
1226 
processInner(ProcessContext & context)1227 void BoxFlowObj::processInner(ProcessContext &context)
1228 {
1229   FOTBuilder &fotb = context.currentFOTBuilder();
1230   fotb.startBox(*nic_);
1231   CompoundFlowObj::processInner(context);
1232   fotb.endBox();
1233 }
1234 
setNonInheritedC(const Identifier * ident,ELObj * obj,const Location & loc,Interpreter & interp)1235 void BoxFlowObj::setNonInheritedC(const Identifier *ident, ELObj *obj,
1236 					      const Location &loc, Interpreter &interp)
1237 {
1238   if (setDisplayNIC(*nic_, ident, obj, loc, interp))
1239     return;
1240   Identifier::SyntacticKey key;
1241   if (ident->syntacticKey(key)) {
1242     switch (key) {
1243     case Identifier::keyIsDisplay:
1244       interp.convertBooleanC(obj, ident, loc, nic_->isDisplay);
1245       return;
1246     case Identifier::keyBreakBeforePriority:
1247       interp.convertIntegerC(obj, ident, loc, nic_->breakBeforePriority);
1248       return;
1249     case Identifier::keyBreakAfterPriority:
1250       interp.convertIntegerC(obj, ident, loc, nic_->breakAfterPriority);
1251       return;
1252     default:
1253       break;
1254     }
1255   }
1256   CANNOT_HAPPEN();
1257 }
1258 
hasNonInheritedC(const Identifier * ident) const1259 bool BoxFlowObj::hasNonInheritedC(const Identifier *ident) const
1260 {
1261   Identifier::SyntacticKey key;
1262   if (ident->syntacticKey(key)) {
1263     switch (key) {
1264     case Identifier::keyIsDisplay:
1265     case Identifier::keyBreakBeforePriority:
1266     case Identifier::keyBreakAfterPriority:
1267       return 1;
1268     default:
1269       break;
1270     }
1271   }
1272   return isDisplayNIC(ident);
1273 }
1274 
copy(Collector & c) const1275 FlowObj *BoxFlowObj::copy(Collector &c) const
1276 {
1277   return new (c) BoxFlowObj(*this);
1278 }
1279 
1280 class LeaderFlowObj : public CompoundFlowObj {
1281 public:
operator new(size_t,Collector & c)1282   void *operator new(size_t, Collector &c) {
1283     return c.allocateObject(1);
1284   }
1285   LeaderFlowObj();
1286   LeaderFlowObj(const LeaderFlowObj &);
1287   void processInner(ProcessContext &);
1288   FlowObj *copy(Collector &) const;
1289   void setNonInheritedC(const Identifier *, ELObj *,
1290 			const Location &, Interpreter &);
1291   bool hasNonInheritedC(const Identifier *) const;
1292 private:
1293   Owner<FOTBuilder::LeaderNIC> nic_;
1294 };
1295 
LeaderFlowObj()1296 LeaderFlowObj::LeaderFlowObj()
1297 : nic_(new FOTBuilder::LeaderNIC)
1298 {
1299 }
1300 
LeaderFlowObj(const LeaderFlowObj & fo)1301 LeaderFlowObj::LeaderFlowObj(const LeaderFlowObj &fo)
1302 : CompoundFlowObj(fo), nic_(new FOTBuilder::LeaderNIC(*fo.nic_))
1303 {
1304 }
1305 
processInner(ProcessContext & context)1306 void LeaderFlowObj::processInner(ProcessContext &context)
1307 {
1308   FOTBuilder &fotb = context.currentFOTBuilder();
1309   fotb.startLeader(*nic_);
1310   CompoundFlowObj::processInner(context);
1311   fotb.endLeader();
1312 }
1313 
setNonInheritedC(const Identifier * ident,ELObj * obj,const Location & loc,Interpreter & interp)1314 void LeaderFlowObj::setNonInheritedC(const Identifier *ident, ELObj *obj,
1315 				     const Location &loc, Interpreter &interp)
1316 {
1317   Identifier::SyntacticKey key;
1318   if (ident->syntacticKey(key)) {
1319     switch (key) {
1320     case Identifier::keyLength:
1321       if (interp.convertLengthSpecC(obj, ident, loc, nic_->length))
1322 	nic_->hasLength = 1;
1323       return;
1324     case Identifier::keyBreakBeforePriority:
1325       interp.convertIntegerC(obj, ident, loc, nic_->breakBeforePriority);
1326       return;
1327     case Identifier::keyBreakAfterPriority:
1328       interp.convertIntegerC(obj, ident, loc, nic_->breakAfterPriority);
1329       return;
1330     default:
1331       break;
1332     }
1333   }
1334   CANNOT_HAPPEN();
1335 }
1336 
hasNonInheritedC(const Identifier * ident) const1337 bool LeaderFlowObj::hasNonInheritedC(const Identifier *ident) const
1338 {
1339   Identifier::SyntacticKey key;
1340   if (ident->syntacticKey(key)) {
1341     switch (key) {
1342     case Identifier::keyLength:
1343     case Identifier::keyBreakBeforePriority:
1344     case Identifier::keyBreakAfterPriority:
1345       return 1;
1346     default:
1347       break;
1348     }
1349   }
1350   return 0;
1351 }
1352 
copy(Collector & c) const1353 FlowObj *LeaderFlowObj::copy(Collector &c) const
1354 {
1355   return new (c) LeaderFlowObj(*this);
1356 }
1357 
1358 class CharacterFlowObj : public FlowObj {
1359 public:
operator new(size_t,Collector & c)1360   void *operator new(size_t, Collector &c) {
1361     return c.allocateObject(1);
1362   }
1363   CharacterFlowObj();
1364   CharacterFlowObj(const CharacterFlowObj &);
1365   void processInner(ProcessContext &);
1366   FlowObj *copy(Collector &) const;
1367   void setNonInheritedC(const Identifier *, ELObj *,
1368 			const Location &, Interpreter &);
1369   bool hasNonInheritedC(const Identifier *) const;
characterStyle(ProcessContext &,StyleObj * & style,FOTBuilder::CharacterNIC & nic)1370   bool characterStyle(ProcessContext &, StyleObj *&style, FOTBuilder::CharacterNIC &nic) {
1371     style = style_;
1372     nic = *nic_;
1373     return 1;
1374   }
isCharacter()1375   bool isCharacter() { return 1; }
1376 private:
1377   Owner<FOTBuilder::CharacterNIC> nic_;
1378 };
1379 
CharacterFlowObj()1380 CharacterFlowObj::CharacterFlowObj()
1381 : nic_(new FOTBuilder::CharacterNIC)
1382 {
1383 }
1384 
CharacterFlowObj(const CharacterFlowObj & fo)1385 CharacterFlowObj::CharacterFlowObj(const CharacterFlowObj &fo)
1386 : FlowObj(fo), nic_(new FOTBuilder::CharacterNIC(*fo.nic_))
1387 {
1388 }
1389 
processInner(ProcessContext & context)1390 void CharacterFlowObj::processInner(ProcessContext &context)
1391 {
1392   context.currentFOTBuilder().character(*nic_);
1393 }
1394 
setNonInheritedC(const Identifier * ident,ELObj * obj,const Location & loc,Interpreter & interp)1395 void CharacterFlowObj::setNonInheritedC(const Identifier *ident, ELObj *obj,
1396 					const Location &loc, Interpreter &interp)
1397 {
1398   Identifier::SyntacticKey key;
1399   if (ident->syntacticKey(key)) {
1400     switch (key) {
1401     case Identifier::keyIsSpace:
1402       if (interp.convertBooleanC(obj, ident, loc, nic_->isSpace))
1403         nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cIsSpace);
1404       return;
1405     case Identifier::keyIsRecordEnd:
1406       if (interp.convertBooleanC(obj, ident, loc, nic_->isRecordEnd))
1407         nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cIsRecordEnd);
1408       return;
1409     case Identifier::keyIsInputTab:
1410       if (interp.convertBooleanC(obj, ident, loc, nic_->isInputTab))
1411         nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cIsInputTab);
1412       return;
1413     case Identifier::keyIsInputWhitespace:
1414       if (interp.convertBooleanC(obj, ident, loc, nic_->isInputWhitespace))
1415         nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cIsInputWhitespace);
1416       return;
1417     case Identifier::keyIsPunct:
1418       if (interp.convertBooleanC(obj, ident, loc, nic_->isPunct))
1419         nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cIsPunct);
1420       return;
1421     case Identifier::keyIsDropAfterLineBreak:
1422       if (interp.convertBooleanC(obj, ident, loc, nic_->isDropAfterLineBreak))
1423         nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cIsDropAfterLineBreak);
1424       return;
1425     case Identifier::keyIsDropUnlessBeforeLineBreak:
1426       if (interp.convertBooleanC(obj, ident, loc, nic_->isDropUnlessBeforeLineBreak))
1427         nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cIsDropUnlessBeforeLineBreak);
1428       return;
1429     case Identifier::keyBreakBeforePriority:
1430       if (interp.convertIntegerC(obj, ident, loc, nic_->breakBeforePriority))
1431         nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cBreakBeforePriority);
1432       return;
1433     case Identifier::keyBreakAfterPriority:
1434       if (interp.convertIntegerC(obj, ident, loc, nic_->breakAfterPriority))
1435         nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cBreakAfterPriority);
1436       return;
1437     case Identifier::keyScript:
1438       {
1439 	if (obj == interp.makeFalse())
1440 	  nic_->script = 0;
1441 	else {
1442 	  StringC tem;
1443 	  if (!interp.convertStringC(obj, ident, loc, tem))
1444 	    return;
1445 	  nic_->script = interp.storePublicId(tem.data(), tem.size(), loc);
1446 	}
1447         nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cScript);
1448       }
1449       return;
1450     case Identifier::keyChar:
1451       if (interp.convertCharC(obj, ident, loc, nic_->ch))
1452         nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cChar);
1453       return;
1454     case Identifier::keyGlyphId:
1455       {
1456 	if (obj == interp.makeFalse()) {
1457 	  nic_->glyphId = FOTBuilder::GlyphId();
1458 	  nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cGlyphId);
1459 	  return;
1460 	}
1461 	const FOTBuilder::GlyphId *p = obj->glyphId();
1462 	if (!p) {
1463 	  interp.setNextLocation(loc);
1464 	  interp.message(InterpreterMessages::invalidCharacteristicValue,
1465   		         StringMessageArg(ident->name()));
1466 	  return;
1467 	}
1468 	nic_->glyphId = *p;
1469 	nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cGlyphId);
1470       }
1471       return;
1472     case Identifier::keyMathFontPosture:
1473       {
1474 	static FOTBuilder::Symbol vals[] = {
1475 	  FOTBuilder::symbolFalse,
1476 	  FOTBuilder::symbolNotApplicable,
1477 	  FOTBuilder::symbolUpright,
1478 	  FOTBuilder::symbolOblique,
1479 	  FOTBuilder::symbolBackSlantedOblique,
1480 	  FOTBuilder::symbolItalic,
1481 	  FOTBuilder::symbolBackSlantedItalic,
1482 	};
1483 	if (interp.convertEnumC(vals, SIZEOF(vals), obj, ident, loc, nic_->mathFontPosture))
1484 	  nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cMathFontPosture);
1485       }
1486       return;
1487     case Identifier::keyMathClass:
1488       {
1489 	static FOTBuilder::Symbol vals[] = {
1490 	  FOTBuilder::symbolOrdinary,
1491 	  FOTBuilder::symbolOperator,
1492 	  FOTBuilder::symbolBinary,
1493 	  FOTBuilder::symbolRelation,
1494 	  FOTBuilder::symbolOpening,
1495 	  FOTBuilder::symbolClosing,
1496 	  FOTBuilder::symbolPunctuation,
1497 	  FOTBuilder::symbolInner,
1498 	  FOTBuilder::symbolSpace,
1499 	};
1500 	if (interp.convertEnumC(vals, SIZEOF(vals), obj, ident, loc, nic_->mathClass))
1501 	  nic_->specifiedC |= (1 << FOTBuilder::CharacterNIC::cMathClass);
1502       }
1503       return;
1504     case Identifier::keyStretchFactor:
1505       interp.convertRealC(obj, ident, loc, nic_->stretchFactor);
1506       return;
1507     default:
1508       break;
1509     }
1510   }
1511   CANNOT_HAPPEN();
1512 }
1513 
hasNonInheritedC(const Identifier * ident) const1514 bool CharacterFlowObj::hasNonInheritedC(const Identifier *ident) const
1515 {
1516   Identifier::SyntacticKey key;
1517   if (ident->syntacticKey(key)) {
1518     switch (key) {
1519     case Identifier::keyChar:
1520     case Identifier::keyGlyphId:
1521     case Identifier::keyIsSpace:
1522     case Identifier::keyIsRecordEnd:
1523     case Identifier::keyIsInputTab:
1524     case Identifier::keyIsInputWhitespace:
1525     case Identifier::keyIsPunct:
1526     case Identifier::keyIsDropAfterLineBreak:
1527     case Identifier::keyIsDropUnlessBeforeLineBreak:
1528     case Identifier::keyScript:
1529     case Identifier::keyMathClass:
1530     case Identifier::keyMathFontPosture:
1531     case Identifier::keyStretchFactor:
1532     case Identifier::keyBreakBeforePriority:
1533     case Identifier::keyBreakAfterPriority:
1534       return 1;
1535     default:
1536       break;
1537     }
1538   }
1539   return 0;
1540 }
1541 
copy(Collector & c) const1542 FlowObj *CharacterFlowObj::copy(Collector &c) const
1543 {
1544   return new (c) CharacterFlowObj(*this);
1545 }
1546 
1547 class MathSequenceFlowObj : public CompoundFlowObj {
1548 public:
MathSequenceFlowObj()1549   MathSequenceFlowObj() { }
processInner(ProcessContext & context)1550   void processInner(ProcessContext &context) {
1551     FOTBuilder &fotb = context.currentFOTBuilder();
1552     fotb.startMathSequence();
1553     CompoundFlowObj::processInner(context);
1554     fotb.endMathSequence();
1555   }
copy(Collector & c) const1556   FlowObj *copy(Collector &c) const {
1557     return new (c) MathSequenceFlowObj(*this);
1558   }
1559 };
1560 
1561 class FractionFlowObj : public CompoundFlowObj {
1562 public:
FractionFlowObj()1563   FractionFlowObj() { }
1564   void processInner(ProcessContext &);
1565   FlowObj *copy(Collector &) const;
1566 };
1567 
processInner(ProcessContext & context)1568 void FractionFlowObj::processInner(ProcessContext &context)
1569 {
1570   FOTBuilder &fotb = context.currentFOTBuilder();
1571   Vector<FOTBuilder *> fotbs(2);
1572   fotb.startFraction(fotbs[0], fotbs[1]);
1573   Vector<size_t> dep;
1574   StyleObj *fractionBarStyle = 0;
1575   SosofoObj *sosofo
1576     = context.currentStyleStack().actual(context.vm().interp->fractionBarC(),
1577 					 *context.vm().interp, dep)->asSosofo();
1578   if (sosofo)
1579     sosofo->ruleStyle(context, fractionBarStyle);
1580   if (fractionBarStyle)
1581     context.currentStyleStack().push(fractionBarStyle, context.vm(), fotb);
1582   fotb.fractionBar();
1583   if (fractionBarStyle)
1584     context.currentStyleStack().pop();
1585   Vector<SymbolObj *> labels(2);
1586   labels[0] = context.vm().interp->portName(Interpreter::portNumerator);
1587   labels[1] = context.vm().interp->portName(Interpreter::portDenominator);
1588   context.pushPorts(0, labels, fotbs);
1589   // Fraction flow object doesn't have principal port,
1590   // so clear the current connection.
1591   CompoundFlowObj::processInner(context);
1592   context.popPorts();
1593   fotb.endFraction();
1594 }
1595 
copy(Collector & c) const1596 FlowObj *FractionFlowObj::copy(Collector &c) const
1597 {
1598   return new (c) FractionFlowObj(*this);
1599 }
1600 
1601 class UnmathFlowObj : public CompoundFlowObj {
1602 public:
UnmathFlowObj()1603   UnmathFlowObj() { }
processInner(ProcessContext & context)1604   void processInner(ProcessContext &context) {
1605     FOTBuilder &fotb = context.currentFOTBuilder();
1606     fotb.startUnmath();
1607     CompoundFlowObj::processInner(context);
1608     fotb.endUnmath();
1609   }
copy(Collector & c) const1610   FlowObj *copy(Collector &c) const {
1611     return new (c) UnmathFlowObj(*this);
1612   }
1613 };
1614 
1615 class SuperscriptFlowObj : public CompoundFlowObj {
1616 public:
SuperscriptFlowObj()1617   SuperscriptFlowObj() { }
processInner(ProcessContext & context)1618   void processInner(ProcessContext &context) {
1619     FOTBuilder &fotb = context.currentFOTBuilder();
1620     fotb.startSuperscript();
1621     CompoundFlowObj::processInner(context);
1622     fotb.endSuperscript();
1623   }
copy(Collector & c) const1624   FlowObj *copy(Collector &c) const {
1625     return new (c) SuperscriptFlowObj(*this);
1626   }
1627 };
1628 
1629 class SubscriptFlowObj : public CompoundFlowObj {
1630 public:
SubscriptFlowObj()1631   SubscriptFlowObj() { }
processInner(ProcessContext & context)1632   void processInner(ProcessContext &context) {
1633     FOTBuilder &fotb = context.currentFOTBuilder();
1634     fotb.startSubscript();
1635     CompoundFlowObj::processInner(context);
1636     fotb.endSubscript();
1637   }
copy(Collector & c) const1638   FlowObj *copy(Collector &c) const {
1639     return new (c) SubscriptFlowObj(*this);
1640   }
1641 };
1642 
1643 class ScriptFlowObj : public CompoundFlowObj {
1644 public:
ScriptFlowObj()1645   ScriptFlowObj() { }
1646   void processInner(ProcessContext &);
copy(Collector & c) const1647   FlowObj *copy(Collector &c) const {
1648     return new (c) ScriptFlowObj(*this);
1649   }
1650 
1651 };
1652 
processInner(ProcessContext & context)1653 void ScriptFlowObj::processInner(ProcessContext &context)
1654 {
1655   FOTBuilder &fotb = context.currentFOTBuilder();
1656   Vector<FOTBuilder *> fotbs(6);
1657   fotb.startScript(fotbs[0], fotbs[1], fotbs[2], fotbs[3],
1658                    fotbs[4], fotbs[5]);
1659   Vector<SymbolObj *> labels(6);
1660   labels[0] = context.vm().interp->portName(Interpreter::portPreSup);
1661   labels[1] = context.vm().interp->portName(Interpreter::portPreSub);
1662   labels[2] = context.vm().interp->portName(Interpreter::portPostSup);
1663   labels[3] = context.vm().interp->portName(Interpreter::portPostSub);
1664   labels[4] = context.vm().interp->portName(Interpreter::portMidSup);
1665   labels[5] = context.vm().interp->portName(Interpreter::portMidSub);
1666   context.pushPorts(1, labels, fotbs);
1667   CompoundFlowObj::processInner(context);
1668   context.popPorts();
1669   fotb.endScript();
1670 }
1671 
1672 class MarkFlowObj : public CompoundFlowObj {
1673 public:
MarkFlowObj()1674   MarkFlowObj() { }
1675   void processInner(ProcessContext &);
copy(Collector & c) const1676   FlowObj *copy(Collector &c) const {
1677     return new (c) MarkFlowObj(*this);
1678   }
1679 };
1680 
processInner(ProcessContext & context)1681 void MarkFlowObj::processInner(ProcessContext &context)
1682 {
1683   FOTBuilder &fotb = context.currentFOTBuilder();
1684   Vector<FOTBuilder *> fotbs(2);
1685   fotb.startMark(fotbs[0], fotbs[1]);
1686   Vector<SymbolObj *> labels(2);
1687   labels[0] = context.vm().interp->portName(Interpreter::portOverMark);
1688   labels[1] = context.vm().interp->portName(Interpreter::portUnderMark);
1689   context.pushPorts(1, labels, fotbs);
1690   CompoundFlowObj::processInner(context);
1691   context.popPorts();
1692   fotb.endMark();
1693 }
1694 
1695 class FenceFlowObj : public CompoundFlowObj {
1696 public:
FenceFlowObj()1697   FenceFlowObj() { }
1698   void processInner(ProcessContext &);
copy(Collector & c) const1699   FlowObj *copy(Collector &c) const {
1700     return new (c) FenceFlowObj(*this);
1701   }
1702 };
1703 
processInner(ProcessContext & context)1704 void FenceFlowObj::processInner(ProcessContext &context)
1705 {
1706   FOTBuilder &fotb = context.currentFOTBuilder();
1707   Vector<FOTBuilder *> fotbs(2);
1708   fotb.startFence(fotbs[0], fotbs[1]);
1709   Vector<SymbolObj *> labels(2);
1710   labels[0] = context.vm().interp->portName(Interpreter::portOpen);
1711   labels[1] = context.vm().interp->portName(Interpreter::portClose);
1712   context.pushPorts(1, labels, fotbs);
1713   CompoundFlowObj::processInner(context);
1714   context.popPorts();
1715   fotb.endFence();
1716 }
1717 
1718 class RadicalFlowObj : public CompoundFlowObj {
1719 public:
RadicalFlowObj()1720   RadicalFlowObj() : radical_(0) { }
1721   void processInner(ProcessContext &);
copy(Collector & c) const1722   FlowObj *copy(Collector &c) const {
1723     return new (c) RadicalFlowObj(*this);
1724   }
1725   void setNonInheritedC(const Identifier *, ELObj *,
1726 			const Location &, Interpreter &);
1727   bool hasNonInheritedC(const Identifier *) const;
traceSubObjects(Collector & c) const1728   void traceSubObjects(Collector &c) const {
1729     c.trace(radical_);
1730     CompoundFlowObj::traceSubObjects(c);
1731   }
1732 private:
1733   SosofoObj *radical_;
1734 };
1735 
processInner(ProcessContext & context)1736 void RadicalFlowObj::processInner(ProcessContext &context)
1737 {
1738   FOTBuilder &fotb = context.currentFOTBuilder();
1739   Vector<FOTBuilder *> fotbs(1);
1740   fotb.startRadical(fotbs[0]);
1741   StyleObj *style;
1742   FOTBuilder::CharacterNIC nic;
1743   if (radical_ && radical_->characterStyle(context, style, nic)) {
1744     if (style)
1745       context.currentStyleStack().push(style, context.vm(), fotb);
1746     fotb.radicalRadical(nic);
1747     if (style)
1748       context.currentStyleStack().pop();
1749   }
1750   else
1751     fotb.radicalRadicalDefaulted();
1752   Vector<SymbolObj *> labels(1);
1753   labels[0] = context.vm().interp->portName(Interpreter::portDegree);
1754   context.pushPorts(1, labels, fotbs);
1755   CompoundFlowObj::processInner(context);
1756   context.popPorts();
1757   fotb.endRadical();
1758 }
1759 
hasNonInheritedC(const Identifier * ident) const1760 bool RadicalFlowObj::hasNonInheritedC(const Identifier *ident) const
1761 {
1762   Identifier::SyntacticKey key;
1763   return ident->syntacticKey(key) && key == Identifier::keyRadical;
1764 }
1765 
setNonInheritedC(const Identifier * ident,ELObj * obj,const Location & loc,Interpreter & interp)1766 void RadicalFlowObj::setNonInheritedC(const Identifier *ident, ELObj *obj,
1767 				      const Location &loc, Interpreter &interp)
1768 {
1769   radical_ = obj->asSosofo();
1770   if (!radical_ || !radical_->isCharacter()) {
1771     interp.setNextLocation(loc);
1772     interp.message(InterpreterMessages::invalidCharacteristicValue,
1773 		   StringMessageArg(ident->name()));
1774   }
1775 }
1776 
1777 class MathOperatorFlowObj : public CompoundFlowObj {
1778 public:
MathOperatorFlowObj()1779   MathOperatorFlowObj() { }
1780   void processInner(ProcessContext &);
copy(Collector & c) const1781   FlowObj *copy(Collector &c) const {
1782     return new (c) MathOperatorFlowObj(*this);
1783   }
1784 };
1785 
processInner(ProcessContext & context)1786 void MathOperatorFlowObj::processInner(ProcessContext &context)
1787 {
1788   FOTBuilder &fotb = context.currentFOTBuilder();
1789   Vector<FOTBuilder *> fotbs(3);
1790   fotb.startMathOperator(fotbs[0], fotbs[1], fotbs[2]);
1791   Vector<SymbolObj *> labels(3);
1792   labels[0] = context.vm().interp->portName(Interpreter::portOperator);
1793   labels[1] = context.vm().interp->portName(Interpreter::portLowerLimit);
1794   labels[2] = context.vm().interp->portName(Interpreter::portUpperLimit);
1795   context.pushPorts(1, labels, fotbs);
1796   CompoundFlowObj::processInner(context);
1797   context.popPorts();
1798   fotb.endMathOperator();
1799 }
1800 
1801 class GridFlowObj : public CompoundFlowObj {
1802 public:
operator new(size_t,Collector & c)1803   void *operator new(size_t, Collector &c) {
1804     return c.allocateObject(1);
1805   }
1806   GridFlowObj();
1807   GridFlowObj(const GridFlowObj &);
1808   void processInner(ProcessContext &);
copy(Collector & c) const1809   FlowObj *copy(Collector &c) const {
1810     return new (c) GridFlowObj(*this);
1811   }
1812   void setNonInheritedC(const Identifier *, ELObj *,
1813 			const Location &, Interpreter &);
1814   bool hasNonInheritedC(const Identifier *) const;
1815 private:
1816   Owner<FOTBuilder::GridNIC> nic_;
1817 };
1818 
GridFlowObj()1819 GridFlowObj::GridFlowObj()
1820 : nic_(new FOTBuilder::GridNIC)
1821 {
1822 }
1823 
GridFlowObj(const GridFlowObj & fo)1824 GridFlowObj::GridFlowObj(const GridFlowObj &fo)
1825 : CompoundFlowObj(fo), nic_(new FOTBuilder::GridNIC(*fo.nic_))
1826 {
1827 }
1828 
processInner(ProcessContext & context)1829 void GridFlowObj::processInner(ProcessContext &context)
1830 {
1831   FOTBuilder &fotb = context.currentFOTBuilder();
1832   fotb.startGrid(*nic_);
1833   CompoundFlowObj::processInner(context);
1834   fotb.endGrid();
1835 }
1836 
setNonInheritedC(const Identifier * ident,ELObj * obj,const Location & loc,Interpreter & interp)1837 void GridFlowObj::setNonInheritedC(const Identifier *ident, ELObj *obj,
1838 					const Location &loc, Interpreter &interp)
1839 {
1840   long tem;
1841   if (!interp.convertIntegerC(obj, ident, loc, tem))
1842     return;
1843   if (tem <= 0) {
1844     interp.setNextLocation(loc);
1845     interp.message(InterpreterMessages::invalidCharacteristicValue,
1846 		   StringMessageArg(ident->name()));
1847     return;
1848   }
1849   Identifier::SyntacticKey key;
1850   if (ident->syntacticKey(key)) {
1851     switch (key) {
1852     case Identifier::keyGridNColumns:
1853       nic_->nColumns = tem;
1854       return;
1855     case Identifier::keyGridNRows:
1856       nic_->nRows = tem;
1857       return;
1858     default:
1859       break;
1860     }
1861   }
1862   CANNOT_HAPPEN();
1863 }
1864 
hasNonInheritedC(const Identifier * ident) const1865 bool GridFlowObj::hasNonInheritedC(const Identifier *ident) const
1866 {
1867   Identifier::SyntacticKey key;
1868   if (ident->syntacticKey(key)) {
1869     switch (key) {
1870     case Identifier::keyGridNColumns:
1871     case Identifier::keyGridNRows:
1872       return 1;
1873     default:
1874       break;
1875     }
1876   }
1877   return 0;
1878 }
1879 
1880 class GridCellFlowObj : public CompoundFlowObj {
1881 public:
operator new(size_t,Collector & c)1882   void *operator new(size_t, Collector &c) {
1883     return c.allocateObject(1);
1884   }
1885   GridCellFlowObj();
1886   GridCellFlowObj(const GridCellFlowObj &);
1887   void processInner(ProcessContext &);
copy(Collector & c) const1888   FlowObj *copy(Collector &c) const {
1889     return new (c) GridCellFlowObj(*this);
1890   }
1891   void setNonInheritedC(const Identifier *, ELObj *,
1892 			const Location &, Interpreter &);
1893   bool hasNonInheritedC(const Identifier *) const;
1894 private:
1895   Owner<FOTBuilder::GridCellNIC> nic_;
1896 };
1897 
GridCellFlowObj()1898 GridCellFlowObj::GridCellFlowObj()
1899 : nic_(new FOTBuilder::GridCellNIC)
1900 {
1901 }
1902 
GridCellFlowObj(const GridCellFlowObj & fo)1903 GridCellFlowObj::GridCellFlowObj(const GridCellFlowObj &fo)
1904 : CompoundFlowObj(fo), nic_(new FOTBuilder::GridCellNIC(*fo.nic_))
1905 {
1906 }
1907 
processInner(ProcessContext & context)1908 void GridCellFlowObj::processInner(ProcessContext &context)
1909 {
1910   FOTBuilder &fotb = context.currentFOTBuilder();
1911   fotb.startGridCell(*nic_);
1912   CompoundFlowObj::processInner(context);
1913   fotb.endGridCell();
1914 }
1915 
setNonInheritedC(const Identifier * ident,ELObj * obj,const Location & loc,Interpreter & interp)1916 void GridCellFlowObj::setNonInheritedC(const Identifier *ident, ELObj *obj,
1917 				       const Location &loc, Interpreter &interp)
1918 {
1919   long tem;
1920   if (!interp.convertIntegerC(obj, ident, loc, tem))
1921     return;
1922   if (tem <= 0) {
1923     interp.setNextLocation(loc);
1924     interp.message(InterpreterMessages::invalidCharacteristicValue,
1925 		   StringMessageArg(ident->name()));
1926     return;
1927   }
1928   Identifier::SyntacticKey key;
1929   if (ident->syntacticKey(key)) {
1930     switch (key) {
1931     case Identifier::keyColumnNumber:
1932       nic_->columnNumber = tem;
1933       return;
1934     case Identifier::keyRowNumber:
1935       nic_->rowNumber = tem;
1936       return;
1937     default:
1938       break;
1939     }
1940   }
1941   CANNOT_HAPPEN();
1942 }
1943 
hasNonInheritedC(const Identifier * ident) const1944 bool GridCellFlowObj::hasNonInheritedC(const Identifier *ident) const
1945 {
1946   Identifier::SyntacticKey key;
1947   if (ident->syntacticKey(key)) {
1948     switch (key) {
1949     case Identifier::keyColumnNumber:
1950     case Identifier::keyRowNumber:
1951       return 1;
1952     default:
1953       break;
1954     }
1955   }
1956   return 0;
1957 }
1958 
1959 class TableFlowObj : public CompoundFlowObj {
1960 public:
operator new(size_t,Collector & c)1961   void *operator new(size_t, Collector &c) {
1962     return c.allocateObject(1);
1963   }
1964   struct NIC : public FOTBuilder::TableNIC {
NICDSSSL_NAMESPACE::TableFlowObj::NIC1965     NIC() : beforeRowBorder(0), afterRowBorder(0),
1966             beforeColumnBorder(0), afterColumnBorder(0) { }
1967     StyleObj *beforeRowBorder;
1968     StyleObj *afterRowBorder;
1969     StyleObj *beforeColumnBorder;
1970     StyleObj *afterColumnBorder;
1971   };
TableFlowObj()1972   TableFlowObj() : nic_(new NIC) { }
TableFlowObj(const TableFlowObj & fo)1973   TableFlowObj(const TableFlowObj &fo) : CompoundFlowObj(fo), nic_(new NIC(*fo.nic_)) { }
processInner(ProcessContext & context)1974   void processInner(ProcessContext &context) {
1975     context.startTable();
1976     FOTBuilder &fotb = context.currentFOTBuilder();
1977     fotb.startTable(*nic_);
1978     Interpreter &interp = *context.vm().interp;
1979     Vector<size_t> dep;
1980     ELObj *obj = context.currentStyleStack().actual(interp.tableBorderC(), interp, dep);
1981     StyleObj *borderStyle;
1982     if (obj == interp.makeFalse())
1983       borderStyle = interp.borderFalseStyle();
1984     else if (obj == interp.makeTrue())
1985       borderStyle = interp.borderTrueStyle();
1986     else {
1987       SosofoObj *sosofo = obj->asSosofo();
1988       if (!sosofo || !sosofo->tableBorderStyle(borderStyle))
1989 	borderStyle = 0;
1990     }
1991     border(nic_->beforeRowBorder, borderStyle, &FOTBuilder::tableBeforeRowBorder, context);
1992     border(nic_->afterRowBorder, borderStyle, &FOTBuilder::tableAfterRowBorder, context);
1993     border(nic_->beforeColumnBorder, borderStyle, &FOTBuilder::tableBeforeColumnBorder, context);
1994     border(nic_->afterColumnBorder, borderStyle, &FOTBuilder::tableAfterColumnBorder, context);
1995     CompoundFlowObj::processInner(context);
1996     if (context.inTableRow())
1997       context.endTableRow();
1998     context.endTable();
1999     fotb.endTable();
2000   }
copy(Collector & c) const2001   FlowObj *copy(Collector &c) const {
2002     return new (c) TableFlowObj(*this);
2003   }
hasNonInheritedC(const Identifier * ident) const2004   bool hasNonInheritedC(const Identifier *ident) const {
2005     Identifier::SyntacticKey key;
2006     if (ident->syntacticKey(key)) {
2007       switch (key) {
2008       case Identifier::keyBeforeRowBorder:
2009       case Identifier::keyAfterRowBorder:
2010       case Identifier::keyBeforeColumnBorder:
2011       case Identifier::keyAfterColumnBorder:
2012       case Identifier::keyTableWidth:
2013 	return 1;
2014       default:
2015 	break;
2016       }
2017     }
2018     return isDisplayNIC(ident);
2019   }
setNonInheritedC(const Identifier * ident,ELObj * obj,const Location & loc,Interpreter & interp)2020   void setNonInheritedC(const Identifier *ident, ELObj *obj,
2021                         const Location &loc, Interpreter &interp) {
2022     if (setDisplayNIC(*nic_, ident, obj, loc, interp))
2023       return;
2024     Identifier::SyntacticKey key;
2025     if (!ident->syntacticKey(key))
2026       CANNOT_HAPPEN();
2027     if (key == Identifier::keyTableWidth) {
2028       if (obj == interp.makeFalse())
2029 	nic_->widthType = FOTBuilder::TableNIC::widthMinimum;
2030       else if (interp.convertLengthSpecC(obj, ident, loc, nic_->width))
2031 	nic_->widthType = FOTBuilder::TableNIC::widthExplicit;
2032       return;
2033     }
2034     StyleObj *style;
2035     SosofoObj *sosofo = obj->asSosofo();
2036     if (!sosofo || !sosofo->tableBorderStyle(style)) {
2037       Boolean b;
2038       if (!interp.convertBooleanC(obj, ident, loc, b))
2039 	return;
2040       style = b ? interp.borderTrueStyle() : interp.borderFalseStyle();
2041     }
2042     switch (key) {
2043     case Identifier::keyBeforeRowBorder:
2044       nic_->beforeRowBorder = style;
2045       break;
2046     case Identifier::keyAfterRowBorder:
2047       nic_->afterRowBorder = style;
2048       break;
2049     case Identifier::keyBeforeColumnBorder:
2050       nic_->beforeColumnBorder = style;
2051       break;
2052     case Identifier::keyAfterColumnBorder:
2053       nic_->afterColumnBorder = style;
2054       break;
2055     default:
2056       CANNOT_HAPPEN();
2057     }
2058   }
2059 private:
border(StyleObj * style,StyleObj * style2,void (FOTBuilder::* setter)(),ProcessContext & context)2060   void border(StyleObj *style, StyleObj *style2,
2061               void (FOTBuilder::*setter)(), ProcessContext &context) {
2062     FOTBuilder &fotb = context.currentFOTBuilder();
2063     if (!style)
2064       style = style2;
2065     if (style)
2066       context.currentStyleStack().push(style, context.vm(), fotb);
2067     (fotb.*setter)();
2068     if (style)
2069       context.currentStyleStack().pop();
2070   }
2071   Owner<NIC> nic_;
2072 };
2073 
2074 class TablePartFlowObj : public CompoundFlowObj {
2075 public:
operator new(size_t,Collector & c)2076   void *operator new(size_t, Collector &c) {
2077     return c.allocateObject(1);
2078   }
TablePartFlowObj()2079   TablePartFlowObj() : nic_(new FOTBuilder::TablePartNIC) { }
TablePartFlowObj(const TablePartFlowObj & fo)2080   TablePartFlowObj(const TablePartFlowObj &fo)
2081     : CompoundFlowObj(fo), nic_(new FOTBuilder::TablePartNIC(*fo.nic_)) { }
processInner(ProcessContext & context)2082   void processInner(ProcessContext &context) {
2083     context.startTablePart();
2084     FOTBuilder &fotb = context.currentFOTBuilder();
2085     Vector<FOTBuilder *> fotbs(2);
2086     fotb.startTablePart(*nic_, fotbs[0], fotbs[1]);
2087     Vector<SymbolObj *> labels(2);
2088     labels[0] = context.vm().interp->portName(Interpreter::portHeader);
2089     labels[1] = context.vm().interp->portName(Interpreter::portFooter);
2090     context.pushPorts(1, labels, fotbs);
2091     CompoundFlowObj::processInner(context);
2092     context.popPorts();
2093     if (context.inTableRow())
2094       context.endTableRow();
2095     context.endTablePart();
2096     fotb.endTablePart();
2097   }
copy(Collector & c) const2098   FlowObj *copy(Collector &c) const {
2099     return new (c) TablePartFlowObj(*this);
2100   }
setNonInheritedC(const Identifier * ident,ELObj * obj,const Location & loc,Interpreter & interp)2101   void setNonInheritedC(const Identifier *ident, ELObj *obj,
2102 			const Location &loc, Interpreter &interp) {
2103     setDisplayNIC(*nic_, ident, obj, loc, interp);
2104   }
hasNonInheritedC(const Identifier * ident) const2105   bool hasNonInheritedC(const Identifier *ident) const {
2106     if (!isDisplayNIC(ident))
2107       return 0;
2108     Identifier::SyntacticKey key;
2109     ident->syntacticKey(key);
2110     if (key == Identifier::keyPositionPreference)
2111       return 0;
2112     return 1;
2113   }
2114 private:
2115   Owner<FOTBuilder::TablePartNIC> nic_;
2116 };
2117 
2118 class TableColumnFlowObj : public FlowObj {
2119 public:
operator new(size_t,Collector & c)2120   void *operator new(size_t, Collector &c) {
2121     return c.allocateObject(1);
2122   }
2123   struct NIC : public FOTBuilder::TableColumnNIC {
NICDSSSL_NAMESPACE::TableColumnFlowObj::NIC2124     NIC() : hasColumnNumber(0) { }
2125     bool hasColumnNumber;
2126   };
TableColumnFlowObj()2127   TableColumnFlowObj() : nic_(new NIC) { }
TableColumnFlowObj(const TableColumnFlowObj & fo)2128   TableColumnFlowObj(const TableColumnFlowObj &fo) : FlowObj(fo), nic_(new NIC(*fo.nic_)) { }
processInner(ProcessContext & context)2129   void processInner(ProcessContext &context) {
2130     if (nic_->hasColumnNumber) {
2131       context.currentFOTBuilder().tableColumn(*nic_);
2132       context.addTableColumn(nic_->columnIndex, nic_->nColumnsSpanned, style_);
2133     }
2134     else {
2135       FOTBuilder::TableColumnNIC nic(*nic_);
2136       nic.columnIndex = context.currentTableColumn();
2137       context.currentFOTBuilder().tableColumn(nic);
2138       context.addTableColumn(nic.columnIndex, nic_->nColumnsSpanned, style_);
2139     }
2140   }
copy(Collector & c) const2141   FlowObj *copy(Collector &c) const {
2142     return new (c) TableColumnFlowObj(*this);
2143   }
hasNonInheritedC(const Identifier * ident) const2144   bool hasNonInheritedC(const Identifier *ident) const {
2145     Identifier::SyntacticKey key;
2146     if (ident->syntacticKey(key)) {
2147       switch (key) {
2148       case Identifier::keyColumnNumber:
2149       case Identifier::keyNColumnsSpanned:
2150       case Identifier::keyWidth:
2151 	return 1;
2152       default:
2153 	break;
2154       }
2155     }
2156     return 0;
2157   }
setNonInheritedC(const Identifier * ident,ELObj * obj,const Location & loc,Interpreter & interp)2158   void setNonInheritedC(const Identifier *ident, ELObj *obj,
2159   			const Location &loc, Interpreter &interp) {
2160     Identifier::SyntacticKey key;
2161     if (ident->syntacticKey(key)) {
2162       switch (key) {
2163       case Identifier::keyColumnNumber:
2164       case Identifier::keyNColumnsSpanned:
2165 	{
2166 	  long n;
2167 	  if (!interp.convertIntegerC(obj, ident, loc, n))
2168 	    return;
2169           if (n <= 0) {
2170 	    interp.setNextLocation(loc);
2171             interp.message(InterpreterMessages::invalidCharacteristicValue,
2172 	  		   StringMessageArg(ident->name()));
2173 	    return;
2174           }
2175 	  if (key == Identifier::keyColumnNumber) {
2176 	    nic_->columnIndex = n - 1;
2177 	    nic_->hasColumnNumber = 1;
2178 	  }
2179 	  else
2180 	    nic_->nColumnsSpanned = n;
2181 	}
2182 	return;
2183       case Identifier::keyWidth:
2184 	{
2185 	  const LengthSpec *ls = obj->lengthSpec();
2186 	  if (ls) {
2187 	    // width is a TableLengthSpec not just a LengthSpec
2188 	    if (ls->convert(nic_->width))
2189 	      nic_->hasWidth = 1;
2190 	    else
2191 	      interp.invalidCharacteristicValue(ident, loc);
2192 	  }
2193 	  else if (interp.convertLengthSpecC(obj, ident, loc, nic_->width))
2194 	    nic_->hasWidth = 1;
2195 	}
2196 	return;
2197       default:
2198 	break;
2199       }
2200     }
2201     CANNOT_HAPPEN();
2202   }
2203 private:
2204   Owner<NIC> nic_;
2205 };
2206 
2207 class TableRowFlowObj : public CompoundFlowObj {
2208 public:
TableRowFlowObj()2209   TableRowFlowObj() { }
pushStyle(ProcessContext &,unsigned &)2210   void pushStyle(ProcessContext &, unsigned &) {  }
popStyle(ProcessContext &,unsigned)2211   void popStyle(ProcessContext &, unsigned) {  }
processInner(ProcessContext & context)2212   void processInner(ProcessContext &context) {
2213     if (!context.inTable()) {
2214       // FIXME location
2215       context.vm().interp->message(InterpreterMessages::tableRowOutsideTable);
2216       CompoundFlowObj::processInner(context);
2217       return;
2218     }
2219     if (context.inTableRow())
2220       context.endTableRow();
2221     context.startTableRow(style_);
2222     CompoundFlowObj::processInner(context);
2223     if (context.inTableRow())
2224       context.endTableRow();
2225     // else FIXME give an error
2226     // must have used ends-row? in a table-row
2227   }
copy(Collector & c) const2228   FlowObj *copy(Collector &c) const {
2229     return new (c) TableRowFlowObj(*this);
2230   }
2231 };
2232 
2233 class TableCellFlowObj : public CompoundFlowObj {
2234 public:
operator new(size_t,Collector & c)2235   void *operator new(size_t, Collector &c) {
2236     return c.allocateObject(1);
2237   }
2238   struct NIC : FOTBuilder::TableCellNIC {
NICDSSSL_NAMESPACE::TableCellFlowObj::NIC2239     NIC() : startsRow(0), endsRow(0), hasColumnNumber(0) { }
2240     bool hasColumnNumber;
2241     bool startsRow;
2242     bool endsRow;
2243   };
TableCellFlowObj(bool missing=0)2244   TableCellFlowObj(bool missing = 0) : nic_(new NIC) {
2245     if (missing)
2246       nic_->missing = 1;
2247   }
TableCellFlowObj(const TableCellFlowObj & fo)2248   TableCellFlowObj(const TableCellFlowObj &fo) : CompoundFlowObj(fo), nic_(new NIC(*fo.nic_)) { }
pushStyle(ProcessContext & context,unsigned & nPush)2249   void pushStyle(ProcessContext &context, unsigned &nPush) {
2250     if (context.inTableRow()) {
2251       if (nic_->startsRow) {
2252 	context.endTableRow();
2253 	context.startTableRow(0);
2254       }
2255     }
2256     else
2257       context.startTableRow(0);
2258     unsigned columnNumber
2259       = nic_->hasColumnNumber ? nic_->columnIndex : context.currentTableColumn();
2260     StyleObj *columnStyle = context.tableColumnStyle(columnNumber, nic_->nColumnsSpanned);
2261     if (columnStyle) {
2262       context.currentStyleStack().push(columnStyle, context.vm(), context.currentFOTBuilder());
2263       context.currentFOTBuilder().startSequence();
2264       nPush++;
2265     }
2266     StyleObj *rowStyle = context.tableRowStyle();
2267     if (rowStyle) {
2268       context.currentStyleStack().push(rowStyle, context.vm(), context.currentFOTBuilder());
2269       context.currentFOTBuilder().startSequence();
2270       nPush++;
2271     }
2272     CompoundFlowObj::pushStyle(context, nPush);
2273   }
popStyle(ProcessContext & context,unsigned nPush)2274   void popStyle(ProcessContext &context, unsigned nPush) {
2275     CompoundFlowObj::popStyle(context, nPush);
2276     for (unsigned i = 0; i < nPush; i++) {
2277       context.currentFOTBuilder().endSequence();
2278       context.currentStyleStack().pop();
2279     }
2280     if (nic_->endsRow)
2281       context.endTableRow();
2282   }
processInner(ProcessContext & context)2283   void processInner(ProcessContext &context) {
2284     if (!context.inTable()) {
2285       // FIXME location
2286       context.vm().interp->message(InterpreterMessages::tableCellOutsideTable);
2287       CompoundFlowObj::processInner(context);
2288       return;
2289     }
2290     FOTBuilder &fotb = context.currentFOTBuilder();
2291     if (!nic_->hasColumnNumber) {
2292       FOTBuilder::TableCellNIC nic(*nic_);
2293       nic.columnIndex = context.currentTableColumn();
2294       fotb.startTableCell(nic);
2295       if (!nic_->missing)
2296 	context.noteTableCell(nic.columnIndex, nic.nColumnsSpanned, nic.nRowsSpanned);
2297     }
2298     else {
2299       fotb.startTableCell(*nic_);
2300       if (!nic_->missing)
2301 	context.noteTableCell(nic_->columnIndex, nic_->nColumnsSpanned, nic_->nRowsSpanned);
2302     }
2303     Interpreter &interp = *context.vm().interp;
2304     border(interp.cellBeforeRowBorderC(), &FOTBuilder::tableCellBeforeRowBorder, context);
2305     border(interp.cellAfterRowBorderC(), &FOTBuilder::tableCellAfterRowBorder, context);
2306     border(interp.cellBeforeColumnBorderC(), &FOTBuilder::tableCellBeforeColumnBorder, context);
2307     border(interp.cellAfterColumnBorderC(), &FOTBuilder::tableCellAfterColumnBorder, context);
2308     CompoundFlowObj::processInner(context);
2309     fotb.endTableCell();
2310   }
copy(Collector & c) const2311   FlowObj *copy(Collector &c) const {
2312     return new (c) TableCellFlowObj(*this);
2313   }
hasNonInheritedC(const Identifier * ident) const2314   bool hasNonInheritedC(const Identifier *ident) const {
2315     Identifier::SyntacticKey key;
2316     if (ident->syntacticKey(key)) {
2317       switch (key) {
2318       case Identifier::keyNRowsSpanned:
2319 	return 1;
2320       default:
2321 	break;
2322       }
2323     }
2324     return 0;
2325   }
hasPseudoNonInheritedC(const Identifier * ident) const2326   bool hasPseudoNonInheritedC(const Identifier *ident) const {
2327     Identifier::SyntacticKey key;
2328     if (ident->syntacticKey(key)) {
2329       switch (key) {
2330       case Identifier::keyColumnNumber:
2331       case Identifier::keyNColumnsSpanned:
2332       case Identifier::keyIsStartsRow:
2333       case Identifier::keyIsEndsRow:
2334 	return 1;
2335       default:
2336 	break;
2337       }
2338     }
2339     return 0;
2340   }
setNonInheritedC(const Identifier * ident,ELObj * obj,const Location & loc,Interpreter & interp)2341   void setNonInheritedC(const Identifier *ident, ELObj *obj,
2342   			const Location &loc, Interpreter &interp) {
2343     Identifier::SyntacticKey key;
2344     if (ident->syntacticKey(key)) {
2345       switch (key) {
2346       case Identifier::keyIsStartsRow:
2347         interp.convertBooleanC(obj, ident, loc, nic_->startsRow);
2348 	return;
2349       case Identifier::keyIsEndsRow:
2350         interp.convertBooleanC(obj, ident, loc, nic_->endsRow);
2351 	return;
2352       case Identifier::keyColumnNumber:
2353       case Identifier::keyNColumnsSpanned:
2354       case Identifier::keyNRowsSpanned:
2355 	{
2356 	  long n;
2357           if (!interp.convertIntegerC(obj, ident, loc, n))
2358 	    return;
2359           if (n <= 0) {
2360 	    interp.setNextLocation(loc);
2361 	    interp.message(InterpreterMessages::invalidCharacteristicValue,
2362   		 	   StringMessageArg(ident->name()));
2363 	    return;
2364           }
2365 	  if (key == Identifier::keyColumnNumber) {
2366 	    nic_->columnIndex = n - 1;
2367 	    nic_->hasColumnNumber = 1;
2368 	  }
2369 	  else if (key == Identifier::keyNColumnsSpanned)
2370 	    nic_->nColumnsSpanned = n;
2371 	  else
2372 	    nic_->nRowsSpanned = n;
2373 	}
2374 	return;
2375       default:
2376 	break;
2377       }
2378     }
2379     CANNOT_HAPPEN();
2380   }
2381 private:
border(const ConstPtr<InheritedC> & ic,void (FOTBuilder::* setter)(),ProcessContext & context)2382   void border(const ConstPtr<InheritedC> &ic, void (FOTBuilder::*setter)(),
2383 	      ProcessContext &context) {
2384     Interpreter &interp = *context.vm().interp;
2385     Vector<size_t> dep;
2386     ELObj *obj = context.currentStyleStack().actual(ic, interp, dep);
2387     StyleObj *style;
2388     if (obj == interp.makeFalse())
2389       style = interp.borderFalseStyle();
2390     else if (obj == interp.makeTrue())
2391       style = interp.borderTrueStyle();
2392     else {
2393       SosofoObj *sosofo = obj->asSosofo();
2394       if (!sosofo || !sosofo->tableBorderStyle(style))
2395 	style = 0;
2396     }
2397     FOTBuilder &fotb = context.currentFOTBuilder();
2398     if (style)
2399       context.currentStyleStack().push(style, context.vm(), fotb);
2400     (fotb.*setter)();
2401     if (style)
2402       context.currentStyleStack().pop();
2403   }
2404   Owner<NIC> nic_;
2405 };
2406 
2407 class TableBorderFlowObj : public FlowObj {
2408 public:
TableBorderFlowObj()2409   TableBorderFlowObj() { }
process(ProcessContext &)2410   void process(ProcessContext &) { }
processInner(ProcessContext &)2411   void processInner(ProcessContext &) { }
tableBorderStyle(StyleObj * & style)2412   bool tableBorderStyle(StyleObj *&style) {
2413     style = style_;
2414     return 1;
2415   }
copy(Collector & c) const2416   FlowObj *copy(Collector &c) const {
2417     return new (c) TableBorderFlowObj(*this);
2418   }
2419 };
2420 
2421 
startTable()2422 void ProcessContext::startTable()
2423 {
2424   tableStack_.insert(new Table);
2425 }
2426 
endTable()2427 void ProcessContext::endTable()
2428 {
2429   coverSpannedRows();
2430   delete tableStack_.get();
2431 }
2432 
coverSpannedRows()2433 void ProcessContext::coverSpannedRows()
2434 {
2435   // Generate empty cells to cover any remaining vertical spans
2436   Table *table = tableStack_.head();
2437   if (!table)
2438     return;
2439   unsigned n = 0;
2440   for (size_t i = 0; i < table->covered.size(); i++)
2441     if (table->covered[i] > n)
2442       n = table->covered[i];
2443   for (; n > 0; n--) {
2444     SosofoObj *content = new (*vm().interp) EmptySosofoObj;
2445     ELObjDynamicRoot protect(*vm().interp, content);
2446     TableRowFlowObj *row = new (*vm().interp) TableRowFlowObj;
2447     row->setContent(content);
2448     protect = row;
2449     row->process(*this);
2450   }
2451 }
2452 
startTablePart()2453 void ProcessContext::startTablePart()
2454 {
2455   Table *table = tableStack_.head();
2456   if (table) {
2457     table->currentColumn = 0;
2458     table->rowStyle = 0;
2459     table->columnStyles.clear();
2460     table->covered.clear();
2461     table->nColumns = 0;
2462   }
2463 }
2464 
endTablePart()2465 void ProcessContext::endTablePart()
2466 {
2467   coverSpannedRows();
2468 }
2469 
addTableColumn(unsigned columnIndex,unsigned span,StyleObj * style)2470 void ProcessContext::addTableColumn(unsigned columnIndex, unsigned span, StyleObj *style)
2471 {
2472   Table *table = tableStack_.head();
2473   if (table) {
2474     table->currentColumn = columnIndex + span;
2475     if (columnIndex >= table->columnStyles.size())
2476       table->columnStyles.resize(columnIndex + 1);
2477     Vector<StyleObj *> &tem = table->columnStyles[columnIndex];
2478     if (span > 0) {
2479       while (tem.size() < span)
2480 	tem.push_back((StyleObj *)0);
2481       tem[span - 1] = style;
2482     }
2483   }
2484 }
2485 
currentTableColumn()2486 unsigned ProcessContext::currentTableColumn()
2487 {
2488   Table *table = tableStack_.head();
2489   if (table)
2490     return table->currentColumn;
2491   return 0;
2492 }
2493 
noteTableCell(unsigned colIndex,unsigned colSpan,unsigned rowSpan)2494 void ProcessContext::noteTableCell(unsigned colIndex, unsigned colSpan, unsigned rowSpan)
2495 {
2496   Table *table = tableStack_.head();
2497   if (!table)
2498     return;
2499   table->currentColumn = colIndex + colSpan;
2500   Vector<unsigned> &covered = table->covered;
2501   for (size_t i = covered.size(); i < colIndex + colSpan; i++)
2502     covered.push_back(0);
2503   for (size_t i = 0; i < colSpan; i++)
2504     covered[colIndex + i] = rowSpan;
2505   if (colIndex + colSpan > table->nColumns)
2506     table->nColumns = colIndex + colSpan;
2507 }
2508 
tableColumnStyle(unsigned columnIndex,unsigned span)2509 StyleObj *ProcessContext::tableColumnStyle(unsigned columnIndex, unsigned span)
2510 {
2511   Table *table = tableStack_.head();
2512   if (table) {
2513     if (columnIndex < table->columnStyles.size()) {
2514       Vector<StyleObj *> &tem = table->columnStyles[columnIndex];
2515       if (span > 0 && span <= tem.size())
2516 	return tem[span - 1];
2517     }
2518   }
2519   return 0;
2520 }
2521 
tableRowStyle()2522 StyleObj *ProcessContext::tableRowStyle()
2523 {
2524   Table *table = tableStack_.head();
2525   if (table)
2526     return table->rowStyle;
2527   return 0;
2528 }
2529 
startTableRow(StyleObj * style)2530 void ProcessContext::startTableRow(StyleObj *style)
2531 {
2532   Table *table = tableStack_.head();
2533   if (table) {
2534     table->rowStyle = style;
2535     table->currentColumn = 0;
2536     table->inTableRow = 1;
2537     table->rowConnectableLevel = connectionStack_.head()->connectableLevel;
2538   }
2539   currentFOTBuilder().startTableRow();
2540 }
2541 
endTableRow()2542 void ProcessContext::endTableRow()
2543 {
2544   Table *table = tableStack_.head();
2545   if (table) {
2546     // Fill in blank cells
2547     Vector<unsigned> &covered = table->covered;
2548     for (size_t i = 0; i < table->nColumns + 1; i++) {
2549       if (i >= covered.size() || !covered[i]) {
2550 	table->currentColumn = i;
2551 	SosofoObj *content = new (*vm().interp) EmptySosofoObj;
2552 	ELObjDynamicRoot protect(*vm().interp, content);
2553 	// The last cell is a dummy one
2554 	TableCellFlowObj *cell = new (*vm().interp) TableCellFlowObj(i >= table->nColumns);
2555 	cell->setContent(content);
2556 	protect = cell;
2557 	cell->process(*this);
2558       }
2559       // cell->process() will cover it
2560       if (i < table->nColumns)
2561 	covered[i] -= 1;
2562     }
2563     table->inTableRow = 0;
2564   }
2565   currentFOTBuilder().endTableRow();
2566 }
2567 
inTableRow()2568 bool ProcessContext::inTableRow()
2569 {
2570   Table *table = tableStack_.head();
2571   if (table)
2572     return table->inTableRow;
2573   return 0;
2574 }
2575 
Table()2576 ProcessContext::Table::Table()
2577 : rowStyle(0), currentColumn(0), inTableRow(0), nColumns(0)
2578 {
2579 }
2580 
2581 
2582 // Flow object classes declared with declare-flow-object-class
2583 // that we don't know about are assumed to have one principal port
2584 // and accept any non-inherited characteristic.
2585 
2586 class UnknownFlowObj : public CompoundFlowObj {
2587 public:
UnknownFlowObj()2588   UnknownFlowObj() { }
copy(Collector & c) const2589   FlowObj *copy(Collector &c) const {
2590     return new (c) UnknownFlowObj(*this);
2591   }
setNonInheritedC(const Identifier *,ELObj *,const Location &,Interpreter &)2592   void setNonInheritedC(const Identifier *, ELObj *,
2593 			const Location &, Interpreter &) { }
hasNonInheritedC(const Identifier * ident) const2594   bool hasNonInheritedC(const Identifier *ident) const {
2595     Identifier::SyntacticKey syn;
2596     if (ident->syntacticKey(syn)
2597         && (syn == Identifier::keyLabel || syn == Identifier::keyContentMap))
2598       return 0;
2599     if (!ident->inheritedC().isNull())
2600       return 0;
2601     return 1;
2602   }
2603 };
2604 
2605 class FormattingInstructionFlowObj : public FlowObj {
2606 public:
operator new(size_t,Collector & c)2607   void *operator new(size_t, Collector &c) {
2608     return c.allocateObject(1);
2609   }
FormattingInstructionFlowObj()2610   FormattingInstructionFlowObj() { }
processInner(ProcessContext & context)2611   void processInner(ProcessContext &context) {
2612     context.currentFOTBuilder().formattingInstruction(data_);
2613   }
copy(Collector & c) const2614   FlowObj *copy(Collector &c) const {
2615     return new (c) FormattingInstructionFlowObj(*this);
2616   }
setNonInheritedC(const Identifier * ident,ELObj * obj,const Location & loc,Interpreter & interp)2617   void setNonInheritedC(const Identifier *ident, ELObj *obj,
2618 			const Location &loc, Interpreter &interp) {
2619     interp.convertStringC(obj, ident, loc, data_);
2620   }
hasNonInheritedC(const Identifier * ident) const2621   bool hasNonInheritedC(const Identifier *ident) const {
2622     Identifier::SyntacticKey key;
2623     return ident->syntacticKey(key) && key == Identifier::keyData;
2624   }
2625 private:
2626   StringC data_;
2627 };
2628 
2629 class ELObjExtensionFlowObjValue : public FOTBuilder::ExtensionFlowObj::Value {
2630 public:
ELObjExtensionFlowObjValue(const Identifier * ident,ELObj * obj,const Location & loc,Interpreter & interp)2631   ELObjExtensionFlowObjValue(const Identifier *ident, ELObj *obj,
2632 			     const Location &loc, Interpreter &interp)
2633   : ident_(ident), obj_(obj), loc_(&loc), interp_(&interp) { }
convertString(StringC & result) const2634   bool convertString(StringC &result) const {
2635     return interp_->convertStringC(obj_, ident_, *loc_, result);
2636   }
convertStringPairList(Vector<StringC> & v) const2637   bool convertStringPairList(Vector<StringC> &v) const {
2638     ELObj *obj = obj_;
2639     for (;;) {
2640       if (obj->isNil())
2641 	return 1;
2642       PairObj *pair = obj->asPair();
2643       if (!pair)
2644 	break;
2645       obj = pair->cdr();
2646       PairObj *att = pair->car()->asPair();
2647       if (!att)
2648 	break;
2649       const Char *s;
2650       size_t n;
2651       if (!att->car()->stringData(s, n))
2652 	break;
2653       v.resize(v.size() + 1);
2654       v.back().assign(s, n);
2655       att = att->cdr()->asPair();
2656       if (!att || !att->car()->stringData(s, n) || !att->cdr()->isNil()) {
2657 	v.resize(v.size() - 1);
2658 	break;
2659       }
2660       v.resize(v.size() + 1);
2661       v.back().assign(s, n);
2662     }
2663     interp_->setNextLocation(*loc_);
2664     interp_->message(InterpreterMessages::invalidCharacteristicValue,
2665 		     StringMessageArg(ident_->name()));
2666     return 0;
2667   }
convertStringList(Vector<StringC> & v) const2668   bool convertStringList(Vector<StringC> &v) const {
2669     ELObj *obj = obj_;
2670     for (;;) {
2671       if (obj->isNil())
2672         return 1;
2673       PairObj *pair = obj->asPair();
2674       if (!pair)
2675         break;
2676       const Char *s;
2677       size_t n;
2678       if (!pair->car()->stringData(s, n))
2679         break;
2680       v.resize(v.size() + 1);
2681       v.back().assign(s, n);
2682       obj = pair->cdr();
2683     }
2684     interp_->setNextLocation(*loc_);
2685     interp_->message(InterpreterMessages::invalidCharacteristicValue,
2686                      StringMessageArg(ident_->name()));
2687     return 0;
2688   }
convertBoolean(bool & result) const2689   bool convertBoolean(bool &result) const {
2690     return interp_->convertBooleanC(obj_, ident_, *loc_, result);
2691   }
2692 private:
2693   ELObj *obj_;
2694   const Identifier *ident_;
2695   const Location *loc_;
2696   Interpreter *interp_;
2697 };
2698 
2699 class ExtensionFlowObj : public FlowObj {
2700 public:
operator new(size_t,Collector & c)2701   void *operator new(size_t, Collector &c) {
2702     return c.allocateObject(1);
2703   }
2704   ExtensionFlowObj(const FOTBuilder::ExtensionFlowObj &);
2705   ExtensionFlowObj(const ExtensionFlowObj &);
2706   void processInner(ProcessContext &);
2707   FlowObj *copy(Collector &) const;
2708   bool hasNonInheritedC(const Identifier *) const;
2709   void setNonInheritedC(const Identifier *, ELObj *,
2710 			const Location &, Interpreter &);
2711 private:
2712   Owner<FOTBuilder::ExtensionFlowObj> fo_;
2713 };
2714 
ExtensionFlowObj(const FOTBuilder::ExtensionFlowObj & fo)2715 ExtensionFlowObj::ExtensionFlowObj(const FOTBuilder::ExtensionFlowObj &fo)
2716 : fo_(fo.copy())
2717 {
2718 }
2719 
ExtensionFlowObj(const ExtensionFlowObj & fo)2720 ExtensionFlowObj::ExtensionFlowObj(const ExtensionFlowObj &fo)
2721 : FlowObj(fo), fo_(fo.fo_->copy())
2722 {
2723 }
2724 
processInner(ProcessContext & context)2725 void ExtensionFlowObj::processInner(ProcessContext &context)
2726 {
2727   context.currentFOTBuilder().extension(*fo_, context.vm().currentNode);
2728 }
2729 
setNonInheritedC(const Identifier * ident,ELObj * obj,const Location & loc,Interpreter & interp)2730 void ExtensionFlowObj::setNonInheritedC(const Identifier *ident,
2731 					ELObj *obj,
2732 					const Location &loc,
2733 					Interpreter &interp)
2734 {
2735   fo_->setNIC(ident->name(), ELObjExtensionFlowObjValue(ident, obj, loc, interp));
2736 }
2737 
hasNonInheritedC(const Identifier * ident) const2738 bool ExtensionFlowObj::hasNonInheritedC(const Identifier *ident) const
2739 {
2740   return fo_->hasNIC(ident->name());
2741 }
2742 
copy(Collector & c) const2743 FlowObj *ExtensionFlowObj::copy(Collector &c) const
2744 {
2745   return new (c) ExtensionFlowObj(*this);
2746 }
2747 
2748 class CompoundExtensionFlowObj : public CompoundFlowObj {
2749 public:
operator new(size_t,Collector & c)2750   void *operator new(size_t, Collector &c) {
2751     return c.allocateObject(1);
2752   }
2753   CompoundExtensionFlowObj(const FOTBuilder::CompoundExtensionFlowObj &);
2754   CompoundExtensionFlowObj(const CompoundExtensionFlowObj &);
2755   void processInner(ProcessContext &);
2756   FlowObj *copy(Collector &) const;
2757   bool hasNonInheritedC(const Identifier *) const;
2758   void setNonInheritedC(const Identifier *, ELObj *,
2759 			const Location &, Interpreter &);
2760 private:
2761   Owner<FOTBuilder::CompoundExtensionFlowObj> fo_;
2762 };
2763 
CompoundExtensionFlowObj(const FOTBuilder::CompoundExtensionFlowObj & fo)2764 CompoundExtensionFlowObj::CompoundExtensionFlowObj(const FOTBuilder::CompoundExtensionFlowObj &fo)
2765 : fo_(fo.copy()->asCompoundExtensionFlowObj())
2766 {
2767 }
2768 
CompoundExtensionFlowObj(const CompoundExtensionFlowObj & fo)2769 CompoundExtensionFlowObj::CompoundExtensionFlowObj(const CompoundExtensionFlowObj &fo)
2770 : CompoundFlowObj(fo), fo_(fo.fo_->copy()->asCompoundExtensionFlowObj())
2771 {
2772 }
2773 
processInner(ProcessContext & context)2774 void CompoundExtensionFlowObj::processInner(ProcessContext &context)
2775 {
2776   FOTBuilder &fotb = context.currentFOTBuilder();
2777   Vector<StringC> portNames;
2778   fo_->portNames(portNames);
2779   Vector<FOTBuilder *> fotbs(portNames.size());
2780   fotb.startExtension(*fo_, context.vm().currentNode, fotbs);
2781   if (portNames.size()) {
2782     Vector<SymbolObj *> portSyms(portNames.size());
2783     for (size_t i = 0; i < portSyms.size(); i++)
2784       portSyms[i] = context.vm().interp->makeSymbol(portNames[i]);
2785     context.pushPorts(fo_->hasPrincipalPort(), portSyms, fotbs);
2786     CompoundFlowObj::processInner(context);
2787     context.popPorts();
2788   }
2789   else
2790     CompoundFlowObj::processInner(context);
2791   fotb.endExtension(*fo_);
2792 }
2793 
setNonInheritedC(const Identifier * ident,ELObj * obj,const Location & loc,Interpreter & interp)2794 void CompoundExtensionFlowObj::setNonInheritedC(const Identifier *ident,
2795 					        ELObj *obj,
2796 						const Location &loc,
2797 						Interpreter &interp)
2798 {
2799   fo_->setNIC(ident->name(), ELObjExtensionFlowObjValue(ident, obj, loc, interp));
2800 }
2801 
hasNonInheritedC(const Identifier * ident) const2802 bool CompoundExtensionFlowObj::hasNonInheritedC(const Identifier *ident) const
2803 {
2804   return fo_->hasNIC(ident->name());
2805 }
2806 
copy(Collector & c) const2807 FlowObj *CompoundExtensionFlowObj::copy(Collector &c) const
2808 {
2809   return new (c) CompoundExtensionFlowObj(*this);
2810 }
2811 
2812 #define FLOW_OBJ(name, string) \
2813 { FlowObj *tem = new (*this) name; \
2814   lookup(makeStringC(string))->setFlowObj(tem); \
2815   makePermanent(tem); }
2816 
installFlowObjs()2817 void Interpreter::installFlowObjs()
2818 {
2819   FLOW_OBJ(SequenceFlowObj, "sequence");
2820   FLOW_OBJ(DisplayGroupFlowObj, "display-group");
2821   FLOW_OBJ(ParagraphFlowObj, "paragraph");
2822   FLOW_OBJ(ParagraphBreakFlowObj, "paragraph-break");
2823   FLOW_OBJ(LineFieldFlowObj, "line-field");
2824   FLOW_OBJ(ScoreFlowObj, "score");
2825   FLOW_OBJ(ExternalGraphicFlowObj, "external-graphic");
2826   FLOW_OBJ(RuleFlowObj, "rule");
2827   FLOW_OBJ(LeaderFlowObj, "leader");
2828   FLOW_OBJ(CharacterFlowObj, "character");
2829   FLOW_OBJ(BoxFlowObj, "box");
2830   FLOW_OBJ(AlignmentPointFlowObj, "alignment-point");
2831   FLOW_OBJ(SidelineFlowObj, "sideline");
2832   // simple-page
2833   FLOW_OBJ(SimplePageSequenceFlowObj, "simple-page-sequence");
2834   // tables
2835   FLOW_OBJ(TableFlowObj, "table");
2836   FLOW_OBJ(TablePartFlowObj, "table-part");
2837   FLOW_OBJ(TableColumnFlowObj, "table-column");
2838   FLOW_OBJ(TableRowFlowObj, "table-row");
2839   FLOW_OBJ(TableCellFlowObj, "table-cell");
2840   FLOW_OBJ(TableBorderFlowObj, "table-border");
2841   // online
2842   FLOW_OBJ(LinkFlowObj, "link");
2843   FLOW_OBJ(ScrollFlowObj, "scroll");
2844   FLOW_OBJ(MarginaliaFlowObj, "marginalia");
2845   FLOW_OBJ(MultiModeFlowObj, "multi-mode");
2846   // math
2847   FLOW_OBJ(MathSequenceFlowObj, "math-sequence");
2848   FLOW_OBJ(FractionFlowObj, "fraction");
2849   FLOW_OBJ(UnmathFlowObj, "unmath");
2850   FLOW_OBJ(SuperscriptFlowObj, "superscript");
2851   FLOW_OBJ(SubscriptFlowObj, "subscript");
2852   FLOW_OBJ(ScriptFlowObj, "script");
2853   FLOW_OBJ(MarkFlowObj, "mark");
2854   FLOW_OBJ(FenceFlowObj, "fence");
2855   FLOW_OBJ(RadicalFlowObj, "radical");
2856   FLOW_OBJ(MathOperatorFlowObj, "math-operator");
2857   FLOW_OBJ(GridFlowObj, "grid");
2858   FLOW_OBJ(GridCellFlowObj, "grid-cell");
2859 }
2860 
installExtensionFlowObjectClass(Identifier * ident,const StringC & pubid,const Location & loc)2861 void Interpreter::installExtensionFlowObjectClass(Identifier *ident,
2862 						  const StringC &pubid,
2863 						  const Location &loc)
2864 {
2865   FlowObj *tem = 0;
2866   if (extensionTable_) {
2867     for (const FOTBuilder::Extension *ep = extensionTable_; ep->pubid; ep++) {
2868       if (pubid == ep->pubid) {
2869 	if (ep->flowObj) {
2870 	  const FOTBuilder::CompoundExtensionFlowObj *cFlowObj
2871 	    = ep->flowObj->asCompoundExtensionFlowObj();
2872 	  if (cFlowObj)
2873 	    tem = new (*this) CompoundExtensionFlowObj(*cFlowObj);
2874 	  else
2875 	    tem = new (*this) ExtensionFlowObj(*ep->flowObj);
2876 	}
2877 	break;
2878       }
2879     }
2880   }
2881   if (!tem) {
2882     if (pubid
2883         == "UNREGISTERED::James Clark//Flow Object Class::"
2884            "formatting-instruction")
2885       tem = new (*this) FormattingInstructionFlowObj;
2886     else
2887       tem = new (*this) UnknownFlowObj;
2888   }
2889   makePermanent(tem);
2890   ident->setFlowObj(tem, currentPartIndex(), loc);
2891 }
2892 
2893 #ifdef DSSSL_NAMESPACE
2894 }
2895 #endif
2896 
2897 #include "FlowObj_inst.cxx"
2898