mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 18:27:35 +00:00
LibWeb: Implement and use FlexStyleValue
This is not just moving the code from StyleResolver to Parser. The logic has changed to allow for the `flex-basis` to come before or after the `flex-grow/shrink` values, as well as handle the special one-value cases. Also added test cases to flex.html to check the parsing. It does parse correctly, but elements with `flex-basis: auto` do not calculate their width correctly.
This commit is contained in:
parent
44a082391b
commit
2644d2c221
5 changed files with 208 additions and 77 deletions
|
@ -154,6 +154,68 @@
|
|||
<div class="box" style="flex-shrink: 1;">2 I shrink</div>
|
||||
<div class="box" style="flex-shrink: 0;">3 I don't</div>
|
||||
</div>
|
||||
|
||||
<h2>Flex shorthand</h2>
|
||||
<p>flex: initial;</p>
|
||||
<div class="my-container" style="width: 500px;">
|
||||
<div class="box" style="flex: initial;">1</div>
|
||||
<div class="box" style="flex: initial;">2</div>
|
||||
<div class="box" style="flex: initial;">3</div>
|
||||
</div>
|
||||
<p>flex: auto;</p>
|
||||
<div class="my-container" style="width: 500px;">
|
||||
<div class="box" style="flex: auto;">1</div>
|
||||
<div class="box" style="flex: auto;">2</div>
|
||||
<div class="box" style="flex: auto;">3</div>
|
||||
</div>
|
||||
<p>flex: none;</p>
|
||||
<div class="my-container" style="width: 500px;">
|
||||
<div class="box" style="flex: none;">1</div>
|
||||
<div class="box" style="flex: none;">2</div>
|
||||
<div class="box" style="flex: none;">3</div>
|
||||
</div>
|
||||
<p>flex: 1/2/3;</p>
|
||||
<div class="my-container" style="width: 500px;">
|
||||
<div class="box" style="flex: 1;">1</div>
|
||||
<div class="box" style="flex: 2;">2</div>
|
||||
<div class="box" style="flex: 3;">3</div>
|
||||
</div>
|
||||
<p>flex: 0 0 0;</p>
|
||||
<div class="my-container" style="width: 500px;">
|
||||
<div class="box" style="flex: 0 0 0;">1</div>
|
||||
<div class="box" style="flex: 0 0 0;">2</div>
|
||||
<div class="box" style="flex: 0 0 0;">3</div>
|
||||
</div>
|
||||
<p>flex: 1 2 0;</p>
|
||||
<div class="my-container" style="width: 500px;">
|
||||
<div class="box" style="flex: 1 2 0;">1</div>
|
||||
<div class="box" style="flex: 1 2 0;">2</div>
|
||||
<div class="box" style="flex: 1 2 0;">3</div>
|
||||
</div>
|
||||
<p>flex: 0 1 2; <span style="color: red;">(Invalid)</span></p>
|
||||
<div class="my-container" style="width: 500px;">
|
||||
<div class="box" style="flex: 0 1 2;">1</div>
|
||||
<div class="box" style="flex: 0 1 2;">2</div>
|
||||
<div class="box" style="flex: 0 1 2;">3</div>
|
||||
</div>
|
||||
<p>flex: 4/1/0 0 50px;</p>
|
||||
<div class="my-container" style="width: 500px;">
|
||||
<div class="box" style="flex: 4 0 50px;">1</div>
|
||||
<div class="box" style="flex: 1 0 50px;">2</div>
|
||||
<div class="box" style="flex: 0 0 50px;">3</div>
|
||||
</div>
|
||||
<p>flex: 80% 0 4/1/0;</p>
|
||||
<div class="my-container" style="width: 500px;">
|
||||
<div class="box" style="flex: 80% 0 4;">1</div>
|
||||
<div class="box" style="flex: 80% 0 1;">2</div>
|
||||
<div class="box" style="flex: 80% 0 0;">3</div>
|
||||
</div>
|
||||
<p>flex: auto 0 4/1/0;</p>
|
||||
<div class="my-container" style="width: 500px;">
|
||||
<div class="box" style="flex: auto 0 4;">1</div>
|
||||
<div class="box" style="flex: auto 0 1;">2</div>
|
||||
<div class="box" style="flex: auto 0 0;">3</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
|
@ -1889,6 +1889,98 @@ RefPtr<StyleValue> Parser::parse_box_shadow_value(ParsingContext const& context,
|
|||
return BoxShadowStyleValue::create(offset_x, offset_y, blur_radius, color);
|
||||
}
|
||||
|
||||
RefPtr<StyleValue> Parser::parse_flex_value(ParsingContext const& context, Vector<StyleComponentValueRule> const& component_values)
|
||||
{
|
||||
auto is_flex_grow_or_shrink = [](StyleValue const& value) -> bool {
|
||||
if (value.is_numeric())
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
auto is_flex_basis = [](StyleValue const& value) -> bool {
|
||||
if (value.is_length())
|
||||
return true;
|
||||
switch (value.to_identifier()) {
|
||||
case ValueID::Auto:
|
||||
case ValueID::Content:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
if (component_values.size() == 1) {
|
||||
auto value = parse_css_value(context, PropertyID::Flex, component_values[0]);
|
||||
if (!value)
|
||||
return nullptr;
|
||||
|
||||
switch (value->to_identifier()) {
|
||||
case ValueID::Auto: {
|
||||
auto one = NumericStyleValue::create(1);
|
||||
return FlexStyleValue::create(one, one, IdentifierStyleValue::create(ValueID::Auto));
|
||||
}
|
||||
case ValueID::None: {
|
||||
auto zero = NumericStyleValue::create(0);
|
||||
return FlexStyleValue::create(zero, zero, IdentifierStyleValue::create(ValueID::Auto));
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<StyleValue> flex_grow;
|
||||
RefPtr<StyleValue> flex_shrink;
|
||||
RefPtr<StyleValue> flex_basis;
|
||||
|
||||
for (size_t i = 0; i < component_values.size(); ++i) {
|
||||
auto value = parse_css_value(context, PropertyID::Flex, component_values[i]);
|
||||
if (!value)
|
||||
return nullptr;
|
||||
|
||||
// Zero is a valid value for basis, but only if grow and shrink are already specified.
|
||||
if (value->is_numeric() && static_cast<NumericStyleValue&>(*value).value() == 0) {
|
||||
if (flex_grow && flex_shrink && !flex_basis) {
|
||||
flex_basis = LengthStyleValue::create(Length(0, Length::Type::Px));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_flex_grow_or_shrink(*value)) {
|
||||
if (flex_grow)
|
||||
return nullptr;
|
||||
flex_grow = value.release_nonnull();
|
||||
|
||||
// Flex-shrink may optionally follow directly after.
|
||||
if (i + 1 < component_values.size()) {
|
||||
auto second_value = parse_css_value(context, PropertyID::Flex, component_values[i + 1]);
|
||||
if (second_value && is_flex_grow_or_shrink(*second_value)) {
|
||||
flex_shrink = second_value.release_nonnull();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_flex_basis(*value)) {
|
||||
if (flex_basis)
|
||||
return nullptr;
|
||||
flex_basis = value.release_nonnull();
|
||||
continue;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!flex_grow)
|
||||
flex_grow = NumericStyleValue::create(0);
|
||||
if (!flex_shrink)
|
||||
flex_shrink = NumericStyleValue::create(1);
|
||||
if (!flex_basis)
|
||||
flex_basis = IdentifierStyleValue::create(ValueID::Auto);
|
||||
|
||||
return FlexStyleValue::create(flex_grow.release_nonnull(), flex_shrink.release_nonnull(), flex_basis.release_nonnull());
|
||||
}
|
||||
|
||||
RefPtr<StyleValue> Parser::parse_font_value(ParsingContext const& context, Vector<StyleComponentValueRule> const& component_values)
|
||||
{
|
||||
auto is_font_size = [](StyleValue const& value) -> bool {
|
||||
|
@ -2285,6 +2377,10 @@ RefPtr<StyleValue> Parser::parse_css_value(PropertyID property_id, TokenStream<S
|
|||
if (auto parsed_box_shadow = parse_box_shadow_value(m_context, component_values))
|
||||
return parsed_box_shadow;
|
||||
break;
|
||||
case PropertyID::Flex:
|
||||
if (auto parsed_value = parse_flex_value(m_context, component_values))
|
||||
return parsed_value;
|
||||
break;
|
||||
case PropertyID::Font:
|
||||
if (auto parsed_value = parse_font_value(m_context, component_values))
|
||||
return parsed_value;
|
||||
|
|
|
@ -177,6 +177,7 @@ private:
|
|||
static RefPtr<StyleValue> parse_image_value(ParsingContext const&, StyleComponentValueRule const&);
|
||||
static RefPtr<StyleValue> parse_background_value(ParsingContext const&, Vector<StyleComponentValueRule> const&);
|
||||
static RefPtr<StyleValue> parse_box_shadow_value(ParsingContext const&, Vector<StyleComponentValueRule> const&);
|
||||
static RefPtr<StyleValue> parse_flex_value(ParsingContext const&, Vector<StyleComponentValueRule> const&);
|
||||
static RefPtr<StyleValue> parse_font_value(ParsingContext const&, Vector<StyleComponentValueRule> const&);
|
||||
static RefPtr<StyleValue> parse_list_style_value(ParsingContext const&, Vector<StyleComponentValueRule> const&);
|
||||
static RefPtr<StyleValue> parse_text_decoration_value(ParsingContext const&, Vector<StyleComponentValueRule> const&);
|
||||
|
|
|
@ -250,31 +250,6 @@ static inline bool is_flex_wrap(StyleValue const& value)
|
|||
}
|
||||
}
|
||||
|
||||
static inline bool is_flex_grow_or_shrink(StyleValue const& value)
|
||||
{
|
||||
if (value.is_builtin_or_dynamic())
|
||||
return true;
|
||||
|
||||
if (value.is_numeric())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool is_flex_basis(StyleValue const& value)
|
||||
{
|
||||
if (value.is_builtin_or_dynamic())
|
||||
return true;
|
||||
|
||||
if (value.is_length())
|
||||
return true;
|
||||
|
||||
if (value.is_identifier() && value.to_identifier() == ValueID::Content)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool is_font_family(StyleValue const& value)
|
||||
{
|
||||
if (value.is_builtin_or_dynamic())
|
||||
|
@ -801,61 +776,19 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope
|
|||
}
|
||||
|
||||
if (property_id == CSS::PropertyID::Flex) {
|
||||
if (value.is_length() || (value.is_identifier() && value.to_identifier() == CSS::ValueID::Content)) {
|
||||
if (value.is_flex()) {
|
||||
auto& flex = static_cast<CSS::FlexStyleValue const&>(value);
|
||||
style.set_property(CSS::PropertyID::FlexGrow, flex.grow());
|
||||
style.set_property(CSS::PropertyID::FlexShrink, flex.shrink());
|
||||
style.set_property(CSS::PropertyID::FlexBasis, flex.basis());
|
||||
return;
|
||||
}
|
||||
if (value.is_builtin()) {
|
||||
style.set_property(CSS::PropertyID::FlexGrow, value);
|
||||
style.set_property(CSS::PropertyID::FlexShrink, value);
|
||||
style.set_property(CSS::PropertyID::FlexBasis, value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (value.is_component_value_list()) {
|
||||
auto parts = static_cast<CSS::ValueListStyleValue const&>(value).values();
|
||||
if (parts.size() == 1) {
|
||||
auto value = Parser::parse_css_value(context, property_id, parts[0]);
|
||||
if (!value)
|
||||
return;
|
||||
if (is_flex_basis(*value)) {
|
||||
style.set_property(CSS::PropertyID::FlexBasis, *value);
|
||||
} else if (is_flex_grow_or_shrink(*value)) {
|
||||
style.set_property(CSS::PropertyID::FlexGrow, *value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (parts.size() == 2) {
|
||||
auto flex_grow = Parser::parse_css_value(context, property_id, parts[0]);
|
||||
auto second_value = Parser::parse_css_value(context, property_id, parts[1]);
|
||||
if (!flex_grow || !second_value)
|
||||
return;
|
||||
|
||||
style.set_property(CSS::PropertyID::FlexGrow, *flex_grow);
|
||||
|
||||
if (is_flex_basis(*second_value)) {
|
||||
style.set_property(CSS::PropertyID::FlexBasis, *second_value);
|
||||
} else if (is_flex_grow_or_shrink(*second_value)) {
|
||||
style.set_property(CSS::PropertyID::FlexShrink, *second_value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (parts.size() == 3) {
|
||||
auto flex_grow = Parser::parse_css_value(context, property_id, parts[0]);
|
||||
auto flex_shrink = Parser::parse_css_value(context, property_id, parts[1]);
|
||||
auto flex_basis = Parser::parse_css_value(context, property_id, parts[2]);
|
||||
if (!flex_grow || !flex_shrink || !flex_basis)
|
||||
return;
|
||||
|
||||
style.set_property(CSS::PropertyID::FlexGrow, *flex_grow);
|
||||
style.set_property(CSS::PropertyID::FlexShrink, *flex_shrink);
|
||||
|
||||
if (is_flex_basis(*flex_basis))
|
||||
style.set_property(CSS::PropertyID::FlexBasis, *flex_basis);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
dbgln("Unsure what to do with CSS flex value '{}'", value.to_string());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -231,6 +231,7 @@ public:
|
|||
Calculated,
|
||||
Background,
|
||||
BoxShadow,
|
||||
Flex,
|
||||
Font,
|
||||
ListStyle,
|
||||
TextDecoration,
|
||||
|
@ -252,6 +253,7 @@ public:
|
|||
bool is_calculated() const { return type() == Type::Calculated; }
|
||||
bool is_background() const { return type() == Type::Background; }
|
||||
bool is_box_shadow() const { return type() == Type::BoxShadow; }
|
||||
bool is_flex() const { return type() == Type::Flex; }
|
||||
bool is_font() const { return type() == Type::Font; }
|
||||
bool is_list_style() const { return type() == Type::ListStyle; }
|
||||
bool is_text_decoration() const { return type() == Type::TextDecoration; }
|
||||
|
@ -677,6 +679,43 @@ private:
|
|||
// FIXME: background-origin
|
||||
};
|
||||
|
||||
class FlexStyleValue final : public StyleValue {
|
||||
public:
|
||||
static NonnullRefPtr<FlexStyleValue> create(
|
||||
NonnullRefPtr<StyleValue> grow,
|
||||
NonnullRefPtr<StyleValue> shrink,
|
||||
NonnullRefPtr<StyleValue> basis)
|
||||
{
|
||||
return adopt_ref(*new FlexStyleValue(grow, shrink, basis));
|
||||
}
|
||||
virtual ~FlexStyleValue() override { }
|
||||
|
||||
NonnullRefPtr<StyleValue> grow() const { return m_grow; }
|
||||
NonnullRefPtr<StyleValue> shrink() const { return m_shrink; }
|
||||
NonnullRefPtr<StyleValue> basis() const { return m_basis; }
|
||||
|
||||
virtual String to_string() const override
|
||||
{
|
||||
return String::formatted("Flex grow: {}, shrink: {}, basis: {}", m_grow->to_string(), m_shrink->to_string(), m_basis->to_string());
|
||||
}
|
||||
|
||||
private:
|
||||
FlexStyleValue(
|
||||
NonnullRefPtr<StyleValue> grow,
|
||||
NonnullRefPtr<StyleValue> shrink,
|
||||
NonnullRefPtr<StyleValue> basis)
|
||||
: StyleValue(Type::Flex)
|
||||
, m_grow(grow)
|
||||
, m_shrink(shrink)
|
||||
, m_basis(basis)
|
||||
{
|
||||
}
|
||||
|
||||
NonnullRefPtr<StyleValue> m_grow;
|
||||
NonnullRefPtr<StyleValue> m_shrink;
|
||||
NonnullRefPtr<StyleValue> m_basis;
|
||||
};
|
||||
|
||||
class FontStyleValue final : public StyleValue {
|
||||
public:
|
||||
static NonnullRefPtr<FontStyleValue> create(NonnullRefPtr<StyleValue> font_style, NonnullRefPtr<StyleValue> font_weight, NonnullRefPtr<StyleValue> font_size, NonnullRefPtr<StyleValue> line_height, NonnullRefPtrVector<StyleValue>&& font_families) { return adopt_ref(*new FontStyleValue(font_style, font_weight, font_size, line_height, move(font_families))); }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue