mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 23:50:19 +00:00
LibWeb: Adjust flex item main size through aspect ratio if needed
If there are min or max size constraints in the cross axis for a flex item that has a desired aspect ratio, we may need to adjust the main size *after* applying the cross size constraints. All the steps to achieving this aren't mentioned in the spec, but it seems that all other browsers behave this way, so we should too.
This commit is contained in:
parent
f248f566b8
commit
0c26717ba3
Notes:
sideshowbarker
2024-07-17 10:05:47 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/0c26717ba3 Pull-request: https://github.com/SerenityOS/serenity/pull/18752
4 changed files with 66 additions and 9 deletions
|
@ -0,0 +1,6 @@
|
|||
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
|
||||
BlockContainer <html> at (1,1) content-size 798x70 [BFC] children: not-inline
|
||||
Box <body> at (10,10) content-size 780x52 flex-container(row) [FFC] children: not-inline
|
||||
ImageBox <img> at (11,11) content-size 66.666671x50 flex-item children: not-inline
|
||||
BlockContainer <(anonymous)> at (10,10) content-size 0x0 [BFC] children: inline
|
||||
TextNode <#text>
|
|
@ -0,0 +1,10 @@
|
|||
<!doctype html><style>
|
||||
* { border: 1px solid black; }
|
||||
body {
|
||||
background: #444;
|
||||
display: flex;
|
||||
}
|
||||
img {
|
||||
max-height: 50px;
|
||||
}
|
||||
</style><img src="data:image/gif;base64,R0lGODdhgALgAYAAAP///////ywAAAAAgALgAQAC/oSPqcvtD6OctNqLs968+w+G4kiW5omm6sq27gvH8kzX9o3n+s73/g8MCofEovGITCqXzKbzCY1Kp9Sq9YrNarfcrvcLDovH5LL5jE6r1+y2+w2Py+f0uv2Oz+v3/L7/DxgoOEhYaHiImKi4yNjo+AgZKTlJWWl5iZmpucnZ6fkJGio6SlpqeoqaqrrK2ur6ChsrO0tba3uLm6u7y9vr+wscLDxMXGx8jJysvMzc7PwMHS09TV1tfY2drb3N3e39DR4uPk5ebn6Onq6+zt7u/g4fLz9PX29/j5+vv8/f7/8PMKDAgQQLGjyIMKHChQwbOnwIMaLEiRQrWryIMaPG/o0cO3r8CDKkyJEkS5o8iTKlypUsW7p8CTOmzJk0a9q8iTOnzp08e/r8CTSo0KFEixo9ijSp0qVMmzp9CjWq1KlUq1q9ijWr1q1cu3r9Cjas2LFky5o9izat2rVs27p9Czeu3Ll069q9izev3r18+/r9Cziw4MGECxs+jDix4sWMGzt+DDmy5MmUK1u+jDmz5s2cO3v+DDq06NGkS5s+jTq16tWsW7t+DTu27Nm0a9u+jTu37t28e/v+DTy48OHEixs/jjy58uXMmzt/Dj269OnUq1u/jj279u3cu3v/Dj68+PHky5s/jz69+vXs27t/Dz++/Pn069u/jz+//v38/vv7/w9ggAIOSGCBBh6IYIIKLshggw4+CGGEEk5IYYUWXohhhhpuyGGHHn4IYogijkhiiSaeiGKKKq7IYosuvghjjDLOSGONNt6IY4467shjjz7+CGSQQg5JZJFGHolkkkouyWSTTj4JZZRSTklllVZeiWWWWm7JZZdefglmmGKOSWaZZp6JZppqrslmm26+CWeccs5JZ5123olnnnruyWeffv4JaKCCDkpooYYeimiiii7KaKOOPgpppJJOSmmlll6Kaaaabsppp55+Cmqooo5Kaqmmnopqqqquymqrrr4Ka6yyzkprrbbeimuuuu7Ka6++/gpssMIOS2yxxh6LYWyyyi7LbLPOPgtttNJOS2211l6Lbbbabsttt95+C2644o5Lbrnmnotuuuquy2677r4Lb7zyzktvvfbei2+++u7Lb7/+/gtwwAIPTHDBBh+McMIKL8xwww4/DHHEEk/MUAEAOw==" />
|
|
@ -573,6 +573,30 @@ CSS::FlexBasisData FlexFormattingContext::used_flex_basis_for_item(FlexItem cons
|
|||
return flex_basis;
|
||||
}
|
||||
|
||||
CSSPixels FlexFormattingContext::calculate_main_size_from_cross_size_and_aspect_ratio(CSSPixels cross_size, float aspect_ratio) const
|
||||
{
|
||||
if (is_row_layout())
|
||||
return cross_size * aspect_ratio;
|
||||
return cross_size / aspect_ratio;
|
||||
}
|
||||
|
||||
// This function takes a size in the main axis and adjusts it according to the aspect ratio of the box
|
||||
// if the min/max constraints in the cross axis forces us to come up with a new main axis size.
|
||||
CSSPixels FlexFormattingContext::adjust_main_size_through_aspect_ratio_for_cross_size_min_max_constraints(Box const& box, CSSPixels main_size, CSS::Size const& min_cross_size, CSS::Size const& max_cross_size) const
|
||||
{
|
||||
if (!max_cross_size.is_none()) {
|
||||
auto max_cross_size_px = max_cross_size.to_px(box, is_row_layout() ? m_flex_container_state.content_width() : m_flex_container_state.content_height());
|
||||
main_size = min(main_size, calculate_main_size_from_cross_size_and_aspect_ratio(max_cross_size_px, box.intrinsic_aspect_ratio().value()));
|
||||
}
|
||||
|
||||
if (!min_cross_size.is_auto()) {
|
||||
auto min_cross_size_px = min_cross_size.to_px(box, is_row_layout() ? m_flex_container_state.content_width() : m_flex_container_state.content_height());
|
||||
main_size = max(main_size, calculate_main_size_from_cross_size_and_aspect_ratio(min_cross_size_px, box.intrinsic_aspect_ratio().value()));
|
||||
}
|
||||
|
||||
return main_size;
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/css-flexbox-1/#algo-main-item
|
||||
void FlexFormattingContext::determine_flex_base_size_and_hypothetical_main_size(FlexItem& item)
|
||||
{
|
||||
|
@ -612,9 +636,11 @@ void FlexFormattingContext::determine_flex_base_size_and_hypothetical_main_size(
|
|||
&& item.used_flex_basis.type == CSS::FlexBasis::Content
|
||||
&& has_definite_cross_size(item.box)) {
|
||||
// flex_base_size is calculated from definite cross size and intrinsic aspect ratio
|
||||
if (is_row_layout())
|
||||
return inner_cross_size(item.box) * item.box->intrinsic_aspect_ratio().value();
|
||||
return inner_cross_size(item.box) / item.box->intrinsic_aspect_ratio().value();
|
||||
return adjust_main_size_through_aspect_ratio_for_cross_size_min_max_constraints(
|
||||
item.box,
|
||||
calculate_main_size_from_cross_size_and_aspect_ratio(inner_cross_size(item.box), item.box->intrinsic_aspect_ratio().value()),
|
||||
computed_cross_min_size(item.box),
|
||||
computed_cross_max_size(item.box));
|
||||
}
|
||||
|
||||
// C. If the used flex basis is content or depends on its available space,
|
||||
|
@ -670,6 +696,12 @@ void FlexFormattingContext::determine_flex_base_size_and_hypothetical_main_size(
|
|||
return calculate_fit_content_main_size(item);
|
||||
}();
|
||||
|
||||
// AD-HOC: This is not mentioned in the spec, but if the item has an aspect ratio,
|
||||
// we may need to adjust the main size in response to cross size min/max constraints.
|
||||
if (item.box->has_intrinsic_aspect_ratio()) {
|
||||
item.flex_base_size = adjust_main_size_through_aspect_ratio_for_cross_size_min_max_constraints(child_box, item.flex_base_size, computed_cross_min_size(child_box), computed_cross_max_size(child_box));
|
||||
}
|
||||
|
||||
// The hypothetical main size is the item’s 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();
|
||||
|
@ -713,8 +745,13 @@ Optional<CSSPixels> FlexFormattingContext::specified_size_suggestion(FlexItem co
|
|||
// https://drafts.csswg.org/css-flexbox-1/#content-size-suggestion
|
||||
CSSPixels FlexFormattingContext::content_size_suggestion(FlexItem const& item) const
|
||||
{
|
||||
// FIXME: Apply clamps
|
||||
return calculate_min_content_main_size(item);
|
||||
auto suggestion = calculate_min_content_main_size(item);
|
||||
|
||||
if (item.box->has_intrinsic_aspect_ratio()) {
|
||||
suggestion = adjust_main_size_through_aspect_ratio_for_cross_size_min_max_constraints(item.box, suggestion, computed_cross_min_size(item.box), computed_cross_max_size(item.box));
|
||||
}
|
||||
|
||||
return suggestion;
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/css-flexbox-1/#transferred-size-suggestion
|
||||
|
@ -725,10 +762,11 @@ Optional<CSSPixels> FlexFormattingContext::transferred_size_suggestion(FlexItem
|
|||
// (clamped by its minimum and maximum cross sizes if they are definite), converted through the aspect ratio.
|
||||
if (item.box->has_intrinsic_aspect_ratio() && has_definite_cross_size(item.box)) {
|
||||
auto aspect_ratio = item.box->intrinsic_aspect_ratio().value();
|
||||
// FIXME: Clamp cross size to min/max cross size before this conversion.
|
||||
if (is_row_layout())
|
||||
return inner_cross_size(item.box) * aspect_ratio;
|
||||
return inner_cross_size(item.box) / aspect_ratio;
|
||||
return adjust_main_size_through_aspect_ratio_for_cross_size_min_max_constraints(
|
||||
item.box,
|
||||
calculate_main_size_from_cross_size_and_aspect_ratio(inner_cross_size(item.box), aspect_ratio),
|
||||
computed_cross_min_size(item.box),
|
||||
computed_cross_max_size(item.box));
|
||||
}
|
||||
|
||||
// It is otherwise undefined.
|
||||
|
|
|
@ -34,6 +34,9 @@ private:
|
|||
[[nodiscard]] bool should_treat_main_size_as_auto(Box const&) const;
|
||||
[[nodiscard]] bool should_treat_cross_size_as_auto(Box const&) const;
|
||||
|
||||
[[nodiscard]] CSSPixels adjust_main_size_through_aspect_ratio_for_cross_size_min_max_constraints(Box const&, CSSPixels main_size, CSS::Size const& min_cross_size, CSS::Size const& max_cross_size) const;
|
||||
[[nodiscard]] CSSPixels calculate_main_size_from_cross_size_and_aspect_ratio(CSSPixels cross_size, float aspect_ratio) const;
|
||||
|
||||
void dump_items() const;
|
||||
|
||||
struct DirectionAgnosticMargins {
|
||||
|
|
Loading…
Reference in a new issue