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
30using namespace skia_advanced_typeface_metrics_utils;
31
32static const size_t FONT_CACHE_MEMORY_BUDGET    = 1024 * 1024;
33static 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
53static 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
69class SkTypeface_Mac : public SkTypeface {
70public:
71    SkTypeface_Mac(SkTypeface::Style style, SkFontID fontID, bool isMonospace)
72        : SkTypeface(style, fontID, isMonospace), fFontRef(0) {}
73
74    virtual ~SkTypeface_Mac() { CFRelease(fFontRef); }
75
76    SkString    fName;
77    CTFontRef   fFontRef;
78};
79
80static 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
91static 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
143static CTFontRef GetFontRefFromFontID(SkFontID fontID) {
144    SkTypeface_Mac* face = reinterpret_cast<SkTypeface_Mac*>(SkTypefaceCache::FindByID(fontID));
145    return face ? face->fFontRef : 0;
146}
147
148static 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
160struct FontRefRec {
161    CTFontRef   fFontRef;
162};
163
164static 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 */
174SkTypeface* 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
187struct NameStyleRec {
188    const char*         fName;
189    SkTypeface::Style   fStyle;
190};
191
192static 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
200static 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
218SkTypeface* 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
256class SkScalerContext_Mac : public SkScalerContext {
257public:
258                                        SkScalerContext_Mac(const SkDescriptor* desc);
259    virtual                            ~SkScalerContext_Mac(void);
260
261
262protected:
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
272private:
273    static void                         CTPathElement(void *info, const CGPathElement *element);
274
275
276private:
277    CGColorSpaceRef                     mColorSpaceGray;
278    CGColorSpaceRef                     mColorSpaceRGB;
279    CGAffineTransform                   mTransform;
280
281    CTFontRef                           mFont;
282    uint16_t                            mGlyphCount;
283};
284
285SkScalerContext_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
319SkScalerContext_Mac::~SkScalerContext_Mac(void)
320{
321
322    // Clean up
323    CFSafeRelease(mColorSpaceGray);
324    CFSafeRelease(mColorSpaceRGB);
325    CFSafeRelease(mFont);
326}
327
328unsigned SkScalerContext_Mac::generateGlyphCount(void)
329{
330    return(mGlyphCount);
331}
332
333uint16_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
352void SkScalerContext_Mac::generateAdvance(SkGlyph* glyph)
353{
354    this->generateMetrics(glyph);
355}
356
357void 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
394static 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
408static inline int r32_to_16(int x) { return SkR32ToR16(x); }
409static inline int g32_to_16(int x) { return SkG32ToG16(x); }
410static inline int b32_to_16(int x) { return SkB32ToB16(x); }
411#else
412static inline int round8to5(int x) {
413    return (x + 3 - (x >> 5) + (x >> 7)) >> 3;
414}
415static 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
424static inline int r32_to_16(int x) { return round8to5(x); }
425static inline int g32_to_16(int x) { return round8to6(x); }
426static inline int b32_to_16(int x) { return round8to5(x); }
427#endif
428
429static 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
446void 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
537void 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
548void 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
583void 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
621SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream)
622{
623//    SkASSERT(!"SkFontHost::CreateTypefaceFromStream unimplemented");
624    return SkFontHost::CreateTypeface(NULL, NULL, NULL, NULL, SkTypeface::kNormal);
625}
626
627SkTypeface* 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.
636static 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
677static 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
688SkAdvancedTypefaceMetrics* 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
772bool SkFontHost::ValidFontID(SkFontID fontID) {
773    return SkTypefaceCache::FindByID(fontID) != NULL;
774}
775
776struct FontHeader {
777    SkFixed fVersion;
778    uint16_t fNumTables;
779    uint16_t fSearchRange;
780    uint16_t fEntrySelector;
781    uint16_t fRangeShift;
782};
783
784struct TableEntry {
785    uint32_t fTag;
786    uint32_t fCheckSum;
787    uint32_t fOffset;
788    uint32_t fLength;
789};
790
791static 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
801SkStream* 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
860size_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
870void 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
876SkTypeface* 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
886SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) {
887    return new SkScalerContext_Mac(desc);
888}
889
890SkFontID 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
899void 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
917size_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
924int SkFontHost::ComputeGammaFlag(const SkPaint& paint) {
925    return 0;
926}
927
928void 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
935int 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
957int 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
982size_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
1004size_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