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