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