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 #define __STDC_LIMIT_MACROS
8
9 #include "SkDraw.h"
10 #include "SkBlitter.h"
11 #include "SkCanvas.h"
12 #include "SkColorPriv.h"
13 #include "SkDevice.h"
14 #include "SkDeviceLooper.h"
15 #include "SkFindAndPlaceGlyph.h"
16 #include "SkFixed.h"
17 #include "SkMaskFilter.h"
18 #include "SkMatrix.h"
19 #include "SkPaint.h"
20 #include "SkPathEffect.h"
21 #include "SkRasterClip.h"
22 #include "SkRasterizer.h"
23 #include "SkRRect.h"
24 #include "SkScan.h"
25 #include "SkShader.h"
26 #include "SkSmallAllocator.h"
27 #include "SkString.h"
28 #include "SkStroke.h"
29 #include "SkStrokeRec.h"
30 #include "SkTemplates.h"
31 #include "SkTextMapStateProc.h"
32 #include "SkTLazy.h"
33 #include "SkUtils.h"
34 #include "SkVertState.h"
35
36 #include "SkBitmapProcShader.h"
37 #include "SkDrawProcs.h"
38 #include "SkMatrixUtils.h"
39
40 //#define TRACE_BITMAP_DRAWS
41
42 // Helper function to fix code gen bug on ARM64.
43 // See SkFindAndPlaceGlyph.h for more details.
FixGCC49Arm64Bug(int v)44 void FixGCC49Arm64Bug(int v) { }
45
46 /** Helper for allocating small blitters on the stack.
47 */
48 class SkAutoBlitterChoose : SkNoncopyable {
49 public:
SkAutoBlitterChoose()50 SkAutoBlitterChoose() {
51 fBlitter = nullptr;
52 }
SkAutoBlitterChoose(const SkPixmap & dst,const SkMatrix & matrix,const SkPaint & paint,bool drawCoverage=false)53 SkAutoBlitterChoose(const SkPixmap& dst, const SkMatrix& matrix,
54 const SkPaint& paint, bool drawCoverage = false) {
55 fBlitter = SkBlitter::Choose(dst, matrix, paint, &fAllocator, drawCoverage);
56 }
57
operator ->()58 SkBlitter* operator->() { return fBlitter; }
get() const59 SkBlitter* get() const { return fBlitter; }
60
choose(const SkPixmap & dst,const SkMatrix & matrix,const SkPaint & paint,bool drawCoverage=false)61 void choose(const SkPixmap& dst, const SkMatrix& matrix,
62 const SkPaint& paint, bool drawCoverage = false) {
63 SkASSERT(!fBlitter);
64 fBlitter = SkBlitter::Choose(dst, matrix, paint, &fAllocator, drawCoverage);
65 }
66
67 private:
68 // Owned by fAllocator, which will handle the delete.
69 SkBlitter* fBlitter;
70 SkTBlitterAllocator fAllocator;
71 };
72 #define SkAutoBlitterChoose(...) SK_REQUIRE_LOCAL_VAR(SkAutoBlitterChoose)
73
74 /**
75 * Since we are providing the storage for the shader (to avoid the perf cost
76 * of calling new) we insist that in our destructor we can account for all
77 * owners of the shader.
78 */
79 class SkAutoBitmapShaderInstall : SkNoncopyable {
80 public:
SkAutoBitmapShaderInstall(const SkBitmap & src,const SkPaint & paint,const SkMatrix * localMatrix=nullptr)81 SkAutoBitmapShaderInstall(const SkBitmap& src, const SkPaint& paint,
82 const SkMatrix* localMatrix = nullptr)
83 : fPaint(paint) /* makes a copy of the paint */ {
84 fPaint.setShader(SkCreateBitmapShader(src, SkShader::kClamp_TileMode,
85 SkShader::kClamp_TileMode,
86 localMatrix, &fAllocator));
87 // we deliberately left the shader with an owner-count of 2
88 SkASSERT(2 == fPaint.getShader()->getRefCnt());
89 }
90
~SkAutoBitmapShaderInstall()91 ~SkAutoBitmapShaderInstall() {
92 // since fAllocator will destroy shader, we insist that owners == 2
93 SkASSERT(2 == fPaint.getShader()->getRefCnt());
94
95 fPaint.setShader(nullptr); // unref the shader by 1
96
97 }
98
99 // return the new paint that has the shader applied
paintWithShader() const100 const SkPaint& paintWithShader() const { return fPaint; }
101
102 private:
103 // copy of caller's paint (which we then modify)
104 SkPaint fPaint;
105 // Stores the shader.
106 SkTBlitterAllocator fAllocator;
107 };
108 #define SkAutoBitmapShaderInstall(...) SK_REQUIRE_LOCAL_VAR(SkAutoBitmapShaderInstall)
109
110 ///////////////////////////////////////////////////////////////////////////////
111
SkDraw()112 SkDraw::SkDraw() {
113 sk_bzero(this, sizeof(*this));
114 }
115
SkDraw(const SkDraw & src)116 SkDraw::SkDraw(const SkDraw& src) {
117 memcpy(this, &src, sizeof(*this));
118 }
119
computeConservativeLocalClipBounds(SkRect * localBounds) const120 bool SkDraw::computeConservativeLocalClipBounds(SkRect* localBounds) const {
121 if (fRC->isEmpty()) {
122 return false;
123 }
124
125 SkMatrix inverse;
126 if (!fMatrix->invert(&inverse)) {
127 return false;
128 }
129
130 SkIRect devBounds = fRC->getBounds();
131 // outset to have slop for antialasing and hairlines
132 devBounds.outset(1, 1);
133 inverse.mapRect(localBounds, SkRect::Make(devBounds));
134 return true;
135 }
136
137 ///////////////////////////////////////////////////////////////////////////////
138
139 typedef void (*BitmapXferProc)(void* pixels, size_t bytes, uint32_t data);
140
D_Clear_BitmapXferProc(void * pixels,size_t bytes,uint32_t)141 static void D_Clear_BitmapXferProc(void* pixels, size_t bytes, uint32_t) {
142 sk_bzero(pixels, bytes);
143 }
144
D_Dst_BitmapXferProc(void *,size_t,uint32_t data)145 static void D_Dst_BitmapXferProc(void*, size_t, uint32_t data) {}
146
D32_Src_BitmapXferProc(void * pixels,size_t bytes,uint32_t data)147 static void D32_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
148 sk_memset32((uint32_t*)pixels, data, SkToInt(bytes >> 2));
149 }
150
D16_Src_BitmapXferProc(void * pixels,size_t bytes,uint32_t data)151 static void D16_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
152 sk_memset16((uint16_t*)pixels, data, SkToInt(bytes >> 1));
153 }
154
DA8_Src_BitmapXferProc(void * pixels,size_t bytes,uint32_t data)155 static void DA8_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
156 memset(pixels, data, bytes);
157 }
158
ChooseBitmapXferProc(const SkPixmap & dst,const SkPaint & paint,uint32_t * data)159 static BitmapXferProc ChooseBitmapXferProc(const SkPixmap& dst, const SkPaint& paint,
160 uint32_t* data) {
161 // todo: we can apply colorfilter up front if no shader, so we wouldn't
162 // need to abort this fastpath
163 if (paint.getShader() || paint.getColorFilter()) {
164 return nullptr;
165 }
166
167 SkXfermode::Mode mode;
168 if (!SkXfermode::AsMode(paint.getXfermode(), &mode)) {
169 return nullptr;
170 }
171
172 SkColor color = paint.getColor();
173
174 // collaps modes based on color...
175 if (SkXfermode::kSrcOver_Mode == mode) {
176 unsigned alpha = SkColorGetA(color);
177 if (0 == alpha) {
178 mode = SkXfermode::kDst_Mode;
179 } else if (0xFF == alpha) {
180 mode = SkXfermode::kSrc_Mode;
181 }
182 }
183
184 switch (mode) {
185 case SkXfermode::kClear_Mode:
186 // SkDebugf("--- D_Clear_BitmapXferProc\n");
187 return D_Clear_BitmapXferProc; // ignore data
188 case SkXfermode::kDst_Mode:
189 // SkDebugf("--- D_Dst_BitmapXferProc\n");
190 return D_Dst_BitmapXferProc; // ignore data
191 case SkXfermode::kSrc_Mode: {
192 /*
193 should I worry about dithering for the lower depths?
194 */
195 SkPMColor pmc = SkPreMultiplyColor(color);
196 switch (dst.colorType()) {
197 case kN32_SkColorType:
198 if (data) {
199 *data = pmc;
200 }
201 // SkDebugf("--- D32_Src_BitmapXferProc\n");
202 return D32_Src_BitmapXferProc;
203 case kRGB_565_SkColorType:
204 if (data) {
205 *data = SkPixel32ToPixel16(pmc);
206 }
207 // SkDebugf("--- D16_Src_BitmapXferProc\n");
208 return D16_Src_BitmapXferProc;
209 case kAlpha_8_SkColorType:
210 if (data) {
211 *data = SkGetPackedA32(pmc);
212 }
213 // SkDebugf("--- DA8_Src_BitmapXferProc\n");
214 return DA8_Src_BitmapXferProc;
215 default:
216 break;
217 }
218 break;
219 }
220 default:
221 break;
222 }
223 return nullptr;
224 }
225
CallBitmapXferProc(const SkPixmap & dst,const SkIRect & rect,BitmapXferProc proc,uint32_t procData)226 static void CallBitmapXferProc(const SkPixmap& dst, const SkIRect& rect, BitmapXferProc proc,
227 uint32_t procData) {
228 int shiftPerPixel;
229 switch (dst.colorType()) {
230 case kN32_SkColorType:
231 shiftPerPixel = 2;
232 break;
233 case kRGB_565_SkColorType:
234 shiftPerPixel = 1;
235 break;
236 case kAlpha_8_SkColorType:
237 shiftPerPixel = 0;
238 break;
239 default:
240 SkDEBUGFAIL("Can't use xferproc on this config");
241 return;
242 }
243
244 uint8_t* pixels = (uint8_t*)dst.writable_addr();
245 SkASSERT(pixels);
246 const size_t rowBytes = dst.rowBytes();
247 const int widthBytes = rect.width() << shiftPerPixel;
248
249 // skip down to the first scanline and X position
250 pixels += rect.fTop * rowBytes + (rect.fLeft << shiftPerPixel);
251 for (int scans = rect.height() - 1; scans >= 0; --scans) {
252 proc(pixels, widthBytes, procData);
253 pixels += rowBytes;
254 }
255 }
256
drawPaint(const SkPaint & paint) const257 void SkDraw::drawPaint(const SkPaint& paint) const {
258 SkDEBUGCODE(this->validate();)
259
260 if (fRC->isEmpty()) {
261 return;
262 }
263
264 SkIRect devRect;
265 devRect.set(0, 0, fDst.width(), fDst.height());
266
267 if (fRC->isBW()) {
268 /* If we don't have a shader (i.e. we're just a solid color) we may
269 be faster to operate directly on the device bitmap, rather than invoking
270 a blitter. Esp. true for xfermodes, which require a colorshader to be
271 present, which is just redundant work. Since we're drawing everywhere
272 in the clip, we don't have to worry about antialiasing.
273 */
274 uint32_t procData = 0; // to avoid the warning
275 BitmapXferProc proc = ChooseBitmapXferProc(fDst, paint, &procData);
276 if (proc) {
277 if (D_Dst_BitmapXferProc == proc) { // nothing to do
278 return;
279 }
280
281 SkRegion::Iterator iter(fRC->bwRgn());
282 while (!iter.done()) {
283 CallBitmapXferProc(fDst, iter.rect(), proc, procData);
284 iter.next();
285 }
286 return;
287 }
288 }
289
290 // normal case: use a blitter
291 SkAutoBlitterChoose blitter(fDst, *fMatrix, paint);
292 SkScan::FillIRect(devRect, *fRC, blitter.get());
293 }
294
295 ///////////////////////////////////////////////////////////////////////////////
296
297 struct PtProcRec {
298 SkCanvas::PointMode fMode;
299 const SkPaint* fPaint;
300 const SkRegion* fClip;
301 const SkRasterClip* fRC;
302
303 // computed values
304 SkFixed fRadius;
305
306 typedef void (*Proc)(const PtProcRec&, const SkPoint devPts[], int count,
307 SkBlitter*);
308
309 bool init(SkCanvas::PointMode, const SkPaint&, const SkMatrix* matrix,
310 const SkRasterClip*);
311 Proc chooseProc(SkBlitter** blitter);
312
313 private:
314 SkAAClipBlitterWrapper fWrapper;
315 };
316
bw_pt_rect_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)317 static void bw_pt_rect_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
318 int count, SkBlitter* blitter) {
319 SkASSERT(rec.fClip->isRect());
320 const SkIRect& r = rec.fClip->getBounds();
321
322 for (int i = 0; i < count; i++) {
323 int x = SkScalarFloorToInt(devPts[i].fX);
324 int y = SkScalarFloorToInt(devPts[i].fY);
325 if (r.contains(x, y)) {
326 blitter->blitH(x, y, 1);
327 }
328 }
329 }
330
bw_pt_rect_16_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)331 static void bw_pt_rect_16_hair_proc(const PtProcRec& rec,
332 const SkPoint devPts[], int count,
333 SkBlitter* blitter) {
334 SkASSERT(rec.fRC->isRect());
335 const SkIRect& r = rec.fRC->getBounds();
336 uint32_t value;
337 const SkPixmap* dst = blitter->justAnOpaqueColor(&value);
338 SkASSERT(dst);
339
340 uint16_t* addr = dst->writable_addr16(0, 0);
341 size_t rb = dst->rowBytes();
342
343 for (int i = 0; i < count; i++) {
344 int x = SkScalarFloorToInt(devPts[i].fX);
345 int y = SkScalarFloorToInt(devPts[i].fY);
346 if (r.contains(x, y)) {
347 ((uint16_t*)((char*)addr + y * rb))[x] = SkToU16(value);
348 }
349 }
350 }
351
bw_pt_rect_32_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)352 static void bw_pt_rect_32_hair_proc(const PtProcRec& rec,
353 const SkPoint devPts[], int count,
354 SkBlitter* blitter) {
355 SkASSERT(rec.fRC->isRect());
356 const SkIRect& r = rec.fRC->getBounds();
357 uint32_t value;
358 const SkPixmap* dst = blitter->justAnOpaqueColor(&value);
359 SkASSERT(dst);
360
361 SkPMColor* addr = dst->writable_addr32(0, 0);
362 size_t rb = dst->rowBytes();
363
364 for (int i = 0; i < count; i++) {
365 int x = SkScalarFloorToInt(devPts[i].fX);
366 int y = SkScalarFloorToInt(devPts[i].fY);
367 if (r.contains(x, y)) {
368 ((SkPMColor*)((char*)addr + y * rb))[x] = value;
369 }
370 }
371 }
372
bw_pt_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)373 static void bw_pt_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
374 int count, SkBlitter* blitter) {
375 for (int i = 0; i < count; i++) {
376 int x = SkScalarFloorToInt(devPts[i].fX);
377 int y = SkScalarFloorToInt(devPts[i].fY);
378 if (rec.fClip->contains(x, y)) {
379 blitter->blitH(x, y, 1);
380 }
381 }
382 }
383
bw_line_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)384 static void bw_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
385 int count, SkBlitter* blitter) {
386 for (int i = 0; i < count; i += 2) {
387 SkScan::HairLine(&devPts[i], 2, *rec.fRC, blitter);
388 }
389 }
390
bw_poly_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)391 static void bw_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
392 int count, SkBlitter* blitter) {
393 SkScan::HairLine(devPts, count, *rec.fRC, blitter);
394 }
395
396 // aa versions
397
aa_line_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)398 static void aa_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
399 int count, SkBlitter* blitter) {
400 for (int i = 0; i < count; i += 2) {
401 SkScan::AntiHairLine(&devPts[i], 2, *rec.fRC, blitter);
402 }
403 }
404
aa_poly_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)405 static void aa_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
406 int count, SkBlitter* blitter) {
407 SkScan::AntiHairLine(devPts, count, *rec.fRC, blitter);
408 }
409
410 // square procs (strokeWidth > 0 but matrix is square-scale (sx == sy)
411
bw_square_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)412 static void bw_square_proc(const PtProcRec& rec, const SkPoint devPts[],
413 int count, SkBlitter* blitter) {
414 const SkFixed radius = rec.fRadius;
415 for (int i = 0; i < count; i++) {
416 SkFixed x = SkScalarToFixed(devPts[i].fX);
417 SkFixed y = SkScalarToFixed(devPts[i].fY);
418
419 SkXRect r;
420 r.fLeft = x - radius;
421 r.fTop = y - radius;
422 r.fRight = x + radius;
423 r.fBottom = y + radius;
424
425 SkScan::FillXRect(r, *rec.fRC, blitter);
426 }
427 }
428
aa_square_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)429 static void aa_square_proc(const PtProcRec& rec, const SkPoint devPts[],
430 int count, SkBlitter* blitter) {
431 const SkFixed radius = rec.fRadius;
432 for (int i = 0; i < count; i++) {
433 SkFixed x = SkScalarToFixed(devPts[i].fX);
434 SkFixed y = SkScalarToFixed(devPts[i].fY);
435
436 SkXRect r;
437 r.fLeft = x - radius;
438 r.fTop = y - radius;
439 r.fRight = x + radius;
440 r.fBottom = y + radius;
441
442 SkScan::AntiFillXRect(r, *rec.fRC, blitter);
443 }
444 }
445
446 // 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)447 bool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint,
448 const SkMatrix* matrix, const SkRasterClip* rc) {
449 if ((unsigned)mode > (unsigned)SkCanvas::kPolygon_PointMode) {
450 return false;
451 }
452
453 if (paint.getPathEffect()) {
454 return false;
455 }
456 SkScalar width = paint.getStrokeWidth();
457 if (0 == width) {
458 fMode = mode;
459 fPaint = &paint;
460 fClip = nullptr;
461 fRC = rc;
462 fRadius = SK_FixedHalf;
463 return true;
464 }
465 if (paint.getStrokeCap() != SkPaint::kRound_Cap &&
466 matrix->isScaleTranslate() && SkCanvas::kPoints_PointMode == mode) {
467 SkScalar sx = matrix->get(SkMatrix::kMScaleX);
468 SkScalar sy = matrix->get(SkMatrix::kMScaleY);
469 if (SkScalarNearlyZero(sx - sy)) {
470 if (sx < 0) {
471 sx = -sx;
472 }
473
474 fMode = mode;
475 fPaint = &paint;
476 fClip = nullptr;
477 fRC = rc;
478 fRadius = SkScalarToFixed(SkScalarMul(width, sx)) >> 1;
479 return true;
480 }
481 }
482 return false;
483 }
484
chooseProc(SkBlitter ** blitterPtr)485 PtProcRec::Proc PtProcRec::chooseProc(SkBlitter** blitterPtr) {
486 Proc proc = nullptr;
487
488 SkBlitter* blitter = *blitterPtr;
489 if (fRC->isBW()) {
490 fClip = &fRC->bwRgn();
491 } else {
492 fWrapper.init(*fRC, blitter);
493 fClip = &fWrapper.getRgn();
494 blitter = fWrapper.getBlitter();
495 *blitterPtr = blitter;
496 }
497
498 // for our arrays
499 SkASSERT(0 == SkCanvas::kPoints_PointMode);
500 SkASSERT(1 == SkCanvas::kLines_PointMode);
501 SkASSERT(2 == SkCanvas::kPolygon_PointMode);
502 SkASSERT((unsigned)fMode <= (unsigned)SkCanvas::kPolygon_PointMode);
503
504 if (fPaint->isAntiAlias()) {
505 if (0 == fPaint->getStrokeWidth()) {
506 static const Proc gAAProcs[] = {
507 aa_square_proc, aa_line_hair_proc, aa_poly_hair_proc
508 };
509 proc = gAAProcs[fMode];
510 } else if (fPaint->getStrokeCap() != SkPaint::kRound_Cap) {
511 SkASSERT(SkCanvas::kPoints_PointMode == fMode);
512 proc = aa_square_proc;
513 }
514 } else { // BW
515 if (fRadius <= SK_FixedHalf) { // small radii and hairline
516 if (SkCanvas::kPoints_PointMode == fMode && fClip->isRect()) {
517 uint32_t value;
518 const SkPixmap* bm = blitter->justAnOpaqueColor(&value);
519 if (bm && kRGB_565_SkColorType == bm->colorType()) {
520 proc = bw_pt_rect_16_hair_proc;
521 } else if (bm && kN32_SkColorType == bm->colorType()) {
522 proc = bw_pt_rect_32_hair_proc;
523 } else {
524 proc = bw_pt_rect_hair_proc;
525 }
526 } else {
527 static Proc gBWProcs[] = {
528 bw_pt_hair_proc, bw_line_hair_proc, bw_poly_hair_proc
529 };
530 proc = gBWProcs[fMode];
531 }
532 } else {
533 proc = bw_square_proc;
534 }
535 }
536 return proc;
537 }
538
539 // each of these costs 8-bytes of stack space, so don't make it too large
540 // must be even for lines/polygon to work
541 #define MAX_DEV_PTS 32
542
drawPoints(SkCanvas::PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint,bool forceUseDevice) const543 void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count,
544 const SkPoint pts[], const SkPaint& paint,
545 bool forceUseDevice) const {
546 // if we're in lines mode, force count to be even
547 if (SkCanvas::kLines_PointMode == mode) {
548 count &= ~(size_t)1;
549 }
550
551 if ((long)count <= 0) {
552 return;
553 }
554
555 SkASSERT(pts != nullptr);
556 SkDEBUGCODE(this->validate();)
557
558 // nothing to draw
559 if (fRC->isEmpty()) {
560 return;
561 }
562
563 PtProcRec rec;
564 if (!forceUseDevice && rec.init(mode, paint, fMatrix, fRC)) {
565 SkAutoBlitterChoose blitter(fDst, *fMatrix, paint);
566
567 SkPoint devPts[MAX_DEV_PTS];
568 const SkMatrix* matrix = fMatrix;
569 SkBlitter* bltr = blitter.get();
570 PtProcRec::Proc proc = rec.chooseProc(&bltr);
571 // we have to back up subsequent passes if we're in polygon mode
572 const size_t backup = (SkCanvas::kPolygon_PointMode == mode);
573
574 do {
575 int n = SkToInt(count);
576 if (n > MAX_DEV_PTS) {
577 n = MAX_DEV_PTS;
578 }
579 matrix->mapPoints(devPts, pts, n);
580 proc(rec, devPts, n, bltr);
581 pts += n - backup;
582 SkASSERT(SkToInt(count) >= n);
583 count -= n;
584 if (count > 0) {
585 count += backup;
586 }
587 } while (count != 0);
588 } else {
589 switch (mode) {
590 case SkCanvas::kPoints_PointMode: {
591 // temporarily mark the paint as filling.
592 SkPaint newPaint(paint);
593 newPaint.setStyle(SkPaint::kFill_Style);
594
595 SkScalar width = newPaint.getStrokeWidth();
596 SkScalar radius = SkScalarHalf(width);
597
598 if (newPaint.getStrokeCap() == SkPaint::kRound_Cap) {
599 SkPath path;
600 SkMatrix preMatrix;
601
602 path.addCircle(0, 0, radius);
603 for (size_t i = 0; i < count; i++) {
604 preMatrix.setTranslate(pts[i].fX, pts[i].fY);
605 // pass true for the last point, since we can modify
606 // then path then
607 path.setIsVolatile((count-1) == i);
608 if (fDevice) {
609 fDevice->drawPath(*this, path, newPaint, &preMatrix,
610 (count-1) == i);
611 } else {
612 this->drawPath(path, newPaint, &preMatrix,
613 (count-1) == i);
614 }
615 }
616 } else {
617 SkRect r;
618
619 for (size_t i = 0; i < count; i++) {
620 r.fLeft = pts[i].fX - radius;
621 r.fTop = pts[i].fY - radius;
622 r.fRight = r.fLeft + width;
623 r.fBottom = r.fTop + width;
624 if (fDevice) {
625 fDevice->drawRect(*this, r, newPaint);
626 } else {
627 this->drawRect(r, newPaint);
628 }
629 }
630 }
631 break;
632 }
633 case SkCanvas::kLines_PointMode:
634 if (2 == count && paint.getPathEffect()) {
635 // most likely a dashed line - see if it is one of the ones
636 // we can accelerate
637 SkStrokeRec rec(paint);
638 SkPathEffect::PointData pointData;
639
640 SkPath path;
641 path.moveTo(pts[0]);
642 path.lineTo(pts[1]);
643
644 SkRect cullRect = SkRect::Make(fRC->getBounds());
645
646 if (paint.getPathEffect()->asPoints(&pointData, path, rec,
647 *fMatrix, &cullRect)) {
648 // 'asPoints' managed to find some fast path
649
650 SkPaint newP(paint);
651 newP.setPathEffect(nullptr);
652 newP.setStyle(SkPaint::kFill_Style);
653
654 if (!pointData.fFirst.isEmpty()) {
655 if (fDevice) {
656 fDevice->drawPath(*this, pointData.fFirst, newP);
657 } else {
658 this->drawPath(pointData.fFirst, newP);
659 }
660 }
661
662 if (!pointData.fLast.isEmpty()) {
663 if (fDevice) {
664 fDevice->drawPath(*this, pointData.fLast, newP);
665 } else {
666 this->drawPath(pointData.fLast, newP);
667 }
668 }
669
670 if (pointData.fSize.fX == pointData.fSize.fY) {
671 // The rest of the dashed line can just be drawn as points
672 SkASSERT(pointData.fSize.fX == SkScalarHalf(newP.getStrokeWidth()));
673
674 if (SkPathEffect::PointData::kCircles_PointFlag & pointData.fFlags) {
675 newP.setStrokeCap(SkPaint::kRound_Cap);
676 } else {
677 newP.setStrokeCap(SkPaint::kButt_Cap);
678 }
679
680 if (fDevice) {
681 fDevice->drawPoints(*this,
682 SkCanvas::kPoints_PointMode,
683 pointData.fNumPoints,
684 pointData.fPoints,
685 newP);
686 } else {
687 this->drawPoints(SkCanvas::kPoints_PointMode,
688 pointData.fNumPoints,
689 pointData.fPoints,
690 newP,
691 forceUseDevice);
692 }
693 break;
694 } else {
695 // The rest of the dashed line must be drawn as rects
696 SkASSERT(!(SkPathEffect::PointData::kCircles_PointFlag &
697 pointData.fFlags));
698
699 SkRect r;
700
701 for (int i = 0; i < pointData.fNumPoints; ++i) {
702 r.set(pointData.fPoints[i].fX - pointData.fSize.fX,
703 pointData.fPoints[i].fY - pointData.fSize.fY,
704 pointData.fPoints[i].fX + pointData.fSize.fX,
705 pointData.fPoints[i].fY + pointData.fSize.fY);
706 if (fDevice) {
707 fDevice->drawRect(*this, r, newP);
708 } else {
709 this->drawRect(r, newP);
710 }
711 }
712 }
713
714 break;
715 }
716 }
717 // couldn't take fast path so fall through!
718 case SkCanvas::kPolygon_PointMode: {
719 count -= 1;
720 SkPath path;
721 SkPaint p(paint);
722 p.setStyle(SkPaint::kStroke_Style);
723 size_t inc = (SkCanvas::kLines_PointMode == mode) ? 2 : 1;
724 path.setIsVolatile(true);
725 for (size_t i = 0; i < count; i += inc) {
726 path.moveTo(pts[i]);
727 path.lineTo(pts[i+1]);
728 if (fDevice) {
729 fDevice->drawPath(*this, path, p, nullptr, true);
730 } else {
731 this->drawPath(path, p, nullptr, true);
732 }
733 path.rewind();
734 }
735 break;
736 }
737 }
738 }
739 }
740
compute_stroke_size(const SkPaint & paint,const SkMatrix & matrix)741 static inline SkPoint compute_stroke_size(const SkPaint& paint, const SkMatrix& matrix) {
742 SkASSERT(matrix.rectStaysRect());
743 SkASSERT(SkPaint::kFill_Style != paint.getStyle());
744
745 SkVector size;
746 SkPoint pt = { paint.getStrokeWidth(), paint.getStrokeWidth() };
747 matrix.mapVectors(&size, &pt, 1);
748 return SkPoint::Make(SkScalarAbs(size.fX), SkScalarAbs(size.fY));
749 }
750
easy_rect_join(const SkPaint & paint,const SkMatrix & matrix,SkPoint * strokeSize)751 static bool easy_rect_join(const SkPaint& paint, const SkMatrix& matrix,
752 SkPoint* strokeSize) {
753 if (SkPaint::kMiter_Join != paint.getStrokeJoin() ||
754 paint.getStrokeMiter() < SK_ScalarSqrt2) {
755 return false;
756 }
757
758 *strokeSize = compute_stroke_size(paint, matrix);
759 return true;
760 }
761
ComputeRectType(const SkPaint & paint,const SkMatrix & matrix,SkPoint * strokeSize)762 SkDraw::RectType SkDraw::ComputeRectType(const SkPaint& paint,
763 const SkMatrix& matrix,
764 SkPoint* strokeSize) {
765 RectType rtype;
766 const SkScalar width = paint.getStrokeWidth();
767 const bool zeroWidth = (0 == width);
768 SkPaint::Style style = paint.getStyle();
769
770 if ((SkPaint::kStrokeAndFill_Style == style) && zeroWidth) {
771 style = SkPaint::kFill_Style;
772 }
773
774 if (paint.getPathEffect() || paint.getMaskFilter() ||
775 paint.getRasterizer() || !matrix.rectStaysRect() ||
776 SkPaint::kStrokeAndFill_Style == style) {
777 rtype = kPath_RectType;
778 } else if (SkPaint::kFill_Style == style) {
779 rtype = kFill_RectType;
780 } else if (zeroWidth) {
781 rtype = kHair_RectType;
782 } else if (easy_rect_join(paint, matrix, strokeSize)) {
783 rtype = kStroke_RectType;
784 } else {
785 rtype = kPath_RectType;
786 }
787 return rtype;
788 }
789
rect_points(const SkRect & r)790 static const SkPoint* rect_points(const SkRect& r) {
791 return SkTCast<const SkPoint*>(&r);
792 }
793
rect_points(SkRect & r)794 static SkPoint* rect_points(SkRect& r) {
795 return SkTCast<SkPoint*>(&r);
796 }
797
drawRect(const SkRect & prePaintRect,const SkPaint & paint,const SkMatrix * paintMatrix,const SkRect * postPaintRect) const798 void SkDraw::drawRect(const SkRect& prePaintRect, const SkPaint& paint,
799 const SkMatrix* paintMatrix, const SkRect* postPaintRect) const {
800 SkDEBUGCODE(this->validate();)
801
802 // nothing to draw
803 if (fRC->isEmpty()) {
804 return;
805 }
806
807 const SkMatrix* matrix;
808 SkMatrix combinedMatrixStorage;
809 if (paintMatrix) {
810 SkASSERT(postPaintRect);
811 combinedMatrixStorage.setConcat(*fMatrix, *paintMatrix);
812 matrix = &combinedMatrixStorage;
813 } else {
814 SkASSERT(!postPaintRect);
815 matrix = fMatrix;
816 }
817
818 SkPoint strokeSize;
819 RectType rtype = ComputeRectType(paint, *fMatrix, &strokeSize);
820
821 if (kPath_RectType == rtype) {
822 SkDraw draw(*this);
823 if (paintMatrix) {
824 draw.fMatrix = matrix;
825 }
826 SkPath tmp;
827 tmp.addRect(prePaintRect);
828 tmp.setFillType(SkPath::kWinding_FillType);
829 draw.drawPath(tmp, paint, nullptr, true);
830 return;
831 }
832
833 SkRect devRect;
834 const SkRect& paintRect = paintMatrix ? *postPaintRect : prePaintRect;
835 // skip the paintMatrix when transforming the rect by the CTM
836 fMatrix->mapPoints(rect_points(devRect), rect_points(paintRect), 2);
837 devRect.sort();
838
839 // look for the quick exit, before we build a blitter
840 SkRect bbox = devRect;
841 if (paint.getStyle() != SkPaint::kFill_Style) {
842 // extra space for hairlines
843 if (paint.getStrokeWidth() == 0) {
844 bbox.outset(1, 1);
845 } else {
846 // For kStroke_RectType, strokeSize is already computed.
847 const SkPoint& ssize = (kStroke_RectType == rtype)
848 ? strokeSize
849 : compute_stroke_size(paint, *fMatrix);
850 bbox.outset(SkScalarHalf(ssize.x()), SkScalarHalf(ssize.y()));
851 }
852 }
853
854 SkIRect ir = bbox.roundOut();
855 if (fRC->quickReject(ir)) {
856 return;
857 }
858
859 SkDeviceLooper looper(fDst, *fRC, ir, paint.isAntiAlias());
860 while (looper.next()) {
861 SkRect localDevRect;
862 looper.mapRect(&localDevRect, devRect);
863 SkMatrix localMatrix;
864 looper.mapMatrix(&localMatrix, *matrix);
865
866 SkAutoBlitterChoose blitterStorage(looper.getPixmap(), localMatrix, paint);
867 const SkRasterClip& clip = looper.getRC();
868 SkBlitter* blitter = blitterStorage.get();
869
870 // we want to "fill" if we are kFill or kStrokeAndFill, since in the latter
871 // case we are also hairline (if we've gotten to here), which devolves to
872 // effectively just kFill
873 switch (rtype) {
874 case kFill_RectType:
875 if (paint.isAntiAlias()) {
876 SkScan::AntiFillRect(localDevRect, clip, blitter);
877 } else {
878 SkScan::FillRect(localDevRect, clip, blitter);
879 }
880 break;
881 case kStroke_RectType:
882 if (paint.isAntiAlias()) {
883 SkScan::AntiFrameRect(localDevRect, strokeSize, clip, blitter);
884 } else {
885 SkScan::FrameRect(localDevRect, strokeSize, clip, blitter);
886 }
887 break;
888 case kHair_RectType:
889 if (paint.isAntiAlias()) {
890 SkScan::AntiHairRect(localDevRect, clip, blitter);
891 } else {
892 SkScan::HairRect(localDevRect, clip, blitter);
893 }
894 break;
895 default:
896 SkDEBUGFAIL("bad rtype");
897 }
898 }
899 }
900
drawDevMask(const SkMask & srcM,const SkPaint & paint) const901 void SkDraw::drawDevMask(const SkMask& srcM, const SkPaint& paint) const {
902 if (srcM.fBounds.isEmpty()) {
903 return;
904 }
905
906 const SkMask* mask = &srcM;
907
908 SkMask dstM;
909 if (paint.getMaskFilter() &&
910 paint.getMaskFilter()->filterMask(&dstM, srcM, *fMatrix, nullptr)) {
911 mask = &dstM;
912 }
913 SkAutoMaskFreeImage ami(dstM.fImage);
914
915 SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint);
916 SkBlitter* blitter = blitterChooser.get();
917
918 SkAAClipBlitterWrapper wrapper;
919 const SkRegion* clipRgn;
920
921 if (fRC->isBW()) {
922 clipRgn = &fRC->bwRgn();
923 } else {
924 wrapper.init(*fRC, blitter);
925 clipRgn = &wrapper.getRgn();
926 blitter = wrapper.getBlitter();
927 }
928 blitter->blitMaskRegion(*mask, *clipRgn);
929 }
930
fast_len(const SkVector & vec)931 static SkScalar fast_len(const SkVector& vec) {
932 SkScalar x = SkScalarAbs(vec.fX);
933 SkScalar y = SkScalarAbs(vec.fY);
934 if (x < y) {
935 SkTSwap(x, y);
936 }
937 return x + SkScalarHalf(y);
938 }
939
SkDrawTreatAAStrokeAsHairline(SkScalar strokeWidth,const SkMatrix & matrix,SkScalar * coverage)940 bool SkDrawTreatAAStrokeAsHairline(SkScalar strokeWidth, const SkMatrix& matrix,
941 SkScalar* coverage) {
942 SkASSERT(strokeWidth > 0);
943 // We need to try to fake a thick-stroke with a modulated hairline.
944
945 if (matrix.hasPerspective()) {
946 return false;
947 }
948
949 SkVector src[2], dst[2];
950 src[0].set(strokeWidth, 0);
951 src[1].set(0, strokeWidth);
952 matrix.mapVectors(dst, src, 2);
953 SkScalar len0 = fast_len(dst[0]);
954 SkScalar len1 = fast_len(dst[1]);
955 if (len0 <= SK_Scalar1 && len1 <= SK_Scalar1) {
956 if (coverage) {
957 *coverage = SkScalarAve(len0, len1);
958 }
959 return true;
960 }
961 return false;
962 }
963
drawRRect(const SkRRect & rrect,const SkPaint & paint) const964 void SkDraw::drawRRect(const SkRRect& rrect, const SkPaint& paint) const {
965 SkDEBUGCODE(this->validate());
966
967 if (fRC->isEmpty()) {
968 return;
969 }
970
971 {
972 // TODO: Investigate optimizing these options. They are in the same
973 // order as SkDraw::drawPath, which handles each case. It may be
974 // that there is no way to optimize for these using the SkRRect path.
975 SkScalar coverage;
976 if (SkDrawTreatAsHairline(paint, *fMatrix, &coverage)) {
977 goto DRAW_PATH;
978 }
979
980 if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
981 goto DRAW_PATH;
982 }
983
984 if (paint.getRasterizer()) {
985 goto DRAW_PATH;
986 }
987 }
988
989 if (paint.getMaskFilter()) {
990 // Transform the rrect into device space.
991 SkRRect devRRect;
992 if (rrect.transform(*fMatrix, &devRRect)) {
993 SkAutoBlitterChoose blitter(fDst, *fMatrix, paint);
994 if (paint.getMaskFilter()->filterRRect(devRRect, *fMatrix, *fRC, blitter.get(),
995 SkPaint::kFill_Style)) {
996 return; // filterRRect() called the blitter, so we're done
997 }
998 }
999 }
1000
1001 DRAW_PATH:
1002 // Now fall back to the default case of using a path.
1003 SkPath path;
1004 path.addRRect(rrect);
1005 this->drawPath(path, paint, nullptr, true);
1006 }
1007
ComputeResScaleForStroking(const SkMatrix & matrix)1008 SkScalar SkDraw::ComputeResScaleForStroking(const SkMatrix& matrix) {
1009 if (!matrix.hasPerspective()) {
1010 SkScalar sx = SkPoint::Length(matrix[SkMatrix::kMScaleX], matrix[SkMatrix::kMSkewY]);
1011 SkScalar sy = SkPoint::Length(matrix[SkMatrix::kMSkewX], matrix[SkMatrix::kMScaleY]);
1012 if (SkScalarsAreFinite(sx, sy)) {
1013 return SkTMax(sx, sy);
1014 }
1015 }
1016 return 1;
1017 }
1018
drawPath(const SkPath & origSrcPath,const SkPaint & origPaint,const SkMatrix * prePathMatrix,bool pathIsMutable,bool drawCoverage,SkBlitter * customBlitter) const1019 void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint,
1020 const SkMatrix* prePathMatrix, bool pathIsMutable,
1021 bool drawCoverage, SkBlitter* customBlitter) const {
1022 SkDEBUGCODE(this->validate();)
1023
1024 // nothing to draw
1025 if (fRC->isEmpty()) {
1026 return;
1027 }
1028
1029 SkPath* pathPtr = (SkPath*)&origSrcPath;
1030 bool doFill = true;
1031 SkPath tmpPath;
1032 SkMatrix tmpMatrix;
1033 const SkMatrix* matrix = fMatrix;
1034 tmpPath.setIsVolatile(true);
1035
1036 if (prePathMatrix) {
1037 if (origPaint.getPathEffect() || origPaint.getStyle() != SkPaint::kFill_Style ||
1038 origPaint.getRasterizer()) {
1039 SkPath* result = pathPtr;
1040
1041 if (!pathIsMutable) {
1042 result = &tmpPath;
1043 pathIsMutable = true;
1044 }
1045 pathPtr->transform(*prePathMatrix, result);
1046 pathPtr = result;
1047 } else {
1048 tmpMatrix.setConcat(*matrix, *prePathMatrix);
1049 matrix = &tmpMatrix;
1050 }
1051 }
1052 // at this point we're done with prePathMatrix
1053 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
1054
1055 SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
1056
1057 {
1058 SkScalar coverage;
1059 if (SkDrawTreatAsHairline(origPaint, *matrix, &coverage)) {
1060 if (SK_Scalar1 == coverage) {
1061 paint.writable()->setStrokeWidth(0);
1062 } else if (SkXfermode::SupportsCoverageAsAlpha(origPaint.getXfermode())) {
1063 U8CPU newAlpha;
1064 #if 0
1065 newAlpha = SkToU8(SkScalarRoundToInt(coverage *
1066 origPaint.getAlpha()));
1067 #else
1068 // this is the old technique, which we preserve for now so
1069 // we don't change previous results (testing)
1070 // the new way seems fine, its just (a tiny bit) different
1071 int scale = (int)SkScalarMul(coverage, 256);
1072 newAlpha = origPaint.getAlpha() * scale >> 8;
1073 #endif
1074 SkPaint* writablePaint = paint.writable();
1075 writablePaint->setStrokeWidth(0);
1076 writablePaint->setAlpha(newAlpha);
1077 }
1078 }
1079 }
1080
1081 if (paint->getPathEffect() || paint->getStyle() != SkPaint::kFill_Style) {
1082 SkRect cullRect;
1083 const SkRect* cullRectPtr = nullptr;
1084 if (this->computeConservativeLocalClipBounds(&cullRect)) {
1085 cullRectPtr = &cullRect;
1086 }
1087 doFill = paint->getFillPath(*pathPtr, &tmpPath, cullRectPtr,
1088 ComputeResScaleForStroking(*fMatrix));
1089 pathPtr = &tmpPath;
1090 }
1091
1092 if (paint->getRasterizer()) {
1093 SkMask mask;
1094 if (paint->getRasterizer()->rasterize(*pathPtr, *matrix,
1095 &fRC->getBounds(), paint->getMaskFilter(), &mask,
1096 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
1097 this->drawDevMask(mask, *paint);
1098 SkMask::FreeImage(mask.fImage);
1099 }
1100 return;
1101 }
1102
1103 // avoid possibly allocating a new path in transform if we can
1104 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
1105
1106 // transform the path into device space
1107 pathPtr->transform(*matrix, devPathPtr);
1108
1109 SkBlitter* blitter = nullptr;
1110 SkAutoBlitterChoose blitterStorage;
1111 if (nullptr == customBlitter) {
1112 blitterStorage.choose(fDst, *fMatrix, *paint, drawCoverage);
1113 blitter = blitterStorage.get();
1114 } else {
1115 blitter = customBlitter;
1116 }
1117
1118 if (paint->getMaskFilter()) {
1119 SkPaint::Style style = doFill ? SkPaint::kFill_Style :
1120 SkPaint::kStroke_Style;
1121 if (paint->getMaskFilter()->filterPath(*devPathPtr, *fMatrix, *fRC, blitter, style)) {
1122 return; // filterPath() called the blitter, so we're done
1123 }
1124 }
1125
1126 void (*proc)(const SkPath&, const SkRasterClip&, SkBlitter*);
1127 if (doFill) {
1128 if (paint->isAntiAlias()) {
1129 proc = SkScan::AntiFillPath;
1130 } else {
1131 proc = SkScan::FillPath;
1132 }
1133 } else { // hairline
1134 if (paint->isAntiAlias()) {
1135 switch (paint->getStrokeCap()) {
1136 case SkPaint::kButt_Cap:
1137 proc = SkScan::AntiHairPath;
1138 break;
1139 case SkPaint::kSquare_Cap:
1140 proc = SkScan::AntiHairSquarePath;
1141 break;
1142 case SkPaint::kRound_Cap:
1143 proc = SkScan::AntiHairRoundPath;
1144 break;
1145 default:
1146 proc SK_INIT_TO_AVOID_WARNING;
1147 SkDEBUGFAIL("unknown paint cap type");
1148 }
1149 } else {
1150 switch (paint->getStrokeCap()) {
1151 case SkPaint::kButt_Cap:
1152 proc = SkScan::HairPath;
1153 break;
1154 case SkPaint::kSquare_Cap:
1155 proc = SkScan::HairSquarePath;
1156 break;
1157 case SkPaint::kRound_Cap:
1158 proc = SkScan::HairRoundPath;
1159 break;
1160 default:
1161 proc SK_INIT_TO_AVOID_WARNING;
1162 SkDEBUGFAIL("unknown paint cap type");
1163 }
1164 }
1165 }
1166 proc(*devPathPtr, *fRC, blitter);
1167 }
1168
drawBitmapAsMask(const SkBitmap & bitmap,const SkPaint & paint) const1169 void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap,
1170 const SkPaint& paint) const {
1171 SkASSERT(bitmap.colorType() == kAlpha_8_SkColorType);
1172
1173 if (SkTreatAsSprite(*fMatrix, bitmap.dimensions(), paint)) {
1174 int ix = SkScalarRoundToInt(fMatrix->getTranslateX());
1175 int iy = SkScalarRoundToInt(fMatrix->getTranslateY());
1176
1177 SkAutoPixmapUnlock result;
1178 if (!bitmap.requestLock(&result)) {
1179 return;
1180 }
1181 const SkPixmap& pmap = result.pixmap();
1182 SkMask mask;
1183 mask.fBounds.set(ix, iy, ix + pmap.width(), iy + pmap.height());
1184 mask.fFormat = SkMask::kA8_Format;
1185 mask.fRowBytes = SkToU32(pmap.rowBytes());
1186 // fImage is typed as writable, but in this case it is used read-only
1187 mask.fImage = (uint8_t*)pmap.addr8(0, 0);
1188
1189 this->drawDevMask(mask, paint);
1190 } else { // need to xform the bitmap first
1191 SkRect r;
1192 SkMask mask;
1193
1194 r.set(0, 0,
1195 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
1196 fMatrix->mapRect(&r);
1197 r.round(&mask.fBounds);
1198
1199 // set the mask's bounds to the transformed bitmap-bounds,
1200 // clipped to the actual device
1201 {
1202 SkIRect devBounds;
1203 devBounds.set(0, 0, fDst.width(), fDst.height());
1204 // need intersect(l, t, r, b) on irect
1205 if (!mask.fBounds.intersect(devBounds)) {
1206 return;
1207 }
1208 }
1209
1210 mask.fFormat = SkMask::kA8_Format;
1211 mask.fRowBytes = SkAlign4(mask.fBounds.width());
1212 size_t size = mask.computeImageSize();
1213 if (0 == size) {
1214 // the mask is too big to allocated, draw nothing
1215 return;
1216 }
1217
1218 // allocate (and clear) our temp buffer to hold the transformed bitmap
1219 SkAutoTMalloc<uint8_t> storage(size);
1220 mask.fImage = storage.get();
1221 memset(mask.fImage, 0, size);
1222
1223 // now draw our bitmap(src) into mask(dst), transformed by the matrix
1224 {
1225 SkBitmap device;
1226 device.installPixels(SkImageInfo::MakeA8(mask.fBounds.width(), mask.fBounds.height()),
1227 mask.fImage, mask.fRowBytes);
1228
1229 SkCanvas c(device);
1230 // need the unclipped top/left for the translate
1231 c.translate(-SkIntToScalar(mask.fBounds.fLeft),
1232 -SkIntToScalar(mask.fBounds.fTop));
1233 c.concat(*fMatrix);
1234
1235 // We can't call drawBitmap, or we'll infinitely recurse. Instead
1236 // we manually build a shader and draw that into our new mask
1237 SkPaint tmpPaint;
1238 tmpPaint.setFlags(paint.getFlags());
1239 SkAutoBitmapShaderInstall install(bitmap, tmpPaint);
1240 SkRect rr;
1241 rr.set(0, 0, SkIntToScalar(bitmap.width()),
1242 SkIntToScalar(bitmap.height()));
1243 c.drawRect(rr, install.paintWithShader());
1244 }
1245 this->drawDevMask(mask, paint);
1246 }
1247 }
1248
clipped_out(const SkMatrix & m,const SkRasterClip & c,const SkRect & srcR)1249 static bool clipped_out(const SkMatrix& m, const SkRasterClip& c,
1250 const SkRect& srcR) {
1251 SkRect dstR;
1252 m.mapRect(&dstR, srcR);
1253 return c.quickReject(dstR.roundOut());
1254 }
1255
clipped_out(const SkMatrix & matrix,const SkRasterClip & clip,int width,int height)1256 static bool clipped_out(const SkMatrix& matrix, const SkRasterClip& clip,
1257 int width, int height) {
1258 SkRect r;
1259 r.set(0, 0, SkIntToScalar(width), SkIntToScalar(height));
1260 return clipped_out(matrix, clip, r);
1261 }
1262
clipHandlesSprite(const SkRasterClip & clip,int x,int y,const SkPixmap & pmap)1263 static bool clipHandlesSprite(const SkRasterClip& clip, int x, int y, const SkPixmap& pmap) {
1264 return clip.isBW() || clip.quickContains(x, y, x + pmap.width(), y + pmap.height());
1265 }
1266
drawBitmap(const SkBitmap & bitmap,const SkMatrix & prematrix,const SkRect * dstBounds,const SkPaint & origPaint) const1267 void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix,
1268 const SkRect* dstBounds, const SkPaint& origPaint) const {
1269 SkDEBUGCODE(this->validate();)
1270
1271 // nothing to draw
1272 if (fRC->isEmpty() ||
1273 bitmap.width() == 0 || bitmap.height() == 0 ||
1274 bitmap.colorType() == kUnknown_SkColorType) {
1275 return;
1276 }
1277
1278 SkPaint paint(origPaint);
1279 paint.setStyle(SkPaint::kFill_Style);
1280
1281 SkMatrix matrix;
1282 matrix.setConcat(*fMatrix, prematrix);
1283
1284 if (clipped_out(matrix, *fRC, bitmap.width(), bitmap.height())) {
1285 return;
1286 }
1287
1288 if (bitmap.colorType() != kAlpha_8_SkColorType
1289 && SkTreatAsSprite(matrix, bitmap.dimensions(), paint)) {
1290 //
1291 // It is safe to call lock pixels now, since we know the matrix is
1292 // (more or less) identity.
1293 //
1294 SkAutoPixmapUnlock unlocker;
1295 if (!bitmap.requestLock(&unlocker)) {
1296 return;
1297 }
1298 const SkPixmap& pmap = unlocker.pixmap();
1299 int ix = SkScalarRoundToInt(matrix.getTranslateX());
1300 int iy = SkScalarRoundToInt(matrix.getTranslateY());
1301 if (clipHandlesSprite(*fRC, ix, iy, pmap)) {
1302 SkTBlitterAllocator allocator;
1303 // blitter will be owned by the allocator.
1304 SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, paint, pmap, ix, iy, &allocator);
1305 if (blitter) {
1306 SkScan::FillIRect(SkIRect::MakeXYWH(ix, iy, pmap.width(), pmap.height()),
1307 *fRC, blitter);
1308 return;
1309 }
1310 // if !blitter, then we fall-through to the slower case
1311 }
1312 }
1313
1314 // now make a temp draw on the stack, and use it
1315 //
1316 SkDraw draw(*this);
1317 draw.fMatrix = &matrix;
1318
1319 if (bitmap.colorType() == kAlpha_8_SkColorType) {
1320 draw.drawBitmapAsMask(bitmap, paint);
1321 } else {
1322 SkAutoBitmapShaderInstall install(bitmap, paint);
1323 const SkPaint& paintWithShader = install.paintWithShader();
1324 const SkRect srcBounds = SkRect::MakeIWH(bitmap.width(), bitmap.height());
1325 if (dstBounds) {
1326 this->drawRect(srcBounds, paintWithShader, &prematrix, dstBounds);
1327 } else {
1328 draw.drawRect(srcBounds, paintWithShader);
1329 }
1330 }
1331 }
1332
drawSprite(const SkBitmap & bitmap,int x,int y,const SkPaint & origPaint) const1333 void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& origPaint) const {
1334 SkDEBUGCODE(this->validate();)
1335
1336 // nothing to draw
1337 if (fRC->isEmpty() ||
1338 bitmap.width() == 0 || bitmap.height() == 0 ||
1339 bitmap.colorType() == kUnknown_SkColorType) {
1340 return;
1341 }
1342
1343 const SkIRect bounds = SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height());
1344
1345 if (fRC->quickReject(bounds)) {
1346 return; // nothing to draw
1347 }
1348
1349 SkPaint paint(origPaint);
1350 paint.setStyle(SkPaint::kFill_Style);
1351
1352 SkAutoPixmapUnlock unlocker;
1353 if (!bitmap.requestLock(&unlocker)) {
1354 return;
1355 }
1356 const SkPixmap& pmap = unlocker.pixmap();
1357
1358 if (nullptr == paint.getColorFilter() && clipHandlesSprite(*fRC, x, y, pmap)) {
1359 SkTBlitterAllocator allocator;
1360 // blitter will be owned by the allocator.
1361 SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, paint, pmap, x, y, &allocator);
1362 if (blitter) {
1363 SkScan::FillIRect(bounds, *fRC, blitter);
1364 return;
1365 }
1366 }
1367
1368 SkMatrix matrix;
1369 SkRect r;
1370
1371 // get a scalar version of our rect
1372 r.set(bounds);
1373
1374 // create shader with offset
1375 matrix.setTranslate(r.fLeft, r.fTop);
1376 SkAutoBitmapShaderInstall install(bitmap, paint, &matrix);
1377 const SkPaint& shaderPaint = install.paintWithShader();
1378
1379 SkDraw draw(*this);
1380 matrix.reset();
1381 draw.fMatrix = &matrix;
1382 // call ourself with a rect
1383 // is this OK if paint has a rasterizer?
1384 draw.drawRect(r, shaderPaint);
1385 }
1386
1387 ///////////////////////////////////////////////////////////////////////////////
1388
1389 #include "SkScalerContext.h"
1390 #include "SkGlyphCache.h"
1391 #include "SkTextToPathIter.h"
1392 #include "SkUtils.h"
1393
ShouldDrawTextAsPaths(const SkPaint & paint,const SkMatrix & ctm)1394 bool SkDraw::ShouldDrawTextAsPaths(const SkPaint& paint, const SkMatrix& ctm) {
1395 // hairline glyphs are fast enough so we don't need to cache them
1396 if (SkPaint::kStroke_Style == paint.getStyle() && 0 == paint.getStrokeWidth()) {
1397 return true;
1398 }
1399
1400 // we don't cache perspective
1401 if (ctm.hasPerspective()) {
1402 return true;
1403 }
1404
1405 SkMatrix textM;
1406 return SkPaint::TooBigToUseCache(ctm, *paint.setTextMatrix(&textM));
1407 }
1408
drawText_asPaths(const char text[],size_t byteLength,SkScalar x,SkScalar y,const SkPaint & paint) const1409 void SkDraw::drawText_asPaths(const char text[], size_t byteLength,
1410 SkScalar x, SkScalar y,
1411 const SkPaint& paint) const {
1412 SkDEBUGCODE(this->validate();)
1413
1414 SkTextToPathIter iter(text, byteLength, paint, true);
1415
1416 SkMatrix matrix;
1417 matrix.setScale(iter.getPathScale(), iter.getPathScale());
1418 matrix.postTranslate(x, y);
1419
1420 const SkPath* iterPath;
1421 SkScalar xpos, prevXPos = 0;
1422
1423 while (iter.next(&iterPath, &xpos)) {
1424 matrix.postTranslate(xpos - prevXPos, 0);
1425 if (iterPath) {
1426 const SkPaint& pnt = iter.getPaint();
1427 if (fDevice) {
1428 fDevice->drawPath(*this, *iterPath, pnt, &matrix, false);
1429 } else {
1430 this->drawPath(*iterPath, pnt, &matrix, false);
1431 }
1432 }
1433 prevXPos = xpos;
1434 }
1435 }
1436
1437 // disable warning : local variable used without having been initialized
1438 #if defined _WIN32 && _MSC_VER >= 1300
1439 #pragma warning ( push )
1440 #pragma warning ( disable : 4701 )
1441 #endif
1442
1443 ////////////////////////////////////////////////////////////////////////////////////////////////////
1444
1445 class DrawOneGlyph {
1446 public:
DrawOneGlyph(const SkDraw & draw,const SkPaint & paint,SkGlyphCache * cache,SkBlitter * blitter)1447 DrawOneGlyph(const SkDraw& draw, const SkPaint& paint, SkGlyphCache* cache, SkBlitter* blitter)
1448 : fUseRegionToDraw(UsingRegionToDraw(draw.fRC))
1449 , fGlyphCache(cache)
1450 , fBlitter(blitter)
1451 , fClip(fUseRegionToDraw ? &draw.fRC->bwRgn() : nullptr)
1452 , fDraw(draw)
1453 , fPaint(paint)
1454 , fClipBounds(PickClipBounds(draw)) { }
1455
operator ()(const SkGlyph & glyph,SkPoint position,SkPoint rounding)1456 void operator()(const SkGlyph& glyph, SkPoint position, SkPoint rounding) {
1457 position += rounding;
1458 Sk48Dot16 fx = SkScalarTo48Dot16(position.fX);
1459 Sk48Dot16 fy = SkScalarTo48Dot16(position.fY);
1460 // Prevent glyphs from being drawn outside of or straddling the edge of device space.
1461 if ((fx >> 16) > INT_MAX - (INT16_MAX + UINT16_MAX) ||
1462 (fx >> 16) < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/) ||
1463 (fy >> 16) > INT_MAX - (INT16_MAX + UINT16_MAX) ||
1464 (fy >> 16) < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)) {
1465 return;
1466 }
1467
1468 int left = Sk48Dot16FloorToInt(fx);
1469 int top = Sk48Dot16FloorToInt(fy);
1470 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1471
1472 left += glyph.fLeft;
1473 top += glyph.fTop;
1474
1475 int right = left + glyph.fWidth;
1476 int bottom = top + glyph.fHeight;
1477
1478 SkMask mask;
1479 mask.fBounds.set(left, top, right, bottom);
1480
1481 if (fUseRegionToDraw) {
1482 SkRegion::Cliperator clipper(*fClip, mask.fBounds);
1483
1484 if (!clipper.done() && this->getImageData(glyph, &mask)) {
1485 const SkIRect& cr = clipper.rect();
1486 do {
1487 this->blitMask(mask, cr);
1488 clipper.next();
1489 } while (!clipper.done());
1490 }
1491 } else {
1492 SkIRect storage;
1493 SkIRect* bounds = &mask.fBounds;
1494
1495 // this extra test is worth it, assuming that most of the time it succeeds
1496 // since we can avoid writing to storage
1497 if (!fClipBounds.containsNoEmptyCheck(mask.fBounds)) {
1498 if (!storage.intersectNoEmptyCheck(mask.fBounds, fClipBounds))
1499 return;
1500 bounds = &storage;
1501 }
1502
1503 if (this->getImageData(glyph, &mask)) {
1504 this->blitMask(mask, *bounds);
1505 }
1506 }
1507 }
1508
1509 private:
UsingRegionToDraw(const SkRasterClip * rClip)1510 static bool UsingRegionToDraw(const SkRasterClip* rClip) {
1511 return rClip->isBW() && !rClip->isRect();
1512 }
1513
PickClipBounds(const SkDraw & draw)1514 static SkIRect PickClipBounds(const SkDraw& draw) {
1515 const SkRasterClip& rasterClip = *draw.fRC;
1516
1517 if (rasterClip.isBW()) {
1518 return rasterClip.bwRgn().getBounds();
1519 } else {
1520 return rasterClip.aaRgn().getBounds();
1521 }
1522 }
1523
getImageData(const SkGlyph & glyph,SkMask * mask)1524 bool getImageData(const SkGlyph& glyph, SkMask* mask) {
1525 uint8_t* bits = (uint8_t*)(fGlyphCache->findImage(glyph));
1526 if (nullptr == bits) {
1527 return false; // can't rasterize glyph
1528 }
1529 mask->fImage = bits;
1530 mask->fRowBytes = glyph.rowBytes();
1531 mask->fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
1532 return true;
1533 }
1534
blitMask(const SkMask & mask,const SkIRect & clip) const1535 void blitMask(const SkMask& mask, const SkIRect& clip) const {
1536 if (SkMask::kARGB32_Format == mask.fFormat) {
1537 SkBitmap bm;
1538 bm.installPixels(
1539 SkImageInfo::MakeN32Premul(mask.fBounds.width(), mask.fBounds.height()),
1540 (SkPMColor*)mask.fImage, mask.fRowBytes);
1541
1542 fDraw.drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), fPaint);
1543 } else {
1544 fBlitter->blitMask(mask, clip);
1545 }
1546 }
1547
1548 const bool fUseRegionToDraw;
1549 SkGlyphCache * const fGlyphCache;
1550 SkBlitter * const fBlitter;
1551 const SkRegion* const fClip;
1552 const SkDraw& fDraw;
1553 const SkPaint& fPaint;
1554 const SkIRect fClipBounds;
1555 };
1556
1557 ////////////////////////////////////////////////////////////////////////////////////////////////////
1558
fakeGamma() const1559 SkPaint::FakeGamma SkDraw::fakeGamma() const {
1560 return fDevice->imageInfo().isLinear() ? SkPaint::FakeGamma::On : SkPaint::FakeGamma::Off;
1561 }
1562
drawText(const char text[],size_t byteLength,SkScalar x,SkScalar y,const SkPaint & paint) const1563 void SkDraw::drawText(const char text[], size_t byteLength,
1564 SkScalar x, SkScalar y, const SkPaint& paint) const {
1565 SkASSERT(byteLength == 0 || text != nullptr);
1566
1567 SkDEBUGCODE(this->validate();)
1568
1569 // nothing to draw
1570 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) {
1571 return;
1572 }
1573
1574 // SkScalarRec doesn't currently have a way of representing hairline stroke and
1575 // will fill if its frame-width is 0.
1576 if (ShouldDrawTextAsPaths(paint, *fMatrix)) {
1577 this->drawText_asPaths(text, byteLength, x, y, paint);
1578 return;
1579 }
1580
1581 SkAutoGlyphCache cache(paint, &fDevice->surfaceProps(), this->fakeGamma(), fMatrix);
1582
1583 // The Blitter Choose needs to be live while using the blitter below.
1584 SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint);
1585 SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get());
1586 DrawOneGlyph drawOneGlyph(*this, paint, cache.get(), wrapper.getBlitter());
1587
1588 SkFindAndPlaceGlyph::ProcessText(
1589 paint.getTextEncoding(), text, byteLength,
1590 {x, y}, *fMatrix, paint.getTextAlign(), cache.get(), drawOneGlyph);
1591 }
1592
1593 //////////////////////////////////////////////////////////////////////////////
1594
drawPosText_asPaths(const char text[],size_t byteLength,const SkScalar pos[],int scalarsPerPosition,const SkPoint & offset,const SkPaint & origPaint) const1595 void SkDraw::drawPosText_asPaths(const char text[], size_t byteLength,
1596 const SkScalar pos[], int scalarsPerPosition,
1597 const SkPoint& offset, const SkPaint& origPaint) const {
1598 // setup our std paint, in hopes of getting hits in the cache
1599 SkPaint paint(origPaint);
1600 SkScalar matrixScale = paint.setupForAsPaths();
1601
1602 SkMatrix matrix;
1603 matrix.setScale(matrixScale, matrixScale);
1604
1605 // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache.
1606 paint.setStyle(SkPaint::kFill_Style);
1607 paint.setPathEffect(nullptr);
1608
1609 SkPaint::GlyphCacheProc glyphCacheProc = paint.getGlyphCacheProc(true);
1610 SkAutoGlyphCache cache(paint, &fDevice->surfaceProps(), this->fakeGamma(), nullptr);
1611
1612 const char* stop = text + byteLength;
1613 SkTextAlignProc alignProc(paint.getTextAlign());
1614 SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition);
1615
1616 // Now restore the original settings, so we "draw" with whatever style/stroking.
1617 paint.setStyle(origPaint.getStyle());
1618 paint.setPathEffect(origPaint.getPathEffect());
1619
1620 while (text < stop) {
1621 const SkGlyph& glyph = glyphCacheProc(cache.get(), &text);
1622 if (glyph.fWidth) {
1623 const SkPath* path = cache->findPath(glyph);
1624 if (path) {
1625 SkPoint tmsLoc;
1626 tmsProc(pos, &tmsLoc);
1627 SkPoint loc;
1628 alignProc(tmsLoc, glyph, &loc);
1629
1630 matrix[SkMatrix::kMTransX] = loc.fX;
1631 matrix[SkMatrix::kMTransY] = loc.fY;
1632 if (fDevice) {
1633 fDevice->drawPath(*this, *path, paint, &matrix, false);
1634 } else {
1635 this->drawPath(*path, paint, &matrix, false);
1636 }
1637 }
1638 }
1639 pos += scalarsPerPosition;
1640 }
1641 }
1642
drawPosText(const char text[],size_t byteLength,const SkScalar pos[],int scalarsPerPosition,const SkPoint & offset,const SkPaint & paint) const1643 void SkDraw::drawPosText(const char text[], size_t byteLength,
1644 const SkScalar pos[], int scalarsPerPosition,
1645 const SkPoint& offset, const SkPaint& paint) const {
1646 SkASSERT(byteLength == 0 || text != nullptr);
1647 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
1648
1649 SkDEBUGCODE(this->validate();)
1650
1651 // nothing to draw
1652 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) {
1653 return;
1654 }
1655
1656 if (ShouldDrawTextAsPaths(paint, *fMatrix)) {
1657 this->drawPosText_asPaths(text, byteLength, pos, scalarsPerPosition, offset, paint);
1658 return;
1659 }
1660
1661 SkAutoGlyphCache cache(paint, &fDevice->surfaceProps(), this->fakeGamma(), fMatrix);
1662
1663 // The Blitter Choose needs to be live while using the blitter below.
1664 SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint);
1665 SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get());
1666 DrawOneGlyph drawOneGlyph(*this, paint, cache.get(), wrapper.getBlitter());
1667 SkPaint::Align textAlignment = paint.getTextAlign();
1668
1669 SkFindAndPlaceGlyph::ProcessPosText(
1670 paint.getTextEncoding(), text, byteLength,
1671 offset, *fMatrix, pos, scalarsPerPosition, textAlignment, cache.get(), drawOneGlyph);
1672 }
1673
1674 #if defined _WIN32 && _MSC_VER >= 1300
1675 #pragma warning ( pop )
1676 #endif
1677
1678 ///////////////////////////////////////////////////////////////////////////////
1679
ChooseHairProc(bool doAntiAlias)1680 static SkScan::HairRCProc ChooseHairProc(bool doAntiAlias) {
1681 return doAntiAlias ? SkScan::AntiHairLine : SkScan::HairLine;
1682 }
1683
texture_to_matrix(const VertState & state,const SkPoint verts[],const SkPoint texs[],SkMatrix * matrix)1684 static bool texture_to_matrix(const VertState& state, const SkPoint verts[],
1685 const SkPoint texs[], SkMatrix* matrix) {
1686 SkPoint src[3], dst[3];
1687
1688 src[0] = texs[state.f0];
1689 src[1] = texs[state.f1];
1690 src[2] = texs[state.f2];
1691 dst[0] = verts[state.f0];
1692 dst[1] = verts[state.f1];
1693 dst[2] = verts[state.f2];
1694 return matrix->setPolyToPoly(src, dst, 3);
1695 }
1696
1697 class SkTriColorShader : public SkShader {
1698 public:
SkTriColorShader()1699 SkTriColorShader() {}
1700
1701 size_t contextSize(const ContextRec&) const override;
1702
1703 class TriColorShaderContext : public SkShader::Context {
1704 public:
1705 TriColorShaderContext(const SkTriColorShader& shader, const ContextRec&);
1706 virtual ~TriColorShaderContext();
1707
1708 bool setup(const SkPoint pts[], const SkColor colors[], int, int, int);
1709
1710 void shadeSpan(int x, int y, SkPMColor dstC[], int count) override;
1711
1712 private:
1713 SkMatrix fDstToUnit;
1714 SkPMColor fColors[3];
1715
1716 typedef SkShader::Context INHERITED;
1717 };
1718
SK_TO_STRING_OVERRIDE()1719 SK_TO_STRING_OVERRIDE()
1720
1721 // For serialization. This will never be called.
1722 Factory getFactory() const override { sk_throw(); return nullptr; }
1723
1724 protected:
onCreateContext(const ContextRec & rec,void * storage) const1725 Context* onCreateContext(const ContextRec& rec, void* storage) const override {
1726 return new (storage) TriColorShaderContext(*this, rec);
1727 }
1728
1729 private:
1730 typedef SkShader INHERITED;
1731 };
1732
setup(const SkPoint pts[],const SkColor colors[],int index0,int index1,int index2)1733 bool SkTriColorShader::TriColorShaderContext::setup(const SkPoint pts[], const SkColor colors[],
1734 int index0, int index1, int index2) {
1735
1736 fColors[0] = SkPreMultiplyColor(colors[index0]);
1737 fColors[1] = SkPreMultiplyColor(colors[index1]);
1738 fColors[2] = SkPreMultiplyColor(colors[index2]);
1739
1740 SkMatrix m, im;
1741 m.reset();
1742 m.set(0, pts[index1].fX - pts[index0].fX);
1743 m.set(1, pts[index2].fX - pts[index0].fX);
1744 m.set(2, pts[index0].fX);
1745 m.set(3, pts[index1].fY - pts[index0].fY);
1746 m.set(4, pts[index2].fY - pts[index0].fY);
1747 m.set(5, pts[index0].fY);
1748 if (!m.invert(&im)) {
1749 return false;
1750 }
1751 // We can't call getTotalInverse(), because we explicitly don't want to look at the localmatrix
1752 // as our interators are intrinsically tied to the vertices, and nothing else.
1753 SkMatrix ctmInv;
1754 if (!this->getCTM().invert(&ctmInv)) {
1755 return false;
1756 }
1757 fDstToUnit.setConcat(im, ctmInv);
1758 return true;
1759 }
1760
1761 #include "SkColorPriv.h"
1762 #include "SkComposeShader.h"
1763
ScalarTo256(SkScalar v)1764 static int ScalarTo256(SkScalar v) {
1765 return static_cast<int>(SkScalarPin(v, 0, 1) * 256 + 0.5);
1766 }
1767
1768
TriColorShaderContext(const SkTriColorShader & shader,const ContextRec & rec)1769 SkTriColorShader::TriColorShaderContext::TriColorShaderContext(const SkTriColorShader& shader,
1770 const ContextRec& rec)
1771 : INHERITED(shader, rec) {}
1772
~TriColorShaderContext()1773 SkTriColorShader::TriColorShaderContext::~TriColorShaderContext() {}
1774
contextSize(const ContextRec &) const1775 size_t SkTriColorShader::contextSize(const ContextRec&) const {
1776 return sizeof(TriColorShaderContext);
1777 }
shadeSpan(int x,int y,SkPMColor dstC[],int count)1778 void SkTriColorShader::TriColorShaderContext::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
1779 const int alphaScale = Sk255To256(this->getPaintAlpha());
1780
1781 SkPoint src;
1782
1783 for (int i = 0; i < count; i++) {
1784 fDstToUnit.mapXY(SkIntToScalar(x), SkIntToScalar(y), &src);
1785 x += 1;
1786
1787 int scale1 = ScalarTo256(src.fX);
1788 int scale2 = ScalarTo256(src.fY);
1789 int scale0 = 256 - scale1 - scale2;
1790 if (scale0 < 0) {
1791 if (scale1 > scale2) {
1792 scale2 = 256 - scale1;
1793 } else {
1794 scale1 = 256 - scale2;
1795 }
1796 scale0 = 0;
1797 }
1798
1799 if (256 != alphaScale) {
1800 scale0 = SkAlphaMul(scale0, alphaScale);
1801 scale1 = SkAlphaMul(scale1, alphaScale);
1802 scale2 = SkAlphaMul(scale2, alphaScale);
1803 }
1804
1805 dstC[i] = SkAlphaMulQ(fColors[0], scale0) +
1806 SkAlphaMulQ(fColors[1], scale1) +
1807 SkAlphaMulQ(fColors[2], scale2);
1808 }
1809 }
1810
1811 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const1812 void SkTriColorShader::toString(SkString* str) const {
1813 str->append("SkTriColorShader: (");
1814
1815 this->INHERITED::toString(str);
1816
1817 str->append(")");
1818 }
1819 #endif
1820
drawVertices(SkCanvas::VertexMode vmode,int count,const SkPoint vertices[],const SkPoint textures[],const SkColor colors[],SkXfermode * xmode,const uint16_t indices[],int indexCount,const SkPaint & paint) const1821 void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count,
1822 const SkPoint vertices[], const SkPoint textures[],
1823 const SkColor colors[], SkXfermode* xmode,
1824 const uint16_t indices[], int indexCount,
1825 const SkPaint& paint) const {
1826 SkASSERT(0 == count || vertices);
1827
1828 // abort early if there is nothing to draw
1829 if (count < 3 || (indices && indexCount < 3) || fRC->isEmpty()) {
1830 return;
1831 }
1832
1833 // transform out vertices into device coordinates
1834 SkAutoSTMalloc<16, SkPoint> storage(count);
1835 SkPoint* devVerts = storage.get();
1836 fMatrix->mapPoints(devVerts, vertices, count);
1837
1838 /*
1839 We can draw the vertices in 1 of 4 ways:
1840
1841 - solid color (no shader/texture[], no colors[])
1842 - just colors (no shader/texture[], has colors[])
1843 - just texture (has shader/texture[], no colors[])
1844 - colors * texture (has shader/texture[], has colors[])
1845
1846 Thus for texture drawing, we need both texture[] and a shader.
1847 */
1848
1849 SkTriColorShader triShader; // must be above declaration of p
1850 SkPaint p(paint);
1851
1852 SkShader* shader = p.getShader();
1853 if (nullptr == shader) {
1854 // if we have no shader, we ignore the texture coordinates
1855 textures = nullptr;
1856 } else if (nullptr == textures) {
1857 // if we don't have texture coordinates, ignore the shader
1858 p.setShader(nullptr);
1859 shader = nullptr;
1860 }
1861
1862 // setup the custom shader (if needed)
1863 SkAutoTUnref<SkComposeShader> composeShader;
1864 if (colors) {
1865 if (nullptr == textures) {
1866 // just colors (no texture)
1867 shader = p.setShader(&triShader);
1868 } else {
1869 // colors * texture
1870 SkASSERT(shader);
1871 bool releaseMode = false;
1872 if (nullptr == xmode) {
1873 xmode = SkXfermode::Create(SkXfermode::kModulate_Mode);
1874 releaseMode = true;
1875 }
1876 composeShader.reset(new SkComposeShader(&triShader, shader, xmode));
1877 p.setShader(composeShader);
1878 if (releaseMode) {
1879 xmode->unref();
1880 }
1881 }
1882 }
1883
1884 SkAutoBlitterChoose blitter(fDst, *fMatrix, p);
1885 // Abort early if we failed to create a shader context.
1886 if (blitter->isNullBlitter()) {
1887 return;
1888 }
1889
1890 // setup our state and function pointer for iterating triangles
1891 VertState state(count, indices, indexCount);
1892 VertState::Proc vertProc = state.chooseProc(vmode);
1893
1894 if (textures || colors) {
1895 while (vertProc(&state)) {
1896 if (textures) {
1897 SkMatrix tempM;
1898 if (texture_to_matrix(state, vertices, textures, &tempM)) {
1899 SkShader::ContextRec rec(p, *fMatrix, &tempM,
1900 SkBlitter::PreferredShaderDest(fDst.info()));
1901 if (!blitter->resetShaderContext(rec)) {
1902 continue;
1903 }
1904 }
1905 }
1906 if (colors) {
1907 // Find the context for triShader.
1908 SkTriColorShader::TriColorShaderContext* triColorShaderContext;
1909
1910 SkShader::Context* shaderContext = blitter->getShaderContext();
1911 SkASSERT(shaderContext);
1912 if (p.getShader() == &triShader) {
1913 triColorShaderContext =
1914 static_cast<SkTriColorShader::TriColorShaderContext*>(shaderContext);
1915 } else {
1916 // The shader is a compose shader and triShader is its first shader.
1917 SkASSERT(p.getShader() == composeShader);
1918 SkASSERT(composeShader->getShaderA() == &triShader);
1919 SkComposeShader::ComposeShaderContext* composeShaderContext =
1920 static_cast<SkComposeShader::ComposeShaderContext*>(shaderContext);
1921 SkShader::Context* shaderContextA = composeShaderContext->getShaderContextA();
1922 triColorShaderContext =
1923 static_cast<SkTriColorShader::TriColorShaderContext*>(shaderContextA);
1924 }
1925
1926 if (!triColorShaderContext->setup(vertices, colors,
1927 state.f0, state.f1, state.f2)) {
1928 continue;
1929 }
1930 }
1931
1932 SkPoint tmp[] = {
1933 devVerts[state.f0], devVerts[state.f1], devVerts[state.f2]
1934 };
1935 SkScan::FillTriangle(tmp, *fRC, blitter.get());
1936 }
1937 } else {
1938 // no colors[] and no texture, stroke hairlines with paint's color.
1939 SkScan::HairRCProc hairProc = ChooseHairProc(paint.isAntiAlias());
1940 const SkRasterClip& clip = *fRC;
1941 while (vertProc(&state)) {
1942 SkPoint array[] = {
1943 devVerts[state.f0], devVerts[state.f1], devVerts[state.f2], devVerts[state.f0]
1944 };
1945 hairProc(array, 4, clip, blitter.get());
1946 }
1947 }
1948 }
1949
1950 ///////////////////////////////////////////////////////////////////////////////
1951 ///////////////////////////////////////////////////////////////////////////////
1952
1953 #ifdef SK_DEBUG
1954
validate() const1955 void SkDraw::validate() const {
1956 SkASSERT(fMatrix != nullptr);
1957 SkASSERT(fClip != nullptr);
1958 SkASSERT(fRC != nullptr);
1959
1960 const SkIRect& cr = fRC->getBounds();
1961 SkIRect br;
1962
1963 br.set(0, 0, fDst.width(), fDst.height());
1964 SkASSERT(cr.isEmpty() || br.contains(cr));
1965 }
1966
1967 #endif
1968
1969 ////////////////////////////////////////////////////////////////////////////////////////////////
1970
1971 #include "SkPath.h"
1972 #include "SkDraw.h"
1973 #include "SkRegion.h"
1974 #include "SkBlitter.h"
1975
compute_bounds(const SkPath & devPath,const SkIRect * clipBounds,const SkMaskFilter * filter,const SkMatrix * filterMatrix,SkIRect * bounds)1976 static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds,
1977 const SkMaskFilter* filter, const SkMatrix* filterMatrix,
1978 SkIRect* bounds) {
1979 if (devPath.isEmpty()) {
1980 return false;
1981 }
1982
1983 // init our bounds from the path
1984 *bounds = devPath.getBounds().makeOutset(SK_ScalarHalf, SK_ScalarHalf).roundOut();
1985
1986 SkIPoint margin = SkIPoint::Make(0, 0);
1987 if (filter) {
1988 SkASSERT(filterMatrix);
1989
1990 SkMask srcM, dstM;
1991
1992 srcM.fBounds = *bounds;
1993 srcM.fFormat = SkMask::kA8_Format;
1994 if (!filter->filterMask(&dstM, srcM, *filterMatrix, &margin)) {
1995 return false;
1996 }
1997 }
1998
1999 // (possibly) trim the bounds to reflect the clip
2000 // (plus whatever slop the filter needs)
2001 if (clipBounds) {
2002 // Ugh. Guard against gigantic margins from wacky filters. Without this
2003 // check we can request arbitrary amounts of slop beyond our visible
2004 // clip, and bring down the renderer (at least on finite RAM machines
2005 // like handsets, etc.). Need to balance this invented value between
2006 // quality of large filters like blurs, and the corresponding memory
2007 // requests.
2008 static const int MAX_MARGIN = 128;
2009 if (!bounds->intersect(clipBounds->makeOutset(SkMin32(margin.fX, MAX_MARGIN),
2010 SkMin32(margin.fY, MAX_MARGIN)))) {
2011 return false;
2012 }
2013 }
2014
2015 return true;
2016 }
2017
draw_into_mask(const SkMask & mask,const SkPath & devPath,SkPaint::Style style)2018 static void draw_into_mask(const SkMask& mask, const SkPath& devPath, SkPaint::Style style) {
2019 SkDraw draw;
2020 if (!draw.fDst.reset(mask)) {
2021 return;
2022 }
2023
2024 SkRasterClip clip;
2025 SkMatrix matrix;
2026 SkPaint paint;
2027
2028 clip.setRect(SkIRect::MakeWH(mask.fBounds.width(), mask.fBounds.height()));
2029 matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
2030 -SkIntToScalar(mask.fBounds.fTop));
2031
2032 draw.fRC = &clip;
2033 draw.fClip = &clip.bwRgn();
2034 draw.fMatrix = &matrix;
2035 paint.setAntiAlias(true);
2036 paint.setStyle(style);
2037 draw.drawPath(devPath, paint);
2038 }
2039
DrawToMask(const SkPath & devPath,const SkIRect * clipBounds,const SkMaskFilter * filter,const SkMatrix * filterMatrix,SkMask * mask,SkMask::CreateMode mode,SkPaint::Style style)2040 bool SkDraw::DrawToMask(const SkPath& devPath, const SkIRect* clipBounds,
2041 const SkMaskFilter* filter, const SkMatrix* filterMatrix,
2042 SkMask* mask, SkMask::CreateMode mode,
2043 SkPaint::Style style) {
2044 if (SkMask::kJustRenderImage_CreateMode != mode) {
2045 if (!compute_bounds(devPath, clipBounds, filter, filterMatrix, &mask->fBounds))
2046 return false;
2047 }
2048
2049 if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) {
2050 mask->fFormat = SkMask::kA8_Format;
2051 mask->fRowBytes = mask->fBounds.width();
2052 size_t size = mask->computeImageSize();
2053 if (0 == size) {
2054 // we're too big to allocate the mask, abort
2055 return false;
2056 }
2057 mask->fImage = SkMask::AllocImage(size);
2058 memset(mask->fImage, 0, mask->computeImageSize());
2059 }
2060
2061 if (SkMask::kJustComputeBounds_CreateMode != mode) {
2062 draw_into_mask(*mask, devPath, style);
2063 }
2064
2065 return true;
2066 }
2067