mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 19:22:45 +00:00 
			
		
		
		
	LibHTML: Add support for <body bgcolor="#rrggbb" text="#rrggbb">
This patch implements basic support for presentational hints, which are old-school HTML attributes that affect style. You add support for a presentational hint attribute by overriding Element::apply_presentational_hints(StyleProperties&) and setting all of the corresponding CSS properties as appropriate. To make the background color fill the entire document, not just the bounds of the <body> element's LayoutNode, we special-case it in the HtmlView::paint_event() code for now. I'm not entirely sure what the nicest solution would be, but I'm sure we'll discover it eventually.
This commit is contained in:
		
							parent
							
								
									a7ca719c4e
								
							
						
					
					
						commit
						9808d35554
					
				
					 12 changed files with 94 additions and 5 deletions
				
			
		|  | @ -69,6 +69,8 @@ NonnullRefPtr<StyleProperties> StyleResolver::resolve_style(const Element& eleme | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     element.apply_presentational_hints(*style_properties); | ||||||
|  | 
 | ||||||
|     auto matching_rules = collect_matching_rules(element); |     auto matching_rules = collect_matching_rules(element); | ||||||
|     for (auto& rule : matching_rules) { |     for (auto& rule : matching_rules) { | ||||||
|         for (auto& property : rule.declaration().properties()) { |         for (auto& property : rule.declaration().properties()) { | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| #include <LibHTML/CSS/StyleResolver.h> | #include <LibHTML/CSS/StyleResolver.h> | ||||||
| #include <LibHTML/DOM/Document.h> | #include <LibHTML/DOM/Document.h> | ||||||
| #include <LibHTML/DOM/Element.h> | #include <LibHTML/DOM/Element.h> | ||||||
|  | #include <LibHTML/DOM/HTMLBodyElement.h> | ||||||
| #include <LibHTML/DOM/HTMLHeadElement.h> | #include <LibHTML/DOM/HTMLHeadElement.h> | ||||||
| #include <LibHTML/DOM/HTMLHtmlElement.h> | #include <LibHTML/DOM/HTMLHtmlElement.h> | ||||||
| #include <LibHTML/DOM/HTMLTitleElement.h> | #include <LibHTML/DOM/HTMLTitleElement.h> | ||||||
|  | @ -52,6 +53,14 @@ const HTMLHeadElement* Document::head() const | ||||||
|     return static_cast<const HTMLHeadElement*>(html->first_child_with_tag_name("head")); |     return static_cast<const HTMLHeadElement*>(html->first_child_with_tag_name("head")); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | const HTMLBodyElement* Document::body() const | ||||||
|  | { | ||||||
|  |     auto* html = document_element(); | ||||||
|  |     if (!html) | ||||||
|  |         return nullptr; | ||||||
|  |     return static_cast<const HTMLBodyElement*>(html->first_child_with_tag_name("body")); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| String Document::title() const | String Document::title() const | ||||||
| { | { | ||||||
|     auto* head_element = head(); |     auto* head_element = head(); | ||||||
|  | @ -73,3 +82,20 @@ void Document::attach_to_frame(Badge<Frame>, Frame& frame) | ||||||
| void Document::detach_from_frame(Badge<Frame>, Frame&) | void Document::detach_from_frame(Badge<Frame>, Frame&) | ||||||
| { | { | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | Color Document::background_color() const | ||||||
|  | { | ||||||
|  |     auto* body_element = body(); | ||||||
|  |     if (!body_element) | ||||||
|  |         return Color::White; | ||||||
|  | 
 | ||||||
|  |     auto* body_layout_node = body_element->layout_node(); | ||||||
|  |     if (!body_layout_node) | ||||||
|  |         return Color::White; | ||||||
|  | 
 | ||||||
|  |     auto background_color = body_layout_node->style().property("background-color"); | ||||||
|  |     if (!background_color.has_value() || !background_color.value()->is_color()) | ||||||
|  |         return Color::White; | ||||||
|  | 
 | ||||||
|  |     return background_color.value()->to_color(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ | ||||||
| #include <LibHTML/DOM/ParentNode.h> | #include <LibHTML/DOM/ParentNode.h> | ||||||
| 
 | 
 | ||||||
| class Frame; | class Frame; | ||||||
|  | class HTMLBodyElement; | ||||||
| class HTMLHtmlElement; | class HTMLHtmlElement; | ||||||
| class HTMLHeadElement; | class HTMLHeadElement; | ||||||
| class LayoutNode; | class LayoutNode; | ||||||
|  | @ -35,6 +36,7 @@ public: | ||||||
| 
 | 
 | ||||||
|     const HTMLHtmlElement* document_element() const; |     const HTMLHtmlElement* document_element() const; | ||||||
|     const HTMLHeadElement* head() const; |     const HTMLHeadElement* head() const; | ||||||
|  |     const HTMLBodyElement* body() const; | ||||||
| 
 | 
 | ||||||
|     String title() const; |     String title() const; | ||||||
| 
 | 
 | ||||||
|  | @ -44,6 +46,8 @@ public: | ||||||
|     Frame* frame() { return m_frame.ptr(); } |     Frame* frame() { return m_frame.ptr(); } | ||||||
|     const Frame* frame() const { return m_frame.ptr(); } |     const Frame* frame() const { return m_frame.ptr(); } | ||||||
| 
 | 
 | ||||||
|  |     Color background_color() const; | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     OwnPtr<StyleResolver> m_style_resolver; |     OwnPtr<StyleResolver> m_style_resolver; | ||||||
|     NonnullRefPtrVector<StyleSheet> m_sheets; |     NonnullRefPtrVector<StyleSheet> m_sheets; | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <LibHTML/DOM/ParentNode.h> |  | ||||||
| #include <AK/String.h> | #include <AK/String.h> | ||||||
|  | #include <LibHTML/DOM/ParentNode.h> | ||||||
| 
 | 
 | ||||||
| class Attribute { | class Attribute { | ||||||
| public: | public: | ||||||
|  | @ -42,6 +42,8 @@ public: | ||||||
| 
 | 
 | ||||||
|     bool has_class(const StringView&) const; |     bool has_class(const StringView&) const; | ||||||
| 
 | 
 | ||||||
|  |     virtual void apply_presentational_hints(StyleProperties&) const {} | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     Attribute* find_attribute(const String& name); |     Attribute* find_attribute(const String& name); | ||||||
|     const Attribute* find_attribute(const String& name) const; |     const Attribute* find_attribute(const String& name) const; | ||||||
|  | @ -49,4 +51,3 @@ private: | ||||||
|     String m_tag_name; |     String m_tag_name; | ||||||
|     Vector<Attribute> m_attributes; |     Vector<Attribute> m_attributes; | ||||||
| }; | }; | ||||||
| 
 |  | ||||||
|  |  | ||||||
							
								
								
									
										27
									
								
								Libraries/LibHTML/DOM/HTMLBodyElement.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								Libraries/LibHTML/DOM/HTMLBodyElement.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,27 @@ | ||||||
|  | #include <LibHTML/CSS/StyleProperties.h> | ||||||
|  | #include <LibHTML/CSS/StyleValue.h> | ||||||
|  | #include <LibHTML/DOM/HTMLBodyElement.h> | ||||||
|  | 
 | ||||||
|  | HTMLBodyElement::HTMLBodyElement(Document& document, const String& tag_name) | ||||||
|  |     : HTMLElement(document, tag_name) | ||||||
|  | { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | HTMLBodyElement::~HTMLBodyElement() | ||||||
|  | { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void HTMLBodyElement::apply_presentational_hints(StyleProperties& style) const | ||||||
|  | { | ||||||
|  |     for_each_attribute([&](auto& name, auto& value) { | ||||||
|  |         if (name == "bgcolor") { | ||||||
|  |             auto color = Color::from_string(value); | ||||||
|  |             if (color.has_value()) | ||||||
|  |                 style.set_property("background-color", ColorStyleValue::create(color.value())); | ||||||
|  |         } else if (name == "text") { | ||||||
|  |             auto color = Color::from_string(value); | ||||||
|  |             if (color.has_value()) | ||||||
|  |                 style.set_property("color", ColorStyleValue::create(color.value())); | ||||||
|  |         } | ||||||
|  |     }); | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								Libraries/LibHTML/DOM/HTMLBodyElement.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Libraries/LibHTML/DOM/HTMLBodyElement.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <LibHTML/DOM/HTMLElement.h> | ||||||
|  | 
 | ||||||
|  | class HTMLBodyElement : public HTMLElement { | ||||||
|  | public: | ||||||
|  |     HTMLBodyElement(Document&, const String& tag_name); | ||||||
|  |     virtual ~HTMLBodyElement() override; | ||||||
|  | 
 | ||||||
|  |     virtual void apply_presentational_hints(StyleProperties&) const override; | ||||||
|  | }; | ||||||
|  | @ -27,6 +27,8 @@ RefPtr<LayoutNode> Node::create_layout_node(const StyleResolver& resolver, const | ||||||
|     if (is_text()) |     if (is_text()) | ||||||
|         return adopt(*new LayoutText(static_cast<const Text&>(*this))); |         return adopt(*new LayoutText(static_cast<const Text&>(*this))); | ||||||
| 
 | 
 | ||||||
|  |     ASSERT(is_element()); | ||||||
|  | 
 | ||||||
|     auto style_properties = resolver.resolve_style(static_cast<const Element&>(*this), parent_properties); |     auto style_properties = resolver.resolve_style(static_cast<const Element&>(*this), parent_properties); | ||||||
| 
 | 
 | ||||||
|     auto display_property = style_properties->property("display"); |     auto display_property = style_properties->property("display"); | ||||||
|  |  | ||||||
|  | @ -58,9 +58,15 @@ public: | ||||||
|     virtual void inserted_into(Node&) {} |     virtual void inserted_into(Node&) {} | ||||||
|     virtual void removed_from(Node&) {} |     virtual void removed_from(Node&) {} | ||||||
| 
 | 
 | ||||||
|  |     const LayoutNode* layout_node() const { return m_layout_node; } | ||||||
|  |     LayoutNode* layout_node() { return m_layout_node; } | ||||||
|  | 
 | ||||||
|  |     void set_layout_node(Badge<LayoutNode>, LayoutNode* layout_node) const { m_layout_node = layout_node; } | ||||||
|  | 
 | ||||||
| protected: | protected: | ||||||
|     Node(Document&, NodeType); |     Node(Document&, NodeType); | ||||||
| 
 | 
 | ||||||
|     Document& m_document; |     Document& m_document; | ||||||
|  |     mutable LayoutNode* m_layout_node { nullptr }; | ||||||
|     NodeType m_type { NodeType::INVALID }; |     NodeType m_type { NodeType::INVALID }; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -78,13 +78,15 @@ void HtmlView::paint_event(GPaintEvent& event) | ||||||
|     painter.add_clip_rect(widget_inner_rect()); |     painter.add_clip_rect(widget_inner_rect()); | ||||||
|     painter.add_clip_rect(event.rect()); |     painter.add_clip_rect(event.rect()); | ||||||
| 
 | 
 | ||||||
|     painter.fill_rect(event.rect(), background_color()); |     if (!m_layout_root) { | ||||||
|  |         painter.fill_rect(event.rect(), background_color()); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     painter.translate(frame_thickness(), frame_thickness()); |     painter.translate(frame_thickness(), frame_thickness()); | ||||||
|     painter.translate(-horizontal_scrollbar().value(), -vertical_scrollbar().value()); |     painter.translate(-horizontal_scrollbar().value(), -vertical_scrollbar().value()); | ||||||
| 
 | 
 | ||||||
|     if (!m_layout_root) |     painter.fill_rect(rect(), m_document->background_color()); | ||||||
|         return; |  | ||||||
| 
 | 
 | ||||||
|     RenderingContext context { painter }; |     RenderingContext context { painter }; | ||||||
|     m_layout_root->render(context); |     m_layout_root->render(context); | ||||||
|  |  | ||||||
|  | @ -11,10 +11,14 @@ LayoutNode::LayoutNode(const Node* node, RefPtr<StyleProperties> style_propertie | ||||||
|     : m_node(node) |     : m_node(node) | ||||||
|     , m_style_properties(move(style_properties)) |     , m_style_properties(move(style_properties)) | ||||||
| { | { | ||||||
|  |     if (m_node) | ||||||
|  |         m_node->set_layout_node({}, this); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| LayoutNode::~LayoutNode() | LayoutNode::~LayoutNode() | ||||||
| { | { | ||||||
|  |     if (m_node) | ||||||
|  |         m_node->set_layout_node({}, nullptr); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void LayoutNode::layout() | void LayoutNode::layout() | ||||||
|  |  | ||||||
|  | @ -10,6 +10,7 @@ LIBHTML_OBJS = \ | ||||||
|     DOM/HTMLHtmlElement.o \ |     DOM/HTMLHtmlElement.o \ | ||||||
|     DOM/HTMLStyleElement.o \ |     DOM/HTMLStyleElement.o \ | ||||||
|     DOM/HTMLTitleElement.o \ |     DOM/HTMLTitleElement.o \ | ||||||
|  |     DOM/HTMLBodyElement.o \ | ||||||
|     DOM/Document.o \ |     DOM/Document.o \ | ||||||
|     DOM/Text.o \ |     DOM/Text.o \ | ||||||
|     CSS/Selector.o \ |     CSS/Selector.o \ | ||||||
|  |  | ||||||
|  | @ -4,6 +4,7 @@ | ||||||
| #include <LibHTML/DOM/Element.h> | #include <LibHTML/DOM/Element.h> | ||||||
| #include <LibHTML/DOM/HTMLAnchorElement.h> | #include <LibHTML/DOM/HTMLAnchorElement.h> | ||||||
| #include <LibHTML/DOM/HTMLHRElement.h> | #include <LibHTML/DOM/HTMLHRElement.h> | ||||||
|  | #include <LibHTML/DOM/HTMLBodyElement.h> | ||||||
| #include <LibHTML/DOM/HTMLHeadElement.h> | #include <LibHTML/DOM/HTMLHeadElement.h> | ||||||
| #include <LibHTML/DOM/HTMLHeadingElement.h> | #include <LibHTML/DOM/HTMLHeadingElement.h> | ||||||
| #include <LibHTML/DOM/HTMLHtmlElement.h> | #include <LibHTML/DOM/HTMLHtmlElement.h> | ||||||
|  | @ -23,6 +24,8 @@ static NonnullRefPtr<Element> create_element(Document& document, const String& t | ||||||
|         return adopt(*new HTMLHtmlElement(document, tag_name)); |         return adopt(*new HTMLHtmlElement(document, tag_name)); | ||||||
|     if (lowercase_tag_name == "head") |     if (lowercase_tag_name == "head") | ||||||
|         return adopt(*new HTMLHeadElement(document, tag_name)); |         return adopt(*new HTMLHeadElement(document, tag_name)); | ||||||
|  |     if (lowercase_tag_name == "body") | ||||||
|  |         return adopt(*new HTMLBodyElement(document, tag_name)); | ||||||
|     if (lowercase_tag_name == "hr") |     if (lowercase_tag_name == "hr") | ||||||
|         return adopt(*new HTMLHRElement(document, tag_name)); |         return adopt(*new HTMLHRElement(document, tag_name)); | ||||||
|     if (lowercase_tag_name == "style") |     if (lowercase_tag_name == "style") | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling