Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(26)

Side by Side Diff: src/ports/SkFontHost_mac.cpp

Issue 770383002: Replace use of deprecated CG methods. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Add expectations. Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/core/SkScalerContext.cpp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 1
2 /* 2 /*
3 * Copyright 2006 The Android Open Source Project 3 * Copyright 2006 The Android Open Source Project
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 */ 7 */
8 8
9 #ifdef SK_BUILD_FOR_MAC 9 #ifdef SK_BUILD_FOR_MAC
10 #import <ApplicationServices/ApplicationServices.h> 10 #import <ApplicationServices/ApplicationServices.h>
11 #endif 11 #endif
12 12
13 #ifdef SK_BUILD_FOR_IOS 13 #ifdef SK_BUILD_FOR_IOS
14 #include <CoreText/CoreText.h> 14 #include <CoreText/CoreText.h>
15 #include <CoreText/CTFontManager.h> 15 #include <CoreText/CTFontManager.h>
16 #include <CoreGraphics/CoreGraphics.h> 16 #include <CoreGraphics/CoreGraphics.h>
17 #include <CoreFoundation/CoreFoundation.h> 17 #include <CoreFoundation/CoreFoundation.h>
18 #endif 18 #endif
19 19
20 #include "SkFontHost.h" 20 #include "SkFontHost.h"
21 #include "SkCGUtils.h" 21 #include "SkCGUtils.h"
22 #include "SkColorPriv.h" 22 #include "SkColorPriv.h"
23 #include "SkDescriptor.h" 23 #include "SkDescriptor.h"
24 #include "SkEndian.h" 24 #include "SkEndian.h"
25 #include "SkFontDescriptor.h" 25 #include "SkFontDescriptor.h"
26 #include "SkFloatingPoint.h" 26 #include "SkFloatingPoint.h"
27 #include "SkGlyph.h" 27 #include "SkGlyph.h"
28 #include "SkLazyFnPtr.h"
28 #include "SkMaskGamma.h" 29 #include "SkMaskGamma.h"
29 #include "SkSFNTHeader.h" 30 #include "SkSFNTHeader.h"
30 #include "SkOTTable_glyf.h" 31 #include "SkOTTable_glyf.h"
31 #include "SkOTTable_head.h" 32 #include "SkOTTable_head.h"
32 #include "SkOTTable_hhea.h" 33 #include "SkOTTable_hhea.h"
33 #include "SkOTTable_loca.h" 34 #include "SkOTTable_loca.h"
34 #include "SkOTUtils.h" 35 #include "SkOTUtils.h"
35 #include "SkPaint.h" 36 #include "SkPaint.h"
36 #include "SkPath.h" 37 #include "SkPath.h"
37 #include "SkString.h" 38 #include "SkString.h"
38 #include "SkStream.h" 39 #include "SkStream.h"
39 #include "SkThread.h" 40 #include "SkThread.h"
40 #include "SkTypeface_mac.h" 41 #include "SkTypeface_mac.h"
41 #include "SkUtils.h" 42 #include "SkUtils.h"
42 #include "SkTypefaceCache.h" 43 #include "SkTypefaceCache.h"
43 #include "SkFontMgr.h" 44 #include "SkFontMgr.h"
44 #include "SkUtils.h" 45 #include "SkUtils.h"
45 46
46 //#define HACK_COLORGLYPHS 47 #include <dlfcn.h>
47 48
48 class SkScalerContext_Mac; 49 class SkScalerContext_Mac;
49 50
50 // CTFontManagerCopyAvailableFontFamilyNames() is not always available, so we 51 // CTFontManagerCopyAvailableFontFamilyNames() is not always available, so we
51 // provide a wrapper here that will return an empty array if need be. 52 // provide a wrapper here that will return an empty array if need be.
52 static CFArrayRef SkCTFontManagerCopyAvailableFontFamilyNames() { 53 static CFArrayRef SkCTFontManagerCopyAvailableFontFamilyNames() {
53 #ifdef SK_BUILD_FOR_IOS 54 #ifdef SK_BUILD_FOR_IOS
54 return CFArrayCreate(NULL, NULL, 0, NULL); 55 return CFArrayCreate(NULL, NULL, 0, NULL);
55 #else 56 #else
56 return CTFontManagerCopyAvailableFontFamilyNames(); 57 return CTFontManagerCopyAvailableFontFamilyNames();
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after
266 -ScalarToCG(matrix[SkMatrix::kMSkewY] * sy), 267 -ScalarToCG(matrix[SkMatrix::kMSkewY] * sy),
267 -ScalarToCG(matrix[SkMatrix::kMSkewX] * sx), 268 -ScalarToCG(matrix[SkMatrix::kMSkewX] * sx),
268 ScalarToCG(matrix[SkMatrix::kMScaleY] * sy), 269 ScalarToCG(matrix[SkMatrix::kMScaleY] * sy),
269 ScalarToCG(matrix[SkMatrix::kMTransX] * sx), 270 ScalarToCG(matrix[SkMatrix::kMTransX] * sx),
270 ScalarToCG(matrix[SkMatrix::kMTransY] * sy)); 271 ScalarToCG(matrix[SkMatrix::kMTransY] * sy));
271 } 272 }
272 273
273 /////////////////////////////////////////////////////////////////////////////// 274 ///////////////////////////////////////////////////////////////////////////////
274 275
275 #define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host) 276 #define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host)
276 #define BITMAP_INFO_GRAY (kCGImageAlphaNone)
277 277
278 /** 278 /**
279 * There does not appear to be a publicly accessable API for determining if lcd 279 * There does not appear to be a publicly accessable API for determining if lcd
280 * font smoothing will be applied if we request it. The main issue is that if 280 * font smoothing will be applied if we request it. The main issue is that if
281 * smoothing is applied a gamma of 2.0 will be used, if not a gamma of 1.0. 281 * smoothing is applied a gamma of 2.0 will be used, if not a gamma of 1.0.
282 */ 282 */
283 static bool supports_LCD() { 283 static bool supports_LCD() {
284 static int gSupportsLCD = -1; 284 static int gSupportsLCD = -1;
285 if (gSupportsLCD >= 0) { 285 if (gSupportsLCD >= 0) {
286 return (bool) gSupportsLCD; 286 return (bool) gSupportsLCD;
(...skipping 10 matching lines...) Expand all
297 CGContextShowTextAtPoint(cgContext, -1, 0, "|", 1); 297 CGContextShowTextAtPoint(cgContext, -1, 0, "|", 1);
298 uint32_t r = (rgb >> 16) & 0xFF; 298 uint32_t r = (rgb >> 16) & 0xFF;
299 uint32_t g = (rgb >> 8) & 0xFF; 299 uint32_t g = (rgb >> 8) & 0xFF;
300 uint32_t b = (rgb >> 0) & 0xFF; 300 uint32_t b = (rgb >> 0) & 0xFF;
301 gSupportsLCD = (r != g || r != b); 301 gSupportsLCD = (r != g || r != b);
302 return (bool) gSupportsLCD; 302 return (bool) gSupportsLCD;
303 } 303 }
304 304
305 class Offscreen { 305 class Offscreen {
306 public: 306 public:
307 Offscreen(); 307 Offscreen()
308 : fRGBSpace(NULL)
309 , fCG(NULL)
310 , fDoAA(false)
311 , fDoLCD(false)
312 {
313 fSize.set(0, 0);
314 }
308 315
309 CGRGBPixel* getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph, 316 CGRGBPixel* getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
310 CGGlyph glyphID, size_t* rowBytesPtr, 317 CGGlyph glyphID, size_t* rowBytesPtr,
311 bool generateA8FromLCD); 318 bool generateA8FromLCD);
312 319
313 private: 320 private:
314 enum { 321 enum {
315 kSize = 32 * 32 * sizeof(CGRGBPixel) 322 kSize = 32 * 32 * sizeof(CGRGBPixel)
316 }; 323 };
317 SkAutoSMalloc<kSize> fImageStorage; 324 SkAutoSMalloc<kSize> fImageStorage;
318 AutoCFRelease<CGColorSpaceRef> fRGBSpace; 325 AutoCFRelease<CGColorSpaceRef> fRGBSpace;
319 326
320 // cached state 327 // cached state
321 AutoCFRelease<CGContextRef> fCG; 328 AutoCFRelease<CGContextRef> fCG;
322 SkISize fSize; 329 SkISize fSize;
323 bool fDoAA; 330 bool fDoAA;
324 bool fDoLCD; 331 bool fDoLCD;
325 332
326 static int RoundSize(int dimension) { 333 static int RoundSize(int dimension) {
327 return SkNextPow2(dimension); 334 return SkNextPow2(dimension);
328 } 335 }
329 }; 336 };
330 337
331 Offscreen::Offscreen() : fRGBSpace(NULL), fCG(NULL),
332 fDoAA(false), fDoLCD(false) {
333 fSize.set(0, 0);
334 }
335
336 /////////////////////////////////////////////////////////////////////////////// 338 ///////////////////////////////////////////////////////////////////////////////
337 339
338 static bool find_dict_float(CFDictionaryRef dict, CFStringRef name, float* value ) { 340 static bool find_dict_float(CFDictionaryRef dict, CFStringRef name, float* value ) {
339 CFNumberRef num; 341 CFNumberRef num;
340 return CFDictionaryGetValueIfPresent(dict, name, (const void**)&num) 342 return CFDictionaryGetValueIfPresent(dict, name, (const void**)&num)
341 && CFNumberIsFloatType(num) 343 && CFNumberIsFloatType(num)
342 && CFNumberGetValue(num, kCFNumberFloatType, value); 344 && CFNumberGetValue(num, kCFNumberFloatType, value);
343 } 345 }
344 346
345 static int unit_weight_to_fontstyle(float unit) { 347 static int unit_weight_to_fontstyle(float unit) {
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
433 #define WEIGHT_THRESHOLD ((SkFontStyle::kNormal_Weight + SkFontStyle::kBold_W eight)/2) 435 #define WEIGHT_THRESHOLD ((SkFontStyle::kNormal_Weight + SkFontStyle::kBold_W eight)/2)
434 436
435 class SkTypeface_Mac : public SkTypeface { 437 class SkTypeface_Mac : public SkTypeface {
436 public: 438 public:
437 SkTypeface_Mac(const SkFontStyle& fs, SkFontID fontID, bool isFixedPitch, 439 SkTypeface_Mac(const SkFontStyle& fs, SkFontID fontID, bool isFixedPitch,
438 CTFontRef fontRef, const char requestedName[], bool isLocalSt ream) 440 CTFontRef fontRef, const char requestedName[], bool isLocalSt ream)
439 : SkTypeface(fs, fontID, isFixedPitch) 441 : SkTypeface(fs, fontID, isFixedPitch)
440 , fRequestedName(requestedName) 442 , fRequestedName(requestedName)
441 , fFontRef(fontRef) // caller has already called CFRetain for us 443 , fFontRef(fontRef) // caller has already called CFRetain for us
442 , fIsLocalStream(isLocalStream) 444 , fIsLocalStream(isLocalStream)
445 , fHasSbixTable(false)
443 { 446 {
444 SkASSERT(fontRef); 447 SkASSERT(fontRef);
448
449 AutoCFRelease<CFArrayRef> tags(CTFontCopyAvailableTables(fFontRef,kCTFon tTableOptionNoOptions));
450 if (tags) {
451 int count = SkToInt(CFArrayGetCount(tags));
452 for (int i = 0; i < count; ++i) {
453 uintptr_t tag = reinterpret_cast<uintptr_t>(CFArrayGetValueAtInd ex(tags, i));
454 if ('sbix' == tag) {
455 fHasSbixTable = true;
456 break;
457 }
458 }
459 }
445 } 460 }
446 461
447 SkString fRequestedName; 462 SkString fRequestedName;
448 AutoCFRelease<CTFontRef> fFontRef; 463 AutoCFRelease<CTFontRef> fFontRef;
449 464
450 protected: 465 protected:
451 friend class SkFontHost; // to access our protected members for deprecate d methods 466 friend class SkFontHost; // to access our protected members for deprecate d methods
452 467
453 virtual int onGetUPEM() const SK_OVERRIDE; 468 virtual int onGetUPEM() const SK_OVERRIDE;
454 virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE; 469 virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE;
455 virtual void onGetFamilyName(SkString* familyName) const SK_OVERRIDE; 470 virtual void onGetFamilyName(SkString* familyName) const SK_OVERRIDE;
456 virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const SK_ OVERRIDE; 471 virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const SK_ OVERRIDE;
457 virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE; 472 virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE;
458 virtual size_t onGetTableData(SkFontTableTag, size_t offset, 473 virtual size_t onGetTableData(SkFontTableTag, size_t offset,
459 size_t length, void* data) const SK_OVERRIDE; 474 size_t length, void* data) const SK_OVERRIDE;
460 virtual SkScalerContext* onCreateScalerContext(const SkDescriptor*) const SK _OVERRIDE; 475 virtual SkScalerContext* onCreateScalerContext(const SkDescriptor*) const SK _OVERRIDE;
461 virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE; 476 virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE;
462 virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE ; 477 virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE ;
463 virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics( 478 virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics(
464 SkAdvancedTypefaceMetrics::PerGlyphInfo, 479 SkAdvancedTypefaceMetrics::PerGlyphInfo,
465 const uint32_t*, uint32_t) const SK_OVERRIDE; 480 const uint32_t*, uint32_t) const SK_OVERRIDE;
466 virtual int onCharsToGlyphs(const void* chars, Encoding, uint16_t glyphs[], 481 virtual int onCharsToGlyphs(const void* chars, Encoding, uint16_t glyphs[],
467 int glyphCount) const SK_OVERRIDE; 482 int glyphCount) const SK_OVERRIDE;
468 virtual int onCountGlyphs() const SK_OVERRIDE; 483 virtual int onCountGlyphs() const SK_OVERRIDE;
469 484
470 private: 485 private:
471 bool fIsLocalStream; 486 bool fIsLocalStream;
487 bool fHasSbixTable;
472 488
473 typedef SkTypeface INHERITED; 489 typedef SkTypeface INHERITED;
474 }; 490 };
475 491
476 static SkTypeface* NewFromFontRef(CTFontRef fontRef, const char name[], bool isL ocalStream) { 492 static SkTypeface* NewFromFontRef(CTFontRef fontRef, const char name[], bool isL ocalStream) {
477 SkASSERT(fontRef); 493 SkASSERT(fontRef);
478 bool isFixedPitch; 494 bool isFixedPitch;
479 SkFontStyle style = SkFontStyle(computeStyleBits(fontRef, &isFixedPitch)); 495 SkFontStyle style = SkFontStyle(computeStyleBits(fontRef, &isFixedPitch));
480 SkFontID fontID = CTFontRef_to_SkFontID(fontRef); 496 SkFontID fontID = CTFontRef_to_SkFontID(fontRef);
481 497
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after
656 672
657 /** Converts from FUnits (em space, y up) to SkGlyph units (pixels, y down). 673 /** Converts from FUnits (em space, y up) to SkGlyph units (pixels, y down).
658 * 674 *
659 * Used on Snow Leopard to correct CTFontGetVerticalTranslationsForGlyphs. 675 * Used on Snow Leopard to correct CTFontGetVerticalTranslationsForGlyphs.
660 * Used on Lion to correct CTFontGetBoundingRectsForGlyphs. 676 * Used on Lion to correct CTFontGetBoundingRectsForGlyphs.
661 */ 677 */
662 SkMatrix fFUnitMatrix; 678 SkMatrix fFUnitMatrix;
663 679
664 Offscreen fOffscreen; 680 Offscreen fOffscreen;
665 AutoCFRelease<CTFontRef> fCTFont; 681 AutoCFRelease<CTFontRef> fCTFont;
682 CGAffineTransform fInvTransform;
666 683
667 /** Vertical variant of fCTFont. 684 /** Vertical variant of fCTFont.
668 * 685 *
669 * CT vertical metrics are pre-rotated (in em space, before transform) 90de g clock-wise. 686 * CT vertical metrics are pre-rotated (in em space, before transform) 90de g clock-wise.
670 * This makes kCTFontDefaultOrientation dangerous, because the metrics from 687 * This makes kCTFontDefaultOrientation dangerous, because the metrics from
671 * kCTFontHorizontalOrientation are in a different space from kCTFontVertic alOrientation. 688 * kCTFontHorizontalOrientation are in a different space from kCTFontVertic alOrientation.
672 * Use fCTVerticalFont with kCTFontVerticalOrientation to get metrics in th e same space. 689 * Use fCTVerticalFont with kCTFontVerticalOrientation to get metrics in th e same space.
673 */ 690 */
674 AutoCFRelease<CTFontRef> fCTVerticalFont; 691 AutoCFRelease<CTFontRef> fCTVerticalFont;
675 692
(...skipping 18 matching lines...) Expand all
694 , fGeneratedFBoundingBoxes(false) 711 , fGeneratedFBoundingBoxes(false)
695 , fDoSubPosition(SkToBool(fRec.fFlags & kSubpixelPositioning_Flag)) 712 , fDoSubPosition(SkToBool(fRec.fFlags & kSubpixelPositioning_Flag))
696 , fVertical(SkToBool(fRec.fFlags & kVertical_Flag)) 713 , fVertical(SkToBool(fRec.fFlags & kVertical_Flag))
697 714
698 { 715 {
699 CTFontRef ctFont = typeface->fFontRef.get(); 716 CTFontRef ctFont = typeface->fFontRef.get();
700 CFIndex numGlyphs = CTFontGetGlyphCount(ctFont); 717 CFIndex numGlyphs = CTFontGetGlyphCount(ctFont);
701 SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF); 718 SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF);
702 fGlyphCount = SkToU16(numGlyphs); 719 fGlyphCount = SkToU16(numGlyphs);
703 720
721 // CT on (at least) 10.9 will size color glyphs down from the requested size , but not up.
722 // As a result, it is necessary to know the actual device size and request t hat.
723 SkVector scale;
704 SkMatrix skTransform; 724 SkMatrix skTransform;
705 fRec.getSingleMatrixWithoutTextSize(&skTransform); 725 fRec.computeMatrices(SkScalerContextRec::kVertical_PreMatrixScale, &scale, & skTransform,
726 NULL, NULL, &fFUnitMatrix);
706 CGAffineTransform transform = MatrixToCGAffineTransform(skTransform); 727 CGAffineTransform transform = MatrixToCGAffineTransform(skTransform);
728 fInvTransform = CGAffineTransformInvert(transform);
707 729
708 AutoCFRelease<CTFontDescriptorRef> ctFontDesc; 730 AutoCFRelease<CTFontDescriptorRef> ctFontDesc;
709 if (fVertical) { 731 if (fVertical) {
710 AutoCFRelease<CFMutableDictionaryRef> cfAttributes(CFDictionaryCreateMut able( 732 AutoCFRelease<CFMutableDictionaryRef> cfAttributes(CFDictionaryCreateMut able(
711 kCFAllocatorDefault, 0, 733 kCFAllocatorDefault, 0,
712 &kCFTypeDictionaryKeyCallBacks, 734 &kCFTypeDictionaryKeyCallBacks,
713 &kCFTypeDictionaryValueCallBacks)); 735 &kCFTypeDictionaryValueCallBacks));
714 if (cfAttributes) { 736 if (cfAttributes) {
715 CTFontOrientation ctOrientation = kCTFontVerticalOrientation; 737 CTFontOrientation ctOrientation = kCTFontVerticalOrientation;
716 AutoCFRelease<CFNumberRef> cfVertical(CFNumberCreate( 738 AutoCFRelease<CFNumberRef> cfVertical(CFNumberCreate(
717 kCFAllocatorDefault, kCFNumberSInt32Type, &ctOrientation)); 739 kCFAllocatorDefault, kCFNumberSInt32Type, &ctOrientation));
718 CFDictionaryAddValue(cfAttributes, kCTFontOrientationAttribute, cfVe rtical); 740 CFDictionaryAddValue(cfAttributes, kCTFontOrientationAttribute, cfVe rtical);
719 ctFontDesc.reset(CTFontDescriptorCreateWithAttributes(cfAttributes)) ; 741 ctFontDesc.reset(CTFontDescriptorCreateWithAttributes(cfAttributes)) ;
720 } 742 }
721 } 743 }
722 744
723 // The transform contains everything except the requested text size. 745 // The transform contains everything except the requested text size.
724 // Some properties, like 'trak', are based on the text size (before applying the matrix). 746 // Some properties, like 'trak', are based on the text size (before applying the matrix).
725 CGFloat textSize = ScalarToCG(fRec.fTextSize); 747 CGFloat textSize = ScalarToCG(scale.y());
726
727 // If a text size of 0 is requested, CoreGraphics will use 12 instead.
728 // If the text size is 0, set it to something tiny.
729 if (textSize < CGFLOAT_MIN) {
730 textSize = CGFLOAT_MIN;
731 }
732 748
733 fCTFont.reset(CTFontCreateCopyWithAttributes(ctFont, textSize, &transform, c tFontDesc)); 749 fCTFont.reset(CTFontCreateCopyWithAttributes(ctFont, textSize, &transform, c tFontDesc));
734 fCGFont.reset(CTFontCopyGraphicsFont(fCTFont, NULL)); 750 fCGFont.reset(CTFontCopyGraphicsFont(fCTFont, NULL));
735 if (fVertical) { 751 if (fVertical) {
736 CGAffineTransform rotateLeft = CGAffineTransformMake(0, -1, 1, 0, 0, 0); 752 CGAffineTransform rotateLeft = CGAffineTransformMake(0, -1, 1, 0, 0, 0);
737 transform = CGAffineTransformConcat(rotateLeft, transform); 753 transform = CGAffineTransformConcat(rotateLeft, transform);
738 fCTVerticalFont.reset(CTFontCreateCopyWithAttributes(ctFont, textSize, & transform, NULL)); 754 fCTVerticalFont.reset(CTFontCreateCopyWithAttributes(ctFont, textSize, & transform, NULL));
739 } 755 }
740 756
741 // The fUnitMatrix includes the text size (and em) as it is used to scale th e raw font data. 757 // The fUnitMatrix includes the text size (and em) as it is used to scale th e raw font data.
742 fRec.getSingleMatrix(&fFUnitMatrix);
743 SkScalar emPerFUnit = SkScalarInvert(SkIntToScalar(CGFontGetUnitsPerEm(fCGFo nt))); 758 SkScalar emPerFUnit = SkScalarInvert(SkIntToScalar(CGFontGetUnitsPerEm(fCGFo nt)));
744 fFUnitMatrix.preScale(emPerFUnit, -emPerFUnit); 759 fFUnitMatrix.preScale(emPerFUnit, -emPerFUnit);
745 } 760 }
746 761
762 extern "C" {
763
764 /** CTFontDrawGlyphs was introduced in 10.7. */
765 typedef void (*CTFontDrawGlyphsProc)(CTFontRef, const CGGlyph[], const CGPoint[] ,
766 size_t, CGContextRef);
767
768 /** This is an implementation of CTFontDrawGlyphs for 10.6. */
769 static void sk_legacy_CTFontDrawGlyphs(CTFontRef, const CGGlyph glyphs[], const CGPoint points[],
770 size_t count, CGContextRef cg)
771 {
772 CGContextShowGlyphsAtPositions(cg, glyphs, points, count);
773 }
774
775 }
776
777 CTFontDrawGlyphsProc SkChooseCTFontDrawGlyphs() {
778 CTFontDrawGlyphsProc realCTFontDrawGlyphs;
779 *reinterpret_cast<void**>(&realCTFontDrawGlyphs) = dlsym(RTLD_DEFAULT, "CTFo ntDrawGlyphs");
780 return realCTFontDrawGlyphs ? realCTFontDrawGlyphs : sk_legacy_CTFontDrawGly phs;
781 };
782
783 SK_DECLARE_STATIC_LAZY_FN_PTR(CTFontDrawGlyphsProc, gCTFontDrawGlyphs, SkChooseC TFontDrawGlyphs);
784
747 CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph, 785 CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
748 CGGlyph glyphID, size_t* rowBytesPtr, 786 CGGlyph glyphID, size_t* rowBytesPtr,
749 bool generateA8FromLCD) { 787 bool generateA8FromLCD)
788 {
789 CTFontDrawGlyphsProc ctFontDrawGlyphs = gCTFontDrawGlyphs.get();
790
750 if (!fRGBSpace) { 791 if (!fRGBSpace) {
751 //It doesn't appear to matter what color space is specified. 792 //It doesn't appear to matter what color space is specified.
752 //Regular blends and antialiased text are always (s*a + d*(1-a)) 793 //Regular blends and antialiased text are always (s*a + d*(1-a))
753 //and smoothed text is always g=2.0. 794 //and smoothed text is always g=2.0.
754 fRGBSpace.reset(CGColorSpaceCreateDeviceRGB()); 795 fRGBSpace.reset(CGColorSpaceCreateDeviceRGB());
755 } 796 }
756 797
757 // default to kBW_Format 798 // default to kBW_Format
758 bool doAA = false; 799 bool doAA = false;
759 bool doLCD = false; 800 bool doLCD = false;
760 801
761 if (SkMask::kBW_Format != glyph.fMaskFormat) { 802 if (SkMask::kBW_Format != glyph.fMaskFormat) {
762 doLCD = true; 803 doLCD = true;
763 doAA = true; 804 doAA = true;
764 } 805 }
765 806
766 // FIXME: lcd smoothed un-hinted rasterization unsupported. 807 // FIXME: lcd smoothed un-hinted rasterization unsupported.
767 if (!generateA8FromLCD && SkMask::kA8_Format == glyph.fMaskFormat) { 808 if (!generateA8FromLCD && SkMask::kA8_Format == glyph.fMaskFormat) {
768 doLCD = false; 809 doLCD = false;
769 doAA = true; 810 doAA = true;
770 } 811 }
771 812
813 // If this font might have color glyphs, disable LCD as there's no way to su pport it.
814 // CoreText doesn't tell us which format it ended up using, so we can't dete ct it.
815 // A8 will be ugly too (white on transparent), but TODO: we can detect gray and set to A8.
816 if (SkMask::kARGB32_Format == glyph.fMaskFormat) {
817 doLCD = false;
818 }
819
772 size_t rowBytes = fSize.fWidth * sizeof(CGRGBPixel); 820 size_t rowBytes = fSize.fWidth * sizeof(CGRGBPixel);
773 if (!fCG || fSize.fWidth < glyph.fWidth || fSize.fHeight < glyph.fHeight) { 821 if (!fCG || fSize.fWidth < glyph.fWidth || fSize.fHeight < glyph.fHeight) {
774 if (fSize.fWidth < glyph.fWidth) { 822 if (fSize.fWidth < glyph.fWidth) {
775 fSize.fWidth = RoundSize(glyph.fWidth); 823 fSize.fWidth = RoundSize(glyph.fWidth);
776 } 824 }
777 if (fSize.fHeight < glyph.fHeight) { 825 if (fSize.fHeight < glyph.fHeight) {
778 fSize.fHeight = RoundSize(glyph.fHeight); 826 fSize.fHeight = RoundSize(glyph.fHeight);
779 } 827 }
780 828
781 rowBytes = fSize.fWidth * sizeof(CGRGBPixel); 829 rowBytes = fSize.fWidth * sizeof(CGRGBPixel);
782 void* image = fImageStorage.reset(rowBytes * fSize.fHeight); 830 void* image = fImageStorage.reset(rowBytes * fSize.fHeight);
831 const CGImageAlphaInfo alpha = (SkMask::kARGB32_Format == glyph.fMaskFor mat)
832 ? kCGImageAlphaPremultipliedFirst
833 : kCGImageAlphaNoneSkipFirst;
834 const CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host | alpha;
783 fCG.reset(CGBitmapContextCreate(image, fSize.fWidth, fSize.fHeight, 8, 835 fCG.reset(CGBitmapContextCreate(image, fSize.fWidth, fSize.fHeight, 8,
784 rowBytes, fRGBSpace, BITMAP_INFO_RGB)); 836 rowBytes, fRGBSpace, bitmapInfo));
785 837
786 // skia handles quantization itself, so we disable this for cg to get 838 // Skia handles quantization and subpixel positioning,
787 // full fractional data from them. 839 // so disable quantization and enabe subpixel positioning in CG.
788 CGContextSetAllowsFontSubpixelQuantization(fCG, false); 840 CGContextSetAllowsFontSubpixelQuantization(fCG, false);
789 CGContextSetShouldSubpixelQuantizeFonts(fCG, false); 841 CGContextSetShouldSubpixelQuantizeFonts(fCG, false);
790 842
791 CGContextSetTextDrawingMode(fCG, kCGTextFill);
792 CGContextSetFont(fCG, context.fCGFont);
793 CGContextSetFontSize(fCG, CTFontGetSize(context.fCTFont));
794 CGContextSetTextMatrix(fCG, CTFontGetMatrix(context.fCTFont));
795
796 // Because CG always draws from the horizontal baseline, 843 // Because CG always draws from the horizontal baseline,
797 // if there is a non-integral translation from the horizontal origin to the vertical origin, 844 // if there is a non-integral translation from the horizontal origin to the vertical origin,
798 // then CG cannot draw the glyph in the correct location without subpixe l positioning. 845 // then CG cannot draw the glyph in the correct location without subpixe l positioning.
799 CGContextSetAllowsFontSubpixelPositioning(fCG, context.fDoSubPosition || context.fVertical); 846 CGContextSetAllowsFontSubpixelPositioning(fCG, true);
800 CGContextSetShouldSubpixelPositionFonts(fCG, context.fDoSubPosition || c ontext.fVertical); 847 CGContextSetShouldSubpixelPositionFonts(fCG, true);
848
849 CGContextSetTextDrawingMode(fCG, kCGTextFill);
801 850
802 // Draw white on black to create mask. 851 // Draw white on black to create mask.
803 // TODO: Draw black on white and invert, CG has a special case codepath. 852 // TODO: Draw black on white and invert, CG has a special case codepath.
804 CGContextSetGrayFillColor(fCG, 1.0f, 1.0f); 853 CGContextSetGrayFillColor(fCG, 1.0f, 1.0f);
805 854
806 // force our checks below to happen 855 // force our checks below to happen
807 fDoAA = !doAA; 856 fDoAA = !doAA;
808 fDoLCD = !doLCD; 857 fDoLCD = !doLCD;
858
859 if (sk_legacy_CTFontDrawGlyphs == ctFontDrawGlyphs) {
860 // CTFontDrawGlyphs will apply the font, font size, and font matrix to the CGContext.
861 // Our 'fake' one does not, so set up the CGContext here.
862 CGContextSetFont(fCG, context.fCGFont);
863 CGContextSetFontSize(fCG, CTFontGetSize(context.fCTFont));
864 CGContextSetTextMatrix(fCG, CTFontGetMatrix(context.fCTFont));
865 }
809 } 866 }
810 867
811 if (fDoAA != doAA) { 868 if (fDoAA != doAA) {
812 CGContextSetShouldAntialias(fCG, doAA); 869 CGContextSetShouldAntialias(fCG, doAA);
813 fDoAA = doAA; 870 fDoAA = doAA;
814 } 871 }
815 if (fDoLCD != doLCD) { 872 if (fDoLCD != doLCD) {
816 CGContextSetShouldSmoothFonts(fCG, doLCD); 873 CGContextSetShouldSmoothFonts(fCG, doLCD);
817 fDoLCD = doLCD; 874 fDoLCD = doLCD;
818 } 875 }
819 876
820 CGRGBPixel* image = (CGRGBPixel*)fImageStorage.get(); 877 CGRGBPixel* image = (CGRGBPixel*)fImageStorage.get();
821 // skip rows based on the glyph's height 878 // skip rows based on the glyph's height
822 image += (fSize.fHeight - glyph.fHeight) * fSize.fWidth; 879 image += (fSize.fHeight - glyph.fHeight) * fSize.fWidth;
823 880
824 // erase to black 881 // erase to black
825 sk_memset_rect32(image, 0, glyph.fWidth, glyph.fHeight, rowBytes); 882 sk_memset_rect32(image, 0, glyph.fWidth, glyph.fHeight, rowBytes);
826 883
827 float subX = 0; 884 float subX = 0;
828 float subY = 0; 885 float subY = 0;
829 if (context.fDoSubPosition) { 886 if (context.fDoSubPosition) {
830 subX = SkFixedToFloat(glyph.getSubXFixed()); 887 subX = SkFixedToFloat(glyph.getSubXFixed());
831 subY = SkFixedToFloat(glyph.getSubYFixed()); 888 subY = SkFixedToFloat(glyph.getSubYFixed());
832 } 889 }
833 890
834 // CGContextShowGlyphsAtPoint always draws using the horizontal baseline ori gin. 891 // CoreText and CoreGraphics always draw using the horizontal baseline origi n.
835 if (context.fVertical) { 892 if (context.fVertical) {
836 SkPoint offset; 893 SkPoint offset;
837 context.getVerticalOffset(glyphID, &offset); 894 context.getVerticalOffset(glyphID, &offset);
838 subX += offset.fX; 895 subX += offset.fX;
839 subY += offset.fY; 896 subY += offset.fY;
840 } 897 }
841 898
842 CGContextShowGlyphsAtPoint(fCG, -glyph.fLeft + subX, 899 // CTFontDrawGlyphs and CGContextShowGlyphsAtPositions take 'positions' whic h are in text space.
843 glyph.fTop + glyph.fHeight - subY, 900 // The glyph location (in device space) must be mapped into text space, so t hat CG can convert
844 &glyphID, 1); 901 // it back into device space.
902 CGPoint point = CGPointMake(-glyph.fLeft + subX, glyph.fTop + glyph.fHeight - subY);
903 point = CGPointApplyAffineTransform(point, context.fInvTransform);
904 ctFontDrawGlyphs(context.fCTFont, &glyphID, &point, 1, fCG);
845 905
846 SkASSERT(rowBytesPtr); 906 SkASSERT(rowBytesPtr);
847 *rowBytesPtr = rowBytes; 907 *rowBytesPtr = rowBytes;
848 return image; 908 return image;
849 } 909 }
850 910
851 void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkPoint* offset) co nst { 911 void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkPoint* offset) co nst {
852 // Snow Leopard returns cgVertOffset in completely un-transformed FUnits (em space, y up). 912 // Snow Leopard returns cgVertOffset in completely un-transformed FUnits (em space, y up).
853 // Lion and Leopard return cgVertOffset in CG units (pixels, y up). 913 // Lion and Leopard return cgVertOffset in CG units (pixels, y up).
854 CGSize cgVertOffset; 914 CGSize cgVertOffset;
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
1038 skBounds.roundOut(&skIBounds); 1098 skBounds.roundOut(&skIBounds);
1039 // Expand the bounds by 1 pixel, to give CG room for anti-aliasing. 1099 // Expand the bounds by 1 pixel, to give CG room for anti-aliasing.
1040 // Note that this outset is to allow room for LCD smoothed glyphs. However, the correct outset 1100 // Note that this outset is to allow room for LCD smoothed glyphs. However, the correct outset
1041 // is not currently known, as CG dilates the outlines by some percentage. 1101 // is not currently known, as CG dilates the outlines by some percentage.
1042 // Note that if this context is A8 and not back-forming from LCD, there is n o need to outset. 1102 // Note that if this context is A8 and not back-forming from LCD, there is n o need to outset.
1043 skIBounds.outset(1, 1); 1103 skIBounds.outset(1, 1);
1044 glyph->fLeft = SkToS16(skIBounds.fLeft); 1104 glyph->fLeft = SkToS16(skIBounds.fLeft);
1045 glyph->fTop = SkToS16(skIBounds.fTop); 1105 glyph->fTop = SkToS16(skIBounds.fTop);
1046 glyph->fWidth = SkToU16(skIBounds.width()); 1106 glyph->fWidth = SkToU16(skIBounds.width());
1047 glyph->fHeight = SkToU16(skIBounds.height()); 1107 glyph->fHeight = SkToU16(skIBounds.height());
1048
1049 #ifdef HACK_COLORGLYPHS
1050 glyph->fMaskFormat = SkMask::kARGB32_Format;
1051 #endif
1052 } 1108 }
1053 1109
1054 #include "SkColorPriv.h" 1110 #include "SkColorPriv.h"
1055 1111
1056 static void build_power_table(uint8_t table[], float ee) { 1112 static void build_power_table(uint8_t table[], float ee) {
1057 for (int i = 0; i < 256; i++) { 1113 for (int i = 0; i < 256; i++) {
1058 float x = i / 255.f; 1114 float x = i / 255.f;
1059 x = sk_float_pow(x, ee); 1115 x = sk_float_pow(x, ee);
1060 int xx = SkScalarRoundToInt(x * 255); 1116 int xx = SkScalarRoundToInt(x * 255);
1061 table[i] = SkToU8(xx); 1117 table[i] = SkToU8(xx);
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
1133 1189
1134 for (int y = 0; y < glyph.fHeight; y++) { 1190 for (int y = 0; y < glyph.fHeight; y++) {
1135 for (int i = 0; i < width; i++) { 1191 for (int i = 0; i < width; i++) {
1136 dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(cgPixels[i], tableR, tableG, t ableB); 1192 dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(cgPixels[i], tableR, tableG, t ableB);
1137 } 1193 }
1138 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes); 1194 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1139 dst = (uint16_t*)((char*)dst + dstRB); 1195 dst = (uint16_t*)((char*)dst + dstRB);
1140 } 1196 }
1141 } 1197 }
1142 1198
1143 #ifdef HACK_COLORGLYPHS 1199 static SkPMColor cgpixels_to_pmcolor(CGRGBPixel rgb) {
1144 // hack to colorize the output for testing kARGB32_Format 1200 U8CPU a = (rgb >> 24) & 0xFF;
1145 static SkPMColor cgpixels_to_pmcolor(CGRGBPixel rgb, const SkGlyph& glyph,
1146 int x, int y) {
1147 U8CPU r = (rgb >> 16) & 0xFF; 1201 U8CPU r = (rgb >> 16) & 0xFF;
1148 U8CPU g = (rgb >> 8) & 0xFF; 1202 U8CPU g = (rgb >> 8) & 0xFF;
1149 U8CPU b = (rgb >> 0) & 0xFF; 1203 U8CPU b = (rgb >> 0) & 0xFF;
1150 unsigned a = SkComputeLuminance(r, g, b);
1151 1204
1152 // compute gradient from x,y 1205 return SkPackARGB32(a, r, g, b);
1153 r = x * 255 / glyph.fWidth;
1154 g = 0;
1155 b = (glyph.fHeight - y) * 255 / glyph.fHeight;
1156 return SkPreMultiplyARGB(a, r, g, b); // red
1157 } 1206 }
1158 #endif
1159 1207
1160 template <typename T> T* SkTAddByteOffset(T* ptr, size_t byteOffset) { 1208 template <typename T> T* SkTAddByteOffset(T* ptr, size_t byteOffset) {
1161 return (T*)((char*)ptr + byteOffset); 1209 return (T*)((char*)ptr + byteOffset);
1162 } 1210 }
1163 1211
1164 void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) { 1212 void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
1165 CGGlyph cgGlyph = (CGGlyph) glyph.getGlyphID(); 1213 CGGlyph cgGlyph = (CGGlyph) glyph.getGlyphID();
1166 1214
1167 // FIXME: lcd smoothed un-hinted rasterization unsupported. 1215 // FIXME: lcd smoothed un-hinted rasterization unsupported.
1168 bool generateA8FromLCD = fRec.getHinting() != SkPaint::kNo_Hinting; 1216 bool generateA8FromLCD = fRec.getHinting() != SkPaint::kNo_Hinting;
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
1221 case SkMask::kBW_Format: { 1269 case SkMask::kBW_Format: {
1222 const int width = glyph.fWidth; 1270 const int width = glyph.fWidth;
1223 size_t dstRB = glyph.rowBytes(); 1271 size_t dstRB = glyph.rowBytes();
1224 uint8_t* dst = (uint8_t*)glyph.fImage; 1272 uint8_t* dst = (uint8_t*)glyph.fImage;
1225 for (int y = 0; y < glyph.fHeight; y++) { 1273 for (int y = 0; y < glyph.fHeight; y++) {
1226 cgpixels_to_bits(dst, cgPixels, width); 1274 cgpixels_to_bits(dst, cgPixels, width);
1227 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes); 1275 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1228 dst += dstRB; 1276 dst += dstRB;
1229 } 1277 }
1230 } break; 1278 } break;
1231 #ifdef HACK_COLORGLYPHS
1232 case SkMask::kARGB32_Format: { 1279 case SkMask::kARGB32_Format: {
1233 const int width = glyph.fWidth; 1280 const int width = glyph.fWidth;
1234 size_t dstRB = glyph.rowBytes(); 1281 size_t dstRB = glyph.rowBytes();
1235 SkPMColor* dst = (SkPMColor*)glyph.fImage; 1282 SkPMColor* dst = (SkPMColor*)glyph.fImage;
1236 for (int y = 0; y < glyph.fHeight; y++) { 1283 for (int y = 0; y < glyph.fHeight; y++) {
1237 for (int x = 0; x < width; ++x) { 1284 for (int x = 0; x < width; ++x) {
1238 dst[x] = cgpixels_to_pmcolor(cgPixels[x], glyph, x, y); 1285 dst[x] = cgpixels_to_pmcolor(cgPixels[x]);
1239 } 1286 }
1240 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes); 1287 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1241 dst = (SkPMColor*)((char*)dst + dstRB); 1288 dst = (SkPMColor*)((char*)dst + dstRB);
1242 } 1289 }
1243 } break; 1290 } break;
1244 #endif
1245 default: 1291 default:
1246 SkDEBUGFAIL("unexpected mask format"); 1292 SkDEBUGFAIL("unexpected mask format");
1247 break; 1293 break;
1248 } 1294 }
1249 } 1295 }
1250 1296
1251 /* 1297 /*
1252 * Our subpixel resolution is only 2 bits in each direction, so a scale of 4 1298 * Our subpixel resolution is only 2 bits in each direction, so a scale of 4
1253 * seems sufficient, and possibly even correct, to allow the hinted outline 1299 * seems sufficient, and possibly even correct, to allow the hinted outline
1254 * to be subpixel positioned. 1300 * to be subpixel positioned.
(...skipping 566 matching lines...) Expand 10 before | Expand all | Expand 10 after
1821 if (isLCDFormat(rec->fMaskFormat)) { 1867 if (isLCDFormat(rec->fMaskFormat)) {
1822 if (lcdSupport) { 1868 if (lcdSupport) {
1823 //CoreGraphics creates 555 masks for smoothed text anyway. 1869 //CoreGraphics creates 555 masks for smoothed text anyway.
1824 rec->fMaskFormat = SkMask::kLCD16_Format; 1870 rec->fMaskFormat = SkMask::kLCD16_Format;
1825 rec->setHinting(SkPaint::kNormal_Hinting); 1871 rec->setHinting(SkPaint::kNormal_Hinting);
1826 } else { 1872 } else {
1827 rec->fMaskFormat = SkMask::kA8_Format; 1873 rec->fMaskFormat = SkMask::kA8_Format;
1828 } 1874 }
1829 } 1875 }
1830 1876
1877 // CoreText provides no information as to whether a glyph will be color or n ot.
1878 // Fonts may mix outlines and bitmaps, so information is needed on a glyph b y glyph basis.
1879 // If a font contains an 'sbix' table, consider it to be a color font, and d isable lcd.
1880 if (fHasSbixTable) {
1881 rec->fMaskFormat = SkMask::kARGB32_Format;
1882 }
1883
1831 // Unhinted A8 masks (those not derived from LCD masks) must respect SK_GAMM A_APPLY_TO_A8. 1884 // Unhinted A8 masks (those not derived from LCD masks) must respect SK_GAMM A_APPLY_TO_A8.
1832 // All other masks can use regular gamma. 1885 // All other masks can use regular gamma.
1833 if (SkMask::kA8_Format == rec->fMaskFormat && SkPaint::kNo_Hinting == hintin g) { 1886 if (SkMask::kA8_Format == rec->fMaskFormat && SkPaint::kNo_Hinting == hintin g) {
1834 #ifndef SK_GAMMA_APPLY_TO_A8 1887 #ifndef SK_GAMMA_APPLY_TO_A8
1835 rec->ignorePreBlend(); 1888 rec->ignorePreBlend();
1836 #endif 1889 #endif
1837 } else { 1890 } else {
1838 //CoreGraphics dialates smoothed text as needed. 1891 //CoreGraphics dialates smoothed text as needed.
1839 rec->setContrast(0); 1892 rec->setContrast(0);
1840 } 1893 }
(...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after
2211 } 2264 }
2212 return face; 2265 return face;
2213 } 2266 }
2214 }; 2267 };
2215 2268
2216 /////////////////////////////////////////////////////////////////////////////// 2269 ///////////////////////////////////////////////////////////////////////////////
2217 2270
2218 SkFontMgr* SkFontMgr::Factory() { 2271 SkFontMgr* SkFontMgr::Factory() {
2219 return SkNEW(SkFontMgr_Mac); 2272 return SkNEW(SkFontMgr_Mac);
2220 } 2273 }
OLDNEW
« no previous file with comments | « src/core/SkScalerContext.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698