editeng/source/items/svxfont.cxx      |    2 
 include/vcl/outdev.hxx                |    2 
 include/vcl/vcllayout.hxx             |    6 +-
 osx/soffice.xcodeproj/project.pbxproj |    7 ++
 sw/source/core/inc/drawfont.hxx       |   13 +++++
 sw/source/core/text/inftxt.cxx        |   12 ++++
 sw/source/core/text/inftxt.hxx        |    4 +
 sw/source/core/text/itrcrsr.cxx       |   29 ++++++++++--
 sw/source/core/txtnode/fntcache.cxx   |   41 +++++++++++------
 sw/source/core/txtnode/swfont.cxx     |   16 ++++++
 vcl/inc/sallayout.hxx                 |    7 +-
 vcl/qa/cppunit/complextext.cxx        |   82 ++++++++++++++++++++++++++++++++++
 vcl/source/gdi/CommonSalLayout.cxx    |   50 ++++++++++++++++++--
 vcl/source/gdi/sallayout.cxx          |   18 ++++---
 vcl/source/outdev/text.cxx            |    8 +--
 15 files changed, 253 insertions(+), 44 deletions(-)

New commits:
commit 8cb4db941f91cc234dd18c61f8b1e51f65360d1f
Author:     Khaled Hosny <kha...@aliftype.com>
AuthorDate: Fri Aug 26 22:20:55 2022 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Wed Aug 31 08:29:49 2022 +0200

    tdf#30731: Improve caret travelling in Writer
    
    Previously, when measuring caret position, Writer would measure the
    width of the substring before the caret (i.e. layout it independent of
    the text after the caret and measure its width).
    
    This is incorrect, though. It assumes cutting the string laying it out
    would result in the same width as when laid out as part of a bigger
    string, which is invalid assumption when e.g. cutting inside a ligature
    or between letters that have different shapes when next to each other,
    etc.
    
    This appears to work when the width of the substring laid out alone is
    close enough to its width when laid out with the full text. But in cases
    where is widths are largely different, like the extreme case in the bug
    report, the caret will be jumping around as it is positioned based on
    the unligated glyphs not the ligated, rendered glyphs.
    
    This change introduces a special mode of measuring text width for caret
    positioning, that will layout the whole string that return the width of
    the requested substring.
    
    Fields and small caps text are trickier to handle, so old behaviour is
    retained for them. Now one will probably notice but if they do, it can
    be dealt with then.
    
    This also tries to be conservative and keep other pleases using the
    existing behaviour which might be desirable (e.g. when measuring text
    width for line breaking, we want the unligated width), but there might
    be other places that should use the new behaviour.
    
    To handle caret inside ligatures, the grapheme clusters in the ligature
    are counted and the width of the whole ligature is distributed on them
    evenly. A further improvement would be using HarfBuzz API to get
    ligature caret positions for fonts that provide them, which helps when
    the ligature components have different widths.
    
    Change-Id: I02062e2e2e1b1a35c8f84307c0a8f5d743059ab5
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138889
    Tested-by: Jenkins
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/editeng/source/items/svxfont.cxx b/editeng/source/items/svxfont.cxx
index 868b830c63cc..65191cab8ed7 100644
--- a/editeng/source/items/svxfont.cxx
+++ b/editeng/source/items/svxfont.cxx
@@ -37,7 +37,7 @@ static tools::Long GetTextArray( const OutputDevice* pOut, 
const OUString& rStr,
 
 {
     const SalLayoutGlyphs* layoutGlyphs = 
SalLayoutGlyphsCache::self()->GetLayoutGlyphs(pOut, rStr, nIndex, nLen);
-    return pOut->GetTextArray( rStr, pDXAry, nIndex, nLen, nullptr, 
layoutGlyphs);
+    return pOut->GetTextArray( rStr, pDXAry, nIndex, nLen, false, nullptr, 
layoutGlyphs);
 }
 
 SvxFont::SvxFont()
diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx
index 27e7650e8f72..1162ef3c116e 100644
--- a/include/vcl/outdev.hxx
+++ b/include/vcl/outdev.hxx
@@ -1043,7 +1043,7 @@ public:
                                                SalLayoutFlags flags = 
SalLayoutFlags::NONE,
                                                const SalLayoutGlyphs* 
pLayoutCache = nullptr);
     tools::Long                        GetTextArray( const OUString& rStr, 
std::vector<sal_Int32>* pDXAry,
-                                              sal_Int32 nIndex = 0, sal_Int32 
nLen = -1,
+                                              sal_Int32 nIndex = 0, sal_Int32 
nLen = -1, bool bCaret = false,
                                               vcl::text::TextLayoutCache 
const* = nullptr,
                                               SalLayoutGlyphs const*const 
pLayoutCache = nullptr) const;
 
diff --git a/include/vcl/vcllayout.hxx b/include/vcl/vcllayout.hxx
index e63d365b49c4..cb88760cd98e 100644
--- a/include/vcl/vcllayout.hxx
+++ b/include/vcl/vcllayout.hxx
@@ -20,6 +20,7 @@
 #pragma once
 
 #include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <i18nlangtag/languagetag.hxx>
 #include <tools/gen.hxx>
 #include <tools/degree.hxx>
 
@@ -94,8 +95,8 @@ public:
 
     // methods using string indexing
     virtual sal_Int32 GetTextBreak(DeviceCoordinate nMaxWidth, 
DeviceCoordinate nCharExtra, int nFactor) const = 0;
-    virtual DeviceCoordinate FillDXArray( std::vector<DeviceCoordinate>* 
pDXArray ) const = 0;
-    virtual DeviceCoordinate GetTextWidth() const { return FillDXArray( 
nullptr ); }
+    virtual DeviceCoordinate FillDXArray( std::vector<DeviceCoordinate>* 
pDXArray, const OUString& rStr ) const = 0;
+    virtual DeviceCoordinate GetTextWidth() const { return FillDXArray( 
nullptr, {} ); }
     virtual void    GetCaretPositions( int nArraySize, sal_Int32* pCaretXArray 
) const = 0;
     virtual bool    IsKashidaPosValid ( int /*nCharPos*/, int /*nNextCharPos*/ 
) const = 0; // i60594
 
@@ -119,6 +120,7 @@ private:
 protected:
     int             mnMinCharPos;
     int             mnEndCharPos;
+    LanguageTag     maLanguageTag;
 
     int             mnUnitsPerPixel;
     Degree10        mnOrientation;
diff --git a/osx/soffice.xcodeproj/project.pbxproj 
b/osx/soffice.xcodeproj/project.pbxproj
index 7c201c130e24..4a2038c7d373 100644
--- a/osx/soffice.xcodeproj/project.pbxproj
+++ b/osx/soffice.xcodeproj/project.pbxproj
@@ -7,6 +7,8 @@
        objects = {
 
 /* Begin PBXFileReference section */
+               29FD821128BC548D00159078 /* text */ = {isa = PBXFileReference; 
lastKnownFileType = folder; name = text; path = ../sw/source/core/text; 
sourceTree = "<group>"; };
+               29FD821228BC54AB00159078 /* txtnode */ = {isa = 
PBXFileReference; lastKnownFileType = folder; name = txtnode; path = 
../sw/source/core/txtnode; sourceTree = "<group>"; };
                456E58CF277CB9C700FA12D2 /* unoshap2.cxx */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; 
name = unoshap2.cxx; path = ../svx/source/unodraw/unoshap2.cxx; sourceTree = 
"<group>"; };
                456E58D1277CC33E00FA12D2 /* unopage.cxx */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; 
name = unopage.cxx; path = ../svx/source/unodraw/unopage.cxx; sourceTree = 
"<group>"; };
                BE017B8725AF2ABE00244ED8 /* autostyl.cxx */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = autostyl.cxx; 
path = ../sc/source/ui/docshell/autostyl.cxx; sourceTree = "<group>"; };
@@ -123,7 +125,6 @@
                BE017BF825AF568900244ED8 /* solveroptions.cxx */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = 
solveroptions.cxx; path = ../sc/source/ui/miscdlgs/solveroptions.cxx; 
sourceTree = "<group>"; };
                BE017BF925AF568900244ED8 /* mtrindlg.cxx */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = mtrindlg.cxx; 
path = ../sc/source/ui/miscdlgs/mtrindlg.cxx; sourceTree = "<group>"; };
                BE017BFA25AF568900244ED8 /* linkarea.cxx */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = linkarea.cxx; 
path = ../sc/source/ui/miscdlgs/linkarea.cxx; sourceTree = "<group>"; };
-               BE017BFB25AF568900244ED8 /* shtabdlg.cxx */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = shtabdlg.cxx; 
path = ../sc/source/ui/miscdlgs/shtabdlg.cxx; sourceTree = "<group>"; };
                BE017BFB25AF568900244ED8 /* gototabdlg.cxx */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = 
gototabdlg.cxx; path = ../sc/source/ui/miscdlgs/gototabdlg.cxx; sourceTree = 
"<group>"; };
                BE017BFC25AF568900244ED8 /* inscodlg.cxx */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = inscodlg.cxx; 
path = ../sc/source/ui/miscdlgs/inscodlg.cxx; sourceTree = "<group>"; };
                BE017BFD25AF568A00244ED8 /* crdlg.cxx */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = crdlg.cxx; 
path = ../sc/source/ui/miscdlgs/crdlg.cxx; sourceTree = "<group>"; };
@@ -1281,7 +1282,7 @@
                                BE017C1D25AF568B00244ED8 /* retypepassdlg.cxx 
*/,
                                BE017C0125AF568A00244ED8 /* scuiautofmt.cxx */,
                                BE017C1C25AF568B00244ED8 /* sharedocdlg.cxx */,
-                               BE017BFB25AF568900244ED8 /* shtabdlg.cxx */,
+                               BE017BFB25AF568900244ED8 /* gototabdlg.cxx */,
                                BE017C1F25AF568B00244ED8 /* simpref.cxx */,
                                BE017BF825AF568900244ED8 /* solveroptions.cxx 
*/,
                                BE017C0C25AF568A00244ED8 /* solverutil.cxx */,
@@ -2365,6 +2366,8 @@
                BEBF3E662465907000415E87 /* sw */ = {
                        isa = PBXGroup;
                        children = (
+                               29FD821228BC54AB00159078 /* txtnode */,
+                               29FD821128BC548D00159078 /* text */,
                                BEBF3E6E246593A300415E87 /* ui */,
                                BEBF3E672465907D00415E87 /* uibase */,
                        );
diff --git a/sw/source/core/inc/drawfont.hxx b/sw/source/core/inc/drawfont.hxx
index c40ff1044d70..9a02e881e10e 100644
--- a/sw/source/core/inc/drawfont.hxx
+++ b/sw/source/core/inc/drawfont.hxx
@@ -61,6 +61,7 @@ class SW_DLLPUBLIC SwDrawTextInfo
     tools::Long m_nKanaDiff;
     TextFrameIndex m_nIdx;
     TextFrameIndex m_nLen;
+    TextFrameIndex m_nMeasureLen;
     /// this is not a string index
     sal_Int32 m_nOfst;
     sal_uInt16 m_nWidth;
@@ -127,6 +128,7 @@ public:
         m_aText = rText;
         m_nIdx = nIdx;
         m_nLen = nLen;
+        m_nMeasureLen = TextFrameIndex(COMPLETE_STRING);
         m_nKern = 0;
         m_nCompress = 0;
         m_nWidth = nWidth;
@@ -274,6 +276,11 @@ public:
         return m_nLen;
     }
 
+    TextFrameIndex GetMeasureLen() const
+    {
+        return m_nMeasureLen;
+    }
+
     sal_Int32 GetOffset() const
     {
 #ifdef DBG_UTIL
@@ -488,6 +495,12 @@ public:
         m_nLen = nNew;
     }
 
+    void SetMeasureLen(TextFrameIndex const nNew)
+    {
+        assert( nNew == TextFrameIndex(COMPLETE_STRING) || nNew <= m_nLen );
+        m_nMeasureLen = nNew;
+    }
+
     void SetOffset( sal_Int32 nNew )
     {
         m_nOfst = nNew;
diff --git a/sw/source/core/text/inftxt.cxx b/sw/source/core/text/inftxt.cxx
index 61a53c0aab76..1ca1046990a6 100644
--- a/sw/source/core/text/inftxt.cxx
+++ b/sw/source/core/text/inftxt.cxx
@@ -191,6 +191,7 @@ SwTextSizeInfo::SwTextSizeInfo()
 , m_pText(nullptr)
 , m_nIdx(0)
 , m_nLen(0)
+, m_nMeasureLen(COMPLETE_STRING)
 , m_nKanaIdx(0)
 , m_bOnWin    (false)
 , m_bNotEOL   (false)
@@ -221,6 +222,7 @@ SwTextSizeInfo::SwTextSizeInfo( const SwTextSizeInfo &rNew )
       m_pText(&rNew.GetText()),
       m_nIdx(rNew.GetIdx()),
       m_nLen(rNew.GetLen()),
+      m_nMeasureLen(rNew.GetMeasureLen()),
       m_nKanaIdx( rNew.GetKanaIdx() ),
       m_bOnWin( rNew.OnWin() ),
       m_bNotEOL( rNew.NotEOL() ),
@@ -309,7 +311,7 @@ void SwTextSizeInfo::CtorInitTextSizeInfo( OutputDevice* 
pRenderContext, SwTextF
     m_pText = &m_pFrame->GetText();
 
     m_nIdx = nNewIdx;
-    m_nLen = TextFrameIndex(COMPLETE_STRING);
+    m_nLen = m_nMeasureLen = TextFrameIndex(COMPLETE_STRING);
     m_bNotEOL = false;
     m_bStopUnderflow = m_bFootnoteInside = m_bOtherThanFootnoteInside = false;
     m_bMulti = m_bFirstMulti = m_bRuby = m_bHanging = m_bScriptSpace =
@@ -332,6 +334,7 @@ SwTextSizeInfo::SwTextSizeInfo( const SwTextSizeInfo &rNew, 
const OUString* pTex
       m_pText(pText),
       m_nIdx(nIndex),
       m_nLen(COMPLETE_STRING),
+      m_nMeasureLen(COMPLETE_STRING),
       m_nKanaIdx( rNew.GetKanaIdx() ),
       m_bOnWin( rNew.OnWin() ),
       m_bNotEOL( rNew.NotEOL() ),
@@ -407,6 +410,7 @@ SwPosSize SwTextSizeInfo::GetTextSize() const
                                 0 ;
 
     SwDrawTextInfo aDrawInf( m_pVsh, *m_pOut, &rSI, *m_pText, m_nIdx, m_nLen );
+    aDrawInf.SetMeasureLen( m_nMeasureLen );
     aDrawInf.SetFrame( m_pFrame );
     aDrawInf.SetFont( m_pFnt );
     aDrawInf.SetSnapToGrid( SnapToGrid() );
@@ -1826,6 +1830,7 @@ SwTextSlot::SwTextSlot(
     , m_pOldGrammarCheckList(nullptr)
     , nIdx(0)
     , nLen(0)
+    , nMeasureLen(0)
     , pInf(nullptr)
 {
     if( rCh.isEmpty() )
@@ -1845,11 +1850,15 @@ SwTextSlot::SwTextSlot(
     pInf = const_cast<SwTextSizeInfo*>(pNew);
     nIdx = pInf->GetIdx();
     nLen = pInf->GetLen();
+    nMeasureLen = pInf->GetMeasureLen();
     pOldText = &(pInf->GetText());
     m_pOldCachedVclData = pInf->GetCachedVclData();
     pInf->SetText( aText );
     pInf->SetIdx(TextFrameIndex(0));
     pInf->SetLen(bTextLen ? TextFrameIndex(pInf->GetText().getLength()) : 
pPor->GetLen());
+    if (nMeasureLen != TextFrameIndex(COMPLETE_STRING))
+        pInf->SetMeasureLen(TextFrameIndex(COMPLETE_STRING));
+
     pInf->SetCachedVclData(nullptr);
 
     // ST2
@@ -1923,6 +1932,7 @@ SwTextSlot::~SwTextSlot()
     pInf->SetText( *pOldText );
     pInf->SetIdx( nIdx );
     pInf->SetLen( nLen );
+    pInf->SetMeasureLen( nMeasureLen );
 
     // ST2
     // Restore old smart tag list
diff --git a/sw/source/core/text/inftxt.hxx b/sw/source/core/text/inftxt.hxx
index 1621b4f35a8f..8011b29b442a 100644
--- a/sw/source/core/text/inftxt.hxx
+++ b/sw/source/core/text/inftxt.hxx
@@ -154,6 +154,7 @@ protected:
     const OUString *m_pText;
     TextFrameIndex m_nIdx;
     TextFrameIndex m_nLen;
+    TextFrameIndex m_nMeasureLen;
     sal_uInt16 m_nKanaIdx;
     bool m_bOnWin     : 1;
     bool m_bNotEOL    : 1;
@@ -273,6 +274,8 @@ public:
     void SetIdx(const TextFrameIndex nNew) { m_nIdx = nNew; }
     TextFrameIndex GetLen() const { return m_nLen; }
     void SetLen(const TextFrameIndex nNew) { m_nLen = nNew; }
+    TextFrameIndex GetMeasureLen() const { return m_nMeasureLen; }
+    void SetMeasureLen(const TextFrameIndex nNew) { m_nMeasureLen = nNew; }
     void SetText( const OUString &rNew ){ m_pText = &rNew; }
 
     // No Bullets for the symbol font!
@@ -682,6 +685,7 @@ class SwTextSlot final
     std::unique_ptr<sw::WrongListIterator> m_pTempIter;
     TextFrameIndex nIdx;
     TextFrameIndex nLen;
+    TextFrameIndex nMeasureLen;
     bool bOn;
     SwTextSizeInfo *pInf;
 
diff --git a/sw/source/core/text/itrcrsr.cxx b/sw/source/core/text/itrcrsr.cxx
index f8220650c827..47befa14d008 100644
--- a/sw/source/core/text/itrcrsr.cxx
+++ b/sw/source/core/text/itrcrsr.cxx
@@ -907,9 +907,21 @@ void SwTextCursor::GetCharRect_( SwRect* pOrig, 
TextFrameIndex const nOfst,
                     }
                     if ( pPor->PrtWidth() )
                     {
+                        // tdf#30731: To get the correct nOfst width, we need
+                        // to send the whole portion string to GetTextSize()
+                        // and ask it to return the width of nOfst by calling
+                        // SetMeasureLen(). Cutting the string at nOfst can
+                        // give the wrong width if nOfst is in e.g. the middle
+                        // of a ligature. See SwFntObj::DrawText().
                         TextFrameIndex const nOldLen = pPor->GetLen();
-                        pPor->SetLen( nOfst - aInf.GetIdx() );
                         aInf.SetLen( pPor->GetLen() );
+                        pPor->SetLen( nOfst - aInf.GetIdx() );
+                        aInf.SetMeasureLen(pPor->GetLen());
+                        if (aInf.GetLen() < aInf.GetMeasureLen())
+                        {
+                            pPor->SetLen(aInf.GetMeasureLen());
+                            aInf.SetLen(pPor->GetLen());
+                        }
                         if( nX || !pPor->InNumberGrp() )
                         {
                             SeekAndChg( aInf );
@@ -925,7 +937,12 @@ void SwTextCursor::GetCharRect_( SwRect* pOrig, 
TextFrameIndex const nOfst,
                             if( bWidth )
                             {
                                 pPor->SetLen(pPor->GetLen() + 
TextFrameIndex(1));
-                                aInf.SetLen( pPor->GetLen() );
+                                aInf.SetMeasureLen(pPor->GetLen());
+                                if (aInf.GetLen() < aInf.GetMeasureLen())
+                                {
+                                    pPor->SetLen(aInf.GetMeasureLen());
+                                    aInf.SetLen(pPor->GetLen());
+                                }
                                 aInf.SetOnWin( false ); // no BULLETs!
                                 nTmp += pPor->GetTextSize( aInf ).Width();
                                 aInf.SetOnWin( bOldOnWin );
@@ -1102,8 +1119,14 @@ void SwTextCursor::GetCharRect_( SwRect* pOrig, 
TextFrameIndex const nOfst,
                     {
                         const bool bOldOnWin = aInf.OnWin();
                         TextFrameIndex const nOldLen = pPor->GetLen();
-                        pPor->SetLen( TextFrameIndex(1) );
                         aInf.SetLen( pPor->GetLen() );
+                        pPor->SetLen( TextFrameIndex(1) );
+                        aInf.SetMeasureLen(pPor->GetLen());
+                        if (aInf.GetLen() < aInf.GetMeasureLen())
+                        {
+                            pPor->SetLen(aInf.GetMeasureLen());
+                            aInf.SetLen(pPor->GetLen());
+                        }
                         SeekAndChg( aInf );
                         aInf.SetOnWin( false ); // no BULLETs!
                         aInf.SetKanaComp( pKanaComp );
diff --git a/sw/source/core/txtnode/fntcache.cxx 
b/sw/source/core/txtnode/fntcache.cxx
index 146122841e7c..5e1a04fe7160 100644
--- a/sw/source/core/txtnode/fntcache.cxx
+++ b/sw/source/core/txtnode/fntcache.cxx
@@ -732,23 +732,27 @@ static void lcl_DrawLineForWrongListData(
 }
 
 static void GetTextArray(const OutputDevice& rDevice, const OUString& rStr, 
std::vector<sal_Int32>& rDXAry,
-                         sal_Int32 nIndex, sal_Int32 nLen, const 
vcl::text::TextLayoutCache* layoutCache = nullptr)
+                         sal_Int32 nIndex, sal_Int32 nLen, bool bCaret = false,
+                         const vcl::text::TextLayoutCache* layoutCache = 
nullptr)
 {
     const SalLayoutGlyphs* pLayoutCache = 
SalLayoutGlyphsCache::self()->GetLayoutGlyphs(&rDevice, rStr, nIndex, nLen,
         0, layoutCache);
-    rDevice.GetTextArray(rStr, &rDXAry, nIndex, nLen, layoutCache, 
pLayoutCache);
+    rDevice.GetTextArray(rStr, &rDXAry, nIndex, nLen, bCaret, layoutCache, 
pLayoutCache);
 }
 
-static void GetTextArray(const OutputDevice& rOutputDevice, const 
SwDrawTextInfo& rInf, std::vector<sal_Int32>& rDXAry)
+static void GetTextArray(const OutputDevice& rOutputDevice, const 
SwDrawTextInfo& rInf, std::vector<sal_Int32>& rDXAry,
+                         bool bCaret = false)
 {
-    return GetTextArray(rOutputDevice, rInf.GetText(), rDXAry, 
rInf.GetIdx().get(), rInf.GetLen().get(), rInf.GetVclCache());
+    return GetTextArray(rOutputDevice, rInf.GetText(), rDXAry, 
rInf.GetIdx().get(), rInf.GetLen().get(),
+                        bCaret, rInf.GetVclCache());
 }
 
-static void GetTextArray(const OutputDevice& rOutputDevice, const 
SwDrawTextInfo& rInf, std::vector<sal_Int32>& rDXAry, sal_Int32 nLen)
+static void GetTextArray(const OutputDevice& rOutputDevice, const 
SwDrawTextInfo& rInf, std::vector<sal_Int32>& rDXAry,
+                         sal_Int32 nLen, bool bCaret = false)
 {
     // Substring is fine.
     assert( nLen <= rInf.GetLen().get());
-    return GetTextArray(rOutputDevice, rInf.GetText(), rDXAry, 
rInf.GetIdx().get(), nLen, rInf.GetVclCache());
+    return GetTextArray(rOutputDevice, rInf.GetText(), rDXAry, 
rInf.GetIdx().get(), nLen, bCaret, rInf.GetVclCache());
 }
 
 void SwFntObj::DrawText( SwDrawTextInfo &rInf )
@@ -1529,6 +1533,15 @@ Size SwFntObj::GetTextSize( SwDrawTextInfo& rInf )
         ? rInf.GetLen()
         : TextFrameIndex(rInf.GetText().getLength());
 
+    const TextFrameIndex nMsrLn = (TextFrameIndex(COMPLETE_STRING) != 
rInf.GetMeasureLen())
+        ? rInf.GetMeasureLen()
+        : nLn;
+
+    // If the measure length is different from the length, then we are
+    // measuring substring width for caret positioning, see SetMeasureLength()
+    // use in TextCursor::GetCharRect_().
+    bool bCaret(nMsrLn != nLn);
+
     // be sure to have the correct layout mode at the printer
     if ( m_pPrinter )
     {
@@ -1566,7 +1579,7 @@ Size SwFntObj::GetTextSize( SwDrawTextInfo& rInf )
                                 GetFontLeading( rInf.GetShell(), rInf.GetOut() 
) );
 
             std::vector<sal_Int32> aKernArray;
-            GetTextArray(*pOutDev, rInf, aKernArray, sal_Int32(rInf.GetLen()));
+            GetTextArray(*pOutDev, rInf, aKernArray, sal_Int32(nLn), bCaret);
             if (pGrid->IsSnapToChars())
             {
                 sw::Justify::SnapToGrid(aKernArray, rInf.GetText(), 
sal_Int32(rInf.GetIdx()),
@@ -1579,7 +1592,7 @@ Size SwFntObj::GetTextSize( SwDrawTextInfo& rInf )
                         rInf.GetKern());
             }
 
-            aTextSize.setWidth(aKernArray[sal_Int32(rInf.GetLen()) - 1]);
+            aTextSize.setWidth(aKernArray[sal_Int32(nMsrLn) - 1]);
             rInf.SetKanaDiff( 0 );
             return aTextSize;
         }
@@ -1609,7 +1622,7 @@ Size SwFntObj::GetTextSize( SwDrawTextInfo& rInf )
             rInf.GetOut().SetFont( *m_pScrFont );
 
         GetTextArray(*m_pPrinter, rInf.GetText(), aKernArray,
-                     sal_Int32(rInf.GetIdx()), sal_Int32(nLn));
+                     sal_Int32(rInf.GetIdx()), sal_Int32(nLn), bCaret);
     }
     else
     {
@@ -1617,7 +1630,7 @@ Size SwFntObj::GetTextSize( SwDrawTextInfo& rInf )
             rInf.GetOut().SetFont( *m_pPrtFont );
         aTextSize.setHeight( rInf.GetOut().GetTextHeight() );
 
-        GetTextArray(rInf.GetOut(), rInf, aKernArray, nLn.get());
+        GetTextArray(rInf.GetOut(), rInf, aKernArray, nLn.get(), bCaret);
     }
 
     if (bCompress)
@@ -1628,16 +1641,16 @@ Size SwFntObj::GetTextSize( SwDrawTextInfo& rInf )
     else
         rInf.SetKanaDiff( 0 );
 
-    if (nLn)
+    if (nMsrLn)
     {
-        aTextSize.setWidth(aKernArray[sal_Int32(nLn) - 1]);
+        aTextSize.setWidth(aKernArray[sal_Int32(nMsrLn) - 1]);
 
-        // Note that we can't simply use sal_Int(nLn) - 1 as nSpaceCount
+        // Note that we can't simply use sal_Int(nMsrLn) - 1 as nSpaceCount
         // because a glyph may be made up of more than one characters.
         sal_Int32 nSpaceCount = 0;
         tools::Long nOldValue = aKernArray[0];
 
-        for(sal_Int32 i = 1; i < sal_Int32(nLn); ++i)
+        for(sal_Int32 i = 1; i < sal_Int32(nMsrLn); ++i)
         {
             if (nOldValue != aKernArray[i])
             {
diff --git a/sw/source/core/txtnode/swfont.cxx 
b/sw/source/core/txtnode/swfont.cxx
index 0ed7baf87894..c0149d9a6573 100644
--- a/sw/source/core/txtnode/swfont.cxx
+++ b/sw/source/core/txtnode/swfont.cxx
@@ -986,8 +986,16 @@ Size SwSubFont::GetTextSize_( SwDrawTextInfo& rInf )
             ? TextFrameIndex(rInf.GetText().getLength())
             : rInf.GetLen();
     rInf.SetLen( nLn );
+
     if( IsCapital() && nLn )
+    {
+        if (rInf.GetMeasureLen() != TextFrameIndex(COMPLETE_STRING))
+        {
+            rInf.SetLen(rInf.GetMeasureLen());
+            rInf.SetMeasureLen(TextFrameIndex(COMPLETE_STRING));
+        }
         aTextSize = GetCapitalSize( rInf );
+    }
     else
     {
         SV_STAT( nGetTextSize );
@@ -1009,17 +1017,25 @@ Size SwSubFont::GetTextSize_( SwDrawTextInfo& rInf )
                 // a single snippet since its size may differ, too.
                 TextFrameIndex const nOldIdx(rInf.GetIdx());
                 TextFrameIndex const nOldLen(rInf.GetLen());
+                TextFrameIndex const nOldMeasureLen(rInf.GetMeasureLen());
                 const OUString aSnippet(oldStr.copy(sal_Int32(nOldIdx), 
sal_Int32(nOldLen)));
                 const OUString aNewText(CalcCaseMap(aSnippet));
 
                 rInf.SetText( aNewText );
                 rInf.SetIdx( TextFrameIndex(0) );
                 rInf.SetLen( TextFrameIndex(aNewText.getLength()) );
+                if (nOldMeasureLen != TextFrameIndex(COMPLETE_STRING))
+                {
+                    const OUString 
aMeasureSnippet(oldStr.copy(sal_Int32(nOldIdx), sal_Int32(nOldMeasureLen)));
+                    const OUString 
aNewMeasureText(CalcCaseMap(aMeasureSnippet));
+                    
rInf.SetMeasureLen(TextFrameIndex(aNewMeasureText.getLength()));
+                }
 
                 aTextSize = pLastFont->GetTextSize( rInf );
 
                 rInf.SetIdx( nOldIdx );
                 rInf.SetLen( nOldLen );
+                rInf.SetMeasureLen(nOldMeasureLen);
             }
             else
             {
diff --git a/vcl/inc/sallayout.hxx b/vcl/inc/sallayout.hxx
index 165a6170bbc2..0210161b83d2 100644
--- a/vcl/inc/sallayout.hxx
+++ b/vcl/inc/sallayout.hxx
@@ -62,7 +62,7 @@ class MultiSalLayout final : public SalLayout
 public:
     void            DrawText(SalGraphics&) const override;
     sal_Int32       GetTextBreak(DeviceCoordinate nMaxWidth, DeviceCoordinate 
nCharExtra, int nFactor) const override;
-    DeviceCoordinate FillDXArray(std::vector<DeviceCoordinate>* pDXArray) 
const override;
+    DeviceCoordinate FillDXArray(std::vector<DeviceCoordinate>* pDXArray, 
const OUString& rStr) const override;
     void            GetCaretPositions(int nArraySize, sal_Int32* pCaretXArray) 
const override;
     bool            GetNextGlyph(const GlyphItem** pGlyph, DevicePoint& rPos, 
int& nStart,
                                  const LogicalFontInstance** ppGlyphFont = 
nullptr,
@@ -118,7 +118,7 @@ public:
 
     // used by upper layers
     DeviceCoordinate GetTextWidth() const final override;
-    DeviceCoordinate FillDXArray(std::vector<DeviceCoordinate>* pDXArray) 
const final override;
+    DeviceCoordinate FillDXArray(std::vector<DeviceCoordinate>* pDXArray, 
const OUString& rStr) const final override;
     sal_Int32 GetTextBreak(DeviceCoordinate nMaxWidth, DeviceCoordinate 
nCharExtra, int nFactor) const final override;
     void            GetCaretPositions(int nArraySize, sal_Int32* pCaretXArray) 
const final override;
 
@@ -145,7 +145,8 @@ private:
     void            Justify(DeviceCoordinate nNewWidth);
     void            ApplyAsianKerning(const OUString& rStr);
 
-    void            GetCharWidths(std::vector<DeviceCoordinate>& rCharWidths) 
const;
+    void            GetCharWidths(std::vector<DeviceCoordinate>& rCharWidths,
+                                  const OUString& rStr) const;
 
     void            SetNeedFallback(vcl::text::ImplLayoutArgs&, sal_Int32, 
bool);
 
diff --git a/vcl/qa/cppunit/complextext.cxx b/vcl/qa/cppunit/complextext.cxx
index 6c35fd740b33..0b76f5eb91d9 100644
--- a/vcl/qa/cppunit/complextext.cxx
+++ b/vcl/qa/cppunit/complextext.cxx
@@ -52,12 +52,14 @@ public:
     void testTdf95650(); // Windows-only issue
     void testCaching();
     void testCachingSubstring();
+    void testCaret();
 
     CPPUNIT_TEST_SUITE(VclComplexTextTest);
     CPPUNIT_TEST(testArabic);
     CPPUNIT_TEST(testTdf95650);
     CPPUNIT_TEST(testCaching);
     CPPUNIT_TEST(testCachingSubstring);
+    CPPUNIT_TEST(testCaret);
     CPPUNIT_TEST_SUITE_END();
 };
 
@@ -231,6 +233,86 @@ void VclComplexTextTest::testCachingSubstring()
     testCachedGlyphsSubstring( text, "Dejavu Sans", false );
 }
 
+void VclComplexTextTest::testCaret()
+{
+#if HAVE_MORE_FONTS
+    ScopedVclPtrInstance<WorkWindow> pWin(static_cast<vcl::Window *>(nullptr));
+    CPPUNIT_ASSERT( pWin );
+
+    vcl::Font aFont("DejaVu Sans", "Book", Size(0, 200));
+
+    OutputDevice *pOutDev = pWin->GetOutDev();
+    pOutDev->SetFont( aFont );
+
+    OUString aText;
+    std::vector<sal_Int32> aCharWidths, aRefCharWidths;
+    tools::Long nTextWidth, nTextWidth2;
+
+    // A. RTL text
+    aText = u"لا بلا";
+
+    // 1) Regular DX array, the ligature width is given to the first components
+    // and the next ones are all zero width.
+    aRefCharWidths = { 114, 114, 178, 234, 353, 353 };
+    aCharWidths.resize(aText.getLength());
+    std::fill(aCharWidths.begin(), aCharWidths.end(), 0);
+    nTextWidth = pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, 
/*bCaret*/false);
+    CPPUNIT_ASSERT_EQUAL(aRefCharWidths, aCharWidths);
+    CPPUNIT_ASSERT_EQUAL(tools::Long(353), nTextWidth);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(nTextWidth), aCharWidths.back());
+
+    // 2) Caret placement DX array, ligature width is distributed over its
+    // components.
+    aRefCharWidths = { 57, 114, 178, 234, 293, 353 };
+    aCharWidths.resize(aText.getLength());
+    std::fill(aCharWidths.begin(), aCharWidths.end(), 0);
+    nTextWidth = pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, 
/*bCaret*/true);
+    CPPUNIT_ASSERT_EQUAL(aRefCharWidths, aCharWidths);
+    CPPUNIT_ASSERT_EQUAL(tools::Long(353), nTextWidth);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(nTextWidth), aCharWidths.back());
+
+    // 3) caret placement with combining marks, they should not add to ligature
+    // component count.
+    aText = u"لَاَ بلَاَ";
+    aRefCharWidths = { 57, 57, 114, 114, 178, 234, 293, 293, 353, 353 };
+    aCharWidths.resize(aText.getLength());
+    std::fill(aCharWidths.begin(), aCharWidths.end(), 0);
+    nTextWidth2 = pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, 
/*bCaret*/true);
+    CPPUNIT_ASSERT_EQUAL(aCharWidths[0], aCharWidths[1]);
+    CPPUNIT_ASSERT_EQUAL(aCharWidths[2], aCharWidths[3]);
+    CPPUNIT_ASSERT_EQUAL(aCharWidths[6], aCharWidths[7]);
+    CPPUNIT_ASSERT_EQUAL(aCharWidths[8], aCharWidths[9]);
+    CPPUNIT_ASSERT_EQUAL(aRefCharWidths, aCharWidths);
+    // FIXME: this should be 353, and the next assert should be true as well.
+    CPPUNIT_ASSERT_EQUAL(tools::Long(388), nTextWidth2);
+    //CPPUNIT_ASSERT_EQUAL(nTextWidth, nTextWidth2);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(nTextWidth), aCharWidths.back());
+
+    // B. LTR text
+    aText = u"fi fl ffi ffl";
+
+    // 1) Regular DX array, the ligature width is given to the first components
+    // and the next ones are all zero width.
+    aRefCharWidths = { 126, 126, 190, 316, 316, 380, 573, 573, 573, 637, 830, 
830, 830 };
+    aCharWidths.resize(aText.getLength());
+    std::fill(aCharWidths.begin(), aCharWidths.end(), 0);
+    nTextWidth = pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, 
/*bCaret*/false);
+    CPPUNIT_ASSERT_EQUAL(aRefCharWidths, aCharWidths);
+    CPPUNIT_ASSERT_EQUAL(tools::Long(830), nTextWidth);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(nTextWidth), aCharWidths.back());
+
+    // 2) Caret placement DX array, ligature width is distributed over its
+    // components.
+    aRefCharWidths = { 63, 126, 190, 253, 316, 380, 444, 508, 573, 637, 701, 
765, 830 };
+    aCharWidths.resize(aText.getLength());
+    std::fill(aCharWidths.begin(), aCharWidths.end(), 0);
+    nTextWidth = pOutDev->GetTextArray(aText, &aCharWidths, 0, -1, 
/*bCaret*/true);
+    CPPUNIT_ASSERT_EQUAL(aRefCharWidths, aCharWidths);
+    CPPUNIT_ASSERT_EQUAL(tools::Long(830), nTextWidth);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(nTextWidth), aCharWidths.back());
+#endif
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(VclComplexTextTest);
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/gdi/CommonSalLayout.cxx 
b/vcl/source/gdi/CommonSalLayout.cxx
index fc28200ff98a..f75dc12dedd0 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -26,6 +26,7 @@
 #include <vcl/unohelp.hxx>
 #include <vcl/font/Feature.hxx>
 #include <vcl/font/FeatureParser.hxx>
+#include <vcl/svapp.hxx>
 
 #include <ImplLayoutArgs.hxx>
 #include <TextLayoutCache.hxx>
@@ -638,19 +639,58 @@ bool 
GenericSalLayout::LayoutText(vcl::text::ImplLayoutArgs& rArgs, const SalLay
     return true;
 }
 
-void GenericSalLayout::GetCharWidths(std::vector<DeviceCoordinate>& 
rCharWidths) const
+void GenericSalLayout::GetCharWidths(std::vector<DeviceCoordinate>& 
rCharWidths, const OUString& rStr) const
 {
     const int nCharCount = mnEndCharPos - mnMinCharPos;
 
     rCharWidths.clear();
     rCharWidths.resize(nCharCount, 0);
 
+    css::uno::Reference<css::i18n::XBreakIterator> xBreak;
+    auto aLocale(maLanguageTag.getLocale());
+
     for (auto const& aGlyphItem : m_GlyphItems)
     {
-        const int nIndex = aGlyphItem.charPos() - mnMinCharPos;
-        if (nIndex >= nCharCount)
+        if (aGlyphItem.charPos() >= mnEndCharPos)
             continue;
-        rCharWidths[nIndex] += aGlyphItem.newWidth();
+        if (aGlyphItem.charCount() > 1 && aGlyphItem.newWidth() != 0 && 
!rStr.isEmpty())
+        {
+            // We are calculating DX array for cursor positions and this is a
+            // ligature, we want to distribute the glyph width over the
+            // ligature components.
+            if (!xBreak.is())
+                xBreak = mxBreak.is() ? mxBreak : 
vcl::unohelper::CreateBreakIterator();
+
+            sal_Int32 nDone;
+            sal_Int32 nPos = aGlyphItem.charPos();
+            unsigned int nGraphemeCount = 0;
+
+            // Count grapheme clusters in the ligatures.
+            while (nPos < aGlyphItem.charPos() + aGlyphItem.charCount())
+            {
+                nPos = xBreak->nextCharacters(rStr, nPos, aLocale,
+                    css::i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
+                nGraphemeCount++;
+            }
+
+            // Set the width of each grapheme cluster.
+            nPos = aGlyphItem.charPos();
+            auto nWidth = aGlyphItem.newWidth() / nGraphemeCount;
+            // rounding difference
+            auto nDiff = aGlyphItem.newWidth() - (nWidth * nGraphemeCount);
+            for (unsigned int i = 0; i < nGraphemeCount; i++)
+            {
+                rCharWidths[nPos - mnMinCharPos] += nWidth;
+                // add rounding difference to last component to maintain
+                // ligature width.
+                if (i == nGraphemeCount - 1)
+                    rCharWidths[nPos - mnMinCharPos] += nDiff;
+                nPos = xBreak->nextCharacters(rStr, nPos, aLocale,
+                    css::i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
+            }
+        }
+        else
+            rCharWidths[aGlyphItem.charPos() - mnMinCharPos] += 
aGlyphItem.newWidth();
     }
 }
 
@@ -665,7 +705,7 @@ void GenericSalLayout::ApplyDXArray(const double* pDXArray, 
const sal_Bool* pKas
     std::unique_ptr<double[]> const pNewCharWidths(new double[nCharCount]);
 
     // Get the natural character widths (i.e. before applying DX adjustments).
-    GetCharWidths(aOldCharWidths);
+    GetCharWidths(aOldCharWidths, {});
 
     // Calculate the character widths after DX adjustments.
     for (int i = 0; i < nCharCount; ++i)
diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx
index eca07148ed53..6d22b302b6c5 100644
--- a/vcl/source/gdi/sallayout.cxx
+++ b/vcl/source/gdi/sallayout.cxx
@@ -133,6 +133,7 @@ sal_UCS4 GetLocalizedChar( sal_UCS4 nChar, LanguageType 
eLang )
 SalLayout::SalLayout()
 :   mnMinCharPos( -1 ),
     mnEndCharPos( -1 ),
+    maLanguageTag( LANGUAGE_DONTKNOW ),
     mnUnitsPerPixel( 1 ),
     mnOrientation( 0 ),
     maDrawOffset( 0, 0 ),
@@ -147,6 +148,7 @@ void SalLayout::AdjustLayout( vcl::text::ImplLayoutArgs& 
rArgs )
     mnMinCharPos  = rArgs.mnMinCharPos;
     mnEndCharPos  = rArgs.mnEndCharPos;
     mnOrientation = rArgs.mnOrientation;
+    maLanguageTag = rArgs.maLanguageTag;
 }
 
 DevicePoint SalLayout::GetDrawPosition(const DevicePoint& rRelative) const
@@ -263,10 +265,10 @@ SalLayoutGlyphs SalLayout::GetGlyphs() const
     return SalLayoutGlyphs(); // invalid
 }
 
-DeviceCoordinate GenericSalLayout::FillDXArray( std::vector<DeviceCoordinate>* 
pCharWidths ) const
+DeviceCoordinate GenericSalLayout::FillDXArray( std::vector<DeviceCoordinate>* 
pCharWidths, const OUString& rStr ) const
 {
     if (pCharWidths)
-        GetCharWidths(*pCharWidths);
+        GetCharWidths(*pCharWidths, rStr);
 
     return GetTextWidth();
 }
@@ -494,7 +496,7 @@ void GenericSalLayout::GetCaretPositions( int nMaxIndex, 
sal_Int32* pCaretXArray
 sal_Int32 GenericSalLayout::GetTextBreak( DeviceCoordinate nMaxWidth, 
DeviceCoordinate nCharExtra, int nFactor ) const
 {
     std::vector<DeviceCoordinate> aCharWidths;
-    GetCharWidths(aCharWidths);
+    GetCharWidths(aCharWidths, {});
 
     DeviceCoordinate nWidth = 0;
     for( int i = mnMinCharPos; i < mnEndCharPos; ++i )
@@ -675,7 +677,7 @@ void MultiSalLayout::AdjustLayout( 
vcl::text::ImplLayoutArgs& rArgs )
             mpLayouts[n]->SalLayout::AdjustLayout( aMultiArgs );
         // then we can measure the unmodified metrics
         int nCharCount = rArgs.mnEndCharPos - rArgs.mnMinCharPos;
-        FillDXArray( &aJustificationArray );
+        FillDXArray( &aJustificationArray, {} );
         // #i17359# multilayout is not simplified yet, so calculating the
         // unjustified width needs handholding; also count the number of
         // stretchable virtual char widths
@@ -1039,12 +1041,12 @@ sal_Int32 MultiSalLayout::GetTextBreak( 
DeviceCoordinate nMaxWidth, DeviceCoordi
     int nCharCount = mnEndCharPos - mnMinCharPos;
     std::vector<DeviceCoordinate> aCharWidths;
     std::vector<DeviceCoordinate> aFallbackCharWidths;
-    mpLayouts[0]->FillDXArray( &aCharWidths );
+    mpLayouts[0]->FillDXArray( &aCharWidths, {} );
 
     for( int n = 1; n < mnLevel; ++n )
     {
         SalLayout& rLayout = *mpLayouts[ n ];
-        rLayout.FillDXArray( &aFallbackCharWidths );
+        rLayout.FillDXArray( &aFallbackCharWidths, {} );
         double fUnitMul = mnUnitsPerPixel;
         fUnitMul /= rLayout.GetUnitsPerPixel();
         for( int i = 0; i < nCharCount; ++i )
@@ -1070,7 +1072,7 @@ sal_Int32 MultiSalLayout::GetTextBreak( DeviceCoordinate 
nMaxWidth, DeviceCoordi
     return -1;
 }
 
-DeviceCoordinate MultiSalLayout::FillDXArray( std::vector<DeviceCoordinate>* 
pCharWidths ) const
+DeviceCoordinate MultiSalLayout::FillDXArray( std::vector<DeviceCoordinate>* 
pCharWidths, const OUString& rStr ) const
 {
     DeviceCoordinate nMaxWidth = 0;
 
@@ -1086,7 +1088,7 @@ DeviceCoordinate MultiSalLayout::FillDXArray( 
std::vector<DeviceCoordinate>* pCh
     for( int n = mnLevel; --n >= 0; )
     {
         // query every fallback level
-        DeviceCoordinate nTextWidth = mpLayouts[n]->FillDXArray( &aTempWidths 
);
+        DeviceCoordinate nTextWidth = mpLayouts[n]->FillDXArray( &aTempWidths, 
rStr );
         if( !nTextWidth )
             continue;
         // merge results from current level
diff --git a/vcl/source/outdev/text.cxx b/vcl/source/outdev/text.cxx
index 0cf0283dc5c7..d5969c7a0092 100644
--- a/vcl/source/outdev/text.cxx
+++ b/vcl/source/outdev/text.cxx
@@ -889,7 +889,7 @@ tools::Long OutputDevice::GetTextWidth( const OUString& 
rStr, sal_Int32 nIndex,
 {
 
     tools::Long nWidth = GetTextArray( rStr, nullptr, nIndex,
-            nLen, pLayoutCache, pSalLayoutCache );
+            nLen, false, pLayoutCache, pSalLayoutCache );
 
     return nWidth;
 }
@@ -956,7 +956,7 @@ void OutputDevice::DrawTextArray( const Point& rStartPt, 
const OUString& rStr,
 }
 
 tools::Long OutputDevice::GetTextArray( const OUString& rStr, 
std::vector<sal_Int32>* pDXAry,
-                                 sal_Int32 nIndex, sal_Int32 nLen,
+                                 sal_Int32 nIndex, sal_Int32 nLen, bool bCaret,
                                  vcl::text::TextLayoutCache const*const 
pLayoutCache,
                                  SalLayoutGlyphs const*const pSalLayoutCache) 
const
 {
@@ -994,7 +994,7 @@ tools::Long OutputDevice::GetTextArray( const OUString& 
rStr, std::vector<sal_In
         xDXPixelArray.reset(new std::vector<DeviceCoordinate>(nLen));
     }
     std::vector<DeviceCoordinate>* pDXPixelArray = xDXPixelArray.get();
-    DeviceCoordinate nWidth = pSalLayout->FillDXArray(pDXPixelArray);
+    DeviceCoordinate nWidth = pSalLayout->FillDXArray(pDXPixelArray, bCaret ? 
rStr : OUString());
     int nWidthFactor = pSalLayout->GetUnitsPerPixel();
 
     // convert virtual char widths to virtual absolute positions
@@ -1039,7 +1039,7 @@ tools::Long OutputDevice::GetTextArray( const OUString& 
rStr, std::vector<sal_In
 
 #else /* ! VCL_FLOAT_DEVICE_PIXEL */
 
-    tools::Long nWidth = pSalLayout->FillDXArray( pDXAry );
+    tools::Long nWidth = pSalLayout->FillDXArray( pDXAry, bCaret ? rStr : 
OUString() );
     int nWidthFactor = pSalLayout->GetUnitsPerPixel();
 
     // convert virtual char widths to virtual absolute positions

Reply via email to