53static constexpr float kRoundEpsilon = 1e-3f;
55std::pair<bool, bool> are_axes_nearly_integer_aligned(
const LayerSpace<SkMatrix>& m,
56 LayerSpace<SkIPoint>* out=
nullptr) {
66 return {
false,
false};
75 if (out && xAxis && yAxis) {
76 *
out = LayerSpace<SkIPoint>({(
int) tx, (
int) ty});
78 return {xAxis, yAxis};
86bool is_nearly_integer_translation(
const LayerSpace<SkMatrix>& m,
87 LayerSpace<SkIPoint>* out=
nullptr) {
88 auto [axisX, axisY] = are_axes_nearly_integer_aligned(m, out);
89 return axisX && axisY;
114std::optional<LayerSpace<SkMatrix>> periodic_axis_transform(
116 const LayerSpace<SkIRect>& crop,
117 const LayerSpace<SkIRect>& output) {
125 double cropL = (double) crop.left();
126 double cropT = (double) crop.top();
127 double cropWidth = crop.right() - cropL;
128 double cropHeight = crop.bottom() - cropT;
136 if (periodR - periodL <= 1 && periodB - periodT <= 1) {
147 if (periodL % 2 != 0) {
151 if (periodT % 2 != 0) {
153 ty = cropHeight - ty;
158 tx += periodL * cropWidth + cropL;
159 ty += periodT * cropHeight + cropT;
170 return LayerSpace<SkMatrix>(periodicTransform);
178class RasterBackend :
public Backend {
190 std::move(colorSpace));
195 return SkSpecialImages::MakeFromRaster(subset,
image, this->surfaceProps());
202 const SkBlurEngine* getBlurEngine()
const override {
return nullptr; }
212 : fCache(
std::move(cache))
213 , fSurfaceProps(surfaceProps)
224 return sk_make_sp<RasterBackend>(surfaceProps,
colorType);
229 " # visited filters: %d\n"
230 " # cache hits: %d\n"
231 " # offscreen surfaces: %d\n"
232 " # shader-clamped draws: %d\n"
233 " # shader-tiled draws: %d\n",
272 decompose_transform(ctm,
SkPoint(representativePt), &remainder, &layer);
276 if (!remainder.
invert(&invRemainder)) {
283 fParamToLayerMatrix = layer;
284 fLayerToDevMatrix = remainder;
285 fDevToLayerMatrix = invRemainder;
301 if (!layer.
invert(&invLayer)) {
326 if (
matrix.isScaleTranslate()) {
327 double l = (double)
matrix.getScaleX()*geom.
fLeft + (double)
matrix.getTranslateX();
329 double t = (double)
matrix.getScaleY()*geom.
fTop + (double)
matrix.getTranslateY();
350 matrix.mapPoints(&p, &geom, 1);
355Vector Mapping::map<Vector>(
const Vector& geom,
const SkMatrix& matrix) {
362IVector Mapping::map<IVector>(
const IVector& geom,
const SkMatrix& matrix) {
373 if (
matrix.isScaleTranslate()) {
413 if (!fittedSrc.intersect(dstRect)) {
480 if (rect.isEmpty()) {
484 }
else if (fData.isScaleTranslate()) {
486 if (fData.getScaleX() == 0.f || fData.getScaleY() == 0.f) {
489 double l = (rect.left() - (double)fData.getTranslateX()) / (
double)fData.getScaleX();
490 double r = (rect.right() - (double)fData.getTranslateX()) / (
double)fData.getScaleX();
491 double t = (rect.top() - (double)fData.getTranslateY()) / (
double)fData.getScaleY();
492 double b = (rect.bottom() - (double)fData.getTranslateY()) / (
double)fData.getScaleY();
529 [[maybe_unused]] PixelBoundary boundary,
530 bool renderInParameterSpace,
532 : fDstBounds(dstBounds)
533#
if defined(SK_DONT_PAD_LAYER_IMAGES)
534 , fBoundary(PixelBoundary::kUnknown) {
536 , fBoundary(boundary) {
543 if (!dstBounds.isEmpty()) {
558 fCanvas.emplace(std::move(
device));
559 fCanvas->translate(-fDstBounds.
left(), -fDstBounds.
top());
561 if (fBoundary == PixelBoundary::kTransparent) {
564 fCanvas->clipIRect(
SkIRect(dstBounds));
569 fCanvas->clipIRect(
SkIRect(fDstBounds));
572 if (renderInParameterSpace) {
577 explicit operator bool()
const {
return fCanvas.has_value(); }
583 if (fCanvas.has_value()) {
586 fCanvas->restoreToCount(0);
594 if (
image && fBoundary != PixelBoundary::kUnknown) {
596 const int padding = this->padding();
599 fDstBounds.
top() + padding}};
603 return {
image, fDstBounds.
topLeft(), PixelBoundary::kUnknown};
611 int padding()
const {
return fBoundary == PixelBoundary::kUnknown ? 0 : 1; }
613 std::optional<SkCanvas> fCanvas;
615 PixelBoundary fBoundary;
649 inset.fBoundary = PixelBoundary::kTransparent;
656 auto insetBounds = fLayerBounds;
660 return this->subset(fLayerBounds.topLeft(), insetBounds);
666 BoundsScope scope)
const {
668 static constexpr float kHalfPixel = 0.5f;
669 static constexpr float kCubicRadius = 1.5f;
684 bool requireLayerCrop = fillsLayerBounds;
685 if (!fillsLayerBounds) {
686 LayerSpace<SkIRect> imageBounds =
687 fTransform.mapRect(LayerSpace<SkIRect>{fImage->dimensions()});
688 requireLayerCrop = !fLayerBounds.contains(imageBounds);
691 if (requireLayerCrop) {
692 analysis |= BoundsAnalysis::kRequiresLayerCrop;
695 SkIRect layerBoundsInDst = Mapping::map(
SkIRect(fLayerBounds), xtraTransform);
713 LayerSpace<SkMatrix> netTransform = fTransform;
714 netTransform.postConcat(LayerSpace<SkMatrix>(xtraTransform));
717 const auto [xAxisAligned, yAxisAligned] = are_axes_nearly_integer_aligned(netTransform);
718 const bool isPixelAligned = xAxisAligned && yAxisAligned;
726 const float sampleRadius = fSamplingOptions.useCubic ? kCubicRadius : kHalfPixel;
727 SkRect safeImageBounds = imageBounds.
makeInset(sampleRadius, sampleRadius);
734 safeImageBounds.
inset(xAxisAligned ? 0.f : kRoundEpsilon,
735 yAxisAligned ? 0.f : kRoundEpsilon);
737 bool hasPixelPadding = fBoundary != PixelBoundary::kUnknown;
740 decalLeaks ? safeImageBounds : imageBounds,
743 analysis |= BoundsAnalysis::kDstBoundsNotCovered;
744 if (fillsLayerBounds) {
745 analysis |= BoundsAnalysis::kHasLayerFillingEffect;
751 float scaleFactors[2];
752 if (!(
SkMatrix(netTransform).getMinMaxScales(scaleFactors) &&
755 analysis |= BoundsAnalysis::kRequiresDecalInLayerSpace;
756 if (fBoundary == PixelBoundary::kTransparent) {
759 hasPixelPadding =
false;
765 if (scope == BoundsScope::kDeferred) {
767 }
else if (scope == BoundsScope::kCanDrawDirectly &&
768 !(analysis & BoundsAnalysis::kHasLayerFillingEffect)) {
773 if (nnOrBilerp && (hasPixelPadding || isPixelAligned)) {
782 if (hasPixelPadding) {
783 safeImageBounds.
outset(1.f, 1.f);
785 pixelCenterBounds.
inset(kHalfPixel, kHalfPixel);
793 if (!
all(edgeMask)) {
797 fImage->subset().fRight == fImage->backingStoreDimensions().fWidth,
798 fImage->subset().fBottom == fImage->backingStoreDimensions().fHeight,
799 fImage->subset().fLeft == 0};
802 hwEdge = hwEdge & skvx::shuffle<2,3,0,1>(hwEdge);
804 if (!
all(edgeMask | hwEdge)) {
805 analysis |= BoundsAnalysis::kRequiresShaderTiling;
816 fLayerBounds = ctx.desiredOutput();
835 !cropContent.intersect(fLayerBounds)) {
847 if (!cropContent.intersect(fittedCrop)) {
854 if (periodicTransform) {
858 bool preserveTransparencyInCrop =
false;
861 fittedCrop = cropContent;
865 }
else if (!cropContent.contains(fittedCrop)) {
868 preserveTransparencyInCrop =
true;
882 if (!preserveTransparencyInCrop &&
883 is_nearly_integer_translation(fTransform, &origin) &&
885 !(this->analyzeBounds(fittedCrop) & BoundsAnalysis::kHasLayerFillingEffect))) {
893 FilterResult restrictedOutput = this->subset(origin, fittedCrop, doubleClamp);
894 restrictedOutput.updateTileMode(ctx,
tileMode);
895 if (restrictedOutput.fBoundary == PixelBoundary::kInitialized ||
899 restrictedOutput.fBoundary = PixelBoundary::kUnknown;
901 return restrictedOutput;
905 SkASSERT(!preserveTransparencyInCrop);
907 restrictedOutput.fLayerBounds = fittedCrop;
908 return restrictedOutput;
912 FilterResult tiled = this->resolve(ctx, fittedCrop,
true);
913 tiled.updateTileMode(ctx,
tileMode);
932 if (!fImage || !newLayerBounds.intersect(ctx.
desiredOutput())) {
940 PixelBoundary::kInitialized,
953 if (this->analyzeBounds(ctx.
desiredOutput()) & BoundsAnalysis::kRequiresLayerCrop) {
959 FilterResult filtered = this->resolve(ctx, newLayerBounds,
982 filtered.fLayerBounds = newLayerBounds;
988 bool currentXformWontAffectNearest,
990 bool nextXformWontAffectNearest) {
1005 *nextSampling = currentSampling;
1016 *nextSampling = currentSampling;
1032 *nextSampling = currentSampling;
1054 const bool currentXformIsInteger = is_nearly_integer_translation(fTransform);
1055 const bool nextXformIsInteger = is_nearly_integer_translation(
transform);
1064 bool isCropped = !nextXformIsInteger &&
1066 & BoundsAnalysis::kRequiresLayerCrop);
1070 &nextSampling, nextXformIsInteger)) {
1073 transformed = *
this;
1079 transformed = this->resolve(ctx, tightBounds);
1082 if (!transformed.fImage) {
1088 transformed.fSamplingOptions = nextSampling;
1089 transformed.fTransform.postConcat(
transform);
1094 transformed.fLayerBounds =
transform.mapRect(transformed.fLayerBounds);
1105 bool preserveDstBounds)
const {
1109 if (!fImage || (!preserveDstBounds && !dstBounds.intersect(fLayerBounds))) {
1110 return {
nullptr, {}};
1114 const bool subsetCompatible = !fColorFilter &&
1120 LayerSpace<SkIPoint> origin;
1121 if (subsetCompatible && is_nearly_integer_translation(fTransform, &origin)) {
1122 return this->subset(origin, dstBounds);
1127 PixelBoundary boundary = preserveDstBounds ? PixelBoundary::kUnknown
1128 : PixelBoundary::kTransparent;
1136FilterResult FilterResult::subset(
const LayerSpace<SkIPoint>& knownOrigin,
1137 const LayerSpace<SkIRect>& subsetBounds,
1138 bool clampSrcIfDisjoint)
const {
1140 SkASSERT(is_nearly_integer_translation(fTransform, &actualOrigin) &&
1144 LayerSpace<SkIRect> imageBounds(
SkIRect::MakeXYWH(knownOrigin.x(), knownOrigin.y(),
1145 fImage->width(), fImage->height()));
1146 imageBounds = imageBounds.relevantSubset(subsetBounds, clampSrcIfDisjoint ?
SkTileMode::kClamp
1155 SkIRect subset = { imageBounds.
left() - knownOrigin.x(),
1156 imageBounds.
top() - knownOrigin.y(),
1157 imageBounds.
right() - knownOrigin.x(),
1158 imageBounds.
bottom() - knownOrigin.y() };
1160 subset.
fRight <= fImage->width() && subset.
fBottom <= fImage->height());
1163 result.fColorFilter = fColorFilter;
1168 if (fImage->subset() ==
result.fImage->subset()) {
1169 result.fBoundary = fBoundary;
1172 SkIRect safeSubset = fImage->subset();
1173 if (fBoundary == PixelBoundary::kUnknown) {
1174 safeSubset.
inset(1, 1);
1177 result.fBoundary = PixelBoundary::kInitialized;
1190 bool preserveDeviceState,
1195 if (blendAffectsTransparentBlack) {
1204 BoundsScope scope = blendAffectsTransparentBlack ? BoundsScope::kShaderOnly
1205 : BoundsScope::kCanDrawDirectly;
1210 if (analysis & BoundsAnalysis::kRequiresLayerCrop) {
1211 if (blendAffectsTransparentBlack) {
1218 LayerSpace<SkIRect> dstBounds;
1225 clipped.draw(ctx,
device, preserveDeviceState, blender);
1229 if (preserveDeviceState) {
1240 const bool pixelAligned =
1241 is_nearly_integer_translation(fTransform) &&
1248 if (analysis & BoundsAnalysis::kHasLayerFillingEffect ||
1249 (blendAffectsTransparentBlack && (analysis & BoundsAnalysis::kDstBoundsNotCovered))) {
1255 paint.setShader(this->getAnalyzedShaderView(ctx,
sampling, analysis));
1258 this->drawAnalyzedImage(ctx,
device,
sampling, analysis, blender);
1261 if (preserveDeviceState && (analysis & BoundsAnalysis::kRequiresLayerCrop)) {
1266void FilterResult::drawAnalyzedImage(
const Context& ctx,
1271 SkASSERT(!(analysis & BoundsAnalysis::kHasLayerFillingEffect));
1275 paint.setColorFilter(fColorFilter);
1284 if (this->canClampToTransparentBoundary(analysis) && fSamplingOptions ==
kDefaultSampling) {
1285 SkASSERT(!(analysis & BoundsAnalysis::kRequiresShaderTiling));
1292 paint.setAntiAlias(
true);
1294 if (analysis & BoundsAnalysis::kRequiresShaderTiling) {
1305 const LayerSpace<SkIRect>& sampleBounds)
const {
1315 const bool currentXformIsInteger = is_nearly_integer_translation(fTransform);
1320 BoundsScope::kShaderOnly);
1323 const bool needsResolve =
1327 ((fColorFilter && (!fColorFilter->asAColorMode(
nullptr, &colorFilterMode) ||
1334 (analysis & BoundsAnalysis::kRequiresLayerCrop);
1338 (needsResolve || currentXformIsInteger)) {
1346 FilterResult resolved = this->resolve(ctx, sampleBounds);
1354 BoundsAnalysis::kDstBoundsNotCovered | BoundsAnalysis::kRequiresShaderTiling;
1355 analysis = resolved.analyzeBounds(sampleBounds, BoundsScope::kShaderOnly);
1356 SkASSERT(!(analysis & ~kExpectedAnalysis));
1357 return resolved.getAnalyzedShaderView(ctx,
sampling, analysis);
1360 shader = this->getAnalyzedShaderView(ctx,
sampling, analysis);
1370 const SkMatrix& localMatrix(fTransform);
1377 if (localMatrix.rectStaysRect() ||
1378 !(analysis & BoundsAnalysis::kRequiresDecalInLayerSpace)) {
1380 preDecal = localMatrix;
1382 decompose_transform(localMatrix, imageBounds.
center(), &postDecal, &preDecal);
1390 const bool decalClampToTransparent = this->canClampToTransparentBoundary(analysis);
1391 const bool strict =
SkToBool(analysis & BoundsAnalysis::kRequiresShaderTiling);
1394 if (strict && decalClampToTransparent) {
1402 if (!(analysis & BoundsAnalysis::kDstBoundsNotCovered) ||
1403 (analysis & BoundsAnalysis::kRequiresDecalInLayerSpace)) {
1406 imageShader = fImage->asShader(effectiveTileMode, finalSampling, preDecal, strict);
1409 ctx.markShaderBasedTilingRequired(effectiveTileMode);
1412 if (analysis & BoundsAnalysis::kRequiresDecalInLayerSpace) {
1424 builder.child(
"image") = std::move(imageShader);
1427 imageShader =
builder.makeShader();
1430 if (imageShader && (analysis & BoundsAnalysis::kRequiresDecalInLayerSpace)) {
1431 imageShader = imageShader->makeWithLocalMatrix(postDecal);
1434 if (imageShader && fColorFilter) {
1435 imageShader = imageShader->makeWithColorFilter(fColorFilter);
1455 static constexpr float kMultiPassLimit = 0.8f;
1456 static constexpr float kNearIdentityLimit = 1.f - kRoundEpsilon;
1458 float finalStepScale = netScaleFactor * (1 << (steps - 1));
1459 float limit = steps == 1 ? kNearIdentityLimit : kMultiPassLimit;
1460 if (finalStepScale >= limit) {
1470template <
typename T>
1475 bool enforceDecal)
const {
1477 if (!fImage || !visibleLayerBounds.intersect(ctx.
desiredOutput()) ||
1478 scale.width() <= 0.f ||
scale.height() <= 0.f) {
1487 const bool pixelAligned = is_nearly_integer_translation(fTransform, &origin);
1489 BoundsScope::kShaderOnly);
1494 const bool canDeferTiling =
1496 !(analysis & BoundsAnalysis::kRequiresLayerCrop) &&
1497 !(enforceDecal && (analysis & BoundsAnalysis::kHasLayerFillingEffect));
1499 const bool hasEffectsToApply =
1505 if (xSteps == 0 && ySteps == 0 && !hasEffectsToApply) {
1506 if (analysis & BoundsAnalysis::kHasLayerFillingEffect) {
1510 noop.fLayerBounds = visibleLayerBounds;
1514 return this->subset(origin, visibleLayerBounds);
1520 if (canDeferTiling && (analysis & BoundsAnalysis::kHasLayerFillingEffect)) {
1524 fImage->width(), fImage->height()));
1530 srcRect = visibleLayerBounds;
1535 if (srcRect.isEmpty()) {
1553 while(!
image || xSteps > 0 || ySteps > 0) {
1556 sx = xSteps > 1 ? 0.5f : srcRect.width()*
scale.width() / stepBoundsF.width();
1562 sy = ySteps > 1 ? 0.5f : srcRect.height()*
scale.height() / stepBoundsF.height();
1567 stepBoundsF.height() * sy)};
1575 float srcFracX = stepPixelBounds.right() - stepBoundsF.right() - 0.5f;
1576 float dstFracX = dstPixelBounds.right() - dstBoundsF.right() - 0.5f;
1579 float srcFracY = stepPixelBounds.bottom() - stepBoundsF.bottom() - 0.5f;
1580 float dstFracY = dstPixelBounds.bottom() - dstBoundsF.bottom() - 0.5f;
1588 SkASSERT(sx != 1.f || dstPixelBounds.width() == stepPixelBounds.width());
1589 SkASSERT(sy != 1.f || dstPixelBounds.height() == stepPixelBounds.height());
1594 AutoSurface
surface{ctx, dstPixelBounds, PixelBoundary::kUnknown,
1606 analysis = this->analyzeBounds(
SkMatrix(scaleXform),
SkIRect(dstPixelBounds),
1607 BoundsScope::kShaderOnly);
1608 analysis &= ~BoundsAnalysis::kRequiresDecalInLayerSpace;
1609 paint.setShader(this->getAnalyzedShaderView(ctx, fSamplingOptions, analysis));
1635 image = snapped.fImage;
1636 origin = snapped.fLayerBounds.
topLeft();
1637 stepBoundsF = dstBoundsF;
1638 stepPixelBounds = dstPixelBounds;
1644 result.fTransform.postConcat(
1646 result.fLayerBounds = visibleLayerBounds;
1683 surface->drawPicture(std::move(pic));
1696 paint.setShader(shader);
1697 paint.setDither(dither);
1711 if (!imageBounds.
contains(srcRect)) {
1720 if (
SkRect(dstRect).isEmpty()) {
1753 paint.setAntiAlias(
true);
1768 bool evaluateInParameterSpace) {
1771 if (evaluateInParameterSpace) {
1784 fInputShaders.reserve(fInputs.size());
1785 for (
const SampledFilterResult& input : fInputs) {
1788 auto sampleBounds = input.fSampleBounds ? *input.fSampleBounds : outputBounds;
1789 auto shader = input.fImage.asShader(
fContext,
1791 input.fFlags | xtraFlags,
1793 if (evaluateInParameterSpace && shader) {
1794 shader = shader->makeWithLocalMatrix(layerToParam);
1796 fInputShaders.push_back(std::move(shader));
1801LayerSpace<SkIRect> FilterResult::Builder::outputBounds(
1802 std::optional<LayerSpace<SkIRect>> explicitOutput)
const {
1805 if (explicitOutput.has_value()) {
1807 if (!
output.intersect(*explicitOutput)) {
1808 return LayerSpace<SkIRect>::Empty();
1815 const LayerSpace<SkIRect>& outputBounds,
1816 bool evaluateInParameterSpace)
const {
1822 AutoSurface
surface{
fContext, outputBounds, PixelBoundary::kTransparent,
1823 evaluateInParameterSpace};
1826 paint.setShader(std::move(shader));
1836 if (fInputs.size() == 1) {
1837 SkASSERT(!fInputs[0].fSampleBounds.has_value() &&
1840 return fInputs[0].fImage;
1844 (
int) fInputs.size(),
1845 [
this](
int i) { return fInputs[i].fImage.layerBounds(); });
1846 const auto outputBounds = this->outputBounds(mergedBounds);
1851 for (
const SampledFilterResult& input : fInputs) {
1852 SkASSERT(!input.fSampleBounds.has_value() &&
1882 auto maxOutput = fInputs[0].fImage.layerBounds();
1883 maxOutput.outset(radii);
1889 const auto outputBounds = this->outputBounds(maxOutput);
1890 if (outputBounds.isEmpty()) {
1897 auto sampleBounds = outputBounds;
1898 sampleBounds.outset(radii);
1916 auto srcRelativeOutput = outputBounds;
1923 outputBounds.topLeft()};
static SkM44 inv(const SkM44 &m)
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
#define SkAssertResult(cond)
@ kLastCoeffMode
last porter duff blend mode
SkBlenderBase * as_BB(SkBlender *blend)
static SkColorFilterBase * as_CFB(SkColorFilter *filter)
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
#define sk_float_ceil2int(x)
#define sk_double_floor2int(x)
static bool SkIsFinite(T x, Pack... values)
#define sk_double_ceil2int(x)
static constexpr int sk_double_saturate2int(double x)
static constexpr float sk_ieee_float_divide(float numer, float denom)
static SkImageFilter_Base * as_IFB(SkImageFilter *filter)
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)
static int SkNextLog2(uint32_t value)
sk_sp< T > sk_ref_sp(T *obj)
#define SkScalarInvert(x)
static bool SkScalarNearlyZero(SkScalar x, SkScalar tolerance=SK_ScalarNearlyZero)
static bool SkScalarNearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance=SK_ScalarNearlyZero)
#define SkScalarRoundToInt(x)
#define SkScalarCeilToInt(x)
#define SkScalarRoundToScalar(x)
#define SkScalarFloorToInt(x)
@ kUnknown_SkPixelGeometry
static constexpr bool SkToBool(const T &x)
#define TRACE_EVENT_SCOPE_THREAD
Type::kYUV Type::kRGBA() int(0.7 *637)
static sk_sp< SkBitmapDevice > Create(const SkImageInfo &, const SkSurfaceProps &, SkRasterHandleAllocator *=nullptr)
bool affectsTransparentBlack() const
virtual float maxSigma() const =0
virtual sk_sp< SkSpecialImage > blur(SkSize sigma, sk_sp< SkSpecialImage > src, const SkIRect &srcRect, SkTileMode tileMode, const SkIRect &dstRect) const =0
virtual const Algorithm * findAlgorithm(SkSize sigma, SkColorType colorType) const =0
static SkDevice * TopDevice(const SkCanvas *canvas)
@ kStrict_SrcRectConstraint
sample only inside bounds; slower
@ kFast_SrcRectConstraint
sample outside bounds; faster
bool affectsTransparentBlack() const
static sk_sp< SkColorFilter > Compose(const sk_sp< SkColorFilter > &outer, sk_sp< SkColorFilter > inner)
static bool Equals(const SkColorSpace *, const SkColorSpace *)
virtual void setImmutable()
virtual void popClipStack()=0
virtual void pushClipStack()=0
const SkMatrix & localToDevice() const
virtual sk_sp< SkSpecialImage > snapSpecial(const SkIRect &subset, bool forceCopy=false)
virtual void drawSpecial(SkSpecialImage *, const SkMatrix &localToDevice, const SkSamplingOptions &, const SkPaint &, SkCanvas::SrcRectConstraint constraint=SkCanvas::kStrict_SrcRectConstraint)
virtual SkIRect devClipBounds() const =0
virtual void clipRect(const SkRect &rect, SkClipOp op, bool aa)=0
virtual void drawPaint(const SkPaint &paint)=0
SkM44 & postConcat(const SkM44 &m)
static SkScalar DifferentialAreaScale(const SkMatrix &m, const SkPoint &p)
static bool InverseMapRect(const SkMatrix &mx, SkRect *dst, const SkRect &src)
static SkMatrix Scale(SkScalar sx, SkScalar sy)
static SkMatrix RectToRect(const SkRect &src, const SkRect &dst, ScaleToFit mode=kFill_ScaleToFit)
SkMatrix & postConcat(const SkMatrix &other)
static SkMatrix Translate(SkScalar dx, SkScalar dy)
void setScaleTranslate(SkScalar sx, SkScalar sy, SkScalar tx, SkScalar ty)
static SkMatrix Concat(const SkMatrix &a, const SkMatrix &b)
bool invert(SkMatrix *inverse) const
static const SkMatrix & I()
SkMatrix & preTranslate(SkScalar dx, SkScalar dy)
SkMatrix & preConcat(const SkMatrix &other)
bool isScaleTranslate() const
SkMatrix & preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
bool mapRect(SkRect *dst, const SkRect &src, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
void setColor4f(const SkColor4f &color, SkColorSpace *colorSpace=nullptr)
void setBlender(sk_sp< SkBlender > blender)
static skvx::int4 QuadContainsRectMask(const SkM44 &m, const SkRect &a, const SkRect &b, float tol=0.f)
static SkIRect ClosestDisjointEdge(const SkIRect &src, const SkIRect &dst)
static bool QuadContainsRect(const SkMatrix &m, const SkIRect &a, const SkIRect &b, float tol=0.f)
sk_sp< SkSpecialImage > makeSubset(const SkIRect &subset) const
SkISize dimensions() const
virtual sk_sp< SkShader > asShader(SkTileMode, const SkSamplingOptions &, const SkMatrix &lm, bool strict=true) const
SkSurfaceProps cloneWithPixelGeometry(SkPixelGeometry newPixelGeometry) const
const SkSurfaceProps & surfaceProps() const
SkColorType colorType() const
virtual sk_sp< SkSpecialImage > makeImage(const SkIRect &subset, sk_sp< SkImage > image) const =0
Backend(sk_sp< SkImageFilterCache > cache, const SkSurfaceProps &surfaceProps, const SkColorType colorType)
virtual sk_sp< SkDevice > makeDevice(SkISize size, sk_sp< SkColorSpace >, const SkSurfaceProps *props=nullptr) const =0
const Backend * backend() const
void markNewSurface() const
void markShaderBasedTilingRequired(SkTileMode tileMode) const
SkColorSpace * colorSpace() const
sk_sp< SkColorSpace > refColorSpace() const
const LayerSpace< SkIRect > & desiredOutput() const
const Mapping & mapping() const
AutoSurface(const Context &ctx, const LayerSpace< SkIRect > &dstBounds, PixelBoundary boundary, bool renderInParameterSpace, const SkSurfaceProps *props=nullptr)
Builder(const Context &context)
FilterResult blur(const LayerSpace< SkSize > &sigma)
FilterResult applyColorFilter(const Context &ctx, sk_sp< SkColorFilter > colorFilter) const
FilterResult applyCrop(const Context &ctx, const LayerSpace< SkIRect > &crop, SkTileMode tileMode=SkTileMode::kDecal) const
FilterResult insetForSaveLayer() const
static FilterResult MakeFromPicture(const Context &ctx, sk_sp< SkPicture > pic, ParameterSpace< SkRect > cullRect)
void draw(const Context &ctx, SkDevice *target, const SkBlender *blender) const
sk_sp< SkSpecialImage > imageAndOffset(const Context &ctx, SkIPoint *offset) const
static FilterResult MakeFromImage(const Context &ctx, sk_sp< SkImage > image, SkRect srcRect, ParameterSpace< SkRect > dstRect, const SkSamplingOptions &sampling)
const SkSpecialImage * image() const
const SkColorFilter * colorFilter() const
SkSamplingOptions sampling() const
LayerSpace< SkIRect > layerBounds() const
static constexpr SkSamplingOptions kDefaultSampling
SkTileMode tileMode() const
static FilterResult MakeFromShader(const Context &ctx, sk_sp< SkShader > shader, bool dither)
FilterResult applyTransform(const Context &ctx, const LayerSpace< SkMatrix > &transform, const SkSamplingOptions &sampling) const
LayerSpace< SkIPoint > topLeft() const
void outset(const LayerSpace< SkISize > &delta)
LayerSpace< SkISize > size() 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 > ¶mGeometry) const
bool adjustLayerSpace(const SkMatrix &layer)
FlutterSemanticsFlag flags
const GrXPFactory * Get(SkBlendMode mode)
constexpr SkColor4f kTransparent
SK_API sk_sp< SkImage > RasterFromBitmap(const SkBitmap &bitmap)
const SkRuntimeEffect * GetKnownRuntimeEffect(StableKey stableKey)
unsigned useCenter Optional< SkMatrix > matrix
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
SkIRect RoundOut(SkRect r)
sk_sp< Backend > MakeRasterBackend(const SkSurfaceProps &surfaceProps, SkColorType colorType)
static int downscale_step_count(float netScaleFactor)
static bool compatible_sampling(const SkSamplingOptions ¤tSampling, bool currentXformWontAffectNearest, SkSamplingOptions *nextSampling, bool nextXformWontAffectNearest)
SkIRect RoundIn(SkRect r)
SIT bool all(const Vec< 1, T > &x)
static SkColor4f transform(SkColor4f c, SkColorSpace *src, SkColorSpace *dst)
static SkRect inset(const SkRect &r)
static constexpr SkIPoint Make(int32_t x, int32_t y)
void inset(int32_t dx, int32_t dy)
int32_t fBottom
larger y-axis bounds
int32_t fTop
smaller y-axis bounds
static constexpr SkIRect MakeSize(const SkISize &size)
static constexpr SkIRect MakeEmpty()
static constexpr SkIRect MakeWH(int32_t w, int32_t h)
constexpr SkIPoint topLeft() const
static constexpr SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h)
SkIRect makeInset(int32_t dx, int32_t dy) const
int32_t fLeft
smaller x-axis bounds
bool contains(int32_t x, int32_t y) const
int32_t fRight
larger x-axis bounds
static constexpr SkISize Make(int32_t w, int32_t h)
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
static constexpr SkPoint Make(float x, float y)
static SkRect Make(const SkISize &size)
static constexpr SkRect MakeEmpty()
constexpr float left() const
void inset(float dx, float dy)
constexpr float top() const
void roundIn(SkIRect *dst) const
bool intersect(const SkRect &r)
void outset(float dx, float dy)
SkRect makeOutset(float dx, float dy) const
SkRect makeInset(float dx, float dy) const
bool contains(SkScalar x, SkScalar y) const
void roundOut(SkIRect *dst) const
constexpr float right() const
constexpr SkPoint center() const
static constexpr SkRect MakeWH(float w, float h)
constexpr float bottom() const
static constexpr SkSamplingOptions Aniso(int maxAniso)
const SkCubicResampler cubic
const SkFilterMode filter
static constexpr SkSize Make(SkScalar w, SkScalar h)
int fNumShaderClampedDraws
int fNumShaderBasedTilingDraws
int fNumOffscreenSurfaces
int fNumVisitedImageFilters
#define TRACE_EVENT_INSTANT2(category_group, name, arg1_name, arg1_val, arg2_name, arg2_val)
#define TRACE_EVENT_INSTANT1(category_group, name, arg1_name, arg1_val)