mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 00:47:34 +00:00
LibWeb: Add transform property to the system
This patch adds parsing support as well as all the needed stuctures all over LibWeb to pass Transformations around.
This commit is contained in:
parent
74b88a8156
commit
9ebfafafbe
8 changed files with 133 additions and 0 deletions
|
@ -41,6 +41,11 @@ public:
|
||||||
float width { 0 };
|
float width { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Transformation {
|
||||||
|
CSS::TransformFunction function;
|
||||||
|
Vector<Variant<CSS::Length, float>> values;
|
||||||
|
};
|
||||||
|
|
||||||
struct FlexBasisData {
|
struct FlexBasisData {
|
||||||
CSS::FlexBasis type { CSS::FlexBasis::Auto };
|
CSS::FlexBasis type { CSS::FlexBasis::Auto };
|
||||||
CSS::Length length {};
|
CSS::Length length {};
|
||||||
|
@ -109,6 +114,8 @@ public:
|
||||||
Optional<Color> stroke() const { return m_inherited.stroke; }
|
Optional<Color> stroke() const { return m_inherited.stroke; }
|
||||||
Optional<Length> const& stroke_width() const { return m_inherited.stroke_width; }
|
Optional<Length> const& stroke_width() const { return m_inherited.stroke_width; }
|
||||||
|
|
||||||
|
Vector<CSS::Transformation> transformations() const { return m_noninherited.transformations; }
|
||||||
|
|
||||||
ComputedValues clone_inherited_values() const
|
ComputedValues clone_inherited_values() const
|
||||||
{
|
{
|
||||||
ComputedValues clone;
|
ComputedValues clone;
|
||||||
|
@ -168,6 +175,7 @@ protected:
|
||||||
CSS::Overflow overflow_y { InitialValues::overflow() };
|
CSS::Overflow overflow_y { InitialValues::overflow() };
|
||||||
Optional<float> opacity;
|
Optional<float> opacity;
|
||||||
Optional<BoxShadowData> box_shadow {};
|
Optional<BoxShadowData> box_shadow {};
|
||||||
|
Vector<CSS::Transformation> transformations {};
|
||||||
} m_noninherited;
|
} m_noninherited;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -219,6 +227,7 @@ public:
|
||||||
void set_opacity(Optional<float> value) { m_noninherited.opacity = value; }
|
void set_opacity(Optional<float> value) { m_noninherited.opacity = value; }
|
||||||
void set_justify_content(CSS::JustifyContent value) { m_noninherited.justify_content = value; }
|
void set_justify_content(CSS::JustifyContent value) { m_noninherited.justify_content = value; }
|
||||||
void set_box_shadow(Optional<BoxShadowData> value) { m_noninherited.box_shadow = move(value); }
|
void set_box_shadow(Optional<BoxShadowData> value) { m_noninherited.box_shadow = move(value); }
|
||||||
|
void set_transformations(Vector<CSS::Transformation> value) { m_noninherited.transformations = move(value); }
|
||||||
|
|
||||||
void set_fill(Color value) { m_inherited.fill = value; }
|
void set_fill(Color value) { m_inherited.fill = value; }
|
||||||
void set_stroke(Color value) { m_inherited.stroke = value; }
|
void set_stroke(Color value) { m_inherited.stroke = value; }
|
||||||
|
|
|
@ -2788,6 +2788,45 @@ RefPtr<StyleValue> Parser::parse_text_decoration_value(ParsingContext const& con
|
||||||
return TextDecorationStyleValue::create(decoration_line.release_nonnull(), decoration_style.release_nonnull(), decoration_color.release_nonnull());
|
return TextDecorationStyleValue::create(decoration_line.release_nonnull(), decoration_style.release_nonnull(), decoration_color.release_nonnull());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Optional<CSS::TransformFunction> parse_transform_function_name(StringView name)
|
||||||
|
{
|
||||||
|
if (name == "translateY")
|
||||||
|
return CSS::TransformFunction::TranslateY;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
RefPtr<StyleValue> Parser::parse_transform_value(ParsingContext const& context, Vector<StyleComponentValueRule> const& component_values)
|
||||||
|
{
|
||||||
|
NonnullRefPtrVector<StyleValue> transformations;
|
||||||
|
|
||||||
|
for (auto& part : component_values) {
|
||||||
|
if (!part.is_function())
|
||||||
|
return nullptr;
|
||||||
|
auto maybe_function = parse_transform_function_name(part.function().name());
|
||||||
|
if (!maybe_function.has_value())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
NonnullRefPtrVector<StyleValue> values;
|
||||||
|
for (auto& value : part.function().values()) {
|
||||||
|
if (value.is(Token::Type::Dimension)) {
|
||||||
|
auto maybe_length = parse_length(context, value);
|
||||||
|
if (!maybe_length.has_value())
|
||||||
|
return nullptr;
|
||||||
|
values.append(LengthStyleValue::create(maybe_length.release_value()));
|
||||||
|
} else if (value.is(Token::Type::Number)) {
|
||||||
|
auto number = parse_numeric_value(context, value);
|
||||||
|
values.append(number.release_nonnull());
|
||||||
|
} else {
|
||||||
|
dbgln("FIXME: Unsupported value type for transformation!");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
transformations.append(TransformationStyleValue::create(maybe_function.value(), move(values)));
|
||||||
|
}
|
||||||
|
return StyleValueList::create(move(transformations));
|
||||||
|
}
|
||||||
|
|
||||||
RefPtr<StyleValue> Parser::parse_as_css_value(PropertyID property_id)
|
RefPtr<StyleValue> Parser::parse_as_css_value(PropertyID property_id)
|
||||||
{
|
{
|
||||||
auto component_values = parse_as_list_of_component_values();
|
auto component_values = parse_as_list_of_component_values();
|
||||||
|
@ -2893,6 +2932,10 @@ Result<NonnullRefPtr<StyleValue>, Parser::ParsingResult> Parser::parse_css_value
|
||||||
if (auto parsed_value = parse_text_decoration_value(m_context, component_values))
|
if (auto parsed_value = parse_text_decoration_value(m_context, component_values))
|
||||||
return parsed_value.release_nonnull();
|
return parsed_value.release_nonnull();
|
||||||
break;
|
break;
|
||||||
|
case PropertyID::Transform:
|
||||||
|
if (auto parsed_value = parse_transform_value(m_context, component_values))
|
||||||
|
return parsed_value.release_nonnull();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -198,6 +198,7 @@ private:
|
||||||
static RefPtr<StyleValue> parse_list_style_value(ParsingContext const&, Vector<StyleComponentValueRule> const&);
|
static RefPtr<StyleValue> parse_list_style_value(ParsingContext const&, Vector<StyleComponentValueRule> const&);
|
||||||
static RefPtr<StyleValue> parse_overflow_value(ParsingContext const&, Vector<StyleComponentValueRule> const&);
|
static RefPtr<StyleValue> parse_overflow_value(ParsingContext const&, Vector<StyleComponentValueRule> const&);
|
||||||
static RefPtr<StyleValue> parse_text_decoration_value(ParsingContext const&, Vector<StyleComponentValueRule> const&);
|
static RefPtr<StyleValue> parse_text_decoration_value(ParsingContext const&, Vector<StyleComponentValueRule> const&);
|
||||||
|
static RefPtr<StyleValue> parse_transform_value(ParsingContext const&, Vector<StyleComponentValueRule> const&);
|
||||||
|
|
||||||
// calc() parsing, according to https://www.w3.org/TR/css-values-3/#calc-syntax
|
// calc() parsing, according to https://www.w3.org/TR/css-values-3/#calc-syntax
|
||||||
static OwnPtr<CalculatedStyleValue::CalcSum> parse_calc_sum(ParsingContext const&, TokenStream<StyleComponentValueRule>&);
|
static OwnPtr<CalculatedStyleValue::CalcSum> parse_calc_sum(ParsingContext const&, TokenStream<StyleComponentValueRule>&);
|
||||||
|
|
|
@ -605,6 +605,10 @@
|
||||||
"unitless-length"
|
"unitless-length"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"transform": {
|
||||||
|
"inherited": false,
|
||||||
|
"initial": "none"
|
||||||
|
},
|
||||||
"user-select": {
|
"user-select": {
|
||||||
"inherited": false,
|
"inherited": false,
|
||||||
"initial": "auto"
|
"initial": "auto"
|
||||||
|
|
|
@ -424,6 +424,44 @@ Optional<CSS::JustifyContent> StyleProperties::justify_content() const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector<CSS::Transformation> StyleProperties::transformations() const
|
||||||
|
{
|
||||||
|
auto value = property(CSS::PropertyID::Transform);
|
||||||
|
if (!value.has_value())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (value.value()->is_identifier() && value.value()->to_identifier() == CSS::ValueID::None)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (!value.value()->is_value_list())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto& list = static_cast<const StyleValueList&>(*value.value());
|
||||||
|
|
||||||
|
Vector<CSS::Transformation> transformations;
|
||||||
|
|
||||||
|
for (auto& it : list.values()) {
|
||||||
|
if (!it.is_transformation())
|
||||||
|
return {};
|
||||||
|
auto& transformation_style_value = static_cast<TransformationStyleValue const&>(it);
|
||||||
|
CSS::Transformation transformation;
|
||||||
|
transformation.function = transformation_style_value.transform_function();
|
||||||
|
Vector<Variant<CSS::Length, float>> values;
|
||||||
|
for (auto& transformation_value : transformation_style_value.values()) {
|
||||||
|
if (transformation_value.is_length()) {
|
||||||
|
values.append({ transformation_value.to_length() });
|
||||||
|
} else if (transformation_value.is_numeric()) {
|
||||||
|
values.append({ static_cast<NumericStyleValue const&>(transformation_value).value() });
|
||||||
|
} else {
|
||||||
|
dbgln("FIXME: Unsupported value in transform!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
transformation.values = move(values);
|
||||||
|
transformations.append(move(transformation));
|
||||||
|
}
|
||||||
|
return transformations;
|
||||||
|
}
|
||||||
|
|
||||||
Optional<CSS::AlignItems> StyleProperties::align_items() const
|
Optional<CSS::AlignItems> StyleProperties::align_items() const
|
||||||
{
|
{
|
||||||
auto value = property(CSS::PropertyID::AlignItems);
|
auto value = property(CSS::PropertyID::AlignItems);
|
||||||
|
|
|
@ -64,6 +64,8 @@ public:
|
||||||
Optional<CSS::Repeat> background_repeat_y() const;
|
Optional<CSS::Repeat> background_repeat_y() const;
|
||||||
Optional<CSS::BoxShadowData> box_shadow() const;
|
Optional<CSS::BoxShadowData> box_shadow() const;
|
||||||
|
|
||||||
|
Vector<CSS::Transformation> transformations() const;
|
||||||
|
|
||||||
const Gfx::Font& font(Layout::Node const& node) const
|
const Gfx::Font& font(Layout::Node const& node) const
|
||||||
{
|
{
|
||||||
if (!m_font)
|
if (!m_font)
|
||||||
|
|
|
@ -219,6 +219,10 @@ enum class AlignItems {
|
||||||
Stretch,
|
Stretch,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class TransformFunction {
|
||||||
|
TranslateY,
|
||||||
|
};
|
||||||
|
|
||||||
class StyleValue : public RefCounted<StyleValue> {
|
class StyleValue : public RefCounted<StyleValue> {
|
||||||
public:
|
public:
|
||||||
virtual ~StyleValue();
|
virtual ~StyleValue();
|
||||||
|
@ -249,6 +253,7 @@ public:
|
||||||
ListStyle,
|
ListStyle,
|
||||||
Overflow,
|
Overflow,
|
||||||
TextDecoration,
|
TextDecoration,
|
||||||
|
Transformation,
|
||||||
};
|
};
|
||||||
|
|
||||||
Type type() const { return m_type; }
|
Type type() const { return m_type; }
|
||||||
|
@ -276,6 +281,7 @@ public:
|
||||||
bool is_list_style() const { return type() == Type::ListStyle; }
|
bool is_list_style() const { return type() == Type::ListStyle; }
|
||||||
bool is_overflow() const { return type() == Type::Overflow; }
|
bool is_overflow() const { return type() == Type::Overflow; }
|
||||||
bool is_text_decoration() const { return type() == Type::TextDecoration; }
|
bool is_text_decoration() const { return type() == Type::TextDecoration; }
|
||||||
|
bool is_transformation() const { return type() == Type::Transformation; }
|
||||||
|
|
||||||
bool is_builtin() const { return is_inherit() || is_initial() || is_unset(); }
|
bool is_builtin() const { return is_inherit() || is_initial() || is_unset(); }
|
||||||
|
|
||||||
|
@ -1060,6 +1066,34 @@ private:
|
||||||
NonnullRefPtr<StyleValue> m_color;
|
NonnullRefPtr<StyleValue> m_color;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TransformationStyleValue final : public StyleValue {
|
||||||
|
public:
|
||||||
|
static NonnullRefPtr<TransformationStyleValue> create(CSS::TransformFunction transform_function, NonnullRefPtrVector<StyleValue>&& values)
|
||||||
|
{
|
||||||
|
return adopt_ref(*new TransformationStyleValue(transform_function, move(values)));
|
||||||
|
}
|
||||||
|
virtual ~TransformationStyleValue() override { }
|
||||||
|
|
||||||
|
CSS::TransformFunction transform_function() const { return m_transform_function; }
|
||||||
|
NonnullRefPtrVector<StyleValue> values() const { return m_values; }
|
||||||
|
|
||||||
|
virtual String to_string() const override
|
||||||
|
{
|
||||||
|
return String::formatted("TransformationStyleValue");
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TransformationStyleValue(CSS::TransformFunction transform_function, NonnullRefPtrVector<StyleValue>&& values)
|
||||||
|
: StyleValue(Type::Transformation)
|
||||||
|
, m_transform_function(transform_function)
|
||||||
|
, m_values(move(values))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CSS::TransformFunction m_transform_function;
|
||||||
|
NonnullRefPtrVector<StyleValue> m_values;
|
||||||
|
};
|
||||||
|
|
||||||
class StyleValueList final : public StyleValue {
|
class StyleValueList final : public StyleValue {
|
||||||
public:
|
public:
|
||||||
static NonnullRefPtr<StyleValueList> create(NonnullRefPtrVector<StyleValue>&& values) { return adopt_ref(*new StyleValueList(move(values))); }
|
static NonnullRefPtr<StyleValueList> create(NonnullRefPtrVector<StyleValue>&& values) { return adopt_ref(*new StyleValueList(move(values))); }
|
||||||
|
|
|
@ -347,6 +347,8 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& specified_style)
|
||||||
|
|
||||||
computed_values.set_box_shadow(specified_style.box_shadow());
|
computed_values.set_box_shadow(specified_style.box_shadow());
|
||||||
|
|
||||||
|
computed_values.set_transformations(specified_style.transformations());
|
||||||
|
|
||||||
auto do_border_style = [&](CSS::BorderData& border, CSS::PropertyID width_property, CSS::PropertyID color_property, CSS::PropertyID style_property) {
|
auto do_border_style = [&](CSS::BorderData& border, CSS::PropertyID width_property, CSS::PropertyID color_property, CSS::PropertyID style_property) {
|
||||||
// FIXME: The default border color value is `currentcolor`, but since we can't resolve that easily,
|
// FIXME: The default border color value is `currentcolor`, but since we can't resolve that easily,
|
||||||
// we just manually grab the value from `color`. This makes it dependent on `color` being
|
// we just manually grab the value from `color`. This makes it dependent on `color` being
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue