SkDraw.cpp revision 986480a71f4e860663ced7ad90a1fe346a164afb
1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7#define __STDC_LIMIT_MACROS
8
9#include "SkDraw.h"
10#include "SkBlendModePriv.h"
11#include "SkBlitter.h"
12#include "SkCanvas.h"
13#include "SkColorPriv.h"
14#include "SkDevice.h"
15#include "SkDeviceLooper.h"
16#include "SkFindAndPlaceGlyph.h"
17#include "SkFixed.h"
18#include "SkMaskFilter.h"
19#include "SkMatrix.h"
20#include "SkPaint.h"
21#include "SkPathEffect.h"
22#include "SkRasterClip.h"
23#include "SkRasterizer.h"
24#include "SkRRect.h"
25#include "SkScan.h"
26#include "SkShader.h"
27#include "SkSmallAllocator.h"
28#include "SkString.h"
29#include "SkStroke.h"
30#include "SkStrokeRec.h"
31#include "SkTemplates.h"
32#include "SkTextMapStateProc.h"
33#include "SkTLazy.h"
34#include "SkUtils.h"
35#include "SkVertState.h"
36
37#include "SkBitmapProcShader.h"
38#include "SkDrawProcs.h"
39#include "SkMatrixUtils.h"
40
41//#define TRACE_BITMAP_DRAWS
42
43// Helper function to fix code gen bug on ARM64.
44// See SkFindAndPlaceGlyph.h for more details.
45void FixGCC49Arm64Bug(int v) { }
46
47/** Helper for allocating small blitters on the stack.
48 */
49class SkAutoBlitterChoose : SkNoncopyable {
50public:
51    SkAutoBlitterChoose() {
52        fBlitter = nullptr;
53    }
54    SkAutoBlitterChoose(const SkPixmap& dst, const SkMatrix& matrix,
55                        const SkPaint& paint, bool drawCoverage = false) {
56        fBlitter = SkBlitter::Choose(dst, matrix, paint, &fAllocator, drawCoverage);
57    }
58
59    SkBlitter*  operator->() { return fBlitter; }
60    SkBlitter*  get() const { return fBlitter; }
61
62    void choose(const SkPixmap& dst, const SkMatrix& matrix,
63                const SkPaint& paint, bool drawCoverage = false) {
64        SkASSERT(!fBlitter);
65        fBlitter = SkBlitter::Choose(dst, matrix, paint, &fAllocator, drawCoverage);
66    }
67
68private:
69    // Owned by fAllocator, which will handle the delete.
70    SkBlitter*          fBlitter;
71    SkTBlitterAllocator fAllocator;
72};
73#define SkAutoBlitterChoose(...) SK_REQUIRE_LOCAL_VAR(SkAutoBlitterChoose)
74
75/**
76 *  Since we are providing the storage for the shader (to avoid the perf cost
77 *  of calling new) we insist that in our destructor we can account for all
78 *  owners of the shader.
79 */
80class SkAutoBitmapShaderInstall : SkNoncopyable {
81public:
82    SkAutoBitmapShaderInstall(const SkBitmap& src, const SkPaint& paint,
83                              const SkMatrix* localMatrix = nullptr)
84            : fPaint(paint) /* makes a copy of the paint */ {
85        fPaint.setShader(SkMakeBitmapShader(src, SkShader::kClamp_TileMode,
86                                            SkShader::kClamp_TileMode, localMatrix,
87                                            kNever_SkCopyPixelsMode,
88                                            &fAllocator));
89        // we deliberately left the shader with an owner-count of 2
90        fPaint.getShader()->ref();
91        SkASSERT(2 == fPaint.getShader()->getRefCnt());
92    }
93
94    ~SkAutoBitmapShaderInstall() {
95        // since fAllocator will destroy shader, we insist that owners == 2
96        SkASSERT(2 == fPaint.getShader()->getRefCnt());
97
98        fPaint.setShader(nullptr); // unref the shader by 1
99
100    }
101
102    // return the new paint that has the shader applied
103    const SkPaint& paintWithShader() const { return fPaint; }
104
105private:
106    // copy of caller's paint (which we then modify)
107    SkPaint             fPaint;
108    // Stores the shader.
109    SkTBlitterAllocator fAllocator;
110};
111#define SkAutoBitmapShaderInstall(...) SK_REQUIRE_LOCAL_VAR(SkAutoBitmapShaderInstall)
112
113///////////////////////////////////////////////////////////////////////////////
114
115SkDraw::SkDraw() {
116    sk_bzero(this, sizeof(*this));
117}
118
119bool SkDraw::computeConservativeLocalClipBounds(SkRect* localBounds) const {
120    if (fRC->isEmpty()) {
121        return false;
122    }
123
124    SkMatrix inverse;
125    if (!fMatrix->invert(&inverse)) {
126        return false;
127    }
128
129    SkIRect devBounds = fRC->getBounds();
130    // outset to have slop for antialasing and hairlines
131    devBounds.outset(1, 1);
132    inverse.mapRect(localBounds, SkRect::Make(devBounds));
133    return true;
134}
135
136///////////////////////////////////////////////////////////////////////////////
137
138typedef void (*BitmapXferProc)(void* pixels, size_t bytes, uint32_t data);
139
140static void D_Clear_BitmapXferProc(void* pixels, size_t bytes, uint32_t) {
141    sk_bzero(pixels, bytes);
142}
143
144static void D_Dst_BitmapXferProc(void*, size_t, uint32_t data) {}
145
146static void D32_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
147    sk_memset32((uint32_t*)pixels, data, SkToInt(bytes >> 2));
148}
149
150static void D16_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
151    sk_memset16((uint16_t*)pixels, data, SkToInt(bytes >> 1));
152}
153
154static void DA8_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
155    memset(pixels, data, bytes);
156}
157
158static BitmapXferProc ChooseBitmapXferProc(const SkPixmap& dst, const SkPaint& paint,
159                                           uint32_t* data) {
160    // todo: we can apply colorfilter up front if no shader, so we wouldn't
161    // need to abort this fastpath
162    if (paint.getShader() || paint.getColorFilter()) {
163        return nullptr;
164    }
165
166    SkBlendMode mode = paint.getBlendMode();
167    SkColor color = paint.getColor();
168
169    // collaps modes based on color...
170    if (SkBlendMode::kSrcOver == mode) {
171        unsigned alpha = SkColorGetA(color);
172        if (0 == alpha) {
173            mode = SkBlendMode::kDst;
174        } else if (0xFF == alpha) {
175            mode = SkBlendMode::kSrc;
176        }
177    }
178
179    switch (mode) {
180        case SkBlendMode::kClear:
181//            SkDebugf("--- D_Clear_BitmapXferProc\n");
182            return D_Clear_BitmapXferProc;  // ignore data
183        case SkBlendMode::kDst:
184//            SkDebugf("--- D_Dst_BitmapXferProc\n");
185            return D_Dst_BitmapXferProc;    // ignore data
186        case SkBlendMode::kSrc: {
187            /*
188                should I worry about dithering for the lower depths?
189            */
190            SkPMColor pmc = SkPreMultiplyColor(color);
191            switch (dst.colorType()) {
192                case kN32_SkColorType:
193                    if (data) {
194                        *data = pmc;
195                    }
196//                    SkDebugf("--- D32_Src_BitmapXferProc\n");
197                    return D32_Src_BitmapXferProc;
198                case kRGB_565_SkColorType:
199                    if (data) {
200                        *data = SkPixel32ToPixel16(pmc);
201                    }
202//                    SkDebugf("--- D16_Src_BitmapXferProc\n");
203                    return D16_Src_BitmapXferProc;
204                case kAlpha_8_SkColorType:
205                    if (data) {
206                        *data = SkGetPackedA32(pmc);
207                    }
208//                    SkDebugf("--- DA8_Src_BitmapXferProc\n");
209                    return DA8_Src_BitmapXferProc;
210                default:
211                    break;
212            }
213            break;
214        }
215        default:
216            break;
217    }
218    return nullptr;
219}
220
221static void CallBitmapXferProc(const SkPixmap& dst, const SkIRect& rect, BitmapXferProc proc,
222                               uint32_t procData) {
223    int shiftPerPixel;
224    switch (dst.colorType()) {
225        case kN32_SkColorType:
226            shiftPerPixel = 2;
227            break;
228        case kRGB_565_SkColorType:
229            shiftPerPixel = 1;
230            break;
231        case kAlpha_8_SkColorType:
232            shiftPerPixel = 0;
233            break;
234        default:
235            SkDEBUGFAIL("Can't use xferproc on this config");
236            return;
237    }
238
239    uint8_t* pixels = (uint8_t*)dst.writable_addr();
240    SkASSERT(pixels);
241    const size_t rowBytes = dst.rowBytes();
242    const int widthBytes = rect.width() << shiftPerPixel;
243
244    // skip down to the first scanline and X position
245    pixels += rect.fTop * rowBytes + (rect.fLeft << shiftPerPixel);
246    for (int scans = rect.height() - 1; scans >= 0; --scans) {
247        proc(pixels, widthBytes, procData);
248        pixels += rowBytes;
249    }
250}
251
252void SkDraw::drawPaint(const SkPaint& paint) const {
253    SkDEBUGCODE(this->validate();)
254
255    if (fRC->isEmpty()) {
256        return;
257    }
258
259    SkIRect    devRect;
260    devRect.set(0, 0, fDst.width(), fDst.height());
261
262    if (fRC->isBW()) {
263        /*  If we don't have a shader (i.e. we're just a solid color) we may
264            be faster to operate directly on the device bitmap, rather than invoking
265            a blitter. Esp. true for xfermodes, which require a colorshader to be
266            present, which is just redundant work. Since we're drawing everywhere
267            in the clip, we don't have to worry about antialiasing.
268        */
269        uint32_t procData = 0;  // to avoid the warning
270        BitmapXferProc proc = ChooseBitmapXferProc(fDst, paint, &procData);
271        if (proc) {
272            if (D_Dst_BitmapXferProc == proc) { // nothing to do
273                return;
274            }
275
276            SkRegion::Iterator iter(fRC->bwRgn());
277            while (!iter.done()) {
278                CallBitmapXferProc(fDst, iter.rect(), proc, procData);
279                iter.next();
280            }
281            return;
282        }
283    }
284
285    // normal case: use a blitter
286    SkAutoBlitterChoose blitter(fDst, *fMatrix, paint);
287    SkScan::FillIRect(devRect, *fRC, blitter.get());
288}
289
290///////////////////////////////////////////////////////////////////////////////
291
292struct PtProcRec {
293    SkCanvas::PointMode fMode;
294    const SkPaint*  fPaint;
295    const SkRegion* fClip;
296    const SkRasterClip* fRC;
297
298    // computed values
299    SkFixed fRadius;
300
301    typedef void (*Proc)(const PtProcRec&, const SkPoint devPts[], int count,
302                         SkBlitter*);
303
304    bool init(SkCanvas::PointMode, const SkPaint&, const SkMatrix* matrix,
305              const SkRasterClip*);
306    Proc chooseProc(SkBlitter** blitter);
307
308private:
309    SkAAClipBlitterWrapper fWrapper;
310};
311
312static void bw_pt_rect_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
313                                 int count, SkBlitter* blitter) {
314    SkASSERT(rec.fClip->isRect());
315    const SkIRect& r = rec.fClip->getBounds();
316
317    for (int i = 0; i < count; i++) {
318        int x = SkScalarFloorToInt(devPts[i].fX);
319        int y = SkScalarFloorToInt(devPts[i].fY);
320        if (r.contains(x, y)) {
321            blitter->blitH(x, y, 1);
322        }
323    }
324}
325
326static void bw_pt_rect_16_hair_proc(const PtProcRec& rec,
327                                    const SkPoint devPts[], int count,
328                                    SkBlitter* blitter) {
329    SkASSERT(rec.fRC->isRect());
330    const SkIRect& r = rec.fRC->getBounds();
331    uint32_t value;
332    const SkPixmap* dst = blitter->justAnOpaqueColor(&value);
333    SkASSERT(dst);
334
335    uint16_t* addr = dst->writable_addr16(0, 0);
336    size_t    rb = dst->rowBytes();
337
338    for (int i = 0; i < count; i++) {
339        int x = SkScalarFloorToInt(devPts[i].fX);
340        int y = SkScalarFloorToInt(devPts[i].fY);
341        if (r.contains(x, y)) {
342            ((uint16_t*)((char*)addr + y * rb))[x] = SkToU16(value);
343        }
344    }
345}
346
347static void bw_pt_rect_32_hair_proc(const PtProcRec& rec,
348                                    const SkPoint devPts[], int count,
349                                    SkBlitter* blitter) {
350    SkASSERT(rec.fRC->isRect());
351    const SkIRect& r = rec.fRC->getBounds();
352    uint32_t value;
353    const SkPixmap* dst = blitter->justAnOpaqueColor(&value);
354    SkASSERT(dst);
355
356    SkPMColor* addr = dst->writable_addr32(0, 0);
357    size_t     rb = dst->rowBytes();
358
359    for (int i = 0; i < count; i++) {
360        int x = SkScalarFloorToInt(devPts[i].fX);
361        int y = SkScalarFloorToInt(devPts[i].fY);
362        if (r.contains(x, y)) {
363            ((SkPMColor*)((char*)addr + y * rb))[x] = value;
364        }
365    }
366}
367
368static void bw_pt_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
369                            int count, SkBlitter* blitter) {
370    for (int i = 0; i < count; i++) {
371        int x = SkScalarFloorToInt(devPts[i].fX);
372        int y = SkScalarFloorToInt(devPts[i].fY);
373        if (rec.fClip->contains(x, y)) {
374            blitter->blitH(x, y, 1);
375        }
376    }
377}
378
379static void bw_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
380                              int count, SkBlitter* blitter) {
381    for (int i = 0; i < count; i += 2) {
382        SkScan::HairLine(&devPts[i], 2, *rec.fRC, blitter);
383    }
384}
385
386static void bw_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
387                              int count, SkBlitter* blitter) {
388    SkScan::HairLine(devPts, count, *rec.fRC, blitter);
389}
390
391// aa versions
392
393static void aa_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
394                              int count, SkBlitter* blitter) {
395    for (int i = 0; i < count; i += 2) {
396        SkScan::AntiHairLine(&devPts[i], 2, *rec.fRC, blitter);
397    }
398}
399
400static void aa_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
401                              int count, SkBlitter* blitter) {
402    SkScan::AntiHairLine(devPts, count, *rec.fRC, blitter);
403}
404
405// square procs (strokeWidth > 0 but matrix is square-scale (sx == sy)
406
407static void bw_square_proc(const PtProcRec& rec, const SkPoint devPts[],
408                           int count, SkBlitter* blitter) {
409    const SkFixed radius = rec.fRadius;
410    for (int i = 0; i < count; i++) {
411        SkFixed x = SkScalarToFixed(devPts[i].fX);
412        SkFixed y = SkScalarToFixed(devPts[i].fY);
413
414        SkXRect r;
415        r.fLeft = x - radius;
416        r.fTop = y - radius;
417        r.fRight = x + radius;
418        r.fBottom = y + radius;
419
420        SkScan::FillXRect(r, *rec.fRC, blitter);
421    }
422}
423
424static void aa_square_proc(const PtProcRec& rec, const SkPoint devPts[],
425                           int count, SkBlitter* blitter) {
426    const SkFixed radius = rec.fRadius;
427    for (int i = 0; i < count; i++) {
428        SkFixed x = SkScalarToFixed(devPts[i].fX);
429        SkFixed y = SkScalarToFixed(devPts[i].fY);
430
431        SkXRect r;
432        r.fLeft = x - radius;
433        r.fTop = y - radius;
434        r.fRight = x + radius;
435        r.fBottom = y + radius;
436
437        SkScan::AntiFillXRect(r, *rec.fRC, blitter);
438    }
439}
440
441// If this guy returns true, then chooseProc() must return a valid proc
442bool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint,
443                     const SkMatrix* matrix, const SkRasterClip* rc) {
444    if ((unsigned)mode > (unsigned)SkCanvas::kPolygon_PointMode) {
445        return false;
446    }
447
448    if (paint.getPathEffect()) {
449        return false;
450    }
451    SkScalar width = paint.getStrokeWidth();
452    if (0 == width) {
453        fMode = mode;
454        fPaint = &paint;
455        fClip = nullptr;
456        fRC = rc;
457        fRadius = SK_FixedHalf;
458        return true;
459    }
460    if (paint.getStrokeCap() != SkPaint::kRound_Cap &&
461        matrix->isScaleTranslate() && SkCanvas::kPoints_PointMode == mode) {
462        SkScalar sx = matrix->get(SkMatrix::kMScaleX);
463        SkScalar sy = matrix->get(SkMatrix::kMScaleY);
464        if (SkScalarNearlyZero(sx - sy)) {
465            if (sx < 0) {
466                sx = -sx;
467            }
468
469            fMode = mode;
470            fPaint = &paint;
471            fClip = nullptr;
472            fRC = rc;
473            fRadius = SkScalarToFixed(SkScalarMul(width, sx)) >> 1;
474            return true;
475        }
476    }
477    return false;
478}
479
480PtProcRec::Proc PtProcRec::chooseProc(SkBlitter** blitterPtr) {
481    Proc proc = nullptr;
482
483    SkBlitter* blitter = *blitterPtr;
484    if (fRC->isBW()) {
485        fClip = &fRC->bwRgn();
486    } else {
487        fWrapper.init(*fRC, blitter);
488        fClip = &fWrapper.getRgn();
489        blitter = fWrapper.getBlitter();
490        *blitterPtr = blitter;
491    }
492
493    // for our arrays
494    SkASSERT(0 == SkCanvas::kPoints_PointMode);
495    SkASSERT(1 == SkCanvas::kLines_PointMode);
496    SkASSERT(2 == SkCanvas::kPolygon_PointMode);
497    SkASSERT((unsigned)fMode <= (unsigned)SkCanvas::kPolygon_PointMode);
498
499    if (fPaint->isAntiAlias()) {
500        if (0 == fPaint->getStrokeWidth()) {
501            static const Proc gAAProcs[] = {
502                aa_square_proc, aa_line_hair_proc, aa_poly_hair_proc
503            };
504            proc = gAAProcs[fMode];
505        } else if (fPaint->getStrokeCap() != SkPaint::kRound_Cap) {
506            SkASSERT(SkCanvas::kPoints_PointMode == fMode);
507            proc = aa_square_proc;
508        }
509    } else {    // BW
510        if (fRadius <= SK_FixedHalf) {    // small radii and hairline
511            if (SkCanvas::kPoints_PointMode == fMode && fClip->isRect()) {
512                uint32_t value;
513                const SkPixmap* bm = blitter->justAnOpaqueColor(&value);
514                if (bm && kRGB_565_SkColorType == bm->colorType()) {
515                    proc = bw_pt_rect_16_hair_proc;
516                } else if (bm && kN32_SkColorType == bm->colorType()) {
517                    proc = bw_pt_rect_32_hair_proc;
518                } else {
519                    proc = bw_pt_rect_hair_proc;
520                }
521            } else {
522                static Proc gBWProcs[] = {
523                    bw_pt_hair_proc, bw_line_hair_proc, bw_poly_hair_proc
524                };
525                proc = gBWProcs[fMode];
526            }
527        } else {
528            proc = bw_square_proc;
529        }
530    }
531    return proc;
532}
533
534// each of these costs 8-bytes of stack space, so don't make it too large
535// must be even for lines/polygon to work
536#define MAX_DEV_PTS     32
537
538void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count,
539                        const SkPoint pts[], const SkPaint& paint,
540                        bool forceUseDevice) const {
541    // if we're in lines mode, force count to be even
542    if (SkCanvas::kLines_PointMode == mode) {
543        count &= ~(size_t)1;
544    }
545
546    if ((long)count <= 0) {
547        return;
548    }
549
550    SkASSERT(pts != nullptr);
551    SkDEBUGCODE(this->validate();)
552
553     // nothing to draw
554    if (fRC->isEmpty()) {
555        return;
556    }
557
558    PtProcRec rec;
559    if (!forceUseDevice && rec.init(mode, paint, fMatrix, fRC)) {
560        SkAutoBlitterChoose blitter(fDst, *fMatrix, paint);
561
562        SkPoint             devPts[MAX_DEV_PTS];
563        const SkMatrix*     matrix = fMatrix;
564        SkBlitter*          bltr = blitter.get();
565        PtProcRec::Proc     proc = rec.chooseProc(&bltr);
566        // we have to back up subsequent passes if we're in polygon mode
567        const size_t backup = (SkCanvas::kPolygon_PointMode == mode);
568
569        do {
570            int n = SkToInt(count);
571            if (n > MAX_DEV_PTS) {
572                n = MAX_DEV_PTS;
573            }
574            matrix->mapPoints(devPts, pts, n);
575            proc(rec, devPts, n, bltr);
576            pts += n - backup;
577            SkASSERT(SkToInt(count) >= n);
578            count -= n;
579            if (count > 0) {
580                count += backup;
581            }
582        } while (count != 0);
583    } else {
584        switch (mode) {
585            case SkCanvas::kPoints_PointMode: {
586                // temporarily mark the paint as filling.
587                SkPaint newPaint(paint);
588                newPaint.setStyle(SkPaint::kFill_Style);
589
590                SkScalar width = newPaint.getStrokeWidth();
591                SkScalar radius = SkScalarHalf(width);
592
593                if (newPaint.getStrokeCap() == SkPaint::kRound_Cap) {
594                    SkPath      path;
595                    SkMatrix    preMatrix;
596
597                    path.addCircle(0, 0, radius);
598                    for (size_t i = 0; i < count; i++) {
599                        preMatrix.setTranslate(pts[i].fX, pts[i].fY);
600                        // pass true for the last point, since we can modify
601                        // then path then
602                        path.setIsVolatile((count-1) == i);
603                        if (fDevice) {
604                            fDevice->drawPath(*this, path, newPaint, &preMatrix,
605                                              (count-1) == i);
606                        } else {
607                            this->drawPath(path, newPaint, &preMatrix,
608                                           (count-1) == i);
609                        }
610                    }
611                } else {
612                    SkRect  r;
613
614                    for (size_t i = 0; i < count; i++) {
615                        r.fLeft = pts[i].fX - radius;
616                        r.fTop = pts[i].fY - radius;
617                        r.fRight = r.fLeft + width;
618                        r.fBottom = r.fTop + width;
619                        if (fDevice) {
620                            fDevice->drawRect(*this, r, newPaint);
621                        } else {
622                            this->drawRect(r, newPaint);
623                        }
624                    }
625                }
626                break;
627            }
628            case SkCanvas::kLines_PointMode:
629                if (2 == count && paint.getPathEffect()) {
630                    // most likely a dashed line - see if it is one of the ones
631                    // we can accelerate
632                    SkStrokeRec rec(paint);
633                    SkPathEffect::PointData pointData;
634
635                    SkPath path;
636                    path.moveTo(pts[0]);
637                    path.lineTo(pts[1]);
638
639                    SkRect cullRect = SkRect::Make(fRC->getBounds());
640
641                    if (paint.getPathEffect()->asPoints(&pointData, path, rec,
642                                                        *fMatrix, &cullRect)) {
643                        // 'asPoints' managed to find some fast path
644
645                        SkPaint newP(paint);
646                        newP.setPathEffect(nullptr);
647                        newP.setStyle(SkPaint::kFill_Style);
648
649                        if (!pointData.fFirst.isEmpty()) {
650                            if (fDevice) {
651                                fDevice->drawPath(*this, pointData.fFirst, newP);
652                            } else {
653                                this->drawPath(pointData.fFirst, newP);
654                            }
655                        }
656
657                        if (!pointData.fLast.isEmpty()) {
658                            if (fDevice) {
659                                fDevice->drawPath(*this, pointData.fLast, newP);
660                            } else {
661                                this->drawPath(pointData.fLast, newP);
662                            }
663                        }
664
665                        if (pointData.fSize.fX == pointData.fSize.fY) {
666                            // The rest of the dashed line can just be drawn as points
667                            SkASSERT(pointData.fSize.fX == SkScalarHalf(newP.getStrokeWidth()));
668
669                            if (SkPathEffect::PointData::kCircles_PointFlag & pointData.fFlags) {
670                                newP.setStrokeCap(SkPaint::kRound_Cap);
671                            } else {
672                                newP.setStrokeCap(SkPaint::kButt_Cap);
673                            }
674
675                            if (fDevice) {
676                                fDevice->drawPoints(*this,
677                                                    SkCanvas::kPoints_PointMode,
678                                                    pointData.fNumPoints,
679                                                    pointData.fPoints,
680                                                    newP);
681                            } else {
682                                this->drawPoints(SkCanvas::kPoints_PointMode,
683                                                 pointData.fNumPoints,
684                                                 pointData.fPoints,
685                                                 newP,
686                                                 forceUseDevice);
687                            }
688                            break;
689                        } else {
690                            // The rest of the dashed line must be drawn as rects
691                            SkASSERT(!(SkPathEffect::PointData::kCircles_PointFlag &
692                                      pointData.fFlags));
693
694                            SkRect r;
695
696                            for (int i = 0; i < pointData.fNumPoints; ++i) {
697                                r.set(pointData.fPoints[i].fX - pointData.fSize.fX,
698                                      pointData.fPoints[i].fY - pointData.fSize.fY,
699                                      pointData.fPoints[i].fX + pointData.fSize.fX,
700                                      pointData.fPoints[i].fY + pointData.fSize.fY);
701                                if (fDevice) {
702                                    fDevice->drawRect(*this, r, newP);
703                                } else {
704                                    this->drawRect(r, newP);
705                                }
706                            }
707                        }
708
709                        break;
710                    }
711                }
712                // couldn't take fast path so fall through!
713            case SkCanvas::kPolygon_PointMode: {
714                count -= 1;
715                SkPath path;
716                SkPaint p(paint);
717                p.setStyle(SkPaint::kStroke_Style);
718                size_t inc = (SkCanvas::kLines_PointMode == mode) ? 2 : 1;
719                path.setIsVolatile(true);
720                for (size_t i = 0; i < count; i += inc) {
721                    path.moveTo(pts[i]);
722                    path.lineTo(pts[i+1]);
723                    if (fDevice) {
724                        fDevice->drawPath(*this, path, p, nullptr, true);
725                    } else {
726                        this->drawPath(path, p, nullptr, true);
727                    }
728                    path.rewind();
729                }
730                break;
731            }
732        }
733    }
734}
735
736static inline SkPoint compute_stroke_size(const SkPaint& paint, const SkMatrix& matrix) {
737    SkASSERT(matrix.rectStaysRect());
738    SkASSERT(SkPaint::kFill_Style != paint.getStyle());
739
740    SkVector size;
741    SkPoint pt = { paint.getStrokeWidth(), paint.getStrokeWidth() };
742    matrix.mapVectors(&size, &pt, 1);
743    return SkPoint::Make(SkScalarAbs(size.fX), SkScalarAbs(size.fY));
744}
745
746static bool easy_rect_join(const SkPaint& paint, const SkMatrix& matrix,
747                           SkPoint* strokeSize) {
748    if (SkPaint::kMiter_Join != paint.getStrokeJoin() ||
749        paint.getStrokeMiter() < SK_ScalarSqrt2) {
750        return false;
751    }
752
753    *strokeSize = compute_stroke_size(paint, matrix);
754    return true;
755}
756
757SkDraw::RectType SkDraw::ComputeRectType(const SkPaint& paint,
758                                         const SkMatrix& matrix,
759                                         SkPoint* strokeSize) {
760    RectType rtype;
761    const SkScalar width = paint.getStrokeWidth();
762    const bool zeroWidth = (0 == width);
763    SkPaint::Style style = paint.getStyle();
764
765    if ((SkPaint::kStrokeAndFill_Style == style) && zeroWidth) {
766        style = SkPaint::kFill_Style;
767    }
768
769    if (paint.getPathEffect() || paint.getMaskFilter() ||
770        paint.getRasterizer() || !matrix.rectStaysRect() ||
771        SkPaint::kStrokeAndFill_Style == style) {
772        rtype = kPath_RectType;
773    } else if (SkPaint::kFill_Style == style) {
774        rtype = kFill_RectType;
775    } else if (zeroWidth) {
776        rtype = kHair_RectType;
777    } else if (easy_rect_join(paint, matrix, strokeSize)) {
778        rtype = kStroke_RectType;
779    } else {
780        rtype = kPath_RectType;
781    }
782    return rtype;
783}
784
785static const SkPoint* rect_points(const SkRect& r) {
786    return SkTCast<const SkPoint*>(&r);
787}
788
789static SkPoint* rect_points(SkRect& r) {
790    return SkTCast<SkPoint*>(&r);
791}
792
793void SkDraw::drawRect(const SkRect& prePaintRect, const SkPaint& paint,
794                      const SkMatrix* paintMatrix, const SkRect* postPaintRect) const {
795    SkDEBUGCODE(this->validate();)
796
797    // nothing to draw
798    if (fRC->isEmpty()) {
799        return;
800    }
801
802    const SkMatrix* matrix;
803    SkMatrix combinedMatrixStorage;
804    if (paintMatrix) {
805        SkASSERT(postPaintRect);
806        combinedMatrixStorage.setConcat(*fMatrix, *paintMatrix);
807        matrix = &combinedMatrixStorage;
808    } else {
809        SkASSERT(!postPaintRect);
810        matrix = fMatrix;
811    }
812
813    SkPoint strokeSize;
814    RectType rtype = ComputeRectType(paint, *fMatrix, &strokeSize);
815
816    if (kPath_RectType == rtype) {
817        SkDraw draw(*this);
818        if (paintMatrix) {
819            draw.fMatrix = matrix;
820        }
821        SkPath  tmp;
822        tmp.addRect(prePaintRect);
823        tmp.setFillType(SkPath::kWinding_FillType);
824        draw.drawPath(tmp, paint, nullptr, true);
825        return;
826    }
827
828    SkRect devRect;
829    const SkRect& paintRect = paintMatrix ? *postPaintRect : prePaintRect;
830    // skip the paintMatrix when transforming the rect by the CTM
831    fMatrix->mapPoints(rect_points(devRect), rect_points(paintRect), 2);
832    devRect.sort();
833
834    // look for the quick exit, before we build a blitter
835    SkRect bbox = devRect;
836    if (paint.getStyle() != SkPaint::kFill_Style) {
837        // extra space for hairlines
838        if (paint.getStrokeWidth() == 0) {
839            bbox.outset(1, 1);
840        } else {
841            // For kStroke_RectType, strokeSize is already computed.
842            const SkPoint& ssize = (kStroke_RectType == rtype)
843                ? strokeSize
844                : compute_stroke_size(paint, *fMatrix);
845            bbox.outset(SkScalarHalf(ssize.x()), SkScalarHalf(ssize.y()));
846        }
847    }
848
849    SkIRect ir = bbox.roundOut();
850    if (fRC->quickReject(ir)) {
851        return;
852    }
853
854    SkDeviceLooper looper(fDst, *fRC, ir, paint.isAntiAlias());
855    while (looper.next()) {
856        SkRect localDevRect;
857        looper.mapRect(&localDevRect, devRect);
858        SkMatrix localMatrix;
859        looper.mapMatrix(&localMatrix, *matrix);
860
861        SkAutoBlitterChoose blitterStorage(looper.getPixmap(), localMatrix, paint);
862        const SkRasterClip& clip = looper.getRC();
863        SkBlitter*          blitter = blitterStorage.get();
864
865        // we want to "fill" if we are kFill or kStrokeAndFill, since in the latter
866        // case we are also hairline (if we've gotten to here), which devolves to
867        // effectively just kFill
868        switch (rtype) {
869            case kFill_RectType:
870                if (paint.isAntiAlias()) {
871                    SkScan::AntiFillRect(localDevRect, clip, blitter);
872                } else {
873                    SkScan::FillRect(localDevRect, clip, blitter);
874                }
875                break;
876            case kStroke_RectType:
877                if (paint.isAntiAlias()) {
878                    SkScan::AntiFrameRect(localDevRect, strokeSize, clip, blitter);
879                } else {
880                    SkScan::FrameRect(localDevRect, strokeSize, clip, blitter);
881                }
882                break;
883            case kHair_RectType:
884                if (paint.isAntiAlias()) {
885                    SkScan::AntiHairRect(localDevRect, clip, blitter);
886                } else {
887                    SkScan::HairRect(localDevRect, clip, blitter);
888                }
889                break;
890            default:
891                SkDEBUGFAIL("bad rtype");
892        }
893    }
894}
895
896void SkDraw::drawDevMask(const SkMask& srcM, const SkPaint& paint) const {
897    if (srcM.fBounds.isEmpty()) {
898        return;
899    }
900
901    const SkMask* mask = &srcM;
902
903    SkMask dstM;
904    if (paint.getMaskFilter() &&
905        paint.getMaskFilter()->filterMask(&dstM, srcM, *fMatrix, nullptr)) {
906        mask = &dstM;
907    }
908    SkAutoMaskFreeImage ami(dstM.fImage);
909
910    SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint);
911    SkBlitter* blitter = blitterChooser.get();
912
913    SkAAClipBlitterWrapper wrapper;
914    const SkRegion* clipRgn;
915
916    if (fRC->isBW()) {
917        clipRgn = &fRC->bwRgn();
918    } else {
919        wrapper.init(*fRC, blitter);
920        clipRgn = &wrapper.getRgn();
921        blitter = wrapper.getBlitter();
922    }
923    blitter->blitMaskRegion(*mask, *clipRgn);
924}
925
926static SkScalar fast_len(const SkVector& vec) {
927    SkScalar x = SkScalarAbs(vec.fX);
928    SkScalar y = SkScalarAbs(vec.fY);
929    if (x < y) {
930        SkTSwap(x, y);
931    }
932    return x + SkScalarHalf(y);
933}
934
935bool SkDrawTreatAAStrokeAsHairline(SkScalar strokeWidth, const SkMatrix& matrix,
936                                   SkScalar* coverage) {
937    SkASSERT(strokeWidth > 0);
938    // We need to try to fake a thick-stroke with a modulated hairline.
939
940    if (matrix.hasPerspective()) {
941        return false;
942    }
943
944    SkVector src[2], dst[2];
945    src[0].set(strokeWidth, 0);
946    src[1].set(0, strokeWidth);
947    matrix.mapVectors(dst, src, 2);
948    SkScalar len0 = fast_len(dst[0]);
949    SkScalar len1 = fast_len(dst[1]);
950    if (len0 <= SK_Scalar1 && len1 <= SK_Scalar1) {
951        if (coverage) {
952            *coverage = SkScalarAve(len0, len1);
953        }
954        return true;
955    }
956    return false;
957}
958
959void SkDraw::drawRRect(const SkRRect& rrect, const SkPaint& paint) const {
960    SkDEBUGCODE(this->validate());
961
962    if (fRC->isEmpty()) {
963        return;
964    }
965
966    {
967        // TODO: Investigate optimizing these options. They are in the same
968        // order as SkDraw::drawPath, which handles each case. It may be
969        // that there is no way to optimize for these using the SkRRect path.
970        SkScalar coverage;
971        if (SkDrawTreatAsHairline(paint, *fMatrix, &coverage)) {
972            goto DRAW_PATH;
973        }
974
975        if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
976            goto DRAW_PATH;
977        }
978
979        if (paint.getRasterizer()) {
980            goto DRAW_PATH;
981        }
982    }
983
984    if (paint.getMaskFilter()) {
985        // Transform the rrect into device space.
986        SkRRect devRRect;
987        if (rrect.transform(*fMatrix, &devRRect)) {
988            SkAutoBlitterChoose blitter(fDst, *fMatrix, paint);
989            if (paint.getMaskFilter()->filterRRect(devRRect, *fMatrix, *fRC, blitter.get())) {
990                return; // filterRRect() called the blitter, so we're done
991            }
992        }
993    }
994
995DRAW_PATH:
996    // Now fall back to the default case of using a path.
997    SkPath path;
998    path.addRRect(rrect);
999    this->drawPath(path, paint, nullptr, true);
1000}
1001
1002SkScalar SkDraw::ComputeResScaleForStroking(const SkMatrix& matrix) {
1003    if (!matrix.hasPerspective()) {
1004        SkScalar sx = SkPoint::Length(matrix[SkMatrix::kMScaleX], matrix[SkMatrix::kMSkewY]);
1005        SkScalar sy = SkPoint::Length(matrix[SkMatrix::kMSkewX],  matrix[SkMatrix::kMScaleY]);
1006        if (SkScalarsAreFinite(sx, sy)) {
1007            SkScalar scale = SkTMax(sx, sy);
1008            if (scale > 0) {
1009                return scale;
1010            }
1011        }
1012    }
1013    return 1;
1014}
1015
1016void SkDraw::drawDevPath(const SkPath& devPath, const SkPaint& paint, bool drawCoverage,
1017                         SkBlitter* customBlitter, bool doFill) const {
1018    // Do a conservative quick-reject test, since a looper or other modifier may have moved us
1019    // out of range.
1020    if (!devPath.isInverseFillType()) {
1021        // If we're a H or V line, our bounds will be empty. So we bloat here just so we don't
1022        // appear empty to the intersects call. This also gives us slop in case we're antialiasing
1023        SkRect pathBounds = devPath.getBounds().makeOutset(1, 1);
1024
1025        if (paint.getMaskFilter()) {
1026            paint.getMaskFilter()->computeFastBounds(pathBounds, &pathBounds);
1027
1028            // Need to outset the path to work-around a bug in blurmaskfilter. When that is fixed
1029            // we can remove this hack. See skbug.com/5542
1030            pathBounds.outset(7, 7);
1031        }
1032
1033        // Now compare against the clip's bounds
1034        if (!SkRect::Make(fRC->getBounds()).intersects(pathBounds)) {
1035            return;
1036        }
1037    }
1038
1039    SkBlitter* blitter = nullptr;
1040    SkAutoBlitterChoose blitterStorage;
1041    if (nullptr == customBlitter) {
1042        blitterStorage.choose(fDst, *fMatrix, paint, drawCoverage);
1043        blitter = blitterStorage.get();
1044    } else {
1045        blitter = customBlitter;
1046    }
1047
1048    if (paint.getMaskFilter()) {
1049        SkStrokeRec::InitStyle style = doFill ? SkStrokeRec::kFill_InitStyle
1050        : SkStrokeRec::kHairline_InitStyle;
1051        if (paint.getMaskFilter()->filterPath(devPath, *fMatrix, *fRC, blitter, style)) {
1052            return; // filterPath() called the blitter, so we're done
1053        }
1054    }
1055
1056    void (*proc)(const SkPath&, const SkRasterClip&, SkBlitter*);
1057    if (doFill) {
1058        if (paint.isAntiAlias()) {
1059            proc = SkScan::AntiFillPath;
1060        } else {
1061            proc = SkScan::FillPath;
1062        }
1063    } else {    // hairline
1064        if (paint.isAntiAlias()) {
1065            switch (paint.getStrokeCap()) {
1066                case SkPaint::kButt_Cap:
1067                    proc = SkScan::AntiHairPath;
1068                    break;
1069                case SkPaint::kSquare_Cap:
1070                    proc = SkScan::AntiHairSquarePath;
1071                    break;
1072                case SkPaint::kRound_Cap:
1073                    proc = SkScan::AntiHairRoundPath;
1074                    break;
1075                default:
1076                    proc SK_INIT_TO_AVOID_WARNING;
1077                    SkDEBUGFAIL("unknown paint cap type");
1078            }
1079        } else {
1080            switch (paint.getStrokeCap()) {
1081                case SkPaint::kButt_Cap:
1082                    proc = SkScan::HairPath;
1083                    break;
1084                case SkPaint::kSquare_Cap:
1085                    proc = SkScan::HairSquarePath;
1086                    break;
1087                case SkPaint::kRound_Cap:
1088                    proc = SkScan::HairRoundPath;
1089                    break;
1090                default:
1091                    proc SK_INIT_TO_AVOID_WARNING;
1092                    SkDEBUGFAIL("unknown paint cap type");
1093            }
1094        }
1095    }
1096    proc(devPath, *fRC, blitter);
1097}
1098
1099void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint,
1100                      const SkMatrix* prePathMatrix, bool pathIsMutable,
1101                      bool drawCoverage, SkBlitter* customBlitter) const {
1102    SkDEBUGCODE(this->validate();)
1103
1104    // nothing to draw
1105    if (fRC->isEmpty()) {
1106        return;
1107    }
1108
1109    SkPath*         pathPtr = (SkPath*)&origSrcPath;
1110    bool            doFill = true;
1111    SkPath          tmpPath;
1112    SkMatrix        tmpMatrix;
1113    const SkMatrix* matrix = fMatrix;
1114    tmpPath.setIsVolatile(true);
1115
1116    if (prePathMatrix) {
1117        if (origPaint.getPathEffect() || origPaint.getStyle() != SkPaint::kFill_Style ||
1118                origPaint.getRasterizer()) {
1119            SkPath* result = pathPtr;
1120
1121            if (!pathIsMutable) {
1122                result = &tmpPath;
1123                pathIsMutable = true;
1124            }
1125            pathPtr->transform(*prePathMatrix, result);
1126            pathPtr = result;
1127        } else {
1128            tmpMatrix.setConcat(*matrix, *prePathMatrix);
1129            matrix = &tmpMatrix;
1130        }
1131    }
1132    // at this point we're done with prePathMatrix
1133    SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
1134
1135    SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
1136
1137    {
1138        SkScalar coverage;
1139        if (SkDrawTreatAsHairline(origPaint, *matrix, &coverage)) {
1140            if (SK_Scalar1 == coverage) {
1141                paint.writable()->setStrokeWidth(0);
1142            } else if (SkBlendMode_SupportsCoverageAsAlpha(origPaint.getBlendMode())) {
1143                U8CPU newAlpha;
1144#if 0
1145                newAlpha = SkToU8(SkScalarRoundToInt(coverage *
1146                                                     origPaint.getAlpha()));
1147#else
1148                // this is the old technique, which we preserve for now so
1149                // we don't change previous results (testing)
1150                // the new way seems fine, its just (a tiny bit) different
1151                int scale = (int)SkScalarMul(coverage, 256);
1152                newAlpha = origPaint.getAlpha() * scale >> 8;
1153#endif
1154                SkPaint* writablePaint = paint.writable();
1155                writablePaint->setStrokeWidth(0);
1156                writablePaint->setAlpha(newAlpha);
1157            }
1158        }
1159    }
1160
1161    if (paint->getPathEffect() || paint->getStyle() != SkPaint::kFill_Style) {
1162        SkRect cullRect;
1163        const SkRect* cullRectPtr = nullptr;
1164        if (this->computeConservativeLocalClipBounds(&cullRect)) {
1165            cullRectPtr = &cullRect;
1166        }
1167        doFill = paint->getFillPath(*pathPtr, &tmpPath, cullRectPtr,
1168                                    ComputeResScaleForStroking(*fMatrix));
1169        pathPtr = &tmpPath;
1170    }
1171
1172    if (paint->getRasterizer()) {
1173        SkMask  mask;
1174        if (paint->getRasterizer()->rasterize(*pathPtr, *matrix,
1175                            &fRC->getBounds(), paint->getMaskFilter(), &mask,
1176                            SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
1177            this->drawDevMask(mask, *paint);
1178            SkMask::FreeImage(mask.fImage);
1179        }
1180        return;
1181    }
1182
1183    // avoid possibly allocating a new path in transform if we can
1184    SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
1185
1186    // transform the path into device space
1187    pathPtr->transform(*matrix, devPathPtr);
1188
1189    this->drawDevPath(*devPathPtr, *paint, drawCoverage, customBlitter, doFill);
1190}
1191
1192void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, const SkPaint& paint) const {
1193    SkASSERT(bitmap.colorType() == kAlpha_8_SkColorType);
1194
1195    if (SkTreatAsSprite(*fMatrix, bitmap.dimensions(), paint)) {
1196        int ix = SkScalarRoundToInt(fMatrix->getTranslateX());
1197        int iy = SkScalarRoundToInt(fMatrix->getTranslateY());
1198
1199        SkAutoPixmapUnlock result;
1200        if (!bitmap.requestLock(&result)) {
1201            return;
1202        }
1203        const SkPixmap& pmap = result.pixmap();
1204        SkMask  mask;
1205        mask.fBounds.set(ix, iy, ix + pmap.width(), iy + pmap.height());
1206        mask.fFormat = SkMask::kA8_Format;
1207        mask.fRowBytes = SkToU32(pmap.rowBytes());
1208        // fImage is typed as writable, but in this case it is used read-only
1209        mask.fImage = (uint8_t*)pmap.addr8(0, 0);
1210
1211        this->drawDevMask(mask, paint);
1212    } else {    // need to xform the bitmap first
1213        SkRect  r;
1214        SkMask  mask;
1215
1216        r.set(0, 0,
1217              SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
1218        fMatrix->mapRect(&r);
1219        r.round(&mask.fBounds);
1220
1221        // set the mask's bounds to the transformed bitmap-bounds,
1222        // clipped to the actual device
1223        {
1224            SkIRect    devBounds;
1225            devBounds.set(0, 0, fDst.width(), fDst.height());
1226            // need intersect(l, t, r, b) on irect
1227            if (!mask.fBounds.intersect(devBounds)) {
1228                return;
1229            }
1230        }
1231
1232        mask.fFormat = SkMask::kA8_Format;
1233        mask.fRowBytes = SkAlign4(mask.fBounds.width());
1234        size_t size = mask.computeImageSize();
1235        if (0 == size) {
1236            // the mask is too big to allocated, draw nothing
1237            return;
1238        }
1239
1240        // allocate (and clear) our temp buffer to hold the transformed bitmap
1241        SkAutoTMalloc<uint8_t> storage(size);
1242        mask.fImage = storage.get();
1243        memset(mask.fImage, 0, size);
1244
1245        // now draw our bitmap(src) into mask(dst), transformed by the matrix
1246        {
1247            SkBitmap    device;
1248            device.installPixels(SkImageInfo::MakeA8(mask.fBounds.width(), mask.fBounds.height()),
1249                                 mask.fImage, mask.fRowBytes);
1250
1251            SkCanvas c(device);
1252            // need the unclipped top/left for the translate
1253            c.translate(-SkIntToScalar(mask.fBounds.fLeft),
1254                        -SkIntToScalar(mask.fBounds.fTop));
1255            c.concat(*fMatrix);
1256
1257            // We can't call drawBitmap, or we'll infinitely recurse. Instead
1258            // we manually build a shader and draw that into our new mask
1259            SkPaint tmpPaint;
1260            tmpPaint.setFlags(paint.getFlags());
1261            tmpPaint.setFilterQuality(paint.getFilterQuality());
1262            SkAutoBitmapShaderInstall install(bitmap, tmpPaint);
1263            SkRect rr;
1264            rr.set(0, 0, SkIntToScalar(bitmap.width()),
1265                   SkIntToScalar(bitmap.height()));
1266            c.drawRect(rr, install.paintWithShader());
1267        }
1268        this->drawDevMask(mask, paint);
1269    }
1270}
1271
1272static bool clipped_out(const SkMatrix& m, const SkRasterClip& c,
1273                        const SkRect& srcR) {
1274    SkRect  dstR;
1275    m.mapRect(&dstR, srcR);
1276    return c.quickReject(dstR.roundOut());
1277}
1278
1279static bool clipped_out(const SkMatrix& matrix, const SkRasterClip& clip,
1280                        int width, int height) {
1281    SkRect  r;
1282    r.set(0, 0, SkIntToScalar(width), SkIntToScalar(height));
1283    return clipped_out(matrix, clip, r);
1284}
1285
1286static bool clipHandlesSprite(const SkRasterClip& clip, int x, int y, const SkPixmap& pmap) {
1287    return clip.isBW() || clip.quickContains(x, y, x + pmap.width(), y + pmap.height());
1288}
1289
1290void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix,
1291                        const SkRect* dstBounds, const SkPaint& origPaint) const {
1292    SkDEBUGCODE(this->validate();)
1293
1294    // nothing to draw
1295    if (fRC->isEmpty() ||
1296            bitmap.width() == 0 || bitmap.height() == 0 ||
1297            bitmap.colorType() == kUnknown_SkColorType) {
1298        return;
1299    }
1300
1301    SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
1302    if (origPaint.getStyle() != SkPaint::kFill_Style) {
1303        paint.writable()->setStyle(SkPaint::kFill_Style);
1304    }
1305
1306    SkMatrix matrix;
1307    matrix.setConcat(*fMatrix, prematrix);
1308
1309    if (clipped_out(matrix, *fRC, bitmap.width(), bitmap.height())) {
1310        return;
1311    }
1312
1313    if (bitmap.colorType() != kAlpha_8_SkColorType
1314        && SkTreatAsSprite(matrix, bitmap.dimensions(), *paint)) {
1315        //
1316        // It is safe to call lock pixels now, since we know the matrix is
1317        // (more or less) identity.
1318        //
1319        SkAutoPixmapUnlock unlocker;
1320        if (!bitmap.requestLock(&unlocker)) {
1321            return;
1322        }
1323        const SkPixmap& pmap = unlocker.pixmap();
1324        int ix = SkScalarRoundToInt(matrix.getTranslateX());
1325        int iy = SkScalarRoundToInt(matrix.getTranslateY());
1326        if (clipHandlesSprite(*fRC, ix, iy, pmap)) {
1327            SkTBlitterAllocator allocator;
1328            // blitter will be owned by the allocator.
1329            SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, *paint, pmap, ix, iy, &allocator);
1330            if (blitter) {
1331                SkScan::FillIRect(SkIRect::MakeXYWH(ix, iy, pmap.width(), pmap.height()),
1332                                  *fRC, blitter);
1333                return;
1334            }
1335            // if !blitter, then we fall-through to the slower case
1336        }
1337    }
1338
1339    // now make a temp draw on the stack, and use it
1340    //
1341    SkDraw draw(*this);
1342    draw.fMatrix = &matrix;
1343
1344    if (bitmap.colorType() == kAlpha_8_SkColorType && !paint->getColorFilter()) {
1345        draw.drawBitmapAsMask(bitmap, *paint);
1346    } else {
1347        SkAutoBitmapShaderInstall install(bitmap, *paint);
1348        const SkPaint& paintWithShader = install.paintWithShader();
1349        const SkRect srcBounds = SkRect::MakeIWH(bitmap.width(), bitmap.height());
1350        if (dstBounds) {
1351            this->drawRect(srcBounds, paintWithShader, &prematrix, dstBounds);
1352        } else {
1353            draw.drawRect(srcBounds, paintWithShader);
1354        }
1355    }
1356}
1357
1358void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& origPaint) const {
1359    SkDEBUGCODE(this->validate();)
1360
1361    // nothing to draw
1362    if (fRC->isEmpty() ||
1363            bitmap.width() == 0 || bitmap.height() == 0 ||
1364            bitmap.colorType() == kUnknown_SkColorType) {
1365        return;
1366    }
1367
1368    const SkIRect bounds = SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height());
1369
1370    if (fRC->quickReject(bounds)) {
1371        return; // nothing to draw
1372    }
1373
1374    SkPaint paint(origPaint);
1375    paint.setStyle(SkPaint::kFill_Style);
1376
1377    SkAutoPixmapUnlock unlocker;
1378    if (!bitmap.requestLock(&unlocker)) {
1379        return;
1380    }
1381    const SkPixmap& pmap = unlocker.pixmap();
1382
1383    if (nullptr == paint.getColorFilter() && clipHandlesSprite(*fRC, x, y, pmap)) {
1384        SkTBlitterAllocator allocator;
1385        // blitter will be owned by the allocator.
1386        SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, paint, pmap, x, y, &allocator);
1387        if (blitter) {
1388            SkScan::FillIRect(bounds, *fRC, blitter);
1389            return;
1390        }
1391    }
1392
1393    SkMatrix        matrix;
1394    SkRect          r;
1395
1396    // get a scalar version of our rect
1397    r.set(bounds);
1398
1399    // create shader with offset
1400    matrix.setTranslate(r.fLeft, r.fTop);
1401    SkAutoBitmapShaderInstall install(bitmap, paint, &matrix);
1402    const SkPaint& shaderPaint = install.paintWithShader();
1403
1404    SkDraw draw(*this);
1405    matrix.reset();
1406    draw.fMatrix = &matrix;
1407    // call ourself with a rect
1408    // is this OK if paint has a rasterizer?
1409    draw.drawRect(r, shaderPaint);
1410}
1411
1412///////////////////////////////////////////////////////////////////////////////
1413
1414#include "SkScalerContext.h"
1415#include "SkGlyphCache.h"
1416#include "SkTextToPathIter.h"
1417#include "SkUtils.h"
1418
1419bool SkDraw::ShouldDrawTextAsPaths(const SkPaint& paint, const SkMatrix& ctm) {
1420    // hairline glyphs are fast enough so we don't need to cache them
1421    if (SkPaint::kStroke_Style == paint.getStyle() && 0 == paint.getStrokeWidth()) {
1422        return true;
1423    }
1424
1425    // we don't cache perspective
1426    if (ctm.hasPerspective()) {
1427        return true;
1428    }
1429
1430    SkMatrix textM;
1431    return SkPaint::TooBigToUseCache(ctm, *paint.setTextMatrix(&textM));
1432}
1433
1434void SkDraw::drawText_asPaths(const char text[], size_t byteLength,
1435                              SkScalar x, SkScalar y,
1436                              const SkPaint& paint) const {
1437    SkDEBUGCODE(this->validate();)
1438
1439    SkTextToPathIter iter(text, byteLength, paint, true);
1440
1441    SkMatrix    matrix;
1442    matrix.setScale(iter.getPathScale(), iter.getPathScale());
1443    matrix.postTranslate(x, y);
1444
1445    const SkPath* iterPath;
1446    SkScalar xpos, prevXPos = 0;
1447
1448    while (iter.next(&iterPath, &xpos)) {
1449        matrix.postTranslate(xpos - prevXPos, 0);
1450        if (iterPath) {
1451            const SkPaint& pnt = iter.getPaint();
1452            if (fDevice) {
1453                fDevice->drawPath(*this, *iterPath, pnt, &matrix, false);
1454            } else {
1455                this->drawPath(*iterPath, pnt, &matrix, false);
1456            }
1457        }
1458        prevXPos = xpos;
1459    }
1460}
1461
1462// disable warning : local variable used without having been initialized
1463#if defined _WIN32
1464#pragma warning ( push )
1465#pragma warning ( disable : 4701 )
1466#endif
1467
1468////////////////////////////////////////////////////////////////////////////////////////////////////
1469
1470class DrawOneGlyph {
1471public:
1472    DrawOneGlyph(const SkDraw& draw, const SkPaint& paint, SkGlyphCache* cache, SkBlitter* blitter)
1473        : fUseRegionToDraw(UsingRegionToDraw(draw.fRC))
1474        , fGlyphCache(cache)
1475        , fBlitter(blitter)
1476        , fClip(fUseRegionToDraw ? &draw.fRC->bwRgn() : nullptr)
1477        , fDraw(draw)
1478        , fPaint(paint)
1479        , fClipBounds(PickClipBounds(draw)) { }
1480
1481    void operator()(const SkGlyph& glyph, SkPoint position, SkPoint rounding) {
1482        position += rounding;
1483        // Prevent glyphs from being drawn outside of or straddling the edge of device space.
1484        // Comparisons written a little weirdly so that NaN coordinates are treated safely.
1485        auto gt = [](float a, int b) { return !(a <= (float)b); };
1486        auto lt = [](float a, int b) { return !(a >= (float)b); };
1487        if (gt(position.fX, INT_MAX - (INT16_MAX + UINT16_MAX)) ||
1488            lt(position.fX, INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)) ||
1489            gt(position.fY, INT_MAX - (INT16_MAX + UINT16_MAX)) ||
1490            lt(position.fY, INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/))) {
1491            return;
1492        }
1493
1494        int left = SkScalarFloorToInt(position.fX);
1495        int top  = SkScalarFloorToInt(position.fY);
1496        SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1497
1498        left += glyph.fLeft;
1499        top  += glyph.fTop;
1500
1501        int right   = left + glyph.fWidth;
1502        int bottom  = top  + glyph.fHeight;
1503
1504        SkMask mask;
1505        mask.fBounds.set(left, top, right, bottom);
1506        SkASSERT(!mask.fBounds.isEmpty());
1507
1508        if (fUseRegionToDraw) {
1509            SkRegion::Cliperator clipper(*fClip, mask.fBounds);
1510
1511            if (!clipper.done() && this->getImageData(glyph, &mask)) {
1512                const SkIRect& cr = clipper.rect();
1513                do {
1514                    this->blitMask(mask, cr);
1515                    clipper.next();
1516                } while (!clipper.done());
1517            }
1518        } else {
1519            SkIRect  storage;
1520            SkIRect* bounds = &mask.fBounds;
1521
1522            // this extra test is worth it, assuming that most of the time it succeeds
1523            // since we can avoid writing to storage
1524            if (!fClipBounds.containsNoEmptyCheck(mask.fBounds)) {
1525                if (!storage.intersectNoEmptyCheck(mask.fBounds, fClipBounds))
1526                    return;
1527                bounds = &storage;
1528            }
1529
1530            if (this->getImageData(glyph, &mask)) {
1531                this->blitMask(mask, *bounds);
1532            }
1533        }
1534    }
1535
1536private:
1537    static bool UsingRegionToDraw(const SkRasterClip* rClip) {
1538        return rClip->isBW() && !rClip->isRect();
1539    }
1540
1541    static SkIRect PickClipBounds(const SkDraw& draw) {
1542        const SkRasterClip& rasterClip = *draw.fRC;
1543
1544        if (rasterClip.isBW()) {
1545            return rasterClip.bwRgn().getBounds();
1546        } else {
1547            return rasterClip.aaRgn().getBounds();
1548        }
1549    }
1550
1551    bool getImageData(const SkGlyph& glyph, SkMask* mask) {
1552        uint8_t* bits = (uint8_t*)(fGlyphCache->findImage(glyph));
1553        if (nullptr == bits) {
1554            return false;  // can't rasterize glyph
1555        }
1556        mask->fImage    = bits;
1557        mask->fRowBytes = glyph.rowBytes();
1558        mask->fFormat   = static_cast<SkMask::Format>(glyph.fMaskFormat);
1559        return true;
1560    }
1561
1562    void blitMask(const SkMask& mask, const SkIRect& clip) const {
1563        if (SkMask::kARGB32_Format == mask.fFormat) {
1564            SkBitmap bm;
1565            bm.installPixels(
1566                SkImageInfo::MakeN32Premul(mask.fBounds.width(), mask.fBounds.height()),
1567                (SkPMColor*)mask.fImage, mask.fRowBytes);
1568
1569            fDraw.drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), fPaint);
1570        } else {
1571            fBlitter->blitMask(mask, clip);
1572        }
1573    }
1574
1575    const bool            fUseRegionToDraw;
1576    SkGlyphCache  * const fGlyphCache;
1577    SkBlitter     * const fBlitter;
1578    const SkRegion* const fClip;
1579    const SkDraw&         fDraw;
1580    const SkPaint&        fPaint;
1581    const SkIRect         fClipBounds;
1582};
1583
1584////////////////////////////////////////////////////////////////////////////////////////////////////
1585
1586uint32_t SkDraw::scalerContextFlags() const {
1587    uint32_t flags = SkPaint::kBoostContrast_ScalerContextFlag;
1588    if (!fDevice->imageInfo().colorSpace()) {
1589        flags |= SkPaint::kFakeGamma_ScalerContextFlag;
1590    }
1591    return flags;
1592}
1593
1594void SkDraw::drawText(const char text[], size_t byteLength,
1595                      SkScalar x, SkScalar y, const SkPaint& paint) const {
1596    SkASSERT(byteLength == 0 || text != nullptr);
1597
1598    SkDEBUGCODE(this->validate();)
1599
1600    // nothing to draw
1601    if (text == nullptr || byteLength == 0 || fRC->isEmpty()) {
1602        return;
1603    }
1604
1605    // SkScalarRec doesn't currently have a way of representing hairline stroke and
1606    // will fill if its frame-width is 0.
1607    if (ShouldDrawTextAsPaths(paint, *fMatrix)) {
1608        this->drawText_asPaths(text, byteLength, x, y, paint);
1609        return;
1610    }
1611
1612    SkAutoGlyphCache cache(paint, &fDevice->surfaceProps(), this->scalerContextFlags(), fMatrix);
1613
1614    // The Blitter Choose needs to be live while using the blitter below.
1615    SkAutoBlitterChoose    blitterChooser(fDst, *fMatrix, paint);
1616    SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get());
1617    DrawOneGlyph           drawOneGlyph(*this, paint, cache.get(), wrapper.getBlitter());
1618
1619    SkFindAndPlaceGlyph::ProcessText(
1620        paint.getTextEncoding(), text, byteLength,
1621        {x, y}, *fMatrix, paint.getTextAlign(), cache.get(), drawOneGlyph);
1622}
1623
1624//////////////////////////////////////////////////////////////////////////////
1625
1626void SkDraw::drawPosText_asPaths(const char text[], size_t byteLength,
1627                                 const SkScalar pos[], int scalarsPerPosition,
1628                                 const SkPoint& offset, const SkPaint& origPaint) const {
1629    // setup our std paint, in hopes of getting hits in the cache
1630    SkPaint paint(origPaint);
1631    SkScalar matrixScale = paint.setupForAsPaths();
1632
1633    SkMatrix matrix;
1634    matrix.setScale(matrixScale, matrixScale);
1635
1636    // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache.
1637    paint.setStyle(SkPaint::kFill_Style);
1638    paint.setPathEffect(nullptr);
1639
1640    SkPaint::GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(paint.getTextEncoding(),
1641                                                                        paint.isDevKernText(),
1642                                                                        true);
1643    SkAutoGlyphCache cache(paint, &fDevice->surfaceProps(), this->scalerContextFlags(), nullptr);
1644
1645    const char*        stop = text + byteLength;
1646    SkTextAlignProc    alignProc(paint.getTextAlign());
1647    SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition);
1648
1649    // Now restore the original settings, so we "draw" with whatever style/stroking.
1650    paint.setStyle(origPaint.getStyle());
1651    paint.setPathEffect(origPaint.refPathEffect());
1652
1653    while (text < stop) {
1654        const SkGlyph& glyph = glyphCacheProc(cache.get(), &text);
1655        if (glyph.fWidth) {
1656            const SkPath* path = cache->findPath(glyph);
1657            if (path) {
1658                SkPoint tmsLoc;
1659                tmsProc(pos, &tmsLoc);
1660                SkPoint loc;
1661                alignProc(tmsLoc, glyph, &loc);
1662
1663                matrix[SkMatrix::kMTransX] = loc.fX;
1664                matrix[SkMatrix::kMTransY] = loc.fY;
1665                if (fDevice) {
1666                    fDevice->drawPath(*this, *path, paint, &matrix, false);
1667                } else {
1668                    this->drawPath(*path, paint, &matrix, false);
1669                }
1670            }
1671        }
1672        pos += scalarsPerPosition;
1673    }
1674}
1675
1676void SkDraw::drawPosText(const char text[], size_t byteLength,
1677                         const SkScalar pos[], int scalarsPerPosition,
1678                         const SkPoint& offset, const SkPaint& paint) const {
1679    SkASSERT(byteLength == 0 || text != nullptr);
1680    SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
1681
1682    SkDEBUGCODE(this->validate();)
1683
1684    // nothing to draw
1685    if (text == nullptr || byteLength == 0 || fRC->isEmpty()) {
1686        return;
1687    }
1688
1689    if (ShouldDrawTextAsPaths(paint, *fMatrix)) {
1690        this->drawPosText_asPaths(text, byteLength, pos, scalarsPerPosition, offset, paint);
1691        return;
1692    }
1693
1694    SkAutoGlyphCache cache(paint, &fDevice->surfaceProps(), this->scalerContextFlags(), fMatrix);
1695
1696    // The Blitter Choose needs to be live while using the blitter below.
1697    SkAutoBlitterChoose    blitterChooser(fDst, *fMatrix, paint);
1698    SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get());
1699    DrawOneGlyph           drawOneGlyph(*this, paint, cache.get(), wrapper.getBlitter());
1700    SkPaint::Align         textAlignment = paint.getTextAlign();
1701
1702    SkFindAndPlaceGlyph::ProcessPosText(
1703        paint.getTextEncoding(), text, byteLength,
1704        offset, *fMatrix, pos, scalarsPerPosition, textAlignment, cache.get(), drawOneGlyph);
1705}
1706
1707#if defined _WIN32
1708#pragma warning ( pop )
1709#endif
1710
1711///////////////////////////////////////////////////////////////////////////////
1712
1713static SkScan::HairRCProc ChooseHairProc(bool doAntiAlias) {
1714    return doAntiAlias ? SkScan::AntiHairLine : SkScan::HairLine;
1715}
1716
1717static bool texture_to_matrix(const VertState& state, const SkPoint verts[],
1718                              const SkPoint texs[], SkMatrix* matrix) {
1719    SkPoint src[3], dst[3];
1720
1721    src[0] = texs[state.f0];
1722    src[1] = texs[state.f1];
1723    src[2] = texs[state.f2];
1724    dst[0] = verts[state.f0];
1725    dst[1] = verts[state.f1];
1726    dst[2] = verts[state.f2];
1727    return matrix->setPolyToPoly(src, dst, 3);
1728}
1729
1730class SkTriColorShader : public SkShader {
1731public:
1732    SkTriColorShader();
1733
1734    class TriColorShaderContext : public SkShader::Context {
1735    public:
1736        TriColorShaderContext(const SkTriColorShader& shader, const ContextRec&);
1737        virtual ~TriColorShaderContext();
1738        void shadeSpan(int x, int y, SkPMColor dstC[], int count) override;
1739
1740    private:
1741        bool setup(const SkPoint pts[], const SkColor colors[], int, int, int);
1742
1743        SkMatrix    fDstToUnit;
1744        SkPMColor   fColors[3];
1745        bool fSetup;
1746
1747        typedef SkShader::Context INHERITED;
1748    };
1749
1750    struct TriColorShaderData {
1751        const SkPoint* pts;
1752        const SkColor* colors;
1753        const VertState *state;
1754    };
1755
1756    SK_TO_STRING_OVERRIDE()
1757
1758    // For serialization.  This will never be called.
1759    Factory getFactory() const override { sk_throw(); return nullptr; }
1760
1761    // Supply setup data to context from drawing setup
1762    void bindSetupData(TriColorShaderData* setupData) { fSetupData = setupData; }
1763
1764    // Take the setup data from context when needed.
1765    TriColorShaderData* takeSetupData() {
1766        TriColorShaderData *data = fSetupData;
1767        fSetupData = NULL;
1768        return data;
1769    }
1770
1771protected:
1772    size_t onContextSize(const ContextRec&) const override;
1773    Context* onCreateContext(const ContextRec& rec, void* storage) const override {
1774        return new (storage) TriColorShaderContext(*this, rec);
1775    }
1776
1777private:
1778    TriColorShaderData *fSetupData;
1779
1780    typedef SkShader INHERITED;
1781};
1782
1783bool SkTriColorShader::TriColorShaderContext::setup(const SkPoint pts[], const SkColor colors[],
1784                                                    int index0, int index1, int index2) {
1785
1786    fColors[0] = SkPreMultiplyColor(colors[index0]);
1787    fColors[1] = SkPreMultiplyColor(colors[index1]);
1788    fColors[2] = SkPreMultiplyColor(colors[index2]);
1789
1790    SkMatrix m, im;
1791    m.reset();
1792    m.set(0, pts[index1].fX - pts[index0].fX);
1793    m.set(1, pts[index2].fX - pts[index0].fX);
1794    m.set(2, pts[index0].fX);
1795    m.set(3, pts[index1].fY - pts[index0].fY);
1796    m.set(4, pts[index2].fY - pts[index0].fY);
1797    m.set(5, pts[index0].fY);
1798    if (!m.invert(&im)) {
1799        return false;
1800    }
1801    // We can't call getTotalInverse(), because we explicitly don't want to look at the localmatrix
1802    // as our interators are intrinsically tied to the vertices, and nothing else.
1803    SkMatrix ctmInv;
1804    if (!this->getCTM().invert(&ctmInv)) {
1805        return false;
1806    }
1807    // TODO replace INV(m) * INV(ctm) with INV(ctm * m)
1808    fDstToUnit.setConcat(im, ctmInv);
1809    return true;
1810}
1811
1812#include "SkColorPriv.h"
1813#include "SkComposeShader.h"
1814
1815static int ScalarTo256(SkScalar v) {
1816    return static_cast<int>(SkScalarPin(v, 0, 1) * 256 + 0.5);
1817}
1818
1819SkTriColorShader::SkTriColorShader()
1820    : INHERITED(NULL)
1821    , fSetupData(NULL) {}
1822
1823SkTriColorShader::TriColorShaderContext::TriColorShaderContext(const SkTriColorShader& shader,
1824                                                               const ContextRec& rec)
1825    : INHERITED(shader, rec)
1826    , fSetup(false) {}
1827
1828SkTriColorShader::TriColorShaderContext::~TriColorShaderContext() {}
1829
1830size_t SkTriColorShader::onContextSize(const ContextRec&) const {
1831    return sizeof(TriColorShaderContext);
1832}
1833
1834void SkTriColorShader::TriColorShaderContext::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
1835    SkTriColorShader* parent = static_cast<SkTriColorShader*>(const_cast<SkShader*>(&fShader));
1836    TriColorShaderData* set = parent->takeSetupData();
1837    if (set) {
1838        fSetup = setup(set->pts, set->colors, set->state->f0, set->state->f1, set->state->f2);
1839    }
1840
1841    if (!fSetup) {
1842        // Invalid matrices. Not checked before so no need to assert.
1843        return;
1844    }
1845
1846    const int alphaScale = Sk255To256(this->getPaintAlpha());
1847
1848    SkPoint src;
1849
1850    for (int i = 0; i < count; i++) {
1851        fDstToUnit.mapXY(SkIntToScalar(x), SkIntToScalar(y), &src);
1852        x += 1;
1853
1854        int scale1 = ScalarTo256(src.fX);
1855        int scale2 = ScalarTo256(src.fY);
1856        int scale0 = 256 - scale1 - scale2;
1857        if (scale0 < 0) {
1858            if (scale1 > scale2) {
1859                scale2 = 256 - scale1;
1860            } else {
1861                scale1 = 256 - scale2;
1862            }
1863            scale0 = 0;
1864        }
1865
1866        if (256 != alphaScale) {
1867            scale0 = SkAlphaMul(scale0, alphaScale);
1868            scale1 = SkAlphaMul(scale1, alphaScale);
1869            scale2 = SkAlphaMul(scale2, alphaScale);
1870        }
1871
1872        dstC[i] = SkAlphaMulQ(fColors[0], scale0) +
1873                  SkAlphaMulQ(fColors[1], scale1) +
1874                  SkAlphaMulQ(fColors[2], scale2);
1875    }
1876}
1877
1878#ifndef SK_IGNORE_TO_STRING
1879void SkTriColorShader::toString(SkString* str) const {
1880    str->append("SkTriColorShader: (");
1881
1882    this->INHERITED::toString(str);
1883
1884    str->append(")");
1885}
1886#endif
1887
1888void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count,
1889                          const SkPoint vertices[], const SkPoint textures[],
1890                          const SkColor colors[], SkBlendMode bmode,
1891                          const uint16_t indices[], int indexCount,
1892                          const SkPaint& paint) const {
1893    SkASSERT(0 == count || vertices);
1894
1895    // abort early if there is nothing to draw
1896    if (count < 3 || (indices && indexCount < 3) || fRC->isEmpty()) {
1897        return;
1898    }
1899
1900    // transform out vertices into device coordinates
1901    SkAutoSTMalloc<16, SkPoint> storage(count);
1902    SkPoint* devVerts = storage.get();
1903    fMatrix->mapPoints(devVerts, vertices, count);
1904
1905    /*
1906        We can draw the vertices in 1 of 4 ways:
1907
1908        - solid color (no shader/texture[], no colors[])
1909        - just colors (no shader/texture[], has colors[])
1910        - just texture (has shader/texture[], no colors[])
1911        - colors * texture (has shader/texture[], has colors[])
1912
1913        Thus for texture drawing, we need both texture[] and a shader.
1914    */
1915
1916    auto triShader = sk_make_sp<SkTriColorShader>();
1917    SkPaint p(paint);
1918
1919    SkShader* shader = p.getShader();
1920    if (nullptr == shader) {
1921        // if we have no shader, we ignore the texture coordinates
1922        textures = nullptr;
1923    } else if (nullptr == textures) {
1924        // if we don't have texture coordinates, ignore the shader
1925        p.setShader(nullptr);
1926        shader = nullptr;
1927    }
1928
1929    // setup the custom shader (if needed)
1930    if (colors) {
1931        if (nullptr == textures) {
1932            // just colors (no texture)
1933            p.setShader(triShader);
1934        } else {
1935            // colors * texture
1936            SkASSERT(shader);
1937            p.setShader(SkShader::MakeComposeShader(triShader, sk_ref_sp(shader), bmode));
1938        }
1939    }
1940
1941    SkAutoBlitterChoose blitter(fDst, *fMatrix, p);
1942    // Abort early if we failed to create a shader context.
1943    if (blitter->isNullBlitter()) {
1944        return;
1945    }
1946
1947    // setup our state and function pointer for iterating triangles
1948    VertState       state(count, indices, indexCount);
1949    VertState::Proc vertProc = state.chooseProc(vmode);
1950
1951    if (textures || colors) {
1952        SkTriColorShader::TriColorShaderData verticesSetup = { vertices, colors, &state };
1953
1954        while (vertProc(&state)) {
1955            if (textures) {
1956                SkMatrix tempM;
1957                if (texture_to_matrix(state, vertices, textures, &tempM)) {
1958                    SkShader::ContextRec rec(p, *fMatrix, &tempM,
1959                                             SkBlitter::PreferredShaderDest(fDst.info()),
1960                                             fDst.colorSpace());
1961                    if (!blitter->resetShaderContext(rec)) {
1962                        continue;
1963                    }
1964                }
1965            }
1966            if (colors) {
1967                triShader->bindSetupData(&verticesSetup);
1968            }
1969
1970            SkPoint tmp[] = {
1971                devVerts[state.f0], devVerts[state.f1], devVerts[state.f2]
1972            };
1973            SkScan::FillTriangle(tmp, *fRC, blitter.get());
1974            triShader->bindSetupData(NULL);
1975        }
1976    } else {
1977        // no colors[] and no texture, stroke hairlines with paint's color.
1978        SkScan::HairRCProc hairProc = ChooseHairProc(paint.isAntiAlias());
1979        const SkRasterClip& clip = *fRC;
1980        while (vertProc(&state)) {
1981            SkPoint array[] = {
1982                devVerts[state.f0], devVerts[state.f1], devVerts[state.f2], devVerts[state.f0]
1983            };
1984            hairProc(array, 4, clip, blitter.get());
1985        }
1986    }
1987}
1988
1989///////////////////////////////////////////////////////////////////////////////
1990///////////////////////////////////////////////////////////////////////////////
1991
1992#ifdef SK_DEBUG
1993
1994void SkDraw::validate() const {
1995    SkASSERT(fMatrix != nullptr);
1996    SkASSERT(fRC != nullptr);
1997
1998    const SkIRect&  cr = fRC->getBounds();
1999    SkIRect         br;
2000
2001    br.set(0, 0, fDst.width(), fDst.height());
2002    SkASSERT(cr.isEmpty() || br.contains(cr));
2003}
2004
2005#endif
2006
2007////////////////////////////////////////////////////////////////////////////////////////////////
2008
2009#include "SkPath.h"
2010#include "SkDraw.h"
2011#include "SkRegion.h"
2012#include "SkBlitter.h"
2013
2014static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds,
2015                           const SkMaskFilter* filter, const SkMatrix* filterMatrix,
2016                           SkIRect* bounds) {
2017    if (devPath.isEmpty()) {
2018        return false;
2019    }
2020
2021    //  init our bounds from the path
2022    *bounds = devPath.getBounds().makeOutset(SK_ScalarHalf, SK_ScalarHalf).roundOut();
2023
2024    SkIPoint margin = SkIPoint::Make(0, 0);
2025    if (filter) {
2026        SkASSERT(filterMatrix);
2027
2028        SkMask srcM, dstM;
2029
2030        srcM.fBounds = *bounds;
2031        srcM.fFormat = SkMask::kA8_Format;
2032        if (!filter->filterMask(&dstM, srcM, *filterMatrix, &margin)) {
2033            return false;
2034        }
2035    }
2036
2037    // (possibly) trim the bounds to reflect the clip
2038    // (plus whatever slop the filter needs)
2039    if (clipBounds) {
2040        // Ugh. Guard against gigantic margins from wacky filters. Without this
2041        // check we can request arbitrary amounts of slop beyond our visible
2042        // clip, and bring down the renderer (at least on finite RAM machines
2043        // like handsets, etc.). Need to balance this invented value between
2044        // quality of large filters like blurs, and the corresponding memory
2045        // requests.
2046        static const int MAX_MARGIN = 128;
2047        if (!bounds->intersect(clipBounds->makeOutset(SkMin32(margin.fX, MAX_MARGIN),
2048                                                      SkMin32(margin.fY, MAX_MARGIN)))) {
2049            return false;
2050        }
2051    }
2052
2053    return true;
2054}
2055
2056static void draw_into_mask(const SkMask& mask, const SkPath& devPath,
2057                           SkStrokeRec::InitStyle style) {
2058    SkDraw draw;
2059    if (!draw.fDst.reset(mask)) {
2060        return;
2061    }
2062
2063    SkRasterClip    clip;
2064    SkMatrix        matrix;
2065    SkPaint         paint;
2066
2067    clip.setRect(SkIRect::MakeWH(mask.fBounds.width(), mask.fBounds.height()));
2068    matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
2069                        -SkIntToScalar(mask.fBounds.fTop));
2070
2071    draw.fRC        = &clip;
2072    draw.fMatrix    = &matrix;
2073    paint.setAntiAlias(true);
2074    switch (style) {
2075        case SkStrokeRec::kHairline_InitStyle:
2076            SkASSERT(!paint.getStrokeWidth());
2077            paint.setStyle(SkPaint::kStroke_Style);
2078            break;
2079        case SkStrokeRec::kFill_InitStyle:
2080            SkASSERT(paint.getStyle() == SkPaint::kFill_Style);
2081            break;
2082
2083    }
2084    draw.drawPath(devPath, paint);
2085}
2086
2087bool SkDraw::DrawToMask(const SkPath& devPath, const SkIRect* clipBounds,
2088                        const SkMaskFilter* filter, const SkMatrix* filterMatrix,
2089                        SkMask* mask, SkMask::CreateMode mode,
2090                        SkStrokeRec::InitStyle style) {
2091    if (SkMask::kJustRenderImage_CreateMode != mode) {
2092        if (!compute_bounds(devPath, clipBounds, filter, filterMatrix, &mask->fBounds))
2093            return false;
2094    }
2095
2096    if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) {
2097        mask->fFormat = SkMask::kA8_Format;
2098        mask->fRowBytes = mask->fBounds.width();
2099        size_t size = mask->computeImageSize();
2100        if (0 == size) {
2101            // we're too big to allocate the mask, abort
2102            return false;
2103        }
2104        mask->fImage = SkMask::AllocImage(size);
2105        memset(mask->fImage, 0, mask->computeImageSize());
2106    }
2107
2108    if (SkMask::kJustComputeBounds_CreateMode != mode) {
2109        draw_into_mask(*mask, devPath, style);
2110    }
2111
2112    return true;
2113}
2114