tdf#129708 speed-up: reuse enumeration for each effect

Change-Id: I336278c5a9eec75a2a71fe4d04d2029a5a08e6a7
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/86102
Tested-by: Jenkins
Reviewed-by: Thorsten Behrens <Thorsten.Behrens@CIB.de>
diff --git a/editeng/source/uno/unotext2.cxx b/editeng/source/uno/unotext2.cxx
index ef9ab68..72980c9 100644
--- a/editeng/source/uno/unotext2.cxx
+++ b/editeng/source/uno/unotext2.cxx
@@ -46,40 +46,41 @@
    if( mrText.GetEditSource() )
        mpEditSource = mrText.GetEditSource()->Clone();
    mnNextParagraph = 0;
    for( sal_Int32 currentPara = 0; currentPara < mrText.GetEditSource()->GetTextForwarder()->GetParagraphCount(); currentPara++ )

    const SvxTextForwarder* pTextForwarder = mrText.GetEditSource()->GetTextForwarder();
    const sal_Int32 maxParaIndex = std::min( rSel.nEndPara + 1, pTextForwarder->GetParagraphCount() );

    for( sal_Int32 currentPara = rSel.nStartPara; currentPara < maxParaIndex; currentPara++ )
    {
        if( currentPara>=rSel.nStartPara && currentPara<=rSel.nEndPara )
        const SvxUnoTextRangeBaseVec& rRanges( mpEditSource->getRanges() );
        SvxUnoTextContent* pContent = nullptr;
        sal_Int32 nStartPos = 0;
        sal_Int32 nEndPos = pTextForwarder->GetTextLen( currentPara );
        if( currentPara == rSel.nStartPara )
            nStartPos = std::max(nStartPos, rSel.nStartPos);
        if( currentPara == rSel.nEndPara )
            nEndPos = std::min(nEndPos, rSel.nEndPos);
        ESelection aCurrentParaSel( currentPara, nStartPos, currentPara, nEndPos );
        for (auto const& elemRange : rRanges)
        {
            const SvxUnoTextRangeBaseVec& rRanges( mpEditSource->getRanges() );
            SvxUnoTextContent* pContent = nullptr;
            sal_Int32 nStartPos = 0;
            sal_Int32 nEndPos = mrText.GetEditSource()->GetTextForwarder()->GetTextLen( currentPara );
            if( currentPara == rSel.nStartPara )
                nStartPos = std::max(nStartPos, rSel.nStartPos);
            if( currentPara == rSel.nEndPara )
                nEndPos = std::min(nEndPos, rSel.nEndPos);
            ESelection aCurrentParaSel( currentPara, nStartPos, currentPara, nEndPos );
            for (auto const& elemRange : rRanges)
            if (pContent)
                break;
            SvxUnoTextContent* pIterContent = dynamic_cast< SvxUnoTextContent* >( elemRange );
            if( pIterContent && (pIterContent->mnParagraph == currentPara) )
            {
                if (pContent)
                    break;
                SvxUnoTextContent* pIterContent = dynamic_cast< SvxUnoTextContent* >( elemRange );
                if( pIterContent && (pIterContent->mnParagraph == currentPara) )
                ESelection aIterSel = pIterContent->GetSelection();
                if( aIterSel == aCurrentParaSel )
                {
                    ESelection aIterSel = pIterContent->GetSelection();
                    if( aIterSel == aCurrentParaSel )
                    {
                        pContent = pIterContent;
                        maContents.emplace_back(pContent );
                    }
                    pContent = pIterContent;
                    maContents.emplace_back(pContent );
                }
            }
            if( pContent == nullptr )
            {
                pContent = new SvxUnoTextContent( mrText, currentPara );
                pContent->SetSelection( aCurrentParaSel );
                maContents.emplace_back(pContent );
            }
        }
        if( pContent == nullptr )
        {
            pContent = new SvxUnoTextContent( mrText, currentPara );
            pContent->SetSelection( aCurrentParaSel );
            maContents.emplace_back(pContent );
        }
    }
}
diff --git a/sd/inc/CustomAnimationEffect.hxx b/sd/inc/CustomAnimationEffect.hxx
index 962ce9b..26f1cef 100644
--- a/sd/inc/CustomAnimationEffect.hxx
+++ b/sd/inc/CustomAnimationEffect.hxx
@@ -144,7 +144,7 @@
    SAL_DLLPRIVATE OUString getPath() const;
    SAL_DLLPRIVATE void setPath( const OUString& rPath );

    SAL_DLLPRIVATE bool checkForText();
    SAL_DLLPRIVATE bool checkForText( const std::vector<sal_Int32>* paragraphNumberingLevel = nullptr );
    SAL_DLLPRIVATE bool calculateIterateDuration();

    SAL_DLLPRIVATE void setAudio( const css::uno::Reference< css::animations::XAudio >& xAudio );
@@ -334,6 +334,8 @@

    SAL_DLLPRIVATE void updateTextGroups();

    SAL_DLLPRIVATE bool getParagraphNumberingLevels( const css::uno::Reference< css::drawing::XShape >& xShape, std::vector< sal_Int32 >& rParagraphNumberingLevel );

protected:
    css::uno::Reference< css::animations::XTimeContainer > mxSequenceRoot;
    EffectSequence maEffects;
diff --git a/sd/source/core/CustomAnimationEffect.cxx b/sd/source/core/CustomAnimationEffect.cxx
index a4b1d64..95c1ca8 100644
--- a/sd/source/core/CustomAnimationEffect.cxx
+++ b/sd/source/core/CustomAnimationEffect.cxx
@@ -523,7 +523,7 @@
/** checks if the text for this effect has changed and updates internal flags.
    returns true if something changed.
*/
bool CustomAnimationEffect::checkForText()
bool CustomAnimationEffect::checkForText( const std::vector<sal_Int32>* paragraphNumberingLevel )
{
    bool bChange = false;

@@ -540,36 +540,52 @@
        // get paragraph
        if( xText.is() )
        {
            Reference< XEnumerationAccess > xEA( xText, UNO_QUERY );
            if( xEA.is() )
            sal_Int32 nPara = aParaTarget.Paragraph;

            bool bHasText = false;
            sal_Int32 nParaDepth = 0;

            if ( paragraphNumberingLevel )
            {
                Reference< XEnumeration > xEnumeration = xEA->createEnumeration();
                if( xEnumeration.is() )
                bHasText = !paragraphNumberingLevel->empty();
                if (nPara >= 0 && static_cast<size_t>(nPara) < paragraphNumberingLevel->size())
                    nParaDepth = paragraphNumberingLevel->at(nPara);
            }
            else
            {
                Reference< XEnumerationAccess > xEA( xText, UNO_QUERY );
                if( xEA.is() )
                {
                    bool bHasText = xEnumeration->hasMoreElements();
                    bChange |= bHasText != mbHasText;
                    mbHasText = bHasText;

                    sal_Int32 nPara = aParaTarget.Paragraph;

                    while( xEnumeration->hasMoreElements() && nPara-- )
                        xEnumeration->nextElement();

                    if( xEnumeration->hasMoreElements() )
                    Reference< XEnumeration > xEnumeration = xEA->createEnumeration();
                    if( xEnumeration.is() )
                    {
                        Reference< XPropertySet > xParaSet;
                        xEnumeration->nextElement() >>= xParaSet;
                        if( xParaSet.is() )
                        bHasText = xEnumeration->hasMoreElements();

                        while( xEnumeration->hasMoreElements() && nPara-- )
                            xEnumeration->nextElement();

                        if( xEnumeration->hasMoreElements() )
                        {
                            sal_Int32 nParaDepth = 0;
                            const OUString strNumberingLevel( "NumberingLevel" );
                            xParaSet->getPropertyValue( strNumberingLevel ) >>= nParaDepth;
                            bChange |= nParaDepth != mnParaDepth;
                            mnParaDepth = nParaDepth;
                            Reference< XPropertySet > xParaSet;
                            xEnumeration->nextElement() >>= xParaSet;
                            if( xParaSet.is() )
                            {
                                const OUString strNumberingLevel( "NumberingLevel" );
                                xParaSet->getPropertyValue( strNumberingLevel ) >>= nParaDepth;
                            }
                        }
                    }
                }
            }

            if( bHasText )
            {
                bChange |= bHasText != mbHasText;
                mbHasText = bHasText;

                bChange |= nParaDepth != mnParaDepth;
                mnParaDepth = nParaDepth;
            }
        }
    }
    else
@@ -2138,17 +2154,63 @@
        [&xShape](const CustomAnimationEffectPtr& rxEffect) { return rxEffect->getTargetShape() == xShape; });
}

bool EffectSequenceHelper::getParagraphNumberingLevels( const Reference< XShape >& xShape, std::vector< sal_Int32 >& rParagraphNumberingLevel )
{
    rParagraphNumberingLevel.clear();

    if( !hasEffect( xShape ) )
        return false;

    Reference< XText > xText( xShape, UNO_QUERY );
    if( xText.is() )
    {
        Reference< XEnumerationAccess > xEA( xText, UNO_QUERY );
        if( xEA.is() )
        {
            Reference< XEnumeration > xEnumeration = xEA->createEnumeration();

            if( xEnumeration.is() )
            {
                for( sal_Int32 index = 0; xEnumeration->hasMoreElements(); index++ )
                {
                    Reference< XPropertySet > xParaSet;
                    xEnumeration->nextElement() >>= xParaSet;

                    sal_Int32 nParaDepth = 0;
                    if( xParaSet.is() )
                    {
                        const OUString strNumberingLevel( "NumberingLevel" );
                        xParaSet->getPropertyValue( strNumberingLevel ) >>= nParaDepth;
                    }

                    rParagraphNumberingLevel.push_back( nParaDepth );
                }
            }
        }
    }

    return true;
}

void EffectSequenceHelper::insertTextRange( const css::uno::Any& aTarget )
{
    ParagraphTarget aParaTarget;
    if( !(aTarget >>= aParaTarget ) )
        return;

    bool bChanges = std::accumulate(maEffects.begin(), maEffects.end(), false,
        [&aParaTarget](const bool bCheck, const CustomAnimationEffectPtr& rxEffect) {
    // get map [paragraph index] -> [NumberingLevel]
    // for following reusage inside all animation effects
    std::vector< sal_Int32 > paragraphNumberingLevel;
    std::vector< sal_Int32 >* paragraphNumberingLevelParam = nullptr;
    if ( getParagraphNumberingLevels( aParaTarget.Shape, paragraphNumberingLevel ) )
        paragraphNumberingLevelParam = &paragraphNumberingLevel;

    // update internal flags for each animation effect
    const bool bChanges = std::accumulate(maEffects.begin(), maEffects.end(), false,
        [&aParaTarget, &paragraphNumberingLevelParam](const bool bCheck, const CustomAnimationEffectPtr& rxEffect) {
            bool bRes = bCheck;
            if (rxEffect->getTargetShape() == aParaTarget.Shape)
                bRes |= rxEffect->checkForText();
                bRes |= rxEffect->checkForText( paragraphNumberingLevelParam );
            return bRes;
        });

@@ -3273,11 +3335,19 @@

void EffectSequenceHelper::onTextChanged( const Reference< XShape >& xShape )
{
    bool bChanges = std::accumulate(maEffects.begin(), maEffects.end(), false,
        [&xShape](const bool bCheck, const CustomAnimationEffectPtr& rxEffect) {
    // get map [paragraph index] -> [NumberingLevel]
    // for following reusage inside all animation effects
    std::vector< sal_Int32 > paragraphNumberingLevel;
    std::vector< sal_Int32 >* paragraphNumberingLevelParam = nullptr;
    if ( getParagraphNumberingLevels( xShape, paragraphNumberingLevel ) )
        paragraphNumberingLevelParam = &paragraphNumberingLevel;

    // update internal flags for each animation effect
    const bool bChanges = std::accumulate(maEffects.begin(), maEffects.end(), false,
        [&xShape, &paragraphNumberingLevelParam](const bool bCheck, const CustomAnimationEffectPtr& rxEffect) {
            bool bRes = bCheck;
            if (rxEffect->getTargetShape() == xShape)
                bRes |= rxEffect->checkForText();
                bRes |= rxEffect->checkForText( paragraphNumberingLevelParam );
            return bRes;
        });