mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-28 21:26:22 +00:00
LibWeb: Parse and propagate touch-action CSS property
Co-authored-by: Sam Atkins <sam@ladybird.org>
This commit is contained in:
parent
b3713db4ab
commit
6cbb5d2785
Notes:
github-actions[bot]
2025-05-06 11:23:01 +00:00
Author: https://github.com/stravant 🔰
Commit: 6cbb5d2785
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3837
Reviewed-by: https://github.com/AtkinsSJ ✅
21 changed files with 364 additions and 19 deletions
|
@ -1580,6 +1580,54 @@ Isolation ComputedProperties::isolation() const
|
|||
return keyword_to_isolation(value.to_keyword()).release_value();
|
||||
}
|
||||
|
||||
TouchActionData ComputedProperties::touch_action() const
|
||||
{
|
||||
auto const& touch_action = property(PropertyID::TouchAction);
|
||||
if (touch_action.is_keyword()) {
|
||||
switch (touch_action.to_keyword()) {
|
||||
case Keyword::Auto:
|
||||
return TouchActionData {};
|
||||
case Keyword::None:
|
||||
return TouchActionData::none();
|
||||
case Keyword::Manipulation:
|
||||
return TouchActionData { .allow_other = false };
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
if (touch_action.is_value_list()) {
|
||||
TouchActionData touch_action_data = TouchActionData::none();
|
||||
for (auto const& value : touch_action.as_value_list().values()) {
|
||||
switch (value->as_keyword().keyword()) {
|
||||
case Keyword::PanX:
|
||||
touch_action_data.allow_right = true;
|
||||
touch_action_data.allow_left = true;
|
||||
break;
|
||||
case Keyword::PanLeft:
|
||||
touch_action_data.allow_left = true;
|
||||
break;
|
||||
case Keyword::PanRight:
|
||||
touch_action_data.allow_right = true;
|
||||
break;
|
||||
case Keyword::PanY:
|
||||
touch_action_data.allow_up = true;
|
||||
touch_action_data.allow_down = true;
|
||||
break;
|
||||
case Keyword::PanUp:
|
||||
touch_action_data.allow_up = true;
|
||||
break;
|
||||
case Keyword::PanDown:
|
||||
touch_action_data.allow_down = true;
|
||||
break;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
return touch_action_data;
|
||||
}
|
||||
return TouchActionData {};
|
||||
}
|
||||
|
||||
Containment ComputedProperties::contain() const
|
||||
{
|
||||
Containment containment = {};
|
||||
|
|
|
@ -166,6 +166,7 @@ public:
|
|||
WritingMode writing_mode() const;
|
||||
UserSelect user_select() const;
|
||||
Isolation isolation() const;
|
||||
TouchActionData touch_action() const;
|
||||
Containment contain() const;
|
||||
MixBlendMode mix_blend_mode() const;
|
||||
Optional<FlyString> view_transition_name() const;
|
||||
|
|
|
@ -309,6 +309,29 @@ public:
|
|||
bool operator==(BorderData const&) const = default;
|
||||
};
|
||||
|
||||
struct TouchActionData {
|
||||
bool allow_left : 1 { true };
|
||||
bool allow_right : 1 { true };
|
||||
bool allow_up : 1 { true };
|
||||
bool allow_down : 1 { true };
|
||||
bool allow_pinch_zoom : 1 { true };
|
||||
|
||||
// Other touch interactions which aren't pan or pinch to zoom. E.g.: Double tap to zoom.
|
||||
bool allow_other : 1 { true };
|
||||
|
||||
static TouchActionData none()
|
||||
{
|
||||
return TouchActionData {
|
||||
.allow_left = false,
|
||||
.allow_right = false,
|
||||
.allow_up = false,
|
||||
.allow_down = false,
|
||||
.allow_pinch_zoom = false,
|
||||
.allow_other = false,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
struct TransformOrigin {
|
||||
CSS::LengthPercentage x { Percentage(50) };
|
||||
CSS::LengthPercentage y { Percentage(50) };
|
||||
|
@ -456,6 +479,7 @@ public:
|
|||
CSS::Containment const& contain() const { return m_noninherited.contain; }
|
||||
CSS::MixBlendMode mix_blend_mode() const { return m_noninherited.mix_blend_mode; }
|
||||
Optional<FlyString> view_transition_name() const { return m_noninherited.view_transition_name; }
|
||||
TouchActionData touch_action() const { return m_noninherited.touch_action; }
|
||||
|
||||
CSS::LengthBox const& inset() const { return m_noninherited.inset; }
|
||||
const CSS::LengthBox& margin() const { return m_noninherited.margin; }
|
||||
|
@ -713,6 +737,7 @@ protected:
|
|||
CSS::Containment contain { InitialValues::contain() };
|
||||
CSS::MixBlendMode mix_blend_mode { InitialValues::mix_blend_mode() };
|
||||
Optional<FlyString> view_transition_name;
|
||||
TouchActionData touch_action;
|
||||
|
||||
Optional<CSS::Transformation> rotate;
|
||||
Optional<CSS::Transformation> translate;
|
||||
|
@ -891,6 +916,7 @@ public:
|
|||
void set_contain(CSS::Containment value) { m_noninherited.contain = move(value); }
|
||||
void set_mix_blend_mode(CSS::MixBlendMode value) { m_noninherited.mix_blend_mode = value; }
|
||||
void set_view_transition_name(Optional<FlyString> value) { m_noninherited.view_transition_name = value; }
|
||||
void set_touch_action(TouchActionData value) { m_noninherited.touch_action = value; }
|
||||
|
||||
void set_fill(SVGPaint value) { m_inherited.fill = move(value); }
|
||||
void set_stroke(SVGPaint value) { m_inherited.stroke = move(value); }
|
||||
|
|
|
@ -605,6 +605,17 @@
|
|||
"none",
|
||||
"uppercase"
|
||||
],
|
||||
"touch-action": [
|
||||
"auto",
|
||||
"manipulation",
|
||||
"none",
|
||||
"pan-down",
|
||||
"pan-left",
|
||||
"pan-right",
|
||||
"pan-up",
|
||||
"pan-x",
|
||||
"pan-y"
|
||||
],
|
||||
"transform-box": [
|
||||
"content-box",
|
||||
"border-box",
|
||||
|
|
|
@ -279,6 +279,7 @@
|
|||
"ltr",
|
||||
"luminance",
|
||||
"luminosity",
|
||||
"manipulation",
|
||||
"mark",
|
||||
"marktext",
|
||||
"match-parent",
|
||||
|
@ -344,6 +345,12 @@
|
|||
"padding-box",
|
||||
"paged",
|
||||
"paint",
|
||||
"pan-down",
|
||||
"pan-left",
|
||||
"pan-right",
|
||||
"pan-up",
|
||||
"pan-x",
|
||||
"pan-y",
|
||||
"paused",
|
||||
"petite-caps",
|
||||
"pi",
|
||||
|
|
|
@ -434,6 +434,7 @@ private:
|
|||
RefPtr<CSSStyleValue const> parse_grid_template_areas_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<CSSStyleValue const> parse_grid_area_shorthand_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<CSSStyleValue const> parse_grid_shorthand_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<CSSStyleValue const> parse_touch_action_value(TokenStream<ComponentValue>&);
|
||||
|
||||
RefPtr<CSSStyleValue const> parse_list_of_time_values(PropertyID, TokenStream<ComponentValue>&);
|
||||
|
||||
|
|
|
@ -664,6 +664,10 @@ Parser::ParseErrorOr<NonnullRefPtr<CSSStyleValue const>> Parser::parse_css_value
|
|||
if (auto parsed_value = parse_shadow_value(tokens, AllowInsetKeyword::No); parsed_value && !tokens.has_next_token())
|
||||
return parsed_value.release_nonnull();
|
||||
return ParseError::SyntaxError;
|
||||
case PropertyID::TouchAction:
|
||||
if (auto parsed_value = parse_touch_action_value(tokens); parsed_value && !tokens.has_next_token())
|
||||
return parsed_value.release_nonnull();
|
||||
return ParseError::SyntaxError;
|
||||
case PropertyID::Transform:
|
||||
if (auto parsed_value = parse_transform_value(tokens); parsed_value && !tokens.has_next_token())
|
||||
return parsed_value.release_nonnull();
|
||||
|
@ -3528,6 +3532,67 @@ RefPtr<CSSStyleValue const> Parser::parse_text_decoration_line_value(TokenStream
|
|||
return StyleValueList::create(move(style_values), StyleValueList::Separator::Space);
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/pointerevents/#the-touch-action-css-property
|
||||
RefPtr<CSSStyleValue const> Parser::parse_touch_action_value(TokenStream<ComponentValue>& tokens)
|
||||
{
|
||||
// auto | none | [ [ pan-x | pan-left | pan-right ] || [ pan-y | pan-up | pan-down ] ] | manipulation
|
||||
|
||||
if (auto value = parse_all_as_single_keyword_value(tokens, Keyword::Auto))
|
||||
return value;
|
||||
if (auto value = parse_all_as_single_keyword_value(tokens, Keyword::None))
|
||||
return value;
|
||||
if (auto value = parse_all_as_single_keyword_value(tokens, Keyword::Manipulation))
|
||||
return value;
|
||||
|
||||
StyleValueVector parsed_values;
|
||||
auto transaction = tokens.begin_transaction();
|
||||
|
||||
// We will verify that we have up to one vertical and one horizontal value
|
||||
bool has_horizontal = false;
|
||||
bool has_vertical = false;
|
||||
|
||||
// Were the values specified in y/x order? (we need to store them in canonical x/y order)
|
||||
bool swap_order = false;
|
||||
|
||||
while (auto parsed_value = parse_css_value_for_property(PropertyID::TouchAction, tokens)) {
|
||||
switch (parsed_value->as_keyword().keyword()) {
|
||||
case Keyword::PanX:
|
||||
case Keyword::PanLeft:
|
||||
case Keyword::PanRight:
|
||||
if (has_horizontal)
|
||||
return {};
|
||||
if (has_vertical)
|
||||
swap_order = true;
|
||||
has_horizontal = true;
|
||||
break;
|
||||
case Keyword::PanY:
|
||||
case Keyword::PanUp:
|
||||
case Keyword::PanDown:
|
||||
if (has_vertical)
|
||||
return {};
|
||||
has_vertical = true;
|
||||
break;
|
||||
case Keyword::Auto:
|
||||
case Keyword::None:
|
||||
case Keyword::Manipulation:
|
||||
// Not valid as part of a list
|
||||
return {};
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
parsed_values.append(parsed_value.release_nonnull());
|
||||
if (!tokens.has_next_token())
|
||||
break;
|
||||
}
|
||||
|
||||
if (swap_order)
|
||||
swap(parsed_values[0], parsed_values[1]);
|
||||
|
||||
transaction.commit();
|
||||
return StyleValueList::create(move(parsed_values), StyleValueList::Separator::Space);
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/css-transforms-1/#transform-property
|
||||
RefPtr<CSSStyleValue const> Parser::parse_transform_value(TokenStream<ComponentValue>& tokens)
|
||||
{
|
||||
|
|
|
@ -2954,6 +2954,15 @@
|
|||
"unitless-length"
|
||||
]
|
||||
},
|
||||
"touch-action": {
|
||||
"animation-type": "discrete",
|
||||
"inherited": false,
|
||||
"initial": "auto",
|
||||
"max-values": 2,
|
||||
"valid-types": [
|
||||
"touch-action"
|
||||
]
|
||||
},
|
||||
"transform": {
|
||||
"animation-type": "custom",
|
||||
"inherited": false,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue