• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  ** Copyright 2006, The Android Open Source Project
3  **
4  ** Licensed under the Apache License, Version 2.0 (the "License");
5  ** you may not use this file except in compliance with the License.
6  ** You may obtain a copy of the License at
7  **
8  **     http://www.apache.org/licenses/LICENSE-2.0
9  **
10  ** Unless required by applicable law or agreed to in writing, software
11  ** distributed under the License is distributed on an "AS IS" BASIS,
12  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  ** See the License for the specific language governing permissions and
14  ** limitations under the License.
15 */
16 #include <vector>
17 #include <Carbon/Carbon.h>
18 
19 #include "SkFontHost.h"
20 #include "SkDescriptor.h"
21 #include "SkEndian.h"
22 #include "SkFloatingPoint.h"
23 #include "SkPaint.h"
24 #include "SkString.h"
25 #include "SkStream.h"
26 #include "SkTypeface_mac.h"
27 #include "SkUtils.h"
28 #include "SkTypefaceCache.h"
29 
30 using namespace skia_advanced_typeface_metrics_utils;
31 
32 static const size_t FONT_CACHE_MEMORY_BUDGET    = 1024 * 1024;
33 static const char FONT_DEFAULT_NAME[]           = "Lucida Sans";
34 
35 //============================================================================
36 //      Macros
37 //----------------------------------------------------------------------------
38 // Release a CFTypeRef
39 #ifndef CFSafeRelease
40 #define CFSafeRelease(_object)                                      \
41     do                                                              \
42         {                                                           \
43         if ((_object) != NULL)                                      \
44             {                                                       \
45             CFRelease((CFTypeRef) (_object));                       \
46             (_object) = NULL;                                       \
47             }                                                       \
48         }                                                           \
49     while (false)
50 #endif
51 
52 
computeStyleBits(CTFontRef font,bool * isMonospace)53 static SkTypeface::Style computeStyleBits(CTFontRef font, bool* isMonospace) {
54     unsigned style = SkTypeface::kNormal;
55     CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(font);
56 
57     if (traits & kCTFontBoldTrait) {
58         style |= SkTypeface::kBold;
59     }
60     if (traits & kCTFontItalicTrait) {
61         style |= SkTypeface::kItalic;
62     }
63     if (isMonospace) {
64         *isMonospace = (traits & kCTFontMonoSpaceTrait) != 0;
65     }
66     return (SkTypeface::Style)style;
67 }
68 
69 class SkTypeface_Mac : public SkTypeface {
70 public:
SkTypeface_Mac(SkTypeface::Style style,SkFontID fontID,bool isMonospace)71     SkTypeface_Mac(SkTypeface::Style style, SkFontID fontID, bool isMonospace)
72         : SkTypeface(style, fontID, isMonospace), fFontRef(0) {}
73 
~SkTypeface_Mac()74     virtual ~SkTypeface_Mac() { CFRelease(fFontRef); }
75 
76     SkString    fName;
77     CTFontRef   fFontRef;
78 };
79 
NewFromFontRef(CTFontRef fontRef,const char name[])80 static SkTypeface* NewFromFontRef(CTFontRef fontRef, const char name[]) {
81     bool isMonospace;
82     SkTypeface::Style style = computeStyleBits(fontRef, &isMonospace);
83     SkTypeface_Mac* face = new SkTypeface_Mac(style,
84                                               SkTypefaceCache::NewFontID(),
85                                               isMonospace);
86     face->fFontRef = fontRef;   // we take over ownership of fontRef
87     face->fName.set(name);
88     return face;
89 }
90 
NewFromName(const char familyName[],SkTypeface::Style theStyle)91 static SkTypeface* NewFromName(const char familyName[],
92                                SkTypeface::Style theStyle) {
93     CFMutableDictionaryRef      cfAttributes, cfTraits;
94     CFNumberRef                 cfFontTraits;
95     CTFontSymbolicTraits        ctFontTraits;
96     CTFontDescriptorRef         ctFontDesc;
97     CFStringRef                 cfFontName;
98     CTFontRef                   ctFont;
99 
100 
101     // Get the state we need
102     ctFontDesc   = NULL;
103     ctFont       = NULL;
104     ctFontTraits = 0;
105 
106     if (theStyle & SkTypeface::kBold) {
107         ctFontTraits |= kCTFontBoldTrait;
108     }
109 
110     if (theStyle & SkTypeface::kItalic) {
111         ctFontTraits |= kCTFontItalicTrait;
112     }
113 
114     // Create the font info
115     cfFontName   = CFStringCreateWithCString(NULL, familyName, kCFStringEncodingUTF8);
116     cfFontTraits = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &ctFontTraits);
117     cfAttributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
118     cfTraits     = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
119 
120 
121     // Create the font
122     if (cfFontName != NULL && cfFontTraits != NULL && cfAttributes != NULL && cfTraits != NULL) {
123         CFDictionaryAddValue(cfTraits, kCTFontSymbolicTrait, cfFontTraits);
124 
125         CFDictionaryAddValue(cfAttributes, kCTFontFamilyNameAttribute, cfFontName);
126         CFDictionaryAddValue(cfAttributes, kCTFontTraitsAttribute,     cfTraits);
127 
128         ctFontDesc = CTFontDescriptorCreateWithAttributes(cfAttributes);
129         if (ctFontDesc != NULL) {
130             ctFont = CTFontCreateWithFontDescriptor(ctFontDesc, 0, NULL);
131         }
132     }
133 
134     CFSafeRelease(cfFontName);
135     CFSafeRelease(cfFontTraits);
136     CFSafeRelease(cfAttributes);
137     CFSafeRelease(cfTraits);
138     CFSafeRelease(ctFontDesc);
139 
140     return ctFont ? NewFromFontRef(ctFont, familyName) : NULL;
141 }
142 
GetFontRefFromFontID(SkFontID fontID)143 static CTFontRef GetFontRefFromFontID(SkFontID fontID) {
144     SkTypeface_Mac* face = reinterpret_cast<SkTypeface_Mac*>(SkTypefaceCache::FindByID(fontID));
145     return face ? face->fFontRef : 0;
146 }
147 
GetDefaultFace()148 static SkTypeface* GetDefaultFace() {
149     static SkTypeface* gDefaultFace;
150 
151     if (NULL == gDefaultFace) {
152         gDefaultFace = new SkTypeface_Mac(SkTypeface::kNormal,
153                                           SkTypefaceCache::NewFontID(), false);
154     }
155     return gDefaultFace;
156 }
157 
158 ///////////////////////////////////////////////////////////////////////////////
159 
160 struct FontRefRec {
161     CTFontRef   fFontRef;
162 };
163 
FindByFontRef(SkTypeface * face,SkTypeface::Style,void * ctx)164 static bool FindByFontRef(SkTypeface* face, SkTypeface::Style, void* ctx) {
165     const SkTypeface_Mac* mface = reinterpret_cast<SkTypeface_Mac*>(face);
166     const FontRefRec* rec = reinterpret_cast<const FontRefRec*>(ctx);
167 
168     return rec->fFontRef == mface->fFontRef;
169 }
170 
171 /*  This function is visible on the outside. It first searches the cache, and if
172  *  not found, returns a new entry (after adding it to the cache).
173  */
SkCreateTypefaceFromCTFont(CTFontRef fontRef)174 SkTypeface* SkCreateTypefaceFromCTFont(CTFontRef fontRef) {
175     FontRefRec rec = { fontRef };
176     SkTypeface* face = SkTypefaceCache::FindByProc(FindByFontRef, &rec);
177     if (face) {
178         face->ref();
179     } else {
180         face = NewFromFontRef(fontRef, NULL);
181         SkTypefaceCache::Add(face, face->style());
182     }
183     SkASSERT(face->getRefCnt() > 1);
184     return face;
185 }
186 
187 struct NameStyleRec {
188     const char*         fName;
189     SkTypeface::Style   fStyle;
190 };
191 
FindByNameStyle(SkTypeface * face,SkTypeface::Style style,void * ctx)192 static bool FindByNameStyle(SkTypeface* face, SkTypeface::Style style,
193                             void* ctx) {
194     const SkTypeface_Mac* mface = reinterpret_cast<SkTypeface_Mac*>(face);
195     const NameStyleRec* rec = reinterpret_cast<const NameStyleRec*>(ctx);
196 
197     return rec->fStyle == style && mface->fName.equals(rec->fName);
198 }
199 
map_css_names(const char * name)200 static const char* map_css_names(const char* name) {
201     static const struct {
202         const char* fFrom;  // name the caller specified
203         const char* fTo;    // "canonical" name we map to
204     } gPairs[] = {
205         { "sans-serif", "Helvetica" },
206         { "serif",      "Times"     },
207         { "monospace",  "Courier"   }
208     };
209 
210     for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
211         if (strcmp(name, gPairs[i].fFrom) == 0) {
212             return gPairs[i].fTo;
213         }
214     }
215     return name;    // no change
216 }
217 
CreateTypeface(const SkTypeface * familyFace,const char familyName[],const void * data,size_t bytelength,SkTypeface::Style style)218 SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
219                                        const char familyName[],
220                                        const void* data, size_t bytelength,
221                                        SkTypeface::Style style) {
222     if (familyName) {
223         familyName = map_css_names(familyName);
224     }
225 
226     // Clone an existing typeface
227     // TODO: only clone if style matches the familyFace's style...
228     if (familyName == NULL && familyFace != NULL) {
229         familyFace->ref();
230         return const_cast<SkTypeface*>(familyFace);
231     }
232 
233     if (!familyName || !*familyName) {
234         familyName = FONT_DEFAULT_NAME;
235     }
236 
237     NameStyleRec rec = { familyName, style };
238     SkTypeface* face = SkTypefaceCache::FindByProc(FindByNameStyle, &rec);
239 
240     if (face) {
241         face->ref();
242     } else {
243         face = NewFromName(familyName, style);
244         if (face) {
245             SkTypefaceCache::Add(face, style);
246         } else {
247             face = GetDefaultFace();
248             face->ref();
249         }
250     }
251     return face;
252 }
253 
254 ///////////////////////////////////////////////////////////////////////////////
255 
256 class SkScalerContext_Mac : public SkScalerContext {
257 public:
258                                         SkScalerContext_Mac(const SkDescriptor* desc);
259     virtual                            ~SkScalerContext_Mac(void);
260 
261 
262 protected:
263     unsigned                            generateGlyphCount(void);
264     uint16_t                            generateCharToGlyph(SkUnichar uni);
265     void                                generateAdvance(SkGlyph* glyph);
266     void                                generateMetrics(SkGlyph* glyph);
267     void                                generateImage(const SkGlyph& glyph);
268     void                                generatePath( const SkGlyph& glyph, SkPath* path);
269     void                                generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY);
270 
271 
272 private:
273     static void                         CTPathElement(void *info, const CGPathElement *element);
274 
275 
276 private:
277     CGColorSpaceRef                     mColorSpaceGray;
278     CGColorSpaceRef                     mColorSpaceRGB;
279     CGAffineTransform                   mTransform;
280 
281     CTFontRef                           mFont;
282     uint16_t                            mGlyphCount;
283 };
284 
SkScalerContext_Mac(const SkDescriptor * desc)285 SkScalerContext_Mac::SkScalerContext_Mac(const SkDescriptor* desc)
286         : SkScalerContext(desc)
287 {   CFIndex             numGlyphs;
288     CTFontRef           ctFont;
289     SkMatrix            skMatrix;
290 
291 
292 
293     // Get the state we need
294     fRec.getSingleMatrix(&skMatrix);
295 
296     ctFont    = GetFontRefFromFontID(fRec.fFontID);
297     numGlyphs = CTFontGetGlyphCount(ctFont);
298     SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF);
299 
300 
301     // Initialise ourselves
302     mColorSpaceRGB = CGColorSpaceCreateDeviceRGB();
303 //    mColorSpaceRGB = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
304 //    mColorSpaceRGB = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGBLinear);
305     mColorSpaceGray = CGColorSpaceCreateDeviceGray();
306 
307     mTransform  = CGAffineTransformMake(SkScalarToFloat(skMatrix[SkMatrix::kMScaleX]),
308                                         -SkScalarToFloat(skMatrix[SkMatrix::kMSkewY]),
309                                         -SkScalarToFloat(skMatrix[SkMatrix::kMSkewX]),
310                                         SkScalarToFloat(skMatrix[SkMatrix::kMScaleY]),
311                                         SkScalarToFloat(skMatrix[SkMatrix::kMTransX]),
312                                         SkScalarToFloat(skMatrix[SkMatrix::kMTransY]));
313 
314     // since our matrix includes everything, we pass 1 for pointSize
315     mFont       = CTFontCreateCopyWithAttributes(ctFont, 1, &mTransform, NULL);
316     mGlyphCount = (uint16_t) numGlyphs;
317 }
318 
~SkScalerContext_Mac(void)319 SkScalerContext_Mac::~SkScalerContext_Mac(void)
320 {
321 
322     // Clean up
323     CFSafeRelease(mColorSpaceGray);
324     CFSafeRelease(mColorSpaceRGB);
325     CFSafeRelease(mFont);
326 }
327 
generateGlyphCount(void)328 unsigned SkScalerContext_Mac::generateGlyphCount(void)
329 {
330     return(mGlyphCount);
331 }
332 
generateCharToGlyph(SkUnichar uni)333 uint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni)
334 {   CGGlyph     cgGlyph;
335     UniChar     theChar;
336 
337 
338     // Validate our parameters and state
339     SkASSERT(uni             <= 0x0000FFFF);
340     SkASSERT(sizeof(CGGlyph) <= sizeof(uint16_t));
341 
342 
343     // Get the glyph
344     theChar = (UniChar) uni;
345 
346     if (!CTFontGetGlyphsForCharacters(mFont, &theChar, &cgGlyph, 1))
347         cgGlyph = 0;
348 
349     return(cgGlyph);
350 }
351 
generateAdvance(SkGlyph * glyph)352 void SkScalerContext_Mac::generateAdvance(SkGlyph* glyph)
353 {
354     this->generateMetrics(glyph);
355 }
356 
generateMetrics(SkGlyph * glyph)357 void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph)
358 {   CGSize      theAdvance;
359     CGRect      theBounds;
360     CGGlyph     cgGlyph;
361 
362 
363 
364     // Get the state we need
365     cgGlyph = (CGGlyph) glyph->getGlyphID(fBaseGlyphCount);
366 
367     CTFontGetBoundingRectsForGlyphs(mFont, kCTFontDefaultOrientation, &cgGlyph, &theBounds,  1);
368     CTFontGetAdvancesForGlyphs(     mFont, kCTFontDefaultOrientation, &cgGlyph, &theAdvance, 1);
369 
370 
371 
372     // Adjust the bounds
373     //
374     // CTFontGetBoundingRectsForGlyphs ignores the font transform, so we need
375     // to transform the bounding box ourselves.
376     //
377     // The bounds are also expanded by 1 pixel, to give CG room for anti-aliasing.
378     theBounds = CGRectInset(theBounds, -1, -1);
379 
380 
381 
382     // Get the metrics
383     glyph->zeroMetrics();
384     glyph->fAdvanceX =  SkFloatToFixed(theAdvance.width);
385     glyph->fAdvanceY = -SkFloatToFixed(theAdvance.height);
386     glyph->fWidth    =  sk_float_round2int(theBounds.size.width);
387     glyph->fHeight   =  sk_float_round2int(theBounds.size.height);
388     glyph->fTop      = -sk_float_round2int(CGRectGetMaxY(theBounds));
389     glyph->fLeft     =  sk_float_round2int(CGRectGetMinX(theBounds));
390 }
391 
392 #include "SkColorPriv.h"
393 
bytes_to_bits(uint8_t dst[],const uint8_t src[],int count)394 static void bytes_to_bits(uint8_t dst[], const uint8_t src[], int count) {
395     while (count > 0) {
396         uint8_t mask = 0;
397         for (int i = 7; i >= 0; --i) {
398             mask |= (*src++ >> 7) << i;
399             if (0 == --count) {
400                 break;
401             }
402         }
403         *dst++ = mask;
404     }
405 }
406 
407 #if 1
r32_to_16(int x)408 static inline int r32_to_16(int x) { return SkR32ToR16(x); }
g32_to_16(int x)409 static inline int g32_to_16(int x) { return SkG32ToG16(x); }
b32_to_16(int x)410 static inline int b32_to_16(int x) { return SkB32ToB16(x); }
411 #else
round8to5(int x)412 static inline int round8to5(int x) {
413     return (x + 3 - (x >> 5) + (x >> 7)) >> 3;
414 }
round8to6(int x)415 static inline int round8to6(int x) {
416     int xx = (x + 1 - (x >> 6) + (x >> 7)) >> 2;
417     SkASSERT((unsigned)xx <= 63);
418 
419     int ix = x >> 2;
420     SkASSERT(SkAbs32(xx - ix) <= 1);
421     return xx;
422 }
423 
r32_to_16(int x)424 static inline int r32_to_16(int x) { return round8to5(x); }
g32_to_16(int x)425 static inline int g32_to_16(int x) { return round8to6(x); }
b32_to_16(int x)426 static inline int b32_to_16(int x) { return round8to5(x); }
427 #endif
428 
rgb_to_lcd16(uint32_t rgb)429 static inline uint16_t rgb_to_lcd16(uint32_t rgb) {
430     int r = (rgb >> 16) & 0xFF;
431     int g = (rgb >>  8) & 0xFF;
432     int b = (rgb >>  0) & 0xFF;
433 
434     // invert, since we draw black-on-white, but we want the original
435     // src mask values.
436     r = 255 - r;
437     g = 255 - g;
438     b = 255 - b;
439 
440     return SkPackRGB16(r32_to_16(r), g32_to_16(g), b32_to_16(b));
441 }
442 
443 #define BITMAP_INFO_RGB     (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host)
444 #define BITMAP_INFO_GRAY    (kCGImageAlphaNone)
445 
generateImage(const SkGlyph & glyph)446 void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
447     CGContextRef        cgContext;
448     CGGlyph             cgGlyph;
449     CGFontRef           cgFont;
450 
451     // Get the state we need
452     sk_bzero(glyph.fImage, glyph.fHeight * glyph.rowBytes());
453 
454     cgGlyph   = (CGGlyph) glyph.getGlyphID(fBaseGlyphCount);
455     cgFont    = CTFontCopyGraphicsFont(mFont, NULL);
456 
457     SkAutoSMalloc<1024> storage;
458 
459     CGColorSpaceRef colorspace = mColorSpaceGray;
460     uint32_t info = BITMAP_INFO_GRAY;
461     void* image = glyph.fImage;
462     size_t rowBytes = glyph.rowBytes();
463     float grayColor = 1; // white
464     bool doAA = true;
465 
466     /*  For LCD16, we first create a temp offscreen cg-context in 32bit,
467      *  erase to white, and then draw a black glyph into it. Then we can
468      *  extract the r,g,b values, invert-them, and now we have the original
469      *  src mask components, which we pack into our 16bit mask.
470      */
471     if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
472         colorspace = mColorSpaceRGB;
473         info = BITMAP_INFO_RGB;
474         // need tmp storage for 32bit RGB offscreen
475         rowBytes = glyph.fWidth << 2;
476         size_t size = glyph.fHeight * rowBytes;
477         image = storage.realloc(size);
478         // we draw black-on-white (and invert in rgb_to_lcd16)
479         sk_memset32((uint32_t*)image, 0xFFFFFFFF, size >> 2);
480         grayColor = 0;  // black
481     } else if (SkMask::kBW_Format == glyph.fMaskFormat) {
482         rowBytes = SkAlign4(glyph.fWidth);
483         size_t size = glyph.fHeight * rowBytes;
484         image = storage.realloc(size);
485         sk_bzero(image, size);
486         doAA = false;
487     }
488 
489     cgContext = CGBitmapContextCreate(image, glyph.fWidth, glyph.fHeight, 8,
490                                       rowBytes, colorspace, info);
491 
492     // Draw the glyph
493     if (cgFont != NULL && cgContext != NULL) {
494 #ifdef WE_ARE_RUNNING_ON_10_6_OR_LATER
495         CGContextSetAllowsFontSubpixelQuantization(cgContext, true);
496         CGContextSetShouldSubpixelQuantizeFonts(cgContext, true);
497 #endif
498         CGContextSetShouldAntialias(cgContext, doAA);
499         CGContextSetGrayFillColor(  cgContext, grayColor, 1.0);
500         CGContextSetTextDrawingMode(cgContext, kCGTextFill);
501         CGContextSetFont(           cgContext, cgFont);
502         CGContextSetFontSize(       cgContext, 1); // cgFont know's its size
503         CGContextSetTextMatrix(     cgContext, mTransform);
504         CGContextShowGlyphsAtPoint( cgContext, -glyph.fLeft, glyph.fTop + glyph.fHeight, &cgGlyph, 1);
505 
506         if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
507             // downsample from rgba to rgb565
508             int width = glyph.fWidth;
509             const uint32_t* src = (const uint32_t*)image;
510             uint16_t* dst = (uint16_t*)glyph.fImage;
511             size_t dstRB = glyph.rowBytes();
512             for (int y = 0; y < glyph.fHeight; y++) {
513                 for (int i = 0; i < width; i++) {
514                     dst[i] = rgb_to_lcd16(src[i]);
515                 }
516                 src = (const uint32_t*)((const char*)src + rowBytes);
517                 dst = (uint16_t*)((char*)dst + dstRB);
518             }
519         } else if (SkMask::kBW_Format == glyph.fMaskFormat) {
520             // downsample from A8 to A1
521             const uint8_t* src = (const uint8_t*)image;
522             uint8_t* dst = (uint8_t*)glyph.fImage;
523             size_t dstRB = glyph.rowBytes();
524             for (int y = 0; y < glyph.fHeight; y++) {
525                 bytes_to_bits(dst, src, glyph.fWidth);
526                 src += rowBytes;
527                 dst += dstRB;
528             }
529         }
530     }
531 
532     // Clean up
533     CFSafeRelease(cgFont);
534     CFSafeRelease(cgContext);
535 }
536 
generatePath(const SkGlyph & glyph,SkPath * path)537 void SkScalerContext_Mac::generatePath(const SkGlyph& glyph, SkPath* path) {
538     CGGlyph   cgGlyph = (CGGlyph)glyph.getGlyphID(fBaseGlyphCount);
539     CGPathRef cgPath  = CTFontCreatePathForGlyph(mFont, cgGlyph, NULL);
540 
541     path->reset();
542     if (cgPath != NULL) {
543         CGPathApply(cgPath, path, SkScalerContext_Mac::CTPathElement);
544         CFRelease(cgPath);
545     }
546 }
547 
generateFontMetrics(SkPaint::FontMetrics * mx,SkPaint::FontMetrics * my)548 void SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* mx,
549                                               SkPaint::FontMetrics* my) {
550     CGRect theBounds = CTFontGetBoundingBox(mFont);
551 
552     SkPaint::FontMetrics        theMetrics;
553     theMetrics.fTop          = -CGRectGetMaxY(theBounds);
554     theMetrics.fAscent       = -CTFontGetAscent(mFont);
555     theMetrics.fDescent      =  CTFontGetDescent(mFont);
556     theMetrics.fBottom       = -CGRectGetMinY(theBounds);
557     theMetrics.fLeading      =  CTFontGetLeading(mFont);
558     theMetrics.fAvgCharWidth =  CGRectGetWidth(theBounds);
559     theMetrics.fXMin         =  CGRectGetMinX(theBounds);
560     theMetrics.fXMax         =  CGRectGetMaxX(theBounds);
561     theMetrics.fXHeight      =  CTFontGetXHeight(mFont);
562 
563 #if 0
564     SkASSERT(theMetrics.fTop          <= 0.0);
565     SkASSERT(theMetrics.fAscent       <= 0.0);
566     SkASSERT(theMetrics.fDescent      >= 0.0);
567     SkASSERT(theMetrics.fBottom       >= 0.0);
568     SkASSERT(theMetrics.fLeading      >= 0.0);
569     SkASSERT(theMetrics.fAvgCharWidth >= 0.0);
570     SkASSERT(theMetrics.fXMin         <= 0.0);
571     SkASSERT(theMetrics.fXMax         >  0.0);
572     SkASSERT(theMetrics.fXHeight      >= 0.0);
573 #endif
574 
575     if (mx != NULL) {
576         *mx = theMetrics;
577     }
578     if (my != NULL) {
579         *my = theMetrics;
580     }
581 }
582 
CTPathElement(void * info,const CGPathElement * element)583 void SkScalerContext_Mac::CTPathElement(void *info, const CGPathElement *element)
584 {   SkPath      *skPath = (SkPath *) info;
585 
586 
587     // Process the path element
588     switch (element->type) {
589         case kCGPathElementMoveToPoint:
590             skPath->moveTo( element->points[0].x, -element->points[0].y);
591             break;
592 
593         case kCGPathElementAddLineToPoint:
594             skPath->lineTo( element->points[0].x, -element->points[0].y);
595             break;
596 
597         case kCGPathElementAddQuadCurveToPoint:
598             skPath->quadTo( element->points[0].x, -element->points[0].y,
599                             element->points[1].x, -element->points[1].y);
600             break;
601 
602         case kCGPathElementAddCurveToPoint:
603             skPath->cubicTo(element->points[0].x, -element->points[0].y,
604                             element->points[1].x, -element->points[1].y,
605                             element->points[2].x, -element->points[2].y);
606             break;
607 
608         case kCGPathElementCloseSubpath:
609             skPath->close();
610             break;
611 
612         default:
613             SkASSERT("Unknown path element!");
614             break;
615         }
616 }
617 
618 
619 ///////////////////////////////////////////////////////////////////////////////
620 
CreateTypefaceFromStream(SkStream * stream)621 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream)
622 {
623 //    SkASSERT(!"SkFontHost::CreateTypefaceFromStream unimplemented");
624     return SkFontHost::CreateTypeface(NULL, NULL, NULL, NULL, SkTypeface::kNormal);
625 }
626 
CreateTypefaceFromFile(const char path[])627 SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[])
628 {
629 //    SkASSERT(!"SkFontHost::CreateTypefaceFromFile unimplemented");
630     return SkFontHost::CreateTypeface(NULL, NULL, NULL, NULL, SkTypeface::kNormal);
631 }
632 
633 // Construct Glyph to Unicode table.
634 // Unicode code points that require conjugate pairs in utf16 are not
635 // supported.
populate_glyph_to_unicode(CTFontRef ctFont,const unsigned glyphCount,SkTDArray<SkUnichar> * glyphToUnicode)636 static void populate_glyph_to_unicode(CTFontRef ctFont,
637         const unsigned glyphCount, SkTDArray<SkUnichar>* glyphToUnicode) {
638     CFCharacterSetRef charSet = CTFontCopyCharacterSet(ctFont);
639     CFDataRef bitmap = CFCharacterSetCreateBitmapRepresentation(
640         kCFAllocatorDefault, charSet);
641     if (!bitmap) {
642         return;
643     }
644     CFIndex length = CFDataGetLength(bitmap);
645     if (!length) {
646         CFSafeRelease(bitmap);
647         return;
648     }
649     if (length > 8192) {
650         // TODO: Add support for Unicode above 0xFFFF
651         // Consider only the BMP portion of the Unicode character points.
652         // The bitmap may contain other planes, up to plane 16.
653         // See http://developer.apple.com/library/ios/#documentation/CoreFoundation/Reference/CFCharacterSetRef/Reference/reference.html
654         length = 8192;
655     }
656     const UInt8* bits = CFDataGetBytePtr(bitmap);
657     glyphToUnicode->setCount(glyphCount);
658     SkUnichar* out = glyphToUnicode->begin();
659     sk_bzero(out, glyphCount * sizeof(SkUnichar));
660     for (int i = 0; i < length; i++) {
661         int mask = bits[i];
662         if (!mask) {
663             continue;
664         }
665         for (int j = 0; j < 8; j++) {
666             CGGlyph glyph;
667             UniChar unichar = static_cast<UniChar>((i << 3) + j);
668             if (mask & (1 << j) && CTFontGetGlyphsForCharacters(ctFont,
669                     &unichar, &glyph, 1)) {
670                 out[glyph] = unichar;
671             }
672         }
673     }
674     CFSafeRelease(bitmap);
675 }
676 
getWidthAdvance(CTFontRef ctFont,int gId,int16_t * data)677 static bool getWidthAdvance(CTFontRef ctFont, int gId, int16_t* data) {
678     CGSize advance;
679     advance.width = 0;
680     CGGlyph glyph = gId;
681     CTFontGetAdvancesForGlyphs(ctFont, kCTFontHorizontalOrientation, &glyph,
682         &advance, 1);
683     *data = advance.width;
684     return true;
685 }
686 
687 // static
GetAdvancedTypefaceMetrics(uint32_t fontID,SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo)688 SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
689         uint32_t fontID,
690         SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo) {
691     CTFontRef ctFont = GetFontRefFromFontID(fontID);
692     SkAdvancedTypefaceMetrics* info = new SkAdvancedTypefaceMetrics;
693     CFStringRef fontName = CTFontCopyPostScriptName(ctFont);
694     int length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(fontName),
695         kCFStringEncodingUTF8);
696     info->fFontName.resize(length);
697     CFStringGetCString(fontName, info->fFontName.writable_str(), length,
698         kCFStringEncodingUTF8);
699     info->fMultiMaster = false;
700     CFIndex glyphCount = CTFontGetGlyphCount(ctFont);
701     info->fLastGlyphID = SkToU16(glyphCount - 1);
702     info->fEmSize = CTFontGetUnitsPerEm(ctFont);
703 
704     if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) {
705         populate_glyph_to_unicode(ctFont, glyphCount, &info->fGlyphToUnicode);
706     }
707 
708     // TODO: get font type, ala:
709     //  CFTypeRef attr = CTFontCopyAttribute(ctFont, kCTFontFormatAttribute);
710     info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
711     info->fStyle = 0;
712     CTFontSymbolicTraits symbolicTraits = CTFontGetSymbolicTraits(ctFont);
713     if (symbolicTraits & kCTFontMonoSpaceTrait) {
714         info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
715     }
716     if (symbolicTraits & kCTFontItalicTrait) {
717         info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
718     }
719     CTFontStylisticClass stylisticClass = symbolicTraits &
720             kCTFontClassMaskTrait;
721     if (stylisticClass & kCTFontSymbolicClass) {
722         info->fStyle |= SkAdvancedTypefaceMetrics::kSymbolic_Style;
723     }
724     if (stylisticClass >= kCTFontOldStyleSerifsClass
725             && stylisticClass <= kCTFontSlabSerifsClass) {
726         info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
727     } else if (stylisticClass & kCTFontScriptsClass) {
728         info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
729     }
730     info->fItalicAngle = CTFontGetSlantAngle(ctFont);
731     info->fAscent = CTFontGetAscent(ctFont);
732     info->fDescent = CTFontGetDescent(ctFont);
733     info->fCapHeight = CTFontGetCapHeight(ctFont);
734     CGRect bbox = CTFontGetBoundingBox(ctFont);
735     info->fBBox = SkIRect::MakeXYWH(bbox.origin.x, bbox.origin.y,
736         bbox.size.width, bbox.size.height);
737 
738     // Figure out a good guess for StemV - Min width of i, I, !, 1.
739     // This probably isn't very good with an italic font.
740     int16_t min_width = SHRT_MAX;
741     info->fStemV = 0;
742     static const UniChar stem_chars[] = {'i', 'I', '!', '1'};
743     const size_t count = sizeof(stem_chars) / sizeof(stem_chars[0]);
744     CGGlyph glyphs[count];
745     CGRect boundingRects[count];
746     if (CTFontGetGlyphsForCharacters(ctFont, stem_chars, glyphs, count)) {
747         CTFontGetBoundingRectsForGlyphs(ctFont, kCTFontHorizontalOrientation,
748             glyphs, boundingRects, count);
749         for (size_t i = 0; i < count; i++) {
750             int16_t width = boundingRects[i].size.width;
751             if (width > 0 && width < min_width) {
752                 min_width = width;
753                 info->fStemV = min_width;
754             }
755         }
756     }
757 
758     if (false) { // TODO: haven't figured out how to know if font is embeddable
759         // (information is in the OS/2 table)
760         info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
761     } else if (perGlyphInfo &
762                SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
763         info->fGlyphWidths.reset(
764             getAdvanceData(ctFont, glyphCount, &getWidthAdvance));
765     }
766 
767     return info;
768 }
769 
770 ///////////////////////////////////////////////////////////////////////////////
771 
ValidFontID(SkFontID fontID)772 bool SkFontHost::ValidFontID(SkFontID fontID) {
773     return SkTypefaceCache::FindByID(fontID) != NULL;
774 }
775 
776 struct FontHeader {
777     SkFixed fVersion;
778     uint16_t fNumTables;
779     uint16_t fSearchRange;
780     uint16_t fEntrySelector;
781     uint16_t fRangeShift;
782 };
783 
784 struct TableEntry {
785     uint32_t fTag;
786     uint32_t fCheckSum;
787     uint32_t fOffset;
788     uint32_t fLength;
789 };
790 
CalcTableCheckSum(uint32 * table,uint32 numberOfBytesInTable)791 static uint32 CalcTableCheckSum(uint32 *table, uint32 numberOfBytesInTable) {
792     uint32 sum = 0;
793     uint32 nLongs = (numberOfBytesInTable + 3) / 4;
794 
795     while (nLongs-- > 0) {
796         sum += SkEndian_SwapBE32(*table++);
797     }
798     return sum;
799 }
800 
OpenStream(SkFontID uniqueID)801 SkStream* SkFontHost::OpenStream(SkFontID uniqueID) {
802     // get table tags
803     int tableCount = CountTables(uniqueID);
804     SkTDArray<SkFontTableTag> tableTags;
805     tableTags.setCount(tableCount);
806     GetTableTags(uniqueID, tableTags.begin());
807 
808     // calc total size for font, save sizes
809     SkTDArray<size_t> tableSizes;
810     size_t totalSize = sizeof(FontHeader) + sizeof(TableEntry) * tableCount;
811     for (int index = 0; index < tableCount; ++index) {
812         size_t tableSize = GetTableSize(uniqueID, tableTags[index]);
813         totalSize += (tableSize + 3) & ~3;
814         *tableSizes.append() = tableSize;
815     }
816 
817     // reserve memory for stream, and zero it (tables must be zero padded)
818     SkMemoryStream* stream = new SkMemoryStream(totalSize);
819     char* dataStart = (char*)stream->getMemoryBase();
820     sk_bzero(dataStart, totalSize);
821     char* dataPtr = dataStart;
822 
823     // compute font header entries
824     uint16_t entrySelector = 0;
825     uint16_t searchRange = 1;
826     while (searchRange < tableCount >> 1) {
827         entrySelector++;
828         searchRange <<= 1;
829     }
830     searchRange <<= 4;
831     uint16_t rangeShift = (tableCount << 4) - searchRange;
832 
833     // write font header (also called sfnt header, offset subtable)
834     FontHeader* offsetTable = (FontHeader*)dataPtr;
835     offsetTable->fVersion = SkEndian_SwapBE32(SK_Fixed1);
836     offsetTable->fNumTables = SkEndian_SwapBE16(tableCount);
837     offsetTable->fSearchRange = SkEndian_SwapBE16(searchRange);
838     offsetTable->fEntrySelector = SkEndian_SwapBE16(entrySelector);
839     offsetTable->fRangeShift = SkEndian_SwapBE16(rangeShift);
840     dataPtr += sizeof(FontHeader);
841 
842     // write tables
843     TableEntry* entry = (TableEntry*)dataPtr;
844     dataPtr += sizeof(TableEntry) * tableCount;
845     for (int index = 0; index < tableCount; ++index) {
846         size_t tableSize = tableSizes[index];
847         GetTableData(uniqueID, tableTags[index], 0, tableSize, dataPtr);
848         entry->fTag = SkEndian_SwapBE32(tableTags[index]);
849         entry->fCheckSum = SkEndian_SwapBE32(CalcTableCheckSum(
850             (uint32*)dataPtr, tableSize));
851         entry->fOffset = SkEndian_SwapBE32(dataPtr - dataStart);
852         entry->fLength = SkEndian_SwapBE32(tableSize);
853         dataPtr += (tableSize + 3) & ~3;
854         ++entry;
855     }
856 
857     return stream;
858 }
859 
GetFileName(SkFontID fontID,char path[],size_t length,int32_t * index)860 size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
861                                int32_t* index) {
862     SkASSERT(!"SkFontHost::GetFileName unimplemented");
863     return(0);
864 }
865 
866 ///////////////////////////////////////////////////////////////////////////////
867 
868 #include "SkStream.h"
869 
Serialize(const SkTypeface * face,SkWStream * stream)870 void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
871     // hack: need a real name or something from CG
872     uint32_t fontID = face->uniqueID();
873     stream->write(&fontID, 4);
874 }
875 
Deserialize(SkStream * stream)876 SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
877     // hack: need a real name or something from CG
878     SkFontID fontID = stream->readU32();
879     SkTypeface* face = SkTypefaceCache::FindByID(fontID);
880     SkSafeRef(face);
881     return face;
882 }
883 
884 ///////////////////////////////////////////////////////////////////////////////
885 
CreateScalerContext(const SkDescriptor * desc)886 SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) {
887     return new SkScalerContext_Mac(desc);
888 }
889 
NextLogicalFont(SkFontID currFontID,SkFontID origFontID)890 SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
891     SkFontID nextFontID = 0;
892     SkTypeface* face = GetDefaultFace();
893     if (face->uniqueID() != currFontID) {
894         nextFontID = face->uniqueID();
895     }
896     return nextFontID;
897 }
898 
FilterRec(SkScalerContext::Rec * rec)899 void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
900     // we only support 2 levels of hinting
901     SkPaint::Hinting h = rec->getHinting();
902     if (SkPaint::kSlight_Hinting == h) {
903         h = SkPaint::kNo_Hinting;
904     } else if (SkPaint::kFull_Hinting == h) {
905         h = SkPaint::kNormal_Hinting;
906     }
907     rec->setHinting(h);
908 
909     // we don't support LCD text
910     if (SkMask::FormatIsLCD((SkMask::Format)rec->fMaskFormat)) {
911         rec->fMaskFormat = SkMask::kA8_Format;
912     }
913 }
914 
915 ///////////////////////////////////////////////////////////////////////////
916 
ShouldPurgeFontCache(size_t sizeAllocatedSoFar)917 size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) {
918     if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET) {
919         return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET;
920     }
921     return 0;
922 }
923 
ComputeGammaFlag(const SkPaint & paint)924 int SkFontHost::ComputeGammaFlag(const SkPaint& paint) {
925     return 0;
926 }
927 
GetGammaTables(const uint8_t * tables[2])928 void SkFontHost::GetGammaTables(const uint8_t* tables[2]) {
929     tables[0] = NULL;   // black gamma (e.g. exp=1.4)
930     tables[1] = NULL;   // white gamma (e.g. exp= 1/1.4)
931 }
932 
933 ///////////////////////////////////////////////////////////////////////////
934 
CountTables(SkFontID fontID)935 int SkFontHost::CountTables(SkFontID fontID) {
936     int             numTables;
937     CFArrayRef      cfArray;
938     CTFontRef       ctFont;
939 
940 
941     // Get the state we need
942     ctFont    = GetFontRefFromFontID(fontID);
943     cfArray   = CTFontCopyAvailableTables(ctFont, kCTFontTableOptionNoOptions);
944     numTables = 0;
945 
946 
947     // Get the table count
948     if (cfArray != NULL)
949         {
950         numTables = CFArrayGetCount(cfArray);
951         CFSafeRelease(cfArray);
952         }
953 
954     return(numTables);
955 }
956 
GetTableTags(SkFontID fontID,SkFontTableTag tags[])957 int SkFontHost::GetTableTags(SkFontID fontID, SkFontTableTag tags[])
958 {   int             n, numTables;
959     CFArrayRef      cfArray;
960     CTFontRef       ctFont;
961 
962 
963     // Get the state we need
964     ctFont    = GetFontRefFromFontID(fontID);
965     cfArray   = CTFontCopyAvailableTables(ctFont, kCTFontTableOptionNoOptions);
966     numTables = 0;
967 
968 
969     // Get the table tags
970     if (cfArray != NULL)
971         {
972         numTables = CFArrayGetCount(cfArray);
973         for (n = 0; n < numTables; n++)
974             tags[n] = (SkFontTableTag) ((uintptr_t) CFArrayGetValueAtIndex(cfArray, n));
975 
976         CFSafeRelease(cfArray);
977         }
978 
979     return(numTables);
980 }
981 
GetTableSize(SkFontID fontID,SkFontTableTag tag)982 size_t SkFontHost::GetTableSize(SkFontID fontID, SkFontTableTag tag)
983 {   size_t      theSize;
984     CTFontRef   ctFont;
985     CFDataRef   cfData;
986 
987 
988     // Get the state we need
989     ctFont  = GetFontRefFromFontID(fontID);
990     cfData  = CTFontCopyTable(ctFont, (CTFontTableTag) tag, kCTFontTableOptionNoOptions);
991     theSize = 0;
992 
993 
994     // Get the data size
995     if (cfData != NULL)
996         {
997         theSize = CFDataGetLength(cfData);
998         CFSafeRelease(cfData);
999         }
1000 
1001     return(theSize);
1002 }
1003 
GetTableData(SkFontID fontID,SkFontTableTag tag,size_t offset,size_t length,void * data)1004 size_t SkFontHost::GetTableData(SkFontID fontID, SkFontTableTag tag,
1005                                 size_t offset, size_t length, void* data)
1006 {   size_t          theSize;
1007     CTFontRef       ctFont;
1008     CFDataRef       cfData;
1009 
1010 
1011     // Get the state we need
1012     ctFont  = GetFontRefFromFontID(fontID);
1013     cfData  = CTFontCopyTable(ctFont, (CTFontTableTag) tag, kCTFontTableOptionNoOptions);
1014     theSize = 0;
1015 
1016 
1017     // Get the data
1018     if (cfData != NULL)
1019         theSize = CFDataGetLength(cfData);
1020 
1021     if (offset >= theSize)
1022         return 0;
1023 
1024     if ((offset + length) > theSize)
1025         length = theSize - offset;
1026 
1027     memcpy(data, CFDataGetBytePtr(cfData) + offset, length);
1028     return(length);
1029 }
1030 
1031 
1032 
1033 
1034