xref: /trunk/main/vcl/unx/generic/gdi/gcach_xpeer.cxx (revision 248a599f)
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 
X11GlyphPeer()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 
~X11GlyphPeer()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 
InitAntialiasing()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 
PrepareForMultiscreen(ExtGlyphData & rEGD) const157 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 
GetRenderGlyph(const GlyphData & rGD) const191 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 
SetRenderGlyph(GlyphData & rGD,Glyph aGlyphId) const204 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 
GetRawBitmap(const GlyphData & rGD) const229 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 
SetRawBitmap(GlyphData & rGD,const RawBitmap * pRawBitmap) const242 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 
GetPixmap(const GlyphData & rGD,int nScreen) const268 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 
SetPixmap(GlyphData & rGD,Pixmap aPixmap,int nScreen) const281 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 
RemovingFont(ServerFont & rServerFont)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
RemovingGlyph(ServerFont &,GlyphData & rGlyphData,sal_GlyphId)330 void X11GlyphPeer::RemovingGlyph( ServerFont& /*rServerFont*/, GlyphData& rGlyphData, sal_GlyphId /*aGlyphId*/ )
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                 // XRenderGlyph nXRGlyph = (XRenderGlyph)rGlyphData.GetExtPointer();
368                 // XRenderPeer::GetInstance().FreeGlyph( aGlyphSet, &nXRGlyph );
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                 // XRenderGlyph nXRGlyph = (XRenderGlyph)rGlyphData.GetExtPointer();
388                 // XRenderPeer::GetInstance().FreeGlyph( aGlyphSet, &nXRGlyph );
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 
ForcedAntialiasing(const ServerFont & rServerFont,int nScreen) const402 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 
GetGlyphSet(ServerFont & rServerFont,int nScreen)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 
GetPixmap(ServerFont & rServerFont,sal_GlyphId aGlyphId,int nReqScreen)452 Pixmap X11GlyphPeer::GetPixmap( ServerFont& rServerFont, sal_GlyphId aGlyphId, int nReqScreen )
453 {
454     if( rServerFont.IsGlyphInvisible( aGlyphId ) )
455         return None;
456 
457     GlyphData& rGlyphData = rServerFont.GetGlyphData( aGlyphId );
458     Pixmap aPixmap = GetPixmap( rGlyphData, nReqScreen );
459     if( aPixmap == NO_PIXMAP )
460     {
461         aPixmap = None;
462         if( rServerFont.GetGlyphBitmap1( aGlyphId, 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( aGlyphId != 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 
GetRawBitmap(ServerFont & rServerFont,sal_GlyphId aGlyphId)557 const RawBitmap* X11GlyphPeer::GetRawBitmap( ServerFont& rServerFont, sal_GlyphId aGlyphId )
558 {
559     if( rServerFont.IsGlyphInvisible( aGlyphId ) )
560         return NO_RAWBMP;
561 
562     GlyphData& rGlyphData = rServerFont.GetGlyphData( aGlyphId );
563 
564     const RawBitmap* pRawBitmap = GetRawBitmap( rGlyphData );
565     if( pRawBitmap == NO_RAWBMP )
566     {
567         RawBitmap* pNewBitmap = new RawBitmap;
568         if( rServerFont.GetGlyphBitmap8( aGlyphId, *pNewBitmap ) )
569         {
570             pRawBitmap = pNewBitmap;
571             mnBytesUsed += pNewBitmap->mnScanlineSize * pNewBitmap->mnHeight;
572             mnBytesUsed += sizeof(pNewBitmap);
573         }
574         else
575         {
576             delete pNewBitmap;
577             // fall back to .notdef glyph
578             if( aGlyphId != 0 )  // recurse only once
579                 pRawBitmap = GetRawBitmap( rServerFont, 0 );
580         }
581 
582         SetRawBitmap( rGlyphData, pRawBitmap );
583     }
584 
585     return pRawBitmap;
586 }
587 
588 // ---------------------------------------------------------------------------
589 
GetXRGlyph(ServerFont & rServerFont,sal_GlyphId aGlyphId)590 XRenderGlyph X11GlyphPeer::GetXRGlyph( ServerFont& rServerFont, sal_GlyphId aGlyphId )
591 {
592     if( rServerFont.IsGlyphInvisible( aGlyphId ) )
593         return NO_GLYPHID;
594 
595     GlyphData& rGlyphData = rServerFont.GetGlyphData( aGlyphId );
596 
597     XRenderGlyph nXRGlyph = GetRenderGlyph( rGlyphData );
598     if( nXRGlyph == NO_GLYPHID )
599     {
600         // prepare GlyphInfo and Bitmap
601         if( rServerFont.GetGlyphBitmap8( aGlyphId, maRawBitmap ) )
602         {
603             XGlyphInfo aGlyphInfo;
604             aGlyphInfo.width    = maRawBitmap.mnWidth;
605             aGlyphInfo.height   = maRawBitmap.mnHeight;
606             aGlyphInfo.x        = -maRawBitmap.mnXOffset;
607             aGlyphInfo.y        = -maRawBitmap.mnYOffset;
608 
609             rGlyphData.SetSize( Size( maRawBitmap.mnWidth, maRawBitmap.mnHeight ) );
610             rGlyphData.SetOffset( +maRawBitmap.mnXOffset, +maRawBitmap.mnYOffset );
611 
612             const GlyphMetric& rGM = rGlyphData.GetMetric();
613             aGlyphInfo.xOff     = +rGM.GetDelta().X();
614             aGlyphInfo.yOff     = +rGM.GetDelta().Y();
615 
616             // upload glyph bitmap to server
617             GlyphSet aGlyphSet = GetGlyphSet( rServerFont, -1 );
618 
619             nXRGlyph = aGlyphId & 0x00FFFFFF;
620             const sal_uLong nBytes = maRawBitmap.mnScanlineSize * maRawBitmap.mnHeight;
621             XRenderPeer::GetInstance().AddGlyph( aGlyphSet, nXRGlyph,
622                 aGlyphInfo, (char*)maRawBitmap.mpBits, nBytes );
623             mnBytesUsed += nBytes;
624         }
625         else
626         {
627             // fall back to .notdef glyph
628             if( nXRGlyph != 0 )  // recurse only once
629                 nXRGlyph = GetXRGlyph( rServerFont, 0 );
630         }
631 
632         SetRenderGlyph( rGlyphData, nXRGlyph );
633     }
634 
635     return nXRGlyph;
636 }
637 
638 // ===========================================================================
639 
X11GlyphCache(X11GlyphPeer & rPeer)640 X11GlyphCache::X11GlyphCache( X11GlyphPeer& rPeer )
641 :	GlyphCache( rPeer )
642 {
643 }
644 
645 // ---------------------------------------------------------------------------
646 
647 static X11GlyphPeer* pX11GlyphPeer = NULL;
648 static X11GlyphCache* pX11GlyphCache = NULL;
649 
GetInstance()650 X11GlyphCache& X11GlyphCache::GetInstance()
651 {
652     if( !pX11GlyphCache )
653     {
654         pX11GlyphPeer = new X11GlyphPeer();
655         pX11GlyphCache = new X11GlyphCache( *pX11GlyphPeer );
656     }
657     return *pX11GlyphCache;
658 }
659 
660 // ---------------------------------------------------------------------------
661 
KillInstance()662 void X11GlyphCache::KillInstance()
663 {
664     delete pX11GlyphCache;
665     delete pX11GlyphPeer;
666     pX11GlyphCache = NULL;
667     pX11GlyphPeer = NULL;
668 }
669 
670 // ===========================================================================
671 
releaseGlyphPeer()672 void X11SalGraphics::releaseGlyphPeer()
673 {
674     X11GlyphCache::KillInstance();
675 }
676 
677 // ===========================================================================
678 
679