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