Skip to content

Commit cb63782

Browse files
nduaartemeta-codesync[bot]
authored andcommitted
Fix color stop interpolation when positioned stop has no gap before it (#57356)
Summary: Fixes #57345 `ColorStopUtils.getFixedColorStops()` produced incorrect positions when a color stop with an explicit position was immediately followed by a color stop without a position (i.e. zero unpositioned stops between them). The root cause is that `lastDefinedIndex` was only advanced when interpolation actually occurred (`unpositionedStops > 0`). When a positioned stop was encountered with no unpositioned stops before it, `lastDefinedIndex` failed to advance, causing the *next* interpolation to use a stale start point and silently overwrite the explicitly declared position of the skipped stop. The fix adds an `else if` branch that advances `lastDefinedIndex` whenever the current stop has a defined position, even when no interpolation is needed at that step. ## Changelog: [ANDROID] [FIXED] - Fix incorrect color stop positions in gradients when a positioned stop is immediately followed by an unpositioned stop Pull Request resolved: #57356 Test Plan: Added `testColorStopsWithPositionedStopAdjacentToUnpositionedStop` to `ColorStopTest.kt`, covering the exact case from the issue: Input: [red 0%, green 20%, blue (no position), yellow 80%, purple 100%] Expected: [0.0, 0.2, 0.5, 0.8, 1.0] Before the fix this produced [0.0, 0.267, 0.533, 0.8, 1.0]. Verified the new test passes via CI (no local Android environment available). Reviewed By: Abbondanzo Differential Revision: D110037894 Pulled By: javache fbshipit-source-id: f7bc84b01f88aa343c03d83fc3293ee744240c41
1 parent 3fcde34 commit cb63782

2 files changed

Lines changed: 31 additions & 0 deletions

File tree

  • packages/react-native/ReactAndroid/src

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/style/ColorStop.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,12 @@ internal object ColorStopUtils {
124124
)
125125
}
126126
lastDefinedIndex = i
127+
} else if (endPosition != null) {
128+
// Current stop has a defined position but there are no unpositioned
129+
// stops between lastDefinedIndex and i. Still need to advance
130+
// lastDefinedIndex so that subsequent interpolation uses the
131+
// correct start point instead of stale data.
132+
lastDefinedIndex = i
127133
}
128134
}
129135
}

packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/style/ColorStopTest.kt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,4 +158,29 @@ class ColorStopTest {
158158
assertThat(processed[20].color).isEqualTo(Color.BLUE)
159159
assertThat(processed[20].position).isEqualTo(1f)
160160
}
161+
162+
@Test
163+
fun testColorStopsWithPositionedStopAdjacentToUnpositionedStop() {
164+
val colorStops =
165+
listOf(
166+
ColorStop(Color.RED, LengthPercentage(0f, LengthPercentageType.PERCENT)),
167+
ColorStop(Color.GREEN, LengthPercentage(20f, LengthPercentageType.PERCENT)),
168+
ColorStop(Color.BLUE),
169+
ColorStop(Color.YELLOW, LengthPercentage(80f, LengthPercentageType.PERCENT)),
170+
ColorStop(Color.MAGENTA, LengthPercentage(100f, LengthPercentageType.PERCENT)),
171+
)
172+
val processed = ColorStopUtils.getFixedColorStops(colorStops, 100f)
173+
174+
assertThat(processed).hasSize(5)
175+
assertThat(processed[0].color).isEqualTo(Color.RED)
176+
assertThat(processed[0].position).isEqualTo(0f)
177+
assertThat(processed[1].color).isEqualTo(Color.GREEN)
178+
assertThat(processed[1].position).isEqualTo(0.2f)
179+
assertThat(processed[2].color).isEqualTo(Color.BLUE)
180+
assertThat(processed[2].position).isEqualTo(0.5f)
181+
assertThat(processed[3].color).isEqualTo(Color.YELLOW)
182+
assertThat(processed[3].position).isEqualTo(0.8f)
183+
assertThat(processed[4].color).isEqualTo(Color.MAGENTA)
184+
assertThat(processed[4].position).isEqualTo(1f)
185+
}
161186
}

0 commit comments

Comments
 (0)