sw/source/core/text/EnhancedPDFExportHelper.cxx |   18 +++++++++++++-----
 sw/source/core/text/frmpaint.cxx                |   17 ++++++++++++-----
 sw/source/core/text/itrpaint.cxx                |   10 +++++-----
 sw/source/core/text/itrpaint.hxx                |    3 ++-
 sw/source/core/text/porlay.cxx                  |   14 ++++++++++++++
 sw/source/core/text/porlay.hxx                  |    1 +
 6 files changed, 47 insertions(+), 16 deletions(-)

New commits:
commit dd3c70518851b532f43a853d8e0c6189013844c4
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Fri Mar 17 15:20:57 2023 +0100
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Fri Mar 17 17:22:05 2023 +0000

    sw: fix assert on tdf140219-2.odt
    
    itrpaint.cxx:421: void SwTextPainter::DrawTextLine: Assertion 
`!roTaggedParagraph' failed.
    
    The unexpected situation is that the SwTextFrame contains no numbering
    portions but only fly portions, and the follow SwTextFrame contains the
    numbering portion.
    
    Delay producing the numbering and paragraph structured elements until
    the numbering portions - it's the only way to create the list structure
    correctly.
    
    Unfortunately this means that the fly anchored on the paragraph won't be
    nested inside the paragraph structured element any more, because it's
    created later, but that seems rather difficult to do and the paint order
    in sw already prevents this from working for hell layer flys.
    
    (regression from commit 9b38beadf9eaf027b201cdf0ecb2bce5611014dd)
    
    Change-Id: I9b40b85edd6f4b9920beac5602a5d3a6d4de5dd3
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/149058
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/sw/source/core/text/EnhancedPDFExportHelper.cxx 
b/sw/source/core/text/EnhancedPDFExportHelper.cxx
index f7daeefa0ce6..4db59dcd1be5 100644
--- a/sw/source/core/text/EnhancedPDFExportHelper.cxx
+++ b/sw/source/core/text/EnhancedPDFExportHelper.cxx
@@ -976,10 +976,19 @@ void 
SwTaggedPDFHelper::BeginNumberedListStructureElements()
     const SwTextFrame& rTextFrame = static_cast<const SwTextFrame&>(rFrame);
 
     // Lowers of NonStructureElements should not be considered:
-
-    if ( lcl_IsInNonStructEnv( rTextFrame ) || rTextFrame.IsFollow() )
+    if (lcl_IsInNonStructEnv(rTextFrame))
         return;
 
+    // do it for the first one in the follow chain that has content
+    for (SwFlowFrame const* pPrecede = rTextFrame.GetPrecede(); pPrecede; 
pPrecede = pPrecede->GetPrecede())
+    {
+        SwTextFrame const*const pText(static_cast<SwTextFrame 
const*>(pPrecede));
+        if (!pText->HasPara() || pText->GetPara()->HasContentPortions())
+        {
+            return;
+        }
+    }
+
     const SwTextNode *const pTextNd = rTextFrame.GetTextNodeForParaProps();
     const SwNumRule* pNumRule = pTextNd->GetNumRule();
     const SwNodeNum* pNodeNum = pTextNd->GetNum(rTextFrame.getRootFrame());
@@ -1099,7 +1108,7 @@ void 
SwTaggedPDFHelper::BeginNumberedListStructureElements()
     {
         BeginTag( vcl::PDFWriter::ListItem, aListItemString );
         assert(rTextFrame.GetPara());
-        // check whether to open LIBody now or delay until after Lbl
+        // check whether to open LBody now or delay until after Lbl
         if 
(!rTextFrame.GetPara()->HasNumberingPortion(SwParaPortion::OnlyNumbering))
         {
             BeginTag(vcl::PDFWriter::LIBody, aListBodyString);
@@ -1203,10 +1212,9 @@ void SwTaggedPDFHelper::BeginBlockStructureElements()
         case SwFrameType::Txt :
             {
                 SwTextFrame const& rTextFrame(*static_cast<const 
SwTextFrame*>(pFrame));
-                // lazy open LIBody after Lbl
+                // lazy open LBody after Lbl
                 if 
(rTextFrame.GetPara()->HasNumberingPortion(SwParaPortion::OnlyNumbering))
                 {
-                    assert(!rTextFrame.IsFollow());
                     BeginTag(vcl::PDFWriter::LIBody, aListBodyString);
                 }
 
diff --git a/sw/source/core/text/frmpaint.cxx b/sw/source/core/text/frmpaint.cxx
index 5f004b403916..74ff8c968e07 100644
--- a/sw/source/core/text/frmpaint.cxx
+++ b/sw/source/core/text/frmpaint.cxx
@@ -673,8 +673,15 @@ void SwTextFrame::PaintSwFrame(vcl::RenderContext& 
rRenderContext, SwRect const&
         }
     }
 
-    Num_Info aNumInfo( *this );
-    SwTaggedPDFHelper aTaggedPDFHelperNumbering( &aNumInfo, nullptr, nullptr, 
rRenderContext );
+    // tdf140219-2.odt text frame with only fly portions and a follow is not
+    // actually a paragraph - delay creating all structured elements to follow.
+    bool const isPDFTaggingEnabled(!HasFollow() || 
GetPara()->HasContentPortions());
+    ::std::optional<SwTaggedPDFHelper> oTaggedPDFHelperNumbering;
+    if (isPDFTaggingEnabled)
+    {
+        Num_Info aNumInfo(*this);
+        oTaggedPDFHelperNumbering.emplace(&aNumInfo, nullptr, nullptr, 
rRenderContext);
+    }
 
     // Lbl unfortunately must be able to contain multiple numbering portions
     // that may be on multiple lines of text (but apparently always in the
@@ -683,7 +690,7 @@ void SwTextFrame::PaintSwFrame(vcl::RenderContext& 
rRenderContext, SwRect const&
     // Paragraph tag - if there is a list label, opening should be delayed.
     ::std::optional<SwTaggedPDFHelper> oTaggedParagraph;
 
-    if (IsFollow() || 
!GetPara()->HasNumberingPortion(SwParaPortion::FootnoteToo))
+    if (isPDFTaggingEnabled && 
!GetPara()->HasNumberingPortion(SwParaPortion::FootnoteToo))
     {   // no Lbl needed => open paragraph tag now
         Frame_Info aFrameInfo(*this);
         oTaggedParagraph.emplace(nullptr, &aFrameInfo, nullptr, 
rRenderContext);
@@ -773,7 +780,7 @@ void SwTextFrame::PaintSwFrame(vcl::RenderContext& 
rRenderContext, SwRect const&
         {
             do
             {
-                aLine.DrawTextLine(rRect, aClip, IsUndersized(), oTaggedLabel, 
oTaggedParagraph);
+                aLine.DrawTextLine(rRect, aClip, IsUndersized(), oTaggedLabel, 
oTaggedParagraph, isPDFTaggingEnabled);
 
             } while( aLine.Next() && aLine.Y() <= nBottom );
         }
@@ -791,7 +798,7 @@ void SwTextFrame::PaintSwFrame(vcl::RenderContext& 
rRenderContext, SwRect const&
     OSL_ENSURE( ! IsSwapped(), "A frame is swapped after Paint" );
 
     assert(!oTaggedLabel); // must have been closed if opened
-    assert(oTaggedParagraph || rRect.GetIntersection(getFrameArea()) != 
getFrameArea()); // must have been created during complete paint (PDF export is 
always complete paint)
+    assert(!isPDFTaggingEnabled || oTaggedParagraph || 
rRect.GetIntersection(getFrameArea()) != getFrameArea()); // must have been 
created during complete paint (PDF export is always complete paint)
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/text/itrpaint.cxx b/sw/source/core/text/itrpaint.cxx
index 8f212988cba8..c2a455641715 100644
--- a/sw/source/core/text/itrpaint.cxx
+++ b/sw/source/core/text/itrpaint.cxx
@@ -121,7 +121,8 @@ SwLinePortion *SwTextPainter::CalcPaintOfst( const SwRect 
&rPaint )
 void SwTextPainter::DrawTextLine( const SwRect &rPaint, SwSaveClip &rClip,
     const bool bUnderSized,
     ::std::optional<SwTaggedPDFHelper> & roTaggedLabel,
-    ::std::optional<SwTaggedPDFHelper> & roTaggedParagraph)
+    ::std::optional<SwTaggedPDFHelper> & roTaggedParagraph,
+    bool const isPDFTaggingEnabled)
 {
 #if OSL_DEBUG_LEVEL > 1
 //    sal_uInt16 nFntHeight = GetInfo().GetFont()->GetHeight( 
GetInfo().GetVsh(), GetInfo().GetOut() );
@@ -394,7 +395,7 @@ void SwTextPainter::DrawTextLine( const SwRect &rPaint, 
SwSaveClip &rClip,
             && !static_cast<SwNumberPortion const*>(pPor)->IsFollow())
         {
             assert(!roTaggedLabel);
-            assert(!m_pFrame->IsFollow());
+            assert(isPDFTaggingEnabled); (void) isPDFTaggingEnabled;
             Por_Info aPorInfo(*pPor, *this, true); // open Lbl
             roTaggedLabel.emplace(nullptr, nullptr, &aPorInfo, *pOut);
         }
@@ -410,7 +411,7 @@ void SwTextPainter::DrawTextLine( const SwRect &rPaint, 
SwSaveClip &rClip,
                 pPor->Paint( GetInfo() );
         }
 
-        // lazy open LIBody and paragraph tag after num portions have been 
painted to Lbl
+        // lazy open LBody and paragraph tag after num portions have been 
painted to Lbl
         if (pPor->InNumberGrp() // also footnote label
             // note: numbering portion may be split if it has multiple scripts
             && !static_cast<SwNumberPortion const*>(pPor)->HasFollow()) // so 
wait for the last one
@@ -418,8 +419,7 @@ void SwTextPainter::DrawTextLine( const SwRect &rPaint, 
SwSaveClip &rClip,
             assert(roTaggedLabel);
             roTaggedLabel.reset(); // close Lbl
             assert(!roTaggedParagraph);
-            assert(!m_pFrame->IsFollow());
-            Frame_Info aFrameInfo(*m_pFrame); // open LIBody
+            Frame_Info aFrameInfo(*m_pFrame); // open LBody
             roTaggedParagraph.emplace(nullptr, &aFrameInfo, nullptr, *pOut);
         }
 
diff --git a/sw/source/core/text/itrpaint.hxx b/sw/source/core/text/itrpaint.hxx
index a941e2125c8b..1c614e2a34d3 100644
--- a/sw/source/core/text/itrpaint.hxx
+++ b/sw/source/core/text/itrpaint.hxx
@@ -51,7 +51,8 @@ public:
     void DrawTextLine( const SwRect &rPaint, SwSaveClip &rClip,
         const bool bUnderSz,
         ::std::optional<SwTaggedPDFHelper> & roTaggedLabel,
-        ::std::optional<SwTaggedPDFHelper> & roTaggedParagraph);
+        ::std::optional<SwTaggedPDFHelper> & roTaggedParagraph,
+        bool isPDFTaggingEnabled);
     void PaintDropPortion();
     // if PaintMultiPortion is called recursively, we have to pass the
     // surrounding SwBidiPortion
diff --git a/sw/source/core/text/porlay.cxx b/sw/source/core/text/porlay.cxx
index 7535580aa9c5..271c76efed02 100644
--- a/sw/source/core/text/porlay.cxx
+++ b/sw/source/core/text/porlay.cxx
@@ -2699,6 +2699,20 @@ bool SwParaPortion::HasNumberingPortion(FootnoteOrNot 
const eFootnote) const
         && (eFootnote == SwParaPortion::FootnoteToo || 
!pPortion->IsFootnoteNumPortion());
 }
 
+bool SwParaPortion::HasContentPortions() const
+{
+    SwLinePortion const* pPortion(nullptr);
+    for (SwLineLayout const* pLine = this; pLine && !pPortion; pLine = 
pLine->GetNext())
+    {
+        pPortion = pLine->GetFirstPortion();
+        while (pPortion && (pPortion->InGlueGrp() || pPortion->IsFlyPortion()))
+        {   // skip margins and fly spacers
+            pPortion = pPortion->GetNextPortion();
+        }
+    }
+    return pPortion != nullptr;
+}
+
 const SwDropPortion *SwParaPortion::FindDropPortion() const
 {
     const SwLineLayout *pLay = this;
diff --git a/sw/source/core/text/porlay.hxx b/sw/source/core/text/porlay.hxx
index 5a824bdec5f6..3b07b7016118 100644
--- a/sw/source/core/text/porlay.hxx
+++ b/sw/source/core/text/porlay.hxx
@@ -321,6 +321,7 @@ public:
     bool IsMargin() const { return m_bMargin; }
     enum FootnoteOrNot { OnlyNumbering, FootnoteToo };
     bool HasNumberingPortion(FootnoteOrNot) const;
+    bool HasContentPortions() const;
 
     // Set nErgo in the QuoVadisPortion
     void SetErgoSumNum( const OUString &rErgo );

Reply via email to