Skip to content

Instantly share code, notes, and snippets.

@jjgod
Created March 5, 2015 11:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jjgod/5bfd62a6509db5154b7c to your computer and use it in GitHub Desktop.
Save jjgod/5bfd62a6509db5154b7c to your computer and use it in GitHub Desktop.
From 3b4b66c04a2567c72754a55e53db41394249b223 Mon Sep 17 00:00:00 2001
From: bungeman <bungeman@google.com>
Date: Thu, 8 Jan 2015 08:33:44 -0800
Subject: [PATCH] Work around changes in OSX 10.10.
In 10.10.1 CTFontGetAdvancesForGlyphs applies the font
transform to the width of the advance but always sets the
height of the advance to 0. Work around this by measuring the
advance with an unrotated font and apply the transform
manually.
In 10.7 through 10.9 CTFontDrawGlyphs appears to take
'positions' in text space and acts like
CGContextShowGlyphsAtPosition. In 10.10.1, these 'positions' now appear to be in glyph space, and
CTFontDrawGlyphs maps the glyph positions internally.
BUG=chromium:442574
Review URL: https://codereview.chromium.org/841843002
---
src/ports/SkFontHost_mac.cpp | 55 +++++++++++++++++++++++++++++++-------------
1 file changed, 39 insertions(+), 16 deletions(-)
diff --git a/src/ports/SkFontHost_mac.cpp b/src/ports/SkFontHost_mac.cpp
index 0d4bbb7..8d3a6fa 100755
--- a/src/ports/SkFontHost_mac.cpp
+++ b/src/ports/SkFontHost_mac.cpp
@@ -46,6 +46,9 @@
#include <dlfcn.h>
+// Set to make glyph bounding boxes visible.
+#define SK_SHOW_TEXT_BLIT_COVERAGE 0
+
class SkScalerContext_Mac;
// CTFontManagerCopyAvailableFontFamilyNames() is not always available, so we
@@ -681,14 +684,18 @@ private:
AutoCFRelease<CTFontRef> fCTFont;
CGAffineTransform fInvTransform;
- /** Vertical variant of fCTFont.
+ /** Unrotated variant of fCTFont.
+ *
+ * In 10.10.1 CTFontGetAdvancesForGlyphs applies the font transform to the width of the
+ * advances, but always sets the height to 0. This font is used to get the advances of the
+ * unrotated glyph, and then the rotation is applied separately.
*
* CT vertical metrics are pre-rotated (in em space, before transform) 90deg clock-wise.
* This makes kCTFontDefaultOrientation dangerous, because the metrics from
* kCTFontHorizontalOrientation are in a different space from kCTFontVerticalOrientation.
- * Use fCTVerticalFont with kCTFontVerticalOrientation to get metrics in the same space.
+ * With kCTFontVerticalOrientation the advances must be unrotated.
*/
- AutoCFRelease<CTFontRef> fCTVerticalFont;
+ AutoCFRelease<CTFontRef> fCTUnrotatedFont;
AutoCFRelease<CGFontRef> fCGFont;
SkAutoTMalloc<GlyphRect> fFBoundingBoxes;
@@ -729,6 +736,7 @@ SkScalerContext_Mac::SkScalerContext_Mac(SkTypeface_Mac* typeface,
AutoCFRelease<CTFontDescriptorRef> ctFontDesc;
if (fVertical) {
+ // Setting the vertical orientation here affects the character to glyph mapping.
AutoCFRelease<CFMutableDictionaryRef> cfAttributes(CFDictionaryCreateMutable(
kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
@@ -748,11 +756,8 @@ SkScalerContext_Mac::SkScalerContext_Mac(SkTypeface_Mac* typeface,
fCTFont.reset(CTFontCreateCopyWithAttributes(ctFont, textSize, &transform, ctFontDesc));
fCGFont.reset(CTFontCopyGraphicsFont(fCTFont, NULL));
- if (fVertical) {
- CGAffineTransform rotateLeft = CGAffineTransformMake(0, -1, 1, 0, 0, 0);
- transform = CGAffineTransformConcat(rotateLeft, transform);
- fCTVerticalFont.reset(CTFontCreateCopyWithAttributes(ctFont, textSize, &transform, NULL));
- }
+ fCTUnrotatedFont.reset(CTFontCreateCopyWithAttributes(ctFont, textSize,
+ &CGAffineTransformIdentity, NULL));
// The fUnitMatrix includes the text size (and em) as it is used to scale the raw font data.
SkScalar emPerFUnit = SkScalarInvert(SkIntToScalar(CGFontGetUnitsPerEm(fCGFont)));
@@ -896,11 +901,14 @@ CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph&
subY += offset.fY;
}
- // CTFontDrawGlyphs and CGContextShowGlyphsAtPositions take 'positions' which are in text space.
- // The glyph location (in device space) must be mapped into text space, so that CG can convert
- // it back into device space.
CGPoint point = CGPointMake(-glyph.fLeft + subX, glyph.fTop + glyph.fHeight - subY);
- point = CGPointApplyAffineTransform(point, context.fInvTransform);
+ if (darwinVersion() < 14) {
+ // Prior to 10.10, CTFontDrawGlyphs acted like CGContextShowGlyphsAtPositions and took
+ // 'positions' which are in text space. The glyph location (in device space) must be
+ // mapped into text space, so that CG can convert it back into device space.
+ // In 10.10 and later, this is handled directly in CTFontDrawGlyphs.
+ point = CGPointApplyAffineTransform(point, context.fInvTransform);
+ }
ctFontDrawGlyphs(context.fCTFont, &glyphID, &point, 1, fCG);
SkASSERT(rowBytesPtr);
@@ -1007,12 +1015,16 @@ void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) {
// The following block produces cgAdvance in CG units (pixels, y up).
CGSize cgAdvance;
if (fVertical) {
- CTFontGetAdvancesForGlyphs(fCTVerticalFont, kCTFontVerticalOrientation,
+ CTFontGetAdvancesForGlyphs(fCTUnrotatedFont, kCTFontVerticalOrientation,
&cgGlyph, &cgAdvance, 1);
+ // Vertical advances are returned as widths instead of heights.
+ SkTSwap(cgAdvance.height, cgAdvance.width);
+ cgAdvance.height = -cgAdvance.height;
} else {
- CTFontGetAdvancesForGlyphs(fCTFont, kCTFontHorizontalOrientation,
+ CTFontGetAdvancesForGlyphs(fCTUnrotatedFont, kCTFontHorizontalOrientation,
&cgGlyph, &cgAdvance, 1);
}
+ cgAdvance = CGSizeApplyAffineTransform(cgAdvance, CTFontGetMatrix(fCTFont));
glyph->fAdvanceX = SkFloatToFixed_Check(cgAdvance.width);
glyph->fAdvanceY = -SkFloatToFixed_Check(cgAdvance.height);
@@ -1153,7 +1165,11 @@ static inline uint8_t rgb_to_a8(CGRGBPixel rgb, const uint8_t* table8) {
U8CPU r = (rgb >> 16) & 0xFF;
U8CPU g = (rgb >> 8) & 0xFF;
U8CPU b = (rgb >> 0) & 0xFF;
- return sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8);
+ U8CPU lum = sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8);
+#if SK_SHOW_TEXT_BLIT_COVERAGE
+ lum = SkTMax(lum, (U8CPU)0x30);
+#endif
+ return lum;
}
template<bool APPLY_PREBLEND>
static void rgb_to_a8(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes,
@@ -1178,6 +1194,11 @@ static inline uint16_t rgb_to_lcd16(CGRGBPixel rgb, const uint8_t* tableR,
U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG);
U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB);
+#if SK_SHOW_TEXT_BLIT_COVERAGE
+ r = SkTMax(r, (U8CPU)0x30);
+ g = SkTMax(g, (U8CPU)0x30);
+ b = SkTMax(b, (U8CPU)0x30);
+#endif
return SkPack888ToRGB16(r, g, b);
}
template<bool APPLY_PREBLEND>
@@ -1201,7 +1222,9 @@ static SkPMColor cgpixels_to_pmcolor(CGRGBPixel rgb) {
U8CPU r = (rgb >> 16) & 0xFF;
U8CPU g = (rgb >> 8) & 0xFF;
U8CPU b = (rgb >> 0) & 0xFF;
-
+#if SK_SHOW_TEXT_BLIT_COVERAGE
+ a = SkTMax(a, (U8CPU)0x30);
+#endif
return SkPackARGB32(a, r, g, b);
}
--
2.3.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment