• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright 2006 The Android Open Source Project
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 
10 #include <Carbon/Carbon.h>
11 #include "SkFontHost.h"
12 #include "SkDescriptor.h"
13 #include "SkEndian.h"
14 #include "SkFloatingPoint.h"
15 #include "SkPaint.h"
16 #include "SkPoint.h"
17 
18 const char* gDefaultfont = "Arial"; // hard code for now
19 SK_DECLARE_STATIC_MUTEX(gFTMutex);
20 
F32PtToSkPoint(const Float32Point p)21 static inline SkPoint F32PtToSkPoint(const Float32Point p) {
22     SkPoint sp = { SkFloatToScalar(p.x), SkFloatToScalar(p.y) };
23     return sp;
24 }
25 
_rotl(uint32_t v,uint32_t r)26 static inline uint32_t _rotl(uint32_t v, uint32_t r) {
27     return (v << r | v >> (32 - r));
28 }
29 
30 class SkTypeface_Mac : public SkTypeface {
31 public:
SkTypeface_Mac(SkTypeface::Style style,uint32_t id)32     SkTypeface_Mac(SkTypeface::Style style, uint32_t id)
33         : SkTypeface(style, id) {}
34 };
35 
36 #pragma mark -
37 
find_from_name(const char name[])38 static uint32_t find_from_name(const char name[]) {
39     CFStringRef str = CFStringCreateWithCString(NULL, name,
40                                                 kCFStringEncodingUTF8);
41     uint32_t fontID = ::ATSFontFindFromName(str, kATSOptionFlagsDefault);
42     CFRelease(str);
43     return fontID;
44 }
45 
find_default_fontID()46 static uint32_t find_default_fontID() {
47     static const char* gDefaultNames[] = { "Arial", "Tahoma", "Helvetica" };
48 
49     uint32_t fontID;
50     for (size_t i = 0; i < SK_ARRAY_COUNT(gDefaultNames); i++) {
51         fontID = find_from_name(gDefaultNames[i]);
52         if (fontID) {
53             return fontID;
54         }
55     }
56     sk_throw();
57     return 0;
58 }
59 
CreateTypeface_(const char name[],SkTypeface::Style style)60 static SkTypeface* CreateTypeface_(const char name[], SkTypeface::Style style) {
61     uint32_t fontID = 0;
62     if (NULL != name) {
63         fontID = find_from_name(name);
64     }
65     if (0 == fontID) {
66         fontID = find_default_fontID();
67     }
68     // we lie (for now) and report that we found the exact style bits
69     return new SkTypeface_Mac(style, fontID);
70 }
71 
72 #pragma mark -
73 
74 class SkScalerContext_Mac : public SkScalerContext {
75 public:
76     SkScalerContext_Mac(const SkDescriptor* desc);
77     virtual ~SkScalerContext_Mac();
78 
79 protected:
80     virtual unsigned generateGlyphCount();
81     virtual uint16_t generateCharToGlyph(SkUnichar uni);
82     virtual void generateAdvance(SkGlyph* glyph);
83     virtual void generateMetrics(SkGlyph* glyph);
84     virtual void generateImage(const SkGlyph& glyph);
85     virtual void generatePath(const SkGlyph& glyph, SkPath* path);
86     virtual void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY);
87 
88 private:
89     ATSUTextLayout  fLayout;
90     ATSUStyle       fStyle;
91     CGColorSpaceRef fGrayColorSpace;
92     CGAffineTransform   fTransform;
93 
94     static OSStatus MoveTo(const Float32Point *pt, void *cb);
95     static OSStatus Line(const Float32Point *pt, void *cb);
96     static OSStatus Curve(const Float32Point *pt1, const Float32Point *pt2, const Float32Point *pt3, void *cb);
97     static OSStatus Close(void *cb);
98 };
99 
FilterRec(SkScalerContext::Rec * rec)100 void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
101     // we only support 2 levels of hinting
102     SkPaint::Hinting h = rec->getHinting();
103     if (SkPaint::kSlight_Hinting == h) {
104         h = SkPaint::kNo_Hinting;
105     } else if (SkPaint::kFull_Hinting == h) {
106         h = SkPaint::kNormal_Hinting;
107     }
108     rec->setHinting(h);
109 
110     // we don't support LCD text
111     if (SkMask::kLCD16_Format == rec->fMaskFormat ||
112         SkMask::kLCD32_Format == rec->fMaskFormat) {
113         rec->fMaskFormat = SkMask::kA8_Format;
114     }
115 }
116 
SkScalerContext_Mac(const SkDescriptor * desc)117 SkScalerContext_Mac::SkScalerContext_Mac(const SkDescriptor* desc)
118     : SkScalerContext(desc), fLayout(0), fStyle(0)
119 {
120     SkAutoMutexAcquire  ac(gFTMutex);
121     OSStatus err;
122 
123     err = ::ATSUCreateStyle(&fStyle);
124     SkASSERT(0 == err);
125 
126     SkMatrix    m;
127     fRec.getSingleMatrix(&m);
128 
129     fTransform = CGAffineTransformMake(SkScalarToFloat(m[SkMatrix::kMScaleX]),
130                                        SkScalarToFloat(m[SkMatrix::kMSkewX]),
131                                        SkScalarToFloat(m[SkMatrix::kMSkewY]),
132                                        SkScalarToFloat(m[SkMatrix::kMScaleY]),
133                                        SkScalarToFloat(m[SkMatrix::kMTransX]),
134                                        SkScalarToFloat(m[SkMatrix::kMTransY]));
135 
136     ATSStyleRenderingOptions renderOpts = kATSStyleApplyAntiAliasing;
137     switch (fRec.getHinting()) {
138         case SkPaint::kNo_Hinting:
139         case SkPaint::kSlight_Hinting:
140             renderOpts |= kATSStyleNoHinting;
141             break;
142         case SkPaint::kNormal_Hinting:
143         case SkPaint::kFull_Hinting:
144             renderOpts |= kATSStyleApplyHints;
145             break;
146     }
147 
148     ATSUFontID fontID = FMGetFontFromATSFontRef(fRec.fFontID);
149     // we put everything in the matrix, so our pt size is just 1.0
150     Fixed fixedSize = SK_Fixed1;
151     static const ATSUAttributeTag tags[] = {
152         kATSUFontTag, kATSUSizeTag, kATSUFontMatrixTag, kATSUStyleRenderingOptionsTag
153     };
154     static const ByteCount sizes[] = {
155         sizeof(fontID), sizeof(fixedSize), sizeof(fTransform), sizeof(renderOpts)
156     };
157     const ATSUAttributeValuePtr values[] = {
158         &fontID, &fixedSize, &fTransform, &renderOpts
159     };
160     err = ::ATSUSetAttributes(fStyle, SK_ARRAY_COUNT(tags),
161                               tags, sizes, values);
162     SkASSERT(0 == err);
163 
164     err = ::ATSUCreateTextLayout(&fLayout);
165     SkASSERT(0 == err);
166 
167     fGrayColorSpace = ::CGColorSpaceCreateDeviceGray();
168 }
169 
~SkScalerContext_Mac()170 SkScalerContext_Mac::~SkScalerContext_Mac() {
171     ::CGColorSpaceRelease(fGrayColorSpace);
172     ::ATSUDisposeTextLayout(fLayout);
173     ::ATSUDisposeStyle(fStyle);
174 }
175 
176 // man, we need to consider caching this, since it is just dependent on
177 // fFontID, and not on any of the other settings like matrix or flags
generateGlyphCount()178 unsigned SkScalerContext_Mac::generateGlyphCount() {
179     // The 'maxp' table stores the number of glyphs a offset 4, in 2 bytes
180     uint16_t numGlyphs;
181     if (SkFontHost::GetTableData(fRec.fFontID,
182                                  SkSetFourByteTag('m', 'a', 'x', 'p'),
183                                  4, 2, &numGlyphs) != 2) {
184         return 0xFFFF;
185     }
186     return SkEndian_SwapBE16(numGlyphs);
187 }
188 
generateCharToGlyph(SkUnichar uni)189 uint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni)
190 {
191     SkAutoMutexAcquire  ac(gFTMutex);
192 
193     OSStatus err;
194     UniChar achar = uni;
195     err = ::ATSUSetTextPointerLocation(fLayout,&achar,0,1,1);
196     err = ::ATSUSetRunStyle(fLayout,fStyle,kATSUFromTextBeginning,kATSUToTextEnd);
197 
198     ATSLayoutRecord *layoutPtr;
199     ItemCount count;
200     ATSGlyphRef glyph;
201 
202     err = ::ATSUDirectGetLayoutDataArrayPtrFromTextLayout(fLayout,0,kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,(void**)&layoutPtr,&count);
203     glyph = layoutPtr->glyphID;
204     ::ATSUDirectReleaseLayoutDataArrayPtr(NULL,kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,(void**)&layoutPtr);
205     return glyph;
206 }
207 
set_glyph_metrics_on_error(SkGlyph * glyph)208 static void set_glyph_metrics_on_error(SkGlyph* glyph) {
209     glyph->fRsbDelta = 0;
210     glyph->fLsbDelta = 0;
211     glyph->fWidth    = 0;
212     glyph->fHeight   = 0;
213     glyph->fTop      = 0;
214     glyph->fLeft     = 0;
215     glyph->fAdvanceX = 0;
216     glyph->fAdvanceY = 0;
217 }
218 
generateAdvance(SkGlyph * glyph)219 void SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) {
220     this->generateMetrics(glyph);
221 }
222 
generateMetrics(SkGlyph * glyph)223 void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) {
224     GlyphID glyphID = glyph->getGlyphID(fBaseGlyphCount);
225     ATSGlyphScreenMetrics screenMetrics;
226     ATSGlyphIdealMetrics idealMetrics;
227 
228     OSStatus err = ATSUGlyphGetScreenMetrics(fStyle, 1, &glyphID, 0, true, true,
229                                              &screenMetrics);
230     if (noErr != err) {
231         set_glyph_metrics_on_error(glyph);
232         return;
233     }
234     err = ATSUGlyphGetIdealMetrics(fStyle, 1, &glyphID, 0, &idealMetrics);
235     if (noErr != err) {
236         set_glyph_metrics_on_error(glyph);
237         return;
238     }
239 
240     if ((fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) == 0) {
241         glyph->fAdvanceX = SkFloatToFixed(screenMetrics.deviceAdvance.x);
242         glyph->fAdvanceY = -SkFloatToFixed(screenMetrics.deviceAdvance.y);
243     } else {
244         glyph->fAdvanceX = SkFloatToFixed(idealMetrics.advance.x);
245         glyph->fAdvanceY = -SkFloatToFixed(idealMetrics.advance.y);
246     }
247 
248     // specify an extra 1-pixel border, go tive CG room for its antialiasing
249     // i.e. without this, I was seeing some edges chopped off!
250     glyph->fWidth = screenMetrics.width + 2;
251     glyph->fHeight = screenMetrics.height + 2;
252     glyph->fLeft = sk_float_round2int(screenMetrics.topLeft.x) - 1;
253     glyph->fTop = -sk_float_round2int(screenMetrics.topLeft.y) - 1;
254 }
255 
generateImage(const SkGlyph & glyph)256 void SkScalerContext_Mac::generateImage(const SkGlyph& glyph)
257 {
258     SkAutoMutexAcquire  ac(gFTMutex);
259     SkASSERT(fLayout);
260 
261     sk_bzero(glyph.fImage, glyph.fHeight * glyph.rowBytes());
262     CGContextRef contextRef = ::CGBitmapContextCreate(glyph.fImage,
263                                               glyph.fWidth, glyph.fHeight, 8,
264                                               glyph.rowBytes(), fGrayColorSpace,
265                                               kCGImageAlphaNone);
266     if (!contextRef) {
267         SkASSERT(false);
268         return;
269     }
270 
271     ::CGContextSetGrayFillColor(contextRef, 1.0, 1.0);
272     ::CGContextSetTextDrawingMode(contextRef, kCGTextFill);
273 
274     CGGlyph glyphID = glyph.getGlyphID(fBaseGlyphCount);
275     CGFontRef fontRef = CGFontCreateWithPlatformFont(&fRec.fFontID);
276     CGContextSetFont(contextRef, fontRef);
277     CGContextSetFontSize(contextRef, 1);
278     CGContextSetTextMatrix(contextRef, fTransform);
279     CGContextShowGlyphsAtPoint(contextRef, -glyph.fLeft,
280                                glyph.fTop + glyph.fHeight, &glyphID, 1);
281 
282     ::CGContextRelease(contextRef);
283 }
284 
285 #if 0
286 static void convert_metrics(SkPaint::FontMetrics* dst,
287                             const ATSFontMetrics& src) {
288     dst->fTop     = -SkFloatToScalar(src.ascent);
289     dst->fAscent  = -SkFloatToScalar(src.ascent);
290     dst->fDescent = SkFloatToScalar(src.descent);
291     dst->fBottom  = SkFloatToScalar(src.descent);
292     dst->fLeading = SkFloatToScalar(src.leading);
293 }
294 #endif
295 
get_font_table(ATSFontRef fontID,uint32_t tag)296 static void* get_font_table(ATSFontRef fontID, uint32_t tag) {
297     ByteCount size;
298     OSStatus err = ATSFontGetTable(fontID, tag, 0, 0, NULL, &size);
299     if (err) {
300         return NULL;
301     }
302     void* data = sk_malloc_throw(size);
303     err = ATSFontGetTable(fontID, tag, 0, size, data, &size);
304     if (err) {
305         sk_free(data);
306         data = NULL;
307     }
308     return data;
309 }
310 
get_be16(const void * data,size_t offset)311 static int get_be16(const void* data, size_t offset) {
312     const char* ptr = reinterpret_cast<const char*>(data);
313     uint16_t value = *reinterpret_cast<const uint16_t*>(ptr + offset);
314     int n = SkEndian_SwapBE16(value);
315     // now force it to be signed
316     return n << 16 >> 16;
317 }
318 
319 #define SFNT_HEAD_UPEM_OFFSET       18
320 #define SFNT_HEAD_YMIN_OFFSET       38
321 #define SFNT_HEAD_YMAX_OFFSET       42
322 #define SFNT_HEAD_STYLE_OFFSET      44
323 
324 #define SFNT_HHEA_ASCENT_OFFSET     4
325 #define SFNT_HHEA_DESCENT_OFFSET    6
326 #define SFNT_HHEA_LEADING_OFFSET    8
327 
init_vertical_metrics(ATSFontRef font,SkPoint pts[5])328 static bool init_vertical_metrics(ATSFontRef font, SkPoint pts[5]) {
329     void* head = get_font_table(font, 'head');
330     if (NULL == head) {
331         return false;
332     }
333     void* hhea = get_font_table(font, 'hhea');
334     if (NULL == hhea) {
335         sk_free(head);
336         return false;
337     }
338 
339     int upem = get_be16(head, SFNT_HEAD_UPEM_OFFSET);
340     int ys[5];
341 
342     ys[0] = -get_be16(head, SFNT_HEAD_YMAX_OFFSET);
343     ys[1] = -get_be16(hhea, SFNT_HHEA_ASCENT_OFFSET);
344     ys[2] = -get_be16(hhea, SFNT_HHEA_DESCENT_OFFSET);
345     ys[3] = -get_be16(head, SFNT_HEAD_YMIN_OFFSET);
346     ys[4] =  get_be16(hhea, SFNT_HHEA_LEADING_OFFSET);
347 
348     // now do some cleanup, to ensure y[max,min] are really that
349     if (ys[0] > ys[1]) {
350         ys[0] = ys[1];
351     }
352     if (ys[3] < ys[2]) {
353         ys[3] = ys[2];
354     }
355 
356     for (int i = 0; i < 5; i++) {
357         pts[i].set(0, SkIntToScalar(ys[i]) / upem);
358     }
359 
360     sk_free(hhea);
361     sk_free(head);
362     return true;
363 }
364 
generateFontMetrics(SkPaint::FontMetrics * mx,SkPaint::FontMetrics * my)365 void SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* mx,
366                                               SkPaint::FontMetrics* my) {
367     SkPoint pts[5];
368 
369     if (!init_vertical_metrics(fRec.fFontID, pts)) {
370         // these are not as accurate as init_vertical_metrics :(
371         ATSFontMetrics metrics;
372         ATSFontGetVerticalMetrics(fRec.fFontID, kATSOptionFlagsDefault,
373                                   &metrics);
374         pts[0].set(0, -SkFloatToScalar(metrics.ascent));
375         pts[1].set(0, -SkFloatToScalar(metrics.ascent));
376         pts[2].set(0, -SkFloatToScalar(metrics.descent));
377         pts[3].set(0, -SkFloatToScalar(metrics.descent));
378         pts[4].set(0, SkFloatToScalar(metrics.leading));    //+ or -?
379     }
380 
381     SkMatrix m;
382     fRec.getSingleMatrix(&m);
383     m.mapPoints(pts, 5);
384 
385     if (mx) {
386         mx->fTop = pts[0].fX;
387         mx->fAscent = pts[1].fX;
388         mx->fDescent = pts[2].fX;
389         mx->fBottom = pts[3].fX;
390         mx->fLeading = pts[4].fX;
391         // FIXME:
392         mx->fAvgCharWidth = 0;
393         mx->fXMin = 0;
394         mx->fXMax = 0;
395         mx->fXHeight = 0;
396     }
397     if (my) {
398         my->fTop = pts[0].fY;
399         my->fAscent = pts[1].fY;
400         my->fDescent = pts[2].fY;
401         my->fBottom = pts[3].fY;
402         my->fLeading = pts[4].fY;
403         // FIXME:
404         my->fAvgCharWidth = 0;
405         my->fXMin = 0;
406         my->fXMax = 0;
407         my->fXHeight = 0;
408     }
409 }
410 
generatePath(const SkGlyph & glyph,SkPath * path)411 void SkScalerContext_Mac::generatePath(const SkGlyph& glyph, SkPath* path)
412 {
413     SkAutoMutexAcquire  ac(gFTMutex);
414     OSStatus err,result;
415 
416     err = ::ATSUGlyphGetCubicPaths(
417             fStyle,glyph.fID,
418             &SkScalerContext_Mac::MoveTo,
419             &SkScalerContext_Mac::Line,
420             &SkScalerContext_Mac::Curve,
421             &SkScalerContext_Mac::Close,
422             path,&result);
423     SkASSERT(err == noErr);
424 }
425 
MoveTo(const Float32Point * pt,void * cb)426 OSStatus SkScalerContext_Mac::MoveTo(const Float32Point *pt, void *cb)
427 {
428     reinterpret_cast<SkPath*>(cb)->moveTo(F32PtToSkPoint(*pt));
429     return noErr;
430 }
431 
Line(const Float32Point * pt,void * cb)432 OSStatus SkScalerContext_Mac::Line(const Float32Point *pt, void *cb)
433 {
434     reinterpret_cast<SkPath*>(cb)->lineTo(F32PtToSkPoint(*pt));
435     return noErr;
436 }
437 
Curve(const Float32Point * pt1,const Float32Point * pt2,const Float32Point * pt3,void * cb)438 OSStatus SkScalerContext_Mac::Curve(const Float32Point *pt1,
439                                     const Float32Point *pt2,
440                                     const Float32Point *pt3, void *cb)
441 {
442     reinterpret_cast<SkPath*>(cb)->cubicTo(F32PtToSkPoint(*pt1),
443                                            F32PtToSkPoint(*pt2),
444                                            F32PtToSkPoint(*pt3));
445     return noErr;
446 }
447 
Close(void * cb)448 OSStatus SkScalerContext_Mac::Close(void *cb)
449 {
450     reinterpret_cast<SkPath*>(cb)->close();
451     return noErr;
452 }
453 
454 #pragma mark -
455 
Serialize(const SkTypeface * face,SkWStream * stream)456 void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
457     SkDEBUGFAIL("SkFontHost::Serialize unimplemented");
458 }
459 
Deserialize(SkStream * stream)460 SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
461     SkDEBUGFAIL("SkFontHost::Deserialize unimplemented");
462     return NULL;
463 }
464 
CreateTypefaceFromStream(SkStream * stream)465 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
466     return NULL;
467 }
468 
CreateTypefaceFromFile(const char path[])469 SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
470     return NULL;
471 }
472 
473 // static
GetAdvancedTypefaceMetrics(uint32_t fontID,SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,const uint32_t * glyphIDs,uint32_t glyphIDsCount)474 SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
475         uint32_t fontID,
476         SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
477         const uint32_t* glyphIDs,
478         uint32_t glyphIDsCount) {
479     SkDEBUGFAIL("SkFontHost::GetAdvancedTypefaceMetrics unimplemented");
480     return NULL;
481 }
482 
CreateScalerContext(const SkDescriptor * desc)483 SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) {
484     return new SkScalerContext_Mac(desc);
485 }
486 
NextLogicalFont(SkFontID currFontID,SkFontID origFontID)487 SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
488     uint32_t newFontID = find_default_fontID();
489     if (newFontID == currFontID) {
490         newFontID = 0;
491     }
492     return newFontID;
493 }
494 
CreateTypeface(const SkTypeface * familyFace,const char familyName[],const void * data,size_t bytelength,SkTypeface::Style style)495 SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
496                             const char familyName[],
497                             const void* data, size_t bytelength,
498                             SkTypeface::Style style) {
499     // todo: we don't know how to respect style bits
500     if (NULL == familyName && NULL != familyFace) {
501         familyFace->ref();
502         return const_cast<SkTypeface*>(familyFace);
503     } else {
504         return CreateTypeface_(familyName, style);
505     }
506 }
507 
508 ///////////////////////////////////////////////////////////////////////////////
509 
510 struct SkSFNTHeader {
511     uint32_t    fVersion;
512     uint16_t    fNumTables;
513     uint16_t    fSearchRange;
514     uint16_t    fEntrySelector;
515     uint16_t    fRangeShift;
516 };
517 
518 struct SkSFNTDirEntry {
519     uint32_t    fTag;
520     uint32_t    fChecksum;
521     uint32_t    fOffset;
522     uint32_t    fLength;
523 };
524 
525 struct SfntHeader {
SfntHeaderSfntHeader526     SfntHeader(SkFontID fontID, bool needDir) : fCount(0), fData(NULL) {
527         ByteCount size;
528         if (ATSFontGetTableDirectory(fontID, 0, NULL, &size)) {
529             return;
530         }
531 
532         SkAutoMalloc storage(size);
533         SkSFNTHeader* header = reinterpret_cast<SkSFNTHeader*>(storage.get());
534         if (ATSFontGetTableDirectory(fontID, size, header, &size)) {
535             return;
536         }
537 
538         fCount = SkEndian_SwapBE16(header->fNumTables);
539         fData = header;
540         storage.detach();
541     }
542 
~SfntHeaderSfntHeader543     ~SfntHeader() {
544         sk_free(fData);
545     }
546 
countSfntHeader547     int count() const { return fCount; }
entriesSfntHeader548     const SkSFNTDirEntry* entries() const {
549         return reinterpret_cast<const SkSFNTDirEntry*>
550             (reinterpret_cast<char*>(fData) + sizeof(SkSFNTHeader));
551     }
552 
553 private:
554     int     fCount;
555     void*   fData;
556 };
557 
CountTables(SkFontID fontID)558 int SkFontHost::CountTables(SkFontID fontID) {
559     SfntHeader header(fontID, false);
560     return header.count();
561 }
562 
GetTableTags(SkFontID fontID,SkFontTableTag tags[])563 int SkFontHost::GetTableTags(SkFontID fontID, SkFontTableTag tags[]) {
564     SfntHeader header(fontID, true);
565     int count = header.count();
566     const SkSFNTDirEntry* entry = header.entries();
567     for (int i = 0; i < count; i++) {
568         tags[i] = SkEndian_SwapBE32(entry[i].fTag);
569     }
570     return count;
571 }
572 
GetTableSize(SkFontID fontID,SkFontTableTag tag)573 size_t SkFontHost::GetTableSize(SkFontID fontID, SkFontTableTag tag) {
574     ByteCount size;
575     if (ATSFontGetTable(fontID, tag, 0, 0, NULL, &size)) {
576         return 0;
577     }
578     return size;
579 }
580 
GetTableData(SkFontID fontID,SkFontTableTag tag,size_t offset,size_t length,void * data)581 size_t SkFontHost::GetTableData(SkFontID fontID, SkFontTableTag tag,
582                                 size_t offset, size_t length, void* data) {
583     ByteCount size;
584     if (ATSFontGetTable(fontID, tag, offset, length, data, &size)) {
585         return 0;
586     }
587     if (offset >= size) {
588         return 0;
589     }
590     if (offset + length > size) {
591         length = size - offset;
592     }
593     return length;
594 }
595