include/basegfx/tuple/Tuple2D.hxx        |    6 
 include/vcl/devicecoordinate.hxx         |   11 -
 include/vcl/outdev.hxx                   |   10 +
 include/vcl/vcllayout.hxx                |   17 +-
 sw/qa/extras/layout/layout.cxx           |    2 
 sw/source/core/inc/fntcache.hxx          |    8 -
 sw/source/core/inc/scriptinfo.hxx        |   10 -
 sw/source/core/text/itradj.cxx           |    6 
 sw/source/core/text/porlay.cxx           |   10 -
 sw/source/core/text/portxt.cxx           |    4 
 sw/source/core/txtnode/fntcache.cxx      |  201 ++++++++++---------------------
 sw/source/uibase/config/usrpref.cxx      |    2 
 vcl/inc/ImplLayoutArgs.hxx               |    6 
 vcl/inc/impglyphitem.hxx                 |    4 
 vcl/inc/quartz/salgdi.h                  |    4 
 vcl/inc/salgdi.hxx                       |   11 +
 vcl/inc/sallayout.hxx                    |   18 ++
 vcl/inc/skia/osx/gdiimpl.hxx             |    3 
 vcl/inc/skia/win/gdiimpl.hxx             |    4 
 vcl/inc/win/DWriteTextRenderer.hxx       |   17 +-
 vcl/inc/win/salgdi.h                     |    2 
 vcl/inc/win/winlayout.hxx                |    8 -
 vcl/qt5/QtGraphics_Text.cxx              |   21 ++-
 vcl/quartz/salgdi.cxx                    |   16 +-
 vcl/skia/gdiimpl.cxx                     |    4 
 vcl/skia/osx/gdiimpl.cxx                 |   11 +
 vcl/skia/win/gdiimpl.cxx                 |   78 ++++++++++--
 vcl/skia/x11/textrender.cxx              |   18 ++
 vcl/source/gdi/CommonSalLayout.cxx       |   35 ++---
 vcl/source/gdi/pdfwriter_impl.cxx        |   28 ++--
 vcl/source/gdi/salgdilayout.cxx          |    3 
 vcl/source/gdi/sallayout.cxx             |  102 +++++++++------
 vcl/source/gdi/virdev.cxx                |    2 
 vcl/source/outdev/font.cxx               |   10 -
 vcl/source/outdev/map.cxx                |   25 +++
 vcl/source/outdev/outdev.cxx             |   19 ++
 vcl/source/outdev/text.cxx               |  150 ++++++++++++++---------
 vcl/source/outdev/textline.cxx           |   18 +-
 vcl/source/text/ImplLayoutArgs.cxx       |   18 ++
 vcl/unx/generic/gdi/cairotextrender.cxx  |   23 ++-
 vcl/unx/generic/print/genpspgraphics.cxx |    4 
 vcl/win/gdi/DWriteTextRenderer.cxx       |   42 ++----
 vcl/win/gdi/winlayout.cxx                |   31 +++-
 43 files changed, 618 insertions(+), 404 deletions(-)

New commits:
commit f793891368d1fbe47b6dc119a89a1cd3e7a40082
Author:     Caolán McNamara <caol...@redhat.com>
AuthorDate: Mon Dec 20 11:38:47 2021 +0000
Commit:     Andras Timar <andras.ti...@collabora.com>
CommitDate: Tue Mar 15 08:07:10 2022 +0100

    tdf#144862 use resolution independent positions for writer's 
screen-rendering
    
    in favor of pushing it down to the text renderers and leave
    it to them to optimized as best they can the the rendering
    to make it look as well as possible.
    
    Change-Id: Ic0849c091a36e1a90453771b1c91b8ff706b679e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/128418
    Tested-by: Caolán McNamara <caol...@redhat.com>
    Reviewed-by: Caolán McNamara <caol...@redhat.com>
    (cherry picked from commit 4ed26badfd6fd9190cb6e54078b41eb38cb37dca)

diff --git a/include/basegfx/tuple/Tuple2D.hxx 
b/include/basegfx/tuple/Tuple2D.hxx
index 2007732543b6..b173ad3033c1 100644
--- a/include/basegfx/tuple/Tuple2D.hxx
+++ b/include/basegfx/tuple/Tuple2D.hxx
@@ -73,6 +73,12 @@ public:
     /// Set Y-Coordinate of 2D Tuple
     void setY(TYPE fY) { mnY = fY; }
 
+    /// Adjust X-Coordinate of 2D Tuple
+    void adjustX(TYPE fX) { mnX += fX; }
+
+    /// Adjust Y-Coordinate of 2D Tuple
+    void adjustY(TYPE fY) { mnY += fY; }
+
     // comparators with tolerance
 
     template <typename T = TYPE, std::enable_if_t<std::is_integral_v<T>, int> 
= 0>
diff --git a/include/vcl/devicecoordinate.hxx b/include/vcl/devicecoordinate.hxx
index acece32cc204..bd0bf1ee7963 100644
--- a/include/vcl/devicecoordinate.hxx
+++ b/include/vcl/devicecoordinate.hxx
@@ -7,23 +7,22 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
-#ifndef INCLUDED_VCL_DEVICE_COORDINATE_HXX
-#define INCLUDED_VCL_DEVICE_COORDINATE_HXX
+#pragma once
 
 #include <config_vcl.h>
 #include <tools/long.hxx>
 
-#if VCL_FLOAT_DEVICE_PIXEL
 #include <basegfx/point/b2dpoint.hxx>
+typedef basegfx::B2DPoint DevicePoint;
+
+#if VCL_FLOAT_DEVICE_PIXEL
+
 typedef double DeviceCoordinate;
 
 #else /* !VCL_FLOAT_DEVICE_PIXEL */
 
-#include <basegfx/point/b2ipoint.hxx>
 typedef sal_Int32 DeviceCoordinate;
 
 #endif /* ! Carpet Cushion */
 
-#endif /* NDef INCLUDED_VCL_DEVICE_COORDINATE_HXX */
-
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx
index e8011412955c..85670e44dec3 100644
--- a/include/vcl/outdev.hxx
+++ b/include/vcl/outdev.hxx
@@ -242,6 +242,7 @@ private:
     Point                           maRefPoint;
     AntialiasingFlags               mnAntialiasing;
     LanguageType                    meTextLanguage;
+    bool mbTextRenderModeForResolutionIndependentLayout;
 
     mutable bool                    mbMap : 1;
     mutable bool                    mbClipRegion : 1;
@@ -489,6 +490,10 @@ public:
     void                        SetAntialiasing( AntialiasingFlags nMode );
     AntialiasingFlags           GetAntialiasing() const { return 
mnAntialiasing; }
 
+    // Render glyphs with a mode suitable for rendering of 
resolution-independent layout positions.
+    void                        
SetTextRenderModeForResolutionIndependentLayout(bool bMode);
+    bool                        
GetTextRenderModeForResolutionIndependentLayout() const { return 
mbTextRenderModeForResolutionIndependentLayout; }
+
     void                        SetDrawMode( DrawModeFlags nDrawMode );
     DrawModeFlags               GetDrawMode() const { return mnDrawMode; }
 
@@ -1244,8 +1249,9 @@ public:
                                             o3tl::span<const sal_Int32> 
pLogicDXArray={}, SalLayoutFlags flags = SalLayoutFlags::NONE,
                                             vcl::text::TextLayoutCache const* 
= nullptr,
                                             const SalLayoutGlyphs* pGlyphs = 
nullptr) const;
+
     SAL_DLLPRIVATE vcl::text::ImplLayoutArgs ImplPrepareLayoutArgs( OUString&, 
const sal_Int32 nIndex, const sal_Int32 nLen,
-                                                         DeviceCoordinate 
nPixelWidth, const DeviceCoordinate* pPixelDXArray,
+                                                         DeviceCoordinate 
nPixelWidth,
                                                          SalLayoutFlags flags 
= SalLayoutFlags::NONE,
                                                          
vcl::text::TextLayoutCache const* = nullptr) const;
     SAL_DLLPRIVATE std::unique_ptr<SalLayout>
@@ -1693,6 +1699,7 @@ public:
      @returns Physical point on the device.
      */
     SAL_DLLPRIVATE Point        ImplLogicToDevicePixel( const Point& rLogicPt 
) const;
+    SAL_DLLPRIVATE DevicePoint  ImplLogicToDeviceFontCoordinate(const Point& 
rLogicPt) const;
 
     /** Convert a logical width to a width in units of device pixels.
 
@@ -1705,6 +1712,7 @@ public:
      @returns Width in units of device pixels.
      */
     SAL_DLLPRIVATE tools::Long         ImplLogicWidthToDevicePixel( 
tools::Long nWidth ) const;
+    SAL_DLLPRIVATE double              
ImplLogicWidthToDeviceFontWidth(tools::Long nWidth) const;
 
     SAL_DLLPRIVATE DeviceCoordinate LogicWidthToDeviceCoordinate( tools::Long 
nWidth ) const;
 
diff --git a/include/vcl/vcllayout.hxx b/include/vcl/vcllayout.hxx
index 6ea9bc61bfbb..18d4da907375 100644
--- a/include/vcl/vcllayout.hxx
+++ b/include/vcl/vcllayout.hxx
@@ -70,11 +70,11 @@ class VCL_DLLPUBLIC SalLayout
 public:
     virtual         ~SalLayout();
     // used by upper layers
-    Point&          DrawBase()                              { return 
maDrawBase; }
-    const Point&    DrawBase() const                        { return 
maDrawBase; }
+    DevicePoint&    DrawBase()                              { return 
maDrawBase; }
+    const DevicePoint& DrawBase() const                     { return 
maDrawBase; }
     Point&          DrawOffset()                            { return 
maDrawOffset; }
     const Point&    DrawOffset() const                      { return 
maDrawOffset; }
-    Point           GetDrawPosition( const Point& rRelative = Point(0,0) ) 
const;
+    DevicePoint     GetDrawPosition( const DevicePoint& rRelative = 
DevicePoint(0,0) ) const;
 
     virtual bool    LayoutText( vcl::text::ImplLayoutArgs&, const 
SalLayoutGlyphsImpl* ) = 0;  // first step of layouting
     virtual void    AdjustLayout( vcl::text::ImplLayoutArgs& );    // 
adjusting after fallback etc.
@@ -84,6 +84,11 @@ public:
     int             GetUnitsPerPixel() const                { return 
mnUnitsPerPixel; }
     Degree10        GetOrientation() const                  { return 
mnOrientation; }
 
+    void            SetTextRenderModeForResolutionIndependentLayout(bool 
bTextRenderModeForResolutionIndependentLayout)
+    {
+        mbTextRenderModeForResolutionIndependentLayout = 
bTextRenderModeForResolutionIndependentLayout;
+    }
+
     // 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;
@@ -92,7 +97,7 @@ public:
     virtual bool    IsKashidaPosValid ( int /*nCharPos*/ ) const { return 
true; } // i60594
 
     // methods using glyph indexing
-    virtual bool    GetNextGlyph(const GlyphItem** pGlyph, Point& rPos, int& 
nStart,
+    virtual bool    GetNextGlyph(const GlyphItem** pGlyph, DevicePoint& rPos, 
int& nStart,
                                  const LogicalFontInstance** ppGlyphFont = 
nullptr,
                                  const vcl::font::PhysicalFontFace** 
pFallbackFont = nullptr) const = 0;
     virtual bool GetOutline(basegfx::B2DPolyPolygonVector&) const;
@@ -116,7 +121,9 @@ protected:
     Degree10        mnOrientation;
 
     mutable Point   maDrawOffset;
-    Point           maDrawBase;
+    DevicePoint     maDrawBase;
+
+    bool            mbTextRenderModeForResolutionIndependentLayout;
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/extras/layout/layout.cxx b/sw/qa/extras/layout/layout.cxx
index 94edf650a359..267c20770bef 100644
--- a/sw/qa/extras/layout/layout.cxx
+++ b/sw/qa/extras/layout/layout.cxx
@@ -2823,7 +2823,7 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testBtlrCell)
     // Without the accompanying fix in place, this test would have failed with 
'Expected: 1979;
     // Actual  : 2129', i.e. the gray background of the "AAA2." text was too 
close to the right edge
     // of the text portion. Now it's exactly behind the text portion.
-    assertXPath(pXmlDoc, "//rect[@top='2159']", "left", "1979");
+    assertXPath(pXmlDoc, "(//rect)[2]", "left", "1979");
 
     // Without the accompanying fix in place, this test would have failed with 
'Expected: 269;
     // Actual  : 0', i.e. the AAA2 frame was not visible due to 0 width.
diff --git a/sw/source/core/inc/fntcache.hxx b/sw/source/core/inc/fntcache.hxx
index 0bdc4757d9b3..4285165a3336 100644
--- a/sw/source/core/inc/fntcache.hxx
+++ b/sw/source/core/inc/fntcache.hxx
@@ -66,13 +66,13 @@ extern SwFntObj *pLastFont;
  */
 struct SwTextGlyphsKey
 {
-    VclPtr<OutputDevice> m_pOutputDevice;
+    VclPtr<const OutputDevice> m_pOutputDevice;
     OUString m_aText;
     sal_Int32 m_nIndex;
     sal_Int32 m_nLength;
     size_t mnHashCode;
 
-    SwTextGlyphsKey(VclPtr<OutputDevice> const& pOutputDevice, const OUString 
& sText, sal_Int32 nIndex, sal_Int32 nLength);
+    SwTextGlyphsKey(const OutputDevice* pOutputDevice, const OUString & sText, 
sal_Int32 nIndex, sal_Int32 nLength);
     bool operator==(SwTextGlyphsKey const & rhs) const;
 };
 struct SwTextGlyphsKeyHash
@@ -113,6 +113,10 @@ class SwFntObj final : public SwCacheObj
     /// Cache of already calculated layout glyphs and text widths.
     SwTextGlyphsMap m_aTextGlyphs;
 
+    void GetTextArray(const OutputDevice& rOutputDevice, const OUString& rStr,
+                      std::vector<sal_Int32>& rDXAry, sal_Int32 nIndex, 
sal_Int32 nLen,
+                      bool bCaching);
+
     static tools::Long s_nPixWidth;
     static MapMode *s_pPixMap;
 
diff --git a/sw/source/core/inc/scriptinfo.hxx 
b/sw/source/core/inc/scriptinfo.hxx
index cd479034ed06..cfe9ef3e55fb 100644
--- a/sw/source/core/inc/scriptinfo.hxx
+++ b/sw/source/core/inc/scriptinfo.hxx
@@ -281,8 +281,6 @@ public:
             positions in the kerning array.
     @param  pKernArray
                 The printers kerning array. Optional.
-    @param  pScrArray
-                The screen kerning array. Optional.
     @param  nStt
                 Start referring to the paragraph.
     @param  nLen
@@ -291,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* pScrArray,
+    sal_Int32 KashidaJustify( sal_Int32* pKernArray,
           TextFrameIndex nStt, TextFrameIndex nLen, tools::Long nSpaceAdd = 0) 
const;
 
 /** Clears array of kashidas marked as invalid
@@ -354,8 +352,6 @@ public:
                 The String
     @param  pKernArray
                 The printers kerning array. Optional.
-    @param  pScrArray
-                The screen kerning array. Optional.
     @param  nIdx
                 Start referring to the paragraph.
     @param  nLen
@@ -365,7 +361,7 @@ public:
     @return The number of extra spaces in the given range
 */
     static TextFrameIndex ThaiJustify( const OUString& rText, sal_Int32* 
pKernArray,
-                                  sal_Int32* pScrArray, TextFrameIndex nIdx,
+                                  TextFrameIndex nIdx,
                                   TextFrameIndex nLen,
                                   TextFrameIndex nNumberOfBlanks = 
TextFrameIndex(0),
                                   tools::Long nSpaceAdd = 0 );
@@ -374,7 +370,7 @@ public:
             TextFrameIndex nPos, TextFrameIndex nEnd, LanguageType aLang);
 
     static void CJKJustify( const OUString& rText, sal_Int32* pKernArray,
-                                  sal_Int32* pScrArray, TextFrameIndex nStt,
+                                  TextFrameIndex nStt,
                                   TextFrameIndex nLen, LanguageType aLang,
                                   tools::Long nSpaceAdd, bool bIsSpaceStop );
 
diff --git a/sw/source/core/text/itradj.cxx b/sw/source/core/text/itradj.cxx
index d664602bf3ce..a952ce7649c2 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, nullptr, rItr.GetStart(), 
rItr.GetLength() );
+    rKashidas = rSI.KashidaJustify(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, nullptr, 
nIdx, nNext - nIdx );
+        sal_Int32 nKashidasInAttr = rSI.KashidaJustify(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, nullptr, 
nIdx, nNext - nIdx );
+            sal_Int32 nKashidasInAttr = rSI.KashidaJustify(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 3db5d2ab0ac3..bd9d6a0e143c 100644
--- a/sw/source/core/text/porlay.cxx
+++ b/sw/source/core/text/porlay.cxx
@@ -2183,7 +2183,6 @@ 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_Int32* pScrArray,
                                         TextFrameIndex const nStt,
                                         TextFrameIndex const nLen,
                                         tools::Long nSpaceAdd ) const
@@ -2253,8 +2252,6 @@ sal_Int32 SwScriptInfo::KashidaJustify( sal_Int32* 
pKernArray,
             while ( nArrayPos < nArrayEnd )
             {
                 pKernArray[ sal_Int32(nArrayPos) ] += nKashAdd;
-                if ( pScrArray )
-                    pScrArray[ sal_Int32(nArrayPos) ] += nKashAdd;
                 ++nArrayPos;
             }
             nKashAdd += nSpaceAdd;
@@ -2442,7 +2439,7 @@ void SwScriptInfo::MarkKashidasInvalid(sal_Int32 const 
nCnt,
 }
 
 TextFrameIndex SwScriptInfo::ThaiJustify( const OUString& rText, sal_Int32* 
pKernArray,
-                                     sal_Int32* pScrArray, TextFrameIndex 
const nStt,
+                                     TextFrameIndex const nStt,
                                      TextFrameIndex const nLen,
                                      TextFrameIndex nNumberOfBlanks,
                                      tools::Long nSpaceAdd )
@@ -2474,7 +2471,6 @@ TextFrameIndex SwScriptInfo::ThaiJustify( const OUString& 
rText, sal_Int32* pKer
         }
 
         if ( pKernArray ) pKernArray[ nI ] += nSpaceSum;
-        if ( pScrArray ) pScrArray[ nI ] += nSpaceSum;
     }
 
     return nCnt;
@@ -2775,7 +2771,7 @@ TextFrameIndex SwScriptInfo::CountCJKCharacters(const 
OUString &rText,
 }
 
 void SwScriptInfo::CJKJustify( const OUString& rText, sal_Int32* pKernArray,
-                                     sal_Int32* pScrArray, TextFrameIndex 
const nStt,
+                                     TextFrameIndex const nStt,
                                      TextFrameIndex const nLen, LanguageType 
aLang,
                                      tools::Long nSpaceAdd, bool bIsSpaceStop )
 {
@@ -2798,8 +2794,6 @@ void SwScriptInfo::CJKJustify( const OUString& rText, 
sal_Int32* pKernArray,
                 nSpaceSum += nSpaceAdd;
         }
         pKernArray[ nI ] += nSpaceSum;
-        if ( pScrArray )
-            pScrArray[ nI ] += nSpaceSum;
     }
 }
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/text/portxt.cxx b/sw/source/core/text/portxt.cxx
index 7def7badcc7a..219036aa834d 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, nullptr, 
nPos, nEnd - nPos );
+            const sal_Int32 nKashRes = pSI->KashidaJustify(nullptr, nPos, nEnd 
- nPos);
             // i60591: need to check result of KashidaJustify
             // determine if kashida justification is applicable
             if (nKashRes != -1)
@@ -129,7 +129,7 @@ static TextFrameIndex lcl_AddSpace(const SwTextSizeInfo 
&rInf,
 
         if ( LANGUAGE_THAI == aLang )
         {
-            nCnt = SwScriptInfo::ThaiJustify( *pStr, nullptr, nullptr, nPos, 
nEnd - nPos );
+            nCnt = SwScriptInfo::ThaiJustify(*pStr, nullptr, nPos, nEnd - 
nPos);
 
             const SwLinePortion* pPor = rPor.GetNextPortion();
             if ( pPor && ( pPor->IsKernPortion() ||
diff --git a/sw/source/core/txtnode/fntcache.cxx 
b/sw/source/core/txtnode/fntcache.cxx
index 93e83c2013e9..6ceaeaf99206 100644
--- a/sw/source/core/txtnode/fntcache.cxx
+++ b/sw/source/core/txtnode/fntcache.cxx
@@ -77,11 +77,11 @@ static vcl::DeleteOnDeinit< VclPtr<OutputDevice> > 
s_pFntObjPixOut {};
  * Defines a substring on a given output device, to be used as an 
std::unordered_map<>
  * key.
  */
-SwTextGlyphsKey::SwTextGlyphsKey(VclPtr<OutputDevice> const& pOutputDevice, 
const OUString & sText, sal_Int32 nIndex, sal_Int32 nLength)
+SwTextGlyphsKey::SwTextGlyphsKey(const OutputDevice* pOutputDevice, const 
OUString & sText, sal_Int32 nIndex, sal_Int32 nLength)
     : m_pOutputDevice(pOutputDevice), m_aText(sText), m_nIndex(nIndex), 
m_nLength(nLength)
 {
     mnHashCode = 0;
-    o3tl::hash_combine(mnHashCode, pOutputDevice.get());
+    o3tl::hash_combine(mnHashCode, pOutputDevice);
     o3tl::hash_combine(mnHashCode, m_nIndex);
     o3tl::hash_combine(mnHashCode, m_nLength);
     if(m_nLength >= 0 && m_nIndex >= 0 && m_nIndex + m_nLength <= 
m_aText.getLength())
@@ -855,6 +855,18 @@ static void lcl_DrawLineForWrongListData(
         rInf.GetOut().Pop();
 }
 
+void SwFntObj::GetTextArray(const OutputDevice& rDevice, const OUString& rStr, 
std::vector<sal_Int32>& rDXAry,
+                            sal_Int32 nIndex, sal_Int32 nLen, bool bCaching)
+{
+    SalLayoutGlyphs* pLayoutCache = nullptr;
+    if (bCaching)
+    {
+        SwTextGlyphsKey aGlyphsKey{&rDevice, rStr, nIndex, nLen};
+        pLayoutCache = GetCachedSalLayoutGlyphs(aGlyphsKey);
+    }
+    rDevice.GetTextArray(rStr, &rDXAry, nIndex, nLen, nullptr, pLayoutCache);
+}
+
 void SwFntObj::DrawText( SwDrawTextInfo &rInf )
 {
     OSL_ENSURE( rInf.GetShell(), "SwFntObj::DrawText without shell" );
@@ -1031,11 +1043,11 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
             std::vector<sal_Int32> aKernArray;
 
             if ( m_pPrinter )
-                m_pPrinter->GetTextArray( rInf.GetText(), &aKernArray,
-                            sal_Int32(rInf.GetIdx()), 
sal_Int32(rInf.GetLen()));
+                GetTextArray(*m_pPrinter, rInf.GetText(), aKernArray,
+                            sal_Int32(rInf.GetIdx()), 
sal_Int32(rInf.GetLen()), false);
             else
-                rInf.GetOut().GetTextArray( rInf.GetText(), &aKernArray,
-                            sal_Int32(rInf.GetIdx()), 
sal_Int32(rInf.GetLen()));
+                GetTextArray(rInf.GetOut(), rInf.GetText(), aKernArray,
+                            sal_Int32(rInf.GetIdx()), 
sal_Int32(rInf.GetLen()), false);
 
             // Change the average width per character to an appropriate grid 
width
             // basically get the ratio of the avg width to the grid unit 
width, then
@@ -1138,11 +1150,11 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
             std::vector<sal_Int32> aKernArray;
 
             if ( m_pPrinter )
-                m_pPrinter->GetTextArray( rInf.GetText(), &aKernArray,
-                    sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
+                GetTextArray(*m_pPrinter, rInf.GetText(), aKernArray,
+                    sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), false);
             else
-                rInf.GetOut().GetTextArray( rInf.GetText(), &aKernArray,
-                    sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
+                GetTextArray(rInf.GetOut(), rInf.GetText(), aKernArray,
+                    sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), false);
             if ( bSwitchH2V )
                 rInf.GetFrame()->SwitchHorizontalToVertical( aTextOriginPos );
             if ( rInf.GetSpace() || rInf.GetKanaComp())
@@ -1278,8 +1290,8 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
         if( rInf.GetSpace() || rInf.GetKanaComp() )
         {
             std::vector<sal_Int32> aKernArray;
-            rInf.GetOut().GetTextArray( rInf.GetText(), &aKernArray,
-                           sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
+            GetTextArray(rInf.GetOut(), rInf.GetText(), aKernArray,
+                         sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), 
false);
 
             if( bStretch )
             {
@@ -1337,7 +1349,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
 
                     if (!MsLangId::isKorean(aLang))
                     {
-                        SwScriptInfo::CJKJustify( rInf.GetText(), 
aKernArray.data(), nullptr,
+                        SwScriptInfo::CJKJustify( rInf.GetText(), 
aKernArray.data(),
                                 rInf.GetIdx(), rInf.GetLen(), aLang, 
nSpaceAdd, rInf.IsSpaceStop() );
 
                         bSpecialJust = true;
@@ -1351,7 +1363,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
                     if ( SwScriptInfo::IsArabicText( rInf.GetText(), 
rInf.GetIdx(), rInf.GetLen() ) )
                     {
                         if ( pSI && pSI->CountKashida() &&
-                            pSI->KashidaJustify( aKernArray.data(), nullptr, 
rInf.GetIdx(),
+                            pSI->KashidaJustify( aKernArray.data(), 
rInf.GetIdx(),
                                                  rInf.GetLen(), nSpaceAdd ) != 
-1 )
                         {
                             bSpecialJust = true;
@@ -1369,7 +1381,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
                     {
                         // Use rInf.GetSpace() because it has more precision 
than
                         // nSpaceAdd:
-                        SwScriptInfo::ThaiJustify( rInf.GetText(), 
aKernArray.data(), nullptr,
+                        SwScriptInfo::ThaiJustify( rInf.GetText(), 
aKernArray.data(),
                                                    rInf.GetIdx(), 
rInf.GetLen(),
                                                    rInf.GetNumberOfBlanks(),
                                                    rInf.GetSpace() );
@@ -1478,6 +1490,10 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
 
     else
     {
+        const bool 
bOrigTextRenderModeForResolutionIndependentLayout(rInf.GetOut().GetTextRenderModeForResolutionIndependentLayout());
+        // set text render mode to suit use of resolution independent text 
layout
+        rInf.GetOut().SetTextRenderModeForResolutionIndependentLayout(true);
+
         const OUString* pStr = &rInf.GetText();
 
         OUString aStr;
@@ -1487,14 +1503,6 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
             bBullet = false;
         std::vector<sal_Int32> aKernArray;
         CreateScrFont( *rInf.GetShell(), rInf.GetOut() );
-        tools::Long nScrPos;
-
-        // get screen array
-        std::vector<sal_Int32> aScrArray;
-        SwTextGlyphsKey aGlyphsKey{ &rInf.GetOut(), rInf.GetText(), 
sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()) };
-        SalLayoutGlyphs* pGlyphs = GetCachedSalLayoutGlyphs(aGlyphsKey);
-        rInf.GetOut().GetTextArray( rInf.GetText(), &aScrArray,
-                        sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), 
nullptr, pGlyphs);
 
         // OLE: no printer available
         // OSL_ENSURE( pPrinter, "DrawText needs pPrinter" )
@@ -1506,15 +1514,13 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
                 if( !m_pPrtFont->IsSameInstance( m_pPrinter->GetFont() ) )
                     m_pPrinter->SetFont( *m_pPrtFont );
             }
-            aGlyphsKey = SwTextGlyphsKey{ m_pPrinter, rInf.GetText(), 
sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()) };
-            pGlyphs = GetCachedSalLayoutGlyphs(aGlyphsKey);
-            m_pPrinter->GetTextArray(rInf.GetText(), &aKernArray,
-                    sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), 
nullptr, pGlyphs);
+            GetTextArray(*m_pPrinter, rInf.GetText(), aKernArray,
+                    sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), true);
         }
         else
         {
-            rInf.GetOut().GetTextArray( rInf.GetText(), &aKernArray,
-                    sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
+            GetTextArray(rInf.GetOut(), rInf.GetText(), aKernArray,
+                    sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), true);
         }
 
         // Modify Printer and ScreenArrays for special justifications
@@ -1532,10 +1538,6 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
                  pSI && pSI->CountCompChg() &&
                  lcl_IsMonoSpaceFont( rInf.GetOut() ) )
             {
-                Point aTmpPos( aTextOriginPos );
-                pSI->Compress( aScrArray.data(), rInf.GetIdx(), rInf.GetLen(),
-                               rInf.GetKanaComp(),
-                               
o3tl::narrowing<sal_uInt16>(m_aFont.GetFontSize().Height()), 
lcl_IsFullstopCentered( rInf.GetOut() ), &aTmpPos );
                 pSI->Compress( aKernArray.data(), rInf.GetIdx(), rInf.GetLen(),
                                rInf.GetKanaComp(),
                                
o3tl::narrowing<sal_uInt16>(m_aFont.GetFontSize().Height()), 
lcl_IsFullstopCentered( rInf.GetOut() ), &aTextOriginPos );
@@ -1548,7 +1550,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
 
                 if (!MsLangId::isKorean(aLang))
                 {
-                    SwScriptInfo::CJKJustify( rInf.GetText(), 
aKernArray.data(), aScrArray.data(),
+                    SwScriptInfo::CJKJustify( rInf.GetText(), 
aKernArray.data(),
                             rInf.GetIdx(), rInf.GetLen(), aLang, nSpaceAdd, 
rInf.IsSpaceStop() );
 
                     nSpaceAdd = 0;
@@ -1561,7 +1563,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
                 if ( SwScriptInfo::IsArabicText( rInf.GetText(), 
rInf.GetIdx(), rInf.GetLen() ) )
                 {
                     if ( pSI && pSI->CountKashida() &&
-                         pSI->KashidaJustify( aKernArray.data(), 
aScrArray.data(), rInf.GetIdx(),
+                         pSI->KashidaJustify( aKernArray.data(), rInf.GetIdx(),
                                               rInf.GetLen(), nSpaceAdd ) != -1 
)
                         nSpaceAdd = 0;
                     else
@@ -1577,7 +1579,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
                 if ( LANGUAGE_THAI == aLang )
                 {
                     SwScriptInfo::ThaiJustify( rInf.GetText(), 
aKernArray.data(),
-                                               aScrArray.data(), rInf.GetIdx(),
+                                               rInf.GetIdx(),
                                                rInf.GetLen(),
                                                rInf.GetNumberOfBlanks(),
                                                rInf.GetSpace() );
@@ -1588,8 +1590,6 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
             }
         }
 
-        nScrPos = aScrArray[ 0 ];
-
         if( bBullet )
         {
             // !!! HACK !!!
@@ -1661,13 +1661,6 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
         }
         else
         {
-            sal_Unicode nCh;
-
-            // In case of Pair Kerning the printer influence on the positioning
-            // grows
-            const int nMul = m_pPrtFont->GetKerning() != FontKerning::NONE ? 1 
: 3;
-            const int nDiv = nMul+1;
-
             // nSpaceSum contains the sum of the intermediate space distributed
             // among Spaces by the Justification.
             // The Spaces themselves will be positioned in the middle of the
@@ -1686,43 +1679,25 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
                 nSpaceSum = nHalfSpace;
             for (sal_Int32 i = 1; i < sal_Int32(nCnt); ++i, nKernSum += 
rInf.GetKern())
             {
-                nCh = rInf.GetText()[sal_Int32(rInf.GetIdx()) + i];
-
-                tools::Long nScr = aScrArray[ i ] - aScrArray[ i - 1 ];
+                sal_Unicode nCh = rInf.GetText()[sal_Int32(rInf.GetIdx()) + i];
 
-                // If there is an (ex-)Space before us, position optimally,
-                // i.e., our right margin to the 100% printer position;
-                // if we _are_ an ex-Space, position us left-aligned to the
-                // printer position.
-                if ( nCh == CH_BLANK )
+                // Apply SpaceSum
+                if (cChPrev == CH_BLANK)
                 {
-                    nScrPos = aKernArray[i-1] + nScr;
+                    // no Pixel is lost:
+                    nSpaceSum += nOtherHalf;
+                }
 
-                    if ( cChPrev == CH_BLANK )
-                        nSpaceSum += nOtherHalf;
+                if (nCh == CH_BLANK)
+                {
                     if (i + 1 == sal_Int32(nCnt))
                         nSpaceSum += nSpaceAdd;
                     else
                         nSpaceSum += nHalfSpace;
                 }
-                else
-                {
-                    if ( cChPrev == CH_BLANK )
-                    {
-                        nScrPos = aKernArray[i-1] + nScr;
-                        // no Pixel is lost:
-                        nSpaceSum += nOtherHalf;
-                    }
-                    else if ( cChPrev == '-' )
-                        nScrPos = aKernArray[i-1] + nScr;
-                    else
-                    {
-                        nScrPos += nScr;
-                        nScrPos = ( nMul * nScrPos + aKernArray[i] ) / nDiv;
-                    }
-                }
+
                 cChPrev = nCh;
-                aKernArray[i-1] = nScrPos - nScr + nKernSum + nSpaceSum;
+                aKernArray[i-1] += nKernSum + nSpaceSum;
                 // In word line mode and for Arabic, we disabled the half 
space trick. If a portion
                 // ends with a blank, the full nSpaceAdd value has been added 
to the character in
                 // front of the blank. This leads to painting artifacts, 
therefore we remove the
@@ -1843,8 +1818,8 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
                 sal_Int32 nTmpIdx = bBullet
                             ? (rInf.GetIdx() ? 1 : 0)
                             : sal_Int32(rInf.GetIdx());
-                aGlyphsKey = SwTextGlyphsKey{ &rInf.GetOut(), *pStr, nTmpIdx, 
nLen };
-                pGlyphs = GetCachedSalLayoutGlyphs(aGlyphsKey);
+                SwTextGlyphsKey aGlyphsKey{ &rInf.GetOut(), *pStr, nTmpIdx, 
nLen };
+                SalLayoutGlyphs* pGlyphs = 
GetCachedSalLayoutGlyphs(aGlyphsKey);
                 rInf.GetOut().DrawTextArray( aTextOriginPos, *pStr, aKernArray,
                                              nTmpIdx , nLen, 
SalLayoutFlags::NONE, pGlyphs );
                 if (bBullet)
@@ -1894,6 +1869,8 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
                 }
             }
         }
+
+        
rInf.GetOut().SetTextRenderModeForResolutionIndependentLayout(bOrigTextRenderModeForResolutionIndependentLayout);
     }
 }
 
@@ -1997,17 +1974,14 @@ Size SwFntObj::GetTextSize( SwDrawTextInfo& rInf )
     {
         if( !m_pPrtFont->IsSameInstance( m_pPrinter->GetFont() ) )
             m_pPrinter->SetFont(*m_pPrtFont);
-        aTextSize.setWidth( m_pPrinter->GetTextWidth( rInf.GetText(),
-                               sal_Int32(rInf.GetIdx()), sal_Int32(nLn)));
         aTextSize.setHeight( m_pPrinter->GetTextHeight() );
         std::vector<sal_Int32> aKernArray;
         CreateScrFont( *rInf.GetShell(), rInf.GetOut() );
         if( !GetScrFont()->IsSameInstance( rInf.GetOut().GetFont() ) )
             rInf.GetOut().SetFont( *m_pScrFont );
-        tools::Long nScrPos;
 
-        m_pPrinter->GetTextArray(rInf.GetText(), &aKernArray,
-                sal_Int32(rInf.GetIdx()), sal_Int32(nLn));
+        GetTextArray(*m_pPrinter, rInf.GetText(), aKernArray,
+                sal_Int32(rInf.GetIdx()), sal_Int32(nLn), false);
         if( bCompress )
             rInf.SetKanaDiff( rInf.GetScriptInfo()->Compress( 
aKernArray.data(),
                 rInf.GetIdx(), nLn, rInf.GetKanaComp(),
@@ -2015,50 +1989,7 @@ Size SwFntObj::GetTextSize( SwDrawTextInfo& rInf )
         else
             rInf.SetKanaDiff( 0 );
 
-        if ( rInf.GetKanaDiff() )
-            nScrPos = aKernArray[ sal_Int32(nLn) - 1 ];
-        else
-        {
-            std::vector<sal_Int32> aScrArray;
-            rInf.GetOut().GetTextArray( rInf.GetText(), &aScrArray,
-                        sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
-            nScrPos = aScrArray[ 0 ];
-            TextFrameIndex nCnt(rInf.GetText().getLength());
-            if ( nCnt < rInf.GetIdx() )
-                nCnt = TextFrameIndex(0); // assert???
-            else
-                nCnt = nCnt - rInf.GetIdx();
-            nCnt = std::min(nCnt, nLn);
-            sal_Unicode nChPrev = rInf.GetText()[ sal_Int32(rInf.GetIdx()) ];
-
-            sal_Unicode nCh;
-
-            // In case of Pair Kerning the printer influence on the positioning
-            // grows
-            const int nMul = m_pPrtFont->GetKerning() != FontKerning::NONE ? 1 
: 3;
-            const int nDiv = nMul+1;
-            for (sal_Int32 i = 1; i < sal_Int32(nCnt); i++)
-            {
-                nCh = rInf.GetText()[ sal_Int32(rInf.GetIdx()) + i ];
-                tools::Long nScr = aScrArray[ i ] - aScrArray[ i - 1 ];
-                if ( nCh == CH_BLANK )
-                    nScrPos = aKernArray[i-1]+nScr;
-                else
-                {
-                    if ( nChPrev == CH_BLANK || nChPrev == '-' )
-                        nScrPos = aKernArray[i-1]+nScr;
-                    else
-                    {
-                        nScrPos += nScr;
-                        nScrPos = ( nMul * nScrPos + aKernArray[i] ) / nDiv;
-                    }
-                }
-                nChPrev = nCh;
-                aKernArray[i-1] = nScrPos - nScr;
-            }
-        }
-
-        aTextSize.setWidth( nScrPos );
+        aTextSize.setWidth(aKernArray[sal_Int32(nLn) - 1]);
     }
     else
     {
@@ -2067,8 +1998,8 @@ Size SwFntObj::GetTextSize( SwDrawTextInfo& rInf )
         if( bCompress )
         {
             std::vector<sal_Int32> aKernArray;
-            rInf.GetOut().GetTextArray( rInf.GetText(), &aKernArray,
-                                sal_Int32(rInf.GetIdx()), sal_Int32(nLn));
+            GetTextArray(rInf.GetOut(), rInf.GetText(), aKernArray,
+                         sal_Int32(rInf.GetIdx()), sal_Int32(nLn), false);
             rInf.SetKanaDiff( rInf.GetScriptInfo()->Compress( 
aKernArray.data(),
                 rInf.GetIdx(), nLn, rInf.GetKanaComp(),
                 o3tl::narrowing<sal_uInt16>(m_aFont.GetFontSize().Height()) 
,lcl_IsFullstopCentered( rInf.GetOut() ) ) );
@@ -2110,14 +2041,14 @@ TextFrameIndex 
SwFntObj::GetModelPositionForViewPoint(SwDrawTextInfo &rInf)
     {
         m_pPrinter->SetLayoutMode( rInf.GetOut().GetLayoutMode() );
         m_pPrinter->SetDigitLanguage( rInf.GetOut().GetDigitLanguage() );
-        SwTextGlyphsKey aGlyphsKey{ m_pPrinter, rInf.GetText(), 
sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()) };
-        SalLayoutGlyphs* pGlyphs = GetCachedSalLayoutGlyphs(aGlyphsKey);
-        m_pPrinter->GetTextArray( rInf.GetText(), &aKernArray,
-                sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), nullptr, 
pGlyphs);
+        GetTextArray(*m_pPrinter, rInf.GetText(), aKernArray,
+                     sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), true);
     }
     else
-        rInf.GetOut().GetTextArray( rInf.GetText(), &aKernArray,
-                sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()));
+    {
+        GetTextArray(rInf.GetOut(), rInf.GetText(), aKernArray,
+                     sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), 
false);
+    }
 
     const SwScriptInfo* pSI = rInf.GetScriptInfo();
     if ( rInf.GetFont() && rInf.GetLen() )
@@ -2142,7 +2073,7 @@ TextFrameIndex 
SwFntObj::GetModelPositionForViewPoint(SwDrawTextInfo &rInf)
 
             if (!MsLangId::isKorean(aLang))
             {
-                SwScriptInfo::CJKJustify( rInf.GetText(), aKernArray.data(), 
nullptr,
+                SwScriptInfo::CJKJustify( rInf.GetText(), aKernArray.data(),
                         rInf.GetIdx(), rInf.GetLen(), aLang, nSpaceAdd, 
rInf.IsSpaceStop() );
 
                 nSpaceAdd = 0;
@@ -2156,7 +2087,7 @@ TextFrameIndex 
SwFntObj::GetModelPositionForViewPoint(SwDrawTextInfo &rInf)
             if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), 
rInf.GetLen() ) )
             {
                 if ( pSI && pSI->CountKashida() &&
-                    pSI->KashidaJustify( aKernArray.data(), nullptr, 
rInf.GetIdx(), rInf.GetLen(),
+                    pSI->KashidaJustify( aKernArray.data(), rInf.GetIdx(), 
rInf.GetLen(),
                                          nSpaceAdd ) != -1 )
                     nSpaceAdd = 0;
             }
@@ -2169,7 +2100,7 @@ TextFrameIndex 
SwFntObj::GetModelPositionForViewPoint(SwDrawTextInfo &rInf)
 
             if ( LANGUAGE_THAI == aLang )
             {
-                SwScriptInfo::ThaiJustify( rInf.GetText(), aKernArray.data(), 
nullptr,
+                SwScriptInfo::ThaiJustify( rInf.GetText(), aKernArray.data(),
                                            rInf.GetIdx(), rInf.GetLen(),
                                            rInf.GetNumberOfBlanks(),
                                            rInf.GetSpace() );
diff --git a/sw/source/uibase/config/usrpref.cxx 
b/sw/source/uibase/config/usrpref.cxx
index 0c759a78cf94..e7b43df54c34 100644
--- a/sw/source/uibase/config/usrpref.cxx
+++ b/sw/source/uibase/config/usrpref.cxx
@@ -388,7 +388,7 @@ void SwLayoutViewConfig::Load()
                 case 16: m_rParent.SetViewLayoutBookMode(bSet); break;// 
"ViewLayout/BookMode",
                 case 17: m_rParent.SetDefaultPageMode(bSet,true); break;// 
"Other/IsSquaredPageMode",
                 case 18: m_rParent.SetApplyCharUnit(bSet, true); break;// 
"Other/ApplyUserChar"
-                case 19: m_rParent.SetShowScrollBarTips(bSet); break;// 
"Window/ShowScrollBarTips",
+                case 29: m_rParent.SetShowScrollBarTips(bSet); break;// 
"Window/ShowScrollBarTips",
             }
         }
     }
diff --git a/vcl/inc/ImplLayoutArgs.hxx b/vcl/inc/ImplLayoutArgs.hxx
index 865470b7897a..fa94562ca86c 100644
--- a/vcl/inc/ImplLayoutArgs.hxx
+++ b/vcl/inc/ImplLayoutArgs.hxx
@@ -35,7 +35,8 @@ public:
     vcl::text::TextLayoutCache const* m_pTextLayoutCache;
 
     // positioning related inputs
-    const DeviceCoordinate* mpDXArray; // in pixel units
+    const DeviceCoordinate* mpDXArray; // in integer pixel units
+    const double* mpAltNaturalDXArray; // in floating point pixel units
     DeviceCoordinate mnLayoutWidth; // in pixel units
     Degree10 mnOrientation; // in 0-3600 system
 
@@ -48,12 +49,15 @@ public:
 
     void SetLayoutWidth(DeviceCoordinate nWidth);
     void SetDXArray(const DeviceCoordinate* pDXArray);
+    void SetAltNaturalDXArray(const double* pDXArray);
     void SetOrientation(Degree10 nOrientation);
 
     void ResetPos();
     bool GetNextPos(int* nCharPos, bool* bRTL);
     bool GetNextRun(int* nMinRunPos, int* nEndRunPos, bool* bRTL);
     void AddFallbackRun(int nMinRunPos, int nEndRunPos, bool bRTL);
+    bool HasDXArray() const { return mpDXArray || mpAltNaturalDXArray; }
+
     // methods used by BiDi and glyph fallback
     bool HasFallbackRun() const;
     bool PrepareFallback(const SalLayoutGlyphsImpl* pGlyphsImpl);
diff --git a/vcl/inc/impglyphitem.hxx b/vcl/inc/impglyphitem.hxx
index ca9f7cf5c052..4fc48f1ca2a2 100644
--- a/vcl/inc/impglyphitem.hxx
+++ b/vcl/inc/impglyphitem.hxx
@@ -58,10 +58,10 @@ class VCL_DLLPUBLIC GlyphItem
     GlyphItemFlags m_nFlags;
 
 public:
-    Point m_aLinearPos; // absolute position of non rotated string
+    DevicePoint m_aLinearPos; // absolute position of non rotated string
     sal_Int32 m_nNewWidth; // width after adjustments
 
-    GlyphItem(int nCharPos, int nCharCount, sal_GlyphId aGlyphId, const Point& 
rLinearPos,
+    GlyphItem(int nCharPos, int nCharCount, sal_GlyphId aGlyphId, const 
DevicePoint& rLinearPos,
               GlyphItemFlags nFlags, int nOrigWidth, int nXOffset)
         : m_nOrigWidth(nOrigWidth)
         , m_nCharPos(nCharPos)
diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h
index f0aa925c6083..569a14a6d3fc 100644
--- a/vcl/inc/quartz/salgdi.h
+++ b/vcl/inc/quartz/salgdi.h
@@ -297,7 +297,7 @@ public:
                                    const tools::Rectangle &rControlRegion,
                                    ControlState nState,
                                    const ImplControlValue &aValue) = 0;
-    virtual void drawTextLayout(const GenericSalLayout& layout) = 0;
+    virtual void drawTextLayout(const GenericSalLayout& layout, bool 
bTextRenderModeForResolutionIndependentLayout) = 0;
     virtual void Flush() {}
     virtual void Flush( const tools::Rectangle& ) {}
 protected:
@@ -446,7 +446,7 @@ public:
                                    ControlState nState,
                                    const ImplControlValue &aValue) override;
 
-    virtual void drawTextLayout(const GenericSalLayout& layout) override;
+    virtual void drawTextLayout(const GenericSalLayout& layout, bool 
bTextRenderModeForResolutionIndependentLayout) override;
 
     bool supportsOperation(OutDevSupportType eType) const override;
 };
diff --git a/vcl/inc/salgdi.hxx b/vcl/inc/salgdi.hxx
index 716c9aa934a6..6f9ee67f69a4 100644
--- a/vcl/inc/salgdi.hxx
+++ b/vcl/inc/salgdi.hxx
@@ -96,6 +96,16 @@ public:
         return m_bAntiAlias;
     }
 
+    void setTextRenderModeForResolutionIndependentLayout(bool bNew)
+    {
+        m_bTextRenderModeForResolutionIndependentLayout = bNew;
+    }
+
+    bool getTextRenderModeForResolutionIndependentLayoutEnabled() const
+    {
+        return m_bTextRenderModeForResolutionIndependentLayout;
+    }
+
     // public SalGraphics methods, the interface to the independent vcl part
 
     // get device resolution
@@ -631,6 +641,7 @@ private:
 protected:
     /// flags which hold the SetAntialiasing() value from OutputDevice
     bool                        m_bAntiAlias : 1;
+    bool                        
m_bTextRenderModeForResolutionIndependentLayout : 1;
 
     inline tools::Long GetDeviceWidth(const OutputDevice& rOutDev) const;
 
diff --git a/vcl/inc/sallayout.hxx b/vcl/inc/sallayout.hxx
index ab29a2022985..847c22ace091 100644
--- a/vcl/inc/sallayout.hxx
+++ b/vcl/inc/sallayout.hxx
@@ -64,7 +64,7 @@ public:
     sal_Int32       GetTextBreak(DeviceCoordinate nMaxWidth, DeviceCoordinate 
nCharExtra, int nFactor) const override;
     DeviceCoordinate FillDXArray(std::vector<DeviceCoordinate>* pDXArray) 
const override;
     void            GetCaretPositions(int nArraySize, sal_Int32* pCaretXArray) 
const override;
-    bool            GetNextGlyph(const GlyphItem** pGlyph, Point& rPos, int& 
nStart,
+    bool            GetNextGlyph(const GlyphItem** pGlyph, DevicePoint& rPos, 
int& nStart,
                                  const LogicalFontInstance** ppGlyphFont = 
nullptr,
                                  const vcl::font::PhysicalFontFace** 
pFallbackFont = nullptr) const override;
     bool            GetOutline(basegfx::B2DPolyPolygonVector&) const override;
@@ -82,7 +82,11 @@ public:
 
     void SetIncomplete(bool bIncomplete);
 
-public:
+    template<typename DC>
+    void            ImplAdjustMultiLayout(vcl::text::ImplLayoutArgs& rArgs,
+                                          vcl::text::ImplLayoutArgs& 
rMultiArgs,
+                                          const DC* pMultiDXArray);
+
     virtual         ~MultiSalLayout() override;
 
 private:
@@ -97,7 +101,10 @@ private:
 
 class VCL_DLLPUBLIC GenericSalLayout : public SalLayout
 {
-    friend void MultiSalLayout::AdjustLayout(vcl::text::ImplLayoutArgs&);
+    template<typename DC> friend void MultiSalLayout::ImplAdjustMultiLayout(
+            vcl::text::ImplLayoutArgs& rArgs,
+            vcl::text::ImplLayoutArgs& rMultiArgs,
+            const DC* pMultiDXArray);
 
 public:
                     GenericSalLayout(LogicalFontInstance&);
@@ -121,7 +128,7 @@ public:
     LogicalFontInstance& GetFont() const
         { return *m_GlyphItems.GetFont(); }
 
-    bool            GetNextGlyph(const GlyphItem** pGlyph, Point& rPos, int& 
nStart,
+    bool            GetNextGlyph(const GlyphItem** pGlyph, DevicePoint& rPos, 
int& nStart,
                                  const LogicalFontInstance** ppGlyphFont = 
nullptr,
                                  const vcl::font::PhysicalFontFace** 
pFallbackFont = nullptr) const override;
 
@@ -136,7 +143,8 @@ private:
                     GenericSalLayout( const GenericSalLayout& ) = delete;
                     GenericSalLayout& operator=( const GenericSalLayout& ) = 
delete;
 
-    void            ApplyDXArray(const DeviceCoordinate*, SalLayoutFlags 
nLayoutFlags);
+    template<typename DC>
+    void            ApplyDXArray(const DC*, SalLayoutFlags nLayoutFlags);
     void            Justify(DeviceCoordinate nNewWidth);
     void            ApplyAsianKerning(const OUString& rStr);
 
diff --git a/vcl/inc/skia/osx/gdiimpl.hxx b/vcl/inc/skia/osx/gdiimpl.hxx
index e59aa60f56df..71baf24625fc 100644
--- a/vcl/inc/skia/osx/gdiimpl.hxx
+++ b/vcl/inc/skia/osx/gdiimpl.hxx
@@ -38,7 +38,8 @@ public:
                                    const tools::Rectangle& rControlRegion, 
ControlState nState,
                                    const ImplControlValue& aValue) override;
 
-    virtual void drawTextLayout(const GenericSalLayout& layout) override;
+    virtual void drawTextLayout(const GenericSalLayout& layout,
+                                bool 
bTextRenderModeForResolutionIndependentLayout) override;
 
     virtual void Flush() override;
     virtual void Flush(const tools::Rectangle&) override;
diff --git a/vcl/inc/skia/win/gdiimpl.hxx b/vcl/inc/skia/win/gdiimpl.hxx
index 58043e5f6a83..a8897d0d7c20 100644
--- a/vcl/inc/skia/win/gdiimpl.hxx
+++ b/vcl/inc/skia/win/gdiimpl.hxx
@@ -25,6 +25,8 @@
 #include <SkFont.h>
 #include <SkFontMgr.h>
 
+#include <dwrite_3.h>
+
 class SkTypeface;
 class ControlCacheKey;
 
@@ -64,6 +66,8 @@ protected:
     static void initFontInfo();
     inline static sal::systools::COMReference<IDWriteFactory> dwriteFactory;
     inline static sal::systools::COMReference<IDWriteGdiInterop> 
dwriteGdiInterop;
+    inline static sal::systools::COMReference<IDWriteFontSetBuilder> 
dwriteFontSetBuilder;
+    inline static sal::systools::COMReference<IDWriteFontCollection1> 
dwritePrivateCollection;
     inline static sk_sp<SkFontMgr> dwriteFontMgr;
     inline static bool dwriteDone = false;
     static SkFont::Edging fontEdging;
diff --git a/vcl/inc/win/DWriteTextRenderer.hxx 
b/vcl/inc/win/DWriteTextRenderer.hxx
index 6e097546d1e2..b64cc48a1c6a 100644
--- a/vcl/inc/win/DWriteTextRenderer.hxx
+++ b/vcl/inc/win/DWriteTextRenderer.hxx
@@ -37,12 +37,13 @@ enum class D2DTextAntiAliasMode
 class D2DWriteTextOutRenderer : public TextOutRenderer
 {
 public:
-    explicit D2DWriteTextOutRenderer();
+    explicit D2DWriteTextOutRenderer(bool bRenderingModeNatural);
     virtual ~D2DWriteTextOutRenderer() override;
 
-    bool operator ()(GenericSalLayout const &rLayout,
+    bool operator()(GenericSalLayout const &rLayout,
         SalGraphics &rGraphics,
-        HDC hDC) override;
+        HDC hDC,
+        bool bRenderingModeNatural) override;
 
     HRESULT BindDC(HDC hDC, tools::Rectangle const & rRect = 
tools::Rectangle(0, 0, 1, 1));
 
@@ -54,12 +55,13 @@ public:
     IDWriteFontFace   * GetFontFace() const { return mpFontFace; }
     float               GetEmHeight() const { return mlfEmHeight; }
 
-    HRESULT CreateRenderTarget();
+    HRESULT CreateRenderTarget(bool bRenderingModeNatural);
 
     bool Ready() const;
 
-    void applyTextAntiAliasMode();
-    void changeTextAntiAliasMode(D2DTextAntiAliasMode eMode);
+    void applyTextAntiAliasMode(bool bRenderingModeNatural);
+
+    bool GetRenderingModeNatural() const { return mbRenderingModeNatural; }
 
 private:
     // This is a singleton object disable copy ctor and assignment operator
@@ -67,7 +69,7 @@ private:
     D2DWriteTextOutRenderer & operator = (const D2DWriteTextOutRenderer &) = 
delete;
 
     bool GetDWriteFaceFromHDC(HDC hDC, IDWriteFontFace ** ppFontFace, float * 
lfSize) const;
-    bool performRender(GenericSalLayout const &rLayout, SalGraphics 
&rGraphics, HDC hDC, bool& bRetry);
+    bool performRender(GenericSalLayout const &rLayout, SalGraphics 
&rGraphics, HDC hDC, bool& bRetry, bool bRenderingModeNatural);
 
     ID2D1Factory        * mpD2DFactory;
     IDWriteFactory      * mpDWriteFactory;
@@ -78,6 +80,7 @@ private:
     IDWriteFontFace * mpFontFace;
     float             mlfEmHeight;
     HDC               mhDC;
+    bool mbRenderingModeNatural;
     D2DTextAntiAliasMode meTextAntiAliasMode;
 };
 
diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h
index b472ece0a256..7833f988bd18 100644
--- a/vcl/inc/win/salgdi.h
+++ b/vcl/inc/win/salgdi.h
@@ -316,7 +316,7 @@ public:
 private:
     // local helpers
 
-    void                    DrawTextLayout(const GenericSalLayout&, HDC, bool 
bUseDWrite);
+    void DrawTextLayout(const GenericSalLayout&, HDC, bool bUseDWrite, bool 
bRenderingModeNatural);
 
 public:
     // public SalGraphics methods, the interface to the independent vcl part
diff --git a/vcl/inc/win/winlayout.hxx b/vcl/inc/win/winlayout.hxx
index 0b43ef4eeca1..5f56fe6b0c5e 100644
--- a/vcl/inc/win/winlayout.hxx
+++ b/vcl/inc/win/winlayout.hxx
@@ -75,13 +75,14 @@ protected:
     TextOutRenderer & operator = (const TextOutRenderer &) = delete;
 
 public:
-    static TextOutRenderer & get(bool bUseDWrite);
+    static TextOutRenderer & get(bool bUseDWrite, bool bRenderingModeNatural);
 
     virtual ~TextOutRenderer() = default;
 
     virtual bool operator ()(GenericSalLayout const &rLayout,
         SalGraphics &rGraphics,
-        HDC hDC) = 0;
+        HDC hDC,
+        bool bRenderingModeNatural) = 0;
 };
 
 class ExTextOutRenderer : public TextOutRenderer
@@ -94,7 +95,8 @@ public:
 
     bool operator ()(GenericSalLayout const &rLayout,
         SalGraphics &rGraphics,
-        HDC hDC) override;
+        HDC hDC,
+        bool bRenderingModeNatural) override;
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/qt5/QtGraphics_Text.cxx b/vcl/qt5/QtGraphics_Text.cxx
index b509c2a946bd..02158fca29db 100644
--- a/vcl/qt5/QtGraphics_Text.cxx
+++ b/vcl/qt5/QtGraphics_Text.cxx
@@ -294,11 +294,26 @@ std::unique_ptr<GenericSalLayout> 
QtGraphics::GetTextLayout(int nFallbackLevel)
     return std::make_unique<QtCommonSalLayout>(*m_pTextStyle[nFallbackLevel]);
 }
 
+static QRawFont GetRawFont(const QFont& rFont, bool 
bWithoutHintingInTextDirection)
+{
+    QFont::HintingPreference eHinting = rFont.hintingPreference();
+    bool bAllowedHintStyle
+        = !bWithoutHintingInTextDirection
+          || (eHinting == QFont::PreferNoHinting || eHinting == 
QFont::PreferVerticalHinting);
+    if (bWithoutHintingInTextDirection && !bAllowedHintStyle)
+    {
+        QFont aFont(rFont);
+        aFont.setHintingPreference(QFont::PreferVerticalHinting);
+        return QRawFont::fromFont(aFont);
+    }
+    return QRawFont::fromFont(rFont);
+}
+
 void QtGraphics::DrawTextLayout(const GenericSalLayout& rLayout)
 {
     const QtFont* pFont = static_cast<const QtFont*>(&rLayout.GetFont());
     assert(pFont);
-    QRawFont aRawFont(QRawFont::fromFont(*pFont));
+    QRawFont aRawFont(GetRawFont(*pFont, 
getTextRenderModeForResolutionIndependentLayoutEnabled()));
 
     QVector<quint32> glyphIndexes;
     QVector<QPointF> positions;
@@ -311,13 +326,13 @@ void QtGraphics::DrawTextLayout(const GenericSalLayout& 
rLayout)
     if (nOrientation)
         pQtLayout->SetOrientation(0_deg10);
 
-    Point aPos;
+    DevicePoint aPos;
     const GlyphItem* pGlyph;
     int nStart = 0;
     while (rLayout.GetNextGlyph(&pGlyph, aPos, nStart))
     {
         glyphIndexes.push_back(pGlyph->glyphId());
-        positions.push_back(QPointF(aPos.X(), aPos.Y()));
+        positions.push_back(QPointF(aPos.getX(), aPos.getY()));
     }
 
     // seems to be common to try to layout an empty string...
diff --git a/vcl/quartz/salgdi.cxx b/vcl/quartz/salgdi.cxx
index 9928cc4df3a2..b8a3ac375655 100644
--- a/vcl/quartz/salgdi.cxx
+++ b/vcl/quartz/salgdi.cxx
@@ -363,10 +363,10 @@ bool 
AquaSalGraphics::AddTempDevFont(vcl::font::PhysicalFontCollection*,
 
 void AquaSalGraphics::DrawTextLayout(const GenericSalLayout& rLayout)
 {
-    mpBackend->drawTextLayout(rLayout);
+    mpBackend->drawTextLayout(rLayout, 
getTextRenderModeForResolutionIndependentLayoutEnabled());
 }
 
-void AquaGraphicsBackend::drawTextLayout(const GenericSalLayout& rLayout)
+void AquaGraphicsBackend::drawTextLayout(const GenericSalLayout& rLayout, bool 
bTextRenderModeForResolutionIndependentLayout)
 {
 #ifdef IOS
     if (!mrShared.checkContext())
@@ -387,7 +387,7 @@ void AquaGraphicsBackend::drawTextLayout(const 
GenericSalLayout& rLayout)
     CTFontRef pFont = 
static_cast<CTFontRef>(CFDictionaryGetValue(rStyle.GetStyleDict(), 
kCTFontAttributeName));
     CGAffineTransform aRotMatrix = 
CGAffineTransformMakeRotation(-rStyle.mfFontRotation);
 
-    Point aPos;
+    DevicePoint aPos;
     const GlyphItem* pGlyph;
     std::vector<CGGlyph> aGlyphIds;
     std::vector<CGPoint> aGlyphPos;
@@ -395,7 +395,7 @@ void AquaGraphicsBackend::drawTextLayout(const 
GenericSalLayout& rLayout)
     int nStart = 0;
     while (rLayout.GetNextGlyph(&pGlyph, aPos, nStart))
     {
-        CGPoint aGCPos = CGPointMake(aPos.X(), -aPos.Y());
+        CGPoint aGCPos = CGPointMake(aPos.getX(), -aPos.getY());
 
         // Whether the glyph should be upright in vertical mode or not
         bool bUprightGlyph = false;
@@ -460,6 +460,14 @@ void AquaGraphicsBackend::drawTextLayout(const 
GenericSalLayout& rLayout)
         CGContextSetTextDrawingMode(mrShared.maContextHolder.get(), 
kCGTextFillStroke);
     }
 
+    if (bTextRenderModeForResolutionIndependentLayout)
+    {
+        
CGContextSetAllowsFontSubpixelQuantization(mrShared.maContextHolder.get(), 
false);
+        
CGContextSetShouldSubpixelQuantizeFonts(mrShared.maContextHolder.get(), false);
+        
CGContextSetAllowsFontSubpixelPositioning(mrShared.maContextHolder.get(), true);
+        
CGContextSetShouldSubpixelPositionFonts(mrShared.maContextHolder.get(), true);
+    }
+
     auto aIt = aGlyphOrientation.cbegin();
     while (aIt != aGlyphOrientation.cend())
     {
diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx
index 55fed5b84e72..6d027a6f860a 100644
--- a/vcl/skia/gdiimpl.cxx
+++ b/vcl/skia/gdiimpl.cxx
@@ -2206,7 +2206,7 @@ void SkiaSalGraphicsImpl::drawGenericLayout(const 
GenericSalLayout& layout, Colo
     glyphIds.reserve(256);
     glyphForms.reserve(256);
     verticals.reserve(256);
-    Point aPos;
+    DevicePoint aPos;
     const GlyphItem* pGlyph;
     int nStart = 0;
     while (layout.GetNextGlyph(&pGlyph, aPos, nStart))
@@ -2215,7 +2215,7 @@ void SkiaSalGraphicsImpl::drawGenericLayout(const 
GenericSalLayout& layout, Colo
         Degree10 angle = layout.GetOrientation();
         if (pGlyph->IsVertical())
             angle += 900_deg10;
-        SkRSXform form = SkRSXform::Make(toCos(angle), toSin(angle), aPos.X(), 
aPos.Y());
+        SkRSXform form = SkRSXform::Make(toCos(angle), toSin(angle), 
aPos.getX(), aPos.getY());
         glyphForms.emplace_back(std::move(form));
         verticals.emplace_back(pGlyph->IsVertical());
     }
diff --git a/vcl/skia/osx/gdiimpl.cxx b/vcl/skia/osx/gdiimpl.cxx
index 126f43bb6ac3..4c9ae86dbadf 100644
--- a/vcl/skia/osx/gdiimpl.cxx
+++ b/vcl/skia/osx/gdiimpl.cxx
@@ -261,7 +261,8 @@ bool AquaSkiaSalGraphicsImpl::drawNativeControl(ControlType 
nType, ControlPart n
     return bOK;
 }
 
-void AquaSkiaSalGraphicsImpl::drawTextLayout(const GenericSalLayout& rLayout)
+void AquaSkiaSalGraphicsImpl::drawTextLayout(const GenericSalLayout& rLayout,
+                                             bool bSubpixelPositioning)
 {
     const CoreTextStyle& rStyle = *static_cast<const 
CoreTextStyle*>(&rLayout.GetFont());
     const vcl::font::FontSelectPattern& rFontSelect = 
rStyle.GetFontSelectPattern();
@@ -295,8 +296,12 @@ void AquaSkiaSalGraphicsImpl::drawTextLayout(const 
GenericSalLayout& rLayout)
     //    font.setScaleX(rStyle.mfFontStretch); TODO
     if (rStyle.mbFauxBold)
         font.setEmbolden(true);
-    font.setEdging(!mrShared.mbNonAntialiasedText ? SkFont::Edging::kAntiAlias
-                                                  : SkFont::Edging::kAlias);
+
+    SkFont::Edging ePreferredAliasing
+        = bSubpixelPositioning ? SkFont::Edging::kSubpixelAntiAlias : 
SkFont::Edging::kAntiAlias;
+    if (bSubpixelPositioning)
+        font.setSubpixel(true);
+    font.setEdging(mrShared.mbNonAntialiasedText ? SkFont::Edging::kAlias : 
ePreferredAliasing);
 
     // Vertical font, use width as "height".
     SkFont verticalFont(font);
diff --git a/vcl/skia/win/gdiimpl.cxx b/vcl/skia/win/gdiimpl.cxx
index a10351888eac..e9074340e66e 100644
--- a/vcl/skia/win/gdiimpl.cxx
+++ b/vcl/skia/win/gdiimpl.cxx
@@ -163,11 +163,7 @@ sk_sp<SkTypeface> 
WinSkiaSalGraphicsImpl::createDirectWriteTypeface(HDC hdc, HFO
     // different version of the same font installed system-wide).
     // For that CreateFromFaceFromHdc() is necessary. The simpler
     // CreateFontFromLOGFONT() seems to search for the best matching font,
-    // which may not be the exact font. Our private fonts are installed
-    // using AddFontResourceExW( FR_PRIVATE ) and that apparently does
-    // not make them available to DirectWrite (at least, they are not
-    // included the DWrite system font collection). For such cases, we'll
-    // need to fall back to Skia's GDI-based font rendering.
+    // which may not be the exact font.
     HFONT oldFont = SelectFont(hdc, hfont);
     sal::systools::COMReference<IDWriteFontFace> fontFace;
     if (FAILED(CHECKHR(dwriteGdiInterop->CreateFontFaceFromHdc(hdc, 
&fontFace))))
@@ -175,6 +171,7 @@ sk_sp<SkTypeface> 
WinSkiaSalGraphicsImpl::createDirectWriteTypeface(HDC hdc, HFO
         SelectFont(hdc, oldFont);
         return nullptr;
     }
+
     SelectFont(hdc, oldFont);
     sal::systools::COMReference<IDWriteFontCollection> collection;
     if (FAILED(CHECKHR(dwriteFactory->GetSystemFontCollection(&collection))))
@@ -182,7 +179,66 @@ sk_sp<SkTypeface> 
WinSkiaSalGraphicsImpl::createDirectWriteTypeface(HDC hdc, HFO
     sal::systools::COMReference<IDWriteFont> font;
     // Do not use CHECKHR() here, as said above, this fails for our fonts.
     if (FAILED(collection->GetFontFromFontFace(fontFace.get(), &font)))
-        return nullptr;
+    {
+        // If not found in system collection, try our private font collection.
+        // If that's not possible we'll fall back to Skia's GDI-based font 
rendering.
+        if (!dwritePrivateCollection
+            || 
FAILED(dwritePrivateCollection->GetFontFromFontFace(fontFace.get(), &font)))
+        {
+            // Our private fonts are installed using AddFontResourceExW( 
FR_PRIVATE )
+            // and that does not make them available to the DWrite system font
+            // collection. For such cases attempt to update a collection of
+            // private fonts with this newly used font.
+
+            sal::systools::COMReference<IDWriteFactory3> dwriteFactory3;
+            if 
(FAILED(dwriteFactory->QueryInterface<IDWriteFactory3>(&dwriteFactory3)))
+                return nullptr;
+
+            if (!dwriteFontSetBuilder
+                && 
FAILED(dwriteFactory3->CreateFontSetBuilder(&dwriteFontSetBuilder)))
+                return nullptr;
+
+            UINT32 numberOfFiles;
+            if (FAILED(fontFace->GetFiles(&numberOfFiles, nullptr)) || 
numberOfFiles != 1)
+                return nullptr;
+
+            sal::systools::COMReference<IDWriteFontFile> fontFile;
+            if (FAILED(fontFace->GetFiles(&numberOfFiles, &fontFile)))
+                return nullptr;
+
+            BOOL isSupported;
+            DWRITE_FONT_FILE_TYPE fileType;
+            UINT32 numberOfFonts;
+            if (FAILED(fontFile->Analyze(&isSupported, &fileType, nullptr, 
&numberOfFonts))
+                || !isSupported)
+                return nullptr;
+
+            // For each font within the font file, get a font face reference 
and add to the builder.
+            for (UINT32 fontIndex = 0; fontIndex < numberOfFonts; ++fontIndex)
+            {
+                sal::systools::COMReference<IDWriteFontFaceReference> 
fontFaceReference;
+                if 
(FAILED(dwriteFactory3->CreateFontFaceReference(fontFile.get(), fontIndex,
+                                                                   
DWRITE_FONT_SIMULATIONS_NONE,
+                                                                   
&fontFaceReference)))
+                    continue;
+
+                // Leave it to DirectWrite to read properties directly out of 
the font files
+                
dwriteFontSetBuilder->AddFontFaceReference(fontFaceReference.get());
+            }
+
+            dwritePrivateCollection.clear();
+            sal::systools::COMReference<IDWriteFontSet> fontSet;
+            if 
(SUCCEEDED(CHECKHR(dwriteFontSetBuilder->CreateFontSet(&fontSet))))
+                dwriteFactory3->CreateFontCollectionFromFontSet(fontSet.get(),
+                                                                
&dwritePrivateCollection);
+        }
+
+        if (!dwritePrivateCollection)
+            return nullptr;
+        // CHECKHR because we expect to succeed here
+        if 
(FAILED(CHECKHR(dwritePrivateCollection->GetFontFromFontFace(fontFace.get(), 
&font))))
+            return nullptr;
+    }
     sal::systools::COMReference<IDWriteFontFamily> fontFamily;
     if (FAILED(CHECKHR(font->GetFontFamily(&fontFamily))))
         return nullptr;
@@ -231,8 +287,14 @@ bool WinSkiaSalGraphicsImpl::DrawTextLayout(const 
GenericSalLayout& rLayout)
     }
 
     SkFont font(typeface);
+
+    bool bSubpixelPositioning = 
mWinParent.getTextRenderModeForResolutionIndependentLayoutEnabled();
+    SkFont::Edging ePreferredAliasing
+        = bSubpixelPositioning ? SkFont::Edging::kSubpixelAntiAlias : 
fontEdging;
+    if (bSubpixelPositioning)
+        font.setSubpixel(true);
     font.setEdging(logFont.lfQuality == NONANTIALIASED_QUALITY ? 
SkFont::Edging::kAlias
-                                                               : fontEdging);
+                                                               : 
ePreferredAliasing);
 
     const vcl::font::FontSelectPattern& rFSD = 
pWinFont->GetFontSelectPattern();
     int nHeight = rFSD.mnHeight;
@@ -296,6 +358,8 @@ void WinSkiaSalGraphicsImpl::initFontInfo()
 void WinSkiaSalGraphicsImpl::ClearDevFontCache()
 {
     dwriteFontMgr.reset();
+    dwriteFontSetBuilder.clear();
+    dwritePrivateCollection.clear();
     dwriteFactory.clear();
     dwriteGdiInterop.clear();
     dwriteDone = false;
diff --git a/vcl/skia/x11/textrender.cxx b/vcl/skia/x11/textrender.cxx
index a2d0dcbb36f6..9fda8ba6601c 100644
--- a/vcl/skia/x11/textrender.cxx
+++ b/vcl/skia/x11/textrender.cxx
@@ -57,8 +57,22 @@ void SkiaTextRender::DrawTextLayout(const GenericSalLayout& 
rLayout, const SalGr
         font.setSkewX(1.0 * -0x4000L / 0x10000L);
     if (rFont.NeedsArtificialBold())
         font.setEmbolden(true);
-    font.setEdging(rFont.GetAntialiasAdvice() ? SkFont::Edging::kAntiAlias
-                                              : SkFont::Edging::kAlias);
+
+    bool bSubpixelPositioning = 
rGraphics.getTextRenderModeForResolutionIndependentLayoutEnabled();
+    SkFont::Edging ePreferredAliasing
+        = bSubpixelPositioning ? SkFont::Edging::kSubpixelAntiAlias : 
SkFont::Edging::kAntiAlias;
+    if (bSubpixelPositioning)
+    {
+        font.setSubpixel(true);
+
+        SkFontHinting eHinting = font.getHinting();
+        bool bAllowedHintStyle
+            = eHinting == SkFontHinting::kNone || eHinting == 
SkFontHinting::kSlight;
+        if (!bAllowedHintStyle)
+            font.setHinting(SkFontHinting::kSlight);
+    }
+
+    font.setEdging(rFont.GetAntialiasAdvice() ? ePreferredAliasing : 
SkFont::Edging::kAlias);
 
     // Vertical font, use width as "height".
     SkFont verticalFont(font);
diff --git a/vcl/source/gdi/CommonSalLayout.cxx 
b/vcl/source/gdi/CommonSalLayout.cxx
index 13bc53ebbdab..811849309d67 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -197,7 +197,9 @@ void 
GenericSalLayout::AdjustLayout(vcl::text::ImplLayoutArgs& rArgs)
 {
     SalLayout::AdjustLayout(rArgs);
 
-    if (rArgs.mpDXArray)
+    if (rArgs.mpAltNaturalDXArray) // Used when 
"TextRenderModeForResolutionIndependentLayout" is set
+        ApplyDXArray(rArgs.mpAltNaturalDXArray, rArgs.mnFlags);
+    else if (rArgs.mpDXArray)   // Normal case
         ApplyDXArray(rArgs.mpDXArray, rArgs.mnFlags);
     else if (rArgs.mnLayoutWidth)
         Justify(rArgs.mnLayoutWidth);
@@ -331,7 +333,7 @@ bool 
GenericSalLayout::LayoutText(vcl::text::ImplLayoutArgs& rArgs, const SalLay
     double nYScale = 0;
     GetFont().GetScale(&nXScale, &nYScale);
 
-    Point aCurrPos(0, 0);
+    DevicePoint aCurrPos(0, 0);
     while (true)
     {
         int nBidiMinRunPos, nBidiEndRunPos;
@@ -584,12 +586,12 @@ bool 
GenericSalLayout::LayoutText(vcl::text::ImplLayoutArgs& rArgs, const SalLay
                 nXOffset = std::lround(nXOffset * nXScale);
                 nYOffset = std::lround(nYOffset * nYScale);
 
-                Point aNewPos(aCurrPos.X() + nXOffset, aCurrPos.Y() + 
nYOffset);
+                DevicePoint aNewPos(aCurrPos.getX() + nXOffset, 
aCurrPos.getY() + nYOffset);
                 const GlyphItem aGI(nCharPos, nCharCount, nGlyphIndex, 
aNewPos, nGlyphFlags,
                                     nAdvance, nXOffset);
                 m_GlyphItems.push_back(aGI);
 
-                aCurrPos.AdjustX(nAdvance );
+                aCurrPos.adjustX(nAdvance);
             }
         }
     }
@@ -635,12 +637,12 @@ void 
GenericSalLayout::GetCharWidths(std::vector<DeviceCoordinate>& rCharWidths)
 //   * 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.
-
-void GenericSalLayout::ApplyDXArray(const DeviceCoordinate* pDXArray, 
SalLayoutFlags nLayoutFlags)
+template<typename DC>
+void GenericSalLayout::ApplyDXArray(const DC* pDXArray, SalLayoutFlags 
nLayoutFlags)
 {
     int nCharCount = mnEndCharPos - mnMinCharPos;
     std::vector<DeviceCoordinate> aOldCharWidths;
-    std::unique_ptr<DeviceCoordinate[]> const pNewCharWidths(new 
DeviceCoordinate[nCharCount]);
+    std::unique_ptr<DC[]> const pNewCharWidths(new DC[nCharCount]);
 
     // Get the natural character widths (i.e. before applying DX adjustments).
     GetCharWidths(aOldCharWidths);
@@ -671,7 +673,7 @@ void GenericSalLayout::ApplyDXArray(const DeviceCoordinate* 
pDXArray, SalLayoutF
     std::map<size_t, DeviceCoordinate> pKashidas;
 
     // The accumulated difference in X position.
-    DeviceCoordinate nDelta = 0;
+    DC nDelta = 0;
 
     // Apply the DX adjustments to glyph positions and widths.
     size_t i = 0;
@@ -680,7 +682,7 @@ void GenericSalLayout::ApplyDXArray(const DeviceCoordinate* 
pDXArray, SalLayoutF
         // Accumulate the width difference for all characters corresponding to
         // this glyph.
         int nCharPos = m_GlyphItems[i].charPos() - mnMinCharPos;
-        DeviceCoordinate nDiff = 0;
+        DC nDiff = 0;
         for (int j = 0; j < m_GlyphItems[i].charCount(); j++)
             nDiff += pNewCharWidths[nCharPos + j] - aOldCharWidths[nCharPos + 
j];
 
@@ -689,14 +691,14 @@ void GenericSalLayout::ApplyDXArray(const 
DeviceCoordinate* pDXArray, SalLayoutF
             // Adjust the width and position of the first (leftmost) glyph in
             // the cluster.
             m_GlyphItems[i].m_nNewWidth += nDiff;
-            m_GlyphItems[i].m_aLinearPos.AdjustX(nDelta);
+            m_GlyphItems[i].m_aLinearPos.adjustX(nDelta);
 
             // Adjust the position of the rest of the glyphs in the cluster.
             while (++i < m_GlyphItems.size())
             {
                 if (!m_GlyphItems[i].IsInCluster())
                     break;
-                m_GlyphItems[i].m_aLinearPos.AdjustX(nDelta);
+                m_GlyphItems[i].m_aLinearPos.adjustX(nDelta);
             }
         }
         else if (m_GlyphItems[i].IsInCluster())
@@ -711,7 +713,7 @@ void GenericSalLayout::ApplyDXArray(const DeviceCoordinate* 
pDXArray, SalLayoutF
             // the cluster.
             // For RTL, we put all the adjustment to the left of the glyph.
             m_GlyphItems[i].m_nNewWidth += nDiff;
-            m_GlyphItems[i].m_aLinearPos.AdjustX(nDelta + nDiff);
+            m_GlyphItems[i].m_aLinearPos.adjustX(nDelta + nDiff);
 
             // Adjust the X position of all glyphs in the cluster.
             size_t j = i;
@@ -720,7 +722,7 @@ void GenericSalLayout::ApplyDXArray(const DeviceCoordinate* 
pDXArray, SalLayoutF
                 --j;
                 if (!m_GlyphItems[j].IsInCluster())
                     break;
-                m_GlyphItems[j].m_aLinearPos.AdjustX(nDelta + nDiff);
+                m_GlyphItems[j].m_aLinearPos.adjustX(nDelta + nDiff);
             }
 
             // If this glyph is Kashida-justifiable, then mark this as a
@@ -737,7 +739,7 @@ void GenericSalLayout::ApplyDXArray(const DeviceCoordinate* 
pDXArray, SalLayoutF
                 {
                     if (!m_GlyphItems[j].IsDiacritic())
                         break;
-                    m_GlyphItems[j--].m_aLinearPos.AdjustX(nDiff);
+                    m_GlyphItems[j--].m_aLinearPos.adjustX(nDiff);
                 }
             }
             i++;
@@ -779,15 +781,14 @@ void GenericSalLayout::ApplyDXArray(const 
DeviceCoordinate* pDXArray, SalLayoutF
                 nOverlap = nExcess / (nCopies - 1);
         }
 
-        Point aPos(pGlyphIter->m_aLinearPos.getX() - nTotalWidth, 0);
+        DevicePoint aPos(pGlyphIter->m_aLinearPos.getX() - nTotalWidth, 0);
         int nCharPos = pGlyphIter->charPos();
         GlyphItemFlags const nFlags = GlyphItemFlags::IS_IN_CLUSTER | 
GlyphItemFlags::IS_RTL_GLYPH;
         while (nCopies--)
         {
             GlyphItem aKashida(nCharPos, 0, nKashidaIndex, aPos, nFlags, 
nKashidaWidth, 0);
             pGlyphIter = m_GlyphItems.insert(pGlyphIter, aKashida);
-            aPos.AdjustX(nKashidaWidth );
-            aPos.AdjustX( -nOverlap );
+            aPos.adjustX(nKashidaWidth - nOverlap);
             ++pGlyphIter;
             ++nInserted;
         }
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx 
b/vcl/source/gdi/pdfwriter_impl.cxx
index 6f10c891330d..c418baab334d 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -3895,7 +3895,7 @@ void PDFWriterImpl::createDefaultCheckBoxAppearance( 
PDFWidget& rBox, const PDFW
     // make sure OpenSymbol is embedded, and includes our checkmark
     const sal_Unicode cMark=0x2713;
     const GlyphItem aItem(0, 0, pMap->GetGlyphIndex(cMark),
-                          Point(), GlyphItemFlags::NONE, 0, 0);
+                          DevicePoint(), GlyphItemFlags::NONE, 0, 0);
     const std::vector<sal_Ucs> aCodeUnits={ cMark };
     sal_uInt8 nMappedGlyph;
     sal_Int32 nMappedFontObject;
@@ -5804,9 +5804,9 @@ void PDFWriterImpl::drawShadow( SalLayout& rLayout, const 
OUString& rText, bool
     tools::Long nOff = 1 + ((GetFontInstance()->mnLineHeight-24)/24);
     if( rFont.IsOutline() )
         nOff++;
-    rLayout.DrawBase() += Point( nOff, nOff );
+    rLayout.DrawBase() += DevicePoint(nOff, nOff);
     drawLayout( rLayout, rText, bTextLines );
-    rLayout.DrawBase() -= Point( nOff, nOff );
+    rLayout.DrawBase() -= DevicePoint(nOff, nOff);
 
     setFont( aSaveFont );
     setTextLineColor( aSaveTextLineColor );
@@ -6129,7 +6129,7 @@ void PDFWriterImpl::drawLayout( SalLayout& rLayout, const 
OUString& rText, bool
     std::vector< PDFGlyph > aGlyphs;
     aGlyphs.reserve( nMaxGlyphs );
     // first get all the glyphs and register them; coordinates still in Pixel
-    Point aPos;
+    DevicePoint aPos;
     while (rLayout.GetNextGlyph(&pGlyph, aPos, nIndex, nullptr, 
&pFallbackFont))
     {
         const auto* pFont = pFallbackFont ? pFallbackFont : pDevFont;
@@ -6202,7 +6202,7 @@ void PDFWriterImpl::drawLayout( SalLayout& rLayout, const 
OUString& rText, bool
         if (bUseActualText || pGlyph->IsInCluster())
             nCharPos = pGlyph->charPos();
 
-        aGlyphs.emplace_back(aPos,
+        aGlyphs.emplace_back(Point(aPos.getX(), aPos.getY()),
                              pGlyph,
                              nGlyphWidth,
                              nMappedFontObject,
@@ -6225,7 +6225,8 @@ void PDFWriterImpl::drawLayout( SalLayout& rLayout, const 
OUString& rText, bool
         // The rectangle is the bounding box of the text, but also includes
         // ascent / descent to match the on-screen rendering.
         // This is the top left of the text without ascent / descent.
-        tools::Rectangle aRectangle(PixelToLogic(rLayout.GetDrawPosition()),
+        DevicePoint aDrawPosition(rLayout.GetDrawPosition());
+        tools::Rectangle aRectangle(PixelToLogic(Point(aDrawPosition.getX(), 
aDrawPosition.getY())),
                                     
Size(ImplDevicePixelToLogicWidth(rLayout.GetTextWidth()), 0));
         aRectangle.AdjustTop(-aRefDevFontMetric.GetAscent());
         // This includes ascent / descent.
@@ -6236,7 +6237,7 @@ void PDFWriterImpl::drawLayout( SalLayout& rLayout, const 
OUString& rText, bool
         {
             // Adapt rectangle for rotated text.
             tools::Polygon aPolygon(aRectangle);
-            aPolygon.Rotate(PixelToLogic(rLayout.GetDrawPosition()), 
pFontInstance->mnOrientation);
+            aPolygon.Rotate(PixelToLogic(Point(aDrawPosition.getX(), 
aDrawPosition.getY())), pFontInstance->mnOrientation);
             drawPolygon(aPolygon);
         }
         else
@@ -6333,7 +6334,7 @@ void PDFWriterImpl::drawLayout( SalLayout& rLayout, const 
OUString& rText, bool
                 if (!pGlyph->IsSpacing())
                 {
                     if( !nWidth )
-                        aStartPt = aPos;
+                        aStartPt = Point(aPos.getX(), aPos.getY());
 
                     nWidth += pGlyph->m_nNewWidth;
                 }
@@ -6355,9 +6356,9 @@ void PDFWriterImpl::drawLayout( SalLayout& rLayout, const 
OUString& rText, bool
         }
         else
         {
-            Point aStartPt = rLayout.GetDrawPosition();
+            DevicePoint aStartPt = rLayout.GetDrawPosition();
             int nWidth = rLayout.GetTextWidth() / rLayout.GetUnitsPerPixel();
-            drawTextLine( PixelToLogic( aStartPt ),
+            drawTextLine( PixelToLogic(Point(aStartPt.getX(), aStartPt.getY()) 
),
                           ImplDevicePixelToLogicWidth( nWidth ),
                           eStrikeout, eUnderline, eOverline, bUnderlineAbove );
         }
@@ -6433,9 +6434,10 @@ void PDFWriterImpl::drawLayout( SalLayout& rLayout, 
const OUString& rText, bool
 
             aAdjOffset -= Point( nEmphWidth2, nEmphHeight2 );
 
-            aPos += aAdjOffset;
-            aPos = PixelToLogic( aPos );
-            drawEmphasisMark( aPos.X(), aPos.Y(),
+            Point aMarkPos(aPos.getX(), aPos.getY());
+            aMarkPos += aAdjOffset;
+            aMarkPos = PixelToLogic(aMarkPos);
+            drawEmphasisMark( aMarkPos.X(), aMarkPos.Y(),
                               aEmphPoly, bEmphPolyLine,
                               aEmphRect1, aEmphRect2 );
         }
diff --git a/vcl/source/gdi/salgdilayout.cxx b/vcl/source/gdi/salgdilayout.cxx
index 2a0d27cbc24e..34f54a8ce870 100644
--- a/vcl/source/gdi/salgdilayout.cxx
+++ b/vcl/source/gdi/salgdilayout.cxx
@@ -55,7 +55,8 @@ SalGraphics::SalGraphics()
     m_aLastMirrorW(0),
     m_nLastMirrorDeviceLTRButBiDiRtlTranslate(0),
     m_bLastMirrorDeviceLTRButBiDiRtlSet(false),
-    m_bAntiAlias(false)
+    m_bAntiAlias(false),
+    m_bTextRenderModeForResolutionIndependentLayout(false)
 {
     // read global RTL settings
     if( AllSettings::GetLayoutRTL() )
diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx
index ebf10bf8e17c..abad66427491 100644
--- a/vcl/source/gdi/sallayout.cxx
+++ b/vcl/source/gdi/sallayout.cxx
@@ -135,7 +135,8 @@ SalLayout::SalLayout()
     mnEndCharPos( -1 ),
     mnUnitsPerPixel( 1 ),
     mnOrientation( 0 ),
-    maDrawOffset( 0, 0 )
+    maDrawOffset( 0, 0 ),
+    mbTextRenderModeForResolutionIndependentLayout(false)
 {}
 
 SalLayout::~SalLayout()
@@ -148,10 +149,11 @@ void SalLayout::AdjustLayout( vcl::text::ImplLayoutArgs& 
rArgs )
     mnOrientation = rArgs.mnOrientation;
 }
 
-Point SalLayout::GetDrawPosition( const Point& rRelative ) const
+DevicePoint SalLayout::GetDrawPosition(const DevicePoint& rRelative) const
 {
-    Point aPos = maDrawBase;
-    Point aOfs = rRelative + maDrawOffset;
+    DevicePoint aPos(maDrawBase);
+    DevicePoint aOfs(rRelative.getX() + maDrawOffset.X(),
+                     rRelative.getY() + maDrawOffset.Y());
 
     if( mnOrientation == 0_deg10 )
         aPos += aOfs;
@@ -168,11 +170,20 @@ Point SalLayout::GetDrawPosition( const Point& rRelative 
) const
             fSin = sin( fRad );
         }
 
-        double fX = aOfs.X();
-        double fY = aOfs.Y();
-        tools::Long nX = static_cast<tools::Long>( +fCos * fX + fSin * fY );
-        tools::Long nY = static_cast<tools::Long>( +fCos * fY - fSin * fX );
-        aPos += Point( nX, nY );
+        double fX = aOfs.getX();
+        double fY = aOfs.getY();
+        if (mbTextRenderModeForResolutionIndependentLayout)
+        {
+            double nX = +fCos * fX + fSin * fY;
+            double nY = +fCos * fY - fSin * fX;
+            aPos += DevicePoint(nX, nY);
+        }
+        else
+        {
+            tools::Long nX = static_cast<tools::Long>( +fCos * fX + fSin * fY 
);
+            tools::Long nY = static_cast<tools::Long>( +fCos * fY - fSin * fX 
);
+            aPos += DevicePoint(nX, nY);
+        }
     }
 
     return aPos;
@@ -185,7 +196,7 @@ bool SalLayout::GetOutline(basegfx::B2DPolyPolygonVector& 
rVector) const
 
     basegfx::B2DPolyPolygon aGlyphOutline;
 
-    Point aPos;
+    DevicePoint aPos;
     const GlyphItem* pGlyph;
     int nStart = 0;
     const LogicalFontInstance* pGlyphFont;
@@ -198,9 +209,9 @@ bool SalLayout::GetOutline(basegfx::B2DPolyPolygonVector& 
rVector) const
         // only add non-empty outlines
         if( bSuccess && (aGlyphOutline.count() > 0) )
         {
-            if( aPos.X() || aPos.Y() )
+            if( aPos.getX() || aPos.getY() )
             {
-                
aGlyphOutline.transform(basegfx::utils::createTranslateB2DHomMatrix(aPos.X(), 
aPos.Y()));
+                
aGlyphOutline.transform(basegfx::utils::createTranslateB2DHomMatrix(aPos.getX(),
 aPos.getY()));
             }
 
             // insert outline at correct position
@@ -218,7 +229,7 @@ bool SalLayout::GetBoundRect(tools::Rectangle& rRect) const
 
     tools::Rectangle aRectangle;
 
-    Point aPos;
+    DevicePoint aPos;
     const GlyphItem* pGlyph;
     int nStart = 0;
     const LogicalFontInstance* pGlyphFont;
@@ -228,7 +239,7 @@ bool SalLayout::GetBoundRect(tools::Rectangle& rRect) const
         if (pGlyph->GetGlyphBoundRect(pGlyphFont, aRectangle))
         {
             // merge rectangle
-            aRectangle += aPos;
+            aRectangle += Point(aPos.getX(), aPos.getY());
             if (rRect.IsEmpty())
                 rRect = aRectangle;
             else
@@ -322,7 +333,7 @@ void GenericSalLayout::Justify( DeviceCoordinate nNewWidth )
         for( pGlyphIter = m_GlyphItems.begin(); pGlyphIter != pGlyphIterRight; 
++pGlyphIter )
         {
             // move glyph to justified position
-            pGlyphIter->m_aLinearPos.AdjustX(nDeltaSum );
+            pGlyphIter->m_aLinearPos.adjustX(nDeltaSum);
 
             // do not stretch non-stretchable glyphs
             if( pGlyphIter->IsDiacritic() || (nStretchable <= 0) )
@@ -438,7 +449,7 @@ void GenericSalLayout::ApplyAsianKerning(const OUString& 
rStr)
 
         // adjust the glyph positions to the new glyph widths
         if( pGlyphIter+1 != pGlyphIterEnd )
-            pGlyphIter->m_aLinearPos.AdjustX(nOffset);
+            pGlyphIter->m_aLinearPos.adjustX(nOffset);
     }
 }
 
@@ -491,7 +502,7 @@ sal_Int32 GenericSalLayout::GetTextBreak( DeviceCoordinate 
nMaxWidth, DeviceCoor
 }
 
 bool GenericSalLayout::GetNextGlyph(const GlyphItem** pGlyph,
-                                    Point& rPos, int& nStart,
+                                    DevicePoint& rPos, int& nStart,
                                     const LogicalFontInstance** ppGlyphFont,
                                     const vcl::font::PhysicalFontFace**) const
 {
@@ -521,10 +532,10 @@ bool GenericSalLayout::GetNextGlyph(const GlyphItem** 
pGlyph,
         *ppGlyphFont = m_GlyphItems.GetFont().get();
 
     // calculate absolute position in pixel units
-    Point aRelativePos = pGlyphIter->m_aLinearPos;
+    DevicePoint aRelativePos = pGlyphIter->m_aLinearPos;
 
-    aRelativePos.setX( aRelativePos.X() / mnUnitsPerPixel );
-    aRelativePos.setY( aRelativePos.Y() / mnUnitsPerPixel );
+    aRelativePos.setX( aRelativePos.getX() / mnUnitsPerPixel );
+    aRelativePos.setY( aRelativePos.getY() / mnUnitsPerPixel );
     rPos = GetDrawPosition( aRelativePos );
 
     return true;
@@ -550,7 +561,7 @@ void GenericSalLayout::MoveGlyph( int nStart, tools::Long 
nNewXPos )
     {
         for( std::vector<GlyphItem>::iterator pGlyphIterEnd = 
m_GlyphItems.end(); pGlyphIter != pGlyphIterEnd; ++pGlyphIter )
         {
-            pGlyphIter->m_aLinearPos.AdjustX(nXDelta );
+            pGlyphIter->m_aLinearPos.adjustX(nXDelta);
         }
     }
 }
@@ -637,7 +648,7 @@ void MultiSalLayout::AdjustLayout( 
vcl::text::ImplLayoutArgs& rArgs )
     vcl::text::ImplLayoutArgs aMultiArgs = rArgs;
     std::vector<DeviceCoordinate> aJustificationArray;
 
-    if( !rArgs.mpDXArray && rArgs.mnLayoutWidth )
+    if( !rArgs.HasDXArray() && rArgs.mnLayoutWidth )
     {
         // for stretched text in a MultiSalLayout the target width needs to be
         // distributed by individually adjusting its virtual character widths
@@ -702,6 +713,17 @@ void MultiSalLayout::AdjustLayout( 
vcl::text::ImplLayoutArgs& rArgs )
         }
     }
 
+    if (aMultiArgs.mpAltNaturalDXArray)
+        ImplAdjustMultiLayout(rArgs, aMultiArgs, 
aMultiArgs.mpAltNaturalDXArray);
+    else
+        ImplAdjustMultiLayout(rArgs, aMultiArgs, aMultiArgs.mpDXArray);
+}
+
+template<typename DC>
+void MultiSalLayout::ImplAdjustMultiLayout(vcl::text::ImplLayoutArgs& rArgs,
+                                           vcl::text::ImplLayoutArgs& 
rMultiArgs,
+                                           const DC* pMultiDXArray)
+{
     // Compute rtl flags, since in some scripts glyphs/char order can be
     // reversed for a few character sequences e.g. Myanmar
     std::vector<bool> vRtl(rArgs.mnEndCharPos - rArgs.mnMinCharPos, false);
@@ -721,17 +743,17 @@ void MultiSalLayout::AdjustLayout( 
vcl::text::ImplLayoutArgs& rArgs )
     const GlyphItem* pGlyphs[MAX_FALLBACK];
     bool bValid[MAX_FALLBACK] = { false };
 
-    Point aPos;
+    DevicePoint aPos;
     int nLevel = 0, n;
     for( n = 0; n < mnLevel; ++n )
     {
         // now adjust the individual components
         if( n > 0 )
         {
-            aMultiArgs.maRuns = maFallbackRuns[ n-1 ];
-            aMultiArgs.mnFlags |= SalLayoutFlags::ForFallback;
+            rMultiArgs.maRuns = maFallbackRuns[ n-1 ];
+            rMultiArgs.mnFlags |= SalLayoutFlags::ForFallback;
         }
-        mpLayouts[n]->AdjustLayout( aMultiArgs );
+        mpLayouts[n]->AdjustLayout( rMultiArgs );
 
         // remove unused parts of component
         if( n > 0 )
@@ -830,7 +852,7 @@ void MultiSalLayout::AdjustLayout( 
vcl::text::ImplLayoutArgs& rArgs )
         }
 
         // skip to end of layout run and calculate its advance width
-        DeviceCoordinate nRunAdvance = 0;
+        DC nRunAdvance = 0;
         bool bKeepNotDef = (nFBLevel >= nLevel);
         for(;;)
         {
@@ -886,7 +908,7 @@ void MultiSalLayout::AdjustLayout( 
vcl::text::ImplLayoutArgs& rArgs )
                 bKeepNotDef = bNeedFallback;
             }
             // check for reordered glyphs
-            if (aMultiArgs.mpDXArray &&
+            if (pMultiDXArray &&
                 nRunVisibleEndChar < mnEndCharPos &&
                 nRunVisibleEndChar >= mnMinCharPos &&
                 pGlyphs[n]->charPos() < mnEndCharPos &&
@@ -894,14 +916,14 @@ void MultiSalLayout::AdjustLayout( 
vcl::text::ImplLayoutArgs& rArgs )
             {
                 if (vRtl[nActiveCharPos - mnMinCharPos])
                 {
-                    if (aMultiArgs.mpDXArray[nRunVisibleEndChar-mnMinCharPos]
-                        >= aMultiArgs.mpDXArray[pGlyphs[n]->charPos() - 
mnMinCharPos])
+                    if (pMultiDXArray[nRunVisibleEndChar-mnMinCharPos]
+                        >= pMultiDXArray[pGlyphs[n]->charPos() - mnMinCharPos])
                     {
                         nRunVisibleEndChar = pGlyphs[n]->charPos();
                     }
                 }
-                else if (aMultiArgs.mpDXArray[nRunVisibleEndChar-mnMinCharPos]
-                         <= aMultiArgs.mpDXArray[pGlyphs[n]->charPos() - 
mnMinCharPos])
+                else if (pMultiDXArray[nRunVisibleEndChar-mnMinCharPos]
+                         <= pMultiDXArray[pGlyphs[n]->charPos() - 
mnMinCharPos])
                 {
                     nRunVisibleEndChar = pGlyphs[n]->charPos();
                 }
@@ -910,7 +932,7 @@ void MultiSalLayout::AdjustLayout( 
vcl::text::ImplLayoutArgs& rArgs )
 
         // if a justification array is available
         // => use it directly to calculate the corresponding run width
-        if( aMultiArgs.mpDXArray )
+        if (pMultiDXArray)
         {
             // the run advance is the width from the first char
             // in the run to the first char in the next run
@@ -919,16 +941,16 @@ void MultiSalLayout::AdjustLayout( 
vcl::text::ImplLayoutArgs& rArgs )
             if (nActiveCharIndex >= 0 && vRtl[nActiveCharIndex])
             {
               if (nRunVisibleEndChar > mnMinCharPos && nRunVisibleEndChar <= 
mnEndCharPos)
-                  nRunAdvance -= aMultiArgs.mpDXArray[nRunVisibleEndChar - 1 - 
mnMinCharPos];
+                  nRunAdvance -= pMultiDXArray[nRunVisibleEndChar - 1 - 
mnMinCharPos];
               if (nLastRunEndChar > mnMinCharPos && nLastRunEndChar <= 
mnEndCharPos)
-                  nRunAdvance += aMultiArgs.mpDXArray[nLastRunEndChar - 1 - 
mnMinCharPos];
+                  nRunAdvance += pMultiDXArray[nLastRunEndChar - 1 - 
mnMinCharPos];
             }
             else
             {
                 if (nRunVisibleEndChar >= mnMinCharPos)
-                  nRunAdvance += aMultiArgs.mpDXArray[nRunVisibleEndChar - 
mnMinCharPos];
+                  nRunAdvance += pMultiDXArray[nRunVisibleEndChar - 
mnMinCharPos];
                 if (nLastRunEndChar >= mnMinCharPos)
-                  nRunAdvance -= aMultiArgs.mpDXArray[nLastRunEndChar - 
mnMinCharPos];
+                  nRunAdvance -= pMultiDXArray[nLastRunEndChar - mnMinCharPos];
             }
             nLastRunEndChar = nRunVisibleEndChar;
             nRunVisibleEndChar = pGlyphs[nFirstValid]->charPos();
@@ -1105,7 +1127,7 @@ void MultiSalLayout::GetCaretPositions( int nMaxIndex, 
sal_Int32* pCaretXArray )
 }
 
 bool MultiSalLayout::GetNextGlyph(const GlyphItem** pGlyph,
-                                  Point& rPos, int& nStart,
+                                  DevicePoint& rPos, int& nStart,
                                   const LogicalFontInstance** ppGlyphFont,
                                   const vcl::font::PhysicalFontFace** 
pFallbackFont) const
 {
@@ -1123,8 +1145,8 @@ bool MultiSalLayout::GetNextGlyph(const GlyphItem** 
pGlyph,
             nStart |= nFontTag;
             if (pFallbackFont)
                 *pFallbackFont = pFontFace;
-            rPos += maDrawBase;
-            rPos += maDrawOffset;
+            rPos.adjustX(maDrawBase.getX() + maDrawOffset.X());
+            rPos.adjustY(maDrawBase.getY() + maDrawOffset.Y());
             return true;
         }
     }
diff --git a/vcl/source/gdi/virdev.cxx b/vcl/source/gdi/virdev.cxx
index 6a44cc1cd136..87721c683d77 100644
--- a/vcl/source/gdi/virdev.cxx
+++ b/vcl/source/gdi/virdev.cxx
@@ -379,6 +379,8 @@ bool VirtualDevice::ImplSetOutputSizePixel( const Size& 
rNewSize, bool bErase,
             mpAlphaVDev->SetMapMode( GetMapMode() );
 
             mpAlphaVDev->SetAntialiasing( GetAntialiasing() );
+
+            
mpAlphaVDev->SetTextRenderModeForResolutionIndependentLayout(GetTextRenderModeForResolutionIndependentLayout());
         }
 
         return true;
diff --git a/vcl/source/outdev/font.cxx b/vcl/source/outdev/font.cxx
index 5139f1fc03a4..71e4091e754e 100644
--- a/vcl/source/outdev/font.cxx
+++ b/vcl/source/outdev/font.cxx
@@ -1117,7 +1117,7 @@ void OutputDevice::ImplDrawEmphasisMarks( SalLayout& 
rSalLayout )
     tools::Long nEmphasisHeight2 = nEmphasisHeight / 2;
     aOffset += Point( nEmphasisWidth2, nEmphasisHeight2 );
 
-    Point aOutPoint;
+    DevicePoint aOutPoint;
     tools::Rectangle aRectangle;
     const GlyphItem* pGlyph;
     const LogicalFontInstance* pGlyphFont;
@@ -1136,10 +1136,10 @@ void OutputDevice::ImplDrawEmphasisMarks( SalLayout& 
rSalLayout )
                 Point aOriginPt(0, 0);
                 aOriginPt.RotateAround( aAdjPoint, 
mpFontInstance->mnOrientation );
             }
-            aOutPoint += aAdjPoint;
-            aOutPoint -= Point( nEmphasisWidth2, nEmphasisHeight2 );
-            ImplDrawEmphasisMark( rSalLayout.DrawBase().X(),
-                                  aOutPoint.X(), aOutPoint.Y(),
+            aOutPoint.adjustX(aAdjPoint.X() - nEmphasisWidth2);
+            aOutPoint.adjustY(aAdjPoint.Y() - nEmphasisHeight2);
+            ImplDrawEmphasisMark( rSalLayout.DrawBase().getX(),
+                                  aOutPoint.getX(), aOutPoint.getY(),
                                   aPolyPoly, bPolyLine, aRect1, aRect2 );
         }
     }
diff --git a/vcl/source/outdev/map.cxx b/vcl/source/outdev/map.cxx
index 227905f075a8..bb4683f37a19 100644
--- a/vcl/source/outdev/map.cxx
+++ b/vcl/source/outdev/map.cxx
@@ -1879,11 +1879,32 @@ DeviceCoordinate 
OutputDevice::LogicWidthToDeviceCoordinate( tools::Long nWidth
         return static_cast<DeviceCoordinate>(nWidth);
 
 #if VCL_FLOAT_DEVICE_PIXEL
-    return (double)nWidth * maMapRes.mfScaleX * mnDPIX;
+    return ImplLogicToPixel(static_cast<double>(nWidth), mnDPIX, 
maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX);
 #else
-
     return ImplLogicToPixel(nWidth, mnDPIX, maMapRes.mnMapScNumX, 
maMapRes.mnMapScDenomX);
 #endif
 }
 
+double OutputDevice::ImplLogicWidthToDeviceFontWidth(tools::Long nWidth) const
+{
+    if (!mbMap)
+        return nWidth;
+
+    return ImplLogicToPixel(static_cast<double>(nWidth), mnDPIX,
+                            maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX);
+}
+
+DevicePoint OutputDevice::ImplLogicToDeviceFontCoordinate(const Point& rPoint) 
const
+{
+    if (!mbMap)
+        return DevicePoint(rPoint.X() + mnOutOffX, rPoint.Y() + mnOutOffY);
+
+    return DevicePoint(ImplLogicToPixel(static_cast<double>(rPoint.X() + 
maMapRes.mnMapOfsX), mnDPIX,
+                                        maMapRes.mnMapScNumX, 
maMapRes.mnMapScDenomX)
+                                        + mnOutOffX + mnOutOffOrigX,
+                       ImplLogicToPixel(static_cast<double>(rPoint.Y() + 
maMapRes.mnMapOfsY), mnDPIY,
+                                        maMapRes.mnMapScNumY, 
maMapRes.mnMapScDenomY)
+                                        + mnOutOffY + mnOutOffOrigY);
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/outdev/outdev.cxx b/vcl/source/outdev/outdev.cxx
index 9231f7779a6b..1ad7a2e71dd0 100644
--- a/vcl/source/outdev/outdev.cxx
+++ b/vcl/source/outdev/outdev.cxx
@@ -105,6 +105,7 @@ OutputDevice::OutputDevice(OutDevType eOutDevType) :
     meRasterOp                      = RasterOp::OverPaint;
     mnAntialiasing                  = AntialiasingFlags::NONE;
     meTextLanguage                  = LANGUAGE_SYSTEM;  // TODO: get default 
from configuration?
+    mbTextRenderModeForResolutionIndependentLayout = false;
     mbLineColor                     = true;
     mbFillColor                     = true;
     mbInitLineColor                 = true;
@@ -354,16 +355,28 @@ void OutputDevice::SetAntialiasing( AntialiasingFlags 
nMode )
         mnAntialiasing = nMode;
         mbInitFont = true;
 
-        if(mpGraphics)
-        {
+        if (mpGraphics)
             mpGraphics->setAntiAlias(bool(mnAntialiasing & 
AntialiasingFlags::Enable));
-        }
     }
 
     if( mpAlphaVDev )
         mpAlphaVDev->SetAntialiasing( nMode );
 }
 
+void OutputDevice::SetTextRenderModeForResolutionIndependentLayout(bool bMode)
+{
+    if (mbTextRenderModeForResolutionIndependentLayout!= bMode)
+    {
+        mbTextRenderModeForResolutionIndependentLayout = bMode;
+
+        if (mpGraphics)
+            mpGraphics->setTextRenderModeForResolutionIndependentLayout(bMode);
+    }
+
+    if (mpAlphaVDev)
+        mpAlphaVDev->SetTextRenderModeForResolutionIndependentLayout(bMode);
+}
+
 void OutputDevice::SetDrawMode(DrawModeFlags nDrawMode)
 {
     mnDrawMode = nDrawMode;
diff --git a/vcl/source/outdev/text.cxx b/vcl/source/outdev/text.cxx
index a28dc49e5ebd..3d773e56d488 100644
--- a/vcl/source/outdev/text.cxx
+++ b/vcl/source/outdev/text.cxx
@@ -168,9 +168,9 @@ void OutputDevice::ImplDrawTextRect( tools::Long nBaseX, 
tools::Long nBaseY,
 void OutputDevice::ImplDrawTextBackground( const SalLayout& rSalLayout )
 {
     const tools::Long nWidth = rSalLayout.GetTextWidth() / 
rSalLayout.GetUnitsPerPixel();
-    const Point aBase = rSalLayout.DrawBase();
-    const tools::Long nX = aBase.X();
-    const tools::Long nY = aBase.Y();
+    const DevicePoint aBase = rSalLayout.DrawBase();
+    const tools::Long nX = aBase.getX();
+    const tools::Long nY = aBase.getY();
 
     if ( mbLineColor || mbInitLineColor )
     {
@@ -187,9 +187,9 @@ void OutputDevice::ImplDrawTextBackground( const SalLayout& 
rSalLayout )
 
 tools::Rectangle OutputDevice::ImplGetTextBoundRect( const SalLayout& 
rSalLayout ) const
 {
-    Point aPoint = rSalLayout.GetDrawPosition();
-    tools::Long nX = aPoint.X();
-    tools::Long nY = aPoint.Y();
+    DevicePoint aPoint = rSalLayout.GetDrawPosition();
+    tools::Long nX = aPoint.getX();
+    tools::Long nY = aPoint.getY();
 
     tools::Long nWidth = rSalLayout.GetTextWidth();
     tools::Long nHeight = mpFontInstance->mnLineHeight + mnEmphasisAscent + 
mnEmphasisDescent;
@@ -225,11 +225,11 @@ tools::Rectangle OutputDevice::ImplGetTextBoundRect( 
const SalLayout& rSalLayout
 
 bool OutputDevice::ImplDrawRotateText( SalLayout& rSalLayout )
 {
-    tools::Long nX = rSalLayout.DrawBase().X();
-    tools::Long nY = rSalLayout.DrawBase().Y();
+    tools::Long nX = rSalLayout.DrawBase().getX();
+    tools::Long nY = rSalLayout.DrawBase().getY();
 
     tools::Rectangle aBoundRect;
-    rSalLayout.DrawBase() = Point( 0, 0 );
+    rSalLayout.DrawBase() = DevicePoint( 0, 0 );
     rSalLayout.DrawOffset() = Point( 0, 0 );
     if (!rSalLayout.GetBoundRect(aBoundRect))
     {
@@ -261,7 +261,8 @@ bool OutputDevice::ImplDrawRotateText( SalLayout& 
rSalLayout )
     pVDev->ImplInitTextColor();
 
     // draw text into upper left corner
-    rSalLayout.DrawBase() -= aBoundRect.TopLeft();
+    rSalLayout.DrawBase().adjustX(-aBoundRect.Left());
+    rSalLayout.DrawBase().adjustY(-aBoundRect.Top());
     rSalLayout.DrawText( *pVDev->mpGraphics );
 
     Bitmap aBmp = pVDev->GetBitmap( Point(), aBoundRect.GetSize() );
@@ -302,18 +303,18 @@ void OutputDevice::ImplDrawTextDirect( SalLayout& 
rSalLayout,
         if( ImplDrawRotateText( rSalLayout ) )
             return;
 
-    tools::Long nOldX = rSalLayout.DrawBase().X();
+    auto nOldX = rSalLayout.DrawBase().getX();
     if( HasMirroredGraphics() )
     {
         tools::Long w = IsVirtual() ? mnOutWidth : 
mpGraphics->GetGraphicsWidth();
-        tools::Long x = rSalLayout.DrawBase().X();
+        auto x = rSalLayout.DrawBase().getX();
         rSalLayout.DrawBase().setX( w - 1 - x );
         if( !IsRTLEnabled() )
         {
             OutputDevice *pOutDevRef = this;
             // mirror this window back
             tools::Long devX = w-pOutDevRef->mnOutWidth-pOutDevRef->mnOutOffX; 
  // re-mirrored mnOutOffX
-            rSalLayout.DrawBase().setX( devX + ( pOutDevRef->mnOutWidth - 1 - 
(rSalLayout.DrawBase().X() - devX) ) ) ;
+            rSalLayout.DrawBase().setX( devX + ( pOutDevRef->mnOutWidth - 1 - 
(rSalLayout.DrawBase().getX() - devX) ) ) ;
         }
     }
     else if( IsRTLEnabled() )
@@ -322,7 +323,7 @@ void OutputDevice::ImplDrawTextDirect( SalLayout& 
rSalLayout,
 
         // mirror this window back
         tools::Long devX = pOutDevRef->mnOutOffX;   // re-mirrored mnOutOffX
-        rSalLayout.DrawBase().setX( pOutDevRef->mnOutWidth - 1 - 
(rSalLayout.DrawBase().X() - devX) + devX );
+        rSalLayout.DrawBase().setX( pOutDevRef->mnOutWidth - 1 - 
(rSalLayout.DrawBase().getX() - devX) + devX );
     }
 
     rSalLayout.DrawText( *mpGraphics );
@@ -345,7 +346,7 @@ void OutputDevice::ImplDrawSpecialText( SalLayout& 
rSalLayout )
     Color       aOldOverlineColor   = GetOverlineColor();
     FontRelief  eRelief             = maFont.GetRelief();
 
-    Point aOrigPos = rSalLayout.DrawBase();

... etc. - the rest is truncated

Reply via email to