1 2 /* 3 * Copyright 2006 The Android Open Source Project 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 #include <vector> 10 #ifdef SK_BUILD_FOR_MAC 11 #import <ApplicationServices/ApplicationServices.h> 12 #endif 13 14 #ifdef SK_BUILD_FOR_IOS 15 #include <CoreText/CoreText.h> 16 #include <CoreGraphics/CoreGraphics.h> 17 #include <CoreFoundation/CoreFoundation.h> 18 #endif 19 20 #include "SkFontHost.h" 21 #include "SkCGUtils.h" 22 #include "SkColorPriv.h" 23 #include "SkDescriptor.h" 24 #include "SkEndian.h" 25 #include "SkFontDescriptor.h" 26 #include "SkFloatingPoint.h" 27 #include "SkGlyph.h" 28 #include "SkMaskGamma.h" 29 #include "SkSFNTHeader.h" 30 #include "SkOTTable_glyf.h" 31 #include "SkOTTable_head.h" 32 #include "SkOTTable_hhea.h" 33 #include "SkOTTable_loca.h" 34 #include "SkOTUtils.h" 35 #include "SkPaint.h" 36 #include "SkPath.h" 37 #include "SkString.h" 38 #include "SkStream.h" 39 #include "SkThread.h" 40 #include "SkTypeface_mac.h" 41 #include "SkUtils.h" 42 #include "SkTypefaceCache.h" 43 44 class SkScalerContext_Mac; 45 46 // Being templated and taking const T* prevents calling 47 // CFSafeRelease(autoCFRelease) through implicit conversion. 48 template <typename T> static void CFSafeRelease(/*CFTypeRef*/const T* cfTypeRef) { 49 if (cfTypeRef) { 50 CFRelease(cfTypeRef); 51 } 52 } 53 54 // Being templated and taking const T* prevents calling 55 // CFSafeRetain(autoCFRelease) through implicit conversion. 56 template <typename T> static void CFSafeRetain(/*CFTypeRef*/const T* cfTypeRef) { 57 if (cfTypeRef) { 58 CFRetain(cfTypeRef); 59 } 60 } 61 62 /** Acts like a CFRef, but calls CFSafeRelease when it goes out of scope. */ 63 template<typename CFRef> class AutoCFRelease : private SkNoncopyable { 64 public: 65 explicit AutoCFRelease(CFRef cfRef = NULL) : fCFRef(cfRef) { } 66 ~AutoCFRelease() { CFSafeRelease(fCFRef); } 67 68 void reset(CFRef that = NULL) { 69 CFSafeRetain(that); 70 CFSafeRelease(fCFRef); 71 fCFRef = that; 72 } 73 74 AutoCFRelease& operator =(CFRef that) { 75 reset(that); 76 return *this; 77 } 78 79 operator CFRef() const { return fCFRef; } 80 CFRef get() const { return fCFRef; } 81 82 private: 83 CFRef fCFRef; 84 }; 85 86 template<typename T> class AutoCGTable : SkNoncopyable { 87 public: 88 AutoCGTable(CGFontRef font) 89 //Undocumented: the tag parameter in this call is expected in machine order and not BE order. 90 : fCFData(CGFontCopyTableForTag(font, SkSetFourByteTag(T::TAG0, T::TAG1, T::TAG2, T::TAG3))) 91 , fData(fCFData ? reinterpret_cast<const T*>(CFDataGetBytePtr(fCFData)) : NULL) 92 { } 93 94 const T* operator->() const { return fData; } 95 96 private: 97 AutoCFRelease<CFDataRef> fCFData; 98 public: 99 const T* fData; 100 }; 101 102 // inline versions of these rect helpers 103 104 static bool CGRectIsEmpty_inline(const CGRect& rect) { 105 return rect.size.width <= 0 || rect.size.height <= 0; 106 } 107 108 static void CGRectInset_inline(CGRect* rect, CGFloat dx, CGFloat dy) { 109 rect->origin.x += dx; 110 rect->origin.y += dy; 111 rect->size.width -= dx * 2; 112 rect->size.height -= dy * 2; 113 } 114 115 static CGFloat CGRectGetMinX_inline(const CGRect& rect) { 116 return rect.origin.x; 117 } 118 119 static CGFloat CGRectGetMaxX_inline(const CGRect& rect) { 120 return rect.origin.x + rect.size.width; 121 } 122 123 static CGFloat CGRectGetMinY_inline(const CGRect& rect) { 124 return rect.origin.y; 125 } 126 127 static CGFloat CGRectGetMaxY_inline(const CGRect& rect) { 128 return rect.origin.y + rect.size.height; 129 } 130 131 static CGFloat CGRectGetWidth_inline(const CGRect& rect) { 132 return rect.size.width; 133 } 134 135 /////////////////////////////////////////////////////////////////////////////// 136 137 static void sk_memset_rect32(uint32_t* ptr, uint32_t value, 138 size_t width, size_t height, size_t rowBytes) { 139 SkASSERT(width); 140 SkASSERT(width * sizeof(uint32_t) <= rowBytes); 141 142 if (width >= 32) { 143 while (height) { 144 sk_memset32(ptr, value, width); 145 ptr = (uint32_t*)((char*)ptr + rowBytes); 146 height -= 1; 147 } 148 return; 149 } 150 151 rowBytes -= width * sizeof(uint32_t); 152 153 if (width >= 8) { 154 while (height) { 155 int w = width; 156 do { 157 *ptr++ = value; *ptr++ = value; 158 *ptr++ = value; *ptr++ = value; 159 *ptr++ = value; *ptr++ = value; 160 *ptr++ = value; *ptr++ = value; 161 w -= 8; 162 } while (w >= 8); 163 while (--w >= 0) { 164 *ptr++ = value; 165 } 166 ptr = (uint32_t*)((char*)ptr + rowBytes); 167 height -= 1; 168 } 169 } else { 170 while (height) { 171 int w = width; 172 do { 173 *ptr++ = value; 174 } while (--w > 0); 175 ptr = (uint32_t*)((char*)ptr + rowBytes); 176 height -= 1; 177 } 178 } 179 } 180 181 #include <sys/utsname.h> 182 183 typedef uint32_t CGRGBPixel; 184 185 static unsigned CGRGBPixel_getAlpha(CGRGBPixel pixel) { 186 return pixel & 0xFF; 187 } 188 189 // The calls to support subpixel are present in 10.5, but are not included in 190 // the 10.5 SDK. The needed calls have been extracted from the 10.6 SDK and are 191 // included below. To verify that CGContextSetShouldSubpixelQuantizeFonts, for 192 // instance, is present in the 10.5 CoreGraphics libary, use: 193 // cd /Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/ 194 // cd ApplicationServices.framework/Frameworks/CoreGraphics.framework/ 195 // nm CoreGraphics | grep CGContextSetShouldSubpixelQuantizeFonts 196 197 #if !defined(MAC_OS_X_VERSION_10_6) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6) 198 CG_EXTERN void CGContextSetAllowsFontSmoothing(CGContextRef context, bool value); 199 CG_EXTERN void CGContextSetAllowsFontSubpixelPositioning(CGContextRef context, bool value); 200 CG_EXTERN void CGContextSetShouldSubpixelPositionFonts(CGContextRef context, bool value); 201 CG_EXTERN void CGContextSetAllowsFontSubpixelQuantization(CGContextRef context, bool value); 202 CG_EXTERN void CGContextSetShouldSubpixelQuantizeFonts(CGContextRef context, bool value); 203 #endif 204 205 static const char FONT_DEFAULT_NAME[] = "Lucida Sans"; 206 207 // See Source/WebKit/chromium/base/mac/mac_util.mm DarwinMajorVersionInternal for original source. 208 static int readVersion() { 209 struct utsname info; 210 if (uname(&info) != 0) { 211 SkDebugf("uname failed\n"); 212 return 0; 213 } 214 if (strcmp(info.sysname, "Darwin") != 0) { 215 SkDebugf("unexpected uname sysname %s\n", info.sysname); 216 return 0; 217 } 218 char* dot = strchr(info.release, '.'); 219 if (!dot) { 220 SkDebugf("expected dot in uname release %s\n", info.release); 221 return 0; 222 } 223 int version = atoi(info.release); 224 if (version == 0) { 225 SkDebugf("could not parse uname release %s\n", info.release); 226 } 227 return version; 228 } 229 230 static int darwinVersion() { 231 static int darwin_version = readVersion(); 232 return darwin_version; 233 } 234 235 static bool isLeopard() { 236 return darwinVersion() == 9; 237 } 238 239 static bool isSnowLeopard() { 240 return darwinVersion() == 10; 241 } 242 243 static bool isLion() { 244 return darwinVersion() == 11; 245 } 246 247 static bool isMountainLion() { 248 return darwinVersion() == 12; 249 } 250 251 static bool isLCDFormat(unsigned format) { 252 return SkMask::kLCD16_Format == format || SkMask::kLCD32_Format == format; 253 } 254 255 static CGFloat ScalarToCG(SkScalar scalar) { 256 if (sizeof(CGFloat) == sizeof(float)) { 257 return SkScalarToFloat(scalar); 258 } else { 259 SkASSERT(sizeof(CGFloat) == sizeof(double)); 260 return (CGFloat) SkScalarToDouble(scalar); 261 } 262 } 263 264 static SkScalar CGToScalar(CGFloat cgFloat) { 265 if (sizeof(CGFloat) == sizeof(float)) { 266 return SkFloatToScalar(cgFloat); 267 } else { 268 SkASSERT(sizeof(CGFloat) == sizeof(double)); 269 return SkDoubleToScalar(cgFloat); 270 } 271 } 272 273 static CGAffineTransform MatrixToCGAffineTransform(const SkMatrix& matrix, 274 SkScalar sx = SK_Scalar1, 275 SkScalar sy = SK_Scalar1) { 276 return CGAffineTransformMake( ScalarToCG(matrix[SkMatrix::kMScaleX] * sx), 277 -ScalarToCG(matrix[SkMatrix::kMSkewY] * sy), 278 -ScalarToCG(matrix[SkMatrix::kMSkewX] * sx), 279 ScalarToCG(matrix[SkMatrix::kMScaleY] * sy), 280 ScalarToCG(matrix[SkMatrix::kMTransX] * sx), 281 ScalarToCG(matrix[SkMatrix::kMTransY] * sy)); 282 } 283 284 static SkScalar getFontScale(CGFontRef cgFont) { 285 int unitsPerEm = CGFontGetUnitsPerEm(cgFont); 286 return SkScalarInvert(SkIntToScalar(unitsPerEm)); 287 } 288 289 /////////////////////////////////////////////////////////////////////////////// 290 291 #define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host) 292 #define BITMAP_INFO_GRAY (kCGImageAlphaNone) 293 294 /** 295 * There does not appear to be a publicly accessable API for determining if lcd 296 * font smoothing will be applied if we request it. The main issue is that if 297 * smoothing is applied a gamma of 2.0 will be used, if not a gamma of 1.0. 298 */ 299 static bool supports_LCD() { 300 static int gSupportsLCD = -1; 301 if (gSupportsLCD >= 0) { 302 return (bool) gSupportsLCD; 303 } 304 uint32_t rgb = 0; 305 AutoCFRelease<CGColorSpaceRef> colorspace(CGColorSpaceCreateDeviceRGB()); 306 AutoCFRelease<CGContextRef> cgContext(CGBitmapContextCreate(&rgb, 1, 1, 8, 4, 307 colorspace, BITMAP_INFO_RGB)); 308 CGContextSelectFont(cgContext, "Helvetica", 16, kCGEncodingMacRoman); 309 CGContextSetShouldSmoothFonts(cgContext, true); 310 CGContextSetShouldAntialias(cgContext, true); 311 CGContextSetTextDrawingMode(cgContext, kCGTextFill); 312 CGContextSetGrayFillColor(cgContext, 1, 1); 313 CGContextShowTextAtPoint(cgContext, -1, 0, "|", 1); 314 uint32_t r = (rgb >> 16) & 0xFF; 315 uint32_t g = (rgb >> 8) & 0xFF; 316 uint32_t b = (rgb >> 0) & 0xFF; 317 gSupportsLCD = (r != g || r != b); 318 return (bool) gSupportsLCD; 319 } 320 321 class Offscreen { 322 public: 323 Offscreen(); 324 325 CGRGBPixel* getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph, 326 CGGlyph glyphID, size_t* rowBytesPtr, 327 bool generateA8FromLCD); 328 329 private: 330 enum { 331 kSize = 32 * 32 * sizeof(CGRGBPixel) 332 }; 333 SkAutoSMalloc<kSize> fImageStorage; 334 AutoCFRelease<CGColorSpaceRef> fRGBSpace; 335 336 // cached state 337 AutoCFRelease<CGContextRef> fCG; 338 SkISize fSize; 339 bool fDoAA; 340 bool fDoLCD; 341 342 static int RoundSize(int dimension) { 343 return SkNextPow2(dimension); 344 } 345 }; 346 347 Offscreen::Offscreen() : fRGBSpace(NULL), fCG(NULL) { 348 fSize.set(0, 0); 349 } 350 351 /////////////////////////////////////////////////////////////////////////////// 352 353 static SkTypeface::Style computeStyleBits(CTFontRef font, bool* isMonospace) { 354 unsigned style = SkTypeface::kNormal; 355 CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(font); 356 357 if (traits & kCTFontBoldTrait) { 358 style |= SkTypeface::kBold; 359 } 360 if (traits & kCTFontItalicTrait) { 361 style |= SkTypeface::kItalic; 362 } 363 if (isMonospace) { 364 *isMonospace = (traits & kCTFontMonoSpaceTrait) != 0; 365 } 366 return (SkTypeface::Style)style; 367 } 368 369 static SkFontID CTFontRef_to_SkFontID(CTFontRef fontRef) { 370 SkFontID id = 0; 371 // CTFontGetPlatformFont and ATSFontRef are not supported on iOS, so we have to 372 // bracket this to be Mac only. 373 #ifdef SK_BUILD_FOR_MAC 374 ATSFontRef ats = CTFontGetPlatformFont(fontRef, NULL); 375 id = (SkFontID)ats; 376 if (id != 0) { 377 id &= 0x3FFFFFFF; // make top two bits 00 378 return id; 379 } 380 #endif 381 // CTFontGetPlatformFont returns NULL if the font is local 382 // (e.g., was created by a CSS3 @font-face rule). 383 AutoCFRelease<CGFontRef> cgFont(CTFontCopyGraphicsFont(fontRef, NULL)); 384 AutoCGTable<SkOTTableHead> headTable(cgFont); 385 if (headTable.fData) { 386 id = (SkFontID) headTable->checksumAdjustment; 387 id = (id & 0x3FFFFFFF) | 0x40000000; // make top two bits 01 388 } 389 // well-formed fonts have checksums, but as a last resort, use the pointer. 390 if (id == 0) { 391 id = (SkFontID) (uintptr_t) fontRef; 392 id = (id & 0x3FFFFFFF) | 0x80000000; // make top two bits 10 393 } 394 return id; 395 } 396 397 class SkTypeface_Mac : public SkTypeface { 398 public: 399 SkTypeface_Mac(SkTypeface::Style style, SkFontID fontID, bool isMonospace, 400 CTFontRef fontRef, const char name[]) 401 : SkTypeface(style, fontID, isMonospace) 402 , fName(name) 403 , fFontRef(fontRef) // caller has already called CFRetain for us 404 { 405 SkASSERT(fontRef); 406 } 407 408 SkString fName; 409 AutoCFRelease<CTFontRef> fFontRef; 410 }; 411 412 static CTFontRef typeface_to_fontref(const SkTypeface* face) { 413 const SkTypeface_Mac* macface = reinterpret_cast<const SkTypeface_Mac*>(face); 414 return macface->fFontRef; 415 } 416 417 static SkTypeface* NewFromFontRef(CTFontRef fontRef, const char name[]) { 418 SkASSERT(fontRef); 419 bool isMonospace; 420 SkTypeface::Style style = computeStyleBits(fontRef, &isMonospace); 421 SkFontID fontID = CTFontRef_to_SkFontID(fontRef); 422 423 return new SkTypeface_Mac(style, fontID, isMonospace, fontRef, name); 424 } 425 426 static SkTypeface* NewFromName(const char familyName[], SkTypeface::Style theStyle) { 427 CTFontRef ctFont = NULL; 428 429 CTFontSymbolicTraits ctFontTraits = 0; 430 if (theStyle & SkTypeface::kBold) { 431 ctFontTraits |= kCTFontBoldTrait; 432 } 433 if (theStyle & SkTypeface::kItalic) { 434 ctFontTraits |= kCTFontItalicTrait; 435 } 436 437 // Create the font info 438 AutoCFRelease<CFStringRef> cfFontName( 439 CFStringCreateWithCString(NULL, familyName, kCFStringEncodingUTF8)); 440 441 AutoCFRelease<CFNumberRef> cfFontTraits( 442 CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &ctFontTraits)); 443 444 AutoCFRelease<CFMutableDictionaryRef> cfAttributes( 445 CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 446 &kCFTypeDictionaryKeyCallBacks, 447 &kCFTypeDictionaryValueCallBacks)); 448 449 AutoCFRelease<CFMutableDictionaryRef> cfTraits( 450 CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 451 &kCFTypeDictionaryKeyCallBacks, 452 &kCFTypeDictionaryValueCallBacks)); 453 454 // Create the font 455 if (cfFontName != NULL && cfFontTraits != NULL && cfAttributes != NULL && cfTraits != NULL) { 456 CFDictionaryAddValue(cfTraits, kCTFontSymbolicTrait, cfFontTraits); 457 458 CFDictionaryAddValue(cfAttributes, kCTFontFamilyNameAttribute, cfFontName); 459 CFDictionaryAddValue(cfAttributes, kCTFontTraitsAttribute, cfTraits); 460 461 AutoCFRelease<CTFontDescriptorRef> ctFontDesc( 462 CTFontDescriptorCreateWithAttributes(cfAttributes)); 463 464 if (ctFontDesc != NULL) { 465 if (isLeopard()) { 466 // CTFontCreateWithFontDescriptor on Leopard ignores the name 467 AutoCFRelease<CTFontRef> ctNamed(CTFontCreateWithName(cfFontName, 1, NULL)); 468 ctFont = CTFontCreateCopyWithAttributes(ctNamed, 1, NULL, ctFontDesc); 469 } else { 470 ctFont = CTFontCreateWithFontDescriptor(ctFontDesc, 0, NULL); 471 } 472 } 473 } 474 475 return ctFont ? NewFromFontRef(ctFont, familyName) : NULL; 476 } 477 478 static CTFontRef GetFontRefFromFontID(SkFontID fontID) { 479 SkTypeface_Mac* face = reinterpret_cast<SkTypeface_Mac*>(SkTypefaceCache::FindByID(fontID)); 480 return face ? face->fFontRef.get() : NULL; 481 } 482 483 static SkTypeface* GetDefaultFace() { 484 SK_DECLARE_STATIC_MUTEX(gMutex); 485 SkAutoMutexAcquire ma(gMutex); 486 487 static SkTypeface* gDefaultFace; 488 489 if (NULL == gDefaultFace) { 490 gDefaultFace = NewFromName(FONT_DEFAULT_NAME, SkTypeface::kNormal); 491 SkTypefaceCache::Add(gDefaultFace, SkTypeface::kNormal); 492 } 493 return gDefaultFace; 494 } 495 496 /////////////////////////////////////////////////////////////////////////////// 497 498 extern CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face); 499 CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face) { 500 const SkTypeface_Mac* macface = (const SkTypeface_Mac*)face; 501 return macface ? macface->fFontRef.get() : NULL; 502 } 503 504 /* This function is visible on the outside. It first searches the cache, and if 505 * not found, returns a new entry (after adding it to the cache). 506 */ 507 SkTypeface* SkCreateTypefaceFromCTFont(CTFontRef fontRef) { 508 SkFontID fontID = CTFontRef_to_SkFontID(fontRef); 509 SkTypeface* face = SkTypefaceCache::FindByID(fontID); 510 if (face) { 511 face->ref(); 512 } else { 513 face = NewFromFontRef(fontRef, NULL); 514 SkTypefaceCache::Add(face, face->style()); 515 // NewFromFontRef doesn't retain the parameter, but the typeface it 516 // creates does release it in its destructor, so we balance that with 517 // a retain call here. 518 CFRetain(fontRef); 519 } 520 SkASSERT(face->getRefCnt() > 1); 521 return face; 522 } 523 524 struct NameStyleRec { 525 const char* fName; 526 SkTypeface::Style fStyle; 527 }; 528 529 static bool FindByNameStyle(SkTypeface* face, SkTypeface::Style style, 530 void* ctx) { 531 const SkTypeface_Mac* mface = reinterpret_cast<SkTypeface_Mac*>(face); 532 const NameStyleRec* rec = reinterpret_cast<const NameStyleRec*>(ctx); 533 534 return rec->fStyle == style && mface->fName.equals(rec->fName); 535 } 536 537 static const char* map_css_names(const char* name) { 538 static const struct { 539 const char* fFrom; // name the caller specified 540 const char* fTo; // "canonical" name we map to 541 } gPairs[] = { 542 { "sans-serif", "Helvetica" }, 543 { "serif", "Times" }, 544 { "monospace", "Courier" } 545 }; 546 547 for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) { 548 if (strcmp(name, gPairs[i].fFrom) == 0) { 549 return gPairs[i].fTo; 550 } 551 } 552 return name; // no change 553 } 554 555 SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, 556 const char familyName[], 557 SkTypeface::Style style) { 558 if (familyName) { 559 familyName = map_css_names(familyName); 560 } 561 562 // Clone an existing typeface 563 // TODO: only clone if style matches the familyFace's style... 564 if (familyName == NULL && familyFace != NULL) { 565 familyFace->ref(); 566 return const_cast<SkTypeface*>(familyFace); 567 } 568 569 if (!familyName || !*familyName) { 570 familyName = FONT_DEFAULT_NAME; 571 } 572 573 NameStyleRec rec = { familyName, style }; 574 SkTypeface* face = SkTypefaceCache::FindByProcAndRef(FindByNameStyle, &rec); 575 576 if (NULL == face) { 577 face = NewFromName(familyName, style); 578 if (face) { 579 SkTypefaceCache::Add(face, style); 580 } else { 581 face = GetDefaultFace(); 582 face->ref(); 583 } 584 } 585 return face; 586 } 587 588 static void flip(SkMatrix* matrix) { 589 matrix->setSkewX(-matrix->getSkewX()); 590 matrix->setSkewY(-matrix->getSkewY()); 591 } 592 593 /////////////////////////////////////////////////////////////////////////////// 594 595 struct GlyphRect { 596 int16_t fMinX; 597 int16_t fMinY; 598 int16_t fMaxX; 599 int16_t fMaxY; 600 }; 601 602 class SkScalerContext_Mac : public SkScalerContext { 603 public: 604 SkScalerContext_Mac(const SkDescriptor* desc); 605 virtual ~SkScalerContext_Mac(void); 606 607 608 protected: 609 unsigned generateGlyphCount(void) SK_OVERRIDE; 610 uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE; 611 void generateAdvance(SkGlyph* glyph) SK_OVERRIDE; 612 void generateMetrics(SkGlyph* glyph) SK_OVERRIDE; 613 void generateImage(const SkGlyph& glyph) SK_OVERRIDE; 614 void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE; 615 void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY) SK_OVERRIDE; 616 617 private: 618 static void CTPathElement(void *info, const CGPathElement *element); 619 uint16_t getFBoundingBoxesGlyphOffset(); 620 void getVerticalOffset(CGGlyph glyphID, SkIPoint* offset) const; 621 bool generateBBoxes(); 622 623 CGAffineTransform fTransform; 624 SkMatrix fUnitMatrix; // without font size 625 SkMatrix fVerticalMatrix; // unit rotated 626 SkMatrix fMatrix; // with font size 627 SkMatrix fFBoundingBoxesMatrix; // lion-specific fix 628 Offscreen fOffscreen; 629 AutoCFRelease<CTFontRef> fCTFont; 630 AutoCFRelease<CTFontRef> fCTVerticalFont; // for vertical advance 631 AutoCFRelease<CGFontRef> fCGFont; 632 GlyphRect* fFBoundingBoxes; 633 uint16_t fFBoundingBoxesGlyphOffset; 634 uint16_t fGlyphCount; 635 bool fGeneratedFBoundingBoxes; 636 bool fDoSubPosition; 637 bool fVertical; 638 639 friend class Offscreen; 640 }; 641 642 SkScalerContext_Mac::SkScalerContext_Mac(const SkDescriptor* desc) 643 : SkScalerContext(desc) 644 , fFBoundingBoxes(NULL) 645 , fFBoundingBoxesGlyphOffset(0) 646 , fGeneratedFBoundingBoxes(false) 647 { 648 CTFontRef ctFont = GetFontRefFromFontID(fRec.fFontID); 649 CFIndex numGlyphs = CTFontGetGlyphCount(ctFont); 650 651 // Get the state we need 652 fRec.getSingleMatrix(&fMatrix); 653 fUnitMatrix = fMatrix; 654 655 // extract the font size out of the matrix, but leave the skewing for italic 656 SkScalar reciprocal = SkScalarInvert(fRec.fTextSize); 657 fUnitMatrix.preScale(reciprocal, reciprocal); 658 659 SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF); 660 661 fTransform = MatrixToCGAffineTransform(fMatrix); 662 663 CGAffineTransform transform; 664 CGFloat unitFontSize; 665 if (isLeopard()) { 666 // passing 1 for pointSize to Leopard sets the font size to 1 pt. 667 // pass the CoreText size explicitly 668 transform = MatrixToCGAffineTransform(fUnitMatrix); 669 unitFontSize = SkScalarToFloat(fRec.fTextSize); 670 } else { 671 // since our matrix includes everything, we pass 1 for pointSize 672 transform = fTransform; 673 unitFontSize = 1; 674 } 675 flip(&fUnitMatrix); // flip to fix up bounds later 676 fVertical = SkToBool(fRec.fFlags & kVertical_Flag); 677 AutoCFRelease<CTFontDescriptorRef> ctFontDesc; 678 if (fVertical) { 679 AutoCFRelease<CFMutableDictionaryRef> cfAttributes(CFDictionaryCreateMutable( 680 kCFAllocatorDefault, 0, 681 &kCFTypeDictionaryKeyCallBacks, 682 &kCFTypeDictionaryValueCallBacks)); 683 if (cfAttributes) { 684 CTFontOrientation ctOrientation = kCTFontVerticalOrientation; 685 AutoCFRelease<CFNumberRef> cfVertical(CFNumberCreate( 686 kCFAllocatorDefault, kCFNumberSInt32Type, &ctOrientation)); 687 CFDictionaryAddValue(cfAttributes, kCTFontOrientationAttribute, cfVertical); 688 ctFontDesc = CTFontDescriptorCreateWithAttributes(cfAttributes); 689 } 690 } 691 fCTFont = CTFontCreateCopyWithAttributes(ctFont, unitFontSize, &transform, ctFontDesc); 692 fCGFont = CTFontCopyGraphicsFont(fCTFont, NULL); 693 if (fVertical) { 694 CGAffineTransform rotateLeft = CGAffineTransformMake(0, -1, 1, 0, 0, 0); 695 transform = CGAffineTransformConcat(rotateLeft, transform); 696 fCTVerticalFont = CTFontCreateCopyWithAttributes(ctFont, unitFontSize, &transform, NULL); 697 fVerticalMatrix = fUnitMatrix; 698 if (isSnowLeopard()) { 699 SkScalar scale = SkScalarMul(fRec.fTextSize, getFontScale(fCGFont)); 700 fVerticalMatrix.preScale(scale, scale); 701 } else { 702 fVerticalMatrix.preRotate(SkIntToScalar(90)); 703 } 704 fVerticalMatrix.postScale(SK_Scalar1, -SK_Scalar1); 705 } 706 fGlyphCount = SkToU16(numGlyphs); 707 fDoSubPosition = SkToBool(fRec.fFlags & kSubpixelPositioning_Flag); 708 } 709 710 SkScalerContext_Mac::~SkScalerContext_Mac() { 711 delete[] fFBoundingBoxes; 712 } 713 714 CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph, 715 CGGlyph glyphID, size_t* rowBytesPtr, 716 bool generateA8FromLCD) { 717 if (!fRGBSpace) { 718 //It doesn't appear to matter what color space is specified. 719 //Regular blends and antialiased text are always (s*a + d*(1-a)) 720 //and smoothed text is always g=2.0. 721 fRGBSpace = CGColorSpaceCreateDeviceRGB(); 722 } 723 724 // default to kBW_Format 725 bool doAA = false; 726 bool doLCD = false; 727 728 if (SkMask::kBW_Format != glyph.fMaskFormat) { 729 doLCD = true; 730 doAA = true; 731 } 732 733 // FIXME: lcd smoothed un-hinted rasterization unsupported. 734 if (!generateA8FromLCD && SkMask::kA8_Format == glyph.fMaskFormat) { 735 doLCD = false; 736 doAA = true; 737 } 738 739 size_t rowBytes = fSize.fWidth * sizeof(CGRGBPixel); 740 if (!fCG || fSize.fWidth < glyph.fWidth || fSize.fHeight < glyph.fHeight) { 741 if (fSize.fWidth < glyph.fWidth) { 742 fSize.fWidth = RoundSize(glyph.fWidth); 743 } 744 if (fSize.fHeight < glyph.fHeight) { 745 fSize.fHeight = RoundSize(glyph.fHeight); 746 } 747 748 rowBytes = fSize.fWidth * sizeof(CGRGBPixel); 749 void* image = fImageStorage.reset(rowBytes * fSize.fHeight); 750 fCG = CGBitmapContextCreate(image, fSize.fWidth, fSize.fHeight, 8, 751 rowBytes, fRGBSpace, BITMAP_INFO_RGB); 752 753 // skia handles quantization itself, so we disable this for cg to get 754 // full fractional data from them. 755 CGContextSetAllowsFontSubpixelQuantization(fCG, false); 756 CGContextSetShouldSubpixelQuantizeFonts(fCG, false); 757 758 CGContextSetTextDrawingMode(fCG, kCGTextFill); 759 CGContextSetFont(fCG, context.fCGFont); 760 CGContextSetFontSize(fCG, 1); 761 CGContextSetTextMatrix(fCG, context.fTransform); 762 763 CGContextSetAllowsFontSubpixelPositioning(fCG, context.fDoSubPosition); 764 CGContextSetShouldSubpixelPositionFonts(fCG, context.fDoSubPosition); 765 766 // Draw white on black to create mask. 767 // TODO: Draw black on white and invert, CG has a special case codepath. 768 CGContextSetGrayFillColor(fCG, 1.0f, 1.0f); 769 770 // force our checks below to happen 771 fDoAA = !doAA; 772 fDoLCD = !doLCD; 773 } 774 775 if (fDoAA != doAA) { 776 CGContextSetShouldAntialias(fCG, doAA); 777 fDoAA = doAA; 778 } 779 if (fDoLCD != doLCD) { 780 CGContextSetShouldSmoothFonts(fCG, doLCD); 781 fDoLCD = doLCD; 782 } 783 784 CGRGBPixel* image = (CGRGBPixel*)fImageStorage.get(); 785 // skip rows based on the glyph's height 786 image += (fSize.fHeight - glyph.fHeight) * fSize.fWidth; 787 788 // erase to black 789 sk_memset_rect32(image, 0, glyph.fWidth, glyph.fHeight, rowBytes); 790 791 float subX = 0; 792 float subY = 0; 793 if (context.fDoSubPosition) { 794 subX = SkFixedToFloat(glyph.getSubXFixed()); 795 subY = SkFixedToFloat(glyph.getSubYFixed()); 796 } 797 if (context.fVertical) { 798 SkIPoint offset; 799 context.getVerticalOffset(glyphID, &offset); 800 subX += offset.fX; 801 subY += offset.fY; 802 } 803 CGContextShowGlyphsAtPoint(fCG, -glyph.fLeft + subX, 804 glyph.fTop + glyph.fHeight - subY, 805 &glyphID, 1); 806 807 SkASSERT(rowBytesPtr); 808 *rowBytesPtr = rowBytes; 809 return image; 810 } 811 812 void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkIPoint* offset) const { 813 CGSize vertOffset; 814 CTFontGetVerticalTranslationsForGlyphs(fCTVerticalFont, &glyphID, &vertOffset, 1); 815 const SkPoint trans = {CGToScalar(vertOffset.width), 816 CGToScalar(vertOffset.height)}; 817 SkPoint floatOffset; 818 fVerticalMatrix.mapPoints(&floatOffset, &trans, 1); 819 if (!isSnowLeopard()) { 820 // SnowLeopard fails to apply the font's matrix to the vertical metrics, 821 // but Lion and Leopard do. The unit matrix describes the font's matrix at 822 // point size 1. There may be some way to avoid mapping here by setting up 823 // fVerticalMatrix differently, but this works for now. 824 fUnitMatrix.mapPoints(&floatOffset, 1); 825 } 826 offset->fX = SkScalarRound(floatOffset.fX); 827 offset->fY = SkScalarRound(floatOffset.fY); 828 } 829 830 uint16_t SkScalerContext_Mac::getFBoundingBoxesGlyphOffset() { 831 if (fFBoundingBoxesGlyphOffset) { 832 return fFBoundingBoxesGlyphOffset; 833 } 834 fFBoundingBoxesGlyphOffset = fGlyphCount; // fallback for all fonts 835 AutoCGTable<SkOTTableHorizontalHeader> hheaTable(fCGFont); 836 if (hheaTable.fData) { 837 fFBoundingBoxesGlyphOffset = SkEndian_SwapBE16(hheaTable->numberOfHMetrics); 838 } 839 return fFBoundingBoxesGlyphOffset; 840 } 841 842 /* 843 * Lion has a bug in CTFontGetBoundingRectsForGlyphs which returns a bad value 844 * in theBounds.origin.x for fonts whose numOfLogHorMetrics is less than its 845 * glyph count. This workaround reads the glyph bounds from the font directly. 846 * 847 * The table is computed only if the font is a TrueType font, if the glyph 848 * value is >= fFBoundingBoxesGlyphOffset. (called only if fFBoundingBoxesGlyphOffset < fGlyphCount). 849 * 850 * TODO: A future optimization will compute fFBoundingBoxes once per CGFont, and 851 * compute fFBoundingBoxesMatrix once per font context. 852 */ 853 bool SkScalerContext_Mac::generateBBoxes() { 854 if (fGeneratedFBoundingBoxes) { 855 return NULL != fFBoundingBoxes; 856 } 857 fGeneratedFBoundingBoxes = true; 858 859 AutoCGTable<SkOTTableHead> headTable(fCGFont); 860 if (!headTable.fData) { 861 return false; 862 } 863 864 AutoCGTable<SkOTTableIndexToLocation> locaTable(fCGFont); 865 if (!locaTable.fData) { 866 return false; 867 } 868 869 AutoCGTable<SkOTTableGlyph> glyfTable(fCGFont); 870 if (!glyfTable.fData) { 871 return false; 872 } 873 874 uint16_t entries = fGlyphCount - fFBoundingBoxesGlyphOffset; 875 fFBoundingBoxes = new GlyphRect[entries]; 876 877 SkOTTableHead::IndexToLocFormat locaFormat = headTable->indexToLocFormat; 878 SkOTTableGlyph::Iterator glyphDataIter(*glyfTable.fData, *locaTable.fData, locaFormat); 879 glyphDataIter.advance(fFBoundingBoxesGlyphOffset); 880 for (uint16_t boundingBoxesIndex = 0; boundingBoxesIndex < entries; ++boundingBoxesIndex) { 881 const SkOTTableGlyphData* glyphData = glyphDataIter.next(); 882 GlyphRect& rect = fFBoundingBoxes[boundingBoxesIndex]; 883 rect.fMinX = SkEndian_SwapBE16(glyphData->xMin); 884 rect.fMinY = SkEndian_SwapBE16(glyphData->yMin); 885 rect.fMaxX = SkEndian_SwapBE16(glyphData->xMax); 886 rect.fMaxY = SkEndian_SwapBE16(glyphData->yMax); 887 } 888 fFBoundingBoxesMatrix = fMatrix; 889 flip(&fFBoundingBoxesMatrix); 890 SkScalar fontScale = getFontScale(fCGFont); 891 fFBoundingBoxesMatrix.preScale(fontScale, fontScale); 892 return true; 893 } 894 895 unsigned SkScalerContext_Mac::generateGlyphCount(void) { 896 return fGlyphCount; 897 } 898 899 uint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni) { 900 CGGlyph cgGlyph; 901 UniChar theChar; 902 903 // Validate our parameters and state 904 SkASSERT(uni <= 0x0000FFFF); 905 SkASSERT(sizeof(CGGlyph) <= sizeof(uint16_t)); 906 907 // Get the glyph 908 theChar = (UniChar) uni; 909 910 if (!CTFontGetGlyphsForCharacters(fCTFont, &theChar, &cgGlyph, 1)) { 911 cgGlyph = 0; 912 } 913 914 return cgGlyph; 915 } 916 917 void SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) { 918 this->generateMetrics(glyph); 919 } 920 921 void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) { 922 CGSize advance; 923 CGRect bounds; 924 CGGlyph cgGlyph; 925 926 // Get the state we need 927 cgGlyph = (CGGlyph) glyph->getGlyphID(fBaseGlyphCount); 928 929 if (fVertical) { 930 if (!isSnowLeopard()) { 931 // Lion and Leopard respect the vertical font metrics. 932 CTFontGetBoundingRectsForGlyphs(fCTVerticalFont, kCTFontVerticalOrientation, 933 &cgGlyph, &bounds, 1); 934 } else { 935 // Snow Leopard and earlier respect the vertical font metrics for 936 // advances, but not bounds, so use the default box and adjust it below. 937 CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontDefaultOrientation, 938 &cgGlyph, &bounds, 1); 939 } 940 CTFontGetAdvancesForGlyphs(fCTVerticalFont, kCTFontVerticalOrientation, 941 &cgGlyph, &advance, 1); 942 } else { 943 CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontDefaultOrientation, 944 &cgGlyph, &bounds, 1); 945 CTFontGetAdvancesForGlyphs(fCTFont, kCTFontDefaultOrientation, 946 &cgGlyph, &advance, 1); 947 } 948 949 // BUG? 950 // 0x200B (zero-advance space) seems to return a huge (garbage) bounds, when 951 // it should be empty. So, if we see a zero-advance, we check if it has an 952 // empty path or not, and if so, we jam the bounds to 0. Hopefully a zero-advance 953 // is rare, so we won't incur a big performance cost for this extra check. 954 if (0 == advance.width && 0 == advance.height) { 955 AutoCFRelease<CGPathRef> path(CTFontCreatePathForGlyph(fCTFont, cgGlyph, NULL)); 956 if (NULL == path || CGPathIsEmpty(path)) { 957 bounds = CGRectMake(0, 0, 0, 0); 958 } 959 } 960 961 glyph->zeroMetrics(); 962 glyph->fAdvanceX = SkFloatToFixed_Check(advance.width); 963 glyph->fAdvanceY = -SkFloatToFixed_Check(advance.height); 964 965 if (CGRectIsEmpty_inline(bounds)) { 966 return; 967 } 968 969 if (isLeopard() && !fVertical) { 970 // Leopard does not consider the matrix skew in its bounds. 971 // Run the bounding rectangle through the skew matrix to determine 972 // the true bounds. However, this doesn't work if the font is vertical. 973 // FIXME (Leopard): If the font has synthetic italic (e.g., matrix skew) 974 // and the font is vertical, the bounds need to be recomputed. 975 SkRect glyphBounds = SkRect::MakeXYWH( 976 bounds.origin.x, bounds.origin.y, 977 bounds.size.width, bounds.size.height); 978 fUnitMatrix.mapRect(&glyphBounds); 979 bounds.origin.x = glyphBounds.fLeft; 980 bounds.origin.y = glyphBounds.fTop; 981 bounds.size.width = glyphBounds.width(); 982 bounds.size.height = glyphBounds.height(); 983 } 984 // Adjust the bounds 985 // 986 // CTFontGetBoundingRectsForGlyphs ignores the font transform, so we need 987 // to transform the bounding box ourselves. 988 // 989 // The bounds are also expanded by 1 pixel, to give CG room for anti-aliasing. 990 CGRectInset_inline(&bounds, -1, -1); 991 992 // Get the metrics 993 bool lionAdjustedMetrics = false; 994 if (isLion() || isMountainLion()) { 995 if (cgGlyph < fGlyphCount && cgGlyph >= getFBoundingBoxesGlyphOffset() && generateBBoxes()){ 996 lionAdjustedMetrics = true; 997 SkRect adjust; 998 const GlyphRect& gRect = fFBoundingBoxes[cgGlyph - fFBoundingBoxesGlyphOffset]; 999 adjust.set(gRect.fMinX, gRect.fMinY, gRect.fMaxX, gRect.fMaxY); 1000 fFBoundingBoxesMatrix.mapRect(&adjust); 1001 bounds.origin.x = SkScalarToFloat(adjust.fLeft) - 1; 1002 bounds.origin.y = SkScalarToFloat(adjust.fTop) - 1; 1003 } 1004 // Lion returns fractions in the bounds 1005 glyph->fWidth = SkToU16(sk_float_ceil2int(bounds.size.width)); 1006 glyph->fHeight = SkToU16(sk_float_ceil2int(bounds.size.height)); 1007 } else { 1008 glyph->fWidth = SkToU16(sk_float_round2int(bounds.size.width)); 1009 glyph->fHeight = SkToU16(sk_float_round2int(bounds.size.height)); 1010 } 1011 glyph->fTop = SkToS16(-sk_float_round2int(CGRectGetMaxY_inline(bounds))); 1012 glyph->fLeft = SkToS16(sk_float_round2int(CGRectGetMinX_inline(bounds))); 1013 SkIPoint offset; 1014 if (fVertical && (isSnowLeopard() || lionAdjustedMetrics)) { 1015 // SnowLeopard doesn't respect vertical metrics, so compute them manually. 1016 // Also compute them for Lion when the metrics were computed by hand. 1017 getVerticalOffset(cgGlyph, &offset); 1018 glyph->fLeft += offset.fX; 1019 glyph->fTop += offset.fY; 1020 } 1021 } 1022 1023 #include "SkColorPriv.h" 1024 1025 static void build_power_table(uint8_t table[], float ee) { 1026 for (int i = 0; i < 256; i++) { 1027 float x = i / 255.f; 1028 x = sk_float_pow(x, ee); 1029 int xx = SkScalarRoundToInt(SkFloatToScalar(x * 255)); 1030 table[i] = SkToU8(xx); 1031 } 1032 } 1033 1034 /** 1035 * This will invert the gamma applied by CoreGraphics, so we can get linear 1036 * values. 1037 * 1038 * CoreGraphics obscurely defaults to 2.0 as the smoothing gamma value. 1039 * The color space used does not appear to affect this choice. 1040 */ 1041 static const uint8_t* getInverseGammaTableCoreGraphicSmoothing() { 1042 static bool gInited; 1043 static uint8_t gTableCoreGraphicsSmoothing[256]; 1044 if (!gInited) { 1045 build_power_table(gTableCoreGraphicsSmoothing, 2.0f); 1046 gInited = true; 1047 } 1048 return gTableCoreGraphicsSmoothing; 1049 } 1050 1051 static void cgpixels_to_bits(uint8_t dst[], const CGRGBPixel src[], int count) { 1052 while (count > 0) { 1053 uint8_t mask = 0; 1054 for (int i = 7; i >= 0; --i) { 1055 mask |= (CGRGBPixel_getAlpha(*src++) >> 7) << i; 1056 if (0 == --count) { 1057 break; 1058 } 1059 } 1060 *dst++ = mask; 1061 } 1062 } 1063 1064 template<bool APPLY_PREBLEND> 1065 static inline uint8_t rgb_to_a8(CGRGBPixel rgb, const uint8_t* table8) { 1066 U8CPU r = (rgb >> 16) & 0xFF; 1067 U8CPU g = (rgb >> 8) & 0xFF; 1068 U8CPU b = (rgb >> 0) & 0xFF; 1069 return sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8); 1070 } 1071 template<bool APPLY_PREBLEND> 1072 static void rgb_to_a8(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes, 1073 const SkGlyph& glyph, const uint8_t* table8) { 1074 const int width = glyph.fWidth; 1075 size_t dstRB = glyph.rowBytes(); 1076 uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage; 1077 1078 for (int y = 0; y < glyph.fHeight; y++) { 1079 for (int i = 0; i < width; ++i) { 1080 dst[i] = rgb_to_a8<APPLY_PREBLEND>(cgPixels[i], table8); 1081 } 1082 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes); 1083 dst += dstRB; 1084 } 1085 } 1086 1087 template<bool APPLY_PREBLEND> 1088 static inline uint16_t rgb_to_lcd16(CGRGBPixel rgb, const uint8_t* tableR, 1089 const uint8_t* tableG, 1090 const uint8_t* tableB) { 1091 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR); 1092 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG); 1093 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB); 1094 return SkPack888ToRGB16(r, g, b); 1095 } 1096 template<bool APPLY_PREBLEND> 1097 static void rgb_to_lcd16(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes, const SkGlyph& glyph, 1098 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) { 1099 const int width = glyph.fWidth; 1100 size_t dstRB = glyph.rowBytes(); 1101 uint16_t* SK_RESTRICT dst = (uint16_t*)glyph.fImage; 1102 1103 for (int y = 0; y < glyph.fHeight; y++) { 1104 for (int i = 0; i < width; i++) { 1105 dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(cgPixels[i], tableR, tableG, tableB); 1106 } 1107 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes); 1108 dst = (uint16_t*)((char*)dst + dstRB); 1109 } 1110 } 1111 1112 template<bool APPLY_PREBLEND> 1113 static inline uint32_t rgb_to_lcd32(CGRGBPixel rgb, const uint8_t* tableR, 1114 const uint8_t* tableG, 1115 const uint8_t* tableB) { 1116 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR); 1117 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG); 1118 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB); 1119 return SkPackARGB32(0xFF, r, g, b); 1120 } 1121 template<bool APPLY_PREBLEND> 1122 static void rgb_to_lcd32(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes, const SkGlyph& glyph, 1123 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) { 1124 const int width = glyph.fWidth; 1125 size_t dstRB = glyph.rowBytes(); 1126 uint32_t* SK_RESTRICT dst = (uint32_t*)glyph.fImage; 1127 for (int y = 0; y < glyph.fHeight; y++) { 1128 for (int i = 0; i < width; i++) { 1129 dst[i] = rgb_to_lcd32<APPLY_PREBLEND>(cgPixels[i], tableR, tableG, tableB); 1130 } 1131 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes); 1132 dst = (uint32_t*)((char*)dst + dstRB); 1133 } 1134 } 1135 1136 template <typename T> T* SkTAddByteOffset(T* ptr, size_t byteOffset) { 1137 return (T*)((char*)ptr + byteOffset); 1138 } 1139 1140 void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) { 1141 CGGlyph cgGlyph = (CGGlyph) glyph.getGlyphID(fBaseGlyphCount); 1142 1143 // FIXME: lcd smoothed un-hinted rasterization unsupported. 1144 bool generateA8FromLCD = fRec.getHinting() != SkPaint::kNo_Hinting; 1145 1146 // Draw the glyph 1147 size_t cgRowBytes; 1148 CGRGBPixel* cgPixels = fOffscreen.getCG(*this, glyph, cgGlyph, &cgRowBytes, generateA8FromLCD); 1149 if (cgPixels == NULL) { 1150 return; 1151 } 1152 1153 //TODO: see if drawing black on white and inverting is faster (at least in 1154 //lcd case) as core graphics appears to have special case code for drawing 1155 //black text. 1156 1157 // Fix the glyph 1158 const bool isLCD = isLCDFormat(glyph.fMaskFormat); 1159 if (isLCD || (glyph.fMaskFormat == SkMask::kA8_Format && supports_LCD() && generateA8FromLCD)) { 1160 const uint8_t* table = getInverseGammaTableCoreGraphicSmoothing(); 1161 1162 //Note that the following cannot really be integrated into the 1163 //pre-blend, since we may not be applying the pre-blend; when we aren't 1164 //applying the pre-blend it means that a filter wants linear anyway. 1165 //Other code may also be applying the pre-blend, so we'd need another 1166 //one with this and one without. 1167 CGRGBPixel* addr = cgPixels; 1168 for (int y = 0; y < glyph.fHeight; ++y) { 1169 for (int x = 0; x < glyph.fWidth; ++x) { 1170 int r = (addr[x] >> 16) & 0xFF; 1171 int g = (addr[x] >> 8) & 0xFF; 1172 int b = (addr[x] >> 0) & 0xFF; 1173 addr[x] = (table[r] << 16) | (table[g] << 8) | table[b]; 1174 } 1175 addr = SkTAddByteOffset(addr, cgRowBytes); 1176 } 1177 } 1178 1179 // Convert glyph to mask 1180 switch (glyph.fMaskFormat) { 1181 case SkMask::kLCD32_Format: { 1182 if (fPreBlend.isApplicable()) { 1183 rgb_to_lcd32<true>(cgPixels, cgRowBytes, glyph, 1184 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 1185 } else { 1186 rgb_to_lcd32<false>(cgPixels, cgRowBytes, glyph, 1187 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 1188 } 1189 } break; 1190 case SkMask::kLCD16_Format: { 1191 if (fPreBlend.isApplicable()) { 1192 rgb_to_lcd16<true>(cgPixels, cgRowBytes, glyph, 1193 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 1194 } else { 1195 rgb_to_lcd16<false>(cgPixels, cgRowBytes, glyph, 1196 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 1197 } 1198 } break; 1199 case SkMask::kA8_Format: { 1200 if (fPreBlend.isApplicable()) { 1201 rgb_to_a8<true>(cgPixels, cgRowBytes, glyph, fPreBlend.fG); 1202 } else { 1203 rgb_to_a8<false>(cgPixels, cgRowBytes, glyph, fPreBlend.fG); 1204 } 1205 } break; 1206 case SkMask::kBW_Format: { 1207 const int width = glyph.fWidth; 1208 size_t dstRB = glyph.rowBytes(); 1209 uint8_t* dst = (uint8_t*)glyph.fImage; 1210 for (int y = 0; y < glyph.fHeight; y++) { 1211 cgpixels_to_bits(dst, cgPixels, width); 1212 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes); 1213 dst += dstRB; 1214 } 1215 } break; 1216 default: 1217 SkDEBUGFAIL("unexpected mask format"); 1218 break; 1219 } 1220 } 1221 1222 /* 1223 * Our subpixel resolution is only 2 bits in each direction, so a scale of 4 1224 * seems sufficient, and possibly even correct, to allow the hinted outline 1225 * to be subpixel positioned. 1226 */ 1227 #define kScaleForSubPixelPositionHinting (4.0f) 1228 1229 void SkScalerContext_Mac::generatePath(const SkGlyph& glyph, SkPath* path) { 1230 CTFontRef font = fCTFont; 1231 SkScalar scaleX = SK_Scalar1; 1232 SkScalar scaleY = SK_Scalar1; 1233 1234 /* 1235 * For subpixel positioning, we want to return an unhinted outline, so it 1236 * can be positioned nicely at fractional offsets. However, we special-case 1237 * if the baseline of the (horizontal) text is axis-aligned. In those cases 1238 * we want to retain hinting in the direction orthogonal to the baseline. 1239 * e.g. for horizontal baseline, we want to retain hinting in Y. 1240 * The way we remove hinting is to scale the font by some value (4) in that 1241 * direction, ask for the path, and then scale the path back down. 1242 */ 1243 if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) { 1244 SkMatrix m; 1245 fRec.getSingleMatrix(&m); 1246 1247 // start out by assuming that we want no hining in X and Y 1248 scaleX = scaleY = SkFloatToScalar(kScaleForSubPixelPositionHinting); 1249 // now see if we need to restore hinting for axis-aligned baselines 1250 switch (SkComputeAxisAlignmentForHText(m)) { 1251 case kX_SkAxisAlignment: 1252 scaleY = SK_Scalar1; // want hinting in the Y direction 1253 break; 1254 case kY_SkAxisAlignment: 1255 scaleX = SK_Scalar1; // want hinting in the X direction 1256 break; 1257 default: 1258 break; 1259 } 1260 1261 CGAffineTransform xform = MatrixToCGAffineTransform(m, scaleX, scaleY); 1262 // need to release font when we're done 1263 font = CTFontCreateCopyWithAttributes(fCTFont, 1, &xform, NULL); 1264 } 1265 1266 CGGlyph cgGlyph = (CGGlyph)glyph.getGlyphID(fBaseGlyphCount); 1267 AutoCFRelease<CGPathRef> cgPath(CTFontCreatePathForGlyph(font, cgGlyph, NULL)); 1268 1269 path->reset(); 1270 if (cgPath != NULL) { 1271 CGPathApply(cgPath, path, SkScalerContext_Mac::CTPathElement); 1272 } 1273 1274 if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) { 1275 SkMatrix m; 1276 m.setScale(SkScalarInvert(scaleX), SkScalarInvert(scaleY)); 1277 path->transform(m); 1278 // balance the call to CTFontCreateCopyWithAttributes 1279 CFSafeRelease(font); 1280 } 1281 if (fRec.fFlags & SkScalerContext::kVertical_Flag) { 1282 SkIPoint offset; 1283 getVerticalOffset(cgGlyph, &offset); 1284 path->offset(SkIntToScalar(offset.fX), SkIntToScalar(offset.fY)); 1285 } 1286 } 1287 1288 void SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* mx, 1289 SkPaint::FontMetrics* my) { 1290 CGRect theBounds = CTFontGetBoundingBox(fCTFont); 1291 1292 SkPaint::FontMetrics theMetrics; 1293 theMetrics.fTop = CGToScalar(-CGRectGetMaxY_inline(theBounds)); 1294 theMetrics.fAscent = CGToScalar(-CTFontGetAscent(fCTFont)); 1295 theMetrics.fDescent = CGToScalar( CTFontGetDescent(fCTFont)); 1296 theMetrics.fBottom = CGToScalar(-CGRectGetMinY_inline(theBounds)); 1297 theMetrics.fLeading = CGToScalar( CTFontGetLeading(fCTFont)); 1298 theMetrics.fAvgCharWidth = CGToScalar( CGRectGetWidth_inline(theBounds)); 1299 theMetrics.fXMin = CGToScalar( CGRectGetMinX_inline(theBounds)); 1300 theMetrics.fXMax = CGToScalar( CGRectGetMaxX_inline(theBounds)); 1301 theMetrics.fXHeight = CGToScalar( CTFontGetXHeight(fCTFont)); 1302 1303 if (mx != NULL) { 1304 *mx = theMetrics; 1305 } 1306 if (my != NULL) { 1307 *my = theMetrics; 1308 } 1309 } 1310 1311 void SkScalerContext_Mac::CTPathElement(void *info, const CGPathElement *element) { 1312 SkPath* skPath = (SkPath*)info; 1313 1314 // Process the path element 1315 switch (element->type) { 1316 case kCGPathElementMoveToPoint: 1317 skPath->moveTo(element->points[0].x, -element->points[0].y); 1318 break; 1319 1320 case kCGPathElementAddLineToPoint: 1321 skPath->lineTo(element->points[0].x, -element->points[0].y); 1322 break; 1323 1324 case kCGPathElementAddQuadCurveToPoint: 1325 skPath->quadTo(element->points[0].x, -element->points[0].y, 1326 element->points[1].x, -element->points[1].y); 1327 break; 1328 1329 case kCGPathElementAddCurveToPoint: 1330 skPath->cubicTo(element->points[0].x, -element->points[0].y, 1331 element->points[1].x, -element->points[1].y, 1332 element->points[2].x, -element->points[2].y); 1333 break; 1334 1335 case kCGPathElementCloseSubpath: 1336 skPath->close(); 1337 break; 1338 1339 default: 1340 SkDEBUGFAIL("Unknown path element!"); 1341 break; 1342 } 1343 } 1344 1345 1346 /////////////////////////////////////////////////////////////////////////////// 1347 1348 // Returns NULL on failure 1349 // Call must still manage its ownership of provider 1350 static SkTypeface* create_from_dataProvider(CGDataProviderRef provider) { 1351 AutoCFRelease<CGFontRef> cg(CGFontCreateWithDataProvider(provider)); 1352 if (NULL == cg) { 1353 return NULL; 1354 } 1355 CTFontRef ct = CTFontCreateWithGraphicsFont(cg, 0, NULL, NULL); 1356 return cg ? SkCreateTypefaceFromCTFont(ct) : NULL; 1357 } 1358 1359 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) { 1360 AutoCFRelease<CGDataProviderRef> provider(SkCreateDataProviderFromStream(stream)); 1361 if (NULL == provider) { 1362 return NULL; 1363 } 1364 return create_from_dataProvider(provider); 1365 } 1366 1367 SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) { 1368 AutoCFRelease<CGDataProviderRef> provider(CGDataProviderCreateWithFilename(path)); 1369 if (NULL == provider) { 1370 return NULL; 1371 } 1372 return create_from_dataProvider(provider); 1373 } 1374 1375 // Web fonts added to the the CTFont registry do not return their character set. 1376 // Iterate through the font in this case. The existing caller caches the result, 1377 // so the performance impact isn't too bad. 1378 static void populate_glyph_to_unicode_slow(CTFontRef ctFont, CFIndex glyphCount, 1379 SkTDArray<SkUnichar>* glyphToUnicode) { 1380 glyphToUnicode->setCount(glyphCount); 1381 SkUnichar* out = glyphToUnicode->begin(); 1382 sk_bzero(out, glyphCount * sizeof(SkUnichar)); 1383 UniChar unichar = 0; 1384 while (glyphCount > 0) { 1385 CGGlyph glyph; 1386 if (CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) { 1387 out[glyph] = unichar; 1388 --glyphCount; 1389 } 1390 if (++unichar == 0) { 1391 break; 1392 } 1393 } 1394 } 1395 1396 // Construct Glyph to Unicode table. 1397 // Unicode code points that require conjugate pairs in utf16 are not 1398 // supported. 1399 static void populate_glyph_to_unicode(CTFontRef ctFont, CFIndex glyphCount, 1400 SkTDArray<SkUnichar>* glyphToUnicode) { 1401 AutoCFRelease<CFCharacterSetRef> charSet(CTFontCopyCharacterSet(ctFont)); 1402 if (!charSet) { 1403 populate_glyph_to_unicode_slow(ctFont, glyphCount, glyphToUnicode); 1404 return; 1405 } 1406 1407 AutoCFRelease<CFDataRef> bitmap(CFCharacterSetCreateBitmapRepresentation(kCFAllocatorDefault, 1408 charSet)); 1409 if (!bitmap) { 1410 return; 1411 } 1412 CFIndex length = CFDataGetLength(bitmap); 1413 if (!length) { 1414 return; 1415 } 1416 if (length > 8192) { 1417 // TODO: Add support for Unicode above 0xFFFF 1418 // Consider only the BMP portion of the Unicode character points. 1419 // The bitmap may contain other planes, up to plane 16. 1420 // See http://developer.apple.com/library/ios/#documentation/CoreFoundation/Reference/CFCharacterSetRef/Reference/reference.html 1421 length = 8192; 1422 } 1423 const UInt8* bits = CFDataGetBytePtr(bitmap); 1424 glyphToUnicode->setCount(glyphCount); 1425 SkUnichar* out = glyphToUnicode->begin(); 1426 sk_bzero(out, glyphCount * sizeof(SkUnichar)); 1427 for (int i = 0; i < length; i++) { 1428 int mask = bits[i]; 1429 if (!mask) { 1430 continue; 1431 } 1432 for (int j = 0; j < 8; j++) { 1433 CGGlyph glyph; 1434 UniChar unichar = static_cast<UniChar>((i << 3) + j); 1435 if (mask & (1 << j) && CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) { 1436 out[glyph] = unichar; 1437 } 1438 } 1439 } 1440 } 1441 1442 static bool getWidthAdvance(CTFontRef ctFont, int gId, int16_t* data) { 1443 CGSize advance; 1444 advance.width = 0; 1445 CGGlyph glyph = gId; 1446 CTFontGetAdvancesForGlyphs(ctFont, kCTFontHorizontalOrientation, &glyph, &advance, 1); 1447 *data = sk_float_round2int(advance.width); 1448 return true; 1449 } 1450 1451 // we might move this into our CGUtils... 1452 static void CFStringToSkString(CFStringRef src, SkString* dst) { 1453 // Reserve enough room for the worst-case string, 1454 // plus 1 byte for the trailing null. 1455 CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(src), 1456 kCFStringEncodingUTF8) + 1; 1457 dst->resize(length); 1458 CFStringGetCString(src, dst->writable_str(), length, kCFStringEncodingUTF8); 1459 // Resize to the actual UTF-8 length used, stripping the null character. 1460 dst->resize(strlen(dst->c_str())); 1461 } 1462 1463 // static 1464 SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics( 1465 uint32_t fontID, 1466 SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo, 1467 const uint32_t* glyphIDs, 1468 uint32_t glyphIDsCount) { 1469 CTFontRef originalCTFont = GetFontRefFromFontID(fontID); 1470 AutoCFRelease<CTFontRef> ctFont(CTFontCreateCopyWithAttributes( 1471 originalCTFont, CTFontGetUnitsPerEm(originalCTFont), NULL, NULL)); 1472 SkAdvancedTypefaceMetrics* info = new SkAdvancedTypefaceMetrics; 1473 1474 { 1475 AutoCFRelease<CFStringRef> fontName(CTFontCopyPostScriptName(ctFont)); 1476 CFStringToSkString(fontName, &info->fFontName); 1477 } 1478 1479 info->fMultiMaster = false; 1480 CFIndex glyphCount = CTFontGetGlyphCount(ctFont); 1481 info->fLastGlyphID = SkToU16(glyphCount - 1); 1482 info->fEmSize = CTFontGetUnitsPerEm(ctFont); 1483 1484 if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) { 1485 populate_glyph_to_unicode(ctFont, glyphCount, &info->fGlyphToUnicode); 1486 } 1487 1488 info->fStyle = 0; 1489 1490 // If it's not a truetype font, mark it as 'other'. Assume that TrueType 1491 // fonts always have both glyf and loca tables. At the least, this is what 1492 // sfntly needs to subset the font. CTFontCopyAttribute() does not always 1493 // succeed in determining this directly. 1494 if (!GetTableSize(fontID, 'glyf') || !GetTableSize(fontID, 'loca')) { 1495 info->fType = SkAdvancedTypefaceMetrics::kOther_Font; 1496 info->fItalicAngle = 0; 1497 info->fAscent = 0; 1498 info->fDescent = 0; 1499 info->fStemV = 0; 1500 info->fCapHeight = 0; 1501 info->fBBox = SkIRect::MakeEmpty(); 1502 return info; 1503 } 1504 1505 info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font; 1506 CTFontSymbolicTraits symbolicTraits = CTFontGetSymbolicTraits(ctFont); 1507 if (symbolicTraits & kCTFontMonoSpaceTrait) { 1508 info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style; 1509 } 1510 if (symbolicTraits & kCTFontItalicTrait) { 1511 info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style; 1512 } 1513 CTFontStylisticClass stylisticClass = symbolicTraits & kCTFontClassMaskTrait; 1514 if (stylisticClass & kCTFontSymbolicClass) { 1515 info->fStyle |= SkAdvancedTypefaceMetrics::kSymbolic_Style; 1516 } 1517 if (stylisticClass >= kCTFontOldStyleSerifsClass && stylisticClass <= kCTFontSlabSerifsClass) { 1518 info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style; 1519 } else if (stylisticClass & kCTFontScriptsClass) { 1520 info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style; 1521 } 1522 info->fItalicAngle = (int16_t) CTFontGetSlantAngle(ctFont); 1523 info->fAscent = (int16_t) CTFontGetAscent(ctFont); 1524 info->fDescent = (int16_t) CTFontGetDescent(ctFont); 1525 info->fCapHeight = (int16_t) CTFontGetCapHeight(ctFont); 1526 CGRect bbox = CTFontGetBoundingBox(ctFont); 1527 1528 SkRect r; 1529 r.set( CGToScalar(CGRectGetMinX_inline(bbox)), // Left 1530 CGToScalar(CGRectGetMaxY_inline(bbox)), // Top 1531 CGToScalar(CGRectGetMaxX_inline(bbox)), // Right 1532 CGToScalar(CGRectGetMinY_inline(bbox))); // Bottom 1533 1534 r.roundOut(&(info->fBBox)); 1535 1536 // Figure out a good guess for StemV - Min width of i, I, !, 1. 1537 // This probably isn't very good with an italic font. 1538 int16_t min_width = SHRT_MAX; 1539 info->fStemV = 0; 1540 static const UniChar stem_chars[] = {'i', 'I', '!', '1'}; 1541 const size_t count = sizeof(stem_chars) / sizeof(stem_chars[0]); 1542 CGGlyph glyphs[count]; 1543 CGRect boundingRects[count]; 1544 if (CTFontGetGlyphsForCharacters(ctFont, stem_chars, glyphs, count)) { 1545 CTFontGetBoundingRectsForGlyphs(ctFont, kCTFontHorizontalOrientation, 1546 glyphs, boundingRects, count); 1547 for (size_t i = 0; i < count; i++) { 1548 int16_t width = (int16_t) boundingRects[i].size.width; 1549 if (width > 0 && width < min_width) { 1550 min_width = width; 1551 info->fStemV = min_width; 1552 } 1553 } 1554 } 1555 1556 if (false) { // TODO: haven't figured out how to know if font is embeddable 1557 // (information is in the OS/2 table) 1558 info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font; 1559 } else if (perGlyphInfo & SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) { 1560 if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) { 1561 skia_advanced_typeface_metrics_utils::appendRange(&info->fGlyphWidths, 0); 1562 info->fGlyphWidths->fAdvance.append(1, &min_width); 1563 skia_advanced_typeface_metrics_utils::finishRange(info->fGlyphWidths.get(), 0, 1564 SkAdvancedTypefaceMetrics::WidthRange::kDefault); 1565 } else { 1566 info->fGlyphWidths.reset( 1567 skia_advanced_typeface_metrics_utils::getAdvanceData(ctFont.get(), 1568 glyphCount, 1569 glyphIDs, 1570 glyphIDsCount, 1571 &getWidthAdvance)); 1572 } 1573 } 1574 return info; 1575 } 1576 1577 /////////////////////////////////////////////////////////////////////////////// 1578 1579 static SK_SFNT_ULONG get_font_type_tag(SkFontID uniqueID) { 1580 CTFontRef ctFont = GetFontRefFromFontID(uniqueID); 1581 AutoCFRelease<CFNumberRef> fontFormatRef( 1582 static_cast<CFNumberRef>(CTFontCopyAttribute(ctFont, kCTFontFormatAttribute))); 1583 if (!fontFormatRef) { 1584 return 0; 1585 } 1586 1587 SInt32 fontFormatValue; 1588 if (!CFNumberGetValue(fontFormatRef, kCFNumberSInt32Type, &fontFormatValue)) { 1589 return 0; 1590 } 1591 1592 switch (fontFormatValue) { 1593 case kCTFontFormatOpenTypePostScript: 1594 return SkSFNTHeader::fontType_OpenTypeCFF::TAG; 1595 case kCTFontFormatOpenTypeTrueType: 1596 return SkSFNTHeader::fontType_WindowsTrueType::TAG; 1597 case kCTFontFormatTrueType: 1598 return SkSFNTHeader::fontType_MacTrueType::TAG; 1599 case kCTFontFormatPostScript: 1600 return SkSFNTHeader::fontType_PostScript::TAG; 1601 case kCTFontFormatBitmap: 1602 return SkSFNTHeader::fontType_MacTrueType::TAG; 1603 case kCTFontFormatUnrecognized: 1604 default: 1605 //CT seems to be unreliable in being able to obtain the type, 1606 //even if all we want is the first four bytes of the font resource. 1607 //Just the presence of the FontForge 'FFTM' table seems to throw it off. 1608 return SkSFNTHeader::fontType_WindowsTrueType::TAG; 1609 } 1610 } 1611 1612 SkStream* SkFontHost::OpenStream(SkFontID uniqueID) { 1613 SK_SFNT_ULONG fontType = get_font_type_tag(uniqueID); 1614 if (0 == fontType) { 1615 return NULL; 1616 } 1617 1618 // get table tags 1619 int numTables = CountTables(uniqueID); 1620 SkTDArray<SkFontTableTag> tableTags; 1621 tableTags.setCount(numTables); 1622 GetTableTags(uniqueID, tableTags.begin()); 1623 1624 // calc total size for font, save sizes 1625 SkTDArray<size_t> tableSizes; 1626 size_t totalSize = sizeof(SkSFNTHeader) + sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables; 1627 for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) { 1628 size_t tableSize = GetTableSize(uniqueID, tableTags[tableIndex]); 1629 totalSize += (tableSize + 3) & ~3; 1630 *tableSizes.append() = tableSize; 1631 } 1632 1633 // reserve memory for stream, and zero it (tables must be zero padded) 1634 SkMemoryStream* stream = new SkMemoryStream(totalSize); 1635 char* dataStart = (char*)stream->getMemoryBase(); 1636 sk_bzero(dataStart, totalSize); 1637 char* dataPtr = dataStart; 1638 1639 // compute font header entries 1640 uint16_t entrySelector = 0; 1641 uint16_t searchRange = 1; 1642 while (searchRange < numTables >> 1) { 1643 entrySelector++; 1644 searchRange <<= 1; 1645 } 1646 searchRange <<= 4; 1647 uint16_t rangeShift = (numTables << 4) - searchRange; 1648 1649 // write font header 1650 SkSFNTHeader* header = (SkSFNTHeader*)dataPtr; 1651 header->fontType = fontType; 1652 header->numTables = SkEndian_SwapBE16(numTables); 1653 header->searchRange = SkEndian_SwapBE16(searchRange); 1654 header->entrySelector = SkEndian_SwapBE16(entrySelector); 1655 header->rangeShift = SkEndian_SwapBE16(rangeShift); 1656 dataPtr += sizeof(SkSFNTHeader); 1657 1658 // write tables 1659 SkSFNTHeader::TableDirectoryEntry* entry = (SkSFNTHeader::TableDirectoryEntry*)dataPtr; 1660 dataPtr += sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables; 1661 for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) { 1662 size_t tableSize = tableSizes[tableIndex]; 1663 GetTableData(uniqueID, tableTags[tableIndex], 0, tableSize, dataPtr); 1664 entry->tag = SkEndian_SwapBE32(tableTags[tableIndex]); 1665 entry->checksum = SkEndian_SwapBE32(SkOTUtils::CalcTableChecksum((SK_OT_ULONG*)dataPtr, 1666 tableSize)); 1667 entry->offset = SkEndian_SwapBE32(dataPtr - dataStart); 1668 entry->logicalLength = SkEndian_SwapBE32(tableSize); 1669 1670 dataPtr += (tableSize + 3) & ~3; 1671 ++entry; 1672 } 1673 1674 return stream; 1675 } 1676 1677 size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length, int32_t* index) { 1678 SkDEBUGFAIL("SkFontHost::GetFileName unimplemented"); 1679 return 0; 1680 } 1681 1682 /////////////////////////////////////////////////////////////////////////////// 1683 1684 #include "SkStream.h" 1685 1686 // we take ownership of the ref 1687 static const char* get_str(CFStringRef ref, SkString* str) { 1688 CFStringToSkString(ref, str); 1689 CFSafeRelease(ref); 1690 return str->c_str(); 1691 } 1692 1693 void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) { 1694 CTFontRef ctFont = typeface_to_fontref(face); 1695 SkFontDescriptor desc(face->style()); 1696 SkString tmpStr; 1697 1698 desc.setFamilyName(get_str(CTFontCopyFamilyName(ctFont), &tmpStr)); 1699 desc.setFullName(get_str(CTFontCopyFullName(ctFont), &tmpStr)); 1700 desc.setPostscriptName(get_str(CTFontCopyPostScriptName(ctFont), &tmpStr)); 1701 1702 desc.serialize(stream); 1703 1704 // by convention, we also write out the actual sfnt data, preceeded by 1705 // a packed-length. For now we skip that, so we just write the zero. 1706 stream->writePackedUInt(0); 1707 } 1708 1709 SkTypeface* SkFontHost::Deserialize(SkStream* stream) { 1710 SkFontDescriptor desc(stream); 1711 1712 // by convention, Serialize will have also written the actual sfnt data. 1713 // for now, we just want to skip it. 1714 size_t size = stream->readPackedUInt(); 1715 stream->skip(size); 1716 1717 return SkFontHost::CreateTypeface(NULL, desc.getFamilyName(), desc.getStyle()); 1718 } 1719 1720 /////////////////////////////////////////////////////////////////////////////// 1721 1722 SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) { 1723 return new SkScalerContext_Mac(desc); 1724 } 1725 1726 SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) { 1727 SkFontID nextFontID = 0; 1728 SkTypeface* face = GetDefaultFace(); 1729 if (face->uniqueID() != currFontID) { 1730 nextFontID = face->uniqueID(); 1731 } 1732 return nextFontID; 1733 } 1734 1735 void SkFontHost::FilterRec(SkScalerContext::Rec* rec, SkTypeface*) { 1736 unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag | 1737 SkScalerContext::kAutohinting_Flag; 1738 1739 rec->fFlags &= ~flagsWeDontSupport; 1740 1741 bool lcdSupport = supports_LCD(); 1742 1743 // Only two levels of hinting are supported. 1744 // kNo_Hinting means avoid CoreGraphics outline dilation. 1745 // kNormal_Hinting means CoreGraphics outline dilation is allowed. 1746 // If there is no lcd support, hinting (dilation) cannot be supported. 1747 SkPaint::Hinting hinting = rec->getHinting(); 1748 if (SkPaint::kSlight_Hinting == hinting || !lcdSupport) { 1749 hinting = SkPaint::kNo_Hinting; 1750 } else if (SkPaint::kFull_Hinting == hinting) { 1751 hinting = SkPaint::kNormal_Hinting; 1752 } 1753 rec->setHinting(hinting); 1754 1755 // FIXME: lcd smoothed un-hinted rasterization unsupported. 1756 // Tracked by http://code.google.com/p/skia/issues/detail?id=915 . 1757 // There is no current means to honor a request for unhinted lcd, 1758 // so arbitrarilly ignore the hinting request and honor lcd. 1759 1760 // Hinting and smoothing should be orthogonal, but currently they are not. 1761 // CoreGraphics has no API to influence hinting. However, its lcd smoothed 1762 // output is drawn from auto-dilated outlines (the amount of which is 1763 // determined by AppleFontSmoothing). Its regular anti-aliased output is 1764 // drawn from un-dilated outlines. 1765 1766 // The behavior of Skia is as follows: 1767 // [AA][no-hint]: generate AA using CoreGraphic's AA output. 1768 // [AA][yes-hint]: use CoreGraphic's LCD output and reduce it to a single 1769 // channel. This matches [LCD][yes-hint] in weight. 1770 // [LCD][no-hint]: curently unable to honor, and must pick which to respect. 1771 // Currenly side with LCD, effectively ignoring the hinting setting. 1772 // [LCD][yes-hint]: generate LCD using CoreGraphic's LCD output. 1773 1774 if (isLCDFormat(rec->fMaskFormat)) { 1775 if (lcdSupport) { 1776 //CoreGraphics creates 555 masks for smoothed text anyway. 1777 rec->fMaskFormat = SkMask::kLCD16_Format; 1778 rec->setHinting(SkPaint::kNormal_Hinting); 1779 } else { 1780 rec->fMaskFormat = SkMask::kA8_Format; 1781 } 1782 } 1783 1784 // Unhinted A8 masks (those not derived from LCD masks) must respect SK_GAMMA_APPLY_TO_A8. 1785 // All other masks can use regular gamma. 1786 if (SkMask::kA8_Format == rec->fMaskFormat && SkPaint::kNo_Hinting == hinting) { 1787 #ifndef SK_GAMMA_APPLY_TO_A8 1788 rec->ignorePreBlend(); 1789 #endif 1790 } else { 1791 //CoreGraphics dialates smoothed text as needed. 1792 rec->setContrast(0); 1793 } 1794 } 1795 1796 /////////////////////////////////////////////////////////////////////////// 1797 1798 int SkFontHost::CountTables(SkFontID fontID) { 1799 CTFontRef ctFont = GetFontRefFromFontID(fontID); 1800 AutoCFRelease<CFArrayRef> cfArray(CTFontCopyAvailableTables(ctFont, 1801 kCTFontTableOptionNoOptions)); 1802 if (NULL == cfArray) { 1803 return 0; 1804 } 1805 return CFArrayGetCount(cfArray); 1806 } 1807 1808 int SkFontHost::GetTableTags(SkFontID fontID, SkFontTableTag tags[]) { 1809 CTFontRef ctFont = GetFontRefFromFontID(fontID); 1810 AutoCFRelease<CFArrayRef> cfArray(CTFontCopyAvailableTables(ctFont, 1811 kCTFontTableOptionNoOptions)); 1812 if (NULL == cfArray) { 1813 return 0; 1814 } 1815 1816 int count = CFArrayGetCount(cfArray); 1817 if (tags) { 1818 for (int i = 0; i < count; ++i) { 1819 uintptr_t fontTag = reinterpret_cast<uintptr_t>(CFArrayGetValueAtIndex(cfArray, i)); 1820 tags[i] = static_cast<SkFontTableTag>(fontTag); 1821 } 1822 } 1823 return count; 1824 } 1825 1826 // If, as is the case with web fonts, the CTFont data isn't available, 1827 // the CGFont data may work. While the CGFont may always provide the 1828 // right result, leave the CTFont code path to minimize disruption. 1829 static CFDataRef copyTableFromFont(CTFontRef ctFont, SkFontTableTag tag) { 1830 CFDataRef data = CTFontCopyTable(ctFont, (CTFontTableTag) tag, kCTFontTableOptionNoOptions); 1831 if (NULL == data) { 1832 AutoCFRelease<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont, NULL)); 1833 data = CGFontCopyTableForTag(cgFont, tag); 1834 } 1835 return data; 1836 } 1837 1838 size_t SkFontHost::GetTableSize(SkFontID fontID, SkFontTableTag tag) { 1839 CTFontRef ctFont = GetFontRefFromFontID(fontID); 1840 AutoCFRelease<CFDataRef> srcData(copyTableFromFont(ctFont, tag)); 1841 if (NULL == srcData) { 1842 return 0; 1843 } 1844 return CFDataGetLength(srcData); 1845 } 1846 1847 size_t SkFontHost::GetTableData(SkFontID fontID, SkFontTableTag tag, 1848 size_t offset, size_t length, void* dst) { 1849 CTFontRef ctFont = GetFontRefFromFontID(fontID); 1850 AutoCFRelease<CFDataRef> srcData(copyTableFromFont(ctFont, tag)); 1851 if (NULL == srcData) { 1852 return 0; 1853 } 1854 1855 size_t srcSize = CFDataGetLength(srcData); 1856 if (offset >= srcSize) { 1857 return 0; 1858 } 1859 1860 if ((offset + length) > srcSize) { 1861 length = srcSize - offset; 1862 } 1863 1864 if (dst) { 1865 memcpy(dst, CFDataGetBytePtr(srcData) + offset, length); 1866 } 1867 return length; 1868 } 1869