fdo#53472 Created Dynamic Integral Node classes. Integrals size made dependent on body.

Change-Id: I0348155f2429cf7dd3cbe7d71f333879ec6de980
Reviewed-on: https://gerrit.libreoffice.org/8569
Reviewed-by: Norbert Thiebaud <nthiebaud@gmail.com>
Tested-by: Norbert Thiebaud <nthiebaud@gmail.com>
diff --git a/starmath/inc/node.hxx b/starmath/inc/node.hxx
index c15ab25..ab27af0 100644
--- a/starmath/inc/node.hxx
+++ b/starmath/inc/node.hxx
@@ -73,7 +73,7 @@ enum SmNodeType
/*10*/ NBINDIAGONAL,   NSUBSUP,        NMATRIX,        NPLACE,         NTEXT,
/*15*/ NSPECIAL,       NGLYPH_SPECIAL, NMATH,          NBLANK,         NERROR,
/*20*/ NLINE,          NEXPRESSION,    NPOLYLINE,      NROOT,          NROOTSYMBOL,
/*25*/ NRECTANGLE,     NVERTICAL_BRACE, NMATHIDENT
/*25*/ NRECTANGLE,  NVERTICAL_BRACE, NMATHIDENT,  NDYNINT, NDYNINTSYMBOL
};


@@ -618,6 +618,30 @@ public:
    void Accept(SmVisitor* pVisitor);
};

////////////////////////////////////////////////////////////////////////////////

/** Dynamic Integral symbol node
 *
 * Node for drawing dynamicall sized integral symbols.
 *
 * TODO: It might be created a parent class SmDynamicSizedNode
        (for both dynamic integrals, roots and other dynamic symbols)

 */
class SmDynIntegralSymbolNode : public SmMathSymbolNode
{


public:
    SmDynIntegralSymbolNode(const SmToken &rNodeToken)
    :   SmMathSymbolNode(NDYNINTSYMBOL, rNodeToken)
    {}

    virtual void AdaptToY(const OutputDevice &rDev, sal_uLong nHeight);

    void Accept(SmVisitor* pVisitor);
};




@@ -806,6 +830,40 @@ public:
};


////////////////////////////////////////////////////////////////////////////////

/** Dynamic Integral node
 *
 * Used to create Dynamically sized integrals
 *
 * Children:<BR>
 * 0: Symbol (instance of DynIntegralSymbolNode)<BR>
 * 1: Body<BR>
 */
class SmDynIntegralNode : public SmStructureNode
{
protected:
    void   GetHeightVerOffset(const SmRect &rRect,
                              long &rHeight, long &rVerOffset) const;

public:
    SmDynIntegralNode(const SmToken &rNodeToken)
    :   SmStructureNode(NDYNINT, rNodeToken)
    {
        SetNumSubNodes(2);
    }

    virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
    void CreateTextFromNode(OUString &rText);
    void Accept(SmVisitor* pVisitor);

    SmDynIntegralSymbolNode* Symbol();
    const SmDynIntegralSymbolNode* Symbol() const;
    SmNode* Body();
    const SmNode* Body() const;
};




/** Binary horizontial node
@@ -1293,6 +1351,28 @@ inline const SmNode* SmRootNode::Body() const
    return const_cast< SmRootNode* >( this )->Body();
}



inline SmDynIntegralSymbolNode* SmDynIntegralNode::Symbol()
{
    OSL_ASSERT( GetNumSubNodes() > 0 && GetSubNode( 0 )->GetType() == NDYNINTSYMBOL );
    return static_cast< SmDynIntegralSymbolNode* >( GetSubNode( 0 ));
}
inline const SmDynIntegralSymbolNode* SmDynIntegralNode::Symbol() const
{
    return const_cast< SmDynIntegralNode* >( this )->Symbol();
}
inline SmNode* SmDynIntegralNode::Body()
{
    OSL_ASSERT( GetNumSubNodes() > 1 );
    return GetSubNode( 1 );
}
inline const SmNode* SmDynIntegralNode::Body() const
{
    return const_cast< SmDynIntegralNode* >( this )->Body();
}


inline SmMathSymbolNode* SmBinHorNode::Symbol()
{
    OSL_ASSERT( GetNumSubNodes() > 1 && GetSubNode( 1 )->GetType() == NMATH );
diff --git a/starmath/inc/parse.hxx b/starmath/inc/parse.hxx
index 41071f2..d967be7 100644
--- a/starmath/inc/parse.hxx
+++ b/starmath/inc/parse.hxx
@@ -102,7 +102,8 @@ enum SmTokenType
/*215*/ TSETR,          TSETC,          TWIDEVEC,       TWIDETILDE,     TWIDEHAT,
/*220*/ TWIDESLASH,     TWIDEBACKSLASH, TLDBRACKET,     TRDBRACKET,     TNOSPACE,
/*225*/ TUNKNOWN,       TDEBUG,         TPRECEDES,      TSUCCEEDS,      TPRECEDESEQUAL,
/*230*/ TSUCCEEDSEQUAL, TPRECEDESEQUIV, TSUCCEEDSEQUIV, TNOTPRECEDES,   TNOTSUCCEEDS
/*230*/ TSUCCEEDSEQUAL, TPRECEDESEQUIV, TSUCCEEDSEQUIV, TNOTPRECEDES,   TNOTSUCCEEDS,
/*235*/ TINTD
};


diff --git a/starmath/inc/visitors.hxx b/starmath/inc/visitors.hxx
index 630b311..7c4dcf7 100644
--- a/starmath/inc/visitors.hxx
+++ b/starmath/inc/visitors.hxx
@@ -42,6 +42,8 @@ public:
    virtual void Visit( SmLineNode* pNode ) = 0;
    virtual void Visit( SmExpressionNode* pNode ) = 0;
    virtual void Visit( SmPolyLineNode* pNode ) = 0;
    virtual void Visit( SmDynIntegralNode* pNode ) = 0;
    virtual void Visit( SmDynIntegralSymbolNode* pNode ) = 0;
    virtual void Visit( SmRootNode* pNode ) = 0;
    virtual void Visit( SmRootSymbolNode* pNode ) = 0;
    virtual void Visit( SmRectangleNode* pNode ) = 0;
@@ -81,6 +83,8 @@ public:
    void Visit( SmPolyLineNode* pNode );
    void Visit( SmRootNode* pNode );
    void Visit( SmRootSymbolNode* pNode );
    void Visit( SmDynIntegralNode* pNode );
    void Visit( SmDynIntegralSymbolNode* pNode );
    void Visit( SmRectangleNode* pNode );
    void Visit( SmVerticalBraceNode* pNode );
private:
@@ -124,6 +128,8 @@ public:
    void Visit( SmPolyLineNode* pNode );
    void Visit( SmRootNode* pNode );
    void Visit( SmRootSymbolNode* pNode );
    void Visit( SmDynIntegralNode* pNode );
    void Visit( SmDynIntegralSymbolNode* pNode );
    void Visit( SmRectangleNode* pNode );
    void Visit( SmVerticalBraceNode* pNode );
protected:
@@ -227,6 +233,8 @@ public:
    void Visit( SmPolyLineNode* pNode );
    void Visit( SmRootNode* pNode );
    void Visit( SmRootSymbolNode* pNode );
    void Visit( SmDynIntegralNode* pNode );
    void Visit( SmDynIntegralSymbolNode* pNode );
    void Visit( SmRectangleNode* pNode );
    void Visit( SmVerticalBraceNode* pNode );
private:
@@ -344,6 +352,8 @@ public:
    void Visit( SmPolyLineNode* pNode );
    void Visit( SmRootNode* pNode );
    void Visit( SmRootSymbolNode* pNode );
    void Visit( SmDynIntegralNode* pNode );
    void Visit( SmDynIntegralSymbolNode* pNode );
    void Visit( SmRectangleNode* pNode );
    void Visit( SmVerticalBraceNode* pNode );
    SmCaretPosGraph* takeGraph()
@@ -393,6 +403,8 @@ public:
    void Visit( SmPolyLineNode* pNode );
    void Visit( SmRootNode* pNode );
    void Visit( SmRootSymbolNode* pNode );
    void Visit( SmDynIntegralNode* pNode );
    void Visit( SmDynIntegralSymbolNode* pNode );
    void Visit( SmRectangleNode* pNode );
    void Visit( SmVerticalBraceNode* pNode );
    /** Clone a pNode */
@@ -465,6 +477,8 @@ public:
    void Visit( SmPolyLineNode* pNode );
    void Visit( SmRootNode* pNode );
    void Visit( SmRootSymbolNode* pNode );
    void Visit( SmDynIntegralNode* pNode );
    void Visit( SmDynIntegralSymbolNode* pNode );
    void Visit( SmRectangleNode* pNode );
    void Visit( SmVerticalBraceNode* pNode );
private:
diff --git a/starmath/source/mathtype.cxx b/starmath/source/mathtype.cxx
index b90b79d..8212421 100644
--- a/starmath/source/mathtype.cxx
+++ b/starmath/source/mathtype.cxx
@@ -2516,6 +2516,7 @@ void MathType::HandleOperator(SmNode *pNode,int nLevel)
    switch(pNode->GetToken().eType)
    {
    case TINT:
    case TINTD:
        if (nOldVariation != 0xff)
            pS->WriteUChar( sal_uInt8(0x18) ); //selector
        else
@@ -2640,6 +2641,7 @@ void MathType::HandleOperator(SmNode *pNode,int nLevel)
        pS->WriteUChar( sal_uInt8(0x86) );
        pS->WriteUInt16( sal_uInt16(0x222B) );
    case TINT:
    case TINTD:
    case TLINT:
        pS->WriteUChar( sal_uInt8(CHAR) );
        pS->WriteUChar( sal_uInt8(0x86) );
diff --git a/starmath/source/mathtype.hxx b/starmath/source/mathtype.hxx
index 20bed43..402e017 100644
--- a/starmath/source/mathtype.hxx
+++ b/starmath/source/mathtype.hxx
@@ -197,7 +197,7 @@ private:
        tmANGLE,tmPAREN,tmBRACE,tmBRACK,tmBAR,tmDBAR,tmFLOOR,tmCEILING,
        tmLBLB,tmRBRB,tmRBLB,tmLBRP,tmLPRB,tmROOT,tmFRACT,tmSCRIPT,tmUBAR,
        tmOBAR,tmLARROW,tmRARROW,tmBARROW,tmSINT,tmDINT,tmTINT,tmSSINT,
        tmDSINT,tmTSINT,tmUHBRACE,tmLHBRACE,tmSUM
        tmDSINT,tmTSINT,tmUHBRACE,tmLHBRACE,tmSUM,tmTINTD
    };
public:
    static sal_Bool LookupChar(sal_Unicode nChar,OUString &rRet,
diff --git a/starmath/source/node.cxx b/starmath/source/node.cxx
index bbac173..75d7529 100644
--- a/starmath/source/node.cxx
+++ b/starmath/source/node.cxx
@@ -622,6 +622,8 @@ void SmNode::DumpAsDot(std::ostream &out, OUString* label, int number, int& id, 
        case NRECTANGLE:       out<<"SmRectangleNode"; break;
        case NVERTICAL_BRACE:  out<<"SmVerticalBraceNode"; break;
        case NMATHIDENT:       out<<"SmMathIdentifierNode"; break;
        case NINTDYNSYMBOL:            out<<"SmDynIntegralSymbolNode"; break;
        case NINTDYN:            out<<"SmDynIntegralNode"; break;
        default:
            out<<"Unknown Node";
    }
@@ -1115,6 +1117,53 @@ void SmRootNode::CreateTextFromNode(OUString &rText)
        rText += "} ";
}

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


void SmDynIntegralNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
{
    SmNode  *pDynIntegralSym = Symbol(),
           *pBody    = Body();
    OSL_ENSURE(pDynIntegralSym, "Sm: NULL pointer");
    OSL_ENSURE(pBody,    "Sm: NULL pointer");

    pBody->Arrange(rDev, rFormat);

    long  nHeight = pBody->GetHeight();
    pDynIntegralSym->AdaptToY(rDev, nHeight);

    pDynIntegralSym->Arrange(rDev, rFormat);

    Point  aPos = pDynIntegralSym->AlignTo(*pBody, RP_LEFT, RHA_CENTER, RVA_BASELINE);
    //! override calculated vertical position
    aPos.Y()  = pDynIntegralSym->GetTop() + pBody->GetBottom() - pDynIntegralSym->GetBottom();
    pDynIntegralSym->MoveTo(aPos);


    // override its own rectangle with pBody's
    SmRect::operator = (*pBody);
    // extends this rectangle with the symbol's one
    ExtendBy(*pDynIntegralSym, RCP_THIS);

}


void SmDynIntegralNode::CreateTextFromNode(OUString &rText)
{

    rText += "intd ";
    SmNode *pBody = GetSubNode(1);

    if (pBody->GetNumSubNodes() > 1)
        rText += "{ ";

    pBody->CreateTextFromNode(rText);

    if (pBody->GetNumSubNodes() > 1)
        rText += "} ";
}



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

@@ -2297,6 +2346,23 @@ void SmRootSymbolNode::AdaptToY(const OutputDevice &rDev, sal_uLong nHeight)
/**************************************************************************/


void SmDynIntegralSymbolNode::AdaptToY(const OutputDevice &rDev, sal_uLong nHeight)
{
    long nFactor = 12L;

    // The new height equals (1 + nFactor) * oldHeight
    // nFactor was chosen for keeping the integral sign from becoming too "fat".
    SmMathSymbolNode::AdaptToY(rDev, nHeight + nHeight / nFactor);

    // keep the ratio
    long nCurWidth = GetSize().Width();
    SmMathSymbolNode::AdaptToX(rDev, nCurWidth + nCurWidth / nFactor);
}


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


void SmRectangleNode::AdaptToX(const OutputDevice &/*rDev*/, sal_uLong nWidth)
{
    aToSize.Width() = nWidth;
@@ -3196,6 +3262,15 @@ void SmRootSymbolNode::Accept(SmVisitor* pVisitor) {
    pVisitor->Visit(this);
}

void SmDynIntegralNode::Accept(SmVisitor* pVisitor) {
    pVisitor->Visit(this);
}


void SmDynIntegralSymbolNode::Accept(SmVisitor* pVisitor) {
    pVisitor->Visit(this);
}

void SmRectangleNode::Accept(SmVisitor* pVisitor) {
    pVisitor->Visit(this);
}
diff --git a/starmath/source/ooxmlexport.cxx b/starmath/source/ooxmlexport.cxx
index 0a98d98..7110c81 100644
--- a/starmath/source/ooxmlexport.cxx
+++ b/starmath/source/ooxmlexport.cxx
@@ -249,6 +249,7 @@ void SmOoxmlExport::HandleOperator( const SmOperNode* pNode, int nLevel )
    switch( pNode->GetToken().eType )
    {
        case TINT:
        case TINTD:
        case TIINT:
        case TIIINT:
        case TLINT:
diff --git a/starmath/source/parse.cxx b/starmath/source/parse.cxx
index d4c94f4..bb4598d 100644
--- a/starmath/source/parse.cxx
+++ b/starmath/source/parse.cxx
@@ -161,6 +161,7 @@ static const SmTokenTableEntry aTokenTable[] =
    { "infinity" , TINFINITY, MS_INFINITY, TGSTANDALONE, 5},
    { "infty" , TINFINITY, MS_INFINITY, TGSTANDALONE, 5},
    { "int", TINT, MS_INT, TGOPER, 5},
    { "intd", TINTD, MS_INT, TGUNOPER, 5},
    { "intersection", TINTERSECT, MS_INTERSECT, TGPRODUCT, 0},
    { "ital", TITALIC, '\0', TGFONTATTR, 5},
    { "italic", TITALIC, '\0', TGFONTATTR, 5},
@@ -1689,6 +1690,10 @@ void SmParser::UnOper()
    {
        case TABS :
        case TSQRT :
           /* Dynamic integrals are handled as unary operators so we can wrap
             the symbol together with the body in a upper level node and make
             proper graphic arrangements */
        case TINTD:
            NextToken();
            break;

@@ -1743,10 +1748,15 @@ void SmParser::UnOper()
        pSNode->SetSubNodes(pLeft, pArg, pRight);
    }
    else if (eType == TSQRT  ||  eType == TNROOT)
    {   pSNode = new SmRootNode(aNodeToken);
    {  pSNode = new SmRootNode(aNodeToken);
        pOper = new SmRootSymbolNode(aNodeToken);
        pSNode->SetSubNodes(pExtra, pOper, pArg);
    }
    else if(eType == TINTD)
    {  pSNode = new SmDynIntegralNode(aNodeToken);
        pOper = new SmDynIntegralSymbolNode(aNodeToken);
        pSNode->SetSubNodes(pOper, pArg);
    }
    else
    {   pSNode = new SmUnHorNode(aNodeToken);

diff --git a/starmath/source/rtfexport.cxx b/starmath/source/rtfexport.cxx
index bc121f5..d700732 100644
--- a/starmath/source/rtfexport.cxx
+++ b/starmath/source/rtfexport.cxx
@@ -198,6 +198,7 @@ void SmRtfExport::HandleOperator(const SmOperNode* pNode, int nLevel)
    switch (pNode->GetToken().eType)
    {
    case TINT:
    case TINTD:
    case TIINT:
    case TIIINT:
    case TLINT:
diff --git a/starmath/source/visitors.cxx b/starmath/source/visitors.cxx
index 33624b0..4c515df 100644
--- a/starmath/source/visitors.cxx
+++ b/starmath/source/visitors.cxx
@@ -161,6 +161,18 @@ void SmVisitorTest::Visit( SmRootSymbolNode* pNode )
    VisitChildren( pNode );
}

void SmVisitorTest::Visit( SmDynIntegralNode* pNode )
{
    assert( pNode->GetType( ) == NDYNINT );
    VisitChildren( pNode );
}

void SmVisitorTest::Visit( SmDynIntegralSymbolNode* pNode )
{
    assert( pNode->GetType( ) == NDYNINTSYMBOL );
    VisitChildren( pNode );
}

void SmVisitorTest::Visit( SmRectangleNode* pNode )
{
    assert( pNode->GetType( ) == NRECTANGLE );
@@ -307,6 +319,16 @@ void SmDefaultingVisitor::Visit( SmRootSymbolNode* pNode )
    DefaultVisit( pNode );
}

void SmDefaultingVisitor::Visit( SmDynIntegralNode* pNode )
{
    DefaultVisit( pNode );
}

void SmDefaultingVisitor::Visit( SmDynIntegralSymbolNode* pNode )
{
    DefaultVisit( pNode );
}

void SmDefaultingVisitor::Visit( SmRectangleNode* pNode )
{
    DefaultVisit( pNode );
@@ -630,6 +652,11 @@ void SmDrawingVisitor::Visit( SmRootNode* pNode )
    DrawChildren( pNode );
}

void SmDrawingVisitor::Visit(SmDynIntegralNode* pNode)
{
    DrawChildren( pNode );
}

void SmDrawingVisitor::Visit( SmVerticalBraceNode* pNode )
{
    DrawChildren( pNode );
@@ -668,6 +695,22 @@ void SmDrawingVisitor::Visit( SmRootSymbolNode* pNode )
    rDev.DrawRect( aBar );
}

void SmDrawingVisitor::Visit( SmDynIntegralSymbolNode* pNode )
{
    if ( pNode->IsPhantom( ) )
        return;

    // draw integral-sign itself
    DrawSpecialNode( pNode );

    //! the rest of this may not be needed at all

    // this should be something like:
    // instead of just drawing the node, take some information about the body.
    // This is also how SmRootSymbol does it (probably by means of SmRootNode)
    // NEXT: Check out SmRootNode
}

void SmDrawingVisitor::Visit( SmPolyLineNode* pNode )
{
    if ( pNode->IsPhantom( ) )
@@ -1630,6 +1673,40 @@ void SmCaretPosGraphBuildingVisitor::Visit( SmRootNode* pNode )
    pRightMost = right;
}


void SmCaretPosGraphBuildingVisitor::Visit( SmDynIntegralNode* pNode )
{
    //! To be changed: Integrals don't have args.
    SmNode  *pBody  = pNode->Body(); //Body of the root
    SAL_WARN_IF( !pBody, "starmath", "pBody cannot be NULL" );

    SmCaretPosGraphEntry  *left,
                        *right,
                        *bodyLeft,
                        *bodyRight;

    //Get left and save it
    SAL_WARN_IF( !pRightMost, "starmath", "There must be a position in front of this" );
    left = pRightMost;

    //Create body left
    bodyLeft = pGraph->Add( SmCaretPos( pBody, 0 ), left );
    left->SetRight( bodyLeft );

    //Create right
    right = pGraph->Add( SmCaretPos( pNode, 1 ) );

    //Visit body
    pRightMost = bodyLeft;
    pBody->Accept( this );
    bodyRight = pRightMost;
    bodyRight->SetRight( right );
    right->SetLeft( bodyRight );

    pRightMost = right;
}


/** Build SmCaretPosGraph for SmPlaceNode
 * Consider this a single character.
 */
@@ -1772,6 +1849,13 @@ void SmCaretPosGraphBuildingVisitor::Visit( SmRootSymbolNode* )
{
    //Do nothing
}

void SmCaretPosGraphBuildingVisitor::Visit( SmDynIntegralSymbolNode* )
{
    //Do nothing
}


void SmCaretPosGraphBuildingVisitor::Visit( SmRectangleNode* )
{
    //Do nothing
@@ -2016,6 +2100,20 @@ void SmCloningVisitor::Visit( SmRootSymbolNode* pNode )
    CloneNodeAttr( pNode, pResult );
}

void SmCloningVisitor::Visit( SmDynIntegralNode* pNode )
{
    SmDynIntegralNode* pClone = new SmDynIntegralNode( pNode->GetToken( ) );
    CloneNodeAttr( pNode, pClone );
    CloneKids( pNode, pClone );
    pResult = pClone;
}

void SmCloningVisitor::Visit( SmDynIntegralSymbolNode* pNode )
{
    pResult = new SmDynIntegralSymbolNode( pNode->GetToken( ) );
    CloneNodeAttr( pNode, pResult );
}

void SmCloningVisitor::Visit( SmRectangleNode* pNode )
{
    pResult = new SmRectangleNode( pNode->GetToken( ) );
@@ -2539,6 +2637,17 @@ void SmNodeToTextVisitor::Visit( SmRootSymbolNode* )
{
}

void SmNodeToTextVisitor::Visit( SmDynIntegralNode* pNode )
{
    SmNode *pBody    = pNode->Body();
    Append( "intd" );
    LineToText( pBody );
}

void SmNodeToTextVisitor::Visit( SmDynIntegralSymbolNode* )
{
}

void SmNodeToTextVisitor::Visit( SmRectangleNode* )
{
}