blob: f319a310c566ca0c1cb4d2e577eb210d2278dca0 [file] [log] [blame]
/**************************************************************
*
* 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<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, 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<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;
// 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();
}
// ===========================================================================