Repository navigation
Commit 5a29c68
Animate filter without forcing a Fabric commit every frame (#58071)
Summary:
`NativeAnimatedAllowlist.h` carries this instruction:
```c++
/**
* Direct manipulation eligible styles allowed by the NativeAnimated JS
* implementation. Keep in sync with
* packages/react-native/Libraries/Animated/NativeAnimatedAllowlist.js
*/
```
It has drifted by one entry. `SUPPORTED_STYLES` in the JS file lists `filter` between `opacity` and `transform`; the C++ set goes straight from `"opacity"` to `"transform"`. Every other member of the JS list's non-layout half is present, so this is a missed sync rather than a deliberate exclusion.
The set is not advisory — it is what separates layout props from paint props:
```c++
// StyleAnimatedNode.cpp
bool isLayoutPropsUpdated(const folly::dynamic& props) {
for (const auto& styleNodeProp : props.items()) {
if (getDirectManipulationAllowlist().count(styleNodeProp.first.asString()) == 0u) {
return true; // absent => treated as a layout prop
}
}
return false;
}
```
and that verdict picks the transport:
```c++
// NativeAnimatedNodesManager.cpp
auto& current = layoutStyleUpdated
? updateViewPropsForBackend_[viewTag] // Fabric commit
: updateViewPropsDirectForBackend_[viewTag]; // direct manipulation
```
So animating `filter` runs a shadow-tree commit on every frame instead of taking the direct-manipulation path, for a property that cannot affect layout — `filter` lives in `BaseViewProps` (`std::vector<FilterFunction> filter{}`), not in `YogaStylableProps`, and nothing in `react/renderer/animated/` treats it specially.
Note the C++ set is deliberately *not* a mirror of the whole JS `SUPPORTED_STYLES`: the entries the JS file adds under `useSharedAnimatedBackend()` (`width`, `height`, `margin`, `padding`, `flex`, `gap`, …) are genuine layout props and must stay out so they keep going through Fabric. Only the non-layout half has to match, and `filter` belongs to it.
## Changelog:
[GENERAL] [FIXED] - Animating `filter` no longer forces a Fabric commit on every frame
Pull Request resolved: #58071
Test Plan:
Added `directManipulationAllowlistCoversNonLayoutStyles` to `AnimatedNodeTests`. It asserts the allowlist contains every non-layout style the JS file supports, and — so the test cannot be satisfied by simply widening the set — that the layout styles are still absent.
The allowlist header is dependency-free, so the invariant can also be checked directly:
```
$ c++ -std=c++20 -Wall -Wextra -I packages/react-native/ReactCommon allowcheck.cpp -o allowcheck
# before
MISSING from C++ allowlist: filter
checked 34 JS non-layout styles, missing=1 (exit 1)
# after
checked 34 JS non-layout styles, missing=0 (exit 0)
```
```
$ yarn jest packages/react-native/Libraries/Animated
Test Suites: 3 passed, 3 total
Tests: 66 passed, 66 total
$ node ./scripts/clang-format.js <both changed files>
(no changes)
```
`getDirectManipulationAllowlist` appears in the C++ API snapshots, but only by signature — this changes the contents of the static set, not the declaration, so `scripts/cxx-api` is unaffected.
The gtest itself was neither executed locally nor built by the public CI. `react/renderer/animated/tests` is excluded from the iOS build (`React-Fabric.podspec`: `ss.exclude_files = "react/renderer/animated/tests"`) and is not in the Android CMake glob (`react/renderer/animated/CMakeLists.txt` globs `*.cpp drivers/*.cpp event_drivers/*.cpp internal/*.cpp nodes/*.cpp`), so it builds only in the internal build reached at import time. What is verified here: the test body compiles clean against the real header under `-std=c++20 -Wall -Wextra`, and the standalone parity check above exercises the same assertions and fails without the one-line change.
Reviewed By: zeyap
Differential Revision: D117174629
Pulled By: javache
fbshipit-source-id: 5cfab73b61773df1b10ebc38bfb0a6c365e64fc01 parent a2f0a43 commit 5a29c68
2 files changed
Lines changed: 59 additions & 0 deletions
File tree
- packages/react-native/ReactCommon/react/renderer/animated
- internal
- tests
Lines changed: 1 addition & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
48 | 48 | | |
49 | 49 | | |
50 | 50 | | |
| 51 | + | |
51 | 52 | | |
52 | 53 | | |
53 | 54 | | |
| |||
Lines changed: 58 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
10 | 11 | | |
11 | 12 | | |
12 | 13 | | |
| |||
332 | 333 | | |
333 | 334 | | |
334 | 335 | | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
335 | 393 | | |
0 commit comments