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