fix(ios,android): polish wavy/dotted/dashed text decoration rendering#56749
Open
quantizor wants to merge 4 commits intofacebook:mainfrom
Open
fix(ios,android): polish wavy/dotted/dashed text decoration rendering#56749quantizor wants to merge 4 commits intofacebook:mainfrom
quantizor wants to merge 4 commits intofacebook:mainfrom
Conversation
Android's `Layout.draw` paints the underline produced by `setUnderlineText(true)` using `paint.color`, ignoring `paint.underlineColor` on all API levels. This caused `textDecorationColor` to be silently dropped on Android. Refactor `ReactUnderlineSpan` to extend `DrawCommandSpan` and paint the underline itself in `onDraw`, falling back to the text color when no color was specified. Thread the color through `TextAttributeProps` (both MapBuffer and ReadableMap ingestion paths) and `TextLayoutManager`. Add `DrawCommandSpan` invocation to `ReactTextView.onDraw`, mirroring the existing `PreparedLayoutTextView` behavior so both text view classes honor custom-drawing spans. ## Changelog [ANDROID] [FIXED] - Text underlines honor `textDecorationColor` ## Test Plan Render a Text component with `textDecorationColor` set to a value distinct from the text color; the underline now renders in the specified color rather than the text color. Verified on Android API 36 emulator.
Iterations on the textDecorationStyle implementation that landed in PR facebook#56748, based on visual comparison with Chrome / Safari and side-by-side testing of the two platforms. iOS: - Wavy: thickness divisor relaxed from `fontSize / 8` to `fontSize / 12` and control-point distance multiplier halved (`1.5 * thickness + 0.5` vs Blink's literal `3 * thickness + 0.5`). At iOS point sizes the literal Blink amplitude renders as a very pronounced wave; the dialed- back values read as a clear-but-subtle browser-style wave. - Dotted: switched from UIKit's `NSUnderlineStylePatternDot` (which doesn't match browser geometry) to a custom CG path with a zero-length dash + round line caps, producing actual circular dots at `2 * thickness` spacing. - Dashed: switched from UIKit's `NSUnderlineStylePatternDash` to custom CG path with `[2 * thickness, thickness]` intervals — short rectangular dashes with a tight gap, closer to Safari's geometry than UIKit's default. - The custom decoration attribute (formerly `RCTWavyDecorationAttributeName`) is now `RCTCustomDecorationAttributeName` and carries a `style` key so the same drawing pipeline handles wavy + dotted + dashed. Cross-platform: - Wavy drawing loop now iterates `while x < x2` instead of `while x + wavelength <= x2`, so the final cycle continues through the last character (including trailing punctuation). Previously a trailing period could be visually uncovered when the run width was not an integer multiple of the wavelength. ## Changelog: [IOS] [CHANGED] - Wavy, dotted, and dashed text decorations render with custom CoreGraphics paths instead of UIKit pattern bits, matching browser geometry more closely [GENERAL] [FIXED] - Wavy underline / strikethrough now extends through the final character of the run, including trailing punctuation ## Test Plan: Side-by-side comparison on Android API 36 emulator and iPhone 17 sim (iOS 26.4) of a `<Text>` with `textDecorationLine="underline"` and `textDecorationStyle` cycling through `wavy` / `dotted` / `dashed`, verified against Chrome (Android view) and Safari (iOS view) rendering of the same CSS. Trailing periods now fall under the wavy stroke on both platforms.
5898e8f to
7bf5142
Compare
Contributor
|
@quantizor would it be too hard to split this into 2 separate PRs? 🙏 |
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.
Summary:
Polish pass on the
textDecorationStylecross-platform implementation from #56748, based on visual comparison with Chrome (Android) and Safari (iOS) rendering of the same CSS.iOS rendering:
fontSize / 8tofontSize / 12and the control-point distance multiplier halved (1.5 * thickness + 0.5vs Blink's literal3 * thickness + 0.5). At iOS point sizes the literal Blink amplitude renders as a very pronounced wave because Core Graphics paints in points, not device pixels — the dialed-back values read as a clear-but-subtle browser-style wave.NSUnderlineStylePatternDot(which doesn't match browser geometry on iOS) to a custom CG path with a zero-length dash + round line caps, producing actual circular dots at2 * thicknessspacing.NSUnderlineStylePatternDashto a custom CG path with[2 * thickness, thickness]intervals — short rectangular dashes with a tight gap, closer to Safari's geometry than UIKit's default.RCTWavyDecorationAttributeName) is nowRCTCustomDecorationAttributeNameand carries astylekey so the same drawing pipeline handles wavy + dotted + dashed.Cross-platform:
while x < x2instead ofwhile x + wavelength <= x2, so the final cycle continues through the last character (including trailing punctuation). Previously a trailing period could be visually uncovered when the run width was not an integer multiple of the wavelength.Changelog:
[IOS] [CHANGED] - Wavy, dotted, and dashed text decorations render with custom CoreGraphics paths instead of UIKit pattern bits, matching browser geometry more closely
[GENERAL] [FIXED] - Wavy underline / strikethrough now extends through the final character of the run, including trailing punctuation
Test Plan:
Side-by-side comparison on Android API 36 emulator and iPhone 17 sim (iOS 26.4) of a
<Text>withtextDecorationLine="underline"andtextDecorationStylecycling throughwavy/dotted/dashed, verified against Chrome (Android view) and Safari (iOS view) rendering of the same CSS. Trailing periods now fall under the wavy stroke on both platforms.