We now evaluate the conditions of `@media` rules at the same point in
the HTML event loop as evaluation of `MediaQueryList`s. This is not
strictly to spec, but since the spec doesn't actually say when to do
this, it seems to make the most sense. In any case, it works! :^)
The main thing missing is that we don't serialize the supports clause,
but for actually using a `@supports (something: cool) {}` rule in CSS,
it works!
The logic is handled by `CSSGroupingRule` and `CSSConditionRule`, so
`CSSMediaRule` only has to report if its condition matches.
Right now, that condition is always false because we do not evaluate the
media query.
... according to
https://www.w3.org/TR/css-conditional-3/#typedef-supports-condition
This works very similarly to `@media`, but is different enough to
require its own parsing. (Though, the draft of Conditional-4 currently
mentions combining the two into a `@when` rule.)
Made some small changes to parsing code to make this work. Notably,
making `consume_a_declaration()` fail gracefully instead of
`VERIFY()`ing.
The name is a little awkward, but this corresponds to the condition of a
`@supports` rule or the `CSS.supports("")` function.
A supports query only gets evaluated once, since its condition cannot
change during runtime. (We either support something or we don't, and the
spec specifically mentions that user preferences that disable features
do not affect the result here.) We keep a representation of it around
though, so that it can be serialized if needed. This is a little awkward
since we hold onto a `StyleDeclarationRule` which should be an internal
Parser class. This means making some Parser functions more public.
Potentially we could evaluate the Supports inside the Parser, and have
it only store a String representation of itself. But this works for now.
:^)
This is the `CSS` namespace defined in IDL here:
https://www.w3.org/TR/cssom-1/#namespacedef-css , not to be confused
with our `Web::CSS` namespace. Words are hard.
`CSS.escape()` lets you escape identifiers that can then be used to
create a CSS string.
I've also stubbed out the `CSS.supports()` function.
Previously: Length (and all nearly all of its inline method
definitions) depended on the definition of class CalculatedStyleValue.
Meanwhile, CalculatedStyleValue (and nearly all of its namespaced
structs) depended on the definition of class Length.
Thus, a compilation unit that (for example) only contains
#include <Userland/Libraries/LibWeb/CSS/Length.h>
would fail to compile.
This patch resolves this issue by pushing the inline definition of
various Web::CSS::Length methods into a different file.
Previously: CSSImportRule::loaded_style_sheet() (and others) depend on
the definition of class CSSStyleSheet. Meanwhile,
CSSStyleSheet::template for_each_effective_style_rule (and others)
depend on the definition of class CSSImportRule.
This hasn't caused any problems so far because CSSStyleSheet.h happened
to be always included after CSSImportRule.h (in part due to alphabetical
ordering).
However, a compilation unit that (for example) only contains
#include <Userland/Libraries/LibWeb/CSSImportRule.h>
would fail to compile.
This patch resolves this issue by pushing the inline definition of
Web::CSS::CSSStyleSheet::for_each_effective_style_rule and
for_first_not_loaded_import_rule into a different file, and adding the
missing headers.
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
Currently, `evaluate()` recalculates whether the MediaQuery matches or
not, and stores it in `m_matches`, which users can query using
`matches()`. This allows us to know when the match-state changes, which
is required to fire MediaQueryList's change event.
In cases where we know the Length is absolute, we know we don't need to
pass in a Layout::Node or FontMetrics etc, and yet we were required to
before. Splitting it means jumping through less hoops that we don't have
to. :^)
If the specified value for these properties is "none", we end up storing
it as an "undefined" CSS::Length in the computed values.
We need to convert it back into "none" for getComputedStyle().
Since we expose these strings to web content via LengthStyleValue,
let's not have non-standard brackets in there to confuse anyone trying
to parse these values. :^)
There are a handful of FIXME's here, but this seems generally good.
Note that CSS *values* don't get serialized in a spec-compliant way
since we currently rely on StyleValue::to_string() which is ad-hoc.
While not complete by any means, we are now compatible with the [level 3
spec](https://www.w3.org/TR/css3-mediaqueries/#syntax) and some parts of
[level 4.](https://www.w3.org/TR/mediaqueries-4#mq-syntax)
Compatibility with level 4+ requires:
- Implementing the range syntax: `(800px <= width <= 1200px)`
- Parsing `<general-enclosed>`, which represents syntax that is not yet
used but they may use in the future.
Parsing media queries sometimes requires significant back-tracking, so
`reconsume_current_input_token()` was not good enough.
`rewind_to_position()` lets you reconsume an erbitrary number of tokens
to return to an earlier point in the stream, which you previously saved
from `TokenStream::position()`.
This now matches the spec, and fixes the situation where if it was given
a TokenStream of StyleComponentValueRules, it would drop any Blocks on
the floor instead of adding them to the result StyleRule.
This is a list of MediaQuery objects. Not to be confused with
`MediaQueryList`, which is concerned with firing events when a media
query's match-state changes.
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.
This patch makes both of these classes inherit from RefCounted and
Bindings::Wrappable, plus some minimal rejigging to allow us to keep
using them internally while also exposing them to web content.