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