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