From 3901e029bd39575f700e69a73818565d62226a23 Mon Sep 17 00:00:00 2001 From: Khaled Hosny Date: Mon, 8 Aug 2022 22:08:37 +0200 Subject: tdf#104921: Cleanup Kashida insertion logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Communicate Kashida insertion positions in an explicit way. Rest of LibreOffice communicate adjustments to character widths (e.g. for justification or spacing) using so-called DX array. DX array is an array of absolute character positions (e.g. DX[n] is the position after character n from the start of the lines, and its widths is DX[n] - DX[n-1]). This DX array is modified also when Kashidas are inserted after a given character for Arabic justification, by expanding its width. VCL would use this to know where to insert the Kashidas and how many ones. But because DX array is used for both widths adjustments and kashida insertion, this turns out to be a source of bugs since VCL has tosecond guess the DX array to find which is pure width adjustment and which also involves Kashida insertion, and the heuristics it uses are fragile. This change adds a second array of booleans that records where Kashida is inserted and communicates it all the way from where Kashida insertion is decoded in Writer and down to VCL layout. This change passes the Kashida array only when it seems necessary (e.g. during drawing but not when measuring text since the DX array is enough in this case). Hopefully no places where Kashida insertion needs to be passed down were missed. A couple of glyph and layout flags that were used for old heuristics and no longer needed and are removed. This also fixes: tdf#87731 tdf#106309 tdf#108604 tdf#112849 tdf#114257 tdf#127176 tdf#145647 tdf#146199 Change-Id: I4ed0850ef2fdc3e9143341afac649e7e7d463c39 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138068 Tested-by: Jenkins Reviewed-by: Caolán McNamara --- canvas/source/cairo/cairo_textlayout.cxx | 2 +- canvas/source/directx/dx_textlayout_drawhelper.cxx | 1 + canvas/source/vcl/textlayout.cxx | 1 + .../source/primitive2d/textbreakuphelper.cxx | 10 +++ .../primitive2d/textdecoratedprimitive2d.cxx | 7 +- .../source/primitive2d/textlayoutdevice.cxx | 6 +- .../source/primitive2d/textprimitive2d.cxx | 13 +-- .../primitive2d/textstrikeoutprimitive2d.cxx | 1 + drawinglayer/source/processor2d/vclprocessor2d.cxx | 3 +- drawinglayer/source/tools/emfphelperdata.cxx | 4 + drawinglayer/source/tools/wmfemfhelper.cxx | 7 ++ editeng/inc/editdoc.hxx | 4 + editeng/source/editeng/editeng.cxx | 3 +- editeng/source/editeng/impedit3.cxx | 33 ++++++-- editeng/source/items/svxfont.cxx | 13 +-- editeng/source/outliner/outleeng.cxx | 5 +- editeng/source/outliner/outleeng.hxx | 3 +- editeng/source/outliner/outliner.cxx | 9 +- emfio/source/reader/mtftools.cxx | 4 +- .../primitive2d/textdecoratedprimitive2d.hxx | 2 + .../drawinglayer/primitive2d/textlayoutdevice.hxx | 3 +- .../drawinglayer/primitive2d/textprimitive2d.hxx | 8 ++ include/editeng/editeng.hxx | 4 +- include/editeng/outliner.hxx | 7 +- include/editeng/svxfont.hxx | 3 +- include/vcl/metaact.hxx | 11 ++- include/vcl/outdev.hxx | 12 ++- include/vcl/pdfwriter.hxx | 1 + include/vcl/rendercontext/SalLayoutFlags.hxx | 3 +- sc/source/ui/view/hintwin.cxx | 4 +- sd/source/ui/view/sdview.cxx | 1 + sfx2/source/control/thumbnailviewitem.cxx | 1 + svgio/source/svgreader/svgcharacternode.cxx | 2 + svtools/source/control/ruler.cxx | 4 +- svx/source/diagram/IDiagramHelper.cxx | 3 +- svx/source/svdraw/svdotextdecomposition.cxx | 14 ++++ svx/source/svdraw/svdotextpathdecomposition.cxx | 5 ++ svx/source/tbxctrls/StylesPreviewWindow.cxx | 3 +- sw/source/core/inc/scriptinfo.hxx | 2 +- sw/source/core/layout/paintfrm.cxx | 1 + sw/source/core/text/itradj.cxx | 6 +- sw/source/core/text/porlay.cxx | 6 ++ sw/source/core/text/portxt.cxx | 2 +- sw/source/core/txtnode/fntcache.cxx | 32 ++++--- sw/source/uibase/docvw/HeaderFooterWin.cxx | 2 +- sw/source/uibase/docvw/UnfloatTableButton.cxx | 2 +- vcl/inc/ImplLayoutArgs.hxx | 2 + vcl/inc/impglyphitem.hxx | 4 +- vcl/inc/pdf/pdfwriter_impl.hxx | 2 +- vcl/inc/sallayout.hxx | 2 +- vcl/qa/cppunit/complextext.cxx | 37 ++------ vcl/qa/cppunit/svm/svmtest.cxx | 2 +- vcl/qa/cppunit/text.cxx | 2 +- vcl/source/control/imp_listbox.cxx | 2 +- vcl/source/filter/eps/eps.cxx | 12 +-- vcl/source/filter/svm/SvmConverter.cxx | 2 +- vcl/source/gdi/CommonSalLayout.cxx | 98 ++++++++-------------- vcl/source/gdi/gdimtf.cxx | 4 +- vcl/source/gdi/impglyphitem.cxx | 25 +----- vcl/source/gdi/metaact.cxx | 12 ++- vcl/source/gdi/pdfwriter.cxx | 3 +- vcl/source/gdi/pdfwriter_impl.cxx | 8 +- vcl/source/gdi/pdfwriter_impl2.cxx | 2 +- vcl/source/gdi/textlayout.cxx | 2 +- vcl/source/outdev/text.cxx | 42 ++++++---- vcl/source/outdev/transparent.cxx | 2 +- vcl/source/text/ImplLayoutArgs.cxx | 32 ++++++- vcl/source/window/menuitemlist.cxx | 2 +- vcl/source/window/status.cxx | 2 +- 69 files changed, 346 insertions(+), 228 deletions(-) diff --git a/canvas/source/cairo/cairo_textlayout.cxx b/canvas/source/cairo/cairo_textlayout.cxx index cbbf02c5629d..2b48dd977d52 100644 --- a/canvas/source/cairo/cairo_textlayout.cxx +++ b/canvas/source/cairo/cairo_textlayout.cxx @@ -270,7 +270,7 @@ namespace cairocanvas if (maLogicalAdvancements.hasElements()) { - rOutDev.DrawTextArray( rOutpos, maText.Text, aOffsets, + rOutDev.DrawTextArray( rOutpos, maText.Text, aOffsets, {}, ::canvas::tools::numeric_cast(maText.StartPosition), ::canvas::tools::numeric_cast(maText.Length) ); } diff --git a/canvas/source/directx/dx_textlayout_drawhelper.cxx b/canvas/source/directx/dx_textlayout_drawhelper.cxx index 20ff8bd441c9..9e83b77ca901 100644 --- a/canvas/source/directx/dx_textlayout_drawhelper.cxx +++ b/canvas/source/directx/dx_textlayout_drawhelper.cxx @@ -215,6 +215,7 @@ namespace dxcanvas xVirtualDevice->DrawTextArray( aEmptyPoint, aText, DXArray, + {}, rText.StartPosition, rText.Length, bIsRTL ? SalLayoutFlags::BiDiRtl : SalLayoutFlags::NONE); diff --git a/canvas/source/vcl/textlayout.cxx b/canvas/source/vcl/textlayout.cxx index 63a3453ff0c4..f628d155f3a7 100644 --- a/canvas/source/vcl/textlayout.cxx +++ b/canvas/source/vcl/textlayout.cxx @@ -344,6 +344,7 @@ namespace vclcanvas rOutDev.DrawTextArray( rOutpos, maText.Text, aOffsets, + {}, ::canvas::tools::numeric_cast(maText.StartPosition), ::canvas::tools::numeric_cast(maText.Length) ); } diff --git a/drawinglayer/source/primitive2d/textbreakuphelper.cxx b/drawinglayer/source/primitive2d/textbreakuphelper.cxx index 5ca10ce633b6..8f92d9817a0e 100644 --- a/drawinglayer/source/primitive2d/textbreakuphelper.cxx +++ b/drawinglayer/source/primitive2d/textbreakuphelper.cxx @@ -58,6 +58,7 @@ namespace drawinglayer::primitive2d // prepare values for new portion basegfx::B2DHomMatrix aNewTransform; std::vector< double > aNewDXArray; + std::vector< sal_Bool > aNewKashidaArray; const bool bNewStartIsNotOldStart(nIndex > mrSource.getTextPosition()); if(!mbNoDXArray) @@ -68,6 +69,13 @@ namespace drawinglayer::primitive2d mrSource.getDXArray().begin() + ((nIndex + nLength) - mrSource.getTextPosition())); } + if(!mbNoDXArray && !mrSource.getKashidaArray().empty()) + { + aNewKashidaArray = std::vector< sal_Bool >( + mrSource.getKashidaArray().begin() + (nIndex - mrSource.getTextPosition()), + mrSource.getKashidaArray().begin() + ((nIndex + nLength) - mrSource.getTextPosition())); + } + if(bNewStartIsNotOldStart) { // needs to be moved to a new start position @@ -137,6 +145,7 @@ namespace drawinglayer::primitive2d nIndex, nLength, std::move(aNewDXArray), + std::move(aNewKashidaArray), mrSource.getFontAttribute(), mrSource.getLocale(), mrSource.getFontColor(), @@ -168,6 +177,7 @@ namespace drawinglayer::primitive2d nIndex, nLength, std::move(aNewDXArray), + std::move(aNewKashidaArray), mrSource.getFontAttribute(), mrSource.getLocale(), mrSource.getFontColor())); diff --git a/drawinglayer/source/primitive2d/textdecoratedprimitive2d.cxx b/drawinglayer/source/primitive2d/textdecoratedprimitive2d.cxx index 0db26fbeb28d..b14e6994f7c9 100644 --- a/drawinglayer/source/primitive2d/textdecoratedprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/textdecoratedprimitive2d.cxx @@ -36,6 +36,7 @@ namespace drawinglayer::primitive2d sal_Int32 nTextPosition, sal_Int32 nTextLength, const std::vector< double >& rDXArray, + const std::vector< sal_Bool >& rKashidaArray, const attribute::FontAttribute& rFontAttribute) const { // create the SimpleTextPrimitive needed in any case @@ -46,6 +47,7 @@ namespace drawinglayer::primitive2d nTextPosition, nTextLength, std::vector(rDXArray), + std::vector(rKashidaArray), rFontAttribute, getLocale(), getFontColor()))); @@ -189,7 +191,7 @@ namespace drawinglayer::primitive2d getFontAttribute().getBiDiStrong()); // handle as one word - impCreateGeometryContent(aRetval, aDecTrans, getText(), getTextPosition(), getTextLength(), getDXArray(), aNewFontAttribute); + impCreateGeometryContent(aRetval, aDecTrans, getText(), getTextPosition(), getTextLength(), getDXArray(), getKashidaArray(), aNewFontAttribute); // Handle Shadow, Outline and TextRelief if(!aRetval.empty()) @@ -294,6 +296,7 @@ namespace drawinglayer::primitive2d sal_Int32 nTextPosition, sal_Int32 nTextLength, std::vector< double >&& rDXArray, + std::vector< sal_Bool >&& rKashidaArray, const attribute::FontAttribute& rFontAttribute, const css::lang::Locale& rLocale, const basegfx::BColor& rFontColor, @@ -312,7 +315,7 @@ namespace drawinglayer::primitive2d bool bEmphasisMarkBelow, TextRelief eTextRelief, bool bShadow) - : TextSimplePortionPrimitive2D(rNewTransform, rText, nTextPosition, nTextLength, std::move(rDXArray), rFontAttribute, rLocale, rFontColor, false, 0, rFillColor), + : TextSimplePortionPrimitive2D(rNewTransform, rText, nTextPosition, nTextLength, std::move(rDXArray), std::move(rKashidaArray), rFontAttribute, rLocale, rFontColor, false, 0, rFillColor), maOverlineColor(rOverlineColor), maTextlineColor(rTextlineColor), meFontOverline(eFontOverline), diff --git a/drawinglayer/source/primitive2d/textlayoutdevice.cxx b/drawinglayer/source/primitive2d/textlayoutdevice.cxx index f70f9f63b81d..78e0c23189ad 100644 --- a/drawinglayer/source/primitive2d/textlayoutdevice.cxx +++ b/drawinglayer/source/primitive2d/textlayoutdevice.cxx @@ -215,8 +215,8 @@ double TextLayouterDevice::getTextWidth(const OUString& rText, sal_uInt32 nIndex void TextLayouterDevice::getTextOutlines(basegfx::B2DPolyPolygonVector& rB2DPolyPolyVector, const OUString& rText, sal_uInt32 nIndex, - sal_uInt32 nLength, - const std::vector& rDXArray) const + sal_uInt32 nLength, const std::vector& rDXArray, + const std::vector& rKashidaArray) const { const sal_uInt32 nDXArrayCount(rDXArray.size()); sal_uInt32 nTextLength(nLength); @@ -239,7 +239,7 @@ void TextLayouterDevice::getTextOutlines(basegfx::B2DPolyPolygonVector& rB2DPoly } mrDevice.GetTextOutlines(rB2DPolyPolyVector, rText, nIndex, nIndex, nLength, 0, - aIntegerDXArray); + aIntegerDXArray, rKashidaArray); } else { diff --git a/drawinglayer/source/primitive2d/textprimitive2d.cxx b/drawinglayer/source/primitive2d/textprimitive2d.cxx index 6330c89b9184..f60f73b21045 100644 --- a/drawinglayer/source/primitive2d/textprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/textprimitive2d.cxx @@ -132,13 +132,13 @@ void TextSimplePortionPrimitive2D::getTextOutlinesAndTransformation( // get the text outlines aTextLayouter.getTextOutlines(rTarget, getText(), getTextPosition(), getTextLength(), - aScaledDXArray); + aScaledDXArray, getKashidaArray()); } else { // get the text outlines aTextLayouter.getTextOutlines(rTarget, getText(), getTextPosition(), getTextLength(), - getDXArray()); + getDXArray(), getKashidaArray()); } // create primitives for the outlines @@ -202,14 +202,16 @@ void TextSimplePortionPrimitive2D::create2DDecomposition( TextSimplePortionPrimitive2D::TextSimplePortionPrimitive2D( basegfx::B2DHomMatrix rNewTransform, OUString rText, sal_Int32 nTextPosition, - sal_Int32 nTextLength, std::vector&& rDXArray, attribute::FontAttribute aFontAttribute, - css::lang::Locale aLocale, const basegfx::BColor& rFontColor, bool bFilled, - tools::Long nWidthToFill, const Color& rTextFillColor) + sal_Int32 nTextLength, std::vector&& rDXArray, std::vector&& rKashidaArray, + attribute::FontAttribute aFontAttribute, css::lang::Locale aLocale, + const basegfx::BColor& rFontColor, bool bFilled, tools::Long nWidthToFill, + const Color& rTextFillColor) : maTextTransform(std::move(rNewTransform)) , maText(std::move(rText)) , mnTextPosition(nTextPosition) , mnTextLength(nTextLength) , maDXArray(std::move(rDXArray)) + , maKashidaArray(std::move(rKashidaArray)) , maFontAttribute(std::move(aFontAttribute)) , maLocale(std::move(aLocale)) , maFontColor(rFontColor) @@ -241,6 +243,7 @@ bool TextSimplePortionPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) && getTextPosition() == rCompare.getTextPosition() && getTextLength() == rCompare.getTextLength() && getDXArray() == rCompare.getDXArray() + && getKashidaArray() == rCompare.getKashidaArray() && getFontAttribute() == rCompare.getFontAttribute() && LocalesAreEqual(getLocale(), rCompare.getLocale()) && getFontColor() == rCompare.getFontColor() && mbFilled == rCompare.mbFilled diff --git a/drawinglayer/source/primitive2d/textstrikeoutprimitive2d.cxx b/drawinglayer/source/primitive2d/textstrikeoutprimitive2d.cxx index f7aedb3c9172..269be2d01817 100644 --- a/drawinglayer/source/primitive2d/textstrikeoutprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/textstrikeoutprimitive2d.cxx @@ -97,6 +97,7 @@ namespace drawinglayer::primitive2d 0, len, std::move(aDXArray), + {}, getFontAttribute(), getLocale(), getFontColor())); diff --git a/drawinglayer/source/processor2d/vclprocessor2d.cxx b/drawinglayer/source/processor2d/vclprocessor2d.cxx index 019feba35182..822800882d55 100644 --- a/drawinglayer/source/processor2d/vclprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclprocessor2d.cxx @@ -321,7 +321,8 @@ void VclProcessor2D::RenderTextSimpleOrDecoratedPortionPrimitive2D( if (!aTransformedDXArray.empty()) { - mpOutputDevice->DrawTextArray(aStartPoint, aText, aTransformedDXArray, nPos, nLen); + mpOutputDevice->DrawTextArray(aStartPoint, aText, aTransformedDXArray, + rTextCandidate.getKashidaArray(), nPos, nLen); } else { diff --git a/drawinglayer/source/tools/emfphelperdata.cxx b/drawinglayer/source/tools/emfphelperdata.cxx index 542259568cd0..e9b8422557a9 100644 --- a/drawinglayer/source/tools/emfphelperdata.cxx +++ b/drawinglayer/source/tools/emfphelperdata.cxx @@ -1683,6 +1683,7 @@ namespace emfplushelper 0, // text always starts at 0 stringLength, std::move(emptyVector), // EMF-PLUS has no DX-array + {}, fontAttribute, locale, color.getBColor(), // Font Color @@ -1702,6 +1703,7 @@ namespace emfplushelper 0, // text always starts at 0 stringLength, std::move(emptyVector), // EMF-PLUS has no DX-array + {}, fontAttribute, locale, color.getBColor()); @@ -2195,6 +2197,7 @@ namespace emfplushelper pos, // take character at current pos aLength, // use determined length std::move(aDXArray), // generated DXArray + {}, fontAttribute, Application::GetSettings().GetLanguageTag().getLocale(), color.getBColor(), @@ -2214,6 +2217,7 @@ namespace emfplushelper pos, // take character at current pos aLength, // use determined length std::move(aDXArray), // generated DXArray + {}, fontAttribute, Application::GetSettings().GetLanguageTag().getLocale(), color.getBColor()); diff --git a/drawinglayer/source/tools/wmfemfhelper.cxx b/drawinglayer/source/tools/wmfemfhelper.cxx index f763cd887ff7..4ec6863eecea 100644 --- a/drawinglayer/source/tools/wmfemfhelper.cxx +++ b/drawinglayer/source/tools/wmfemfhelper.cxx @@ -1077,6 +1077,7 @@ namespace wmfemfhelper sal_uInt16 nTextStart, sal_uInt16 nTextLength, std::vector< double >&& rDXArray, + std::vector< sal_Bool >&& rKashidaArray, TargetHolder& rTarget, PropertyHolder const & rProperty) { @@ -1161,6 +1162,7 @@ namespace wmfemfhelper nTextStart, nTextLength, std::move(rDXArray), + std::move(rKashidaArray), aFontAttribute, aLocale, aFontColor, @@ -1189,6 +1191,7 @@ namespace wmfemfhelper nTextStart, nTextLength, std::vector(rDXArray), + std::vector(rKashidaArray), std::move(aFontAttribute), std::move(aLocale), aFontColor); @@ -1770,6 +1773,7 @@ namespace wmfemfhelper nTextIndex, nTextLength, std::move(aDXArray), + {}, rTargetHolders.Current(), rPropertyHolders.Current()); } @@ -1794,6 +1798,7 @@ namespace wmfemfhelper // prepare DXArray (if used) std::vector< double > aDXArray; const std::vector & rDXArray = pA->GetDXArray(); + std::vector< sal_Bool > aKashidaArray = pA->GetKashidaArray(); if(!rDXArray.empty()) { @@ -1811,6 +1816,7 @@ namespace wmfemfhelper nTextIndex, nTextLength, std::move(aDXArray), + std::move(aKashidaArray), rTargetHolders.Current(), rPropertyHolders.Current()); } @@ -1874,6 +1880,7 @@ namespace wmfemfhelper nTextIndex, nTextLength, std::move(aTextArray), + {}, rTargetHolders.Current(), rPropertyHolders.Current()); } diff --git a/editeng/inc/editdoc.hxx b/editeng/inc/editdoc.hxx index 6ce00d05c40b..25a3dca4b1fc 100644 --- a/editeng/inc/editdoc.hxx +++ b/editeng/inc/editdoc.hxx @@ -463,6 +463,7 @@ public: private: CharPosArrayType aPositions; + std::vector aKashidaPositions; sal_Int32 nTxtWidth; sal_Int32 nStartPosX; sal_Int32 nStart; // could be replaced by nStartPortion @@ -531,6 +532,9 @@ public: CharPosArrayType& GetCharPosArray() { return aPositions;} const CharPosArrayType& GetCharPosArray() const { return aPositions;} + std::vector& GetKashidaArray() { return aKashidaPositions; } + const std::vector& GetKashidaArray() const { return aKashidaPositions; } + EditLine* Clone() const; EditLine& operator = ( const EditLine& rLine ); diff --git a/editeng/source/editeng/editeng.cxx b/editeng/source/editeng/editeng.cxx index db4ae5db4491..88bc04a9efed 100644 --- a/editeng/source/editeng/editeng.cxx +++ b/editeng/source/editeng/editeng.cxx @@ -2465,7 +2465,8 @@ css::uno::Reference< css::datatransfer::XTransferable > // ====================== Virtual Methods ======================== void EditEngine::DrawingText( const Point&, const OUString&, sal_Int32, sal_Int32, - o3tl::span, const SvxFont&, sal_Int32 /*nPara*/, sal_uInt8 /*nRightToLeft*/, + o3tl::span, o3tl::span, + const SvxFont&, sal_Int32 /*nPara*/, sal_uInt8 /*nRightToLeft*/, const EEngineData::WrongSpellVector*, const SvxFieldData*, bool, bool, const css::lang::Locale*, const Color&, const Color&) diff --git a/editeng/source/editeng/impedit3.cxx b/editeng/source/editeng/impedit3.cxx index 143a763208e1..9d71560c108b 100644 --- a/editeng/source/editeng/impedit3.cxx +++ b/editeng/source/editeng/impedit3.cxx @@ -2147,6 +2147,10 @@ void ImpEditEngine::ImpAdjustBlocks( ParaPortion* pParaPortion, EditLine* pLine, nLastScript = nScript; } + // Save the number of blanks, we will use it below when marking Kashida + // positions. + auto nBlankSize = aPositions.size(); + // Kashidas ? ImpFindKashidas( pNode, nFirstChar, nLastChar, aPositions ); @@ -2186,6 +2190,19 @@ void ImpEditEngine::ImpAdjustBlocks( ParaPortion* pParaPortion, EditLine* pLine, DBG_ASSERT( nSomeExtraSpace < static_cast(nGaps), "AdjustBlocks: ExtraSpace too large" ); DBG_ASSERT( nSomeExtraSpace >= 0, "AdjustBlocks: ExtraSpace < 0 " ); + // Mark Kashida positions, so that VCL knows where to insert Kashida and + // where to only expand the width. + if (aPositions.size() > nBlankSize) + { + pLine->GetKashidaArray().resize(pLine->GetCharPosArray().size(), false); + for (auto i = nBlankSize; i < aPositions.size(); i++) + { + auto nChar = aPositions[i]; + if ( nChar < nLastChar ) + pLine->GetKashidaArray()[nChar-nFirstChar] = 1 /*sal_True*/; + } + } + // Correct the positions in the Array and the portion widths: // Last character won't be considered... for (auto const& nChar : aPositions) @@ -2202,7 +2219,6 @@ void ImpEditEngine::ImpAdjustBlocks( ParaPortion* pParaPortion, EditLine* pLine, rLastPortion.GetSize().AdjustWidth( 1 ); // Correct positions in array - // Even for kashidas just change positions, VCL will then draw the kashida automatically sal_Int32 nPortionEnd = nPortionStart + rLastPortion.GetLen(); for ( sal_Int32 _n = nChar; _n < nPortionEnd; _n++ ) { @@ -3293,6 +3309,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po sal_Int32 nTextStart = 0; sal_Int32 nTextLen = 0; o3tl::span pDXArray; + o3tl::span pKashidaArray; std::vector aTmpDXArray; if ( rTextPortion.GetKind() == PortionKind::TEXT ) @@ -3303,6 +3320,12 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po pDXArray = o3tl::span(pLine->GetCharPosArray().data() + (nIndex - pLine->GetStart()), pLine->GetCharPosArray().size() - (nIndex - pLine->GetStart())); + if (!pLine->GetKashidaArray().empty()) + { + pKashidaArray = o3tl::span(pLine->GetKashidaArray().data() + (nIndex - pLine->GetStart()), + pLine->GetKashidaArray().size() - (nIndex - pLine->GetStart())); + } + // Paint control characters (#i55716#) /* XXX: Given that there's special handling * only for some specific characters @@ -3552,7 +3575,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po ImplCalcDigitLang(aTmpFont.GetLanguage())); // StripPortions() data callback - GetEditEnginePtr()->DrawingText( aOutPos, aText, nTextStart, nTextLen, pDXArray, + GetEditEnginePtr()->DrawingText( aOutPos, aText, nTextStart, nTextLen, pDXArray, pKashidaArray, aTmpFont, n, rTextPortion.GetRightToLeftLevel(), !aWrongSpellVector.empty() ? &aWrongSpellVector : nullptr, pFieldData, @@ -3656,7 +3679,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po --nTextLen; // output directly - aTmpFont.QuickDrawText( &rOutDev, aRealOutPos, aText, nTextStart, nTextLen, pDXArray ); + aTmpFont.QuickDrawText( &rOutDev, aRealOutPos, aText, nTextStart, nTextLen, pDXArray, pKashidaArray ); if ( bDrawFrame ) { @@ -3792,7 +3815,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po const Color aTextLineColor(rOutDev.GetTextLineColor()); GetEditEnginePtr()->DrawingText( - aTmpPos, OUString(), 0, 0, {}, + aTmpPos, OUString(), 0, 0, {}, {}, aTmpFont, n, 0, nullptr, nullptr, @@ -3841,7 +3864,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po const Color aTextLineColor(rOutDev.GetTextLineColor()); GetEditEnginePtr()->DrawingText( - aTmpPos, OUString(), 0, 0, {}, + aTmpPos, OUString(), 0, 0, {}, {}, aTmpFont, n, 0, nullptr, nullptr, diff --git a/editeng/source/items/svxfont.cxx b/editeng/source/items/svxfont.cxx index ca8c5f3fddc6..ac360873824a 100644 --- a/editeng/source/items/svxfont.cxx +++ b/editeng/source/items/svxfont.cxx @@ -545,21 +545,24 @@ Size SvxFont::GetTextSize(const OutputDevice& rOut, const OUString &rTxt, static void DrawTextArray( OutputDevice* pOut, const Point& rStartPt, const OUString& rStr, o3tl::span pDXAry, + o3tl::span pKashidaAry, sal_Int32 nIndex, sal_Int32 nLen ) { const SalLayoutGlyphs* layoutGlyphs = SalLayoutGlyphsCache::self()->GetLayoutGlyphs(pOut, rStr, nIndex, nLen); - pOut->DrawTextArray(rStartPt, rStr, pDXAry, nIndex, nLen, SalLayoutFlags::NONE, layoutGlyphs); + pOut->DrawTextArray(rStartPt, rStr, pDXAry, pKashidaAry, nIndex, nLen, SalLayoutFlags::NONE, layoutGlyphs); } void SvxFont::QuickDrawText( OutputDevice *pOut, const Point &rPos, const OUString &rTxt, - const sal_Int32 nIdx, const sal_Int32 nLen, o3tl::span pDXArray ) const + const sal_Int32 nIdx, const sal_Int32 nLen, + o3tl::span pDXArray, + o3tl::span pKashidaArray) const { // Font has to be selected in OutputDevice... if ( !IsCaseMap() && !IsCapital() && !IsKern() && !IsEsc() ) { - DrawTextArray( pOut, rPos, rTxt, pDXArray, nIdx, nLen ); + DrawTextArray( pOut, rPos, rTxt, pDXArray, pKashidaArray, nIdx, nLen ); return; } @@ -596,9 +599,9 @@ void SvxFont::QuickDrawText( OutputDevice *pOut, else { if ( !IsCaseMap() ) - DrawTextArray( pOut, aPos, rTxt, pDXArray, nIdx, nLen ); + DrawTextArray( pOut, aPos, rTxt, pDXArray, pKashidaArray, nIdx, nLen ); else - DrawTextArray( pOut, aPos, CalcCaseMap( rTxt ), pDXArray, nIdx, nLen ); + DrawTextArray( pOut, aPos, CalcCaseMap( rTxt ), pDXArray, pKashidaArray, nIdx, nLen ); } } } diff --git a/editeng/source/outliner/outleeng.cxx b/editeng/source/outliner/outleeng.cxx index e4fc414ad8e3..275636b6581e 100644 --- a/editeng/source/outliner/outleeng.cxx +++ b/editeng/source/outliner/outleeng.cxx @@ -141,7 +141,8 @@ OUString OutlinerEditEng::GetUndoComment( sal_uInt16 nUndoId ) const } void OutlinerEditEng::DrawingText( const Point& rStartPos, const OUString& rText, sal_Int32 nTextStart, sal_Int32 nTextLen, - o3tl::span pDXArray, const SvxFont& rFont, sal_Int32 nPara, sal_uInt8 nRightToLeft, + o3tl::span pDXArray, o3tl::span pKashidaArray, + const SvxFont& rFont, sal_Int32 nPara, sal_uInt8 nRightToLeft, const EEngineData::WrongSpellVector* pWrongSpellVector, const SvxFieldData* pFieldData, bool bEndOfLine, @@ -150,7 +151,7 @@ void OutlinerEditEng::DrawingText( const Point& rStartPos, const OUString& rText const Color& rOverlineColor, const Color& rTextLineColor) { - pOwner->DrawingText(rStartPos,rText,nTextStart,nTextLen,pDXArray,rFont,nPara,nRightToLeft, + pOwner->DrawingText(rStartPos,rText,nTextStart,nTextLen,pDXArray,pKashidaArray,rFont,nPara,nRightToLeft, pWrongSpellVector, pFieldData, bEndOfLine, bEndOfParagraph, false/*bEndOfBullet*/, pLocale, rOverlineColor, rTextLineColor); } diff --git a/editeng/source/outliner/outleeng.hxx b/editeng/source/outliner/outleeng.hxx index 963e74582ec0..d19b54eba06a 100644 --- a/editeng/source/outliner/outleeng.hxx +++ b/editeng/source/outliner/outleeng.hxx @@ -44,7 +44,8 @@ public: virtual void ParagraphConnected( sal_Int32 nLeftParagraph, sal_Int32 nRightParagraph ) override; virtual void DrawingText( const Point& rStartPos, const OUString& rText, sal_Int32 nTextStart, - sal_Int32 nTextLen, o3tl::span pDXArray, const SvxFont& rFont, + sal_Int32 nTextLen, o3tl::span pDXArray, + o3tl::span pKashidaArray, const SvxFont& rFont, sal_Int32 nPara, sal_uInt8 nRightToLeft, const EEngineData::WrongSpellVector* pWrongSpellVector, const SvxFieldData* pFieldData, diff --git a/editeng/source/outliner/outliner.cxx b/editeng/source/outliner/outliner.cxx index 4d67810c7a77..d7ea27662e77 100644 --- a/editeng/source/outliner/outliner.cxx +++ b/editeng/source/outliner/outliner.cxx @@ -974,7 +974,7 @@ void Outliner::PaintBullet(sal_Int32 nPara, const Point& rStartPos, const Point& aTextPos.AdjustY( -(aMetric.GetDescent()) ); } - DrawingText(aTextPos, pPara->GetText(), 0, pPara->GetText().getLength(), aBuf, + DrawingText(aTextPos, pPara->GetText(), 0, pPara->GetText().getLength(), aBuf, {}, aSvxFont, nPara, bRightToLeftPara ? 1 : 0, nullptr, nullptr, false, false, true, nullptr, Color(), Color()); } else @@ -1650,7 +1650,8 @@ void Outliner::StripPortions() } void Outliner::DrawingText( const Point& rStartPos, const OUString& rText, sal_Int32 nTextStart, - sal_Int32 nTextLen, o3tl::span pDXArray,const SvxFont& rFont, + sal_Int32 nTextLen, o3tl::span pDXArray, + o3tl::span pKashidaArray, const SvxFont& rFont, sal_Int32 nPara, sal_uInt8 nRightToLeft, const EEngineData::WrongSpellVector* pWrongSpellVector, const SvxFieldData* pFieldData, @@ -1663,7 +1664,7 @@ void Outliner::DrawingText( const Point& rStartPos, const OUString& rText, sal_I { if(aDrawPortionHdl.IsSet()) { - DrawPortionInfo aInfo( rStartPos, rText, nTextStart, nTextLen, rFont, nPara, pDXArray, pWrongSpellVector, + DrawPortionInfo aInfo( rStartPos, rText, nTextStart, nTextLen, rFont, nPara, pDXArray, pKashidaArray, pWrongSpellVector, pFieldData, pLocale, rOverlineColor, rTextLineColor, nRightToLeft, false, 0, bEndOfLine, bEndOfParagraph, bEndOfBullet); aDrawPortionHdl.Call( &aInfo ); @@ -1676,7 +1677,7 @@ void Outliner::DrawingTab( const Point& rStartPos, tools::Long nWidth, const OUS { if(aDrawPortionHdl.IsSet()) { - DrawPortionInfo aInfo( rStartPos, rChar, 0, rChar.getLength(), rFont, nPara, {}, nullptr, + DrawPortionInfo aInfo( rStartPos, rChar, 0, rChar.getLength(), rFont, nPara, {}, {}, nullptr, nullptr, nullptr, rOverlineColor, rTextLineColor, nRightToLeft, true, nWidth, bEndOfLine, bEndOfParagraph, false); aDrawPortionHdl.Call( &aInfo ); diff --git a/emfio/source/reader/mtftools.cxx b/emfio/source/reader/mtftools.cxx index 67dfdbeaedf0..95c51188bc3f 100644 --- a/emfio/source/reader/mtftools.cxx +++ b/emfio/source/reader/mtftools.cxx @@ -1828,7 +1828,7 @@ namespace emfio { Point aCharDisplacement( i ? (*pDXArry)[i-1] : 0, i ? pDYArry[i-1] : 0 ); Point().RotateAround(aCharDisplacement, maFont.GetOrientation()); - mpGDIMetaFile->AddAction( new MetaTextArrayAction( rPosition + aCharDisplacement, OUString( rText[i] ), o3tl::span{}, 0, 1 ) ); + mpGDIMetaFile->AddAction( new MetaTextArrayAction( rPosition + aCharDisplacement, OUString( rText[i] ), o3tl::span{}, {}, 0, 1 ) ); } } else @@ -1859,7 +1859,7 @@ namespace emfio pVDev->GetTextArray( rText, &aMyDXArray, 0, rText.getLength()); pDX = aMyDXArray; } - mpGDIMetaFile->AddAction( new MetaTextArrayAction( rPosition, rText, pDX, 0, rText.getLength() ) ); + mpGDIMetaFile->AddAction( new MetaTextArrayAction( rPosition, rText, pDX, {}, 0, rText.getLength() ) ); } } SetGfxMode( nOldGfxMode ); diff --git a/include/drawinglayer/primitive2d/textdecoratedprimitive2d.hxx b/include/drawinglayer/primitive2d/textdecoratedprimitive2d.hxx index 1a4d821c7e60..73663ff95d32 100644 --- a/include/drawinglayer/primitive2d/textdecoratedprimitive2d.hxx +++ b/include/drawinglayer/primitive2d/textdecoratedprimitive2d.hxx @@ -63,6 +63,7 @@ namespace drawinglayer::primitive2d sal_Int32 nTextPosition, sal_Int32 nTextLength, const ::std::vector< double >& rDXArray, + const ::std::vector< sal_Bool >& rKashidaArray, const attribute::FontAttribute& rFontAttribute) const; /// local decomposition. @@ -77,6 +78,7 @@ namespace drawinglayer::primitive2d sal_Int32 nTextPosition, sal_Int32 nTextLength, std::vector< double >&& rDXArray, + std::vector< sal_Bool >&& rKashidaArray, const attribute::FontAttribute& rFontAttribute, const css::lang::Locale& rLocale, const basegfx::BColor& rFontColor, diff --git a/include/drawinglayer/primitive2d/textlayoutdevice.hxx b/include/drawinglayer/primitive2d/textlayoutdevice.hxx index 93587769c449..6348de0ddd25 100644 --- a/include/drawinglayer/primitive2d/textlayoutdevice.hxx +++ b/include/drawinglayer/primitive2d/textlayoutdevice.hxx @@ -84,7 +84,8 @@ public: double getTextWidth(const OUString& rText, sal_uInt32 nIndex, sal_uInt32 nLength) const; void getTextOutlines(basegfx::B2DPolyPolygonVector&, const OUString& rText, sal_uInt32 nIndex, - sal_uInt32 nLength, const ::std::vector& rDXArray) const; + sal_uInt32 nLength, const ::std::vector& rDXArray, + const ::std::vector& rKashidaArray) const; basegfx::B2DRange getTextBoundRect(const OUString& rText, sal_uInt32 nIndex, sal_uInt32 nLength) const; diff --git a/include/drawinglayer/primitive2d/textprimitive2d.hxx b/include/drawinglayer/primitive2d/textprimitive2d.hxx index fd80e531e910..4182b0c0fbe4 100644 --- a/include/drawinglayer/primitive2d/textprimitive2d.hxx +++ b/include/drawinglayer/primitive2d/textprimitive2d.hxx @@ -72,6 +72,9 @@ namespace drawinglayer::primitive2d point in FontCoordinateSystem X-Direction (given by maTextTransform) to the start point of the second character + @param rKashidaArray + The Kashida insertion positions. + @param rFontAttribute The font definition @@ -107,6 +110,9 @@ private: /// The DX array in logic units std::vector maDXArray; + /// The Kashida array + std::vector maKashidaArray; + /// The font definition attribute::FontAttribute maFontAttribute; @@ -139,6 +145,7 @@ public: TextSimplePortionPrimitive2D(basegfx::B2DHomMatrix aNewTransform, OUString aText, sal_Int32 nTextPosition, sal_Int32 nTextLength, std::vector&& rDXArray, + std::vector&& rKashidaArray, attribute::FontAttribute aFontAttribute, css::lang::Locale aLocale, const basegfx::BColor& rFontColor, bool bFilled = false, tools::Long nWidthToFill = 0, @@ -156,6 +163,7 @@ public: sal_Int32 getTextPosition() const { return mnTextPosition; } sal_Int32 getTextLength() const { return mnTextLength; } const ::std::vector& getDXArray() const { return maDXArray; } + const ::std::vector& getKashidaArray() const { return maKashidaArray; } const attribute::FontAttribute& getFontAttribute() const { return maFontAttribute; } const css::lang::Locale& getLocale() const { return maLocale; } const basegfx::BColor& getFontColor() const { return maFontColor; } diff --git a/include/editeng/editeng.hxx b/include/editeng/editeng.hxx index a0ce29ca26d1..ae0990666ded 100644 --- a/include/editeng/editeng.hxx +++ b/include/editeng/editeng.hxx @@ -498,7 +498,9 @@ public: virtual void DrawingText( const Point& rStartPos, const OUString& rText, sal_Int32 nTextStart, sal_Int32 nTextLen, - o3tl::span pDXArray, const SvxFont& rFont, + o3tl::span pDXArray, + o3tl::span pKashidaArray, + const SvxFont& rFont, sal_Int32 nPara, sal_uInt8 nRightToLeft, const EEngineData::WrongSpellVector* pWrongSpellVector, const SvxFieldData* pFieldData, diff --git a/include/editeng/outliner.hxx b/include/editeng/outliner.hxx index 6e19aa129a78..3326a3d6662b 100644 --- a/include/editeng/outliner.hxx +++ b/include/editeng/outliner.hxx @@ -401,6 +401,7 @@ public: sal_Int32 mnPara; const SvxFont& mrFont; o3tl::span mpDXArray; + o3tl::span mpKashidaArray; const EEngineData::WrongSpellVector* mpWrongSpellVector; const SvxFieldData* mpFieldData; @@ -427,6 +428,7 @@ public: const SvxFont& rFnt, sal_Int32 nPar, o3tl::span pDXArr, + o3tl::span pKashidaArr, const EEngineData::WrongSpellVector* pWrongSpellVector, const SvxFieldData* pFieldData, const css::lang::Locale* pLocale, @@ -445,6 +447,7 @@ public: mnPara(nPar), mrFont(rFnt), mpDXArray(pDXArr), + mpKashidaArray(pKashidaArr), mpWrongSpellVector(pWrongSpellVector), mpFieldData(pFieldData), mpLocale(pLocale), @@ -818,7 +821,9 @@ public: void DrawingText( const Point& rStartPos, const OUString& rText, sal_Int32 nTextStart, sal_Int32 nTextLen, - o3tl::span pDXArray, const SvxFont& rFont, + o3tl::span pDXArray, + o3tl::span pKashidaArray, + const SvxFont& rFont, sal_Int32 nPara, sal_uInt8 nRightToLeft, const EEngineData::WrongSpellVector* pWrongSpellVector, const SvxFieldData* pFieldData, diff --git a/include/editeng/svxfont.hxx b/include/editeng/svxfont.hxx index e0f92c57289d..ac4ec390128a 100644 --- a/include/editeng/svxfont.hxx +++ b/include/editeng/svxfont.hxx @@ -96,7 +96,8 @@ public: void QuickDrawText( OutputDevice *pOut, const Point &rPos, const OUString &rTxt, const sal_Int32 nIdx = 0, const sal_Int32 nLen = SAL_MAX_INT32, - o3tl::span pDXArray = {} ) const; + o3tl::span pDXArray = {}, + o3tl::span pKashidaArray = {} ) const; Size QuickGetTextSize( const OutputDevice *pOut, const OUString &rTxt, const sal_Int32 nIdx, const sal_Int32 nLen, diff --git a/include/vcl/metaact.hxx b/include/vcl/metaact.hxx index 37c3db3d9273..11caf48b2429 100644 --- a/include/vcl/metaact.hxx +++ b/include/vcl/metaact.hxx @@ -507,6 +507,7 @@ private: Point maStartPt; OUString maStr; std::vector maDXAry; + std::vector maKashidaAry; sal_Int32 mnIndex; sal_Int32 mnLen; @@ -516,10 +517,14 @@ public: MetaTextArrayAction(); MetaTextArrayAction( const MetaTextArrayAction& rAction ); MetaTextArrayAction( const Point& rStartPt, OUString aStr, - std::vector rDXAry, sal_Int32 nIndex, + std::vector rDXAry, + std::vector pKashidaAry, + sal_Int32 nIndex, sal_Int32 nLen ); MetaTextArrayAction( const Point& rStartPt, OUString aStr, - o3tl::span pDXAry, sal_Int32 nIndex, + o3tl::span pDXAry, + o3tl::span pKashidaAry, + sal_Int32 nIndex, sal_Int32 nLen ); virtual void Execute( OutputDevice* pOut ) override; @@ -534,11 +539,13 @@ public: sal_Int32 GetIndex() const { return mnIndex; } sal_Int32 GetLen() const { return mnLen; } const std::vector & GetDXArray() const { return maDXAry; } + const std::vector & GetKashidaArray() const { return maKashidaAry; } void SetPoint(const Point& rPt) { maStartPt = rPt; } void SetText(const OUString& rStr) { maStr = rStr; } void SetIndex(sal_Int32 rIndex) { mnIndex = rIndex; } void SetLen(sal_Int32 rLen) { mnLen = rLen; } void SetDXArray(std::vector aArray); + void SetKashidaArray(std::vector aArray); }; class SAL_DLLPUBLIC_RTTI MetaStretchTextAction final : public MetaAction diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx index 2595415db1b5..af55ebd3d614 100644 --- a/include/vcl/outdev.hxx +++ b/include/vcl/outdev.hxx @@ -963,6 +963,7 @@ public: bool GetTextBoundRect( tools::Rectangle& rRect, const OUString& rStr, sal_Int32 nBase = 0, sal_Int32 nIndex = 0, sal_Int32 nLen = -1, sal_uLong nLayoutWidth = 0, o3tl::span pDXArray = {}, + o3tl::span pKashidaArray = {}, const SalLayoutGlyphs* pGlyphs = nullptr ) const; tools::Rectangle ImplGetTextBoundRect( const SalLayout& ) const; @@ -973,12 +974,14 @@ public: bool GetTextOutlines( PolyPolyVector&, const OUString& rStr, sal_Int32 nBase = 0, sal_Int32 nIndex = 0, sal_Int32 nLen = -1, - sal_uLong nLayoutWidth = 0, o3tl::span pDXArray = {} ) const; + sal_uLong nLayoutWidth = 0, o3tl::span pDXArray = {}, + o3tl::span pKashidaArray = {} ) const; bool GetTextOutlines( basegfx::B2DPolyPolygonVector &rVector, const OUString& rStr, sal_Int32 nBase, sal_Int32 nIndex = 0, sal_Int32 nLen = -1, - sal_uLong nLayoutWidth = 0, o3tl::span pDXArray = {} ) const; + sal_uLong nLayoutWidth = 0, o3tl::span pDXArray = {}, + o3tl::span pKashidaArray = {} ) const; OUString GetEllipsisString( const OUString& rStr, tools::Long nMaxWidth, @@ -1044,6 +1047,7 @@ public: void DrawTextArray( const Point& rStartPt, const OUString& rStr, o3tl::span pDXAry, + o3tl::span pKashidaAry={}, sal_Int32 nIndex = 0, sal_Int32 nLen = -1, SalLayoutFlags flags = SalLayoutFlags::NONE, @@ -1236,7 +1240,9 @@ public: std::unique_ptr ImplLayout( const OUString&, sal_Int32 nIndex, sal_Int32 nLen, const Point& rLogicPos = Point(0,0), tools::Long nLogicWidth=0, - o3tl::span pLogicDXArray={}, SalLayoutFlags flags = SalLayoutFlags::NONE, + o3tl::span pLogicDXArray={}, + o3tl::span pKashidaArray={}, + SalLayoutFlags flags = SalLayoutFlags::NONE, vcl::text::TextLayoutCache const* = nullptr, const SalLayoutGlyphs* pGlyphs = nullptr) const; diff --git a/include/vcl/pdfwriter.hxx b/include/vcl/pdfwriter.hxx index 8764f3f49c8e..0c2cbb6294dd 100644 --- a/include/vcl/pdfwriter.hxx +++ b/include/vcl/pdfwriter.hxx @@ -764,6 +764,7 @@ The following structure describes the permissions used in PDF security FontLineStyle eOverline ); void DrawTextArray( const Point& rStartPt, const OUString& rStr, o3tl::span pDXAry, + o3tl::span pKashidaAry, sal_Int32 nIndex, sal_Int32 nLen ); void DrawStretchText( const Point& rStartPt, sal_uLong nWidth, diff --git a/include/vcl/rendercontext/SalLayoutFlags.hxx b/include/vcl/rendercontext/SalLayoutFlags.hxx index 68c26cadb48b..e8c5901d8528 100644 --- a/include/vcl/rendercontext/SalLayoutFlags.hxx +++ b/include/vcl/rendercontext/SalLayoutFlags.hxx @@ -30,13 +30,12 @@ enum class SalLayoutFlags DisableKerning = 0x0010, KerningAsian = 0x0020, Vertical = 0x0040, - KashidaJustification = 0x0800, ForFallback = 0x2000, GlyphItemsOnly = 0x4000, }; namespace o3tl { -template <> struct typed_flags : is_typed_flags +template <> struct typed_flags : is_typed_flags { }; } diff --git a/sc/source/ui/view/hintwin.cxx b/sc/source/ui/view/hintwin.cxx index 1dc76d139dd0..d57d8e0b787f 100644 --- a/sc/source/ui/view/hintwin.cxx +++ b/sc/source/ui/view/hintwin.cxx @@ -83,7 +83,7 @@ drawinglayer::primitive2d::Primitive2DContainer ScOverlayHint::createOverlaySequ rtl::Reference pTitle = new drawinglayer::primitive2d::TextSimplePortionPrimitive2D( aTextMatrix, m_aTitle, 0, m_aTitle.getLength(), - std::vector(), std::move(aFontAttr), css::lang::Locale(), + std::vector(), {}, std::move(aFontAttr), css::lang::Locale(), rColor.getBColor()); Point aTextStart(nLeft + aHintMargin.Width() + aIndent.Width(), @@ -123,7 +123,7 @@ drawinglayer::primitive2d::Primitive2DContainer ScOverlayHint::createOverlaySequ rtl::Reference pMessage = new drawinglayer::primitive2d::TextSimplePortionPrimitive2D( aTextMatrix, aLine, 0, aLine.getLength(), - std::vector(), aFontAttr, css::lang::Locale(), + std::vector(), {}, aFontAttr, css::lang::Locale(), rColor.getBColor()); rRange.expand(pMessage->getB2DRange(aDummy)); diff --git a/sd/source/ui/view/sdview.cxx b/sd/source/ui/view/sdview.cxx index 429a8c408753..7099977b31cf 100644 --- a/sd/source/ui/view/sdview.cxx +++ b/sd/source/ui/view/sdview.cxx @@ -430,6 +430,7 @@ void ViewRedirector::createRedirectedPrimitive2DSequence( 0, nTextLength, std::move(aDXArray), + {}, std::move(aFontAttribute), std::move(aLocale), aRGBColor)); diff --git a/sfx2/source/control/thumbnailviewitem.cxx b/sfx2/source/control/thumbnailviewitem.cxx index 36a33edc086b..9b75120289be 100644 --- a/sfx2/source/control/thumbnailviewitem.cxx +++ b/sfx2/source/control/thumbnailviewitem.cxx @@ -269,6 +269,7 @@ void ThumbnailViewItem::addTextPrimitives (const OUString& rText, const Thumbnai new TextSimplePortionPrimitive2D(aTextMatrix, aText, nLineStart, nLineLength, std::vector(), + {}, pAttrs->aFontAttr, css::lang::Locale(), aTextColor)); diff --git a/svgio/source/svgreader/svgcharacternode.cxx b/svgio/source/svgreader/svgcharacternode.cxx index 581129cf1025..0a4731b200d5 100644 --- a/svgio/source/svgreader/svgcharacternode.cxx +++ b/svgio/source/svgreader/svgcharacternode.cxx @@ -452,6 +452,7 @@ namespace svgio::svgreader nIndex, nLength, std::move(aTextArray), + {}, aFontAttribute, aLocale, aFill, @@ -480,6 +481,7 @@ namespace svgio::svgreader nIndex, nLength, std::move(aTextArray), + {}, aFontAttribute, aLocale, aFill); diff --git a/svtools/source/control/ruler.cxx b/svtools/source/control/ruler.cxx index 07e030aac109..340d29b27cfc 100644 --- a/svtools/source/control/ruler.cxx +++ b/svtools/source/control/ruler.cxx @@ -79,7 +79,7 @@ SalLayoutGlyphs* lcl_GetRulerTextGlyphs(const vcl::RenderContext& rRenderContext // Calculate glyph items. std::unique_ptr pLayout = rRenderContext.ImplLayout( - rText, 0, rText.getLength(), Point(0, 0), 0, {}, SalLayoutFlags::GlyphItemsOnly); + rText, 0, rText.getLength(), Point(0, 0), 0, {}, {}, SalLayoutFlags::GlyphItemsOnly); if (!pLayout) return nullptr; @@ -339,7 +339,7 @@ void Ruler::ImplVDrawText(vcl::RenderContext& rRenderContext, tools::Long nX, to tools::Rectangle aRect; SalLayoutGlyphs* pTextLayout = lcl_GetRulerTextGlyphs(rRenderContext, rText, maTextGlyphs[rText]); - rRenderContext.GetTextBoundRect(aRect, rText, 0, 0, -1, 0, {}, pTextLayout); + rRenderContext.GetTextBoundRect(aRect, rText, 0, 0, -1, 0, {}, {}, pTextLayout); tools::Long nShiftX = ( aRect.GetWidth() / 2 ) + aRect.Left(); tools::Long nShiftY = ( aRect.GetHeight() / 2 ) + aRect.Top(); diff --git a/svx/source/diagram/IDiagramHelper.cxx b/svx/source/diagram/IDiagramHelper.cxx index 672c7485540a..ad1db2334d68 100644 --- a/svx/source/diagram/IDiagramHelper.cxx +++ b/svx/source/diagram/IDiagramHelper.cxx @@ -167,7 +167,8 @@ void OverlayDiagramPrimitive::create2DDecomposition( aName, 0, aName.getLength(), - aDXArray); + aDXArray, + {}); // put into one PolyPolygon (also simplification - overlapping chars // may create XOR gaps, so these exist for a reason, but low probability) diff --git a/svx/source/svdraw/svdotextdecomposition.cxx b/svx/source/svdraw/svdotextdecomposition.cxx index 666c20d48f5a..f5955eb7d869 100644 --- a/svx/source/svdraw/svdotextdecomposition.cxx +++ b/svx/source/svdraw/svdotextdecomposition.cxx @@ -234,6 +234,18 @@ namespace } } + ::std::vector< sal_Bool > aKashidaArray; + + if(!rInfo.mpKashidaArray.empty() && rInfo.mnTextLen) + { + aKashidaArray.reserve(rInfo.mnTextLen); + + for(sal_Int32 a=0; a < rInfo.mnTextLen; a++) + { + aKashidaArray.push_back(rInfo.mpKashidaArray[a]); + } + } + // create complex text primitive and append const Color aFontColor(rInfo.mrFont.GetColor()); const basegfx::BColor aBFontColor(aFontColor.getBColor()); @@ -316,6 +328,7 @@ namespace rInfo.mnTextStart, rInfo.mnTextLen, std::vector(aDXArray), + std::vector(aKashidaArray), aFontAttribute, rInfo.mpLocale ? *rInfo.mpLocale : css::lang::Locale(), aBFontColor, @@ -344,6 +357,7 @@ namespace rInfo.mnTextStart, rInfo.mnTextLen, std::vector(aDXArray), + std::vector(aKashidaArray), std::move(aFontAttribute), rInfo.mpLocale ? *rInfo.mpLocale : css::lang::Locale(), aBFontColor, diff --git a/svx/source/svdraw/svdotextpathdecomposition.cxx b/svx/source/svdraw/svdotextpathdecomposition.cxx index 99a7169c1fe6..7537625b2a26 100644 --- a/svx/source/svdraw/svdotextpathdecomposition.cxx +++ b/svx/source/svdraw/svdotextpathdecomposition.cxx @@ -58,6 +58,7 @@ namespace sal_Int32 mnParagraph; SvxFont maFont; ::std::vector< double > maDblDXArray; // double DXArray, font size independent -> unit coordinate system + ::std::vector< sal_Bool > maKashidaArray; lang::Locale maLocale; bool mbRTL : 1; @@ -70,6 +71,7 @@ namespace mnTextLength(rInfo.mnTextLen), mnParagraph(rInfo.mnPara), maFont(rInfo.mrFont), + maKashidaArray(rInfo.mpKashidaArray.begin(), rInfo.mpKashidaArray.end()), maLocale(rInfo.mpLocale ? *rInfo.mpLocale : lang::Locale()), mbRTL(!rInfo.mrFont.IsVertical() && rInfo.IsRTL()) { @@ -107,6 +109,7 @@ namespace const SvxFont& getFont() const { return maFont; } bool isRTL() const { return mbRTL; } const ::std::vector< double >& getDoubleDXArray() const { return maDblDXArray; } + const ::std::vector< sal_Bool >& getKashidaArray() const { return maKashidaArray; } const lang::Locale& getLocale() const { return maLocale; } sal_Int32 getPortionIndex(sal_Int32 nIndex, sal_Int32 nLength) const @@ -497,6 +500,7 @@ namespace nPortionIndex, nNextGlyphLen, std::vector(aNewDXArray), + std::vector(pCandidate->getKashidaArray()), aCandidateFontAttribute, pCandidate->getLocale(), aRGBShadowColor) ); @@ -514,6 +518,7 @@ namespace nPortionIndex, nNextGlyphLen, std::move(aNewDXArray), + std::vector(pCandidate->getKashidaArray()), aCandidateFontAttribute, pCandidate->getLocale(), aRGBColor) ); diff --git a/svx/source/tbxctrls/StylesPreviewWindow.cxx b/svx/source/tbxctrls/StylesPreviewWindow.cxx index 3ad9fa780117..8f5dfea0b2c8 100644 --- a/svx/source/tbxctrls/StylesPreviewWindow.cxx +++ b/svx/source/tbxctrls/StylesPreviewWindow.cxx @@ -358,7 +358,8 @@ void StyleItemController::DrawText(vcl::RenderContext& rRenderContext) const SalLayoutGlyphs* layoutGlyphs = SalLayoutGlyphsCache::self()->GetLayoutGlyphs(&rRenderContext, m_aStyleName.second); tools::Rectangle aTextRect; - rRenderContext.GetTextBoundRect(aTextRect, m_aStyleName.second, 0, 0, -1, 0, {}, layoutGlyphs); + rRenderContext.GetTextBoundRect(aTextRect, m_aStyleName.second, 0, 0, -1, 0, {}, {}, + layoutGlyphs); Point aPos(0, 0); aPos.AdjustX(LEFT_MARGIN); diff --git a/sw/source/core/inc/scriptinfo.hxx b/sw/source/core/inc/scriptinfo.hxx index cfe9ef3e55fb..ee536803a617 100644 --- a/sw/source/core/inc/scriptinfo.hxx +++ b/sw/source/core/inc/scriptinfo.hxx @@ -289,7 +289,7 @@ public: The value which has to be added to a kashida opportunity. @return The number of kashida opportunities in the given range */ - sal_Int32 KashidaJustify( sal_Int32* pKernArray, + sal_Int32 KashidaJustify( sal_Int32* pKernArray, sal_Bool* pKashidaArray, TextFrameIndex nStt, TextFrameIndex nLen, tools::Long nSpaceAdd = 0) const; /** Clears array of kashidas marked as invalid diff --git a/sw/source/core/layout/paintfrm.cxx b/sw/source/core/layout/paintfrm.cxx index 1c9fde902730..dd76c8609fda 100644 --- a/sw/source/core/layout/paintfrm.cxx +++ b/sw/source/core/layout/paintfrm.cxx @@ -3782,6 +3782,7 @@ void SwColumnFrame::PaintBreak( ) const aTextMatrix, aBreakText, 0, aBreakText.getLength(), std::vector< double >(), + {}, std::move(aFontAttr), lang::Locale(), aLineColor ) ); diff --git a/sw/source/core/text/itradj.cxx b/sw/source/core/text/itradj.cxx index a952ce7649c2..b248f20f4785 100644 --- a/sw/source/core/text/itradj.cxx +++ b/sw/source/core/text/itradj.cxx @@ -122,7 +122,7 @@ static bool lcl_CheckKashidaPositions( SwScriptInfo& rSI, SwTextSizeInfo& rInf, // total number of kashida positions, or the number of kashida positions after some positions // have been dropped. // Here we want the clean total, which is OK: We have called ClearKashidaInvalid() before. - rKashidas = rSI.KashidaJustify(nullptr, rItr.GetStart(), rItr.GetLength()); + rKashidas = rSI.KashidaJustify(nullptr, nullptr, rItr.GetStart(), rItr.GetLength()); if (rKashidas <= 0) // nothing to do return true; @@ -147,7 +147,7 @@ static bool lcl_CheckKashidaPositions( SwScriptInfo& rSI, SwTextSizeInfo& rInf, if (nNext == TextFrameIndex(COMPLETE_STRING) || nNext > nEnd) nNext = nEnd; - sal_Int32 nKashidasInAttr = rSI.KashidaJustify(nullptr, nIdx, nNext - nIdx); + sal_Int32 nKashidasInAttr = rSI.KashidaJustify(nullptr, nullptr, nIdx, nNext - nIdx); if (nKashidasInAttr > 0) { // Kashida glyph looks suspicious, skip Kashida justification @@ -212,7 +212,7 @@ static bool lcl_CheckKashidaWidth ( SwScriptInfo& rSI, SwTextSizeInfo& rInf, SwT if (nNext == TextFrameIndex(COMPLETE_STRING) || nNext > nEnd) nNext = nEnd; - sal_Int32 nKashidasInAttr = rSI.KashidaJustify(nullptr, nIdx, nNext - nIdx); + sal_Int32 nKashidasInAttr = rSI.KashidaJustify(nullptr, nullptr, nIdx, nNext - nIdx); tools::Long nFontMinKashida = rInf.GetOut()->GetMinKashida(); if ( nFontMinKashida && nKashidasInAttr > 0 && SwScriptInfo::IsArabicText( rInf.GetText(), nIdx, nNext - nIdx ) ) diff --git a/sw/source/core/text/porlay.cxx b/sw/source/core/text/porlay.cxx index 30abc01703f1..3db6a07600e9 100644 --- a/sw/source/core/text/porlay.cxx +++ b/sw/source/core/text/porlay.cxx @@ -2231,6 +2231,7 @@ tools::Long SwScriptInfo::Compress(sal_Int32* pKernArray, TextFrameIndex nIdx, T // have been dropped, depending on the state of the m_KashidaInvalid set. sal_Int32 SwScriptInfo::KashidaJustify( sal_Int32* pKernArray, + sal_Bool* pKashidaArray, TextFrameIndex const nStt, TextFrameIndex const nLen, tools::Long nSpaceAdd ) const @@ -2286,6 +2287,11 @@ sal_Int32 SwScriptInfo::KashidaJustify( sal_Int32* pKernArray, { TextFrameIndex nArrayPos = nIdx - nStt; + // mark Kashida insertion positions, code in VCL will use this + // array to know where to insert Kashida. + if (pKashidaArray) + pKashidaArray[sal_Int32(nArrayPos)] = true; + // next kashida position ++nCntKash; while (nCntKash < nCntKashEnd && !IsKashidaValid(nCntKash)) diff --git a/sw/source/core/text/portxt.cxx b/sw/source/core/text/portxt.cxx index c0f66496f134..09a2fc2c0b67 100644 --- a/sw/source/core/text/portxt.cxx +++ b/sw/source/core/text/portxt.cxx @@ -113,7 +113,7 @@ static TextFrameIndex lcl_AddSpace(const SwTextSizeInfo &rInf, { if ( SwScriptInfo::IsArabicText( *pStr, nPos, nEnd - nPos ) && pSI->CountKashida() ) { - const sal_Int32 nKashRes = pSI->KashidaJustify(nullptr, nPos, nEnd - nPos); + const sal_Int32 nKashRes = pSI->KashidaJustify(nullptr, nullptr, nPos, nEnd - nPos); // i60591: need to check result of KashidaJustify // determine if kashida justification is applicable if (nKashRes != -1) diff --git a/sw/source/core/txtnode/fntcache.cxx b/sw/source/core/txtnode/fntcache.cxx index 4058f12a1492..88d9037a3eb1 100644 --- a/sw/source/core/txtnode/fntcache.cxx +++ b/sw/source/core/txtnode/fntcache.cxx @@ -951,7 +951,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) rInf.GetFrame()->SwitchHorizontalToVertical( aTextOriginPos ); rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(), - aKernArray, sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen())); + aKernArray, {}, sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen())); return; } @@ -980,6 +980,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) { std::vector aKernArray; GetTextArray(rInf.GetOut(), rInf, aKernArray); + std::vector aKashidaArray; if( bStretch ) { @@ -1050,13 +1051,16 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) { if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) ) { + aKashidaArray.resize(aKernArray.size(), false); if ( pSI && pSI->CountKashida() && - pSI->KashidaJustify( aKernArray.data(), rInf.GetIdx(), + pSI->KashidaJustify( aKernArray.data(), aKashidaArray.data(), rInf.GetIdx(), rInf.GetLen(), nSpaceAdd ) != -1 ) { bSpecialJust = true; nSpaceAdd = 0; } + else + aKashidaArray.clear(); } } @@ -1104,18 +1108,18 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) aKernArray[0] = rInf.GetWidth() + nSpaceAdd; rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(), - aKernArray, sal_Int32(rInf.GetIdx()), 1 ); + aKernArray, aKashidaArray, sal_Int32(rInf.GetIdx()), 1 ); } else { aKernArray[ sal_Int32(rInf.GetLen()) - 2 ] += nSpaceAdd; rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(), - aKernArray, sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen())); + aKernArray, aKashidaArray, sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen())); } } else rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(), - aKernArray, sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen())); + aKernArray, aKashidaArray, sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen())); } else { @@ -1209,6 +1213,8 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) GetTextArray(rInf.GetOut(), rInf, aKernArray); } + std::vector aKashidaArray; + // Modify Printer and ScreenArrays for special justifications tools::Long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR; @@ -1248,12 +1254,16 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) { if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) ) { + aKashidaArray.resize(aKernArray.size(), false); if ( pSI && pSI->CountKashida() && - pSI->KashidaJustify( aKernArray.data(), rInf.GetIdx(), + pSI->KashidaJustify( aKernArray.data(), aKashidaArray.data(), rInf.GetIdx(), rInf.GetLen(), nSpaceAdd ) != -1 ) nSpaceAdd = 0; else + { + aKashidaArray.clear(); bNoHalfSpace = true; + } } } @@ -1339,9 +1349,9 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) rInf.GetFrame()->SwitchHorizontalToVertical( aTextOriginPos ); rInf.GetOut().DrawTextArray( aTextOriginPos, rInf.GetText(), - aKernArray, sal_Int32(rInf.GetIdx()), 1 ); + aKernArray, aKashidaArray, sal_Int32(rInf.GetIdx()), 1 ); if( bBullet ) - rInf.GetOut().DrawTextArray( aTextOriginPos, *pStr, aKernArray, + rInf.GetOut().DrawTextArray( aTextOriginPos, *pStr, aKernArray, aKashidaArray, rInf.GetIdx() ? 1 : 0, 1 ); } else @@ -1464,7 +1474,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) : sal_Int32(rInf.GetIdx()); const SalLayoutGlyphs* pGlyphs = SalLayoutGlyphsCache::self()->GetLayoutGlyphs(&rInf.GetOut(), *pStr, nTmpIdx, nLen); - rInf.GetOut().DrawTextArray( aTextOriginPos, *pStr, aKernArray, + rInf.GetOut().DrawTextArray( aTextOriginPos, *pStr, aKernArray, aKashidaArray, nTmpIdx , nLen, SalLayoutFlags::NONE, pGlyphs ); if (bBullet) { @@ -1503,7 +1513,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) } } rInf.GetOut().DrawTextArray( aTextOriginPos, aBulletOverlay, aKernArray, - nTmpIdx , nLen ); + aKashidaArray, nTmpIdx , nLen ); pTmpFont->SetColor( aPreviousColor ); pTmpFont->SetUnderline(aPreviousUnderline); @@ -1738,7 +1748,7 @@ TextFrameIndex SwFntObj::GetModelPositionForViewPoint(SwDrawTextInfo &rInf) if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) ) { if ( pSI && pSI->CountKashida() && - pSI->KashidaJustify( aKernArray.data(), rInf.GetIdx(), rInf.GetLen(), + pSI->KashidaJustify( aKernArray.data(), nullptr, rInf.GetIdx(), rInf.GetLen(), nSpaceAdd ) != -1 ) nSpaceAdd = 0; } diff --git a/sw/source/uibase/docvw/HeaderFooterWin.cxx b/sw/source/uibase/docvw/HeaderFooterWin.cxx index cca26f41e78c..ba75b20ec3ff 100644 --- a/sw/source/uibase/docvw/HeaderFooterWin.cxx +++ b/sw/source/uibase/docvw/HeaderFooterWin.cxx @@ -319,7 +319,7 @@ void SwHeaderFooterWin::PaintButton() aSeq.push_back(drawinglayer::primitive2d::Primitive2DReference( new drawinglayer::primitive2d::TextSimplePortionPrimitive2D( aTextMatrix, m_sLabel, 0, m_sLabel.getLength(), - std::vector(), std::move(aFontAttr), css::lang::Locale(), aLineColor))); + std::vector(), {}, std::move(aFontAttr), css::lang::Locale(), aLineColor))); // Create the 'plus' or 'arrow' primitive B2DRectangle aSignArea(B2DPoint(aRect.Right() - BUTTON_WIDTH, 0.0), diff --git a/sw/source/uibase/docvw/UnfloatTableButton.cxx b/sw/source/uibase/docvw/UnfloatTableButton.cxx index 82320732c707..49bf9c660771 100644 --- a/sw/source/uibase/docvw/UnfloatTableButton.cxx +++ b/sw/source/uibase/docvw/UnfloatTableButton.cxx @@ -223,7 +223,7 @@ void UnfloatTableButton::PaintButton() aSeq.push_back(drawinglayer::primitive2d::Primitive2DReference( new drawinglayer::primitive2d::TextSimplePortionPrimitive2D( - aTextMatrix, m_sLabel, 0, m_sLabel.getLength(), std::vector(), + aTextMatrix, m_sLabel, 0, m_sLabel.getLength(), std::vector(), {}, std::move(aFontAttr), css::lang::Locale(), aLineColor))); // Create the processor and process the primitives diff --git a/vcl/inc/ImplLayoutArgs.hxx b/vcl/inc/ImplLayoutArgs.hxx index a94557afeb36..105a4e2d8961 100644 --- a/vcl/inc/ImplLayoutArgs.hxx +++ b/vcl/inc/ImplLayoutArgs.hxx @@ -37,6 +37,7 @@ public: // positioning related inputs const DeviceCoordinate* mpDXArray; // in integer pixel units const double* mpAltNaturalDXArray; // in floating point pixel units + const sal_Bool* mpKashidaArray; DeviceCoordinate mnLayoutWidth; // in pixel units Degree10 mnOrientation; // in 0-3600 system @@ -50,6 +51,7 @@ public: void SetLayoutWidth(DeviceCoordinate nWidth); void SetDXArray(const DeviceCoordinate* pDXArray); void SetAltNaturalDXArray(const double* pDXArray); + void SetKashidaArray(const sal_Bool* pKashidaArray); void SetOrientation(Degree10 nOrientation); void ResetPos(); diff --git a/vcl/inc/impglyphitem.hxx b/vcl/inc/impglyphitem.hxx index f0e4e70ef21c..f43ef0e99e61 100644 --- a/vcl/inc/impglyphitem.hxx +++ b/vcl/inc/impglyphitem.hxx @@ -37,7 +37,6 @@ enum class GlyphItemFlags : sal_uInt16 IS_DIACRITIC = 0x04, IS_VERTICAL = 0x08, IS_SPACING = 0x10, - ALLOW_KASHIDA = 0x20, IS_DROPPED = 0x40, IS_CLUSTER_START = 0x80, IS_UNSAFE_TO_BREAK = 0x100, // HB_GLYPH_FLAG_UNSAFE_TO_BREAK from harfbuzz @@ -45,7 +44,7 @@ enum class GlyphItemFlags : sal_uInt16 }; namespace o3tl { -template <> struct typed_flags : is_typed_flags +template <> struct typed_flags : is_typed_flags { }; }; @@ -82,7 +81,6 @@ public: bool IsDiacritic() const { return bool(m_nFlags & GlyphItemFlags::IS_DIACRITIC); } bool IsVertical() const { return bool(m_nFlags & GlyphItemFlags::IS_VERTICAL); } bool IsSpacing() const { return bool(m_nFlags & GlyphItemFlags::IS_SPACING); } - bool AllowKashida() const { return bool(m_nFlags & GlyphItemFlags::ALLOW_KASHIDA); } bool IsDropped() const { return bool(m_nFlags & GlyphItemFlags::IS_DROPPED); } bool IsClusterStart() const { return bool(m_nFlags & GlyphItemFlags::IS_CLUSTER_START); } bool IsUnsafeToBreak() const { return bool(m_nFlags & GlyphItemFlags::IS_UNSAFE_TO_BREAK); } diff --git a/vcl/inc/pdf/pdfwriter_impl.hxx b/vcl/inc/pdf/pdfwriter_impl.hxx index d718529476b9..4ebddbe5edaf 100644 --- a/vcl/inc/pdf/pdfwriter_impl.hxx +++ b/vcl/inc/pdf/pdfwriter_impl.hxx @@ -1188,7 +1188,7 @@ public: /* actual drawing functions */ void drawText( const Point& rPos, const OUString& rText, sal_Int32 nIndex, sal_Int32 nLen, bool bTextLines = true ); - void drawTextArray( const Point& rPos, const OUString& rText, o3tl::span pDXArray, sal_Int32 nIndex, sal_Int32 nLen ); + void drawTextArray( const Point& rPos, const OUString& rText, o3tl::span pDXArray, o3tl::span pKashidaArray, sal_Int32 nIndex, sal_Int32 nLen ); void drawStretchText( const Point& rPos, sal_uLong nWidth, const OUString& rText, sal_Int32 nIndex, sal_Int32 nLen ); void drawText( const tools::Rectangle& rRect, const OUString& rOrigStr, DrawTextFlags nStyle ); diff --git a/vcl/inc/sallayout.hxx b/vcl/inc/sallayout.hxx index 35f27ee20edf..885de2446db7 100644 --- a/vcl/inc/sallayout.hxx +++ b/vcl/inc/sallayout.hxx @@ -143,7 +143,7 @@ private: GenericSalLayout& operator=( const GenericSalLayout& ) = delete; template - void ApplyDXArray(const DC*, SalLayoutFlags nLayoutFlags); + void ApplyDXArray(const DC*, const sal_Bool*); void Justify(DeviceCoordinate nNewWidth); void ApplyAsianKerning(const OUString& rStr); diff --git a/vcl/qa/cppunit/complextext.cxx b/vcl/qa/cppunit/complextext.cxx index 9e96205946b1..ff85b14e33ef 100644 --- a/vcl/qa/cppunit/complextext.cxx +++ b/vcl/qa/cppunit/complextext.cxx @@ -49,14 +49,12 @@ public: /// Play with font measuring etc. void testArabic(); - void testKashida(); void testTdf95650(); // Windows-only issue void testCaching(); void testCachingSubstring(); CPPUNIT_TEST_SUITE(VclComplexTextTest); CPPUNIT_TEST(testArabic); - CPPUNIT_TEST(testKashida); CPPUNIT_TEST(testTdf95650); CPPUNIT_TEST(testCaching); CPPUNIT_TEST(testCachingSubstring); @@ -114,31 +112,6 @@ void VclComplexTextTest::testArabic() #endif } -void VclComplexTextTest::testKashida() -{ -#if HAVE_MORE_FONTS - // Cache the glyph list of some Arabic text. - ScopedVclPtrInstance pOutputDevice; - auto aText - = OUString(u"عنصر الفوسفور عنصر فلزي صلب. تتكون الدورة الرابعة من 15 عنصرا."); - std::unique_ptr pLayout = pOutputDevice->ImplLayout( - aText, 0, aText.getLength(), Point(0, 0), 0, {}, SalLayoutFlags::GlyphItemsOnly); - SalLayoutGlyphs aGlyphs = pLayout->GetGlyphs(); - CPPUNIT_ASSERT(aGlyphs.IsValid()); - CPPUNIT_ASSERT(aGlyphs.Impl(0) != nullptr); - - // Now lay it out using the cached glyph list. - vcl::text::ImplLayoutArgs aLayoutArgs(aText, 0, aText.getLength(), SalLayoutFlags::NONE, - pOutputDevice->GetFont().GetLanguageTag(), nullptr); - pLayout = pOutputDevice->GetGraphics()->GetTextLayout(0); - CPPUNIT_ASSERT(pLayout->LayoutText(aLayoutArgs, aGlyphs.Impl(0))); - - // Without the accompanying fix in place, this test would have failed with 'assertion failed'. - // The kashida justification flag was lost when going via the glyph cache. - CPPUNIT_ASSERT(aLayoutArgs.mnFlags & SalLayoutFlags::KashidaJustification); -#endif -} - void VclComplexTextTest::testTdf95650() { static constexpr OUStringLiteral aTxt = @@ -152,7 +125,7 @@ void VclComplexTextTest::testTdf95650() OutputDevice *pOutDev = pWin->GetOutDev(); // Check that the following executes without failing assertion - pOutDev->ImplLayout(aTxt, 9, 1, Point(), 0, {}, SalLayoutFlags::BiDiRtl); + pOutDev->ImplLayout(aTxt, 9, 1, Point(), 0, {}, {}, SalLayoutFlags::BiDiRtl); } static void checkCompareGlyphs( const SalLayoutGlyphs& aGlyphs1, const SalLayoutGlyphs& aGlyphs2, @@ -190,11 +163,11 @@ static void testCachedGlyphs( const OUString& aText, const OUString& aFontName ) SalLayoutGlyphsCache::self()->clear(); // Get the glyphs for the text. std::unique_ptr pLayout1 = pOutputDevice->ImplLayout( - aText, 0, aText.getLength(), Point(0, 0), 0, {}, SalLayoutFlags::GlyphItemsOnly); + aText, 0, aText.getLength(), Point(0, 0), 0, {}, {}, SalLayoutFlags::GlyphItemsOnly); SalLayoutGlyphs aGlyphs1 = pLayout1->GetGlyphs(); // Reuse the cached glyphs to get glyphs again. std::unique_ptr pLayout2 = pOutputDevice->ImplLayout( - aText, 0, aText.getLength(), Point(0, 0), 0, {}, SalLayoutFlags::GlyphItemsOnly, nullptr, &aGlyphs1); + aText, 0, aText.getLength(), Point(0, 0), 0, {}, {}, SalLayoutFlags::GlyphItemsOnly, nullptr, &aGlyphs1); SalLayoutGlyphs aGlyphs2 = pLayout2->GetGlyphs(); checkCompareGlyphs(aGlyphs1, aGlyphs2, message + " (reuse)"); // Get cached glyphs from SalLayoutGlyphsCache. @@ -228,7 +201,7 @@ static void testCachedGlyphsSubstring( const OUString& aText, const OUString& aF SalLayoutGlyphsCache::self()->clear(); std::shared_ptr layoutCache = OutputDevice::CreateTextLayoutCache(aText); // Get the glyphs for the entire text once, to ensure the cache can built subsets from it. - pOutputDevice->ImplLayout( aText, 0, aText.getLength(), Point(0, 0), 0, {}, SalLayoutFlags::GlyphItemsOnly, + pOutputDevice->ImplLayout( aText, 0, aText.getLength(), Point(0, 0), 0, {}, {}, SalLayoutFlags::GlyphItemsOnly, layoutCache.get()); // Now check for all subsets. Some of them possibly do not make sense in practice, but the code // should cope with them. @@ -237,7 +210,7 @@ static void testCachedGlyphsSubstring( const OUString& aText, const OUString& aF { std::string message = prefix + " (" + std::to_string(pos) + "/" + std::to_string(len) + ")"; std::unique_ptr pLayout1 = pOutputDevice->ImplLayout( - aText, pos, len, Point(0, 0), 0, {}, SalLayoutFlags::GlyphItemsOnly, layoutCache.get()); + aText, pos, len, Point(0, 0), 0, {}, {}, SalLayoutFlags::GlyphItemsOnly, layoutCache.get()); SalLayoutGlyphs aGlyphs1 = pLayout1->GetGlyphs(); const SalLayoutGlyphs* aGlyphs2 = SalLayoutGlyphsCache::self()->GetLayoutGlyphs( pOutputDevice, aText, pos, len, 0, layoutCache.get()); diff --git a/vcl/qa/cppunit/svm/svmtest.cxx b/vcl/qa/cppunit/svm/svmtest.cxx index fcea61afb5a9..2f4f17d7beb4 100644 --- a/vcl/qa/cppunit/svm/svmtest.cxx +++ b/vcl/qa/cppunit/svm/svmtest.cxx @@ -860,7 +860,7 @@ void SvmTest::testTextArray() ScopedVclPtrInstance pVirtualDev; setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); sal_Int32 const aDX[] = { 10, 15, 20, 25, 30, 35 }; - pVirtualDev->DrawTextArray(Point(4,6), "123456", aDX, 1, 4); + pVirtualDev->DrawTextArray(Point(4,6), "123456", aDX, {}, 1, 4); checkTextArray(writeAndReadStream(aGDIMetaFile)); checkTextArray(readFile(u"textarray.svm")); diff --git a/vcl/qa/cppunit/text.cxx b/vcl/qa/cppunit/text.cxx index 668e84ef2aad..7a73ee3bc6e2 100644 --- a/vcl/qa/cppunit/text.cxx +++ b/vcl/qa/cppunit/text.cxx @@ -702,7 +702,7 @@ void VclTextTest::testImplLayoutArgs_PrepareFallback_precalculatedglyphs() const OString sUTF8String(u8"Тхе яуицк\n ыумпед овер"); const OUString sTestString(OUString::fromUtf8(sUTF8String)); std::unique_ptr pLayout - = pVirDev->ImplLayout(sTestString, 0, sTestString.getLength(), Point(0, 0), 0, {}, + = pVirDev->ImplLayout(sTestString, 0, sTestString.getLength(), Point(0, 0), 0, {}, {}, SalLayoutFlags::GlyphItemsOnly); SalLayoutGlyphs aGlyphs = pLayout->GetGlyphs(); SalLayoutGlyphsImpl* pGlyphsImpl = aGlyphs.Impl(1); diff --git a/vcl/source/control/imp_listbox.cxx b/vcl/source/control/imp_listbox.cxx index 911770678667..fbd655eb04dd 100644 --- a/vcl/source/control/imp_listbox.cxx +++ b/vcl/source/control/imp_listbox.cxx @@ -590,7 +590,7 @@ SalLayoutGlyphs* ImplEntryType::GetTextGlyphs(const OutputDevice* pOutputDevice) return &maStrGlyphs; std::unique_ptr pLayout = pOutputDevice->ImplLayout( - maStr, 0, maStr.getLength(), Point(0, 0), 0, {}, SalLayoutFlags::GlyphItemsOnly); + maStr, 0, maStr.getLength(), Point(0, 0), 0, {}, {}, SalLayoutFlags::GlyphItemsOnly); if (!pLayout) return nullptr; diff --git a/vcl/source/filter/eps/eps.cxx b/vcl/source/filter/eps/eps.cxx index bb25bdccb57e..797d6b887efc 100644 --- a/vcl/source/filter/eps/eps.cxx +++ b/vcl/source/filter/eps/eps.cxx @@ -201,7 +201,7 @@ private: void ImplSetClipRegion( vcl::Region const & rRegion ); void ImplBmp( Bitmap const *, Bitmap const *, const Point &, double nWidth, double nHeight ); - void ImplText( const OUString& rUniString, const Point& rPos, o3tl::span pDXArry, sal_Int32 nWidth, VirtualDevice const & rVDev ); + void ImplText( const OUString& rUniString, const Point& rPos, o3tl::span pDXArry, o3tl::span pKashidaArry, sal_Int32 nWidth, VirtualDevice const & rVDev ); void ImplSetAttrForText( const Point & rPoint ); void ImplWriteCharacter( char ); void ImplWriteString( const OString&, VirtualDevice const & rVDev, o3tl::span pDXArry, bool bStretch ); @@ -748,7 +748,7 @@ void PSWriter::ImplWriteActions( const GDIMetaFile& rMtf, VirtualDevice& rVDev ) OUString aUniStr = pA->GetText().copy( pA->GetIndex(), pA->GetLen() ); Point aPoint( pA->GetPoint() ); - ImplText( aUniStr, aPoint, {}, 0, rVDev ); + ImplText( aUniStr, aPoint, {}, {}, 0, rVDev ); } break; @@ -764,7 +764,7 @@ void PSWriter::ImplWriteActions( const GDIMetaFile& rMtf, VirtualDevice& rVDev ) OUString aUniStr = pA->GetText().copy( pA->GetIndex(), pA->GetLen() ); Point aPoint( pA->GetPoint() ); - ImplText( aUniStr, aPoint, {}, pA->GetWidth(), rVDev ); + ImplText( aUniStr, aPoint, {}, {}, pA->GetWidth(), rVDev ); } break; @@ -774,7 +774,7 @@ void PSWriter::ImplWriteActions( const GDIMetaFile& rMtf, VirtualDevice& rVDev ) OUString aUniStr = pA->GetText().copy( pA->GetIndex(), pA->GetLen() ); Point aPoint( pA->GetPoint() ); - ImplText( aUniStr, aPoint, pA->GetDXArray(), 0, rVDev ); + ImplText( aUniStr, aPoint, pA->GetDXArray(), pA->GetKashidaArray(), 0, rVDev ); } break; @@ -1988,7 +1988,7 @@ void PSWriter::ImplWriteString( const OString& rString, VirtualDevice const & rV } } -void PSWriter::ImplText( const OUString& rUniString, const Point& rPos, o3tl::span pDXArry, sal_Int32 nWidth, VirtualDevice const & rVDev ) +void PSWriter::ImplText( const OUString& rUniString, const Point& rPos, o3tl::span pDXArry, o3tl::span pKashidaArry, sal_Int32 nWidth, VirtualDevice const & rVDev ) { if ( rUniString.isEmpty() ) return; @@ -2015,7 +2015,7 @@ void PSWriter::ImplText( const OUString& rUniString, const Point& rPos, o3tl::sp bool bOldLineColor = bLineColor; bLineColor = false; std::vector aPolyPolyVec; - if ( pVirDev->GetTextOutlines( aPolyPolyVec, rUniString, 0, 0, -1, nWidth, pDXArry ) ) + if ( pVirDev->GetTextOutlines( aPolyPolyVec, rUniString, 0, 0, -1, nWidth, pDXArry, pKashidaArry ) ) { // always adjust text position to match baseline alignment ImplWriteLine( "pum" ); diff --git a/vcl/source/filter/svm/SvmConverter.cxx b/vcl/source/filter/svm/SvmConverter.cxx index 4127d132557e..efc036cc264a 100644 --- a/vcl/source/filter/svm/SvmConverter.cxx +++ b/vcl/source/filter/svm/SvmConverter.cxx @@ -809,7 +809,7 @@ void SVMConverter::ImplConvertFromSVM1( SvStream& rIStm, GDIMetaFile& rMtf ) if ( nUnicodeCommentActionNumber == i ) ImplReadUnicodeComment( nUnicodeCommentStreamPos, rIStm, aStr ); ClampRange(aStr, nIndex, nLen, &aDXAry); - rMtf.AddAction( new MetaTextArrayAction( aPt, aStr, std::move(aDXAry), nIndex, nLen ) ); + rMtf.AddAction( new MetaTextArrayAction( aPt, aStr, std::move(aDXAry), {}, nIndex, nLen ) ); } if (nActionSize < 24) diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index 98364d4ae443..da7334352858 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -197,9 +197,9 @@ void GenericSalLayout::AdjustLayout(vcl::text::ImplLayoutArgs& rArgs) SalLayout::AdjustLayout(rArgs); if (rArgs.mpAltNaturalDXArray) // Used when "TextRenderModeForResolutionIndependentLayout" is set - ApplyDXArray(rArgs.mpAltNaturalDXArray, rArgs.mnFlags); + ApplyDXArray(rArgs.mpAltNaturalDXArray, rArgs.mpKashidaArray); else if (rArgs.mpDXArray) // Normal case - ApplyDXArray(rArgs.mpDXArray, rArgs.mnFlags); + ApplyDXArray(rArgs.mpDXArray, rArgs.mpKashidaArray); else if (rArgs.mnLayoutWidth) Justify(rArgs.mnLayoutWidth); // apply asian kerning if the glyphs are not already formatted @@ -565,14 +565,6 @@ bool GenericSalLayout::LayoutText(vcl::text::ImplLayoutArgs& rArgs, const SalLay if (u_isUWhiteSpace(aChar)) nGlyphFlags |= GlyphItemFlags::IS_SPACING; - if (aSubRun.maScript == HB_SCRIPT_ARABIC && - HB_DIRECTION_IS_BACKWARD(aSubRun.maDirection) && - !(nGlyphFlags & GlyphItemFlags::IS_SPACING)) - { - nGlyphFlags |= GlyphItemFlags::ALLOW_KASHIDA; - rArgs.mnFlags |= SalLayoutFlags::KashidaJustification; - } - #if HB_VERSION_ATLEAST(1, 5, 0) if (hb_glyph_info_get_glyph_flags(&pHbGlyphInfos[i]) & HB_GLYPH_FLAG_UNSAFE_TO_BREAK) nGlyphFlags |= GlyphItemFlags::IS_UNSAFE_TO_BREAK; @@ -657,24 +649,12 @@ void GenericSalLayout::GetCharWidths(std::vector& rCharWidths) } } -// A note on how Kashida justification is implemented (because it took me 5 -// years to figure it out): -// The decision to insert Kashidas, where and how much is taken by Writer. -// This decision is communicated to us in a very indirect way; by increasing -// the width of the character after which Kashidas should be inserted by the -// desired amount. -// -// Writer eventually calls IsKashidaPosValid() to check whether it can insert a -// Kashida between two characters or not. -// -// Here we do: -// - In LayoutText() set KashidaJustification flag based on text script. -// - In ApplyDXArray(): -// * Check the above flag to decide whether to insert Kashidas or not. -// * For any RTL glyph that has DX adjustment, insert enough Kashidas to -// fill in the added space. +// - pDXArray: is the adjustments to glyph advances (usually due to +// justification). +// - pKashidaArray: is the places where kashidas are inserted (for Arabic +// justification). The number of kashidas is calculated from the pDXArray. template -void GenericSalLayout::ApplyDXArray(const DC* pDXArray, SalLayoutFlags nLayoutFlags) +void GenericSalLayout::ApplyDXArray(const DC* pDXArray, const sal_Bool* pKashidaArray) { int nCharCount = mnEndCharPos - mnMinCharPos; std::vector aOldCharWidths; @@ -692,18 +672,6 @@ void GenericSalLayout::ApplyDXArray(const DC* pDXArray, SalLayoutFlags nLayoutFl pNewCharWidths[i] = pDXArray[i] - pDXArray[i - 1]; } - bool bKashidaJustify = false; - DeviceCoordinate nKashidaWidth = 0; - hb_codepoint_t nKashidaIndex = 0; - if (nLayoutFlags & SalLayoutFlags::KashidaJustification) - { - hb_font_t *pHbFont = GetFont().GetHbFont(); - // Find Kashida glyph width and index. - if (hb_font_get_glyph(pHbFont, 0x0640, 0, &nKashidaIndex)) - nKashidaWidth = GetFont().GetKashidaWidth(); - bKashidaJustify = nKashidaWidth != 0; - } - // Map of Kashida insertion points (in the glyph items vector) and the // requested width. std::map pKashidas; @@ -743,15 +711,15 @@ void GenericSalLayout::ApplyDXArray(const DC* pDXArray, SalLayoutFlags nLayoutFl // loop below. i++; } - else + else // RTL { // Adjust the width and position of the first (rightmost) glyph in - // the cluster. - // For RTL, we put all the adjustment to the left of the glyph. + // the cluster. This is RTL, so we put all the adjustment to the + // left of the glyph. m_GlyphItems[i].addNewWidth(nDiff); m_GlyphItems[i].adjustLinearPosX(nDelta + nDiff); - // Adjust the X position of all glyphs in the cluster. + // Adjust the X position of the rest of the glyphs in the cluster. size_t j = i; while (j > 0) { @@ -761,36 +729,44 @@ void GenericSalLayout::ApplyDXArray(const DC* pDXArray, SalLayoutFlags nLayoutFl m_GlyphItems[j].adjustLinearPosX(nDelta + nDiff); } - // If this glyph is Kashida-justifiable, then mark this as a - // Kashida position. Since this must be a RTL glyph, we mark the - // last glyph in the cluster not the first as this would be the - // base glyph. - if (bKashidaJustify && m_GlyphItems[i].AllowKashida() && - nDiff > m_GlyphItems[i].charCount()) // Rounding errors, 1 pixel per character! + // Move any non-spacing marks to keep attached to this cluster. + while (j > 0) { - pKashidas[i] = nDiff; - // Move any non-spacing marks attached to this cluster as well. - // Looping backward because this is RTL glyph. - while (j > 0) - { - if (!m_GlyphItems[j].IsDiacritic()) - break; - m_GlyphItems[j--].adjustLinearPosX(nDiff); - } + if (!m_GlyphItems[j].IsDiacritic()) + break; + m_GlyphItems[j--].adjustLinearPosX(nDiff); } + + // This is a Kashida insertion position, mark it. Kashida glyphs + // will be inserted below. + if (pKashidaArray && pKashidaArray[nCharPos]) + pKashidas[i] = nDiff; + i++; } // Increment the delta, the loop above makes sure we do so only once // for every character (cluster) not for every glyph (otherwise we - // would apply it multiple times for each glyphs belonging to the same - // character which is wrong since DX adjustments are character based). + // would apply it multiple times for each glyph belonging to the same + // character which is wrong as DX adjustments are character based). nDelta += nDiff; } // Insert Kashida glyphs. - if (!bKashidaJustify || pKashidas.empty()) + if (pKashidas.empty()) + return; + + // Find Kashida glyph width and index. + DeviceCoordinate nKashidaWidth = 0; + hb_codepoint_t nKashidaIndex = 0; + if (hb_font_get_glyph(GetFont().GetHbFont(), 0x0640, 0, &nKashidaIndex)) + nKashidaWidth = GetFont().GetKashidaWidth(); + + if (nKashidaWidth <= 0) + { + SAL_WARN("vcl.gdi", "Asked to insert Kashidas in a font with zero-width Kashida"); return; + } size_t nInserted = 0; for (auto const& pKashida : pKashidas) diff --git a/vcl/source/gdi/gdimtf.cxx b/vcl/source/gdi/gdimtf.cxx index 4d889f6d54d0..e15cf05b9cf5 100644 --- a/vcl/source/gdi/gdimtf.cxx +++ b/vcl/source/gdi/gdimtf.cxx @@ -978,7 +978,7 @@ void GDIMetaFile::Rotate( Degree10 nAngle10 ) { MetaTextArrayAction* pAct = static_cast(pAction); aMtf.AddAction( new MetaTextArrayAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ), - pAct->GetText(), pAct->GetDXArray(), pAct->GetIndex(), pAct->GetLen() ) ); + pAct->GetText(), pAct->GetDXArray(), pAct->GetKashidaArray(), pAct->GetIndex(), pAct->GetLen() ) ); } break; @@ -1452,7 +1452,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& i_rReference ) const tools::Rectangle aRect; // hdu said base = index aMapVDev->GetTextBoundRect( aRect, pAct->GetText(), pAct->GetIndex(), pAct->GetIndex(), pAct->GetLen(), - 0, pAct->GetDXArray() ); + 0, pAct->GetDXArray(), pAct->GetKashidaArray() ); Point aPt( pAct->GetPoint() ); aRect.Move( aPt.X(), aPt.Y() ); ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack ); diff --git a/vcl/source/gdi/impglyphitem.cxx b/vcl/source/gdi/impglyphitem.cxx index 51bff5966d32..6cbb245e922b 100644 --- a/vcl/source/gdi/impglyphitem.cxx +++ b/vcl/source/gdi/impglyphitem.cxx @@ -297,27 +297,6 @@ static SalLayoutGlyphs makeGlyphsSubset(const SalLayoutGlyphs& source, // would assert on flags being different. cloned->SetFlags(cloned->GetFlags() | outputDevice->GetBiDiLayoutFlags(text, index, index + len)); - // SalLayoutFlags::KashidaJustification is set only if any glyph - // in the range has GlyphItemFlags::ALLOW_KASHIDA (otherwise unset it). - if (cloned->GetFlags() & SalLayoutFlags::KashidaJustification) - { - bool hasKashida = false; - for (const GlyphItem& item : *cloned) - { - if (item.AllowKashida()) - { - hasKashida = true; - break; - } - } - if (!hasKashida) - cloned->SetFlags(cloned->GetFlags() & ~SalLayoutFlags::KashidaJustification); - } -#ifdef DBG_UTIL - else - for (const GlyphItem& item : *cloned) - assert(!item.AllowKashida()); -#endif ret.AppendImpl(cloned); } return ret; @@ -433,7 +412,7 @@ SalLayoutGlyphsCache::GetLayoutGlyphs(VclPtr outputDevice, c // Check if the subset result really matches what we would get normally, // to make sure corner cases are handled well (see SalLayoutGlyphsImpl::cloneCharRange()). std::unique_ptr layout - = outputDevice->ImplLayout(text, nIndex, nLen, Point(0, 0), nLogicWidth, {}, + = outputDevice->ImplLayout(text, nIndex, nLen, Point(0, 0), nLogicWidth, {}, {}, SalLayoutFlags::GlyphItemsOnly, layoutCache); assert(layout); checkGlyphsEqual(mLastTemporaryGlyphs, layout->GetGlyphs()); @@ -458,7 +437,7 @@ SalLayoutGlyphsCache::GetLayoutGlyphs(VclPtr outputDevice, c layoutCache = tmpLayoutCache.get(); } std::unique_ptr layout - = outputDevice->ImplLayout(text, nIndex, nLen, Point(0, 0), nLogicWidth, {}, + = outputDevice->ImplLayout(text, nIndex, nLen, Point(0, 0), nLogicWidth, {}, {}, SalLayoutFlags::GlyphItemsOnly, layoutCache); if (layout) { diff --git a/vcl/source/gdi/metaact.cxx b/vcl/source/gdi/metaact.cxx index 4d6705e39115..cd06b016d4be 100644 --- a/vcl/source/gdi/metaact.cxx +++ b/vcl/source/gdi/metaact.cxx @@ -601,6 +601,7 @@ MetaTextArrayAction::MetaTextArrayAction( const MetaTextArrayAction& rAction ) : maStartPt ( rAction.maStartPt ), maStr ( rAction.maStr ), maDXAry ( rAction.maDXAry ), + maKashidaAry( rAction.maKashidaAry ), mnIndex ( rAction.mnIndex ), mnLen ( rAction.mnLen ) { @@ -609,12 +610,14 @@ MetaTextArrayAction::MetaTextArrayAction( const MetaTextArrayAction& rAction ) : MetaTextArrayAction::MetaTextArrayAction( const Point& rStartPt, OUString aStr, std::vector aDXAry, + std::vector aKashidaAry, sal_Int32 nIndex, sal_Int32 nLen ) : MetaAction ( MetaActionType::TEXTARRAY ), maStartPt ( rStartPt ), maStr (std::move( aStr )), maDXAry (std::move( aDXAry )), + maKashidaAry(std::move( aKashidaAry )), mnIndex ( nIndex ), mnLen ( nLen ) { @@ -623,12 +626,14 @@ MetaTextArrayAction::MetaTextArrayAction( const Point& rStartPt, MetaTextArrayAction::MetaTextArrayAction( const Point& rStartPt, OUString aStr, o3tl::span pDXAry, + o3tl::span pKashidaAry, sal_Int32 nIndex, sal_Int32 nLen ) : MetaAction ( MetaActionType::TEXTARRAY ), maStartPt ( rStartPt ), maStr (std::move( aStr )), maDXAry ( pDXAry.begin(), pDXAry.end() ), + maKashidaAry( pKashidaAry.begin(), pKashidaAry.end() ), mnIndex ( nIndex ), mnLen ( nLen ) { @@ -640,7 +645,7 @@ MetaTextArrayAction::~MetaTextArrayAction() void MetaTextArrayAction::Execute( OutputDevice* pOut ) { - pOut->DrawTextArray( maStartPt, maStr, maDXAry, mnIndex, mnLen ); + pOut->DrawTextArray( maStartPt, maStr, maDXAry, maKashidaAry, mnIndex, mnLen ); } rtl::Reference MetaTextArrayAction::Clone() const @@ -669,6 +674,11 @@ void MetaTextArrayAction::SetDXArray(std::vector aArray) maDXAry = std::move(aArray); } +void MetaTextArrayAction::SetKashidaArray(std::vector aArray) +{ + maKashidaAry = std::move(aArray); +} + MetaStretchTextAction::MetaStretchTextAction() : MetaAction ( MetaActionType::STRETCHTEXT ), mnWidth ( 0 ), diff --git a/vcl/source/gdi/pdfwriter.cxx b/vcl/source/gdi/pdfwriter.cxx index 1a8d407c7247..3e20c12f2720 100644 --- a/vcl/source/gdi/pdfwriter.cxx +++ b/vcl/source/gdi/pdfwriter.cxx @@ -82,10 +82,11 @@ void PDFWriter::DrawTextArray( const Point& rStartPt, const OUString& rStr, o3tl::span pDXAry, + o3tl::span pKashidaAry, sal_Int32 nIndex, sal_Int32 nLen ) { - xImplementation->drawTextArray( rStartPt, rStr, pDXAry, nIndex, nLen ); + xImplementation->drawTextArray( rStartPt, rStr, pDXAry, pKashidaAry, nIndex, nLen ); } void PDFWriter::DrawStretchText( diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index f16bdc090f03..f0413d635a54 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -6616,14 +6616,14 @@ void PDFWriterImpl::drawText( const Point& rPos, const OUString& rText, sal_Int3 const SalLayoutGlyphs* layoutGlyphs = SalLayoutGlyphsCache::self()-> GetLayoutGlyphs( this, rText, nIndex, nLen ); std::unique_ptr pLayout = ImplLayout( rText, nIndex, nLen, rPos, - 0, {}, SalLayoutFlags::NONE, nullptr, layoutGlyphs ); + 0, {}, {}, SalLayoutFlags::NONE, nullptr, layoutGlyphs ); if( pLayout ) { drawLayout( *pLayout, rText, bTextLines ); } } -void PDFWriterImpl::drawTextArray( const Point& rPos, const OUString& rText, o3tl::span pDXArray, sal_Int32 nIndex, sal_Int32 nLen ) +void PDFWriterImpl::drawTextArray( const Point& rPos, const OUString& rText, o3tl::span pDXArray, o3tl::span pKashidaArray, sal_Int32 nIndex, sal_Int32 nLen ) { MARK( "drawText with array" ); @@ -6633,7 +6633,7 @@ void PDFWriterImpl::drawTextArray( const Point& rPos, const OUString& rText, o3t // this also enforces font substitution and sets the font on SalGraphics const SalLayoutGlyphs* layoutGlyphs = SalLayoutGlyphsCache::self()-> GetLayoutGlyphs( this, rText, nIndex, nLen ); - std::unique_ptr pLayout = ImplLayout( rText, nIndex, nLen, rPos, 0, pDXArray, + std::unique_ptr pLayout = ImplLayout( rText, nIndex, nLen, rPos, 0, pDXArray, pKashidaArray, SalLayoutFlags::NONE, nullptr, layoutGlyphs ); if( pLayout ) { @@ -6652,7 +6652,7 @@ void PDFWriterImpl::drawStretchText( const Point& rPos, sal_uLong nWidth, const const SalLayoutGlyphs* layoutGlyphs = SalLayoutGlyphsCache::self()-> GetLayoutGlyphs( this, rText, nIndex, nLen, nWidth ); std::unique_ptr pLayout = ImplLayout( rText, nIndex, nLen, rPos, nWidth, - {}, SalLayoutFlags::NONE, nullptr, layoutGlyphs ); + {}, {}, SalLayoutFlags::NONE, nullptr, layoutGlyphs ); if( pLayout ) { drawLayout( *pLayout, rText, true ); diff --git a/vcl/source/gdi/pdfwriter_impl2.cxx b/vcl/source/gdi/pdfwriter_impl2.cxx index f4c60a661684..cac3813cdedc 100644 --- a/vcl/source/gdi/pdfwriter_impl2.cxx +++ b/vcl/source/gdi/pdfwriter_impl2.cxx @@ -813,7 +813,7 @@ void PDFWriterImpl::playMetafile( const GDIMetaFile& i_rMtf, vcl::PDFExtOutDevDa case MetaActionType::TEXTARRAY: { const MetaTextArrayAction* pA = static_cast(pAction); - m_rOuterFace.DrawTextArray( pA->GetPoint(), pA->GetText(), pA->GetDXArray(), pA->GetIndex(), pA->GetLen() ); + m_rOuterFace.DrawTextArray( pA->GetPoint(), pA->GetText(), pA->GetDXArray(), pA->GetKashidaArray(), pA->GetIndex(), pA->GetLen() ); } break; diff --git a/vcl/source/gdi/textlayout.cxx b/vcl/source/gdi/textlayout.cxx index 416c68343f47..25bf47767ec7 100644 --- a/vcl/source/gdi/textlayout.cxx +++ b/vcl/source/gdi/textlayout.cxx @@ -209,7 +209,7 @@ namespace vcl std::vector aCharWidths; tools::Long nTextWidth = GetTextArray( _rText, &aCharWidths, _nStartIndex, _nLength ); - m_rTargetDevice.DrawTextArray( _rStartPoint, _rText, aCharWidths, _nStartIndex, _nLength ); + m_rTargetDevice.DrawTextArray( _rStartPoint, _rText, aCharWidths, {}, _nStartIndex, _nLength ); m_aCompleteTextRect.Union( tools::Rectangle( _rStartPoint, Size( nTextWidth, m_rTargetDevice.GetTextHeight() ) ) ); } diff --git a/vcl/source/outdev/text.cxx b/vcl/source/outdev/text.cxx index 2f7199fa3fa3..06f43fa2d3ea 100644 --- a/vcl/source/outdev/text.cxx +++ b/vcl/source/outdev/text.cxx @@ -872,7 +872,7 @@ void OutputDevice::DrawText( const Point& rStartPt, const OUString& rStr, if(mpFontInstance->mpConversion) pLayoutCache = nullptr; - std::unique_ptr pSalLayout = ImplLayout(rStr, nIndex, nLen, rStartPt, 0, {}, eDefaultLayout, nullptr, pLayoutCache); + std::unique_ptr pSalLayout = ImplLayout(rStr, nIndex, nLen, rStartPt, 0, {}, {}, eDefaultLayout, nullptr, pLayoutCache); if(pSalLayout) { ImplDrawText( *pSalLayout ); @@ -921,6 +921,7 @@ float OutputDevice::approximate_digit_width() const void OutputDevice::DrawTextArray( const Point& rStartPt, const OUString& rStr, o3tl::span pDXAry, + o3tl::span pKashidaAry, sal_Int32 nIndex, sal_Int32 nLen, SalLayoutFlags flags, const SalLayoutGlyphs* pSalLayoutCache ) { @@ -931,7 +932,7 @@ void OutputDevice::DrawTextArray( const Point& rStartPt, const OUString& rStr, nLen = rStr.getLength() - nIndex; } if ( mpMetaFile ) - mpMetaFile->AddAction( new MetaTextArrayAction( rStartPt, rStr, pDXAry, nIndex, nLen ) ); + mpMetaFile->AddAction( new MetaTextArrayAction( rStartPt, rStr, pDXAry, pKashidaAry, nIndex, nLen ) ); if ( !IsDeviceOutputNecessary() ) return; @@ -943,14 +944,14 @@ void OutputDevice::DrawTextArray( const Point& rStartPt, const OUString& rStr, if( mbOutputClipped ) return; - std::unique_ptr pSalLayout = ImplLayout(rStr, nIndex, nLen, rStartPt, 0, pDXAry, flags, nullptr, pSalLayoutCache); + std::unique_ptr pSalLayout = ImplLayout(rStr, nIndex, nLen, rStartPt, 0, pDXAry, pKashidaAry, flags, nullptr, pSalLayoutCache); if( pSalLayout ) { ImplDrawText( *pSalLayout ); } if( mpAlphaVDev ) - mpAlphaVDev->DrawTextArray( rStartPt, rStr, pDXAry, nIndex, nLen, flags ); + mpAlphaVDev->DrawTextArray( rStartPt, rStr, pDXAry, pKashidaAry, nIndex, nLen, flags ); } tools::Long OutputDevice::GetTextArray( const OUString& rStr, std::vector* pDXAry, @@ -968,7 +969,7 @@ tools::Long OutputDevice::GetTextArray( const OUString& rStr, std::vector pSalLayout = ImplLayout(rStr, nIndex, nLen, - Point(0,0), 0, {}, eDefaultLayout, pLayoutCache, pSalLayoutCache); + Point(0,0), 0, {}, {}, eDefaultLayout, pLayoutCache, pSalLayoutCache); if( !pSalLayout ) { // The caller expects this to init the elements of pDXAry. @@ -1076,7 +1077,7 @@ void OutputDevice::GetCaretPositions( const OUString& rStr, sal_Int32* pCaretXAr nLen = rStr.getLength() - nIndex; // layout complex text - std::unique_ptr pSalLayout = ImplLayout(rStr, nIndex, nLen, Point(0, 0), 0, {}, + std::unique_ptr pSalLayout = ImplLayout(rStr, nIndex, nLen, Point(0, 0), 0, {}, {}, eDefaultLayout, nullptr, pGlyphs); if( !pSalLayout ) { @@ -1312,7 +1313,9 @@ OutputDevice::FontMappingUseData OutputDevice::FinishTrackingFontMappingUse() std::unique_ptr OutputDevice::ImplLayout(const OUString& rOrigStr, sal_Int32 nMinIndex, sal_Int32 nLen, const Point& rLogicalPos, tools::Long nLogicalWidth, - o3tl::span pDXArray, SalLayoutFlags flags, + o3tl::span pDXArray, + o3tl::span pKashidaArray, + SalLayoutFlags flags, vcl::text::TextLayoutCache const* pLayoutCache, const SalLayoutGlyphs* pGlyphs) const { @@ -1427,6 +1430,9 @@ std::unique_ptr OutputDevice::ImplLayout(const OUString& rOrigStr, } } + if (!pKashidaArray.empty()) + aLayoutArgs.SetKashidaArray(pKashidaArray.data()); + // get matching layout object for base font std::unique_ptr pSalLayout = mpGraphics->GetTextLayout(0); @@ -1505,7 +1511,7 @@ sal_Int32 OutputDevice::GetTextBreak( const OUString& rStr, tools::Long nTextWid const SalLayoutGlyphs* pGlyphs) const { std::unique_ptr pSalLayout = ImplLayout( rStr, nIndex, nLen, - Point(0,0), 0, {}, eDefaultLayout, pLayoutCache, pGlyphs); + Point(0,0), 0, {}, {}, eDefaultLayout, pLayoutCache, pGlyphs); sal_Int32 nRetVal = -1; if( pSalLayout ) { @@ -1539,7 +1545,7 @@ sal_Int32 OutputDevice::GetTextBreak( const OUString& rStr, tools::Long nTextWid rHyphenPos = -1; std::unique_ptr pSalLayout = ImplLayout( rStr, nIndex, nLen, - Point(0,0), 0, {}, eDefaultLayout, pLayoutCache, pGlyphs); + Point(0,0), 0, {}, {}, eDefaultLayout, pLayoutCache, pGlyphs); sal_Int32 nRetVal = -1; if( pSalLayout ) { @@ -2397,6 +2403,7 @@ bool OutputDevice::GetTextBoundRect( tools::Rectangle& rRect, const OUString& rStr, sal_Int32 nBase, sal_Int32 nIndex, sal_Int32 nLen, sal_uLong nLayoutWidth, o3tl::span pDXAry, + o3tl::span pKashidaAry, const SalLayoutGlyphs* pGlyphs ) const { bool bRet = false; @@ -2410,7 +2417,7 @@ bool OutputDevice::GetTextBoundRect( tools::Rectangle& rRect, { sal_Int32 nStart = std::min( nBase, nIndex ); sal_Int32 nOfsLen = std::max( nBase, nIndex ) - nStart; - pSalLayout = ImplLayout( rStr, nStart, nOfsLen, aPoint, nLayoutWidth, pDXAry ); + pSalLayout = ImplLayout( rStr, nStart, nOfsLen, aPoint, nLayoutWidth, pDXAry, pKashidaAry ); if( pSalLayout ) { nXOffset = pSalLayout->GetTextWidth(); @@ -2421,7 +2428,7 @@ bool OutputDevice::GetTextBoundRect( tools::Rectangle& rRect, } } - pSalLayout = ImplLayout(rStr, nIndex, nLen, aPoint, nLayoutWidth, pDXAry, eDefaultLayout, + pSalLayout = ImplLayout(rStr, nIndex, nLen, aPoint, nLayoutWidth, pDXAry, pKashidaAry, eDefaultLayout, nullptr, pGlyphs); if( pSalLayout ) { @@ -2461,7 +2468,9 @@ bool OutputDevice::GetTextBoundRect( tools::Rectangle& rRect, bool OutputDevice::GetTextOutlines( basegfx::B2DPolyPolygonVector& rVector, const OUString& rStr, sal_Int32 nBase, sal_Int32 nIndex, sal_Int32 nLen, - sal_uLong nLayoutWidth, o3tl::span pDXArray ) const + sal_uLong nLayoutWidth, + o3tl::span pDXArray, + o3tl::span pKashidaArray ) const { if (!InitFont()) return false; @@ -2491,7 +2500,7 @@ bool OutputDevice::GetTextOutlines( basegfx::B2DPolyPolygonVector& rVector, { sal_Int32 nStart = std::min( nBase, nIndex ); sal_Int32 nOfsLen = std::max( nBase, nIndex ) - nStart; - pSalLayout = ImplLayout( rStr, nStart, nOfsLen, Point(0,0), nLayoutWidth, pDXArray ); + pSalLayout = ImplLayout( rStr, nStart, nOfsLen, Point(0,0), nLayoutWidth, pDXArray, pKashidaArray); if( pSalLayout ) { nXOffset = pSalLayout->GetTextWidth(); @@ -2502,7 +2511,7 @@ bool OutputDevice::GetTextOutlines( basegfx::B2DPolyPolygonVector& rVector, } } - pSalLayout = ImplLayout( rStr, nIndex, nLen, Point(0,0), nLayoutWidth, pDXArray ); + pSalLayout = ImplLayout( rStr, nIndex, nLen, Point(0,0), nLayoutWidth, pDXArray, pKashidaArray ); if( pSalLayout ) { bRet = pSalLayout->GetOutline(rVector); @@ -2548,14 +2557,15 @@ bool OutputDevice::GetTextOutlines( basegfx::B2DPolyPolygonVector& rVector, bool OutputDevice::GetTextOutlines( PolyPolyVector& rResultVector, const OUString& rStr, sal_Int32 nBase, sal_Int32 nIndex, sal_Int32 nLen, - sal_uLong nLayoutWidth, o3tl::span pDXArray ) const + sal_uLong nLayoutWidth, o3tl::span pDXArray, + o3tl::span pKashidaArray ) const { rResultVector.clear(); // get the basegfx polypolygon vector basegfx::B2DPolyPolygonVector aB2DPolyPolyVector; if( !GetTextOutlines( aB2DPolyPolyVector, rStr, nBase, nIndex, nLen, - nLayoutWidth, pDXArray ) ) + nLayoutWidth, pDXArray, pKashidaArray ) ) return false; // convert to a tool polypolygon vector diff --git a/vcl/source/outdev/transparent.cxx b/vcl/source/outdev/transparent.cxx index a4019ca94f85..536498703bb5 100644 --- a/vcl/source/outdev/transparent.cxx +++ b/vcl/source/outdev/transparent.cxx @@ -1193,7 +1193,7 @@ tools::Rectangle ImplCalcActionBounds( const MetaAction& rAct, const OutputDevic // #105987# ImplLayout takes everything in logical coordinates std::unique_ptr pSalLayout = rOut.ImplLayout( rTextAct.GetText(), rTextAct.GetIndex(), rTextAct.GetLen(), rTextAct.GetPoint(), - 0, rTextAct.GetDXArray()); + 0, rTextAct.GetDXArray(), rTextAct.GetKashidaArray() ); if( pSalLayout ) { tools::Rectangle aBoundRect( rOut.ImplGetTextBoundRect( *pSalLayout ) ); diff --git a/vcl/source/text/ImplLayoutArgs.cxx b/vcl/source/text/ImplLayoutArgs.cxx index 80e85a66dc26..45b951a9845d 100644 --- a/vcl/source/text/ImplLayoutArgs.cxx +++ b/vcl/source/text/ImplLayoutArgs.cxx @@ -39,6 +39,7 @@ ImplLayoutArgs::ImplLayoutArgs(const OUString& rStr, int nMinCharPos, int nEndCh , m_pTextLayoutCache(pLayoutCache) , mpDXArray(nullptr) , mpAltNaturalDXArray(nullptr) + , mpKashidaArray(nullptr) , mnLayoutWidth(0) , mnOrientation(0) { @@ -97,6 +98,11 @@ void ImplLayoutArgs::SetAltNaturalDXArray(double const* pDXArray) mpAltNaturalDXArray = pDXArray; } +void ImplLayoutArgs::SetKashidaArray(sal_Bool const* pKashidaArray) +{ + mpKashidaArray = pKashidaArray; +} + void ImplLayoutArgs::SetOrientation(Degree10 nOrientation) { mnOrientation = nOrientation; } void ImplLayoutArgs::ResetPos() { maRuns.ResetPos(); } @@ -269,7 +275,6 @@ std::ostream& operator<<(std::ostream& s, vcl::text::ImplLayoutArgs const& rArgs TEST(DisableKerning); TEST(KerningAsian); TEST(Vertical); - TEST(KashidaJustification); TEST(ForFallback); #undef TEST s << "}"; @@ -333,6 +338,31 @@ std::ostream& operator<<(std::ostream& s, vcl::text::ImplLayoutArgs const& rArgs else s << "NULL"; + s << ",KashidaArray="; + if (rArgs.mpKashidaArray) + { + s << "["; + int count = rArgs.mnEndCharPos - rArgs.mnMinCharPos; + lim = count; + if (lim > 10) + lim = 7; + for (int i = 0; i < lim; i++) + { + s << rArgs.mpKashidaArray[i]; + if (i < lim - 1) + s << ","; + } + if (count > lim) + { + if (count > lim + 1) + s << "..."; + s << rArgs.mpKashidaArray[count - 1]; + } + s << "]"; + } + else + s << "NULL"; + s << ",LayoutWidth=" << rArgs.mnLayoutWidth; s << "}"; diff --git a/vcl/source/window/menuitemlist.cxx b/vcl/source/window/menuitemlist.cxx index 173a6204eb48..0efae5b43b8c 100644 --- a/vcl/source/window/menuitemlist.cxx +++ b/vcl/source/window/menuitemlist.cxx @@ -48,7 +48,7 @@ SalLayoutGlyphs* MenuItemData::GetTextGlyphs(const OutputDevice* pOutputDevice) OUString aNonMnemonicString = OutputDevice::GetNonMnemonicString(aText); std::unique_ptr pLayout = pOutputDevice->ImplLayout(aNonMnemonicString, 0, aNonMnemonicString.getLength(), - Point(0, 0), 0, {}, SalLayoutFlags::GlyphItemsOnly); + Point(0, 0), 0, {}, {}, SalLayoutFlags::GlyphItemsOnly); if (!pLayout) return nullptr; diff --git a/vcl/source/window/status.cxx b/vcl/source/window/status.cxx index 8c701b496b14..81ce41db73e7 100644 --- a/vcl/source/window/status.cxx +++ b/vcl/source/window/status.cxx @@ -79,7 +79,7 @@ SalLayoutGlyphs* ImplStatusItem::GetTextGlyphs(const OutputDevice* outputDevice) if(!mLayoutGlyphsCache.has_value()) { std::unique_ptr pSalLayout = outputDevice->ImplLayout( - maText, 0, -1, Point(0, 0), 0, {}, SalLayoutFlags::GlyphItemsOnly); + maText, 0, -1, Point(0, 0), 0, {}, {}, SalLayoutFlags::GlyphItemsOnly); mLayoutGlyphsCache = pSalLayout ? pSalLayout->GetGlyphs() : SalLayoutGlyphs(); } return mLayoutGlyphsCache->IsValid() ? &mLayoutGlyphsCache.value() : nullptr; -- cgit