1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 08:08:12 +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:
Andreas Kling 2019-06-15 18:55:47 +02:00
parent 01d1aee922
commit a67e823838
19 changed files with 329 additions and 0 deletions

View file

@ -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... "

View file

@ -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
View file

@ -0,0 +1,4 @@
*.o
*.d
libhtml.a
tho

11
LibHTML/Document.cpp Normal file
View file

@ -0,0 +1,11 @@
#include <LibHTML/Document.h>
Document::Document()
: ParentNode(NodeType::DOCUMENT_NODE)
{
}
Document::~Document()
{
}

13
LibHTML/Document.h Normal file
View 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
View 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
View file

@ -0,0 +1,5 @@
#pragma once
class Node;
void dump_tree(Node&);

12
LibHTML/Element.cpp Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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);
}