• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2006 The Android Open Source Project
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkDraw.h"
9 
10 #include "SkArenaAlloc.h"
11 #include "SkAutoBlitterChoose.h"
12 #include "SkBlendModePriv.h"
13 #include "SkBlitter.h"
14 #include "SkCanvas.h"
15 #include "SkColorData.h"
16 #include "SkDevice.h"
17 #include "SkDrawProcs.h"
18 #include "SkMaskFilterBase.h"
19 #include "SkMacros.h"
20 #include "SkMatrix.h"
21 #include "SkMatrixUtils.h"
22 #include "SkPaint.h"
23 #include "SkPathEffect.h"
24 #include "SkPathPriv.h"
25 #include "SkRRect.h"
26 #include "SkRasterClip.h"
27 #include "SkRectPriv.h"
28 #include "SkScan.h"
29 #include "SkShader.h"
30 #include "SkString.h"
31 #include "SkStroke.h"
32 #include "SkStrokeRec.h"
33 #include "SkTLazy.h"
34 #include "SkTemplates.h"
35 #include "SkTo.h"
36 #include "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(SkMakeBitmapShader(bitmap, SkShader::kClamp_TileMode,
44                                        SkShader::kClamp_TileMode, 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.set(0, 0, 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.set(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             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     SkPathPriv::SetIsBadForDAA(*tmpPath, SkPathPriv::IsBadForDAA(origSrcPath));
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     if (SkTreatAsSprite(*fMatrix, bitmap.dimensions(), paint)) {
970         int ix = SkScalarRoundToInt(fMatrix->getTranslateX());
971         int iy = SkScalarRoundToInt(fMatrix->getTranslateY());
972 
973         SkPixmap pmap;
974         if (!bitmap.peekPixels(&pmap)) {
975             return;
976         }
977         SkMask  mask;
978         mask.fBounds.set(ix, iy, ix + pmap.width(), iy + pmap.height());
979         mask.fFormat = SkMask::kA8_Format;
980         mask.fRowBytes = SkToU32(pmap.rowBytes());
981         // fImage is typed as writable, but in this case it is used read-only
982         mask.fImage = (uint8_t*)pmap.addr8(0, 0);
983 
984         this->drawDevMask(mask, paint);
985     } else {    // need to xform the bitmap first
986         SkRect  r;
987         SkMask  mask;
988 
989         r.set(0, 0,
990               SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
991         fMatrix->mapRect(&r);
992         r.round(&mask.fBounds);
993 
994         // set the mask's bounds to the transformed bitmap-bounds,
995         // clipped to the actual device
996         {
997             SkIRect    devBounds;
998             devBounds.set(0, 0, fDst.width(), fDst.height());
999             // need intersect(l, t, r, b) on irect
1000             if (!mask.fBounds.intersect(devBounds)) {
1001                 return;
1002             }
1003         }
1004 
1005         mask.fFormat = SkMask::kA8_Format;
1006         mask.fRowBytes = SkAlign4(mask.fBounds.width());
1007         size_t size = mask.computeImageSize();
1008         if (0 == size) {
1009             // the mask is too big to allocated, draw nothing
1010             return;
1011         }
1012 
1013         // allocate (and clear) our temp buffer to hold the transformed bitmap
1014         SkAutoTMalloc<uint8_t> storage(size);
1015         mask.fImage = storage.get();
1016         memset(mask.fImage, 0, size);
1017 
1018         // now draw our bitmap(src) into mask(dst), transformed by the matrix
1019         {
1020             SkBitmap    device;
1021             device.installPixels(SkImageInfo::MakeA8(mask.fBounds.width(), mask.fBounds.height()),
1022                                  mask.fImage, mask.fRowBytes);
1023 
1024             SkCanvas c(device);
1025             // need the unclipped top/left for the translate
1026             c.translate(-SkIntToScalar(mask.fBounds.fLeft),
1027                         -SkIntToScalar(mask.fBounds.fTop));
1028             c.concat(*fMatrix);
1029 
1030             // We can't call drawBitmap, or we'll infinitely recurse. Instead
1031             // we manually build a shader and draw that into our new mask
1032             SkPaint tmpPaint;
1033             tmpPaint.setAntiAlias(paint.isAntiAlias());
1034             tmpPaint.setDither(paint.isDither());
1035             tmpPaint.setFilterQuality(paint.getFilterQuality());
1036             SkPaint paintWithShader = make_paint_with_image(tmpPaint, bitmap);
1037             SkRect rr;
1038             rr.set(0, 0, SkIntToScalar(bitmap.width()),
1039                    SkIntToScalar(bitmap.height()));
1040             c.drawRect(rr, paintWithShader);
1041         }
1042         this->drawDevMask(mask, paint);
1043     }
1044 }
1045 
clipped_out(const SkMatrix & m,const SkRasterClip & c,const SkRect & srcR)1046 static bool clipped_out(const SkMatrix& m, const SkRasterClip& c,
1047                         const SkRect& srcR) {
1048     SkRect  dstR;
1049     m.mapRect(&dstR, srcR);
1050     return c.quickReject(dstR.roundOut());
1051 }
1052 
clipped_out(const SkMatrix & matrix,const SkRasterClip & clip,int width,int height)1053 static bool clipped_out(const SkMatrix& matrix, const SkRasterClip& clip,
1054                         int width, int height) {
1055     SkRect  r;
1056     r.set(0, 0, SkIntToScalar(width), SkIntToScalar(height));
1057     return clipped_out(matrix, clip, r);
1058 }
1059 
clipHandlesSprite(const SkRasterClip & clip,int x,int y,const SkPixmap & pmap)1060 static bool clipHandlesSprite(const SkRasterClip& clip, int x, int y, const SkPixmap& pmap) {
1061     return clip.isBW() || clip.quickContains(x, y, x + pmap.width(), y + pmap.height());
1062 }
1063 
drawBitmap(const SkBitmap & bitmap,const SkMatrix & prematrix,const SkRect * dstBounds,const SkPaint & origPaint) const1064 void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix,
1065                         const SkRect* dstBounds, const SkPaint& origPaint) const {
1066     SkDEBUGCODE(this->validate();)
1067 
1068     // nothing to draw
1069     if (fRC->isEmpty() ||
1070             bitmap.width() == 0 || bitmap.height() == 0 ||
1071             bitmap.colorType() == kUnknown_SkColorType) {
1072         return;
1073     }
1074 
1075     SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
1076     if (origPaint.getStyle() != SkPaint::kFill_Style) {
1077         paint.writable()->setStyle(SkPaint::kFill_Style);
1078     }
1079 
1080     SkMatrix matrix;
1081     matrix.setConcat(*fMatrix, prematrix);
1082 
1083     if (clipped_out(matrix, *fRC, bitmap.width(), bitmap.height())) {
1084         return;
1085     }
1086 
1087     if (bitmap.colorType() != kAlpha_8_SkColorType
1088         && SkTreatAsSprite(matrix, bitmap.dimensions(), *paint)) {
1089         //
1090         // It is safe to call lock pixels now, since we know the matrix is
1091         // (more or less) identity.
1092         //
1093         SkPixmap pmap;
1094         if (!bitmap.peekPixels(&pmap)) {
1095             return;
1096         }
1097         int ix = SkScalarRoundToInt(matrix.getTranslateX());
1098         int iy = SkScalarRoundToInt(matrix.getTranslateY());
1099         if (clipHandlesSprite(*fRC, ix, iy, pmap)) {
1100             SkSTArenaAlloc<kSkBlitterContextSize> allocator;
1101             // blitter will be owned by the allocator.
1102             SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, *paint, pmap, ix, iy, &allocator);
1103             if (blitter) {
1104                 SkScan::FillIRect(SkIRect::MakeXYWH(ix, iy, pmap.width(), pmap.height()),
1105                                   *fRC, blitter);
1106                 return;
1107             }
1108             // if !blitter, then we fall-through to the slower case
1109         }
1110     }
1111 
1112     // now make a temp draw on the stack, and use it
1113     //
1114     SkDraw draw(*this);
1115     draw.fMatrix = &matrix;
1116 
1117     if (bitmap.colorType() == kAlpha_8_SkColorType && !paint->getColorFilter()) {
1118         draw.drawBitmapAsMask(bitmap, *paint);
1119     } else {
1120         SkPaint paintWithShader = make_paint_with_image(*paint, bitmap);
1121         const SkRect srcBounds = SkRect::MakeIWH(bitmap.width(), bitmap.height());
1122         if (dstBounds) {
1123             this->drawRect(srcBounds, paintWithShader, &prematrix, dstBounds);
1124         } else {
1125             draw.drawRect(srcBounds, paintWithShader);
1126         }
1127     }
1128 }
1129 
drawSprite(const SkBitmap & bitmap,int x,int y,const SkPaint & origPaint) const1130 void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& origPaint) const {
1131     SkDEBUGCODE(this->validate();)
1132 
1133     // nothing to draw
1134     if (fRC->isEmpty() ||
1135             bitmap.width() == 0 || bitmap.height() == 0 ||
1136             bitmap.colorType() == kUnknown_SkColorType) {
1137         return;
1138     }
1139 
1140     const SkIRect bounds = SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height());
1141 
1142     if (fRC->quickReject(bounds)) {
1143         return; // nothing to draw
1144     }
1145 
1146     SkPaint paint(origPaint);
1147     paint.setStyle(SkPaint::kFill_Style);
1148 
1149     SkPixmap pmap;
1150     if (!bitmap.peekPixels(&pmap)) {
1151         return;
1152     }
1153 
1154     if (nullptr == paint.getColorFilter() && clipHandlesSprite(*fRC, x, y, pmap)) {
1155         // blitter will be owned by the allocator.
1156         SkSTArenaAlloc<kSkBlitterContextSize> allocator;
1157         SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, paint, pmap, x, y, &allocator);
1158         if (blitter) {
1159             SkScan::FillIRect(bounds, *fRC, blitter);
1160             return;
1161         }
1162     }
1163 
1164     SkMatrix        matrix;
1165     SkRect          r;
1166 
1167     // get a scalar version of our rect
1168     r.set(bounds);
1169 
1170     // create shader with offset
1171     matrix.setTranslate(r.fLeft, r.fTop);
1172     SkPaint paintWithShader = make_paint_with_image(paint, bitmap, &matrix);
1173     SkDraw draw(*this);
1174     matrix.reset();
1175     draw.fMatrix = &matrix;
1176     // call ourself with a rect
1177     draw.drawRect(r, paintWithShader);
1178 }
1179 
1180 ////////////////////////////////////////////////////////////////////////////////////////////////
1181 
1182 #ifdef SK_DEBUG
1183 
validate() const1184 void SkDraw::validate() const {
1185     SkASSERT(fMatrix != nullptr);
1186     SkASSERT(fRC != nullptr);
1187 
1188     const SkIRect&  cr = fRC->getBounds();
1189     SkIRect         br;
1190 
1191     br.set(0, 0, fDst.width(), fDst.height());
1192     SkASSERT(cr.isEmpty() || br.contains(cr));
1193 }
1194 
1195 #endif
1196 
1197 ////////////////////////////////////////////////////////////////////////////////////////////////
1198 
1199 #include "SkPath.h"
1200 #include "SkDraw.h"
1201 #include "SkRegion.h"
1202 #include "SkBlitter.h"
1203 
ComputeMaskBounds(const SkRect & devPathBounds,const SkIRect * clipBounds,const SkMaskFilter * filter,const SkMatrix * filterMatrix,SkIRect * bounds)1204 bool SkDraw::ComputeMaskBounds(const SkRect& devPathBounds, const SkIRect* clipBounds,
1205                                const SkMaskFilter* filter, const SkMatrix* filterMatrix,
1206                                SkIRect* bounds) {
1207     //  init our bounds from the path
1208     *bounds = devPathBounds.makeOutset(SK_ScalarHalf, SK_ScalarHalf).roundOut();
1209 
1210     SkIPoint margin = SkIPoint::Make(0, 0);
1211     if (filter) {
1212         SkASSERT(filterMatrix);
1213 
1214         SkMask srcM, dstM;
1215 
1216         srcM.fBounds = *bounds;
1217         srcM.fFormat = SkMask::kA8_Format;
1218         if (!as_MFB(filter)->filterMask(&dstM, srcM, *filterMatrix, &margin)) {
1219             return false;
1220         }
1221     }
1222 
1223     // (possibly) trim the bounds to reflect the clip
1224     // (plus whatever slop the filter needs)
1225     if (clipBounds) {
1226         // Ugh. Guard against gigantic margins from wacky filters. Without this
1227         // check we can request arbitrary amounts of slop beyond our visible
1228         // clip, and bring down the renderer (at least on finite RAM machines
1229         // like handsets, etc.). Need to balance this invented value between
1230         // quality of large filters like blurs, and the corresponding memory
1231         // requests.
1232         static const int MAX_MARGIN = 128;
1233         if (!bounds->intersect(clipBounds->makeOutset(SkMin32(margin.fX, MAX_MARGIN),
1234                                                       SkMin32(margin.fY, MAX_MARGIN)))) {
1235             return false;
1236         }
1237     }
1238 
1239     return true;
1240 }
1241 
draw_into_mask(const SkMask & mask,const SkPath & devPath,SkStrokeRec::InitStyle style)1242 static void draw_into_mask(const SkMask& mask, const SkPath& devPath,
1243                            SkStrokeRec::InitStyle style) {
1244     SkDraw draw;
1245     if (!draw.fDst.reset(mask)) {
1246         return;
1247     }
1248 
1249     SkRasterClip    clip;
1250     SkMatrix        matrix;
1251     SkPaint         paint;
1252 
1253     clip.setRect(SkIRect::MakeWH(mask.fBounds.width(), mask.fBounds.height()));
1254     matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
1255                         -SkIntToScalar(mask.fBounds.fTop));
1256 
1257     draw.fRC        = &clip;
1258     draw.fMatrix    = &matrix;
1259     paint.setAntiAlias(true);
1260     switch (style) {
1261         case SkStrokeRec::kHairline_InitStyle:
1262             SkASSERT(!paint.getStrokeWidth());
1263             paint.setStyle(SkPaint::kStroke_Style);
1264             break;
1265         case SkStrokeRec::kFill_InitStyle:
1266             SkASSERT(paint.getStyle() == SkPaint::kFill_Style);
1267             break;
1268 
1269     }
1270     draw.drawPath(devPath, paint);
1271 }
1272 
DrawToMask(const SkPath & devPath,const SkIRect * clipBounds,const SkMaskFilter * filter,const SkMatrix * filterMatrix,SkMask * mask,SkMask::CreateMode mode,SkStrokeRec::InitStyle style)1273 bool SkDraw::DrawToMask(const SkPath& devPath, const SkIRect* clipBounds,
1274                         const SkMaskFilter* filter, const SkMatrix* filterMatrix,
1275                         SkMask* mask, SkMask::CreateMode mode,
1276                         SkStrokeRec::InitStyle style) {
1277     if (devPath.isEmpty()) {
1278         return false;
1279     }
1280 
1281     if (SkMask::kJustRenderImage_CreateMode != mode) {
1282         if (!ComputeMaskBounds(devPath.getBounds(), clipBounds, filter,
1283                                filterMatrix, &mask->fBounds))
1284             return false;
1285     }
1286 
1287     if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) {
1288         mask->fFormat = SkMask::kA8_Format;
1289         mask->fRowBytes = mask->fBounds.width();
1290         size_t size = mask->computeImageSize();
1291         if (0 == size) {
1292             // we're too big to allocate the mask, abort
1293             return false;
1294         }
1295         mask->fImage = SkMask::AllocImage(size, SkMask::kZeroInit_Alloc);
1296     }
1297 
1298     if (SkMask::kJustComputeBounds_CreateMode != mode) {
1299         draw_into_mask(*mask, devPath, style);
1300     }
1301 
1302     return true;
1303 }
1304