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