fix(iOS): hold first/last gradient stop colors for out-of-range stops (CLAMP parity with Android)#16
Draft
andrewkunkel wants to merge 1 commit into
Draft
Conversation
… (CLAMP parity with Android) iOS clamped each color-stop position independently into [0, 1] before handing locations to CAGradientLayer, so stops positioned outside the gradient box collapsed onto the edge and distorted the gradient. Android passes raw positions to android.graphics.LinearGradient/RadialGradient with Shader.TileMode.CLAMP, which holds the first/last colors and shows only the visible slice of a gradient whose stops extend past the box. Emulate CLAMP on iOS by resampling out-of-range stops back into [0, 1]: hold the terminal color as a solid fill when the whole box is past the first/last stop, and interpolate boundary colors (reusing the existing straight-sRGB RCTInterpolateColorInRange path) otherwise. In-range stops pass through unchanged, so the common case is preserved byte-for-byte. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nxs5hyXkj8fZ6TUPzv37cA
andrewkunkel
force-pushed
the
claude/text-gradient-clamp-mode-kpjohk
branch
from
July 16, 2026 17:13
e045964 to
51bcaf1
Compare
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:
View background gradients (
experimental_backgroundImage) rendered differently on iOS and Android whenever a color-stop position fell outside the[0, 1]gradient box (e.g.linear-gradient(to right, red -50%, blue 150%), percentages beyond 0–100%, orpxstops that extend past the box).< 0or> 1— only a monotonic lower-bound clamp is applied) straight intoandroid.graphics.LinearGradient/RadialGradientwithShader.TileMode.CLAMP. CLAMP holds the first color before the first stop and the last color after the last stop, so a gradient whose stops extend past the box shows only its visible slice.RCTGradientUtils.mm,getColors:andLocations:) clamped each stop position independently into[0, 1]before handinglocationstoCAGradientLayer. This collapsed out-of-range stops onto the box edge and distorted the gradient instead of holding the terminal colors.CAGradientLayer.locationsmust lie within[0, 1](it clamps out-of-range values internally), so the fix cannot simply pass raw positions through — it emulatesTileMode.CLAMPby resampling the fixed-up stop list into the[0, 1]window:RCTInterpolateColorInRangepath (the same interpolation the transition-hint code already uses, matching Android's default sRGB shader interpolation).Stops already within
[0, 1]pass through unchanged, so the common case is preserved byte-for-byte. The change is contained toRCTGradientUtils.mm— no call-site or public-signature changes, and the linear "squish" correction / radial axis math are untouched (their axis endpoints already map to positions 0 and 1).Changelog:
[IOS] [FIXED] - Gradient color stops positioned outside
[0, 1]now hold the first/last stop colors, matching Android'sShader.TileMode.CLAMPbehaviorTest Plan:
Manual visual verification on a local iOS build against Android (there is no automated screenshot coverage for gradients in the repo today):
linear-gradient(to right, red -50%, green 50%, blue 150%)(partial slice) andlinear-gradient(to right, red 120%, blue 150%)(solid hold), plus a radial equivalent.[0, 1]).🤖 Generated with Claude Code