mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-10 13:00:29 +03:00
LibWeb+Browser: Decode non-animated images out-of-process :^)
We now use the ImageDecoder service in LibWeb for everything except GIF images (we'll have to deal with them later, ofc.) This has a little bit of overhead but we should be able to optimize it until it becomes negligible.
This commit is contained in:
parent
b273b31c7d
commit
10255bc5c6
Notes:
sideshowbarker
2024-07-19 05:26:30 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/10255bc5c66
@ -102,6 +102,11 @@ int main(int argc, char** argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (unveil("/tmp/portal/image", "rw") < 0) {
|
||||
perror("unveil");
|
||||
return 1;
|
||||
}
|
||||
|
||||
unveil(nullptr, nullptr);
|
||||
|
||||
auto m_config = Core::ConfigFile::get_for_app("Browser");
|
||||
|
@ -193,4 +193,4 @@ add_custom_command(
|
||||
)
|
||||
|
||||
serenity_lib(LibWeb web)
|
||||
target_link_libraries(LibWeb LibCore LibJS LibMarkdown LibGemini LibGUI LibGfx LibTextCodec LibProtocol)
|
||||
target_link_libraries(LibWeb LibCore LibJS LibMarkdown LibGemini LibGUI LibGfx LibTextCodec LibProtocol LibImageDecoderClient)
|
||||
|
@ -77,11 +77,6 @@ RefPtr<LayoutNode> HTMLImageElement::create_layout_node(const StyleProperties* p
|
||||
return adopt(*new LayoutImage(*this, move(style), m_image_loader));
|
||||
}
|
||||
|
||||
const Gfx::ImageDecoder* HTMLImageElement::image_decoder() const
|
||||
{
|
||||
return m_image_loader.image_decoder();
|
||||
}
|
||||
|
||||
const Gfx::Bitmap* HTMLImageElement::bitmap() const
|
||||
{
|
||||
return m_image_loader.bitmap();
|
||||
|
@ -49,7 +49,6 @@ public:
|
||||
String src() const { return attribute(HTML::AttributeNames::src); }
|
||||
|
||||
const Gfx::Bitmap* bitmap() const;
|
||||
const Gfx::ImageDecoder* image_decoder() const;
|
||||
|
||||
private:
|
||||
void animate();
|
||||
|
@ -44,14 +44,12 @@ LayoutImage::~LayoutImage()
|
||||
|
||||
int LayoutImage::preferred_width() const
|
||||
{
|
||||
auto* decoder = m_image_loader.image_decoder();
|
||||
return node().attribute(HTML::AttributeNames::width).to_int().value_or(decoder ? decoder->width() : 0);
|
||||
return node().attribute(HTML::AttributeNames::width).to_int().value_or(m_image_loader.width());
|
||||
}
|
||||
|
||||
int LayoutImage::preferred_height() const
|
||||
{
|
||||
auto* decoder = m_image_loader.image_decoder();
|
||||
return node().attribute(HTML::AttributeNames::height).to_int().value_or(decoder ? decoder->height() : 0);
|
||||
return node().attribute(HTML::AttributeNames::height).to_int().value_or(m_image_loader.height());
|
||||
}
|
||||
|
||||
void LayoutImage::layout(LayoutMode layout_mode)
|
||||
@ -97,8 +95,8 @@ void LayoutImage::paint(PaintContext& context, PaintPhase phase)
|
||||
if (alt.is_empty())
|
||||
alt = image_element.src();
|
||||
context.painter().draw_text(enclosing_int_rect(absolute_rect()), alt, Gfx::TextAlignment::Center, style().color_or_fallback(CSS::PropertyID::Color, document(), Color::Black), Gfx::TextElision::Right);
|
||||
} else if (m_image_loader.bitmap()) {
|
||||
context.painter().draw_scaled_bitmap(enclosing_int_rect(absolute_rect()), *m_image_loader.bitmap(), m_image_loader.bitmap()->rect());
|
||||
} else if (auto* bitmap = m_image_loader.bitmap()) {
|
||||
context.painter().draw_scaled_bitmap(enclosing_int_rect(absolute_rect()), *bitmap, bitmap->rect());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -106,7 +104,7 @@ void LayoutImage::paint(PaintContext& context, PaintPhase phase)
|
||||
bool LayoutImage::renders_as_alt_text() const
|
||||
{
|
||||
if (is<HTMLImageElement>(node()))
|
||||
return !m_image_loader.image_decoder();
|
||||
return !m_image_loader.has_image();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -67,11 +67,15 @@ void ImageLoader::resource_did_load()
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef IMAGE_LOADER_DEBUG
|
||||
if (!resource()->has_encoded_data()) {
|
||||
dbg() << "ImageLoader: Resource did load, no encoded data. URL: " << resource()->url();
|
||||
} else {
|
||||
dbg() << "ImageLoader: Resource did load, has encoded data. URL: " << resource()->url();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (resource()->should_decode_in_process()) {
|
||||
m_decoder = resource()->ensure_decoder();
|
||||
|
||||
if (m_decoder->is_animated() && m_decoder->frame_count() > 1) {
|
||||
@ -80,6 +84,7 @@ void ImageLoader::resource_did_load()
|
||||
m_timer->on_timeout = [this] { animate(); };
|
||||
m_timer->start();
|
||||
}
|
||||
}
|
||||
|
||||
if (on_load)
|
||||
on_load();
|
||||
@ -120,16 +125,43 @@ void ImageLoader::resource_did_fail()
|
||||
|
||||
void ImageLoader::resource_did_replace_decoder()
|
||||
{
|
||||
if (resource()->should_decode_in_process()) {
|
||||
m_decoder = resource()->ensure_decoder();
|
||||
}
|
||||
}
|
||||
|
||||
bool ImageLoader::has_image() const
|
||||
{
|
||||
if (!resource())
|
||||
return false;
|
||||
if (resource()->should_decode_in_process())
|
||||
return image_decoder();
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned ImageLoader::width() const
|
||||
{
|
||||
if (!resource())
|
||||
return 0;
|
||||
if (resource()->should_decode_in_process())
|
||||
return image_decoder() ? image_decoder()->width() : 0;
|
||||
return bitmap() ? bitmap()->width() : 0;
|
||||
}
|
||||
|
||||
unsigned ImageLoader::height() const
|
||||
{
|
||||
if (!resource())
|
||||
return 0;
|
||||
if (resource()->should_decode_in_process())
|
||||
return image_decoder() ? image_decoder()->height() : 0;
|
||||
return bitmap() ? bitmap()->height() : 0;
|
||||
}
|
||||
|
||||
const Gfx::Bitmap* ImageLoader::bitmap() const
|
||||
{
|
||||
if (!m_decoder)
|
||||
if (!resource())
|
||||
return nullptr;
|
||||
if (m_decoder->is_animated())
|
||||
return m_decoder->frame(m_current_frame_index).image;
|
||||
return m_decoder->bitmap();
|
||||
return resource()->bitmap(0);
|
||||
}
|
||||
|
||||
const Gfx::ImageDecoder* ImageLoader::image_decoder() const
|
||||
|
@ -41,8 +41,13 @@ public:
|
||||
const Gfx::Bitmap* bitmap() const;
|
||||
const Gfx::ImageDecoder* image_decoder() const;
|
||||
|
||||
bool has_image() const;
|
||||
|
||||
void set_visible_in_viewport(bool) const;
|
||||
|
||||
unsigned width() const;
|
||||
unsigned height() const;
|
||||
|
||||
Function<void()> on_load;
|
||||
Function<void()> on_fail;
|
||||
Function<void()> on_animate;
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <AK/Function.h>
|
||||
#include <LibGfx/Bitmap.h>
|
||||
#include <LibGfx/ImageDecoder.h>
|
||||
#include <LibImageDecoderClient/Client.h>
|
||||
#include <LibWeb/Loader/ImageResource.h>
|
||||
|
||||
namespace Web {
|
||||
@ -40,6 +41,11 @@ ImageResource::~ImageResource()
|
||||
{
|
||||
}
|
||||
|
||||
bool ImageResource::should_decode_in_process() const
|
||||
{
|
||||
return mime_type() == "image/gif";
|
||||
}
|
||||
|
||||
Gfx::ImageDecoder& ImageResource::ensure_decoder()
|
||||
{
|
||||
if (!m_decoder)
|
||||
@ -47,6 +53,26 @@ Gfx::ImageDecoder& ImageResource::ensure_decoder()
|
||||
return *m_decoder;
|
||||
}
|
||||
|
||||
const Gfx::Bitmap* ImageResource::bitmap(size_t frame_index) const
|
||||
{
|
||||
if (!has_encoded_data())
|
||||
return nullptr;
|
||||
|
||||
if (should_decode_in_process()) {
|
||||
if (!m_decoder)
|
||||
return nullptr;
|
||||
if (m_decoder->is_animated())
|
||||
return m_decoder->frame(frame_index).image;
|
||||
return m_decoder->bitmap();
|
||||
}
|
||||
if (!m_decoded_image && !m_has_attempted_decode) {
|
||||
auto image_decoder_client = ImageDecoderClient::Client::construct();
|
||||
m_decoded_image = image_decoder_client->decode_image(encoded_data());
|
||||
m_has_attempted_decode = true;
|
||||
}
|
||||
return m_decoded_image;
|
||||
}
|
||||
|
||||
void ImageResource::update_volatility()
|
||||
{
|
||||
if (!m_decoder)
|
||||
|
@ -36,12 +36,17 @@ class ImageResource final : public Resource {
|
||||
public:
|
||||
virtual ~ImageResource() override;
|
||||
Gfx::ImageDecoder& ensure_decoder();
|
||||
const Gfx::Bitmap* bitmap(size_t frame_index) const;
|
||||
|
||||
bool should_decode_in_process() const;
|
||||
|
||||
void update_volatility();
|
||||
|
||||
private:
|
||||
explicit ImageResource(const LoadRequest&);
|
||||
RefPtr<Gfx::ImageDecoder> m_decoder;
|
||||
mutable RefPtr<Gfx::Bitmap> m_decoded_image;
|
||||
mutable bool m_has_attempted_decode { false };
|
||||
};
|
||||
|
||||
class ImageResourceClient : public ResourceClient {
|
||||
|
@ -107,15 +107,21 @@ void Resource::did_load(Badge<ResourceLoader>, const ByteBuffer& data, const Has
|
||||
|
||||
auto content_type = headers.get("Content-Type");
|
||||
if (content_type.has_value()) {
|
||||
#ifdef RESOURCE_DEBUG
|
||||
dbg() << "Content-Type header: _" << content_type.value() << "_";
|
||||
#endif
|
||||
m_encoding = encoding_from_content_type(content_type.value());
|
||||
m_mime_type = mime_type_from_content_type(content_type.value());
|
||||
} else if (url().protocol() == "data" && !url().data_mime_type().is_empty()) {
|
||||
#ifdef RESOURCE_DEBUG
|
||||
dbg() << "This is a data URL with mime-type _" << url().data_mime_type() << "_";
|
||||
#endif
|
||||
m_encoding = "utf-8"; // FIXME: This doesn't seem nice.
|
||||
m_mime_type = url().data_mime_type();
|
||||
} else {
|
||||
#ifdef RESOURCE_DEBUG
|
||||
dbg() << "No Content-Type header to go on! Guessing based on filename...";
|
||||
#endif
|
||||
m_encoding = "utf-8"; // FIXME: This doesn't seem nice.
|
||||
m_mime_type = guess_mime_type_based_on_filename(url());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user