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(SkPath::kWinding_FillType);
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 = SkTMax(sx, sy);
811         if (scale > 0) {
812             static const SkScalar kMaxStrokeScale = 1e5f;
813             return SkTMin(scale, kMaxStrokeScale);
814         }
815     }
816     return 1;
817 }
818 
drawDevPath(const SkPath & devPath,const SkPaint & paint,bool drawCoverage,SkBlitter * customBlitter,bool doFill) const819 void SkDraw::drawDevPath(const SkPath& devPath, const SkPaint& paint, bool drawCoverage,
820                          SkBlitter* customBlitter, bool doFill) const {
821     if (SkPathPriv::TooBigForMath(devPath)) {
822         return;
823     }
824     SkBlitter* blitter = nullptr;
825     SkAutoBlitterChoose blitterStorage;
826     if (nullptr == customBlitter) {
827         blitter = blitterStorage.choose(*this, nullptr, paint, drawCoverage);
828     } else {
829         blitter = customBlitter;
830     }
831 
832     if (paint.getMaskFilter()) {
833         SkStrokeRec::InitStyle style = doFill ? SkStrokeRec::kFill_InitStyle
834         : SkStrokeRec::kHairline_InitStyle;
835         if (as_MFB(paint.getMaskFilter())->filterPath(devPath, *fMatrix, *fRC, blitter, style)) {
836             return; // filterPath() called the blitter, so we're done
837         }
838     }
839 
840     void (*proc)(const SkPath&, const SkRasterClip&, SkBlitter*);
841     if (doFill) {
842         if (paint.isAntiAlias()) {
843             proc = SkScan::AntiFillPath;
844         } else {
845             proc = SkScan::FillPath;
846         }
847     } else {    // hairline
848         if (paint.isAntiAlias()) {
849             switch (paint.getStrokeCap()) {
850                 case SkPaint::kButt_Cap:
851                     proc = SkScan::AntiHairPath;
852                     break;
853                 case SkPaint::kSquare_Cap:
854                     proc = SkScan::AntiHairSquarePath;
855                     break;
856                 case SkPaint::kRound_Cap:
857                     proc = SkScan::AntiHairRoundPath;
858                     break;
859                 default:
860                     proc SK_INIT_TO_AVOID_WARNING;
861                     SkDEBUGFAIL("unknown paint cap type");
862             }
863         } else {
864             switch (paint.getStrokeCap()) {
865                 case SkPaint::kButt_Cap:
866                     proc = SkScan::HairPath;
867                     break;
868                 case SkPaint::kSquare_Cap:
869                     proc = SkScan::HairSquarePath;
870                     break;
871                 case SkPaint::kRound_Cap:
872                     proc = SkScan::HairRoundPath;
873                     break;
874                 default:
875                     proc SK_INIT_TO_AVOID_WARNING;
876                     SkDEBUGFAIL("unknown paint cap type");
877             }
878         }
879     }
880 
881     proc(devPath, *fRC, blitter);
882 }
883 
drawPath(const SkPath & origSrcPath,const SkPaint & origPaint,const SkMatrix * prePathMatrix,bool pathIsMutable,bool drawCoverage,SkBlitter * customBlitter) const884 void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint,
885                       const SkMatrix* prePathMatrix, bool pathIsMutable,
886                       bool drawCoverage, SkBlitter* customBlitter) const {
887     SkDEBUGCODE(this->validate();)
888 
889     // nothing to draw
890     if (fRC->isEmpty()) {
891         return;
892     }
893 
894     SkPath*         pathPtr = (SkPath*)&origSrcPath;
895     bool            doFill = true;
896     SkPath          tmpPathStorage;
897     SkPath*         tmpPath = &tmpPathStorage;
898     SkMatrix        tmpMatrix;
899     const SkMatrix* matrix = fMatrix;
900     tmpPath->setIsVolatile(true);
901 
902     if (prePathMatrix) {
903         if (origPaint.getPathEffect() || origPaint.getStyle() != SkPaint::kFill_Style) {
904             SkPath* result = pathPtr;
905 
906             if (!pathIsMutable) {
907                 result = tmpPath;
908                 pathIsMutable = true;
909             }
910             pathPtr->transform(*prePathMatrix, result);
911             pathPtr = result;
912         } else {
913             tmpMatrix.setConcat(*matrix, *prePathMatrix);
914             matrix = &tmpMatrix;
915         }
916     }
917     // at this point we're done with prePathMatrix
918     SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
919 
920     SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
921 
922     {
923         SkScalar coverage;
924         if (SkDrawTreatAsHairline(origPaint, *matrix, &coverage)) {
925             if (SK_Scalar1 == coverage) {
926                 paint.writable()->setStrokeWidth(0);
927             } else if (SkBlendMode_SupportsCoverageAsAlpha(origPaint.getBlendMode())) {
928                 U8CPU newAlpha;
929 #if 0
930                 newAlpha = SkToU8(SkScalarRoundToInt(coverage *
931                                                      origPaint.getAlpha()));
932 #else
933                 // this is the old technique, which we preserve for now so
934                 // we don't change previous results (testing)
935                 // the new way seems fine, its just (a tiny bit) different
936                 int scale = (int)(coverage * 256);
937                 newAlpha = origPaint.getAlpha() * scale >> 8;
938 #endif
939                 SkPaint* writablePaint = paint.writable();
940                 writablePaint->setStrokeWidth(0);
941                 writablePaint->setAlpha(newAlpha);
942             }
943         }
944     }
945 
946     if (paint->getPathEffect() || paint->getStyle() != SkPaint::kFill_Style) {
947         SkRect cullRect;
948         const SkRect* cullRectPtr = nullptr;
949         if (this->computeConservativeLocalClipBounds(&cullRect)) {
950             cullRectPtr = &cullRect;
951         }
952         doFill = paint->getFillPath(*pathPtr, tmpPath, cullRectPtr,
953                                     ComputeResScaleForStroking(*fMatrix));
954         pathPtr = tmpPath;
955     }
956 
957     // avoid possibly allocating a new path in transform if we can
958     SkPath* devPathPtr = pathIsMutable ? pathPtr : tmpPath;
959 
960     // transform the path into device space
961     pathPtr->transform(*matrix, devPathPtr);
962 
963     this->drawDevPath(*devPathPtr, *paint, drawCoverage, customBlitter, doFill);
964 }
965 
drawBitmapAsMask(const SkBitmap & bitmap,const SkPaint & paint) const966 void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, const SkPaint& paint) const {
967     SkASSERT(bitmap.colorType() == kAlpha_8_SkColorType);
968 
969     // nothing to draw
970     if (fRC->isEmpty()) {
971         return;
972     }
973 
974     if (SkTreatAsSprite(*fMatrix, bitmap.dimensions(), paint)) {
975         int ix = SkScalarRoundToInt(fMatrix->getTranslateX());
976         int iy = SkScalarRoundToInt(fMatrix->getTranslateY());
977 
978         SkPixmap pmap;
979         if (!bitmap.peekPixels(&pmap)) {
980             return;
981         }
982         SkMask  mask;
983         mask.fBounds.setXYWH(ix, iy, pmap.width(), pmap.height());
984         mask.fFormat = SkMask::kA8_Format;
985         mask.fRowBytes = SkToU32(pmap.rowBytes());
986         // fImage is typed as writable, but in this case it is used read-only
987         mask.fImage = (uint8_t*)pmap.addr8(0, 0);
988 
989         this->drawDevMask(mask, paint);
990     } else {    // need to xform the bitmap first
991         SkRect  r;
992         SkMask  mask;
993 
994         r.setIWH(bitmap.width(), bitmap.height());
995         fMatrix->mapRect(&r);
996         r.round(&mask.fBounds);
997 
998         // set the mask's bounds to the transformed bitmap-bounds,
999         // clipped to the actual device and further limited by the clip bounds
1000         {
1001             SkASSERT(fDst.bounds().contains(fRC->getBounds()));
1002             SkIRect devBounds = fDst.bounds();
1003             devBounds.intersect(fRC->getBounds().makeOutset(1, 1));
1004             // need intersect(l, t, r, b) on irect
1005             if (!mask.fBounds.intersect(devBounds)) {
1006                 return;
1007             }
1008         }
1009 
1010         mask.fFormat = SkMask::kA8_Format;
1011         mask.fRowBytes = SkAlign4(mask.fBounds.width());
1012         size_t size = mask.computeImageSize();
1013         if (0 == size) {
1014             // the mask is too big to allocated, draw nothing
1015             return;
1016         }
1017 
1018         // allocate (and clear) our temp buffer to hold the transformed bitmap
1019         SkAutoTMalloc<uint8_t> storage(size);
1020         mask.fImage = storage.get();
1021         memset(mask.fImage, 0, size);
1022 
1023         // now draw our bitmap(src) into mask(dst), transformed by the matrix
1024         {
1025             SkBitmap    device;
1026             device.installPixels(SkImageInfo::MakeA8(mask.fBounds.width(), mask.fBounds.height()),
1027                                  mask.fImage, mask.fRowBytes);
1028 
1029             SkCanvas c(device);
1030             // need the unclipped top/left for the translate
1031             c.translate(-SkIntToScalar(mask.fBounds.fLeft),
1032                         -SkIntToScalar(mask.fBounds.fTop));
1033             c.concat(*fMatrix);
1034 
1035             // We can't call drawBitmap, or we'll infinitely recurse. Instead
1036             // we manually build a shader and draw that into our new mask
1037             SkPaint tmpPaint;
1038             tmpPaint.setAntiAlias(paint.isAntiAlias());
1039             tmpPaint.setDither(paint.isDither());
1040             tmpPaint.setFilterQuality(paint.getFilterQuality());
1041             SkPaint paintWithShader = make_paint_with_image(tmpPaint, bitmap);
1042             SkRect rr;
1043             rr.setIWH(bitmap.width(), bitmap.height());
1044             c.drawRect(rr, paintWithShader);
1045         }
1046         this->drawDevMask(mask, paint);
1047     }
1048 }
1049 
clipped_out(const SkMatrix & m,const SkRasterClip & c,const SkRect & srcR)1050 static bool clipped_out(const SkMatrix& m, const SkRasterClip& c,
1051                         const SkRect& srcR) {
1052     SkRect  dstR;
1053     m.mapRect(&dstR, srcR);
1054     return c.quickReject(dstR.roundOut());
1055 }
1056 
clipped_out(const SkMatrix & matrix,const SkRasterClip & clip,int width,int height)1057 static bool clipped_out(const SkMatrix& matrix, const SkRasterClip& clip,
1058                         int width, int height) {
1059     SkRect  r;
1060     r.setIWH(width, height);
1061     return clipped_out(matrix, clip, r);
1062 }
1063 
clipHandlesSprite(const SkRasterClip & clip,int x,int y,const SkPixmap & pmap)1064 static bool clipHandlesSprite(const SkRasterClip& clip, int x, int y, const SkPixmap& pmap) {
1065     return clip.isBW() || clip.quickContains(x, y, x + pmap.width(), y + pmap.height());
1066 }
1067 
drawBitmap(const SkBitmap & bitmap,const SkMatrix & prematrix,const SkRect * dstBounds,const SkPaint & origPaint) const1068 void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix,
1069                         const SkRect* dstBounds, const SkPaint& origPaint) const {
1070     SkDEBUGCODE(this->validate();)
1071 
1072     // nothing to draw
1073     if (fRC->isEmpty() ||
1074             bitmap.width() == 0 || bitmap.height() == 0 ||
1075             bitmap.colorType() == kUnknown_SkColorType) {
1076         return;
1077     }
1078 
1079     SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
1080     if (origPaint.getStyle() != SkPaint::kFill_Style) {
1081         paint.writable()->setStyle(SkPaint::kFill_Style);
1082     }
1083 
1084     SkMatrix matrix;
1085     matrix.setConcat(*fMatrix, prematrix);
1086 
1087     if (clipped_out(matrix, *fRC, bitmap.width(), bitmap.height())) {
1088         return;
1089     }
1090 
1091     if (bitmap.colorType() != kAlpha_8_SkColorType
1092         && SkTreatAsSprite(matrix, bitmap.dimensions(), *paint)) {
1093         //
1094         // It is safe to call lock pixels now, since we know the matrix is
1095         // (more or less) identity.
1096         //
1097         SkPixmap pmap;
1098         if (!bitmap.peekPixels(&pmap)) {
1099             return;
1100         }
1101         int ix = SkScalarRoundToInt(matrix.getTranslateX());
1102         int iy = SkScalarRoundToInt(matrix.getTranslateY());
1103         if (clipHandlesSprite(*fRC, ix, iy, pmap)) {
1104             SkSTArenaAlloc<kSkBlitterContextSize> allocator;
1105             // blitter will be owned by the allocator.
1106             SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, *paint, pmap, ix, iy, &allocator);
1107             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         if (blitter) {
1163             SkScan::FillIRect(bounds, *fRC, blitter);
1164             return;
1165         }
1166     }
1167 
1168     SkMatrix        matrix;
1169     SkRect          r;
1170 
1171     // get a scalar version of our rect
1172     r.set(bounds);
1173 
1174     // create shader with offset
1175     matrix.setTranslate(r.fLeft, r.fTop);
1176     SkPaint paintWithShader = make_paint_with_image(paint, bitmap, &matrix);
1177     SkDraw draw(*this);
1178     matrix.reset();
1179     draw.fMatrix = &matrix;
1180     // call ourself with a rect
1181     draw.drawRect(r, paintWithShader);
1182 }
1183 
1184 ////////////////////////////////////////////////////////////////////////////////////////////////
1185 
1186 #ifdef SK_DEBUG
1187 
validate() const1188 void SkDraw::validate() const {
1189     SkASSERT(fMatrix != nullptr);
1190     SkASSERT(fRC != nullptr);
1191 
1192     const SkIRect&  cr = fRC->getBounds();
1193     SkIRect         br;
1194 
1195     br.setWH(fDst.width(), fDst.height());
1196     SkASSERT(cr.isEmpty() || br.contains(cr));
1197 }
1198 
1199 #endif
1200 
1201 ////////////////////////////////////////////////////////////////////////////////////////////////
1202 
1203 #include "include/core/SkPath.h"
1204 #include "include/core/SkRegion.h"
1205 #include "src/core/SkBlitter.h"
1206 #include "src/core/SkDraw.h"
1207 
ComputeMaskBounds(const SkRect & devPathBounds,const SkIRect * clipBounds,const SkMaskFilter * filter,const SkMatrix * filterMatrix,SkIRect * bounds)1208 bool SkDraw::ComputeMaskBounds(const SkRect& devPathBounds, const SkIRect* clipBounds,
1209                                const SkMaskFilter* filter, const SkMatrix* filterMatrix,
1210                                SkIRect* bounds) {
1211     //  init our bounds from the path
1212     *bounds = devPathBounds.makeOutset(SK_ScalarHalf, SK_ScalarHalf).roundOut();
1213 
1214     SkIPoint margin = SkIPoint::Make(0, 0);
1215     if (filter) {
1216         SkASSERT(filterMatrix);
1217 
1218         SkMask srcM, dstM;
1219 
1220         srcM.fBounds = *bounds;
1221         srcM.fFormat = SkMask::kA8_Format;
1222         if (!as_MFB(filter)->filterMask(&dstM, srcM, *filterMatrix, &margin)) {
1223             return false;
1224         }
1225     }
1226 
1227     // (possibly) trim the bounds to reflect the clip
1228     // (plus whatever slop the filter needs)
1229     if (clipBounds) {
1230         // Ugh. Guard against gigantic margins from wacky filters. Without this
1231         // check we can request arbitrary amounts of slop beyond our visible
1232         // clip, and bring down the renderer (at least on finite RAM machines
1233         // like handsets, etc.). Need to balance this invented value between
1234         // quality of large filters like blurs, and the corresponding memory
1235         // requests.
1236         static const int MAX_MARGIN = 128;
1237         if (!bounds->intersect(clipBounds->makeOutset(SkMin32(margin.fX, MAX_MARGIN),
1238                                                       SkMin32(margin.fY, MAX_MARGIN)))) {
1239             return false;
1240         }
1241     }
1242 
1243     return true;
1244 }
1245 
draw_into_mask(const SkMask & mask,const SkPath & devPath,SkStrokeRec::InitStyle style)1246 static void draw_into_mask(const SkMask& mask, const SkPath& devPath,
1247                            SkStrokeRec::InitStyle style) {
1248     SkDraw draw;
1249     if (!draw.fDst.reset(mask)) {
1250         return;
1251     }
1252 
1253     SkRasterClip    clip;
1254     SkMatrix        matrix;
1255     SkPaint         paint;
1256 
1257     clip.setRect(SkIRect::MakeWH(mask.fBounds.width(), mask.fBounds.height()));
1258     matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
1259                         -SkIntToScalar(mask.fBounds.fTop));
1260 
1261     draw.fRC        = &clip;
1262     draw.fMatrix    = &matrix;
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