Instead of invoking the CSS parser every time we compute the style for
an element that has a "style" attribute, we now cache the result of
parsing the inline style whenever the "style" attribute is set.
This is a nice boost to relayout performance since we no longer hit the
CSS parser at all.
Bring the names of various boxes closer to spec language. This should
hopefully make things easier to understand and hack on. :^)
Some notable changes:
- LayoutNode -> Layout::Node
- LayoutBox -> Layout::Box
- LayoutBlock -> Layout::BlockBox
- LayoutReplaced -> Layout::ReplacedBox
- LayoutDocument -> Layout::InitialContainingBlockBox
- LayoutText -> Layout::TextNode
- LayoutInline -> Layout::InlineNode
Note that this is not strictly a "box tree" as we also hang inline/text
nodes in the same tree, and they don't generate boxes. (Instead, they
contribute line box fragments to their containing block!)
This is a first (huge) step towards modernizing the layout architecture
and bringing it closer to spec language.
Layout is now performed by a stack of formatting contexts, operating on
the box tree (or layout tree, if you will.)
There are currently three types of formatting context:
- BlockFormattingContext (BFC)
- InlineFormattingContext (IFC)
- TableFormattingContext (TFC)
Document::layout() creates the initial BlockFormattingContext (BFC)
which lays out the initial containing block (ICB), and then we recurse
through the tree, creating BFC, IFC or TFC as appropriate and handing
over control at the context boundaries.
The majority of this patch is just refactoring the old logic spread out
in LayoutBlock and LayoutTableRowGroup, and turning into these context
classes instead. A lot more cleanup will be needed.
There are many architectural wins here, the main one being that layout
is no longer performed by boxes themselves, which gives us much greater
flexibility in the outer/inner layout of a given box.
This patch introduces the HighResolutionTime namespace which is home to
the Performance object (exposed via window.performance)
performance.now() is currently the only function, and it returns the
number of milliseconds since the window object was constructed. :^)
This will be inherited by documents and workers, to provide a common
abstraction for script execution. (We don't have workers yet, but we
might as well make this little space for them now to simplify things
down the road.)
Following in the footsteps of <input type=checkbox>, this patch adds
LayoutButton which implements a basic push button using LibGfx styling
primitives.
Note that there is currently no way to display them as we can't
currently clone nodes.
Adds special case for templates for dumping to console.
Doesn't add it to the DOM inspector as I'm not sure how to do it.
...{All} to ParentNode. Exposes createDocumentFragment and
createComment on Document. Stubs out the document.body setter.
Also adds ParentNode back :^).
This is mostly to get the grunt work of the way. This is split up into
multiple commits to hopefully make it more manageable to review.
Note that these are not full implementations, and the bindings mostly
get the low hanging fruit.
Also implements some attributes that I kept out because they had
dashes in them. Therefore, this closes#2905.
Note that these aren't full implementations of the bindings. This
mostly implements the low hanging fruit (namely, basic reflections)
There are some attributes that should be USVString instead of
DOMString. However, USVString is a slightly different definition
of DOMString, so it should suffice for now.
LibWeb keeps growing and the Web namespace is filling up fast.
Let's put DOM stuff into Web::DOM, just like we already started doing
with SVG stuff in Web::SVG.
This allows us to determine which mode to render the page in.
Exposes "doctype" and "compatMode" on Document.
Exposes "name", "publicId" and "systemId" on DocumentType.
This patch adds a Web::Timer object that represents a single timer
registration made with window.setTimeout() or window.setInterval().
All live timers are owned by the DOM Window object.
The timers can be stopped via clearTimeout() or clearInterval().
Note that those API's are actually interchangeable, but we have to
support both.
"Paint" matches what we call this in the rest of the system. Let's not
confuse things by mixing paint/render/draw all the time. I'm guilty of
this in more places..
Also rename RenderingContext => PaintContext.
To support z-ordering when painting, the layout tree now has a parallel
sparse tree of stacking contexts. The rules for which layout boxes
establish a stacking context are a bit complex, but the intent is to
encapsulate the decision making into establishes_stacking_context().
When we paint, we start from the ICB (LayoutDocument) who always has a
StackingContext and then paint the tree of StackingContexts where each
node has its children sorted by z-index.
This is pretty crude, but gets the basic job done. Note that this does
not yet support hit testing; hit testing is still done using a naive
treewalk from the root.
Previously, layout recursively performed these steps (roughly):
1. Compute own width
2. Compute own position
3. Layout in-flow children
4. Compute own height
5. Layout absolutely positioned descendants
However, step (2) was pretty inconsistent. Some things computed their
own position, others had their parent do it for them, etc.
To get closer to CSS spec language, and make things easier in general,
this patch reorganizes the algorithm into:
1. Compute own width & height
2. Compute width & height of in-flow managed descendants
3. Move in-flow managed descendants to their final position
4. Layout absolutely positioned descendants
Block layout is now driven by the containing block, which will iterate
the descendants it's responsible for. There are a lot of inefficient
patterns in this logic right now, but they can easily be replaced with
better iteration functions once we settle on a long-term architecture.
Since the ICB (LayoutDocument) is at (0, 0), it doesn't rely on a
containing block to move it into place.
This code is still evolving along with my understanding of CSS layout,
so it's likely that we'll reorganize this again sooner or later. :^)
The box tree and line boxes now all store a relative offset from their
containing block, instead of an absolute (document-relative) position.
This removes a huge pain point from the layout system which was having
to adjust offsets recursively when something moved. It also makes some
layout logic significantly simpler.
Every box can still find its absolute position by walking its chain
of containing blocks and accumulating the translation from the root.
This is currently what we do both for rendering and hit testing.
* A PageView is a view onto a Page object.
* A Page always has a main Frame (root of Frame tree.)
* Page has a PageClient. PageView is a PageClient.
The goal here is to allow building another kind of view onto
a Page while keeping the rest of LibWeb intact.
This patch introduces a caching mechanism in ResourceLoader. It's keyed
on a LoadRequest object which is what you provide to load_resource()
when you want to load a resource.
We currently never prune the cache, so resources will stay in there
forever. This is obviously not gonna stay that way, but we're just
getting started here. :^)
This should drastically reduce the number of requests when loading
some sites (like Twitter) that reuse the same images over and over.
A Resource represents a resource that we're loading, have loaded or
will soon load. Basically, it's a downloadable resource that can be
shared by multiple clients.
A typical usecase is multiple <img> elements with the same src.
In a future patch, we will try to make sure that those <img> elements
get the same Resource if possible. This will reduce network usage,
memory usage, and CPU usage. :^)
For now, this first patch simply introduces the mechanism.
You get a Resource by calling ResourceLoader::load_resource().
To get notified about changes to a Resource's load status, you inherit
from ResourceClient and implement the callbacks you're interested in.
This patch turns HTMLImageElement into a ResourceClient.
This patch adds very basic XMLHttpRequest support to LibWeb. Here's an
example that currently works:
var callback = function() { alert(this.responseText); }
var xhr = new XMLHttpRequest();
xhr.addEventListener("load", callback);
xhr.open("GET", "http://serenityos.org/~kling/test/example.txt");
xhr.send();
There are many limitations and bugs, but it's pretty dang awesome that
we have XHR. :^)