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