`DOM::XMLHttpRequest` now checks if the requested URL has the same
`Origin` as the requesting `Document`. If the requested URL is in
violation of SOP the request is rejected and an "error" `DOM::Event`
is dispatched.
Ref-counted objects must not be stack allocated. Make DOM::Document's
constructor private to avoid this issue. (I wish we could mark classes
as heap-only..)
When a document reaches ref_count==0, we will now remove all of the
descendant nodes from the document, and also break all the explicit
links (such as the currently hovered element.)
Basically, DOM nodes will keep the document alive even after the
document reaches ref_count==0. This allows JS wrappers to stay alive
and keep the document alive as well. This matches the behavior of
at least some other browsers.
This patch also adds a bunch of sanity checking assertions around
DOM teardown, to help catch mistakes in the future.
Fixes#3771.
DOM::Node now points to its LayoutNode with a WeakPtr.
LayoutNode points to its DOM::Node and DOM::Document with RefPtrs.
Layout trees come and go in response to various events, so the DOM tree
already has to deal with that. The DOM should always live at least as
long as the layout tree, so this patch enforces that assumption by
making layout nodes keep their corresponding DOM objects alive.
This may not be optimal, but it removes a lot of ambiguous raw pointer
action which is not worth accomodating.
Oops, it seems like I implemented all of the "nodes keep the document
alive" mechanism except the part where the functions are actually
called. :^)
Fixes#3811.
Instead of just ripping out the root of the layout tree from its RefPtr
in Document, actually go through the DOM and gather up all the layout
nodes. Then destroy them all in one swoop.
Also, make sure to do this when detaching Document from Frame,
to enforce the invariant that layout only occurs in framed documents.
These happen right after "DOMContentLoaded" for now, which is incorrect
since they should really wait until subresources have loaded.
However, this makes a bunch of things work already so let's do it.
We were never wrapping and using the actual DOM::Event but instead
wrapped the *target* twice and passed it to the event listener callback,
as this value and as argument.
This unbreaks "fun demo" and "canvas path quadratic curve test" - and
event dispatching in general, of course :^)
Fixes#3721.
In addition to being reference-counted, all nodes that are part of a
document must also keep the document alive.
This is achieved by adding a second ref-count to the Document object
and incrementing/decrementing it whenever a node is created/destroyed
in that document.
This brings us much closer to a proper DOM lifetime model, although
the JS bindings still need more work.
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. :^)
Taking a big step towards a world of multiple global object, this patch
adds a new JS::VM object that houses the JS::Heap.
This means that the Heap moves out of Interpreter, and the same Heap
can now be used by multiple Interpreters, and can also outlive them.
The VM keeps a stack of Interpreter pointers. We push/pop on this
stack when entering/exiting execution with a given Interpreter.
This allows us to make this change without disturbing too much of
the existing code.
There is still a 1-to-1 relationship between Interpreter and the
global object. This will change in the future.
Ultimately, the goal here is to make Interpreter a transient object
that only needs to exist while you execute some code. Getting there
will take a lot more work though. :^)
Note that in LibWeb, the global JS::VM is called main_thread_vm(),
to distinguish it from future worker VM's.
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.)
For now, the new DOM::EventDispatcher is very simple, it just iterates
over the set of listeners on an EventTarget and invokes the callbacks
as it goes.
This simplifies EventTarget subclasses since they no longer have to
implement the callback mechanism themselves.
The fact that a `MarkedValueList` had to be created was just annoying,
so here's an alternative.
This patchset also removes some (now) unneeded MarkedValueList.h includes.
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.
Reading the property has a few warts (see FIXMEs in the included
tests), but with this the timestamps on http://45.33.8.238/
get localized :^)
Since the Date() constructor currently ignores all arguments,
they don't get localized correctly but are all set to the current
time, but hey, it's still progress from a certain point of view.
...{All} to ParentNode. Exposes createDocumentFragment and
createComment on Document. Stubs out the document.body setter.
Also adds ParentNode back :^).
This requires moving remove_all_children() from ParentNode to
Node, which makes ParentNode.cpp empty, so remove it.
It also co-opts the existing Node::text_content() method and
tweaks it slightly to fit the semantics of Node.textContent.
You can now cycle through focusable elements (currently only hyperlinks
are focusable) with the Tab key.
The focus outline is rendered in a new FocusOutline paint phase.
Decorated Interpreter::call() with [[nodiscard]] to provoke thinking
about the returned value at each call site. This is definitely not
perfect and we should really start thinking about slimming down the
public-facing LibJS interpreter API.
Fixes#3136.
We don't want to carry over exceptions across multiple
Document::run_javascript() calls as Interpreter::run() and every of its
exception checks will get confused - in this case there would be an
exception, but not because a certain action failed.
Real-life example:
<script>var a = {}; a.test()</script>
<script>alert("It worked!")</script>
The above HTML will invoke Document::run_javascript() twice, the first
call will result in a TypeError, which is still stored during the second
call. The interpreter will eventually call the following functions (in
order) for the alert() invocation:
- Identifier::execute()
- Interpreter::get_variable()
- Object::get() (on the global object)
That last Object::get() call has an exception check which is triggered
as we still carry around the exception from earlier - and eventually
returns an empty value.
Long story short, the second script will wrongly fail with
"ReferenceError, 'alert' is not defined".
Fixes#3091.
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.
Now that document element returns a generic DOM element, we need to
make sure head and body get a html element.
The spec just says to check if the document element is a html element,
so let's do that.
Also change DOM::Document::document_element() to return an Element*
and not an HTML::HTMLHtmlElement since that's not the only kind of
documentElement we might encounter.
HTMLElement is the only interface that includes ElementContentEditable
in the HTML specification. This makes sense, as Element is also a base
class for elements in other specifications such as SVG,
which definitely shouldn't be editable.
Also adds a test for the attribute based on what Andreas did in the
video that added it.