Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkDrawBase.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2023 Google LLC
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
10#include "include/core/SkPath.h"
17#include "include/core/SkRect.h"
25#include "src/base/SkTLazy.h"
26#include "src/base/SkZip.h"
30#include "src/core/SkDevice.h"
31#include "src/core/SkDrawBase.h"
33#include "src/core/SkMask.h"
36#include "src/core/SkPathPriv.h"
38#include "src/core/SkRectPriv.h"
39#include "src/core/SkScan.h"
40#include <algorithm>
41#include <cstddef>
42#include <optional>
43
44class SkBitmap;
45class SkBlitter;
46class SkGlyph;
47class SkMaskFilter;
48
49using namespace skia_private;
50
51///////////////////////////////////////////////////////////////////////////////
52
54
55bool SkDrawBase::computeConservativeLocalClipBounds(SkRect* localBounds) const {
56 if (fRC->isEmpty()) {
57 return false;
58 }
59
60 SkMatrix inverse;
61 if (!fCTM->invert(&inverse)) {
62 return false;
63 }
64
65 SkIRect devBounds = fRC->getBounds();
66 // outset to have slop for antialasing and hairlines
67 devBounds.outset(1, 1);
68 inverse.mapRect(localBounds, SkRect::Make(devBounds));
69 return true;
70}
71
72///////////////////////////////////////////////////////////////////////////////
73
75 SkDEBUGCODE(this->validate();)
76
77 if (fRC->isEmpty()) {
78 return;
79 }
80
81 SkIRect devRect;
82 devRect.setWH(fDst.width(), fDst.height());
83
84 SkAutoBlitterChoose blitter(*this, nullptr, paint);
85 SkScan::FillIRect(devRect, *fRC, blitter.get());
86}
87
88///////////////////////////////////////////////////////////////////////////////
89
90static inline SkPoint compute_stroke_size(const SkPaint& paint, const SkMatrix& matrix) {
91 SkASSERT(matrix.rectStaysRect());
92 SkASSERT(SkPaint::kFill_Style != paint.getStyle());
93
94 SkVector size;
95 SkPoint pt = { paint.getStrokeWidth(), paint.getStrokeWidth() };
96 matrix.mapVectors(&size, &pt, 1);
97 return SkPoint::Make(SkScalarAbs(size.fX), SkScalarAbs(size.fY));
98}
99
100static bool easy_rect_join(const SkRect& rect, const SkPaint& paint, const SkMatrix& matrix,
101 SkPoint* strokeSize) {
102 if (rect.isEmpty() || SkPaint::kMiter_Join != paint.getStrokeJoin() ||
103 paint.getStrokeMiter() < SK_ScalarSqrt2) {
104 return false;
105 }
106
107 *strokeSize = compute_stroke_size(paint, matrix);
108 return true;
109}
110
112 const SkPaint& paint,
113 const SkMatrix& matrix,
114 SkPoint* strokeSize) {
115 RectType rtype;
116 const SkScalar width = paint.getStrokeWidth();
117 const bool zeroWidth = (0 == width);
118 SkPaint::Style style = paint.getStyle();
119
120 if ((SkPaint::kStrokeAndFill_Style == style) && zeroWidth) {
121 style = SkPaint::kFill_Style;
122 }
123
124 if (paint.getPathEffect() || paint.getMaskFilter() ||
125 !matrix.rectStaysRect() || SkPaint::kStrokeAndFill_Style == style) {
126 rtype = kPath_RectType;
127 } else if (SkPaint::kFill_Style == style) {
128 rtype = kFill_RectType;
129 } else if (zeroWidth) {
130 rtype = kHair_RectType;
131 } else if (easy_rect_join(rect, paint, matrix, strokeSize)) {
132 rtype = kStroke_RectType;
133 } else {
134 rtype = kPath_RectType;
135 }
136 return rtype;
137}
138
139static const SkPoint* rect_points(const SkRect& r) {
140 return reinterpret_cast<const SkPoint*>(&r);
141}
142
144 return reinterpret_cast<SkPoint*>(&r);
145}
146
147static void draw_rect_as_path(const SkDrawBase& orig,
148 const SkRect& prePaintRect,
149 const SkPaint& paint,
150 const SkMatrix& ctm) {
151 SkDrawBase draw(orig);
152 draw.fCTM = &ctm;
153 SkPath tmp;
154 tmp.addRect(prePaintRect);
156 draw.drawPath(tmp, paint, nullptr, true);
157}
158
159void SkDrawBase::drawRect(const SkRect& prePaintRect, const SkPaint& paint,
160 const SkMatrix* paintMatrix, const SkRect* postPaintRect) const {
161 SkDEBUGCODE(this->validate();)
162
163 // nothing to draw
164 if (fRC->isEmpty()) {
165 return;
166 }
167
169 if (paintMatrix) {
170 SkASSERT(postPaintRect);
171 matrix.writable()->preConcat(*paintMatrix);
172 } else {
173 SkASSERT(!postPaintRect);
174 }
175
176 SkPoint strokeSize;
177 RectType rtype = ComputeRectType(prePaintRect, paint, *fCTM, &strokeSize);
178
179 if (kPath_RectType == rtype) {
180 draw_rect_as_path(*this, prePaintRect, paint, *matrix);
181 return;
182 }
183
184 SkRect devRect;
185 const SkRect& paintRect = paintMatrix ? *postPaintRect : prePaintRect;
186 // skip the paintMatrix when transforming the rect by the CTM
187 fCTM->mapPoints(rect_points(devRect), rect_points(paintRect), 2);
188 devRect.sort();
189
190 // look for the quick exit, before we build a blitter
191 SkRect bbox = devRect;
192 if (paint.getStyle() != SkPaint::kFill_Style) {
193 // extra space for hairlines
194 if (paint.getStrokeWidth() == 0) {
195 bbox.outset(1, 1);
196 } else {
197 // For kStroke_RectType, strokeSize is already computed.
198 const SkPoint& ssize = (kStroke_RectType == rtype)
199 ? strokeSize
201 bbox.outset(SkScalarHalf(ssize.x()), SkScalarHalf(ssize.y()));
202 }
203 }
204 if (SkPathPriv::TooBigForMath(bbox)) {
205 return;
206 }
207
208 if (!SkRectPriv::FitsInFixed(bbox) && rtype != kHair_RectType) {
209 draw_rect_as_path(*this, prePaintRect, paint, *matrix);
210 return;
211 }
212
213 SkIRect ir = bbox.roundOut();
214 if (fRC->quickReject(ir)) {
215 return;
216 }
217
218 SkAutoBlitterChoose blitterStorage(*this, matrix, paint);
219 const SkRasterClip& clip = *fRC;
220 SkBlitter* blitter = blitterStorage.get();
221
222 // we want to "fill" if we are kFill or kStrokeAndFill, since in the latter
223 // case we are also hairline (if we've gotten to here), which devolves to
224 // effectively just kFill
225 switch (rtype) {
226 case kFill_RectType:
227 if (paint.isAntiAlias()) {
228 SkScan::AntiFillRect(devRect, clip, blitter);
229 } else {
230 SkScan::FillRect(devRect, clip, blitter);
231 }
232 break;
233 case kStroke_RectType:
234 if (paint.isAntiAlias()) {
235 SkScan::AntiFrameRect(devRect, strokeSize, clip, blitter);
236 } else {
237 SkScan::FrameRect(devRect, strokeSize, clip, blitter);
238 }
239 break;
240 case kHair_RectType:
241 if (paint.isAntiAlias()) {
242 SkScan::AntiHairRect(devRect, clip, blitter);
243 } else {
244 SkScan::HairRect(devRect, clip, blitter);
245 }
246 break;
247 default:
248 SkDEBUGFAIL("bad rtype");
249 }
250}
251
252static SkScalar fast_len(const SkVector& vec) {
253 SkScalar x = SkScalarAbs(vec.fX);
254 SkScalar y = SkScalarAbs(vec.fY);
255 if (x < y) {
256 using std::swap;
257 swap(x, y);
258 }
259 return x + SkScalarHalf(y);
260}
261
263 SkScalar* coverage) {
265 // We need to try to fake a thick-stroke with a modulated hairline.
266
267 if (matrix.hasPerspective()) {
268 return false;
269 }
270
271 SkVector src[2], dst[2];
272 src[0].set(strokeWidth, 0);
273 src[1].set(0, strokeWidth);
274 matrix.mapVectors(dst, src, 2);
275 SkScalar len0 = fast_len(dst[0]);
276 SkScalar len1 = fast_len(dst[1]);
277 if (len0 <= SK_Scalar1 && len1 <= SK_Scalar1) {
278 if (coverage) {
279 *coverage = SkScalarAve(len0, len1);
280 }
281 return true;
282 }
283 return false;
284}
285
286void SkDrawBase::drawRRect(const SkRRect& rrect, const SkPaint& paint) const {
287 SkDEBUGCODE(this->validate());
288
289 if (fRC->isEmpty()) {
290 return;
291 }
292
293 {
294 // TODO: Investigate optimizing these options. They are in the same
295 // order as SkDrawBase::drawPath, which handles each case. It may be
296 // that there is no way to optimize for these using the SkRRect path.
297 SkScalar coverage;
298 if (SkDrawTreatAsHairline(paint, *fCTM, &coverage)) {
299 goto DRAW_PATH;
300 }
301
302 if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
303 goto DRAW_PATH;
304 }
305 }
306
307 if (paint.getMaskFilter()) {
308 // Transform the rrect into device space.
309 SkRRect devRRect;
310 if (rrect.transform(*fCTM, &devRRect)) {
311 SkAutoBlitterChoose blitter(*this, nullptr, paint);
312 if (as_MFB(paint.getMaskFilter())->filterRRect(devRRect, *fCTM, *fRC, blitter.get())) {
313 return; // filterRRect() called the blitter, so we're done
314 }
315 }
316 }
317
319 // Now fall back to the default case of using a path.
320 SkPath path;
321 path.addRRect(rrect);
322 this->drawPath(path, paint, nullptr, true);
323}
324
325void SkDrawBase::drawDevPath(const SkPath& devPath, const SkPaint& paint, bool drawCoverage,
326 SkBlitter* customBlitter, bool doFill) const {
327 if (SkPathPriv::TooBigForMath(devPath)) {
328 return;
329 }
330 SkBlitter* blitter = nullptr;
331 SkAutoBlitterChoose blitterStorage;
332 if (nullptr == customBlitter) {
333 blitter = blitterStorage.choose(*this, nullptr, paint, drawCoverage);
334 } else {
335 blitter = customBlitter;
336 }
337
338 if (paint.getMaskFilter()) {
341 if (as_MFB(paint.getMaskFilter())->filterPath(devPath, *fCTM, *fRC, blitter, style)) {
342 return; // filterPath() called the blitter, so we're done
343 }
344 }
345
346 void (*proc)(const SkPath&, const SkRasterClip&, SkBlitter*);
347 if (doFill) {
348 if (paint.isAntiAlias()) {
350 } else {
351 proc = SkScan::FillPath;
352 }
353 } else { // hairline
354 if (paint.isAntiAlias()) {
355 switch (paint.getStrokeCap()) {
358 break;
361 break;
364 break;
365 }
366 } else {
367 switch (paint.getStrokeCap()) {
369 proc = SkScan::HairPath;
370 break;
373 break;
376 break;
377 }
378 }
379 }
380
381 proc(devPath, *fRC, blitter);
382}
383
384void SkDrawBase::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint,
385 const SkMatrix* prePathMatrix, bool pathIsMutable,
386 bool drawCoverage, SkBlitter* customBlitter) const {
387 SkDEBUGCODE(this->validate();)
388
389 // nothing to draw
390 if (fRC->isEmpty()) {
391 return;
392 }
393
394 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
395 bool doFill = true;
396 SkPath tmpPathStorage;
397 SkPath* tmpPath = &tmpPathStorage;
399 tmpPath->setIsVolatile(true);
400
401 if (prePathMatrix) {
402 if (origPaint.getPathEffect() || origPaint.getStyle() != SkPaint::kFill_Style) {
403 SkPath* result = pathPtr;
404
405 if (!pathIsMutable) {
406 result = tmpPath;
407 pathIsMutable = true;
408 }
409 pathPtr->transform(*prePathMatrix, result);
410 pathPtr = result;
411 } else {
412 matrix.writable()->preConcat(*prePathMatrix);
413 }
414 }
415
417
418 {
420 if (SkDrawTreatAsHairline(origPaint, *matrix, &coverage)) {
421 const auto bm = origPaint.asBlendMode();
422 if (SK_Scalar1 == coverage) {
423 paint.writable()->setStrokeWidth(0);
424 } else if (bm && SkBlendMode_SupportsCoverageAsAlpha(bm.value())) {
425 U8CPU newAlpha;
426#if 0
427 newAlpha = SkToU8(SkScalarRoundToInt(coverage * origPaint.getAlpha()));
428#else
429 // this is the old technique, which we preserve for now so
430 // we don't change previous results (testing)
431 // the new way seems fine, its just (a tiny bit) different
432 int scale = (int)(coverage * 256);
433 newAlpha = origPaint.getAlpha() * scale >> 8;
434#endif
435 SkPaint* writablePaint = paint.writable();
436 writablePaint->setStrokeWidth(0);
437 writablePaint->setAlpha(newAlpha);
438 }
439 }
440 }
441
442 if (paint->getPathEffect() || paint->getStyle() != SkPaint::kFill_Style) {
443 SkRect cullRect;
444 const SkRect* cullRectPtr = nullptr;
445 if (this->computeConservativeLocalClipBounds(&cullRect)) {
446 cullRectPtr = &cullRect;
447 }
448 doFill = skpathutils::FillPathWithPaint(*pathPtr, *paint, tmpPath, cullRectPtr, *fCTM);
449 pathPtr = tmpPath;
450 }
451
452 // avoid possibly allocating a new path in transform if we can
453 SkPath* devPathPtr = pathIsMutable ? pathPtr : tmpPath;
454
455 // transform the path into device space
456 pathPtr->transform(*matrix, devPathPtr);
457
458#if defined(SK_BUILD_FOR_FUZZER)
459 if (devPathPtr->countPoints() > 1000) {
460 return;
461 }
462#endif
463
464 this->drawDevPath(*devPathPtr, *paint, drawCoverage, customBlitter, doFill);
465}
466
470void SkDrawBase::drawBitmap(const SkBitmap&, const SkMatrix&, const SkRect*,
471 const SkSamplingOptions&, const SkPaint&) const {
472 SkASSERT(false);
473}
474
475////////////////////////////////////////////////////////////////////////////////////////////////
476
477#ifdef SK_DEBUG
478
479void SkDrawBase::validate() const {
480 SkASSERT(fCTM != nullptr);
481 SkASSERT(fRC != nullptr);
482
483 const SkIRect& cr = fRC->getBounds();
484 SkIRect br;
485
486 br.setWH(fDst.width(), fDst.height());
487 SkASSERT(cr.isEmpty() || br.contains(cr));
488}
489
490#endif
491
492////////////////////////////////////////////////////////////////////////////////////////////////
493
494bool SkDrawBase::ComputeMaskBounds(const SkRect& devPathBounds, const SkIRect& clipBounds,
495 const SkMaskFilter* filter, const SkMatrix* filterMatrix,
496 SkIRect* bounds) {
497 // init our bounds from the path
498 *bounds = devPathBounds.makeOutset(SK_ScalarHalf, SK_ScalarHalf).roundOut();
499
500 SkIPoint margin = SkIPoint::Make(0, 0);
501 if (filter) {
502 SkASSERT(filterMatrix);
503
504 SkMask srcM(nullptr, *bounds, 0, SkMask::kA8_Format);
505 SkMaskBuilder dstM;
506 if (!as_MFB(filter)->filterMask(&dstM, srcM, *filterMatrix, &margin)) {
507 return false;
508 }
509 }
510
511 // trim the bounds to reflect the clip (plus whatever slop the filter needs)
512 // Ugh. Guard against gigantic margins from wacky filters. Without this
513 // check we can request arbitrary amounts of slop beyond our visible
514 // clip, and bring down the renderer (at least on finite RAM machines
515 // like handsets, etc.). Need to balance this invented value between
516 // quality of large filters like blurs, and the corresponding memory
517 // requests.
518 static constexpr int kMaxMargin = 128;
519 if (!bounds->intersect(clipBounds.makeOutset(std::min(margin.fX, kMaxMargin),
520 std::min(margin.fY, kMaxMargin)))) {
521 return false;
522 }
523
524 return true;
525}
526
527static void draw_into_mask(const SkMask& mask, const SkPath& devPath,
531 if (!draw.fDst.reset(mask)) {
532 return;
533 }
534
536 SkMatrix matrix;
538
539 clip.setRect(SkIRect::MakeWH(mask.fBounds.width(), mask.fBounds.height()));
540 matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
541 -SkIntToScalar(mask.fBounds.fTop));
542
543 draw.fRC = &clip;
544 draw.fCTM = &matrix;
545 paint.setAntiAlias(true);
546 switch (style) {
548 SkASSERT(!paint.getStrokeWidth());
550 break;
552 SkASSERT(paint.getStyle() == SkPaint::kFill_Style);
553 break;
554
555 }
556 draw.drawPath(devPath, paint);
557}
558
559bool SkDrawBase::DrawToMask(const SkPath& devPath, const SkIRect& clipBounds,
560 const SkMaskFilter* filter, const SkMatrix* filterMatrix,
563 if (devPath.isEmpty()) {
564 return false;
565 }
566
568 // By using infinite bounds for inverse fills, ComputeMaskBounds is able to clip it to
569 // 'clipBounds' outset by whatever extra margin the mask filter requires.
570 static const SkRect kInverseBounds = { SK_ScalarNegativeInfinity, SK_ScalarNegativeInfinity,
572 SkRect pathBounds = devPath.isInverseFillType() ? kInverseBounds
573 : devPath.getBounds();
574 if (!ComputeMaskBounds(pathBounds, clipBounds, filter,
575 filterMatrix, &dst->bounds()))
576 return false;
577 }
578
580 dst->format() = SkMask::kA8_Format;
581 dst->rowBytes() = dst->fBounds.width();
582 size_t size = dst->computeImageSize();
583 if (0 == size) {
584 // we're too big to allocate the mask, abort
585 return false;
586 }
588 }
589
591 draw_into_mask(*dst, devPath, style);
592 }
593
594 return true;
595}
596
598 const SkPoint pts[], const SkPaint& paint,
599 SkDevice* device) const {
600 // if we're in lines mode, force count to be even
601 if (SkCanvas::kLines_PointMode == mode) {
602 count &= ~(size_t)1;
603 }
604
605 SkASSERT(pts != nullptr);
606 SkDEBUGCODE(this->validate();)
607
608 // nothing to draw
609 if (!count || fRC->isEmpty()) {
610 return;
611 }
612
613 // needed?
614 if (!SkIsFinite(&pts[0].fX, count * 2)) {
615 return;
616 }
617
618 switch (mode) {
620 // temporarily mark the paint as filling.
621 SkPaint newPaint(paint);
623
624 SkScalar width = newPaint.getStrokeWidth();
625 SkScalar radius = SkScalarHalf(width);
626
627 if (newPaint.getStrokeCap() == SkPaint::kRound_Cap) {
628 if (device) {
629 for (size_t i = 0; i < count; ++i) {
630 SkRect r = SkRect::MakeLTRB(pts[i].fX - radius, pts[i].fY - radius,
631 pts[i].fX + radius, pts[i].fY + radius);
632 device->drawOval(r, newPaint);
633 }
634 } else {
635 SkPath path;
636 SkMatrix preMatrix;
637
638 path.addCircle(0, 0, radius);
639 for (size_t i = 0; i < count; i++) {
640 preMatrix.setTranslate(pts[i].fX, pts[i].fY);
641 // pass true for the last point, since we can modify
642 // then path then
643 path.setIsVolatile((count-1) == i);
644 this->drawPath(path, newPaint, &preMatrix, (count-1) == i);
645 }
646 }
647 } else {
648 SkRect r;
649
650 for (size_t i = 0; i < count; i++) {
651 r.fLeft = pts[i].fX - radius;
652 r.fTop = pts[i].fY - radius;
653 r.fRight = r.fLeft + width;
654 r.fBottom = r.fTop + width;
655 if (device) {
656 device->drawRect(r, newPaint);
657 } else {
658 this->drawRect(r, newPaint);
659 }
660 }
661 }
662 break;
663 }
665 if (2 == count && paint.getPathEffect()) {
666 // most likely a dashed line - see if it is one of the ones
667 // we can accelerate
668 SkStrokeRec stroke(paint);
670
671 SkPath path = SkPath::Line(pts[0], pts[1]);
672
673 SkRect cullRect = SkRect::Make(fRC->getBounds());
674
675 if (as_PEB(paint.getPathEffect())->asPoints(&pointData, path, stroke, *fCTM,
676 &cullRect)) {
677 // 'asPoints' managed to find some fast path
678
679 SkPaint newP(paint);
680 newP.setPathEffect(nullptr);
682
683 if (!pointData.fFirst.isEmpty()) {
684 if (device) {
685 device->drawPath(pointData.fFirst, newP);
686 } else {
687 this->drawPath(pointData.fFirst, newP);
688 }
689 }
690
691 if (!pointData.fLast.isEmpty()) {
692 if (device) {
693 device->drawPath(pointData.fLast, newP);
694 } else {
695 this->drawPath(pointData.fLast, newP);
696 }
697 }
698
699 if (pointData.fSize.fX == pointData.fSize.fY) {
700 // The rest of the dashed line can just be drawn as points
701 SkASSERT(pointData.fSize.fX == SkScalarHalf(newP.getStrokeWidth()));
702
705 } else {
707 }
708
709 if (device) {
711 pointData.fNumPoints,
712 pointData.fPoints,
713 newP);
714 } else {
716 pointData.fNumPoints,
717 pointData.fPoints,
718 newP,
719 device);
720 }
721 break;
722 } else {
723 // The rest of the dashed line must be drawn as rects
725 pointData.fFlags));
726
727 SkRect r;
728
729 for (int i = 0; i < pointData.fNumPoints; ++i) {
730 r.setLTRB(pointData.fPoints[i].fX - pointData.fSize.fX,
731 pointData.fPoints[i].fY - pointData.fSize.fY,
732 pointData.fPoints[i].fX + pointData.fSize.fX,
733 pointData.fPoints[i].fY + pointData.fSize.fY);
734 if (device) {
735 device->drawRect(r, newP);
736 } else {
737 this->drawRect(r, newP);
738 }
739 }
740 }
741
742 break;
743 }
744 }
745 [[fallthrough]]; // couldn't take fast path
747 count -= 1;
748 SkPath path;
749 SkPaint p(paint);
750 p.setStyle(SkPaint::kStroke_Style);
751 size_t inc = (SkCanvas::kLines_PointMode == mode) ? 2 : 1;
752 path.setIsVolatile(true);
753 for (size_t i = 0; i < count; i += inc) {
754 path.moveTo(pts[i]);
755 path.lineTo(pts[i+1]);
756 if (device) {
757 device->drawPath(path, p, true);
758 } else {
759 this->drawPath(path, p, nullptr, true);
760 }
761 path.rewind();
762 }
763 break;
764 }
765 }
766}
static const int strokeWidth
Definition BlurTest.cpp:60
int count
#define SkDEBUGFAIL(message)
Definition SkAssert.h:118
#define SkASSERT(cond)
Definition SkAssert.h:116
bool SkBlendMode_SupportsCoverageAsAlpha(SkBlendMode mode)
SkBlitter * SkA8Blitter_Choose(const SkPixmap &dst, const SkMatrix &ctm, const SkPaint &paint, SkArenaAlloc *alloc, bool drawCoverage, sk_sp< SkShader > clipShader, const SkSurfaceProps &)
bool draw_into_mask(SkMaskBuilder *mask, const SkRect &bounds, Proc proc)
unsigned U8CPU
Definition SkCPUTypes.h:18
#define SkDEBUGCODE(...)
Definition SkDebug.h:23
static const SkPoint * rect_points(const SkRect &r)
static SkPoint compute_stroke_size(const SkPaint &paint, const SkMatrix &matrix)
bool SkDrawTreatAAStrokeAsHairline(SkScalar strokeWidth, const SkMatrix &matrix, SkScalar *coverage)
static SkScalar fast_len(const SkVector &vec)
static void draw_rect_as_path(const SkDrawBase &orig, const SkRect &prePaintRect, const SkPaint &paint, const SkMatrix &ctm)
static bool easy_rect_join(const SkRect &rect, const SkPaint &paint, const SkMatrix &matrix, SkPoint *strokeSize)
static void draw_into_mask(const SkMask &mask, const SkPath &devPath, SkStrokeRec::InitStyle style)
bool SkDrawTreatAsHairline(const SkPaint &paint, const SkMatrix &matrix, SkScalar *coverage)
Definition SkDrawProcs.h:24
static bool SkIsFinite(T x, Pack... values)
SkMaskFilterBase * as_MFB(SkMaskFilter *mf)
static SkPathEffectBase * as_PEB(SkPathEffect *effect)
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition SkPath.cpp:3824
@ DRAW_PATH
#define SK_Scalar1
Definition SkScalar.h:18
#define SkScalarHalf(a)
Definition SkScalar.h:75
#define SkScalarAve(a, b)
Definition SkScalar.h:74
#define SK_ScalarHalf
Definition SkScalar.h:19
#define SkScalarRoundToInt(x)
Definition SkScalar.h:37
#define SkIntToScalar(x)
Definition SkScalar.h:57
#define SK_ScalarSqrt2
Definition SkScalar.h:20
#define SK_ScalarInfinity
Definition SkScalar.h:26
#define SkScalarAbs(x)
Definition SkScalar.h:39
#define SK_ScalarNegativeInfinity
Definition SkScalar.h:27
constexpr uint8_t SkToU8(S x)
Definition SkTo.h:22
static void draw(SkCanvas *canvas, SkRect &target, int x, int y)
Definition aaclip.cpp:27
Type::kYUV Type::kRGBA() int(0.7 *637)
SkBlitter * choose(const SkDrawBase &draw, const SkMatrix *ctm, const SkPaint &paint, bool drawCoverage=false)
SkBlitter * get() const
@ kLines_PointMode
draw each pair of points as a line segment
Definition SkCanvas.h:1242
@ kPolygon_PointMode
draw the array of points as a open polygon
Definition SkCanvas.h:1243
@ kPoints_PointMode
draw each point separately
Definition SkCanvas.h:1241
@ kStroke_RectType
Definition SkDrawBase.h:96
void drawRRect(const SkRRect &, const SkPaint &) const
BlitterChooser * fBlitterChooser
Definition SkDrawBase.h:152
void drawPath(const SkPath &path, const SkPaint &paint, const SkMatrix *prePathMatrix=nullptr, bool pathIsMutable=false) const
Definition SkDrawBase.h:58
static bool DrawToMask(const SkPath &devPath, const SkIRect &clipBounds, const SkMaskFilter *, const SkMatrix *filterMatrix, SkMaskBuilder *dst, SkMaskBuilder::CreateMode mode, SkStrokeRec::InitStyle style)
static bool ComputeMaskBounds(const SkRect &devPathBounds, const SkIRect &clipBounds, const SkMaskFilter *filter, const SkMatrix *filterMatrix, SkIRect *bounds)
void drawPaint(const SkPaint &) const
const SkRasterClip * fRC
Definition SkDrawBase.h:154
void drawRect(const SkRect &prePaintRect, const SkPaint &, const SkMatrix *paintMatrix, const SkRect *postPaintRect) const
SkPixmap fDst
Definition SkDrawBase.h:151
void validate() const
Definition SkDrawBase.h:160
void drawBitmap(const SkBitmap &, const SkMatrix &, const SkRect *dstOrNull, const SkSamplingOptions &, const SkPaint &) const override
static RectType ComputeRectType(const SkRect &, const SkPaint &, const SkMatrix &, SkPoint *strokeSize)
const SkMatrix * fCTM
Definition SkDrawBase.h:153
void paintMasks(SkZip< const SkGlyph *, SkPoint > accepted, const SkPaint &paint) const override
void drawDevicePoints(SkCanvas::PointMode, size_t count, const SkPoint[], const SkPaint &, SkDevice *) const
void mapPoints(SkPoint dst[], const SkPoint src[], int count) const
Definition SkMatrix.cpp:770
SkMatrix & setTranslate(SkScalar dx, SkScalar dy)
Definition SkMatrix.cpp:254
bool invert(SkMatrix *inverse) const
Definition SkMatrix.h:1206
bool mapRect(SkRect *dst, const SkRect &src, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
@ kRound_Cap
adds circle
Definition SkPaint.h:335
@ kButt_Cap
no stroke extension
Definition SkPaint.h:334
@ kSquare_Cap
adds square
Definition SkPaint.h:336
void setStyle(Style style)
Definition SkPaint.cpp:105
Style getStyle() const
Definition SkPaint.h:204
SkPathEffect * getPathEffect() const
Definition SkPaint.h:506
void setStrokeCap(Cap cap)
Definition SkPaint.cpp:179
@ kStroke_Style
set to stroke geometry
Definition SkPaint.h:194
@ kFill_Style
set to fill geometry
Definition SkPaint.h:193
@ kStrokeAndFill_Style
sets to stroke and fill geometry
Definition SkPaint.h:195
void setAlpha(U8CPU a)
Definition SkPaint.h:279
void setPathEffect(sk_sp< SkPathEffect > pathEffect)
SkScalar getStrokeWidth() const
Definition SkPaint.h:300
@ kMiter_Join
extends to miter limit
Definition SkPaint.h:359
uint8_t getAlpha() const
Definition SkPaint.h:264
Cap getStrokeCap() const
Definition SkPaint.h:372
void setStrokeWidth(SkScalar width)
Definition SkPaint.cpp:159
std::optional< SkBlendMode > asBlendMode() const
Definition SkPaint.cpp:138
bool asPoints(PointData *results, const SkPath &src, const SkStrokeRec &, const SkMatrix &, const SkRect *cullR) const
static bool TooBigForMath(const SkRect &bounds)
Definition SkPathPriv.h:290
bool isEmpty() const
Definition SkPath.cpp:406
bool isInverseFillType() const
Definition SkPath.h:244
int countPoints() const
Definition SkPath.cpp:525
void setFillType(SkPathFillType ft)
Definition SkPath.h:235
SkPath & setIsVolatile(bool isVolatile)
Definition SkPath.h:370
const SkRect & getBounds() const
Definition SkPath.cpp:420
void transform(const SkMatrix &matrix, SkPath *dst, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
Definition SkPath.cpp:1647
static SkPath Line(const SkPoint a, const SkPoint b)
Definition SkPath.h:106
SkPath & addRect(const SkRect &rect, SkPathDirection dir, unsigned start)
Definition SkPath.cpp:854
int width() const
Definition SkPixmap.h:160
int height() const
Definition SkPixmap.h:166
bool transform(const SkMatrix &matrix, SkRRect *dst) const
Definition SkRRect.cpp:436
const SkIRect & getBounds() const
bool isEmpty() const
bool quickReject(const SkIRect &rect) const
static bool FitsInFixed(const SkRect &r)
Definition SkRectPriv.h:56
static void HairRoundPath(const SkPath &, const SkRasterClip &, SkBlitter *)
static void HairPath(const SkPath &, const SkRasterClip &, SkBlitter *)
static void HairSquarePath(const SkPath &, const SkRasterClip &, SkBlitter *)
static void AntiHairRect(const SkRect &, const SkRasterClip &, SkBlitter *)
static void AntiFillRect(const SkRect &, const SkRasterClip &, SkBlitter *)
static void FillRect(const SkRect &, const SkRasterClip &, SkBlitter *)
Definition SkScan.cpp:95
static void AntiFillPath(const SkPath &, const SkRasterClip &, SkBlitter *)
static void AntiHairPath(const SkPath &, const SkRasterClip &, SkBlitter *)
static void FrameRect(const SkRect &, const SkPoint &strokeSize, const SkRasterClip &, SkBlitter *)
static void AntiHairRoundPath(const SkPath &, const SkRasterClip &, SkBlitter *)
static void FillPath(const SkPath &, const SkIRect &, SkBlitter *)
static void AntiHairSquarePath(const SkPath &, const SkRasterClip &, SkBlitter *)
static void AntiFrameRect(const SkRect &, const SkPoint &strokeSize, const SkRasterClip &, SkBlitter *)
static void FillIRect(const SkIRect &, const SkRasterClip &, SkBlitter *)
Definition SkScan.cpp:65
static void HairRect(const SkRect &, const SkRasterClip &, SkBlitter *)
@ kHairline_InitStyle
Definition SkStrokeRec.h:25
Definition SkZip.h:25
const Paint & paint
VkDevice device
Definition main.cc:53
float SkScalar
Definition extension.cpp:12
GAsyncResult * result
double y
double x
unsigned useCenter Optional< SkMatrix > matrix
Definition SkRecords.h:258
static void swap(TArray< T, M > &a, TArray< T, M > &b)
Definition SkTArray.h:737
SK_API bool FillPathWithPaint(const SkPath &src, const SkPaint &paint, SkPath *dst, const SkRect *cullRect, SkScalar resScale=1)
int32_t width
const Scalar scale
int32_t fX
x-axis value
int32_t fY
y-axis value
static constexpr SkIPoint Make(int32_t x, int32_t y)
SkIRect makeOutset(int32_t dx, int32_t dy) const
Definition SkRect.h:350
constexpr int32_t height() const
Definition SkRect.h:165
int32_t fTop
smaller y-axis bounds
Definition SkRect.h:34
constexpr int32_t width() const
Definition SkRect.h:158
static constexpr SkIRect MakeWH(int32_t w, int32_t h)
Definition SkRect.h:56
bool isEmpty() const
Definition SkRect.h:202
void setWH(int32_t width, int32_t height)
Definition SkRect.h:275
int32_t fLeft
smaller x-axis bounds
Definition SkRect.h:33
void outset(int32_t dx, int32_t dy)
Definition SkRect.h:428
bool contains(int32_t x, int32_t y) const
Definition SkRect.h:463
@ kComputeBoundsAndRenderImage_CreateMode
compute bounds, alloc image and render into it
Definition SkMask.h:301
@ kJustRenderImage_CreateMode
render into preallocate mask
Definition SkMask.h:300
@ kJustComputeBounds_CreateMode
compute bounds and return
Definition SkMask.h:299
@ kZeroInit_Alloc
Definition SkMask.h:293
static uint8_t * AllocImage(size_t bytes, AllocType=kUninit_Alloc)
Definition SkMask.cpp:45
@ kA8_Format
8bits per pixel mask (e.g. antialiasing)
Definition SkMask.h:28
const SkIRect fBounds
Definition SkMask.h:42
float fX
x-axis value
static constexpr SkPoint Make(float x, float y)
float fY
y-axis value
constexpr float y() const
constexpr float x() const
static SkRect Make(const SkISize &size)
Definition SkRect.h:669
SkScalar fBottom
larger y-axis bounds
Definition extension.cpp:17
SkScalar fLeft
smaller x-axis bounds
Definition extension.cpp:14
void outset(float dx, float dy)
Definition SkRect.h:1077
SkRect makeOutset(float dx, float dy) const
Definition SkRect.h:1002
SkScalar fRight
larger x-axis bounds
Definition extension.cpp:16
void roundOut(SkIRect *dst) const
Definition SkRect.h:1241
void setLTRB(float left, float top, float right, float bottom)
Definition SkRect.h:865
void sort()
Definition SkRect.h:1313
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
Definition SkRect.h:646
SkScalar fTop
smaller y-axis bounds
Definition extension.cpp:15