mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-05-09 04:32:51 +00:00
LibWeb+WebContent+UI: Support image cursors
The `cursor` property accepts a list of possible cursors, which behave as a fallback: We use whichever cursor is the first available one. This is a little complicated because initially, any remote images have not loaded, so we need to use the fallback standard cursor, and then switch to another when it loads. So, ComputedValues stores a Vector of cursors, and then in EventHandler we scan down that list until we find a cursor that's ready for use. The spec defines cursors as being `<url>`, but allows for `<image>` instead. That includes functions like `linear-gradient()`. This commit implements image cursors in the Qt UI, but not AppKit.
This commit is contained in:
parent
fd2414ba35
commit
bfd7ac1204
Notes:
github-actions[bot]
2025-02-28 12:51:27 +00:00
Author: https://github.com/AtkinsSJ
Commit: bfd7ac1204
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3644
20 changed files with 297 additions and 170 deletions
|
@ -26,6 +26,7 @@
|
|||
#include <LibWeb/CSS/StyleValues/ColorSchemeStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/ContentStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/CounterDefinitionsStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/CursorStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/CustomIdentStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/DisplayStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/EasingStyleValue.h>
|
||||
|
@ -537,6 +538,10 @@ Parser::ParseErrorOr<NonnullRefPtr<CSSStyleValue>> Parser::parse_css_value(Prope
|
|||
if (auto parsed_value = parse_counter_set_value(tokens); parsed_value && !tokens.has_next_token())
|
||||
return parsed_value.release_nonnull();
|
||||
return ParseError::SyntaxError;
|
||||
case PropertyID::Cursor:
|
||||
if (auto parsed_value = parse_cursor_value(tokens); parsed_value && !tokens.has_next_token())
|
||||
return parsed_value.release_nonnull();
|
||||
return ParseError::SyntaxError;
|
||||
case PropertyID::Display:
|
||||
if (auto parsed_value = parse_display_value(tokens); parsed_value && !tokens.has_next_token())
|
||||
return parsed_value.release_nonnull();
|
||||
|
@ -958,6 +963,72 @@ RefPtr<CSSStyleValue> Parser::parse_counter_set_value(TokenStream<ComponentValue
|
|||
return parse_counter_definitions_value(tokens, AllowReversed::No, 0);
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/css-ui-3/#cursor
|
||||
RefPtr<CSSStyleValue> Parser::parse_cursor_value(TokenStream<ComponentValue>& tokens)
|
||||
{
|
||||
// [ [<url> [<x> <y>]?,]* <built-in-cursor> ]
|
||||
// So, any number of custom cursor definitions, and then a mandatory cursor name keyword, all comma-separated.
|
||||
|
||||
auto transaction = tokens.begin_transaction();
|
||||
|
||||
StyleValueVector cursors;
|
||||
|
||||
auto parts = parse_a_comma_separated_list_of_component_values(tokens);
|
||||
for (auto i = 0u; i < parts.size(); ++i) {
|
||||
auto& part = parts[i];
|
||||
TokenStream part_tokens { part };
|
||||
|
||||
if (i == parts.size() - 1) {
|
||||
// Cursor keyword
|
||||
part_tokens.discard_whitespace();
|
||||
auto keyword_value = parse_keyword_value(part_tokens);
|
||||
if (!keyword_value || !keyword_to_cursor(keyword_value->to_keyword()).has_value())
|
||||
return {};
|
||||
|
||||
part_tokens.discard_whitespace();
|
||||
if (part_tokens.has_next_token())
|
||||
return {};
|
||||
|
||||
cursors.append(keyword_value.release_nonnull());
|
||||
} else {
|
||||
// Custom cursor definition
|
||||
// <url> [<x> <y>]?
|
||||
// "Conforming user agents may, instead of <url>, support <image> which is a superset."
|
||||
|
||||
part_tokens.discard_whitespace();
|
||||
auto image_value = parse_image_value(part_tokens);
|
||||
if (!image_value)
|
||||
return {};
|
||||
|
||||
part_tokens.discard_whitespace();
|
||||
|
||||
if (part_tokens.has_next_token()) {
|
||||
// x and y, which are both <number>
|
||||
auto x = parse_number(part_tokens);
|
||||
part_tokens.discard_whitespace();
|
||||
auto y = parse_number(part_tokens);
|
||||
part_tokens.discard_whitespace();
|
||||
if (!x.has_value() || !y.has_value() || part_tokens.has_next_token())
|
||||
return nullptr;
|
||||
|
||||
cursors.append(CursorStyleValue::create(image_value.release_nonnull(), x.release_value(), y.release_value()));
|
||||
continue;
|
||||
}
|
||||
|
||||
cursors.append(CursorStyleValue::create(image_value.release_nonnull(), {}, {}));
|
||||
}
|
||||
}
|
||||
|
||||
if (cursors.is_empty())
|
||||
return nullptr;
|
||||
|
||||
transaction.commit();
|
||||
if (cursors.size() == 1)
|
||||
return *cursors.first();
|
||||
|
||||
return StyleValueList::create(move(cursors), StyleValueList::Separator::Comma);
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/css-sizing-4/#aspect-ratio
|
||||
RefPtr<CSSStyleValue> Parser::parse_aspect_ratio_value(TokenStream<ComponentValue>& tokens)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue