editeng/inc/EditLine.hxx            |    3 
 editeng/qa/unit/core-test.cxx       |   60 ++++++++++++++
 editeng/source/editeng/EditLine.cxx |    1 
 editeng/source/editeng/impedit3.cxx |  147 ++++++++++++++++++++++++++----------
 4 files changed, 172 insertions(+), 39 deletions(-)

New commits:
commit 9ed6d80622174826f8b7413529320ccd94782296
Author:     Attila Szűcs <attila.sz...@collabora.com>
AuthorDate: Wed Jan 24 12:03:28 2024 +0100
Commit:     Caolán McNamara <caolan.mcnam...@collabora.com>
CommitDate: Fri Feb 16 18:10:51 2024 +0100

    tdf#154248 sd: change multiline field wrapping
    
    Modified ImpEditEngine::CreateLines and ImpEditEngine::Paint
    to wrap multiline fields (hyperlinks) to wrap better:
    
    Multiline hyperlinks can start/end in the middle of a line.
    like this:
    text hyperlink-start
    hyperlink-line2.....
    hyperlink-end text
    
    Start of the lines of the multiline hyperlinks now follow the line
    start (for example if the 1. line has a bullet/indent, and the
    2. line does not then the multiline hyperlink 2. line will start
    where normal 2. line would start)
    
    Changed the way how fields wrapped while editing.. (we didn't split
    fields into lines, when its textbox is edited, but now we do)
    This way it is more a WYSIWYG editor. (when we edit, we see what
    we will get)
    
    Changed the constant reference rLine to non-constant pointer
    pLine, because this hack change the actual line to the next line
    at the end of a muliline hyperlink, so the algotithm will
    continue calculating with the next line, as if it would be still
    the previous line.
    
    Change-Id: I2c67f4ae1b86ee9c73f01ae0c045f02e56a09c1c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162503
    Tested-by: Jenkins
    Tested-by: Caolán McNamara <caolan.mcnam...@collabora.com>
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>

diff --git a/editeng/inc/EditLine.hxx b/editeng/inc/EditLine.hxx
index 165f3fcf0a59..7d4a43e0e639 100644
--- a/editeng/inc/EditLine.hxx
+++ b/editeng/inc/EditLine.hxx
@@ -35,6 +35,7 @@ private:
     std::vector<sal_Bool> aKashidaPositions;
     sal_Int32 nTxtWidth = 0;
     sal_Int32 nStartPosX = 0;
+    sal_Int32 nNextLinePosXDiff = 0;
     sal_Int32 nStart = 0; // could be replaced by nStartPortion
     sal_Int32 nEnd = 0; // could be replaced by nEndPortion
     sal_Int32 nStartPortion = 0;
@@ -97,6 +98,8 @@ public:
 
     sal_Int32 GetStartPosX() const { return nStartPosX; }
     void SetStartPosX(sal_Int32 start);
+    sal_Int32 GetNextLinePosXDiff() const { return nNextLinePosXDiff; }
+    void SetNextLinePosXDiff(sal_Int32 diff) { nNextLinePosXDiff = diff; }
     Size CalcTextSize(ParaPortion& rParaPortion);
 
     bool IsInvalid() const { return bInvalid; }
diff --git a/editeng/qa/unit/core-test.cxx b/editeng/qa/unit/core-test.cxx
index 59f5c0ac7839..177310dd6b82 100644
--- a/editeng/qa/unit/core-test.cxx
+++ b/editeng/qa/unit/core-test.cxx
@@ -122,6 +122,7 @@ public:
     void testSingleLine();
     void testMoveParagraph();
     void testCreateLines();
+    void testTdf154248MultilineFieldWrapping();
 
     DECL_STATIC_LINK( Test, CalcFieldValueHdl, EditFieldInfo*, void );
 
@@ -152,6 +153,7 @@ public:
     CPPUNIT_TEST(testSingleLine);
     CPPUNIT_TEST(testMoveParagraph);
     CPPUNIT_TEST(testCreateLines);
+    CPPUNIT_TEST(testTdf154248MultilineFieldWrapping);
     CPPUNIT_TEST_SUITE_END();
 
 private:
@@ -2238,6 +2240,64 @@ void Test::testCreateLines()
     // CPPUNIT_ASSERT_MESSAGE("INTENTIONALLY FALSE", false);
 }
 
+void Test::testTdf154248MultilineFieldWrapping()
+{
+    // If field wrapping changes, this test may need to be updated
+
+    // Create Outliner instance
+    Outliner aOutliner(mpItemPool.get(), OutlinerMode::TextObject);
+    aOutliner.SetCalcFieldValueHdl(LINK(nullptr, Test, CalcFieldValueHdl));
+
+    // Create EditEngine's instance
+    EditEngine& aEditEngine = 
const_cast<EditEngine&>(aOutliner.GetEditEngine());
+    aEditEngine.SetPaperSize(Size(2000, 2000));
+    aEditEngine.SetText("ABC  DEF ABC DEFGH");
+    // Positions Ref     ....*4............
+
+    // Get Field Item for inserting URLs in text
+    SvxURLField aURLField("http://not.a.real.link";,
+                          "Really long hyperlink text that wont fit in 1 line, 
no matter what.",
+                          SvxURLFormat::Repr);
+    SvxFieldItem aField(aURLField, EE_FEATURE_FIELD);
+
+    // Insert URL
+    EditDoc& rDoc = aEditEngine.GetEditDoc();
+    ContentNode* pNode = rDoc.GetObject(0);
+    EditSelection aSel(EditPaM(pNode, 4), EditPaM(pNode, 4));
+    aEditEngine.InsertField(aSel, aField);
+
+    // Assert Field Count
+    CPPUNIT_ASSERT_EQUAL(sal_uInt16(1), aEditEngine.GetFieldCount(0));
+
+    aEditEngine.QuickFormatDoc(false);
+    CPPUNIT_ASSERT_EQUAL(true, aEditEngine.IsFormatted());
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aEditEngine.GetParagraphCount());
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), aEditEngine.GetLineCount(0));
+
+    ParaPortionList& rParagraphPortionList = aEditEngine.GetParaPortions();
+    EditLineList& rLines = rParagraphPortionList.getRef(0).GetLines();
+    {
+        EditLine const& rLine = rLines[0];
+        CPPUNIT_ASSERT_EQUAL(sal_Int32(0), rLine.GetStart());
+        // Line 1 contains the beginning of the link.
+        CPPUNIT_ASSERT_EQUAL(sal_Int32(5), rLine.GetEnd());
+    }
+
+    {
+        EditLine const& rLine = rLines[1];
+        CPPUNIT_ASSERT_EQUAL(sal_Int32(5), rLine.GetStart());
+        //Line 2 contains the end of the link and the text that follows it
+        CPPUNIT_ASSERT_EQUAL(sal_Int32(14), rLine.GetEnd());
+    }
+
+    {
+        EditLine const& rLine = rLines[2];
+        //line 3 contains the last word that does not fit in line 2
+        CPPUNIT_ASSERT_EQUAL(sal_Int32(14), rLine.GetStart());
+        CPPUNIT_ASSERT_EQUAL(sal_Int32(19), rLine.GetEnd());
+    }
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(Test);
 
 }
diff --git a/editeng/source/editeng/EditLine.cxx 
b/editeng/source/editeng/EditLine.cxx
index 7724f8f12a79..af61651ab72f 100644
--- a/editeng/source/editeng/EditLine.cxx
+++ b/editeng/source/editeng/EditLine.cxx
@@ -26,6 +26,7 @@ EditLine* EditLine::Clone() const
     EditLine* pL = new EditLine;
     pL->aPositions = aPositions;
     pL->nStartPosX      = nStartPosX;
+    pL->nNextLinePosXDiff = nNextLinePosXDiff;
     pL->nStart          = nStart;
     pL->nEnd            = nEnd;
     pL->nStartPortion   = nStartPortion;
diff --git a/editeng/source/editeng/impedit3.cxx 
b/editeng/source/editeng/impedit3.cxx
index 54a7745eca7a..5beaaf95e434 100644
--- a/editeng/source/editeng/impedit3.cxx
+++ b/editeng/source/editeng/impedit3.cxx
@@ -823,6 +823,8 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, 
sal_uInt32 nStartPosY )
 
     // Reformat all lines from here...
 
+    int nStartNextLineAfterMultiLineField = 0;
+
     sal_Int32 nDelFromLine = -1;
     bool bLineBreak = false;
 
@@ -845,6 +847,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, 
sal_uInt32 nStartPosY )
         assert(pLine);
 
         bForceOneRun = false;
+        bool bFieldStartNextLine = false;
 
         bool bEOL = false;
         bool bEOC = false;
@@ -852,6 +855,8 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, 
sal_uInt32 nStartPosY )
         sal_Int32 nPortionEnd = 0;
 
         tools::Long nStartX = scaleXSpacingValue(rLRItem.GetTextLeft() + 
nSpaceBeforeAndMinLabelWidth);
+        // Multiline hyperlink may need to know if the next line is bigger.
+        tools::Long nStartXNextLine = nStartX;
         if ( nIndex == 0 )
         {
             tools::Long nFI = 
scaleXSpacingValue(rLRItem.GetTextFirstLineOffset());
@@ -863,6 +868,8 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, 
sal_uInt32 nStartPosY )
             }
         }
 
+        nStartX += nStartNextLineAfterMultiLineField;
+        nStartNextLineAfterMultiLineField = 0;
         tools::Long nMaxLineWidth = calculateMaxLineWidth(nStartX, rLRItem);
 
         // Problem:
@@ -1113,7 +1120,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, 
sal_uInt32 nStartPosY )
                             aFieldValue, 0, aFieldValue.getLength(), 
&aTmpDXArray));
 
                         // So no scrolling for oversized fields
-                        if ( pPortion->GetSize().Width() > nXWidth )
+                        if (pPortion->GetSize().Width() > nXWidth - nTmpWidth)
                         {
                             // create ExtraPortionInfo on-demand, flush 
lineBreaksList
                             ExtraPortionInfo *pExtraInfo = 
pPortion->GetExtraInfos();
@@ -1145,6 +1152,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, 
sal_uInt32 nStartPosY )
                                         nDone));
                             sal_Int32 nLastCellBreak(0);
                             sal_Int32 nLineStartX(0);
+                            nLineStartX = -nTmpWidth;
 
                             // always add 1st line break (safe, we already 
know we are larger than nXWidth)
                             pExtraInfo->lineBreaksList.push_back(0);
@@ -1162,6 +1170,22 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, 
sal_uInt32 nStartPosY )
                                         if(0 != a)
                                         {
                                             
pExtraInfo->lineBreaksList.push_back(a);
+                                            // the following lines may be 
different sized
+                                            if (nStartX > nStartXNextLine)
+                                            {
+                                                nXWidth += nStartX - 
nStartXNextLine;
+                                                
pLine->SetNextLinePosXDiff(nStartX
+                                                                           - 
nStartXNextLine);
+                                                nStartXNextLine = nStartX;
+                                            }
+                                        }
+                                        else
+                                        {
+                                            //even the 1. char does not fit..
+                                            //this means the field should 
start on next line
+                                            //except if the actual line is a 
full line already
+                                            if (nLineStartX < 0 || nStartX > 
nStartXNextLine)
+                                                bFieldStartNextLine = true;
                                         }
 
                                         // moveLineStart forward in X
@@ -1179,6 +1203,17 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, 
sal_uInt32 nStartPosY )
                                         nDone);
                                 }
                             }
+                            //next Line should start here... after this field 
end
+                            if (!bFieldStartNextLine)
+                                nStartNextLineAfterMultiLineField
+                                    = aTmpDXArray[nTextLength - 1] - 
nLineStartX;
+                            else if (pExtraInfo)
+                            {
+                                // if the 1. character does not fit,
+                                // but there is pExtraInfo, then delete it
+                                pPortion->SetExtraInfos(nullptr);
+                                pExtraInfo = nullptr;
+                            }
                         }
                         nTmpWidth += pPortion->GetSize().Width();
                         EditLine::CharPosArrayType& rArray = 
pLine->GetCharPosArray();
@@ -1403,13 +1438,29 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, 
sal_uInt32 nStartPosY )
         }
         else if ( bFixedEnd )
         {
-            pLine->SetEnd( nPortionStart );
-            pLine->SetEndPortion( nTmpPortion-1 );
+            if (bFieldStartNextLine)
+            {
+                pLine->SetEnd(nPortionStart);
+                pLine->SetEndPortion(nTmpPortion - 1);
+            }
+            else
+            {
+                pLine->SetEnd(nPortionStart + 1);
+                pLine->SetEndPortion(nTmpPortion);
+            }
         }
         else if ( bLineBreak || bBrokenLine )
         {
-            pLine->SetEnd( nPortionStart+1 );
-            pLine->SetEndPortion( nTmpPortion-1 );
+            if (bFieldStartNextLine)
+            {
+                pLine->SetEnd(nPortionStart);
+                pLine->SetEndPortion(nTmpPortion - 2);
+            }
+            else
+            {
+                pLine->SetEnd(nPortionStart + 1);
+                pLine->SetEndPortion(nTmpPortion - 1);
+            }
             bEOC = false; // was set above, maybe change the sequence of the 
if's?
         }
         else if ( !bEOL && !bContinueLastPortion )
@@ -3313,7 +3364,6 @@ Point ImpEditEngine::MoveToNextLine(
 }
 
 // TODO: use IterateLineAreas in ImpEditEngine::Paint, to avoid algorithm 
duplication
-
 void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, 
Point aStartPos, bool bStripOnly, Degree10 nOrientation )
 {
     if ( !IsUpdateLayout() && !bStripOnly )
@@ -3382,15 +3432,15 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, 
tools::Rectangle aClipRect, Po
 
             for ( sal_Int32 nLine = 0; nLine < nLines; nLine++ )
             {
-                EditLine const& rLine = rParaPortion.GetLines()[nLine];
-                sal_Int32 nIndex = rLine.GetStart();
-                tools::Long nLineHeight = rLine.GetHeight();
+                EditLine* pLine = 
&GetParaPortions().getRef(nParaPortion).GetLines()[nLine];
+                sal_Int32 nIndex = pLine->GetStart();
+                tools::Long nLineHeight = pLine->GetHeight();
                 if (nLine != nLastLine)
                     nLineHeight += nVertLineSpacing;
                 MoveToNextLine(aStartPos, nLineHeight, nColumn, aOrigin);
                 aTmpPos = aStartPos;
-                adjustXDirectionAware(aTmpPos, rLine.GetStartPosX());
-                adjustYDirectionAware(aTmpPos, rLine.GetMaxAscent() - 
nLineHeight);
+                adjustXDirectionAware(aTmpPos, pLine->GetStartPosX());
+                adjustYDirectionAware(aTmpPos, pLine->GetMaxAscent() - 
nLineHeight);
 
                 if ( ( !IsEffectivelyVertical() && ( aStartPos.Y() > 
aClipRect.Top() ) )
                     || ( IsEffectivelyVertical() && IsTopToBottom() && 
aStartPos.X() < aClipRect.Right() )
@@ -3418,15 +3468,24 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, 
tools::Rectangle aClipRect, Po
 
                     bool bParsingFields = false;
                     std::vector< sal_Int32 >::iterator itSubLines;
+                    tools::Long nFirstPortionXOffset = 0;
 
-                    for ( sal_Int32 nPortion = rLine.GetStartPortion(); 
nPortion <= rLine.GetEndPortion(); nPortion++ )
+                    for ( sal_Int32 nPortion = pLine->GetStartPortion(); 
nPortion <= pLine->GetEndPortion(); nPortion++ )
                     {
                         DBG_ASSERT(rParaPortion.GetTextPortions().Count(), 
"Line without Textportion in Paint!");
                         const TextPortion& rTextPortion = 
rParaPortion.GetTextPortions()[nPortion];
 
-                        const tools::Long nPortionXOffset = 
GetPortionXOffset(rParaPortion, rLine, nPortion);
+                        const tools::Long nPortionXOffset = 
GetPortionXOffset(rParaPortion, *pLine, nPortion);
                         setXDirectionAwareFrom(aTmpPos, aStartPos);
-                        adjustXDirectionAware(aTmpPos, nPortionXOffset);
+
+                        if (nPortion == pLine->GetStartPortion())
+                            nFirstPortionXOffset = nPortionXOffset;
+
+                        if (!bParsingFields)
+                            adjustXDirectionAware(aTmpPos, nPortionXOffset);
+                        else
+                            adjustXDirectionAware(aTmpPos, 
nFirstPortionXOffset);
+
                         if (isXOverflowDirectionAware(aTmpPos, aClipRect))
                             break; // No further output in line necessary
 
@@ -3488,13 +3547,13 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, 
tools::Rectangle aClipRect, Po
                                     aText = 
rParaPortion.GetNode()->GetString();
                                     nTextStart = nIndex;
                                     nTextLen = rTextPortion.GetLen();
-                                    pDXArray = 
std::span(rLine.GetCharPosArray().data() + (nIndex - rLine.GetStart()),
-                                                    
rLine.GetCharPosArray().size() - (nIndex - rLine.GetStart()));
+                                    pDXArray = 
std::span(pLine->GetCharPosArray().data() + (nIndex - pLine->GetStart()),
+                                                    
pLine->GetCharPosArray().size() - (nIndex - pLine->GetStart()));
 
-                                    if (!rLine.GetKashidaArray().empty())
+                                    if (!pLine->GetKashidaArray().empty())
                                     {
-                                        pKashidaArray = 
std::span(rLine.GetKashidaArray().data() + (nIndex - rLine.GetStart()),
-                                                    
rLine.GetKashidaArray().size() - (nIndex - rLine.GetStart()));
+                                        pKashidaArray = 
std::span(pLine->GetKashidaArray().data() + (nIndex - pLine->GetStart()),
+                                                    
pLine->GetKashidaArray().size() - (nIndex - pLine->GetStart()));
                                     }
 
                                     // Paint control characters (#i55716#)
@@ -3522,7 +3581,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, 
tools::Rectangle aClipRect, Po
                                                 const tools::Long nAdvanceX = 
( nTmpIdx == nTmpEnd ?
                                                                          
rTextPortion.GetSize().Width() :
                                                                          
pDXArray[ nTmpIdx - nTextStart ] ) - nHalfBlankWidth;
-                                                const tools::Long nAdvanceY = 
-rLine.GetMaxAscent();
+                                                const tools::Long nAdvanceY = 
-pLine->GetMaxAscent();
 
                                                 Point aTopLeftRectPos( aTmpPos 
);
                                                 
adjustXDirectionAware(aTopLeftRectPos, nAdvanceX);
@@ -3530,7 +3589,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, 
tools::Rectangle aClipRect, Po
 
                                                 Point aBottomRightRectPos( 
aTopLeftRectPos );
                                                 
adjustXDirectionAware(aBottomRightRectPos, 2 * nHalfBlankWidth);
-                                                
adjustYDirectionAware(aBottomRightRectPos, rLine.GetHeight());
+                                                
adjustYDirectionAware(aBottomRightRectPos, pLine->GetHeight());
 
                                                 rOutDev.Push( 
vcl::PushFlags::FILLCOLOR );
                                                 rOutDev.Push( 
vcl::PushFlags::LINECOLOR );
@@ -3579,15 +3638,12 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, 
tools::Rectangle aClipRect, Po
                                     nTextStart = 0;
                                     nTextLen = aText.getLength();
                                     ExtraPortionInfo *pExtraInfo = 
rTextPortion.GetExtraInfos();
-                                    // Do not split the Fields into different 
lines while editing
-                                    // With EditView on Overlay bStripOnly is 
now set for stripping to
-                                    // primitives. To stay compatible in 
EditMode use mpActiveView to detect
-                                    // when we are in EditMode. For whatever 
reason URLs are drawn as single
-                                    // line in edit mode, originally clipped 
against edit area (which is no
-                                    // longer done in Overlay mode and allows 
to *read* the URL).
-                                    // It would be difficult to change this 
due to needed adaptations in
-                                    // EditEngine (look for lineBreaksList 
creation)
-                                    if (nullptr == mpActiveView && bStripOnly 
&& !bParsingFields && pExtraInfo && !pExtraInfo->lineBreaksList.empty())
+                                    //For historical reasons URLs was drawn as 
single line in edit mode
+                                    //but now we changed it, so it wraps 
similar as simple text.
+                                    //It is not perfect, it still use 
lineBreaksList, so it won’t seek
+                                    //word ends to wrap text there, but it 
would be difficult to change
+                                    //this due to needed adaptations in 
EditEngine
+                                    if (bStripOnly && !bParsingFields && 
pExtraInfo && !pExtraInfo->lineBreaksList.empty())
                                     {
                                         bParsingFields = true;
                                         itSubLines = 
pExtraInfo->lineBreaksList.begin();
@@ -3597,13 +3653,14 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, 
tools::Rectangle aClipRect, Po
                                     {
                                         if( itSubLines != 
pExtraInfo->lineBreaksList.begin() )
                                         {
-                                            // only use GetMaxAscent(), 
rLine.GetHeight() will not
+                                            // only use GetMaxAscent(), 
pLine->GetHeight() will not
                                             // proceed as needed (see 
PortionKind::TEXT above and nAdvanceY)
                                             // what will lead to a compressed 
look with multiple lines
-                                            const sal_uInt16 
nMaxAscent(rLine.GetMaxAscent());
+                                            const sal_uInt16 
nMaxAscent(pLine->GetMaxAscent());
 
                                             aTmpPos += 
MoveToNextLine(aStartPos, nMaxAscent,
                                                                       nColumn, 
aOrigin);
+                                            adjustXDirectionAware(aTmpPos, 
-pLine->GetNextLinePosXDiff());
                                         }
                                         std::vector< sal_Int32 >::iterator 
curIt = itSubLines;
                                         ++itSubLines;
@@ -3623,15 +3680,27 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, 
tools::Rectangle aClipRect, Po
                                                 // tdf#148966 don't paint the 
line break following a
                                                 // multiline field based on a 
compat flag
                                                 OutlinerEditEng* pOutlEditEng{ 
dynamic_cast<OutlinerEditEng*>(mpEditEngine)};
+                                                int nStartNextLine = 
rParaPortion.GetLines()[nLine + 1].GetStartPortion();
+                                                const TextPortion& 
rNextTextPortion = rParaPortion.GetTextPortions()[nStartNextLine];
                                                 if (pOutlEditEng
                                                     && 
pOutlEditEng->GetCompatFlag(SdrCompatibilityFlag::IgnoreBreakAfterMultilineField)
                                                            .value_or(false))
                                                 {
-                                                    int nStartNextLine = 
rParaPortion.GetLines()[nLine + 1].GetStartPortion();
-                                                    const TextPortion& 
rNextTextPortion = rParaPortion.GetTextPortions()[nStartNextLine];
                                                     if 
(rNextTextPortion.GetKind() == PortionKind::LINEBREAK)
                                                         ++nLine; //ignore the 
following linebreak
                                                 }
+                                                else if (mpActiveView && 
rNextTextPortion.GetKind() == PortionKind::LINEBREAK)
+                                                {
+                                                    // if we are at edit mode, 
the compat flag does not work
+                                                    // here we choose to work 
if compat flag is true,
+                                                    // this is better for 
newer documents
+                                                    nLine++;
+                                                }
+                                                if (rNextTextPortion.GetKind() 
!= PortionKind::LINEBREAK)
+                                                {
+                                                    nLine++;
+                                                    pLine = 
&GetParaPortions().getRef(nParaPortion).GetLines()[nLine];
+                                                }
                                             }
                                         }
                                     }
@@ -3750,7 +3819,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, 
tools::Rectangle aClipRect, Po
                                     const lang::Locale 
aLocale(GetLocale(EditPaM(rParaPortion.GetNode(), nIndex + 1)));
 
                                     // create EOL and EOP bools
-                                    const bool bEndOfLine(nPortion == 
rLine.GetEndPortion());
+                                    const bool bEndOfLine(nPortion == 
pLine->GetEndPortion());
                                     const bool bEndOfParagraph(bEndOfLine && 
nLine + 1 == nLines);
 
                                     // get Overline color (from ((const 
SvxOverlineItem*)GetItem())->GetColor() in
@@ -3897,7 +3966,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, 
tools::Rectangle aClipRect, Po
                                         if ( bDrawFrame )
                                         {
                                             Point aTopLeft( aTmpPos );
-                                            aTopLeft.AdjustY( 
-(rLine.GetMaxAscent()) );
+                                            aTopLeft.AdjustY( 
-(pLine->GetMaxAscent()) );
                                             if ( nOrientation )
                                                 aOrigin.RotateAround(aTopLeft, 
nOrientation);
                                             tools::Rectangle aRect( aTopLeft, 
rTextPortion.GetSize() );
@@ -3910,7 +3979,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, 
tools::Rectangle aClipRect, Po
                                             if (auto pUrlField = 
dynamic_cast<const SvxURLField*>(pFieldData))
                                             {
                                                 Point aTopLeft(aTmpPos);
-                                                
aTopLeft.AdjustY(-(rLine.GetMaxAscent()));
+                                                
aTopLeft.AdjustY(-(pLine->GetMaxAscent()));
 
                                                 tools::Rectangle 
aRect(aTopLeft, rTextPortion.GetSize());
                                                 vcl::PDFExtOutDevBookmarkEntry 
aBookmark;
@@ -4001,7 +4070,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, 
tools::Rectangle aClipRect, Po
                                     if ( bStripOnly )
                                     {
                                         // create EOL and EOP bools
-                                        const bool bEndOfLine(nPortion == 
rLine.GetEndPortion());
+                                        const bool bEndOfLine(nPortion == 
pLine->GetEndPortion());
                                         const bool bEndOfParagraph(bEndOfLine 
&& nLine + 1 == nLines);
 
                                         const Color 
aOverlineColor(rOutDev.GetOverlineColor());
@@ -4021,7 +4090,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, 
tools::Rectangle aClipRect, Po
                                     // #i108052# When stripping, a callback 
for _empty_ paragraphs is also needed.
                                     // This was optimized away (by not 
rendering the space-only tab portion), so do
                                     // it manually here.
-                                    const bool bEndOfLine(nPortion == 
rLine.GetEndPortion());
+                                    const bool bEndOfLine(nPortion == 
pLine->GetEndPortion());
                                     const bool bEndOfParagraph(bEndOfLine && 
nLine + 1 == nLines);
 
                                     const Color 
aOverlineColor(rOutDev.GetOverlineColor());

Reply via email to