• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "src/core/SkDraw.h"
9 
10 #include "include/core/SkBitmap.h"
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkMatrix.h"
13 #include "include/core/SkPaint.h"
14 #include "include/core/SkPathEffect.h"
15 #include "include/core/SkPathUtils.h"
16 #include "include/core/SkRRect.h"
17 #include "include/core/SkShader.h"
18 #include "include/core/SkString.h"
19 #include "include/core/SkStrokeRec.h"
20 #include "include/private/SkColorData.h"
21 #include "include/private/base/SkMacros.h"
22 #include "include/private/base/SkTemplates.h"
23 #include "include/private/base/SkTo.h"
24 #include "src/base/SkArenaAlloc.h"
25 #include "src/base/SkTLazy.h"
26 #include "src/base/SkUtils.h"
27 #include "src/core/SkAutoBlitterChoose.h"
28 #include "src/core/SkBlendModePriv.h"
29 #include "src/core/SkBlitter.h"
30 #include "src/core/SkDevice.h"
31 #include "src/core/SkDrawProcs.h"
32 #include "src/core/SkImageInfoPriv.h"
33 #include "src/core/SkImagePriv.h"
34 #include "src/core/SkMaskFilterBase.h"
35 #include "src/core/SkMatrixUtils.h"
36 #include "src/core/SkPathEffectBase.h"
37 #include "src/core/SkPathPriv.h"
38 #include "src/core/SkRasterClip.h"
39 #include "src/core/SkRectPriv.h"
40 #include "src/core/SkSamplingPriv.h"
41 #include "src/core/SkScan.h"
42 #include "src/core/SkStroke.h"
43 
44 #include <utility>
45 
46 using namespace skia_private;
47 
make_paint_with_image(const SkPaint & origPaint,const SkBitmap & bitmap,const SkSamplingOptions & sampling,SkMatrix * matrix=nullptr)48 static SkPaint make_paint_with_image(const SkPaint& origPaint, const SkBitmap& bitmap,
49                                      const SkSamplingOptions& sampling,
50                                      SkMatrix* matrix = nullptr) {
51     SkPaint paint(origPaint);
52     paint.setShader(SkMakeBitmapShaderForPaint(origPaint, bitmap, SkTileMode::kClamp,
53                                                SkTileMode::kClamp, sampling, matrix,
54                                                kNever_SkCopyPixelsMode));
55     return paint;
56 }
57 
58 ///////////////////////////////////////////////////////////////////////////////
59 
SkDraw()60 SkDraw::SkDraw() {}
61 
computeConservativeLocalClipBounds(SkRect * localBounds) const62 bool SkDraw::computeConservativeLocalClipBounds(SkRect* localBounds) const {
63     if (fRC->isEmpty()) {
64         return false;
65     }
66 
67     SkMatrix inverse;
68     if (!fMatrixProvider->localToDevice().invert(&inverse)) {
69         return false;
70     }
71 
72     SkIRect devBounds = fRC->getBounds();
73     // outset to have slop for antialasing and hairlines
74     devBounds.outset(1, 1);
75     inverse.mapRect(localBounds, SkRect::Make(devBounds));
76     return true;
77 }
78 
79 ///////////////////////////////////////////////////////////////////////////////
80 
drawPaint(const SkPaint & paint) const81 void SkDraw::drawPaint(const SkPaint& paint) const {
82     SkDEBUGCODE(this->validate();)
83 
84     if (fRC->isEmpty()) {
85         return;
86     }
87 
88     SkIRect    devRect;
89     devRect.setWH(fDst.width(), fDst.height());
90 
91     SkAutoBlitterChoose blitter(*this, nullptr, paint);
92     SkScan::FillIRect(devRect, *fRC, blitter.get());
93 }
94 
95 ///////////////////////////////////////////////////////////////////////////////
96 
97 struct PtProcRec {
98     SkCanvas::PointMode fMode;
99     const SkPaint*  fPaint;
100     const SkRegion* fClip;
101     const SkRasterClip* fRC;
102 
103     // computed values
104     SkRect   fClipBounds;
105     SkScalar fRadius;
106 
107     typedef void (*Proc)(const PtProcRec&, const SkPoint devPts[], int count,
108                          SkBlitter*);
109 
110     bool init(SkCanvas::PointMode, const SkPaint&, const SkMatrix* matrix,
111               const SkRasterClip*);
112     Proc chooseProc(SkBlitter** blitter);
113 
114 private:
115     SkAAClipBlitterWrapper fWrapper;
116 };
117 
bw_pt_rect_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)118 static void bw_pt_rect_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
119                                  int count, SkBlitter* blitter) {
120     SkASSERT(rec.fClip->isRect());
121     const SkIRect& r = rec.fClip->getBounds();
122 
123     for (int i = 0; i < count; i++) {
124         int x = SkScalarFloorToInt(devPts[i].fX);
125         int y = SkScalarFloorToInt(devPts[i].fY);
126         if (r.contains(x, y)) {
127             blitter->blitH(x, y, 1);
128         }
129     }
130 }
131 
bw_pt_rect_16_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)132 static void bw_pt_rect_16_hair_proc(const PtProcRec& rec,
133                                     const SkPoint devPts[], int count,
134                                     SkBlitter* blitter) {
135     SkASSERT(rec.fRC->isRect());
136     const SkIRect& r = rec.fRC->getBounds();
137     uint32_t value;
138     const SkPixmap* dst = blitter->justAnOpaqueColor(&value);
139     SkASSERT(dst);
140 
141     uint16_t* addr = dst->writable_addr16(0, 0);
142     size_t    rb = dst->rowBytes();
143 
144     for (int i = 0; i < count; i++) {
145         int x = SkScalarFloorToInt(devPts[i].fX);
146         int y = SkScalarFloorToInt(devPts[i].fY);
147         if (r.contains(x, y)) {
148             ((uint16_t*)((char*)addr + y * rb))[x] = SkToU16(value);
149         }
150     }
151 }
152 
bw_pt_rect_32_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)153 static void bw_pt_rect_32_hair_proc(const PtProcRec& rec,
154                                     const SkPoint devPts[], int count,
155                                     SkBlitter* blitter) {
156     SkASSERT(rec.fRC->isRect());
157     const SkIRect& r = rec.fRC->getBounds();
158     uint32_t value;
159     const SkPixmap* dst = blitter->justAnOpaqueColor(&value);
160     SkASSERT(dst);
161 
162     SkPMColor* addr = dst->writable_addr32(0, 0);
163     size_t     rb = dst->rowBytes();
164 
165     for (int i = 0; i < count; i++) {
166         int x = SkScalarFloorToInt(devPts[i].fX);
167         int y = SkScalarFloorToInt(devPts[i].fY);
168         if (r.contains(x, y)) {
169             ((SkPMColor*)((char*)addr + y * rb))[x] = value;
170         }
171     }
172 }
173 
bw_pt_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)174 static void bw_pt_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
175                             int count, SkBlitter* blitter) {
176     for (int i = 0; i < count; i++) {
177         int x = SkScalarFloorToInt(devPts[i].fX);
178         int y = SkScalarFloorToInt(devPts[i].fY);
179         if (rec.fClip->contains(x, y)) {
180             blitter->blitH(x, y, 1);
181         }
182     }
183 }
184 
bw_line_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)185 static void bw_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
186                               int count, SkBlitter* blitter) {
187     for (int i = 0; i < count; i += 2) {
188         SkScan::HairLine(&devPts[i], 2, *rec.fRC, blitter);
189     }
190 }
191 
bw_poly_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)192 static void bw_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
193                               int count, SkBlitter* blitter) {
194     SkScan::HairLine(devPts, count, *rec.fRC, blitter);
195 }
196 
197 // aa versions
198 
aa_line_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)199 static void aa_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
200                               int count, SkBlitter* blitter) {
201     for (int i = 0; i < count; i += 2) {
202         SkScan::AntiHairLine(&devPts[i], 2, *rec.fRC, blitter);
203     }
204 }
205 
aa_poly_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)206 static void aa_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
207                               int count, SkBlitter* blitter) {
208     SkScan::AntiHairLine(devPts, count, *rec.fRC, blitter);
209 }
210 
211 // square procs (strokeWidth > 0 but matrix is square-scale (sx == sy)
212 
make_square_rad(SkPoint center,SkScalar radius)213 static SkRect make_square_rad(SkPoint center, SkScalar radius) {
214     return {
215         center.fX - radius, center.fY - radius,
216         center.fX + radius, center.fY + radius
217     };
218 }
219 
make_xrect(const SkRect & r)220 static SkXRect make_xrect(const SkRect& r) {
221     SkASSERT(SkRectPriv::FitsInFixed(r));
222     return {
223         SkScalarToFixed(r.fLeft), SkScalarToFixed(r.fTop),
224         SkScalarToFixed(r.fRight), SkScalarToFixed(r.fBottom)
225     };
226 }
227 
bw_square_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)228 static void bw_square_proc(const PtProcRec& rec, const SkPoint devPts[],
229                            int count, SkBlitter* blitter) {
230     for (int i = 0; i < count; i++) {
231         SkRect r = make_square_rad(devPts[i], rec.fRadius);
232         if (r.intersect(rec.fClipBounds)) {
233             SkScan::FillXRect(make_xrect(r), *rec.fRC, blitter);
234         }
235     }
236 }
237 
aa_square_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)238 static void aa_square_proc(const PtProcRec& rec, const SkPoint devPts[],
239                            int count, SkBlitter* blitter) {
240     for (int i = 0; i < count; i++) {
241         SkRect r = make_square_rad(devPts[i], rec.fRadius);
242         if (r.intersect(rec.fClipBounds)) {
243             SkScan::AntiFillXRect(make_xrect(r), *rec.fRC, blitter);
244         }
245     }
246 }
247 
248 // If this returns true, then chooseProc() must return a valid proc
init(SkCanvas::PointMode mode,const SkPaint & paint,const SkMatrix * matrix,const SkRasterClip * rc)249 bool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint,
250                      const SkMatrix* matrix, const SkRasterClip* rc) {
251     if ((unsigned)mode > (unsigned)SkCanvas::kPolygon_PointMode) {
252         return false;
253     }
254     if (paint.getPathEffect() || paint.getMaskFilter()) {
255         return false;
256     }
257     SkScalar width = paint.getStrokeWidth();
258     SkScalar radius = -1;   // sentinel value, a "valid" value must be > 0
259 
260     if (0 == width) {
261         radius = 0.5f;
262     } else if (paint.getStrokeCap() != SkPaint::kRound_Cap &&
263                matrix->isScaleTranslate() && SkCanvas::kPoints_PointMode == mode) {
264         SkScalar sx = matrix->get(SkMatrix::kMScaleX);
265         SkScalar sy = matrix->get(SkMatrix::kMScaleY);
266         if (SkScalarNearlyZero(sx - sy)) {
267             radius = SkScalarHalf(width * SkScalarAbs(sx));
268         }
269     }
270     if (radius > 0) {
271         SkRect clipBounds = SkRect::Make(rc->getBounds());
272         // if we return true, the caller may assume that the constructed shapes can be represented
273         // using SkFixed (after clipping), so we preflight that here.
274         if (!SkRectPriv::FitsInFixed(clipBounds)) {
275             return false;
276         }
277         fMode = mode;
278         fPaint = &paint;
279         fClip = nullptr;
280         fRC = rc;
281         fClipBounds = clipBounds;
282         fRadius = radius;
283         return true;
284     }
285     return false;
286 }
287 
chooseProc(SkBlitter ** blitterPtr)288 PtProcRec::Proc PtProcRec::chooseProc(SkBlitter** blitterPtr) {
289     Proc proc = nullptr;
290 
291     SkBlitter* blitter = *blitterPtr;
292     if (fRC->isBW()) {
293         fClip = &fRC->bwRgn();
294     } else {
295         fWrapper.init(*fRC, blitter);
296         fClip = &fWrapper.getRgn();
297         blitter = fWrapper.getBlitter();
298         *blitterPtr = blitter;
299     }
300 
301     // for our arrays
302     SkASSERT(0 == SkCanvas::kPoints_PointMode);
303     SkASSERT(1 == SkCanvas::kLines_PointMode);
304     SkASSERT(2 == SkCanvas::kPolygon_PointMode);
305     SkASSERT((unsigned)fMode <= (unsigned)SkCanvas::kPolygon_PointMode);
306 
307     if (fPaint->isAntiAlias()) {
308         if (0 == fPaint->getStrokeWidth()) {
309             static const Proc gAAProcs[] = {
310                 aa_square_proc, aa_line_hair_proc, aa_poly_hair_proc
311             };
312             proc = gAAProcs[fMode];
313         } else if (fPaint->getStrokeCap() != SkPaint::kRound_Cap) {
314             SkASSERT(SkCanvas::kPoints_PointMode == fMode);
315             proc = aa_square_proc;
316         }
317     } else {    // BW
318         if (fRadius <= 0.5f) {    // small radii and hairline
319             if (SkCanvas::kPoints_PointMode == fMode && fClip->isRect()) {
320                 uint32_t value;
321                 const SkPixmap* bm = blitter->justAnOpaqueColor(&value);
322                 if (bm && kRGB_565_SkColorType == bm->colorType()) {
323                     proc = bw_pt_rect_16_hair_proc;
324                 } else if (bm && kN32_SkColorType == bm->colorType()) {
325                     proc = bw_pt_rect_32_hair_proc;
326                 } else {
327                     proc = bw_pt_rect_hair_proc;
328                 }
329             } else {
330                 static Proc gBWProcs[] = {
331                     bw_pt_hair_proc, bw_line_hair_proc, bw_poly_hair_proc
332                 };
333                 proc = gBWProcs[fMode];
334             }
335         } else {
336             proc = bw_square_proc;
337         }
338     }
339     return proc;
340 }
341 
342 // each of these costs 8-bytes of stack space, so don't make it too large
343 // must be even for lines/polygon to work
344 #define MAX_DEV_PTS     32
345 
drawPoints(SkCanvas::PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint,SkBaseDevice * device) const346 void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count,
347                         const SkPoint pts[], const SkPaint& paint,
348                         SkBaseDevice* device) const {
349     // if we're in lines mode, force count to be even
350     if (SkCanvas::kLines_PointMode == mode) {
351         count &= ~(size_t)1;
352     }
353 
354     if ((long)count <= 0) {
355         return;
356     }
357 
358     SkASSERT(pts != nullptr);
359     SkDEBUGCODE(this->validate();)
360 
361      // nothing to draw
362     if (fRC->isEmpty()) {
363         return;
364     }
365 
366     if (!SkScalarsAreFinite(&pts[0].fX, count * 2)) {
367         return;
368     }
369 
370     SkMatrix ctm = fMatrixProvider->localToDevice();
371     PtProcRec rec;
372     if (!device && rec.init(mode, paint, &ctm, fRC)) {
373         SkAutoBlitterChoose blitter(*this, nullptr, paint);
374 
375         SkPoint             devPts[MAX_DEV_PTS];
376         SkBlitter*          bltr = blitter.get();
377         PtProcRec::Proc     proc = rec.chooseProc(&bltr);
378         // we have to back up subsequent passes if we're in polygon mode
379         const size_t backup = (SkCanvas::kPolygon_PointMode == mode);
380 
381         do {
382             int n = SkToInt(count);
383             if (n > MAX_DEV_PTS) {
384                 n = MAX_DEV_PTS;
385             }
386             ctm.mapPoints(devPts, pts, n);
387             if (!SkScalarsAreFinite(&devPts[0].fX, n * 2)) {
388                 return;
389             }
390             proc(rec, devPts, n, bltr);
391             pts += n - backup;
392             SkASSERT(SkToInt(count) >= n);
393             count -= n;
394             if (count > 0) {
395                 count += backup;
396             }
397         } while (count != 0);
398     } else {
399         switch (mode) {
400             case SkCanvas::kPoints_PointMode: {
401                 // temporarily mark the paint as filling.
402                 SkPaint newPaint(paint);
403                 newPaint.setStyle(SkPaint::kFill_Style);
404 
405                 SkScalar width = newPaint.getStrokeWidth();
406                 SkScalar radius = SkScalarHalf(width);
407 
408                 if (newPaint.getStrokeCap() == SkPaint::kRound_Cap) {
409                     if (device) {
410                         for (size_t i = 0; i < count; ++i) {
411                             SkRect r = SkRect::MakeLTRB(pts[i].fX - radius, pts[i].fY - radius,
412                                                         pts[i].fX + radius, pts[i].fY + radius);
413                             device->drawOval(r, newPaint);
414                         }
415                     } else {
416                         SkPath     path;
417                         SkMatrix   preMatrix;
418 
419                         path.addCircle(0, 0, radius);
420                         for (size_t i = 0; i < count; i++) {
421                             preMatrix.setTranslate(pts[i].fX, pts[i].fY);
422                             // pass true for the last point, since we can modify
423                             // then path then
424                             path.setIsVolatile((count-1) == i);
425                             this->drawPath(path, newPaint, &preMatrix, (count-1) == i);
426                         }
427                     }
428                 } else {
429                     SkRect  r;
430 
431                     for (size_t i = 0; i < count; i++) {
432                         r.fLeft = pts[i].fX - radius;
433                         r.fTop = pts[i].fY - radius;
434                         r.fRight = r.fLeft + width;
435                         r.fBottom = r.fTop + width;
436                         if (device) {
437                             device->drawRect(r, newPaint);
438                         } else {
439                             this->drawRect(r, newPaint);
440                         }
441                     }
442                 }
443                 break;
444             }
445             case SkCanvas::kLines_PointMode:
446                 if (2 == count && paint.getPathEffect()) {
447                     // most likely a dashed line - see if it is one of the ones
448                     // we can accelerate
449                     SkStrokeRec stroke(paint);
450                     SkPathEffectBase::PointData pointData;
451 
452                     SkPath path = SkPath::Line(pts[0], pts[1]);
453 
454                     SkRect cullRect = SkRect::Make(fRC->getBounds());
455 
456                     if (as_PEB(paint.getPathEffect())->asPoints(&pointData, path, stroke, ctm,
457                                                                 &cullRect)) {
458                         // 'asPoints' managed to find some fast path
459 
460                         SkPaint newP(paint);
461                         newP.setPathEffect(nullptr);
462                         newP.setStyle(SkPaint::kFill_Style);
463 
464                         if (!pointData.fFirst.isEmpty()) {
465                             if (device) {
466                                 device->drawPath(pointData.fFirst, newP);
467                             } else {
468                                 this->drawPath(pointData.fFirst, newP);
469                             }
470                         }
471 
472                         if (!pointData.fLast.isEmpty()) {
473                             if (device) {
474                                 device->drawPath(pointData.fLast, newP);
475                             } else {
476                                 this->drawPath(pointData.fLast, newP);
477                             }
478                         }
479 
480                         if (pointData.fSize.fX == pointData.fSize.fY) {
481                             // The rest of the dashed line can just be drawn as points
482                             SkASSERT(pointData.fSize.fX == SkScalarHalf(newP.getStrokeWidth()));
483 
484                             if (SkPathEffectBase::PointData::kCircles_PointFlag & pointData.fFlags) {
485                                 newP.setStrokeCap(SkPaint::kRound_Cap);
486                             } else {
487                                 newP.setStrokeCap(SkPaint::kButt_Cap);
488                             }
489 
490                             if (device) {
491                                 device->drawPoints(SkCanvas::kPoints_PointMode,
492                                                    pointData.fNumPoints,
493                                                    pointData.fPoints,
494                                                    newP);
495                             } else {
496                                 this->drawPoints(SkCanvas::kPoints_PointMode,
497                                                  pointData.fNumPoints,
498                                                  pointData.fPoints,
499                                                  newP,
500                                                  device);
501                             }
502                             break;
503                         } else {
504                             // The rest of the dashed line must be drawn as rects
505                             SkASSERT(!(SkPathEffectBase::PointData::kCircles_PointFlag &
506                                       pointData.fFlags));
507 
508                             SkRect r;
509 
510                             for (int i = 0; i < pointData.fNumPoints; ++i) {
511                                 r.setLTRB(pointData.fPoints[i].fX - pointData.fSize.fX,
512                                           pointData.fPoints[i].fY - pointData.fSize.fY,
513                                           pointData.fPoints[i].fX + pointData.fSize.fX,
514                                           pointData.fPoints[i].fY + pointData.fSize.fY);
515                                 if (device) {
516                                     device->drawRect(r, newP);
517                                 } else {
518                                     this->drawRect(r, newP);
519                                 }
520                             }
521                         }
522 
523                         break;
524                     }
525                 }
526                 [[fallthrough]]; // couldn't take fast path
527             case SkCanvas::kPolygon_PointMode: {
528                 count -= 1;
529                 SkPath path;
530                 SkPaint p(paint);
531                 p.setStyle(SkPaint::kStroke_Style);
532                 size_t inc = (SkCanvas::kLines_PointMode == mode) ? 2 : 1;
533                 path.setIsVolatile(true);
534                 for (size_t i = 0; i < count; i += inc) {
535                     path.moveTo(pts[i]);
536                     path.lineTo(pts[i+1]);
537                     if (device) {
538                         device->drawPath(path, p, true);
539                     } else {
540                         this->drawPath(path, p, nullptr, true);
541                     }
542                     path.rewind();
543                 }
544                 break;
545             }
546         }
547     }
548 }
549 
compute_stroke_size(const SkPaint & paint,const SkMatrix & matrix)550 static inline SkPoint compute_stroke_size(const SkPaint& paint, const SkMatrix& matrix) {
551     SkASSERT(matrix.rectStaysRect());
552     SkASSERT(SkPaint::kFill_Style != paint.getStyle());
553 
554     SkVector size;
555     SkPoint pt = { paint.getStrokeWidth(), paint.getStrokeWidth() };
556     matrix.mapVectors(&size, &pt, 1);
557     return SkPoint::Make(SkScalarAbs(size.fX), SkScalarAbs(size.fY));
558 }
559 
easy_rect_join(const SkRect & rect,const SkPaint & paint,const SkMatrix & matrix,SkPoint * strokeSize)560 static bool easy_rect_join(const SkRect& rect, const SkPaint& paint, const SkMatrix& matrix,
561                            SkPoint* strokeSize) {
562     if (rect.isEmpty() || SkPaint::kMiter_Join != paint.getStrokeJoin() ||
563         paint.getStrokeMiter() < SK_ScalarSqrt2) {
564         return false;
565     }
566 
567     *strokeSize = compute_stroke_size(paint, matrix);
568     return true;
569 }
570 
ComputeRectType(const SkRect & rect,const SkPaint & paint,const SkMatrix & matrix,SkPoint * strokeSize)571 SkDraw::RectType SkDraw::ComputeRectType(const SkRect& rect,
572                                          const SkPaint& paint,
573                                          const SkMatrix& matrix,
574                                          SkPoint* strokeSize) {
575     RectType rtype;
576     const SkScalar width = paint.getStrokeWidth();
577     const bool zeroWidth = (0 == width);
578     SkPaint::Style style = paint.getStyle();
579 
580     if ((SkPaint::kStrokeAndFill_Style == style) && zeroWidth) {
581         style = SkPaint::kFill_Style;
582     }
583 
584     if (paint.getPathEffect() || paint.getMaskFilter() ||
585         !matrix.rectStaysRect() || SkPaint::kStrokeAndFill_Style == style) {
586         rtype = kPath_RectType;
587     } else if (SkPaint::kFill_Style == style) {
588         rtype = kFill_RectType;
589     } else if (zeroWidth) {
590         rtype = kHair_RectType;
591     } else if (easy_rect_join(rect, paint, matrix, strokeSize)) {
592         rtype = kStroke_RectType;
593     } else {
594         rtype = kPath_RectType;
595     }
596     return rtype;
597 }
598 
rect_points(const SkRect & r)599 static const SkPoint* rect_points(const SkRect& r) {
600     return reinterpret_cast<const SkPoint*>(&r);
601 }
602 
rect_points(SkRect & r)603 static SkPoint* rect_points(SkRect& r) {
604     return reinterpret_cast<SkPoint*>(&r);
605 }
606 
draw_rect_as_path(const SkDraw & orig,const SkRect & prePaintRect,const SkPaint & paint,const SkMatrixProvider * matrixProvider)607 static void draw_rect_as_path(const SkDraw& orig, const SkRect& prePaintRect,
608                               const SkPaint& paint, const SkMatrixProvider* matrixProvider) {
609     SkDraw draw(orig);
610     draw.fMatrixProvider = matrixProvider;
611     SkPath  tmp;
612     tmp.addRect(prePaintRect);
613     tmp.setFillType(SkPathFillType::kWinding);
614     draw.drawPath(tmp, paint, nullptr, true);
615 }
616 
drawRect(const SkRect & prePaintRect,const SkPaint & paint,const SkMatrix * paintMatrix,const SkRect * postPaintRect) const617 void SkDraw::drawRect(const SkRect& prePaintRect, const SkPaint& paint,
618                       const SkMatrix* paintMatrix, const SkRect* postPaintRect) const {
619     SkDEBUGCODE(this->validate();)
620 
621     // nothing to draw
622     if (fRC->isEmpty()) {
623         return;
624     }
625 
626     const SkMatrixProvider* matrixProvider = fMatrixProvider;
627     SkTLazy<SkPreConcatMatrixProvider> preConcatMatrixProvider;
628     if (paintMatrix) {
629         SkASSERT(postPaintRect);
630         matrixProvider = preConcatMatrixProvider.init(*matrixProvider, *paintMatrix);
631     } else {
632         SkASSERT(!postPaintRect);
633     }
634 
635     SkMatrix ctm = fMatrixProvider->localToDevice();
636     SkPoint strokeSize;
637     RectType rtype = ComputeRectType(prePaintRect, paint, ctm, &strokeSize);
638 
639     if (kPath_RectType == rtype) {
640         draw_rect_as_path(*this, prePaintRect, paint, matrixProvider);
641         return;
642     }
643 
644     SkRect devRect;
645     const SkRect& paintRect = paintMatrix ? *postPaintRect : prePaintRect;
646     // skip the paintMatrix when transforming the rect by the CTM
647     ctm.mapPoints(rect_points(devRect), rect_points(paintRect), 2);
648     devRect.sort();
649 
650     // look for the quick exit, before we build a blitter
651     SkRect bbox = devRect;
652     if (paint.getStyle() != SkPaint::kFill_Style) {
653         // extra space for hairlines
654         if (paint.getStrokeWidth() == 0) {
655             bbox.outset(1, 1);
656         } else {
657             // For kStroke_RectType, strokeSize is already computed.
658             const SkPoint& ssize = (kStroke_RectType == rtype)
659                 ? strokeSize
660                 : compute_stroke_size(paint, ctm);
661             bbox.outset(SkScalarHalf(ssize.x()), SkScalarHalf(ssize.y()));
662         }
663     }
664     if (SkPathPriv::TooBigForMath(bbox)) {
665         return;
666     }
667 
668     if (!SkRectPriv::FitsInFixed(bbox) && rtype != kHair_RectType) {
669         draw_rect_as_path(*this, prePaintRect, paint, matrixProvider);
670         return;
671     }
672 
673     SkIRect ir = bbox.roundOut();
674     if (fRC->quickReject(ir)) {
675         return;
676     }
677 
678     SkAutoBlitterChoose blitterStorage(*this, matrixProvider, paint);
679     const SkRasterClip& clip = *fRC;
680     SkBlitter*          blitter = blitterStorage.get();
681 
682     // we want to "fill" if we are kFill or kStrokeAndFill, since in the latter
683     // case we are also hairline (if we've gotten to here), which devolves to
684     // effectively just kFill
685     switch (rtype) {
686         case kFill_RectType:
687             if (paint.isAntiAlias()) {
688                 SkScan::AntiFillRect(devRect, clip, blitter);
689             } else {
690                 SkScan::FillRect(devRect, clip, blitter);
691             }
692             break;
693         case kStroke_RectType:
694             if (paint.isAntiAlias()) {
695                 SkScan::AntiFrameRect(devRect, strokeSize, clip, blitter);
696             } else {
697                 SkScan::FrameRect(devRect, strokeSize, clip, blitter);
698             }
699             break;
700         case kHair_RectType:
701             if (paint.isAntiAlias()) {
702                 SkScan::AntiHairRect(devRect, clip, blitter);
703             } else {
704                 SkScan::HairRect(devRect, clip, blitter);
705             }
706             break;
707         default:
708             SkDEBUGFAIL("bad rtype");
709     }
710 }
711 
712 #if defined(SK_SUPPORT_LEGACY_ALPHA_BITMAP_AS_COVERAGE)
drawDevMask(const SkMask & srcM,const SkPaint & paint) const713 void SkDraw::drawDevMask(const SkMask& srcM, const SkPaint& paint) const {
714     if (srcM.fBounds.isEmpty()) {
715         return;
716     }
717 
718     const SkMask* mask = &srcM;
719 
720     SkMask dstM;
721     if (paint.getMaskFilter() &&
722         as_MFB(paint.getMaskFilter())
723                 ->filterMask(&dstM, srcM, fMatrixProvider->localToDevice(), nullptr)) {
724         mask = &dstM;
725     }
726     SkAutoMaskFreeImage ami(dstM.fImage);
727 
728     SkAutoBlitterChoose blitterChooser(*this, nullptr, paint);
729     SkBlitter* blitter = blitterChooser.get();
730 
731     SkAAClipBlitterWrapper wrapper;
732     const SkRegion* clipRgn;
733 
734     if (fRC->isBW()) {
735         clipRgn = &fRC->bwRgn();
736     } else {
737         wrapper.init(*fRC, blitter);
738         clipRgn = &wrapper.getRgn();
739         blitter = wrapper.getBlitter();
740     }
741     blitter->blitMaskRegion(*mask, *clipRgn);
742 }
743 #endif
744 
fast_len(const SkVector & vec)745 static SkScalar fast_len(const SkVector& vec) {
746     SkScalar x = SkScalarAbs(vec.fX);
747     SkScalar y = SkScalarAbs(vec.fY);
748     if (x < y) {
749         using std::swap;
750         swap(x, y);
751     }
752     return x + SkScalarHalf(y);
753 }
754 
SkDrawTreatAAStrokeAsHairline(SkScalar strokeWidth,const SkMatrix & matrix,SkScalar * coverage)755 bool SkDrawTreatAAStrokeAsHairline(SkScalar strokeWidth, const SkMatrix& matrix,
756                                    SkScalar* coverage) {
757     SkASSERT(strokeWidth > 0);
758     // We need to try to fake a thick-stroke with a modulated hairline.
759 
760     if (matrix.hasPerspective()) {
761         return false;
762     }
763 
764     SkVector src[2], dst[2];
765     src[0].set(strokeWidth, 0);
766     src[1].set(0, strokeWidth);
767     matrix.mapVectors(dst, src, 2);
768     SkScalar len0 = fast_len(dst[0]);
769     SkScalar len1 = fast_len(dst[1]);
770     if (len0 <= SK_Scalar1 && len1 <= SK_Scalar1) {
771         if (coverage) {
772             *coverage = SkScalarAve(len0, len1);
773         }
774         return true;
775     }
776     return false;
777 }
778 
drawRRect(const SkRRect & rrect,const SkPaint & paint) const779 void SkDraw::drawRRect(const SkRRect& rrect, const SkPaint& paint) const {
780     SkDEBUGCODE(this->validate());
781 
782     if (fRC->isEmpty()) {
783         return;
784     }
785 
786     SkMatrix ctm = fMatrixProvider->localToDevice();
787     {
788         // TODO: Investigate optimizing these options. They are in the same
789         // order as SkDraw::drawPath, which handles each case. It may be
790         // that there is no way to optimize for these using the SkRRect path.
791         SkScalar coverage;
792         if (SkDrawTreatAsHairline(paint, ctm, &coverage)) {
793             goto DRAW_PATH;
794         }
795 
796         if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
797             goto DRAW_PATH;
798         }
799     }
800 
801     if (paint.getMaskFilter()) {
802         // Transform the rrect into device space.
803         SkRRect devRRect;
804         if (rrect.transform(ctm, &devRRect)) {
805             SkAutoBlitterChoose blitter(*this, nullptr, paint);
806             if (as_MFB(paint.getMaskFilter())->filterRRect(devRRect, ctm, *fRC, blitter.get())) {
807                 return;  // filterRRect() called the blitter, so we're done
808             }
809         }
810     }
811 
812 DRAW_PATH:
813     // Now fall back to the default case of using a path.
814     SkPath path;
815     path.addRRect(rrect);
816     this->drawPath(path, paint, nullptr, true);
817 }
818 
drawDevPath(const SkPath & devPath,const SkPaint & paint,bool drawCoverage,SkBlitter * customBlitter,bool doFill) const819 void SkDraw::drawDevPath(const SkPath& devPath, const SkPaint& paint, bool drawCoverage,
820                          SkBlitter* customBlitter, bool doFill) const {
821     if (SkPathPriv::TooBigForMath(devPath)) {
822         return;
823     }
824     SkBlitter* blitter = nullptr;
825     SkAutoBlitterChoose blitterStorage;
826     if (nullptr == customBlitter) {
827         blitter = blitterStorage.choose(*this, nullptr, paint, drawCoverage);
828     } else {
829         blitter = customBlitter;
830     }
831 
832     if (paint.getMaskFilter()) {
833         SkStrokeRec::InitStyle style = doFill ? SkStrokeRec::kFill_InitStyle
834                                               : SkStrokeRec::kHairline_InitStyle;
835         if (as_MFB(paint.getMaskFilter())
836                     ->filterPath(devPath, fMatrixProvider->localToDevice(), *fRC, blitter, style)) {
837             return;  // filterPath() called the blitter, so we're done
838         }
839     }
840 
841     void (*proc)(const SkPath&, const SkRasterClip&, SkBlitter*);
842     if (doFill) {
843         if (paint.isAntiAlias()) {
844             proc = SkScan::AntiFillPath;
845         } else {
846             proc = SkScan::FillPath;
847         }
848     } else {    // hairline
849         if (paint.isAntiAlias()) {
850             switch (paint.getStrokeCap()) {
851                 case SkPaint::kButt_Cap:
852                     proc = SkScan::AntiHairPath;
853                     break;
854                 case SkPaint::kSquare_Cap:
855                     proc = SkScan::AntiHairSquarePath;
856                     break;
857                 case SkPaint::kRound_Cap:
858                     proc = SkScan::AntiHairRoundPath;
859                     break;
860             }
861         } else {
862             switch (paint.getStrokeCap()) {
863                 case SkPaint::kButt_Cap:
864                     proc = SkScan::HairPath;
865                     break;
866                 case SkPaint::kSquare_Cap:
867                     proc = SkScan::HairSquarePath;
868                     break;
869                 case SkPaint::kRound_Cap:
870                     proc = SkScan::HairRoundPath;
871                     break;
872             }
873         }
874     }
875 
876     proc(devPath, *fRC, blitter);
877 }
878 
drawPath(const SkPath & origSrcPath,const SkPaint & origPaint,const SkMatrix * prePathMatrix,bool pathIsMutable,bool drawCoverage,SkBlitter * customBlitter) const879 void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint,
880                       const SkMatrix* prePathMatrix, bool pathIsMutable,
881                       bool drawCoverage, SkBlitter* customBlitter) const {
882     SkDEBUGCODE(this->validate();)
883 
884     // nothing to draw
885     if (fRC->isEmpty()) {
886         return;
887     }
888 
889     SkPath*         pathPtr = (SkPath*)&origSrcPath;
890     bool            doFill = true;
891     SkPath          tmpPathStorage;
892     SkPath*         tmpPath = &tmpPathStorage;
893     const SkMatrixProvider*            matrixProvider = fMatrixProvider;
894     SkTLazy<SkPreConcatMatrixProvider> preConcatMatrixProvider;
895     tmpPath->setIsVolatile(true);
896 
897     if (prePathMatrix) {
898         if (origPaint.getPathEffect() || origPaint.getStyle() != SkPaint::kFill_Style) {
899             SkPath* result = pathPtr;
900 
901             if (!pathIsMutable) {
902                 result = tmpPath;
903                 pathIsMutable = true;
904             }
905             pathPtr->transform(*prePathMatrix, result);
906             pathPtr = result;
907         } else {
908             matrixProvider = preConcatMatrixProvider.init(*matrixProvider, *prePathMatrix);
909         }
910     }
911 
912     SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
913 
914     {
915         SkScalar coverage;
916         if (SkDrawTreatAsHairline(origPaint, matrixProvider->localToDevice(), &coverage)) {
917             const auto bm = origPaint.asBlendMode();
918             if (SK_Scalar1 == coverage) {
919                 paint.writable()->setStrokeWidth(0);
920             } else if (bm && SkBlendMode_SupportsCoverageAsAlpha(bm.value())) {
921                 U8CPU newAlpha;
922 #if 0
923                 newAlpha = SkToU8(SkScalarRoundToInt(coverage *
924                                                      origPaint.getAlpha()));
925 #else
926                 // this is the old technique, which we preserve for now so
927                 // we don't change previous results (testing)
928                 // the new way seems fine, its just (a tiny bit) different
929                 int scale = (int)(coverage * 256);
930                 newAlpha = origPaint.getAlpha() * scale >> 8;
931 #endif
932                 SkPaint* writablePaint = paint.writable();
933                 writablePaint->setStrokeWidth(0);
934                 writablePaint->setAlpha(newAlpha);
935             }
936         }
937     }
938 
939     if (paint->getPathEffect() || paint->getStyle() != SkPaint::kFill_Style) {
940         SkRect cullRect;
941         const SkRect* cullRectPtr = nullptr;
942         if (this->computeConservativeLocalClipBounds(&cullRect)) {
943             cullRectPtr = &cullRect;
944         }
945         doFill = skpathutils::FillPathWithPaint(*pathPtr, *paint, tmpPath, cullRectPtr,
946                                                 fMatrixProvider->localToDevice());
947         pathPtr = tmpPath;
948     }
949 
950     // avoid possibly allocating a new path in transform if we can
951     SkPath* devPathPtr = pathIsMutable ? pathPtr : tmpPath;
952 
953     // transform the path into device space
954     pathPtr->transform(matrixProvider->localToDevice(), devPathPtr);
955 
956 #if defined(SK_BUILD_FOR_FUZZER)
957     if (devPathPtr->countPoints() > 1000) {
958         return;
959     }
960 #endif
961 
962     this->drawDevPath(*devPathPtr, *paint, drawCoverage, customBlitter, doFill);
963 }
964 
965 #if defined(SK_SUPPORT_LEGACY_ALPHA_BITMAP_AS_COVERAGE)
drawBitmapAsMask(const SkBitmap & bitmap,const SkSamplingOptions & sampling,const SkPaint & paint) const966 void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, const SkSamplingOptions& sampling,
967                               const SkPaint& paint) const {
968     SkASSERT(bitmap.colorType() == kAlpha_8_SkColorType);
969 
970     // nothing to draw
971     if (fRC->isEmpty()) {
972         return;
973     }
974 
975     SkMatrix ctm = fMatrixProvider->localToDevice();
976     if (SkTreatAsSprite(ctm, bitmap.dimensions(), sampling, paint.isAntiAlias()))
977     {
978         int ix = SkScalarRoundToInt(ctm.getTranslateX());
979         int iy = SkScalarRoundToInt(ctm.getTranslateY());
980 
981         SkPixmap pmap;
982         if (!bitmap.peekPixels(&pmap)) {
983             return;
984         }
985         SkMask  mask;
986         mask.fBounds.setXYWH(ix, iy, pmap.width(), pmap.height());
987         mask.fFormat = SkMask::kA8_Format;
988         mask.fRowBytes = SkToU32(pmap.rowBytes());
989         // fImage is typed as writable, but in this case it is used read-only
990         mask.fImage = (uint8_t*)pmap.addr8(0, 0);
991 
992         this->drawDevMask(mask, paint);
993     } else {    // need to xform the bitmap first
994         SkRect  r;
995         SkMask  mask;
996 
997         r.setIWH(bitmap.width(), bitmap.height());
998         ctm.mapRect(&r);
999         r.round(&mask.fBounds);
1000 
1001         // set the mask's bounds to the transformed bitmap-bounds,
1002         // clipped to the actual device and further limited by the clip bounds
1003         {
1004             SkASSERT(fDst.bounds().contains(fRC->getBounds()));
1005             SkIRect devBounds = fDst.bounds();
1006             devBounds.intersect(fRC->getBounds().makeOutset(1, 1));
1007             // need intersect(l, t, r, b) on irect
1008             if (!mask.fBounds.intersect(devBounds)) {
1009                 return;
1010             }
1011         }
1012 
1013         mask.fFormat = SkMask::kA8_Format;
1014         mask.fRowBytes = SkAlign4(mask.fBounds.width());
1015         size_t size = mask.computeImageSize();
1016         if (0 == size) {
1017             // the mask is too big to allocated, draw nothing
1018             return;
1019         }
1020 
1021         // allocate (and clear) our temp buffer to hold the transformed bitmap
1022         AutoTMalloc<uint8_t> storage(size);
1023         mask.fImage = storage.get();
1024         memset(mask.fImage, 0, size);
1025 
1026         // now draw our bitmap(src) into mask(dst), transformed by the matrix
1027         {
1028             SkBitmap    device;
1029             device.installPixels(SkImageInfo::MakeA8(mask.fBounds.width(), mask.fBounds.height()),
1030                                  mask.fImage, mask.fRowBytes);
1031 
1032             SkCanvas c(device);
1033             // need the unclipped top/left for the translate
1034             c.translate(-SkIntToScalar(mask.fBounds.fLeft),
1035                         -SkIntToScalar(mask.fBounds.fTop));
1036             c.concat(ctm);
1037 
1038             // We can't call drawBitmap, or we'll infinitely recurse. Instead
1039             // we manually build a shader and draw that into our new mask
1040             SkPaint tmpPaint;
1041             tmpPaint.setAntiAlias(paint.isAntiAlias());
1042             tmpPaint.setDither(paint.isDither());
1043             SkPaint paintWithShader = make_paint_with_image(tmpPaint, bitmap, sampling);
1044             SkRect rr;
1045             rr.setIWH(bitmap.width(), bitmap.height());
1046             c.drawRect(rr, paintWithShader);
1047         }
1048         this->drawDevMask(mask, paint);
1049     }
1050 }
1051 #endif
1052 
clipped_out(const SkMatrix & m,const SkRasterClip & c,const SkRect & srcR)1053 static bool clipped_out(const SkMatrix& m, const SkRasterClip& c,
1054                         const SkRect& srcR) {
1055     SkRect  dstR;
1056     m.mapRect(&dstR, srcR);
1057     return c.quickReject(dstR.roundOut());
1058 }
1059 
clipped_out(const SkMatrix & matrix,const SkRasterClip & clip,int width,int height)1060 static bool clipped_out(const SkMatrix& matrix, const SkRasterClip& clip,
1061                         int width, int height) {
1062     SkRect  r;
1063     r.setIWH(width, height);
1064     return clipped_out(matrix, clip, r);
1065 }
1066 
clipHandlesSprite(const SkRasterClip & clip,int x,int y,const SkPixmap & pmap)1067 static bool clipHandlesSprite(const SkRasterClip& clip, int x, int y, const SkPixmap& pmap) {
1068     return clip.isBW() || clip.quickContains(SkIRect::MakeXYWH(x, y, pmap.width(), pmap.height()));
1069 }
1070 
drawBitmap(const SkBitmap & bitmap,const SkMatrix & prematrix,const SkRect * dstBounds,const SkSamplingOptions & sampling,const SkPaint & origPaint) const1071 void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix,
1072                         const SkRect* dstBounds, const SkSamplingOptions& sampling,
1073                         const SkPaint& origPaint) const {
1074     SkDEBUGCODE(this->validate();)
1075 
1076     // nothing to draw
1077     if (fRC->isEmpty() ||
1078             bitmap.width() == 0 || bitmap.height() == 0 ||
1079             bitmap.colorType() == kUnknown_SkColorType) {
1080         return;
1081     }
1082 
1083     SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
1084     if (origPaint.getStyle() != SkPaint::kFill_Style) {
1085         paint.writable()->setStyle(SkPaint::kFill_Style);
1086     }
1087 
1088     SkPreConcatMatrixProvider matrixProvider(*fMatrixProvider, prematrix);
1089     SkMatrix matrix = matrixProvider.localToDevice();
1090 
1091     if (clipped_out(matrix, *fRC, bitmap.width(), bitmap.height())) {
1092         return;
1093     }
1094 
1095     if (!SkColorTypeIsAlphaOnly(bitmap.colorType()) &&
1096         SkTreatAsSprite(matrix, bitmap.dimensions(), sampling, paint->isAntiAlias())) {
1097         //
1098         // It is safe to call lock pixels now, since we know the matrix is
1099         // (more or less) identity.
1100         //
1101         SkPixmap pmap;
1102         if (!bitmap.peekPixels(&pmap)) {
1103             return;
1104         }
1105         int ix = SkScalarRoundToInt(matrix.getTranslateX());
1106         int iy = SkScalarRoundToInt(matrix.getTranslateY());
1107         if (clipHandlesSprite(*fRC, ix, iy, pmap)) {
1108             SkSTArenaAlloc<kSkBlitterContextSize> allocator;
1109             // blitter will be owned by the allocator.
1110             SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, *paint, pmap, ix, iy, &allocator,
1111                                                          fRC->clipShader());
1112             if (blitter) {
1113                 SkScan::FillIRect(SkIRect::MakeXYWH(ix, iy, pmap.width(), pmap.height()),
1114                                   *fRC, blitter);
1115                 return;
1116             }
1117             // if !blitter, then we fall-through to the slower case
1118         }
1119     }
1120 
1121     // now make a temp draw on the stack, and use it
1122     //
1123     SkDraw draw(*this);
1124     draw.fMatrixProvider = &matrixProvider;
1125 
1126     // For a long time, the CPU backend treated A8 bitmaps as coverage, rather than alpha. This was
1127     // inconsistent with the GPU backend (skbug.com/9692). When this was fixed, it altered behavior
1128     // for some Android apps (b/231400686). Thus: keep the old behavior in the framework.
1129 #if defined(SK_SUPPORT_LEGACY_ALPHA_BITMAP_AS_COVERAGE)
1130     if (bitmap.colorType() == kAlpha_8_SkColorType && !paint->getColorFilter()) {
1131         draw.drawBitmapAsMask(bitmap, sampling, *paint);
1132         return;
1133     }
1134 #endif
1135 
1136     SkPaint paintWithShader = make_paint_with_image(*paint, bitmap, sampling);
1137     const SkRect srcBounds = SkRect::MakeIWH(bitmap.width(), bitmap.height());
1138     if (dstBounds) {
1139         this->drawRect(srcBounds, paintWithShader, &prematrix, dstBounds);
1140     } else {
1141         draw.drawRect(srcBounds, paintWithShader);
1142     }
1143 }
1144 
drawSprite(const SkBitmap & bitmap,int x,int y,const SkPaint & origPaint) const1145 void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& origPaint) const {
1146     SkDEBUGCODE(this->validate();)
1147 
1148     // nothing to draw
1149     if (fRC->isEmpty() ||
1150             bitmap.width() == 0 || bitmap.height() == 0 ||
1151             bitmap.colorType() == kUnknown_SkColorType) {
1152         return;
1153     }
1154 
1155     const SkIRect bounds = SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height());
1156 
1157     if (fRC->quickReject(bounds)) {
1158         return; // nothing to draw
1159     }
1160 
1161     SkPaint paint(origPaint);
1162     paint.setStyle(SkPaint::kFill_Style);
1163 
1164     SkPixmap pmap;
1165     if (!bitmap.peekPixels(&pmap)) {
1166         return;
1167     }
1168 
1169     if (nullptr == paint.getColorFilter() && clipHandlesSprite(*fRC, x, y, pmap)) {
1170         // blitter will be owned by the allocator.
1171         SkSTArenaAlloc<kSkBlitterContextSize> allocator;
1172         SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, paint, pmap, x, y, &allocator,
1173                                                      fRC->clipShader());
1174         if (blitter) {
1175             SkScan::FillIRect(bounds, *fRC, blitter);
1176             return;
1177         }
1178     }
1179 
1180     SkMatrix        matrix;
1181     SkRect          r;
1182 
1183     // get a scalar version of our rect
1184     r.set(bounds);
1185 
1186     // create shader with offset
1187     matrix.setTranslate(r.fLeft, r.fTop);
1188     SkPaint paintWithShader = make_paint_with_image(paint, bitmap, SkSamplingOptions(), &matrix);
1189     SkDraw draw(*this);
1190     SkMatrixProvider matrixProvider(SkMatrix::I());
1191     draw.fMatrixProvider = &matrixProvider;
1192     // call ourself with a rect
1193     draw.drawRect(r, paintWithShader);
1194 }
1195 
1196 ////////////////////////////////////////////////////////////////////////////////////////////////
1197 
1198 #ifdef SK_DEBUG
1199 
validate() const1200 void SkDraw::validate() const {
1201     SkASSERT(fMatrixProvider != nullptr);
1202     SkASSERT(fRC != nullptr);
1203 
1204     const SkIRect&  cr = fRC->getBounds();
1205     SkIRect         br;
1206 
1207     br.setWH(fDst.width(), fDst.height());
1208     SkASSERT(cr.isEmpty() || br.contains(cr));
1209 }
1210 
1211 #endif
1212 
1213 ////////////////////////////////////////////////////////////////////////////////////////////////
1214 
1215 #include "include/core/SkPath.h"
1216 #include "include/core/SkRegion.h"
1217 #include "src/core/SkBlitter.h"
1218 #include "src/core/SkDraw.h"
1219 
ComputeMaskBounds(const SkRect & devPathBounds,const SkIRect & clipBounds,const SkMaskFilter * filter,const SkMatrix * filterMatrix,SkIRect * bounds)1220 bool SkDraw::ComputeMaskBounds(const SkRect& devPathBounds, const SkIRect& clipBounds,
1221                                const SkMaskFilter* filter, const SkMatrix* filterMatrix,
1222                                SkIRect* bounds) {
1223     //  init our bounds from the path
1224     *bounds = devPathBounds.makeOutset(SK_ScalarHalf, SK_ScalarHalf).roundOut();
1225 
1226     SkIPoint margin = SkIPoint::Make(0, 0);
1227     if (filter) {
1228         SkASSERT(filterMatrix);
1229 
1230         SkMask srcM, dstM;
1231 
1232         srcM.fBounds = *bounds;
1233         srcM.fFormat = SkMask::kA8_Format;
1234         if (!as_MFB(filter)->filterMask(&dstM, srcM, *filterMatrix, &margin)) {
1235             return false;
1236         }
1237     }
1238 
1239     // trim the bounds to reflect the clip (plus whatever slop the filter needs)
1240     // Ugh. Guard against gigantic margins from wacky filters. Without this
1241     // check we can request arbitrary amounts of slop beyond our visible
1242     // clip, and bring down the renderer (at least on finite RAM machines
1243     // like handsets, etc.). Need to balance this invented value between
1244     // quality of large filters like blurs, and the corresponding memory
1245     // requests.
1246     static constexpr int kMaxMargin = 128;
1247     if (!bounds->intersect(clipBounds.makeOutset(std::min(margin.fX, kMaxMargin),
1248                                                  std::min(margin.fY, kMaxMargin)))) {
1249         return false;
1250     }
1251 
1252     return true;
1253 }
1254 
draw_into_mask(const SkMask & mask,const SkPath & devPath,SkStrokeRec::InitStyle style)1255 static void draw_into_mask(const SkMask& mask, const SkPath& devPath,
1256                            SkStrokeRec::InitStyle style) {
1257     SkDraw draw;
1258     if (!draw.fDst.reset(mask)) {
1259         return;
1260     }
1261 
1262     SkRasterClip    clip;
1263     SkMatrix        matrix;
1264     SkPaint         paint;
1265 
1266     clip.setRect(SkIRect::MakeWH(mask.fBounds.width(), mask.fBounds.height()));
1267     matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
1268                         -SkIntToScalar(mask.fBounds.fTop));
1269 
1270     SkMatrixProvider matrixProvider(matrix);
1271     draw.fRC             = &clip;
1272     draw.fMatrixProvider = &matrixProvider;
1273     paint.setAntiAlias(true);
1274     switch (style) {
1275         case SkStrokeRec::kHairline_InitStyle:
1276             SkASSERT(!paint.getStrokeWidth());
1277             paint.setStyle(SkPaint::kStroke_Style);
1278             break;
1279         case SkStrokeRec::kFill_InitStyle:
1280             SkASSERT(paint.getStyle() == SkPaint::kFill_Style);
1281             break;
1282 
1283     }
1284     draw.drawPath(devPath, paint);
1285 }
1286 
DrawToMask(const SkPath & devPath,const SkIRect & clipBounds,const SkMaskFilter * filter,const SkMatrix * filterMatrix,SkMask * mask,SkMask::CreateMode mode,SkStrokeRec::InitStyle style)1287 bool SkDraw::DrawToMask(const SkPath& devPath, const SkIRect& clipBounds,
1288                         const SkMaskFilter* filter, const SkMatrix* filterMatrix,
1289                         SkMask* mask, SkMask::CreateMode mode,
1290                         SkStrokeRec::InitStyle style) {
1291     if (devPath.isEmpty()) {
1292         return false;
1293     }
1294 
1295     if (SkMask::kJustRenderImage_CreateMode != mode) {
1296         // By using infinite bounds for inverse fills, ComputeMaskBounds is able to clip it to
1297         // 'clipBounds' outset by whatever extra margin the mask filter requires.
1298         static const SkRect kInverseBounds = { SK_ScalarNegativeInfinity, SK_ScalarNegativeInfinity,
1299                                                SK_ScalarInfinity, SK_ScalarInfinity};
1300         SkRect pathBounds = devPath.isInverseFillType() ? kInverseBounds
1301                                                         : devPath.getBounds();
1302         if (!ComputeMaskBounds(pathBounds, clipBounds, filter,
1303                                filterMatrix, &mask->fBounds))
1304             return false;
1305     }
1306 
1307     if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) {
1308         mask->fFormat = SkMask::kA8_Format;
1309         mask->fRowBytes = mask->fBounds.width();
1310         size_t size = mask->computeImageSize();
1311         if (0 == size) {
1312             // we're too big to allocate the mask, abort
1313             return false;
1314         }
1315         mask->fImage = SkMask::AllocImage(size, SkMask::kZeroInit_Alloc);
1316     }
1317 
1318     if (SkMask::kJustComputeBounds_CreateMode != mode) {
1319         draw_into_mask(*mask, devPath, style);
1320     }
1321 
1322     return true;
1323 }
1324