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.setWH(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.setLTRB(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 static const SkScalar kMaxStrokeScale = 1e5f;
813 return SkTMin(scale, kMaxStrokeScale);
814 }
815 }
816 return 1;
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())->filterPath(devPath, *fMatrix, *fRC, blitter, style)) {
836 return; // filterPath() called the blitter, so we're done
837 }
838 }
839
840 void (*proc)(const SkPath&, const SkRasterClip&, SkBlitter*);
841 if (doFill) {
842 if (paint.isAntiAlias()) {
843 proc = SkScan::AntiFillPath;
844 } else {
845 proc = SkScan::FillPath;
846 }
847 } else { // hairline
848 if (paint.isAntiAlias()) {
849 switch (paint.getStrokeCap()) {
850 case SkPaint::kButt_Cap:
851 proc = SkScan::AntiHairPath;
852 break;
853 case SkPaint::kSquare_Cap:
854 proc = SkScan::AntiHairSquarePath;
855 break;
856 case SkPaint::kRound_Cap:
857 proc = SkScan::AntiHairRoundPath;
858 break;
859 default:
860 proc SK_INIT_TO_AVOID_WARNING;
861 SkDEBUGFAIL("unknown paint cap type");
862 }
863 } else {
864 switch (paint.getStrokeCap()) {
865 case SkPaint::kButt_Cap:
866 proc = SkScan::HairPath;
867 break;
868 case SkPaint::kSquare_Cap:
869 proc = SkScan::HairSquarePath;
870 break;
871 case SkPaint::kRound_Cap:
872 proc = SkScan::HairRoundPath;
873 break;
874 default:
875 proc SK_INIT_TO_AVOID_WARNING;
876 SkDEBUGFAIL("unknown paint cap type");
877 }
878 }
879 }
880
881 proc(devPath, *fRC, blitter);
882 }
883
drawPath(const SkPath & origSrcPath,const SkPaint & origPaint,const SkMatrix * prePathMatrix,bool pathIsMutable,bool drawCoverage,SkBlitter * customBlitter) const884 void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint,
885 const SkMatrix* prePathMatrix, bool pathIsMutable,
886 bool drawCoverage, SkBlitter* customBlitter) const {
887 SkDEBUGCODE(this->validate();)
888
889 // nothing to draw
890 if (fRC->isEmpty()) {
891 return;
892 }
893
894 SkPath* pathPtr = (SkPath*)&origSrcPath;
895 bool doFill = true;
896 SkPath tmpPathStorage;
897 SkPath* tmpPath = &tmpPathStorage;
898 SkMatrix tmpMatrix;
899 const SkMatrix* matrix = fMatrix;
900 tmpPath->setIsVolatile(true);
901
902 if (prePathMatrix) {
903 if (origPaint.getPathEffect() || origPaint.getStyle() != SkPaint::kFill_Style) {
904 SkPath* result = pathPtr;
905
906 if (!pathIsMutable) {
907 result = tmpPath;
908 pathIsMutable = true;
909 }
910 pathPtr->transform(*prePathMatrix, result);
911 pathPtr = result;
912 } else {
913 tmpMatrix.setConcat(*matrix, *prePathMatrix);
914 matrix = &tmpMatrix;
915 }
916 }
917 // at this point we're done with prePathMatrix
918 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
919
920 SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
921
922 {
923 SkScalar coverage;
924 if (SkDrawTreatAsHairline(origPaint, *matrix, &coverage)) {
925 if (SK_Scalar1 == coverage) {
926 paint.writable()->setStrokeWidth(0);
927 } else if (SkBlendMode_SupportsCoverageAsAlpha(origPaint.getBlendMode())) {
928 U8CPU newAlpha;
929 #if 0
930 newAlpha = SkToU8(SkScalarRoundToInt(coverage *
931 origPaint.getAlpha()));
932 #else
933 // this is the old technique, which we preserve for now so
934 // we don't change previous results (testing)
935 // the new way seems fine, its just (a tiny bit) different
936 int scale = (int)(coverage * 256);
937 newAlpha = origPaint.getAlpha() * scale >> 8;
938 #endif
939 SkPaint* writablePaint = paint.writable();
940 writablePaint->setStrokeWidth(0);
941 writablePaint->setAlpha(newAlpha);
942 }
943 }
944 }
945
946 if (paint->getPathEffect() || paint->getStyle() != SkPaint::kFill_Style) {
947 SkRect cullRect;
948 const SkRect* cullRectPtr = nullptr;
949 if (this->computeConservativeLocalClipBounds(&cullRect)) {
950 cullRectPtr = &cullRect;
951 }
952 doFill = paint->getFillPath(*pathPtr, tmpPath, cullRectPtr,
953 ComputeResScaleForStroking(*fMatrix));
954 pathPtr = tmpPath;
955 }
956
957 // avoid possibly allocating a new path in transform if we can
958 SkPath* devPathPtr = pathIsMutable ? pathPtr : tmpPath;
959
960 // transform the path into device space
961 pathPtr->transform(*matrix, devPathPtr);
962
963 this->drawDevPath(*devPathPtr, *paint, drawCoverage, customBlitter, doFill);
964 }
965
drawBitmapAsMask(const SkBitmap & bitmap,const SkPaint & paint) const966 void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, const SkPaint& paint) const {
967 SkASSERT(bitmap.colorType() == kAlpha_8_SkColorType);
968
969 // nothing to draw
970 if (fRC->isEmpty()) {
971 return;
972 }
973
974 if (SkTreatAsSprite(*fMatrix, bitmap.dimensions(), paint)) {
975 int ix = SkScalarRoundToInt(fMatrix->getTranslateX());
976 int iy = SkScalarRoundToInt(fMatrix->getTranslateY());
977
978 SkPixmap pmap;
979 if (!bitmap.peekPixels(&pmap)) {
980 return;
981 }
982 SkMask mask;
983 mask.fBounds.setXYWH(ix, iy, pmap.width(), pmap.height());
984 mask.fFormat = SkMask::kA8_Format;
985 mask.fRowBytes = SkToU32(pmap.rowBytes());
986 // fImage is typed as writable, but in this case it is used read-only
987 mask.fImage = (uint8_t*)pmap.addr8(0, 0);
988
989 this->drawDevMask(mask, paint);
990 } else { // need to xform the bitmap first
991 SkRect r;
992 SkMask mask;
993
994 r.setIWH(bitmap.width(), 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.setIWH(bitmap.width(), bitmap.height());
1044 c.drawRect(rr, paintWithShader);
1045 }
1046 this->drawDevMask(mask, paint);
1047 }
1048 }
1049
clipped_out(const SkMatrix & m,const SkRasterClip & c,const SkRect & srcR)1050 static bool clipped_out(const SkMatrix& m, const SkRasterClip& c,
1051 const SkRect& srcR) {
1052 SkRect dstR;
1053 m.mapRect(&dstR, srcR);
1054 return c.quickReject(dstR.roundOut());
1055 }
1056
clipped_out(const SkMatrix & matrix,const SkRasterClip & clip,int width,int height)1057 static bool clipped_out(const SkMatrix& matrix, const SkRasterClip& clip,
1058 int width, int height) {
1059 SkRect r;
1060 r.setIWH(width, height);
1061 return clipped_out(matrix, clip, r);
1062 }
1063
clipHandlesSprite(const SkRasterClip & clip,int x,int y,const SkPixmap & pmap)1064 static bool clipHandlesSprite(const SkRasterClip& clip, int x, int y, const SkPixmap& pmap) {
1065 return clip.isBW() || clip.quickContains(x, y, x + pmap.width(), y + pmap.height());
1066 }
1067
drawBitmap(const SkBitmap & bitmap,const SkMatrix & prematrix,const SkRect * dstBounds,const SkPaint & origPaint) const1068 void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix,
1069 const SkRect* dstBounds, const SkPaint& origPaint) const {
1070 SkDEBUGCODE(this->validate();)
1071
1072 // nothing to draw
1073 if (fRC->isEmpty() ||
1074 bitmap.width() == 0 || bitmap.height() == 0 ||
1075 bitmap.colorType() == kUnknown_SkColorType) {
1076 return;
1077 }
1078
1079 SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
1080 if (origPaint.getStyle() != SkPaint::kFill_Style) {
1081 paint.writable()->setStyle(SkPaint::kFill_Style);
1082 }
1083
1084 SkMatrix matrix;
1085 matrix.setConcat(*fMatrix, prematrix);
1086
1087 if (clipped_out(matrix, *fRC, bitmap.width(), bitmap.height())) {
1088 return;
1089 }
1090
1091 if (bitmap.colorType() != kAlpha_8_SkColorType
1092 && SkTreatAsSprite(matrix, bitmap.dimensions(), *paint)) {
1093 //
1094 // It is safe to call lock pixels now, since we know the matrix is
1095 // (more or less) identity.
1096 //
1097 SkPixmap pmap;
1098 if (!bitmap.peekPixels(&pmap)) {
1099 return;
1100 }
1101 int ix = SkScalarRoundToInt(matrix.getTranslateX());
1102 int iy = SkScalarRoundToInt(matrix.getTranslateY());
1103 if (clipHandlesSprite(*fRC, ix, iy, pmap)) {
1104 SkSTArenaAlloc<kSkBlitterContextSize> allocator;
1105 // blitter will be owned by the allocator.
1106 SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, *paint, pmap, ix, iy, &allocator);
1107 if (blitter) {
1108 SkScan::FillIRect(SkIRect::MakeXYWH(ix, iy, pmap.width(), pmap.height()),
1109 *fRC, blitter);
1110 return;
1111 }
1112 // if !blitter, then we fall-through to the slower case
1113 }
1114 }
1115
1116 // now make a temp draw on the stack, and use it
1117 //
1118 SkDraw draw(*this);
1119 draw.fMatrix = &matrix;
1120
1121 if (bitmap.colorType() == kAlpha_8_SkColorType && !paint->getColorFilter()) {
1122 draw.drawBitmapAsMask(bitmap, *paint);
1123 } else {
1124 SkPaint paintWithShader = make_paint_with_image(*paint, bitmap);
1125 const SkRect srcBounds = SkRect::MakeIWH(bitmap.width(), bitmap.height());
1126 if (dstBounds) {
1127 this->drawRect(srcBounds, paintWithShader, &prematrix, dstBounds);
1128 } else {
1129 draw.drawRect(srcBounds, paintWithShader);
1130 }
1131 }
1132 }
1133
drawSprite(const SkBitmap & bitmap,int x,int y,const SkPaint & origPaint) const1134 void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& origPaint) const {
1135 SkDEBUGCODE(this->validate();)
1136
1137 // nothing to draw
1138 if (fRC->isEmpty() ||
1139 bitmap.width() == 0 || bitmap.height() == 0 ||
1140 bitmap.colorType() == kUnknown_SkColorType) {
1141 return;
1142 }
1143
1144 const SkIRect bounds = SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height());
1145
1146 if (fRC->quickReject(bounds)) {
1147 return; // nothing to draw
1148 }
1149
1150 SkPaint paint(origPaint);
1151 paint.setStyle(SkPaint::kFill_Style);
1152
1153 SkPixmap pmap;
1154 if (!bitmap.peekPixels(&pmap)) {
1155 return;
1156 }
1157
1158 if (nullptr == paint.getColorFilter() && clipHandlesSprite(*fRC, x, y, pmap)) {
1159 // blitter will be owned by the allocator.
1160 SkSTArenaAlloc<kSkBlitterContextSize> allocator;
1161 SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, paint, pmap, x, y, &allocator);
1162 if (blitter) {
1163 SkScan::FillIRect(bounds, *fRC, blitter);
1164 return;
1165 }
1166 }
1167
1168 SkMatrix matrix;
1169 SkRect r;
1170
1171 // get a scalar version of our rect
1172 r.set(bounds);
1173
1174 // create shader with offset
1175 matrix.setTranslate(r.fLeft, r.fTop);
1176 SkPaint paintWithShader = make_paint_with_image(paint, bitmap, &matrix);
1177 SkDraw draw(*this);
1178 matrix.reset();
1179 draw.fMatrix = &matrix;
1180 // call ourself with a rect
1181 draw.drawRect(r, paintWithShader);
1182 }
1183
1184 ////////////////////////////////////////////////////////////////////////////////////////////////
1185
1186 #ifdef SK_DEBUG
1187
validate() const1188 void SkDraw::validate() const {
1189 SkASSERT(fMatrix != nullptr);
1190 SkASSERT(fRC != nullptr);
1191
1192 const SkIRect& cr = fRC->getBounds();
1193 SkIRect br;
1194
1195 br.setWH(fDst.width(), fDst.height());
1196 SkASSERT(cr.isEmpty() || br.contains(cr));
1197 }
1198
1199 #endif
1200
1201 ////////////////////////////////////////////////////////////////////////////////////////////////
1202
1203 #include "include/core/SkPath.h"
1204 #include "include/core/SkRegion.h"
1205 #include "src/core/SkBlitter.h"
1206 #include "src/core/SkDraw.h"
1207
ComputeMaskBounds(const SkRect & devPathBounds,const SkIRect * clipBounds,const SkMaskFilter * filter,const SkMatrix * filterMatrix,SkIRect * bounds)1208 bool SkDraw::ComputeMaskBounds(const SkRect& devPathBounds, const SkIRect* clipBounds,
1209 const SkMaskFilter* filter, const SkMatrix* filterMatrix,
1210 SkIRect* bounds) {
1211 // init our bounds from the path
1212 *bounds = devPathBounds.makeOutset(SK_ScalarHalf, SK_ScalarHalf).roundOut();
1213
1214 SkIPoint margin = SkIPoint::Make(0, 0);
1215 if (filter) {
1216 SkASSERT(filterMatrix);
1217
1218 SkMask srcM, dstM;
1219
1220 srcM.fBounds = *bounds;
1221 srcM.fFormat = SkMask::kA8_Format;
1222 if (!as_MFB(filter)->filterMask(&dstM, srcM, *filterMatrix, &margin)) {
1223 return false;
1224 }
1225 }
1226
1227 // (possibly) trim the bounds to reflect the clip
1228 // (plus whatever slop the filter needs)
1229 if (clipBounds) {
1230 // Ugh. Guard against gigantic margins from wacky filters. Without this
1231 // check we can request arbitrary amounts of slop beyond our visible
1232 // clip, and bring down the renderer (at least on finite RAM machines
1233 // like handsets, etc.). Need to balance this invented value between
1234 // quality of large filters like blurs, and the corresponding memory
1235 // requests.
1236 static const int MAX_MARGIN = 128;
1237 if (!bounds->intersect(clipBounds->makeOutset(SkMin32(margin.fX, MAX_MARGIN),
1238 SkMin32(margin.fY, MAX_MARGIN)))) {
1239 return false;
1240 }
1241 }
1242
1243 return true;
1244 }
1245
draw_into_mask(const SkMask & mask,const SkPath & devPath,SkStrokeRec::InitStyle style)1246 static void draw_into_mask(const SkMask& mask, const SkPath& devPath,
1247 SkStrokeRec::InitStyle style) {
1248 SkDraw draw;
1249 if (!draw.fDst.reset(mask)) {
1250 return;
1251 }
1252
1253 SkRasterClip clip;
1254 SkMatrix matrix;
1255 SkPaint paint;
1256
1257 clip.setRect(SkIRect::MakeWH(mask.fBounds.width(), mask.fBounds.height()));
1258 matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
1259 -SkIntToScalar(mask.fBounds.fTop));
1260
1261 draw.fRC = &clip;
1262 draw.fMatrix = &matrix;
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