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