Skip to content

Commit

Permalink
LibHTML: Start working on a simple HTML library.
Browse files Browse the repository at this point in the history
I'd like to have rich text, and we might as well use HTML for that. :^)
  • Loading branch information
awesomekling committed Jun 15, 2019
1 parent 01d1aee commit a67e823
Show file tree
Hide file tree
Showing 19 changed files with 329 additions and 0 deletions.
1 change: 1 addition & 0 deletions Kernel/build-root-filesystem.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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... "
Expand Down
1 change: 1 addition & 0 deletions Kernel/makeall.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions LibHTML/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.o
*.d
libhtml.a
tho
11 changes: 11 additions & 0 deletions LibHTML/Document.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include <LibHTML/Document.h>

Document::Document()
: ParentNode(NodeType::DOCUMENT_NODE)
{
}

Document::~Document()
{
}

13 changes: 13 additions & 0 deletions LibHTML/Document.h
Original file line number Diff line number Diff line change
@@ -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 changes: 26 additions & 0 deletions LibHTML/Dump.cpp
Original file line number Diff line number Diff line change
@@ -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 changes: 5 additions & 0 deletions LibHTML/Dump.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#pragma once

class Node;

void dump_tree(Node&);
12 changes: 12 additions & 0 deletions LibHTML/Element.cpp
Original file line number Diff line number Diff line change
@@ -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 changes: 30 additions & 0 deletions LibHTML/Element.h
Original file line number Diff line number Diff line change
@@ -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 changes: 42 additions & 0 deletions LibHTML/Makefile
Original file line number Diff line number Diff line change
@@ -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 changes: 24 additions & 0 deletions LibHTML/Node.cpp
Original file line number Diff line number Diff line change
@@ -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 changes: 41 additions & 0 deletions LibHTML/Node.h
Original file line number Diff line number Diff line change
@@ -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 changes: 10 additions & 0 deletions LibHTML/ParentNode.cpp
Original file line number Diff line number Diff line change
@@ -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 changes: 32 additions & 0 deletions LibHTML/ParentNode.h
Original file line number Diff line number Diff line change
@@ -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 changes: 32 additions & 0 deletions LibHTML/Parser.cpp
Original file line number Diff line number Diff line change
@@ -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 changes: 7 additions & 0 deletions LibHTML/Parser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#pragma once

#include <AK/Retained.h>
#include <LibHTML/Document.h>

Retained<Document> parse(const String& html);

13 changes: 13 additions & 0 deletions LibHTML/Text.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include <LibHTML/Text.h>

Text::Text(const String& data)
: Node(NodeType::TEXT_NODE)
, m_data(data)
{
}

Text::~Text()
{
}


15 changes: 15 additions & 0 deletions LibHTML/Text.h
Original file line number Diff line number Diff line change
@@ -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 changes: 10 additions & 0 deletions LibHTML/test.cpp
Original file line number Diff line number Diff line change
@@ -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);
}

0 comments on commit a67e823

Please sign in to comment.