summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp44
-rw-r--r--Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.cpp100
-rw-r--r--Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.h14
3 files changed, 138 insertions, 20 deletions
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp
index 56537cd7ed..02b1b5b8da 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp
+++ b/Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp
@@ -29,6 +29,7 @@
#include <LibWeb/Loader/ResourceLoader.h>
#include <LibWeb/Painting/PaintableBox.h>
#include <LibWeb/Platform/ImageCodecPlugin.h>
+#include <LibWeb/SVG/SVGDecodedImageData.h>
namespace Web::HTML {
@@ -545,21 +546,38 @@ void HTMLImageElement::handle_successful_fetch(AK::URL const& url_string, ImageR
m_load_event_delayer.clear();
};
- auto result = Web::Platform::ImageCodecPlugin::the().decode_image(data.bytes());
- if (!result.has_value()) {
- dispatch_event(DOM::Event::create(realm(), HTML::EventNames::error).release_value_but_fixme_should_propagate_errors());
- return;
- }
+ // FIXME: Look at the MIME type instead!
+ bool is_svg_image = url_string.basename().ends_with(".svg"sv);
- Vector<AnimatedBitmapDecodedImageData::Frame> frames;
- for (auto& frame : result.value().frames) {
- frames.append(AnimatedBitmapDecodedImageData::Frame {
- .bitmap = frame.bitmap,
- .duration = static_cast<int>(frame.duration),
- });
+ RefPtr<DecodedImageData> image_data;
+
+ if (is_svg_image) {
+ VERIFY(document().page());
+ auto result = SVG::SVGDecodedImageData::create(*document().page(), url_string, data);
+ if (result.is_error()) {
+ dbgln("Failed to decode SVG image: {}", result.error());
+ dispatch_event(DOM::Event::create(realm(), HTML::EventNames::error).release_value_but_fixme_should_propagate_errors());
+ return;
+ }
+
+ image_data = result.release_value();
+ } else {
+ auto result = Web::Platform::ImageCodecPlugin::the().decode_image(data.bytes());
+ if (!result.has_value()) {
+ dispatch_event(DOM::Event::create(realm(), HTML::EventNames::error).release_value_but_fixme_should_propagate_errors());
+ return;
+ }
+
+ Vector<AnimatedBitmapDecodedImageData::Frame> frames;
+ for (auto& frame : result.value().frames) {
+ frames.append(AnimatedBitmapDecodedImageData::Frame {
+ .bitmap = frame.bitmap,
+ .duration = static_cast<int>(frame.duration),
+ });
+ }
+ image_data = AnimatedBitmapDecodedImageData::create(move(frames), result.value().loop_count, result.value().is_animated).release_value_but_fixme_should_propagate_errors();
}
- auto image_data = AnimatedBitmapDecodedImageData::create(move(frames), result.value().loop_count, result.value().is_animated).release_value_but_fixme_should_propagate_errors();
image_request.set_image_data(image_data);
ListOfAvailableImages::Key key;
@@ -580,7 +598,7 @@ void HTMLImageElement::handle_successful_fetch(AK::URL const& url_string, ImageR
image_request.set_state(ImageRequest::State::CompletelyAvailable);
// 3. Add the image to the list of available images using the key key, with the ignore higher-layer caching flag set.
- document().list_of_available_images().add(key, image_data, true).release_value_but_fixme_should_propagate_errors();
+ document().list_of_available_images().add(key, *image_data, true).release_value_but_fixme_should_propagate_errors();
// 4. Fire an event named load at the img element.
dispatch_event(DOM::Event::create(realm(), HTML::EventNames::load).release_value_but_fixme_should_propagate_errors());
diff --git a/Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.cpp b/Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.cpp
index bda9e99561..f2e0074e78 100644
--- a/Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.cpp
+++ b/Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.cpp
@@ -5,24 +5,114 @@
*/
#include <LibGfx/Bitmap.h>
+#include <LibWeb/DOM/Document.h>
+#include <LibWeb/Dump.h>
+#include <LibWeb/Fetch/Infrastructure/HTTP/Responses.h>
+#include <LibWeb/HTML/BrowsingContext.h>
+#include <LibWeb/HTML/NavigationParams.h>
+#include <LibWeb/HTML/Parser/HTMLParser.h>
+#include <LibWeb/Layout/Viewport.h>
+#include <LibWeb/Painting/PaintContext.h>
#include <LibWeb/SVG/SVGDecodedImageData.h>
+#include <LibWeb/SVG/SVGSVGElement.h>
namespace Web::SVG {
-ErrorOr<NonnullRefPtr<SVGDecodedImageData>> SVGDecodedImageData::create(ByteBuffer)
+class SVGDecodedImageData::SVGPageClient final : public PageClient {
+public:
+ explicit SVGPageClient(Page& host_page)
+ : m_host_page(host_page)
+ {
+ }
+
+ virtual ~SVGPageClient() override = default;
+
+ Page& m_host_page;
+ Page* m_svg_page { nullptr };
+
+ virtual Page& page() override { return *m_svg_page; }
+ virtual Page const& page() const override { return *m_svg_page; }
+ virtual bool is_connection_open() const override { return false; }
+ virtual Gfx::Palette palette() const override { return m_host_page.client().palette(); }
+ virtual DevicePixelRect screen_rect() const override { return {}; }
+ virtual float device_pixels_per_css_pixel() const override { return m_host_page.client().device_pixels_per_css_pixel(); }
+ virtual CSS::PreferredColorScheme preferred_color_scheme() const override { return m_host_page.client().preferred_color_scheme(); }
+ virtual void request_file(FileRequest) override { }
+ virtual void paint(DevicePixelRect const&, Gfx::Bitmap&) override { }
+};
+
+ErrorOr<NonnullRefPtr<SVGDecodedImageData>> SVGDecodedImageData::create(Page& host_page, AK::URL const& url, ByteBuffer data)
{
- return adopt_nonnull_ref_or_enomem(new (nothrow) SVGDecodedImageData());
+ auto page_client = make<SVGPageClient>(host_page);
+ auto page = make<Page>(*page_client);
+ page_client->m_svg_page = page.ptr();
+ auto browsing_context = HTML::BrowsingContext::create_a_new_top_level_browsing_context(*page);
+ auto response = Fetch::Infrastructure::Response::create(browsing_context->vm());
+ response->url_list().append(url);
+ HTML::NavigationParams navigation_params {
+ .id = {},
+ .request = nullptr,
+ .response = response,
+ .origin = HTML::Origin {},
+ .policy_container = HTML::PolicyContainer {},
+ .final_sandboxing_flag_set = HTML::SandboxingFlagSet {},
+ .cross_origin_opener_policy = HTML::CrossOriginOpenerPolicy {},
+ .coop_enforcement_result = HTML::CrossOriginOpenerPolicyEnforcementResult {},
+ .reserved_environment = {},
+ .browsing_context = browsing_context,
+ .navigable = nullptr,
+ };
+ auto document = DOM::Document::create_and_initialize(DOM::Document::Type::HTML, "text/html", move(navigation_params)).release_value_but_fixme_should_propagate_errors();
+ browsing_context->set_active_document(document);
+
+ auto parser = HTML::HTMLParser::create_with_uncertain_encoding(document, data);
+ parser->run(document->url());
+
+ // Perform some DOM surgery to make the SVG root element be the first child of the Document.
+ // FIXME: This is a huge hack until we figure out how to actually parse separate SVG files.
+ auto* svg_root = document->body()->first_child_of_type<SVG::SVGSVGElement>();
+ svg_root->remove();
+ document->remove_all_children();
+
+ MUST(document->append_child(*svg_root));
+
+ return adopt_nonnull_ref_or_enomem(new (nothrow) SVGDecodedImageData(move(page), move(page_client), move(document), move(svg_root)));
}
-SVGDecodedImageData::SVGDecodedImageData()
+SVGDecodedImageData::SVGDecodedImageData(NonnullOwnPtr<Page> page, NonnullOwnPtr<SVGPageClient> page_client, JS::Handle<DOM::Document> document, JS::Handle<SVG::SVGSVGElement> root_element)
+ : m_page(move(page))
+ , m_page_client(move(page_client))
+ , m_document(move(document))
+ , m_root_element(move(root_element))
{
}
SVGDecodedImageData::~SVGDecodedImageData() = default;
-RefPtr<Gfx::Bitmap const> SVGDecodedImageData::bitmap(size_t, Gfx::IntSize) const
+void SVGDecodedImageData::render(Gfx::IntSize size) const
{
- return nullptr;
+ m_document->browsing_context()->set_viewport_rect({ 0, 0, size.width(), size.height() });
+ m_document->update_layout();
+
+ dump_tree(*m_document->layout_node());
+
+ Gfx::Painter painter(*m_bitmap);
+ PaintContext context(painter, m_page_client->palette(), m_page_client->device_pixels_per_css_pixel());
+
+ m_document->layout_node()->paint_all_phases(context);
+}
+
+RefPtr<Gfx::Bitmap const> SVGDecodedImageData::bitmap(size_t, Gfx::IntSize size) const
+{
+ if (size.is_empty())
+ return nullptr;
+
+ if (m_bitmap && m_bitmap->size() == size)
+ return m_bitmap;
+
+ m_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, size).release_value_but_fixme_should_propagate_errors();
+ render(size);
+ return m_bitmap;
}
Optional<CSSPixels> SVGDecodedImageData::intrinsic_width() const
diff --git a/Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.h b/Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.h
index 1adc482684..355e954614 100644
--- a/Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.h
+++ b/Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.h
@@ -12,7 +12,7 @@ namespace Web::SVG {
class SVGDecodedImageData final : public HTML::DecodedImageData {
public:
- static ErrorOr<NonnullRefPtr<SVGDecodedImageData>> create(ByteBuffer encoded_svg);
+ static ErrorOr<NonnullRefPtr<SVGDecodedImageData>> create(Page&, AK::URL const&, ByteBuffer encoded_svg);
virtual ~SVGDecodedImageData() override;
virtual RefPtr<Gfx::Bitmap const> bitmap(size_t frame_index, Gfx::IntSize) const override;
@@ -28,7 +28,17 @@ public:
virtual bool is_animated() const override { return false; }
private:
- SVGDecodedImageData();
+ class SVGPageClient;
+ SVGDecodedImageData(NonnullOwnPtr<Page>, NonnullOwnPtr<SVGPageClient>, JS::Handle<DOM::Document>, JS::Handle<SVG::SVGSVGElement>);
+
+ void render(Gfx::IntSize) const;
+ mutable RefPtr<Gfx::Bitmap> m_bitmap;
+
+ NonnullOwnPtr<Page> m_page;
+ NonnullOwnPtr<SVGPageClient> m_page_client;
+
+ JS::Handle<DOM::Document> m_document;
+ JS::Handle<SVG::SVGSVGElement> m_root_element;
};
}