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