xref: /aoo42x/main/vcl/unx/generic/gdi/gcach_xpeer.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 
31 #include "rtl/ustring.hxx"
32 #include "osl/module.h"
33 #include "osl/thread.h"
34 
35 #include "unx/saldisp.hxx"
36 #include "unx/saldata.hxx"
37 #include "unx/salgdi.h"
38 
39 #include "gcach_xpeer.hxx"
40 #include "xrender_peer.hxx"
41 
42 // ===========================================================================
43 
44 // all glyph specific data needed by the XGlyphPeer is quite trivial
45 // with one exception: if multiple screens are involved and non-antialiased
46 // glyph rendering is active, then we need screen specific pixmaps
47 struct MultiScreenGlyph
48 {
49     const RawBitmap*    mpRawBitmap;
50     Glyph               maXRGlyphId;
51     Pixmap              maPixmaps[1];   // [mnMaxScreens]
52 };
53 
54 // ===========================================================================
55 
56 X11GlyphPeer::X11GlyphPeer()
57 :   mpDisplay( GetX11SalData()->GetDisplay()->GetDisplay() )
58 ,   mnMaxScreens(0)
59 ,   mnDefaultScreen(0)
60 ,   mnExtByteCount(0)
61 ,   mnForcedAA(0)
62 ,   mnUsingXRender(0)
63 {
64     maRawBitmap.mnAllocated = 0;
65     maRawBitmap.mpBits = NULL;
66     if( !mpDisplay )
67         return;
68 
69     SalDisplay& rSalDisplay = *GetX11SalData()->GetDisplay();
70     mpDisplay    = rSalDisplay.GetDisplay();
71     mnMaxScreens = rSalDisplay.GetScreenCount();
72     if( mnMaxScreens > MAX_GCACH_SCREENS )
73         mnMaxScreens = MAX_GCACH_SCREENS;
74     // if specific glyph data has to be kept for many screens
75     // then prepare the allocation of MultiScreenGlyph objects
76     if( mnMaxScreens > 1 )
77         mnExtByteCount = sizeof(MultiScreenGlyph) + sizeof(Pixmap) * (mnMaxScreens - 1);
78     mnDefaultScreen = rSalDisplay.GetDefaultScreenNumber();
79 
80     InitAntialiasing();
81 }
82 
83 // ---------------------------------------------------------------------------
84 
85 X11GlyphPeer::~X11GlyphPeer()
86 {
87     SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
88     Display* const pX11Disp = pSalDisp->GetDisplay();
89     XRenderPeer& rRenderPeer = XRenderPeer::GetInstance();
90     for( int i = 0; i < mnMaxScreens; i++ )
91     {
92         SalDisplay::RenderEntryMap& rMap = pSalDisp->GetRenderEntries( i );
93         for( SalDisplay::RenderEntryMap::iterator it = rMap.begin(); it != rMap.end(); ++it )
94         {
95             if( it->second.m_aPixmap )
96                 ::XFreePixmap( pX11Disp, it->second.m_aPixmap );
97             if( it->second.m_aPicture )
98                 rRenderPeer.FreePicture( it->second.m_aPicture );
99         }
100         rMap.clear();
101     }
102 }
103 
104 // ---------------------------------------------------------------------------
105 
106 void X11GlyphPeer::InitAntialiasing()
107 {
108     int nEnvAntiAlias = 0;
109     const char* pEnvAntiAlias = getenv( "SAL_ANTIALIAS_DISABLE" );
110     if( pEnvAntiAlias )
111     {
112         nEnvAntiAlias = atoi( pEnvAntiAlias );
113         if( nEnvAntiAlias == 0 )
114             return;
115     }
116 
117     mnUsingXRender = 0;
118     mnForcedAA = 0;
119 
120     // enable XRENDER accelerated aliasing on screens that support it
121     // unless it explicitly disabled by an environment variable
122     if( (nEnvAntiAlias & 2) == 0 )
123         mnUsingXRender = XRenderPeer::GetInstance().InitRenderText();
124 
125     // else enable client side antialiasing for these screens
126     // unless it is explicitly disabled by an environment variable
127     if( (nEnvAntiAlias & 1) != 0 )
128         return;
129 
130     // enable client side antialiasing for screen visuals that are suitable
131     // mnForcedAA is a bitmask of screens enabled for client side antialiasing
132     mnForcedAA = (~(~0U << mnMaxScreens)) ^ mnUsingXRender;
133     SalDisplay& rSalDisplay = *GetX11SalData()->GetDisplay();
134     for( int nScreen = 0; nScreen < mnMaxScreens; ++nScreen)
135     {
136         Visual* pVisual = rSalDisplay.GetVisual( nScreen ).GetVisual();
137         XVisualInfo aXVisualInfo;
138         aXVisualInfo.visualid = pVisual->visualid;
139         int nVisuals = 0;
140         XVisualInfo* pXVisualInfo = XGetVisualInfo( mpDisplay, VisualIDMask, &aXVisualInfo, &nVisuals );
141         for( int i = nVisuals; --i >= 0; )
142         {
143             if( ((pXVisualInfo[i].c_class==PseudoColor) || (pXVisualInfo[i].depth<24))
144             && ((pXVisualInfo[i].c_class>GrayScale) || (pXVisualInfo[i].depth!=8) ) )
145                 mnForcedAA &= ~(1U << nScreen);
146         }
147         if( pXVisualInfo != NULL )
148             XFree( pXVisualInfo );
149     }
150 }
151 
152 // ===========================================================================
153 
154 enum { INFO_EMPTY=0, INFO_PIXMAP, INFO_XRENDER, INFO_RAWBMP, INFO_MULTISCREEN };
155 static const Glyph NO_GLYPHID = 0;
156 static RawBitmap* const NO_RAWBMP = NULL;
157 static const Pixmap NO_PIXMAP = ~0;
158 
159 // ---------------------------------------------------------------------------
160 
161 MultiScreenGlyph* X11GlyphPeer::PrepareForMultiscreen( ExtGlyphData& rEGD ) const
162 {
163     // prepare to store screen specific pixmaps
164     MultiScreenGlyph* pMSGlyph = (MultiScreenGlyph*)new char[ mnExtByteCount ];
165 
166     // init the glyph formats
167     pMSGlyph->mpRawBitmap = NO_RAWBMP;
168     pMSGlyph->maXRGlyphId = NO_GLYPHID;
169     for( int i = 0; i < mnMaxScreens; ++i )
170         pMSGlyph->maPixmaps[i] = NO_PIXMAP;
171     // reuse already available glyph formats
172     if( rEGD.meInfo == INFO_XRENDER )
173         pMSGlyph->maXRGlyphId = reinterpret_cast<Glyph>(rEGD.mpData);
174     else if( rEGD.meInfo == INFO_RAWBMP )
175         pMSGlyph->mpRawBitmap = reinterpret_cast<RawBitmap*>(rEGD.mpData);
176     else if( rEGD.meInfo == INFO_PIXMAP )
177     {
178         Pixmap aPixmap = reinterpret_cast<Pixmap>(rEGD.mpData);
179         if( aPixmap != None )
180             // pixmap for the default screen is available
181             pMSGlyph->maPixmaps[ mnDefaultScreen ] = aPixmap;
182         else // empty pixmap for all screens is available
183             for( int i = 0; i < mnMaxScreens; ++i )
184                 pMSGlyph->maPixmaps[ i ] = None;
185     }
186     // enable use of multiscreen glyph
187     rEGD.mpData = (void*)pMSGlyph;
188     rEGD.meInfo = INFO_MULTISCREEN;
189 
190     return pMSGlyph;
191  }
192 
193 // ---------------------------------------------------------------------------
194 
195 Glyph X11GlyphPeer::GetRenderGlyph( const GlyphData& rGD ) const
196 {
197     Glyph aGlyphId = NO_GLYPHID;
198     const ExtGlyphData& rEGD = rGD.ExtDataRef();
199     if( rEGD.meInfo == INFO_XRENDER )
200         aGlyphId = reinterpret_cast<Glyph>(rEGD.mpData);
201     else if( rEGD.meInfo == INFO_MULTISCREEN )
202         aGlyphId = reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->maXRGlyphId;
203     return aGlyphId;
204 }
205 
206 // ---------------------------------------------------------------------------
207 
208 void X11GlyphPeer::SetRenderGlyph( GlyphData& rGD, Glyph aGlyphId ) const
209 {
210     ExtGlyphData& rEGD = rGD.ExtDataRef();
211     switch( rEGD.meInfo )
212     {
213         case INFO_EMPTY:
214             rEGD.meInfo = INFO_XRENDER;
215             // fall through
216         case INFO_XRENDER:
217             rEGD.mpData = reinterpret_cast<void*>(aGlyphId);
218             break;
219         case INFO_PIXMAP:
220         case INFO_RAWBMP:
221             PrepareForMultiscreen( rEGD );
222             // fall through
223         case INFO_MULTISCREEN:
224             reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->maXRGlyphId = aGlyphId;
225             break;
226         default:
227             break;  // cannot happen...
228     }
229 }
230 
231 // ---------------------------------------------------------------------------
232 
233 const RawBitmap* X11GlyphPeer::GetRawBitmap( const GlyphData& rGD ) const
234 {
235     const RawBitmap* pRawBitmap = NO_RAWBMP;
236     const ExtGlyphData& rEGD = rGD.ExtDataRef();
237     if( rEGD.meInfo == INFO_RAWBMP )
238         pRawBitmap = reinterpret_cast<RawBitmap*>(rEGD.mpData);
239     else if( rEGD.meInfo == INFO_MULTISCREEN )
240         pRawBitmap = reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->mpRawBitmap;
241     return pRawBitmap;
242 }
243 
244 // ---------------------------------------------------------------------------
245 
246 void X11GlyphPeer::SetRawBitmap( GlyphData& rGD, const RawBitmap* pRawBitmap ) const
247 {
248     ExtGlyphData& rEGD = rGD.ExtDataRef();
249     switch( rEGD.meInfo )
250     {
251         case INFO_EMPTY:
252             rEGD.meInfo = INFO_RAWBMP;
253             // fall through
254         case INFO_RAWBMP:
255             rEGD.mpData = (void*)pRawBitmap;
256             break;
257         case INFO_PIXMAP:
258         case INFO_XRENDER:
259             PrepareForMultiscreen( rEGD );
260             // fall through
261         case INFO_MULTISCREEN:
262             reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->mpRawBitmap = pRawBitmap;
263             break;
264         default:
265             // cannot happen...
266             break;
267     }
268 }
269 
270 // ---------------------------------------------------------------------------
271 
272 Pixmap X11GlyphPeer::GetPixmap( const GlyphData& rGD, int nScreen ) const
273 {
274     Pixmap aPixmap = NO_PIXMAP;
275     const ExtGlyphData& rEGD = rGD.ExtDataRef();
276     if( (rEGD.meInfo == INFO_PIXMAP) && (nScreen == mnDefaultScreen) )
277         aPixmap = (Pixmap)rEGD.mpData;
278     else if( rEGD.meInfo == INFO_MULTISCREEN )
279         aPixmap = (Pixmap)(reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->maPixmaps[nScreen]);
280     return aPixmap;
281 }
282 
283 // ---------------------------------------------------------------------------
284 
285 void X11GlyphPeer::SetPixmap( GlyphData& rGD, Pixmap aPixmap, int nScreen ) const
286 {
287     if( aPixmap == NO_PIXMAP )
288         aPixmap = None;
289 
290     ExtGlyphData& rEGD = rGD.ExtDataRef();
291     if( (rEGD.meInfo == INFO_EMPTY) && (nScreen == mnDefaultScreen) )
292     {
293         rEGD.meInfo = INFO_PIXMAP;
294         rEGD.mpData = (void*)aPixmap;
295     }
296     else
297     {
298         MultiScreenGlyph* pMSGlyph;
299         if( rEGD.meInfo == INFO_MULTISCREEN )
300             pMSGlyph = reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData);
301         else
302             pMSGlyph = PrepareForMultiscreen( rEGD );
303 
304         pMSGlyph->maPixmaps[ nScreen ] = aPixmap;
305     }
306 }
307 
308 // ---------------------------------------------------------------------------
309 
310 void X11GlyphPeer::RemovingFont( ServerFont& rServerFont )
311 {
312     void* pFontExt = rServerFont.GetExtPointer();
313     switch( rServerFont.GetExtInfo() )
314     {
315         case INFO_PIXMAP:
316         case INFO_RAWBMP:
317             // nothing to do
318             break;
319         case INFO_MULTISCREEN:
320             // cannot happen...
321             break;
322 
323         case INFO_XRENDER:
324             XRenderPeer::GetInstance().FreeGlyphSet( (GlyphSet)pFontExt );
325             break;
326     }
327 
328     rServerFont.SetExtended( INFO_EMPTY, NULL );
329 }
330 
331 // ---------------------------------------------------------------------------
332 
333 // notification to clean up GlyphPeer resources for this glyph
334 void X11GlyphPeer::RemovingGlyph( ServerFont& /*rServerFont*/, GlyphData& rGlyphData, int /*nGlyphIndex*/ )
335 {
336     // nothing to do if the GlyphPeer hasn't allocated resources for the glyph
337     if( rGlyphData.ExtDataRef().meInfo == INFO_EMPTY )
338         return;
339 
340     const GlyphMetric& rGM = rGlyphData.GetMetric();
341     const int nWidth  = rGM.GetSize().Width();
342     const int nHeight = rGM.GetSize().Height();
343 
344     void* pGlyphExt = rGlyphData.ExtDataRef().mpData;
345     switch( rGlyphData.ExtDataRef().meInfo )
346     {
347         case INFO_PIXMAP:
348             {
349                 Pixmap aPixmap = (Pixmap)pGlyphExt;
350                 if( aPixmap != None )
351                 {
352                     XFreePixmap( mpDisplay, aPixmap );
353                     mnBytesUsed -= nHeight * ((nWidth + 7) >> 3);
354                 }
355             }
356             break;
357 
358         case INFO_MULTISCREEN:
359             {
360                 MultiScreenGlyph* pMSGlyph = reinterpret_cast<MultiScreenGlyph*>(pGlyphExt);
361                 for( int i = 0; i < mnMaxScreens; ++i)
362                 {
363                     if( pMSGlyph->maPixmaps[i] == NO_PIXMAP )
364                         continue;
365                     if( pMSGlyph->maPixmaps[i] == None )
366                         continue;
367                     XFreePixmap( mpDisplay, pMSGlyph->maPixmaps[i] );
368                     mnBytesUsed -= nHeight * ((nWidth + 7) >> 3);
369                 }
370                 delete pMSGlyph->mpRawBitmap;
371                 // Glyph nGlyphId = (Glyph)rGlyphData.GetExtPointer();
372                 // XRenderPeer::GetInstance().FreeGlyph( aGlyphSet, &nGlyphId );
373                 delete[] pMSGlyph; // it was allocated with new char[]
374             }
375             break;
376 
377         case INFO_RAWBMP:
378             {
379                 RawBitmap* pRawBitmap = (RawBitmap*)pGlyphExt;
380                 if( pRawBitmap != NULL )
381                 {
382                     mnBytesUsed -= pRawBitmap->mnScanlineSize * pRawBitmap->mnHeight;
383                     mnBytesUsed -= sizeof(RawBitmap);
384                     delete pRawBitmap;
385                 }
386             }
387             break;
388 
389         case INFO_XRENDER:
390             {
391                 // Glyph nGlyphId = (Glyph)rGlyphData.GetExtPointer();
392                 // XRenderPeer::GetInstance().FreeGlyph( aGlyphSet, &nGlyphId );
393                 mnBytesUsed -= nHeight * ((nWidth + 3) & ~3);
394             }
395             break;
396     }
397 
398     if( mnBytesUsed < 0 )   // TODO: eliminate nBytesUsed calc mismatch
399         mnBytesUsed = 0;
400 
401     rGlyphData.ExtDataRef() = ExtGlyphData();
402 }
403 
404 // ---------------------------------------------------------------------------
405 
406 bool X11GlyphPeer::ForcedAntialiasing( const ServerFont& rServerFont, int nScreen ) const
407 {
408     bool bForceOk = rServerFont.GetAntialiasAdvice();
409     // maximum size for antialiasing is 250 pixels
410     bForceOk &= (rServerFont.GetFontSelData().mnHeight < 250);
411     return (bForceOk && ((mnForcedAA >> nScreen) & 1));
412 }
413 
414 // ---------------------------------------------------------------------------
415 
416 GlyphSet X11GlyphPeer::GetGlyphSet( ServerFont& rServerFont, int nScreen )
417 {
418     if( (nScreen >= 0) && ((mnUsingXRender >> nScreen) & 1) == 0 )
419         return 0;
420 
421     GlyphSet aGlyphSet;
422 
423     switch( rServerFont.GetExtInfo() )
424     {
425         case INFO_XRENDER:
426             aGlyphSet = (GlyphSet)rServerFont.GetExtPointer();
427             break;
428 
429         case INFO_EMPTY:
430             {
431                 // antialiasing for reasonable font heights only
432                 // => prevents crashes caused by X11 requests >= 256k
433                 // => prefer readablity of hinted glyphs at small sizes
434                 // => prefer "grey clouds" to "black clouds" at very small sizes
435                 int nHeight = rServerFont.GetFontSelData().mnHeight;
436                 if( nHeight<250 && rServerFont.GetAntialiasAdvice() )
437                 {
438                     aGlyphSet = XRenderPeer::GetInstance().CreateGlyphSet();
439                     rServerFont.SetExtended( INFO_XRENDER, (void*)aGlyphSet );
440                 }
441                 else
442                     aGlyphSet = 0;
443             }
444             break;
445 
446         default:
447             aGlyphSet = 0;
448             break;
449     }
450 
451     return aGlyphSet;
452 }
453 
454 // ---------------------------------------------------------------------------
455 
456 Pixmap X11GlyphPeer::GetPixmap( ServerFont& rServerFont, int nGlyphIndex, int nReqScreen )
457 {
458     if( rServerFont.IsGlyphInvisible( nGlyphIndex ) )
459         return None;
460 
461     GlyphData& rGlyphData = rServerFont.GetGlyphData( nGlyphIndex );
462     Pixmap aPixmap = GetPixmap( rGlyphData, nReqScreen );
463     if( aPixmap == NO_PIXMAP )
464     {
465         aPixmap = None;
466         if( rServerFont.GetGlyphBitmap1( nGlyphIndex, maRawBitmap ) )
467         {
468             // #94666# circumvent bug in some X11 systems, e.g. XF410.LynxEM.v163
469             sal_uLong nPixmapWidth = 8 * maRawBitmap.mnScanlineSize - 1;
470             nPixmapWidth = Max( nPixmapWidth, maRawBitmap.mnWidth );
471 
472             rGlyphData.SetSize( Size( nPixmapWidth, maRawBitmap.mnHeight ) );
473             rGlyphData.SetOffset( +maRawBitmap.mnXOffset, +maRawBitmap.mnYOffset );
474 
475             const sal_uLong nBytes = maRawBitmap.mnHeight * maRawBitmap.mnScanlineSize;
476             if( nBytes > 0 )
477             {
478                 // conversion table LSB<->MSB (for XCreatePixmapFromData)
479                 static const unsigned char lsb2msb[256] =
480                 {
481                     0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
482                     0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
483                     0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
484                     0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
485                     0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
486                     0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
487                     0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
488                     0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
489                     0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
490                     0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
491                     0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
492                     0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
493                     0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
494                     0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
495                     0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
496                     0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
497                     0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
498                     0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
499                     0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
500                     0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
501                     0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
502                     0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
503                     0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
504                     0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
505                     0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
506                     0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
507                     0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
508                     0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
509                     0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
510                     0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
511                     0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
512                     0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
513                 };
514 
515                 unsigned char* pTemp = maRawBitmap.mpBits;
516                 for( int i = nBytes; --i >= 0; ++pTemp )
517                     *pTemp = lsb2msb[ *pTemp ];
518 
519                 // often a glyph pixmap is only needed on the default screen
520                 // => optimize for this common case
521                 int nMinScreen = 0;
522                 int nEndScreen = mnMaxScreens;
523                 if( nReqScreen == mnDefaultScreen ) {
524                     nMinScreen = mnDefaultScreen;
525                     nEndScreen = mnDefaultScreen + 1;
526                 }
527                 // prepare glyph pixmaps for the different screens
528                 for( int i = nMinScreen; i < nEndScreen; ++i )
529                 {
530                     // don't bother if the pixmap is already there
531                     if( GetPixmap( rGlyphData, i ) != NO_PIXMAP )
532                         continue;
533                     // create the glyph pixmap
534                     Pixmap aScreenPixmap = XCreatePixmapFromBitmapData( mpDisplay,
535                         RootWindow( mpDisplay, i ), (char*)maRawBitmap.mpBits,
536                         nPixmapWidth, maRawBitmap.mnHeight, 1, 0, 1 );
537                     // and cache it as glyph specific data
538                     SetPixmap( rGlyphData, aScreenPixmap, i );
539                     mnBytesUsed += nBytes;
540                     if( i == nReqScreen )
541                         aPixmap = aScreenPixmap;
542                 }
543             }
544         }
545         else
546         {
547             // fall back to .notdef glyph
548             if( nGlyphIndex != 0 )  // recurse only once
549                 aPixmap = GetPixmap( rServerFont, 0, nReqScreen );
550 
551             if( aPixmap == NO_PIXMAP )
552                 aPixmap = None;
553         }
554     }
555 
556     return aPixmap;
557 }
558 
559 // ---------------------------------------------------------------------------
560 
561 const RawBitmap* X11GlyphPeer::GetRawBitmap( ServerFont& rServerFont,
562     int nGlyphIndex )
563 {
564     if( rServerFont.IsGlyphInvisible( nGlyphIndex ) )
565         return NO_RAWBMP;
566 
567     GlyphData& rGlyphData = rServerFont.GetGlyphData( nGlyphIndex );
568 
569     const RawBitmap* pRawBitmap = GetRawBitmap( rGlyphData );
570     if( pRawBitmap == NO_RAWBMP )
571     {
572         RawBitmap* pNewBitmap = new RawBitmap;
573         if( rServerFont.GetGlyphBitmap8( nGlyphIndex, *pNewBitmap ) )
574         {
575             pRawBitmap = pNewBitmap;
576             mnBytesUsed += pNewBitmap->mnScanlineSize * pNewBitmap->mnHeight;
577             mnBytesUsed += sizeof(pNewBitmap);
578         }
579         else
580         {
581             delete pNewBitmap;
582             // fall back to .notdef glyph
583             if( nGlyphIndex != 0 )  // recurse only once
584                 pRawBitmap = GetRawBitmap( rServerFont, 0 );
585         }
586 
587         SetRawBitmap( rGlyphData, pRawBitmap );
588     }
589 
590     return pRawBitmap;
591 }
592 
593 // ---------------------------------------------------------------------------
594 
595 Glyph X11GlyphPeer::GetGlyphId( ServerFont& rServerFont, int nGlyphIndex )
596 {
597     if( rServerFont.IsGlyphInvisible( nGlyphIndex ) )
598         return NO_GLYPHID;
599 
600     GlyphData& rGlyphData = rServerFont.GetGlyphData( nGlyphIndex );
601 
602     Glyph aGlyphId = GetRenderGlyph( rGlyphData );
603     if( aGlyphId == NO_GLYPHID )
604     {
605         // prepare GlyphInfo and Bitmap
606         if( rServerFont.GetGlyphBitmap8( nGlyphIndex, maRawBitmap ) )
607         {
608             XGlyphInfo aGlyphInfo;
609             aGlyphInfo.width    = maRawBitmap.mnWidth;
610             aGlyphInfo.height   = maRawBitmap.mnHeight;
611             aGlyphInfo.x        = -maRawBitmap.mnXOffset;
612             aGlyphInfo.y        = -maRawBitmap.mnYOffset;
613 
614             rGlyphData.SetSize( Size( maRawBitmap.mnWidth, maRawBitmap.mnHeight ) );
615             rGlyphData.SetOffset( +maRawBitmap.mnXOffset, +maRawBitmap.mnYOffset );
616 
617             const GlyphMetric& rGM = rGlyphData.GetMetric();
618             aGlyphInfo.xOff     = +rGM.GetDelta().X();
619             aGlyphInfo.yOff     = +rGM.GetDelta().Y();
620 
621             // upload glyph bitmap to server
622             GlyphSet aGlyphSet = GetGlyphSet( rServerFont, -1 );
623 
624             aGlyphId = nGlyphIndex & 0x00FFFFFF;
625             const sal_uLong nBytes = maRawBitmap.mnScanlineSize * maRawBitmap.mnHeight;
626             XRenderPeer::GetInstance().AddGlyph( aGlyphSet, aGlyphId,
627                 aGlyphInfo, (char*)maRawBitmap.mpBits, nBytes );
628             mnBytesUsed += nBytes;
629         }
630         else
631         {
632             // fall back to .notdef glyph
633             if( nGlyphIndex != 0 )  // recurse only once
634                 aGlyphId = GetGlyphId( rServerFont, 0 );
635         }
636 
637         SetRenderGlyph( rGlyphData, aGlyphId );
638     }
639 
640     return aGlyphId;
641 }
642 
643 // ===========================================================================
644 
645 X11GlyphCache::X11GlyphCache( X11GlyphPeer& rPeer )
646 :	GlyphCache( rPeer )
647 {
648 }
649 
650 // ---------------------------------------------------------------------------
651 
652 static X11GlyphPeer* pX11GlyphPeer = NULL;
653 static X11GlyphCache* pX11GlyphCache = NULL;
654 
655 X11GlyphCache& X11GlyphCache::GetInstance()
656 {
657     if( !pX11GlyphCache )
658     {
659         pX11GlyphPeer = new X11GlyphPeer();
660         pX11GlyphCache = new X11GlyphCache( *pX11GlyphPeer );
661     }
662     return *pX11GlyphCache;
663 }
664 
665 // ---------------------------------------------------------------------------
666 
667 void X11GlyphCache::KillInstance()
668 {
669     delete pX11GlyphCache;
670     delete pX11GlyphPeer;
671     pX11GlyphCache = NULL;
672     pX11GlyphPeer = NULL;
673 }
674 
675 // ===========================================================================
676 
677 void X11SalGraphics::releaseGlyphPeer()
678 {
679     X11GlyphCache::KillInstance();
680 }
681 
682 // ===========================================================================
683 
684