mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-12-07 21:59:54 +00:00
LibWeb+LibGfx: Move CSS sRGB color serialization function to LibGfx
This commit is contained in:
parent
633fc45e0f
commit
ebd802f6fc
Notes:
github-actions[bot]
2025-10-26 17:56:37 +00:00
Author: https://github.com/tcl3
Commit: ebd802f6fc
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/6593
Reviewed-by: https://github.com/gmta ✅
8 changed files with 74 additions and 73 deletions
|
|
@ -25,6 +25,73 @@
|
||||||
|
|
||||||
namespace Gfx {
|
namespace Gfx {
|
||||||
|
|
||||||
|
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 Color::serialize_a_srgb_value(StringBuilder& builder) const
|
||||||
|
{
|
||||||
|
// 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 (alpha() == 0)
|
||||||
|
builder.appendff("rgba({}, {}, {}, 0)", red(), green(), blue());
|
||||||
|
else if (alpha() == 255)
|
||||||
|
builder.appendff("rgb({}, {}, {})", red(), green(), blue());
|
||||||
|
else
|
||||||
|
builder.appendff("rgba({}, {}, {}, 0.{})", red(), green(), blue(), format_to_8bit_compatible(alpha()).data());
|
||||||
|
}
|
||||||
|
|
||||||
|
String Color::serialize_a_srgb_value() const
|
||||||
|
{
|
||||||
|
StringBuilder builder;
|
||||||
|
serialize_a_srgb_value(builder);
|
||||||
|
return builder.to_string_without_validation();
|
||||||
|
}
|
||||||
|
|
||||||
String Color::to_string(HTMLCompatibleSerialization html_compatible_serialization) const
|
String Color::to_string(HTMLCompatibleSerialization html_compatible_serialization) const
|
||||||
{
|
{
|
||||||
// If the following conditions are all true:
|
// If the following conditions are all true:
|
||||||
|
|
|
||||||
|
|
@ -502,6 +502,9 @@ public:
|
||||||
String to_string_without_alpha() const;
|
String to_string_without_alpha() const;
|
||||||
Utf16String to_utf16_string_without_alpha() const;
|
Utf16String to_utf16_string_without_alpha() const;
|
||||||
|
|
||||||
|
void serialize_a_srgb_value(StringBuilder&) const;
|
||||||
|
String serialize_a_srgb_value() const;
|
||||||
|
|
||||||
ByteString to_byte_string() const;
|
ByteString to_byte_string() const;
|
||||||
ByteString to_byte_string_without_alpha() const;
|
ByteString to_byte_string_without_alpha() const;
|
||||||
static Optional<Color> from_string(StringView);
|
static Optional<Color> from_string(StringView);
|
||||||
|
|
|
||||||
|
|
@ -127,66 +127,6 @@ 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() == 0)
|
|
||||||
builder.appendff("rgba({}, {}, {}, 0)", color.red(), color.green(), color.blue());
|
|
||||||
else if (color.alpha() == 255)
|
|
||||||
builder.appendff("rgb({}, {}, {})", color.red(), color.green(), color.blue());
|
|
||||||
else
|
|
||||||
builder.appendff("rgba({}, {}, {}, 0.{})", color.red(), color.green(), color.blue(), format_to_8bit_compatible(color.alpha()).data());
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://drafts.csswg.org/cssom/#serialize-a-css-value
|
// https://drafts.csswg.org/cssom/#serialize-a-css-value
|
||||||
void serialize_a_number(StringBuilder& builder, double value)
|
void serialize_a_number(StringBuilder& builder, double value)
|
||||||
{
|
{
|
||||||
|
|
@ -218,13 +158,6 @@ String serialize_a_url(StringView url)
|
||||||
return builder.to_string_without_validation();
|
return builder.to_string_without_validation();
|
||||||
}
|
}
|
||||||
|
|
||||||
String serialize_a_srgb_value(Color color)
|
|
||||||
{
|
|
||||||
StringBuilder builder;
|
|
||||||
serialize_a_srgb_value(builder, color);
|
|
||||||
return builder.to_string_without_validation();
|
|
||||||
}
|
|
||||||
|
|
||||||
String serialize_a_number(double value)
|
String serialize_a_number(double value)
|
||||||
{
|
{
|
||||||
StringBuilder builder;
|
StringBuilder builder;
|
||||||
|
|
|
||||||
|
|
@ -23,13 +23,11 @@ WEB_API void serialize_an_identifier(StringBuilder&, StringView ident);
|
||||||
void serialize_a_string(StringBuilder&, StringView string);
|
void serialize_a_string(StringBuilder&, StringView string);
|
||||||
WEB_API void serialize_a_url(StringBuilder&, StringView url);
|
WEB_API void serialize_a_url(StringBuilder&, StringView url);
|
||||||
void serialize_unicode_ranges(StringBuilder&, Vector<Gfx::UnicodeRange> const& unicode_ranges);
|
void serialize_unicode_ranges(StringBuilder&, Vector<Gfx::UnicodeRange> const& unicode_ranges);
|
||||||
void serialize_a_srgb_value(StringBuilder&, Color color);
|
|
||||||
void serialize_a_number(StringBuilder&, double value);
|
void serialize_a_number(StringBuilder&, double value);
|
||||||
|
|
||||||
String serialize_an_identifier(StringView ident);
|
String serialize_an_identifier(StringView ident);
|
||||||
String serialize_a_string(StringView string);
|
String serialize_a_string(StringView string);
|
||||||
String serialize_a_url(StringView url);
|
String serialize_a_url(StringView url);
|
||||||
String serialize_a_srgb_value(Color color);
|
|
||||||
String serialize_a_number(double value);
|
String serialize_a_number(double value);
|
||||||
|
|
||||||
// https://www.w3.org/TR/cssom/#serialize-a-comma-separated-list
|
// https://www.w3.org/TR/cssom/#serialize-a-comma-separated-list
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ String FilterValueListStyleValue::to_string(SerializationMode mode) const
|
||||||
[&](FilterOperation::DropShadow const& drop_shadow) {
|
[&](FilterOperation::DropShadow const& drop_shadow) {
|
||||||
builder.append("drop-shadow("sv);
|
builder.append("drop-shadow("sv);
|
||||||
if (drop_shadow.color.has_value()) {
|
if (drop_shadow.color.has_value()) {
|
||||||
serialize_a_srgb_value(builder, *drop_shadow.color);
|
drop_shadow.color->serialize_a_srgb_value(builder);
|
||||||
builder.append(' ');
|
builder.append(' ');
|
||||||
}
|
}
|
||||||
builder.appendff("{} {}", drop_shadow.offset_x, drop_shadow.offset_y);
|
builder.appendff("{} {}", drop_shadow.offset_x, drop_shadow.offset_y);
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ bool HSLColorStyleValue::equals(StyleValue const& other) const
|
||||||
String HSLColorStyleValue::to_string(SerializationMode mode) const
|
String HSLColorStyleValue::to_string(SerializationMode mode) const
|
||||||
{
|
{
|
||||||
if (auto color = to_color({}); color.has_value())
|
if (auto color = to_color({}); color.has_value())
|
||||||
return serialize_a_srgb_value(color.value());
|
return color->serialize_a_srgb_value();
|
||||||
|
|
||||||
StringBuilder builder;
|
StringBuilder builder;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ bool HWBColorStyleValue::equals(StyleValue const& other) const
|
||||||
String HWBColorStyleValue::to_string(SerializationMode mode) const
|
String HWBColorStyleValue::to_string(SerializationMode mode) const
|
||||||
{
|
{
|
||||||
if (auto color = to_color({}); color.has_value())
|
if (auto color = to_color({}); color.has_value())
|
||||||
return serialize_a_srgb_value(color.value());
|
return color->serialize_a_srgb_value();
|
||||||
|
|
||||||
StringBuilder builder;
|
StringBuilder builder;
|
||||||
builder.append("hwb("sv);
|
builder.append("hwb("sv);
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ String RGBColorStyleValue::to_string(SerializationMode mode) const
|
||||||
return m_properties.name.value().to_string().to_ascii_lowercase();
|
return m_properties.name.value().to_string().to_ascii_lowercase();
|
||||||
|
|
||||||
if (auto color = to_color({}); color.has_value())
|
if (auto color = to_color({}); color.has_value())
|
||||||
return serialize_a_srgb_value(color.value());
|
return color->serialize_a_srgb_value();
|
||||||
|
|
||||||
StringBuilder builder;
|
StringBuilder builder;
|
||||||
builder.append("rgb("sv);
|
builder.append("rgb("sv);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue