Commit 66f27eb
Fix radial-gradient position being dropped after an explicit size (#57873)
Summary:
`processBackgroundImage` silently drops the `at <position>` clause of a radial gradient whenever it follows an explicit size, and then re-parses the position values as a new size that overrides the declared one.
In the explicit-size branch of `parseRadialGradientCSSString`, the parser shifts the next token to look for a second size value. When that token is not a length/percentage it is discarded instead of being put back — so for `radial-gradient(circle 100px at 25% 75%, red, blue)` the `at` token is swallowed, the loop then treats `25%` and `75%` as a new `<size>`, and the gradient parses as:
```js
// before
{shape: 'circle', size: {x: '25%', y: '75%'}, position: {top: '50%', left: '50%'}}
// after (matches web)
{shape: 'circle', size: {x: 100, y: 100}, position: {left: '25%', top: '75%'}}
```
The bug was invisible in tests because the only existing test for this syntax uses `at center`, which is indistinguishable from the default position.
The fix is to unshift the peeked token back so the main loop processes it (this also fixes `<size> <shape>` orderings like `100px ellipse`, where the shape keyword was previously swallowed too). The structured C++ parser in `react/renderer/css/CSSBackgroundImage.h` is not affected — this is specific to the JS tokenizer.
## Changelog:
[GENERAL] [FIXED] - Fix radial-gradient `at <position>` being ignored (and corrupting the size) when it follows an explicit size
Pull Request resolved: #57873
Test Plan:
Added two Fantom tests in `processBackgroundImage-itest.js` covering `circle 100px at 25% 75%` (single explicit size + position) and `50px 100px at left bottom` (two sizes + keyword position).
Verified the parse output for a matrix of radial gradient strings against Chrome's accepted/computed values (all match after the fix, including the untouched `circle 100px at center` case covered by the existing test):
| input | before | after |
| --- | --- | --- |
| `circle 100px at 25% 75%` | size `{25%, 75%}`, position center | size `{100, 100}`, position `{left 25%, top 75%}` |
| `50px 100px at left bottom` | unaffected | unaffected |
| `circle 100px at center` | ✓ (masked the bug) | ✓ |
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Reviewed By: fabriziocucci
Differential Revision: D115426012
Pulled By: cipolleschi
fbshipit-source-id: 9964c4196f1101655fe02fdbe219bc8f599f3e741 parent 727e87e commit 66f27eb
2 files changed
Lines changed: 21 additions & 0 deletions
File tree
- packages/react-native/Libraries/StyleSheet
- __tests__
Lines changed: 16 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
999 | 999 | | |
1000 | 1000 | | |
1001 | 1001 | | |
| 1002 | + | |
| 1003 | + | |
| 1004 | + | |
| 1005 | + | |
| 1006 | + | |
| 1007 | + | |
| 1008 | + | |
| 1009 | + | |
| 1010 | + | |
| 1011 | + | |
| 1012 | + | |
| 1013 | + | |
| 1014 | + | |
| 1015 | + | |
| 1016 | + | |
| 1017 | + | |
1002 | 1018 | | |
1003 | 1019 | | |
1004 | 1020 | | |
| |||
Lines changed: 5 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
348 | 348 | | |
349 | 349 | | |
350 | 350 | | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
351 | 356 | | |
352 | 357 | | |
353 | 358 | | |
| |||
0 commit comments