summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNoel Grandin <noel.grandin@collabora.co.uk>2018-04-04 11:17:15 +0200
committerNoel Grandin <noel.grandin@collabora.co.uk>2018-04-04 13:28:52 +0200
commite278df1a14c5cb5dbb7add5d6ed5dd52da131e92 (patch)
tree10ca8af6f78a576fb9c11ffbeffd02a30e3fb5c6
parent891e41fac81fbd8d5cdb277b26639abfd25a7143 (diff)
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@libreoffice.org> Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
-rw-r--r--editeng/source/editeng/editeng.cxx27
-rw-r--r--editeng/source/editeng/impedit.hxx1
-rw-r--r--editeng/source/editeng/impedit2.cxx78
-rw-r--r--editeng/source/outliner/outlin2.cxx5
-rw-r--r--editeng/source/uno/unoforou.cxx19
-rw-r--r--include/editeng/editeng.hxx1
-rw-r--r--include/editeng/outliner.hxx1
7 files changed, 80 insertions, 52 deletions
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 );