mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-28 19:59:17 +00:00
LibWeb/CSS: Add alternative src() syntax for URLs
url() has some limitations because of allowing unquoted URLs as its contents. For example, it can't use `var()`. To get around this, there's an alternative `src()` function which behaves the same as `url()` except that it is parsed as a regular function, which makes `var()` and friends work properly. There's no WPT test for this as far as I can tell, so I added our own.
This commit is contained in:
parent
ea0bfda1b9
commit
00f76ccbf4
Notes:
github-actions[bot]
2025-06-11 14:27:18 +00:00
Author: https://github.com/AtkinsSJ
Commit: 00f76ccbf4
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5041
5 changed files with 63 additions and 8 deletions
|
@ -2710,7 +2710,6 @@ Optional<URL> Parser::parse_url_function(TokenStream<ComponentValue>& tokens)
|
||||||
// <url> = <url()> | <src()>
|
// <url> = <url()> | <src()>
|
||||||
// <url()> = url( <string> <url-modifier>* ) | <url-token>
|
// <url()> = url( <string> <url-modifier>* ) | <url-token>
|
||||||
// <src()> = src( <string> <url-modifier>* )
|
// <src()> = src( <string> <url-modifier>* )
|
||||||
// FIXME: Also parse src() function
|
|
||||||
auto transaction = tokens.begin_transaction();
|
auto transaction = tokens.begin_transaction();
|
||||||
auto const& component_value = tokens.consume_a_token();
|
auto const& component_value = tokens.consume_a_token();
|
||||||
|
|
||||||
|
@ -2721,7 +2720,17 @@ Optional<URL> Parser::parse_url_function(TokenStream<ComponentValue>& tokens)
|
||||||
}
|
}
|
||||||
|
|
||||||
// <url()> = url( <string> <url-modifier>* )
|
// <url()> = url( <string> <url-modifier>* )
|
||||||
if (component_value.is_function("url"sv)) {
|
// <src()> = src( <string> <url-modifier>* )
|
||||||
|
if (component_value.is_function()) {
|
||||||
|
URL::Type function_type;
|
||||||
|
if (component_value.is_function("url"sv)) {
|
||||||
|
function_type = URL::Type::Url;
|
||||||
|
} else if (component_value.is_function("src"sv)) {
|
||||||
|
function_type = URL::Type::Src;
|
||||||
|
} else {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
auto const& function_values = component_value.function().value;
|
auto const& function_values = component_value.function().value;
|
||||||
TokenStream url_tokens { function_values };
|
TokenStream url_tokens { function_values };
|
||||||
|
|
||||||
|
@ -2802,7 +2811,7 @@ Optional<URL> Parser::parse_url_function(TokenStream<ComponentValue>& tokens)
|
||||||
});
|
});
|
||||||
|
|
||||||
transaction.commit();
|
transaction.commit();
|
||||||
return URL { url_string.token().string().to_string(), move(request_url_modifiers) };
|
return URL { url_string.token().string().to_string(), function_type, move(request_url_modifiers) };
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -10,8 +10,9 @@
|
||||||
|
|
||||||
namespace Web::CSS {
|
namespace Web::CSS {
|
||||||
|
|
||||||
URL::URL(String url, Vector<RequestURLModifier> request_url_modifiers)
|
URL::URL(String url, Type type, Vector<RequestURLModifier> request_url_modifiers)
|
||||||
: m_url(move(url))
|
: m_type(type)
|
||||||
|
, m_url(move(url))
|
||||||
, m_request_url_modifiers(move(request_url_modifiers))
|
, m_request_url_modifiers(move(request_url_modifiers))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -19,9 +20,18 @@ URL::URL(String url, Vector<RequestURLModifier> request_url_modifiers)
|
||||||
// https://drafts.csswg.org/cssom-1/#serialize-a-url
|
// https://drafts.csswg.org/cssom-1/#serialize-a-url
|
||||||
String URL::to_string() const
|
String URL::to_string() const
|
||||||
{
|
{
|
||||||
// To serialize a URL means to create a string represented by "url(", followed by the serialization of the URL as a string, followed by ")".
|
// To serialize a URL means to create a string represented by "url(", followed by the serialization of the URL as a
|
||||||
|
// string, followed by ")".
|
||||||
|
// AD-HOC: Serialize as src() if it was declared as that.
|
||||||
StringBuilder builder;
|
StringBuilder builder;
|
||||||
builder.append("url("sv);
|
switch (m_type) {
|
||||||
|
case Type::Url:
|
||||||
|
builder.append("url("sv);
|
||||||
|
break;
|
||||||
|
case Type::Src:
|
||||||
|
builder.append("src("sv);
|
||||||
|
break;
|
||||||
|
}
|
||||||
serialize_a_string(builder, m_url);
|
serialize_a_string(builder, m_url);
|
||||||
|
|
||||||
// AD-HOC: Serialize the RequestURLModifiers
|
// AD-HOC: Serialize the RequestURLModifiers
|
||||||
|
|
|
@ -44,7 +44,12 @@ private:
|
||||||
// https://drafts.csswg.org/css-values-4/#urls
|
// https://drafts.csswg.org/css-values-4/#urls
|
||||||
class URL {
|
class URL {
|
||||||
public:
|
public:
|
||||||
URL(String url, Vector<RequestURLModifier> = {});
|
enum class Type : u8 {
|
||||||
|
Url,
|
||||||
|
Src,
|
||||||
|
};
|
||||||
|
|
||||||
|
URL(String url, Type = Type::Url, Vector<RequestURLModifier> = {});
|
||||||
|
|
||||||
String const& url() const { return m_url; }
|
String const& url() const { return m_url; }
|
||||||
Vector<RequestURLModifier> const& request_url_modifiers() const { return m_request_url_modifiers; }
|
Vector<RequestURLModifier> const& request_url_modifiers() const { return m_request_url_modifiers; }
|
||||||
|
@ -53,6 +58,7 @@ public:
|
||||||
bool operator==(URL const&) const;
|
bool operator==(URL const&) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Type m_type;
|
||||||
String m_url;
|
String m_url;
|
||||||
Vector<RequestURLModifier> m_request_url_modifiers;
|
Vector<RequestURLModifier> m_request_url_modifiers;
|
||||||
};
|
};
|
||||||
|
|
5
Tests/LibWeb/Text/expected/css/src-function.txt
Normal file
5
Tests/LibWeb/Text/expected/css/src-function.txt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
Before: none
|
||||||
|
Using url('cool.png'): url("cool.png")
|
||||||
|
Using url(var(--some-url)): none
|
||||||
|
Using src('cool.png'): src("cool.png")
|
||||||
|
Using src(var(--some-url)): src("awesome.png")
|
25
Tests/LibWeb/Text/input/css/src-function.html
Normal file
25
Tests/LibWeb/Text/input/css/src-function.html
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<script src="../include.js"></script>
|
||||||
|
<div id="target" style="--some-url: 'awesome.png'"></div>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
let target = document.getElementById("target");
|
||||||
|
println(`Before: ${getComputedStyle(target).backgroundImage}`);
|
||||||
|
|
||||||
|
target.style.backgroundImage = "url('cool.png')";
|
||||||
|
println(`Using url('cool.png'): ${getComputedStyle(target).backgroundImage}`);
|
||||||
|
|
||||||
|
target.style.backgroundImage = "";
|
||||||
|
target.style.backgroundImage = "url(var(--some-url))";
|
||||||
|
println(`Using url(var(--some-url)): ${getComputedStyle(target).backgroundImage}`);
|
||||||
|
|
||||||
|
target.style.backgroundImage = "";
|
||||||
|
target.style.backgroundImage = "src('cool.png')";
|
||||||
|
println(`Using src('cool.png'): ${getComputedStyle(target).backgroundImage}`);
|
||||||
|
|
||||||
|
target.style.backgroundImage = "";
|
||||||
|
target.style.backgroundImage = "src(var(--some-url))";
|
||||||
|
println(`Using src(var(--some-url)): ${getComputedStyle(target).backgroundImage}`);
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
Loading…
Add table
Add a link
Reference in a new issue