1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 22:57:44 +00:00

LibWeb: Remove implicit conversion from float and double to CSSPixels

In general it is not safe to convert any arbitrary floating-point value
to CSSPixels. CSSPixels has a resolution of 0.015625, which for small
values (e.g. scale factors between 0 and 1), can produce bad results
if converted to CSSPixels then scaled back up. In the worst case values
can underflow to zero and produce incorrect results.
This commit is contained in:
MacDue 2023-08-26 15:03:04 +01:00 committed by Alexander Kalenik
parent 0f9c088302
commit 360c0eb509
43 changed files with 248 additions and 221 deletions

View file

@ -36,7 +36,7 @@ public:
CSSPixels to_px_or_zero() const
{
if (!is_definite())
return 0.0f;
return 0;
return m_value;
}

View file

@ -1069,7 +1069,7 @@ void BlockFormattingContext::layout_list_item_marker(ListItemBox const& list_ite
marker_state.set_content_width(image_width + default_marker_width);
} else {
auto text_width = marker.font().width(marker.text());
marker_state.set_content_width(image_width + text_width);
marker_state.set_content_width(image_width + CSSPixels(text_width));
}
marker_state.set_content_height(max(image_height, marker.font().pixel_size_rounded_up() + 1));

View file

@ -25,7 +25,7 @@ void ButtonBox::prepare_for_replaced_layout()
// value attribute. This is not the case with <button />, which contains
// its contents normally.
if (is<HTML::HTMLInputElement>(dom_node())) {
set_natural_width(font().width(static_cast<HTML::HTMLInputElement&>(dom_node()).value()));
set_natural_width(CSSPixels(font().width(static_cast<HTML::HTMLInputElement&>(dom_node()).value())));
set_natural_height(font().pixel_size_rounded_up());
}
}

View file

@ -540,15 +540,15 @@ CSS::FlexBasis FlexFormattingContext::used_flex_basis_for_item(FlexItem const& i
CSSPixels FlexFormattingContext::calculate_main_size_from_cross_size_and_aspect_ratio(CSSPixels cross_size, double aspect_ratio) const
{
if (is_row_layout())
return cross_size * aspect_ratio;
return cross_size / aspect_ratio;
return CSSPixels(cross_size * aspect_ratio);
return CSSPixels(cross_size / aspect_ratio);
}
CSSPixels FlexFormattingContext::calculate_cross_size_from_main_size_and_aspect_ratio(CSSPixels main_size, double aspect_ratio) const
{
if (is_row_layout())
return main_size / aspect_ratio;
return main_size * aspect_ratio;
return CSSPixels(main_size / aspect_ratio);
return CSSPixels(main_size * aspect_ratio);
}
// This function takes a size in the main axis and adjusts it according to the aspect ratio of the box
@ -687,7 +687,7 @@ void FlexFormattingContext::determine_flex_base_size_and_hypothetical_main_size(
// The hypothetical main size is the items flex base size clamped according to its used min and max main sizes (and flooring the content box size at zero).
auto clamp_min = has_main_min_size(child_box) ? specified_main_min_size(child_box) : automatic_minimum_size(item);
auto clamp_max = has_main_max_size(child_box) ? specified_main_max_size(child_box) : NumericLimits<float>::max();
auto clamp_max = has_main_max_size(child_box) ? specified_main_max_size(child_box) : CSSPixels::max();
item.hypothetical_main_size = max(CSSPixels(0), css_clamp(item.flex_base_size, clamp_min, clamp_max));
// NOTE: At this point, we set the hypothetical main size as the flex item's *temporary* main size.
@ -982,7 +982,7 @@ void FlexFormattingContext::resolve_flexible_lengths_for_line(FlexLine& line)
// If the sum of the unfrozen flex items flex factors is less than one, multiply the initial free space by this sum.
if (auto sum_of_flex_factor_of_unfrozen_items = line.sum_of_flex_factor_of_unfrozen_items(); sum_of_flex_factor_of_unfrozen_items < 1 && initial_free_space.has_value()) {
auto value = initial_free_space.value() * sum_of_flex_factor_of_unfrozen_items;
auto value = CSSPixels(initial_free_space.value() * sum_of_flex_factor_of_unfrozen_items);
// If the magnitude of this value is less than the magnitude of the remaining free space, use this as the remaining free space.
if (abs(value) < abs(line.remaining_free_space.value()))
line.remaining_free_space = value;
@ -1004,7 +1004,7 @@ void FlexFormattingContext::resolve_flexible_lengths_for_line(FlexLine& line)
continue;
double ratio = item.flex_factor.value() / sum_of_flex_factor_of_unfrozen_items;
// Set the items target main size to its flex base size plus a fraction of the remaining free space proportional to the ratio.
item.target_main_size = item.flex_base_size + (remaining_free_space_or_zero_if_infinite * ratio);
item.target_main_size = item.flex_base_size + remaining_free_space_or_zero_if_infinite.scaled(ratio);
}
}
// If using the flex shrink factor
@ -1026,7 +1026,7 @@ void FlexFormattingContext::resolve_flexible_lengths_for_line(FlexLine& line)
// Set the items target main size to its flex base size minus a fraction of the absolute value of the remaining free space proportional to the ratio.
// (Note this may result in a negative inner main size; it will be corrected in the next step.)
item.target_main_size = item.flex_base_size - (abs(remaining_free_space_or_zero_if_infinite) * ratio);
item.target_main_size = item.flex_base_size - abs(remaining_free_space_or_zero_if_infinite).scaled(ratio);
}
}
}
@ -1044,7 +1044,7 @@ void FlexFormattingContext::resolve_flexible_lengths_for_line(FlexLine& line)
auto used_max_main_size = has_main_max_size(item.box)
? specified_main_max_size(item.box)
: NumericLimits<float>::max();
: CSSPixels::max();
auto original_target_main_size = item.target_main_size;
item.target_main_size = css_clamp(item.target_main_size, used_min_main_size, used_max_main_size);
@ -1123,7 +1123,7 @@ void FlexFormattingContext::determine_hypothetical_cross_size_of_item(FlexItem&
auto const& computed_max_size = this->computed_cross_max_size(item.box);
auto clamp_min = (!computed_min_size.is_auto() && (resolve_percentage_min_max_sizes || !computed_min_size.contains_percentage())) ? specified_cross_min_size(item.box) : 0;
auto clamp_max = (!computed_max_size.is_none() && (resolve_percentage_min_max_sizes || !computed_max_size.contains_percentage())) ? specified_cross_max_size(item.box) : NumericLimits<float>::max();
auto clamp_max = (!computed_max_size.is_none() && (resolve_percentage_min_max_sizes || !computed_max_size.contains_percentage())) ? specified_cross_max_size(item.box) : CSSPixels::max();
// If we have a definite cross size, this is easy! No need to perform layout, we can just use it as-is.
if (has_definite_cross_size(item.box)) {
@ -1339,7 +1339,7 @@ void FlexFormattingContext::distribute_any_remaining_free_space()
}
break;
case CSS::JustifyContent::Center:
initial_offset = (inner_main_size(flex_container()) - used_main_space) / 2.0;
initial_offset = (inner_main_size(flex_container()) - used_main_space) / 2;
if (is_direction_reverse()) {
initial_offset = inner_main_size(flex_container()) - initial_offset;
}
@ -1357,9 +1357,9 @@ void FlexFormattingContext::distribute_any_remaining_free_space()
if (flex_line.remaining_free_space.has_value())
space_between_items = flex_line.remaining_free_space.value() / number_of_items;
if (is_direction_reverse()) {
initial_offset = inner_main_size(flex_container()) - space_between_items / 2.0;
initial_offset = inner_main_size(flex_container()) - space_between_items / 2;
} else {
initial_offset = space_between_items / 2.0;
initial_offset = space_between_items / 2;
}
break;
case CSS::JustifyContent::SpaceEvenly:
@ -1496,7 +1496,7 @@ void FlexFormattingContext::align_all_flex_items_along_the_cross_axis()
// FIXME: Take better care of margins
for (auto& flex_line : m_flex_lines) {
for (auto& item : flex_line.items) {
CSSPixels half_line_size = flex_line.cross_size / 2.0;
CSSPixels half_line_size = flex_line.cross_size / 2;
switch (alignment_for_item(item.box)) {
case CSS::AlignItems::Baseline:
// FIXME: Implement this
@ -1512,7 +1512,7 @@ void FlexFormattingContext::align_all_flex_items_along_the_cross_axis()
item.cross_offset = half_line_size - item.cross_size.value() - item.margins.cross_after - item.borders.cross_after - item.padding.cross_after;
break;
case CSS::AlignItems::Center:
item.cross_offset = -(item.cross_size.value() / 2.0);
item.cross_offset = -(item.cross_size.value() / 2);
break;
default:
break;
@ -1573,7 +1573,7 @@ void FlexFormattingContext::align_all_flex_lines()
if (is_single_line()) {
// For single-line flex containers, we only need to center the line along the cross axis.
auto& flex_line = m_flex_lines[0];
CSSPixels center_of_line = cross_size_of_flex_container / 2.0;
CSSPixels center_of_line = cross_size_of_flex_container / 2;
for (auto& item : flex_line.items) {
item.cross_offset += center_of_line;
}
@ -1732,15 +1732,15 @@ CSSPixels FlexFormattingContext::calculate_intrinsic_main_size_of_flex_container
CSSPixels result = contribution - outer_flex_base_size;
if (result > 0) {
if (item.box->computed_values().flex_grow() >= 1) {
result /= item.box->computed_values().flex_grow();
result.scale_by(1 / item.box->computed_values().flex_grow());
} else {
result *= item.box->computed_values().flex_grow();
result.scale_by(item.box->computed_values().flex_grow());
}
} else if (result < 0) {
if (item.scaled_flex_shrink_factor == 0)
result = CSSPixels::min();
else
result /= item.scaled_flex_shrink_factor;
result.scale_by(1 / item.scaled_flex_shrink_factor);
}
item.desired_flex_fraction = result.to_double();
@ -1793,13 +1793,13 @@ CSSPixels FlexFormattingContext::calculate_intrinsic_main_size_of_flex_container
product = flex_line.chosen_flex_fraction * static_cast<double>(item.box->computed_values().flex_grow());
else if (item.desired_flex_fraction < 0)
product = flex_line.chosen_flex_fraction * item.scaled_flex_shrink_factor;
auto result = item.flex_base_size + product;
auto result = item.flex_base_size + CSSPixels(product);
auto const& computed_min_size = this->computed_main_min_size(item.box);
auto const& computed_max_size = this->computed_main_max_size(item.box);
auto clamp_min = (!computed_min_size.is_auto() && !computed_min_size.contains_percentage()) ? specified_main_min_size(item.box) : automatic_minimum_size(item);
auto clamp_max = (!computed_max_size.is_none() && !computed_max_size.contains_percentage()) ? specified_main_max_size(item.box) : NumericLimits<float>::max();
auto clamp_max = (!computed_max_size.is_none() && !computed_max_size.contains_percentage()) ? specified_main_max_size(item.box) : CSSPixels::max();
result = css_clamp(result, clamp_min, clamp_max);
@ -1906,7 +1906,7 @@ CSSPixels FlexFormattingContext::calculate_main_min_content_contribution(FlexIte
}();
auto clamp_min = has_main_min_size(item.box) ? specified_main_min_size(item.box) : automatic_minimum_size(item);
auto clamp_max = has_main_max_size(item.box) ? specified_main_max_size(item.box) : NumericLimits<float>::max();
auto clamp_max = has_main_max_size(item.box) ? specified_main_max_size(item.box) : CSSPixels::max();
auto clamped_inner_size = css_clamp(larger_size, clamp_min, clamp_max);
return item.add_main_margin_box_sizes(clamped_inner_size);
@ -1927,7 +1927,7 @@ CSSPixels FlexFormattingContext::calculate_main_max_content_contribution(FlexIte
}();
auto clamp_min = has_main_min_size(item.box) ? specified_main_min_size(item.box) : automatic_minimum_size(item);
auto clamp_max = has_main_max_size(item.box) ? specified_main_max_size(item.box) : NumericLimits<float>::max();
auto clamp_max = has_main_max_size(item.box) ? specified_main_max_size(item.box) : CSSPixels::max();
auto clamped_inner_size = css_clamp(larger_size, clamp_min, clamp_max);
return item.add_main_margin_box_sizes(clamped_inner_size);
@ -1959,7 +1959,7 @@ CSSPixels FlexFormattingContext::calculate_cross_min_content_contribution(FlexIt
auto const& computed_max_size = this->computed_cross_max_size(item.box);
auto clamp_min = (!computed_min_size.is_auto() && (resolve_percentage_min_max_sizes || !computed_min_size.contains_percentage())) ? specified_cross_min_size(item.box) : 0;
auto clamp_max = (!computed_max_size.is_none() && (resolve_percentage_min_max_sizes || !computed_max_size.contains_percentage())) ? specified_cross_max_size(item.box) : NumericLimits<float>::max();
auto clamp_max = (!computed_max_size.is_none() && (resolve_percentage_min_max_sizes || !computed_max_size.contains_percentage())) ? specified_cross_max_size(item.box) : CSSPixels::max();
auto clamped_inner_size = css_clamp(size, clamp_min, clamp_max);
@ -1978,7 +1978,7 @@ CSSPixels FlexFormattingContext::calculate_cross_max_content_contribution(FlexIt
auto const& computed_max_size = this->computed_cross_max_size(item.box);
auto clamp_min = (!computed_min_size.is_auto() && (resolve_percentage_min_max_sizes || !computed_min_size.contains_percentage())) ? specified_cross_min_size(item.box) : 0;
auto clamp_max = (!computed_max_size.is_none() && (resolve_percentage_min_max_sizes || !computed_max_size.contains_percentage())) ? specified_cross_max_size(item.box) : NumericLimits<float>::max();
auto clamp_max = (!computed_max_size.is_none() && (resolve_percentage_min_max_sizes || !computed_max_size.contains_percentage())) ? specified_cross_max_size(item.box) : CSSPixels::max();
auto clamped_inner_size = css_clamp(size, clamp_min, clamp_max);
@ -1992,7 +1992,7 @@ CSSPixels FlexFormattingContext::calculate_width_to_use_when_determining_intrins
auto const& computed_min_width = box.computed_values().min_width();
auto const& computed_max_width = box.computed_values().max_width();
auto clamp_min = (!computed_min_width.is_auto() && (!computed_min_width.contains_percentage())) ? specified_cross_min_size(box) : 0;
auto clamp_max = (!computed_max_width.is_none() && (!computed_max_width.contains_percentage())) ? specified_cross_max_size(box) : NumericLimits<float>::max();
auto clamp_max = (!computed_max_width.is_none() && (!computed_max_width.contains_percentage())) ? specified_cross_max_size(box) : CSSPixels::max();
CSSPixels width;
if (should_treat_width_as_auto(box, m_available_space_for_items->space) || computed_width.is_fit_content())
@ -2123,8 +2123,8 @@ void FlexFormattingContext::resolve_cross_axis_auto_margins()
if (outer_cross_size < line.cross_size) {
CSSPixels remainder = line.cross_size - outer_cross_size;
if (item.margins.cross_before_is_auto && item.margins.cross_after_is_auto) {
item.margins.cross_before = remainder / 2.0;
item.margins.cross_after = remainder / 2.0;
item.margins.cross_before = remainder / 2;
item.margins.cross_after = remainder / 2;
} else if (item.margins.cross_before_is_auto) {
item.margins.cross_before = remainder;
} else {
@ -2203,13 +2203,13 @@ CSSPixelPoint FlexFormattingContext::calculate_static_position(Box const& box) c
cross_offset = half_line_size - inner_cross_size(box) - cross_margin_after - cross_border_after - cross_padding_after;
break;
case CSS::AlignItems::Center:
cross_offset = -((inner_cross_size(box) + cross_border_before + cross_border_after) / 2.0);
cross_offset = -((inner_cross_size(box) + cross_border_before + cross_border_after) / 2);
break;
default:
break;
}
cross_offset += inner_cross_size(flex_container()) / 2.0;
cross_offset += inner_cross_size(flex_container()) / 2;
// The main-axis edges of the static-position rectangle are where the margin edges of the child
// would be positioned if it were the sole flex item in the flex container,
@ -2236,7 +2236,7 @@ CSSPixelPoint FlexFormattingContext::calculate_static_position(Box const& box) c
case CSS::JustifyContent::SpaceAround:
case CSS::JustifyContent::SpaceEvenly:
pack_from_end = false;
main_offset = (inner_main_size(flex_container()) - inner_main_size(box) - main_border_before - main_border_after) / 2.0;
main_offset = (inner_main_size(flex_container()) - inner_main_size(box) - main_border_before - main_border_after) / 2;
break;
}

View file

@ -405,7 +405,7 @@ CSSPixels FormattingContext::tentative_width_for_replaced_element(Box const& box
// (used height) * (intrinsic ratio)
if ((computed_height.is_auto() && computed_width.is_auto() && !box.has_natural_width() && box.has_natural_height() && box.has_preferred_aspect_ratio())
|| (computed_width.is_auto() && !computed_height.is_auto() && box.has_preferred_aspect_ratio())) {
return compute_height_for_replaced_element(box, available_space) * static_cast<double>(box.preferred_aspect_ratio().value());
return compute_height_for_replaced_element(box, available_space).scaled(static_cast<double>(box.preferred_aspect_ratio().value()));
}
// If 'height' and 'width' both have computed values of 'auto' and the element has an intrinsic ratio but no intrinsic height or width,
@ -500,7 +500,7 @@ CSSPixels FormattingContext::tentative_height_for_replaced_element(Box const& bo
//
// (used width) / (intrinsic ratio)
if (computed_height.is_auto() && box.has_preferred_aspect_ratio())
return m_state.get(box).content_width() / static_cast<double>(box.preferred_aspect_ratio().value());
return CSSPixels(m_state.get(box).content_width() / static_cast<double>(box.preferred_aspect_ratio().value()));
// Otherwise, if 'height' has a computed value of 'auto', and the element has an intrinsic height, then that intrinsic height is the used value of 'height'.
if (computed_height.is_auto() && box.has_natural_height())
@ -1051,8 +1051,8 @@ CSSPixelPoint FormattingContext::calculate_static_position(Box const& box) const
// The purpose of this function is to calculate the approximate position that `box`
// would have had if it were position:static.
CSSPixels x = 0.0f;
CSSPixels y = 0.0f;
CSSPixels x = 0;
CSSPixels y = 0;
VERIFY(box.parent());
if (box.parent()->children_are_inline()) {
@ -1403,7 +1403,7 @@ CSSPixels FormattingContext::calculate_min_content_height(Layout::Box const& box
CSSPixels FormattingContext::calculate_max_content_height(Layout::Box const& box, CSSPixels width) const
{
if (box.has_preferred_aspect_ratio())
return width / static_cast<double>(*box.preferred_aspect_ratio());
return CSSPixels(width / static_cast<double>(*box.preferred_aspect_ratio()));
if (box.has_natural_height())
return *box.natural_height();
@ -1711,10 +1711,10 @@ CSSPixels FormattingContext::box_baseline(Box const& box) const
return box_state.content_height() + box_state.margin_box_top();
case CSS::VerticalAlign::TextTop:
// TextTop: Align the top of the box with the top of the parent's content area (see 10.6.1).
return box.computed_values().font_size();
return CSSPixels(box.computed_values().font_size());
case CSS::VerticalAlign::TextBottom:
// TextTop: Align the bottom of the box with the bottom of the parent's content area (see 10.6.1).
return box_state.content_height() - (box.containing_block()->font().pixel_metrics().descent * 2);
return box_state.content_height() - CSSPixels(box.containing_block()->font().pixel_metrics().descent * 2);
default:
break;
}

View file

@ -1245,7 +1245,7 @@ void GridFormattingContext::expand_flexible_tracks(AvailableSpace const& availab
for (auto& track : tracks) {
if (track.max_track_sizing_function.is_flexible_length()) {
if (track.max_track_sizing_function.flex_factor() > 1) {
result = max(result, track.base_size / track.max_track_sizing_function.flex_factor());
result = max(result, CSSPixels(track.base_size / track.max_track_sizing_function.flex_factor()));
} else {
result = max(result, track.base_size);
}
@ -1273,8 +1273,8 @@ void GridFormattingContext::expand_flexible_tracks(AvailableSpace const& availab
// For each flexible track, if the product of the used flex fraction and the tracks flex factor is greater than
// the tracks base size, set its base size to that product.
for (auto& track : tracks_and_gaps) {
if (track.max_track_sizing_function.flex_factor() * flex_fraction > track.base_size) {
track.base_size = track.max_track_sizing_function.flex_factor() * flex_fraction;
if (flex_fraction.scaled(track.max_track_sizing_function.flex_factor()) > track.base_size) {
track.base_size = flex_fraction.scaled(track.max_track_sizing_function.flex_factor());
}
}
}

View file

@ -34,11 +34,11 @@ void ImageBox::prepare_for_replaced_layout()
CSSPixels alt_text_width = 0;
if (!m_cached_alt_text_width.has_value())
m_cached_alt_text_width = font.width(alt);
m_cached_alt_text_width = CSSPixels(font.width(alt));
alt_text_width = m_cached_alt_text_width.value();
set_natural_width(alt_text_width + 16);
set_natural_height(font.pixel_size() + 16);
set_natural_height(CSSPixels(font.pixel_size()) + 16);
}
if (!has_natural_width() && !has_natural_height()) {

View file

@ -180,7 +180,7 @@ Optional<InlineLevelIterator::Item> InlineLevelIterator::next_without_lookahead(
m_text_node_context->is_last_chunk = true;
auto& chunk = chunk_opt.value();
CSSPixels chunk_width = text_node.font().width(chunk.view) + text_node.font().glyph_spacing();
CSSPixels chunk_width = CSSPixels(text_node.font().width(chunk.view) + text_node.font().glyph_spacing());
if (m_text_node_context->do_respect_linebreaks && chunk.has_breaking_newline) {
return Item {

View file

@ -386,7 +386,7 @@ void LayoutState::UsedValues::set_node(NodeWithStyleAndBoxModelMetrics& node, Us
if (size.is_percentage()) {
if (containing_block_has_definite_size) {
auto containing_block_size = width ? containing_block_used_values->content_width() : containing_block_used_values->content_height();
resolved_definite_size = adjust_for_box_sizing(containing_block_size * static_cast<double>(size.percentage().as_fraction()), size, width);
resolved_definite_size = adjust_for_box_sizing(containing_block_size.scaled(size.percentage().as_fraction()), size, width);
return true;
}
return false;

View file

@ -25,7 +25,7 @@ void LineBox::add_fragment(Node const& layout_node, int start, int length, CSSPi
m_fragments.last().set_width(m_fragments.last().width() + content_width);
} else {
CSSPixels x_offset = leading_margin + leading_size + m_width;
CSSPixels y_offset = 0.0f;
CSSPixels y_offset = 0;
m_fragments.append(LineBoxFragment { layout_node, start, length, CSSPixelPoint(x_offset, y_offset), CSSPixelSize(content_width, content_height), border_box_top, border_box_bottom });
}
m_width += leading_margin + leading_size + content_width + trailing_size + trailing_margin;

View file

@ -51,7 +51,7 @@ int LineBoxFragment::text_index_at(CSSPixels x) const
Utf8View view(text());
CSSPixels relative_x = x - absolute_x();
float glyph_spacing = font.glyph_spacing();
CSSPixels glyph_spacing = CSSPixels(font.glyph_spacing());
if (relative_x < 0)
return 0;
@ -59,9 +59,9 @@ int LineBoxFragment::text_index_at(CSSPixels x) const
CSSPixels width_so_far = 0;
for (auto it = view.begin(); it != view.end(); ++it) {
auto previous_it = it;
CSSPixels glyph_width = font.glyph_or_emoji_width(it);
CSSPixels glyph_width = CSSPixels(font.glyph_or_emoji_width(it));
if ((width_so_far + (glyph_width + glyph_spacing) / 2) > relative_x)
if ((width_so_far + glyph_width + glyph_spacing / 2) > relative_x)
return m_start + view.byte_offset_of(previous_it);
width_so_far += glyph_width + glyph_spacing;
@ -105,8 +105,8 @@ CSSPixelRect LineBoxFragment::selection_rect(Gfx::Font const& font) const
auto selection_start_in_this_fragment = max(0, range->start_offset() - m_start);
auto selection_end_in_this_fragment = min(m_length, range->end_offset() - m_start);
auto pixel_distance_to_first_selected_character = font.width(text.substring_view(0, selection_start_in_this_fragment));
auto pixel_width_of_selection = font.width(text.substring_view(selection_start_in_this_fragment, selection_end_in_this_fragment - selection_start_in_this_fragment)) + 1;
auto pixel_distance_to_first_selected_character = CSSPixels(font.width(text.substring_view(0, selection_start_in_this_fragment)));
auto pixel_width_of_selection = CSSPixels(font.width(text.substring_view(selection_start_in_this_fragment, selection_end_in_this_fragment - selection_start_in_this_fragment))) + 1;
auto rect = absolute_rect();
rect.set_x(rect.x() + pixel_distance_to_first_selected_character);
@ -121,8 +121,8 @@ CSSPixelRect LineBoxFragment::selection_rect(Gfx::Font const& font) const
auto selection_start_in_this_fragment = max(0, range->start_offset() - m_start);
auto selection_end_in_this_fragment = m_length;
auto pixel_distance_to_first_selected_character = font.width(text.substring_view(0, selection_start_in_this_fragment));
auto pixel_width_of_selection = font.width(text.substring_view(selection_start_in_this_fragment, selection_end_in_this_fragment - selection_start_in_this_fragment)) + 1;
auto pixel_distance_to_first_selected_character = CSSPixels(font.width(text.substring_view(0, selection_start_in_this_fragment)));
auto pixel_width_of_selection = CSSPixels(font.width(text.substring_view(selection_start_in_this_fragment, selection_end_in_this_fragment - selection_start_in_this_fragment))) + 1;
auto rect = absolute_rect();
rect.set_x(rect.x() + pixel_distance_to_first_selected_character);
@ -137,8 +137,8 @@ CSSPixelRect LineBoxFragment::selection_rect(Gfx::Font const& font) const
auto selection_start_in_this_fragment = 0;
auto selection_end_in_this_fragment = min(range->end_offset() - m_start, m_length);
auto pixel_distance_to_first_selected_character = font.width(text.substring_view(0, selection_start_in_this_fragment));
auto pixel_width_of_selection = font.width(text.substring_view(selection_start_in_this_fragment, selection_end_in_this_fragment - selection_start_in_this_fragment)) + 1;
auto pixel_distance_to_first_selected_character = CSSPixels(font.width(text.substring_view(0, selection_start_in_this_fragment)));
auto pixel_width_of_selection = CSSPixels(font.width(text.substring_view(selection_start_in_this_fragment, selection_end_in_this_fragment - selection_start_in_this_fragment))) + 1;
auto rect = absolute_rect();
rect.set_x(rect.x() + pixel_distance_to_first_selected_character);

View file

@ -195,7 +195,7 @@ void LineBuilder::update_last_line()
auto& font = m_context.containing_block().font();
auto const line_height = m_context.containing_block().line_height();
auto const font_metrics = font.pixel_metrics();
auto const typographic_height = font_metrics.ascent + font_metrics.descent;
auto const typographic_height = CSSPixels(font_metrics.ascent + font_metrics.descent);
auto const leading = line_height - typographic_height;
auto const half_leading = leading / 2;
return CSSPixels(font_metrics.ascent) + half_leading;
@ -230,7 +230,7 @@ void LineBuilder::update_last_line()
if (length_percentage->is_length())
fragment_baseline += length_percentage->length().to_px(fragment.layout_node());
else if (length_percentage->is_percentage())
fragment_baseline += length_percentage->percentage().as_fraction() * line_height.to_double();
fragment_baseline += line_height.scaled(length_percentage->percentage().as_fraction());
}
line_box_baseline = max(line_box_baseline, fragment_baseline);
@ -284,7 +284,7 @@ void LineBuilder::update_last_line()
auto vertical_align_amount = length_percentage->length().to_px(fragment.layout_node());
new_fragment_y = y_value_for_alignment(CSS::VerticalAlign::Baseline) - vertical_align_amount;
} else if (length_percentage->is_percentage()) {
auto vertical_align_amount = length_percentage->percentage().as_fraction() * m_context.containing_block().line_height().to_double();
auto vertical_align_amount = m_context.containing_block().line_height().scaled(length_percentage->percentage().as_fraction());
new_fragment_y = y_value_for_alignment(CSS::VerticalAlign::Baseline) - vertical_align_amount;
}
}
@ -302,17 +302,17 @@ void LineBuilder::update_last_line()
bottom_of_inline_box = (fragment.offset().y() + fragment_box_state.content_height() + fragment_box_state.margin_box_bottom());
} else {
auto font_metrics = fragment.layout_node().font().pixel_metrics();
auto typographic_height = font_metrics.ascent + font_metrics.descent;
auto typographic_height = CSSPixels(font_metrics.ascent + font_metrics.descent);
auto leading = fragment.layout_node().line_height() - typographic_height;
auto half_leading = leading / 2;
top_of_inline_box = (fragment.offset().y() + fragment.baseline() - font_metrics.ascent - half_leading);
bottom_of_inline_box = (fragment.offset().y() + fragment.baseline() + font_metrics.descent + half_leading);
top_of_inline_box = (fragment.offset().y() + fragment.baseline() - CSSPixels(font_metrics.ascent) - half_leading);
bottom_of_inline_box = (fragment.offset().y() + fragment.baseline() + CSSPixels(font_metrics.descent) + half_leading);
}
if (auto const* length_percentage = fragment.layout_node().computed_values().vertical_align().get_pointer<CSS::LengthPercentage>()) {
if (length_percentage->is_length())
bottom_of_inline_box += length_percentage->length().to_px(fragment.layout_node());
else if (length_percentage->is_percentage())
bottom_of_inline_box += length_percentage->percentage().as_fraction() * m_context.containing_block().line_height().to_double();
bottom_of_inline_box += m_context.containing_block().line_height().scaled(length_percentage->percentage().as_fraction());
}
}

View file

@ -300,11 +300,11 @@ static CSSPixels snap_a_length_as_a_border_width(double device_pixels_per_css_pi
// 3. If len is greater than zero, but less than 1 device pixel, round len up to 1 device pixel.
if (device_pixels > 0 && device_pixels < 1)
return 1 / device_pixels_per_css_pixel;
return CSSPixels(1 / device_pixels_per_css_pixel);
// 4. If len is greater than 1 device pixel, round it down to the nearest integer number of device pixels.
if (device_pixels > 1)
return floor(device_pixels) / device_pixels_per_css_pixel;
return CSSPixels(floor(device_pixels) / device_pixels_per_css_pixel);
return length;
}
@ -684,11 +684,11 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style)
// https://www.w3.org/TR/css-backgrounds-3/#valdef-line-width-thin
switch (value->to_identifier()) {
case CSS::ValueID::Thin:
return 1.0;
return 1;
case CSS::ValueID::Medium:
return 3.0;
return 3;
case CSS::ValueID::Thick:
return 5.0;
return 5;
default:
VERIFY_NOT_REACHED();
}
@ -742,7 +742,7 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style)
// FIXME: Converting to pixels isn't really correct - values should be in "user units"
// https://svgwg.org/svg2-draft/coords.html#TermUserUnits
if (stroke_width->is_number())
computed_values.set_stroke_width(CSS::Length::make_px(stroke_width->as_number().number()));
computed_values.set_stroke_width(CSS::Length::make_px(CSSPixels(stroke_width->as_number().number())));
else if (stroke_width->is_length())
computed_values.set_stroke_width(stroke_width->as_length().length());
else if (stroke_width->is_percentage())

View file

@ -86,13 +86,13 @@ static ViewBoxTransform scale_and_align_viewbox_content(SVG::PreserveAspectRatio
case SVG::PreserveAspectRatio::Align::xMidYMid:
case SVG::PreserveAspectRatio::Align::xMidYMax:
// Align the midpoint X value of the element's viewBox with the midpoint X value of the SVG viewport.
viewbox_transform.offset.translate_by((svg_box_state.content_width() - (view_box.width * viewbox_transform.scale_factor)) / 2, 0);
viewbox_transform.offset.translate_by((svg_box_state.content_width() - CSSPixels(view_box.width * viewbox_transform.scale_factor)) / 2, 0);
break;
case SVG::PreserveAspectRatio::Align::xMaxYMin:
case SVG::PreserveAspectRatio::Align::xMaxYMid:
case SVG::PreserveAspectRatio::Align::xMaxYMax:
// Align the <min-x>+<width> of the element's viewBox with the maximum X value of the SVG viewport.
viewbox_transform.offset.translate_by((svg_box_state.content_width() - (view_box.width * viewbox_transform.scale_factor)), 0);
viewbox_transform.offset.translate_by((svg_box_state.content_width() - CSSPixels(view_box.width * viewbox_transform.scale_factor)), 0);
break;
default:
VERIFY_NOT_REACHED();
@ -117,13 +117,13 @@ static ViewBoxTransform scale_and_align_viewbox_content(SVG::PreserveAspectRatio
case SVG::PreserveAspectRatio::Align::xMidYMid:
case SVG::PreserveAspectRatio::Align::xMaxYMid:
// Align the midpoint Y value of the element's viewBox with the midpoint Y value of the SVG viewport.
viewbox_transform.offset.translate_by(0, (svg_box_state.content_height() - (view_box.height * viewbox_transform.scale_factor)) / 2);
viewbox_transform.offset.translate_by(0, (svg_box_state.content_height() - CSSPixels(view_box.height * viewbox_transform.scale_factor)) / 2);
break;
case SVG::PreserveAspectRatio::Align::xMinYMax:
case SVG::PreserveAspectRatio::Align::xMidYMax:
case SVG::PreserveAspectRatio::Align::xMaxYMax:
// Align the <min-y>+<height> of the element's viewBox with the maximum Y value of the SVG viewport.
viewbox_transform.offset.translate_by(0, (svg_box_state.content_height() - (view_box.height * viewbox_transform.scale_factor)));
viewbox_transform.offset.translate_by(0, (svg_box_state.content_height() - CSSPixels(view_box.height * viewbox_transform.scale_factor)));
break;
default:
VERIFY_NOT_REACHED();
@ -197,7 +197,7 @@ void SVGFormattingContext::run(Box const& box, LayoutMode layout_mode, Available
// Stroke increases the path's size by stroke_width/2 per side.
auto path_bounding_box = path_transform.map(path.bounding_box()).to_type<CSSPixels>();
CSSPixels stroke_width = static_cast<double>(geometry_box.dom_node().visible_stroke_width()) * viewbox_scale;
CSSPixels stroke_width = CSSPixels(static_cast<double>(geometry_box.dom_node().visible_stroke_width()) * viewbox_scale);
path_bounding_box.inflate(stroke_width, stroke_width);
geometry_box_state.set_content_offset(path_bounding_box.top_left());
geometry_box_state.set_content_width(path_bounding_box.width());

View file

@ -265,11 +265,11 @@ void TableFormattingContext::compute_intrinsic_percentage(size_t max_cell_span)
auto cell_start_rc_index = cell_index<RowOrColumn>(cell);
auto cell_end_rc_index = cell_start_rc_index + cell_span_value;
// 1. Start with the percentage contribution of the cell.
CSSPixels cell_contribution = cell_percentage_contribution<RowOrColumn>(cell);
CSSPixels cell_contribution = CSSPixels(cell_percentage_contribution<RowOrColumn>(cell));
// 2. Subtract the intrinsic percentage width of the column based on cells of span up to N-1 of all columns
// that the cell spans. If this gives a negative result, change it to 0%.
for (auto rc_index = cell_start_rc_index; rc_index < cell_end_rc_index; rc_index++) {
cell_contribution -= rows_or_columns[rc_index].intrinsic_percentage;
cell_contribution -= CSSPixels(rows_or_columns[rc_index].intrinsic_percentage);
cell_contribution = max(cell_contribution, 0);
}
// Compute the sum of the non-spanning max-content sizes of all rows / columns spanned by the cell that have an intrinsic percentage
@ -297,7 +297,7 @@ void TableFormattingContext::compute_intrinsic_percentage(size_t max_cell_span)
// columns spanned by the cell that have an intrinsic percentage width of the column based on cells of span up to N-1 equal to 0%.
CSSPixels ajusted_cell_contribution;
if (width_sum_of_columns_with_zero_intrinsic_percentage != 0) {
ajusted_cell_contribution = cell_contribution * rows_or_columns[rc_index].max_size / static_cast<double>(width_sum_of_columns_with_zero_intrinsic_percentage);
ajusted_cell_contribution = cell_contribution.scaled(rows_or_columns[rc_index].max_size / static_cast<double>(width_sum_of_columns_with_zero_intrinsic_percentage));
} else {
// However, if this ratio is undefined because the denominator is zero, instead use the 1 divided by the number of columns
// spanned by the cell that have an intrinsic percentage width of the column based on cells of span up to N-1 equal to zero.
@ -380,12 +380,12 @@ void TableFormattingContext::compute_table_measures()
auto clamped_diff_to_baseline_min = min(
max(cell_min_size<RowOrColumn>(cell) - baseline_min_content_size - baseline_border_spacing, 0),
baseline_max_content_size - baseline_min_content_size);
cell_min_contribution += normalized_max_min_diff * clamped_diff_to_baseline_min;
cell_min_contribution += CSSPixels(normalized_max_min_diff * clamped_diff_to_baseline_min);
// the product of:
// - the ratio of the max-content size based on cells of span up to N-1 of the column to the baseline max-content size
// - the outer min-content size of the cell minus the baseline max-content size and baseline border spacing, or 0 if this is negative
if (baseline_max_content_size != 0) {
cell_min_contribution += (rows_or_columns[rc_index].max_size / static_cast<double>(baseline_max_content_size))
cell_min_contribution += CSSPixels(rows_or_columns[rc_index].max_size / static_cast<double>(baseline_max_content_size))
* max(CSSPixels(0), cell_min_size<RowOrColumn>(cell) - baseline_max_content_size - baseline_border_spacing);
}
@ -396,7 +396,7 @@ void TableFormattingContext::compute_table_measures()
// - the ratio of the max-content size based on cells of span up to N-1 of the column to the baseline max-content size
// - the outer max-content size of the cell minus the baseline max-content size and the baseline border spacing, or 0 if this is negative
if (baseline_max_content_size != 0) {
cell_max_contribution += (rows_or_columns[rc_index].max_size / static_cast<double>(baseline_max_content_size))
cell_max_contribution += CSSPixels(rows_or_columns[rc_index].max_size / static_cast<double>(baseline_max_content_size))
* max(CSSPixels(0), cell_max_size<RowOrColumn>(cell) - baseline_max_content_size - baseline_border_spacing);
}
cell_min_contributions_by_rc_index[rc_index].append(cell_min_contribution);
@ -461,7 +461,7 @@ void TableFormattingContext::compute_table_width()
// The row/column-grid width minimum (GRIDMIN) width is the sum of the min-content width
// of all the columns plus cell spacing or borders.
CSSPixels grid_min = 0.0f;
CSSPixels grid_min = 0;
for (auto& column : m_columns) {
grid_min += column.min_size;
}
@ -469,7 +469,7 @@ void TableFormattingContext::compute_table_width()
// The row/column-grid width maximum (GRIDMAX) width is the sum of the max-content width
// of all the columns plus cell spacing or borders.
CSSPixels grid_max = 0.0f;
CSSPixels grid_max = 0;
for (auto& column : m_columns) {
grid_max += column.max_size;
}
@ -496,7 +496,7 @@ void TableFormattingContext::compute_table_width()
for (auto& cell : m_cells) {
auto const& cell_width = cell.box->computed_values().width();
if (cell_width.is_percentage()) {
adjusted_used_width = ceil(100 / cell_width.percentage().value() * cell.outer_max_width.to_double());
adjusted_used_width = CSSPixels(ceil(100 / cell_width.percentage().value() * cell.outer_max_width.to_double()));
if (width_of_table_containing_block.is_definite())
used_width = min(max(used_width, adjusted_used_width), width_of_table_containing_block.to_px_or_zero());
else
@ -555,7 +555,7 @@ void TableFormattingContext::assign_columns_width_linear_combination(Vector<CSSP
auto candidate_weight = (available_width - columns_total_used_width) / static_cast<double>(columns_total_candidate_width - columns_total_used_width);
for (size_t i = 0; i < m_columns.size(); ++i) {
auto& column = m_columns[i];
column.used_width = candidate_weight * candidate_widths[i] + (1 - candidate_weight) * column.used_width;
column.used_width = CSSPixels(candidate_weight * candidate_widths[i] + (1 - candidate_weight) * column.used_width);
}
}
@ -576,7 +576,7 @@ bool TableFormattingContext::distribute_excess_width_proportionally_to_base_widt
VERIFY(total_base_width > 0);
for (auto& column : m_columns) {
if (column_filter(column)) {
column.used_width += excess_width * base_width_getter(column) / static_cast<double>(total_base_width);
column.used_width += CSSPixels(excess_width * base_width_getter(column) / static_cast<double>(total_base_width));
}
}
return true;
@ -618,7 +618,7 @@ bool TableFormattingContext::distribute_excess_width_by_intrinsic_percentage(CSS
}
for (auto& column : m_columns) {
if (column_filter(column)) {
column.used_width += excess_width * column.intrinsic_percentage / total_percentage_width;
column.used_width += CSSPixels(excess_width * column.intrinsic_percentage / total_percentage_width);
}
}
return true;
@ -660,7 +660,7 @@ void TableFormattingContext::distribute_width_to_columns()
for (size_t i = 0; i < m_columns.size(); ++i) {
auto& column = m_columns[i];
if (column.has_intrinsic_percentage) {
candidate_widths[i] = max(column.min_size, column.intrinsic_percentage / 100 * available_width);
candidate_widths[i] = max(column.min_size, CSSPixels(column.intrinsic_percentage / 100 * available_width));
}
}
@ -990,7 +990,7 @@ void TableFormattingContext::distribute_height_to_rows()
for (auto& row : m_rows) {
auto weight = row.reference_height / static_cast<double>(sum_reference_height);
auto final_height = m_table_height * weight;
row.final_height = final_height;
row.final_height = CSSPixels(final_height);
}
} else if (rows_with_auto_height.size() > 0) {
// Else, if the table owns any “auto-height” row (a row whose size is only determined by its content size and
@ -1029,7 +1029,7 @@ void TableFormattingContext::position_row_boxes()
for (size_t y = 0; y < m_rows.size(); y++) {
auto& row = m_rows[y];
auto& row_state = m_state.get_mutable(row.box);
CSSPixels row_width = 0.0f;
CSSPixels row_width = 0;
for (auto& column : m_columns) {
row_width += column.used_width;
}
@ -1044,8 +1044,8 @@ void TableFormattingContext::position_row_boxes()
CSSPixels row_group_top_offset = table_state.border_top + table_state.padding_top;
CSSPixels row_group_left_offset = table_state.border_left + table_state.padding_left;
TableGrid::for_each_child_box_matching(table_box(), TableGrid::is_table_row_group, [&](auto& row_group_box) {
CSSPixels row_group_height = 0.0f;
CSSPixels row_group_width = 0.0f;
CSSPixels row_group_height = 0;
CSSPixels row_group_width = 0;
auto& row_group_box_state = m_state.get_mutable(row_group_box);
row_group_box_state.set_content_x(row_group_left_offset);

View file

@ -38,10 +38,10 @@ HTML::HTMLVideoElement const& VideoBox::dom_node() const
void VideoBox::prepare_for_replaced_layout()
{
auto width = static_cast<float>(dom_node().video_width());
set_natural_width(width);
set_natural_width(CSSPixels(width));
auto height = static_cast<float>(dom_node().video_height());
set_natural_height(height);
set_natural_height(CSSPixels(height));
if (width != 0 && height != 0)
set_natural_aspect_ratio(width / height);