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