xref: /aoo41x/main/vcl/unx/generic/gdi/salgdi3.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 <string.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <math.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <sys/mman.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36 
37 #include "sal/alloca.h"
38 #include "sal/types.h"
39 
40 #include "rtl/tencinfo.h"
41 
42 #include "osl/file.hxx"
43 
44 #include "tools/string.hxx"
45 #include "tools/debug.hxx"
46 #include "tools/stream.hxx"
47 
48 #include "basegfx/polygon/b2dpolypolygon.hxx"
49 
50 #include "i18npool/mslangid.hxx"
51 
52 #include <vcl/sysdata.hxx>
53 #include "printergfx.hxx"
54 #include "vcl/fontmanager.hxx"
55 #include "vcl/jobdata.hxx"
56 #include "vcl/printerinfomanager.hxx"
57 #include "vcl/svapp.hxx"
58 
59 #include "unx/salunx.h"
60 #include "unx/saldata.hxx"
61 #include "unx/saldisp.hxx"
62 #include "unx/salgdi.h"
63 #include "unx/pspgraphics.h"
64 #include "unx/salvd.h"
65 
66 #include "salcvt.hxx"
67 #include "gcach_xpeer.hxx"
68 #include "xrender_peer.hxx"
69 #include "impfont.hxx"
70 #include "salframe.hxx"
71 #include "outdev.h"
72 
73 
74 #include <hash_set>
75 
76 #ifdef ENABLE_GRAPHITE
77 #include <graphite_layout.hxx>
78 #include <graphite_serverfont.hxx>
79 #endif
80 
81 struct cairo_surface_t;
82 struct cairo_t;
83 struct cairo_font_face_t;
84 typedef void* FT_Face;
85 struct cairo_matrix_t {
86     double xx; double yx;
87     double xy; double yy;
88     double x0; double y0;
89 };
90 struct cairo_glyph_t
91 {
92     unsigned long index;
93     double x;
94     double y;
95 };
96 struct BOX
97 {
98     short x1, x2, y1, y2;
99 };
100 struct _XRegion
101 {
102     long size;
103     long numRects;
104     BOX *rects;
105     BOX extents;
106 };
107 using namespace rtl;
108 
109 // ===========================================================================
110 
111 // PspKernInfo allows on-demand-querying of psprint provided kerning info (#i29881#)
112 class PspKernInfo : public ExtraKernInfo
113 {
114 public:
115     PspKernInfo( int nFontId ) : ExtraKernInfo(nFontId) {}
116 protected:
117     virtual void Initialize() const;
118 };
119 
120 //--------------------------------------------------------------------------
121 
122 void PspKernInfo::Initialize() const
123 {
124     mbInitialized = true;
125 
126     // get the kerning pairs from psprint
127     const psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
128     typedef std::list< psp::KernPair > PspKernPairs;
129     const PspKernPairs& rKernPairs = rMgr.getKernPairs( mnFontId );
130     if( rKernPairs.empty() )
131         return;
132 
133     // feed psprint's kerning list into a lookup-friendly container
134     maUnicodeKernPairs.resize( rKernPairs.size() );
135     PspKernPairs::const_iterator it = rKernPairs.begin();
136     for(; it != rKernPairs.end(); ++it )
137     {
138         ImplKernPairData aKernPair = { it->first, it->second, it->kern_x };
139         maUnicodeKernPairs.insert( aKernPair );
140     }
141 }
142 
143 // ----------------------------------------------------------------------------
144 //
145 // X11SalGraphics
146 //
147 // ----------------------------------------------------------------------------
148 
149 GC
150 X11SalGraphics::GetFontGC()
151 {
152 	Display *pDisplay = GetXDisplay();
153 
154 	if( !pFontGC_ )
155 	{
156 		XGCValues values;
157 		values.subwindow_mode		= ClipByChildren;
158 		values.fill_rule			= EvenOddRule;		// Pict import/ Gradient
159 		values.graphics_exposures	= False;
160 		values.foreground			= nTextPixel_;
161         pFontGC_ = XCreateGC( pDisplay, hDrawable_,
162                               GCSubwindowMode | GCFillRule
163                               | GCGraphicsExposures | GCForeground,
164                               &values );
165 	}
166 	if( !bFontGC_ )
167 	{
168 		XSetForeground( pDisplay, pFontGC_, nTextPixel_ );
169 		SetClipRegion( pFontGC_ );
170 		bFontGC_ = sal_True;
171 	}
172 
173 	return pFontGC_;
174 }
175 
176 //--------------------------------------------------------------------------
177 
178 bool X11SalGraphics::setFont( const ImplFontSelectData *pEntry, int nFallbackLevel )
179 {
180 #ifdef HDU_DEBUG
181     ByteString aReqName( "NULL" );
182     if( pEntry )
183         aReqName = ByteString( pEntry->maName, RTL_TEXTENCODING_UTF8 );
184     ByteString aUseName( "NULL" );
185     if( pEntry && pEntry->mpFontData )
186         aUseName = ByteString( pEntry->mpFontData->GetFamilyName(), RTL_TEXTENCODING_UTF8 );
187     fprintf( stderr, "SetFont(lvl=%d,\"%s\", %d*%d, naa=%d,b=%d,i=%d) => \"%s\"\n",
188         nFallbackLevel, aReqName.GetBuffer(),
189 	!pEntry?-1:pEntry->mnWidth, !pEntry?-1:pEntry->mnHeight,
190         !pEntry?-1:pEntry->mbNonAntialiased,
191 	!pEntry?-1:pEntry->meWeight, !pEntry?-1:pEntry->meItalic,
192         aUseName.GetBuffer() );
193 #endif
194 
195     // release all no longer needed font resources
196     for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
197     {
198         if( mpServerFont[i] != NULL )
199         {
200             // old server side font is no longer referenced
201             GlyphCache::GetInstance().UncacheFont( *mpServerFont[i] );
202             mpServerFont[i] = NULL;
203         }
204     }
205 
206     // return early if there is no new font
207     if( !pEntry )
208 	return false;
209 
210     bFontVertical_ = pEntry->mbVertical;
211 
212     // return early if this is not a valid font for this graphics
213     if( !pEntry->mpFontData )
214         return false;
215 
216     // handle the request for a non-native X11-font => use the GlyphCache
217     ServerFont* pServerFont = GlyphCache::GetInstance().CacheFont( *pEntry );
218     if( pServerFont != NULL )
219     {
220         // ignore fonts with e.g. corrupted font files
221         if( !pServerFont->TestFont() )
222         {
223             GlyphCache::GetInstance().UncacheFont( *pServerFont );
224             return false;
225         }
226 
227         // register to use the font
228         mpServerFont[ nFallbackLevel ] = pServerFont;
229 
230         // apply font specific-hint settings if needed
231         // TODO: also disable it for reference devices
232 	if( !bPrinter_ )
233 	{
234 	    ImplServerFontEntry* pSFE = static_cast<ImplServerFontEntry*>( pEntry->mpFontEntry );
235 	    pSFE->HandleFontOptions();
236         }
237 
238         return true;
239     }
240 
241     return false;
242 }
243 
244 void ImplServerFontEntry::HandleFontOptions( void )
245 {
246 	bool GetFCFontOptions( const ImplFontAttributes&, int nSize, ImplFontOptions& );
247 
248 	if( !mpServerFont )
249 		return;
250 	if( !mbGotFontOptions )
251 	{
252 		// get and cache the font options
253 		mbGotFontOptions = true;
254 		mbValidFontOptions = GetFCFontOptions( *maFontSelData.mpFontData,
255 			maFontSelData.mnHeight, maFontOptions );
256 	}
257 	// apply the font options
258 	if( mbValidFontOptions )
259 		mpServerFont->SetFontOptions( maFontOptions );
260 }
261 
262 //--------------------------------------------------------------------------
263 
264 namespace {
265 
266 class CairoWrapper
267 {
268 private:
269     oslModule mpCairoLib;
270 
271     cairo_surface_t* (*mp_xlib_surface_create_with_xrender_format)(Display *, Drawable , Screen *, XRenderPictFormat *, int , int );
272     void (*mp_surface_destroy)(cairo_surface_t *);
273     cairo_t* (*mp_create)(cairo_surface_t *);
274     void (*mp_destroy)(cairo_t*);
275     void (*mp_clip)(cairo_t*);
276     void (*mp_rectangle)(cairo_t*, double, double, double, double);
277     cairo_font_face_t * (*mp_ft_font_face_create_for_ft_face)(FT_Face, int);
278     void (*mp_set_font_face)(cairo_t *, cairo_font_face_t *);
279     void (*mp_font_face_destroy)(cairo_font_face_t *);
280     void (*mp_matrix_init_identity)(cairo_matrix_t *);
281     void (*mp_matrix_scale)(cairo_matrix_t *, double, double);
282     void (*mp_matrix_rotate)(cairo_matrix_t *, double);
283     void (*mp_set_font_matrix)(cairo_t *, const cairo_matrix_t *);
284     void (*mp_show_glyphs)(cairo_t *, const cairo_glyph_t *, int );
285     void (*mp_set_source_rgb)(cairo_t *, double , double , double );
286     void (*mp_set_font_options)(cairo_t *, const void *);
287     void (*mp_ft_font_options_substitute)(const void*, void*);
288 
289     bool canEmbolden() const { return false; }
290 
291     CairoWrapper();
292 public:
293     static CairoWrapper& get();
294     bool isValid() const { return (mpCairoLib != NULL); }
295     bool isCairoRenderable(const ServerFont& rFont);
296 
297     cairo_surface_t* xlib_surface_create_with_xrender_format(Display *pDisplay, Drawable drawable, Screen *pScreen, XRenderPictFormat *pFormat, int width, int height)
298         { return (*mp_xlib_surface_create_with_xrender_format)(pDisplay, drawable, pScreen, pFormat, width, height); }
299     void surface_destroy(cairo_surface_t *surface) { (*mp_surface_destroy)(surface); }
300     cairo_t* create(cairo_surface_t *surface) { return (*mp_create)(surface); }
301     void destroy(cairo_t *cr) { (*mp_destroy)(cr); }
302     void clip(cairo_t *cr) { (*mp_clip)(cr); }
303     void rectangle(cairo_t *cr, double x, double y, double width, double height)
304         { (*mp_rectangle)(cr, x, y, width, height); }
305     cairo_font_face_t* ft_font_face_create_for_ft_face(FT_Face face, int load_flags)
306         { return (*mp_ft_font_face_create_for_ft_face)(face, load_flags); }
307     void set_font_face(cairo_t *cr, cairo_font_face_t *font_face)
308         { (*mp_set_font_face)(cr, font_face); }
309     void font_face_destroy(cairo_font_face_t *font_face)
310         { (*mp_font_face_destroy)(font_face); }
311     void matrix_init_identity(cairo_matrix_t *matrix)
312         { (*mp_matrix_init_identity)(matrix); }
313     void matrix_scale(cairo_matrix_t *matrix, double sx, double sy)
314         { (*mp_matrix_scale)(matrix, sx, sy); }
315     void matrix_rotate(cairo_matrix_t *matrix, double radians)
316         { (*mp_matrix_rotate)(matrix, radians); }
317     void set_font_matrix(cairo_t *cr, const cairo_matrix_t *matrix)
318         { (*mp_set_font_matrix)(cr, matrix); }
319     void show_glyphs(cairo_t *cr, const cairo_glyph_t *glyphs, int no_glyphs)
320         { (*mp_show_glyphs)(cr, glyphs, no_glyphs); }
321     void set_source_rgb(cairo_t *cr, double red, double green, double blue)
322         { (*mp_set_source_rgb)(cr, red, green, blue); }
323     void set_font_options(cairo_t *cr, const void *options)
324         { (*mp_set_font_options)(cr, options); }
325     void ft_font_options_substitute(const void *options, void *pattern)
326         { (*mp_ft_font_options_substitute)(options, pattern); }
327 };
328 
329 static CairoWrapper* pCairoInstance = NULL;
330 
331 CairoWrapper& CairoWrapper::get()
332 {
333     if( ! pCairoInstance )
334         pCairoInstance = new CairoWrapper();
335     return *pCairoInstance;
336 }
337 
338 CairoWrapper::CairoWrapper()
339 :   mpCairoLib( NULL )
340 {
341     static const char* pDisableCairoText = getenv( "SAL_DISABLE_CAIROTEXT" );
342     if( pDisableCairoText && (pDisableCairoText[0] != '0') )
343         return;
344 
345     int nDummy;
346     if( !XQueryExtension( GetX11SalData()->GetDisplay()->GetDisplay(), "RENDER", &nDummy, &nDummy, &nDummy ) )
347         return;
348 
349     OUString aLibName( RTL_CONSTASCII_USTRINGPARAM( "libcairo.so.2" ));
350     mpCairoLib = osl_loadModule( aLibName.pData, SAL_LOADMODULE_DEFAULT );
351     if( !mpCairoLib )
352         return;
353 
354 #ifdef DEBUG
355     // check cairo version
356     int (*p_version)();
357     p_version = (int(*)()) osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_version" );
358 	const int nVersion = p_version ? (*p_version)() : 0;
359     fprintf( stderr, "CAIRO version=%d\n", nVersion );
360 #endif
361 
362     mp_xlib_surface_create_with_xrender_format = (cairo_surface_t* (*)(Display *, Drawable , Screen *, XRenderPictFormat *, int , int ))
363         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_xlib_surface_create_with_xrender_format" );
364     mp_surface_destroy = (void(*)(cairo_surface_t*))
365         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_surface_destroy" );
366     mp_create = (cairo_t*(*)(cairo_surface_t*))
367         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_create" );
368     mp_destroy = (void(*)(cairo_t*))
369         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_destroy" );
370     mp_clip = (void(*)(cairo_t*))
371         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_clip" );
372     mp_rectangle = (void(*)(cairo_t*, double, double, double, double))
373         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_rectangle" );
374     mp_ft_font_face_create_for_ft_face = (cairo_font_face_t * (*)(FT_Face, int))
375         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_ft_font_face_create_for_ft_face" );
376     mp_set_font_face = (void (*)(cairo_t *, cairo_font_face_t *))
377         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_set_font_face" );
378     mp_font_face_destroy = (void (*)(cairo_font_face_t *))
379         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_font_face_destroy" );
380     mp_matrix_init_identity = (void (*)(cairo_matrix_t *))
381         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_matrix_init_identity" );
382     mp_matrix_scale = (void (*)(cairo_matrix_t *, double, double))
383         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_matrix_scale" );
384     mp_matrix_rotate = (void (*)(cairo_matrix_t *, double))
385         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_matrix_rotate" );
386     mp_set_font_matrix = (void (*)(cairo_t *, const cairo_matrix_t *))
387         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_set_font_matrix" );
388     mp_show_glyphs = (void (*)(cairo_t *, const cairo_glyph_t *, int ))
389         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_show_glyphs" );
390     mp_set_source_rgb = (void (*)(cairo_t *, double , double , double ))
391         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_set_source_rgb" );
392     mp_set_font_options = (void (*)(cairo_t *, const void *options ))
393         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_set_font_options" );
394     mp_ft_font_options_substitute = (void (*)(const void *, void *))
395         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_ft_font_options_substitute" );
396 
397     if( !(
398             mp_xlib_surface_create_with_xrender_format &&
399             mp_surface_destroy &&
400             mp_create &&
401             mp_destroy &&
402             mp_clip &&
403             mp_rectangle &&
404             mp_ft_font_face_create_for_ft_face &&
405             mp_set_font_face &&
406             mp_font_face_destroy &&
407             mp_matrix_init_identity &&
408             mp_matrix_scale &&
409             mp_matrix_rotate &&
410             mp_set_font_matrix &&
411             mp_show_glyphs &&
412             mp_set_source_rgb &&
413             mp_set_font_options &&
414             mp_ft_font_options_substitute
415         ) )
416     {
417         osl_unloadModule( mpCairoLib );
418 	mpCairoLib = NULL;
419 #if OSL_DEBUG_LEVEL > 1
420         fprintf( stderr, "not all needed symbols were found\n" );
421 #endif
422     }
423 }
424 
425 bool CairoWrapper::isCairoRenderable(const ServerFont& rFont)
426 {
427     return rFont.GetFtFace() && isValid() && rFont.GetAntialiasAdvice() &&
428         (rFont.NeedsArtificialBold() ? canEmbolden() : true);
429 }
430 
431 } //namespace
432 
433 CairoFontsCache::LRUFonts CairoFontsCache::maLRUFonts;
434 int CairoFontsCache::mnRefCount = 0;
435 
436 CairoFontsCache::CairoFontsCache()
437 {
438     ++mnRefCount;
439 }
440 
441 CairoFontsCache::~CairoFontsCache()
442 {
443     --mnRefCount;
444     if (!mnRefCount && !maLRUFonts.empty())
445     {
446         CairoWrapper &rCairo = CairoWrapper::get();
447         LRUFonts::iterator aEnd = maLRUFonts.end();
448         for (LRUFonts::iterator aI = maLRUFonts.begin(); aI != aEnd; ++aI)
449             rCairo.font_face_destroy((cairo_font_face_t*)aI->first);
450     }
451 }
452 
453 void CairoFontsCache::CacheFont(void *pFont, void* pId)
454 {
455     maLRUFonts.push_front( std::pair<void*, void *>(pFont, pId) );
456     if (maLRUFonts.size() > 8)
457     {
458         CairoWrapper &rCairo = CairoWrapper::get();
459         rCairo.font_face_destroy((cairo_font_face_t*)maLRUFonts.back().first);
460         maLRUFonts.pop_back();
461     }
462 }
463 
464 void* CairoFontsCache::FindCachedFont(void *pId)
465 {
466     LRUFonts::iterator aEnd = maLRUFonts.end();
467     for (LRUFonts::iterator aI = maLRUFonts.begin(); aI != aEnd; ++aI)
468         if (aI->second == pId)
469             return aI->first;
470     return NULL;
471 }
472 
473 void X11SalGraphics::DrawCairoAAFontString( const ServerFontLayout& rLayout )
474 {
475     std::vector<cairo_glyph_t> cairo_glyphs;
476     cairo_glyphs.reserve( 256 );
477 
478     Point aPos;
479     sal_GlyphId aGlyphId;
480     for( int nStart = 0; rLayout.GetNextGlyphs( 1, &aGlyphId, aPos, nStart ); )
481     {
482         cairo_glyph_t aGlyph;
483         aGlyph.index = aGlyphId & GF_IDXMASK;
484         aGlyph.x = aPos.X();
485         aGlyph.y = aPos.Y();
486         cairo_glyphs.push_back(aGlyph);
487     }
488 
489     if (cairo_glyphs.empty())
490         return;
491 
492     // find a XRenderPictFormat compatible with the Drawable
493     XRenderPictFormat* pVisualFormat = static_cast<XRenderPictFormat*>(GetXRenderFormat());
494     if( !pVisualFormat )
495     {
496         Visual* pVisual = GetDisplay()->GetVisual( m_nScreen ).GetVisual();
497         pVisualFormat = XRenderPeer::GetInstance().FindVisualFormat( pVisual );
498         // cache the XRenderPictFormat
499         SetXRenderFormat( static_cast<void*>(pVisualFormat) );
500     }
501 
502     DBG_ASSERT( pVisualFormat!=NULL, "no matching XRenderPictFormat for text" );
503     if( !pVisualFormat )
504 	    return;
505 
506     CairoWrapper &rCairo = CairoWrapper::get();
507 
508     Display* pDisplay = GetXDisplay();
509 
510     cairo_surface_t *surface = rCairo.xlib_surface_create_with_xrender_format (pDisplay,
511         hDrawable_, ScreenOfDisplay(pDisplay, m_nScreen), pVisualFormat, SAL_MAX_INT16, SAL_MAX_INT16);
512 
513     /*
514      * It might be ideal to cache surface and cairo context between calls and
515      * only destroy it when the drawable changes, but to do that we need to at
516      * least change the SalFrame etc impls to dtor the SalGraphics *before* the
517      * destruction of the windows they reference
518     */
519     cairo_t *cr = rCairo.create(surface);
520     rCairo.surface_destroy(surface);
521 
522     if (const void *pOptions = Application::GetSettings().GetStyleSettings().GetCairoFontOptions())
523         rCairo.set_font_options( cr, pOptions);
524 
525     if( mpClipRegion && !XEmptyRegion( mpClipRegion ) )
526     {
527         for (long i = 0; i < mpClipRegion->numRects; ++i)
528         {
529             rCairo.rectangle(cr,
530             mpClipRegion->rects[i].x1,
531             mpClipRegion->rects[i].y1,
532             mpClipRegion->rects[i].x2 - mpClipRegion->rects[i].x1,
533             mpClipRegion->rects[i].y2 - mpClipRegion->rects[i].y1);
534         }
535         rCairo.clip(cr);
536     }
537 
538     rCairo.set_source_rgb(cr,
539         SALCOLOR_RED(nTextColor_)/255.0,
540         SALCOLOR_GREEN(nTextColor_)/255.0,
541         SALCOLOR_BLUE(nTextColor_)/255.0);
542 
543     ServerFont& rFont = rLayout.GetServerFont();
544 
545     cairo_font_face_t* font_face = NULL;
546 
547     void *pId = rFont.GetFtFace();
548     font_face = (cairo_font_face_t*)m_aCairoFontsCache.FindCachedFont(pId);
549     if (!font_face)
550     {
551         font_face = rCairo.ft_font_face_create_for_ft_face(pId, rFont.GetLoadFlags());
552         m_aCairoFontsCache.CacheFont(font_face, pId);
553     }
554 
555     rCairo.set_font_face(cr, font_face);
556 
557     cairo_matrix_t m;
558     const ImplFontSelectData& rFSD = rFont.GetFontSelData();
559     int nWidth = rFSD.mnWidth ? rFSD.mnWidth : rFSD.mnHeight;
560 
561     rCairo.matrix_init_identity(&m);
562 
563     if (rLayout.GetOrientation())
564         rCairo.matrix_rotate(&m, (3600 - rLayout.GetOrientation()) * M_PI / 1800.0);
565 
566     rCairo.matrix_scale(&m, nWidth, rFSD.mnHeight);
567     if (rFont.NeedsArtificialItalic())
568         m.xy = -m.xx * 0x6000L / 0x10000L;
569 
570     rCairo.set_font_matrix(cr, &m);
571     rCairo.show_glyphs(cr, &cairo_glyphs[0], cairo_glyphs.size());
572     rCairo.destroy(cr);
573 }
574 
575 //--------------------------------------------------------------------------
576 
577 void X11SalGraphics::DrawServerAAFontString( const ServerFontLayout& rLayout )
578 {
579 	// get xrender target for this drawable
580     Picture aDstPic = GetXRenderPicture();
581 	if( !aDstPic )
582 		return;
583 
584     // get a XRenderPicture for the font foreground
585     // TODO: move into own method
586     XRenderPeer& rRenderPeer = XRenderPeer::GetInstance();
587 	XRenderPictFormat* pVisualFormat = (XRenderPictFormat*)GetXRenderFormat();
588 	DBG_ASSERT( pVisualFormat, "we already have a render picture, but XRenderPictFormat==NULL???");
589     const int nVisualDepth = pVisualFormat->depth;
590     SalDisplay::RenderEntry& rEntry = GetDisplay()->GetRenderEntries( m_nScreen )[ nVisualDepth ];
591     if( !rEntry.m_aPicture )
592     {
593         // create and cache XRenderPicture for the font foreground
594         Display* pDisplay = GetXDisplay();
595 #ifdef DEBUG
596         int iDummy;
597         unsigned uDummy;
598         XLIB_Window wDummy;
599         unsigned int nDrawDepth;
600         ::XGetGeometry( pDisplay, hDrawable_, &wDummy, &iDummy, &iDummy,
601                       &uDummy, &uDummy, &uDummy, &nDrawDepth );
602         DBG_ASSERT( static_cast<unsigned>(nVisualDepth) == nDrawDepth, "depth messed up for XRender" );
603 #endif
604 
605         rEntry.m_aPixmap = ::XCreatePixmap( pDisplay, hDrawable_, 1, 1, nVisualDepth );
606 
607         XRenderPictureAttributes aAttr;
608         aAttr.repeat = true;
609         rEntry.m_aPicture = rRenderPeer.CreatePicture ( rEntry.m_aPixmap, pVisualFormat, CPRepeat, &aAttr );
610     }
611 
612     // set font foreground color and opacity
613     XRenderColor aRenderColor = GetXRenderColor( nTextColor_ );
614     rRenderPeer.FillRectangle( PictOpSrc, rEntry.m_aPicture, &aRenderColor, 0, 0, 1, 1 );
615 
616     // set clipping
617     // TODO: move into GetXRenderPicture()?
618     if( mpClipRegion && !XEmptyRegion( mpClipRegion ) )
619         rRenderPeer.SetPictureClipRegion( aDstPic, mpClipRegion );
620 
621     ServerFont& rFont = rLayout.GetServerFont();
622     X11GlyphPeer& rGlyphPeer = X11GlyphCache::GetInstance().GetPeer();
623     GlyphSet aGlyphSet = rGlyphPeer.GetGlyphSet( rFont, m_nScreen );
624 
625     Point aPos;
626     static const int MAXGLYPHS = 160;
627     sal_GlyphId aGlyphAry[ MAXGLYPHS ];
628     int nMaxGlyphs = rLayout.GetOrientation() ? 1 : MAXGLYPHS;
629     for( int nStart = 0;;)
630     {
631         int nGlyphs = rLayout.GetNextGlyphs( nMaxGlyphs, aGlyphAry, aPos, nStart );
632         if( !nGlyphs )
633             break;
634 
635         // #i51924# avoid 32->16bit coordinate truncation problem in X11
636         // TODO: reevaluate once displays with >30000 pixels are available
637         if( aPos.X() >= 30000 || aPos.Y() >= 30000 )
638             continue;
639 
640         unsigned int aRenderAry[ MAXGLYPHS ];
641         for( int i = 0; i < nGlyphs; ++i )
642              aRenderAry[ i ] = rGlyphPeer.GetGlyphId( rFont, aGlyphAry[i] );
643         rRenderPeer.CompositeString32( rEntry.m_aPicture, aDstPic,
644            aGlyphSet, aPos.X(), aPos.Y(), aRenderAry, nGlyphs );
645     }
646 }
647 
648 //--------------------------------------------------------------------------
649 
650 bool X11SalGraphics::DrawServerAAForcedString( const ServerFontLayout& rLayout )
651 {
652     ServerFont& rFont = rLayout.GetServerFont();
653 
654     // prepare glyphs and get extent of operation
655     X11GlyphPeer& rGlyphPeer = X11GlyphCache::GetInstance().GetPeer();
656     int nXmin = 0;
657     int nXmax = 0;
658     int nYmin = 0;
659     int nYmax = 0;
660     int nStart = 0;
661     Point aPos;
662     sal_GlyphId nGlyph;
663     for( bool bFirst=true; rLayout.GetNextGlyphs( 1, &nGlyph, aPos, nStart ); )
664     {
665         const RawBitmap* const pRawBitmap = rGlyphPeer.GetRawBitmap( rFont, nGlyph );
666         if( !pRawBitmap )
667             continue;
668 
669         const int nX1 = aPos.X() + pRawBitmap->mnXOffset;
670         const int nY1 = aPos.Y() + pRawBitmap->mnYOffset;
671         const int nX2 = nX1 + pRawBitmap->mnWidth;
672         const int nY2 = nY1 + pRawBitmap->mnHeight;
673 
674         if( bFirst )
675         {
676             bFirst = false;
677             nXmin = nX1;
678             nXmax = nX2;
679             nYmin = nY1;
680             nYmax = nY2;
681         }
682         else
683         {
684             if( nXmin > nX1 ) nXmin = nX1;
685             if( nXmax < nX2 ) nXmax = nX2;
686             if( nYmin > nY1 ) nYmin = nY1;
687             if( nYmax < nY2 ) nYmax = nY2;
688         }
689     }
690 
691     // get XImage
692     GetDisplay()->GetXLib()->PushXErrorLevel( true );
693     Display* pDisplay = GetXDisplay();
694 
695     XRectangle aXRect;
696     long nWidth = 1, nHeight = 1;
697     if( m_pFrame )
698         nWidth = m_pFrame->maGeometry.nWidth, nHeight = m_pFrame->maGeometry.nHeight;
699     else if( m_pVDev )
700         nWidth = m_pVDev->GetWidth(), nHeight = m_pVDev->GetHeight();
701 
702     if( mpClipRegion && !XEmptyRegion( mpClipRegion ) )
703     {
704         // get bounding box
705         XClipBox( mpClipRegion, &aXRect );
706         // clip with window
707         if( aXRect.x < 0 ) aXRect.x = 0;
708 
709         if( aXRect.y < 0 ) aXRect.y = 0;
710         if( aXRect.width+aXRect.x > nWidth ) aXRect.width = nWidth-aXRect.x;
711         if( aXRect.height+aXRect.y > nHeight ) aXRect.height = nHeight-aXRect.y;
712     }
713     else
714     {
715         aXRect.x = 0;
716         aXRect.y = 0;
717         aXRect.width = nWidth;
718         aXRect.height = nHeight;
719     }
720     if( m_pFrame )
721     {
722         // clip with screen
723         int nScreenX = m_pFrame->maGeometry.nX+aXRect.x;
724         int nScreenY = m_pFrame->maGeometry.nY+aXRect.y;
725         const Size& rScreenSize = GetDisplay()->getDataForScreen( m_nScreen ).m_aSize;
726         int nScreenW = rScreenSize.Width();
727         int nScreenH = rScreenSize.Height();
728         if( nScreenX < 0 )
729             aXRect.x -= nScreenX, aXRect.width += nScreenX;
730         if( nScreenX+aXRect.width > nScreenW )
731             aXRect.width = nScreenW-nScreenX;
732         if( nScreenY < 0 )
733             aXRect.y -= nScreenY, aXRect.height += nScreenY;
734         if( nScreenY+aXRect.height > nScreenH )
735             aXRect.height = nScreenH-nScreenY;
736     }
737 
738 
739     if( nXmin < aXRect.x )  nXmin = aXRect.x;
740     if( nYmin < aXRect.y )  nYmin = aXRect.y;
741     if( nXmax >= aXRect.x+aXRect.width )    nXmax = aXRect.x + aXRect.width - 1;
742     if( nYmax >= aXRect.y+aXRect.height )   nYmax = aXRect.y + aXRect.height - 1;
743 
744     if( nXmin > nXmax )
745         return false;
746     if( nYmin > nYmax )
747         return false;
748 
749     XImage* pImg = XGetImage( pDisplay, hDrawable_,
750                               nXmin, nYmin,
751                               (nXmax-nXmin+1), (nYmax-nYmin+1),
752                               ~0, ZPixmap );
753     if( pImg == NULL )
754     {
755         if( m_pFrame )
756         {
757             // the reason we did not get an image could be that the frame
758             // geometry changed in the meantime; lets get the current geometry
759             // and clip against the current window size as well as the screen
760             // with the current frame position
761             const Size& rScreenSize = GetDisplay()->getDataForScreen(m_nScreen).m_aSize;
762             int nScreenW = rScreenSize.Width();
763             int nScreenH = rScreenSize.Height();
764             XLIB_Window aRoot = None;
765             int x = 0, y = 0;
766             unsigned int w = 0, h = 0, bw = 0, d;
767             XGetGeometry( pDisplay, hDrawable_, &aRoot, &x, &y, &w, &h, &bw, &d );
768             XTranslateCoordinates( pDisplay, hDrawable_, aRoot, 0, 0, &x, &y, &aRoot );
769             if( nXmin + x < 0 ) // clip on left screen edge
770                 nXmin += x-nXmin;
771             if( nYmin + y < 0 ) // clip on top screen edge
772                 nYmin += y-nYmin;
773             if( nXmax >= int(w) ) // clip on right window egde
774                 nXmax = w-1;
775             if( nYmax >= int(h) ) // clip on bottom window edge
776                 nYmax = h-1;
777             if( nXmax + x >= nScreenW ) // clip on right screen edge
778                 nXmax -= (nXmax + x - nScreenW)+1;
779             if( nYmax + y >= nScreenH ) // clip on bottom screen edge
780                 nYmax -= (nYmax + y - nScreenH)+1;
781             if( nXmax >= nXmin && nYmax >= nYmin )
782             {
783                 // try again to get the image
784                 pImg = XGetImage( pDisplay, hDrawable_,
785                                   nXmin, nYmin,
786                                   (nXmax-nXmin+1), (nYmax-nYmin+1),
787                                   ~0, ZPixmap );
788             }
789         }
790         if( pImg == NULL )
791         {
792             GetDisplay()->GetXLib()->PopXErrorLevel();
793             return false;
794         }
795     }
796 
797     // prepare context
798     GC nGC = GetFontGC();
799     XGCValues aGCVal;
800     XGetGCValues( pDisplay, nGC, GCForeground, &aGCVal );
801 
802     unsigned long nOrigColor = XGetPixel( pImg, 0, 0 );
803     XPutPixel( pImg, 0, 0, aGCVal.foreground );
804     unsigned char aColor[4];
805     aColor[0] = pImg->data[0];
806     aColor[1] = pImg->data[1];
807     aColor[2] = pImg->data[2];
808     aColor[3] = pImg->data[3];
809     XPutPixel( pImg, 0, 0, nOrigColor );
810 
811     // work on XImage
812     const int bpp = pImg->bits_per_pixel >> 3;
813     for( nStart = 0; rLayout.GetNextGlyphs( 1, &nGlyph, aPos, nStart ); )
814     {
815         const RawBitmap* const pRawBitmap = rGlyphPeer.GetRawBitmap( rFont, nGlyph );
816         if( !pRawBitmap )
817             continue;
818 
819         const int nX1 = aPos.X() + pRawBitmap->mnXOffset;
820         const int nY1 = aPos.Y() + pRawBitmap->mnYOffset;
821 
822         if( (nX1 <= nXmax) && (int(nX1 + pRawBitmap->mnWidth) > nXmin)
823         &&  (nY1 <= nYmax) && (int(nY1 + pRawBitmap->mnHeight) > nYmin) )
824         {
825             const unsigned char* p10 = pRawBitmap->mpBits;
826             unsigned char* p20 = (unsigned char*)pImg->data;                // dest left limit
827             p20 += (nY1 - nYmin) * pImg->bytes_per_line;
828             unsigned char* p21 = p20 + (nX1 - nXmin + pImg->xoffset) * bpp;
829             int y = pRawBitmap->mnHeight;
830             if( y > nYmax - nY1 )
831                 y = nYmax - nY1 + 1;
832             while( --y >= 0 )
833             {
834                 if( p20 >= (unsigned char*)pImg->data )
835                 {
836                     unsigned char* const p22 = p20 + pImg->width * bpp; // dest right limit
837                     unsigned char* pDst = p21;
838                     const unsigned char* pSrc = p10;
839                     for( int x = pRawBitmap->mnWidth; (--x >= 0) && (p22 > pDst); ++pSrc )
840                     {
841                         if( (*pSrc == 0) || (p20 > pDst) )          // keep background
842                             pDst += bpp;
843                         else if( *pSrc == 0xFF )                    // paint foreground
844                         {
845                             const unsigned char* pColor = aColor;
846                             for( int z = bpp; --z >= 0; ++pColor, ++pDst )
847                                 *pDst = *pColor;
848                         }
849                         else                                        // blend fg into bg
850                         {
851                             const unsigned char* pColor = aColor;
852                             for( int z = bpp; --z >= 0; ++pColor, ++pDst )
853                                 // theoretically it should be *257) >> 16
854                                 // but the error is <0.4% worst case and we are in
855                                 // the innermost loop of very perf-sensitive code
856 
857                                 *pDst += (*pSrc * ((int)*pColor - *pDst)) >> 8;
858                         }
859                     }
860                 }
861                 p10 += pRawBitmap->mnScanlineSize;
862                 p20 += pImg->bytes_per_line;
863                 p21 += pImg->bytes_per_line;
864             }
865         }
866     }
867 
868     // put XImage
869     XPutImage( pDisplay, hDrawable_, nGC, pImg,
870         0, 0, nXmin, nYmin, (nXmax - nXmin + 1), (nYmax - nYmin + 1) );
871     XDestroyImage( pImg );
872 
873     GetDisplay()->GetXLib()->PopXErrorLevel();
874     return true;
875 }
876 
877 //--------------------------------------------------------------------------
878 
879 void X11SalGraphics::DrawServerSimpleFontString( const ServerFontLayout& rSalLayout )
880 {
881     ServerFont& rFont = rSalLayout.GetServerFont();
882     X11GlyphPeer& rGlyphPeer = X11GlyphCache::GetInstance().GetPeer();
883 
884     Display* pDisplay = GetXDisplay();
885     GC nGC = GetFontGC();
886 
887     XGCValues aGCVal;
888     aGCVal.fill_style = FillStippled;
889     aGCVal.line_width = 0;
890     GC tmpGC = XCreateGC( pDisplay, hDrawable_, GCFillStyle|GCLineWidth, &aGCVal );
891     XCopyGC( pDisplay, nGC, (1<<GCLastBit)-(1+GCFillStyle+GCLineWidth), tmpGC );
892 
893     Point aPos;
894     sal_GlyphId nGlyph;
895     for( int nStart = 0; rSalLayout.GetNextGlyphs( 1, &nGlyph, aPos, nStart ); )
896     {
897         // #i51924# avoid 32->16bit coordinate truncation problem in X11
898         // TODO: reevaluate once displays with >30000 pixels are available
899         if( aPos.X() >= 30000 || aPos.Y() >= 30000 )
900             continue;
901 
902         Pixmap aStipple = rGlyphPeer.GetPixmap( rFont, nGlyph, m_nScreen );
903         const GlyphMetric& rGM = rFont.GetGlyphMetric( nGlyph );
904 
905         if( aStipple != None )
906         {
907             const int nDestX    = aPos.X() + rGM.GetOffset().X();
908             const int nDestY    = aPos.Y() + rGM.GetOffset().Y();
909 
910             aGCVal.stipple      = aStipple;
911             aGCVal.ts_x_origin  = nDestX;
912             aGCVal.ts_y_origin  = nDestY;
913             XChangeGC( pDisplay, tmpGC, GCStipple|GCTileStipXOrigin|GCTileStipYOrigin, &aGCVal );
914 
915             const int nWidth    = rGM.GetSize().Width();
916             const int nHeight   = rGM.GetSize().Height();
917             XFillRectangle( pDisplay, hDrawable_, tmpGC, nDestX, nDestY, nWidth, nHeight );
918         }
919     }
920 
921     XFreeGC( pDisplay, tmpGC );
922 }
923 
924 //--------------------------------------------------------------------------
925 
926 void X11SalGraphics::DrawServerFontLayout( const ServerFontLayout& rLayout )
927 {
928     // draw complex text
929     ServerFont& rFont = rLayout.GetServerFont();
930 	const bool bVertical = rFont.GetFontSelData().mbVertical;
931 
932     if( !bVertical && CairoWrapper::get().isCairoRenderable(rFont) )
933         DrawCairoAAFontString( rLayout );
934     else
935     {
936         X11GlyphPeer& rGlyphPeer = X11GlyphCache::GetInstance().GetPeer();
937         if( rGlyphPeer.GetGlyphSet( rFont, m_nScreen ) )
938             DrawServerAAFontString( rLayout );
939         else if( !rGlyphPeer.ForcedAntialiasing( rFont, m_nScreen ) )
940             DrawServerSimpleFontString( rLayout );
941         else
942             DrawServerAAForcedString( rLayout );
943     }
944 }
945 
946 //--------------------------------------------------------------------------
947 
948 const ImplFontCharMap* X11SalGraphics::GetImplFontCharMap() const
949 {
950     if( !mpServerFont[0] )
951         return NULL;
952 
953     const ImplFontCharMap* pIFCMap = mpServerFont[0]->GetImplFontCharMap();
954     return pIFCMap;
955 }
956 
957 // ----------------------------------------------------------------------------
958 //
959 // SalGraphics
960 //
961 // ----------------------------------------------------------------------------
962 
963 sal_uInt16 X11SalGraphics::SetFont( ImplFontSelectData *pEntry, int nFallbackLevel )
964 {
965     sal_uInt16 nRetVal = 0;
966     if( !setFont( pEntry, nFallbackLevel ) )
967         nRetVal |= SAL_SETFONT_BADFONT;
968     if( bPrinter_ || (mpServerFont[ nFallbackLevel ] != NULL) )
969         nRetVal |= SAL_SETFONT_USEDRAWTEXTARRAY;
970     return nRetVal;
971 }
972 
973 // ----------------------------------------------------------------------------
974 
975 void
976 X11SalGraphics::SetTextColor( SalColor nSalColor )
977 {
978     if( nTextColor_	!= nSalColor )
979     {
980         nTextColor_     = nSalColor;
981         nTextPixel_     = GetPixel( nSalColor );
982         bFontGC_        = sal_False;
983     }
984 }
985 
986 // ----------------------------------------------------------------------------
987 
988 bool X11SalGraphics::AddTempDevFont( ImplDevFontList* pFontList,
989     const String& rFileURL, const String& rFontName )
990 {
991     // inform PSP font manager
992     rtl::OUString aUSystemPath;
993     OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFileURL, aUSystemPath ) );
994     rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
995     OString aOFileName( OUStringToOString( aUSystemPath, aEncoding ) );
996     psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
997     int nFontId = rMgr.addFontFile( aOFileName, 0 );
998     if( !nFontId )
999         return false;
1000 
1001     // prepare font data
1002     psp::FastPrintFontInfo aInfo;
1003     rMgr.getFontFastInfo( nFontId, aInfo );
1004     aInfo.m_aFamilyName = rFontName;
1005 
1006     // inform glyph cache of new font
1007     ImplDevFontAttributes aDFA = PspGraphics::Info2DevFontAttributes( aInfo );
1008     aDFA.mnQuality += 5800;
1009 
1010     int nFaceNum = rMgr.getFontFaceNumber( aInfo.m_nID );
1011     if( nFaceNum < 0 )
1012         nFaceNum = 0;
1013 
1014     GlyphCache& rGC = X11GlyphCache::GetInstance();
1015     const rtl::OString& rFileName = rMgr.getFontFileSysPath( aInfo.m_nID );
1016     rGC.AddFontFile( rFileName, nFaceNum, aInfo.m_nID, aDFA );
1017 
1018     // announce new font to device's font list
1019     rGC.AnnounceFonts( pFontList );
1020     return true;
1021 }
1022 
1023 // ----------------------------------------------------------------------------
1024 
1025 void RegisterFontSubstitutors( ImplDevFontList* );
1026 
1027 void X11SalGraphics::GetDevFontList( ImplDevFontList *pList )
1028 {
1029     // prepare the GlyphCache using psprint's font infos
1030     X11GlyphCache& rGC = X11GlyphCache::GetInstance();
1031 
1032     psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
1033     ::std::list< psp::fontID > aList;
1034     ::std::list< psp::fontID >::iterator it;
1035     psp::FastPrintFontInfo aInfo;
1036     rMgr.getFontList( aList );
1037     for( it = aList.begin(); it != aList.end(); ++it )
1038     {
1039         if( !rMgr.getFontFastInfo( *it, aInfo ) )
1040             continue;
1041 
1042         // the GlyphCache must not bother with builtin fonts because
1043         // it cannot access or use them anyway
1044         if( aInfo.m_eType == psp::fonttype::Builtin )
1045             continue;
1046 
1047         // normalize face number to the GlyphCache
1048         int nFaceNum = rMgr.getFontFaceNumber( aInfo.m_nID );
1049         if( nFaceNum < 0 )
1050             nFaceNum = 0;
1051 
1052         // for fonts where extra kerning info can be provided on demand
1053         // an ExtraKernInfo object is supplied
1054         const ExtraKernInfo* pExtraKernInfo = NULL;
1055         if( aInfo.m_eType == psp::fonttype::Type1 )
1056             pExtraKernInfo = new PspKernInfo( *it );
1057 
1058         // inform GlyphCache about this font provided by the PsPrint subsystem
1059         ImplDevFontAttributes aDFA = PspGraphics::Info2DevFontAttributes( aInfo );
1060         aDFA.mnQuality += 4096;
1061         const rtl::OString& rFileName = rMgr.getFontFileSysPath( aInfo.m_nID );
1062         rGC.AddFontFile( rFileName, nFaceNum, aInfo.m_nID, aDFA, pExtraKernInfo );
1063    }
1064 
1065     // announce glyphcache fonts
1066     rGC.AnnounceFonts( pList );
1067 
1068     // register platform specific font substitutions if available
1069     if( rMgr.hasFontconfig() )
1070         RegisterFontSubstitutors( pList );
1071 
1072     ImplGetSVData()->maGDIData.mbNativeFontConfig = rMgr.hasFontconfig();
1073 }
1074 
1075 // ----------------------------------------------------------------------------
1076 
1077 void X11SalGraphics::GetDevFontSubstList( OutputDevice* )
1078 {
1079     // no device specific font substitutions on X11 needed
1080 }
1081 
1082 // ----------------------------------------------------------------------------
1083 
1084 void cairosubcallback( void* pPattern )
1085 {
1086     CairoWrapper& rCairo = CairoWrapper::get();
1087     if( !rCairo.isValid() )
1088         return;
1089     const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1090     const void* pFontOptions = rStyleSettings.GetCairoFontOptions();
1091     if( !pFontOptions )
1092         return;
1093     rCairo.ft_font_options_substitute( pFontOptions, pPattern );
1094 }
1095 
1096 bool GetFCFontOptions( const ImplFontAttributes& rFontAttributes, int nSize,
1097 	ImplFontOptions& rFontOptions)
1098 {
1099     // TODO: get rid of these insane enum-conversions
1100     // e.g. by using the classic vclenum values inside VCL
1101 
1102     psp::FastPrintFontInfo aInfo;
1103     // set family name
1104     aInfo.m_aFamilyName = rFontAttributes.GetFamilyName();
1105     // set italic
1106     switch( rFontAttributes.GetSlant() )
1107     {
1108         case ITALIC_NONE:
1109             aInfo.m_eItalic = psp::italic::Upright;
1110             break;
1111         case ITALIC_NORMAL:
1112             aInfo.m_eItalic = psp::italic::Italic;
1113             break;
1114         case ITALIC_OBLIQUE:
1115             aInfo.m_eItalic = psp::italic::Oblique;
1116             break;
1117         default:
1118             aInfo.m_eItalic = psp::italic::Unknown;
1119             break;
1120     }
1121     // set weight
1122     switch( rFontAttributes.GetWeight() )
1123     {
1124         case WEIGHT_THIN:
1125             aInfo.m_eWeight = psp::weight::Thin;
1126             break;
1127         case WEIGHT_ULTRALIGHT:
1128             aInfo.m_eWeight = psp::weight::UltraLight;
1129             break;
1130         case WEIGHT_LIGHT:
1131             aInfo.m_eWeight = psp::weight::Light;
1132             break;
1133         case WEIGHT_SEMILIGHT:
1134             aInfo.m_eWeight = psp::weight::SemiLight;
1135             break;
1136         case WEIGHT_NORMAL:
1137             aInfo.m_eWeight = psp::weight::Normal;
1138             break;
1139         case WEIGHT_MEDIUM:
1140             aInfo.m_eWeight = psp::weight::Medium;
1141             break;
1142         case WEIGHT_SEMIBOLD:
1143             aInfo.m_eWeight = psp::weight::SemiBold;
1144             break;
1145         case WEIGHT_BOLD:
1146             aInfo.m_eWeight = psp::weight::Bold;
1147             break;
1148         case WEIGHT_ULTRABOLD:
1149             aInfo.m_eWeight = psp::weight::UltraBold;
1150             break;
1151         case WEIGHT_BLACK:
1152             aInfo.m_eWeight = psp::weight::Black;
1153             break;
1154         default:
1155             aInfo.m_eWeight = psp::weight::Unknown;
1156             break;
1157     }
1158     // set width
1159     switch( rFontAttributes.GetWidthType() )
1160     {
1161         case WIDTH_ULTRA_CONDENSED:
1162             aInfo.m_eWidth = psp::width::UltraCondensed;
1163             break;
1164         case WIDTH_EXTRA_CONDENSED:
1165             aInfo.m_eWidth = psp::width::ExtraCondensed;
1166             break;
1167         case WIDTH_CONDENSED:
1168             aInfo.m_eWidth = psp::width::Condensed;
1169             break;
1170         case WIDTH_SEMI_CONDENSED:
1171             aInfo.m_eWidth = psp::width::SemiCondensed;
1172             break;
1173         case WIDTH_NORMAL:
1174             aInfo.m_eWidth = psp::width::Normal;
1175             break;
1176         case WIDTH_SEMI_EXPANDED:
1177             aInfo.m_eWidth = psp::width::SemiExpanded;
1178             break;
1179         case WIDTH_EXPANDED:
1180             aInfo.m_eWidth = psp::width::Expanded;
1181             break;
1182         case WIDTH_EXTRA_EXPANDED:
1183             aInfo.m_eWidth = psp::width::ExtraExpanded;
1184             break;
1185         case WIDTH_ULTRA_EXPANDED:
1186             aInfo.m_eWidth = psp::width::UltraExpanded;
1187             break;
1188         default:
1189             aInfo.m_eWidth = psp::width::Unknown;
1190             break;
1191     }
1192 
1193     const psp::PrintFontManager& rPFM = psp::PrintFontManager::get();
1194     bool bOK = rPFM.getFontOptions( aInfo, nSize, cairosubcallback, rFontOptions);
1195     return bOK;
1196 }
1197 
1198 // ----------------------------------------------------------------------------
1199 
1200 void
1201 X11SalGraphics::GetFontMetric( ImplFontMetricData *pMetric, int nFallbackLevel )
1202 {
1203     if( nFallbackLevel >= MAX_FALLBACK )
1204         return;
1205 
1206     if( mpServerFont[nFallbackLevel] != NULL )
1207     {
1208         long rDummyFactor;
1209         mpServerFont[nFallbackLevel]->FetchFontMetric( *pMetric, rDummyFactor );
1210     }
1211 }
1212 
1213 // ---------------------------------------------------------------------------
1214 
1215 sal_uLong
1216 X11SalGraphics::GetKernPairs( sal_uLong nPairs, ImplKernPairData *pKernPairs )
1217 {
1218     if( ! bPrinter_ )
1219     {
1220         if( mpServerFont[0] != NULL )
1221         {
1222             ImplKernPairData* pTmpKernPairs;
1223             sal_uLong nGotPairs = mpServerFont[0]->GetKernPairs( &pTmpKernPairs );
1224             for( unsigned int i = 0; i < nPairs && i < nGotPairs; ++i )
1225                 pKernPairs[ i ] = pTmpKernPairs[ i ];
1226             delete[] pTmpKernPairs;
1227             return nGotPairs;
1228         }
1229     }
1230 	return 0;
1231 }
1232 
1233 // ---------------------------------------------------------------------------
1234 
1235 sal_Bool X11SalGraphics::GetGlyphBoundRect( long nGlyphIndex, Rectangle& rRect )
1236 {
1237     int nLevel = nGlyphIndex >> GF_FONTSHIFT;
1238     if( nLevel >= MAX_FALLBACK )
1239         return sal_False;
1240 
1241     ServerFont* pSF = mpServerFont[ nLevel ];
1242     if( !pSF )
1243         return sal_False;
1244 
1245     nGlyphIndex &= ~GF_FONTMASK;
1246     const GlyphMetric& rGM = pSF->GetGlyphMetric( nGlyphIndex );
1247     rRect = Rectangle( rGM.GetOffset(), rGM.GetSize() );
1248     return sal_True;
1249 }
1250 
1251 // ---------------------------------------------------------------------------
1252 
1253 sal_Bool X11SalGraphics::GetGlyphOutline( long nGlyphIndex,
1254     ::basegfx::B2DPolyPolygon& rPolyPoly )
1255 {
1256     int nLevel = nGlyphIndex >> GF_FONTSHIFT;
1257     if( nLevel >= MAX_FALLBACK )
1258         return sal_False;
1259 
1260     ServerFont* pSF = mpServerFont[ nLevel ];
1261     if( !pSF )
1262         return sal_False;
1263 
1264     nGlyphIndex &= ~GF_FONTMASK;
1265     if( pSF->GetGlyphOutline( nGlyphIndex, rPolyPoly ) )
1266         return sal_True;
1267 
1268     return sal_False;
1269 }
1270 
1271 //--------------------------------------------------------------------------
1272 
1273 SalLayout* X11SalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel )
1274 {
1275     SalLayout* pLayout = NULL;
1276 
1277     if( mpServerFont[ nFallbackLevel ]
1278     && !(rArgs.mnFlags & SAL_LAYOUT_DISABLE_GLYPH_PROCESSING) )
1279     {
1280 #ifdef ENABLE_GRAPHITE
1281         // Is this a Graphite font?
1282         if (!bDisableGraphite_ &&
1283             GraphiteFontAdaptor::IsGraphiteEnabledFont(*mpServerFont[nFallbackLevel]))
1284         {
1285             sal_Int32 xdpi, ydpi;
1286 
1287             xdpi = GetDisplay()->GetResolution().A();
1288             ydpi = GetDisplay()->GetResolution().B();
1289 
1290             GraphiteFontAdaptor * pGrfont = new GraphiteFontAdaptor( *mpServerFont[nFallbackLevel], xdpi, ydpi);
1291             if (!pGrfont) return NULL;
1292             pLayout = new GraphiteServerFontLayout(pGrfont);
1293         }
1294         else
1295 #endif
1296             pLayout = new ServerFontLayout( *mpServerFont[ nFallbackLevel ] );
1297     }
1298 
1299     return pLayout;
1300 }
1301 
1302 //--------------------------------------------------------------------------
1303 
1304 SystemFontData X11SalGraphics::GetSysFontData( int nFallbacklevel ) const
1305 {
1306     SystemFontData aSysFontData;
1307     aSysFontData.nSize = sizeof( SystemFontData );
1308     aSysFontData.nFontId = 0;
1309 
1310     if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1;
1311     if (nFallbacklevel < 0 ) nFallbacklevel = 0;
1312 
1313     if (mpServerFont[nFallbacklevel] != NULL)
1314     {
1315         ServerFont* rFont = mpServerFont[nFallbacklevel];
1316         aSysFontData.nFontId = rFont->GetFtFace();
1317         aSysFontData.nFontFlags = rFont->GetLoadFlags();
1318         aSysFontData.bFakeBold = rFont->NeedsArtificialBold();
1319         aSysFontData.bFakeItalic = rFont->NeedsArtificialItalic();
1320         aSysFontData.bAntialias = rFont->GetAntialiasAdvice();
1321         aSysFontData.bVerticalCharacterType = rFont->GetFontSelData().mbVertical;
1322     }
1323 
1324     return aSysFontData;
1325 }
1326 
1327 //--------------------------------------------------------------------------
1328 
1329 sal_Bool X11SalGraphics::CreateFontSubset(
1330                                    const rtl::OUString& rToFile,
1331                                    const ImplFontData* pFont,
1332                                    sal_Int32* pGlyphIDs,
1333                                    sal_uInt8* pEncoding,
1334                                    sal_Int32* pWidths,
1335                                    int nGlyphCount,
1336                                    FontSubsetInfo& rInfo
1337                                    )
1338 {
1339     // in this context the pFont->GetFontId() is a valid PSP
1340     // font since they are the only ones left after the PDF
1341     // export has filtered its list of subsettable fonts (for
1342     // which this method was created). The correct way would
1343     // be to have the GlyphCache search for the ImplFontData pFont
1344     psp::fontID aFont = pFont->GetFontId();
1345 
1346     psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
1347     bool bSuccess = rMgr.createFontSubset( rInfo,
1348                                  aFont,
1349                                  rToFile,
1350                                  pGlyphIDs,
1351                                  pEncoding,
1352                                  pWidths,
1353                                  nGlyphCount );
1354     return bSuccess;
1355 }
1356 
1357 //--------------------------------------------------------------------------
1358 
1359 const void* X11SalGraphics::GetEmbedFontData( const ImplFontData* pFont, const sal_Ucs* pUnicodes, sal_Int32* pWidths, FontSubsetInfo& rInfo, long* pDataLen )
1360 {
1361     // in this context the pFont->GetFontId() is a valid PSP
1362     // font since they are the only ones left after the PDF
1363     // export has filtered its list of subsettable fonts (for
1364     // which this method was created). The correct way would
1365     // be to have the GlyphCache search for the ImplFontData pFont
1366     psp::fontID aFont = pFont->GetFontId();
1367     return PspGraphics::DoGetEmbedFontData( aFont, pUnicodes, pWidths, rInfo, pDataLen );
1368 }
1369 
1370 //--------------------------------------------------------------------------
1371 
1372 void X11SalGraphics::FreeEmbedFontData( const void* pData, long nLen )
1373 {
1374     PspGraphics::DoFreeEmbedFontData( pData, nLen );
1375 }
1376 
1377 //--------------------------------------------------------------------------
1378 
1379 const Ucs2SIntMap* X11SalGraphics::GetFontEncodingVector( const ImplFontData* pFont, const Ucs2OStrMap** pNonEncoded )
1380 {
1381     // in this context the pFont->GetFontId() is a valid PSP
1382     // font since they are the only ones left after the PDF
1383     // export has filtered its list of subsettable fonts (for
1384     // which this method was created). The correct way would
1385     // be to have the GlyphCache search for the ImplFontData pFont
1386     psp::fontID aFont = pFont->GetFontId();
1387     return PspGraphics::DoGetFontEncodingVector( aFont, pNonEncoded );
1388 }
1389 
1390 //--------------------------------------------------------------------------
1391 
1392 void X11SalGraphics::GetGlyphWidths( const ImplFontData* pFont,
1393                                    bool bVertical,
1394                                    Int32Vector& rWidths,
1395                                    Ucs2UIntMap& rUnicodeEnc )
1396 {
1397     // in this context the pFont->GetFontId() is a valid PSP
1398     // font since they are the only ones left after the PDF
1399     // export has filtered its list of subsettable fonts (for
1400     // which this method was created). The correct way would
1401     // be to have the GlyphCache search for the ImplFontData pFont
1402     psp::fontID aFont = pFont->GetFontId();
1403     PspGraphics::DoGetGlyphWidths( aFont, bVertical, rWidths, rUnicodeEnc );
1404 }
1405 
1406 // ===========================================================================
1407 // platform specific font substitution hooks
1408 
1409 class FcPreMatchSubstititution
1410 :   public ImplPreMatchFontSubstitution
1411 {
1412 public:
1413     bool FindFontSubstitute( ImplFontSelectData& ) const;
1414 };
1415 
1416 class FcGlyphFallbackSubstititution
1417 :    public ImplGlyphFallbackFontSubstitution
1418 {
1419     // TODO: add a cache
1420 public:
1421     bool FindFontSubstitute( ImplFontSelectData&, OUString& rMissingCodes ) const;
1422 };
1423 
1424 void RegisterFontSubstitutors( ImplDevFontList* pList )
1425 {
1426     // init font substitution defaults
1427     int nDisableBits = 0;
1428 #ifdef SOLARIS
1429     nDisableBits = 1; // disable "font fallback" here on default
1430 #endif
1431     // apply the environment variable if any
1432     const char* pEnvStr = ::getenv( "SAL_DISABLE_FC_SUBST" );
1433     if( pEnvStr )
1434     {
1435         if( (*pEnvStr >= '0') && (*pEnvStr <= '9') )
1436             nDisableBits = (*pEnvStr - '0');
1437         else
1438             nDisableBits = ~0U; // no specific bits set: disable all
1439     }
1440 
1441     // register font fallback substitutions (unless disabled by bit0)
1442     if( (nDisableBits & 1) == 0 )
1443     {
1444         static FcPreMatchSubstititution aSubstPreMatch;
1445         pList->SetPreMatchHook( &aSubstPreMatch );
1446     }
1447 
1448     // register glyph fallback substitutions (unless disabled by bit1)
1449     if( (nDisableBits & 2) == 0 )
1450     {
1451         static FcGlyphFallbackSubstititution aSubstFallback;
1452         pList->SetFallbackHook( &aSubstFallback );
1453     }
1454 }
1455 
1456 // -----------------------------------------------------------------------
1457 
1458 static ImplFontSelectData GetFcSubstitute(const ImplFontSelectData &rFontSelData, OUString& rMissingCodes )
1459 {
1460     ImplFontSelectData aRet(rFontSelData);
1461 
1462     const rtl::OString aLangAttrib = MsLangId::convertLanguageToIsoByteString( rFontSelData.meLanguage );
1463 
1464     psp::italic::type eItalic = psp::italic::Unknown;
1465     if( rFontSelData.GetSlant() != ITALIC_DONTKNOW )
1466     {
1467         switch( rFontSelData.GetSlant() )
1468         {
1469             case ITALIC_NONE:    eItalic = psp::italic::Upright; break;
1470             case ITALIC_NORMAL:  eItalic = psp::italic::Italic; break;
1471             case ITALIC_OBLIQUE: eItalic = psp::italic::Oblique; break;
1472             default:
1473                 break;
1474         }
1475     }
1476 
1477     psp::weight::type eWeight = psp::weight::Unknown;
1478     if( rFontSelData.GetWeight() != WEIGHT_DONTKNOW )
1479     {
1480         switch( rFontSelData.GetWeight() )
1481         {
1482             case WEIGHT_THIN:		eWeight = psp::weight::Thin; break;
1483             case WEIGHT_ULTRALIGHT:	eWeight = psp::weight::UltraLight; break;
1484             case WEIGHT_LIGHT:		eWeight = psp::weight::Light; break;
1485             case WEIGHT_SEMILIGHT:	eWeight = psp::weight::SemiLight; break;
1486             case WEIGHT_NORMAL:		eWeight = psp::weight::Normal; break;
1487             case WEIGHT_MEDIUM:		eWeight = psp::weight::Medium; break;
1488             case WEIGHT_SEMIBOLD:	eWeight = psp::weight::SemiBold; break;
1489             case WEIGHT_BOLD:		eWeight = psp::weight::Bold; break;
1490             case WEIGHT_ULTRABOLD:	eWeight = psp::weight::UltraBold; break;
1491             case WEIGHT_BLACK:		eWeight = psp::weight::Black; break;
1492             default:
1493                 break;
1494         }
1495     }
1496 
1497     psp::width::type eWidth = psp::width::Unknown;
1498     if( rFontSelData.GetWidthType() != WIDTH_DONTKNOW )
1499     {
1500         switch( rFontSelData.GetWidthType() )
1501         {
1502             case WIDTH_ULTRA_CONDENSED:	eWidth = psp::width::UltraCondensed; break;
1503             case WIDTH_EXTRA_CONDENSED: eWidth = psp::width::ExtraCondensed; break;
1504             case WIDTH_CONDENSED:	eWidth = psp::width::Condensed; break;
1505             case WIDTH_SEMI_CONDENSED:	eWidth = psp::width::SemiCondensed; break;
1506             case WIDTH_NORMAL:		eWidth = psp::width::Normal; break;
1507             case WIDTH_SEMI_EXPANDED:	eWidth = psp::width::SemiExpanded; break;
1508             case WIDTH_EXPANDED:	eWidth = psp::width::Expanded; break;
1509             case WIDTH_EXTRA_EXPANDED:	eWidth = psp::width::ExtraExpanded; break;
1510             case WIDTH_ULTRA_EXPANDED:	eWidth = psp::width::UltraExpanded; break;
1511             default:
1512                 break;
1513         }
1514     }
1515 
1516     psp::pitch::type ePitch = psp::pitch::Unknown;
1517     if( rFontSelData.GetPitch() != PITCH_DONTKNOW )
1518     {
1519         switch( rFontSelData.GetPitch() )
1520         {
1521             case PITCH_FIXED:    ePitch=psp::pitch::Fixed; break;
1522             case PITCH_VARIABLE: ePitch=psp::pitch::Variable; break;
1523             default:
1524                 break;
1525         }
1526     }
1527 
1528     const psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
1529     aRet.maSearchName = rMgr.Substitute( rFontSelData.maTargetName, rMissingCodes, aLangAttrib, eItalic, eWeight, eWidth, ePitch);
1530 
1531     switch (eItalic)
1532     {
1533         case psp::italic::Upright: aRet.meItalic = ITALIC_NONE; break;
1534         case psp::italic::Italic: aRet.meItalic = ITALIC_NORMAL; break;
1535         case psp::italic::Oblique: aRet.meItalic = ITALIC_OBLIQUE; break;
1536         default:
1537             break;
1538     }
1539 
1540     switch (eWeight)
1541     {
1542         case psp::weight::Thin: aRet.meWeight = WEIGHT_THIN; break;
1543         case psp::weight::UltraLight: aRet.meWeight = WEIGHT_ULTRALIGHT; break;
1544         case psp::weight::Light: aRet.meWeight = WEIGHT_LIGHT; break;
1545         case psp::weight::SemiLight: aRet.meWeight = WEIGHT_SEMILIGHT; break;
1546         case psp::weight::Normal: aRet.meWeight = WEIGHT_NORMAL; break;
1547         case psp::weight::Medium: aRet.meWeight = WEIGHT_MEDIUM; break;
1548         case psp::weight::SemiBold: aRet.meWeight = WEIGHT_SEMIBOLD; break;
1549         case psp::weight::Bold: aRet.meWeight = WEIGHT_BOLD; break;
1550         case psp::weight::UltraBold: aRet.meWeight = WEIGHT_ULTRABOLD; break;
1551         case psp::weight::Black: aRet.meWeight = WEIGHT_BLACK; break;
1552         default:
1553                 break;
1554     }
1555 
1556     switch (eWidth)
1557     {
1558         case psp::width::UltraCondensed: aRet.meWidthType = WIDTH_ULTRA_CONDENSED; break;
1559         case psp::width::ExtraCondensed: aRet.meWidthType = WIDTH_EXTRA_CONDENSED; break;
1560         case psp::width::Condensed: aRet.meWidthType = WIDTH_CONDENSED; break;
1561         case psp::width::SemiCondensed: aRet.meWidthType = WIDTH_SEMI_CONDENSED; break;
1562         case psp::width::Normal: aRet.meWidthType = WIDTH_NORMAL; break;
1563         case psp::width::SemiExpanded: aRet.meWidthType = WIDTH_SEMI_EXPANDED; break;
1564         case psp::width::Expanded: aRet.meWidthType = WIDTH_EXPANDED; break;
1565         case psp::width::ExtraExpanded: aRet.meWidthType = WIDTH_EXTRA_EXPANDED; break;
1566         case psp::width::UltraExpanded: aRet.meWidthType = WIDTH_ULTRA_EXPANDED; break;
1567         default:
1568             break;
1569     }
1570 
1571     switch (ePitch)
1572     {
1573         case psp::pitch::Fixed: aRet.mePitch = PITCH_FIXED; break;
1574         case psp::pitch::Variable: aRet.mePitch = PITCH_VARIABLE; break;
1575         default:
1576             break;
1577     }
1578 
1579     return aRet;
1580 }
1581 
1582 namespace
1583 {
1584     bool uselessmatch(const ImplFontSelectData &rOrig, const ImplFontSelectData &rNew)
1585     {
1586         return
1587           (
1588             rOrig.maTargetName == rNew.maSearchName &&
1589             rOrig.meWeight == rNew.meWeight &&
1590             rOrig.meItalic == rNew.meItalic &&
1591             rOrig.mePitch == rNew.mePitch &&
1592             rOrig.meWidthType == rNew.meWidthType
1593           );
1594     }
1595 }
1596 
1597 //--------------------------------------------------------------------------
1598 
1599 bool FcPreMatchSubstititution::FindFontSubstitute( ImplFontSelectData &rFontSelData ) const
1600 {
1601     // We dont' actually want to talk to Fontconfig at all for symbol fonts
1602     if( rFontSelData.IsSymbolFont() )
1603         return false;
1604     // StarSymbol is a unicode font, but it still deserves the symbol flag
1605     if( 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "starsymbol", 10)
1606     ||  0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "opensymbol", 10) )
1607         return false;
1608 
1609     rtl::OUString aDummy;
1610     const ImplFontSelectData aOut = GetFcSubstitute( rFontSelData, aDummy );
1611     // TODO: cache the font substitution suggestion
1612     // FC doing it would be preferable because it knows the invariables
1613     // e.g. FC knows the FC rule that all Arial gets replaced by LiberationSans
1614     // whereas we would have to check for every size or attribute
1615     if( !aOut.maSearchName.Len() )
1616         return false;
1617 
1618     const bool bHaveSubstitute = !uselessmatch( rFontSelData, aOut );
1619 
1620 #ifdef DEBUG
1621     const ByteString aOrigName( rFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 );
1622     const ByteString aSubstName( aOut.maSearchName, RTL_TEXTENCODING_UTF8 );
1623     printf( "FcPreMatchSubstititution \"%s\" bipw=%d%d%d%d -> ",
1624         aOrigName.GetBuffer(), rFontSelData.meWeight, rFontSelData.meItalic,
1625         rFontSelData.mePitch, rFontSelData.meWidthType );
1626     if( !bHaveSubstitute )
1627         printf( "no substitute available\n" );
1628     else
1629         printf( "\"%s\" bipw=%d%d%d%d\n", aSubstName.GetBuffer(),
1630 	    aOut.meWeight, aOut.meItalic, aOut.mePitch, aOut.meWidthType );
1631 #endif
1632 
1633     if( bHaveSubstitute )
1634         rFontSelData = aOut;
1635 
1636     return bHaveSubstitute;
1637 }
1638 
1639 // -----------------------------------------------------------------------
1640 
1641 bool FcGlyphFallbackSubstititution::FindFontSubstitute( ImplFontSelectData& rFontSelData,
1642     rtl::OUString& rMissingCodes ) const
1643 {
1644     // We dont' actually want to talk to Fontconfig at all for symbol fonts
1645     if( rFontSelData.IsSymbolFont() )
1646 	return false;
1647     // StarSymbol is a unicode font, but it still deserves the symbol flag
1648     if( 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "starsymbol", 10)
1649     ||  0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "opensymbol", 10) )
1650         return false;
1651 
1652     const ImplFontSelectData aOut = GetFcSubstitute( rFontSelData, rMissingCodes );
1653     // TODO: cache the unicode + srcfont specific result
1654     // FC doing it would be preferable because it knows the invariables
1655     // e.g. FC knows the FC rule that all Arial gets replaced by LiberationSans
1656     // whereas we would have to check for every size or attribute
1657     if( !aOut.maSearchName.Len() )
1658         return false;
1659 
1660     const bool bHaveSubstitute = !uselessmatch( rFontSelData, aOut );
1661 
1662 #ifdef DEBUG
1663     const ByteString aOrigName( rFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 );
1664     const ByteString aSubstName( aOut.maSearchName, RTL_TEXTENCODING_UTF8 );
1665     printf( "FcGFSubstititution \"%s\" bipw=%d%d%d%d ->",
1666         aOrigName.GetBuffer(), rFontSelData.meWeight, rFontSelData.meItalic,
1667         rFontSelData.mePitch, rFontSelData.meWidthType );
1668     if( !bHaveSubstitute )
1669         printf( "no substitute available\n" );
1670     else
1671         printf( "\"%s\" bipw=%d%d%d%d\n", aSubstName.GetBuffer(),
1672 	    aOut.meWeight, aOut.meItalic, aOut.mePitch, aOut.meWidthType );
1673 #endif
1674 
1675     if( bHaveSubstitute )
1676         rFontSelData = aOut;
1677 
1678     return bHaveSubstitute;
1679 }
1680 
1681 // ===========================================================================
1682 
1683