`EditText` supports two different forms of leading:
1. Font-provided leading, specified relative to the EM square and scaled with font size
2. User-specificed leading, specified in pixels
Notably, the former appears to apply to the first line in the text and pushes it down. This showed up in the `edittext_font_size` test, and according to that test result the leading is rounded *up* to the nearest pixel, plus one.
That last bit seems possibly wrong and is subject to further change, but it matches the tests at multiple scales.
Certain text routines calculate text on the pixel grid, despite the fact that Flash ordinarily works in twips. There is probably a reason for this - my guess is to keep text wrapping stable across multiple pixel densities (e.g. low-res screens plus high-res print).
I don't know why, but this is necessary for the "NEW STUFF" box on homestarrunner.com's toons menu to position correctly. SOMEWHERE, we are performing some kind of operation that adjusts one of the two, but not the other, and I can't find out what.
This fixes spaces at the start of text spans not being rendered, but also breaks center-align.
I also broke the font tests, so I had to rewrite them, which makes me question their value.
Right margins: Simple enough, we just need to subtract the right margin from the bounds when we calculate our alignment adjustment.
Trailing spaces: This is very tricky as we effectively have to remeasure the last box in the line when fixing it up. This also means LayoutContext has to hold the text itself so we can remeasure again...
Lines wider than bounds: If word wrap is disabled it is possible for a line to exceed the bounds of the box. In this case it will be left-aligned. Effectively, the align adjustment is clamped to positive values and we do that here too.
This doesn't work right yet because the resulting width doesn't apply correctly to the field. This is because `EditText`'s `_width` and `_height` change it's intrinsic bounds rather than it's X and Y scale (like it would with a button or a movie clip).
These tests depend on the particulars of our default device font, Noto Sans. If this test proves to be fragile we may need to create a testing font with a locked width and kerning table...
This prevents a bounds-check panic when we inevitably try to slice an array like `[300..2]` or something like that.
We also skip rendering the space that we're turning into a newline to avoid it popping up on the next line by accident.
`max_length` isn't a geometrical width, despite the fact that the type system didn't prevent me from making erroneous conversions. It's actually just a text length limit, which we won't be dealing with for some time.
When first instantiated, we use the static bounds; however, further relayouts grab `local_bounds` and calculate a width from that. `EditText` works almost identically to any other display object, with the exception that device fonts do not render if the transform is not an axis-aligned bounding box (and it doesn't respect scale). We don't have to worry about that for now.
This is surprisingly difficult because of how Flash handles these properties: they are cached at the start of a new line (explicit or flown) and then used for all spans that intersect with that line. Ergo, `LayoutContext` needs to keep track of all the boxes we generate within the line and the span that ultimately is going to provide margins for it.
And yet, at the same time, we also have to precalculate the effects of these margins when flowing text so that we know how much space we have to play with. This needs to be calculated the same at the start of the line as it is at the end. This is why `LayoutContext` is a separate type: it handles all the state tracking and crap that has to be done when splitting text into spans, paragraphs, and lines all at the same time.
Fortunately, this design will make it easier to implement other features like text alignment where we couldn't even begin to calculate everything in one pass.
This involves a new struct called a `FontDescriptor` which is generated whenever a font is registered and used to index the font in the library. When a font is requested, it goes through the descriptor system to get found.
"Mixing" is defined as `Option.or`ing all the properties in the new text format with the old one. Not specifying a text format in the new default will result in the field retaining it's old properties.
This yields nodes as `Step`s. This allows keeping track of the structure of the tree as you walk through descendents, as each element will be yielded twice: both as a `Step::In` *and* as a `Step::Out`. Non-element nodes will be yielded once as a `Step::Around`.
I'm adding `walk` iteration specifically to avoid having to write certain methods recursively. Existing recursive callers of `children` should probably be updated to `walk` the tree and maintain a separate `Vec` stack.