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.
This patch adds the setProperty(name, value) API to CSSStyleDeclaration.
Setting an invalid or empty value will cause the property to be removed
from the declaration.
Note that this only works on mutable declarations (i.e element.style)
and not on resolved declarations (i.e window.getComputedStyle(element)).
This doesn't work correctly in the new world where fonts are resolved
during the CSS cascade. Let's patch it out with a FIXME and get back to
it once everything has fallen into place.
Resolved style is a spec concept that refers to the weird mix of
computed style and used style reflected by getComputedStyle().
The purpose of this class is to produce the *computed* style for a given
element, so let's call it StyleComputer.
Once we've performed the cascade on a set of values for an element,
we should have enough information to resolve/absolutize some lengths.
Basically, any CSS length that isn't "auto" or a percentage can be
turned into an absolute length (in pixels) as long as we have the
following information:
- The viewport rect
- The parent element's font
- The document element's font
- The element's own font
To ensure that we can absolutize lengths relative to the element's own
font, we now do a separate first pass where font-related properties are
defaulted (in the cascade spec sense of the word) and become usable.
There's a lot more work to do here, but this should open up a lot of
simplification in layout code, since it will no longer need to care
about relative lengths. Layout still needs to resolve percentages, since
we can't do that for some properties until the containing block
dimensions are known.
The original name was based on the window.getComputedStyle() API.
However, "Computed" in "getComputedStyle" is actually a misnomer that
the platform is stuck with due to backwards compatibility.
What getComputedStyle() returns is actually a mix of computed and used
values. The spec calls it the "resolved" values. So let's call this
declaration subclass "ResolvedCSSStyleDeclaration" to match.
This replaces a bunch of casts with `.as_foo()` calls, and adjusts calls
to the old `is_foo()` methods that now are better as `has_foo()`.
Also tidied up some whitespace to be more consistent.
This does a few things, that are hard to separate. For a while now, it's
been confuzing what `StyleValue::is_foo()` actually means. It sometimes
was used to check the type, and sometimes to see if it could return a
certain value type. The new naming scheme is:
- `is_length()` - is it a LengthStyleValue?
- `as_length()` - casts it to LengthStyleValue
- `has_length()` - can it return a Length?
- `to_length()` - gets the internal value out (eg, Length)
This also means, no more `static_cast<LengthStyleValue const&>(*this)`
stuff when dealing with StyleValues. :^)
Hopefully this will be a bit clearer going forward. There are lots of
places using the original methods, so I'll be going through them to
hopefully catch any issues.
Calling `is_identifier()` here was wrong, since it just means you can
get an Identifier from it. This meant that an `auto` LengthStyleValue
would return true, then it would get `static_cast` to the wrong class,
and return a garbage value.
Basically, I really need to tidy up the API for StyleValue, so it's
clear whether `is_foo()` means the object is a `FooStyleValue`, or it
can just return a `foo` value.
For `number` and `integer` types, you can add a range afterwards to add
a range check, using similar syntax to that used in the CSS specs. For
example:
```json
"font-weight": {
...
"valid-types": [
"number [1,1000]"
],
...
}
```
This limits any numbers to the range `1 <= n <= 1000`.
This brings us a few nice benefits:
- We only generate a `StyleValueList` for properties that accept
multiple values.
- We reject declarations that have too many values.
- We check the type of each value that is parsed, to make sure it's
acceptable to the property.
Probably there are some regressions here, since this is
Later, we can also replace many of the `is_foo()` functions and lambas
inside the Parser with more calls to `property_accepts_value()`. Also we
can remove some checks when resolving styles, since only valid types of
values will get to that point. But one step at a time. :^)
We don't want a property like `background` to fall back to parsing as a
single value or StyleValueList if `parse_background_style_value()`
fails. We just want it to fail.
In StyleResolver, we were rejecting single values for properties that
take 1-4: `border-color`, `border-style`, and `border-width`. Now, we
handle them correctly. I also added support for `calc()` and `var()` to
`padding` and `margin`.
This fixes the orange border on Acid2, which now correctly appears
black. :^)
We already expand shorthands in the cascade, so there's no need to
preserve them in the output.
This patch reorganizes the CSS::PropertyID enum values so that we can
easily iterate over all shorthand or longhand properties.
The 'C' in "CSS" is for Cascade, so let's actually implement the cascade
in LibWeb. :^)
StyleResolver::resolve_style() now begins by collecting all the matching
CSS rules for the given DOM::Element. Rules are then processed in the
spec's cascade order (instead of in the order we encounter them.)
With this, "!important" is now honored on CSS properties.
After performing the cascade, we do another pass of what the spec calls
"defaulting" where we resolve "inherit" and "initial" values.
I've left a FIXME about supporting correct "initial" values for every
property, since we're currently lacking some coverage there.
Note that this mechanism now resolves every known CSS property. This is
*not* space-efficient and we'll eventually need to come up with some
strategies to reduce memory usage around this. However, this will do
fine until we have more of the engine working correctly. :^)