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 #include <vector> | 9 #include <vector> |
| 10 #ifdef SK_BUILD_FOR_MAC | 10 #ifdef SK_BUILD_FOR_MAC |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 117 public: | 117 public: |
| 118 const T* fData; | 118 const T* fData; |
| 119 }; | 119 }; |
| 120 | 120 |
| 121 // inline versions of these rect helpers | 121 // inline versions of these rect helpers |
| 122 | 122 |
| 123 static bool CGRectIsEmpty_inline(const CGRect& rect) { | 123 static bool CGRectIsEmpty_inline(const CGRect& rect) { |
| 124 return rect.size.width <= 0 || rect.size.height <= 0; | 124 return rect.size.width <= 0 || rect.size.height <= 0; |
| 125 } | 125 } |
| 126 | 126 |
| 127 static void CGRectInset_inline(CGRect* rect, CGFloat dx, CGFloat dy) { | |
| 128 rect->origin.x += dx; | |
| 129 rect->origin.y += dy; | |
| 130 rect->size.width -= dx * 2; | |
| 131 rect->size.height -= dy * 2; | |
| 132 } | |
| 133 | |
| 134 static CGFloat CGRectGetMinX_inline(const CGRect& rect) { | 127 static CGFloat CGRectGetMinX_inline(const CGRect& rect) { |
| 135 return rect.origin.x; | 128 return rect.origin.x; |
| 136 } | 129 } |
| 137 | 130 |
| 138 static CGFloat CGRectGetMaxX_inline(const CGRect& rect) { | 131 static CGFloat CGRectGetMaxX_inline(const CGRect& rect) { |
| 139 return rect.origin.x + rect.size.width; | 132 return rect.origin.x + rect.size.width; |
| 140 } | 133 } |
| 141 | 134 |
| 142 static CGFloat CGRectGetMinY_inline(const CGRect& rect) { | 135 static CGFloat CGRectGetMinY_inline(const CGRect& rect) { |
| 143 return rect.origin.y; | 136 return rect.origin.y; |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 244 SkDebugf("could not parse uname release %s\n", info.release); | 237 SkDebugf("could not parse uname release %s\n", info.release); |
| 245 } | 238 } |
| 246 return version; | 239 return version; |
| 247 } | 240 } |
| 248 | 241 |
| 249 static int darwinVersion() { | 242 static int darwinVersion() { |
| 250 static int darwin_version = readVersion(); | 243 static int darwin_version = readVersion(); |
| 251 return darwin_version; | 244 return darwin_version; |
| 252 } | 245 } |
| 253 | 246 |
| 254 static bool isLeopard() { | |
| 255 return darwinVersion() == 9; | |
| 256 } | |
| 257 | |
| 258 static bool isSnowLeopard() { | 247 static bool isSnowLeopard() { |
| 259 return darwinVersion() == 10; | 248 return darwinVersion() == 10; |
| 260 } | 249 } |
| 261 | 250 |
| 262 static bool isLion() { | 251 static bool isLion() { |
| 263 return darwinVersion() == 11; | 252 return darwinVersion() == 11; |
| 264 } | 253 } |
| 265 | 254 |
| 266 static bool isMountainLion() { | 255 static bool isMountainLion() { |
| 267 return darwinVersion() == 12; | 256 return darwinVersion() == 12; |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 293 SkScalar sx = SK_Scalar1, | 282 SkScalar sx = SK_Scalar1, |
| 294 SkScalar sy = SK_Scalar1) { | 283 SkScalar sy = SK_Scalar1) { |
| 295 return CGAffineTransformMake( ScalarToCG(matrix[SkMatrix::kMScaleX] * sx), | 284 return CGAffineTransformMake( ScalarToCG(matrix[SkMatrix::kMScaleX] * sx), |
| 296 -ScalarToCG(matrix[SkMatrix::kMSkewY] * sy), | 285 -ScalarToCG(matrix[SkMatrix::kMSkewY] * sy), |
| 297 -ScalarToCG(matrix[SkMatrix::kMSkewX] * sx), | 286 -ScalarToCG(matrix[SkMatrix::kMSkewX] * sx), |
| 298 ScalarToCG(matrix[SkMatrix::kMScaleY] * sy), | 287 ScalarToCG(matrix[SkMatrix::kMScaleY] * sy), |
| 299 ScalarToCG(matrix[SkMatrix::kMTransX] * sx), | 288 ScalarToCG(matrix[SkMatrix::kMTransX] * sx), |
| 300 ScalarToCG(matrix[SkMatrix::kMTransY] * sy)); | 289 ScalarToCG(matrix[SkMatrix::kMTransY] * sy)); |
| 301 } | 290 } |
| 302 | 291 |
| 303 static SkScalar getFontScale(CGFontRef cgFont) { | |
| 304 int unitsPerEm = CGFontGetUnitsPerEm(cgFont); | |
| 305 return SkScalarInvert(SkIntToScalar(unitsPerEm)); | |
| 306 } | |
| 307 | |
| 308 /////////////////////////////////////////////////////////////////////////////// | 292 /////////////////////////////////////////////////////////////////////////////// |
| 309 | 293 |
| 310 #define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host) | 294 #define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host) |
| 311 #define BITMAP_INFO_GRAY (kCGImageAlphaNone) | 295 #define BITMAP_INFO_GRAY (kCGImageAlphaNone) |
| 312 | 296 |
| 313 /** | 297 /** |
| 314 * 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 |
| 315 * 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 |
| 316 * 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. |
| 317 */ | 301 */ |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 523 if (cfFontName != NULL && cfFontTraits != NULL && cfAttributes != NULL && cf Traits != NULL) { | 507 if (cfFontName != NULL && cfFontTraits != NULL && cfAttributes != NULL && cf Traits != NULL) { |
| 524 CFDictionaryAddValue(cfTraits, kCTFontSymbolicTrait, cfFontTraits); | 508 CFDictionaryAddValue(cfTraits, kCTFontSymbolicTrait, cfFontTraits); |
| 525 | 509 |
| 526 CFDictionaryAddValue(cfAttributes, kCTFontFamilyNameAttribute, cfFontNam e); | 510 CFDictionaryAddValue(cfAttributes, kCTFontFamilyNameAttribute, cfFontNam e); |
| 527 CFDictionaryAddValue(cfAttributes, kCTFontTraitsAttribute, cfTraits); | 511 CFDictionaryAddValue(cfAttributes, kCTFontTraitsAttribute, cfTraits); |
| 528 | 512 |
| 529 AutoCFRelease<CTFontDescriptorRef> ctFontDesc( | 513 AutoCFRelease<CTFontDescriptorRef> ctFontDesc( |
| 530 CTFontDescriptorCreateWithAttributes(cfAttributes)); | 514 CTFontDescriptorCreateWithAttributes(cfAttributes)); |
| 531 | 515 |
| 532 if (ctFontDesc != NULL) { | 516 if (ctFontDesc != NULL) { |
| 533 if (isLeopard()) { | 517 ctFont = CTFontCreateWithFontDescriptor(ctFontDesc, 0, NULL); |
| 534 // CTFontCreateWithFontDescriptor on Leopard ignores the name | |
| 535 AutoCFRelease<CTFontRef> ctNamed(CTFontCreateWithName(cfFontName , 1, NULL)); | |
| 536 ctFont = CTFontCreateCopyWithAttributes(ctNamed, 1, NULL, ctFont Desc); | |
| 537 } else { | |
| 538 ctFont = CTFontCreateWithFontDescriptor(ctFontDesc, 0, NULL); | |
| 539 } | |
| 540 } | 518 } |
| 541 } | 519 } |
| 542 | 520 |
| 543 return ctFont ? NewFromFontRef(ctFont, familyName) : NULL; | 521 return ctFont ? NewFromFontRef(ctFont, familyName) : NULL; |
| 544 } | 522 } |
| 545 | 523 |
| 546 static SkTypeface* GetDefaultFace() { | 524 static SkTypeface* GetDefaultFace() { |
| 547 SK_DECLARE_STATIC_MUTEX(gMutex); | 525 SK_DECLARE_STATIC_MUTEX(gMutex); |
| 548 SkAutoMutexAcquire ma(gMutex); | 526 SkAutoMutexAcquire ma(gMutex); |
| 549 | 527 |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 641 if (face) { | 619 if (face) { |
| 642 SkTypefaceCache::Add(face, style); | 620 SkTypefaceCache::Add(face, style); |
| 643 } else { | 621 } else { |
| 644 face = GetDefaultFace(); | 622 face = GetDefaultFace(); |
| 645 face->ref(); | 623 face->ref(); |
| 646 } | 624 } |
| 647 } | 625 } |
| 648 return face; | 626 return face; |
| 649 } | 627 } |
| 650 | 628 |
| 651 static void flip(SkMatrix* matrix) { | |
| 652 matrix->setSkewX(-matrix->getSkewX()); | |
| 653 matrix->setSkewY(-matrix->getSkewY()); | |
| 654 } | |
| 655 | |
| 656 /////////////////////////////////////////////////////////////////////////////// | 629 /////////////////////////////////////////////////////////////////////////////// |
| 657 | 630 |
| 631 /** GlyphRect is in FUnits (em space, y up). */ | |
| 658 struct GlyphRect { | 632 struct GlyphRect { |
| 659 int16_t fMinX; | 633 int16_t fMinX; |
| 660 int16_t fMinY; | 634 int16_t fMinY; |
| 661 int16_t fMaxX; | 635 int16_t fMaxX; |
| 662 int16_t fMaxY; | 636 int16_t fMaxY; |
| 663 }; | 637 }; |
| 664 | 638 |
| 665 class SkScalerContext_Mac : public SkScalerContext { | 639 class SkScalerContext_Mac : public SkScalerContext { |
| 666 public: | 640 public: |
| 667 SkScalerContext_Mac(SkTypeface_Mac*, const SkDescriptor*); | 641 SkScalerContext_Mac(SkTypeface_Mac*, const SkDescriptor*); |
| 668 virtual ~SkScalerContext_Mac(); | 642 virtual ~SkScalerContext_Mac() { }; |
|
caryclark
2013/05/14 20:08:09
can we remove the destructor altogether at this po
bungeman-skia
2013/05/14 22:30:21
Done.
| |
| 669 | |
| 670 | 643 |
| 671 protected: | 644 protected: |
| 672 unsigned generateGlyphCount(void) SK_OVERRIDE; | 645 unsigned generateGlyphCount(void) SK_OVERRIDE; |
| 673 uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE; | 646 uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE; |
| 674 void generateAdvance(SkGlyph* glyph) SK_OVERRIDE; | 647 void generateAdvance(SkGlyph* glyph) SK_OVERRIDE; |
| 675 void generateMetrics(SkGlyph* glyph) SK_OVERRIDE; | 648 void generateMetrics(SkGlyph* glyph) SK_OVERRIDE; |
| 676 void generateImage(const SkGlyph& glyph) SK_OVERRIDE; | 649 void generateImage(const SkGlyph& glyph) SK_OVERRIDE; |
| 677 void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE; | 650 void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE; |
| 678 void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY) SK_OVERRIDE; | 651 void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY) SK_OVERRIDE; |
| 679 | 652 |
| 680 private: | 653 private: |
| 681 static void CTPathElement(void *info, const CGPathElement *element); | 654 static void CTPathElement(void *info, const CGPathElement *element); |
| 655 | |
| 656 /** Returns the offset from the horizontal origin to the vertical origin in SkGlyph units. */ | |
| 657 void getVerticalOffset(CGGlyph glyphID, SkPoint* offset) const; | |
| 658 | |
| 659 /** Initializes and returns the value of fFBoundingBoxesGlyphOffset. | |
| 660 * | |
| 661 * For use with (and must be called before) generateBBoxes. | |
| 662 */ | |
| 682 uint16_t getFBoundingBoxesGlyphOffset(); | 663 uint16_t getFBoundingBoxesGlyphOffset(); |
| 683 void getVerticalOffset(CGGlyph glyphID, SkIPoint* offset) const; | 664 |
| 665 /** Initializes fFBoundingBoxes and returns true on success. | |
| 666 * | |
| 667 * On Lion and Mountain Lion, CTFontGetBoundingRectsForGlyphs has a bug whi ch causes it to | |
| 668 * return a bad value in bounds.origin.x for SFNT fonts whose hhea::numberO fHMetrics is | |
| 669 * less than its maxp::numGlyphs. When this is the case we try to read the bounds from the | |
| 670 * font directly. | |
| 671 * | |
| 672 * This routine initializes fFBoundingBoxes to an array of | |
| 673 * fGlyphCount - fFBoundingBoxesGlyphOffset GlyphRects which contain the bo unds in FUnits | |
| 674 * (em space, y up) of glyphs with ids in the range [fFBoundingBoxesGlyphOf fset, fGlyphCount). | |
| 675 * | |
| 676 * Returns true if fFBoundingBoxes is properly initialized. The table can o nly be properly | |
| 677 * initialized for a TrueType font with 'head', 'loca', and 'glyf' tables. | |
| 678 * | |
| 679 * TODO: A future optimization will compute fFBoundingBoxes once per fCTFon t. | |
| 680 */ | |
| 684 bool generateBBoxes(); | 681 bool generateBBoxes(); |
| 685 | 682 |
| 686 CGAffineTransform fTransform; | 683 /** Converts from FUnits (em space, y up) to SkGlyph units (pixels, y down). |
| 687 SkMatrix fUnitMatrix; // without font size | 684 * |
| 688 SkMatrix fVerticalMatrix; // unit rotated | 685 * Used on Snow Leopard to correct CTFontGetVerticalTranslationsForGlyphs. |
| 689 SkMatrix fMatrix; // with font size | 686 * Used on Lion to correct CTFontGetBoundingRectsForGlyphs. |
| 690 SkMatrix fFBoundingBoxesMatrix; // lion-specific fix | 687 */ |
| 688 SkMatrix fFUnitMatrix; | |
| 689 | |
| 691 Offscreen fOffscreen; | 690 Offscreen fOffscreen; |
| 692 AutoCFRelease<CTFontRef> fCTFont; | 691 AutoCFRelease<CTFontRef> fCTFont; |
| 693 AutoCFRelease<CTFontRef> fCTVerticalFont; // for vertical advance | 692 |
| 693 /** Vertical variant of fCTFont. | |
| 694 * | |
| 695 * CT vertical metrics are pre-rotated (in em space, before transform) 90de g clock-wise. | |
| 696 * This makes kCTFontDefaultOrientation dangerous, because the metrics from | |
| 697 * kCTFontHorizontalOrientation are in a different space from kCTFontVertic alOrientation. | |
| 698 * Use fCTVerticalFont with kCTFontVerticalOrientation to get metrics in th e same space. | |
| 699 */ | |
| 700 AutoCFRelease<CTFontRef> fCTVerticalFont; | |
| 701 | |
| 694 AutoCFRelease<CGFontRef> fCGFont; | 702 AutoCFRelease<CGFontRef> fCGFont; |
| 695 GlyphRect* fFBoundingBoxes; | 703 SkAutoTMalloc<GlyphRect> fFBoundingBoxes; |
| 696 uint16_t fFBoundingBoxesGlyphOffset; | 704 uint16_t fFBoundingBoxesGlyphOffset; |
| 697 uint16_t fGlyphCount; | 705 uint16_t fGlyphCount; |
| 698 bool fGeneratedFBoundingBoxes; | 706 bool fGeneratedFBoundingBoxes; |
| 699 bool fDoSubPosition; | 707 const bool fDoSubPosition; |
| 700 bool fVertical; | 708 const bool fVertical; |
| 701 | 709 |
| 702 friend class Offscreen; | 710 friend class Offscreen; |
| 703 | 711 |
| 704 typedef SkScalerContext INHERITED; | 712 typedef SkScalerContext INHERITED; |
| 705 }; | 713 }; |
| 706 | 714 |
| 707 SkScalerContext_Mac::SkScalerContext_Mac(SkTypeface_Mac* typeface, | 715 SkScalerContext_Mac::SkScalerContext_Mac(SkTypeface_Mac* typeface, |
| 708 const SkDescriptor* desc) | 716 const SkDescriptor* desc) |
| 709 : INHERITED(typeface, desc) | 717 : INHERITED(typeface, desc) |
| 710 , fFBoundingBoxes(NULL) | 718 , fFBoundingBoxes() |
| 711 , fFBoundingBoxesGlyphOffset(0) | 719 , fFBoundingBoxesGlyphOffset(0) |
| 712 , fGeneratedFBoundingBoxes(false) | 720 , fGeneratedFBoundingBoxes(false) |
| 721 , fDoSubPosition(SkToBool(fRec.fFlags & kSubpixelPositioning_Flag)) | |
| 722 , fVertical(SkToBool(fRec.fFlags & kVertical_Flag)) | |
| 723 | |
| 713 { | 724 { |
| 714 CTFontRef ctFont = typeface->fFontRef.get(); | 725 CTFontRef ctFont = typeface->fFontRef.get(); |
| 715 CFIndex numGlyphs = CTFontGetGlyphCount(ctFont); | 726 CFIndex numGlyphs = CTFontGetGlyphCount(ctFont); |
| 716 | |
| 717 // Get the state we need | |
| 718 fRec.getSingleMatrix(&fMatrix); | |
| 719 fUnitMatrix = fMatrix; | |
| 720 | |
| 721 // extract the font size out of the matrix, but leave the skewing for italic | |
| 722 SkScalar reciprocal = SkScalarInvert(fRec.fTextSize); | |
| 723 fUnitMatrix.preScale(reciprocal, reciprocal); | |
| 724 | |
| 725 SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF); | 727 SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF); |
| 726 | 728 fGlyphCount = SkToU16(numGlyphs); |
| 727 fTransform = MatrixToCGAffineTransform(fMatrix); | 729 |
| 728 | 730 fRec.getSingleMatrix(&fFUnitMatrix); |
| 729 CGAffineTransform transform; | 731 CGAffineTransform transform = MatrixToCGAffineTransform(fFUnitMatrix); |
| 730 CGFloat unitFontSize; | 732 |
| 731 if (isLeopard()) { | |
| 732 // passing 1 for pointSize to Leopard sets the font size to 1 pt. | |
| 733 // pass the CoreText size explicitly | |
| 734 transform = MatrixToCGAffineTransform(fUnitMatrix); | |
| 735 unitFontSize = SkScalarToFloat(fRec.fTextSize); | |
| 736 } else { | |
| 737 // since our matrix includes everything, we pass 1 for pointSize | |
| 738 transform = fTransform; | |
| 739 unitFontSize = 1; | |
| 740 } | |
| 741 flip(&fUnitMatrix); // flip to fix up bounds later | |
| 742 fVertical = SkToBool(fRec.fFlags & kVertical_Flag); | |
| 743 AutoCFRelease<CTFontDescriptorRef> ctFontDesc; | 733 AutoCFRelease<CTFontDescriptorRef> ctFontDesc; |
| 744 if (fVertical) { | 734 if (fVertical) { |
| 745 AutoCFRelease<CFMutableDictionaryRef> cfAttributes(CFDictionaryCreateMut able( | 735 AutoCFRelease<CFMutableDictionaryRef> cfAttributes(CFDictionaryCreateMut able( |
| 746 kCFAllocatorDefault, 0, | 736 kCFAllocatorDefault, 0, |
| 747 &kCFTypeDictionaryKeyCallBacks, | 737 &kCFTypeDictionaryKeyCallBacks, |
| 748 &kCFTypeDictionaryValueCallBacks)); | 738 &kCFTypeDictionaryValueCallBacks)); |
| 749 if (cfAttributes) { | 739 if (cfAttributes) { |
| 750 CTFontOrientation ctOrientation = kCTFontVerticalOrientation; | 740 CTFontOrientation ctOrientation = kCTFontVerticalOrientation; |
| 751 AutoCFRelease<CFNumberRef> cfVertical(CFNumberCreate( | 741 AutoCFRelease<CFNumberRef> cfVertical(CFNumberCreate( |
| 752 kCFAllocatorDefault, kCFNumberSInt32Type, &ctOrientation)); | 742 kCFAllocatorDefault, kCFNumberSInt32Type, &ctOrientation)); |
| 753 CFDictionaryAddValue(cfAttributes, kCTFontOrientationAttribute, cfVe rtical); | 743 CFDictionaryAddValue(cfAttributes, kCTFontOrientationAttribute, cfVe rtical); |
| 754 ctFontDesc = CTFontDescriptorCreateWithAttributes(cfAttributes); | 744 ctFontDesc = CTFontDescriptorCreateWithAttributes(cfAttributes); |
| 755 } | 745 } |
| 756 } | 746 } |
| 757 fCTFont = CTFontCreateCopyWithAttributes(ctFont, unitFontSize, &transform, c tFontDesc); | 747 // Since our matrix includes everything, we pass 1 for size. |
| 748 fCTFont = CTFontCreateCopyWithAttributes(ctFont, 1.f, &transform, ctFontDesc ); | |
|
caryclark
2013/05/14 20:08:09
It looks like the rest of Skia mostly uses 1.f ins
bungeman-skia
2013/05/14 22:30:21
Done.
| |
| 758 fCGFont = CTFontCopyGraphicsFont(fCTFont, NULL); | 749 fCGFont = CTFontCopyGraphicsFont(fCTFont, NULL); |
| 759 if (fVertical) { | 750 if (fVertical) { |
| 760 CGAffineTransform rotateLeft = CGAffineTransformMake(0, -1, 1, 0, 0, 0); | 751 CGAffineTransform rotateLeft = CGAffineTransformMake(0, -1, 1, 0, 0, 0); |
| 761 transform = CGAffineTransformConcat(rotateLeft, transform); | 752 transform = CGAffineTransformConcat(rotateLeft, transform); |
| 762 fCTVerticalFont = CTFontCreateCopyWithAttributes(ctFont, unitFontSize, & transform, NULL); | 753 fCTVerticalFont = CTFontCreateCopyWithAttributes(ctFont, 1.f, &transform , NULL); |
|
caryclark
2013/05/14 20:08:09
and here
bungeman-skia
2013/05/14 22:30:21
Done.
| |
| 763 fVerticalMatrix = fUnitMatrix; | |
| 764 if (isSnowLeopard()) { | |
| 765 SkScalar scale = SkScalarMul(fRec.fTextSize, getFontScale(fCGFont)); | |
| 766 fVerticalMatrix.preScale(scale, scale); | |
| 767 } else { | |
| 768 fVerticalMatrix.preRotate(SkIntToScalar(90)); | |
| 769 } | |
| 770 fVerticalMatrix.postScale(SK_Scalar1, -SK_Scalar1); | |
| 771 } | 754 } |
| 772 fGlyphCount = SkToU16(numGlyphs); | 755 SkScalar emPerFUnit = SkScalarInvert(SkIntToScalar(CGFontGetUnitsPerEm(fCGFo nt))); |
| 773 fDoSubPosition = SkToBool(fRec.fFlags & kSubpixelPositioning_Flag); | 756 fFUnitMatrix.preScale(emPerFUnit, -emPerFUnit); |
| 774 } | |
| 775 | |
| 776 SkScalerContext_Mac::~SkScalerContext_Mac() { | |
| 777 delete[] fFBoundingBoxes; | |
| 778 } | 757 } |
| 779 | 758 |
| 780 CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph, | 759 CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph, |
| 781 CGGlyph glyphID, size_t* rowBytesPtr, | 760 CGGlyph glyphID, size_t* rowBytesPtr, |
| 782 bool generateA8FromLCD) { | 761 bool generateA8FromLCD) { |
| 783 if (!fRGBSpace) { | 762 if (!fRGBSpace) { |
| 784 //It doesn't appear to matter what color space is specified. | 763 //It doesn't appear to matter what color space is specified. |
| 785 //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)) |
| 786 //and smoothed text is always g=2.0. | 765 //and smoothed text is always g=2.0. |
| 787 fRGBSpace = CGColorSpaceCreateDeviceRGB(); | 766 fRGBSpace = CGColorSpaceCreateDeviceRGB(); |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 816 fCG = CGBitmapContextCreate(image, fSize.fWidth, fSize.fHeight, 8, | 795 fCG = CGBitmapContextCreate(image, fSize.fWidth, fSize.fHeight, 8, |
| 817 rowBytes, fRGBSpace, BITMAP_INFO_RGB); | 796 rowBytes, fRGBSpace, BITMAP_INFO_RGB); |
| 818 | 797 |
| 819 // 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 |
| 820 // full fractional data from them. | 799 // full fractional data from them. |
| 821 CGContextSetAllowsFontSubpixelQuantization(fCG, false); | 800 CGContextSetAllowsFontSubpixelQuantization(fCG, false); |
| 822 CGContextSetShouldSubpixelQuantizeFonts(fCG, false); | 801 CGContextSetShouldSubpixelQuantizeFonts(fCG, false); |
| 823 | 802 |
| 824 CGContextSetTextDrawingMode(fCG, kCGTextFill); | 803 CGContextSetTextDrawingMode(fCG, kCGTextFill); |
| 825 CGContextSetFont(fCG, context.fCGFont); | 804 CGContextSetFont(fCG, context.fCGFont); |
| 826 CGContextSetFontSize(fCG, 1); | 805 CGContextSetFontSize(fCG, 1.0f /*CTFontGetSize(context.fCTFont)*/); |
| 827 CGContextSetTextMatrix(fCG, context.fTransform); | 806 CGContextSetTextMatrix(fCG, CTFontGetMatrix(context.fCTFont)); |
| 828 | 807 |
| 829 CGContextSetAllowsFontSubpixelPositioning(fCG, context.fDoSubPosition); | 808 // Because CG always draws from the horizontal baseline, |
| 830 CGContextSetShouldSubpixelPositionFonts(fCG, context.fDoSubPosition); | 809 // if there is a non-integral translation from the horizontal origin to the vertical origin, |
| 810 // then CG cannot draw the glyph in the correct location without subpixe l positioning. | |
| 811 CGContextSetAllowsFontSubpixelPositioning(fCG, context.fDoSubPosition || context.fVertical); | |
| 812 CGContextSetShouldSubpixelPositionFonts(fCG, context.fDoSubPosition || c ontext.fVertical); | |
| 831 | 813 |
| 832 // Draw white on black to create mask. | 814 // Draw white on black to create mask. |
| 833 // 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. |
| 834 CGContextSetGrayFillColor(fCG, 1.0f, 1.0f); | 816 CGContextSetGrayFillColor(fCG, 1.0f, 1.0f); |
| 835 | 817 |
| 836 // force our checks below to happen | 818 // force our checks below to happen |
| 837 fDoAA = !doAA; | 819 fDoAA = !doAA; |
| 838 fDoLCD = !doLCD; | 820 fDoLCD = !doLCD; |
| 839 } | 821 } |
| 840 | 822 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 853 | 835 |
| 854 // erase to black | 836 // erase to black |
| 855 sk_memset_rect32(image, 0, glyph.fWidth, glyph.fHeight, rowBytes); | 837 sk_memset_rect32(image, 0, glyph.fWidth, glyph.fHeight, rowBytes); |
| 856 | 838 |
| 857 float subX = 0; | 839 float subX = 0; |
| 858 float subY = 0; | 840 float subY = 0; |
| 859 if (context.fDoSubPosition) { | 841 if (context.fDoSubPosition) { |
| 860 subX = SkFixedToFloat(glyph.getSubXFixed()); | 842 subX = SkFixedToFloat(glyph.getSubXFixed()); |
| 861 subY = SkFixedToFloat(glyph.getSubYFixed()); | 843 subY = SkFixedToFloat(glyph.getSubYFixed()); |
| 862 } | 844 } |
| 845 | |
| 846 // CGContextShowGlyphsAtPoint always draws using the horizontal baseline ori gin. | |
| 863 if (context.fVertical) { | 847 if (context.fVertical) { |
| 864 SkIPoint offset; | 848 SkPoint offset; |
| 865 context.getVerticalOffset(glyphID, &offset); | 849 context.getVerticalOffset(glyphID, &offset); |
| 866 subX += offset.fX; | 850 subX += offset.fX; |
| 867 subY += offset.fY; | 851 subY += offset.fY; |
| 868 } | 852 } |
| 853 | |
| 869 CGContextShowGlyphsAtPoint(fCG, -glyph.fLeft + subX, | 854 CGContextShowGlyphsAtPoint(fCG, -glyph.fLeft + subX, |
| 870 glyph.fTop + glyph.fHeight - subY, | 855 glyph.fTop + glyph.fHeight - subY, |
| 871 &glyphID, 1); | 856 &glyphID, 1); |
| 872 | 857 |
| 873 SkASSERT(rowBytesPtr); | 858 SkASSERT(rowBytesPtr); |
| 874 *rowBytesPtr = rowBytes; | 859 *rowBytesPtr = rowBytes; |
| 875 return image; | 860 return image; |
| 876 } | 861 } |
| 877 | 862 |
| 878 void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkIPoint* offset) c onst { | 863 void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkPoint* offset) co nst { |
| 879 CGSize vertOffset; | 864 // Snow Leopard returns cgVertOffset in completely un-transformed FUnits (em space, y up). |
| 880 CTFontGetVerticalTranslationsForGlyphs(fCTVerticalFont, &glyphID, &vertOffse t, 1); | 865 // Lion and Leopard return cgVertOffset in CG units (pixels, y up). |
| 881 const SkPoint trans = {CGToScalar(vertOffset.width), | 866 CGSize cgVertOffset; |
| 882 CGToScalar(vertOffset.height)}; | 867 CTFontGetVerticalTranslationsForGlyphs(fCTFont, &glyphID, &cgVertOffset, 1); |
| 883 SkPoint floatOffset; | 868 |
| 884 fVerticalMatrix.mapPoints(&floatOffset, &trans, 1); | 869 SkPoint skVertOffset = { CGToScalar(cgVertOffset.width), CGToScalar(cgVertOf fset.height) }; |
| 885 if (!isSnowLeopard()) { | 870 if (isSnowLeopard()) { |
| 886 // SnowLeopard fails to apply the font's matrix to the vertical metrics, | 871 // From FUnits (em space, y up) to SkGlyph units (pixels, y down). |
| 887 // but Lion and Leopard do. The unit matrix describes the font's matrix at | 872 fFUnitMatrix.mapPoints(&skVertOffset, 1); |
| 888 // point size 1. There may be some way to avoid mapping here by setting up | 873 } else { |
| 889 // fVerticalMatrix differently, but this works for now. | 874 // From CG units (pixels, y up) to SkGlyph units (pixels, y down). |
| 890 fUnitMatrix.mapPoints(&floatOffset, 1); | 875 skVertOffset.fY = -skVertOffset.fY; |
| 891 } | 876 } |
| 892 offset->fX = SkScalarRound(floatOffset.fX); | 877 |
| 893 offset->fY = SkScalarRound(floatOffset.fY); | 878 *offset = skVertOffset; |
| 894 } | 879 } |
| 895 | 880 |
| 896 uint16_t SkScalerContext_Mac::getFBoundingBoxesGlyphOffset() { | 881 uint16_t SkScalerContext_Mac::getFBoundingBoxesGlyphOffset() { |
| 897 if (fFBoundingBoxesGlyphOffset) { | 882 if (fFBoundingBoxesGlyphOffset) { |
| 898 return fFBoundingBoxesGlyphOffset; | 883 return fFBoundingBoxesGlyphOffset; |
| 899 } | 884 } |
| 900 fFBoundingBoxesGlyphOffset = fGlyphCount; // fallback for all fonts | 885 fFBoundingBoxesGlyphOffset = fGlyphCount; // fallback for all fonts |
| 901 AutoCGTable<SkOTTableHorizontalHeader> hheaTable(fCGFont); | 886 AutoCGTable<SkOTTableHorizontalHeader> hheaTable(fCGFont); |
| 902 if (hheaTable.fData) { | 887 if (hheaTable.fData) { |
| 903 fFBoundingBoxesGlyphOffset = SkEndian_SwapBE16(hheaTable->numberOfHMetri cs); | 888 fFBoundingBoxesGlyphOffset = SkEndian_SwapBE16(hheaTable->numberOfHMetri cs); |
| 904 } | 889 } |
| 905 return fFBoundingBoxesGlyphOffset; | 890 return fFBoundingBoxesGlyphOffset; |
| 906 } | 891 } |
| 907 | 892 |
| 908 /* | |
| 909 * Lion has a bug in CTFontGetBoundingRectsForGlyphs which returns a bad value | |
| 910 * in theBounds.origin.x for fonts whose numOfLogHorMetrics is less than its | |
| 911 * glyph count. This workaround reads the glyph bounds from the font directly. | |
| 912 * | |
| 913 * The table is computed only if the font is a TrueType font, if the glyph | |
| 914 * value is >= fFBoundingBoxesGlyphOffset. (called only if fFBoundingBoxesGlyphO ffset < fGlyphCount). | |
| 915 * | |
| 916 * TODO: A future optimization will compute fFBoundingBoxes once per CGFont, and | |
| 917 * compute fFBoundingBoxesMatrix once per font context. | |
| 918 */ | |
| 919 bool SkScalerContext_Mac::generateBBoxes() { | 893 bool SkScalerContext_Mac::generateBBoxes() { |
| 920 if (fGeneratedFBoundingBoxes) { | 894 if (fGeneratedFBoundingBoxes) { |
| 921 return NULL != fFBoundingBoxes; | 895 return NULL != fFBoundingBoxes.get(); |
| 922 } | 896 } |
| 923 fGeneratedFBoundingBoxes = true; | 897 fGeneratedFBoundingBoxes = true; |
| 924 | 898 |
| 925 AutoCGTable<SkOTTableHead> headTable(fCGFont); | 899 AutoCGTable<SkOTTableHead> headTable(fCGFont); |
| 926 if (!headTable.fData) { | 900 if (!headTable.fData) { |
| 927 return false; | 901 return false; |
| 928 } | 902 } |
| 929 | 903 |
| 930 AutoCGTable<SkOTTableIndexToLocation> locaTable(fCGFont); | 904 AutoCGTable<SkOTTableIndexToLocation> locaTable(fCGFont); |
| 931 if (!locaTable.fData) { | 905 if (!locaTable.fData) { |
| 932 return false; | 906 return false; |
| 933 } | 907 } |
| 934 | 908 |
| 935 AutoCGTable<SkOTTableGlyph> glyfTable(fCGFont); | 909 AutoCGTable<SkOTTableGlyph> glyfTable(fCGFont); |
| 936 if (!glyfTable.fData) { | 910 if (!glyfTable.fData) { |
| 937 return false; | 911 return false; |
| 938 } | 912 } |
| 939 | 913 |
| 940 uint16_t entries = fGlyphCount - fFBoundingBoxesGlyphOffset; | 914 uint16_t entries = fGlyphCount - fFBoundingBoxesGlyphOffset; |
| 941 fFBoundingBoxes = new GlyphRect[entries]; | 915 fFBoundingBoxes.reset(entries); |
| 942 | 916 |
| 943 SkOTTableHead::IndexToLocFormat locaFormat = headTable->indexToLocFormat; | 917 SkOTTableHead::IndexToLocFormat locaFormat = headTable->indexToLocFormat; |
| 944 SkOTTableGlyph::Iterator glyphDataIter(*glyfTable.fData, *locaTable.fData, l ocaFormat); | 918 SkOTTableGlyph::Iterator glyphDataIter(*glyfTable.fData, *locaTable.fData, l ocaFormat); |
| 945 glyphDataIter.advance(fFBoundingBoxesGlyphOffset); | 919 glyphDataIter.advance(fFBoundingBoxesGlyphOffset); |
| 946 for (uint16_t boundingBoxesIndex = 0; boundingBoxesIndex < entries; ++boundi ngBoxesIndex) { | 920 for (uint16_t boundingBoxesIndex = 0; boundingBoxesIndex < entries; ++boundi ngBoxesIndex) { |
| 947 const SkOTTableGlyphData* glyphData = glyphDataIter.next(); | 921 const SkOTTableGlyphData* glyphData = glyphDataIter.next(); |
| 948 GlyphRect& rect = fFBoundingBoxes[boundingBoxesIndex]; | 922 GlyphRect& rect = fFBoundingBoxes[boundingBoxesIndex]; |
| 949 rect.fMinX = SkEndian_SwapBE16(glyphData->xMin); | 923 rect.fMinX = SkEndian_SwapBE16(glyphData->xMin); |
| 950 rect.fMinY = SkEndian_SwapBE16(glyphData->yMin); | 924 rect.fMinY = SkEndian_SwapBE16(glyphData->yMin); |
| 951 rect.fMaxX = SkEndian_SwapBE16(glyphData->xMax); | 925 rect.fMaxX = SkEndian_SwapBE16(glyphData->xMax); |
| 952 rect.fMaxY = SkEndian_SwapBE16(glyphData->yMax); | 926 rect.fMaxY = SkEndian_SwapBE16(glyphData->yMax); |
| 953 } | 927 } |
| 954 fFBoundingBoxesMatrix = fMatrix; | |
| 955 flip(&fFBoundingBoxesMatrix); | |
| 956 SkScalar fontScale = getFontScale(fCGFont); | |
| 957 fFBoundingBoxesMatrix.preScale(fontScale, fontScale); | |
| 958 return true; | 928 return true; |
| 959 } | 929 } |
| 960 | 930 |
| 961 unsigned SkScalerContext_Mac::generateGlyphCount(void) { | 931 unsigned SkScalerContext_Mac::generateGlyphCount(void) { |
| 962 return fGlyphCount; | 932 return fGlyphCount; |
| 963 } | 933 } |
| 964 | 934 |
| 965 uint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni) { | 935 uint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni) { |
| 966 CGGlyph cgGlyph; | 936 CGGlyph cgGlyph; |
| 967 UniChar theChar; | 937 UniChar theChar; |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 978 } | 948 } |
| 979 | 949 |
| 980 return cgGlyph; | 950 return cgGlyph; |
| 981 } | 951 } |
| 982 | 952 |
| 983 void SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) { | 953 void SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) { |
| 984 this->generateMetrics(glyph); | 954 this->generateMetrics(glyph); |
| 985 } | 955 } |
| 986 | 956 |
| 987 void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) { | 957 void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) { |
| 988 CGSize advance; | 958 const CGGlyph cgGlyph = (CGGlyph) glyph->getGlyphID(fBaseGlyphCount); |
| 989 CGRect bounds; | 959 glyph->zeroMetrics(); |
| 990 CGGlyph cgGlyph; | 960 |
| 961 // The following block produces cgAdvance in CG units (pixels, y up). | |
| 962 CGSize cgAdvance; | |
| 963 if (fVertical) { | |
| 964 CTFontGetAdvancesForGlyphs(fCTVerticalFont, kCTFontVerticalOrientation, | |
| 965 &cgGlyph, &cgAdvance, 1); | |
| 966 } else { | |
| 967 CTFontGetAdvancesForGlyphs(fCTFont, kCTFontHorizontalOrientation, | |
| 968 &cgGlyph, &cgAdvance, 1); | |
| 969 } | |
| 970 glyph->fAdvanceX = SkFloatToFixed_Check(cgAdvance.width); | |
| 971 glyph->fAdvanceY = -SkFloatToFixed_Check(cgAdvance.height); | |
| 991 | 972 |
| 992 // Get the state we need | 973 // The following produces skBounds in SkGlyph units (pixels, y down), |
| 993 cgGlyph = (CGGlyph) glyph->getGlyphID(fBaseGlyphCount); | 974 // or returns early if skBounds would be empty. |
| 975 SkRect skBounds; | |
| 976 | |
| 977 // On Mountain Lion, CTFontGetBoundingRectsForGlyphs with kCTFontVerticalOri entation and | |
| 978 // CTFontGetVerticalTranslationsForGlyphs do not agree when using OTF CFF fo nts. | |
| 979 // For TTF fonts these two do agree and we can use CTFontGetBoundingRectsFor Glyphs to get | |
| 980 // the bounding box and CTFontGetVerticalTranslationsForGlyphs to then draw the glyph | |
| 981 // inside that bounding box. However, with OTF CFF fonts this does not work. It appears that | |
| 982 // CTFontGetBoundingRectsForGlyphs with kCTFontVerticalOrientation on OTF CF F fonts tries | |
| 983 // to center the glyph along the vertical baseline and also perform some mys terious shift | |
| 984 // along the baseline. CTFontGetVerticalTranslationsForGlyphs does not appea r to perform | |
| 985 // these steps. | |
| 986 // | |
| 987 // It is not known which is correct (or if either is correct). However, we m ust always draw | |
| 988 // from the horizontal origin and must use CTFontGetVerticalTranslationsForG lyphs to draw. | |
| 989 // As a result, we do not call CTFontGetBoundingRectsForGlyphs for vertical glyphs. | |
| 990 | |
| 991 // On Snow Leopard, CTFontGetBoundingRectsForGlyphs ignores kCTFontVerticalO rientation and | |
| 992 // returns horizontal bounds. | |
| 993 | |
| 994 // On Lion and Mountain Lion, CTFontGetBoundingRectsForGlyphs has a bug whic h causes it to | |
| 995 // return a bad value in cgBounds.origin.x for SFNT fonts whose hhea::number OfHMetrics is | |
| 996 // less than its maxp::numGlyphs. When this is the case we try to read the b ounds from the | |
| 997 // font directly. | |
| 998 if ((isLion() || isMountainLion()) && | |
| 999 (cgGlyph < fGlyphCount && cgGlyph >= getFBoundingBoxesGlyphOffset() && g enerateBBoxes())) | |
| 1000 { | |
| 1001 const GlyphRect& gRect = fFBoundingBoxes[cgGlyph - fFBoundingBoxesGlyphO ffset]; | |
| 1002 if (gRect.fMinX >= gRect.fMaxX || gRect.fMinY >= gRect.fMaxY) { | |
| 1003 return; | |
| 1004 } | |
| 1005 skBounds = SkRect::MakeLTRB(gRect.fMinX, gRect.fMinY, gRect.fMaxX, gRect .fMaxY); | |
| 1006 // From FUnits (em space, y up) to SkGlyph units (pixels, y down). | |
| 1007 fFUnitMatrix.mapRect(&skBounds); | |
| 1008 | |
| 1009 } else { | |
| 1010 // CTFontGetBoundingRectsForGlyphs produces cgBounds in CG units (pixels , y up). | |
| 1011 CGRect cgBounds; | |
| 1012 CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontHorizontalOrientation, | |
| 1013 &cgGlyph, &cgBounds, 1); | |
| 1014 | |
| 1015 // BUG? | |
| 1016 // 0x200B (zero-advance space) seems to return a huge (garbage) bounds, when | |
| 1017 // it should be empty. So, if we see a zero-advance, we check if it has an | |
| 1018 // empty path or not, and if so, we jam the bounds to 0. Hopefully a zer o-advance | |
| 1019 // is rare, so we won't incur a big performance cost for this extra chec k. | |
| 1020 if (0 == cgAdvance.width && 0 == cgAdvance.height) { | |
| 1021 AutoCFRelease<CGPathRef> path(CTFontCreatePathForGlyph(fCTFont, cgGl yph, NULL)); | |
| 1022 if (NULL == path || CGPathIsEmpty(path)) { | |
| 1023 return; | |
| 1024 } | |
| 1025 } | |
| 1026 | |
| 1027 if (CGRectIsEmpty_inline(cgBounds)) { | |
| 1028 return; | |
| 1029 } | |
| 1030 | |
| 1031 // Convert cgBounds to SkGlyph units (pixels, y down). | |
| 1032 skBounds = SkRect::MakeXYWH(cgBounds.origin.x, -cgBounds.origin.y - cgBo unds.size.height, | |
| 1033 cgBounds.size.width, cgBounds.size.height); | |
| 1034 } | |
| 994 | 1035 |
| 995 if (fVertical) { | 1036 if (fVertical) { |
| 996 if (!isSnowLeopard()) { | 1037 // Due to all of the vertical bounds bugs, skBounds is always the horizo ntal bounds. |
| 997 // Lion and Leopard respect the vertical font metrics. | 1038 // Convert these horizontal bounds into vertical bounds. |
| 998 CTFontGetBoundingRectsForGlyphs(fCTVerticalFont, kCTFontVerticalOrie ntation, | 1039 SkPoint offset; |
| 999 &cgGlyph, &bounds, 1); | 1040 getVerticalOffset(cgGlyph, &offset); |
| 1000 } else { | 1041 skBounds.offset(offset); |
| 1001 // Snow Leopard and earlier respect the vertical font metrics for | |
| 1002 // advances, but not bounds, so use the default box and adjust it be low. | |
| 1003 CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontDefaultOrientation, | |
| 1004 &cgGlyph, &bounds, 1); | |
| 1005 } | |
| 1006 CTFontGetAdvancesForGlyphs(fCTVerticalFont, kCTFontVerticalOrientation, | |
| 1007 &cgGlyph, &advance, 1); | |
| 1008 } else { | |
| 1009 CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontDefaultOrientation, | |
| 1010 &cgGlyph, &bounds, 1); | |
| 1011 CTFontGetAdvancesForGlyphs(fCTFont, kCTFontDefaultOrientation, | |
| 1012 &cgGlyph, &advance, 1); | |
| 1013 } | 1042 } |
| 1014 | 1043 |
| 1015 // BUG? | 1044 // Currently the bounds are based on being rendered at (0,0). |
| 1016 // 0x200B (zero-advance space) seems to return a huge (garbage) bounds, when | 1045 // The top left must not move, since that is the base from which subpixel po sitioning is offset. |
| 1017 // it should be empty. So, if we see a zero-advance, we check if it has an | 1046 if (fDoSubPosition) { |
| 1018 // empty path or not, and if so, we jam the bounds to 0. Hopefully a zero-ad vance | 1047 skBounds.fRight += SkFixedToFloat(glyph->getSubXFixed()); |
| 1019 // is rare, so we won't incur a big performance cost for this extra check. | 1048 skBounds.fBottom += SkFixedToFloat(glyph->getSubYFixed()); |
| 1020 if (0 == advance.width && 0 == advance.height) { | |
| 1021 AutoCFRelease<CGPathRef> path(CTFontCreatePathForGlyph(fCTFont, cgGlyph, NULL)); | |
| 1022 if (NULL == path || CGPathIsEmpty(path)) { | |
| 1023 bounds = CGRectMake(0, 0, 0, 0); | |
| 1024 } | |
| 1025 } | 1049 } |
| 1026 | 1050 |
| 1027 glyph->zeroMetrics(); | 1051 SkIRect skIBounds; |
| 1028 glyph->fAdvanceX = SkFloatToFixed_Check(advance.width); | 1052 skBounds.roundOut(&skIBounds); |
| 1029 glyph->fAdvanceY = -SkFloatToFixed_Check(advance.height); | 1053 // Expand the bounds by 1 pixel, to give CG room for anti-aliasing. |
| 1030 | 1054 // Note that this outset is to allow room for LCD smoothed glyphs. However, the correct outset |
| 1031 if (CGRectIsEmpty_inline(bounds)) { | 1055 // is not currently known, as CG dilates the outlines by some percentage. |
| 1032 return; | 1056 // Note that if this context is A8 and not back-forming from LCD, there is n o need to outset. |
| 1033 } | 1057 skIBounds.outset(1, 1); |
| 1034 | 1058 glyph->fLeft = SkToS16(skIBounds.fLeft); |
| 1035 if (isLeopard() && !fVertical) { | 1059 glyph->fTop = SkToS16(skIBounds.fTop); |
| 1036 // Leopard does not consider the matrix skew in its bounds. | 1060 glyph->fWidth = SkToU16(skIBounds.width()); |
| 1037 // Run the bounding rectangle through the skew matrix to determine | 1061 glyph->fHeight = SkToU16(skIBounds.height()); |
| 1038 // the true bounds. However, this doesn't work if the font is vertical. | 1062 |
| 1039 // FIXME (Leopard): If the font has synthetic italic (e.g., matrix skew) | |
| 1040 // and the font is vertical, the bounds need to be recomputed. | |
| 1041 SkRect glyphBounds = SkRect::MakeXYWH( | |
| 1042 bounds.origin.x, bounds.origin.y, | |
| 1043 bounds.size.width, bounds.size.height); | |
| 1044 fUnitMatrix.mapRect(&glyphBounds); | |
| 1045 bounds.origin.x = glyphBounds.fLeft; | |
| 1046 bounds.origin.y = glyphBounds.fTop; | |
| 1047 bounds.size.width = glyphBounds.width(); | |
| 1048 bounds.size.height = glyphBounds.height(); | |
| 1049 } | |
| 1050 // Adjust the bounds | |
| 1051 // | |
| 1052 // CTFontGetBoundingRectsForGlyphs ignores the font transform, so we need | |
| 1053 // to transform the bounding box ourselves. | |
| 1054 // | |
| 1055 // The bounds are also expanded by 1 pixel, to give CG room for anti-aliasin g. | |
| 1056 CGRectInset_inline(&bounds, -1, -1); | |
| 1057 | |
| 1058 // Get the metrics | |
| 1059 bool lionAdjustedMetrics = false; | |
| 1060 if (isLion() || isMountainLion()) { | |
| 1061 if (cgGlyph < fGlyphCount && cgGlyph >= getFBoundingBoxesGlyphOffset() & & generateBBoxes()){ | |
| 1062 lionAdjustedMetrics = true; | |
| 1063 SkRect adjust; | |
| 1064 const GlyphRect& gRect = fFBoundingBoxes[cgGlyph - fFBoundingBoxesGl yphOffset]; | |
| 1065 adjust.set(gRect.fMinX, gRect.fMinY, gRect.fMaxX, gRect.fMaxY); | |
| 1066 fFBoundingBoxesMatrix.mapRect(&adjust); | |
| 1067 bounds.origin.x = SkScalarToFloat(adjust.fLeft) - 1; | |
| 1068 bounds.origin.y = SkScalarToFloat(adjust.fTop) - 1; | |
| 1069 } | |
| 1070 // Lion returns fractions in the bounds | |
| 1071 glyph->fWidth = SkToU16(sk_float_ceil2int(bounds.size.width)); | |
| 1072 glyph->fHeight = SkToU16(sk_float_ceil2int(bounds.size.height)); | |
| 1073 } else { | |
| 1074 glyph->fWidth = SkToU16(sk_float_round2int(bounds.size.width)); | |
| 1075 glyph->fHeight = SkToU16(sk_float_round2int(bounds.size.height)); | |
| 1076 } | |
| 1077 glyph->fTop = SkToS16(-sk_float_round2int(CGRectGetMaxY_inline(bounds))); | |
| 1078 glyph->fLeft = SkToS16(sk_float_round2int(CGRectGetMinX_inline(bounds))); | |
| 1079 SkIPoint offset; | |
| 1080 if (fVertical && (isSnowLeopard() || lionAdjustedMetrics)) { | |
| 1081 // SnowLeopard doesn't respect vertical metrics, so compute them manuall y. | |
| 1082 // Also compute them for Lion when the metrics were computed by hand. | |
| 1083 getVerticalOffset(cgGlyph, &offset); | |
| 1084 glyph->fLeft += offset.fX; | |
| 1085 glyph->fTop += offset.fY; | |
| 1086 } | |
| 1087 #ifdef HACK_COLORGLYPHS | 1063 #ifdef HACK_COLORGLYPHS |
| 1088 glyph->fMaskFormat = SkMask::kARGB32_Format; | 1064 glyph->fMaskFormat = SkMask::kARGB32_Format; |
| 1089 #endif | 1065 #endif |
| 1090 } | 1066 } |
| 1091 | 1067 |
| 1092 #include "SkColorPriv.h" | 1068 #include "SkColorPriv.h" |
| 1093 | 1069 |
| 1094 static void build_power_table(uint8_t table[], float ee) { | 1070 static void build_power_table(uint8_t table[], float ee) { |
| 1095 for (int i = 0; i < 256; i++) { | 1071 for (int i = 0; i < 256; i++) { |
| 1096 float x = i / 255.f; | 1072 float x = i / 255.f; |
| (...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1364 } | 1340 } |
| 1365 | 1341 |
| 1366 CGGlyph cgGlyph = (CGGlyph)glyph.getGlyphID(fBaseGlyphCount); | 1342 CGGlyph cgGlyph = (CGGlyph)glyph.getGlyphID(fBaseGlyphCount); |
| 1367 AutoCFRelease<CGPathRef> cgPath(CTFontCreatePathForGlyph(font, cgGlyph, NULL )); | 1343 AutoCFRelease<CGPathRef> cgPath(CTFontCreatePathForGlyph(font, cgGlyph, NULL )); |
| 1368 | 1344 |
| 1369 path->reset(); | 1345 path->reset(); |
| 1370 if (cgPath != NULL) { | 1346 if (cgPath != NULL) { |
| 1371 CGPathApply(cgPath, path, SkScalerContext_Mac::CTPathElement); | 1347 CGPathApply(cgPath, path, SkScalerContext_Mac::CTPathElement); |
| 1372 } | 1348 } |
| 1373 | 1349 |
| 1374 if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) { | 1350 if (fDoSubPosition) { |
| 1375 SkMatrix m; | 1351 SkMatrix m; |
| 1376 m.setScale(SkScalarInvert(scaleX), SkScalarInvert(scaleY)); | 1352 m.setScale(SkScalarInvert(scaleX), SkScalarInvert(scaleY)); |
| 1377 path->transform(m); | 1353 path->transform(m); |
| 1378 // balance the call to CTFontCreateCopyWithAttributes | 1354 // balance the call to CTFontCreateCopyWithAttributes |
| 1379 CFSafeRelease(font); | 1355 CFSafeRelease(font); |
| 1380 } | 1356 } |
| 1381 if (fRec.fFlags & SkScalerContext::kVertical_Flag) { | 1357 if (fVertical) { |
| 1382 SkIPoint offset; | 1358 SkPoint offset; |
| 1383 getVerticalOffset(cgGlyph, &offset); | 1359 getVerticalOffset(cgGlyph, &offset); |
| 1384 path->offset(SkIntToScalar(offset.fX), SkIntToScalar(offset.fY)); | 1360 path->offset(offset.fX, offset.fY); |
| 1385 } | 1361 } |
| 1386 } | 1362 } |
| 1387 | 1363 |
| 1388 void SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* mx, | 1364 void SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* mx, |
| 1389 SkPaint::FontMetrics* my) { | 1365 SkPaint::FontMetrics* my) { |
| 1390 CGRect theBounds = CTFontGetBoundingBox(fCTFont); | 1366 CGRect theBounds = CTFontGetBoundingBox(fCTFont); |
| 1391 | 1367 |
| 1392 SkPaint::FontMetrics theMetrics; | 1368 SkPaint::FontMetrics theMetrics; |
| 1393 theMetrics.fTop = CGToScalar(-CGRectGetMaxY_inline(theBounds)); | 1369 theMetrics.fTop = CGToScalar(-CGRectGetMaxY_inline(theBounds)); |
| 1394 theMetrics.fAscent = CGToScalar(-CTFontGetAscent(fCTFont)); | 1370 theMetrics.fAscent = CGToScalar(-CTFontGetAscent(fCTFont)); |
| (...skipping 826 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2221 return NULL; | 2197 return NULL; |
| 2222 } | 2198 } |
| 2223 return create_from_dataProvider(pr); | 2199 return create_from_dataProvider(pr); |
| 2224 } | 2200 } |
| 2225 }; | 2201 }; |
| 2226 | 2202 |
| 2227 SkFontMgr* SkFontMgr::Factory() { | 2203 SkFontMgr* SkFontMgr::Factory() { |
| 2228 return SkNEW(SkFontMgr_Mac); | 2204 return SkNEW(SkFontMgr_Mac); |
| 2229 } | 2205 } |
| 2230 #endif | 2206 #endif |
| OLD | NEW |