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 #define __STDC_LIMIT_MACROS
9
10 #include "SkArenaAlloc.h"
11 #include "SkAutoBlitterChoose.h"
12 #include "SkBlendModePriv.h"
13 #include "SkBlitter.h"
14 #include "SkCanvas.h"
15 #include "SkColorData.h"
16 #include "SkDevice.h"
17 #include "SkDraw.h"
18 #include "SkDrawProcs.h"
19 #include "SkFindAndPlaceGlyph.h"
20 #include "SkMaskFilterBase.h"
21 #include "SkMatrix.h"
22 #include "SkMatrixUtils.h"
23 #include "SkPaint.h"
24 #include "SkPathEffect.h"
25 #include "SkRasterClip.h"
26 #include "SkRectPriv.h"
27 #include "SkRRect.h"
28 #include "SkScalerContext.h"
29 #include "SkScan.h"
30 #include "SkShader.h"
31 #include "SkString.h"
32 #include "SkStroke.h"
33 #include "SkStrokeRec.h"
34 #include "SkTemplates.h"
35 #include "SkTextMapStateProc.h"
36 #include "SkThreadedBMPDevice.h"
37 #include "SkTLazy.h"
38 #include "SkUtils.h"
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(SkMakeBitmapShader(bitmap, SkShader::kClamp_TileMode,
44 SkShader::kClamp_TileMode, matrix,
45 kNever_SkCopyPixelsMode));
46 return paint;
47 }
48
49 ///////////////////////////////////////////////////////////////////////////////
50
SkDraw()51 SkDraw::SkDraw() {
52 sk_bzero(this, sizeof(*this));
53 }
54
computeConservativeLocalClipBounds(SkRect * localBounds) const55 bool SkDraw::computeConservativeLocalClipBounds(SkRect* localBounds) const {
56 if (fRC->isEmpty()) {
57 return false;
58 }
59
60 SkMatrix inverse;
61 if (!fMatrix->invert(&inverse)) {
62 return false;
63 }
64
65 SkIRect devBounds = fRC->getBounds();
66 // outset to have slop for antialasing and hairlines
67 devBounds.outset(1, 1);
68 inverse.mapRect(localBounds, SkRect::Make(devBounds));
69 return true;
70 }
71
72 ///////////////////////////////////////////////////////////////////////////////
73
74 typedef void (*BitmapXferProc)(void* pixels, size_t bytes, uint32_t data);
75
D_Clear_BitmapXferProc(void * pixels,size_t bytes,uint32_t)76 static void D_Clear_BitmapXferProc(void* pixels, size_t bytes, uint32_t) {
77 sk_bzero(pixels, bytes);
78 }
79
D_Dst_BitmapXferProc(void *,size_t,uint32_t data)80 static void D_Dst_BitmapXferProc(void*, size_t, uint32_t data) {}
81
D32_Src_BitmapXferProc(void * pixels,size_t bytes,uint32_t data)82 static void D32_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
83 sk_memset32((uint32_t*)pixels, data, SkToInt(bytes >> 2));
84 }
85
D16_Src_BitmapXferProc(void * pixels,size_t bytes,uint32_t data)86 static void D16_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
87 sk_memset16((uint16_t*)pixels, data, SkToInt(bytes >> 1));
88 }
89
DA8_Src_BitmapXferProc(void * pixels,size_t bytes,uint32_t data)90 static void DA8_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
91 memset(pixels, data, bytes);
92 }
93
ChooseBitmapXferProc(const SkPixmap & dst,const SkPaint & paint,uint32_t * data)94 static BitmapXferProc ChooseBitmapXferProc(const SkPixmap& dst, const SkPaint& paint,
95 uint32_t* data) {
96 // todo: we can apply colorfilter up front if no shader, so we wouldn't
97 // need to abort this fastpath
98 if (paint.getShader() || paint.getColorFilter() || dst.colorSpace()) {
99 return nullptr;
100 }
101
102 SkBlendMode mode = paint.getBlendMode();
103 SkColor color = paint.getColor();
104
105 // collaps modes based on color...
106 if (SkBlendMode::kSrcOver == mode) {
107 unsigned alpha = SkColorGetA(color);
108 if (0 == alpha) {
109 mode = SkBlendMode::kDst;
110 } else if (0xFF == alpha) {
111 mode = SkBlendMode::kSrc;
112 }
113 }
114
115 switch (mode) {
116 case SkBlendMode::kClear:
117 // SkDebugf("--- D_Clear_BitmapXferProc\n");
118 return D_Clear_BitmapXferProc; // ignore data
119 case SkBlendMode::kDst:
120 // SkDebugf("--- D_Dst_BitmapXferProc\n");
121 return D_Dst_BitmapXferProc; // ignore data
122 case SkBlendMode::kSrc: {
123 /*
124 should I worry about dithering for the lower depths?
125 */
126 SkPMColor pmc = SkPreMultiplyColor(color);
127 switch (dst.colorType()) {
128 case kN32_SkColorType:
129 if (data) {
130 *data = pmc;
131 }
132 // SkDebugf("--- D32_Src_BitmapXferProc\n");
133 return D32_Src_BitmapXferProc;
134 case kRGB_565_SkColorType:
135 if (data) {
136 *data = SkPixel32ToPixel16(pmc);
137 }
138 // SkDebugf("--- D16_Src_BitmapXferProc\n");
139 return D16_Src_BitmapXferProc;
140 case kAlpha_8_SkColorType:
141 if (data) {
142 *data = SkGetPackedA32(pmc);
143 }
144 // SkDebugf("--- DA8_Src_BitmapXferProc\n");
145 return DA8_Src_BitmapXferProc;
146 default:
147 break;
148 }
149 break;
150 }
151 default:
152 break;
153 }
154 return nullptr;
155 }
156
CallBitmapXferProc(const SkPixmap & dst,const SkIRect & rect,BitmapXferProc proc,uint32_t procData)157 static void CallBitmapXferProc(const SkPixmap& dst, const SkIRect& rect, BitmapXferProc proc,
158 uint32_t procData) {
159 int shiftPerPixel;
160 switch (dst.colorType()) {
161 case kN32_SkColorType:
162 shiftPerPixel = 2;
163 break;
164 case kRGB_565_SkColorType:
165 shiftPerPixel = 1;
166 break;
167 case kAlpha_8_SkColorType:
168 shiftPerPixel = 0;
169 break;
170 default:
171 SkDEBUGFAIL("Can't use xferproc on this config");
172 return;
173 }
174
175 uint8_t* pixels = (uint8_t*)dst.writable_addr();
176 SkASSERT(pixels);
177 const size_t rowBytes = dst.rowBytes();
178 const int widthBytes = rect.width() << shiftPerPixel;
179
180 // skip down to the first scanline and X position
181 pixels += rect.fTop * rowBytes + (rect.fLeft << shiftPerPixel);
182 for (int scans = rect.height() - 1; scans >= 0; --scans) {
183 proc(pixels, widthBytes, procData);
184 pixels += rowBytes;
185 }
186 }
187
drawPaint(const SkPaint & paint) const188 void SkDraw::drawPaint(const SkPaint& paint) const {
189 SkDEBUGCODE(this->validate();)
190
191 if (fRC->isEmpty()) {
192 return;
193 }
194
195 SkIRect devRect;
196 devRect.set(0, 0, fDst.width(), fDst.height());
197
198 if (fRC->isBW()) {
199 /* If we don't have a shader (i.e. we're just a solid color) we may
200 be faster to operate directly on the device bitmap, rather than invoking
201 a blitter. Esp. true for xfermodes, which require a colorshader to be
202 present, which is just redundant work. Since we're drawing everywhere
203 in the clip, we don't have to worry about antialiasing.
204 */
205 uint32_t procData = 0; // to avoid the warning
206 BitmapXferProc proc = ChooseBitmapXferProc(fDst, paint, &procData);
207 if (proc) {
208 if (D_Dst_BitmapXferProc == proc) { // nothing to do
209 return;
210 }
211
212 SkRegion::Iterator iter(fRC->bwRgn());
213 while (!iter.done()) {
214 CallBitmapXferProc(fDst, iter.rect(), proc, procData);
215 iter.next();
216 }
217 return;
218 }
219 }
220
221 // normal case: use a blitter
222 SkAutoBlitterChoose blitter(fDst, *fMatrix, paint);
223 SkScan::FillIRect(devRect, *fRC, blitter.get());
224 }
225
226 ///////////////////////////////////////////////////////////////////////////////
227
228 struct PtProcRec {
229 SkCanvas::PointMode fMode;
230 const SkPaint* fPaint;
231 const SkRegion* fClip;
232 const SkRasterClip* fRC;
233
234 // computed values
235 SkRect fClipBounds;
236 SkScalar fRadius;
237
238 typedef void (*Proc)(const PtProcRec&, const SkPoint devPts[], int count,
239 SkBlitter*);
240
241 bool init(SkCanvas::PointMode, const SkPaint&, const SkMatrix* matrix,
242 const SkRasterClip*);
243 Proc chooseProc(SkBlitter** blitter);
244
245 private:
246 SkAAClipBlitterWrapper fWrapper;
247 };
248
bw_pt_rect_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)249 static void bw_pt_rect_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
250 int count, SkBlitter* blitter) {
251 SkASSERT(rec.fClip->isRect());
252 const SkIRect& r = rec.fClip->getBounds();
253
254 for (int i = 0; i < count; i++) {
255 int x = SkScalarFloorToInt(devPts[i].fX);
256 int y = SkScalarFloorToInt(devPts[i].fY);
257 if (r.contains(x, y)) {
258 blitter->blitH(x, y, 1);
259 }
260 }
261 }
262
bw_pt_rect_16_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)263 static void bw_pt_rect_16_hair_proc(const PtProcRec& rec,
264 const SkPoint devPts[], int count,
265 SkBlitter* blitter) {
266 SkASSERT(rec.fRC->isRect());
267 const SkIRect& r = rec.fRC->getBounds();
268 uint32_t value;
269 const SkPixmap* dst = blitter->justAnOpaqueColor(&value);
270 SkASSERT(dst);
271
272 uint16_t* addr = dst->writable_addr16(0, 0);
273 size_t rb = dst->rowBytes();
274
275 for (int i = 0; i < count; i++) {
276 int x = SkScalarFloorToInt(devPts[i].fX);
277 int y = SkScalarFloorToInt(devPts[i].fY);
278 if (r.contains(x, y)) {
279 ((uint16_t*)((char*)addr + y * rb))[x] = SkToU16(value);
280 }
281 }
282 }
283
bw_pt_rect_32_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)284 static void bw_pt_rect_32_hair_proc(const PtProcRec& rec,
285 const SkPoint devPts[], int count,
286 SkBlitter* blitter) {
287 SkASSERT(rec.fRC->isRect());
288 const SkIRect& r = rec.fRC->getBounds();
289 uint32_t value;
290 const SkPixmap* dst = blitter->justAnOpaqueColor(&value);
291 SkASSERT(dst);
292
293 SkPMColor* addr = dst->writable_addr32(0, 0);
294 size_t rb = dst->rowBytes();
295
296 for (int i = 0; i < count; i++) {
297 int x = SkScalarFloorToInt(devPts[i].fX);
298 int y = SkScalarFloorToInt(devPts[i].fY);
299 if (r.contains(x, y)) {
300 ((SkPMColor*)((char*)addr + y * rb))[x] = value;
301 }
302 }
303 }
304
bw_pt_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)305 static void bw_pt_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
306 int count, SkBlitter* blitter) {
307 for (int i = 0; i < count; i++) {
308 int x = SkScalarFloorToInt(devPts[i].fX);
309 int y = SkScalarFloorToInt(devPts[i].fY);
310 if (rec.fClip->contains(x, y)) {
311 blitter->blitH(x, y, 1);
312 }
313 }
314 }
315
bw_line_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)316 static void bw_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
317 int count, SkBlitter* blitter) {
318 for (int i = 0; i < count; i += 2) {
319 SkScan::HairLine(&devPts[i], 2, *rec.fRC, blitter);
320 }
321 }
322
bw_poly_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)323 static void bw_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
324 int count, SkBlitter* blitter) {
325 SkScan::HairLine(devPts, count, *rec.fRC, blitter);
326 }
327
328 // aa versions
329
aa_line_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)330 static void aa_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
331 int count, SkBlitter* blitter) {
332 for (int i = 0; i < count; i += 2) {
333 SkScan::AntiHairLine(&devPts[i], 2, *rec.fRC, blitter);
334 }
335 }
336
aa_poly_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)337 static void aa_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
338 int count, SkBlitter* blitter) {
339 SkScan::AntiHairLine(devPts, count, *rec.fRC, blitter);
340 }
341
342 // square procs (strokeWidth > 0 but matrix is square-scale (sx == sy)
343
make_square_rad(SkPoint center,SkScalar radius)344 static SkRect make_square_rad(SkPoint center, SkScalar radius) {
345 return {
346 center.fX - radius, center.fY - radius,
347 center.fX + radius, center.fY + radius
348 };
349 }
350
make_xrect(const SkRect & r)351 static SkXRect make_xrect(const SkRect& r) {
352 SkASSERT(SkRectPriv::FitsInFixed(r));
353 return {
354 SkScalarToFixed(r.fLeft), SkScalarToFixed(r.fTop),
355 SkScalarToFixed(r.fRight), SkScalarToFixed(r.fBottom)
356 };
357 }
358
bw_square_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)359 static void bw_square_proc(const PtProcRec& rec, const SkPoint devPts[],
360 int count, SkBlitter* blitter) {
361 for (int i = 0; i < count; i++) {
362 SkRect r = make_square_rad(devPts[i], rec.fRadius);
363 if (r.intersect(rec.fClipBounds)) {
364 SkScan::FillXRect(make_xrect(r), *rec.fRC, blitter);
365 }
366 }
367 }
368
aa_square_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)369 static void aa_square_proc(const PtProcRec& rec, const SkPoint devPts[],
370 int count, SkBlitter* blitter) {
371 for (int i = 0; i < count; i++) {
372 SkRect r = make_square_rad(devPts[i], rec.fRadius);
373 if (r.intersect(rec.fClipBounds)) {
374 SkScan::AntiFillXRect(make_xrect(r), *rec.fRC, blitter);
375 }
376 }
377 }
378
379 // 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)380 bool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint,
381 const SkMatrix* matrix, const SkRasterClip* rc) {
382 if ((unsigned)mode > (unsigned)SkCanvas::kPolygon_PointMode) {
383 return false;
384 }
385 if (paint.getPathEffect()) {
386 return false;
387 }
388 SkScalar width = paint.getStrokeWidth();
389 SkScalar radius = -1; // sentinel value, a "valid" value must be > 0
390
391 if (0 == width) {
392 radius = 0.5f;
393 } else if (paint.getStrokeCap() != SkPaint::kRound_Cap &&
394 matrix->isScaleTranslate() && SkCanvas::kPoints_PointMode == mode) {
395 SkScalar sx = matrix->get(SkMatrix::kMScaleX);
396 SkScalar sy = matrix->get(SkMatrix::kMScaleY);
397 if (SkScalarNearlyZero(sx - sy)) {
398 radius = SkScalarHalf(width * SkScalarAbs(sx));
399 }
400 }
401 if (radius > 0) {
402 SkRect clipBounds = SkRect::Make(rc->getBounds());
403 // if we return true, the caller may assume that the constructed shapes can be represented
404 // using SkFixed (after clipping), so we preflight that here.
405 if (!SkRectPriv::FitsInFixed(clipBounds)) {
406 return false;
407 }
408 fMode = mode;
409 fPaint = &paint;
410 fClip = nullptr;
411 fRC = rc;
412 fClipBounds = clipBounds;
413 fRadius = radius;
414 return true;
415 }
416 return false;
417 }
418
chooseProc(SkBlitter ** blitterPtr)419 PtProcRec::Proc PtProcRec::chooseProc(SkBlitter** blitterPtr) {
420 Proc proc = nullptr;
421
422 SkBlitter* blitter = *blitterPtr;
423 if (fRC->isBW()) {
424 fClip = &fRC->bwRgn();
425 } else {
426 fWrapper.init(*fRC, blitter);
427 fClip = &fWrapper.getRgn();
428 blitter = fWrapper.getBlitter();
429 *blitterPtr = blitter;
430 }
431
432 // for our arrays
433 SkASSERT(0 == SkCanvas::kPoints_PointMode);
434 SkASSERT(1 == SkCanvas::kLines_PointMode);
435 SkASSERT(2 == SkCanvas::kPolygon_PointMode);
436 SkASSERT((unsigned)fMode <= (unsigned)SkCanvas::kPolygon_PointMode);
437
438 if (fPaint->isAntiAlias()) {
439 if (0 == fPaint->getStrokeWidth()) {
440 static const Proc gAAProcs[] = {
441 aa_square_proc, aa_line_hair_proc, aa_poly_hair_proc
442 };
443 proc = gAAProcs[fMode];
444 } else if (fPaint->getStrokeCap() != SkPaint::kRound_Cap) {
445 SkASSERT(SkCanvas::kPoints_PointMode == fMode);
446 proc = aa_square_proc;
447 }
448 } else { // BW
449 if (fRadius <= 0.5f) { // small radii and hairline
450 if (SkCanvas::kPoints_PointMode == fMode && fClip->isRect()) {
451 uint32_t value;
452 const SkPixmap* bm = blitter->justAnOpaqueColor(&value);
453 if (bm && kRGB_565_SkColorType == bm->colorType()) {
454 proc = bw_pt_rect_16_hair_proc;
455 } else if (bm && kN32_SkColorType == bm->colorType()) {
456 proc = bw_pt_rect_32_hair_proc;
457 } else {
458 proc = bw_pt_rect_hair_proc;
459 }
460 } else {
461 static Proc gBWProcs[] = {
462 bw_pt_hair_proc, bw_line_hair_proc, bw_poly_hair_proc
463 };
464 proc = gBWProcs[fMode];
465 }
466 } else {
467 proc = bw_square_proc;
468 }
469 }
470 return proc;
471 }
472
473 // each of these costs 8-bytes of stack space, so don't make it too large
474 // must be even for lines/polygon to work
475 #define MAX_DEV_PTS 32
476
drawPoints(SkCanvas::PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint,SkBaseDevice * device) const477 void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count,
478 const SkPoint pts[], const SkPaint& paint,
479 SkBaseDevice* device) const {
480 // if we're in lines mode, force count to be even
481 if (SkCanvas::kLines_PointMode == mode) {
482 count &= ~(size_t)1;
483 }
484
485 if ((long)count <= 0) {
486 return;
487 }
488
489 SkASSERT(pts != nullptr);
490 SkDEBUGCODE(this->validate();)
491
492 // nothing to draw
493 if (fRC->isEmpty()) {
494 return;
495 }
496
497 PtProcRec rec;
498 if (!device && rec.init(mode, paint, fMatrix, fRC)) {
499 SkAutoBlitterChoose blitter(fDst, *fMatrix, paint);
500
501 SkPoint devPts[MAX_DEV_PTS];
502 const SkMatrix* matrix = fMatrix;
503 SkBlitter* bltr = blitter.get();
504 PtProcRec::Proc proc = rec.chooseProc(&bltr);
505 // we have to back up subsequent passes if we're in polygon mode
506 const size_t backup = (SkCanvas::kPolygon_PointMode == mode);
507
508 do {
509 int n = SkToInt(count);
510 if (n > MAX_DEV_PTS) {
511 n = MAX_DEV_PTS;
512 }
513 matrix->mapPoints(devPts, pts, n);
514 proc(rec, devPts, n, bltr);
515 pts += n - backup;
516 SkASSERT(SkToInt(count) >= n);
517 count -= n;
518 if (count > 0) {
519 count += backup;
520 }
521 } while (count != 0);
522 } else {
523 switch (mode) {
524 case SkCanvas::kPoints_PointMode: {
525 // temporarily mark the paint as filling.
526 SkPaint newPaint(paint);
527 newPaint.setStyle(SkPaint::kFill_Style);
528
529 SkScalar width = newPaint.getStrokeWidth();
530 SkScalar radius = SkScalarHalf(width);
531
532 if (newPaint.getStrokeCap() == SkPaint::kRound_Cap) {
533 SkPath path;
534 SkMatrix preMatrix;
535
536 path.addCircle(0, 0, radius);
537 for (size_t i = 0; i < count; i++) {
538 preMatrix.setTranslate(pts[i].fX, pts[i].fY);
539 // pass true for the last point, since we can modify
540 // then path then
541 path.setIsVolatile((count-1) == i);
542 if (device) {
543 device->drawPath(path, newPaint, &preMatrix, (count-1) == i);
544 } else {
545 this->drawPath(path, newPaint, &preMatrix, (count-1) == i);
546 }
547 }
548 } else {
549 SkRect r;
550
551 for (size_t i = 0; i < count; i++) {
552 r.fLeft = pts[i].fX - radius;
553 r.fTop = pts[i].fY - radius;
554 r.fRight = r.fLeft + width;
555 r.fBottom = r.fTop + width;
556 if (device) {
557 device->drawRect(r, newPaint);
558 } else {
559 this->drawRect(r, newPaint);
560 }
561 }
562 }
563 break;
564 }
565 case SkCanvas::kLines_PointMode:
566 if (2 == count && paint.getPathEffect()) {
567 // most likely a dashed line - see if it is one of the ones
568 // we can accelerate
569 SkStrokeRec rec(paint);
570 SkPathEffect::PointData pointData;
571
572 SkPath path;
573 path.moveTo(pts[0]);
574 path.lineTo(pts[1]);
575
576 SkRect cullRect = SkRect::Make(fRC->getBounds());
577
578 if (paint.getPathEffect()->asPoints(&pointData, path, rec,
579 *fMatrix, &cullRect)) {
580 // 'asPoints' managed to find some fast path
581
582 SkPaint newP(paint);
583 newP.setPathEffect(nullptr);
584 newP.setStyle(SkPaint::kFill_Style);
585
586 if (!pointData.fFirst.isEmpty()) {
587 if (device) {
588 device->drawPath(pointData.fFirst, newP);
589 } else {
590 this->drawPath(pointData.fFirst, newP);
591 }
592 }
593
594 if (!pointData.fLast.isEmpty()) {
595 if (device) {
596 device->drawPath(pointData.fLast, newP);
597 } else {
598 this->drawPath(pointData.fLast, newP);
599 }
600 }
601
602 if (pointData.fSize.fX == pointData.fSize.fY) {
603 // The rest of the dashed line can just be drawn as points
604 SkASSERT(pointData.fSize.fX == SkScalarHalf(newP.getStrokeWidth()));
605
606 if (SkPathEffect::PointData::kCircles_PointFlag & pointData.fFlags) {
607 newP.setStrokeCap(SkPaint::kRound_Cap);
608 } else {
609 newP.setStrokeCap(SkPaint::kButt_Cap);
610 }
611
612 if (device) {
613 device->drawPoints(SkCanvas::kPoints_PointMode,
614 pointData.fNumPoints,
615 pointData.fPoints,
616 newP);
617 } else {
618 this->drawPoints(SkCanvas::kPoints_PointMode,
619 pointData.fNumPoints,
620 pointData.fPoints,
621 newP,
622 device);
623 }
624 break;
625 } else {
626 // The rest of the dashed line must be drawn as rects
627 SkASSERT(!(SkPathEffect::PointData::kCircles_PointFlag &
628 pointData.fFlags));
629
630 SkRect r;
631
632 for (int i = 0; i < pointData.fNumPoints; ++i) {
633 r.set(pointData.fPoints[i].fX - pointData.fSize.fX,
634 pointData.fPoints[i].fY - pointData.fSize.fY,
635 pointData.fPoints[i].fX + pointData.fSize.fX,
636 pointData.fPoints[i].fY + pointData.fSize.fY);
637 if (device) {
638 device->drawRect(r, newP);
639 } else {
640 this->drawRect(r, newP);
641 }
642 }
643 }
644
645 break;
646 }
647 }
648 // couldn't take fast path so fall through!
649 case SkCanvas::kPolygon_PointMode: {
650 count -= 1;
651 SkPath path;
652 SkPaint p(paint);
653 p.setStyle(SkPaint::kStroke_Style);
654 size_t inc = (SkCanvas::kLines_PointMode == mode) ? 2 : 1;
655 path.setIsVolatile(true);
656 for (size_t i = 0; i < count; i += inc) {
657 path.moveTo(pts[i]);
658 path.lineTo(pts[i+1]);
659 if (device) {
660 device->drawPath(path, p, nullptr, true);
661 } else {
662 this->drawPath(path, p, nullptr, true);
663 }
664 path.rewind();
665 }
666 break;
667 }
668 }
669 }
670 }
671
compute_stroke_size(const SkPaint & paint,const SkMatrix & matrix)672 static inline SkPoint compute_stroke_size(const SkPaint& paint, const SkMatrix& matrix) {
673 SkASSERT(matrix.rectStaysRect());
674 SkASSERT(SkPaint::kFill_Style != paint.getStyle());
675
676 SkVector size;
677 SkPoint pt = { paint.getStrokeWidth(), paint.getStrokeWidth() };
678 matrix.mapVectors(&size, &pt, 1);
679 return SkPoint::Make(SkScalarAbs(size.fX), SkScalarAbs(size.fY));
680 }
681
easy_rect_join(const SkPaint & paint,const SkMatrix & matrix,SkPoint * strokeSize)682 static bool easy_rect_join(const SkPaint& paint, const SkMatrix& matrix,
683 SkPoint* strokeSize) {
684 if (SkPaint::kMiter_Join != paint.getStrokeJoin() ||
685 paint.getStrokeMiter() < SK_ScalarSqrt2) {
686 return false;
687 }
688
689 *strokeSize = compute_stroke_size(paint, matrix);
690 return true;
691 }
692
ComputeRectType(const SkPaint & paint,const SkMatrix & matrix,SkPoint * strokeSize)693 SkDraw::RectType SkDraw::ComputeRectType(const SkPaint& paint,
694 const SkMatrix& matrix,
695 SkPoint* strokeSize) {
696 RectType rtype;
697 const SkScalar width = paint.getStrokeWidth();
698 const bool zeroWidth = (0 == width);
699 SkPaint::Style style = paint.getStyle();
700
701 if ((SkPaint::kStrokeAndFill_Style == style) && zeroWidth) {
702 style = SkPaint::kFill_Style;
703 }
704
705 if (paint.getPathEffect() || paint.getMaskFilter() ||
706 !matrix.rectStaysRect() || SkPaint::kStrokeAndFill_Style == style) {
707 rtype = kPath_RectType;
708 } else if (SkPaint::kFill_Style == style) {
709 rtype = kFill_RectType;
710 } else if (zeroWidth) {
711 rtype = kHair_RectType;
712 } else if (easy_rect_join(paint, matrix, strokeSize)) {
713 rtype = kStroke_RectType;
714 } else {
715 rtype = kPath_RectType;
716 }
717 return rtype;
718 }
719
rect_points(const SkRect & r)720 static const SkPoint* rect_points(const SkRect& r) {
721 return SkTCast<const SkPoint*>(&r);
722 }
723
rect_points(SkRect & r)724 static SkPoint* rect_points(SkRect& r) {
725 return SkTCast<SkPoint*>(&r);
726 }
727
draw_rect_as_path(const SkDraw & orig,const SkRect & prePaintRect,const SkPaint & paint,const SkMatrix * matrix)728 static void draw_rect_as_path(const SkDraw& orig, const SkRect& prePaintRect,
729 const SkPaint& paint, const SkMatrix* matrix) {
730 SkDraw draw(orig);
731 draw.fMatrix = matrix;
732 SkPath tmp;
733 tmp.addRect(prePaintRect);
734 tmp.setFillType(SkPath::kWinding_FillType);
735 draw.drawPath(tmp, paint, nullptr, true);
736 }
737
drawRect(const SkRect & prePaintRect,const SkPaint & paint,const SkMatrix * paintMatrix,const SkRect * postPaintRect) const738 void SkDraw::drawRect(const SkRect& prePaintRect, const SkPaint& paint,
739 const SkMatrix* paintMatrix, const SkRect* postPaintRect) const {
740 SkDEBUGCODE(this->validate();)
741
742 // nothing to draw
743 if (fRC->isEmpty()) {
744 return;
745 }
746
747 const SkMatrix* matrix;
748 SkMatrix combinedMatrixStorage;
749 if (paintMatrix) {
750 SkASSERT(postPaintRect);
751 combinedMatrixStorage.setConcat(*fMatrix, *paintMatrix);
752 matrix = &combinedMatrixStorage;
753 } else {
754 SkASSERT(!postPaintRect);
755 matrix = fMatrix;
756 }
757
758 SkPoint strokeSize;
759 RectType rtype = ComputeRectType(paint, *fMatrix, &strokeSize);
760
761 if (kPath_RectType == rtype) {
762 draw_rect_as_path(*this, prePaintRect, paint, matrix);
763 return;
764 }
765
766 SkRect devRect;
767 const SkRect& paintRect = paintMatrix ? *postPaintRect : prePaintRect;
768 // skip the paintMatrix when transforming the rect by the CTM
769 fMatrix->mapPoints(rect_points(devRect), rect_points(paintRect), 2);
770 devRect.sort();
771
772 // look for the quick exit, before we build a blitter
773 SkRect bbox = devRect;
774 if (paint.getStyle() != SkPaint::kFill_Style) {
775 // extra space for hairlines
776 if (paint.getStrokeWidth() == 0) {
777 bbox.outset(1, 1);
778 } else {
779 // For kStroke_RectType, strokeSize is already computed.
780 const SkPoint& ssize = (kStroke_RectType == rtype)
781 ? strokeSize
782 : compute_stroke_size(paint, *fMatrix);
783 bbox.outset(SkScalarHalf(ssize.x()), SkScalarHalf(ssize.y()));
784 }
785 }
786
787 if (!SkRectPriv::FitsInFixed(bbox) && rtype != kHair_RectType) {
788 draw_rect_as_path(*this, prePaintRect, paint, matrix);
789 return;
790 }
791
792 SkIRect ir = bbox.roundOut();
793 if (fRC->quickReject(ir)) {
794 return;
795 }
796
797 SkAutoBlitterChoose blitterStorage(fDst, *matrix, paint);
798 const SkRasterClip& clip = *fRC;
799 SkBlitter* blitter = blitterStorage.get();
800
801 // we want to "fill" if we are kFill or kStrokeAndFill, since in the latter
802 // case we are also hairline (if we've gotten to here), which devolves to
803 // effectively just kFill
804 switch (rtype) {
805 case kFill_RectType:
806 if (paint.isAntiAlias()) {
807 SkScan::AntiFillRect(devRect, clip, blitter);
808 } else {
809 SkScan::FillRect(devRect, clip, blitter);
810 }
811 break;
812 case kStroke_RectType:
813 if (paint.isAntiAlias()) {
814 SkScan::AntiFrameRect(devRect, strokeSize, clip, blitter);
815 } else {
816 SkScan::FrameRect(devRect, strokeSize, clip, blitter);
817 }
818 break;
819 case kHair_RectType:
820 if (paint.isAntiAlias()) {
821 SkScan::AntiHairRect(devRect, clip, blitter);
822 } else {
823 SkScan::HairRect(devRect, clip, blitter);
824 }
825 break;
826 default:
827 SkDEBUGFAIL("bad rtype");
828 }
829 }
830
drawDevMask(const SkMask & srcM,const SkPaint & paint) const831 void SkDraw::drawDevMask(const SkMask& srcM, const SkPaint& paint) const {
832 if (srcM.fBounds.isEmpty()) {
833 return;
834 }
835
836 const SkMask* mask = &srcM;
837
838 SkMask dstM;
839 if (paint.getMaskFilter() &&
840 as_MFB(paint.getMaskFilter())->filterMask(&dstM, srcM, *fMatrix, nullptr)) {
841 mask = &dstM;
842 }
843 SkAutoMaskFreeImage ami(dstM.fImage);
844
845 SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint);
846 SkBlitter* blitter = blitterChooser.get();
847
848 SkAAClipBlitterWrapper wrapper;
849 const SkRegion* clipRgn;
850
851 if (fRC->isBW()) {
852 clipRgn = &fRC->bwRgn();
853 } else {
854 wrapper.init(*fRC, blitter);
855 clipRgn = &wrapper.getRgn();
856 blitter = wrapper.getBlitter();
857 }
858 blitter->blitMaskRegion(*mask, *clipRgn);
859 }
860
fast_len(const SkVector & vec)861 static SkScalar fast_len(const SkVector& vec) {
862 SkScalar x = SkScalarAbs(vec.fX);
863 SkScalar y = SkScalarAbs(vec.fY);
864 if (x < y) {
865 SkTSwap(x, y);
866 }
867 return x + SkScalarHalf(y);
868 }
869
SkDrawTreatAAStrokeAsHairline(SkScalar strokeWidth,const SkMatrix & matrix,SkScalar * coverage)870 bool SkDrawTreatAAStrokeAsHairline(SkScalar strokeWidth, const SkMatrix& matrix,
871 SkScalar* coverage) {
872 SkASSERT(strokeWidth > 0);
873 // We need to try to fake a thick-stroke with a modulated hairline.
874
875 if (matrix.hasPerspective()) {
876 return false;
877 }
878
879 SkVector src[2], dst[2];
880 src[0].set(strokeWidth, 0);
881 src[1].set(0, strokeWidth);
882 matrix.mapVectors(dst, src, 2);
883 SkScalar len0 = fast_len(dst[0]);
884 SkScalar len1 = fast_len(dst[1]);
885 if (len0 <= SK_Scalar1 && len1 <= SK_Scalar1) {
886 if (coverage) {
887 *coverage = SkScalarAve(len0, len1);
888 }
889 return true;
890 }
891 return false;
892 }
893
drawRRect(const SkRRect & rrect,const SkPaint & paint) const894 void SkDraw::drawRRect(const SkRRect& rrect, const SkPaint& paint) const {
895 SkDEBUGCODE(this->validate());
896
897 if (fRC->isEmpty()) {
898 return;
899 }
900
901 {
902 // TODO: Investigate optimizing these options. They are in the same
903 // order as SkDraw::drawPath, which handles each case. It may be
904 // that there is no way to optimize for these using the SkRRect path.
905 SkScalar coverage;
906 if (SkDrawTreatAsHairline(paint, *fMatrix, &coverage)) {
907 goto DRAW_PATH;
908 }
909
910 if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
911 goto DRAW_PATH;
912 }
913 }
914
915 if (paint.getMaskFilter()) {
916 // Transform the rrect into device space.
917 SkRRect devRRect;
918 if (rrect.transform(*fMatrix, &devRRect)) {
919 SkAutoBlitterChoose blitter(fDst, *fMatrix, paint);
920 if (as_MFB(paint.getMaskFilter())->filterRRect(devRRect, *fMatrix,
921 *fRC, blitter.get())) {
922 return; // filterRRect() called the blitter, so we're done
923 }
924 }
925 }
926
927 DRAW_PATH:
928 // Now fall back to the default case of using a path.
929 SkPath path;
930 path.addRRect(rrect);
931 this->drawPath(path, paint, nullptr, true);
932 }
933
ComputeResScaleForStroking(const SkMatrix & matrix)934 SkScalar SkDraw::ComputeResScaleForStroking(const SkMatrix& matrix) {
935 if (!matrix.hasPerspective()) {
936 SkScalar sx = SkPoint::Length(matrix[SkMatrix::kMScaleX], matrix[SkMatrix::kMSkewY]);
937 SkScalar sy = SkPoint::Length(matrix[SkMatrix::kMSkewX], matrix[SkMatrix::kMScaleY]);
938 if (SkScalarsAreFinite(sx, sy)) {
939 SkScalar scale = SkTMax(sx, sy);
940 if (scale > 0) {
941 return scale;
942 }
943 }
944 }
945 return 1;
946 }
947
drawDevPath(const SkPath & devPath,const SkPaint & paint,bool drawCoverage,SkBlitter * customBlitter,bool doFill,SkInitOnceData * iData) const948 void SkDraw::drawDevPath(const SkPath& devPath, const SkPaint& paint, bool drawCoverage,
949 SkBlitter* customBlitter, bool doFill, SkInitOnceData* iData) const {
950 SkBlitter* blitter = nullptr;
951 SkAutoBlitterChoose blitterStorage;
952 SkAutoBlitterChoose* blitterStoragePtr = &blitterStorage;
953 if (iData) {
954 // we're in the threaded init-once phase; the blitter has to be allocated in the thread
955 // allocator so it will remain valid later during the draw phase.
956 blitterStoragePtr = iData->fAlloc->make<SkAutoBlitterChoose>();
957 }
958 if (nullptr == customBlitter) {
959 blitterStoragePtr->choose(fDst, *fMatrix, paint, drawCoverage);
960 blitter = blitterStoragePtr->get();
961 } else {
962 blitter = customBlitter;
963 }
964
965 if (paint.getMaskFilter()) {
966 SkStrokeRec::InitStyle style = doFill ? SkStrokeRec::kFill_InitStyle
967 : SkStrokeRec::kHairline_InitStyle;
968 if (as_MFB(paint.getMaskFilter())->filterPath(devPath, *fMatrix, *fRC, blitter, style)) {
969 if (iData) {
970 iData->setEmptyDrawFn();
971 }
972 return; // filterPath() called the blitter, so we're done
973 }
974 }
975
976 void (*proc)(const SkPath&, const SkRasterClip&, SkBlitter*);
977 if (doFill) {
978 if (paint.isAntiAlias()) {
979 proc = SkScan::AntiFillPath;
980 } else {
981 proc = SkScan::FillPath;
982 }
983 } else { // hairline
984 if (paint.isAntiAlias()) {
985 switch (paint.getStrokeCap()) {
986 case SkPaint::kButt_Cap:
987 proc = SkScan::AntiHairPath;
988 break;
989 case SkPaint::kSquare_Cap:
990 proc = SkScan::AntiHairSquarePath;
991 break;
992 case SkPaint::kRound_Cap:
993 proc = SkScan::AntiHairRoundPath;
994 break;
995 default:
996 proc SK_INIT_TO_AVOID_WARNING;
997 SkDEBUGFAIL("unknown paint cap type");
998 }
999 } else {
1000 switch (paint.getStrokeCap()) {
1001 case SkPaint::kButt_Cap:
1002 proc = SkScan::HairPath;
1003 break;
1004 case SkPaint::kSquare_Cap:
1005 proc = SkScan::HairSquarePath;
1006 break;
1007 case SkPaint::kRound_Cap:
1008 proc = SkScan::HairRoundPath;
1009 break;
1010 default:
1011 proc SK_INIT_TO_AVOID_WARNING;
1012 SkDEBUGFAIL("unknown paint cap type");
1013 }
1014 }
1015 }
1016
1017 if (iData == nullptr) {
1018 proc(devPath, *fRC, blitter); // proceed directly if we're not in threaded init-once
1019 } else if (!doFill || !paint.isAntiAlias()) {
1020 // TODO remove true in the if statement above so we can proceed to DAA.
1021
1022 // We're in threaded init-once but we can't use DAA. Hence we'll stop here and hand all the
1023 // remaining work to draw phase. This is a simple example of how to add init-once to
1024 // existing drawXXX commands: simply send in SkInitOnceData, do as much init work as
1025 // possible, and finally wrap the remaining work into iData->fElement->fDrawFn.
1026 iData->fElement->setDrawFn([proc, devPath, blitter](SkArenaAlloc* alloc,
1027 const SkThreadedBMPDevice::DrawState& ds, const SkIRect& tileBounds) {
1028 SkThreadedBMPDevice::TileDraw tileDraw(ds, tileBounds);
1029 proc(devPath, *tileDraw.fRC, blitter);
1030 });
1031 } else {
1032 // We can use DAA to do scan conversion in the init-once phase.
1033 SkDAARecord* record = iData->fAlloc->make<SkDAARecord>(iData->fAlloc);
1034 SkNullBlitter nullBlitter; // We don't want to blit anything during the init phase
1035 SkScan::AntiFillPath(devPath, *fRC, &nullBlitter, record);
1036 iData->fElement->setDrawFn([record, devPath, blitter](SkArenaAlloc* alloc,
1037 const SkThreadedBMPDevice::DrawState& ds, const SkIRect& tileBounds) {
1038 SkASSERT(record->fType != SkDAARecord::Type::kToBeComputed);
1039 SkThreadedBMPDevice::TileDraw tileDraw(ds, tileBounds);
1040 SkScan::AntiFillPath(devPath, *tileDraw.fRC, blitter, record);
1041 });
1042 }
1043 }
1044
drawPath(const SkPath & origSrcPath,const SkPaint & origPaint,const SkMatrix * prePathMatrix,bool pathIsMutable,bool drawCoverage,SkBlitter * customBlitter,SkInitOnceData * iData) const1045 void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint,
1046 const SkMatrix* prePathMatrix, bool pathIsMutable,
1047 bool drawCoverage, SkBlitter* customBlitter,
1048 SkInitOnceData* iData) const {
1049 SkDEBUGCODE(this->validate();)
1050
1051 // nothing to draw
1052 if (fRC->isEmpty()) {
1053 if (iData) {
1054 iData->setEmptyDrawFn();
1055 }
1056 return;
1057 }
1058
1059 SkPath* pathPtr = (SkPath*)&origSrcPath;
1060 bool doFill = true;
1061 SkPath tmpPathStorage;
1062 SkPath* tmpPath = &tmpPathStorage;
1063 SkMatrix tmpMatrix;
1064 const SkMatrix* matrix = fMatrix;
1065 if (iData) {
1066 tmpPath = iData->fAlloc->make<SkPath>();
1067 }
1068 tmpPath->setIsVolatile(true);
1069
1070 if (prePathMatrix) {
1071 if (origPaint.getPathEffect() || origPaint.getStyle() != SkPaint::kFill_Style) {
1072 SkPath* result = pathPtr;
1073
1074 if (!pathIsMutable) {
1075 result = tmpPath;
1076 pathIsMutable = true;
1077 }
1078 pathPtr->transform(*prePathMatrix, result);
1079 pathPtr = result;
1080 } else {
1081 tmpMatrix.setConcat(*matrix, *prePathMatrix);
1082 matrix = &tmpMatrix;
1083 }
1084 }
1085 // at this point we're done with prePathMatrix
1086 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
1087
1088 SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
1089
1090 {
1091 SkScalar coverage;
1092 if (SkDrawTreatAsHairline(origPaint, *matrix, &coverage)) {
1093 if (SK_Scalar1 == coverage) {
1094 paint.writable()->setStrokeWidth(0);
1095 } else if (SkBlendMode_SupportsCoverageAsAlpha(origPaint.getBlendMode())) {
1096 U8CPU newAlpha;
1097 #if 0
1098 newAlpha = SkToU8(SkScalarRoundToInt(coverage *
1099 origPaint.getAlpha()));
1100 #else
1101 // this is the old technique, which we preserve for now so
1102 // we don't change previous results (testing)
1103 // the new way seems fine, its just (a tiny bit) different
1104 int scale = (int)(coverage * 256);
1105 newAlpha = origPaint.getAlpha() * scale >> 8;
1106 #endif
1107 SkPaint* writablePaint = paint.writable();
1108 writablePaint->setStrokeWidth(0);
1109 writablePaint->setAlpha(newAlpha);
1110 }
1111 }
1112 }
1113
1114 if (paint->getPathEffect() || paint->getStyle() != SkPaint::kFill_Style) {
1115 SkRect cullRect;
1116 const SkRect* cullRectPtr = nullptr;
1117 if (this->computeConservativeLocalClipBounds(&cullRect)) {
1118 cullRectPtr = &cullRect;
1119 }
1120 doFill = paint->getFillPath(*pathPtr, tmpPath, cullRectPtr,
1121 ComputeResScaleForStroking(*fMatrix));
1122 pathPtr = tmpPath;
1123 }
1124
1125 // avoid possibly allocating a new path in transform if we can
1126 SkPath* devPathPtr = pathIsMutable ? pathPtr : tmpPath;
1127
1128 // transform the path into device space
1129 pathPtr->transform(*matrix, devPathPtr);
1130
1131 this->drawDevPath(*devPathPtr, *paint, drawCoverage, customBlitter, doFill, iData);
1132 }
1133
drawBitmapAsMask(const SkBitmap & bitmap,const SkPaint & paint) const1134 void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, const SkPaint& paint) const {
1135 SkASSERT(bitmap.colorType() == kAlpha_8_SkColorType);
1136
1137 if (SkTreatAsSprite(*fMatrix, bitmap.dimensions(), paint)) {
1138 int ix = SkScalarRoundToInt(fMatrix->getTranslateX());
1139 int iy = SkScalarRoundToInt(fMatrix->getTranslateY());
1140
1141 SkPixmap pmap;
1142 if (!bitmap.peekPixels(&pmap)) {
1143 return;
1144 }
1145 SkMask mask;
1146 mask.fBounds.set(ix, iy, ix + pmap.width(), iy + pmap.height());
1147 mask.fFormat = SkMask::kA8_Format;
1148 mask.fRowBytes = SkToU32(pmap.rowBytes());
1149 // fImage is typed as writable, but in this case it is used read-only
1150 mask.fImage = (uint8_t*)pmap.addr8(0, 0);
1151
1152 this->drawDevMask(mask, paint);
1153 } else { // need to xform the bitmap first
1154 SkRect r;
1155 SkMask mask;
1156
1157 r.set(0, 0,
1158 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
1159 fMatrix->mapRect(&r);
1160 r.round(&mask.fBounds);
1161
1162 // set the mask's bounds to the transformed bitmap-bounds,
1163 // clipped to the actual device
1164 {
1165 SkIRect devBounds;
1166 devBounds.set(0, 0, fDst.width(), fDst.height());
1167 // need intersect(l, t, r, b) on irect
1168 if (!mask.fBounds.intersect(devBounds)) {
1169 return;
1170 }
1171 }
1172
1173 mask.fFormat = SkMask::kA8_Format;
1174 mask.fRowBytes = SkAlign4(mask.fBounds.width());
1175 size_t size = mask.computeImageSize();
1176 if (0 == size) {
1177 // the mask is too big to allocated, draw nothing
1178 return;
1179 }
1180
1181 // allocate (and clear) our temp buffer to hold the transformed bitmap
1182 SkAutoTMalloc<uint8_t> storage(size);
1183 mask.fImage = storage.get();
1184 memset(mask.fImage, 0, size);
1185
1186 // now draw our bitmap(src) into mask(dst), transformed by the matrix
1187 {
1188 SkBitmap device;
1189 device.installPixels(SkImageInfo::MakeA8(mask.fBounds.width(), mask.fBounds.height()),
1190 mask.fImage, mask.fRowBytes);
1191
1192 SkCanvas c(device);
1193 // need the unclipped top/left for the translate
1194 c.translate(-SkIntToScalar(mask.fBounds.fLeft),
1195 -SkIntToScalar(mask.fBounds.fTop));
1196 c.concat(*fMatrix);
1197
1198 // We can't call drawBitmap, or we'll infinitely recurse. Instead
1199 // we manually build a shader and draw that into our new mask
1200 SkPaint tmpPaint;
1201 tmpPaint.setFlags(paint.getFlags());
1202 tmpPaint.setFilterQuality(paint.getFilterQuality());
1203 SkPaint paintWithShader = make_paint_with_image(tmpPaint, bitmap);
1204 SkRect rr;
1205 rr.set(0, 0, SkIntToScalar(bitmap.width()),
1206 SkIntToScalar(bitmap.height()));
1207 c.drawRect(rr, paintWithShader);
1208 }
1209 this->drawDevMask(mask, paint);
1210 }
1211 }
1212
clipped_out(const SkMatrix & m,const SkRasterClip & c,const SkRect & srcR)1213 static bool clipped_out(const SkMatrix& m, const SkRasterClip& c,
1214 const SkRect& srcR) {
1215 SkRect dstR;
1216 m.mapRect(&dstR, srcR);
1217 return c.quickReject(dstR.roundOut());
1218 }
1219
clipped_out(const SkMatrix & matrix,const SkRasterClip & clip,int width,int height)1220 static bool clipped_out(const SkMatrix& matrix, const SkRasterClip& clip,
1221 int width, int height) {
1222 SkRect r;
1223 r.set(0, 0, SkIntToScalar(width), SkIntToScalar(height));
1224 return clipped_out(matrix, clip, r);
1225 }
1226
clipHandlesSprite(const SkRasterClip & clip,int x,int y,const SkPixmap & pmap)1227 static bool clipHandlesSprite(const SkRasterClip& clip, int x, int y, const SkPixmap& pmap) {
1228 return clip.isBW() || clip.quickContains(x, y, x + pmap.width(), y + pmap.height());
1229 }
1230
drawBitmap(const SkBitmap & bitmap,const SkMatrix & prematrix,const SkRect * dstBounds,const SkPaint & origPaint) const1231 void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix,
1232 const SkRect* dstBounds, const SkPaint& origPaint) const {
1233 SkDEBUGCODE(this->validate();)
1234
1235 // nothing to draw
1236 if (fRC->isEmpty() ||
1237 bitmap.width() == 0 || bitmap.height() == 0 ||
1238 bitmap.colorType() == kUnknown_SkColorType) {
1239 return;
1240 }
1241
1242 SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
1243 if (origPaint.getStyle() != SkPaint::kFill_Style) {
1244 paint.writable()->setStyle(SkPaint::kFill_Style);
1245 }
1246
1247 SkMatrix matrix;
1248 matrix.setConcat(*fMatrix, prematrix);
1249
1250 if (clipped_out(matrix, *fRC, bitmap.width(), bitmap.height())) {
1251 return;
1252 }
1253
1254 if (bitmap.colorType() != kAlpha_8_SkColorType
1255 && SkTreatAsSprite(matrix, bitmap.dimensions(), *paint)) {
1256 //
1257 // It is safe to call lock pixels now, since we know the matrix is
1258 // (more or less) identity.
1259 //
1260 SkPixmap pmap;
1261 if (!bitmap.peekPixels(&pmap)) {
1262 return;
1263 }
1264 int ix = SkScalarRoundToInt(matrix.getTranslateX());
1265 int iy = SkScalarRoundToInt(matrix.getTranslateY());
1266 if (clipHandlesSprite(*fRC, ix, iy, pmap)) {
1267 SkSTArenaAlloc<kSkBlitterContextSize> allocator;
1268 // blitter will be owned by the allocator.
1269 SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, *paint, pmap, ix, iy, &allocator);
1270 if (blitter) {
1271 SkScan::FillIRect(SkIRect::MakeXYWH(ix, iy, pmap.width(), pmap.height()),
1272 *fRC, blitter);
1273 return;
1274 }
1275 // if !blitter, then we fall-through to the slower case
1276 }
1277 }
1278
1279 // now make a temp draw on the stack, and use it
1280 //
1281 SkDraw draw(*this);
1282 draw.fMatrix = &matrix;
1283
1284 if (bitmap.colorType() == kAlpha_8_SkColorType && !paint->getColorFilter()) {
1285 draw.drawBitmapAsMask(bitmap, *paint);
1286 } else {
1287 SkPaint paintWithShader = make_paint_with_image(*paint, bitmap);
1288 const SkRect srcBounds = SkRect::MakeIWH(bitmap.width(), bitmap.height());
1289 if (dstBounds) {
1290 this->drawRect(srcBounds, paintWithShader, &prematrix, dstBounds);
1291 } else {
1292 draw.drawRect(srcBounds, paintWithShader);
1293 }
1294 }
1295 }
1296
drawSprite(const SkBitmap & bitmap,int x,int y,const SkPaint & origPaint) const1297 void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& origPaint) const {
1298 SkDEBUGCODE(this->validate();)
1299
1300 // nothing to draw
1301 if (fRC->isEmpty() ||
1302 bitmap.width() == 0 || bitmap.height() == 0 ||
1303 bitmap.colorType() == kUnknown_SkColorType) {
1304 return;
1305 }
1306
1307 const SkIRect bounds = SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height());
1308
1309 if (fRC->quickReject(bounds)) {
1310 return; // nothing to draw
1311 }
1312
1313 SkPaint paint(origPaint);
1314 paint.setStyle(SkPaint::kFill_Style);
1315
1316 SkPixmap pmap;
1317 if (!bitmap.peekPixels(&pmap)) {
1318 return;
1319 }
1320
1321 if (nullptr == paint.getColorFilter() && clipHandlesSprite(*fRC, x, y, pmap)) {
1322 // blitter will be owned by the allocator.
1323 SkSTArenaAlloc<kSkBlitterContextSize> allocator;
1324 SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, paint, pmap, x, y, &allocator);
1325 if (blitter) {
1326 SkScan::FillIRect(bounds, *fRC, blitter);
1327 return;
1328 }
1329 }
1330
1331 SkMatrix matrix;
1332 SkRect r;
1333
1334 // get a scalar version of our rect
1335 r.set(bounds);
1336
1337 // create shader with offset
1338 matrix.setTranslate(r.fLeft, r.fTop);
1339 SkPaint paintWithShader = make_paint_with_image(paint, bitmap, &matrix);
1340 SkDraw draw(*this);
1341 matrix.reset();
1342 draw.fMatrix = &matrix;
1343 // call ourself with a rect
1344 draw.drawRect(r, paintWithShader);
1345 }
1346
1347 ///////////////////////////////////////////////////////////////////////////////
1348
1349 #include "SkPaintPriv.h"
1350 #include "SkScalerContext.h"
1351 #include "SkGlyphCache.h"
1352 #include "SkTextToPathIter.h"
1353 #include "SkUtils.h"
1354
ShouldDrawTextAsPaths(const SkPaint & paint,const SkMatrix & ctm,SkScalar sizeLimit)1355 bool SkDraw::ShouldDrawTextAsPaths(const SkPaint& paint, const SkMatrix& ctm, SkScalar sizeLimit) {
1356 // hairline glyphs are fast enough so we don't need to cache them
1357 if (SkPaint::kStroke_Style == paint.getStyle() && 0 == paint.getStrokeWidth()) {
1358 return true;
1359 }
1360
1361 // we don't cache perspective
1362 if (ctm.hasPerspective()) {
1363 return true;
1364 }
1365
1366 // Glyphs like Emojis can't be rendered as a path.
1367 if (paint.getTypeface() && paint.getTypeface()->hasColorGlyphs()) {
1368 return false;
1369 }
1370
1371 SkMatrix textM;
1372 SkPaintPriv::MakeTextMatrix(&textM, paint);
1373 return SkPaint::TooBigToUseCache(ctm, textM, sizeLimit);
1374 }
1375
drawText_asPaths(const char text[],size_t byteLength,SkScalar x,SkScalar y,const SkPaint & paint) const1376 void SkDraw::drawText_asPaths(const char text[], size_t byteLength, SkScalar x, SkScalar y,
1377 const SkPaint& paint) const {
1378 SkDEBUGCODE(this->validate();)
1379
1380 SkTextToPathIter iter(text, byteLength, paint, true);
1381
1382 SkMatrix matrix;
1383 matrix.setScale(iter.getPathScale(), iter.getPathScale());
1384 matrix.postTranslate(x, y);
1385
1386 const SkPath* iterPath;
1387 SkScalar xpos, prevXPos = 0;
1388
1389 while (iter.next(&iterPath, &xpos)) {
1390 matrix.postTranslate(xpos - prevXPos, 0);
1391 if (iterPath) {
1392 this->drawPath(*iterPath, iter.getPaint(), &matrix, false);
1393 }
1394 prevXPos = xpos;
1395 }
1396 }
1397
1398 // disable warning : local variable used without having been initialized
1399 #if defined _WIN32
1400 #pragma warning ( push )
1401 #pragma warning ( disable : 4701 )
1402 #endif
1403
1404 ////////////////////////////////////////////////////////////////////////////////////////////////////
1405
1406 class DrawOneGlyph {
1407 public:
DrawOneGlyph(const SkDraw & draw,const SkPaint & paint,SkGlyphCache * cache,SkBlitter * blitter)1408 DrawOneGlyph(const SkDraw& draw, const SkPaint& paint, SkGlyphCache* cache, SkBlitter* blitter)
1409 : fUseRegionToDraw(UsingRegionToDraw(draw.fRC))
1410 , fGlyphCache(cache)
1411 , fBlitter(blitter)
1412 , fClip(fUseRegionToDraw ? &draw.fRC->bwRgn() : nullptr)
1413 , fDraw(draw)
1414 , fPaint(paint)
1415 , fClipBounds(PickClipBounds(draw)) { }
1416
operator ()(const SkGlyph & glyph,SkPoint position,SkPoint rounding)1417 void operator()(const SkGlyph& glyph, SkPoint position, SkPoint rounding) {
1418 position += rounding;
1419 // Prevent glyphs from being drawn outside of or straddling the edge of device space.
1420 // Comparisons written a little weirdly so that NaN coordinates are treated safely.
1421 auto gt = [](float a, int b) { return !(a <= (float)b); };
1422 auto lt = [](float a, int b) { return !(a >= (float)b); };
1423 if (gt(position.fX, INT_MAX - (INT16_MAX + UINT16_MAX)) ||
1424 lt(position.fX, INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)) ||
1425 gt(position.fY, INT_MAX - (INT16_MAX + UINT16_MAX)) ||
1426 lt(position.fY, INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/))) {
1427 return;
1428 }
1429
1430 int left = SkScalarFloorToInt(position.fX);
1431 int top = SkScalarFloorToInt(position.fY);
1432 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1433
1434 left += glyph.fLeft;
1435 top += glyph.fTop;
1436
1437 int right = left + glyph.fWidth;
1438 int bottom = top + glyph.fHeight;
1439
1440 SkMask mask;
1441 mask.fBounds.set(left, top, right, bottom);
1442 SkASSERT(!mask.fBounds.isEmpty());
1443
1444 if (fUseRegionToDraw) {
1445 SkRegion::Cliperator clipper(*fClip, mask.fBounds);
1446
1447 if (!clipper.done() && this->getImageData(glyph, &mask)) {
1448 const SkIRect& cr = clipper.rect();
1449 do {
1450 this->blitMask(mask, cr);
1451 clipper.next();
1452 } while (!clipper.done());
1453 }
1454 } else {
1455 SkIRect storage;
1456 SkIRect* bounds = &mask.fBounds;
1457
1458 // this extra test is worth it, assuming that most of the time it succeeds
1459 // since we can avoid writing to storage
1460 if (!fClipBounds.containsNoEmptyCheck(mask.fBounds)) {
1461 if (!storage.intersectNoEmptyCheck(mask.fBounds, fClipBounds))
1462 return;
1463 bounds = &storage;
1464 }
1465
1466 if (this->getImageData(glyph, &mask)) {
1467 this->blitMask(mask, *bounds);
1468 }
1469 }
1470 }
1471
1472 private:
UsingRegionToDraw(const SkRasterClip * rClip)1473 static bool UsingRegionToDraw(const SkRasterClip* rClip) {
1474 return rClip->isBW() && !rClip->isRect();
1475 }
1476
PickClipBounds(const SkDraw & draw)1477 static SkIRect PickClipBounds(const SkDraw& draw) {
1478 const SkRasterClip& rasterClip = *draw.fRC;
1479
1480 if (rasterClip.isBW()) {
1481 return rasterClip.bwRgn().getBounds();
1482 } else {
1483 return rasterClip.aaRgn().getBounds();
1484 }
1485 }
1486
getImageData(const SkGlyph & glyph,SkMask * mask)1487 bool getImageData(const SkGlyph& glyph, SkMask* mask) {
1488 uint8_t* bits = (uint8_t*)(fGlyphCache->findImage(glyph));
1489 if (nullptr == bits) {
1490 return false; // can't rasterize glyph
1491 }
1492 mask->fImage = bits;
1493 mask->fRowBytes = glyph.rowBytes();
1494 mask->fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
1495 return true;
1496 }
1497
blitMask(const SkMask & mask,const SkIRect & clip) const1498 void blitMask(const SkMask& mask, const SkIRect& clip) const {
1499 if (SkMask::kARGB32_Format == mask.fFormat) {
1500 SkBitmap bm;
1501 bm.installPixels(
1502 SkImageInfo::MakeN32Premul(mask.fBounds.width(), mask.fBounds.height()),
1503 (SkPMColor*)mask.fImage, mask.fRowBytes);
1504
1505 fDraw.drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), fPaint);
1506 } else {
1507 fBlitter->blitMask(mask, clip);
1508 }
1509 }
1510
1511 const bool fUseRegionToDraw;
1512 SkGlyphCache * const fGlyphCache;
1513 SkBlitter * const fBlitter;
1514 const SkRegion* const fClip;
1515 const SkDraw& fDraw;
1516 const SkPaint& fPaint;
1517 const SkIRect fClipBounds;
1518 };
1519
1520 ////////////////////////////////////////////////////////////////////////////////////////////////////
1521
scalerContextFlags() const1522 SkScalerContextFlags SkDraw::scalerContextFlags() const {
1523 SkScalerContextFlags flags = SkScalerContextFlags::kBoostContrast;
1524 if (!fDst.colorSpace()) {
1525 flags = kFakeGammaAndBoostContrast;
1526 }
1527 return flags;
1528 }
1529
drawText(const char text[],size_t byteLength,SkScalar x,SkScalar y,const SkPaint & paint,const SkSurfaceProps * props) const1530 void SkDraw::drawText(const char text[], size_t byteLength, SkScalar x, SkScalar y,
1531 const SkPaint& paint, const SkSurfaceProps* props) const {
1532 SkASSERT(byteLength == 0 || text != nullptr);
1533
1534 SkDEBUGCODE(this->validate();)
1535
1536 // nothing to draw
1537 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) {
1538 return;
1539 }
1540
1541 // SkScalarRec doesn't currently have a way of representing hairline stroke and
1542 // will fill if its frame-width is 0.
1543 if (ShouldDrawTextAsPaths(paint, *fMatrix)) {
1544 this->drawText_asPaths(text, byteLength, x, y, paint);
1545 return;
1546 }
1547
1548 SkAutoGlyphCache cache(paint, props, this->scalerContextFlags(), fMatrix);
1549
1550 // The Blitter Choose needs to be live while using the blitter below.
1551 SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint);
1552 SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get());
1553 DrawOneGlyph drawOneGlyph(*this, paint, cache.get(), wrapper.getBlitter());
1554
1555 SkFindAndPlaceGlyph::ProcessText(
1556 paint.getTextEncoding(), text, byteLength,
1557 {x, y}, *fMatrix, paint.getTextAlign(), cache.get(), drawOneGlyph);
1558 }
1559
1560 //////////////////////////////////////////////////////////////////////////////
1561
drawPosText_asPaths(const char text[],size_t byteLength,const SkScalar pos[],int scalarsPerPosition,const SkPoint & offset,const SkPaint & origPaint,const SkSurfaceProps * props) const1562 void SkDraw::drawPosText_asPaths(const char text[], size_t byteLength, const SkScalar pos[],
1563 int scalarsPerPosition, const SkPoint& offset,
1564 const SkPaint& origPaint, const SkSurfaceProps* props) const {
1565 // setup our std paint, in hopes of getting hits in the cache
1566 SkPaint paint(origPaint);
1567 SkScalar matrixScale = paint.setupForAsPaths();
1568
1569 SkMatrix matrix;
1570 matrix.setScale(matrixScale, matrixScale);
1571
1572 // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache.
1573 paint.setStyle(SkPaint::kFill_Style);
1574 paint.setPathEffect(nullptr);
1575
1576 SkPaint::GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(paint.getTextEncoding(),
1577 paint.isDevKernText(),
1578 true);
1579 SkAutoGlyphCache cache(paint, props, this->scalerContextFlags(), nullptr);
1580
1581 const char* stop = text + byteLength;
1582 SkTextAlignProc alignProc(paint.getTextAlign());
1583 SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition);
1584
1585 // Now restore the original settings, so we "draw" with whatever style/stroking.
1586 paint.setStyle(origPaint.getStyle());
1587 paint.setPathEffect(origPaint.refPathEffect());
1588
1589 while (text < stop) {
1590 const SkGlyph& glyph = glyphCacheProc(cache.get(), &text);
1591 if (glyph.fWidth) {
1592 const SkPath* path = cache->findPath(glyph);
1593 if (path) {
1594 SkPoint tmsLoc;
1595 tmsProc(pos, &tmsLoc);
1596 SkPoint loc;
1597 alignProc(tmsLoc, glyph, &loc);
1598
1599 matrix[SkMatrix::kMTransX] = loc.fX;
1600 matrix[SkMatrix::kMTransY] = loc.fY;
1601 this->drawPath(*path, paint, &matrix, false);
1602 }
1603 }
1604 pos += scalarsPerPosition;
1605 }
1606 }
1607
drawPosText(const char text[],size_t byteLength,const SkScalar pos[],int scalarsPerPosition,const SkPoint & offset,const SkPaint & paint,const SkSurfaceProps * props) const1608 void SkDraw::drawPosText(const char text[], size_t byteLength, const SkScalar pos[],
1609 int scalarsPerPosition, const SkPoint& offset, const SkPaint& paint,
1610 const SkSurfaceProps* props) const {
1611 SkASSERT(byteLength == 0 || text != nullptr);
1612 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
1613
1614 SkDEBUGCODE(this->validate();)
1615
1616 // nothing to draw
1617 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) {
1618 return;
1619 }
1620
1621 if (ShouldDrawTextAsPaths(paint, *fMatrix)) {
1622 this->drawPosText_asPaths(text, byteLength, pos, scalarsPerPosition, offset, paint, props);
1623 return;
1624 }
1625
1626 SkAutoGlyphCache cache(paint, props, this->scalerContextFlags(), fMatrix);
1627
1628 // The Blitter Choose needs to be live while using the blitter below.
1629 SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint);
1630 SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get());
1631 DrawOneGlyph drawOneGlyph(*this, paint, cache.get(), wrapper.getBlitter());
1632 SkPaint::Align textAlignment = paint.getTextAlign();
1633
1634 SkFindAndPlaceGlyph::ProcessPosText(
1635 paint.getTextEncoding(), text, byteLength,
1636 offset, *fMatrix, pos, scalarsPerPosition, textAlignment, cache.get(), drawOneGlyph);
1637 }
1638
1639 #if defined _WIN32
1640 #pragma warning ( pop )
1641 #endif
1642
1643 ////////////////////////////////////////////////////////////////////////////////////////////////
1644
1645 #ifdef SK_DEBUG
1646
validate() const1647 void SkDraw::validate() const {
1648 SkASSERT(fMatrix != nullptr);
1649 SkASSERT(fRC != nullptr);
1650
1651 const SkIRect& cr = fRC->getBounds();
1652 SkIRect br;
1653
1654 br.set(0, 0, fDst.width(), fDst.height());
1655 SkASSERT(cr.isEmpty() || br.contains(cr));
1656 }
1657
1658 #endif
1659
1660 ////////////////////////////////////////////////////////////////////////////////////////////////
1661
1662 #include "SkPath.h"
1663 #include "SkDraw.h"
1664 #include "SkRegion.h"
1665 #include "SkBlitter.h"
1666
compute_bounds(const SkPath & devPath,const SkIRect * clipBounds,const SkMaskFilter * filter,const SkMatrix * filterMatrix,SkIRect * bounds)1667 static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds,
1668 const SkMaskFilter* filter, const SkMatrix* filterMatrix,
1669 SkIRect* bounds) {
1670 if (devPath.isEmpty()) {
1671 return false;
1672 }
1673
1674 // init our bounds from the path
1675 *bounds = devPath.getBounds().makeOutset(SK_ScalarHalf, SK_ScalarHalf).roundOut();
1676
1677 SkIPoint margin = SkIPoint::Make(0, 0);
1678 if (filter) {
1679 SkASSERT(filterMatrix);
1680
1681 SkMask srcM, dstM;
1682
1683 srcM.fBounds = *bounds;
1684 srcM.fFormat = SkMask::kA8_Format;
1685 if (!as_MFB(filter)->filterMask(&dstM, srcM, *filterMatrix, &margin)) {
1686 return false;
1687 }
1688 }
1689
1690 // (possibly) trim the bounds to reflect the clip
1691 // (plus whatever slop the filter needs)
1692 if (clipBounds) {
1693 // Ugh. Guard against gigantic margins from wacky filters. Without this
1694 // check we can request arbitrary amounts of slop beyond our visible
1695 // clip, and bring down the renderer (at least on finite RAM machines
1696 // like handsets, etc.). Need to balance this invented value between
1697 // quality of large filters like blurs, and the corresponding memory
1698 // requests.
1699 static const int MAX_MARGIN = 128;
1700 if (!bounds->intersect(clipBounds->makeOutset(SkMin32(margin.fX, MAX_MARGIN),
1701 SkMin32(margin.fY, MAX_MARGIN)))) {
1702 return false;
1703 }
1704 }
1705
1706 return true;
1707 }
1708
draw_into_mask(const SkMask & mask,const SkPath & devPath,SkStrokeRec::InitStyle style)1709 static void draw_into_mask(const SkMask& mask, const SkPath& devPath,
1710 SkStrokeRec::InitStyle style) {
1711 SkDraw draw;
1712 if (!draw.fDst.reset(mask)) {
1713 return;
1714 }
1715
1716 SkRasterClip clip;
1717 SkMatrix matrix;
1718 SkPaint paint;
1719
1720 clip.setRect(SkIRect::MakeWH(mask.fBounds.width(), mask.fBounds.height()));
1721 matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
1722 -SkIntToScalar(mask.fBounds.fTop));
1723
1724 draw.fRC = &clip;
1725 draw.fMatrix = &matrix;
1726 paint.setAntiAlias(true);
1727 switch (style) {
1728 case SkStrokeRec::kHairline_InitStyle:
1729 SkASSERT(!paint.getStrokeWidth());
1730 paint.setStyle(SkPaint::kStroke_Style);
1731 break;
1732 case SkStrokeRec::kFill_InitStyle:
1733 SkASSERT(paint.getStyle() == SkPaint::kFill_Style);
1734 break;
1735
1736 }
1737 draw.drawPath(devPath, paint);
1738 }
1739
DrawToMask(const SkPath & devPath,const SkIRect * clipBounds,const SkMaskFilter * filter,const SkMatrix * filterMatrix,SkMask * mask,SkMask::CreateMode mode,SkStrokeRec::InitStyle style)1740 bool SkDraw::DrawToMask(const SkPath& devPath, const SkIRect* clipBounds,
1741 const SkMaskFilter* filter, const SkMatrix* filterMatrix,
1742 SkMask* mask, SkMask::CreateMode mode,
1743 SkStrokeRec::InitStyle style) {
1744 if (SkMask::kJustRenderImage_CreateMode != mode) {
1745 if (!compute_bounds(devPath, clipBounds, filter, filterMatrix, &mask->fBounds))
1746 return false;
1747 }
1748
1749 if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) {
1750 mask->fFormat = SkMask::kA8_Format;
1751 mask->fRowBytes = mask->fBounds.width();
1752 size_t size = mask->computeImageSize();
1753 if (0 == size) {
1754 // we're too big to allocate the mask, abort
1755 return false;
1756 }
1757 mask->fImage = SkMask::AllocImage(size, SkMask::kZeroInit_Alloc);
1758 }
1759
1760 if (SkMask::kJustComputeBounds_CreateMode != mode) {
1761 draw_into_mask(*mask, devPath, style);
1762 }
1763
1764 return true;
1765 }
1766