mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-05-13 10:26:37 +02:00
DecodedImageFrame now owns decoded bitmap pixels directly, so the separate ImmutableBitmap wrapper no longer carries useful semantics. Remove the class and pass decoded image frames or bitmaps at the boundaries where pixels are actually required. The Skia image cache now keys off DecodedImageFrame, matching the display-list commands that paint decoded images. Video frames stay owned by LibMedia, with the explicit YUV-to-bitmap conversion living at HTMLVideoElement's decoded-frame entry point for canvas and WebGL callers.
120 lines
3.7 KiB
C++
120 lines
3.7 KiB
C++
/*
|
|
* Copyright (c) 2025, Tim Ledbetter <tim.ledbetter@gmail.com>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include "SVGFEImageElement.h"
|
|
#include <LibCore/Timer.h>
|
|
#include <LibGfx/DecodedImageFrame.h>
|
|
#include <LibWeb/Bindings/SVGFEImageElement.h>
|
|
#include <LibWeb/DOM/Document.h>
|
|
#include <LibWeb/HTML/DecodedImageData.h>
|
|
#include <LibWeb/HTML/PotentialCORSRequest.h>
|
|
#include <LibWeb/HTML/SharedResourceRequest.h>
|
|
#include <LibWeb/Layout/SVGImageBox.h>
|
|
#include <LibWeb/Namespace.h>
|
|
|
|
namespace Web::SVG {
|
|
|
|
GC_DEFINE_ALLOCATOR(SVGFEImageElement);
|
|
|
|
SVGFEImageElement::SVGFEImageElement(DOM::Document& document, DOM::QualifiedName qualified_name)
|
|
: SVGElement(document, qualified_name)
|
|
{
|
|
}
|
|
|
|
void SVGFEImageElement::initialize(JS::Realm& realm)
|
|
{
|
|
WEB_SET_PROTOTYPE_FOR_INTERFACE(SVGFEImageElement);
|
|
Base::initialize(realm);
|
|
}
|
|
|
|
void SVGFEImageElement::visit_edges(Cell::Visitor& visitor)
|
|
{
|
|
Base::visit_edges(visitor);
|
|
SVGFilterPrimitiveStandardAttributes::visit_edges(visitor);
|
|
SVGURIReferenceMixin::visit_edges(visitor);
|
|
visitor.visit(m_resource_request);
|
|
}
|
|
|
|
void SVGFEImageElement::attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& value, Optional<FlyString> const& namespace_)
|
|
{
|
|
Base::attribute_changed(name, old_value, value, namespace_);
|
|
|
|
if (name == SVG::AttributeNames::href) {
|
|
if (namespace_ == Namespace::XLink && has_attribute_ns({}, name))
|
|
return;
|
|
|
|
auto href = value;
|
|
if (!namespace_.has_value() && !href.has_value())
|
|
href = get_attribute_ns(SVG::AttributeNames::href, Namespace::XLink);
|
|
|
|
process_href(href);
|
|
}
|
|
}
|
|
|
|
void SVGFEImageElement::process_href(Optional<String> const& href)
|
|
{
|
|
if (!href.has_value()) {
|
|
m_href = {};
|
|
return;
|
|
}
|
|
|
|
m_href = document().encoding_parse_url(*href);
|
|
if (!m_href.has_value())
|
|
return;
|
|
|
|
m_resource_request = HTML::SharedResourceRequest::get_or_create(realm(), document().page(), *m_href);
|
|
m_resource_request->add_callbacks(
|
|
[this, resource_request = GC::Root { m_resource_request }] {
|
|
set_needs_style_update(true);
|
|
set_needs_layout_update(DOM::SetNeedsLayoutReason::SVGImageFilterFetch);
|
|
},
|
|
nullptr);
|
|
|
|
if (m_resource_request->needs_fetching()) {
|
|
auto request = HTML::create_potential_CORS_request(vm(), *m_href, Fetch::Infrastructure::Request::Destination::Image, HTML::CORSSettingAttribute::NoCORS);
|
|
request->set_client(&document().relevant_settings_object());
|
|
m_resource_request->fetch_resource(realm(), request);
|
|
}
|
|
}
|
|
|
|
GC::Ptr<HTML::DecodedImageData> SVGFEImageElement::image_data() const
|
|
{
|
|
if (!m_resource_request)
|
|
return {};
|
|
return m_resource_request->image_data();
|
|
}
|
|
|
|
RefPtr<Gfx::DecodedImageFrame> SVGFEImageElement::current_image_frame(Gfx::IntSize size) const
|
|
{
|
|
if (auto data = image_data())
|
|
return data->frame(0, size);
|
|
return {};
|
|
}
|
|
|
|
Optional<Gfx::IntRect> SVGFEImageElement::content_rect() const
|
|
{
|
|
auto bitmap = current_image_frame();
|
|
if (!bitmap)
|
|
return {};
|
|
// NB: Called during painting.
|
|
auto layout_node = this->unsafe_layout_node();
|
|
if (!layout_node)
|
|
return {};
|
|
auto width = layout_node->computed_values().width().to_px(*layout_node, 0);
|
|
if (width == 0)
|
|
width = bitmap->width();
|
|
|
|
auto height = layout_node->computed_values().height().to_px(*layout_node, 0);
|
|
if (height == 0)
|
|
height = bitmap->height();
|
|
|
|
auto x = layout_node->computed_values().x().to_px(*layout_node, 0);
|
|
auto y = layout_node->computed_values().y().to_px(*layout_node, 0);
|
|
return Gfx::enclosing_int_rect({ x, y, width, height });
|
|
}
|
|
|
|
}
|