From 07a9828de307dc9091804f69e281011a4eeb23a5 Mon Sep 17 00:00:00 2001 From: mjedwards Date: Tue, 15 Apr 2025 21:35:23 -0400 Subject: [PATCH 1/2] initial setup --- browser_display.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/browser_display.py b/browser_display.py index a0acdca..561c9e3 100644 --- a/browser_display.py +++ b/browser_display.py @@ -233,6 +233,11 @@ def load(self, url): self.draw() +class BlockLayout: + def __init__(self): + self.block = "" + + if __name__ == "__main__": import sys if (len(sys.argv) == 1): From 84ed747a92e34a5d879809ac222e971b0e1eadff Mon Sep 17 00:00:00 2001 From: mjedwards Date: Mon, 21 Apr 2025 22:18:35 -0400 Subject: [PATCH 2/2] continue working on building a tre layout --- __pycache__/parser.cpython-313.pyc | Bin 4364 -> 5140 bytes __pycache__/url_handler.cpython-313.pyc | Bin 7726 -> 7726 bytes browser_display.py | 147 ++++++++++++++---------- parser.py | 22 +++- 4 files changed, 110 insertions(+), 59 deletions(-) diff --git a/__pycache__/parser.cpython-313.pyc b/__pycache__/parser.cpython-313.pyc index 0341258aa6d3d8dca37c70a5c7db431661fbd943..b984e9a877b68ab370da34b223d129e57ae29986 100644 GIT binary patch delta 1664 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 diff --git a/__pycache__/url_handler.cpython-313.pyc b/__pycache__/url_handler.cpython-313.pyc index 0a1efb4584399a3616ce284150a19d88cda64ce0..7148bef6bea7659cfb262deb0f6a9d6a10db21d1 100644 GIT binary patch delta 21 bcmZ2yv(AR+GcPX}0}#X{F=lM!QIZ1yK?(&N delta 21 bcmZ2yv(AR+GcPX}0}wpt{GGm$M@bF= WIDTH - HSTEP: - # self.cursor_y += VSTEP - # self.cursor_x = HSTEP + def open_tag(self, tag): + if tag == "i": + self.style = "italic" + elif tag == "b": + self.weight = "bold" + elif tag == "small": + self.size -= 2 + elif tag == "big": + self.size += 4 + elif tag == "br": + self.flush() + def close_tag(self, tag): + if tag == "i": + self.style = "roman" + elif tag == "b": + self.weight = "normal" + elif tag == "small": + self.size += 2 + elif tag == "big": + self.size -= 4 + elif tag == "p": + self.flush() + self.cursor_y += VSTEP def word(self, word): font = get_font(self.size, self.weight, self.style) w = font.measure(word) @@ -169,7 +186,18 @@ def flush(self): self.cursor_x = HSTEP self.line = [] + def paint(self): + +class DocumentLayout: + def __init__(self, node): + self.node = node + self.parent = None + self.children = [] + def layout(self): + child = BlockLayout(self.node, self, None) + self.children.append(child) + child.layout() class Browser: def __init__(self): self.window = tkinter.Tk() @@ -229,7 +257,10 @@ def draw(self): def load(self, url): body = load(URL(url)) self.nodes = HTMLParser(body).parse() + print_tree(self.nodes) self.display_list = Layout(self.nodes).display_list + self.document = Layout(self.nodes) + self.document.layout() self.draw() diff --git a/parser.py b/parser.py index ef59750..84c2e3a 100644 --- a/parser.py +++ b/parser.py @@ -4,6 +4,8 @@ class HTMLParser: + HEAD_TAGS = ["base", "basefont", "bgsound", "noscript", "link", "meta", + "title", "style", "script"] def __init__(self, body): self.body = body self.unfinished = [] @@ -31,7 +33,8 @@ def parse(self): def add_text(self, text): if text.isspace(): return - print(self.unfinished[-1]) + + # self.implicit_tags(None) parent = self.unfinished[-1] node = Text(text, parent) parent.children.append(node) @@ -44,6 +47,8 @@ def add_tag(self, tag): if tag.startswith("!"): return + + # self.implicit_tags(tag) if tag.startswith("/"): if len(self.unfinished) == 1: @@ -83,6 +88,21 @@ def get_attributes(self, text): return tag, attributes + def implicit_tags(self, tag): + while True: + open_tags = [node.tag for node in self.unfinished] + + if open_tags == [] and tag != "html": + self.add_tag("html") + elif open_tags == ["html"] and tag not in ["head", "body", "/html"]: + if tag in self.HEAD_TAGS: + self.add_tag("head") + else: + self.add_tag("body") + + elif open_tags == ["html, head"] and tag not in ["/head"] + self.HEAD_TAGS: + self.add_tag("/head") + def print_tree(node, indent=0): print(" "*indent, node)