• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <CoreGraphics/CoreGraphics.h>
17 #include <CoreFoundation/CoreFoundation.h>
18 #endif
19 
20 #include "SkFontHost.h"
21 #include "SkCGUtils.h"
22 #include "SkDescriptor.h"
23 #include "SkEndian.h"
24 #include "SkFloatingPoint.h"
25 #include "SkPaint.h"
26 #include "SkString.h"
27 #include "SkStream.h"
28 #include "SkThread.h"
29 #include "SkTypeface_mac.h"
30 #include "SkUtils.h"
31 #include "SkTypefaceCache.h"
32 
33 class SkScalerContext_Mac;
34 
CFSafeRelease(CFTypeRef obj)35 static void CFSafeRelease(CFTypeRef obj) {
36     if (obj) {
37         CFRelease(obj);
38     }
39 }
40 
41 class AutoCFRelease : SkNoncopyable {
42 public:
AutoCFRelease(CFTypeRef obj)43     AutoCFRelease(CFTypeRef obj) : fObj(obj) {}
~AutoCFRelease()44     ~AutoCFRelease() { CFSafeRelease(fObj); }
45 
46 private:
47     CFTypeRef fObj;
48 };
49 
50 // inline versions of these rect helpers
51 
CGRectIsEmpty_inline(const CGRect & rect)52 static bool CGRectIsEmpty_inline(const CGRect& rect) {
53     return rect.size.width <= 0 || rect.size.height <= 0;
54 }
55 
CGRectInset_inline(CGRect * rect,CGFloat dx,CGFloat dy)56 static void CGRectInset_inline(CGRect* rect, CGFloat dx, CGFloat dy) {
57     rect->origin.x += dx;
58     rect->origin.y += dy;
59     rect->size.width -= dx * 2;
60     rect->size.height -= dy * 2;
61 }
62 
CGRectGetMinX_inline(const CGRect & rect)63 static CGFloat CGRectGetMinX_inline(const CGRect& rect) {
64     return rect.origin.x;
65 }
66 
CGRectGetMaxX_inline(const CGRect & rect)67 static CGFloat CGRectGetMaxX_inline(const CGRect& rect) {
68     return rect.origin.x + rect.size.width;
69 }
70 
CGRectGetMinY_inline(const CGRect & rect)71 static CGFloat CGRectGetMinY_inline(const CGRect& rect) {
72     return rect.origin.y;
73 }
74 
CGRectGetMaxY_inline(const CGRect & rect)75 static CGFloat CGRectGetMaxY_inline(const CGRect& rect) {
76     return rect.origin.y + rect.size.height;
77 }
78 
CGRectGetWidth_inline(const CGRect & rect)79 static CGFloat CGRectGetWidth_inline(const CGRect& rect) {
80     return rect.size.width;
81 }
82 
CGRectGetHeight(const CGRect & rect)83 static CGFloat CGRectGetHeight(const CGRect& rect) {
84     return rect.size.height;
85 }
86 
87 ///////////////////////////////////////////////////////////////////////////////
88 
sk_memset_rect32(uint32_t * ptr,uint32_t value,size_t width,size_t height,size_t rowBytes)89 static void sk_memset_rect32(uint32_t* ptr, uint32_t value, size_t width,
90                              size_t height, size_t rowBytes) {
91     SkASSERT(width);
92     SkASSERT(width * sizeof(uint32_t) <= rowBytes);
93 
94     if (width >= 32) {
95         while (height) {
96             sk_memset32(ptr, value, width);
97             ptr = (uint32_t*)((char*)ptr + rowBytes);
98             height -= 1;
99         }
100         return;
101     }
102 
103     rowBytes -= width * sizeof(uint32_t);
104 
105     if (width >= 8) {
106         while (height) {
107             int w = width;
108             do {
109                 *ptr++ = value; *ptr++ = value;
110                 *ptr++ = value; *ptr++ = value;
111                 *ptr++ = value; *ptr++ = value;
112                 *ptr++ = value; *ptr++ = value;
113                 w -= 8;
114             } while (w >= 8);
115             while (--w >= 0) {
116                 *ptr++ = value;
117             }
118             ptr = (uint32_t*)((char*)ptr + rowBytes);
119             height -= 1;
120         }
121     } else {
122         while (height) {
123             int w = width;
124             do {
125                 *ptr++ = value;
126             } while (--w > 0);
127             ptr = (uint32_t*)((char*)ptr + rowBytes);
128             height -= 1;
129         }
130     }
131 }
132 
133 // Potentially this should be made (1) public (2) optimized when width is small.
134 // Also might want 16 and 32 bit version
135 //
sk_memset_rect(void * ptr,U8CPU byte,size_t width,size_t height,size_t rowBytes)136 static void sk_memset_rect(void* ptr, U8CPU byte, size_t width, size_t height,
137                            size_t rowBytes) {
138     uint8_t* dst = (uint8_t*)ptr;
139     while (height) {
140         memset(dst, byte, width);
141         dst += rowBytes;
142         height -= 1;
143     }
144 }
145 
146 #include <sys/utsname.h>
147 
148 typedef uint32_t CGRGBPixel;
149 
CGRGBPixel_getAlpha(CGRGBPixel pixel)150 static unsigned CGRGBPixel_getAlpha(CGRGBPixel pixel) {
151     return pixel & 0xFF;
152 }
153 
154 // The calls to support subpixel are present in 10.5, but are not included in
155 // the 10.5 SDK. The needed calls have been extracted from the 10.6 SDK and are
156 // included below. To verify that CGContextSetShouldSubpixelQuantizeFonts, for
157 // instance, is present in the 10.5 CoreGraphics libary, use:
158 //   cd /Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/
159 //   cd ApplicationServices.framework/Frameworks/CoreGraphics.framework/
160 //   nm CoreGraphics | grep CGContextSetShouldSubpixelQuantizeFonts
161 
162 #if !defined(MAC_OS_X_VERSION_10_6) || \
163         MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
164     CG_EXTERN void CGContextSetAllowsFontSmoothing(CGContextRef context,
165         bool allowsFontSmoothing);
166     CG_EXTERN void CGContextSetAllowsFontSubpixelPositioning(
167         CGContextRef context,
168         bool allowsFontSubpixelPositioning);
169     CG_EXTERN void CGContextSetShouldSubpixelPositionFonts(CGContextRef context,
170         bool shouldSubpixelPositionFonts);
171     CG_EXTERN void CGContextSetAllowsFontSubpixelQuantization(
172         CGContextRef context,
173         bool allowsFontSubpixelQuantization);
174     CG_EXTERN void CGContextSetShouldSubpixelQuantizeFonts(
175         CGContextRef context,
176         bool shouldSubpixelQuantizeFonts);
177 #endif
178 
179 static const char FONT_DEFAULT_NAME[]           = "Lucida Sans";
180 
181 // see Source/WebKit/chromium/base/mac/mac_util.mm DarwinMajorVersionInternal
182 // for original source
readVersion()183 static int readVersion() {
184     struct utsname info;
185     if (uname(&info) != 0) {
186         SkDebugf("uname failed\n");
187         return 0;
188     }
189     if (strcmp(info.sysname, "Darwin") != 0) {
190         SkDebugf("unexpected uname sysname %s\n", info.sysname);
191         return 0;
192     }
193     char* dot = strchr(info.release, '.');
194     if (!dot) {
195         SkDebugf("expected dot in uname release %s\n", info.release);
196         return 0;
197     }
198     int version = atoi(info.release);
199     if (version == 0) {
200         SkDebugf("could not parse uname release %s\n", info.release);
201     }
202     return version;
203 }
204 
darwinVersion()205 static int darwinVersion() {
206     static int darwin_version = readVersion();
207     return darwin_version;
208 }
209 
isLeopard()210 static bool isLeopard() {
211     return darwinVersion() == 9;
212 }
213 
isSnowLeopard()214 static bool isSnowLeopard() {
215     return darwinVersion() == 10;
216 }
217 
isLion()218 static bool isLion() {
219     return darwinVersion() == 11;
220 }
221 
isLCDFormat(unsigned format)222 static bool isLCDFormat(unsigned format) {
223     return SkMask::kLCD16_Format == format || SkMask::kLCD32_Format == format;
224 }
225 
ScalarToCG(SkScalar scalar)226 static CGFloat ScalarToCG(SkScalar scalar) {
227     if (sizeof(CGFloat) == sizeof(float)) {
228         return SkScalarToFloat(scalar);
229     } else {
230         SkASSERT(sizeof(CGFloat) == sizeof(double));
231         return SkScalarToDouble(scalar);
232     }
233 }
234 
CGToScalar(CGFloat cgFloat)235 static SkScalar CGToScalar(CGFloat cgFloat) {
236     if (sizeof(CGFloat) == sizeof(float)) {
237         return SkFloatToScalar(cgFloat);
238     } else {
239         SkASSERT(sizeof(CGFloat) == sizeof(double));
240         return SkDoubleToScalar(cgFloat);
241     }
242 }
243 
MatrixToCGAffineTransform(const SkMatrix & matrix,float sx=1,float sy=1)244 static CGAffineTransform MatrixToCGAffineTransform(const SkMatrix& matrix,
245                                                    float sx = 1, float sy = 1) {
246     return CGAffineTransformMake(ScalarToCG(matrix[SkMatrix::kMScaleX]) * sx,
247                                  -ScalarToCG(matrix[SkMatrix::kMSkewY]) * sy,
248                                  -ScalarToCG(matrix[SkMatrix::kMSkewX]) * sx,
249                                  ScalarToCG(matrix[SkMatrix::kMScaleY]) * sy,
250                                  ScalarToCG(matrix[SkMatrix::kMTransX]) * sx,
251                                  ScalarToCG(matrix[SkMatrix::kMTransY]) * sy);
252 }
253 
CGAffineTransformToMatrix(const CGAffineTransform & xform,SkMatrix * matrix)254 static void CGAffineTransformToMatrix(const CGAffineTransform& xform, SkMatrix* matrix) {
255     matrix->setAll(
256                    CGToScalar(xform.a), CGToScalar(xform.c), CGToScalar(xform.tx),
257                    CGToScalar(xform.b), CGToScalar(xform.d), CGToScalar(xform.ty),
258                    0, 0, SK_Scalar1);
259 }
260 
getFontScale(CGFontRef cgFont)261 static SkScalar getFontScale(CGFontRef cgFont) {
262     int unitsPerEm = CGFontGetUnitsPerEm(cgFont);
263     return SkScalarInvert(SkIntToScalar(unitsPerEm));
264 }
265 
266 ///////////////////////////////////////////////////////////////////////////////
267 
268 #define BITMAP_INFO_RGB     (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host)
269 #define BITMAP_INFO_GRAY    (kCGImageAlphaNone)
270 
271 class Offscreen {
272 public:
273     Offscreen();
274     ~Offscreen();
275 
276     CGRGBPixel* getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
277                       bool fgColorIsWhite, CGGlyph glyphID, size_t* rowBytesPtr);
278 
279 private:
280     enum {
281         kSize = 32 * 32 * sizeof(CGRGBPixel)
282     };
283     SkAutoSMalloc<kSize> fImageStorage;
284     CGColorSpaceRef fRGBSpace;
285 
286     // cached state
287     CGContextRef    fCG;
288     SkISize         fSize;
289     bool            fFgColorIsWhite;
290     bool            fDoAA;
291     bool            fDoLCD;
292 
RoundSize(int dimension)293     static int RoundSize(int dimension) {
294         return SkNextPow2(dimension);
295     }
296 };
297 
Offscreen()298 Offscreen::Offscreen() : fRGBSpace(NULL), fCG(NULL) {
299     fSize.set(0,0);
300 }
301 
~Offscreen()302 Offscreen::~Offscreen() {
303     CFSafeRelease(fCG);
304     CFSafeRelease(fRGBSpace);
305 }
306 
307 ///////////////////////////////////////////////////////////////////////////////
308 
computeStyleBits(CTFontRef font,bool * isMonospace)309 static SkTypeface::Style computeStyleBits(CTFontRef font, bool* isMonospace) {
310     unsigned style = SkTypeface::kNormal;
311     CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(font);
312 
313     if (traits & kCTFontBoldTrait) {
314         style |= SkTypeface::kBold;
315     }
316     if (traits & kCTFontItalicTrait) {
317         style |= SkTypeface::kItalic;
318     }
319     if (isMonospace) {
320         *isMonospace = (traits & kCTFontMonoSpaceTrait) != 0;
321     }
322     return (SkTypeface::Style)style;
323 }
324 
325 class AutoCFDataRelease {
326 public:
AutoCFDataRelease(CFDataRef obj)327     AutoCFDataRelease(CFDataRef obj) : fObj(obj) {}
getShortPtr()328     const uint16_t* getShortPtr() {
329         return fObj ? (const uint16_t*) CFDataGetBytePtr(fObj) : NULL;
330     }
~AutoCFDataRelease()331     ~AutoCFDataRelease() { CFSafeRelease(fObj); }
332 private:
333     CFDataRef fObj;
334 };
335 
CTFontRef_to_SkFontID(CTFontRef fontRef)336 static SkFontID CTFontRef_to_SkFontID(CTFontRef fontRef) {
337     ATSFontRef ats = CTFontGetPlatformFont(fontRef, NULL);
338     SkFontID id = (SkFontID)ats;
339     if (id != 0) {
340         id &= 0x3FFFFFFF; // make top two bits 00
341         return id;
342     }
343     // CTFontGetPlatformFont returns NULL if the font is local
344     // (e.g., was created by a CSS3 @font-face rule).
345     CGFontRef cgFont = CTFontCopyGraphicsFont(fontRef, NULL);
346     AutoCFDataRelease headRef(CGFontCopyTableForTag(cgFont, 'head'));
347     const uint16_t* headData = headRef.getShortPtr();
348     if (headData) {
349         id = (SkFontID) (headData[4] | headData[5] << 16); // checksum
350         id = (id & 0x3FFFFFFF) | 0x40000000; // make top two bits 01
351     }
352     // well-formed fonts have checksums, but as a last resort, use the pointer.
353     if (id == 0) {
354         id = (SkFontID) (uintptr_t) fontRef;
355         id = (id & 0x3FFFFFFF) | 0x80000000; // make top two bits 10
356     }
357     CGFontRelease(cgFont);
358     return id;
359 }
360 
361 class SkTypeface_Mac : public SkTypeface {
362 public:
SkTypeface_Mac(SkTypeface::Style style,SkFontID fontID,bool isMonospace,CTFontRef fontRef,const char name[])363     SkTypeface_Mac(SkTypeface::Style style, SkFontID fontID, bool isMonospace,
364                    CTFontRef fontRef, const char name[])
365     : SkTypeface(style, fontID, isMonospace) {
366         SkASSERT(fontRef);
367         fFontRef = fontRef; // caller has already called CFRetain for us
368         fName.set(name);
369     }
370 
~SkTypeface_Mac()371     virtual ~SkTypeface_Mac() { CFRelease(fFontRef); }
372 
373     SkString    fName;
374     CTFontRef   fFontRef;
375 };
376 
NewFromFontRef(CTFontRef fontRef,const char name[])377 static SkTypeface* NewFromFontRef(CTFontRef fontRef, const char name[]) {
378     SkASSERT(fontRef);
379     bool isMonospace;
380     SkTypeface::Style style = computeStyleBits(fontRef, &isMonospace);
381     SkFontID fontID = CTFontRef_to_SkFontID(fontRef);
382 
383     return new SkTypeface_Mac(style, fontID, isMonospace, fontRef, name);
384 }
385 
NewFromName(const char familyName[],SkTypeface::Style theStyle)386 static SkTypeface* NewFromName(const char familyName[],
387                                SkTypeface::Style theStyle) {
388     CFMutableDictionaryRef      cfAttributes, cfTraits;
389     CFNumberRef                 cfFontTraits;
390     CTFontSymbolicTraits        ctFontTraits;
391     CTFontDescriptorRef         ctFontDesc;
392     CFStringRef                 cfFontName;
393     CTFontRef                   ctFont;
394 
395 
396     // Get the state we need
397     ctFontDesc   = NULL;
398     ctFont       = NULL;
399     ctFontTraits = 0;
400 
401     if (theStyle & SkTypeface::kBold) {
402         ctFontTraits |= kCTFontBoldTrait;
403     }
404 
405     if (theStyle & SkTypeface::kItalic) {
406         ctFontTraits |= kCTFontItalicTrait;
407     }
408 
409     // Create the font info
410     cfFontName   = CFStringCreateWithCString(NULL, familyName, kCFStringEncodingUTF8);
411     cfFontTraits = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &ctFontTraits);
412     cfAttributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
413     cfTraits     = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
414 
415 
416     // Create the font
417     if (cfFontName != NULL && cfFontTraits != NULL && cfAttributes != NULL && cfTraits != NULL) {
418         CFDictionaryAddValue(cfTraits, kCTFontSymbolicTrait, cfFontTraits);
419 
420         CFDictionaryAddValue(cfAttributes, kCTFontFamilyNameAttribute, cfFontName);
421         CFDictionaryAddValue(cfAttributes, kCTFontTraitsAttribute,     cfTraits);
422 
423         ctFontDesc = CTFontDescriptorCreateWithAttributes(cfAttributes);
424         if (ctFontDesc != NULL) {
425             if (isLeopard()) {
426                 // CTFontCreateWithFontDescriptor on Leopard ignores the name
427                 CTFontRef ctNamed = CTFontCreateWithName(cfFontName, 1, NULL);
428                 ctFont = CTFontCreateCopyWithAttributes(ctNamed, 1, NULL,
429                                                         ctFontDesc);
430                 CFSafeRelease(ctNamed);
431             } else {
432                 ctFont = CTFontCreateWithFontDescriptor(ctFontDesc, 0, NULL);
433             }
434         }
435     }
436 
437     CFSafeRelease(cfFontName);
438     CFSafeRelease(cfFontTraits);
439     CFSafeRelease(cfAttributes);
440     CFSafeRelease(cfTraits);
441     CFSafeRelease(ctFontDesc);
442 
443     return ctFont ? NewFromFontRef(ctFont, familyName) : NULL;
444 }
445 
GetFontRefFromFontID(SkFontID fontID)446 static CTFontRef GetFontRefFromFontID(SkFontID fontID) {
447     SkTypeface_Mac* face = reinterpret_cast<SkTypeface_Mac*>(SkTypefaceCache::FindByID(fontID));
448     return face ? face->fFontRef : 0;
449 }
450 
GetDefaultFace()451 static SkTypeface* GetDefaultFace() {
452     SK_DECLARE_STATIC_MUTEX(gMutex);
453     SkAutoMutexAcquire ma(gMutex);
454 
455     static SkTypeface* gDefaultFace;
456 
457     if (NULL == gDefaultFace) {
458         gDefaultFace = NewFromName(FONT_DEFAULT_NAME, SkTypeface::kNormal);
459         SkTypefaceCache::Add(gDefaultFace, SkTypeface::kNormal);
460     }
461     return gDefaultFace;
462 }
463 
464 ///////////////////////////////////////////////////////////////////////////////
465 
466 extern CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face);
SkTypeface_GetCTFontRef(const SkTypeface * face)467 CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face) {
468     const SkTypeface_Mac* macface = (const SkTypeface_Mac*)face;
469     return macface ? macface->fFontRef : NULL;
470 }
471 
472 /*  This function is visible on the outside. It first searches the cache, and if
473  *  not found, returns a new entry (after adding it to the cache).
474  */
SkCreateTypefaceFromCTFont(CTFontRef fontRef)475 SkTypeface* SkCreateTypefaceFromCTFont(CTFontRef fontRef) {
476     SkFontID fontID = CTFontRef_to_SkFontID(fontRef);
477     SkTypeface* face = SkTypefaceCache::FindByID(fontID);
478     if (face) {
479         face->ref();
480     } else {
481         face = NewFromFontRef(fontRef, NULL);
482         SkTypefaceCache::Add(face, face->style());
483         // NewFromFontRef doesn't retain the parameter, but the typeface it
484         // creates does release it in its destructor, so we balance that with
485         // a retain call here.
486         CFRetain(fontRef);
487     }
488     SkASSERT(face->getRefCnt() > 1);
489     return face;
490 }
491 
492 struct NameStyleRec {
493     const char*         fName;
494     SkTypeface::Style   fStyle;
495 };
496 
FindByNameStyle(SkTypeface * face,SkTypeface::Style style,void * ctx)497 static bool FindByNameStyle(SkTypeface* face, SkTypeface::Style style,
498                             void* ctx) {
499     const SkTypeface_Mac* mface = reinterpret_cast<SkTypeface_Mac*>(face);
500     const NameStyleRec* rec = reinterpret_cast<const NameStyleRec*>(ctx);
501 
502     return rec->fStyle == style && mface->fName.equals(rec->fName);
503 }
504 
map_css_names(const char * name)505 static const char* map_css_names(const char* name) {
506     static const struct {
507         const char* fFrom;  // name the caller specified
508         const char* fTo;    // "canonical" name we map to
509     } gPairs[] = {
510         { "sans-serif", "Helvetica" },
511         { "serif",      "Times"     },
512         { "monospace",  "Courier"   }
513     };
514 
515     for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
516         if (strcmp(name, gPairs[i].fFrom) == 0) {
517             return gPairs[i].fTo;
518         }
519     }
520     return name;    // no change
521 }
522 
CreateTypeface(const SkTypeface * familyFace,const char familyName[],const void * data,size_t bytelength,SkTypeface::Style style)523 SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
524                                        const char familyName[],
525                                        const void* data, size_t bytelength,
526                                        SkTypeface::Style style) {
527     if (familyName) {
528         familyName = map_css_names(familyName);
529     }
530 
531     // Clone an existing typeface
532     // TODO: only clone if style matches the familyFace's style...
533     if (familyName == NULL && familyFace != NULL) {
534         familyFace->ref();
535         return const_cast<SkTypeface*>(familyFace);
536     }
537 
538     if (!familyName || !*familyName) {
539         familyName = FONT_DEFAULT_NAME;
540     }
541 
542     NameStyleRec rec = { familyName, style };
543     SkTypeface* face = SkTypefaceCache::FindByProcAndRef(FindByNameStyle, &rec);
544 
545     if (NULL == face) {
546         face = NewFromName(familyName, style);
547         if (face) {
548             SkTypefaceCache::Add(face, style);
549         } else {
550             face = GetDefaultFace();
551             face->ref();
552         }
553     }
554     return face;
555 }
556 
flip(SkMatrix * matrix)557 static void flip(SkMatrix* matrix) {
558     matrix->setSkewX(-matrix->getSkewX());
559     matrix->setSkewY(-matrix->getSkewY());
560 }
561 
562 ///////////////////////////////////////////////////////////////////////////////
563 
564 struct GlyphRect {
565     int16_t fMinX;
566     int16_t fMinY;
567     int16_t fMaxX;
568     int16_t fMaxY;
569 };
570 
571 class SkScalerContext_Mac : public SkScalerContext {
572 public:
573                                         SkScalerContext_Mac(const SkDescriptor* desc);
574     virtual                            ~SkScalerContext_Mac(void);
575 
576 
577 protected:
578     unsigned                            generateGlyphCount(void);
579     uint16_t                            generateCharToGlyph(SkUnichar uni);
580     void                                generateAdvance(SkGlyph* glyph);
581     void                                generateMetrics(SkGlyph* glyph);
582     void                                generateImage(const SkGlyph& glyph);
583     void                                generatePath( const SkGlyph& glyph, SkPath* path);
584     void                                generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY);
585 
586 
587 private:
588     static void                         CTPathElement(void *info, const CGPathElement *element);
589     uint16_t                            getAdjustStart();
590     void                                getVerticalOffset(CGGlyph glyphID, SkIPoint* offset) const;
591     bool                                generateBBoxes();
592 
593 private:
594     CGAffineTransform                   fTransform;
595     SkMatrix                            fUnitMatrix; // without font size
596     SkMatrix                            fVerticalMatrix; // unit rotated
597     SkMatrix                            fMatrix; // with font size
598     SkMatrix                            fAdjustBadMatrix; // lion-specific fix
599 #ifdef SK_USE_COLOR_LUMINANCE
600     Offscreen                           fBlackScreen;
601     Offscreen                           fWhiteScreen;
602 #else
603     Offscreen                           fOffscreen;
604 #endif
605     CTFontRef                           fCTFont;
606     CTFontRef                           fCTVerticalFont; // for vertical advance
607     CGFontRef                           fCGFont;
608     GlyphRect*                          fAdjustBad;
609     uint16_t                            fAdjustStart;
610     uint16_t                            fGlyphCount;
611     bool                                fGeneratedBBoxes;
612     bool                                fDoSubPosition;
613     bool                                fVertical;
614 
615     friend class                        Offscreen;
616 };
617 
SkScalerContext_Mac(const SkDescriptor * desc)618 SkScalerContext_Mac::SkScalerContext_Mac(const SkDescriptor* desc)
619         : SkScalerContext(desc)
620         , fCTVerticalFont(NULL)
621         , fAdjustBad(NULL)
622         , fAdjustStart(0)
623         , fGeneratedBBoxes(false)
624 {
625     CTFontRef ctFont = GetFontRefFromFontID(fRec.fFontID);
626     CFIndex numGlyphs = CTFontGetGlyphCount(ctFont);
627 
628     // Get the state we need
629     fRec.getSingleMatrix(&fMatrix);
630     fUnitMatrix = fMatrix;
631 
632     // extract the font size out of the matrix, but leave the skewing for italic
633     SkScalar reciprocal = SkScalarInvert(fRec.fTextSize);
634     fUnitMatrix.preScale(reciprocal, reciprocal);
635 
636     SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF);
637 
638     fTransform = MatrixToCGAffineTransform(fMatrix);
639 
640     CGAffineTransform transform;
641     CGFloat unitFontSize;
642     if (isLeopard()) {
643         // passing 1 for pointSize to Leopard sets the font size to 1 pt.
644         // pass the CoreText size explicitly
645         transform = MatrixToCGAffineTransform(fUnitMatrix);
646         unitFontSize = SkScalarToFloat(fRec.fTextSize);
647     } else {
648         // since our matrix includes everything, we pass 1 for pointSize
649         transform = fTransform;
650         unitFontSize = 1;
651     }
652     flip(&fUnitMatrix); // flip to fix up bounds later
653     fVertical = SkToBool(fRec.fFlags & kVertical_Flag);
654     CTFontDescriptorRef ctFontDesc = NULL;
655     if (fVertical) {
656         CFMutableDictionaryRef cfAttributes = CFDictionaryCreateMutable(
657                 kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
658                 &kCFTypeDictionaryValueCallBacks);
659         if (cfAttributes) {
660             CTFontOrientation ctOrientation = kCTFontVerticalOrientation;
661             CFNumberRef cfVertical = CFNumberCreate(kCFAllocatorDefault,
662                     kCFNumberSInt32Type, &ctOrientation);
663             CFDictionaryAddValue(cfAttributes, kCTFontOrientationAttribute,
664                     cfVertical);
665             CFSafeRelease(cfVertical);
666             ctFontDesc = CTFontDescriptorCreateWithAttributes(cfAttributes);
667             CFRelease(cfAttributes);
668         }
669     }
670     fCTFont = CTFontCreateCopyWithAttributes(ctFont, unitFontSize, &transform,
671             ctFontDesc);
672     CFSafeRelease(ctFontDesc);
673     fCGFont = CTFontCopyGraphicsFont(fCTFont, NULL);
674     if (fVertical) {
675         CGAffineTransform rotateLeft = CGAffineTransformMake(0, -1, 1, 0, 0, 0);
676         transform = CGAffineTransformConcat(rotateLeft, transform);
677         fCTVerticalFont = CTFontCreateCopyWithAttributes(ctFont, unitFontSize,
678                 &transform, NULL);
679         fVerticalMatrix = fUnitMatrix;
680         if (isSnowLeopard()) {
681             SkScalar scale = SkScalarMul(fRec.fTextSize, getFontScale(fCGFont));
682             fVerticalMatrix.preScale(scale, scale);
683         } else {
684             fVerticalMatrix.preRotate(SkIntToScalar(90));
685         }
686         fVerticalMatrix.postScale(SK_Scalar1, -SK_Scalar1);
687     }
688     fGlyphCount = SkToU16(numGlyphs);
689     fDoSubPosition = SkToBool(fRec.fFlags & kSubpixelPositioning_Flag);
690 }
691 
~SkScalerContext_Mac()692 SkScalerContext_Mac::~SkScalerContext_Mac() {
693     delete[] fAdjustBad;
694     CFSafeRelease(fCTFont);
695     CFSafeRelease(fCTVerticalFont);
696     CFSafeRelease(fCGFont);
697 }
698 
getCG(const SkScalerContext_Mac & context,const SkGlyph & glyph,bool fgColorIsWhite,CGGlyph glyphID,size_t * rowBytesPtr)699 CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
700                              bool fgColorIsWhite, CGGlyph glyphID, size_t* rowBytesPtr) {
701     if (!fRGBSpace) {
702         fRGBSpace = CGColorSpaceCreateDeviceRGB();
703     }
704 
705     // default to kBW_Format
706     bool doAA = false;
707     bool doLCD = false;
708 
709     switch (glyph.fMaskFormat) {
710         case SkMask::kLCD16_Format:
711         case SkMask::kLCD32_Format:
712             doLCD = true;
713             doAA = true;
714             break;
715         case SkMask::kA8_Format:
716             doLCD = false;
717             doAA = true;
718             break;
719         default:
720             break;
721     }
722 
723     size_t rowBytes = fSize.fWidth * sizeof(CGRGBPixel);
724     if (!fCG || fSize.fWidth < glyph.fWidth || fSize.fHeight < glyph.fHeight) {
725         CFSafeRelease(fCG);
726         if (fSize.fWidth < glyph.fWidth) {
727             fSize.fWidth = RoundSize(glyph.fWidth);
728         }
729         if (fSize.fHeight < glyph.fHeight) {
730             fSize.fHeight = RoundSize(glyph.fHeight);
731         }
732 
733         rowBytes = fSize.fWidth * sizeof(CGRGBPixel);
734         void* image = fImageStorage.reset(rowBytes * fSize.fHeight);
735         fCG = CGBitmapContextCreate(image, fSize.fWidth, fSize.fHeight, 8,
736                                     rowBytes, fRGBSpace, BITMAP_INFO_RGB);
737 
738         // skia handles quantization itself, so we disable this for cg to get
739         // full fractional data from them.
740         CGContextSetAllowsFontSubpixelQuantization(fCG, false);
741         CGContextSetShouldSubpixelQuantizeFonts(fCG, false);
742 
743         CGContextSetTextDrawingMode(fCG, kCGTextFill);
744         CGContextSetFont(fCG, context.fCGFont);
745         CGContextSetFontSize(fCG, 1);
746         CGContextSetTextMatrix(fCG, context.fTransform);
747 
748         CGContextSetAllowsFontSubpixelPositioning(fCG, context.fDoSubPosition);
749         CGContextSetShouldSubpixelPositionFonts(fCG, context.fDoSubPosition);
750 
751         // force our checks below to happen
752         fDoAA = !doAA;
753         fDoLCD = !doLCD;
754         fFgColorIsWhite = !fgColorIsWhite;
755     }
756 
757     if (fDoAA != doAA) {
758         CGContextSetShouldAntialias(fCG, doAA);
759         fDoAA = doAA;
760     }
761     if (fDoLCD != doLCD) {
762         CGContextSetShouldSmoothFonts(fCG, doLCD);
763         fDoLCD = doLCD;
764     }
765     if (fFgColorIsWhite != fgColorIsWhite) {
766         CGContextSetGrayFillColor(fCG, fgColorIsWhite ? 1.0 : 0, 1.0);
767         fFgColorIsWhite = fgColorIsWhite;
768     }
769 
770     CGRGBPixel* image = (CGRGBPixel*)fImageStorage.get();
771     // skip rows based on the glyph's height
772     image += (fSize.fHeight - glyph.fHeight) * fSize.fWidth;
773 
774     // erase with the "opposite" of the fgColor
775     uint32_t erase = fgColorIsWhite ? 0 : ~0;
776 #if 0
777     sk_memset_rect(image, erase, glyph.fWidth * sizeof(CGRGBPixel),
778                    glyph.fHeight, rowBytes);
779 #else
780     sk_memset_rect32(image, erase, glyph.fWidth, glyph.fHeight, rowBytes);
781 #endif
782 
783     float subX = 0;
784     float subY = 0;
785     if (context.fDoSubPosition) {
786         subX = SkFixedToFloat(glyph.getSubXFixed());
787         subY = SkFixedToFloat(glyph.getSubYFixed());
788     }
789     if (context.fVertical) {
790         SkIPoint offset;
791         context.getVerticalOffset(glyphID, &offset);
792         subX += offset.fX;
793         subY += offset.fY;
794     }
795     CGContextShowGlyphsAtPoint(fCG, -glyph.fLeft + subX,
796                                glyph.fTop + glyph.fHeight - subY,
797                                &glyphID, 1);
798 
799     SkASSERT(rowBytesPtr);
800     *rowBytesPtr = rowBytes;
801     return image;
802 }
803 
getVerticalOffset(CGGlyph glyphID,SkIPoint * offset) const804 void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkIPoint* offset) const {
805     CGSize vertOffset;
806     CTFontGetVerticalTranslationsForGlyphs(fCTVerticalFont, &glyphID, &vertOffset, 1);
807     const SkPoint trans = {SkFloatToScalar(vertOffset.width),
808                            SkFloatToScalar(vertOffset.height)};
809     SkPoint floatOffset;
810     fVerticalMatrix.mapPoints(&floatOffset, &trans, 1);
811     if (!isSnowLeopard()) {
812     // SnowLeopard fails to apply the font's matrix to the vertical metrics,
813     // but Lion and Leopard do. The unit matrix describes the font's matrix at
814     // point size 1. There may be some way to avoid mapping here by setting up
815     // fVerticalMatrix differently, but this works for now.
816         fUnitMatrix.mapPoints(&floatOffset, 1);
817     }
818     offset->fX = SkScalarRound(floatOffset.fX);
819     offset->fY = SkScalarRound(floatOffset.fY);
820 }
821 
822 /* from http://developer.apple.com/fonts/TTRefMan/RM06/Chap6loca.html
823  * There are two versions of this table, the short and the long. The version
824  * used is specified in the Font Header ('head') table in the indexToLocFormat
825  * field. The choice of long or short offsets is dependent on the maximum
826  * possible offset distance.
827  *
828  * 'loca' short version: The actual local offset divided by 2 is stored.
829  * 'loca' long version: The actual local offset is stored.
830  *
831  * The result is a offset into a table of 2 byte (16 bit) entries.
832  */
getLocaTableEntry(const uint16_t * & locaPtr,int locaFormat)833 static uint32_t getLocaTableEntry(const uint16_t*& locaPtr, int locaFormat) {
834     uint32_t data = SkEndian_SwapBE16(*locaPtr++); // short
835     if (locaFormat) {
836         data = data << 15 | SkEndian_SwapBE16(*locaPtr++) >> 1; // long
837     }
838     return data;
839 }
840 
841 // see http://developer.apple.com/fonts/TTRefMan/RM06/Chap6hhea.html
getNumLongMetrics(const uint16_t * hheaData)842 static uint16_t getNumLongMetrics(const uint16_t* hheaData) {
843     const int kNumOfLongHorMetrics = 17;
844     return SkEndian_SwapBE16(hheaData[kNumOfLongHorMetrics]);
845 }
846 
847 // see http://developer.apple.com/fonts/TTRefMan/RM06/Chap6head.html
getLocaFormat(const uint16_t * headData)848 static int getLocaFormat(const uint16_t* headData) {
849     const int kIndexToLocFormat = 25;
850     return SkEndian_SwapBE16(headData[kIndexToLocFormat]);
851 }
852 
getAdjustStart()853 uint16_t SkScalerContext_Mac::getAdjustStart() {
854     if (fAdjustStart) {
855         return fAdjustStart;
856     }
857     fAdjustStart = fGlyphCount; // fallback for all fonts
858     AutoCFDataRelease hheaRef(CGFontCopyTableForTag(fCGFont, 'hhea'));
859     const uint16_t* hheaData = hheaRef.getShortPtr();
860     if (hheaData) {
861         fAdjustStart = getNumLongMetrics(hheaData);
862     }
863     return fAdjustStart;
864 }
865 
866 /*
867  * Lion has a bug in CTFontGetBoundingRectsForGlyphs which returns a bad value
868  * in theBounds.origin.x for fonts whose numOfLogHorMetrics is less than its
869  * glyph count. This workaround reads the glyph bounds from the font directly.
870  *
871  * The table is computed only if the font is a TrueType font, if the glyph
872  * value is >= fAdjustStart. (called only if fAdjustStart < fGlyphCount).
873  *
874  * TODO: A future optimization will compute fAdjustBad once per CGFont, and
875  * compute fAdjustBadMatrix once per font context.
876  */
generateBBoxes()877 bool SkScalerContext_Mac::generateBBoxes() {
878     if (fGeneratedBBoxes) {
879         return NULL != fAdjustBad;
880     }
881     fGeneratedBBoxes = true;
882     AutoCFDataRelease headRef(CGFontCopyTableForTag(fCGFont, 'head'));
883     const uint16_t* headData = headRef.getShortPtr();
884     if (!headData) {
885         return false;
886     }
887     AutoCFDataRelease locaRef(CGFontCopyTableForTag(fCGFont, 'loca'));
888     const uint16_t* locaData = locaRef.getShortPtr();
889     if (!locaData) {
890         return false;
891     }
892     AutoCFDataRelease glyfRef(CGFontCopyTableForTag(fCGFont, 'glyf'));
893     const uint16_t* glyfData = glyfRef.getShortPtr();
894     if (!glyfData) {
895         return false;
896     }
897     CFIndex entries = fGlyphCount - fAdjustStart;
898     fAdjustBad = new GlyphRect[entries];
899     int locaFormat = getLocaFormat(headData);
900     const uint16_t* locaPtr = &locaData[fAdjustStart << locaFormat];
901     uint32_t last = getLocaTableEntry(locaPtr, locaFormat);
902     for (CFIndex index = 0; index < entries; ++index) {
903         uint32_t offset = getLocaTableEntry(locaPtr, locaFormat);
904         GlyphRect& rect = fAdjustBad[index];
905         if (offset != last) {
906             rect.fMinX = SkEndian_SwapBE16(glyfData[last + 1]);
907             rect.fMinY = SkEndian_SwapBE16(glyfData[last + 2]);
908             rect.fMaxX = SkEndian_SwapBE16(glyfData[last + 3]);
909             rect.fMaxY = SkEndian_SwapBE16(glyfData[last + 4]);
910         } else {
911             sk_bzero(&rect, sizeof(GlyphRect));
912         }
913         last = offset;
914     }
915     fAdjustBadMatrix = fMatrix;
916     flip(&fAdjustBadMatrix);
917     SkScalar fontScale = getFontScale(fCGFont);
918     fAdjustBadMatrix.preScale(fontScale, fontScale);
919     return true;
920 }
921 
generateGlyphCount(void)922 unsigned SkScalerContext_Mac::generateGlyphCount(void)
923 {
924     return(fGlyphCount);
925 }
926 
generateCharToGlyph(SkUnichar uni)927 uint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni)
928 {   CGGlyph     cgGlyph;
929     UniChar     theChar;
930 
931 
932     // Validate our parameters and state
933     SkASSERT(uni             <= 0x0000FFFF);
934     SkASSERT(sizeof(CGGlyph) <= sizeof(uint16_t));
935 
936 
937     // Get the glyph
938     theChar = (UniChar) uni;
939 
940     if (!CTFontGetGlyphsForCharacters(fCTFont, &theChar, &cgGlyph, 1))
941         cgGlyph = 0;
942 
943     return(cgGlyph);
944 }
945 
generateAdvance(SkGlyph * glyph)946 void SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) {
947     this->generateMetrics(glyph);
948 }
949 
generateMetrics(SkGlyph * glyph)950 void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) {
951     CGSize      theAdvance;
952     CGRect      theBounds;
953     CGGlyph     cgGlyph;
954 
955     // Get the state we need
956     cgGlyph = (CGGlyph) glyph->getGlyphID(fBaseGlyphCount);
957 
958     if (fVertical) {
959         if (!isSnowLeopard()) {
960         // Lion and Leopard respect the vertical font metrics.
961             CTFontGetBoundingRectsForGlyphs(fCTVerticalFont,
962                                             kCTFontVerticalOrientation,
963                                             &cgGlyph, &theBounds,  1);
964         } else {
965         // Snow Leopard and earlier respect the vertical font metrics for
966         // advances, but not bounds, so use the default box and adjust it below.
967             CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontDefaultOrientation,
968                                             &cgGlyph, &theBounds,  1);
969         }
970         CTFontGetAdvancesForGlyphs(fCTVerticalFont, kCTFontVerticalOrientation,
971                                    &cgGlyph, &theAdvance, 1);
972     } else {
973         CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontDefaultOrientation,
974                                         &cgGlyph, &theBounds, 1);
975         CTFontGetAdvancesForGlyphs(fCTFont, kCTFontDefaultOrientation,
976                                    &cgGlyph, &theAdvance, 1);
977     }
978 
979     // BUG?
980     // 0x200B (zero-advance space) seems to return a huge (garbage) bounds, when
981     // it should be empty. So, if we see a zero-advance, we check if it has an
982     // empty path or not, and if so, we jam the bounds to 0. Hopefully a zero-advance
983     // is rare, so we won't incur a big performance cost for this extra check.
984     if (0 == theAdvance.width && 0 == theAdvance.height) {
985         CGPathRef path = CTFontCreatePathForGlyph(fCTFont, cgGlyph, NULL);
986         if (NULL == path || CGPathIsEmpty(path)) {
987             theBounds = CGRectMake(0, 0, 0, 0);
988         }
989         if (path) {
990             CGPathRelease(path);
991         }
992     }
993 
994     glyph->zeroMetrics();
995     glyph->fAdvanceX =  SkFloatToFixed(theAdvance.width);
996     glyph->fAdvanceY = -SkFloatToFixed(theAdvance.height);
997 
998     if (CGRectIsEmpty_inline(theBounds)) {
999         return;
1000     }
1001 
1002     if (isLeopard() && !fVertical) {
1003         // Leopard does not consider the matrix skew in its bounds.
1004         // Run the bounding rectangle through the skew matrix to determine
1005         // the true bounds. However, this doesn't work if the font is vertical.
1006         // FIXME (Leopard): If the font has synthetic italic (e.g., matrix skew)
1007         // and the font is vertical, the bounds need to be recomputed.
1008         SkRect glyphBounds = SkRect::MakeXYWH(
1009                 theBounds.origin.x, theBounds.origin.y,
1010                 theBounds.size.width, theBounds.size.height);
1011         fUnitMatrix.mapRect(&glyphBounds);
1012         theBounds.origin.x = glyphBounds.fLeft;
1013         theBounds.origin.y = glyphBounds.fTop;
1014         theBounds.size.width = glyphBounds.width();
1015         theBounds.size.height = glyphBounds.height();
1016     }
1017     // Adjust the bounds
1018     //
1019     // CTFontGetBoundingRectsForGlyphs ignores the font transform, so we need
1020     // to transform the bounding box ourselves.
1021     //
1022     // The bounds are also expanded by 1 pixel, to give CG room for anti-aliasing.
1023     CGRectInset_inline(&theBounds, -1, -1);
1024 
1025     // Get the metrics
1026     bool lionAdjustedMetrics = false;
1027     if (isLion()) {
1028         if (cgGlyph < fGlyphCount && cgGlyph >= getAdjustStart()
1029                     && generateBBoxes()) {
1030             lionAdjustedMetrics = true;
1031             SkRect adjust;
1032             const GlyphRect& gRect = fAdjustBad[cgGlyph - fAdjustStart];
1033             adjust.set(gRect.fMinX, gRect.fMinY, gRect.fMaxX, gRect.fMaxY);
1034             fAdjustBadMatrix.mapRect(&adjust);
1035             theBounds.origin.x = SkScalarToFloat(adjust.fLeft) - 1;
1036             theBounds.origin.y = SkScalarToFloat(adjust.fTop) - 1;
1037         }
1038         // Lion returns fractions in the bounds
1039         glyph->fWidth = sk_float_ceil2int(theBounds.size.width);
1040         glyph->fHeight = sk_float_ceil2int(theBounds.size.height);
1041     } else {
1042         glyph->fWidth = sk_float_round2int(theBounds.size.width);
1043         glyph->fHeight = sk_float_round2int(theBounds.size.height);
1044     }
1045     glyph->fTop      = -sk_float_round2int(CGRectGetMaxY_inline(theBounds));
1046     glyph->fLeft     =  sk_float_round2int(CGRectGetMinX_inline(theBounds));
1047     SkIPoint offset;
1048     if (fVertical && (isSnowLeopard() || lionAdjustedMetrics)) {
1049     // SnowLeopard doesn't respect vertical metrics, so compute them manually.
1050     // Also compute them for Lion when the metrics were computed by hand.
1051         getVerticalOffset(cgGlyph, &offset);
1052         glyph->fLeft += offset.fX;
1053         glyph->fTop += offset.fY;
1054     }
1055 }
1056 
1057 #include "SkColorPriv.h"
1058 
build_power_table(uint8_t table[],float ee)1059 static void build_power_table(uint8_t table[], float ee) {
1060     for (int i = 0; i < 256; i++) {
1061         float x = i / 255.f;
1062         x = powf(x, ee);
1063         int xx = SkScalarRoundToInt(SkFloatToScalar(x * 255));
1064         table[i] = SkToU8(xx);
1065     }
1066 }
1067 
getInverseTable(bool isWhite)1068 static const uint8_t* getInverseTable(bool isWhite) {
1069     static uint8_t gWhiteTable[256];
1070     static uint8_t gTable[256];
1071     static bool gInited;
1072     if (!gInited) {
1073         build_power_table(gWhiteTable, 1.5f);
1074         build_power_table(gTable, 2.2f);
1075         gInited = true;
1076     }
1077     return isWhite ? gWhiteTable : gTable;
1078 }
1079 
getGammaTable(U8CPU luminance)1080 static const uint8_t* getGammaTable(U8CPU luminance) {
1081     static uint8_t gGammaTables[4][256];
1082     static bool gInited;
1083     if (!gInited) {
1084 #if 1
1085         float start = 1.1;
1086         float stop = 2.1;
1087         for (int i = 0; i < 4; ++i) {
1088             float g = start + (stop - start) * i / 3;
1089             build_power_table(gGammaTables[i], 1/g);
1090         }
1091 #else
1092         build_power_table(gGammaTables[0], 1);
1093         build_power_table(gGammaTables[1], 1);
1094         build_power_table(gGammaTables[2], 1);
1095         build_power_table(gGammaTables[3], 1);
1096 #endif
1097         gInited = true;
1098     }
1099     SkASSERT(0 == (luminance >> 8));
1100     return gGammaTables[luminance >> 6];
1101 }
1102 
invertGammaMask(bool isWhite,CGRGBPixel rgb[],int width,int height,size_t rb)1103 static void invertGammaMask(bool isWhite, CGRGBPixel rgb[], int width,
1104                             int height, size_t rb) {
1105     const uint8_t* table = getInverseTable(isWhite);
1106     for (int y = 0; y < height; ++y) {
1107         for (int x = 0; x < width; ++x) {
1108             uint32_t c = rgb[x];
1109             int r = (c >> 16) & 0xFF;
1110             int g = (c >>  8) & 0xFF;
1111             int b = (c >>  0) & 0xFF;
1112             rgb[x] = (table[r] << 16) | (table[g] << 8) | table[b];
1113         }
1114         rgb = (CGRGBPixel*)((char*)rgb + rb);
1115     }
1116 }
1117 
cgpixels_to_bits(uint8_t dst[],const CGRGBPixel src[],int count)1118 static void cgpixels_to_bits(uint8_t dst[], const CGRGBPixel src[], int count) {
1119     while (count > 0) {
1120         uint8_t mask = 0;
1121         for (int i = 7; i >= 0; --i) {
1122             mask |= (CGRGBPixel_getAlpha(*src++) >> 7) << i;
1123             if (0 == --count) {
1124                 break;
1125             }
1126         }
1127         *dst++ = mask;
1128     }
1129 }
1130 
lerpScale(int dst,int src,int scale)1131 static int lerpScale(int dst, int src, int scale) {
1132     return dst + (scale * (src - dst) >> 23);
1133 }
1134 
lerpPixel(CGRGBPixel dst,CGRGBPixel src,int scaleR,int scaleG,int scaleB)1135 static CGRGBPixel lerpPixel(CGRGBPixel dst, CGRGBPixel src,
1136                             int scaleR, int scaleG, int scaleB) {
1137     int sr = (src >> 16) & 0xFF;
1138     int sg = (src >>  8) & 0xFF;
1139     int sb = (src >>  0) & 0xFF;
1140     int dr = (dst >> 16) & 0xFF;
1141     int dg = (dst >>  8) & 0xFF;
1142     int db = (dst >>  0) & 0xFF;
1143 
1144     int rr = lerpScale(dr, sr, scaleR);
1145     int rg = lerpScale(dg, sg, scaleG);
1146     int rb = lerpScale(db, sb, scaleB);
1147     return (rr << 16) | (rg << 8) | rb;
1148 }
1149 
lerpPixels(CGRGBPixel dst[],const CGRGBPixel src[],int width,int height,int rowBytes,int lumBits)1150 static void lerpPixels(CGRGBPixel dst[], const CGRGBPixel src[], int width,
1151                        int height, int rowBytes, int lumBits) {
1152 #ifdef SK_USE_COLOR_LUMINANCE
1153     int scaleR = (1 << 23) * SkColorGetR(lumBits) / 0xFF;
1154     int scaleG = (1 << 23) * SkColorGetG(lumBits) / 0xFF;
1155     int scaleB = (1 << 23) * SkColorGetB(lumBits) / 0xFF;
1156 #else
1157     int scale = (1 << 23) * lumBits / SkScalerContext::kLuminance_Max;
1158     int scaleR = scale;
1159     int scaleG = scale;
1160     int scaleB = scale;
1161 #endif
1162 
1163     for (int y = 0; y < height; ++y) {
1164         for (int x = 0; x < width; ++x) {
1165             // bit-not the src, since it was drawn from black, so we need the
1166             // compliment of those bits
1167             dst[x] = lerpPixel(dst[x], ~src[x], scaleR, scaleG, scaleB);
1168         }
1169         src = (CGRGBPixel*)((char*)src + rowBytes);
1170         dst = (CGRGBPixel*)((char*)dst + rowBytes);
1171     }
1172 }
1173 
1174 #if 1
r32_to_16(int x)1175 static inline int r32_to_16(int x) { return SkR32ToR16(x); }
g32_to_16(int x)1176 static inline int g32_to_16(int x) { return SkG32ToG16(x); }
b32_to_16(int x)1177 static inline int b32_to_16(int x) { return SkB32ToB16(x); }
1178 #else
round8to5(int x)1179 static inline int round8to5(int x) {
1180     return (x + 3 - (x >> 5) + (x >> 7)) >> 3;
1181 }
round8to6(int x)1182 static inline int round8to6(int x) {
1183     int xx = (x + 1 - (x >> 6) + (x >> 7)) >> 2;
1184     SkASSERT((unsigned)xx <= 63);
1185 
1186     int ix = x >> 2;
1187     SkASSERT(SkAbs32(xx - ix) <= 1);
1188     return xx;
1189 }
1190 
r32_to_16(int x)1191 static inline int r32_to_16(int x) { return round8to5(x); }
g32_to_16(int x)1192 static inline int g32_to_16(int x) { return round8to6(x); }
b32_to_16(int x)1193 static inline int b32_to_16(int x) { return round8to5(x); }
1194 #endif
1195 
rgb_to_lcd16(CGRGBPixel rgb)1196 static inline uint16_t rgb_to_lcd16(CGRGBPixel rgb) {
1197     int r = (rgb >> 16) & 0xFF;
1198     int g = (rgb >>  8) & 0xFF;
1199     int b = (rgb >>  0) & 0xFF;
1200 
1201     return SkPackRGB16(r32_to_16(r), g32_to_16(g), b32_to_16(b));
1202 }
1203 
rgb_to_lcd32(CGRGBPixel rgb)1204 static inline uint32_t rgb_to_lcd32(CGRGBPixel rgb) {
1205     int r = (rgb >> 16) & 0xFF;
1206     int g = (rgb >>  8) & 0xFF;
1207     int b = (rgb >>  0) & 0xFF;
1208 
1209     return SkPackARGB32(0xFF, r, g, b);
1210 }
1211 
1212 #define BLACK_LUMINANCE_LIMIT   0x40
1213 #define WHITE_LUMINANCE_LIMIT   0xA0
1214 
generateImage(const SkGlyph & glyph)1215 void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
1216     CGGlyph cgGlyph = (CGGlyph) glyph.getGlyphID(fBaseGlyphCount);
1217 
1218     const bool isLCD = isLCDFormat(glyph.fMaskFormat);
1219     const bool isBW = SkMask::kBW_Format == glyph.fMaskFormat;
1220     const bool isA8 = !isLCD && !isBW;
1221 
1222 #ifdef SK_USE_COLOR_LUMINANCE
1223     unsigned lumBits = fRec.getLuminanceColor();
1224     uint32_t xorMask = 0;
1225 
1226     if (isA8) {
1227         // for A8, we just want a component (they're all the same)
1228         lumBits = SkColorGetR(lumBits);
1229     }
1230 #else
1231     bool fgColorIsWhite = true;
1232     bool isWhite = fRec.getLuminanceByte() >= WHITE_LUMINANCE_LIMIT;
1233     bool isBlack = fRec.getLuminanceByte() <= BLACK_LUMINANCE_LIMIT;
1234     uint32_t xorMask;
1235     bool invertGamma = false;
1236 
1237     /*  For LCD16, we first create a temp offscreen cg-context in 32bit,
1238      *  erase to white, and then draw a black glyph into it. Then we can
1239      *  extract the r,g,b values, invert-them, and now we have the original
1240      *  src mask components, which we pack into our 16bit mask.
1241      */
1242     if (isLCD) {
1243         if (isBlack) {
1244             xorMask = ~0;
1245             fgColorIsWhite = false;
1246         } else {    /* white or neutral */
1247             xorMask = 0;
1248             invertGamma = true;
1249         }
1250     }
1251 #endif
1252 
1253     size_t cgRowBytes;
1254 #ifdef SK_USE_COLOR_LUMINANCE
1255     CGRGBPixel* cgPixels;
1256     const uint8_t* gammaTable = NULL;
1257 
1258     if (isLCD) {
1259         CGRGBPixel* wtPixels = NULL;
1260         CGRGBPixel* bkPixels = NULL;
1261         bool needBlack = true;
1262         bool needWhite = true;
1263 
1264         if (SK_ColorWHITE == lumBits) {
1265             needBlack = false;
1266         } else if (SK_ColorBLACK == lumBits) {
1267             needWhite = false;
1268         }
1269 
1270         if (needBlack) {
1271             bkPixels = fBlackScreen.getCG(*this, glyph, false, cgGlyph, &cgRowBytes);
1272             cgPixels = bkPixels;
1273             xorMask = ~0;
1274         }
1275         if (needWhite) {
1276             wtPixels = fWhiteScreen.getCG(*this, glyph, true, cgGlyph, &cgRowBytes);
1277             cgPixels = wtPixels;
1278             xorMask = 0;
1279         }
1280 
1281         if (wtPixels && bkPixels) {
1282             lerpPixels(wtPixels, bkPixels, glyph.fWidth, glyph.fHeight, cgRowBytes,
1283                        ~lumBits);
1284         }
1285     } else {    // isA8 or isBW
1286         cgPixels = fWhiteScreen.getCG(*this, glyph, true, cgGlyph, &cgRowBytes);
1287         if (isA8) {
1288             gammaTable = getGammaTable(lumBits);
1289         }
1290     }
1291 #else
1292     CGRGBPixel* cgPixels = fOffscreen.getCG(*this, glyph, fgColorIsWhite, cgGlyph,
1293                                             &cgRowBytes);
1294 #endif
1295 
1296     // Draw the glyph
1297     if (cgPixels != NULL) {
1298 
1299 #ifdef SK_USE_COLOR_LUMINANCE
1300 #else
1301         if (invertGamma) {
1302             invertGammaMask(isWhite, (uint32_t*)cgPixels,
1303                             glyph.fWidth, glyph.fHeight, cgRowBytes);
1304         }
1305 #endif
1306 
1307         int width = glyph.fWidth;
1308         switch (glyph.fMaskFormat) {
1309             case SkMask::kLCD32_Format: {
1310                 uint32_t* dst = (uint32_t*)glyph.fImage;
1311                 size_t dstRB = glyph.rowBytes();
1312                 for (int y = 0; y < glyph.fHeight; y++) {
1313                     for (int i = 0; i < width; i++) {
1314                         dst[i] = rgb_to_lcd32(cgPixels[i] ^ xorMask);
1315                     }
1316                     cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1317                     dst = (uint32_t*)((char*)dst + dstRB);
1318                 }
1319             } break;
1320             case SkMask::kLCD16_Format: {
1321                 // downsample from rgba to rgb565
1322                 uint16_t* dst = (uint16_t*)glyph.fImage;
1323                 size_t dstRB = glyph.rowBytes();
1324                 for (int y = 0; y < glyph.fHeight; y++) {
1325                     for (int i = 0; i < width; i++) {
1326                         dst[i] = rgb_to_lcd16(cgPixels[i] ^ xorMask);
1327                     }
1328                     cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1329                     dst = (uint16_t*)((char*)dst + dstRB);
1330                 }
1331             } break;
1332             case SkMask::kA8_Format: {
1333                 uint8_t* dst = (uint8_t*)glyph.fImage;
1334                 size_t dstRB = glyph.rowBytes();
1335                 for (int y = 0; y < glyph.fHeight; y++) {
1336                     for (int i = 0; i < width; ++i) {
1337                         unsigned alpha8 = CGRGBPixel_getAlpha(cgPixels[i]);
1338 #ifdef SK_USE_COLOR_LUMINANCE
1339                         alpha8 = gammaTable[alpha8];
1340 #endif
1341                         dst[i] = alpha8;
1342                     }
1343                     cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1344                     dst += dstRB;
1345                 }
1346             } break;
1347             case SkMask::kBW_Format: {
1348                 uint8_t* dst = (uint8_t*)glyph.fImage;
1349                 size_t dstRB = glyph.rowBytes();
1350                 for (int y = 0; y < glyph.fHeight; y++) {
1351                     cgpixels_to_bits(dst, cgPixels, width);
1352                     cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1353                     dst += dstRB;
1354                 }
1355             } break;
1356             default:
1357                 SkDEBUGFAIL("unexpected mask format");
1358                 break;
1359         }
1360     }
1361 }
1362 
1363 /*
1364  *  Our subpixel resolution is only 2 bits in each direction, so a scale of 4
1365  *  seems sufficient, and possibly even correct, to allow the hinted outline
1366  *  to be subpixel positioned.
1367  */
1368 #define kScaleForSubPixelPositionHinting  4
1369 
generatePath(const SkGlyph & glyph,SkPath * path)1370 void SkScalerContext_Mac::generatePath(const SkGlyph& glyph, SkPath* path) {
1371     CTFontRef font = fCTFont;
1372     float scaleX = 1;
1373     float scaleY = 1;
1374 
1375     /*
1376      *  For subpixel positioning, we want to return an unhinted outline, so it
1377      *  can be positioned nicely at fractional offsets. However, we special-case
1378      *  if the baseline of the (horizontal) text is axis-aligned. In those cases
1379      *  we want to retain hinting in the direction orthogonal to the baseline.
1380      *  e.g. for horizontal baseline, we want to retain hinting in Y.
1381      *  The way we remove hinting is to scale the font by some value (4) in that
1382      *  direction, ask for the path, and then scale the path back down.
1383      */
1384     if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
1385         SkMatrix m;
1386         fRec.getSingleMatrix(&m);
1387 
1388         // start out by assuming that we want no hining in X and Y
1389         scaleX = scaleY = kScaleForSubPixelPositionHinting;
1390         // now see if we need to restore hinting for axis-aligned baselines
1391         switch (SkComputeAxisAlignmentForHText(m)) {
1392             case kX_SkAxisAlignment:
1393                 scaleY = 1; // want hinting in the Y direction
1394                 break;
1395             case kY_SkAxisAlignment:
1396                 scaleX = 1; // want hinting in the X direction
1397                 break;
1398             default:
1399                 break;
1400         }
1401 
1402         CGAffineTransform xform = MatrixToCGAffineTransform(m, scaleX, scaleY);
1403         // need to release font when we're done
1404         font = CTFontCreateCopyWithAttributes(fCTFont, 1, &xform, NULL);
1405     }
1406 
1407     CGGlyph   cgGlyph = (CGGlyph)glyph.getGlyphID(fBaseGlyphCount);
1408     CGPathRef cgPath  = CTFontCreatePathForGlyph(font, cgGlyph, NULL);
1409 
1410     path->reset();
1411     if (cgPath != NULL) {
1412         CGPathApply(cgPath, path, SkScalerContext_Mac::CTPathElement);
1413         CFRelease(cgPath);
1414     }
1415 
1416     if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
1417         SkMatrix m;
1418         m.setScale(SkFloatToScalar(1 / scaleX), SkFloatToScalar(1 / scaleY));
1419         path->transform(m);
1420         // balance the call to CTFontCreateCopyWithAttributes
1421         CFRelease(font);
1422     }
1423     if (fRec.fFlags & SkScalerContext::kVertical_Flag) {
1424         SkIPoint offset;
1425         getVerticalOffset(cgGlyph, &offset);
1426         path->offset(SkIntToScalar(offset.fX), SkIntToScalar(offset.fY));
1427     }
1428 }
1429 
generateFontMetrics(SkPaint::FontMetrics * mx,SkPaint::FontMetrics * my)1430 void SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* mx,
1431                                               SkPaint::FontMetrics* my) {
1432     CGRect theBounds = CTFontGetBoundingBox(fCTFont);
1433 
1434     SkPaint::FontMetrics theMetrics;
1435     theMetrics.fTop          = CGToScalar(-CGRectGetMaxY_inline(theBounds));
1436     theMetrics.fAscent       = CGToScalar(-CTFontGetAscent(fCTFont));
1437     theMetrics.fDescent      = CGToScalar( CTFontGetDescent(fCTFont));
1438     theMetrics.fBottom       = CGToScalar(-CGRectGetMinY_inline(theBounds));
1439     theMetrics.fLeading      = CGToScalar( CTFontGetLeading(fCTFont));
1440     theMetrics.fAvgCharWidth = CGToScalar( CGRectGetWidth_inline(theBounds));
1441     theMetrics.fXMin         = CGToScalar( CGRectGetMinX_inline(theBounds));
1442     theMetrics.fXMax         = CGToScalar( CGRectGetMaxX_inline(theBounds));
1443     theMetrics.fXHeight      = CGToScalar( CTFontGetXHeight(fCTFont));
1444 
1445     if (mx != NULL) {
1446         *mx = theMetrics;
1447     }
1448     if (my != NULL) {
1449         *my = theMetrics;
1450     }
1451 }
1452 
CTPathElement(void * info,const CGPathElement * element)1453 void SkScalerContext_Mac::CTPathElement(void *info, const CGPathElement *element)
1454 {   SkPath      *skPath = (SkPath *) info;
1455 
1456 
1457     // Process the path element
1458     switch (element->type) {
1459         case kCGPathElementMoveToPoint:
1460             skPath->moveTo( element->points[0].x, -element->points[0].y);
1461             break;
1462 
1463         case kCGPathElementAddLineToPoint:
1464             skPath->lineTo( element->points[0].x, -element->points[0].y);
1465             break;
1466 
1467         case kCGPathElementAddQuadCurveToPoint:
1468             skPath->quadTo( element->points[0].x, -element->points[0].y,
1469                             element->points[1].x, -element->points[1].y);
1470             break;
1471 
1472         case kCGPathElementAddCurveToPoint:
1473             skPath->cubicTo(element->points[0].x, -element->points[0].y,
1474                             element->points[1].x, -element->points[1].y,
1475                             element->points[2].x, -element->points[2].y);
1476             break;
1477 
1478         case kCGPathElementCloseSubpath:
1479             skPath->close();
1480             break;
1481 
1482         default:
1483             SkDEBUGFAIL("Unknown path element!");
1484             break;
1485         }
1486 }
1487 
1488 
1489 ///////////////////////////////////////////////////////////////////////////////
1490 
1491 // Returns NULL on failure
1492 // Call must still manage its ownership of provider
create_from_dataProvider(CGDataProviderRef provider)1493 static SkTypeface* create_from_dataProvider(CGDataProviderRef provider) {
1494     CGFontRef cg = CGFontCreateWithDataProvider(provider);
1495     if (NULL == cg) {
1496         return NULL;
1497     }
1498     CTFontRef ct = CTFontCreateWithGraphicsFont(cg, 0, NULL, NULL);
1499     CGFontRelease(cg);
1500     return cg ? SkCreateTypefaceFromCTFont(ct) : NULL;
1501 }
1502 
1503 class AutoCGDataProviderRelease : SkNoncopyable {
1504 public:
AutoCGDataProviderRelease(CGDataProviderRef provider)1505     AutoCGDataProviderRelease(CGDataProviderRef provider) : fProvider(provider) {}
~AutoCGDataProviderRelease()1506     ~AutoCGDataProviderRelease() { CGDataProviderRelease(fProvider); }
1507 
1508 private:
1509     CGDataProviderRef fProvider;
1510 };
1511 
CreateTypefaceFromStream(SkStream * stream)1512 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
1513     CGDataProviderRef provider = SkCreateDataProviderFromStream(stream);
1514     if (NULL == provider) {
1515         return NULL;
1516     }
1517     AutoCGDataProviderRelease ar(provider);
1518     return create_from_dataProvider(provider);
1519 }
1520 
CreateTypefaceFromFile(const char path[])1521 SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
1522     CGDataProviderRef provider = CGDataProviderCreateWithFilename(path);
1523     if (NULL == provider) {
1524         return NULL;
1525     }
1526     AutoCGDataProviderRelease ar(provider);
1527     return create_from_dataProvider(provider);
1528 }
1529 
1530 // Web fonts added to the the CTFont registry do not return their character set.
1531 // Iterate through the font in this case. The existing caller caches the result,
1532 // so the performance impact isn't too bad.
populate_glyph_to_unicode_slow(CTFontRef ctFont,unsigned glyphCount,SkTDArray<SkUnichar> * glyphToUnicode)1533 static void populate_glyph_to_unicode_slow(CTFontRef ctFont,
1534         unsigned glyphCount, SkTDArray<SkUnichar>* glyphToUnicode) {
1535     glyphToUnicode->setCount(glyphCount);
1536     SkUnichar* out = glyphToUnicode->begin();
1537     sk_bzero(out, glyphCount * sizeof(SkUnichar));
1538     UniChar unichar = 0;
1539     while (glyphCount > 0) {
1540         CGGlyph glyph;
1541         if (CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) {
1542             out[glyph] = unichar;
1543             --glyphCount;
1544         }
1545         if (++unichar == 0) {
1546             break;
1547         }
1548     }
1549 }
1550 
1551 // Construct Glyph to Unicode table.
1552 // Unicode code points that require conjugate pairs in utf16 are not
1553 // supported.
populate_glyph_to_unicode(CTFontRef ctFont,const unsigned glyphCount,SkTDArray<SkUnichar> * glyphToUnicode)1554 static void populate_glyph_to_unicode(CTFontRef ctFont,
1555         const unsigned glyphCount, SkTDArray<SkUnichar>* glyphToUnicode) {
1556     CFCharacterSetRef charSet = CTFontCopyCharacterSet(ctFont);
1557     if (!charSet) {
1558         populate_glyph_to_unicode_slow(ctFont, glyphCount, glyphToUnicode);
1559         return;
1560     }
1561     CFDataRef bitmap = CFCharacterSetCreateBitmapRepresentation(
1562         kCFAllocatorDefault, charSet);
1563     if (!bitmap) {
1564         return;
1565     }
1566     CFIndex length = CFDataGetLength(bitmap);
1567     if (!length) {
1568         CFSafeRelease(bitmap);
1569         return;
1570     }
1571     if (length > 8192) {
1572         // TODO: Add support for Unicode above 0xFFFF
1573         // Consider only the BMP portion of the Unicode character points.
1574         // The bitmap may contain other planes, up to plane 16.
1575         // See http://developer.apple.com/library/ios/#documentation/CoreFoundation/Reference/CFCharacterSetRef/Reference/reference.html
1576         length = 8192;
1577     }
1578     const UInt8* bits = CFDataGetBytePtr(bitmap);
1579     glyphToUnicode->setCount(glyphCount);
1580     SkUnichar* out = glyphToUnicode->begin();
1581     sk_bzero(out, glyphCount * sizeof(SkUnichar));
1582     for (int i = 0; i < length; i++) {
1583         int mask = bits[i];
1584         if (!mask) {
1585             continue;
1586         }
1587         for (int j = 0; j < 8; j++) {
1588             CGGlyph glyph;
1589             UniChar unichar = static_cast<UniChar>((i << 3) + j);
1590             if (mask & (1 << j) && CTFontGetGlyphsForCharacters(ctFont,
1591                     &unichar, &glyph, 1)) {
1592                 out[glyph] = unichar;
1593             }
1594         }
1595     }
1596     CFSafeRelease(bitmap);
1597 }
1598 
getWidthAdvance(CTFontRef ctFont,int gId,int16_t * data)1599 static bool getWidthAdvance(CTFontRef ctFont, int gId, int16_t* data) {
1600     CGSize advance;
1601     advance.width = 0;
1602     CGGlyph glyph = gId;
1603     CTFontGetAdvancesForGlyphs(ctFont, kCTFontHorizontalOrientation, &glyph,
1604         &advance, 1);
1605     *data = sk_float_round2int(advance.width);
1606     return true;
1607 }
1608 
1609 // static
GetAdvancedTypefaceMetrics(uint32_t fontID,SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,const uint32_t * glyphIDs,uint32_t glyphIDsCount)1610 SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
1611         uint32_t fontID,
1612         SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
1613         const uint32_t* glyphIDs,
1614         uint32_t glyphIDsCount) {
1615     CTFontRef ctFont = GetFontRefFromFontID(fontID);
1616     ctFont = CTFontCreateCopyWithAttributes(ctFont, CTFontGetUnitsPerEm(ctFont),
1617                                             NULL, NULL);
1618     SkAdvancedTypefaceMetrics* info = new SkAdvancedTypefaceMetrics;
1619     CFStringRef fontName = CTFontCopyPostScriptName(ctFont);
1620     // Reserve enough room for the worst-case string,
1621     // plus 1 byte for the trailing null.
1622     int length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(
1623         fontName), kCFStringEncodingUTF8) + 1;
1624     info->fFontName.resize(length);
1625     CFStringGetCString(fontName, info->fFontName.writable_str(), length,
1626         kCFStringEncodingUTF8);
1627     // Resize to the actual UTF-8 length used, stripping the null character.
1628     info->fFontName.resize(strlen(info->fFontName.c_str()));
1629     info->fMultiMaster = false;
1630     CFIndex glyphCount = CTFontGetGlyphCount(ctFont);
1631     info->fLastGlyphID = SkToU16(glyphCount - 1);
1632     info->fEmSize = CTFontGetUnitsPerEm(ctFont);
1633 
1634     if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) {
1635         populate_glyph_to_unicode(ctFont, glyphCount, &info->fGlyphToUnicode);
1636     }
1637 
1638     info->fStyle = 0;
1639 
1640     // If it's not a truetype font, mark it as 'other'. Assume that TrueType
1641     // fonts always have both glyf and loca tables. At the least, this is what
1642     // sfntly needs to subset the font. CTFontCopyAttribute() does not always
1643     // succeed in determining this directly.
1644     if (!GetTableSize(fontID, 'glyf') || !GetTableSize(fontID, 'loca')) {
1645         info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
1646         info->fItalicAngle = 0;
1647         info->fAscent = 0;
1648         info->fDescent = 0;
1649         info->fStemV = 0;
1650         info->fCapHeight = 0;
1651         info->fBBox = SkIRect::MakeEmpty();
1652         CFSafeRelease(ctFont);
1653         return info;
1654     }
1655 
1656     info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
1657     CTFontSymbolicTraits symbolicTraits = CTFontGetSymbolicTraits(ctFont);
1658     if (symbolicTraits & kCTFontMonoSpaceTrait) {
1659         info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
1660     }
1661     if (symbolicTraits & kCTFontItalicTrait) {
1662         info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
1663     }
1664     CTFontStylisticClass stylisticClass = symbolicTraits &
1665             kCTFontClassMaskTrait;
1666     if (stylisticClass & kCTFontSymbolicClass) {
1667         info->fStyle |= SkAdvancedTypefaceMetrics::kSymbolic_Style;
1668     }
1669     if (stylisticClass >= kCTFontOldStyleSerifsClass
1670             && stylisticClass <= kCTFontSlabSerifsClass) {
1671         info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
1672     } else if (stylisticClass & kCTFontScriptsClass) {
1673         info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
1674     }
1675     info->fItalicAngle = CTFontGetSlantAngle(ctFont);
1676     info->fAscent = CTFontGetAscent(ctFont);
1677     info->fDescent = CTFontGetDescent(ctFont);
1678     info->fCapHeight = CTFontGetCapHeight(ctFont);
1679     CGRect bbox = CTFontGetBoundingBox(ctFont);
1680     info->fBBox = SkIRect::MakeXYWH(bbox.origin.x, bbox.origin.y,
1681         bbox.size.width, bbox.size.height);
1682 
1683     // Figure out a good guess for StemV - Min width of i, I, !, 1.
1684     // This probably isn't very good with an italic font.
1685     int16_t min_width = SHRT_MAX;
1686     info->fStemV = 0;
1687     static const UniChar stem_chars[] = {'i', 'I', '!', '1'};
1688     const size_t count = sizeof(stem_chars) / sizeof(stem_chars[0]);
1689     CGGlyph glyphs[count];
1690     CGRect boundingRects[count];
1691     if (CTFontGetGlyphsForCharacters(ctFont, stem_chars, glyphs, count)) {
1692         CTFontGetBoundingRectsForGlyphs(ctFont, kCTFontHorizontalOrientation,
1693             glyphs, boundingRects, count);
1694         for (size_t i = 0; i < count; i++) {
1695             int16_t width = boundingRects[i].size.width;
1696             if (width > 0 && width < min_width) {
1697                 min_width = width;
1698                 info->fStemV = min_width;
1699             }
1700         }
1701     }
1702 
1703     if (false) { // TODO: haven't figured out how to know if font is embeddable
1704         // (information is in the OS/2 table)
1705         info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
1706     } else if (perGlyphInfo &
1707                SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
1708         if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) {
1709             skia_advanced_typeface_metrics_utils::appendRange(&info->fGlyphWidths, 0);
1710             info->fGlyphWidths->fAdvance.append(1, &min_width);
1711             skia_advanced_typeface_metrics_utils::finishRange(info->fGlyphWidths.get(), 0,
1712                         SkAdvancedTypefaceMetrics::WidthRange::kDefault);
1713         } else {
1714             info->fGlyphWidths.reset(
1715                 skia_advanced_typeface_metrics_utils::getAdvanceData(ctFont,
1716                                glyphCount,
1717                                glyphIDs,
1718                                glyphIDsCount,
1719                                &getWidthAdvance));
1720         }
1721     }
1722 
1723     CFSafeRelease(ctFont);
1724     return info;
1725 }
1726 
1727 ///////////////////////////////////////////////////////////////////////////////
1728 
1729 struct FontHeader {
1730     SkFixed fVersion;
1731     uint16_t fNumTables;
1732     uint16_t fSearchRange;
1733     uint16_t fEntrySelector;
1734     uint16_t fRangeShift;
1735 };
1736 
1737 struct TableEntry {
1738     uint32_t fTag;
1739     uint32_t fCheckSum;
1740     uint32_t fOffset;
1741     uint32_t fLength;
1742 };
1743 
CalcTableCheckSum(uint32_t * table,uint32_t numberOfBytesInTable)1744 static uint32_t CalcTableCheckSum(uint32_t *table, uint32_t numberOfBytesInTable) {
1745     uint32_t sum = 0;
1746     uint32_t nLongs = (numberOfBytesInTable + 3) / 4;
1747 
1748     while (nLongs-- > 0) {
1749         sum += SkEndian_SwapBE32(*table++);
1750     }
1751     return sum;
1752 }
1753 
OpenStream(SkFontID uniqueID)1754 SkStream* SkFontHost::OpenStream(SkFontID uniqueID) {
1755     // get table tags
1756     int tableCount = CountTables(uniqueID);
1757     SkTDArray<SkFontTableTag> tableTags;
1758     tableTags.setCount(tableCount);
1759     GetTableTags(uniqueID, tableTags.begin());
1760 
1761     // calc total size for font, save sizes
1762     SkTDArray<size_t> tableSizes;
1763     size_t totalSize = sizeof(FontHeader) + sizeof(TableEntry) * tableCount;
1764     for (int index = 0; index < tableCount; ++index) {
1765         size_t tableSize = GetTableSize(uniqueID, tableTags[index]);
1766         totalSize += (tableSize + 3) & ~3;
1767         *tableSizes.append() = tableSize;
1768     }
1769 
1770     // reserve memory for stream, and zero it (tables must be zero padded)
1771     SkMemoryStream* stream = new SkMemoryStream(totalSize);
1772     char* dataStart = (char*)stream->getMemoryBase();
1773     sk_bzero(dataStart, totalSize);
1774     char* dataPtr = dataStart;
1775 
1776     // compute font header entries
1777     uint16_t entrySelector = 0;
1778     uint16_t searchRange = 1;
1779     while (searchRange < tableCount >> 1) {
1780         entrySelector++;
1781         searchRange <<= 1;
1782     }
1783     searchRange <<= 4;
1784     uint16_t rangeShift = (tableCount << 4) - searchRange;
1785 
1786     // write font header (also called sfnt header, offset subtable)
1787     FontHeader* offsetTable = (FontHeader*)dataPtr;
1788     offsetTable->fVersion = SkEndian_SwapBE32(SK_Fixed1);
1789     offsetTable->fNumTables = SkEndian_SwapBE16(tableCount);
1790     offsetTable->fSearchRange = SkEndian_SwapBE16(searchRange);
1791     offsetTable->fEntrySelector = SkEndian_SwapBE16(entrySelector);
1792     offsetTable->fRangeShift = SkEndian_SwapBE16(rangeShift);
1793     dataPtr += sizeof(FontHeader);
1794 
1795     // write tables
1796     TableEntry* entry = (TableEntry*)dataPtr;
1797     dataPtr += sizeof(TableEntry) * tableCount;
1798     for (int index = 0; index < tableCount; ++index) {
1799         size_t tableSize = tableSizes[index];
1800         GetTableData(uniqueID, tableTags[index], 0, tableSize, dataPtr);
1801         entry->fTag = SkEndian_SwapBE32(tableTags[index]);
1802         entry->fCheckSum = SkEndian_SwapBE32(CalcTableCheckSum(
1803             (uint32_t*)dataPtr, tableSize));
1804         entry->fOffset = SkEndian_SwapBE32(dataPtr - dataStart);
1805         entry->fLength = SkEndian_SwapBE32(tableSize);
1806         dataPtr += (tableSize + 3) & ~3;
1807         ++entry;
1808     }
1809 
1810     return stream;
1811 }
1812 
GetFileName(SkFontID fontID,char path[],size_t length,int32_t * index)1813 size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
1814                                int32_t* index) {
1815     SkDEBUGFAIL("SkFontHost::GetFileName unimplemented");
1816     return(0);
1817 }
1818 
1819 ///////////////////////////////////////////////////////////////////////////////
1820 
1821 #include "SkStream.h"
1822 
Serialize(const SkTypeface * face,SkWStream * stream)1823 void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
1824     // hack: need a real name or something from CG
1825     uint32_t fontID = face->uniqueID();
1826     stream->write(&fontID, 4);
1827 }
1828 
Deserialize(SkStream * stream)1829 SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
1830     // hack: need a real name or something from CG
1831     SkFontID fontID = stream->readU32();
1832     SkTypeface* face = SkTypefaceCache::FindByID(fontID);
1833     SkSafeRef(face);
1834     return face;
1835 }
1836 
1837 ///////////////////////////////////////////////////////////////////////////////
1838 
CreateScalerContext(const SkDescriptor * desc)1839 SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) {
1840     return new SkScalerContext_Mac(desc);
1841 }
1842 
NextLogicalFont(SkFontID currFontID,SkFontID origFontID)1843 SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
1844     SkFontID nextFontID = 0;
1845     SkTypeface* face = GetDefaultFace();
1846     if (face->uniqueID() != currFontID) {
1847         nextFontID = face->uniqueID();
1848     }
1849     return nextFontID;
1850 }
1851 
supports_LCD()1852 static bool supports_LCD() {
1853     static int gSupportsLCD = -1;
1854     if (gSupportsLCD >= 0) {
1855         return (bool) gSupportsLCD;
1856     }
1857     int rgb = 0;
1858     CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
1859     CGContextRef cgContext = CGBitmapContextCreate(&rgb, 1, 1, 8, 4, colorspace,
1860                                                    BITMAP_INFO_RGB);
1861     CGContextSelectFont(cgContext, "Helvetica", 16, kCGEncodingMacRoman);
1862     CGContextSetShouldSmoothFonts(cgContext, true);
1863     CGContextSetShouldAntialias(cgContext, true);
1864     CGContextSetTextDrawingMode(cgContext, kCGTextFill);
1865     CGContextSetGrayFillColor(  cgContext, 1, 1.0);
1866     CGContextShowTextAtPoint(cgContext, -1, 0, "|", 1);
1867     CFSafeRelease(colorspace);
1868     CFSafeRelease(cgContext);
1869     int r = (rgb >> 16) & 0xFF;
1870     int g = (rgb >>  8) & 0xFF;
1871     int b = (rgb >>  0) & 0xFF;
1872     gSupportsLCD = r != g || r != b;
1873     return (bool) gSupportsLCD;
1874 }
1875 
FilterRec(SkScalerContext::Rec * rec)1876 void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
1877     unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag |
1878                                   SkScalerContext::kAutohinting_Flag;
1879 
1880     rec->fFlags &= ~flagsWeDontSupport;
1881 
1882     // we only support 2 levels of hinting
1883     SkPaint::Hinting h = rec->getHinting();
1884     if (SkPaint::kSlight_Hinting == h) {
1885         h = SkPaint::kNo_Hinting;
1886     } else if (SkPaint::kFull_Hinting == h) {
1887         h = SkPaint::kNormal_Hinting;
1888     }
1889     rec->setHinting(h);
1890 
1891 #ifdef SK_USE_COLOR_LUMINANCE
1892     if (isLCDFormat(rec->fMaskFormat)) {
1893         SkColor c = rec->getLuminanceColor();
1894         // apply our chosen scaling between Black and White cg output
1895         int r = SkColorGetR(c)*2/3;
1896         int g = SkColorGetG(c)*2/3;
1897         int b = SkColorGetB(c)*2/3;
1898         rec->setLuminanceColor(SkColorSetRGB(r, g, b));
1899     }
1900 #else
1901     {
1902         unsigned lum = rec->getLuminanceByte();
1903         if (lum <= BLACK_LUMINANCE_LIMIT) {
1904             lum = 0;
1905         } else if (lum >= WHITE_LUMINANCE_LIMIT) {
1906             lum = SkScalerContext::kLuminance_Max;
1907         } else {
1908             lum = SkScalerContext::kLuminance_Max >> 1;
1909         }
1910         rec->setLuminanceBits(lum);
1911     }
1912 #endif
1913 
1914     if (SkMask::kLCD16_Format == rec->fMaskFormat
1915             || SkMask::kLCD32_Format == rec->fMaskFormat) {
1916         if (supports_LCD()) {
1917             rec->fMaskFormat = SkMask::kLCD32_Format;
1918         } else {
1919             rec->fMaskFormat = SkMask::kA8_Format;
1920         }
1921     }
1922 }
1923 
1924 ///////////////////////////////////////////////////////////////////////////
1925 
CountTables(SkFontID fontID)1926 int SkFontHost::CountTables(SkFontID fontID) {
1927     CTFontRef ctFont = GetFontRefFromFontID(fontID);
1928     CFArrayRef cfArray = CTFontCopyAvailableTables(ctFont,
1929                                                    kCTFontTableOptionNoOptions);
1930     if (NULL == cfArray) {
1931         return 0;
1932     }
1933 
1934     AutoCFRelease ar(cfArray);
1935     return CFArrayGetCount(cfArray);
1936 }
1937 
GetTableTags(SkFontID fontID,SkFontTableTag tags[])1938 int SkFontHost::GetTableTags(SkFontID fontID, SkFontTableTag tags[]) {
1939     CTFontRef ctFont = GetFontRefFromFontID(fontID);
1940     CFArrayRef cfArray = CTFontCopyAvailableTables(ctFont,
1941                                                    kCTFontTableOptionNoOptions);
1942     if (NULL == cfArray) {
1943         return 0;
1944     }
1945 
1946     AutoCFRelease ar(cfArray);
1947 
1948     int count = CFArrayGetCount(cfArray);
1949     if (tags) {
1950         for (int i = 0; i < count; ++i) {
1951             tags[i] = (SkFontTableTag)CFArrayGetValueAtIndex(cfArray, i);
1952         }
1953     }
1954     return count;
1955 }
1956 
1957 // If, as is the case with web fonts, the CTFont data isn't available,
1958 // the CGFont data may work. While the CGFont may always provide the
1959 // right result, leave the CTFont code path to minimize disruption.
copyTableFromFont(CTFontRef ctFont,SkFontTableTag tag)1960 static CFDataRef copyTableFromFont(CTFontRef ctFont, SkFontTableTag tag) {
1961     CFDataRef data = CTFontCopyTable(ctFont, (CTFontTableTag) tag,
1962                                      kCTFontTableOptionNoOptions);
1963     if (NULL == data) {
1964         CGFontRef cgFont = CTFontCopyGraphicsFont(ctFont, NULL);
1965         data = CGFontCopyTableForTag(cgFont, tag);
1966         CGFontRelease(cgFont);
1967     }
1968     return data;
1969 }
1970 
GetTableSize(SkFontID fontID,SkFontTableTag tag)1971 size_t SkFontHost::GetTableSize(SkFontID fontID, SkFontTableTag tag) {
1972     CTFontRef ctFont = GetFontRefFromFontID(fontID);
1973     CFDataRef srcData = copyTableFromFont(ctFont, tag);
1974     if (NULL == srcData) {
1975         return 0;
1976     }
1977 
1978     AutoCFRelease ar(srcData);
1979     return CFDataGetLength(srcData);
1980 }
1981 
GetTableData(SkFontID fontID,SkFontTableTag tag,size_t offset,size_t length,void * dst)1982 size_t SkFontHost::GetTableData(SkFontID fontID, SkFontTableTag tag,
1983                                 size_t offset, size_t length, void* dst) {
1984     CTFontRef ctFont = GetFontRefFromFontID(fontID);
1985     CFDataRef srcData = copyTableFromFont(ctFont, tag);
1986     if (NULL == srcData) {
1987         return 0;
1988     }
1989 
1990     AutoCFRelease ar(srcData);
1991 
1992     size_t srcSize = CFDataGetLength(srcData);
1993     if (offset >= srcSize) {
1994         return 0;
1995     }
1996 
1997     if ((offset + length) > srcSize) {
1998         length = srcSize - offset;
1999     }
2000 
2001     if (dst) {
2002         memcpy(dst, CFDataGetBytePtr(srcData) + offset, length);
2003     }
2004     return length;
2005 }
2006