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