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 #include <vector> | 9 #include <vector> |
10 #ifdef SK_BUILD_FOR_MAC | 10 #ifdef SK_BUILD_FOR_MAC |
(...skipping 26 matching lines...) Expand all Loading... |
37 #include "SkPath.h" | 37 #include "SkPath.h" |
38 #include "SkString.h" | 38 #include "SkString.h" |
39 #include "SkStream.h" | 39 #include "SkStream.h" |
40 #include "SkThread.h" | 40 #include "SkThread.h" |
41 #include "SkTypeface_mac.h" | 41 #include "SkTypeface_mac.h" |
42 #include "SkUtils.h" | 42 #include "SkUtils.h" |
43 #include "SkTypefaceCache.h" | 43 #include "SkTypefaceCache.h" |
44 #include "SkFontMgr.h" | 44 #include "SkFontMgr.h" |
45 | 45 |
46 //#define HACK_COLORGLYPHS | 46 //#define HACK_COLORGLYPHS |
47 //#define SK_IGNORE_MAC_TEXT_BOUNDS_FIX | |
48 | 47 |
49 class SkScalerContext_Mac; | 48 class SkScalerContext_Mac; |
50 | 49 |
51 // CTFontManagerCopyAvailableFontFamilyNames() is not always available, so we | 50 // CTFontManagerCopyAvailableFontFamilyNames() is not always available, so we |
52 // provide a wrapper here that will return an empty array if need be. | 51 // provide a wrapper here that will return an empty array if need be. |
53 static CFArrayRef SkCTFontManagerCopyAvailableFontFamilyNames() { | 52 static CFArrayRef SkCTFontManagerCopyAvailableFontFamilyNames() { |
54 #ifdef SK_BUILD_FOR_IOS | 53 #ifdef SK_BUILD_FOR_IOS |
55 return CFArrayCreate(NULL, NULL, 0, NULL); | 54 return CFArrayCreate(NULL, NULL, 0, NULL); |
56 #else | 55 #else |
57 return CTFontManagerCopyAvailableFontFamilyNames(); | 56 return CTFontManagerCopyAvailableFontFamilyNames(); |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
118 public: | 117 public: |
119 const T* fData; | 118 const T* fData; |
120 }; | 119 }; |
121 | 120 |
122 // inline versions of these rect helpers | 121 // inline versions of these rect helpers |
123 | 122 |
124 static bool CGRectIsEmpty_inline(const CGRect& rect) { | 123 static bool CGRectIsEmpty_inline(const CGRect& rect) { |
125 return rect.size.width <= 0 || rect.size.height <= 0; | 124 return rect.size.width <= 0 || rect.size.height <= 0; |
126 } | 125 } |
127 | 126 |
128 #if defined(SK_IGNORE_MAC_TEXT_BOUNDS_FIX) | |
129 static void CGRectInset_inline(CGRect* rect, CGFloat dx, CGFloat dy) { | |
130 rect->origin.x += dx; | |
131 rect->origin.y += dy; | |
132 rect->size.width -= dx * 2; | |
133 rect->size.height -= dy * 2; | |
134 } | |
135 #endif | |
136 | |
137 static CGFloat CGRectGetMinX_inline(const CGRect& rect) { | 127 static CGFloat CGRectGetMinX_inline(const CGRect& rect) { |
138 return rect.origin.x; | 128 return rect.origin.x; |
139 } | 129 } |
140 | 130 |
141 static CGFloat CGRectGetMaxX_inline(const CGRect& rect) { | 131 static CGFloat CGRectGetMaxX_inline(const CGRect& rect) { |
142 return rect.origin.x + rect.size.width; | 132 return rect.origin.x + rect.size.width; |
143 } | 133 } |
144 | 134 |
145 static CGFloat CGRectGetMinY_inline(const CGRect& rect) { | 135 static CGFloat CGRectGetMinY_inline(const CGRect& rect) { |
146 return rect.origin.y; | 136 return rect.origin.y; |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
292 SkScalar sx = SK_Scalar1, | 282 SkScalar sx = SK_Scalar1, |
293 SkScalar sy = SK_Scalar1) { | 283 SkScalar sy = SK_Scalar1) { |
294 return CGAffineTransformMake( ScalarToCG(matrix[SkMatrix::kMScaleX] * sx), | 284 return CGAffineTransformMake( ScalarToCG(matrix[SkMatrix::kMScaleX] * sx), |
295 -ScalarToCG(matrix[SkMatrix::kMSkewY] * sy), | 285 -ScalarToCG(matrix[SkMatrix::kMSkewY] * sy), |
296 -ScalarToCG(matrix[SkMatrix::kMSkewX] * sx), | 286 -ScalarToCG(matrix[SkMatrix::kMSkewX] * sx), |
297 ScalarToCG(matrix[SkMatrix::kMScaleY] * sy), | 287 ScalarToCG(matrix[SkMatrix::kMScaleY] * sy), |
298 ScalarToCG(matrix[SkMatrix::kMTransX] * sx), | 288 ScalarToCG(matrix[SkMatrix::kMTransX] * sx), |
299 ScalarToCG(matrix[SkMatrix::kMTransY] * sy)); | 289 ScalarToCG(matrix[SkMatrix::kMTransY] * sy)); |
300 } | 290 } |
301 | 291 |
302 #if defined(SK_IGNORE_MAC_TEXT_BOUNDS_FIX) | |
303 static SkScalar getFontScale(CGFontRef cgFont) { | |
304 int unitsPerEm = CGFontGetUnitsPerEm(cgFont); | |
305 return SkScalarInvert(SkIntToScalar(unitsPerEm)); | |
306 } | |
307 #endif | |
308 | |
309 /////////////////////////////////////////////////////////////////////////////// | 292 /////////////////////////////////////////////////////////////////////////////// |
310 | 293 |
311 #define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host) | 294 #define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host) |
312 #define BITMAP_INFO_GRAY (kCGImageAlphaNone) | 295 #define BITMAP_INFO_GRAY (kCGImageAlphaNone) |
313 | 296 |
314 /** | 297 /** |
315 * There does not appear to be a publicly accessable API for determining if lcd | 298 * There does not appear to be a publicly accessable API for determining if lcd |
316 * font smoothing will be applied if we request it. The main issue is that if | 299 * font smoothing will be applied if we request it. The main issue is that if |
317 * smoothing is applied a gamma of 2.0 will be used, if not a gamma of 1.0. | 300 * smoothing is applied a gamma of 2.0 will be used, if not a gamma of 1.0. |
318 */ | 301 */ |
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
636 if (face) { | 619 if (face) { |
637 SkTypefaceCache::Add(face, style); | 620 SkTypefaceCache::Add(face, style); |
638 } else { | 621 } else { |
639 face = GetDefaultFace(); | 622 face = GetDefaultFace(); |
640 face->ref(); | 623 face->ref(); |
641 } | 624 } |
642 } | 625 } |
643 return face; | 626 return face; |
644 } | 627 } |
645 | 628 |
646 #if defined(SK_IGNORE_MAC_TEXT_BOUNDS_FIX) | |
647 static void flip(SkMatrix* matrix) { | |
648 matrix->setSkewX(-matrix->getSkewX()); | |
649 matrix->setSkewY(-matrix->getSkewY()); | |
650 } | |
651 #endif | |
652 | |
653 /////////////////////////////////////////////////////////////////////////////// | 629 /////////////////////////////////////////////////////////////////////////////// |
654 | 630 |
655 /** GlyphRect is in FUnits (em space, y up). */ | 631 /** GlyphRect is in FUnits (em space, y up). */ |
656 struct GlyphRect { | 632 struct GlyphRect { |
657 int16_t fMinX; | 633 int16_t fMinX; |
658 int16_t fMinY; | 634 int16_t fMinY; |
659 int16_t fMaxX; | 635 int16_t fMaxX; |
660 int16_t fMaxY; | 636 int16_t fMaxY; |
661 }; | 637 }; |
662 | 638 |
663 class SkScalerContext_Mac : public SkScalerContext { | 639 class SkScalerContext_Mac : public SkScalerContext { |
664 public: | 640 public: |
665 SkScalerContext_Mac(SkTypeface_Mac*, const SkDescriptor*); | 641 SkScalerContext_Mac(SkTypeface_Mac*, const SkDescriptor*); |
666 | 642 |
667 protected: | 643 protected: |
668 unsigned generateGlyphCount(void) SK_OVERRIDE; | 644 unsigned generateGlyphCount(void) SK_OVERRIDE; |
669 uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE; | 645 uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE; |
670 void generateAdvance(SkGlyph* glyph) SK_OVERRIDE; | 646 void generateAdvance(SkGlyph* glyph) SK_OVERRIDE; |
671 void generateMetrics(SkGlyph* glyph) SK_OVERRIDE; | 647 void generateMetrics(SkGlyph* glyph) SK_OVERRIDE; |
672 void generateImage(const SkGlyph& glyph) SK_OVERRIDE; | 648 void generateImage(const SkGlyph& glyph) SK_OVERRIDE; |
673 void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE; | 649 void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE; |
674 void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY)
SK_OVERRIDE; | 650 void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY)
SK_OVERRIDE; |
675 | 651 |
676 private: | 652 private: |
677 static void CTPathElement(void *info, const CGPathElement *element); | 653 static void CTPathElement(void *info, const CGPathElement *element); |
678 | 654 |
679 #if defined(SK_IGNORE_MAC_TEXT_BOUNDS_FIX) | |
680 void getVerticalOffset(CGGlyph glyphID, SkIPoint* offset) const; | |
681 #else | |
682 /** Returns the offset from the horizontal origin to the vertical origin in
SkGlyph units. */ | 655 /** Returns the offset from the horizontal origin to the vertical origin in
SkGlyph units. */ |
683 void getVerticalOffset(CGGlyph glyphID, SkPoint* offset) const; | 656 void getVerticalOffset(CGGlyph glyphID, SkPoint* offset) const; |
684 #endif | |
685 | 657 |
686 /** Initializes and returns the value of fFBoundingBoxesGlyphOffset. | 658 /** Initializes and returns the value of fFBoundingBoxesGlyphOffset. |
687 * | 659 * |
688 * For use with (and must be called before) generateBBoxes. | 660 * For use with (and must be called before) generateBBoxes. |
689 */ | 661 */ |
690 uint16_t getFBoundingBoxesGlyphOffset(); | 662 uint16_t getFBoundingBoxesGlyphOffset(); |
691 | 663 |
692 /** Initializes fFBoundingBoxes and returns true on success. | 664 /** Initializes fFBoundingBoxes and returns true on success. |
693 * | 665 * |
694 * On Lion and Mountain Lion, CTFontGetBoundingRectsForGlyphs has a bug whi
ch causes it to | 666 * On Lion and Mountain Lion, CTFontGetBoundingRectsForGlyphs has a bug whi
ch causes it to |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
727 AutoCFRelease<CTFontRef> fCTVerticalFont; | 699 AutoCFRelease<CTFontRef> fCTVerticalFont; |
728 | 700 |
729 AutoCFRelease<CGFontRef> fCGFont; | 701 AutoCFRelease<CGFontRef> fCGFont; |
730 SkAutoTMalloc<GlyphRect> fFBoundingBoxes; | 702 SkAutoTMalloc<GlyphRect> fFBoundingBoxes; |
731 uint16_t fFBoundingBoxesGlyphOffset; | 703 uint16_t fFBoundingBoxesGlyphOffset; |
732 uint16_t fGlyphCount; | 704 uint16_t fGlyphCount; |
733 bool fGeneratedFBoundingBoxes; | 705 bool fGeneratedFBoundingBoxes; |
734 const bool fDoSubPosition; | 706 const bool fDoSubPosition; |
735 const bool fVertical; | 707 const bool fVertical; |
736 | 708 |
737 #if defined(SK_IGNORE_MAC_TEXT_BOUNDS_FIX) | |
738 SkMatrix fVerticalMatrix; // unit rotated | |
739 SkMatrix fMatrix; // with font size | |
740 SkMatrix fFBoundingBoxesMatrix; // lion-specific fix | |
741 SkMatrix fUnitMatrix; // without font size | |
742 #endif | |
743 | |
744 friend class Offscreen; | 709 friend class Offscreen; |
745 | 710 |
746 typedef SkScalerContext INHERITED; | 711 typedef SkScalerContext INHERITED; |
747 }; | 712 }; |
748 | 713 |
749 SkScalerContext_Mac::SkScalerContext_Mac(SkTypeface_Mac* typeface, | 714 SkScalerContext_Mac::SkScalerContext_Mac(SkTypeface_Mac* typeface, |
750 const SkDescriptor* desc) | 715 const SkDescriptor* desc) |
751 : INHERITED(typeface, desc) | 716 : INHERITED(typeface, desc) |
752 , fFBoundingBoxes() | 717 , fFBoundingBoxes() |
753 , fFBoundingBoxesGlyphOffset(0) | 718 , fFBoundingBoxesGlyphOffset(0) |
754 , fGeneratedFBoundingBoxes(false) | 719 , fGeneratedFBoundingBoxes(false) |
755 , fDoSubPosition(SkToBool(fRec.fFlags & kSubpixelPositioning_Flag)) | 720 , fDoSubPosition(SkToBool(fRec.fFlags & kSubpixelPositioning_Flag)) |
756 , fVertical(SkToBool(fRec.fFlags & kVertical_Flag)) | 721 , fVertical(SkToBool(fRec.fFlags & kVertical_Flag)) |
757 | 722 |
758 { | 723 { |
759 CTFontRef ctFont = typeface->fFontRef.get(); | 724 CTFontRef ctFont = typeface->fFontRef.get(); |
760 CFIndex numGlyphs = CTFontGetGlyphCount(ctFont); | 725 CFIndex numGlyphs = CTFontGetGlyphCount(ctFont); |
761 SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF); | 726 SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF); |
762 fGlyphCount = SkToU16(numGlyphs); | 727 fGlyphCount = SkToU16(numGlyphs); |
763 | 728 |
764 #if defined(SK_IGNORE_MAC_TEXT_BOUNDS_FIX) | |
765 // Get the state we need | |
766 fRec.getSingleMatrix(&fMatrix); | |
767 CGAffineTransform transform = MatrixToCGAffineTransform(fMatrix); | |
768 | |
769 // extract the font size out of the matrix, but leave the skewing for italic | |
770 SkScalar reciprocal = SkScalarInvert(fRec.fTextSize); | |
771 fUnitMatrix = fMatrix; | |
772 fUnitMatrix.preScale(reciprocal, reciprocal); | |
773 flip(&fUnitMatrix); // flip to fix up bounds later | |
774 #else | |
775 fRec.getSingleMatrix(&fFUnitMatrix); | 729 fRec.getSingleMatrix(&fFUnitMatrix); |
776 CGAffineTransform transform = MatrixToCGAffineTransform(fFUnitMatrix); | 730 CGAffineTransform transform = MatrixToCGAffineTransform(fFUnitMatrix); |
777 #endif | |
778 | 731 |
779 AutoCFRelease<CTFontDescriptorRef> ctFontDesc; | 732 AutoCFRelease<CTFontDescriptorRef> ctFontDesc; |
780 if (fVertical) { | 733 if (fVertical) { |
781 AutoCFRelease<CFMutableDictionaryRef> cfAttributes(CFDictionaryCreateMut
able( | 734 AutoCFRelease<CFMutableDictionaryRef> cfAttributes(CFDictionaryCreateMut
able( |
782 kCFAllocatorDefault, 0, | 735 kCFAllocatorDefault, 0, |
783 &kCFTypeDictionaryKeyCallBacks, | 736 &kCFTypeDictionaryKeyCallBacks, |
784 &kCFTypeDictionaryValueCallBacks)); | 737 &kCFTypeDictionaryValueCallBacks)); |
785 if (cfAttributes) { | 738 if (cfAttributes) { |
786 CTFontOrientation ctOrientation = kCTFontVerticalOrientation; | 739 CTFontOrientation ctOrientation = kCTFontVerticalOrientation; |
787 AutoCFRelease<CFNumberRef> cfVertical(CFNumberCreate( | 740 AutoCFRelease<CFNumberRef> cfVertical(CFNumberCreate( |
788 kCFAllocatorDefault, kCFNumberSInt32Type, &ctOrientation)); | 741 kCFAllocatorDefault, kCFNumberSInt32Type, &ctOrientation)); |
789 CFDictionaryAddValue(cfAttributes, kCTFontOrientationAttribute, cfVe
rtical); | 742 CFDictionaryAddValue(cfAttributes, kCTFontOrientationAttribute, cfVe
rtical); |
790 ctFontDesc = CTFontDescriptorCreateWithAttributes(cfAttributes); | 743 ctFontDesc = CTFontDescriptorCreateWithAttributes(cfAttributes); |
791 } | 744 } |
792 } | 745 } |
793 // Since our matrix includes everything, we pass 1 for size. | 746 // Since our matrix includes everything, we pass 1 for size. |
794 fCTFont = CTFontCreateCopyWithAttributes(ctFont, 1, &transform, ctFontDesc); | 747 fCTFont = CTFontCreateCopyWithAttributes(ctFont, 1, &transform, ctFontDesc); |
795 fCGFont = CTFontCopyGraphicsFont(fCTFont, NULL); | 748 fCGFont = CTFontCopyGraphicsFont(fCTFont, NULL); |
796 if (fVertical) { | 749 if (fVertical) { |
797 CGAffineTransform rotateLeft = CGAffineTransformMake(0, -1, 1, 0, 0, 0); | 750 CGAffineTransform rotateLeft = CGAffineTransformMake(0, -1, 1, 0, 0, 0); |
798 transform = CGAffineTransformConcat(rotateLeft, transform); | 751 transform = CGAffineTransformConcat(rotateLeft, transform); |
799 fCTVerticalFont = CTFontCreateCopyWithAttributes(ctFont, 1, &transform,
NULL); | 752 fCTVerticalFont = CTFontCreateCopyWithAttributes(ctFont, 1, &transform,
NULL); |
800 #if defined(SK_IGNORE_MAC_TEXT_BOUNDS_FIX) | |
801 fVerticalMatrix = fUnitMatrix; | |
802 if (isSnowLeopard()) { | |
803 SkScalar scale = SkScalarMul(fRec.fTextSize, getFontScale(fCGFont)); | |
804 fVerticalMatrix.preScale(scale, scale); | |
805 } else { | |
806 fVerticalMatrix.preRotate(SkIntToScalar(90)); | |
807 } | |
808 fVerticalMatrix.postScale(SK_Scalar1, -SK_Scalar1); | |
809 #endif | |
810 } | 753 } |
811 #if defined(SK_IGNORE_MAC_TEXT_BOUNDS_FIX) | 754 |
812 #else | |
813 SkScalar emPerFUnit = SkScalarInvert(SkIntToScalar(CGFontGetUnitsPerEm(fCGFo
nt))); | 755 SkScalar emPerFUnit = SkScalarInvert(SkIntToScalar(CGFontGetUnitsPerEm(fCGFo
nt))); |
814 fFUnitMatrix.preScale(emPerFUnit, -emPerFUnit); | 756 fFUnitMatrix.preScale(emPerFUnit, -emPerFUnit); |
815 #endif | |
816 } | 757 } |
817 | 758 |
818 CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph&
glyph, | 759 CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph&
glyph, |
819 CGGlyph glyphID, size_t* rowBytesPtr, | 760 CGGlyph glyphID, size_t* rowBytesPtr, |
820 bool generateA8FromLCD) { | 761 bool generateA8FromLCD) { |
821 if (!fRGBSpace) { | 762 if (!fRGBSpace) { |
822 //It doesn't appear to matter what color space is specified. | 763 //It doesn't appear to matter what color space is specified. |
823 //Regular blends and antialiased text are always (s*a + d*(1-a)) | 764 //Regular blends and antialiased text are always (s*a + d*(1-a)) |
824 //and smoothed text is always g=2.0. | 765 //and smoothed text is always g=2.0. |
825 fRGBSpace = CGColorSpaceCreateDeviceRGB(); | 766 fRGBSpace = CGColorSpaceCreateDeviceRGB(); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
857 // skia handles quantization itself, so we disable this for cg to get | 798 // skia handles quantization itself, so we disable this for cg to get |
858 // full fractional data from them. | 799 // full fractional data from them. |
859 CGContextSetAllowsFontSubpixelQuantization(fCG, false); | 800 CGContextSetAllowsFontSubpixelQuantization(fCG, false); |
860 CGContextSetShouldSubpixelQuantizeFonts(fCG, false); | 801 CGContextSetShouldSubpixelQuantizeFonts(fCG, false); |
861 | 802 |
862 CGContextSetTextDrawingMode(fCG, kCGTextFill); | 803 CGContextSetTextDrawingMode(fCG, kCGTextFill); |
863 CGContextSetFont(fCG, context.fCGFont); | 804 CGContextSetFont(fCG, context.fCGFont); |
864 CGContextSetFontSize(fCG, 1 /*CTFontGetSize(context.fCTFont)*/); | 805 CGContextSetFontSize(fCG, 1 /*CTFontGetSize(context.fCTFont)*/); |
865 CGContextSetTextMatrix(fCG, CTFontGetMatrix(context.fCTFont)); | 806 CGContextSetTextMatrix(fCG, CTFontGetMatrix(context.fCTFont)); |
866 | 807 |
867 #if defined(SK_IGNORE_MAC_TEXT_BOUNDS_FIX) | |
868 CGContextSetAllowsFontSubpixelPositioning(fCG, context.fDoSubPosition); | |
869 CGContextSetShouldSubpixelPositionFonts(fCG, context.fDoSubPosition); | |
870 #else | |
871 // Because CG always draws from the horizontal baseline, | 808 // Because CG always draws from the horizontal baseline, |
872 // if there is a non-integral translation from the horizontal origin to
the vertical origin, | 809 // if there is a non-integral translation from the horizontal origin to
the vertical origin, |
873 // then CG cannot draw the glyph in the correct location without subpixe
l positioning. | 810 // then CG cannot draw the glyph in the correct location without subpixe
l positioning. |
874 CGContextSetAllowsFontSubpixelPositioning(fCG, context.fDoSubPosition ||
context.fVertical); | 811 CGContextSetAllowsFontSubpixelPositioning(fCG, context.fDoSubPosition ||
context.fVertical); |
875 CGContextSetShouldSubpixelPositionFonts(fCG, context.fDoSubPosition || c
ontext.fVertical); | 812 CGContextSetShouldSubpixelPositionFonts(fCG, context.fDoSubPosition || c
ontext.fVertical); |
876 #endif | |
877 | 813 |
878 // Draw white on black to create mask. | 814 // Draw white on black to create mask. |
879 // TODO: Draw black on white and invert, CG has a special case codepath. | 815 // TODO: Draw black on white and invert, CG has a special case codepath. |
880 CGContextSetGrayFillColor(fCG, 1.0f, 1.0f); | 816 CGContextSetGrayFillColor(fCG, 1.0f, 1.0f); |
881 | 817 |
882 // force our checks below to happen | 818 // force our checks below to happen |
883 fDoAA = !doAA; | 819 fDoAA = !doAA; |
884 fDoLCD = !doLCD; | 820 fDoLCD = !doLCD; |
885 } | 821 } |
886 | 822 |
(...skipping 15 matching lines...) Expand all Loading... |
902 | 838 |
903 float subX = 0; | 839 float subX = 0; |
904 float subY = 0; | 840 float subY = 0; |
905 if (context.fDoSubPosition) { | 841 if (context.fDoSubPosition) { |
906 subX = SkFixedToFloat(glyph.getSubXFixed()); | 842 subX = SkFixedToFloat(glyph.getSubXFixed()); |
907 subY = SkFixedToFloat(glyph.getSubYFixed()); | 843 subY = SkFixedToFloat(glyph.getSubYFixed()); |
908 } | 844 } |
909 | 845 |
910 // CGContextShowGlyphsAtPoint always draws using the horizontal baseline ori
gin. | 846 // CGContextShowGlyphsAtPoint always draws using the horizontal baseline ori
gin. |
911 if (context.fVertical) { | 847 if (context.fVertical) { |
912 #if defined(SK_IGNORE_MAC_TEXT_BOUNDS_FIX) | |
913 SkIPoint offset; | |
914 #else | |
915 SkPoint offset; | 848 SkPoint offset; |
916 #endif | |
917 context.getVerticalOffset(glyphID, &offset); | 849 context.getVerticalOffset(glyphID, &offset); |
918 subX += offset.fX; | 850 subX += offset.fX; |
919 subY += offset.fY; | 851 subY += offset.fY; |
920 } | 852 } |
921 | 853 |
922 CGContextShowGlyphsAtPoint(fCG, -glyph.fLeft + subX, | 854 CGContextShowGlyphsAtPoint(fCG, -glyph.fLeft + subX, |
923 glyph.fTop + glyph.fHeight - subY, | 855 glyph.fTop + glyph.fHeight - subY, |
924 &glyphID, 1); | 856 &glyphID, 1); |
925 | 857 |
926 SkASSERT(rowBytesPtr); | 858 SkASSERT(rowBytesPtr); |
927 *rowBytesPtr = rowBytes; | 859 *rowBytesPtr = rowBytes; |
928 return image; | 860 return image; |
929 } | 861 } |
930 | 862 |
931 #if defined(SK_IGNORE_MAC_TEXT_BOUNDS_FIX) | |
932 void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkIPoint* offset) c
onst { | |
933 CGSize vertOffset; | |
934 CTFontGetVerticalTranslationsForGlyphs(fCTVerticalFont, &glyphID, &vertOffse
t, 1); | |
935 const SkPoint trans = {CGToScalar(vertOffset.width), | |
936 CGToScalar(vertOffset.height)}; | |
937 SkPoint floatOffset; | |
938 fVerticalMatrix.mapPoints(&floatOffset, &trans, 1); | |
939 if (!isSnowLeopard()) { | |
940 // SnowLeopard fails to apply the font's matrix to the vertical metrics, | |
941 // but Lion and Leopard do. The unit matrix describes the font's matrix at | |
942 // point size 1. There may be some way to avoid mapping here by setting up | |
943 // fVerticalMatrix differently, but this works for now. | |
944 fUnitMatrix.mapPoints(&floatOffset, 1); | |
945 } | |
946 offset->fX = SkScalarRound(floatOffset.fX); | |
947 offset->fY = SkScalarRound(floatOffset.fY); | |
948 } | |
949 #else | |
950 void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkPoint* offset) co
nst { | 863 void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkPoint* offset) co
nst { |
951 // Snow Leopard returns cgVertOffset in completely un-transformed FUnits (em
space, y up). | 864 // Snow Leopard returns cgVertOffset in completely un-transformed FUnits (em
space, y up). |
952 // Lion and Leopard return cgVertOffset in CG units (pixels, y up). | 865 // Lion and Leopard return cgVertOffset in CG units (pixels, y up). |
953 CGSize cgVertOffset; | 866 CGSize cgVertOffset; |
954 CTFontGetVerticalTranslationsForGlyphs(fCTFont, &glyphID, &cgVertOffset, 1); | 867 CTFontGetVerticalTranslationsForGlyphs(fCTFont, &glyphID, &cgVertOffset, 1); |
955 | 868 |
956 SkPoint skVertOffset = { CGToScalar(cgVertOffset.width), CGToScalar(cgVertOf
fset.height) }; | 869 SkPoint skVertOffset = { CGToScalar(cgVertOffset.width), CGToScalar(cgVertOf
fset.height) }; |
957 if (isSnowLeopard()) { | 870 if (isSnowLeopard()) { |
958 // From FUnits (em space, y up) to SkGlyph units (pixels, y down). | 871 // From FUnits (em space, y up) to SkGlyph units (pixels, y down). |
959 fFUnitMatrix.mapPoints(&skVertOffset, 1); | 872 fFUnitMatrix.mapPoints(&skVertOffset, 1); |
960 } else { | 873 } else { |
961 // From CG units (pixels, y up) to SkGlyph units (pixels, y down). | 874 // From CG units (pixels, y up) to SkGlyph units (pixels, y down). |
962 skVertOffset.fY = -skVertOffset.fY; | 875 skVertOffset.fY = -skVertOffset.fY; |
963 } | 876 } |
964 | 877 |
965 *offset = skVertOffset; | 878 *offset = skVertOffset; |
966 } | 879 } |
967 #endif | |
968 | 880 |
969 uint16_t SkScalerContext_Mac::getFBoundingBoxesGlyphOffset() { | 881 uint16_t SkScalerContext_Mac::getFBoundingBoxesGlyphOffset() { |
970 if (fFBoundingBoxesGlyphOffset) { | 882 if (fFBoundingBoxesGlyphOffset) { |
971 return fFBoundingBoxesGlyphOffset; | 883 return fFBoundingBoxesGlyphOffset; |
972 } | 884 } |
973 fFBoundingBoxesGlyphOffset = fGlyphCount; // fallback for all fonts | 885 fFBoundingBoxesGlyphOffset = fGlyphCount; // fallback for all fonts |
974 AutoCGTable<SkOTTableHorizontalHeader> hheaTable(fCGFont); | 886 AutoCGTable<SkOTTableHorizontalHeader> hheaTable(fCGFont); |
975 if (hheaTable.fData) { | 887 if (hheaTable.fData) { |
976 fFBoundingBoxesGlyphOffset = SkEndian_SwapBE16(hheaTable->numberOfHMetri
cs); | 888 fFBoundingBoxesGlyphOffset = SkEndian_SwapBE16(hheaTable->numberOfHMetri
cs); |
977 } | 889 } |
(...skipping 28 matching lines...) Expand all Loading... |
1006 SkOTTableGlyph::Iterator glyphDataIter(*glyfTable.fData, *locaTable.fData, l
ocaFormat); | 918 SkOTTableGlyph::Iterator glyphDataIter(*glyfTable.fData, *locaTable.fData, l
ocaFormat); |
1007 glyphDataIter.advance(fFBoundingBoxesGlyphOffset); | 919 glyphDataIter.advance(fFBoundingBoxesGlyphOffset); |
1008 for (uint16_t boundingBoxesIndex = 0; boundingBoxesIndex < entries; ++boundi
ngBoxesIndex) { | 920 for (uint16_t boundingBoxesIndex = 0; boundingBoxesIndex < entries; ++boundi
ngBoxesIndex) { |
1009 const SkOTTableGlyphData* glyphData = glyphDataIter.next(); | 921 const SkOTTableGlyphData* glyphData = glyphDataIter.next(); |
1010 GlyphRect& rect = fFBoundingBoxes[boundingBoxesIndex]; | 922 GlyphRect& rect = fFBoundingBoxes[boundingBoxesIndex]; |
1011 rect.fMinX = SkEndian_SwapBE16(glyphData->xMin); | 923 rect.fMinX = SkEndian_SwapBE16(glyphData->xMin); |
1012 rect.fMinY = SkEndian_SwapBE16(glyphData->yMin); | 924 rect.fMinY = SkEndian_SwapBE16(glyphData->yMin); |
1013 rect.fMaxX = SkEndian_SwapBE16(glyphData->xMax); | 925 rect.fMaxX = SkEndian_SwapBE16(glyphData->xMax); |
1014 rect.fMaxY = SkEndian_SwapBE16(glyphData->yMax); | 926 rect.fMaxY = SkEndian_SwapBE16(glyphData->yMax); |
1015 } | 927 } |
1016 #if defined(SK_IGNORE_MAC_TEXT_BOUNDS_FIX) | 928 |
1017 fFBoundingBoxesMatrix = fMatrix; | |
1018 flip(&fFBoundingBoxesMatrix); | |
1019 SkScalar fontScale = getFontScale(fCGFont); | |
1020 fFBoundingBoxesMatrix.preScale(fontScale, fontScale); | |
1021 #endif | |
1022 return true; | 929 return true; |
1023 } | 930 } |
1024 | 931 |
1025 unsigned SkScalerContext_Mac::generateGlyphCount(void) { | 932 unsigned SkScalerContext_Mac::generateGlyphCount(void) { |
1026 return fGlyphCount; | 933 return fGlyphCount; |
1027 } | 934 } |
1028 | 935 |
1029 uint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni) { | 936 uint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni) { |
1030 CGGlyph cgGlyph; | 937 CGGlyph cgGlyph; |
1031 UniChar theChar; | 938 UniChar theChar; |
1032 | 939 |
1033 // Validate our parameters and state | 940 // Validate our parameters and state |
1034 SkASSERT(uni <= 0x0000FFFF); | 941 SkASSERT(uni <= 0x0000FFFF); |
1035 SkASSERT(sizeof(CGGlyph) <= sizeof(uint16_t)); | 942 SkASSERT(sizeof(CGGlyph) <= sizeof(uint16_t)); |
1036 | 943 |
1037 // Get the glyph | 944 // Get the glyph |
1038 theChar = (UniChar) uni; | 945 theChar = (UniChar) uni; |
1039 | 946 |
1040 if (!CTFontGetGlyphsForCharacters(fCTFont, &theChar, &cgGlyph, 1)) { | 947 if (!CTFontGetGlyphsForCharacters(fCTFont, &theChar, &cgGlyph, 1)) { |
1041 cgGlyph = 0; | 948 cgGlyph = 0; |
1042 } | 949 } |
1043 | 950 |
1044 return cgGlyph; | 951 return cgGlyph; |
1045 } | 952 } |
1046 | 953 |
1047 void SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) { | 954 void SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) { |
1048 this->generateMetrics(glyph); | 955 this->generateMetrics(glyph); |
1049 } | 956 } |
1050 | 957 |
1051 #if defined(SK_IGNORE_MAC_TEXT_BOUNDS_FIX) | |
1052 void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) { | |
1053 CGSize advance; | |
1054 CGRect bounds; | |
1055 CGGlyph cgGlyph; | |
1056 | |
1057 // Get the state we need | |
1058 cgGlyph = (CGGlyph) glyph->getGlyphID(fBaseGlyphCount); | |
1059 | |
1060 if (fVertical) { | |
1061 if (!isSnowLeopard()) { | |
1062 // Lion and Leopard respect the vertical font metrics. | |
1063 CTFontGetBoundingRectsForGlyphs(fCTVerticalFont, kCTFontVerticalOrie
ntation, | |
1064 &cgGlyph, &bounds, 1); | |
1065 } else { | |
1066 // Snow Leopard and earlier respect the vertical font metrics for | |
1067 // advances, but not bounds, so use the default box and adjust it be
low. | |
1068 CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontDefaultOrientation, | |
1069 &cgGlyph, &bounds, 1); | |
1070 } | |
1071 CTFontGetAdvancesForGlyphs(fCTVerticalFont, kCTFontVerticalOrientation, | |
1072 &cgGlyph, &advance, 1); | |
1073 } else { | |
1074 CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontDefaultOrientation, | |
1075 &cgGlyph, &bounds, 1); | |
1076 CTFontGetAdvancesForGlyphs(fCTFont, kCTFontDefaultOrientation, | |
1077 &cgGlyph, &advance, 1); | |
1078 } | |
1079 | |
1080 // BUG? | |
1081 // 0x200B (zero-advance space) seems to return a huge (garbage) bounds, when | |
1082 // it should be empty. So, if we see a zero-advance, we check if it has an | |
1083 // empty path or not, and if so, we jam the bounds to 0. Hopefully a zero-ad
vance | |
1084 // is rare, so we won't incur a big performance cost for this extra check. | |
1085 if (0 == advance.width && 0 == advance.height) { | |
1086 AutoCFRelease<CGPathRef> path(CTFontCreatePathForGlyph(fCTFont, cgGlyph,
NULL)); | |
1087 if (NULL == path || CGPathIsEmpty(path)) { | |
1088 bounds = CGRectMake(0, 0, 0, 0); | |
1089 } | |
1090 } | |
1091 | |
1092 glyph->zeroMetrics(); | |
1093 glyph->fAdvanceX = SkFloatToFixed_Check(advance.width); | |
1094 glyph->fAdvanceY = -SkFloatToFixed_Check(advance.height); | |
1095 | |
1096 if (CGRectIsEmpty_inline(bounds)) { | |
1097 return; | |
1098 } | |
1099 | |
1100 // Adjust the bounds | |
1101 // | |
1102 // CTFontGetBoundingRectsForGlyphs ignores the font transform, so we need | |
1103 // to transform the bounding box ourselves. | |
1104 // | |
1105 // The bounds are also expanded by 1 pixel, to give CG room for anti-aliasin
g. | |
1106 CGRectInset_inline(&bounds, -1, -1); | |
1107 | |
1108 // Get the metrics | |
1109 bool lionAdjustedMetrics = false; | |
1110 if (isLion() || isMountainLion()) { | |
1111 if (cgGlyph < fGlyphCount && cgGlyph >= getFBoundingBoxesGlyphOffset() &
& generateBBoxes()){ | |
1112 lionAdjustedMetrics = true; | |
1113 SkRect adjust; | |
1114 const GlyphRect& gRect = fFBoundingBoxes[cgGlyph - fFBoundingBoxesGl
yphOffset]; | |
1115 adjust.set(gRect.fMinX, gRect.fMinY, gRect.fMaxX, gRect.fMaxY); | |
1116 fFBoundingBoxesMatrix.mapRect(&adjust); | |
1117 bounds.origin.x = SkScalarToFloat(adjust.fLeft) - 1; | |
1118 bounds.origin.y = SkScalarToFloat(adjust.fTop) - 1; | |
1119 } | |
1120 // Lion returns fractions in the bounds | |
1121 glyph->fWidth = SkToU16(sk_float_ceil2int(bounds.size.width)); | |
1122 glyph->fHeight = SkToU16(sk_float_ceil2int(bounds.size.height)); | |
1123 } else { | |
1124 glyph->fWidth = SkToU16(sk_float_round2int(bounds.size.width)); | |
1125 glyph->fHeight = SkToU16(sk_float_round2int(bounds.size.height)); | |
1126 } | |
1127 glyph->fTop = SkToS16(-sk_float_round2int(CGRectGetMaxY_inline(bounds))); | |
1128 glyph->fLeft = SkToS16(sk_float_round2int(CGRectGetMinX_inline(bounds))); | |
1129 SkIPoint offset; | |
1130 if (fVertical && (isSnowLeopard() || lionAdjustedMetrics)) { | |
1131 // SnowLeopard doesn't respect vertical metrics, so compute them manuall
y. | |
1132 // Also compute them for Lion when the metrics were computed by hand. | |
1133 getVerticalOffset(cgGlyph, &offset); | |
1134 glyph->fLeft += offset.fX; | |
1135 glyph->fTop += offset.fY; | |
1136 } | |
1137 #ifdef HACK_COLORGLYPHS | |
1138 glyph->fMaskFormat = SkMask::kARGB32_Format; | |
1139 #endif | |
1140 } | |
1141 #else | |
1142 void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) { | 958 void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) { |
1143 const CGGlyph cgGlyph = (CGGlyph) glyph->getGlyphID(fBaseGlyphCount); | 959 const CGGlyph cgGlyph = (CGGlyph) glyph->getGlyphID(fBaseGlyphCount); |
1144 glyph->zeroMetrics(); | 960 glyph->zeroMetrics(); |
1145 | 961 |
1146 // The following block produces cgAdvance in CG units (pixels, y up). | 962 // The following block produces cgAdvance in CG units (pixels, y up). |
1147 CGSize cgAdvance; | 963 CGSize cgAdvance; |
1148 if (fVertical) { | 964 if (fVertical) { |
1149 CTFontGetAdvancesForGlyphs(fCTVerticalFont, kCTFontVerticalOrientation, | 965 CTFontGetAdvancesForGlyphs(fCTVerticalFont, kCTFontVerticalOrientation, |
1150 &cgGlyph, &cgAdvance, 1); | 966 &cgGlyph, &cgAdvance, 1); |
1151 } else { | 967 } else { |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1243 glyph->fLeft = SkToS16(skIBounds.fLeft); | 1059 glyph->fLeft = SkToS16(skIBounds.fLeft); |
1244 glyph->fTop = SkToS16(skIBounds.fTop); | 1060 glyph->fTop = SkToS16(skIBounds.fTop); |
1245 glyph->fWidth = SkToU16(skIBounds.width()); | 1061 glyph->fWidth = SkToU16(skIBounds.width()); |
1246 glyph->fHeight = SkToU16(skIBounds.height()); | 1062 glyph->fHeight = SkToU16(skIBounds.height()); |
1247 | 1063 |
1248 #ifdef HACK_COLORGLYPHS | 1064 #ifdef HACK_COLORGLYPHS |
1249 glyph->fMaskFormat = SkMask::kARGB32_Format; | 1065 glyph->fMaskFormat = SkMask::kARGB32_Format; |
1250 #endif | 1066 #endif |
1251 } | 1067 } |
1252 | 1068 |
1253 #endif | |
1254 #include "SkColorPriv.h" | 1069 #include "SkColorPriv.h" |
1255 | 1070 |
1256 static void build_power_table(uint8_t table[], float ee) { | 1071 static void build_power_table(uint8_t table[], float ee) { |
1257 for (int i = 0; i < 256; i++) { | 1072 for (int i = 0; i < 256; i++) { |
1258 float x = i / 255.f; | 1073 float x = i / 255.f; |
1259 x = sk_float_pow(x, ee); | 1074 x = sk_float_pow(x, ee); |
1260 int xx = SkScalarRoundToInt(SkFloatToScalar(x * 255)); | 1075 int xx = SkScalarRoundToInt(SkFloatToScalar(x * 255)); |
1261 table[i] = SkToU8(xx); | 1076 table[i] = SkToU8(xx); |
1262 } | 1077 } |
1263 } | 1078 } |
(...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1534 } | 1349 } |
1535 | 1350 |
1536 if (fDoSubPosition) { | 1351 if (fDoSubPosition) { |
1537 SkMatrix m; | 1352 SkMatrix m; |
1538 m.setScale(SkScalarInvert(scaleX), SkScalarInvert(scaleY)); | 1353 m.setScale(SkScalarInvert(scaleX), SkScalarInvert(scaleY)); |
1539 path->transform(m); | 1354 path->transform(m); |
1540 // balance the call to CTFontCreateCopyWithAttributes | 1355 // balance the call to CTFontCreateCopyWithAttributes |
1541 CFSafeRelease(font); | 1356 CFSafeRelease(font); |
1542 } | 1357 } |
1543 if (fVertical) { | 1358 if (fVertical) { |
1544 #if defined(SK_IGNORE_MAC_TEXT_BOUNDS_FIX) | |
1545 SkIPoint offset; | |
1546 getVerticalOffset(cgGlyph, &offset); | |
1547 path->offset(SkIntToScalar(offset.fX), SkIntToScalar(offset.fY)); | |
1548 #else | |
1549 SkPoint offset; | 1359 SkPoint offset; |
1550 getVerticalOffset(cgGlyph, &offset); | 1360 getVerticalOffset(cgGlyph, &offset); |
1551 path->offset(offset.fX, offset.fY); | 1361 path->offset(offset.fX, offset.fY); |
1552 #endif | |
1553 } | 1362 } |
1554 } | 1363 } |
1555 | 1364 |
1556 void SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* mx, | 1365 void SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* mx, |
1557 SkPaint::FontMetrics* my) { | 1366 SkPaint::FontMetrics* my) { |
1558 CGRect theBounds = CTFontGetBoundingBox(fCTFont); | 1367 CGRect theBounds = CTFontGetBoundingBox(fCTFont); |
1559 | 1368 |
1560 SkPaint::FontMetrics theMetrics; | 1369 SkPaint::FontMetrics theMetrics; |
1561 theMetrics.fTop = CGToScalar(-CGRectGetMaxY_inline(theBounds)); | 1370 theMetrics.fTop = CGToScalar(-CGRectGetMaxY_inline(theBounds)); |
1562 theMetrics.fAscent = CGToScalar(-CTFontGetAscent(fCTFont)); | 1371 theMetrics.fAscent = CGToScalar(-CTFontGetAscent(fCTFont)); |
(...skipping 826 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2389 return NULL; | 2198 return NULL; |
2390 } | 2199 } |
2391 return create_from_dataProvider(pr); | 2200 return create_from_dataProvider(pr); |
2392 } | 2201 } |
2393 }; | 2202 }; |
2394 | 2203 |
2395 SkFontMgr* SkFontMgr::Factory() { | 2204 SkFontMgr* SkFontMgr::Factory() { |
2396 return SkNEW(SkFontMgr_Mac); | 2205 return SkNEW(SkFontMgr_Mac); |
2397 } | 2206 } |
2398 #endif | 2207 #endif |
OLD | NEW |