Report the step at or above a text's longest line
A wrapping text reported the width it used rounded to the nearest step, which is under the line it measured half the time. A parent that sizes itself from that report then hands the text back a box its own longest line does not fit in, and breaking there is a different break -- one line more. Two tolerances were hiding it and both go. `TextBuffer::shape` answered a width up to 0.05 px under the longest line from the break in hand, which is a structural decision taken on a hair's breadth: it kept a warm tree self-consistent while a cold tree at the same width broke differently, and 0.05 px is fifty steps of the grid. The `Holds` range the text declares started at the nearest step to its longest line for the same reason, so it admitted boxes the line does not fit in. Both are the line itself now, exactly, because the report no longer lands under it. Found by seeds 1121 and 1839 at depth 4, which fail on `ea6dbae` and every commit before it: a defect older than anything on this branch, reached by running 2000 seeds at a depth the long runs do not use. Shrunk to the eight widgets `a_text_is_given_back_a_box_the_line_it_measured_fits_in` builds. 2000 seeds at depth 4 over all fifteen cases are clean now, as are the three long runs. `text` is the one reference render that moves: its lower paragraph shifts a pixel, the box being a step wider and its left edge crossing a snap boundary. Same words, same lines, same breaks; `tabs`, `view`, `minimal` and `random` are byte-identical.
This commit is contained in:
1 parent
ffd79f32d3
commit
4bd8607968
4 files changed
+119
-15
No files matched your search
+12
-2
@@ -55,8 +55,13 @@ impl TextView {
|
||||
// line up to the one it was made at: each line still fits, and none
|
||||
// could take a word that did not fit in the wider box. A line too
|
||||
// long to fit at all says nothing about narrower boxes.
|
||||
//
|
||||
// The step at or above that longest line rather than the nearest
|
||||
// one, since the shaper measures in floats: the nearest step is
|
||||
// under the line half the time, and a range starting there admits a
|
||||
// box the line does not fit in, where the break is not this one.
|
||||
if let Some(width) = width {
|
||||
painter.holds(Axis::X, Px::from_f32(text.size.x).min(width)..=width);
|
||||
painter.holds(Axis::X, Px::ceil_from_f32(text.size.x).min(width)..=width);
|
||||
}
|
||||
text
|
||||
}
|
||||
@@ -78,7 +83,12 @@ impl TextView {
|
||||
|
||||
let tex = self.render(painter);
|
||||
let region = tex.size.align(align);
|
||||
let size = Size::px(tex.size);
|
||||
// The step at or above what the shaper measured, so a parent that
|
||||
// hands back the length this reports hands back a box the longest
|
||||
// line fits in. Rounded to the nearest step it is half the time a
|
||||
// hair under that line, and the break made in it is not the break a
|
||||
// cold layout makes there.
|
||||
let size = Size::from_px(PxVec2::ceil_from_f32(tex.size));
|
||||
let within = region.within(&painter.region());
|
||||
painter.glyphs(tex, within);
|
||||
(region, size)
|
||||
|
||||
Reference in new issue
Block a user