tdf#38885 Remove createTextFromNode

Change-Id: I85df73e498d61b976ddb908ab1b9c5e368d178cf
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/98795
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
diff --git a/starmath/inc/node.hxx b/starmath/inc/node.hxx
index 1e30136..c0320e6b 100644
--- a/starmath/inc/node.hxx
+++ b/starmath/inc/node.hxx
@@ -95,9 +95,9 @@ enum class SmNodeType

class SmNode : public SmRect
{
    SmFace      maFace;

    SmToken     maNodeToken;
    SmFace          maFace;
    SmToken         maNodeToken;
    SmNodeType      meType;
    SmScaleMode     meScaleMode;
    RectHorAlign    meRectHorAlign;
@@ -115,96 +115,304 @@ public:
    SmNode(const SmNode&) = delete;
    SmNode& operator=(const SmNode&) = delete;

    virtual             ~SmNode();
    virtual ~SmNode();

    /**
     * Checks node visibility.
     * Returns true if this is an instance of SmVisibleNode's subclass, false otherwise.
     * @return node visibility
     */
    virtual bool        IsVisible() const = 0;
    virtual bool IsVisible() const = 0;

    virtual size_t      GetNumSubNodes() const = 0;
    virtual SmNode *    GetSubNode(size_t nIndex) = 0;
            const SmNode * GetSubNode(size_t nIndex) const
            {
                return const_cast<SmNode *>(this)->GetSubNode(nIndex);
            }
    /**
     * Gets the number of subnodes.
     * @return number of subnodes
     */
    virtual size_t GetNumSubNodes() const = 0;

    /**
     * Gets the subnode of index nIndex.
     * @param nIndex
     * @return subnode of index nIndex
     */
    virtual SmNode * GetSubNode(size_t nIndex) = 0;
    const   SmNode * GetSubNode(size_t nIndex) const
                     { return const_cast<SmNode *>(this)->GetSubNode(nIndex); }

    virtual const SmNode * GetLeftMost() const;

            FontChangeMask &Flags() { return mnFlags; }
            FontAttribute  &Attributes() { return mnAttributes; }
    /**
     * Gets the FontChangeMask flags.
     * @return FontChangeMask flags
     */
    FontChangeMask &Flags() { return mnFlags; }

            bool IsPhantom() const { return mbIsPhantom; }
            void SetPhantom(bool bIsPhantom);
            void SetColor(const Color &rColor);
    /**
     * Gets the font attributes.
     * @return font attributes
     */
    FontAttribute &Attributes() { return mnAttributes; }

            void SetAttribut(FontAttribute nAttrib);
            void ClearAttribut(FontAttribute nAttrib);
    /**
     * Checks if it is a visible node rendered invisible.
     * @return rendered visibility
     */
    bool IsPhantom() const { return mbIsPhantom; }

            const SmFace & GetFont() const { return maFace; };
                  SmFace & GetFont()       { return maFace; };
    /**
     * Sets the render visibility of a visible node to bIsPhantom.
     * @param bIsPhantom
     * @return
     */
    void SetPhantom(bool bIsPhantom);

            void SetFont(const SmFace &rFace);
            void SetFontSize(const Fraction &rRelSize, FontSizeType nType);
            void SetSize(const Fraction &rScale);
    /**
     * Sets the font color.
     * @param rColor
     * @return
     */
    void SetColor(const Color &rColor);

    /** Prepare preliminary settings about font and text
     *  (e.g. maFace, meRectHorAlign, mnFlags, mnAttributes, etc.)
    /**
     * Sets the font attribute nAttrib.
     * Check FontAttribute class.
     * @param nAttrib
     * @return
     */
    void SetAttribut(FontAttribute nAttrib);

    /**
     * Clears the font attribute nAttrib.
     * Check FontAttribute class.
     * @param nAttrib
     * @return
     */
    void ClearAttribut(FontAttribute nAttrib);

    /**
     * Gets the font.
     * @return font
     */
    const SmFace & GetFont() const { return maFace; };
          SmFace & GetFont()       { return maFace; };

    /**
     * Sets the font to rFace.
     * @param rFace
     * @return
     */
    void SetFont(const SmFace &rFace);

    /**
     * Sets the font size to rRelSize with type nType.
     * Check FontSizeType for details.
     * @param rRelSize
     * @param nType
     * @return
     */
    void SetFontSize(const Fraction &rRelSize, FontSizeType nType);

    /**
     * Sets the font size to rRelSize with type FontSizeType::ABSOLUT.
     * @param rScale
     * @return
     */
    void SetSize(const Fraction &rScale);

    /**
     * Prepare preliminary settings about font and text
     * (e.g. maFace, meRectHorAlign, mnFlags, mnAttributes, etc.)
     * @param rFormat
     * @param rDocShell
     * @param nDepth
     * @return
     */
    virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell, int nDepth);

    /**
     * Prepare preliminary font attributes
     * Called on Prepare(...).
     * @return
     */
    void PrepareAttributes();

    void         SetRectHorAlign(RectHorAlign eHorAlign, bool bApplyToSubTree = true );
    /**
     * Sets the alignment of the text.
     * Check RectHorAlign class for details.
     * The subtrees will be affected if bApplyToSubTree.
     * @param eHorAlign
     * @param bApplyToSubTree
     * @return
     */
    void SetRectHorAlign(RectHorAlign eHorAlign, bool bApplyToSubTree = true );

    /**
     * Gets the alignment of the text.
     * @return alignment of the text
     */
    RectHorAlign GetRectHorAlign() const { return meRectHorAlign; }

    /**
     * Parses itself to SmRect.
     * @return this
     */
    const SmRect & GetRect() const { return *this; }

    void Move(const Point &rPosition);
    void MoveTo(const Point &rPosition) { Move(rPosition - GetTopLeft()); }
    /**
     * Moves the rectangle by rVector.
     * @param rVector
     * @return
     */
    void Move(const Point &rVector);

    /**
     * Moves the rectangle to rPoint, being the top left corner the origin.
     * @param rPoint
     * @return
     */
    void MoveTo(const Point &rPoint) { Move(rPoint - GetTopLeft()); }

    /**
     * Prepares the SmRect to render.
     * @param rDev
     * @param rFormat
     * @return
     */
    virtual void Arrange(OutputDevice &rDev, const SmFormat &rFormat) = 0;
    virtual void CreateTextFromNode(OUStringBuffer &rText);

    virtual void    GetAccessibleText( OUStringBuffer &rText ) const = 0;
    sal_Int32       GetAccessibleIndex() const { return mnAccIndex; }
    void            SetAccessibleIndex(sal_Int32 nAccIndex) { mnAccIndex = nAccIndex; }
    const SmNode *  FindNodeWithAccessibleIndex(sal_Int32 nAccIndex) const;
    /**
     * Appends to rText the node text.
     * @param rText
     * @return
     */
    virtual void GetAccessibleText( OUStringBuffer &rText ) const = 0;

    sal_uInt16  GetRow() const    { return sal::static_int_cast<sal_uInt16>(maNodeToken.nRow); }
    sal_uInt16  GetColumn() const { return sal::static_int_cast<sal_uInt16>(maNodeToken.nCol); }
    /**
     * Gets the node accessible index.
     * Used for visual editing.
     * @return node accessible index
     */
    sal_Int32 GetAccessibleIndex() const { return mnAccIndex; }

    SmScaleMode     GetScaleMode() const { return meScaleMode; }
    void            SetScaleMode(SmScaleMode eMode) { meScaleMode = eMode; }
    /**
     * Sets the node accessible index to nAccIndex.
     * Used for visual editing.
     * @param nAccIndex
     * @return
     */
    void SetAccessibleIndex(sal_Int32 nAccIndex) { mnAccIndex = nAccIndex; }

    /**
     * Finds the node with accessible index nAccIndex.
     * Used for visual editing.
     * @param nAccIndex
     * @return node with accessible index nAccIndex
     */
    const SmNode * FindNodeWithAccessibleIndex(sal_Int32 nAccIndex) const;

    /**
     * Gets the line in the text where the node is located.
     * It is used to do the visual <-> text correspondence.
     * @return line
     */
    sal_uInt16 GetRow() const { return sal::static_int_cast<sal_uInt16>(maNodeToken.nRow); }

    /**
     * Gets the colum of the line in the text where the node is located.
     * It is used to do the visual <-> text correspondence.
     * @return colum
     */
    sal_uInt16 GetColumn() const { return sal::static_int_cast<sal_uInt16>(maNodeToken.nCol); }

    /**
     * Gets the scale mode.
     * @return scale mode
     */
    SmScaleMode GetScaleMode() const { return meScaleMode; }

    /**
     * Sets the scale mode to eMode.
     * @param eMode
     * @return
     */
    void SetScaleMode(SmScaleMode eMode) { meScaleMode = eMode; }

    //visual stuff TODO comment
    virtual void AdaptToX(OutputDevice &rDev, sal_uLong nWidth);
    virtual void AdaptToY(OutputDevice &rDev, sal_uLong nHeight);

    SmNodeType      GetType() const  { return meType; }
    const SmToken & GetToken() const { return maNodeToken; }
    /**
     * Gets the node type.
     * @return node type
     */
    SmNodeType GetType() const  { return meType; }

    /**
     * Gets the token.
     * The token contains the data extracted from the text mode.
     * Ej: text, type (sub, sup, int,...), row and column,...
     * @return node type
     */
    const SmToken & GetToken() const { return maNodeToken; }
          SmToken & GetToken()       { return maNodeToken; }

    /**
     * Finds the node from the position in the text.
     * It is used to do the visual <-> text correspondence.
     * @param nRow
     * @param nCol
     * @return the given node
     */
    const SmNode *  FindTokenAt(sal_uInt16 nRow, sal_uInt16 nCol) const;

    /**
     * Finds the closest rectangle in the screen.
     * @param rPoint
     * @return the given node
     */
    const SmNode *  FindRectClosestTo(const Point &rPoint) const;

    /** Accept a visitor
     * Calls the method for this class on the visitor
    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    virtual void Accept(SmVisitor* pVisitor) = 0;

    /** True if this node is selected */
    /**
     * Checks if the node is selected.
     * @return the node is selected
     */
    bool IsSelected() const {return mbIsSelected;}

    /**
     * Sets the node to Selected.
     * @param Selected
     * @return
     */
    void SetSelected(bool Selected) {mbIsSelected = Selected;}

    /** Get the parent node of this node */
    SmStructureNode* GetParent(){ return mpParentNode; }
    /**
     * Gets the parent node of this node.
     * @return parent node
     */
    const SmStructureNode* GetParent() const { return mpParentNode; }
    /** Set the parent node */
    void SetParent(SmStructureNode* parent){
        mpParentNode = parent;
    }
          SmStructureNode* GetParent()       { return mpParentNode; }

    /** Set the token for this node */
    void SetToken(SmToken const & token){
        maNodeToken = token;
    }
    /**
     * Sets the parent node.
     * @param parent
     * @return
     */
    void SetParent(SmStructureNode* parent){ mpParentNode = parent; }

    /**
     * Sets the token for this node.
     * @param token
     * @return
     */
    void SetToken(SmToken const & token){ maNodeToken = token; }

private:
    SmStructureNode* mpParentNode;
@@ -223,57 +431,102 @@ class SmStructureNode : public SmNode
protected:
    SmStructureNode(SmNodeType eNodeType, const SmToken &rNodeToken, size_t nSize = 0)
        : SmNode(eNodeType, rNodeToken)
        , maSubNodes(nSize)
    {}
        , maSubNodes(nSize) {}

public:
    virtual ~SmStructureNode() override;

    virtual bool        IsVisible() const override;
    /**
     * Checks node visibility.
     * Returns true if this is an instance of SmVisibleNode's subclass, false otherwise.
     * @return node visibility
     */
    virtual bool IsVisible() const override;

    virtual size_t      GetNumSubNodes() const override;
    /**
     * Gets the number of subnodes.
     * @return number of subnodes
     */
    virtual size_t GetNumSubNodes() const override;

    /**
     * Gets the subnode of index nIndex.
     * @param nIndex
     * @return subnode of index nIndex
     */
    using   SmNode::GetSubNode;
    virtual SmNode *    GetSubNode(size_t nIndex) override;
    void ClearSubNodes();
            void SetSubNodes(std::unique_ptr<SmNode> pFirst, std::unique_ptr<SmNode> pSecond, std::unique_ptr<SmNode> pThird = nullptr);
            void SetSubNodes(SmNodeArray&& rNodeArray);
    virtual SmNode * GetSubNode(size_t nIndex) override;

    /**
     * Does the cleaning of the subnodes.
     * @return
     */
    void ClearSubNodes();

    /**
     * Sets subnodes, used for opperators.
     * @param pFirst
     * @param pSecond
     * @param pThird
     * @return
     */
    void SetSubNodes(std::unique_ptr<SmNode> pFirst, std::unique_ptr<SmNode> pSecond,
                     std::unique_ptr<SmNode> pThird = nullptr);

    /**
     * Sets subnodes.
     * @param rNodeArray
     * @return
     */
    void SetSubNodes(SmNodeArray&& rNodeArray);

    /**
     * Appends to rText the node text.
     * @param rText
     * @return
     */
    virtual void  GetAccessibleText( OUStringBuffer &rText ) const override;

    /**
     * Gets the first subnode.
     * @return first subnode
     */
    SmNodeArray::iterator begin() {return maSubNodes.begin();}

    /**
     * Gets the last subnode.
     * @return last subnode
     */
    SmNodeArray::iterator end() {return maSubNodes.end();}

    /**
     * Gets the last subnode.
     * @return last subnode
     */
    SmNodeArray::reverse_iterator rbegin() {return maSubNodes.rbegin();}

    /**
     * Gets the first subnode.
     * @return first subnode
     */
    SmNodeArray::reverse_iterator rend() {return maSubNodes.rend();}

    /** Get the index of a child node
     *
    /**
     * Get the index of the child node pSubNode.
     * Returns -1, if pSubNode isn't a subnode of this.
     * @param pSubNode
     * @return index of the child node
     */
    int IndexOfSubNode(SmNode const * pSubNode)
    {
        size_t nSize = GetNumSubNodes();
        for (size_t i = 0; i < nSize; i++)
            if (pSubNode == GetSubNode(i))
                return i;
        return -1;
    }
    int IndexOfSubNode(SmNode const * pSubNode);

    void SetSubNode(size_t nIndex, SmNode* pNode)
    {
        size_t size = maSubNodes.size();
        if (size <= nIndex)
        {
            //Resize subnodes array
            maSubNodes.resize(nIndex + 1);
            //Set new slots to NULL except at nIndex
            for (size_t i = size; i < nIndex; i++)
                maSubNodes[i] = nullptr;
        }
        maSubNodes[nIndex] = pNode;
        if (pNode)
            pNode->SetParent(this);
    }
    /**
     * Sets the subnode pNode at nIndex.
     * If necessary increases the subnodes length.
     * @param nIndex
     * @param pNode
     * @return
     */
    void SetSubNode(size_t nIndex, SmNode* pNode);

private:
    /** Sets parent on children of this node */
@@ -290,13 +543,28 @@ class SmVisibleNode : public SmNode
{
protected:
    SmVisibleNode(SmNodeType eNodeType, const SmToken &rNodeToken)
    :   SmNode(eNodeType, rNodeToken)
    {}
    :   SmNode(eNodeType, rNodeToken) {}

public:

    /**
     * Checks node visibility.
     * Returns true if this is an instance of SmVisibleNode's subclass, false otherwise.
     * @return node visibility
     */
    virtual bool        IsVisible() const override;

    /**
     * Gets the number of subnodes.
     * @return number of subnodes
     */
    virtual size_t      GetNumSubNodes() const override;

    /**
     * Gets the subnode of index nIndex.
     * @param nIndex
     * @return subnode of index nIndex
     */
    using   SmNode::GetSubNode;
    virtual SmNode *    GetSubNode(size_t nIndex) override;
};
@@ -306,11 +574,15 @@ class SmGraphicNode : public SmVisibleNode
{
protected:
    SmGraphicNode(SmNodeType eNodeType, const SmToken &rNodeToken)
    :   SmVisibleNode(eNodeType, rNodeToken)
    {}
    :   SmVisibleNode(eNodeType, rNodeToken) {}

public:

    /**
     * Appends to rText the node text.
     * @param rText
     * @return
     */
    virtual void  GetAccessibleText( OUStringBuffer &rText ) const override;
};

@@ -328,12 +600,24 @@ public:
        : SmGraphicNode(SmNodeType::Rectangle, rNodeToken)
    {}

    //visual stuff TODO comment
    virtual void AdaptToX(OutputDevice &rDev, sal_uLong nWidth) override;
    virtual void AdaptToY(OutputDevice &rDev, sal_uLong nHeight) override;

    /**
     * Prepares the SmRect to render.
     * @param rDev
     * @param rFormat
     * @return
     */
    virtual void Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;

    void CreateTextFromNode(OUStringBuffer &rText) override;
    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    void Accept(SmVisitor* pVisitor) override;
};

@@ -351,14 +635,36 @@ class SmPolyLineNode final : public SmGraphicNode
public:
    explicit SmPolyLineNode(const SmToken &rNodeToken);

    long         GetWidth() const { return mnWidth; }
    tools::Polygon &GetPolygon() { return maPoly; }
    /**
     * Gets the width of the rect.
     * @return width
     */
    long GetWidth() const { return mnWidth; }

    /**
     * Gets the polygon to draw the node.
     * @return polygon
     */
    tools::Polygon &GetPolygon()  { return maPoly; }

    //visual stuff TODO comment
    virtual void AdaptToX(OutputDevice &rDev, sal_uLong nWidth) override;
    virtual void AdaptToY(OutputDevice &rDev, sal_uLong nHeight) override;

    /**
     * Prepares the SmRect to render.
     * @param rDev
     * @param rFormat
     * @return
     */
    virtual void Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;

    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    void Accept(SmVisitor* pVisitor) override;
};

@@ -369,6 +675,8 @@ public:
 */
class SmTextNode : public SmVisibleNode
{

protected:
    OUString   maText;
    sal_uInt16 mnFontDesc;
    /** Index within text where the selection starts
@@ -386,42 +694,115 @@ protected:
public:
    SmTextNode(const SmToken &rNodeToken, sal_uInt16 nFontDescP );

    sal_uInt16              GetFontDesc() const { return mnFontDesc; }
    void                SetText(const OUString &rText) { maText = rText; }
    const OUString &    GetText() const { return maText; }
    /** Change the text of this node, including the underlying token */
    void                ChangeText(const OUString &rText) {
        maText = rText;
        SmToken token = GetToken();
        token.aText = rText;
        SetToken(token); //TODO: Merge this with AdjustFontDesc for better performance
        AdjustFontDesc();
    }
    /** Try to guess the correct FontDesc, used during visual editing */
    void                AdjustFontDesc();
    /** Index within GetText() where the selection starts
     * @remarks Only valid of SmNode::IsSelected() is true
     */
    sal_Int32           GetSelectionStart() const {return mnSelectionStart;}
    /** Index within GetText() where the selection end
     * @remarks Only valid of SmNode::IsSelected() is true
     */
    sal_Int32           GetSelectionEnd() const {return mnSelectionEnd;}
    /** Set the index within GetText() where the selection starts */
    void                SetSelectionStart(sal_Int32 index) {mnSelectionStart = index;}
    /** Set the index within GetText() where the selection end */
    void                SetSelectionEnd(sal_Int32 index) {mnSelectionEnd = index;}

    virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell, int nDepth) override;
    virtual void Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;
    virtual void CreateTextFromNode(OUStringBuffer &rText) override;

    virtual void  GetAccessibleText( OUStringBuffer &rText ) const override;
    void Accept(SmVisitor* pVisitor) override;
    /**
      Converts the character from StarMath's private area symbols to a matching Unicode
      character, if necessary. To be used when converting GetText() to a normal text.
    */
     * Returns the font type being used (text, variabla, symbol, ...).
     * @retutn font type
     */
    sal_uInt16 GetFontDesc() const { return mnFontDesc; }

    /**
     * Sets the font type to fontdesc.
     * Definitions are on format.hxx.
     * @param fontdesc
     * @return
     */
    void SetFontDesc(sal_uInt16 fontdesc) { mnFontDesc=fontdesc; }

    /**
     * Sets the node text to rText.
     * @param rText
     * @return
     */
    void SetText(const OUString &rText) { maText = rText; }

    /**
     * Gets the node text.
     * @return node text
     */
    const OUString & GetText() const { return maText; }
          OUString & GetText()       { return maText; }

    /**
     * Change the text of this node, including the underlying token to rText.
     * @param rText
     * @return
     */
    void ChangeText(const OUString &rText);

    /**
     * Try to guess the correct FontDesc, used during visual editing
     * @return
     */
    void AdjustFontDesc();

    /**
     * Index within GetText() where the selection starts.
     * @remarks Only valid of SmNode::IsSelected() is true.
     * @return index.
     */
    sal_Int32 GetSelectionStart() const { return mnSelectionStart; }

    /**
     * Index within GetText() where the selection ends.
     * @remarks Only valid of SmNode::IsSelected() is true.
     * @return index.
     */
    sal_Int32 GetSelectionEnd() const  {return mnSelectionEnd; }

    /**
     * Sets the index within GetText() where the selection starts to index.
     * @param index
     * @return
     */
    void SetSelectionStart(sal_Int32 index) {mnSelectionStart = index;}

    /**
     * Sets the index within GetText() where the selection ends to index.
     * @param index
     * @return
     */
    void SetSelectionEnd(sal_Int32 index) {mnSelectionEnd = index;}

    /**
     * Prepare preliminary settings about font and text
     * (e.g. maFace, meRectHorAlign, mnFlags, mnAttributes, etc.)
     * @param rFormat
     * @param rDocShell
     * @param nDepth
     * @return
     */
    virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell,
                         int nDepth) override;

    /**
     * Prepares the SmRect to render.
     * @param rDev
     * @param rFormat
     * @return
     */
    virtual void Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;

    /**
     * Appends to rText the node text.
     * @param rText
     * @return
     */
    virtual void  GetAccessibleText( OUStringBuffer &rText ) const override;

    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    void Accept(SmVisitor* pVisitor) override;

    /**
     * Converts the character from StarMath's private area symbols to a matching Unicode
     * character, if necessary. To be used when converting GetText() to a normal text.
     * @param nIn
     * @return unicode char
     */
    static sal_Unicode ConvertSymbolToUnicode(sal_Unicode nIn);
};

@@ -443,9 +824,31 @@ protected:
public:
    explicit SmSpecialNode(const SmToken &rNodeToken);

    virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell, int nDepth) override;
    /**
     * Prepare preliminary settings about font and text
     * (e.g. maFace, meRectHorAlign, mnFlags, mnAttributes, etc.)
     * @param rFormat
     * @param rDocShell
     * @param nDepth
     * @return
     */
    virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell,
                         int nDepth) override;

    /**
     * Prepares the SmRect to render.
     * @param rDev
     * @param rFormat
     * @return
     */
    virtual void Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;

    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    void Accept(SmVisitor* pVisitor) override;
};

@@ -466,7 +869,20 @@ public:
        : SmSpecialNode(SmNodeType::GlyphSpecial, rNodeToken, FNT_MATH)
    {}

    /**
     * Prepares the SmRect to render.
     * @param rDev
     * @param rFormat
     * @return
     */
    virtual void Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;

    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    void Accept(SmVisitor* pVisitor) override;
};

@@ -482,19 +898,41 @@ protected:
    :   SmSpecialNode(eNodeType, rNodeToken, FNT_MATH)
    {
        sal_Unicode cChar = GetToken().cMathChar;
        if (u'\0' != cChar)
            SetText(OUString(cChar));
        if (u'\0' != cChar) SetText(OUString(cChar));
    }

public:
    explicit SmMathSymbolNode(const SmToken &rNodeToken);

    //visual stuff TODO comment
    virtual void AdaptToX(OutputDevice &rDev, sal_uLong nWidth) override;
    virtual void AdaptToY(OutputDevice &rDev, sal_uLong nHeight) override;

    virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell, int nDepth) override;
    /**
     * Prepare preliminary settings about font and text
     * (e.g. maFace, meRectHorAlign, mnFlags, mnAttributes, etc.)
     * @param rFormat
     * @param rDocShell
     * @param nDepth
     * @return
     */
    virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell,
                         int nDepth) override;

    /**
     * Prepares the SmRect to render.
     * @param rDev
     * @param rFormat
     * @return
     */
    virtual void Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;
    void CreateTextFromNode(OUStringBuffer &rText) override;

    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    void Accept(SmVisitor* pVisitor) override;
};

@@ -526,14 +964,25 @@ class SmRootSymbolNode final : public SmMathSymbolNode
public:
    explicit SmRootSymbolNode(const SmToken &rNodeToken)
        : SmMathSymbolNode(SmNodeType::RootSymbol, rNodeToken)
        , mnBodyWidth(0)
    {
    }
        , mnBodyWidth(0) { }

    /**
     * Gets the body width.
     * Allows to know how long is the root and paint it.
     * @return body width
     */
    sal_uLong GetBodyWidth() const {return mnBodyWidth;};

    //visual stuff TODO comment
    virtual void AdaptToX(OutputDevice &rDev, sal_uLong nHeight) override;
    virtual void AdaptToY(OutputDevice &rDev, sal_uLong nHeight) override;

    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    void Accept(SmVisitor* pVisitor) override;
};

@@ -548,13 +997,34 @@ class SmPlaceNode final : public SmMathSymbolNode
{
public:
    explicit SmPlaceNode(const SmToken &rNodeToken)
        : SmMathSymbolNode(SmNodeType::Place, rNodeToken)
    {
    }
    SmPlaceNode() : SmMathSymbolNode(SmNodeType::Place, SmToken(TPLACE, MS_PLACE, "<?>")) {};
        : SmMathSymbolNode(SmNodeType::Place, rNodeToken) { }
    SmPlaceNode() : SmMathSymbolNode(SmNodeType::Place, SmToken(TPLACE, MS_PLACE, "<?>")) { };

    virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell, int nDepth) override;
    /**
     * Prepare preliminary settings about font and text
     * (e.g. maFace, meRectHorAlign, mnFlags, mnAttributes, etc.)
     * @param rFormat
     * @param rDocShell
     * @param nDepth
     * @return
     */
    virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell,
                         int nDepth) override;

    /**
     * Prepares the SmRect to render.
     * @param rDev
     * @param rFormat
     * @return
     */
    virtual void Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;

    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    void Accept(SmVisitor* pVisitor) override;
};

@@ -568,13 +1038,33 @@ class SmErrorNode final : public SmMathSymbolNode
{
public:
    explicit SmErrorNode(const SmToken &rNodeToken)
        : SmMathSymbolNode(SmNodeType::Error, rNodeToken)
    {
        SetText(OUString(MS_ERROR));
    }
                : SmMathSymbolNode(SmNodeType::Error, rNodeToken) { SetText(OUString(MS_ERROR)); }

    virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell, int nDepth) override;
    /**
     * Prepare preliminary settings about font and text
     * (e.g. maFace, meRectHorAlign, mnFlags, mnAttributes, etc.)
     * @param rFormat
     * @param rDocShell
     * @param nDepth
     * @return
     */
    virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell,
                         int nDepth) override;

    /**
     * Prepares the SmRect to render.
     * @param rDev
     * @param rFormat
     * @return
     */
    virtual void Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;

    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    void Accept(SmVisitor* pVisitor) override;
};

@@ -592,15 +1082,30 @@ class SmTableNode final : public SmStructureNode
public:
    explicit SmTableNode(const SmToken &rNodeToken)
        : SmStructureNode(SmNodeType::Table, rNodeToken)
        , mnFormulaBaseline(0)
    {
    }
        , mnFormulaBaseline(0) { }

    virtual const SmNode * GetLeftMost() const override;

    /**
     * Prepares the SmRect to render.
     * @param rDev
     * @param rFormat
     * @return
     */
    virtual void Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;

    /**
     * Gets the formula baseline.
     * @return formula baseline
     */
    long GetFormulaBaseline() const;

    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    void Accept(SmVisitor* pVisitor) override;
};

@@ -617,22 +1122,55 @@ class SmLineNode : public SmStructureNode
protected:
    SmLineNode(SmNodeType eNodeType, const SmToken &rNodeToken)
        : SmStructureNode(eNodeType, rNodeToken)
        , mbUseExtraSpaces(true)
    {
    }
        , mbUseExtraSpaces(true) { }

public:
    explicit SmLineNode(const SmToken &rNodeToken)
        : SmStructureNode(SmNodeType::Line, rNodeToken)
        , mbUseExtraSpaces(true)
    {
    }
        , mbUseExtraSpaces(true) { }

    /**
     * Sets if it going to use extra spaces.
     * It is used to set if there has to be space between node while rendering.
     * By default it is true.
     * @param bVal
     * @return
     */
    void  SetUseExtraSpaces(bool bVal) { mbUseExtraSpaces = bVal; }

    /**
     * Checks if it is using extra spaces.
     * It is used for calculating space between nodes when rendering.
     * By default it is true.
     * @return is using extra spaces
     */
    bool  IsUseExtraSpaces() const { return mbUseExtraSpaces; };

    virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell, int nDepth) override;
    /**
     * Prepare preliminary settings about font and text
     * (e.g. maFace, meRectHorAlign, mnFlags, mnAttributes, etc.)
     * @param rFormat
     * @param rDocShell
     * @param nDepth
     * @return
     */
    virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell,
                         int nDepth) override;

    /**
     * Prepares the SmRect to render.
     * @param rDev
     * @param rFormat
     * @return
     */
    virtual void Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;

    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    void Accept(SmVisitor* pVisitor) override;
};

@@ -647,11 +1185,22 @@ class SmExpressionNode final : public SmLineNode
{
public:
    explicit SmExpressionNode(const SmToken &rNodeToken)
        : SmLineNode(SmNodeType::Expression, rNodeToken)
    {}
        : SmLineNode(SmNodeType::Expression, rNodeToken) { }

    /**
     * Prepares the SmRect to render.
     * @param rDev
     * @param rFormat
     * @return
     */
    virtual void Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;
    void CreateTextFromNode(OUStringBuffer &rText) override;

    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    void Accept(SmVisitor* pVisitor) override;
};

@@ -664,11 +1213,22 @@ class SmUnHorNode final : public SmStructureNode
{
public:
    explicit SmUnHorNode(const SmToken &rNodeToken)
        : SmStructureNode(SmNodeType::UnHor, rNodeToken, 2)
    {
    }
        : SmStructureNode(SmNodeType::UnHor, rNodeToken, 2) { }

    /**
     * Prepares the SmRect to render.
     * @param rDev
     * @param rFormat
     * @return
     */
    virtual void Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;

    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    void Accept(SmVisitor* pVisitor) override;
};

@@ -688,20 +1248,49 @@ class SmRootNode final : public SmStructureNode
{
public:
    explicit SmRootNode(const SmToken &rNodeToken)
        : SmStructureNode(SmNodeType::Root, rNodeToken, 3)
    {
    }
        : SmStructureNode(SmNodeType::Root, rNodeToken, 3) { }

    /**
     * Prepares the SmRect to render.
     * @param rDev
     * @param rFormat
     * @return
     */
    virtual void Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;
    void CreateTextFromNode(OUStringBuffer &rText) override;

    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    void Accept(SmVisitor* pVisitor) override;

    SmNode* Argument();
    const SmNode* Argument() const;
    SmRootSymbolNode* Symbol();
    const SmRootSymbolNode* Symbol() const;
    SmNode* Body();
    const SmNode* Body() const;
    /**
     * Returns the node containing the data of the order of the root.
     * @return order data
     */
    const SmNode* Argument() const { return const_cast<SmRootNode *>(this)->Argument(); }
          SmNode* Argument()       { assert( GetNumSubNodes() == 3 ); return GetSubNode( 0 ); }

    /**
     * Returns the node containing the data of the character used for the root.
     * @return symbol data
     */
    const SmRootSymbolNode* Symbol() const { return const_cast<SmRootNode *>(this)->Symbol(); }
          SmRootSymbolNode* Symbol()       { assert( GetNumSubNodes() == 3 );
                                             assert( GetSubNode( 1 )->GetType()
                                                        == SmNodeType::RootSymbol );
                                             return static_cast< SmRootSymbolNode* >
                                                ( GetSubNode( 1 )); }

    /**
     * Returns the node containing the data inside the root.
     * @return body data
     */
    const SmNode* Body() const { return const_cast<SmRootNode *>(this)->Body(); }
          SmNode* Body()       { assert( GetNumSubNodes() == 3 ); return GetSubNode( 2 ); }

};


@@ -720,19 +1309,44 @@ class SmBinHorNode final : public SmStructureNode
{
public:
    explicit SmBinHorNode(const SmToken &rNodeToken)
        : SmStructureNode(SmNodeType::BinHor, rNodeToken, 3)
    {
    }
        : SmStructureNode(SmNodeType::BinHor, rNodeToken, 3) { }

    /**
     * Prepares the SmRect to render.
     * @param rDev
     * @param rFormat
     * @return
     */
    virtual void Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;

    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    void Accept(SmVisitor* pVisitor) override;

    SmNode* Symbol();
    const SmNode* Symbol() const;
    SmNode* LeftOperand();
    const SmNode* LeftOperand() const;
    SmNode* RightOperand();
    const SmNode* RightOperand() const;
    /**
     * Returns the node containing the data of the binary opperator.
     * @return symbol data
     */
    const SmNode* Symbol() const { return const_cast<SmBinHorNode *>(this)->Symbol(); }
          SmNode* Symbol()       { assert( GetNumSubNodes() == 3 ); return GetSubNode( 1 ); }

    /**
     * Returns the node containing the data of the left opperand.
     * @return left opperand data
     */
    const SmNode* LeftOperand() const { return const_cast<SmBinHorNode *>(this)->LeftOperand(); }
          SmNode* LeftOperand()       { assert( GetNumSubNodes() == 3 ); return GetSubNode( 0 ); }

    /**
     * Returns the node containing the data of the right opperand.
     * @return right opperand data
     */
    const SmNode* RightOperand() const { return const_cast<SmBinHorNode *>(this)->RightOperand(); }
          SmNode* RightOperand()       { assert( GetNumSubNodes() == 3 ); return GetSubNode( 2 ); }
};


@@ -752,14 +1366,24 @@ class SmBinVerNode final : public SmStructureNode
{
public:
    explicit SmBinVerNode(const SmToken &rNodeToken)
        : SmStructureNode(SmNodeType::BinVer, rNodeToken, 3)
    {
    }
        : SmStructureNode(SmNodeType::BinVer, rNodeToken, 3) { }

    virtual const SmNode * GetLeftMost() const override;

    /**
     * Prepares the SmRect to render.
     * @param rDev
     * @param rFormat
     * @return
     */
    virtual void Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;
    void CreateTextFromNode(OUStringBuffer &rText) override;

    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    void Accept(SmVisitor* pVisitor) override;
};

@@ -778,20 +1402,56 @@ class SmBinDiagonalNode final : public SmStructureNode
{
    bool mbAscending;

    void    GetOperPosSize(Point &rPos, Size &rSize,
                           const Point &rDiagPoint, double fAngleDeg) const;
    /**
     * Returns the position and size of the diagonal line by reference.
     * @param rPos
     * @param rSize
     * @param rDiagPoint
     * @param fAngleDeg
     * @return position and size of the diagonal line
     */
    void GetOperPosSize(Point &rPos, Size &rSize, const Point &rDiagPoint, double fAngleDeg) const;

public:
    explicit SmBinDiagonalNode(const SmToken &rNodeToken)
        : SmStructureNode(SmNodeType::BinDiagonal, rNodeToken, 3)
        , mbAscending(false)
    {
    }
        , mbAscending(false) { }

    /**
     * Checks if it is of ascending type.
     * Ascending:
     *     / b
     *    /
     * a /
     * Descending:
     * a \
     *    \
     *     \ b
     * @return ascending.
     */
    bool    IsAscending() const { return mbAscending; }

    /**
     * Sets if the wideslash is ascending to bVal.
     * @param bVal
     * @return
     */
    void    SetAscending(bool bVal)  { mbAscending = bVal; }

    /**
     * Prepares the SmRect to render.
     * @param rDev
     * @param rFormat
     * @return
     */
    virtual void Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;

    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    void Accept(SmVisitor* pVisitor) override;
};

@@ -843,33 +1503,68 @@ class SmSubSupNode final : public SmStructureNode
public:
    explicit SmSubSupNode(const SmToken &rNodeToken)
        : SmStructureNode(SmNodeType::SubSup, rNodeToken, 1 + SUBSUP_NUM_ENTRIES)
        , mbUseLimits(false)
    {
    }
        , mbUseLimits(false) { }

    /** Get body (Not NULL) */
    SmNode *       GetBody()    { return GetSubNode(0); }
    /** Get body (Not NULL) */
    const SmNode * GetBody() const
    {
        return const_cast<SmSubSupNode *>(this)->GetBody();
    }
    /**
     * Returns the node with the data of what has to be superindex or subindex.
     * @return body data
     */
    const SmNode * GetBody() const { return const_cast<SmSubSupNode *>(this)->GetBody(); }
          SmNode * GetBody()       { return GetSubNode(0); }

    void  SetUseLimits(bool bVal) { mbUseLimits = bVal; }
    /**
     * Checks if it is going to be used for a limit.
     * Example lim from { x towar 0 } { {sin x}over x } = 1
     * @return is a limit
     */
    bool  IsUseLimits() const { return mbUseLimits; };

    /** Get super- or subscript
     * @remarks this method may return NULL.
    /**
     * Sets if it is going to be used for a limit to bVal.
     * @param bVal
     * @return
     */
    SmNode * GetSubSup(SmSubSup eSubSup) { return GetSubNode(1 + eSubSup); };
    const SmNode * GetSubSup(SmSubSup eSubSup) const { return const_cast< SmSubSupNode* >( this )->GetSubSup( eSubSup ); }
    void  SetUseLimits(bool bVal) { mbUseLimits = bVal; }

    /** Set the body */
    /**
     * Gets the node with the data of what has to be superindex or subindex.
     * The position to check is given by eSubSup.
     * @remarks this method may return NULL.
     * @param eSubSup
     * @return body data
     */
     const SmNode * GetSubSup(SmSubSup eSubSup) const { return const_cast< SmSubSupNode* >
                                                            ( this )->GetSubSup( eSubSup ); }
           SmNode * GetSubSup(SmSubSup eSubSup)       { return GetSubNode(1 + eSubSup); };

    /**
     * Sets the node with the data of what has to be superindex or subindex.
     * @param pScript
     */
    void SetBody(SmNode* pBody) { SetSubNode(0, pBody); }

     /**
     * Sets the node with the data of what has to be superindex or subindex.
     * The position to check is given by eSubSup.
     * @param eSubSup
     * @param pScript
     */
    void SetSubSup(SmSubSup eSubSup, SmNode* pScript) { SetSubNode( 1 + eSubSup, pScript); }

    /**
     * Prepares the SmRect to render.
     * @param rDev
     * @param rFormat
     * @return
     */
    virtual void Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;
    void CreateTextFromNode(OUStringBuffer &rText) override;

    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    void Accept(SmVisitor* pVisitor) override;

};
@@ -892,19 +1587,53 @@ class SmBraceNode final : public SmStructureNode
{
public:
    explicit SmBraceNode(const SmToken &rNodeToken)
        : SmStructureNode(SmNodeType::Brace, rNodeToken, 3)
    {
    }
        : SmStructureNode(SmNodeType::Brace, rNodeToken, 3) { }

    SmMathSymbolNode* OpeningBrace();
    const SmMathSymbolNode* OpeningBrace() const;
    SmNode* Body();
    const SmNode* Body() const;
    SmMathSymbolNode* ClosingBrace();
    const SmMathSymbolNode* ClosingBrace() const;
    /**
     * Returns the node containing the data of the opening brace.
     * @return opening brace data
     */
    const SmMathSymbolNode* OpeningBrace() const { return const_cast<SmBraceNode *>
                                                       (this)->OpeningBrace(); }
    SmMathSymbolNode* OpeningBrace()             { assert( GetNumSubNodes() == 3 );
                                                   assert( GetSubNode( 0 )->GetType()
                                                               == SmNodeType::Math );
                                                   return static_cast< SmMathSymbolNode* >
                                                       ( GetSubNode( 0 )); }

    /**
     * Returns the node containing the data of what is between braces.
     * @return body data
     */
    const SmNode* Body() const { return const_cast<SmBraceNode *>(this)->Body(); }
    SmNode* Body()             { assert( GetNumSubNodes() == 3 ); return GetSubNode( 1 ); }

    /**
     * Returns the node containing the data of the closing brace.
     * @return closing brace data
     */
    const SmMathSymbolNode* ClosingBrace() const { return const_cast<SmBraceNode *>
                                                       (this)->ClosingBrace(); }
    SmMathSymbolNode* ClosingBrace()             { assert( GetNumSubNodes() == 3 );
                                                   assert( GetSubNode( 2 )->GetType()
                                                               == SmNodeType::Math );
                                                   return static_cast< SmMathSymbolNode* >
                                                       ( GetSubNode( 2 )); }

    /**
     * Prepares the SmRect to render.
     * @param rDev
     * @param rFormat
     * @return
     */
    virtual void Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;
    void CreateTextFromNode(OUStringBuffer &rText) override;

    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    void Accept(SmVisitor* pVisitor) override;
};

@@ -925,12 +1654,23 @@ class SmBracebodyNode final : public SmStructureNode
public:
    explicit SmBracebodyNode(const SmToken &rNodeToken)
        : SmStructureNode(SmNodeType::Bracebody, rNodeToken)
        , mnBodyHeight(0)
    {
    }
        , mnBodyHeight(0) { }

    /**
     * Prepares the SmRect to render.
     * @param rDev
     * @param rFormat
     * @return
     */
    virtual void    Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;
    long GetBodyHeight() const { return mnBodyHeight; }

    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    void Accept(SmVisitor* pVisitor) override;
};

@@ -950,26 +1690,54 @@ public:
class SmVerticalBraceNode final : public SmStructureNode
{
public:
    explicit inline SmVerticalBraceNode(const SmToken &rNodeToken);
    explicit SmVerticalBraceNode(const SmToken &rNodeToken)
    : SmStructureNode(SmNodeType::VerticalBrace, rNodeToken, 3) { }

    SmNode* Body();
    const SmNode* Body() const;
    SmMathSymbolNode* Brace();
    const SmMathSymbolNode* Brace() const;
    SmNode* Script();
    const SmNode* Script() const;
    /**
     * Returns the node containing the data of what the brace is pointing for.
     * body { script }
     * @return body data
     */
    const SmNode* Body() const { return const_cast<SmVerticalBraceNode *>(this)->Body(); }
    SmNode* Body()             { assert( GetNumSubNodes() == 3 ); return GetSubNode( 0 ); }

    virtual void    Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;
    /**
     * Returns the node containing the data of the brace.
     * @return brace data
     */
    const SmMathSymbolNode* Brace() const { return const_cast<SmVerticalBraceNode *>
                                                (this)->Brace(); }
          SmMathSymbolNode* Brace()       { assert( GetNumSubNodes() == 3 );
                                            assert( GetSubNode( 1 )->GetType()
                                                        == SmNodeType::Math );
                                            return static_cast< SmMathSymbolNode* >
                                                ( GetSubNode( 1 )); }

    /**
     * Returns the node containing the data of what is in the brace.
     * body { script }
     * @return opening brace data
     */
    const SmNode* Script() const { return const_cast<SmVerticalBraceNode *>(this)->Script(); }
          SmNode* Script()       { assert( GetNumSubNodes() == 3 ); return GetSubNode( 2 ); }

    /**
     * Prepares the SmRect to render.
     * @param rDev
     * @param rFormat
     * @return
     */
    virtual void Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;

    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    void Accept(SmVisitor* pVisitor) override;
};


inline SmVerticalBraceNode::SmVerticalBraceNode(const SmToken &rNodeToken)
    : SmStructureNode(SmNodeType::VerticalBrace, rNodeToken, 3)
{
}


/** Operation Node
 *
 * Used for commands like SUM, INT and similar.
@@ -984,19 +1752,39 @@ class SmOperNode final : public SmStructureNode
{
public:
    explicit SmOperNode(const SmToken &rNodeToken)
        : SmStructureNode(SmNodeType::Oper, rNodeToken, 2)
    {
    }
        : SmStructureNode(SmNodeType::Oper, rNodeToken, 2) { }

    SmNode *       GetSymbol();
    const SmNode * GetSymbol() const
    {
        return const_cast<SmOperNode *>(this)->GetSymbol();
    }
    /**
     * Returns the node with the opperator data
     * @return opperator data
     */
    const SmNode * GetSymbol() const { return const_cast<SmOperNode *>(this)->GetSymbol(); }
          SmNode * GetSymbol();

    /**
     * Returns the height of the node in base to the symbol
     * ( rSymbol contains the opperator data )
     * and the font format ( rFormat ).
     * @param rSymbol
     * @param rFormat
     * @return node's height
     */
    long CalcSymbolHeight(const SmNode &rSymbol, const SmFormat &rFormat) const;

    /**
     * Prepares the SmRect to render.
     * @param rDev
     * @param rFormat
     * @return
     */
    virtual void Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;

    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    void Accept(SmVisitor* pVisitor) override;
};

@@ -1009,10 +1797,22 @@ class SmAlignNode final : public SmStructureNode
{
public:
    explicit SmAlignNode(const SmToken &rNodeToken)
        : SmStructureNode(SmNodeType::Align, rNodeToken)
    {}
        : SmStructureNode(SmNodeType::Align, rNodeToken) { }

    /**
     * Prepares the SmRect to render.
     * @param rDev
     * @param rFormat
     * @return
     */
    virtual void Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;

    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    void Accept(SmVisitor* pVisitor) override;
};

@@ -1031,17 +1831,37 @@ class SmAttributNode final : public SmStructureNode
{
public:
    explicit SmAttributNode(const SmToken &rNodeToken)
        : SmStructureNode(SmNodeType::Attribut, rNodeToken, 2)
    {}
        : SmStructureNode(SmNodeType::Attribut, rNodeToken, 2) {}

    /**
     * Prepares the SmRect to render.
     * @param rDev
     * @param rFormat
     * @return
     */
    virtual void Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;
    void CreateTextFromNode(OUStringBuffer &rText) override;

    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    void Accept(SmVisitor* pVisitor) override;

    SmNode* Attribute();
    const SmNode* Attribute() const;
    SmNode* Body();
    const SmNode* Body() const;
    /**
     * Gets the attribute data.
     * @return attribute data
     */
    const SmNode* Attribute() const { return const_cast<SmAttributNode *>(this)->Attribute(); }
          SmNode* Attribute()       { assert( GetNumSubNodes() == 2 ); return GetSubNode( 0 ); }

    /**
     * Gets the body data ( the nodes affected by the attribute ).
     * @return body data
     */
    const SmNode* Body() const { return const_cast<SmAttributNode *>(this)->Body(); }
          SmNode* Body()      { assert( GetNumSubNodes() == 2 ); return GetSubNode( 1 ); }
};


@@ -1058,17 +1878,56 @@ public:
    explicit SmFontNode(const SmToken &rNodeToken)
        : SmStructureNode(SmNodeType::Font, rNodeToken)
        , meSizeType(FontSizeType::MULTIPLY)
        , maFontSize(1)
    {
    }
        , maFontSize(1) { }

    void SetSizeParameter(const Fraction &rValue, FontSizeType nType);
    /**
     * Sets font size to rValue in nType mode.
     * Check FontSizeType for details.
     * @param rValue
     * @param nType
     * @return
     */
    void SetSizeParameter(const Fraction &rValue, FontSizeType nType)
                            { meSizeType = nType; maFontSize = rValue; }

    /**
     * Returns the font size.
     * @return font size.
     */
    const Fraction & GetSizeParameter() const {return maFontSize;}

    /**
     * Returns the font size type.
     * Check FontSizeType for details.
     * @return font size type.
     */
    FontSizeType GetSizeType() const {return meSizeType;}

    virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell, int nDepth) override;
    /**
     * Prepare preliminary settings about font and text
     * (e.g. maFace, meRectHorAlign, mnFlags, mnAttributes, etc.)
     * @param rFormat
     * @param rDocShell
     * @param nDepth
     * @return
     */
    virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell,
                         int nDepth) override;

    /**
     * Prepares the SmRect to render.
     * @param rDev
     * @param rFormat
     * @return
     */
    virtual void Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;
    void CreateTextFromNode(OUStringBuffer &rText) override;

    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    void Accept(SmVisitor* pVisitor) override;
};

@@ -1087,18 +1946,45 @@ public:
    explicit SmMatrixNode(const SmToken &rNodeToken)
        : SmStructureNode(SmNodeType::Matrix, rNodeToken)
        , mnNumRows(0)
        , mnNumCols(0)
    {
    }
        , mnNumCols(0) { }

    /**
     * Gets the number of rows of the matrix.
     * @return rows number
     */
    sal_uInt16 GetNumRows() const {return mnNumRows;}

    /**
     * Gets the number of columns of the matrix.
     * @return columns number
     */
    sal_uInt16 GetNumCols() const {return mnNumCols;}
    void SetRowCol(sal_uInt16 nMatrixRows, sal_uInt16 nMatrixCols);

    /**
     * Sets the dimensions of the matrix.
     * @param nMatrixRows
     * @param nMatrixCols
     * @return
     */
    void SetRowCol(sal_uInt16 nMatrixRows, sal_uInt16 nMatrixCols)
                     { mnNumRows = nMatrixRows; mnNumCols = nMatrixCols; }

    virtual const SmNode * GetLeftMost() const override;

    /**
     * Prepares the SmRect to render.
     * @param rDev
     * @param rFormat
     * @return
     */
    virtual void Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;
    void CreateTextFromNode(OUStringBuffer &rText) override;

    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    void Accept(SmVisitor* pVisitor) override;
};

@@ -1114,158 +2000,42 @@ class SmBlankNode final : public SmGraphicNode
public:
    explicit SmBlankNode(const SmToken &rNodeToken)
        : SmGraphicNode(SmNodeType::Blank, rNodeToken)
        , mnNum(0)
    {
    }
        , mnNum(0) { }

    void         IncreaseBy(const SmToken &rToken, sal_uInt32 nMultiplyBy = 1);
    void         Clear() { mnNum = 0; }
    sal_uInt16   GetBlankNum() const { return mnNum; }
    void         SetBlankNum(sal_uInt16 nNumber) { mnNum = nNumber; }

    virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell, int nDepth) override;
    /**
     * Prepare preliminary settings about font and text
     * (e.g. maFace, meRectHorAlign, mnFlags, mnAttributes, etc.)
     * @param rFormat
     * @param rDocShell
     * @param nDepth
     * @return
     */
    virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell,
                         int nDepth) override;

    /**
     * Prepares the SmRect to render.
     * @param rDev
     * @param rFormat
     * @return
     */
    virtual void Arrange(OutputDevice &rDev, const SmFormat &rFormat) override;

    /**
     * Accept a visitor.
     * Calls the method for this class on the visitor.
     * @param pVisitor
     * @return
     */
    void Accept(SmVisitor* pVisitor) override;
    virtual void CreateTextFromNode(OUStringBuffer &rText) override;

};


inline SmNode* SmRootNode::Argument()
{
    assert( GetNumSubNodes() == 3 );
    return GetSubNode( 0 );
}
inline const SmNode* SmRootNode::Argument() const
{
    return const_cast< SmRootNode* >( this )->Argument();
}
inline SmRootSymbolNode* SmRootNode::Symbol()
{
    assert( GetNumSubNodes() == 3 );
    assert( GetSubNode( 1 )->GetType() == SmNodeType::RootSymbol );
    return static_cast< SmRootSymbolNode* >( GetSubNode( 1 ));
}
inline const SmRootSymbolNode* SmRootNode::Symbol() const
{
    return const_cast< SmRootNode* >( this )->Symbol();
}
inline SmNode* SmRootNode::Body()
{
    assert( GetNumSubNodes() == 3 );
    return GetSubNode( 2 );
}
inline const SmNode* SmRootNode::Body() const
{
    return const_cast< SmRootNode* >( this )->Body();
}


inline SmNode* SmBinHorNode::Symbol()
{
    assert( GetNumSubNodes() == 3 );
    return GetSubNode( 1 );
}
inline const SmNode* SmBinHorNode::Symbol() const
{
    return const_cast< SmBinHorNode* >( this )->Symbol();
}
inline SmNode* SmBinHorNode::LeftOperand()
{
    assert( GetNumSubNodes() == 3 );
    return GetSubNode( 0 );
}
inline const SmNode* SmBinHorNode::LeftOperand() const
{
    return const_cast< SmBinHorNode* >( this )->LeftOperand();
}
inline SmNode* SmBinHorNode::RightOperand()
{
    assert( GetNumSubNodes() == 3 );
    return GetSubNode( 2 );
}
inline const SmNode* SmBinHorNode::RightOperand() const
{
    return const_cast< SmBinHorNode* >( this )->RightOperand();
}

inline SmNode* SmAttributNode::Attribute()
{
    assert( GetNumSubNodes() == 2 );
    return GetSubNode( 0 );
}
inline const SmNode* SmAttributNode::Attribute() const
{
    return const_cast< SmAttributNode* >( this )->Attribute();
}
inline SmNode* SmAttributNode::Body()
{
    assert( GetNumSubNodes() == 2 );
    return GetSubNode( 1 );
}
inline const SmNode* SmAttributNode::Body() const
{
    return const_cast< SmAttributNode* >( this )->Body();
}

inline SmMathSymbolNode* SmBraceNode::OpeningBrace()
{
    assert( GetNumSubNodes() == 3 );
    assert( GetSubNode( 0 )->GetType() == SmNodeType::Math );
    return static_cast< SmMathSymbolNode* >( GetSubNode( 0 ));
}
inline const SmMathSymbolNode* SmBraceNode::OpeningBrace() const
{
    return const_cast< SmBraceNode* >( this )->OpeningBrace();
}
inline SmNode* SmBraceNode::Body()
{
    assert( GetNumSubNodes() == 3 );
    return GetSubNode( 1 );
}
inline const SmNode* SmBraceNode::Body() const
{
    return const_cast< SmBraceNode* >( this )->Body();
}
inline SmMathSymbolNode* SmBraceNode::ClosingBrace()
{
    assert( GetNumSubNodes() == 3 );
    assert( GetSubNode( 2 )->GetType() == SmNodeType::Math );
    return static_cast< SmMathSymbolNode* >( GetSubNode( 2 ));
}
inline const SmMathSymbolNode* SmBraceNode::ClosingBrace() const
{
    return const_cast< SmBraceNode* >( this )->ClosingBrace();
}

inline SmNode* SmVerticalBraceNode::Body()
{
    assert( GetNumSubNodes() == 3 );
    return GetSubNode( 0 );
}
inline const SmNode* SmVerticalBraceNode::Body() const
{
    return const_cast< SmVerticalBraceNode* >( this )->Body();
}
inline SmMathSymbolNode* SmVerticalBraceNode::Brace()
{
    assert( GetNumSubNodes() == 3 );
    assert( GetSubNode( 1 )->GetType() == SmNodeType::Math );
    return static_cast< SmMathSymbolNode* >( GetSubNode( 1 ));
}
inline const SmMathSymbolNode* SmVerticalBraceNode::Brace() const
{
    return const_cast< SmVerticalBraceNode* >( this )->Brace();
}
inline SmNode* SmVerticalBraceNode::Script()
{
    assert( GetNumSubNodes() == 3 );
    return GetSubNode( 2 );
}
inline const SmNode* SmVerticalBraceNode::Script() const
{
    return const_cast< SmVerticalBraceNode* >( this )->Script();
}

#endif


diff --git a/starmath/inc/visitors.hxx b/starmath/inc/visitors.hxx
index 3f903ab..1591d37 100644
--- a/starmath/inc/visitors.hxx
+++ b/starmath/inc/visitors.hxx
@@ -438,21 +438,37 @@ public:
    void Visit( SmRectangleNode* pNode ) override;
    void Visit( SmVerticalBraceNode* pNode ) override;
private:
    /** Extract text from a pNode that constitutes a line */

    /**
      * Extract text from a pNode that constitutes a line.
      * @param pNode
      * @return
      */
    void LineToText( SmNode* pNode ) {
        Separate( );
        if( pNode )
            pNode->Accept( this );
        if( pNode ) pNode->Accept( this );
        Separate( );
    }

    /**
      * Appends rText to the OUStringBuffer ( maCmdText ).
      * @param rText
      * @return
      */
    void Append( const OUString &rText ) {
        maCmdText.append( rText );
    }
    /** Append a blank for separation, if needed */

    /**
     * Append a blank for separation, if needed.
     * It is needed if last char is not ' '.
     * @return
     */
    void Separate( ){
        if( maCmdText.isEmpty() || maCmdText[ maCmdText.getLength() - 1 ] != ' ' )
        if( !maCmdText.isEmpty() && maCmdText[ maCmdText.getLength() - 1 ] != ' ' )
            maCmdText.append(' ');
    }

    /** Output text generated from the pNodes */
    OUStringBuffer maCmdText;
};
diff --git a/starmath/qa/cppunit/test_cursor.cxx b/starmath/qa/cppunit/test_cursor.cxx
index 200af93..8cf0bce 100644
--- a/starmath/qa/cppunit/test_cursor.cxx
+++ b/starmath/qa/cppunit/test_cursor.cxx
@@ -84,7 +84,7 @@ void Test::testCopyPaste()
    aCursor.Move(pOutputDevice, MoveRight);
    aCursor.Paste();

    CPPUNIT_ASSERT_EQUAL(OUString(" { a * b + c * b } "), xDocShRef->GetText());
    CPPUNIT_ASSERT_EQUAL(OUString("{ a * b + c * b }"), xDocShRef->GetText());
}

void Test::testCopySelectPaste()
@@ -110,7 +110,7 @@ void Test::testCopySelectPaste()
    aCursor.Move(pOutputDevice, MoveRight, false);
    aCursor.Paste();

    CPPUNIT_ASSERT_EQUAL(OUString(" { b + c * b + c } "), xDocShRef->GetText());
    CPPUNIT_ASSERT_EQUAL(OUString("{ b + c * b + c }"), xDocShRef->GetText());
}

void Test::testCutPaste()
@@ -132,7 +132,7 @@ void Test::testCutPaste()
    aCursor.Move(pOutputDevice, MoveRight);
    aCursor.Paste();

    CPPUNIT_ASSERT_EQUAL(OUString(" { a + c * b } "), xDocShRef->GetText());
    CPPUNIT_ASSERT_EQUAL(OUString("{ a + c * b }"), xDocShRef->GetText());
}

void Test::testCutSelectPaste()
@@ -158,7 +158,7 @@ void Test::testCutSelectPaste()
    aCursor.Move(pOutputDevice, MoveRight, false);
    aCursor.Paste();

    CPPUNIT_ASSERT_EQUAL(OUString(" { b + c * } "), xDocShRef->GetText());
    CPPUNIT_ASSERT_EQUAL(OUString("{ b + c * }"), xDocShRef->GetText());
}

CPPUNIT_TEST_SUITE_REGISTRATION(Test);
diff --git a/starmath/qa/cppunit/test_nodetotextvisitors.cxx b/starmath/qa/cppunit/test_nodetotextvisitors.cxx
index 0faf69e..72a78ab 100644
--- a/starmath/qa/cppunit/test_nodetotextvisitors.cxx
+++ b/starmath/qa/cppunit/test_nodetotextvisitors.cxx
@@ -114,16 +114,16 @@ void Test::SimpleUnaryOp()
    parseandparseagain("-+4", "Minus/plus");
    parseandparseagain("neg a", "Boolean 'not'");
    parseandparseagain("fact a", "Factorial");
    parseandparseagain(" - { 1 over 2 } ", "BinVer in Unary 1");
    ParseAndCheck(" - { 1 over 2 } ", " - { 1 over 2 } ", "BinVer in Unary 1");
    parseandparseagain(" { - { 1 over 2 } } ", "BinVer in Unary 2");
    parseandparseagain(" - 1 over 2 ", "Unary in BinVer as numerator 1");
    parseandparseagain(" { - 1 } over 2 ", "Unary in BinVer as numerator 2");
    parseandparseagain(" 1 over - 2 ", "Unary in BinVer as denominator 1");
    parseandparseagain(" 1 over { - 2 } ", "Unary in BinVer as denominator 2");
    parseandparseagain(" 2 { - 1 over 2 } ", "Mixed number with Unary in denominator 1");
    parseandparseagain(" 2 { - 1 } over 2 ", "Mixed number with Unary in denominator 2");
    parseandparseagain(" - 1 + 2 ", "Unary in BinHor");
    parseandparseagain("- { 1 over 2 }", "BinVer in Unary 1");
    ParseAndCheck("- { 1 over 2 }", "- { 1 over 2 }", "BinVer in Unary 1");
    parseandparseagain("{- { 1 over 2 } }", "BinVer in Unary 2");
    parseandparseagain("- 1 over 2", "Unary in BinVer as numerator 1");
    parseandparseagain("{ - 1 } over 2", "Unary in BinVer as numerator 2");
    parseandparseagain("1 over - 2", "Unary in BinVer as denominator 1");
    parseandparseagain("1 over { - 2 }", "Unary in BinVer as denominator 2");
    parseandparseagain("2 { - 1 over 2 }", "Mixed number with Unary in denominator 1");
    parseandparseagain("2 { - 1 } over 2", "Mixed number with Unary in denominator 2");
    parseandparseagain("- 1 + 2", "Unary in BinHor");
}

void Test::SimpleBinaryOp()
@@ -227,8 +227,8 @@ void Test::SimpleOperators()
    parseandparseagain("prod{a}", "Product");
    parseandparseagain("coprod{a}", "Coproduct");
    parseandparseagain("int from {r_0} to {r_t} a", "Upper and lower bounds shown with integral (from & to)");
    ParseAndCheck("int csup {r_0} csub {r_t} a", "int csup { r _ 0 } csub { r _ t } a ", "Upper and lower bounds shown with integral (csub & csup)");
    ParseAndCheck("sum csup { size 8 { x - 1 } } csub { size 8 a } b ", "sum csup { size 8 { x - 1 } } csub { size 8 a } b ", "Sum with sized upper and lower bounds");
    ParseAndCheck("int csup {r_0} csub {r_t} a", "int csup { r _ 0 } csub { r _ t } a", "Upper and lower bounds shown with integral (csub & csup)");
    ParseAndCheck("sum csup { size 8 { x - 1 } } csub { size 8 a } b", "sum csup { size 8 { x - 1 } } csub { size 8 a } b", "Sum with sized upper and lower bounds");
    parseandparseagain("int{a}", "Integral");
    parseandparseagain("intd_{1}^{2}{x dx}", "Dynamically-sized integral");
    parseandparseagain("iint{a}", "Double integral");
@@ -523,7 +523,7 @@ void Test::testBinomInBinHor()
    aCursor.InsertElement(PlusElement);
    aCursor.InsertText("d");

    sExpected += " { { binom a b + c } + d } ";
    sExpected += "{ { binom a b + c } + d }";
    CPPUNIT_ASSERT_EQUAL_MESSAGE("Binom Node in BinHor Node", sExpected, xDocShRef->GetText());
}

@@ -551,7 +551,7 @@ void Test::testBinVerInUnary()
    aCursor.Move(pOutputDevice, MoveDown);
    aCursor.InsertText("2");

    sExpected += " - { 1 over 2 } ";
    sExpected += "- { 1 over 2 }";
    CPPUNIT_ASSERT_EQUAL_MESSAGE("Binary Vertical in Unary Operator", sExpected, xDocShRef->GetText());
}

@@ -576,7 +576,7 @@ void Test::testBinHorInSubSup()
    aCursor.InsertElement(PlusElement);
    aCursor.InsertText("d");

    CPPUNIT_ASSERT_EQUAL_MESSAGE("BinHor in SubSup", OUString(" { a ^ { b + c } + d } "), xDocShRef->GetText());
    CPPUNIT_ASSERT_EQUAL_MESSAGE("BinHor in SubSup", OUString("{ a ^ { b + c } + d }"), xDocShRef->GetText());
}

void Test::testUnaryInMixedNumberAsNumerator()
@@ -615,7 +615,7 @@ void Test::testUnaryInMixedNumberAsNumerator()
    aCursor.InsertElement(PlusElement);
    aCursor.InsertText("4");

    CPPUNIT_ASSERT_EQUAL_MESSAGE("Unary in mixed number as Numerator", OUString(" { 2 { - 1 over 2 } + 4 } "), xDocShRef->GetText());
    CPPUNIT_ASSERT_EQUAL_MESSAGE("Unary in mixed number as Numerator", OUString("{ 2 { - 1 over 2 } + 4 }"), xDocShRef->GetText());
}

void Test::testMiscEquivalent()
diff --git a/starmath/qa/extras/mmlimport-test.cxx b/starmath/qa/extras/mmlimport-test.cxx
index 5ed9bc8..279dbd5 100644
--- a/starmath/qa/extras/mmlimport-test.cxx
+++ b/starmath/qa/extras/mmlimport-test.cxx
@@ -96,66 +96,66 @@ void Test::tearDown()
void Test::testColor()
{
    loadURL(m_directories.getURLFromSrc("starmath/qa/extras/data/color.mml"));
    CPPUNIT_ASSERT_EQUAL(OUString("{{color black b}"
                                  " {color white w}"
                                  " {color red r}"
                                  " {color green g}"
                                  " {color blue b}"
                                  " {color yellow y}"
                                  " {color silver s}"
                                  " {color gray g}"
                                  " {color maroon m}"
                                  " {color purple p}"
                                  " {color lime l}"
                                  " {color olive o}"
                                  " {color navy n}"
                                  " {color teal t}"
                                  " {color aqua a}"
                                  " {color fuchsia f}}"),
    CPPUNIT_ASSERT_EQUAL(OUString("{ color black b"
                                  " color white w"
                                  " color red r"
                                  " color green g"
                                  " color blue b"
                                  " color yellow y"
                                  " color silver s"
                                  " color gray g"
                                  " color maroon m"
                                  " color purple p"
                                  " color lime l"
                                  " color olive o"
                                  " color navy n"
                                  " color teal t"
                                  " color aqua a"
                                  " color fuchsia f }"),
                         mxDocShell->GetText());
}

void Test::testSimple()
{
    loadURL(m_directories.getURLFromSrc("starmath/qa/extras/data/simple.mml"));
    CPPUNIT_ASSERT_EQUAL_MESSAGE("loaded text", OUString("left ( {a + b} right )^2"), mxDocShell->GetText());
    CPPUNIT_ASSERT_EQUAL_MESSAGE("loaded text", OUString("left ( { a + b } right ) ^ 2"), mxDocShell->GetText());
}

void Test::testNsPrefixMath()
{
    loadURL(m_directories.getURLFromSrc("starmath/qa/extras/data/ns-prefix-math.mml"));
    CPPUNIT_ASSERT_EQUAL_MESSAGE("loaded text", OUString("left ( {a + b} right )^2"), mxDocShell->GetText());
    CPPUNIT_ASSERT_EQUAL_MESSAGE("loaded text", OUString("left ( { a + b } right ) ^ 2"), mxDocShell->GetText());
}

void Test::testMaction()
{
    loadURL(m_directories.getURLFromSrc("starmath/qa/extras/data/maction.mml"));
    CPPUNIT_ASSERT_EQUAL_MESSAGE("loaded text", OUString("matrix {1 ## 2 ## 3}"), mxDocShell->GetText());
    CPPUNIT_ASSERT_EQUAL_MESSAGE("loaded text", OUString("matrix{ 1 ## 2 ## 3 }"), mxDocShell->GetText());
}

void Test::testMspace()
{
    loadURL(m_directories.getURLFromSrc("starmath/qa/extras/data/mspace.mml"));
    CPPUNIT_ASSERT_EQUAL(OUString("{a b ~ c ~~``` d}"), mxDocShell->GetText());
    CPPUNIT_ASSERT_EQUAL(OUString("{ a b ~ c ~~``` d }"), mxDocShell->GetText());
}

void Test::testtdf99556()
{
    loadURL(m_directories.getURLFromSrc("starmath/qa/extras/data/tdf99556-1.mml"));
    CPPUNIT_ASSERT_EQUAL_MESSAGE("loaded text", OUString("sqrt { {} }"), mxDocShell->GetText());
    CPPUNIT_ASSERT_EQUAL_MESSAGE("loaded text", OUString("sqrt { }"), mxDocShell->GetText());
}

void Test::testTdf103430()
{
    loadURL(m_directories.getURLFromSrc("starmath/qa/extras/data/tdf103430.mml"));
    CPPUNIT_ASSERT_EQUAL(OUString("{{nitalic d}^2 {nitalic {color blue y}}} over {{nitalic d} {font sans {bold {italic {color red x}}}}}"),
    CPPUNIT_ASSERT_EQUAL(OUString("{ { nitalic d ^ 2 nitalic color blue y } over { nitalic d font sans bold italic color red x } }"),
                         mxDocShell->GetText());
}

void Test::testTdf103500()
{
    loadURL(m_directories.getURLFromSrc("starmath/qa/extras/data/tdf103500.mml"));
    CPPUNIT_ASSERT_EQUAL(OUString("{{ int csub a csup b {1 over x ` {nitalic d} x}} = {intd csub a csup b {1 over y ` {nitalic d} y}}}"),
    CPPUNIT_ASSERT_EQUAL(OUString("{ { int csup b csub a { { 1 over x } ` nitalic d x } } = { intd csup b csub a { { 1 over y } ` nitalic d y } } }"),
                         mxDocShell->GetText());
}

diff --git a/starmath/source/mathmlimport.cxx b/starmath/source/mathmlimport.cxx
index b367b99..76b82a5 100644
--- a/starmath/source/mathmlimport.cxx
+++ b/starmath/source/mathmlimport.cxx
@@ -71,6 +71,7 @@ one go*/
#include <smdll.hxx>
#include <unomodel.hxx>
#include <utility.hxx>
#include <visitors.hxx>

using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::container;
@@ -462,17 +463,13 @@ void SmXMLImport::endDocument()

        if (pModel)
        {
            SmDocShell *pDocShell =
                static_cast<SmDocShell*>(pModel->GetObjectShell());
            SmDocShell *pDocShell = static_cast<SmDocShell*>(pModel->GetObjectShell());
            auto pTreeTmp = pTree.get();
            pDocShell->SetFormulaTree(static_cast<SmTableNode *>(pTree.release()));
            if (aText.isEmpty())  //If we picked up no annotation text
            {
                OUStringBuffer aStrBuf;
                // Get text from imported formula
                pTreeTmp->CreateTextFromNode(aStrBuf);
                aStrBuf.stripEnd(' ');
                aText = aStrBuf.makeStringAndClear();
                SmNodeToTextVisitor tmpvisitor( pTreeTmp, aText );
            }

            // Convert symbol names
diff --git a/starmath/source/node.cxx b/starmath/source/node.cxx
index 526b2e3..e894ad8 100644
--- a/starmath/source/node.cxx
+++ b/starmath/source/node.cxx
@@ -140,7 +140,6 @@ void SmNode::SetFont(const SmFace &rFace)
{
    if (!(Flags() & FontChangeMask::Face))
        GetFont() = rFace;

    ForEachNonNull(this, [&rFace](SmNode *pNode){pNode->SetFont(rFace);});
}

@@ -244,27 +243,14 @@ void SmNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell, int n
    ForEachNonNull(this, [&rFormat, &rDocShell, nDepth](SmNode *pNode){pNode->Prepare(rFormat, rDocShell, nDepth + 1);});
}

void SmNode::Move(const Point& rPosition)
void SmNode::Move(const Point& rVector)
{
    if (rPosition.X() == 0  &&  rPosition.Y() == 0)
    if (rVector.X() == 0  &&  rVector.Y() == 0)
        return;

    SmRect::Move(rPosition);
    SmRect::Move(rVector);

    ForEachNonNull(this, [&rPosition](SmNode *pNode){pNode->Move(rPosition);});
}

void SmNode::CreateTextFromNode(OUStringBuffer &rText)
{
    auto nSize = GetNumSubNodes();
    if (nSize > 1)
        rText.append("{");
    ForEachNonNull(this, [&rText](SmNode *pNode){pNode->CreateTextFromNode(rText);});
    if (nSize > 1)
    {
        rText.stripEnd(' ');
        rText.append("} ");
    }
    ForEachNonNull(this, [&rVector](SmNode *pNode){pNode->Move(rVector);});
}

void SmNode::AdaptToX(OutputDevice &/*rDev*/, sal_uLong /*nWidth*/)
@@ -441,6 +427,31 @@ void SmStructureNode::ClaimPaternity()
    ForEachNonNull(this, [this](SmNode *pNode){pNode->SetParent(this);});
}

int SmStructureNode::IndexOfSubNode(SmNode const * pSubNode)
{
    size_t nSize = GetNumSubNodes();
    for (size_t i = 0; i < nSize; i++)
        if (pSubNode == GetSubNode(i))
            return i;
    return -1;
}

void SmStructureNode::SetSubNode(size_t nIndex, SmNode* pNode)
{
    size_t size = maSubNodes.size();
    if (size <= nIndex)
    {
        //Resize subnodes array
        maSubNodes.resize(nIndex + 1);
        //Set new slots to NULL except at nIndex
        for (size_t i = size; i < nIndex; i++)
            maSubNodes[i] = nullptr;
    }
    maSubNodes[nIndex] = pNode;
    if (pNode)
        pNode->SetParent(this);
}

bool SmVisibleNode::IsVisible() const
{
    return true;
@@ -461,32 +472,6 @@ void SmGraphicNode::GetAccessibleText( OUStringBuffer &rText ) const
    rText.append(GetToken().aText);
}

void SmExpressionNode::CreateTextFromNode(OUStringBuffer &rText)
{
    size_t nSize = GetNumSubNodes();
    if (nSize > 1)
        rText.append("{");
    for (size_t i = 0; i < nSize; ++i)
    {
        SmNode *pNode = GetSubNode(i);
        if (pNode)
        {
            pNode->CreateTextFromNode(rText);
            //Just a bit of foo to make unary +asd -asd +-asd -+asd look nice
            if (pNode->GetType() == SmNodeType::Math)
                if ((nSize != 2) || rText.isEmpty() ||
                    (rText[rText.getLength() - 1] != '+' && rText[rText.getLength() - 1] != '-') )
                    rText.append(" ");
        }
    }

    if (nSize > 1)
    {
        rText.stripEnd(' ');
        rText.append("} ");
    }
}

void SmTableNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
    // arranges all subnodes in one column
{
@@ -760,27 +745,6 @@ void SmRootNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
        ExtendBy(*pExtra, RectCopyMBL::This, true);
}


void SmRootNode::CreateTextFromNode(OUStringBuffer &rText)
{
    SmNode *pExtra = GetSubNode(0);
    if (pExtra)
    {
        rText.append("nroot ");
        pExtra->CreateTextFromNode(rText);
    }
    else
        rText.append("sqrt ");

    if (!pExtra && GetSubNode(2)->GetNumSubNodes() > 1)
        rText.append("{ ");

    GetSubNode(2)->CreateTextFromNode(rText);

    if (!pExtra && GetSubNode(2)->GetNumSubNodes() > 1)
        rText.append("} ");
}

/**************************************************************************/


@@ -880,15 +844,6 @@ void SmBinVerNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
    ExtendBy(*pDenom, RectCopyMBL::None).ExtendBy(*pLine, RectCopyMBL::None, pLine->GetCenterY());
}

void SmBinVerNode::CreateTextFromNode(OUStringBuffer &rText)
{
    SmNode *pNum   = GetSubNode(0),
           *pDenom = GetSubNode(2);
    pNum->CreateTextFromNode(rText);
    rText.append("over ");
    pDenom->CreateTextFromNode(rText);
}

const SmNode * SmBinVerNode::GetLeftMost() const
{
    return this;
@@ -1256,100 +1211,8 @@ void SmSubSupNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
    }
}

void SmSubSupNode::CreateTextFromNode(OUStringBuffer &rText)
{
    SmNode *pNode;
    GetSubNode(0)->CreateTextFromNode(rText);

    if (nullptr != (pNode = GetSubNode(LSUB+1)))
    {
        rText.append("lsub ");
        pNode->CreateTextFromNode(rText);
    }
    if (nullptr != (pNode = GetSubNode(LSUP+1)))
    {
        rText.append("lsup ");
        pNode->CreateTextFromNode(rText);
    }
    if (nullptr != (pNode = GetSubNode(CSUB+1)))
    {
        rText.append("csub ");
        pNode->CreateTextFromNode(rText);
    }
    if (nullptr != (pNode = GetSubNode(CSUP+1)))
    {
        rText.append("csup ");
        pNode->CreateTextFromNode(rText);
    }
    if (nullptr != (pNode = GetSubNode(RSUB+1)))
    {
        rText.stripEnd(' ');
        rText.append("_");
        pNode->CreateTextFromNode(rText);
    }
    if (nullptr != (pNode = GetSubNode(RSUP+1)))
    {
        rText.stripEnd(' ');
        rText.append("^");
        pNode->CreateTextFromNode(rText);
    }
}


/**************************************************************************/

void SmBraceNode::CreateTextFromNode(OUStringBuffer &rText)
{
    if (GetScaleMode() == SmScaleMode::Height)
        rText.append("left ");
    {
        OUStringBuffer aStrBuf;
        OpeningBrace()->CreateTextFromNode(aStrBuf);
        OUString aStr = aStrBuf.makeStringAndClear();
        aStr = comphelper::string::strip(aStr, ' ');
        aStr = comphelper::string::stripStart(aStr, '\\');
        if (!aStr.isEmpty())
        {
            if (aStr == "divides")
                rText.append("lline");
            else if (aStr == "parallel")
                rText.append("ldline");
            else if (aStr == "<")
                rText.append("langle");
            else
                rText.append(aStr);
            rText.append(" ");
        }
        else
            rText.append("none ");
    }
    Body()->CreateTextFromNode(rText);
    if (GetScaleMode() == SmScaleMode::Height)
        rText.append("right ");
    {
        OUStringBuffer aStrBuf;
        ClosingBrace()->CreateTextFromNode(aStrBuf);
        OUString aStr = aStrBuf.makeStringAndClear();
        aStr = comphelper::string::strip(aStr, ' ');
        aStr = comphelper::string::stripStart(aStr, '\\');
        if (!aStr.isEmpty())
        {
            if (aStr == "divides")
                rText.append("rline");
            else if (aStr == "parallel")
                rText.append("rdline");
            else if (aStr == ">")
                rText.append("rangle");
            else
                rText.append(aStr);
            rText.append(" ");
        }
        else
            rText.append("none ");
    }
    rText.append(" ");
}

void SmBraceNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
{
    SmNode *pLeft  = OpeningBrace(),
@@ -1716,144 +1579,6 @@ void SmAttributNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
    ExtendBy(*pAttr, RectCopyMBL::This, true);
}

void SmFontNode::CreateTextFromNode(OUStringBuffer &rText)
{
    rText.append("{");
    sal_Int32 nc,r,g,b;

    switch (GetToken().eType)
    {
        case TBOLD:
            rText.append("bold ");
            break;
        case TNBOLD:
            rText.append("nbold ");
            break;
        case TITALIC:
            rText.append("italic ");
            break;
        case TNITALIC:
            rText.append("nitalic ");
            break;
        case TPHANTOM:
            rText.append("phantom ");
            break;
        case TSIZE:
            {
                rText.append("size ");
                switch (meSizeType)
                {
                    case FontSizeType::PLUS:
                        rText.append("+");
                        break;
                    case FontSizeType::MINUS:
                        rText.append("-");
                        break;
                    case FontSizeType::MULTIPLY:
                        rText.append("*");
                        break;
                    case FontSizeType::DIVIDE:
                        rText.append("/");
                        break;
                    case FontSizeType::ABSOLUT:
                    default:
                        break;
                }
                rText.append(::rtl::math::doubleToUString(
                            static_cast<double>(maFontSize),
                            rtl_math_StringFormat_Automatic,
                            rtl_math_DecimalPlaces_Max, '.', true));
                rText.append(" ");
            }
            break;
        case TBLACK:
            rText.append("color black ");
            break;
        case TWHITE:
            rText.append("color white ");
            break;
        case TRED:
            rText.append("color red ");
            break;
        case TGREEN:
            rText.append("color green ");
            break;
        case TBLUE:
            rText.append("color blue ");
            break;
        case TCYAN:
            rText.append("color cyan ");
            break;
        case TMAGENTA:
            rText.append("color magenta ");
            break;
        case TYELLOW:
            rText.append("color yellow ");
            break;
        case TTEAL:
            rText.append("color teal ");
            break;
        case TSILVER:
            rText.append("color silver ");
            break;
        case TGRAY:
            rText.append("color gray ");
            break;
        case TMAROON:
            rText.append("color maroon ");
            break;
        case TPURPLE:
            rText.append("color purple ");
            break;
        case TLIME:
            rText.append("color lime ");
            break;
        case TOLIVE:
            rText.append("color olive ");
            break;
        case TNAVY:
            rText.append("color navy ");
            break;
        case TAQUA:
            rText.append("color aqua ");
            break;
        case TFUCHSIA:
            rText.append("color fuchsia ");
            break;
        case TRGB:
            rText.append("color rgb ");
            nc = GetToken().aText.toInt32();
            b = nc % 256;
            nc /= 256;
            g = nc % 256;
            nc /= 256;
            r = nc % 256;
            rText.append(r);
            rText.append(" ");
            rText.append(g);
            rText.append(" ");
            rText.append(b);
            rText.append(" ");
            break;
        case TSANS:
            rText.append("font sans ");
            break;
        case TSERIF:
            rText.append("font serif ");
            break;
        case TFIXED:
            rText.append("font fixed ");
            break;
        default:
            break;
    }
    if (GetNumSubNodes() > 1)
        GetSubNode(1)->CreateTextFromNode(rText);

    rText.stripEnd(' ');
    rText.append("} ");
}

void SmFontNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell, int nDepth)
{
    //! prepare subnodes first
@@ -1883,7 +1608,7 @@ void SmFontNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
    SmNode *pNode = GetSubNode(1);
    assert(pNode);
    sal_Int32 nc;
    Color col_perso_rgb_color (0);
    Color col_perso_rgb_color = COL_AUTO;

    switch (GetToken().eType)
    {   case TSIZE :
@@ -1902,23 +1627,23 @@ void SmFontNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
        case TNBOLD :   ClearAttribut(FontAttribute::Bold);   break;
        case TNITALIC : ClearAttribut(FontAttribute::Italic); break;

        case TBLACK :   SetColor(COL_BLACK);     break;
        case TWHITE :   SetColor(COL_WHITE);     break;
        case TBLACK :   SetColor(COL_BLACK);         break;
        case TWHITE :   SetColor(COL_WHITE);         break;
        case TRED :     SetColor(COL_LIGHTRED);      break;
        case TGREEN :   SetColor(COL_GREEN);     break;
        case TGREEN :   SetColor(COL_GREEN);         break;
        case TBLUE :    SetColor(COL_LIGHTBLUE);     break;
        case TCYAN :    SetColor(COL_LIGHTCYAN);     break; // as in Calc
        case TMAGENTA : SetColor(COL_LIGHTMAGENTA);  break; // as in Calc
        case TYELLOW :  SetColor(COL_YELLOW);    break;
        case TTEAL :    SetColor(COL_CYAN);  break;
        case TSILVER :  SetColor(COL_LIGHTGRAY);  break;
        case TGRAY :    SetColor(COL_GRAY);  break;
        case TMAROON :  SetColor(COL_RED);  break;
        case TPURPLE :  SetColor(COL_MAGENTA);  break;
        case TLIME :    SetColor(COL_LIGHTGREEN);  break;
        case TOLIVE :   SetColor(COL_BROWN);  break;
        case TNAVY :    SetColor(COL_BLUE);  break;
        case TAQUA :    SetColor(COL_LIGHTCYAN);  break;
        case TYELLOW :  SetColor(COL_YELLOW);        break;
        case TTEAL :    SetColor(COL_CYAN);          break;
        case TSILVER :  SetColor(COL_LIGHTGRAY);     break;
        case TGRAY :    SetColor(COL_GRAY);          break;
        case TMAROON :  SetColor(COL_RED);           break;
        case TPURPLE :  SetColor(COL_MAGENTA);       break;
        case TLIME :    SetColor(COL_LIGHTGREEN);    break;
        case TOLIVE :   SetColor(COL_BROWN);         break;
        case TNAVY :    SetColor(COL_BLUE);          break;
        case TAQUA :    SetColor(COL_LIGHTCYAN);     break;
        case TFUCHSIA : SetColor(COL_LIGHTMAGENTA);  break;
        case TRGB :
            nc = GetToken().aText.toInt32();
@@ -1939,14 +1664,6 @@ void SmFontNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
    SmRect::operator = (pNode->GetRect());
}


void SmFontNode::SetSizeParameter(const Fraction& rValue, FontSizeType eType)
{
    meSizeType = eType;
    maFontSize = rValue;
}


/**************************************************************************/


@@ -2085,6 +1802,12 @@ SmTextNode::SmTextNode( const SmToken &rNodeToken, sal_uInt16 nFontDescP )
{
}

void SmTextNode::ChangeText(const OUString &rText) {
    maText = rText;
    GetToken().aText = rText;
    AdjustFontDesc();
}

void SmTextNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell, int nDepth)
{
    SmNode::Prepare(rFormat, rDocShell, nDepth);
@@ -2125,52 +1848,6 @@ void SmTextNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
    SmRect::operator = (SmRect(aTmpDev, &rFormat, maText, GetFont().GetBorderWidth()));
}

void SmTextNode::CreateTextFromNode(OUStringBuffer &rText)
{
    bool bQuoted=false;
    if (GetToken().eType == TTEXT)
    {
        rText.append("\"");
        bQuoted=true;
    }
    else
    {
        SmParser aParseTest;
        auto pTable = aParseTest.Parse(GetToken().aText);
        assert(pTable->GetType() == SmNodeType::Table);
        bQuoted=true;
        if (pTable->GetNumSubNodes() == 1)
        {
            SmNode *pResult = pTable->GetSubNode(0);
            if ( (pResult->GetType() == SmNodeType::Line) &&
                (pResult->GetNumSubNodes() == 1) )
            {
                pResult = pResult->GetSubNode(0);
                if (pResult->GetType() == SmNodeType::Text)
                    bQuoted=false;
            }
        }

        if ((GetToken().eType == TIDENT) && (GetFontDesc() == FNT_FUNCTION))
        {
            //Search for existing functions and remove extraneous keyword
            rText.append("func ");
        }
        else if (bQuoted)
            rText.append("italic ");

        if (bQuoted)
            rText.append("\"");

    }

    rText.append(GetToken().aText);

    if (bQuoted)
        rText.append("\"");
    rText.append(" ");
}

void SmTextNode::GetAccessibleText( OUStringBuffer &rText ) const
{
    rText.append(maText);
@@ -2183,27 +1860,23 @@ void SmTextNode::AdjustFontDesc()
    else if(GetToken().eType == TFUNC)
        mnFontDesc = FNT_FUNCTION;
    else {
        SmTokenType nTok;
        const SmTokenTableEntry *pEntry = SmParser::GetTokenTableEntry( maText );
        if (pEntry && pEntry->nGroup == TG::Function) {
            nTok = pEntry->eType;
            GetToken().eType = pEntry->eType;
            mnFontDesc = FNT_FUNCTION;
        } else {
            sal_Unicode firstChar = maText[0];
            if( ('0' <= firstChar && firstChar <= '9') || firstChar == '.' || firstChar == ',') {
                mnFontDesc = FNT_NUMBER;
                nTok = TNUMBER;
                GetToken().eType = TNUMBER;
            } else if (maText.getLength() > 1) {
                mnFontDesc = FNT_VARIABLE;
                nTok = TIDENT;
                GetToken().eType = TIDENT;
            } else {
                mnFontDesc = FNT_VARIABLE;
                nTok = TCHARACTER;
                GetToken().eType = TCHARACTER;
            }
        }
        SmToken tok = GetToken();
        tok.eType = nTok;
        SetToken(tok);
    }
}

@@ -2242,26 +1915,6 @@ sal_Unicode SmTextNode::ConvertSymbolToUnicode(sal_Unicode nIn)

/**************************************************************************/

void SmMatrixNode::CreateTextFromNode(OUStringBuffer &rText)
{
    rText.append("matrix {");
    for (size_t i = 0;  i < mnNumRows; ++i)
    {
        for (size_t j = 0;  j < mnNumCols; ++j)
        {
            SmNode *pNode = GetSubNode(i * mnNumCols + j);
            if (pNode)
                pNode->CreateTextFromNode(rText);
            if (j != mnNumCols - 1U)
                rText.append("# ");
        }
        if (i != mnNumRows - 1U)
            rText.append("## ");
    }
    rText.stripEnd(' ');
    rText.append("} ");
}

void SmMatrixNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
{
    SmNode *pNode;
@@ -2360,14 +2013,6 @@ void SmMatrixNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
    }
}


void SmMatrixNode::SetRowCol(sal_uInt16 nMatrixRows, sal_uInt16 nMatrixCols)
{
    mnNumRows = nMatrixRows;
    mnNumCols = nMatrixCols;
}


const SmNode * SmMatrixNode::GetLeftMost() const
{
    return this;
@@ -2481,124 +2126,6 @@ void SmMathSymbolNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
    SmRect::operator = (SmRect(aTmpDev, &rFormat, rText, GetFont().GetBorderWidth()));
}

void SmMathSymbolNode::CreateTextFromNode(OUStringBuffer &rText)
{
    sal_Unicode cChar = GetToken().cMathChar;
    if (cChar == MS_INT && GetScaleMode() == SmScaleMode::Height)
        rText.append("intd ");
    else
        MathType::LookupChar(cChar, rText, 3);
}

void SmRectangleNode::CreateTextFromNode(OUStringBuffer &rText)
{
    switch (GetToken().eType)
    {
    case TUNDERLINE:
        rText.append("underline ");
        break;
    case TOVERLINE:
        rText.append("overline ");
        break;
    case TOVERSTRIKE:
        rText.append("overstrike ");
        break;
    default:
        break;
    }
}

void SmAttributNode::CreateTextFromNode(OUStringBuffer &rText)
{
    SmNode *pNode;
    assert(GetNumSubNodes() == 2);
    rText.append("{");
    sal_Unicode nLast=0;
    if (nullptr != (pNode = Attribute()))
    {
        OUStringBuffer aStr;
        pNode->CreateTextFromNode(aStr);
        if (aStr.getLength() > 1)
            rText.append(aStr);
        else
        {
            nLast = aStr[0];
            switch (nLast)
            {
            case MS_BAR: // MACRON
                rText.append("overline ");
                break;
            case MS_DOT: // DOT ABOVE
                rText.append("dot ");
                break;
            case 0x2dc: // SMALL TILDE
                rText.append("widetilde ");
                break;
            case MS_DDOT: // DIAERESIS
                rText.append("ddot ");
                break;
            case 0xE082:
                break;
            case 0xE09B:
            case MS_DDDOT: // COMBINING THREE DOTS ABOVE
                rText.append("dddot ");
                break;
            case MS_ACUTE: // ACUTE ACCENT
            case MS_COMBACUTE: // COMBINING ACUTE ACCENT
                rText.append("acute ");
                break;
            case MS_GRAVE: // GRAVE ACCENT
            case MS_COMBGRAVE: // COMBINING GRAVE ACCENT
                rText.append("grave ");
                break;
            case MS_CHECK: // CARON
            case MS_COMBCHECK: // COMBINING CARON
                rText.append("check ");
                break;
            case MS_BREVE: // BREVE
            case MS_COMBBREVE: // COMBINING BREVE
                rText.append("breve ");
                break;
            case MS_CIRCLE: // RING ABOVE
            case MS_COMBCIRCLE: // COMBINING RING ABOVE
                rText.append("circle ");
                break;
            case MS_RIGHTARROW: // RIGHTWARDS ARROW
            case MS_VEC: // COMBINING RIGHT ARROW ABOVE
                rText.append("vec ");
                break;
            case MS_HARPOON: // COMBINING RIGHT HARPOON ABOVE
                rText.append("harpoon ");
                break;
            case MS_TILDE: // TILDE
            case MS_COMBTILDE: // COMBINING TILDE
                rText.append("tilde ");
                break;
            case MS_HAT: // CIRCUMFLEX ACCENT
            case MS_COMBHAT: // COMBINING CIRCUMFLEX ACCENT
                rText.append("hat ");
                break;
            case MS_COMBBAR: // COMBINING MACRON
                rText.append("bar ");
                break;
            default:
                rText.append(OUStringChar(nLast));
                break;
            }
        }
    }

    if (nullptr != (pNode = Body()))
        pNode->CreateTextFromNode(rText);

    rText.stripEnd(' ');

    if (nLast == 0xE082)
        rText.append(" overbrace {}");

    rText.append("} ");
}

/**************************************************************************/

static bool lcl_IsFromGreekSymbolSet( const OUString &rTokenText )
@@ -2812,20 +2339,6 @@ void SmBlankNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
    SetWidth(nSpace);
}

void SmBlankNode::CreateTextFromNode(OUStringBuffer &rText)
{
    if (mnNum <= 0)
        return;
    sal_uInt16 nWide = mnNum / 4;
    sal_uInt16 nNarrow = mnNum % 4;
    for (sal_uInt16 i = 0; i < nWide; i++)
        rText.append("~");
    for (sal_uInt16 i = 0; i < nNarrow; i++)
        rText.append("`");
    rText.append(" ");
}


/**************************************************************************/
//Implementation of all accept methods for SmVisitor

diff --git a/starmath/source/parse.cxx b/starmath/source/parse.cxx
index a51d65f..e931c49 100644
--- a/starmath/source/parse.cxx
+++ b/starmath/source/parse.cxx
@@ -1681,8 +1681,8 @@ std::unique_ptr<SmNode> SmParser::DoOper()

        case TOPER :
            NextToken();

            OSL_ENSURE(m_aCurToken.eType == TSPECIAL, "Sm: wrong token");
            m_aCurToken.eType = TOPER;
            pNode.reset(new SmGlyphSpecialNode(m_aCurToken));
            break;

@@ -2176,6 +2176,7 @@ std::unique_ptr<SmTextNode> SmParser::DoFunction()
    {
        case TFUNC:
            NextToken();    // skip "FUNC"-statement
            m_aCurToken.eType = TFUNC;
            [[fallthrough]];

        case TSIN :
diff --git a/starmath/source/visitors.cxx b/starmath/source/visitors.cxx
index 5362551..f663dcf 100644
--- a/starmath/source/visitors.cxx
+++ b/starmath/source/visitors.cxx
@@ -15,6 +15,7 @@
#include "tmpdevice.hxx"
#include <cursor.hxx>
#include <cassert>
#include "mathtype.hxx"

// SmDefaultingVisitor

@@ -1918,6 +1919,7 @@ void SmSelectionDrawingVisitor::Visit( SmTextNode* pNode )
SmNodeToTextVisitor::SmNodeToTextVisitor( SmNode* pNode, OUString &rText )
{
    pNode->Accept( this );
    maCmdText.stripEnd(' ');
    rText = maCmdText.makeStringAndClear();
}

@@ -2077,6 +2079,8 @@ void SmNodeToTextVisitor::Visit( SmAttributNode* pNode )

void SmNodeToTextVisitor::Visit( SmFontNode* pNode )
{
    sal_Int32 nc;
    sal_Int16 nr, ng, nb;
    switch ( pNode->GetToken( ).eType )
    {
        case TBOLD:
@@ -2119,7 +2123,7 @@ void SmNodeToTextVisitor::Visit( SmFontNode* pNode )
                            static_cast<double>( pNode->GetSizeParameter( ) ),
                            rtl_math_StringFormat_Automatic,
                            rtl_math_DecimalPlaces_Max, '.', true ) );
                Append( " " );
                Separate( );
            }
            break;
        case TBLACK:
@@ -2146,6 +2150,51 @@ void SmNodeToTextVisitor::Visit( SmFontNode* pNode )
        case TYELLOW:
            Append( "color yellow " );
            break;
        case TGRAY:
            Append( "color gray " );
            break;
        case TLIME:
            Append( "color lime " );
            break;
        case TMAROON:
            Append( "color maroon " );
            break;
        case TNAVY:
            Append( "color navy " );
            break;
        case TOLIVE:
            Append( "color olive " );
            break;
        case TPURPLE:
            Append( "color purple " );
            break;
        case TSILVER:
            Append( "color silver " );
            break;
        case TTEAL:
            Append( "color teal " );
            break;
        case TAQUA:
            Append( "color aqua " );
            break;
        case TFUCHSIA:
            Append("color fuchsia ");
            break;
        case TRGB:
            Append( "color rgb " );
            nc = pNode->GetToken().aText.toInt32();
            nb = nc % 256;
            nc /= 256;
            ng = nc % 256;
            nc /= 256;
            nr = nc % 256;
            Append(OUString::number(nr));
            Separate();
            Append(OUString::number(ng));
            Separate();
            Append(OUString::number(nb));
            Separate();
            break;
        case TSANS:
            Append( "font sans " );
            break;
@@ -2305,17 +2354,76 @@ void SmNodeToTextVisitor::Visit( SmPlaceNode* )

void SmNodeToTextVisitor::Visit( SmTextNode* pNode )
{
    //TODO: This method might need improvements, see SmTextNode::CreateTextFromNode
    if( pNode->GetToken( ).eType == TTEXT )
        Append( "\"" );
    Append( pNode->GetText( ) );
    if( pNode->GetToken( ).eType == TTEXT )
        Append( "\"" );
    SmTokenType type = pNode->GetToken( ).eType;
    switch(type){
        case TTEXT:
            Append( "\"" );
            Append( pNode->GetToken().aText );
            Append( "\"" );
            break;
        case TNUMBER:
            Append( pNode->GetToken().aText );
            break;
        case TIDENT:
            Append( pNode->GetToken().aText );
            break;
        case TFUNC:
            Append("func ");
            Append( pNode->GetToken().aText );
            break;
        default:
            Append( pNode->GetToken().aText );
    }
    Separate( );
}

void SmNodeToTextVisitor::Visit( SmSpecialNode* pNode )
{
    Append( pNode->GetToken( ).aText );
    SmTokenType type = pNode->GetToken().eType;
    switch(type){
        case TINTD:
            Append("intd ");
            break;
        case TINT:
            Append("int ");
            break;
        case TSUM:
            Append("sum ");
            break;
        case TIINT:
            Append("iint ");
            break;
        case TIIINT:
            Append("iiint ");
            break;
        case TLINT:
            Append("lint ");
            break;
        case TLLINT:
            Append("llint ");
            break;
        case TLLLINT:
            Append("lllint ");
            break;
        case TCOPROD:
            Append("coprod ");
            break;
        case TPROD:
            Append("prod ");
            break;
        case TLIM:
            Append("lim ");
            break;
        case TLIMSUP:
            Append("lim sup ");
            break;
        case TLIMINF:
            Append("lim inf ");
            break;
        default:
            Append( pNode->GetToken().aText );
            break;
    }
}

void SmNodeToTextVisitor::Visit( SmGlyphSpecialNode* pNode )
@@ -2327,9 +2435,392 @@ void SmNodeToTextVisitor::Visit( SmGlyphSpecialNode* pNode )
    Append( pNode->GetToken( ).aText );
}

//TODO to improve this it is requiered to improve mathmlimport.
void SmNodeToTextVisitor::Visit( SmMathSymbolNode* pNode )
{
    Append( pNode->GetToken( ).aText );
    sal_Unicode cChar = pNode->GetToken().cMathChar;
    Separate( );
    switch(cChar){
        case '(':
            Append("(");
            break;
        case '[':
            Append("[");
            break;
        case '{':
            Append("lbrace");
            break;
        case ')':
            Append(")");
            break;
        case ']':
            Append("]");
            break;
        case '}':
            Append("rbrace");
            break;
        case 0x0000:
            Append("none");
            break;
        case MS_NEG:
            Append("neg");
            break;
        case MS_PLUSMINUS:
            Append("+-");
            break;
        case MS_FACT:
            Append("fact");
            break;
        case MS_VERTLINE:
            if( pNode->GetToken().eType == TLLINE ) Append("lline");
            else if( pNode->GetToken().eType == TRLINE ) Append("rline");
            else Append("mline");
            break;
        case MS_TILDE:
            Append("\"~\"");
            break;
        case MS_SIM:
            Append("sim");
            break;
        case MS_DVERTLINE:
            if( pNode->GetToken().eType == TLDLINE ) Append("ldline");
            else Append("rdline");
            break;
        case MS_RIGHTARROW:
            if( pNode->GetToken().eType == TTOWARD ) Append("toward");
            else Append("rightarrow");
            break;
        case MS_LEFTARROW:
            Append("leftarrow");
            break;
        case MS_UPARROW:
            Append("uparrow");
            break;
        case MS_DOWNARROW:
            Append("downarrow");
            break;
        case MS_NDIVIDES:
            Append("ndivides");
            break;
        case MS_DLINE:
            Append("parallel");
            break;
        case MS_TIMES:
            Append("times");
            break;
        case MS_DIV:
            Append("div");
            break;
        case MS_LAMBDABAR:
            Append("lambdabar");
            break;
        case MS_DOTSLOW:
            Append("dotslow");
            break;
        case 0x2022:
            Append("cdot");
            break;
        case MS_CDOT:
            Append("cdot");
            break;
        case MS_SETC:
            Append("setC");
            break;
        case MS_HBAR:
            Append("hbar");
            break;
        case MS_IM:
            Append("Im");
            break;
        case MS_SETN:
            Append("setN");
            break;
        case MS_WP:
            Append("wp");
            break;
        case MS_LAPLACE:
            Append("laplace");
            break;
        case MS_SETQ:
            Append("setQ");
            break;
        case MS_RE:
            Append("Re");
            break;
        case MS_SETR:
            Append("setR");
            break;
        case MS_SETZ:
            Append("setZ");
            break;
        case MS_ALEPH:
            Append("aleph");
            break;
        case 0x0362:
            Append("widevec");
            break;
        case MS_DLARROW:
            Append("dlarrow");
            break;
        case MS_DRARROW:
            Append("drarrow");
            break;
        case MS_DLRARROW:
            Append("dlrarrow");
            break;
        case MS_FORALL:
            Append("forall");
            break;
        case MS_PARTIAL:
            Append("partial");
            break;
        case MS_EXISTS:
            Append("exists");
            break;
        case MS_NOTEXISTS:
            Append("notexists");
            break;
        case MS_EMPTYSET:
            Append("emptyset");
            break;
        case MS_NABLA:
            Append("nabla");
            break;
        case MS_IN:
            Append("in");
            break;
        case MS_NI:
            Append("owns");
            break;
        case MS_NOTIN:
            Append("notin");
            break;
        case MS_BACKEPSILON:
            Append("backepsilon");
            break;
        case MS_PROD:
            Append("prod");
            break;
        case MS_COPROD:
            Append("coprod");
            break;
        case MS_SUM:
            Append("sum");
            break;
        case MS_MINUS:
            Append("-");
            break;
        case MS_MINUSPLUS:
            Append("-+");
            break;
        case MS_MULTIPLY:
            Append("*");
            break;
        case MS_CIRC:
            Append("circ");
            break;
        case MS_PROP:
            Append("prop");
            break;
        case MS_INFINITY:
            Append("infinity");
            break;
        case MS_AND:
            Append("and");
            break;
        case MS_OR:
            Append("or");
            break;
        case MS_INTERSECT:
            Append("intersection");
            break;
        case MS_UNION:
            Append("union");
            break;
        case MS_LINE:
            Append("divides");
            break;
        case MS_INT:
            if (pNode->GetScaleMode() == SmScaleMode::Height) Append("intd");
            else Append("int");
            break;
        case MS_IINT:
            Append("iint");
            break;
        case MS_IIINT:
            Append("iiint");
            break;
        case MS_LINT:
            Append("lint");
            break;
        case MS_LLINT:
            Append("llint");
            break;
        case MS_LLLINT:
            Append("lllint");
            break;
        case 0x2245:
            Append("simeq");
            break;
        case MS_SIMEQ:
            Append("simeq");
            break;
        case MS_BACKSLASH:
            Append("setminus");
            break;
        case MS_APPROX:
            Append("approx");
            break;
        case MS_NEQ:
            Append("<>");
            break;
        case MS_EQUIV:
            Append("equiv");
            break;
        case MS_LE:
            Append("<=");
            break;
        case MS_GE:
            Append(">=");
            break;
        case MS_LESLANT:
            Append("leslant");
            break;
        case MS_GESLANT:
            Append("geslant");
            break;
        case MS_PRECEDES:
            Append("prec");
            break;
        case MS_SUCCEEDS:
            Append("succ");
            break;
        case MS_PRECEDESEQUAL:
            Append("preccurlyeq");
            break;
        case MS_SUCCEEDSEQUAL:
            Append("succcurlyeq");
            break;
        case MS_PRECEDESEQUIV:
            Append("precsim");
            break;
        case MS_SUCCEEDSEQUIV:
            Append("succsim");
            break;
        case MS_NOTPRECEDES:
            Append("nprec");
            break;
        case MS_NOTSUCCEEDS:
            Append("nsucc");
            break;
        case MS_SUBSET:
            Append("subset");
            break;
        case MS_SUPSET:
            Append("supset");
            break;
        case MS_NSUBSET:
            Append("nsubset");
            break;
        case MS_NSUPSET:
            Append("nsupset");
            break;
        case MS_SUBSETEQ:
            Append("subseteq");
            break;
        case MS_SUPSETEQ:
            Append("supseteq");
            break;
        case MS_NSUBSETEQ:
            Append("nsubseteq");
            break;
        case MS_NSUPSETEQ:
            Append("nsupseteq");
            break;
        case 0x22b2: // NORMAL SUBGROUP OF
            Append(OUStringChar(cChar));
            break;
        case 0x22b3: // CONTAINS AS NORMAL SUBGROUP
            Append(OUStringChar(cChar));
            break;
        case MS_ORTHO:
            Append("ortho");
            break;
        case MS_DOTSVERT:
            Append("dotsvert");
            break;
        case MS_DOTSAXIS:
            Append("dotsaxis");
            break;
        case MS_DOTSUP:
            Append("dotsup");
            break;
        case MS_DOTSDOWN:
            Append("dotsdown");
            break;
        case MS_LANGLE:
        case MS_LMATHANGLE:
            Append("langle");
            break;
        case MS_RANGLE:
        case MS_RMATHANGLE:
            Append("rangle");
            break;
        case 0x301a:
            Append("ldbracket");
            break;
        case 0x301b:
            Append("rdbracket");
            break;
        case MS_LDBRACKET:
            Append("ldbracket");
            break;
        case MS_RDBRACKET:
            Append("rdbracket");
            break;
        case 0xe083:
            Append("+");
            break;
        case MS_PLUS:
            Append("+");
            break;
        case '^':
            Append("^");
            break;
        case 0xe091:
            Append("widehat");
            break;
        case 0xe096:
            Append("widetilde");
            break;
        case 0xe098:
            Append("widevec");
            break;
        case 0xE421:
            Append("geslant");
            break;
        case 0xE425:
            Append("leslant");
            break;
        case 0xeb01:    //no space
        case 0xeb08:    //normal space
            break;
        case 0xef04:    //tiny space
        case 0xef05:    //tiny space
        case 0xeb02:    //small space
        case 0xeb04:    //medium space
            Append("`");
            break;
        case 0xeb05:    //large space
            Append("~");
            break;
        case 0x3a9:
            Append("%OMEGA");
            break;
        default:
            Append(OUStringChar(cChar));
            break;
    }
}

void SmNodeToTextVisitor::Visit( SmBlankNode* pNode )