|
7 | 7 |
|
8 | 8 | #include "ShorthandStyleValue.h" |
9 | 9 | #include <LibGfx/Font/FontWeight.h> |
| 10 | +#include <LibWeb/CSS/Parser/Parser.h> |
10 | 11 | #include <LibWeb/CSS/PropertyID.h> |
11 | 12 | #include <LibWeb/CSS/StyleComputer.h> |
12 | 13 | #include <LibWeb/CSS/StyleValues/BorderRadiusStyleValue.h> |
@@ -69,6 +70,74 @@ String ShorthandStyleValue::to_string(SerializationMode mode) const |
69 | 70 | return ""_string; |
70 | 71 | } |
71 | 72 |
|
| 73 | + // FIXME: This is required as parse_comma_separated_value_list() returns a single value directly instead of a list if there's only one. |
| 74 | + auto const style_value_as_value_list = [&](RefPtr<StyleValue const> value) -> StyleValueVector { |
| 75 | + if (value->is_value_list()) |
| 76 | + return value->as_value_list().values(); |
| 77 | + |
| 78 | + return { value.release_nonnull() }; |
| 79 | + }; |
| 80 | + |
| 81 | + auto const coordinating_value_list_shorthand_to_string = [&](StringView entry_when_all_longhands_initial) { |
| 82 | + auto entry_count = style_value_as_value_list(longhand(m_properties.sub_properties[0])).size(); |
| 83 | + |
| 84 | + // If we don't have the same number of values for each longhand, we can't serialize this shorthand. |
| 85 | + if (any_of(m_properties.sub_properties, [&](auto longhand_id) { return style_value_as_value_list(longhand(longhand_id)).size() != entry_count; })) |
| 86 | + return ""_string; |
| 87 | + |
| 88 | + // We should serialize a longhand if: |
| 89 | + // - The value is not the initial value |
| 90 | + // - Another longhand value which will be included later in the serialization is valid for this longhand. |
| 91 | + auto should_serialize_longhand = [&](size_t entry_index, size_t longhand_index) { |
| 92 | + auto longhand_id = m_properties.sub_properties[longhand_index]; |
| 93 | + auto longhand_value = style_value_as_value_list(longhand(longhand_id))[entry_index]; |
| 94 | + |
| 95 | + if (!longhand_value->equals(style_value_as_value_list(property_initial_value(longhand_id))[0])) |
| 96 | + return true; |
| 97 | + |
| 98 | + for (size_t other_longhand_index = longhand_index + 1; other_longhand_index < m_properties.sub_properties.size(); other_longhand_index++) { |
| 99 | + auto other_longhand_id = m_properties.sub_properties[other_longhand_index]; |
| 100 | + auto other_longhand_value = style_value_as_value_list(longhand(other_longhand_id))[entry_index]; |
| 101 | + |
| 102 | + // FIXME: This should really account for the other longhand being included in the serialization for any reason, not just because it is not the initial value. |
| 103 | + if (other_longhand_value->equals(style_value_as_value_list(property_initial_value(other_longhand_id))[0])) |
| 104 | + continue; |
| 105 | + |
| 106 | + if (parse_css_value(Parser::ParsingParams {}, other_longhand_value->to_string(mode), longhand_id)) |
| 107 | + return true; |
| 108 | + } |
| 109 | + |
| 110 | + return false; |
| 111 | + }; |
| 112 | + |
| 113 | + StringBuilder builder; |
| 114 | + for (size_t entry_index = 0; entry_index < entry_count; entry_index++) { |
| 115 | + bool first = true; |
| 116 | + |
| 117 | + for (size_t longhand_index = 0; longhand_index < m_properties.sub_properties.size(); longhand_index++) { |
| 118 | + auto longhand_id = m_properties.sub_properties[longhand_index]; |
| 119 | + auto longhand_value = style_value_as_value_list(longhand(longhand_id))[entry_index]; |
| 120 | + |
| 121 | + if (!should_serialize_longhand(entry_index, longhand_index)) |
| 122 | + continue; |
| 123 | + |
| 124 | + if (!builder.is_empty() && !first) |
| 125 | + builder.append(' '); |
| 126 | + |
| 127 | + builder.append(longhand_value->to_string(mode)); |
| 128 | + first = false; |
| 129 | + } |
| 130 | + |
| 131 | + if (first) |
| 132 | + builder.append(entry_when_all_longhands_initial); |
| 133 | + |
| 134 | + if (entry_index != entry_count - 1) |
| 135 | + builder.append(", "sv); |
| 136 | + } |
| 137 | + |
| 138 | + return builder.to_string_without_validation(); |
| 139 | + }; |
| 140 | + |
72 | 141 | auto positional_value_list_shorthand_to_string = [&](Vector<ValueComparingNonnullRefPtr<StyleValue const>> values) -> String { |
73 | 142 | switch (values.size()) { |
74 | 143 | case 2: { |
@@ -141,79 +210,8 @@ String ShorthandStyleValue::to_string(SerializationMode mode) const |
141 | 210 | // handled above, thus, if we get to here that mustn't be the case and we should return the empty string. |
142 | 211 | return ""_string; |
143 | 212 | } |
144 | | - case PropertyID::Animation: { |
145 | | - auto const get_longhand_as_vector = [&](PropertyID longhand_id) -> StyleValueVector { |
146 | | - auto value = longhand(longhand_id); |
147 | | - |
148 | | - if (value->is_value_list()) |
149 | | - return value->as_value_list().values(); |
150 | | - |
151 | | - // FIXME: This is required as parse_comma_separated_value_list() returns a single value directly instead of a list if there's only one. |
152 | | - return { value.release_nonnull() }; |
153 | | - }; |
154 | | - |
155 | | - // If we don't have the same number of values for each longhand, we can't serialize this shorthand. |
156 | | - if (any_of(m_properties.sub_properties, [&](auto longhand_id) { return get_longhand_as_vector(longhand_id).size() != get_longhand_as_vector(m_properties.sub_properties[0]).size(); })) |
157 | | - return ""_string; |
158 | | - |
159 | | - StringBuilder builder; |
160 | | - for (size_t i = 0; i < get_longhand_as_vector(m_properties.sub_properties[0]).size(); i++) { |
161 | | - auto animation_name = get_longhand_as_vector(PropertyID::AnimationName)[i]->to_string(mode); |
162 | | - bool first = true; |
163 | | - |
164 | | - for (auto longhand_id : m_properties.sub_properties) { |
165 | | - auto longhand_value = get_longhand_as_vector(longhand_id)[i]; |
166 | | - |
167 | | - bool should_serialize_longhand = [&]() { |
168 | | - if (!longhand_value->equals(property_initial_value(longhand_id))) |
169 | | - return true; |
170 | | - |
171 | | - if (longhand_id == PropertyID::AnimationDuration && !get_longhand_as_vector(PropertyID::AnimationDelay)[i]->equals(property_initial_value(PropertyID::AnimationDelay))) |
172 | | - return true; |
173 | | - |
174 | | - auto animation_name_keyword = keyword_from_string(animation_name); |
175 | | - |
176 | | - if (!animation_name_keyword.has_value() || animation_name_keyword == Keyword::None) |
177 | | - return false; |
178 | | - |
179 | | - // https://drafts.csswg.org/css-animations-1/#animation |
180 | | - // Furthermore, when serializing, default values of other properties must be output in at least the |
181 | | - // cases necessary to distinguish an animation-name that could be a value of another property |
182 | | - if (longhand_id == PropertyID::AnimationTimingFunction && animation_name.bytes_as_string_view().is_one_of_ignoring_ascii_case("linear"sv, "ease"sv, "ease-in"sv, "ease-out"sv, "ease-in-out"sv, "step-start"sv, "step-end"sv)) |
183 | | - return true; |
184 | | - |
185 | | - if (longhand_id == PropertyID::AnimationDirection && keyword_to_animation_direction(animation_name_keyword.value()).has_value()) |
186 | | - return true; |
187 | | - |
188 | | - if (longhand_id == PropertyID::AnimationFillMode && keyword_to_animation_fill_mode(animation_name_keyword.value()).has_value()) |
189 | | - return true; |
190 | | - |
191 | | - if (longhand_id == PropertyID::AnimationPlayState && keyword_to_animation_play_state(animation_name_keyword.value()).has_value()) |
192 | | - return true; |
193 | | - |
194 | | - return false; |
195 | | - }(); |
196 | | - |
197 | | - if (!should_serialize_longhand) |
198 | | - continue; |
199 | | - |
200 | | - if (!builder.is_empty() && !first) |
201 | | - builder.append(' '); |
202 | | - |
203 | | - builder.append(longhand_value->to_string(mode)); |
204 | | - first = false; |
205 | | - } |
206 | | - |
207 | | - if (first) { |
208 | | - builder.append("none"sv); |
209 | | - } |
210 | | - |
211 | | - if (i != get_longhand_as_vector(m_properties.sub_properties[0]).size() - 1) |
212 | | - builder.append(", "sv); |
213 | | - } |
214 | | - |
215 | | - return builder.to_string_without_validation(); |
216 | | - } |
| 213 | + case PropertyID::Animation: |
| 214 | + return coordinating_value_list_shorthand_to_string("none"sv); |
217 | 215 | case PropertyID::Background: { |
218 | 216 | auto color = longhand(PropertyID::BackgroundColor); |
219 | 217 | auto image = longhand(PropertyID::BackgroundImage); |
|
0 commit comments