tdf#136545 revert cairo canvas uses cairo for text rendering already

This was the fallback path, so the problem must already exist in the uncommon
fallback case. I think I know the best approach to take, but for the 7-0 case
be conservative and restore the historic state.

this reverts 770892a387361067d23ab08ed38690c50b8b9395 and associated
code removal

Change-Id: I0e61d934e4dae03442ca5910f802199a1d3d53f4
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/102197
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
diff --git a/canvas/source/cairo/cairo_canvashelper_text.cxx b/canvas/source/cairo/cairo_canvashelper_text.cxx
index 8303887..3b4d161 100644
--- a/canvas/source/cairo/cairo_canvashelper_text.cxx
+++ b/canvas/source/cairo/cairo_canvashelper_text.cxx
@@ -254,7 +254,7 @@ namespace cairocanvas
            mpVirtualDevice->SetLayoutMode( nLayoutMode );

            rtl::Reference pTextLayout( new TextLayout(text, textDirection, 0, CanvasFont::Reference(dynamic_cast< CanvasFont* >( xFont.get() )), mpSurfaceProvider) );
            pTextLayout->draw(*mpVirtualDevice, aOutpos, viewState, renderState);
            pTextLayout->draw(mpCairo, *mpVirtualDevice, aOutpos, viewState, renderState);
        }

        return uno::Reference< rendering::XCachedPrimitive >(nullptr);
@@ -289,7 +289,7 @@ namespace cairocanvas
                    return uno::Reference< rendering::XCachedPrimitive >(nullptr); // no output necessary

                // TODO(F2): What about the offset scalings?
                pTextLayout->draw(*mpVirtualDevice, aOutpos, viewState, renderState);
                pTextLayout->draw(mpCairo, *mpVirtualDevice, aOutpos, viewState, renderState);
            }
        }
        else
diff --git a/canvas/source/cairo/cairo_textlayout.cxx b/canvas/source/cairo/cairo_textlayout.cxx
index d81a739..32a62c5 100644
--- a/canvas/source/cairo/cairo_textlayout.cxx
+++ b/canvas/source/cairo/cairo_textlayout.cxx
@@ -77,6 +77,11 @@ namespace cairocanvas
            // as required at the API spec
            rOutDev.SetLayoutMode( nLayoutMode | ComplexTextLayoutFlags::TextOriginLeft );
        }

        bool compareFallbacks(const SystemGlyphData&rA, const SystemGlyphData &rB)
        {
            return rA.fallbacklevel < rB.fallbacklevel;
        }
    }

    TextLayout::TextLayout( const rendering::StringContext&     aText,
@@ -257,6 +262,33 @@ namespace cairocanvas
    }

  /**
   * TextLayout::isCairoRenderable
   *
   * Features currently not supported by Cairo (VCL rendering is used as fallback):
   * - vertical glyphs
   *
   * @return true, if text/font can be rendered with cairo
   **/
    bool TextLayout::isCairoRenderable(SystemFontData aSysFontData) const
    {
#if defined CAIRO_HAS_FT_FONT
        // is font usable?
        if (!aSysFontData.nFontId)
            return false;
#endif

        // vertical glyph rendering is not supported in cairo for now
        if (aSysFontData.bVerticalCharacterType)
        {
            SAL_WARN("canvas.cairo", ":cairocanvas::TextLayout::isCairoRenderable(): Vertical Character Style not supported");
            return false;
        }

        return true;
    }


  /**
   * TextLayout::draw
   *
   * Cairo-based text rendering. Draw text directly on the cairo surface with cairo fonts.
@@ -265,30 +297,207 @@ namespace cairocanvas
   * Note: some text effects are not rendered due to lacking generic canvas or cairo canvas
   *       implementation. See issues 92657, 92658, 92659, 92660, 97529
   **/
    void TextLayout::draw( OutputDevice&                 rOutDev,
    void TextLayout::draw( CairoSharedPtr const &        pSCairo,
                           OutputDevice&                 rOutDev,
                           const Point&                  rOutpos,
                           const rendering::ViewState&   viewState,
                           const rendering::RenderState& renderState ) const
    {
        ::osl::MutexGuard aGuard( m_aMutex );
        SystemTextLayoutData aSysLayoutData;
        setupLayoutMode( rOutDev, mnTextDirection );

        // TODO(P2): cache that
        std::unique_ptr< long []> aOffsets(new long[maLogicalAdvancements.getLength()]);

        if( maLogicalAdvancements.hasElements() )
        {
            setupTextOffsets( aOffsets.get(), maLogicalAdvancements, viewState, renderState );

        if (maLogicalAdvancements.hasElements())
        {
            rOutDev.DrawTextArray( rOutpos, maText.Text, aOffsets.get(),
                                   ::canvas::tools::numeric_cast<sal_uInt16>(maText.StartPosition),
                                   ::canvas::tools::numeric_cast<sal_uInt16>(maText.Length) );
            // TODO(F3): ensure correct length and termination for DX
            // array (last entry _must_ contain the overall width)
        }
        else

        aSysLayoutData = rOutDev.GetSysTextLayoutData(rOutpos, maText.Text,
                                                      ::canvas::tools::numeric_cast<sal_uInt16>(maText.StartPosition),
                                                      ::canvas::tools::numeric_cast<sal_uInt16>(maText.Length),
                                                      maLogicalAdvancements.hasElements() ? aOffsets.get() : nullptr);

        // Sort them so that all glyphs on the same glyph fallback level are consecutive
        std::sort(aSysLayoutData.rGlyphData.begin(), aSysLayoutData.rGlyphData.end(), compareFallbacks);
        bool bCairoRenderable = true;

        //Pull all the fonts we need to render the text
        typedef std::pair<SystemFontData,int> FontLevel;
        std::vector<FontLevel> aFontData;
        for (auto const& glyph : aSysLayoutData.rGlyphData)
        {
            rOutDev.DrawText( rOutpos, maText.Text,
                              ::canvas::tools::numeric_cast<sal_uInt16>(maText.StartPosition),
                              ::canvas::tools::numeric_cast<sal_uInt16>(maText.Length) );
            if( aFontData.empty() || glyph.fallbacklevel != aFontData.back().second )
            {
                aFontData.emplace_back(rOutDev.GetSysFontData(glyph.fallbacklevel),
                                              glyph.fallbacklevel);
                if( !isCairoRenderable(aFontData.back().first) )
                {
                    bCairoRenderable = false;
                    SAL_INFO("canvas.cairo", ":cairocanvas::TextLayout::draw(S,O,p,v,r): VCL FALLBACK " <<
                             (maLogicalAdvancements.hasElements() ? "ADV " : "") <<
                             (aFontData.back().first.bAntialias ? "AA " : "") <<
                             (aFontData.back().first.bFakeBold ? "FB " : "") <<
                             (aFontData.back().first.bFakeItalic ? "FI " : "") <<
                             " - " <<
                             maText.Text.copy( maText.StartPosition, maText.Length));
                    break;
                }
            }
        }

        // The ::GetSysTextLayoutData(), i.e. layouting of text to glyphs can change the font being used.
        // The fallback checks need to be done after final font is known.
        if (!bCairoRenderable)    // VCL FALLBACKS
        {
            if (maLogicalAdvancements.hasElements())        // VCL FALLBACK - with glyph advances
            {
                rOutDev.DrawTextArray( rOutpos, maText.Text, aOffsets.get(),
                                       ::canvas::tools::numeric_cast<sal_uInt16>(maText.StartPosition),
                                       ::canvas::tools::numeric_cast<sal_uInt16>(maText.Length) );
                return;
            }
            else                                               // VCL FALLBACK - without advances
            {
                rOutDev.DrawText( rOutpos, maText.Text,
                                  ::canvas::tools::numeric_cast<sal_uInt16>(maText.StartPosition),
                                  ::canvas::tools::numeric_cast<sal_uInt16>(maText.Length) );
                return;
            }
        }

        if (aSysLayoutData.rGlyphData.empty())
            return; //??? false?

        /**
         * Setup platform independent glyph vector into cairo-based glyphs vector.
         **/

        // Loop through the fonts used and render the matching glyphs for each
        for (auto const& elemFontData : aFontData)
        {
            const SystemFontData &rSysFontData = elemFontData.first;

            // setup glyphs
            std::vector<cairo_glyph_t> cairo_glyphs;
            cairo_glyphs.reserve( 256 );

            for (auto const& systemGlyph : aSysLayoutData.rGlyphData)
            {
                if( systemGlyph.fallbacklevel != elemFontData.second )
                    continue;

                cairo_glyph_t aGlyph;
                aGlyph.index = systemGlyph.index;
                aGlyph.x = systemGlyph.x;
                aGlyph.y = systemGlyph.y;
                cairo_glyphs.push_back(aGlyph);
            }

            if (cairo_glyphs.empty())
                continue;

            const vcl::Font& aFont = rOutDev.GetFont();
            long nWidth = aFont.GetAverageFontWidth();
            long nHeight = aFont.GetFontHeight();
            if (nWidth == 0)
                nWidth = nHeight;
            if (nWidth == 0 || nHeight == 0)
                continue;

            /**
             * Setup font
             **/
            cairo_font_face_t* font_face = nullptr;

#if defined CAIRO_HAS_FT_FONT
            font_face = cairo_ft_font_face_create_for_ft_face(static_cast<FT_Face>(rSysFontData.nFontId),
                                                              rSysFontData.nFontFlags);
#else
# error Native API needed.
#endif

            cairo_set_font_face( pSCairo.get(), font_face);

            // create default font options. cairo_get_font_options() does not retrieve the surface defaults,
            // only what has been set before with cairo_set_font_options()
            cairo_font_options_t* options = cairo_font_options_create();
            if (rSysFontData.bAntialias)
            {
                // CAIRO_ANTIALIAS_GRAY provides more similar result to VCL Canvas,
                // so we're not using CAIRO_ANTIALIAS_SUBPIXEL
                cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_GRAY);
            }
            cairo_set_font_options( pSCairo.get(), options);

            // Font color
            Color aTextColor = rOutDev.GetTextColor();
            cairo_set_source_rgb(pSCairo.get(),
                                 aTextColor.GetRed()/255.0,
                                 aTextColor.GetGreen()/255.0,
                                 aTextColor.GetBlue()/255.0);

            // Font rotation and scaling
            cairo_matrix_t m;

            cairo_matrix_init_identity(&m);

            if (aSysLayoutData.orientation)
                cairo_matrix_rotate(&m, (3600 - aSysLayoutData.orientation) * M_PI / 1800.0);

            cairo_matrix_scale(&m, nWidth, nHeight);

            //faux italics
            if (rSysFontData.bFakeItalic)
                m.xy = -m.xx * 0x6000 / 0x10000;

            cairo_set_font_matrix(pSCairo.get(), &m);

            SAL_INFO(
                "canvas.cairo",
                "Size:(" << aFont.GetAverageFontWidth() << "," << aFont.GetFontHeight()
                    << "), Pos (" << rOutpos.X() << "," << rOutpos.Y()
                    << "), G("
                    << (!cairo_glyphs.empty() ? cairo_glyphs[0].index : -1)
                    << ","
                    << (cairo_glyphs.size() > 1 ? cairo_glyphs[1].index : -1)
                    << ","
                    << (cairo_glyphs.size() > 2 ? cairo_glyphs[2].index : -1)
                    << ") " << (maLogicalAdvancements.hasElements() ? "ADV " : "")
                    << (rSysFontData.bAntialias ? "AA " : "")
                    << (rSysFontData.bFakeBold ? "FB " : "")
                    << (rSysFontData.bFakeItalic ? "FI " : "") << " || Name:"
                    << aFont.GetFamilyName() << " - "
                    << maText.Text.copy(maText.StartPosition, maText.Length));

            cairo_show_glyphs(pSCairo.get(), cairo_glyphs.data(), cairo_glyphs.size());

            //faux bold
            if (rSysFontData.bFakeBold)
            {
                double bold_dx = 0.5 * sqrt( 0.7 * aFont.GetFontHeight() );
                int total_steps = 1 * static_cast<int>(bold_dx + 0.5);

                // loop to draw the text for every half pixel of displacement
                for (int nSteps = 0; nSteps < total_steps; nSteps++)
                {
                    for(cairo_glyph_t & cairo_glyph : cairo_glyphs)
                    {
                        cairo_glyph.x += (bold_dx * nSteps / total_steps) / 4;
                        cairo_glyph.y -= (bold_dx * nSteps / total_steps) / 4;
                    }
                    cairo_show_glyphs(pSCairo.get(), cairo_glyphs.data(), cairo_glyphs.size());
                }
                SAL_INFO("canvas.cairo",":cairocanvas::TextLayout::draw(S,O,p,v,r): FAKEBOLD - dx:" << static_cast<int>(bold_dx));
            }

            cairo_font_face_destroy(font_face);
            cairo_font_options_destroy(options);
        }
    }

diff --git a/canvas/source/cairo/cairo_textlayout.hxx b/canvas/source/cairo/cairo_textlayout.hxx
index 6254108..b5ba2d8 100644
--- a/canvas/source/cairo/cairo_textlayout.hxx
+++ b/canvas/source/cairo/cairo_textlayout.hxx
@@ -82,7 +82,8 @@ namespace cairocanvas
        virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
        virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;

        void draw( OutputDevice&                                   rOutDev,
        void draw( ::cairo::CairoSharedPtr const &                 pSCairo,
                   OutputDevice&                                   rOutDev,
                   const Point&                                    rOutpos,
                   const css::rendering::ViewState&   viewState,
                   const css::rendering::RenderState& renderState ) const;
@@ -101,6 +102,8 @@ namespace cairocanvas
        CanvasFont::Reference                      mpFont;
        SurfaceProviderRef                         mpRefDevice;
        sal_Int8                                   mnTextDirection;

        bool isCairoRenderable(SystemFontData aSysFontData) const;
    };

}
diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx
index 372d1a7..26a2920 100644
--- a/include/vcl/outdev.hxx
+++ b/include/vcl/outdev.hxx
@@ -55,6 +55,8 @@
struct ImplOutDevData;
class LogicalFontInstance;
struct SystemGraphicsData;
struct SystemFontData;
struct SystemTextLayoutData;
class ImplFontCache;
class PhysicalFontCollection;
class ImplDeviceFontList;
@@ -1231,6 +1233,15 @@ public:

    bool GetFontFeatures(std::vector<vcl::font::Feature>& rFontFeatures) const;


    /** Retrieve detailed font information in platform independent structure

        @param  nFallbacklevel      Fallback font level (0 = best matching font)

        @return SystemFontData
     */
    SystemFontData              GetSysFontData( int nFallbacklevel ) const;

    SAL_DLLPRIVATE void         ImplGetEmphasisMark( tools::PolyPolygon& rPolyPoly, bool& rPolyLine, tools::Rectangle& rRect1, tools::Rectangle& rRect2,
                                                     long& rYOff, long& rWidth, FontEmphasisMark eEmphasis, long nHeight );
    SAL_DLLPRIVATE static FontEmphasisMark
@@ -1320,6 +1331,10 @@ private:

public:

    SystemTextLayoutData        GetSysTextLayoutData( const Point& rStartPt, const OUString& rStr,
                                                      sal_Int32 nIndex, sal_Int32 nLen,
                                                      const long* pDXAry ) const;

    // tells whether this output device is RTL in an LTR UI or LTR in a RTL UI
    SAL_DLLPRIVATE bool         ImplIsAntiparallel() const ;
    SAL_DLLPRIVATE void         ReMirror( Point &rPoint ) const;
diff --git a/include/vcl/sysdata.hxx b/include/vcl/sysdata.hxx
index 1be73fe..3152fa3 100644
--- a/include/vcl/sysdata.hxx
+++ b/include/vcl/sysdata.hxx
@@ -185,6 +185,49 @@ struct SystemWindowData
#endif
};

struct SystemGlyphData
{
    sal_uInt32           index;
    double               x;
    double               y;
    int                  fallbacklevel;
};

#if ENABLE_CAIRO_CANVAS

struct SystemFontData
{
#if defined( UNX )
    void*           nFontId;        // native font id
    int             nFontFlags;     // native font flags
#endif
    bool            bFakeBold;      // Does this font need faking the bold style
    bool            bFakeItalic;    // Does this font need faking the italic style
    bool            bAntialias;     // Should this font be antialiased
    bool            bVerticalCharacterType;      // Is the font using vertical character type

    SystemFontData()
        :
#if defined( UNX )
        nFontId( nullptr ),
        nFontFlags( 0 ),
#endif
        bFakeBold( false ),
        bFakeItalic( false ),
        bAntialias( true ),
        bVerticalCharacterType( false )
    {
    }
};

#endif // ENABLE_CAIRO_CANVAS

struct SystemTextLayoutData
{
    std::vector<SystemGlyphData> rGlyphData;    // glyph data
    int orientation;   // Text orientation
};

#endif // INCLUDED_VCL_SYSDATA_HXX

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/vcl/vcllayout.hxx b/include/vcl/vcllayout.hxx
index 1d6aa9f..9988401 100644
--- a/include/vcl/vcllayout.hxx
+++ b/include/vcl/vcllayout.hxx
@@ -89,7 +89,8 @@ public:

    // methods using glyph indexing
    virtual bool    GetNextGlyph(const GlyphItem** pGlyph, Point& rPos, int& nStart,
                                 const PhysicalFontFace** pFallbackFont = nullptr) const = 0;
                                 const PhysicalFontFace** pFallbackFont = nullptr,
                                 int* const pFallbackLevel = nullptr) const = 0;
    virtual bool GetOutline(basegfx::B2DPolyPolygonVector&) const;
    bool GetBoundRect(tools::Rectangle&) const;

diff --git a/vcl/headless/svptext.cxx b/vcl/headless/svptext.cxx
index f44373f..e4b625b 100644
--- a/vcl/headless/svptext.cxx
+++ b/vcl/headless/svptext.cxx
@@ -22,6 +22,7 @@
#include <vcl/fontcharmap.hxx>
#include <basegfx/range/b2ibox.hxx>
#include <headless/svpgdi.hxx>
#include <config_cairo_canvas.h>
#include <impfontmetricdata.hxx>
#include <sallayout.hxx>

@@ -108,4 +109,13 @@ void SvpSalGraphics::SetTextColor( Color nColor )
    m_aTextRenderImpl.SetTextColor(nColor);
}

#if ENABLE_CAIRO_CANVAS

SystemFontData SvpSalGraphics::GetSysFontData( int nFallbacklevel ) const
{
    return m_aTextRenderImpl.GetSysFontData(nFallbacklevel);
}

#endif // ENABLE_CAIRO_CANVAS

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/headless/svpgdi.hxx b/vcl/inc/headless/svpgdi.hxx
index 3cffdcd..3d1617d 100644
--- a/vcl/inc/headless/svpgdi.hxx
+++ b/vcl/inc/headless/svpgdi.hxx
@@ -273,6 +273,7 @@ public:
    virtual cairo::SurfaceSharedPtr CreateSurface(const OutputDevice& rRefDevice, int x, int y, int width, int height) const override;
    virtual cairo::SurfaceSharedPtr CreateBitmapSurface(const OutputDevice& rRefDevice, const BitmapSystemData& rData, const Size& rSize) const override;
    virtual css::uno::Any   GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& rSurface, const basegfx::B2ISize& rSize) const override;
    virtual SystemFontData  GetSysFontData( int nFallbacklevel ) const override;
#endif // ENABLE_CAIRO_CANVAS

    cairo_t*                getCairoContext(bool bXorModeAllowed) const;
diff --git a/vcl/inc/qt5/Qt5Graphics.hxx b/vcl/inc/qt5/Qt5Graphics.hxx
index 1515783..bc4870ee 100644
--- a/vcl/inc/qt5/Qt5Graphics.hxx
+++ b/vcl/inc/qt5/Qt5Graphics.hxx
@@ -92,6 +92,7 @@ public:
                                                        const Size& rSize) const override;
    virtual css::uno::Any GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& rSurface,
                                                 const basegfx::B2ISize& rSize) const override;
    virtual SystemFontData GetSysFontData(int nFallbacklevel) const override;
#endif // ENABLE_CAIRO_CANVAS

    // GDI
diff --git a/vcl/inc/salgdi.hxx b/vcl/inc/salgdi.hxx
index d2b92c6..8d8e4c9 100644
--- a/vcl/inc/salgdi.hxx
+++ b/vcl/inc/salgdi.hxx
@@ -48,6 +48,10 @@ class OutputDevice;
class FreetypeFont;
struct SystemGraphicsData;

#if ENABLE_CAIRO_CANVAS
struct SystemFontData;
#endif // ENABLE_CAIRO_CANVAS

namespace basegfx {
    class B2DVector;
    class B2DPolygon;
@@ -431,6 +435,8 @@ public:
    virtual cairo::SurfaceSharedPtr CreateBitmapSurface(const OutputDevice& rRefDevice, const BitmapSystemData& rData, const Size& rSize) const = 0;
    virtual css::uno::Any       GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& rSurface, const basegfx::B2ISize& rSize) const = 0;

    virtual SystemFontData      GetSysFontData( int nFallbacklevel ) const = 0;

#endif // ENABLE_CAIRO_CANVAS

protected:
diff --git a/vcl/inc/sallayout.hxx b/vcl/inc/sallayout.hxx
index 9ab5263..e94b4c2 100644
--- a/vcl/inc/sallayout.hxx
+++ b/vcl/inc/sallayout.hxx
@@ -130,7 +130,8 @@ public:
    DeviceCoordinate FillDXArray(DeviceCoordinate* pDXArray) const override;
    void            GetCaretPositions(int nArraySize, long* pCaretXArray) const override;
    bool            GetNextGlyph(const GlyphItem** pGlyph, Point& rPos, int& nStart,
                                 const PhysicalFontFace** pFallbackFont = nullptr) const override;
                                 const PhysicalFontFace** pFallbackFont = nullptr,
                                 int* const pFallbackLevel = nullptr) const override;
    bool            GetOutline(basegfx::B2DPolyPolygonVector&) const override;
    bool            IsKashidaPosValid(int nCharPos) const override;

@@ -183,7 +184,8 @@ public:
        { return m_GlyphItems.Impl()->GetFont(); }

    bool            GetNextGlyph(const GlyphItem** pGlyph, Point& rPos, int& nStart,
                                 const PhysicalFontFace** pFallbackFont = nullptr) const override;
                                 const PhysicalFontFace** pFallbackFont = nullptr,
                                 int* const pFallbackLevel = nullptr) const override;

private:
    // for glyph+font+script fallback
diff --git a/vcl/inc/textrender.hxx b/vcl/inc/textrender.hxx
index f1cbfd8..1aec8fb 100644
--- a/vcl/inc/textrender.hxx
+++ b/vcl/inc/textrender.hxx
@@ -22,6 +22,8 @@

#include "salgdi.hxx"

#include <config_cairo_canvas.h>

class ImplLayoutArgs;
class ImplFontMetricData;
class PhysicalFontCollection;
@@ -62,6 +64,9 @@ public:
    virtual std::unique_ptr<GenericSalLayout>
                                    GetTextLayout(int nFallbackLevel) = 0;
    virtual void                    DrawTextLayout(const GenericSalLayout&, const SalGraphics&) = 0;
#if ENABLE_CAIRO_CANVAS
    virtual SystemFontData          GetSysFontData( int nFallbackLevel ) const = 0;
#endif // ENABLE_CAIRO_CANVAS
};

#endif
diff --git a/vcl/inc/unx/freetypetextrender.hxx b/vcl/inc/unx/freetypetextrender.hxx
index 9c4960e..ccc1db0 100644
--- a/vcl/inc/unx/freetypetextrender.hxx
+++ b/vcl/inc/unx/freetypetextrender.hxx
@@ -65,6 +65,9 @@ public:

    virtual std::unique_ptr<GenericSalLayout>
                                GetTextLayout(int nFallbackLevel) override;
#if ENABLE_CAIRO_CANVAS
    virtual SystemFontData      GetSysFontData( int nFallbackLevel ) const override;
#endif
};

#endif
diff --git a/vcl/inc/unx/genpspgraphics.h b/vcl/inc/unx/genpspgraphics.h
index c02d6aa..b696618 100644
--- a/vcl/inc/unx/genpspgraphics.h
+++ b/vcl/inc/unx/genpspgraphics.h
@@ -203,6 +203,8 @@ public:
    virtual cairo::SurfaceSharedPtr CreateSurface(const OutputDevice& rRefDevice, int x, int y, int width, int height) const override;
    virtual cairo::SurfaceSharedPtr CreateBitmapSurface(const OutputDevice& rRefDevice, const BitmapSystemData& rData, const Size& rSize) const override;
    virtual css::uno::Any   GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& rSurface, const basegfx::B2ISize& rSize) const override;

    virtual SystemFontData  GetSysFontData( int nFallbacklevel ) const override;
#endif // ENABLE_CAIRO_CANVAS
};

diff --git a/vcl/inc/unx/glyphcache.hxx b/vcl/inc/unx/glyphcache.hxx
index 993a0cf..983a6ec 100644
--- a/vcl/inc/unx/glyphcache.hxx
+++ b/vcl/inc/unx/glyphcache.hxx
@@ -116,6 +116,7 @@ public:
    int                     GetFontFaceVariation() const;
    bool                    TestFont() const { return mbFaceOk;}
    FT_Face                 GetFtFace() const;
    int                     GetLoadFlags() const { return (mnLoadFlags & ~FT_LOAD_IGNORE_TRANSFORM); }
    const FontConfigFontOptions* GetFontOptions() const;
    bool                    NeedsArtificialBold() const { return mbArtBold; }
    bool                    NeedsArtificialItalic() const { return mbArtItalic; }
@@ -129,6 +130,8 @@ public:
    bool                    GetGlyphOutline(sal_GlyphId, basegfx::B2DPolyPolygon&, bool) const;
    bool                    GetAntialiasAdvice() const;

    FreetypeFontInstance&   GetFontInstance() const { return mrFontInstance; }

    void                    SetFontVariationsOnHBFont(hb_font_t* pHbFace) const;

    // tdf#127189 FreeType <= 2.8 will fail to render stretched horizontal brace glyphs
diff --git a/vcl/inc/unx/salgdi.h b/vcl/inc/unx/salgdi.h
index caef46a..4216b70 100644
--- a/vcl/inc/unx/salgdi.h
+++ b/vcl/inc/unx/salgdi.h
@@ -264,6 +264,7 @@ public:
    virtual cairo::SurfaceSharedPtr CreateSurface(const OutputDevice& rRefDevice, int x, int y, int width, int height) const override;
    virtual cairo::SurfaceSharedPtr CreateBitmapSurface(const OutputDevice& rRefDevice, const BitmapSystemData& rData, const Size& rSize) const override;
    virtual css::uno::Any           GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& rSurface, const basegfx::B2ISize& rSize) const override;
    virtual SystemFontData          GetSysFontData( int nFallbackLevel ) const override;

    void clipRegion(cairo_t* cr);
#endif // ENABLE_CAIRO_CANVAS
diff --git a/vcl/qt5/Qt5Graphics.cxx b/vcl/qt5/Qt5Graphics.cxx
index 257e0f4..34f6108 100644
--- a/vcl/qt5/Qt5Graphics.cxx
+++ b/vcl/qt5/Qt5Graphics.cxx
@@ -104,6 +104,11 @@ css::uno::Any Qt5Graphics::GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& /*rSu
    return css::uno::Any();
}

SystemFontData Qt5Graphics::GetSysFontData(int /*nFallbacklevel*/) const
{
    return SystemFontData();
}

#endif

void Qt5Graphics::handleDamage(const tools::Rectangle& rDamagedRegion)
diff --git a/vcl/source/control/button.cxx b/vcl/source/control/button.cxx
index 1f9e257..7e0a1bf 100644
--- a/vcl/source/control/button.cxx
+++ b/vcl/source/control/button.cxx
@@ -1528,6 +1528,7 @@ void PushButton::SetState( TriState eState )
void PushButton::statusChanged(const css::frame::FeatureStateEvent& rEvent)
{
    Button::statusChanged(rEvent);
    fprintf(stderr, "State is %d\n", rEvent.State.has<bool>());
    if (rEvent.State.has<bool>())
        SetPressed(rEvent.State.get<bool>());
}
diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx
index 55aa1450..eaa016ed 100644
--- a/vcl/source/gdi/sallayout.cxx
+++ b/vcl/source/gdi/sallayout.cxx
@@ -895,7 +895,7 @@ sal_Int32 GenericSalLayout::GetTextBreak( DeviceCoordinate nMaxWidth, DeviceCoor

bool GenericSalLayout::GetNextGlyph(const GlyphItem** pGlyph,
                                    Point& rPos, int& nStart,
                                    const PhysicalFontFace**) const
                                    const PhysicalFontFace**, int* const pFallbackLevel) const
{
    std::vector<GlyphItem>::const_iterator pGlyphIter = m_GlyphItems.Impl()->begin();
    std::vector<GlyphItem>::const_iterator pGlyphIterEnd = m_GlyphItems.Impl()->end();
@@ -918,6 +918,8 @@ bool GenericSalLayout::GetNextGlyph(const GlyphItem** pGlyph,

    // update return data with glyph info
    *pGlyph = &(*pGlyphIter);
    if (pFallbackLevel)
        *pFallbackLevel = 0;
    ++nStart;

    // calculate absolute position in pixel units
@@ -1504,7 +1506,8 @@ void MultiSalLayout::GetCaretPositions( int nMaxIndex, long* pCaretXArray ) cons

bool MultiSalLayout::GetNextGlyph(const GlyphItem** pGlyph,
                                  Point& rPos, int& nStart,
                                  const PhysicalFontFace** pFallbackFont) const
                                  const PhysicalFontFace** pFallbackFont,
                                  int* const pFallbackLevel) const
{
    // NOTE: nStart is tagged with current font index
    int nLevel = static_cast<unsigned>(nStart) >> GF_FONTSHIFT;
@@ -1520,6 +1523,8 @@ bool MultiSalLayout::GetNextGlyph(const GlyphItem** pGlyph,
            nStart |= nFontTag;
            if (pFallbackFont)
                *pFallbackFont = pFontFace;
            if (pFallbackLevel)
                *pFallbackLevel = nLevel;
            rPos += maDrawBase;
            rPos += maDrawOffset;
            return true;
diff --git a/vcl/source/outdev/font.cxx b/vcl/source/outdev/font.cxx
index b7d8bfe..59ce4ef 100644
--- a/vcl/source/outdev/font.cxx
+++ b/vcl/source/outdev/font.cxx
@@ -278,6 +278,23 @@ bool OutputDevice::GetFontCapabilities( vcl::FontCapabilities& rFontCapabilities
    return mpGraphics->GetFontCapabilities(rFontCapabilities);
}

#if ENABLE_CAIRO_CANVAS

SystemFontData OutputDevice::GetSysFontData(int nFallbacklevel) const
{
    SystemFontData aSysFontData;

    if (!mpGraphics)
        (void) AcquireGraphics();

    if (mpGraphics)
        aSysFontData = mpGraphics->GetSysFontData(nFallbacklevel);

    return aSysFontData;
}

#endif // ENABLE_CAIRO_CANVAS

void OutputDevice::ImplGetEmphasisMark( tools::PolyPolygon& rPolyPoly, bool& rPolyLine,
                                        tools::Rectangle& rRect1, tools::Rectangle& rRect2,
                                        long& rYOff, long& rWidth,
diff --git a/vcl/source/outdev/text.cxx b/vcl/source/outdev/text.cxx
index b11e1e4..34db8e6 100644
--- a/vcl/source/outdev/text.cxx
+++ b/vcl/source/outdev/text.cxx
@@ -2254,6 +2254,67 @@ OUString OutputDevice::GetNonMnemonicString( const OUString& rStr, sal_Int32& rM
    return aStr;
}

/** OutputDevice::GetSysTextLayoutData
 *
 * @param rStartPt Start point of the text
 * @param rStr Text string that will be transformed into layout of glyphs
 * @param nIndex Position in the string from where layout will be done
 * @param nLen Length of the string
 * @param pDXAry Custom layout adjustment data
 *
 * Export finalized glyph layout data as platform independent SystemTextLayoutData
 * (see vcl/inc/vcl/sysdata.hxx)
 *
 * Only parameters rStartPt and rStr are mandatory, the rest is optional
 * (default values will be used)
 *
 * @return SystemTextLayoutData
 **/
SystemTextLayoutData OutputDevice::GetSysTextLayoutData(const Point& rStartPt, const OUString& rStr, sal_Int32 nIndex, sal_Int32 nLen,
                                                        const long* pDXAry) const
{
    if( (nLen < 0) || (nIndex + nLen >= rStr.getLength()))
    {
        nLen = rStr.getLength() - nIndex;
    }

    SystemTextLayoutData aSysLayoutData;
    aSysLayoutData.rGlyphData.reserve( 256 );
    aSysLayoutData.orientation = 0;

    if ( mpMetaFile )
    {
        if (pDXAry)
            mpMetaFile->AddAction( new MetaTextArrayAction( rStartPt, rStr, pDXAry, nIndex, nLen ) );
        else
            mpMetaFile->AddAction( new MetaTextAction( rStartPt, rStr, nIndex, nLen ) );
    }

    if ( !IsDeviceOutputNecessary() ) return aSysLayoutData;

    std::unique_ptr<SalLayout> pLayout = ImplLayout(rStr, nIndex, nLen, rStartPt, 0, pDXAry);

    if ( !pLayout ) return aSysLayoutData;

    // setup glyphs
    Point aPos;
    const GlyphItem* pGlyph;
    int nStart = 0;
    SystemGlyphData aSystemGlyph;
    while (pLayout->GetNextGlyph(&pGlyph, aPos, nStart, nullptr, &aSystemGlyph.fallbacklevel))
    {
        aSystemGlyph.index = pGlyph->glyphId();
        aSystemGlyph.x = aPos.X();
        aSystemGlyph.y = aPos.Y();
        aSysLayoutData.rGlyphData.push_back(aSystemGlyph);
    }

    // Get font data
    aSysLayoutData.orientation = pLayout->GetOrientation();

    return aSysLayoutData;
}

bool OutputDevice::GetTextBoundRect( tools::Rectangle& rRect,
                                         const OUString& rStr, sal_Int32 nBase,
                                         sal_Int32 nIndex, sal_Int32 nLen,
diff --git a/vcl/unx/generic/gdi/font.cxx b/vcl/unx/generic/gdi/font.cxx
index 5a6f04f..ede4d95 100644
--- a/vcl/unx/generic/gdi/font.cxx
+++ b/vcl/unx/generic/gdi/font.cxx
@@ -80,6 +80,15 @@ std::unique_ptr<GenericSalLayout> X11SalGraphics::GetTextLayout(int nFallbackLev
    return mxTextRenderImpl->GetTextLayout(nFallbackLevel);
}

#if ENABLE_CAIRO_CANVAS

SystemFontData X11SalGraphics::GetSysFontData( int nFallbackLevel ) const
{
    return mxTextRenderImpl->GetSysFontData(nFallbackLevel);
}

#endif

bool X11SalGraphics::CreateFontSubset(
                                   const OUString& rToFile,
                                   const PhysicalFontFace* pFont,
diff --git a/vcl/unx/generic/gdi/freetypetextrender.cxx b/vcl/unx/generic/gdi/freetypetextrender.cxx
index b364406..3d94da3 100644
--- a/vcl/unx/generic/gdi/freetypetextrender.cxx
+++ b/vcl/unx/generic/gdi/freetypetextrender.cxx
@@ -153,6 +153,29 @@ std::unique_ptr<GenericSalLayout> FreeTypeTextRenderImpl::GetTextLayout(int nFal
    return std::make_unique<GenericSalLayout>(*mpFreetypeFont[nFallbackLevel]);
}

#if ENABLE_CAIRO_CANVAS
SystemFontData FreeTypeTextRenderImpl::GetSysFontData( int nFallbackLevel ) const
{
    SystemFontData aSysFontData;

    if (nFallbackLevel >= MAX_FALLBACK) nFallbackLevel = MAX_FALLBACK - 1;
    if (nFallbackLevel < 0 ) nFallbackLevel = 0;

    if (mpFreetypeFont[nFallbackLevel])
    {
        FreetypeFont& rFreetypeFont = mpFreetypeFont[nFallbackLevel]->GetFreetypeFont();
        aSysFontData.nFontId = rFreetypeFont.GetFtFace();
        aSysFontData.nFontFlags = rFreetypeFont.GetLoadFlags();
        aSysFontData.bFakeBold = rFreetypeFont.NeedsArtificialBold();
        aSysFontData.bFakeItalic = rFreetypeFont.NeedsArtificialItalic();
        aSysFontData.bAntialias = rFreetypeFont.GetAntialiasAdvice();
        aSysFontData.bVerticalCharacterType = mpFreetypeFont[nFallbackLevel]->GetFontSelectPattern().mbVertical;
    }

    return aSysFontData;
}
#endif

bool FreeTypeTextRenderImpl::CreateFontSubset(
                                   const OUString& rToFile,
                                   const PhysicalFontFace* pFont,
diff --git a/vcl/unx/generic/print/genpspgraphics.cxx b/vcl/unx/generic/print/genpspgraphics.cxx
index 03319d1..235f45e 100644
--- a/vcl/unx/generic/print/genpspgraphics.cxx
+++ b/vcl/unx/generic/print/genpspgraphics.cxx
@@ -944,6 +944,11 @@ css::uno::Any GenPspGraphics::GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& /*
    return css::uno::Any();
}

SystemFontData GenPspGraphics::GetSysFontData( int /* nFallbacklevel */ ) const
{
    return SystemFontData();
}

#endif // ENABLE_CAIRO_CANVAS

bool GenPspGraphics::supportsOperation( OutDevSupportType ) const