Coverage Report

Created: 2021-08-22 09:07

/src/skia/src/core/SkDraw.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2006 The Android Open Source Project
3
 *
4
 * Use of this source code is governed by a BSD-style license that can be
5
 * found in the LICENSE file.
6
 */
7
8
#include "src/core/SkDraw.h"
9
10
#include "include/core/SkBitmap.h"
11
#include "include/core/SkCanvas.h"
12
#include "include/core/SkMatrix.h"
13
#include "include/core/SkPaint.h"
14
#include "include/core/SkPathEffect.h"
15
#include "include/core/SkRRect.h"
16
#include "include/core/SkShader.h"
17
#include "include/core/SkString.h"
18
#include "include/core/SkStrokeRec.h"
19
#include "include/private/SkColorData.h"
20
#include "include/private/SkMacros.h"
21
#include "include/private/SkTemplates.h"
22
#include "include/private/SkTo.h"
23
#include "src/core/SkArenaAlloc.h"
24
#include "src/core/SkAutoBlitterChoose.h"
25
#include "src/core/SkBlendModePriv.h"
26
#include "src/core/SkBlitter.h"
27
#include "src/core/SkDevice.h"
28
#include "src/core/SkDrawProcs.h"
29
#include "src/core/SkMaskFilterBase.h"
30
#include "src/core/SkMatrixUtils.h"
31
#include "src/core/SkPathEffectBase.h"
32
#include "src/core/SkPathPriv.h"
33
#include "src/core/SkRasterClip.h"
34
#include "src/core/SkRectPriv.h"
35
#include "src/core/SkSamplingPriv.h"
36
#include "src/core/SkScan.h"
37
#include "src/core/SkStroke.h"
38
#include "src/core/SkTLazy.h"
39
#include "src/core/SkUtils.h"
40
41
#include <utility>
42
43
static SkPaint make_paint_with_image(const SkPaint& origPaint, const SkBitmap& bitmap,
44
                                     const SkSamplingOptions& sampling,
45
30.2k
                                     SkMatrix* matrix = nullptr) {
46
30.2k
    SkPaint paint(origPaint);
47
30.2k
    paint.setShader(SkMakeBitmapShaderForPaint(origPaint, bitmap, SkTileMode::kClamp,
48
30.2k
                                               SkTileMode::kClamp, sampling, matrix,
49
30.2k
                                               kNever_SkCopyPixelsMode));
50
30.2k
    return paint;
51
30.2k
}
52
53
///////////////////////////////////////////////////////////////////////////////
54
55
476k
SkDraw::SkDraw() {}
56
57
115k
bool SkDraw::computeConservativeLocalClipBounds(SkRect* localBounds) const {
58
115k
    if (fRC->isEmpty()) {
59
0
        return false;
60
0
    }
61
62
115k
    SkMatrix inverse;
63
115k
    if (!fMatrixProvider->localToDevice().invert(&inverse)) {
64
3.04k
        return false;
65
3.04k
    }
66
67
112k
    SkIRect devBounds = fRC->getBounds();
68
    // outset to have slop for antialasing and hairlines
69
112k
    devBounds.outset(1, 1);
70
112k
    inverse.mapRect(localBounds, SkRect::Make(devBounds));
71
112k
    return true;
72
112k
}
73
74
///////////////////////////////////////////////////////////////////////////////
75
76
120k
void SkDraw::drawPaint(const SkPaint& paint) const {
77
60.2k
    SkDEBUGCODE(this->validate();)
78
79
120k
    if (fRC->isEmpty()) {
80
4
        return;
81
4
    }
82
83
120k
    SkIRect    devRect;
84
120k
    devRect.setWH(fDst.width(), fDst.height());
85
86
120k
    SkAutoBlitterChoose blitter(*this, nullptr, paint);
87
120k
    SkScan::FillIRect(devRect, *fRC, blitter.get());
88
120k
}
SkDraw::drawPaint(SkPaint const&) const
Line
Count
Source
76
60.2k
void SkDraw::drawPaint(const SkPaint& paint) const {
77
60.2k
    SkDEBUGCODE(this->validate();)
78
79
60.2k
    if (fRC->isEmpty()) {
80
2
        return;
81
2
    }
82
83
60.2k
    SkIRect    devRect;
84
60.2k
    devRect.setWH(fDst.width(), fDst.height());
85
86
60.2k
    SkAutoBlitterChoose blitter(*this, nullptr, paint);
87
60.2k
    SkScan::FillIRect(devRect, *fRC, blitter.get());
88
60.2k
}
SkDraw::drawPaint(SkPaint const&) const
Line
Count
Source
76
60.2k
void SkDraw::drawPaint(const SkPaint& paint) const {
77
60.2k
    SkDEBUGCODE(this->validate();)
78
79
60.2k
    if (fRC->isEmpty()) {
80
2
        return;
81
2
    }
82
83
60.2k
    SkIRect    devRect;
84
60.2k
    devRect.setWH(fDst.width(), fDst.height());
85
86
60.2k
    SkAutoBlitterChoose blitter(*this, nullptr, paint);
87
60.2k
    SkScan::FillIRect(devRect, *fRC, blitter.get());
88
60.2k
}
89
90
///////////////////////////////////////////////////////////////////////////////
91
92
struct PtProcRec {
93
    SkCanvas::PointMode fMode;
94
    const SkPaint*  fPaint;
95
    const SkRegion* fClip;
96
    const SkRasterClip* fRC;
97
98
    // computed values
99
    SkRect   fClipBounds;
100
    SkScalar fRadius;
101
102
    typedef void (*Proc)(const PtProcRec&, const SkPoint devPts[], int count,
103
                         SkBlitter*);
104
105
    bool init(SkCanvas::PointMode, const SkPaint&, const SkMatrix* matrix,
106
              const SkRasterClip*);
107
    Proc chooseProc(SkBlitter** blitter);
108
109
private:
110
    SkAAClipBlitterWrapper fWrapper;
111
};
112
113
static void bw_pt_rect_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
114
12
                                 int count, SkBlitter* blitter) {
115
12
    SkASSERT(rec.fClip->isRect());
116
12
    const SkIRect& r = rec.fClip->getBounds();
117
118
352
    for (int i = 0; i < count; i++) {
119
340
        int x = SkScalarFloorToInt(devPts[i].fX);
120
340
        int y = SkScalarFloorToInt(devPts[i].fY);
121
340
        if (r.contains(x, y)) {
122
292
            blitter->blitH(x, y, 1);
123
292
        }
124
340
    }
125
12
}
126
127
static void bw_pt_rect_16_hair_proc(const PtProcRec& rec,
128
                                    const SkPoint devPts[], int count,
129
0
                                    SkBlitter* blitter) {
130
0
    SkASSERT(rec.fRC->isRect());
131
0
    const SkIRect& r = rec.fRC->getBounds();
132
0
    uint32_t value;
133
0
    const SkPixmap* dst = blitter->justAnOpaqueColor(&value);
134
0
    SkASSERT(dst);
135
136
0
    uint16_t* addr = dst->writable_addr16(0, 0);
137
0
    size_t    rb = dst->rowBytes();
138
139
0
    for (int i = 0; i < count; i++) {
140
0
        int x = SkScalarFloorToInt(devPts[i].fX);
141
0
        int y = SkScalarFloorToInt(devPts[i].fY);
142
0
        if (r.contains(x, y)) {
143
0
            ((uint16_t*)((char*)addr + y * rb))[x] = SkToU16(value);
144
0
        }
145
0
    }
146
0
}
Unexecuted instantiation: SkDraw.cpp:bw_pt_rect_16_hair_proc(PtProcRec const&, SkPoint const*, int, SkBlitter*)
Unexecuted instantiation: SkDraw.cpp:bw_pt_rect_16_hair_proc(PtProcRec const&, SkPoint const*, int, SkBlitter*)
147
148
static void bw_pt_rect_32_hair_proc(const PtProcRec& rec,
149
                                    const SkPoint devPts[], int count,
150
5
                                    SkBlitter* blitter) {
151
5
    SkASSERT(rec.fRC->isRect());
152
5
    const SkIRect& r = rec.fRC->getBounds();
153
5
    uint32_t value;
154
5
    const SkPixmap* dst = blitter->justAnOpaqueColor(&value);
155
5
    SkASSERT(dst);
156
157
5
    SkPMColor* addr = dst->writable_addr32(0, 0);
158
5
    size_t     rb = dst->rowBytes();
159
160
155
    for (int i = 0; i < count; i++) {
161
150
        int x = SkScalarFloorToInt(devPts[i].fX);
162
150
        int y = SkScalarFloorToInt(devPts[i].fY);
163
150
        if (r.contains(x, y)) {
164
28
            ((SkPMColor*)((char*)addr + y * rb))[x] = value;
165
28
        }
166
150
    }
167
5
}
168
169
static void bw_pt_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
170
7
                            int count, SkBlitter* blitter) {
171
217
    for (int i = 0; i < count; i++) {
172
210
        int x = SkScalarFloorToInt(devPts[i].fX);
173
210
        int y = SkScalarFloorToInt(devPts[i].fY);
174
210
        if (rec.fClip->contains(x, y)) {
175
105
            blitter->blitH(x, y, 1);
176
105
        }
177
210
    }
178
7
}
179
180
static void bw_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
181
75
                              int count, SkBlitter* blitter) {
182
150
    for (int i = 0; i < count; i += 2) {
183
75
        SkScan::HairLine(&devPts[i], 2, *rec.fRC, blitter);
184
75
    }
185
75
}
186
187
static void bw_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
188
4
                              int count, SkBlitter* blitter) {
189
4
    SkScan::HairLine(devPts, count, *rec.fRC, blitter);
190
4
}
191
192
// aa versions
193
194
static void aa_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
195
3.01k
                              int count, SkBlitter* blitter) {
196
6.03k
    for (int i = 0; i < count; i += 2) {
197
3.01k
        SkScan::AntiHairLine(&devPts[i], 2, *rec.fRC, blitter);
198
3.01k
    }
199
3.01k
}
200
201
static void aa_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
202
26
                              int count, SkBlitter* blitter) {
203
26
    SkScan::AntiHairLine(devPts, count, *rec.fRC, blitter);
204
26
}
205
206
// square procs (strokeWidth > 0 but matrix is square-scale (sx == sy)
207
208
1.05k
static SkRect make_square_rad(SkPoint center, SkScalar radius) {
209
1.05k
    return {
210
1.05k
        center.fX - radius, center.fY - radius,
211
1.05k
        center.fX + radius, center.fY + radius
212
1.05k
    };
213
1.05k
}
214
215
720
static SkXRect make_xrect(const SkRect& r) {
216
720
    SkASSERT(SkRectPriv::FitsInFixed(r));
217
720
    return {
218
720
        SkScalarToFixed(r.fLeft), SkScalarToFixed(r.fTop),
219
720
        SkScalarToFixed(r.fRight), SkScalarToFixed(r.fBottom)
220
720
    };
221
720
}
222
223
static void bw_square_proc(const PtProcRec& rec, const SkPoint devPts[],
224
7
                           int count, SkBlitter* blitter) {
225
217
    for (int i = 0; i < count; i++) {
226
210
        SkRect r = make_square_rad(devPts[i], rec.fRadius);
227
210
        if (r.intersect(rec.fClipBounds)) {
228
100
            SkScan::FillXRect(make_xrect(r), *rec.fRC, blitter);
229
100
        }
230
210
    }
231
7
}
232
233
static void aa_square_proc(const PtProcRec& rec, const SkPoint devPts[],
234
28
                           int count, SkBlitter* blitter) {
235
868
    for (int i = 0; i < count; i++) {
236
840
        SkRect r = make_square_rad(devPts[i], rec.fRadius);
237
840
        if (r.intersect(rec.fClipBounds)) {
238
620
            SkScan::AntiFillXRect(make_xrect(r), *rec.fRC, blitter);
239
620
        }
240
840
    }
241
28
}
242
243
// If this returns true, then chooseProc() must return a valid proc
244
bool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint,
245
8.25k
                     const SkMatrix* matrix, const SkRasterClip* rc) {
246
8.25k
    if ((unsigned)mode > (unsigned)SkCanvas::kPolygon_PointMode) {
247
0
        return false;
248
0
    }
249
8.25k
    if (paint.getPathEffect()) {
250
2.95k
        return false;
251
2.95k
    }
252
5.30k
    SkScalar width = paint.getStrokeWidth();
253
5.30k
    SkScalar radius = -1;   // sentinel value, a "valid" value must be > 0
254
255
5.30k
    if (0 == width) {
256
3.16k
        radius = 0.5f;
257
2.13k
    } else if (paint.getStrokeCap() != SkPaint::kRound_Cap &&
258
1.79k
               matrix->isScaleTranslate() && SkCanvas::kPoints_PointMode == mode) {
259
30
        SkScalar sx = matrix->get(SkMatrix::kMScaleX);
260
30
        SkScalar sy = matrix->get(SkMatrix::kMScaleY);
261
30
        if (SkScalarNearlyZero(sx - sy)) {
262
30
            radius = SkScalarHalf(width * SkScalarAbs(sx));
263
30
        }
264
30
    }
265
5.30k
    if (radius > 0) {
266
3.19k
        SkRect clipBounds = SkRect::Make(rc->getBounds());
267
        // if we return true, the caller may assume that the constructed shapes can be represented
268
        // using SkFixed (after clipping), so we preflight that here.
269
3.19k
        if (!SkRectPriv::FitsInFixed(clipBounds)) {
270
0
            return false;
271
0
        }
272
3.19k
        fMode = mode;
273
3.19k
        fPaint = &paint;
274
3.19k
        fClip = nullptr;
275
3.19k
        fRC = rc;
276
3.19k
        fClipBounds = clipBounds;
277
3.19k
        fRadius = radius;
278
3.19k
        return true;
279
3.19k
    }
280
2.11k
    return false;
281
2.11k
}
282
283
3.19k
PtProcRec::Proc PtProcRec::chooseProc(SkBlitter** blitterPtr) {
284
3.19k
    Proc proc = nullptr;
285
286
3.19k
    SkBlitter* blitter = *blitterPtr;
287
3.19k
    if (fRC->isBW()) {
288
3.17k
        fClip = &fRC->bwRgn();
289
18
    } else {
290
18
        fWrapper.init(*fRC, blitter);
291
18
        fClip = &fWrapper.getRgn();
292
18
        blitter = fWrapper.getBlitter();
293
18
        *blitterPtr = blitter;
294
18
    }
295
296
    // for our arrays
297
3.19k
    SkASSERT(0 == SkCanvas::kPoints_PointMode);
298
3.19k
    SkASSERT(1 == SkCanvas::kLines_PointMode);
299
3.19k
    SkASSERT(2 == SkCanvas::kPolygon_PointMode);
300
3.19k
    SkASSERT((unsigned)fMode <= (unsigned)SkCanvas::kPolygon_PointMode);
301
302
3.19k
    if (fPaint->isAntiAlias()) {
303
3.07k
        if (0 == fPaint->getStrokeWidth()) {
304
3.06k
            static const Proc gAAProcs[] = {
305
3.06k
                aa_square_proc, aa_line_hair_proc, aa_poly_hair_proc
306
3.06k
            };
307
3.06k
            proc = gAAProcs[fMode];
308
11
        } else if (fPaint->getStrokeCap() != SkPaint::kRound_Cap) {
309
11
            SkASSERT(SkCanvas::kPoints_PointMode == fMode);
310
11
            proc = aa_square_proc;
311
11
        }
312
115
    } else {    // BW
313
115
        if (fRadius <= 0.5f) {    // small radii and hairline
314
108
            if (SkCanvas::kPoints_PointMode == fMode && fClip->isRect()) {
315
19
                uint32_t value;
316
19
                const SkPixmap* bm = blitter->justAnOpaqueColor(&value);
317
19
                if (bm && kRGB_565_SkColorType == bm->colorType()) {
318
0
                    proc = bw_pt_rect_16_hair_proc;
319
19
                } else if (bm && kN32_SkColorType == bm->colorType()) {
320
6
                    proc = bw_pt_rect_32_hair_proc;
321
13
                } else {
322
13
                    proc = bw_pt_rect_hair_proc;
323
13
                }
324
89
            } else {
325
89
                static Proc gBWProcs[] = {
326
89
                    bw_pt_hair_proc, bw_line_hair_proc, bw_poly_hair_proc
327
89
                };
328
89
                proc = gBWProcs[fMode];
329
89
            }
330
7
        } else {
331
7
            proc = bw_square_proc;
332
7
        }
333
115
    }
334
3.19k
    return proc;
335
3.19k
}
336
337
// each of these costs 8-bytes of stack space, so don't make it too large
338
// must be even for lines/polygon to work
339
3.19k
#define MAX_DEV_PTS     32
340
341
void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count,
342
                        const SkPoint pts[], const SkPaint& paint,
343
8.29k
                        SkBaseDevice* device) const {
344
    // if we're in lines mode, force count to be even
345
8.29k
    if (SkCanvas::kLines_PointMode == mode) {
346
7.55k
        count &= ~(size_t)1;
347
7.55k
    }
348
349
8.29k
    if ((long)count <= 0) {
350
0
        return;
351
0
    }
352
353
8.29k
    SkASSERT(pts != nullptr);
354
8.29k
    SkDEBUGCODE(this->validate();)
355
356
     // nothing to draw
357
8.29k
    if (fRC->isEmpty()) {
358
1
        return;
359
1
    }
360
361
8.29k
    SkMatrix ctm = fMatrixProvider->localToDevice();
362
8.29k
    PtProcRec rec;
363
8.29k
    if (!device && rec.init(mode, paint, &ctm, fRC)) {
364
3.19k
        SkAutoBlitterChoose blitter(*this, nullptr, paint);
365
366
3.19k
        SkPoint             devPts[MAX_DEV_PTS];
367
3.19k
        SkBlitter*          bltr = blitter.get();
368
3.19k
        PtProcRec::Proc     proc = rec.chooseProc(&bltr);
369
        // we have to back up subsequent passes if we're in polygon mode
370
3.19k
        const size_t backup = (SkCanvas::kPolygon_PointMode == mode);
371
372
3.19k
        do {
373
3.19k
            int n = SkToInt(count);
374
3.19k
            if (n > MAX_DEV_PTS) {
375
0
                n = MAX_DEV_PTS;
376
0
            }
377
3.19k
            ctm.mapPoints(devPts, pts, n);
378
3.19k
            if (!SkScalarsAreFinite(&devPts[0].fX, n * 2)) {
379
10
                return;
380
10
            }
381
3.18k
            proc(rec, devPts, n, bltr);
382
3.18k
            pts += n - backup;
383
3.18k
            SkASSERT(SkToInt(count) >= n);
384
3.18k
            count -= n;
385
3.18k
            if (count > 0) {
386
0
                count += backup;
387
0
            }
388
3.18k
        } while (count != 0);
389
5.10k
    } else {
390
5.10k
        switch (mode) {
391
33
            case SkCanvas::kPoints_PointMode: {
392
                // temporarily mark the paint as filling.
393
33
                SkPaint newPaint(paint);
394
33
                newPaint.setStyle(SkPaint::kFill_Style);
395
396
33
                SkScalar width = newPaint.getStrokeWidth();
397
33
                SkScalar radius = SkScalarHalf(width);
398
399
33
                if (newPaint.getStrokeCap() == SkPaint::kRound_Cap) {
400
7
                    if (device) {
401
0
                        for (size_t i = 0; i < count; ++i) {
402
0
                            SkRect r = SkRect::MakeLTRB(pts[i].fX - radius, pts[i].fY - radius,
403
0
                                                        pts[i].fX + radius, pts[i].fY + radius);
404
0
                            device->drawOval(r, newPaint);
405
0
                        }
406
7
                    } else {
407
7
                        SkPath     path;
408
7
                        SkMatrix   preMatrix;
409
410
7
                        path.addCircle(0, 0, radius);
411
217
                        for (size_t i = 0; i < count; i++) {
412
210
                            preMatrix.setTranslate(pts[i].fX, pts[i].fY);
413
                            // pass true for the last point, since we can modify
414
                            // then path then
415
210
                            path.setIsVolatile((count-1) == i);
416
210
                            this->drawPath(path, newPaint, &preMatrix, (count-1) == i);
417
210
                        }
418
7
                    }
419
26
                } else {
420
26
                    SkRect  r;
421
422
780
                    for (size_t i = 0; i < count; i++) {
423
754
                        r.fLeft = pts[i].fX - radius;
424
754
                        r.fTop = pts[i].fY - radius;
425
754
                        r.fRight = r.fLeft + width;
426
754
                        r.fBottom = r.fTop + width;
427
754
                        if (device) {
428
94
                            device->drawRect(r, newPaint);
429
660
                        } else {
430
660
                            this->drawRect(r, newPaint);
431
660
                        }
432
754
                    }
433
26
                }
434
33
                break;
435
0
            }
436
4.46k
            case SkCanvas::kLines_PointMode:
437
4.46k
                if (2 == count && paint.getPathEffect()) {
438
                    // most likely a dashed line - see if it is one of the ones
439
                    // we can accelerate
440
2.56k
                    SkStrokeRec stroke(paint);
441
2.56k
                    SkPathEffectBase::PointData pointData;
442
443
2.56k
                    SkPath path = SkPath::Line(pts[0], pts[1]);
444
445
2.56k
                    SkRect cullRect = SkRect::Make(fRC->getBounds());
446
447
2.56k
                    if (as_PEB(paint.getPathEffect())->asPoints(&pointData, path, stroke, ctm,
448
0
                                                                &cullRect)) {
449
                        // 'asPoints' managed to find some fast path
450
451
0
                        SkPaint newP(paint);
452
0
                        newP.setPathEffect(nullptr);
453
0
                        newP.setStyle(SkPaint::kFill_Style);
454
455
0
                        if (!pointData.fFirst.isEmpty()) {
456
0
                            if (device) {
457
0
                                device->drawPath(pointData.fFirst, newP);
458
0
                            } else {
459
0
                                this->drawPath(pointData.fFirst, newP);
460
0
                            }
461
0
                        }
462
463
0
                        if (!pointData.fLast.isEmpty()) {
464
0
                            if (device) {
465
0
                                device->drawPath(pointData.fLast, newP);
466
0
                            } else {
467
0
                                this->drawPath(pointData.fLast, newP);
468
0
                            }
469
0
                        }
470
471
0
                        if (pointData.fSize.fX == pointData.fSize.fY) {
472
                            // The rest of the dashed line can just be drawn as points
473
0
                            SkASSERT(pointData.fSize.fX == SkScalarHalf(newP.getStrokeWidth()));
474
475
0
                            if (SkPathEffectBase::PointData::kCircles_PointFlag & pointData.fFlags) {
476
0
                                newP.setStrokeCap(SkPaint::kRound_Cap);
477
0
                            } else {
478
0
                                newP.setStrokeCap(SkPaint::kButt_Cap);
479
0
                            }
480
481
0
                            if (device) {
482
0
                                device->drawPoints(SkCanvas::kPoints_PointMode,
483
0
                                                   pointData.fNumPoints,
484
0
                                                   pointData.fPoints,
485
0
                                                   newP);
486
0
                            } else {
487
0
                                this->drawPoints(SkCanvas::kPoints_PointMode,
488
0
                                                 pointData.fNumPoints,
489
0
                                                 pointData.fPoints,
490
0
                                                 newP,
491
0
                                                 device);
492
0
                            }
493
0
                            break;
494
0
                        } else {
495
                            // The rest of the dashed line must be drawn as rects
496
0
                            SkASSERT(!(SkPathEffectBase::PointData::kCircles_PointFlag &
497
0
                                      pointData.fFlags));
498
499
0
                            SkRect r;
500
501
0
                            for (int i = 0; i < pointData.fNumPoints; ++i) {
502
0
                                r.setLTRB(pointData.fPoints[i].fX - pointData.fSize.fX,
503
0
                                          pointData.fPoints[i].fY - pointData.fSize.fY,
504
0
                                          pointData.fPoints[i].fX + pointData.fSize.fX,
505
0
                                          pointData.fPoints[i].fY + pointData.fSize.fY);
506
0
                                if (device) {
507
0
                                    device->drawRect(r, newP);
508
0
                                } else {
509
0
                                    this->drawRect(r, newP);
510
0
                                }
511
0
                            }
512
0
                        }
513
514
0
                        break;
515
4.46k
                    }
516
2.56k
                }
517
4.46k
                [[fallthrough]]; // couldn't take fast path
518
5.07k
            case SkCanvas::kPolygon_PointMode: {
519
5.07k
                count -= 1;
520
5.07k
                SkPath path;
521
5.07k
                SkPaint p(paint);
522
5.07k
                p.setStyle(SkPaint::kStroke_Style);
523
4.46k
                size_t inc = (SkCanvas::kLines_PointMode == mode) ? 2 : 1;
524
5.07k
                path.setIsVolatile(true);
525
27.2k
                for (size_t i = 0; i < count; i += inc) {
526
22.1k
                    path.moveTo(pts[i]);
527
22.1k
                    path.lineTo(pts[i+1]);
528
22.1k
                    if (device) {
529
1.21k
                        device->drawPath(path, p, true);
530
20.9k
                    } else {
531
20.9k
                        this->drawPath(path, p, nullptr, true);
532
20.9k
                    }
533
22.1k
                    path.rewind();
534
22.1k
                }
535
5.07k
                break;
536
4.46k
            }
537
5.10k
        }
538
5.10k
    }
539
8.29k
}
540
541
1.14k
static inline SkPoint compute_stroke_size(const SkPaint& paint, const SkMatrix& matrix) {
542
1.14k
    SkASSERT(matrix.rectStaysRect());
543
1.14k
    SkASSERT(SkPaint::kFill_Style != paint.getStyle());
544
545
1.14k
    SkVector size;
546
1.14k
    SkPoint pt = { paint.getStrokeWidth(), paint.getStrokeWidth() };
547
1.14k
    matrix.mapVectors(&size, &pt, 1);
548
1.14k
    return SkPoint::Make(SkScalarAbs(size.fX), SkScalarAbs(size.fY));
549
1.14k
}
550
551
static bool easy_rect_join(const SkRect& rect, const SkPaint& paint, const SkMatrix& matrix,
552
1.63k
                           SkPoint* strokeSize) {
553
1.63k
    if (rect.isEmpty() || SkPaint::kMiter_Join != paint.getStrokeJoin() ||
554
1.21k
        paint.getStrokeMiter() < SK_ScalarSqrt2) {
555
489
        return false;
556
489
    }
557
558
1.14k
    *strokeSize = compute_stroke_size(paint, matrix);
559
1.14k
    return true;
560
1.14k
}
561
562
SkDraw::RectType SkDraw::ComputeRectType(const SkRect& rect,
563
                                         const SkPaint& paint,
564
                                         const SkMatrix& matrix,
565
69.0k
                                         SkPoint* strokeSize) {
566
69.0k
    RectType rtype;
567
69.0k
    const SkScalar width = paint.getStrokeWidth();
568
69.0k
    const bool zeroWidth = (0 == width);
569
69.0k
    SkPaint::Style style = paint.getStyle();
570
571
69.0k
    if ((SkPaint::kStrokeAndFill_Style == style) && zeroWidth) {
572
80
        style = SkPaint::kFill_Style;
573
80
    }
574
575
69.0k
    if (paint.getPathEffect() || paint.getMaskFilter() ||
576
68.2k
        !matrix.rectStaysRect() || SkPaint::kStrokeAndFill_Style == style) {
577
27.9k
        rtype = kPath_RectType;
578
41.0k
    } else if (SkPaint::kFill_Style == style) {
579
39.3k
        rtype = kFill_RectType;
580
1.71k
    } else if (zeroWidth) {
581
81
        rtype = kHair_RectType;
582
1.63k
    } else if (easy_rect_join(rect, paint, matrix, strokeSize)) {
583
1.14k
        rtype = kStroke_RectType;
584
489
    } else {
585
489
        rtype = kPath_RectType;
586
489
    }
587
69.0k
    return rtype;
588
69.0k
}
589
590
40.5k
static const SkPoint* rect_points(const SkRect& r) {
591
40.5k
    return reinterpret_cast<const SkPoint*>(&r);
592
40.5k
}
593
594
40.5k
static SkPoint* rect_points(SkRect& r) {
595
40.5k
    return reinterpret_cast<SkPoint*>(&r);
596
40.5k
}
597
598
static void draw_rect_as_path(const SkDraw& orig, const SkRect& prePaintRect,
599
56.2k
                              const SkPaint& paint, const SkMatrixProvider* matrixProvider) {
600
56.2k
    SkDraw draw(orig);
601
56.2k
    draw.fMatrixProvider = matrixProvider;
602
56.2k
    SkPath  tmp;
603
56.2k
    tmp.addRect(prePaintRect);
604
56.2k
    tmp.setFillType(SkPathFillType::kWinding);
605
56.2k
    draw.drawPath(tmp, paint, nullptr, true);
606
56.2k
}
607
608
void SkDraw::drawRect(const SkRect& prePaintRect, const SkPaint& paint,
609
69.0k
                      const SkMatrix* paintMatrix, const SkRect* postPaintRect) const {
610
69.0k
    SkDEBUGCODE(this->validate();)
611
612
    // nothing to draw
613
69.0k
    if (fRC->isEmpty()) {
614
7
        return;
615
7
    }
616
617
69.0k
    const SkMatrixProvider* matrixProvider = fMatrixProvider;
618
69.0k
    SkTLazy<SkPreConcatMatrixProvider> preConcatMatrixProvider;
619
69.0k
    if (paintMatrix) {
620
29.6k
        SkASSERT(postPaintRect);
621
29.6k
        matrixProvider = preConcatMatrixProvider.init(*matrixProvider, *paintMatrix);
622
39.4k
    } else {
623
39.4k
        SkASSERT(!postPaintRect);
624
39.4k
    }
625
626
69.0k
    SkMatrix ctm = fMatrixProvider->localToDevice();
627
69.0k
    SkPoint strokeSize;
628
69.0k
    RectType rtype = ComputeRectType(prePaintRect, paint, ctm, &strokeSize);
629
630
69.0k
    if (kPath_RectType == rtype) {
631
28.4k
        draw_rect_as_path(*this, prePaintRect, paint, matrixProvider);
632
28.4k
        return;
633
28.4k
    }
634
635
40.5k
    SkRect devRect;
636
36.9k
    const SkRect& paintRect = paintMatrix ? *postPaintRect : prePaintRect;
637
    // skip the paintMatrix when transforming the rect by the CTM
638
40.5k
    ctm.mapPoints(rect_points(devRect), rect_points(paintRect), 2);
639
40.5k
    devRect.sort();
640
641
    // look for the quick exit, before we build a blitter
642
40.5k
    SkRect bbox = devRect;
643
40.5k
    if (paint.getStyle() != SkPaint::kFill_Style) {
644
        // extra space for hairlines
645
1.25k
        if (paint.getStrokeWidth() == 0) {
646
112
            bbox.outset(1, 1);
647
1.14k
        } else {
648
            // For kStroke_RectType, strokeSize is already computed.
649
1.14k
            const SkPoint& ssize = (kStroke_RectType == rtype)
650
1.14k
                ? strokeSize
651
0
                : compute_stroke_size(paint, ctm);
652
1.14k
            bbox.outset(SkScalarHalf(ssize.x()), SkScalarHalf(ssize.y()));
653
1.14k
        }
654
1.25k
    }
655
40.5k
    if (SkPathPriv::TooBigForMath(bbox)) {
656
28
        return;
657
28
    }
658
659
40.5k
    if (!SkRectPriv::FitsInFixed(bbox) && rtype != kHair_RectType) {
660
27.8k
        draw_rect_as_path(*this, prePaintRect, paint, matrixProvider);
661
27.8k
        return;
662
27.8k
    }
663
664
12.6k
    SkIRect ir = bbox.roundOut();
665
12.6k
    if (fRC->quickReject(ir)) {
666
138
        return;
667
138
    }
668
669
12.5k
    SkAutoBlitterChoose blitterStorage(*this, matrixProvider, paint);
670
12.5k
    const SkRasterClip& clip = *fRC;
671
12.5k
    SkBlitter*          blitter = blitterStorage.get();
672
673
    // we want to "fill" if we are kFill or kStrokeAndFill, since in the latter
674
    // case we are also hairline (if we've gotten to here), which devolves to
675
    // effectively just kFill
676
12.5k
    switch (rtype) {
677
11.3k
        case kFill_RectType:
678
11.3k
            if (paint.isAntiAlias()) {
679
2.11k
                SkScan::AntiFillRect(devRect, clip, blitter);
680
9.24k
            } else {
681
9.24k
                SkScan::FillRect(devRect, clip, blitter);
682
9.24k
            }
683
11.3k
            break;
684
1.11k
        case kStroke_RectType:
685
1.11k
            if (paint.isAntiAlias()) {
686
1.09k
                SkScan::AntiFrameRect(devRect, strokeSize, clip, blitter);
687
16
            } else {
688
16
                SkScan::FrameRect(devRect, strokeSize, clip, blitter);
689
16
            }
690
1.11k
            break;
691
81
        case kHair_RectType:
692
81
            if (paint.isAntiAlias()) {
693
61
                SkScan::AntiHairRect(devRect, clip, blitter);
694
20
            } else {
695
20
                SkScan::HairRect(devRect, clip, blitter);
696
20
            }
697
81
            break;
698
0
        default:
699
0
            SkDEBUGFAIL("bad rtype");
700
12.5k
    }
701
12.5k
}
702
703
83
void SkDraw::drawDevMask(const SkMask& srcM, const SkPaint& paint) const {
704
83
    if (srcM.fBounds.isEmpty()) {
705
0
        return;
706
0
    }
707
708
83
    const SkMask* mask = &srcM;
709
710
83
    SkMask dstM;
711
83
    if (paint.getMaskFilter() &&
712
0
        as_MFB(paint.getMaskFilter())
713
0
                ->filterMask(&dstM, srcM, fMatrixProvider->localToDevice(), nullptr)) {
714
0
        mask = &dstM;
715
0
    }
716
83
    SkAutoMaskFreeImage ami(dstM.fImage);
717
718
83
    SkAutoBlitterChoose blitterChooser(*this, nullptr, paint);
719
83
    SkBlitter* blitter = blitterChooser.get();
720
721
83
    SkAAClipBlitterWrapper wrapper;
722
83
    const SkRegion* clipRgn;
723
724
83
    if (fRC->isBW()) {
725
83
        clipRgn = &fRC->bwRgn();
726
0
    } else {
727
0
        wrapper.init(*fRC, blitter);
728
0
        clipRgn = &wrapper.getRgn();
729
0
        blitter = wrapper.getBlitter();
730
0
    }
731
83
    blitter->blitMaskRegion(*mask, *clipRgn);
732
83
}
733
734
85.8k
static SkScalar fast_len(const SkVector& vec) {
735
85.8k
    SkScalar x = SkScalarAbs(vec.fX);
736
85.8k
    SkScalar y = SkScalarAbs(vec.fY);
737
85.8k
    if (x < y) {
738
36.6k
        using std::swap;
739
36.6k
        swap(x, y);
740
36.6k
    }
741
85.8k
    return x + SkScalarHalf(y);
742
85.8k
}
743
744
bool SkDrawTreatAAStrokeAsHairline(SkScalar strokeWidth, const SkMatrix& matrix,
745
43.0k
                                   SkScalar* coverage) {
746
43.0k
    SkASSERT(strokeWidth > 0);
747
    // We need to try to fake a thick-stroke with a modulated hairline.
748
749
43.0k
    if (matrix.hasPerspective()) {
750
92
        return false;
751
92
    }
752
753
42.9k
    SkVector src[2], dst[2];
754
42.9k
    src[0].set(strokeWidth, 0);
755
42.9k
    src[1].set(0, strokeWidth);
756
42.9k
    matrix.mapVectors(dst, src, 2);
757
42.9k
    SkScalar len0 = fast_len(dst[0]);
758
42.9k
    SkScalar len1 = fast_len(dst[1]);
759
42.9k
    if (len0 <= SK_Scalar1 && len1 <= SK_Scalar1) {
760
20.5k
        if (coverage) {
761
19.4k
            *coverage = SkScalarAve(len0, len1);
762
19.4k
        }
763
20.5k
        return true;
764
20.5k
    }
765
22.3k
    return false;
766
22.3k
}
767
768
10.5k
void SkDraw::drawRRect(const SkRRect& rrect, const SkPaint& paint) const {
769
5.25k
    SkDEBUGCODE(this->validate());
770
771
10.5k
    if (fRC->isEmpty()) {
772
16
        return;
773
16
    }
774
775
10.5k
    SkMatrix ctm = fMatrixProvider->localToDevice();
776
10.5k
    {
777
        // TODO: Investigate optimizing these options. They are in the same
778
        // order as SkDraw::drawPath, which handles each case. It may be
779
        // that there is no way to optimize for these using the SkRRect path.
780
10.5k
        SkScalar coverage;
781
10.5k
        if (SkDrawTreatAsHairline(paint, ctm, &coverage)) {
782
2.00k
            goto DRAW_PATH;
783
2.00k
        }
784
785
8.49k
        if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
786
2.23k
            goto DRAW_PATH;
787
2.23k
        }
788
6.25k
    }
789
790
6.25k
    if (paint.getMaskFilter()) {
791
        // Transform the rrect into device space.
792
32
        SkRRect devRRect;
793
32
        if (rrect.transform(ctm, &devRRect)) {
794
28
            SkAutoBlitterChoose blitter(*this, nullptr, paint);
795
28
            if (as_MFB(paint.getMaskFilter())->filterRRect(devRRect, ctm, *fRC, blitter.get())) {
796
0
                return;  // filterRRect() called the blitter, so we're done
797
0
            }
798
10.5k
        }
799
32
    }
800
801
10.5k
DRAW_PATH:
802
    // Now fall back to the default case of using a path.
803
10.5k
    SkPath path;
804
10.5k
    path.addRRect(rrect);
805
10.5k
    this->drawPath(path, paint, nullptr, true);
806
10.5k
}
SkDraw::drawRRect(SkRRect const&, SkPaint const&) const
Line
Count
Source
768
5.25k
void SkDraw::drawRRect(const SkRRect& rrect, const SkPaint& paint) const {
769
5.25k
    SkDEBUGCODE(this->validate());
770
771
5.25k
    if (fRC->isEmpty()) {
772
8
        return;
773
8
    }
774
775
5.25k
    SkMatrix ctm = fMatrixProvider->localToDevice();
776
5.25k
    {
777
        // TODO: Investigate optimizing these options. They are in the same
778
        // order as SkDraw::drawPath, which handles each case. It may be
779
        // that there is no way to optimize for these using the SkRRect path.
780
5.25k
        SkScalar coverage;
781
5.25k
        if (SkDrawTreatAsHairline(paint, ctm, &coverage)) {
782
1.00k
            goto DRAW_PATH;
783
1.00k
        }
784
785
4.24k
        if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
786
1.11k
            goto DRAW_PATH;
787
1.11k
        }
788
3.12k
    }
789
790
3.12k
    if (paint.getMaskFilter()) {
791
        // Transform the rrect into device space.
792
16
        SkRRect devRRect;
793
16
        if (rrect.transform(ctm, &devRRect)) {
794
14
            SkAutoBlitterChoose blitter(*this, nullptr, paint);
795
14
            if (as_MFB(paint.getMaskFilter())->filterRRect(devRRect, ctm, *fRC, blitter.get())) {
796
0
                return;  // filterRRect() called the blitter, so we're done
797
0
            }
798
5.25k
        }
799
16
    }
800
801
5.25k
DRAW_PATH:
802
    // Now fall back to the default case of using a path.
803
5.25k
    SkPath path;
804
5.25k
    path.addRRect(rrect);
805
5.25k
    this->drawPath(path, paint, nullptr, true);
806
5.25k
}
SkDraw::drawRRect(SkRRect const&, SkPaint const&) const
Line
Count
Source
768
5.25k
void SkDraw::drawRRect(const SkRRect& rrect, const SkPaint& paint) const {
769
5.25k
    SkDEBUGCODE(this->validate());
770
771
5.25k
    if (fRC->isEmpty()) {
772
8
        return;
773
8
    }
774
775
5.25k
    SkMatrix ctm = fMatrixProvider->localToDevice();
776
5.25k
    {
777
        // TODO: Investigate optimizing these options. They are in the same
778
        // order as SkDraw::drawPath, which handles each case. It may be
779
        // that there is no way to optimize for these using the SkRRect path.
780
5.25k
        SkScalar coverage;
781
5.25k
        if (SkDrawTreatAsHairline(paint, ctm, &coverage)) {
782
1.00k
            goto DRAW_PATH;
783
1.00k
        }
784
785
4.24k
        if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
786
1.11k
            goto DRAW_PATH;
787
1.11k
        }
788
3.12k
    }
789
790
3.12k
    if (paint.getMaskFilter()) {
791
        // Transform the rrect into device space.
792
16
        SkRRect devRRect;
793
16
        if (rrect.transform(ctm, &devRRect)) {
794
14
            SkAutoBlitterChoose blitter(*this, nullptr, paint);
795
14
            if (as_MFB(paint.getMaskFilter())->filterRRect(devRRect, ctm, *fRC, blitter.get())) {
796
0
                return;  // filterRRect() called the blitter, so we're done
797
0
            }
798
5.25k
        }
799
16
    }
800
801
5.25k
DRAW_PATH:
802
    // Now fall back to the default case of using a path.
803
5.25k
    SkPath path;
804
5.25k
    path.addRRect(rrect);
805
5.25k
    this->drawPath(path, paint, nullptr, true);
806
5.25k
}
807
808
void SkDraw::drawDevPath(const SkPath& devPath, const SkPaint& paint, bool drawCoverage,
809
272k
                         SkBlitter* customBlitter, bool doFill) const {
810
272k
    if (SkPathPriv::TooBigForMath(devPath)) {
811
3.20k
        return;
812
3.20k
    }
813
269k
    SkBlitter* blitter = nullptr;
814
269k
    SkAutoBlitterChoose blitterStorage;
815
269k
    if (nullptr == customBlitter) {
816
269k
        blitter = blitterStorage.choose(*this, nullptr, paint, drawCoverage);
817
0
    } else {
818
0
        blitter = customBlitter;
819
0
    }
820
821
269k
    if (paint.getMaskFilter()) {
822
57.5k
        SkStrokeRec::InitStyle style = doFill ? SkStrokeRec::kFill_InitStyle
823
4.86k
                                              : SkStrokeRec::kHairline_InitStyle;
824
62.4k
        if (as_MFB(paint.getMaskFilter())
825
4.87k
                    ->filterPath(devPath, fMatrixProvider->localToDevice(), *fRC, blitter, style)) {
826
4.87k
            return;  // filterPath() called the blitter, so we're done
827
4.87k
        }
828
264k
    }
829
830
264k
    void (*proc)(const SkPath&, const SkRasterClip&, SkBlitter*);
831
264k
    if (doFill) {
832
234k
        if (paint.isAntiAlias()) {
833
185k
            proc = SkScan::AntiFillPath;
834
48.8k
        } else {
835
48.8k
            proc = SkScan::FillPath;
836
48.8k
        }
837
29.5k
    } else {    // hairline
838
29.5k
        if (paint.isAntiAlias()) {
839
23.2k
            switch (paint.getStrokeCap()) {
840
16.4k
                case SkPaint::kButt_Cap:
841
16.4k
                    proc = SkScan::AntiHairPath;
842
16.4k
                    break;
843
5.12k
                case SkPaint::kSquare_Cap:
844
5.12k
                    proc = SkScan::AntiHairSquarePath;
845
5.12k
                    break;
846
1.64k
                case SkPaint::kRound_Cap:
847
1.64k
                    proc = SkScan::AntiHairRoundPath;
848
1.64k
                    break;
849
0
                default:
850
0
                    proc SK_INIT_TO_AVOID_WARNING;
851
0
                    SkDEBUGFAIL("unknown paint cap type");
852
23.2k
            }
853
6.29k
        } else {
854
6.29k
            switch (paint.getStrokeCap()) {
855
3.35k
                case SkPaint::kButt_Cap:
856
3.35k
                    proc = SkScan::HairPath;
857
3.35k
                    break;
858
2.81k
                case SkPaint::kSquare_Cap:
859
2.81k
                    proc = SkScan::HairSquarePath;
860
2.81k
                    break;
861
136
                case SkPaint::kRound_Cap:
862
136
                    proc = SkScan::HairRoundPath;
863
136
                    break;
864
0
                default:
865
0
                    proc SK_INIT_TO_AVOID_WARNING;
866
0
                    SkDEBUGFAIL("unknown paint cap type");
867
6.29k
            }
868
6.29k
        }
869
29.5k
    }
870
871
264k
    proc(devPath, *fRC, blitter);
872
264k
}
873
874
void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint,
875
                      const SkMatrix* prePathMatrix, bool pathIsMutable,
876
544k
                      bool drawCoverage, SkBlitter* customBlitter) const {
877
272k
    SkDEBUGCODE(this->validate();)
878
879
    // nothing to draw
880
544k
    if (fRC->isEmpty()) {
881
38
        return;
882
38
    }
883
884
544k
    SkPath*         pathPtr = (SkPath*)&origSrcPath;
885
544k
    bool            doFill = true;
886
544k
    SkPath          tmpPathStorage;
887
544k
    SkPath*         tmpPath = &tmpPathStorage;
888
544k
    const SkMatrixProvider*            matrixProvider = fMatrixProvider;
889
544k
    SkTLazy<SkPreConcatMatrixProvider> preConcatMatrixProvider;
890
544k
    tmpPath->setIsVolatile(true);
891
892
544k
    if (prePathMatrix) {
893
111k
        if (origPaint.getPathEffect() || origPaint.getStyle() != SkPaint::kFill_Style) {
894
22.7k
            SkPath* result = pathPtr;
895
896
22.7k
            if (!pathIsMutable) {
897
22.7k
                result = tmpPath;
898
22.7k
                pathIsMutable = true;
899
22.7k
            }
900
22.7k
            pathPtr->transform(*prePathMatrix, result);
901
22.7k
            pathPtr = result;
902
88.8k
        } else {
903
88.8k
            matrixProvider = preConcatMatrixProvider.init(*matrixProvider, *prePathMatrix);
904
88.8k
        }
905
111k
    }
906
907
544k
    SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
908
909
544k
    {
910
544k
        SkScalar coverage;
911
544k
        if (SkDrawTreatAsHairline(origPaint, matrixProvider->localToDevice(), &coverage)) {
912
64.7k
            const auto bm = origPaint.asBlendMode();
913
64.7k
            if (SK_Scalar1 == coverage) {
914
51.2k
                paint.writable()->setStrokeWidth(0);
915
13.5k
            } else if (bm && SkBlendMode_SupportsCoverageAsAlpha(bm.value())) {
916
11.0k
                U8CPU newAlpha;
917
#if 0
918
                newAlpha = SkToU8(SkScalarRoundToInt(coverage *
919
                                                     origPaint.getAlpha()));
920
#else
921
                // this is the old technique, which we preserve for now so
922
                // we don't change previous results (testing)
923
                // the new way seems fine, its just (a tiny bit) different
924
11.0k
                int scale = (int)(coverage * 256);
925
11.0k
                newAlpha = origPaint.getAlpha() * scale >> 8;
926
11.0k
#endif
927
11.0k
                SkPaint* writablePaint = paint.writable();
928
11.0k
                writablePaint->setStrokeWidth(0);
929
11.0k
                writablePaint->setAlpha(newAlpha);
930
11.0k
            }
931
64.7k
        }
932
544k
    }
933
934
544k
    if (paint->getPathEffect() || paint->getStyle() != SkPaint::kFill_Style) {
935
230k
        SkRect cullRect;
936
230k
        const SkRect* cullRectPtr = nullptr;
937
230k
        if (this->computeConservativeLocalClipBounds(&cullRect)) {
938
224k
            cullRectPtr = &cullRect;
939
224k
        }
940
230k
        doFill = paint->getFillPath(*pathPtr, tmpPath, cullRectPtr,
941
230k
                                    fMatrixProvider->localToDevice());
942
230k
        pathPtr = tmpPath;
943
230k
    }
944
945
    // avoid possibly allocating a new path in transform if we can
946
349k
    SkPath* devPathPtr = pathIsMutable ? pathPtr : tmpPath;
947
948
    // transform the path into device space
949
544k
    pathPtr->transform(matrixProvider->localToDevice(), devPathPtr);
950
951
#if defined(SK_BUILD_FOR_FUZZER)
952
    if (devPathPtr->countPoints() > 1000) {
953
        return;
954
    }
955
#endif
956
957
544k
    this->drawDevPath(*devPathPtr, *paint, drawCoverage, customBlitter, doFill);
958
544k
}
SkDraw::drawPath(SkPath const&, SkPaint const&, SkMatrix const*, bool, bool, SkBlitter*) const
Line
Count
Source
876
272k
                      bool drawCoverage, SkBlitter* customBlitter) const {
877
272k
    SkDEBUGCODE(this->validate();)
878
879
    // nothing to draw
880
272k
    if (fRC->isEmpty()) {
881
19
        return;
882
19
    }
883
884
272k
    SkPath*         pathPtr = (SkPath*)&origSrcPath;
885
272k
    bool            doFill = true;
886
272k
    SkPath          tmpPathStorage;
887
272k
    SkPath*         tmpPath = &tmpPathStorage;
888
272k
    const SkMatrixProvider*            matrixProvider = fMatrixProvider;
889
272k
    SkTLazy<SkPreConcatMatrixProvider> preConcatMatrixProvider;
890
272k
    tmpPath->setIsVolatile(true);
891
892
272k
    if (prePathMatrix) {
893
55.8k
        if (origPaint.getPathEffect() || origPaint.getStyle() != SkPaint::kFill_Style) {
894
11.3k
            SkPath* result = pathPtr;
895
896
11.3k
            if (!pathIsMutable) {
897
11.3k
                result = tmpPath;
898
11.3k
                pathIsMutable = true;
899
11.3k
            }
900
11.3k
            pathPtr->transform(*prePathMatrix, result);
901
11.3k
            pathPtr = result;
902
44.4k
        } else {
903
44.4k
            matrixProvider = preConcatMatrixProvider.init(*matrixProvider, *prePathMatrix);
904
44.4k
        }
905
55.8k
    }
906
907
272k
    SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
908
909
272k
    {
910
272k
        SkScalar coverage;
911
272k
        if (SkDrawTreatAsHairline(origPaint, matrixProvider->localToDevice(), &coverage)) {
912
32.3k
            const auto bm = origPaint.asBlendMode();
913
32.3k
            if (SK_Scalar1 == coverage) {
914
25.6k
                paint.writable()->setStrokeWidth(0);
915
6.76k
            } else if (bm && SkBlendMode_SupportsCoverageAsAlpha(bm.value())) {
916
5.53k
                U8CPU newAlpha;
917
#if 0
918
                newAlpha = SkToU8(SkScalarRoundToInt(coverage *
919
                                                     origPaint.getAlpha()));
920
#else
921
                // this is the old technique, which we preserve for now so
922
                // we don't change previous results (testing)
923
                // the new way seems fine, its just (a tiny bit) different
924
5.53k
                int scale = (int)(coverage * 256);
925
5.53k
                newAlpha = origPaint.getAlpha() * scale >> 8;
926
5.53k
#endif
927
5.53k
                SkPaint* writablePaint = paint.writable();
928
5.53k
                writablePaint->setStrokeWidth(0);
929
5.53k
                writablePaint->setAlpha(newAlpha);
930
5.53k
            }
931
32.3k
        }
932
272k
    }
933
934
272k
    if (paint->getPathEffect() || paint->getStyle() != SkPaint::kFill_Style) {
935
115k
        SkRect cullRect;
936
115k
        const SkRect* cullRectPtr = nullptr;
937
115k
        if (this->computeConservativeLocalClipBounds(&cullRect)) {
938
112k
            cullRectPtr = &cullRect;
939
112k
        }
940
115k
        doFill = paint->getFillPath(*pathPtr, tmpPath, cullRectPtr,
941
115k
                                    fMatrixProvider->localToDevice());
942
115k
        pathPtr = tmpPath;
943
115k
    }
944
945
    // avoid possibly allocating a new path in transform if we can
946
174k
    SkPath* devPathPtr = pathIsMutable ? pathPtr : tmpPath;
947
948
    // transform the path into device space
949
272k
    pathPtr->transform(matrixProvider->localToDevice(), devPathPtr);
950
951
#if defined(SK_BUILD_FOR_FUZZER)
952
    if (devPathPtr->countPoints() > 1000) {
953
        return;
954
    }
955
#endif
956
957
272k
    this->drawDevPath(*devPathPtr, *paint, drawCoverage, customBlitter, doFill);
958
272k
}
SkDraw::drawPath(SkPath const&, SkPaint const&, SkMatrix const*, bool, bool, SkBlitter*) const
Line
Count
Source
876
272k
                      bool drawCoverage, SkBlitter* customBlitter) const {
877
272k
    SkDEBUGCODE(this->validate();)
878
879
    // nothing to draw
880
272k
    if (fRC->isEmpty()) {
881
19
        return;
882
19
    }
883
884
272k
    SkPath*         pathPtr = (SkPath*)&origSrcPath;
885
272k
    bool            doFill = true;
886
272k
    SkPath          tmpPathStorage;
887
272k
    SkPath*         tmpPath = &tmpPathStorage;
888
272k
    const SkMatrixProvider*            matrixProvider = fMatrixProvider;
889
272k
    SkTLazy<SkPreConcatMatrixProvider> preConcatMatrixProvider;
890
272k
    tmpPath->setIsVolatile(true);
891
892
272k
    if (prePathMatrix) {
893
55.8k
        if (origPaint.getPathEffect() || origPaint.getStyle() != SkPaint::kFill_Style) {
894
11.3k
            SkPath* result = pathPtr;
895
896
11.3k
            if (!pathIsMutable) {
897
11.3k
                result = tmpPath;
898
11.3k
                pathIsMutable = true;
899
11.3k
            }
900
11.3k
            pathPtr->transform(*prePathMatrix, result);
901
11.3k
            pathPtr = result;
902
44.4k
        } else {
903
44.4k
            matrixProvider = preConcatMatrixProvider.init(*matrixProvider, *prePathMatrix);
904
44.4k
        }
905
55.8k
    }
906
907
272k
    SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
908
909
272k
    {
910
272k
        SkScalar coverage;
911
272k
        if (SkDrawTreatAsHairline(origPaint, matrixProvider->localToDevice(), &coverage)) {
912
32.3k
            const auto bm = origPaint.asBlendMode();
913
32.3k
            if (SK_Scalar1 == coverage) {
914
25.6k
                paint.writable()->setStrokeWidth(0);
915
6.76k
            } else if (bm && SkBlendMode_SupportsCoverageAsAlpha(bm.value())) {
916
5.53k
                U8CPU newAlpha;
917
#if 0
918
                newAlpha = SkToU8(SkScalarRoundToInt(coverage *
919
                                                     origPaint.getAlpha()));
920
#else
921
                // this is the old technique, which we preserve for now so
922
                // we don't change previous results (testing)
923
                // the new way seems fine, its just (a tiny bit) different
924
5.53k
                int scale = (int)(coverage * 256);
925
5.53k
                newAlpha = origPaint.getAlpha() * scale >> 8;
926
5.53k
#endif
927
5.53k
                SkPaint* writablePaint = paint.writable();
928
5.53k
                writablePaint->setStrokeWidth(0);
929
5.53k
                writablePaint->setAlpha(newAlpha);
930
5.53k
            }
931
32.3k
        }
932
272k
    }
933
934
272k
    if (paint->getPathEffect() || paint->getStyle() != SkPaint::kFill_Style) {
935
115k
        SkRect cullRect;
936
115k
        const SkRect* cullRectPtr = nullptr;
937
115k
        if (this->computeConservativeLocalClipBounds(&cullRect)) {
938
112k
            cullRectPtr = &cullRect;
939
112k
        }
940
115k
        doFill = paint->getFillPath(*pathPtr, tmpPath, cullRectPtr,
941
115k
                                    fMatrixProvider->localToDevice());
942
115k
        pathPtr = tmpPath;
943
115k
    }
944
945
    // avoid possibly allocating a new path in transform if we can
946
174k
    SkPath* devPathPtr = pathIsMutable ? pathPtr : tmpPath;
947
948
    // transform the path into device space
949
272k
    pathPtr->transform(matrixProvider->localToDevice(), devPathPtr);
950
951
#if defined(SK_BUILD_FOR_FUZZER)
952
    if (devPathPtr->countPoints() > 1000) {
953
        return;
954
    }
955
#endif
956
957
272k
    this->drawDevPath(*devPathPtr, *paint, drawCoverage, customBlitter, doFill);
958
272k
}
959
960
void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, const SkSamplingOptions& sampling,
961
84
                              const SkPaint& paint) const {
962
84
    SkASSERT(bitmap.colorType() == kAlpha_8_SkColorType);
963
964
    // nothing to draw
965
84
    if (fRC->isEmpty()) {
966
0
        return;
967
0
    }
968
969
84
    SkMatrix ctm = fMatrixProvider->localToDevice();
970
84
    if (SkTreatAsSprite(ctm, bitmap.dimensions(), sampling, paint))
971
18
    {
972
18
        int ix = SkScalarRoundToInt(ctm.getTranslateX());
973
18
        int iy = SkScalarRoundToInt(ctm.getTranslateY());
974
975
18
        SkPixmap pmap;
976
18
        if (!bitmap.peekPixels(&pmap)) {
977
0
            return;
978
0
        }
979
18
        SkMask  mask;
980
18
        mask.fBounds.setXYWH(ix, iy, pmap.width(), pmap.height());
981
18
        mask.fFormat = SkMask::kA8_Format;
982
18
        mask.fRowBytes = SkToU32(pmap.rowBytes());
983
        // fImage is typed as writable, but in this case it is used read-only
984
18
        mask.fImage = (uint8_t*)pmap.addr8(0, 0);
985
986
18
        this->drawDevMask(mask, paint);
987
66
    } else {    // need to xform the bitmap first
988
66
        SkRect  r;
989
66
        SkMask  mask;
990
991
66
        r.setIWH(bitmap.width(), bitmap.height());
992
66
        ctm.mapRect(&r);
993
66
        r.round(&mask.fBounds);
994
995
        // set the mask's bounds to the transformed bitmap-bounds,
996
        // clipped to the actual device and further limited by the clip bounds
997
66
        {
998
66
            SkASSERT(fDst.bounds().contains(fRC->getBounds()));
999
66
            SkIRect devBounds = fDst.bounds();
1000
66
            devBounds.intersect(fRC->getBounds().makeOutset(1, 1));
1001
            // need intersect(l, t, r, b) on irect
1002
66
            if (!mask.fBounds.intersect(devBounds)) {
1003
1
                return;
1004
1
            }
1005
65
        }
1006
1007
65
        mask.fFormat = SkMask::kA8_Format;
1008
65
        mask.fRowBytes = SkAlign4(mask.fBounds.width());
1009
65
        size_t size = mask.computeImageSize();
1010
65
        if (0 == size) {
1011
            // the mask is too big to allocated, draw nothing
1012
0
            return;
1013
0
        }
1014
1015
        // allocate (and clear) our temp buffer to hold the transformed bitmap
1016
65
        SkAutoTMalloc<uint8_t> storage(size);
1017
65
        mask.fImage = storage.get();
1018
65
        memset(mask.fImage, 0, size);
1019
1020
        // now draw our bitmap(src) into mask(dst), transformed by the matrix
1021
65
        {
1022
65
            SkBitmap    device;
1023
65
            device.installPixels(SkImageInfo::MakeA8(mask.fBounds.width(), mask.fBounds.height()),
1024
65
                                 mask.fImage, mask.fRowBytes);
1025
1026
65
            SkCanvas c(device);
1027
            // need the unclipped top/left for the translate
1028
65
            c.translate(-SkIntToScalar(mask.fBounds.fLeft),
1029
65
                        -SkIntToScalar(mask.fBounds.fTop));
1030
65
            c.concat(ctm);
1031
1032
            // We can't call drawBitmap, or we'll infinitely recurse. Instead
1033
            // we manually build a shader and draw that into our new mask
1034
65
            SkPaint tmpPaint;
1035
65
            tmpPaint.setAntiAlias(paint.isAntiAlias());
1036
65
            tmpPaint.setDither(paint.isDither());
1037
65
            SkPaint paintWithShader = make_paint_with_image(tmpPaint, bitmap, sampling);
1038
65
            SkRect rr;
1039
65
            rr.setIWH(bitmap.width(), bitmap.height());
1040
65
            c.drawRect(rr, paintWithShader);
1041
65
        }
1042
65
        this->drawDevMask(mask, paint);
1043
65
    }
1044
84
}
1045
1046
static bool clipped_out(const SkMatrix& m, const SkRasterClip& c,
1047
154k
                        const SkRect& srcR) {
1048
154k
    SkRect  dstR;
1049
154k
    m.mapRect(&dstR, srcR);
1050
154k
    return c.quickReject(dstR.roundOut());
1051
154k
}
1052
1053
static bool clipped_out(const SkMatrix& matrix, const SkRasterClip& clip,
1054
154k
                        int width, int height) {
1055
154k
    SkRect  r;
1056
154k
    r.setIWH(width, height);
1057
154k
    return clipped_out(matrix, clip, r);
1058
154k
}
1059
1060
123k
static bool clipHandlesSprite(const SkRasterClip& clip, int x, int y, const SkPixmap& pmap) {
1061
123k
    return clip.isBW() || clip.quickContains(x, y, x + pmap.width(), y + pmap.height());
1062
123k
}
1063
1064
void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix,
1065
                        const SkRect* dstBounds, const SkSamplingOptions& sampling,
1066
308k
                        const SkPaint& origPaint) const {
1067
154k
    SkDEBUGCODE(this->validate();)
1068
1069
    // nothing to draw
1070
308k
    if (fRC->isEmpty() ||
1071
308k
            bitmap.width() == 0 || bitmap.height() == 0 ||
1072
308k
            bitmap.colorType() == kUnknown_SkColorType) {
1073
30
        return;
1074
30
    }
1075
1076
308k
    SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
1077
308k
    if (origPaint.getStyle() != SkPaint::kFill_Style) {
1078
60
        paint.writable()->setStyle(SkPaint::kFill_Style);
1079
60
    }
1080
1081
308k
    SkPreConcatMatrixProvider matrixProvider(*fMatrixProvider, prematrix);
1082
308k
    SkMatrix matrix = matrixProvider.localToDevice();
1083
1084
308k
    if (clipped_out(matrix, *fRC, bitmap.width(), bitmap.height())) {
1085
800
        return;
1086
800
    }
1087
1088
307k
    if (bitmap.colorType() != kAlpha_8_SkColorType
1089
307k
        && SkTreatAsSprite(matrix, bitmap.dimensions(), sampling, *paint)) {
1090
        //
1091
        // It is safe to call lock pixels now, since we know the matrix is
1092
        // (more or less) identity.
1093
        //
1094
247k
        SkPixmap pmap;
1095
247k
        if (!bitmap.peekPixels(&pmap)) {
1096
0
            return;
1097
0
        }
1098
247k
        int ix = SkScalarRoundToInt(matrix.getTranslateX());
1099
247k
        int iy = SkScalarRoundToInt(matrix.getTranslateY());
1100
247k
        if (clipHandlesSprite(*fRC, ix, iy, pmap)) {
1101
247k
            SkSTArenaAlloc<kSkBlitterContextSize> allocator;
1102
            // blitter will be owned by the allocator.
1103
247k
            SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, *paint, pmap, ix, iy, &allocator,
1104
247k
                                                         fRC->clipShader());
1105
247k
            if (blitter) {
1106
247k
                SkScan::FillIRect(SkIRect::MakeXYWH(ix, iy, pmap.width(), pmap.height()),
1107
247k
                                  *fRC, blitter);
1108
247k
                return;
1109
247k
            }
1110
            // if !blitter, then we fall-through to the slower case
1111
247k
        }
1112
247k
    }
1113
1114
    // now make a temp draw on the stack, and use it
1115
    //
1116
60.4k
    SkDraw draw(*this);
1117
60.4k
    draw.fMatrixProvider = &matrixProvider;
1118
1119
60.4k
    if (bitmap.colorType() == kAlpha_8_SkColorType && !paint->getColorFilter()) {
1120
168
        draw.drawBitmapAsMask(bitmap, sampling, *paint);
1121
60.3k
    } else {
1122
60.3k
        SkPaint paintWithShader = make_paint_with_image(*paint, bitmap, sampling);
1123
60.3k
        const SkRect srcBounds = SkRect::MakeIWH(bitmap.width(), bitmap.height());
1124
60.3k
        if (dstBounds) {
1125
59.2k
            this->drawRect(srcBounds, paintWithShader, &prematrix, dstBounds);
1126
1.07k
        } else {
1127
1.07k
            draw.drawRect(srcBounds, paintWithShader);
1128
1.07k
        }
1129
60.3k
    }
1130
60.4k
}
SkDraw::drawBitmap(SkBitmap const&, SkMatrix const&, SkRect const*, SkSamplingOptions const&, SkPaint const&) const
Line
Count
Source
1066
154k
                        const SkPaint& origPaint) const {
1067
154k
    SkDEBUGCODE(this->validate();)
1068
1069
    // nothing to draw
1070
154k
    if (fRC->isEmpty() ||
1071
154k
            bitmap.width() == 0 || bitmap.height() == 0 ||
1072
154k
            bitmap.colorType() == kUnknown_SkColorType) {
1073
15
        return;
1074
15
    }
1075
1076
154k
    SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
1077
154k
    if (origPaint.getStyle() != SkPaint::kFill_Style) {
1078
30
        paint.writable()->setStyle(SkPaint::kFill_Style);
1079
30
    }
1080
1081
154k
    SkPreConcatMatrixProvider matrixProvider(*fMatrixProvider, prematrix);
1082
154k
    SkMatrix matrix = matrixProvider.localToDevice();
1083
1084
154k
    if (clipped_out(matrix, *fRC, bitmap.width(), bitmap.height())) {
1085
400
        return;
1086
400
    }
1087
1088
153k
    if (bitmap.colorType() != kAlpha_8_SkColorType
1089
153k
        && SkTreatAsSprite(matrix, bitmap.dimensions(), sampling, *paint)) {
1090
        //
1091
        // It is safe to call lock pixels now, since we know the matrix is
1092
        // (more or less) identity.
1093
        //
1094
123k
        SkPixmap pmap;
1095
123k
        if (!bitmap.peekPixels(&pmap)) {
1096
0
            return;
1097
0
        }
1098
123k
        int ix = SkScalarRoundToInt(matrix.getTranslateX());
1099
123k
        int iy = SkScalarRoundToInt(matrix.getTranslateY());
1100
123k
        if (clipHandlesSprite(*fRC, ix, iy, pmap)) {
1101
123k
            SkSTArenaAlloc<kSkBlitterContextSize> allocator;
1102
            // blitter will be owned by the allocator.
1103
123k
            SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, *paint, pmap, ix, iy, &allocator,
1104
123k
                                                         fRC->clipShader());
1105
123k
            if (blitter) {
1106
123k
                SkScan::FillIRect(SkIRect::MakeXYWH(ix, iy, pmap.width(), pmap.height()),
1107
123k
                                  *fRC, blitter);
1108
123k
                return;
1109
123k
            }
1110
            // if !blitter, then we fall-through to the slower case
1111
123k
        }
1112
123k
    }
1113
1114
    // now make a temp draw on the stack, and use it
1115
    //
1116
30.2k
    SkDraw draw(*this);
1117
30.2k
    draw.fMatrixProvider = &matrixProvider;
1118
1119
30.2k
    if (bitmap.colorType() == kAlpha_8_SkColorType && !paint->getColorFilter()) {
1120
84
        draw.drawBitmapAsMask(bitmap, sampling, *paint);
1121
30.1k
    } else {
1122
30.1k
        SkPaint paintWithShader = make_paint_with_image(*paint, bitmap, sampling);
1123
30.1k
        const SkRect srcBounds = SkRect::MakeIWH(bitmap.width(), bitmap.height());
1124
30.1k
        if (dstBounds) {
1125
29.6k
            this->drawRect(srcBounds, paintWithShader, &prematrix, dstBounds);
1126
538
        } else {
1127
538
            draw.drawRect(srcBounds, paintWithShader);
1128
538
        }
1129
30.1k
    }
1130
30.2k
}
SkDraw::drawBitmap(SkBitmap const&, SkMatrix const&, SkRect const*, SkSamplingOptions const&, SkPaint const&) const
Line
Count
Source
1066
154k
                        const SkPaint& origPaint) const {
1067
154k
    SkDEBUGCODE(this->validate();)
1068
1069
    // nothing to draw
1070
154k
    if (fRC->isEmpty() ||
1071
154k
            bitmap.width() == 0 || bitmap.height() == 0 ||
1072
154k
            bitmap.colorType() == kUnknown_SkColorType) {
1073
15
        return;
1074
15
    }
1075
1076
154k
    SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
1077
154k
    if (origPaint.getStyle() != SkPaint::kFill_Style) {
1078
30
        paint.writable()->setStyle(SkPaint::kFill_Style);
1079
30
    }
1080
1081
154k
    SkPreConcatMatrixProvider matrixProvider(*fMatrixProvider, prematrix);
1082
154k
    SkMatrix matrix = matrixProvider.localToDevice();
1083
1084
154k
    if (clipped_out(matrix, *fRC, bitmap.width(), bitmap.height())) {
1085
400
        return;
1086
400
    }
1087
1088
153k
    if (bitmap.colorType() != kAlpha_8_SkColorType
1089
153k
        && SkTreatAsSprite(matrix, bitmap.dimensions(), sampling, *paint)) {
1090
        //
1091
        // It is safe to call lock pixels now, since we know the matrix is
1092
        // (more or less) identity.
1093
        //
1094
123k
        SkPixmap pmap;
1095
123k
        if (!bitmap.peekPixels(&pmap)) {
1096
0
            return;
1097
0
        }
1098
123k
        int ix = SkScalarRoundToInt(matrix.getTranslateX());
1099
123k
        int iy = SkScalarRoundToInt(matrix.getTranslateY());
1100
123k
        if (clipHandlesSprite(*fRC, ix, iy, pmap)) {
1101
123k
            SkSTArenaAlloc<kSkBlitterContextSize> allocator;
1102
            // blitter will be owned by the allocator.
1103
123k
            SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, *paint, pmap, ix, iy, &allocator,
1104
123k
                                                         fRC->clipShader());
1105
123k
            if (blitter) {
1106
123k
                SkScan::FillIRect(SkIRect::MakeXYWH(ix, iy, pmap.width(), pmap.height()),
1107
123k
                                  *fRC, blitter);
1108
123k
                return;
1109
123k
            }
1110
            // if !blitter, then we fall-through to the slower case
1111
123k
        }
1112
123k
    }
1113
1114
    // now make a temp draw on the stack, and use it
1115
    //
1116
30.2k
    SkDraw draw(*this);
1117
30.2k
    draw.fMatrixProvider = &matrixProvider;
1118
1119
30.2k
    if (bitmap.colorType() == kAlpha_8_SkColorType && !paint->getColorFilter()) {
1120
84
        draw.drawBitmapAsMask(bitmap, sampling, *paint);
1121
30.1k
    } else {
1122
30.1k
        SkPaint paintWithShader = make_paint_with_image(*paint, bitmap, sampling);
1123
30.1k
        const SkRect srcBounds = SkRect::MakeIWH(bitmap.width(), bitmap.height());
1124
30.1k
        if (dstBounds) {
1125
29.6k
            this->drawRect(srcBounds, paintWithShader, &prematrix, dstBounds);
1126
538
        } else {
1127
538
            draw.drawRect(srcBounds, paintWithShader);
1128
538
        }
1129
30.1k
    }
1130
30.2k
}
1131
1132
108
void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& origPaint) const {
1133
54
    SkDEBUGCODE(this->validate();)
1134
1135
    // nothing to draw
1136
108
    if (fRC->isEmpty() ||
1137
108
            bitmap.width() == 0 || bitmap.height() == 0 ||
1138
108
            bitmap.colorType() == kUnknown_SkColorType) {
1139
0
        return;
1140
0
    }
1141
1142
108
    const SkIRect bounds = SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height());
1143
1144
108
    if (fRC->quickReject(bounds)) {
1145
0
        return; // nothing to draw
1146
0
    }
1147
1148
108
    SkPaint paint(origPaint);
1149
108
    paint.setStyle(SkPaint::kFill_Style);
1150
1151
108
    SkPixmap pmap;
1152
108
    if (!bitmap.peekPixels(&pmap)) {
1153
0
        return;
1154
0
    }
1155
1156
108
    if (nullptr == paint.getColorFilter() && clipHandlesSprite(*fRC, x, y, pmap)) {
1157
        // blitter will be owned by the allocator.
1158
52
        SkSTArenaAlloc<kSkBlitterContextSize> allocator;
1159
52
        SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, paint, pmap, x, y, &allocator,
1160
52
                                                     fRC->clipShader());
1161
52
        if (blitter) {
1162
52
            SkScan::FillIRect(bounds, *fRC, blitter);
1163
52
            return;
1164
52
        }
1165
56
    }
1166
1167
56
    SkMatrix        matrix;
1168
56
    SkRect          r;
1169
1170
    // get a scalar version of our rect
1171
56
    r.set(bounds);
1172
1173
    // create shader with offset
1174
56
    matrix.setTranslate(r.fLeft, r.fTop);
1175
56
    SkPaint paintWithShader = make_paint_with_image(paint, bitmap, SkSamplingOptions(), &matrix);
1176
56
    SkDraw draw(*this);
1177
56
    SkOverrideDeviceMatrixProvider matrixProvider(*fMatrixProvider, SkMatrix::I());
1178
56
    draw.fMatrixProvider = &matrixProvider;
1179
    // call ourself with a rect
1180
56
    draw.drawRect(r, paintWithShader);
1181
56
}
SkDraw::drawSprite(SkBitmap const&, int, int, SkPaint const&) const
Line
Count
Source
1132
54
void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& origPaint) const {
1133
54
    SkDEBUGCODE(this->validate();)
1134
1135
    // nothing to draw
1136
54
    if (fRC->isEmpty() ||
1137
54
            bitmap.width() == 0 || bitmap.height() == 0 ||
1138
54
            bitmap.colorType() == kUnknown_SkColorType) {
1139
0
        return;
1140
0
    }
1141
1142
54
    const SkIRect bounds = SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height());
1143
1144
54
    if (fRC->quickReject(bounds)) {
1145
0
        return; // nothing to draw
1146
0
    }
1147
1148
54
    SkPaint paint(origPaint);
1149
54
    paint.setStyle(SkPaint::kFill_Style);
1150
1151
54
    SkPixmap pmap;
1152
54
    if (!bitmap.peekPixels(&pmap)) {
1153
0
        return;
1154
0
    }
1155
1156
54
    if (nullptr == paint.getColorFilter() && clipHandlesSprite(*fRC, x, y, pmap)) {
1157
        // blitter will be owned by the allocator.
1158
26
        SkSTArenaAlloc<kSkBlitterContextSize> allocator;
1159
26
        SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, paint, pmap, x, y, &allocator,
1160
26
                                                     fRC->clipShader());
1161
26
        if (blitter) {
1162
26
            SkScan::FillIRect(bounds, *fRC, blitter);
1163
26
            return;
1164
26
        }
1165
28
    }
1166
1167
28
    SkMatrix        matrix;
1168
28
    SkRect          r;
1169
1170
    // get a scalar version of our rect
1171
28
    r.set(bounds);
1172
1173
    // create shader with offset
1174
28
    matrix.setTranslate(r.fLeft, r.fTop);
1175
28
    SkPaint paintWithShader = make_paint_with_image(paint, bitmap, SkSamplingOptions(), &matrix);
1176
28
    SkDraw draw(*this);
1177
28
    SkOverrideDeviceMatrixProvider matrixProvider(*fMatrixProvider, SkMatrix::I());
1178
28
    draw.fMatrixProvider = &matrixProvider;
1179
    // call ourself with a rect
1180
28
    draw.drawRect(r, paintWithShader);
1181
28
}
SkDraw::drawSprite(SkBitmap const&, int, int, SkPaint const&) const
Line
Count
Source
1132
54
void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& origPaint) const {
1133
54
    SkDEBUGCODE(this->validate();)
1134
1135
    // nothing to draw
1136
54
    if (fRC->isEmpty() ||
1137
54
            bitmap.width() == 0 || bitmap.height() == 0 ||
1138
54
            bitmap.colorType() == kUnknown_SkColorType) {
1139
0
        return;
1140
0
    }
1141
1142
54
    const SkIRect bounds = SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height());
1143
1144
54
    if (fRC->quickReject(bounds)) {
1145
0
        return; // nothing to draw
1146
0
    }
1147
1148
54
    SkPaint paint(origPaint);
1149
54
    paint.setStyle(SkPaint::kFill_Style);
1150
1151
54
    SkPixmap pmap;
1152
54
    if (!bitmap.peekPixels(&pmap)) {
1153
0
        return;
1154
0
    }
1155
1156
54
    if (nullptr == paint.getColorFilter() && clipHandlesSprite(*fRC, x, y, pmap)) {
1157
        // blitter will be owned by the allocator.
1158
26
        SkSTArenaAlloc<kSkBlitterContextSize> allocator;
1159
26
        SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, paint, pmap, x, y, &allocator,
1160
26
                                                     fRC->clipShader());
1161
26
        if (blitter) {
1162
26
            SkScan::FillIRect(bounds, *fRC, blitter);
1163
26
            return;
1164
26
        }
1165
28
    }
1166
1167
28
    SkMatrix        matrix;
1168
28
    SkRect          r;
1169
1170
    // get a scalar version of our rect
1171
28
    r.set(bounds);
1172
1173
    // create shader with offset
1174
28
    matrix.setTranslate(r.fLeft, r.fTop);
1175
28
    SkPaint paintWithShader = make_paint_with_image(paint, bitmap, SkSamplingOptions(), &matrix);
1176
28
    SkDraw draw(*this);
1177
28
    SkOverrideDeviceMatrixProvider matrixProvider(*fMatrixProvider, SkMatrix::I());
1178
28
    draw.fMatrixProvider = &matrixProvider;
1179
    // call ourself with a rect
1180
28
    draw.drawRect(r, paintWithShader);
1181
28
}
1182
1183
////////////////////////////////////////////////////////////////////////////////////////////////
1184
1185
#ifdef SK_DEBUG
1186
1187
0
void SkDraw::validate() const {
1188
0
    SkASSERT(fMatrixProvider != nullptr);
1189
0
    SkASSERT(fRC != nullptr);
1190
1191
0
    const SkIRect&  cr = fRC->getBounds();
1192
0
    SkIRect         br;
1193
1194
0
    br.setWH(fDst.width(), fDst.height());
1195
0
    SkASSERT(cr.isEmpty() || br.contains(cr));
1196
0
}
1197
1198
#endif
1199
1200
////////////////////////////////////////////////////////////////////////////////////////////////
1201
1202
#include "include/core/SkPath.h"
1203
#include "include/core/SkRegion.h"
1204
#include "src/core/SkBlitter.h"
1205
#include "src/core/SkDraw.h"
1206
1207
bool SkDraw::ComputeMaskBounds(const SkRect& devPathBounds, const SkIRect* clipBounds,
1208
                               const SkMaskFilter* filter, const SkMatrix* filterMatrix,
1209
63.5k
                               SkIRect* bounds) {
1210
    //  init our bounds from the path
1211
63.5k
    *bounds = devPathBounds.makeOutset(SK_ScalarHalf, SK_ScalarHalf).roundOut();
1212
1213
63.5k
    SkIPoint margin = SkIPoint::Make(0, 0);
1214
63.5k
    if (filter) {
1215
63.5k
        SkASSERT(filterMatrix);
1216
1217
63.5k
        SkMask srcM, dstM;
1218
1219
63.5k
        srcM.fBounds = *bounds;
1220
63.5k
        srcM.fFormat = SkMask::kA8_Format;
1221
63.5k
        if (!as_MFB(filter)->filterMask(&dstM, srcM, *filterMatrix, &margin)) {
1222
55.3k
            return false;
1223
55.3k
        }
1224
8.27k
    }
1225
1226
    // (possibly) trim the bounds to reflect the clip
1227
    // (plus whatever slop the filter needs)
1228
8.27k
    if (clipBounds) {
1229
        // Ugh. Guard against gigantic margins from wacky filters. Without this
1230
        // check we can request arbitrary amounts of slop beyond our visible
1231
        // clip, and bring down the renderer (at least on finite RAM machines
1232
        // like handsets, etc.). Need to balance this invented value between
1233
        // quality of large filters like blurs, and the corresponding memory
1234
        // requests.
1235
8.27k
        static const int MAX_MARGIN = 128;
1236
8.27k
        if (!bounds->intersect(clipBounds->makeOutset(std::min(margin.fX, MAX_MARGIN),
1237
1.18k
                                                      std::min(margin.fY, MAX_MARGIN)))) {
1238
1.18k
            return false;
1239
1.18k
        }
1240
7.08k
    }
1241
1242
7.08k
    return true;
1243
7.08k
}
1244
1245
static void draw_into_mask(const SkMask& mask, const SkPath& devPath,
1246
7.07k
                           SkStrokeRec::InitStyle style) {
1247
7.07k
    SkDraw draw;
1248
7.07k
    if (!draw.fDst.reset(mask)) {
1249
0
        return;
1250
0
    }
1251
1252
7.07k
    SkRasterClip    clip;
1253
7.07k
    SkMatrix        matrix;
1254
7.07k
    SkPaint         paint;
1255
1256
7.07k
    clip.setRect(SkIRect::MakeWH(mask.fBounds.width(), mask.fBounds.height()));
1257
7.07k
    matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
1258
7.07k
                        -SkIntToScalar(mask.fBounds.fTop));
1259
1260
7.07k
    SkSimpleMatrixProvider matrixProvider(matrix);
1261
7.07k
    draw.fRC             = &clip;
1262
7.07k
    draw.fMatrixProvider = &matrixProvider;
1263
7.07k
    paint.setAntiAlias(true);
1264
7.07k
    switch (style) {
1265
1.73k
        case SkStrokeRec::kHairline_InitStyle:
1266
1.73k
            SkASSERT(!paint.getStrokeWidth());
1267
1.73k
            paint.setStyle(SkPaint::kStroke_Style);
1268
1.73k
            break;
1269
5.33k
        case SkStrokeRec::kFill_InitStyle:
1270
5.33k
            SkASSERT(paint.getStyle() == SkPaint::kFill_Style);
1271
5.33k
            break;
1272
1273
7.07k
    }
1274
7.07k
    draw.drawPath(devPath, paint);
1275
7.07k
}
1276
1277
bool SkDraw::DrawToMask(const SkPath& devPath, const SkIRect* clipBounds,
1278
                        const SkMaskFilter* filter, const SkMatrix* filterMatrix,
1279
                        SkMask* mask, SkMask::CreateMode mode,
1280
67.2k
                        SkStrokeRec::InitStyle style) {
1281
67.2k
    if (devPath.isEmpty()) {
1282
3.64k
        return false;
1283
3.64k
    }
1284
1285
63.5k
    if (SkMask::kJustRenderImage_CreateMode != mode) {
1286
63.5k
        if (!ComputeMaskBounds(devPath.getBounds(), clipBounds, filter,
1287
63.5k
                               filterMatrix, &mask->fBounds))
1288
56.5k
            return false;
1289
7.08k
    }
1290
1291
7.08k
    if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) {
1292
7.08k
        mask->fFormat = SkMask::kA8_Format;
1293
7.08k
        mask->fRowBytes = mask->fBounds.width();
1294
7.08k
        size_t size = mask->computeImageSize();
1295
7.08k
        if (0 == size) {
1296
            // we're too big to allocate the mask, abort
1297
9
            return false;
1298
9
        }
1299
7.07k
        mask->fImage = SkMask::AllocImage(size, SkMask::kZeroInit_Alloc);
1300
7.07k
    }
1301
1302
7.07k
    if (SkMask::kJustComputeBounds_CreateMode != mode) {
1303
7.07k
        draw_into_mask(*mask, devPath, style);
1304
7.07k
    }
1305
1306
7.07k
    return true;
1307
7.08k
}