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