mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 14:42:44 +00:00 
			
		
		
		
	LibHTML: Start working on a simple HTML library.
I'd like to have rich text, and we might as well use HTML for that. :^)
This commit is contained in:
		
							parent
							
								
									01d1aee922
								
							
						
					
					
						commit
						a67e823838
					
				
					 19 changed files with 329 additions and 0 deletions
				
			
		|  | @ -83,6 +83,7 @@ cp ../Servers/LookupServer/LookupServer mnt/bin/LookupServer | |||
| cp ../Servers/SystemServer/SystemServer mnt/bin/SystemServer | ||||
| cp ../Servers/WindowServer/WindowServer mnt/bin/WindowServer | ||||
| cp ../Shell/Shell mnt/bin/Shell | ||||
| cp ../LibHTML/tho mnt/bin/tho | ||||
| echo "done" | ||||
| 
 | ||||
| echo -n "installing shortcuts... " | ||||
|  |  | |||
|  | @ -17,6 +17,7 @@ build_targets="$build_targets ../Servers/SystemServer" | |||
| build_targets="$build_targets ../Servers/LookupServer" | ||||
| build_targets="$build_targets ../Servers/WindowServer" | ||||
| build_targets="$build_targets ../LibGUI" | ||||
| build_targets="$build_targets ../LibHTML" | ||||
| build_targets="$build_targets ../Userland" | ||||
| build_targets="$build_targets ../Applications/Terminal" | ||||
| build_targets="$build_targets ../Applications/FontEditor" | ||||
|  |  | |||
							
								
								
									
										4
									
								
								LibHTML/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								LibHTML/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,4 @@ | |||
| *.o | ||||
| *.d | ||||
| libhtml.a | ||||
| tho | ||||
							
								
								
									
										11
									
								
								LibHTML/Document.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								LibHTML/Document.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | |||
| #include <LibHTML/Document.h> | ||||
| 
 | ||||
| Document::Document() | ||||
|     : ParentNode(NodeType::DOCUMENT_NODE) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| Document::~Document() | ||||
| { | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										13
									
								
								LibHTML/Document.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								LibHTML/Document.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <AK/AKString.h> | ||||
| #include <LibHTML/ParentNode.h> | ||||
| 
 | ||||
| class Document : public ParentNode { | ||||
| public: | ||||
|     Document(); | ||||
|     virtual ~Document() override; | ||||
| 
 | ||||
| private: | ||||
| }; | ||||
| 
 | ||||
							
								
								
									
										26
									
								
								LibHTML/Dump.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								LibHTML/Dump.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | |||
| #include <LibHTML/Document.h> | ||||
| #include <LibHTML/Dump.h> | ||||
| #include <LibHTML/Element.h> | ||||
| #include <LibHTML/Text.h> | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| void dump_tree(Node& node) | ||||
| { | ||||
|     static int indent = 0; | ||||
|     for (int i = 0; i < indent; ++i) | ||||
|         printf("   "); | ||||
|     if (node.is_document()) { | ||||
|         printf("*Document*\n"); | ||||
|     } else if (node.is_element()) { | ||||
|         printf("<%s>\n", static_cast<Element&>(node).tag_name().characters()); | ||||
|     } else if (node.is_text()) { | ||||
|         printf("\"%s\"\n", static_cast<Text&>(node).data().characters()); | ||||
|     } | ||||
|     ++indent; | ||||
|     if (node.is_parent_node()) { | ||||
|         static_cast<ParentNode&>(node).for_each_child([](Node& child) { | ||||
|             dump_tree(child); | ||||
|         }); | ||||
|     } | ||||
|     --indent; | ||||
| } | ||||
							
								
								
									
										5
									
								
								LibHTML/Dump.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								LibHTML/Dump.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | |||
| #pragma once | ||||
| 
 | ||||
| class Node; | ||||
| 
 | ||||
| void dump_tree(Node&); | ||||
							
								
								
									
										12
									
								
								LibHTML/Element.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								LibHTML/Element.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | |||
| #include <LibHTML/Element.h> | ||||
| 
 | ||||
| Element::Element(const String& tag_name) | ||||
|     : ParentNode(NodeType::ELEMENT_NODE) | ||||
|     , m_tag_name(tag_name) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| Element::~Element() | ||||
| { | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										30
									
								
								LibHTML/Element.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								LibHTML/Element.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <LibHTML/ParentNode.h> | ||||
| #include <AK/AKString.h> | ||||
| 
 | ||||
| class Attribute { | ||||
| public: | ||||
|     Attribute(const String& name, const String& value) | ||||
|         : m_name(name) | ||||
|         , m_value(value) | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     String m_name; | ||||
|     String m_value; | ||||
| }; | ||||
| 
 | ||||
| class Element : public ParentNode { | ||||
| public: | ||||
|     explicit Element(const String& tag_name); | ||||
|     virtual ~Element() override; | ||||
| 
 | ||||
|     const String& tag_name() const { return m_tag_name; } | ||||
| 
 | ||||
| private: | ||||
|     String m_tag_name; | ||||
|     Vector<Attribute> m_attributes; | ||||
| }; | ||||
| 
 | ||||
							
								
								
									
										42
									
								
								LibHTML/Makefile
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								LibHTML/Makefile
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | |||
| include ../Makefile.common | ||||
| 
 | ||||
| LIBHTML_OBJS = \
 | ||||
|     Node.o \
 | ||||
|     ParentNode.o \
 | ||||
|     Element.o \
 | ||||
|     Document.o \
 | ||||
|     Text.o \
 | ||||
|     Parser.o \
 | ||||
|     Dump.o | ||||
| 
 | ||||
| TEST_OBJS = test.o | ||||
| TEST_PROGRAM = tho | ||||
| 
 | ||||
| OBJS = $(LIBHTML_OBJS) $(TEST_OBJS) | ||||
| 
 | ||||
| LIBRARY = libhtml.a | ||||
| DEFINES += -DUSERLAND | ||||
| 
 | ||||
| all: $(LIBRARY) $(TEST_PROGRAM) | ||||
| 
 | ||||
| $(TEST_PROGRAM): $(TEST_OBJS) $(LIBRARY) | ||||
| 	$(LD) -o $@ $(LDFLAGS) -L. $(TEST_OBJS) -lhtml -lgui -lcore -lc | ||||
| 
 | ||||
| $(LIBRARY): $(LIBHTML_OBJS) | ||||
| 	@echo "LIB $@"; $(AR) rcs $@ $(LIBHTML_OBJS) | ||||
| 
 | ||||
| .cpp.o: | ||||
| 	@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $< | ||||
| 
 | ||||
| -include $(OBJS:%.o=%.d) | ||||
| 
 | ||||
| clean: | ||||
| 	@echo "CLEAN"; rm -f $(TEST_PROGRAM) $(LIBRARY) $(OBJS) *.d | ||||
| 
 | ||||
| install: $(LIBRARY) | ||||
| 	mkdir -p ../Root/usr/include/LibHTML | ||||
| 	# Copy headers | ||||
| 	rsync -r -a --include '*/' --include '*.h' --exclude '*' . ../Root/usr/include/LibHTML | ||||
| 	# Install the library | ||||
| 	cp $(LIBRARY) ../Root/usr/lib | ||||
| 
 | ||||
							
								
								
									
										24
									
								
								LibHTML/Node.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								LibHTML/Node.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,24 @@ | |||
| #include <AK/Retained.h> | ||||
| #include <LibHTML/Node.h> | ||||
| 
 | ||||
| Node::Node(NodeType type) | ||||
|     : m_type(type) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| Node::~Node() | ||||
| { | ||||
| } | ||||
| 
 | ||||
| void Node::retain() | ||||
| { | ||||
|     ASSERT(m_retain_count); | ||||
|     ++m_retain_count; | ||||
| } | ||||
| 
 | ||||
| void Node::release() | ||||
| { | ||||
|     ASSERT(m_retain_count); | ||||
|     if (!--m_retain_count) | ||||
|         delete this; | ||||
| } | ||||
							
								
								
									
										41
									
								
								LibHTML/Node.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								LibHTML/Node.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,41 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <AK/Retained.h> | ||||
| #include <AK/Vector.h> | ||||
| 
 | ||||
| enum class NodeType : unsigned { | ||||
|     INVALID = 0, | ||||
|     ELEMENT_NODE = 1, | ||||
|     TEXT_NODE = 3, | ||||
|     DOCUMENT_NODE = 9, | ||||
| }; | ||||
| 
 | ||||
| class Node { | ||||
| public: | ||||
|     virtual ~Node(); | ||||
| 
 | ||||
|     void retain(); | ||||
|     void release(); | ||||
|     int retain_count() const { return m_retain_count; } | ||||
| 
 | ||||
|     NodeType type() const { return m_type; } | ||||
|     bool is_element() const { return type() == NodeType::ELEMENT_NODE; } | ||||
|     bool is_text() const { return type() == NodeType::TEXT_NODE; } | ||||
|     bool is_document() const { return type() == NodeType::DOCUMENT_NODE; } | ||||
|     bool is_parent_node() const { return is_element() || is_document(); } | ||||
| 
 | ||||
|     Node* next_sibling() { return m_next_sibling; } | ||||
|     Node* previous_sibling() { return m_previous_sibling; } | ||||
|     void set_next_sibling(Node* node) { m_next_sibling = node; } | ||||
|     void set_previous_sibling(Node* node) { m_previous_sibling = node; } | ||||
| 
 | ||||
| protected: | ||||
|     explicit Node(NodeType); | ||||
| 
 | ||||
|     int m_retain_count { 1 }; | ||||
|     NodeType m_type { NodeType::INVALID }; | ||||
|     Vector<Node*> m_children; | ||||
|     Node* m_next_sibling { nullptr }; | ||||
|     Node* m_previous_sibling { nullptr }; | ||||
| }; | ||||
| 
 | ||||
							
								
								
									
										10
									
								
								LibHTML/ParentNode.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								LibHTML/ParentNode.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | |||
| #include <LibHTML/ParentNode.h> | ||||
| 
 | ||||
| void ParentNode::append_child(Retained<Node> node) | ||||
| { | ||||
|     if (m_last_child) | ||||
|         m_last_child->set_next_sibling(node.ptr()); | ||||
|     m_last_child = &node.leak_ref(); | ||||
|     if (!m_first_child) | ||||
|         m_first_child = m_last_child; | ||||
| } | ||||
							
								
								
									
										32
									
								
								LibHTML/ParentNode.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								LibHTML/ParentNode.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <LibHTML/Node.h> | ||||
| 
 | ||||
| class ParentNode : public Node { | ||||
| public: | ||||
|     void append_child(Retained<Node>); | ||||
| 
 | ||||
|     Node* first_child() { return m_first_child; } | ||||
|     Node* last_child() { return m_last_child; } | ||||
| 
 | ||||
|     template<typename F> void for_each_child(F); | ||||
| 
 | ||||
| protected: | ||||
|     explicit ParentNode(NodeType type) | ||||
|         : Node(type) | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     Node* m_first_child { nullptr }; | ||||
|     Node* m_last_child { nullptr }; | ||||
| }; | ||||
| 
 | ||||
| template<typename F> | ||||
| inline void ParentNode::for_each_child(F func) | ||||
| { | ||||
|     for (auto* node = first_child(); node; node = node->next_sibling()) { | ||||
|         func(*node); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										32
									
								
								LibHTML/Parser.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								LibHTML/Parser.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | |||
| #include <LibHTML/Element.h> | ||||
| #include <LibHTML/Parser.h> | ||||
| #include <LibHTML/Text.h> | ||||
| 
 | ||||
| static Retained<Element> create_element(const String& tag_name) | ||||
| { | ||||
|     return adopt(*new Element(tag_name)); | ||||
| } | ||||
| 
 | ||||
| Retained<Document> parse(const String& html) | ||||
| { | ||||
|     auto doc = adopt(*new Document); | ||||
| 
 | ||||
|     auto head = create_element("head"); | ||||
|     auto title = create_element("title"); | ||||
|     auto title_text = adopt(*new Text("Page Title")); | ||||
|     title->append_child(title_text); | ||||
|     head->append_child(title); | ||||
| 
 | ||||
|     doc->append_child(head); | ||||
| 
 | ||||
|     auto body = create_element("body"); | ||||
|     auto h1 = create_element("h1"); | ||||
|     auto h1_text = adopt(*new Text("Hello World!")); | ||||
| 
 | ||||
|     h1->append_child(h1_text); | ||||
|     body->append_child(h1); | ||||
|     doc->append_child(body); | ||||
| 
 | ||||
|     return doc; | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										7
									
								
								LibHTML/Parser.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								LibHTML/Parser.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,7 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <AK/Retained.h> | ||||
| #include <LibHTML/Document.h> | ||||
| 
 | ||||
| Retained<Document> parse(const String& html); | ||||
| 
 | ||||
							
								
								
									
										13
									
								
								LibHTML/Text.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								LibHTML/Text.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | |||
| #include <LibHTML/Text.h> | ||||
| 
 | ||||
| Text::Text(const String& data) | ||||
|     : Node(NodeType::TEXT_NODE) | ||||
|     , m_data(data) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| Text::~Text() | ||||
| { | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										15
									
								
								LibHTML/Text.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								LibHTML/Text.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,15 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <AK/AKString.h> | ||||
| #include <LibHTML/Node.h> | ||||
| 
 | ||||
| class Text final : public Node { | ||||
| public: | ||||
|     explicit Text(const String&); | ||||
|     virtual ~Text() override; | ||||
| 
 | ||||
|     const String& data() const { return m_data; } | ||||
| 
 | ||||
| private: | ||||
|     String m_data; | ||||
| }; | ||||
							
								
								
									
										10
									
								
								LibHTML/test.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								LibHTML/test.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | |||
| #include <LibHTML/Dump.h> | ||||
| #include <LibHTML/Element.h> | ||||
| #include <LibHTML/Parser.h> | ||||
| 
 | ||||
| int main() | ||||
| { | ||||
|     String html = "<html><head><title>my page</title></head><body><h1>Hi there</h1><p>Hello World!</p></body></html>"; | ||||
|     auto doc = parse(html); | ||||
|     dump_tree(doc); | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling