diff options
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<sal_uInt16>(maText.StartPosition), ::canvas::tools::numeric_cast<sal_uInt16>(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<sal_uInt16>(maText.StartPosition), ::canvas::tools::numeric_cast<sal_uInt16>(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<double>& rDXArray) const + sal_uInt32 nLength, const std::vector<double>& rDXArray, + const std::vector<sal_Bool>& 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<double>&& 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<double>&& rDXArray, std::vector<sal_Bool>&& 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<sal_Int32> & 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<sal_Bool> 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<sal_Bool>& GetKashidaArray() { return aKashidaPositions; } + const std::vector<sal_Bool>& 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 sal_Int32>, const SvxFont&, sal_Int32 /*nPara*/, sal_uInt8 /*nRightToLeft*/, + o3tl::span<const sal_Int32>, o3tl::span<const sal_Bool>, + 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<tools::Long>(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<const sal_Int32> pDXArray; + o3tl::span<const sal_Bool> pKashidaArray; std::vector<sal_Int32> 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<const sal_Int32> pDXAry, + o3tl::span<const sal_Bool> 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<const sal_Int32> pDXArray ) const + const sal_Int32 nIdx, const sal_Int32 nLen, + o3tl::span<const sal_Int32> pDXArray, + o3tl::span<const sal_Bool> 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<const sal_Int32> pDXArray, const SvxFont& rFont, sal_Int32 nPara, sal_uInt8 nRightToLeft, + o3tl::span<const sal_Int32> pDXArray, o3tl::span<const sal_Bool> 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<const sal_Int32> pDXArray, const SvxFont& rFont, + sal_Int32 nTextLen, o3tl::span<const sal_Int32> pDXArray, + o3tl::span<const sal_Bool> 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<const sal_Int32> pDXArray,const SvxFont& rFont, + sal_Int32 nTextLen, o3tl::span<const sal_Int32> pDXArray, + o3tl::span<const sal_Bool> 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<const sal_Int32>{}, 0, 1 ) ); + mpGDIMetaFile->AddAction( new MetaTextArrayAction( rPosition + aCharDisplacement, OUString( rText[i] ), o3tl::span<const sal_Int32>{}, {}, 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<double>& rDXArray) const; + sal_uInt32 nLength, const ::std::vector<double>& rDXArray, + const ::std::vector<sal_Bool>& 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<double> maDXArray; + /// The Kashida array + std::vector<sal_Bool> 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<double>&& rDXArray, + std::vector<sal_Bool>&& 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<double>& getDXArray() const { return maDXArray; } + const ::std::vector<sal_Bool>& 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<const sal_Int32> pDXArray, const SvxFont& rFont, + o3tl::span<const sal_Int32> pDXArray, + o3tl::span<const sal_Bool> 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<const sal_Int32> mpDXArray; + o3tl::span<const sal_Bool> mpKashidaArray; const EEngineData::WrongSpellVector* mpWrongSpellVector; const SvxFieldData* mpFieldData; @@ -427,6 +428,7 @@ public: const SvxFont& rFnt, sal_Int32 nPar, o3tl::span<const sal_Int32> pDXArr, + o3tl::span<const sal_Bool> 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<const sal_Int32> pDXArray, const SvxFont& rFont, + o3tl::span<const sal_Int32> pDXArray, + o3tl::span<const sal_Bool> 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<const sal_Int32> pDXArray = {} ) const; + o3tl::span<const sal_Int32> pDXArray = {}, + o3tl::span<const sal_Bool> 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<sal_Int32> maDXAry; + std::vector<sal_Bool> 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<sal_Int32> rDXAry, sal_Int32 nIndex, + std::vector<sal_Int32> rDXAry, + std::vector<sal_Bool> pKashidaAry, + sal_Int32 nIndex, sal_Int32 nLen ); MetaTextArrayAction( const Point& rStartPt, OUString aStr, - o3tl::span<const sal_Int32> pDXAry, sal_Int32 nIndex, + o3tl::span<const sal_Int32> pDXAry, + o3tl::span<const sal_Bool> 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<sal_Int32> & GetDXArray() const { return maDXAry; } + const std::vector<sal_Bool> & 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<sal_Int32> aArray); + void SetKashidaArray(std::vector<sal_Bool> 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<const sal_Int32> pDXArray = {}, + o3tl::span<const sal_Bool> 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<const sal_Int32> pDXArray = {} ) const; + sal_uLong nLayoutWidth = 0, o3tl::span<const sal_Int32> pDXArray = {}, + o3tl::span<const sal_Bool> 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<const sal_Int32> pDXArray = {} ) const; + sal_uLong nLayoutWidth = 0, o3tl::span<const sal_Int32> pDXArray = {}, + o3tl::span<const sal_Bool> 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<const sal_Int32> pDXAry, + o3tl::span<const sal_Bool> pKashidaAry={}, sal_Int32 nIndex = 0, sal_Int32 nLen = -1, SalLayoutFlags flags = SalLayoutFlags::NONE, @@ -1236,7 +1240,9 @@ public: std::unique_ptr<SalLayout> ImplLayout( const OUString&, sal_Int32 nIndex, sal_Int32 nLen, const Point& rLogicPos = Point(0,0), tools::Long nLogicWidth=0, - o3tl::span<const sal_Int32> pLogicDXArray={}, SalLayoutFlags flags = SalLayoutFlags::NONE, + o3tl::span<const sal_Int32> pLogicDXArray={}, + o3tl::span<const sal_Bool> 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<const sal_Int32> pDXAry, + o3tl::span<const sal_Bool> 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<SalLayoutFlags> : is_typed_flags<SalLayoutFlags, 0x6877> +template <> struct typed_flags<SalLayoutFlags> : is_typed_flags<SalLayoutFlags, 0x6077> { }; } 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<drawinglayer::primitive2d::TextSimplePortionPrimitive2D> pTitle = new drawinglayer::primitive2d::TextSimplePortionPrimitive2D( aTextMatrix, m_aTitle, 0, m_aTitle.getLength(), - std::vector<double>(), std::move(aFontAttr), css::lang::Locale(), + std::vector<double>(), {}, 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<drawinglayer::primitive2d::TextSimplePortionPrimitive2D> pMessage = new drawinglayer::primitive2d::TextSimplePortionPrimitive2D( aTextMatrix, aLine, 0, aLine.getLength(), - std::vector<double>(), aFontAttr, css::lang::Locale(), + std::vector<double>(), {}, 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<double>(), + {}, 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<SalLayout> 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<sal_Int32> aKernArray; GetTextArray(rInf.GetOut(), rInf, aKernArray); + std::vector<sal_Bool> 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<sal_Bool> 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<double>(), std::move(aFontAttr), css::lang::Locale(), aLineColor))); + std::vector<double>(), {}, 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<double>(), + aTextMatrix, m_sLabel, 0, m_sLabel.getLength(), std::vector<double>(), {}, 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<GlyphItemFlags> : is_typed_flags<GlyphItemFlags, 0x3ff> +template <> struct typed_flags<GlyphItemFlags> : is_typed_flags<GlyphItemFlags, 0x3df> { }; }; @@ -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<const sal_Int32> pDXArray, sal_Int32 nIndex, sal_Int32 nLen ); + void drawTextArray( const Point& rPos, const OUString& rText, o3tl::span<const sal_Int32> pDXArray, o3tl::span<const sal_Bool> 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<typename DC> - 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<VirtualDevice> pOutputDevice; - auto aText - = OUString(u"عنصر الفوسفور عنصر فلزي صلب. تتكون الدورة الرابعة من 15 عنصرا."); - std::unique_ptr<SalLayout> 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<SalLayout> 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<SalLayout> 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<const vcl::text::TextLayoutCache> 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<SalLayout> 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<VirtualDevice> 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<SalLayout> 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<SalLayout> 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<const sal_Int32> pDXArry, sal_Int32 nWidth, VirtualDevice const & rVDev ); + void ImplText( const OUString& rUniString, const Point& rPos, o3tl::span<const sal_Int32> pDXArry, o3tl::span<const sal_Bool> pKashidaArry, sal_Int32 nWidth, VirtualDevice const & rVDev ); void ImplSetAttrForText( const Point & rPoint ); void ImplWriteCharacter( char ); void ImplWriteString( const OString&, VirtualDevice const & rVDev, o3tl::span<const sal_Int32> 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<const sal_Int32> pDXArry, sal_Int32 nWidth, VirtualDevice const & rVDev ) +void PSWriter::ImplText( const OUString& rUniString, const Point& rPos, o3tl::span<const sal_Int32> pDXArry, o3tl::span<const sal_Bool> 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<tools::PolyPolygon> 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<DeviceCoordinate>& 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<typename DC> -void GenericSalLayout::ApplyDXArray(const DC* pDXArray, SalLayoutFlags nLayoutFlags) +void GenericSalLayout::ApplyDXArray(const DC* pDXArray, const sal_Bool* pKashidaArray) { int nCharCount = mnEndCharPos - mnMinCharPos; std::vector<DeviceCoordinate> 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<size_t, DeviceCoordinate> 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<MetaTextArrayAction*>(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<const OutputDevice> 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<SalLayout> 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<const OutputDevice> outputDevice, c layoutCache = tmpLayoutCache.get(); } std::unique_ptr<SalLayout> 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<sal_Int32> aDXAry, + std::vector<sal_Bool> 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<const sal_Int32> pDXAry, + o3tl::span<const sal_Bool> 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<MetaAction> MetaTextArrayAction::Clone() const @@ -669,6 +674,11 @@ void MetaTextArrayAction::SetDXArray(std::vector<sal_Int32> aArray) maDXAry = std::move(aArray); } +void MetaTextArrayAction::SetKashidaArray(std::vector<sal_Bool> 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<const sal_Int32> pDXAry, + o3tl::span<const sal_Bool> 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<SalLayout> 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<const sal_Int32> pDXArray, sal_Int32 nIndex, sal_Int32 nLen ) +void PDFWriterImpl::drawTextArray( const Point& rPos, const OUString& rText, o3tl::span<const sal_Int32> pDXArray, o3tl::span<const sal_Bool> 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<SalLayout> pLayout = ImplLayout( rText, nIndex, nLen, rPos, 0, pDXArray, + std::unique_ptr<SalLayout> 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<SalLayout> 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<const MetaTextArrayAction*>(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<sal_Int32> 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<SalLayout> pSalLayout = ImplLayout(rStr, nIndex, nLen, rStartPt, 0, {}, eDefaultLayout, nullptr, pLayoutCache); + std::unique_ptr<SalLayout> 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<const sal_Int32> pDXAry, + o3tl::span<const sal_Bool> 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<SalLayout> pSalLayout = ImplLayout(rStr, nIndex, nLen, rStartPt, 0, pDXAry, flags, nullptr, pSalLayoutCache); + std::unique_ptr<SalLayout> 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<sal_Int32>* pDXAry, @@ -968,7 +969,7 @@ tools::Long OutputDevice::GetTextArray( const OUString& rStr, std::vector<sal_In // do layout std::unique_ptr<SalLayout> 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<SalLayout> pSalLayout = ImplLayout(rStr, nIndex, nLen, Point(0, 0), 0, {}, + std::unique_ptr<SalLayout> 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<SalLayout> OutputDevice::ImplLayout(const OUString& rOrigStr, sal_Int32 nMinIndex, sal_Int32 nLen, const Point& rLogicalPos, tools::Long nLogicalWidth, - o3tl::span<const sal_Int32> pDXArray, SalLayoutFlags flags, + o3tl::span<const sal_Int32> pDXArray, + o3tl::span<const sal_Bool> pKashidaArray, + SalLayoutFlags flags, vcl::text::TextLayoutCache const* pLayoutCache, const SalLayoutGlyphs* pGlyphs) const { @@ -1427,6 +1430,9 @@ std::unique_ptr<SalLayout> OutputDevice::ImplLayout(const OUString& rOrigStr, } } + if (!pKashidaArray.empty()) + aLayoutArgs.SetKashidaArray(pKashidaArray.data()); + // get matching layout object for base font std::unique_ptr<SalLayout> 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<SalLayout> 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<SalLayout> 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<const sal_Int32> pDXAry, + o3tl::span<const sal_Bool> 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<const sal_Int32> pDXArray ) const + sal_uLong nLayoutWidth, + o3tl::span<const sal_Int32> pDXArray, + o3tl::span<const sal_Bool> 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<const sal_Int32> pDXArray ) const + sal_uLong nLayoutWidth, o3tl::span<const sal_Int32> pDXArray, + o3tl::span<const sal_Bool> 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<SalLayout> 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<SalLayout> 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<SalLayout> 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; |