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