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