mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 21:42:43 +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/SystemServer/SystemServer mnt/bin/SystemServer | ||||||
| cp ../Servers/WindowServer/WindowServer mnt/bin/WindowServer | cp ../Servers/WindowServer/WindowServer mnt/bin/WindowServer | ||||||
| cp ../Shell/Shell mnt/bin/Shell | cp ../Shell/Shell mnt/bin/Shell | ||||||
|  | cp ../LibHTML/tho mnt/bin/tho | ||||||
| echo "done" | echo "done" | ||||||
| 
 | 
 | ||||||
| echo -n "installing shortcuts... " | 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/LookupServer" | ||||||
| build_targets="$build_targets ../Servers/WindowServer" | build_targets="$build_targets ../Servers/WindowServer" | ||||||
| build_targets="$build_targets ../LibGUI" | build_targets="$build_targets ../LibGUI" | ||||||
|  | build_targets="$build_targets ../LibHTML" | ||||||
| build_targets="$build_targets ../Userland" | build_targets="$build_targets ../Userland" | ||||||
| build_targets="$build_targets ../Applications/Terminal" | build_targets="$build_targets ../Applications/Terminal" | ||||||
| build_targets="$build_targets ../Applications/FontEditor" | 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