diff --git a/core/src/ui/painter.rs b/core/src/ui/painter.rs index 3c4fd0c..aee438c 100644 --- a/core/src/ui/painter.rs +++ b/core/src/ui/painter.rs @@ -80,6 +80,21 @@ impl<'a> Painter<'a> { /// Takes the kind, for a caller writing many of one primitive. fn write(&mut self, kind: PrimitiveKind

, primitive: P, region: DrawRegion) { + self.write_resolved( + kind, + primitive, + region, + region.resolve(self.region, self.placement), + ); + } + + fn write_resolved( + &mut self, + kind: PrimitiveKind

, + primitive: P, + region: DrawRegion, + resolved: UiRegion, + ) { #[cfg(feature = "layout-diagnostics")] diag::bump(Counter::PrimitiveWrites); let h = self.state.layers.write( @@ -88,7 +103,7 @@ impl<'a> Painter<'a> { kind, id: self.id, primitive, - region: region.resolve(self.region, self.placement), + region: resolved, mask_idx: self.mask, move_idx: self.move_idx, }, @@ -404,9 +419,12 @@ impl<'a> Painter<'a> { // TODO: merge the text methods into the primitive ones. pub fn glyphs(&mut self, text: &RenderedText, origin: impl Into) { let origin = origin.into(); + // Glyph offsets and sizes are pixels, which compose additively. + // Only the shared origin needs the frame/extent composition. + let resolved = origin.resolve(self.region, self.placement); let kind = self.rsc.ui_mut().primitives.kind::(); for glyph in text.glyphs.iter() { - let region = origin.map(|mut region| { + let place = |mut region: UiRegion| { region.x.end = region.x.start; region.y.end = region.y.start; let mut region = region.offset(UiVec2::from_px(glyph.offset)); @@ -417,8 +435,8 @@ impl<'a> Painter<'a> { region.x.end = region.x.start.offset(size.x); region.y.end = region.y.start.offset(size.y); region - }); - self.write( + }; + self.write_resolved( kind, GlyphPrimitive { uv_min: glyph.entry.uv_min, @@ -427,7 +445,8 @@ impl<'a> Painter<'a> { color: text.color, flags: glyph.entry.flags(), }, - region, + origin.map(place), + place(resolved), ); } } diff --git a/tests/cases/retained.rs b/tests/cases/retained.rs index 38add1e..d07a6c5 100644 --- a/tests/cases/retained.rs +++ b/tests/cases/retained.rs @@ -951,3 +951,72 @@ fn a_span_does_not_place_its_measurement_before_assigning_the_childs_slot() { vec![h.region(&leaf.id()).unwrap()] ); } + +#[test] +fn glyph_origins_compose_identically_when_drawn_and_when_retained() { + struct Glyphs { + buffer: TextBuffer, + draws: Rc>, + } + impl Widget for Glyphs { + fn draw(&mut self, painter: &mut Painter) -> Size { + self.draws.set(self.draws.get() + 1); + let text = painter.render_text(&mut self.buffer, &TextAttrs::default(), None); + let origin = UiRegion::new( + UiSpan::new(Len::rel(0.23) + Len::px(-7.125), Len::FULL), + UiSpan::new(Len::rel(0.37) + Len::px(3.25), Len::FULL), + ); + painter.glyphs(text, DrawRegion::Frame(origin)); + painter.glyphs(text, DrawRegion::Extent(origin)); + Size::LEFTOVER + } + } + struct Frame { + child: StrongWidget, + region: UiRegion, + extent: UiRegion, + } + impl Widget for Frame { + fn draw(&mut self, painter: &mut Painter) -> Size { + painter.widget_at( + &self.child, + self.region, + [Some(self.extent.x), Some(self.extent.y)], + ); + Size::LEFTOVER + } + } + for node in [false, true] { + let mut h = Harness::new((403, 211)); + let draws = Rc::new(Cell::new(0)); + let text = Glyphs { + buffer: TextBuffer::new("Glyphs: gj AV\nsecond line"), + draws: draws.clone(), + } + .add(&mut h.rsc); + h.rsc.widgets_mut().set_region_node(text, node); + let root = Frame { + child: text.add_strong(&mut h.rsc), + region: UiRegion::FULL, + extent: UiRegion::FULL, + } + .add(&mut h.rsc); + h.set_root(root); + for (start, end) in [(0.13, 0.83), (-0.17, 1.23), (0.31, 0.67)] { + let before = draws.get(); + h.rsc[root].region.x = UiSpan::new(Len::px(13.125), Len::px(287.375)); + h.rsc[root].extent = UiRegion::new( + UiSpan::new(Len::rel(start), Len::rel(end)), + UiSpan::new(Len::px(7.25), Len::rel(end)), + ); + h.frame(); + assert_eq!(draws.get(), before); + let retained = primitive_bounds(&h, text.id()); + assert!(!retained.is_empty()); + let _ = h.rsc.widgets_mut().get_dyn_mut(text.id()); + h.frame(); + assert!(draws.get() > before); + assert_eq!(retained, primitive_bounds(&h, text.id())); + } + } +}