Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |