mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-02 22:30:31 +00:00
LibGfx: Use Skia for TinyVG rendering
This commit is contained in:
parent
331f26a88b
commit
39c500ec7c
Notes:
github-actions[bot]
2024-11-25 11:15:23 +00:00
Author: https://github.com/shlyakpavel
Commit: 39c500ec7c
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2512
Reviewed-by: https://github.com/gmta ✅
5 changed files with 51 additions and 31 deletions
|
@ -10,10 +10,10 @@
|
||||||
#include <AK/LEB128.h>
|
#include <AK/LEB128.h>
|
||||||
#include <AK/MemoryStream.h>
|
#include <AK/MemoryStream.h>
|
||||||
#include <AK/Variant.h>
|
#include <AK/Variant.h>
|
||||||
#include <LibGfx/AntiAliasingPainter.h>
|
|
||||||
#include <LibGfx/DeprecatedPainter.h>
|
|
||||||
#include <LibGfx/ImageFormats/TinyVGLoader.h>
|
#include <LibGfx/ImageFormats/TinyVGLoader.h>
|
||||||
#include <LibGfx/Line.h>
|
#include <LibGfx/Line.h>
|
||||||
|
#include <LibGfx/Painter.h>
|
||||||
|
#include <LibGfx/Path.h>
|
||||||
#include <LibGfx/Point.h>
|
#include <LibGfx/Point.h>
|
||||||
|
|
||||||
namespace Gfx {
|
namespace Gfx {
|
||||||
|
@ -254,9 +254,9 @@ public:
|
||||||
return FloatLine { TRY(read_point()), TRY(read_point()) };
|
return FloatLine { TRY(read_point()), TRY(read_point()) };
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<DeprecatedPath> read_path(u32 segment_count)
|
ErrorOr<Path> read_path(u32 segment_count)
|
||||||
{
|
{
|
||||||
DeprecatedPath path;
|
Path path;
|
||||||
auto segment_lengths = TRY(FixedArray<u32>::create(segment_count));
|
auto segment_lengths = TRY(FixedArray<u32>::create(segment_count));
|
||||||
for (auto& command_count : segment_lengths) {
|
for (auto& command_count : segment_lengths) {
|
||||||
command_count = TRY(read_var_uint()) + 1;
|
command_count = TRY(read_var_uint()) + 1;
|
||||||
|
@ -366,8 +366,8 @@ ErrorOr<NonnullRefPtr<TinyVGDecodedImageData>> TinyVGDecodedImageData::decode(St
|
||||||
auto color_table = TRY(decode_color_table(stream, header.color_encoding, header.color_count));
|
auto color_table = TRY(decode_color_table(stream, header.color_encoding, header.color_count));
|
||||||
TinyVGReader reader { stream, header, color_table.span() };
|
TinyVGReader reader { stream, header, color_table.span() };
|
||||||
|
|
||||||
auto rectangle_to_path = [](FloatRect const& rect) -> DeprecatedPath {
|
auto rectangle_to_path = [](FloatRect const& rect) -> Path {
|
||||||
DeprecatedPath path;
|
Path path;
|
||||||
path.move_to({ rect.x(), rect.y() });
|
path.move_to({ rect.x(), rect.y() });
|
||||||
path.line_to({ rect.x() + rect.width(), rect.y() });
|
path.line_to({ rect.x() + rect.width(), rect.y() });
|
||||||
path.line_to({ rect.x() + rect.width(), rect.y() + rect.height() });
|
path.line_to({ rect.x() + rect.width(), rect.y() + rect.height() });
|
||||||
|
@ -389,7 +389,7 @@ ErrorOr<NonnullRefPtr<TinyVGDecodedImageData>> TinyVGDecodedImageData::decode(St
|
||||||
break;
|
break;
|
||||||
case Command::FillPolygon: {
|
case Command::FillPolygon: {
|
||||||
auto header = TRY(reader.read_fill_command_header(style_type));
|
auto header = TRY(reader.read_fill_command_header(style_type));
|
||||||
DeprecatedPath polygon;
|
Path polygon;
|
||||||
polygon.move_to(TRY(reader.read_point()));
|
polygon.move_to(TRY(reader.read_point()));
|
||||||
for (u32 i = 0; i < header.count - 1; i++)
|
for (u32 i = 0; i < header.count - 1; i++)
|
||||||
polygon.line_to(TRY(reader.read_point()));
|
polygon.line_to(TRY(reader.read_point()));
|
||||||
|
@ -412,7 +412,7 @@ ErrorOr<NonnullRefPtr<TinyVGDecodedImageData>> TinyVGDecodedImageData::decode(St
|
||||||
}
|
}
|
||||||
case Command::DrawLines: {
|
case Command::DrawLines: {
|
||||||
auto header = TRY(reader.read_draw_command_header(style_type));
|
auto header = TRY(reader.read_draw_command_header(style_type));
|
||||||
DeprecatedPath path;
|
Path path;
|
||||||
for (u32 i = 0; i < header.count; i++) {
|
for (u32 i = 0; i < header.count; i++) {
|
||||||
auto line = TRY(reader.read_line());
|
auto line = TRY(reader.read_line());
|
||||||
path.move_to(line.a());
|
path.move_to(line.a());
|
||||||
|
@ -424,7 +424,7 @@ ErrorOr<NonnullRefPtr<TinyVGDecodedImageData>> TinyVGDecodedImageData::decode(St
|
||||||
case Command::DrawLineStrip:
|
case Command::DrawLineStrip:
|
||||||
case Command::DrawLineLoop: {
|
case Command::DrawLineLoop: {
|
||||||
auto header = TRY(reader.read_draw_command_header(style_type));
|
auto header = TRY(reader.read_draw_command_header(style_type));
|
||||||
DeprecatedPath path;
|
Path path;
|
||||||
path.move_to(TRY(reader.read_point()));
|
path.move_to(TRY(reader.read_point()));
|
||||||
for (u32 i = 0; i < header.count - 1; i++)
|
for (u32 i = 0; i < header.count - 1; i++)
|
||||||
path.line_to(TRY(reader.read_point()));
|
path.line_to(TRY(reader.read_point()));
|
||||||
|
@ -441,7 +441,7 @@ ErrorOr<NonnullRefPtr<TinyVGDecodedImageData>> TinyVGDecodedImageData::decode(St
|
||||||
}
|
}
|
||||||
case Command::OutlineFillPolygon: {
|
case Command::OutlineFillPolygon: {
|
||||||
auto header = TRY(reader.read_outline_fill_command_header(style_type));
|
auto header = TRY(reader.read_outline_fill_command_header(style_type));
|
||||||
DeprecatedPath polygon;
|
Path polygon;
|
||||||
polygon.move_to(TRY(reader.read_point()));
|
polygon.move_to(TRY(reader.read_point()));
|
||||||
for (u32 i = 0; i < header.count - 1; i++)
|
for (u32 i = 0; i < header.count - 1; i++)
|
||||||
polygon.line_to(TRY(reader.read_point()));
|
polygon.line_to(TRY(reader.read_point()));
|
||||||
|
@ -471,29 +471,29 @@ ErrorOr<NonnullRefPtr<TinyVGDecodedImageData>> TinyVGDecodedImageData::decode(St
|
||||||
return TRY(adopt_nonnull_ref_or_enomem(new (nothrow) TinyVGDecodedImageData({ header.width, header.height }, move(draw_commands))));
|
return TRY(adopt_nonnull_ref_or_enomem(new (nothrow) TinyVGDecodedImageData({ header.width, header.height }, move(draw_commands))));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TinyVGDecodedImageData::draw_transformed(DeprecatedPainter& painter, AffineTransform transform) const
|
void TinyVGDecodedImageData::draw_transformed(Painter& painter, AffineTransform transform) const
|
||||||
{
|
{
|
||||||
// FIXME: Correctly handle non-uniform scales.
|
// FIXME: Correctly handle non-uniform scales.
|
||||||
auto scale = max(transform.x_scale(), transform.y_scale());
|
auto scale = max(transform.x_scale(), transform.y_scale());
|
||||||
AntiAliasingPainter aa_painter { painter };
|
|
||||||
for (auto const& command : draw_commands()) {
|
for (auto const& command : draw_commands()) {
|
||||||
auto draw_path = command.path.copy_transformed(transform);
|
auto draw_path = command.path.copy_transformed(transform);
|
||||||
if (command.fill.has_value()) {
|
if (command.fill.has_value()) {
|
||||||
auto fill_path = draw_path;
|
auto fill_path = draw_path;
|
||||||
fill_path.close_all_subpaths();
|
fill_path.close_all_subpaths();
|
||||||
command.fill->visit(
|
command.fill->visit(
|
||||||
[&](Color color) { aa_painter.fill_path(fill_path, color, WindingRule::EvenOdd); },
|
[&](Color color) { painter.fill_path(fill_path, color, WindingRule::EvenOdd); },
|
||||||
[&](NonnullRefPtr<SVGGradientPaintStyle> style) {
|
[&](NonnullRefPtr<SVGGradientPaintStyle> style) {
|
||||||
const_cast<SVGGradientPaintStyle&>(*style).set_gradient_transform(transform);
|
const_cast<SVGGradientPaintStyle&>(*style).set_gradient_transform(transform);
|
||||||
aa_painter.fill_path(fill_path, style, 1.0f, WindingRule::EvenOdd);
|
painter.fill_path(fill_path, style, 1.0f, WindingRule::EvenOdd);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command.stroke.has_value()) {
|
if (command.stroke.has_value()) {
|
||||||
command.stroke->visit(
|
command.stroke->visit(
|
||||||
[&](Color color) { aa_painter.stroke_path(draw_path, color, command.stroke_width * scale); },
|
[&](Color color) { painter.stroke_path(draw_path, color, command.stroke_width * scale); },
|
||||||
[&](NonnullRefPtr<SVGGradientPaintStyle> style) {
|
[&](NonnullRefPtr<SVGGradientPaintStyle> style) {
|
||||||
const_cast<SVGGradientPaintStyle&>(*style).set_gradient_transform(transform);
|
const_cast<SVGGradientPaintStyle&>(*style).set_gradient_transform(transform);
|
||||||
aa_painter.stroke_path(draw_path, style, command.stroke_width * scale);
|
painter.stroke_path(draw_path, style, command.stroke_width * scale, 1.0f);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,11 @@
|
||||||
#include <AK/OwnPtr.h>
|
#include <AK/OwnPtr.h>
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <LibGfx/Color.h>
|
#include <LibGfx/Color.h>
|
||||||
#include <LibGfx/DeprecatedPath.h>
|
|
||||||
#include <LibGfx/Forward.h>
|
#include <LibGfx/Forward.h>
|
||||||
#include <LibGfx/ImageFormats/ImageDecoder.h>
|
#include <LibGfx/ImageFormats/ImageDecoder.h>
|
||||||
#include <LibGfx/PaintStyle.h>
|
#include <LibGfx/PaintStyle.h>
|
||||||
|
#include <LibGfx/Painter.h>
|
||||||
|
#include <LibGfx/Path.h>
|
||||||
#include <LibGfx/VectorGraphic.h>
|
#include <LibGfx/VectorGraphic.h>
|
||||||
|
|
||||||
namespace Gfx {
|
namespace Gfx {
|
||||||
|
@ -41,7 +42,7 @@ public:
|
||||||
using Style = Variant<Color, NonnullRefPtr<SVGGradientPaintStyle>>;
|
using Style = Variant<Color, NonnullRefPtr<SVGGradientPaintStyle>>;
|
||||||
|
|
||||||
struct DrawCommand {
|
struct DrawCommand {
|
||||||
DeprecatedPath path;
|
Path path;
|
||||||
Optional<Style> fill {};
|
Optional<Style> fill {};
|
||||||
Optional<Style> stroke {};
|
Optional<Style> stroke {};
|
||||||
float stroke_width { 0.0f };
|
float stroke_width { 0.0f };
|
||||||
|
@ -52,7 +53,7 @@ public:
|
||||||
return m_size;
|
return m_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void draw_transformed(DeprecatedPainter&, AffineTransform) const override;
|
virtual void draw_transformed(Painter&, AffineTransform) const override;
|
||||||
|
|
||||||
ReadonlySpan<DrawCommand> draw_commands() const
|
ReadonlySpan<DrawCommand> draw_commands() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,12 +4,12 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <LibGfx/DeprecatedPainter.h>
|
#include <LibGfx/PainterSkia.h>
|
||||||
#include <LibGfx/VectorGraphic.h>
|
#include <LibGfx/VectorGraphic.h>
|
||||||
|
|
||||||
namespace Gfx {
|
namespace Gfx {
|
||||||
|
|
||||||
void VectorGraphic::draw_into(DeprecatedPainter& painter, IntRect const& dest, AffineTransform transform) const
|
void VectorGraphic::draw_into(Painter& painter, IntRect const& dest, AffineTransform transform) const
|
||||||
{
|
{
|
||||||
// Apply the transform then center within destination rectangle (this ignores any translation from the transform):
|
// Apply the transform then center within destination rectangle (this ignores any translation from the transform):
|
||||||
// This allows you to easily rotate or flip the image before painting.
|
// This allows you to easily rotate or flip the image before painting.
|
||||||
|
@ -21,14 +21,14 @@ void VectorGraphic::draw_into(DeprecatedPainter& painter, IntRect const& dest, A
|
||||||
.multiply(AffineTransform {}.scale(scale, scale))
|
.multiply(AffineTransform {}.scale(scale, scale))
|
||||||
.multiply(AffineTransform {}.translate(-transformed_rect.location()))
|
.multiply(AffineTransform {}.translate(-transformed_rect.location()))
|
||||||
.multiply(transform);
|
.multiply(transform);
|
||||||
return draw_transformed(painter, view_transform);
|
draw_transformed(painter, view_transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<NonnullRefPtr<Gfx::Bitmap>> VectorGraphic::bitmap(IntSize size, AffineTransform transform) const
|
ErrorOr<NonnullRefPtr<Gfx::Bitmap>> VectorGraphic::bitmap(IntSize size, AffineTransform transform) const
|
||||||
{
|
{
|
||||||
auto bitmap = TRY(Bitmap::create(Gfx::BitmapFormat::BGRA8888, size));
|
auto bitmap = TRY(Bitmap::create(Gfx::BitmapFormat::BGRA8888, size));
|
||||||
DeprecatedPainter painter { *bitmap };
|
auto painter = PainterSkia::create(bitmap);
|
||||||
draw_into(painter, IntRect { {}, size }, transform);
|
draw_into(*painter, IntRect { {}, size }, transform);
|
||||||
return bitmap;
|
return bitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <AK/RefCounted.h>
|
#include <AK/RefCounted.h>
|
||||||
#include <LibGfx/Bitmap.h>
|
#include <LibGfx/Bitmap.h>
|
||||||
#include <LibGfx/Forward.h>
|
#include <LibGfx/Forward.h>
|
||||||
|
#include <LibGfx/Painter.h>
|
||||||
#include <LibGfx/Size.h>
|
#include <LibGfx/Size.h>
|
||||||
|
|
||||||
namespace Gfx {
|
namespace Gfx {
|
||||||
|
@ -16,13 +17,13 @@ namespace Gfx {
|
||||||
class VectorGraphic : public RefCounted<VectorGraphic> {
|
class VectorGraphic : public RefCounted<VectorGraphic> {
|
||||||
public:
|
public:
|
||||||
virtual IntSize intrinsic_size() const = 0;
|
virtual IntSize intrinsic_size() const = 0;
|
||||||
virtual void draw_transformed(DeprecatedPainter&, AffineTransform) const = 0;
|
virtual void draw_transformed(Painter&, AffineTransform) const = 0;
|
||||||
|
|
||||||
IntSize size() const { return intrinsic_size(); }
|
IntSize size() const { return intrinsic_size(); }
|
||||||
IntRect rect() const { return { {}, size() }; }
|
IntRect rect() const { return { {}, size() }; }
|
||||||
|
|
||||||
ErrorOr<NonnullRefPtr<Gfx::Bitmap>> bitmap(IntSize size, AffineTransform = {}) const;
|
ErrorOr<NonnullRefPtr<Gfx::Bitmap>> bitmap(IntSize size, AffineTransform = {}) const;
|
||||||
void draw_into(DeprecatedPainter&, IntRect const& dest, AffineTransform = {}) const;
|
void draw_into(Painter& painter, IntRect const& dest, AffineTransform = {}) const;
|
||||||
|
|
||||||
virtual ~VectorGraphic() = default;
|
virtual ~VectorGraphic() = default;
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
|
|
||||||
#include <AK/MemoryStream.h>
|
#include <AK/MemoryStream.h>
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
#include <LibGfx/DeprecatedPainter.h>
|
#include <LibGfx/PainterSkia.h>
|
||||||
|
#include <LibGfx/Rect.h>
|
||||||
#include <UI/Qt/StringUtils.h>
|
#include <UI/Qt/StringUtils.h>
|
||||||
#include <UI/Qt/TVGIconEngine.h>
|
#include <UI/Qt/TVGIconEngine.h>
|
||||||
|
|
||||||
|
@ -34,15 +35,32 @@ QPixmap TVGIconEngine::pixmap(QSize const& size, QIcon::Mode mode, QIcon::State
|
||||||
if (QPixmapCache::find(key, &pixmap))
|
if (QPixmapCache::find(key, &pixmap))
|
||||||
return pixmap;
|
return pixmap;
|
||||||
auto bitmap = MUST(Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, { size.width(), size.height() }));
|
auto bitmap = MUST(Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, { size.width(), size.height() }));
|
||||||
Gfx::DeprecatedPainter painter { *bitmap };
|
|
||||||
m_image_data->draw_into(painter, bitmap->rect());
|
auto painter = Gfx::PainterSkia::create(bitmap);
|
||||||
|
painter->clear_rect(bitmap->rect().to_type<float>(), Gfx::Color::Transparent);
|
||||||
|
|
||||||
|
m_image_data->draw_into(*painter, bitmap->rect());
|
||||||
|
|
||||||
for (auto const& filter : m_filters) {
|
for (auto const& filter : m_filters) {
|
||||||
if (filter->mode() == mode) {
|
if (filter->mode() == mode) {
|
||||||
painter.blit_filtered({}, *bitmap, bitmap->rect(), filter->function(), false);
|
for (int y = 0; y < bitmap->height(); ++y) {
|
||||||
|
for (int x = 0; x < bitmap->width(); ++x) {
|
||||||
|
auto original_color = bitmap->get_pixel(x, y);
|
||||||
|
auto filtered_color = filter->function()(original_color);
|
||||||
|
bitmap->set_pixel(x, y, filtered_color);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QImage qimage { bitmap->scanline_u8(0), bitmap->width(), bitmap->height(), QImage::Format::Format_ARGB32 };
|
|
||||||
|
QImage qimage(
|
||||||
|
bitmap->scanline_u8(0),
|
||||||
|
bitmap->width(),
|
||||||
|
bitmap->height(),
|
||||||
|
static_cast<qsizetype>(bitmap->pitch()),
|
||||||
|
QImage::Format::Format_ARGB32);
|
||||||
|
|
||||||
pixmap = QPixmap::fromImage(qimage);
|
pixmap = QPixmap::fromImage(qimage);
|
||||||
if (!pixmap.isNull())
|
if (!pixmap.isNull())
|
||||||
QPixmapCache::insert(key, pixmap);
|
QPixmapCache::insert(key, pixmap);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue