LibWeb: Make Serialize functions infallible

This commit is contained in:
Sam Atkins 2023-08-22 12:05:44 +01:00 committed by Sam Atkins
parent 788c2c5a8d
commit b5893ee115
10 changed files with 95 additions and 105 deletions

View file

@ -14,10 +14,10 @@
namespace Web::CSS {
// https://www.w3.org/TR/cssom-1/#dom-css-escape
WebIDL::ExceptionOr<String> escape(JS::VM& vm, StringView identifier)
WebIDL::ExceptionOr<String> escape(JS::VM&, StringView identifier)
{
// The escape(ident) operation must return the result of invoking serialize an identifier of ident.
return TRY_OR_THROW_OOM(vm, serialize_an_identifier(identifier));
return serialize_an_identifier(identifier);
}
// https://www.w3.org/TR/css-conditional-3/#dom-css-supports

View file

@ -50,7 +50,7 @@ DeprecatedString CSSFontFaceRule::serialized() const
builder.append("font-family: "sv);
// 3. The result of performing serialize a string on the rules font family name.
serialize_a_string(builder, m_font_face.font_family()).release_value_but_fixme_should_propagate_errors();
serialize_a_string(builder, m_font_face.font_family());
// 4. The string ";", i.e., SEMICOLON (U+003B).
builder.append(';');
@ -61,18 +61,17 @@ DeprecatedString CSSFontFaceRule::serialized() const
builder.append(" src: "sv);
// 2. The result of invoking serialize a comma-separated list on performing serialize a URL or serialize a LOCAL for each source on the source list.
serialize_a_comma_separated_list(builder, m_font_face.sources(), [&](StringBuilder& builder, FontFace::Source source) -> ErrorOr<void> {
serialize_a_comma_separated_list(builder, m_font_face.sources(), [&](StringBuilder& builder, FontFace::Source source) -> void {
// FIXME: Serialize locals once we support those
TRY(serialize_a_url(builder, source.url.to_deprecated_string()));
serialize_a_url(builder, source.url.to_deprecated_string());
// NOTE: No spec currently exists for format()
if (source.format.has_value()) {
TRY(builder.try_append(" format("sv));
TRY(serialize_a_string(builder, source.format.value()));
TRY(builder.try_append(")"sv));
builder.append(" format("sv);
serialize_a_string(builder, source.format.value());
builder.append(")"sv);
}
return {};
}).release_value_but_fixme_should_propagate_errors();
});
// 3. The string ";", i.e., SEMICOLON (U+003B).
builder.append(';');
@ -80,7 +79,7 @@ DeprecatedString CSSFontFaceRule::serialized() const
// 6. If rules associated unicode-range descriptor is present, a single SPACE (U+0020), followed by the string "unicode-range:", followed by a single SPACE (U+0020), followed by the result of performing serialize a <'unicode-range'>, followed by the string ";", i.e., SEMICOLON (U+003B).
builder.append(" unicode-range: "sv);
serialize_unicode_ranges(builder, m_font_face.unicode_ranges()).release_value_but_fixme_should_propagate_errors();
serialize_unicode_ranges(builder, m_font_face.unicode_ranges());
builder.append(';');
// FIXME: 7. If rules associated font-variant descriptor is present, a single SPACE (U+0020),

View file

@ -41,13 +41,13 @@ DeprecatedString CSSNamespaceRule::serialized() const
// followed by the serialization as an identifier of the prefix attribute (if any),
if (!m_prefix.is_empty() && !m_prefix.is_null()) {
serialize_an_identifier(builder, m_prefix).release_value_but_fixme_should_propagate_errors();
serialize_an_identifier(builder, m_prefix);
// followed by a single SPACE (U+0020) if there is a prefix,
builder.append(" "sv);
}
// followed by the serialization as URL of the namespaceURI attribute,
serialize_a_url(builder, m_namespace_uri).release_value_but_fixme_should_propagate_errors();
serialize_a_url(builder, m_namespace_uri);
// followed the character ";" (U+003B).
builder.append(";"sv);

View file

@ -23,7 +23,7 @@ ErrorOr<String> Declaration::to_string() const
{
StringBuilder builder;
TRY(serialize_an_identifier(builder, m_name));
serialize_an_identifier(builder, m_name);
TRY(builder.try_append(": "sv));
TRY(builder.try_join(' ', m_values));

View file

@ -22,7 +22,7 @@ ErrorOr<String> Function::to_string() const
{
StringBuilder builder;
TRY(serialize_an_identifier(builder, m_name));
serialize_an_identifier(builder, m_name);
TRY(builder.try_append('('));
TRY(builder.try_join(' ', m_values));
TRY(builder.try_append(')'));

View file

@ -20,13 +20,13 @@ ErrorOr<String> Token::to_string() const
case Type::Ident:
return serialize_an_identifier(ident());
case Type::Function:
return String::formatted("{}(", TRY(serialize_an_identifier(function())));
return String::formatted("{}(", serialize_an_identifier(function()));
case Type::AtKeyword:
return String::formatted("@{}", TRY(serialize_an_identifier(at_keyword())));
return String::formatted("@{}", serialize_an_identifier(at_keyword()));
case Type::Hash: {
switch (m_hash_type) {
case HashType::Id:
return String::formatted("#{}", TRY(serialize_an_identifier(hash_value())));
return String::formatted("#{}", serialize_an_identifier(hash_value()));
case HashType::Unrestricted:
return String::formatted("#{}", hash_value());
}

View file

@ -130,7 +130,7 @@ ErrorOr<String> Selector::SimpleSelector::serialize() const
// namespace (not in a namespace) append the serialization of the namespace prefix as an identifier,
// followed by a "|" (U+007C) to s.
if (qualified_name.namespace_type == QualifiedName::NamespaceType::Named) {
TRY(serialize_an_identifier(s, qualified_name.namespace_));
serialize_an_identifier(s, qualified_name.namespace_);
TRY(s.try_append('|'));
}
@ -141,7 +141,7 @@ ErrorOr<String> Selector::SimpleSelector::serialize() const
// 3. If this is a type selector append the serialization of the element name as an identifier to s.
if (type == Selector::SimpleSelector::Type::TagName)
TRY(serialize_an_identifier(s, qualified_name.name.name));
serialize_an_identifier(s, qualified_name.name.name);
// 4. If this is a universal selector append "*" (U+002A) to s.
if (type == Selector::SimpleSelector::Type::Universal)
@ -158,12 +158,12 @@ ErrorOr<String> Selector::SimpleSelector::serialize() const
// 2. If the namespace prefix maps to a namespace that is not the null namespace (not in a namespace)
// append the serialization of the namespace prefix as an identifier, followed by a "|" (U+007C) to s.
if (attribute.qualified_name.namespace_type == QualifiedName::NamespaceType::Named) {
TRY(serialize_an_identifier(s, attribute.qualified_name.namespace_));
serialize_an_identifier(s, attribute.qualified_name.namespace_);
TRY(s.try_append('|'));
}
// 3. Append the serialization of the attribute name as an identifier to s.
TRY(serialize_an_identifier(s, attribute.qualified_name.name.name));
serialize_an_identifier(s, attribute.qualified_name.name.name);
// 4. If there is an attribute value specified, append "=", "~=", "|=", "^=", "$=", or "*=" as appropriate (depending on the type of attribute selector),
// followed by the serialization of the attribute value as a string, to s.
@ -191,7 +191,7 @@ ErrorOr<String> Selector::SimpleSelector::serialize() const
break;
}
TRY(serialize_a_string(s, attribute.value));
serialize_a_string(s, attribute.value);
}
// 5. If the attribute selector has the case-insensitivity flag present, append " i" (U+0020 U+0069) to s.
@ -216,13 +216,13 @@ ErrorOr<String> Selector::SimpleSelector::serialize() const
case Selector::SimpleSelector::Type::Class:
// Append a "." (U+002E), followed by the serialization of the class name as an identifier to s.
TRY(s.try_append('.'));
TRY(serialize_an_identifier(s, name()));
serialize_an_identifier(s, name());
break;
case Selector::SimpleSelector::Type::Id:
// Append a "#" (U+0023), followed by the serialization of the ID as an identifier to s.
TRY(s.try_append('#'));
TRY(serialize_an_identifier(s, name()));
serialize_an_identifier(s, name());
break;
case Selector::SimpleSelector::Type::PseudoClass: {

View file

@ -11,22 +11,20 @@
namespace Web::CSS {
// https://www.w3.org/TR/cssom-1/#escape-a-character
ErrorOr<void> escape_a_character(StringBuilder& builder, u32 character)
void escape_a_character(StringBuilder& builder, u32 character)
{
TRY(builder.try_append('\\'));
TRY(builder.try_append_code_point(character));
return {};
builder.append('\\');
builder.append_code_point(character);
}
// https://www.w3.org/TR/cssom-1/#escape-a-character-as-code-point
ErrorOr<void> escape_a_character_as_code_point(StringBuilder& builder, u32 character)
void escape_a_character_as_code_point(StringBuilder& builder, u32 character)
{
TRY(builder.try_appendff("\\{:x} ", character));
return {};
builder.appendff("\\{:x} ", character);
}
// https://www.w3.org/TR/cssom-1/#serialize-an-identifier
ErrorOr<void> serialize_an_identifier(StringBuilder& builder, StringView ident)
void serialize_an_identifier(StringBuilder& builder, StringView ident)
{
Utf8View characters { ident };
auto first_character = characters.is_empty() ? 0 : *characters.begin();
@ -36,31 +34,31 @@ ErrorOr<void> serialize_an_identifier(StringBuilder& builder, StringView ident)
for (auto character : characters) {
// If the character is NULL (U+0000), then the REPLACEMENT CHARACTER (U+FFFD).
if (character == 0) {
TRY(builder.try_append_code_point(0xFFFD));
builder.append_code_point(0xFFFD);
continue;
}
// If the character is in the range [\1-\1f] (U+0001 to U+001F) or is U+007F,
// then the character escaped as code point.
if ((character >= 0x0001 && character <= 0x001F) || (character == 0x007F)) {
TRY(escape_a_character_as_code_point(builder, character));
escape_a_character_as_code_point(builder, character);
continue;
}
// If the character is the first character and is in the range [0-9] (U+0030 to U+0039),
// then the character escaped as code point.
if (builder.is_empty() && character >= '0' && character <= '9') {
TRY(escape_a_character_as_code_point(builder, character));
escape_a_character_as_code_point(builder, character);
continue;
}
// If the character is the second character and is in the range [0-9] (U+0030 to U+0039)
// and the first character is a "-" (U+002D), then the character escaped as code point.
if (builder.length() == 1 && first_character == '-' && character >= '0' && character <= '9') {
TRY(escape_a_character_as_code_point(builder, character));
escape_a_character_as_code_point(builder, character);
continue;
}
// If the character is the first character and is a "-" (U+002D), and there is no second
// character, then the escaped character.
if (builder.is_empty() && character == '-' && characters.length() == 1) {
TRY(escape_a_character(builder, character));
escape_a_character(builder, character);
continue;
}
// If the character is not handled by one of the above rules and is greater than or equal to U+0080, is "-" (U+002D) or "_" (U+005F), or is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to U+005A), or \[a-z] (U+0061 to U+007A), then the character itself.
@ -69,132 +67,126 @@ ErrorOr<void> serialize_an_identifier(StringBuilder& builder, StringView ident)
|| (character >= '0' && character <= '9')
|| (character >= 'A' && character <= 'Z')
|| (character >= 'a' && character <= 'z')) {
TRY(builder.try_append_code_point(character));
builder.append_code_point(character);
continue;
}
// Otherwise, the escaped character.
TRY(escape_a_character(builder, character));
escape_a_character(builder, character);
}
return {};
}
// https://www.w3.org/TR/cssom-1/#serialize-a-string
ErrorOr<void> serialize_a_string(StringBuilder& builder, StringView string)
void serialize_a_string(StringBuilder& builder, StringView string)
{
Utf8View characters { string };
// To serialize a string means to create a string represented by '"' (U+0022), followed by the result
// of applying the rules below to each character of the given string, followed by '"' (U+0022):
TRY(builder.try_append('"'));
builder.append('"');
for (auto character : characters) {
// If the character is NULL (U+0000), then the REPLACEMENT CHARACTER (U+FFFD).
if (character == 0) {
TRY(builder.try_append_code_point(0xFFFD));
builder.append_code_point(0xFFFD);
continue;
}
// If the character is in the range [\1-\1f] (U+0001 to U+001F) or is U+007F, the character escaped as code point.
if ((character >= 0x0001 && character <= 0x001F) || (character == 0x007F)) {
TRY(escape_a_character_as_code_point(builder, character));
escape_a_character_as_code_point(builder, character);
continue;
}
// If the character is '"' (U+0022) or "\" (U+005C), the escaped character.
if (character == 0x0022 || character == 0x005C) {
TRY(escape_a_character(builder, character));
escape_a_character(builder, character);
continue;
}
// Otherwise, the character itself.
TRY(builder.try_append_code_point(character));
builder.append_code_point(character);
}
TRY(builder.try_append('"'));
return {};
builder.append('"');
}
// https://www.w3.org/TR/cssom-1/#serialize-a-url
ErrorOr<void> serialize_a_url(StringBuilder& builder, StringView url)
void serialize_a_url(StringBuilder& builder, StringView url)
{
// To serialize a URL means to create a string represented by "url(",
// followed by the serialization of the URL as a string, followed by ")".
TRY(builder.try_append("url("sv));
TRY(serialize_a_string(builder, url.to_deprecated_string()));
TRY(builder.try_append(')'));
return {};
builder.append("url("sv);
serialize_a_string(builder, url.to_deprecated_string());
builder.append(')');
}
// https://www.w3.org/TR/cssom-1/#serialize-a-local
ErrorOr<void> serialize_a_local(StringBuilder& builder, StringView path)
void serialize_a_local(StringBuilder& builder, StringView path)
{
// To serialize a LOCAL means to create a string represented by "local(",
// followed by the serialization of the LOCAL as a string, followed by ")".
TRY(builder.try_append("local("sv));
TRY(serialize_a_string(builder, path.to_deprecated_string()));
TRY(builder.try_append(')'));
return {};
builder.append("local("sv);
serialize_a_string(builder, path.to_deprecated_string());
builder.append(')');
}
// NOTE: No spec currently exists for serializing a <'unicode-range'>.
ErrorOr<void> serialize_unicode_ranges(StringBuilder& builder, Vector<UnicodeRange> const& unicode_ranges)
void serialize_unicode_ranges(StringBuilder& builder, Vector<UnicodeRange> const& unicode_ranges)
{
TRY(serialize_a_comma_separated_list(builder, unicode_ranges, [](auto& builder, UnicodeRange unicode_range) -> ErrorOr<void> {
return serialize_a_string(builder, TRY(unicode_range.to_string()));
}));
return {};
serialize_a_comma_separated_list(builder, unicode_ranges, [](auto& builder, UnicodeRange unicode_range) -> void {
return serialize_a_string(builder, MUST(unicode_range.to_string()));
});
}
// https://www.w3.org/TR/css-color-4/#serializing-sRGB-values
ErrorOr<void> serialize_a_srgb_value(StringBuilder& builder, Color color)
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)
TRY(builder.try_appendff("rgb({}, {}, {})"sv, color.red(), color.green(), color.blue()));
builder.appendff("rgb({}, {}, {})"sv, color.red(), color.green(), color.blue());
else
TRY(builder.try_appendff("rgba({}, {}, {}, {})"sv, color.red(), color.green(), color.blue(), (float)(color.alpha()) / 255.0f));
return {};
builder.appendff("rgba({}, {}, {}, {})"sv, color.red(), color.green(), color.blue(), (float)(color.alpha()) / 255.0f);
}
ErrorOr<String> escape_a_character(u32 character)
String escape_a_character(u32 character)
{
StringBuilder builder;
TRY(escape_a_character(builder, character));
return builder.to_string();
escape_a_character(builder, character);
return MUST(builder.to_string());
}
ErrorOr<String> escape_a_character_as_code_point(u32 character)
String escape_a_character_as_code_point(u32 character)
{
StringBuilder builder;
TRY(escape_a_character_as_code_point(builder, character));
return builder.to_string();
escape_a_character_as_code_point(builder, character);
return MUST(builder.to_string());
}
ErrorOr<String> serialize_an_identifier(StringView ident)
String serialize_an_identifier(StringView ident)
{
StringBuilder builder;
TRY(serialize_an_identifier(builder, ident));
return builder.to_string();
serialize_an_identifier(builder, ident);
return MUST(builder.to_string());
}
ErrorOr<String> serialize_a_string(StringView string)
String serialize_a_string(StringView string)
{
StringBuilder builder;
TRY(serialize_a_string(builder, string));
return builder.to_string();
serialize_a_string(builder, string);
return MUST(builder.to_string());
}
ErrorOr<String> serialize_a_url(StringView url)
String serialize_a_url(StringView url)
{
StringBuilder builder;
TRY(serialize_a_url(builder, url));
return builder.to_string();
serialize_a_url(builder, url);
return MUST(builder.to_string());
}
ErrorOr<String> serialize_a_srgb_value(Color color)
String serialize_a_srgb_value(Color color)
{
StringBuilder builder;
TRY(serialize_a_srgb_value(builder, color));
return builder.to_string();
serialize_a_srgb_value(builder, color);
return MUST(builder.to_string());
}
}

View file

@ -15,33 +15,32 @@
namespace Web::CSS {
ErrorOr<void> escape_a_character(StringBuilder&, u32 character);
ErrorOr<void> escape_a_character_as_code_point(StringBuilder&, u32 character);
ErrorOr<void> serialize_an_identifier(StringBuilder&, StringView ident);
ErrorOr<void> serialize_a_string(StringBuilder&, StringView string);
ErrorOr<void> serialize_a_url(StringBuilder&, StringView url);
ErrorOr<void> serialize_a_local(StringBuilder&, StringView path);
ErrorOr<void> serialize_unicode_ranges(StringBuilder&, Vector<UnicodeRange> const& unicode_ranges);
ErrorOr<void> serialize_a_srgb_value(StringBuilder&, Color color);
void escape_a_character(StringBuilder&, u32 character);
void escape_a_character_as_code_point(StringBuilder&, u32 character);
void serialize_an_identifier(StringBuilder&, StringView ident);
void serialize_a_string(StringBuilder&, StringView string);
void serialize_a_url(StringBuilder&, StringView url);
void serialize_a_local(StringBuilder&, StringView path);
void serialize_unicode_ranges(StringBuilder&, Vector<UnicodeRange> const& unicode_ranges);
void serialize_a_srgb_value(StringBuilder&, Color color);
ErrorOr<String> escape_a_character(u32 character);
ErrorOr<String> escape_a_character_as_code_point(u32 character);
ErrorOr<String> serialize_an_identifier(StringView ident);
ErrorOr<String> serialize_a_string(StringView string);
ErrorOr<String> serialize_a_url(StringView url);
ErrorOr<String> serialize_a_srgb_value(Color color);
String escape_a_character(u32 character);
String escape_a_character_as_code_point(u32 character);
String serialize_an_identifier(StringView ident);
String serialize_a_string(StringView string);
String serialize_a_url(StringView url);
String serialize_a_srgb_value(Color color);
template<typename T, typename SerializeItem>
ErrorOr<void> serialize_a_comma_separated_list(StringBuilder& builder, Vector<T> const& items, SerializeItem serialize_item)
void serialize_a_comma_separated_list(StringBuilder& builder, Vector<T> const& items, SerializeItem serialize_item)
{
for (size_t i = 0; i < items.size(); i++) {
auto& item = items.at(i);
TRY(serialize_item(builder, item));
serialize_item(builder, item);
if ((i + 1) < items.size()) {
TRY(builder.try_append(",\n"sv));
builder.append(",\n"sv);
}
}
return {};
}
}

View file

@ -75,7 +75,7 @@ ErrorOr<String> FilterValueListStyleValue::to_string() const
TRY(builder.try_appendff(" {}", TRY(drop_shadow.radius->to_string())));
if (drop_shadow.color.has_value()) {
TRY(builder.try_append(' '));
TRY(serialize_a_srgb_value(builder, *drop_shadow.color));
serialize_a_srgb_value(builder, *drop_shadow.color);
}
return {};
},