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

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

Issue 15064003: Fix vertical text scaling on Mac. (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: Make vertical text look better. Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« src/core/SkDraw.cpp ('K') | « src/core/SkDraw.cpp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 1
2 /* 2 /*
3 * Copyright 2006 The Android Open Source Project 3 * Copyright 2006 The Android Open Source Project
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 */ 7 */
8 8
9 #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
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
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
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
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
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() { };
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);
682 uint16_t getFBoundingBoxesGlyphOffset(); 655 uint16_t getFBoundingBoxesGlyphOffset();
683 void getVerticalOffset(CGGlyph glyphID, SkIPoint* offset) const; 656 /** Returns the offset from the horizontal origin to the vertical origin in SkGlyph units. */
657 void getVerticalOffset(CGGlyph glyphID, SkPoint* offset) const;
684 bool generateBBoxes(); 658 bool generateBBoxes();
685 659
686 CGAffineTransform fTransform; 660 /**
687 SkMatrix fUnitMatrix; // without font size 661 * Converts from FUnits (em space, y up) to SkGlyph units (pixels, y down).
688 SkMatrix fVerticalMatrix; // unit rotated 662 *
689 SkMatrix fMatrix; // with font size 663 * Used on Snow Leopard to correct CTFontGetVerticalTranslationsForGlyphs.
690 SkMatrix fFBoundingBoxesMatrix; // lion-specific fix 664 * Used on Lion to correct CTFontGetBoundingRectsForGlyphs.
665 */
666 SkMatrix fFUnitMatrix;
691 Offscreen fOffscreen; 667 Offscreen fOffscreen;
692 AutoCFRelease<CTFontRef> fCTFont; 668 AutoCFRelease<CTFontRef> fCTFont;
693 AutoCFRelease<CTFontRef> fCTVerticalFont; // for vertical advance 669 /** CT vertical metrics are pre-rotated (in em space, before transform) 90de g clock-wise.
670 * This makes kCTFontDefaultOrientation dangerous, because the metrics from
671 * kCTFontHorizontalOrientation are in a different space from kCTFontVertic alOrientation.
672 * Use fCTVerticalFont with kCTFontVerticalOrientation to get metrics in th e same space.
673 */
674 AutoCFRelease<CTFontRef> fCTVerticalFont;
694 AutoCFRelease<CGFontRef> fCGFont; 675 AutoCFRelease<CGFontRef> fCGFont;
695 GlyphRect* fFBoundingBoxes; 676 SkAutoTMalloc<GlyphRect> fFBoundingBoxes;
696 uint16_t fFBoundingBoxesGlyphOffset; 677 uint16_t fFBoundingBoxesGlyphOffset;
697 uint16_t fGlyphCount; 678 uint16_t fGlyphCount;
698 bool fGeneratedFBoundingBoxes; 679 bool fGeneratedFBoundingBoxes;
699 bool fDoSubPosition; 680 const bool fDoSubPosition;
700 bool fVertical; 681 const bool fVertical;
701 682
702 friend class Offscreen; 683 friend class Offscreen;
703 684
704 typedef SkScalerContext INHERITED; 685 typedef SkScalerContext INHERITED;
705 }; 686 };
706 687
707 SkScalerContext_Mac::SkScalerContext_Mac(SkTypeface_Mac* typeface, 688 SkScalerContext_Mac::SkScalerContext_Mac(SkTypeface_Mac* typeface,
708 const SkDescriptor* desc) 689 const SkDescriptor* desc)
709 : INHERITED(typeface, desc) 690 : INHERITED(typeface, desc)
710 , fFBoundingBoxes(NULL) 691 , fFBoundingBoxes()
711 , fFBoundingBoxesGlyphOffset(0) 692 , fFBoundingBoxesGlyphOffset(0)
712 , fGeneratedFBoundingBoxes(false) 693 , fGeneratedFBoundingBoxes(false)
694 , fDoSubPosition(SkToBool(fRec.fFlags & kSubpixelPositioning_Flag))
695 , fVertical(SkToBool(fRec.fFlags & kVertical_Flag))
696
713 { 697 {
698 //this->forceGenerateImageFromPath();
714 CTFontRef ctFont = typeface->fFontRef.get(); 699 CTFontRef ctFont = typeface->fFontRef.get();
715 CFIndex numGlyphs = CTFontGetGlyphCount(ctFont); 700 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); 701 SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF);
726 702 fGlyphCount = SkToU16(numGlyphs);
727 fTransform = MatrixToCGAffineTransform(fMatrix); 703
728 704 fRec.getSingleMatrix(&fFUnitMatrix);
729 CGAffineTransform transform; 705 CGAffineTransform transform = MatrixToCGAffineTransform(fFUnitMatrix);
730 CGFloat unitFontSize; 706
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; 707 AutoCFRelease<CTFontDescriptorRef> ctFontDesc;
744 if (fVertical) { 708 if (fVertical) {
745 AutoCFRelease<CFMutableDictionaryRef> cfAttributes(CFDictionaryCreateMut able( 709 AutoCFRelease<CFMutableDictionaryRef> cfAttributes(CFDictionaryCreateMut able(
746 kCFAllocatorDefault, 0, 710 kCFAllocatorDefault, 0,
747 &kCFTypeDictionaryKeyCallBacks, 711 &kCFTypeDictionaryKeyCallBacks,
748 &kCFTypeDictionaryValueCallBacks)); 712 &kCFTypeDictionaryValueCallBacks));
749 if (cfAttributes) { 713 if (cfAttributes) {
750 CTFontOrientation ctOrientation = kCTFontVerticalOrientation; 714 CTFontOrientation ctOrientation = kCTFontVerticalOrientation;
751 AutoCFRelease<CFNumberRef> cfVertical(CFNumberCreate( 715 AutoCFRelease<CFNumberRef> cfVertical(CFNumberCreate(
752 kCFAllocatorDefault, kCFNumberSInt32Type, &ctOrientation)); 716 kCFAllocatorDefault, kCFNumberSInt32Type, &ctOrientation));
753 CFDictionaryAddValue(cfAttributes, kCTFontOrientationAttribute, cfVe rtical); 717 CFDictionaryAddValue(cfAttributes, kCTFontOrientationAttribute, cfVe rtical);
754 ctFontDesc = CTFontDescriptorCreateWithAttributes(cfAttributes); 718 ctFontDesc = CTFontDescriptorCreateWithAttributes(cfAttributes);
755 } 719 }
756 } 720 }
757 fCTFont = CTFontCreateCopyWithAttributes(ctFont, unitFontSize, &transform, c tFontDesc); 721 // Since our matrix includes everything, we pass 1 for size.
722 fCTFont = CTFontCreateCopyWithAttributes(ctFont, 1.f, &transform, ctFontDesc );
758 fCGFont = CTFontCopyGraphicsFont(fCTFont, NULL); 723 fCGFont = CTFontCopyGraphicsFont(fCTFont, NULL);
759 if (fVertical) { 724 if (fVertical) {
760 CGAffineTransform rotateLeft = CGAffineTransformMake(0, -1, 1, 0, 0, 0); 725 CGAffineTransform rotateLeft = CGAffineTransformMake(0, -1, 1, 0, 0, 0);
761 transform = CGAffineTransformConcat(rotateLeft, transform); 726 transform = CGAffineTransformConcat(rotateLeft, transform);
762 fCTVerticalFont = CTFontCreateCopyWithAttributes(ctFont, unitFontSize, & transform, NULL); 727 fCTVerticalFont = CTFontCreateCopyWithAttributes(ctFont, 1.f, &transform , NULL);
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 } 728 }
772 fGlyphCount = SkToU16(numGlyphs); 729 SkScalar emPerFUnit = SkScalarInvert(SkIntToScalar(CGFontGetUnitsPerEm(fCGFo nt)));
773 fDoSubPosition = SkToBool(fRec.fFlags & kSubpixelPositioning_Flag); 730 fFUnitMatrix.preScale(emPerFUnit, -emPerFUnit);
774 }
775
776 SkScalerContext_Mac::~SkScalerContext_Mac() {
777 delete[] fFBoundingBoxes;
778 } 731 }
779 732
780 CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph, 733 CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
781 CGGlyph glyphID, size_t* rowBytesPtr, 734 CGGlyph glyphID, size_t* rowBytesPtr,
782 bool generateA8FromLCD) { 735 bool generateA8FromLCD) {
783 if (!fRGBSpace) { 736 if (!fRGBSpace) {
784 //It doesn't appear to matter what color space is specified. 737 //It doesn't appear to matter what color space is specified.
785 //Regular blends and antialiased text are always (s*a + d*(1-a)) 738 //Regular blends and antialiased text are always (s*a + d*(1-a))
786 //and smoothed text is always g=2.0. 739 //and smoothed text is always g=2.0.
787 fRGBSpace = CGColorSpaceCreateDeviceRGB(); 740 fRGBSpace = CGColorSpaceCreateDeviceRGB();
(...skipping 28 matching lines...) Expand all
816 fCG = CGBitmapContextCreate(image, fSize.fWidth, fSize.fHeight, 8, 769 fCG = CGBitmapContextCreate(image, fSize.fWidth, fSize.fHeight, 8,
817 rowBytes, fRGBSpace, BITMAP_INFO_RGB); 770 rowBytes, fRGBSpace, BITMAP_INFO_RGB);
818 771
819 // skia handles quantization itself, so we disable this for cg to get 772 // skia handles quantization itself, so we disable this for cg to get
820 // full fractional data from them. 773 // full fractional data from them.
821 CGContextSetAllowsFontSubpixelQuantization(fCG, false); 774 CGContextSetAllowsFontSubpixelQuantization(fCG, false);
822 CGContextSetShouldSubpixelQuantizeFonts(fCG, false); 775 CGContextSetShouldSubpixelQuantizeFonts(fCG, false);
823 776
824 CGContextSetTextDrawingMode(fCG, kCGTextFill); 777 CGContextSetTextDrawingMode(fCG, kCGTextFill);
825 CGContextSetFont(fCG, context.fCGFont); 778 CGContextSetFont(fCG, context.fCGFont);
826 CGContextSetFontSize(fCG, 1); 779 CGContextSetFontSize(fCG, 1.0f /*CTFontGetSize(context.fCTFont)*/);
827 CGContextSetTextMatrix(fCG, context.fTransform); 780 CGContextSetTextMatrix(fCG, CTFontGetMatrix(context.fCTFont));
828 781
829 CGContextSetAllowsFontSubpixelPositioning(fCG, context.fDoSubPosition); 782 // Because CG always draws from the horizontal baseline,
830 CGContextSetShouldSubpixelPositionFonts(fCG, context.fDoSubPosition); 783 // if there is a non-integral translation from the horizontal origin to the vertical origin,
784 // then CG cannot draw the glyph in the correct location without subpixe l positioning.
785 CGContextSetAllowsFontSubpixelPositioning(fCG, context.fDoSubPosition || context.fVertical);
786 CGContextSetShouldSubpixelPositionFonts(fCG, context.fDoSubPosition || c ontext.fVertical);
831 787
832 // Draw white on black to create mask. 788 // Draw white on black to create mask.
833 // TODO: Draw black on white and invert, CG has a special case codepath. 789 // TODO: Draw black on white and invert, CG has a special case codepath.
834 CGContextSetGrayFillColor(fCG, 1.0f, 1.0f); 790 CGContextSetGrayFillColor(fCG, 1.0f, 1.0f);
835 791
836 // force our checks below to happen 792 // force our checks below to happen
837 fDoAA = !doAA; 793 fDoAA = !doAA;
838 fDoLCD = !doLCD; 794 fDoLCD = !doLCD;
839 } 795 }
840 796
(...skipping 12 matching lines...) Expand all
853 809
854 // erase to black 810 // erase to black
855 sk_memset_rect32(image, 0, glyph.fWidth, glyph.fHeight, rowBytes); 811 sk_memset_rect32(image, 0, glyph.fWidth, glyph.fHeight, rowBytes);
856 812
857 float subX = 0; 813 float subX = 0;
858 float subY = 0; 814 float subY = 0;
859 if (context.fDoSubPosition) { 815 if (context.fDoSubPosition) {
860 subX = SkFixedToFloat(glyph.getSubXFixed()); 816 subX = SkFixedToFloat(glyph.getSubXFixed());
861 subY = SkFixedToFloat(glyph.getSubYFixed()); 817 subY = SkFixedToFloat(glyph.getSubYFixed());
862 } 818 }
819
820 // CGContextShowGlyphsAtPoint always draws using the horizontal baseline ori gin.
863 if (context.fVertical) { 821 if (context.fVertical) {
864 SkIPoint offset; 822 SkPoint offset;
865 context.getVerticalOffset(glyphID, &offset); 823 context.getVerticalOffset(glyphID, &offset);
866 subX += offset.fX; 824 subX += offset.fX;
867 subY += offset.fY; 825 subY += offset.fY;
868 } 826 }
827
869 CGContextShowGlyphsAtPoint(fCG, -glyph.fLeft + subX, 828 CGContextShowGlyphsAtPoint(fCG, -glyph.fLeft + subX,
870 glyph.fTop + glyph.fHeight - subY, 829 glyph.fTop + glyph.fHeight - subY,
871 &glyphID, 1); 830 &glyphID, 1);
872 831
873 SkASSERT(rowBytesPtr); 832 SkASSERT(rowBytesPtr);
874 *rowBytesPtr = rowBytes; 833 *rowBytesPtr = rowBytes;
875 return image; 834 return image;
876 } 835 }
877 836
878 void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkIPoint* offset) c onst { 837 void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkPoint* offset) co nst {
879 CGSize vertOffset; 838 // SnowLeopard returns cgVertOffset in completely un-transformed FUnits (em space, y up).
880 CTFontGetVerticalTranslationsForGlyphs(fCTVerticalFont, &glyphID, &vertOffse t, 1); 839 // Lion and Leopard return cgVertOffset in CG units (pixels, y up).
881 const SkPoint trans = {CGToScalar(vertOffset.width), 840 CGSize cgVertOffset;
882 CGToScalar(vertOffset.height)}; 841 CTFontGetVerticalTranslationsForGlyphs(fCTFont, &glyphID, &cgVertOffset, 1);
883 SkPoint floatOffset; 842
884 fVerticalMatrix.mapPoints(&floatOffset, &trans, 1); 843 SkPoint skVertOffset = { CGToScalar(cgVertOffset.width), CGToScalar(cgVertOf fset.height) };
885 if (!isSnowLeopard()) { 844 if (isSnowLeopard()) {
886 // SnowLeopard fails to apply the font's matrix to the vertical metrics, 845 // 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 846 fFUnitMatrix.mapPoints(&skVertOffset, 1);
888 // point size 1. There may be some way to avoid mapping here by setting up 847 } else {
889 // fVerticalMatrix differently, but this works for now. 848 skVertOffset.fY = -skVertOffset.fY;
890 fUnitMatrix.mapPoints(&floatOffset, 1);
891 } 849 }
892 offset->fX = SkScalarRound(floatOffset.fX); 850
893 offset->fY = SkScalarRound(floatOffset.fY); 851 *offset = skVertOffset;
894 } 852 }
895 853
896 uint16_t SkScalerContext_Mac::getFBoundingBoxesGlyphOffset() { 854 uint16_t SkScalerContext_Mac::getFBoundingBoxesGlyphOffset() {
897 if (fFBoundingBoxesGlyphOffset) { 855 if (fFBoundingBoxesGlyphOffset) {
898 return fFBoundingBoxesGlyphOffset; 856 return fFBoundingBoxesGlyphOffset;
899 } 857 }
900 fFBoundingBoxesGlyphOffset = fGlyphCount; // fallback for all fonts 858 fFBoundingBoxesGlyphOffset = fGlyphCount; // fallback for all fonts
901 AutoCGTable<SkOTTableHorizontalHeader> hheaTable(fCGFont); 859 AutoCGTable<SkOTTableHorizontalHeader> hheaTable(fCGFont);
902 if (hheaTable.fData) { 860 if (hheaTable.fData) {
903 fFBoundingBoxesGlyphOffset = SkEndian_SwapBE16(hheaTable->numberOfHMetri cs); 861 fFBoundingBoxesGlyphOffset = SkEndian_SwapBE16(hheaTable->numberOfHMetri cs);
(...skipping 27 matching lines...) Expand all
931 if (!locaTable.fData) { 889 if (!locaTable.fData) {
932 return false; 890 return false;
933 } 891 }
934 892
935 AutoCGTable<SkOTTableGlyph> glyfTable(fCGFont); 893 AutoCGTable<SkOTTableGlyph> glyfTable(fCGFont);
936 if (!glyfTable.fData) { 894 if (!glyfTable.fData) {
937 return false; 895 return false;
938 } 896 }
939 897
940 uint16_t entries = fGlyphCount - fFBoundingBoxesGlyphOffset; 898 uint16_t entries = fGlyphCount - fFBoundingBoxesGlyphOffset;
941 fFBoundingBoxes = new GlyphRect[entries]; 899 fFBoundingBoxes.reset(entries);
942 900
943 SkOTTableHead::IndexToLocFormat locaFormat = headTable->indexToLocFormat; 901 SkOTTableHead::IndexToLocFormat locaFormat = headTable->indexToLocFormat;
944 SkOTTableGlyph::Iterator glyphDataIter(*glyfTable.fData, *locaTable.fData, l ocaFormat); 902 SkOTTableGlyph::Iterator glyphDataIter(*glyfTable.fData, *locaTable.fData, l ocaFormat);
945 glyphDataIter.advance(fFBoundingBoxesGlyphOffset); 903 glyphDataIter.advance(fFBoundingBoxesGlyphOffset);
946 for (uint16_t boundingBoxesIndex = 0; boundingBoxesIndex < entries; ++boundi ngBoxesIndex) { 904 for (uint16_t boundingBoxesIndex = 0; boundingBoxesIndex < entries; ++boundi ngBoxesIndex) {
947 const SkOTTableGlyphData* glyphData = glyphDataIter.next(); 905 const SkOTTableGlyphData* glyphData = glyphDataIter.next();
948 GlyphRect& rect = fFBoundingBoxes[boundingBoxesIndex]; 906 GlyphRect& rect = fFBoundingBoxes[boundingBoxesIndex];
949 rect.fMinX = SkEndian_SwapBE16(glyphData->xMin); 907 rect.fMinX = SkEndian_SwapBE16(glyphData->xMin);
950 rect.fMinY = SkEndian_SwapBE16(glyphData->yMin); 908 rect.fMinY = SkEndian_SwapBE16(glyphData->yMin);
951 rect.fMaxX = SkEndian_SwapBE16(glyphData->xMax); 909 rect.fMaxX = SkEndian_SwapBE16(glyphData->xMax);
952 rect.fMaxY = SkEndian_SwapBE16(glyphData->yMax); 910 rect.fMaxY = SkEndian_SwapBE16(glyphData->yMax);
953 } 911 }
954 fFBoundingBoxesMatrix = fMatrix;
955 flip(&fFBoundingBoxesMatrix);
956 SkScalar fontScale = getFontScale(fCGFont);
957 fFBoundingBoxesMatrix.preScale(fontScale, fontScale);
958 return true; 912 return true;
959 } 913 }
960 914
961 unsigned SkScalerContext_Mac::generateGlyphCount(void) { 915 unsigned SkScalerContext_Mac::generateGlyphCount(void) {
962 return fGlyphCount; 916 return fGlyphCount;
963 } 917 }
964 918
965 uint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni) { 919 uint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni) {
966 CGGlyph cgGlyph; 920 CGGlyph cgGlyph;
967 UniChar theChar; 921 UniChar theChar;
(...skipping 10 matching lines...) Expand all
978 } 932 }
979 933
980 return cgGlyph; 934 return cgGlyph;
981 } 935 }
982 936
983 void SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) { 937 void SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) {
984 this->generateMetrics(glyph); 938 this->generateMetrics(glyph);
985 } 939 }
986 940
987 void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) { 941 void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) {
988 CGSize advance; 942 const CGGlyph cgGlyph = (CGGlyph) glyph->getGlyphID(fBaseGlyphCount);
989 CGRect bounds; 943 glyph->zeroMetrics();
990 CGGlyph cgGlyph; 944
991 945 bool wantedVerticalBoundsButGotHorizontalBounds = false;
992 // Get the state we need 946
993 cgGlyph = (CGGlyph) glyph->getGlyphID(fBaseGlyphCount); 947 // The following block produces gcAdvance and cgBounds in CG units (pixels, y up).
994 948 CGSize cgAdvance;
949 CGRect cgBounds;
995 if (fVertical) { 950 if (fVertical) {
996 if (!isSnowLeopard()) { 951 if (!isSnowLeopard()) {
997 // Lion and Leopard respect the vertical font metrics. 952 // Lion and Mountain Lion respect requests for vertical bounds.
998 CTFontGetBoundingRectsForGlyphs(fCTVerticalFont, kCTFontVerticalOrie ntation, 953 CTFontGetBoundingRectsForGlyphs(fCTVerticalFont, kCTFontVerticalOrie ntation,
999 &cgGlyph, &bounds, 1); 954 &cgGlyph, &cgBounds, 1);
1000 } else { 955 } else {
1001 // Snow Leopard and earlier respect the vertical font metrics for 956 // Snow Leopard does not respect requests for vertical bounds.
1002 // advances, but not bounds, so use the default box and adjust it be low. 957 // Request the horizontal bounds and adjust it below.
1003 CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontDefaultOrientation, 958 CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontHorizontalOrientatio n,
1004 &cgGlyph, &bounds, 1); 959 &cgGlyph, &cgBounds, 1);
960 wantedVerticalBoundsButGotHorizontalBounds = true;
1005 } 961 }
962 // All versions respect requests for vertical advances.
1006 CTFontGetAdvancesForGlyphs(fCTVerticalFont, kCTFontVerticalOrientation, 963 CTFontGetAdvancesForGlyphs(fCTVerticalFont, kCTFontVerticalOrientation,
1007 &cgGlyph, &advance, 1); 964 &cgGlyph, &cgAdvance, 1);
1008 } else { 965 } else {
1009 CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontDefaultOrientation, 966 CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontHorizontalOrientation,
1010 &cgGlyph, &bounds, 1); 967 &cgGlyph, &cgBounds, 1);
1011 CTFontGetAdvancesForGlyphs(fCTFont, kCTFontDefaultOrientation, 968 CTFontGetAdvancesForGlyphs(fCTFont, kCTFontHorizontalOrientation,
1012 &cgGlyph, &advance, 1); 969 &cgGlyph, &cgAdvance, 1);
1013 } 970 }
971 glyph->fAdvanceX = SkFloatToFixed_Check(cgAdvance.width);
972 glyph->fAdvanceY = -SkFloatToFixed_Check(cgAdvance.height);
973
974 // Now work around all the bounds bugs.
1014 975
1015 // BUG? 976 // BUG?
1016 // 0x200B (zero-advance space) seems to return a huge (garbage) bounds, when 977 // 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 978 // 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 zero-ad vance 979 // empty path or not, and if so, we jam the bounds to 0. Hopefully a zero-ad vance
1019 // is rare, so we won't incur a big performance cost for this extra check. 980 // is rare, so we won't incur a big performance cost for this extra check.
1020 if (0 == advance.width && 0 == advance.height) { 981 if (0 == cgAdvance.width && 0 == cgAdvance.height) {
1021 AutoCFRelease<CGPathRef> path(CTFontCreatePathForGlyph(fCTFont, cgGlyph, NULL)); 982 AutoCFRelease<CGPathRef> path(CTFontCreatePathForGlyph(fCTFont, cgGlyph, NULL));
1022 if (NULL == path || CGPathIsEmpty(path)) { 983 if (NULL == path || CGPathIsEmpty(path)) {
1023 bounds = CGRectMake(0, 0, 0, 0); 984 return;
1024 } 985 }
1025 } 986 }
1026 987
1027 glyph->zeroMetrics(); 988 if (CGRectIsEmpty_inline(cgBounds)) {
1028 glyph->fAdvanceX = SkFloatToFixed_Check(advance.width);
1029 glyph->fAdvanceY = -SkFloatToFixed_Check(advance.height);
1030
1031 if (CGRectIsEmpty_inline(bounds)) {
1032 return; 989 return;
1033 } 990 }
1034 991
1035 if (isLeopard() && !fVertical) { 992 // Convert bounds to SkGlyph units (pixels, y down).
1036 // Leopard does not consider the matrix skew in its bounds. 993 SkRect skBounds = SkRect::MakeXYWH(cgBounds.origin.x, -cgBounds.origin.y - c gBounds.size.height,
1037 // Run the bounding rectangle through the skew matrix to determine 994 cgBounds.size.width, cgBounds.size.height );
1038 // the true bounds. However, this doesn't work if the font is vertical.
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()) { 995 if (isLion() || isMountainLion()) {
1061 if (cgGlyph < fGlyphCount && cgGlyph >= getFBoundingBoxesGlyphOffset() & & generateBBoxes()){ 996 if (cgGlyph < fGlyphCount && cgGlyph >= getFBoundingBoxesGlyphOffset() & & generateBBoxes()){
1062 lionAdjustedMetrics = true;
1063 SkRect adjust;
1064 const GlyphRect& gRect = fFBoundingBoxes[cgGlyph - fFBoundingBoxesGl yphOffset]; 997 const GlyphRect& gRect = fFBoundingBoxes[cgGlyph - fFBoundingBoxesGl yphOffset];
1065 adjust.set(gRect.fMinX, gRect.fMinY, gRect.fMaxX, gRect.fMaxY); 998 skBounds = SkRect::MakeLTRB(gRect.fMinX, gRect.fMinY, gRect.fMaxX, g Rect.fMaxY);
1066 fFBoundingBoxesMatrix.mapRect(&adjust); 999 // From FUnits (em space, y up) to SkGlyph units (pixels, y down).
1067 bounds.origin.x = SkScalarToFloat(adjust.fLeft) - 1; 1000 fFUnitMatrix.mapRect(&skBounds);
1068 bounds.origin.y = SkScalarToFloat(adjust.fTop) - 1; 1001 wantedVerticalBoundsButGotHorizontalBounds = fVertical;
1069 } 1002 }
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 } 1003 }
1077 glyph->fTop = SkToS16(-sk_float_round2int(CGRectGetMaxY_inline(bounds))); 1004 if (wantedVerticalBoundsButGotHorizontalBounds) {
1078 glyph->fLeft = SkToS16(sk_float_round2int(CGRectGetMinX_inline(bounds))); 1005 // Snow Leopard does not respect requests for vertical bounds.
1079 SkIPoint offset; 1006 // Our own fFBoundingBoxes are for horizontal bounds.
1080 if (fVertical && (isSnowLeopard() || lionAdjustedMetrics)) { 1007 // Convert these horizontal bounds into vertical bounds.
1081 // SnowLeopard doesn't respect vertical metrics, so compute them manuall y. 1008 SkPoint offset;
1082 // Also compute them for Lion when the metrics were computed by hand.
1083 getVerticalOffset(cgGlyph, &offset); 1009 getVerticalOffset(cgGlyph, &offset);
1084 glyph->fLeft += offset.fX; 1010 skBounds.offset(offset);
1085 glyph->fTop += offset.fY;
1086 } 1011 }
1012 SkIRect skIBounds;
1013 skBounds.roundOut(&skIBounds);
1014 // Expand the bounds by 1 pixel, to give CG room for anti-aliasing.
1015 // Note that we currently don't know how much room to give subpixel smoothed glyphs
1016 // as CG dilates the outlines by some amount.
1017 skIBounds.outset(1, 1);
1018 glyph->fTop = SkToS16(skIBounds.fTop);
1019 glyph->fLeft = SkToS16(skIBounds.fLeft);
1020 glyph->fWidth = SkToU16(skIBounds.width());
1021 glyph->fHeight = SkToU16(skIBounds.height());
1022
1087 #ifdef HACK_COLORGLYPHS 1023 #ifdef HACK_COLORGLYPHS
1088 glyph->fMaskFormat = SkMask::kARGB32_Format; 1024 glyph->fMaskFormat = SkMask::kARGB32_Format;
1089 #endif 1025 #endif
1090 } 1026 }
1091 1027
1092 #include "SkColorPriv.h" 1028 #include "SkColorPriv.h"
1093 1029
1094 static void build_power_table(uint8_t table[], float ee) { 1030 static void build_power_table(uint8_t table[], float ee) {
1095 for (int i = 0; i < 256; i++) { 1031 for (int i = 0; i < 256; i++) {
1096 float x = i / 255.f; 1032 float x = i / 255.f;
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after
1364 } 1300 }
1365 1301
1366 CGGlyph cgGlyph = (CGGlyph)glyph.getGlyphID(fBaseGlyphCount); 1302 CGGlyph cgGlyph = (CGGlyph)glyph.getGlyphID(fBaseGlyphCount);
1367 AutoCFRelease<CGPathRef> cgPath(CTFontCreatePathForGlyph(font, cgGlyph, NULL )); 1303 AutoCFRelease<CGPathRef> cgPath(CTFontCreatePathForGlyph(font, cgGlyph, NULL ));
1368 1304
1369 path->reset(); 1305 path->reset();
1370 if (cgPath != NULL) { 1306 if (cgPath != NULL) {
1371 CGPathApply(cgPath, path, SkScalerContext_Mac::CTPathElement); 1307 CGPathApply(cgPath, path, SkScalerContext_Mac::CTPathElement);
1372 } 1308 }
1373 1309
1374 if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) { 1310 if (fDoSubPosition) {
1375 SkMatrix m; 1311 SkMatrix m;
1376 m.setScale(SkScalarInvert(scaleX), SkScalarInvert(scaleY)); 1312 m.setScale(SkScalarInvert(scaleX), SkScalarInvert(scaleY));
1377 path->transform(m); 1313 path->transform(m);
1378 // balance the call to CTFontCreateCopyWithAttributes 1314 // balance the call to CTFontCreateCopyWithAttributes
1379 CFSafeRelease(font); 1315 CFSafeRelease(font);
1380 } 1316 }
1381 if (fRec.fFlags & SkScalerContext::kVertical_Flag) { 1317 if (fVertical) {
1382 SkIPoint offset; 1318 SkPoint offset;
1383 getVerticalOffset(cgGlyph, &offset); 1319 getVerticalOffset(cgGlyph, &offset);
1384 path->offset(SkIntToScalar(offset.fX), SkIntToScalar(offset.fY)); 1320 path->offset(offset.fX, offset.fY);
1385 } 1321 }
1386 } 1322 }
1387 1323
1388 void SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* mx, 1324 void SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* mx,
1389 SkPaint::FontMetrics* my) { 1325 SkPaint::FontMetrics* my) {
1390 CGRect theBounds = CTFontGetBoundingBox(fCTFont); 1326 CGRect theBounds = CTFontGetBoundingBox(fCTFont);
1391 1327
1392 SkPaint::FontMetrics theMetrics; 1328 SkPaint::FontMetrics theMetrics;
1393 theMetrics.fTop = CGToScalar(-CGRectGetMaxY_inline(theBounds)); 1329 theMetrics.fTop = CGToScalar(-CGRectGetMaxY_inline(theBounds));
1394 theMetrics.fAscent = CGToScalar(-CTFontGetAscent(fCTFont)); 1330 theMetrics.fAscent = CGToScalar(-CTFontGetAscent(fCTFont));
(...skipping 826 matching lines...) Expand 10 before | Expand all | Expand 10 after
2221 return NULL; 2157 return NULL;
2222 } 2158 }
2223 return create_from_dataProvider(pr); 2159 return create_from_dataProvider(pr);
2224 } 2160 }
2225 }; 2161 };
2226 2162
2227 SkFontMgr* SkFontMgr::Factory() { 2163 SkFontMgr* SkFontMgr::Factory() {
2228 return SkNEW(SkFontMgr_Mac); 2164 return SkNEW(SkFontMgr_Mac);
2229 } 2165 }
2230 #endif 2166 #endif
OLDNEW
« src/core/SkDraw.cpp ('K') | « src/core/SkDraw.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698