LibGfx: Let Painter care about TinyVG transforms

This helps us with non-uniform scales, and makes things simple
This commit is contained in:
Pavel Shliak 2024-12-03 00:24:34 +04:00 committed by Jelle Raaijmakers
parent 0b1c7d6af2
commit ea469fbeab
Notes: github-actions[bot] 2024-12-14 22:30:42 +00:00
5 changed files with 19 additions and 31 deletions

View file

@ -471,29 +471,25 @@ 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(Painter& painter, AffineTransform transform) const void TinyVGDecodedImageData::draw(Painter& painter) const
{ {
// FIXME: Correctly handle non-uniform scales.
auto scale = max(transform.x_scale(), transform.y_scale());
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;
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) { painter.fill_path(fill_path, color, WindingRule::EvenOdd); }, [&](Color color) { painter.fill_path(fill_path, color, WindingRule::EvenOdd); },
[&](NonnullRefPtr<SVGGradientPaintStyle> style) { [&](NonnullRefPtr<SVGGradientPaintStyle> const& style) {
const_cast<SVGGradientPaintStyle&>(*style).set_gradient_transform(transform);
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) { painter.stroke_path(draw_path, color, command.stroke_width * scale); }, [&](Color color) { painter.stroke_path(draw_path, color, command.stroke_width); },
[&](NonnullRefPtr<SVGGradientPaintStyle> style) { [&](NonnullRefPtr<SVGGradientPaintStyle> const& style) {
const_cast<SVGGradientPaintStyle&>(*style).set_gradient_transform(transform); painter.stroke_path(draw_path, style, command.stroke_width, 1.0f);
painter.stroke_path(draw_path, style, command.stroke_width * scale, 1.0f);
}); });
} }
} }

View file

@ -53,7 +53,7 @@ public:
return m_size; return m_size;
} }
virtual void draw_transformed(Painter&, AffineTransform) const override; virtual void draw(Painter&) const override;
ReadonlySpan<DrawCommand> draw_commands() const ReadonlySpan<DrawCommand> draw_commands() const
{ {

View file

@ -9,26 +9,25 @@
namespace Gfx { namespace Gfx {
void VectorGraphic::draw_into(Painter& painter, IntRect const& dest, AffineTransform transform) const ErrorOr<NonnullRefPtr<Gfx::Bitmap>> VectorGraphic::bitmap(IntSize size, AffineTransform transform) const
{ {
auto bitmap = TRY(Bitmap::create(Gfx::BitmapFormat::BGRA8888, size));
auto painter = PainterSkia::create(bitmap);
// 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.
auto transformed_rect = transform.map(FloatRect { {}, size() }); auto transformed_rect = transform.map(FloatRect { {}, this->size() });
auto scale = min(float(dest.width()) / transformed_rect.width(), float(dest.height()) / transformed_rect.height()); auto scale = min(float(size.width()) / transformed_rect.width(), float(size.height()) / transformed_rect.height());
auto centered = FloatRect { {}, transformed_rect.size().scaled(scale) }.centered_within(dest.to_type<float>()); auto centered = FloatRect { {}, transformed_rect.size().scaled(scale) }.centered_within(IntRect { {}, size }.to_type<float>());
auto view_transform = AffineTransform {} auto view_transform = AffineTransform {}
.translate(centered.location()) .translate(centered.location())
.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);
draw_transformed(painter, view_transform);
}
ErrorOr<NonnullRefPtr<Gfx::Bitmap>> VectorGraphic::bitmap(IntSize size, AffineTransform transform) const painter->set_transform(view_transform);
{ draw(*painter);
auto bitmap = TRY(Bitmap::create(Gfx::BitmapFormat::BGRA8888, size));
auto painter = PainterSkia::create(bitmap);
draw_into(*painter, IntRect { {}, size }, transform);
return bitmap; return bitmap;
} }

View file

@ -17,13 +17,12 @@ 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(Painter&, AffineTransform) const = 0; virtual void draw(Painter&) 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(Painter& painter, IntRect const& dest, AffineTransform = {}) const;
virtual ~VectorGraphic() = default; virtual ~VectorGraphic() = default;
}; };

View file

@ -6,7 +6,6 @@
#include <AK/MemoryStream.h> #include <AK/MemoryStream.h>
#include <AK/String.h> #include <AK/String.h>
#include <LibGfx/PainterSkia.h>
#include <LibGfx/Rect.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,12 +33,7 @@ QPixmap TVGIconEngine::pixmap(QSize const& size, QIcon::Mode mode, QIcon::State
auto key = pixmap_cache_key(size, mode, state); auto key = pixmap_cache_key(size, mode, 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(m_image_data->bitmap({ size.width(), size.height() }));
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) {