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