Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Classes | Public Types | Public Member Functions | Static Public Member Functions | Static Public Attributes | Friends | List of all members
skif::FilterResult Class Reference

#include <SkImageFilterTypes.h>

Classes

class  AutoSurface
 
class  Builder
 

Public Types

enum class  ShaderFlags : int { kNone = 0 , kSampledRepeatedly = 1 << 0 , kNonTrivialSampling = 1 << 1 }
 

Public Member Functions

 FilterResult ()
 
 FilterResult (sk_sp< SkSpecialImage > image)
 
 FilterResult (sk_sp< SkSpecialImage > image, const LayerSpace< SkIPoint > &origin)
 
 operator bool () const
 
const SkSpecialImageimage () const
 
sk_sp< SkSpecialImagerefImage () const
 
LayerSpace< SkIRectlayerBounds () const
 
SkTileMode tileMode () const
 
SkSamplingOptions sampling () const
 
const SkColorFiltercolorFilter () const
 
FilterResult applyCrop (const Context &ctx, const LayerSpace< SkIRect > &crop, SkTileMode tileMode=SkTileMode::kDecal) const
 
FilterResult applyTransform (const Context &ctx, const LayerSpace< SkMatrix > &transform, const SkSamplingOptions &sampling) const
 
FilterResult applyColorFilter (const Context &ctx, sk_sp< SkColorFilter > colorFilter) const
 
sk_sp< SkSpecialImageimageAndOffset (const Context &ctx, SkIPoint *offset) const
 
std::pair< sk_sp< SkSpecialImage >, LayerSpace< SkIPoint > > imageAndOffset (const Context &ctx) const
 
void draw (const Context &ctx, SkDevice *target, const SkBlender *blender) const
 
FilterResult insetForSaveLayer () const
 

Static Public Member Functions

static FilterResult MakeFromPicture (const Context &ctx, sk_sp< SkPicture > pic, ParameterSpace< SkRect > cullRect)
 
static FilterResult MakeFromShader (const Context &ctx, sk_sp< SkShader > shader, bool dither)
 
static FilterResult MakeFromImage (const Context &ctx, sk_sp< SkImage > image, SkRect srcRect, ParameterSpace< SkRect > dstRect, const SkSamplingOptions &sampling)
 

Static Public Attributes

static constexpr SkSamplingOptions kDefaultSampling {SkFilterMode::kLinear}
 

Friends

class ::FilterResultTestAccess
 

Detailed Description

Definition at line 695 of file SkImageFilterTypes.h.

Member Enumeration Documentation

◆ ShaderFlags

enum class skif::FilterResult::ShaderFlags : int
strong
Enumerator
kNone 
kSampledRepeatedly 
kNonTrivialSampling 

Definition at line 799 of file SkImageFilterTypes.h.

799 : int {
800 kNone = 0,
801 // A hint that the input FilterResult will be sampled repeatedly per pixel. If there's
802 // colorspace conversions or deferred color filtering, it's worth resolving to a temporary
803 // image so that those calculations are performed once per pixel instead of N times.
804 kSampledRepeatedly = 1 << 0,
805 // Specifies that the shader performs non-trivial operations on its coordinates to determine
806 // how to sample any input FilterResults, so their sampling options should not be converted
807 // to nearest-neighbor even if they appeared pixel-aligned with the output surface.
808 kNonTrivialSampling = 1 << 1,
809 // TODO: Add option to convey that the output can carry input tiling forward to make a
810 // smaller backing surface somehow. May not be a flag and just args passed to eval().
811 };

Constructor & Destructor Documentation

◆ FilterResult() [1/3]

skif::FilterResult::FilterResult ( )
inline

Definition at line 697 of file SkImageFilterTypes.h.

◆ FilterResult() [2/3]

skif::FilterResult::FilterResult ( sk_sp< SkSpecialImage image)
inlineexplicit

Definition at line 699 of file SkImageFilterTypes.h.

700 : FilterResult(std::move(image), LayerSpace<SkIPoint>({0, 0})) {}
const SkSpecialImage * image() const

◆ FilterResult() [3/3]

skif::FilterResult::FilterResult ( sk_sp< SkSpecialImage image,
const LayerSpace< SkIPoint > &  origin 
)
inline

Definition at line 702 of file SkImageFilterTypes.h.

703 : FilterResult(std::move(image), origin, PixelBoundary::kUnknown) {}

Member Function Documentation

◆ applyColorFilter()

FilterResult skif::FilterResult::applyColorFilter ( const Context ctx,
sk_sp< SkColorFilter colorFilter 
) const

Definition at line 918 of file SkImageFilterTypes.cpp.

919 {
920 // A null filter is the identity, so it should have been caught during image filter DAG creation
922
923 if (ctx.desiredOutput().isEmpty()) {
924 return {};
925 }
926
927 // Color filters are applied after the transform and image sampling, but before the fLayerBounds
928 // crop. We can compose 'colorFilter' with any previously applied color filter regardless
929 // of the transform/sample state, so long as it respects the effect of the current crop.
930 LayerSpace<SkIRect> newLayerBounds = fLayerBounds;
931 if (as_CFB(colorFilter)->affectsTransparentBlack()) {
932 if (!fImage || !newLayerBounds.intersect(ctx.desiredOutput())) {
933 // The current image's intersection with the desired output is fully transparent, but
934 // the new color filter converts that into a non-transparent color. The desired output
935 // is filled with this color, but use a 1x1 surface and clamp tiling.
936 AutoSurface surface{ctx,
937 LayerSpace<SkIRect>{SkIRect::MakeXYWH(ctx.desiredOutput().left(),
938 ctx.desiredOutput().top(),
939 1, 1)},
940 PixelBoundary::kInitialized,
941 /*renderInParameterSpace=*/false};
942 if (surface) {
944 paint.setColor4f(SkColors::kTransparent, /*colorSpace=*/nullptr);
945 paint.setColorFilter(std::move(colorFilter));
946 surface->drawPaint(paint);
947 }
948 FilterResult solidColor = surface.snap();
949 solidColor.updateTileMode(ctx, SkTileMode::kClamp);
950 return solidColor;
951 }
952
953 if (this->analyzeBounds(ctx.desiredOutput()) & BoundsAnalysis::kRequiresLayerCrop) {
954 // Since 'colorFilter' modifies transparent black, the new result's layer bounds must
955 // be the desired output. But if the current image is cropped we need to resolve the
956 // image to avoid losing the effect of the current 'fLayerBounds'.
957 newLayerBounds.outset(LayerSpace<SkISize>({1, 1}));
958 SkAssertResult(newLayerBounds.intersect(ctx.desiredOutput()));
959 FilterResult filtered = this->resolve(ctx, newLayerBounds,
960 /*preserveDstBounds=*/true);
961 filtered.fColorFilter = std::move(colorFilter);
962 filtered.updateTileMode(ctx, SkTileMode::kClamp);
963 return filtered;
964 }
965
966 // otherwise we can fill out to the desired output without worrying about losing the crop.
967 newLayerBounds = ctx.desiredOutput();
968 } else {
969 if (!fImage || !LayerSpace<SkIRect>::Intersects(newLayerBounds, ctx.desiredOutput())) {
970 // The color filter does not modify transparent black, so it remains transparent
971 return {};
972 }
973 // otherwise a non-transparent affecting color filter can always be lifted before any crop
974 // because it does not change the "shape" of the prior FilterResult.
975 }
976
977 // If we got here we can compose the new color filter with the previous filter and the prior
978 // layer bounds are either soft-cropped to the desired output, or we fill out the desired output
979 // when the new color filter affects transparent black. We don't check if the entire composed
980 // filter affects transparent black because earlier floods are restricted by the layer bounds.
981 FilterResult filtered = *this;
982 filtered.fLayerBounds = newLayerBounds;
983 filtered.fColorFilter = SkColorFilters::Compose(std::move(colorFilter), fColorFilter);
984 return filtered;
985}
#define SkAssertResult(cond)
Definition SkAssert.h:123
#define SkASSERT(cond)
Definition SkAssert.h:116
static SkColorFilterBase * as_CFB(SkColorFilter *filter)
static sk_sp< SkColorFilter > Compose(const sk_sp< SkColorFilter > &outer, sk_sp< SkColorFilter > inner)
const SkColorFilter * colorFilter() const
const Paint & paint
VkSurfaceKHR surface
Definition main.cc:49
constexpr SkColor4f kTransparent
Definition SkColor.h:434
filtered(names, to_skip)
Definition zip_utils.py:20
static constexpr SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h)
Definition SkRect.h:104

◆ applyCrop()

FilterResult skif::FilterResult::applyCrop ( const Context ctx,
const LayerSpace< SkIRect > &  crop,
SkTileMode  tileMode = SkTileMode::kDecal 
) const

Definition at line 821 of file SkImageFilterTypes.cpp.

823 {
824 static const LayerSpace<SkMatrix> kIdentity{SkMatrix::I()};
825
826 if (crop.isEmpty() || ctx.desiredOutput().isEmpty()) {
827 // An empty crop cannot be anything other than fully transparent
828 return {};
829 }
830
831 // First, determine how this image's layer bounds interact with the crop rect, which determines
832 // the portion of 'crop' that could have non-transparent content.
833 LayerSpace<SkIRect> cropContent = crop;
834 if (!fImage ||
835 !cropContent.intersect(fLayerBounds)) {
836 // The pixels within 'crop' would be fully transparent, and tiling won't change that.
837 return {};
838 }
839
840 // Second, determine the subset of 'crop' that is relevant to ctx.desiredOutput().
841 LayerSpace<SkIRect> fittedCrop = crop.relevantSubset(ctx.desiredOutput(), tileMode);
842
843 // Third, check if there's overlap with the known non-transparent cropped content and what's
844 // used to tile the desired output. If not, the image is known to be empty. This modifies
845 // 'cropContent' and not 'fittedCrop' so that any transparent padding remains if we have to
846 // apply repeat/mirror tiling to the original geometry.
847 if (!cropContent.intersect(fittedCrop)) {
848 return {};
849 }
850
851 // Fourth, a periodic tiling that covers the output with a single instance of the image can be
852 // simplified to just a transform.
853 auto periodicTransform = periodic_axis_transform(tileMode, fittedCrop, ctx.desiredOutput());
854 if (periodicTransform) {
855 return this->applyTransform(ctx, *periodicTransform, FilterResult::kDefaultSampling);
856 }
857
858 bool preserveTransparencyInCrop = false;
860 // We can reduce the crop dimensions to what's non-transparent
861 fittedCrop = cropContent;
862 } else if (fittedCrop.contains(ctx.desiredOutput())) {
864 fittedCrop = ctx.desiredOutput();
865 } else if (!cropContent.contains(fittedCrop)) {
866 // There is transparency in fittedCrop that must be resolved in order to maintain the new
867 // tiling geometry.
868 preserveTransparencyInCrop = true;
869 if (fTileMode == SkTileMode::kDecal && tileMode == SkTileMode::kClamp) {
870 // include 1px buffer for transparency from original kDecal tiling
871 cropContent.outset(skif::LayerSpace<SkISize>({1, 1}));
872 SkAssertResult(fittedCrop.intersect(cropContent));
873 }
874 } // Otherwise cropContent == fittedCrop
875
876 // Fifth, when the transform is an integer translation, any prior tiling and the new tiling
877 // can sometimes be addressed analytically without producing a new image. Moving the crop into
878 // the image dimensions allows future operations like applying a transform or color filter to
879 // be composed without rendering a new image since there will not be an intervening crop.
880 const bool doubleClamp = fTileMode == SkTileMode::kClamp && tileMode == SkTileMode::kClamp;
881 LayerSpace<SkIPoint> origin;
882 if (!preserveTransparencyInCrop &&
883 is_nearly_integer_translation(fTransform, &origin) &&
884 (doubleClamp ||
885 !(this->analyzeBounds(fittedCrop) & BoundsAnalysis::kHasLayerFillingEffect))) {
886 // Since the transform is axis-aligned, the tile mode can be applied to the original
887 // image pre-transformation and still be consistent with the 'crop' geometry. When the
888 // original tile mode is decal, extract_subset is always valid. When the original mode is
889 // mirror/repeat, !kHasLayerFillingEffect ensures that 'fittedCrop' is contained within
890 // the base image bounds, so extract_subset is valid. When the original mode is clamp
891 // and the new mode is not clamp, that is also the case. When both modes are clamp, we have
892 // to consider how 'fittedCrop' intersects (or doesn't) with the base image bounds.
893 FilterResult restrictedOutput = this->subset(origin, fittedCrop, doubleClamp);
894 restrictedOutput.updateTileMode(ctx, tileMode);
895 if (restrictedOutput.fBoundary == PixelBoundary::kInitialized ||
897 // Discard kInitialized since a crop is a strict constraint on sampling outside of it.
898 // But preserve (kTransparent+kDecal) if this is a no-op crop.
899 restrictedOutput.fBoundary = PixelBoundary::kUnknown;
900 }
901 return restrictedOutput;
902 } else if (tileMode == SkTileMode::kDecal) {
903 // A decal crop can always be applied as the final operation by adjusting layer bounds, and
904 // does not modify any prior tile mode.
905 SkASSERT(!preserveTransparencyInCrop);
906 FilterResult restrictedOutput = *this;
907 restrictedOutput.fLayerBounds = fittedCrop;
908 return restrictedOutput;
909 } else {
910 // There is a non-trivial transform to the image data that must be applied before the
911 // non-decal tilemode is meant to be applied to the axis-aligned 'crop'.
912 FilterResult tiled = this->resolve(ctx, fittedCrop, /*preserveDstBounds=*/true);
913 tiled.updateTileMode(ctx, tileMode);
914 return tiled;
915 }
916}
static const SkMatrix & I()
static constexpr SkSamplingOptions kDefaultSampling
SkTileMode tileMode() const
FilterResult applyTransform(const Context &ctx, const LayerSpace< SkMatrix > &transform, const SkSamplingOptions &sampling) const
constexpr std::array< float, 9 > kIdentity

◆ applyTransform()

FilterResult skif::FilterResult::applyTransform ( const Context ctx,
const LayerSpace< SkMatrix > &  transform,
const SkSamplingOptions sampling 
) const

Definition at line 1041 of file SkImageFilterTypes.cpp.

1043 {
1044 if (!fImage || ctx.desiredOutput().isEmpty()) {
1045 // Transformed transparent black remains transparent black.
1046 SkASSERT(!fColorFilter);
1047 return {};
1048 }
1049
1050 // Extract the sampling options that matter based on the current and next transforms.
1051 // We make sure the new sampling is bilerp (default) if the new transform doesn't matter
1052 // (and assert that the current is bilerp if its transform didn't matter). Bilerp can be
1053 // maximally combined, so simplifies the logic in compatible_sampling().
1054 const bool currentXformIsInteger = is_nearly_integer_translation(fTransform);
1055 const bool nextXformIsInteger = is_nearly_integer_translation(transform);
1056
1057 SkASSERT(!currentXformIsInteger || fSamplingOptions == kDefaultSampling);
1058 SkSamplingOptions nextSampling = nextXformIsInteger ? kDefaultSampling : sampling;
1059
1060 // Determine if the image is being visibly cropped by the layer bounds, in which case we can't
1061 // merge this transform with any previous transform (unless the new transform is an integer
1062 // translation in which case any visible edge is aligned with the desired output and can be
1063 // resolved by intersecting the transformed layer bounds and the output bounds).
1064 bool isCropped = !nextXformIsInteger &&
1065 (this->analyzeBounds(SkMatrix(transform), SkIRect(ctx.desiredOutput()))
1066 & BoundsAnalysis::kRequiresLayerCrop);
1067
1068 FilterResult transformed;
1069 if (!isCropped && compatible_sampling(fSamplingOptions, currentXformIsInteger,
1070 &nextSampling, nextXformIsInteger)) {
1071 // We can concat transforms and 'nextSampling' will be either fSamplingOptions,
1072 // sampling, or a merged combination depending on the two transforms in play.
1073 transformed = *this;
1074 } else {
1075 // We'll have to resolve this FilterResult first before 'transform' and 'sampling' can be
1076 // correctly evaluated. 'nextSampling' will always be 'sampling'.
1077 LayerSpace<SkIRect> tightBounds;
1078 if (transform.inverseMapRect(ctx.desiredOutput(), &tightBounds)) {
1079 transformed = this->resolve(ctx, tightBounds);
1080 }
1081
1082 if (!transformed.fImage) {
1083 // Transform not invertible or resolve failed to create an image
1084 return {};
1085 }
1086 }
1087
1088 transformed.fSamplingOptions = nextSampling;
1089 transformed.fTransform.postConcat(transform);
1090 // Rebuild the layer bounds and then restrict to the current desired output. The original value
1091 // of fLayerBounds includes the image mapped by the original fTransform as well as any
1092 // accumulated soft crops from desired outputs of prior stages. To prevent discarding that info,
1093 // we map fLayerBounds by the additional transform, instead of re-mapping the image bounds.
1094 transformed.fLayerBounds = transform.mapRect(transformed.fLayerBounds);
1095 if (!LayerSpace<SkIRect>::Intersects(transformed.fLayerBounds, ctx.desiredOutput())) {
1096 // The transformed output doesn't touch the desired, so it would just be transparent black.
1097 return {};
1098 }
1099
1100 return transformed;
1101}
SkSamplingOptions sampling() const
static bool compatible_sampling(const SkSamplingOptions &currentSampling, bool currentXformWontAffectNearest, SkSamplingOptions *nextSampling, bool nextXformWontAffectNearest)
static SkColor4f transform(SkColor4f c, SkColorSpace *src, SkColorSpace *dst)
Definition p3.cpp:47

◆ colorFilter()

const SkColorFilter * skif::FilterResult::colorFilter ( ) const
inline

Definition at line 747 of file SkImageFilterTypes.h.

747{ return fColorFilter.get(); }
T * get() const
Definition SkRefCnt.h:303

◆ draw()

void skif::FilterResult::draw ( const Context ctx,
SkDevice target,
const SkBlender blender 
) const

Definition at line 1183 of file SkImageFilterTypes.cpp.

1183 {
1184 SkAutoDeviceTransformRestore adtr{target, ctx.mapping().layerToDevice()};
1185 this->draw(ctx, target, /*preserveDeviceState=*/true, blender);
1186}
void draw(const Context &ctx, SkDevice *target, const SkBlender *blender) const
uint32_t * target

◆ image()

const SkSpecialImage * skif::FilterResult::image ( ) const
inline

Definition at line 739 of file SkImageFilterTypes.h.

739{ return fImage.get(); }

◆ imageAndOffset() [1/2]

std::pair< sk_sp< SkSpecialImage >, LayerSpace< SkIPoint > > skif::FilterResult::imageAndOffset ( const Context ctx) const

Definition at line 627 of file SkImageFilterTypes.cpp.

628 {
629 FilterResult resolved = this->resolve(ctx, ctx.desiredOutput());
630 return {resolved.fImage, resolved.layerBounds().topLeft()};
631}

◆ imageAndOffset() [2/2]

sk_sp< SkSpecialImage > skif::FilterResult::imageAndOffset ( const Context ctx,
SkIPoint offset 
) const

Definition at line 621 of file SkImageFilterTypes.cpp.

621 {
622 auto [image, origin] = this->imageAndOffset(ctx);
623 *offset = SkIPoint(origin);
624 return image;
625}
sk_sp< SkSpecialImage > imageAndOffset(const Context &ctx, SkIPoint *offset) const
Point offset

◆ insetForSaveLayer()

FilterResult skif::FilterResult::insetForSaveLayer ( ) const

Definition at line 633 of file SkImageFilterTypes.cpp.

633 {
634 if (!fImage) {
635 return {};
636 }
637
638 // SkCanvas processing should have prepared a decal-tiled image before calling this.
639 SkASSERT(fTileMode == SkTileMode::kDecal);
640
641 // PixelBoundary tracking assumes the special image's subset does not include the padding, so
642 // inset by a single pixel.
643 FilterResult inset = this->insetByPixel();
644 // Trust that SkCanvas configured the layer's SkDevice to ensure the padding remained
645 // transparent. Upgrading this pixel boundary knowledge allows the source image to use the
646 // simpler clamp math (vs. decal math) when used in a shader context.
647 SkASSERT(inset.fBoundary == PixelBoundary::kInitialized &&
648 inset.fTileMode == SkTileMode::kDecal);
649 inset.fBoundary = PixelBoundary::kTransparent;
650 return inset;
651}
static SkRect inset(const SkRect &r)

◆ layerBounds()

LayerSpace< SkIRect > skif::FilterResult::layerBounds ( ) const
inline

Definition at line 743 of file SkImageFilterTypes.h.

743{ return fLayerBounds; }

◆ MakeFromImage()

FilterResult skif::FilterResult::MakeFromImage ( const Context ctx,
sk_sp< SkImage image,
SkRect  srcRect,
ParameterSpace< SkRect dstRect,
const SkSamplingOptions sampling 
)
static

Definition at line 1703 of file SkImageFilterTypes.cpp.

1707 {
1708 SkASSERT(image);
1709
1710 SkRect imageBounds = SkRect::Make(image->dimensions());
1711 if (!imageBounds.contains(srcRect)) {
1712 SkMatrix srcToDst = SkMatrix::RectToRect(srcRect, SkRect(dstRect));
1713 if (!srcRect.intersect(imageBounds)) {
1714 return {}; // No overlap, so return an empty/transparent image
1715 }
1716 // Adjust dstRect to match the updated srcRect
1717 dstRect = ParameterSpace<SkRect>{srcToDst.mapRect(srcRect)};
1718 }
1719
1720 if (SkRect(dstRect).isEmpty()) {
1721 return {}; // Output collapses to empty
1722 }
1723
1724 // Check for direct conversion to an SkSpecialImage and then FilterResult. Eventually this
1725 // whole function should be replaceable with:
1726 // FilterResult(fImage, fSrcRect, fDstRect).applyTransform(mapping.layerMatrix(), fSampling);
1727 SkIRect srcSubset = RoundOut(srcRect);
1728 if (SkRect::Make(srcSubset) == srcRect) {
1729 // Construct an SkSpecialImage from the subset directly instead of drawing.
1730 sk_sp<SkSpecialImage> specialImage = ctx.backend()->makeImage(srcSubset, std::move(image));
1731
1732 // Treat the srcRect's top left as "layer" space since we are folding the src->dst transform
1733 // and the param->layer transform into a single transform step. We don't override the
1734 // PixelBoundary from kUnknown even if srcRect is contained within the 'image' because the
1735 // client could be doing their own external approximate-fit texturing.
1736 skif::FilterResult subset{std::move(specialImage),
1737 skif::LayerSpace<SkIPoint>(srcSubset.topLeft())};
1738 SkMatrix transform = SkMatrix::Concat(ctx.mapping().layerMatrix(),
1739 SkMatrix::RectToRect(srcRect, SkRect(dstRect)));
1741 }
1742
1743 // For now, draw the src->dst subset of image into a new image.
1744 LayerSpace<SkIRect> dstBounds = ctx.mapping().paramToLayer(dstRect).roundOut();
1745 if (!dstBounds.intersect(ctx.desiredOutput())) {
1746 return {};
1747 }
1748
1749 AutoSurface surface{ctx, dstBounds, PixelBoundary::kTransparent,
1750 /*renderInParameterSpace=*/true};
1751 if (surface) {
1752 SkPaint paint;
1753 paint.setAntiAlias(true);
1754 surface->drawImageRect(std::move(image), srcRect, SkRect(dstRect), sampling, &paint,
1756 }
1757 return surface.snap();
1758}
@ kStrict_SrcRectConstraint
sample only inside bounds; slower
Definition SkCanvas.h:1542
static SkMatrix RectToRect(const SkRect &src, const SkRect &dst, ScaleToFit mode=kFill_ScaleToFit)
Definition SkMatrix.h:157
static SkMatrix Concat(const SkMatrix &a, const SkMatrix &b)
Definition SkMatrix.h:1775
bool mapRect(SkRect *dst, const SkRect &src, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
SkISize dimensions() const
SkIRect RoundOut(SkRect r)
constexpr SkIPoint topLeft() const
Definition SkRect.h:151
static SkRect Make(const SkISize &size)
Definition SkRect.h:669
bool intersect(const SkRect &r)
Definition SkRect.cpp:114
bool contains(SkScalar x, SkScalar y) const
Definition extension.cpp:19

◆ MakeFromPicture()

FilterResult skif::FilterResult::MakeFromPicture ( const Context ctx,
sk_sp< SkPicture pic,
ParameterSpace< SkRect cullRect 
)
static

Definition at line 1663 of file SkImageFilterTypes.cpp.

1665 {
1666 SkASSERT(pic);
1667 LayerSpace<SkIRect> dstBounds = ctx.mapping().paramToLayer(cullRect).roundOut();
1668 if (!dstBounds.intersect(ctx.desiredOutput())) {
1669 return {};
1670 }
1671
1672 // Given the standard usage of the picture image filter (i.e., to render content at a fixed
1673 // resolution that, most likely, differs from the screen's) disable LCD text by removing any
1674 // knowledge of the pixel geometry.
1675 // TODO: Should we just generally do this for layers with image filters? Or can we preserve it
1676 // for layers that are still axis-aligned?
1677 SkSurfaceProps props = ctx.backend()->surfaceProps()
1678 .cloneWithPixelGeometry(kUnknown_SkPixelGeometry);
1679 AutoSurface surface{ctx, dstBounds, PixelBoundary::kTransparent,
1680 /*renderInParameterSpace=*/true, &props};
1681 if (surface) {
1682 surface->clipRect(SkRect(cullRect));
1683 surface->drawPicture(std::move(pic));
1684 }
1685 return surface.snap();
1686}
@ kUnknown_SkPixelGeometry

◆ MakeFromShader()

FilterResult skif::FilterResult::MakeFromShader ( const Context ctx,
sk_sp< SkShader shader,
bool  dither 
)
static

Definition at line 1688 of file SkImageFilterTypes.cpp.

1690 {
1691 SkASSERT(shader);
1692 AutoSurface surface{ctx, ctx.desiredOutput(), PixelBoundary::kTransparent,
1693 /*renderInParameterSpace=*/true};
1694 if (surface) {
1695 SkPaint paint;
1696 paint.setShader(shader);
1697 paint.setDither(dither);
1698 surface->drawPaint(paint);
1699 }
1700 return surface.snap();
1701}

◆ operator bool()

skif::FilterResult::operator bool ( ) const
inlineexplicit

Definition at line 734 of file SkImageFilterTypes.h.

734{ return SkToBool(fImage); }
static constexpr bool SkToBool(const T &x)
Definition SkTo.h:35

◆ refImage()

sk_sp< SkSpecialImage > skif::FilterResult::refImage ( ) const
inline

Definition at line 740 of file SkImageFilterTypes.h.

740{ return fImage; }

◆ sampling()

SkSamplingOptions skif::FilterResult::sampling ( ) const
inline

Definition at line 745 of file SkImageFilterTypes.h.

745{ return fSamplingOptions; }

◆ tileMode()

SkTileMode skif::FilterResult::tileMode ( ) const
inline

Definition at line 744 of file SkImageFilterTypes.h.

744{ return fTileMode; }

Friends And Related Symbol Documentation

◆ ::FilterResultTestAccess

friend class ::FilterResultTestAccess
friend

Definition at line 815 of file SkImageFilterTypes.h.

Member Data Documentation

◆ kDefaultSampling

constexpr SkSamplingOptions skif::FilterResult::kDefaultSampling {SkFilterMode::kLinear}
staticconstexpr

Definition at line 732 of file SkImageFilterTypes.h.


The documentation for this class was generated from the following files: