[Libreoffice-commits] core.git: vcl/headless vcl/inc vcl/Library_vcl.mk vcl/StaticLibrary_headless.mk

Caolán McNamara caolanm at redhat.com
Fri Feb 27 06:15:22 PST 2015


 vcl/Library_vcl.mk                 |    1 
 vcl/StaticLibrary_headless.mk      |    1 
 vcl/headless/svpgdi.cxx            |   27 --
 vcl/headless/svptext.cxx           |  396 ++---------------------------
 vcl/headless/svptextrender.cxx     |  496 +++++++++++++++++++++++++++++++++++++
 vcl/inc/devicetextrender.hxx       |   24 +
 vcl/inc/headless/svpgdi.hxx        |   18 -
 vcl/inc/headless/svptextrender.hxx |   82 ++++++
 8 files changed, 651 insertions(+), 394 deletions(-)

New commits:
commit dd179370e0905dc4ae206467d65cb69b70d5356e
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Fri Feb 27 11:01:49 2015 +0000

    seperate headless textrendering into its own class
    
    and forward calls to it from the SvpGraphics
    
    Change-Id: I6d1fbc8919596d5f47661b3471570fcb7e14bc3e

diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index e114ae3..6aeb70b 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -558,6 +558,7 @@ vcl_headless_code= \
 vcl_headless_freetype_code=\
     vcl/headless/svpprn \
     vcl/headless/svptext \
+    vcl/headless/svptextrender \
 
 ifeq ($(GUIBASE),unx)
 $(eval $(call gb_Library_add_exception_objects,vcl,\
diff --git a/vcl/StaticLibrary_headless.mk b/vcl/StaticLibrary_headless.mk
index 1b63851..941f4ed 100644
--- a/vcl/StaticLibrary_headless.mk
+++ b/vcl/StaticLibrary_headless.mk
@@ -25,6 +25,7 @@ $(eval $(call gb_StaticLibrary_add_exception_objects,headless,\
 	vcl/headless/svpframe \
 	vcl/headless/svpprn \
 	vcl/headless/svptext \
+	vcl/headless/svptextrender \
 	vcl/headless/svpvd \
 ))
 
diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx
index 3f63146..677d165 100644
--- a/vcl/headless/svpgdi.cxx
+++ b/vcl/headless/svpgdi.cxx
@@ -19,6 +19,7 @@
 
 #include "headless/svpgdi.hxx"
 #include "headless/svpbmp.hxx"
+#include "headless/svptextrender.hxx"
 #include "saldatabasic.hxx"
 
 #include <vcl/sysdata.hxx>
@@ -101,12 +102,9 @@ SvpSalGraphics::SvpSalGraphics() :
     m_bUseFillColor( false ),
     m_aFillColor( COL_WHITE ),
     m_aDrawMode( basebmp::DrawMode_PAINT ),
-    m_aTextColor( COL_BLACK ),
-    m_eTextFmt( basebmp::FORMAT_EIGHT_BIT_GREY ),
     m_bClipSetup( false )
 {
-    for( int i = 0; i < MAX_FALLBACK; ++i )
-        m_pServerFont[i] = NULL;
+    m_xTextRenderImpl.reset(new SvpTextRender(*this));
 }
 
 SvpSalGraphics::~SvpSalGraphics()
@@ -117,26 +115,7 @@ void SvpSalGraphics::setDevice( basebmp::BitmapDeviceSharedPtr& rDevice )
 {
     m_aOrigDevice = rDevice;
     ResetClipRegion();
-
-    // determine matching bitmap format for masks
-    basebmp::Format nDeviceFmt = m_aDevice ? m_aDevice->getScanlineFormat() : basebmp::FORMAT_EIGHT_BIT_GREY;
-    switch( nDeviceFmt )
-    {
-        case basebmp::FORMAT_EIGHT_BIT_GREY:
-        case basebmp::FORMAT_SIXTEEN_BIT_LSB_TC_MASK:
-        case basebmp::FORMAT_SIXTEEN_BIT_MSB_TC_MASK:
-        case basebmp::FORMAT_TWENTYFOUR_BIT_TC_MASK:
-        case basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_BGRX:
-        case basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_BGRA:
-        case basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_ARGB:
-        case basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_ABGR:
-        case basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_RGBA:
-            m_eTextFmt = basebmp::FORMAT_EIGHT_BIT_GREY;
-            break;
-        default:
-            m_eTextFmt = basebmp::FORMAT_ONE_BIT_LSB_GREY;
-            break;
-    }
+    m_xTextRenderImpl->setDevice(rDevice);
 }
 
 #endif
diff --git a/vcl/headless/svptext.cxx b/vcl/headless/svptext.cxx
index ef6e1ab..1651a3a 100644
--- a/vcl/headless/svptext.cxx
+++ b/vcl/headless/svptext.cxx
@@ -18,279 +18,43 @@
  */
 
 #include <sal/types.h>
-
-#include <cassert>
-
-#include <basebmp/scanlineformats.hxx>
-#include <basegfx/polygon/b2dpolypolygon.hxx>
-#include <basegfx/range/b2drange.hxx>
 #include <basegfx/range/b2ibox.hxx>
-#include <rtl/instance.hxx>
-#include <tools/debug.hxx>
-#include <vcl/sysdata.hxx>
-
-#include "generic/geninst.h"
-#include "generic/genpspgraphics.h"
-#include "generic/glyphcache.hxx"
-#include "headless/svpbmp.hxx"
 #include "headless/svpgdi.hxx"
-#include "impfont.hxx"
-#include "outfont.hxx"
-#include "PhysicalFontFace.hxx"
-
-class PhysicalFontCollection;
-
-using namespace basegfx;
-using namespace basebmp;
-
-class SvpGlyphPeer : public GlyphCachePeer
-{
-public:
-    SvpGlyphPeer() {}
-
-    BitmapDeviceSharedPtr GetGlyphBmp( ServerFont&, sal_GlyphId,
-                                       basebmp::Format nBmpFormat, B2IPoint& rTargetPos );
-
-protected:
-    virtual void    RemovingFont( ServerFont& ) SAL_OVERRIDE;
-    virtual void    RemovingGlyph( GlyphData& ) SAL_OVERRIDE;
-
-    class SvpGcpHelper
-    {
-    public:
-        RawBitmap               maRawBitmap;
-        BitmapDeviceSharedPtr   maBitmapDev;
-    };
-};
-
-class SvpGlyphCache : public GlyphCache
-{
-public:
-    SvpGlyphCache( SvpGlyphPeer& rPeer ) : GlyphCache( rPeer) {}
-    SvpGlyphPeer& GetPeer() { return reinterpret_cast<SvpGlyphPeer&>( mrPeer ); }
-    static SvpGlyphCache& GetInstance();
-};
-
-namespace
-{
-    struct GlyphCacheHolder
-    {
-    private:
-        SvpGlyphPeer* m_pSvpGlyphPeer;
-        SvpGlyphCache* m_pSvpGlyphCache;
-    public:
-        GlyphCacheHolder()
-        {
-            m_pSvpGlyphPeer = new SvpGlyphPeer();
-            m_pSvpGlyphCache = new SvpGlyphCache( *m_pSvpGlyphPeer );
-        }
-        void release()
-        {
-            delete m_pSvpGlyphCache;
-            delete m_pSvpGlyphPeer;
-            m_pSvpGlyphCache = NULL;
-            m_pSvpGlyphPeer = NULL;
-        }
-        SvpGlyphCache& getGlyphCache()
-        {
-            return *m_pSvpGlyphCache;
-        }
-        ~GlyphCacheHolder()
-        {
-            release();
-        }
-    };
-
-    struct theGlyphCacheHolder :
-        public rtl::Static<GlyphCacheHolder, theGlyphCacheHolder>
-    {};
-}
-
-SvpGlyphCache& SvpGlyphCache::GetInstance()
-{
-    return theGlyphCacheHolder::get().getGlyphCache();
-}
-
-BitmapDeviceSharedPtr SvpGlyphPeer::GetGlyphBmp( ServerFont& rServerFont,
-    sal_GlyphId aGlyphId, basebmp::Format nBmpFormat, B2IPoint& rTargetPos )
-{
-    GlyphData& rGlyphData = rServerFont.GetGlyphData( aGlyphId );
-
-    if( rGlyphData.ExtDataRef().meInfo != nBmpFormat )
-    {
-        SvpGcpHelper* pGcpHelper = static_cast<SvpGcpHelper*>(
-            rGlyphData.ExtDataRef().mpData);
-        bool bNew = pGcpHelper == 0;
-        if( bNew )
-            pGcpHelper = new SvpGcpHelper;
-
-        // get glyph bitmap in matching format
-        bool bFound = false;
-        switch( nBmpFormat )
-        {
-            case FORMAT_ONE_BIT_LSB_GREY:
-                bFound = rServerFont.GetGlyphBitmap1( aGlyphId, pGcpHelper->maRawBitmap );
-                break;
-            case FORMAT_EIGHT_BIT_GREY:
-                bFound = rServerFont.GetGlyphBitmap8( aGlyphId, pGcpHelper->maRawBitmap );
-                break;
-            default:
-                OSL_FAIL( "SVP GCP::GetGlyphBmp(): illegal scanline format");
-                // fall back to black&white mask
-                nBmpFormat = FORMAT_ONE_BIT_LSB_GREY;
-                bFound = false;
-                break;
-        }
-
-        // return .notdef glyph if needed
-        if( !bFound && (aGlyphId != 0) )
-        {
-            if( bNew )
-                delete pGcpHelper;
-            return GetGlyphBmp( rServerFont, 0, nBmpFormat, rTargetPos );
-        }
-
-        // construct alpha mask from raw bitmap
-        if (pGcpHelper->maRawBitmap.mnScanlineSize && pGcpHelper->maRawBitmap.mnHeight)
-        {
-            const B2IVector aSize(
-                pGcpHelper->maRawBitmap.mnScanlineSize,
-                pGcpHelper->maRawBitmap.mnHeight );
-            static PaletteMemorySharedVector aDummyPAL;
-            pGcpHelper->maBitmapDev = createBitmapDevice( aSize, true, nBmpFormat, aSize.getX(), pGcpHelper->maRawBitmap.mpBits, aDummyPAL );
-        }
-
-        rGlyphData.ExtDataRef().meInfo = nBmpFormat;
-        rGlyphData.ExtDataRef().mpData = pGcpHelper;
-    }
-
-    SvpGcpHelper* pGcpHelper = static_cast<SvpGcpHelper*>(
-        rGlyphData.ExtDataRef().mpData);
-    assert(pGcpHelper != 0);
-    rTargetPos += B2IPoint( pGcpHelper->maRawBitmap.mnXOffset, pGcpHelper->maRawBitmap.mnYOffset );
-    return pGcpHelper->maBitmapDev;
-}
-
-void SvpGlyphPeer::RemovingFont( ServerFont& )
-{
-    // nothing to do: no font resources held in SvpGlyphPeer
-}
-
-void SvpGlyphPeer::RemovingGlyph( GlyphData& rGlyphData )
-{
-    SvpGcpHelper* pGcpHelper = static_cast<SvpGcpHelper*>(
-        rGlyphData.ExtDataRef().mpData);
-    rGlyphData.ExtDataRef().meInfo = basebmp::FORMAT_NONE;
-    rGlyphData.ExtDataRef().mpData = 0;
-    delete pGcpHelper;
-}
 
 sal_uInt16 SvpSalGraphics::SetFont( FontSelectPattern* pIFSD, int nFallbackLevel )
 {
-    // release all no longer needed font resources
-    for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
-    {
-        if( m_pServerFont[i] != NULL )
-        {
-            // old server side font is no longer referenced
-            SvpGlyphCache::GetInstance().UncacheFont( *m_pServerFont[i] );
-            m_pServerFont[i] = NULL;
-        }
-    }
-
-    // return early if there is no new font
-    if( !pIFSD )
-        return 0;
-
-    // handle the request for a non-native X11-font => use the GlyphCache
-    ServerFont* pServerFont = SvpGlyphCache::GetInstance().CacheFont( *pIFSD );
-    if( !pServerFont )
-        return SAL_SETFONT_BADFONT;
-
-    // check selected font
-    if( !pServerFont->TestFont() )
-    {
-        SvpGlyphCache::GetInstance().UncacheFont( *pServerFont );
-        return SAL_SETFONT_BADFONT;
-    }
-
-    // update SalGraphics font settings
-    m_pServerFont[ nFallbackLevel ] = pServerFont;
-    return SAL_SETFONT_USEDRAWTEXTARRAY;
+    return m_xTextRenderImpl->SetFont(pIFSD, nFallbackLevel);
 }
 
 void SvpSalGraphics::GetFontMetric( ImplFontMetricData* pMetric, int nFallbackLevel )
 {
-    if( nFallbackLevel >= MAX_FALLBACK )
-        return;
-
-    if( m_pServerFont[nFallbackLevel] != NULL )
-    {
-        long rDummyFactor;
-        m_pServerFont[nFallbackLevel]->FetchFontMetric( *pMetric, rDummyFactor );
-    }
+    m_xTextRenderImpl->GetFontMetric(pMetric, nFallbackLevel);
 }
 
 const FontCharMapPtr SvpSalGraphics::GetFontCharMap() const
 {
-    if( !m_pServerFont[0] )
-        return NULL;
-
-    const FontCharMapPtr pFCMap = m_pServerFont[0]->GetFontCharMap();
-    return pFCMap;
+    return m_xTextRenderImpl->GetFontCharMap();
 }
 
 bool SvpSalGraphics::GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
 {
-    if (!m_pServerFont[0])
-        return false;
-
-    return m_pServerFont[0]->GetFontCapabilities(rFontCapabilities);
+    return m_xTextRenderImpl->GetFontCapabilities(rFontCapabilities);
 }
 
 void SvpSalGraphics::GetDevFontList( PhysicalFontCollection* pFontCollection )
 {
-    GlyphCache& rGC = SvpGlyphCache::GetInstance();
-
-    psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
-    psp::FastPrintFontInfo aInfo;
-    ::std::list< psp::fontID > aList;
-    rMgr.getFontList( aList );
-    ::std::list< psp::fontID >::iterator it;
-    for( it = aList.begin(); it != aList.end(); ++it )
-    {
-        if( !rMgr.getFontFastInfo( *it, aInfo ) )
-            continue;
-
-        // normalize face number to the GlyphCache
-        int nFaceNum = rMgr.getFontFaceNumber( aInfo.m_nID );
-
-        // inform GlyphCache about this font provided by the PsPrint subsystem
-        ImplDevFontAttributes aDFA = GenPspGraphics::Info2DevFontAttributes( aInfo );
-        aDFA.mnQuality += 4096;
-        const OString& rFileName = rMgr.getFontFileSysPath( aInfo.m_nID );
-        rGC.AddFontFile( rFileName, nFaceNum, aInfo.m_nID, aDFA );
-   }
-
-    // announce glyphcache fonts
-    rGC.AnnounceFonts( pFontCollection );
-
-    // register platform specific font substitutions if available
-    SalGenericInstance::RegisterFontSubstitutors( pFontCollection );
-
-    ImplGetSVData()->maGDIData.mbNativeFontConfig = true;
+    m_xTextRenderImpl->GetDevFontList(pFontCollection);
 }
 
 void SvpSalGraphics::ClearDevFontCache()
 {
-    GlyphCache& rGC = SvpGlyphCache::GetInstance();
-    rGC.ClearFontCache();
+    m_xTextRenderImpl->ClearDevFontCache();
 }
 
-bool SvpSalGraphics::AddTempDevFont( PhysicalFontCollection*,
-    const OUString&, const OUString& )
+bool SvpSalGraphics::AddTempDevFont( PhysicalFontCollection* pFontCollection,
+    const OUString& rFileURL, const OUString& rFontName)
 {
-    return false;
+    return m_xTextRenderImpl->AddTempDevFont(pFontCollection, rFileURL, rFontName);
 }
 
 bool SvpSalGraphics::CreateFontSubset(
@@ -300,36 +64,14 @@ bool SvpSalGraphics::CreateFontSubset(
     const sal_uInt8* pEncoding,
     sal_Int32* pWidths,
     int nGlyphCount,
-    FontSubsetInfo& rInfo
-    )
+    FontSubsetInfo& rInfo)
 {
-    // in this context the pFont->GetFontId() is a valid PSP
-    // font since they are the only ones left after the PDF
-    // export has filtered its list of subsettable fonts (for
-    // which this method was created). The correct way would
-    // be to have the GlyphCache search for the PhysicalFontFace pFont
-    psp::fontID aFont = pFont->GetFontId();
-
-    psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
-    bool bSuccess = rMgr.createFontSubset( rInfo,
-                                 aFont,
-                                 rToFile,
-                                 pGlyphIds,
-                                 pEncoding,
-                                 pWidths,
-                                 nGlyphCount );
-    return bSuccess;
+    return m_xTextRenderImpl->CreateFontSubset(rToFile, pFont, pGlyphIds, pEncoding, pWidths, nGlyphCount, rInfo);
 }
 
 const Ucs2SIntMap* SvpSalGraphics::GetFontEncodingVector( const PhysicalFontFace* pFont, const Ucs2OStrMap** pNonEncoded, std::set<sal_Unicode> const** ppPriority)
 {
-    // in this context the pFont->GetFontId() is a valid PSP
-    // font since they are the only ones left after the PDF
-    // export has filtered its list of subsettable fonts (for
-    // which this method was created). The correct way would
-    // be to have the GlyphCache search for the PhysicalFontFace pFont
-    psp::fontID aFont = pFont->GetFontId();
-    return GenPspGraphics::DoGetFontEncodingVector(aFont, pNonEncoded, ppPriority);
+    return m_xTextRenderImpl->GetFontEncodingVector(pFont, pNonEncoded, ppPriority);
 }
 
 const void* SvpSalGraphics::GetEmbedFontData(
@@ -338,21 +80,14 @@ const void* SvpSalGraphics::GetEmbedFontData(
     sal_Int32* pWidths,
     size_t nLen,
     FontSubsetInfo& rInfo,
-    long* pDataLen
-    )
+    long* pDataLen)
 {
-    // in this context the pFont->GetFontId() is a valid PSP
-    // font since they are the only ones left after the PDF
-    // export has filtered its list of subsettable fonts (for
-    // which this method was created). The correct way would
-    // be to have the GlyphCache search for the PhysicalFontFace pFont
-    psp::fontID aFont = pFont->GetFontId();
-    return GenPspGraphics::DoGetEmbedFontData( aFont, pUnicodes, pWidths, nLen, rInfo, pDataLen );
+    return m_xTextRenderImpl->GetEmbedFontData(pFont, pUnicodes, pWidths, nLen, rInfo, pDataLen);
 }
 
 void SvpSalGraphics::FreeEmbedFontData( const void* pData, long nLen )
 {
-    GenPspGraphics::DoFreeEmbedFontData( pData, nLen );
+    m_xTextRenderImpl->FreeEmbedFontData(pData, nLen);
 }
 
 void SvpSalGraphics::GetGlyphWidths( const PhysicalFontFace* pFont,
@@ -360,110 +95,51 @@ void SvpSalGraphics::GetGlyphWidths( const PhysicalFontFace* pFont,
                                    Int32Vector& rWidths,
                                    Ucs2UIntMap& rUnicodeEnc )
 {
-    // in this context the pFont->GetFontId() is a valid PSP
-    // font since they are the only ones left after the PDF
-    // export has filtered its list of subsettable fonts (for
-    // which this method was created). The correct way would
-    // be to have the GlyphCache search for the PhysicalFontFace pFont
-    psp::fontID aFont = pFont->GetFontId();
-    GenPspGraphics::DoGetGlyphWidths( aFont, bVertical, rWidths, rUnicodeEnc );
+    m_xTextRenderImpl->GetGlyphWidths(pFont, bVertical, rWidths, rUnicodeEnc);
 }
 
 bool SvpSalGraphics::GetGlyphBoundRect( sal_GlyphId aGlyphId, Rectangle& rRect )
 {
-    const int nLevel = aGlyphId >> GF_FONTSHIFT;
-    if( nLevel >= MAX_FALLBACK )
-        return false;
-
-    ServerFont* pSF = m_pServerFont[ nLevel ];
-    if( !pSF )
-        return false;
-
-    aGlyphId &= GF_IDXMASK;
-    const GlyphMetric& rGM = pSF->GetGlyphMetric( aGlyphId );
-    rRect = Rectangle( rGM.GetOffset(), rGM.GetSize() );
-    return true;
+    return m_xTextRenderImpl->GetGlyphBoundRect(aGlyphId, rRect);
 }
 
-bool SvpSalGraphics::GetGlyphOutline( sal_GlyphId aGlyphId, B2DPolyPolygon& rPolyPoly )
+bool SvpSalGraphics::GetGlyphOutline( sal_GlyphId aGlyphId, basegfx::B2DPolyPolygon& rPolyPoly )
 {
-    const int nLevel = aGlyphId >> GF_FONTSHIFT;
-    if( nLevel >= MAX_FALLBACK )
-        return false;
-
-    const ServerFont* pSF = m_pServerFont[ nLevel ];
-    if( !pSF )
-        return false;
-
-    aGlyphId &= GF_IDXMASK;
-    if( pSF->GetGlyphOutline( aGlyphId, rPolyPoly ) )
-        return true;
-
-    return false;
+    return m_xTextRenderImpl->GetGlyphOutline(aGlyphId, rPolyPoly);
 }
 
-SalLayout* SvpSalGraphics::GetTextLayout( ImplLayoutArgs&, int nFallbackLevel )
+SalLayout* SvpSalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel )
 {
-    GenericSalLayout* pLayout = NULL;
-
-    if( m_pServerFont[ nFallbackLevel ] )
-        pLayout = new ServerFontLayout( *m_pServerFont[ nFallbackLevel ] );
-
-    return pLayout;
+    return m_xTextRenderImpl->GetTextLayout(rArgs, nFallbackLevel);
 }
 
 void SvpSalGraphics::DrawServerFontLayout( const ServerFontLayout& rSalLayout )
 {
-    // iterate over all glyphs in the layout
-    Point aPos;
-    sal_GlyphId aGlyphId;
-    SvpGlyphPeer& rGlyphPeer = SvpGlyphCache::GetInstance().GetPeer();
-    for( int nStart = 0; rSalLayout.GetNextGlyphs( 1, &aGlyphId, aPos, nStart ); )
-    {
-        int nLevel = aGlyphId >> GF_FONTSHIFT;
-        DBG_ASSERT( nLevel < MAX_FALLBACK, "SvpGDI: invalid glyph fallback level" );
-        ServerFont* pSF = m_pServerFont[ nLevel ];
-        if( !pSF )
-            continue;
-
-        // get the glyph's alpha mask and adjust the drawing position
-        aGlyphId &= GF_IDXMASK;
-        B2IPoint aDstPoint( aPos.X(), aPos.Y() );
-        BitmapDeviceSharedPtr aAlphaMask
-            = rGlyphPeer.GetGlyphBmp( *pSF, aGlyphId, m_eTextFmt, aDstPoint );
-        if( !aAlphaMask )   // ignore empty glyphs
-            continue;
-
-        // blend text color into target using the glyph's mask
-        const B2IBox aSrcRect( B2ITuple(0,0), aAlphaMask->getSize() );
-        const B2IBox aClipRect( aDstPoint, aAlphaMask->getSize() );
-
-        SvpSalGraphics::ClipUndoHandle aUndo( this );
-        if( !isClippedSetup( aClipRect, aUndo ) )
-            m_aDevice->drawMaskedColor( m_aTextColor, aAlphaMask,
-                                        aSrcRect, aDstPoint, m_aClipMap );
-    }
+    m_xTextRenderImpl->DrawServerFontLayout(rSalLayout );
 }
 
 void SvpSalGraphics::SetTextColor( SalColor nSalColor )
 {
-    m_aTextColor = basebmp::Color( nSalColor );
+    m_xTextRenderImpl->SetTextColor(nSalColor);
 }
 
 SystemFontData SvpSalGraphics::GetSysFontData( int nFallbacklevel ) const
 {
-    SystemFontData aSysFontData;
+    return m_xTextRenderImpl->GetSysFontData(nFallbacklevel);
+}
 
-    if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1;
-    if (nFallbacklevel < 0 ) nFallbacklevel = 0;
+void SvpSalGraphics::BlendTextColor(const basebmp::Color &rTextColor, const basebmp::BitmapDeviceSharedPtr &rAlphaMask,
+                                    const basegfx::B2IPoint &rDstPoint)
+{
+    // blend text color into target using the glyph's mask
+    const basegfx::B2IBox aSrcRect(basegfx::B2ITuple(0,0), rAlphaMask->getSize());
+    const basegfx::B2IBox aClipRect(rDstPoint, rAlphaMask->getSize());
+
+    SvpSalGraphics::ClipUndoHandle aUndo(this);
+    if (isClippedSetup(aClipRect, aUndo))
+        return;
 
-    aSysFontData.nSize = sizeof( SystemFontData );
-    aSysFontData.nFontId = 0;
-    aSysFontData.nFontFlags = 0;
-    aSysFontData.bFakeBold = false;
-    aSysFontData.bFakeItalic = false;
-    aSysFontData.bAntialias = true;
-    return aSysFontData;
+    m_aDevice->drawMaskedColor(rTextColor, rAlphaMask, aSrcRect, rDstPoint, m_aClipMap);
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/headless/svptextrender.cxx b/vcl/headless/svptextrender.cxx
new file mode 100644
index 0000000..d28de18
--- /dev/null
+++ b/vcl/headless/svptextrender.cxx
@@ -0,0 +1,496 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/types.h>
+
+#include <cassert>
+
+#include <basebmp/scanlineformats.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/range/b2ibox.hxx>
+#include <rtl/instance.hxx>
+#include <tools/debug.hxx>
+#include <vcl/sysdata.hxx>
+
+#include "generic/geninst.h"
+#include "generic/genpspgraphics.h"
+#include "generic/glyphcache.hxx"
+#include "headless/svpbmp.hxx"
+#include "headless/svpgdi.hxx"
+#include "headless/svptextrender.hxx"
+#include "impfont.hxx"
+#include "outfont.hxx"
+#include "PhysicalFontFace.hxx"
+
+class PhysicalFontCollection;
+
+using namespace basegfx;
+using namespace basebmp;
+
+class SvpGlyphPeer : public GlyphCachePeer
+{
+public:
+    SvpGlyphPeer() {}
+
+    BitmapDeviceSharedPtr GetGlyphBmp( ServerFont&, sal_GlyphId,
+                                       basebmp::Format nBmpFormat, B2IPoint& rTargetPos );
+
+protected:
+    virtual void    RemovingFont( ServerFont& ) SAL_OVERRIDE;
+    virtual void    RemovingGlyph( GlyphData& ) SAL_OVERRIDE;
+
+    class SvpGcpHelper
+    {
+    public:
+        RawBitmap               maRawBitmap;
+        BitmapDeviceSharedPtr   maBitmapDev;
+    };
+};
+
+class SvpGlyphCache : public GlyphCache
+{
+public:
+    SvpGlyphCache( SvpGlyphPeer& rPeer ) : GlyphCache( rPeer) {}
+    SvpGlyphPeer& GetPeer() { return reinterpret_cast<SvpGlyphPeer&>( mrPeer ); }
+    static SvpGlyphCache& GetInstance();
+};
+
+namespace
+{
+    struct GlyphCacheHolder
+    {
+    private:
+        SvpGlyphPeer* m_pSvpGlyphPeer;
+        SvpGlyphCache* m_pSvpGlyphCache;
+    public:
+        GlyphCacheHolder()
+        {
+            m_pSvpGlyphPeer = new SvpGlyphPeer();
+            m_pSvpGlyphCache = new SvpGlyphCache( *m_pSvpGlyphPeer );
+        }
+        void release()
+        {
+            delete m_pSvpGlyphCache;
+            delete m_pSvpGlyphPeer;
+            m_pSvpGlyphCache = NULL;
+            m_pSvpGlyphPeer = NULL;
+        }
+        SvpGlyphCache& getGlyphCache()
+        {
+            return *m_pSvpGlyphCache;
+        }
+        ~GlyphCacheHolder()
+        {
+            release();
+        }
+    };
+
+    struct theGlyphCacheHolder :
+        public rtl::Static<GlyphCacheHolder, theGlyphCacheHolder>
+    {};
+}
+
+SvpGlyphCache& SvpGlyphCache::GetInstance()
+{
+    return theGlyphCacheHolder::get().getGlyphCache();
+}
+
+BitmapDeviceSharedPtr SvpGlyphPeer::GetGlyphBmp( ServerFont& rServerFont,
+    sal_GlyphId aGlyphId, basebmp::Format nBmpFormat, B2IPoint& rTargetPos )
+{
+    GlyphData& rGlyphData = rServerFont.GetGlyphData( aGlyphId );
+
+    if( rGlyphData.ExtDataRef().meInfo != nBmpFormat )
+    {
+        SvpGcpHelper* pGcpHelper = static_cast<SvpGcpHelper*>(
+            rGlyphData.ExtDataRef().mpData);
+        bool bNew = pGcpHelper == 0;
+        if( bNew )
+            pGcpHelper = new SvpGcpHelper;
+
+        // get glyph bitmap in matching format
+        bool bFound = false;
+        switch( nBmpFormat )
+        {
+            case FORMAT_ONE_BIT_LSB_GREY:
+                bFound = rServerFont.GetGlyphBitmap1( aGlyphId, pGcpHelper->maRawBitmap );
+                break;
+            case FORMAT_EIGHT_BIT_GREY:
+                bFound = rServerFont.GetGlyphBitmap8( aGlyphId, pGcpHelper->maRawBitmap );
+                break;
+            default:
+                OSL_FAIL( "SVP GCP::GetGlyphBmp(): illegal scanline format");
+                // fall back to black&white mask
+                nBmpFormat = FORMAT_ONE_BIT_LSB_GREY;
+                bFound = false;
+                break;
+        }
+
+        // return .notdef glyph if needed
+        if( !bFound && (aGlyphId != 0) )
+        {
+            if( bNew )
+                delete pGcpHelper;
+            return GetGlyphBmp( rServerFont, 0, nBmpFormat, rTargetPos );
+        }
+
+        // construct alpha mask from raw bitmap
+        if (pGcpHelper->maRawBitmap.mnScanlineSize && pGcpHelper->maRawBitmap.mnHeight)
+        {
+            const B2IVector aSize(
+                pGcpHelper->maRawBitmap.mnScanlineSize,
+                pGcpHelper->maRawBitmap.mnHeight );
+            static PaletteMemorySharedVector aDummyPAL;
+            pGcpHelper->maBitmapDev = createBitmapDevice( aSize, true, nBmpFormat, aSize.getX(), pGcpHelper->maRawBitmap.mpBits, aDummyPAL );
+        }
+
+        rGlyphData.ExtDataRef().meInfo = nBmpFormat;
+        rGlyphData.ExtDataRef().mpData = pGcpHelper;
+    }
+
+    SvpGcpHelper* pGcpHelper = static_cast<SvpGcpHelper*>(
+        rGlyphData.ExtDataRef().mpData);
+    assert(pGcpHelper != 0);
+    rTargetPos += B2IPoint( pGcpHelper->maRawBitmap.mnXOffset, pGcpHelper->maRawBitmap.mnYOffset );
+    return pGcpHelper->maBitmapDev;
+}
+
+void SvpGlyphPeer::RemovingFont( ServerFont& )
+{
+    // nothing to do: no font resources held in SvpGlyphPeer
+}
+
+void SvpGlyphPeer::RemovingGlyph( GlyphData& rGlyphData )
+{
+    SvpGcpHelper* pGcpHelper = static_cast<SvpGcpHelper*>(
+        rGlyphData.ExtDataRef().mpData);
+    rGlyphData.ExtDataRef().meInfo = basebmp::FORMAT_NONE;
+    rGlyphData.ExtDataRef().mpData = 0;
+    delete pGcpHelper;
+}
+
+SvpTextRender::SvpTextRender(SvpSalGraphics& rParent)
+    : m_rParent(rParent)
+    , m_aTextColor(COL_BLACK)
+    , m_eTextFmt(basebmp::FORMAT_EIGHT_BIT_GREY)
+{
+    for( int i = 0; i < MAX_FALLBACK; ++i )
+        m_pServerFont[i] = NULL;
+}
+
+sal_uInt16 SvpTextRender::SetFont( FontSelectPattern* pIFSD, int nFallbackLevel )
+{
+    // release all no longer needed font resources
+    for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
+    {
+        if( m_pServerFont[i] != NULL )
+        {
+            // old server side font is no longer referenced
+            SvpGlyphCache::GetInstance().UncacheFont( *m_pServerFont[i] );
+            m_pServerFont[i] = NULL;
+        }
+    }
+
+    // return early if there is no new font
+    if( !pIFSD )
+        return 0;
+
+    // handle the request for a non-native X11-font => use the GlyphCache
+    ServerFont* pServerFont = SvpGlyphCache::GetInstance().CacheFont( *pIFSD );
+    if( !pServerFont )
+        return SAL_SETFONT_BADFONT;
+
+    // check selected font
+    if( !pServerFont->TestFont() )
+    {
+        SvpGlyphCache::GetInstance().UncacheFont( *pServerFont );
+        return SAL_SETFONT_BADFONT;
+    }
+
+    // update SalGraphics font settings
+    m_pServerFont[ nFallbackLevel ] = pServerFont;
+    return SAL_SETFONT_USEDRAWTEXTARRAY;
+}
+
+void SvpTextRender::GetFontMetric( ImplFontMetricData* pMetric, int nFallbackLevel )
+{
+    if( nFallbackLevel >= MAX_FALLBACK )
+        return;
+
+    if( m_pServerFont[nFallbackLevel] != NULL )
+    {
+        long rDummyFactor;
+        m_pServerFont[nFallbackLevel]->FetchFontMetric( *pMetric, rDummyFactor );
+    }
+}
+
+const FontCharMapPtr SvpTextRender::GetFontCharMap() const
+{
+    if( !m_pServerFont[0] )
+        return NULL;
+
+    const FontCharMapPtr pFCMap = m_pServerFont[0]->GetFontCharMap();
+    return pFCMap;
+}
+
+bool SvpTextRender::GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
+{
+    if (!m_pServerFont[0])
+        return false;
+
+    return m_pServerFont[0]->GetFontCapabilities(rFontCapabilities);
+}
+
+void SvpTextRender::GetDevFontList( PhysicalFontCollection* pFontCollection )
+{
+    GlyphCache& rGC = SvpGlyphCache::GetInstance();
+
+    psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+    psp::FastPrintFontInfo aInfo;
+    ::std::list< psp::fontID > aList;
+    rMgr.getFontList( aList );
+    ::std::list< psp::fontID >::iterator it;
+    for( it = aList.begin(); it != aList.end(); ++it )
+    {
+        if( !rMgr.getFontFastInfo( *it, aInfo ) )
+            continue;
+
+        // normalize face number to the GlyphCache
+        int nFaceNum = rMgr.getFontFaceNumber( aInfo.m_nID );
+
+        // inform GlyphCache about this font provided by the PsPrint subsystem
+        ImplDevFontAttributes aDFA = GenPspGraphics::Info2DevFontAttributes( aInfo );
+        aDFA.mnQuality += 4096;
+        const OString& rFileName = rMgr.getFontFileSysPath( aInfo.m_nID );
+        rGC.AddFontFile( rFileName, nFaceNum, aInfo.m_nID, aDFA );
+   }
+
+    // announce glyphcache fonts
+    rGC.AnnounceFonts( pFontCollection );
+
+    // register platform specific font substitutions if available
+    SalGenericInstance::RegisterFontSubstitutors( pFontCollection );
+
+    ImplGetSVData()->maGDIData.mbNativeFontConfig = true;
+}
+
+void SvpTextRender::ClearDevFontCache()
+{
+    GlyphCache& rGC = SvpGlyphCache::GetInstance();
+    rGC.ClearFontCache();
+}
+
+bool SvpTextRender::AddTempDevFont( PhysicalFontCollection*,
+    const OUString&, const OUString& )
+{
+    return false;
+}
+
+bool SvpTextRender::CreateFontSubset(
+    const OUString& rToFile,
+    const PhysicalFontFace* pFont,
+    const sal_GlyphId* pGlyphIds,
+    const sal_uInt8* pEncoding,
+    sal_Int32* pWidths,
+    int nGlyphCount,
+    FontSubsetInfo& rInfo
+    )
+{
+    // in this context the pFont->GetFontId() is a valid PSP
+    // font since they are the only ones left after the PDF
+    // export has filtered its list of subsettable fonts (for
+    // which this method was created). The correct way would
+    // be to have the GlyphCache search for the PhysicalFontFace pFont
+    psp::fontID aFont = pFont->GetFontId();
+
+    psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+    bool bSuccess = rMgr.createFontSubset( rInfo,
+                                 aFont,
+                                 rToFile,
+                                 pGlyphIds,
+                                 pEncoding,
+                                 pWidths,
+                                 nGlyphCount );
+    return bSuccess;
+}
+
+const Ucs2SIntMap* SvpTextRender::GetFontEncodingVector( const PhysicalFontFace* pFont, const Ucs2OStrMap** pNonEncoded, std::set<sal_Unicode> const** ppPriority)
+{
+    // in this context the pFont->GetFontId() is a valid PSP
+    // font since they are the only ones left after the PDF
+    // export has filtered its list of subsettable fonts (for
+    // which this method was created). The correct way would
+    // be to have the GlyphCache search for the PhysicalFontFace pFont
+    psp::fontID aFont = pFont->GetFontId();
+    return GenPspGraphics::DoGetFontEncodingVector(aFont, pNonEncoded, ppPriority);
+}
+
+const void* SvpTextRender::GetEmbedFontData(
+    const PhysicalFontFace* pFont,
+    const sal_Ucs* pUnicodes,
+    sal_Int32* pWidths,
+    size_t nLen,
+    FontSubsetInfo& rInfo,
+    long* pDataLen
+    )
+{
+    // in this context the pFont->GetFontId() is a valid PSP
+    // font since they are the only ones left after the PDF
+    // export has filtered its list of subsettable fonts (for
+    // which this method was created). The correct way would
+    // be to have the GlyphCache search for the PhysicalFontFace pFont
+    psp::fontID aFont = pFont->GetFontId();
+    return GenPspGraphics::DoGetEmbedFontData( aFont, pUnicodes, pWidths, nLen, rInfo, pDataLen );
+}
+
+void SvpTextRender::FreeEmbedFontData( const void* pData, long nLen )
+{
+    GenPspGraphics::DoFreeEmbedFontData( pData, nLen );
+}
+
+void SvpTextRender::GetGlyphWidths( const PhysicalFontFace* pFont,
+                                   bool bVertical,
+                                   Int32Vector& rWidths,
+                                   Ucs2UIntMap& rUnicodeEnc )
+{
+    // in this context the pFont->GetFontId() is a valid PSP
+    // font since they are the only ones left after the PDF
+    // export has filtered its list of subsettable fonts (for
+    // which this method was created). The correct way would
+    // be to have the GlyphCache search for the PhysicalFontFace pFont
+    psp::fontID aFont = pFont->GetFontId();
+    GenPspGraphics::DoGetGlyphWidths( aFont, bVertical, rWidths, rUnicodeEnc );
+}
+
+bool SvpTextRender::GetGlyphBoundRect( sal_GlyphId aGlyphId, Rectangle& rRect )
+{
+    const int nLevel = aGlyphId >> GF_FONTSHIFT;
+    if( nLevel >= MAX_FALLBACK )
+        return false;
+
+    ServerFont* pSF = m_pServerFont[ nLevel ];
+    if( !pSF )
+        return false;
+
+    aGlyphId &= GF_IDXMASK;
+    const GlyphMetric& rGM = pSF->GetGlyphMetric( aGlyphId );
+    rRect = Rectangle( rGM.GetOffset(), rGM.GetSize() );
+    return true;
+}
+
+bool SvpTextRender::GetGlyphOutline( sal_GlyphId aGlyphId, B2DPolyPolygon& rPolyPoly )
+{
+    const int nLevel = aGlyphId >> GF_FONTSHIFT;
+    if( nLevel >= MAX_FALLBACK )
+        return false;
+
+    const ServerFont* pSF = m_pServerFont[ nLevel ];
+    if( !pSF )
+        return false;
+
+    aGlyphId &= GF_IDXMASK;
+    if( pSF->GetGlyphOutline( aGlyphId, rPolyPoly ) )
+        return true;
+
+    return false;
+}
+
+SalLayout* SvpTextRender::GetTextLayout( ImplLayoutArgs&, int nFallbackLevel )
+{
+    GenericSalLayout* pLayout = NULL;
+
+    if( m_pServerFont[ nFallbackLevel ] )
+        pLayout = new ServerFontLayout( *m_pServerFont[ nFallbackLevel ] );
+
+    return pLayout;
+}
+
+void SvpTextRender::DrawServerFontLayout( const ServerFontLayout& rSalLayout )
+{
+    // iterate over all glyphs in the layout
+    Point aPos;
+    sal_GlyphId aGlyphId;
+    SvpGlyphPeer& rGlyphPeer = SvpGlyphCache::GetInstance().GetPeer();
+    for( int nStart = 0; rSalLayout.GetNextGlyphs( 1, &aGlyphId, aPos, nStart ); )
+    {
+        int nLevel = aGlyphId >> GF_FONTSHIFT;
+        DBG_ASSERT( nLevel < MAX_FALLBACK, "SvpGDI: invalid glyph fallback level" );
+        ServerFont* pSF = m_pServerFont[ nLevel ];
+        if( !pSF )
+            continue;
+
+        // get the glyph's alpha mask and adjust the drawing position
+        aGlyphId &= GF_IDXMASK;
+        B2IPoint aDstPoint( aPos.X(), aPos.Y() );
+        BitmapDeviceSharedPtr aAlphaMask
+            = rGlyphPeer.GetGlyphBmp( *pSF, aGlyphId, m_eTextFmt, aDstPoint );
+        if( !aAlphaMask )   // ignore empty glyphs
+            continue;
+
+        // blend text color into target using the glyph's mask
+        m_rParent.BlendTextColor(m_aTextColor, aAlphaMask, aDstPoint);
+    }
+}
+
+void SvpTextRender::SetTextColor( SalColor nSalColor )
+{
+    m_aTextColor = basebmp::Color( nSalColor );
+}
+
+SystemFontData SvpTextRender::GetSysFontData( int nFallbacklevel ) const
+{
+    SystemFontData aSysFontData;
+
+    if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1;
+    if (nFallbacklevel < 0 ) nFallbacklevel = 0;
+
+    aSysFontData.nSize = sizeof( SystemFontData );
+    aSysFontData.nFontId = 0;
+    aSysFontData.nFontFlags = 0;
+    aSysFontData.bFakeBold = false;
+    aSysFontData.bFakeItalic = false;
+    aSysFontData.bAntialias = true;
+    return aSysFontData;
+}
+
+void SvpTextRender::setDevice( basebmp::BitmapDeviceSharedPtr& rDevice )
+{
+    // determine matching bitmap format for masks
+    basebmp::Format nDeviceFmt = rDevice ? rDevice->getScanlineFormat() : basebmp::FORMAT_EIGHT_BIT_GREY;
+    switch( nDeviceFmt )
+    {
+        case basebmp::FORMAT_EIGHT_BIT_GREY:
+        case basebmp::FORMAT_SIXTEEN_BIT_LSB_TC_MASK:
+        case basebmp::FORMAT_SIXTEEN_BIT_MSB_TC_MASK:
+        case basebmp::FORMAT_TWENTYFOUR_BIT_TC_MASK:
+        case basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_BGRX:
+        case basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_BGRA:
+        case basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_ARGB:
+        case basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_ABGR:
+        case basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_RGBA:
+            m_eTextFmt = basebmp::FORMAT_EIGHT_BIT_GREY;
+            break;
+        default:
+            m_eTextFmt = basebmp::FORMAT_ONE_BIT_LSB_GREY;
+            break;
+    }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/devicetextrender.hxx b/vcl/inc/devicetextrender.hxx
new file mode 100644
index 0000000..3880e88
--- /dev/null
+++ b/vcl/inc/devicetextrender.hxx
@@ -0,0 +1,24 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_VCL_INC_DEVICETEXTRENDER_HXX
+#define INCLUDED_VCL_INC_DEVICETEXTRENDER_HXX
+
+#include <basebmp/bitmapdevice.hxx>
+#include "textrender.hxx"
+
+class VCL_DLLPUBLIC DeviceTextRenderImpl : public TextRenderImpl
+{
+public:
+    virtual void setDevice(basebmp::BitmapDeviceSharedPtr& rDevice) = 0;
+};
+
+#endif
+
+/* vim:set tabstop=4 shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/headless/svpgdi.hxx b/vcl/inc/headless/svpgdi.hxx
index d429b80..b811a55 100644
--- a/vcl/inc/headless/svpgdi.hxx
+++ b/vcl/inc/headless/svpgdi.hxx
@@ -27,6 +27,7 @@
 
 #include "salgdi.hxx"
 #include "sallayout.hxx"
+#include "devicetextrender.hxx"
 
 #ifdef IOS
 #define SvpSalGraphics AquaSalGraphics
@@ -48,15 +49,14 @@ class SvpSalGraphics : public SalGraphics
 
     basebmp::DrawMode                    m_aDrawMode;
 
-    // These fields are used only when we use FreeType to draw into a
-    // headless backend, i.e. not on iOS.
-    basebmp::Color                       m_aTextColor;
-    ServerFont*                          m_pServerFont[ MAX_FALLBACK ];
-    basebmp::Format                      m_eTextFmt;
-
 protected:
     basegfx::B2IVector                   GetSize() { return m_aOrigDevice->getSize(); }
 
+public:
+    void setDevice(basebmp::BitmapDeviceSharedPtr& rDevice);
+    void BlendTextColor(const basebmp::Color &rTextColor, const basebmp::BitmapDeviceSharedPtr &rAlphaMask,
+                        const basegfx::B2IPoint &rDstPoint);
+
 private:
     bool                                 m_bClipSetup;
     struct ClipUndoHandle {
@@ -68,11 +68,9 @@ private:
     bool isClippedSetup( const basegfx::B2IBox &aRange, ClipUndoHandle &rUndo );
     void ensureClip();
 
-public:
-    void setDevice( basebmp::BitmapDeviceSharedPtr& rDevice );
-
 protected:
-    vcl::Region                               m_aClipRegion;
+    vcl::Region                           m_aClipRegion;
+    std::unique_ptr<DeviceTextRenderImpl> m_xTextRenderImpl;
 
 protected:
     virtual bool blendBitmap( const SalTwoRect&, const SalBitmap& rBitmap ) SAL_OVERRIDE;
diff --git a/vcl/inc/headless/svptextrender.hxx b/vcl/inc/headless/svptextrender.hxx
new file mode 100644
index 0000000..a4a9415
--- /dev/null
+++ b/vcl/inc/headless/svptextrender.hxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_VCL_INC_HEADLESS_SVPTEXTRENDER_HXX
+#define INCLUDED_VCL_INC_HEADLESS_SVPTEXTRENDER_HXX
+
+#include "devicetextrender.hxx"
+#include <vcl/region.hxx>
+#include <deque>
+
+class VCL_DLLPUBLIC SvpTextRender : public DeviceTextRenderImpl
+{
+private:
+    SvpSalGraphics& m_rParent;
+    // These fields are used only when we use FreeType to draw into a
+    // headless backend, i.e. not on iOS.
+    basebmp::Color              m_aTextColor;
+    basebmp::Format             m_eTextFmt;
+    ServerFont*                 m_pServerFont[ MAX_FALLBACK ];
+public:
+    SvpTextRender(SvpSalGraphics& rParent);
+    virtual void setDevice(basebmp::BitmapDeviceSharedPtr& rDevice) SAL_OVERRIDE;
+
+    virtual void                SetTextColor( SalColor nSalColor ) SAL_OVERRIDE;
+    virtual sal_uInt16          SetFont( FontSelectPattern*, int nFallbackLevel ) SAL_OVERRIDE;
+    virtual void                GetFontMetric( ImplFontMetricData*, int nFallbackLevel ) SAL_OVERRIDE;
+    virtual const FontCharMapPtr GetFontCharMap() const SAL_OVERRIDE;
+    virtual bool                GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const SAL_OVERRIDE;
+    virtual void                GetDevFontList( PhysicalFontCollection* ) SAL_OVERRIDE;
+    virtual void                ClearDevFontCache() SAL_OVERRIDE;
+    virtual bool                AddTempDevFont( PhysicalFontCollection*, const OUString& rFileURL, const OUString& rFontName ) SAL_OVERRIDE;
+    virtual bool                CreateFontSubset(
+                                    const OUString& rToFile,
+                                    const PhysicalFontFace*,
+                                    const sal_GlyphId* pGlyphIDs,
+                                    const sal_uInt8* pEncoding,
+                                    sal_Int32* pWidths,
+                                    int nGlyphs,
+                                    FontSubsetInfo& rInfo) SAL_OVERRIDE;
+
+    virtual const Ucs2SIntMap*  GetFontEncodingVector( const PhysicalFontFace*, const Ucs2OStrMap** ppNonEncoded, std::set<sal_Unicode> const**) SAL_OVERRIDE;
+    virtual const void*         GetEmbedFontData(
+                                    const PhysicalFontFace*,
+                                    const sal_Ucs* pUnicodes,
+                                    sal_Int32* pWidths,
+                                    size_t nLen,
+                                    FontSubsetInfo& rInfo,
+                                    long* pDataLen ) SAL_OVERRIDE;
+
+    virtual void                FreeEmbedFontData( const void* pData, long nDataLen ) SAL_OVERRIDE;
+    virtual void                GetGlyphWidths(
+                                    const PhysicalFontFace*,
+                                    bool bVertical,
+                                    Int32Vector& rWidths,
+                                    Ucs2UIntMap& rUnicodeEnc ) SAL_OVERRIDE;
+
+    virtual bool                GetGlyphBoundRect( sal_GlyphId nIndex, Rectangle& ) SAL_OVERRIDE;
+    virtual bool                GetGlyphOutline( sal_GlyphId nIndex, ::basegfx::B2DPolyPolygon& ) SAL_OVERRIDE;
+    virtual SalLayout*          GetTextLayout( ImplLayoutArgs&, int nFallbackLevel ) SAL_OVERRIDE;
+    virtual void                DrawServerFontLayout( const ServerFontLayout& ) SAL_OVERRIDE;
+    virtual SystemFontData      GetSysFontData( int nFallbackLevel ) const SAL_OVERRIDE;
+};
+
+#endif // INCLUDED_VCL_INC_HEADLESS_SVPTEXTRENDER_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list