46 const std::optional<SkV4>& coefficients,
50 , fBlender(
std::move(blender))
51 , fArithmeticCoefficients(coefficients)
52 , fEnforcePremul(enforcePremul) {
65 friend void ::SkRegisterBlendImageFilterFlattenable();
75 (!fArithmeticCoefficients.has_value() || (*fArithmeticCoefficients)[3] != 0.f);
95 std::optional<SkV4> fArithmeticCoefficients;
103 std::optional<SkV4> coefficients = {},
104 bool enforcePremul =
false) {
116 if (
auto bm =
as_BB(blender)->asBlendMode()) {
118 return cropped(std::move(foreground));
120 return cropped(std::move(background));
128 enforcePremul, inputs)};
129 return cropped(std::move(filter));
139 std::move(background),
140 std::move(foreground),
148 return make_blend(std::move(blender), std::move(background), std::move(foreground), cropRect);
164 return make_blend(std::move(blender),
165 std::move(background),
166 std::move(foreground),
170 SkV4{k1, k2, k3, k4},
180 SkBlendImageFilter::LegacyArithmeticCreateProc);
182 SkBlendImageFilter::LegacyArithmeticCreateProc);
194 for (
int i = 0; i < 4; ++i) {
195 k[i] =
buffer.readScalar();
197 const bool enforcePremul =
buffer.readBool();
206 std::optional<SkV4> coefficients;
207 bool enforcePremul =
false;
210 if (mode == kArithmetic_SkBlendMode) {
214 for (
int i = 0; i < 4; ++i) {
215 k[i] =
buffer.readScalar();
218 enforcePremul =
buffer.readBool();
225 blender =
buffer.readBlender();
233 return make_blend(std::move(blender),
235 common.getInput(kForeground),
243 if (fArithmeticCoefficients.has_value()) {
244 buffer.write32(kArithmetic_SkBlendMode);
246 const SkV4& k = *fArithmeticCoefficients;
251 buffer.writeBool(fEnforcePremul);
252 }
else if (
auto bm =
as_BB(fBlender)->asBlendMode()) {
253 buffer.write32((
unsigned)bm.value());
256 buffer.writeFlattenable(fBlender.get());
268 if (!this->onAffectsTransparentBlack() && !bg && !fg) {
272 if (
auto bm =
as_BB(fBlender)->asBlendMode()) {
292 return SkShaders::Blend(fBlender, std::move(bg), std::move(fg));
313 builder.add(this->getChildOutput(kForeground, inputCtx));
316 return this->makeBlendShader(inputs[
kBackground], inputs[kForeground]);
326 std::optional<skif::LayerSpace<SkIRect>> maxOutput;
327 if (contentBounds && (maxOutput = this->onGetOutputLayerBounds(mapping, *contentBounds))) {
329 requiredInput = *maxOutput;
330 if (!requiredInput.intersect(desiredOutput)) {
337 requiredInput = desiredOutput;
342 this->getChildInputLayerBounds(
kBackground, mapping, requiredInput, contentBounds);
344 this->getChildInputLayerBounds(kForeground, mapping, requiredInput, contentBounds);
346 bgInput.join(fgInput);
350std::optional<skif::LayerSpace<SkIRect>> SkBlendImageFilter::onGetOutputLayerBounds(
365 bool transparentOutsideFG =
false;
366 bool transparentOutsideBG =
false;
367 if (
auto bm =
as_BB(fBlender)->asBlendMode()) {
381 }
else if (fArithmeticCoefficients.has_value()) {
382 [[maybe_unused]]
static constexpr SkV4 kClearCoeff = {0.f, 0.f, 0.f, 0.f};
383 const SkV4& k = *fArithmeticCoefficients;
393 transparentOutsideFG = k[2] == 0.f;
394 transparentOutsideBG = k[1] == 0.f;
402 auto foregroundBounds = this->getChildOutputLayerBounds(kForeground, mapping, contentBounds);
403 auto backgroundBounds = this->getChildOutputLayerBounds(
kBackground, mapping, contentBounds);
404 if (transparentOutsideFG) {
405 if (transparentOutsideBG) {
407 if (!foregroundBounds && backgroundBounds) {
408 foregroundBounds = *backgroundBounds;
409 }
else if (backgroundBounds && !foregroundBounds->intersect(*backgroundBounds)) {
415 return foregroundBounds;
417 if (!transparentOutsideBG) {
419 if (foregroundBounds && backgroundBounds) {
420 backgroundBounds->join(*foregroundBounds);
423 backgroundBounds.reset();
426 return backgroundBounds;
430SkRect SkBlendImageFilter::computeFastBounds(
const SkRect& bounds)
const {
433 bool transparentOutsideFG =
false;
434 bool transparentOutsideBG =
false;
435 if (
auto bm =
as_BB(fBlender)->asBlendMode()) {
445 }
else if (fArithmeticCoefficients.has_value()) {
446 [[maybe_unused]]
static constexpr SkV4 kClearCoeff = {0.f, 0.f, 0.f, 0.f};
447 const SkV4& k = *fArithmeticCoefficients;
457 transparentOutsideFG = k[2] == 0.f;
458 transparentOutsideBG = k[1] == 0.f;
466 SkRect foregroundBounds = this->getInput(kForeground) ?
467 this->getInput(kForeground)->computeFastBounds(bounds) :
bounds;
470 if (transparentOutsideFG) {
471 if (transparentOutsideBG) {
473 if (!foregroundBounds.
intersect(backgroundBounds)) {
477 return foregroundBounds;
479 if (!transparentOutsideBG) {
481 backgroundBounds.
join(foregroundBounds);
483 return backgroundBounds;
void SkRegisterBlendImageFilterFlattenable()
constexpr uint8_t kCustom_SkBlendMode
SK_API bool SkBlendMode_AsCoeff(SkBlendMode mode, SkBlendModeCoeff *src, SkBlendModeCoeff *dst)
@ kSrcOver
r = s + (1-sa)*d
@ kLastMode
last valid value
SkBlenderBase * as_BB(SkBlender *blend)
constexpr SkColor SK_ColorTRANSPARENT
#define SK_FLATTENABLE_HOOKS(type)
#define SK_REGISTER_FLATTENABLE(type)
#define SK_IMAGEFILTER_UNFLATTEN_COMMON(localVar, expectedCount)
static constexpr bool SkToBool(const T &x)
virtual std::optional< SkBlendMode > asBlendMode() const
static sk_sp< SkBlender > Mode(SkBlendMode mode)
static sk_sp< SkBlender > Arithmetic(float k1, float k2, float k3, float k4, bool enforcePremul)
static void Register(const char name[], Factory)
virtual skif::LayerSpace< SkIRect > onGetInputLayerBounds(const skif::Mapping &mapping, const skif::LayerSpace< SkIRect > &desiredOutput, std::optional< skif::LayerSpace< SkIRect > > contentBounds) const =0
virtual bool onAffectsTransparentBlack() const
void flatten(SkWriteBuffer &) const override
virtual std::optional< skif::LayerSpace< SkIRect > > onGetOutputLayerBounds(const skif::Mapping &mapping, std::optional< skif::LayerSpace< SkIRect > > contentBounds) const =0
virtual skif::FilterResult onFilterImage(const skif::Context &context) const =0
virtual MatrixCapability onGetCTMCapability() const
virtual SkRect computeFastBounds(const SkRect &bounds) const
static sk_sp< SkImageFilter > Arithmetic(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4, bool enforcePMColor, sk_sp< SkImageFilter > background, sk_sp< SkImageFilter > foreground, const CropRect &cropRect={})
static sk_sp< SkImageFilter > Empty()
static sk_sp< SkImageFilter > Crop(const SkRect &rect, SkTileMode tileMode, sk_sp< SkImageFilter > input)
static sk_sp< SkImageFilter > Blend(SkBlendMode mode, sk_sp< SkImageFilter > background, sk_sp< SkImageFilter > foreground=nullptr, const CropRect &cropRect={})
@ kCombineBlendArithmeticFilters
static SkRect MakeLargeS32()
const LayerSpace< SkIRect > & desiredOutput() const
const FilterResult & source() const
Context withNewDesiredOutput(const LayerSpace< SkIRect > &desiredOutput) const
const Mapping & mapping() const
LayerSpace< SkIRect > layerBounds() const
@ kBackground
Suitable for threads that shouldn't disrupt high priority work.
static const uint8_t buffer[]
Optional< SkRect > bounds
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
static constexpr SkRect MakeEmpty()
bool intersect(const SkRect &r)
void join(const SkRect &r)