Anonymous wrapper boxes inherit style from their layout tree parent,
and since style data is per-layout-node, we have to manually sync them
from parent to anonymous children when something changes.
This is not very elegant or efficient, so I've left a FIXME about
solving it in a nicer way.
This fixes horizontal dog alignment on https://waffles.dog/ :^)
The CSS box-shadow property takes 2-4 properties that are `<length>`s,
those being:
- offset-x
- offset-y
- blur-radius
- spread-radius
Previously these were resolved directly to concrete Lengths at parse
time, but now they will be parsed as LengthStyleValues and/or
CalculatedStyleValues and be stored that way until styles are later
resolved.
On style update, we have to preserve the invariant established when we
built the layout tree - some properties are applied to the table wrapper
and the table box values are reset to their initial values.
This also ensures that the containing block of a table box is always a
table wrapper, which isn't the case if we set absolute position on the
box instead of the wrapper.
Fixes#19452.
Although DistinctNumeric, which is supposed to abstract the underlying
type, was used to represent CSSPixels, we have a whole bunch of places
in the layout code that assume CSSPixels::value() returns a
floating-point type. This assumption makes it difficult to replace the
underlying type in CSSPixels with a non-floating type.
To make it easier to transition CSSPixels to fixed-point math, one step
we can take is to prevent access to the underlying type using value()
and instead use explicit conversions with the to_float(), to_double(),
and to_int() methods.
Previously, we did an evenodd fill for everything which while for most
SVGs works, it is not correct default (it should be nonzero), and broke
some SVGs. This fixes a few of the icons on https://shopify.com/.
Having one StyleValue for `<number>` and `<integer>` is making user code
more complicated than it needs to be. We know based on the property
being parsed, whether it wants a `<number>` or an `<integer>`, so we
can use separate StyleValue types for these.
Solves conflict in layout tree "type system" when elements <label> (or
<button>) can't have `display: table` because Box can't be
Layout::Label (or Layout::ButtonBox) and Layout::TableBox at the same
time.
Specifically, stop letting NumericStyleValues holding `0` from
pretending to hold a Length. The parser is now smart enough that we
don't have to do this. :^)
Only NumericStyleValue holds integers.
I'm not sure our current distinction between NumericStyleValue holding
an integer or non-integer is useful given it always returns a float.
:thonk:
Ignore anonymous block boxes when resolving percentage weights that
would refer to them, per the CSS 2 visual formatting model
specification. This fixes the case when we create an anonymous block
between an image which uses a percentage height relative to a parent
which specifies a definite height.
Fixes#19052.
This fixes a plethora of rounding problems on many websites.
In the future, we may want to replace this with fixed-point arithmetic
(bug #18566) for performance (and consistency with other engines),
but in the meantime this makes the web look a bit better. :^)
There's a lot more things that could be converted to doubles, which
would reduce the amount of casting necessary in this patch.
We can do that incrementally, however.
Before this change, LayoutState essentially had a Vector<UsedValues*>
resized to the exact number of layout nodes in the current document.
When a nested layout is performed (to calculate the intrinsic size of
something), we make a new LayoutState with its own Vector. If an entry
is missing in a nested LayoutState, we check the parent chain all the
way up to the root.
Because each nested LayoutState had to allocate a new Vector with space
for all layout nodes, this could get really nasty on very large pages
(such as the ECMA262 specification).
This patch replaces the Vector with a HashMap. There's now a small cost
to lookups, but what we get in return is the ability to handle huge
layout trees without spending eternity in page faults.
This implements the stop-opacity, fill-opacity, and stroke-opacity
properties (in CSS). This replaces the existing more ad-hoc
fill-opacity attribute handling.
Note that this simple form of text-indent only affects the first line
of formatted content in each block.
Percentages are resolved against the width of the block.
This bit is mostly ad-hoc for now. This simply turns fill: url(#grad1)
into document().get_element_by_id('grad1') then resolves the gradient.
This seems to do the trick for most use cases, but this is not
attempting to follow the spec yet to keep things simple.
Now that LengthStyleValue never contains `auto`, IdentifierStyleValue is
the only type that can hold an identifier. This lets us remove a couple
of virtual methods from StyleValue.
I've kept `has_auto()` and `to_identifier()` for convenience, but they
are now simple non-virtual methods.
This parses the new background-position-x/y longhands and properly
hooks up them up. This requires converting PositionStyleValue to
just contain two EdgeStyleValues so that it can be easily expanded
into the longhands.
Explicitly check is_viewport() instead of looking at the corresponding
DOM node. (The viewport has the DOM document as its DOM node, but that's
not obvious from context here.)
Until now we were just creating a stacking context for the tree root,
which usually is the viewport element. This lead to weird painting
behaviour when negative z-index children of the html element that
established their own stacking context were drawn below the canvas
background.
Now we establish a stacking context for both, the root element and the
viewport.
This moves color to be the first value resolved, this ensures that
calls to .to_color() on style values for other properties will always
be able to resolve the current color.
This change fixes the `background-color: currentColor` example in
colors.html.
The name "initial containing block" was wrong for this, as it doesn't
correspond to the HTML element, and that's specifically what it's
supposed to do! :^)