Skip to content

Commit

Permalink
Add small CSS features
Browse files Browse the repository at this point in the history
  • Loading branch information
KevinL10 committed Sep 3, 2023
1 parent ae6461f commit f3c565d
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 66 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ A web browser implemented from scratch in Python.
Adapted from [browser.engineering](https://browser.engineering/).

### Todo:

- [] Fix comment handling in HTML and CSS parser
- [] `<pre>` and `<code>`
- [] Browser resizing
Expand Down
7 changes: 4 additions & 3 deletions browser/graphics.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
DrawText,
DrawOutline,
get_font,
print_layout
)
from browser.utils import tree_to_list
from browser.request import URL
Expand Down Expand Up @@ -95,7 +96,7 @@ def load(self, url):
]

rules = self.default_style_sheet.copy()

for link in links:
head, body = url.resolve(link).request()
rules.extend(CSSParser(body).parse())
Expand All @@ -107,7 +108,8 @@ def load(self, url):
self.document = DocumentLayout(self.node)
self.document.layout()

# print_layout(self.document)
# print_tree(self.node)
print_layout(self.document)

# The display_list consists of commands like DrawText and DrawRect
self.display_list = []
Expand Down Expand Up @@ -141,7 +143,6 @@ def __init__(self):
self.window.bind("<Key>", self.handle_key)
self.window.bind("<Return>", self.handle_enter)


self.tabs = []
self.active_tab = None

Expand Down
26 changes: 19 additions & 7 deletions browser/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ def execute(self, scroll, canvas: tkinter.Canvas):
fill=self.color,
)


class DrawLine:
def __init__(self, x1, y1, x2, y2, color, thickness):
self.top = y1
Expand All @@ -69,11 +70,15 @@ def __init__(self, x1, y1, x2, y2, color, thickness):

def execute(self, scroll, canvas):
canvas.create_line(
self.left, self.top - scroll,
self.right, self.bottom - scroll,
fill=self.color, width=self.thickness,
self.left,
self.top - scroll,
self.right,
self.bottom - scroll,
fill=self.color,
width=self.thickness,
)


class DrawOutline:
def __init__(self, x1, y1, x2, y2, color, thickness):
self.top = y1
Expand All @@ -85,14 +90,15 @@ def __init__(self, x1, y1, x2, y2, color, thickness):

def execute(self, scroll, canvas):
canvas.create_rectangle(
self.left, self.top - scroll,
self.right, self.bottom - scroll,
self.left,
self.top - scroll,
self.right,
self.bottom - scroll,
width=self.thickness,
outline=self.color,
)



# Represents the layout of a block element
class BlockLayout:
BLOCK_ELEMENTS = [
Expand Down Expand Up @@ -194,6 +200,10 @@ def layout(self):
previous = None
# Create a BlockLayout for every child in the HTML tree of the current node
for child in self.node.children:
# Don't add the <head> tag to the layout tree
if isinstance(child, Element) and child.tag == "head":
continue

next = BlockLayout(child, self, previous)
self.children.append(next)
previous = next
Expand Down Expand Up @@ -322,12 +332,14 @@ def __repr__(self):
# Layout the current text object by computing its font, x, width, and height
# Note: the text's y coordinate is already computed by the LineLayout object
def layout(self):
# Set the font for the current word
weight = self.node.style["font-weight"]
style = self.node.style["font-style"]
font_size = int(float(self.node.style["font-size"][:-2]) * 0.75)

# Convert to tkinter
if style == "normal":
style = "roman"

self.font = get_font(font_size, weight, style)

# Compute the position and dimensions of the word
Expand Down
21 changes: 17 additions & 4 deletions browser/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ def finish(self):


def print_tree(node, indent=0):
print(" " * indent, node, node.style, getattr(node, "attributes", ""))
print(" " * indent, node)
for child in node.children:
print_tree(child, indent + 2)

Expand Down Expand Up @@ -293,21 +293,28 @@ def style(node, rules):
for property, value in pairs.items():
node.style[property] = value

# print(rules)
# Resolve font sizes
parent_px = (
float(node.parent.style["font-size"][:-2])
parent_font_size = (
node.parent.style["font-size"]
if node.parent
else INHERITED_PROPERTIES["font-size"]
)

parent_px = float(parent_font_size[:-2])

if node.style["font-size"].endswith("%"):
node_pct = float(node.style["font-size"][:-1]) / 100
node.style["font-size"] = str(parent_px * node_pct) + "px"
# TODO: handle rem and em separately
elif node.style["font-size"].endswith("em"):
node_em = float(node.style["font-size"][:-2])
node.style["font-size"] = str(node_em * parent_px) + "px"

# TODO: do we need to support floats?
if node.style["font-weight"].isnumeric():
weight = int(node.style["font-weight"])
node.style["font-weight"] = "normal" if weight < (400 + 700) / 2 else "bold"

for child in node.children:
style(child, rules)

Expand All @@ -321,6 +328,9 @@ def __init__(self, tag):
def matches(self, node):
return isinstance(node, Element) and self.tag == node.tag

def __repr__(self):
return f"<TagSelector {self.tag}>"


class DescendantSelector:
def __init__(self, ancestor, descendant):
Expand All @@ -339,6 +349,9 @@ def matches(self, node):

return False

def __repr__(self):
return f"<TagSelector {self.ancestor} {self.descendant}>"


# Returns the priority of the given CSS rule.
# Higher priority should override lower priority.
Expand Down
2 changes: 1 addition & 1 deletion browser/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def request(self, num_redirects=0):
type=socket.SOCK_STREAM,
proto=socket.IPPROTO_TCP,
)

print(self.host)
s.connect((self.host, self.port))

if self.scheme == "https":
Expand Down
58 changes: 8 additions & 50 deletions tests/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,60 +4,18 @@
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>

<link href="pre-blue.css" rel="stylesheet" />


<title>Home</title>
</head>
<body>
<h1>
Title!
Welcome!
</h1>
<h2>
An h2 header
</h2>
<h3>
An h3 header
</h3>

<a>
This is some a text
</a>
Hi! this is a test

<a href="https://example.com">
Click this link to visit example.com!
</a>
<h1> title</h1>
<b>bold text</b>

<i>italic text</i>
<p style="background-color:green;">
GREEN TEXT
</p>
<p>
<big>this is a big text!</big>
</p>


<b>bold again !</b>
<pre>
some pre text
</pre>
<small>
this is a small paragraph!
</small>
<big>
big big big
</big>

some text <sub>tm</sub>
<pre>
this is some code
</pre>
<div>
<p>Our browser supports HTML tags like <b>bold text</b> and <i>italics.</i></p>
<br>
<p>We can also change the <span style="color:red;">color</span> and <span style="font-size:20px;">size</span> of words with CSS!</p>
</div>


<abbr>CSS</abbr> (Cascading Style Sheets)
<a href="https://example.com">Check out another example page here!</a>
</body>
</html>

0 comments on commit f3c565d

Please sign in to comment.