diff options
Diffstat (limited to 'vcl/unx/generic/gdi/gcach_xpeer.cxx')
-rw-r--r-- | vcl/unx/generic/gdi/gcach_xpeer.cxx | 685 |
1 files changed, 685 insertions, 0 deletions
diff --git a/vcl/unx/generic/gdi/gcach_xpeer.cxx b/vcl/unx/generic/gdi/gcach_xpeer.cxx new file mode 100644 index 000000000000..9da147dbec9c --- /dev/null +++ b/vcl/unx/generic/gdi/gcach_xpeer.cxx @@ -0,0 +1,685 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include "rtl/ustring.hxx" +#include "osl/module.h" +#include "osl/thread.h" + +#include "unx/saldisp.hxx" +#include "unx/saldata.hxx" +#include "unx/salgdi.h" + +#include "gcach_xpeer.hxx" +#include "xrender_peer.hxx" + +// =========================================================================== + +// all glyph specific data needed by the XGlyphPeer is quite trivial +// with one exception: if multiple screens are involved and non-antialiased +// glyph rendering is active, then we need screen specific pixmaps +struct MultiScreenGlyph +{ + const RawBitmap* mpRawBitmap; + Glyph maXRGlyphId; + Pixmap maPixmaps[1]; // [mnMaxScreens] +}; + +// =========================================================================== + +X11GlyphPeer::X11GlyphPeer() +: mpDisplay( GetX11SalData()->GetDisplay()->GetDisplay() ) +, mnMaxScreens(0) +, mnDefaultScreen(0) +, mnExtByteCount(0) +, mnForcedAA(0) +, mnUsingXRender(0) +{ + maRawBitmap.mnAllocated = 0; + maRawBitmap.mpBits = NULL; + if( !mpDisplay ) + return; + + SalDisplay& rSalDisplay = *GetX11SalData()->GetDisplay(); + mpDisplay = rSalDisplay.GetDisplay(); + mnMaxScreens = rSalDisplay.GetScreenCount(); + if( mnMaxScreens > MAX_GCACH_SCREENS ) + mnMaxScreens = MAX_GCACH_SCREENS; + // if specific glyph data has to be kept for many screens + // then prepare the allocation of MultiScreenGlyph objects + if( mnMaxScreens > 1 ) + mnExtByteCount = sizeof(MultiScreenGlyph) + sizeof(Pixmap) * (mnMaxScreens - 1); + mnDefaultScreen = rSalDisplay.GetDefaultScreenNumber(); + + InitAntialiasing(); +} + +// --------------------------------------------------------------------------- + +X11GlyphPeer::~X11GlyphPeer() +{ + SalDisplay* pSalDisp = GetX11SalData()->GetDisplay(); + Display* const pX11Disp = pSalDisp->GetDisplay(); + XRenderPeer& rRenderPeer = XRenderPeer::GetInstance(); + for( int i = 0; i < mnMaxScreens; i++ ) + { + SalDisplay::RenderEntryMap& rMap = pSalDisp->GetRenderEntries( i ); + for( SalDisplay::RenderEntryMap::iterator it = rMap.begin(); it != rMap.end(); ++it ) + { + if( it->second.m_aPixmap ) + ::XFreePixmap( pX11Disp, it->second.m_aPixmap ); + if( it->second.m_aPicture ) + rRenderPeer.FreePicture( it->second.m_aPicture ); + } + rMap.clear(); + } +} + +// --------------------------------------------------------------------------- + +void X11GlyphPeer::InitAntialiasing() +{ + int nEnvAntiAlias = 0; + const char* pEnvAntiAlias = getenv( "SAL_ANTIALIAS_DISABLE" ); + if( pEnvAntiAlias ) + { + nEnvAntiAlias = atoi( pEnvAntiAlias ); + if( nEnvAntiAlias == 0 ) + return; + } + + mnUsingXRender = 0; + mnForcedAA = 0; + + // enable XRENDER accelerated aliasing on screens that support it + // unless it explicitly disabled by an environment variable + if( (nEnvAntiAlias & 2) == 0 ) + mnUsingXRender = XRenderPeer::GetInstance().InitRenderText(); + + // else enable client side antialiasing for these screens + // unless it is explicitly disabled by an environment variable + if( (nEnvAntiAlias & 1) != 0 ) + return; + + // enable client side antialiasing for screen visuals that are suitable + // mnForcedAA is a bitmask of screens enabled for client side antialiasing + mnForcedAA = (~(~0U << mnMaxScreens)) ^ mnUsingXRender; + SalDisplay& rSalDisplay = *GetX11SalData()->GetDisplay(); + for( int nScreen = 0; nScreen < mnMaxScreens; ++nScreen) + { + Visual* pVisual = rSalDisplay.GetVisual( nScreen ).GetVisual(); + XVisualInfo aXVisualInfo; + aXVisualInfo.visualid = pVisual->visualid; + int nVisuals = 0; + XVisualInfo* pXVisualInfo = XGetVisualInfo( mpDisplay, VisualIDMask, &aXVisualInfo, &nVisuals ); + for( int i = nVisuals; --i >= 0; ) + { + if( ((pXVisualInfo[i].c_class==PseudoColor) || (pXVisualInfo[i].depth<24)) + && ((pXVisualInfo[i].c_class>GrayScale) || (pXVisualInfo[i].depth!=8) ) ) + mnForcedAA &= ~(1U << nScreen); + } + if( pXVisualInfo != NULL ) + XFree( pXVisualInfo ); + } +} + +// =========================================================================== + +enum { INFO_EMPTY=0, INFO_PIXMAP, INFO_XRENDER, INFO_RAWBMP, INFO_MULTISCREEN }; +static const Glyph NO_GLYPHID = 0; +static RawBitmap* const NO_RAWBMP = NULL; +static const Pixmap NO_PIXMAP = ~0; + +// --------------------------------------------------------------------------- + +MultiScreenGlyph* X11GlyphPeer::PrepareForMultiscreen( ExtGlyphData& rEGD ) const +{ + // prepare to store screen specific pixmaps + MultiScreenGlyph* pMSGlyph = (MultiScreenGlyph*)new char[ mnExtByteCount ]; + + // init the glyph formats + pMSGlyph->mpRawBitmap = NO_RAWBMP; + pMSGlyph->maXRGlyphId = NO_GLYPHID; + for( int i = 0; i < mnMaxScreens; ++i ) + pMSGlyph->maPixmaps[i] = NO_PIXMAP; + // reuse already available glyph formats + if( rEGD.meInfo == INFO_XRENDER ) + pMSGlyph->maXRGlyphId = reinterpret_cast<Glyph>(rEGD.mpData); + else if( rEGD.meInfo == INFO_RAWBMP ) + pMSGlyph->mpRawBitmap = reinterpret_cast<RawBitmap*>(rEGD.mpData); + else if( rEGD.meInfo == INFO_PIXMAP ) + { + Pixmap aPixmap = reinterpret_cast<Pixmap>(rEGD.mpData); + if( aPixmap != None ) + // pixmap for the default screen is available + pMSGlyph->maPixmaps[ mnDefaultScreen ] = aPixmap; + else // empty pixmap for all screens is available + for( int i = 0; i < mnMaxScreens; ++i ) + pMSGlyph->maPixmaps[ i ] = None; + } + // enable use of multiscreen glyph + rEGD.mpData = (void*)pMSGlyph; + rEGD.meInfo = INFO_MULTISCREEN; + + return pMSGlyph; + } + +// --------------------------------------------------------------------------- + +Glyph X11GlyphPeer::GetRenderGlyph( const GlyphData& rGD ) const +{ + Glyph aGlyphId = NO_GLYPHID; + const ExtGlyphData& rEGD = rGD.ExtDataRef(); + if( rEGD.meInfo == INFO_XRENDER ) + aGlyphId = reinterpret_cast<Glyph>(rEGD.mpData); + else if( rEGD.meInfo == INFO_MULTISCREEN ) + aGlyphId = reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->maXRGlyphId; + return aGlyphId; +} + +// --------------------------------------------------------------------------- + +void X11GlyphPeer::SetRenderGlyph( GlyphData& rGD, Glyph aGlyphId ) const +{ + ExtGlyphData& rEGD = rGD.ExtDataRef(); + switch( rEGD.meInfo ) + { + case INFO_EMPTY: + rEGD.meInfo = INFO_XRENDER; + // fall through + case INFO_XRENDER: + rEGD.mpData = reinterpret_cast<void*>(aGlyphId); + break; + case INFO_PIXMAP: + case INFO_RAWBMP: + PrepareForMultiscreen( rEGD ); + // fall through + case INFO_MULTISCREEN: + reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->maXRGlyphId = aGlyphId; + break; + default: + break; // cannot happen... + } +} + +// --------------------------------------------------------------------------- + +const RawBitmap* X11GlyphPeer::GetRawBitmap( const GlyphData& rGD ) const +{ + const RawBitmap* pRawBitmap = NO_RAWBMP; + const ExtGlyphData& rEGD = rGD.ExtDataRef(); + if( rEGD.meInfo == INFO_RAWBMP ) + pRawBitmap = reinterpret_cast<RawBitmap*>(rEGD.mpData); + else if( rEGD.meInfo == INFO_MULTISCREEN ) + pRawBitmap = reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->mpRawBitmap; + return pRawBitmap; +} + +// --------------------------------------------------------------------------- + +void X11GlyphPeer::SetRawBitmap( GlyphData& rGD, const RawBitmap* pRawBitmap ) const +{ + ExtGlyphData& rEGD = rGD.ExtDataRef(); + switch( rEGD.meInfo ) + { + case INFO_EMPTY: + rEGD.meInfo = INFO_RAWBMP; + // fall through + case INFO_RAWBMP: + rEGD.mpData = (void*)pRawBitmap; + break; + case INFO_PIXMAP: + case INFO_XRENDER: + PrepareForMultiscreen( rEGD ); + // fall through + case INFO_MULTISCREEN: + reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->mpRawBitmap = pRawBitmap; + break; + default: + // cannot happen... + break; + } +} + +// --------------------------------------------------------------------------- + +Pixmap X11GlyphPeer::GetPixmap( const GlyphData& rGD, int nScreen ) const +{ + Pixmap aPixmap = NO_PIXMAP; + const ExtGlyphData& rEGD = rGD.ExtDataRef(); + if( (rEGD.meInfo == INFO_PIXMAP) && (nScreen == mnDefaultScreen) ) + aPixmap = (Pixmap)rEGD.mpData; + else if( rEGD.meInfo == INFO_MULTISCREEN ) + aPixmap = (Pixmap)(reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->maPixmaps[nScreen]); + return aPixmap; +} + +// --------------------------------------------------------------------------- + +void X11GlyphPeer::SetPixmap( GlyphData& rGD, Pixmap aPixmap, int nScreen ) const +{ + if( aPixmap == NO_PIXMAP ) + aPixmap = None; + + ExtGlyphData& rEGD = rGD.ExtDataRef(); + if( (rEGD.meInfo == INFO_EMPTY) && (nScreen == mnDefaultScreen) ) + { + rEGD.meInfo = INFO_PIXMAP; + rEGD.mpData = (void*)aPixmap; + } + else + { + MultiScreenGlyph* pMSGlyph; + if( rEGD.meInfo == INFO_MULTISCREEN ) + pMSGlyph = reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData); + else + pMSGlyph = PrepareForMultiscreen( rEGD ); + + pMSGlyph->maPixmaps[ nScreen ] = aPixmap; + } +} + +// --------------------------------------------------------------------------- + +void X11GlyphPeer::RemovingFont( ServerFont& rServerFont ) +{ + void* pFontExt = rServerFont.GetExtPointer(); + switch( rServerFont.GetExtInfo() ) + { + case INFO_PIXMAP: + case INFO_RAWBMP: + // nothing to do + break; + case INFO_MULTISCREEN: + // cannot happen... + break; + + case INFO_XRENDER: + XRenderPeer::GetInstance().FreeGlyphSet( (GlyphSet)pFontExt ); + break; + } + + rServerFont.SetExtended( INFO_EMPTY, NULL ); +} + +// --------------------------------------------------------------------------- + +// notification to clean up GlyphPeer resources for this glyph +void X11GlyphPeer::RemovingGlyph( ServerFont& /*rServerFont*/, GlyphData& rGlyphData, int /*nGlyphIndex*/ ) +{ + // nothing to do if the GlyphPeer hasn't allocated resources for the glyph + if( rGlyphData.ExtDataRef().meInfo == INFO_EMPTY ) + return; + + const GlyphMetric& rGM = rGlyphData.GetMetric(); + const int nWidth = rGM.GetSize().Width(); + const int nHeight = rGM.GetSize().Height(); + + void* pGlyphExt = rGlyphData.ExtDataRef().mpData; + switch( rGlyphData.ExtDataRef().meInfo ) + { + case INFO_PIXMAP: + { + Pixmap aPixmap = (Pixmap)pGlyphExt; + if( aPixmap != None ) + { + XFreePixmap( mpDisplay, aPixmap ); + mnBytesUsed -= nHeight * ((nWidth + 7) >> 3); + } + } + break; + + case INFO_MULTISCREEN: + { + MultiScreenGlyph* pMSGlyph = reinterpret_cast<MultiScreenGlyph*>(pGlyphExt); + for( int i = 0; i < mnMaxScreens; ++i) + { + if( pMSGlyph->maPixmaps[i] == NO_PIXMAP ) + continue; + if( pMSGlyph->maPixmaps[i] == None ) + continue; + XFreePixmap( mpDisplay, pMSGlyph->maPixmaps[i] ); + mnBytesUsed -= nHeight * ((nWidth + 7) >> 3); + } + delete pMSGlyph->mpRawBitmap; + // Glyph nGlyphId = (Glyph)rGlyphData.GetExtPointer(); + // XRenderPeer::GetInstance().FreeGlyph( aGlyphSet, &nGlyphId ); + delete[] pMSGlyph; // it was allocated with new char[] + } + break; + + case INFO_RAWBMP: + { + RawBitmap* pRawBitmap = (RawBitmap*)pGlyphExt; + if( pRawBitmap != NULL ) + { + mnBytesUsed -= pRawBitmap->mnScanlineSize * pRawBitmap->mnHeight; + mnBytesUsed -= sizeof(RawBitmap); + delete pRawBitmap; + } + } + break; + + case INFO_XRENDER: + { + // Glyph nGlyphId = (Glyph)rGlyphData.GetExtPointer(); + // XRenderPeer::GetInstance().FreeGlyph( aGlyphSet, &nGlyphId ); + mnBytesUsed -= nHeight * ((nWidth + 3) & ~3); + } + break; + } + + if( mnBytesUsed < 0 ) // TODO: eliminate nBytesUsed calc mismatch + mnBytesUsed = 0; + + rGlyphData.ExtDataRef() = ExtGlyphData(); +} + +// --------------------------------------------------------------------------- + +bool X11GlyphPeer::ForcedAntialiasing( const ServerFont& rServerFont, int nScreen ) const +{ + bool bForceOk = rServerFont.GetAntialiasAdvice(); + // maximum size for antialiasing is 250 pixels + bForceOk &= (rServerFont.GetFontSelData().mnHeight < 250); + return (bForceOk && ((mnForcedAA >> nScreen) & 1)); +} + +// --------------------------------------------------------------------------- + +GlyphSet X11GlyphPeer::GetGlyphSet( ServerFont& rServerFont, int nScreen ) +{ + if( (nScreen >= 0) && ((mnUsingXRender >> nScreen) & 1) == 0 ) + return 0; + + GlyphSet aGlyphSet; + + switch( rServerFont.GetExtInfo() ) + { + case INFO_XRENDER: + aGlyphSet = (GlyphSet)rServerFont.GetExtPointer(); + break; + + case INFO_EMPTY: + { + // antialiasing for reasonable font heights only + // => prevents crashes caused by X11 requests >= 256k + // => prefer readablity of hinted glyphs at small sizes + // => prefer "grey clouds" to "black clouds" at very small sizes + int nHeight = rServerFont.GetFontSelData().mnHeight; + if( nHeight<250 && rServerFont.GetAntialiasAdvice() ) + { + aGlyphSet = XRenderPeer::GetInstance().CreateGlyphSet(); + rServerFont.SetExtended( INFO_XRENDER, (void*)aGlyphSet ); + } + else + aGlyphSet = 0; + } + break; + + default: + aGlyphSet = 0; + break; + } + + return aGlyphSet; +} + +// --------------------------------------------------------------------------- + +Pixmap X11GlyphPeer::GetPixmap( ServerFont& rServerFont, int nGlyphIndex, int nReqScreen ) +{ + if( rServerFont.IsGlyphInvisible( nGlyphIndex ) ) + return None; + + GlyphData& rGlyphData = rServerFont.GetGlyphData( nGlyphIndex ); + Pixmap aPixmap = GetPixmap( rGlyphData, nReqScreen ); + if( aPixmap == NO_PIXMAP ) + { + aPixmap = None; + if( rServerFont.GetGlyphBitmap1( nGlyphIndex, maRawBitmap ) ) + { + // #94666# circumvent bug in some X11 systems, e.g. XF410.LynxEM.v163 + sal_uLong nPixmapWidth = 8 * maRawBitmap.mnScanlineSize - 1; + nPixmapWidth = Max( nPixmapWidth, maRawBitmap.mnWidth ); + + rGlyphData.SetSize( Size( nPixmapWidth, maRawBitmap.mnHeight ) ); + rGlyphData.SetOffset( +maRawBitmap.mnXOffset, +maRawBitmap.mnYOffset ); + + const sal_uLong nBytes = maRawBitmap.mnHeight * maRawBitmap.mnScanlineSize; + if( nBytes > 0 ) + { + // conversion table LSB<->MSB (for XCreatePixmapFromData) + static const unsigned char lsb2msb[256] = + { + 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, + 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, + 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, + 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, + 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, + 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, + 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, + 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, + 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, + 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, + 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, + 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, + 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, + 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, + 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, + 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, + 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, + 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, + 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, + 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, + 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, + 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, + 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, + 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, + 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, + 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, + 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, + 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, + 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, + 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, + 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, + 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF + }; + + unsigned char* pTemp = maRawBitmap.mpBits; + for( int i = nBytes; --i >= 0; ++pTemp ) + *pTemp = lsb2msb[ *pTemp ]; + + // often a glyph pixmap is only needed on the default screen + // => optimize for this common case + int nMinScreen = 0; + int nEndScreen = mnMaxScreens; + if( nReqScreen == mnDefaultScreen ) { + nMinScreen = mnDefaultScreen; + nEndScreen = mnDefaultScreen + 1; + } + // prepare glyph pixmaps for the different screens + for( int i = nMinScreen; i < nEndScreen; ++i ) + { + // don't bother if the pixmap is already there + if( GetPixmap( rGlyphData, i ) != NO_PIXMAP ) + continue; + // create the glyph pixmap + Pixmap aScreenPixmap = XCreatePixmapFromBitmapData( mpDisplay, + RootWindow( mpDisplay, i ), (char*)maRawBitmap.mpBits, + nPixmapWidth, maRawBitmap.mnHeight, 1, 0, 1 ); + // and cache it as glyph specific data + SetPixmap( rGlyphData, aScreenPixmap, i ); + mnBytesUsed += nBytes; + if( i == nReqScreen ) + aPixmap = aScreenPixmap; + } + } + } + else + { + // fall back to .notdef glyph + if( nGlyphIndex != 0 ) // recurse only once + aPixmap = GetPixmap( rServerFont, 0, nReqScreen ); + + if( aPixmap == NO_PIXMAP ) + aPixmap = None; + } + } + + return aPixmap; +} + +// --------------------------------------------------------------------------- + +const RawBitmap* X11GlyphPeer::GetRawBitmap( ServerFont& rServerFont, + int nGlyphIndex ) +{ + if( rServerFont.IsGlyphInvisible( nGlyphIndex ) ) + return NO_RAWBMP; + + GlyphData& rGlyphData = rServerFont.GetGlyphData( nGlyphIndex ); + + const RawBitmap* pRawBitmap = GetRawBitmap( rGlyphData ); + if( pRawBitmap == NO_RAWBMP ) + { + RawBitmap* pNewBitmap = new RawBitmap; + if( rServerFont.GetGlyphBitmap8( nGlyphIndex, *pNewBitmap ) ) + { + pRawBitmap = pNewBitmap; + mnBytesUsed += pNewBitmap->mnScanlineSize * pNewBitmap->mnHeight; + mnBytesUsed += sizeof(pNewBitmap); + } + else + { + delete pNewBitmap; + // fall back to .notdef glyph + if( nGlyphIndex != 0 ) // recurse only once + pRawBitmap = GetRawBitmap( rServerFont, 0 ); + } + + SetRawBitmap( rGlyphData, pRawBitmap ); + } + + return pRawBitmap; +} + +// --------------------------------------------------------------------------- + +Glyph X11GlyphPeer::GetGlyphId( ServerFont& rServerFont, int nGlyphIndex ) +{ + if( rServerFont.IsGlyphInvisible( nGlyphIndex ) ) + return NO_GLYPHID; + + GlyphData& rGlyphData = rServerFont.GetGlyphData( nGlyphIndex ); + + Glyph aGlyphId = GetRenderGlyph( rGlyphData ); + if( aGlyphId == NO_GLYPHID ) + { + // prepare GlyphInfo and Bitmap + if( rServerFont.GetGlyphBitmap8( nGlyphIndex, maRawBitmap ) ) + { + XGlyphInfo aGlyphInfo; + aGlyphInfo.width = maRawBitmap.mnWidth; + aGlyphInfo.height = maRawBitmap.mnHeight; + aGlyphInfo.x = -maRawBitmap.mnXOffset; + aGlyphInfo.y = -maRawBitmap.mnYOffset; + + rGlyphData.SetSize( Size( maRawBitmap.mnWidth, maRawBitmap.mnHeight ) ); + rGlyphData.SetOffset( +maRawBitmap.mnXOffset, +maRawBitmap.mnYOffset ); + + const GlyphMetric& rGM = rGlyphData.GetMetric(); + aGlyphInfo.xOff = +rGM.GetDelta().X(); + aGlyphInfo.yOff = +rGM.GetDelta().Y(); + + // upload glyph bitmap to server + GlyphSet aGlyphSet = GetGlyphSet( rServerFont, -1 ); + + aGlyphId = nGlyphIndex & 0x00FFFFFF; + const sal_uLong nBytes = maRawBitmap.mnScanlineSize * maRawBitmap.mnHeight; + XRenderPeer::GetInstance().AddGlyph( aGlyphSet, aGlyphId, + aGlyphInfo, (char*)maRawBitmap.mpBits, nBytes ); + mnBytesUsed += nBytes; + } + else + { + // fall back to .notdef glyph + if( nGlyphIndex != 0 ) // recurse only once + aGlyphId = GetGlyphId( rServerFont, 0 ); + } + + SetRenderGlyph( rGlyphData, aGlyphId ); + } + + return aGlyphId; +} + +// =========================================================================== + +X11GlyphCache::X11GlyphCache( X11GlyphPeer& rPeer ) +: GlyphCache( rPeer ) +{ +} + +// --------------------------------------------------------------------------- + +static X11GlyphPeer* pX11GlyphPeer = NULL; +static X11GlyphCache* pX11GlyphCache = NULL; + +X11GlyphCache& X11GlyphCache::GetInstance() +{ + if( !pX11GlyphCache ) + { + pX11GlyphPeer = new X11GlyphPeer(); + pX11GlyphCache = new X11GlyphCache( *pX11GlyphPeer ); + } + return *pX11GlyphCache; +} + +// --------------------------------------------------------------------------- + +void X11GlyphCache::KillInstance() +{ + delete pX11GlyphCache; + delete pX11GlyphPeer; + pX11GlyphCache = NULL; + pX11GlyphPeer = NULL; +} + +// =========================================================================== + +void X11SalGraphics::releaseGlyphPeer() +{ + X11GlyphCache::KillInstance(); +} + +// =========================================================================== + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |