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

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: Clean up code. (121 failures.) 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 | « no previous file | 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 310 matching lines...) Expand 10 before | Expand all | Expand 10 after
656 658
657 /** Converts from FUnits (em space, y up) to SkGlyph units (pixels, y down). 659 /** Converts from FUnits (em space, y up) to SkGlyph units (pixels, y down).
658 * 660 *
659 * Used on Snow Leopard to correct CTFontGetVerticalTranslationsForGlyphs. 661 * Used on Snow Leopard to correct CTFontGetVerticalTranslationsForGlyphs.
660 * Used on Lion to correct CTFontGetBoundingRectsForGlyphs. 662 * Used on Lion to correct CTFontGetBoundingRectsForGlyphs.
661 */ 663 */
662 SkMatrix fFUnitMatrix; 664 SkMatrix fFUnitMatrix;
663 665
664 Offscreen fOffscreen; 666 Offscreen fOffscreen;
665 AutoCFRelease<CTFontRef> fCTFont; 667 AutoCFRelease<CTFontRef> fCTFont;
668 CGAffineTransform fInvTransform;
666 669
667 /** Vertical variant of fCTFont. 670 /** Vertical variant of fCTFont.
668 * 671 *
669 * CT vertical metrics are pre-rotated (in em space, before transform) 90de g clock-wise. 672 * CT vertical metrics are pre-rotated (in em space, before transform) 90de g clock-wise.
670 * This makes kCTFontDefaultOrientation dangerous, because the metrics from 673 * This makes kCTFontDefaultOrientation dangerous, because the metrics from
671 * kCTFontHorizontalOrientation are in a different space from kCTFontVertic alOrientation. 674 * kCTFontHorizontalOrientation are in a different space from kCTFontVertic alOrientation.
672 * Use fCTVerticalFont with kCTFontVerticalOrientation to get metrics in th e same space. 675 * Use fCTVerticalFont with kCTFontVerticalOrientation to get metrics in th e same space.
673 */ 676 */
674 AutoCFRelease<CTFontRef> fCTVerticalFont; 677 AutoCFRelease<CTFontRef> fCTVerticalFont;
675 678
(...skipping 18 matching lines...) Expand all
694 , fGeneratedFBoundingBoxes(false) 697 , fGeneratedFBoundingBoxes(false)
695 , fDoSubPosition(SkToBool(fRec.fFlags & kSubpixelPositioning_Flag)) 698 , fDoSubPosition(SkToBool(fRec.fFlags & kSubpixelPositioning_Flag))
696 , fVertical(SkToBool(fRec.fFlags & kVertical_Flag)) 699 , fVertical(SkToBool(fRec.fFlags & kVertical_Flag))
697 700
698 { 701 {
699 CTFontRef ctFont = typeface->fFontRef.get(); 702 CTFontRef ctFont = typeface->fFontRef.get();
700 CFIndex numGlyphs = CTFontGetGlyphCount(ctFont); 703 CFIndex numGlyphs = CTFontGetGlyphCount(ctFont);
701 SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF); 704 SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF);
702 fGlyphCount = SkToU16(numGlyphs); 705 fGlyphCount = SkToU16(numGlyphs);
703 706
707 // CT on (at least) 10.9 will size color glyphs down from the requested size , but not up.
708 // As a result, it is necessary to know the actual device size and request t hat.
709 SkVector scale;
704 SkMatrix skTransform; 710 SkMatrix skTransform;
705 fRec.getSingleMatrixWithoutTextSize(&skTransform); 711 fRec.computeMatrices(SkScalerContextRec::kVertical_PreMatrixScale, &scale, & skTransform,
712 NULL, NULL, &fFUnitMatrix);
706 CGAffineTransform transform = MatrixToCGAffineTransform(skTransform); 713 CGAffineTransform transform = MatrixToCGAffineTransform(skTransform);
714 fInvTransform = CGAffineTransformInvert(transform);
707 715
708 AutoCFRelease<CTFontDescriptorRef> ctFontDesc; 716 AutoCFRelease<CTFontDescriptorRef> ctFontDesc;
709 if (fVertical) { 717 if (fVertical) {
710 AutoCFRelease<CFMutableDictionaryRef> cfAttributes(CFDictionaryCreateMut able( 718 AutoCFRelease<CFMutableDictionaryRef> cfAttributes(CFDictionaryCreateMut able(
711 kCFAllocatorDefault, 0, 719 kCFAllocatorDefault, 0,
712 &kCFTypeDictionaryKeyCallBacks, 720 &kCFTypeDictionaryKeyCallBacks,
713 &kCFTypeDictionaryValueCallBacks)); 721 &kCFTypeDictionaryValueCallBacks));
714 if (cfAttributes) { 722 if (cfAttributes) {
715 CTFontOrientation ctOrientation = kCTFontVerticalOrientation; 723 CTFontOrientation ctOrientation = kCTFontVerticalOrientation;
716 AutoCFRelease<CFNumberRef> cfVertical(CFNumberCreate( 724 AutoCFRelease<CFNumberRef> cfVertical(CFNumberCreate(
717 kCFAllocatorDefault, kCFNumberSInt32Type, &ctOrientation)); 725 kCFAllocatorDefault, kCFNumberSInt32Type, &ctOrientation));
718 CFDictionaryAddValue(cfAttributes, kCTFontOrientationAttribute, cfVe rtical); 726 CFDictionaryAddValue(cfAttributes, kCTFontOrientationAttribute, cfVe rtical);
719 ctFontDesc.reset(CTFontDescriptorCreateWithAttributes(cfAttributes)) ; 727 ctFontDesc.reset(CTFontDescriptorCreateWithAttributes(cfAttributes)) ;
720 } 728 }
721 } 729 }
722 730
723 // The transform contains everything except the requested text size. 731 // The transform contains everything except the requested text size.
724 // Some properties, like 'trak', are based on the text size (before applying the matrix). 732 // Some properties, like 'trak', are based on the text size (before applying the matrix).
725 CGFloat textSize = ScalarToCG(fRec.fTextSize); 733 CGFloat textSize = ScalarToCG(scale.y());
726 734
727 // If a text size of 0 is requested, CoreGraphics will use 12 instead. 735 // 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. 736 // If the text size is 0, set it to something tiny.
729 if (textSize < CGFLOAT_MIN) { 737 if (textSize < CGFLOAT_MIN) {
730 textSize = CGFLOAT_MIN; 738 textSize = CGFLOAT_MIN;
731 } 739 }
732 740
733 fCTFont.reset(CTFontCreateCopyWithAttributes(ctFont, textSize, &transform, c tFontDesc)); 741 fCTFont.reset(CTFontCreateCopyWithAttributes(ctFont, textSize, &transform, c tFontDesc));
734 fCGFont.reset(CTFontCopyGraphicsFont(fCTFont, NULL)); 742 fCGFont.reset(CTFontCopyGraphicsFont(fCTFont, NULL));
735 if (fVertical) { 743 if (fVertical) {
736 CGAffineTransform rotateLeft = CGAffineTransformMake(0, -1, 1, 0, 0, 0); 744 CGAffineTransform rotateLeft = CGAffineTransformMake(0, -1, 1, 0, 0, 0);
737 transform = CGAffineTransformConcat(rotateLeft, transform); 745 transform = CGAffineTransformConcat(rotateLeft, transform);
738 fCTVerticalFont.reset(CTFontCreateCopyWithAttributes(ctFont, textSize, & transform, NULL)); 746 fCTVerticalFont.reset(CTFontCreateCopyWithAttributes(ctFont, textSize, & transform, NULL));
739 } 747 }
740 748
741 // The fUnitMatrix includes the text size (and em) as it is used to scale th e raw font data. 749 // 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))); 750 SkScalar emPerFUnit = SkScalarInvert(SkIntToScalar(CGFontGetUnitsPerEm(fCGFo nt)));
744 fFUnitMatrix.preScale(emPerFUnit, -emPerFUnit); 751 fFUnitMatrix.preScale(emPerFUnit, -emPerFUnit);
745 } 752 }
746 753
754 extern "C" {
755
756 /** CTFontDrawGlyphs was introduced in 10.7. */
757 typedef void (*CTFontDrawGlyphsProc)(CTFontRef, const CGGlyph[], const CGPoint[] ,
758 size_t, CGContextRef);
759
760 /** This is an implementation of CTFontDrawGlyphs for 10.6. */
761 static void sk_legacy_CTFontDrawGlyphs(CTFontRef, const CGGlyph glyphs[], const CGPoint points[],
762 size_t count, CGContextRef cg)
763 {
764 CGContextShowGlyphsAtPositions(cg, glyphs, points, count);
765 }
766
767 }
768
769 CTFontDrawGlyphsProc SkChooseCTFontDrawGlyphs() {
770 CTFontDrawGlyphsProc realCTFontDrawGlyphs;
771 *reinterpret_cast<void**>(&realCTFontDrawGlyphs) = dlsym(RTLD_DEFAULT, "CTFo ntDrawGlyphs");
772 return realCTFontDrawGlyphs ? realCTFontDrawGlyphs : sk_legacy_CTFontDrawGly phs;
773 };
774
775 SK_DECLARE_STATIC_LAZY_FN_PTR(CTFontDrawGlyphsProc, gCTFontDrawGlyphs, SkChooseC TFontDrawGlyphs);
776
747 CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph, 777 CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
748 CGGlyph glyphID, size_t* rowBytesPtr, 778 CGGlyph glyphID, size_t* rowBytesPtr,
749 bool generateA8FromLCD) { 779 bool generateA8FromLCD)
780 {
781 CTFontDrawGlyphsProc ctFontDrawGlyphs = gCTFontDrawGlyphs.get();
782
750 if (!fRGBSpace) { 783 if (!fRGBSpace) {
751 //It doesn't appear to matter what color space is specified. 784 //It doesn't appear to matter what color space is specified.
752 //Regular blends and antialiased text are always (s*a + d*(1-a)) 785 //Regular blends and antialiased text are always (s*a + d*(1-a))
753 //and smoothed text is always g=2.0. 786 //and smoothed text is always g=2.0.
754 fRGBSpace.reset(CGColorSpaceCreateDeviceRGB()); 787 fRGBSpace.reset(CGColorSpaceCreateDeviceRGB());
755 } 788 }
756 789
757 // default to kBW_Format 790 // default to kBW_Format
758 bool doAA = false; 791 bool doAA = false;
759 bool doLCD = false; 792 bool doLCD = false;
760 793
761 if (SkMask::kBW_Format != glyph.fMaskFormat) { 794 if (SkMask::kBW_Format != glyph.fMaskFormat) {
762 doLCD = true; 795 doLCD = true;
763 doAA = true; 796 doAA = true;
764 } 797 }
765 798
766 // FIXME: lcd smoothed un-hinted rasterization unsupported. 799 // FIXME: lcd smoothed un-hinted rasterization unsupported.
767 if (!generateA8FromLCD && SkMask::kA8_Format == glyph.fMaskFormat) { 800 if (!generateA8FromLCD && SkMask::kA8_Format == glyph.fMaskFormat) {
768 doLCD = false; 801 doLCD = false;
769 doAA = true; 802 doAA = true;
770 } 803 }
771 804
805 // If this font might have color glyphs, disable LCD as there's no way to su pport it.
806 // CoreText doesn't tell us which format it ended up using, so we can't dete ct it.
807 // A8 will be ugly too (white on transparent), but TODO: we can detect gray and set to A8.
808 if (SkMask::kARGB32_Format == glyph.fMaskFormat) {
809 doLCD = false;
810 }
811
772 size_t rowBytes = fSize.fWidth * sizeof(CGRGBPixel); 812 size_t rowBytes = fSize.fWidth * sizeof(CGRGBPixel);
773 if (!fCG || fSize.fWidth < glyph.fWidth || fSize.fHeight < glyph.fHeight) { 813 if (!fCG || fSize.fWidth < glyph.fWidth || fSize.fHeight < glyph.fHeight) {
774 if (fSize.fWidth < glyph.fWidth) { 814 if (fSize.fWidth < glyph.fWidth) {
775 fSize.fWidth = RoundSize(glyph.fWidth); 815 fSize.fWidth = RoundSize(glyph.fWidth);
776 } 816 }
777 if (fSize.fHeight < glyph.fHeight) { 817 if (fSize.fHeight < glyph.fHeight) {
778 fSize.fHeight = RoundSize(glyph.fHeight); 818 fSize.fHeight = RoundSize(glyph.fHeight);
779 } 819 }
780 820
781 rowBytes = fSize.fWidth * sizeof(CGRGBPixel); 821 rowBytes = fSize.fWidth * sizeof(CGRGBPixel);
782 void* image = fImageStorage.reset(rowBytes * fSize.fHeight); 822 void* image = fImageStorage.reset(rowBytes * fSize.fHeight);
823 const CGImageAlphaInfo alpha = (SkMask::kARGB32_Format == glyph.fMaskFor mat)
824 ? kCGImageAlphaPremultipliedFirst
825 : kCGImageAlphaNoneSkipFirst;
826 const CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host | alpha;
783 fCG.reset(CGBitmapContextCreate(image, fSize.fWidth, fSize.fHeight, 8, 827 fCG.reset(CGBitmapContextCreate(image, fSize.fWidth, fSize.fHeight, 8,
784 rowBytes, fRGBSpace, BITMAP_INFO_RGB)); 828 rowBytes, fRGBSpace, bitmapInfo));
785 829
786 // skia handles quantization itself, so we disable this for cg to get 830 // Skia handles quantization and subpixel positioning,
787 // full fractional data from them. 831 // so disable quantization and enabe subpixel positioning in CG.
788 CGContextSetAllowsFontSubpixelQuantization(fCG, false); 832 CGContextSetAllowsFontSubpixelQuantization(fCG, false);
789 CGContextSetShouldSubpixelQuantizeFonts(fCG, false); 833 CGContextSetShouldSubpixelQuantizeFonts(fCG, false);
790 834
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, 835 // Because CG always draws from the horizontal baseline,
797 // if there is a non-integral translation from the horizontal origin to the vertical origin, 836 // 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. 837 // then CG cannot draw the glyph in the correct location without subpixe l positioning.
799 CGContextSetAllowsFontSubpixelPositioning(fCG, context.fDoSubPosition || context.fVertical); 838 CGContextSetAllowsFontSubpixelPositioning(fCG, true);
800 CGContextSetShouldSubpixelPositionFonts(fCG, context.fDoSubPosition || c ontext.fVertical); 839 CGContextSetShouldSubpixelPositionFonts(fCG, true);
840
841 CGContextSetTextDrawingMode(fCG, kCGTextFill);
801 842
802 // Draw white on black to create mask. 843 // Draw white on black to create mask.
803 // TODO: Draw black on white and invert, CG has a special case codepath. 844 // TODO: Draw black on white and invert, CG has a special case codepath.
804 CGContextSetGrayFillColor(fCG, 1.0f, 1.0f); 845 CGContextSetGrayFillColor(fCG, 1.0f, 1.0f);
805 846
806 // force our checks below to happen 847 // force our checks below to happen
807 fDoAA = !doAA; 848 fDoAA = !doAA;
808 fDoLCD = !doLCD; 849 fDoLCD = !doLCD;
850
851 if (sk_legacy_CTFontDrawGlyphs == ctFontDrawGlyphs) {
852 // CTFontDrawGlyphs will apply the font, font size, and font matrix to the CGContext.
853 // Our 'fake' one does not, so set up the CGContext here.
854 CGContextSetFont(fCG, context.fCGFont);
855 CGContextSetFontSize(fCG, CTFontGetSize(context.fCTFont));
856 CGContextSetTextMatrix(fCG, CTFontGetMatrix(context.fCTFont));
857 }
809 } 858 }
810 859
811 if (fDoAA != doAA) { 860 if (fDoAA != doAA) {
812 CGContextSetShouldAntialias(fCG, doAA); 861 CGContextSetShouldAntialias(fCG, doAA);
813 fDoAA = doAA; 862 fDoAA = doAA;
814 } 863 }
815 if (fDoLCD != doLCD) { 864 if (fDoLCD != doLCD) {
816 CGContextSetShouldSmoothFonts(fCG, doLCD); 865 CGContextSetShouldSmoothFonts(fCG, doLCD);
817 fDoLCD = doLCD; 866 fDoLCD = doLCD;
818 } 867 }
819 868
820 CGRGBPixel* image = (CGRGBPixel*)fImageStorage.get(); 869 CGRGBPixel* image = (CGRGBPixel*)fImageStorage.get();
821 // skip rows based on the glyph's height 870 // skip rows based on the glyph's height
822 image += (fSize.fHeight - glyph.fHeight) * fSize.fWidth; 871 image += (fSize.fHeight - glyph.fHeight) * fSize.fWidth;
823 872
824 // erase to black 873 // erase to black
825 sk_memset_rect32(image, 0, glyph.fWidth, glyph.fHeight, rowBytes); 874 sk_memset_rect32(image, 0, glyph.fWidth, glyph.fHeight, rowBytes);
826 875
827 float subX = 0; 876 float subX = 0;
828 float subY = 0; 877 float subY = 0;
829 if (context.fDoSubPosition) { 878 if (context.fDoSubPosition) {
830 subX = SkFixedToFloat(glyph.getSubXFixed()); 879 subX = SkFixedToFloat(glyph.getSubXFixed());
831 subY = SkFixedToFloat(glyph.getSubYFixed()); 880 subY = SkFixedToFloat(glyph.getSubYFixed());
832 } 881 }
833 882
834 // CGContextShowGlyphsAtPoint always draws using the horizontal baseline ori gin. 883 // CoreText and CoreGraphics always draw using the horizontal baseline origi n.
835 if (context.fVertical) { 884 if (context.fVertical) {
836 SkPoint offset; 885 SkPoint offset;
837 context.getVerticalOffset(glyphID, &offset); 886 context.getVerticalOffset(glyphID, &offset);
838 subX += offset.fX; 887 subX += offset.fX;
839 subY += offset.fY; 888 subY += offset.fY;
840 } 889 }
841 890
842 CGContextShowGlyphsAtPoint(fCG, -glyph.fLeft + subX, 891 // CTFontDrawGlyphs and CGContextShowGlyphsAtPositions take 'positions' whic h are in text space.
843 glyph.fTop + glyph.fHeight - subY, 892 // The glyph location (in device space) must be mapped into text space, so t hat CG can convert
844 &glyphID, 1); 893 // it back into device space.
894 CGPoint point = CGPointMake(-glyph.fLeft + subX, glyph.fTop + glyph.fHeight - subY);
895 point = CGPointApplyAffineTransform(point, context.fInvTransform);
896 ctFontDrawGlyphs(context.fCTFont, &glyphID, &point, 1, fCG);
845 897
846 SkASSERT(rowBytesPtr); 898 SkASSERT(rowBytesPtr);
847 *rowBytesPtr = rowBytes; 899 *rowBytesPtr = rowBytes;
848 return image; 900 return image;
849 } 901 }
850 902
851 void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkPoint* offset) co nst { 903 void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkPoint* offset) co nst {
852 // Snow Leopard returns cgVertOffset in completely un-transformed FUnits (em space, y up). 904 // 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). 905 // Lion and Leopard return cgVertOffset in CG units (pixels, y up).
854 CGSize cgVertOffset; 906 CGSize cgVertOffset;
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
1038 skBounds.roundOut(&skIBounds); 1090 skBounds.roundOut(&skIBounds);
1039 // Expand the bounds by 1 pixel, to give CG room for anti-aliasing. 1091 // 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 1092 // 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. 1093 // 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. 1094 // 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); 1095 skIBounds.outset(1, 1);
1044 glyph->fLeft = SkToS16(skIBounds.fLeft); 1096 glyph->fLeft = SkToS16(skIBounds.fLeft);
1045 glyph->fTop = SkToS16(skIBounds.fTop); 1097 glyph->fTop = SkToS16(skIBounds.fTop);
1046 glyph->fWidth = SkToU16(skIBounds.width()); 1098 glyph->fWidth = SkToU16(skIBounds.width());
1047 glyph->fHeight = SkToU16(skIBounds.height()); 1099 glyph->fHeight = SkToU16(skIBounds.height());
1048
1049 #ifdef HACK_COLORGLYPHS
1050 glyph->fMaskFormat = SkMask::kARGB32_Format;
1051 #endif
1052 } 1100 }
1053 1101
1054 #include "SkColorPriv.h" 1102 #include "SkColorPriv.h"
1055 1103
1056 static void build_power_table(uint8_t table[], float ee) { 1104 static void build_power_table(uint8_t table[], float ee) {
1057 for (int i = 0; i < 256; i++) { 1105 for (int i = 0; i < 256; i++) {
1058 float x = i / 255.f; 1106 float x = i / 255.f;
1059 x = sk_float_pow(x, ee); 1107 x = sk_float_pow(x, ee);
1060 int xx = SkScalarRoundToInt(x * 255); 1108 int xx = SkScalarRoundToInt(x * 255);
1061 table[i] = SkToU8(xx); 1109 table[i] = SkToU8(xx);
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
1133 1181
1134 for (int y = 0; y < glyph.fHeight; y++) { 1182 for (int y = 0; y < glyph.fHeight; y++) {
1135 for (int i = 0; i < width; i++) { 1183 for (int i = 0; i < width; i++) {
1136 dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(cgPixels[i], tableR, tableG, t ableB); 1184 dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(cgPixels[i], tableR, tableG, t ableB);
1137 } 1185 }
1138 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes); 1186 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1139 dst = (uint16_t*)((char*)dst + dstRB); 1187 dst = (uint16_t*)((char*)dst + dstRB);
1140 } 1188 }
1141 } 1189 }
1142 1190
1143 #ifdef HACK_COLORGLYPHS 1191 static SkPMColor cgpixels_to_pmcolor(CGRGBPixel rgb) {
1144 // hack to colorize the output for testing kARGB32_Format 1192 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; 1193 U8CPU r = (rgb >> 16) & 0xFF;
1148 U8CPU g = (rgb >> 8) & 0xFF; 1194 U8CPU g = (rgb >> 8) & 0xFF;
1149 U8CPU b = (rgb >> 0) & 0xFF; 1195 U8CPU b = (rgb >> 0) & 0xFF;
1150 unsigned a = SkComputeLuminance(r, g, b);
1151 1196
1152 // compute gradient from x,y 1197 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 } 1198 }
1158 #endif
1159 1199
1160 template <typename T> T* SkTAddByteOffset(T* ptr, size_t byteOffset) { 1200 template <typename T> T* SkTAddByteOffset(T* ptr, size_t byteOffset) {
1161 return (T*)((char*)ptr + byteOffset); 1201 return (T*)((char*)ptr + byteOffset);
1162 } 1202 }
1163 1203
1164 void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) { 1204 void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
1165 CGGlyph cgGlyph = (CGGlyph) glyph.getGlyphID(); 1205 CGGlyph cgGlyph = (CGGlyph) glyph.getGlyphID();
1166 1206
1167 // FIXME: lcd smoothed un-hinted rasterization unsupported. 1207 // FIXME: lcd smoothed un-hinted rasterization unsupported.
1168 bool generateA8FromLCD = fRec.getHinting() != SkPaint::kNo_Hinting; 1208 bool generateA8FromLCD = fRec.getHinting() != SkPaint::kNo_Hinting;
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
1221 case SkMask::kBW_Format: { 1261 case SkMask::kBW_Format: {
1222 const int width = glyph.fWidth; 1262 const int width = glyph.fWidth;
1223 size_t dstRB = glyph.rowBytes(); 1263 size_t dstRB = glyph.rowBytes();
1224 uint8_t* dst = (uint8_t*)glyph.fImage; 1264 uint8_t* dst = (uint8_t*)glyph.fImage;
1225 for (int y = 0; y < glyph.fHeight; y++) { 1265 for (int y = 0; y < glyph.fHeight; y++) {
1226 cgpixels_to_bits(dst, cgPixels, width); 1266 cgpixels_to_bits(dst, cgPixels, width);
1227 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes); 1267 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1228 dst += dstRB; 1268 dst += dstRB;
1229 } 1269 }
1230 } break; 1270 } break;
1231 #ifdef HACK_COLORGLYPHS
1232 case SkMask::kARGB32_Format: { 1271 case SkMask::kARGB32_Format: {
1233 const int width = glyph.fWidth; 1272 const int width = glyph.fWidth;
1234 size_t dstRB = glyph.rowBytes(); 1273 size_t dstRB = glyph.rowBytes();
1235 SkPMColor* dst = (SkPMColor*)glyph.fImage; 1274 SkPMColor* dst = (SkPMColor*)glyph.fImage;
1236 for (int y = 0; y < glyph.fHeight; y++) { 1275 for (int y = 0; y < glyph.fHeight; y++) {
1237 for (int x = 0; x < width; ++x) { 1276 for (int x = 0; x < width; ++x) {
1238 dst[x] = cgpixels_to_pmcolor(cgPixels[x], glyph, x, y); 1277 dst[x] = cgpixels_to_pmcolor(cgPixels[x]);
1239 } 1278 }
1240 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes); 1279 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1241 dst = (SkPMColor*)((char*)dst + dstRB); 1280 dst = (SkPMColor*)((char*)dst + dstRB);
1242 } 1281 }
1243 } break; 1282 } break;
1244 #endif
1245 default: 1283 default:
1246 SkDEBUGFAIL("unexpected mask format"); 1284 SkDEBUGFAIL("unexpected mask format");
1247 break; 1285 break;
1248 } 1286 }
1249 } 1287 }
1250 1288
1251 /* 1289 /*
1252 * Our subpixel resolution is only 2 bits in each direction, so a scale of 4 1290 * 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 1291 * seems sufficient, and possibly even correct, to allow the hinted outline
1254 * to be subpixel positioned. 1292 * to be subpixel positioned.
(...skipping 566 matching lines...) Expand 10 before | Expand all | Expand 10 after
1821 if (isLCDFormat(rec->fMaskFormat)) { 1859 if (isLCDFormat(rec->fMaskFormat)) {
1822 if (lcdSupport) { 1860 if (lcdSupport) {
1823 //CoreGraphics creates 555 masks for smoothed text anyway. 1861 //CoreGraphics creates 555 masks for smoothed text anyway.
1824 rec->fMaskFormat = SkMask::kLCD16_Format; 1862 rec->fMaskFormat = SkMask::kLCD16_Format;
1825 rec->setHinting(SkPaint::kNormal_Hinting); 1863 rec->setHinting(SkPaint::kNormal_Hinting);
1826 } else { 1864 } else {
1827 rec->fMaskFormat = SkMask::kA8_Format; 1865 rec->fMaskFormat = SkMask::kA8_Format;
1828 } 1866 }
1829 } 1867 }
1830 1868
1869 // CoreText provides no information as to whether a glyph will be color or n ot.
1870 // Fonts may mix outlines and bitmaps, so information is needed on a glyph b y glyph basis.
1871 // If a font contains an 'sbix' table, consider it to be a color font, and d isable lcd.
1872 AutoCFRelease<CFArrayRef> tags(CTFontCopyAvailableTables(fFontRef,kCTFontTab leOptionNoOptions));
reed1 2014/12/08 21:24:44 should we lazily do this and cache the answer in t
bungeman-skia 2014/12/08 21:33:22 This is onFilterRec, so it is being cached in the
1873 if (tags) {
1874 int count = SkToInt(CFArrayGetCount(tags));
1875 for (int i = 0; i < count; ++i) {
1876 uintptr_t tag = reinterpret_cast<uintptr_t>(CFArrayGetValueAtIndex(t ags, i));
1877 if ('sbix' == tag) {
1878 //probably color
1879 rec->fMaskFormat = SkMask::kARGB32_Format;
1880 break;
1881 }
1882 }
1883 }
1884
1831 // Unhinted A8 masks (those not derived from LCD masks) must respect SK_GAMM A_APPLY_TO_A8. 1885 // 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. 1886 // All other masks can use regular gamma.
1833 if (SkMask::kA8_Format == rec->fMaskFormat && SkPaint::kNo_Hinting == hintin g) { 1887 if (SkMask::kA8_Format == rec->fMaskFormat && SkPaint::kNo_Hinting == hintin g) {
1834 #ifndef SK_GAMMA_APPLY_TO_A8 1888 #ifndef SK_GAMMA_APPLY_TO_A8
1835 rec->ignorePreBlend(); 1889 rec->ignorePreBlend();
1836 #endif 1890 #endif
1837 } else { 1891 } else {
1838 //CoreGraphics dialates smoothed text as needed. 1892 //CoreGraphics dialates smoothed text as needed.
1839 rec->setContrast(0); 1893 rec->setContrast(0);
1840 } 1894 }
(...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after
2211 } 2265 }
2212 return face; 2266 return face;
2213 } 2267 }
2214 }; 2268 };
2215 2269
2216 /////////////////////////////////////////////////////////////////////////////// 2270 ///////////////////////////////////////////////////////////////////////////////
2217 2271
2218 SkFontMgr* SkFontMgr::Factory() { 2272 SkFontMgr* SkFontMgr::Factory() {
2219 return SkNEW(SkFontMgr_Mac); 2273 return SkNEW(SkFontMgr_Mac);
2220 } 2274 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698