mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-02 15:46:33 +00:00
LibGfx+LibWeb: Remove everything in LibGfx/Filters
These are no longer needed after switching to use Skia for web page painting.
This commit is contained in:
parent
ba56cb6e51
commit
44e23dce77
Notes:
github-actions[bot]
2024-07-21 17:31:47 +00:00
Author: https://github.com/kalenikaliaksandr
Commit: 44e23dce77
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/754
29 changed files with 0 additions and 1471 deletions
|
@ -6,10 +6,6 @@ set(SOURCES
|
||||||
Color.cpp
|
Color.cpp
|
||||||
DeltaE.cpp
|
DeltaE.cpp
|
||||||
EdgeFlagPathRasterizer.cpp
|
EdgeFlagPathRasterizer.cpp
|
||||||
Filters/ColorBlindnessFilter.cpp
|
|
||||||
Filters/FastBoxBlurFilter.cpp
|
|
||||||
Filters/LumaFilter.cpp
|
|
||||||
Filters/StackBlurFilter.cpp
|
|
||||||
FontCascadeList.cpp
|
FontCascadeList.cpp
|
||||||
Font/Emoji.cpp
|
Font/Emoji.cpp
|
||||||
Font/Font.cpp
|
Font/Font.cpp
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020, the SerenityOS developers.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "GenericConvolutionFilter.h"
|
|
||||||
#include <AK/StringView.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
|
||||||
|
|
||||||
template<size_t N>
|
|
||||||
class BoxBlurFilter : public GenericConvolutionFilter<N> {
|
|
||||||
public:
|
|
||||||
BoxBlurFilter() = default;
|
|
||||||
virtual ~BoxBlurFilter() = default;
|
|
||||||
|
|
||||||
virtual StringView class_name() const override { return "BoxBlurFilter"sv; }
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2022, MacDue <macdue@dueutil.tech>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <AK/StringView.h>
|
|
||||||
#include <LibGfx/Filters/ColorFilter.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
|
||||||
|
|
||||||
class BrightnessFilter : public ColorFilter {
|
|
||||||
public:
|
|
||||||
using ColorFilter::ColorFilter;
|
|
||||||
virtual ~BrightnessFilter() = default;
|
|
||||||
|
|
||||||
virtual StringView class_name() const override { return "BrightnessFilter"sv; }
|
|
||||||
|
|
||||||
virtual bool amount_handled_in_filter() const override
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
Color convert_color(Color original) override
|
|
||||||
{
|
|
||||||
auto convert_channel = [&](u8 channel) {
|
|
||||||
return static_cast<u8>(clamp(round_to<int>(channel * m_amount), 0, 255));
|
|
||||||
};
|
|
||||||
return Gfx::Color {
|
|
||||||
convert_channel(original.red()),
|
|
||||||
convert_channel(original.green()),
|
|
||||||
convert_channel(original.blue()),
|
|
||||||
original.alpha()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,84 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2021, Antonio Di Stefano <tonio9681@gmail.com>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "ColorBlindnessFilter.h"
|
|
||||||
|
|
||||||
namespace Gfx {
|
|
||||||
|
|
||||||
NonnullOwnPtr<ColorBlindnessFilter> ColorBlindnessFilter::create_protanopia()
|
|
||||||
{
|
|
||||||
return make<ColorBlindnessFilter>(
|
|
||||||
.56, .44, .0,
|
|
||||||
.55, .45, .0,
|
|
||||||
.0, .24, .76);
|
|
||||||
}
|
|
||||||
|
|
||||||
NonnullOwnPtr<ColorBlindnessFilter> ColorBlindnessFilter::create_protanomaly()
|
|
||||||
{
|
|
||||||
return make<ColorBlindnessFilter>(
|
|
||||||
.82, .18, .0,
|
|
||||||
.33, .67, .0,
|
|
||||||
.0, .13, .87);
|
|
||||||
}
|
|
||||||
|
|
||||||
NonnullOwnPtr<ColorBlindnessFilter> ColorBlindnessFilter::create_deuteranopia()
|
|
||||||
{
|
|
||||||
return make<ColorBlindnessFilter>(
|
|
||||||
.63, .37, .0,
|
|
||||||
.7, .3, .0,
|
|
||||||
.0, .3, .7);
|
|
||||||
}
|
|
||||||
|
|
||||||
NonnullOwnPtr<ColorBlindnessFilter> ColorBlindnessFilter::create_deuteranomaly()
|
|
||||||
{
|
|
||||||
return make<ColorBlindnessFilter>(
|
|
||||||
.8, .2, .0,
|
|
||||||
.26, .74, .0,
|
|
||||||
.0, .15, .85);
|
|
||||||
}
|
|
||||||
|
|
||||||
NonnullOwnPtr<ColorBlindnessFilter> ColorBlindnessFilter::create_tritanopia()
|
|
||||||
{
|
|
||||||
return make<ColorBlindnessFilter>(
|
|
||||||
.95, .05, .0,
|
|
||||||
.0, .44, .56,
|
|
||||||
.0, .48, .52);
|
|
||||||
}
|
|
||||||
|
|
||||||
NonnullOwnPtr<ColorBlindnessFilter> ColorBlindnessFilter::create_tritanomaly()
|
|
||||||
{
|
|
||||||
return make<ColorBlindnessFilter>(
|
|
||||||
.97, .03, .0,
|
|
||||||
.0, .73, .27,
|
|
||||||
.0, .18, .82);
|
|
||||||
}
|
|
||||||
|
|
||||||
NonnullOwnPtr<ColorBlindnessFilter> ColorBlindnessFilter::create_achromatopsia()
|
|
||||||
{
|
|
||||||
return make<ColorBlindnessFilter>(
|
|
||||||
.3, .59, .11,
|
|
||||||
.3, .59, .11,
|
|
||||||
.3, .59, .11);
|
|
||||||
}
|
|
||||||
|
|
||||||
NonnullOwnPtr<ColorBlindnessFilter> ColorBlindnessFilter::create_achromatomaly()
|
|
||||||
{
|
|
||||||
return make<ColorBlindnessFilter>(
|
|
||||||
.62, .32, .06,
|
|
||||||
.16, .78, .06,
|
|
||||||
.16, .32, .52);
|
|
||||||
}
|
|
||||||
|
|
||||||
Color ColorBlindnessFilter::convert_color(Color original)
|
|
||||||
{
|
|
||||||
return Color(
|
|
||||||
(u8)(original.red() * m_red_in_red_band + original.green() * m_green_in_red_band + original.blue() * m_blue_in_red_band),
|
|
||||||
(u8)(original.red() * m_red_in_green_band + original.green() * m_green_in_green_band + original.blue() * m_blue_in_green_band),
|
|
||||||
(u8)(original.red() * m_red_in_blue_band + original.green() * m_green_in_blue_band + original.blue() * m_blue_in_blue_band),
|
|
||||||
original.alpha());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,64 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2021, Antonio Di Stefano <tonio9681@gmail.com>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "ColorFilter.h"
|
|
||||||
#include <AK/NonnullOwnPtr.h>
|
|
||||||
#include <AK/StringView.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
|
||||||
class ColorBlindnessFilter : public ColorFilter {
|
|
||||||
public:
|
|
||||||
ColorBlindnessFilter(
|
|
||||||
double red_in_red_band,
|
|
||||||
double green_in_red_band,
|
|
||||||
double blue_in_red_band,
|
|
||||||
double red_in_green_band,
|
|
||||||
double green_in_green_band,
|
|
||||||
double blue_in_green_band,
|
|
||||||
double red_in_blue_band,
|
|
||||||
double green_in_blue_band,
|
|
||||||
double blue_in_blue_band)
|
|
||||||
: m_red_in_red_band(red_in_red_band)
|
|
||||||
, m_green_in_red_band(green_in_red_band)
|
|
||||||
, m_blue_in_red_band(blue_in_red_band)
|
|
||||||
, m_red_in_green_band(red_in_green_band)
|
|
||||||
, m_green_in_green_band(green_in_green_band)
|
|
||||||
, m_blue_in_green_band(blue_in_green_band)
|
|
||||||
, m_red_in_blue_band(red_in_blue_band)
|
|
||||||
, m_green_in_blue_band(green_in_blue_band)
|
|
||||||
, m_blue_in_blue_band(blue_in_blue_band)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~ColorBlindnessFilter() = default;
|
|
||||||
virtual StringView class_name() const override { return "ColorBlindnessFilter"sv; }
|
|
||||||
|
|
||||||
static NonnullOwnPtr<ColorBlindnessFilter> create_protanopia();
|
|
||||||
static NonnullOwnPtr<ColorBlindnessFilter> create_protanomaly();
|
|
||||||
static NonnullOwnPtr<ColorBlindnessFilter> create_deuteranopia();
|
|
||||||
static NonnullOwnPtr<ColorBlindnessFilter> create_deuteranomaly();
|
|
||||||
static NonnullOwnPtr<ColorBlindnessFilter> create_tritanopia();
|
|
||||||
static NonnullOwnPtr<ColorBlindnessFilter> create_tritanomaly();
|
|
||||||
static NonnullOwnPtr<ColorBlindnessFilter> create_achromatopsia();
|
|
||||||
static NonnullOwnPtr<ColorBlindnessFilter> create_achromatomaly();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
Color convert_color(Color original) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
double m_red_in_red_band;
|
|
||||||
double m_green_in_red_band;
|
|
||||||
double m_blue_in_red_band;
|
|
||||||
double m_red_in_green_band;
|
|
||||||
double m_green_in_green_band;
|
|
||||||
double m_blue_in_green_band;
|
|
||||||
double m_red_in_blue_band;
|
|
||||||
double m_green_in_blue_band;
|
|
||||||
double m_blue_in_blue_band;
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2021, Antonio Di Stefano <tonio9681@gmail.com>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Filter.h"
|
|
||||||
|
|
||||||
namespace Gfx {
|
|
||||||
|
|
||||||
class ColorFilter : public Filter {
|
|
||||||
public:
|
|
||||||
ColorFilter(float amount = 1.0f)
|
|
||||||
: m_amount(amount)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~ColorFilter() = default;
|
|
||||||
|
|
||||||
virtual bool amount_handled_in_filter() const
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void apply(Bitmap& target_bitmap, IntRect const& target_rect, Bitmap const& source_bitmap, IntRect const& source_rect) override
|
|
||||||
{
|
|
||||||
VERIFY(source_rect.size() == target_rect.size());
|
|
||||||
VERIFY(target_bitmap.rect().contains(target_rect));
|
|
||||||
VERIFY(source_bitmap.rect().contains(source_rect));
|
|
||||||
|
|
||||||
for (auto y = 0; y < source_rect.height(); ++y) {
|
|
||||||
ssize_t source_y = y + source_rect.y();
|
|
||||||
ssize_t target_y = y + target_rect.y();
|
|
||||||
for (auto x = 0; x < source_rect.width(); ++x) {
|
|
||||||
ssize_t source_x = x + source_rect.x();
|
|
||||||
ssize_t target_x = x + target_rect.x();
|
|
||||||
|
|
||||||
auto source_pixel = source_bitmap.get_pixel(source_x, source_y);
|
|
||||||
auto target_color = convert_color(source_pixel);
|
|
||||||
|
|
||||||
target_bitmap.set_pixel(target_x, target_y, m_amount < 1.0f && !amount_handled_in_filter() ? source_pixel.mixed_with(target_color, m_amount) : target_color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual Color convert_color(Color) = 0;
|
|
||||||
float m_amount { 1.0f };
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2022, MacDue <macdue@dueutil.tech>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <AK/StringView.h>
|
|
||||||
#include <LibGfx/Filters/ColorFilter.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
|
||||||
|
|
||||||
class ContrastFilter : public ColorFilter {
|
|
||||||
public:
|
|
||||||
using ColorFilter::ColorFilter;
|
|
||||||
virtual ~ContrastFilter() = default;
|
|
||||||
|
|
||||||
virtual StringView class_name() const override { return "ContrastFilter"sv; }
|
|
||||||
|
|
||||||
virtual bool amount_handled_in_filter() const override
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
Color convert_color(Color original) override
|
|
||||||
{
|
|
||||||
auto convert_channel = [&](u8 channel) {
|
|
||||||
return static_cast<u8>(clamp(round_to<int>(channel * m_amount + (-128 * m_amount) + 128), 0, 255));
|
|
||||||
};
|
|
||||||
return Gfx::Color {
|
|
||||||
convert_channel(original.red()),
|
|
||||||
convert_channel(original.green()),
|
|
||||||
convert_channel(original.blue()),
|
|
||||||
original.alpha()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,182 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2021, Tobias Christiansen <tobyase@serenityos.org>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(AK_COMPILER_GCC)
|
|
||||||
# pragma GCC optimize("O3")
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <AK/Function.h>
|
|
||||||
#include <AK/Vector.h>
|
|
||||||
#include <LibGfx/Filters/FastBoxBlurFilter.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
|
||||||
|
|
||||||
ALWAYS_INLINE static constexpr u8 red_value(Color color)
|
|
||||||
{
|
|
||||||
return (color.alpha() == 0) ? 0xFF : color.red();
|
|
||||||
}
|
|
||||||
ALWAYS_INLINE static constexpr u8 green_value(Color color)
|
|
||||||
{
|
|
||||||
return (color.alpha() == 0) ? 0xFF : color.green();
|
|
||||||
}
|
|
||||||
ALWAYS_INLINE static constexpr u8 blue_value(Color color)
|
|
||||||
{
|
|
||||||
return (color.alpha() == 0) ? 0xFF : color.blue();
|
|
||||||
}
|
|
||||||
|
|
||||||
FastBoxBlurFilter::FastBoxBlurFilter(Bitmap& bitmap)
|
|
||||||
: m_bitmap(bitmap)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void FastBoxBlurFilter::apply_single_pass(size_t radius)
|
|
||||||
{
|
|
||||||
apply_single_pass(radius, radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename GetPixelFunction, typename SetPixelFunction>
|
|
||||||
static void do_single_pass(int width, int height, size_t radius_x, size_t radius_y, GetPixelFunction get_pixel_function, SetPixelFunction set_pixel_function)
|
|
||||||
{
|
|
||||||
int div_x = 2 * radius_x + 1;
|
|
||||||
int div_y = 2 * radius_y + 1;
|
|
||||||
|
|
||||||
Vector<Color, 1024> intermediate;
|
|
||||||
intermediate.resize(width * height);
|
|
||||||
|
|
||||||
// First pass: vertical
|
|
||||||
for (int y = 0; y < height; ++y) {
|
|
||||||
size_t sum_red = 0;
|
|
||||||
size_t sum_green = 0;
|
|
||||||
size_t sum_blue = 0;
|
|
||||||
size_t sum_alpha = 0;
|
|
||||||
|
|
||||||
// Setup sliding window
|
|
||||||
for (int i = -(int)radius_x; i <= (int)radius_x; ++i) {
|
|
||||||
auto color_at_px = get_pixel_function(clamp(i, 0, width - 1), y);
|
|
||||||
sum_red += red_value(color_at_px);
|
|
||||||
sum_green += green_value(color_at_px);
|
|
||||||
sum_blue += blue_value(color_at_px);
|
|
||||||
sum_alpha += color_at_px.alpha();
|
|
||||||
}
|
|
||||||
// Slide horizontally
|
|
||||||
for (int x = 0; x < width; ++x) {
|
|
||||||
auto const index = y * width + x;
|
|
||||||
auto& current_intermediate = intermediate[index];
|
|
||||||
current_intermediate.set_red(sum_red / div_x);
|
|
||||||
current_intermediate.set_green(sum_green / div_x);
|
|
||||||
current_intermediate.set_blue(sum_blue / div_x);
|
|
||||||
current_intermediate.set_alpha(sum_alpha / div_x);
|
|
||||||
|
|
||||||
auto leftmost_x_coord = max(x - (int)radius_x, 0);
|
|
||||||
auto rightmost_x_coord = min(x + (int)radius_x + 1, width - 1);
|
|
||||||
|
|
||||||
auto leftmost_x_color = get_pixel_function(leftmost_x_coord, y);
|
|
||||||
auto rightmost_x_color = get_pixel_function(rightmost_x_coord, y);
|
|
||||||
|
|
||||||
sum_red -= red_value(leftmost_x_color);
|
|
||||||
sum_red += red_value(rightmost_x_color);
|
|
||||||
sum_green -= green_value(leftmost_x_color);
|
|
||||||
sum_green += green_value(rightmost_x_color);
|
|
||||||
sum_blue -= blue_value(leftmost_x_color);
|
|
||||||
sum_blue += blue_value(rightmost_x_color);
|
|
||||||
sum_alpha -= leftmost_x_color.alpha();
|
|
||||||
sum_alpha += rightmost_x_color.alpha();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Second pass: horizontal
|
|
||||||
for (int x = 0; x < width; ++x) {
|
|
||||||
size_t sum_red = 0;
|
|
||||||
size_t sum_green = 0;
|
|
||||||
size_t sum_blue = 0;
|
|
||||||
size_t sum_alpha = 0;
|
|
||||||
|
|
||||||
// Setup sliding window
|
|
||||||
for (int i = -(int)radius_y; i <= (int)radius_y; ++i) {
|
|
||||||
int offset = clamp(i, 0, height - 1) * width + x;
|
|
||||||
auto& current_intermediate = intermediate[offset];
|
|
||||||
sum_red += current_intermediate.red();
|
|
||||||
sum_green += current_intermediate.green();
|
|
||||||
sum_blue += current_intermediate.blue();
|
|
||||||
sum_alpha += current_intermediate.alpha();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int y = 0; y < height; ++y) {
|
|
||||||
auto color = Color(
|
|
||||||
sum_red / div_y,
|
|
||||||
sum_green / div_y,
|
|
||||||
sum_blue / div_y,
|
|
||||||
sum_alpha / div_y);
|
|
||||||
|
|
||||||
set_pixel_function(x, y, color);
|
|
||||||
|
|
||||||
auto const bottommost_y_coord = min(y + (int)radius_y + 1, height - 1);
|
|
||||||
auto const bottom_index = x + bottommost_y_coord * width;
|
|
||||||
auto& bottom_intermediate = intermediate[bottom_index];
|
|
||||||
sum_red += bottom_intermediate.red();
|
|
||||||
sum_green += bottom_intermediate.green();
|
|
||||||
sum_blue += bottom_intermediate.blue();
|
|
||||||
sum_alpha += bottom_intermediate.alpha();
|
|
||||||
|
|
||||||
auto const topmost_y_coord = max(y - (int)radius_y, 0);
|
|
||||||
auto const top_index = x + topmost_y_coord * width;
|
|
||||||
auto& top_intermediate = intermediate[top_index];
|
|
||||||
sum_red -= top_intermediate.red();
|
|
||||||
sum_green -= top_intermediate.green();
|
|
||||||
sum_blue -= top_intermediate.blue();
|
|
||||||
sum_alpha -= top_intermediate.alpha();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Based on the super fast blur algorithm by Quasimondo, explored here: https://stackoverflow.com/questions/21418892/understanding-super-fast-blur-algorithm
|
|
||||||
FLATTEN void FastBoxBlurFilter::apply_single_pass(size_t radius_x, size_t radius_y)
|
|
||||||
{
|
|
||||||
auto format = m_bitmap.format();
|
|
||||||
VERIFY(format == BitmapFormat::BGRA8888 || format == BitmapFormat::BGRx8888);
|
|
||||||
|
|
||||||
switch (format) {
|
|
||||||
case BitmapFormat::BGRx8888:
|
|
||||||
do_single_pass(
|
|
||||||
m_bitmap.width(), m_bitmap.height(), radius_x, radius_y,
|
|
||||||
[&](int x, int y) { return m_bitmap.get_pixel<StorageFormat::BGRx8888>(x, y); },
|
|
||||||
[&](int x, int y, Color color) { return m_bitmap.set_pixel<StorageFormat::BGRx8888>(x, y, color); });
|
|
||||||
break;
|
|
||||||
case BitmapFormat::BGRA8888:
|
|
||||||
do_single_pass(
|
|
||||||
m_bitmap.width(), m_bitmap.height(), radius_x, radius_y,
|
|
||||||
[&](int x, int y) { return m_bitmap.get_pixel<StorageFormat::BGRA8888>(x, y); },
|
|
||||||
[&](int x, int y, Color color) { return m_bitmap.set_pixel<StorageFormat::BGRA8888>(x, y, color); });
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
VERIFY_NOT_REACHED();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Math from here: http://blog.ivank.net/fastest-gaussian-blur.html
|
|
||||||
void FastBoxBlurFilter::apply_three_passes(size_t radius)
|
|
||||||
{
|
|
||||||
if (!radius)
|
|
||||||
return;
|
|
||||||
|
|
||||||
constexpr size_t no_of_passes = 3;
|
|
||||||
double w_ideal = sqrt((12 * radius * radius / (double)no_of_passes) + 1);
|
|
||||||
int wl = floor(w_ideal);
|
|
||||||
if (wl % 2 == 0)
|
|
||||||
wl--;
|
|
||||||
int wu = wl - 2;
|
|
||||||
double m_ideal = (12 * radius * radius - no_of_passes * wl * wl - 4 * no_of_passes * wl - 3 * no_of_passes) / (double)(-4 * wl - 4);
|
|
||||||
int m = round(m_ideal);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < no_of_passes; ++i) {
|
|
||||||
int weighted_radius = (int)i < m ? wl : wu;
|
|
||||||
if (weighted_radius < 2)
|
|
||||||
continue;
|
|
||||||
apply_single_pass((weighted_radius - 1) / 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2021, Tobias Christiansen <tobyase@serenityos.org>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <LibGfx/Bitmap.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
|
||||||
|
|
||||||
class FastBoxBlurFilter {
|
|
||||||
public:
|
|
||||||
FastBoxBlurFilter(Bitmap&);
|
|
||||||
|
|
||||||
void apply_single_pass(size_t radius);
|
|
||||||
void apply_single_pass(size_t radius_x, size_t radius_y);
|
|
||||||
|
|
||||||
void apply_three_passes(size_t radius);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Bitmap& m_bitmap;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020, the SerenityOS developers.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <AK/StringView.h>
|
|
||||||
#include <LibGfx/Bitmap.h>
|
|
||||||
#include <LibGfx/Rect.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
|
||||||
|
|
||||||
class Filter {
|
|
||||||
public:
|
|
||||||
class Parameters {
|
|
||||||
public:
|
|
||||||
virtual bool is_generic_convolution_filter() const { return false; }
|
|
||||||
|
|
||||||
virtual ~Parameters() = default;
|
|
||||||
};
|
|
||||||
virtual ~Filter() = default;
|
|
||||||
|
|
||||||
virtual StringView class_name() const = 0;
|
|
||||||
|
|
||||||
virtual void apply(Bitmap&, IntRect const&, Bitmap const&, IntRect const&, Parameters const&) {};
|
|
||||||
virtual void apply(Bitmap&, IntRect const&, Bitmap const&, IntRect const&) {};
|
|
||||||
|
|
||||||
protected:
|
|
||||||
Filter() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,154 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020, the SerenityOS developers.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Filter.h"
|
|
||||||
#include <AK/StringView.h>
|
|
||||||
#include <LibGfx/Matrix.h>
|
|
||||||
#include <LibGfx/Matrix4x4.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
|
||||||
|
|
||||||
template<size_t N, typename T>
|
|
||||||
static constexpr void normalize(Matrix<N, T>& matrix)
|
|
||||||
{
|
|
||||||
auto sum = 0.0f;
|
|
||||||
for (size_t i = 0; i < matrix.Size; ++i) {
|
|
||||||
for (size_t j = 0; j < matrix.Size; ++j) {
|
|
||||||
sum += matrix.elements()[i][j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < matrix.Size; ++i) {
|
|
||||||
for (size_t j = 0; j < matrix.Size; ++j) {
|
|
||||||
matrix.elements()[i][j] /= sum;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<size_t N>
|
|
||||||
class GenericConvolutionFilter : public Filter {
|
|
||||||
public:
|
|
||||||
class Parameters : public Filter::Parameters {
|
|
||||||
public:
|
|
||||||
Parameters(Gfx::Matrix<N, float> const& kernel, bool should_wrap = true)
|
|
||||||
: m_kernel(kernel)
|
|
||||||
, m_should_wrap(should_wrap)
|
|
||||||
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Gfx::Matrix<N, float> const& kernel() const { return m_kernel; }
|
|
||||||
Gfx::Matrix<N, float>& kernel() { return m_kernel; }
|
|
||||||
bool should_wrap() const { return m_should_wrap; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
virtual bool is_generic_convolution_filter() const override { return true; }
|
|
||||||
Gfx::Matrix<N, float> m_kernel;
|
|
||||||
bool m_should_wrap { false };
|
|
||||||
};
|
|
||||||
|
|
||||||
class ApplyCache {
|
|
||||||
template<size_t>
|
|
||||||
friend class GenericConvolutionFilter;
|
|
||||||
|
|
||||||
private:
|
|
||||||
RefPtr<Gfx::Bitmap> m_target;
|
|
||||||
};
|
|
||||||
|
|
||||||
GenericConvolutionFilter() = default;
|
|
||||||
virtual ~GenericConvolutionFilter() = default;
|
|
||||||
|
|
||||||
virtual StringView class_name() const override { return "GenericConvolutionFilter"sv; }
|
|
||||||
|
|
||||||
virtual void apply(Bitmap& target_bitmap, IntRect const& target_rect, Bitmap const& source_bitmap, IntRect const& source_rect, Filter::Parameters const& parameters) override
|
|
||||||
{
|
|
||||||
VERIFY(parameters.is_generic_convolution_filter());
|
|
||||||
auto& gcf_params = static_cast<GenericConvolutionFilter::Parameters const&>(parameters);
|
|
||||||
|
|
||||||
ApplyCache apply_cache;
|
|
||||||
apply_with_cache(target_bitmap, target_rect, source_bitmap, source_rect, gcf_params, apply_cache);
|
|
||||||
}
|
|
||||||
|
|
||||||
void apply_with_cache(Bitmap& target, IntRect target_rect, Bitmap const& source, IntRect const& source_rect, GenericConvolutionFilter::Parameters const& parameters, ApplyCache& apply_cache)
|
|
||||||
{
|
|
||||||
// The target area (where the filter is applied) must be entirely
|
|
||||||
// contained by the source area. source_rect should be describing
|
|
||||||
// the pixels that can be accessed to apply this filter, while
|
|
||||||
// target_rect should describe the area where to apply the filter on.
|
|
||||||
VERIFY(source_rect.contains(target_rect));
|
|
||||||
VERIFY(source.size().contains(target.size()));
|
|
||||||
VERIFY(target.rect().contains(target_rect));
|
|
||||||
VERIFY(source.rect().contains(source_rect));
|
|
||||||
|
|
||||||
// If source is different from target, it should still be describing
|
|
||||||
// essentially the same bitmap. But it allows us to modify target
|
|
||||||
// without a temporary bitmap. This is important if this filter
|
|
||||||
// is applied on multiple areas of the same bitmap, at which point
|
|
||||||
// we would need to be able to access unmodified pixels if the
|
|
||||||
// areas are (almost) adjacent.
|
|
||||||
int source_delta_x = target_rect.x() - source_rect.x();
|
|
||||||
int source_delta_y = target_rect.y() - source_rect.y();
|
|
||||||
if (&target == &source && (!apply_cache.m_target || !apply_cache.m_target->size().contains(source_rect.size()))) {
|
|
||||||
// TODO: We probably don't need the entire source_rect, we could inflate
|
|
||||||
// the target_rect appropriately
|
|
||||||
apply_cache.m_target = Gfx::Bitmap::create(source.format(), source_rect.size()).release_value_but_fixme_should_propagate_errors();
|
|
||||||
target_rect.translate_by(-target_rect.location());
|
|
||||||
}
|
|
||||||
|
|
||||||
Bitmap* render_target_bitmap = (&target != &source) ? &target : apply_cache.m_target.ptr();
|
|
||||||
|
|
||||||
// FIXME: Help! I am naive!
|
|
||||||
constexpr static ssize_t offset = N / 2;
|
|
||||||
for (auto i_ = 0; i_ < target_rect.width(); ++i_) {
|
|
||||||
ssize_t i = i_ + target_rect.x();
|
|
||||||
for (auto j_ = 0; j_ < target_rect.height(); ++j_) {
|
|
||||||
ssize_t j = j_ + target_rect.y();
|
|
||||||
FloatVector3 value(0, 0, 0);
|
|
||||||
for (auto k = 0l; k < (ssize_t)N; ++k) {
|
|
||||||
auto ki = i + k - offset;
|
|
||||||
if (ki < source_rect.x() || ki >= source_rect.right()) {
|
|
||||||
if (parameters.should_wrap())
|
|
||||||
ki = (ki + source.size().width()) % source.size().width(); // TODO: fix up using source_rect
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto l = 0l; l < (ssize_t)N; ++l) {
|
|
||||||
auto lj = j + l - offset;
|
|
||||||
if (lj < source_rect.y() || lj >= source_rect.bottom()) {
|
|
||||||
if (parameters.should_wrap())
|
|
||||||
lj = (lj + source.size().height()) % source.size().height(); // TODO: fix up using source_rect
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto pixel = source.get_pixel(ki, lj);
|
|
||||||
FloatVector3 pixel_value(pixel.red(), pixel.green(), pixel.blue());
|
|
||||||
|
|
||||||
value = value + pixel_value * parameters.kernel().elements()[k][l];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
value.clamp(0, 255);
|
|
||||||
render_target_bitmap->set_pixel(i, j, Color(value.x(), value.y(), value.z(), source.get_pixel(i + source_delta_x, j + source_delta_y).alpha()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (render_target_bitmap != &target) {
|
|
||||||
// FIXME: Substitute for some sort of faster "blit" method.
|
|
||||||
for (auto i_ = 0; i_ < target_rect.width(); ++i_) {
|
|
||||||
auto i = i_ + target_rect.x();
|
|
||||||
for (auto j_ = 0; j_ < target_rect.height(); ++j_) {
|
|
||||||
auto j = j_ + target_rect.y();
|
|
||||||
target.set_pixel(i, j, render_target_bitmap->get_pixel(i_, j_));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2021, David Savary <david.savarymartinez@gmail.com>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <AK/StringView.h>
|
|
||||||
#include <LibGfx/Filters/ColorFilter.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
|
||||||
|
|
||||||
class GrayscaleFilter : public ColorFilter {
|
|
||||||
public:
|
|
||||||
using ColorFilter::ColorFilter;
|
|
||||||
virtual ~GrayscaleFilter() = default;
|
|
||||||
|
|
||||||
virtual StringView class_name() const override { return "GrayscaleFilter"sv; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
Color convert_color(Color original) override { return original.to_grayscale(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2022, MacDue <macdue@dueutil.tech>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <LibGfx/Filters/MatrixFilter.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
|
||||||
|
|
||||||
class HueRotateFilter : public MatrixFilter {
|
|
||||||
public:
|
|
||||||
HueRotateFilter(float angle_degrees)
|
|
||||||
: MatrixFilter(calculate_hue_rotate_matrix(angle_degrees))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool amount_handled_in_filter() const override
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual StringView class_name() const override { return "HueRotateFilter"sv; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
static FloatMatrix3x3 calculate_hue_rotate_matrix(float angle_degrees)
|
|
||||||
{
|
|
||||||
float angle_rads = AK::to_radians(angle_degrees);
|
|
||||||
float cos_angle = 0;
|
|
||||||
float sin_angle = 0;
|
|
||||||
AK::sincos(angle_rads, sin_angle, cos_angle);
|
|
||||||
// The matrices here are taken directly from the SVG filter specification:
|
|
||||||
// https://drafts.fxtf.org/filter-effects-1/#feColorMatrixElement
|
|
||||||
// clang-format off
|
|
||||||
return FloatMatrix3x3 {
|
|
||||||
+0.213, +0.715, +0.072,
|
|
||||||
+0.213, +0.715, +0.072,
|
|
||||||
+0.213, +0.715, +0.072
|
|
||||||
} + cos_angle * FloatMatrix3x3 {
|
|
||||||
+0.787, -0.715, -0.072,
|
|
||||||
-0.213, +0.285, -0.072,
|
|
||||||
-0.213, -0.715, +0.928
|
|
||||||
} + sin_angle * FloatMatrix3x3 {
|
|
||||||
-0.213, -0.715, +0.928,
|
|
||||||
+0.143, +0.140, -0.283,
|
|
||||||
-0.787, +0.715, +0.072
|
|
||||||
};
|
|
||||||
// clang-format on
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2021, Musab Kılıç <musabkilic@protonmail.com>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <AK/StringView.h>
|
|
||||||
#include <LibGfx/Filters/ColorFilter.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
|
||||||
|
|
||||||
class InvertFilter : public ColorFilter {
|
|
||||||
public:
|
|
||||||
using ColorFilter::ColorFilter;
|
|
||||||
virtual ~InvertFilter() = default;
|
|
||||||
|
|
||||||
virtual StringView class_name() const override { return "InvertFilter"sv; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
Color convert_color(Color original) override { return original.inverted(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020, the SerenityOS developers.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "GenericConvolutionFilter.h"
|
|
||||||
#include <AK/StringView.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
|
||||||
|
|
||||||
class LaplacianFilter : public GenericConvolutionFilter<3> {
|
|
||||||
public:
|
|
||||||
LaplacianFilter() = default;
|
|
||||||
virtual ~LaplacianFilter() = default;
|
|
||||||
|
|
||||||
virtual StringView class_name() const override { return "LaplacianFilter"sv; }
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2022, Tobias Christiansen <tobyase@serenityos.org>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "LumaFilter.h"
|
|
||||||
namespace Gfx {
|
|
||||||
|
|
||||||
void LumaFilter::apply(u8 lower_bound, u8 upper_bound)
|
|
||||||
{
|
|
||||||
if (upper_bound < lower_bound)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int height = m_bitmap.height();
|
|
||||||
int width = m_bitmap.width();
|
|
||||||
|
|
||||||
auto format = m_bitmap.format();
|
|
||||||
VERIFY(format == BitmapFormat::BGRA8888 || format == BitmapFormat::BGRx8888);
|
|
||||||
|
|
||||||
for (int y = 0; y < height; ++y) {
|
|
||||||
for (int x = 0; x < width; ++x) {
|
|
||||||
Color color;
|
|
||||||
color = m_bitmap.get_pixel(x, y);
|
|
||||||
|
|
||||||
auto luma = color.luminosity();
|
|
||||||
if (lower_bound > luma || upper_bound < luma)
|
|
||||||
m_bitmap.set_pixel(x, y, { 0, 0, 0, color.alpha() });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2022, Tobias Christiansen <tobyase@serenityos.org>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <LibGfx/Bitmap.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
|
||||||
|
|
||||||
class LumaFilter {
|
|
||||||
public:
|
|
||||||
LumaFilter(Bitmap& bitmap)
|
|
||||||
: m_bitmap(bitmap) {};
|
|
||||||
|
|
||||||
void apply(u8 lower_bound, u8 upper_bound);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Bitmap& m_bitmap;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2022, MacDue <macdue@dueutil.tech>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <LibGfx/Filters/ColorFilter.h>
|
|
||||||
#include <LibGfx/Matrix3x3.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
|
||||||
|
|
||||||
class MatrixFilter : public ColorFilter {
|
|
||||||
public:
|
|
||||||
MatrixFilter(FloatMatrix3x3 operation, float amount = 1.0f)
|
|
||||||
: ColorFilter(amount)
|
|
||||||
, m_operation(operation)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
Color convert_color(Color original) override
|
|
||||||
{
|
|
||||||
auto safe_float_to_u8 = [](float value) -> u8 {
|
|
||||||
return AK::clamp(static_cast<int>(value), 0, AK::NumericLimits<u8>::max());
|
|
||||||
};
|
|
||||||
FloatVector3 rgb = {
|
|
||||||
float(original.red()),
|
|
||||||
float(original.green()),
|
|
||||||
float(original.blue())
|
|
||||||
};
|
|
||||||
rgb = m_operation * rgb;
|
|
||||||
return Color {
|
|
||||||
safe_float_to_u8(rgb[0]),
|
|
||||||
safe_float_to_u8(rgb[1]),
|
|
||||||
safe_float_to_u8(rgb[2]),
|
|
||||||
original.alpha()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
FloatMatrix3x3 const m_operation;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2022, MacDue <macdue@dueutil.tech>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <AK/StringView.h>
|
|
||||||
#include <LibGfx/Filters/ColorFilter.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
|
||||||
|
|
||||||
class OpacityFilter : public ColorFilter {
|
|
||||||
public:
|
|
||||||
using ColorFilter::ColorFilter;
|
|
||||||
virtual ~OpacityFilter() = default;
|
|
||||||
|
|
||||||
virtual StringView class_name() const override { return "OpacityFilter"sv; }
|
|
||||||
|
|
||||||
virtual bool amount_handled_in_filter() const override
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
Color convert_color(Color original) override
|
|
||||||
{
|
|
||||||
return original.with_alpha(m_amount * 255);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2022, MacDue <macdue@dueutil.tech>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <LibGfx/Filters/MatrixFilter.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
|
||||||
|
|
||||||
class SaturateFilter : public MatrixFilter {
|
|
||||||
public:
|
|
||||||
SaturateFilter(float amount)
|
|
||||||
: MatrixFilter(calculate_saturate_matrix(amount))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool amount_handled_in_filter() const override
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual StringView class_name() const override { return "SaturateFilter"sv; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
static FloatMatrix3x3 calculate_saturate_matrix(float amount)
|
|
||||||
{
|
|
||||||
// The matrix is taken directly from the SVG filter specification:
|
|
||||||
// https://drafts.fxtf.org/filter-effects-1/#feColorMatrixElement
|
|
||||||
return FloatMatrix3x3 {
|
|
||||||
0.213f + 0.787f * amount, 0.715f - 0.715f * amount, 0.072f - 0.072f * amount,
|
|
||||||
0.213f - 0.213f * amount, 0.715f + 0.285f * amount, 0.072f - 0.072f * amount,
|
|
||||||
0.213f - 0.213f * amount, 0.715f - 0.715f * amount, 0.072f + 0.928f * amount
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2022, Xavier Defrang <xavier.defrang@gmail.com>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <AK/StringView.h>
|
|
||||||
#include <LibGfx/Filters/ColorFilter.h>
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
|
||||||
|
|
||||||
class SepiaFilter : public ColorFilter {
|
|
||||||
public:
|
|
||||||
using ColorFilter::ColorFilter;
|
|
||||||
virtual ~SepiaFilter() = default;
|
|
||||||
|
|
||||||
virtual StringView class_name() const override { return "SepiaFilter"sv; }
|
|
||||||
|
|
||||||
virtual bool amount_handled_in_filter() const override
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
Color convert_color(Color original) override { return original.sepia(m_amount); }
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020, the SerenityOS developers.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "GenericConvolutionFilter.h"
|
|
||||||
#include <AK/StringView.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
|
||||||
|
|
||||||
class SharpenFilter : public GenericConvolutionFilter<3> {
|
|
||||||
public:
|
|
||||||
SharpenFilter() = default;
|
|
||||||
virtual ~SharpenFilter() = default;
|
|
||||||
|
|
||||||
virtual StringView class_name() const override { return "SharpenFilter"sv; }
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020, the SerenityOS developers.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "GenericConvolutionFilter.h"
|
|
||||||
#include <AK/StringView.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
|
||||||
|
|
||||||
template<size_t N>
|
|
||||||
requires(N % 2 == 1) class SpatialGaussianBlurFilter : public GenericConvolutionFilter<N> {
|
|
||||||
public:
|
|
||||||
SpatialGaussianBlurFilter() = default;
|
|
||||||
virtual ~SpatialGaussianBlurFilter() = default;
|
|
||||||
|
|
||||||
virtual StringView class_name() const override { return "SpatialGaussianBlurFilter"sv; }
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,312 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2010, Mario Klingemann <mario@quasimondo.com>
|
|
||||||
* Copyright (c) 2022, MacDue <macdue@dueutil.tech>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(AK_COMPILER_GCC)
|
|
||||||
# pragma GCC optimize("O3")
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <AK/Array.h>
|
|
||||||
#include <AK/IntegralMath.h>
|
|
||||||
#include <AK/Math.h>
|
|
||||||
#include <AK/Vector.h>
|
|
||||||
#include <LibGfx/Filters/StackBlurFilter.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
|
||||||
|
|
||||||
using uint = unsigned;
|
|
||||||
|
|
||||||
constexpr size_t MAX_RADIUS = 256;
|
|
||||||
|
|
||||||
// Magic lookup tables!
|
|
||||||
// `(value * sum_mult[radius - 2]) >> shift_table[radius - 2]` closely approximates value/(radius*radius)
|
|
||||||
// These LUTs are the same as the original, but converted to constexpr functions rather than magic numbers.
|
|
||||||
|
|
||||||
constexpr auto shift_table = [] {
|
|
||||||
Array<u8, MAX_RADIUS> lut {};
|
|
||||||
for (size_t r = 2; r <= MAX_RADIUS + 1; r++)
|
|
||||||
lut[r - 2] = static_cast<u8>(AK::ceil_log2(256 * (r * r + 1)));
|
|
||||||
return lut;
|
|
||||||
}();
|
|
||||||
|
|
||||||
constexpr auto mult_table = [] {
|
|
||||||
Array<u16, MAX_RADIUS> lut {};
|
|
||||||
for (size_t r = 2; r <= MAX_RADIUS + 1; r++)
|
|
||||||
lut[r - 2] = static_cast<u16>(AK::ceil(static_cast<double>(1 << shift_table[r - 2]) / (r * r)));
|
|
||||||
return lut;
|
|
||||||
}();
|
|
||||||
|
|
||||||
// Note: This is named to be consistent with the algorithm, but it's actually a simple circular buffer.
|
|
||||||
struct BlurStack {
|
|
||||||
BlurStack(size_t size)
|
|
||||||
{
|
|
||||||
m_data.resize(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Iterator {
|
|
||||||
friend BlurStack;
|
|
||||||
|
|
||||||
ALWAYS_INLINE Color& operator*()
|
|
||||||
{
|
|
||||||
return m_data.at(m_idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
ALWAYS_INLINE Color* operator->()
|
|
||||||
{
|
|
||||||
return &m_data.at(m_idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
ALWAYS_INLINE Iterator operator++()
|
|
||||||
{
|
|
||||||
// Note: This seemed to profile slightly better than %
|
|
||||||
if (++m_idx >= m_data.size())
|
|
||||||
m_idx = 0;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
ALWAYS_INLINE Iterator operator++(int)
|
|
||||||
{
|
|
||||||
auto prev_it = *this;
|
|
||||||
++*(this);
|
|
||||||
return prev_it;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Iterator(size_t idx, Span<Color> data)
|
|
||||||
: m_idx(idx)
|
|
||||||
, m_data(data)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t m_idx;
|
|
||||||
Span<Color> m_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
Iterator iterator_from_position(size_t position)
|
|
||||||
{
|
|
||||||
VERIFY(position < m_data.size());
|
|
||||||
return Iterator(position, m_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Vector<Color, 512> m_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is an implementation of StackBlur by Mario Klingemann (https://observablehq.com/@jobleonard/mario-klingemans-stackblur)
|
|
||||||
// (Link is to a secondary source as the original site is now down)
|
|
||||||
FLATTEN void StackBlurFilter::process_rgba(u8 radius, Color fill_color)
|
|
||||||
{
|
|
||||||
// TODO: Implement a plain RGB version of this (if required)
|
|
||||||
|
|
||||||
if (radius == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
fill_color = fill_color.with_alpha(0);
|
|
||||||
|
|
||||||
uint width = m_bitmap.width();
|
|
||||||
uint height = m_bitmap.height();
|
|
||||||
|
|
||||||
uint div = 2 * radius + 1;
|
|
||||||
uint radius_plus_1 = radius + 1;
|
|
||||||
uint sum_factor = radius_plus_1 * (radius_plus_1 + 1) / 2;
|
|
||||||
|
|
||||||
auto get_pixel = [&](int x, int y) {
|
|
||||||
auto color = m_bitmap.get_pixel<StorageFormat::BGRA8888>(x, y);
|
|
||||||
if (color.alpha() == 0)
|
|
||||||
return fill_color;
|
|
||||||
return color;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto set_pixel = [&](int x, int y, Color color) {
|
|
||||||
return m_bitmap.set_pixel<StorageFormat::BGRA8888>(x, y, color);
|
|
||||||
};
|
|
||||||
|
|
||||||
BlurStack blur_stack { div };
|
|
||||||
auto const stack_start = blur_stack.iterator_from_position(0);
|
|
||||||
auto const stack_end = blur_stack.iterator_from_position(radius_plus_1);
|
|
||||||
auto stack_iterator = stack_start;
|
|
||||||
|
|
||||||
auto const sum_mult = mult_table[radius - 1];
|
|
||||||
auto const sum_shift = shift_table[radius - 1];
|
|
||||||
|
|
||||||
for (uint y = 0; y < height; y++) {
|
|
||||||
stack_iterator = stack_start;
|
|
||||||
|
|
||||||
auto color = get_pixel(0, y);
|
|
||||||
for (uint i = 0; i < radius_plus_1; i++)
|
|
||||||
*(stack_iterator++) = color;
|
|
||||||
|
|
||||||
// All the sums here work to approximate a gaussian.
|
|
||||||
// Note: Only about 17 bits are actually used in each sum.
|
|
||||||
uint red_in_sum = 0;
|
|
||||||
uint green_in_sum = 0;
|
|
||||||
uint blue_in_sum = 0;
|
|
||||||
uint alpha_in_sum = 0;
|
|
||||||
uint red_out_sum = radius_plus_1 * color.red();
|
|
||||||
uint green_out_sum = radius_plus_1 * color.green();
|
|
||||||
uint blue_out_sum = radius_plus_1 * color.blue();
|
|
||||||
uint alpha_out_sum = radius_plus_1 * color.alpha();
|
|
||||||
uint red_sum = sum_factor * color.red();
|
|
||||||
uint green_sum = sum_factor * color.green();
|
|
||||||
uint blue_sum = sum_factor * color.blue();
|
|
||||||
uint alpha_sum = sum_factor * color.alpha();
|
|
||||||
|
|
||||||
for (uint i = 1; i <= radius; i++) {
|
|
||||||
auto color = get_pixel(min(i, width - 1), y);
|
|
||||||
|
|
||||||
auto bias = radius_plus_1 - i;
|
|
||||||
*stack_iterator = color;
|
|
||||||
red_sum += color.red() * bias;
|
|
||||||
green_sum += color.green() * bias;
|
|
||||||
blue_sum += color.blue() * bias;
|
|
||||||
alpha_sum += color.alpha() * bias;
|
|
||||||
|
|
||||||
red_in_sum += color.red();
|
|
||||||
green_in_sum += color.green();
|
|
||||||
blue_in_sum += color.blue();
|
|
||||||
alpha_in_sum += color.alpha();
|
|
||||||
|
|
||||||
++stack_iterator;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto stack_in_iterator = stack_start;
|
|
||||||
auto stack_out_iterator = stack_end;
|
|
||||||
|
|
||||||
for (uint x = 0; x < width; x++) {
|
|
||||||
auto alpha = (alpha_sum * sum_mult) >> sum_shift;
|
|
||||||
if (alpha != 0)
|
|
||||||
set_pixel(x, y, Color((red_sum * sum_mult) >> sum_shift, (green_sum * sum_mult) >> sum_shift, (blue_sum * sum_mult) >> sum_shift, alpha));
|
|
||||||
else
|
|
||||||
set_pixel(x, y, fill_color);
|
|
||||||
|
|
||||||
red_sum -= red_out_sum;
|
|
||||||
green_sum -= green_out_sum;
|
|
||||||
blue_sum -= blue_out_sum;
|
|
||||||
alpha_sum -= alpha_out_sum;
|
|
||||||
|
|
||||||
red_out_sum -= stack_in_iterator->red();
|
|
||||||
green_out_sum -= stack_in_iterator->green();
|
|
||||||
blue_out_sum -= stack_in_iterator->blue();
|
|
||||||
alpha_out_sum -= stack_in_iterator->alpha();
|
|
||||||
|
|
||||||
auto color = get_pixel(min(x + radius_plus_1, width - 1), y);
|
|
||||||
*stack_in_iterator = color;
|
|
||||||
red_in_sum += color.red();
|
|
||||||
green_in_sum += color.green();
|
|
||||||
blue_in_sum += color.blue();
|
|
||||||
alpha_in_sum += color.alpha();
|
|
||||||
|
|
||||||
red_sum += red_in_sum;
|
|
||||||
green_sum += green_in_sum;
|
|
||||||
blue_sum += blue_in_sum;
|
|
||||||
alpha_sum += alpha_in_sum;
|
|
||||||
|
|
||||||
++stack_in_iterator;
|
|
||||||
|
|
||||||
color = *stack_out_iterator;
|
|
||||||
red_out_sum += color.red();
|
|
||||||
green_out_sum += color.green();
|
|
||||||
blue_out_sum += color.blue();
|
|
||||||
alpha_out_sum += color.alpha();
|
|
||||||
|
|
||||||
red_in_sum -= color.red();
|
|
||||||
green_in_sum -= color.green();
|
|
||||||
blue_in_sum -= color.blue();
|
|
||||||
alpha_in_sum -= color.alpha();
|
|
||||||
|
|
||||||
++stack_out_iterator;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint x = 0; x < width; x++) {
|
|
||||||
stack_iterator = stack_start;
|
|
||||||
|
|
||||||
auto color = get_pixel(x, 0);
|
|
||||||
for (uint i = 0; i < radius_plus_1; i++)
|
|
||||||
*(stack_iterator++) = color;
|
|
||||||
|
|
||||||
uint red_in_sum = 0;
|
|
||||||
uint green_in_sum = 0;
|
|
||||||
uint blue_in_sum = 0;
|
|
||||||
uint alpha_in_sum = 0;
|
|
||||||
uint red_out_sum = radius_plus_1 * color.red();
|
|
||||||
uint green_out_sum = radius_plus_1 * color.green();
|
|
||||||
uint blue_out_sum = radius_plus_1 * color.blue();
|
|
||||||
uint alpha_out_sum = radius_plus_1 * color.alpha();
|
|
||||||
uint red_sum = sum_factor * color.red();
|
|
||||||
uint green_sum = sum_factor * color.green();
|
|
||||||
uint blue_sum = sum_factor * color.blue();
|
|
||||||
uint alpha_sum = sum_factor * color.alpha();
|
|
||||||
|
|
||||||
for (uint i = 1; i <= radius; i++) {
|
|
||||||
auto color = get_pixel(x, min(i, height - 1));
|
|
||||||
|
|
||||||
auto bias = radius_plus_1 - i;
|
|
||||||
*stack_iterator = color;
|
|
||||||
red_sum += color.red() * bias;
|
|
||||||
green_sum += color.green() * bias;
|
|
||||||
blue_sum += color.blue() * bias;
|
|
||||||
alpha_sum += color.alpha() * bias;
|
|
||||||
|
|
||||||
red_in_sum += color.red();
|
|
||||||
green_in_sum += color.green();
|
|
||||||
blue_in_sum += color.blue();
|
|
||||||
alpha_in_sum += color.alpha();
|
|
||||||
|
|
||||||
++stack_iterator;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto stack_in_iterator = stack_start;
|
|
||||||
auto stack_out_iterator = stack_end;
|
|
||||||
|
|
||||||
for (uint y = 0; y < height; y++) {
|
|
||||||
auto alpha = (alpha_sum * sum_mult) >> sum_shift;
|
|
||||||
if (alpha != 0)
|
|
||||||
set_pixel(x, y, Color((red_sum * sum_mult) >> sum_shift, (green_sum * sum_mult) >> sum_shift, (blue_sum * sum_mult) >> sum_shift, alpha));
|
|
||||||
else
|
|
||||||
set_pixel(x, y, fill_color);
|
|
||||||
|
|
||||||
red_sum -= red_out_sum;
|
|
||||||
green_sum -= green_out_sum;
|
|
||||||
blue_sum -= blue_out_sum;
|
|
||||||
alpha_sum -= alpha_out_sum;
|
|
||||||
|
|
||||||
red_out_sum -= stack_in_iterator->red();
|
|
||||||
green_out_sum -= stack_in_iterator->green();
|
|
||||||
blue_out_sum -= stack_in_iterator->blue();
|
|
||||||
alpha_out_sum -= stack_in_iterator->alpha();
|
|
||||||
|
|
||||||
auto color = get_pixel(x, min(y + radius_plus_1, height - 1));
|
|
||||||
*stack_in_iterator = color;
|
|
||||||
red_in_sum += color.red();
|
|
||||||
green_in_sum += color.green();
|
|
||||||
blue_in_sum += color.blue();
|
|
||||||
alpha_in_sum += color.alpha();
|
|
||||||
|
|
||||||
red_sum += red_in_sum;
|
|
||||||
green_sum += green_in_sum;
|
|
||||||
blue_sum += blue_in_sum;
|
|
||||||
alpha_sum += alpha_in_sum;
|
|
||||||
|
|
||||||
++stack_in_iterator;
|
|
||||||
|
|
||||||
color = *stack_out_iterator;
|
|
||||||
red_out_sum += color.red();
|
|
||||||
green_out_sum += color.green();
|
|
||||||
blue_out_sum += color.blue();
|
|
||||||
alpha_out_sum += color.alpha();
|
|
||||||
|
|
||||||
red_in_sum -= color.red();
|
|
||||||
green_in_sum -= color.green();
|
|
||||||
blue_in_sum -= color.blue();
|
|
||||||
alpha_in_sum -= color.alpha();
|
|
||||||
|
|
||||||
++stack_out_iterator;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2022, MacDue <macdue@dueutil.tech>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <LibGfx/Bitmap.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
|
||||||
|
|
||||||
class StackBlurFilter {
|
|
||||||
public:
|
|
||||||
StackBlurFilter(Bitmap& bitmap)
|
|
||||||
: m_bitmap(bitmap)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: The radius is a u8 for reason! This implementation can only handle radii from 0 to 255.
|
|
||||||
void process_rgba(u8 radius, Color fill_color = Color::NamedColor::White);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Bitmap& m_bitmap;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2022, MacDue <macdue@dueutil.tech>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <AK/StringView.h>
|
|
||||||
#include <LibGfx/Filters/ColorFilter.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
|
||||||
|
|
||||||
class TintFilter : public ColorFilter {
|
|
||||||
public:
|
|
||||||
TintFilter(Color color, float amount)
|
|
||||||
: ColorFilter(amount)
|
|
||||||
, m_color(Color::from_rgb(color.value()))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool amount_handled_in_filter() const override { return true; }
|
|
||||||
|
|
||||||
virtual StringView class_name() const override { return "TintFilter"sv; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
Color convert_color(Color dest) override
|
|
||||||
{
|
|
||||||
return Color::from_rgb(dest.value())
|
|
||||||
.mixed_with(m_color, m_amount)
|
|
||||||
.with_alpha(dest.alpha());
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Gfx::Color m_color;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -23,7 +23,6 @@
|
||||||
#include <gpu/ganesh/SkSurfaceGanesh.h>
|
#include <gpu/ganesh/SkSurfaceGanesh.h>
|
||||||
#include <pathops/SkPathOps.h>
|
#include <pathops/SkPathOps.h>
|
||||||
|
|
||||||
#include <LibGfx/Filters/StackBlurFilter.h>
|
|
||||||
#include <LibWeb/CSS/ComputedValues.h>
|
#include <LibWeb/CSS/ComputedValues.h>
|
||||||
#include <LibWeb/Painting/DisplayListPlayerSkia.h>
|
#include <LibWeb/Painting/DisplayListPlayerSkia.h>
|
||||||
#include <LibWeb/Painting/ShadowPainting.h>
|
#include <LibWeb/Painting/ShadowPainting.h>
|
||||||
|
|
|
@ -4,15 +4,6 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <LibGfx/Filters/BrightnessFilter.h>
|
|
||||||
#include <LibGfx/Filters/ContrastFilter.h>
|
|
||||||
#include <LibGfx/Filters/GrayscaleFilter.h>
|
|
||||||
#include <LibGfx/Filters/HueRotateFilter.h>
|
|
||||||
#include <LibGfx/Filters/InvertFilter.h>
|
|
||||||
#include <LibGfx/Filters/OpacityFilter.h>
|
|
||||||
#include <LibGfx/Filters/SaturateFilter.h>
|
|
||||||
#include <LibGfx/Filters/SepiaFilter.h>
|
|
||||||
#include <LibGfx/Filters/StackBlurFilter.h>
|
|
||||||
#include <LibWeb/Layout/Node.h>
|
#include <LibWeb/Layout/Node.h>
|
||||||
#include <LibWeb/Painting/BorderRadiusCornerClipper.h>
|
#include <LibWeb/Painting/BorderRadiusCornerClipper.h>
|
||||||
#include <LibWeb/Painting/FilterPainting.h>
|
#include <LibWeb/Painting/FilterPainting.h>
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
#include <AK/NumericLimits.h>
|
#include <AK/NumericLimits.h>
|
||||||
#include <LibGfx/DisjointRectSet.h>
|
#include <LibGfx/DisjointRectSet.h>
|
||||||
#include <LibGfx/Filters/StackBlurFilter.h>
|
|
||||||
#include <LibGfx/Font/Font.h>
|
#include <LibGfx/Font/Font.h>
|
||||||
#include <LibGfx/Painter.h>
|
#include <LibGfx/Painter.h>
|
||||||
#include <LibWeb/Layout/LineBoxFragment.h>
|
#include <LibWeb/Layout/LineBoxFragment.h>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue