mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-02 22:30:31 +00:00
LibGfx+LibWeb: Turn Gfx::Filter into a SkImageFilter wrapper
This commit is contained in:
parent
417f4edc46
commit
0fcb574041
Notes:
github-actions[bot]
2025-06-01 21:23:19 +00:00
Author: https://github.com/ananas-dev
Commit: 0fcb574041
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4692
Reviewed-by: https://github.com/kalenikaliaksandr ✅
Reviewed-by: https://github.com/konradekk
26 changed files with 412 additions and 256 deletions
|
@ -9,6 +9,7 @@ set(SOURCES
|
|||
Color.cpp
|
||||
ColorSpace.cpp
|
||||
Cursor.cpp
|
||||
Filter.cpp
|
||||
FontCascadeList.cpp
|
||||
Font/Font.cpp
|
||||
Font/FontData.cpp
|
||||
|
|
224
Libraries/LibGfx/Filter.cpp
Normal file
224
Libraries/LibGfx/Filter.cpp
Normal file
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Lucien Fiorini <lucienfiorini@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibGfx/Filter.h>
|
||||
#include <LibGfx/FilterImpl.h>
|
||||
#include <LibGfx/SkiaUtils.h>
|
||||
#include <core/SkBlendMode.h>
|
||||
#include <core/SkColorFilter.h>
|
||||
#include <effects/SkColorMatrix.h>
|
||||
#include <effects/SkImageFilters.h>
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
using Impl = FilterImpl;
|
||||
|
||||
Filter::Filter(Filter const& other)
|
||||
: m_impl(other.m_impl->clone())
|
||||
{
|
||||
}
|
||||
|
||||
Filter& Filter::operator=(Filter const& other)
|
||||
{
|
||||
if (this != &other) {
|
||||
m_impl = other.m_impl->clone();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Filter::~Filter() = default;
|
||||
|
||||
Filter::Filter(NonnullOwnPtr<FilterImpl>&& impl)
|
||||
: m_impl(impl->clone())
|
||||
{
|
||||
}
|
||||
|
||||
FilterImpl const& Filter::impl() const
|
||||
{
|
||||
return *m_impl;
|
||||
}
|
||||
|
||||
Filter Filter::compose(Filter const& outer, Filter const& inner)
|
||||
{
|
||||
auto inner_skia = inner.m_impl->filter;
|
||||
auto outer_skia = outer.m_impl->filter;
|
||||
|
||||
auto filter = SkImageFilters::Compose(outer_skia, inner_skia);
|
||||
return Filter(Impl::create(filter));
|
||||
}
|
||||
|
||||
Filter Filter::blend(Filter const& background, Filter const& foreground, Gfx::CompositingAndBlendingOperator mode)
|
||||
{
|
||||
auto filter = SkImageFilters::Blend(to_skia_blender(mode), background.m_impl->filter, foreground.m_impl->filter);
|
||||
return Filter(Impl::create(filter));
|
||||
}
|
||||
|
||||
Filter Filter::blur(float radius, Optional<Filter const&> input)
|
||||
{
|
||||
sk_sp<SkImageFilter> input_skia = input.has_value() ? input->m_impl->filter : nullptr;
|
||||
|
||||
auto filter = SkImageFilters::Blur(radius, radius, input_skia);
|
||||
return Filter(Impl::create(filter));
|
||||
}
|
||||
|
||||
Filter Filter::flood(Gfx::Color color, float opacity)
|
||||
{
|
||||
auto color_skia = to_skia_color(color);
|
||||
color_skia = SkColorSetA(color_skia, static_cast<u8>(opacity * 255));
|
||||
|
||||
return Filter(Impl::create(SkImageFilters::Shader(SkShaders::Color(color_skia))));
|
||||
}
|
||||
|
||||
Filter Filter::drop_shadow(float offset_x, float offset_y, float radius, Gfx::Color color,
|
||||
Optional<Filter const&> input)
|
||||
{
|
||||
sk_sp<SkImageFilter> input_skia = input.has_value() ? input->m_impl->filter : nullptr;
|
||||
auto shadow_color = to_skia_color(color);
|
||||
|
||||
auto filter = SkImageFilters::DropShadow(offset_x, offset_y, radius, radius, shadow_color, input_skia);
|
||||
return Filter(Impl::create(filter));
|
||||
}
|
||||
|
||||
Filter Filter::color(ColorFilterType type, float amount, Optional<Filter const&> input)
|
||||
{
|
||||
sk_sp<SkImageFilter> input_skia = input.has_value() ? input->m_impl->filter : nullptr;
|
||||
|
||||
sk_sp<SkColorFilter> color_filter;
|
||||
|
||||
// Matrices are taken from https://drafts.fxtf.org/filter-effects-1/#FilterPrimitiveRepresentation
|
||||
switch (type) {
|
||||
case ColorFilterType::Grayscale: {
|
||||
float matrix[20] = {
|
||||
0.2126f + 0.7874f * (1 - amount), 0.7152f - 0.7152f * (1 - amount),
|
||||
0.0722f - 0.0722f * (1 - amount), 0, 0,
|
||||
0.2126f - 0.2126f * (1 - amount), 0.7152f + 0.2848f * (1 - amount),
|
||||
0.0722f - 0.0722f * (1 - amount), 0, 0,
|
||||
0.2126f - 0.2126f * (1 - amount), 0.7152f - 0.7152f * (1 - amount),
|
||||
0.0722f + 0.9278f * (1 - amount), 0, 0,
|
||||
0, 0, 0, 1, 0
|
||||
};
|
||||
color_filter = SkColorFilters::Matrix(matrix, SkColorFilters::Clamp::kYes);
|
||||
break;
|
||||
}
|
||||
case Gfx::ColorFilterType::Brightness: {
|
||||
float matrix[20] = {
|
||||
amount, 0, 0, 0, 0,
|
||||
0, amount, 0, 0, 0,
|
||||
0, 0, amount, 0, 0,
|
||||
0, 0, 0, 1, 0
|
||||
};
|
||||
color_filter = SkColorFilters::Matrix(matrix, SkColorFilters::Clamp::kNo);
|
||||
break;
|
||||
}
|
||||
case Gfx::ColorFilterType::Contrast: {
|
||||
float intercept = -(0.5f * amount) + 0.5f;
|
||||
float matrix[20] = {
|
||||
amount, 0, 0, 0, intercept,
|
||||
0, amount, 0, 0, intercept,
|
||||
0, 0, amount, 0, intercept,
|
||||
0, 0, 0, 1, 0
|
||||
};
|
||||
color_filter = SkColorFilters::Matrix(matrix, SkColorFilters::Clamp::kNo);
|
||||
break;
|
||||
}
|
||||
case Gfx::ColorFilterType::Invert: {
|
||||
float matrix[20] = {
|
||||
1 - 2 * amount, 0, 0, 0, amount,
|
||||
0, 1 - 2 * amount, 0, 0, amount,
|
||||
0, 0, 1 - 2 * amount, 0, amount,
|
||||
0, 0, 0, 1, 0
|
||||
};
|
||||
color_filter = SkColorFilters::Matrix(matrix, SkColorFilters::Clamp::kYes);
|
||||
break;
|
||||
}
|
||||
case Gfx::ColorFilterType::Opacity: {
|
||||
float matrix[20] = {
|
||||
1, 0, 0, 0, 0,
|
||||
0, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 0,
|
||||
0, 0, 0, amount, 0
|
||||
};
|
||||
color_filter = SkColorFilters::Matrix(matrix, SkColorFilters::Clamp::kYes);
|
||||
break;
|
||||
}
|
||||
case Gfx::ColorFilterType::Sepia: {
|
||||
float matrix[20] = {
|
||||
0.393f + 0.607f * (1 - amount), 0.769f - 0.769f * (1 - amount), 0.189f - 0.189f * (1 - amount), 0,
|
||||
0,
|
||||
0.349f - 0.349f * (1 - amount), 0.686f + 0.314f * (1 - amount), 0.168f - 0.168f * (1 - amount), 0,
|
||||
0,
|
||||
0.272f - 0.272f * (1 - amount), 0.534f - 0.534f * (1 - amount), 0.131f + 0.869f * (1 - amount), 0,
|
||||
0,
|
||||
0, 0, 0, 1, 0
|
||||
};
|
||||
color_filter = SkColorFilters::Matrix(matrix, SkColorFilters::Clamp::kYes);
|
||||
break;
|
||||
}
|
||||
case Gfx::ColorFilterType::Saturate: {
|
||||
float matrix[20] = {
|
||||
0.213f + 0.787f * amount, 0.715f - 0.715f * amount, 0.072f - 0.072f * amount, 0, 0,
|
||||
0.213f - 0.213f * amount, 0.715f + 0.285f * amount, 0.072f - 0.072f * amount, 0, 0,
|
||||
0.213f - 0.213f * amount, 0.715f - 0.715f * amount, 0.072f + 0.928f * amount, 0, 0,
|
||||
0, 0, 0, 1, 0
|
||||
};
|
||||
color_filter = SkColorFilters::Matrix(matrix, SkColorFilters::Clamp::kNo);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
return Filter(Impl::create(SkImageFilters::ColorFilter(color_filter, input_skia)));
|
||||
}
|
||||
|
||||
Filter Filter::color_matrix(float matrix[20], Optional<Filter const&> input)
|
||||
{
|
||||
sk_sp<SkImageFilter> input_skia = input.has_value() ? input->m_impl->filter : nullptr;
|
||||
|
||||
return Filter(Impl::create(SkImageFilters::ColorFilter(SkColorFilters::Matrix(matrix), input_skia)));
|
||||
}
|
||||
|
||||
Filter Filter::saturate(float value, Optional<Filter const&> input)
|
||||
{
|
||||
sk_sp<SkImageFilter> input_skia = input.has_value() ? input->m_impl->filter : nullptr;
|
||||
|
||||
SkColorMatrix matrix;
|
||||
matrix.setSaturation(value);
|
||||
|
||||
return Filter(Impl::create(SkImageFilters::ColorFilter(SkColorFilters::Matrix(matrix), input_skia)));
|
||||
}
|
||||
|
||||
Filter Filter::hue_rotate(float angle_degrees, Optional<Filter const&> input)
|
||||
{
|
||||
sk_sp<SkImageFilter> input_skia = input.has_value() ? input->m_impl->filter : nullptr;
|
||||
|
||||
float radians = AK::to_radians(angle_degrees);
|
||||
|
||||
auto cosA = cos(radians);
|
||||
auto sinA = sin(radians);
|
||||
|
||||
auto a00 = 0.213f + cosA * 0.787f - sinA * 0.213f;
|
||||
auto a01 = 0.715f - cosA * 0.715f - sinA * 0.715f;
|
||||
auto a02 = 0.072f - cosA * 0.072f + sinA * 0.928f;
|
||||
auto a10 = 0.213f - cosA * 0.213f + sinA * 0.143f;
|
||||
auto a11 = 0.715f + cosA * 0.285f + sinA * 0.140f;
|
||||
auto a12 = 0.072f - cosA * 0.072f - sinA * 0.283f;
|
||||
auto a20 = 0.213f - cosA * 0.213f - sinA * 0.787f;
|
||||
auto a21 = 0.715f - cosA * 0.715f + sinA * 0.715f;
|
||||
auto a22 = 0.072f + cosA * 0.928f + sinA * 0.072f;
|
||||
|
||||
float matrix[20] = {
|
||||
a00, a01, a02, 0, 0,
|
||||
a10, a11, a12, 0, 0,
|
||||
a20, a21, a22, 0, 0,
|
||||
0, 0, 0, 1, 0
|
||||
};
|
||||
|
||||
auto color_filter = SkColorFilters::Matrix(matrix, SkColorFilters::Clamp::kNo);
|
||||
return Filter(Impl::create(SkImageFilters::ColorFilter(color_filter, input_skia)));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,44 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Lucien Fiorini <lucienfiorini@gmail.com>
|
||||
* Copyright (c) 2024-2025, Lucien Fiorini <lucienfiorini@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Variant.h>
|
||||
#include <AK/NonnullOwnPtr.h>
|
||||
#include <LibGfx/Color.h>
|
||||
#include <LibGfx/CompositingAndBlendingOperator.h>
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
struct BlurFilter {
|
||||
float radius;
|
||||
enum class ColorFilterType {
|
||||
Brightness,
|
||||
Contrast,
|
||||
Grayscale,
|
||||
Invert,
|
||||
Opacity,
|
||||
Saturate,
|
||||
Sepia
|
||||
};
|
||||
|
||||
struct DropShadowFilter {
|
||||
float offset_x;
|
||||
float offset_y;
|
||||
float radius;
|
||||
Gfx::Color color;
|
||||
};
|
||||
struct FilterImpl;
|
||||
|
||||
struct HueRotateFilter {
|
||||
float angle_degrees;
|
||||
};
|
||||
class Filter {
|
||||
public:
|
||||
Filter(Filter const&);
|
||||
Filter& operator=(Filter const&);
|
||||
|
||||
struct ColorFilter {
|
||||
enum class Type {
|
||||
Brightness,
|
||||
Contrast,
|
||||
Grayscale,
|
||||
Invert,
|
||||
Opacity,
|
||||
Saturate,
|
||||
Sepia
|
||||
} type;
|
||||
float amount;
|
||||
};
|
||||
~Filter();
|
||||
|
||||
using Filter = Variant<BlurFilter, DropShadowFilter, HueRotateFilter, ColorFilter>;
|
||||
static Filter compose(Filter const& outer, Filter const& inner);
|
||||
static Filter blend(Filter const& background, Filter const& foreground, CompositingAndBlendingOperator mode);
|
||||
static Filter flood(Gfx::Color color, float opacity);
|
||||
static Filter drop_shadow(float offset_x, float offset_y, float radius, Gfx::Color color, Optional<Filter const&> input = {});
|
||||
static Filter blur(float radius, Optional<Filter const&> input = {});
|
||||
static Filter color(ColorFilterType type, float amount, Optional<Filter const&> input = {});
|
||||
static Filter color_matrix(float matrix[20], Optional<Filter const&> input = {});
|
||||
static Filter saturate(float value, Optional<Filter const&> input = {});
|
||||
static Filter hue_rotate(float angle_degrees, Optional<Filter const&> input = {});
|
||||
|
||||
FilterImpl const& impl() const;
|
||||
|
||||
private:
|
||||
Filter(NonnullOwnPtr<FilterImpl>&&);
|
||||
NonnullOwnPtr<FilterImpl> m_impl;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
29
Libraries/LibGfx/FilterImpl.h
Normal file
29
Libraries/LibGfx/FilterImpl.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2024-2025, Lucien Fiorini <lucienfiorini@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/NonnullOwnPtr.h>
|
||||
#include <core/SkColorFilter.h>
|
||||
#include <effects/SkImageFilters.h>
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
struct FilterImpl {
|
||||
sk_sp<SkImageFilter> filter;
|
||||
|
||||
static NonnullOwnPtr<FilterImpl> create(sk_sp<SkImageFilter> filter)
|
||||
{
|
||||
return adopt_own(*new FilterImpl(move(filter)));
|
||||
}
|
||||
|
||||
NonnullOwnPtr<FilterImpl> clone() const
|
||||
{
|
||||
return adopt_own(*new FilterImpl(filter));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -26,16 +26,16 @@ 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, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator) = 0;
|
||||
virtual void draw_bitmap(Gfx::FloatRect const& dst_rect, Gfx::ImmutableBitmap const& src_bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode, Optional<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, 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 stroke_path(Gfx::Path const&, Gfx::PaintStyle const&, ReadonlySpan<Gfx::Filter>, float thickness, float global_alpha, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator, Gfx::Path::CapStyle const&, Gfx::Path::JoinStyle const&, float miter_limit, Vector<float> const&, float dash_offset) = 0;
|
||||
virtual void stroke_path(Gfx::Path const&, Gfx::PaintStyle const&, Optional<Gfx::Filter>, float thickness, float global_alpha, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator) = 0;
|
||||
virtual void stroke_path(Gfx::Path const&, Gfx::PaintStyle const&, Optional<Gfx::Filter>, float thickness, float global_alpha, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator, Gfx::Path::CapStyle const&, Gfx::Path::JoinStyle const&, float miter_limit, Vector<float> const&, float dash_offset) = 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, 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 fill_path(Gfx::Path const&, Gfx::PaintStyle const&, Optional<Gfx::Filter>, float global_alpha, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator, Gfx::WindingRule) = 0;
|
||||
|
||||
virtual void set_transform(Gfx::AffineTransform const&) = 0;
|
||||
|
||||
|
|
|
@ -17,10 +17,8 @@
|
|||
#include <LibGfx/SkiaUtils.h>
|
||||
|
||||
#include <AK/TypeCasts.h>
|
||||
#include <core/SkBlender.h>
|
||||
#include <core/SkCanvas.h>
|
||||
#include <core/SkPath.h>
|
||||
#include <core/SkPathEffect.h>
|
||||
#include <effects/SkBlurMaskFilter.h>
|
||||
#include <effects/SkDashPathEffect.h>
|
||||
#include <effects/SkGradientShader.h>
|
||||
|
@ -99,19 +97,19 @@ static void apply_paint_style(SkPaint& paint, Gfx::PaintStyle const& style)
|
|||
}
|
||||
}
|
||||
|
||||
static void apply_filters(SkPaint& paint, ReadonlySpan<Gfx::Filter> filters)
|
||||
static void apply_filter(SkPaint& paint, Gfx::Filter const& filter)
|
||||
{
|
||||
for (auto const& filter : filters) {
|
||||
paint.setImageFilter(to_skia_image_filter(filter));
|
||||
}
|
||||
paint.setImageFilter(to_skia_image_filter(filter));
|
||||
}
|
||||
|
||||
static SkPaint to_skia_paint(Gfx::PaintStyle const& style, ReadonlySpan<Gfx::Filter> filters)
|
||||
static SkPaint to_skia_paint(Gfx::PaintStyle const& style, Optional<Gfx::Filter const&> filter)
|
||||
{
|
||||
SkPaint paint;
|
||||
|
||||
apply_paint_style(paint, style);
|
||||
apply_filters(paint, filters);
|
||||
|
||||
if (filter.has_value())
|
||||
apply_filter(paint, move(filter.value()));
|
||||
|
||||
return paint;
|
||||
}
|
||||
|
@ -142,10 +140,13 @@ void PainterSkia::fill_rect(Gfx::FloatRect const& rect, Color color)
|
|||
});
|
||||
}
|
||||
|
||||
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)
|
||||
void PainterSkia::draw_bitmap(Gfx::FloatRect const& dst_rect, Gfx::ImmutableBitmap const& src_bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode scaling_mode, Optional<Gfx::Filter> filter, float global_alpha, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator)
|
||||
{
|
||||
SkPaint paint;
|
||||
apply_filters(paint, filters);
|
||||
|
||||
if (filter.has_value())
|
||||
apply_filter(paint, filter.value());
|
||||
|
||||
paint.setAlpha(static_cast<u8>(global_alpha * 255));
|
||||
paint.setBlender(to_skia_blender(compositing_and_blending_operator));
|
||||
|
||||
|
@ -208,14 +209,14 @@ void PainterSkia::stroke_path(Gfx::Path const& path, Gfx::Color color, float thi
|
|||
});
|
||||
}
|
||||
|
||||
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)
|
||||
void PainterSkia::stroke_path(Gfx::Path const& path, Gfx::PaintStyle const& paint_style, Optional<Gfx::Filter> filter, 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)
|
||||
return;
|
||||
|
||||
auto sk_path = to_skia_path(path);
|
||||
auto paint = to_skia_paint(paint_style, filters);
|
||||
auto paint = to_skia_paint(paint_style, filter);
|
||||
paint.setAntiAlias(true);
|
||||
float alpha = paint.getAlphaf();
|
||||
paint.setAlphaf(alpha * global_alpha);
|
||||
|
@ -227,14 +228,14 @@ void PainterSkia::stroke_path(Gfx::Path const& path, Gfx::PaintStyle const& pain
|
|||
});
|
||||
}
|
||||
|
||||
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, Gfx::Path::CapStyle const& cap_style, Gfx::Path::JoinStyle const& join_style, float miter_limit, Vector<float> const& dash_array, float dash_offset)
|
||||
void PainterSkia::stroke_path(Gfx::Path const& path, Gfx::PaintStyle const& paint_style, Optional<Gfx::Filter> filter, float thickness, float global_alpha, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator, Gfx::Path::CapStyle const& cap_style, Gfx::Path::JoinStyle const& join_style, float miter_limit, Vector<float> const& dash_array, float dash_offset)
|
||||
{
|
||||
// Skia treats zero thickness as a special case and will draw a hairline, while we want to draw nothing.
|
||||
if (thickness <= 0)
|
||||
return;
|
||||
|
||||
auto sk_path = to_skia_path(path);
|
||||
auto paint = to_skia_paint(paint_style, filters);
|
||||
auto paint = to_skia_paint(paint_style, filter);
|
||||
paint.setAntiAlias(true);
|
||||
float alpha = paint.getAlphaf();
|
||||
paint.setAlphaf(alpha * global_alpha);
|
||||
|
@ -276,11 +277,11 @@ void PainterSkia::fill_path(Gfx::Path const& path, Gfx::Color color, Gfx::Windin
|
|||
});
|
||||
}
|
||||
|
||||
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)
|
||||
void PainterSkia::fill_path(Gfx::Path const& path, Gfx::PaintStyle const& paint_style, Optional<Gfx::Filter> filter, 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));
|
||||
auto paint = to_skia_paint(paint_style, filters);
|
||||
auto paint = to_skia_paint(paint_style, filter);
|
||||
paint.setAntiAlias(true);
|
||||
float alpha = paint.getAlphaf();
|
||||
paint.setAlphaf(alpha * global_alpha);
|
||||
|
|
|
@ -21,14 +21,14 @@ 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, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator) override;
|
||||
virtual void draw_bitmap(Gfx::FloatRect const& dst_rect, Gfx::ImmutableBitmap const& src_bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode, Optional<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, 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 stroke_path(Gfx::Path const&, Gfx::PaintStyle const&, ReadonlySpan<Gfx::Filter>, float thickness, float global_alpha, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator, Gfx::Path::CapStyle const&, Gfx::Path::JoinStyle const&, float miter_limit, Vector<float> const&, float dash_offset) override;
|
||||
virtual void stroke_path(Gfx::Path const&, Gfx::PaintStyle const&, Optional<Gfx::Filter>, float thickness, float global_alpha, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator) override;
|
||||
virtual void stroke_path(Gfx::Path const&, Gfx::PaintStyle const&, Optional<Gfx::Filter>, float thickness, float global_alpha, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator, Gfx::Path::CapStyle const&, Gfx::Path::JoinStyle const&, float miter_limit, Vector<float> const&, float dash_offset) 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, 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 fill_path(Gfx::Path const&, Gfx::PaintStyle const&, Optional<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;
|
||||
|
|
|
@ -6,12 +6,11 @@
|
|||
|
||||
#include <AK/Assertions.h>
|
||||
#include <LibGfx/Filter.h>
|
||||
#include <LibGfx/FilterImpl.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 {
|
||||
|
@ -23,124 +22,7 @@ SkPath to_skia_path(Path const& path)
|
|||
|
||||
sk_sp<SkImageFilter> to_skia_image_filter(Gfx::Filter const& filter)
|
||||
{
|
||||
// See: https://drafts.fxtf.org/filter-effects-1/#supported-filter-functions
|
||||
return filter.visit(
|
||||
[&](Gfx::BlurFilter blur_filter) {
|
||||
return SkImageFilters::Blur(blur_filter.radius, blur_filter.radius, nullptr);
|
||||
},
|
||||
[&](Gfx::ColorFilter color_filter) {
|
||||
sk_sp<SkColorFilter> skia_color_filter;
|
||||
float amount = color_filter.amount;
|
||||
|
||||
// Matrices are taken from https://drafts.fxtf.org/filter-effects-1/#FilterPrimitiveRepresentation
|
||||
switch (color_filter.type) {
|
||||
case ColorFilter::Type::Grayscale: {
|
||||
float matrix[20] = {
|
||||
0.2126f + 0.7874f * (1 - amount), 0.7152f - 0.7152f * (1 - amount), 0.0722f - 0.0722f * (1 - amount), 0, 0,
|
||||
0.2126f - 0.2126f * (1 - amount), 0.7152f + 0.2848f * (1 - amount), 0.0722f - 0.0722f * (1 - amount), 0, 0,
|
||||
0.2126f - 0.2126f * (1 - amount), 0.7152f - 0.7152f * (1 - amount), 0.0722f + 0.9278f * (1 - amount), 0, 0,
|
||||
0, 0, 0, 1, 0
|
||||
};
|
||||
skia_color_filter = SkColorFilters::Matrix(matrix, SkColorFilters::Clamp::kYes);
|
||||
break;
|
||||
}
|
||||
case Gfx::ColorFilter::Type::Brightness: {
|
||||
float matrix[20] = {
|
||||
amount, 0, 0, 0, 0,
|
||||
0, amount, 0, 0, 0,
|
||||
0, 0, amount, 0, 0,
|
||||
0, 0, 0, 1, 0
|
||||
};
|
||||
skia_color_filter = SkColorFilters::Matrix(matrix, SkColorFilters::Clamp::kNo);
|
||||
break;
|
||||
}
|
||||
case Gfx::ColorFilter::Type::Contrast: {
|
||||
float intercept = -(0.5f * amount) + 0.5f;
|
||||
float matrix[20] = {
|
||||
amount, 0, 0, 0, intercept,
|
||||
0, amount, 0, 0, intercept,
|
||||
0, 0, amount, 0, intercept,
|
||||
0, 0, 0, 1, 0
|
||||
};
|
||||
skia_color_filter = SkColorFilters::Matrix(matrix, SkColorFilters::Clamp::kNo);
|
||||
break;
|
||||
}
|
||||
case Gfx::ColorFilter::Type::Invert: {
|
||||
float matrix[20] = {
|
||||
1 - 2 * amount, 0, 0, 0, amount,
|
||||
0, 1 - 2 * amount, 0, 0, amount,
|
||||
0, 0, 1 - 2 * amount, 0, amount,
|
||||
0, 0, 0, 1, 0
|
||||
};
|
||||
skia_color_filter = SkColorFilters::Matrix(matrix, SkColorFilters::Clamp::kYes);
|
||||
break;
|
||||
}
|
||||
case Gfx::ColorFilter::Type::Opacity: {
|
||||
float matrix[20] = {
|
||||
1, 0, 0, 0, 0,
|
||||
0, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 0,
|
||||
0, 0, 0, amount, 0
|
||||
};
|
||||
skia_color_filter = SkColorFilters::Matrix(matrix, SkColorFilters::Clamp::kYes);
|
||||
break;
|
||||
}
|
||||
case Gfx::ColorFilter::Type::Sepia: {
|
||||
float matrix[20] = {
|
||||
0.393f + 0.607f * (1 - amount), 0.769f - 0.769f * (1 - amount), 0.189f - 0.189f * (1 - amount), 0, 0,
|
||||
0.349f - 0.349f * (1 - amount), 0.686f + 0.314f * (1 - amount), 0.168f - 0.168f * (1 - amount), 0, 0,
|
||||
0.272f - 0.272f * (1 - amount), 0.534f - 0.534f * (1 - amount), 0.131f + 0.869f * (1 - amount), 0, 0,
|
||||
0, 0, 0, 1, 0
|
||||
};
|
||||
skia_color_filter = SkColorFilters::Matrix(matrix, SkColorFilters::Clamp::kYes);
|
||||
break;
|
||||
}
|
||||
case Gfx::ColorFilter::Type::Saturate: {
|
||||
float matrix[20] = {
|
||||
0.213f + 0.787f * amount, 0.715f - 0.715f * amount, 0.072f - 0.072f * amount, 0, 0,
|
||||
0.213f - 0.213f * amount, 0.715f + 0.285f * amount, 0.072f - 0.072f * amount, 0, 0,
|
||||
0.213f - 0.213f * amount, 0.715f - 0.715f * amount, 0.072f + 0.928f * amount, 0, 0,
|
||||
0, 0, 0, 1, 0
|
||||
};
|
||||
skia_color_filter = SkColorFilters::Matrix(matrix, SkColorFilters::Clamp::kNo);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
return SkImageFilters::ColorFilter(skia_color_filter, nullptr);
|
||||
},
|
||||
[&](Gfx::HueRotateFilter hue_rotate_filter) {
|
||||
float radians = AK::to_radians(hue_rotate_filter.angle_degrees);
|
||||
|
||||
auto cosA = cos(radians);
|
||||
auto sinA = sin(radians);
|
||||
|
||||
auto a00 = 0.213f + cosA * 0.787f - sinA * 0.213f;
|
||||
auto a01 = 0.715f - cosA * 0.715f - sinA * 0.715f;
|
||||
auto a02 = 0.072f - cosA * 0.072f + sinA * 0.928f;
|
||||
auto a10 = 0.213f - cosA * 0.213f + sinA * 0.143f;
|
||||
auto a11 = 0.715f + cosA * 0.285f + sinA * 0.140f;
|
||||
auto a12 = 0.072f - cosA * 0.072f - sinA * 0.283f;
|
||||
auto a20 = 0.213f - cosA * 0.213f - sinA * 0.787f;
|
||||
auto a21 = 0.715f - cosA * 0.715f + sinA * 0.715f;
|
||||
auto a22 = 0.072f + cosA * 0.928f + sinA * 0.072f;
|
||||
|
||||
float matrix[20] = {
|
||||
a00, a01, a02, 0, 0,
|
||||
a10, a11, a12, 0, 0,
|
||||
a20, a21, a22, 0, 0,
|
||||
0, 0, 0, 1, 0
|
||||
};
|
||||
|
||||
auto filter = SkColorFilters::Matrix(matrix, SkColorFilters::Clamp::kNo);
|
||||
return SkImageFilters::ColorFilter(filter, nullptr);
|
||||
},
|
||||
[&](Gfx::DropShadowFilter drop_shadow_filter) {
|
||||
auto shadow_color = to_skia_color(drop_shadow_filter.color);
|
||||
return SkImageFilters::DropShadow(drop_shadow_filter.offset_x, drop_shadow_filter.offset_y, drop_shadow_filter.radius, drop_shadow_filter.radius, shadow_color, nullptr);
|
||||
});
|
||||
return filter.impl().filter;
|
||||
}
|
||||
|
||||
sk_sp<SkBlender> to_skia_blender(Gfx::CompositingAndBlendingOperator compositing_and_blending_operator)
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <core/SkImageFilter.h>
|
||||
#include <core/SkPaint.h>
|
||||
#include <core/SkPath.h>
|
||||
#include <core/SkPathEffect.h>
|
||||
#include <core/SkSamplingOptions.h>
|
||||
|
||||
namespace Gfx {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue