Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LibWeb: Calculate image size in CSS pixels #2982

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 33 additions & 33 deletions Libraries/LibWeb/Painting/ImagePaintable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,28 +62,28 @@ void ImagePaintable::paint(PaintContext& context, PaintPhase phase) const
PaintableBox::paint(context, phase);

if (phase == PaintPhase::Foreground) {
auto image_rect = context.rounded_device_rect(absolute_rect());
auto image_rect = absolute_rect();
auto image_rect_device_pixels = context.rounded_device_rect(image_rect);
if (m_renders_as_alt_text) {
auto enclosing_rect = context.enclosing_device_rect(absolute_rect()).to_type<int>();
auto enclosing_rect = context.enclosing_device_rect(image_rect).to_type<int>();
context.display_list_recorder().draw_rect(enclosing_rect, Gfx::Color::Black);
context.display_list_recorder().draw_text(enclosing_rect, m_alt_text, Platform::FontPlugin::the().default_font(), Gfx::TextAlignment::Center, computed_values().color());
} else if (auto bitmap = m_image_provider.current_image_bitmap(image_rect.size().to_type<int>())) {
ScopedCornerRadiusClip corner_clip { context, image_rect, normalized_border_radii_data(ShrinkRadiiForBorders::Yes) };
auto image_int_rect = image_rect.to_type<int>();
} else if (auto bitmap = m_image_provider.current_image_bitmap(image_rect_device_pixels.size().to_type<int>())) {
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>();
auto bitmap_rect = bitmap->rect();
auto scaling_mode = to_gfx_scaling_mode(computed_values().image_rendering(), bitmap_rect, image_int_rect);
auto scaling_mode = to_gfx_scaling_mode(computed_values().image_rendering(), bitmap_rect, image_int_rect_device_pixels);
auto bitmap_aspect_ratio = (float)bitmap_rect.height() / bitmap_rect.width();
auto image_aspect_ratio = (float)image_rect.height().value() / image_rect.width().value();
auto image_aspect_ratio = (float)image_rect.height() / (float)image_rect.width();

// FIXME: Scale may be wrong if device-pixels != css-pixels.
auto scale_x = 0.0f;
auto scale_y = 0.0f;
Gfx::IntRect bitmap_intersect = bitmap_rect;

// https://drafts.csswg.org/css-images/#the-object-fit
auto object_fit = m_is_svg_image ? CSS::ObjectFit::Contain : computed_values().object_fit();
if (object_fit == CSS::ObjectFit::ScaleDown) {
if (bitmap_rect.width() > image_int_rect.width() || bitmap_rect.height() > image_int_rect.height()) {
if (bitmap_rect.width() > image_rect.width() || bitmap_rect.height() > image_rect.height()) {
object_fit = CSS::ObjectFit::Contain;
} else {
object_fit = CSS::ObjectFit::None;
Expand All @@ -92,25 +92,25 @@ void ImagePaintable::paint(PaintContext& context, PaintPhase phase) const

switch (object_fit) {
case CSS::ObjectFit::Fill:
scale_x = (float)image_int_rect.width() / bitmap_rect.width();
scale_y = (float)image_int_rect.height() / bitmap_rect.height();
scale_x = (float)image_rect.width() / bitmap_rect.width();
scale_y = (float)image_rect.height() / bitmap_rect.height();
break;
case CSS::ObjectFit::Contain:
if (bitmap_aspect_ratio >= image_aspect_ratio) {
scale_x = (float)image_int_rect.height() / bitmap_rect.height();
scale_x = (float)image_rect.height() / bitmap_rect.height();
scale_y = scale_x;
} else {
scale_x = (float)image_int_rect.width() / bitmap_rect.width();
scale_x = (float)image_rect.width() / bitmap_rect.width();
scale_y = scale_x;
}
break;
case CSS::ObjectFit::Cover:
if (bitmap_aspect_ratio >= image_aspect_ratio) {
scale_x = (float)image_int_rect.width() / bitmap_rect.width();
scale_x = (float)image_rect.width() / bitmap_rect.width();
scale_y = scale_x;
bitmap_intersect.set_height(bitmap_rect.width() * image_aspect_ratio);
} else {
scale_x = (float)image_int_rect.height() / bitmap_rect.height();
scale_x = (float)image_rect.height() / bitmap_rect.height();
scale_y = scale_x;
bitmap_intersect.set_width(bitmap_rect.height() / image_aspect_ratio);
}
Expand All @@ -120,49 +120,49 @@ void ImagePaintable::paint(PaintContext& context, PaintPhase phase) const
case CSS::ObjectFit::None:
scale_x = 1;
scale_y = 1;
bitmap_intersect.set_size(image_int_rect.size());
bitmap_intersect.set_size(image_rect.size().to_type<int>());
}

auto scaled_bitmap_width = bitmap_rect.width() * scale_x;
auto scaled_bitmap_height = bitmap_rect.height() * scale_y;
auto scaled_bitmap_width = CSSPixels::nearest_value_for(bitmap_rect.width() * scale_x);
auto scaled_bitmap_height = CSSPixels::nearest_value_for(bitmap_rect.height() * scale_y);

auto residual_horizontal = CSSPixels::nearest_value_for(image_int_rect.width() - scaled_bitmap_width);
auto residual_vertical = CSSPixels::nearest_value_for(image_int_rect.height() - scaled_bitmap_height);
auto residual_horizontal = image_rect.width() - scaled_bitmap_width;
auto residual_vertical = image_rect.height() - scaled_bitmap_height;

bitmap_intersect.set_x((bitmap_rect.width() - bitmap_intersect.width()) / 2);
bitmap_intersect.set_y((bitmap_rect.height() - bitmap_intersect.height()) / 2);

// https://drafts.csswg.org/css-images/#the-object-position
auto const& object_position = computed_values().object_position();

auto offset_x = 0;
auto offset_x = CSSPixels::from_raw(0);
if (object_position.edge_x == CSS::PositionEdge::Left) {
offset_x = object_position.offset_x.to_px(layout_node(), residual_horizontal).to_int();
offset_x = object_position.offset_x.to_px(layout_node(), residual_horizontal);
bitmap_intersect.set_x(0);
} else if (object_position.edge_x == CSS::PositionEdge::Right) {
offset_x = residual_horizontal.to_int() - object_position.offset_x.to_px(layout_node(), residual_horizontal).to_int();
offset_x = residual_horizontal - object_position.offset_x.to_px(layout_node(), residual_horizontal);
}
if (image_int_rect.width() < scaled_bitmap_width)
if (image_rect.width() < scaled_bitmap_width)
bitmap_intersect.set_x(-(offset_x / scale_x));

auto offset_y = 0;
auto offset_y = CSSPixels::from_raw(0);
if (object_position.edge_y == CSS::PositionEdge::Top) {
offset_y = object_position.offset_y.to_px(layout_node(), residual_vertical).to_int();
offset_y = object_position.offset_y.to_px(layout_node(), residual_vertical);
bitmap_intersect.set_y(0);
} else if (object_position.edge_y == CSS::PositionEdge::Bottom) {
offset_y = residual_vertical.to_int() - object_position.offset_y.to_px(layout_node(), residual_vertical).to_int();
offset_y = residual_vertical - object_position.offset_y.to_px(layout_node(), residual_vertical);
}
if (image_int_rect.height() < scaled_bitmap_height)
if (image_rect.height() < scaled_bitmap_height)
bitmap_intersect.set_y(-(offset_y / scale_y));

Gfx::IntRect draw_rect = {
image_int_rect.x() + offset_x,
image_int_rect.y() + offset_y,
(int)scaled_bitmap_width,
(int)scaled_bitmap_height
image_int_rect_device_pixels.x() + context.rounded_device_pixels(offset_x).value(),
image_int_rect_device_pixels.y() + context.rounded_device_pixels(offset_y).value(),
context.rounded_device_pixels(scaled_bitmap_width).value(),
context.rounded_device_pixels(scaled_bitmap_height).value()
};

context.display_list_recorder().draw_scaled_immutable_bitmap(draw_rect.intersected(image_int_rect), *bitmap, bitmap_rect.intersected(bitmap_intersect), scaling_mode);
context.display_list_recorder().draw_scaled_immutable_bitmap(draw_rect.intersected(image_int_rect_device_pixels), *bitmap, bitmap_rect.intersected(bitmap_intersect), scaling_mode);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion Tests/LibWeb/Ref/expected/svg-image-positioning-ref.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
</svg>
<svg width="300" height="300">
<rect x="0" y="0" width="250" height="250" fill="red" />
<rect width="250" height="166" fill="green" />
<rect width="250" height="167" fill="green" />
</svg>
<svg width="300" height="300">
<rect x="0" y="0" width="250" height="250" fill="red" />
Expand Down
Binary file modified Tests/LibWeb/Screenshot/images/object-fit-position.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading