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 );