Flutter Engine
The Flutter Engine
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 };
@ kNone
Definition: layer.h:53

Constructor & Destructor Documentation

◆ FilterResult() [1/3]

skif::FilterResult::FilterResult ( )
inline

Definition at line 697 of file SkImageFilterTypes.h.

697: FilterResult(nullptr) {}

◆ 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 917 of file SkImageFilterTypes.cpp.

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

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

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

◆ 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 1182 of file SkImageFilterTypes.cpp.

1182 {
1183 SkAutoDeviceTransformRestore adtr{target, ctx.mapping().layerToDevice()};
1184 this->draw(ctx, target, /*preserveDeviceState=*/true, blender);
1185}
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 624 of file SkImageFilterTypes.cpp.

625 {
626 FilterResult resolved = this->resolve(ctx, ctx.desiredOutput());
627 return {resolved.fImage, resolved.layerBounds().topLeft()};
628}

◆ imageAndOffset() [2/2]

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

Definition at line 618 of file SkImageFilterTypes.cpp.

618 {
619 auto [image, origin] = this->imageAndOffset(ctx);
620 *offset = SkIPoint(origin);
621 return image;
622}
sk_sp< SkSpecialImage > imageAndOffset(const Context &ctx, SkIPoint *offset) const
SeparatedVector2 offset

◆ insetForSaveLayer()

FilterResult skif::FilterResult::insetForSaveLayer ( ) const

Definition at line 630 of file SkImageFilterTypes.cpp.

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

1899 {
1900 SkASSERT(image);
1901
1902 SkRect imageBounds = SkRect::Make(image->dimensions());
1903 if (!imageBounds.contains(srcRect)) {
1904 SkMatrix srcToDst = SkMatrix::RectToRect(srcRect, SkRect(dstRect));
1905 if (!srcRect.intersect(imageBounds)) {
1906 return {}; // No overlap, so return an empty/transparent image
1907 }
1908 // Adjust dstRect to match the updated srcRect
1909 dstRect = ParameterSpace<SkRect>{srcToDst.mapRect(srcRect)};
1910 }
1911
1912 if (SkRect(dstRect).isEmpty()) {
1913 return {}; // Output collapses to empty
1914 }
1915
1916 // Check for direct conversion to an SkSpecialImage and then FilterResult. Eventually this
1917 // whole function should be replaceable with:
1918 // FilterResult(fImage, fSrcRect, fDstRect).applyTransform(mapping.layerMatrix(), fSampling);
1919 SkIRect srcSubset = RoundOut(srcRect);
1920 if (SkRect::Make(srcSubset) == srcRect) {
1921 // Construct an SkSpecialImage from the subset directly instead of drawing.
1922 sk_sp<SkSpecialImage> specialImage = ctx.backend()->makeImage(srcSubset, std::move(image));
1923
1924 // Treat the srcRect's top left as "layer" space since we are folding the src->dst transform
1925 // and the param->layer transform into a single transform step. We don't override the
1926 // PixelBoundary from kUnknown even if srcRect is contained within the 'image' because the
1927 // client could be doing their own external approximate-fit texturing.
1928 skif::FilterResult subset{std::move(specialImage),
1929 skif::LayerSpace<SkIPoint>(srcSubset.topLeft())};
1930 SkMatrix transform = SkMatrix::Concat(ctx.mapping().layerMatrix(),
1931 SkMatrix::RectToRect(srcRect, SkRect(dstRect)));
1933 }
1934
1935 // For now, draw the src->dst subset of image into a new image.
1936 LayerSpace<SkIRect> dstBounds = ctx.mapping().paramToLayer(dstRect).roundOut();
1937 if (!dstBounds.intersect(ctx.desiredOutput())) {
1938 return {};
1939 }
1940
1941 AutoSurface surface{ctx, dstBounds, PixelBoundary::kTransparent,
1942 /*renderInParameterSpace=*/true};
1943 if (surface) {
1944 SkPaint paint;
1945 paint.setAntiAlias(true);
1946 surface->drawImageRect(std::move(image), srcRect, SkRect(dstRect), sampling, &paint,
1948 }
1949 return surface.snap();
1950}
@ 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
Definition: SkMatrix.cpp:1141
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 1849 of file SkImageFilterTypes.cpp.

1851 {
1852 SkASSERT(pic);
1853 LayerSpace<SkIRect> dstBounds = ctx.mapping().paramToLayer(cullRect).roundOut();
1854 if (!dstBounds.intersect(ctx.desiredOutput())) {
1855 return {};
1856 }
1857
1858 // Given the standard usage of the picture image filter (i.e., to render content at a fixed
1859 // resolution that, most likely, differs from the screen's) disable LCD text by removing any
1860 // knowledge of the pixel geometry.
1861 // TODO: Should we just generally do this for layers with image filters? Or can we preserve it
1862 // for layers that are still axis-aligned?
1863 SkSurfaceProps props = ctx.backend()->surfaceProps()
1864 .cloneWithPixelGeometry(kUnknown_SkPixelGeometry);
1865 // TODO(b/329700315): The SkPicture may contain dithered content, which would be affected by any
1866 // boundary padding. Until we can control the dither origin, force it to have no padding.
1867 AutoSurface surface{ctx, dstBounds, PixelBoundary::kUnknown,
1868 /*renderInParameterSpace=*/true, &props};
1869 if (surface) {
1870 surface->clipRect(SkRect(cullRect));
1871 surface->drawPicture(std::move(pic));
1872 }
1873 return surface.snap();
1874}
@ kUnknown_SkPixelGeometry

◆ MakeFromShader()

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

Definition at line 1876 of file SkImageFilterTypes.cpp.

1878 {
1879 SkASSERT(shader);
1880
1881 // TODO(b/329700315): Using a boundary other than unknown shifts the origin of dithering, which
1882 // complicates layout test validation in chrome. Until we can control the dither origin,
1883 // force dithered shader FilterResults to have no padding.
1884 PixelBoundary boundary = dither ? PixelBoundary::kUnknown : PixelBoundary::kTransparent;
1885 AutoSurface surface{ctx, ctx.desiredOutput(), boundary, /*renderInParameterSpace=*/true};
1886 if (surface) {
1887 SkPaint paint;
1888 paint.setShader(shader);
1889 paint.setDither(dither);
1890 surface->drawPaint(paint);
1891 }
1892 return surface.snap();
1893}

◆ 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 Function 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: