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