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