/************************************************************** * * 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 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the 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(rEGD.mpData); else if( rEGD.meInfo == INFO_RAWBMP ) pMSGlyph->mpRawBitmap = reinterpret_cast(rEGD.mpData); else if( rEGD.meInfo == INFO_PIXMAP ) { Pixmap aPixmap = reinterpret_cast(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(rEGD.mpData); else if( rEGD.meInfo == INFO_MULTISCREEN ) aGlyphId = reinterpret_cast(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(aGlyphId); break; case INFO_PIXMAP: case INFO_RAWBMP: PrepareForMultiscreen( rEGD ); // fall through case INFO_MULTISCREEN: reinterpret_cast(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(rEGD.mpData); else if( rEGD.meInfo == INFO_MULTISCREEN ) pRawBitmap = reinterpret_cast(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(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(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(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, sal_GlyphId /*aGlyphId*/ ) { // 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(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; // XRenderGlyph nXRGlyph = (XRenderGlyph)rGlyphData.GetExtPointer(); // XRenderPeer::GetInstance().FreeGlyph( aGlyphSet, &nXRGlyph ); 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: { // XRenderGlyph nXRGlyph = (XRenderGlyph)rGlyphData.GetExtPointer(); // XRenderPeer::GetInstance().FreeGlyph( aGlyphSet, &nXRGlyph ); 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, sal_GlyphId aGlyphId, int nReqScreen ) { if( rServerFont.IsGlyphInvisible( aGlyphId ) ) return None; GlyphData& rGlyphData = rServerFont.GetGlyphData( aGlyphId ); Pixmap aPixmap = GetPixmap( rGlyphData, nReqScreen ); if( aPixmap == NO_PIXMAP ) { aPixmap = None; if( rServerFont.GetGlyphBitmap1( aGlyphId, 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( aGlyphId != 0 ) // recurse only once aPixmap = GetPixmap( rServerFont, 0, nReqScreen ); if( aPixmap == NO_PIXMAP ) aPixmap = None; } } return aPixmap; } // --------------------------------------------------------------------------- const RawBitmap* X11GlyphPeer::GetRawBitmap( ServerFont& rServerFont, sal_GlyphId aGlyphId ) { if( rServerFont.IsGlyphInvisible( aGlyphId ) ) return NO_RAWBMP; GlyphData& rGlyphData = rServerFont.GetGlyphData( aGlyphId ); const RawBitmap* pRawBitmap = GetRawBitmap( rGlyphData ); if( pRawBitmap == NO_RAWBMP ) { RawBitmap* pNewBitmap = new RawBitmap; if( rServerFont.GetGlyphBitmap8( aGlyphId, *pNewBitmap ) ) { pRawBitmap = pNewBitmap; mnBytesUsed += pNewBitmap->mnScanlineSize * pNewBitmap->mnHeight; mnBytesUsed += sizeof(pNewBitmap); } else { delete pNewBitmap; // fall back to .notdef glyph if( aGlyphId != 0 ) // recurse only once pRawBitmap = GetRawBitmap( rServerFont, 0 ); } SetRawBitmap( rGlyphData, pRawBitmap ); } return pRawBitmap; } // --------------------------------------------------------------------------- XRenderGlyph X11GlyphPeer::GetXRGlyph( ServerFont& rServerFont, sal_GlyphId aGlyphId ) { if( rServerFont.IsGlyphInvisible( aGlyphId ) ) return NO_GLYPHID; GlyphData& rGlyphData = rServerFont.GetGlyphData( aGlyphId ); XRenderGlyph nXRGlyph = GetRenderGlyph( rGlyphData ); if( nXRGlyph == NO_GLYPHID ) { // prepare GlyphInfo and Bitmap if( rServerFont.GetGlyphBitmap8( aGlyphId, 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 ); nXRGlyph = aGlyphId & 0x00FFFFFF; const sal_uLong nBytes = maRawBitmap.mnScanlineSize * maRawBitmap.mnHeight; XRenderPeer::GetInstance().AddGlyph( aGlyphSet, nXRGlyph, aGlyphInfo, (char*)maRawBitmap.mpBits, nBytes ); mnBytesUsed += nBytes; } else { // fall back to .notdef glyph if( nXRGlyph != 0 ) // recurse only once nXRGlyph = GetXRGlyph( rServerFont, 0 ); } SetRenderGlyph( rGlyphData, nXRGlyph ); } return nXRGlyph; } // =========================================================================== 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(); } // ===========================================================================