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

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: Create initial metrics in CG space. 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
« no previous file with comments | « samplecode/SampleApp.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 233 matching lines...) Expand 10 before | Expand all | Expand 10 after
244 SkDebugf("could not parse uname release %s\n", info.release); 244 SkDebugf("could not parse uname release %s\n", info.release);
245 } 245 }
246 return version; 246 return version;
247 } 247 }
248 248
249 static int darwinVersion() { 249 static int darwinVersion() {
250 static int darwin_version = readVersion(); 250 static int darwin_version = readVersion();
251 return darwin_version; 251 return darwin_version;
252 } 252 }
253 253
254 static bool isLeopard() {
255 return darwinVersion() == 9;
256 }
257
258 static bool isSnowLeopard() { 254 static bool isSnowLeopard() {
259 return darwinVersion() == 10; 255 return darwinVersion() == 10;
260 } 256 }
261 257
262 static bool isLion() { 258 static bool isLion() {
263 return darwinVersion() == 11; 259 return darwinVersion() == 11;
264 } 260 }
265 261
266 static bool isMountainLion() { 262 static bool isMountainLion() {
267 return darwinVersion() == 12; 263 return darwinVersion() == 12;
(...skipping 25 matching lines...) Expand all
293 SkScalar sx = SK_Scalar1, 289 SkScalar sx = SK_Scalar1,
294 SkScalar sy = SK_Scalar1) { 290 SkScalar sy = SK_Scalar1) {
295 return CGAffineTransformMake( ScalarToCG(matrix[SkMatrix::kMScaleX] * sx), 291 return CGAffineTransformMake( ScalarToCG(matrix[SkMatrix::kMScaleX] * sx),
296 -ScalarToCG(matrix[SkMatrix::kMSkewY] * sy), 292 -ScalarToCG(matrix[SkMatrix::kMSkewY] * sy),
297 -ScalarToCG(matrix[SkMatrix::kMSkewX] * sx), 293 -ScalarToCG(matrix[SkMatrix::kMSkewX] * sx),
298 ScalarToCG(matrix[SkMatrix::kMScaleY] * sy), 294 ScalarToCG(matrix[SkMatrix::kMScaleY] * sy),
299 ScalarToCG(matrix[SkMatrix::kMTransX] * sx), 295 ScalarToCG(matrix[SkMatrix::kMTransX] * sx),
300 ScalarToCG(matrix[SkMatrix::kMTransY] * sy)); 296 ScalarToCG(matrix[SkMatrix::kMTransY] * sy));
301 } 297 }
302 298
303 static SkScalar getFontScale(CGFontRef cgFont) {
304 int unitsPerEm = CGFontGetUnitsPerEm(cgFont);
305 return SkScalarInvert(SkIntToScalar(unitsPerEm));
306 }
307
308 /////////////////////////////////////////////////////////////////////////////// 299 ///////////////////////////////////////////////////////////////////////////////
309 300
310 #define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host) 301 #define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host)
311 #define BITMAP_INFO_GRAY (kCGImageAlphaNone) 302 #define BITMAP_INFO_GRAY (kCGImageAlphaNone)
312 303
313 /** 304 /**
314 * There does not appear to be a publicly accessable API for determining if lcd 305 * 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 306 * 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. 307 * smoothing is applied a gamma of 2.0 will be used, if not a gamma of 1.0.
317 */ 308 */
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
523 if (cfFontName != NULL && cfFontTraits != NULL && cfAttributes != NULL && cf Traits != NULL) { 514 if (cfFontName != NULL && cfFontTraits != NULL && cfAttributes != NULL && cf Traits != NULL) {
524 CFDictionaryAddValue(cfTraits, kCTFontSymbolicTrait, cfFontTraits); 515 CFDictionaryAddValue(cfTraits, kCTFontSymbolicTrait, cfFontTraits);
525 516
526 CFDictionaryAddValue(cfAttributes, kCTFontFamilyNameAttribute, cfFontNam e); 517 CFDictionaryAddValue(cfAttributes, kCTFontFamilyNameAttribute, cfFontNam e);
527 CFDictionaryAddValue(cfAttributes, kCTFontTraitsAttribute, cfTraits); 518 CFDictionaryAddValue(cfAttributes, kCTFontTraitsAttribute, cfTraits);
528 519
529 AutoCFRelease<CTFontDescriptorRef> ctFontDesc( 520 AutoCFRelease<CTFontDescriptorRef> ctFontDesc(
530 CTFontDescriptorCreateWithAttributes(cfAttributes)); 521 CTFontDescriptorCreateWithAttributes(cfAttributes));
531 522
532 if (ctFontDesc != NULL) { 523 if (ctFontDesc != NULL) {
533 if (isLeopard()) { 524 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 } 525 }
541 } 526 }
542 527
543 return ctFont ? NewFromFontRef(ctFont, familyName) : NULL; 528 return ctFont ? NewFromFontRef(ctFont, familyName) : NULL;
544 } 529 }
545 530
546 static SkTypeface* GetDefaultFace() { 531 static SkTypeface* GetDefaultFace() {
547 SK_DECLARE_STATIC_MUTEX(gMutex); 532 SK_DECLARE_STATIC_MUTEX(gMutex);
548 SkAutoMutexAcquire ma(gMutex); 533 SkAutoMutexAcquire ma(gMutex);
549 534
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
641 if (face) { 626 if (face) {
642 SkTypefaceCache::Add(face, style); 627 SkTypefaceCache::Add(face, style);
643 } else { 628 } else {
644 face = GetDefaultFace(); 629 face = GetDefaultFace();
645 face->ref(); 630 face->ref();
646 } 631 }
647 } 632 }
648 return face; 633 return face;
649 } 634 }
650 635
651 static void flip(SkMatrix* matrix) {
652 matrix->setSkewX(-matrix->getSkewX());
653 matrix->setSkewY(-matrix->getSkewY());
654 }
655
656 /////////////////////////////////////////////////////////////////////////////// 636 ///////////////////////////////////////////////////////////////////////////////
657 637
638 /** GlyphRect is in upside-down FUnits (em space, y down). */
658 struct GlyphRect { 639 struct GlyphRect {
659 int16_t fMinX; 640 int16_t fMinX;
660 int16_t fMinY; 641 int16_t fMinY;
661 int16_t fMaxX; 642 int16_t fMaxX;
662 int16_t fMaxY; 643 int16_t fMaxY;
663 }; 644 };
664 645
665 class SkScalerContext_Mac : public SkScalerContext { 646 class SkScalerContext_Mac : public SkScalerContext {
666 public: 647 public:
667 SkScalerContext_Mac(SkTypeface_Mac*, const SkDescriptor*); 648 SkScalerContext_Mac(SkTypeface_Mac*, const SkDescriptor*);
668 virtual ~SkScalerContext_Mac(); 649 virtual ~SkScalerContext_Mac() { };
669
670 650
671 protected: 651 protected:
672 unsigned generateGlyphCount(void) SK_OVERRIDE; 652 unsigned generateGlyphCount(void) SK_OVERRIDE;
673 uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE; 653 uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE;
674 void generateAdvance(SkGlyph* glyph) SK_OVERRIDE; 654 void generateAdvance(SkGlyph* glyph) SK_OVERRIDE;
675 void generateMetrics(SkGlyph* glyph) SK_OVERRIDE; 655 void generateMetrics(SkGlyph* glyph) SK_OVERRIDE;
676 void generateImage(const SkGlyph& glyph) SK_OVERRIDE; 656 void generateImage(const SkGlyph& glyph) SK_OVERRIDE;
677 void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE; 657 void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE;
678 void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY) SK_OVERRIDE; 658 void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY) SK_OVERRIDE;
679 659
680 private: 660 private:
681 static void CTPathElement(void *info, const CGPathElement *element); 661 static void CTPathElement(void *info, const CGPathElement *element);
682 uint16_t getFBoundingBoxesGlyphOffset(); 662 uint16_t getFBoundingBoxesGlyphOffset();
683 void getVerticalOffset(CGGlyph glyphID, SkIPoint* offset) const; 663 void getVerticalOffset(CGGlyph glyphID, SkIPoint* offset) const;
684 bool generateBBoxes(); 664 bool generateBBoxes();
685 665
686 CGAffineTransform fTransform; 666 /**
687 SkMatrix fUnitMatrix; // without font size 667 * Converts from FUnits (em space) to SkGlyph units (pixels) without flippi ng y.
688 SkMatrix fVerticalMatrix; // unit rotated 668 *
689 SkMatrix fMatrix; // with font size 669 * Used on SnowLeopard to correct the implementation of CTFontGetVerticalTr anslationsForGlyphs.
690 SkMatrix fFBoundingBoxesMatrix; // lion-specific fix 670 * (Matrix from FUnits (em space, y up) to CG units (pixels, y up).)
671 *
672 * Used on Lion to correct the implementation of CTFontGetBoundingRectsForG lyphs.
673 * (Matrix from upside-down FUnits (em space, y down) to SkGlyph units (pix els, y down).)
674 */
675 SkMatrix fFUnitMatrix;
691 Offscreen fOffscreen; 676 Offscreen fOffscreen;
692 AutoCFRelease<CTFontRef> fCTFont; 677 AutoCFRelease<CTFontRef> fCTFont;
693 AutoCFRelease<CTFontRef> fCTVerticalFont; // for vertical advance 678 AutoCFRelease<CTFontRef> fCTVerticalFont;
694 AutoCFRelease<CGFontRef> fCGFont; 679 AutoCFRelease<CGFontRef> fCGFont;
695 GlyphRect* fFBoundingBoxes; 680 SkAutoTMalloc<GlyphRect> fFBoundingBoxes;
696 uint16_t fFBoundingBoxesGlyphOffset; 681 uint16_t fFBoundingBoxesGlyphOffset;
697 uint16_t fGlyphCount; 682 uint16_t fGlyphCount;
698 bool fGeneratedFBoundingBoxes; 683 bool fGeneratedFBoundingBoxes;
699 bool fDoSubPosition; 684 const bool fDoSubPosition;
700 bool fVertical; 685 const bool fVertical;
701 686
702 friend class Offscreen; 687 friend class Offscreen;
703 688
704 typedef SkScalerContext INHERITED; 689 typedef SkScalerContext INHERITED;
705 }; 690 };
706 691
707 SkScalerContext_Mac::SkScalerContext_Mac(SkTypeface_Mac* typeface, 692 SkScalerContext_Mac::SkScalerContext_Mac(SkTypeface_Mac* typeface,
708 const SkDescriptor* desc) 693 const SkDescriptor* desc)
709 : INHERITED(typeface, desc) 694 : INHERITED(typeface, desc)
710 , fFBoundingBoxes(NULL) 695 , fFBoundingBoxes()
711 , fFBoundingBoxesGlyphOffset(0) 696 , fFBoundingBoxesGlyphOffset(0)
712 , fGeneratedFBoundingBoxes(false) 697 , fGeneratedFBoundingBoxes(false)
698 , fDoSubPosition(SkToBool(fRec.fFlags & kSubpixelPositioning_Flag))
699 , fVertical(SkToBool(fRec.fFlags & kVertical_Flag))
700
713 { 701 {
714 CTFontRef ctFont = typeface->fFontRef.get(); 702 CTFontRef ctFont = typeface->fFontRef.get();
715 CFIndex numGlyphs = CTFontGetGlyphCount(ctFont); 703 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); 704 SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF);
726 705 fGlyphCount = SkToU16(numGlyphs);
727 fTransform = MatrixToCGAffineTransform(fMatrix); 706
728 707 fRec.getSingleMatrix(&fFUnitMatrix);
729 CGAffineTransform transform; 708 CGAffineTransform transform = MatrixToCGAffineTransform(fFUnitMatrix);
730 CGFloat unitFontSize; 709
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; 710 AutoCFRelease<CTFontDescriptorRef> ctFontDesc;
744 if (fVertical) { 711 if (fVertical) {
745 AutoCFRelease<CFMutableDictionaryRef> cfAttributes(CFDictionaryCreateMut able( 712 AutoCFRelease<CFMutableDictionaryRef> cfAttributes(CFDictionaryCreateMut able(
746 kCFAllocatorDefault, 0, 713 kCFAllocatorDefault, 0,
747 &kCFTypeDictionaryKeyCallBacks, 714 &kCFTypeDictionaryKeyCallBacks,
748 &kCFTypeDictionaryValueCallBacks)); 715 &kCFTypeDictionaryValueCallBacks));
749 if (cfAttributes) { 716 if (cfAttributes) {
750 CTFontOrientation ctOrientation = kCTFontVerticalOrientation; 717 CTFontOrientation ctOrientation = kCTFontVerticalOrientation;
751 AutoCFRelease<CFNumberRef> cfVertical(CFNumberCreate( 718 AutoCFRelease<CFNumberRef> cfVertical(CFNumberCreate(
752 kCFAllocatorDefault, kCFNumberSInt32Type, &ctOrientation)); 719 kCFAllocatorDefault, kCFNumberSInt32Type, &ctOrientation));
753 CFDictionaryAddValue(cfAttributes, kCTFontOrientationAttribute, cfVe rtical); 720 CFDictionaryAddValue(cfAttributes, kCTFontOrientationAttribute, cfVe rtical);
754 ctFontDesc = CTFontDescriptorCreateWithAttributes(cfAttributes); 721 ctFontDesc = CTFontDescriptorCreateWithAttributes(cfAttributes);
755 } 722 }
756 } 723 }
757 fCTFont = CTFontCreateCopyWithAttributes(ctFont, unitFontSize, &transform, c tFontDesc); 724 // Since our matrix includes everything, we pass 1 for size.
725 fCTFont = CTFontCreateCopyWithAttributes(ctFont, 1.f, &transform, ctFontDesc );
758 fCGFont = CTFontCopyGraphicsFont(fCTFont, NULL); 726 fCGFont = CTFontCopyGraphicsFont(fCTFont, NULL);
759 if (fVertical) { 727 if (fVertical) {
760 CGAffineTransform rotateLeft = CGAffineTransformMake(0, -1, 1, 0, 0, 0); 728 CGAffineTransform rotateLeft = CGAffineTransformMake(0, -1, 1, 0, 0, 0);
761 transform = CGAffineTransformConcat(rotateLeft, transform); 729 transform = CGAffineTransformConcat(rotateLeft, transform);
762 fCTVerticalFont = CTFontCreateCopyWithAttributes(ctFont, unitFontSize, & transform, NULL); 730 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 } 731 }
772 fGlyphCount = SkToU16(numGlyphs); 732 SkScalar emPerFUnit = SkScalarInvert(SkIntToScalar(CGFontGetUnitsPerEm(fCGFo nt)));
773 fDoSubPosition = SkToBool(fRec.fFlags & kSubpixelPositioning_Flag); 733 fFUnitMatrix.preScale(emPerFUnit, emPerFUnit);
774 }
775
776 SkScalerContext_Mac::~SkScalerContext_Mac() {
777 delete[] fFBoundingBoxes;
778 } 734 }
779 735
780 CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph, 736 CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
781 CGGlyph glyphID, size_t* rowBytesPtr, 737 CGGlyph glyphID, size_t* rowBytesPtr,
782 bool generateA8FromLCD) { 738 bool generateA8FromLCD) {
783 if (!fRGBSpace) { 739 if (!fRGBSpace) {
784 //It doesn't appear to matter what color space is specified. 740 //It doesn't appear to matter what color space is specified.
785 //Regular blends and antialiased text are always (s*a + d*(1-a)) 741 //Regular blends and antialiased text are always (s*a + d*(1-a))
786 //and smoothed text is always g=2.0. 742 //and smoothed text is always g=2.0.
787 fRGBSpace = CGColorSpaceCreateDeviceRGB(); 743 fRGBSpace = CGColorSpaceCreateDeviceRGB();
(...skipping 28 matching lines...) Expand all
816 fCG = CGBitmapContextCreate(image, fSize.fWidth, fSize.fHeight, 8, 772 fCG = CGBitmapContextCreate(image, fSize.fWidth, fSize.fHeight, 8,
817 rowBytes, fRGBSpace, BITMAP_INFO_RGB); 773 rowBytes, fRGBSpace, BITMAP_INFO_RGB);
818 774
819 // skia handles quantization itself, so we disable this for cg to get 775 // skia handles quantization itself, so we disable this for cg to get
820 // full fractional data from them. 776 // full fractional data from them.
821 CGContextSetAllowsFontSubpixelQuantization(fCG, false); 777 CGContextSetAllowsFontSubpixelQuantization(fCG, false);
822 CGContextSetShouldSubpixelQuantizeFonts(fCG, false); 778 CGContextSetShouldSubpixelQuantizeFonts(fCG, false);
823 779
824 CGContextSetTextDrawingMode(fCG, kCGTextFill); 780 CGContextSetTextDrawingMode(fCG, kCGTextFill);
825 CGContextSetFont(fCG, context.fCGFont); 781 CGContextSetFont(fCG, context.fCGFont);
826 CGContextSetFontSize(fCG, 1); 782 CGContextSetFontSize(fCG, 1.0f /*CTFontGetSize(context.fCTFont)*/);
827 CGContextSetTextMatrix(fCG, context.fTransform); 783 CGContextSetTextMatrix(fCG, CTFontGetMatrix(context.fCTFont));
828 784
829 CGContextSetAllowsFontSubpixelPositioning(fCG, context.fDoSubPosition); 785 CGContextSetAllowsFontSubpixelPositioning(fCG, context.fDoSubPosition);
830 CGContextSetShouldSubpixelPositionFonts(fCG, context.fDoSubPosition); 786 CGContextSetShouldSubpixelPositionFonts(fCG, context.fDoSubPosition);
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
841 if (fDoAA != doAA) { 797 if (fDoAA != doAA) {
842 CGContextSetShouldAntialias(fCG, doAA); 798 CGContextSetShouldAntialias(fCG, doAA);
843 fDoAA = doAA; 799 fDoAA = doAA;
844 } 800 }
845 if (fDoLCD != doLCD) { 801 if (fDoLCD != doLCD) {
846 CGContextSetShouldSmoothFonts(fCG, doLCD); 802 CGContextSetShouldSmoothFonts(fCG, doLCD);
847 fDoLCD = doLCD; 803 fDoLCD = doLCD;
848 } 804 }
849 805
850 CGRGBPixel* image = (CGRGBPixel*)fImageStorage.get(); 806 CGRGBPixel* image = (CGRGBPixel*)fImageStorage.get();
851 // skip rows based on the glyph's height 807 // skip rows based on the glyph's height
852 image += (fSize.fHeight - glyph.fHeight) * fSize.fWidth; 808 image += (fSize.fHeight - glyph.fHeight) * fSize.fWidth;
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, 0x00333333, glyph.fWidth, glyph.fHeight, rowBytes);
bungeman-skia 2013/05/10 17:08:03 This is here just to make the bbox visible. Will b
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.
821 // Get the offset from the vertical origin to the horizontal origin.
863 if (context.fVertical) { 822 if (context.fVertical) {
864 SkIPoint offset; 823 SkIPoint offset;
865 context.getVerticalOffset(glyphID, &offset); 824 context.getVerticalOffset(glyphID, &offset);
866 subX += offset.fX; 825 subX += offset.fX;
867 subY += offset.fY; 826 subY += offset.fY;
868 } 827 }
828
869 CGContextShowGlyphsAtPoint(fCG, -glyph.fLeft + subX, 829 CGContextShowGlyphsAtPoint(fCG, -glyph.fLeft + subX,
870 glyph.fTop + glyph.fHeight - subY, 830 glyph.fTop + glyph.fHeight - subY,
871 &glyphID, 1); 831 &glyphID, 1);
872 832
873 SkASSERT(rowBytesPtr); 833 SkASSERT(rowBytesPtr);
874 *rowBytesPtr = rowBytes; 834 *rowBytesPtr = rowBytes;
875 return image; 835 return image;
876 } 836 }
877 837
878 void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkIPoint* offset) c onst { 838 void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkIPoint* offset) c onst {
879 CGSize vertOffset; 839 CGSize cgVertOffset;
880 CTFontGetVerticalTranslationsForGlyphs(fCTVerticalFont, &glyphID, &vertOffse t, 1); 840 CTFontGetVerticalTranslationsForGlyphs(fCTFont, &glyphID, &cgVertOffset, 1);
881 const SkPoint trans = {CGToScalar(vertOffset.width), 841
882 CGToScalar(vertOffset.height)}; 842 // While this is an SkPoint, it is in CG space (y up).
883 SkPoint floatOffset; 843 SkPoint skVertOffset = { CGToScalar(cgVertOffset.width), CGToScalar(cgVertOf fset.height) };
884 fVerticalMatrix.mapPoints(&floatOffset, &trans, 1); 844
885 if (!isSnowLeopard()) { 845 // SnowLeopard returns cgVertOffset in completely un-transformed FUnits (em space, y up).
886 // SnowLeopard fails to apply the font's matrix to the vertical metrics, 846 // Lion and Leopard return cgVertOffset in transformed font units (pixels, y up).
887 // but Lion and Leopard do. The unit matrix describes the font's matrix at 847 if (isSnowLeopard()) {
888 // point size 1. There may be some way to avoid mapping here by setting up 848 // From FUnits (em space, y up) to CG units (pixels, y up).
889 // fVerticalMatrix differently, but this works for now. 849 fFUnitMatrix.mapPoints(&skVertOffset, 1);
890 fUnitMatrix.mapPoints(&floatOffset, 1);
891 } 850 }
892 offset->fX = SkScalarRound(floatOffset.fX); 851
893 offset->fY = SkScalarRound(floatOffset.fY); 852 offset->fX = SkScalarRound(skVertOffset.fX);
853 offset->fY = SkScalarRound(-skVertOffset.fY);
894 } 854 }
895 855
896 uint16_t SkScalerContext_Mac::getFBoundingBoxesGlyphOffset() { 856 uint16_t SkScalerContext_Mac::getFBoundingBoxesGlyphOffset() {
897 if (fFBoundingBoxesGlyphOffset) { 857 if (fFBoundingBoxesGlyphOffset) {
898 return fFBoundingBoxesGlyphOffset; 858 return fFBoundingBoxesGlyphOffset;
899 } 859 }
900 fFBoundingBoxesGlyphOffset = fGlyphCount; // fallback for all fonts 860 fFBoundingBoxesGlyphOffset = fGlyphCount; // fallback for all fonts
901 AutoCGTable<SkOTTableHorizontalHeader> hheaTable(fCGFont); 861 AutoCGTable<SkOTTableHorizontalHeader> hheaTable(fCGFont);
902 if (hheaTable.fData) { 862 if (hheaTable.fData) {
903 fFBoundingBoxesGlyphOffset = SkEndian_SwapBE16(hheaTable->numberOfHMetri cs); 863 fFBoundingBoxesGlyphOffset = SkEndian_SwapBE16(hheaTable->numberOfHMetri cs);
(...skipping 27 matching lines...) Expand all
931 if (!locaTable.fData) { 891 if (!locaTable.fData) {
932 return false; 892 return false;
933 } 893 }
934 894
935 AutoCGTable<SkOTTableGlyph> glyfTable(fCGFont); 895 AutoCGTable<SkOTTableGlyph> glyfTable(fCGFont);
936 if (!glyfTable.fData) { 896 if (!glyfTable.fData) {
937 return false; 897 return false;
938 } 898 }
939 899
940 uint16_t entries = fGlyphCount - fFBoundingBoxesGlyphOffset; 900 uint16_t entries = fGlyphCount - fFBoundingBoxesGlyphOffset;
941 fFBoundingBoxes = new GlyphRect[entries]; 901 fFBoundingBoxes.reset(entries);
942 902
943 SkOTTableHead::IndexToLocFormat locaFormat = headTable->indexToLocFormat; 903 SkOTTableHead::IndexToLocFormat locaFormat = headTable->indexToLocFormat;
944 SkOTTableGlyph::Iterator glyphDataIter(*glyfTable.fData, *locaTable.fData, l ocaFormat); 904 SkOTTableGlyph::Iterator glyphDataIter(*glyfTable.fData, *locaTable.fData, l ocaFormat);
945 glyphDataIter.advance(fFBoundingBoxesGlyphOffset); 905 glyphDataIter.advance(fFBoundingBoxesGlyphOffset);
946 for (uint16_t boundingBoxesIndex = 0; boundingBoxesIndex < entries; ++boundi ngBoxesIndex) { 906 for (uint16_t boundingBoxesIndex = 0; boundingBoxesIndex < entries; ++boundi ngBoxesIndex) {
947 const SkOTTableGlyphData* glyphData = glyphDataIter.next(); 907 const SkOTTableGlyphData* glyphData = glyphDataIter.next();
948 GlyphRect& rect = fFBoundingBoxes[boundingBoxesIndex]; 908 GlyphRect& rect = fFBoundingBoxes[boundingBoxesIndex];
949 rect.fMinX = SkEndian_SwapBE16(glyphData->xMin); 909 rect.fMinX = SkEndian_SwapBE16(glyphData->xMin);
950 rect.fMinY = SkEndian_SwapBE16(glyphData->yMin); 910 rect.fMinY = -SkEndian_SwapBE16(glyphData->yMin);
951 rect.fMaxX = SkEndian_SwapBE16(glyphData->xMax); 911 rect.fMaxX = SkEndian_SwapBE16(glyphData->xMax);
952 rect.fMaxY = SkEndian_SwapBE16(glyphData->yMax); 912 rect.fMaxY = -SkEndian_SwapBE16(glyphData->yMax);
953 } 913 }
954 fFBoundingBoxesMatrix = fMatrix;
955 flip(&fFBoundingBoxesMatrix);
956 SkScalar fontScale = getFontScale(fCGFont);
957 fFBoundingBoxesMatrix.preScale(fontScale, fontScale);
958 return true; 914 return true;
959 } 915 }
960 916
961 unsigned SkScalerContext_Mac::generateGlyphCount(void) { 917 unsigned SkScalerContext_Mac::generateGlyphCount(void) {
962 return fGlyphCount; 918 return fGlyphCount;
963 } 919 }
964 920
965 uint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni) { 921 uint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni) {
966 CGGlyph cgGlyph; 922 CGGlyph cgGlyph;
967 UniChar theChar; 923 UniChar theChar;
(...skipping 10 matching lines...) Expand all
978 } 934 }
979 935
980 return cgGlyph; 936 return cgGlyph;
981 } 937 }
982 938
983 void SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) { 939 void SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) {
984 this->generateMetrics(glyph); 940 this->generateMetrics(glyph);
985 } 941 }
986 942
987 void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) { 943 void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) {
944 const CGGlyph cgGlyph = (CGGlyph) glyph->getGlyphID(fBaseGlyphCount);
945
946 // The following block produces advance and bounds in CG units (pixels, y up ).
988 CGSize advance; 947 CGSize advance;
989 CGRect bounds; 948 CGRect bounds;
990 CGGlyph cgGlyph;
991
992 // Get the state we need
993 cgGlyph = (CGGlyph) glyph->getGlyphID(fBaseGlyphCount);
994
995 if (fVertical) { 949 if (fVertical) {
996 if (!isSnowLeopard()) { 950 if (!isSnowLeopard()) {
997 // Lion and Leopard respect the vertical font metrics. 951 // Lion and Leopard respect the vertical font metrics.
998 CTFontGetBoundingRectsForGlyphs(fCTVerticalFont, kCTFontVerticalOrie ntation, 952 CTFontGetBoundingRectsForGlyphs(fCTVerticalFont, kCTFontVerticalOrie ntation,
999 &cgGlyph, &bounds, 1); 953 &cgGlyph, &bounds, 1);
1000 } else { 954 } else {
1001 // Snow Leopard and earlier respect the vertical font metrics for 955 // 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. 956 // advances, but not bounds, so use the default box and adjust it be low.
1003 CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontDefaultOrientation, 957 CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontHorizontalOrientatio n,
1004 &cgGlyph, &bounds, 1); 958 &cgGlyph, &bounds, 1);
1005 } 959 }
1006 CTFontGetAdvancesForGlyphs(fCTVerticalFont, kCTFontVerticalOrientation, 960 CTFontGetAdvancesForGlyphs(fCTVerticalFont, kCTFontVerticalOrientation,
1007 &cgGlyph, &advance, 1); 961 &cgGlyph, &advance, 1);
1008 } else { 962 } else {
1009 CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontDefaultOrientation, 963 CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontHorizontalOrientation,
1010 &cgGlyph, &bounds, 1); 964 &cgGlyph, &bounds, 1);
1011 CTFontGetAdvancesForGlyphs(fCTFont, kCTFontDefaultOrientation, 965 CTFontGetAdvancesForGlyphs(fCTFont, kCTFontHorizontalOrientation,
1012 &cgGlyph, &advance, 1); 966 &cgGlyph, &advance, 1);
1013 } 967 }
968 // Convert advance and bounds to SkGlyph units (pixels, y down).
969 bounds.origin.y = -bounds.origin.y - bounds.size.height;
970 advance.height = -advance.height;
1014 971
1015 // BUG? 972 // BUG?
1016 // 0x200B (zero-advance space) seems to return a huge (garbage) bounds, when 973 // 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 974 // 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 975 // 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. 976 // is rare, so we won't incur a big performance cost for this extra check.
1020 if (0 == advance.width && 0 == advance.height) { 977 if (0 == advance.width && 0 == advance.height) {
1021 AutoCFRelease<CGPathRef> path(CTFontCreatePathForGlyph(fCTFont, cgGlyph, NULL)); 978 AutoCFRelease<CGPathRef> path(CTFontCreatePathForGlyph(fCTFont, cgGlyph, NULL));
1022 if (NULL == path || CGPathIsEmpty(path)) { 979 if (NULL == path || CGPathIsEmpty(path)) {
1023 bounds = CGRectMake(0, 0, 0, 0); 980 bounds = CGRectMake(0, 0, 0, 0);
1024 } 981 }
1025 } 982 }
1026 983
1027 glyph->zeroMetrics(); 984 glyph->zeroMetrics();
1028 glyph->fAdvanceX = SkFloatToFixed_Check(advance.width); 985 glyph->fAdvanceX = SkFloatToFixed_Check(advance.width);
1029 glyph->fAdvanceY = -SkFloatToFixed_Check(advance.height); 986 glyph->fAdvanceY = SkFloatToFixed_Check(advance.height);
1030 987
1031 if (CGRectIsEmpty_inline(bounds)) { 988 if (CGRectIsEmpty_inline(bounds)) {
1032 return; 989 return;
1033 } 990 }
1034 991
1035 if (isLeopard() && !fVertical) { 992 // Expand the bounds by 1 pixel, to give CG room for anti-aliasing.
1036 // Leopard does not consider the matrix skew in its bounds.
1037 // Run the bounding rectangle through the skew matrix to determine
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); 993 CGRectInset_inline(&bounds, -1, -1);
1057 994
1058 // Get the metrics 995 // Get the metrics
1059 bool lionAdjustedMetrics = false; 996 bool lionAdjustedMetrics = false;
1060 if (isLion() || isMountainLion()) { 997 if (isLion() || isMountainLion()) {
1061 if (cgGlyph < fGlyphCount && cgGlyph >= getFBoundingBoxesGlyphOffset() & & generateBBoxes()){ 998 if (cgGlyph < fGlyphCount && cgGlyph >= getFBoundingBoxesGlyphOffset() & & generateBBoxes()){
1062 lionAdjustedMetrics = true; 999 lionAdjustedMetrics = true;
1063 SkRect adjust;
1064 const GlyphRect& gRect = fFBoundingBoxes[cgGlyph - fFBoundingBoxesGl yphOffset]; 1000 const GlyphRect& gRect = fFBoundingBoxes[cgGlyph - fFBoundingBoxesGl yphOffset];
1065 adjust.set(gRect.fMinX, gRect.fMinY, gRect.fMaxX, gRect.fMaxY); 1001 SkRect adjust = SkRect::MakeLTRB(gRect.fMinX, gRect.fMinY, gRect.fMa xX, gRect.fMaxY);
1066 fFBoundingBoxesMatrix.mapRect(&adjust); 1002 // From upside-down FUnits (em space, y down) to SkGlyph units (pixe ls, y down).
1003 fFUnitMatrix.mapRect(&adjust);
1067 bounds.origin.x = SkScalarToFloat(adjust.fLeft) - 1; 1004 bounds.origin.x = SkScalarToFloat(adjust.fLeft) - 1;
1068 bounds.origin.y = SkScalarToFloat(adjust.fTop) - 1; 1005 bounds.origin.y = SkScalarToFloat(adjust.fTop) - 1;
1069 } 1006 }
1070 // Lion returns fractions in the bounds 1007 // Lion returns fractions in the bounds
1071 glyph->fWidth = SkToU16(sk_float_ceil2int(bounds.size.width)); 1008 glyph->fWidth = SkToU16(sk_float_ceil2int(bounds.size.width));
1072 glyph->fHeight = SkToU16(sk_float_ceil2int(bounds.size.height)); 1009 glyph->fHeight = SkToU16(sk_float_ceil2int(bounds.size.height));
1073 } else { 1010 } else {
1074 glyph->fWidth = SkToU16(sk_float_round2int(bounds.size.width)); 1011 glyph->fWidth = SkToU16(sk_float_round2int(bounds.size.width));
1075 glyph->fHeight = SkToU16(sk_float_round2int(bounds.size.height)); 1012 glyph->fHeight = SkToU16(sk_float_round2int(bounds.size.height));
1076 } 1013 }
1077 glyph->fTop = SkToS16(-sk_float_round2int(CGRectGetMaxY_inline(bounds))); 1014 glyph->fTop = SkToS16(sk_float_round2int(bounds.origin.y));
1078 glyph->fLeft = SkToS16(sk_float_round2int(CGRectGetMinX_inline(bounds))); 1015 glyph->fLeft = SkToS16(sk_float_round2int(bounds.origin.x));
1079 SkIPoint offset;
1080 if (fVertical && (isSnowLeopard() || lionAdjustedMetrics)) { 1016 if (fVertical && (isSnowLeopard() || lionAdjustedMetrics)) {
1081 // SnowLeopard doesn't respect vertical metrics, so compute them manuall y. 1017 // SnowLeopard doesn't respect vertical metrics, so compute them manuall y.
1082 // Also compute them for Lion when the metrics were computed by hand. 1018 // Also compute them for Lion when the metrics were computed by hand.
1019 SkIPoint offset;
1083 getVerticalOffset(cgGlyph, &offset); 1020 getVerticalOffset(cgGlyph, &offset);
1084 glyph->fLeft += offset.fX; 1021 glyph->fLeft += offset.fX;
1085 glyph->fTop += offset.fY; 1022 glyph->fTop += offset.fY;
1086 } 1023 }
1087 #ifdef HACK_COLORGLYPHS 1024 #ifdef HACK_COLORGLYPHS
1088 glyph->fMaskFormat = SkMask::kARGB32_Format; 1025 glyph->fMaskFormat = SkMask::kARGB32_Format;
1089 #endif 1026 #endif
1090 } 1027 }
1091 1028
1092 #include "SkColorPriv.h" 1029 #include "SkColorPriv.h"
(...skipping 1128 matching lines...) Expand 10 before | Expand all | Expand 10 after
2221 return NULL; 2158 return NULL;
2222 } 2159 }
2223 return create_from_dataProvider(pr); 2160 return create_from_dataProvider(pr);
2224 } 2161 }
2225 }; 2162 };
2226 2163
2227 SkFontMgr* SkFontMgr::Factory() { 2164 SkFontMgr* SkFontMgr::Factory() {
2228 return SkNEW(SkFontMgr_Mac); 2165 return SkNEW(SkFontMgr_Mac);
2229 } 2166 }
2230 #endif 2167 #endif
OLDNEW
« no previous file with comments | « samplecode/SampleApp.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698