1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 09:38:11 +00:00

LibWeb: Support animated backgrounds

This commit is contained in:
Moustafa Raafat 2022-10-30 15:43:42 +00:00 committed by Andrew Kaster
parent bfdb30c74a
commit 6ff9a88c3b
3 changed files with 54 additions and 14 deletions

View file

@ -16,6 +16,7 @@
#include <LibWeb/Loader/ResourceLoader.h> #include <LibWeb/Loader/ResourceLoader.h>
#include <LibWeb/Page/Page.h> #include <LibWeb/Page/Page.h>
#include <LibWeb/Painting/GradientPainting.h> #include <LibWeb/Painting/GradientPainting.h>
#include <LibWeb/Platform/Timer.h>
namespace Web::CSS { namespace Web::CSS {
@ -1650,9 +1651,6 @@ ImageStyleValue::ImageStyleValue(AK::URL const& url)
void ImageStyleValue::load_any_resources(DOM::Document& document) void ImageStyleValue::load_any_resources(DOM::Document& document)
{ {
if (m_bitmap)
return;
if (resource()) if (resource())
return; return;
@ -1665,10 +1663,41 @@ void ImageStyleValue::resource_did_load()
{ {
if (!m_document) if (!m_document)
return; return;
m_bitmap = resource()->bitmap();
// FIXME: Do less than a full repaint if possible? // FIXME: Do less than a full repaint if possible?
if (m_document && m_document->browsing_context()) if (m_document && m_document->browsing_context())
m_document->browsing_context()->set_needs_display(); m_document->browsing_context()->set_needs_display();
if (resource()->is_animated() && resource()->frame_count() > 1) {
m_timer = Platform::Timer::create();
m_timer->set_interval(resource()->frame_duration(0));
m_timer->on_timeout = [this] { animate(); };
m_timer->start();
}
}
void ImageStyleValue::animate()
{
m_current_frame_index = (m_current_frame_index + 1) % resource()->frame_count();
auto current_frame_duration = resource()->frame_duration(m_current_frame_index);
if (current_frame_duration != m_timer->interval())
m_timer->restart(current_frame_duration);
if (m_current_frame_index == resource()->frame_count() - 1) {
++m_loops_completed;
if (m_loops_completed > 0 && m_loops_completed == resource()->loop_count())
m_timer->stop();
}
if (on_animate)
on_animate();
}
Gfx::Bitmap const* ImageStyleValue::bitmap(size_t frame_index) const
{
if (!resource())
return nullptr;
return resource()->bitmap(frame_index);
} }
String ImageStyleValue::to_string() const String ImageStyleValue::to_string() const
@ -1685,22 +1714,22 @@ bool ImageStyleValue::equals(StyleValue const& other) const
Optional<int> ImageStyleValue::natural_width() const Optional<int> ImageStyleValue::natural_width() const
{ {
if (m_bitmap) if (resource())
return m_bitmap->width(); return bitmap(0)->width();
return {}; return {};
} }
Optional<int> ImageStyleValue::natural_height() const Optional<int> ImageStyleValue::natural_height() const
{ {
if (m_bitmap) if (resource())
return m_bitmap->height(); return bitmap(0)->height();
return {}; return {};
} }
void ImageStyleValue::paint(PaintContext& context, Gfx::IntRect const& dest_rect, CSS::ImageRendering image_rendering) const void ImageStyleValue::paint(PaintContext& context, Gfx::IntRect const& dest_rect, CSS::ImageRendering image_rendering) const
{ {
if (m_bitmap) if (resource())
context.painter().draw_scaled_bitmap(dest_rect, *m_bitmap, m_bitmap->rect(), 1.0f, to_gfx_scaling_mode(image_rendering)); context.painter().draw_scaled_bitmap(dest_rect, *bitmap(m_current_frame_index), bitmap(0)->rect(), 1.0f, to_gfx_scaling_mode(image_rendering));
} }
static void serialize_color_stop_list(StringBuilder& builder, auto const& color_stop_list) static void serialize_color_stop_list(StringBuilder& builder, auto const& color_stop_list)

View file

@ -1171,23 +1171,29 @@ public:
virtual void load_any_resources(DOM::Document&) override; virtual void load_any_resources(DOM::Document&) override;
Gfx::Bitmap const* bitmap() const { return m_bitmap; }
Optional<int> natural_width() const override; Optional<int> natural_width() const override;
Optional<int> natural_height() const override; Optional<int> natural_height() const override;
bool is_paintable() const override { return !m_bitmap.is_null(); } bool is_paintable() const override { return bitmap(0) != nullptr; }
void paint(PaintContext& context, Gfx::IntRect const& dest_rect, CSS::ImageRendering image_rendering) const override; void paint(PaintContext& context, Gfx::IntRect const& dest_rect, CSS::ImageRendering image_rendering) const override;
Function<void()> on_animate;
private: private:
ImageStyleValue(AK::URL const&); ImageStyleValue(AK::URL const&);
// ^ResourceClient // ^ResourceClient
virtual void resource_did_load() override; virtual void resource_did_load() override;
void animate();
Gfx::Bitmap const* bitmap(size_t index) const;
AK::URL m_url; AK::URL m_url;
WeakPtr<DOM::Document> m_document; WeakPtr<DOM::Document> m_document;
RefPtr<Gfx::Bitmap> m_bitmap;
size_t m_current_frame_index { 0 };
size_t m_loops_completed { 0 };
RefPtr<Platform::Timer> m_timer;
}; };
enum class GradientRepeating { enum class GradientRepeating {

View file

@ -55,6 +55,11 @@ void HTMLBodyElement::parse_attribute(FlyString const& name, String const& value
document().set_visited_link_color(color.value()); document().set_visited_link_color(color.value());
} else if (name.equals_ignoring_case("background"sv)) { } else if (name.equals_ignoring_case("background"sv)) {
m_background_style_value = CSS::ImageStyleValue::create(document().parse_url(value)); m_background_style_value = CSS::ImageStyleValue::create(document().parse_url(value));
m_background_style_value->on_animate = [this] {
if (layout_node()) {
layout_node()->set_needs_display();
}
};
} }
#undef __ENUMERATE #undef __ENUMERATE