fix(text): colour alpha, rich_text whitespace and baseline, gradient_text angle and stops - #392
Merged
Merged
Conversation
…adient angle Three text components silently diverged from their own documented model: - text forced style.color's alpha to 1.0 after parsing it, so a translucent color rendered fully opaque. rich_text, backgrounds and borders already respected alpha; text was the outlier. Just stop clobbering it. - rich_text tokenized every span with split_whitespace(), which collapses runs of spaces to a single one — so white-space: pre (or nowrap) lost leading/internal spaces that the plain text component preserves. It also computed its baseline as (line_height + ascent) / 2, dropping descent, which text's formula includes; that alone put rich_text ~9px lower than an identical text at the same font size, so swapping one for the other visibly jumped. Pre/nowrap now keeps each span's text verbatim as a single token with no re-wrapping, and the baseline formula now matches text's. - gradient_text's default angle (90) rendered vertical because the angle was applied as (cos, sin) — a top/bottom axis — while CSS defines 90deg as "to right". It also always drew the gradient across the box diagonal regardless of angle, so a wide/short text sampled only the unsaturated middle of the ramp. angle now follows the CSS convention (0 = to top, 90 = to right — same meaning as view.background's linear-gradient) and the gradient line is the CSS box projection (|w*sin(a)| + |h*cos(a)|), so the first and last colors land exactly on the first and last glyph edges at any angle. This changes what the same angle number renders as; scenarios that set an explicit angle to work around the old axis need a look. A new optional `stops` field (color + position) lets a scenario place colors explicitly instead of the always-even default spacing, which stays the fallback when stops is omitted. Each fix has a pixel-level test that fails on the pre-fix code: - text::tests::a_translucent_color_alpha_channel_survives_to_the_painted_pixels - rich_text::tests::white_space_pre_keeps_leading_spaces_as_a_single_literal_token - rich_text::tests::white_space_pre_preserves_leading_spaces_at_the_pixel_level - rich_text::tests::baseline_offset_matches_the_text_components_formula - gradient_text::tests::default_angle_ramps_left_to_right_across_the_glyphs - gradient_text::tests::gradient_line_length_is_the_box_projection_not_the_diagonal - gradient_text::tests::explicit_stops_override_even_color_spacing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #366. Closes #367. Closes #368. Refs #388.
#368 changes what an existing
gradient_textanglerenders as. The angle was applied as(cos θ, sin θ); it now follows the CSS convention(sin θ, −cos θ), so0°is to top and90°is to right. The default stays90, and now genuinely renders left-to-right.A scenario that set an explicit
angleto compensate for the old axis will render differently. That is the fix, not a side effect — but it is worth a look at any file that tuned an angle by eye.#366 —
textignored the alpha ofstyle.colorpaint.set_alpha_f(1.0)immediately afterpaint_from_hex(color)threw the parsed alpha away.hex-colors.mdalready documented#RRGGBBAAgenerically — that claim is now true fortexttoo.#367 —
rich_text: two independent bugsLeading spaces. Tokenization always used
split_whitespace(), collapsing runs. Awhite-space: pre|nowrapbranch now keeps each span verbatim and disables wrapping, mirroring whattextalready does for those values.The 9 px offset.
baseline_offsetwas(line_height + ascent) / 2, missing the descent;textuses(line_height + ascent − descent) / 2.A 9 px gap — exactly the issue's own measurement.
#368 —
gradient_text: angle, line length, andstopsBeyond the angle convention above, the gradient line length was the box diagonal regardless of angle. It is now the CSS box projection
(|w·sinθ| + |h·cosθ|) / 2, so the first and last colour land on the first and last glyph edge at any angle. The pre-fix symptom is the issue's own: the left glyph edge read(152, 0, 103)— muddy purple — instead of the first colour.New optional
stops(color+position), falling back to even spacing when omitted. Pinned as backward-compatible:even=(50, 205, 0), skewed=(50, 205, 0)was the pre-fix failure, identical colours provingstopswas ignored.Verification
Seven tests, each proven red before the fix by hand-editing the code back rather than by
git stash(worktree safety).cargo fmt --all --check,cargo clippy --workspace --all-targets -- -D warnings,cargo test --workspace(1601) all clean. Comment count still 0 — the only///added are onGradientTextStopand the newstopsfield, bothJsonSchema-derived.Also found
The
gradient_textearly-return guard would have skipped rendering for a scenario usingstopswith an explicitcolors: []. Widened, since it is the same code path.Written comment-free, per the codebase-wide rule from #345.