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