summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKhaled Hosny <khaled@aliftype.com>2022-08-08 22:08:37 +0200
committerCaolán McNamara <caolanm@redhat.com>2022-08-14 21:10:24 +0200
commit3901e029bd39575f700e69a73818565d62226a23 (patch)
tree2851945d9b13ac071d1e21af53288f46125dbc32
parentcc54063b915a58db9133c919c151ec7e6209f4cd (diff)
tdf#104921: Cleanup Kashida insertion logic
Communicate Kashida insertion positions in an explicit way. Rest of LibreOffice communicate adjustments to character widths (e.g. for justification or spacing) using so-called DX array. DX array is an array of absolute character positions (e.g. DX[n] is the position after character n from the start of the lines, and its widths is DX[n] - DX[n-1]). This DX array is modified also when Kashidas are inserted after a given character for Arabic justification, by expanding its width. VCL would use this to know where to insert the Kashidas and how many ones. But because DX array is used for both widths adjustments and kashida insertion, this turns out to be a source of bugs since VCL has tosecond guess the DX array to find which is pure width adjustment and which also involves Kashida insertion, and the heuristics it uses are fragile. This change adds a second array of booleans that records where Kashida is inserted and communicates it all the way from where Kashida insertion is decoded in Writer and down to VCL layout. This change passes the Kashida array only when it seems necessary (e.g. during drawing but not when measuring text since the DX array is enough in this case). Hopefully no places where Kashida insertion needs to be passed down were missed. A couple of glyph and layout flags that were used for old heuristics and no longer needed and are removed. This also fixes: tdf#87731 tdf#106309 tdf#108604 tdf#112849 tdf#114257 tdf#127176 tdf#145647 tdf#146199 Change-Id: I4ed0850ef2fdc3e9143341afac649e7e7d463c39 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138068 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caolanm@redhat.com>
-rw-r--r--canvas/source/cairo/cairo_textlayout.cxx2
-rw-r--r--canvas/source/directx/dx_textlayout_drawhelper.cxx1
-rw-r--r--canvas/source/vcl/textlayout.cxx1
-rw-r--r--drawinglayer/source/primitive2d/textbreakuphelper.cxx10
-rw-r--r--drawinglayer/source/primitive2d/textdecoratedprimitive2d.cxx7
-rw-r--r--drawinglayer/source/primitive2d/textlayoutdevice.cxx6
-rw-r--r--drawinglayer/source/primitive2d/textprimitive2d.cxx13
-rw-r--r--drawinglayer/source/primitive2d/textstrikeoutprimitive2d.cxx1
-rw-r--r--drawinglayer/source/processor2d/vclprocessor2d.cxx3
-rw-r--r--drawinglayer/source/tools/emfphelperdata.cxx4
-rw-r--r--drawinglayer/source/tools/wmfemfhelper.cxx7
-rw-r--r--editeng/inc/editdoc.hxx4
-rw-r--r--editeng/source/editeng/editeng.cxx3
-rw-r--r--editeng/source/editeng/impedit3.cxx33
-rw-r--r--editeng/source/items/svxfont.cxx13
-rw-r--r--editeng/source/outliner/outleeng.cxx5
-rw-r--r--editeng/source/outliner/outleeng.hxx3
-rw-r--r--editeng/source/outliner/outliner.cxx9
-rw-r--r--emfio/source/reader/mtftools.cxx4
-rw-r--r--include/drawinglayer/primitive2d/textdecoratedprimitive2d.hxx2
-rw-r--r--include/drawinglayer/primitive2d/textlayoutdevice.hxx3
-rw-r--r--include/drawinglayer/primitive2d/textprimitive2d.hxx8
-rw-r--r--include/editeng/editeng.hxx4
-rw-r--r--include/editeng/outliner.hxx7
-rw-r--r--include/editeng/svxfont.hxx3
-rw-r--r--include/vcl/metaact.hxx11
-rw-r--r--include/vcl/outdev.hxx12
-rw-r--r--include/vcl/pdfwriter.hxx1
-rw-r--r--include/vcl/rendercontext/SalLayoutFlags.hxx3
-rw-r--r--sc/source/ui/view/hintwin.cxx4
-rw-r--r--sd/source/ui/view/sdview.cxx1
-rw-r--r--sfx2/source/control/thumbnailviewitem.cxx1
-rw-r--r--svgio/source/svgreader/svgcharacternode.cxx2
-rw-r--r--svtools/source/control/ruler.cxx4
-rw-r--r--svx/source/diagram/IDiagramHelper.cxx3
-rw-r--r--svx/source/svdraw/svdotextdecomposition.cxx14
-rw-r--r--svx/source/svdraw/svdotextpathdecomposition.cxx5
-rw-r--r--svx/source/tbxctrls/StylesPreviewWindow.cxx3
-rw-r--r--sw/source/core/inc/scriptinfo.hxx2
-rw-r--r--sw/source/core/layout/paintfrm.cxx1
-rw-r--r--sw/source/core/text/itradj.cxx6
-rw-r--r--sw/source/core/text/porlay.cxx6
-rw-r--r--sw/source/core/text/portxt.cxx2
-rw-r--r--sw/source/core/txtnode/fntcache.cxx32
-rw-r--r--sw/source/uibase/docvw/HeaderFooterWin.cxx2
-rw-r--r--sw/source/uibase/docvw/UnfloatTableButton.cxx2
-rw-r--r--vcl/inc/ImplLayoutArgs.hxx2
-rw-r--r--vcl/inc/impglyphitem.hxx4
-rw-r--r--vcl/inc/pdf/pdfwriter_impl.hxx2
-rw-r--r--vcl/inc/sallayout.hxx2
-rw-r--r--vcl/qa/cppunit/complextext.cxx37
-rw-r--r--vcl/qa/cppunit/svm/svmtest.cxx2
-rw-r--r--vcl/qa/cppunit/text.cxx2
-rw-r--r--vcl/source/control/imp_listbox.cxx2
-rw-r--r--vcl/source/filter/eps/eps.cxx12
-rw-r--r--vcl/source/filter/svm/SvmConverter.cxx2
-rw-r--r--vcl/source/gdi/CommonSalLayout.cxx98
-rw-r--r--vcl/source/gdi/gdimtf.cxx4
-rw-r--r--vcl/source/gdi/impglyphitem.cxx25
-rw-r--r--vcl/source/gdi/metaact.cxx12
-rw-r--r--vcl/source/gdi/pdfwriter.cxx3
-rw-r--r--vcl/source/gdi/pdfwriter_impl.cxx8
-rw-r--r--vcl/source/gdi/pdfwriter_impl2.cxx2
-rw-r--r--vcl/source/gdi/textlayout.cxx2
-rw-r--r--vcl/source/outdev/text.cxx42
-rw-r--r--vcl/source/outdev/transparent.cxx2
-rw-r--r--vcl/source/text/ImplLayoutArgs.cxx32
-rw-r--r--vcl/source/window/menuitemlist.cxx2
-rw-r--r--vcl/source/window/status.cxx2
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;