|
@@ -235,6 +235,128 @@ static SkColor4f to_skia_color4f(Gfx::Color const& color)
|
|
|
};
|
|
|
}
|
|
|
|
|
|
+static sk_sp<SkImageFilter> to_skia_image_filter(CSS::ResolvedFilter::FilterFunction const& function)
|
|
|
+{
|
|
|
+ // See: https://drafts.fxtf.org/filter-effects-1/#supported-filter-functions
|
|
|
+ return function.visit(
|
|
|
+ [&](CSS::ResolvedFilter::Blur const& blur_filter) {
|
|
|
+ return SkImageFilters::Blur(blur_filter.radius, blur_filter.radius, nullptr);
|
|
|
+ },
|
|
|
+ [&](CSS::ResolvedFilter::Color const& color) {
|
|
|
+ auto amount = clamp(color.amount, 0.0f, 1.0f);
|
|
|
+
|
|
|
+ // Matrices are taken from https://drafts.fxtf.org/filter-effects-1/#FilterPrimitiveRepresentation
|
|
|
+ sk_sp<SkColorFilter> color_filter;
|
|
|
+ switch (color.type) {
|
|
|
+ case CSS::FilterOperation::Color::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
|
|
|
+ };
|
|
|
+ color_filter = SkColorFilters::Matrix(matrix);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case CSS::FilterOperation::Color::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
|
|
|
+ };
|
|
|
+ color_filter = SkColorFilters::Matrix(matrix);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case CSS::FilterOperation::Color::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
|
|
|
+ };
|
|
|
+ color_filter = SkColorFilters::Matrix(matrix);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case CSS::FilterOperation::Color::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
|
|
|
+ };
|
|
|
+ color_filter = SkColorFilters::Matrix(matrix);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case CSS::FilterOperation::Color::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
|
|
|
+ };
|
|
|
+ color_filter = SkColorFilters::Matrix(matrix);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case CSS::FilterOperation::Color::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
|
|
|
+ };
|
|
|
+ color_filter = SkColorFilters::Matrix(matrix);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case CSS::FilterOperation::Color::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
|
|
|
+ };
|
|
|
+ color_filter = SkColorFilters::Matrix(matrix);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ VERIFY_NOT_REACHED();
|
|
|
+ }
|
|
|
+
|
|
|
+ return SkImageFilters::ColorFilter(color_filter, nullptr);
|
|
|
+ },
|
|
|
+ [&](CSS::ResolvedFilter::HueRotate const& hue_rotate) {
|
|
|
+ float radians = AK::to_radians(hue_rotate.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);
|
|
|
+ return SkImageFilters::ColorFilter(color_filter, nullptr);
|
|
|
+ },
|
|
|
+ [&](CSS::ResolvedFilter::DropShadow const&) {
|
|
|
+ dbgln("TODO: Implement drop-shadow() filter function!");
|
|
|
+ return sk_sp<SkImageFilter> {};
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
static SkPath to_skia_path(Gfx::Path const& path)
|
|
|
{
|
|
|
return static_cast<Gfx::PathImplSkia const&>(path.impl()).sk_path();
|
|
@@ -444,7 +566,33 @@ void DisplayListPlayerSkia::push_stacking_context(PushStackingContext const& com
|
|
|
.translate(-command.transform.origin);
|
|
|
auto matrix = to_skia_matrix(new_transform);
|
|
|
|
|
|
- if (command.opacity < 1) {
|
|
|
+ if (!command.filter.is_none()) {
|
|
|
+ sk_sp<SkImageFilter> image_filter;
|
|
|
+ auto append_filter = [&image_filter](auto new_filter) {
|
|
|
+ if (image_filter)
|
|
|
+ image_filter = SkImageFilters::Compose(new_filter, image_filter);
|
|
|
+ else
|
|
|
+ image_filter = new_filter;
|
|
|
+ };
|
|
|
+
|
|
|
+ // Apply filters in order
|
|
|
+ for (auto const& filter_function : command.filter.filters)
|
|
|
+ append_filter(to_skia_image_filter(filter_function));
|
|
|
+
|
|
|
+ // We apply opacity as a color filter here so we only need to save and restore a single layer.
|
|
|
+ if (command.opacity < 1) {
|
|
|
+ append_filter(to_skia_image_filter(CSS::ResolvedFilter::FilterFunction {
|
|
|
+ CSS::ResolvedFilter::Color {
|
|
|
+ CSS::FilterOperation::Color::Type::Opacity,
|
|
|
+ command.opacity,
|
|
|
+ },
|
|
|
+ }));
|
|
|
+ }
|
|
|
+
|
|
|
+ SkPaint paint;
|
|
|
+ paint.setImageFilter(image_filter);
|
|
|
+ canvas.saveLayer(nullptr, &paint);
|
|
|
+ } else if (command.opacity < 1) {
|
|
|
auto source_paintable_rect = to_skia_rect(command.source_paintable_rect);
|
|
|
SkRect dest;
|
|
|
matrix.mapRect(&dest, source_paintable_rect);
|
|
@@ -453,9 +601,8 @@ void DisplayListPlayerSkia::push_stacking_context(PushStackingContext const& com
|
|
|
canvas.save();
|
|
|
}
|
|
|
|
|
|
- if (command.clip_path.has_value()) {
|
|
|
+ if (command.clip_path.has_value())
|
|
|
canvas.clipPath(to_skia_path(command.clip_path.value()), true);
|
|
|
- }
|
|
|
|
|
|
canvas.concat(matrix);
|
|
|
}
|
|
@@ -962,129 +1109,9 @@ void DisplayListPlayerSkia::apply_backdrop_filter(ApplyBackdropFilter const& com
|
|
|
ScopeGuard guard = [&] { canvas.restore(); };
|
|
|
|
|
|
for (auto const& filter_function : command.backdrop_filter.filters) {
|
|
|
- // See: https://drafts.fxtf.org/filter-effects-1/#supported-filter-functions
|
|
|
- filter_function.visit(
|
|
|
- [&](CSS::ResolvedFilter::Blur const& blur_filter) {
|
|
|
- auto blur_image_filter = SkImageFilters::Blur(blur_filter.radius, blur_filter.radius, nullptr);
|
|
|
- canvas.saveLayer(SkCanvas::SaveLayerRec(nullptr, nullptr, blur_image_filter.get(), 0));
|
|
|
- canvas.restore();
|
|
|
- },
|
|
|
- [&](CSS::ResolvedFilter::Color const& color) {
|
|
|
- auto amount = clamp(color.amount, 0.0f, 1.0f);
|
|
|
-
|
|
|
- // Matrices are taken from https://drafts.fxtf.org/filter-effects-1/#FilterPrimitiveRepresentation
|
|
|
- sk_sp<SkColorFilter> color_filter;
|
|
|
- switch (color.type) {
|
|
|
- case CSS::FilterOperation::Color::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
|
|
|
- };
|
|
|
- color_filter = SkColorFilters::Matrix(matrix);
|
|
|
- break;
|
|
|
- }
|
|
|
- case CSS::FilterOperation::Color::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
|
|
|
- };
|
|
|
- color_filter = SkColorFilters::Matrix(matrix);
|
|
|
- break;
|
|
|
- }
|
|
|
- case CSS::FilterOperation::Color::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
|
|
|
- };
|
|
|
- color_filter = SkColorFilters::Matrix(matrix);
|
|
|
- break;
|
|
|
- }
|
|
|
- case CSS::FilterOperation::Color::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
|
|
|
- };
|
|
|
- color_filter = SkColorFilters::Matrix(matrix);
|
|
|
- break;
|
|
|
- }
|
|
|
- case CSS::FilterOperation::Color::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
|
|
|
- };
|
|
|
- color_filter = SkColorFilters::Matrix(matrix);
|
|
|
- break;
|
|
|
- }
|
|
|
- case CSS::FilterOperation::Color::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
|
|
|
- };
|
|
|
- color_filter = SkColorFilters::Matrix(matrix);
|
|
|
- break;
|
|
|
- }
|
|
|
- case CSS::FilterOperation::Color::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
|
|
|
- };
|
|
|
- color_filter = SkColorFilters::Matrix(matrix);
|
|
|
- break;
|
|
|
- }
|
|
|
- default:
|
|
|
- VERIFY_NOT_REACHED();
|
|
|
- }
|
|
|
-
|
|
|
- auto image_filter = SkImageFilters::ColorFilter(color_filter, nullptr);
|
|
|
- canvas.saveLayer(SkCanvas::SaveLayerRec(nullptr, nullptr, image_filter.get(), 0));
|
|
|
- canvas.restore();
|
|
|
- },
|
|
|
- [&](CSS::ResolvedFilter::HueRotate const& hue_rotate) {
|
|
|
- float radians = AK::to_radians(hue_rotate.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);
|
|
|
- auto image_filter = SkImageFilters::ColorFilter(color_filter, nullptr);
|
|
|
- canvas.saveLayer(SkCanvas::SaveLayerRec(nullptr, nullptr, image_filter.get(), 0));
|
|
|
- canvas.restore();
|
|
|
- },
|
|
|
- [&](CSS::ResolvedFilter::DropShadow const&) {
|
|
|
- dbgln("TODO: Implement drop-shadow() filter function!");
|
|
|
- });
|
|
|
+ auto image_filter = to_skia_image_filter(filter_function);
|
|
|
+ canvas.saveLayer(SkCanvas::SaveLayerRec(nullptr, nullptr, image_filter.get(), 0));
|
|
|
+ canvas.restore();
|
|
|
}
|
|
|
}
|
|
|
|