| 
									
										
										
										
											2020-01-18 09:38:21 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> | 
					
						
							|  |  |  |  * All rights reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Redistribution and use in source and binary forms, with or without | 
					
						
							|  |  |  |  * modification, are permitted provided that the following conditions are met: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 1. Redistributions of source code must retain the above copyright notice, this | 
					
						
							|  |  |  |  *    list of conditions and the following disclaimer. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 2. Redistributions in binary form must reproduce the above copyright notice, | 
					
						
							|  |  |  |  *    this list of conditions and the following disclaimer in the documentation | 
					
						
							|  |  |  |  *    and/or other materials provided with the distribution. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | 
					
						
							|  |  |  |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
					
						
							|  |  |  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 
					
						
							|  |  |  |  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | 
					
						
							|  |  |  |  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 
					
						
							|  |  |  |  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | 
					
						
							|  |  |  |  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | 
					
						
							|  |  |  |  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 
					
						
							|  |  |  |  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
					
						
							|  |  |  |  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 16:41:30 +02:00
										 |  |  | #include <AK/QuickSort.h>
 | 
					
						
							| 
									
										
										
										
											2020-07-28 19:20:11 +02:00
										 |  |  | #include <LibWeb/CSS/Parser/CSSParser.h>
 | 
					
						
							| 
									
										
										
										
											2020-03-07 10:32:51 +01:00
										 |  |  | #include <LibWeb/CSS/SelectorEngine.h>
 | 
					
						
							|  |  |  | #include <LibWeb/CSS/StyleResolver.h>
 | 
					
						
							|  |  |  | #include <LibWeb/CSS/StyleSheet.h>
 | 
					
						
							|  |  |  | #include <LibWeb/DOM/Document.h>
 | 
					
						
							|  |  |  | #include <LibWeb/DOM/Element.h>
 | 
					
						
							|  |  |  | #include <LibWeb/Dump.h>
 | 
					
						
							| 
									
										
										
										
											2019-11-18 11:49:19 +01:00
										 |  |  | #include <ctype.h>
 | 
					
						
							| 
									
										
										
										
											2019-06-27 20:40:21 +02:00
										 |  |  | #include <stdio.h>
 | 
					
						
							| 
									
										
										
										
											2019-06-27 17:47:59 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-26 20:01:35 +02:00
										 |  |  | namespace Web::CSS { | 
					
						
							| 
									
										
										
										
											2020-03-07 10:27:02 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-26 19:37:56 +02:00
										 |  |  | StyleResolver::StyleResolver(DOM::Document& document) | 
					
						
							| 
									
										
										
										
											2019-06-27 17:47:59 +02:00
										 |  |  |     : m_document(document) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | StyleResolver::~StyleResolver() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 09:01:12 +02:00
										 |  |  | static StyleSheet& default_stylesheet() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     static StyleSheet* sheet; | 
					
						
							|  |  |  |     if (!sheet) { | 
					
						
							|  |  |  |         extern const char default_stylesheet_source[]; | 
					
						
							|  |  |  |         String css = default_stylesheet_source; | 
					
						
							| 
									
										
										
										
											2020-06-28 12:43:22 +02:00
										 |  |  |         sheet = parse_css(CSS::ParsingContext(), css).leak_ref(); | 
					
						
							| 
									
										
										
										
											2019-10-05 09:01:12 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |     return *sheet; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-24 10:33:33 +02:00
										 |  |  | static StyleSheet& quirks_mode_stylesheet() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     static StyleSheet* sheet; | 
					
						
							|  |  |  |     if (!sheet) { | 
					
						
							|  |  |  |         extern const char quirks_mode_stylesheet_source[]; | 
					
						
							|  |  |  |         String css = quirks_mode_stylesheet_source; | 
					
						
							|  |  |  |         sheet = parse_css(CSS::ParsingContext(), css).leak_ref(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return *sheet; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 09:01:12 +02:00
										 |  |  | template<typename Callback> | 
					
						
							|  |  |  | void StyleResolver::for_each_stylesheet(Callback callback) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     callback(default_stylesheet()); | 
					
						
							| 
									
										
										
										
											2020-09-24 10:33:33 +02:00
										 |  |  |     if (document().in_quirks_mode()) | 
					
						
							|  |  |  |         callback(quirks_mode_stylesheet()); | 
					
						
							| 
									
										
										
										
											2020-06-04 16:06:32 +02:00
										 |  |  |     for (auto& sheet : document().style_sheets().sheets()) { | 
					
						
							| 
									
										
										
										
											2019-10-05 09:01:12 +02:00
										 |  |  |         callback(sheet); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-26 19:37:56 +02:00
										 |  |  | Vector<MatchingRule> StyleResolver::collect_matching_rules(const DOM::Element& element) const | 
					
						
							| 
									
										
										
										
											2019-06-27 20:40:21 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-06-13 00:44:26 +02:00
										 |  |  |     Vector<MatchingRule> matching_rules; | 
					
						
							| 
									
										
										
										
											2019-10-05 09:01:12 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-13 00:44:26 +02:00
										 |  |  |     size_t style_sheet_index = 0; | 
					
						
							| 
									
										
										
										
											2019-10-05 09:01:12 +02:00
										 |  |  |     for_each_stylesheet([&](auto& sheet) { | 
					
						
							| 
									
										
										
										
											2020-06-13 00:44:26 +02:00
										 |  |  |         size_t rule_index = 0; | 
					
						
							| 
									
										
										
										
											2019-06-27 20:40:21 +02:00
										 |  |  |         for (auto& rule : sheet.rules()) { | 
					
						
							| 
									
										
										
										
											2020-06-13 00:44:26 +02:00
										 |  |  |             size_t selector_index = 0; | 
					
						
							| 
									
										
										
										
											2019-06-27 20:40:21 +02:00
										 |  |  |             for (auto& selector : rule.selectors()) { | 
					
						
							| 
									
										
										
										
											2019-10-08 15:33:58 +02:00
										 |  |  |                 if (SelectorEngine::matches(selector, element)) { | 
					
						
							| 
									
										
										
										
											2020-06-13 00:44:26 +02:00
										 |  |  |                     matching_rules.append({ rule, style_sheet_index, rule_index, selector_index }); | 
					
						
							| 
									
										
										
										
											2019-06-27 20:40:21 +02:00
										 |  |  |                     break; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2020-06-13 00:44:26 +02:00
										 |  |  |                 ++selector_index; | 
					
						
							| 
									
										
										
										
											2019-06-27 20:40:21 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-06-13 00:44:26 +02:00
										 |  |  |             ++rule_index; | 
					
						
							| 
									
										
										
										
											2019-06-27 20:40:21 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-06-13 00:44:26 +02:00
										 |  |  |         ++style_sheet_index; | 
					
						
							| 
									
										
										
										
											2019-10-05 09:01:12 +02:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-09-25 12:42:10 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-27 20:40:21 +02:00
										 |  |  |     return matching_rules; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 21:31:10 +00:00
										 |  |  | void StyleResolver::sort_matching_rules(Vector<MatchingRule>& matching_rules) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     quick_sort(matching_rules, [&](MatchingRule& a, MatchingRule& b) { | 
					
						
							|  |  |  |         auto& a_selector = a.rule->selectors()[a.selector_index]; | 
					
						
							|  |  |  |         auto& b_selector = b.rule->selectors()[b.selector_index]; | 
					
						
							|  |  |  |         auto a_specificity = a_selector.specificity(); | 
					
						
							|  |  |  |         auto b_specificity = b_selector.specificity(); | 
					
						
							|  |  |  |         if (a_selector.specificity() == b_selector.specificity()) { | 
					
						
							|  |  |  |             if (a.style_sheet_index == b.style_sheet_index) | 
					
						
							|  |  |  |                 return a.rule_index < b.rule_index; | 
					
						
							|  |  |  |             return a.style_sheet_index < b.style_sheet_index; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return a_specificity < b_specificity; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-08 15:34:19 +02:00
										 |  |  | bool StyleResolver::is_inherited_property(CSS::PropertyID property_id) | 
					
						
							| 
									
										
										
										
											2019-10-04 22:52:49 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-10-08 15:34:19 +02:00
										 |  |  |     static HashTable<CSS::PropertyID> inherited_properties; | 
					
						
							| 
									
										
										
										
											2019-10-04 22:52:49 +02:00
										 |  |  |     if (inherited_properties.is_empty()) { | 
					
						
							| 
									
										
										
										
											2019-10-08 15:34:19 +02:00
										 |  |  |         inherited_properties.set(CSS::PropertyID::BorderCollapse); | 
					
						
							|  |  |  |         inherited_properties.set(CSS::PropertyID::BorderSpacing); | 
					
						
							|  |  |  |         inherited_properties.set(CSS::PropertyID::Color); | 
					
						
							|  |  |  |         inherited_properties.set(CSS::PropertyID::FontFamily); | 
					
						
							|  |  |  |         inherited_properties.set(CSS::PropertyID::FontSize); | 
					
						
							|  |  |  |         inherited_properties.set(CSS::PropertyID::FontStyle); | 
					
						
							|  |  |  |         inherited_properties.set(CSS::PropertyID::FontVariant); | 
					
						
							|  |  |  |         inherited_properties.set(CSS::PropertyID::FontWeight); | 
					
						
							|  |  |  |         inherited_properties.set(CSS::PropertyID::LetterSpacing); | 
					
						
							|  |  |  |         inherited_properties.set(CSS::PropertyID::LineHeight); | 
					
						
							|  |  |  |         inherited_properties.set(CSS::PropertyID::ListStyle); | 
					
						
							|  |  |  |         inherited_properties.set(CSS::PropertyID::ListStyleImage); | 
					
						
							|  |  |  |         inherited_properties.set(CSS::PropertyID::ListStylePosition); | 
					
						
							|  |  |  |         inherited_properties.set(CSS::PropertyID::ListStyleType); | 
					
						
							|  |  |  |         inherited_properties.set(CSS::PropertyID::TextAlign); | 
					
						
							|  |  |  |         inherited_properties.set(CSS::PropertyID::TextIndent); | 
					
						
							|  |  |  |         inherited_properties.set(CSS::PropertyID::TextTransform); | 
					
						
							|  |  |  |         inherited_properties.set(CSS::PropertyID::Visibility); | 
					
						
							|  |  |  |         inherited_properties.set(CSS::PropertyID::WhiteSpace); | 
					
						
							|  |  |  |         inherited_properties.set(CSS::PropertyID::WordSpacing); | 
					
						
							| 
									
										
										
										
											2019-10-04 22:52:49 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // FIXME: This property is not supposed to be inherited, but we currently
 | 
					
						
							|  |  |  |         //        rely on inheritance to propagate decorations into line boxes.
 | 
					
						
							| 
									
										
										
										
											2020-12-15 20:48:16 +01:00
										 |  |  |         inherited_properties.set(CSS::PropertyID::TextDecorationLine); | 
					
						
							| 
									
										
										
										
											2019-10-04 22:52:49 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-10-08 15:34:19 +02:00
										 |  |  |     return inherited_properties.contains(property_id); | 
					
						
							| 
									
										
										
										
											2019-10-04 22:52:49 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-18 11:49:19 +01:00
										 |  |  | static Vector<String> split_on_whitespace(const StringView& string) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (string.is_empty()) | 
					
						
							|  |  |  |         return {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Vector<String> v; | 
					
						
							| 
									
										
										
										
											2019-12-09 17:45:40 +01:00
										 |  |  |     size_t substart = 0; | 
					
						
							|  |  |  |     for (size_t i = 0; i < string.length(); ++i) { | 
					
						
							| 
									
										
										
										
											2019-11-18 11:49:19 +01:00
										 |  |  |         char ch = string.characters_without_null_termination()[i]; | 
					
						
							|  |  |  |         if (isspace(ch)) { | 
					
						
							| 
									
										
										
										
											2019-12-09 17:45:40 +01:00
										 |  |  |             size_t sublen = i - substart; | 
					
						
							| 
									
										
										
										
											2019-11-18 11:49:19 +01:00
										 |  |  |             if (sublen != 0) | 
					
						
							|  |  |  |                 v.append(string.substring_view(substart, sublen)); | 
					
						
							|  |  |  |             substart = i + 1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-12-09 17:45:40 +01:00
										 |  |  |     size_t taillen = string.length() - substart; | 
					
						
							| 
									
										
										
										
											2019-11-18 11:49:19 +01:00
										 |  |  |     if (taillen != 0) | 
					
						
							|  |  |  |         v.append(string.substring_view(substart, taillen)); | 
					
						
							|  |  |  |     return v; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 16:14:31 +02:00
										 |  |  | enum class Edge { | 
					
						
							|  |  |  |     Top, | 
					
						
							|  |  |  |     Right, | 
					
						
							|  |  |  |     Bottom, | 
					
						
							|  |  |  |     Left, | 
					
						
							|  |  |  |     All, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool contains(Edge a, Edge b) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return a == b || b == Edge::All; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void set_property_border_width(StyleProperties& style, const StyleValue& value, Edge edge) | 
					
						
							| 
									
										
										
										
											2020-03-20 20:29:39 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     ASSERT(value.is_length()); | 
					
						
							| 
									
										
										
										
											2020-06-10 16:14:31 +02:00
										 |  |  |     if (contains(Edge::Top, edge)) | 
					
						
							|  |  |  |         style.set_property(CSS::PropertyID::BorderTopWidth, value); | 
					
						
							|  |  |  |     if (contains(Edge::Right, edge)) | 
					
						
							|  |  |  |         style.set_property(CSS::PropertyID::BorderRightWidth, value); | 
					
						
							|  |  |  |     if (contains(Edge::Bottom, edge)) | 
					
						
							|  |  |  |         style.set_property(CSS::PropertyID::BorderBottomWidth, value); | 
					
						
							|  |  |  |     if (contains(Edge::Left, edge)) | 
					
						
							|  |  |  |         style.set_property(CSS::PropertyID::BorderLeftWidth, value); | 
					
						
							| 
									
										
										
										
											2020-03-20 20:29:39 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 16:14:31 +02:00
										 |  |  | static inline void set_property_border_color(StyleProperties& style, const StyleValue& value, Edge edge) | 
					
						
							| 
									
										
										
										
											2020-03-20 20:29:39 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     ASSERT(value.is_color()); | 
					
						
							| 
									
										
										
										
											2020-06-10 16:14:31 +02:00
										 |  |  |     if (contains(Edge::Top, edge)) | 
					
						
							|  |  |  |         style.set_property(CSS::PropertyID::BorderTopColor, value); | 
					
						
							|  |  |  |     if (contains(Edge::Right, edge)) | 
					
						
							|  |  |  |         style.set_property(CSS::PropertyID::BorderRightColor, value); | 
					
						
							|  |  |  |     if (contains(Edge::Bottom, edge)) | 
					
						
							|  |  |  |         style.set_property(CSS::PropertyID::BorderBottomColor, value); | 
					
						
							|  |  |  |     if (contains(Edge::Left, edge)) | 
					
						
							|  |  |  |         style.set_property(CSS::PropertyID::BorderLeftColor, value); | 
					
						
							| 
									
										
										
										
											2020-03-20 20:29:39 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 16:14:31 +02:00
										 |  |  | static inline void set_property_border_style(StyleProperties& style, const StyleValue& value, Edge edge) | 
					
						
							| 
									
										
										
										
											2020-03-20 20:29:39 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     ASSERT(value.is_string()); | 
					
						
							| 
									
										
										
										
											2020-06-10 16:14:31 +02:00
										 |  |  |     if (contains(Edge::Top, edge)) | 
					
						
							|  |  |  |         style.set_property(CSS::PropertyID::BorderTopStyle, value); | 
					
						
							|  |  |  |     if (contains(Edge::Right, edge)) | 
					
						
							|  |  |  |         style.set_property(CSS::PropertyID::BorderRightStyle, value); | 
					
						
							|  |  |  |     if (contains(Edge::Bottom, edge)) | 
					
						
							|  |  |  |         style.set_property(CSS::PropertyID::BorderBottomStyle, value); | 
					
						
							|  |  |  |     if (contains(Edge::Left, edge)) | 
					
						
							|  |  |  |         style.set_property(CSS::PropertyID::BorderLeftStyle, value); | 
					
						
							| 
									
										
										
										
											2020-03-20 20:29:39 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-26 19:37:56 +02:00
										 |  |  | static void set_property_expanding_shorthands(StyleProperties& style, CSS::PropertyID property_id, const StyleValue& value, DOM::Document& document) | 
					
						
							| 
									
										
										
										
											2019-11-18 11:49:19 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-06-28 12:43:22 +02:00
										 |  |  |     CSS::ParsingContext context(document); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-15 13:36:27 +01:00
										 |  |  |     if (property_id == CSS::PropertyID::TextDecoration) { | 
					
						
							|  |  |  |         switch (value.to_identifier()) { | 
					
						
							|  |  |  |         case CSS::ValueID::None: | 
					
						
							|  |  |  |         case CSS::ValueID::Underline: | 
					
						
							|  |  |  |         case CSS::ValueID::Overline: | 
					
						
							|  |  |  |         case CSS::ValueID::LineThrough: | 
					
						
							|  |  |  |         case CSS::ValueID::Blink: | 
					
						
							|  |  |  |             set_property_expanding_shorthands(style, CSS::PropertyID::TextDecorationLine, value, document); | 
					
						
							|  |  |  |         default: | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-20 20:29:39 +01:00
										 |  |  |     if (property_id == CSS::PropertyID::Border) { | 
					
						
							| 
									
										
										
										
											2020-06-10 17:47:04 +02:00
										 |  |  |         set_property_expanding_shorthands(style, CSS::PropertyID::BorderTop, value, document); | 
					
						
							|  |  |  |         set_property_expanding_shorthands(style, CSS::PropertyID::BorderRight, value, document); | 
					
						
							|  |  |  |         set_property_expanding_shorthands(style, CSS::PropertyID::BorderBottom, value, document); | 
					
						
							|  |  |  |         set_property_expanding_shorthands(style, CSS::PropertyID::BorderLeft, value, document); | 
					
						
							| 
									
										
										
										
											2020-12-19 19:30:49 +01:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2020-06-10 16:14:31 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (property_id == CSS::PropertyID::BorderTop | 
					
						
							|  |  |  |         || property_id == CSS::PropertyID::BorderRight | 
					
						
							|  |  |  |         || property_id == CSS::PropertyID::BorderBottom | 
					
						
							|  |  |  |         || property_id == CSS::PropertyID::BorderLeft) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Edge edge = Edge::All; | 
					
						
							|  |  |  |         switch (property_id) { | 
					
						
							|  |  |  |         case CSS::PropertyID::BorderTop: | 
					
						
							|  |  |  |             edge = Edge::Top; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case CSS::PropertyID::BorderRight: | 
					
						
							|  |  |  |             edge = Edge::Right; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case CSS::PropertyID::BorderBottom: | 
					
						
							|  |  |  |             edge = Edge::Bottom; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case CSS::PropertyID::BorderLeft: | 
					
						
							|  |  |  |             edge = Edge::Left; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         default: | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-20 20:29:39 +01:00
										 |  |  |         auto parts = split_on_whitespace(value.to_string()); | 
					
						
							|  |  |  |         if (value.is_length()) { | 
					
						
							| 
									
										
										
										
											2020-06-10 16:14:31 +02:00
										 |  |  |             set_property_border_width(style, value, edge); | 
					
						
							| 
									
										
										
										
											2020-03-20 20:29:39 +01:00
										 |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (value.is_color()) { | 
					
						
							| 
									
										
										
										
											2020-06-10 16:14:31 +02:00
										 |  |  |             set_property_border_color(style, value, edge); | 
					
						
							| 
									
										
										
										
											2020-03-20 20:29:39 +01:00
										 |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (value.is_string()) { | 
					
						
							|  |  |  |             auto parts = split_on_whitespace(value.to_string()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (parts.size() == 1) { | 
					
						
							| 
									
										
										
										
											2020-06-28 12:43:22 +02:00
										 |  |  |                 if (auto value = parse_line_style(context, parts[0])) { | 
					
						
							| 
									
										
										
										
											2020-06-10 16:14:31 +02:00
										 |  |  |                     set_property_border_style(style, value.release_nonnull(), edge); | 
					
						
							|  |  |  |                     set_property_border_color(style, ColorStyleValue::create(Gfx::Color::Black), edge); | 
					
						
							|  |  |  |                     set_property_border_width(style, LengthStyleValue::create(Length(3, Length::Type::Px)), edge); | 
					
						
							| 
									
										
										
										
											2020-03-20 20:29:39 +01:00
										 |  |  |                     return; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             RefPtr<LengthStyleValue> line_width_value; | 
					
						
							|  |  |  |             RefPtr<ColorStyleValue> color_value; | 
					
						
							|  |  |  |             RefPtr<StringStyleValue> line_style_value; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for (auto& part : parts) { | 
					
						
							| 
									
										
										
										
											2020-06-28 12:43:22 +02:00
										 |  |  |                 if (auto value = parse_line_width(context, part)) { | 
					
						
							| 
									
										
										
										
											2020-03-20 20:29:39 +01:00
										 |  |  |                     if (line_width_value) | 
					
						
							|  |  |  |                         return; | 
					
						
							|  |  |  |                     line_width_value = move(value); | 
					
						
							|  |  |  |                     continue; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2020-06-28 12:43:22 +02:00
										 |  |  |                 if (auto value = parse_color(context, part)) { | 
					
						
							| 
									
										
										
										
											2020-03-20 20:29:39 +01:00
										 |  |  |                     if (color_value) | 
					
						
							|  |  |  |                         return; | 
					
						
							|  |  |  |                     color_value = move(value); | 
					
						
							|  |  |  |                     continue; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2020-06-28 12:43:22 +02:00
										 |  |  |                 if (auto value = parse_line_style(context, part)) { | 
					
						
							| 
									
										
										
										
											2020-03-20 20:29:39 +01:00
										 |  |  |                     if (line_style_value) | 
					
						
							|  |  |  |                         return; | 
					
						
							|  |  |  |                     line_style_value = move(value); | 
					
						
							|  |  |  |                     continue; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (line_width_value) | 
					
						
							| 
									
										
										
										
											2020-06-10 16:14:31 +02:00
										 |  |  |                 set_property_border_width(style, line_width_value.release_nonnull(), edge); | 
					
						
							| 
									
										
										
										
											2020-03-20 20:29:39 +01:00
										 |  |  |             if (color_value) | 
					
						
							| 
									
										
										
										
											2020-06-10 16:14:31 +02:00
										 |  |  |                 set_property_border_color(style, color_value.release_nonnull(), edge); | 
					
						
							| 
									
										
										
										
											2020-03-20 20:29:39 +01:00
										 |  |  |             if (line_style_value) | 
					
						
							| 
									
										
										
										
											2020-06-10 16:14:31 +02:00
										 |  |  |                 set_property_border_style(style, line_style_value.release_nonnull(), edge); | 
					
						
							| 
									
										
										
										
											2020-03-20 20:29:39 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-27 20:51:15 +01:00
										 |  |  |     if (property_id == CSS::PropertyID::BorderStyle) { | 
					
						
							| 
									
										
										
										
											2020-06-10 19:34:49 +02:00
										 |  |  |         auto parts = split_on_whitespace(value.to_string()); | 
					
						
							|  |  |  |         if (value.is_string() && parts.size() == 3) { | 
					
						
							| 
									
										
										
										
											2020-06-28 12:43:22 +02:00
										 |  |  |             auto top = parse_css_value(context, parts[0]); | 
					
						
							|  |  |  |             auto right = parse_css_value(context, parts[1]); | 
					
						
							|  |  |  |             auto bottom = parse_css_value(context, parts[2]); | 
					
						
							|  |  |  |             auto left = parse_css_value(context, parts[1]); | 
					
						
							|  |  |  |             if (top && right && bottom && left) { | 
					
						
							|  |  |  |                 style.set_property(CSS::PropertyID::BorderTopStyle, *top); | 
					
						
							|  |  |  |                 style.set_property(CSS::PropertyID::BorderRightStyle, *right); | 
					
						
							|  |  |  |                 style.set_property(CSS::PropertyID::BorderBottomStyle, *bottom); | 
					
						
							|  |  |  |                 style.set_property(CSS::PropertyID::BorderLeftStyle, *left); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-06-10 19:34:49 +02:00
										 |  |  |         } else { | 
					
						
							|  |  |  |             style.set_property(CSS::PropertyID::BorderTopStyle, value); | 
					
						
							|  |  |  |             style.set_property(CSS::PropertyID::BorderRightStyle, value); | 
					
						
							|  |  |  |             style.set_property(CSS::PropertyID::BorderBottomStyle, value); | 
					
						
							|  |  |  |             style.set_property(CSS::PropertyID::BorderLeftStyle, value); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-11-27 20:51:15 +01:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (property_id == CSS::PropertyID::BorderWidth) { | 
					
						
							| 
									
										
										
										
											2020-06-10 16:42:58 +02:00
										 |  |  |         auto parts = split_on_whitespace(value.to_string()); | 
					
						
							| 
									
										
										
										
											2020-06-10 19:34:49 +02:00
										 |  |  |         if (value.is_string() && parts.size() == 2) { | 
					
						
							| 
									
										
										
										
											2020-06-28 12:43:22 +02:00
										 |  |  |             auto vertical_border_width = parse_css_value(context, parts[0]); | 
					
						
							|  |  |  |             auto horizontal_border_width = parse_css_value(context, parts[1]); | 
					
						
							|  |  |  |             if (vertical_border_width && horizontal_border_width) { | 
					
						
							|  |  |  |                 style.set_property(CSS::PropertyID::BorderTopWidth, *vertical_border_width); | 
					
						
							|  |  |  |                 style.set_property(CSS::PropertyID::BorderRightWidth, *horizontal_border_width); | 
					
						
							|  |  |  |                 style.set_property(CSS::PropertyID::BorderBottomWidth, *vertical_border_width); | 
					
						
							|  |  |  |                 style.set_property(CSS::PropertyID::BorderLeftWidth, *horizontal_border_width); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-06-10 16:42:58 +02:00
										 |  |  |         } else { | 
					
						
							|  |  |  |             style.set_property(CSS::PropertyID::BorderTopWidth, value); | 
					
						
							|  |  |  |             style.set_property(CSS::PropertyID::BorderRightWidth, value); | 
					
						
							|  |  |  |             style.set_property(CSS::PropertyID::BorderBottomWidth, value); | 
					
						
							|  |  |  |             style.set_property(CSS::PropertyID::BorderLeftWidth, value); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-11-27 20:51:15 +01:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (property_id == CSS::PropertyID::BorderColor) { | 
					
						
							| 
									
										
										
										
											2020-06-10 19:34:49 +02:00
										 |  |  |         auto parts = split_on_whitespace(value.to_string()); | 
					
						
							|  |  |  |         if (value.is_string() && parts.size() == 4) { | 
					
						
							| 
									
										
										
										
											2020-06-28 12:43:22 +02:00
										 |  |  |             auto top = parse_css_value(context, parts[0]); | 
					
						
							|  |  |  |             auto right = parse_css_value(context, parts[1]); | 
					
						
							|  |  |  |             auto bottom = parse_css_value(context, parts[2]); | 
					
						
							|  |  |  |             auto left = parse_css_value(context, parts[3]); | 
					
						
							| 
									
										
										
										
											2020-07-28 19:20:11 +02:00
										 |  |  |             if (top && right && bottom && left) { | 
					
						
							| 
									
										
										
										
											2020-06-28 12:43:22 +02:00
										 |  |  |                 style.set_property(CSS::PropertyID::BorderTopColor, *top); | 
					
						
							|  |  |  |                 style.set_property(CSS::PropertyID::BorderRightColor, *right); | 
					
						
							|  |  |  |                 style.set_property(CSS::PropertyID::BorderBottomColor, *bottom); | 
					
						
							|  |  |  |                 style.set_property(CSS::PropertyID::BorderLeftColor, *left); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-06-10 19:34:49 +02:00
										 |  |  |         } else { | 
					
						
							|  |  |  |             style.set_property(CSS::PropertyID::BorderTopColor, value); | 
					
						
							|  |  |  |             style.set_property(CSS::PropertyID::BorderRightColor, value); | 
					
						
							|  |  |  |             style.set_property(CSS::PropertyID::BorderBottomColor, value); | 
					
						
							|  |  |  |             style.set_property(CSS::PropertyID::BorderLeftColor, value); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-11-27 20:51:15 +01:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-30 11:58:05 +02:00
										 |  |  |     if (property_id == CSS::PropertyID::Background) { | 
					
						
							| 
									
										
										
										
											2020-12-15 12:03:17 +01:00
										 |  |  |         if (value.is_identifier() && static_cast<const IdentifierStyleValue&>(value).id() == CSS::ValueID::None) { | 
					
						
							| 
									
										
										
										
											2020-06-13 20:03:41 +02:00
										 |  |  |             style.set_property(CSS::PropertyID::BackgroundColor, ColorStyleValue::create(Color::Transparent)); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-05-30 11:58:05 +02:00
										 |  |  |         auto parts = split_on_whitespace(value.to_string()); | 
					
						
							|  |  |  |         NonnullRefPtrVector<StyleValue> values; | 
					
						
							|  |  |  |         for (auto& part : parts) { | 
					
						
							| 
									
										
										
										
											2020-06-28 12:43:22 +02:00
										 |  |  |             auto value = parse_css_value(context, part); | 
					
						
							|  |  |  |             if (!value) | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             values.append(value.release_nonnull()); | 
					
						
							| 
									
										
										
										
											2020-05-30 11:58:05 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-06-25 16:55:43 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // HACK: Disallow more than one color value in a 'background' shorthand
 | 
					
						
							|  |  |  |         size_t color_value_count = 0; | 
					
						
							|  |  |  |         for (auto& value : values) | 
					
						
							|  |  |  |             color_value_count += value.is_color(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (values[0].is_color() && color_value_count == 1) | 
					
						
							| 
									
										
										
										
											2020-05-30 11:58:05 +02:00
										 |  |  |             style.set_property(CSS::PropertyID::BackgroundColor, values[0]); | 
					
						
							| 
									
										
										
										
											2020-06-25 16:55:43 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 17:47:04 +02:00
										 |  |  |         for (auto& value : values) { | 
					
						
							|  |  |  |             if (!value.is_string()) | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |             auto string = value.to_string(); | 
					
						
							| 
									
										
										
										
											2020-10-08 15:35:21 +02:00
										 |  |  |             set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundImage, value, document); | 
					
						
							| 
									
										
										
										
											2020-06-10 17:47:04 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-05-30 11:58:05 +02:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-08 15:35:21 +02:00
										 |  |  |     if (property_id == CSS::PropertyID::BackgroundImage) { | 
					
						
							|  |  |  |         if (!value.is_string()) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         auto string = value.to_string(); | 
					
						
							| 
									
										
										
										
											2020-10-09 21:27:01 +02:00
										 |  |  |         if (!string.starts_with("url(")) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         if (!string.ends_with(')')) | 
					
						
							|  |  |  |             return; | 
					
						
							| 
									
										
										
										
											2020-10-08 15:35:21 +02:00
										 |  |  |         auto url = string.substring_view(4, string.length() - 5); | 
					
						
							|  |  |  |         if (url.length() >= 2 && url.starts_with('"') && url.ends_with('"')) | 
					
						
							|  |  |  |             url = url.substring_view(1, url.length() - 2); | 
					
						
							|  |  |  |         else if (url.length() >= 2 && url.starts_with('\'') && url.ends_with('\'')) | 
					
						
							|  |  |  |             url = url.substring_view(1, url.length() - 2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         auto background_image_value = ImageStyleValue::create(document.complete_url(url), document); | 
					
						
							|  |  |  |         style.set_property(CSS::PropertyID::BackgroundImage, move(background_image_value)); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-18 11:49:19 +01:00
										 |  |  |     if (property_id == CSS::PropertyID::Margin) { | 
					
						
							|  |  |  |         if (value.is_length()) { | 
					
						
							|  |  |  |             style.set_property(CSS::PropertyID::MarginTop, value); | 
					
						
							|  |  |  |             style.set_property(CSS::PropertyID::MarginRight, value); | 
					
						
							|  |  |  |             style.set_property(CSS::PropertyID::MarginBottom, value); | 
					
						
							|  |  |  |             style.set_property(CSS::PropertyID::MarginLeft, value); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (value.is_string()) { | 
					
						
							|  |  |  |             auto parts = split_on_whitespace(value.to_string()); | 
					
						
							| 
									
										
										
										
											2020-06-10 19:34:49 +02:00
										 |  |  |             if (value.is_string() && parts.size() == 2) { | 
					
						
							| 
									
										
										
										
											2020-06-28 12:43:22 +02:00
										 |  |  |                 auto vertical = parse_css_value(context, parts[0]); | 
					
						
							|  |  |  |                 auto horizontal = parse_css_value(context, parts[1]); | 
					
						
							|  |  |  |                 if (vertical && horizontal) { | 
					
						
							|  |  |  |                     style.set_property(CSS::PropertyID::MarginTop, *vertical); | 
					
						
							|  |  |  |                     style.set_property(CSS::PropertyID::MarginBottom, *vertical); | 
					
						
							|  |  |  |                     style.set_property(CSS::PropertyID::MarginLeft, *horizontal); | 
					
						
							|  |  |  |                     style.set_property(CSS::PropertyID::MarginRight, *horizontal); | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2019-11-18 11:49:19 +01:00
										 |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-06-10 19:34:49 +02:00
										 |  |  |             if (value.is_string() && parts.size() == 3) { | 
					
						
							| 
									
										
										
										
											2020-06-28 12:43:22 +02:00
										 |  |  |                 auto top = parse_css_value(context, parts[0]); | 
					
						
							|  |  |  |                 auto horizontal = parse_css_value(context, parts[1]); | 
					
						
							|  |  |  |                 auto bottom = parse_css_value(context, parts[2]); | 
					
						
							|  |  |  |                 if (top && horizontal && bottom) { | 
					
						
							|  |  |  |                     style.set_property(CSS::PropertyID::MarginTop, *top); | 
					
						
							|  |  |  |                     style.set_property(CSS::PropertyID::MarginBottom, *bottom); | 
					
						
							|  |  |  |                     style.set_property(CSS::PropertyID::MarginLeft, *horizontal); | 
					
						
							|  |  |  |                     style.set_property(CSS::PropertyID::MarginRight, *horizontal); | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2019-11-18 11:49:19 +01:00
										 |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-06-10 19:34:49 +02:00
										 |  |  |             if (value.is_string() && parts.size() == 4) { | 
					
						
							| 
									
										
										
										
											2020-06-28 12:43:22 +02:00
										 |  |  |                 auto top = parse_css_value(context, parts[0]); | 
					
						
							|  |  |  |                 auto right = parse_css_value(context, parts[1]); | 
					
						
							|  |  |  |                 auto bottom = parse_css_value(context, parts[2]); | 
					
						
							|  |  |  |                 auto left = parse_css_value(context, parts[3]); | 
					
						
							|  |  |  |                 if (top && right && bottom && left) { | 
					
						
							|  |  |  |                     style.set_property(CSS::PropertyID::MarginTop, *top); | 
					
						
							|  |  |  |                     style.set_property(CSS::PropertyID::MarginBottom, *bottom); | 
					
						
							|  |  |  |                     style.set_property(CSS::PropertyID::MarginLeft, *left); | 
					
						
							|  |  |  |                     style.set_property(CSS::PropertyID::MarginRight, *right); | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2019-11-18 11:49:19 +01:00
										 |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-01-12 14:11:44 +01:00
										 |  |  |             dbgln("Unsure what to do with CSS margin value '{}'", value.to_string()); | 
					
						
							| 
									
										
										
										
											2019-11-18 11:49:19 +01:00
										 |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-18 12:25:22 +01:00
										 |  |  |     if (property_id == CSS::PropertyID::Padding) { | 
					
						
							|  |  |  |         if (value.is_length()) { | 
					
						
							|  |  |  |             style.set_property(CSS::PropertyID::PaddingTop, value); | 
					
						
							|  |  |  |             style.set_property(CSS::PropertyID::PaddingRight, value); | 
					
						
							|  |  |  |             style.set_property(CSS::PropertyID::PaddingBottom, value); | 
					
						
							|  |  |  |             style.set_property(CSS::PropertyID::PaddingLeft, value); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (value.is_string()) { | 
					
						
							|  |  |  |             auto parts = split_on_whitespace(value.to_string()); | 
					
						
							| 
									
										
										
										
											2020-06-10 19:34:49 +02:00
										 |  |  |             if (value.is_string() && parts.size() == 2) { | 
					
						
							| 
									
										
										
										
											2020-06-28 12:43:22 +02:00
										 |  |  |                 auto vertical = parse_css_value(context, parts[0]); | 
					
						
							|  |  |  |                 auto horizontal = parse_css_value(context, parts[1]); | 
					
						
							|  |  |  |                 if (vertical && horizontal) { | 
					
						
							|  |  |  |                     style.set_property(CSS::PropertyID::PaddingTop, *vertical); | 
					
						
							|  |  |  |                     style.set_property(CSS::PropertyID::PaddingBottom, *vertical); | 
					
						
							|  |  |  |                     style.set_property(CSS::PropertyID::PaddingLeft, *horizontal); | 
					
						
							|  |  |  |                     style.set_property(CSS::PropertyID::PaddingRight, *horizontal); | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2019-11-18 12:25:22 +01:00
										 |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-06-10 19:34:49 +02:00
										 |  |  |             if (value.is_string() && parts.size() == 3) { | 
					
						
							| 
									
										
										
										
											2020-06-28 12:43:22 +02:00
										 |  |  |                 auto top = parse_css_value(context, parts[0]); | 
					
						
							|  |  |  |                 auto horizontal = parse_css_value(context, parts[1]); | 
					
						
							|  |  |  |                 auto bottom = parse_css_value(context, parts[2]); | 
					
						
							|  |  |  |                 if (top && bottom && horizontal) { | 
					
						
							|  |  |  |                     style.set_property(CSS::PropertyID::PaddingTop, *top); | 
					
						
							|  |  |  |                     style.set_property(CSS::PropertyID::PaddingBottom, *bottom); | 
					
						
							|  |  |  |                     style.set_property(CSS::PropertyID::PaddingLeft, *horizontal); | 
					
						
							|  |  |  |                     style.set_property(CSS::PropertyID::PaddingRight, *horizontal); | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2019-11-18 12:25:22 +01:00
										 |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-06-10 19:34:49 +02:00
										 |  |  |             if (value.is_string() && parts.size() == 4) { | 
					
						
							| 
									
										
										
										
											2020-06-28 12:43:22 +02:00
										 |  |  |                 auto top = parse_css_value(context, parts[0]); | 
					
						
							|  |  |  |                 auto right = parse_css_value(context, parts[1]); | 
					
						
							|  |  |  |                 auto bottom = parse_css_value(context, parts[2]); | 
					
						
							|  |  |  |                 auto left = parse_css_value(context, parts[3]); | 
					
						
							|  |  |  |                 if (top && bottom && left && right) { | 
					
						
							|  |  |  |                     style.set_property(CSS::PropertyID::PaddingTop, *top); | 
					
						
							|  |  |  |                     style.set_property(CSS::PropertyID::PaddingBottom, *bottom); | 
					
						
							|  |  |  |                     style.set_property(CSS::PropertyID::PaddingLeft, *left); | 
					
						
							|  |  |  |                     style.set_property(CSS::PropertyID::PaddingRight, *right); | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2019-11-18 12:25:22 +01:00
										 |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-01-12 14:11:44 +01:00
										 |  |  |             dbgln("Unsure what to do with CSS padding value '{}'", value.to_string()); | 
					
						
							| 
									
										
										
										
											2019-11-18 12:25:22 +01:00
										 |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-30 12:04:15 +02:00
										 |  |  |     if (property_id == CSS::PropertyID::ListStyle) { | 
					
						
							|  |  |  |         auto parts = split_on_whitespace(value.to_string()); | 
					
						
							|  |  |  |         if (!parts.is_empty()) { | 
					
						
							| 
									
										
										
										
											2020-06-28 12:43:22 +02:00
										 |  |  |             auto value = parse_css_value(context, parts[0]); | 
					
						
							|  |  |  |             if (!value) | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             style.set_property(CSS::PropertyID::ListStyleType, value.release_nonnull()); | 
					
						
							| 
									
										
										
										
											2020-05-30 12:04:15 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-18 11:49:19 +01:00
										 |  |  |     style.set_property(property_id, value); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-06 14:27:40 +01:00
										 |  |  | NonnullRefPtr<StyleProperties> StyleResolver::resolve_style(const DOM::Element& element) const | 
					
						
							| 
									
										
										
										
											2019-06-27 17:47:59 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-10-07 09:23:53 +02:00
										 |  |  |     auto style = StyleProperties::create(); | 
					
						
							| 
									
										
										
										
											2019-09-25 12:33:28 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-06 14:27:40 +01:00
										 |  |  |     if (auto* parent_style = element.parent_element() ? element.parent_element()->specified_css_values() : nullptr) { | 
					
						
							| 
									
										
										
										
											2019-10-08 15:34:19 +02:00
										 |  |  |         parent_style->for_each_property([&](auto property_id, auto& value) { | 
					
						
							|  |  |  |             if (is_inherited_property(property_id)) | 
					
						
							| 
									
										
										
										
											2020-06-10 17:47:04 +02:00
										 |  |  |                 set_property_expanding_shorthands(style, property_id, value, m_document); | 
					
						
							| 
									
										
										
										
											2019-09-25 12:33:28 +03:00
										 |  |  |         }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-07 09:23:53 +02:00
										 |  |  |     element.apply_presentational_hints(*style); | 
					
						
							| 
									
										
										
										
											2019-10-04 21:05:52 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-27 20:40:21 +02:00
										 |  |  |     auto matching_rules = collect_matching_rules(element); | 
					
						
							| 
									
										
										
										
											2020-12-14 21:31:10 +00:00
										 |  |  |     sort_matching_rules(matching_rules); | 
					
						
							| 
									
										
										
										
											2020-06-10 16:41:30 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-13 00:44:26 +02:00
										 |  |  |     for (auto& match : matching_rules) { | 
					
						
							|  |  |  |         for (auto& property : match.rule->declaration().properties()) { | 
					
						
							| 
									
										
										
										
											2020-06-10 17:47:04 +02:00
										 |  |  |             set_property_expanding_shorthands(style, property.property_id, property.value, m_document); | 
					
						
							| 
									
										
										
										
											2019-06-28 21:17:34 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-09-30 20:25:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-07 19:56:53 +01:00
										 |  |  |     if (auto* inline_style = element.inline_style()) { | 
					
						
							|  |  |  |         for (auto& property : inline_style->properties()) { | 
					
						
							|  |  |  |             set_property_expanding_shorthands(style, property.property_id, property.value, m_document); | 
					
						
							| 
									
										
										
										
											2019-09-30 20:25:33 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-07 09:23:53 +02:00
										 |  |  |     return style; | 
					
						
							| 
									
										
										
										
											2019-06-27 17:47:59 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-03-07 10:27:02 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | } |