[Libreoffice-commits] core.git: editeng/source include/editeng

Noel Grandin noel.grandin at collabora.co.uk
Wed Apr 4 11:29:16 UTC 2018


 editeng/source/editeng/editeng.cxx  |   27 +++++++++++-
 editeng/source/editeng/impedit.hxx  |    1 
 editeng/source/editeng/impedit2.cxx |   78 +++++++++++++++++++++---------------
 editeng/source/outliner/outlin2.cxx |    5 ++
 editeng/source/uno/unoforou.cxx     |   19 --------
 include/editeng/editeng.hxx         |    1 
 include/editeng/outliner.hxx        |    1 
 7 files changed, 80 insertions(+), 52 deletions(-)

New commits:
commit e278df1a14c5cb5dbb7add5d6ed5dd52da131e92
Author: Noel Grandin <noel.grandin at collabora.co.uk>
Date:   Wed Apr 4 11:17:15 2018 +0200

    tdf#108608 Draw file unresponsive on large text pasted into textbox
    
    We have O(n^2) algorithm here.
    
    The stack trace looks like:
        ImpEditEngine::CalcTextWidth
        EditEngine::CalcTextWidth
        Outliner::CalcTextSize
        SvxOutlinerForwarder::GetParaBounds
        SvxAccessibleTextAdapter::GetParaBounds
        accessibility::AccessibleEditableTextPara::getBounds
        ...
        OutlinerView::PasteSpecial
    where AccessibleEditableTextPara::getBounds iterates over all
    paragraphs, and so does ImpEditEngine::CalcTextWidth.
    
    To solve this, push the logic down from
    SvxOutlinerForwarder::GetParaBounds, to new logic in EditEngine and
    ImpEditEngine, where we can optimise the width calculation.
    
    Note that this means that the width returned for a specific paragraph is
    no longer the maximum width of all paragraphs, lets hope that does not
    cause regressions.
    
    Change-Id: I9f879d9a67b16a4aec08915328c99961b7313c2f
    Reviewed-on: https://gerrit.libreoffice.org/52369
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Noel Grandin <noel.grandin at collabora.co.uk>

diff --git a/editeng/source/editeng/editeng.cxx b/editeng/source/editeng/editeng.cxx
index 6c6a0257993f..01bc8dadc7e2 100644
--- a/editeng/source/editeng/editeng.cxx
+++ b/editeng/source/editeng/editeng.cxx
@@ -609,14 +609,37 @@ sal_uInt32 EditEngine::GetLineHeight( sal_Int32 nParagraph )
     return pImpEditEngine->GetLineHeight( nParagraph, 0 );
 }
 
-sal_uInt32 EditEngine::GetTextHeight( sal_Int32 nParagraph ) const
+tools::Rectangle EditEngine::GetParaBounds( sal_Int32 nPara )
 {
+    if ( !pImpEditEngine->IsFormatted() )
+        pImpEditEngine->FormatDoc();
+
+    Point aPnt = GetDocPosTopLeft( nPara );
+
+    if( IsVertical() )
+    {
+        sal_Int32 nTextHeight = pImpEditEngine->GetTextHeight();
+        sal_Int32 nParaWidth = pImpEditEngine->CalcParaWidth( nPara, true );
+        sal_uLong nParaHeight = pImpEditEngine->GetParaHeight( nPara );
+
+        return tools::Rectangle( nTextHeight - aPnt.Y() - nParaHeight, 0, nTextHeight - aPnt.Y(), nParaWidth );
+    }
+    else
+    {
+        sal_Int32 nParaWidth = pImpEditEngine->CalcParaWidth( nPara, true );
+        sal_uLong nParaHeight = pImpEditEngine->GetParaHeight( nPara );
+
+        return tools::Rectangle( 0, aPnt.Y(), nParaWidth, aPnt.Y() + nParaHeight );
+    }
+}
 
+sal_uInt32 EditEngine::GetTextHeight( sal_Int32 nParagraph ) const
+{
     if ( !pImpEditEngine->IsFormatted() )
         pImpEditEngine->FormatDoc();
 
     sal_uInt32 nHeight = pImpEditEngine->GetParaHeight( nParagraph );
-     return nHeight;
+    return nHeight;
 }
 
 OUString EditEngine::GetWord( sal_Int32 nPara, sal_Int32 nIndex )
diff --git a/editeng/source/editeng/impedit.hxx b/editeng/source/editeng/impedit.hxx
index 864ba04e31ba..0d282605c428 100644
--- a/editeng/source/editeng/impedit.hxx
+++ b/editeng/source/editeng/impedit.hxx
@@ -834,6 +834,7 @@ public:
     sal_uInt32      GetTextHeight() const;
     sal_uInt32      GetTextHeightNTP() const;
     sal_uInt32      CalcTextWidth( bool bIgnoreExtraSpace );
+    sal_uInt32      CalcParaWidth( sal_Int32 nParagraph, bool bIgnoreExtraSpace );
     sal_uInt32      CalcLineWidth( ParaPortion* pPortion, EditLine* pLine, bool bIgnoreExtraSpace, bool bIgnoreTrailingWhiteSpaces = false );
     sal_Int32       GetLineCount( sal_Int32 nParagraph ) const;
     sal_Int32       GetLineLen( sal_Int32 nParagraph, sal_Int32 nLine ) const;
diff --git a/editeng/source/editeng/impedit2.cxx b/editeng/source/editeng/impedit2.cxx
index 9d5658a68109..c58c76b4e8a5 100644
--- a/editeng/source/editeng/impedit2.cxx
+++ b/editeng/source/editeng/impedit2.cxx
@@ -3084,52 +3084,66 @@ sal_uInt32 ImpEditEngine::CalcTextWidth( bool bIgnoreExtraSpace )
     if ( !IsFormatted() && !IsFormatting() )
         FormatDoc();
 
-    long nMaxWidth = 0;
-    long nCurWidth = 0;
-
+    sal_uInt32 nMaxWidth = 0;
 
     // Over all the paragraphs ...
 
     sal_Int32 nParas = GetParaPortions().Count();
     for ( sal_Int32 nPara = 0; nPara < nParas; nPara++ )
     {
-        ParaPortion* pPortion = GetParaPortions()[nPara];
-        if ( pPortion->IsVisible() )
-        {
-            const SvxLRSpaceItem& rLRItem = GetLRSpaceItem( pPortion->GetNode() );
-            sal_Int32 nSpaceBeforeAndMinLabelWidth = GetSpaceBeforeAndMinLabelWidth( pPortion->GetNode() );
+        nMaxWidth = std::max(nMaxWidth, CalcParaWidth(nPara, bIgnoreExtraSpace));
+    }
+
+    return nMaxWidth;
+}
+
+sal_uInt32 ImpEditEngine::CalcParaWidth( sal_Int32 nPara, bool bIgnoreExtraSpace )
+{
+    // If still not formatted and not in the process.
+    // Will be brought in the formatting for AutoPageSize.
+    if ( !IsFormatted() && !IsFormatting() )
+        FormatDoc();
+
+    long nMaxWidth = 0;
 
+    // Over all the paragraphs ...
 
-            // On the lines of the paragraph ...
+    ParaPortion* pPortion = GetParaPortions()[nPara];
+    if ( pPortion->IsVisible() )
+    {
+        const SvxLRSpaceItem& rLRItem = GetLRSpaceItem( pPortion->GetNode() );
+        sal_Int32 nSpaceBeforeAndMinLabelWidth = GetSpaceBeforeAndMinLabelWidth( pPortion->GetNode() );
 
-            sal_Int32 nLines = pPortion->GetLines().Count();
-            for ( sal_Int32 nLine = 0; nLine < nLines; nLine++ )
+
+        // On the lines of the paragraph ...
+
+        sal_Int32 nLines = pPortion->GetLines().Count();
+        for ( sal_Int32 nLine = 0; nLine < nLines; nLine++ )
+        {
+            EditLine& rLine = pPortion->GetLines()[nLine];
+            // nCurWidth = pLine->GetStartPosX();
+            // For Center- or Right- alignment it depends on the paper
+            // width, here not preferred. I general, it is best not leave it
+            // to StartPosX, also the right indents have to be taken into
+            // account!
+            long nCurWidth = GetXValue( rLRItem.GetTextLeft() + nSpaceBeforeAndMinLabelWidth );
+            if ( nLine == 0 )
             {
-                EditLine& rLine = pPortion->GetLines()[nLine];
-                // nCurWidth = pLine->GetStartPosX();
-                // For Center- or Right- alignment it depends on the paper
-                // width, here not preferred. I general, it is best not leave it
-                // to StartPosX, also the right indents have to be taken into
-                // account!
-                nCurWidth = GetXValue( rLRItem.GetTextLeft() + nSpaceBeforeAndMinLabelWidth );
-                if ( nLine == 0 )
+                long nFI = GetXValue( rLRItem.GetTextFirstLineOfst() );
+                nCurWidth -= nFI;
+                if ( pPortion->GetBulletX() > nCurWidth )
                 {
-                    long nFI = GetXValue( rLRItem.GetTextFirstLineOfst() );
-                    nCurWidth -= nFI;
+                    nCurWidth += nFI;   // LI?
                     if ( pPortion->GetBulletX() > nCurWidth )
-                    {
-                        nCurWidth += nFI;   // LI?
-                        if ( pPortion->GetBulletX() > nCurWidth )
-                            nCurWidth = pPortion->GetBulletX();
-                    }
-                }
-                nCurWidth += GetXValue( rLRItem.GetRight() );
-                nCurWidth += CalcLineWidth( pPortion, &rLine, bIgnoreExtraSpace );
-                if ( nCurWidth > nMaxWidth )
-                {
-                    nMaxWidth = nCurWidth;
+                        nCurWidth = pPortion->GetBulletX();
                 }
             }
+            nCurWidth += GetXValue( rLRItem.GetRight() );
+            nCurWidth += CalcLineWidth( pPortion, &rLine, bIgnoreExtraSpace );
+            if ( nCurWidth > nMaxWidth )
+            {
+                nMaxWidth = nCurWidth;
+            }
         }
     }
 
diff --git a/editeng/source/outliner/outlin2.cxx b/editeng/source/outliner/outlin2.cxx
index 78112d85dfac..96285309a635 100644
--- a/editeng/source/outliner/outlin2.cxx
+++ b/editeng/source/outliner/outlin2.cxx
@@ -419,6 +419,11 @@ sal_uLong Outliner::GetTextHeight( sal_Int32 nParagraph ) const
     return pEditEngine->GetTextHeight(nParagraph );
 }
 
+tools::Rectangle Outliner::GetParaBounds( sal_Int32 nParagraph ) const
+{
+    return pEditEngine->GetParaBounds(nParagraph );
+}
+
 Point Outliner::GetDocPos( const Point& rPaperPos ) const
 {
     return pEditEngine->GetDocPos( rPaperPos );
diff --git a/editeng/source/uno/unoforou.cxx b/editeng/source/uno/unoforou.cxx
index 04267165fe55..4abad85c0dff 100644
--- a/editeng/source/uno/unoforou.cxx
+++ b/editeng/source/uno/unoforou.cxx
@@ -338,24 +338,7 @@ tools::Rectangle SvxOutlinerForwarder::GetCharBounds( sal_Int32 nPara, sal_Int32
 
 tools::Rectangle SvxOutlinerForwarder::GetParaBounds( sal_Int32 nPara ) const
 {
-    Point aPnt = rOutliner.GetDocPosTopLeft( nPara );
-    Size aSize = rOutliner.CalcTextSize();
-
-    if( rOutliner.IsVertical() )
-    {
-        // Hargl. Outliner's 'external' methods return the rotated
-        // dimensions, 'internal' methods like GetTextHeight( n )
-        // don't rotate.
-        sal_uLong nWidth = rOutliner.GetTextHeight( nPara );
-
-        return tools::Rectangle( aSize.Width() - aPnt.Y() - nWidth, 0, aSize.Width() - aPnt.Y(), aSize.Height() );
-    }
-    else
-    {
-        sal_uLong nHeight = rOutliner.GetTextHeight( nPara );
-
-        return tools::Rectangle( 0, aPnt.Y(), aSize.Width(), aPnt.Y() + nHeight );
-    }
+    return rOutliner.GetParaBounds( nPara );
 }
 
 MapMode SvxOutlinerForwarder::GetMapMode() const
diff --git a/include/editeng/editeng.hxx b/include/editeng/editeng.hxx
index 44663abcc28b..ee4eb7baeb31 100644
--- a/include/editeng/editeng.hxx
+++ b/include/editeng/editeng.hxx
@@ -286,6 +286,7 @@ public:
     void            GetLineBoundaries( /*out*/sal_Int32& rStart, /*out*/sal_Int32& rEnd, sal_Int32 nParagraph, sal_Int32 nLine ) const;
     sal_Int32       GetLineNumberAtIndex( sal_Int32 nPara, sal_Int32 nIndex ) const;
     sal_uInt32      GetLineHeight( sal_Int32 nParagraph );
+    tools::Rectangle GetParaBounds( sal_Int32 nPara );
     ParagraphInfos  GetParagraphInfos( sal_Int32 nPara );
     sal_Int32       FindParagraph( long nDocPosY );
     EPosition       FindDocPosition( const Point& rDocPos ) const;
diff --git a/include/editeng/outliner.hxx b/include/editeng/outliner.hxx
index 5ef2a56ac05c..ee856b9e6b35 100644
--- a/include/editeng/outliner.hxx
+++ b/include/editeng/outliner.hxx
@@ -931,6 +931,7 @@ public:
 
     sal_uLong       GetTextHeight() const;
     sal_uLong       GetTextHeight( sal_Int32 nParagraph ) const;
+    tools::Rectangle GetParaBounds( sal_Int32 nParagraph ) const;
     Point           GetDocPosTopLeft( sal_Int32 nParagraph );
     Point           GetDocPos( const Point& rPaperPos ) const;
     bool            IsTextPos( const Point& rPaperPos, sal_uInt16 nBorder );


More information about the Libreoffice-commits mailing list