mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 07:58:11 +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