Flutter Engine
The Flutter Engine
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
95 SkPoint pt = { paint.getStrokeWidth(), paint.getStrokeWidth() };
96 matrix.mapVectors(&size, &pt, 1);
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
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.
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
467void SkDrawBase::paintMasks(SkZip<const SkGlyph*, SkPoint>, const SkPaint&) const {
468 SkASSERT(false);
469}
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
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,
530 draw.fBlitterChooser = SkA8Blitter_Choose;
531 if (!draw.fDst.reset(mask)) {
532 return;
533 }
534
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
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
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
Definition: FontMgrTest.cpp:50
#define SkDEBUGFAIL(message)
Definition: SkAssert.h:118
#define SkASSERT(cond)
Definition: SkAssert.h:116
bool SkBlendMode_SupportsCoverageAsAlpha(SkBlendMode mode)
Definition: SkBlendMode.cpp:53
SkBlitter * SkA8Blitter_Choose(const SkPixmap &dst, const SkMatrix &ctm, const SkPaint &paint, SkArenaAlloc *alloc, bool drawCoverage, sk_sp< SkShader > clipShader, const SkSurfaceProps &)
unsigned U8CPU
Definition: SkCPUTypes.h:18
static const SkPoint * rect_points(const SkRect &r)
Definition: SkDrawBase.cpp:139
static SkPoint compute_stroke_size(const SkPaint &paint, const SkMatrix &matrix)
Definition: SkDrawBase.cpp:90
bool SkDrawTreatAAStrokeAsHairline(SkScalar strokeWidth, const SkMatrix &matrix, SkScalar *coverage)
Definition: SkDrawBase.cpp:262
static SkScalar fast_len(const SkVector &vec)
Definition: SkDrawBase.cpp:252
static void draw_rect_as_path(const SkDrawBase &orig, const SkRect &prePaintRect, const SkPaint &paint, const SkMatrix &ctm)
Definition: SkDrawBase.cpp:147
static bool easy_rect_join(const SkRect &rect, const SkPaint &paint, const SkMatrix &matrix, SkPoint *strokeSize)
Definition: SkDrawBase.cpp:100
static void draw_into_mask(const SkMask &mask, const SkPath &devPath, SkStrokeRec::InitStyle style)
Definition: SkDrawBase.cpp:527
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:3892
@ DRAW_PATH
Definition: SkPictureFlat.h:47
void swap(sk_sp< T > &a, sk_sp< T > &b)
Definition: SkRefCnt.h:341
#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
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
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
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
@ kFill_RectType
Definition: SkDrawBase.h:97
@ kPath_RectType
Definition: SkDrawBase.h:99
@ kHair_RectType
Definition: SkDrawBase.h:96
@ kStroke_RectType
Definition: SkDrawBase.h:98
void drawRRect(const SkRRect &, const SkPaint &) const
Definition: SkDrawBase.cpp:286
void drawPath(const SkPath &path, const SkPaint &paint, const SkMatrix *prePathMatrix=nullptr, bool pathIsMutable=false) const
Definition: SkDrawBase.h:60
static bool DrawToMask(const SkPath &devPath, const SkIRect &clipBounds, const SkMaskFilter *, const SkMatrix *filterMatrix, SkMaskBuilder *dst, SkMaskBuilder::CreateMode mode, SkStrokeRec::InitStyle style)
Definition: SkDrawBase.cpp:559
static bool ComputeMaskBounds(const SkRect &devPathBounds, const SkIRect &clipBounds, const SkMaskFilter *filter, const SkMatrix *filterMatrix, SkIRect *bounds)
Definition: SkDrawBase.cpp:494
void drawPaint(const SkPaint &) const
Definition: SkDrawBase.cpp:74
const SkRasterClip * fRC
Definition: SkDrawBase.h:156
void drawRect(const SkRect &prePaintRect, const SkPaint &, const SkMatrix *paintMatrix, const SkRect *postPaintRect) const
Definition: SkDrawBase.cpp:159
SkPixmap fDst
Definition: SkDrawBase.h:153
void validate() const
Definition: SkDrawBase.h:162
static RectType ComputeRectType(const SkRect &, const SkPaint &, const SkMatrix &, SkPoint *strokeSize)
Definition: SkDrawBase.cpp:111
const SkMatrix * fCTM
Definition: SkDrawBase.h:155
void drawDevicePoints(SkCanvas::PointMode, size_t count, const SkPoint[], const SkPaint &, SkDevice *) const
Definition: SkDrawBase.cpp:597
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
Definition: SkMatrix.cpp:1141
@ 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
Definition: SkPath.h:59
bool isEmpty() const
Definition: SkPath.cpp:416
bool isInverseFillType() const
Definition: SkPath.h:244
int countPoints() const
Definition: SkPath.cpp:535
void setFillType(SkPathFillType ft)
Definition: SkPath.h:235
SkPath & setIsVolatile(bool isVolatile)
Definition: SkPath.h:370
const SkRect & getBounds() const
Definition: SkPath.cpp:430
void transform(const SkMatrix &matrix, SkPath *dst, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
Definition: SkPath.cpp:1711
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:864
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
Definition: SkRasterClip.h:60
bool isEmpty() const
Definition: SkRasterClip.h:47
bool quickReject(const SkIRect &rect) const
Definition: SkRasterClip.h:85
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
Definition: color_source.cc:38
VkDevice device
Definition: main.cc:53
float SkScalar
Definition: extension.cpp:12
GAsyncResult * result
static float min(float r, float g, float b)
Definition: hsl.cpp:48
double y
double x
unsigned useCenter Optional< SkMatrix > matrix
Definition: SkRecords.h:258
Optional< SkRect > bounds
Definition: SkRecords.h:189
SkRRect rrect
Definition: SkRecords.h:232
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
Definition: switches.h:228
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
dst
Definition: cp.py:12
SK_API bool FillPathWithPaint(const SkPath &src, const SkPaint &paint, SkPath *dst, const SkRect *cullRect, SkScalar resScale=1)
Definition: SkPathUtils.cpp:23
int32_t width
const Scalar scale
int32_t fX
x-axis value
Definition: SkPoint_impl.h:29
int32_t fY
y-axis value
Definition: SkPoint_impl.h:30
static constexpr SkIPoint Make(int32_t x, int32_t y)
Definition: SkPoint_impl.h:38
Definition: SkRect.h:32
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
Definition: SkMask.h:25
@ 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
Definition: SkPoint_impl.h:164
static constexpr SkPoint Make(float x, float y)
Definition: SkPoint_impl.h:173
float fY
y-axis value
Definition: SkPoint_impl.h:165
constexpr float y() const
Definition: SkPoint_impl.h:187
constexpr float x() const
Definition: SkPoint_impl.h:181
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