diff --git a/docs/PLAN.md b/docs/PLAN.md index a0c5048..d387939 100644 --- a/docs/PLAN.md +++ b/docs/PLAN.md @@ -862,10 +862,12 @@ absolute position back into this same public field; callers animating it own stopping their animation when editing begins. Position changes and changes among the unwrapped treatments reuse shaping; entering or leaving `Wrap` reshapes at the viewport width, while content, font, spans, or density retain -the normal shape invalidation path. `Hidden` clips at the exact pixel position -for continuous scrolling. `Ellipsis` keeps that same continuous position but -snaps each content-mask edge outward past any shaped cluster or ligature it -crosses, so a marker never leaves a partial shaped cluster behind. +the normal shape invalidation path. Overflow masks only the horizontal axis; +vertical ink such as descenders and accents remains untouched. `Hidden` clips +at the exact horizontal pixel position for continuous scrolling. `Ellipsis` +keeps that same continuous position but snaps each content-mask edge outward +past any shaped cluster or ligature it crosses, so a marker never leaves a +partial shaped cluster behind. An ellipsis marker maps its visually omitted side to one contiguous source range. This is exact for ordinary LTR and RTL runs; mixed-bidi text can place discontiguous logical ranges on one visual side, which Iris's deliberately diff --git a/iris/src/widget/text/mod.rs b/iris/src/widget/text/mod.rs index c2f11d6..5cd9ad4 100644 --- a/iris/src/widget/text/mod.rs +++ b/iris/src/widget/text/mod.rs @@ -354,11 +354,12 @@ impl TextView { } else { (self.overflow.content_end - self.overflow.content_start).max(0.0) }; - let mask = vec2(content_width, self.overflow.viewport.y) + let horizontal_mask = vec2(content_width, self.overflow.viewport.y) .align(Align::TOP_LEFT) .offset(vec2(self.overflow.content_start, 0.0)) .within(&viewport) .within(&painter.region()); + let mask = UiRegion::new(horizontal_mask.x, UiSpan::FULL); painter.set_mask(mask); let origin = tex .size @@ -656,6 +657,24 @@ mod tests { assert_eq!(rsc.ui.widgets[text].view.overflow.trailing_marker, 0.0); } + #[test] + fn overflow_masks_only_the_horizontal_axis() { + let mut rsc = TestRsc { ui: Ui::default() }; + let text = wtext("glyphs jumping") + .overflow(TextOverflow::Hidden) + .size(18) + .add(&mut rsc); + let root = text.width(abs(50)).add_strong(&mut rsc).any(); + let mut render = UiRenderState::new(); + render.resize((800.0, 600.0)); + render.update(&root, &mut rsc); + + let mask = rsc.ui.masks[render.active[&text.id()].own_mask.idx()]; + let region = render.primitives.instance(mask.primitive).region; + assert_eq!(region.y, UiSpan::FULL); + assert_ne!(region.x, UiSpan::FULL); + } + #[test] fn selecting_an_ellipsis_selects_the_omitted_source_text() { let mut rsc = TestRsc { ui: Ui::default() };