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