1 // Copyright (c) 1996 James Clark
2 // See the file copying.txt for copying permission.
5 #include "ProcessContext.h"
6 #include "Interpreter.h"
7 #include "InterpreterMessages.h"
10 #include "IListIter.h"
12 #ifdef DSSSL_NAMESPACE
13 namespace DSSSL_NAMESPACE {
16 ProcessContext::ProcessContext(Interpreter &interp, FOTBuilder &fotb)
17 : Collector::DynamicRoot(interp), vm_(interp), flowObjLevel_(0), havePageType_(0), connectableStackLevel_(0)
19 connectionStack_.insert(new Connection(&fotb));
22 void ProcessContext::process(const NodePtr &node)
24 Interpreter &interp = *vm_.interp;
25 StyleObj *style = interp.initialStyle();
27 currentStyleStack().push(style, vm(), currentFOTBuilder());
28 currentFOTBuilder().startSequence();
30 processNode(node, interp.initialProcessingMode());
32 currentFOTBuilder().endSequence();
33 currentStyleStack().pop();
37 void ProcessContext::processNodeSafe(const NodePtr &nodePtr,
38 const ProcessingMode *processingMode,
41 unsigned long elementIndex;
42 if (nodePtr->elementIndex(elementIndex) == accessOK) {
43 unsigned groveIndex = nodePtr->groveIndex();
44 for (size_t i = 0; i < nodeStack_.size(); i++) {
45 const NodeStackEntry &nse = nodeStack_[i];
46 if (nse.elementIndex == elementIndex
47 && nse.groveIndex == groveIndex
48 && nse.processingMode == processingMode) {
49 vm_.interp->setNodeLocation(nodePtr);
50 vm_.interp->message(InterpreterMessages::processNodeLoop);
54 nodeStack_.resize(nodeStack_.size() + 1);
55 NodeStackEntry &e = nodeStack_.back();
56 e.elementIndex = elementIndex;
57 e.groveIndex = groveIndex;
58 e.processingMode = processingMode;
59 processNode(nodePtr, processingMode, chunk);
60 nodeStack_.resize(nodeStack_.size() - 1);
63 processNode(nodePtr, processingMode, chunk);
66 void ProcessContext::processNode(const NodePtr &nodePtr,
67 const ProcessingMode *processingMode,
70 ASSERT(processingMode != 0);
72 if (nodePtr->charChunk(*vm_.interp, str) == accessOK)
73 currentFOTBuilder().charactersFromNode(nodePtr, str.data(), chunk ? str.size() : 1);
75 EvalContext::CurrentNodeSetter cns(nodePtr, processingMode, vm());
76 ProcessingMode::Specificity saveSpecificity(matchSpecificity_);
77 matchSpecificity_ = ProcessingMode::Specificity();
79 currentFOTBuilder().startNode(nodePtr, processingMode->name());
81 const ProcessingMode::Rule *rule
82 = vm().processingMode->findMatch(nodePtr, *vm_.interp, *vm_.interp,
86 currentStyleStack().pushEnd(vm(), currentFOTBuilder());
87 currentFOTBuilder().startSequence();
89 processChildren(processingMode);
92 if (!matchSpecificity_.isStyle()) {
95 rule->action().get(insn, sosofoObj);
97 currentStyleStack().pushEnd(vm(), currentFOTBuilder());
98 currentFOTBuilder().startSequence();
101 sosofoObj->process(*this);
103 ELObj *obj = vm().eval(insn.pointer());
104 if (vm_.interp->isError(obj)) {
105 if (processingMode->name().size() == 0)
106 processChildren(processingMode);
109 ELObjDynamicRoot protect(*vm_.interp, obj);
110 ((SosofoObj *)obj)->process(*this);
115 SosofoObj *sosofoObj;
117 rule->action().get(insn, sosofoObj);
118 ELObj *obj = vm().eval(insn.pointer());
119 if (!vm_.interp->isError(obj)) {
121 currentStyleStack().pushStart();
124 currentStyleStack().pushContinue((StyleObj *)obj, rule, nodePtr, vm_.interp);
128 currentFOTBuilder().endSequence();
129 currentStyleStack().pop();
131 currentFOTBuilder().endNode();
132 matchSpecificity_ = saveSpecificity;
136 void ProcessContext::nextMatch(StyleObj *overridingStyle)
138 ProcessingMode::Specificity saveSpecificity(matchSpecificity_);
139 StyleObj *saveOverridingStyle = vm().overridingStyle;
141 vm().overridingStyle = overridingStyle;
142 const ProcessingMode::Rule *rule
143 = vm().processingMode->findMatch(vm().currentNode, *vm_.interp, *vm_.interp,
146 ASSERT(!matchSpecificity_.isStyle());
147 SosofoObj *sosofoObj;
149 rule->action().get(insn, sosofoObj);
151 sosofoObj->process(*this);
153 ELObj *obj = vm().eval(insn.pointer());
154 if (vm_.interp->isError(obj))
155 processChildren(vm().processingMode);
157 ELObjDynamicRoot protect(*vm_.interp, obj);
158 ((SosofoObj *)obj)->process(*this);
163 processChildren(vm().processingMode);
164 vm().overridingStyle = saveOverridingStyle;
165 matchSpecificity_ = saveSpecificity;
168 void ProcessContext::processChildren(const ProcessingMode *processingMode)
170 if (vm().currentNode.assignFirstChild() == accessOK) {
172 processNode(vm().currentNode, processingMode);
173 } while (vm().currentNode.assignNextChunkSibling() == accessOK);
175 else if (vm().currentNode->getDocumentElement(vm().currentNode) == accessOK)
176 processNode(vm().currentNode, processingMode);
180 bool isWhiteSpace(Char c, Interpreter &interp)
184 interp.makeStringC("input-whitespace?"), c, Location(), 0)->isTrue();
188 bool onlyWhiteSpaceFollows(const NodePtr &node, Interpreter &interp)
191 if (node->nextChunkSibling(tem) == accessOK) {
194 if (tem->charChunk(interp, str) == accessOK) {
195 for (size_t i = 0; i < str.size(); i++)
196 if (!isWhiteSpace(str[i], interp))
199 else if (tem->getGi(str) == accessOK)
201 } while (tem.assignNextChunkSibling() == accessOK);
206 void ProcessContext::processChildrenTrim(const ProcessingMode *processingMode)
208 if (vm().currentNode.assignFirstChild() == accessOK) {
211 NodePtr curNode = vm().currentNode;
213 if (curNode->charChunk(*vm().interp, str) == accessOK) {
215 const Char *s = str.data();
216 size_t n = str.size();
217 for (; n > 0; n--, s++) {
218 if (!isWhiteSpace(*s, *vm().interp))
225 if (s != str.data()) {
226 if (curNode->followSiblingRef(str.size() - (n + 1), curNode) != accessOK)
233 if (isWhiteSpace(str[str.size() - 1], *vm().interp)
234 && onlyWhiteSpaceFollows(curNode, *vm().interp)) {
235 for (size_t n = str.size() - 1; n > 0; n--) {
236 if (!isWhiteSpace(str[n - 1], *vm().interp)) {
237 currentFOTBuilder().charactersFromNode(curNode, str.data(), n);
243 currentFOTBuilder().charactersFromNode(curNode, str.data(), str.size());
247 if (atStart && vm().currentNode->getGi(str) == accessOK)
249 processNode(vm().currentNode, processingMode);
251 } while (vm().currentNode.assignNextChunkSibling() == accessOK);
253 else if (vm().currentNode->getDocumentElement(vm().currentNode) == accessOK)
254 processNode(vm().currentNode, processingMode);
257 void ProcessContext::startConnection(SymbolObj *label, const Location &loc)
259 unsigned connLevel = connectableStackLevel_;
260 for (IListIter<Connectable> iter(connectableStack_); !iter.done(); iter.next(), --connLevel) {
261 Connectable *conn = iter.cur();
262 for (size_t i = 0; i < conn->ports.size(); i++) {
263 Port &port = conn->ports[i];
264 for (size_t j = 0; j < port.labels.size(); j++)
265 if (port.labels[j] == label) {
266 restoreConnection(connLevel, i);
270 for (size_t i = 0; i < conn->principalPortLabels.size(); i++)
271 if (conn->principalPortLabels[i] == label) {
272 restoreConnection(connLevel, size_t(-1));
276 vm().interp->setNextLocation(loc);
277 vm().interp->message(InterpreterMessages::badConnection,
278 StringMessageArg(*label->name()));
279 connectionStack_.head()->nBadFollow++;
283 void ProcessContext::endConnection()
285 if (inTableRow() && tableStack_.head()->rowConnectableLevel == connectableStackLevel_)
287 if (connectionStack_.head()->nBadFollow > 0)
288 connectionStack_.head()->nBadFollow--;
290 currentFOTBuilder().endNode();
291 Port *port = connectionStack_.head()->port;
292 if (port && --(port->connected) == 0) {
293 while (!port->saveQueue.empty()) {
294 SaveFOTBuilder *saved = port->saveQueue.get();
295 saved->emit(*port->fotb);
299 delete connectionStack_.get();
303 void ProcessContext::restoreConnection(unsigned connectableLevel, size_t portIndex)
305 unsigned connLevel = connectableStackLevel_;
306 IListIter<Connectable> iter(connectableStack_);
307 for (; connLevel != connectableLevel; iter.next(), --connLevel)
309 Connectable *conn = iter.cur();
310 if (portIndex != size_t(-1)) {
311 Port &port = conn->ports[portIndex];
312 Connection *c = new Connection(conn->styleStack, &port, connLevel);
313 if (port.connected) {
315 SaveFOTBuilder *save = new SaveFOTBuilder(vm().currentNode,
316 vm().processingMode->name());
318 port.saveQueue.append(save);
324 connectionStack_.insert(c);
325 currentFOTBuilder().startNode(vm().currentNode,
326 vm().processingMode->name());
329 Connection *c = new Connection(conn->styleStack, 0, connLevel);
330 if (conn->flowObjLevel == flowObjLevel_) {
331 c->fotb = ¤tFOTBuilder();
334 SaveFOTBuilder *save = new SaveFOTBuilder(vm().currentNode,
335 vm().processingMode->name());
337 if (conn->flowObjLevel >= principalPortSaveQueues_.size())
338 principalPortSaveQueues_.resize(conn->flowObjLevel + 1);
339 principalPortSaveQueues_[conn->flowObjLevel].append(save);
341 connectionStack_.insert(c);
342 currentFOTBuilder().startNode(vm().currentNode,
343 vm().processingMode->name());
347 void ProcessContext::endFlowObj()
350 if (flowObjLevel_ < principalPortSaveQueues_.size()) {
351 IQueue<SaveFOTBuilder> &saveQueue = principalPortSaveQueues_[flowObjLevel_];
352 while (!saveQueue.empty()) {
353 SaveFOTBuilder *saved = saveQueue.get();
354 saved->emit(currentFOTBuilder());
361 ProcessContext::Connection::Connection(const StyleStack &s, Port *p, unsigned connLevel)
362 : styleStack(s), port(p), nBadFollow(0), connectableLevel(connLevel)
366 ProcessContext::Connection::Connection(FOTBuilder *f)
367 : fotb(f), port(0), nBadFollow(0), connectableLevel(0)
371 void ProcessContext::pushPorts(bool,
372 const Vector<SymbolObj *> &labels,
373 const Vector<FOTBuilder *> &fotbs)
375 Connectable *c = new Connectable(labels.size(), currentStyleStack(), flowObjLevel_);
376 connectableStack_.insert(c);
377 for (size_t i = 0; i < labels.size(); i++) {
378 c->ports[i].labels.push_back(labels[i]);
379 c->ports[i].fotb = fotbs[i];
381 connectableStackLevel_++;
382 // FIXME deal with !hasPrincipalPort
385 void ProcessContext::popPorts()
387 connectableStackLevel_--;
388 delete connectableStack_.get();
391 void ProcessContext::pushPrincipalPort(FOTBuilder* principalPort)
393 connectionStack_.insert(new Connection(principalPort));
396 void ProcessContext::popPrincipalPort()
398 delete connectionStack_.get();
401 void ProcessContext::startDiscardLabeled(SymbolObj *label)
404 Connectable *c = new Connectable(1, currentStyleStack(), flowObjLevel_);
405 connectableStack_.insert(c);
406 c->ports[0].labels.push_back(label);
407 c->ports[0].fotb = &ignoreFotb_;
410 void ProcessContext::endDiscardLabeled()
412 delete connectableStack_.get();
416 void ProcessContext::startMapContent(ELObj *contentMap, const Location &loc)
419 if (!connectableStack_.head() || connectableStack_.head()->flowObjLevel != flowObjLevel_)
420 connectableStack_.insert(new Connectable(0, currentStyleStack(), flowObjLevel_));
421 Connectable &conn = *connectableStack_.head();
422 Vector<SymbolObj *> portNames(conn.ports.size());
423 for (size_t i = 0; i < conn.ports.size(); i++) {
424 portNames[i] = conn.ports[i].labels[0];
425 conn.ports[i].labels.clear();
428 if (contentMap->isNil())
430 PairObj *tem = contentMap->asPair();
432 badContentMap(badFlag, loc);
435 ELObj *entry = tem->car();
436 contentMap = tem->cdr();
437 tem = entry->asPair();
439 SymbolObj *label = tem->car()->asSymbol();
441 // FIXME check if label already specified
442 tem = tem->cdr()->asPair();
444 SymbolObj *port = tem->car()->asSymbol();
446 for (size_t i = 0; i < portNames.size(); i++)
447 if (portNames[i] == port) {
448 conn.ports[i].labels.push_back(label);
453 vm().interp->setNextLocation(loc);
454 vm().interp->message(InterpreterMessages::contentMapBadPort,
455 StringMessageArg(*port->name()));
458 else if (tem->car() == vm().interp->makeFalse())
459 conn.principalPortLabels.push_back(label);
461 badContentMap(badFlag, loc);
462 if (!tem->cdr()->isNil())
463 badContentMap(badFlag, loc);
466 badContentMap(badFlag, loc);
469 badContentMap(badFlag, loc);
472 badContentMap(badFlag, loc);
476 void ProcessContext::endMapContent()
478 if (connectableStack_.head()->ports.size() == 0)
479 delete connectableStack_.get();
482 void ProcessContext::badContentMap(bool &badFlag, const Location &loc)
487 vm().interp->setNextLocation(loc);
488 vm().interp->message(InterpreterMessages::badContentMap);
491 ProcessContext::Connectable::Connectable(int nPorts, const StyleStack &ss, unsigned fol)
492 : ports(nPorts), styleStack(ss), flowObjLevel(fol)
496 ProcessContext::Port::Port()
497 : connected(0), fotb(0)
501 void ProcessContext::trace(Collector &c) const
503 for (IListIter<Connection> iter(connectionStack_); !iter.done(); iter.next())
504 iter.cur()->styleStack.trace(c);
505 for (IListIter<Connectable> iter(connectableStack_); !iter.done(); iter.next())
506 iter.cur()->styleStack.trace(c);
507 for (IListIter<Table> iter(tableStack_); !iter.done(); iter.next()) {
508 c.trace(iter.cur()->rowStyle);
509 Vector<Vector<StyleObj *> > &styles = iter.cur()->columnStyles;
510 for (size_t i = 0; i < styles.size(); i++)
511 for (size_t j = 0; j < styles[i].size(); j++)
512 c.trace(styles[i][j]);
515 SosofoObj *SosofoObj::asSosofo()
520 bool SosofoObj::tableBorderStyle(StyleObj *&)
525 bool SosofoObj::isRule()
530 bool SosofoObj::ruleStyle(ProcessContext &, StyleObj *&)
535 bool SosofoObj::isCharacter()
540 bool SosofoObj::characterStyle(ProcessContext &, StyleObj *&, FOTBuilder::CharacterNIC &)
545 AppendSosofoObj *AppendSosofoObj::asAppendSosofo()
550 void AppendSosofoObj::process(ProcessContext &context)
552 for (size_t i = 0; i < v_.size(); i++)
553 v_[i]->process(context);
556 void AppendSosofoObj::traceSubObjects(Collector &c) const
558 for (size_t i = 0; i < v_.size(); i++)
562 void LiteralSosofoObj::process(ProcessContext &context)
566 if (str_->stringData(s, n))
567 context.currentFOTBuilder().characters(s, n);
570 void LiteralSosofoObj::traceSubObjects(Collector &c) const
575 void ProcessChildrenSosofoObj::process(ProcessContext &context)
577 NodePtr node(context.vm().currentNode);
578 context.processChildren(mode_);
579 context.vm().currentNode = node;
582 void ProcessChildrenTrimSosofoObj::process(ProcessContext &context)
584 NodePtr node(context.vm().currentNode);
585 context.processChildrenTrim(mode_);
586 context.vm().currentNode = node;
589 NextMatchSosofoObj::NextMatchSosofoObj(StyleObj *style)
594 void NextMatchSosofoObj::process(ProcessContext &context)
596 context.nextMatch(style_);
599 void EmptySosofoObj::process(ProcessContext &)
604 ProcessNodeListSosofoObj::ProcessNodeListSosofoObj(NodeListObj *nodeList,
605 const ProcessingMode *mode)
606 : nodeList_(nodeList), mode_(mode)
611 void ProcessNodeListSosofoObj::process(ProcessContext &context)
613 NodeListObj *nl = nodeList_;
614 Interpreter &interp = *context.vm().interp;
615 ELObjDynamicRoot protect(interp, nl);
617 NodePtr node = nl->nodeListFirst(context.vm(), interp);
621 nl = nl->nodeListChunkRest(context.vm(), interp, chunk);
623 context.processNodeSafe(node, mode_, chunk);
627 void ProcessNodeListSosofoObj::traceSubObjects(Collector &c) const
632 ProcessNodeSosofoObj::ProcessNodeSosofoObj(const NodePtr &node, const ProcessingMode *mode)
633 : node_(node), mode_(mode)
637 void ProcessNodeSosofoObj::process(ProcessContext &context)
639 context.processNode(node_, mode_);
642 void CurrentNodePageNumberSosofoObj::process(ProcessContext &context)
644 context.currentFOTBuilder().currentNodePageNumber(node_);
647 void PageNumberSosofoObj::process(ProcessContext &context)
649 context.currentFOTBuilder().pageNumber();
652 SetNonInheritedCsSosofoObj
653 ::SetNonInheritedCsSosofoObj(FlowObj *flowObj, const InsnPtr &code, ELObj **display, const NodePtr &node)
654 : flowObj_(flowObj), code_(code), display_(display), node_(node)
659 SetNonInheritedCsSosofoObj::~SetNonInheritedCsSosofoObj()
664 ELObj *SetNonInheritedCsSosofoObj::resolve(ProcessContext &context)
666 VM &vm = context.vm();
667 EvalContext::CurrentNodeSetter cns(node_, 0, vm);
668 StyleStack *saveStyleStack = vm.styleStack;
669 vm.styleStack = &context.currentStyleStack();
670 unsigned saveSpecLevel = vm.specLevel;
671 vm.specLevel = vm.styleStack->level();
673 vm.actualDependencies = &dep;
674 ELObj *obj = vm.eval(code_.pointer(), display_, flowObj_->copy(*vm.interp));
675 vm.styleStack = saveStyleStack;
676 vm.specLevel = saveSpecLevel;
677 if (vm.interp->isError(obj))
682 void SetNonInheritedCsSosofoObj::process(ProcessContext &context)
684 context.startFlowObj();
686 flowObj_->pushStyle(context, flags);
687 ELObj *obj = resolve(context);
689 ELObjDynamicRoot protect(*context.vm().interp, obj);
690 ((FlowObj *)obj)->processInner(context);
692 flowObj_->popStyle(context, flags);
693 context.endFlowObj();
696 bool SetNonInheritedCsSosofoObj::isCharacter()
698 return flowObj_->isCharacter();
701 bool SetNonInheritedCsSosofoObj::isRule()
703 return flowObj_->isRule();
706 bool SetNonInheritedCsSosofoObj::characterStyle(ProcessContext &context, StyleObj *&style, FOTBuilder::CharacterNIC &nic)
708 ELObj *obj = resolve(context);
710 ELObjDynamicRoot protect(*context.vm().interp, obj);
711 return ((SosofoObj *)obj)->characterStyle(context, style, nic);
716 bool SetNonInheritedCsSosofoObj::ruleStyle(ProcessContext &context, StyleObj *&style)
718 ELObj *obj = resolve(context);
720 ELObjDynamicRoot protect(*context.vm().interp, obj);
721 return ((SosofoObj *)obj)->ruleStyle(context, style);
726 void SetNonInheritedCsSosofoObj::traceSubObjects(Collector &c) const
730 for (ELObj **p = display_; *p; p++)
734 LabelSosofoObj::LabelSosofoObj(SymbolObj *label, const Location &loc, SosofoObj *content)
735 : label_(label), locp_(new Location(loc)), content_(content)
740 void LabelSosofoObj::process(ProcessContext &context)
742 context.startConnection(label_, *locp_);
743 content_->process(context);
744 context.endConnection();
747 void LabelSosofoObj::traceSubObjects(Collector &c) const
749 // Symbols are permanent and don't need tracing.
753 ContentMapSosofoObj::ContentMapSosofoObj(ELObj *contentMap,
754 const Location *locp, SosofoObj *content)
755 : contentMap_(contentMap), locp_(locp), content_(content)
760 void ContentMapSosofoObj::process(ProcessContext &context)
762 context.startMapContent(contentMap_, *locp_);
763 content_->process(context);
764 context.endMapContent();
767 void ContentMapSosofoObj::traceSubObjects(Collector &c) const
769 c.trace(contentMap_);
773 DiscardLabeledSosofoObj::DiscardLabeledSosofoObj(SymbolObj *label, SosofoObj *content)
774 : label_(label), content_(content)
779 void DiscardLabeledSosofoObj::process(ProcessContext &context)
781 context.startDiscardLabeled(label_);
782 content_->process(context);
783 context.endDiscardLabeled();
786 void DiscardLabeledSosofoObj::traceSubObjects(Collector &c) const
791 PageTypeSosofoObj::PageTypeSosofoObj(unsigned pageTypeFlag, SosofoObj *match, SosofoObj *noMatch)
792 : pageTypeFlag_(pageTypeFlag), match_(match), noMatch_(noMatch)
797 void PageTypeSosofoObj::process(ProcessContext &context)
800 if (context.getPageType(pageType)) {
801 if (pageType & pageTypeFlag_)
802 match_->process(context);
804 noMatch_->process(context);
808 void PageTypeSosofoObj::traceSubObjects(Collector &c) const
814 #ifdef DSSSL_NAMESPACE