There are multiple things happening here which are interconnected:
- We now use AbstractElement to refer to the source of a counter, which
means we also need to pass that around to compute `content`.
- Give AbstractElement new helper methods that are needed by
CountersSet, so it doesn't have to care whether it's dealing with a
true Element or PseudoElement.
- The CountersSet algorithms now walk the layout tree instead of DOM
tree, so TreeBuilder needs to wait until the layout node exists
before it resolves counters for it.
- Resolve counters when creating a pseudo-element's layout node. We
awkwardly compute the `content` value up to twice: Once to figure out
what kind of node we need to make, and then if it's a string, we do
so again after counters are resolved so we can get the true value of
any `counter()` functions. This will need adjusting in the future but
it works for now.
This is one of those cases where the spec says "element" and
means "element or pseudo-element". The easiest way to handle both is to
make these be free functions that take an AbstractElement, and then
give AbstractElement some helper methods so that the caller doesn't
have to care which it's dealing with.
There are some FIXMEs here because PseudoElement doesn't have a
CountersSet yet, and because the CountersSet currently uses a
UniqueNodeID to identify counter sources, which doesn't support
pseudo-elements.