// Copyright (C) 2000-2007, Luca Padovani . // // This file is part of GtkMathView, a flexible, high-quality rendering // engine for MathML documents. // // GtkMathView is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // // GtkMathView is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program. If not, see . #ifndef __TemplateBuilder_hh__ #define __TemplateBuilder_hh__ #include #include "defs.h" #include "Attribute.hh" #include "MathML.hh" #include "MathMLTableContentFactory.hh" #include "MathMLNamespaceContext.hh" #include "MathMLAttributeSignatures.hh" #if GMV_ENABLE_BOXML #include "BoxML.hh" #include "BoxMLNamespaceContext.hh" #include "BoxMLAttributeSignatures.hh" #include "BoxMLMathMLAdapter.hh" #include "MathMLBoxMLAdapter.hh" #endif // GMV_ENABLE_BOXML #include "ValueConversion.hh" #include "AbstractLogger.hh" #include "HashMap.hh" #include "StringHash.hh" template class TemplateBuilder : public Builder { protected: template SmartPtr getElement(const typename Model::Element& el) const { if (SmartPtr elem = smart_cast(linkerAssoc(el))) return elem; else { { SmartPtr elem = ElementBuilder::type::create(ElementBuilder::getContext(*this)); linkerAdd(el, elem); return elem; } } } template SmartPtr updateElement(const typename Model::Element& el) const { SmartPtr elem = getElement(el); #if 0 std::cerr << "BEFORE" << " updateElement " << static_cast(elem) << " dirtyAttribute=" << elem->dirtyAttribute() << " dirtyAttributeP=" << elem->dirtyAttributeP() << " dirtyStructure=" << elem->dirtyStructure() << " dirtyLayout=" << elem->dirtyLayout() << std::endl; #endif if (elem->dirtyAttribute() || elem->dirtyAttributeP() || elem->dirtyStructure()) { ElementBuilder::begin(*this, el, elem); ElementBuilder::refine(*this, el, elem); ElementBuilder::construct(*this, el, elem); ElementBuilder::end(*this, el, elem); } #if 0 std::cerr << "AFTER" << " updateElement " << static_cast(elem) << " dirtyAttribute=" << elem->dirtyAttribute() << " dirtyAttributeP=" << elem->dirtyAttributeP() << " dirtyStructure=" << elem->dirtyStructure() << " dirtyLayout=" << elem->dirtyLayout() << std::endl; #endif return elem; } TemplateBuilder() { static struct { String tag; MathMLUpdateMethod update; } mathml_tab[] = { { "math", &TemplateBuilder::template updateElement }, { "mi", &TemplateBuilder::template updateElement }, { "mn", &TemplateBuilder::template updateElement }, { "mo", &TemplateBuilder::template updateElement }, { "mtext", &TemplateBuilder::template updateElement }, { "mspace", &TemplateBuilder::template updateElement }, { "ms", &TemplateBuilder::template updateElement }, { "mrow", &TemplateBuilder::template updateElement }, { "mfrac", &TemplateBuilder::template updateElement }, { "msqrt", &TemplateBuilder::template updateElement }, { "mroot", &TemplateBuilder::template updateElement }, { "mstyle", &TemplateBuilder::template updateElement }, { "merror", &TemplateBuilder::template updateElement }, { "mpadded", &TemplateBuilder::template updateElement }, { "mphantom", &TemplateBuilder::template updateElement }, { "mfenced", &TemplateBuilder::update_MathML_mfenced_Element }, { "msub", &TemplateBuilder::template updateElement }, { "msup", &TemplateBuilder::template updateElement }, { "msubsup", &TemplateBuilder::template updateElement }, { "munder", &TemplateBuilder::template updateElement }, { "mover", &TemplateBuilder::template updateElement }, { "munderover", &TemplateBuilder::template updateElement }, { "mmultiscripts", &TemplateBuilder::template updateElement }, { "mtable", &TemplateBuilder::template updateElement }, { "mtd", &TemplateBuilder::template updateElement }, { "maligngroup", &TemplateBuilder::template updateElement }, { "malignmark", &TemplateBuilder::template updateElement }, { "maction", &TemplateBuilder::template updateElement }, { "menclose", &TemplateBuilder::template updateElement }, { "semantics", &TemplateBuilder::update_MathML_semantics_Element }, { "", 0 } }; if (!mathmlMapInitialized) { for (unsigned i = 0; mathml_tab[i].update; i++) mathmlMap[mathml_tab[i].tag] = mathml_tab[i].update; mathmlMapInitialized = true; } #if GMV_ENABLE_BOXML static struct { String tag; BoxMLUpdateMethod update; } boxml_tab[] = { { "at", &TemplateBuilder::template updateElement }, { "layout", &TemplateBuilder::template updateElement }, { "h", &TemplateBuilder::template updateElement }, { "ink", &TemplateBuilder::template updateElement }, { "space", &TemplateBuilder::template updateElement }, { "text", &TemplateBuilder::template updateElement }, { "v", &TemplateBuilder::template updateElement }, { "hv", &TemplateBuilder::template updateElement }, { "hov", &TemplateBuilder::template updateElement }, { "box", &TemplateBuilder::template updateElement }, { "action", &TemplateBuilder::template updateElement }, { "obj", &TemplateBuilder::update_BoxML_obj_Element }, { "decor", &TemplateBuilder::template updateElement }, { "", 0 } }; if (!boxmlMapInitialized) { for (unsigned i = 0; boxml_tab[i].update; i++) boxmlMap[boxml_tab[i].tag] = boxml_tab[i].update; boxmlMapInitialized = true; } #endif // GMV_ENABLE_BOXML } //////////////////////////////////// // SPECIALIZED MATHML UPDATE METHODS //////////////////////////////////// SmartPtr update_MathML_mfenced_Element(const typename Model::Element& el) const { String open = ToString(getAttributeValue(el, ATTRIBUTE_SIGNATURE(MathML, Fenced, open))); String close = ToString(getAttributeValue(el, ATTRIBUTE_SIGNATURE(MathML, Fenced, close))); String separators = ToString(getAttributeValue(el, ATTRIBUTE_SIGNATURE(MathML, Fenced, separators))); std::vector > content; getChildMathMLElements(el, content); SmartPtr openElem = MathMLOperatorElement::create(this->getMathMLNamespaceContext()); openElem->setSize(0); openElem->append(open); openElem->SetFence(); SmartPtr closeElem = MathMLOperatorElement::create(this->getMathMLNamespaceContext()); closeElem->setSize(0); closeElem->append(close); closeElem->SetFence(); std::vector< SmartPtr > outerRowContent; outerRowContent.reserve(3); outerRowContent.push_back(openElem); if (content.size() == 1) outerRowContent.push_back(content[0]); else { std::vector< SmartPtr > innerRowContent; if (content.size() > 0) innerRowContent.reserve(separators.empty() ? content.size() : (2 * content.size() - 1)); for (unsigned i = 0; i < content.size(); i++) { innerRowContent.push_back(content[i]); if (!separators.empty() && i + 1 < content.size()) { SmartPtr sep = MathMLOperatorElement::create(this->mathmlContext); unsigned offset = (i < separators.length()) ? i : separators.length() - 1; sep->setSize(0); sep->append(separators.substr(offset, 1)); sep->SetSeparator(); innerRowContent.push_back(sep); } } SmartPtr innerRow = MathMLRowElement::create(this->getMathMLNamespaceContext()); innerRow->swapContent(innerRowContent); outerRowContent.push_back(innerRow); } outerRowContent.push_back(closeElem); // this can probably remain attached to the model SmartPtr outerRow = MathMLRowElement::create(this->getMathMLNamespaceContext()); outerRow->swapContent(outerRowContent); return outerRow; } SmartPtr update_MathML_semantics_Element(const typename Model::Element& el) const { typename Model::ElementIterator iter(el, MATHML_NS_URI); if (iter.more()) if (typename Model::Element e = iter.element()) if (Model::getNodeName(Model::asNode(e)) != "annotation" && Model::getNodeName(Model::asNode(e)) != "annotation-xml") if (SmartPtr elem = getMathMLElementNoCreate(iter.element())) return elem; else iter.next(); while (typename Model::Element e = iter.element()) { if (Model::getNodeName(Model::asNode(e)) == "annotation-xml") { String encoding = Model::getAttribute(e, "encoding"); if (encoding == "MathML-Presentation") return getMathMLElement(typename Model::ElementIterator(e, MATHML_NS_URI).element()); #if GMV_ENABLE_BOXML else if (encoding == "BoxML") { // this element can probably be associated with the model element SmartPtr adapter = getElement(el); assert(adapter); adapter->setChild(getBoxMLElement(typename Model::ElementIterator(e, BOXML_NS_URI).element())); adapter->resetDirtyStructure(); adapter->resetDirtyAttribute(); return adapter; } #endif } iter.next(); } return createMathMLDummyElement(); } SmartPtr update_MathML_mglyph_Node(const typename Model::Element& el) const { assert(el); String alt = Model::getAttribute(el, "alt"); String fontFamily = Model::getAttribute(el, "fontfamily"); String index = Model::getAttribute(el, "index"); if (alt.empty() || fontFamily.empty() || index.empty()) { this->getLogger()->out(LOG_WARNING, "malformed `mglyph' element (some required attribute is missing)\n"); return MathMLStringNode::create("?"); } return MathMLGlyphNode::create(fontFamily, index, alt); } SmartPtr update_MathML_malignmark_Node(const typename Model::Element& el) const { assert(el); const String edge = Model::getAttribute(el, "edge"); TokenId align = T__NOTVALID; if (!edge.empty()) { if (edge == "left") align = T_LEFT; else if (edge == "right") align = T_RIGHT; else this->getLogger()->out(LOG_WARNING, "malformed `malignmark' element, attribute `edge' has invalid value `%s' (ignored)", std::string(edge).c_str()); } return MathMLMarkNode::create(align); } #if GMV_ENABLE_BOXML /////////////////////////////////// // SPECIALIZED BOXML UPDATE METHODS /////////////////////////////////// SmartPtr update_BoxML_obj_Element(const typename Model::Element& el) const { String encoding = Model::getAttribute(el, "encoding"); if (encoding == "BoxML") return getBoxMLElement(typename Model::ElementIterator(el, BOXML_NS_URI).element()); else /* if (encoding == "MathML-Presentation") */ { // this element can be associated to the corresponding model element SmartPtr adapter = getElement(el); assert(adapter); adapter->setChild(getMathMLElement(typename Model::ElementIterator(el, MATHML_NS_URI).element())); adapter->resetDirtyStructure(); adapter->resetDirtyAttribute(); return adapter; } #if 0 else return createBoxMLDummyElement(); #endif } #endif // GMV_ENABLE_BOXML ////////////////// // MATHML BUILDERS ////////////////// struct MathMLElementBuilder { typedef MathMLElement target_type; static SmartPtr getContext(const TemplateBuilder& builder) { return builder.getMathMLNamespaceContext(); } static void begin(const TemplateBuilder&, const typename Model::Element&, const SmartPtr&) { } static void end(const TemplateBuilder&, const typename Model::Element&, const SmartPtr&) { } static void refine(const TemplateBuilder&, const typename Model::Element&, const SmartPtr&) { } static void construct(const TemplateBuilder&, const typename Model::Element&, const SmartPtr&) { } }; struct MathMLBinContainerElementBuilder : public MathMLElementBuilder { static void construct(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { elem->setChild(builder.getMathMLElement(el)); } }; struct MathMLNormalizingContainerElementBuilder : public MathMLBinContainerElementBuilder { static void construct(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { std::vector > content; builder.getChildMathMLElements(el, content); if (content.size() == 1) elem->setChild(content[0]); else { SmartPtr row = MathMLInferredRowElement::create(builder.getMathMLNamespaceContext()); row->swapContent(content); elem->setChild(row); } } }; struct MathMLLinearContainerElementBuilder : public MathMLElementBuilder { static void construct(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { std::vector > content; builder.getChildMathMLElements(el, content); elem->swapContent(content); } }; struct MathMLTokenElementBuilder : public MathMLElementBuilder { static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Token, mathvariant)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Token, mathsize)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Token, mathcolor)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Token, mathbackground)); } static void construct(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { std::vector > content; builder.getChildMathMLTextNodes(el, content); elem->swapContent(content); // should normalize spaces etc. } }; struct MathML_mi_ElementBuilder : public MathMLTokenElementBuilder { typedef MathMLIdentifierElement type; }; struct MathML_mn_ElementBuilder : public MathMLTokenElementBuilder { typedef MathMLNumberElement type; }; struct MathML_mo_ElementBuilder : public MathMLTokenElementBuilder { typedef MathMLOperatorElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { MathMLTokenElementBuilder::refine(builder, el, elem); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Operator, form)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Operator, fence)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Operator, separator)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Operator, lspace)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Operator, rspace)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Operator, stretchy)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Operator, symmetric)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Operator, maxsize)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Operator, minsize)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Operator, largeop)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Operator, movablelimits)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Operator, accent)); } }; struct MathML_mtext_ElementBuilder : public MathMLTokenElementBuilder { typedef MathMLTextElement type; }; struct MathML_ms_ElementBuilder : public MathMLTokenElementBuilder { typedef MathMLStringLitElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { MathMLTokenElementBuilder::refine(builder, el, elem); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, StringLit, lquote)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, StringLit, rquote)); } }; struct MathML_mspace_ElementBuilder : public MathMLElementBuilder { typedef MathMLSpaceElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Space, width)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Space, height)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Space, depth)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Space, linebreak)); } }; struct MathML_mrow_ElementBuilder : public MathMLLinearContainerElementBuilder { typedef MathMLRowElement type; }; struct MathML_mstyle_ElementBuilder : public MathMLNormalizingContainerElementBuilder { typedef MathMLStyleElement type; static void begin(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr&) { builder.refinementContext.push(el); } static void end(const TemplateBuilder& builder, const typename Model::Element&, const SmartPtr&) { builder.refinementContext.pop(); } static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Style, scriptlevel)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Style, displaystyle)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Style, scriptsizemultiplier)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Style, scriptminsize)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Style, mathcolor)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Style, mathbackground)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Style, color)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Style, background)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Style, negativeveryverythickmathspace)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Style, negativeverythickmathspace)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Style, negativethickmathspace)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Style, negativemediummathspace)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Style, negativethinmathspace)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Style, negativeverythinmathspace)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Style, negativeveryverythinmathspace)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Style, veryverythinmathspace)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Style, verythinmathspace)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Style, thinmathspace)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Style, mediummathspace)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Style, thickmathspace)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Style, verythickmathspace)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Style, veryverythickmathspace)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Style, mathsize)); } }; struct MathML_merror_ElementBuilder : public MathMLNormalizingContainerElementBuilder { typedef MathMLErrorElement type; }; struct MathML_mpadded_ElementBuilder : public MathMLNormalizingContainerElementBuilder { typedef MathMLPaddedElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Padded, width)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Padded, lspace)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Padded, height)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Padded, depth)); } }; struct MathML_mphantom_ElementBuilder : public MathMLNormalizingContainerElementBuilder { typedef MathMLPhantomElement type; }; struct MathML_maligngroup_ElementBuilder : public MathMLElementBuilder { typedef MathMLAlignGroupElement type; static void refine(const TemplateBuilder&, const typename Model::Element&, const SmartPtr&) { // NO ATTRIBUTES TO REFINE??? } }; struct MathML_malignmark_ElementBuilder : public MathMLElementBuilder { typedef MathMLAlignMarkElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, AlignMark, edge)); } }; struct MathML_maction_ElementBuilder : public MathMLLinearContainerElementBuilder { typedef MathMLActionElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Action, actiontype)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Action, selection)); } }; struct MathML_menclose_ElementBuilder : public MathMLNormalizingContainerElementBuilder { typedef MathMLEncloseElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Enclose, notation)); } }; struct MathML_math_ElementBuilder : public MathMLNormalizingContainerElementBuilder { typedef MathMLmathElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, math, mode)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, math, display)); } }; struct MathML_mfrac_ElementBuilder : public MathMLElementBuilder { typedef MathMLFractionElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Fraction, numalign)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Fraction, denomalign)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Fraction, linethickness)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Fraction, bevelled)); } static void construct(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { typename Model::ElementIterator iter(el, MATHML_NS_URI); elem->setNumerator(builder.getMathMLElement(iter.element())); iter.next(); elem->setDenominator(builder.getMathMLElement(iter.element())); } }; struct MathML_mroot_ElementBuilder : public MathMLElementBuilder { typedef MathMLRadicalElement type; static void construct(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { typename Model::ElementIterator iter(el, MATHML_NS_URI); elem->setBase(builder.getMathMLElement(iter.element())); iter.next(); elem->setIndex(builder.getMathMLElement(iter.element())); } }; struct MathML_msqrt_ElementBuilder : public MathMLElementBuilder { typedef MathMLRadicalElement type; static void construct(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { std::vector > content; builder.getChildMathMLElements(el, content); if (content.size() == 1) elem->setBase(content[0]); else { SmartPtr row = MathMLInferredRowElement::create(builder.getMathMLNamespaceContext()); row->swapContent(content); elem->setBase(row); } elem->setIndex(0); } }; struct MathML_msub_ElementBuilder : public MathMLElementBuilder { typedef MathMLScriptElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Script, subscriptshift)); } static void construct(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { typename Model::ElementIterator iter(el, MATHML_NS_URI); elem->setBase(builder.getMathMLElement(iter.element())); iter.next(); elem->setSubScript(builder.getMathMLElement(iter.element())); elem->setSuperScript(0); } }; struct MathML_msup_ElementBuilder : public MathMLElementBuilder { typedef MathMLScriptElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Script, superscriptshift)); } static void construct(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { typename Model::ElementIterator iter(el, MATHML_NS_URI); elem->setBase(builder.getMathMLElement(iter.element())); iter.next(); elem->setSubScript(0); elem->setSuperScript(builder.getMathMLElement(iter.element())); } }; struct MathML_msubsup_ElementBuilder : public MathMLElementBuilder { typedef MathMLScriptElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { MathML_msub_ElementBuilder::refine(builder, el, elem); MathML_msup_ElementBuilder::refine(builder, el, elem); } static void construct(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { typename Model::ElementIterator iter(el, MATHML_NS_URI); elem->setBase(builder.getMathMLElement(iter.element())); iter.next(); elem->setSubScript(builder.getMathMLElement(iter.element())); iter.next(); elem->setSuperScript(builder.getMathMLElement(iter.element())); } }; struct MathML_munder_ElementBuilder : public MathMLElementBuilder { typedef MathMLUnderOverElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, UnderOver, accentunder)); } static void construct(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { typename Model::ElementIterator iter(el, MATHML_NS_URI); elem->setBase(builder.getMathMLElement(iter.element())); iter.next(); elem->setUnderScript(builder.getMathMLElement(iter.element())); elem->setOverScript(0); } }; struct MathML_mover_ElementBuilder : public MathMLElementBuilder { typedef MathMLUnderOverElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, UnderOver, accent)); } static void construct(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { typename Model::ElementIterator iter(el, MATHML_NS_URI); elem->setBase(builder.getMathMLElement(iter.element())); iter.next(); elem->setUnderScript(0); elem->setOverScript(builder.getMathMLElement(iter.element())); } }; struct MathML_munderover_ElementBuilder : public MathMLElementBuilder { typedef MathMLUnderOverElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { MathML_munder_ElementBuilder::refine(builder, el, elem); MathML_mover_ElementBuilder::refine(builder, el, elem); } static void construct(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { typename Model::ElementIterator iter(el, MATHML_NS_URI); elem->setBase(builder.getMathMLElement(iter.element())); iter.next(); elem->setUnderScript(builder.getMathMLElement(iter.element())); iter.next(); elem->setOverScript(builder.getMathMLElement(iter.element())); } }; struct MathML_mtd_ElementBuilder : public MathMLNormalizingContainerElementBuilder { typedef MathMLTableCellElement type; }; struct MathML_mtable_ElementBuilder : public MathMLElementBuilder { typedef MathMLTableElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Table, align)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Table, rowalign)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Table, columnalign)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Table, groupalign)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Table, alignmentscope)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Table, columnwidth)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Table, rowspacing)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Table, columnspacing)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Table, rowlines)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Table, columnlines)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Table, frame)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Table, framespacing)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Table, equalrows)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Table, equalcolumns)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Table, displaystyle)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Table, side)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Table, minlabelspacing)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, Table, width)); } static const SmartPtr refineAlignAttribute(const SmartPtr& cellAlign, const SmartPtr& rowAlign, const SmartPtr& tableAlign) { #if 1 if (cellAlign) return cellAlign; else if (rowAlign) return rowAlign; else if (tableAlign) return tableAlign; else return 0; #else // Because of a bug in GCC-3.4 the following code, which is // syntactically and semantically correct, does not compile // and the compiler issues a misleading error message return (cellAlign ? cellAlign : (rowAlign ? rowAlign : (tableAlign ? tableAlign : 0))); #endif } static void construct(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { MathMLTableContentFactory tableContentFactory; unsigned rowIndex = 0; const SmartPtr tableRowAlign = builder.getAttributeValue(el, ATTRIBUTE_SIGNATURE(MathML, Table, rowalign)); const SmartPtr tableColumnAlign = builder.getAttributeValue(el, ATTRIBUTE_SIGNATURE(MathML, Table, columnalign)); const SmartPtr tableGroupAlign = builder.getAttributeValue(el, ATTRIBUTE_SIGNATURE(MathML, Table, groupalign)); for (typename Model::ElementIterator iter(el, MATHML_NS_URI); iter.more(); iter.next()) { typename Model::Element row = iter.element(); const SmartPtr rowRowAlign = builder.getAttributeValue(row, ATTRIBUTE_SIGNATURE(MathML, TableRow, rowalign)); const SmartPtr rowColumnAlign = builder.getAttributeValue(row, ATTRIBUTE_SIGNATURE(MathML, TableRow, columnalign)); const SmartPtr rowGroupAlign = builder.getAttributeValue(row, ATTRIBUTE_SIGNATURE(MathML, TableRow, groupalign)); const String name = Model::getNodeName(Model::asNode(row)); if (name == "mtr" || name == "mlabeledtr") { unsigned columnIndex = 0; for (typename Model::ElementIterator iter(row, MATHML_NS_URI); iter.more(); iter.next()) { typename Model::Element cell = iter.element(); const SmartPtr cellRowAlign = builder.getAttributeValue(cell, ATTRIBUTE_SIGNATURE(MathML, TableCell, rowalign)); const SmartPtr cellColumnAlign = builder.getAttributeValue(cell, ATTRIBUTE_SIGNATURE(MathML, TableCell, columnalign)); const SmartPtr cellGroupAlign = builder.getAttributeValue(cell, ATTRIBUTE_SIGNATURE(MathML, TableCell, groupalign)); const int cellRowSpan = ToInteger(builder.getAttributeValue(cell, ATTRIBUTE_SIGNATURE(MathML, TableCell, rowspan))); const int cellColumnSpan = ToInteger(builder.getAttributeValue(cell, ATTRIBUTE_SIGNATURE(MathML, TableCell, columnspan))); SmartPtr elem = builder.getMathMLElement(cell); SmartPtr cellElem = smart_cast(elem); if (!cellElem) { cellElem = MathMLTableCellElement::create(builder.getMathMLNamespaceContext()); cellElem->setChild(elem); // WARNING: should we clear the dirty flags? } if (name == "mtr" || columnIndex > 0) { cellElem->setSpan(cellRowSpan, cellColumnSpan); columnIndex = tableContentFactory.setChild(rowIndex, columnIndex, cellRowSpan, cellColumnSpan, cellElem); } else { cellElem->setSpan(1, 1); tableContentFactory.setLabelChild(rowIndex, cellElem); } // now rowIndex and columnIndex are final values cellElem->setPosition(rowIndex, columnIndex); const SmartPtr rowAlign = refineAlignAttribute(cellRowAlign, rowRowAlign, GetComponent(tableRowAlign, rowIndex)); const SmartPtr columnAlign = refineAlignAttribute(cellColumnAlign, GetComponent(rowColumnAlign, columnIndex), GetComponent(tableColumnAlign, columnIndex)); const SmartPtr groupAlign = refineAlignAttribute(cellGroupAlign, GetComponent(rowGroupAlign, columnIndex), GetComponent(tableGroupAlign, columnIndex)); cellElem->setAlignment(ToTokenId(rowAlign), ToTokenId(columnAlign)); //cellElem->setGroupAlignment(groupAlign); } rowIndex++; } else { // issue a warning message or promote to mtr with single mtd inside } } elem->updateContent(tableContentFactory); } }; struct MathML_mmultiscripts_ElementBuilder : public MathMLElementBuilder { typedef MathMLMultiScriptsElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, MultiScripts, subscriptshift)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(MathML, MultiScripts, superscriptshift)); } static void construct(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { typename Model::ElementIterator iter(el, MATHML_NS_URI); unsigned i = 0; unsigned nScripts = 0; unsigned nPreScripts = 0; bool preScripts = false; elem->setBase(builder.getMathMLElement(iter.element())); iter.next(); while (iter.more()) { typename Model::Element node = iter.element(); assert(node); const String nodeName = Model::getNodeName(Model::asNode(node)); if (nodeName == "mprescripts") { if (preScripts) builder.getLogger()->out(LOG_WARNING, "multiple elements in mmultiscript"); else { if (i % 2 == 1) elem->setSuperScript(nScripts, 0); preScripts = true; i = 0; } } else { if (i % 2 == 0) // sub script { SmartPtr sub = (nodeName == "none") ? 0 : builder.getMathMLElement(node); if (preScripts) elem->setPreSubScript(nPreScripts, sub); else elem->setSubScript(nScripts, sub); } else // super script { SmartPtr sup = (nodeName == "none") ? 0 : builder.getMathMLElement(node); if (preScripts) { elem->setPreSuperScript(nPreScripts, sup); nPreScripts++; } else { elem->setSuperScript(nScripts, sup); nScripts++; } } i++; } iter.next(); } if (preScripts && i % 2 == 1) elem->setPreSuperScript(nPreScripts, 0); elem->setScriptsSize(nScripts); elem->setPreScriptsSize(nPreScripts); } }; #if GMV_ENABLE_BOXML ///////////////// // BOXML BUILDERS ///////////////// struct BoxMLElementBuilder { typedef BoxMLElement target_type; static SmartPtr getContext(const TemplateBuilder& builder) { return builder.getBoxMLNamespaceContext(); } static void begin(const TemplateBuilder&, const typename Model::Element&, const SmartPtr&) { } static void end(const TemplateBuilder&, const typename Model::Element&, const SmartPtr&) { } static void refine(const TemplateBuilder&, const typename Model::Element&, const SmartPtr&) { } static void construct(const TemplateBuilder&, const typename Model::Element&, const SmartPtr&) { } }; struct MathMLBoxMLAdapterBuilder : public MathMLElementBuilder { typedef MathMLBoxMLAdapter type; }; struct BoxMLMathMLAdapterBuilder : public BoxMLElementBuilder { typedef BoxMLMathMLAdapter type; }; struct BoxMLBinContainerElementBuilder : public BoxMLElementBuilder { static void construct(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { elem->setChild(builder.getBoxMLElement(typename Model::ElementIterator(el, BOXML_NS_URI).element())); } }; struct BoxMLLinearContainerElementBuilder : public BoxMLElementBuilder { static void construct(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { std::vector > content; builder.getChildBoxMLElements(el, content); elem->swapContent(content); } }; struct BoxML_box_ElementBuilder : public BoxMLBinContainerElementBuilder { typedef BoxMLboxElement type; }; struct BoxML_action_ElementBuilder : public BoxMLLinearContainerElementBuilder { typedef BoxMLActionElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, Action, selection)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, Action, actiontype)); } }; struct BoxML_at_ElementBuilder : public BoxMLBinContainerElementBuilder { typedef BoxMLAtElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, At, x)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, At, y)); } }; struct BoxML_decor_ElementBuilder : public BoxMLBinContainerElementBuilder { typedef BoxMLDecorElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, Decor, type)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, Decor, color)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, Decor, thickness)); } }; struct BoxML_g_ElementBuilder : public BoxMLLinearContainerElementBuilder { typedef BoxMLGroupElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, Text, size)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, Text, color)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, Text, background)); } }; struct BoxML_h_ElementBuilder : public BoxMLLinearContainerElementBuilder { typedef BoxMLHElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, H, spacing)); } }; struct BoxML_ink_ElementBuilder : public BoxMLElementBuilder { typedef BoxMLInkElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, Ink, color)); BoxML_space_ElementBuilder::refine(builder, el, elem); } }; struct BoxML_layout_ElementBuilder : public BoxMLLinearContainerElementBuilder { typedef BoxMLLayoutElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, Layout, width)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, Layout, height)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, Layout, depth)); } }; #if 0 struct BoxML_par_ElementBuilder : public BoxMLElementBuilder { typedef BoxMLParagraphElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, V, align)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, V, minlinespacing)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, Text, width)); } static void construct(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { std::vector > content; for (typename Model::NodeIterator iter(Model::asNode(el)); iter.more(); iter.next()) { typename Model::Node p = iter.node(); assert(p); if (Model::getNodeType(p) == Model::TEXT_NODE) { SmartPtr text = builder.getElement(el); text->setContent(Model::getNodeValue(p)); content.push_back(text); } else if (Model::getNodeType(p) == Model::ELEMENT_NODE && Model::getNodeNamespaceURI(p) == BOXML_NS_URI) content.push_back(builder.getBoxMLElement(Model::asElement(p))); } elem->swapContent(content); } }; #endif struct BoxML_space_ElementBuilder : public BoxMLElementBuilder { typedef BoxMLSpaceElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, Space, width)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, Space, height)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, Space, depth)); } }; struct BoxML_text_ElementBuilder : public BoxMLElementBuilder { typedef BoxMLTextElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, Text, size)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, Text, color)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, Text, background)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, Text, width)); } static void construct(const TemplateBuilder&, const typename Model::Element& el, const SmartPtr& elem) { String content; for (typename Model::NodeIterator iter(Model::asNode(el)); iter.more(); iter.next()) { typename Model::Node p = iter.node(); assert(p); if (Model::getNodeType(p) == Model::TEXT_NODE) content += Model::getNodeValue(p); } content = trimSpacesLeft(trimSpacesRight(collapseSpaces(content))); elem->setContent(content); } }; struct BoxML_v_ElementBuilder : public BoxMLLinearContainerElementBuilder { typedef BoxMLVElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, V, enter)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, V, exit)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, V, indent)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, V, minlinespacing)); } }; struct BoxML_hv_ElementBuilder : public BoxMLLinearContainerElementBuilder { typedef BoxMLHVElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, HV, spacing)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, HV, indent)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, HV, minlinespacing)); } }; struct BoxML_hov_ElementBuilder : public BoxMLLinearContainerElementBuilder { typedef BoxMLHOVElement type; static void refine(const TemplateBuilder& builder, const typename Model::Element& el, const SmartPtr& elem) { builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, HOV, spacing)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, HOV, indent)); builder.refineAttribute(elem, el, ATTRIBUTE_SIGNATURE(BoxML, HOV, minlinespacing)); } }; #endif // GMV_ENABLE_BOXML //////////////////////////// // BUILDER AUXILIARY METHODS //////////////////////////// SmartPtr getAttribute(const typename Model::Element& el, const AttributeSignature& signature) const { SmartPtr attr; if (signature.fromElement) if (Model::hasAttribute(el, signature.name)) attr = Attribute::create(signature, Model::getAttribute(el, signature.name)); if (!attr && signature.fromContext) attr = refinementContext.get(signature); return attr; } SmartPtr getAttributeValue(const typename Model::Element& el, const AttributeSignature& signature) const { if (SmartPtr attr = getAttribute(el, signature)) return attr->getValue(); else return signature.getDefaultValue(); } void refineAttribute(const SmartPtr& elem, const typename Model::Element& el, const AttributeSignature& signature) const { if (SmartPtr attr = getAttribute(el, signature)) elem->setAttribute(attr); else elem->removeAttribute(signature); } /////////////////////////////////////// // BUILDER AUXILIARY METHODS FOR MATHML /////////////////////////////////////// SmartPtr getMathMLElementNoCreate(const typename Model::Element& el) const { if (el) { //std::cout << "createMathMLElement " << el.get_localName() << std::endl; typename MathMLBuilderMap::const_iterator m = mathmlMap.find(Model::getNodeName(Model::asNode(el))); if (m != mathmlMap.end()) { SmartPtr elem = (this->*(m->second))(el); assert(elem); elem->resetDirtyStructure(); elem->resetDirtyAttribute(); return elem; } } return 0; } SmartPtr getMathMLElement(const typename Model::Element& el) const { if (SmartPtr elem = getMathMLElementNoCreate(el)) return elem; else return createMathMLDummyElement(); } void getChildMathMLElements(const typename Model::Element& el, std::vector >& content) const { content.clear(); for (typename Model::ElementIterator iter(el, MATHML_NS_URI); iter.more(); iter.next()) content.push_back(getMathMLElement(iter.element())); } void getChildMathMLTextNodes(const typename Model::Element& el, std::vector >& content) const { bool first = true; content.clear(); for (typename Model::NodeIterator iter(Model::asNode(el)); iter.more(); ) { typename Model::Node n = iter.node(); assert(n); switch (Model::getNodeType(n)) { case Model::TEXT_NODE: { // ok, we have a chunk of text String s = collapseSpaces(Model::getNodeValue(n)); iter.next(); // ...but spaces at the at the beginning (end) are deleted only if this // is the very first (last) chunk in the token. if (first) s = trimSpacesLeft(s); if (!iter.more()) s = trimSpacesRight(s); content.push_back(createMathMLTextNode(s)); } break; case Model::ELEMENT_NODE: { if (Model::getNodeNamespaceURI(n) == MATHML_NS_URI) { const String nodeName = Model::getNodeName(n); if (nodeName == "mglyph") content.push_back(update_MathML_mglyph_Node(Model::asElement(n))); else if (nodeName == "malignmark") content.push_back(update_MathML_malignmark_Node(Model::asElement(n))); } } iter.next(); break; default: iter.next(); break; } first = false; } } #if ENABLE_BUILDER_CACHE SmartPtr createMathMLTextNode(const String& content) const { std::pair r = mathmlTextNodeCache.insert(std::make_pair(content, SmartPtr(0))); if (r.second) { if (content == MathMLFunctionApplicationNode::getContent()) r.first->second = MathMLFunctionApplicationNode::create(); else if (content == MathMLInvisibleTimesNode::getContent()) r.first->second = MathMLInvisibleTimesNode::create(); else r.first->second = MathMLStringNode::create(content); return r.first->second; } else return r.first->second; } #else SmartPtr createMathMLTextNode(const String& content) const { if (content == MathMLFunctionApplicationNode::getContent()) return MathMLFunctionApplicationNode::create(); else if (content == MathMLInvisibleTimesNode::getContent()) return MathMLInvisibleTimesNode::create(); else return MathMLStringNode::create(content); } #endif // ENABLE_BUILDER_CACHE SmartPtr createMathMLDummyElement(void) const { SmartPtr elem = MathMLDummyElement::create(this->getMathMLNamespaceContext()); elem->resetDirtyStructure(); elem->resetDirtyAttribute(); return elem; } #if GMV_ENABLE_BOXML ////////////////////////////////////// // BUILDER AUXILIARY METHODS FOR BOXML ////////////////////////////////////// SmartPtr getBoxMLElement(const typename Model::Element& el) const { if (el) { typename BoxMLBuilderMap::const_iterator m = boxmlMap.find(Model::getNodeName(Model::asNode(el))); if (m != boxmlMap.end()) { SmartPtr elem = (this->*(m->second))(el); assert(elem); elem->resetDirtyStructure(); elem->resetDirtyAttribute(); return elem; } } return createBoxMLDummyElement(); } void getChildBoxMLElements(const typename Model::Element& el, std::vector >& content) const { content.clear(); for (typename Model::ElementIterator iter(el, BOXML_NS_URI); iter.more(); iter.next()) content.push_back(getBoxMLElement(iter.element())); } SmartPtr createBoxMLDummyElement(void) const { assert(false); return 0; } #endif // GMV_ENABLE_BOXML public: static SmartPtr create(void) { return new TemplateBuilder(); } virtual void forgetElement(Element* elem) const { this->linkerRemove(elem); } virtual SmartPtr getRootElement() const { if (typename Model::Element root = this->getRootModelElement()) { const String ns = Model::getNodeNamespaceURI(Model::asNode(root)); if (ns == MATHML_NS_URI) return getMathMLElement(root); #if GMV_ENABLE_BOXML else if (ns == BOXML_NS_URI) return getBoxMLElement(root); #endif // GMV_ENABLE_BOXML } return 0; } private: #if ENABLE_BUILDER_CACHE typedef HASH_MAP_NS::hash_map, StringHashCompare> MathMLTextNodeCache; mutable MathMLTextNodeCache mathmlTextNodeCache; #endif // ENABLE_BUILDER_CACHE typedef SmartPtr (TemplateBuilder::* MathMLUpdateMethod)(const typename Model::Element&) const; typedef HASH_MAP_NS::hash_map MathMLBuilderMap; static MathMLBuilderMap mathmlMap; static bool mathmlMapInitialized; #if GMV_ENABLE_BOXML typedef SmartPtr (TemplateBuilder::* BoxMLUpdateMethod)(const typename Model::Element&) const; typedef HASH_MAP_NS::hash_map BoxMLBuilderMap; static BoxMLBuilderMap boxmlMap; static bool boxmlMapInitialized; #endif // GMV_ENABLE_BOXML mutable RefinementContext refinementContext; }; template typename TemplateBuilder::MathMLBuilderMap TemplateBuilder::mathmlMap; template bool TemplateBuilder::mathmlMapInitialized = false; #ifdef GMV_ENABLE_BOXML template typename TemplateBuilder::BoxMLBuilderMap TemplateBuilder::boxmlMap; template bool TemplateBuilder::boxmlMapInitialized = false; #endif // GMV_ENABLE_BOXML #endif // __TemplateBuilder_hh__