From the HTML spec:
Modulo platform conventions, it is suggested that the following
elements should be considered as focusable areas and be sequentially
focusable:
...
- button elements
- select elements
- textarea elements
...
Also add a spec link to the existing HTMLAnchorElement::is_focusable().
Note that this still doesn't allow triggering keyboard-focused buttons,
checkboxes, or radio buttons - we don't seem to run the expected
activation behavior for any of them.
From the HTML spec:
Modulo platform conventions, it is suggested that the following
elements should be considered as focusable areas and be sequentially
focusable:
...
- input elements whose type attribute are not in the Hidden state
...
This commit moves the regular handling of links to the anchor elements'
activation behavior, and implements a few auxiliary algorithms as
defined by the HTML specification.
Note that certain things such as javascript links, fragments and opening
a new tab are still handled directly in EventHandler, but they have been
moved to handle_mouseup so that it behaves closer to how it would if it
was entirely up-to-spec.
Specifically HTMLIFrameElement and HTMLObjectElement. HTMLEmbedElement
will gain it automatically once it's also converted to inherit from
BrowsingContextContainer.
The HTMLObjectElement spec is set up to ignore application/octet-stream
MIME types only. For this to work, we need to implement the MIME type
sniffing algorithm so that all unknown MIME types become mapped to the
application/octet-stream type. Until then, ignore all application/ MIME
types as we won't be able to display them anyways.
We were using the literal string "unknown" as the unknown MIME type,
which caused us to treat the object as a nested browsing context (as
"unknown" does not start with "image/"). Use an Optional instead to
prevent this mishap.
We currently only supported loading image data from an HTMLObjectElement
node. This adds (some) support for non-image data. A big FIXME is to
actually paint that data. We will need to make FrameBox and
NestedBrowsingContextPaintable work with HTMLObjectElement for this
(they currently only work with HTMLIFrameElement).
We will soon have two DOM nodes which contain nested browsing contexts:
HTMLIFrameElement and HTMLObjectElement. Only HTMLIFrameElement should
have its nested context created automatically upon insertion, so move
the invocation of that logic to HTMLIFrameElement.
HTMLObjectElement will need to be both a FormAssociatedElement and a
BrowsingContextContainer. Currently, both of these classes inherit from
HTMLElement. This can work in C++, but is generally frowned upon, and
doesn't play particularly well with the rest of LibWeb.
Instead, we can essentially revert commit 3bb5c62 to remove HTMLElement
from FormAssociatedElement's hierarchy. This means that objects such as
HTMLObjectElement individually inherit from FormAssociatedElement and
HTMLElement now.
Some caveats are:
* FormAssociatedElement still needs to know when the HTMLElement is
inserted into and removed from the DOM. This hook is automatically
injected via a macro now, while still allowing classes like
HTMLInputElement to also know when the element is inserted.
* Casting from a DOM::Element to a FormAssociatedElement is now a
sideways cast, rather than directly following an inheritance chain.
This means static_cast cannot be used here; but we can safely use
dynamic_cast since the only 2 instances of this already use RTTI to
verify the cast.
This is another event upon which the task to determine an object's
respresentation must be queued:
* one of the element's ancestor object elements changes to or from
showing its fallback content
For example, on Acid2, the image for the eyes is nested below an object
that is designed to fail to load. This ensures the eyes will render as
the fallback of the failed parent object.
There are a long list of conditions under which the HTMLObjectElement is
to queue an element task to load / determine an object's representation.
This handles the case where the data attribute has changed.
Much of the spec for determining the object's representation is not
implemented here. Namely, anything to do with XML documents or browser
plugins are left as FIXMEs.
This replaces the usage of `rounded_int_rect`, whose name did not
accurately reflect the rounding operation happening. For example, the
position of the rect was not rounded but floored, and the size was
pulled through `roundf` before casting to `int` which could result in
inadvertent flooring if the resulting floating point could not exactly
represent the rounded value.
We should not set the 'value' attribute when an input element's value is
changed (by the user or programmatically). Instead, we should track the
value internally and mark it with a dirty flag when it is changed.
The HTML Specification is quite tricky in this case.
Usually "have a particular element in <x> scope" mentions
"consisting of the following element types:", but in this case it's
"consisting of all element types except the following:"
Thanks to @AtkinsSJ for spotting this difference
Instead of choking on the VERIFY(document), let's just return null if
there's no active document for now. This is incorrect, but sidesteps
a frequent crash that happens on content with iframes.
I've left a FIXME about removing the hack once it's no longer needed.
We shouldn't delay the load event for scripts that we're completely
refusing to run anyway. Also, for scripts that have inline text content,
we don't need to delay them either, as they will become ready before
returning from "prepare script".
This makes the "load" event finally fire on lots of websites, including
Wikipedia. :^)
If we try loading a link element but it's reject for whatever reason
(broken URL, content filtering, etc.) make sure we don't mark that link
element as delaying the document load event.
We previously had a bug where markup with unclosed script tags caused
the document load event to be delayed indefinitely. Fix this by only
marking script elements as delaying the load event once we encounter
the script end tag.
It makes no sense to require passing a global object and doing a stack
space check in some cases where running out of stack is highly unlikely,
we can't recover from errors, and currently ignore the result anyway.
This is most commonly in constructors and when setting things up, rather
than regular function calls.
Right now the only functionality supported is getting/setting via JS
and resetting when browsing cross origin.
The HTML Specification (7.11 Browsing the web) also specifies how the
name should be restored from history entries, but we don't have those
yet.
This adds (or at least stubs-out) the following:
- display-mode
- dynamic-range
- environment-blending
- forced-colors
- horizontal-viewport-segments
- vertical-viewport-segments
- inverted-colors
- nav-controls
- prefers-contrast
- prefers-reduced-data
- prefers-reduced-motion
- prefers-reduced-transparency
- scripting
- video-color-gamut
- video-dynamic-range
The `@media (inverted-colors)` CSS that the spec requires we add to the
UA style sheet does not actually do anything for us yet since we don't
support `filter`, but it seemed sensible to include it now to avoid
forgetting later. :^)
Use the stub implementation of HTMLOptionsCollection to expose the
`option` children of `select` elements.
This fixes a JS error on openstreetmap.org, which occured when JQuery
code tried to access `options.length`:
https://github.com/jquery/jquery/blob/main/src/attributes/val.js#L121
This is a subtype of `DOM::HTMLCollection` that only holds
`HTMLOptionElement`s. In this stub implementation only `item`,
`namedItem` and `length`, inherited from HTMLCollection, are exposed.
This is good enough for applications that only read the collection.
This doesn't have any performance benefit yet as we still do string
comparisons everytime, but it should improve once type_state() has a
better implementation.
This commit is messy due to the Paintable and Layout classes being
tangled together.
The RadioButton, CheckBox and ButtonBox classes are now subclasses of
FormAssociatedLabelableNode. This subclass separates these layout nodes
from LabelableNode, which is also the superclass of non-form associated
labelable nodes (Progress).
ButtonPaintable, CheckBoxPaintable and RadioButtonPaintable no longer
call events on DOM nodes directly from their mouse event handlers;
instead, all the functionality is now directly in EventHandler, which
dispatches the related events. handle_mousedown and related methods
return a bool indicating whether the event handling should proceed.
Paintable classes can now return an alternative DOM::Node which should
be the target of the mouse event. Labels use this to indicate that the
labeled control should be the target of the mouse events.
HTMLInputElement put its activation behavior on run_activation_behavior,
which wasn't actually called anywhere and had to be manually called by
other places. We now use activation_behavior which is used by
EventDispatcher.
This commit also brings HTMLInputElement closer to spec by removing the
did_foo functions that did ad-hoc event dispatching and unifies the
behavior under run_input_activation_behavior.
Previously, we were creating a user-agent shadow tree when constructing
a layout tree. This meant that we did DOM manipulation (and consequently
style invalidation) during layout tree construction, which made things
very hard to reason about in Layout::TreeBuilder.
Simply everything by simply creating the UA shadow tree when the input
element inserted into a parent node instead.
Input events have nothing to do with layout, so let's not send them to
layout nodes.
The job of Paintable starts to become clear. It represents a paintable
item that can be rendered into the viewport, which means it can also
be targeted by the mouse cursor.
The "paintable" state in Layout::Box was actually not safe to access
until after layout had been performed.
As a first step towards making this harder to mess up accidentally,
this patch moves painting information from Layout::Box to a new class:
Painting::Box. Every layout can have a corresponding paint box, and
it holds the final used metrics determined by layout.
The paint box is created and populated by FormattingState::commit().
I've also added DOM::Node::paint_box() as a convenient way to access
the paint box (if available) of a given DOM node.
Going forward, I believe this will allow us to better separate data
that belongs to layout vs painting, and also open up opportunities
for naturally invalidating caches in the paint box (since it's
reconstituted by every layout.)
Not sure why these are doubles in the IDL definition, both the IDL in
the spec and the implementation in the CanvasRenderingContext2D class
use integers.
Also add support for HTMLCanvasElement for the image parameter, leading
to replacing HTMLImageElement with the CanvasImageSource Variant type.
Also stub out the 'check the usability of the image argument' and 'is
not origin-clean' operations, while taking into consideration that these
can throw (and require DOM::ExceptionOr).
Services expect cookies to be submitted with forms, especially login
screens.
Allows us to sign in to GitHub (including two factor authentication)
and start using it!
This allows us to submit forms from <button> elements and not just
<input type="submit">
This allows Discord to progress past the username registration :^)
This makes it available for all form associated elements and not just
select and input elements. It also makes it more spec compliant,
especially around the form attribute.
The main thing missing is re-associating form elements with a form
attribute when the form attribute changes or an element with an ID
is inserted/removed or has its ID changed.
A top level browsing context is a browsing context with no parent
browsing context.
However, we considered a top level browsing context to be a browsing
context with no associated browsing context container.
We now validate that the provided tag names are valid XML tag names,
and otherwise throw an "invalid character" DOM exception.
2% progression on ACID3. :^)
Note that we implement .elements as a HTMLCollection for now, instead of
the correct HTMLFormControlsCollection subclass. This covers most
use-cases already.
1% progression on ACID3. :^)
This API now follows the spec a bit more closely, with regards to the
event being dispatched. There are still FIXME's but this is already an
improvement.
2% progression on ACID3. :^)
This necessitated making HTMLParser ref-counted, and having it register
itself with Document when created. That makes it possible for scripts to
add new input at the current parser insertion point.
There is now a reference cycle between Document and HTMLParser. This
cycle is explicitly broken by calling Document::detach_parser() at the
end of HTMLParser::run().
This is a huge progression on ACID3, from 31% to 49%! :^)
This implements basic support for dynamic markup insertion, adding
* Document::open()
* Document::write(Vector<String> const&)
* Document::writeln(Vector<String> const&)
* Document::close()
The HTMLParser is modified to make it possible to create a
script-created parser which initially only contains a HTMLTokenizer
without any data. Aditionally the HTMLParser::run method gains an
overload which does not modify the Document and does not run
HTMLParser::the_end() so that we can reenter the parser at a later time.
Furthermore all FIXMEs that consern the insertion point are implemented
wich is defined in the HTMLTokenizer. Additionally the following
member-variables of the HTMLParser are now exposed by getter funcions:
* m_tokenizer
* m_aborted
* m_script_nesting_level
The HTMLTokenizer is modified so that it contains an insertion
point which keeps track of where the next input from the Document::write
functions will be inserted. The insertion point is implemented as the
charakter offset into m_decoded_input and a boolean describing if the
insertion point is defined. Functions to update, check and {re}store the
insertion point are also added.
The function HTMLTokenizer::insert_eof is added to tell a script-created
parser that document::close was called and HTMLParser::the_end() should
be called.
Lastly an explicit default constructor is added to HTMLTokenizer to
create a empty HTMLTokenizer into which data can be inserted.
Also, update the expected hash in the LibWeb TestHTMLTokenizer
regression test.
This is due to the "This comment has a few too many dashes." comment
token being updated.
Newline normalization will replace \r and \r\n with \n.
The spec specifically states
> Before the tokenization stage, the input stream must be preprocessed
> by normalizing newlines.
wheras this is implemented the processing during the tokenization
itself.
This should still exhibit the same behaviour, while keeping the
tokenization logic in the same place.
In 'NamedCharacterReference' we attempt to lookup the code point by a
identifier, eg apos; becomes '
This is done by passing the entire rest of the document to the
`HTML::code_points_from_entity` function.
However, before this change we didn't sent the final character which
meant if the document ended in a named character reference the lookup
would fail.
The entry we get from the active formatting elements list during the
Rewind step of "reconstruct the active formatting elements" can be a
marker. Previously we assumed it was not a marker, which can trigger
an assertion failure with certain malformed HTML.
If the entry in this step is a marker, the spec simply ignores it.
This is step 6 of the algorithm.
This also makes the index unsigned, as this algorithm is a no-op if
the list is empty.
Additionally, this also adds spec comments to this algorithm.
Fixes#12668.
This patch adds a default padding around the contents of text <input>
elements. It adds these defaults to the existing style attribute in
'HTMLInputElement::create_shadow_tree_if_needed()'.
Use a default padding for text <input> elements:
- padding-top and padding-bottom: 1px
- padding-left and padding-right: 2px
These values seems to align with what other browsers do.
Previously it would accept any DOMString, as we didn't support enums at
the time. Now it will only accept what's specified in the
DOMParserSupportedType enum.
This also adds spec comments to DOMParser::parse_from_string.
WebSockets got moved from the HTML standard to their own, the new
WebSockets Standard (https://websockets.spec.whatwg.org).
Move the IDL file and implementation into a new WebSockets directory and
C++ namespace accordingly.
This makes React react to checkboxes. Apparently they ignore the
"change" event in favor of "click" on checkboxes. This is a
compatibility hack for IE8.
Once we paint, it's way too late for this check to happen anyway.
Additionally, the spec's steps for retrieving the content document
assume that both the browsing context's active document and the
container's node document are non-null, which evidently isn't always the
case here, as seen by crashes on the SerenityOS 2nd and 3rd birthday
pages (I'm not sure about the details though).
Fixes#12565.
I can't imagine how this happened, but it seems we've managed to
conflate the "event listener" and "EventListener" concepts from the DOM
specification in some parts of the code.
We previously had two things:
- DOM::EventListener
- DOM::EventTarget::EventListenerRegistration
DOM::EventListener was roughly the "EventListener" IDL type,
and DOM::EventTarget::EventListenerRegistration was roughly the "event
listener" concept. However, they were used interchangeably (and
incorrectly!) in many places.
After this patch, we now have:
- DOM::IDLEventListener
- DOM::DOMEventListener
DOM::IDLEventListener is the "EventListener" IDL type,
and DOM::DOMEventListener is the "event listener" concept.
This patch also updates the addEventListener() and removeEventListener()
functions to follow the spec more closely, along with the "inner invoke"
function in our EventDispatcher.
Pages such as https://html5test.com are testing all sorts of weird,
incomplete, and wrong HTML but can be useful or at least interesting for
development - let's try to avoid crashing the process.
This is needed to access the 'adjusted current node' in the 'Markup
declaration open state'. We don't want to create a full parser for
something like syntax highlighting, so it's optional (null) by default.
If we try to <link> a stylesheet that was already cached, we'll get a
synchronous resource_did_load() callback. Because of this, it's
necessary to set up the document load event delayer *before* calling
set_resource(), as otherwise we'd be stuck without a load event forever.
This ensures that the layout information is current, even when the
scroll request happens immediately upon page load.
This fixes an issue where reloading ACID2 wouldn't scroll down to the
"#top" anchor point.
This is no longer needed as BrowsingContextContainer::content_document()
now does the right thing, and HTMLIFrameElement.contentDocument is the
only user of this attribute. Let's not invent our own mechanisms for
things that are important to get right, like same origin comparisons.
The HTML Origin spec has two similar but slightly different concepts of
origin equality: "same origin" and "same origin-domain". Let's be
explicit with the naming here :^)
Also add spec comments.
Emitting tokens on EOF caused an infinite loop, freezing the app, which
could be a bit annoying when writing an HTML comment at the end of
the file in Text Editor. :^)
Commit b193351a99 caused the HTML comments to flash when changing
the text cursor. Also, when double-clicking on a comment, the selection
started from the beginning of the file instead.
The following message was displaying when `TOKENIZER_TRACE_DEBUG`
was enabled:
(Tokenizer::nth_last_position) Invalid position requested: 4th-last
of 4. Returning (0-0).
Changing the `nth_last_position` to 3 fixes this. I'm guessing that's
because the parser is at that moment on the second hyphen of the `<!--`
string, so it has to go back only by three characters.
The difference should be between m_utf8_iterator and the
the new position, if m_prev_utf8_iterator is used one fewer
source position is popped than required.
This issue was not apparent on most pages since restore_to
used for tokens such <!doctype> that are normally
followed by a newline that resets the column to zero,
but it can be seen on pages with minified HTML.
This initial implementation stubs out the WorkerGlobalScope,
WorkerLocation and WorkerNavigator classes. It doesn't take into account
all the things that actually need passed into the constructors for these
objects, nor the extra abstract operations that need to be performed on
them by the rest of the Browser infrastructure. However, it does create
bindings that compile and link :^)
While trying to get http://lite.duckduckgo.com to work in the Browser I
noticed that we kept on getting 400 (Bad Request) errors when you click
the "Search" button for a request.
After turning on `JOB_DEBUG` to see what headers we were sending it
turned out that we were actually setting `Content-Length` twice once
in LibWeb, and again when the request is handled by LibHTTP.
Since LibHTTP transparently handles this now, we can avoid it in LibWeb.
This is a naive-but-somewhat-functional initial implementation of
HTML Storage.
Note that there is no persistence yet, everything is in-process only,
and one local Storage object per origin.
This overrides the JS host hooks to follow the spec for queuing
promises, making/calling job callbacks, unhandled promise rejection
handling and FinalizationRegistry queuing.
This also allows us to drop the on_call_stack_emptied hook in
Document::interpreter().
This isn't perfect (especially the global object situation in
activate_event_handler), but I believe it's in a much more complete
state now :^)
This fixes the issue of crashing in prepare_for_ordinary_call with the
`i < m_size` crash, as it now uses the IDL callback functions which
requires the Environment Settings Object. The environment settings
object for the callback is fetched at the time the callback is created,
for example, WrapperGenerator gets the incumbent settings object for
the callback at the time of wrapping. This allows us to remove passing
in ScriptExecutionContext into EventTarget's constructor.
With this, we can now drop ScriptExecutionContext.
The new event target implementation requires us to downcast an
EventTarget to a FormAssociatedElement to check if the current Element
EventTarget has a form owner to setup a with scope for the form owner.
This also makes all form associated elements inherit from
FormAssociatedElement where it was previously missing.
https://html.spec.whatwg.org/#form-associated-element
The environment settings object is effectively the context a piece of
script is running under, for example, it contains the origin,
responsible document, realm, global object and event loop for the
current context. This effectively replaces ScriptExecutionContext, but
it cannot be removed in this commit as EventTarget still depends on it.
https://html.spec.whatwg.org/multipage/webappapis.html#environment-settings-object
This commit removes all exception related code:
Remove VM::exception(), VM::throw_exception() etc. Any leftover
throw_exception calls are moved to throw_completion.
The one method left is clear_exception() which is now a no-op. Most of
these calls are just to clear whatever exception might have been thrown
when handling a Completion. So to have a cleaner commit this will be
removed in a next commit.
It also removes the actual Exception and TemporaryClearException classes
since these are no longer used.
In any spot where the exception was actually used an attempt was made to
preserve that behavior. However since it is no longer tracked by the VM
we cannot access exceptions which were thrown in previous calls.
There are two such cases which might have different behavior:
- In Web::DOM::Document::interpreter() the on_call_stack_emptied hook
used to print any uncaught exception but this is now no longer
possible as the VM does not store uncaught exceptions.
- In js the code used to be interruptable by throwing an exception on
the VM. This is no longer possible but was already somewhat fragile
before as you could happen to throw an exception just before a VERIFY.
This function was unnecessarily nested, which created a scenario where
we could get stuck in an infinite loop without advancing the
current_object pointer up the browsing context container chain.
The main deviation from the spec is that we don't have a straightforward
representation of the spec's "focusable area" concept.
I've left a bunch of FIXME's around for our future selves. :^)
Instead of making each Layout::Node compute style for itself, we now
compute it in TreeBuilder before even calling create_layout_node().
For non-element DOM nodes, we create the style and layout tree node
in TreeBuilder. This allows us to move create_layout_node() from
DOM::Node to DOM::Element.
This also refactors interpreter creation to follow
InitializeHostDefinedRealm, but I couldn't fit it in the title :^)
This allows us to follow the spec much more closely rather than being
completely ad-hoc with just the parse node instead of having all the
surrounding data such as the realm of the parse node.
The interpreter creation refactor creates the global execution context
once and doesn't take it off the stack. This allows LibWeb to take the
global execution context and manually handle it, following the HTML
spec. The HTML spec calls this the "realm execution context" of the
environment settings object.
It also allows us to specify the globalThis type, as it can be
different from the global object type. For example, on the web, Window
global objects use a WindowProxy global this value to enforce the same
origin policy on operations like [[GetOwnProperty]].
Finally, it allows us to directly call Program::execute in perform_eval
and perform_shadow_realm_eval as this moves
global_declaration_instantiation into Interpreter::run
(ScriptEvaluation) as per the spec.
Note that this doesn't evalulate Source Text Modules yet or refactor
the bytecode interpreter, that's work for future us :^)
This patch was originally build by Luke for the environment settings
object change but was also needed for modules. So I (davidot) have
modified it with the new completion changes and setup for that.
Co-authored-by: davidot <davidot@serenityos.org>
This change unfortunately cannot be atomically made without a single
commit changing everything.
Most of the important changes are in LibIPC/Connection.cpp,
LibIPC/ServerConnection.cpp and LibCore/LocalServer.cpp.
The notable changes are:
- IPCCompiler now generates the decode and decode_message functions such
that they take a Core::Stream::LocalSocket instead of the socket fd.
- IPC::Decoder now uses the receive_fd method of LocalSocket instead of
doing system calls directly on the fd.
- IPC::ConnectionBase and related classes now use the Stream API
functions.
- IPC::ServerConnection no longer constructs the socket itself; instead,
a convenience macro, IPC_CLIENT_CONNECTION, is used in place of
C_OBJECT and will generate a static try_create factory function for
the ServerConnection subclass. The subclass is now responsible for
passing the socket constructed in this function to its
ServerConnection base; the socket is passed as the first argument to
the constructor (as a NonnullOwnPtr<Core::Stream::LocalServer>) before
any other arguments.
- The functionality regarding taking over sockets from SystemServer has
been moved to LibIPC/SystemServerTakeover.cpp. The Core::LocalSocket
implementation of this functionality hasn't been deleted due to my
intention of removing this class in the near future and to reduce
noise on this (already quite noisy) PR.
Instead of making it a void function, checking for an exception, and
then receiving the relevant result via VM::last_value(), we can
consolidate all of this by using completions.
This allows us to remove more uses of VM::exception(), and all uses of
VM::last_value().
This requires an implementation of the "text preparation algorithm" as
specified here:
html.spec.whatwg.org/multipage/canvas.html#text-preparation-algorithm
However, we're missing a lot of things such as the
CanvasTextDrawingStyles interface, so most of the algorithm was not
implemented. Additionally, we also are not able to use a LineBox like
the algorithm suggests, because our layouting infra is not up to the
task yet. The prepare_text function does nothing other than figuring out
the width of the given text and return glyphs with offsets at the
moment.
This will allow us to easily add copies of the relevant canvas drawing
state to a stack, and likewise replace the current drawing state with
an entry from that stack.
I don't know if the original author simply missed this or thought the
default color of Gfx::Color is black, but this meant that drawing on a
canvas without explicitly setting a fillStyle or strokeStyle first would
be drawn in transparent color and therefore be invisible.
In the spec this is indicated by a small comment in the IDL definition:
attribute ... strokeStyle; // (default black)
attribute ... fillStyle; // (default black)
I'm starting to question whether Gfx::Color actually *should* have a
default constructor.
This wasn't quite following what the spec says for step 2:
"If index is −1, then remove the last element in the rows collection
from its parent, or do nothing if the rows collection is empty."
It was behaving like:
"If index is −1 and the rows collection is not empty, then remove the
last element in the rows collection from its parent."
Which is not the same, as it will fall into the "Otherwise" if
`index == -1` and the rows collection is empty and try and get the -2nd
element of the rows.
Found with Domato.
Step 1 of the spec is to capture the <script> element's node document
into a local variable.
When I originally implemented this, I thought this was not necessary.
However, I realised that the script that runs can adopt the current
script element into a different document, meaning step 5.4 and 6 then
operate on the incorrect document.
Covered by this WPT: 7b0ebaccc6/html/semantics/scripting-1/the-script-element/moving-between-documents-during-evaluation.html
The "completely finish loading" algorithm (from the HTML spec) is
responsible for sending a "load" event to nested browsing context
containers (iframes).
This patch removes the old mechanism for sending "load" events, which we
had mistakenly kept around, causing two events to be sent instead of
one. :^)
This changes allows for nested browser contexts to be embedded in the
serialized JSON of their container element (like `iframe`) and enables
their inspection in the DOM Inspector.
When valid, this attribute needs to result in an IdentifierStyleValue.
Before this change we were turning it into a StringStyleValue, which
then defaulted to left alignment for all values.
For "center" and "middle", we turn it into -libweb-center. All other
values are passed verbatim to the CSS parser.
This always felt awkward to me, and required a few other hacks to make
it work. Now, the request is only started when `load_bitmap()` is
called, which we do inside `NodeWithStyle::apply_style()`.
Note our Attribute class is what the spec refers to as just "Attr". The
main differences between the existing implementation and the spec are
just that the spec defines more fields.
Attributes can contain namespace URIs and prefixes. However, note that
these are not parsed in HTML documents unless the document content-type
is XML. So for now, these are initialized to null. Web pages are able to
set the namespace via JavaScript (setAttributeNS), so these fields may
be filled in when the corresponding APIs are implemented.
The main change to be aware of is that an attribute is a node. This has
implications on how attributes are stored in the Element class. Nodes
are non-copyable and non-movable because these constructors are deleted
by the EventTarget base class. This means attributes cannot be stored in
a Vector or HashMap as these containers assume copyability / movability.
So for now, the Vector holding attributes is changed to hold RefPtrs to
attributes instead. This might change when attribute storage is
implemented according to the spec (by way of NamedNodeMap).
https://www.w3.org/TR/cssom/ is the more permanent home of the CSSOM
specification's latest version, and is up to date with the draft spec.
Also, https://drafts.csswg.org/ has been down multiple times recently
which made looking things up a pain.
This paves the way for the rejectionhandled and unhandledrejection
events.
It's also used by core-js (in browsers, at least) to check whether
Promise needs to be polyfilled, so adding it should allow more websites
to leverage LibJS's native Promise implementation :^)
There's a subtle difference here. A "block box" in the spec is a
block-level box, while a "block container" is a box whose children are
either all inline-level boxes in an IFC, or all block-level boxes
participating in a BFC.
Notably, an "inline-block" box is a "block container" but not a "block
box" since it is itself inline-level.
Until now, we've internally thought of the CSS "display" property as a
single-value property. In practice, "display" is a much more complex
property that comes in a number of configurations.
The most interesting one is the two-part format that describes the
outside and inside behavior of a box. Switching our own internal
representation towards this model will allow for much cleaner
abstractions around layout and the various formatting contexts.
Note that we don't *parse* two-part "display" yet, this is only about
changing the internal representation of the property.
Spec: https://drafts.csswg.org/css-display
Instead of doing layout synchronously whenever something changes,
we now use a basic event loop timer to defer and coalesce relayouts.
If you did something that requires a relayout of the page, make sure
to call Document::set_needs_layout() and it will get coalesced with all
the other layout updates.
There's lots of room for improvement here, but this already makes many
web pages significantly snappier. :^)
Also, note that this exposes a number of layout bugs where we have been
relying on multiple relayouts to calculate the correct dimensions for
things. Now that we only do a single layout in many cases, these kind of
problems are much more noticeable. That should also make them easier to
figure out and fix. :^)
This patch adds the "has a rendering opportunity" concept from the spec
to BrowsingContext and uses it to filter out contexts that are unable
to render right now when doing the event loop's rendering updates.
Note that we actually consider all contexts to have a rendering
opportunity at all times right now. Coming up with reasons to avoid
rendering is left as a FIXME. :^)
We now invoke DOM timer callbacks via HTML tasks. This brings callback
sequencing closer to the spec, although there are still many
imperfections in this area.
This particularly implements these two points:
- "If the adjusted current node is an HTML integration point and the
token is a start tag"
- "If the adjusted current node is an HTML integration point and the
token is a character token"
This also adds spec comments to the tree constructor.
When parsing a CSS value in the context of a CSSStyleDeclaration
camelCase property setter, we don't necessarily have a Document to
provide the CSS parser for context.
So the parser can't go assuming that there's always a Document in the
ParsingContext. And ImageStyleValue can't go assuming that there's
always a Document either. This will require some more work to get things
right, I'm just patching up the null dereference for now.
We now follow the "update a style block" algorithm from the HTML spec
instead of using the ad-hoc CSSLoader mechanism.
This necessitated improving our StyleSheet and CSSStyleSheet classes as
well, so that's baked into this commit.