2022-03-10 10:02:25 -03:00
|
|
|
/*
|
2024-10-04 08:19:50 -03:00
|
|
|
* Copyright (c) 2018-2023, Andreas Kling <andreas@ladybird.org>
|
2026-01-30 06:25:36 -03:00
|
|
|
* Copyright (c) 2026, Jelle Raaijmakers <jelle@ladybird.org>
|
2022-03-10 10:02:25 -03:00
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
|
*/
|
|
|
|
|
|
2025-11-23 09:07:35 -03:00
|
|
|
#include <LibGfx/ImmutableBitmap.h>
|
2023-10-16 08:54:19 -03:00
|
|
|
#include <LibWeb/CSS/StyleValues/PositionStyleValue.h>
|
2023-05-11 14:23:36 -03:00
|
|
|
#include <LibWeb/HTML/DecodedImageData.h>
|
2022-03-10 10:02:25 -03:00
|
|
|
#include <LibWeb/HTML/HTMLImageElement.h>
|
2022-06-15 17:29:55 -03:00
|
|
|
#include <LibWeb/Painting/BorderRadiusCornerClipper.h>
|
2025-02-02 11:55:26 -03:00
|
|
|
#include <LibWeb/Painting/DisplayListRecorder.h>
|
2022-03-10 10:02:25 -03:00
|
|
|
#include <LibWeb/Painting/ImagePaintable.h>
|
2026-04-18 08:40:34 -03:00
|
|
|
#include <LibWeb/Painting/ReplacedElementCommon.h>
|
2022-09-17 16:25:50 -03:00
|
|
|
#include <LibWeb/Platform/FontPlugin.h>
|
2022-03-10 10:02:25 -03:00
|
|
|
|
|
|
|
|
namespace Web::Painting {
|
|
|
|
|
|
2024-11-14 12:01:23 -03:00
|
|
|
GC_DEFINE_ALLOCATOR(ImagePaintable);
|
2024-04-06 14:16:04 -03:00
|
|
|
|
2024-11-14 12:01:23 -03:00
|
|
|
GC::Ref<ImagePaintable> ImagePaintable::create(Layout::SVGImageBox const& layout_box)
|
2024-08-20 11:12:55 -03:00
|
|
|
{
|
2024-11-13 14:13:46 -03:00
|
|
|
return layout_box.heap().allocate<ImagePaintable>(layout_box, layout_box.dom_node(), false, String {}, true);
|
2024-08-20 11:12:55 -03:00
|
|
|
}
|
|
|
|
|
|
2024-11-14 12:01:23 -03:00
|
|
|
GC::Ref<ImagePaintable> ImagePaintable::create(Layout::ImageBox const& layout_box)
|
2022-03-10 10:02:25 -03:00
|
|
|
{
|
2025-07-26 09:22:50 -03:00
|
|
|
String alt;
|
|
|
|
|
if (auto element = layout_box.dom_node())
|
|
|
|
|
alt = element->get_attribute_value(HTML::AttributeNames::alt);
|
2024-11-13 14:13:46 -03:00
|
|
|
return layout_box.heap().allocate<ImagePaintable>(layout_box, layout_box.image_provider(), layout_box.renders_as_alt_text(), move(alt), false);
|
2022-03-10 10:02:25 -03:00
|
|
|
}
|
|
|
|
|
|
2024-08-20 11:12:55 -03:00
|
|
|
ImagePaintable::ImagePaintable(Layout::Box const& layout_box, Layout::ImageProvider const& image_provider, bool renders_as_alt_text, String alt_text, bool is_svg_image)
|
2022-03-10 11:50:57 -03:00
|
|
|
: PaintableBox(layout_box)
|
2024-08-20 11:12:55 -03:00
|
|
|
, m_renders_as_alt_text(renders_as_alt_text)
|
2024-02-26 05:18:31 -03:00
|
|
|
, m_alt_text(move(alt_text))
|
2024-08-20 11:12:55 -03:00
|
|
|
, m_image_provider(image_provider)
|
|
|
|
|
, m_is_svg_image(is_svg_image)
|
2022-03-10 10:02:25 -03:00
|
|
|
{
|
2023-05-09 02:02:28 -03:00
|
|
|
}
|
|
|
|
|
|
2024-02-26 05:38:52 -03:00
|
|
|
void ImagePaintable::visit_edges(JS::Cell::Visitor& visitor)
|
|
|
|
|
{
|
|
|
|
|
Base::visit_edges(visitor);
|
2025-07-26 09:54:12 -03:00
|
|
|
m_image_provider.image_provider_visit_edges(visitor);
|
2024-02-26 05:38:52 -03:00
|
|
|
}
|
|
|
|
|
|
2026-01-20 13:34:27 -03:00
|
|
|
void ImagePaintable::reset_for_relayout()
|
|
|
|
|
{
|
|
|
|
|
PaintableBox::reset_for_relayout();
|
|
|
|
|
|
|
|
|
|
if (!m_is_svg_image) {
|
|
|
|
|
m_renders_as_alt_text = !m_image_provider.is_image_available();
|
|
|
|
|
if (auto const* image_box = as_if<Layout::ImageBox>(layout_node())) {
|
|
|
|
|
if (auto element = image_box->dom_node())
|
|
|
|
|
m_alt_text = element->get_attribute_value(HTML::AttributeNames::alt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-31 18:07:26 -03:00
|
|
|
void ImagePaintable::paint(DisplayListRecordingContext& context, PaintPhase phase) const
|
2022-03-10 10:02:25 -03:00
|
|
|
{
|
|
|
|
|
if (!is_visible())
|
|
|
|
|
return;
|
|
|
|
|
|
2022-03-10 11:50:57 -03:00
|
|
|
PaintableBox::paint(context, phase);
|
2022-03-10 10:02:25 -03:00
|
|
|
|
|
|
|
|
if (phase == PaintPhase::Foreground) {
|
2024-12-19 18:07:34 -03:00
|
|
|
auto image_rect = absolute_rect();
|
|
|
|
|
auto image_rect_device_pixels = context.rounded_device_rect(image_rect);
|
2024-02-26 05:18:31 -03:00
|
|
|
if (m_renders_as_alt_text) {
|
2025-06-16 06:51:18 -03:00
|
|
|
if (!m_alt_text.is_empty()) {
|
|
|
|
|
auto enclosing_rect = context.enclosing_device_rect(image_rect).to_type<int>();
|
2026-02-03 08:18:25 -03:00
|
|
|
context.display_list_recorder().draw_text(enclosing_rect, Utf16String::from_utf8(m_alt_text), layout_node().font(context), Gfx::TextAlignment::Center, computed_values().color());
|
2025-06-16 06:51:18 -03:00
|
|
|
}
|
2025-11-04 17:22:50 -03:00
|
|
|
} else if (auto decoded_image_data = m_image_provider.decoded_image_data()) {
|
2024-12-19 18:07:34 -03:00
|
|
|
ScopedCornerRadiusClip corner_clip { context, image_rect_device_pixels, normalized_border_radii_data(ShrinkRadiiForBorders::Yes) };
|
|
|
|
|
auto image_int_rect_device_pixels = image_rect_device_pixels.to_type<int>();
|
2025-11-04 17:22:50 -03:00
|
|
|
auto bitmap_rect = decoded_image_data->frame_rect(m_image_provider.current_frame_index()).value_or(image_int_rect_device_pixels);
|
2025-11-12 05:37:53 -03:00
|
|
|
auto scaling_mode = to_gfx_scaling_mode(computed_values().image_rendering(), bitmap_rect.size(), image_int_rect_device_pixels.size());
|
2023-08-01 15:07:34 -03:00
|
|
|
|
2024-12-08 17:23:15 -03:00
|
|
|
// https://drafts.csswg.org/css-images/#the-object-fit
|
2024-08-20 11:12:55 -03:00
|
|
|
auto object_fit = m_is_svg_image ? CSS::ObjectFit::Contain : computed_values().object_fit();
|
2026-04-18 08:40:34 -03:00
|
|
|
auto draw_rect = get_replaced_box_painting_area(*this, context, object_fit, bitmap_rect.size());
|
2025-11-05 20:46:30 -03:00
|
|
|
if (!draw_rect.is_empty())
|
|
|
|
|
decoded_image_data->paint(context, m_image_provider.current_frame_index(), draw_rect, image_int_rect_device_pixels, scaling_mode);
|
2022-03-10 10:02:25 -03:00
|
|
|
}
|
2026-01-30 06:25:36 -03:00
|
|
|
|
|
|
|
|
if (selection_state() != SelectionState::None) {
|
2026-02-03 12:15:10 -03:00
|
|
|
auto selection_background_color = selection_style().background_color;
|
|
|
|
|
if (selection_background_color.alpha() > 0)
|
|
|
|
|
context.display_list_recorder().fill_rect(image_rect_device_pixels.to_type<int>(), selection_background_color);
|
2026-01-30 06:25:36 -03:00
|
|
|
}
|
2022-03-10 10:02:25 -03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|