SkScalerContext.cpp revision 045e62d715f5ee9b03deb5af3c750f8318096179
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 "SkScalerContext.h"
11#include "SkColorPriv.h"
12#include "SkDescriptor.h"
13#include "SkDraw.h"
14#include "SkFontHost.h"
15#include "SkMaskFilter.h"
16#include "SkPathEffect.h"
17#include "SkRasterizer.h"
18#include "SkRasterClip.h"
19#include "SkStroke.h"
20#include "SkThread.h"
21
22#define ComputeBWRowBytes(width)        (((unsigned)(width) + 7) >> 3)
23
24static const uint8_t* gBlackGammaTable;
25static const uint8_t* gWhiteGammaTable;
26
27void SkGlyph::toMask(SkMask* mask) const {
28    SkASSERT(mask);
29
30    mask->fImage = (uint8_t*)fImage;
31    mask->fBounds.set(fLeft, fTop, fLeft + fWidth, fTop + fHeight);
32    mask->fRowBytes = this->rowBytes();
33    mask->fFormat = static_cast<SkMask::Format>(fMaskFormat);
34}
35
36size_t SkGlyph::computeImageSize() const {
37    const size_t size = this->rowBytes() * fHeight;
38
39    switch (fMaskFormat) {
40        case SkMask::k3D_Format:
41            return 3 * size;
42        default:
43            return size;
44    }
45}
46
47void SkGlyph::zeroMetrics() {
48    fAdvanceX = 0;
49    fAdvanceY = 0;
50    fWidth    = 0;
51    fHeight   = 0;
52    fTop      = 0;
53    fLeft     = 0;
54    fRsbDelta = 0;
55    fLsbDelta = 0;
56}
57
58///////////////////////////////////////////////////////////////////////////////
59
60#ifdef SK_DEBUG
61    #define DUMP_RECx
62#endif
63
64static SkFlattenable* load_flattenable(const SkDescriptor* desc, uint32_t tag) {
65    SkFlattenable*  obj = NULL;
66    uint32_t        len;
67    const void*     data = desc->findEntry(tag, &len);
68
69    if (data) {
70        SkFlattenableReadBuffer   buffer(data, len);
71        obj = buffer.readFlattenable();
72        SkASSERT(buffer.offset() == buffer.size());
73    }
74    return obj;
75}
76
77SkScalerContext::SkScalerContext(const SkDescriptor* desc)
78    : fPathEffect(NULL), fMaskFilter(NULL)
79{
80    static bool gHaveGammaTables;
81    if (!gHaveGammaTables) {
82        const uint8_t* tables[2];
83        SkFontHost::GetGammaTables(tables);
84        gBlackGammaTable = tables[0];
85        gWhiteGammaTable = tables[1];
86        gHaveGammaTables = true;
87    }
88
89    fBaseGlyphCount = 0;
90    fNextContext = NULL;
91
92    const Rec* rec = (const Rec*)desc->findEntry(kRec_SkDescriptorTag, NULL);
93    SkASSERT(rec);
94
95    fRec = *rec;
96
97#ifdef DUMP_REC
98    desc->assertChecksum();
99    SkDebugf("SkScalarContext checksum %x count %d length %d\n",
100             desc->getChecksum(), desc->getCount(), desc->getLength());
101    SkDebugf(" textsize %g prescale %g preskew %g post [%g %g %g %g]\n",
102        rec->fTextSize, rec->fPreScaleX, rec->fPreSkewX, rec->fPost2x2[0][0],
103        rec->fPost2x2[0][1], rec->fPost2x2[1][0], rec->fPost2x2[1][1]);
104    SkDebugf("  frame %g miter %g hints %d framefill %d format %d join %d\n",
105        rec->fFrameWidth, rec->fMiterLimit, rec->fHints, rec->fFrameAndFill,
106        rec->fMaskFormat, rec->fStrokeJoin);
107    SkDebugf("  pathEffect %x maskFilter %x\n",
108             desc->findEntry(kPathEffect_SkDescriptorTag, NULL),
109        desc->findEntry(kMaskFilter_SkDescriptorTag, NULL));
110#endif
111
112    fPathEffect = (SkPathEffect*)load_flattenable(desc, kPathEffect_SkDescriptorTag);
113    fMaskFilter = (SkMaskFilter*)load_flattenable(desc, kMaskFilter_SkDescriptorTag);
114    fRasterizer = (SkRasterizer*)load_flattenable(desc, kRasterizer_SkDescriptorTag);
115
116    // initialize based on our settings. subclasses can also force this
117    fGenerateImageFromPath = fRec.fFrameWidth > 0 || fPathEffect != NULL ||
118                             fRasterizer != NULL;
119}
120
121SkScalerContext::~SkScalerContext() {
122    SkDELETE(fNextContext);
123
124    SkSafeUnref(fPathEffect);
125    SkSafeUnref(fMaskFilter);
126    SkSafeUnref(fRasterizer);
127}
128
129static SkScalerContext* allocNextContext(const SkScalerContext::Rec& rec) {
130    // fonthost will determine the next possible font to search, based
131    // on the current font in fRec. It will return NULL if ctx is our
132    // last font that can be searched (i.e. ultimate fallback font)
133    uint32_t newFontID = SkFontHost::NextLogicalFont(rec.fFontID, rec.fOrigFontID);
134    if (0 == newFontID) {
135        return NULL;
136    }
137
138    SkAutoDescriptor    ad(sizeof(rec) + SkDescriptor::ComputeOverhead(1));
139    SkDescriptor*       desc = ad.getDesc();
140
141    desc->init();
142    SkScalerContext::Rec* newRec =
143    (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag,
144                                          sizeof(rec), &rec);
145    newRec->fFontID = newFontID;
146    desc->computeChecksum();
147
148    return SkFontHost::CreateScalerContext(desc);
149}
150
151/*  Return the next context, creating it if its not already created, but return
152    NULL if the fonthost says there are no more fonts to fallback to.
153 */
154SkScalerContext* SkScalerContext::getNextContext() {
155    SkScalerContext* next = fNextContext;
156    // if next is null, then either it isn't cached yet, or we're at the
157    // end of our possible chain
158    if (NULL == next) {
159        next = allocNextContext(fRec);
160        if (NULL == next) {
161            return NULL;
162        }
163        // next's base is our base + our local count
164        next->setBaseGlyphCount(fBaseGlyphCount + this->getGlyphCount());
165        // cache the answer
166        fNextContext = next;
167    }
168    return next;
169}
170
171SkScalerContext* SkScalerContext::getGlyphContext(const SkGlyph& glyph) {
172    unsigned glyphID = glyph.getGlyphID();
173    SkScalerContext* ctx = this;
174    for (;;) {
175        unsigned count = ctx->getGlyphCount();
176        if (glyphID < count) {
177            break;
178        }
179        glyphID -= count;
180        ctx = ctx->getNextContext();
181        if (NULL == ctx) {
182            SkDebugf("--- no context for glyph %x\n", glyph.getGlyphID());
183            // just return the original context (this)
184            return this;
185        }
186    }
187    return ctx;
188}
189
190/*  This loops through all available fallback contexts (if needed) until it
191    finds some context that can handle the unichar. If all fail, returns 0
192 */
193uint16_t SkScalerContext::charToGlyphID(SkUnichar uni) {
194    SkScalerContext* ctx = this;
195    unsigned glyphID;
196    for (;;) {
197        glyphID = ctx->generateCharToGlyph(uni);
198        if (glyphID) {
199            break;  // found it
200        }
201        ctx = ctx->getNextContext();
202        if (NULL == ctx) {
203            return 0;   // no more contexts, return missing glyph
204        }
205    }
206    // add the ctx's base, making glyphID unique for chain of contexts
207    glyphID += ctx->fBaseGlyphCount;
208    // check for overflow of 16bits, since our glyphID cannot exceed that
209    if (glyphID > 0xFFFF) {
210        glyphID = 0;
211    }
212    return SkToU16(glyphID);
213}
214
215SkUnichar SkScalerContext::glyphIDToChar(uint16_t glyphID) {
216    SkScalerContext* ctx = this;
217    unsigned rangeEnd = 0;
218    do {
219        unsigned rangeStart = rangeEnd;
220
221        rangeEnd += ctx->getGlyphCount();
222        if (rangeStart <= glyphID && glyphID < rangeEnd) {
223            return ctx->generateGlyphToChar(glyphID - rangeStart);
224        }
225        ctx = ctx->getNextContext();
226    } while (NULL != ctx);
227    return 0;
228}
229
230void SkScalerContext::getAdvance(SkGlyph* glyph) {
231    // mark us as just having a valid advance
232    glyph->fMaskFormat = MASK_FORMAT_JUST_ADVANCE;
233    // we mark the format before making the call, in case the impl
234    // internally ends up calling its generateMetrics, which is OK
235    // albeit slower than strictly necessary
236    this->getGlyphContext(*glyph)->generateAdvance(glyph);
237}
238
239void SkScalerContext::getMetrics(SkGlyph* glyph) {
240    this->getGlyphContext(*glyph)->generateMetrics(glyph);
241
242    // for now we have separate cache entries for devkerning on and off
243    // in the future we might share caches, but make our measure/draw
244    // code make the distinction. Thus we zap the values if the caller
245    // has not asked for them.
246    if ((fRec.fFlags & SkScalerContext::kDevKernText_Flag) == 0) {
247        // no devkern, so zap the fields
248        glyph->fLsbDelta = glyph->fRsbDelta = 0;
249    }
250
251    // if either dimension is empty, zap the image bounds of the glyph
252    if (0 == glyph->fWidth || 0 == glyph->fHeight) {
253        glyph->fWidth   = 0;
254        glyph->fHeight  = 0;
255        glyph->fTop     = 0;
256        glyph->fLeft    = 0;
257        glyph->fMaskFormat = 0;
258        return;
259    }
260
261    if (fGenerateImageFromPath) {
262        SkPath      devPath, fillPath;
263        SkMatrix    fillToDevMatrix;
264
265        this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
266
267        if (fRasterizer) {
268            SkMask  mask;
269
270            if (fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
271                                       fMaskFilter, &mask,
272                                       SkMask::kJustComputeBounds_CreateMode)) {
273                glyph->fLeft    = mask.fBounds.fLeft;
274                glyph->fTop     = mask.fBounds.fTop;
275                glyph->fWidth   = SkToU16(mask.fBounds.width());
276                glyph->fHeight  = SkToU16(mask.fBounds.height());
277            } else {
278                goto SK_ERROR;
279            }
280        } else {
281            // just use devPath
282            SkIRect ir;
283            devPath.getBounds().roundOut(&ir);
284
285            if (ir.isEmpty() || !ir.is16Bit()) {
286                goto SK_ERROR;
287            }
288            glyph->fLeft    = ir.fLeft;
289            glyph->fTop     = ir.fTop;
290            glyph->fWidth   = SkToU16(ir.width());
291            glyph->fHeight  = SkToU16(ir.height());
292        }
293    }
294
295	if (SkMask::kARGB32_Format != glyph->fMaskFormat) {
296		glyph->fMaskFormat = fRec.fMaskFormat;
297	}
298
299    if (fMaskFilter) {
300        SkMask      src, dst;
301        SkMatrix    matrix;
302
303        glyph->toMask(&src);
304        fRec.getMatrixFrom2x2(&matrix);
305
306        src.fImage = NULL;  // only want the bounds from the filter
307        if (fMaskFilter->filterMask(&dst, src, matrix, NULL)) {
308            SkASSERT(dst.fImage == NULL);
309            glyph->fLeft    = dst.fBounds.fLeft;
310            glyph->fTop     = dst.fBounds.fTop;
311            glyph->fWidth   = SkToU16(dst.fBounds.width());
312            glyph->fHeight  = SkToU16(dst.fBounds.height());
313            glyph->fMaskFormat = dst.fFormat;
314        }
315    }
316    return;
317
318SK_ERROR:
319    // draw nothing 'cause we failed
320    glyph->fLeft    = 0;
321    glyph->fTop     = 0;
322    glyph->fWidth   = 0;
323    glyph->fHeight  = 0;
324    // put a valid value here, in case it was earlier set to
325    // MASK_FORMAT_JUST_ADVANCE
326    glyph->fMaskFormat = fRec.fMaskFormat;
327}
328
329static bool isLCD(const SkScalerContext::Rec& rec) {
330    return SkMask::kLCD16_Format == rec.fMaskFormat ||
331           SkMask::kLCD32_Format == rec.fMaskFormat;
332}
333
334static uint16_t a8_to_rgb565(unsigned a8) {
335    return SkPackRGB16(a8 >> 3, a8 >> 2, a8 >> 3);
336}
337
338static void copyToLCD16(const SkBitmap& src, const SkMask& dst) {
339    SkASSERT(SkBitmap::kA8_Config == src.config());
340    SkASSERT(SkMask::kLCD16_Format == dst.fFormat);
341
342    const int width = dst.fBounds.width();
343    const int height = dst.fBounds.height();
344    const uint8_t* srcP = src.getAddr8(0, 0);
345    size_t srcRB = src.rowBytes();
346    uint16_t* dstP = (uint16_t*)dst.fImage;
347    size_t dstRB = dst.fRowBytes;
348    for (int y = 0; y < height; ++y) {
349        for (int x = 0; x < width; ++x) {
350            dstP[x] = a8_to_rgb565(srcP[x]);
351        }
352        srcP += srcRB;
353        dstP = (uint16_t*)((char*)dstP + dstRB);
354    }
355}
356
357#define SK_FREETYPE_LCD_LERP    160
358
359static int lerp(int start, int end) {
360    SkASSERT((unsigned)SK_FREETYPE_LCD_LERP <= 256);
361    return start + ((end - start) * (SK_FREETYPE_LCD_LERP) >> 8);
362}
363
364static uint16_t packLCD16(unsigned r, unsigned g, unsigned b) {
365    if (SK_FREETYPE_LCD_LERP) {
366        // want (a+b+c)/3, but we approx to avoid the divide
367        unsigned ave = (5 * (r + g + b) + g) >> 4;
368        r = lerp(r, ave);
369        g = lerp(g, ave);
370        b = lerp(b, ave);
371    }
372    return SkPackRGB16(r >> 3, g >> 2, b >> 3);
373}
374
375static void pack3xHToLCD16(const SkBitmap& src, const SkMask& dst) {
376    SkASSERT(SkBitmap::kA8_Config == src.config());
377    SkASSERT(SkMask::kLCD16_Format == dst.fFormat);
378
379    const int width = dst.fBounds.width();
380    const int height = dst.fBounds.height();
381    uint16_t* dstP = (uint16_t*)dst.fImage;
382    size_t dstRB = dst.fRowBytes;
383    for (int y = 0; y < height; ++y) {
384        const uint8_t* srcP = src.getAddr8(0, y);
385        for (int x = 0; x < width; ++x) {
386            unsigned r = *srcP++;
387            unsigned g = *srcP++;
388            unsigned b = *srcP++;
389            dstP[x] = packLCD16(r, g, b);
390        }
391        dstP = (uint16_t*)((char*)dstP + dstRB);
392    }
393}
394
395static void pack3xHToLCD32(const SkBitmap& src, const SkMask& dst) {
396    SkASSERT(SkBitmap::kA8_Config == src.config());
397    SkASSERT(SkMask::kLCD32_Format == dst.fFormat);
398
399    const int width = dst.fBounds.width();
400    const int height = dst.fBounds.height();
401    SkPMColor* dstP = (SkPMColor*)dst.fImage;
402    size_t dstRB = dst.fRowBytes;
403    for (int y = 0; y < height; ++y) {
404        const uint8_t* srcP = src.getAddr8(0, y);
405        for (int x = 0; x < width; ++x) {
406            unsigned r = *srcP++;
407            unsigned g = *srcP++;
408            unsigned b = *srcP++;
409            unsigned a = SkMax32(SkMax32(r, g), b);
410            dstP[x] = SkPackARGB32(a, r, g, b);
411        }
412        dstP = (SkPMColor*)((char*)dstP + dstRB);
413    }
414}
415
416static void generateMask(const SkMask& mask, const SkPath& path) {
417    SkBitmap::Config config;
418    SkPaint     paint;
419
420    int srcW = mask.fBounds.width();
421    int srcH = mask.fBounds.height();
422    int dstW = srcW;
423    int dstH = srcH;
424    int dstRB = mask.fRowBytes;
425
426    SkMatrix matrix;
427    matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
428                        -SkIntToScalar(mask.fBounds.fTop));
429
430    if (SkMask::kBW_Format == mask.fFormat) {
431        config = SkBitmap::kA1_Config;
432        paint.setAntiAlias(false);
433    } else {
434        config = SkBitmap::kA8_Config;
435        paint.setAntiAlias(true);
436        switch (mask.fFormat) {
437            case SkMask::kA8_Format:
438                break;
439            case SkMask::kLCD16_Format:
440            case SkMask::kLCD32_Format:
441                // TODO: trigger off LCD orientation
442                dstW *= 3;
443                matrix.postScale(SkIntToScalar(3), SK_Scalar1);
444                dstRB = 0;  // signals we need a copy
445                break;
446            default:
447                SkASSERT(!"unexpected mask format");
448        }
449    }
450
451    SkRasterClip clip;
452    clip.setRect(SkIRect::MakeWH(dstW, dstH));
453
454    SkBitmap bm;
455    bm.setConfig(config, dstW, dstH, dstRB);
456
457    if (0 == dstRB) {
458        bm.allocPixels();
459        bm.lockPixels();
460    } else {
461        bm.setPixels(mask.fImage);
462    }
463    sk_bzero(bm.getPixels(), bm.getSafeSize());
464
465    SkDraw  draw;
466    sk_bzero(&draw, sizeof(draw));
467    draw.fRC    = &clip;
468    draw.fClip  = &clip.bwRgn();
469    draw.fMatrix = &matrix;
470    draw.fBitmap = &bm;
471    draw.drawPath(path, paint);
472
473    if (0 == dstRB) {
474        switch (mask.fFormat) {
475            case SkMask::kLCD16_Format:
476                pack3xHToLCD16(bm, mask);
477                break;
478            case SkMask::kLCD32_Format:
479                pack3xHToLCD32(bm, mask);
480                break;
481            default:
482                SkASSERT(!"bad format for copyback");
483        }
484    }
485}
486
487void SkScalerContext::getImage(const SkGlyph& origGlyph) {
488    const SkGlyph*  glyph = &origGlyph;
489    SkGlyph         tmpGlyph;
490
491    if (fMaskFilter) {   // restore the prefilter bounds
492        tmpGlyph.init(origGlyph.fID);
493
494        // need the original bounds, sans our maskfilter
495        SkMaskFilter* mf = fMaskFilter;
496        fMaskFilter = NULL;             // temp disable
497        this->getMetrics(&tmpGlyph);
498        fMaskFilter = mf;               // restore
499
500        tmpGlyph.fImage = origGlyph.fImage;
501
502        // we need the prefilter bounds to be <= filter bounds
503        SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth);
504        SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight);
505        glyph = &tmpGlyph;
506    }
507
508    if (fGenerateImageFromPath) {
509        SkPath      devPath, fillPath;
510        SkMatrix    fillToDevMatrix;
511        SkMask      mask;
512
513        this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
514        glyph->toMask(&mask);
515
516        if (fRasterizer) {
517            mask.fFormat = SkMask::kA8_Format;
518            sk_bzero(glyph->fImage, mask.computeImageSize());
519
520            if (!fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
521                                        fMaskFilter, &mask,
522                                        SkMask::kJustRenderImage_CreateMode)) {
523                return;
524            }
525        } else {
526            generateMask(mask, devPath);
527        }
528    } else {
529        this->getGlyphContext(*glyph)->generateImage(*glyph);
530    }
531
532    if (fMaskFilter) {
533        SkMask      srcM, dstM;
534        SkMatrix    matrix;
535
536        // the src glyph image shouldn't be 3D
537        SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat);
538        glyph->toMask(&srcM);
539        fRec.getMatrixFrom2x2(&matrix);
540
541        if (fMaskFilter->filterMask(&dstM, srcM, matrix, NULL)) {
542            int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width());
543            int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height());
544            int dstRB = origGlyph.rowBytes();
545            int srcRB = dstM.fRowBytes;
546
547            const uint8_t* src = (const uint8_t*)dstM.fImage;
548            uint8_t* dst = (uint8_t*)origGlyph.fImage;
549
550            if (SkMask::k3D_Format == dstM.fFormat) {
551                // we have to copy 3 times as much
552                height *= 3;
553            }
554
555            // clean out our glyph, since it may be larger than dstM
556            //sk_bzero(dst, height * dstRB);
557
558            while (--height >= 0) {
559                memcpy(dst, src, width);
560                src += srcRB;
561                dst += dstRB;
562            }
563            SkMask::FreeImage(dstM.fImage);
564        }
565    }
566
567    // check to see if we should filter the alpha channel
568
569    if (NULL == fMaskFilter &&
570        fRec.fMaskFormat != SkMask::kBW_Format &&
571        fRec.fMaskFormat != SkMask::kLCD16_Format &&
572        fRec.fMaskFormat != SkMask::kLCD32_Format &&
573        (fRec.fFlags & (kGammaForBlack_Flag | kGammaForWhite_Flag)) != 0)
574    {
575        const uint8_t* table = (fRec.fFlags & kGammaForBlack_Flag) ? gBlackGammaTable : gWhiteGammaTable;
576        if (NULL != table) {
577            uint8_t* dst = (uint8_t*)origGlyph.fImage;
578            unsigned rowBytes = origGlyph.rowBytes();
579
580            for (int y = origGlyph.fHeight - 1; y >= 0; --y) {
581                for (int x = origGlyph.fWidth - 1; x >= 0; --x) {
582                    dst[x] = table[dst[x]];
583                }
584                dst += rowBytes;
585            }
586        }
587    }
588}
589
590void SkScalerContext::getPath(const SkGlyph& glyph, SkPath* path) {
591    this->internalGetPath(glyph, NULL, path, NULL);
592}
593
594void SkScalerContext::getFontMetrics(SkPaint::FontMetrics* mx,
595                                     SkPaint::FontMetrics* my) {
596    this->generateFontMetrics(mx, my);
597}
598
599SkUnichar SkScalerContext::generateGlyphToChar(uint16_t glyph) {
600    return 0;
601}
602
603///////////////////////////////////////////////////////////////////////////////
604
605void SkScalerContext::internalGetPath(const SkGlyph& glyph, SkPath* fillPath,
606                                  SkPath* devPath, SkMatrix* fillToDevMatrix) {
607    SkPath  path;
608
609    this->getGlyphContext(glyph)->generatePath(glyph, &path);
610
611    if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
612        SkFixed dx = glyph.getSubXFixed();
613        SkFixed dy = glyph.getSubYFixed();
614        if (dx | dy) {
615            path.offset(SkFixedToScalar(dx), SkFixedToScalar(dy));
616        }
617    }
618
619    if (fRec.fFrameWidth > 0 || fPathEffect != NULL) {
620        // need the path in user-space, with only the point-size applied
621        // so that our stroking and effects will operate the same way they
622        // would if the user had extracted the path themself, and then
623        // called drawPath
624        SkPath      localPath;
625        SkMatrix    matrix, inverse;
626
627        fRec.getMatrixFrom2x2(&matrix);
628        matrix.invert(&inverse);
629        path.transform(inverse, &localPath);
630        // now localPath is only affected by the paint settings, and not the canvas matrix
631
632        SkScalar width = fRec.fFrameWidth;
633
634        if (fPathEffect) {
635            SkPath effectPath;
636
637            if (fPathEffect->filterPath(&effectPath, localPath, &width)) {
638                localPath.swap(effectPath);
639            }
640        }
641
642        if (width > 0) {
643            SkStroke    stroker;
644            SkPath      outline;
645
646            stroker.setWidth(width);
647            stroker.setMiterLimit(fRec.fMiterLimit);
648            stroker.setJoin((SkPaint::Join)fRec.fStrokeJoin);
649            stroker.setDoFill(SkToBool(fRec.fFlags & kFrameAndFill_Flag));
650            stroker.strokePath(localPath, &outline);
651            localPath.swap(outline);
652        }
653
654        // now return stuff to the caller
655        if (fillToDevMatrix) {
656            *fillToDevMatrix = matrix;
657        }
658        if (devPath) {
659            localPath.transform(matrix, devPath);
660        }
661        if (fillPath) {
662            fillPath->swap(localPath);
663        }
664    } else {   // nothing tricky to do
665        if (fillToDevMatrix) {
666            fillToDevMatrix->reset();
667        }
668        if (devPath) {
669            if (fillPath == NULL) {
670                devPath->swap(path);
671            } else {
672                *devPath = path;
673            }
674        }
675
676        if (fillPath) {
677            fillPath->swap(path);
678        }
679    }
680
681    if (devPath) {
682        devPath->updateBoundsCache();
683    }
684    if (fillPath) {
685        fillPath->updateBoundsCache();
686    }
687}
688
689
690void SkScalerContext::Rec::getMatrixFrom2x2(SkMatrix* dst) const {
691    dst->reset();
692    dst->setScaleX(fPost2x2[0][0]);
693    dst->setSkewX( fPost2x2[0][1]);
694    dst->setSkewY( fPost2x2[1][0]);
695    dst->setScaleY(fPost2x2[1][1]);
696}
697
698void SkScalerContext::Rec::getLocalMatrix(SkMatrix* m) const {
699    m->setScale(SkScalarMul(fTextSize, fPreScaleX), fTextSize);
700    if (fPreSkewX) {
701        m->postSkew(fPreSkewX, 0);
702    }
703}
704
705void SkScalerContext::Rec::getSingleMatrix(SkMatrix* m) const {
706    this->getLocalMatrix(m);
707
708    //  now concat the device matrix
709    SkMatrix    deviceMatrix;
710    this->getMatrixFrom2x2(&deviceMatrix);
711    m->postConcat(deviceMatrix);
712}
713
714SkAxisAlignment SkComputeAxisAlignmentForHText(const SkMatrix& matrix) {
715    SkASSERT(!matrix.hasPerspective());
716
717    if (0 == matrix[SkMatrix::kMSkewY]) {
718        return kX_SkAxisAlignment;
719    }
720    if (0 == matrix[SkMatrix::kMScaleX]) {
721        return kY_SkAxisAlignment;
722    }
723    return kNone_SkAxisAlignment;
724}
725
726///////////////////////////////////////////////////////////////////////////////
727
728#include "SkFontHost.h"
729
730class SkScalerContext_Empty : public SkScalerContext {
731public:
732    SkScalerContext_Empty(const SkDescriptor* desc) : SkScalerContext(desc) {}
733
734protected:
735    virtual unsigned generateGlyphCount() {
736        return 0;
737    }
738    virtual uint16_t generateCharToGlyph(SkUnichar uni) {
739        return 0;
740    }
741    virtual void generateAdvance(SkGlyph* glyph) {
742        glyph->zeroMetrics();
743    }
744    virtual void generateMetrics(SkGlyph* glyph) {
745        glyph->zeroMetrics();
746    }
747    virtual void generateImage(const SkGlyph& glyph) {}
748    virtual void generatePath(const SkGlyph& glyph, SkPath* path) {}
749    virtual void generateFontMetrics(SkPaint::FontMetrics* mx,
750                                     SkPaint::FontMetrics* my) {
751        if (mx) {
752            sk_bzero(mx, sizeof(*mx));
753        }
754        if (my) {
755            sk_bzero(my, sizeof(*my));
756        }
757    }
758};
759
760extern SkScalerContext* SkCreateColorScalerContext(const SkDescriptor* desc);
761
762SkScalerContext* SkScalerContext::Create(const SkDescriptor* desc) {
763	SkScalerContext* c = NULL;  //SkCreateColorScalerContext(desc);
764	if (NULL == c) {
765		c = SkFontHost::CreateScalerContext(desc);
766	}
767    if (NULL == c) {
768        c = SkNEW_ARGS(SkScalerContext_Empty, (desc));
769    }
770    return c;
771}
772
773