3 * Copyright 2006 The Android Open Source Project
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
10 #ifdef SK_BUILD_FOR_MAC
11 #import <ApplicationServices/ApplicationServices.h>
14 #ifdef SK_BUILD_FOR_IOS
15 #include <CoreText/CoreText.h>
16 #include <CoreText/CTFontManager.h>
17 #include <CoreGraphics/CoreGraphics.h>
18 #include <CoreFoundation/CoreFoundation.h>
21 #include "SkFontHost.h"
22 #include "SkCGUtils.h"
23 #include "SkColorPriv.h"
24 #include "SkDescriptor.h"
26 #include "SkFontDescriptor.h"
27 #include "SkFloatingPoint.h"
29 #include "SkMaskGamma.h"
30 #include "SkSFNTHeader.h"
31 #include "SkOTTable_glyf.h"
32 #include "SkOTTable_head.h"
33 #include "SkOTTable_hhea.h"
34 #include "SkOTTable_loca.h"
35 #include "SkOTUtils.h"
41 #include "SkTypeface_mac.h"
43 #include "SkTypefaceCache.h"
44 #include "SkFontMgr.h"
47 //#define HACK_COLORGLYPHS
49 class SkScalerContext_Mac;
51 // CTFontManagerCopyAvailableFontFamilyNames() is not always available, so we
52 // provide a wrapper here that will return an empty array if need be.
53 static CFArrayRef SkCTFontManagerCopyAvailableFontFamilyNames() {
54 #ifdef SK_BUILD_FOR_IOS
55 return CFArrayCreate(NULL, NULL, 0, NULL);
57 return CTFontManagerCopyAvailableFontFamilyNames();
62 // Being templated and taking const T* prevents calling
63 // CFSafeRelease(autoCFRelease) through implicit conversion.
64 template <typename T> static void CFSafeRelease(/*CFTypeRef*/const T* cfTypeRef) {
70 // Being templated and taking const T* prevents calling
71 // CFSafeRetain(autoCFRelease) through implicit conversion.
72 template <typename T> static void CFSafeRetain(/*CFTypeRef*/const T* cfTypeRef) {
78 /** Acts like a CFRef, but calls CFSafeRelease when it goes out of scope. */
79 template<typename CFRef> class AutoCFRelease : private SkNoncopyable {
81 explicit AutoCFRelease(CFRef cfRef = NULL) : fCFRef(cfRef) { }
82 ~AutoCFRelease() { CFSafeRelease(fCFRef); }
84 void reset(CFRef that = NULL) {
86 CFSafeRelease(fCFRef);
91 operator CFRef() const { return fCFRef; }
92 CFRef get() const { return fCFRef; }
94 CFRef* operator&() { SkASSERT(fCFRef == NULL); return &fCFRef; }
99 static CFStringRef make_CFString(const char str[]) {
100 return CFStringCreateWithCString(NULL, str, kCFStringEncodingUTF8);
103 template<typename T> class AutoCGTable : SkNoncopyable {
105 AutoCGTable(CGFontRef font)
106 //Undocumented: the tag parameter in this call is expected in machine order and not BE order.
107 : fCFData(CGFontCopyTableForTag(font, SkSetFourByteTag(T::TAG0, T::TAG1, T::TAG2, T::TAG3)))
108 , fData(fCFData ? reinterpret_cast<const T*>(CFDataGetBytePtr(fCFData)) : NULL)
111 const T* operator->() const { return fData; }
114 AutoCFRelease<CFDataRef> fCFData;
119 // inline versions of these rect helpers
121 static bool CGRectIsEmpty_inline(const CGRect& rect) {
122 return rect.size.width <= 0 || rect.size.height <= 0;
125 static CGFloat CGRectGetMinX_inline(const CGRect& rect) {
126 return rect.origin.x;
129 static CGFloat CGRectGetMaxX_inline(const CGRect& rect) {
130 return rect.origin.x + rect.size.width;
133 static CGFloat CGRectGetMinY_inline(const CGRect& rect) {
134 return rect.origin.y;
137 static CGFloat CGRectGetMaxY_inline(const CGRect& rect) {
138 return rect.origin.y + rect.size.height;
141 static CGFloat CGRectGetWidth_inline(const CGRect& rect) {
142 return rect.size.width;
145 ///////////////////////////////////////////////////////////////////////////////
147 static void sk_memset_rect32(uint32_t* ptr, uint32_t value,
148 int width, int height, size_t rowBytes) {
150 SkASSERT(width * sizeof(uint32_t) <= rowBytes);
154 sk_memset32(ptr, value, width);
155 ptr = (uint32_t*)((char*)ptr + rowBytes);
161 rowBytes -= width * sizeof(uint32_t);
167 *ptr++ = value; *ptr++ = value;
168 *ptr++ = value; *ptr++ = value;
169 *ptr++ = value; *ptr++ = value;
170 *ptr++ = value; *ptr++ = value;
176 ptr = (uint32_t*)((char*)ptr + rowBytes);
185 ptr = (uint32_t*)((char*)ptr + rowBytes);
191 #include <sys/utsname.h>
193 typedef uint32_t CGRGBPixel;
195 static unsigned CGRGBPixel_getAlpha(CGRGBPixel pixel) {
199 // The calls to support subpixel are present in 10.5, but are not included in
200 // the 10.5 SDK. The needed calls have been extracted from the 10.6 SDK and are
201 // included below. To verify that CGContextSetShouldSubpixelQuantizeFonts, for
202 // instance, is present in the 10.5 CoreGraphics libary, use:
203 // cd /Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/
204 // cd ApplicationServices.framework/Frameworks/CoreGraphics.framework/
205 // nm CoreGraphics | grep CGContextSetShouldSubpixelQuantizeFonts
207 #if !defined(MAC_OS_X_VERSION_10_6) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6)
208 CG_EXTERN void CGContextSetAllowsFontSmoothing(CGContextRef context, bool value);
209 CG_EXTERN void CGContextSetAllowsFontSubpixelPositioning(CGContextRef context, bool value);
210 CG_EXTERN void CGContextSetShouldSubpixelPositionFonts(CGContextRef context, bool value);
211 CG_EXTERN void CGContextSetAllowsFontSubpixelQuantization(CGContextRef context, bool value);
212 CG_EXTERN void CGContextSetShouldSubpixelQuantizeFonts(CGContextRef context, bool value);
215 static const char FONT_DEFAULT_NAME[] = "Lucida Sans";
217 // See Source/WebKit/chromium/base/mac/mac_util.mm DarwinMajorVersionInternal for original source.
218 static int readVersion() {
220 if (uname(&info) != 0) {
221 SkDebugf("uname failed\n");
224 if (strcmp(info.sysname, "Darwin") != 0) {
225 SkDebugf("unexpected uname sysname %s\n", info.sysname);
228 char* dot = strchr(info.release, '.');
230 SkDebugf("expected dot in uname release %s\n", info.release);
233 int version = atoi(info.release);
235 SkDebugf("could not parse uname release %s\n", info.release);
240 static int darwinVersion() {
241 static int darwin_version = readVersion();
242 return darwin_version;
245 static bool isSnowLeopard() {
246 return darwinVersion() == 10;
249 static bool isLion() {
250 return darwinVersion() == 11;
253 static bool isMountainLion() {
254 return darwinVersion() == 12;
257 static bool isLCDFormat(unsigned format) {
258 return SkMask::kLCD16_Format == format || SkMask::kLCD32_Format == format;
261 static CGFloat ScalarToCG(SkScalar scalar) {
262 if (sizeof(CGFloat) == sizeof(float)) {
263 return SkScalarToFloat(scalar);
265 SkASSERT(sizeof(CGFloat) == sizeof(double));
266 return (CGFloat) SkScalarToDouble(scalar);
270 static SkScalar CGToScalar(CGFloat cgFloat) {
271 if (sizeof(CGFloat) == sizeof(float)) {
274 SkASSERT(sizeof(CGFloat) == sizeof(double));
275 return SkDoubleToScalar(cgFloat);
279 static CGAffineTransform MatrixToCGAffineTransform(const SkMatrix& matrix,
280 SkScalar sx = SK_Scalar1,
281 SkScalar sy = SK_Scalar1) {
282 return CGAffineTransformMake( ScalarToCG(matrix[SkMatrix::kMScaleX] * sx),
283 -ScalarToCG(matrix[SkMatrix::kMSkewY] * sy),
284 -ScalarToCG(matrix[SkMatrix::kMSkewX] * sx),
285 ScalarToCG(matrix[SkMatrix::kMScaleY] * sy),
286 ScalarToCG(matrix[SkMatrix::kMTransX] * sx),
287 ScalarToCG(matrix[SkMatrix::kMTransY] * sy));
290 ///////////////////////////////////////////////////////////////////////////////
292 #define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host)
293 #define BITMAP_INFO_GRAY (kCGImageAlphaNone)
296 * There does not appear to be a publicly accessable API for determining if lcd
297 * font smoothing will be applied if we request it. The main issue is that if
298 * smoothing is applied a gamma of 2.0 will be used, if not a gamma of 1.0.
300 static bool supports_LCD() {
301 static int gSupportsLCD = -1;
302 if (gSupportsLCD >= 0) {
303 return (bool) gSupportsLCD;
306 AutoCFRelease<CGColorSpaceRef> colorspace(CGColorSpaceCreateDeviceRGB());
307 AutoCFRelease<CGContextRef> cgContext(CGBitmapContextCreate(&rgb, 1, 1, 8, 4,
308 colorspace, BITMAP_INFO_RGB));
309 CGContextSelectFont(cgContext, "Helvetica", 16, kCGEncodingMacRoman);
310 CGContextSetShouldSmoothFonts(cgContext, true);
311 CGContextSetShouldAntialias(cgContext, true);
312 CGContextSetTextDrawingMode(cgContext, kCGTextFill);
313 CGContextSetGrayFillColor(cgContext, 1, 1);
314 CGContextShowTextAtPoint(cgContext, -1, 0, "|", 1);
315 uint32_t r = (rgb >> 16) & 0xFF;
316 uint32_t g = (rgb >> 8) & 0xFF;
317 uint32_t b = (rgb >> 0) & 0xFF;
318 gSupportsLCD = (r != g || r != b);
319 return (bool) gSupportsLCD;
326 CGRGBPixel* getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
327 CGGlyph glyphID, size_t* rowBytesPtr,
328 bool generateA8FromLCD);
332 kSize = 32 * 32 * sizeof(CGRGBPixel)
334 SkAutoSMalloc<kSize> fImageStorage;
335 AutoCFRelease<CGColorSpaceRef> fRGBSpace;
338 AutoCFRelease<CGContextRef> fCG;
343 static int RoundSize(int dimension) {
344 return SkNextPow2(dimension);
348 Offscreen::Offscreen() : fRGBSpace(NULL), fCG(NULL),
349 fDoAA(false), fDoLCD(false) {
353 ///////////////////////////////////////////////////////////////////////////////
355 static SkTypeface::Style computeStyleBits(CTFontRef font, bool* isFixedPitch) {
356 unsigned style = SkTypeface::kNormal;
357 CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(font);
359 if (traits & kCTFontBoldTrait) {
360 style |= SkTypeface::kBold;
362 if (traits & kCTFontItalicTrait) {
363 style |= SkTypeface::kItalic;
366 *isFixedPitch = (traits & kCTFontMonoSpaceTrait) != 0;
368 return (SkTypeface::Style)style;
371 static SkFontID CTFontRef_to_SkFontID(CTFontRef fontRef) {
373 // CTFontGetPlatformFont and ATSFontRef are not supported on iOS, so we have to
374 // bracket this to be Mac only.
375 #ifdef SK_BUILD_FOR_MAC
376 ATSFontRef ats = CTFontGetPlatformFont(fontRef, NULL);
379 id &= 0x3FFFFFFF; // make top two bits 00
383 // CTFontGetPlatformFont returns NULL if the font is local
384 // (e.g., was created by a CSS3 @font-face rule).
385 AutoCFRelease<CGFontRef> cgFont(CTFontCopyGraphicsFont(fontRef, NULL));
386 AutoCGTable<SkOTTableHead> headTable(cgFont);
387 if (headTable.fData) {
388 id = (SkFontID) headTable->checksumAdjustment;
389 id = (id & 0x3FFFFFFF) | 0x40000000; // make top two bits 01
391 // well-formed fonts have checksums, but as a last resort, use the pointer.
393 id = (SkFontID) (uintptr_t) fontRef;
394 id = (id & 0x3FFFFFFF) | 0x80000000; // make top two bits 10
399 static SkFontStyle stylebits2fontstyle(SkTypeface::Style styleBits) {
400 return SkFontStyle((styleBits & SkTypeface::kBold)
401 ? SkFontStyle::kBold_Weight
402 : SkFontStyle::kNormal_Weight,
403 SkFontStyle::kNormal_Width,
404 (styleBits & SkTypeface::kItalic)
405 ? SkFontStyle::kItalic_Slant
406 : SkFontStyle::kUpright_Slant);
409 #define WEIGHT_THRESHOLD ((SkFontStyle::kNormal_Weight + SkFontStyle::kBold_Weight)/2)
411 static SkTypeface::Style fontstyle2stylebits(const SkFontStyle& fs) {
413 if (fs.width() >= WEIGHT_THRESHOLD) {
414 style |= SkTypeface::kBold;
417 style |= SkTypeface::kItalic;
419 return (SkTypeface::Style)style;
422 class SkTypeface_Mac : public SkTypeface {
424 SkTypeface_Mac(SkTypeface::Style style, SkFontID fontID, bool isFixedPitch,
425 CTFontRef fontRef, const char name[], bool isLocalStream)
426 : SkTypeface(style, fontID, isFixedPitch)
428 , fFontRef(fontRef) // caller has already called CFRetain for us
429 , fFontStyle(stylebits2fontstyle(style))
430 , fIsLocalStream(isLocalStream)
435 SkTypeface_Mac(const SkFontStyle& fs, SkFontID fontID, bool isFixedPitch,
436 CTFontRef fontRef, const char name[], bool isLocalStream)
437 : SkTypeface(fontstyle2stylebits(fs), fontID, isFixedPitch)
439 , fFontRef(fontRef) // caller has already called CFRetain for us
441 , fIsLocalStream(isLocalStream)
447 AutoCFRelease<CTFontRef> fFontRef;
448 SkFontStyle fFontStyle;
451 friend class SkFontHost; // to access our protected members for deprecated methods
453 virtual int onGetUPEM() const SK_OVERRIDE;
454 virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE;
455 virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const SK_OVERRIDE;
456 virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE;
457 virtual size_t onGetTableData(SkFontTableTag, size_t offset,
458 size_t length, void* data) const SK_OVERRIDE;
459 virtual SkScalerContext* onCreateScalerContext(const SkDescriptor*) const SK_OVERRIDE;
460 virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE;
461 virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE;
462 virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics(
463 SkAdvancedTypefaceMetrics::PerGlyphInfo,
464 const uint32_t*, uint32_t) const SK_OVERRIDE;
465 virtual int onCharsToGlyphs(const void* chars, Encoding, uint16_t glyphs[],
466 int glyphCount) const SK_OVERRIDE;
467 virtual int onCountGlyphs() const SK_OVERRIDE;
472 typedef SkTypeface INHERITED;
475 static SkTypeface* NewFromFontRef(CTFontRef fontRef, const char name[], bool isLocalStream) {
478 SkTypeface::Style style = computeStyleBits(fontRef, &isFixedPitch);
479 SkFontID fontID = CTFontRef_to_SkFontID(fontRef);
481 return new SkTypeface_Mac(style, fontID, isFixedPitch, fontRef, name, isLocalStream);
484 static SkTypeface* NewFromName(const char familyName[], SkTypeface::Style theStyle) {
485 CTFontRef ctFont = NULL;
487 CTFontSymbolicTraits ctFontTraits = 0;
488 if (theStyle & SkTypeface::kBold) {
489 ctFontTraits |= kCTFontBoldTrait;
491 if (theStyle & SkTypeface::kItalic) {
492 ctFontTraits |= kCTFontItalicTrait;
495 // Create the font info
496 AutoCFRelease<CFStringRef> cfFontName(make_CFString(familyName));
498 AutoCFRelease<CFNumberRef> cfFontTraits(
499 CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &ctFontTraits));
501 AutoCFRelease<CFMutableDictionaryRef> cfAttributes(
502 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
503 &kCFTypeDictionaryKeyCallBacks,
504 &kCFTypeDictionaryValueCallBacks));
506 AutoCFRelease<CFMutableDictionaryRef> cfTraits(
507 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
508 &kCFTypeDictionaryKeyCallBacks,
509 &kCFTypeDictionaryValueCallBacks));
512 if (cfFontName != NULL && cfFontTraits != NULL && cfAttributes != NULL && cfTraits != NULL) {
513 CFDictionaryAddValue(cfTraits, kCTFontSymbolicTrait, cfFontTraits);
515 CFDictionaryAddValue(cfAttributes, kCTFontFamilyNameAttribute, cfFontName);
516 CFDictionaryAddValue(cfAttributes, kCTFontTraitsAttribute, cfTraits);
518 AutoCFRelease<CTFontDescriptorRef> ctFontDesc(
519 CTFontDescriptorCreateWithAttributes(cfAttributes));
521 if (ctFontDesc != NULL) {
522 ctFont = CTFontCreateWithFontDescriptor(ctFontDesc, 0, NULL);
526 return ctFont ? NewFromFontRef(ctFont, familyName, false) : NULL;
529 SK_DECLARE_STATIC_MUTEX(gGetDefaultFaceMutex);
530 static SkTypeface* GetDefaultFace() {
531 SkAutoMutexAcquire ma(gGetDefaultFaceMutex);
533 static SkTypeface* gDefaultFace;
535 if (NULL == gDefaultFace) {
536 gDefaultFace = NewFromName(FONT_DEFAULT_NAME, SkTypeface::kNormal);
537 SkTypefaceCache::Add(gDefaultFace, SkTypeface::kNormal);
542 ///////////////////////////////////////////////////////////////////////////////
544 extern CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face);
545 CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face) {
546 const SkTypeface_Mac* macface = (const SkTypeface_Mac*)face;
547 return macface ? macface->fFontRef.get() : NULL;
550 /* This function is visible on the outside. It first searches the cache, and if
551 * not found, returns a new entry (after adding it to the cache).
553 SkTypeface* SkCreateTypefaceFromCTFont(CTFontRef fontRef) {
554 SkFontID fontID = CTFontRef_to_SkFontID(fontRef);
555 SkTypeface* face = SkTypefaceCache::FindByID(fontID);
559 face = NewFromFontRef(fontRef, NULL, false);
560 SkTypefaceCache::Add(face, face->style());
561 // NewFromFontRef doesn't retain the parameter, but the typeface it
562 // creates does release it in its destructor, so we balance that with
563 // a retain call here.
566 SkASSERT(face->getRefCnt() > 1);
570 struct NameStyleRec {
572 SkTypeface::Style fStyle;
575 static bool FindByNameStyle(SkTypeface* face, SkTypeface::Style style,
577 const SkTypeface_Mac* mface = reinterpret_cast<SkTypeface_Mac*>(face);
578 const NameStyleRec* rec = reinterpret_cast<const NameStyleRec*>(ctx);
580 return rec->fStyle == style && mface->fName.equals(rec->fName);
583 static const char* map_css_names(const char* name) {
584 static const struct {
585 const char* fFrom; // name the caller specified
586 const char* fTo; // "canonical" name we map to
588 { "sans-serif", "Helvetica" },
589 { "serif", "Times" },
590 { "monospace", "Courier" }
593 for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
594 if (strcmp(name, gPairs[i].fFrom) == 0) {
595 return gPairs[i].fTo;
598 return name; // no change
601 static SkTypeface* create_typeface(const SkTypeface* familyFace,
602 const char familyName[],
603 SkTypeface::Style style) {
605 familyName = map_css_names(familyName);
608 // Clone an existing typeface
609 // TODO: only clone if style matches the familyFace's style...
610 if (familyName == NULL && familyFace != NULL) {
612 return const_cast<SkTypeface*>(familyFace);
615 if (!familyName || !*familyName) {
616 familyName = FONT_DEFAULT_NAME;
619 NameStyleRec rec = { familyName, style };
620 SkTypeface* face = SkTypefaceCache::FindByProcAndRef(FindByNameStyle, &rec);
623 face = NewFromName(familyName, style);
625 SkTypefaceCache::Add(face, style);
627 face = GetDefaultFace();
634 ///////////////////////////////////////////////////////////////////////////////
636 /** GlyphRect is in FUnits (em space, y up). */
644 class SkScalerContext_Mac : public SkScalerContext {
646 SkScalerContext_Mac(SkTypeface_Mac*, const SkDescriptor*);
649 unsigned generateGlyphCount(void) SK_OVERRIDE;
650 uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE;
651 void generateAdvance(SkGlyph* glyph) SK_OVERRIDE;
652 void generateMetrics(SkGlyph* glyph) SK_OVERRIDE;
653 void generateImage(const SkGlyph& glyph) SK_OVERRIDE;
654 void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE;
655 void generateFontMetrics(SkPaint::FontMetrics*) SK_OVERRIDE;
658 static void CTPathElement(void *info, const CGPathElement *element);
660 /** Returns the offset from the horizontal origin to the vertical origin in SkGlyph units. */
661 void getVerticalOffset(CGGlyph glyphID, SkPoint* offset) const;
663 /** Initializes and returns the value of fFBoundingBoxesGlyphOffset.
665 * For use with (and must be called before) generateBBoxes.
667 uint16_t getFBoundingBoxesGlyphOffset();
669 /** Initializes fFBoundingBoxes and returns true on success.
671 * On Lion and Mountain Lion, CTFontGetBoundingRectsForGlyphs has a bug which causes it to
672 * return a bad value in bounds.origin.x for SFNT fonts whose hhea::numberOfHMetrics is
673 * less than its maxp::numGlyphs. When this is the case we try to read the bounds from the
676 * This routine initializes fFBoundingBoxes to an array of
677 * fGlyphCount - fFBoundingBoxesGlyphOffset GlyphRects which contain the bounds in FUnits
678 * (em space, y up) of glyphs with ids in the range [fFBoundingBoxesGlyphOffset, fGlyphCount).
680 * Returns true if fFBoundingBoxes is properly initialized. The table can only be properly
681 * initialized for a TrueType font with 'head', 'loca', and 'glyf' tables.
683 * TODO: A future optimization will compute fFBoundingBoxes once per fCTFont.
685 bool generateBBoxes();
687 /** Converts from FUnits (em space, y up) to SkGlyph units (pixels, y down).
689 * Used on Snow Leopard to correct CTFontGetVerticalTranslationsForGlyphs.
690 * Used on Lion to correct CTFontGetBoundingRectsForGlyphs.
692 SkMatrix fFUnitMatrix;
694 Offscreen fOffscreen;
695 AutoCFRelease<CTFontRef> fCTFont;
697 /** Vertical variant of fCTFont.
699 * CT vertical metrics are pre-rotated (in em space, before transform) 90deg clock-wise.
700 * This makes kCTFontDefaultOrientation dangerous, because the metrics from
701 * kCTFontHorizontalOrientation are in a different space from kCTFontVerticalOrientation.
702 * Use fCTVerticalFont with kCTFontVerticalOrientation to get metrics in the same space.
704 AutoCFRelease<CTFontRef> fCTVerticalFont;
706 AutoCFRelease<CGFontRef> fCGFont;
707 SkAutoTMalloc<GlyphRect> fFBoundingBoxes;
708 uint16_t fFBoundingBoxesGlyphOffset;
709 uint16_t fGlyphCount;
710 bool fGeneratedFBoundingBoxes;
711 const bool fDoSubPosition;
712 const bool fVertical;
714 friend class Offscreen;
716 typedef SkScalerContext INHERITED;
719 SkScalerContext_Mac::SkScalerContext_Mac(SkTypeface_Mac* typeface,
720 const SkDescriptor* desc)
721 : INHERITED(typeface, desc)
723 , fFBoundingBoxesGlyphOffset(0)
724 , fGeneratedFBoundingBoxes(false)
725 , fDoSubPosition(SkToBool(fRec.fFlags & kSubpixelPositioning_Flag))
726 , fVertical(SkToBool(fRec.fFlags & kVertical_Flag))
729 CTFontRef ctFont = typeface->fFontRef.get();
730 CFIndex numGlyphs = CTFontGetGlyphCount(ctFont);
731 SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF);
732 fGlyphCount = SkToU16(numGlyphs);
734 fRec.getSingleMatrix(&fFUnitMatrix);
735 CGAffineTransform transform = MatrixToCGAffineTransform(fFUnitMatrix);
737 AutoCFRelease<CTFontDescriptorRef> ctFontDesc;
739 AutoCFRelease<CFMutableDictionaryRef> cfAttributes(CFDictionaryCreateMutable(
740 kCFAllocatorDefault, 0,
741 &kCFTypeDictionaryKeyCallBacks,
742 &kCFTypeDictionaryValueCallBacks));
744 CTFontOrientation ctOrientation = kCTFontVerticalOrientation;
745 AutoCFRelease<CFNumberRef> cfVertical(CFNumberCreate(
746 kCFAllocatorDefault, kCFNumberSInt32Type, &ctOrientation));
747 CFDictionaryAddValue(cfAttributes, kCTFontOrientationAttribute, cfVertical);
748 ctFontDesc.reset(CTFontDescriptorCreateWithAttributes(cfAttributes));
751 // Since our matrix includes everything, we pass 1 for size.
752 fCTFont.reset(CTFontCreateCopyWithAttributes(ctFont, 1, &transform, ctFontDesc));
753 fCGFont.reset(CTFontCopyGraphicsFont(fCTFont, NULL));
755 CGAffineTransform rotateLeft = CGAffineTransformMake(0, -1, 1, 0, 0, 0);
756 transform = CGAffineTransformConcat(rotateLeft, transform);
757 fCTVerticalFont.reset(CTFontCreateCopyWithAttributes(ctFont, 1, &transform, NULL));
760 SkScalar emPerFUnit = SkScalarInvert(SkIntToScalar(CGFontGetUnitsPerEm(fCGFont)));
761 fFUnitMatrix.preScale(emPerFUnit, -emPerFUnit);
764 CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
765 CGGlyph glyphID, size_t* rowBytesPtr,
766 bool generateA8FromLCD) {
768 //It doesn't appear to matter what color space is specified.
769 //Regular blends and antialiased text are always (s*a + d*(1-a))
770 //and smoothed text is always g=2.0.
771 fRGBSpace.reset(CGColorSpaceCreateDeviceRGB());
774 // default to kBW_Format
778 if (SkMask::kBW_Format != glyph.fMaskFormat) {
783 // FIXME: lcd smoothed un-hinted rasterization unsupported.
784 if (!generateA8FromLCD && SkMask::kA8_Format == glyph.fMaskFormat) {
789 size_t rowBytes = fSize.fWidth * sizeof(CGRGBPixel);
790 if (!fCG || fSize.fWidth < glyph.fWidth || fSize.fHeight < glyph.fHeight) {
791 if (fSize.fWidth < glyph.fWidth) {
792 fSize.fWidth = RoundSize(glyph.fWidth);
794 if (fSize.fHeight < glyph.fHeight) {
795 fSize.fHeight = RoundSize(glyph.fHeight);
798 rowBytes = fSize.fWidth * sizeof(CGRGBPixel);
799 void* image = fImageStorage.reset(rowBytes * fSize.fHeight);
800 fCG.reset(CGBitmapContextCreate(image, fSize.fWidth, fSize.fHeight, 8,
801 rowBytes, fRGBSpace, BITMAP_INFO_RGB));
803 // skia handles quantization itself, so we disable this for cg to get
804 // full fractional data from them.
805 CGContextSetAllowsFontSubpixelQuantization(fCG, false);
806 CGContextSetShouldSubpixelQuantizeFonts(fCG, false);
808 CGContextSetTextDrawingMode(fCG, kCGTextFill);
809 CGContextSetFont(fCG, context.fCGFont);
810 CGContextSetFontSize(fCG, 1 /*CTFontGetSize(context.fCTFont)*/);
811 CGContextSetTextMatrix(fCG, CTFontGetMatrix(context.fCTFont));
813 // Because CG always draws from the horizontal baseline,
814 // if there is a non-integral translation from the horizontal origin to the vertical origin,
815 // then CG cannot draw the glyph in the correct location without subpixel positioning.
816 CGContextSetAllowsFontSubpixelPositioning(fCG, context.fDoSubPosition || context.fVertical);
817 CGContextSetShouldSubpixelPositionFonts(fCG, context.fDoSubPosition || context.fVertical);
819 // Draw white on black to create mask.
820 // TODO: Draw black on white and invert, CG has a special case codepath.
821 CGContextSetGrayFillColor(fCG, 1.0f, 1.0f);
823 // force our checks below to happen
829 CGContextSetShouldAntialias(fCG, doAA);
832 if (fDoLCD != doLCD) {
833 CGContextSetShouldSmoothFonts(fCG, doLCD);
837 CGRGBPixel* image = (CGRGBPixel*)fImageStorage.get();
838 // skip rows based on the glyph's height
839 image += (fSize.fHeight - glyph.fHeight) * fSize.fWidth;
842 sk_memset_rect32(image, 0, glyph.fWidth, glyph.fHeight, rowBytes);
846 if (context.fDoSubPosition) {
847 subX = SkFixedToFloat(glyph.getSubXFixed());
848 subY = SkFixedToFloat(glyph.getSubYFixed());
851 // CGContextShowGlyphsAtPoint always draws using the horizontal baseline origin.
852 if (context.fVertical) {
854 context.getVerticalOffset(glyphID, &offset);
859 CGContextShowGlyphsAtPoint(fCG, -glyph.fLeft + subX,
860 glyph.fTop + glyph.fHeight - subY,
863 SkASSERT(rowBytesPtr);
864 *rowBytesPtr = rowBytes;
868 void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkPoint* offset) const {
869 // Snow Leopard returns cgVertOffset in completely un-transformed FUnits (em space, y up).
870 // Lion and Leopard return cgVertOffset in CG units (pixels, y up).
872 CTFontGetVerticalTranslationsForGlyphs(fCTFont, &glyphID, &cgVertOffset, 1);
874 SkPoint skVertOffset = { CGToScalar(cgVertOffset.width), CGToScalar(cgVertOffset.height) };
875 if (isSnowLeopard()) {
876 // From FUnits (em space, y up) to SkGlyph units (pixels, y down).
877 fFUnitMatrix.mapPoints(&skVertOffset, 1);
879 // From CG units (pixels, y up) to SkGlyph units (pixels, y down).
880 skVertOffset.fY = -skVertOffset.fY;
883 *offset = skVertOffset;
886 uint16_t SkScalerContext_Mac::getFBoundingBoxesGlyphOffset() {
887 if (fFBoundingBoxesGlyphOffset) {
888 return fFBoundingBoxesGlyphOffset;
890 fFBoundingBoxesGlyphOffset = fGlyphCount; // fallback for all fonts
891 AutoCGTable<SkOTTableHorizontalHeader> hheaTable(fCGFont);
892 if (hheaTable.fData) {
893 fFBoundingBoxesGlyphOffset = SkEndian_SwapBE16(hheaTable->numberOfHMetrics);
895 return fFBoundingBoxesGlyphOffset;
898 bool SkScalerContext_Mac::generateBBoxes() {
899 if (fGeneratedFBoundingBoxes) {
900 return NULL != fFBoundingBoxes.get();
902 fGeneratedFBoundingBoxes = true;
904 AutoCGTable<SkOTTableHead> headTable(fCGFont);
905 if (!headTable.fData) {
909 AutoCGTable<SkOTTableIndexToLocation> locaTable(fCGFont);
910 if (!locaTable.fData) {
914 AutoCGTable<SkOTTableGlyph> glyfTable(fCGFont);
915 if (!glyfTable.fData) {
919 uint16_t entries = fGlyphCount - fFBoundingBoxesGlyphOffset;
920 fFBoundingBoxes.reset(entries);
922 SkOTTableHead::IndexToLocFormat locaFormat = headTable->indexToLocFormat;
923 SkOTTableGlyph::Iterator glyphDataIter(*glyfTable.fData, *locaTable.fData, locaFormat);
924 glyphDataIter.advance(fFBoundingBoxesGlyphOffset);
925 for (uint16_t boundingBoxesIndex = 0; boundingBoxesIndex < entries; ++boundingBoxesIndex) {
926 const SkOTTableGlyphData* glyphData = glyphDataIter.next();
927 GlyphRect& rect = fFBoundingBoxes[boundingBoxesIndex];
928 rect.fMinX = SkEndian_SwapBE16(glyphData->xMin);
929 rect.fMinY = SkEndian_SwapBE16(glyphData->yMin);
930 rect.fMaxX = SkEndian_SwapBE16(glyphData->xMax);
931 rect.fMaxY = SkEndian_SwapBE16(glyphData->yMax);
937 unsigned SkScalerContext_Mac::generateGlyphCount(void) {
941 uint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni) {
943 UniChar theChar[2]; // UniChar is a UTF-16 16-bit code unit.
946 size_t numUniChar = SkUTF16_FromUnichar(uni, theChar);
947 SkASSERT(sizeof(CGGlyph) <= sizeof(uint16_t));
949 // Undocumented behavior of CTFontGetGlyphsForCharacters with non-bmp code points:
950 // When a surrogate pair is detected, the glyph index used is the index of the high surrogate.
951 // It is documented that if a mapping is unavailable, the glyph will be set to 0.
952 CTFontGetGlyphsForCharacters(fCTFont, theChar, cgGlyph, numUniChar);
956 void SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) {
957 this->generateMetrics(glyph);
960 void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) {
961 const CGGlyph cgGlyph = (CGGlyph) glyph->getGlyphID();
962 glyph->zeroMetrics();
964 // The following block produces cgAdvance in CG units (pixels, y up).
967 CTFontGetAdvancesForGlyphs(fCTVerticalFont, kCTFontVerticalOrientation,
968 &cgGlyph, &cgAdvance, 1);
970 CTFontGetAdvancesForGlyphs(fCTFont, kCTFontHorizontalOrientation,
971 &cgGlyph, &cgAdvance, 1);
973 glyph->fAdvanceX = SkFloatToFixed_Check(cgAdvance.width);
974 glyph->fAdvanceY = -SkFloatToFixed_Check(cgAdvance.height);
976 // The following produces skBounds in SkGlyph units (pixels, y down),
977 // or returns early if skBounds would be empty.
980 // On Mountain Lion, CTFontGetBoundingRectsForGlyphs with kCTFontVerticalOrientation and
981 // CTFontGetVerticalTranslationsForGlyphs do not agree when using OTF CFF fonts.
982 // For TTF fonts these two do agree and we can use CTFontGetBoundingRectsForGlyphs to get
983 // the bounding box and CTFontGetVerticalTranslationsForGlyphs to then draw the glyph
984 // inside that bounding box. However, with OTF CFF fonts this does not work. It appears that
985 // CTFontGetBoundingRectsForGlyphs with kCTFontVerticalOrientation on OTF CFF fonts tries
986 // to center the glyph along the vertical baseline and also perform some mysterious shift
987 // along the baseline. CTFontGetVerticalTranslationsForGlyphs does not appear to perform
990 // It is not known which is correct (or if either is correct). However, we must always draw
991 // from the horizontal origin and must use CTFontGetVerticalTranslationsForGlyphs to draw.
992 // As a result, we do not call CTFontGetBoundingRectsForGlyphs for vertical glyphs.
994 // On Snow Leopard, CTFontGetBoundingRectsForGlyphs ignores kCTFontVerticalOrientation and
995 // returns horizontal bounds.
997 // On Lion and Mountain Lion, CTFontGetBoundingRectsForGlyphs has a bug which causes it to
998 // return a bad value in cgBounds.origin.x for SFNT fonts whose hhea::numberOfHMetrics is
999 // less than its maxp::numGlyphs. When this is the case we try to read the bounds from the
1001 if ((isLion() || isMountainLion()) &&
1002 (cgGlyph < fGlyphCount && cgGlyph >= getFBoundingBoxesGlyphOffset() && generateBBoxes()))
1004 const GlyphRect& gRect = fFBoundingBoxes[cgGlyph - fFBoundingBoxesGlyphOffset];
1005 if (gRect.fMinX >= gRect.fMaxX || gRect.fMinY >= gRect.fMaxY) {
1008 skBounds = SkRect::MakeLTRB(gRect.fMinX, gRect.fMinY, gRect.fMaxX, gRect.fMaxY);
1009 // From FUnits (em space, y up) to SkGlyph units (pixels, y down).
1010 fFUnitMatrix.mapRect(&skBounds);
1013 // CTFontGetBoundingRectsForGlyphs produces cgBounds in CG units (pixels, y up).
1015 CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontHorizontalOrientation,
1016 &cgGlyph, &cgBounds, 1);
1019 // 0x200B (zero-advance space) seems to return a huge (garbage) bounds, when
1020 // it should be empty. So, if we see a zero-advance, we check if it has an
1021 // empty path or not, and if so, we jam the bounds to 0. Hopefully a zero-advance
1022 // is rare, so we won't incur a big performance cost for this extra check.
1023 if (0 == cgAdvance.width && 0 == cgAdvance.height) {
1024 AutoCFRelease<CGPathRef> path(CTFontCreatePathForGlyph(fCTFont, cgGlyph, NULL));
1025 if (NULL == path || CGPathIsEmpty(path)) {
1030 if (CGRectIsEmpty_inline(cgBounds)) {
1034 // Convert cgBounds to SkGlyph units (pixels, y down).
1035 skBounds = SkRect::MakeXYWH(cgBounds.origin.x, -cgBounds.origin.y - cgBounds.size.height,
1036 cgBounds.size.width, cgBounds.size.height);
1040 // Due to all of the vertical bounds bugs, skBounds is always the horizontal bounds.
1041 // Convert these horizontal bounds into vertical bounds.
1043 getVerticalOffset(cgGlyph, &offset);
1044 skBounds.offset(offset);
1047 // Currently the bounds are based on being rendered at (0,0).
1048 // The top left must not move, since that is the base from which subpixel positioning is offset.
1049 if (fDoSubPosition) {
1050 skBounds.fRight += SkFixedToFloat(glyph->getSubXFixed());
1051 skBounds.fBottom += SkFixedToFloat(glyph->getSubYFixed());
1055 skBounds.roundOut(&skIBounds);
1056 // Expand the bounds by 1 pixel, to give CG room for anti-aliasing.
1057 // Note that this outset is to allow room for LCD smoothed glyphs. However, the correct outset
1058 // is not currently known, as CG dilates the outlines by some percentage.
1059 // Note that if this context is A8 and not back-forming from LCD, there is no need to outset.
1060 skIBounds.outset(1, 1);
1061 glyph->fLeft = SkToS16(skIBounds.fLeft);
1062 glyph->fTop = SkToS16(skIBounds.fTop);
1063 glyph->fWidth = SkToU16(skIBounds.width());
1064 glyph->fHeight = SkToU16(skIBounds.height());
1066 #ifdef HACK_COLORGLYPHS
1067 glyph->fMaskFormat = SkMask::kARGB32_Format;
1071 #include "SkColorPriv.h"
1073 static void build_power_table(uint8_t table[], float ee) {
1074 for (int i = 0; i < 256; i++) {
1075 float x = i / 255.f;
1076 x = sk_float_pow(x, ee);
1077 int xx = SkScalarRoundToInt(x * 255);
1078 table[i] = SkToU8(xx);
1083 * This will invert the gamma applied by CoreGraphics, so we can get linear
1086 * CoreGraphics obscurely defaults to 2.0 as the smoothing gamma value.
1087 * The color space used does not appear to affect this choice.
1089 static const uint8_t* getInverseGammaTableCoreGraphicSmoothing() {
1090 static bool gInited;
1091 static uint8_t gTableCoreGraphicsSmoothing[256];
1093 build_power_table(gTableCoreGraphicsSmoothing, 2.0f);
1096 return gTableCoreGraphicsSmoothing;
1099 static void cgpixels_to_bits(uint8_t dst[], const CGRGBPixel src[], int count) {
1102 for (int i = 7; i >= 0; --i) {
1103 mask |= (CGRGBPixel_getAlpha(*src++) >> 7) << i;
1112 template<bool APPLY_PREBLEND>
1113 static inline uint8_t rgb_to_a8(CGRGBPixel rgb, const uint8_t* table8) {
1114 U8CPU r = (rgb >> 16) & 0xFF;
1115 U8CPU g = (rgb >> 8) & 0xFF;
1116 U8CPU b = (rgb >> 0) & 0xFF;
1117 return sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8);
1119 template<bool APPLY_PREBLEND>
1120 static void rgb_to_a8(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes,
1121 const SkGlyph& glyph, const uint8_t* table8) {
1122 const int width = glyph.fWidth;
1123 size_t dstRB = glyph.rowBytes();
1124 uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage;
1126 for (int y = 0; y < glyph.fHeight; y++) {
1127 for (int i = 0; i < width; ++i) {
1128 dst[i] = rgb_to_a8<APPLY_PREBLEND>(cgPixels[i], table8);
1130 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1135 template<bool APPLY_PREBLEND>
1136 static inline uint16_t rgb_to_lcd16(CGRGBPixel rgb, const uint8_t* tableR,
1137 const uint8_t* tableG,
1138 const uint8_t* tableB) {
1139 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
1140 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG);
1141 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB);
1142 return SkPack888ToRGB16(r, g, b);
1144 template<bool APPLY_PREBLEND>
1145 static void rgb_to_lcd16(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes, const SkGlyph& glyph,
1146 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
1147 const int width = glyph.fWidth;
1148 size_t dstRB = glyph.rowBytes();
1149 uint16_t* SK_RESTRICT dst = (uint16_t*)glyph.fImage;
1151 for (int y = 0; y < glyph.fHeight; y++) {
1152 for (int i = 0; i < width; i++) {
1153 dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(cgPixels[i], tableR, tableG, tableB);
1155 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1156 dst = (uint16_t*)((char*)dst + dstRB);
1160 template<bool APPLY_PREBLEND>
1161 static inline uint32_t rgb_to_lcd32(CGRGBPixel rgb, const uint8_t* tableR,
1162 const uint8_t* tableG,
1163 const uint8_t* tableB) {
1164 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
1165 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG);
1166 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB);
1167 return SkPackARGB32(0xFF, r, g, b);
1169 template<bool APPLY_PREBLEND>
1170 static void rgb_to_lcd32(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes, const SkGlyph& glyph,
1171 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
1172 const int width = glyph.fWidth;
1173 size_t dstRB = glyph.rowBytes();
1174 uint32_t* SK_RESTRICT dst = (uint32_t*)glyph.fImage;
1175 for (int y = 0; y < glyph.fHeight; y++) {
1176 for (int i = 0; i < width; i++) {
1177 dst[i] = rgb_to_lcd32<APPLY_PREBLEND>(cgPixels[i], tableR, tableG, tableB);
1179 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1180 dst = (uint32_t*)((char*)dst + dstRB);
1184 #ifdef HACK_COLORGLYPHS
1185 // hack to colorize the output for testing kARGB32_Format
1186 static SkPMColor cgpixels_to_pmcolor(CGRGBPixel rgb, const SkGlyph& glyph,
1188 U8CPU r = (rgb >> 16) & 0xFF;
1189 U8CPU g = (rgb >> 8) & 0xFF;
1190 U8CPU b = (rgb >> 0) & 0xFF;
1191 unsigned a = SkComputeLuminance(r, g, b);
1193 // compute gradient from x,y
1194 r = x * 255 / glyph.fWidth;
1196 b = (glyph.fHeight - y) * 255 / glyph.fHeight;
1197 return SkPreMultiplyARGB(a, r, g, b); // red
1201 template <typename T> T* SkTAddByteOffset(T* ptr, size_t byteOffset) {
1202 return (T*)((char*)ptr + byteOffset);
1205 void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
1206 CGGlyph cgGlyph = (CGGlyph) glyph.getGlyphID();
1208 // FIXME: lcd smoothed un-hinted rasterization unsupported.
1209 bool generateA8FromLCD = fRec.getHinting() != SkPaint::kNo_Hinting;
1213 CGRGBPixel* cgPixels = fOffscreen.getCG(*this, glyph, cgGlyph, &cgRowBytes, generateA8FromLCD);
1214 if (cgPixels == NULL) {
1218 //TODO: see if drawing black on white and inverting is faster (at least in
1219 //lcd case) as core graphics appears to have special case code for drawing
1223 const bool isLCD = isLCDFormat(glyph.fMaskFormat);
1224 if (isLCD || (glyph.fMaskFormat == SkMask::kA8_Format && supports_LCD() && generateA8FromLCD)) {
1225 const uint8_t* table = getInverseGammaTableCoreGraphicSmoothing();
1227 //Note that the following cannot really be integrated into the
1228 //pre-blend, since we may not be applying the pre-blend; when we aren't
1229 //applying the pre-blend it means that a filter wants linear anyway.
1230 //Other code may also be applying the pre-blend, so we'd need another
1231 //one with this and one without.
1232 CGRGBPixel* addr = cgPixels;
1233 for (int y = 0; y < glyph.fHeight; ++y) {
1234 for (int x = 0; x < glyph.fWidth; ++x) {
1235 int r = (addr[x] >> 16) & 0xFF;
1236 int g = (addr[x] >> 8) & 0xFF;
1237 int b = (addr[x] >> 0) & 0xFF;
1238 addr[x] = (table[r] << 16) | (table[g] << 8) | table[b];
1240 addr = SkTAddByteOffset(addr, cgRowBytes);
1244 // Convert glyph to mask
1245 switch (glyph.fMaskFormat) {
1246 case SkMask::kLCD32_Format: {
1247 if (fPreBlend.isApplicable()) {
1248 rgb_to_lcd32<true>(cgPixels, cgRowBytes, glyph,
1249 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1251 rgb_to_lcd32<false>(cgPixels, cgRowBytes, glyph,
1252 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1255 case SkMask::kLCD16_Format: {
1256 if (fPreBlend.isApplicable()) {
1257 rgb_to_lcd16<true>(cgPixels, cgRowBytes, glyph,
1258 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1260 rgb_to_lcd16<false>(cgPixels, cgRowBytes, glyph,
1261 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1264 case SkMask::kA8_Format: {
1265 if (fPreBlend.isApplicable()) {
1266 rgb_to_a8<true>(cgPixels, cgRowBytes, glyph, fPreBlend.fG);
1268 rgb_to_a8<false>(cgPixels, cgRowBytes, glyph, fPreBlend.fG);
1271 case SkMask::kBW_Format: {
1272 const int width = glyph.fWidth;
1273 size_t dstRB = glyph.rowBytes();
1274 uint8_t* dst = (uint8_t*)glyph.fImage;
1275 for (int y = 0; y < glyph.fHeight; y++) {
1276 cgpixels_to_bits(dst, cgPixels, width);
1277 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1281 #ifdef HACK_COLORGLYPHS
1282 case SkMask::kARGB32_Format: {
1283 const int width = glyph.fWidth;
1284 size_t dstRB = glyph.rowBytes();
1285 SkPMColor* dst = (SkPMColor*)glyph.fImage;
1286 for (int y = 0; y < glyph.fHeight; y++) {
1287 for (int x = 0; x < width; ++x) {
1288 dst[x] = cgpixels_to_pmcolor(cgPixels[x], glyph, x, y);
1290 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1291 dst = (SkPMColor*)((char*)dst + dstRB);
1296 SkDEBUGFAIL("unexpected mask format");
1302 * Our subpixel resolution is only 2 bits in each direction, so a scale of 4
1303 * seems sufficient, and possibly even correct, to allow the hinted outline
1304 * to be subpixel positioned.
1306 #define kScaleForSubPixelPositionHinting (4.0f)
1308 void SkScalerContext_Mac::generatePath(const SkGlyph& glyph, SkPath* path) {
1309 CTFontRef font = fCTFont;
1310 SkScalar scaleX = SK_Scalar1;
1311 SkScalar scaleY = SK_Scalar1;
1314 * For subpixel positioning, we want to return an unhinted outline, so it
1315 * can be positioned nicely at fractional offsets. However, we special-case
1316 * if the baseline of the (horizontal) text is axis-aligned. In those cases
1317 * we want to retain hinting in the direction orthogonal to the baseline.
1318 * e.g. for horizontal baseline, we want to retain hinting in Y.
1319 * The way we remove hinting is to scale the font by some value (4) in that
1320 * direction, ask for the path, and then scale the path back down.
1322 if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
1324 fRec.getSingleMatrix(&m);
1326 // start out by assuming that we want no hining in X and Y
1327 scaleX = scaleY = kScaleForSubPixelPositionHinting;
1328 // now see if we need to restore hinting for axis-aligned baselines
1329 switch (SkComputeAxisAlignmentForHText(m)) {
1330 case kX_SkAxisAlignment:
1331 scaleY = SK_Scalar1; // want hinting in the Y direction
1333 case kY_SkAxisAlignment:
1334 scaleX = SK_Scalar1; // want hinting in the X direction
1340 CGAffineTransform xform = MatrixToCGAffineTransform(m, scaleX, scaleY);
1341 // need to release font when we're done
1342 font = CTFontCreateCopyWithAttributes(fCTFont, 1, &xform, NULL);
1345 CGGlyph cgGlyph = (CGGlyph)glyph.getGlyphID();
1346 AutoCFRelease<CGPathRef> cgPath(CTFontCreatePathForGlyph(font, cgGlyph, NULL));
1349 if (cgPath != NULL) {
1350 CGPathApply(cgPath, path, SkScalerContext_Mac::CTPathElement);
1353 if (fDoSubPosition) {
1355 m.setScale(SkScalarInvert(scaleX), SkScalarInvert(scaleY));
1357 // balance the call to CTFontCreateCopyWithAttributes
1358 CFSafeRelease(font);
1362 getVerticalOffset(cgGlyph, &offset);
1363 path->offset(offset.fX, offset.fY);
1367 void SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* metrics) {
1368 if (NULL == metrics) {
1372 CGRect theBounds = CTFontGetBoundingBox(fCTFont);
1374 metrics->fTop = CGToScalar(-CGRectGetMaxY_inline(theBounds));
1375 metrics->fAscent = CGToScalar(-CTFontGetAscent(fCTFont));
1376 metrics->fDescent = CGToScalar( CTFontGetDescent(fCTFont));
1377 metrics->fBottom = CGToScalar(-CGRectGetMinY_inline(theBounds));
1378 metrics->fLeading = CGToScalar( CTFontGetLeading(fCTFont));
1379 metrics->fAvgCharWidth = CGToScalar( CGRectGetWidth_inline(theBounds));
1380 metrics->fXMin = CGToScalar( CGRectGetMinX_inline(theBounds));
1381 metrics->fXMax = CGToScalar( CGRectGetMaxX_inline(theBounds));
1382 metrics->fXHeight = CGToScalar( CTFontGetXHeight(fCTFont));
1383 metrics->fUnderlineThickness = CGToScalar( CTFontGetUnderlineThickness(fCTFont));
1384 metrics->fUnderlinePosition = -CGToScalar( CTFontGetUnderlinePosition(fCTFont));
1386 metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
1387 metrics->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
1390 void SkScalerContext_Mac::CTPathElement(void *info, const CGPathElement *element) {
1391 SkPath* skPath = (SkPath*)info;
1393 // Process the path element
1394 switch (element->type) {
1395 case kCGPathElementMoveToPoint:
1396 skPath->moveTo(element->points[0].x, -element->points[0].y);
1399 case kCGPathElementAddLineToPoint:
1400 skPath->lineTo(element->points[0].x, -element->points[0].y);
1403 case kCGPathElementAddQuadCurveToPoint:
1404 skPath->quadTo(element->points[0].x, -element->points[0].y,
1405 element->points[1].x, -element->points[1].y);
1408 case kCGPathElementAddCurveToPoint:
1409 skPath->cubicTo(element->points[0].x, -element->points[0].y,
1410 element->points[1].x, -element->points[1].y,
1411 element->points[2].x, -element->points[2].y);
1414 case kCGPathElementCloseSubpath:
1419 SkDEBUGFAIL("Unknown path element!");
1425 ///////////////////////////////////////////////////////////////////////////////
1427 // Returns NULL on failure
1428 // Call must still manage its ownership of provider
1429 static SkTypeface* create_from_dataProvider(CGDataProviderRef provider) {
1430 AutoCFRelease<CGFontRef> cg(CGFontCreateWithDataProvider(provider));
1434 CTFontRef ct = CTFontCreateWithGraphicsFont(cg, 0, NULL, NULL);
1435 return ct ? NewFromFontRef(ct, NULL, true) : NULL;
1438 // Web fonts added to the the CTFont registry do not return their character set.
1439 // Iterate through the font in this case. The existing caller caches the result,
1440 // so the performance impact isn't too bad.
1441 static void populate_glyph_to_unicode_slow(CTFontRef ctFont, CFIndex glyphCount,
1442 SkTDArray<SkUnichar>* glyphToUnicode) {
1443 glyphToUnicode->setCount(SkToInt(glyphCount));
1444 SkUnichar* out = glyphToUnicode->begin();
1445 sk_bzero(out, glyphCount * sizeof(SkUnichar));
1446 UniChar unichar = 0;
1447 while (glyphCount > 0) {
1449 if (CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) {
1450 out[glyph] = unichar;
1453 if (++unichar == 0) {
1459 // Construct Glyph to Unicode table.
1460 // Unicode code points that require conjugate pairs in utf16 are not
1462 static void populate_glyph_to_unicode(CTFontRef ctFont, CFIndex glyphCount,
1463 SkTDArray<SkUnichar>* glyphToUnicode) {
1464 AutoCFRelease<CFCharacterSetRef> charSet(CTFontCopyCharacterSet(ctFont));
1466 populate_glyph_to_unicode_slow(ctFont, glyphCount, glyphToUnicode);
1470 AutoCFRelease<CFDataRef> bitmap(CFCharacterSetCreateBitmapRepresentation(kCFAllocatorDefault,
1475 CFIndex length = CFDataGetLength(bitmap);
1479 if (length > 8192) {
1480 // TODO: Add support for Unicode above 0xFFFF
1481 // Consider only the BMP portion of the Unicode character points.
1482 // The bitmap may contain other planes, up to plane 16.
1483 // See http://developer.apple.com/library/ios/#documentation/CoreFoundation/Reference/CFCharacterSetRef/Reference/reference.html
1486 const UInt8* bits = CFDataGetBytePtr(bitmap);
1487 glyphToUnicode->setCount(SkToInt(glyphCount));
1488 SkUnichar* out = glyphToUnicode->begin();
1489 sk_bzero(out, glyphCount * sizeof(SkUnichar));
1490 for (int i = 0; i < length; i++) {
1495 for (int j = 0; j < 8; j++) {
1497 UniChar unichar = static_cast<UniChar>((i << 3) + j);
1498 if (mask & (1 << j) && CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) {
1499 out[glyph] = unichar;
1505 static bool getWidthAdvance(CTFontRef ctFont, int gId, int16_t* data) {
1508 CGGlyph glyph = gId;
1509 CTFontGetAdvancesForGlyphs(ctFont, kCTFontHorizontalOrientation, &glyph, &advance, 1);
1510 *data = sk_float_round2int(advance.width);
1514 /** Assumes src and dst are not NULL. */
1515 static void CFStringToSkString(CFStringRef src, SkString* dst) {
1516 // Reserve enough room for the worst-case string,
1517 // plus 1 byte for the trailing null.
1518 CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(src),
1519 kCFStringEncodingUTF8) + 1;
1520 dst->resize(length);
1521 CFStringGetCString(src, dst->writable_str(), length, kCFStringEncodingUTF8);
1522 // Resize to the actual UTF-8 length used, stripping the null character.
1523 dst->resize(strlen(dst->c_str()));
1526 SkAdvancedTypefaceMetrics* SkTypeface_Mac::onGetAdvancedTypefaceMetrics(
1527 SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
1528 const uint32_t* glyphIDs,
1529 uint32_t glyphIDsCount) const {
1531 CTFontRef originalCTFont = fFontRef.get();
1532 AutoCFRelease<CTFontRef> ctFont(CTFontCreateCopyWithAttributes(
1533 originalCTFont, CTFontGetUnitsPerEm(originalCTFont), NULL, NULL));
1534 SkAdvancedTypefaceMetrics* info = new SkAdvancedTypefaceMetrics;
1537 AutoCFRelease<CFStringRef> fontName(CTFontCopyPostScriptName(ctFont));
1538 if (fontName.get()) {
1539 CFStringToSkString(fontName, &info->fFontName);
1543 CFIndex glyphCount = CTFontGetGlyphCount(ctFont);
1544 info->fLastGlyphID = SkToU16(glyphCount - 1);
1545 info->fEmSize = CTFontGetUnitsPerEm(ctFont);
1546 info->fFlags = SkAdvancedTypefaceMetrics::kEmpty_FontFlag;
1549 if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) {
1550 populate_glyph_to_unicode(ctFont, glyphCount, &info->fGlyphToUnicode);
1553 // If it's not a truetype font, mark it as 'other'. Assume that TrueType
1554 // fonts always have both glyf and loca tables. At the least, this is what
1555 // sfntly needs to subset the font. CTFontCopyAttribute() does not always
1556 // succeed in determining this directly.
1557 if (!this->getTableSize('glyf') || !this->getTableSize('loca')) {
1558 info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
1559 info->fItalicAngle = 0;
1563 info->fCapHeight = 0;
1564 info->fBBox = SkIRect::MakeEmpty();
1568 info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
1569 CTFontSymbolicTraits symbolicTraits = CTFontGetSymbolicTraits(ctFont);
1570 if (symbolicTraits & kCTFontMonoSpaceTrait) {
1571 info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
1573 if (symbolicTraits & kCTFontItalicTrait) {
1574 info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
1576 CTFontStylisticClass stylisticClass = symbolicTraits & kCTFontClassMaskTrait;
1577 if (stylisticClass >= kCTFontOldStyleSerifsClass && stylisticClass <= kCTFontSlabSerifsClass) {
1578 info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
1579 } else if (stylisticClass & kCTFontScriptsClass) {
1580 info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
1582 info->fItalicAngle = (int16_t) CTFontGetSlantAngle(ctFont);
1583 info->fAscent = (int16_t) CTFontGetAscent(ctFont);
1584 info->fDescent = (int16_t) CTFontGetDescent(ctFont);
1585 info->fCapHeight = (int16_t) CTFontGetCapHeight(ctFont);
1586 CGRect bbox = CTFontGetBoundingBox(ctFont);
1589 r.set( CGToScalar(CGRectGetMinX_inline(bbox)), // Left
1590 CGToScalar(CGRectGetMaxY_inline(bbox)), // Top
1591 CGToScalar(CGRectGetMaxX_inline(bbox)), // Right
1592 CGToScalar(CGRectGetMinY_inline(bbox))); // Bottom
1594 r.roundOut(&(info->fBBox));
1596 // Figure out a good guess for StemV - Min width of i, I, !, 1.
1597 // This probably isn't very good with an italic font.
1598 int16_t min_width = SHRT_MAX;
1600 static const UniChar stem_chars[] = {'i', 'I', '!', '1'};
1601 const size_t count = sizeof(stem_chars) / sizeof(stem_chars[0]);
1602 CGGlyph glyphs[count];
1603 CGRect boundingRects[count];
1604 if (CTFontGetGlyphsForCharacters(ctFont, stem_chars, glyphs, count)) {
1605 CTFontGetBoundingRectsForGlyphs(ctFont, kCTFontHorizontalOrientation,
1606 glyphs, boundingRects, count);
1607 for (size_t i = 0; i < count; i++) {
1608 int16_t width = (int16_t) boundingRects[i].size.width;
1609 if (width > 0 && width < min_width) {
1611 info->fStemV = min_width;
1616 if (perGlyphInfo & SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
1617 if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) {
1618 skia_advanced_typeface_metrics_utils::appendRange(&info->fGlyphWidths, 0);
1619 info->fGlyphWidths->fAdvance.append(1, &min_width);
1620 skia_advanced_typeface_metrics_utils::finishRange(info->fGlyphWidths.get(), 0,
1621 SkAdvancedTypefaceMetrics::WidthRange::kDefault);
1623 info->fGlyphWidths.reset(
1624 skia_advanced_typeface_metrics_utils::getAdvanceData(ctFont.get(),
1625 SkToInt(glyphCount),
1634 ///////////////////////////////////////////////////////////////////////////////
1636 static SK_SFNT_ULONG get_font_type_tag(const SkTypeface_Mac* typeface) {
1637 CTFontRef ctFont = typeface->fFontRef.get();
1638 AutoCFRelease<CFNumberRef> fontFormatRef(
1639 static_cast<CFNumberRef>(CTFontCopyAttribute(ctFont, kCTFontFormatAttribute)));
1640 if (!fontFormatRef) {
1644 SInt32 fontFormatValue;
1645 if (!CFNumberGetValue(fontFormatRef, kCFNumberSInt32Type, &fontFormatValue)) {
1649 switch (fontFormatValue) {
1650 case kCTFontFormatOpenTypePostScript:
1651 return SkSFNTHeader::fontType_OpenTypeCFF::TAG;
1652 case kCTFontFormatOpenTypeTrueType:
1653 return SkSFNTHeader::fontType_WindowsTrueType::TAG;
1654 case kCTFontFormatTrueType:
1655 return SkSFNTHeader::fontType_MacTrueType::TAG;
1656 case kCTFontFormatPostScript:
1657 return SkSFNTHeader::fontType_PostScript::TAG;
1658 case kCTFontFormatBitmap:
1659 return SkSFNTHeader::fontType_MacTrueType::TAG;
1660 case kCTFontFormatUnrecognized:
1662 //CT seems to be unreliable in being able to obtain the type,
1663 //even if all we want is the first four bytes of the font resource.
1664 //Just the presence of the FontForge 'FFTM' table seems to throw it off.
1665 return SkSFNTHeader::fontType_WindowsTrueType::TAG;
1669 SkStream* SkTypeface_Mac::onOpenStream(int* ttcIndex) const {
1670 SK_SFNT_ULONG fontType = get_font_type_tag(this);
1671 if (0 == fontType) {
1676 int numTables = this->countTables();
1677 SkTDArray<SkFontTableTag> tableTags;
1678 tableTags.setCount(numTables);
1679 this->getTableTags(tableTags.begin());
1681 // calc total size for font, save sizes
1682 SkTDArray<size_t> tableSizes;
1683 size_t totalSize = sizeof(SkSFNTHeader) + sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables;
1684 for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
1685 size_t tableSize = this->getTableSize(tableTags[tableIndex]);
1686 totalSize += (tableSize + 3) & ~3;
1687 *tableSizes.append() = tableSize;
1690 // reserve memory for stream, and zero it (tables must be zero padded)
1691 SkMemoryStream* stream = new SkMemoryStream(totalSize);
1692 char* dataStart = (char*)stream->getMemoryBase();
1693 sk_bzero(dataStart, totalSize);
1694 char* dataPtr = dataStart;
1696 // compute font header entries
1697 uint16_t entrySelector = 0;
1698 uint16_t searchRange = 1;
1699 while (searchRange < numTables >> 1) {
1704 uint16_t rangeShift = (numTables << 4) - searchRange;
1706 // write font header
1707 SkSFNTHeader* header = (SkSFNTHeader*)dataPtr;
1708 header->fontType = fontType;
1709 header->numTables = SkEndian_SwapBE16(numTables);
1710 header->searchRange = SkEndian_SwapBE16(searchRange);
1711 header->entrySelector = SkEndian_SwapBE16(entrySelector);
1712 header->rangeShift = SkEndian_SwapBE16(rangeShift);
1713 dataPtr += sizeof(SkSFNTHeader);
1716 SkSFNTHeader::TableDirectoryEntry* entry = (SkSFNTHeader::TableDirectoryEntry*)dataPtr;
1717 dataPtr += sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables;
1718 for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
1719 size_t tableSize = tableSizes[tableIndex];
1720 this->getTableData(tableTags[tableIndex], 0, tableSize, dataPtr);
1721 entry->tag = SkEndian_SwapBE32(tableTags[tableIndex]);
1722 entry->checksum = SkEndian_SwapBE32(SkOTUtils::CalcTableChecksum((SK_OT_ULONG*)dataPtr,
1724 entry->offset = SkEndian_SwapBE32(SkToU32(dataPtr - dataStart));
1725 entry->logicalLength = SkEndian_SwapBE32(SkToU32(tableSize));
1727 dataPtr += (tableSize + 3) & ~3;
1734 ///////////////////////////////////////////////////////////////////////////////
1735 ///////////////////////////////////////////////////////////////////////////////
1737 int SkTypeface_Mac::onGetUPEM() const {
1738 AutoCFRelease<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef, NULL));
1739 return CGFontGetUnitsPerEm(cgFont);
1742 SkTypeface::LocalizedStrings* SkTypeface_Mac::onCreateFamilyNameIterator() const {
1743 SkTypeface::LocalizedStrings* nameIter =
1744 SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*this);
1745 if (NULL == nameIter) {
1746 AutoCFRelease<CFStringRef> cfLanguage;
1747 AutoCFRelease<CFStringRef> cfFamilyName(
1748 CTFontCopyLocalizedName(fFontRef, kCTFontFamilyNameKey, &cfLanguage));
1750 SkString skLanguage;
1751 SkString skFamilyName;
1752 if (cfLanguage.get()) {
1753 CFStringToSkString(cfLanguage.get(), &skLanguage);
1755 skLanguage = "und"; //undetermined
1757 if (cfFamilyName.get()) {
1758 CFStringToSkString(cfFamilyName.get(), &skFamilyName);
1761 nameIter = new SkOTUtils::LocalizedStrings_SingleName(skFamilyName, skLanguage);
1766 // If, as is the case with web fonts, the CTFont data isn't available,
1767 // the CGFont data may work. While the CGFont may always provide the
1768 // right result, leave the CTFont code path to minimize disruption.
1769 static CFDataRef copyTableFromFont(CTFontRef ctFont, SkFontTableTag tag) {
1770 CFDataRef data = CTFontCopyTable(ctFont, (CTFontTableTag) tag,
1771 kCTFontTableOptionNoOptions);
1773 AutoCFRelease<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont, NULL));
1774 data = CGFontCopyTableForTag(cgFont, tag);
1779 int SkTypeface_Mac::onGetTableTags(SkFontTableTag tags[]) const {
1780 AutoCFRelease<CFArrayRef> cfArray(CTFontCopyAvailableTables(fFontRef,
1781 kCTFontTableOptionNoOptions));
1782 if (NULL == cfArray) {
1785 int count = SkToInt(CFArrayGetCount(cfArray));
1787 for (int i = 0; i < count; ++i) {
1788 uintptr_t fontTag = reinterpret_cast<uintptr_t>(CFArrayGetValueAtIndex(cfArray, i));
1789 tags[i] = static_cast<SkFontTableTag>(fontTag);
1795 size_t SkTypeface_Mac::onGetTableData(SkFontTableTag tag, size_t offset,
1796 size_t length, void* dstData) const {
1797 AutoCFRelease<CFDataRef> srcData(copyTableFromFont(fFontRef, tag));
1798 if (NULL == srcData) {
1802 size_t srcSize = CFDataGetLength(srcData);
1803 if (offset >= srcSize) {
1806 if (length > srcSize - offset) {
1807 length = srcSize - offset;
1810 memcpy(dstData, CFDataGetBytePtr(srcData) + offset, length);
1815 SkScalerContext* SkTypeface_Mac::onCreateScalerContext(const SkDescriptor* desc) const {
1816 return new SkScalerContext_Mac(const_cast<SkTypeface_Mac*>(this), desc);
1819 void SkTypeface_Mac::onFilterRec(SkScalerContextRec* rec) const {
1820 if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag ||
1821 rec->fFlags & SkScalerContext::kLCD_Vertical_Flag)
1823 rec->fMaskFormat = SkMask::kA8_Format;
1824 // Render the glyphs as close as possible to what was requested.
1825 // The above turns off subpixel rendering, but the user requested it.
1826 // Normal hinting will cause the A8 masks to be generated from CoreGraphics subpixel masks.
1827 // See comments below for more details.
1828 rec->setHinting(SkPaint::kNormal_Hinting);
1831 unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag |
1832 SkScalerContext::kForceAutohinting_Flag |
1833 SkScalerContext::kLCD_BGROrder_Flag |
1834 SkScalerContext::kLCD_Vertical_Flag;
1836 rec->fFlags &= ~flagsWeDontSupport;
1838 bool lcdSupport = supports_LCD();
1840 // Only two levels of hinting are supported.
1841 // kNo_Hinting means avoid CoreGraphics outline dilation.
1842 // kNormal_Hinting means CoreGraphics outline dilation is allowed.
1843 // If there is no lcd support, hinting (dilation) cannot be supported.
1844 SkPaint::Hinting hinting = rec->getHinting();
1845 if (SkPaint::kSlight_Hinting == hinting || !lcdSupport) {
1846 hinting = SkPaint::kNo_Hinting;
1847 } else if (SkPaint::kFull_Hinting == hinting) {
1848 hinting = SkPaint::kNormal_Hinting;
1850 rec->setHinting(hinting);
1852 // FIXME: lcd smoothed un-hinted rasterization unsupported.
1853 // Tracked by http://code.google.com/p/skia/issues/detail?id=915 .
1854 // There is no current means to honor a request for unhinted lcd,
1855 // so arbitrarilly ignore the hinting request and honor lcd.
1857 // Hinting and smoothing should be orthogonal, but currently they are not.
1858 // CoreGraphics has no API to influence hinting. However, its lcd smoothed
1859 // output is drawn from auto-dilated outlines (the amount of which is
1860 // determined by AppleFontSmoothing). Its regular anti-aliased output is
1861 // drawn from un-dilated outlines.
1863 // The behavior of Skia is as follows:
1864 // [AA][no-hint]: generate AA using CoreGraphic's AA output.
1865 // [AA][yes-hint]: use CoreGraphic's LCD output and reduce it to a single
1866 // channel. This matches [LCD][yes-hint] in weight.
1867 // [LCD][no-hint]: curently unable to honor, and must pick which to respect.
1868 // Currenly side with LCD, effectively ignoring the hinting setting.
1869 // [LCD][yes-hint]: generate LCD using CoreGraphic's LCD output.
1871 if (isLCDFormat(rec->fMaskFormat)) {
1873 //CoreGraphics creates 555 masks for smoothed text anyway.
1874 rec->fMaskFormat = SkMask::kLCD16_Format;
1875 rec->setHinting(SkPaint::kNormal_Hinting);
1877 rec->fMaskFormat = SkMask::kA8_Format;
1881 // Unhinted A8 masks (those not derived from LCD masks) must respect SK_GAMMA_APPLY_TO_A8.
1882 // All other masks can use regular gamma.
1883 if (SkMask::kA8_Format == rec->fMaskFormat && SkPaint::kNo_Hinting == hinting) {
1884 #ifndef SK_GAMMA_APPLY_TO_A8
1885 rec->ignorePreBlend();
1888 //CoreGraphics dialates smoothed text as needed.
1889 rec->setContrast(0);
1893 // we take ownership of the ref
1894 static const char* get_str(CFStringRef ref, SkString* str) {
1898 CFStringToSkString(ref, str);
1900 return str->c_str();
1903 void SkTypeface_Mac::onGetFontDescriptor(SkFontDescriptor* desc,
1904 bool* isLocalStream) const {
1907 desc->setFamilyName(get_str(CTFontCopyFamilyName(fFontRef), &tmpStr));
1908 desc->setFullName(get_str(CTFontCopyFullName(fFontRef), &tmpStr));
1909 desc->setPostscriptName(get_str(CTFontCopyPostScriptName(fFontRef), &tmpStr));
1910 *isLocalStream = fIsLocalStream;
1913 int SkTypeface_Mac::onCharsToGlyphs(const void* chars, Encoding encoding,
1914 uint16_t glyphs[], int glyphCount) const
1916 // Undocumented behavior of CTFontGetGlyphsForCharacters with non-bmp code points:
1917 // When a surrogate pair is detected, the glyph index used is the index of the high surrogate.
1918 // It is documented that if a mapping is unavailable, the glyph will be set to 0.
1920 SkAutoSTMalloc<1024, UniChar> charStorage;
1921 const UniChar* src; // UniChar is a UTF-16 16-bit code unit.
1924 case kUTF8_Encoding: {
1925 const char* utf8 = reinterpret_cast<const char*>(chars);
1926 UniChar* utf16 = charStorage.reset(2 * glyphCount);
1928 for (int i = 0; i < glyphCount; ++i) {
1929 SkUnichar uni = SkUTF8_NextUnichar(&utf8);
1930 utf16 += SkUTF16_FromUnichar(uni, utf16);
1932 srcCount = SkToInt(utf16 - src);
1935 case kUTF16_Encoding: {
1936 src = reinterpret_cast<const UniChar*>(chars);
1938 for (int i = 0; i < glyphCount; ++i) {
1939 if (SkUTF16_IsHighSurrogate(src[i + extra])) {
1943 srcCount = glyphCount + extra;
1946 case kUTF32_Encoding: {
1947 const SkUnichar* utf32 = reinterpret_cast<const SkUnichar*>(chars);
1948 UniChar* utf16 = charStorage.reset(2 * glyphCount);
1950 for (int i = 0; i < glyphCount; ++i) {
1951 utf16 += SkUTF16_FromUnichar(utf32[i], utf16);
1953 srcCount = SkToInt(utf16 - src);
1958 // If glyphs is NULL, CT still needs glyph storage for finding the first failure.
1959 // Also, if there are any non-bmp code points, the provided 'glyphs' storage will be inadequate.
1960 SkAutoSTMalloc<1024, uint16_t> glyphStorage;
1961 uint16_t* macGlyphs = glyphs;
1962 if (NULL == macGlyphs || srcCount > glyphCount) {
1963 macGlyphs = glyphStorage.reset(srcCount);
1966 bool allEncoded = CTFontGetGlyphsForCharacters(fFontRef, src, macGlyphs, srcCount);
1968 // If there were any non-bmp, then copy and compact.
1969 // If 'glyphs' is NULL, then compact glyphStorage in-place.
1970 // If all are bmp and 'glyphs' is non-NULL, 'glyphs' already contains the compact glyphs.
1971 // If some are non-bmp and 'glyphs' is non-NULL, copy and compact into 'glyphs'.
1972 uint16_t* compactedGlyphs = glyphs;
1973 if (NULL == compactedGlyphs) {
1974 compactedGlyphs = macGlyphs;
1976 if (srcCount > glyphCount) {
1978 for (int i = 0; i < glyphCount; ++i) {
1979 if (SkUTF16_IsHighSurrogate(src[i + extra])) {
1982 compactedGlyphs[i] = macGlyphs[i + extra];
1990 // If we got false, then we need to manually look for first failure.
1991 for (int i = 0; i < glyphCount; ++i) {
1992 if (0 == compactedGlyphs[i]) {
1996 // Odd to get here, as we expected CT to have returned true up front.
2000 int SkTypeface_Mac::onCountGlyphs() const {
2001 return SkToInt(CTFontGetGlyphCount(fFontRef));
2004 ///////////////////////////////////////////////////////////////////////////////
2005 ///////////////////////////////////////////////////////////////////////////////
2008 static bool find_desc_str(CTFontDescriptorRef desc, CFStringRef name, SkString* value) {
2009 AutoCFRelease<CFStringRef> ref((CFStringRef)CTFontDescriptorCopyAttribute(desc, name));
2010 if (NULL == ref.get()) {
2013 CFStringToSkString(ref, value);
2017 static bool find_dict_float(CFDictionaryRef dict, CFStringRef name, float* value) {
2019 return CFDictionaryGetValueIfPresent(dict, name, (const void**)&num)
2020 && CFNumberIsFloatType(num)
2021 && CFNumberGetValue(num, kCFNumberFloatType, value);
2024 #include "SkFontMgr.h"
2026 static int unit_weight_to_fontstyle(float unit) {
2029 value = 100 + (1 + unit) * 300;
2031 value = 400 + unit * 500;
2033 return sk_float_round2int(value);
2036 static int unit_width_to_fontstyle(float unit) {
2039 value = 1 + (1 + unit) * 4;
2041 value = 5 + unit * 4;
2043 return sk_float_round2int(value);
2046 static inline int sqr(int value) {
2047 SkASSERT(SkAbs32(value) < 0x7FFF); // check for overflow
2048 return value * value;
2051 // We normalize each axis (weight, width, italic) to be base-900
2052 static int compute_metric(const SkFontStyle& a, const SkFontStyle& b) {
2053 return sqr(a.weight() - b.weight()) +
2054 sqr((a.width() - b.width()) * 100) +
2055 sqr((a.isItalic() != b.isItalic()) * 900);
2058 static SkFontStyle desc2fontstyle(CTFontDescriptorRef desc) {
2059 AutoCFRelease<CFDictionaryRef> dict(
2060 (CFDictionaryRef)CTFontDescriptorCopyAttribute(desc,
2061 kCTFontTraitsAttribute));
2062 if (NULL == dict.get()) {
2063 return SkFontStyle();
2066 float weight, width, slant;
2067 if (!find_dict_float(dict, kCTFontWeightTrait, &weight)) {
2070 if (!find_dict_float(dict, kCTFontWidthTrait, &width)) {
2073 if (!find_dict_float(dict, kCTFontSlantTrait, &slant)) {
2077 return SkFontStyle(unit_weight_to_fontstyle(weight),
2078 unit_width_to_fontstyle(width),
2079 slant ? SkFontStyle::kItalic_Slant
2080 : SkFontStyle::kUpright_Slant);
2083 struct NameFontStyleRec {
2084 SkString fFamilyName;
2085 SkFontStyle fFontStyle;
2088 static bool nameFontStyleProc(SkTypeface* face, SkTypeface::Style,
2090 SkTypeface_Mac* macFace = (SkTypeface_Mac*)face;
2091 const NameFontStyleRec* rec = (const NameFontStyleRec*)ctx;
2093 return macFace->fFontStyle == rec->fFontStyle &&
2094 macFace->fName == rec->fFamilyName;
2097 static SkTypeface* createFromDesc(CFStringRef cfFamilyName,
2098 CTFontDescriptorRef desc) {
2099 NameFontStyleRec rec;
2100 CFStringToSkString(cfFamilyName, &rec.fFamilyName);
2101 rec.fFontStyle = desc2fontstyle(desc);
2103 SkTypeface* face = SkTypefaceCache::FindByProcAndRef(nameFontStyleProc,
2109 AutoCFRelease<CFDictionaryRef> fontFamilyNameDictionary(
2110 CFDictionaryCreate(kCFAllocatorDefault,
2111 (const void**)&kCTFontFamilyNameAttribute, (const void**)&cfFamilyName,
2112 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
2113 AutoCFRelease<CTFontDescriptorRef> fontDescriptor(
2114 CTFontDescriptorCreateWithAttributes(fontFamilyNameDictionary));
2115 AutoCFRelease<CTFontRef> ctNamed(CTFontCreateWithFontDescriptor(fontDescriptor, 0, NULL));
2116 CTFontRef ctFont = CTFontCreateCopyWithAttributes(ctNamed, 1, NULL, desc);
2117 if (NULL == ctFont) {
2122 CFStringToSkString(cfFamilyName, &str);
2125 (void)computeStyleBits(ctFont, &isFixedPitch);
2126 SkFontID fontID = CTFontRef_to_SkFontID(ctFont);
2128 face = SkNEW_ARGS(SkTypeface_Mac, (rec.fFontStyle, fontID, isFixedPitch,
2129 ctFont, str.c_str(), false));
2130 SkTypefaceCache::Add(face, face->style());
2134 class SkFontStyleSet_Mac : public SkFontStyleSet {
2136 SkFontStyleSet_Mac(CFStringRef familyName, CTFontDescriptorRef desc)
2137 : fArray(CTFontDescriptorCreateMatchingFontDescriptors(desc, NULL))
2138 , fFamilyName(familyName)
2140 CFRetain(familyName);
2141 if (NULL == fArray) {
2142 fArray = CFArrayCreate(NULL, NULL, 0, NULL);
2144 fCount = SkToInt(CFArrayGetCount(fArray));
2147 virtual ~SkFontStyleSet_Mac() {
2149 CFRelease(fFamilyName);
2152 virtual int count() SK_OVERRIDE {
2156 virtual void getStyle(int index, SkFontStyle* style,
2157 SkString* name) SK_OVERRIDE {
2158 SkASSERT((unsigned)index < (unsigned)fCount);
2159 CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray, index);
2161 *style = desc2fontstyle(desc);
2164 if (!find_desc_str(desc, kCTFontStyleNameAttribute, name)) {
2170 virtual SkTypeface* createTypeface(int index) SK_OVERRIDE {
2171 SkASSERT((unsigned)index < (unsigned)CFArrayGetCount(fArray));
2172 CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray, index);
2174 return createFromDesc(fFamilyName, desc);
2177 virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE {
2181 return createFromDesc(fFamilyName, findMatchingDesc(pattern));
2186 CFStringRef fFamilyName;
2189 CTFontDescriptorRef findMatchingDesc(const SkFontStyle& pattern) const {
2190 int bestMetric = SK_MaxS32;
2191 CTFontDescriptorRef bestDesc = NULL;
2193 for (int i = 0; i < fCount; ++i) {
2194 CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray, i);
2195 int metric = compute_metric(pattern, desc2fontstyle(desc));
2199 if (metric < bestMetric) {
2200 bestMetric = metric;
2209 class SkFontMgr_Mac : public SkFontMgr {
2213 CFStringRef stringAt(int index) const {
2214 SkASSERT((unsigned)index < (unsigned)fCount);
2215 return (CFStringRef)CFArrayGetValueAtIndex(fNames, index);
2218 static SkFontStyleSet* CreateSet(CFStringRef cfFamilyName) {
2219 AutoCFRelease<CFMutableDictionaryRef> cfAttr(
2220 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2221 &kCFTypeDictionaryKeyCallBacks,
2222 &kCFTypeDictionaryValueCallBacks));
2224 CFDictionaryAddValue(cfAttr, kCTFontFamilyNameAttribute, cfFamilyName);
2226 AutoCFRelease<CTFontDescriptorRef> desc(
2227 CTFontDescriptorCreateWithAttributes(cfAttr));
2228 return SkNEW_ARGS(SkFontStyleSet_Mac, (cfFamilyName, desc));
2233 : fNames(SkCTFontManagerCopyAvailableFontFamilyNames())
2234 , fCount(fNames ? SkToInt(CFArrayGetCount(fNames)) : 0) {}
2236 virtual ~SkFontMgr_Mac() {
2237 CFSafeRelease(fNames);
2241 virtual int onCountFamilies() const SK_OVERRIDE {
2245 virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERRIDE {
2246 if ((unsigned)index < (unsigned)fCount) {
2247 CFStringToSkString(this->stringAt(index), familyName);
2249 familyName->reset();
2253 virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE {
2254 if ((unsigned)index >= (unsigned)fCount) {
2257 return CreateSet(this->stringAt(index));
2260 virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVERRIDE {
2261 AutoCFRelease<CFStringRef> cfName(make_CFString(familyName));
2262 return CreateSet(cfName);
2265 virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
2266 const SkFontStyle&) const SK_OVERRIDE {
2270 virtual SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember,
2271 const SkFontStyle&) const SK_OVERRIDE {
2275 virtual SkTypeface* onCreateFromData(SkData* data,
2276 int ttcIndex) const SK_OVERRIDE {
2277 AutoCFRelease<CGDataProviderRef> pr(SkCreateDataProviderFromData(data));
2281 return create_from_dataProvider(pr);
2284 virtual SkTypeface* onCreateFromStream(SkStream* stream,
2285 int ttcIndex) const SK_OVERRIDE {
2286 AutoCFRelease<CGDataProviderRef> pr(SkCreateDataProviderFromStream(stream));
2290 return create_from_dataProvider(pr);
2293 virtual SkTypeface* onCreateFromFile(const char path[],
2294 int ttcIndex) const SK_OVERRIDE {
2295 AutoCFRelease<CGDataProviderRef> pr(CGDataProviderCreateWithFilename(path));
2299 return create_from_dataProvider(pr);
2302 virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
2303 unsigned styleBits) const SK_OVERRIDE {
2304 return create_typeface(NULL, familyName, (SkTypeface::Style)styleBits);
2308 ///////////////////////////////////////////////////////////////////////////////
2310 SkFontMgr* SkFontMgr::Factory() {
2311 return SkNEW(SkFontMgr_Mac);