Skip to content

Commit 00f76cc

Browse files
AtkinsSJawesomekling
authored andcommitted
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.
1 parent ea0bfda commit 00f76cc

File tree

5 files changed

+63
-8
lines changed

5 files changed

+63
-8
lines changed

Libraries/LibWeb/CSS/Parser/ValueParsing.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2710,7 +2710,6 @@ Optional<URL> Parser::parse_url_function(TokenStream<ComponentValue>& tokens)
27102710
// <url> = <url()> | <src()>
27112711
// <url()> = url( <string> <url-modifier>* ) | <url-token>
27122712
// <src()> = src( <string> <url-modifier>* )
2713-
// FIXME: Also parse src() function
27142713
auto transaction = tokens.begin_transaction();
27152714
auto const& component_value = tokens.consume_a_token();
27162715

@@ -2721,7 +2720,17 @@ Optional<URL> Parser::parse_url_function(TokenStream<ComponentValue>& tokens)
27212720
}
27222721

27232722
// <url()> = url( <string> <url-modifier>* )
2724-
if (component_value.is_function("url"sv)) {
2723+
// <src()> = src( <string> <url-modifier>* )
2724+
if (component_value.is_function()) {
2725+
URL::Type function_type;
2726+
if (component_value.is_function("url"sv)) {
2727+
function_type = URL::Type::Url;
2728+
} else if (component_value.is_function("src"sv)) {
2729+
function_type = URL::Type::Src;
2730+
} else {
2731+
return {};
2732+
}
2733+
27252734
auto const& function_values = component_value.function().value;
27262735
TokenStream url_tokens { function_values };
27272736

@@ -2802,7 +2811,7 @@ Optional<URL> Parser::parse_url_function(TokenStream<ComponentValue>& tokens)
28022811
});
28032812

28042813
transaction.commit();
2805-
return URL { url_string.token().string().to_string(), move(request_url_modifiers) };
2814+
return URL { url_string.token().string().to_string(), function_type, move(request_url_modifiers) };
28062815
}
28072816

28082817
return {};

Libraries/LibWeb/CSS/URL.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,28 @@
1010

1111
namespace Web::CSS {
1212

13-
URL::URL(String url, Vector<RequestURLModifier> request_url_modifiers)
14-
: m_url(move(url))
13+
URL::URL(String url, Type type, Vector<RequestURLModifier> request_url_modifiers)
14+
: m_type(type)
15+
, m_url(move(url))
1516
, m_request_url_modifiers(move(request_url_modifiers))
1617
{
1718
}
1819

1920
// https://drafts.csswg.org/cssom-1/#serialize-a-url
2021
String URL::to_string() const
2122
{
22-
// To serialize a URL means to create a string represented by "url(", followed by the serialization of the URL as a string, followed by ")".
23+
// To serialize a URL means to create a string represented by "url(", followed by the serialization of the URL as a
24+
// string, followed by ")".
25+
// AD-HOC: Serialize as src() if it was declared as that.
2326
StringBuilder builder;
24-
builder.append("url("sv);
27+
switch (m_type) {
28+
case Type::Url:
29+
builder.append("url("sv);
30+
break;
31+
case Type::Src:
32+
builder.append("src("sv);
33+
break;
34+
}
2535
serialize_a_string(builder, m_url);
2636

2737
// AD-HOC: Serialize the RequestURLModifiers

Libraries/LibWeb/CSS/URL.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,12 @@ class RequestURLModifier {
4444
// https://drafts.csswg.org/css-values-4/#urls
4545
class URL {
4646
public:
47-
URL(String url, Vector<RequestURLModifier> = {});
47+
enum class Type : u8 {
48+
Url,
49+
Src,
50+
};
51+
52+
URL(String url, Type = Type::Url, Vector<RequestURLModifier> = {});
4853

4954
String const& url() const { return m_url; }
5055
Vector<RequestURLModifier> const& request_url_modifiers() const { return m_request_url_modifiers; }
@@ -53,6 +58,7 @@ class URL {
5358
bool operator==(URL const&) const;
5459

5560
private:
61+
Type m_type;
5662
String m_url;
5763
Vector<RequestURLModifier> m_request_url_modifiers;
5864
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Before: none
2+
Using url('cool.png'): url("cool.png")
3+
Using url(var(--some-url)): none
4+
Using src('cool.png'): src("cool.png")
5+
Using src(var(--some-url)): src("awesome.png")
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<!DOCTYPE html>
2+
<script src="../include.js"></script>
3+
<div id="target" style="--some-url: 'awesome.png'"></div>
4+
<script>
5+
test(() => {
6+
let target = document.getElementById("target");
7+
println(`Before: ${getComputedStyle(target).backgroundImage}`);
8+
9+
target.style.backgroundImage = "url('cool.png')";
10+
println(`Using url('cool.png'): ${getComputedStyle(target).backgroundImage}`);
11+
12+
target.style.backgroundImage = "";
13+
target.style.backgroundImage = "url(var(--some-url))";
14+
println(`Using url(var(--some-url)): ${getComputedStyle(target).backgroundImage}`);
15+
16+
target.style.backgroundImage = "";
17+
target.style.backgroundImage = "src('cool.png')";
18+
println(`Using src('cool.png'): ${getComputedStyle(target).backgroundImage}`);
19+
20+
target.style.backgroundImage = "";
21+
target.style.backgroundImage = "src(var(--some-url))";
22+
println(`Using src(var(--some-url)): ${getComputedStyle(target).backgroundImage}`);
23+
24+
});
25+
</script>

0 commit comments

Comments
 (0)