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