mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-30 13:19:02 +00:00
LibWeb/Canvas: Support globalCompositionOperation
Canvas now supports compositing and various blending modes via the `globalCompositeOperation` attribute.
This commit is contained in:
parent
19ab213b16
commit
8575bddfe6
Notes:
github-actions[bot]
2025-02-05 11:28:07 +00:00
Author: https://github.com/skyz1
Commit: 8575bddfe6
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3267
Reviewed-by: https://github.com/AtkinsSJ ✅
Reviewed-by: https://github.com/konradekk
16 changed files with 283 additions and 32 deletions
44
Libraries/LibGfx/CompositingAndBlendingOperator.h
Normal file
44
Libraries/LibGfx/CompositingAndBlendingOperator.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Glenn Skrzypczak <glenn.skrzypczak@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
enum class CompositingAndBlendingOperator {
|
||||
Normal,
|
||||
Multiply,
|
||||
Screen,
|
||||
Overlay,
|
||||
Darken,
|
||||
Lighten,
|
||||
ColorDodge,
|
||||
ColorBurn,
|
||||
HardLight,
|
||||
SoftLight,
|
||||
Difference,
|
||||
Exclusion,
|
||||
Hue,
|
||||
Saturation,
|
||||
Color,
|
||||
Luminosity,
|
||||
Clear,
|
||||
Copy,
|
||||
SourceOver,
|
||||
DestinationOver,
|
||||
SourceIn,
|
||||
DestinationIn,
|
||||
SourceOut,
|
||||
DestinationOut,
|
||||
SourceATop,
|
||||
DestinationATop,
|
||||
Xor,
|
||||
Lighter,
|
||||
PlusDarker,
|
||||
PlusLighter
|
||||
};
|
||||
|
||||
}
|
|
@ -283,12 +283,11 @@ ErrorOr<size_t> PNGLoadingContext::read_frames(png_structp png_ptr, png_infop in
|
|||
switch (blend_op) {
|
||||
case PNG_BLEND_OP_SOURCE:
|
||||
// All color components of the frame, including alpha, overwrite the current contents of the frame's output buffer region.
|
||||
painter->clear_rect(frame_rect, Gfx::Color::Transparent);
|
||||
painter->draw_bitmap(frame_rect, Gfx::ImmutableBitmap::create(*decoded_frame_bitmap), decoded_frame_bitmap->rect(), Gfx::ScalingMode::NearestNeighbor, {}, 1.0f);
|
||||
painter->draw_bitmap(frame_rect, Gfx::ImmutableBitmap::create(*decoded_frame_bitmap), decoded_frame_bitmap->rect(), Gfx::ScalingMode::NearestNeighbor, {}, 1.0f, Gfx::CompositingAndBlendingOperator::Copy);
|
||||
break;
|
||||
case PNG_BLEND_OP_OVER:
|
||||
// The frame should be composited onto the output buffer based on its alpha, using a simple OVER operation as described in the "Alpha Channel Processing" section of the PNG specification.
|
||||
painter->draw_bitmap(frame_rect, Gfx::ImmutableBitmap::create(*decoded_frame_bitmap), decoded_frame_bitmap->rect(), ScalingMode::NearestNeighbor, {}, 1.0f);
|
||||
painter->draw_bitmap(frame_rect, Gfx::ImmutableBitmap::create(*decoded_frame_bitmap), decoded_frame_bitmap->rect(), ScalingMode::NearestNeighbor, {}, 1.0f, Gfx::CompositingAndBlendingOperator::SourceOver);
|
||||
break;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
|
@ -306,8 +305,7 @@ ErrorOr<size_t> PNGLoadingContext::read_frames(png_structp png_ptr, png_infop in
|
|||
break;
|
||||
case PNG_DISPOSE_OP_PREVIOUS:
|
||||
// The frame's region of the output buffer is to be reverted to the previous contents before rendering the next frame.
|
||||
painter->clear_rect(frame_rect, Gfx::Color::Transparent);
|
||||
painter->draw_bitmap(frame_rect, Gfx::ImmutableBitmap::create(*prev_output_buffer), IntRect { x, y, width, height }, Gfx::ScalingMode::NearestNeighbor, {}, 1.0f);
|
||||
painter->draw_bitmap(frame_rect, Gfx::ImmutableBitmap::create(*prev_output_buffer), IntRect { x, y, width, height }, Gfx::ScalingMode::NearestNeighbor, {}, 1.0f, Gfx::CompositingAndBlendingOperator::Copy);
|
||||
break;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
|
|
|
@ -481,7 +481,7 @@ void TinyVGDecodedImageData::draw(Painter& painter) const
|
|||
command.fill->visit(
|
||||
[&](Color color) { painter.fill_path(fill_path, color, WindingRule::EvenOdd); },
|
||||
[&](NonnullRefPtr<SVGGradientPaintStyle> const& style) {
|
||||
painter.fill_path(fill_path, style, {}, 1.0f, WindingRule::EvenOdd);
|
||||
painter.fill_path(fill_path, style, {}, 1.0f, CompositingAndBlendingOperator::SourceOver, WindingRule::EvenOdd);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -489,7 +489,7 @@ void TinyVGDecodedImageData::draw(Painter& painter) const
|
|||
command.stroke->visit(
|
||||
[&](Color color) { painter.stroke_path(draw_path, color, command.stroke_width); },
|
||||
[&](NonnullRefPtr<SVGGradientPaintStyle> const& style) {
|
||||
painter.stroke_path(draw_path, style, {}, command.stroke_width, 1.0f);
|
||||
painter.stroke_path(draw_path, style, {}, command.stroke_width, 1.0f, CompositingAndBlendingOperator::SourceOver);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Forward.h>
|
||||
#include <LibGfx/CompositingAndBlendingOperator.h>
|
||||
#include <LibGfx/Filter.h>
|
||||
#include <LibGfx/Forward.h>
|
||||
#include <LibGfx/PaintStyle.h>
|
||||
|
@ -24,15 +25,15 @@ public:
|
|||
virtual void clear_rect(Gfx::FloatRect const&, Gfx::Color) = 0;
|
||||
virtual void fill_rect(Gfx::FloatRect const&, Gfx::Color) = 0;
|
||||
|
||||
virtual void draw_bitmap(Gfx::FloatRect const& dst_rect, Gfx::ImmutableBitmap const& src_bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode, ReadonlySpan<Gfx::Filter> filters, float global_alpha) = 0;
|
||||
virtual void draw_bitmap(Gfx::FloatRect const& dst_rect, Gfx::ImmutableBitmap const& src_bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode, ReadonlySpan<Gfx::Filter> filters, float global_alpha, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator) = 0;
|
||||
|
||||
virtual void stroke_path(Gfx::Path const&, Gfx::Color, float thickness) = 0;
|
||||
virtual void stroke_path(Gfx::Path const&, Gfx::Color, float thickness, float blur_radius) = 0;
|
||||
virtual void stroke_path(Gfx::Path const&, Gfx::PaintStyle const&, ReadonlySpan<Gfx::Filter>, float thickness, float global_alpha) = 0;
|
||||
virtual void stroke_path(Gfx::Path const&, Gfx::Color, float thickness, float blur_radius, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator) = 0;
|
||||
virtual void stroke_path(Gfx::Path const&, Gfx::PaintStyle const&, ReadonlySpan<Gfx::Filter>, float thickness, float global_alpha, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator) = 0;
|
||||
|
||||
virtual void fill_path(Gfx::Path const&, Gfx::Color, Gfx::WindingRule) = 0;
|
||||
virtual void fill_path(Gfx::Path const&, Gfx::Color, Gfx::WindingRule, float blur_radius) = 0;
|
||||
virtual void fill_path(Gfx::Path const&, Gfx::PaintStyle const&, ReadonlySpan<Gfx::Filter>, float global_alpha, Gfx::WindingRule) = 0;
|
||||
virtual void fill_path(Gfx::Path const&, Gfx::Color, Gfx::WindingRule, float blur_radius, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator) = 0;
|
||||
virtual void fill_path(Gfx::Path const&, Gfx::PaintStyle const&, ReadonlySpan<Gfx::Filter>, float global_alpha, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator, Gfx::WindingRule) = 0;
|
||||
|
||||
virtual void set_transform(Gfx::AffineTransform const&) = 0;
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#define AK_DONT_REPLACE_STD
|
||||
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/String.h>
|
||||
#include <LibGfx/Filter.h>
|
||||
#include <LibGfx/ImmutableBitmap.h>
|
||||
#include <LibGfx/PainterSkia.h>
|
||||
|
@ -16,6 +17,7 @@
|
|||
#include <LibGfx/SkiaUtils.h>
|
||||
|
||||
#include <AK/TypeCasts.h>
|
||||
#include <core/SkBlender.h>
|
||||
#include <core/SkCanvas.h>
|
||||
#include <core/SkPath.h>
|
||||
#include <effects/SkBlurMaskFilter.h>
|
||||
|
@ -130,11 +132,12 @@ void PainterSkia::fill_rect(Gfx::FloatRect const& rect, Color color)
|
|||
impl().canvas()->drawRect(to_skia_rect(rect), paint);
|
||||
}
|
||||
|
||||
void PainterSkia::draw_bitmap(Gfx::FloatRect const& dst_rect, Gfx::ImmutableBitmap const& src_bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode scaling_mode, ReadonlySpan<Gfx::Filter> filters, float global_alpha)
|
||||
void PainterSkia::draw_bitmap(Gfx::FloatRect const& dst_rect, Gfx::ImmutableBitmap const& src_bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode scaling_mode, ReadonlySpan<Gfx::Filter> filters, float global_alpha, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator)
|
||||
{
|
||||
SkPaint paint;
|
||||
apply_filters(paint, filters);
|
||||
paint.setAlpha(static_cast<u8>(global_alpha * 255));
|
||||
paint.setBlender(to_skia_blender(compositing_and_blending_operator));
|
||||
|
||||
impl().canvas()->drawImageRect(
|
||||
src_bitmap.sk_image(),
|
||||
|
@ -170,7 +173,7 @@ void PainterSkia::stroke_path(Gfx::Path const& path, Gfx::Color color, float thi
|
|||
impl().canvas()->drawPath(sk_path, paint);
|
||||
}
|
||||
|
||||
void PainterSkia::stroke_path(Gfx::Path const& path, Gfx::Color color, float thickness, float blur_radius)
|
||||
void PainterSkia::stroke_path(Gfx::Path const& path, Gfx::Color color, float thickness, float blur_radius, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator)
|
||||
{
|
||||
// Skia treats zero thickness as a special case and will draw a hairline, while we want to draw nothing.
|
||||
if (thickness <= 0)
|
||||
|
@ -182,11 +185,12 @@ void PainterSkia::stroke_path(Gfx::Path const& path, Gfx::Color color, float thi
|
|||
paint.setStyle(SkPaint::kStroke_Style);
|
||||
paint.setStrokeWidth(thickness);
|
||||
paint.setColor(to_skia_color(color));
|
||||
paint.setBlender(to_skia_blender(compositing_and_blending_operator));
|
||||
auto sk_path = to_skia_path(path);
|
||||
impl().canvas()->drawPath(sk_path, paint);
|
||||
}
|
||||
|
||||
void PainterSkia::stroke_path(Gfx::Path const& path, Gfx::PaintStyle const& paint_style, ReadonlySpan<Gfx::Filter> filters, float thickness, float global_alpha)
|
||||
void PainterSkia::stroke_path(Gfx::Path const& path, Gfx::PaintStyle const& paint_style, ReadonlySpan<Gfx::Filter> filters, float thickness, float global_alpha, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator)
|
||||
{
|
||||
// Skia treats zero thickness as a special case and will draw a hairline, while we want to draw nothing.
|
||||
if (thickness <= 0)
|
||||
|
@ -199,6 +203,7 @@ void PainterSkia::stroke_path(Gfx::Path const& path, Gfx::PaintStyle const& pain
|
|||
paint.setAlphaf(alpha * global_alpha);
|
||||
paint.setStyle(SkPaint::Style::kStroke_Style);
|
||||
paint.setStrokeWidth(thickness);
|
||||
paint.setBlender(to_skia_blender(compositing_and_blending_operator));
|
||||
impl().canvas()->drawPath(sk_path, paint);
|
||||
}
|
||||
|
||||
|
@ -212,18 +217,19 @@ void PainterSkia::fill_path(Gfx::Path const& path, Gfx::Color color, Gfx::Windin
|
|||
impl().canvas()->drawPath(sk_path, paint);
|
||||
}
|
||||
|
||||
void PainterSkia::fill_path(Gfx::Path const& path, Gfx::Color color, Gfx::WindingRule winding_rule, float blur_radius)
|
||||
void PainterSkia::fill_path(Gfx::Path const& path, Gfx::Color color, Gfx::WindingRule winding_rule, float blur_radius, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator)
|
||||
{
|
||||
SkPaint paint;
|
||||
paint.setAntiAlias(true);
|
||||
paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, blur_radius / 2));
|
||||
paint.setColor(to_skia_color(color));
|
||||
paint.setBlender(to_skia_blender(compositing_and_blending_operator));
|
||||
auto sk_path = to_skia_path(path);
|
||||
sk_path.setFillType(to_skia_path_fill_type(winding_rule));
|
||||
impl().canvas()->drawPath(sk_path, paint);
|
||||
}
|
||||
|
||||
void PainterSkia::fill_path(Gfx::Path const& path, Gfx::PaintStyle const& paint_style, ReadonlySpan<Gfx::Filter> filters, float global_alpha, Gfx::WindingRule winding_rule)
|
||||
void PainterSkia::fill_path(Gfx::Path const& path, Gfx::PaintStyle const& paint_style, ReadonlySpan<Gfx::Filter> filters, float global_alpha, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator, Gfx::WindingRule winding_rule)
|
||||
{
|
||||
auto sk_path = to_skia_path(path);
|
||||
sk_path.setFillType(to_skia_path_fill_type(winding_rule));
|
||||
|
@ -231,6 +237,7 @@ void PainterSkia::fill_path(Gfx::Path const& path, Gfx::PaintStyle const& paint_
|
|||
paint.setAntiAlias(true);
|
||||
float alpha = paint.getAlphaf();
|
||||
paint.setAlphaf(alpha * global_alpha);
|
||||
paint.setBlender(to_skia_blender(compositing_and_blending_operator));
|
||||
impl().canvas()->drawPath(sk_path, paint);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <AK/NonnullOwnPtr.h>
|
||||
#include <LibGfx/Bitmap.h>
|
||||
#include <LibGfx/CompositingAndBlendingOperator.h>
|
||||
#include <LibGfx/Painter.h>
|
||||
#include <LibGfx/PaintingSurface.h>
|
||||
|
||||
|
@ -20,13 +21,13 @@ public:
|
|||
|
||||
virtual void clear_rect(Gfx::FloatRect const&, Color) override;
|
||||
virtual void fill_rect(Gfx::FloatRect const&, Color) override;
|
||||
virtual void draw_bitmap(Gfx::FloatRect const& dst_rect, Gfx::ImmutableBitmap const& src_bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode, ReadonlySpan<Gfx::Filter>, float global_alpha) override;
|
||||
virtual void draw_bitmap(Gfx::FloatRect const& dst_rect, Gfx::ImmutableBitmap const& src_bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode, ReadonlySpan<Gfx::Filter>, float global_alpha, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator) override;
|
||||
virtual void stroke_path(Gfx::Path const&, Gfx::Color, float thickness) override;
|
||||
virtual void stroke_path(Gfx::Path const&, Gfx::Color, float thickness, float blur_radius) override;
|
||||
virtual void stroke_path(Gfx::Path const&, Gfx::PaintStyle const&, ReadonlySpan<Gfx::Filter>, float thickness, float global_alpha) override;
|
||||
virtual void stroke_path(Gfx::Path const&, Gfx::Color, float thickness, float blur_radius, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator) override;
|
||||
virtual void stroke_path(Gfx::Path const&, Gfx::PaintStyle const&, ReadonlySpan<Gfx::Filter>, float thickness, float global_alpha, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator) override;
|
||||
virtual void fill_path(Gfx::Path const&, Gfx::Color, Gfx::WindingRule) override;
|
||||
virtual void fill_path(Gfx::Path const&, Gfx::Color, Gfx::WindingRule, float blur_radius) override;
|
||||
virtual void fill_path(Gfx::Path const&, Gfx::PaintStyle const&, ReadonlySpan<Gfx::Filter>, float global_alpha, Gfx::WindingRule) override;
|
||||
virtual void fill_path(Gfx::Path const&, Gfx::Color, Gfx::WindingRule, float blur_radius, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator) override;
|
||||
virtual void fill_path(Gfx::Path const&, Gfx::PaintStyle const&, ReadonlySpan<Gfx::Filter>, float global_alpha, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator, Gfx::WindingRule) override;
|
||||
virtual void set_transform(Gfx::AffineTransform const&) override;
|
||||
virtual void save() override;
|
||||
virtual void restore() override;
|
||||
|
|
|
@ -7,9 +7,12 @@
|
|||
#include <AK/Assertions.h>
|
||||
#include <LibGfx/Filter.h>
|
||||
#include <LibGfx/SkiaUtils.h>
|
||||
#include <core/SkBlender.h>
|
||||
#include <core/SkColorFilter.h>
|
||||
#include <core/SkImageFilter.h>
|
||||
#include <core/SkString.h>
|
||||
#include <effects/SkImageFilters.h>
|
||||
#include <effects/SkRuntimeEffect.h>
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
|
@ -140,4 +143,85 @@ sk_sp<SkImageFilter> to_skia_image_filter(Gfx::Filter const& filter)
|
|||
});
|
||||
}
|
||||
|
||||
sk_sp<SkBlender> to_skia_blender(Gfx::CompositingAndBlendingOperator compositing_and_blending_operator)
|
||||
{
|
||||
switch (compositing_and_blending_operator) {
|
||||
case CompositingAndBlendingOperator::Normal:
|
||||
return SkBlender::Mode(SkBlendMode::kSrcOver);
|
||||
case CompositingAndBlendingOperator::Multiply:
|
||||
return SkBlender::Mode(SkBlendMode::kMultiply);
|
||||
case CompositingAndBlendingOperator::Screen:
|
||||
return SkBlender::Mode(SkBlendMode::kScreen);
|
||||
case CompositingAndBlendingOperator::Overlay:
|
||||
return SkBlender::Mode(SkBlendMode::kOverlay);
|
||||
case CompositingAndBlendingOperator::Darken:
|
||||
return SkBlender::Mode(SkBlendMode::kDarken);
|
||||
case CompositingAndBlendingOperator::Lighten:
|
||||
return SkBlender::Mode(SkBlendMode::kLighten);
|
||||
case CompositingAndBlendingOperator::ColorDodge:
|
||||
return SkBlender::Mode(SkBlendMode::kColorDodge);
|
||||
case CompositingAndBlendingOperator::ColorBurn:
|
||||
return SkBlender::Mode(SkBlendMode::kColorBurn);
|
||||
case CompositingAndBlendingOperator::HardLight:
|
||||
return SkBlender::Mode(SkBlendMode::kHardLight);
|
||||
case CompositingAndBlendingOperator::SoftLight:
|
||||
return SkBlender::Mode(SkBlendMode::kSoftLight);
|
||||
case CompositingAndBlendingOperator::Difference:
|
||||
return SkBlender::Mode(SkBlendMode::kDifference);
|
||||
case CompositingAndBlendingOperator::Exclusion:
|
||||
return SkBlender::Mode(SkBlendMode::kExclusion);
|
||||
case CompositingAndBlendingOperator::Hue:
|
||||
return SkBlender::Mode(SkBlendMode::kHue);
|
||||
case CompositingAndBlendingOperator::Saturation:
|
||||
return SkBlender::Mode(SkBlendMode::kSaturation);
|
||||
case CompositingAndBlendingOperator::Color:
|
||||
return SkBlender::Mode(SkBlendMode::kColor);
|
||||
case CompositingAndBlendingOperator::Luminosity:
|
||||
return SkBlender::Mode(SkBlendMode::kLuminosity);
|
||||
case CompositingAndBlendingOperator::Clear:
|
||||
return SkBlender::Mode(SkBlendMode::kClear);
|
||||
case CompositingAndBlendingOperator::Copy:
|
||||
return SkBlender::Mode(SkBlendMode::kSrc);
|
||||
case CompositingAndBlendingOperator::SourceOver:
|
||||
return SkBlender::Mode(SkBlendMode::kSrcOver);
|
||||
case CompositingAndBlendingOperator::DestinationOver:
|
||||
return SkBlender::Mode(SkBlendMode::kDstOver);
|
||||
case CompositingAndBlendingOperator::SourceIn:
|
||||
return SkBlender::Mode(SkBlendMode::kSrcIn);
|
||||
case CompositingAndBlendingOperator::DestinationIn:
|
||||
return SkBlender::Mode(SkBlendMode::kDstIn);
|
||||
case CompositingAndBlendingOperator::SourceOut:
|
||||
return SkBlender::Mode(SkBlendMode::kSrcOut);
|
||||
case CompositingAndBlendingOperator::DestinationOut:
|
||||
return SkBlender::Mode(SkBlendMode::kDstOut);
|
||||
case CompositingAndBlendingOperator::SourceATop:
|
||||
return SkBlender::Mode(SkBlendMode::kSrcATop);
|
||||
case CompositingAndBlendingOperator::DestinationATop:
|
||||
return SkBlender::Mode(SkBlendMode::kDstATop);
|
||||
case CompositingAndBlendingOperator::Xor:
|
||||
return SkBlender::Mode(SkBlendMode::kXor);
|
||||
case CompositingAndBlendingOperator::Lighter:
|
||||
return SkBlender::Mode(SkBlendMode::kPlus);
|
||||
case CompositingAndBlendingOperator::PlusDarker:
|
||||
// https://drafts.fxtf.org/compositing/#porterduffcompositingoperators_plus_darker
|
||||
// FIXME: This does not match the spec, however it looks like Safari, the only popular browser supporting this operator.
|
||||
return SkRuntimeEffect::MakeForBlender(SkString(R"(
|
||||
vec4 main(vec4 source, vec4 destination) {
|
||||
return saturate(saturate(destination.a + source.a) - saturate(destination.a - destination) - saturate(source.a - source));
|
||||
}
|
||||
)"))
|
||||
.effect->makeBlender(nullptr);
|
||||
case CompositingAndBlendingOperator::PlusLighter:
|
||||
// https://drafts.fxtf.org/compositing/#porterduffcompositingoperators_plus_lighter
|
||||
return SkRuntimeEffect::MakeForBlender(SkString(R"(
|
||||
vec4 main(vec4 source, vec4 destination) {
|
||||
return saturate(source + destination);
|
||||
}
|
||||
)"))
|
||||
.effect->makeBlender(nullptr);
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <AK/Assertions.h>
|
||||
#include <LibGfx/Bitmap.h>
|
||||
#include <LibGfx/CompositingAndBlendingOperator.h>
|
||||
#include <LibGfx/Filter.h>
|
||||
#include <LibGfx/PathSkia.h>
|
||||
#include <LibGfx/ScalingMode.h>
|
||||
|
@ -18,6 +19,7 @@
|
|||
#include <core/SkImageFilter.h>
|
||||
#include <core/SkPath.h>
|
||||
#include <core/SkSamplingOptions.h>
|
||||
#include <include/core/SkBlender.h>
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
|
@ -90,5 +92,5 @@ constexpr SkSamplingOptions to_skia_sampling_options(Gfx::ScalingMode scaling_mo
|
|||
|
||||
SkPath to_skia_path(Path const& path);
|
||||
sk_sp<SkImageFilter> to_skia_image_filter(Gfx::Filter const& filter);
|
||||
|
||||
sk_sp<SkBlender> to_skia_blender(Gfx::CompositingAndBlendingOperator compositing_and_blending_operator);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue