SkDraw.cpp revision 338029608024c1c735e4d351aec7ed3319c5f0b4
1/* libs/graphics/sgl/SkDraw.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include "SkDraw.h"
19#include "SkBlitter.h"
20#include "SkBounder.h"
21#include "SkCanvas.h"
22#include "SkColorPriv.h"
23#include "SkDevice.h"
24#include "SkMaskFilter.h"
25#include "SkPaint.h"
26#include "SkPathEffect.h"
27#include "SkRasterizer.h"
28#include "SkScan.h"
29#include "SkShader.h"
30#include "SkStroke.h"
31#include "SkTemplatesPriv.h"
32#include "SkTextFormatParams.h"
33#include "SkUtils.h"
34
35#include "SkAutoKern.h"
36#include "SkBitmapProcShader.h"
37#include "SkDrawProcs.h"
38
39//#define TRACE_BITMAP_DRAWS
40
41class SkAutoRestoreBounder : SkNoncopyable {
42public:
43    // note: initializing fBounder is done only to fix a warning
44    SkAutoRestoreBounder() : fDraw(NULL), fBounder(NULL) {}
45    ~SkAutoRestoreBounder() {
46        if (fDraw) {
47            fDraw->fBounder = fBounder;
48        }
49    }
50
51    void clearBounder(const SkDraw* draw) {
52        fDraw = const_cast<SkDraw*>(draw);
53        fBounder = draw->fBounder;
54        fDraw->fBounder = NULL;
55    }
56
57private:
58    SkDraw*     fDraw;
59    SkBounder*  fBounder;
60};
61
62static SkPoint* rect_points(SkRect& r, int index) {
63    SkASSERT((unsigned)index < 2);
64    return &((SkPoint*)(void*)&r)[index];
65}
66
67/** Helper for allocating small blitters on the stack.
68*/
69
70#define kBlitterStorageLongCount    (sizeof(SkBitmapProcShader) >> 2)
71
72class SkAutoBlitterChoose {
73public:
74    SkAutoBlitterChoose(const SkBitmap& device, const SkMatrix& matrix,
75                        const SkPaint& paint) {
76        fBlitter = SkBlitter::Choose(device, matrix, paint,
77                                     fStorage, sizeof(fStorage));
78    }
79
80    ~SkAutoBlitterChoose();
81
82    SkBlitter*  operator->() { return fBlitter; }
83    SkBlitter*  get() const { return fBlitter; }
84
85private:
86    SkBlitter*  fBlitter;
87    uint32_t    fStorage[kBlitterStorageLongCount];
88};
89
90SkAutoBlitterChoose::~SkAutoBlitterChoose() {
91    if ((void*)fBlitter == (void*)fStorage) {
92        fBlitter->~SkBlitter();
93    } else {
94        SkDELETE(fBlitter);
95    }
96}
97
98class SkAutoBitmapShaderInstall {
99public:
100    SkAutoBitmapShaderInstall(const SkBitmap& src, const SkPaint* paint)
101            : fPaint((SkPaint*)paint) {
102        fPrevShader = paint->getShader();
103        SkSafeRef(fPrevShader);
104        fPaint->setShader(SkShader::CreateBitmapShader( src,
105                           SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
106                           fStorage, sizeof(fStorage)));
107    }
108
109    ~SkAutoBitmapShaderInstall() {
110        SkShader* shader = fPaint->getShader();
111
112        fPaint->setShader(fPrevShader);
113        SkSafeUnref(fPrevShader);
114
115        if ((void*)shader == (void*)fStorage) {
116            shader->~SkShader();
117        } else {
118            SkDELETE(shader);
119        }
120    }
121
122private:
123    SkPaint*    fPaint;
124    SkShader*   fPrevShader;
125    uint32_t    fStorage[kBlitterStorageLongCount];
126};
127
128class SkAutoPaintStyleRestore {
129public:
130    SkAutoPaintStyleRestore(const SkPaint& paint, SkPaint::Style style)
131            : fPaint((SkPaint&)paint) {
132        fStyle = paint.getStyle();  // record the old
133        fPaint.setStyle(style);     // change it to the specified style
134    }
135
136    ~SkAutoPaintStyleRestore() {
137        fPaint.setStyle(fStyle);    // restore the old
138    }
139
140private:
141    SkPaint&        fPaint;
142    SkPaint::Style  fStyle;
143
144    // illegal
145    SkAutoPaintStyleRestore(const SkAutoPaintStyleRestore&);
146    SkAutoPaintStyleRestore& operator=(const SkAutoPaintStyleRestore&);
147};
148
149///////////////////////////////////////////////////////////////////////////////
150
151SkDraw::SkDraw() {
152    sk_bzero(this, sizeof(*this));
153}
154
155SkDraw::SkDraw(const SkDraw& src) {
156    memcpy(this, &src, sizeof(*this));
157}
158
159///////////////////////////////////////////////////////////////////////////////
160
161typedef void (*BitmapXferProc)(void* pixels, size_t bytes, uint32_t data);
162
163static void D_Clear_BitmapXferProc(void* pixels, size_t bytes, uint32_t) {
164    sk_bzero(pixels, bytes);
165}
166
167static void D_Dst_BitmapXferProc(void*, size_t, uint32_t data) {}
168
169static void D32_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
170    sk_memset32((uint32_t*)pixels, data, bytes >> 2);
171}
172
173static void D16_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
174    sk_memset16((uint16_t*)pixels, data, bytes >> 1);
175}
176
177static void DA8_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
178    memset(pixels, data, bytes);
179}
180
181static BitmapXferProc ChooseBitmapXferProc(const SkBitmap& bitmap,
182                                           const SkPaint& paint,
183                                           uint32_t* data) {
184    // todo: we can apply colorfilter up front if no shader, so we wouldn't
185    // need to abort this fastpath
186    if (paint.getShader() || paint.getColorFilter()) {
187        return NULL;
188    }
189
190    SkXfermode::Mode mode;
191    if (!SkXfermode::IsMode(paint.getXfermode(), &mode)) {
192        return NULL;
193    }
194
195    SkColor color = paint.getColor();
196
197    // collaps modes based on color...
198    if (SkXfermode::kSrcOver_Mode == mode) {
199        unsigned alpha = SkColorGetA(color);
200        if (0 == alpha) {
201            mode = SkXfermode::kDst_Mode;
202        } else if (0xFF == alpha) {
203            mode = SkXfermode::kSrc_Mode;
204        }
205    }
206
207    switch (mode) {
208        case SkXfermode::kClear_Mode:
209//            SkDebugf("--- D_Clear_BitmapXferProc\n");
210            return D_Clear_BitmapXferProc;  // ignore data
211        case SkXfermode::kDst_Mode:
212//            SkDebugf("--- D_Dst_BitmapXferProc\n");
213            return D_Dst_BitmapXferProc;    // ignore data
214        case SkXfermode::kSrc_Mode: {
215            /*
216                should I worry about dithering for the lower depths?
217            */
218            SkPMColor pmc = SkPreMultiplyColor(color);
219            switch (bitmap.config()) {
220                case SkBitmap::kARGB_8888_Config:
221                    if (data) {
222                        *data = pmc;
223                    }
224//                    SkDebugf("--- D32_Src_BitmapXferProc\n");
225                    return D32_Src_BitmapXferProc;
226                case SkBitmap::kARGB_4444_Config:
227                    if (data) {
228                        *data = SkPixel32ToPixel4444(pmc);
229                    }
230//                    SkDebugf("--- D16_Src_BitmapXferProc\n");
231                    return D16_Src_BitmapXferProc;
232                case SkBitmap::kRGB_565_Config:
233                    if (data) {
234                        *data = SkPixel32ToPixel16(pmc);
235                    }
236//                    SkDebugf("--- D16_Src_BitmapXferProc\n");
237                    return D16_Src_BitmapXferProc;
238                case SkBitmap::kA8_Config:
239                    if (data) {
240                        *data = SkGetPackedA32(pmc);
241                    }
242//                    SkDebugf("--- DA8_Src_BitmapXferProc\n");
243                    return DA8_Src_BitmapXferProc;
244                default:
245                    break;
246            }
247            break;
248        }
249        default:
250            break;
251    }
252    return NULL;
253}
254
255static void CallBitmapXferProc(const SkBitmap& bitmap, const SkIRect& rect,
256                               BitmapXferProc proc, uint32_t procData) {
257    int shiftPerPixel;
258    switch (bitmap.config()) {
259        case SkBitmap::kARGB_8888_Config:
260            shiftPerPixel = 2;
261            break;
262        case SkBitmap::kARGB_4444_Config:
263        case SkBitmap::kRGB_565_Config:
264            shiftPerPixel = 1;
265            break;
266        case SkBitmap::kA8_Config:
267            shiftPerPixel = 0;
268            break;
269        default:
270            SkASSERT(!"Can't use xferproc on this config");
271            return;
272    }
273
274    uint8_t* pixels = (uint8_t*)bitmap.getPixels();
275    SkASSERT(pixels);
276    const size_t rowBytes = bitmap.rowBytes();
277    const int widthBytes = rect.width() << shiftPerPixel;
278
279    // skip down to the first scanline and X position
280    pixels += rect.fTop * rowBytes + (rect.fLeft << shiftPerPixel);
281    for (int scans = rect.height() - 1; scans >= 0; --scans) {
282        proc(pixels, widthBytes, procData);
283        pixels += rowBytes;
284    }
285}
286
287void SkDraw::drawPaint(const SkPaint& paint) const {
288    SkDEBUGCODE(this->validate();)
289
290    if (fClip->isEmpty()) {
291        return;
292    }
293
294    SkIRect    devRect;
295    devRect.set(0, 0, fBitmap->width(), fBitmap->height());
296    if (fBounder && !fBounder->doIRect(devRect)) {
297        return;
298    }
299
300    /*  If we don't have a shader (i.e. we're just a solid color) we may
301        be faster to operate directly on the device bitmap, rather than invoking
302        a blitter. Esp. true for xfermodes, which require a colorshader to be
303        present, which is just redundant work. Since we're drawing everywhere
304        in the clip, we don't have to worry about antialiasing.
305    */
306    uint32_t procData = 0;  // to avoid the warning
307    BitmapXferProc proc = ChooseBitmapXferProc(*fBitmap, paint, &procData);
308    if (proc) {
309        if (D_Dst_BitmapXferProc == proc) { // nothing to do
310            return;
311        }
312
313        SkRegion::Iterator iter(*fClip);
314        while (!iter.done()) {
315            CallBitmapXferProc(*fBitmap, iter.rect(), proc, procData);
316            iter.next();
317        }
318    } else {
319        // normal case: use a blitter
320        SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
321        SkScan::FillIRect(devRect, fClip, blitter.get());
322    }
323}
324
325///////////////////////////////////////////////////////////////////////////////
326
327struct PtProcRec {
328    SkCanvas::PointMode fMode;
329    const SkPaint*  fPaint;
330    const SkRegion* fClip;
331
332    // computed values
333    SkFixed fRadius;
334
335    typedef void (*Proc)(const PtProcRec&, const SkPoint devPts[], int count,
336                         SkBlitter*);
337
338    bool init(SkCanvas::PointMode, const SkPaint&, const SkMatrix* matrix,
339              const SkRegion* clip);
340    Proc chooseProc(SkBlitter* blitter);
341};
342
343static void bw_pt_rect_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
344                                 int count, SkBlitter* blitter) {
345    SkASSERT(rec.fClip->isRect());
346    const SkIRect& r = rec.fClip->getBounds();
347
348    for (int i = 0; i < count; i++) {
349        int x = SkScalarFloor(devPts[i].fX);
350        int y = SkScalarFloor(devPts[i].fY);
351        if (r.contains(x, y)) {
352            blitter->blitH(x, y, 1);
353        }
354    }
355}
356
357static void bw_pt_rect_16_hair_proc(const PtProcRec& rec,
358                                    const SkPoint devPts[], int count,
359                                    SkBlitter* blitter) {
360    SkASSERT(rec.fClip->isRect());
361    const SkIRect& r = rec.fClip->getBounds();
362    uint32_t value;
363    const SkBitmap* bitmap = blitter->justAnOpaqueColor(&value);
364    SkASSERT(bitmap);
365
366    uint16_t* addr = bitmap->getAddr16(0, 0);
367    int rb = bitmap->rowBytes();
368
369    for (int i = 0; i < count; i++) {
370        int x = SkScalarFloor(devPts[i].fX);
371        int y = SkScalarFloor(devPts[i].fY);
372        if (r.contains(x, y)) {
373//            *bitmap->getAddr16(x, y) = SkToU16(value);
374            ((uint16_t*)((char*)addr + y * rb))[x] = SkToU16(value);
375        }
376    }
377}
378
379static void bw_pt_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
380                            int count, SkBlitter* blitter) {
381    for (int i = 0; i < count; i++) {
382        int x = SkScalarFloor(devPts[i].fX);
383        int y = SkScalarFloor(devPts[i].fY);
384        if (rec.fClip->contains(x, y)) {
385            blitter->blitH(x, y, 1);
386        }
387    }
388}
389
390static void bw_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
391                              int count, SkBlitter* blitter) {
392    for (int i = 0; i < count; i += 2) {
393        SkScan::HairLine(devPts[i], devPts[i+1], rec.fClip, blitter);
394    }
395}
396
397static void bw_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
398                              int count, SkBlitter* blitter) {
399    for (int i = 0; i < count - 1; i++) {
400        SkScan::HairLine(devPts[i], devPts[i+1], rec.fClip, blitter);
401    }
402}
403
404// aa versions
405
406static void aa_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
407                              int count, SkBlitter* blitter) {
408    for (int i = 0; i < count; i += 2) {
409        SkScan::AntiHairLine(devPts[i], devPts[i+1], rec.fClip, blitter);
410    }
411}
412
413static void aa_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
414                              int count, SkBlitter* blitter) {
415    for (int i = 0; i < count - 1; i++) {
416        SkScan::AntiHairLine(devPts[i], devPts[i+1], rec.fClip, blitter);
417    }
418}
419
420// square procs (strokeWidth > 0 but matrix is square-scale (sx == sy)
421
422static void bw_square_proc(const PtProcRec& rec, const SkPoint devPts[],
423                           int count, SkBlitter* blitter) {
424    const SkFixed radius = rec.fRadius;
425    for (int i = 0; i < count; i++) {
426        SkFixed x = SkScalarToFixed(devPts[i].fX);
427        SkFixed y = SkScalarToFixed(devPts[i].fY);
428
429        SkXRect r;
430        r.fLeft = x - radius;
431        r.fTop = y - radius;
432        r.fRight = x + radius;
433        r.fBottom = y + radius;
434
435        SkScan::FillXRect(r, rec.fClip, blitter);
436    }
437}
438
439static void aa_square_proc(const PtProcRec& rec, const SkPoint devPts[],
440                           int count, SkBlitter* blitter) {
441    const SkFixed radius = rec.fRadius;
442    for (int i = 0; i < count; i++) {
443        SkFixed x = SkScalarToFixed(devPts[i].fX);
444        SkFixed y = SkScalarToFixed(devPts[i].fY);
445
446        SkXRect r;
447        r.fLeft = x - radius;
448        r.fTop = y - radius;
449        r.fRight = x + radius;
450        r.fBottom = y + radius;
451
452        SkScan::AntiFillXRect(r, rec.fClip, blitter);
453    }
454}
455
456// If this guy returns true, then chooseProc() must return a valid proc
457bool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint,
458                     const SkMatrix* matrix, const SkRegion* clip) {
459    if (paint.getPathEffect()) {
460        return false;
461    }
462    SkScalar width = paint.getStrokeWidth();
463    if (0 == width) {
464        fMode = mode;
465        fPaint = &paint;
466        fClip = clip;
467        fRadius = SK_Fixed1 >> 1;
468        return true;
469    }
470    if (paint.getStrokeCap() != SkPaint::kRound_Cap &&
471            matrix->rectStaysRect() && SkCanvas::kPoints_PointMode == mode) {
472        SkScalar sx = matrix->get(SkMatrix::kMScaleX);
473        SkScalar sy = matrix->get(SkMatrix::kMScaleY);
474        if (SkScalarNearlyZero(sx - sy)) {
475            if (sx < 0) {
476                sx = -sx;
477            }
478
479            fMode = mode;
480            fPaint = &paint;
481            fClip = clip;
482            fRadius = SkScalarToFixed(SkScalarMul(width, sx)) >> 1;
483            return true;
484        }
485    }
486    return false;
487}
488
489PtProcRec::Proc PtProcRec::chooseProc(SkBlitter* blitter) {
490    Proc proc = NULL;
491
492    // for our arrays
493    SkASSERT(0 == SkCanvas::kPoints_PointMode);
494    SkASSERT(1 == SkCanvas::kLines_PointMode);
495    SkASSERT(2 == SkCanvas::kPolygon_PointMode);
496    SkASSERT((unsigned)fMode <= (unsigned)SkCanvas::kPolygon_PointMode);
497
498    // first check for hairlines
499    if (0 == fPaint->getStrokeWidth()) {
500        if (fPaint->isAntiAlias()) {
501            static const Proc gAAProcs[] = {
502                aa_square_proc, aa_line_hair_proc, aa_poly_hair_proc
503            };
504            proc = gAAProcs[fMode];
505        } else {
506            if (SkCanvas::kPoints_PointMode == fMode && fClip->isRect()) {
507                uint32_t value;
508                const SkBitmap* bm = blitter->justAnOpaqueColor(&value);
509                if (bm && bm->config() == SkBitmap::kRGB_565_Config) {
510                    proc = bw_pt_rect_16_hair_proc;
511                } else {
512                    proc = bw_pt_rect_hair_proc;
513                }
514            } else {
515                static Proc gBWProcs[] = {
516                    bw_pt_hair_proc, bw_line_hair_proc, bw_poly_hair_proc
517                };
518                proc = gBWProcs[fMode];
519            }
520        }
521    } else if (fPaint->getStrokeCap() != SkPaint::kRound_Cap) {
522        SkASSERT(SkCanvas::kPoints_PointMode == fMode);
523        if (fPaint->isAntiAlias()) {
524            proc = aa_square_proc;
525        } else {
526            proc = bw_square_proc;
527        }
528    }
529    return proc;
530}
531
532static bool bounder_points(SkBounder* bounder, SkCanvas::PointMode mode,
533                           size_t count, const SkPoint pts[],
534                           const SkPaint& paint, const SkMatrix& matrix) {
535    SkIRect ibounds;
536    SkRect bounds;
537    SkScalar inset = paint.getStrokeWidth();
538
539    bounds.set(pts, count);
540    bounds.inset(-inset, -inset);
541    matrix.mapRect(&bounds);
542
543    bounds.roundOut(&ibounds);
544    return bounder->doIRect(ibounds);
545}
546
547// each of these costs 8-bytes of stack space, so don't make it too large
548// must be even for lines/polygon to work
549#define MAX_DEV_PTS     32
550
551void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count,
552                        const SkPoint pts[], const SkPaint& paint,
553                        bool forceUseDevice) const {
554    // if we're in lines mode, force count to be even
555    if (SkCanvas::kLines_PointMode == mode) {
556        count &= ~(size_t)1;
557    }
558
559    if ((long)count <= 0) {
560        return;
561    }
562
563    SkAutoRestoreBounder arb;
564
565    if (fBounder) {
566        if (!bounder_points(fBounder, mode, count, pts, paint, *fMatrix)) {
567            return;
568        }
569        // clear the bounder for the rest of this function, so we don't call it
570        // again later if we happen to call ourselves for drawRect, drawPath,
571        // etc.
572        arb.clearBounder(this);
573    }
574
575    SkASSERT(pts != NULL);
576    SkDEBUGCODE(this->validate();)
577
578     // nothing to draw
579    if (fClip->isEmpty() ||
580        (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
581        return;
582    }
583
584    PtProcRec rec;
585    if (!forceUseDevice && rec.init(mode, paint, fMatrix, fClip)) {
586        SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
587
588        SkPoint             devPts[MAX_DEV_PTS];
589        const SkMatrix*     matrix = fMatrix;
590        SkBlitter*          bltr = blitter.get();
591        PtProcRec::Proc     proc = rec.chooseProc(bltr);
592        // we have to back up subsequent passes if we're in polygon mode
593        const size_t backup = (SkCanvas::kPolygon_PointMode == mode);
594
595        do {
596            size_t n = count;
597            if (n > MAX_DEV_PTS) {
598                n = MAX_DEV_PTS;
599            }
600            matrix->mapPoints(devPts, pts, n);
601            proc(rec, devPts, n, bltr);
602            pts += n - backup;
603            SkASSERT(count >= n);
604            count -= n;
605            if (count > 0) {
606                count += backup;
607            }
608        } while (count != 0);
609    } else {
610        switch (mode) {
611            case SkCanvas::kPoints_PointMode: {
612                // temporarily mark the paint as filling.
613                SkAutoPaintStyleRestore restore(paint, SkPaint::kFill_Style);
614
615                SkScalar width = paint.getStrokeWidth();
616                SkScalar radius = SkScalarHalf(width);
617
618                if (paint.getStrokeCap() == SkPaint::kRound_Cap) {
619                    SkPath      path;
620                    SkMatrix    preMatrix;
621
622                    path.addCircle(0, 0, radius);
623                    for (size_t i = 0; i < count; i++) {
624                        preMatrix.setTranslate(pts[i].fX, pts[i].fY);
625                        // pass true for the last point, since we can modify
626                        // then path then
627                        if (fDevice) {
628                            fDevice->drawPath(*this, path, paint, &preMatrix,
629                                              (count-1) == i);
630                        } else {
631                            this->drawPath(path, paint, &preMatrix, (count-1) == i);
632                        }
633                    }
634                } else {
635                    SkRect  r;
636
637                    for (size_t i = 0; i < count; i++) {
638                        r.fLeft = pts[i].fX - radius;
639                        r.fTop = pts[i].fY - radius;
640                        r.fRight = r.fLeft + width;
641                        r.fBottom = r.fTop + width;
642                        if (fDevice) {
643                            fDevice->drawRect(*this, r, paint);
644                        } else {
645                            this->drawRect(r, paint);
646                        }
647                    }
648                }
649                break;
650            }
651            case SkCanvas::kLines_PointMode:
652            case SkCanvas::kPolygon_PointMode: {
653                count -= 1;
654                SkPath path;
655                SkPaint p(paint);
656                p.setStyle(SkPaint::kStroke_Style);
657                size_t inc = (SkCanvas::kLines_PointMode == mode) ? 2 : 1;
658                for (size_t i = 0; i < count; i += inc) {
659                    path.moveTo(pts[i]);
660                    path.lineTo(pts[i+1]);
661                    if (fDevice) {
662                        fDevice->drawPath(*this, path, p, NULL, true);
663                    } else {
664                        this->drawPath(path, p, NULL, true);
665                    }
666                    path.rewind();
667                }
668                break;
669            }
670        }
671    }
672}
673
674static inline SkPoint* as_lefttop(SkRect* r) {
675    return (SkPoint*)(void*)r;
676}
677
678static inline SkPoint* as_rightbottom(SkRect* r) {
679    return ((SkPoint*)(void*)r) + 1;
680}
681
682static bool easy_rect_join(const SkPaint& paint) {
683#if 0
684    return SkPaint::kMiter_Join == paint.getStrokeJoin() &&
685           paint.getStrokeMiter() >= SK_ScalarSqrt2;
686#else
687    // return false until we handle non-square scaling in the matrix, where
688    // the horizontal and vertical widths may differ.
689    return false;
690#endif
691}
692
693enum RectType {
694    kHair_RectType,
695    kFill_RectType,
696    kStroke_RectType,
697    kPath_RectType
698};
699
700void SkDraw::drawRect(const SkRect& rect, const SkPaint& paint) const {
701    SkDEBUGCODE(this->validate();)
702
703    // nothing to draw
704    if (fClip->isEmpty() ||
705        (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
706        return;
707    }
708
709    RectType rtype;
710    const SkScalar width = paint.getStrokeWidth();
711    bool zeroWidth = (0 == width);
712    SkPaint::Style style = paint.getStyle();
713
714    if ((SkPaint::kStrokeAndFill_Style == style) && zeroWidth) {
715        style = SkPaint::kFill_Style;
716    }
717
718    if (paint.getPathEffect() || paint.getMaskFilter() ||
719        paint.getRasterizer() || !fMatrix->rectStaysRect() ||
720        SkPaint::kStrokeAndFill_Style == style) {
721            rtype = kPath_RectType;
722    } else if (SkPaint::kFill_Style == paint.getStyle()) {
723        rtype = kFill_RectType;
724    } else if (zeroWidth) {
725        rtype = kHair_RectType;
726    } else if (easy_rect_join(paint)) {
727#ifdef SK_DISABLE_FAST_AA_STROKE_RECT
728        if (paint.isAntiAlias()) {
729            rtype = kPath_RectType;
730        } else
731#endif
732        rtype = kStroke_RectType;
733    } else {
734        rtype = kPath_RectType;
735    }
736
737    if (kPath_RectType == rtype) {
738        SkPath  tmp;
739        tmp.addRect(rect);
740        tmp.setFillType(SkPath::kWinding_FillType);
741        this->drawPath(tmp, paint, NULL, true);
742        return;
743    }
744
745    const SkMatrix& matrix = *fMatrix;
746    SkRect          devRect;
747
748    // transform rect into devRect
749    {
750        matrix.mapXY(rect.fLeft, rect.fTop, rect_points(devRect, 0));
751        matrix.mapXY(rect.fRight, rect.fBottom, rect_points(devRect, 1));
752        devRect.sort();
753    }
754
755    if (fBounder && !fBounder->doRect(devRect, paint)) {
756        return;
757    }
758
759    // look for the quick exit, before we build a blitter
760    {
761        SkIRect ir;
762        devRect.roundOut(&ir);
763        if (paint.getStyle() != SkPaint::kFill_Style) {
764            // extra space for hairlines
765            ir.inset(-1, -1);
766        }
767        if (fClip->quickReject(ir))
768            return;
769    }
770
771    SkAutoBlitterChoose blitterStorage(*fBitmap, matrix, paint);
772    SkBlitter*          blitter = blitterStorage.get();
773    const SkRegion*     clip = fClip;
774
775    // we want to "fill" if we are kFill or kStrokeAndFill, since in the latter
776    // case we are also hairline (if we've gotten to here), which devolves to
777    // effectively just kFill
778    switch (rtype) {
779        case kFill_RectType:
780            if (paint.isAntiAlias()) {
781                SkScan::AntiFillRect(devRect, clip, blitter);
782            } else {
783                SkScan::FillRect(devRect, clip, blitter);
784            }
785            break;
786        case kStroke_RectType:
787            if (paint.isAntiAlias()) {
788                SkScan::AntiFrameRect(devRect, width, clip, blitter);
789            } else {
790                SkScan::FrameRect(devRect, width, clip, blitter);
791            }
792            break;
793        case kHair_RectType:
794            if (paint.isAntiAlias()) {
795                SkScan::AntiHairRect(devRect, clip, blitter);
796            } else {
797                SkScan::HairRect(devRect, clip, blitter);
798            }
799            break;
800        default:
801            SkASSERT(!"bad rtype");
802    }
803}
804
805void SkDraw::drawDevMask(const SkMask& srcM, const SkPaint& paint) const {
806    if (srcM.fBounds.isEmpty()) {
807        return;
808    }
809
810    SkMask          dstM;
811    const SkMask*   mask = &srcM;
812
813    dstM.fImage = NULL;
814    SkAutoMaskImage ami(&dstM, false);
815
816    if (paint.getMaskFilter() &&
817            paint.getMaskFilter()->filterMask(&dstM, srcM, *fMatrix, NULL)) {
818        mask = &dstM;
819    }
820
821    if (fBounder && !fBounder->doIRect(mask->fBounds)) {
822        return;
823    }
824
825    SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
826
827    blitter->blitMaskRegion(*mask, *fClip);
828}
829
830class SkAutoPaintRestoreColorStrokeWidth {
831public:
832    SkAutoPaintRestoreColorStrokeWidth(const SkPaint& paint) {
833        fPaint = (SkPaint*)&paint;
834        fColor = paint.getColor();
835        fWidth = paint.getStrokeWidth();
836    }
837    ~SkAutoPaintRestoreColorStrokeWidth() {
838        fPaint->setColor(fColor);
839        fPaint->setStrokeWidth(fWidth);
840    }
841
842private:
843    SkPaint*    fPaint;
844    SkColor     fColor;
845    SkScalar    fWidth;
846};
847
848static SkScalar fast_len(const SkVector& vec) {
849    SkScalar x = SkScalarAbs(vec.fX);
850    SkScalar y = SkScalarAbs(vec.fY);
851    if (x < y) {
852        SkTSwap(x, y);
853    }
854    return x + SkScalarHalf(y);
855}
856
857// our idea is to return true if there is no appreciable skew or non-square scale
858// for that we'll transform (0,1) and (1,0), and check that the resulting dot-prod
859// is nearly one
860static bool map_radius(const SkMatrix& matrix, SkScalar* value) {
861    if (matrix.getType() & SkMatrix::kPerspective_Mask) {
862        return false;
863    }
864    SkVector src[2], dst[2];
865    src[0].set(*value, 0);
866    src[1].set(0, *value);
867    matrix.mapVectors(dst, src, 2);
868    SkScalar len0 = fast_len(dst[0]);
869    SkScalar len1 = fast_len(dst[1]);
870    if (len0 <= SK_Scalar1 && len1 <= SK_Scalar1) {
871        *value = SkScalarAve(len0, len1);
872        return true;
873    }
874    return false;
875}
876
877void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& paint,
878                      const SkMatrix* prePathMatrix, bool pathIsMutable) const {
879    SkDEBUGCODE(this->validate();)
880
881    // nothing to draw
882    if (fClip->isEmpty() ||
883        (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
884        return;
885    }
886
887    SkPath*         pathPtr = (SkPath*)&origSrcPath;
888    bool            doFill = true;
889    SkPath          tmpPath;
890    SkMatrix        tmpMatrix;
891    const SkMatrix* matrix = fMatrix;
892
893    if (prePathMatrix) {
894        if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style ||
895                paint.getRasterizer()) {
896            SkPath* result = pathPtr;
897
898            if (!pathIsMutable) {
899                result = &tmpPath;
900                pathIsMutable = true;
901            }
902            pathPtr->transform(*prePathMatrix, result);
903            pathPtr = result;
904        } else {
905            if (!tmpMatrix.setConcat(*matrix, *prePathMatrix)) {
906                // overflow
907                return;
908            }
909            matrix = &tmpMatrix;
910        }
911    }
912    // at this point we're done with prePathMatrix
913    SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
914
915    /*
916        If the device thickness < 1.0, then make it a hairline, and
917        modulate alpha if the thickness is even smaller (e.g. thickness == 0.5
918        should modulate the alpha by 1/2)
919    */
920
921    SkAutoPaintRestoreColorStrokeWidth aprc(paint);
922
923    // can we approximate a thin (but not hairline) stroke with an alpha-modulated
924    // hairline? Only if the matrix scales evenly in X and Y, and the device-width is
925    // less than a pixel
926    if (paint.isAntiAlias() &&
927        paint.getStyle() == SkPaint::kStroke_Style && paint.getXfermode() == NULL) {
928        SkScalar width = paint.getStrokeWidth();
929        if (width > 0 && map_radius(*matrix, &width)) {
930            int scale = (int)SkScalarMul(width, 256);
931            int alpha = paint.getAlpha() * scale >> 8;
932
933            // pretend to be a hairline, with a modulated alpha
934            ((SkPaint*)&paint)->setAlpha(alpha);
935            ((SkPaint*)&paint)->setStrokeWidth(0);
936        }
937    }
938
939    if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
940        doFill = paint.getFillPath(*pathPtr, &tmpPath);
941        pathPtr = &tmpPath;
942    }
943
944    if (paint.getRasterizer()) {
945        SkMask  mask;
946        if (paint.getRasterizer()->rasterize(*pathPtr, *matrix,
947                            &fClip->getBounds(), paint.getMaskFilter(), &mask,
948                            SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
949            this->drawDevMask(mask, paint);
950            SkMask::FreeImage(mask.fImage);
951        }
952        return;
953    }
954
955    // avoid possibly allocating a new path in transform if we can
956    SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
957
958    // transform the path into device space
959    pathPtr->transform(*matrix, devPathPtr);
960
961    SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
962
963    // how does filterPath() know to fill or hairline the path??? <mrr>
964    if (paint.getMaskFilter() &&
965            paint.getMaskFilter()->filterPath(*devPathPtr, *fMatrix, *fClip,
966                                              fBounder, blitter.get())) {
967        return; // filterPath() called the blitter, so we're done
968    }
969
970    if (fBounder && !fBounder->doPath(*devPathPtr, paint, doFill)) {
971        return;
972    }
973
974    if (doFill) {
975        if (paint.isAntiAlias()) {
976            SkScan::AntiFillPath(*devPathPtr, *fClip, blitter.get());
977        } else {
978            SkScan::FillPath(*devPathPtr, *fClip, blitter.get());
979        }
980    } else {    // hairline
981        if (paint.isAntiAlias()) {
982            SkScan::AntiHairPath(*devPathPtr, fClip, blitter.get());
983        } else {
984            SkScan::HairPath(*devPathPtr, fClip, blitter.get());
985        }
986    }
987}
988
989/** For the purposes of drawing bitmaps, if a matrix is "almost" translate
990    go ahead and treat it as if it were, so that subsequent code can go fast.
991 */
992static bool just_translate(const SkMatrix& matrix, const SkBitmap& bitmap) {
993    SkMatrix::TypeMask mask = matrix.getType();
994
995    if (mask & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) {
996        return false;
997    }
998    if (mask & SkMatrix::kScale_Mask) {
999        SkScalar sx = matrix[SkMatrix::kMScaleX];
1000        SkScalar sy = matrix[SkMatrix::kMScaleY];
1001        int w = bitmap.width();
1002        int h = bitmap.height();
1003        int sw = SkScalarRound(SkScalarMul(sx, SkIntToScalar(w)));
1004        int sh = SkScalarRound(SkScalarMul(sy, SkIntToScalar(h)));
1005        return sw == w && sh == h;
1006    }
1007    // if we got here, we're either kTranslate_Mask or identity
1008    return true;
1009}
1010
1011void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap,
1012                              const SkPaint& paint) const {
1013    SkASSERT(bitmap.getConfig() == SkBitmap::kA8_Config);
1014
1015    if (just_translate(*fMatrix, bitmap)) {
1016        int ix = SkScalarRound(fMatrix->getTranslateX());
1017        int iy = SkScalarRound(fMatrix->getTranslateY());
1018
1019        SkMask  mask;
1020        mask.fBounds.set(ix, iy, ix + bitmap.width(), iy + bitmap.height());
1021        mask.fFormat = SkMask::kA8_Format;
1022        mask.fRowBytes = bitmap.rowBytes();
1023        mask.fImage = bitmap.getAddr8(0, 0);
1024
1025        this->drawDevMask(mask, paint);
1026    } else {    // need to xform the bitmap first
1027        SkRect  r;
1028        SkMask  mask;
1029
1030        r.set(0, 0,
1031              SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
1032        fMatrix->mapRect(&r);
1033        r.round(&mask.fBounds);
1034
1035        // set the mask's bounds to the transformed bitmap-bounds,
1036        // clipped to the actual device
1037        {
1038            SkIRect    devBounds;
1039            devBounds.set(0, 0, fBitmap->width(), fBitmap->height());
1040            // need intersect(l, t, r, b) on irect
1041            if (!mask.fBounds.intersect(devBounds)) {
1042                return;
1043            }
1044        }
1045
1046        mask.fFormat = SkMask::kA8_Format;
1047        mask.fRowBytes = SkAlign4(mask.fBounds.width());
1048        size_t size = mask.computeImageSize();
1049        if (0 == size) {
1050            // the mask is too big to allocated, draw nothing
1051            return;
1052        }
1053
1054        // allocate (and clear) our temp buffer to hold the transformed bitmap
1055        SkAutoMalloc    storage(size);
1056        mask.fImage = (uint8_t*)storage.get();
1057        memset(mask.fImage, 0, size);
1058
1059        // now draw our bitmap(src) into mask(dst), transformed by the matrix
1060        {
1061            SkBitmap    device;
1062            device.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(),
1063                             mask.fBounds.height(), mask.fRowBytes);
1064            device.setPixels(mask.fImage);
1065
1066            SkCanvas c(device);
1067            // need the unclipped top/left for the translate
1068            c.translate(-SkIntToScalar(mask.fBounds.fLeft),
1069                        -SkIntToScalar(mask.fBounds.fTop));
1070            c.concat(*fMatrix);
1071
1072            // We can't call drawBitmap, or we'll infinitely recurse. Instead
1073            // we manually build a shader and draw that into our new mask
1074            SkPaint tmpPaint;
1075            tmpPaint.setFlags(paint.getFlags());
1076            SkAutoBitmapShaderInstall   install(bitmap, &tmpPaint);
1077            SkRect rr;
1078            rr.set(0, 0, SkIntToScalar(bitmap.width()),
1079                   SkIntToScalar(bitmap.height()));
1080            c.drawRect(rr, tmpPaint);
1081        }
1082        this->drawDevMask(mask, paint);
1083    }
1084}
1085
1086static bool clipped_out(const SkMatrix& m, const SkRegion& c,
1087                        const SkRect& srcR) {
1088    SkRect  dstR;
1089    SkIRect devIR;
1090
1091    m.mapRect(&dstR, srcR);
1092    dstR.roundOut(&devIR);
1093    return c.quickReject(devIR);
1094}
1095
1096static bool clipped_out(const SkMatrix& matrix, const SkRegion& clip,
1097                        int width, int height) {
1098    SkRect  r;
1099    r.set(0, 0, SkIntToScalar(width), SkIntToScalar(height));
1100    return clipped_out(matrix, clip, r);
1101}
1102
1103void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix,
1104                        const SkPaint& paint) const {
1105    SkDEBUGCODE(this->validate();)
1106
1107    // nothing to draw
1108    if (fClip->isEmpty() ||
1109            bitmap.width() == 0 || bitmap.height() == 0 ||
1110            bitmap.getConfig() == SkBitmap::kNo_Config ||
1111            (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
1112        return;
1113    }
1114
1115#ifndef SK_ALLOW_OVER_32K_BITMAPS
1116    // run away on too-big bitmaps for now (exceed 16.16)
1117    if (bitmap.width() > 32767 || bitmap.height() > 32767) {
1118        return;
1119    }
1120#endif
1121
1122    SkAutoPaintStyleRestore restore(paint, SkPaint::kFill_Style);
1123
1124    SkMatrix matrix;
1125    if (!matrix.setConcat(*fMatrix, prematrix)) {
1126        return;
1127    }
1128
1129    if (clipped_out(matrix, *fClip, bitmap.width(), bitmap.height())) {
1130        return;
1131    }
1132
1133    if (fBounder && just_translate(matrix, bitmap)) {
1134        SkIRect ir;
1135        int32_t ix = SkScalarRound(matrix.getTranslateX());
1136        int32_t iy = SkScalarRound(matrix.getTranslateY());
1137        ir.set(ix, iy, ix + bitmap.width(), iy + bitmap.height());
1138        if (!fBounder->doIRect(ir)) {
1139            return;
1140        }
1141    }
1142
1143    // only lock the pixels if we passed the clip and bounder tests
1144    SkAutoLockPixels alp(bitmap);
1145    // after the lock, check if we are valid
1146    if (!bitmap.readyToDraw()) {
1147        return;
1148    }
1149
1150    if (bitmap.getConfig() != SkBitmap::kA8_Config &&
1151            just_translate(matrix, bitmap)) {
1152        int         ix = SkScalarRound(matrix.getTranslateX());
1153        int         iy = SkScalarRound(matrix.getTranslateY());
1154        uint32_t    storage[kBlitterStorageLongCount];
1155        SkBlitter*  blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap,
1156                                            ix, iy, storage, sizeof(storage));
1157        if (blitter) {
1158            SkAutoTPlacementDelete<SkBlitter>   ad(blitter, storage);
1159
1160            SkIRect    ir;
1161            ir.set(ix, iy, ix + bitmap.width(), iy + bitmap.height());
1162
1163            SkRegion::Cliperator iter(*fClip, ir);
1164            const SkIRect&       cr = iter.rect();
1165
1166            for (; !iter.done(); iter.next()) {
1167                SkASSERT(!cr.isEmpty());
1168                blitter->blitRect(cr.fLeft, cr.fTop, cr.width(), cr.height());
1169            }
1170            return;
1171        }
1172#if 0
1173        SkDebugf("---- MISSING sprite case: config=%d [%d %d], device=%d, xfer=%p, alpha=0x%X colorFilter=%p\n",
1174                bitmap.config(), bitmap.width(), bitmap.height(), fBitmap->config(),
1175                paint.getXfermode(), paint.getAlpha(), paint.getColorFilter());
1176#endif
1177    }
1178
1179    // now make a temp draw on the stack, and use it
1180    //
1181    SkDraw draw(*this);
1182    draw.fMatrix = &matrix;
1183
1184    if (bitmap.getConfig() == SkBitmap::kA8_Config) {
1185        draw.drawBitmapAsMask(bitmap, paint);
1186    } else {
1187        SkAutoBitmapShaderInstall   install(bitmap, &paint);
1188
1189        SkRect  r;
1190        r.set(0, 0, SkIntToScalar(bitmap.width()),
1191              SkIntToScalar(bitmap.height()));
1192        // is this ok if paint has a rasterizer?
1193        draw.drawRect(r, paint);
1194    }
1195}
1196
1197void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y,
1198                        const SkPaint& paint) const {
1199    SkDEBUGCODE(this->validate();)
1200
1201    // nothing to draw
1202    if (fClip->isEmpty() ||
1203            bitmap.width() == 0 || bitmap.height() == 0 ||
1204            bitmap.getConfig() == SkBitmap::kNo_Config ||
1205            (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
1206        return;
1207    }
1208
1209    SkIRect    bounds;
1210    bounds.set(x, y, x + bitmap.width(), y + bitmap.height());
1211
1212    if (fClip->quickReject(bounds)) {
1213        return; // nothing to draw
1214    }
1215
1216    SkAutoPaintStyleRestore restore(paint, SkPaint::kFill_Style);
1217
1218    if (NULL == paint.getColorFilter()) {
1219        uint32_t    storage[kBlitterStorageLongCount];
1220        SkBlitter*  blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap,
1221                                                x, y, storage, sizeof(storage));
1222
1223        if (blitter) {
1224            SkAutoTPlacementDelete<SkBlitter> ad(blitter, storage);
1225
1226            if (fBounder && !fBounder->doIRect(bounds)) {
1227                return;
1228            }
1229
1230            SkRegion::Cliperator iter(*fClip, bounds);
1231            const SkIRect&       cr = iter.rect();
1232
1233            for (; !iter.done(); iter.next()) {
1234                SkASSERT(!cr.isEmpty());
1235                blitter->blitRect(cr.fLeft, cr.fTop, cr.width(), cr.height());
1236            }
1237            return;
1238        }
1239    }
1240
1241    SkAutoBitmapShaderInstall   install(bitmap, &paint);
1242
1243    SkMatrix        matrix;
1244    SkRect          r;
1245
1246    // get a scalar version of our rect
1247    r.set(bounds);
1248
1249    // tell the shader our offset
1250    matrix.setTranslate(r.fLeft, r.fTop);
1251    paint.getShader()->setLocalMatrix(matrix);
1252
1253    SkDraw draw(*this);
1254    matrix.reset();
1255    draw.fMatrix = &matrix;
1256    // call ourself with a rect
1257    // is this OK if paint has a rasterizer?
1258    draw.drawRect(r, paint);
1259}
1260
1261///////////////////////////////////////////////////////////////////////////////
1262
1263#include "SkScalerContext.h"
1264#include "SkGlyphCache.h"
1265#include "SkUtils.h"
1266
1267static void measure_text(SkGlyphCache* cache, SkDrawCacheProc glyphCacheProc,
1268                const char text[], size_t byteLength, SkVector* stopVector) {
1269    SkFixed     x = 0, y = 0;
1270    const char* stop = text + byteLength;
1271
1272    SkAutoKern  autokern;
1273
1274    while (text < stop) {
1275        // don't need x, y here, since all subpixel variants will have the
1276        // same advance
1277        const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
1278
1279        x += autokern.adjust(glyph) + glyph.fAdvanceX;
1280        y += glyph.fAdvanceY;
1281    }
1282    stopVector->set(SkFixedToScalar(x), SkFixedToScalar(y));
1283
1284    SkASSERT(text == stop);
1285}
1286
1287void SkDraw::drawText_asPaths(const char text[], size_t byteLength,
1288                              SkScalar x, SkScalar y,
1289                              const SkPaint& paint) const {
1290    SkDEBUGCODE(this->validate();)
1291
1292    SkTextToPathIter iter(text, byteLength, paint, true, true);
1293
1294    SkMatrix    matrix;
1295    matrix.setScale(iter.getPathScale(), iter.getPathScale());
1296    matrix.postTranslate(x, y);
1297
1298    const SkPath* iterPath;
1299    SkScalar xpos, prevXPos = 0;
1300
1301    while ((iterPath = iter.next(&xpos)) != NULL) {
1302        matrix.postTranslate(xpos - prevXPos, 0);
1303        const SkPaint& pnt = iter.getPaint();
1304        if (fDevice) {
1305            fDevice->drawPath(*this, *iterPath, pnt, &matrix, false);
1306        } else {
1307            this->drawPath(*iterPath, pnt, &matrix, false);
1308        }
1309        prevXPos = xpos;
1310    }
1311}
1312
1313static void draw_paint_rect(const SkDraw* draw, const SkPaint& paint,
1314                            const SkRect& r, SkScalar textSize) {
1315    if (paint.getStyle() == SkPaint::kFill_Style) {
1316        draw->drawRect(r, paint);
1317    } else {
1318        SkPaint p(paint);
1319        p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
1320        draw->drawRect(r, p);
1321    }
1322}
1323
1324static void handle_aftertext(const SkDraw* draw, const SkPaint& paint,
1325                             SkScalar width, const SkPoint& start) {
1326    uint32_t flags = paint.getFlags();
1327
1328    if (flags & (SkPaint::kUnderlineText_Flag |
1329                 SkPaint::kStrikeThruText_Flag)) {
1330        SkScalar textSize = paint.getTextSize();
1331        SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
1332        SkRect   r;
1333
1334        r.fLeft = start.fX;
1335        r.fRight = start.fX + width;
1336
1337        if (flags & SkPaint::kUnderlineText_Flag) {
1338            SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
1339                                             start.fY);
1340            r.fTop = offset;
1341            r.fBottom = offset + height;
1342            draw_paint_rect(draw, paint, r, textSize);
1343        }
1344        if (flags & SkPaint::kStrikeThruText_Flag) {
1345            SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
1346                                             start.fY);
1347            r.fTop = offset;
1348            r.fBottom = offset + height;
1349            draw_paint_rect(draw, paint, r, textSize);
1350        }
1351    }
1352}
1353
1354// disable warning : local variable used without having been initialized
1355#if defined _WIN32 && _MSC_VER >= 1300
1356#pragma warning ( push )
1357#pragma warning ( disable : 4701 )
1358#endif
1359
1360//////////////////////////////////////////////////////////////////////////////
1361
1362static void D1G_NoBounder_RectClip(const SkDraw1Glyph& state,
1363                                   SkFixed fx, SkFixed fy,
1364                                   const SkGlyph& glyph) {
1365    int left = SkFixedFloor(fx);
1366    int top = SkFixedFloor(fy);
1367    SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1368	SkASSERT(state.fClip->isRect());
1369	SkASSERT(NULL == state.fBounder);
1370	SkASSERT(state.fClipBounds == state.fClip->getBounds());
1371
1372    left += glyph.fLeft;
1373    top  += glyph.fTop;
1374
1375    int right   = left + glyph.fWidth;
1376    int bottom  = top + glyph.fHeight;
1377
1378	SkMask		mask;
1379	SkIRect		storage;
1380	SkIRect*	bounds = &mask.fBounds;
1381
1382	mask.fBounds.set(left, top, right, bottom);
1383
1384	// this extra test is worth it, assuming that most of the time it succeeds
1385	// since we can avoid writing to storage
1386	if (!state.fClipBounds.containsNoEmptyCheck(left, top, right, bottom)) {
1387		if (!storage.intersectNoEmptyCheck(mask.fBounds, state.fClipBounds))
1388			return;
1389		bounds = &storage;
1390	}
1391
1392	uint8_t* aa = (uint8_t*)glyph.fImage;
1393	if (NULL == aa) {
1394		aa = (uint8_t*)state.fCache->findImage(glyph);
1395		if (NULL == aa) {
1396			return; // can't rasterize glyph
1397        }
1398	}
1399
1400	mask.fRowBytes = glyph.rowBytes();
1401	mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
1402	mask.fImage = aa;
1403	state.fBlitter->blitMask(mask, *bounds);
1404}
1405
1406static void D1G_NoBounder_RgnClip(const SkDraw1Glyph& state,
1407                                  SkFixed fx, SkFixed fy,
1408								  const SkGlyph& glyph) {
1409    int left = SkFixedFloor(fx);
1410    int top = SkFixedFloor(fy);
1411    SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1412	SkASSERT(!state.fClip->isRect());
1413	SkASSERT(NULL == state.fBounder);
1414
1415    SkMask  mask;
1416
1417    left += glyph.fLeft;
1418    top  += glyph.fTop;
1419
1420    mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight);
1421	SkRegion::Cliperator clipper(*state.fClip, mask.fBounds);
1422
1423	if (!clipper.done()) {
1424		const SkIRect&  cr = clipper.rect();
1425		const uint8_t*  aa = (const uint8_t*)glyph.fImage;
1426		if (NULL == aa) {
1427			aa = (uint8_t*)state.fCache->findImage(glyph);
1428			if (NULL == aa) {
1429				return;
1430            }
1431		}
1432
1433		mask.fRowBytes = glyph.rowBytes();
1434		mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
1435		mask.fImage = (uint8_t*)aa;
1436		do {
1437			state.fBlitter->blitMask(mask, cr);
1438			clipper.next();
1439		} while (!clipper.done());
1440	}
1441}
1442
1443static void D1G_Bounder(const SkDraw1Glyph& state,
1444                        SkFixed fx, SkFixed fy,
1445						const SkGlyph& glyph) {
1446    int left = SkFixedFloor(fx);
1447    int top = SkFixedFloor(fy);
1448    SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1449
1450    SkMask  mask;
1451
1452    left += glyph.fLeft;
1453    top  += glyph.fTop;
1454
1455    mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight);
1456    SkRegion::Cliperator clipper(*state.fClip, mask.fBounds);
1457
1458	if (!clipper.done()) {
1459		const SkIRect&  cr = clipper.rect();
1460		const uint8_t*  aa = (const uint8_t*)glyph.fImage;
1461		if (NULL == aa) {
1462			aa = (uint8_t*)state.fCache->findImage(glyph);
1463			if (NULL == aa) {
1464				return;
1465            }
1466		}
1467
1468        // we need to pass the origin, which we approximate with our
1469        // (unadjusted) left,top coordinates (the caller called fixedfloor)
1470		if (state.fBounder->doIRectGlyph(cr,
1471                                         left - glyph.fLeft,
1472                                         top - glyph.fTop, glyph)) {
1473			mask.fRowBytes = glyph.rowBytes();
1474			mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
1475			mask.fImage = (uint8_t*)aa;
1476			do {
1477				state.fBlitter->blitMask(mask, cr);
1478				clipper.next();
1479			} while (!clipper.done());
1480		}
1481	}
1482}
1483
1484SkDraw1Glyph::Proc SkDraw1Glyph::init(const SkDraw* draw, SkBlitter* blitter,
1485                                      SkGlyphCache* cache) {
1486    fDraw = draw;
1487	fBounder = draw->fBounder;
1488	fClip = draw->fClip;
1489    fClipBounds = fClip->getBounds();
1490	fBlitter = blitter;
1491	fCache = cache;
1492
1493    if (draw->fProcs && draw->fProcs->fD1GProc) {
1494        return draw->fProcs->fD1GProc;
1495    }
1496
1497    if (NULL == fBounder) {
1498        if (fClip->isRect()) {
1499            return D1G_NoBounder_RectClip;
1500        } else {
1501            return D1G_NoBounder_RgnClip;
1502        }
1503    } else {
1504        return D1G_Bounder;
1505    }
1506}
1507
1508enum RoundBaseline {
1509    kDont_Round_Baseline,
1510    kRound_X_Baseline,
1511    kRound_Y_Baseline
1512};
1513
1514static RoundBaseline computeRoundBaseline(const SkMatrix& mat) {
1515    if (mat[1] == 0 && mat[3] == 0) {
1516        // we're 0 or 180 degrees, round the y coordinate of the baseline
1517        return kRound_Y_Baseline;
1518    } else if (mat[0] == 0 && mat[4] == 0) {
1519        // we're 90 or 270 degrees, round the x coordinate of the baseline
1520        return kRound_X_Baseline;
1521    } else {
1522        return kDont_Round_Baseline;
1523    }
1524}
1525
1526///////////////////////////////////////////////////////////////////////////////
1527
1528void SkDraw::drawText(const char text[], size_t byteLength,
1529                      SkScalar x, SkScalar y, const SkPaint& paint) const {
1530    SkASSERT(byteLength == 0 || text != NULL);
1531
1532    SkDEBUGCODE(this->validate();)
1533
1534    // nothing to draw
1535    if (text == NULL || byteLength == 0 ||
1536        fClip->isEmpty() ||
1537        (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
1538        return;
1539    }
1540
1541    SkScalar    underlineWidth = 0;
1542    SkPoint     underlineStart;
1543
1544    underlineStart.set(0, 0);    // to avoid warning
1545    if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
1546                            SkPaint::kStrikeThruText_Flag)) {
1547        underlineWidth = paint.measureText(text, byteLength);
1548
1549        SkScalar offsetX = 0;
1550        if (paint.getTextAlign() == SkPaint::kCenter_Align) {
1551            offsetX = SkScalarHalf(underlineWidth);
1552        } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
1553            offsetX = underlineWidth;
1554        }
1555        underlineStart.set(x - offsetX, y);
1556    }
1557
1558    if (/*paint.isLinearText() ||*/
1559        (fMatrix->getType() & SkMatrix::kPerspective_Mask)) {
1560        this->drawText_asPaths(text, byteLength, x, y, paint);
1561        handle_aftertext(this, paint, underlineWidth, underlineStart);
1562        return;
1563    }
1564
1565    SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc();
1566
1567    const SkMatrix* matrix = fMatrix;
1568    SkFixed finalFYMask = ~0xFFFF;  // trunc fy;
1569    if (fProcs && fProcs->fD1GProc) {
1570        // only support the fMVMatrix (for now) for the GPU case, which also
1571        // sets the fD1GProc
1572        if (fMVMatrix) {
1573            matrix = fMVMatrix;
1574            finalFYMask = ~0;  // don't truncate
1575        }
1576    }
1577
1578    SkAutoGlyphCache    autoCache(paint, matrix);
1579    SkGlyphCache*       cache = autoCache.getCache();
1580    SkAutoBlitterChoose blitter(*fBitmap, *matrix, paint);
1581
1582    // transform our starting point
1583    {
1584        SkPoint loc;
1585        matrix->mapXY(x, y, &loc);
1586        x = loc.fX;
1587        y = loc.fY;
1588    }
1589
1590    // need to measure first
1591    if (paint.getTextAlign() != SkPaint::kLeft_Align) {
1592        SkVector    stop;
1593
1594        measure_text(cache, glyphCacheProc, text, byteLength, &stop);
1595
1596        SkScalar    stopX = stop.fX;
1597        SkScalar    stopY = stop.fY;
1598
1599        if (paint.getTextAlign() == SkPaint::kCenter_Align) {
1600            stopX = SkScalarHalf(stopX);
1601            stopY = SkScalarHalf(stopY);
1602        }
1603        x -= stopX;
1604        y -= stopY;
1605    }
1606
1607    SkFixed fx = SkScalarToFixed(x);
1608    SkFixed fy = SkScalarToFixed(y);
1609    const char* stop = text + byteLength;
1610
1611    SkFixed fxMask = ~0;
1612    SkFixed fyMask = ~0;
1613    if (paint.isSubpixelText()) {
1614        RoundBaseline roundBaseline = computeRoundBaseline(*matrix);
1615        if (kRound_Y_Baseline == roundBaseline) {
1616            fyMask = 0;
1617//            fy = (fy + 0x8000) & ~0xFFFF;
1618        } else if (kRound_X_Baseline == roundBaseline) {
1619            fxMask = 0;
1620        }
1621    }
1622    // apply the bias here, so we don't have to add 1/2 in the loop
1623    fx += SK_FixedHalf;
1624    fy += SK_FixedHalf;
1625    fy &= finalFYMask;
1626
1627    SkAutoKern          autokern;
1628	SkDraw1Glyph        d1g;
1629	SkDraw1Glyph::Proc  proc = d1g.init(this, blitter.get(), cache);
1630
1631    while (text < stop) {
1632        const SkGlyph& glyph  = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
1633
1634        fx += autokern.adjust(glyph);
1635
1636        if (glyph.fWidth) {
1637			proc(d1g, fx, fy, glyph);
1638        }
1639        fx += glyph.fAdvanceX;
1640        fy += glyph.fAdvanceY;
1641    }
1642
1643    if (underlineWidth) {
1644        autoCache.release();    // release this now to free up the RAM
1645        handle_aftertext(this, paint, underlineWidth, underlineStart);
1646    }
1647}
1648
1649// last parameter is interpreted as SkFixed [x, y]
1650// return the fixed position, which may be rounded or not by the caller
1651//   e.g. subpixel doesn't round
1652typedef void (*AlignProc)(const SkPoint&, const SkGlyph&, SkIPoint*);
1653
1654static void leftAlignProc(const SkPoint& loc, const SkGlyph& glyph,
1655                          SkIPoint* dst) {
1656    dst->set(SkScalarToFixed(loc.fX), SkScalarToFixed(loc.fY));
1657}
1658
1659static void centerAlignProc(const SkPoint& loc, const SkGlyph& glyph,
1660                            SkIPoint* dst) {
1661    dst->set(SkScalarToFixed(loc.fX) - (glyph.fAdvanceX >> 1),
1662             SkScalarToFixed(loc.fY) - (glyph.fAdvanceY >> 1));
1663}
1664
1665static void rightAlignProc(const SkPoint& loc, const SkGlyph& glyph,
1666                           SkIPoint* dst) {
1667    dst->set(SkScalarToFixed(loc.fX) - glyph.fAdvanceX,
1668             SkScalarToFixed(loc.fY) - glyph.fAdvanceY);
1669}
1670
1671static AlignProc pick_align_proc(SkPaint::Align align) {
1672    static const AlignProc gProcs[] = {
1673        leftAlignProc, centerAlignProc, rightAlignProc
1674    };
1675
1676    SkASSERT((unsigned)align < SK_ARRAY_COUNT(gProcs));
1677
1678    return gProcs[align];
1679}
1680
1681class TextMapState {
1682public:
1683    mutable SkPoint fLoc;
1684
1685    TextMapState(const SkMatrix& matrix, SkScalar y)
1686        : fMatrix(matrix), fProc(matrix.getMapXYProc()), fY(y) {}
1687
1688    typedef void (*Proc)(const TextMapState&, const SkScalar pos[]);
1689
1690    Proc pickProc(int scalarsPerPosition);
1691
1692private:
1693    const SkMatrix&     fMatrix;
1694    SkMatrix::MapXYProc fProc;
1695    SkScalar            fY; // ignored by MapXYProc
1696    // these are only used by Only... procs
1697    SkScalar            fScaleX, fTransX, fTransformedY;
1698
1699    static void MapXProc(const TextMapState& state, const SkScalar pos[]) {
1700        state.fProc(state.fMatrix, *pos, state.fY, &state.fLoc);
1701    }
1702
1703    static void MapXYProc(const TextMapState& state, const SkScalar pos[]) {
1704        state.fProc(state.fMatrix, pos[0], pos[1], &state.fLoc);
1705    }
1706
1707    static void MapOnlyScaleXProc(const TextMapState& state,
1708                                  const SkScalar pos[]) {
1709        state.fLoc.set(SkScalarMul(state.fScaleX, *pos) + state.fTransX,
1710                       state.fTransformedY);
1711    }
1712
1713    static void MapOnlyTransXProc(const TextMapState& state,
1714                                  const SkScalar pos[]) {
1715        state.fLoc.set(*pos + state.fTransX, state.fTransformedY);
1716    }
1717};
1718
1719TextMapState::Proc TextMapState::pickProc(int scalarsPerPosition) {
1720    SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
1721
1722    if (1 == scalarsPerPosition) {
1723        unsigned mtype = fMatrix.getType();
1724        if (mtype & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) {
1725            return MapXProc;
1726        } else {
1727            fScaleX = fMatrix.getScaleX();
1728            fTransX = fMatrix.getTranslateX();
1729            fTransformedY = SkScalarMul(fY, fMatrix.getScaleY()) +
1730                            fMatrix.getTranslateY();
1731            return (mtype & SkMatrix::kScale_Mask) ?
1732                        MapOnlyScaleXProc : MapOnlyTransXProc;
1733        }
1734    } else {
1735        return MapXYProc;
1736    }
1737}
1738
1739//////////////////////////////////////////////////////////////////////////////
1740
1741void SkDraw::drawPosText(const char text[], size_t byteLength,
1742                         const SkScalar pos[], SkScalar constY,
1743                         int scalarsPerPosition, const SkPaint& paint) const {
1744    SkASSERT(byteLength == 0 || text != NULL);
1745    SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
1746
1747    SkDEBUGCODE(this->validate();)
1748
1749    // nothing to draw
1750    if (text == NULL || byteLength == 0 ||
1751        fClip->isEmpty() ||
1752        (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
1753        return;
1754    }
1755
1756    if (/*paint.isLinearText() ||*/
1757        (fMatrix->getType() & SkMatrix::kPerspective_Mask)) {
1758        // TODO !!!!
1759//      this->drawText_asPaths(text, byteLength, x, y, paint);
1760        return;
1761    }
1762
1763    const SkMatrix* matrix = fMatrix;
1764    if (fProcs && fProcs->fD1GProc) {
1765        // only support the fMVMatrix (for now) for the GPU case, which also
1766        // sets the fD1GProc
1767        if (fMVMatrix) {
1768            matrix = fMVMatrix;
1769        }
1770    }
1771
1772    SkDrawCacheProc     glyphCacheProc = paint.getDrawCacheProc();
1773    SkAutoGlyphCache    autoCache(paint, matrix);
1774    SkGlyphCache*       cache = autoCache.getCache();
1775    SkAutoBlitterChoose blitter(*fBitmap, *matrix, paint);
1776
1777    const char*        stop = text + byteLength;
1778    AlignProc          alignProc = pick_align_proc(paint.getTextAlign());
1779	SkDraw1Glyph	   d1g;
1780	SkDraw1Glyph::Proc  proc = d1g.init(this, blitter.get(), cache);
1781    TextMapState       tms(*matrix, constY);
1782    TextMapState::Proc tmsProc = tms.pickProc(scalarsPerPosition);
1783
1784    if (paint.isSubpixelText()) {
1785        // maybe we should skip the rounding if linearText is set
1786        RoundBaseline roundBaseline = computeRoundBaseline(*matrix);
1787
1788        if (SkPaint::kLeft_Align == paint.getTextAlign()) {
1789            while (text < stop) {
1790
1791                tmsProc(tms, pos);
1792
1793                SkFixed fx = SkScalarToFixed(tms.fLoc.fX);
1794                SkFixed fy = SkScalarToFixed(tms.fLoc.fY);
1795                SkFixed fxMask = ~0;
1796                SkFixed fyMask = ~0;
1797
1798                if (kRound_Y_Baseline == roundBaseline) {
1799                    fyMask = 0;
1800                } else if (kRound_X_Baseline == roundBaseline) {
1801                    fxMask = 0;
1802                }
1803
1804                const SkGlyph& glyph = glyphCacheProc(cache, &text,
1805                                                      fx & fxMask, fy & fyMask);
1806
1807                if (glyph.fWidth) {
1808                    proc(d1g, fx, fy, glyph);
1809                }
1810                pos += scalarsPerPosition;
1811            }
1812        } else {
1813            while (text < stop) {
1814                const SkGlyph* glyph = &glyphCacheProc(cache, &text, 0, 0);
1815
1816                if (glyph->fWidth) {
1817                    SkDEBUGCODE(SkFixed prevAdvX = glyph->fAdvanceX;)
1818                    SkDEBUGCODE(SkFixed prevAdvY = glyph->fAdvanceY;)
1819
1820                    SkFixed fx, fy;
1821                    SkFixed fxMask = ~0;
1822                    SkFixed fyMask = ~0;
1823                    tmsProc(tms, pos);
1824
1825                    {
1826                        SkIPoint fixedLoc;
1827                        alignProc(tms.fLoc, *glyph, &fixedLoc);
1828                        fx = fixedLoc.fX;
1829                        fy = fixedLoc.fY;
1830
1831                        if (kRound_Y_Baseline == roundBaseline) {
1832                            fyMask = 0;
1833                        } else if (kRound_X_Baseline == roundBaseline) {
1834                            fxMask = 0;
1835                        }
1836                    }
1837
1838                    // have to call again, now that we've been "aligned"
1839                    glyph = &glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
1840                    // the assumption is that the advance hasn't changed
1841                    SkASSERT(prevAdvX == glyph->fAdvanceX);
1842                    SkASSERT(prevAdvY == glyph->fAdvanceY);
1843
1844                    proc(d1g, fx, fy, *glyph);
1845                }
1846                pos += scalarsPerPosition;
1847            }
1848        }
1849    } else {    // not subpixel
1850        while (text < stop) {
1851            // the last 2 parameters are ignored
1852            const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
1853
1854            if (glyph.fWidth) {
1855                tmsProc(tms, pos);
1856
1857                SkIPoint fixedLoc;
1858                alignProc(tms.fLoc, glyph, &fixedLoc);
1859
1860                proc(d1g, fixedLoc.fX + SK_FixedHalf,
1861                     fixedLoc.fY + SK_FixedHalf, glyph);
1862            }
1863            pos += scalarsPerPosition;
1864        }
1865    }
1866}
1867
1868#if defined _WIN32 && _MSC_VER >= 1300
1869#pragma warning ( pop )
1870#endif
1871
1872///////////////////////////////////////////////////////////////////////////////
1873
1874#include "SkPathMeasure.h"
1875
1876static void morphpoints(SkPoint dst[], const SkPoint src[], int count,
1877                        SkPathMeasure& meas, const SkMatrix& matrix) {
1878    SkMatrix::MapXYProc proc = matrix.getMapXYProc();
1879
1880    for (int i = 0; i < count; i++) {
1881        SkPoint pos;
1882        SkVector tangent;
1883
1884        proc(matrix, src[i].fX, src[i].fY, &pos);
1885        SkScalar sx = pos.fX;
1886        SkScalar sy = pos.fY;
1887
1888        meas.getPosTan(sx, &pos, &tangent);
1889
1890        /*  This is the old way (that explains our approach but is way too slow
1891            SkMatrix    matrix;
1892            SkPoint     pt;
1893
1894            pt.set(sx, sy);
1895            matrix.setSinCos(tangent.fY, tangent.fX);
1896            matrix.preTranslate(-sx, 0);
1897            matrix.postTranslate(pos.fX, pos.fY);
1898            matrix.mapPoints(&dst[i], &pt, 1);
1899        */
1900        dst[i].set(pos.fX - SkScalarMul(tangent.fY, sy),
1901                   pos.fY + SkScalarMul(tangent.fX, sy));
1902    }
1903}
1904
1905/*  TODO
1906
1907    Need differentially more subdivisions when the follow-path is curvy. Not sure how to
1908    determine that, but we need it. I guess a cheap answer is let the caller tell us,
1909    but that seems like a cop-out. Another answer is to get Rob Johnson to figure it out.
1910*/
1911static void morphpath(SkPath* dst, const SkPath& src, SkPathMeasure& meas,
1912                      const SkMatrix& matrix) {
1913    SkPath::Iter    iter(src, false);
1914    SkPoint         srcP[4], dstP[3];
1915    SkPath::Verb    verb;
1916
1917    while ((verb = iter.next(srcP)) != SkPath::kDone_Verb) {
1918        switch (verb) {
1919            case SkPath::kMove_Verb:
1920                morphpoints(dstP, srcP, 1, meas, matrix);
1921                dst->moveTo(dstP[0]);
1922                break;
1923            case SkPath::kLine_Verb:
1924                // turn lines into quads to look bendy
1925                srcP[0].fX = SkScalarAve(srcP[0].fX, srcP[1].fX);
1926                srcP[0].fY = SkScalarAve(srcP[0].fY, srcP[1].fY);
1927                morphpoints(dstP, srcP, 2, meas, matrix);
1928                dst->quadTo(dstP[0], dstP[1]);
1929                break;
1930            case SkPath::kQuad_Verb:
1931                morphpoints(dstP, &srcP[1], 2, meas, matrix);
1932                dst->quadTo(dstP[0], dstP[1]);
1933                break;
1934            case SkPath::kCubic_Verb:
1935                morphpoints(dstP, &srcP[1], 3, meas, matrix);
1936                dst->cubicTo(dstP[0], dstP[1], dstP[2]);
1937                break;
1938            case SkPath::kClose_Verb:
1939                dst->close();
1940                break;
1941            default:
1942                SkASSERT(!"unknown verb");
1943                break;
1944        }
1945    }
1946}
1947
1948void SkDraw::drawTextOnPath(const char text[], size_t byteLength,
1949                            const SkPath& follow, const SkMatrix* matrix,
1950                            const SkPaint& paint) const {
1951    SkASSERT(byteLength == 0 || text != NULL);
1952
1953    // nothing to draw
1954    if (text == NULL || byteLength == 0 ||
1955        fClip->isEmpty() ||
1956        (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
1957        return;
1958    }
1959
1960    SkTextToPathIter    iter(text, byteLength, paint, true, true);
1961    SkPathMeasure       meas(follow, false);
1962    SkScalar            hOffset = 0;
1963
1964    // need to measure first
1965    if (paint.getTextAlign() != SkPaint::kLeft_Align) {
1966        SkScalar pathLen = meas.getLength();
1967        if (paint.getTextAlign() == SkPaint::kCenter_Align) {
1968            pathLen = SkScalarHalf(pathLen);
1969        }
1970        hOffset += pathLen;
1971    }
1972
1973    const SkPath*   iterPath;
1974    SkScalar        xpos;
1975    SkMatrix        scaledMatrix;
1976    SkScalar        scale = iter.getPathScale();
1977
1978    scaledMatrix.setScale(scale, scale);
1979
1980    while ((iterPath = iter.next(&xpos)) != NULL) {
1981        SkPath      tmp;
1982        SkMatrix    m(scaledMatrix);
1983
1984        m.postTranslate(xpos + hOffset, 0);
1985        if (matrix) {
1986            m.postConcat(*matrix);
1987        }
1988        morphpath(&tmp, *iterPath, meas, m);
1989        if (fDevice) {
1990            fDevice->drawPath(*this, tmp, iter.getPaint(), NULL, true);
1991        } else {
1992            this->drawPath(tmp, iter.getPaint(), NULL, true);
1993        }
1994    }
1995}
1996
1997#ifdef ANDROID
1998void SkDraw::drawPosTextOnPath(const char text[], size_t byteLength,
1999                               const SkPoint pos[], const SkPaint& paint,
2000                               const SkPath& path, const SkMatrix* matrix) const {
2001    // nothing to draw
2002    if (text == NULL || byteLength == 0 || fClip->isEmpty() ||
2003        (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2004        return;
2005    }
2006
2007    SkMatrix scaledMatrix;
2008    SkPathMeasure meas(path, false);
2009
2010    SkMeasureCacheProc glyphCacheProc = paint.getMeasureCacheProc(
2011            SkPaint::kForward_TextBufferDirection, true);
2012
2013    // Copied (modified) from SkTextToPathIter constructor to setup paint
2014    SkPaint tempPaint(paint);
2015
2016    tempPaint.setLinearText(true);
2017    tempPaint.setMaskFilter(NULL); // don't want this affecting our path-cache lookup
2018
2019    if (tempPaint.getPathEffect() == NULL && !(tempPaint.getStrokeWidth() > 0
2020            && tempPaint.getStyle() != SkPaint::kFill_Style)) {
2021        tempPaint.setStyle(SkPaint::kFill_Style);
2022        tempPaint.setPathEffect(NULL);
2023    }
2024    // End copied from SkTextToPathIter constructor
2025
2026    // detach cache
2027    SkGlyphCache* cache = tempPaint.detachCache(NULL);
2028
2029    // Must set scale, even if 1
2030    SkScalar scale = SK_Scalar1;
2031    scaledMatrix.setScale(scale, scale);
2032
2033    // Loop over all glyph ids
2034    for (const char* stop = text + byteLength; text < stop; pos++) {
2035
2036        const SkGlyph& glyph = glyphCacheProc(cache, &text);
2037        SkPath tmp;
2038
2039        const SkPath* glyphPath = cache->findPath(glyph);
2040        if (glyphPath == NULL) {
2041            continue;
2042        }
2043
2044        SkMatrix m(scaledMatrix);
2045        m.postTranslate(pos->fX, 0);
2046
2047        if (matrix) {
2048            m.postConcat(*matrix);
2049        }
2050
2051        morphpath(&tmp, *glyphPath, meas, m);
2052        this->drawPath(tmp, tempPaint);
2053
2054    }
2055
2056    // re-attach cache
2057    SkGlyphCache::AttachCache(cache);
2058}
2059#endif
2060
2061///////////////////////////////////////////////////////////////////////////////
2062
2063struct VertState {
2064    int f0, f1, f2;
2065
2066    VertState(int vCount, const uint16_t indices[], int indexCount)
2067            : fIndices(indices) {
2068        fCurrIndex = 0;
2069        if (indices) {
2070            fCount = indexCount;
2071        } else {
2072            fCount = vCount;
2073        }
2074    }
2075
2076    typedef bool (*Proc)(VertState*);
2077    Proc chooseProc(SkCanvas::VertexMode mode);
2078
2079private:
2080    int             fCount;
2081    int             fCurrIndex;
2082    const uint16_t* fIndices;
2083
2084    static bool Triangles(VertState*);
2085    static bool TrianglesX(VertState*);
2086    static bool TriangleStrip(VertState*);
2087    static bool TriangleStripX(VertState*);
2088    static bool TriangleFan(VertState*);
2089    static bool TriangleFanX(VertState*);
2090};
2091
2092bool VertState::Triangles(VertState* state) {
2093    int index = state->fCurrIndex;
2094    if (index + 3 > state->fCount) {
2095        return false;
2096    }
2097    state->f0 = index + 0;
2098    state->f1 = index + 1;
2099    state->f2 = index + 2;
2100    state->fCurrIndex = index + 3;
2101    return true;
2102}
2103
2104bool VertState::TrianglesX(VertState* state) {
2105    const uint16_t* indices = state->fIndices;
2106    int index = state->fCurrIndex;
2107    if (index + 3 > state->fCount) {
2108        return false;
2109    }
2110    state->f0 = indices[index + 0];
2111    state->f1 = indices[index + 1];
2112    state->f2 = indices[index + 2];
2113    state->fCurrIndex = index + 3;
2114    return true;
2115}
2116
2117bool VertState::TriangleStrip(VertState* state) {
2118    int index = state->fCurrIndex;
2119    if (index + 3 > state->fCount) {
2120        return false;
2121    }
2122    state->f2 = index + 2;
2123    if (index & 1) {
2124        state->f0 = index + 1;
2125        state->f1 = index + 0;
2126    } else {
2127        state->f0 = index + 0;
2128        state->f1 = index + 1;
2129    }
2130    state->fCurrIndex = index + 1;
2131    return true;
2132}
2133
2134bool VertState::TriangleStripX(VertState* state) {
2135    const uint16_t* indices = state->fIndices;
2136    int index = state->fCurrIndex;
2137    if (index + 3 > state->fCount) {
2138        return false;
2139    }
2140    state->f2 = indices[index + 2];
2141    if (index & 1) {
2142        state->f0 = indices[index + 1];
2143        state->f1 = indices[index + 0];
2144    } else {
2145        state->f0 = indices[index + 0];
2146        state->f1 = indices[index + 1];
2147    }
2148    state->fCurrIndex = index + 1;
2149    return true;
2150}
2151
2152bool VertState::TriangleFan(VertState* state) {
2153    int index = state->fCurrIndex;
2154    if (index + 3 > state->fCount) {
2155        return false;
2156    }
2157    state->f0 = 0;
2158    state->f1 = index + 1;
2159    state->f2 = index + 2;
2160    state->fCurrIndex = index + 1;
2161    return true;
2162}
2163
2164bool VertState::TriangleFanX(VertState* state) {
2165    const uint16_t* indices = state->fIndices;
2166    int index = state->fCurrIndex;
2167    if (index + 3 > state->fCount) {
2168        return false;
2169    }
2170    state->f0 = indices[0];
2171    state->f1 = indices[index + 1];
2172    state->f2 = indices[index + 2];
2173    state->fCurrIndex = index + 1;
2174    return true;
2175}
2176
2177VertState::Proc VertState::chooseProc(SkCanvas::VertexMode mode) {
2178    switch (mode) {
2179        case SkCanvas::kTriangles_VertexMode:
2180            return fIndices ? TrianglesX : Triangles;
2181        case SkCanvas::kTriangleStrip_VertexMode:
2182            return fIndices ? TriangleStripX : TriangleStrip;
2183        case SkCanvas::kTriangleFan_VertexMode:
2184            return fIndices ? TriangleFanX : TriangleFan;
2185        default:
2186            return NULL;
2187    }
2188}
2189
2190typedef void (*HairProc)(const SkPoint&, const SkPoint&, const SkRegion*,
2191                         SkBlitter*);
2192
2193static HairProc ChooseHairProc(bool doAntiAlias) {
2194    return doAntiAlias ? SkScan::AntiHairLine : SkScan::HairLine;
2195}
2196
2197static bool texture_to_matrix(const VertState& state, const SkPoint verts[],
2198                              const SkPoint texs[], SkMatrix* matrix) {
2199    SkPoint src[3], dst[3];
2200
2201    src[0] = texs[state.f0];
2202    src[1] = texs[state.f1];
2203    src[2] = texs[state.f2];
2204    dst[0] = verts[state.f0];
2205    dst[1] = verts[state.f1];
2206    dst[2] = verts[state.f2];
2207    return matrix->setPolyToPoly(src, dst, 3);
2208}
2209
2210class SkTriColorShader : public SkShader {
2211public:
2212    SkTriColorShader() {}
2213
2214    bool setup(const SkPoint pts[], const SkColor colors[], int, int, int);
2215
2216    virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count);
2217
2218protected:
2219    SkTriColorShader(SkFlattenableReadBuffer& buffer) : SkShader(buffer) {}
2220
2221    virtual Factory getFactory() { return CreateProc; }
2222
2223private:
2224    SkMatrix    fDstToUnit;
2225    SkPMColor   fColors[3];
2226
2227    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
2228        return SkNEW_ARGS(SkTriColorShader, (buffer));
2229    }
2230    typedef SkShader INHERITED;
2231};
2232
2233bool SkTriColorShader::setup(const SkPoint pts[], const SkColor colors[],
2234                             int index0, int index1, int index2) {
2235
2236    fColors[0] = SkPreMultiplyColor(colors[index0]);
2237    fColors[1] = SkPreMultiplyColor(colors[index1]);
2238    fColors[2] = SkPreMultiplyColor(colors[index2]);
2239
2240    SkMatrix m, im;
2241    m.reset();
2242    m.set(0, pts[index1].fX - pts[index0].fX);
2243    m.set(1, pts[index2].fX - pts[index0].fX);
2244    m.set(2, pts[index0].fX);
2245    m.set(3, pts[index1].fY - pts[index0].fY);
2246    m.set(4, pts[index2].fY - pts[index0].fY);
2247    m.set(5, pts[index0].fY);
2248    if (!m.invert(&im)) {
2249        return false;
2250    }
2251    return fDstToUnit.setConcat(im, this->getTotalInverse());
2252}
2253
2254#include "SkColorPriv.h"
2255#include "SkComposeShader.h"
2256
2257static int ScalarTo256(SkScalar v) {
2258    int scale = SkScalarToFixed(v) >> 8;
2259    if (scale < 0) {
2260        scale = 0;
2261    }
2262    if (scale > 255) {
2263        scale = 255;
2264    }
2265    return SkAlpha255To256(scale);
2266}
2267
2268void SkTriColorShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
2269    SkPoint src;
2270
2271    for (int i = 0; i < count; i++) {
2272        fDstToUnit.mapXY(SkIntToScalar(x), SkIntToScalar(y), &src);
2273        x += 1;
2274
2275        int scale1 = ScalarTo256(src.fX);
2276        int scale2 = ScalarTo256(src.fY);
2277        int scale0 = 256 - scale1 - scale2;
2278        if (scale0 < 0) {
2279            if (scale1 > scale2) {
2280                scale2 = 256 - scale1;
2281            } else {
2282                scale1 = 256 - scale2;
2283            }
2284            scale0 = 0;
2285        }
2286
2287        dstC[i] = SkAlphaMulQ(fColors[0], scale0) +
2288        SkAlphaMulQ(fColors[1], scale1) +
2289        SkAlphaMulQ(fColors[2], scale2);
2290    }
2291}
2292
2293void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count,
2294                          const SkPoint vertices[], const SkPoint textures[],
2295                          const SkColor colors[], SkXfermode* xmode,
2296                          const uint16_t indices[], int indexCount,
2297                          const SkPaint& paint) const {
2298    SkASSERT(0 == count || NULL != vertices);
2299
2300    // abort early if there is nothing to draw
2301    if (count < 3 || (indices && indexCount < 3) || fClip->isEmpty() ||
2302            (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2303        return;
2304    }
2305
2306    // transform out vertices into device coordinates
2307    SkAutoSTMalloc<16, SkPoint> storage(count);
2308    SkPoint* devVerts = storage.get();
2309    fMatrix->mapPoints(devVerts, vertices, count);
2310
2311    if (fBounder) {
2312        SkRect bounds;
2313        bounds.set(devVerts, count);
2314        if (!fBounder->doRect(bounds, paint)) {
2315            return;
2316        }
2317    }
2318
2319    /*
2320        We can draw the vertices in 1 of 4 ways:
2321
2322        - solid color (no shader/texture[], no colors[])
2323        - just colors (no shader/texture[], has colors[])
2324        - just texture (has shader/texture[], no colors[])
2325        - colors * texture (has shader/texture[], has colors[])
2326
2327        Thus for texture drawing, we need both texture[] and a shader.
2328    */
2329
2330    SkTriColorShader triShader; // must be above declaration of p
2331    SkPaint p(paint);
2332
2333    SkShader* shader = p.getShader();
2334    if (NULL == shader) {
2335        // if we have no shader, we ignore the texture coordinates
2336        textures = NULL;
2337    } else if (NULL == textures) {
2338        // if we don't have texture coordinates, ignore the shader
2339        p.setShader(NULL);
2340        shader = NULL;
2341    }
2342
2343    // setup the custom shader (if needed)
2344    if (NULL != colors) {
2345        if (NULL == textures) {
2346            // just colors (no texture)
2347            p.setShader(&triShader);
2348        } else {
2349            // colors * texture
2350            SkASSERT(shader);
2351            bool releaseMode = false;
2352            if (NULL == xmode) {
2353                xmode = SkXfermode::Create(SkXfermode::kMultiply_Mode);
2354                releaseMode = true;
2355            }
2356            SkShader* compose = SkNEW_ARGS(SkComposeShader,
2357                                           (&triShader, shader, xmode));
2358            p.setShader(compose)->unref();
2359            if (releaseMode) {
2360                xmode->unref();
2361            }
2362        }
2363    }
2364
2365    SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, p);
2366    // setup our state and function pointer for iterating triangles
2367    VertState       state(count, indices, indexCount);
2368    VertState::Proc vertProc = state.chooseProc(vmode);
2369
2370    if (NULL != textures || NULL != colors) {
2371        SkMatrix  localM, tempM;
2372        bool      hasLocalM = shader && shader->getLocalMatrix(&localM);
2373
2374        if (NULL != colors) {
2375            if (!triShader.setContext(*fBitmap, p, *fMatrix)) {
2376                colors = NULL;
2377            }
2378        }
2379
2380        while (vertProc(&state)) {
2381            if (NULL != textures) {
2382                if (texture_to_matrix(state, vertices, textures, &tempM)) {
2383                    if (hasLocalM) {
2384                        tempM.postConcat(localM);
2385                    }
2386                    shader->setLocalMatrix(tempM);
2387                    // need to recal setContext since we changed the local matrix
2388                    if (!shader->setContext(*fBitmap, p, *fMatrix)) {
2389                        continue;
2390                    }
2391                }
2392            }
2393            if (NULL != colors) {
2394                if (!triShader.setup(vertices, colors,
2395                                     state.f0, state.f1, state.f2)) {
2396                    continue;
2397                }
2398            }
2399            SkScan::FillTriangle(devVerts[state.f0], devVerts[state.f1],
2400                                 devVerts[state.f2], fClip, blitter.get());
2401        }
2402        // now restore the shader's original local matrix
2403        if (NULL != shader) {
2404            if (hasLocalM) {
2405                shader->setLocalMatrix(localM);
2406            } else {
2407                shader->resetLocalMatrix();
2408            }
2409        }
2410    } else {
2411        // no colors[] and no texture
2412        HairProc hairProc = ChooseHairProc(paint.isAntiAlias());
2413        while (vertProc(&state)) {
2414            hairProc(devVerts[state.f0], devVerts[state.f1], fClip, blitter.get());
2415            hairProc(devVerts[state.f1], devVerts[state.f2], fClip, blitter.get());
2416            hairProc(devVerts[state.f2], devVerts[state.f0], fClip, blitter.get());
2417        }
2418    }
2419}
2420
2421///////////////////////////////////////////////////////////////////////////////
2422///////////////////////////////////////////////////////////////////////////////
2423
2424#ifdef SK_DEBUG
2425
2426void SkDraw::validate() const {
2427    SkASSERT(fBitmap != NULL);
2428    SkASSERT(fMatrix != NULL);
2429    SkASSERT(fClip != NULL);
2430
2431    const SkIRect&  cr = fClip->getBounds();
2432    SkIRect         br;
2433
2434    br.set(0, 0, fBitmap->width(), fBitmap->height());
2435    SkASSERT(cr.isEmpty() || br.contains(cr));
2436
2437    // assert that both are null, or both are not-null
2438    SkASSERT(!fMVMatrix == !fExtMatrix);
2439}
2440
2441#endif
2442
2443///////////////////////////////////////////////////////////////////////////////
2444
2445SkBounder::SkBounder() {
2446    // initialize up front. This gets reset by SkCanvas before each draw call.
2447    fClip = &SkRegion::GetEmptyRegion();
2448}
2449
2450bool SkBounder::doIRect(const SkIRect& r) {
2451    SkIRect    rr;
2452    return rr.intersect(fClip->getBounds(), r) && this->onIRect(rr);
2453}
2454
2455// TODO: change the prototype to take fixed, and update the callers
2456bool SkBounder::doIRectGlyph(const SkIRect& r, int x, int y,
2457                             const SkGlyph& glyph) {
2458    SkIRect    rr;
2459    if (!rr.intersect(fClip->getBounds(), r)) {
2460        return false;
2461    }
2462    GlyphRec rec;
2463    rec.fLSB.set(SkIntToFixed(x), SkIntToFixed(y));
2464    rec.fRSB.set(rec.fLSB.fX + glyph.fAdvanceX,
2465                 rec.fLSB.fY + glyph.fAdvanceY);
2466    rec.fGlyphID = glyph.getGlyphID();
2467    rec.fFlags = 0;
2468    return this->onIRectGlyph(rr, rec);
2469}
2470
2471bool SkBounder::doHairline(const SkPoint& pt0, const SkPoint& pt1,
2472                           const SkPaint& paint) {
2473    SkIRect     r;
2474    SkScalar    v0, v1;
2475
2476    v0 = pt0.fX;
2477    v1 = pt1.fX;
2478    if (v0 > v1) {
2479        SkTSwap<SkScalar>(v0, v1);
2480    }
2481    r.fLeft     = SkScalarFloor(v0);
2482    r.fRight    = SkScalarCeil(v1);
2483
2484    v0 = pt0.fY;
2485    v1 = pt1.fY;
2486    if (v0 > v1) {
2487        SkTSwap<SkScalar>(v0, v1);
2488    }
2489    r.fTop      = SkScalarFloor(v0);
2490    r.fBottom   = SkScalarCeil(v1);
2491
2492    if (paint.isAntiAlias()) {
2493        r.inset(-1, -1);
2494    }
2495    return this->doIRect(r);
2496}
2497
2498bool SkBounder::doRect(const SkRect& rect, const SkPaint& paint) {
2499    SkIRect    r;
2500
2501    if (paint.getStyle() == SkPaint::kFill_Style) {
2502        rect.round(&r);
2503    } else {
2504        int rad = -1;
2505        rect.roundOut(&r);
2506        if (paint.isAntiAlias()) {
2507            rad = -2;
2508        }
2509        r.inset(rad, rad);
2510    }
2511    return this->doIRect(r);
2512}
2513
2514bool SkBounder::doPath(const SkPath& path, const SkPaint& paint, bool doFill) {
2515    SkIRect       r;
2516    const SkRect& bounds = path.getBounds();
2517
2518    if (doFill) {
2519        bounds.round(&r);
2520    } else {    // hairline
2521        bounds.roundOut(&r);
2522    }
2523
2524    if (paint.isAntiAlias()) {
2525        r.inset(-1, -1);
2526    }
2527    return this->doIRect(r);
2528}
2529
2530void SkBounder::commit() {
2531    // override in subclass
2532}
2533
2534////////////////////////////////////////////////////////////////////////////////////////////////
2535
2536#include "SkPath.h"
2537#include "SkDraw.h"
2538#include "SkRegion.h"
2539#include "SkBlitter.h"
2540
2541static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds,
2542                           SkMaskFilter* filter, const SkMatrix* filterMatrix,
2543                           SkIRect* bounds) {
2544    if (devPath.isEmpty()) {
2545        return false;
2546    }
2547
2548    SkIPoint   margin;
2549    margin.set(0, 0);
2550
2551    //  init our bounds from the path
2552    {
2553        SkRect pathBounds = devPath.getBounds();
2554        pathBounds.inset(-SK_ScalarHalf, -SK_ScalarHalf);
2555        pathBounds.roundOut(bounds);
2556    }
2557
2558    if (filter) {
2559        SkASSERT(filterMatrix);
2560
2561        SkMask  srcM, dstM;
2562
2563        srcM.fBounds = *bounds;
2564        srcM.fFormat = SkMask::kA8_Format;
2565        srcM.fImage = NULL;
2566        if (!filter->filterMask(&dstM, srcM, *filterMatrix, &margin)) {
2567            return false;
2568        }
2569        *bounds = dstM.fBounds;
2570    }
2571
2572    if (clipBounds && !SkIRect::Intersects(*clipBounds, *bounds)) {
2573        return false;
2574    }
2575
2576    // (possibly) trim the srcM bounds to reflect the clip
2577    // (plus whatever slop the filter needs)
2578    if (clipBounds && !clipBounds->contains(*bounds)) {
2579        SkIRect tmp = *bounds;
2580        (void)tmp.intersect(*clipBounds);
2581        // Ugh. Guard against gigantic margins from wacky filters. Without this
2582        // check we can request arbitrary amounts of slop beyond our visible
2583        // clip, and bring down the renderer (at least on finite RAM machines
2584        // like handsets, etc.). Need to balance this invented value between
2585        // quality of large filters like blurs, and the corresponding memory
2586        // requests.
2587        static const int MAX_MARGIN = 128;
2588        tmp.inset(-SkMin32(margin.fX, MAX_MARGIN),
2589                  -SkMin32(margin.fY, MAX_MARGIN));
2590        (void)bounds->intersect(tmp);
2591    }
2592
2593    return true;
2594}
2595
2596static void draw_into_mask(const SkMask& mask, const SkPath& devPath) {
2597    SkBitmap    bm;
2598    SkDraw      draw;
2599    SkRegion    clipRgn;
2600    SkMatrix    matrix;
2601    SkPaint     paint;
2602
2603    bm.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(), mask.fBounds.height(), mask.fRowBytes);
2604    bm.setPixels(mask.fImage);
2605
2606    clipRgn.setRect(0, 0, mask.fBounds.width(), mask.fBounds.height());
2607    matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
2608                        -SkIntToScalar(mask.fBounds.fTop));
2609
2610    draw.fBitmap    = &bm;
2611    draw.fClip      = &clipRgn;
2612    draw.fMatrix    = &matrix;
2613    draw.fBounder   = NULL;
2614    paint.setAntiAlias(true);
2615    draw.drawPath(devPath, paint);
2616}
2617
2618bool SkDraw::DrawToMask(const SkPath& devPath, const SkIRect* clipBounds,
2619                        SkMaskFilter* filter, const SkMatrix* filterMatrix,
2620                        SkMask* mask, SkMask::CreateMode mode) {
2621    if (SkMask::kJustRenderImage_CreateMode != mode) {
2622        if (!compute_bounds(devPath, clipBounds, filter, filterMatrix, &mask->fBounds))
2623            return false;
2624    }
2625
2626    if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) {
2627        mask->fFormat = SkMask::kA8_Format;
2628        mask->fRowBytes = mask->fBounds.width();
2629        size_t size = mask->computeImageSize();
2630        if (0 == size) {
2631            // we're too big to allocate the mask, abort
2632            return false;
2633        }
2634        mask->fImage = SkMask::AllocImage(size);
2635        memset(mask->fImage, 0, mask->computeImageSize());
2636    }
2637
2638    if (SkMask::kJustComputeBounds_CreateMode != mode) {
2639        draw_into_mask(*mask, devPath);
2640    }
2641
2642    return true;
2643}
2644