diff options
Diffstat (limited to 'sw/source/core/text/pormulti.cxx')
-rw-r--r-- | sw/source/core/text/pormulti.cxx | 313 |
1 files changed, 189 insertions, 124 deletions
diff --git a/sw/source/core/text/pormulti.cxx b/sw/source/core/text/pormulti.cxx index c51fb973ad29..9fb6011f0db5 100644 --- a/sw/source/core/text/pormulti.cxx +++ b/sw/source/core/text/pormulti.cxx @@ -31,6 +31,7 @@ #include <charfmt.hxx> #include <layfrm.hxx> #include <SwPortionHandler.hxx> +#include <EnhancedPDFExportHelper.hxx> #include "pormulti.hxx" #include "inftxt.hxx" #include "itrpaint.hxx" @@ -119,7 +120,7 @@ void SwMultiPortion::CalcSize( SwTextFormatter& rLine, SwTextFormatInfo &rInf ) SetAscent( nTmp ); } -tools::Long SwMultiPortion::CalcSpacing( tools::Long , const SwTextSizeInfo & ) const +SwTwips SwMultiPortion::CalcSpacing( tools::Long , const SwTextSizeInfo & ) const { return 0; } @@ -134,6 +135,31 @@ void SwMultiPortion::HandlePortion( SwPortionHandler& rPH ) const rPH.Text( GetLen(), GetWhichPor() ); } +void SwMultiPortion::dumpAsXml(xmlTextWriterPtr pWriter, const OUString& rText, + TextFrameIndex& nOffset) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwMultiPortion")); + dumpAsXmlAttributes(pWriter, rText, nOffset); + // Intentionally not incrementing nOffset here, one of the child portions will do that. + + const SwLineLayout* pLine = &GetRoot(); + while (pLine) + { + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwLineLayout")); + pLine->dumpAsXmlAttributes(pWriter, rText, nOffset); + const SwLinePortion* pPor = pLine->GetFirstPortion(); + while (pPor) + { + pPor->dumpAsXml(pWriter, rText, nOffset); + pPor = pPor->GetNextPortion(); + } + (void)xmlTextWriterEndElement(pWriter); + pLine = pLine->GetNext(); + } + + (void)xmlTextWriterEndElement(pWriter); +} + // sets the tabulator-flag, if there's any tabulator-portion inside. void SwMultiPortion::ActualizeTabulator() { @@ -193,7 +219,7 @@ SwBidiPortion::SwBidiPortion(TextFrameIndex const nEnd, sal_uInt8 nLv) SetDirection( DIR_LEFT2RIGHT ); } -tools::Long SwBidiPortion::CalcSpacing( tools::Long nSpaceAdd, const SwTextSizeInfo& rInf ) const +SwTwips SwBidiPortion::CalcSpacing( tools::Long nSpaceAdd, const SwTextSizeInfo& rInf ) const { return HasTabulator() ? 0 : sal_Int32(GetSpaceCnt(rInf)) * nSpaceAdd / SPACING_PRECISION_FACTOR; } @@ -351,12 +377,12 @@ void SwDoubleLinePortion::PaintBracket( SwTextPaintInfo &rInf, aBlank.Width( nChWidth ); aBlank.Height( m_pBracket->nHeight ); { - std::unique_ptr<SwFont> pTmpFnt( new SwFont( *rInf.GetFont() ) ); + SwFont aTmpFnt( *rInf.GetFont() ); SwFontScript nAct = bOpen ? m_pBracket->nPreScript : m_pBracket->nPostScript; if( SW_SCRIPTS > nAct ) - pTmpFnt->SetActual( nAct ); - pTmpFnt->SetProportion( 100 ); - SwFontSave aSave( rInf, pTmpFnt.get() ); + aTmpFnt.SetActual( nAct ); + aTmpFnt.SetProportion( 100 ); + SwFontSave aSave( rInf, &aTmpFnt ); aBlank.Paint( rInf ); } if( bOpen ) @@ -384,21 +410,21 @@ void SwDoubleLinePortion::SetBrackets( const SwDoubleLinePortion& rDouble ) void SwDoubleLinePortion::FormatBrackets( SwTextFormatInfo &rInf, SwTwips& nMaxWidth ) { nMaxWidth -= rInf.X(); - std::unique_ptr<SwFont> pTmpFnt( new SwFont( *rInf.GetFont() ) ); - pTmpFnt->SetProportion( 100 ); + SwFont aTmpFnt( *rInf.GetFont() ); + aTmpFnt.SetProportion( 100 ); m_pBracket->nAscent = 0; m_pBracket->nHeight = 0; if( m_pBracket->cPre ) { OUString aStr( m_pBracket->cPre ); - SwFontScript nActualScr = pTmpFnt->GetActual(); + SwFontScript nActualScr = aTmpFnt.GetActual(); if( SW_SCRIPTS > m_pBracket->nPreScript ) - pTmpFnt->SetActual( m_pBracket->nPreScript ); - SwFontSave aSave( rInf, pTmpFnt.get() ); + aTmpFnt.SetActual( m_pBracket->nPreScript ); + SwFontSave aSave( rInf, &aTmpFnt ); SwPosSize aSize = rInf.GetTextSize( aStr ); m_pBracket->nAscent = rInf.GetAscent(); m_pBracket->nHeight = aSize.Height(); - pTmpFnt->SetActual( nActualScr ); + aTmpFnt.SetActual( nActualScr ); if( nMaxWidth > aSize.Width() ) { m_pBracket->nPreWidth = aSize.Width(); @@ -417,8 +443,8 @@ void SwDoubleLinePortion::FormatBrackets( SwTextFormatInfo &rInf, SwTwips& nMaxW { OUString aStr( m_pBracket->cPost ); if( SW_SCRIPTS > m_pBracket->nPostScript ) - pTmpFnt->SetActual( m_pBracket->nPostScript ); - SwFontSave aSave( rInf, pTmpFnt.get() ); + aTmpFnt.SetActual( m_pBracket->nPostScript ); + SwFontSave aSave( rInf, &aTmpFnt ); SwPosSize aSize = rInf.GetTextSize( aStr ); const sal_uInt16 nTmpAsc = rInf.GetAscent(); if( nTmpAsc > m_pBracket->nAscent ) @@ -479,7 +505,7 @@ void SwDoubleLinePortion::CalcBlanks( SwTextFormatInfo &rInf ) rInf.SetIdx( nStart ); } -tools::Long SwDoubleLinePortion::CalcSpacing( tools::Long nSpaceAdd, const SwTextSizeInfo & ) const +SwTwips SwDoubleLinePortion::CalcSpacing( tools::Long nSpaceAdd, const SwTextSizeInfo & ) const { return HasTabulator() ? 0 : sal_Int32(GetSpaceCnt()) * nSpaceAdd / SPACING_PRECISION_FACTOR; } @@ -592,7 +618,7 @@ SwRubyPortion::SwRubyPortion( const SwMultiCreator& rCreate, const SwFont& rFnt, } OUString aStr = rRuby.GetText().copy( sal_Int32(nOffs) ); - SwFieldPortion *pField = new SwFieldPortion( aStr, std::move(pRubyFont) ); + SwFieldPortion *pField = new SwFieldPortion( std::move(aStr), std::move(pRubyFont) ); pField->SetNextOffset( nOffs ); pField->SetFollow( true ); @@ -654,9 +680,9 @@ void SwRubyPortion::Adjust_( SwTextFormatInfo &rInf ) TextFrameIndex nSub(0); switch ( m_nAdjustment ) { - case css::text::RubyAdjust_CENTER: nRight = static_cast<sal_uInt16>(nLineDiff / 2); + case css::text::RubyAdjust_CENTER: nRight = o3tl::narrowing<sal_uInt16>(nLineDiff / 2); [[fallthrough]]; - case css::text::RubyAdjust_RIGHT: nLeft = static_cast<sal_uInt16>(nLineDiff - nRight); break; + case css::text::RubyAdjust_RIGHT: nLeft = o3tl::narrowing<sal_uInt16>(nLineDiff - nRight); break; case css::text::RubyAdjust_BLOCK: nSub = TextFrameIndex(1); [[fallthrough]]; case css::text::RubyAdjust_INDENT_BLOCK: @@ -683,8 +709,8 @@ void SwRubyPortion::Adjust_( SwTextFormatInfo &rInf ) } if( nLineDiff > 1 ) { - nRight = static_cast<sal_uInt16>(nLineDiff / 2); - nLeft = static_cast<sal_uInt16>(nLineDiff - nRight); + nRight = o3tl::narrowing<sal_uInt16>(nLineDiff / 2); + nLeft = o3tl::narrowing<sal_uInt16>(nLineDiff - nRight); } break; } @@ -846,12 +872,14 @@ namespace sw { } if (m_pMerged) { - while (m_CurrentExtent < m_pMerged->extents.size()) + const auto nExtentsSize = m_pMerged->extents.size(); + while (m_CurrentExtent < nExtentsSize) { sw::Extent const& rExtent(m_pMerged->extents[m_CurrentExtent]); if (SwpHints const*const pHints = rExtent.pNode->GetpSwpHints()) { - while (m_CurrentHint < pHints->Count()) + auto nHintsCount = pHints->Count(); + while (m_CurrentHint < nHintsCount) { SwTextAttr const*const pHint(pHints->Get(m_CurrentHint)); if (rExtent.nEnd < pHint->GetStart()) @@ -867,7 +895,7 @@ namespace sw { } } ++m_CurrentExtent; - if (m_CurrentExtent < m_pMerged->extents.size() && + if (m_CurrentExtent < nExtentsSize && rExtent.pNode != m_pMerged->extents[m_CurrentExtent].pNode) { m_CurrentHint = 0; // reset @@ -904,7 +932,7 @@ namespace sw { // interrupts the first attribute. // E.g. a ruby portion interrupts a 2-line-attribute, a 2-line-attribute // with different brackets interrupts another 2-line-attribute. -std::unique_ptr<SwMultiCreator> SwTextSizeInfo::GetMultiCreator(TextFrameIndex &rPos, +std::optional<SwMultiCreator> SwTextSizeInfo::GetMultiCreator(TextFrameIndex &rPos, SwMultiPortion const * pMulti ) const { SwScriptInfo& rSI = const_cast<SwParaPortion*>(GetParaPortion())->GetScriptInfo(); @@ -936,26 +964,26 @@ std::unique_ptr<SwMultiCreator> SwTextSizeInfo::GetMultiCreator(TextFrameIndex & { rPos = bFieldBidi ? rPos + TextFrameIndex(1) : rSI.NextDirChg(rPos, &nCurrLevel); if (TextFrameIndex(COMPLETE_STRING) == rPos) - return nullptr; - std::unique_ptr<SwMultiCreator> pRet(new SwMultiCreator); - pRet->pItem = nullptr; - pRet->pAttr = nullptr; - pRet->nStartOfAttr = TextFrameIndex(-1); - pRet->nId = SwMultiCreatorId::Bidi; - pRet->nLevel = nCurrLevel + 1; - return pRet; + return {}; + SwMultiCreator aRet; + aRet.pItem = nullptr; + aRet.pAttr = nullptr; + aRet.nStartOfAttr = TextFrameIndex(-1); + aRet.nId = SwMultiCreatorId::Bidi; + aRet.nLevel = nCurrLevel + 1; + return aRet; } // a bidi portion can only contain other bidi portions if ( pMulti ) - return nullptr; + return {}; // need the node that contains input rPos std::pair<SwTextNode const*, sal_Int32> startPos(m_pFrame->MapViewToModel(rPos)); const SvxCharRotateItem* pActiveRotateItem(nullptr); - const SfxPoolItem* pNodeRotateItem(nullptr); + const SvxCharRotateItem* pNodeRotateItem(nullptr); const SvxTwoLinesItem* pActiveTwoLinesItem(nullptr); - const SfxPoolItem* pNodeTwoLinesItem(nullptr); + const SvxTwoLinesItem* pNodeTwoLinesItem(nullptr); SwTextAttr const* pActiveTwoLinesHint(nullptr); SwTextAttr const* pActiveRotateHint(nullptr); const SwTextAttr *pRuby = nullptr; @@ -1004,59 +1032,57 @@ std::unique_ptr<SwMultiCreator> SwTextSizeInfo::GetMultiCreator(TextFrameIndex & } } } - else if (pNode) // !pAttr && pNode means the node changed + // !pAttr && pNode means the node changed + if (startPos.first->GetIndex() < pNode->GetIndex()) + { + break; // only one node initially + } + if (startPos.first->GetIndex() == pNode->GetIndex()) { - if (startPos.first->GetIndex() < pNode->GetIndex()) + iterAtStartOfNode.Assign(iter); + if (SfxItemState::SET == pNode->GetSwAttrSet().GetItemState( + RES_CHRATR_ROTATE, true, &pNodeRotateItem) && + pNodeRotateItem->GetValue()) { - break; // only one node initially + pActiveRotateItem = pNodeRotateItem; } - if (startPos.first->GetIndex() == pNode->GetIndex()) + else { - iterAtStartOfNode.Assign(iter); - if (SfxItemState::SET == pNode->GetSwAttrSet().GetItemState( - RES_CHRATR_ROTATE, true, &pNodeRotateItem) && - static_cast<const SvxCharRotateItem*>(pNodeRotateItem)->GetValue()) - { - pActiveRotateItem = static_cast<const SvxCharRotateItem*>(pNodeRotateItem); - } - else - { - pNodeRotateItem = nullptr; - } - if (SfxItemState::SET == startPos.first->GetSwAttrSet().GetItemState( - RES_CHRATR_TWO_LINES, true, &pNodeTwoLinesItem) && - static_cast<const SvxTwoLinesItem*>(pNodeTwoLinesItem)->GetValue()) - { - pActiveTwoLinesItem = static_cast<const SvxTwoLinesItem*>(pNodeTwoLinesItem); - } - else - { - pNodeTwoLinesItem = nullptr; - } + pNodeRotateItem = nullptr; + } + if (SfxItemState::SET == startPos.first->GetSwAttrSet().GetItemState( + RES_CHRATR_TWO_LINES, true, &pNodeTwoLinesItem) && + pNodeTwoLinesItem->GetValue()) + { + pActiveTwoLinesItem = pNodeTwoLinesItem; + } + else + { + pNodeTwoLinesItem = nullptr; } } } if (!pRuby && !pActiveTwoLinesItem && !pActiveRotateItem) - return nullptr; + return {}; if( pRuby ) { // The winner is ... a ruby attribute and so // the end of the multiportion is the end of the ruby attribute. rPos = m_pFrame->MapModelToView(startPos.first, *pRuby->End()); - std::unique_ptr<SwMultiCreator> pRet(new SwMultiCreator); - pRet->pItem = nullptr; - pRet->pAttr = pRuby; - pRet->nStartOfAttr = m_pFrame->MapModelToView(startPos.first, pRet->pAttr->GetStart()); - pRet->nId = SwMultiCreatorId::Ruby; - pRet->nLevel = GetTextFrame()->IsRightToLeft() ? 1 : 0; - return pRet; + SwMultiCreator aRet; + aRet.pItem = nullptr; + aRet.pAttr = pRuby; + aRet.nStartOfAttr = m_pFrame->MapModelToView(startPos.first, aRet.pAttr->GetStart()); + aRet.nId = SwMultiCreatorId::Ruby; + aRet.nLevel = GetTextFrame()->IsRightToLeft() ? 1 : 0; + return aRet; } if (pActiveTwoLinesHint || - (pNodeTwoLinesItem && pNodeTwoLinesItem == pActiveTwoLinesItem && + (pNodeTwoLinesItem && SfxPoolItem::areSame(pNodeTwoLinesItem, pActiveTwoLinesItem) && rPos < TextFrameIndex(GetText().getLength()))) { // The winner is a 2-line-attribute, // the end of the multiportion depends on the following attributes... - std::unique_ptr<SwMultiCreator> pRet(new SwMultiCreator); + SwMultiCreator aRet; // We note the endpositions of the 2-line attributes in aEnd as stack std::deque<TextFrameIndex> aEnd; @@ -1068,31 +1094,31 @@ std::unique_ptr<SwMultiCreator> SwTextSizeInfo::GetMultiCreator(TextFrameIndex & if (pActiveTwoLinesHint) { - pRet->pItem = nullptr; - pRet->pAttr = pActiveTwoLinesHint; - pRet->nStartOfAttr = m_pFrame->MapModelToView(startPos.first, pRet->pAttr->GetStart()); + aRet.pItem = nullptr; + aRet.pAttr = pActiveTwoLinesHint; + aRet.nStartOfAttr = m_pFrame->MapModelToView(startPos.first, aRet.pAttr->GetStart()); if (pNodeTwoLinesItem) { aEnd.push_front(m_pFrame->MapModelToView(startPos.first, startPos.first->Len())); - bOn = static_cast<const SvxTwoLinesItem*>(pNodeTwoLinesItem)->GetEndBracket() == + bOn = pNodeTwoLinesItem->GetEndBracket() == pActiveTwoLinesItem->GetEndBracket() && - static_cast<const SvxTwoLinesItem*>(pNodeTwoLinesItem)->GetStartBracket() == + pNodeTwoLinesItem->GetStartBracket() == pActiveTwoLinesItem->GetStartBracket(); } else { - aEnd.push_front(m_pFrame->MapModelToView(startPos.first, *pRet->pAttr->End())); + aEnd.push_front(m_pFrame->MapModelToView(startPos.first, *aRet.pAttr->End())); } } else { - pRet->pItem = pNodeTwoLinesItem; - pRet->pAttr = nullptr; - pRet->nStartOfAttr = TextFrameIndex(-1); + aRet.pItem = pNodeTwoLinesItem; + aRet.pAttr = nullptr; + aRet.nStartOfAttr = TextFrameIndex(-1); aEnd.push_front(m_pFrame->MapModelToView(startPos.first, startPos.first->Len())); } - pRet->nId = SwMultiCreatorId::Double; - pRet->nLevel = GetTextFrame()->IsRightToLeft() ? 1 : 0; + aRet.nId = SwMultiCreatorId::Double; + aRet.nLevel = GetTextFrame()->IsRightToLeft() ? 1 : 0; // pActiveTwoLinesHint is the last 2-line-attribute, which contains // the actual position. @@ -1134,9 +1160,8 @@ std::unique_ptr<SwMultiCreator> SwTextSizeInfo::GetMultiCreator(TextFrameIndex & } else { - pNodeTwoLinesItem = nullptr; - pNode->GetSwAttrSet().GetItemState( - RES_CHRATR_TWO_LINES, true, &pNodeTwoLinesItem); + pNodeTwoLinesItem = pNode->GetSwAttrSet().GetItemIfSet( + RES_CHRATR_TWO_LINES); nTmpStart = m_pFrame->MapModelToView(pNode, 0); nTmpEnd = m_pFrame->MapModelToView(pNode, pNode->Len()); assert(rPos <= nTmpEnd); // next node must not have smaller index @@ -1171,7 +1196,7 @@ std::unique_ptr<SwMultiCreator> SwTextSizeInfo::GetMultiCreator(TextFrameIndex & } // A ruby attribute stops the 2-line immediately if (pTmp && RES_TXTATR_CJK_RUBY == pTmp->Which()) - return pRet; + return aRet; if (pTmp ? lcl_Has2Lines(*pTmp, pActiveTwoLinesItem, bTwo) : lcl_Check2Lines(pNodeTwoLinesItem, pActiveTwoLinesItem, bTwo)) { // We have an interesting attribute... @@ -1198,15 +1223,15 @@ std::unique_ptr<SwMultiCreator> SwTextSizeInfo::GetMultiCreator(TextFrameIndex & } if( bOn && !aEnd.empty() ) rPos = aEnd.back(); - return pRet; + return aRet; } if (pActiveRotateHint || - (pNodeRotateItem && pNodeRotateItem == pActiveRotateItem && + (pNodeRotateItem && SfxPoolItem::areSame(pNodeRotateItem, pActiveRotateItem) && rPos < TextFrameIndex(GetText().getLength()))) { // The winner is a rotate-attribute, // the end of the multiportion depends on the following attributes... - std::unique_ptr<SwMultiCreator> pRet(new SwMultiCreator); - pRet->nId = SwMultiCreatorId::Rotate; + SwMultiCreator aRet; + aRet.nId = SwMultiCreatorId::Rotate; // We note the endpositions of the 2-line attributes in aEnd as stack std::deque<TextFrameIndex> aEnd; @@ -1239,9 +1264,8 @@ std::unique_ptr<SwMultiCreator> SwTextSizeInfo::GetMultiCreator(TextFrameIndex & } else { - pNodeTwoLinesItem = nullptr; - pNode->GetSwAttrSet().GetItemState( - RES_CHRATR_TWO_LINES, true, &pNodeTwoLinesItem); + pNodeTwoLinesItem = pNode->GetSwAttrSet().GetItemIfSet( + RES_CHRATR_TWO_LINES); nTmpStart = m_pFrame->MapModelToView(pNode, 0); nTmpEnd = m_pFrame->MapModelToView(pNode, pNode->Len()); assert(n2Start <= nTmpEnd); // next node must not have smaller index @@ -1299,25 +1323,25 @@ std::unique_ptr<SwMultiCreator> SwTextSizeInfo::GetMultiCreator(TextFrameIndex & bOn = true; if (pActiveRotateHint) { - pRet->pItem = nullptr; - pRet->pAttr = pActiveRotateHint; - pRet->nStartOfAttr = m_pFrame->MapModelToView(startPos.first, pRet->pAttr->GetStart()); + aRet.pItem = nullptr; + aRet.pAttr = pActiveRotateHint; + aRet.nStartOfAttr = m_pFrame->MapModelToView(startPos.first, aRet.pAttr->GetStart()); if (pNodeRotateItem) { aEnd.push_front(m_pFrame->MapModelToView(startPos.first, startPos.first->Len())); - bOn = static_cast<const SvxCharRotateItem*>(pNodeRotateItem)->GetValue() == + bOn = pNodeRotateItem->GetValue() == pActiveRotateItem->GetValue(); } else { - aEnd.push_front(m_pFrame->MapModelToView(startPos.first, *pRet->pAttr->End())); + aEnd.push_front(m_pFrame->MapModelToView(startPos.first, *aRet.pAttr->End())); } } else { - pRet->pItem = pNodeRotateItem; - pRet->pAttr = nullptr; - pRet->nStartOfAttr = TextFrameIndex(-1); + aRet.pItem = pNodeRotateItem; + aRet.pAttr = nullptr; + aRet.nStartOfAttr = TextFrameIndex(-1); aEnd.push_front(m_pFrame->MapModelToView(startPos.first, startPos.first->Len())); } for (sw::MergedAttrIterMulti iter = iterAtStartOfNode; ; ) @@ -1340,9 +1364,8 @@ std::unique_ptr<SwMultiCreator> SwTextSizeInfo::GetMultiCreator(TextFrameIndex & } else { - pNodeRotateItem = nullptr; - pNode->GetSwAttrSet().GetItemState( - RES_CHRATR_ROTATE, true, &pNodeRotateItem); + pNodeRotateItem = pNode->GetSwAttrSet().GetItemIfSet( + RES_CHRATR_ROTATE); nTmpStart = m_pFrame->MapModelToView(pNode, 0); nTmpEnd = m_pFrame->MapModelToView(pNode, pNode->Len()); assert(rPos <= nTmpEnd); // next node must not have smaller index @@ -1394,9 +1417,9 @@ std::unique_ptr<SwMultiCreator> SwTextSizeInfo::GetMultiCreator(TextFrameIndex & rPos = aEnd.back(); if( rPos > n2Start ) rPos = n2Start; - return pRet; + return aRet; } - return nullptr; + return {}; } namespace { @@ -1557,7 +1580,7 @@ void SwTextPainter::PaintMultiPortion( const SwRect &rPaint, SwSpaceManipulator aManip( GetInfo(), rMulti ); - std::unique_ptr<SwFontSave> pFontSave; + std::optional<SwFontSave> oFontSave; std::unique_ptr<SwFont> pTmpFnt; if( rMulti.IsDouble() ) @@ -1568,16 +1591,19 @@ void SwTextPainter::PaintMultiPortion( const SwRect &rPaint, SetPropFont( 50 ); pTmpFnt->SetProportion( GetPropFont() ); } - pFontSave.reset(new SwFontSave( GetInfo(), pTmpFnt.get(), this )); + oFontSave.emplace( GetInfo(), pTmpFnt.get(), this ); } else { - pFontSave = nullptr; pTmpFnt = nullptr; } if( rMulti.HasBrackets() ) { + // WP is mandatory + Por_Info const por(rMulti, *this, 1); + SwTaggedPDFHelper const tag(nullptr, nullptr, &por, *GetInfo().GetOut()); + TextFrameIndex const nTmpOldIdx = GetInfo().GetIdx(); GetInfo().SetIdx(static_cast<SwDoubleLinePortion&>(rMulti).GetBrackets()->nStart); SeekAndChg( GetInfo() ); @@ -1636,8 +1662,18 @@ void SwTextPainter::PaintMultiPortion( const SwRect &rPaint, OSL_ENSURE( nullptr == GetInfo().GetUnderFnt() || rMulti.IsBidi(), " Only BiDi portions are allowed to use the common underlining font" ); - if ( rMulti.IsRuby() ) + ::std::optional<SwTaggedPDFHelper> oTag; + if (rMulti.IsDouble()) + { + Por_Info const por(rMulti, *this, 2); + oTag.emplace(nullptr, nullptr, &por, *GetInfo().GetOut()); + } + else if (rMulti.IsRuby()) + { + Por_Info const por(rMulti, *this, bRubyTop ? 1 : 2); + oTag.emplace(nullptr, nullptr, &por, *GetInfo().GetOut()); GetInfo().SetRuby( rMulti.OnTop() ); + } do { @@ -1679,7 +1715,7 @@ void SwTextPainter::PaintMultiPortion( const SwRect &rPaint, } else if ( rMulti.IsRuby() && rMulti.OnRight() && GetInfo().IsRuby() ) { - SwTwips nLineDiff = std::max(( rMulti.GetRoot().Height() - pPor->Width() ) / 2, 0 ); + SwTwips nLineDiff = std::max(( rMulti.GetRoot().Height() - pPor->Width() ) / 2, static_cast<SwTwips>(0) ); GetInfo().Y( nOfst + nLineDiff ); // Draw the ruby text on top of the preserved space. GetInfo().X( GetInfo().X() - pPor->Height() ); @@ -1740,7 +1776,12 @@ void SwTextPainter::PaintMultiPortion( const SwRect &rPaint, PaintMultiPortion( rPaint, static_cast<SwMultiPortion&>(*pPor), &rMulti ); } else + { + Por_Info const por(*pPor, *this, 0); + SwTaggedPDFHelper const tag(nullptr, nullptr, &por, *GetInfo().GetOut()); + pPor->Paint( GetInfo() ); + } bFirst &= !pPor->GetLen(); if( pNext || !pPor->IsMarginPortion() ) @@ -1799,9 +1840,20 @@ void SwTextPainter::PaintMultiPortion( const SwRect &rPaint, // We switch to the baseline of the next inner line nOfst += rMulti.GetRoot().Height(); } + if (rMulti.IsRuby()) + { + oTag.reset(); + Por_Info const por(rMulti, *this, bRubyTop ? 2 : 1); + oTag.emplace(nullptr, nullptr, &por, *GetInfo().GetOut()); + } } } while( pPor ); + if (rMulti.IsDouble()) + { + oTag.reset(); + } + if ( bRubyInGrid ) GetInfo().SetSnapToGrid( bOldGridModeAllowed ); @@ -1817,6 +1869,10 @@ void SwTextPainter::PaintMultiPortion( const SwRect &rPaint, if( rMulti.HasBrackets() ) { + // WP is mandatory + Por_Info const por(rMulti, *this, 1); + SwTaggedPDFHelper const tag(nullptr, nullptr, &por, *GetInfo().GetOut()); + TextFrameIndex const nTmpOldIdx = GetInfo().GetIdx(); GetInfo().SetIdx(static_cast<SwDoubleLinePortion&>(rMulti).GetBrackets()->nStart); SeekAndChg( GetInfo() ); @@ -1828,7 +1884,7 @@ void SwTextPainter::PaintMultiPortion( const SwRect &rPaint, // Restore the saved values GetInfo().X( nOldX ); GetInfo().SetLen( nOldLen ); - pFontSave.reset(); + oFontSave.reset(); pTmpFnt.reset(); SetPropFont( 0 ); } @@ -1898,16 +1954,17 @@ bool SwTextFormatter::BuildMultiPortion( SwTextFormatInfo &rInf, } SeekAndChg( rInf ); - std::unique_ptr<SwFontSave> xFontSave; + std::optional<SwFontSave> oFontSave; + std::unique_ptr<SwFont> xTmpFont; if( rMulti.IsDouble() ) { - SwFont* pTmpFnt = new SwFont( *rInf.GetFont() ); + xTmpFont.reset(new SwFont( *rInf.GetFont() )); if( rMulti.IsDouble() ) { SetPropFont( 50 ); - pTmpFnt->SetProportion( GetPropFont() ); + xTmpFont->SetProportion( GetPropFont() ); } - xFontSave.reset(new SwFontSave(rInf, pTmpFnt, this)); + oFontSave.emplace(rInf, xTmpFont.get(), this); } SwLayoutModeModifier aLayoutModeModifier( *GetInfo().GetOut() ); @@ -1995,7 +2052,7 @@ bool SwTextFormatter::BuildMultiPortion( SwTextFormatInfo &rInf, // save some values const OUString* pOldText = &(rInf.GetText()); const SwTwips nOldPaintOfst = rInf.GetPaintOfst(); - std::shared_ptr<vcl::TextLayoutCache> const pOldCachedVclData(rInf.GetCachedVclData()); + std::shared_ptr<const vcl::text::TextLayoutCache> const pOldCachedVclData(rInf.GetCachedVclData()); rInf.SetCachedVclData(nullptr); OUString const aMultiStr( rInf.GetText().copy(0, sal_Int32(nMultiLen + rInf.GetIdx())) ); @@ -2285,6 +2342,9 @@ bool SwTextFormatter::BuildMultiPortion( SwTextFormatInfo &rInf, // we try to keep our ruby portion together lcl_TruncateMultiPortion( rMulti, rInf, nStartIdx ); pTmp = nullptr; + // A follow field portion may still be waiting. If nobody wants + // it, we delete it. + delete pNextSecond; } } else if( rMulti.HasRotation() ) @@ -2354,10 +2414,15 @@ bool SwTextFormatter::BuildMultiPortion( SwTextFormatInfo &rInf, SeekAndChg( rInf ); delete pFirstRest; delete pSecondRest; - xFontSave.reset(); + oFontSave.reset(); return bRet; } +static bool IsIncompleteRuby(const SwMultiPortion& rHelpMulti) +{ + return rHelpMulti.IsRuby() && static_cast<const SwRubyPortion&>(rHelpMulti).GetRubyOffset() < TextFrameIndex(COMPLETE_STRING); +} + // When a fieldportion at the end of line breaks and needs a following // fieldportion in the next line, then the "restportion" of the formatinfo // has to be set. Normally this happens during the formatting of the first @@ -2453,7 +2518,7 @@ SwLinePortion* SwTextFormatter::MakeRestPortion( const SwLineLayout* pLine, return pRest; nPosition = nMultiPos + pHelpMulti->GetLen(); - std::unique_ptr<SwMultiCreator> pCreate = GetInfo().GetMultiCreator( nMultiPos, nullptr ); + std::optional<SwMultiCreator> pCreate = GetInfo().GetMultiCreator( nMultiPos, nullptr ); if ( !pCreate ) { @@ -2466,19 +2531,19 @@ SwLinePortion* SwTextFormatter::MakeRestPortion( const SwLineLayout* pLine, if (!pCreate) return pRest; - if( pRest || nMultiPos > nPosition || ( pHelpMulti->IsRuby() && - static_cast<const SwRubyPortion*>(pHelpMulti)->GetRubyOffset() < TextFrameIndex(COMPLETE_STRING))) + if( pRest || nMultiPos > nPosition || IsIncompleteRuby(*pHelpMulti)) { SwMultiPortion* pTmp; if( pHelpMulti->IsDouble() ) pTmp = new SwDoubleLinePortion( *pCreate, nMultiPos ); else if( pHelpMulti->IsBidi() ) pTmp = new SwBidiPortion( nMultiPos, pCreate->nLevel ); - else if( pHelpMulti->IsRuby() ) + else if (IsIncompleteRuby(*pHelpMulti) && pCreate->pAttr) { + TextFrameIndex nRubyOffset = static_cast<const SwRubyPortion*>(pHelpMulti)->GetRubyOffset(); pTmp = new SwRubyPortion( *pCreate, *GetInfo().GetFont(), m_pFrame->GetDoc().getIDocumentSettingAccess(), - nMultiPos, static_cast<const SwRubyPortion*>(pHelpMulti)->GetRubyOffset(), + nMultiPos, nRubyOffset, GetInfo() ); } else if( pHelpMulti->HasRotation() ) @@ -2510,7 +2575,7 @@ SwLinePortion* SwTextFormatter::MakeRestPortion( const SwLineLayout* pLine, SwTextCursorSave::SwTextCursorSave( SwTextCursor* pCursor, SwMultiPortion* pMulti, SwTwips nY, - sal_uInt16& nX, + SwTwips& nX, TextFrameIndex const nCurrStart, tools::Long nSpaceAdd ) : pTextCursor(pCursor), @@ -2544,7 +2609,7 @@ SwTextCursorSave::SwTextCursorSave( SwTextCursor* pCursor, } if( nSpaceAdd > 0 && !pMulti->HasTabulator() ) - pCursor->m_pCurr->Width( static_cast<sal_uInt16>(nWidth + nSpaceAdd * sal_Int32(nSpaceCnt) / SPACING_PRECISION_FACTOR) ); + pCursor->m_pCurr->Width( o3tl::narrowing<sal_uInt16>(nWidth + nSpaceAdd * sal_Int32(nSpaceCnt) / SPACING_PRECISION_FACTOR) ); // For a BidiPortion we have to calculate the offset from the // end of the portion |