Flutter Engine
The Flutter Engine
SkCanvas.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2008 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
9
21#include "include/core/SkPath.h"
46#include "src/base/SkMSAN.h"
50#include "src/core/SkDevice.h"
64#include "src/text/GlyphRun.h"
66
67#include <algorithm>
68#include <memory>
69#include <new>
70#include <optional>
71#include <tuple>
72#include <utility>
73
74#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
75#define RETURN_ON_FALSE(pred) do { if (!(pred)) return; } while (0)
76
77// This is a test: static_assert with no message is a c++17 feature,
78// and std::max() is constexpr only since the c++14 stdlib.
79static_assert(std::max(3,4) == 4);
80
82
83///////////////////////////////////////////////////////////////////////////////////////////////////
84
85SK_MAKE_BITMASK_OPS(SkCanvas::PredrawFlags)
86
87/*
88 * Return true if the drawing this rect would hit every pixels in the canvas.
89 *
90 * Returns false if
91 * - rect does not contain the canvas' bounds
92 * - paint is not fill
93 * - paint would blur or otherwise change the coverage of the rect
94 */
95bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
97 // Convert flags to a ShaderOverrideOpacity enum
98 auto overrideOpacity = (flags & PredrawFlags::kOpaqueShaderOverride) ?
100 (flags & PredrawFlags::kNonOpaqueShaderOverride) ?
103
104 const SkISize size = this->getBaseLayerSize();
105 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
106
107 // if we're clipped at all, we can't overwrite the entire surface
108 {
109 const SkDevice* root = this->rootDevice();
110 const SkDevice* top = this->topDevice();
111 if (root != top) {
112 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
113 }
114 if (!root->isClipWideOpen()) {
115 return false;
116 }
117 }
118
119 if (rect) {
120 if (!this->getTotalMatrix().isScaleTranslate()) {
121 return false; // conservative
122 }
123
124 SkRect devRect;
125 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
126 if (!devRect.contains(bounds)) {
127 return false;
128 }
129 }
130
131 if (paint) {
132 SkPaint::Style paintStyle = paint->getStyle();
133 if (!(paintStyle == SkPaint::kFill_Style ||
134 paintStyle == SkPaint::kStrokeAndFill_Style)) {
135 return false;
136 }
137 if (paint->getMaskFilter() || paint->getPathEffect() || paint->getImageFilter()) {
138 return false; // conservative
139 }
140 }
141 return SkPaintPriv::Overwrites(paint, overrideOpacity);
142}
143
144///////////////////////////////////////////////////////////////////////////////////////////////////
145
146bool SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
147 if (fSurfaceBase) {
148 if (!fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
151 return false;
152 }
153 }
154 return true;
155}
156
157bool SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
159 if (fSurfaceBase) {
161 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
162 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
163 // and therefore we don't care which mode we're in.
164 //
165 if (fSurfaceBase->outstandingImageSnapshot()) {
166 if (this->wouldOverwriteEntireSurface(rect, paint, flags)) {
168 }
169 }
170 if (!fSurfaceBase->aboutToDraw(mode)) {
171 return false;
172 }
173 }
174 return true;
175}
176
177///////////////////////////////////////////////////////////////////////////////
178
179SkCanvas::Layer::Layer(sk_sp<SkDevice> device,
180 FilterSpan imageFilters,
181 const SkPaint& paint,
182 bool isCoverage)
183 : fDevice(std::move(device))
184 , fImageFilters(imageFilters.data(), imageFilters.size())
185 , fPaint(paint)
186 , fIsCoverage(isCoverage)
187 , fDiscard(false) {
188 SkASSERT(fDevice);
189 // Any image filter should have been pulled out and stored in 'imageFilter' so that 'paint'
190 // can be used as-is to draw the result of the filter to the dst device.
191 SkASSERT(!fPaint.getImageFilter());
192}
193
194SkCanvas::BackImage::BackImage(sk_sp<SkSpecialImage> img, SkIPoint loc)
195 :fImage(img), fLoc(loc) {}
196SkCanvas::BackImage::BackImage(const BackImage&) = default;
197SkCanvas::BackImage::BackImage(BackImage&&) = default;
198SkCanvas::BackImage& SkCanvas::BackImage::operator=(const BackImage&) = default;
199SkCanvas::BackImage::~BackImage() = default;
200
201SkCanvas::MCRec::MCRec(SkDevice* device) : fDevice(device) {
202 SkASSERT(fDevice);
203}
204
205SkCanvas::MCRec::MCRec(const MCRec* prev) : fDevice(prev->fDevice), fMatrix(prev->fMatrix) {
206 SkASSERT(fDevice);
207}
208
209SkCanvas::MCRec::~MCRec() {}
210
211void SkCanvas::MCRec::newLayer(sk_sp<SkDevice> layerDevice,
212 FilterSpan filters,
213 const SkPaint& restorePaint,
214 bool layerIsCoverage) {
215 SkASSERT(!fBackImage);
216 fLayer =
217 std::make_unique<Layer>(std::move(layerDevice), filters, restorePaint, layerIsCoverage);
218 fDevice = fLayer->fDevice.get();
219}
220
222 SkASSERT(!fLayer);
224 SkASSERT(fDeferredSaveCount == 0);
225 fDevice = device;
227}
228
230public:
231 explicit AutoUpdateQRBounds(SkCanvas* canvas) : fCanvas(canvas) {
232 // pre-condition, fQuickRejectBounds and other state should be valid before anything
233 // modifies the device's clip.
234 fCanvas->validateClip();
235 }
237 fCanvas->fQuickRejectBounds = fCanvas->computeDeviceClipBounds();
238 // post-condition, we should remain valid after re-computing the bounds
239 fCanvas->validateClip();
240 }
241
242private:
243 SkCanvas* fCanvas;
244
246 AutoUpdateQRBounds(const AutoUpdateQRBounds&) = delete;
247 AutoUpdateQRBounds& operator=(AutoUpdateQRBounds&&) = delete;
248 AutoUpdateQRBounds& operator=(const AutoUpdateQRBounds&) = delete;
249};
250
251/////////////////////////////////////////////////////////////////////////////
252
253std::optional<AutoLayerForImageFilter> SkCanvas::aboutToDraw(
254 const SkPaint& paint,
255 const SkRect* rawBounds,
257 if (flags & PredrawFlags::kCheckForOverwrite) {
258 if (!this->predrawNotify(rawBounds, &paint, flags)) {
259 return std::nullopt;
260 }
261 } else {
262 if (!this->predrawNotify()) {
263 return std::nullopt;
264 }
265 }
266
267 // TODO: Eventually all devices will use this code path and this will just test 'flags'.
268 const bool skipMaskFilterLayer = (flags & PredrawFlags::kSkipMaskFilterAutoLayer) ||
269 !this->topDevice()->useDrawCoverageMaskForMaskFilters();
270 return std::optional<AutoLayerForImageFilter>(
271 std::in_place, this, paint, rawBounds, skipMaskFilterLayer);
272}
273
274std::optional<AutoLayerForImageFilter> SkCanvas::aboutToDraw(
275 const SkPaint& paint,
276 const SkRect* rawBounds) {
277 return this->aboutToDraw(paint, rawBounds, PredrawFlags::kNone);
278}
279
280////////////////////////////////////////////////////////////////////////////
281
282void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
283 this->restoreToCount(1);
284
285 // We're peering through a lot of structs here. Only at this scope do we know that the device
286 // is a SkNoPixelsDevice.
287 SkASSERT(fRootDevice->isNoPixelsDevice());
288 SkNoPixelsDevice* asNoPixelsDevice = static_cast<SkNoPixelsDevice*>(fRootDevice.get());
289 if (!asNoPixelsDevice->resetForNextPicture(bounds)) {
290 fRootDevice = sk_make_sp<SkNoPixelsDevice>(bounds,
291 fRootDevice->surfaceProps(),
292 fRootDevice->imageInfo().refColorSpace());
293 }
294
295 fMCRec->reset(fRootDevice.get());
296 fQuickRejectBounds = this->computeDeviceClipBounds();
297}
298
299void SkCanvas::init(sk_sp<SkDevice> device) {
300 // SkCanvas.h declares internal storage for the hidden struct MCRec, and this
301 // assert ensure it's sufficient. <= is used because the struct has pointer fields, so the
302 // declared size is an upper bound across architectures. When the size is smaller, more stack
303 static_assert(sizeof(MCRec) <= kMCRecSize);
304
305 if (!device) {
306 device = sk_make_sp<SkNoPixelsDevice>(SkIRect::MakeEmpty(), fProps);
307 }
308
309 // From this point on, SkCanvas will always have a device
311
312 fSaveCount = 1;
313 fMCRec = new (fMCStack.push_back()) MCRec(device.get());
314
315 // The root device and the canvas should always have the same pixel geometry
316 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
317
318 fSurfaceBase = nullptr;
319 fRootDevice = std::move(device);
320 fScratchGlyphRunBuilder = std::make_unique<sktext::GlyphRunBuilder>();
321 fQuickRejectBounds = this->computeDeviceClipBounds();
322}
323
324SkCanvas::SkCanvas() : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
325 this->init(nullptr);
326}
327
329 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
330 , fProps(SkSurfacePropsCopyOrDefault(props)) {
331 this->init(sk_make_sp<SkNoPixelsDevice>(
332 SkIRect::MakeWH(std::max(width, 0), std::max(height, 0)), fProps));
333}
334
336 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
337 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
338 this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps));
339}
340
342 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
343 , fProps(device->surfaceProps()) {
344 this->init(std::move(device));
345}
346
348 // Mark all pending layers to be discarded during restore (rather than drawn)
350 for (;;) {
351 MCRec* rec = (MCRec*)iter.next();
352 if (!rec) {
353 break;
354 }
355 if (rec->fLayer) {
356 rec->fLayer->fDiscard = true;
357 }
358 }
359
360 // free up the contents of our deque
361 this->restoreToCount(1); // restore everything but the last
362 this->internalRestore(); // restore the last, since we're going away
363}
364
366 return fSurfaceBase;
367}
368
370 return this->rootDevice()->imageInfo().dimensions();
371}
372
373SkDevice* SkCanvas::topDevice() const {
374 SkASSERT(fMCRec->fDevice);
375 return fMCRec->fDevice;
376}
377
378bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
379 return pm.addr() && this->rootDevice()->readPixels(pm, x, y);
380}
381
382bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
383 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
384}
385
386bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
387 SkPixmap pm;
388 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
389}
390
391bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
392 SkPixmap pm;
393 if (bitmap.peekPixels(&pm)) {
394 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
395 }
396 return false;
397}
398
399bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
400 int x, int y) {
401 SkDevice* device = this->rootDevice();
402
403 // This check gives us an early out and prevents generation ID churn on the surface.
404 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
405 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
406 if (!srcRect.intersect({0, 0, device->width(), device->height()})) {
407 return false;
408 }
409
410 // Tell our owning surface to bump its generation ID.
411 const bool completeOverwrite = srcRect.size() == device->imageInfo().dimensions();
412 if (!this->predrawNotify(completeOverwrite)) {
413 return false;
414 }
415
416 // This can still fail, most notably in the case of a invalid color type or alpha type
417 // conversion. We could pull those checks into this function and avoid the unnecessary
418 // generation ID bump. But then we would be performing those checks twice, since they
419 // are also necessary at the bitmap/pixmap entry points.
420 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
421}
422
423//////////////////////////////////////////////////////////////////////////////
424
425void SkCanvas::checkForDeferredSave() {
426 if (fMCRec->fDeferredSaveCount > 0) {
427 this->doSave();
428 }
429}
430
432#ifdef SK_DEBUG
433 int count = 0;
435 for (;;) {
436 const MCRec* rec = (const MCRec*)iter.next();
437 if (!rec) {
438 break;
439 }
440 count += 1 + rec->fDeferredSaveCount;
441 }
442 SkASSERT(count == fSaveCount);
443#endif
444 return fSaveCount;
445}
446
448 fSaveCount += 1;
449 fMCRec->fDeferredSaveCount += 1;
450 return this->getSaveCount() - 1; // return our prev value
451}
452
453void SkCanvas::doSave() {
454 this->willSave();
455
456 SkASSERT(fMCRec->fDeferredSaveCount > 0);
457 fMCRec->fDeferredSaveCount -= 1;
458 this->internalSave();
459}
460
462 if (fMCRec->fDeferredSaveCount > 0) {
463 SkASSERT(fSaveCount > 1);
464 fSaveCount -= 1;
465 fMCRec->fDeferredSaveCount -= 1;
466 } else {
467 // check for underflow
468 if (fMCStack.count() > 1) {
469 this->willRestore();
470 SkASSERT(fSaveCount > 1);
471 fSaveCount -= 1;
472 this->internalRestore();
473 this->didRestore();
474 }
475 }
476}
477
479 // safety check
480 if (count < 1) {
481 count = 1;
482 }
483
484 int n = this->getSaveCount() - count;
485 for (int i = 0; i < n; ++i) {
486 this->restore();
487 }
488}
489
490void SkCanvas::internalSave() {
491 fMCRec = new (fMCStack.push_back()) MCRec(fMCRec);
492
493 this->topDevice()->pushClipStack();
494}
495
497 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
498}
499
501 TRACE_EVENT0("skia", TRACE_FUNC);
502 if (rec.fPaint && rec.fPaint->nothingToDraw()) {
503 // no need for the layer (or any of the draws until the matching restore()
504 this->save();
505 this->clipRect({0,0,0,0});
506 } else {
507 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
508 fSaveCount += 1;
509 this->internalSaveLayer(rec, strategy);
510 }
511 return this->getSaveCount() - 1;
512}
513
514int SkCanvas::only_axis_aligned_saveBehind(const SkRect* bounds) {
515 if (bounds && !this->getLocalClipBounds().intersects(*bounds)) {
516 // Assuming clips never expand, if the request bounds is outside of the current clip
517 // there is no need to copy/restore the area, so just devolve back to a regular save.
518 this->save();
519 } else {
520 bool doTheWork = this->onDoSaveBehind(bounds);
521 fSaveCount += 1;
522 this->internalSave();
523 if (doTheWork) {
524 this->internalSaveBehind(bounds);
525 }
526 }
527 return this->getSaveCount() - 1;
528}
529
530// Helper function to compute the center reference point used for scale decomposition under
531// non-linear transformations.
533 const SkMatrix& dstToLocal,
534 std::optional<skif::ParameterSpace<SkRect>> contentBounds,
535 const skif::DeviceSpace<SkIRect>& targetOutput) {
536 // Will use the inverse and center of the device bounds if the content bounds aren't provided.
537 SkRect rect = contentBounds ? SkRect(*contentBounds) : SkRect::Make(SkIRect(targetOutput));
538 SkPoint center = {rect.centerX(), rect.centerY()};
539 if (!contentBounds) {
540 // Theoretically, the inverse transform could put center's homogeneous coord behind W = 0,
541 // but that case is handled automatically in Mapping::decomposeCTM later.
542 dstToLocal.mapPoints(&center, 1);
543 }
544
546}
547
548// Helper when we need to upgrade a single filter to a FilterSpan
550 FilterToSpan(const SkImageFilter* filter) : fFilter(sk_ref_sp(filter)) {}
551
554 }
555
557};
558
559// Compute suitable transformations and layer bounds for a new layer that will be used as the source
560// input into 'filter' before being drawn into 'dst' via the returned skif::Mapping.
561// Null filters are permitted and act as the identity. The returned mapping will be compatible with
562// the image filter.
563//
564// An empty optional is returned if the layer mapping and bounds couldn't be determined, in which
565// case the layer should be skipped. An instantiated optional can have an empty layer bounds rect
566// if the image filter doesn't require an input image to produce a valid output.
567static std::optional<std::pair<skif::Mapping, skif::LayerSpace<SkIRect>>>
569 SkCanvas::FilterSpan filters,
570 const SkMatrix& localToDst,
571 const skif::DeviceSpace<SkIRect>& targetOutput,
572 std::optional<skif::ParameterSpace<SkRect>> contentBounds = {},
573 SkScalar scaleFactor = 1.0f) {
574 SkMatrix dstToLocal;
575 if (!localToDst.isFinite() ||
576 !localToDst.invert(&dstToLocal)) {
577 return {};
578 }
579
581 compute_decomposition_center(dstToLocal, contentBounds, targetOutput);
582
583 // Determine initial mapping and a reasonable maximum dimension to prevent layer-to-device
584 // transforms with perspective and skew from triggering excessive buffer allocations.
585 skif::Mapping mapping;
587 for (const sk_sp<SkImageFilter>& filter : filters) {
588 if (filter) {
589 capability = std::min(capability, as_IFB(filter)->getCTMCapability());
590 }
591 }
592 if (!mapping.decomposeCTM(localToDst, capability, center)) {
593 return {};
594 }
595 // Push scale factor into layer matrix and device matrix (net no change, but the layer will have
596 // its resolution adjusted in comparison to the final device).
597 if (scaleFactor != 1.0f &&
598 !mapping.adjustLayerSpace(SkMatrix::Scale(scaleFactor, scaleFactor))) {
599 return {};
600 }
601
602 // Perspective and skew could exceed this since mapping.deviceToLayer(targetOutput) is
603 // theoretically unbounded under those conditions. Under a 45 degree rotation, a layer needs to
604 // be 2X larger per side of the prior device in order to fully cover it. We use the max of that
605 // and 2048 for a reasonable upper limit (this allows small layers under extreme transforms to
606 // use more relative resolution than a larger layer).
607 static const int kMinDimThreshold = 2048;
608 int maxLayerDim = std::max(Sk64_pin_to_s32(2 * std::max(SkIRect(targetOutput).width64(),
609 SkIRect(targetOutput).height64())),
610 kMinDimThreshold);
611
612 auto baseLayerBounds = mapping.deviceToLayer(targetOutput);
613 if (contentBounds) {
614 // For better or for worse, user bounds currently act as a hard clip on the layer's
615 // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
616 skif::LayerSpace<SkIRect> knownBounds = mapping.paramToLayer(*contentBounds).roundOut();
617 if (!baseLayerBounds.intersect(knownBounds)) {
618 baseLayerBounds = skif::LayerSpace<SkIRect>::Empty();
619 }
620 }
621
622 skif::LayerSpace<SkIRect> layerBounds;
623 if (!filters.empty()) {
624 layerBounds = skif::LayerSpace<SkIRect>::Union(filters.size(), [&](int i) {
625 return filters[i] ? as_IFB(filters[i])
626 ->getInputBounds(mapping, targetOutput, contentBounds)
627 : baseLayerBounds;
628 });
629 // When a filter is involved, the layer size may be larger than the default maxLayerDim due
630 // to required inputs for filters (e.g. a displacement map with a large radius).
631 if (layerBounds.width() > maxLayerDim || layerBounds.height() > maxLayerDim) {
632 skif::Mapping idealMapping{mapping.layerMatrix()};
633 for (const sk_sp<SkImageFilter>& filter : filters) {
634 if (filter) {
635 auto idealLayerBounds = as_IFB(filter)->getInputBounds(
636 idealMapping, targetOutput, contentBounds);
637 maxLayerDim = std::max(std::max(idealLayerBounds.width(),
638 idealLayerBounds.height()),
639 maxLayerDim);
640 }
641 }
642 }
643 } else {
644 if (baseLayerBounds.isEmpty()) {
645 return {};
646 }
647 layerBounds = baseLayerBounds;
648 }
649
650 if (layerBounds.width() > maxLayerDim || layerBounds.height() > maxLayerDim) {
651 skif::LayerSpace<SkIRect> newLayerBounds(
652 SkIRect::MakeWH(std::min(layerBounds.width(), maxLayerDim),
653 std::min(layerBounds.height(), maxLayerDim)));
655 SkRect::Make(SkIRect(newLayerBounds)),
657 if (!mapping.adjustLayerSpace(adjust)) {
658 return {};
659 } else {
660 layerBounds = newLayerBounds;
661 }
662 }
663
664 return std::make_pair(mapping, layerBounds);
665}
666
667// Ideally image filters operate in the dst color type, but if there is insufficient alpha bits
668// we move some bits from color channels into the alpha channel since that can greatly improve
669// the quality of blurs and other filters.
671 if (dstInfo.bytesPerPixel() <= 4 &&
672 dstInfo.colorType() != kRGBA_8888_SkColorType &&
673 dstInfo.colorType() != kBGRA_8888_SkColorType) {
674 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888
675 return kN32_SkColorType;
676 } else {
677 return dstInfo.colorType();
678 }
679}
680
683 const SkPaint& paint) {
684 // The only effects that apply to layers (other than the SkImageFilter that made this image in
685 // the first place) are transparency and color filters.
687 if (paint.getAlphaf() < 1.f) {
688 result = result.applyColorFilter(ctx, SkColorFilters::Blend(paint.getColor4f(),
689 /*colorSpace=*/nullptr,
691 }
692 if (paint.getColorFilter()) {
693 result = result.applyColorFilter(ctx, paint.refColorFilter());
694 }
695 return result;
696}
697
698void SkCanvas::internalDrawDeviceWithFilter(SkDevice* src,
699 SkDevice* dst,
700 FilterSpan filters,
701 const SkPaint& paint,
702 DeviceCompatibleWithFilter compat,
703 const SkColorInfo& filterColorInfo,
704 SkScalar scaleFactor,
705 bool srcIsCoverageLayer) {
706 // The dst is always required, the src can be null if 'filter' is non-null and does not require
707 // a source image. For regular filters, 'src' is the layer and 'dst' is the parent device. For
708 // backdrop filters, 'src' is the parent device and 'dst' is the layer.
709 SkASSERT(dst);
710
711 sk_sp<SkColorSpace> filterColorSpace = filterColorInfo.refColorSpace();
712
713 const SkColorType filterColorType =
714 srcIsCoverageLayer ? kAlpha_8_SkColorType : image_filter_color_type(filterColorInfo);
715
716 // 'filter' sees the src device's buffer as the implicit input image, and processes the image
717 // in this device space (referred to as the "layer" space). However, the filter
718 // parameters need to respect the current matrix, which is not necessarily the local matrix that
719 // was set on 'src' (e.g. because we've popped src off the stack already).
720 // TODO (michaelludwig): Stay in SkM44 once skif::Mapping supports SkM44 instead of SkMatrix.
721 SkMatrix localToSrc = src ? (src->globalToDevice() * fMCRec->fMatrix).asM33() : SkMatrix::I();
722 SkISize srcDims = src ? src->imageInfo().dimensions() : SkISize::Make(0, 0);
723
724 // Whether or not we need to make a transformed tmp image from 'src', and what that transform is
726
727 skif::Mapping mapping;
728 skif::LayerSpace<SkIRect> requiredInput;
729 skif::DeviceSpace<SkIRect> outputBounds{dst->devClipBounds()};
730 if (compat == DeviceCompatibleWithFilter::kYes) {
731 // Just use the relative transform from src to dst and the src's whole image, since
732 // internalSaveLayer should have already determined what was necessary. We explicitly
733 // construct the inverse (dst->src) to avoid the case where src's and dst's coord transforms
734 // were individually invertible by SkM44::invert() but their product is considered not
735 // invertible by SkMatrix::invert(). When this happens the matrices are already poorly
736 // conditioned so getRelativeTransform() gives us something reasonable.
737 SkASSERT(src);
738 SkASSERT(scaleFactor == 1.0f);
739 SkASSERT(!srcDims.isEmpty());
740
741 mapping = skif::Mapping(src->getRelativeTransform(*dst),
742 dst->getRelativeTransform(*src),
743 localToSrc);
744 requiredInput = skif::LayerSpace<SkIRect>(SkIRect::MakeSize(srcDims));
746 } else {
747 // Compute the image filter mapping by decomposing the local->device matrix of dst and
748 // re-determining the required input.
749 auto mappingAndBounds = get_layer_mapping_and_bounds(
750 filters, dst->localToDevice(), outputBounds, {}, SkTPin(scaleFactor, 0.f, 1.f));
751 if (!mappingAndBounds) {
752 return;
753 }
754
755 std::tie(mapping, requiredInput) = *mappingAndBounds;
756 if (src) {
757 if (!requiredInput.isEmpty()) {
758 // The above mapping transforms from local to dst's device space, where the layer
759 // space represents the intermediate buffer. Now we need to determine the transform
760 // from src to intermediate to prepare the input to the filter.
761 SkMatrix srcToLocal;
762 if (!localToSrc.invert(&srcToLocal)) {
763 return;
764 }
766 srcToLocal));
767 } // Else no input is needed which can happen if a backdrop filter that doesn't use src
768 } else {
769 // Trust the caller that no input was required, but keep the calculated mapping
770 requiredInput = skif::LayerSpace<SkIRect>::Empty();
771 }
772 }
773
774 // Start out with an empty source image, to be replaced with the snapped 'src' device.
775 auto backend = dst->createImageFilteringBackend(src ? src->surfaceProps() : dst->surfaceProps(),
776 filterColorType);
778 skif::Context ctx{std::move(backend),
779 mapping,
780 requiredInput,
782 filterColorSpace.get(),
783 &stats};
784
786 if (src && !requiredInput.isEmpty()) {
788 if (!srcToLayer.inverseMapRect(requiredInput, &srcSubset)) {
789 return;
790 }
791
792 // Include the layer in the offscreen count
793 ctx.markNewSurface();
794
795 auto availSrc = skif::LayerSpace<SkIRect>(src->size()).relevantSubset(
796 srcSubset, SkTileMode::kClamp);
797
798 if (SkMatrix(srcToLayer).isScaleTranslate()) {
799 // Apply the srcToLayer transformation directly while snapping an image from the src
800 // device. Calculate the subset of requiredInput that corresponds to srcSubset that was
801 // restricted to the actual src dimensions.
802 auto requiredSubset = srcToLayer.mapRect(availSrc);
803 if (requiredSubset.width() == availSrc.width() &&
804 requiredSubset.height() == availSrc.height()) {
805 // Unlike snapSpecialScaled(), snapSpecial() can avoid a copy when the underlying
806 // representation permits it.
807 source = {src->snapSpecial(SkIRect(availSrc)), requiredSubset.topLeft()};
808 } else {
809 SkASSERT(compat == DeviceCompatibleWithFilter::kUnknown);
810 source = {src->snapSpecialScaled(SkIRect(availSrc),
811 SkISize(requiredSubset.size())),
812 requiredSubset.topLeft()};
813 ctx.markNewSurface();
814 }
815 }
816
817 if (compat == DeviceCompatibleWithFilter::kYes) {
818 // Padding was added to the source image when the 'src' SkDevice was created, so inset
819 // to allow bounds tracking to skip shader-based tiling when possible.
820 if (!filters.empty()) {
821 source = source.insetForSaveLayer();
822 }
823 } else if (source) {
824 // A backdrop filter that succeeded in snapSpecial() or snapSpecialScaled(), but since
825 // the 'src' device wasn't prepared with 'requiredInput' in mind, add clamping.
826 source = source.applyCrop(ctx, source.layerBounds(), SkTileMode::kClamp);
827 } else if (!requiredInput.isEmpty()) {
828 // Otherwise snapSpecialScaled() failed or the transform was complex, so snap the source
829 // image at its original resolution and then apply srcToLayer to map to the effective
830 // layer coordinate space.
831 source = {src->snapSpecial(SkIRect(availSrc)), availSrc.topLeft()};
832 // We adjust the desired output of the applyCrop() because ctx was original set to
833 // fulfill 'requiredInput', which is valid *after* we apply srcToLayer. Use the original
834 // 'srcSubset' for the desired output so that the kClamp applied to the available subset
835 // is not discarded as a no-op.
836 source = source.applyCrop(ctx.withNewDesiredOutput(srcSubset),
837 source.layerBounds(),
839 .applyTransform(ctx, srcToLayer, SkFilterMode::kLinear);
840 }
841 } // else leave 'source' as the empty image
842
843 // Evaluate the image filter, with a context pointing to the source snapped from 'src' and
844 // possibly transformed into the intermediate layer coordinate space.
845 ctx = ctx.withNewDesiredOutput(mapping.deviceToLayer(outputBounds))
846 .withNewSource(source);
847
848 // Here, we allow a single-element FilterSpan with a null entry, to simplify the loop:
849 sk_sp<SkImageFilter> nullFilter;
850 FilterSpan filtersOrNull = filters.empty() ? FilterSpan{&nullFilter, 1} : filters;
851
852 for (const sk_sp<SkImageFilter>& filter : filtersOrNull) {
853 auto result = filter ? as_IFB(filter)->filterImage(ctx) : source;
854
855 if (srcIsCoverageLayer) {
856 SkASSERT(dst->useDrawCoverageMaskForMaskFilters());
857 // TODO: Can FilterResult optimize this in any meaningful way if it still has to go
858 // through drawCoverageMask that requires an image (vs a coverage shader)?
859 auto [coverageMask, origin] = result.imageAndOffset(ctx);
860 if (coverageMask) {
861 SkMatrix deviceMatrixWithOffset = mapping.layerToDevice();
862 deviceMatrixWithOffset.preTranslate(origin.x(), origin.y());
863 dst->drawCoverageMask(
864 coverageMask.get(), deviceMatrixWithOffset, result.sampling(), paint);
865 }
866 } else {
868 result.draw(ctx, dst, paint.getBlender());
869 }
870 }
871
872 stats.reportStats();
873}
874
875void SkCanvas::internalSaveLayer(const SaveLayerRec& rec,
876 SaveLayerStrategy strategy,
877 bool coverageOnly) {
878 TRACE_EVENT0("skia", TRACE_FUNC);
879 // Do this before we create the layer. We don't call the public save() since that would invoke a
880 // possibly overridden virtual.
881 this->internalSave();
882
883 if (this->isClipEmpty()) {
884 // Early out if the layer wouldn't draw anything
885 return;
886 }
887
888 // Build up the paint for restoring the layer, taking only the pieces of rec.fPaint that are
889 // relevant. Filtering is automatically chosen in internalDrawDeviceWithFilter based on the
890 // device's coordinate space.
891 SkPaint restorePaint(rec.fPaint ? *rec.fPaint : SkPaint());
892 restorePaint.setStyle(SkPaint::kFill_Style); // a layer is filled out "infinitely"
893 restorePaint.setPathEffect(nullptr); // path effects are ignored for saved layers
894 restorePaint.setMaskFilter(nullptr); // mask filters are ignored for saved layers
895 restorePaint.setImageFilter(nullptr); // the image filter is held separately
896 // Smooth non-axis-aligned layer edges; this automatically downgrades to non-AA for aligned
897 // layer restores. This is done to match legacy behavior where the post-applied MatrixTransform
898 // bilerp also smoothed cropped edges. See skbug.com/11252
899 restorePaint.setAntiAlias(true);
900
901 sk_sp<SkImageFilter> paintFilter = rec.fPaint ? rec.fPaint->refImageFilter() : nullptr;
902 FilterSpan filters = paintFilter ? FilterSpan{&paintFilter, 1} : rec.fFilters;
903 if (filters.size() > kMaxFiltersPerLayer) {
904 filters = filters.first(kMaxFiltersPerLayer);
905 }
906 const SkColorFilter* cf = restorePaint.getColorFilter();
907 const SkBlender* blender = restorePaint.getBlender();
908
909 // When this is false, restoring the layer filled with unmodified prior contents should be
910 // identical to the prior contents, so we can restrict the layer even more than just the
911 // clip bounds.
912 bool filtersPriorDevice = rec.fBackdrop;
913#if !defined(SK_LEGACY_INITWITHPREV_LAYER_SIZING)
914 // A regular filter applied to a layer initialized with prior contents is somewhat
915 // analogous to a backdrop filter so they are treated the same.
916 // TODO(b/314968012): Chrome needs to be updated to clip saveAlphaLayer bounds explicitly when
917 // it uses kInitWithPrevious and LCD text.
918 filtersPriorDevice |= ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) &&
919 (!filters.empty() || cf || blender || restorePaint.getAlphaf() < 1.f));
920#endif
921 // If the restorePaint has a transparency-affecting colorfilter or blender, the output is
922 // unbounded during restore(). `internalDrawDeviceWithFilter` automatically applies these
923 // effects. When there's no image filter, SkDevice::drawDevice is used, which does
924 // not apply effects beyond the layer's image so we mark `trivialRestore` as false too.
925 // TODO: drawDevice() could be updated to apply transparency-affecting effects to a content-
926 // clipped image, but this is the simplest solution when considering document-based SkDevices.
927 const bool drawDeviceMustFillClip = filters.empty() &&
928 ((cf && as_CFB(cf)->affectsTransparentBlack()) ||
929 (blender && as_BB(blender)->affectsTransparentBlack()));
930 const bool trivialRestore = !filtersPriorDevice && !drawDeviceMustFillClip;
931
932 // Size the new layer relative to the prior device, which may already be aligned for filters.
933 SkDevice* priorDevice = this->topDevice();
934 skif::Mapping newLayerMapping;
935 skif::LayerSpace<SkIRect> layerBounds;
936 skif::DeviceSpace<SkIRect> outputBounds{priorDevice->devClipBounds()};
937
938 std::optional<skif::ParameterSpace<SkRect>> contentBounds;
939 // Set the bounds hint if provided and there's no further effects on prior device content
940 if (rec.fBounds && trivialRestore) {
941 contentBounds = skif::ParameterSpace<SkRect>(*rec.fBounds);
942 }
943
944 auto mappingAndBounds = get_layer_mapping_and_bounds(
945 filters, priorDevice->localToDevice(), outputBounds, contentBounds);
946
947 auto abortLayer = [this]() {
948 // The filtered content would not draw anything, or the new device space has an invalid
949 // coordinate system, in which case we mark the current top device as empty so that nothing
950 // draws until the canvas is restored past this saveLayer.
951 AutoUpdateQRBounds aqr(this);
952 this->topDevice()->clipRect(SkRect::MakeEmpty(), SkClipOp::kIntersect, /* aa */ false);
953 };
954
955 if (!mappingAndBounds) {
956 abortLayer();
957 return;
958 }
959
960 std::tie(newLayerMapping, layerBounds) = *mappingAndBounds;
961
962 if (layerBounds.isEmpty()) {
963 // The image filter graph does not require any input, so we don't need to actually render
964 // a new layer for the source image. This could be because the image filter itself will not
965 // produce output, or that the filter DAG has no references to the dynamic source image.
966 // In this case it still has an output that we need to render, but do so now since there is
967 // no new layer pushed on the stack and the paired restore() will be a no-op.
968 if (!filters.empty() && !priorDevice->isNoPixelsDevice()) {
969 SkColorInfo filterColorInfo = priorDevice->imageInfo().colorInfo();
970 if (rec.fColorSpace) {
971 filterColorInfo = filterColorInfo.makeColorSpace(sk_ref_sp(rec.fColorSpace));
972 }
973 this->internalDrawDeviceWithFilter(/*src=*/nullptr, priorDevice, filters, restorePaint,
974 DeviceCompatibleWithFilter::kUnknown,
975 filterColorInfo);
976 }
977
978 // Regardless of if we drew the "restored" image filter or not, mark the layer as empty
979 // until the restore() since we don't care about any of its content.
980 abortLayer();
981 return;
982 } else {
983 // TODO(b/329700315): Once dithers can be anchored more flexibly, we can return to
984 // universally adding padding even for layers w/o filters. This change would simplify layer
985 // prep and restore logic and allow us to flexibly switch the sampling to linear if NN has
986 // issues on certain hardware.
987 if (!filters.empty()) {
988 // Add a buffer of padding so that image filtering can avoid accessing unitialized data
989 // and switch from shader-decal'ing to clamping.
990 layerBounds.outset(skif::LayerSpace<SkISize>({1, 1}));
991 }
992 }
993
994 sk_sp<SkDevice> newDevice;
995 if (strategy == kFullLayer_SaveLayerStrategy) {
996 SkASSERT(!layerBounds.isEmpty());
997
998 SkColorType layerColorType;
999 if (coverageOnly) {
1000 layerColorType = kAlpha_8_SkColorType;
1001 } else {
1002 layerColorType = SkToBool(rec.fSaveLayerFlags & kF16ColorType)
1004 : image_filter_color_type(priorDevice->imageInfo().colorInfo());
1005 }
1007 SkImageInfo::Make(layerBounds.width(),
1008 layerBounds.height(),
1009 layerColorType,
1011 rec.fColorSpace ? sk_ref_sp(rec.fColorSpace)
1012 : priorDevice->imageInfo().refColorSpace());
1013
1014 SkPixelGeometry geo = rec.fSaveLayerFlags & kPreserveLCDText_SaveLayerFlag
1015 ? fProps.pixelGeometry()
1017 const auto createInfo = SkDevice::CreateInfo(info, geo, fAllocator.get());
1018 // Use the original paint as a hint so that it includes the image filter
1019 newDevice = priorDevice->createDevice(createInfo, rec.fPaint);
1020 }
1021
1022 bool initBackdrop = (rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop;
1023 if (!newDevice) {
1024 // Either we weren't meant to allocate a full layer, or the full layer creation failed.
1025 // Using an explicit NoPixelsDevice lets us reflect what the layer state would have been
1026 // on success (or kFull_LayerStrategy) while squashing draw calls that target something that
1027 // doesn't exist.
1028 newDevice = sk_make_sp<SkNoPixelsDevice>(SkIRect::MakeWH(layerBounds.width(),
1029 layerBounds.height()),
1030 fProps, this->imageInfo().refColorSpace());
1031 initBackdrop = false;
1032 }
1033
1034 // Clip while the device coordinate space is the identity so it's easy to define the rect that
1035 // excludes the added padding pixels. This ensures they remain cleared to transparent black.
1036 if (!filters.empty()) {
1037 newDevice->clipRect(SkRect::Make(newDevice->devClipBounds().makeInset(1, 1)),
1038 SkClipOp::kIntersect, /*aa=*/false);
1039 }
1040
1041 // Configure device to match determined mapping for any image filters.
1042 // The setDeviceCoordinateSystem applies the prior device's global transform since
1043 // 'newLayerMapping' only defines the transforms between the two devices and it must be updated
1044 // to the global coordinate system.
1045 newDevice->setDeviceCoordinateSystem(
1046 priorDevice->deviceToGlobal() * SkM44(newLayerMapping.layerToDevice()),
1047 SkM44(newLayerMapping.deviceToLayer()) * priorDevice->globalToDevice(),
1048 SkM44(newLayerMapping.layerMatrix()),
1049 layerBounds.left(),
1050 layerBounds.top());
1051
1052 if (initBackdrop) {
1053 SkASSERT(!coverageOnly);
1054 SkPaint backdropPaint;
1055 FilterToSpan backdropAsSpan(rec.fBackdrop);
1056 // The new device was constructed to be compatible with 'filter', not necessarily
1057 // 'rec.fBackdrop', so allow DrawDeviceWithFilter to transform the prior device contents
1058 // if necessary to evaluate the backdrop filter. If no filters are involved, then the
1059 // devices differ by integer translations and are always compatible.
1060 bool scaleBackdrop = rec.fExperimentalBackdropScale != 1.0f;
1061 auto compat = (!filters.empty() || rec.fBackdrop || scaleBackdrop)
1062 ? DeviceCompatibleWithFilter::kUnknown : DeviceCompatibleWithFilter::kYes;
1063 // Using the color info of 'newDevice' is equivalent to using 'rec.fColorSpace'.
1064 this->internalDrawDeviceWithFilter(priorDevice, // src
1065 newDevice.get(), // dst
1066 backdropAsSpan,
1067 backdropPaint,
1068 compat,
1069 newDevice->imageInfo().colorInfo(),
1070 rec.fExperimentalBackdropScale);
1071 }
1072
1073 fMCRec->newLayer(std::move(newDevice), filters, restorePaint, coverageOnly);
1074 fQuickRejectBounds = this->computeDeviceClipBounds();
1075}
1076
1077int SkCanvas::saveLayerAlphaf(const SkRect* bounds, float alpha) {
1078 if (alpha >= 1.0f) {
1079 return this->saveLayer(bounds, nullptr);
1080 } else {
1081 SkPaint tmpPaint;
1082 tmpPaint.setAlphaf(alpha);
1083 return this->saveLayer(bounds, &tmpPaint);
1084 }
1085}
1086
1087void SkCanvas::internalSaveBehind(const SkRect* localBounds) {
1088 SkDevice* device = this->topDevice();
1089
1090 // Map the local bounds into the top device's coordinate space (this is not
1091 // necessarily the full global CTM transform).
1092 SkIRect devBounds;
1093 if (localBounds) {
1094 SkRect tmp;
1095 device->localToDevice().mapRect(&tmp, *localBounds);
1096 if (!devBounds.intersect(tmp.round(), device->devClipBounds())) {
1097 devBounds.setEmpty();
1098 }
1099 } else {
1100 devBounds = device->devClipBounds();
1101 }
1102 if (devBounds.isEmpty()) {
1103 return;
1104 }
1105
1106 // This is getting the special image from the current device, which is then drawn into (both by
1107 // a client, and the drawClippedToSaveBehind below). Since this is not saving a layer, with its
1108 // own device, we need to explicitly copy the back image contents so that its original content
1109 // is available when we splat it back later during restore.
1110 auto backImage = device->snapSpecial(devBounds, /* forceCopy= */ true);
1111 if (!backImage) {
1112 return;
1113 }
1114
1115 // we really need the save, so we can wack the fMCRec
1116 this->checkForDeferredSave();
1117
1118 fMCRec->fBackImage =
1119 std::make_unique<BackImage>(BackImage{std::move(backImage), devBounds.topLeft()});
1120
1121 SkPaint paint;
1122 paint.setBlendMode(SkBlendMode::kClear);
1123 this->drawClippedToSaveBehind(paint);
1124}
1125
1126void SkCanvas::internalRestore() {
1127 SkASSERT(!fMCStack.empty());
1128
1129 // now detach these from fMCRec so we can pop(). Gets freed after its drawn
1130 std::unique_ptr<Layer> layer = std::move(fMCRec->fLayer);
1131 std::unique_ptr<BackImage> backImage = std::move(fMCRec->fBackImage);
1132
1133 // now do the normal restore()
1134 fMCRec->~MCRec(); // balanced in save()
1135 fMCStack.pop_back();
1136 fMCRec = (MCRec*) fMCStack.back();
1137
1138 if (!fMCRec) {
1139 // This was the last record, restored during the destruction of the SkCanvas
1140 return;
1141 }
1142
1143 this->topDevice()->popClipStack();
1144 this->topDevice()->setGlobalCTM(fMCRec->fMatrix);
1145
1146 if (backImage) {
1147 SkPaint paint;
1148 paint.setBlendMode(SkBlendMode::kDstOver);
1149 this->topDevice()->drawSpecial(backImage->fImage.get(),
1150 SkMatrix::Translate(backImage->fLoc),
1152 paint);
1153 }
1154
1155 // Draw the layer's device contents into the now-current older device. We can't call public
1156 // draw functions since we don't want to record them.
1157 if (layer && !layer->fDevice->isNoPixelsDevice() && !layer->fDiscard) {
1158 layer->fDevice->setImmutable();
1159
1160 // Don't go through AutoLayerForImageFilter since device draws are so closely tied to
1161 // internalSaveLayer and internalRestore.
1162 if (this->predrawNotify()) {
1163 SkDevice* dstDev = this->topDevice();
1164 if (!layer->fImageFilters.empty()) {
1165 this->internalDrawDeviceWithFilter(layer->fDevice.get(), // src
1166 dstDev, // dst
1167 layer->fImageFilters,
1168 layer->fPaint,
1169 DeviceCompatibleWithFilter::kYes,
1170 layer->fDevice->imageInfo().colorInfo(),
1171 /*scaleFactor=*/1.0f,
1172 layer->fIsCoverage);
1173 } else {
1174 // NOTE: We don't just call internalDrawDeviceWithFilter with a null filter
1175 // because we want to take advantage of overridden drawDevice functions for
1176 // document-based devices.
1177 SkASSERT(!layer->fIsCoverage);
1179 dstDev->drawDevice(layer->fDevice.get(), sampling, layer->fPaint);
1180 }
1181 }
1182 }
1183
1184 // Reset the clip restriction if the restore went past the save point that had added it.
1185 if (this->getSaveCount() < fClipRestrictionSaveCount) {
1186 fClipRestrictionRect.setEmpty();
1187 fClipRestrictionSaveCount = -1;
1188 }
1189 // Update the quick-reject bounds in case the restore changed the top device or the
1190 // removed save record had included modifications to the clip stack.
1191 fQuickRejectBounds = this->computeDeviceClipBounds();
1192 this->validateClip();
1193}
1194
1196 if (nullptr == props) {
1197 props = &fProps;
1198 }
1199 return this->onNewSurface(info, *props);
1200}
1201
1203 return this->rootDevice()->makeSurface(info, props);
1204}
1205
1207 return this->onImageInfo();
1208}
1209
1211 return this->rootDevice()->imageInfo();
1212}
1213
1215 return this->onGetProps(props, /*top=*/false);
1216}
1217
1219 SkSurfaceProps props;
1220 this->onGetProps(&props, /*top=*/false);
1221 return props;
1222}
1223
1225 SkSurfaceProps props;
1226 this->onGetProps(&props, /*top=*/true);
1227 return props;
1228}
1229
1230bool SkCanvas::onGetProps(SkSurfaceProps* props, bool top) const {
1231 if (props) {
1232 *props = top ? topDevice()->surfaceProps() : fProps;
1233 }
1234 return true;
1235}
1236
1238 return this->onPeekPixels(pmap);
1239}
1240
1242 return this->rootDevice()->peekPixels(pmap);
1243}
1244
1245void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1246 SkPixmap pmap;
1247 if (!this->onAccessTopLayerPixels(&pmap)) {
1248 return nullptr;
1249 }
1250 if (info) {
1251 *info = pmap.info();
1252 }
1253 if (rowBytes) {
1254 *rowBytes = pmap.rowBytes();
1255 }
1256 if (origin) {
1257 // If the caller requested the origin, they presumably are expecting the returned pixels to
1258 // be axis-aligned with the root canvas. If the top level device isn't axis aligned, that's
1259 // not the case. Until we update accessTopLayerPixels() to accept a coord space matrix
1260 // instead of an origin, just don't expose the pixels in that case. Note that this means
1261 // that layers with complex coordinate spaces can still report their pixels if the caller
1262 // does not ask for the origin (e.g. just to dump its output to a file, etc).
1263 if (this->topDevice()->isPixelAlignedToGlobal()) {
1264 *origin = this->topDevice()->getOrigin();
1265 } else {
1266 return nullptr;
1267 }
1268 }
1269 return pmap.writable_addr();
1270}
1271
1273 return this->topDevice()->accessPixels(pmap);
1274}
1275
1276/////////////////////////////////////////////////////////////////////////////
1277
1279 if (dx || dy) {
1280 this->checkForDeferredSave();
1281 fMCRec->fMatrix.preTranslate(dx, dy);
1282
1283 this->topDevice()->setGlobalCTM(fMCRec->fMatrix);
1284
1285 this->didTranslate(dx,dy);
1286 }
1287}
1288
1290 if (sx != 1 || sy != 1) {
1291 this->checkForDeferredSave();
1292 fMCRec->fMatrix.preScale(sx, sy);
1293
1294 this->topDevice()->setGlobalCTM(fMCRec->fMatrix);
1295
1296 this->didScale(sx, sy);
1297 }
1298}
1299
1301 SkMatrix m;
1302 m.setRotate(degrees);
1303 this->concat(m);
1304}
1305
1307 SkMatrix m;
1308 m.setRotate(degrees, px, py);
1309 this->concat(m);
1310}
1311
1313 SkMatrix m;
1314 m.setSkew(sx, sy);
1315 this->concat(m);
1316}
1317
1319 if (matrix.isIdentity()) {
1320 return;
1321 }
1322 this->concat(SkM44(matrix));
1323}
1324
1325void SkCanvas::internalConcat44(const SkM44& m) {
1326 this->checkForDeferredSave();
1327
1328 fMCRec->fMatrix.preConcat(m);
1329
1330 this->topDevice()->setGlobalCTM(fMCRec->fMatrix);
1331}
1332
1334 this->internalConcat44(m);
1335 // notify subclasses
1336 this->didConcat44(m);
1337}
1338
1339void SkCanvas::internalSetMatrix(const SkM44& m) {
1340 fMCRec->fMatrix = m;
1341
1342 this->topDevice()->setGlobalCTM(fMCRec->fMatrix);
1343}
1344
1346 this->setMatrix(SkM44(matrix));
1347}
1348
1350 this->checkForDeferredSave();
1351 this->internalSetMatrix(m);
1352 this->didSetM44(m);
1353}
1354
1356 this->setMatrix(SkM44());
1357}
1358
1359//////////////////////////////////////////////////////////////////////////////
1360
1361void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
1362 if (!rect.isFinite()) {
1363 return;
1364 }
1365 this->checkForDeferredSave();
1367 this->onClipRect(rect.makeSorted(), op, edgeStyle);
1368}
1369
1371 SkASSERT(rect.isSorted());
1372 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1373
1374 AutoUpdateQRBounds aqr(this);
1375 this->topDevice()->clipRect(rect, op, isAA);
1376}
1377
1379 // The device clip restriction is a surface-space rectangular intersection that cannot be
1380 // drawn outside of. The rectangle is remembered so that subsequent resetClip calls still
1381 // respect the restriction. Other than clip resetting, all clip operations restrict the set
1382 // of renderable pixels, so once set, the restriction will be respected until the canvas
1383 // save stack is restored past the point this function was invoked. Unfortunately, the current
1384 // implementation relies on the clip stack of the underyling SkDevices, which leads to some
1385 // awkward behavioral interactions (see skbug.com/12252).
1386 //
1387 // Namely, a canvas restore() could undo the clip restriction's rect, and if
1388 // setDeviceClipRestriction were called at a nested save level, there's no way to undo just the
1389 // prior restriction and re-apply the new one. It also only makes sense to apply to the base
1390 // device; any other device for a saved layer will be clipped back to the base device during its
1391 // matched restore. As such, we:
1392 // - Remember the save count that added the clip restriction and reset the rect to empty when
1393 // we've restored past that point to keep our state in sync with the device's clip stack.
1394 // - We assert that we're on the base device when this is invoked.
1395 // - We assert that setDeviceClipRestriction() is only called when there was no prior
1396 // restriction (cannot re-restrict, and prior state must have been reset by restoring the
1397 // canvas state).
1398 // - Historically, the empty rect would reset the clip restriction but it only could do so
1399 // partially since the device's clips wasn't adjusted. Resetting is now handled
1400 // automatically via SkCanvas::restore(), so empty input rects are skipped.
1401 SkASSERT(this->topDevice() == this->rootDevice()); // shouldn't be in a nested layer
1402 // and shouldn't already have a restriction
1403 SkASSERT(fClipRestrictionSaveCount < 0 && fClipRestrictionRect.isEmpty());
1404
1405 if (fClipRestrictionSaveCount < 0 && !rect.isEmpty()) {
1406 fClipRestrictionRect = rect;
1407 fClipRestrictionSaveCount = this->getSaveCount();
1408
1409 // A non-empty clip restriction immediately applies an intersection op (ignoring the ctm).
1410 // so we have to resolve the save.
1411 this->checkForDeferredSave();
1412 AutoUpdateQRBounds aqr(this);
1413 // Use clipRegion() since that operates in canvas-space, whereas clipRect() would apply the
1414 // device's current transform first.
1415 this->topDevice()->clipRegion(SkRegion(rect), SkClipOp::kIntersect);
1416 }
1417}
1418
1419void SkCanvas::internal_private_resetClip() {
1420 this->checkForDeferredSave();
1421 this->onResetClip();
1422}
1423
1425 SkIRect deviceRestriction = this->topDevice()->imageInfo().bounds();
1426 if (fClipRestrictionSaveCount >= 0 && this->topDevice() == this->rootDevice()) {
1427 // Respect the device clip restriction when resetting the clip if we're on the base device.
1428 // If we're not on the base device, then the "reset" applies to the top device's clip stack,
1429 // and the clip restriction will be respected automatically during a restore of the layer.
1430 if (!deviceRestriction.intersect(fClipRestrictionRect)) {
1431 deviceRestriction = SkIRect::MakeEmpty();
1432 }
1433 }
1434
1435 AutoUpdateQRBounds aqr(this);
1436 this->topDevice()->replaceClip(deviceRestriction);
1437}
1438
1439void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
1440 this->checkForDeferredSave();
1442 if (rrect.isRect()) {
1443 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1444 } else {
1445 this->onClipRRect(rrect, op, edgeStyle);
1446 }
1447}
1448
1450 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1451
1452 AutoUpdateQRBounds aqr(this);
1453 this->topDevice()->clipRRect(rrect, op, isAA);
1454}
1455
1456void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
1457 this->checkForDeferredSave();
1459
1460 if (!path.isInverseFillType() && fMCRec->fMatrix.asM33().rectStaysRect()) {
1461 SkRect r;
1462 if (path.isRect(&r)) {
1463 this->onClipRect(r, op, edgeStyle);
1464 return;
1465 }
1466 SkRRect rrect;
1467 if (path.isOval(&r)) {
1468 rrect.setOval(r);
1469 this->onClipRRect(rrect, op, edgeStyle);
1470 return;
1471 }
1472 if (path.isRRect(&rrect)) {
1473 this->onClipRRect(rrect, op, edgeStyle);
1474 return;
1475 }
1476 }
1477
1478 this->onClipPath(path, op, edgeStyle);
1479}
1480
1482 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1483
1484 AutoUpdateQRBounds aqr(this);
1485 this->topDevice()->clipPath(path, op, isAA);
1486}
1487
1489 if (sh) {
1490 if (sh->isOpaque()) {
1491 if (op == SkClipOp::kIntersect) {
1492 // we don't occlude anything, so skip this call
1493 } else {
1495 // we occlude everything, so set the clip to empty
1496 this->clipRect({0,0,0,0});
1497 }
1498 } else {
1499 this->checkForDeferredSave();
1500 this->onClipShader(std::move(sh), op);
1501 }
1502 }
1503}
1504
1506 AutoUpdateQRBounds aqr(this);
1507 this->topDevice()->clipShader(sh, op);
1508}
1509
1511 this->checkForDeferredSave();
1512 this->onClipRegion(rgn, op);
1513}
1514
1516 AutoUpdateQRBounds aqr(this);
1517 this->topDevice()->clipRegion(rgn, op);
1518}
1519
1520void SkCanvas::validateClip() const {
1521#ifdef SK_DEBUG
1522 SkRect tmp = this->computeDeviceClipBounds();
1523 if (this->isClipEmpty()) {
1524 SkASSERT(fQuickRejectBounds.isEmpty());
1525 } else {
1526 SkASSERT(tmp == fQuickRejectBounds);
1527 }
1528#endif
1529}
1530
1531bool SkCanvas::androidFramework_isClipAA() const {
1532 return this->topDevice()->isClipAntiAliased();
1533}
1534
1536 rgn->setEmpty();
1537 SkDevice* device = this->topDevice();
1538 if (device && device->isPixelAlignedToGlobal()) {
1539 device->android_utils_clipAsRgn(rgn);
1540 SkIPoint origin = device->getOrigin();
1541 if (origin.x() | origin.y()) {
1542 rgn->translate(origin.x(), origin.y());
1543 }
1544 }
1545}
1546
1547///////////////////////////////////////////////////////////////////////////////
1548
1550 return this->topDevice()->isClipEmpty();
1551}
1552
1554 return this->topDevice()->isClipRect();
1555}
1556
1558#ifdef SK_DEBUG
1559 // Verify that fQuickRejectBounds are set properly.
1560 this->validateClip();
1561#endif
1562
1563 SkRect devRect = SkMatrixPriv::MapRect(fMCRec->fMatrix, src);
1564 return !devRect.isFinite() || !devRect.intersects(fQuickRejectBounds);
1565}
1566
1568 return path.isEmpty() || this->quickReject(path.getBounds());
1569}
1570
1571bool SkCanvas::internalQuickReject(const SkRect& bounds, const SkPaint& paint,
1572 const SkMatrix* matrix) {
1573 if (!bounds.isFinite() || paint.nothingToDraw()) {
1574 return true;
1575 }
1576
1577 if (paint.canComputeFastBounds()) {
1578 SkRect tmp = matrix ? matrix->mapRect(bounds) : bounds;
1579 return this->quickReject(paint.computeFastBounds(tmp, &tmp));
1580 }
1581
1582 return false;
1583}
1584
1585
1587 SkIRect ibounds = this->getDeviceClipBounds();
1588 if (ibounds.isEmpty()) {
1589 return SkRect::MakeEmpty();
1590 }
1591
1592 SkMatrix inverse;
1593 // if we can't invert the CTM, we can't return local clip bounds
1594 if (!fMCRec->fMatrix.asM33().invert(&inverse)) {
1595 return SkRect::MakeEmpty();
1596 }
1597
1598 SkRect bounds;
1599 // adjust it outwards in case we are antialiasing
1600 const int margin = 1;
1601
1602 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
1603 inverse.mapRect(&bounds, r);
1604 return bounds;
1605}
1606
1608 return this->computeDeviceClipBounds(/*outsetForAA=*/false).roundOut();
1609}
1610
1611SkRect SkCanvas::computeDeviceClipBounds(bool outsetForAA) const {
1612 const SkDevice* dev = this->topDevice();
1613 if (dev->isClipEmpty()) {
1614 return SkRect::MakeEmpty();
1615 } else {
1616 SkRect devClipBounds =
1618 if (outsetForAA) {
1619 // Expand bounds out by 1 in case we are anti-aliasing. We store the
1620 // bounds as floats to enable a faster quick reject implementation.
1621 devClipBounds.outset(1.f, 1.f);
1622 }
1623 return devClipBounds;
1624 }
1625}
1626
1627///////////////////////////////////////////////////////////////////////
1628
1630 return fMCRec->fMatrix.asM33();
1631}
1632
1634 return fMCRec->fMatrix;
1635}
1636
1638 return this->topDevice()->recordingContext();
1639}
1640
1642 return this->topDevice()->recorder();
1643}
1644
1645void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1646 const SkPaint& paint) {
1647 TRACE_EVENT0("skia", TRACE_FUNC);
1648 if (outer.isEmpty()) {
1649 return;
1650 }
1651 if (inner.isEmpty()) {
1652 this->drawRRect(outer, paint);
1653 return;
1654 }
1655
1656 // We don't have this method (yet), but technically this is what we should
1657 // be able to return ...
1658 // if (!outer.contains(inner))) {
1659 //
1660 // For now at least check for containment of bounds
1661 if (!outer.getBounds().contains(inner.getBounds())) {
1662 return;
1663 }
1664
1665 this->onDrawDRRect(outer, inner, paint);
1666}
1667
1669 TRACE_EVENT0("skia", TRACE_FUNC);
1670 this->onDrawPaint(paint);
1671}
1672
1673void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1674 TRACE_EVENT0("skia", TRACE_FUNC);
1675 // To avoid redundant logic in our culling code and various backends, we always sort rects
1676 // before passing them along.
1677 this->onDrawRect(r.makeSorted(), paint);
1678}
1679
1680void SkCanvas::drawClippedToSaveBehind(const SkPaint& paint) {
1681 TRACE_EVENT0("skia", TRACE_FUNC);
1682 this->onDrawBehind(paint);
1683}
1684
1686 TRACE_EVENT0("skia", TRACE_FUNC);
1687 if (region.isEmpty()) {
1688 return;
1689 }
1690
1691 if (region.isRect()) {
1692 return this->drawIRect(region.getBounds(), paint);
1693 }
1694
1695 this->onDrawRegion(region, paint);
1696}
1697
1698void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1699 TRACE_EVENT0("skia", TRACE_FUNC);
1700 // To avoid redundant logic in our culling code and various backends, we always sort rects
1701 // before passing them along.
1702 this->onDrawOval(r.makeSorted(), paint);
1703}
1704
1706 TRACE_EVENT0("skia", TRACE_FUNC);
1707 this->onDrawRRect(rrect, paint);
1708}
1709
1710void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1711 TRACE_EVENT0("skia", TRACE_FUNC);
1712 this->onDrawPoints(mode, count, pts, paint);
1713}
1714
1716 const SkPaint& paint) {
1717 this->drawVertices(vertices.get(), mode, paint);
1718}
1719
1721 TRACE_EVENT0("skia", TRACE_FUNC);
1722 RETURN_ON_NULL(vertices);
1723
1724 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1726
1727#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
1728 // Preserve legacy behavior for Android: ignore the SkShader if there are no texCoords present
1729 if (paint.getShader() && !vertices->priv().hasTexCoords()) {
1730 SkPaint noShaderPaint(paint);
1731 noShaderPaint.setShader(nullptr);
1732 this->onDrawVerticesObject(vertices, mode, noShaderPaint);
1733 return;
1734 }
1735#endif
1736 this->onDrawVerticesObject(vertices, mode, paint);
1737}
1738
1740 TRACE_EVENT0("skia", TRACE_FUNC);
1741 if (!blender) {
1743 }
1744 this->onDrawMesh(mesh, std::move(blender), paint);
1745}
1746
1748 TRACE_EVENT0("skia", TRACE_FUNC);
1749 this->onDrawPath(path, paint);
1750}
1751
1752// Returns true if the rect can be "filled" : non-empty and finite
1753static bool fillable(const SkRect& r) {
1754 SkScalar w = r.width();
1755 SkScalar h = r.height();
1756 return SkIsFinite(w, h) && w > 0 && h > 0;
1757}
1758
1760 SkPaint cleaned;
1761 if (paint) {
1762 cleaned = *paint;
1763 cleaned.setMaskFilter(nullptr);
1764 cleaned.setAntiAlias(false);
1765 }
1766 return cleaned;
1767}
1768
1770 SkFilterMode filter, const SkPaint* paint) {
1772
1773 const int xdivs[] = {center.fLeft, center.fRight};
1774 const int ydivs[] = {center.fTop, center.fBottom};
1775
1776 Lattice lat;
1777 lat.fXDivs = xdivs;
1778 lat.fYDivs = ydivs;
1779 lat.fRectTypes = nullptr;
1780 lat.fXCount = lat.fYCount = 2;
1781 lat.fBounds = nullptr;
1782 lat.fColors = nullptr;
1783 this->drawImageLattice(image, lat, dst, filter, paint);
1784}
1785
1786void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1787 SkFilterMode filter, const SkPaint* paint) {
1788 TRACE_EVENT0("skia", TRACE_FUNC);
1790 if (dst.isEmpty()) {
1791 return;
1792 }
1793
1795 Lattice latticePlusBounds = lattice;
1796 if (!latticePlusBounds.fBounds) {
1798 latticePlusBounds.fBounds = &bounds;
1799 }
1800
1801 SkPaint latticePaint = clean_paint_for_lattice(paint);
1802 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1803 this->onDrawImageLattice2(image, latticePlusBounds, dst, filter, &latticePaint);
1804 } else {
1805 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst,
1806 SkSamplingOptions(filter), &latticePaint, kStrict_SrcRectConstraint);
1807 }
1808}
1809
1810void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
1811 const SkColor colors[], int count, SkBlendMode mode,
1812 const SkSamplingOptions& sampling, const SkRect* cull,
1813 const SkPaint* paint) {
1814 TRACE_EVENT0("skia", TRACE_FUNC);
1816 if (count <= 0) {
1817 return;
1818 }
1819 SkASSERT(atlas);
1820 SkASSERT(tex);
1821 this->onDrawAtlas2(atlas, xform, tex, colors, count, mode, sampling, cull, paint);
1822}
1823
1824void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
1825 TRACE_EVENT0("skia", TRACE_FUNC);
1826 if (key) {
1827 this->onDrawAnnotation(rect, key, value);
1828 }
1829}
1830
1832 TRACE_EVENT0("skia", TRACE_FUNC);
1833 this->onDrawShadowRec(path, rec);
1834}
1835
1837 // We don't test quickReject because the shadow outsets the path's bounds.
1838 // TODO(michaelludwig): Is it worth calling SkDrawShadowMetrics::GetLocalBounds here?
1839 if (!this->predrawNotify()) {
1840 return;
1841 }
1842 this->topDevice()->drawShadow(path, rec);
1843}
1844
1846 QuadAAFlags aaFlags, const SkColor4f& color,
1847 SkBlendMode mode) {
1848 TRACE_EVENT0("skia", TRACE_FUNC);
1849 // Make sure the rect is sorted before passing it along
1850 this->onDrawEdgeAAQuad(rect.makeSorted(), clip, aaFlags, color, mode);
1851}
1852
1854 const SkPoint dstClips[],
1855 const SkMatrix preViewMatrices[],
1857 const SkPaint* paint,
1858 SrcRectConstraint constraint) {
1859 TRACE_EVENT0("skia", TRACE_FUNC);
1860 // Route single, rectangular quads to drawImageRect() to take advantage of image filter
1861 // optimizations that avoid a layer.
1862 if (paint && paint->getImageFilter() && cnt == 1) {
1863 const auto& entry = imageSet[0];
1864 // If the preViewMatrix is skipped or a positive-scale + translate matrix, we can apply it
1865 // to the entry's dstRect w/o changing output behavior.
1866 const bool canMapDstRect = entry.fMatrixIndex < 0 ||
1867 (preViewMatrices[entry.fMatrixIndex].isScaleTranslate() &&
1868 preViewMatrices[entry.fMatrixIndex].getScaleX() > 0.f &&
1869 preViewMatrices[entry.fMatrixIndex].getScaleY() > 0.f);
1870 if (!entry.fHasClip && canMapDstRect) {
1871 SkRect dst = entry.fDstRect;
1872 if (entry.fMatrixIndex >= 0) {
1873 preViewMatrices[entry.fMatrixIndex].mapRect(&dst);
1874 }
1875 this->drawImageRect(entry.fImage.get(), entry.fSrcRect, dst,
1876 sampling, paint, constraint);
1877 return;
1878 } // Else the entry is doing more than can be represented by drawImageRect
1879 } // Else no filter, or many entries that should be filtered together
1881 constraint);
1882}
1883
1884//////////////////////////////////////////////////////////////////////////////
1885// These are the virtual drawing methods
1886//////////////////////////////////////////////////////////////////////////////
1887
1889 if (fSurfaceBase) {
1891 }
1892}
1893
1895 this->internalDrawPaint(paint);
1896}
1897
1898void SkCanvas::internalDrawPaint(const SkPaint& paint) {
1899 // drawPaint does not call internalQuickReject() because computing its geometry is not free
1900 // (see getLocalClipBounds(), and the two conditions below are sufficient.
1901 if (paint.nothingToDraw() || this->isClipEmpty()) {
1902 return;
1903 }
1904
1905 auto layer = this->aboutToDraw(paint, nullptr, PredrawFlags::kCheckForOverwrite);
1906 if (layer) {
1907 this->topDevice()->drawPaint(layer->paint());
1908 }
1909}
1910
1912 const SkPaint& paint) {
1913 if ((long)count <= 0 || paint.nothingToDraw()) {
1914 return;
1915 }
1916 SkASSERT(pts != nullptr);
1917
1918 SkRect bounds;
1919 // Compute bounds from points (common for drawing a single line)
1920 if (count == 2) {
1921 bounds.set(pts[0], pts[1]);
1922 } else {
1923 bounds.setBounds(pts, SkToInt(count));
1924 }
1925
1926 // Enforce paint style matches implicit behavior of drawPoints
1927 SkPaint strokePaint = paint;
1928 strokePaint.setStyle(SkPaint::kStroke_Style);
1929 if (this->internalQuickReject(bounds, strokePaint)) {
1930 return;
1931 }
1932
1933 auto layer = this->aboutToDraw(strokePaint, &bounds);
1934 if (layer) {
1935 this->topDevice()->drawPoints(mode, count, pts, layer->paint());
1936 }
1937}
1938
1940 if (paint.getPathEffect()) {
1941 return nullptr;
1942 }
1943
1944 // TODO: Once stroke-and-fill goes away, we can check the paint's style directly.
1945 if (SkStrokeRec(paint).getStyle() != SkStrokeRec::kFill_Style) {
1946 return nullptr;
1947 }
1948
1949 const SkMaskFilterBase* maskFilter = as_MFB(paint.getMaskFilter());
1950 if (!maskFilter || maskFilter->type() != SkMaskFilterBase::Type::kBlur) {
1951 return nullptr;
1952 }
1953
1954 const SkBlurMaskFilterImpl* blurMaskFilter =
1955 static_cast<const SkBlurMaskFilterImpl*>(maskFilter);
1956 if (blurMaskFilter->blurStyle() != kNormal_SkBlurStyle) {
1957 return nullptr;
1958 }
1959
1960 return blurMaskFilter;
1961}
1962
1963std::optional<AutoLayerForImageFilter> SkCanvas::attemptBlurredRRectDraw(
1965 SkASSERT(!(flags & PredrawFlags::kSkipMaskFilterAutoLayer));
1966 const SkRect& bounds = rrect.getBounds();
1967
1968 if (!this->topDevice()->useDrawCoverageMaskForMaskFilters()) {
1969 // Regular draw in the legacy mask filter case.
1970 return this->aboutToDraw(paint, &bounds, flags);
1971 }
1972
1973 if (!this->getTotalMatrix().isSimilarity()) {
1974 // TODO: If the CTM does more than just translation, rotation, and uniform scale, then the
1975 // results of analytic blurring will be different than mask filter blurring. Skip the
1976 // specialized path in this case.
1977 return this->aboutToDraw(paint, &bounds, flags);
1978 }
1979
1981 if (!blurMaskFilter) {
1982 // Can't attempt a specialized blurred draw, so do a regular draw.
1983 return this->aboutToDraw(paint, &bounds, flags);
1984 }
1985
1986 auto layer = this->aboutToDraw(paint, &bounds, flags | PredrawFlags::kSkipMaskFilterAutoLayer);
1987 if (!layer) {
1988 // predrawNotify failed.
1989 return std::nullopt;
1990 }
1991
1992 const float deviceSigma = blurMaskFilter->computeXformedSigma(this->getTotalMatrix());
1993 if (this->topDevice()->drawBlurredRRect(rrect, layer->paint(), deviceSigma)) {
1994 // Analytic draw was successful.
1995 return std::nullopt;
1996 }
1997
1998 // Fall back on a regular draw, adding any mask filter layer we skipped earlier. We know the
1999 // paint has a mask filter here, otherwise we would have failed the can_attempt check above.
2000 layer->addMaskFilterLayer(&bounds);
2001 return layer;
2002}
2003
2005 SkASSERT(r.isSorted());
2006 if (this->internalQuickReject(r, paint)) {
2007 return;
2008 }
2009
2010 // Returns a layer if a blurred draw is not applicable or was unsuccessful.
2011 std::optional<AutoLayerForImageFilter> layer = this->attemptBlurredRRectDraw(
2012 SkRRect::MakeRect(r), paint, PredrawFlags::kCheckForOverwrite);
2013
2014 if (layer) {
2015 this->topDevice()->drawRect(r, layer->paint());
2016 }
2017}
2018
2021 if (this->internalQuickReject(bounds, paint)) {
2022 return;
2023 }
2024
2025 auto layer = this->aboutToDraw(paint, &bounds);
2026 if (layer) {
2027 this->topDevice()->drawRegion(region, layer->paint());
2028 }
2029}
2030
2032 SkDevice* dev = this->topDevice();
2033 if (!dev) {
2034 return;
2035 }
2036
2039 for (;;) {
2040 const MCRec* rec = (const MCRec*)iter.prev();
2041 if (!rec) {
2042 return; // no backimages, so nothing to draw
2043 }
2044 if (rec->fBackImage) {
2045 // drawBehind should only have been called when the saveBehind record is active;
2046 // if this fails, it means a real saveLayer was made w/o being restored first.
2047 SkASSERT(dev == rec->fDevice);
2048 bounds = SkIRect::MakeXYWH(rec->fBackImage->fLoc.fX, rec->fBackImage->fLoc.fY,
2049 rec->fBackImage->fImage->width(),
2050 rec->fBackImage->fImage->height());
2051 break;
2052 }
2053 }
2054
2055 // The backimage location (and thus bounds) were defined in the device's space, so mark it
2056 // as a clip. We use a clip instead of just drawing a rect in case the paint has an image
2057 // filter on it (which is applied before any auto-layer so the filter is clipped).
2058 dev->pushClipStack();
2059 {
2060 // We also have to temporarily whack the device matrix since clipRegion is affected by the
2061 // global-to-device matrix and clipRect is affected by the local-to-device.
2063 dev->clipRect(SkRect::Make(bounds), SkClipOp::kIntersect, /* aa */ false);
2064 // ~adtr will reset the local-to-device matrix so that drawPaint() shades correctly.
2065 }
2066
2067 auto layer = this->aboutToDraw(paint);
2068 if (layer) {
2069 this->topDevice()->drawPaint(layer->paint());
2070 }
2071
2072 dev->popClipStack();
2073}
2074
2077 if (this->internalQuickReject(oval, paint)) {
2078 return;
2079 }
2080
2081 // Returns a layer if a blurred draw is not applicable or was unsuccessful.
2082 std::optional<AutoLayerForImageFilter> layer =
2083 this->attemptBlurredRRectDraw(SkRRect::MakeOval(oval), paint, PredrawFlags::kNone);
2084
2085 if (layer) {
2086 this->topDevice()->drawOval(oval, layer->paint());
2087 }
2088}
2089
2091 SkScalar sweepAngle, bool useCenter,
2092 const SkPaint& paint) {
2094 if (this->internalQuickReject(oval, paint)) {
2095 return;
2096 }
2097
2098 auto layer = this->aboutToDraw(paint, &oval);
2099 if (layer) {
2100 this->topDevice()->drawArc(SkArc::Make(oval, startAngle, sweepAngle, useCenter),
2101 layer->paint());
2102 }
2103}
2104
2106 const SkRect& bounds = rrect.getBounds();
2107
2108 // Delegating to simpler draw operations
2109 if (rrect.isRect()) {
2110 // call the non-virtual version
2111 this->SkCanvas::drawRect(bounds, paint);
2112 return;
2113 } else if (rrect.isOval()) {
2114 // call the non-virtual version
2115 this->SkCanvas::drawOval(bounds, paint);
2116 return;
2117 }
2118
2119 if (this->internalQuickReject(bounds, paint)) {
2120 return;
2121 }
2122
2123 // Returns a layer if a blurred draw is not applicable or was unsuccessful.
2124 std::optional<AutoLayerForImageFilter> layer =
2125 this->attemptBlurredRRectDraw(rrect, paint, PredrawFlags::kNone);
2126
2127 if (layer) {
2128 this->topDevice()->drawRRect(rrect, layer->paint());
2129 }
2130}
2131
2132void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
2133 const SkRect& bounds = outer.getBounds();
2134 if (this->internalQuickReject(bounds, paint)) {
2135 return;
2136 }
2137
2138 auto layer = this->aboutToDraw(paint, &bounds);
2139 if (layer) {
2140 this->topDevice()->drawDRRect(outer, inner, layer->paint());
2141 }
2142}
2143
2145 if (!path.isFinite()) {
2146 return;
2147 }
2148
2149 const SkRect& pathBounds = path.getBounds();
2150 if (!path.isInverseFillType() && this->internalQuickReject(pathBounds, paint)) {
2151 return;
2152 }
2153 if (path.isInverseFillType() && pathBounds.width() <= 0 && pathBounds.height() <= 0) {
2154 this->internalDrawPaint(paint);
2155 return;
2156 }
2157
2158 auto layer = this->aboutToDraw(paint, path.isInverseFillType() ? nullptr : &pathBounds);
2159 if (layer) {
2160 this->topDevice()->drawPath(path, layer->paint());
2161 }
2162}
2163
2164// Clean-up the paint to match the drawing semantics for drawImage et al. (skbug.com/7804).
2166 SkPaint cleaned;
2167 if (paint) {
2168 cleaned = *paint;
2170 cleaned.setPathEffect(nullptr);
2171 }
2172 return cleaned;
2173}
2174
2175// drawVertices fills triangles and ignores mask filter and path effect,
2176// so canonicalize the paint before checking quick reject.
2178 paint.setStyle(SkPaint::kFill_Style);
2179 paint.setMaskFilter(nullptr);
2180 paint.setPathEffect(nullptr);
2181 return paint;
2182}
2183
2184// TODO: Delete this since it is no longer used
2186 const SkSamplingOptions& sampling, const SkPaint* paint) {
2188}
2189
2192 SkCanvas::SrcRectConstraint constraint) {
2193 if (constraint == SkCanvas::kStrict_SrcRectConstraint) {
2196 }
2197 if (sampling.isAniso()) {
2199 }
2200 }
2201 return sampling;
2202}
2203
2205 const SkSamplingOptions& sampling, const SkPaint* paint,
2206 SrcRectConstraint constraint) {
2208 SkSamplingOptions realSampling = clean_sampling_for_constraint(sampling, constraint);
2209
2210 if (this->internalQuickReject(dst, realPaint)) {
2211 return;
2212 }
2213
2214 if (this->topDevice()->shouldDrawAsTiledImageRect()) {
2215 if (this->topDevice()->drawAsTiledImageRect(
2216 this, image, &src, dst, realSampling, realPaint, constraint)) {
2217 return;
2218 }
2219 }
2220
2221 // drawImageRect()'s behavior is modified by the presence of an image filter, a mask filter, a
2222 // color filter, the paint's alpha, the paint's blender, and--when it's an alpha-only image--
2223 // the paint's color or shader. When there's an image filter, the paint's blender is applied to
2224 // the result of the image filter function, but every other aspect would influence the source
2225 // image that's then rendered with src-over blending into a transparent temporary layer.
2226 //
2227 // However, skif::FilterResult can apply the paint alpha and any color filter often without
2228 // requiring a layer, and src-over blending onto a transparent dst is a no-op, so we can use the
2229 // input image directly as the source for filtering. When the image is alpha-only and must be
2230 // colorized, or when a mask filter would change the coverage we skip this optimization for
2231 // simplicity since *somehow* embedding colorization or mask blurring into the filter graph
2232 // would likely be equivalent to using the existing AutoLayerForImageFilter functionality.
2233 if (realPaint.getImageFilter() && !image->isAlphaOnly() && !realPaint.getMaskFilter()) {
2234 SkDevice* device = this->topDevice();
2235
2236 skif::ParameterSpace<SkRect> imageBounds{dst};
2237 skif::DeviceSpace<SkIRect> outputBounds{device->devClipBounds()};
2238 FilterToSpan filterAsSpan(realPaint.getImageFilter());
2239 auto mappingAndBounds = get_layer_mapping_and_bounds(filterAsSpan,
2240 device->localToDevice(),
2241 outputBounds,
2242 imageBounds);
2243 if (!mappingAndBounds) {
2244 return;
2245 }
2246 if (!this->predrawNotify()) {
2247 return;
2248 }
2249
2250 // Start out with an empty source image, to be replaced with the converted 'image', and a
2251 // desired output equal to the calculated initial source layer bounds, which accounts for
2252 // how the image filters will access 'image' (possibly different than just 'outputBounds').
2253 auto backend = device->createImageFilteringBackend(
2254 device->surfaceProps(),
2255 image_filter_color_type(device->imageInfo().colorInfo()));
2256 auto [mapping, srcBounds] = *mappingAndBounds;
2258 skif::Context ctx{std::move(backend),
2259 mapping,
2260 srcBounds,
2262 device->imageInfo().colorSpace(),
2263 &stats};
2264
2266 ctx, sk_ref_sp(image), src, imageBounds, sampling);
2267 // Apply effects that are normally processed on the draw *before* any layer/image filter.
2268 source = apply_alpha_and_colorfilter(ctx, source, realPaint);
2269
2270 // Evaluate the image filter, with a context pointing to the source created directly from
2271 // 'image' (which will not require intermediate renderpasses when 'src' is integer aligned).
2272 // and a desired output matching the device clip bounds.
2273 ctx = ctx.withNewDesiredOutput(mapping.deviceToLayer(outputBounds))
2274 .withNewSource(source);
2275 auto result = as_IFB(realPaint.getImageFilter())->filterImage(ctx);
2276 result.draw(ctx, device, realPaint.getBlender());
2277 stats.reportStats();
2278 return;
2279 }
2280
2281 // When there's a alpha-only image that must be colorized or a mask filter to apply, go through
2282 // the regular auto-layer-for-imagefilter process
2283 if (realPaint.getMaskFilter() && this->topDevice()->useDrawCoverageMaskForMaskFilters()) {
2284 // Route mask-filtered drawImages to drawRect() to use the auto-layer for mask filters,
2285 // which require all shading to be encoded in the paint.
2287 image, sampling, src, dst, constraint == kStrict_SrcRectConstraint, &realPaint);
2288 if (drawDst.isEmpty()) {
2289 return;
2290 } else {
2291 this->drawRect(drawDst, realPaint);
2292 return;
2293 }
2294 }
2295
2296 auto layer = this->aboutToDraw(realPaint, &dst,
2297 PredrawFlags::kCheckForOverwrite |
2298 (image->isOpaque() ? PredrawFlags::kOpaqueShaderOverride
2299 : PredrawFlags::kNonOpaqueShaderOverride));
2300 if (layer) {
2301 this->topDevice()->drawImageRect(image, &src, dst, realSampling, layer->paint(),
2302 constraint);
2303 }
2304}
2305
2306void SkCanvas::onDrawImageLattice2(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2307 SkFilterMode filter, const SkPaint* paint) {
2309
2310 if (this->internalQuickReject(dst, realPaint)) {
2311 return;
2312 }
2313
2314 auto layer = this->aboutToDraw(realPaint, &dst);
2315 if (layer) {
2316 this->topDevice()->drawImageLattice(image, lattice, dst, filter, layer->paint());
2317 }
2318}
2319
2321 const SkSamplingOptions& sampling, const SkPaint* paint) {
2322 TRACE_EVENT0("skia", TRACE_FUNC);
2324
2325 this->drawImageRect(image,
2326 /*src=*/SkRect::MakeWH(image->width(), image->height()),
2327 /*dst=*/SkRect::MakeXYWH(x, y, image->width(), image->height()),
2328 sampling,
2329 paint,
2331}
2332
2334 const SkSamplingOptions& sampling, const SkPaint* paint,
2335 SrcRectConstraint constraint) {
2337 if (!fillable(dst) || !fillable(src)) {
2338 return;
2339 }
2340 this->onDrawImageRect2(image, src, dst, sampling, paint, constraint);
2341}
2342
2344 const SkSamplingOptions& sampling, const SkPaint* paint) {
2348}
2349
2351 const SkPaint& paint) {
2352 auto glyphRunList = fScratchGlyphRunBuilder->blobToGlyphRunList(*blob, {x, y});
2353 this->onDrawGlyphRunList(glyphRunList, paint);
2354}
2355
2357 SkRect bounds = glyphRunList.sourceBoundsWithOrigin();
2358 if (this->internalQuickReject(bounds, paint)) {
2359 return;
2360 }
2361
2362 // Text attempts to apply any SkMaskFilter internally and save the blurred masks in the
2363 // strike cache; if a glyph must be drawn as a path or drawable, SkDevice routes back to
2364 // this SkCanvas to retry, which will go through a function that does *not* skip the mask
2365 // filter layer.
2366 auto layer = this->aboutToDraw(paint, &bounds, PredrawFlags::kSkipMaskFilterAutoLayer);
2367 if (layer) {
2368 this->topDevice()->drawGlyphRunList(this, glyphRunList, layer->paint());
2369 }
2370}
2371
2372sk_sp<Slug> SkCanvas::convertBlobToSlug(
2373 const SkTextBlob& blob, SkPoint origin, const SkPaint& paint) {
2374 TRACE_EVENT0("skia", TRACE_FUNC);
2375 auto glyphRunList = fScratchGlyphRunBuilder->blobToGlyphRunList(blob, origin);
2376 return this->onConvertGlyphRunListToSlug(glyphRunList, paint);
2377}
2378
2380 const SkPaint& paint) {
2381 SkRect bounds = glyphRunList.sourceBoundsWithOrigin();
2382 if (bounds.isEmpty() || !bounds.isFinite() || paint.nothingToDraw()) {
2383 return nullptr;
2384 }
2385 // See comment in onDrawGlyphRunList()
2386 auto layer = this->aboutToDraw(paint, &bounds, PredrawFlags::kSkipMaskFilterAutoLayer);
2387 if (layer) {
2388 return this->topDevice()->convertGlyphRunListToSlug(glyphRunList, layer->paint());
2389 }
2390 return nullptr;
2391}
2392
2393void SkCanvas::drawSlug(const Slug* slug, const SkPaint& paint) {
2394 TRACE_EVENT0("skia", TRACE_FUNC);
2395 if (slug) {
2396 this->onDrawSlug(slug, paint);
2397 }
2398}
2399
2400void SkCanvas::onDrawSlug(const Slug* slug, const SkPaint& paint) {
2402 if (this->internalQuickReject(bounds, paint)) {
2403 return;
2404 }
2405 // See comment in onDrawGlyphRunList()
2406 auto layer = this->aboutToDraw(paint, &bounds, PredrawFlags::kSkipMaskFilterAutoLayer);
2407 if (layer) {
2408 this->topDevice()->drawSlug(this, slug, layer->paint());
2409 }
2410}
2411
2412// These call the (virtual) onDraw... method
2413void SkCanvas::drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding,
2414 SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) {
2415 TRACE_EVENT0("skia", TRACE_FUNC);
2416 if (byteLength) {
2417 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
2418 const sktext::GlyphRunList& glyphRunList =
2419 fScratchGlyphRunBuilder->textToGlyphRunList(
2420 font, paint, text, byteLength, {x, y}, encoding);
2421 if (!glyphRunList.empty()) {
2422 this->onDrawGlyphRunList(glyphRunList, paint);
2423 }
2424 }
2425}
2426
2427void SkCanvas::drawGlyphs(int count, const SkGlyphID* glyphs, const SkPoint* positions,
2428 const uint32_t* clusters, int textByteCount, const char* utf8text,
2429 SkPoint origin, const SkFont& font, const SkPaint& paint) {
2430 if (count <= 0) { return; }
2431
2432 sktext::GlyphRun glyphRun {
2433 font,
2434 SkSpan(positions, count),
2436 SkSpan(utf8text, textByteCount),
2437 SkSpan(clusters, count),
2439 };
2440
2441 sktext::GlyphRunList glyphRunList = fScratchGlyphRunBuilder->makeGlyphRunList(
2442 glyphRun, paint, origin);
2443 this->onDrawGlyphRunList(glyphRunList, paint);
2444}
2445
2446void SkCanvas::drawGlyphs(int count, const SkGlyphID glyphs[], const SkPoint positions[],
2447 SkPoint origin, const SkFont& font, const SkPaint& paint) {
2448 if (count <= 0) { return; }
2449
2450 sktext::GlyphRun glyphRun {
2451 font,
2452 SkSpan(positions, count),
2457 };
2458
2459 sktext::GlyphRunList glyphRunList = fScratchGlyphRunBuilder->makeGlyphRunList(
2460 glyphRun, paint, origin);
2461 this->onDrawGlyphRunList(glyphRunList, paint);
2462}
2463
2465 SkPoint origin, const SkFont& font, const SkPaint& paint) {
2466 if (count <= 0) { return; }
2467
2468 auto [positions, rotateScales] =
2469 fScratchGlyphRunBuilder->convertRSXForm(SkSpan(xforms, count));
2470
2471 sktext::GlyphRun glyphRun {
2472 font,
2473 positions,
2477 rotateScales
2478 };
2479 sktext::GlyphRunList glyphRunList = fScratchGlyphRunBuilder->makeGlyphRunList(
2480 glyphRun, paint, origin);
2481 this->onDrawGlyphRunList(glyphRunList, paint);
2482}
2483
2485 const SkPaint& paint) {
2486 TRACE_EVENT0("skia", TRACE_FUNC);
2487 RETURN_ON_NULL(blob);
2489
2490 // Overflow if more than 2^21 glyphs stopping a buffer overflow latter in the stack.
2491 // See chromium:1080481
2492 // TODO: can consider unrolling a few at a time if this limit becomes a problem.
2493 int totalGlyphCount = 0;
2494 constexpr int kMaxGlyphCount = 1 << 21;
2495 SkTextBlob::Iter i(*blob);
2497 while (i.next(&r)) {
2498 int glyphsLeft = kMaxGlyphCount - totalGlyphCount;
2499 RETURN_ON_FALSE(r.fGlyphCount <= glyphsLeft);
2500 totalGlyphCount += r.fGlyphCount;
2501 }
2502
2503 this->onDrawTextBlob(blob, x, y, paint);
2504}
2505
2507 const SkPaint& paint) {
2509
2510 const SkRect& bounds = vertices->bounds();
2511 if (this->internalQuickReject(bounds, simplePaint)) {
2512 return;
2513 }
2514
2515 auto layer = this->aboutToDraw(simplePaint, &bounds);
2516 if (layer) {
2517 this->topDevice()->drawVertices(vertices, SkBlender::Mode(bmode), layer->paint());
2518 }
2519}
2520
2523 auto layer = this->aboutToDraw(simplePaint, nullptr);
2524 if (layer) {
2525 this->topDevice()->drawMesh(mesh, std::move(blender), paint);
2526 }
2527}
2528
2529void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2530 const SkPoint texCoords[4], SkBlendMode bmode,
2531 const SkPaint& paint) {
2532 TRACE_EVENT0("skia", TRACE_FUNC);
2533 if (nullptr == cubics) {
2534 return;
2535 }
2536
2537 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
2538}
2539
2540void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2541 const SkPoint texCoords[4], SkBlendMode bmode,
2542 const SkPaint& paint) {
2543 // drawPatch has the same behavior restrictions as drawVertices
2545
2546 // Since a patch is always within the convex hull of the control points, we discard it when its
2547 // bounding rectangle is completely outside the current clip.
2548 SkRect bounds;
2549 bounds.setBounds(cubics, SkPatchUtils::kNumCtrlPts);
2550 if (this->internalQuickReject(bounds, simplePaint)) {
2551 return;
2552 }
2553
2554 auto layer = this->aboutToDraw(simplePaint, &bounds);
2555 if (layer) {
2556 this->topDevice()->drawPatch(cubics, colors, texCoords, SkBlender::Mode(bmode),
2557 layer->paint());
2558 }
2559}
2560
2562#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
2563 TRACE_EVENT0("skia", TRACE_FUNC);
2564#endif
2566 if (x || y) {
2568 this->onDrawDrawable(dr, &matrix);
2569 } else {
2570 this->onDrawDrawable(dr, nullptr);
2571 }
2572}
2573
2575#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
2576 TRACE_EVENT0("skia", TRACE_FUNC);
2577#endif
2579 if (matrix && matrix->isIdentity()) {
2580 matrix = nullptr;
2581 }
2582 this->onDrawDrawable(dr, matrix);
2583}
2584
2586 // drawable bounds are no longer reliable (e.g. android displaylist)
2587 // so don't use them for quick-reject
2588 if (this->predrawNotify()) {
2589 this->topDevice()->drawDrawable(this, dr, matrix);
2590 }
2591}
2592
2593void SkCanvas::onDrawAtlas2(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2594 const SkColor colors[], int count, SkBlendMode bmode,
2595 const SkSamplingOptions& sampling, const SkRect* cull,
2596 const SkPaint* paint) {
2597 // drawAtlas is a combination of drawVertices and drawImage...
2599 realPaint.setShader(atlas->makeShader(sampling));
2600
2601 if (cull && this->internalQuickReject(*cull, realPaint)) {
2602 return;
2603 }
2604
2605 // drawAtlas should not have mask filters on its paint, so we don't need to worry about
2606 // converting its "drawImage" behavior into the paint to work with the auto-mask-filter system.
2607 SkASSERT(!realPaint.getMaskFilter());
2608 auto layer = this->aboutToDraw(realPaint);
2609 if (layer) {
2610 this->topDevice()->drawAtlas(xform, tex, colors, count, SkBlender::Mode(bmode),
2611 layer->paint());
2612 }
2613}
2614
2616 SkASSERT(key);
2617
2618 if (this->predrawNotify()) {
2619 this->topDevice()->drawAnnotation(rect, key, value);
2620 }
2621}
2622
2624 const SkColor4f& color, SkBlendMode mode) {
2625 SkASSERT(r.isSorted());
2626
2628 paint.setBlendMode(mode);
2629 if (this->internalQuickReject(r, paint)) {
2630 return;
2631 }
2632
2633 if (this->predrawNotify()) {
2634 this->topDevice()->drawEdgeAAQuad(r, clip, edgeAA, color, mode);
2635 }
2636}
2637
2639 const SkPoint dstClips[], const SkMatrix preViewMatrices[],
2640 const SkSamplingOptions& sampling, const SkPaint* paint,
2641 SrcRectConstraint constraint) {
2642 if (count <= 0) {
2643 // Nothing to draw
2644 return;
2645 }
2646
2648 SkSamplingOptions realSampling = clean_sampling_for_constraint(sampling, constraint);
2649
2650 // We could calculate the set's dstRect union to always check quickReject(), but we can't reject
2651 // individual entries and Chromium's occlusion culling already makes it likely that at least one
2652 // entry will be visible. So, we only calculate the draw bounds when it's trivial (count == 1),
2653 // or we need it for the autolooper (since it greatly improves image filter perf).
2654 bool needsAutoLayer = SkToBool(realPaint.getImageFilter());
2655 bool setBoundsValid = count == 1 || needsAutoLayer;
2656 SkRect setBounds = imageSet[0].fDstRect;
2657 if (imageSet[0].fMatrixIndex >= 0) {
2658 // Account for the per-entry transform that is applied prior to the CTM when drawing
2659 preViewMatrices[imageSet[0].fMatrixIndex].mapRect(&setBounds);
2660 }
2661 if (needsAutoLayer) {
2662 for (int i = 1; i < count; ++i) {
2663 SkRect entryBounds = imageSet[i].fDstRect;
2664 if (imageSet[i].fMatrixIndex >= 0) {
2665 preViewMatrices[imageSet[i].fMatrixIndex].mapRect(&entryBounds);
2666 }
2667 setBounds.joinPossiblyEmptyRect(entryBounds);
2668 }
2669 }
2670
2671 // If we happen to have the draw bounds, though, might as well check quickReject().
2672 if (setBoundsValid && this->internalQuickReject(setBounds, realPaint)) {
2673 return;
2674 }
2675
2676 auto layer = this->aboutToDraw(realPaint, setBoundsValid ? &setBounds : nullptr);
2677 if (layer) {
2678 this->topDevice()->drawEdgeAAImageSet(imageSet, count, dstClips, preViewMatrices,
2679 realSampling, layer->paint(), constraint);
2680 }
2681}
2682
2683//////////////////////////////////////////////////////////////////////////////
2684// These methods are NOT virtual, and therefore must call back into virtual
2685// methods, rather than actually drawing themselves.
2686//////////////////////////////////////////////////////////////////////////////
2687
2689 SkPaint paint;
2690 paint.setColor(c);
2691 paint.setBlendMode(mode);
2692 this->drawPaint(paint);
2693}
2694
2696 const SkPoint pt = { x, y };
2697 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2698}
2699
2701 SkPoint pts[2];
2702 pts[0].set(x0, y0);
2703 pts[1].set(x1, y1);
2704 this->drawPoints(kLines_PointMode, 2, pts, paint);
2705}
2706
2708 if (radius < 0) {
2709 radius = 0;
2710 }
2711
2712 SkRect r;
2713 r.setLTRB(cx - radius, cy - radius, cx + radius, cy + radius);
2714 this->drawOval(r, paint);
2715}
2716
2718 const SkPaint& paint) {
2719 if (rx > 0 && ry > 0) {
2720 SkRRect rrect;
2721 rrect.setRectXY(r, rx, ry);
2722 this->drawRRect(rrect, paint);
2723 } else {
2724 this->drawRect(r, paint);
2725 }
2726}
2727
2729 SkScalar sweepAngle, bool useCenter,
2730 const SkPaint& paint) {
2731 TRACE_EVENT0("skia", TRACE_FUNC);
2732 if (oval.isEmpty() || !sweepAngle) {
2733 return;
2734 }
2735 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
2736}
2737
2738///////////////////////////////////////////////////////////////////////////////
2739#ifdef SK_DISABLE_SKPICTURE
2740void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {}
2741
2742
2744 const SkPaint* paint) {}
2745#else
2746
2748 TRACE_EVENT0("skia", TRACE_FUNC);
2750
2751 if (matrix && matrix->isIdentity()) {
2752 matrix = nullptr;
2753 }
2756 picture->playback(this);
2757 } else {
2758 this->onDrawPicture(picture, matrix, paint);
2759 }
2760}
2761
2763 const SkPaint* paint) {
2764 if (this->internalQuickReject(picture->cullRect(), paint ? *paint : SkPaint{}, matrix)) {
2765 return;
2766 }
2767
2769 picture->playback(this);
2770}
2771#endif
2772
2773///////////////////////////////////////////////////////////////////////////////
2774
2777SkCanvas::ImageSetEntry::ImageSetEntry(const ImageSetEntry&) = default;
2778SkCanvas::ImageSetEntry& SkCanvas::ImageSetEntry::operator=(const ImageSetEntry&) = default;
2779
2781 const SkRect& dstRect, int matrixIndex, float alpha,
2782 unsigned aaFlags, bool hasClip)
2783 : fImage(std::move(image))
2784 , fSrcRect(srcRect)
2785 , fDstRect(dstRect)
2786 , fMatrixIndex(matrixIndex)
2787 , fAlpha(alpha)
2788 , fAAFlags(aaFlags)
2789 , fHasClip(hasClip) {}
2790
2792 const SkRect& dstRect, float alpha, unsigned aaFlags)
2793 : fImage(std::move(image))
2794 , fSrcRect(srcRect)
2795 , fDstRect(dstRect)
2796 , fAlpha(alpha)
2797 , fAAFlags(aaFlags) {}
2798
2799///////////////////////////////////////////////////////////////////////////////
2800
2801std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
2802 size_t rowBytes, const SkSurfaceProps* props) {
2803 if (!SkSurfaceValidateRasterInfo(info, rowBytes)) {
2804 return nullptr;
2805 }
2806
2808 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2809 return nullptr;
2810 }
2811
2812 return props ?
2813 std::make_unique<SkCanvas>(bitmap, *props) :
2814 std::make_unique<SkCanvas>(bitmap);
2815}
2816
2817///////////////////////////////////////////////////////////////////////////////
2818
2820 : INHERITED(SkIRect::MakeWH(width, height)) {}
2821
2823 : INHERITED(bounds) {}
2824
2826 (void)this->INHERITED::getSaveLayerStrategy(rec);
2828}
2829
2831 return false;
2832}
2833
2834///////////////////////////////////////////////////////////////////////////////
2835
2836static_assert((int)SkRegion::kDifference_Op == (int)SkClipOp::kDifference, "");
2837static_assert((int)SkRegion::kIntersect_Op == (int)SkClipOp::kIntersect, "");
2838
2839///////////////////////////////////////////////////////////////////////////////////////////////////
2840
2842 const SkDevice* dev = this->topDevice();
2843 if (fAllocator) {
2845 SkIRect clip = dev->devClipBounds();
2846 if (!clip.intersect({0, 0, dev->width(), dev->height()})) {
2847 clip.setEmpty();
2848 }
2849
2850 fAllocator->updateHandle(handle, dev->localToDevice(), clip);
2851 return handle;
2852 }
2853 return nullptr;
2854}
2855
2856static bool install(SkBitmap* bm, const SkImageInfo& info,
2857 const SkRasterHandleAllocator::Rec& rec) {
2858 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
2859}
2860
2861SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2862 SkBitmap* bm) {
2864 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2865 return nullptr;
2866 }
2867 return rec.fHandle;
2868}
2869
2870std::unique_ptr<SkCanvas>
2871SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2872 const SkImageInfo& info, const Rec* rec,
2873 const SkSurfaceProps* props) {
2874 if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) {
2875 return nullptr;
2876 }
2877
2878 SkBitmap bm;
2879 Handle hndl;
2880
2881 if (rec) {
2882 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2883 } else {
2884 hndl = alloc->allocBitmap(info, &bm);
2885 }
2886 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl, props))
2887 : nullptr;
2888}
const char * backend
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
m reset()
SkMatrix fMatrix
Definition: FillRRectOp.cpp:74
uint16_t glyphs[5]
Definition: FontMgrTest.cpp:46
int count
Definition: FontMgrTest.cpp:50
constexpr int kMaxGlyphCount
Definition: FuzzCanvas.cpp:865
static float prev(float f)
static void Union(SkRegion *rgn, const SkIRect &rect)
Definition: RegionTest.cpp:27
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
#define SkUNREACHABLE
Definition: SkAssert.h:135
#define SkASSERT(cond)
Definition: SkAssert.h:116
SkBlendMode
Definition: SkBlendMode.h:38
@ kDstIn
r = d * sa
@ kModulate
r = s*d
@ kDstOver
r = d + (1-da)*s
@ kClear
r = 0
SkBlenderBase * as_BB(SkBlender *blend)
Definition: SkBlenderBase.h:69
@ kNormal_SkBlurStyle
fuzzy inside and outside
Definition: SkBlurTypes.h:12
constexpr int kMaxPictureOpsToUnrollInsteadOfRef
Definition: SkCanvasPriv.h:108
#define RETURN_ON_NULL(ptr)
Definition: SkCanvas.cpp:74
static SkPaint clean_paint_for_drawImage(const SkPaint *paint)
Definition: SkCanvas.cpp:2165
static bool install(SkBitmap *bm, const SkImageInfo &info, const SkRasterHandleAllocator::Rec &rec)
Definition: SkCanvas.cpp:2856
static SkPaint clean_paint_for_drawVertices(SkPaint paint)
Definition: SkCanvas.cpp:2177
static SkSamplingOptions clean_sampling_for_constraint(const SkSamplingOptions &sampling, SkCanvas::SrcRectConstraint constraint)
Definition: SkCanvas.cpp:2190
static SkPaint clean_paint_for_lattice(const SkPaint *paint)
Definition: SkCanvas.cpp:1759
sktext::gpu::Slug Slug
Definition: SkCanvas.cpp:81
static std::optional< std::pair< skif::Mapping, skif::LayerSpace< SkIRect > > > get_layer_mapping_and_bounds(SkCanvas::FilterSpan filters, const SkMatrix &localToDst, const skif::DeviceSpace< SkIRect > &targetOutput, std::optional< skif::ParameterSpace< SkRect > > contentBounds={}, SkScalar scaleFactor=1.0f)
Definition: SkCanvas.cpp:568
static skif::FilterResult apply_alpha_and_colorfilter(const skif::Context &ctx, const skif::FilterResult &image, const SkPaint &paint)
Definition: SkCanvas.cpp:681
static SkColorType image_filter_color_type(const SkColorInfo &dstInfo)
Definition: SkCanvas.cpp:670
static bool fillable(const SkRect &r)
Definition: SkCanvas.cpp:1753
static skif::ParameterSpace< SkPoint > compute_decomposition_center(const SkMatrix &dstToLocal, std::optional< skif::ParameterSpace< SkRect > > contentBounds, const skif::DeviceSpace< SkIRect > &targetOutput)
Definition: SkCanvas.cpp:532
static const SkBlurMaskFilterImpl * can_attempt_blurred_rrect_draw(const SkPaint &paint)
Definition: SkCanvas.cpp:1939
#define RETURN_ON_FALSE(pred)
Definition: SkCanvas.cpp:75
SkClipOp
Definition: SkClipOp.h:13
static SkColorFilterBase * as_CFB(SkColorFilter *filter)
SkColorType
Definition: SkColorType.h:19
@ kBGRA_8888_SkColorType
pixel with 8 bits for blue, green, red, alpha; in 32-bit word
Definition: SkColorType.h:26
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
Definition: SkColorType.h:38
@ kAlpha_8_SkColorType
pixel with alpha in 8-bit byte
Definition: SkColorType.h:21
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24
uint32_t SkColor
Definition: SkColor.h:37
#define SK_MAKE_BITMASK_OPS(E)
Definition: SkEnumBitMask.h:68
static bool SkIsFinite(T x, Pack... values)
SkTextEncoding
Definition: SkFontTypes.h:11
static SkImageFilter_Base * as_IFB(SkImageFilter *filter)
SkRect SkModifyPaintAndDstForDrawImageRect(const SkImage *image, const SkSamplingOptions &, SkRect src, SkRect dst, bool strictSrcSubset, SkPaint *paint)
static void sk_msan_assert_initialized(const void *begin, const void *end)
Definition: SkMSAN.h:24
SkMaskFilterBase * as_MFB(SkMaskFilter *mf)
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition: SkPath.cpp:3892
sk_sp< T > sk_ref_sp(T *obj)
Definition: SkRefCnt.h:381
static constexpr int32_t Sk64_pin_to_s32(int64_t x)
Definition: SkSafe32.h:16
SkFilterMode
SkSpan(Container &&) -> SkSpan< std::remove_pointer_t< decltype(std::data(std::declval< Container >()))> >
static SkSurfaceProps SkSurfacePropsCopyOrDefault(const SkSurfaceProps *props)
Definition: SkSurfacePriv.h:15
bool SkSurfaceValidateRasterInfo(const SkImageInfo &, size_t rb=kIgnoreRowBytesValue)
constexpr size_t kIgnoreRowBytesValue
Definition: SkSurfacePriv.h:19
SkPixelGeometry
@ kUnknown_SkPixelGeometry
static constexpr const T & SkTPin(const T &x, const T &lo, const T &hi)
Definition: SkTPin.h:19
void sk_ignore_unused_variable(const T &)
Definition: SkTemplates.h:37
constexpr int SkToInt(S x)
Definition: SkTo.h:29
static constexpr bool SkToBool(const T &x)
Definition: SkTo.h:35
#define TRACE_FUNC
Definition: SkTraceEvent.h:30
uint16_t SkGlyphID
Definition: SkTypes.h:179
static SkScalar center(float pos0, float pos1)
bool installPixels(const SkImageInfo &info, void *pixels, size_t rowBytes, void(*releaseProc)(void *addr, void *context), void *context)
Definition: SkBitmap.cpp:323
bool peekPixels(SkPixmap *pixmap) const
Definition: SkBitmap.cpp:635
bool affectsTransparentBlack() const
static sk_sp< SkBlender > Mode(SkBlendMode mode)
SkBlurStyle blurStyle() const
SkScalar computeXformedSigma(const SkMatrix &ctm) const
AutoUpdateQRBounds(SkCanvas *canvas)
Definition: SkCanvas.cpp:231
virtual void onDrawDrawable(SkDrawable *drawable, const SkMatrix *matrix)
Definition: SkCanvas.cpp:2585
virtual void onDrawImage2(const SkImage *, SkScalar dx, SkScalar dy, const SkSamplingOptions &, const SkPaint *)
Definition: SkCanvas.cpp:2185
int saveLayer(const SkRect *bounds, const SkPaint *paint)
Definition: SkCanvas.cpp:496
bool getProps(SkSurfaceProps *props) const
Definition: SkCanvas.cpp:1214
virtual void onDrawDRRect(const SkRRect &outer, const SkRRect &inner, const SkPaint &paint)
Definition: SkCanvas.cpp:2132
SkRasterHandleAllocator::Handle accessTopRasterHandle() const
Definition: SkCanvas.cpp:2841
SkSpan< sk_sp< SkImageFilter > > FilterSpan
Definition: SkCanvas.h:678
void drawRect(const SkRect &rect, const SkPaint &paint)
Definition: SkCanvas.cpp:1673
SkSurface * getSurface() const
Definition: SkCanvas.cpp:365
void drawOval(const SkRect &oval, const SkPaint &paint)
Definition: SkCanvas.cpp:1698
void clipRect(const SkRect &rect, SkClipOp op, bool doAntiAlias)
Definition: SkCanvas.cpp:1361
virtual void onDrawPath(const SkPath &path, const SkPaint &paint)
Definition: SkCanvas.cpp:2144
bool peekPixels(SkPixmap *pixmap)
Definition: SkCanvas.cpp:1237
void drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint &paint)
Definition: SkCanvas.cpp:1710
virtual void onDrawAtlas2(const SkImage *, const SkRSXform[], const SkRect src[], const SkColor[], int count, SkBlendMode, const SkSamplingOptions &, const SkRect *cull, const SkPaint *)
Definition: SkCanvas.cpp:2593
virtual bool isClipEmpty() const
Definition: SkCanvas.cpp:1549
SkSurfaceProps getTopProps() const
Definition: SkCanvas.cpp:1224
void drawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texCoords[4], SkBlendMode mode, const SkPaint &paint)
Definition: SkCanvas.cpp:2529
void restore()
Definition: SkCanvas.cpp:461
void drawPoint(SkScalar x, SkScalar y, const SkPaint &paint)
Definition: SkCanvas.cpp:2695
virtual bool onPeekPixels(SkPixmap *pixmap)
Definition: SkCanvas.cpp:1241
void drawSimpleText(const void *text, size_t byteLength, SkTextEncoding encoding, SkScalar x, SkScalar y, const SkFont &font, const SkPaint &paint)
Definition: SkCanvas.cpp:2413
void translate(SkScalar dx, SkScalar dy)
Definition: SkCanvas.cpp:1278
sk_sp< SkSurface > makeSurface(const SkImageInfo &info, const SkSurfaceProps *props=nullptr)
Definition: SkCanvas.cpp:1195
virtual SkImageInfo onImageInfo() const
Definition: SkCanvas.cpp:1210
virtual void onDrawImageLattice2(const SkImage *, const Lattice &, const SkRect &dst, SkFilterMode, const SkPaint *)
Definition: SkCanvas.cpp:2306
void drawImageNine(const SkImage *image, const SkIRect &center, const SkRect &dst, SkFilterMode filter, const SkPaint *paint=nullptr)
Definition: SkCanvas.cpp:1769
void drawColor(SkColor color, SkBlendMode mode=SkBlendMode::kSrcOver)
Definition: SkCanvas.h:1182
virtual void onDrawPicture(const SkPicture *picture, const SkMatrix *matrix, const SkPaint *paint)
Definition: SkCanvas.cpp:2762
void androidFramework_setDeviceClipRestriction(const SkIRect &rect)
Definition: SkCanvas.cpp:1378
virtual void onDrawAnnotation(const SkRect &rect, const char key[], SkData *value)
Definition: SkCanvas.cpp:2615
virtual void onDrawPaint(const SkPaint &paint)
Definition: SkCanvas.cpp:1894
virtual void onDrawBehind(const SkPaint &paint)
Definition: SkCanvas.cpp:2031
bool writePixels(const SkImageInfo &info, const void *pixels, size_t rowBytes, int x, int y)
Definition: SkCanvas.cpp:399
SkRect getLocalClipBounds() const
Definition: SkCanvas.cpp:1586
virtual GrRecordingContext * recordingContext() const
Definition: SkCanvas.cpp:1637
virtual ~SkCanvas()
Definition: SkCanvas.cpp:347
virtual void onClipShader(sk_sp< SkShader >, SkClipOp)
Definition: SkCanvas.cpp:1505
virtual sk_sp< sktext::gpu::Slug > onConvertGlyphRunListToSlug(const sktext::GlyphRunList &glyphRunList, const SkPaint &paint)
Definition: SkCanvas.cpp:2379
virtual void didScale(SkScalar, SkScalar)
Definition: SkCanvas.h:2282
virtual void didSetM44(const SkM44 &)
Definition: SkCanvas.h:2280
virtual bool isClipRect() const
Definition: SkCanvas.cpp:1553
virtual void didRestore()
Definition: SkCanvas.h:2277
virtual void onDrawTextBlob(const SkTextBlob *blob, SkScalar x, SkScalar y, const SkPaint &paint)
Definition: SkCanvas.cpp:2350
virtual skgpu::graphite::Recorder * recorder() const
Definition: SkCanvas.cpp:1641
void drawPaint(const SkPaint &paint)
Definition: SkCanvas.cpp:1668
void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint &paint)
Definition: SkCanvas.cpp:2700
void private_draw_shadow_rec(const SkPath &, const SkDrawShadowRec &)
Definition: SkCanvas.cpp:1831
void drawDrawable(SkDrawable *drawable, const SkMatrix *matrix=nullptr)
Definition: SkCanvas.cpp:2574
virtual void onDrawRect(const SkRect &rect, const SkPaint &paint)
Definition: SkCanvas.cpp:2004
virtual void onDrawEdgeAAImageSet2(const ImageSetEntry imageSet[], int count, const SkPoint dstClips[], const SkMatrix preViewMatrices[], const SkSamplingOptions &, const SkPaint *, SrcRectConstraint)
Definition: SkCanvas.cpp:2638
void drawAnnotation(const SkRect &rect, const char key[], SkData *value)
Definition: SkCanvas.cpp:1824
virtual SkISize getBaseLayerSize() const
Definition: SkCanvas.cpp:369
virtual void onDrawRegion(const SkRegion &region, const SkPaint &paint)
Definition: SkCanvas.cpp:2019
virtual void onDiscard()
Definition: SkCanvas.cpp:1888
virtual bool onAccessTopLayerPixels(SkPixmap *pixmap)
Definition: SkCanvas.cpp:1272
virtual void onDrawShadowRec(const SkPath &, const SkDrawShadowRec &)
Definition: SkCanvas.cpp:1836
static constexpr int kMaxFiltersPerLayer
Definition: SkCanvas.h:679
virtual SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec &)
Definition: SkCanvas.h:2270
virtual void onClipRect(const SkRect &rect, SkClipOp op, ClipEdgeStyle edgeStyle)
Definition: SkCanvas.cpp:1370
friend class SkNoDrawCanvas
Definition: SkCanvas.h:2491
virtual void onResetClip()
Definition: SkCanvas.cpp:1424
virtual void onDrawMesh(const SkMesh &, sk_sp< SkBlender >, const SkPaint &)
Definition: SkCanvas.cpp:2521
SrcRectConstraint
Definition: SkCanvas.h:1541
@ kStrict_SrcRectConstraint
sample only inside bounds; slower
Definition: SkCanvas.h:1542
@ kFast_SrcRectConstraint
sample outside bounds; faster
Definition: SkCanvas.h:1543
void drawGlyphs(int count, const SkGlyphID glyphs[], const SkPoint positions[], const uint32_t clusters[], int textByteCount, const char utf8text[], SkPoint origin, const SkFont &font, const SkPaint &paint)
SkM44 getLocalToDevice() const
Definition: SkCanvas.cpp:1633
void clipRegion(const SkRegion &deviceRgn, SkClipOp op=SkClipOp::kIntersect)
Definition: SkCanvas.cpp:1510
void experimental_DrawEdgeAAQuad(const SkRect &rect, const SkPoint clip[4], QuadAAFlags aaFlags, const SkColor4f &color, SkBlendMode mode)
Definition: SkCanvas.cpp:1845
SaveLayerStrategy
Definition: SkCanvas.h:2263
@ kFullLayer_SaveLayerStrategy
Definition: SkCanvas.h:2264
@ kNoLayer_SaveLayerStrategy
Definition: SkCanvas.h:2265
void drawMesh(const SkMesh &mesh, sk_sp< SkBlender > blender, const SkPaint &paint)
Definition: SkCanvas.cpp:1739
virtual void onDrawSlug(const sktext::gpu::Slug *slug, const SkPaint &paint)
Definition: SkCanvas.cpp:2400
void drawIRect(const SkIRect &rect, const SkPaint &paint)
Definition: SkCanvas.h:1358
virtual void willRestore()
Definition: SkCanvas.h:2276
int getSaveCount() const
Definition: SkCanvas.cpp:431
void experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[], int cnt, const SkPoint dstClips[], const SkMatrix preViewMatrices[], const SkSamplingOptions &, const SkPaint *paint=nullptr, SrcRectConstraint constraint=kStrict_SrcRectConstraint)
Definition: SkCanvas.cpp:1853
void rotate(SkScalar degrees)
Definition: SkCanvas.cpp:1300
virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texCoords[4], SkBlendMode mode, const SkPaint &paint)
Definition: SkCanvas.cpp:2540
void restoreToCount(int saveCount)
Definition: SkCanvas.cpp:478
virtual void didTranslate(SkScalar, SkScalar)
Definition: SkCanvas.h:2281
void drawRRect(const SkRRect &rrect, const SkPaint &paint)
Definition: SkCanvas.cpp:1705
SkMatrix getTotalMatrix() const
Definition: SkCanvas.cpp:1629
virtual void onDrawVerticesObject(const SkVertices *vertices, SkBlendMode mode, const SkPaint &paint)
Definition: SkCanvas.cpp:2506
void drawRoundRect(const SkRect &rect, SkScalar rx, SkScalar ry, const SkPaint &paint)
Definition: SkCanvas.cpp:2717
void drawArc(const SkRect &oval, SkScalar startAngle, SkScalar sweepAngle, bool useCenter, const SkPaint &paint)
Definition: SkCanvas.cpp:2728
void drawImageLattice(const SkImage *image, const Lattice &lattice, const SkRect &dst, SkFilterMode filter, const SkPaint *paint=nullptr)
Definition: SkCanvas.cpp:1786
void resetMatrix()
Definition: SkCanvas.cpp:1355
void clipPath(const SkPath &path, SkClipOp op, bool doAntiAlias)
Definition: SkCanvas.cpp:1456
SkIRect getDeviceClipBounds() const
Definition: SkCanvas.cpp:1607
@ kPreserveLCDText_SaveLayerFlag
Definition: SkCanvas.h:671
@ kF16ColorType
Definition: SkCanvas.h:674
@ kInitWithPrevious_SaveLayerFlag
initializes with previous contents
Definition: SkCanvas.h:672
virtual void onDrawOval(const SkRect &rect, const SkPaint &paint)
Definition: SkCanvas.cpp:2075
void drawRegion(const SkRegion &region, const SkPaint &paint)
Definition: SkCanvas.cpp:1685
virtual void didConcat44(const SkM44 &)
Definition: SkCanvas.h:2279
virtual bool onGetProps(SkSurfaceProps *props, bool top) const
Definition: SkCanvas.cpp:1230
void drawImageRect(const SkImage *, const SkRect &src, const SkRect &dst, const SkSamplingOptions &, const SkPaint *, SrcRectConstraint)
Definition: SkCanvas.cpp:2333
int save()
Definition: SkCanvas.cpp:447
void drawPath(const SkPath &path, const SkPaint &paint)
Definition: SkCanvas.cpp:1747
void drawAtlas(const SkImage *atlas, const SkRSXform xform[], const SkRect tex[], const SkColor colors[], int count, SkBlendMode mode, const SkSamplingOptions &sampling, const SkRect *cullRect, const SkPaint *paint)
Definition: SkCanvas.cpp:1810
void setMatrix(const SkM44 &matrix)
Definition: SkCanvas.cpp:1349
virtual void onClipRRect(const SkRRect &rrect, SkClipOp op, ClipEdgeStyle edgeStyle)
Definition: SkCanvas.cpp:1449
void temporary_internal_getRgnClip(SkRegion *region)
Definition: SkCanvas.cpp:1535
virtual void onClipPath(const SkPath &path, SkClipOp op, ClipEdgeStyle edgeStyle)
Definition: SkCanvas.cpp:1481
void drawDRRect(const SkRRect &outer, const SkRRect &inner, const SkPaint &paint)
Definition: SkCanvas.cpp:1645
void scale(SkScalar sx, SkScalar sy)
Definition: SkCanvas.cpp:1289
void concat(const SkMatrix &matrix)
Definition: SkCanvas.cpp:1318
@ kHard_ClipEdgeStyle
Definition: SkCanvas.h:2336
@ kSoft_ClipEdgeStyle
Definition: SkCanvas.h:2337
virtual bool onDoSaveBehind(const SkRect *)
Definition: SkCanvas.h:2275
virtual void onDrawGlyphRunList(const sktext::GlyphRunList &glyphRunList, const SkPaint &paint)
Definition: SkCanvas.cpp:2356
SkSurfaceProps getBaseProps() const
Definition: SkCanvas.cpp:1218
void drawPicture(const SkPicture *picture)
Definition: SkCanvas.h:1961
virtual void onDrawImageRect2(const SkImage *, const SkRect &src, const SkRect &dst, const SkSamplingOptions &, const SkPaint *, SrcRectConstraint)
Definition: SkCanvas.cpp:2204
void clipShader(sk_sp< SkShader >, SkClipOp=SkClipOp::kIntersect)
Definition: SkCanvas.cpp:1488
static std::unique_ptr< SkCanvas > MakeRasterDirect(const SkImageInfo &info, void *pixels, size_t rowBytes, const SkSurfaceProps *props=nullptr)
Definition: SkCanvas.cpp:2801
virtual void willSave()
Definition: SkCanvas.h:2268
void drawVertices(const SkVertices *vertices, SkBlendMode mode, const SkPaint &paint)
Definition: SkCanvas.cpp:1720
virtual sk_sp< SkSurface > onNewSurface(const SkImageInfo &info, const SkSurfaceProps &props)
Definition: SkCanvas.cpp:1202
SkImageInfo imageInfo() const
Definition: SkCanvas.cpp:1206
void * accessTopLayerPixels(SkImageInfo *info, size_t *rowBytes, SkIPoint *origin=nullptr)
Definition: SkCanvas.cpp:1245
@ kLines_PointMode
draw each pair of points as a line segment
Definition: SkCanvas.h:1242
@ kPoints_PointMode
draw each point separately
Definition: SkCanvas.h:1241
bool readPixels(const SkImageInfo &dstInfo, void *dstPixels, size_t dstRowBytes, int srcX, int srcY)
Definition: SkCanvas.cpp:382
virtual void onDrawEdgeAAQuad(const SkRect &rect, const SkPoint clip[4], QuadAAFlags aaFlags, const SkColor4f &color, SkBlendMode mode)
Definition: SkCanvas.cpp:2623
virtual void onDrawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint &paint)
Definition: SkCanvas.cpp:1911
void skew(SkScalar sx, SkScalar sy)
Definition: SkCanvas.cpp:1312
void drawTextBlob(const SkTextBlob *blob, SkScalar x, SkScalar y, const SkPaint &paint)
Definition: SkCanvas.cpp:2484
void drawImage(const SkImage *image, SkScalar left, SkScalar top)
Definition: SkCanvas.h:1528
bool quickReject(const SkRect &rect) const
Definition: SkCanvas.cpp:1557
virtual void onDrawRRect(const SkRRect &rrect, const SkPaint &paint)
Definition: SkCanvas.cpp:2105
virtual void onClipRegion(const SkRegion &deviceRgn, SkClipOp op)
Definition: SkCanvas.cpp:1515
void clipRRect(const SkRRect &rrect, SkClipOp op, bool doAntiAlias)
Definition: SkCanvas.cpp:1439
int saveLayerAlphaf(const SkRect *bounds, float alpha)
Definition: SkCanvas.cpp:1077
void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint &paint)
Definition: SkCanvas.cpp:2707
virtual void onDrawArc(const SkRect &rect, SkScalar startAngle, SkScalar sweepAngle, bool useCenter, const SkPaint &paint)
Definition: SkCanvas.cpp:2090
bool affectsTransparentBlack() const
static sk_sp< SkColorFilter > Blend(const SkColor4f &c, sk_sp< SkColorSpace >, SkBlendMode mode)
int bytesPerPixel() const
Definition: SkImageInfo.cpp:88
SkColorInfo makeColorSpace(sk_sp< SkColorSpace > cs) const
Definition: SkImageInfo.cpp:84
sk_sp< SkColorSpace > refColorSpace() const
Definition: SkImageInfo.cpp:67
SkColorType colorType() const
Definition: SkImageInfo.h:140
Definition: SkData.h:25
void * next()
Definition: SkDeque.cpp:251
void * prev()
Definition: SkDeque.cpp:270
@ kBack_IterStart
Definition: SkDeque.h:66
@ kFront_IterStart
Definition: SkDeque.h:65
void * push_back()
Definition: SkDeque.cpp:112
bool empty() const
Definition: SkDeque.h:38
void pop_back()
Definition: SkDeque.cpp:187
const void * back() const
Definition: SkDeque.h:43
int count() const
Definition: SkDeque.h:39
const SkImageInfo & imageInfo() const
Definition: SkDevice.h:117
virtual sk_sp< SkDevice > createDevice(const CreateInfo &, const SkPaint *)
Definition: SkDevice.h:322
virtual void drawVertices(const SkVertices *, sk_sp< SkBlender >, const SkPaint &, bool skipColorXform=false)=0
virtual void drawRRect(const SkRRect &rr, const SkPaint &paint)=0
virtual void drawEdgeAAQuad(const SkRect &rect, const SkPoint clip[4], SkCanvas::QuadAAFlags aaFlags, const SkColor4f &color, SkBlendMode mode)
Definition: SkDevice.cpp:236
virtual void drawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint[], const SkPaint &paint)=0
virtual void drawRegion(const SkRegion &r, const SkPaint &paint)
Definition: SkDevice.cpp:113
SkIPoint getOrigin() const
Definition: SkDevice.cpp:91
virtual void drawAtlas(const SkRSXform[], const SkRect[], const SkColor[], int count, sk_sp< SkBlender >, const SkPaint &)
Definition: SkDevice.cpp:203
virtual void clipPath(const SkPath &path, SkClipOp op, bool aa)=0
bool readPixels(const SkPixmap &dst, int x, int y)
Definition: SkDevice.h:153
virtual bool isClipEmpty() const =0
void clipShader(sk_sp< SkShader > sh, SkClipOp op)
Definition: SkDevice.h:251
virtual void drawShadow(const SkPath &, const SkDrawShadowRec &)
virtual bool isClipRect() const =0
virtual void clipRegion(const SkRegion &region, SkClipOp op)=0
void drawGlyphRunList(SkCanvas *, const sktext::GlyphRunList &glyphRunList, const SkPaint &paint)
Definition: SkDevice.cpp:426
virtual void drawEdgeAAImageSet(const SkCanvas::ImageSetEntry[], int count, const SkPoint dstClips[], const SkMatrix preViewMatrices[], const SkSamplingOptions &, const SkPaint &, SkCanvas::SrcRectConstraint)
Definition: SkDevice.cpp:253
const SkM44 & globalToDevice() const
Definition: SkDevice.h:191
virtual void drawDRRect(const SkRRect &outer, const SkRRect &inner, const SkPaint &)
Definition: SkDevice.cpp:141
virtual void * getRasterHandle() const
Definition: SkDevice.h:282
virtual void popClipStack()=0
virtual void pushClipStack()=0
bool accessPixels(SkPixmap *pmap)
Definition: SkDevice.cpp:383
const SkMatrix & localToDevice() const
Definition: SkDevice.h:179
virtual void drawSlug(SkCanvas *, const sktext::gpu::Slug *slug, const SkPaint &paint)
Definition: SkDevice.cpp:488
virtual GrRecordingContext * recordingContext() const
Definition: SkDevice.h:284
virtual void drawSpecial(SkSpecialImage *, const SkMatrix &localToDevice, const SkSamplingOptions &, const SkPaint &, SkCanvas::SrcRectConstraint constraint=SkCanvas::kStrict_SrcRectConstraint)
Definition: SkDevice.cpp:304
virtual void drawDevice(SkDevice *, const SkSamplingOptions &, const SkPaint &)
Definition: SkDevice.cpp:329
virtual void clipRRect(const SkRRect &rrect, SkClipOp op, bool aa)=0
virtual SkIRect devClipBounds() const =0
const SkSurfaceProps & surfaceProps() const
Definition: SkDevice.h:131
virtual void clipRect(const SkRect &rect, SkClipOp op, bool aa)=0
const SkM44 & deviceToGlobal() const
Definition: SkDevice.h:186
virtual void drawDrawable(SkCanvas *, SkDrawable *, const SkMatrix *)
Definition: SkDevice.cpp:298
virtual skgpu::graphite::Recorder * recorder() const
Definition: SkDevice.h:285
void setDeviceCoordinateSystem(const SkM44 &deviceToGlobal, const SkM44 &globalToDevice, const SkM44 &localToDevice, int bufferOriginX, int bufferOriginY)
Definition: SkDevice.cpp:52
void setGlobalCTM(const SkM44 &ctm)
Definition: SkDevice.cpp:73
virtual sk_sp< sktext::gpu::Slug > convertGlyphRunListToSlug(const sktext::GlyphRunList &glyphRunList, const SkPaint &paint)
Definition: SkDevice.cpp:483
bool peekPixels(SkPixmap *)
Definition: SkDevice.cpp:391
virtual sk_sp< SkSurface > makeSurface(const SkImageInfo &, const SkSurfaceProps &)
Definition: SkDevice.cpp:494
virtual void drawPaint(const SkPaint &paint)=0
virtual void drawMesh(const SkMesh &mesh, sk_sp< SkBlender >, const SkPaint &)=0
virtual bool isClipAntiAliased() const =0
virtual bool useDrawCoverageMaskForMaskFilters() const
Definition: SkDevice.h:276
virtual void drawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texCoords[4], sk_sp< SkBlender >, const SkPaint &paint)
Definition: SkDevice.cpp:152
virtual void drawRect(const SkRect &r, const SkPaint &paint)=0
virtual void drawImageRect(const SkImage *, const SkRect *src, const SkRect &dst, const SkSamplingOptions &, const SkPaint &, SkCanvas::SrcRectConstraint)=0
virtual void drawArc(const SkArc &arc, const SkPaint &paint)
Definition: SkDevice.cpp:134
virtual void drawAnnotation(const SkRect &, const char[], SkData *)
Definition: SkDevice.h:399
virtual void drawPath(const SkPath &path, const SkPaint &paint, bool pathIsMutable=false)=0
virtual void drawOval(const SkRect &oval, const SkPaint &paint)=0
virtual bool isNoPixelsDevice() const
Definition: SkDevice.h:280
virtual void replaceClip(const SkIRect &rect)=0
virtual void drawImageLattice(const SkImage *, const SkCanvas::Lattice &, const SkRect &dst, SkFilterMode, const SkPaint &)
Definition: SkDevice.cpp:163
Definition: SkFont.h:35
skif::LayerSpace< SkIRect > getInputBounds(const skif::Mapping &mapping, const skif::DeviceSpace< SkIRect > &desiredOutput, std::optional< skif::ParameterSpace< SkRect > > knownContentBounds) const
skif::FilterResult filterImage(const skif::Context &context) const
bool isAlphaOnly() const
Definition: SkImage.cpp:239
int width() const
Definition: SkImage.h:285
sk_sp< SkShader > makeShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions &, const SkMatrix *localMatrix=nullptr) const
Definition: SkImage.cpp:179
bool isOpaque() const
Definition: SkImage.h:375
int height() const
Definition: SkImage.h:291
static bool Valid(int imageWidth, int imageHeight, const SkCanvas::Lattice &lattice)
Definition: SkM44.h:150
virtual Type type() const =0
static SkRect MapRect(const SkM44 &m, const SkRect &r)
Definition: SkM44.cpp:216
static SkMatrix Scale(SkScalar sx, SkScalar sy)
Definition: SkMatrix.h:75
static SkMatrix Translate(SkScalar dx, SkScalar dy)
Definition: SkMatrix.h:91
@ kFill_ScaleToFit
scales in x and y to fill destination SkRect
Definition: SkMatrix.h:137
void mapPoints(SkPoint dst[], const SkPoint src[], int count) const
Definition: SkMatrix.cpp:770
static SkMatrix Concat(const SkMatrix &a, const SkMatrix &b)
Definition: SkMatrix.h:1775
bool invert(SkMatrix *inverse) const
Definition: SkMatrix.h:1206
SkMatrix & setIdentity()
Definition: SkMatrix.h:626
static const SkMatrix & I()
Definition: SkMatrix.cpp:1544
SkMatrix & preTranslate(SkScalar dx, SkScalar dy)
Definition: SkMatrix.cpp:263
void mapRectScaleTranslate(SkRect *dst, const SkRect &src) const
Definition: SkMatrix.cpp:1128
static SkMatrix MakeRectToRect(const SkRect &src, const SkRect &dst, ScaleToFit stf)
Definition: SkMatrix.h:1172
bool isFinite() const
Definition: SkMatrix.h:1834
bool mapRect(SkRect *dst, const SkRect &src, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
Definition: SkMatrix.cpp:1141
Definition: SkMesh.h:263
bool onDoSaveBehind(const SkRect *) override
Definition: SkCanvas.cpp:2830
SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec &rec) override
Definition: SkCanvas.cpp:2825
bool resetForNextPicture(const SkIRect &bounds)
Definition: SkDevice.cpp:526
static bool Overwrites(const SkPaint *paint, ShaderOverrideOpacity)
Definition: SkPaintPriv.cpp:83
@ kNone_ShaderOverrideOpacity
there is no overriding shader (bitmap or image)
Definition: SkPaintPriv.h:22
@ kOpaque_ShaderOverrideOpacity
the overriding shader is opaque
Definition: SkPaintPriv.h:23
@ kNotOpaque_ShaderOverrideOpacity
the overriding shader may not be opaque
Definition: SkPaintPriv.h:24
void setStyle(Style style)
Definition: SkPaint.cpp:105
void setAntiAlias(bool aa)
Definition: SkPaint.h:170
void setImageFilter(sk_sp< SkImageFilter > imageFilter)
const SkRect & computeFastBounds(const SkRect &orig, SkRect *storage) const
Definition: SkPaint.cpp:213
SkColorFilter * getColorFilter() const
Definition: SkPaint.h:426
@ 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 setMaskFilter(sk_sp< SkMaskFilter > maskFilter)
bool nothingToDraw() const
Definition: SkPaint.cpp:273
SkMaskFilter * getMaskFilter() const
Definition: SkPaint.h:534
void setShader(sk_sp< SkShader > shader)
void setPathEffect(sk_sp< SkPathEffect > pathEffect)
float getAlphaf() const
Definition: SkPaint.h:261
SkBlender * getBlender() const
Definition: SkPaint.h:480
SkImageFilter * getImageFilter() const
Definition: SkPaint.h:564
void setAlphaf(float a)
Definition: SkPaint.cpp:130
Definition: SkPath.h:59
const SkRect & getBounds() const
Definition: SkPath.cpp:430
virtual SkRect cullRect() const =0
virtual void playback(SkCanvas *canvas, AbortCallback *callback=nullptr) const =0
virtual int approximateOpCount(bool nested=false) const =0
size_t rowBytes() const
Definition: SkPixmap.h:145
const SkImageInfo & info() const
Definition: SkPixmap.h:135
void * writable_addr() const
Definition: SkPixmap.h:483
const void * addr() const
Definition: SkPixmap.h:153
bool isOval() const
Definition: SkRRect.h:85
static SkRRect MakeOval(const SkRect &oval)
Definition: SkRRect.h:162
static SkRRect MakeRect(const SkRect &r)
Definition: SkRRect.h:149
void setOval(const SkRect &oval)
Definition: SkRRect.cpp:30
bool isRect() const
Definition: SkRRect.h:84
bool isEmpty() const
Definition: SkRRect.h:83
void setRectXY(const SkRect &rect, SkScalar xRad, SkScalar yRad)
Definition: SkRRect.cpp:52
const SkRect & getBounds() const
Definition: SkRRect.h:279
static std::unique_ptr< SkCanvas > MakeCanvas(std::unique_ptr< SkRasterHandleAllocator >, const SkImageInfo &, const Rec *rec=nullptr, const SkSurfaceProps *props=nullptr)
Definition: SkCanvas.cpp:2871
virtual bool allocHandle(const SkImageInfo &, Rec *)=0
void translate(int dx, int dy)
Definition: SkRegion.h:349
bool setEmpty()
Definition: SkRegion.cpp:185
@ kIntersect_Op
target intersected with operand
Definition: SkRegion.h:368
@ kDifference_Op
target minus operand
Definition: SkRegion.h:367
bool isRect() const
Definition: SkRegion.h:152
const SkIRect & getBounds() const
Definition: SkRegion.h:165
bool isEmpty() const
Definition: SkRegion.h:146
constexpr bool empty() const
Definition: SkSpan_impl.h:96
SkPixelGeometry pixelGeometry() const
ContentChangeMode
Definition: SkSurface.h:203
@ kDiscard_ContentChangeMode
discards surface on change
Definition: SkSurface.h:204
@ kRetain_ContentChangeMode
preserves surface on change
Definition: SkSurface.h:205
const SkRect & bounds() const
Definition: SkTextBlob.h:53
SkVertices::VertexMode mode() const
bool hasTexCoords() const
const SkRect & bounds() const
Definition: SkVertices.h:98
@ kTriangleFan_VertexMode
Definition: SkVertices.h:33
SkVerticesPriv priv()
T * get() const
Definition: SkRefCnt.h:303
static FilterResult MakeFromImage(const Context &ctx, sk_sp< SkImage > image, SkRect srcRect, ParameterSpace< SkRect > dstRect, const SkSamplingOptions &sampling)
void outset(const LayerSpace< SkISize > &delta)
LayerSpace< SkIRect > relevantSubset(const LayerSpace< SkIRect > dstRect, SkTileMode) const
LayerSpace< SkRect > mapRect(const LayerSpace< SkRect > &r) const
bool inverseMapRect(const LayerSpace< SkRect > &r, LayerSpace< SkRect > *out) const
const SkMatrix & deviceToLayer() const
const SkMatrix & layerToDevice() const
bool decomposeCTM(const SkMatrix &ctm, const SkImageFilter *filter, const skif::ParameterSpace< SkPoint > &representativePt)
const SkMatrix & layerMatrix() const
LayerSpace< T > paramToLayer(const ParameterSpace< T > &paramGeometry) const
bool adjustLayerSpace(const SkMatrix &layer)
auto empty() const -> decltype(fGlyphRuns.empty())
Definition: GlyphRun.h:125
SkRect sourceBoundsWithOrigin() const
Definition: GlyphRun.h:116
virtual SkRect sourceBoundsWithOrigin() const =0
const Paint & paint
Definition: color_source.cc:38
DlColor color
VkDevice device
Definition: main.cc:53
SkBitmap source
Definition: examples.cpp:28
float SkScalar
Definition: extension.cpp:12
FlutterSemanticsFlag flags
if(end==-1)
uint8_t value
GAsyncResult * result
static float max(float r, float g, float b)
Definition: hsl.cpp:49
static float min(float r, float g, float b)
Definition: hsl.cpp:48
std::u16string text
double y
double x
sk_sp< const SkImage > atlas
Definition: SkRecords.h:331
unsigned useCenter Optional< SkMatrix > matrix
Definition: SkRecords.h:258
Optional< SkRect > bounds
Definition: SkRecords.h:189
PODArray< SkPoint > dstClips
Definition: SkRecords.h:364
sk_sp< const SkImage > image
Definition: SkRecords.h:269
ClipOpAndAA opAA SkRegion region
Definition: SkRecords.h:238
sk_sp< const SkPicture > picture
Definition: SkRecords.h:299
SkRRect rrect
Definition: SkRecords.h:232
SkRect oval
Definition: SkRecords.h:249
PODArray< SkRSXform > xforms
Definition: SkRecords.h:332
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
PODArray< SkMatrix > preViewMatrices
Definition: SkRecords.h:365
SkScalar startAngle
Definition: SkRecords.h:250
SkScalar sweepAngle
Definition: SkRecords.h:251
SkMesh mesh
Definition: SkRecords.h:345
PODArray< SkColor > colors
Definition: SkRecords.h:276
SkSamplingOptions sampling
Definition: SkRecords.h:337
skia_private::AutoTArray< sk_sp< SkImageFilter > > filters TypedMatrix matrix TypedMatrix matrix SkScalar dx
Definition: SkRecords.h:208
SK_API sk_sp< SkShader > Empty()
Definition: bitmap.py:1
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
font
Font Metadata and Metrics.
dst
Definition: cp.py:12
dictionary stats
Definition: malisc.py:20
sh
Definition: run_sh.py:10
string root
Definition: scale_cpu.py:20
SkSamplingOptions(SkFilterMode::kLinear))
Definition: ref_ptr.h:256
SkScalar w
SkScalar h
int32_t height
int32_t width
sk_sp< SkImageFilter > fFilter
Definition: SkCanvas.cpp:556
FilterToSpan(const SkImageFilter *filter)
Definition: SkCanvas.cpp:550
Definition: SkMD5.cpp:134
static SkArc Make(const SkRect &oval, SkScalar startAngleDegrees, SkScalar sweepAngleDegrees, Type type)
Definition: SkArc.h:38
ImageSetEntry & operator=(const ImageSetEntry &)
int fYCount
number of y-coordinates
Definition: SkCanvas.h:1617
const SkIRect * fBounds
source bounds to draw from
Definition: SkCanvas.h:1618
const int * fYDivs
y-axis values dividing bitmap
Definition: SkCanvas.h:1614
int fXCount
number of x-coordinates
Definition: SkCanvas.h:1616
const RectType * fRectTypes
array of fill types
Definition: SkCanvas.h:1615
const SkColor * fColors
array of colors
Definition: SkCanvas.h:1619
const int * fXDivs
x-axis values dividing bitmap
Definition: SkCanvas.h:1613
const SkPaint * fPaint
Definition: SkCanvas.h:743
constexpr int32_t y() const
Definition: SkPoint_impl.h:52
constexpr int32_t x() const
Definition: SkPoint_impl.h:46
Definition: SkRect.h:32
SkIRect makeOutset(int32_t dx, int32_t dy) const
Definition: SkRect.h:350
bool intersect(const SkIRect &r)
Definition: SkRect.h:513
constexpr SkISize size() const
Definition: SkRect.h:172
static constexpr SkIRect MakeSize(const SkISize &size)
Definition: SkRect.h:66
static constexpr SkIRect MakeEmpty()
Definition: SkRect.h:45
void setEmpty()
Definition: SkRect.h:242
static constexpr SkIRect MakeWH(int32_t w, int32_t h)
Definition: SkRect.h:56
bool isEmpty() const
Definition: SkRect.h:202
constexpr SkIPoint topLeft() const
Definition: SkRect.h:151
static constexpr SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h)
Definition: SkRect.h:104
SkIRect makeInset(int32_t dx, int32_t dy) const
Definition: SkRect.h:332
Definition: SkSize.h:16
bool isEmpty() const
Definition: SkSize.h:31
static constexpr SkISize Make(int32_t w, int32_t h)
Definition: SkSize.h:20
const SkColorInfo & colorInfo() const
Definition: SkImageInfo.h:404
sk_sp< SkColorSpace > refColorSpace() const
SkIRect bounds() const
Definition: SkImageInfo.h:427
SkISize dimensions() const
Definition: SkImageInfo.h:421
int width() const
Definition: SkImageInfo.h:365
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
int height() const
Definition: SkImageInfo.h:371
void set(float x, float y)
Definition: SkPoint_impl.h:200
void(* fReleaseProc)(void *pixels, void *ctx)
SkRect makeSorted() const
Definition: SkRect.h:1330
static SkRect Make(const SkISize &size)
Definition: SkRect.h:669
static constexpr SkRect MakeEmpty()
Definition: SkRect.h:595
constexpr SkRect makeOffset(float dx, float dy) const
Definition: SkRect.h:965
bool isFinite() const
Definition: SkRect.h:711
void joinPossiblyEmptyRect(const SkRect &r)
Definition: SkRect.h:1174
static SkRect MakeIWH(int w, int h)
Definition: SkRect.h:623
void outset(float dx, float dy)
Definition: SkRect.h:1077
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition: SkRect.h:659
bool intersects(const SkRect &r) const
Definition: SkRect.h:1121
bool contains(SkScalar x, SkScalar y) const
Definition: extension.cpp:19
void roundOut(SkIRect *dst) const
Definition: SkRect.h:1241
void round(SkIRect *dst) const
Definition: SkRect.h:1228
constexpr float height() const
Definition: SkRect.h:769
void setLTRB(float left, float top, float right, float bottom)
Definition: SkRect.h:865
constexpr float width() const
Definition: SkRect.h:762
bool isEmpty() const
Definition: SkRect.h:693
static constexpr SkRect MakeWH(float w, float h)
Definition: SkRect.h:609
bool isSorted() const
Definition: SkRect.h:705
const SkFilterMode filter
const SkMipmapMode mipmap
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:131