LibWeb/CSS: Shorten the length of srgb serialization

The WPT tests require the shortest possible serialization that support
an 8 bits roundtrip.

As an example, `128` is serialized to `0.5` while `127` needs more
precision and thus will be serialized to `0.498`.

This commit fixes 33 WPT subtests in css/css-color.
This commit is contained in:
Lucas CHOLLET 2024-11-23 17:15:36 -05:00 committed by Sam Atkins
commit ad3dd547b7
Notes: github-actions[bot] 2024-12-04 11:31:36 +00:00
16 changed files with 8478 additions and 3 deletions

View file

@ -135,16 +135,64 @@ void serialize_unicode_ranges(StringBuilder& builder, Vector<Gfx::UnicodeRange>
});
}
namespace {
char nth_digit(u32 value, u8 digit)
{
// This helper is used to format integers.
// nth_digit(745, 1) -> '5'
// nth_digit(745, 2) -> '4'
// nth_digit(745, 3) -> '7'
VERIFY(value < 1000);
VERIFY(digit <= 3);
VERIFY(digit > 0);
while (digit > 1) {
value /= 10;
digit--;
}
return '0' + value % 10;
}
Array<char, 4> format_to_8bit_compatible(u8 value)
{
// This function formats to the shortest string that roundtrips at 8 bits.
// As an example:
// 127 / 255 = 0.498 ± 0.001
// 128 / 255 = 0.502 ± 0.001
// But round(.5 * 255) == 128, so this function returns (note that it's only the fractional part):
// 127 -> "498"
// 128 -> "5"
u32 const three_digits = (value * 1000u + 127) / 255;
u32 const rounded_to_two_digits = (three_digits + 5) / 10 * 10;
if ((rounded_to_two_digits * 255 / 100 + 5) / 10 != value)
return { nth_digit(three_digits, 3), nth_digit(three_digits, 2), nth_digit(three_digits, 1), '\0' };
u32 const rounded_to_one_digit = (three_digits + 50) / 100 * 100;
if ((rounded_to_one_digit * 255 / 100 + 5) / 10 != value)
return { nth_digit(rounded_to_two_digits, 3), nth_digit(rounded_to_two_digits, 2), '\0', '\0' };
return { nth_digit(rounded_to_one_digit, 3), '\0', '\0', '\0' };
}
}
// https://www.w3.org/TR/css-color-4/#serializing-sRGB-values
void serialize_a_srgb_value(StringBuilder& builder, Color color)
{
// The serialized form is derived from the computed value and thus, uses either the rgb() or rgba() form
// (depending on whether the alpha is exactly 1, or not), with lowercase letters for the function name.
// NOTE: Since we use Gfx::Color, having an "alpha of 1" means its value is 255.
if (color.alpha() == 255)
if (color.alpha() == 0)
builder.appendff("rgba({}, {}, {}, 0)"sv, color.red(), color.green(), color.blue());
else if (color.alpha() == 255)
builder.appendff("rgb({}, {}, {})"sv, color.red(), color.green(), color.blue());
else
builder.appendff("rgba({}, {}, {}, {:.4})"sv, color.red(), color.green(), color.blue(), (float)(color.alpha()) / 255.0f);
builder.appendff("rgba({}, {}, {}, 0.{})"sv, color.red(), color.green(), color.blue(), format_to_8bit_compatible(color.alpha()).data());
}
String serialize_an_identifier(StringView ident)