[Libreoffice-commits] core.git: vcl/inc vcl/win

Khaled Hosny khaledhosny at eglug.org
Thu Dec 1 08:50:27 UTC 2016


 vcl/inc/win/salgdi.h      |   39 
 vcl/inc/win/winlayout.hxx |  161 --
 vcl/win/gdi/salfont.cxx   |  129 -
 vcl/win/gdi/salgdi.cxx    |    5 
 vcl/win/gdi/winlayout.cxx | 3173 +---------------------------------------------
 5 files changed, 132 insertions(+), 3375 deletions(-)

New commits:
commit 6c436ba09cb35235ce6f4065cf74c9a6ff14a4bd
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Thu Dec 1 03:33:30 2016 +0200

    Kill old Windows layout engines
    
    Change-Id: I33f8322a6371150698bf926165fb6dddb9d4092c
    Reviewed-on: https://gerrit.libreoffice.org/31452
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Khaled Hosny <khaledhosny at eglug.org>

diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h
index 8471699..d3a7185 100644
--- a/vcl/inc/win/salgdi.h
+++ b/vcl/inc/win/salgdi.h
@@ -74,27 +74,16 @@ public:
 
     BYTE                    GetCharSet() const          { return meWinCharSet; }
     BYTE                    GetPitchAndFamily() const   { return mnPitchAndFamily; }
-    bool                    SupportsCJK() const         { return mbHasCJKSupport; }
-    bool                    SupportsArabic() const      { return mbHasArabicSupport; }
 
     FontCharMapRef          GetFontCharMap() const;
     bool GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const;
-    const Ucs2SIntMap* GetEncodingVector() const { return mpEncodingVector; }
-    void SetEncodingVector( const Ucs2SIntMap* pNewVec ) const
-    {
-        if( mpEncodingVector )
-            delete mpEncodingVector;
-        mpEncodingVector = pNewVec;
-    }
+
 private:
     sal_IntPtr              mnId;
 
     // some members that are initalized lazily when the font gets selected into a HDC
-    mutable bool                    mbHasCJKSupport;
-    mutable bool                    mbHasArabicSupport;
     mutable bool                    mbFontCapabilitiesRead;
     mutable FontCharMapRef          mxUnicodeMap;
-    mutable const Ucs2SIntMap*      mpEncodingVector;
     mutable vcl::FontCapabilities   maFontCapabilities;
 
     BYTE                    meWinCharSet;
@@ -105,14 +94,8 @@ private:
     void                    ReadCmapTable( HDC ) const;
     void                    GetFontCapabilities( HDC hDC ) const;
 
-    void                    ReadGsubTable( HDC ) const;
-
-    mutable std::unordered_set<sal_UCS4>      maGsubTable;
-    mutable bool            mbGsubRead;
     mutable hb_font_t*      mpHbFont;
 public:
-    bool                    HasGSUBstitutions( HDC ) const;
-    bool                    IsGSUBstituted( sal_UCS4 ) const;
     hb_font_t*              GetHbFont() const { return mpHbFont; }
     void                    SetHbFont( hb_font_t* pHbFont ) const { mpHbFont = pHbFont; }
 };
@@ -168,9 +151,6 @@ class WinSalGraphics : public SalGraphics
     friend class WinOpenGLSalGraphicsImpl;
     friend class ScopedFont;
     friend class OpenGLCompatibleDC;
-    friend class WinLayout;
-    friend class SimpleWinLayout;
-    friend class UniscribeLayout;
 
 protected:
     std::unique_ptr<SalGraphicsImpl> mpImpl;
@@ -196,9 +176,6 @@ private:
     COLORREF                mnTextColor;        // TextColor
     RGNDATA*                mpClipRgnData;      // ClipRegion-Data
     RGNDATA*                mpStdClipRgnData;   // Cache Standard-ClipRegion-Data
-    bool                    mbFontKernInit;     // FALSE: FontKerns must be queried
-    KERNINGPAIR*            mpFontKernPairs;    // Kerning Pairs of the current Font
-    sal_uIntPtr             mnFontKernPairCount;// Number of Kerning Pairs of the current Font
     int                     mnPenWidth;         // Linienbreite
 
     LogicalFontInstance* GetWinFontEntry(int nFallbackLevel);
@@ -321,9 +298,6 @@ protected:
 private:
     // local helpers
 
-    // get kernign pairs of the current font
-    sal_uLong               GetKernPairs();
-
     static void             DrawTextLayout(const CommonSalLayout&, HDC, bool bUseDWrite);
 
 public:
@@ -427,17 +401,6 @@ void    ImplGetLogFontFromFontSelect( HDC, const FontSelectPattern*,
 
 #define MAX_64KSALPOINTS    ((((sal_uInt16)0xFFFF)-8)/sizeof(POINTS))
 
-// #102411# Win's GCP mishandles kerning => we need to do it ourselves
-// SalGraphicsData::mpFontKernPairs is sorted by
-inline bool ImplCmpKernData( const KERNINGPAIR& a, const KERNINGPAIR& b )
-{
-    if( a.wFirst < b.wFirst )
-        return true;
-    if( a.wFirst > b.wFirst )
-        return false;
-    return (a.wSecond < b.wSecond);
-}
-
 // called extremely often from just one spot => inline
 inline bool WinFontFace::HasChar( sal_uInt32 cChar ) const
 {
diff --git a/vcl/inc/win/winlayout.hxx b/vcl/inc/win/winlayout.hxx
index ff57506..d339df3 100644
--- a/vcl/inc/win/winlayout.hxx
+++ b/vcl/inc/win/winlayout.hxx
@@ -35,7 +35,6 @@
 typedef std::unordered_map<int,int> IntMap;
 
 class WinFontInstance;
-struct VisualItem;
 
 namespace
 {
@@ -53,7 +52,6 @@ struct OpenGLGlyphDrawElement
     int mnBaselineOffset;
     int mnHeight;
     bool mbVertical;
-    bool mbRealGlyphIndices;
 
     int getExtraSpace() const
     {
@@ -160,24 +158,12 @@ private:
     // TODO: also add HFONT??? Watch out for issues with too many active fonts...
 
 public:
-    bool                    HasKernData() const;
-    void                    SetKernData( int, const KERNINGPAIR* );
-    int                     GetKerning( sal_Unicode, sal_Unicode ) const;
-
-private:
-    KERNINGPAIR*            mpKerningPairs;
-    int                     mnKerningPairs;
-
-public:
     SCRIPT_CACHE&           GetScriptCache() const
                             { return maScriptCache; }
 private:
     mutable SCRIPT_CACHE    maScriptCache;
 
 public:
-    int                     GetCachedGlyphWidth( int nCharCode ) const;
-    void                    CacheGlyphWidth( int nCharCode, int nCharWidth );
-
     bool                    InitKashidaHandling( HDC );
     int                     GetMinKashidaWidth() const { return mnMinKashidaWidth; }
     int                     GetMinKashidaGlyph() const { return mnMinKashidaGlyph; }
@@ -185,7 +171,7 @@ public:
 private:
     GlyphCache maGlyphCache;
 public:
-    bool CacheGlyphToAtlas(bool bRealGlyphIndices, int nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics);
+    bool CacheGlyphToAtlas(HDC hDC, HFONT hFont, int nGlyphIndex, SalGraphics& rGraphics);
 
     GlyphCache& GetGlyphCache()
     {
@@ -193,155 +179,10 @@ public:
     }
 
 private:
-    std::unordered_map<int, int>    maWidthMap;
     mutable int                     mnMinKashidaWidth;
     mutable int                     mnMinKashidaGlyph;
 };
 
-class WinLayout : public SalLayout
-{
-public:
-                        WinLayout(HDC, const WinFontFace&, WinFontInstance&, bool bUseOpenGL);
-    virtual             ~WinLayout() override;
-    virtual void        InitFont() const override;
-    void                SetFontScale( float f ) { mfFontScale = f; }
-    HFONT               DisableFontScaling() const;
-
-    SCRIPT_CACHE&       GetScriptCache() const;
-
-    /// In the non-OpenGL case, call the DrawTextImpl directly, otherwise make
-    /// sure we draw to an interim texture.
-    virtual void        DrawText(SalGraphics&) const override;
-
-    /// Draw to the provided HDC.
-    virtual bool        DrawTextImpl(HDC hDC, const Rectangle* pRectToErase, Point* pPos, int* pGetNextGlypInfo) const = 0;
-
-    virtual bool        CacheGlyphs(SalGraphics& rGraphics) const = 0;
-    virtual bool        DrawCachedGlyphs(SalGraphics& rGraphics) const = 0;
-
-    HDC                 mhDC;               // WIN32 device handle
-    HFONT               mhFont;             // WIN32 font handle
-    int                 mnBaseAdv;          // x-offset relative to Layout origin
-    float               mfFontScale;        // allows metrics emulation of huge font sizes
-    bool                mbUseOpenGL;        ///< We need to render via OpenGL
-
-    const WinFontFace& mrWinFontData;
-    WinFontInstance&   mrWinFontEntry;
-};
-
-class SimpleWinLayout : public WinLayout
-{
-public:
-                    SimpleWinLayout(HDC, const WinFontFace&, WinFontInstance&, bool bUseOpenGL);
-    virtual         ~SimpleWinLayout() override;
-
-    virtual bool    LayoutText( ImplLayoutArgs& ) override;
-    virtual void    AdjustLayout( ImplLayoutArgs& ) override;
-    virtual bool    DrawTextImpl(HDC hDC, const Rectangle* pRectToErase, Point* pPos, int* pGetNextGlypInfo) const override;
-
-    virtual bool    CacheGlyphs(SalGraphics& rGraphics) const override;
-    virtual bool    DrawCachedGlyphs(SalGraphics& rGraphics) const override;
-    virtual int     GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int&,
-                                   DeviceCoordinate* pGlyphAdvances = nullptr, int* pCharIndexes = nullptr,
-                                   const PhysicalFontFace** pFallbackFonts = nullptr ) const override;
-
-    virtual DeviceCoordinate FillDXArray( DeviceCoordinate* pDXArray ) const override;
-    virtual sal_Int32 GetTextBreak(DeviceCoordinate nMaxWidth, DeviceCoordinate nCharExtra, int nFactor) const override;
-    virtual void    GetCaretPositions( int nArraySize, long* pCaretXArray ) const override;
-
-    // for glyph+font+script fallback
-    virtual void    MoveGlyph( int nStart, long nNewXPos ) override;
-    virtual void    DropGlyph( int nStart ) override;
-    virtual void    Simplify( bool bIsBase ) override;
-
-protected:
-    void            Justify( DeviceCoordinate nNewWidth );
-    void            ApplyDXArray( const ImplLayoutArgs& );
-
-private:
-    int             mnGlyphCount;
-    int             mnCharCount;
-    WCHAR*          mpOutGlyphs;
-    int*            mpGlyphAdvances;    // if possible this is shared with mpGlyphAdvances[]
-    int*            mpGlyphOrigAdvs;
-    int*            mpCharWidths;       // map rel char pos to char width
-    int*            mpChars2Glyphs;     // map rel char pos to abs glyph pos
-    int*            mpGlyphs2Chars;     // map abs glyph pos to abs char pos
-    bool*           mpGlyphRTLFlags;    // BiDi status for glyphs: true=>RTL
-    mutable long    mnWidth;
-
-    int             mnNotdefWidth;
-};
-
-class UniscribeLayout : public WinLayout
-{
-public:
-                    UniscribeLayout(HDC, const WinFontFace&, WinFontInstance&, bool bUseOpenGL);
-
-    virtual bool    LayoutText( ImplLayoutArgs& ) override;
-    virtual void    AdjustLayout( ImplLayoutArgs& ) override;
-    virtual bool    DrawTextImpl(HDC hDC, const Rectangle* pRectToErase, Point* pPos, int* pGetNextGlypInfo) const override;
-    virtual bool    CacheGlyphs(SalGraphics& rGraphics) const override;
-    virtual bool    DrawCachedGlyphs(SalGraphics& rGraphics) const override;
-    virtual int     GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int&,
-                                   DeviceCoordinate* pGlyphAdvances = nullptr, int* pCharPosAry = nullptr,
-                                   const PhysicalFontFace** pFallbackFonts = nullptr ) const override;
-
-    virtual DeviceCoordinate FillDXArray( DeviceCoordinate* pDXArray ) const override;
-    virtual sal_Int32 GetTextBreak(DeviceCoordinate nMaxWidth, DeviceCoordinate nCharExtra, int nFactor) const override;
-    virtual void    GetCaretPositions( int nArraySize, long* pCaretXArray ) const override;
-    virtual bool    IsKashidaPosValid ( int nCharPos ) const override;
-
-    // for glyph+font+script fallback
-    virtual void    MoveGlyph( int nStart, long nNewXPos ) override;
-    virtual void    DropGlyph( int nStart ) override;
-    virtual void    Simplify( bool bIsBase ) override;
-    virtual void    DisableGlyphInjection( bool bDisable ) override { mbDisableGlyphInjection = bDisable; }
-
-protected:
-    virtual         ~UniscribeLayout() override;
-
-    void            Justify( DeviceCoordinate nNewWidth );
-    void            ApplyDXArray( const ImplLayoutArgs& );
-
-    bool            GetItemSubrange( const VisualItem&,
-                        int& rMinIndex, int& rEndIndex ) const;
-
-private:
-    // item specific info
-    SCRIPT_ITEM*    mpScriptItems;      // in logical order
-    VisualItem*     mpVisualItems;      // in visual order
-    int             mnItemCount;        // number of visual items
-
-    // string specific info
-    // everything is in logical order
-    OUString        msTheString;        // Sadly we need it in GetNextGlyphs(), to be able to call GetVerticalFlags()
-    int             mnCharCapacity;
-    WORD*           mpLogClusters;      // map from absolute_char_pos to relative_glyph_pos
-    int*            mpCharWidths;       // map from absolute_char_pos to char_width
-    int             mnSubStringMin;     // char_pos of first char in context
-
-    // glyph specific info
-    // everything is in visual order
-    int             mnGlyphCount;
-    int             mnGlyphCapacity;
-    int*            mpGlyphAdvances;    // glyph advance width before justification
-    int*            mpJustifications;   // glyph advance width after justification
-    WORD*           mpOutGlyphs;        // glyphids in visual order
-    GOFFSET*        mpGlyphOffsets;     // glyph offsets to the "naive" layout
-    SCRIPT_VISATTR* mpVisualAttrs;      // glyph visual attributes
-    mutable int*    mpGlyphs2Chars;     // map from absolute_glyph_pos to absolute_char_pos
-
-    // kashida stuff
-    void InitKashidaHandling();
-    void KashidaItemFix( int nMinGlyphPos, int nEndGlyphPos );
-    bool KashidaWordFix( int nMinGlyphPos, int nEndGlyphPos, int* pnCurrentPos );
-
-    int            mnMinKashidaWidth;
-    int            mnMinKashidaGlyph;
-    bool           mbDisableGlyphInjection;
-};
-
 class TextOutRenderer
 {
 protected:
diff --git a/vcl/win/gdi/salfont.cxx b/vcl/win/gdi/salfont.cxx
index 5d1e6bc..7147be1 100644
--- a/vcl/win/gdi/salfont.cxx
+++ b/vcl/win/gdi/salfont.cxx
@@ -613,16 +613,12 @@ WinFontFace::WinFontFace( const FontAttributes& rDFS,
     int nHeight, BYTE eWinCharSet, BYTE nPitchAndFamily )
 :   PhysicalFontFace( rDFS ),
     mnId( 0 ),
-    mbHasCJKSupport( false ),
-    mbHasArabicSupport ( false ),
     mbFontCapabilitiesRead( false ),
     mxUnicodeMap( nullptr ),
-    mpEncodingVector( nullptr ),
     meWinCharSet( eWinCharSet ),
     mnPitchAndFamily( nPitchAndFamily ),
     mbAliasSymbolsHigh( false ),
     mbAliasSymbolsLow( false ),
-    mbGsubRead( false ),
     mpHbFont( nullptr )
 {
     SetBitmapSize( 0, nHeight );
@@ -657,8 +653,6 @@ WinFontFace::~WinFontFace()
     if( mxUnicodeMap.Is() )
         mxUnicodeMap = nullptr;
 
-    delete mpEncodingVector;
-
     if( mpHbFont )
         hb_font_destroy( mpHbFont );
 }
@@ -681,18 +675,6 @@ void WinFontFace::UpdateFromHDC( HDC hDC ) const
     GetFontCapabilities( hDC );
 }
 
-bool WinFontFace::HasGSUBstitutions( HDC hDC ) const
-{
-    if( !mbGsubRead )
-        ReadGsubTable( hDC );
-    return !maGsubTable.empty();
-}
-
-bool WinFontFace::IsGSUBstituted( sal_UCS4 cChar ) const
-{
-    return( maGsubTable.find( cChar ) != maGsubTable.end() );
-}
-
 FontCharMapRef WinFontFace::GetFontCharMap() const
 {
     return mxUnicodeMap;
@@ -704,51 +686,6 @@ bool WinFontFace::GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities)
     return rFontCapabilities.oUnicodeRange || rFontCapabilities.oCodePageRange;
 }
 
-void WinFontFace::ReadGsubTable( HDC hDC ) const
-{
-    mbGsubRead = true;
-
-    // check the existence of a GSUB table
-    const DWORD GsubTag = CalcTag( "GSUB" );
-    DWORD nRC = ::GetFontData( hDC, GsubTag, 0, nullptr, 0 );
-    if( (nRC == GDI_ERROR) || !nRC )
-        return;
-
-    // parse the GSUB table through sft
-    // TODO: parse it directly
-
-    // sft needs the full font file data => get it
-    const RawFontData aRawFontData( hDC );
-    if( !aRawFontData.get() )
-        return;
-
-    // open font file
-    sal_uInt32 nFaceNum = 0;
-    if( !*aRawFontData.get() )  // TTC candidate
-        nFaceNum = ~0U;  // indicate "TTC font extracts only"
-
-    TrueTypeFont* pTTFont = nullptr;
-    ::OpenTTFontBuffer( aRawFontData.get(), aRawFontData.size(), nFaceNum, &pTTFont );
-    if( !pTTFont )
-        return;
-
-    // add vertically substituted characters to list
-    static const sal_Unicode aGSUBCandidates[] = {
-        0x0020, 0x0080, // ASCII
-        0x2000, 0x2600, // misc
-        0x3000, 0x3100, // CJK punctutation
-        0x3300, 0x3400, // squared words
-        0xFF00, 0xFFF0, // halfwidth|fullwidth forms
-    0 };
-
-    for( const sal_Unicode* pPair = aGSUBCandidates; *pPair; pPair += 2 )
-        for( sal_Unicode cChar = pPair[0]; cChar < pPair[1]; ++cChar )
-            if( ::MapChar( pTTFont, cChar, false ) != ::MapChar( pTTFont, cChar, true ) )
-                maGsubTable.insert( cChar ); // insert GSUBbed unicodes
-
-    CloseTTFont( pTTFont );
-}
-
 void WinFontFace::ReadCmapTable( HDC hDC ) const
 {
     if( mxUnicodeMap.Is() )
@@ -784,37 +721,15 @@ void WinFontFace::GetFontCapabilities( HDC hDC ) const
 
     mbFontCapabilitiesRead = true;
 
-    // GSUB table
-    DWORD nLength;
-    const DWORD GsubTag = CalcTag( "GSUB" );
-    nLength = ::GetFontData( hDC, GsubTag, 0, nullptr, 0 );
-    if( (nLength != GDI_ERROR) && nLength )
-    {
-        std::vector<unsigned char> aTable( nLength );
-        unsigned char* pTable = &aTable[0];
-        ::GetFontData( hDC, GsubTag, 0, pTable, nLength );
-        vcl::getTTScripts(maFontCapabilities.maGSUBScriptTags, pTable, nLength);
-    }
-
     // OS/2 table
     const DWORD OS2Tag = CalcTag( "OS/2" );
-    nLength = ::GetFontData( hDC, OS2Tag, 0, nullptr, 0 );
+    DWORD nLength = ::GetFontData( hDC, OS2Tag, 0, nullptr, 0 );
     if( (nLength != GDI_ERROR) && nLength )
     {
         std::vector<unsigned char> aTable( nLength );
         unsigned char* pTable = &aTable[0];
         ::GetFontData( hDC, OS2Tag, 0, pTable, nLength );
-        if (vcl::getTTCoverage(maFontCapabilities.oUnicodeRange, maFontCapabilities.oCodePageRange, pTable, nLength))
-        {
-            // Check for CJK capabilities of the current font
-            // TODO, we have this info already from getTT, decode bits to
-            // a readable bitset
-            sal_uInt32 ulUnicodeRange1 = GetUInt( pTable + 42 );
-            sal_uInt32 ulUnicodeRange2 = GetUInt( pTable + 46 );
-
-            mbHasCJKSupport = (ulUnicodeRange2 & 0x2DF00000);
-            mbHasArabicSupport = (ulUnicodeRange1 & 0x00002000);
-        }
+        vcl::getTTCoverage(maFontCapabilities.oUnicodeRange, maFontCapabilities.oCodePageRange, pTable, nLength);
     }
 }
 
@@ -1051,17 +966,6 @@ void WinSalGraphics::SetFont( FontSelectPattern* pFont, int nFallbackLevel )
     // now the font is live => update font face
     if( mpWinFontData[ nFallbackLevel ] )
         mpWinFontData[ nFallbackLevel ]->UpdateFromHDC( getHDC() );
-
-    if( !nFallbackLevel )
-    {
-        mbFontKernInit = TRUE;
-        if ( mpFontKernPairs )
-        {
-            delete[] mpFontKernPairs;
-            mpFontKernPairs = nullptr;
-        }
-        mnFontKernPairCount = 0;
-    }
 }
 
 void WinSalGraphics::GetFontMetric( ImplFontMetricDataRef& rxFontMetric, int nFallbackLevel )
@@ -1106,35 +1010,6 @@ void WinSalGraphics::GetFontMetric( ImplFontMetricDataRef& rxFontMetric, int nFa
     rxFontMetric->SetMinKashida( GetMinKashidaWidth() );
 }
 
-sal_uLong WinSalGraphics::GetKernPairs()
-{
-    if ( mbFontKernInit )
-    {
-        if( mpFontKernPairs )
-        {
-            delete[] mpFontKernPairs;
-            mpFontKernPairs = nullptr;
-        }
-        mnFontKernPairCount = 0;
-
-        KERNINGPAIR* pPairs = nullptr;
-        int nCount = ::GetKerningPairsW( getHDC(), 0, nullptr );
-        if( nCount )
-        {
-            pPairs = new KERNINGPAIR[ nCount+1 ];
-            mpFontKernPairs = pPairs;
-            mnFontKernPairCount = nCount;
-            ::GetKerningPairsW( getHDC(), nCount, pPairs );
-        }
-
-        mbFontKernInit = FALSE;
-
-        std::sort( mpFontKernPairs, mpFontKernPairs + mnFontKernPairCount, ImplCmpKernData );
-    }
-
-    return mnFontKernPairCount;
-}
-
 const FontCharMapRef WinSalGraphics::GetFontCharMap() const
 {
     if( !mpWinFontData[0] )
diff --git a/vcl/win/gdi/salgdi.cxx b/vcl/win/gdi/salgdi.cxx
index 2956fed..4c63eea 100644
--- a/vcl/win/gdi/salgdi.cxx
+++ b/vcl/win/gdi/salgdi.cxx
@@ -615,9 +615,6 @@ WinSalGraphics::WinSalGraphics(WinSalGraphics::Type eType, bool bScreen, HWND hW
     mhDefFont(nullptr),
     mhDefPal(nullptr),
     mpStdClipRgnData(nullptr),
-    mbFontKernInit(false),
-    mpFontKernPairs(nullptr),
-    mnFontKernPairCount(0),
     mnPenWidth(GSL_PEN_WIDTH)
 {
     if (OpenGLHelper::isVCLOpenGLEnabled() && !mbPrinter)
@@ -647,8 +644,6 @@ WinSalGraphics::~WinSalGraphics()
 
     // delete cache data
     delete [] reinterpret_cast<BYTE*>(mpStdClipRgnData);
-
-    delete [] mpFontKernPairs;
 }
 
 SalGraphicsImpl* WinSalGraphics::GetImpl() const
diff --git a/vcl/win/gdi/winlayout.cxx b/vcl/win/gdi/winlayout.cxx
index e2ea865..621c241 100644
--- a/vcl/win/gdi/winlayout.cxx
+++ b/vcl/win/gdi/winlayout.cxx
@@ -37,7 +37,6 @@
 #include <cstdio>
 #include <cstdlib>
 
-#include <sal/alloca.h>
 #include <rtl/character.hxx>
 
 #include <algorithm>
@@ -45,3010 +44,187 @@
 #include <shlwapi.h>
 #include <winver.h>
 
-#include <unordered_map>
-#include <unordered_set>
-
-#define DROPPED_OUTGLYPH 0xFFFF
-
 // static initialization
 std::unique_ptr<GlobalGlyphCache> GlyphCache::gGlobalGlyphCache(new GlobalGlyphCache);
 
-inline void WinFontInstance::CacheGlyphWidth( int nCharCode, int nCharWidth )
-{
-    maWidthMap[ nCharCode ] = nCharWidth;
-}
-
-inline int WinFontInstance::GetCachedGlyphWidth( int nCharCode ) const
-{
-    auto it = maWidthMap.find( nCharCode );
-    if( it == maWidthMap.end() )
-        return -1;
-    return it->second;
-}
-
-bool WinFontInstance::CacheGlyphToAtlas(bool bRealGlyphIndices, int nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics)
+bool WinFontInstance::CacheGlyphToAtlas(HDC hDC, HFONT hFont, int nGlyphIndex, SalGraphics& rGraphics)
 {
-    if (nGlyphIndex == DROPPED_OUTGLYPH)
-        return true;
-
     OpenGLGlyphDrawElement aElement;
-    aElement.mbRealGlyphIndices = bRealGlyphIndices;
-
-    std::vector<uint32_t> aCodePointsOrGlyphIndices(1);
-    aCodePointsOrGlyphIndices[0] = nGlyphIndex;
 
-    HDC hDC = CreateCompatibleDC(rLayout.mhDC);
-    if (hDC == nullptr)
+    HDC hNewDC = CreateCompatibleDC(hDC);
+    if (hNewDC == nullptr)
     {
         SAL_WARN("vcl.gdi", "CreateCompatibleDC failed: " << WindowsErrorString(GetLastError()));
         return false;
     }
-    HFONT hOrigFont = static_cast<HFONT>(SelectObject(hDC, rLayout.mhFont));
-    if (hOrigFont == nullptr)
-    {
-        SAL_WARN("vcl.gdi", "SelectObject failed: " << WindowsErrorString(GetLastError()));
-        DeleteDC(hDC);
-        return false;
-    }
-
-    // For now we assume DWrite is present and we won't bother with fallback paths.
-    D2DWriteTextOutRenderer * pTxt = dynamic_cast<D2DWriteTextOutRenderer *>(&TextOutRenderer::get(true));
-    if (!pTxt)
-        return false;
-
-    if (!pTxt->BindFont(hDC))
-    {
-        SAL_WARN("vcl.gdi", "Binding of font failed. The font might not be supported by Direct Write.");
-        DeleteDC(hDC);
-        return false;
-    }
-
-    // Bail for non-horizontal text.
-    {
-        wchar_t sFaceName[200];
-        int nFaceNameLen = GetTextFaceW(hDC, SAL_N_ELEMENTS(sFaceName), sFaceName);
-
-        if (!nFaceNameLen)
-            SAL_WARN("vcl.gdi", "GetTextFace failed: " << WindowsErrorString(GetLastError()));
-
-        LOGFONTW aLogFont;
-        GetObjectW(rLayout.mhFont, sizeof(LOGFONTW), &aLogFont);
-
-        SelectObject(hDC, hOrigFont);
-        DeleteDC(hDC);
-
-        if (sFaceName[0] == '@' || aLogFont.lfOrientation != 0 || aLogFont.lfEscapement != 0)
-        {
-            pTxt->ReleaseFont();
-            return false;
-        }
-    }
-    std::vector<WORD> aGlyphIndices(1);
-    // Fetch the ink boxes and calculate the size of the atlas.
-    if (!bRealGlyphIndices)
-    {
-        if (!pTxt->GetFontFace())
-        {
-            SAL_WARN("vcl.gdi", "Font face is not available.");
-            return false;
-        }
-        if (!SUCCEEDED(pTxt->GetFontFace()->GetGlyphIndices(aCodePointsOrGlyphIndices.data(), aCodePointsOrGlyphIndices.size(), aGlyphIndices.data())))
-        {
-            pTxt->ReleaseFont();
-            return false;
-        }
-    }
-    else
-    {
-        aGlyphIndices[0] = aCodePointsOrGlyphIndices[0];
-    }
-
-    Rectangle bounds(0, 0, 0, 0);
-    auto aInkBoxes = pTxt->GetGlyphInkBoxes(aGlyphIndices.data(), aGlyphIndices.data() + 1);
-    for (auto &box : aInkBoxes)
-        bounds.Union(box + Point(bounds.Right(), 0));
-
-    // bounds.Top() is the offset from the baseline at (0,0) to the top of the
-    // inkbox.
-    aElement.mnBaselineOffset = -bounds.Top();
-    aElement.mnHeight = bounds.getHeight();
-    aElement.mbVertical = false;
-
-    // Try hard to avoid overlap as we want to be able to use
-    // individual rectangles for each glyph. The ABC widths don't
-    // take anti-aliasing into consideration. Let's hope that leaving
-    // "extra" space between glyphs will help.
-    std::vector<float> aGlyphAdv(1);   // offsets between glyphs
-    std::vector<DWRITE_GLYPH_OFFSET> aGlyphOffset(1, DWRITE_GLYPH_OFFSET{0.0f, 0.0f});
-    std::vector<int> aEnds(1); // end of each glyph box
-    float totWidth = 0;
-    {
-        int overhang = aInkBoxes[0].Left();
-        int blackWidth = aInkBoxes[0].getWidth(); // width of non-AA pixels
-        aElement.maLeftOverhangs = overhang;
-
-        aGlyphAdv[0] = blackWidth + aElement.getExtraSpace();
-        aGlyphOffset[0].advanceOffset = -overhang;
-
-        totWidth += aGlyphAdv[0];
-        aEnds[0] = totWidth;
-    }
-    // Leave extra space also at top and bottom
-    int nBitmapWidth = totWidth;
-    int nBitmapHeight = bounds.getHeight() + aElement.getExtraSpace();
-
-    UINT nPos = 0;
-
-    // FIXME: really I don't get why 'vertical' makes any difference [!] what does it mean !?
-    if (aElement.mbVertical)
-    {
-        aElement.maLocation.Left() = 0;
-        aElement.maLocation.Right() = nBitmapWidth;
-        aElement.maLocation.Top() = nPos;
-        aElement.maLocation.Bottom() = nPos + aGlyphAdv[0] + aElement.maLeftOverhangs;
-    }
-    else
-    {
-        aElement.maLocation.Left() = nPos;
-        aElement.maLocation.Right() = aEnds[0];
-        aElement.maLocation.Top() = 0;
-        aElement.maLocation.Bottom() = bounds.getHeight() + aElement.getExtraSpace();
-    }
-    nPos = aEnds[0];
-
-    OpenGLCompatibleDC aDC(rGraphics, 0, 0, nBitmapWidth, nBitmapHeight);
-
-    HFONT hNonAntialiasedFont = nullptr;
-
-    SetTextColor(aDC.getCompatibleHDC(), RGB(0, 0, 0));
-    SetBkColor(aDC.getCompatibleHDC(), RGB(255, 255, 255));
-
-    aDC.fill(MAKE_SALCOLOR(0xff, 0xff, 0xff));
-
-    pTxt->BindDC(aDC.getCompatibleHDC(), Rectangle(0, 0, nBitmapWidth, nBitmapHeight));
-    auto pRT = pTxt->GetRenderTarget();
-
-    ID2D1SolidColorBrush* pBrush = nullptr;
-    if (!SUCCEEDED(pRT->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &pBrush)))
-    {
-        pTxt->ReleaseFont();
-        return false;
-    }
-
-    D2D1_POINT_2F baseline = {
-        aElement.getExtraOffset(),
-        aElement.getExtraOffset() + aElement.mnBaselineOffset
-    };
-
-    DWRITE_GLYPH_RUN glyphs = {
-        pTxt->GetFontFace(),
-        pTxt->GetEmHeight(),
-        1,
-        aGlyphIndices.data(),
-        aGlyphAdv.data(),
-        aGlyphOffset.data(),
-        false,
-        0
-    };
-
-    pRT->BeginDraw();
-    pRT->DrawGlyphRun(baseline, &glyphs, pBrush);
-    HRESULT hResult = pRT->EndDraw();
-
-    pBrush->Release();
-
-    switch (hResult)
-    {
-    case S_OK:
-        break;
-    case D2DERR_RECREATE_TARGET:
-        pTxt->CreateRenderTarget();
-        break;
-    default:
-        SAL_WARN("vcl.gdi", "DrawGlyphRun-EndDraw failed: " << WindowsErrorString(GetLastError()));
-        SelectFont(aDC.getCompatibleHDC(), hOrigFont);
-        if (hNonAntialiasedFont != nullptr)
-            DeleteObject(hNonAntialiasedFont);
-        return false;
-    }
-
-    pTxt->ReleaseFont();
-
-    if (!GlyphCache::ReserveTextureSpace(aElement, nBitmapWidth, nBitmapHeight))
-        return false;
-    if (!aDC.copyToTexture(aElement.maTexture))
-        return false;
-
-    maGlyphCache.PutDrawElementInCache(aElement, nGlyphIndex);
-
-    SelectFont(aDC.getCompatibleHDC(), hOrigFont);
-    if (hNonAntialiasedFont != nullptr)
-        DeleteObject(hNonAntialiasedFont);
-
-    return true;
-}
-
-SimpleWinLayout::SimpleWinLayout(HDC hDC, const WinFontFace& rWinFontData,
-        WinFontInstance& rWinFontEntry, bool bUseOpenGL)
-:   WinLayout(hDC, rWinFontData, rWinFontEntry, bUseOpenGL),
-    mnGlyphCount( 0 ),
-    mnCharCount( 0 ),
-    mpOutGlyphs( nullptr ),
-    mpGlyphAdvances( nullptr ),
-    mpGlyphOrigAdvs( nullptr ),
-    mpCharWidths( nullptr ),
-    mpChars2Glyphs( nullptr ),
-    mpGlyphs2Chars( nullptr ),
-    mpGlyphRTLFlags( nullptr ),
-    mnWidth( 0 ),
-    mnNotdefWidth( -1 )
-{
-}
-
-SimpleWinLayout::~SimpleWinLayout()
-{
-    delete[] mpGlyphRTLFlags;
-    delete[] mpGlyphs2Chars;
-    delete[] mpChars2Glyphs;
-    if( mpCharWidths != mpGlyphAdvances )
-        delete[] mpCharWidths;
-    delete[] mpGlyphOrigAdvs;
-    delete[] mpGlyphAdvances;
-    delete[] mpOutGlyphs;
-}
-
-bool SimpleWinLayout::LayoutText( ImplLayoutArgs& rArgs )
-{
-    // prepare layout
-    // TODO: fix case when recyclying old SimpleWinLayout object
-    mnCharCount = rArgs.mnEndCharPos - rArgs.mnMinCharPos;
-
-    // TODO: use a cached value for bDisableAsianKern from upper layers
-    if( rArgs.mnFlags & SalLayoutFlags::KerningAsian )
-    {
-        TEXTMETRICA aTextMetricA;
-        if( GetTextMetricsA( mhDC, &aTextMetricA )
-        && !(aTextMetricA.tmPitchAndFamily & TMPF_FIXED_PITCH) && !(aTextMetricA.tmCharSet == 0x86) )
-            rArgs.mnFlags &= ~SalLayoutFlags::KerningAsian;
-    }
-
-    // layout text
-    int i, j;
-
-    mnGlyphCount = 0;
-    bool bVertical(rArgs.mnFlags & SalLayoutFlags::Vertical);
-
-    // count the number of chars to process if no RTL run
-    rArgs.ResetPos();
-    bool bHasRTL = false;
-    while( rArgs.GetNextRun( &i, &j, &bHasRTL ) && !bHasRTL )
-        mnGlyphCount += j - i;
-
-    // if there are RTL runs we need room to remember individual BiDi flags
-    if( bHasRTL )
-    {
-        mpGlyphRTLFlags = new bool[ mnCharCount ];
-        for( i = 0; i < mnCharCount; ++i )
-            mpGlyphRTLFlags[i] = false;
-    }
-
-    // rewrite the logical string if needed to prepare for the API calls
-    const sal_Unicode* pBidiStr = rArgs.mrStr.pData->buffer + rArgs.mnMinCharPos;
-    if( (mnGlyphCount != mnCharCount) || bVertical )
-    {
-        // we need to rewrite the pBidiStr when any of
-        // - BiDirectional layout
-        // - vertical layout
-        // - partial runs (e.g. with control chars or for glyph fallback)
-        // are involved
-        sal_Unicode* pRewrittenStr = static_cast<sal_Unicode*>(alloca( mnCharCount * sizeof(sal_Unicode) ));
-        pBidiStr = pRewrittenStr;
-
-        // note: glyph to char mapping is relative to first character
-        mpChars2Glyphs = new int[ mnCharCount ];
-        mpGlyphs2Chars = new int[ mnCharCount ];
-        for( i = 0; i < mnCharCount; ++i )
-            mpChars2Glyphs[i] = mpGlyphs2Chars[i] = -1;
-
-        mnGlyphCount = 0;
-        rArgs.ResetPos();
-        bool bIsRTL = false;
-        while( rArgs.GetNextRun( &i, &j, &bIsRTL ) )
-        {
-            do
-            {
-                // get the next leftmost character in this run
-                int nCharPos = bIsRTL ? --j : i++;
-                sal_UCS4 cChar = rArgs.mrStr[ nCharPos ];
-
-                // in the RTL case mirror the character and remember its RTL status
-                if( bIsRTL )
-                {
-                    cChar = GetMirroredChar( cChar );
-                    mpGlyphRTLFlags[ mnGlyphCount ] = true;
-                }
-
-                // rewrite the original string
-                // update the mappings between original and rewritten string
-               // TODO: support surrogates in rewritten strings
-                pRewrittenStr[ mnGlyphCount ] = static_cast<sal_Unicode>(cChar);
-                mpGlyphs2Chars[ mnGlyphCount ] = nCharPos;
-                mpChars2Glyphs[ nCharPos - rArgs.mnMinCharPos ] = mnGlyphCount;
-                ++mnGlyphCount;
-            } while( i < j );
-        }
-    }
-
-    mpOutGlyphs     = new WCHAR[ mnGlyphCount ];
-    mpGlyphAdvances = new int[ mnGlyphCount ];
-
-    if( rArgs.mnFlags & (SalLayoutFlags::KerningPairs | SalLayoutFlags::KerningAsian) )
-        mpGlyphOrigAdvs = new int[ mnGlyphCount ];
-
-    for( i = 0; i < mnGlyphCount; ++i )
-        mpOutGlyphs[i] = pBidiStr[ i ];
-    mnWidth = 0;
-    for( i = 0; i < mnGlyphCount; ++i )
-    {
-        // get the current UCS-4 code point, check for surrogate pairs
-        const WCHAR* pCodes = reinterpret_cast<LPCWSTR>(&pBidiStr[i]);
-        unsigned nCharCode = pCodes[0];
-        bool bSurrogate = ((nCharCode >= 0xD800) && (nCharCode <= 0xDFFF));
-        if( bSurrogate )
-        {
-            // ignore high surrogates, they were already processed with their low surrogates
-            if( nCharCode >= 0xDC00 )
-                continue;
-            // check the second half of the surrogate pair
-            bSurrogate &= (0xDC00 <= pCodes[1]) && (pCodes[1] <= 0xDFFF);
-            // calculate the UTF-32 code of valid surrogate pairs
-            if( bSurrogate )
-                nCharCode = 0x10000 + ((pCodes[0] - 0xD800) << 10) + (pCodes[1] - 0xDC00);
-            else // or fall back to a replacement character
-            {
-                // FIXME: Surely this is an error situation that should not happen?
-                nCharCode = '?';
-            }
-        }
-
-        int nGlyphWidth = 0;
-        // Unicode variance selectors selects glyph of previous base character, do not have width itself.
-        if ( (nCharCode >= 0xFE00 && nCharCode <= 0xFE0F) || (nCharCode >= 0xE0100 && nCharCode <= 0xE01EF) )
-        {
-            mpOutGlyphs[ i ] = DROPPED_OUTGLYPH;
-            mpGlyphAdvances[ i ] = 0;
-            if ( bSurrogate &&  ( i+1 ) < mnGlyphCount )
-            {
-                mpOutGlyphs[ ++i ] = DROPPED_OUTGLYPH;
-                mpGlyphAdvances[ i ] = 0;
-            }
-            continue;
-        }
-        else
-        {
-            // get the advance width for the current UTF-32 code point
-             nGlyphWidth = mrWinFontEntry.GetCachedGlyphWidth( nCharCode );
-        }
-
-        if( nGlyphWidth == -1 )
-        {
-            ABC aABC;
-            SIZE aExtent;
-            if( GetTextExtentPoint32W( mhDC, &pCodes[0], bSurrogate ? 2 : 1, &aExtent) )
-                nGlyphWidth = aExtent.cx;
-            else if( GetCharABCWidthsW( mhDC, nCharCode, nCharCode, &aABC ) )
-                nGlyphWidth = aABC.abcA + aABC.abcB + aABC.abcC;
-            else if( !GetCharWidth32W( mhDC, nCharCode, nCharCode, &nGlyphWidth )
-                 &&  !GetCharWidthW( mhDC, nCharCode, nCharCode, &nGlyphWidth ) )
-                    nGlyphWidth = 0;
-            mrWinFontEntry.CacheGlyphWidth( nCharCode, nGlyphWidth );
-        }
-        mpGlyphAdvances[ i ] = nGlyphWidth;
-        mnWidth += nGlyphWidth;
-
-        // the second half of surrogate pair gets a zero width
-        if( bSurrogate && ((i+1) < mnGlyphCount) )
-            mpGlyphAdvances[ i+1 ] = 0;
-
-        // check with the font face if glyph fallback is needed
-        if( mrWinFontData.HasChar( nCharCode ) )
-            continue;
-
-        // request glyph fallback at this position in the string
-        bool bRTL = mpGlyphRTLFlags && mpGlyphRTLFlags[i];
-        int nCharPos = mpGlyphs2Chars ? mpGlyphs2Chars[i]: i + rArgs.mnMinCharPos;
-        rArgs.NeedFallback( nCharPos, bRTL );
-        if( bSurrogate && ((nCharPos+1) < rArgs.mrStr.getLength()) )
-            rArgs.NeedFallback( nCharPos+1, bRTL );
-
-        // replace the current glyph shape with the NotDef glyph shape
-        if( rArgs.mnFlags & SalLayoutFlags::ForFallback )
-        {
-            // when we already are layouting for glyph fallback
-            // then a new unresolved glyph is not interesting
-            mnNotdefWidth = 0;
-            mpOutGlyphs[i] = DROPPED_OUTGLYPH;
-        }
-        else
-        {
-            if( mnNotdefWidth < 0 )
-            {
-                // get the width of the NotDef glyph
-                SIZE aExtent;
-                WCHAR cNotDef = rArgs.mrStr[ nCharPos ];
-                mnNotdefWidth = 0;
-                if( GetTextExtentPoint32W( mhDC, &cNotDef, 1, &aExtent) )
-                    mnNotdefWidth = aExtent.cx;
-            }
-        }
-        if( bSurrogate && ((i+1) < mnGlyphCount) )
-            mpOutGlyphs[i+1] = DROPPED_OUTGLYPH;
-
-        // adjust the current glyph width to the NotDef glyph width
-        mnWidth += mnNotdefWidth - mpGlyphAdvances[i];
-        mpGlyphAdvances[i] = mnNotdefWidth;
-        if( mpGlyphOrigAdvs )
-            mpGlyphOrigAdvs[i] = mnNotdefWidth;
-    }
-
-    // apply kerning if the layout engine has not yet done it
-    if( rArgs.mnFlags & (SalLayoutFlags::KerningAsian|SalLayoutFlags::KerningPairs) )
-    {
-        for( i = 0; i < mnGlyphCount; ++i )
-            mpGlyphOrigAdvs[i] = mpGlyphAdvances[i];
-
-        // #99658# also apply asian kerning on the substring border
-        int nLen = mnGlyphCount;
-        if( rArgs.mnMinCharPos + nLen < rArgs.mrStr.getLength() )
-            ++nLen;
-        for( i = 1; i < nLen; ++i )
-        {
-            if( rArgs.mnFlags & SalLayoutFlags::KerningPairs )
-            {
-                int nKernAmount = mrWinFontEntry.GetKerning( pBidiStr[i-1], pBidiStr[i] );
-                mpGlyphAdvances[ i-1 ] += nKernAmount;
-                mnWidth += nKernAmount;
-            }
-            else if( rArgs.mnFlags & SalLayoutFlags::KerningAsian )
-
-            if( ( (0x3000 == (0xFF00 & pBidiStr[i-1])) || (0x2010 == (0xFFF0 & pBidiStr[i-1])) || (0xFF00 == (0xFF00 & pBidiStr[i-1])))
-            &&  ( (0x3000 == (0xFF00 & pBidiStr[i])) || (0x2010 == (0xFFF0 & pBidiStr[i])) || (0xFF00 == (0xFF00 & pBidiStr[i])) ) )
-            {
-                long nKernFirst = +CalcAsianKerning( pBidiStr[i-1], true, bVertical );
-                long nKernNext  = -CalcAsianKerning( pBidiStr[i], false, bVertical );
-
-                long nDelta = (nKernFirst < nKernNext) ? nKernFirst : nKernNext;
-                if( nDelta<0 && nKernFirst!=0 && nKernNext!=0 )
-                {
-                    nDelta = (nDelta * mpGlyphAdvances[i-1] + 2) / 4;
-                    mpGlyphAdvances[i-1] += nDelta;
-                    mnWidth += nDelta;
-                }
-            }
-        }
-    }
-
-    // calculate virtual char widths
-    if( !mpGlyphs2Chars )
-        mpCharWidths = mpGlyphAdvances;
-    else
-    {
-        mpCharWidths = new int[ mnCharCount ];
-        for( i = 0; i < mnCharCount; ++i )
-            mpCharWidths[ i ] = 0;
-        for( i = 0; i < mnGlyphCount; ++i )
-        {
-            int k = mpGlyphs2Chars[ i ] - rArgs.mnMinCharPos;
-            if( k >= 0 )
-                mpCharWidths[ k ] += mpGlyphAdvances[ i ];
-        }
-    }
-
-    // scale layout metrics if needed
-    // TODO: does it make the code more simple if the metric scaling
-    // is moved to the methods that need metric scaling (e.g. FillDXArray())?
-    if( mfFontScale != 1.0 )
-    {
-        mnWidth   = (long)(mnWidth * mfFontScale);
-        mnBaseAdv = (int)(mnBaseAdv * mfFontScale);
-        for( i = 0; i < mnCharCount; ++i )
-            mpCharWidths[i] = (int)(mpCharWidths[i] * mfFontScale);
-        if( mpGlyphAdvances != mpCharWidths )
-            for( i = 0; i < mnGlyphCount; ++i )
-                mpGlyphAdvances[i] = (int)(mpGlyphAdvances[i] * mfFontScale);
-        if( mpGlyphOrigAdvs && (mpGlyphOrigAdvs != mpGlyphAdvances) )
-            for( i = 0; i < mnGlyphCount; ++i )
-                mpGlyphOrigAdvs[i] = (int)(mpGlyphOrigAdvs[i] * mfFontScale);
-    }
-
-    return true;
-}
-
-int SimpleWinLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphIds, Point& rPos, int& nStart,
-                                    DeviceCoordinate* pGlyphAdvances, int* pCharIndexes,
-                                    const PhysicalFontFace** /*pFallbackFonts*/ ) const
-{
-    // return zero if no more glyph found
-    if( nStart >= mnGlyphCount )
-        return 0;
-
-    // calculate glyph position relative to layout base
-    // TODO: avoid for nStart!=0 case by reusing rPos
-    long nXOffset = mnBaseAdv;
-    for( int i = 0; i < nStart; ++i )
-        nXOffset += mpGlyphAdvances[ i ];
-
-    // calculate absolute position in pixel units
-    Point aRelativePos( nXOffset, 0 );
-    rPos = GetDrawPosition( aRelativePos );
-
-    int nCount = 0;
-    while( nCount < nLen )
-    {
-        // update return values {aGlyphId,nCharPos,nGlyphAdvance}
-        sal_GlyphId aGlyphId = mpOutGlyphs[ nStart ];
-        if( mnLayoutFlags & SalLayoutFlags::Vertical )
-        {
-            const sal_UCS4 cChar = static_cast<sal_UCS4>(aGlyphId & GF_IDXMASK);
-            if( mrWinFontData.HasGSUBstitutions( mhDC )
-            &&  mrWinFontData.IsGSUBstituted( cChar ) )
-                aGlyphId |= GF_GSUB | GF_ROTL;
-            else
-            {
-                aGlyphId |= GetVerticalFlags( cChar );
-                if( (aGlyphId & GF_ROTMASK) == 0 )
-                    aGlyphId |= GF_VERT;
-            }
-        }
-        aGlyphId |= GF_ISCHAR;
-
-        ++nCount;
-        *(pGlyphIds++) = aGlyphId;
-        if( pGlyphAdvances )
-            *(pGlyphAdvances++) = mpGlyphAdvances[ nStart ];
-        if( pCharIndexes )
-        {
-            int nCharPos;
-            if( !mpGlyphs2Chars )
-                nCharPos = nStart + mnMinCharPos;
-            else
-                nCharPos = mpGlyphs2Chars[nStart];
-            *(pCharIndexes++) = nCharPos;
-        }
-
-        // stop at last glyph
-        if( ++nStart >= mnGlyphCount )
-            break;
-
-        // stop when next x-position is unexpected
-        if( !pGlyphAdvances && mpGlyphOrigAdvs )
-            if( mpGlyphAdvances[nStart-1] != mpGlyphOrigAdvs[nStart-1] )
-                break;
-    }
-
-    return nCount;
-}
-
-bool SimpleWinLayout::DrawTextImpl(HDC hDC,
-                                   const Rectangle* /* pRectToErase */,
-                                   Point* /* pPos */,
-                                   int* /* pGetNextGlypInfo */) const
-{
-    if( mnGlyphCount <= 0 )
-        return false;
-
-    HFONT hOrigFont = DisableFontScaling();
-    Point aPos = GetDrawPosition( Point( mnBaseAdv, 0 ) );
-
-    // #108267#, break up into glyph portions of a limited size required by Win32 API
-    const unsigned int maxGlyphCount = 8192;
-    UINT numGlyphPortions = mnGlyphCount / maxGlyphCount;
-    UINT remainingGlyphs = mnGlyphCount % maxGlyphCount;
-
-    if( numGlyphPortions )
-    {
-        // #108267#,#109387# break up string into smaller chunks
-        // the output positions will be updated by windows (SetTextAlign)
-        POINT oldPos;
-        UINT oldTa = GetTextAlign(hDC);
-        SetTextAlign(hDC, (oldTa & ~TA_NOUPDATECP) | TA_UPDATECP);
-        MoveToEx(hDC, aPos.X(), aPos.Y(), &oldPos);
-        unsigned int i = 0;
-        for( unsigned int n = 0; n < numGlyphPortions; ++n, i+=maxGlyphCount )
-        {
-            ExtTextOutW(hDC, 0, 0, 0, nullptr, mpOutGlyphs+i, maxGlyphCount, mpGlyphAdvances+i);
-        }
-        ExtTextOutW(hDC, 0, 0, 0, nullptr, mpOutGlyphs+i, remainingGlyphs, mpGlyphAdvances+i);
-        MoveToEx(hDC, oldPos.x, oldPos.y, nullptr);
-        SetTextAlign(hDC, oldTa);
-    }
-    else
-        ExtTextOutW(hDC, aPos.X(), aPos.Y(), 0, nullptr, mpOutGlyphs, mnGlyphCount, mpGlyphAdvances);
-
-    if( hOrigFont )
-        DeleteFont(SelectFont(hDC, hOrigFont));
-
-    return false;
-}
-
-DeviceCoordinate SimpleWinLayout::FillDXArray( DeviceCoordinate* pDXArray ) const
-{
-    if( !mnWidth )
-    {
-        mnWidth = mnBaseAdv;
-        for( int i = 0; i < mnGlyphCount; ++i )
-            mnWidth += mpGlyphAdvances[ i ];
-    }
-
-    if( pDXArray != nullptr )
-    {
-        for( int i = 0; i < mnCharCount; ++i )
-             pDXArray[ i ] = mpCharWidths[ i ];
-    }
-
-    return mnWidth;
-}
-
-sal_Int32 SimpleWinLayout::GetTextBreak( DeviceCoordinate nMaxWidth, DeviceCoordinate nCharExtra, int nFactor ) const
-// NOTE: the nFactor is used to prevent rounding errors for small nCharExtra values
-{
-    if( mnWidth )
-        if( (mnWidth * nFactor + mnCharCount * nCharExtra) <= nMaxWidth )
-            return -1;
-
-    long nExtraWidth = mnBaseAdv * nFactor;
-    for( int n = 0; n < mnCharCount; ++n )
-    {
-        // skip unused characters
-        if( mpChars2Glyphs && (mpChars2Glyphs[n] < 0) )
-            continue;
-        // add char widths until max
-        nExtraWidth += mpCharWidths[ n ] * nFactor;
-        if( nExtraWidth > nMaxWidth )
-            return (mnMinCharPos + n);
-        nExtraWidth += nCharExtra;
-    }
-
-    return -1;
-}
-
-void SimpleWinLayout::GetCaretPositions( int nMaxIdx, long* pCaretXArray ) const
-{
-    long nXPos = mnBaseAdv;
-
-    if( !mpGlyphs2Chars )
-    {
-        for( int i = 0; i < nMaxIdx; i += 2 )
-        {
-            pCaretXArray[ i ] = nXPos;
-            nXPos += mpGlyphAdvances[ i>>1 ];
-            pCaretXArray[ i+1 ] = nXPos;
-        }
-    }
-    else
-    {
-        int  i;
-        for( i = 0; i < nMaxIdx; ++i )
-            pCaretXArray[ i ] = -1;
-
-        // assign glyph positions to character positions
-        for( i = 0; i < mnGlyphCount; ++i )
-        {
-            int nCurrIdx = mpGlyphs2Chars[ i ] - mnMinCharPos;
-            long nXRight = nXPos + mpCharWidths[ nCurrIdx ];
-            nCurrIdx *= 2;
-            if( !(mpGlyphRTLFlags && mpGlyphRTLFlags[i]) )
-            {
-                // normal positions for LTR case
-                pCaretXArray[ nCurrIdx ]   = nXPos;
-                pCaretXArray[ nCurrIdx+1 ] = nXRight;
-            }
-            else
-            {
-                // reverse positions for RTL case
-                pCaretXArray[ nCurrIdx ]   = nXRight;
-                pCaretXArray[ nCurrIdx+1 ] = nXPos;
-            }
-            nXPos += mpGlyphAdvances[ i ];
-        }
-    }
-}
-
-void SimpleWinLayout::Justify( DeviceCoordinate nNewWidth )
-{
-    DeviceCoordinate nOldWidth = mnWidth;
-    mnWidth = nNewWidth;
-
-    if( mnGlyphCount <= 0 )
-        return;
-
-    if( nNewWidth == nOldWidth )
-        return;
-
-    // the rightmost glyph cannot be stretched
-    const int nRight = mnGlyphCount - 1;
-    nOldWidth -= mpGlyphAdvances[ nRight ];
-    nNewWidth -= mpGlyphAdvances[ nRight ];
-
-    // count stretchable glyphs
-    int nStretchable = 0, i;
-    for( i = 0; i < nRight; ++i )
-        if( mpGlyphAdvances[i] >= 0 )
-            ++nStretchable;
-
-    // stretch these glyphs
-    DeviceCoordinate nDiffWidth = nNewWidth - nOldWidth;
-    for( i = 0; (i < nRight) && (nStretchable > 0); ++i )
-    {
-        if( mpGlyphAdvances[i] <= 0 )
-            continue;
-        DeviceCoordinate nDeltaWidth = nDiffWidth / nStretchable;
-        mpGlyphAdvances[i] += nDeltaWidth;
-        --nStretchable;
-        nDiffWidth -= nDeltaWidth;
-    }
-}
-
-void SimpleWinLayout::AdjustLayout( ImplLayoutArgs& rArgs )
-{
-    SalLayout::AdjustLayout( rArgs );
-
-    // adjust positions if requested
-    if( rArgs.mpDXArray )
-        ApplyDXArray( rArgs );
-    else if( rArgs.mnLayoutWidth )
-        Justify( rArgs.mnLayoutWidth );
-    else
-        return;
-
-    // recalculate virtual char widths if they were changed
-    if( mpCharWidths != mpGlyphAdvances )
-    {
-        int i;
-        if( !mpGlyphs2Chars )
-        {
-            // standard LTR case
-            for( i = 0; i < mnGlyphCount; ++i )
-                 mpCharWidths[ i ] = mpGlyphAdvances[ i ];
-        }
-        else
-        {
-            // BiDi or complex case
-            for( i = 0; i < mnCharCount; ++i )
-                mpCharWidths[ i ] = 0;
-            for( i = 0; i < mnGlyphCount; ++i )
-            {
-                int j = mpGlyphs2Chars[ i ] - rArgs.mnMinCharPos;
-                if( j >= 0 )
-                    mpCharWidths[ j ] += mpGlyphAdvances[ i ];
-            }
-        }
-    }
-}
-
-void SimpleWinLayout::ApplyDXArray( const ImplLayoutArgs& rArgs )
-{
-    // try to avoid disturbance of text flow for LSB rounding case;
-    const long* pDXArray = rArgs.mpDXArray;
-
-    int i = 0;
-    long nOldWidth = mnBaseAdv;
-    for(; i < mnCharCount; ++i )
-    {
-        int j = !mpChars2Glyphs ? i : mpChars2Glyphs[i];
-        if( j >= 0 )
-        {
-            nOldWidth += mpGlyphAdvances[ j ];
-            long nDiff = nOldWidth - pDXArray[ i ];
-
-            // disabled because of #104768#
-            // works great for static text, but problems when typing
-            // if( nDiff>+1 || nDiff<-1 )
-            // only bother with changing anything when something moved
-            if( nDiff != 0 )
-                break;
-        }
-    }
-    if( i >= mnCharCount )
-        return;
-
-    if( !mpGlyphOrigAdvs )
-    {
-        mpGlyphOrigAdvs = new int[ mnGlyphCount ];
-        for( i = 0; i < mnGlyphCount; ++i )
-            mpGlyphOrigAdvs[ i ] = mpGlyphAdvances[ i ];
-    }
-
-    mnWidth = mnBaseAdv;
-    for( i = 0; i < mnCharCount; ++i )
-    {
-        int j = !mpChars2Glyphs ? i : mpChars2Glyphs[i];
-        if( j >= 0 )
-            mpGlyphAdvances[j] = pDXArray[i] - mnWidth;
-        mnWidth = pDXArray[i];
-    }
-}
-
-void SimpleWinLayout::MoveGlyph( int nStart, long nNewXPos )
-{
-   if( nStart > mnGlyphCount )
-        return;
-
-    // calculate the current x-position of the requested glyph
-    // TODO: cache absolute positions
-    int nXPos = mnBaseAdv;
-    for( int i = 0; i < nStart; ++i )
-        nXPos += mpGlyphAdvances[i];
-
-    // calculate the difference to the current glyph position
-    int nDelta = nNewXPos - nXPos;
-
-    // adjust the width of the layout if it was already cached
-    if( mnWidth )
-        mnWidth += nDelta;
-
-    // depending on whether the requested glyph is leftmost in the layout
-    // adjust either the layout's or the requested glyph's relative position
-    if( nStart > 0 )
-        mpGlyphAdvances[ nStart-1 ] += nDelta;
-    else
-        mnBaseAdv += nDelta;
-}
-
-void SimpleWinLayout::DropGlyph( int nStart )
-{
-    mpOutGlyphs[ nStart ] = DROPPED_OUTGLYPH;
-}
-
-void SimpleWinLayout::Simplify( bool /*bIsBase*/ )
-{
-    // return early if no glyph has been dropped
-    int i = mnGlyphCount;
-    while( (--i >= 0) && (mpOutGlyphs[ i ] != DROPPED_OUTGLYPH) );
-    if( i < 0 )
-        return;
-
-    // convert the layout to a sparse layout if it is not already
-    if( !mpGlyphs2Chars )
-    {
-        mpGlyphs2Chars = new int[ mnGlyphCount ];
-        mpCharWidths = new int[ mnCharCount ];
-        // assertion: mnGlyphCount == mnCharCount
-        for( int k = 0; k < mnGlyphCount; ++k )
-        {
-            mpGlyphs2Chars[ k ] = mnMinCharPos + k;
-            mpCharWidths[ k ] = mpGlyphAdvances[ k ];
-        }
-    }
-
-    // remove dropped glyphs that are rightmost in the layout
-    for( i = mnGlyphCount; --i >= 0; )
-    {
-        if( mpOutGlyphs[ i ] != DROPPED_OUTGLYPH )
-            break;
-        if( mnWidth )
-            mnWidth -= mpGlyphAdvances[ i ];
-        int nRelCharPos = mpGlyphs2Chars[ i ] - mnMinCharPos;
-        if( nRelCharPos >= 0 )
-            mpCharWidths[ nRelCharPos ] = 0;
-    }
-    mnGlyphCount = i + 1;
-
-    // keep original glyph widths around
-    if( !mpGlyphOrigAdvs )
-    {
-        mpGlyphOrigAdvs = new int[ mnGlyphCount ];
-        for( int k = 0; k < mnGlyphCount; ++k )
-            mpGlyphOrigAdvs[ k ] = mpGlyphAdvances[ k ];
-    }
-
-    // remove dropped glyphs inside the layout
-    int nNewGC = 0;
-    for( i = 0; i < mnGlyphCount; ++i )
-    {
-        if( mpOutGlyphs[ i ] == DROPPED_OUTGLYPH )
-        {
-            // adjust relative position to last valid glyph
-            int nDroppedWidth = mpGlyphAdvances[ i ];
-            mpGlyphAdvances[ i ] = 0;
-            if( nNewGC > 0 )
-                mpGlyphAdvances[ nNewGC-1 ] += nDroppedWidth;
-            else
-                mnBaseAdv += nDroppedWidth;
-
-            // zero the virtual char width for the char that has a fallback
-            int nRelCharPos = mpGlyphs2Chars[ i ] - mnMinCharPos;
-            if( nRelCharPos >= 0 )
-                mpCharWidths[ nRelCharPos ] = 0;
-        }
-        else
-        {
-            if( nNewGC != i )
-            {
-                // rearrange the glyph array to get rid of the dropped glyph
-                mpOutGlyphs[ nNewGC ]     = mpOutGlyphs[ i ];
-                mpGlyphAdvances[ nNewGC ] = mpGlyphAdvances[ i ];
-                mpGlyphOrigAdvs[ nNewGC ] = mpGlyphOrigAdvs[ i ];
-                mpGlyphs2Chars[ nNewGC ]  = mpGlyphs2Chars[ i ];
-            }
-            ++nNewGC;
-        }
-    }
-
-    mnGlyphCount = nNewGC;
-    if( mnGlyphCount <= 0 )
-        mnWidth = mnBaseAdv = 0;
-}
-
-WinLayout::WinLayout(HDC hDC, const WinFontFace& rWFD, WinFontInstance& rWFE, bool bUseOpenGL)
-:   mhDC( hDC ),
-    mhFont( static_cast<HFONT>(GetCurrentObject(hDC,OBJ_FONT)) ),
-    mnBaseAdv( 0 ),
-    mfFontScale( 1.0 ),
-    mbUseOpenGL(bUseOpenGL),
-    mrWinFontData( rWFD ),
-    mrWinFontEntry(rWFE)
-{
-    assert(mrWinFontEntry.mnRefCount > 0);
-    // keep mrWinFontEntry alive
-    mrWinFontEntry.mpFontCache->Acquire(&mrWinFontEntry);
-}
-
-WinLayout::~WinLayout()
-{
-    mrWinFontEntry.mpFontCache->Release(&mrWinFontEntry);
-}
-
-void WinLayout::InitFont() const
-{
-    SelectObject( mhDC, mhFont );
-}
-
-// Using reasonably sized fonts to emulate huge fonts works around
-// a lot of problems in printer and display drivers. Huge fonts are
-// mostly used by high resolution reference devices which are never
-// painted to anyway. In the rare case that a huge font needs to be
-// displayed somewhere then the workaround doesn't help anymore.
-// If the drivers fail silently for huge fonts, so be it...
-HFONT WinLayout::DisableFontScaling() const
-{
-    if( mfFontScale == 1.0 )
-        return nullptr;
-
-    LOGFONTW aLogFont;
-    GetObjectW( mhFont, sizeof(LOGFONTW), &aLogFont);
-    aLogFont.lfHeight = (LONG)(mfFontScale * aLogFont.lfHeight);
-    aLogFont.lfWidth  = (LONG)(mfFontScale * aLogFont.lfWidth);
-    HFONT hHugeFont = CreateFontIndirectW( &aLogFont);
-    if( !hHugeFont )
-        return nullptr;
-
-    return SelectFont( mhDC, hHugeFont );
-}
-
-SCRIPT_CACHE& WinLayout::GetScriptCache() const
-{
-    return mrWinFontEntry.GetScriptCache();
-}
-
-void WinLayout::DrawText(SalGraphics& rGraphics) const
-{
-    WinSalGraphics& rWinGraphics = static_cast<WinSalGraphics&>(rGraphics);
-    HDC hDC = rWinGraphics.getHDC();
-
-    if (!mbUseOpenGL)
-    {
-        // no OpenGL, just classic rendering
-        Point aPos(0, 0);
-        int nGetNextGlypInfo(0);
-        bool bContinue = DrawTextImpl(hDC, nullptr, &aPos, &nGetNextGlypInfo);
-        assert(!bContinue);
-    }
-    else if (CacheGlyphs(rGraphics) &&
-             DrawCachedGlyphs(rGraphics))
-    {
-        // Nothing
-    }
-    else
-    {
-        // We have to render the text to a hidden texture, and draw it.
-        //
-        // Note that Windows GDI does not really support the alpha correctly
-        // when drawing - ie. it draws nothing to the alpha channel when
-        // rendering the text, even the antialiasing is done as 'real' pixels,
-        // not alpha...
-        //
-        // Luckily, this does not really limit us:
-        //
-        // To blend properly, we draw the texture, but then use it as an alpha
-        // channel for solid color (that will define the text color).  This
-        // destroys the subpixel antialiasing - turns it into 'classic'
-        // antialiasing - but that is the best we can do, because the subpixel
-        // antialiasing needs to know what is in the background: When the
-        // background is white, or white-ish, it does the subpixel, but when
-        // there is a color, it just darkens the color (and does this even
-        // when part of the character is on a colored background, and part on
-        // white).  It has to work this way, the results would look strange
-        // otherwise.
-        //
-        // For the GL rendering to work even with the subpixel antialiasing,
-        // we would need to get the current texture from the screen, let GDI
-        // draw the text to it (so that it can decide well where to use the
-        // subpixel and where not), and draw the result - but in that case we
-        // don't need alpha anyway.
-        //
-        // TODO: check the performance of this 2nd approach at some stage and
-        // switch to that if it performs well.
-
-        Rectangle aRect;
-        GetBoundRect(rGraphics, aRect);
-
-        WinOpenGLSalGraphicsImpl *pImpl = dynamic_cast<WinOpenGLSalGraphicsImpl*>(rWinGraphics.mpImpl.get());
-
-        if (pImpl)
-        {
-            pImpl->PreDraw();
-
-            Point aPos(0, 0);
-            int nGetNextGlypInfo(0);
-            while (true)
-            {
-                OpenGLCompatibleDC aDC(rGraphics, aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight());
-
-                // we are making changes to the DC, make sure we got a new one
-                assert(aDC.getCompatibleHDC() != hDC);
-
-                RECT aWinRect = { aRect.Left(), aRect.Top(), aRect.Left() + aRect.GetWidth(), aRect.Top() + aRect.GetHeight() };
-                FillRect(aDC.getCompatibleHDC(), &aWinRect, static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)));
-
-                // setup the hidden DC with black color and white background, we will
-                // use the result of the text drawing later as a mask only
-                HFONT hOrigFont = SelectFont(aDC.getCompatibleHDC(), mhFont);
-
-                SetTextColor(aDC.getCompatibleHDC(), RGB(0, 0, 0));
-                SetBkColor(aDC.getCompatibleHDC(), RGB(255, 255, 255));
-
-                UINT nTextAlign = GetTextAlign(hDC);
-                SetTextAlign(aDC.getCompatibleHDC(), nTextAlign);
-
-                COLORREF color = GetTextColor(hDC);
-                SalColor salColor = MAKE_SALCOLOR(GetRValue(color), GetGValue(color), GetBValue(color));
-
-                // the actual drawing
-                bool bContinue = DrawTextImpl(aDC.getCompatibleHDC(), &aRect, &aPos, &nGetNextGlypInfo);
-
-                std::unique_ptr<OpenGLTexture> xTexture(aDC.getTexture());
-                if (xTexture)
-                    pImpl->DrawMask(*xTexture, salColor, aDC.getTwoRect());
-
-                SelectFont(aDC.getCompatibleHDC(), hOrigFont);
-
-                if (!bContinue)
-                    break;
-            }
-            pImpl->PostDraw();
-        }
-
-    }
-}
-
-bool SimpleWinLayout::CacheGlyphs(SalGraphics& rGraphics) const
-{
-    static bool bDoGlyphCaching = (std::getenv("SAL_DISABLE_GLYPH_CACHING") == nullptr);
-
-    if (!bDoGlyphCaching)
-        return false;
-
-    for (int i = 0; i < mnGlyphCount; i++)
-    {
-        int nCodePoint;
-        if (i < mnGlyphCount-1 && rtl::isHighSurrogate(mpOutGlyphs[i]) && rtl::isLowSurrogate(mpOutGlyphs[i+1]))
-        {
-#if 1 // Don't remove the #else branch in case somebody wants to
-      // continue trying to figure out why sequential non-BMP glyphs
-      // get scribbled on top of each others if caching is used.
-            return false;
-#else
-            nCodePoint = rtl::combineSurrogates(mpOutGlyphs[i], mpOutGlyphs[i+1]);
-            i++;
-#endif
-        }
-        else
-        {
-            nCodePoint = mpOutGlyphs[i];
-        }
-
-        if (!mrWinFontEntry.GetGlyphCache().IsGlyphCached(nCodePoint))
-        {
-            if (!mrWinFontEntry.CacheGlyphToAtlas(false, nCodePoint, *this, rGraphics))
-                return false;
-        }
-    }
-
-    return true;
-}
-
-bool SimpleWinLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const
-{
-    WinSalGraphics& rWinGraphics = static_cast<WinSalGraphics&>(rGraphics);
-    HDC hDC = rWinGraphics.getHDC();
-
-    Rectangle aRect;
-    GetBoundRect(rGraphics, aRect);
-
-    COLORREF color = GetTextColor(hDC);
-    SalColor salColor = MAKE_SALCOLOR(GetRValue(color), GetGValue(color), GetBValue(color));
-
-    WinOpenGLSalGraphicsImpl *pImpl = dynamic_cast<WinOpenGLSalGraphicsImpl*>(rWinGraphics.mpImpl.get());
-    if (!pImpl)
-        return false;
-
-    HFONT hOrigFont = DisableFontScaling();
-    Point aPos = GetDrawPosition( Point( mnBaseAdv, 0 ) );
-
-    int nAdvance = 0;
-
-    for (int i = 0; i < mnGlyphCount; i++)
-    {
-        if (mpOutGlyphs[i] == DROPPED_OUTGLYPH)
-            continue;
-
-        int nCodePoint;
-        if (i < mnGlyphCount-1 && rtl::isHighSurrogate(mpOutGlyphs[i]) && rtl::isLowSurrogate(mpOutGlyphs[i+1]))
-        {
-            nCodePoint = rtl::combineSurrogates(mpOutGlyphs[i], mpOutGlyphs[i+1]);
-            i++;
-        }
-        else
-        {
-            nCodePoint = mpOutGlyphs[i];
-        }
-
-        OpenGLGlyphDrawElement& rElement(mrWinFontEntry.GetGlyphCache().GetDrawElement(nCodePoint));
-        OpenGLTexture& rTexture = rElement.maTexture;
-
-        if (!rTexture)
-            return false;
-
-        SalTwoRect a2Rects(0, 0,
-                           rTexture.GetWidth(), rTexture.GetHeight(),
-                           nAdvance + aPos.X() - rElement.getExtraOffset() + rElement.maLeftOverhangs,
-                           aPos.Y() - rElement.mnBaselineOffset - rElement.getExtraOffset(),
-                           rTexture.GetWidth(), rTexture.GetHeight());
-
-        pImpl->DeferredTextDraw(rTexture, salColor, a2Rects);
-
-        nAdvance += mpGlyphAdvances[i];
-    }
-
-    if( hOrigFont )
-        DeleteFont(SelectFont(hDC, hOrigFont));
-
-    return true;
-}
-
-struct VisualItem
-{
-public:
-    SCRIPT_ITEM*    mpScriptItem;
-    int             mnMinGlyphPos;
-    int             mnEndGlyphPos;
-    int             mnMinCharPos;
-    int             mnEndCharPos;
-    int             mnXOffset;
-    ABC             maABCWidths;
-    bool            mbHasKashidas;
-
-public:
-    bool            IsEmpty() const { return (mnEndGlyphPos <= 0); }
-    bool            IsRTL() const { return mpScriptItem->a.fRTL; }
-    bool            HasKashidas() const { return mbHasKashidas; }
-};
-
-static bool bUspInited = false;
-
-static bool bManualCellAlign = true;
-
-static void InitUSP()
-{
-#if _WIN32_WINNT < _WIN32_WINNT_VISTA
-    // get the usp10.dll version info
-    HMODULE usp10 = GetModuleHandle("usp10.dll");
-    void *pScriptIsComplex = reinterpret_cast< void* >( GetProcAddress(usp10, "ScriptIsComplex"));
-    int nUspVersion = 0;
-    rtl_uString* pModuleURL = NULL;
-    osl_getModuleURLFromAddress( pScriptIsComplex, &pModuleURL );
-    rtl_uString* pModuleFileName = NULL;
-    if( pModuleURL )
-        osl_getSystemPathFromFileURL( pModuleURL, &pModuleFileName );
-    const sal_Unicode* pModuleFileCStr = NULL;
-    if( pModuleFileName )
-        pModuleFileCStr = rtl_uString_getStr( pModuleFileName );
-    if( pModuleFileCStr )
-    {
-        DWORD nHandle;
-        DWORD nBufSize = GetFileVersionInfoSizeW( const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(pModuleFileCStr)), &nHandle );
-        char* pBuffer = (char*)alloca( nBufSize );
-        BOOL bRC = GetFileVersionInfoW( const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(pModuleFileCStr)), nHandle, nBufSize, pBuffer );
-        VS_FIXEDFILEINFO* pFixedFileInfo = NULL;
-        UINT nFixedFileSize = 0;
-        if( bRC )
-            VerQueryValueW( pBuffer, const_cast<LPWSTR>(L"\\"), (void**)&pFixedFileInfo, &nFixedFileSize );
-        if( pFixedFileInfo && pFixedFileInfo->dwSignature == 0xFEEF04BD )
-            nUspVersion = HIWORD(pFixedFileInfo->dwProductVersionMS) * 10000
-                        + LOWORD(pFixedFileInfo->dwProductVersionMS);
-    }
-
-    // #i77976# USP>=1.0600 changed the need to manually align glyphs in their cells
-    if( nUspVersion >= 10600 )
-#endif
-    {
-        bManualCellAlign = false;
-    }
-
-    bUspInited = true;
-}
-
-UniscribeLayout::UniscribeLayout(HDC hDC, const WinFontFace& rWinFontData,
-        WinFontInstance& rWinFontEntry, bool bUseOpenGL)
-:   WinLayout(hDC, rWinFontData, rWinFontEntry, bUseOpenGL),
-    mpScriptItems( nullptr ),
-    mpVisualItems( nullptr ),
-    mnItemCount( 0 ),
-    mnCharCapacity( 0 ),
-    mpLogClusters( nullptr ),
-    mpCharWidths( nullptr ),
-    mnSubStringMin( 0 ),
-    mnGlyphCount( 0 ),
-    mnGlyphCapacity( 0 ),
-    mpGlyphAdvances( nullptr ),
-    mpJustifications( nullptr ),
-    mpOutGlyphs( nullptr ),
-    mpGlyphOffsets( nullptr ),
-    mpVisualAttrs( nullptr ),
-    mpGlyphs2Chars( nullptr ),
-    mnMinKashidaWidth( 0 ),
-    mnMinKashidaGlyph( 0 ),
-    mbDisableGlyphInjection( false )
-{
-}
-
-UniscribeLayout::~UniscribeLayout()
-{
-    delete[] mpScriptItems;
-    delete[] mpVisualItems;
-    delete[] mpLogClusters;
-    delete[] mpCharWidths;
-    delete[] mpOutGlyphs;
-    delete[] mpGlyphAdvances;
-    delete[] mpJustifications;
-    delete[] mpGlyphOffsets;
-    delete[] mpVisualAttrs;
-    delete[] mpGlyphs2Chars;
-}
-
-#if 0 // Don't remove -- useful for temporary SAL_ DEBUG when hacking on this
-
-namespace {
-
-template<typename IntegerType>
-OUString IntegerArrayToString(IntegerType *pWords, int n)
-{
-    OUString result = "{";
-    for (int i = 0; i < n; ++i)
-    {
-        if (i > 0)
-            result += ",";
-        if (i > 0 && i % 10 == 0)
-            result += OUString::number(i) + ":";
-        result += OUString::number(pWords[i]);
-    }
-    result += "}";
-
-    return result;
-}
-
-OUString GoffsetArrayToString(GOFFSET *pGoffsets, int n)
-{
-    OUString result = "{";
-    for (int i = 0; i < n; ++i)
-    {
-        if (i > 0)
-            result += ",";
-        if (i > 0 && i % 10 == 0)
-            result += OUString::number(i) + ":";
-        result += "(" + OUString::number(pGoffsets[i].du) + "," + OUString::number(pGoffsets[i].dv) + ")";
-    }
-    result += "}";
-
-    return result;
-}
-
-OUString VisAttrArrayToString(SCRIPT_VISATTR *pVisAttrs, int n)
-{
-    static const OUString JUSTIFICATION_NAME[] = {
-        "NONE",
-        "ARABIC_BLANK",
-        "CHARACTER",
-        "RESERVED1",
-        "BLANK",
-        "RESERVED2",
-        "RESERVED3",
-        "ARABIC_NORMAL",
-        "ARABIC_KASHIDA",
-        "ARABIC_ALEF",
-        "ARABIC_HA",
-        "ARABIC_RA",
-        "ARABIC_BA",
-        "ARABIC_BARA",
-        "ARABIC_SEEN",
-        "ARABIC_SEEN_M"
-    };
-
-    OUString result = "{";
-    for (int i = 0; i < n; ++i)
-    {
-        if (i > 0)
-            result += ",";
-        if (i > 0 && i % 10 == 0)
-            result += OUString::number(i) + ":";
-        result += OUString("{") + JUSTIFICATION_NAME[pVisAttrs[i].uJustification] + (pVisAttrs[i].fClusterStart ? OUString(",ClusterStart") : OUString()) + (pVisAttrs[i].fDiacritic ? OUString(",Diacritic") : OUString()) + OUString(pVisAttrs[i].fZeroWidth ? OUString(",ZeroWidth") : OUString()) + OUString("}");
-    }
-    result += "}";
-
-    return result;
-}
-
-} // anonymous namespace
-
-#endif // 0
-
-bool UniscribeLayout::LayoutText( ImplLayoutArgs& rArgs )
-{
-    msTheString = rArgs.mrStr;
-
-    // for a base layout only the context glyphs have to be dropped
-    // => when the whole string is involved there is no extra context
-    std::vector<int> aDropChars;
-    if( rArgs.mnFlags & SalLayoutFlags::ForFallback )
-    {
-        // calculate superfluous context char positions
-        aDropChars.push_back(0);
-        aDropChars.push_back(rArgs.mrStr.getLength());
-        int nMin, nEnd;
-        bool bRTL;
-        for( rArgs.ResetPos(); rArgs.GetNextRun( &nMin, &nEnd, &bRTL ); )
-        {
-            aDropChars.push_back( nMin );
-            aDropChars.push_back( nEnd );
-        }
-        // prepare aDropChars for binary search which will allow to
-        // not bother with visual items that will be dropped anyway
-        std::sort( aDropChars.begin(), aDropChars.end() );
-    }
-
-    // prepare layout
-    // TODO: fix case when recycling old UniscribeLayout object
-    mnMinCharPos = rArgs.mnMinCharPos;
-    mnEndCharPos = rArgs.mnEndCharPos;
-
-    // determine script items from string
-
-    // prepare itemization
-    // TODO: try to avoid itemization since it costs a lot of performance
-    SCRIPT_STATE aScriptState = {0,WORD(false),WORD(false),WORD(false),WORD(false),WORD(false),WORD(false),WORD(false),WORD(false),0,0};
-    aScriptState.uBidiLevel         = WORD(bool(rArgs.mnFlags & SalLayoutFlags::BiDiRtl));
-    aScriptState.fOverrideDirection = WORD(bool(rArgs.mnFlags & SalLayoutFlags::BiDiStrong));
-    aScriptState.fDigitSubstitute   = WORD(bool(rArgs.mnFlags & SalLayoutFlags::SubstituteDigits));
-    aScriptState.fArabicNumContext  = aScriptState.fDigitSubstitute & aScriptState.uBidiLevel;
-    DWORD nLangId = 0;  // TODO: get language from font
-    SCRIPT_CONTROL aScriptControl;
-    memset(&aScriptControl, 0, sizeof(aScriptControl));
-    aScriptControl.uDefaultLanguage = nLangId;
-    aScriptControl.fNeutralOverride = aScriptState.fOverrideDirection;
-    aScriptControl.fContextDigits   = DWORD(bool(rArgs.mnFlags & SalLayoutFlags::SubstituteDigits));
-    aScriptControl.fMergeNeutralItems = DWORD(true);
-
-    // determine relevant substring and work only on it
-    // when Bidi status is unknown we need to look at the whole string though
-    mnSubStringMin = 0;
-    const int nLength = rArgs.mrStr.getLength();
-    const sal_Unicode *pStr = rArgs.mrStr.getStr();
-    int nSubStringEnd = nLength;
-    if( aScriptState.fOverrideDirection )
-    {
-        // TODO: limit substring to portion limits
-        mnSubStringMin = rArgs.mnMinCharPos - 8;
-        if( mnSubStringMin < 0 )
-            mnSubStringMin = 0;
-        nSubStringEnd = rArgs.mnEndCharPos + 8;
-        if( nSubStringEnd > nLength )
-            nSubStringEnd = nLength;
-
-    }
-    // now itemize the substring with its context
-    for( int nItemCapacity = 16;; nItemCapacity *= 8 )
-    {
-        mpScriptItems = new SCRIPT_ITEM[ nItemCapacity ];
-        HRESULT nRC = ScriptItemize(
-            reinterpret_cast<LPCWSTR>(pStr + mnSubStringMin), nSubStringEnd - mnSubStringMin,
-            nItemCapacity - 1, &aScriptControl, &aScriptState,
-            mpScriptItems, &mnItemCount );
-        if( !nRC )  // break loop when everything is correctly itemized
-            break;
-
-        // prepare bigger buffers for another itemization round
-        delete[] mpScriptItems;
-        mpScriptItems = nullptr;
-        if( nRC != E_OUTOFMEMORY )
-            return false;
-        if( nItemCapacity > (nSubStringEnd - mnSubStringMin) + 16 )
-            return false;
-    }
-
-    // calculate the order of visual items
-    int nItem, i;
-
-    // adjust char positions by substring offset
-    for( nItem = 0; nItem <= mnItemCount; ++nItem )
-        mpScriptItems[ nItem ].iCharPos += mnSubStringMin;
-    // default visual item ordering
-    mpVisualItems = new VisualItem[ mnItemCount ];
-    for( nItem = 0; nItem < mnItemCount; ++nItem )
-    {
-        // initialize char specific item info
-        VisualItem& rVisualItem = mpVisualItems[ nItem ];
-        SCRIPT_ITEM* pScriptItem = &mpScriptItems[ nItem ];
-        rVisualItem.mpScriptItem = pScriptItem;
-        rVisualItem.mnMinCharPos = pScriptItem[0].iCharPos;
-        rVisualItem.mnEndCharPos = pScriptItem[1].iCharPos;
-    }
-
-    // reorder visual item order if needed
-    if( rArgs.mnFlags & SalLayoutFlags::BiDiStrong )
-    {
-        // force RTL item ordering if requested
-        if( rArgs.mnFlags & SalLayoutFlags::BiDiRtl )
-        {
-            VisualItem* pVI0 = &mpVisualItems[ 0 ];
-            VisualItem* pVI1 = &mpVisualItems[ mnItemCount ];
-            while( pVI0 < --pVI1 )
-            {
-                VisualItem aVtmp = *pVI0;
-                *(pVI0++) = *pVI1;
-                *pVI1 = aVtmp;
-            }
-        }
-    }
-    else if( mnItemCount > 1 )
-    {
-        // apply bidi algorithm's rule L2 on item level
-        // TODO: use faster L2 algorithm
-        int nMaxBidiLevel = 0;
-        VisualItem* pVI = &mpVisualItems[0];
-        VisualItem* const pVIend = pVI + mnItemCount;
-        for(; pVI < pVIend; ++pVI )
-            if( nMaxBidiLevel < pVI->mpScriptItem->a.s.uBidiLevel )
-                nMaxBidiLevel = pVI->mpScriptItem->a.s.uBidiLevel;
-
-        while( --nMaxBidiLevel >= 0 )
-        {
-            for( pVI = &mpVisualItems[0]; pVI < pVIend; )
-            {
-                // find item range that needs reordering
-                for(; pVI < pVIend; ++pVI )
-                    if( nMaxBidiLevel < pVI->mpScriptItem->a.s.uBidiLevel )
-                        break;
-                VisualItem* pVImin = pVI++;
-                for(; pVI < pVIend; ++pVI )
-                    if( nMaxBidiLevel >= pVI->mpScriptItem->a.s.uBidiLevel )
-                        break;
-                VisualItem* pVImax = pVI++;
-
-                // reverse order of items in this range
-                while( pVImin < --pVImax )
-                {
-                    VisualItem aVtmp = *pVImin;
-                    *(pVImin++) = *pVImax;
-                    *pVImax = aVtmp;
-                }
-            }
-        }
-    }
-
-    // allocate arrays
-    // TODO: when reusing object reuse old allocations or delete them
-    // TODO: use only [nSubStringMin..nSubStringEnd) instead of [0..nSubStringEnd)
-    mnCharCapacity  = nSubStringEnd;
-    mpLogClusters   = new WORD[ mnCharCapacity ];
-    mpCharWidths    = new int[ mnCharCapacity ];
-
-    mnGlyphCount    = 0;
-    mnGlyphCapacity = 16 + 4 * (nSubStringEnd - mnSubStringMin); // worst case assumption
-    mpGlyphAdvances = new int[ mnGlyphCapacity ];
-    mpOutGlyphs     = new WORD[ mnGlyphCapacity ];
-    mpGlyphOffsets  = new GOFFSET[ mnGlyphCapacity ];
-    mpVisualAttrs   = new SCRIPT_VISATTR[ mnGlyphCapacity ];
-
-    long nXOffset = 0;
-    for( int j = mnSubStringMin; j < nSubStringEnd; ++j )
-        mpCharWidths[j] = 0;
-
-    // layout script items
-    SCRIPT_CACHE& rScriptCache = GetScriptCache();
-    for( nItem = 0; nItem < mnItemCount; ++nItem )
-    {
-        VisualItem& rVisualItem = mpVisualItems[ nItem ];
-
-        // initialize glyph specific item info
-        rVisualItem.mnMinGlyphPos = mnGlyphCount;
-        rVisualItem.mnEndGlyphPos = 0;
-        rVisualItem.mnXOffset     = nXOffset;
-
-        // shortcut ignorable items
-        if( (rArgs.mnEndCharPos <= rVisualItem.mnMinCharPos)
-         || (rArgs.mnMinCharPos >= rVisualItem.mnEndCharPos) )
-        {
-            for( int j = rVisualItem.mnMinCharPos; j < rVisualItem.mnEndCharPos; ++j )
-                mpLogClusters[j] = sal::static_int_cast<WORD>(~0U);
-            if (rArgs.mnMinCharPos >= rVisualItem.mnEndCharPos)
-            {   // fdo#47553 adjust "guessed" min (maybe up to -8 off) to
-                // actual min so it can be used properly in GetNextGlyphs
-                if (mnSubStringMin < rVisualItem.mnEndCharPos)
-                    mnSubStringMin = rVisualItem.mnEndCharPos;
-            }
-            continue;
-        }
-
-        // override bidi analysis if requested
-        if( rArgs.mnFlags & SalLayoutFlags::BiDiStrong )
-        {
-            // FIXME: is this intended ?
-            rVisualItem.mpScriptItem->a.fRTL                 = (aScriptState.uBidiLevel & 1);
-            rVisualItem.mpScriptItem->a.s.uBidiLevel         = aScriptState.uBidiLevel;
-            rVisualItem.mpScriptItem->a.s.fOverrideDirection = aScriptState.fOverrideDirection;
-        }
-
-        // convert the unicodes to glyphs
-        int nGlyphCount = 0;
-        int nCharCount = rVisualItem.mnEndCharPos - rVisualItem.mnMinCharPos;
-        HRESULT nRC = ScriptShape( mhDC, &rScriptCache,
-            reinterpret_cast<LPCWSTR>(pStr + rVisualItem.mnMinCharPos),
-            nCharCount,
-            mnGlyphCapacity - rVisualItem.mnMinGlyphPos, // problem when >0xFFFF
-            &rVisualItem.mpScriptItem->a,
-            mpOutGlyphs + rVisualItem.mnMinGlyphPos,
-            mpLogClusters + rVisualItem.mnMinCharPos,
-            mpVisualAttrs + rVisualItem.mnMinGlyphPos,
-            &nGlyphCount );
-
-        // find and handle problems in the unicode to glyph conversion
-        if( nRC == USP_E_SCRIPT_NOT_IN_FONT )
-        {
-            // the whole visual item needs a fallback, but make sure that the next
-            // fallback request is limited to the characters in the original request
-            // => this is handled in ImplLayoutArgs::PrepareFallback()
-            rArgs.NeedFallback( rVisualItem.mnMinCharPos, rVisualItem.mnEndCharPos,
-                rVisualItem.IsRTL() );
-
-            // don't bother to do a default layout in a fallback level
-            if( rArgs.mnFlags & SalLayoutFlags::ForFallback )
-                continue;
-
-            // the primitive layout engine is good enough for the default layout
-            rVisualItem.mpScriptItem->a.eScript = SCRIPT_UNDEFINED;
-            nRC = ScriptShape( mhDC, &rScriptCache,
-                reinterpret_cast<LPCWSTR>(pStr + rVisualItem.mnMinCharPos),
-                nCharCount,
-                mnGlyphCapacity - rVisualItem.mnMinGlyphPos,
-                &rVisualItem.mpScriptItem->a,
-                mpOutGlyphs + rVisualItem.mnMinGlyphPos,
-                mpLogClusters + rVisualItem.mnMinCharPos,
-                mpVisualAttrs + rVisualItem.mnMinGlyphPos,
-                &nGlyphCount );
-
-            if( nRC != 0 )
-                continue;
-
-        }
-        else if( nRC != 0 )
-            // something undefined happened => give up for this visual item
-            continue;
-        else // if( nRC == 0 )
-        {
-            // check if there are any NotDef glyphs
-            for( i = 0; i < nGlyphCount; ++i )
-                if( 0 == mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] )
-                    break;
-            if( i < nGlyphCount )
-            {
-                // clip charpos limits to the layout string without context
-                int nMinCharPos = rVisualItem.mnMinCharPos;
-                if( nMinCharPos < rArgs.mnMinCharPos )
-                    nMinCharPos = rArgs.mnMinCharPos;
-                int nEndCharPos = rVisualItem.mnEndCharPos;
-                if( nEndCharPos > rArgs.mnEndCharPos )
-                    nEndCharPos = rArgs.mnEndCharPos;
-                // request fallback for individual NotDef glyphs
-                do
-                {
-                    // ignore non-NotDef glyphs
-                    if( 0 != mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] )
-                        continue;
-                    mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = DROPPED_OUTGLYPH;
-                    // request fallback for the whole cell that resulted in a NotDef glyph
-                    // TODO: optimize algorithm
-                    const bool bRTL = rVisualItem.IsRTL();
-                    if( !bRTL )
-                    {
-                        // request fallback for the left-to-right cell
-                        for( int c = nMinCharPos; c < nEndCharPos; ++c )
-                        {
-                            if( mpLogClusters[ c ] == i )
-                            {
-                                // #i55716# skip WORDJOINER
-                                if( pStr[ c ] == 0x2060 )
-                                    mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = 1;
-                                else
-                                    rArgs.NeedFallback( c, false );
-                           }
-                        }
-                    }
-                    else
-                    {
-                        // request fallback for the right to left cell
-                        for( int c = nEndCharPos; --c >= nMinCharPos; )
-                        {
-                            if( mpLogClusters[ c ] == i )
-                            {
-                                // #i55716# skip WORDJOINER
-                                if( pStr[ c ] == 0x2060 )
-                                    mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = 1;
-                                else
-                                    rArgs.NeedFallback( c, true );
-                            }
-                        }
-                    }
-                } while( ++i < nGlyphCount );
-            }
-        }
-
-        // now place the glyphs
-        nRC = ScriptPlace( mhDC, &rScriptCache,
-            mpOutGlyphs + rVisualItem.mnMinGlyphPos,
-            nGlyphCount,
-            mpVisualAttrs + rVisualItem.mnMinGlyphPos,
-            &rVisualItem.mpScriptItem->a,
-            mpGlyphAdvances + rVisualItem.mnMinGlyphPos,
-            mpGlyphOffsets + rVisualItem.mnMinGlyphPos,
-            &rVisualItem.maABCWidths );
-
-        if( nRC != 0 )
-            continue;
-
-        // calculate the logical char widths from the glyph layout
-        nRC = ScriptGetLogicalWidths(
-            &rVisualItem.mpScriptItem->a,
-            nCharCount, nGlyphCount,
-            mpGlyphAdvances + rVisualItem.mnMinGlyphPos,
-            mpLogClusters + rVisualItem.mnMinCharPos,
-            mpVisualAttrs + rVisualItem.mnMinGlyphPos,
-            mpCharWidths + rVisualItem.mnMinCharPos );
-
-        // update the glyph counters
-        mnGlyphCount += nGlyphCount;
-        rVisualItem.mnEndGlyphPos = mnGlyphCount;
-
-        // update nXOffset
-        int nEndGlyphPos;
-        if( GetItemSubrange( rVisualItem, i, nEndGlyphPos ) )
-            for(; i < nEndGlyphPos; ++i )
-                nXOffset += mpGlyphAdvances[ i ];
-
-        // TODO: shrink glyphpos limits to match charpos/fallback limits
-        //pVI->mnMinGlyphPos = nMinGlyphPos;
-        //pVI->mnEndGlyphPos = nEndGlyphPos;
-
-        // drop the superfluous context glyphs
-        auto it = aDropChars.cbegin();
-        while( it != aDropChars.cend() )
-        {
-            // find matching "drop range"
-            int nMinDropPos = *(it++); // begin of drop range
-            if( nMinDropPos >= rVisualItem.mnEndCharPos )
-                break;
-            int nEndDropPos = *(it++); // end of drop range
-            if( nEndDropPos <= rVisualItem.mnMinCharPos )
-                continue;
-            // clip "drop range" to visual item's char range
-            if( nMinDropPos <= rVisualItem.mnMinCharPos )
-            {
-                nMinDropPos = rVisualItem.mnMinCharPos;
-                // drop the whole visual item if possible
-                if( nEndDropPos >= rVisualItem.mnEndCharPos )
-                {
-                    rVisualItem.mnEndGlyphPos = 0;
-                    break;
-                }
-            }
-            if( nEndDropPos > rVisualItem.mnEndCharPos )
-                nEndDropPos = rVisualItem.mnEndCharPos;
-
-            // drop the glyphs which correspond to the charpos range
-            // drop the corresponding glyphs in the cluster
-            for( int c = nMinDropPos; c < nEndDropPos; ++c )
-            {
-                int nGlyphPos = mpLogClusters[c] + rVisualItem.mnMinGlyphPos;
-                // no need to bother when the cluster was already dropped
-                if( mpOutGlyphs[ nGlyphPos ] != DROPPED_OUTGLYPH )
-                {
-                    for(;;)
-                    {
-                        mpOutGlyphs[ nGlyphPos ] = DROPPED_OUTGLYPH;
-                        // until the end of visual item
-                        if( ++nGlyphPos >= rVisualItem.mnEndGlyphPos )
-                            break;
-                        // until the next cluster start
-                        if( mpVisualAttrs[ nGlyphPos ].fClusterStart )
-                            break;
-                    }
-                }
-            }
-        }
-    }
-
-    // scale layout metrics if needed
-    // TODO: does it make the code more simple if the metric scaling
-    // is moved to the methods that need metric scaling (e.g. FillDXArray())?
-    if( mfFontScale != 1.0 )
-    {
-        mnBaseAdv = (int)((double)mnBaseAdv*mfFontScale);
-
-        for( i = 0; i < mnItemCount; ++i )
-            mpVisualItems[i].mnXOffset = (int)((double)mpVisualItems[i].mnXOffset*mfFontScale);
-
-        mnBaseAdv = (int)((double)mnBaseAdv*mfFontScale);
-        for( i = 0; i < mnGlyphCount; ++i )
-        {
-            mpGlyphAdvances[i]   = (int)(mpGlyphAdvances[i] * mfFontScale);
-            mpGlyphOffsets[i].du = (LONG)(mpGlyphOffsets[i].du * mfFontScale);
-            mpGlyphOffsets[i].dv = (LONG)(mpGlyphOffsets[i].dv * mfFontScale);
-            // mpJustifications are still NULL
-        }
-
-        for( i = mnSubStringMin; i < nSubStringEnd; ++i )
-            mpCharWidths[i] = (int)(mpCharWidths[i] * mfFontScale);
-    }
-
-    return true;
-}
-
-// calculate the range of relevant glyphs for this visual item
-bool UniscribeLayout::GetItemSubrange( const VisualItem& rVisualItem,
-    int& rMinGlyphPos, int& rEndGlyphPos ) const
-{
-    // return early when nothing of interest in this item
-    if( rVisualItem.IsEmpty()
-     || (rVisualItem.mnEndCharPos <= mnMinCharPos)
-     || (mnEndCharPos <= rVisualItem.mnMinCharPos) )
-        return false;
-
-    // default: subrange is complete range
-    rMinGlyphPos = rVisualItem.mnMinGlyphPos;
-    rEndGlyphPos = rVisualItem.mnEndGlyphPos;
-
-    // return early when the whole item is of interest
-    if( (mnMinCharPos <= rVisualItem.mnMinCharPos)
-     && (rVisualItem.mnEndCharPos <= mnEndCharPos ) )
-        return true;
-
-    // get glyph range from char range by looking at cluster boundries
-    // TODO: optimize for case that LTR/RTL correspond to monotonous glyph indexes
-    rMinGlyphPos = rVisualItem.mnEndGlyphPos;
-    int nMaxGlyphPos = 0;
-
-    int i = mnMinCharPos;
-    if( i < rVisualItem.mnMinCharPos )
-        i = rVisualItem.mnMinCharPos;
-    int nCharPosLimit = rVisualItem.mnEndCharPos;
-    if( nCharPosLimit > mnEndCharPos )
-        nCharPosLimit = mnEndCharPos;
-    for(; i < nCharPosLimit; ++i )
-    {
-        int n = mpLogClusters[ i ] + rVisualItem.mnMinGlyphPos;
-        if( rMinGlyphPos > n )
-            rMinGlyphPos = n;
-        if( nMaxGlyphPos < n )
-            nMaxGlyphPos = n;
-    }
-    if (nMaxGlyphPos > rVisualItem.mnEndGlyphPos)
-        nMaxGlyphPos = rVisualItem.mnEndGlyphPos - 1;
-
-    // extend the glyph range to account for all glyphs in referenced clusters
-    if( !rVisualItem.IsRTL() ) // LTR-item
-    {
-        // extend to rightmost glyph of rightmost referenced cluster
-        for( i = nMaxGlyphPos; ++i < rVisualItem.mnEndGlyphPos; nMaxGlyphPos = i )
-            if( mpVisualAttrs[i].fClusterStart )
-                break;
-    }
-    else // RTL-item
-    {
-        // extend to leftmost glyph of leftmost referenced cluster
-        for( i = rMinGlyphPos; --i >= rVisualItem.mnMinGlyphPos; rMinGlyphPos = i )
-            if( mpVisualAttrs[i].fClusterStart )
-                break;
-    }
-    rEndGlyphPos = nMaxGlyphPos + 1;
-
-    return true;
-}
-
-int UniscribeLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos,
-                                    int& nStartx8, DeviceCoordinate* pGlyphAdvances, int* pCharPosAry,
-                                    const PhysicalFontFace** /*pFallbackFonts*/ ) const
-{
-    // HACK to allow fake-glyph insertion (e.g. for kashidas)
-    // TODO: use iterator idiom instead of GetNextGlyphs(...)
-    // TODO: else make sure that the limit for glyph injection is sufficient (currently 256)
-    int nSubIter = nStartx8 & 0xff;
-    int nStart = nStartx8 >> 8;
-
-    // check the glyph iterator
-    if( nStart > mnGlyphCount )       // nStart>MAX means no more glyphs
-        return 0;
-
-    // find the visual item for the nStart glyph position
-    int nItem = 0;
-    const VisualItem* pVI = mpVisualItems;
-    if( nStart <= 0 )                 // nStart<=0 requests the first visible glyph
-    {
-        // find first visible item
-        for(; nItem < mnItemCount; ++nItem, ++pVI )
-            if( !pVI->IsEmpty() )
-                break;
-        // it is possible that there are glyphs but no valid visual item
-        // TODO: get rid of these visual items more early
-        if( nItem < mnItemCount )
-            nStart = pVI->mnMinGlyphPos;
-    }
-    else //if( nStart > 0 )           // nStart>0 means absolute glyph pos +1
-    {
-        --nStart;
-
-        // find matching item
-        for(; nItem < mnItemCount; ++nItem, ++pVI )
-            if( (nStart >= pVI->mnMinGlyphPos)
-            &&  (nStart < pVI->mnEndGlyphPos) )
-                break;
-    }
-
-    // after the last visual item there are no more glyphs
-    if( (nItem >= mnItemCount) || (nStart < 0) )
-    {
-        nStartx8 = (mnGlyphCount + 1) << 8;
-        return 0;
-    }
-
-    // calculate the first glyph in the next visual item
-    int nNextItemStart = mnGlyphCount;
-    while( ++nItem < mnItemCount )
-    {
-        if( mpVisualItems[nItem].IsEmpty() )
-            continue;
-        nNextItemStart = mpVisualItems[nItem].mnMinGlyphPos;
-        break;
-    }
-
-    // get the range of relevant glyphs in this visual item
-    int nMinGlyphPos, nEndGlyphPos;
-    bool bRC = GetItemSubrange( *pVI, nMinGlyphPos, nEndGlyphPos );
-    SAL_WARN_IF( !bRC, "vcl", "USPLayout::GNG GISR() returned false" );
-    if( !bRC )
-    {
-        nStartx8 = (mnGlyphCount + 1) << 8;
-        return 0;
-    }
-
-    // make sure nStart is inside the range of relevant glyphs
-    if( nStart < nMinGlyphPos )
-        nStart = nMinGlyphPos;
-
-    // calculate the start glyph xoffset relative to layout's base position,
-    // advance to next visual glyph position by using adjusted glyph widths
-    // TODO: speed up the calculation for nStart!=0 case by using rPos as a cache
-    long nXOffset = pVI->mnXOffset;
-    const int* pGlyphWidths = mpJustifications ? mpJustifications : mpGlyphAdvances;
-    for( int i = nMinGlyphPos; i < nStart; ++i )
-        nXOffset += pGlyphWidths[ i ];
-
-    // adjust the nXOffset relative to glyph cluster start
-    int c = mnMinCharPos;
-    if( !pVI->IsRTL() ) // LTR-case
-    {
-        // LTR case: subtract the remainder of the cell from xoffset
-        int nTmpIndex = mpLogClusters[c];
-        while( (--c >= pVI->mnMinCharPos)
-            && (nTmpIndex == mpLogClusters[c]) )
-            nXOffset -= mpCharWidths[c];
-    }
-    else // RTL-case
-    {
-        // RTL case: add the remainder of the cell from xoffset
-        int nTmpIndex = mpLogClusters[ pVI->mnEndCharPos - 1 ];
-        while( (--c >= pVI->mnMinCharPos)
-            && (nTmpIndex == mpLogClusters[c]) )
-            nXOffset += mpCharWidths[c];
-
-        // adjust the xoffset if justified glyphs are not positioned at their justified positions yet
-        if( mpJustifications && !bManualCellAlign )
-           nXOffset += mpJustifications[ nStart ] - mpGlyphAdvances[ nStart ];
-    }
-
-    // create mpGlyphs2Chars[] if it is needed later
-    if( pCharPosAry && !mpGlyphs2Chars )
-    {
-        // create and reset the new array
-        mpGlyphs2Chars = new int[ mnGlyphCapacity ];
-        for( int i = 0; i < mnGlyphCount; ++i )
-            mpGlyphs2Chars[i] = -1;
-        // calculate the char->glyph mapping
-        for( nItem = 0; nItem < mnItemCount; ++nItem )
-        {
-            // ignore invisible visual items
-            const VisualItem& rVI = mpVisualItems[ nItem ];
-            if( rVI.IsEmpty() )
-                continue;
-
-            //Resolves: fdo#33090 Ensure that all glyph slots, even if 0-width
-            //or empty due to combining chars etc, map back to a character
-            //position so that iterating over glyph slots one at a time for
-            //glyph fallback can keep context as to what characters are the
-            //inputs that caused a missing glyph in a given font.
-
-            //See: fdo#46923/fdo#46896/fdo#46750 for extra complexities
-            {
-                int dir = 1;
-                int out = rVI.mnMinCharPos;
-                if (rVI.IsRTL())
-                {
-                    dir = -1;
-                    out = rVI.mnEndCharPos-1;
-                }
-                for(c = rVI.mnMinCharPos; c < rVI.mnEndCharPos; ++c)
-                {
-                    int i = out - mnSubStringMin;
-                    mpGlyphs2Chars[i] = c;
-                    out += dir;
-                }
-            }
-
-            // calculate the mapping by using mpLogClusters[]
-            // mpGlyphs2Chars[] should obey the logical order
-            // => reversing the loop does this by overwriting higher logicals
-            for( c = rVI.mnEndCharPos; --c >= rVI.mnMinCharPos; )
-            {
-                int i = mpLogClusters[c] + rVI.mnMinGlyphPos;
-                mpGlyphs2Chars[i] = c;
-            }
-            // use a heuristic to fill the gaps in the glyphs2chars array
-            c = !rVI.IsRTL() ? rVI.mnMinCharPos : rVI.mnEndCharPos - 1;
-            for( int i = rVI.mnMinGlyphPos; i < rVI.mnEndGlyphPos; ++i ) {
-                if( mpGlyphs2Chars[i] == -1 )
-                    mpGlyphs2Chars[i] = c;
-                else
-                    c = mpGlyphs2Chars[i];
-            }
-        }
-    }
-
-    // calculate the absolute position of the first result glyph in pixel units
-    const GOFFSET aGOffset = mpGlyphOffsets[ nStart ];
-    Point aRelativePos( nXOffset + aGOffset.du, -aGOffset.dv );
-    rPos = GetDrawPosition( aRelativePos );
-
-    // fill the result arrays
-    int nCount = 0;
-    while( nCount < nLen )
-    {
-        // prepare return values
-        sal_GlyphId aGlyphId = mpOutGlyphs[ nStart ];
-        int nGlyphWidth = pGlyphWidths[ nStart ];
-        int nCharPos = -1;    // no need to determine charpos
-        if( mpGlyphs2Chars )  // unless explicitly requested+provided
-        {
-            nCharPos = mpGlyphs2Chars[ nStart ];
-        }
-
-        // inject kashida glyphs if needed
-        if( !mbDisableGlyphInjection
-        && mpJustifications
-        && mnMinKashidaWidth
-        && mpVisualAttrs[nStart].uJustification >= SCRIPT_JUSTIFY_ARABIC_NORMAL )
-        {
-            // prepare draw position adjustment
-            int nExtraOfs = (nSubIter++) * mnMinKashidaWidth;
-            // calculate space available for the injected glyphs
-               nGlyphWidth = mpGlyphAdvances[ nStart ];
-            const int nExtraWidth = mpJustifications[ nStart ] - nGlyphWidth;
-            const int nToFillWidth = nExtraWidth - nExtraOfs;
-            if( (4*nToFillWidth >= mnMinKashidaWidth)    // prevent glyph-injection if there is no room
-            ||  ((nSubIter > 1) && (nToFillWidth > 0)) ) // unless they can overlap with others
-            {
-                // handle if there is not sufficient room for a full glyph
-                if( nToFillWidth < mnMinKashidaWidth )
-                {
-                    // overlap it with the previously injected glyph if possible
-                    int nOverlap = mnMinKashidaWidth - nToFillWidth;
-                    // else overlap it with both neighboring glyphs
-                    if( nSubIter <= 1 )
-                        nOverlap /= 2;
-                    nExtraOfs -= nOverlap;
-                }
-                nGlyphWidth = mnMinKashidaWidth;
-                aGlyphId = mnMinKashidaGlyph;
-                nCharPos = -1;
-            }
-            else
-            {
-                nExtraOfs += nToFillWidth;    // at right of cell
-                nSubIter = 0;                 // done with glyph injection
-            }
-            if( !bManualCellAlign )
-                nExtraOfs -= nExtraWidth;     // adjust for right-aligned cells
-
-            // adjust the draw position for the injected-glyphs case
-            if( nExtraOfs )
-            {
-                aRelativePos.X() += nExtraOfs;
-                rPos = GetDrawPosition( aRelativePos );
-            }
-        }
-
-        // update return values
-        if( (mnLayoutFlags & SalLayoutFlags::Vertical) &&
-            nCharPos != -1 )
-            aGlyphId |= GetVerticalFlags( msTheString[nCharPos] );
-        *(pGlyphs++) = aGlyphId;
-        if( pGlyphAdvances )
-            *(pGlyphAdvances++) = nGlyphWidth;
-        if( pCharPosAry )
-            *(pCharPosAry++) = nCharPos;
-
-        // increment counter of returned glyphs
-        ++nCount;
-
-        // reduce code complexity by returning early in glyph-injection case
-           if( nSubIter != 0 )
-               break;
-
-        // stop after the last visible glyph in this visual item
-        if( ++nStart >= nEndGlyphPos )
-        {
-            nStart = nNextItemStart;
-            break;
-        }
-
-        // RTL-justified glyph positioning is not easy
-        // simplify the code by just returning only one glyph at a time
-        if( mpJustifications && pVI->IsRTL() )
-            break;
-
-        // stop when the x-position of the next glyph is unexpected
-        if( !pGlyphAdvances  )
-            if( (mpGlyphOffsets && (mpGlyphOffsets[nStart].du != aGOffset.du) )
-             || (mpJustifications && (mpJustifications[nStart] != mpGlyphAdvances[nStart]) ) )
-                break;
-
-        // stop when the y-position of the next glyph is unexpected
-        if( mpGlyphOffsets && (mpGlyphOffsets[nStart].dv != aGOffset.dv) )
-            break;
-    }
-
-    ++nStart;
-    nStartx8 = (nStart << 8) + nSubIter;
-    return nCount;
-}
-
-void UniscribeLayout::MoveGlyph( int nStartx8, long nNewXPos )
-{
-    SAL_WARN_IF( (nStartx8 & 0xff), "vcl", "USP::MoveGlyph(): glyph injection not disabled!" );
-    int nStart = nStartx8 >> 8;
-    if( nStart > mnGlyphCount )
-        return;
-
-    VisualItem* pVI = mpVisualItems;
-    int nMinGlyphPos = 0, nEndGlyphPos;
-    if( nStart == 0 )               // nStart==0 for first visible glyph
-    {
-        for( int i = mnItemCount; --i >= 0; ++pVI )
-            if( GetItemSubrange( *pVI, nMinGlyphPos, nEndGlyphPos ) )
-                break;
-        nStart = nMinGlyphPos;
-        SAL_WARN_IF( nStart > mnGlyphCount, "vcl", "USPLayout::MoveG overflow" );
-    }
-    else //if( nStart > 0 )         // nStart>0 means absolute_glyphpos+1
-    {
-        --nStart;
-        for( int i = mnItemCount; --i >= 0; ++pVI )
-            if( (nStart >= pVI->mnMinGlyphPos) && (nStart < pVI->mnEndGlyphPos) )
-                break;
-        bool bRC = GetItemSubrange( *pVI, nMinGlyphPos, nEndGlyphPos );
-    (void)bRC; // avoid var-not-used warning
-        SAL_WARN_IF( !bRC, "vcl", "USPLayout::MoveG GISR() returned false" );
-    }
-
-    long nDelta = nNewXPos - pVI->mnXOffset;
-    if( nStart > nMinGlyphPos )
-    {
-        // move the glyph by expanding its left glyph but ignore dropped glyphs
-        int i, nLastUndropped = nMinGlyphPos - 1;
-        for( i = nMinGlyphPos; i < nStart; ++i )
-        {
-            if (mpOutGlyphs[i] != DROPPED_OUTGLYPH)
-            {
-                nDelta -= (mpJustifications)? mpJustifications[ i ] : mpGlyphAdvances[ i ];
-                nLastUndropped = i;
-            }
-        }

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list