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