Files
taffy/tests/hand_written.rs
T
RiteshandGitHub d1ff7e339b Implement safe and unsafe overflow-position alignment keywords (#952)
* feat(style): add Safe* alignment variants and parser

Add SafeStart/SafeEnd/SafeFlexStart/SafeFlexEnd/SafeCenter on AlignItems
and AlignContent with is_safe()/position() helpers, RTL-aware reversed()
extension, and a hand-rolled FromCss parser for `safe X` / `unsafe X`
that rejects spec-invalid combinations. apply_alignment_fallback now
folds the safe modifier into its is_safe flag, so content alignment in
grid tracks and flex justify/align-content honor the Start fallback when
overflowing. Self-alignment paths accept the new variants but defer the
overflow fallback to a follow-up commit.

* feat(compute): wire safe-overflow fallback for self alignment

Implement the Start fallback for "safe" overflow-position keywords on
align-self and justify-self in both grid and flex layouts. When an item
overflows its alignment container and the alignment value is one of the
Safe* variants, the offset is anchored to the logical Start edge to
avoid data loss; an item that fits its container keeps its requested
position.

In grid `align_item_within_area`, overflow is detected from the resolved
size and non-auto margins versus the grid area size, and the fallback
respects the container `direction` so RTL anchors at the right edge.

In flex `align_flex_items_along_cross_axis`, the fallback short-circuits
when the cross-axis free space is negative, accounting for
`cross_axis_should_reverse` and `is_wrap_reverse` so the Start edge
matches the underlying writing-mode-relative start.

The three previously-stale `// TODO: Implement safe alignment` comments
at the grid track, flex justify-content, and flex align-content sites
are removed; the modifier-folding inside `apply_alignment_fallback`
already routes Safe* keywords through the Start fallback path on
overflow.

Add ten integration tests covering the new self-alignment behavior, the
content-alignment behavior wired by the previous commit, the no-overflow
case, the unsafe (default) overflow regression, the RTL fallback edge,
and a multi-line flex `align-content` overflow.

The flex absolutely-positioned alignment paths still strip Safe* via
`.position()` without invoking the Start fallback; this is left for a
follow-up commit.

* test(safe-alignment): add gentest fixtures for safe and unsafe overflow alignment

Add 17 HTML fixtures under test_fixtures/grid/ and test_fixtures/flex/
that exercise the `safe` and `unsafe` overflow-position keywords across
container-level (justify-content, align-content) and item-level
(justify-self, align-self) alignment in both grid and flex layouts. The
fixtures pair overflow and no-overflow geometries so that the Start
fallback path and the normal positional path are both verified, and
include unsafe-end regressions to prove the default behavior is
unchanged for plain end alignment.

Run the gentest pipeline against these fixtures to render each in
headless Chrome and capture the expected layout into 68 generated XML
expectation files (4 variants per fixture: border-box LTR, border-box
RTL, content-box LTR, content-box RTL). Register the new entries in
tests/xml/mod.rs.

The full suite passes — taffy's safe-alignment implementation matches
Chrome byte-for-byte on every fixture.

* docs: document safe and unsafe overflow alignment keywords

Add a section to docs/style-properties.md that lists the new Safe*
variants on AlignItems and AlignContent, describes the overflow
fallback to logical Start, and clarifies which position keywords are
valid pairings under the spec.

* refactor(safe-alignment): address review feedback

- Drop dead `is_safe` parameter from `apply_alignment_fallback`; infer
  it from the alignment style itself.
- In `align_item_within_area` (grid) and `align_flex_items_along_cross_axis`
  (flex), mutate `alignment_style` to `Start` on safe + overflow and
  reuse the existing match, removing a duplicated RTL branch.
- Add `Safe*` arms to `benches/yoga_helpers.rs` so the bench crate builds
  on CI; Yoga has no overflow-position equivalent, so they map to
  `unimplemented!()` like the other unsupported variants.

* refactor(safe-alignment): collapse Safe* variants into struct { keyword, safety }

Addresses review feedback from @nicoburns. Replaces the combinatorial Safe*
variants on AlignContent / AlignItems with a struct holding a position-keyword
enum and an orthogonal AlignmentSafety { Safe, Unsafe } modifier. Every
pre-existing CSS spelling (Start, End, FlexStart, FlexEnd, Center, Stretch,
SpaceBetween, SpaceEvenly, SpaceAround, Baseline) and every Safe* spelling
(SafeStart, SafeEnd, SafeFlexStart, SafeFlexEnd, SafeCenter) is exposed as a
PascalCase associated constant, so call sites read identically to the previous
enum form. Compute paths take the struct at the API boundary, fold safety into
the keyword via the fallback step, and then match on the bare *Keyword enum —
exhaustive, with zero unreachable!() arms in src/compute/.

- public API: AlignContent / AlignItems are now `pub struct { keyword, safety }`
  with associated consts for every prior spelling
- new public types: AlignContentKeyword, AlignItemsKeyword, AlignmentSafety
  (added to the prelude)
- `position()` accessor renamed to `keyword()` (returns the new *Keyword enum)
- compute/common/alignment::apply_alignment_fallback returns
  AlignContentKeyword; compute_alignment_offset takes one — internal matches
  lose every `| Self::Safe*` sibling
- custom Serialize / Deserialize preserves the single-tag wire format
  ("Start", "SafeFlexEnd", …) so deserializing data produced by older builds
  still works
- drive-by: fix pre-existing rand::distributions → rand::distr drift and
  Dimension/LengthPercentage enum-variant → tag-based API drift in
  benches/src/taffy_03_helpers.rs so `cargo test --workspace --all-features`
  passes again

Size impact (src/style/mod.rs::style_sizes asserts these now):
  AlignContent / AlignItems          : 1 → 2 bytes
  Option<AlignContent> / <AlignItems>: 1 → 2 bytes (niche-packed in safety byte)
  Style<String>                      : 536 → 544 bytes
  Style<Arc<str>>                    : 504 → 512 bytes

No behaviour change: test_fixtures byte-identical, all 4345 generated + 107 lib
+ 45 hand-written + 5 doc tests pass with `--all-features` and
`--no-default-features`.

* style: drop drive-by _f32 literal suffixes

Reverts 208 _f32 type-annotation suffixes that were inserted by an
IDE auto-fixer responding to a nightly-only `f32: From<f64>` lint
that's not yet a hard error. None of them are necessary on stable;
several landed inside string literals or doc comments where there
was no float to annotate at all (e.g. "Taffy 0.3" became
"Taffy 0.3_f32"). Per @nicoburns review feedback: keep the diff
minimal and let upstream address the lint when it actually fires.

No behavior change: test_fixtures byte-identical, all 4345 generated
+ 107 lib + 45 hand-written + 5 doc tests pass with --all-features
and --no-default-features.
2026-05-27 20:04:29 +01:00

12 lines
211 B
Rust

mod hand_written {
mod border_and_padding;
mod caching;
mod measure;
mod min_max_overrides;
mod relayout;
mod root_constraints;
mod rounding;
mod safe_alignment;
mod serde;
}