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