Commit Graph

112 Commits

Author SHA1 Message Date
David Wendt 4f3d4c82fb For some reason, Flash does not respect `<br>` at all, so we won't, either.
It *does*, however, respect `<sbr>` (which does the exact same thing), as well as `\n` (which makes absolutely no sense in HTML, normally that would get stripped out).
2020-06-20 19:55:57 -04:00
David Wendt efc6236cb5 Treat the end of each paragraph as a newline. 2020-06-20 19:55:56 -04:00
David Wendt d8a38d06bb Collect font height, letter spacing and the kerning flag into a single `EvalParameters` structure. 2020-06-20 19:55:55 -04:00
David Wendt 1f6d6018dc Use a char pattern here for clippy's sake 2020-06-20 19:55:55 -04:00
David Wendt 1966ec5cb1 Implement `sbr` tags.
No, I don't know what they are either, but at least one movie exists which treats them like `br`, so we'll treat them like that, too.
2020-06-20 19:55:54 -04:00
David Wendt f746ac5539 Implement `justify`, mostly.
This implementation has a few bugs which appear to have something to do with alignment. It's not only justify, but justify is the only test that's flagged as failing.

If you look at the margins test, you'll see what I mean: right-aligned and justified text doesn't quite make it to the right edge of the box even though it should. I'm not sure why.

This also restricts text rounding further: `measure` now only rounds when wrapping text, since Flash Player appears to account for fractional pixels in all other cases.
2020-06-20 19:55:54 -04:00
David Wendt 670c4723e3 Add support for the `kerning` flag, which turns on and off the kerning information on fonts. 2020-06-20 19:55:53 -04:00
David Wendt 180ef3b423 Recognize `<br>` as a line break.
This code is currently unreachable as `<br>` will actually trigger an AVM1 error due to our overly-strict XML parser.
2020-06-20 19:55:52 -04:00
David Wendt 2452124631 Break individual words at the start of lines that are too big to fit on the line. 2020-06-20 19:55:51 -04:00
David Wendt 2ad216cab4 Don't continue comparing tab stops after we find one that fits. 2020-06-20 19:55:50 -04:00
David Wendt b6c12b1e23 Use current font height times 2.7 as the natural tab stop, as that seems to match Flash... for now. 2020-06-20 19:55:50 -04:00
David Wendt 2caaa6875d Add support for explicit tabs and newlines. 2020-06-20 19:55:49 -04:00
David Wendt 153ab675e9 When aligning a line, actually consider all the boxes within the line. 2020-06-20 19:55:49 -04:00
David Wendt db0398d2ee Left and right margins and indents should not be included in `textWidth`. 2020-06-20 19:55:48 -04:00
David Wendt 6ce7ecee78 Implement `letterSpacing`. 2020-06-20 19:55:47 -04:00
David Wendt 16da6d827c Line-leading is always applied at least once, even if there are no line breaks in the text field. 2020-06-20 19:55:46 -04:00
David Wendt 410fb3ab86 Don't round each line's leading. Instead, round at the end of the operation.
This was verified by visual comparison with Flash Player; lines of text appear to be shifted by half-pixels, while the script output is always still rounded down.
2020-06-20 19:55:45 -04:00
David Wendt 2858c09b6e Only apply leading adjustment on newlines.
This results in ALL height adjustments being off by 2px, regardless of leading or font size. Tantalizing!
2020-06-20 19:55:45 -04:00
David Wendt 09c91d191a Round-trip tab stops between `EditText` and AVM1 2020-06-20 19:55:43 -04:00
David Wendt 00217072e6 After the previous set of fixes our tests are now consistent with a layout engine that always rounds down to the nearest pixel and never up. Adjust code to match. 2020-06-20 19:55:43 -04:00
David Wendt 06c66533c7 Don't apply leading twice. 2020-06-20 19:55:42 -04:00
David Wendt 82c6269cf6 Ensure that presentational markup styles cascade from parent tag to child, and from the default format to the first tag. 2020-06-20 19:55:42 -04:00
David Wendt 9981148482 Add a test for `BoxBounds.with_size`, since we're using it now 2020-06-20 19:55:41 -04:00
David Wendt aae1f0ba7a Skip fixups on empty lines. 2020-06-20 19:55:41 -04:00
David Wendt bd40295076 Ensure that the font-provided leading is accounted for when moving the cursor for a newline. 2020-06-20 19:55:41 -04:00
David Wendt 0e0b2fb85d All layout boxes on the line should have trailing whitespace trimmed off of their measurements.
Flash has a weird bug where it will NOT trim trailing spaces off of the metrics reported to users if the text is left-aligned. We replicate this here so that tests pass.
2020-06-20 19:55:40 -04:00
David Wendt 50a05df998 Generated lines should *always* include their end spaces, there should be no gaps. 2020-06-20 19:55:40 -04:00
David Wendt ab2b9cc733 Change all of the `BoxBounds` in the layout machinery to not use `Default`.
The `Default` bounds are NOT safe to union against if they were uninitialized. Doing so will force any resulting layout box to enclose `(0,0)`, which can throw off certain layout calculations. Instead, we use `None` to signal an uninitialized box.
2020-06-20 19:55:40 -04:00
David Wendt 318f09d241 Include the font-provided leading in the exterior bounds sent off for `autoSize` calculation. 2020-06-20 19:55:39 -04:00
David Wendt 06dc2f5fe0 Implement the `leading` attribute as defined by fonts.
`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.
2020-06-20 19:55:29 -04:00
David Wendt 8a5a2bf7c7 When `Font.wrap_text` indicates that none of the line can fit, we should also refresh our width and offset and check if there's even more text to measure or not. 2020-06-20 19:48:12 -04:00
David Wendt a0477e7525 Adjust the layout code to properly align content with right margins, trailing spaces on lines, and lines wider than the bounds.
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.
2020-06-20 19:48:11 -04:00
David Wendt dc46885021 Implement `autoSize`.
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).
2020-06-20 19:48:00 -04:00
David Wendt cb47e0bae8 `wrap_line` returns breakpoints relative to how we sliced the text, so we need to break things appropriately.
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.
2020-06-20 19:26:47 -04:00
David Wendt ece879a15c The align adjustment should be positive, not negative. 2020-06-20 19:26:47 -04:00
David Wendt 593f442372 Implement `leading` between lines 2020-06-20 19:26:47 -04:00
David Wendt e83cebc4fb Vertically align different-font-size boxes to the same bottom baseline. 2020-06-20 19:26:46 -04:00
David Wendt c7ac0e4bb1 Implement center and right alignment.
Justification will have to wait for another day.
2020-06-20 19:26:46 -04:00
David Wendt 562adcdc7e Implement `leftMargin`, `rightMargin`, `indent` and `blockIndent`.
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.
2020-06-20 19:26:46 -04:00
David Wendt 5fcaa52687 Restore newline functionality (mostly...) 2020-06-20 19:26:45 -04:00
David Wendt e3f59ac00f Implement `color` on spans 2020-06-20 19:26:45 -04:00
David Wendt b5de92edeb Properly retrieve default font class 2020-06-20 19:26:44 -04:00
David Wendt c4e5a9afc2 In the spirit of shared-nothing `post_instantiation` should duplicate any `LayoutBox`es it has, in case we mutate them later. 2020-06-20 19:26:44 -04:00
David Wendt 361ea1f774 Index fonts by font name, boldness, and italicization.
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.
2020-06-20 19:26:43 -04:00
David Wendt f234926e63 Default text formats are not replaced when movies call `setNewTextFormat`, they instead mix with the existing one.
"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.
2020-06-20 19:26:43 -04:00
David Wendt 3b80ff8d23 Clippy compliance 2020-06-20 19:26:42 -04:00
David Wendt 8622cb97a9 Add a system of layout boxes to store text layout decisions made at update time. 2020-06-20 19:16:17 -04:00
David Wendt 4a2fac28d1 Add iterator for text spans 2020-06-20 19:16:17 -04:00
David Wendt ec72ac518c Allow HTML text nodes to populate text.
This will need to be updated to handle line breaks, spaces, and so on correctly - the way whitespace works in HTML differs from plain text.
2020-06-20 19:16:17 -04:00
David Wendt 816644c497 Add an internal implementation of `replaceText`. 2020-06-20 19:16:17 -04:00
David Wendt a1f548f744 Add a routine to generate `TextFormat`s from presentational markup, and another lowering process which tracks the text formats generated by this process. 2020-06-20 19:16:16 -04:00
David Wendt 4eca2d4bdd Replace the existing default format on `EditText` with our brand-new `FormatSpans`.
This also includes code to automatically populate the default format with data from the SWF tag.
2020-06-20 19:16:16 -04:00
David Wendt efdecdea64 Store the default text format, and use it when generating new spans during normalization.
I'm sure this will wind up having further uses eventually.
2020-06-20 19:16:15 -04:00
David Wendt 153571c0c4 Implement `FormatSpans::set_text_format`.
This also necessitated the addition of code to:

 * Ensure span breaks exist at both sides of the text boundary, without creating degenerate (length-0) spans
  * Consolidate spans with matching text formats
  * Shorten or lengthen the total list of text spans to match the backing string
  * Ensure at least one text span exists at all times

This still has some minor to-dos: for example, it relies on the default `TextSpan` formatting, which probably should be replaced with actually accepting or storing a default format to be used when constructing new text spans.
2020-06-20 19:16:15 -04:00
David Wendt 102c494de4 Add a type to hold text with some text spans, and some tests for that type. 2020-06-20 19:16:14 -04:00
David Wendt 1671fc6eba Add an internal representation of text spans.
Despite having HTML and CSS rendering capabilities, the Flash text field actually does not use HTML as it's internal representation. Instead, the text-span format implied by `getTextFormat` and `setTextFormat` is used to drive layout. You can see this by watching what happens to `htmlText`, *especially* when you add and remove stylesheets.

The `LayoutBox` machinery will be adapted to consume text spans in a future commit. This would make the entire rendering pipeline: HTML/CSS -> Text Spans -> Layout Boxes -> Render commands.
2020-06-20 19:16:14 -04:00
David Wendt 850831181c Add tests for all non-trivial methods of `Position`, `Size`, and `BoxBounds`. 2020-06-20 19:16:13 -04:00
David Wendt ef035c5283 Add `Size.max`, conversions between `Position` and `Size`, `BoxBounds.extent`, and `BoxBounds.with_size`. 2020-06-20 19:16:13 -04:00
David Wendt e7c34d9745 Switch `BoxBounds` from a position-and-size representation to an offset-and-extent representation.
This makes the implementation of rectangle union (`Add`/`AddAssign`) far easier as we just compute the min and max of the offset and extent coordinates. It also makes the conversion into and from `swf::Rectangle` easier as it's now effectively a generic version of that datatype.

On the other hand, `width`, `height`, and `size` now have to be calculated, and require `T` to be self-`Sub`. I'm not sure if this is that much of a problem or not.
2020-06-20 19:16:12 -04:00
David Wendt 0a1de3276f Add extra types for indicating moving a position and resizing a box. 2020-06-20 19:16:12 -04:00
David Wendt a4c8cd4711 Add a set of types for tracking CSS attributes, positions, sizes, and bounds on layout boxes. 2020-06-20 19:16:12 -04:00
David Wendt ac9cd0cf87 Move `TextFormat` over to a new `html` module, which will hold all the stuff necessary for rendering HTML in an `EditText`.
`TextFormat` is owned data and should be collectable as static.
2020-06-20 19:16:10 -04:00