1
2 /*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9 #include <vector>
10 #ifdef SK_BUILD_FOR_MAC
11 #import <ApplicationServices/ApplicationServices.h>
12 #endif
13
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>
19 #endif
20
21 #include "SkFontHost.h"
22 #include "SkCGUtils.h"
23 #include "SkColorPriv.h"
24 #include "SkDescriptor.h"
25 #include "SkEndian.h"
26 #include "SkFontDescriptor.h"
27 #include "SkFloatingPoint.h"
28 #include "SkGlyph.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"
36 #include "SkPaint.h"
37 #include "SkPath.h"
38 #include "SkString.h"
39 #include "SkStream.h"
40 #include "SkThread.h"
41 #include "SkTypeface_mac.h"
42 #include "SkUtils.h"
43 #include "SkTypefaceCache.h"
44 #include "SkFontMgr.h"
45 #include "SkUtils.h"
46
47 //#define HACK_COLORGLYPHS
48
49 class SkScalerContext_Mac;
50
51 // CTFontManagerCopyAvailableFontFamilyNames() is not always available, so we
52 // provide a wrapper here that will return an empty array if need be.
SkCTFontManagerCopyAvailableFontFamilyNames()53 static CFArrayRef SkCTFontManagerCopyAvailableFontFamilyNames() {
54 #ifdef SK_BUILD_FOR_IOS
55 return CFArrayCreate(NULL, NULL, 0, NULL);
56 #else
57 return CTFontManagerCopyAvailableFontFamilyNames();
58 #endif
59 }
60
61
62 // Being templated and taking const T* prevents calling
63 // CFSafeRelease(autoCFRelease) through implicit conversion.
CFSafeRelease(const T * cfTypeRef)64 template <typename T> static void CFSafeRelease(/*CFTypeRef*/const T* cfTypeRef) {
65 if (cfTypeRef) {
66 CFRelease(cfTypeRef);
67 }
68 }
69
70 // Being templated and taking const T* prevents calling
71 // CFSafeRetain(autoCFRelease) through implicit conversion.
CFSafeRetain(const T * cfTypeRef)72 template <typename T> static void CFSafeRetain(/*CFTypeRef*/const T* cfTypeRef) {
73 if (cfTypeRef) {
74 CFRetain(cfTypeRef);
75 }
76 }
77
78 /** Acts like a CFRef, but calls CFSafeRelease when it goes out of scope. */
79 template<typename CFRef> class AutoCFRelease : private SkNoncopyable {
80 public:
AutoCFRelease(CFRef cfRef=NULL)81 explicit AutoCFRelease(CFRef cfRef = NULL) : fCFRef(cfRef) { }
~AutoCFRelease()82 ~AutoCFRelease() { CFSafeRelease(fCFRef); }
83
reset(CFRef that=NULL)84 void reset(CFRef that = NULL) {
85 CFSafeRetain(that);
86 CFSafeRelease(fCFRef);
87 fCFRef = that;
88 }
89
operator =(CFRef that)90 AutoCFRelease& operator =(CFRef that) {
91 reset(that);
92 return *this;
93 }
94
operator CFRef() const95 operator CFRef() const { return fCFRef; }
get() const96 CFRef get() const { return fCFRef; }
97
operator &()98 CFRef* operator&() { SkASSERT(fCFRef == NULL); return &fCFRef; }
99 private:
100 CFRef fCFRef;
101 };
102
make_CFString(const char str[])103 static CFStringRef make_CFString(const char str[]) {
104 return CFStringCreateWithCString(NULL, str, kCFStringEncodingUTF8);
105 }
106
107 template<typename T> class AutoCGTable : SkNoncopyable {
108 public:
AutoCGTable(CGFontRef font)109 AutoCGTable(CGFontRef font)
110 //Undocumented: the tag parameter in this call is expected in machine order and not BE order.
111 : fCFData(CGFontCopyTableForTag(font, SkSetFourByteTag(T::TAG0, T::TAG1, T::TAG2, T::TAG3)))
112 , fData(fCFData ? reinterpret_cast<const T*>(CFDataGetBytePtr(fCFData)) : NULL)
113 { }
114
operator ->() const115 const T* operator->() const { return fData; }
116
117 private:
118 AutoCFRelease<CFDataRef> fCFData;
119 public:
120 const T* fData;
121 };
122
123 // inline versions of these rect helpers
124
CGRectIsEmpty_inline(const CGRect & rect)125 static bool CGRectIsEmpty_inline(const CGRect& rect) {
126 return rect.size.width <= 0 || rect.size.height <= 0;
127 }
128
CGRectGetMinX_inline(const CGRect & rect)129 static CGFloat CGRectGetMinX_inline(const CGRect& rect) {
130 return rect.origin.x;
131 }
132
CGRectGetMaxX_inline(const CGRect & rect)133 static CGFloat CGRectGetMaxX_inline(const CGRect& rect) {
134 return rect.origin.x + rect.size.width;
135 }
136
CGRectGetMinY_inline(const CGRect & rect)137 static CGFloat CGRectGetMinY_inline(const CGRect& rect) {
138 return rect.origin.y;
139 }
140
CGRectGetMaxY_inline(const CGRect & rect)141 static CGFloat CGRectGetMaxY_inline(const CGRect& rect) {
142 return rect.origin.y + rect.size.height;
143 }
144
CGRectGetWidth_inline(const CGRect & rect)145 static CGFloat CGRectGetWidth_inline(const CGRect& rect) {
146 return rect.size.width;
147 }
148
149 ///////////////////////////////////////////////////////////////////////////////
150
sk_memset_rect32(uint32_t * ptr,uint32_t value,int width,int height,size_t rowBytes)151 static void sk_memset_rect32(uint32_t* ptr, uint32_t value,
152 int width, int height, size_t rowBytes) {
153 SkASSERT(width);
154 SkASSERT(width * sizeof(uint32_t) <= rowBytes);
155
156 if (width >= 32) {
157 while (height) {
158 sk_memset32(ptr, value, width);
159 ptr = (uint32_t*)((char*)ptr + rowBytes);
160 height -= 1;
161 }
162 return;
163 }
164
165 rowBytes -= width * sizeof(uint32_t);
166
167 if (width >= 8) {
168 while (height) {
169 int w = width;
170 do {
171 *ptr++ = value; *ptr++ = value;
172 *ptr++ = value; *ptr++ = value;
173 *ptr++ = value; *ptr++ = value;
174 *ptr++ = value; *ptr++ = value;
175 w -= 8;
176 } while (w >= 8);
177 while (--w >= 0) {
178 *ptr++ = value;
179 }
180 ptr = (uint32_t*)((char*)ptr + rowBytes);
181 height -= 1;
182 }
183 } else {
184 while (height) {
185 int w = width;
186 do {
187 *ptr++ = value;
188 } while (--w > 0);
189 ptr = (uint32_t*)((char*)ptr + rowBytes);
190 height -= 1;
191 }
192 }
193 }
194
195 #include <sys/utsname.h>
196
197 typedef uint32_t CGRGBPixel;
198
CGRGBPixel_getAlpha(CGRGBPixel pixel)199 static unsigned CGRGBPixel_getAlpha(CGRGBPixel pixel) {
200 return pixel & 0xFF;
201 }
202
203 // The calls to support subpixel are present in 10.5, but are not included in
204 // the 10.5 SDK. The needed calls have been extracted from the 10.6 SDK and are
205 // included below. To verify that CGContextSetShouldSubpixelQuantizeFonts, for
206 // instance, is present in the 10.5 CoreGraphics libary, use:
207 // cd /Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/
208 // cd ApplicationServices.framework/Frameworks/CoreGraphics.framework/
209 // nm CoreGraphics | grep CGContextSetShouldSubpixelQuantizeFonts
210
211 #if !defined(MAC_OS_X_VERSION_10_6) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6)
212 CG_EXTERN void CGContextSetAllowsFontSmoothing(CGContextRef context, bool value);
213 CG_EXTERN void CGContextSetAllowsFontSubpixelPositioning(CGContextRef context, bool value);
214 CG_EXTERN void CGContextSetShouldSubpixelPositionFonts(CGContextRef context, bool value);
215 CG_EXTERN void CGContextSetAllowsFontSubpixelQuantization(CGContextRef context, bool value);
216 CG_EXTERN void CGContextSetShouldSubpixelQuantizeFonts(CGContextRef context, bool value);
217 #endif
218
219 static const char FONT_DEFAULT_NAME[] = "Lucida Sans";
220
221 // See Source/WebKit/chromium/base/mac/mac_util.mm DarwinMajorVersionInternal for original source.
readVersion()222 static int readVersion() {
223 struct utsname info;
224 if (uname(&info) != 0) {
225 SkDebugf("uname failed\n");
226 return 0;
227 }
228 if (strcmp(info.sysname, "Darwin") != 0) {
229 SkDebugf("unexpected uname sysname %s\n", info.sysname);
230 return 0;
231 }
232 char* dot = strchr(info.release, '.');
233 if (!dot) {
234 SkDebugf("expected dot in uname release %s\n", info.release);
235 return 0;
236 }
237 int version = atoi(info.release);
238 if (version == 0) {
239 SkDebugf("could not parse uname release %s\n", info.release);
240 }
241 return version;
242 }
243
darwinVersion()244 static int darwinVersion() {
245 static int darwin_version = readVersion();
246 return darwin_version;
247 }
248
isSnowLeopard()249 static bool isSnowLeopard() {
250 return darwinVersion() == 10;
251 }
252
isLion()253 static bool isLion() {
254 return darwinVersion() == 11;
255 }
256
isMountainLion()257 static bool isMountainLion() {
258 return darwinVersion() == 12;
259 }
260
isLCDFormat(unsigned format)261 static bool isLCDFormat(unsigned format) {
262 return SkMask::kLCD16_Format == format || SkMask::kLCD32_Format == format;
263 }
264
ScalarToCG(SkScalar scalar)265 static CGFloat ScalarToCG(SkScalar scalar) {
266 if (sizeof(CGFloat) == sizeof(float)) {
267 return SkScalarToFloat(scalar);
268 } else {
269 SkASSERT(sizeof(CGFloat) == sizeof(double));
270 return (CGFloat) SkScalarToDouble(scalar);
271 }
272 }
273
CGToScalar(CGFloat cgFloat)274 static SkScalar CGToScalar(CGFloat cgFloat) {
275 if (sizeof(CGFloat) == sizeof(float)) {
276 return cgFloat;
277 } else {
278 SkASSERT(sizeof(CGFloat) == sizeof(double));
279 return SkDoubleToScalar(cgFloat);
280 }
281 }
282
MatrixToCGAffineTransform(const SkMatrix & matrix,SkScalar sx=SK_Scalar1,SkScalar sy=SK_Scalar1)283 static CGAffineTransform MatrixToCGAffineTransform(const SkMatrix& matrix,
284 SkScalar sx = SK_Scalar1,
285 SkScalar sy = SK_Scalar1) {
286 return CGAffineTransformMake( ScalarToCG(matrix[SkMatrix::kMScaleX] * sx),
287 -ScalarToCG(matrix[SkMatrix::kMSkewY] * sy),
288 -ScalarToCG(matrix[SkMatrix::kMSkewX] * sx),
289 ScalarToCG(matrix[SkMatrix::kMScaleY] * sy),
290 ScalarToCG(matrix[SkMatrix::kMTransX] * sx),
291 ScalarToCG(matrix[SkMatrix::kMTransY] * sy));
292 }
293
294 ///////////////////////////////////////////////////////////////////////////////
295
296 #define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host)
297 #define BITMAP_INFO_GRAY (kCGImageAlphaNone)
298
299 /**
300 * There does not appear to be a publicly accessable API for determining if lcd
301 * font smoothing will be applied if we request it. The main issue is that if
302 * smoothing is applied a gamma of 2.0 will be used, if not a gamma of 1.0.
303 */
supports_LCD()304 static bool supports_LCD() {
305 static int gSupportsLCD = -1;
306 if (gSupportsLCD >= 0) {
307 return (bool) gSupportsLCD;
308 }
309 uint32_t rgb = 0;
310 AutoCFRelease<CGColorSpaceRef> colorspace(CGColorSpaceCreateDeviceRGB());
311 AutoCFRelease<CGContextRef> cgContext(CGBitmapContextCreate(&rgb, 1, 1, 8, 4,
312 colorspace, BITMAP_INFO_RGB));
313 CGContextSelectFont(cgContext, "Helvetica", 16, kCGEncodingMacRoman);
314 CGContextSetShouldSmoothFonts(cgContext, true);
315 CGContextSetShouldAntialias(cgContext, true);
316 CGContextSetTextDrawingMode(cgContext, kCGTextFill);
317 CGContextSetGrayFillColor(cgContext, 1, 1);
318 CGContextShowTextAtPoint(cgContext, -1, 0, "|", 1);
319 uint32_t r = (rgb >> 16) & 0xFF;
320 uint32_t g = (rgb >> 8) & 0xFF;
321 uint32_t b = (rgb >> 0) & 0xFF;
322 gSupportsLCD = (r != g || r != b);
323 return (bool) gSupportsLCD;
324 }
325
326 class Offscreen {
327 public:
328 Offscreen();
329
330 CGRGBPixel* getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
331 CGGlyph glyphID, size_t* rowBytesPtr,
332 bool generateA8FromLCD);
333
334 private:
335 enum {
336 kSize = 32 * 32 * sizeof(CGRGBPixel)
337 };
338 SkAutoSMalloc<kSize> fImageStorage;
339 AutoCFRelease<CGColorSpaceRef> fRGBSpace;
340
341 // cached state
342 AutoCFRelease<CGContextRef> fCG;
343 SkISize fSize;
344 bool fDoAA;
345 bool fDoLCD;
346
RoundSize(int dimension)347 static int RoundSize(int dimension) {
348 return SkNextPow2(dimension);
349 }
350 };
351
Offscreen()352 Offscreen::Offscreen() : fRGBSpace(NULL), fCG(NULL),
353 fDoAA(false), fDoLCD(false) {
354 fSize.set(0, 0);
355 }
356
357 ///////////////////////////////////////////////////////////////////////////////
358
computeStyleBits(CTFontRef font,bool * isFixedPitch)359 static SkTypeface::Style computeStyleBits(CTFontRef font, bool* isFixedPitch) {
360 unsigned style = SkTypeface::kNormal;
361 CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(font);
362
363 if (traits & kCTFontBoldTrait) {
364 style |= SkTypeface::kBold;
365 }
366 if (traits & kCTFontItalicTrait) {
367 style |= SkTypeface::kItalic;
368 }
369 if (isFixedPitch) {
370 *isFixedPitch = (traits & kCTFontMonoSpaceTrait) != 0;
371 }
372 return (SkTypeface::Style)style;
373 }
374
CTFontRef_to_SkFontID(CTFontRef fontRef)375 static SkFontID CTFontRef_to_SkFontID(CTFontRef fontRef) {
376 SkFontID id = 0;
377 // CTFontGetPlatformFont and ATSFontRef are not supported on iOS, so we have to
378 // bracket this to be Mac only.
379 #ifdef SK_BUILD_FOR_MAC
380 ATSFontRef ats = CTFontGetPlatformFont(fontRef, NULL);
381 id = (SkFontID)ats;
382 if (id != 0) {
383 id &= 0x3FFFFFFF; // make top two bits 00
384 return id;
385 }
386 #endif
387 // CTFontGetPlatformFont returns NULL if the font is local
388 // (e.g., was created by a CSS3 @font-face rule).
389 AutoCFRelease<CGFontRef> cgFont(CTFontCopyGraphicsFont(fontRef, NULL));
390 AutoCGTable<SkOTTableHead> headTable(cgFont);
391 if (headTable.fData) {
392 id = (SkFontID) headTable->checksumAdjustment;
393 id = (id & 0x3FFFFFFF) | 0x40000000; // make top two bits 01
394 }
395 // well-formed fonts have checksums, but as a last resort, use the pointer.
396 if (id == 0) {
397 id = (SkFontID) (uintptr_t) fontRef;
398 id = (id & 0x3FFFFFFF) | 0x80000000; // make top two bits 10
399 }
400 return id;
401 }
402
stylebits2fontstyle(SkTypeface::Style styleBits)403 static SkFontStyle stylebits2fontstyle(SkTypeface::Style styleBits) {
404 return SkFontStyle((styleBits & SkTypeface::kBold)
405 ? SkFontStyle::kBold_Weight
406 : SkFontStyle::kNormal_Weight,
407 SkFontStyle::kNormal_Width,
408 (styleBits & SkTypeface::kItalic)
409 ? SkFontStyle::kItalic_Slant
410 : SkFontStyle::kUpright_Slant);
411 }
412
413 #define WEIGHT_THRESHOLD ((SkFontStyle::kNormal_Weight + SkFontStyle::kBold_Weight)/2)
414
fontstyle2stylebits(const SkFontStyle & fs)415 static SkTypeface::Style fontstyle2stylebits(const SkFontStyle& fs) {
416 unsigned style = 0;
417 if (fs.width() >= WEIGHT_THRESHOLD) {
418 style |= SkTypeface::kBold;
419 }
420 if (fs.isItalic()) {
421 style |= SkTypeface::kItalic;
422 }
423 return (SkTypeface::Style)style;
424 }
425
426 class SkTypeface_Mac : public SkTypeface {
427 public:
SkTypeface_Mac(SkTypeface::Style style,SkFontID fontID,bool isFixedPitch,CTFontRef fontRef,const char name[])428 SkTypeface_Mac(SkTypeface::Style style, SkFontID fontID, bool isFixedPitch,
429 CTFontRef fontRef, const char name[])
430 : SkTypeface(style, fontID, isFixedPitch)
431 , fName(name)
432 , fFontRef(fontRef) // caller has already called CFRetain for us
433 , fFontStyle(stylebits2fontstyle(style))
434 {
435 SkASSERT(fontRef);
436 }
437
SkTypeface_Mac(const SkFontStyle & fs,SkFontID fontID,bool isFixedPitch,CTFontRef fontRef,const char name[])438 SkTypeface_Mac(const SkFontStyle& fs, SkFontID fontID, bool isFixedPitch,
439 CTFontRef fontRef, const char name[])
440 : SkTypeface(fontstyle2stylebits(fs), fontID, isFixedPitch)
441 , fName(name)
442 , fFontRef(fontRef) // caller has already called CFRetain for us
443 , fFontStyle(fs)
444 {
445 SkASSERT(fontRef);
446 }
447
448 SkString fName;
449 AutoCFRelease<CTFontRef> fFontRef;
450 SkFontStyle fFontStyle;
451
452 protected:
453 friend class SkFontHost; // to access our protected members for deprecated methods
454
455 virtual int onGetUPEM() const SK_OVERRIDE;
456 virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE;
457 virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const SK_OVERRIDE;
458 virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE;
459 virtual size_t onGetTableData(SkFontTableTag, size_t offset,
460 size_t length, void* data) const SK_OVERRIDE;
461 virtual SkScalerContext* onCreateScalerContext(const SkDescriptor*) const SK_OVERRIDE;
462 virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE;
463 virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE;
464 virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics(
465 SkAdvancedTypefaceMetrics::PerGlyphInfo,
466 const uint32_t*, uint32_t) const SK_OVERRIDE;
467 virtual int onCharsToGlyphs(const void* chars, Encoding, uint16_t glyphs[],
468 int glyphCount) const SK_OVERRIDE;
469 virtual int onCountGlyphs() const SK_OVERRIDE;
470
471 private:
472
473 typedef SkTypeface INHERITED;
474 };
475
NewFromFontRef(CTFontRef fontRef,const char name[])476 static SkTypeface* NewFromFontRef(CTFontRef fontRef, const char name[]) {
477 SkASSERT(fontRef);
478 bool isFixedPitch;
479 SkTypeface::Style style = computeStyleBits(fontRef, &isFixedPitch);
480 SkFontID fontID = CTFontRef_to_SkFontID(fontRef);
481
482 return new SkTypeface_Mac(style, fontID, isFixedPitch, fontRef, name);
483 }
484
NewFromName(const char familyName[],SkTypeface::Style theStyle)485 static SkTypeface* NewFromName(const char familyName[], SkTypeface::Style theStyle) {
486 CTFontRef ctFont = NULL;
487
488 CTFontSymbolicTraits ctFontTraits = 0;
489 if (theStyle & SkTypeface::kBold) {
490 ctFontTraits |= kCTFontBoldTrait;
491 }
492 if (theStyle & SkTypeface::kItalic) {
493 ctFontTraits |= kCTFontItalicTrait;
494 }
495
496 // Create the font info
497 AutoCFRelease<CFStringRef> cfFontName(make_CFString(familyName));
498
499 AutoCFRelease<CFNumberRef> cfFontTraits(
500 CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &ctFontTraits));
501
502 AutoCFRelease<CFMutableDictionaryRef> cfAttributes(
503 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
504 &kCFTypeDictionaryKeyCallBacks,
505 &kCFTypeDictionaryValueCallBacks));
506
507 AutoCFRelease<CFMutableDictionaryRef> cfTraits(
508 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
509 &kCFTypeDictionaryKeyCallBacks,
510 &kCFTypeDictionaryValueCallBacks));
511
512 // Create the font
513 if (cfFontName != NULL && cfFontTraits != NULL && cfAttributes != NULL && cfTraits != NULL) {
514 CFDictionaryAddValue(cfTraits, kCTFontSymbolicTrait, cfFontTraits);
515
516 CFDictionaryAddValue(cfAttributes, kCTFontFamilyNameAttribute, cfFontName);
517 CFDictionaryAddValue(cfAttributes, kCTFontTraitsAttribute, cfTraits);
518
519 AutoCFRelease<CTFontDescriptorRef> ctFontDesc(
520 CTFontDescriptorCreateWithAttributes(cfAttributes));
521
522 if (ctFontDesc != NULL) {
523 ctFont = CTFontCreateWithFontDescriptor(ctFontDesc, 0, NULL);
524 }
525 }
526
527 return ctFont ? NewFromFontRef(ctFont, familyName) : NULL;
528 }
529
GetDefaultFace()530 static SkTypeface* GetDefaultFace() {
531 SK_DECLARE_STATIC_MUTEX(gMutex);
532 SkAutoMutexAcquire ma(gMutex);
533
534 static SkTypeface* gDefaultFace;
535
536 if (NULL == gDefaultFace) {
537 gDefaultFace = NewFromName(FONT_DEFAULT_NAME, SkTypeface::kNormal);
538 SkTypefaceCache::Add(gDefaultFace, SkTypeface::kNormal);
539 }
540 return gDefaultFace;
541 }
542
543 ///////////////////////////////////////////////////////////////////////////////
544
545 extern CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face);
SkTypeface_GetCTFontRef(const SkTypeface * face)546 CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face) {
547 const SkTypeface_Mac* macface = (const SkTypeface_Mac*)face;
548 return macface ? macface->fFontRef.get() : NULL;
549 }
550
551 /* This function is visible on the outside. It first searches the cache, and if
552 * not found, returns a new entry (after adding it to the cache).
553 */
SkCreateTypefaceFromCTFont(CTFontRef fontRef)554 SkTypeface* SkCreateTypefaceFromCTFont(CTFontRef fontRef) {
555 SkFontID fontID = CTFontRef_to_SkFontID(fontRef);
556 SkTypeface* face = SkTypefaceCache::FindByID(fontID);
557 if (face) {
558 face->ref();
559 } else {
560 face = NewFromFontRef(fontRef, NULL);
561 SkTypefaceCache::Add(face, face->style());
562 // NewFromFontRef doesn't retain the parameter, but the typeface it
563 // creates does release it in its destructor, so we balance that with
564 // a retain call here.
565 CFRetain(fontRef);
566 }
567 SkASSERT(face->getRefCnt() > 1);
568 return face;
569 }
570
571 struct NameStyleRec {
572 const char* fName;
573 SkTypeface::Style fStyle;
574 };
575
FindByNameStyle(SkTypeface * face,SkTypeface::Style style,void * ctx)576 static bool FindByNameStyle(SkTypeface* face, SkTypeface::Style style,
577 void* ctx) {
578 const SkTypeface_Mac* mface = reinterpret_cast<SkTypeface_Mac*>(face);
579 const NameStyleRec* rec = reinterpret_cast<const NameStyleRec*>(ctx);
580
581 return rec->fStyle == style && mface->fName.equals(rec->fName);
582 }
583
map_css_names(const char * name)584 static const char* map_css_names(const char* name) {
585 static const struct {
586 const char* fFrom; // name the caller specified
587 const char* fTo; // "canonical" name we map to
588 } gPairs[] = {
589 { "sans-serif", "Helvetica" },
590 { "serif", "Times" },
591 { "monospace", "Courier" }
592 };
593
594 for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
595 if (strcmp(name, gPairs[i].fFrom) == 0) {
596 return gPairs[i].fTo;
597 }
598 }
599 return name; // no change
600 }
601
create_typeface(const SkTypeface * familyFace,const char familyName[],SkTypeface::Style style)602 static SkTypeface* create_typeface(const SkTypeface* familyFace,
603 const char familyName[],
604 SkTypeface::Style style) {
605 if (familyName) {
606 familyName = map_css_names(familyName);
607 }
608
609 // Clone an existing typeface
610 // TODO: only clone if style matches the familyFace's style...
611 if (familyName == NULL && familyFace != NULL) {
612 familyFace->ref();
613 return const_cast<SkTypeface*>(familyFace);
614 }
615
616 if (!familyName || !*familyName) {
617 familyName = FONT_DEFAULT_NAME;
618 }
619
620 NameStyleRec rec = { familyName, style };
621 SkTypeface* face = SkTypefaceCache::FindByProcAndRef(FindByNameStyle, &rec);
622
623 if (NULL == face) {
624 face = NewFromName(familyName, style);
625 if (face) {
626 SkTypefaceCache::Add(face, style);
627 } else {
628 face = GetDefaultFace();
629 face->ref();
630 }
631 }
632 return face;
633 }
634
635 ///////////////////////////////////////////////////////////////////////////////
636
637 /** GlyphRect is in FUnits (em space, y up). */
638 struct GlyphRect {
639 int16_t fMinX;
640 int16_t fMinY;
641 int16_t fMaxX;
642 int16_t fMaxY;
643 };
644
645 class SkScalerContext_Mac : public SkScalerContext {
646 public:
647 SkScalerContext_Mac(SkTypeface_Mac*, const SkDescriptor*);
648
649 protected:
650 unsigned generateGlyphCount(void) SK_OVERRIDE;
651 uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE;
652 void generateAdvance(SkGlyph* glyph) SK_OVERRIDE;
653 void generateMetrics(SkGlyph* glyph) SK_OVERRIDE;
654 void generateImage(const SkGlyph& glyph) SK_OVERRIDE;
655 void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE;
656 void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY) SK_OVERRIDE;
657
658 private:
659 static void CTPathElement(void *info, const CGPathElement *element);
660
661 /** Returns the offset from the horizontal origin to the vertical origin in SkGlyph units. */
662 void getVerticalOffset(CGGlyph glyphID, SkPoint* offset) const;
663
664 /** Initializes and returns the value of fFBoundingBoxesGlyphOffset.
665 *
666 * For use with (and must be called before) generateBBoxes.
667 */
668 uint16_t getFBoundingBoxesGlyphOffset();
669
670 /** Initializes fFBoundingBoxes and returns true on success.
671 *
672 * On Lion and Mountain Lion, CTFontGetBoundingRectsForGlyphs has a bug which causes it to
673 * return a bad value in bounds.origin.x for SFNT fonts whose hhea::numberOfHMetrics is
674 * less than its maxp::numGlyphs. When this is the case we try to read the bounds from the
675 * font directly.
676 *
677 * This routine initializes fFBoundingBoxes to an array of
678 * fGlyphCount - fFBoundingBoxesGlyphOffset GlyphRects which contain the bounds in FUnits
679 * (em space, y up) of glyphs with ids in the range [fFBoundingBoxesGlyphOffset, fGlyphCount).
680 *
681 * Returns true if fFBoundingBoxes is properly initialized. The table can only be properly
682 * initialized for a TrueType font with 'head', 'loca', and 'glyf' tables.
683 *
684 * TODO: A future optimization will compute fFBoundingBoxes once per fCTFont.
685 */
686 bool generateBBoxes();
687
688 /** Converts from FUnits (em space, y up) to SkGlyph units (pixels, y down).
689 *
690 * Used on Snow Leopard to correct CTFontGetVerticalTranslationsForGlyphs.
691 * Used on Lion to correct CTFontGetBoundingRectsForGlyphs.
692 */
693 SkMatrix fFUnitMatrix;
694
695 Offscreen fOffscreen;
696 AutoCFRelease<CTFontRef> fCTFont;
697
698 /** Vertical variant of fCTFont.
699 *
700 * CT vertical metrics are pre-rotated (in em space, before transform) 90deg clock-wise.
701 * This makes kCTFontDefaultOrientation dangerous, because the metrics from
702 * kCTFontHorizontalOrientation are in a different space from kCTFontVerticalOrientation.
703 * Use fCTVerticalFont with kCTFontVerticalOrientation to get metrics in the same space.
704 */
705 AutoCFRelease<CTFontRef> fCTVerticalFont;
706
707 AutoCFRelease<CGFontRef> fCGFont;
708 SkAutoTMalloc<GlyphRect> fFBoundingBoxes;
709 uint16_t fFBoundingBoxesGlyphOffset;
710 uint16_t fGlyphCount;
711 bool fGeneratedFBoundingBoxes;
712 const bool fDoSubPosition;
713 const bool fVertical;
714
715 friend class Offscreen;
716
717 typedef SkScalerContext INHERITED;
718 };
719
SkScalerContext_Mac(SkTypeface_Mac * typeface,const SkDescriptor * desc)720 SkScalerContext_Mac::SkScalerContext_Mac(SkTypeface_Mac* typeface,
721 const SkDescriptor* desc)
722 : INHERITED(typeface, desc)
723 , fFBoundingBoxes()
724 , fFBoundingBoxesGlyphOffset(0)
725 , fGeneratedFBoundingBoxes(false)
726 , fDoSubPosition(SkToBool(fRec.fFlags & kSubpixelPositioning_Flag))
727 , fVertical(SkToBool(fRec.fFlags & kVertical_Flag))
728
729 {
730 CTFontRef ctFont = typeface->fFontRef.get();
731 CFIndex numGlyphs = CTFontGetGlyphCount(ctFont);
732 SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF);
733 fGlyphCount = SkToU16(numGlyphs);
734
735 fRec.getSingleMatrix(&fFUnitMatrix);
736 CGAffineTransform transform = MatrixToCGAffineTransform(fFUnitMatrix);
737
738 AutoCFRelease<CTFontDescriptorRef> ctFontDesc;
739 if (fVertical) {
740 AutoCFRelease<CFMutableDictionaryRef> cfAttributes(CFDictionaryCreateMutable(
741 kCFAllocatorDefault, 0,
742 &kCFTypeDictionaryKeyCallBacks,
743 &kCFTypeDictionaryValueCallBacks));
744 if (cfAttributes) {
745 CTFontOrientation ctOrientation = kCTFontVerticalOrientation;
746 AutoCFRelease<CFNumberRef> cfVertical(CFNumberCreate(
747 kCFAllocatorDefault, kCFNumberSInt32Type, &ctOrientation));
748 CFDictionaryAddValue(cfAttributes, kCTFontOrientationAttribute, cfVertical);
749 ctFontDesc = CTFontDescriptorCreateWithAttributes(cfAttributes);
750 }
751 }
752 // Since our matrix includes everything, we pass 1 for size.
753 fCTFont = CTFontCreateCopyWithAttributes(ctFont, 1, &transform, ctFontDesc);
754 fCGFont = CTFontCopyGraphicsFont(fCTFont, NULL);
755 if (fVertical) {
756 CGAffineTransform rotateLeft = CGAffineTransformMake(0, -1, 1, 0, 0, 0);
757 transform = CGAffineTransformConcat(rotateLeft, transform);
758 fCTVerticalFont = CTFontCreateCopyWithAttributes(ctFont, 1, &transform, NULL);
759 }
760
761 SkScalar emPerFUnit = SkScalarInvert(SkIntToScalar(CGFontGetUnitsPerEm(fCGFont)));
762 fFUnitMatrix.preScale(emPerFUnit, -emPerFUnit);
763 }
764
getCG(const SkScalerContext_Mac & context,const SkGlyph & glyph,CGGlyph glyphID,size_t * rowBytesPtr,bool generateA8FromLCD)765 CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
766 CGGlyph glyphID, size_t* rowBytesPtr,
767 bool generateA8FromLCD) {
768 if (!fRGBSpace) {
769 //It doesn't appear to matter what color space is specified.
770 //Regular blends and antialiased text are always (s*a + d*(1-a))
771 //and smoothed text is always g=2.0.
772 fRGBSpace = CGColorSpaceCreateDeviceRGB();
773 }
774
775 // default to kBW_Format
776 bool doAA = false;
777 bool doLCD = false;
778
779 if (SkMask::kBW_Format != glyph.fMaskFormat) {
780 doLCD = true;
781 doAA = true;
782 }
783
784 // FIXME: lcd smoothed un-hinted rasterization unsupported.
785 if (!generateA8FromLCD && SkMask::kA8_Format == glyph.fMaskFormat) {
786 doLCD = false;
787 doAA = true;
788 }
789
790 size_t rowBytes = fSize.fWidth * sizeof(CGRGBPixel);
791 if (!fCG || fSize.fWidth < glyph.fWidth || fSize.fHeight < glyph.fHeight) {
792 if (fSize.fWidth < glyph.fWidth) {
793 fSize.fWidth = RoundSize(glyph.fWidth);
794 }
795 if (fSize.fHeight < glyph.fHeight) {
796 fSize.fHeight = RoundSize(glyph.fHeight);
797 }
798
799 rowBytes = fSize.fWidth * sizeof(CGRGBPixel);
800 void* image = fImageStorage.reset(rowBytes * fSize.fHeight);
801 fCG = CGBitmapContextCreate(image, fSize.fWidth, fSize.fHeight, 8,
802 rowBytes, fRGBSpace, BITMAP_INFO_RGB);
803
804 // skia handles quantization itself, so we disable this for cg to get
805 // full fractional data from them.
806 CGContextSetAllowsFontSubpixelQuantization(fCG, false);
807 CGContextSetShouldSubpixelQuantizeFonts(fCG, false);
808
809 CGContextSetTextDrawingMode(fCG, kCGTextFill);
810 CGContextSetFont(fCG, context.fCGFont);
811 CGContextSetFontSize(fCG, 1 /*CTFontGetSize(context.fCTFont)*/);
812 CGContextSetTextMatrix(fCG, CTFontGetMatrix(context.fCTFont));
813
814 // Because CG always draws from the horizontal baseline,
815 // if there is a non-integral translation from the horizontal origin to the vertical origin,
816 // then CG cannot draw the glyph in the correct location without subpixel positioning.
817 CGContextSetAllowsFontSubpixelPositioning(fCG, context.fDoSubPosition || context.fVertical);
818 CGContextSetShouldSubpixelPositionFonts(fCG, context.fDoSubPosition || context.fVertical);
819
820 // Draw white on black to create mask.
821 // TODO: Draw black on white and invert, CG has a special case codepath.
822 CGContextSetGrayFillColor(fCG, 1.0f, 1.0f);
823
824 // force our checks below to happen
825 fDoAA = !doAA;
826 fDoLCD = !doLCD;
827 }
828
829 if (fDoAA != doAA) {
830 CGContextSetShouldAntialias(fCG, doAA);
831 fDoAA = doAA;
832 }
833 if (fDoLCD != doLCD) {
834 CGContextSetShouldSmoothFonts(fCG, doLCD);
835 fDoLCD = doLCD;
836 }
837
838 CGRGBPixel* image = (CGRGBPixel*)fImageStorage.get();
839 // skip rows based on the glyph's height
840 image += (fSize.fHeight - glyph.fHeight) * fSize.fWidth;
841
842 // erase to black
843 sk_memset_rect32(image, 0, glyph.fWidth, glyph.fHeight, rowBytes);
844
845 float subX = 0;
846 float subY = 0;
847 if (context.fDoSubPosition) {
848 subX = SkFixedToFloat(glyph.getSubXFixed());
849 subY = SkFixedToFloat(glyph.getSubYFixed());
850 }
851
852 // CGContextShowGlyphsAtPoint always draws using the horizontal baseline origin.
853 if (context.fVertical) {
854 SkPoint offset;
855 context.getVerticalOffset(glyphID, &offset);
856 subX += offset.fX;
857 subY += offset.fY;
858 }
859
860 CGContextShowGlyphsAtPoint(fCG, -glyph.fLeft + subX,
861 glyph.fTop + glyph.fHeight - subY,
862 &glyphID, 1);
863
864 SkASSERT(rowBytesPtr);
865 *rowBytesPtr = rowBytes;
866 return image;
867 }
868
getVerticalOffset(CGGlyph glyphID,SkPoint * offset) const869 void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkPoint* offset) const {
870 // Snow Leopard returns cgVertOffset in completely un-transformed FUnits (em space, y up).
871 // Lion and Leopard return cgVertOffset in CG units (pixels, y up).
872 CGSize cgVertOffset;
873 CTFontGetVerticalTranslationsForGlyphs(fCTFont, &glyphID, &cgVertOffset, 1);
874
875 SkPoint skVertOffset = { CGToScalar(cgVertOffset.width), CGToScalar(cgVertOffset.height) };
876 if (isSnowLeopard()) {
877 // From FUnits (em space, y up) to SkGlyph units (pixels, y down).
878 fFUnitMatrix.mapPoints(&skVertOffset, 1);
879 } else {
880 // From CG units (pixels, y up) to SkGlyph units (pixels, y down).
881 skVertOffset.fY = -skVertOffset.fY;
882 }
883
884 *offset = skVertOffset;
885 }
886
getFBoundingBoxesGlyphOffset()887 uint16_t SkScalerContext_Mac::getFBoundingBoxesGlyphOffset() {
888 if (fFBoundingBoxesGlyphOffset) {
889 return fFBoundingBoxesGlyphOffset;
890 }
891 fFBoundingBoxesGlyphOffset = fGlyphCount; // fallback for all fonts
892 AutoCGTable<SkOTTableHorizontalHeader> hheaTable(fCGFont);
893 if (hheaTable.fData) {
894 fFBoundingBoxesGlyphOffset = SkEndian_SwapBE16(hheaTable->numberOfHMetrics);
895 }
896 return fFBoundingBoxesGlyphOffset;
897 }
898
generateBBoxes()899 bool SkScalerContext_Mac::generateBBoxes() {
900 if (fGeneratedFBoundingBoxes) {
901 return NULL != fFBoundingBoxes.get();
902 }
903 fGeneratedFBoundingBoxes = true;
904
905 AutoCGTable<SkOTTableHead> headTable(fCGFont);
906 if (!headTable.fData) {
907 return false;
908 }
909
910 AutoCGTable<SkOTTableIndexToLocation> locaTable(fCGFont);
911 if (!locaTable.fData) {
912 return false;
913 }
914
915 AutoCGTable<SkOTTableGlyph> glyfTable(fCGFont);
916 if (!glyfTable.fData) {
917 return false;
918 }
919
920 uint16_t entries = fGlyphCount - fFBoundingBoxesGlyphOffset;
921 fFBoundingBoxes.reset(entries);
922
923 SkOTTableHead::IndexToLocFormat locaFormat = headTable->indexToLocFormat;
924 SkOTTableGlyph::Iterator glyphDataIter(*glyfTable.fData, *locaTable.fData, locaFormat);
925 glyphDataIter.advance(fFBoundingBoxesGlyphOffset);
926 for (uint16_t boundingBoxesIndex = 0; boundingBoxesIndex < entries; ++boundingBoxesIndex) {
927 const SkOTTableGlyphData* glyphData = glyphDataIter.next();
928 GlyphRect& rect = fFBoundingBoxes[boundingBoxesIndex];
929 rect.fMinX = SkEndian_SwapBE16(glyphData->xMin);
930 rect.fMinY = SkEndian_SwapBE16(glyphData->yMin);
931 rect.fMaxX = SkEndian_SwapBE16(glyphData->xMax);
932 rect.fMaxY = SkEndian_SwapBE16(glyphData->yMax);
933 }
934
935 return true;
936 }
937
generateGlyphCount(void)938 unsigned SkScalerContext_Mac::generateGlyphCount(void) {
939 return fGlyphCount;
940 }
941
generateCharToGlyph(SkUnichar uni)942 uint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni) {
943 CGGlyph cgGlyph[2];
944 UniChar theChar[2]; // UniChar is a UTF-16 16-bit code unit.
945
946 // Get the glyph
947 size_t numUniChar = SkUTF16_FromUnichar(uni, theChar);
948 SkASSERT(sizeof(CGGlyph) <= sizeof(uint16_t));
949
950 // Undocumented behavior of CTFontGetGlyphsForCharacters with non-bmp code points:
951 // When a surrogate pair is detected, the glyph index used is the index of the high surrogate.
952 // It is documented that if a mapping is unavailable, the glyph will be set to 0.
953 CTFontGetGlyphsForCharacters(fCTFont, theChar, cgGlyph, numUniChar);
954 return cgGlyph[0];
955 }
956
generateAdvance(SkGlyph * glyph)957 void SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) {
958 this->generateMetrics(glyph);
959 }
960
generateMetrics(SkGlyph * glyph)961 void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) {
962 const CGGlyph cgGlyph = (CGGlyph) glyph->getGlyphID(fBaseGlyphCount);
963 glyph->zeroMetrics();
964
965 // The following block produces cgAdvance in CG units (pixels, y up).
966 CGSize cgAdvance;
967 if (fVertical) {
968 CTFontGetAdvancesForGlyphs(fCTVerticalFont, kCTFontVerticalOrientation,
969 &cgGlyph, &cgAdvance, 1);
970 } else {
971 CTFontGetAdvancesForGlyphs(fCTFont, kCTFontHorizontalOrientation,
972 &cgGlyph, &cgAdvance, 1);
973 }
974 glyph->fAdvanceX = SkFloatToFixed_Check(cgAdvance.width);
975 glyph->fAdvanceY = -SkFloatToFixed_Check(cgAdvance.height);
976
977 // The following produces skBounds in SkGlyph units (pixels, y down),
978 // or returns early if skBounds would be empty.
979 SkRect skBounds;
980
981 // On Mountain Lion, CTFontGetBoundingRectsForGlyphs with kCTFontVerticalOrientation and
982 // CTFontGetVerticalTranslationsForGlyphs do not agree when using OTF CFF fonts.
983 // For TTF fonts these two do agree and we can use CTFontGetBoundingRectsForGlyphs to get
984 // the bounding box and CTFontGetVerticalTranslationsForGlyphs to then draw the glyph
985 // inside that bounding box. However, with OTF CFF fonts this does not work. It appears that
986 // CTFontGetBoundingRectsForGlyphs with kCTFontVerticalOrientation on OTF CFF fonts tries
987 // to center the glyph along the vertical baseline and also perform some mysterious shift
988 // along the baseline. CTFontGetVerticalTranslationsForGlyphs does not appear to perform
989 // these steps.
990 //
991 // It is not known which is correct (or if either is correct). However, we must always draw
992 // from the horizontal origin and must use CTFontGetVerticalTranslationsForGlyphs to draw.
993 // As a result, we do not call CTFontGetBoundingRectsForGlyphs for vertical glyphs.
994
995 // On Snow Leopard, CTFontGetBoundingRectsForGlyphs ignores kCTFontVerticalOrientation and
996 // returns horizontal bounds.
997
998 // On Lion and Mountain Lion, CTFontGetBoundingRectsForGlyphs has a bug which causes it to
999 // return a bad value in cgBounds.origin.x for SFNT fonts whose hhea::numberOfHMetrics is
1000 // less than its maxp::numGlyphs. When this is the case we try to read the bounds from the
1001 // font directly.
1002 if ((isLion() || isMountainLion()) &&
1003 (cgGlyph < fGlyphCount && cgGlyph >= getFBoundingBoxesGlyphOffset() && generateBBoxes()))
1004 {
1005 const GlyphRect& gRect = fFBoundingBoxes[cgGlyph - fFBoundingBoxesGlyphOffset];
1006 if (gRect.fMinX >= gRect.fMaxX || gRect.fMinY >= gRect.fMaxY) {
1007 return;
1008 }
1009 skBounds = SkRect::MakeLTRB(gRect.fMinX, gRect.fMinY, gRect.fMaxX, gRect.fMaxY);
1010 // From FUnits (em space, y up) to SkGlyph units (pixels, y down).
1011 fFUnitMatrix.mapRect(&skBounds);
1012
1013 } else {
1014 // CTFontGetBoundingRectsForGlyphs produces cgBounds in CG units (pixels, y up).
1015 CGRect cgBounds;
1016 CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontHorizontalOrientation,
1017 &cgGlyph, &cgBounds, 1);
1018
1019 // BUG?
1020 // 0x200B (zero-advance space) seems to return a huge (garbage) bounds, when
1021 // it should be empty. So, if we see a zero-advance, we check if it has an
1022 // empty path or not, and if so, we jam the bounds to 0. Hopefully a zero-advance
1023 // is rare, so we won't incur a big performance cost for this extra check.
1024 if (0 == cgAdvance.width && 0 == cgAdvance.height) {
1025 AutoCFRelease<CGPathRef> path(CTFontCreatePathForGlyph(fCTFont, cgGlyph, NULL));
1026 if (NULL == path || CGPathIsEmpty(path)) {
1027 return;
1028 }
1029 }
1030
1031 if (CGRectIsEmpty_inline(cgBounds)) {
1032 return;
1033 }
1034
1035 // Convert cgBounds to SkGlyph units (pixels, y down).
1036 skBounds = SkRect::MakeXYWH(cgBounds.origin.x, -cgBounds.origin.y - cgBounds.size.height,
1037 cgBounds.size.width, cgBounds.size.height);
1038 }
1039
1040 if (fVertical) {
1041 // Due to all of the vertical bounds bugs, skBounds is always the horizontal bounds.
1042 // Convert these horizontal bounds into vertical bounds.
1043 SkPoint offset;
1044 getVerticalOffset(cgGlyph, &offset);
1045 skBounds.offset(offset);
1046 }
1047
1048 // Currently the bounds are based on being rendered at (0,0).
1049 // The top left must not move, since that is the base from which subpixel positioning is offset.
1050 if (fDoSubPosition) {
1051 skBounds.fRight += SkFixedToFloat(glyph->getSubXFixed());
1052 skBounds.fBottom += SkFixedToFloat(glyph->getSubYFixed());
1053 }
1054
1055 SkIRect skIBounds;
1056 skBounds.roundOut(&skIBounds);
1057 // Expand the bounds by 1 pixel, to give CG room for anti-aliasing.
1058 // Note that this outset is to allow room for LCD smoothed glyphs. However, the correct outset
1059 // is not currently known, as CG dilates the outlines by some percentage.
1060 // Note that if this context is A8 and not back-forming from LCD, there is no need to outset.
1061 skIBounds.outset(1, 1);
1062 glyph->fLeft = SkToS16(skIBounds.fLeft);
1063 glyph->fTop = SkToS16(skIBounds.fTop);
1064 glyph->fWidth = SkToU16(skIBounds.width());
1065 glyph->fHeight = SkToU16(skIBounds.height());
1066
1067 #ifdef HACK_COLORGLYPHS
1068 glyph->fMaskFormat = SkMask::kARGB32_Format;
1069 #endif
1070 }
1071
1072 #include "SkColorPriv.h"
1073
build_power_table(uint8_t table[],float ee)1074 static void build_power_table(uint8_t table[], float ee) {
1075 for (int i = 0; i < 256; i++) {
1076 float x = i / 255.f;
1077 x = sk_float_pow(x, ee);
1078 int xx = SkScalarRoundToInt(x * 255);
1079 table[i] = SkToU8(xx);
1080 }
1081 }
1082
1083 /**
1084 * This will invert the gamma applied by CoreGraphics, so we can get linear
1085 * values.
1086 *
1087 * CoreGraphics obscurely defaults to 2.0 as the smoothing gamma value.
1088 * The color space used does not appear to affect this choice.
1089 */
getInverseGammaTableCoreGraphicSmoothing()1090 static const uint8_t* getInverseGammaTableCoreGraphicSmoothing() {
1091 static bool gInited;
1092 static uint8_t gTableCoreGraphicsSmoothing[256];
1093 if (!gInited) {
1094 build_power_table(gTableCoreGraphicsSmoothing, 2.0f);
1095 gInited = true;
1096 }
1097 return gTableCoreGraphicsSmoothing;
1098 }
1099
cgpixels_to_bits(uint8_t dst[],const CGRGBPixel src[],int count)1100 static void cgpixels_to_bits(uint8_t dst[], const CGRGBPixel src[], int count) {
1101 while (count > 0) {
1102 uint8_t mask = 0;
1103 for (int i = 7; i >= 0; --i) {
1104 mask |= (CGRGBPixel_getAlpha(*src++) >> 7) << i;
1105 if (0 == --count) {
1106 break;
1107 }
1108 }
1109 *dst++ = mask;
1110 }
1111 }
1112
1113 template<bool APPLY_PREBLEND>
rgb_to_a8(CGRGBPixel rgb,const uint8_t * table8)1114 static inline uint8_t rgb_to_a8(CGRGBPixel rgb, const uint8_t* table8) {
1115 U8CPU r = (rgb >> 16) & 0xFF;
1116 U8CPU g = (rgb >> 8) & 0xFF;
1117 U8CPU b = (rgb >> 0) & 0xFF;
1118 return sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8);
1119 }
1120 template<bool APPLY_PREBLEND>
rgb_to_a8(const CGRGBPixel * SK_RESTRICT cgPixels,size_t cgRowBytes,const SkGlyph & glyph,const uint8_t * table8)1121 static void rgb_to_a8(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes,
1122 const SkGlyph& glyph, const uint8_t* table8) {
1123 const int width = glyph.fWidth;
1124 size_t dstRB = glyph.rowBytes();
1125 uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage;
1126
1127 for (int y = 0; y < glyph.fHeight; y++) {
1128 for (int i = 0; i < width; ++i) {
1129 dst[i] = rgb_to_a8<APPLY_PREBLEND>(cgPixels[i], table8);
1130 }
1131 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1132 dst += dstRB;
1133 }
1134 }
1135
1136 template<bool APPLY_PREBLEND>
rgb_to_lcd16(CGRGBPixel rgb,const uint8_t * tableR,const uint8_t * tableG,const uint8_t * tableB)1137 static inline uint16_t rgb_to_lcd16(CGRGBPixel rgb, const uint8_t* tableR,
1138 const uint8_t* tableG,
1139 const uint8_t* tableB) {
1140 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
1141 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG);
1142 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB);
1143 return SkPack888ToRGB16(r, g, b);
1144 }
1145 template<bool APPLY_PREBLEND>
rgb_to_lcd16(const CGRGBPixel * SK_RESTRICT cgPixels,size_t cgRowBytes,const SkGlyph & glyph,const uint8_t * tableR,const uint8_t * tableG,const uint8_t * tableB)1146 static void rgb_to_lcd16(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes, const SkGlyph& glyph,
1147 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
1148 const int width = glyph.fWidth;
1149 size_t dstRB = glyph.rowBytes();
1150 uint16_t* SK_RESTRICT dst = (uint16_t*)glyph.fImage;
1151
1152 for (int y = 0; y < glyph.fHeight; y++) {
1153 for (int i = 0; i < width; i++) {
1154 dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(cgPixels[i], tableR, tableG, tableB);
1155 }
1156 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1157 dst = (uint16_t*)((char*)dst + dstRB);
1158 }
1159 }
1160
1161 template<bool APPLY_PREBLEND>
rgb_to_lcd32(CGRGBPixel rgb,const uint8_t * tableR,const uint8_t * tableG,const uint8_t * tableB)1162 static inline uint32_t rgb_to_lcd32(CGRGBPixel rgb, const uint8_t* tableR,
1163 const uint8_t* tableG,
1164 const uint8_t* tableB) {
1165 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
1166 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG);
1167 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB);
1168 return SkPackARGB32(0xFF, r, g, b);
1169 }
1170 template<bool APPLY_PREBLEND>
rgb_to_lcd32(const CGRGBPixel * SK_RESTRICT cgPixels,size_t cgRowBytes,const SkGlyph & glyph,const uint8_t * tableR,const uint8_t * tableG,const uint8_t * tableB)1171 static void rgb_to_lcd32(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes, const SkGlyph& glyph,
1172 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
1173 const int width = glyph.fWidth;
1174 size_t dstRB = glyph.rowBytes();
1175 uint32_t* SK_RESTRICT dst = (uint32_t*)glyph.fImage;
1176 for (int y = 0; y < glyph.fHeight; y++) {
1177 for (int i = 0; i < width; i++) {
1178 dst[i] = rgb_to_lcd32<APPLY_PREBLEND>(cgPixels[i], tableR, tableG, tableB);
1179 }
1180 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1181 dst = (uint32_t*)((char*)dst + dstRB);
1182 }
1183 }
1184
1185 #ifdef HACK_COLORGLYPHS
1186 // hack to colorize the output for testing kARGB32_Format
cgpixels_to_pmcolor(CGRGBPixel rgb,const SkGlyph & glyph,int x,int y)1187 static SkPMColor cgpixels_to_pmcolor(CGRGBPixel rgb, const SkGlyph& glyph,
1188 int x, int y) {
1189 U8CPU r = (rgb >> 16) & 0xFF;
1190 U8CPU g = (rgb >> 8) & 0xFF;
1191 U8CPU b = (rgb >> 0) & 0xFF;
1192 unsigned a = SkComputeLuminance(r, g, b);
1193
1194 // compute gradient from x,y
1195 r = x * 255 / glyph.fWidth;
1196 g = 0;
1197 b = (glyph.fHeight - y) * 255 / glyph.fHeight;
1198 return SkPreMultiplyARGB(a, r, g, b); // red
1199 }
1200 #endif
1201
SkTAddByteOffset(T * ptr,size_t byteOffset)1202 template <typename T> T* SkTAddByteOffset(T* ptr, size_t byteOffset) {
1203 return (T*)((char*)ptr + byteOffset);
1204 }
1205
generateImage(const SkGlyph & glyph)1206 void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
1207 CGGlyph cgGlyph = (CGGlyph) glyph.getGlyphID(fBaseGlyphCount);
1208
1209 // FIXME: lcd smoothed un-hinted rasterization unsupported.
1210 bool generateA8FromLCD = fRec.getHinting() != SkPaint::kNo_Hinting;
1211
1212 // Draw the glyph
1213 size_t cgRowBytes;
1214 CGRGBPixel* cgPixels = fOffscreen.getCG(*this, glyph, cgGlyph, &cgRowBytes, generateA8FromLCD);
1215 if (cgPixels == NULL) {
1216 return;
1217 }
1218
1219 //TODO: see if drawing black on white and inverting is faster (at least in
1220 //lcd case) as core graphics appears to have special case code for drawing
1221 //black text.
1222
1223 // Fix the glyph
1224 const bool isLCD = isLCDFormat(glyph.fMaskFormat);
1225 if (isLCD || (glyph.fMaskFormat == SkMask::kA8_Format && supports_LCD() && generateA8FromLCD)) {
1226 const uint8_t* table = getInverseGammaTableCoreGraphicSmoothing();
1227
1228 //Note that the following cannot really be integrated into the
1229 //pre-blend, since we may not be applying the pre-blend; when we aren't
1230 //applying the pre-blend it means that a filter wants linear anyway.
1231 //Other code may also be applying the pre-blend, so we'd need another
1232 //one with this and one without.
1233 CGRGBPixel* addr = cgPixels;
1234 for (int y = 0; y < glyph.fHeight; ++y) {
1235 for (int x = 0; x < glyph.fWidth; ++x) {
1236 int r = (addr[x] >> 16) & 0xFF;
1237 int g = (addr[x] >> 8) & 0xFF;
1238 int b = (addr[x] >> 0) & 0xFF;
1239 addr[x] = (table[r] << 16) | (table[g] << 8) | table[b];
1240 }
1241 addr = SkTAddByteOffset(addr, cgRowBytes);
1242 }
1243 }
1244
1245 // Convert glyph to mask
1246 switch (glyph.fMaskFormat) {
1247 case SkMask::kLCD32_Format: {
1248 if (fPreBlend.isApplicable()) {
1249 rgb_to_lcd32<true>(cgPixels, cgRowBytes, glyph,
1250 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1251 } else {
1252 rgb_to_lcd32<false>(cgPixels, cgRowBytes, glyph,
1253 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1254 }
1255 } break;
1256 case SkMask::kLCD16_Format: {
1257 if (fPreBlend.isApplicable()) {
1258 rgb_to_lcd16<true>(cgPixels, cgRowBytes, glyph,
1259 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1260 } else {
1261 rgb_to_lcd16<false>(cgPixels, cgRowBytes, glyph,
1262 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1263 }
1264 } break;
1265 case SkMask::kA8_Format: {
1266 if (fPreBlend.isApplicable()) {
1267 rgb_to_a8<true>(cgPixels, cgRowBytes, glyph, fPreBlend.fG);
1268 } else {
1269 rgb_to_a8<false>(cgPixels, cgRowBytes, glyph, fPreBlend.fG);
1270 }
1271 } break;
1272 case SkMask::kBW_Format: {
1273 const int width = glyph.fWidth;
1274 size_t dstRB = glyph.rowBytes();
1275 uint8_t* dst = (uint8_t*)glyph.fImage;
1276 for (int y = 0; y < glyph.fHeight; y++) {
1277 cgpixels_to_bits(dst, cgPixels, width);
1278 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1279 dst += dstRB;
1280 }
1281 } break;
1282 #ifdef HACK_COLORGLYPHS
1283 case SkMask::kARGB32_Format: {
1284 const int width = glyph.fWidth;
1285 size_t dstRB = glyph.rowBytes();
1286 SkPMColor* dst = (SkPMColor*)glyph.fImage;
1287 for (int y = 0; y < glyph.fHeight; y++) {
1288 for (int x = 0; x < width; ++x) {
1289 dst[x] = cgpixels_to_pmcolor(cgPixels[x], glyph, x, y);
1290 }
1291 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1292 dst = (SkPMColor*)((char*)dst + dstRB);
1293 }
1294 } break;
1295 #endif
1296 default:
1297 SkDEBUGFAIL("unexpected mask format");
1298 break;
1299 }
1300 }
1301
1302 /*
1303 * Our subpixel resolution is only 2 bits in each direction, so a scale of 4
1304 * seems sufficient, and possibly even correct, to allow the hinted outline
1305 * to be subpixel positioned.
1306 */
1307 #define kScaleForSubPixelPositionHinting (4.0f)
1308
generatePath(const SkGlyph & glyph,SkPath * path)1309 void SkScalerContext_Mac::generatePath(const SkGlyph& glyph, SkPath* path) {
1310 CTFontRef font = fCTFont;
1311 SkScalar scaleX = SK_Scalar1;
1312 SkScalar scaleY = SK_Scalar1;
1313
1314 /*
1315 * For subpixel positioning, we want to return an unhinted outline, so it
1316 * can be positioned nicely at fractional offsets. However, we special-case
1317 * if the baseline of the (horizontal) text is axis-aligned. In those cases
1318 * we want to retain hinting in the direction orthogonal to the baseline.
1319 * e.g. for horizontal baseline, we want to retain hinting in Y.
1320 * The way we remove hinting is to scale the font by some value (4) in that
1321 * direction, ask for the path, and then scale the path back down.
1322 */
1323 if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
1324 SkMatrix m;
1325 fRec.getSingleMatrix(&m);
1326
1327 // start out by assuming that we want no hining in X and Y
1328 scaleX = scaleY = kScaleForSubPixelPositionHinting;
1329 // now see if we need to restore hinting for axis-aligned baselines
1330 switch (SkComputeAxisAlignmentForHText(m)) {
1331 case kX_SkAxisAlignment:
1332 scaleY = SK_Scalar1; // want hinting in the Y direction
1333 break;
1334 case kY_SkAxisAlignment:
1335 scaleX = SK_Scalar1; // want hinting in the X direction
1336 break;
1337 default:
1338 break;
1339 }
1340
1341 CGAffineTransform xform = MatrixToCGAffineTransform(m, scaleX, scaleY);
1342 // need to release font when we're done
1343 font = CTFontCreateCopyWithAttributes(fCTFont, 1, &xform, NULL);
1344 }
1345
1346 CGGlyph cgGlyph = (CGGlyph)glyph.getGlyphID(fBaseGlyphCount);
1347 AutoCFRelease<CGPathRef> cgPath(CTFontCreatePathForGlyph(font, cgGlyph, NULL));
1348
1349 path->reset();
1350 if (cgPath != NULL) {
1351 CGPathApply(cgPath, path, SkScalerContext_Mac::CTPathElement);
1352 }
1353
1354 if (fDoSubPosition) {
1355 SkMatrix m;
1356 m.setScale(SkScalarInvert(scaleX), SkScalarInvert(scaleY));
1357 path->transform(m);
1358 // balance the call to CTFontCreateCopyWithAttributes
1359 CFSafeRelease(font);
1360 }
1361 if (fVertical) {
1362 SkPoint offset;
1363 getVerticalOffset(cgGlyph, &offset);
1364 path->offset(offset.fX, offset.fY);
1365 }
1366 }
1367
generateFontMetrics(SkPaint::FontMetrics * mx,SkPaint::FontMetrics * my)1368 void SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* mx,
1369 SkPaint::FontMetrics* my) {
1370 CGRect theBounds = CTFontGetBoundingBox(fCTFont);
1371
1372 SkPaint::FontMetrics theMetrics;
1373 theMetrics.fTop = CGToScalar(-CGRectGetMaxY_inline(theBounds));
1374 theMetrics.fAscent = CGToScalar(-CTFontGetAscent(fCTFont));
1375 theMetrics.fDescent = CGToScalar( CTFontGetDescent(fCTFont));
1376 theMetrics.fBottom = CGToScalar(-CGRectGetMinY_inline(theBounds));
1377 theMetrics.fLeading = CGToScalar( CTFontGetLeading(fCTFont));
1378 theMetrics.fAvgCharWidth = CGToScalar( CGRectGetWidth_inline(theBounds));
1379 theMetrics.fXMin = CGToScalar( CGRectGetMinX_inline(theBounds));
1380 theMetrics.fXMax = CGToScalar( CGRectGetMaxX_inline(theBounds));
1381 theMetrics.fXHeight = CGToScalar( CTFontGetXHeight(fCTFont));
1382 theMetrics.fUnderlineThickness = CGToScalar( CTFontGetUnderlineThickness(fCTFont));
1383 theMetrics.fUnderlinePosition = -CGToScalar( CTFontGetUnderlinePosition(fCTFont));
1384
1385 theMetrics.fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
1386 theMetrics.fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
1387
1388 if (mx != NULL) {
1389 *mx = theMetrics;
1390 }
1391 if (my != NULL) {
1392 *my = theMetrics;
1393 }
1394 }
1395
CTPathElement(void * info,const CGPathElement * element)1396 void SkScalerContext_Mac::CTPathElement(void *info, const CGPathElement *element) {
1397 SkPath* skPath = (SkPath*)info;
1398
1399 // Process the path element
1400 switch (element->type) {
1401 case kCGPathElementMoveToPoint:
1402 skPath->moveTo(element->points[0].x, -element->points[0].y);
1403 break;
1404
1405 case kCGPathElementAddLineToPoint:
1406 skPath->lineTo(element->points[0].x, -element->points[0].y);
1407 break;
1408
1409 case kCGPathElementAddQuadCurveToPoint:
1410 skPath->quadTo(element->points[0].x, -element->points[0].y,
1411 element->points[1].x, -element->points[1].y);
1412 break;
1413
1414 case kCGPathElementAddCurveToPoint:
1415 skPath->cubicTo(element->points[0].x, -element->points[0].y,
1416 element->points[1].x, -element->points[1].y,
1417 element->points[2].x, -element->points[2].y);
1418 break;
1419
1420 case kCGPathElementCloseSubpath:
1421 skPath->close();
1422 break;
1423
1424 default:
1425 SkDEBUGFAIL("Unknown path element!");
1426 break;
1427 }
1428 }
1429
1430
1431 ///////////////////////////////////////////////////////////////////////////////
1432
1433 // Returns NULL on failure
1434 // Call must still manage its ownership of provider
create_from_dataProvider(CGDataProviderRef provider)1435 static SkTypeface* create_from_dataProvider(CGDataProviderRef provider) {
1436 AutoCFRelease<CGFontRef> cg(CGFontCreateWithDataProvider(provider));
1437 if (NULL == cg) {
1438 return NULL;
1439 }
1440 CTFontRef ct = CTFontCreateWithGraphicsFont(cg, 0, NULL, NULL);
1441 return cg ? SkCreateTypefaceFromCTFont(ct) : NULL;
1442 }
1443
1444 // Web fonts added to the the CTFont registry do not return their character set.
1445 // Iterate through the font in this case. The existing caller caches the result,
1446 // so the performance impact isn't too bad.
populate_glyph_to_unicode_slow(CTFontRef ctFont,CFIndex glyphCount,SkTDArray<SkUnichar> * glyphToUnicode)1447 static void populate_glyph_to_unicode_slow(CTFontRef ctFont, CFIndex glyphCount,
1448 SkTDArray<SkUnichar>* glyphToUnicode) {
1449 glyphToUnicode->setCount(SkToInt(glyphCount));
1450 SkUnichar* out = glyphToUnicode->begin();
1451 sk_bzero(out, glyphCount * sizeof(SkUnichar));
1452 UniChar unichar = 0;
1453 while (glyphCount > 0) {
1454 CGGlyph glyph;
1455 if (CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) {
1456 out[glyph] = unichar;
1457 --glyphCount;
1458 }
1459 if (++unichar == 0) {
1460 break;
1461 }
1462 }
1463 }
1464
1465 // Construct Glyph to Unicode table.
1466 // Unicode code points that require conjugate pairs in utf16 are not
1467 // supported.
populate_glyph_to_unicode(CTFontRef ctFont,CFIndex glyphCount,SkTDArray<SkUnichar> * glyphToUnicode)1468 static void populate_glyph_to_unicode(CTFontRef ctFont, CFIndex glyphCount,
1469 SkTDArray<SkUnichar>* glyphToUnicode) {
1470 AutoCFRelease<CFCharacterSetRef> charSet(CTFontCopyCharacterSet(ctFont));
1471 if (!charSet) {
1472 populate_glyph_to_unicode_slow(ctFont, glyphCount, glyphToUnicode);
1473 return;
1474 }
1475
1476 AutoCFRelease<CFDataRef> bitmap(CFCharacterSetCreateBitmapRepresentation(kCFAllocatorDefault,
1477 charSet));
1478 if (!bitmap) {
1479 return;
1480 }
1481 CFIndex length = CFDataGetLength(bitmap);
1482 if (!length) {
1483 return;
1484 }
1485 if (length > 8192) {
1486 // TODO: Add support for Unicode above 0xFFFF
1487 // Consider only the BMP portion of the Unicode character points.
1488 // The bitmap may contain other planes, up to plane 16.
1489 // See http://developer.apple.com/library/ios/#documentation/CoreFoundation/Reference/CFCharacterSetRef/Reference/reference.html
1490 length = 8192;
1491 }
1492 const UInt8* bits = CFDataGetBytePtr(bitmap);
1493 glyphToUnicode->setCount(SkToInt(glyphCount));
1494 SkUnichar* out = glyphToUnicode->begin();
1495 sk_bzero(out, glyphCount * sizeof(SkUnichar));
1496 for (int i = 0; i < length; i++) {
1497 int mask = bits[i];
1498 if (!mask) {
1499 continue;
1500 }
1501 for (int j = 0; j < 8; j++) {
1502 CGGlyph glyph;
1503 UniChar unichar = static_cast<UniChar>((i << 3) + j);
1504 if (mask & (1 << j) && CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) {
1505 out[glyph] = unichar;
1506 }
1507 }
1508 }
1509 }
1510
getWidthAdvance(CTFontRef ctFont,int gId,int16_t * data)1511 static bool getWidthAdvance(CTFontRef ctFont, int gId, int16_t* data) {
1512 CGSize advance;
1513 advance.width = 0;
1514 CGGlyph glyph = gId;
1515 CTFontGetAdvancesForGlyphs(ctFont, kCTFontHorizontalOrientation, &glyph, &advance, 1);
1516 *data = sk_float_round2int(advance.width);
1517 return true;
1518 }
1519
1520 // we might move this into our CGUtils...
CFStringToSkString(CFStringRef src,SkString * dst)1521 static void CFStringToSkString(CFStringRef src, SkString* dst) {
1522 // Reserve enough room for the worst-case string,
1523 // plus 1 byte for the trailing null.
1524 CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(src),
1525 kCFStringEncodingUTF8) + 1;
1526 dst->resize(length);
1527 CFStringGetCString(src, dst->writable_str(), length, kCFStringEncodingUTF8);
1528 // Resize to the actual UTF-8 length used, stripping the null character.
1529 dst->resize(strlen(dst->c_str()));
1530 }
1531
onGetAdvancedTypefaceMetrics(SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,const uint32_t * glyphIDs,uint32_t glyphIDsCount) const1532 SkAdvancedTypefaceMetrics* SkTypeface_Mac::onGetAdvancedTypefaceMetrics(
1533 SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
1534 const uint32_t* glyphIDs,
1535 uint32_t glyphIDsCount) const {
1536
1537 CTFontRef originalCTFont = fFontRef.get();
1538 AutoCFRelease<CTFontRef> ctFont(CTFontCreateCopyWithAttributes(
1539 originalCTFont, CTFontGetUnitsPerEm(originalCTFont), NULL, NULL));
1540 SkAdvancedTypefaceMetrics* info = new SkAdvancedTypefaceMetrics;
1541
1542 {
1543 AutoCFRelease<CFStringRef> fontName(CTFontCopyPostScriptName(ctFont));
1544 CFStringToSkString(fontName, &info->fFontName);
1545 }
1546
1547 CFIndex glyphCount = CTFontGetGlyphCount(ctFont);
1548 info->fLastGlyphID = SkToU16(glyphCount - 1);
1549 info->fEmSize = CTFontGetUnitsPerEm(ctFont);
1550 info->fFlags = SkAdvancedTypefaceMetrics::kEmpty_FontFlag;
1551 info->fStyle = 0;
1552
1553 if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) {
1554 populate_glyph_to_unicode(ctFont, glyphCount, &info->fGlyphToUnicode);
1555 }
1556
1557 // If it's not a truetype font, mark it as 'other'. Assume that TrueType
1558 // fonts always have both glyf and loca tables. At the least, this is what
1559 // sfntly needs to subset the font. CTFontCopyAttribute() does not always
1560 // succeed in determining this directly.
1561 if (!this->getTableSize('glyf') || !this->getTableSize('loca')) {
1562 info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
1563 info->fItalicAngle = 0;
1564 info->fAscent = 0;
1565 info->fDescent = 0;
1566 info->fStemV = 0;
1567 info->fCapHeight = 0;
1568 info->fBBox = SkIRect::MakeEmpty();
1569 return info;
1570 }
1571
1572 info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
1573 CTFontSymbolicTraits symbolicTraits = CTFontGetSymbolicTraits(ctFont);
1574 if (symbolicTraits & kCTFontMonoSpaceTrait) {
1575 info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
1576 }
1577 if (symbolicTraits & kCTFontItalicTrait) {
1578 info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
1579 }
1580 CTFontStylisticClass stylisticClass = symbolicTraits & kCTFontClassMaskTrait;
1581 if (stylisticClass >= kCTFontOldStyleSerifsClass && stylisticClass <= kCTFontSlabSerifsClass) {
1582 info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
1583 } else if (stylisticClass & kCTFontScriptsClass) {
1584 info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
1585 }
1586 info->fItalicAngle = (int16_t) CTFontGetSlantAngle(ctFont);
1587 info->fAscent = (int16_t) CTFontGetAscent(ctFont);
1588 info->fDescent = (int16_t) CTFontGetDescent(ctFont);
1589 info->fCapHeight = (int16_t) CTFontGetCapHeight(ctFont);
1590 CGRect bbox = CTFontGetBoundingBox(ctFont);
1591
1592 SkRect r;
1593 r.set( CGToScalar(CGRectGetMinX_inline(bbox)), // Left
1594 CGToScalar(CGRectGetMaxY_inline(bbox)), // Top
1595 CGToScalar(CGRectGetMaxX_inline(bbox)), // Right
1596 CGToScalar(CGRectGetMinY_inline(bbox))); // Bottom
1597
1598 r.roundOut(&(info->fBBox));
1599
1600 // Figure out a good guess for StemV - Min width of i, I, !, 1.
1601 // This probably isn't very good with an italic font.
1602 int16_t min_width = SHRT_MAX;
1603 info->fStemV = 0;
1604 static const UniChar stem_chars[] = {'i', 'I', '!', '1'};
1605 const size_t count = sizeof(stem_chars) / sizeof(stem_chars[0]);
1606 CGGlyph glyphs[count];
1607 CGRect boundingRects[count];
1608 if (CTFontGetGlyphsForCharacters(ctFont, stem_chars, glyphs, count)) {
1609 CTFontGetBoundingRectsForGlyphs(ctFont, kCTFontHorizontalOrientation,
1610 glyphs, boundingRects, count);
1611 for (size_t i = 0; i < count; i++) {
1612 int16_t width = (int16_t) boundingRects[i].size.width;
1613 if (width > 0 && width < min_width) {
1614 min_width = width;
1615 info->fStemV = min_width;
1616 }
1617 }
1618 }
1619
1620 if (perGlyphInfo & SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
1621 if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) {
1622 skia_advanced_typeface_metrics_utils::appendRange(&info->fGlyphWidths, 0);
1623 info->fGlyphWidths->fAdvance.append(1, &min_width);
1624 skia_advanced_typeface_metrics_utils::finishRange(info->fGlyphWidths.get(), 0,
1625 SkAdvancedTypefaceMetrics::WidthRange::kDefault);
1626 } else {
1627 info->fGlyphWidths.reset(
1628 skia_advanced_typeface_metrics_utils::getAdvanceData(ctFont.get(),
1629 SkToInt(glyphCount),
1630 glyphIDs,
1631 glyphIDsCount,
1632 &getWidthAdvance));
1633 }
1634 }
1635 return info;
1636 }
1637
1638 ///////////////////////////////////////////////////////////////////////////////
1639
get_font_type_tag(const SkTypeface_Mac * typeface)1640 static SK_SFNT_ULONG get_font_type_tag(const SkTypeface_Mac* typeface) {
1641 CTFontRef ctFont = typeface->fFontRef.get();
1642 AutoCFRelease<CFNumberRef> fontFormatRef(
1643 static_cast<CFNumberRef>(CTFontCopyAttribute(ctFont, kCTFontFormatAttribute)));
1644 if (!fontFormatRef) {
1645 return 0;
1646 }
1647
1648 SInt32 fontFormatValue;
1649 if (!CFNumberGetValue(fontFormatRef, kCFNumberSInt32Type, &fontFormatValue)) {
1650 return 0;
1651 }
1652
1653 switch (fontFormatValue) {
1654 case kCTFontFormatOpenTypePostScript:
1655 return SkSFNTHeader::fontType_OpenTypeCFF::TAG;
1656 case kCTFontFormatOpenTypeTrueType:
1657 return SkSFNTHeader::fontType_WindowsTrueType::TAG;
1658 case kCTFontFormatTrueType:
1659 return SkSFNTHeader::fontType_MacTrueType::TAG;
1660 case kCTFontFormatPostScript:
1661 return SkSFNTHeader::fontType_PostScript::TAG;
1662 case kCTFontFormatBitmap:
1663 return SkSFNTHeader::fontType_MacTrueType::TAG;
1664 case kCTFontFormatUnrecognized:
1665 default:
1666 //CT seems to be unreliable in being able to obtain the type,
1667 //even if all we want is the first four bytes of the font resource.
1668 //Just the presence of the FontForge 'FFTM' table seems to throw it off.
1669 return SkSFNTHeader::fontType_WindowsTrueType::TAG;
1670 }
1671 }
1672
onOpenStream(int * ttcIndex) const1673 SkStream* SkTypeface_Mac::onOpenStream(int* ttcIndex) const {
1674 SK_SFNT_ULONG fontType = get_font_type_tag(this);
1675 if (0 == fontType) {
1676 return NULL;
1677 }
1678
1679 // get table tags
1680 int numTables = this->countTables();
1681 SkTDArray<SkFontTableTag> tableTags;
1682 tableTags.setCount(numTables);
1683 this->getTableTags(tableTags.begin());
1684
1685 // calc total size for font, save sizes
1686 SkTDArray<size_t> tableSizes;
1687 size_t totalSize = sizeof(SkSFNTHeader) + sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables;
1688 for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
1689 size_t tableSize = this->getTableSize(tableTags[tableIndex]);
1690 totalSize += (tableSize + 3) & ~3;
1691 *tableSizes.append() = tableSize;
1692 }
1693
1694 // reserve memory for stream, and zero it (tables must be zero padded)
1695 SkMemoryStream* stream = new SkMemoryStream(totalSize);
1696 char* dataStart = (char*)stream->getMemoryBase();
1697 sk_bzero(dataStart, totalSize);
1698 char* dataPtr = dataStart;
1699
1700 // compute font header entries
1701 uint16_t entrySelector = 0;
1702 uint16_t searchRange = 1;
1703 while (searchRange < numTables >> 1) {
1704 entrySelector++;
1705 searchRange <<= 1;
1706 }
1707 searchRange <<= 4;
1708 uint16_t rangeShift = (numTables << 4) - searchRange;
1709
1710 // write font header
1711 SkSFNTHeader* header = (SkSFNTHeader*)dataPtr;
1712 header->fontType = fontType;
1713 header->numTables = SkEndian_SwapBE16(numTables);
1714 header->searchRange = SkEndian_SwapBE16(searchRange);
1715 header->entrySelector = SkEndian_SwapBE16(entrySelector);
1716 header->rangeShift = SkEndian_SwapBE16(rangeShift);
1717 dataPtr += sizeof(SkSFNTHeader);
1718
1719 // write tables
1720 SkSFNTHeader::TableDirectoryEntry* entry = (SkSFNTHeader::TableDirectoryEntry*)dataPtr;
1721 dataPtr += sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables;
1722 for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
1723 size_t tableSize = tableSizes[tableIndex];
1724 this->getTableData(tableTags[tableIndex], 0, tableSize, dataPtr);
1725 entry->tag = SkEndian_SwapBE32(tableTags[tableIndex]);
1726 entry->checksum = SkEndian_SwapBE32(SkOTUtils::CalcTableChecksum((SK_OT_ULONG*)dataPtr,
1727 tableSize));
1728 entry->offset = SkEndian_SwapBE32(SkToU32(dataPtr - dataStart));
1729 entry->logicalLength = SkEndian_SwapBE32(SkToU32(tableSize));
1730
1731 dataPtr += (tableSize + 3) & ~3;
1732 ++entry;
1733 }
1734
1735 return stream;
1736 }
1737
1738 ///////////////////////////////////////////////////////////////////////////////
1739 ///////////////////////////////////////////////////////////////////////////////
1740
onGetUPEM() const1741 int SkTypeface_Mac::onGetUPEM() const {
1742 AutoCFRelease<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef, NULL));
1743 return CGFontGetUnitsPerEm(cgFont);
1744 }
1745
onCreateFamilyNameIterator() const1746 SkTypeface::LocalizedStrings* SkTypeface_Mac::onCreateFamilyNameIterator() const {
1747 SkTypeface::LocalizedStrings* nameIter =
1748 SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*this);
1749 if (NULL == nameIter) {
1750 AutoCFRelease<CFStringRef> cfLanguage;
1751 AutoCFRelease<CFStringRef> cfFamilyName(
1752 CTFontCopyLocalizedName(fFontRef, kCTFontFamilyNameKey, &cfLanguage));
1753
1754 SkString skLanguage;
1755 SkString skFamilyName;
1756 if (cfLanguage.get()) {
1757 CFStringToSkString(cfLanguage.get(), &skLanguage);
1758 } else {
1759 skLanguage = "und"; //undetermined
1760 }
1761 if (cfFamilyName.get()) {
1762 CFStringToSkString(cfFamilyName.get(), &skFamilyName);
1763 }
1764
1765 nameIter = new SkOTUtils::LocalizedStrings_SingleName(skFamilyName, skLanguage);
1766 }
1767 return nameIter;
1768 }
1769
1770 // If, as is the case with web fonts, the CTFont data isn't available,
1771 // the CGFont data may work. While the CGFont may always provide the
1772 // right result, leave the CTFont code path to minimize disruption.
copyTableFromFont(CTFontRef ctFont,SkFontTableTag tag)1773 static CFDataRef copyTableFromFont(CTFontRef ctFont, SkFontTableTag tag) {
1774 CFDataRef data = CTFontCopyTable(ctFont, (CTFontTableTag) tag,
1775 kCTFontTableOptionNoOptions);
1776 if (NULL == data) {
1777 AutoCFRelease<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont, NULL));
1778 data = CGFontCopyTableForTag(cgFont, tag);
1779 }
1780 return data;
1781 }
1782
onGetTableTags(SkFontTableTag tags[]) const1783 int SkTypeface_Mac::onGetTableTags(SkFontTableTag tags[]) const {
1784 AutoCFRelease<CFArrayRef> cfArray(CTFontCopyAvailableTables(fFontRef,
1785 kCTFontTableOptionNoOptions));
1786 if (NULL == cfArray) {
1787 return 0;
1788 }
1789 int count = SkToInt(CFArrayGetCount(cfArray));
1790 if (tags) {
1791 for (int i = 0; i < count; ++i) {
1792 uintptr_t fontTag = reinterpret_cast<uintptr_t>(CFArrayGetValueAtIndex(cfArray, i));
1793 tags[i] = static_cast<SkFontTableTag>(fontTag);
1794 }
1795 }
1796 return count;
1797 }
1798
onGetTableData(SkFontTableTag tag,size_t offset,size_t length,void * dstData) const1799 size_t SkTypeface_Mac::onGetTableData(SkFontTableTag tag, size_t offset,
1800 size_t length, void* dstData) const {
1801 AutoCFRelease<CFDataRef> srcData(copyTableFromFont(fFontRef, tag));
1802 if (NULL == srcData) {
1803 return 0;
1804 }
1805
1806 size_t srcSize = CFDataGetLength(srcData);
1807 if (offset >= srcSize) {
1808 return 0;
1809 }
1810 if (length > srcSize - offset) {
1811 length = srcSize - offset;
1812 }
1813 if (dstData) {
1814 memcpy(dstData, CFDataGetBytePtr(srcData) + offset, length);
1815 }
1816 return length;
1817 }
1818
onCreateScalerContext(const SkDescriptor * desc) const1819 SkScalerContext* SkTypeface_Mac::onCreateScalerContext(const SkDescriptor* desc) const {
1820 return new SkScalerContext_Mac(const_cast<SkTypeface_Mac*>(this), desc);
1821 }
1822
onFilterRec(SkScalerContextRec * rec) const1823 void SkTypeface_Mac::onFilterRec(SkScalerContextRec* rec) const {
1824 if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag ||
1825 rec->fFlags & SkScalerContext::kLCD_Vertical_Flag)
1826 {
1827 rec->fMaskFormat = SkMask::kA8_Format;
1828 // Render the glyphs as close as possible to what was requested.
1829 // The above turns off subpixel rendering, but the user requested it.
1830 // Normal hinting will cause the A8 masks to be generated from CoreGraphics subpixel masks.
1831 // See comments below for more details.
1832 rec->setHinting(SkPaint::kNormal_Hinting);
1833 }
1834
1835 unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag |
1836 SkScalerContext::kForceAutohinting_Flag |
1837 SkScalerContext::kLCD_BGROrder_Flag |
1838 SkScalerContext::kLCD_Vertical_Flag;
1839
1840 rec->fFlags &= ~flagsWeDontSupport;
1841
1842 bool lcdSupport = supports_LCD();
1843
1844 // Only two levels of hinting are supported.
1845 // kNo_Hinting means avoid CoreGraphics outline dilation.
1846 // kNormal_Hinting means CoreGraphics outline dilation is allowed.
1847 // If there is no lcd support, hinting (dilation) cannot be supported.
1848 SkPaint::Hinting hinting = rec->getHinting();
1849 if (SkPaint::kSlight_Hinting == hinting || !lcdSupport) {
1850 hinting = SkPaint::kNo_Hinting;
1851 } else if (SkPaint::kFull_Hinting == hinting) {
1852 hinting = SkPaint::kNormal_Hinting;
1853 }
1854 rec->setHinting(hinting);
1855
1856 // FIXME: lcd smoothed un-hinted rasterization unsupported.
1857 // Tracked by http://code.google.com/p/skia/issues/detail?id=915 .
1858 // There is no current means to honor a request for unhinted lcd,
1859 // so arbitrarilly ignore the hinting request and honor lcd.
1860
1861 // Hinting and smoothing should be orthogonal, but currently they are not.
1862 // CoreGraphics has no API to influence hinting. However, its lcd smoothed
1863 // output is drawn from auto-dilated outlines (the amount of which is
1864 // determined by AppleFontSmoothing). Its regular anti-aliased output is
1865 // drawn from un-dilated outlines.
1866
1867 // The behavior of Skia is as follows:
1868 // [AA][no-hint]: generate AA using CoreGraphic's AA output.
1869 // [AA][yes-hint]: use CoreGraphic's LCD output and reduce it to a single
1870 // channel. This matches [LCD][yes-hint] in weight.
1871 // [LCD][no-hint]: curently unable to honor, and must pick which to respect.
1872 // Currenly side with LCD, effectively ignoring the hinting setting.
1873 // [LCD][yes-hint]: generate LCD using CoreGraphic's LCD output.
1874
1875 if (isLCDFormat(rec->fMaskFormat)) {
1876 if (lcdSupport) {
1877 //CoreGraphics creates 555 masks for smoothed text anyway.
1878 rec->fMaskFormat = SkMask::kLCD16_Format;
1879 rec->setHinting(SkPaint::kNormal_Hinting);
1880 } else {
1881 rec->fMaskFormat = SkMask::kA8_Format;
1882 }
1883 }
1884
1885 // Unhinted A8 masks (those not derived from LCD masks) must respect SK_GAMMA_APPLY_TO_A8.
1886 // All other masks can use regular gamma.
1887 if (SkMask::kA8_Format == rec->fMaskFormat && SkPaint::kNo_Hinting == hinting) {
1888 #ifndef SK_GAMMA_APPLY_TO_A8
1889 rec->ignorePreBlend();
1890 #endif
1891 } else {
1892 //CoreGraphics dialates smoothed text as needed.
1893 rec->setContrast(0);
1894 }
1895 }
1896
1897 // we take ownership of the ref
get_str(CFStringRef ref,SkString * str)1898 static const char* get_str(CFStringRef ref, SkString* str) {
1899 CFStringToSkString(ref, str);
1900 CFSafeRelease(ref);
1901 return str->c_str();
1902 }
1903
onGetFontDescriptor(SkFontDescriptor * desc,bool * isLocalStream) const1904 void SkTypeface_Mac::onGetFontDescriptor(SkFontDescriptor* desc,
1905 bool* isLocalStream) const {
1906 SkString tmpStr;
1907
1908 desc->setFamilyName(get_str(CTFontCopyFamilyName(fFontRef), &tmpStr));
1909 desc->setFullName(get_str(CTFontCopyFullName(fFontRef), &tmpStr));
1910 desc->setPostscriptName(get_str(CTFontCopyPostScriptName(fFontRef), &tmpStr));
1911 // TODO: need to add support for local-streams (here and openStream)
1912 *isLocalStream = false;
1913 }
1914
onCharsToGlyphs(const void * chars,Encoding encoding,uint16_t glyphs[],int glyphCount) const1915 int SkTypeface_Mac::onCharsToGlyphs(const void* chars, Encoding encoding,
1916 uint16_t glyphs[], int glyphCount) const
1917 {
1918 // Undocumented behavior of CTFontGetGlyphsForCharacters with non-bmp code points:
1919 // When a surrogate pair is detected, the glyph index used is the index of the high surrogate.
1920 // It is documented that if a mapping is unavailable, the glyph will be set to 0.
1921
1922 SkAutoSTMalloc<1024, UniChar> charStorage;
1923 const UniChar* src; // UniChar is a UTF-16 16-bit code unit.
1924 int srcCount;
1925 switch (encoding) {
1926 case kUTF8_Encoding: {
1927 const char* utf8 = reinterpret_cast<const char*>(chars);
1928 UniChar* utf16 = charStorage.reset(2 * glyphCount);
1929 src = utf16;
1930 for (int i = 0; i < glyphCount; ++i) {
1931 SkUnichar uni = SkUTF8_NextUnichar(&utf8);
1932 utf16 += SkUTF16_FromUnichar(uni, utf16);
1933 }
1934 srcCount = SkToInt(utf16 - src);
1935 break;
1936 }
1937 case kUTF16_Encoding: {
1938 src = reinterpret_cast<const UniChar*>(chars);
1939 int extra = 0;
1940 for (int i = 0; i < glyphCount; ++i) {
1941 if (SkUTF16_IsHighSurrogate(src[i + extra])) {
1942 ++extra;
1943 }
1944 }
1945 srcCount = glyphCount + extra;
1946 break;
1947 }
1948 case kUTF32_Encoding: {
1949 const SkUnichar* utf32 = reinterpret_cast<const SkUnichar*>(chars);
1950 UniChar* utf16 = charStorage.reset(2 * glyphCount);
1951 src = utf16;
1952 for (int i = 0; i < glyphCount; ++i) {
1953 utf16 += SkUTF16_FromUnichar(utf32[i], utf16);
1954 }
1955 srcCount = SkToInt(utf16 - src);
1956 break;
1957 }
1958 }
1959
1960 // If glyphs is NULL, CT still needs glyph storage for finding the first failure.
1961 // Also, if there are any non-bmp code points, the provided 'glyphs' storage will be inadequate.
1962 SkAutoSTMalloc<1024, uint16_t> glyphStorage;
1963 uint16_t* macGlyphs = glyphs;
1964 if (NULL == macGlyphs || srcCount > glyphCount) {
1965 macGlyphs = glyphStorage.reset(srcCount);
1966 }
1967
1968 bool allEncoded = CTFontGetGlyphsForCharacters(fFontRef, src, macGlyphs, srcCount);
1969
1970 // If there were any non-bmp, then copy and compact.
1971 // If 'glyphs' is NULL, then compact glyphStorage in-place.
1972 // If all are bmp and 'glyphs' is non-NULL, 'glyphs' already contains the compact glyphs.
1973 // If some are non-bmp and 'glyphs' is non-NULL, copy and compact into 'glyphs'.
1974 uint16_t* compactedGlyphs = glyphs;
1975 if (NULL == compactedGlyphs) {
1976 compactedGlyphs = macGlyphs;
1977 }
1978 if (srcCount > glyphCount) {
1979 int extra = 0;
1980 for (int i = 0; i < glyphCount; ++i) {
1981 if (SkUTF16_IsHighSurrogate(src[i + extra])) {
1982 ++extra;
1983 }
1984 compactedGlyphs[i] = macGlyphs[i + extra];
1985 }
1986 }
1987
1988 if (allEncoded) {
1989 return glyphCount;
1990 }
1991
1992 // If we got false, then we need to manually look for first failure.
1993 for (int i = 0; i < glyphCount; ++i) {
1994 if (0 == compactedGlyphs[i]) {
1995 return i;
1996 }
1997 }
1998 // Odd to get here, as we expected CT to have returned true up front.
1999 return glyphCount;
2000 }
2001
onCountGlyphs() const2002 int SkTypeface_Mac::onCountGlyphs() const {
2003 return SkToInt(CTFontGetGlyphCount(fFontRef));
2004 }
2005
2006 ///////////////////////////////////////////////////////////////////////////////
2007 ///////////////////////////////////////////////////////////////////////////////
2008 #if 1
2009
find_desc_str(CTFontDescriptorRef desc,CFStringRef name,SkString * value)2010 static bool find_desc_str(CTFontDescriptorRef desc, CFStringRef name, SkString* value) {
2011 AutoCFRelease<CFStringRef> ref((CFStringRef)CTFontDescriptorCopyAttribute(desc, name));
2012 if (NULL == ref.get()) {
2013 return false;
2014 }
2015 CFStringToSkString(ref, value);
2016 return true;
2017 }
2018
find_dict_float(CFDictionaryRef dict,CFStringRef name,float * value)2019 static bool find_dict_float(CFDictionaryRef dict, CFStringRef name, float* value) {
2020 CFNumberRef num;
2021 return CFDictionaryGetValueIfPresent(dict, name, (const void**)&num)
2022 && CFNumberIsFloatType(num)
2023 && CFNumberGetValue(num, kCFNumberFloatType, value);
2024 }
2025
2026 #include "SkFontMgr.h"
2027
unit_weight_to_fontstyle(float unit)2028 static int unit_weight_to_fontstyle(float unit) {
2029 float value;
2030 if (unit < 0) {
2031 value = 100 + (1 + unit) * 300;
2032 } else {
2033 value = 400 + unit * 500;
2034 }
2035 return sk_float_round2int(value);
2036 }
2037
unit_width_to_fontstyle(float unit)2038 static int unit_width_to_fontstyle(float unit) {
2039 float value;
2040 if (unit < 0) {
2041 value = 1 + (1 + unit) * 4;
2042 } else {
2043 value = 5 + unit * 4;
2044 }
2045 return sk_float_round2int(value);
2046 }
2047
sqr(int value)2048 static inline int sqr(int value) {
2049 SkASSERT(SkAbs32(value) < 0x7FFF); // check for overflow
2050 return value * value;
2051 }
2052
2053 // We normalize each axis (weight, width, italic) to be base-900
compute_metric(const SkFontStyle & a,const SkFontStyle & b)2054 static int compute_metric(const SkFontStyle& a, const SkFontStyle& b) {
2055 return sqr(a.weight() - b.weight()) +
2056 sqr((a.width() - b.width()) * 100) +
2057 sqr((a.isItalic() != b.isItalic()) * 900);
2058 }
2059
desc2fontstyle(CTFontDescriptorRef desc)2060 static SkFontStyle desc2fontstyle(CTFontDescriptorRef desc) {
2061 AutoCFRelease<CFDictionaryRef> dict(
2062 (CFDictionaryRef)CTFontDescriptorCopyAttribute(desc,
2063 kCTFontTraitsAttribute));
2064 if (NULL == dict.get()) {
2065 return SkFontStyle();
2066 }
2067
2068 float weight, width, slant;
2069 if (!find_dict_float(dict, kCTFontWeightTrait, &weight)) {
2070 weight = 0;
2071 }
2072 if (!find_dict_float(dict, kCTFontWidthTrait, &width)) {
2073 width = 0;
2074 }
2075 if (!find_dict_float(dict, kCTFontSlantTrait, &slant)) {
2076 slant = 0;
2077 }
2078
2079 return SkFontStyle(unit_weight_to_fontstyle(weight),
2080 unit_width_to_fontstyle(width),
2081 slant ? SkFontStyle::kItalic_Slant
2082 : SkFontStyle::kUpright_Slant);
2083 }
2084
2085 struct NameFontStyleRec {
2086 SkString fFamilyName;
2087 SkFontStyle fFontStyle;
2088 };
2089
nameFontStyleProc(SkTypeface * face,SkTypeface::Style,void * ctx)2090 static bool nameFontStyleProc(SkTypeface* face, SkTypeface::Style,
2091 void* ctx) {
2092 SkTypeface_Mac* macFace = (SkTypeface_Mac*)face;
2093 const NameFontStyleRec* rec = (const NameFontStyleRec*)ctx;
2094
2095 return macFace->fFontStyle == rec->fFontStyle &&
2096 macFace->fName == rec->fFamilyName;
2097 }
2098
createFromDesc(CFStringRef cfFamilyName,CTFontDescriptorRef desc)2099 static SkTypeface* createFromDesc(CFStringRef cfFamilyName,
2100 CTFontDescriptorRef desc) {
2101 NameFontStyleRec rec;
2102 CFStringToSkString(cfFamilyName, &rec.fFamilyName);
2103 rec.fFontStyle = desc2fontstyle(desc);
2104
2105 SkTypeface* face = SkTypefaceCache::FindByProcAndRef(nameFontStyleProc,
2106 &rec);
2107 if (face) {
2108 return face;
2109 }
2110
2111 AutoCFRelease<CFDictionaryRef> fontFamilyNameDictionary(
2112 CFDictionaryCreate(kCFAllocatorDefault,
2113 (const void**)&kCTFontFamilyNameAttribute, (const void**)&cfFamilyName,
2114 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
2115 AutoCFRelease<CTFontDescriptorRef> fontDescriptor(
2116 CTFontDescriptorCreateWithAttributes(fontFamilyNameDictionary));
2117 AutoCFRelease<CTFontRef> ctNamed(CTFontCreateWithFontDescriptor(fontDescriptor, 0, NULL));
2118 CTFontRef ctFont = CTFontCreateCopyWithAttributes(ctNamed, 1, NULL, desc);
2119 if (NULL == ctFont) {
2120 return NULL;
2121 }
2122
2123 SkString str;
2124 CFStringToSkString(cfFamilyName, &str);
2125
2126 bool isFixedPitch;
2127 (void)computeStyleBits(ctFont, &isFixedPitch);
2128 SkFontID fontID = CTFontRef_to_SkFontID(ctFont);
2129
2130 face = SkNEW_ARGS(SkTypeface_Mac, (rec.fFontStyle, fontID, isFixedPitch,
2131 ctFont, str.c_str()));
2132 SkTypefaceCache::Add(face, face->style());
2133 return face;
2134 }
2135
2136 class SkFontStyleSet_Mac : public SkFontStyleSet {
2137 public:
SkFontStyleSet_Mac(CFStringRef familyName,CTFontDescriptorRef desc)2138 SkFontStyleSet_Mac(CFStringRef familyName, CTFontDescriptorRef desc)
2139 : fArray(CTFontDescriptorCreateMatchingFontDescriptors(desc, NULL))
2140 , fFamilyName(familyName)
2141 , fCount(0) {
2142 CFRetain(familyName);
2143 if (NULL == fArray) {
2144 fArray = CFArrayCreate(NULL, NULL, 0, NULL);
2145 }
2146 fCount = SkToInt(CFArrayGetCount(fArray));
2147 }
2148
~SkFontStyleSet_Mac()2149 virtual ~SkFontStyleSet_Mac() {
2150 CFRelease(fArray);
2151 CFRelease(fFamilyName);
2152 }
2153
count()2154 virtual int count() SK_OVERRIDE {
2155 return fCount;
2156 }
2157
getStyle(int index,SkFontStyle * style,SkString * name)2158 virtual void getStyle(int index, SkFontStyle* style,
2159 SkString* name) SK_OVERRIDE {
2160 SkASSERT((unsigned)index < (unsigned)fCount);
2161 CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray, index);
2162 if (style) {
2163 *style = desc2fontstyle(desc);
2164 }
2165 if (name) {
2166 if (!find_desc_str(desc, kCTFontStyleNameAttribute, name)) {
2167 name->reset();
2168 }
2169 }
2170 }
2171
createTypeface(int index)2172 virtual SkTypeface* createTypeface(int index) SK_OVERRIDE {
2173 SkASSERT((unsigned)index < (unsigned)CFArrayGetCount(fArray));
2174 CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray, index);
2175
2176 return createFromDesc(fFamilyName, desc);
2177 }
2178
matchStyle(const SkFontStyle & pattern)2179 virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE {
2180 if (0 == fCount) {
2181 return NULL;
2182 }
2183 return createFromDesc(fFamilyName, findMatchingDesc(pattern));
2184 }
2185
2186 private:
2187 CFArrayRef fArray;
2188 CFStringRef fFamilyName;
2189 int fCount;
2190
findMatchingDesc(const SkFontStyle & pattern) const2191 CTFontDescriptorRef findMatchingDesc(const SkFontStyle& pattern) const {
2192 int bestMetric = SK_MaxS32;
2193 CTFontDescriptorRef bestDesc = NULL;
2194
2195 for (int i = 0; i < fCount; ++i) {
2196 CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray, i);
2197 int metric = compute_metric(pattern, desc2fontstyle(desc));
2198 if (0 == metric) {
2199 return desc;
2200 }
2201 if (metric < bestMetric) {
2202 bestMetric = metric;
2203 bestDesc = desc;
2204 }
2205 }
2206 SkASSERT(bestDesc);
2207 return bestDesc;
2208 }
2209 };
2210
2211 class SkFontMgr_Mac : public SkFontMgr {
2212 CFArrayRef fNames;
2213 int fCount;
2214
stringAt(int index) const2215 CFStringRef stringAt(int index) const {
2216 SkASSERT((unsigned)index < (unsigned)fCount);
2217 return (CFStringRef)CFArrayGetValueAtIndex(fNames, index);
2218 }
2219
CreateSet(CFStringRef cfFamilyName)2220 static SkFontStyleSet* CreateSet(CFStringRef cfFamilyName) {
2221 AutoCFRelease<CFMutableDictionaryRef> cfAttr(
2222 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2223 &kCFTypeDictionaryKeyCallBacks,
2224 &kCFTypeDictionaryValueCallBacks));
2225
2226 CFDictionaryAddValue(cfAttr, kCTFontFamilyNameAttribute, cfFamilyName);
2227
2228 AutoCFRelease<CTFontDescriptorRef> desc(
2229 CTFontDescriptorCreateWithAttributes(cfAttr));
2230 return SkNEW_ARGS(SkFontStyleSet_Mac, (cfFamilyName, desc));
2231 }
2232
2233 public:
SkFontMgr_Mac()2234 SkFontMgr_Mac()
2235 : fNames(SkCTFontManagerCopyAvailableFontFamilyNames())
2236 , fCount(fNames ? SkToInt(CFArrayGetCount(fNames)) : 0) {}
2237
~SkFontMgr_Mac()2238 virtual ~SkFontMgr_Mac() {
2239 CFSafeRelease(fNames);
2240 }
2241
2242 protected:
onCountFamilies() const2243 virtual int onCountFamilies() const SK_OVERRIDE {
2244 return fCount;
2245 }
2246
onGetFamilyName(int index,SkString * familyName) const2247 virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERRIDE {
2248 if ((unsigned)index < (unsigned)fCount) {
2249 CFStringToSkString(this->stringAt(index), familyName);
2250 } else {
2251 familyName->reset();
2252 }
2253 }
2254
onCreateStyleSet(int index) const2255 virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE {
2256 if ((unsigned)index >= (unsigned)fCount) {
2257 return NULL;
2258 }
2259 return CreateSet(this->stringAt(index));
2260 }
2261
onMatchFamily(const char familyName[]) const2262 virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVERRIDE {
2263 AutoCFRelease<CFStringRef> cfName(make_CFString(familyName));
2264 return CreateSet(cfName);
2265 }
2266
onMatchFamilyStyle(const char familyName[],const SkFontStyle &) const2267 virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
2268 const SkFontStyle&) const SK_OVERRIDE {
2269 return NULL;
2270 }
2271
onMatchFaceStyle(const SkTypeface * familyMember,const SkFontStyle &) const2272 virtual SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember,
2273 const SkFontStyle&) const SK_OVERRIDE {
2274 return NULL;
2275 }
2276
onCreateFromData(SkData * data,int ttcIndex) const2277 virtual SkTypeface* onCreateFromData(SkData* data,
2278 int ttcIndex) const SK_OVERRIDE {
2279 AutoCFRelease<CGDataProviderRef> pr(SkCreateDataProviderFromData(data));
2280 if (NULL == pr) {
2281 return NULL;
2282 }
2283 return create_from_dataProvider(pr);
2284 }
2285
onCreateFromStream(SkStream * stream,int ttcIndex) const2286 virtual SkTypeface* onCreateFromStream(SkStream* stream,
2287 int ttcIndex) const SK_OVERRIDE {
2288 AutoCFRelease<CGDataProviderRef> pr(SkCreateDataProviderFromStream(stream));
2289 if (NULL == pr) {
2290 return NULL;
2291 }
2292 return create_from_dataProvider(pr);
2293 }
2294
onCreateFromFile(const char path[],int ttcIndex) const2295 virtual SkTypeface* onCreateFromFile(const char path[],
2296 int ttcIndex) const SK_OVERRIDE {
2297 AutoCFRelease<CGDataProviderRef> pr(CGDataProviderCreateWithFilename(path));
2298 if (NULL == pr) {
2299 return NULL;
2300 }
2301 return create_from_dataProvider(pr);
2302 }
2303
onLegacyCreateTypeface(const char familyName[],unsigned styleBits) const2304 virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
2305 unsigned styleBits) const SK_OVERRIDE {
2306 return create_typeface(NULL, familyName, (SkTypeface::Style)styleBits);
2307 }
2308 };
2309
2310 ///////////////////////////////////////////////////////////////////////////////
2311
Factory()2312 SkFontMgr* SkFontMgr::Factory() {
2313 return SkNEW(SkFontMgr_Mac);
2314 }
2315 #endif
2316