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