LibWeb: Round lengths to 3 decimals after resolving from percentage

This is a hack to emulate the behavior of other engines that use
fixed-point math. By rounding to 3 decimals, we retain a fair amount of
detail, while still allowing overshooting 100% without breaking lines.

This is both gross and slow, but it fixes real sites. Notably, the
popular Bootstrap library uses overshooting percentages in their
12-column grid system.

This hack can be removed when CSSPixels is made a fixed-point type.
This commit is contained in:
Andreas Kling 2023-06-01 16:45:35 +02:00
parent 2452cf6b55
commit 1a6a4ca7d4
5 changed files with 45 additions and 13 deletions

View file

@ -7,7 +7,7 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline
TextNode <#text> TextNode <#text>
BlockContainer <dl> at (25,25) content-size 470x0 children: inline BlockContainer <dl> at (25,25) content-size 470x0 children: inline
TextNode <#text> TextNode <#text>
BlockContainer <dt> at (40,40) content-size 49.998597x280 floating [BFC] children: inline BlockContainer <dt> at (40,40) content-size 49.999x280 floating [BFC] children: inline
line 0 width: 28.310546, height: 10, bottom: 10, baseline: 7.998046 line 0 width: 28.310546, height: 10, bottom: 10, baseline: 7.998046
frag 0 from TextNode start: 0, length: 6, rect: [40,40 28.310546x10] frag 0 from TextNode start: 0, length: 6, rect: [40,40 28.310546x10]
"toggle" "toggle"
@ -24,21 +24,21 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline
"the way" "the way"
TextNode <#text> TextNode <#text>
TextNode <#text> TextNode <#text>
BlockContainer <li#bar> at (235,55) content-size 139.977993x90 floating [BFC] children: not-inline BlockContainer <li#bar> at (235,55) content-size 139.978x90 floating [BFC] children: not-inline
BlockContainer <(anonymous)> at (235,55) content-size 139.977993x0 children: inline BlockContainer <(anonymous)> at (235,55) content-size 139.978x0 children: inline
TextNode <#text> TextNode <#text>
BlockContainer <p> at (235,55) content-size 139.977993x10 children: inline BlockContainer <p> at (235,55) content-size 139.978x10 children: inline
line 0 width: 74.316406, height: 10, bottom: 10, baseline: 7.998046 line 0 width: 74.316406, height: 10, bottom: 10, baseline: 7.998046
frag 0 from TextNode start: 0, length: 14, rect: [235,55 74.316406x10] frag 0 from TextNode start: 0, length: 14, rect: [235,55 74.316406x10]
"the world ends" "the world ends"
TextNode <#text> TextNode <#text>
BlockContainer <(anonymous)> at (235,65) content-size 139.977993x0 children: inline BlockContainer <(anonymous)> at (235,65) content-size 139.978x0 children: inline
TextNode <#text> TextNode <#text>
InlineNode <form> InlineNode <form>
TextNode <#text> TextNode <#text>
TextNode <#text> TextNode <#text>
TextNode <#text> TextNode <#text>
BlockContainer <p> at (235,65) content-size 139.977993x18.999999 children: inline BlockContainer <p> at (235,65) content-size 139.978x18.999999 children: inline
line 0 width: 39.490234, height: 18.999999, bottom: 18.999999, baseline: 12.498046 line 0 width: 39.490234, height: 18.999999, bottom: 18.999999, baseline: 12.498046
frag 0 from TextNode start: 1, length: 5, rect: [235,65 27.490234x18.999999] frag 0 from TextNode start: 1, length: 5, rect: [235,65 27.490234x18.999999]
"bang " "bang "
@ -46,7 +46,7 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline
TextNode <#text> TextNode <#text>
RadioButton <input> at (262,65) content-size 12x12 inline-block children: not-inline RadioButton <input> at (262,65) content-size 12x12 inline-block children: not-inline
TextNode <#text> TextNode <#text>
BlockContainer <p> at (235,83.999999) content-size 139.977993x18.999999 children: inline BlockContainer <p> at (235,83.999999) content-size 139.978x18.999999 children: inline
line 0 width: 57.15625, height: 18.999999, bottom: 18.999999, baseline: 12.498046 line 0 width: 57.15625, height: 18.999999, bottom: 18.999999, baseline: 12.498046
frag 0 from TextNode start: 1, length: 8, rect: [235,83.999999 45.15625x18.999999] frag 0 from TextNode start: 1, length: 8, rect: [235,83.999999 45.15625x18.999999]
"whimper " "whimper "
@ -54,15 +54,15 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline
TextNode <#text> TextNode <#text>
RadioButton <input> at (280,83.999999) content-size 12x12 inline-block children: not-inline RadioButton <input> at (280,83.999999) content-size 12x12 inline-block children: not-inline
TextNode <#text> TextNode <#text>
BlockContainer <(anonymous)> at (235,102.999999) content-size 139.977993x0 children: inline BlockContainer <(anonymous)> at (235,102.999999) content-size 139.978x0 children: inline
TextNode <#text> TextNode <#text>
TextNode <#text> TextNode <#text>
BlockContainer <li> at (409.977993,60) content-size 50x90 floating [BFC] children: inline BlockContainer <li> at (409.978,60) content-size 50x90 floating [BFC] children: inline
line 0 width: 31.582031, height: 10, bottom: 10, baseline: 7.998046 line 0 width: 31.582031, height: 10, bottom: 10, baseline: 7.998046
frag 0 from TextNode start: 0, length: 6, rect: [409.977993,60 31.582031x10] frag 0 from TextNode start: 0, length: 6, rect: [409.978,60 31.582031x10]
"i grow" "i grow"
line 1 width: 14.033203, height: 10, bottom: 20, baseline: 7.998046 line 1 width: 14.033203, height: 10, bottom: 20, baseline: 7.998046
frag 0 from TextNode start: 7, length: 3, rect: [409.977993,70 14.033203x10] frag 0 from TextNode start: 7, length: 3, rect: [409.978,70 14.033203x10]
"old" "old"
TextNode <#text> TextNode <#text>
TextNode <#text> TextNode <#text>

View file

@ -3,7 +3,7 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <body> at (8,8) content-size 784x17.46875 children: not-inline BlockContainer <body> at (8,8) content-size 784x17.46875 children: not-inline
Box <div.ipc-page-grid> at (8,8) content-size 784x17.46875 flex-container(row) [FFC] children: not-inline Box <div.ipc-page-grid> at (8,8) content-size 784x17.46875 flex-container(row) [FFC] children: not-inline
Box <div.ipc-sub-grid> at (8,8) content-size 36.84375x17.46875 flex-item [GFC] children: not-inline Box <div.ipc-sub-grid> at (8,8) content-size 36.84375x17.46875 flex-item [GFC] children: not-inline
BlockContainer <div> at (8,8) content-size 36.84375x17.46875 [BFC] children: inline BlockContainer <div> at (8,8) content-size 36.844x17.46875 [BFC] children: inline
line 0 width: 36.84375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 line 0 width: 36.84375, height: 17.46875, bottom: 17.46875, baseline: 13.53125
frag 0 from TextNode start: 0, length: 5, rect: [8,8 36.84375x17.46875] frag 0 from TextNode start: 0, length: 5, rect: [8,8 36.84375x17.46875]
"hello" "hello"

View file

@ -0,0 +1,6 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x600 [BFC] children: not-inline
BlockContainer <body> at (8,8) content-size 500x0 children: not-inline
BlockContainer <div.larg.red> at (8,8) content-size 208.332999x100 floating [BFC] children: not-inline
BlockContainer <div.larg.green> at (216.332999,8) content-size 208.332999x100 floating [BFC] children: not-inline
BlockContainer <div.smol.blue> at (424.665999,8) content-size 83.332999x100 floating [BFC] children: not-inline

View file

@ -0,0 +1,18 @@
<style>
body {
width: 500px;
}
div {
float: left;
height: 100px;
}
.larg {
width: 41.66667%;
}
.smol {
width: 16.66667%;
}
.red { background: red; }
.green { background: green; }
.blue { background: blue; }
</style><div class="larg red"></div><div class="larg green"></div><div class="smol blue"></div>

View file

@ -59,7 +59,15 @@ Length Length::percentage_of(Percentage const& percentage) const
return *this; return *this;
} }
return Length { static_cast<double>(percentage.as_fraction()) * raw_value(), m_type }; // HACK: We round to 3 decimal places to emulate what happens in browsers that used fixed point math.
// FIXME: Remove this when converting CSSPixels to a fixed-point type.
// https://github.com/SerenityOS/serenity/issues/18566
auto value = percentage.as_fraction() * raw_value();
value *= 1000;
value = round(value);
value /= 1000;
return Length { value, m_type };
} }
CSSPixels Length::font_relative_length_to_px(Length::FontMetrics const& font_metrics, Length::FontMetrics const& root_font_metrics) const CSSPixels Length::font_relative_length_to_px(Length::FontMetrics const& font_metrics, Length::FontMetrics const& root_font_metrics) const