Kaydet (Commit) e278df1a authored tarafından Noel Grandin's avatar Noel Grandin

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/52369Tested-by: 's avatarJenkins <ci@libreoffice.org>
Reviewed-by: 's avatarNoel Grandin <noel.grandin@collabora.co.uk>
üst 891e41fa
......@@ -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 )
......
......@@ -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;
......
......@@ -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;
}
}
}
......
......@@ -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 );
......
......@@ -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
......
......@@ -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;
......
......@@ -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 );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment