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