Commit Graph

32 Commits

Author SHA1 Message Date
Valentin Shergin 8684ef499f Fabric: Implementation for ShadowNodeTraits::Trait::MeasurableYogaNode
Summary:
This implements the `MeasurableYogaNode` trait in `YogaLayoutableShadowNode`. We had this trait from the very beginning but never used it. Now, if the trait is specified, `YogaLayoutableShadowNode` will set the measure function for the node and dirty it during cloning.

Previously, we used (and still use) a dedicated method for setting up the measure function - `YogaLayoutableShadowNode::enableMeasurement()`. The problem with it is that to make it work we have to dirty the Yoga node every time we clone it. And the only proper way to do this in the `YogaLayoutableShadowNode` constructor because if we do it later ancestor nodes could not observe this and react to this. Therefore we have to have a trait for it.

The plan is to use it for TextInput first to fix a crash (see the next diff). After we confirm it works fine, we will replace all the usages of `enableMeasurement` with the new trait.

This diff also renames the other two yoga-related traits (to make them less verbose and look unified), adds more comments, and asserts.

Changelog: [Internal] Fabric-specific internal change.

Reviewed By: sammy-SC

Differential Revision: D25937711

fbshipit-source-id: fafbd5d62537ac09e02ffbfd56adab6d629d791d
2021-01-16 15:53:55 -08:00
David Vacca 4076293aa1 Fix changes of View visibilities
Summary:
The purpose of this diff is to ensure that visibility changes are handled correctly when the value of "display" for a View changes from 'flex' to 'none'.

RNTester is nesting several Views with different kind of visibilities. When the user tap on an item there's a state update that changes the visibility styles for some of these views. Fabric does not reflect the right changes of visibility on the screen.

changelog: internal

Reviewed By: shergin

Differential Revision: D25841763

fbshipit-source-id: 769b97afb72939d346a4c6f2669ff938b35596bc
2021-01-10 19:46:40 -08:00
Andres Suarez 0f4f917663 Apply clang-format update fixes
Reviewed By: igorsugak

Differential Revision: D25861683

fbshipit-source-id: 616afca13ae64c76421053ce49286035e0687e36
2021-01-09 22:11:00 -08:00
Samuel Susla deda35134a Make EventQueue a virtual class
Summary:
Changelog: [internal]

EventQueue is used as a virtual class, this diff makes it one.

Reviewed By: JoshuaGross, shergin

Differential Revision: D25826983

fbshipit-source-id: 60e6937514cd3b837b0ca9f61bfaa081823ffc61
2021-01-07 13:42:24 -08:00
Samuel Susla 1bafd0086f Remove v1 event coalescing
Summary:
Changelog: [internal]

Old event coalescing isn't used anymore and there haven't been any problems with the new one.

Reviewed By: shergin

Differential Revision: D25701311

fbshipit-source-id: 359f0361edffa22130cfa8322038acdbe26fd599
2021-01-04 04:12:30 -08:00
Joshua Gross 907b574cf6 LayoutAnimations: change default prop interpolation on Android: set new non-interpolated prop values at beginning of animation, not end
Summary:
In Android, only changed prop values are sent to the mounting layer via folly::dynamic maps. In the LayoutAnimation system, before this, we only sent that
map at the /end/ of the animation for any non-interpolated values (for example, image source is not interpolated so it was not updated until the end of the animation).

However, what we probably expect is that all non-interpolated values change immediately, and interpolated values smoothly transition. This diff makes that change on Android
by using the final RawProps as the /initial/ value that interpolations are stacked on.

Changelog: [Internal]

Reviewed By: mdvacca

Differential Revision: D25727483

fbshipit-source-id: e692d37b9965fedcdf429a81d60b7cb7f0c6abe1
2020-12-29 15:54:45 -08:00
Valentin Shergin f379b1e583 Fabric: Shipping updateStateWithAutorepeat as the only way to update a state
Summary:
This replaces the internal core implementation of `setState` with the new `updateStateWithAutorepeat` which is now the only option.
In short, `updateStateWithAutorepeat` works as `setState` with the following features:
* The state update might be performed several times until it succeeds.
* The callback is being called on every retry with actual previous data provided (can be different on every call).
* In case of a static value is provided (simple case, not lambda, the only case on Android for now), the same *new*/provided value will be used for all state updates. In this case, the state update cannot fail.
* If a callback is provided, the update operation can be canceled via returning `nullptr` from the callback.

This diff removes all mentions of the previous state update approach from the core; some other leftovers will be removed separatly.

Changelog: [Internal] Fabric-specific internal change.

Reviewed By: sammy-SC

Differential Revision: D25695600

fbshipit-source-id: 14b3d4bad7ee69e024a9b0b9fc018f7d58bf060c
2020-12-23 21:49:44 -08:00
Valentin Shergin fba0631ba7 Fabric: Farewell ConcreteStateTeller
Summary:
ConcreteStateTeller is being replaced with a new built-in state autorepeat mechanism.

Changelog: [Internal] Fabric-specific internal change.

Reviewed By: sammy-SC

Differential Revision: D25687692

fbshipit-source-id: a89d0a4d63b9c97775a312afa3df43f26b5ecc08
2020-12-23 10:09:25 -08:00
Samuel Susla 369b3d2983 Remove unused methods from LayoutableShadowNode
Summary:
Changelog: [internal]

These methods were not used, removing them.

Reviewed By: shergin

Differential Revision: D25680765

fbshipit-source-id: 7e44aa5b9c4ffa9d0264b573dcb7edc2ad2a74c3
2020-12-23 04:45:54 -08:00
Samuel Susla 2669118fc8 Make event coalescing more aggressive
Summary:
Changelog: [internal]

Previous implementation of coalescing would only look at the last element in `eventQueue_` and if it was the same type and target, it would coalesce the two together. This was problem when user would scroll in UIScrollView, this triggers onTouchMove and onScroll events at high rates and prevents coalescing of them.

This changes changes the behaviour to search the `eventQueue_` backwards for an event of the same type and target. If one if found, it is moved into its place. If even of another type is found before for the same target, the event is pushed back onto the queue.

Reviewed By: JoshuaGross

Differential Revision: D24992941

fbshipit-source-id: fc1eae4ecd100af6202346674778b0634ed7a15b
2020-11-17 04:21:01 -08:00
Valentin Shergin bd7ab6c90b Fabric: Introducing YogaLayoutableKindMutatesStylesAfterCloning trait
Summary:
This implements a new ShadowNode trait that helps to propagate Yoga node `isDirty` flag down the root of the tree and clone siblings appropriately.

Several Fabric components mutate its Yoga styles after the node was cloned. In such cases, we need to mark the node as dirty after doing so. The problem with this is that the parent node and its siblings were already updated (cloned or not) based on the previous value of the `isDirty` flag. This happens because this logic is implemented in YogaLayoutableShadowNode which is a base constructor that must be called before any other logic from a subclass can run.

For now, this change enables that for SafeAreaView only (which seems to help with some junkiness issues), later we can extend the usage of this for other components if needed.

Changelog: [Internal] Fabric-specific internal change.

Reviewed By: JoshuaGross

Differential Revision: D24719347

fbshipit-source-id: b0d050afea5de9c470e05e1b4c9e7052e00ae949
2020-11-04 08:10:30 -08:00
Valentin Shergin 0cec0134e6 Fabric: operator== for LayoutContext
Summary:
We will need it soon.

Changelog: [Internal] Fabric-specific internal change.

Reviewed By: sammy-SC

Differential Revision: D24290775

fbshipit-source-id: a312e537a3c3954e709a10c8792b3462b574054a
2020-10-15 10:47:11 -07:00
Samuel Susla 0544568d86 Drop old state updates
Summary:
Changelog: [internal]

Components can update state multiple times before the state update queue is flushed. This causes unnecessary layout/diff and mount passes. To solve this, drop stale state updates inside `stateUpdateQueue_ ` for specific `ShadowNodeFamily`.

Delivering stale status updates is redundant. Let's take SafeAreaView as an example. It schedules 5-6 state updates before `stateUpdateQueue_` is flushed. That's unnecessary work blocking JS thread. We only care about the latest state update. Same for TextInput and other components using state updates.

Reviewed By: JoshuaGross

Differential Revision: D23987707

fbshipit-source-id: 2e3f92cc93af61d78ac564aa40aef165af64b8c1
2020-09-30 08:36:06 -07:00
Samuel Susla 18f29db5a7 Fix ordering of children in LayoutableShadowNode::findNodeAtPoint
Summary:
Changelog: [internal]

`LayoutableShadowNode::findNodeAtPoint` was iterating children in incorrect order and wasn't taking zIndex into accout.

Reviewed By: JoshuaGross

Differential Revision: D23814866

fbshipit-source-id: 38eee297147a5c5912304d139bb10f8b16ae2ee1
2020-09-21 11:14:19 -07:00
Samuel Susla 30d170adc6 Use Element<> in FindNodeAtPointTest
Summary: Changelog: [Internal]

Reviewed By: JoshuaGross

Differential Revision: D23815171

fbshipit-source-id: bf420be172a55a966f8881371473e121c3848c78
2020-09-21 11:14:19 -07:00
Valentin Shergin 57dd48b246 Fabric: Marking all JS function lambdas noexcept in UIManagerBinding
Summary:
Exceptions in C++ work quite differently from exceptions in other languages. To make exceptions actually work **correctly** all the code needs to be written with "exceptions in mind" (e.g., see https://www.stroustrup.com/except.pdf). In short, if the code is not "exceptions ready", throwing an exception causes memory leaks, dangling pointers, and invariant violations all over the place, which will probably cause another crashes down the road (which will be especially hard to investigate and attribute to the original issue).
Fabric Core (Layout, Props parsing, ShadowNodes management, and so on) does not use exceptions because in most (all?) the cases the exception is now recoverable. So, if a program detects some internal state invariant violation or missing some resource, *logically* it's fatal. We also don't want to pay code-size and performance tax for exception support, so that's why we don't use them. It's just not the right fit for Fabric Core.

This does not mean that exceptions don't happen though. C++ standard library can throw them... sometimes. And if our library is compiled with exceptions enabled (still the case, unfortunately), an exception can bubble to JavaScript code and losing all context down the road. And it's hard to investigate such crashes. To isolate those occasional exceptions inside C++ core we are marking all C++/JS boundaries with `noexcept` that stops the bubbling.

I hope that will give us much more informative crash reports.

Changelog: [Internal] Fabric-specific internal change.

Reviewed By: sammy-SC

Differential Revision: D23787492

fbshipit-source-id: 0822dbf36fc680c15b02b5cd0f2d87328296b642
2020-09-18 17:07:29 -07:00
Valentin Shergin a8b090b128 Fabric: Another attempt to deal with failing state updates
Summary:
This is *another* attempt to solve a failed state update problem.

Unfortunately, some applications are inherently not compatible with the "let's recommit the update on the application side in case it failed" approach. The problem is that if we call `updateState` on the application side, we miss the original event window. E.g. if we need to deliver some state update with AsyncBatched priority and if the update fails, we lose the opportunity to commit it on time. These issues can be critical for some complex use-cases as ComponentKit interop.

This diff adds implementation for `updateState` that does the work a bit differently. For all failed state updates it tres to recommit them asap using `ShadowTree::commit` and calling lambda on every attempt. With this approach the update might fail in two cases:
The node disappeared from the tree, so there is no way to update it.
The lambda returned `nullptr` indicating that the update is no longer needed.

We need this for the ComponentKit interoperability layer that is very sensitive for missing state updates.

Changelog: [Internal] Fabric-specific internal change.

Reviewed By: sammy-SC

Differential Revision: D23603958

fbshipit-source-id: a3b8c09fb2f1c8302583aa5880b48fc0840224e3
2020-09-11 09:22:08 -07:00
empyrical 777bf6529a Fabric Tests: Change default constructor in TestComponents' TestProps (#29898)
Summary:
This pull request changes the default constructor in the `TestProps` class in `react/renderer/core/tests/TestComponent.h`

`using ViewProps::ViewProps;` was causing problems in Visual Studio 2017 - changing it to ` TestProps() = default;` allowed dependent CPP files to compile on MSVC and caused no regressions in the Fabric test suite.

## Changelog

Changelog: [Internal] [Changed] - Fabric Tests: Change default constructor in TestComponents' TestProps

Pull Request resolved: https://github.com/facebook/react-native/pull/29898

Test Plan: The Fabric test suite passes on Windows after this change is made. I also tested it under macOS and Linux built with Clang and they both pass with this change made.

Reviewed By: sammy-SC

Differential Revision: D23591986

Pulled By: shergin

fbshipit-source-id: 132e1c2e38fa74aa4f2c8746054d6152f30035e9
2020-09-10 10:41:27 -07:00
Valentin Shergin 900c3878e1 Fabric: Removing ShadowNode state revision
Summary:
We don't use it anymore.

Changelog: [Internal] Fabric-specific internal change.

Reviewed By: sammy-SC

Differential Revision: D23605897

fbshipit-source-id: 3502726d2b249f75f6c3992b7685869cf7dd154f
2020-09-09 15:08:23 -07:00
Samuel Susla 19cd630f04 Clone node with state in yogaNodeCloneCallbackConnector
Summary: Changelog: [Internal]

Reviewed By: shergin

Differential Revision: D23317682

fbshipit-source-id: c273804efbe48143dcecd7c62c4edced0a746bc6
2020-08-25 14:48:38 -07:00
Samuel Susla 2bc8ce1549 Introduce ConcreteStateTeller
Summary:
Changelog: [internal]

# What is Teller?
Teller is a bank's employee who deals with the customer on behalf of the bank. In Fabric's scenario it is a class that on behalf of the view deals with State.

# Why do we need it?
Dealing with `ConcreteState` can be complicated and patterns are often repeated among different component views. `ConcreteStateTeller` aims to resolve these issues. Examples:
- You can call teller's methods without checking for nullptr (we have had crashes because of this before).
- Methods are save to be called on any thread.
- Mechanism to retry state update if it fails is built in.

It is designed to be used from ComponentView so views don't have to talk directly to `ConcreteState`.

Reviewed By: JoshuaGross, shergin

Differential Revision: D23216865

fbshipit-source-id: 90a50702e036eac084f89743ebab687a67182dc0
2020-08-24 06:43:17 -07:00
Samuel Susla 6c1ee871c0 Calling ConcreteShadowNode::setStateData sets mostReventState
Summary:
Changelog: [Internal]

If `ConcreteShadowNode::setStateData` is called and the node is cloned before it is mounted, the cloned node will have old state before `setStateData` was called.

To solve this, simply call `setMostRecentState` on the family inside `ConcreteShadowNode::setStateData`.

Reviewed By: JoshuaGross

Differential Revision: D23283560

fbshipit-source-id: f9822fb69e4234f776d512fc02fe13ea7de64897
2020-08-24 01:43:29 -07:00
Joshua Gross 77accf2380 Log more diagnostics when JSI values cannot be cast to Object
Summary:
There are a few places where we cast JSI values to objects without much validation and without proper error logging, and in some places the crashes aren't symbolicated well. To make debugging easier in the short-term, I'm adding some additional logs.

Changelog: [Internal]

Reviewed By: mdvacca, RSNara

Differential Revision: D23033222

fbshipit-source-id: 9343d693a441f0af728e560a0c245bcc4eb97869
2020-08-10 16:08:50 -07:00
Samuel Susla 154ce78972 Take viewport offset into account in UIManager.measureInWindow
Summary:
Changelog: [Internal]

Fabric's UIManager.measureInWindow didn't take viewport's offset into account. This diff fixes it by including viewport's offset in `LayoutContext`.

Reviewed By: JoshuaGross

Differential Revision: D23021903

fbshipit-source-id: 9106a8789d66fe19d8cb0a9378ee5bc8f2c83005
2020-08-10 12:52:23 -07:00
Samuel Susla efd005724f Convert LayoutableShadowNodeTests to use Element<>
Summary:
Changelog: [internal]

Use `Element<>` in `LayoutableShadowNodeTests`. It makes the tests cleaner and easier to understand.

Reviewed By: JoshuaGross

Differential Revision: D23028341

fbshipit-source-id: f7a2255581bdde667db0f68c222228a5b405b22f
2020-08-10 12:52:23 -07:00
Samuel Susla 8d6b41e9bc Add support for onTextLayout in Text
Summary:
Changelog: [Internal]

Add `Text.onTextLayout` implementation

Reviewed By: JoshuaGross

Differential Revision: D22865139

fbshipit-source-id: 563084754ebdc9fb23463a306c526b97c61f85ec
2020-08-10 05:42:20 -07:00
Samuel Susla 43b2c6dd85 Fix conditions to fire onLayout event
Summary:
Changelog: [Internal]

# Problem

## Step 1
JS clones a node that has size {100, 100} and changes props that cause the node to increase size to {200, 200}. JS holds pointer to this node.

Now, the size (stored in LayoutableShadowNode.layoutMetrics_) changes after Yoga layout is triggered.

However, the node gets cloned inside State Reconciliation before Yoga layout phase. The JS pointer points to a node with size {100, 100}, not to a node with size {200, 200}.

## Step 2

Again, JS clones node (with old reference, therefore gets old layoutMetrics_ with size {100, 100}) and it changes props that cause the node to decrease its size back to {100, 100}.
We go all the way to Yoga layout and looking for nodes that have been affected by the node. The node, affected by the layout because it went from {200, 200} to {100, 100}, will be evaluated as not affected. This causes onLayout event to not be fired.

# Fix
We can safely remove the frame equality check (please see below). This can be done because we already check for equality before dispatching onLayout. It happens here:

https://www.internalfb.com/intern/diffusion/FBS/browsefile/master/xplat/js/react-native-github/ReactCommon/react/renderer/components/view/ViewEventEmitter.cpp?commit=881853eb0c42625fd0812bd2652bf36fcbd614ee&lines=43

As far as I know, `affectedNodes` isn't used for anything else besides dispatching onLayout.

# Discussion

This problem manifests itself only when a node has two different sizes that it flips between. To better understand this, please watch the video in Test plan labelled "before". Notice how the text has 2 different values that it flips between.

Here is a code that was affected by it https://fburl.com/diffusion/3hwo0iy5
If you inspect it closely, you will notice that it depends on `onLayout` to return correct value to calculate offset from left.

Reviewed By: JoshuaGross

Differential Revision: D22999891

fbshipit-source-id: e2d0f5771c1bf3cd788e5e9da0155c92e33fb84e
2020-08-10 05:11:29 -07:00
David Vacca 886d1bad74 Make react/core module to compile in OSS
Summary:
Make react/core module to compile in OSS

This is necessary to make fabric compile in OSS

changelog: [internal] internal

Reviewed By: fkgozali

Differential Revision: D22908222

fbshipit-source-id: a37b87d02ecf77bb25693ce32cd0f3432be5daa7
2020-08-06 00:09:12 -07:00
David Vacca 08d7b542de Create Android OSS build system for react/utils module
Summary:
This diff creates the Android OSS build system for the module react/utils

As part of this diff I also moved the module to react/utils folder

changelog: [internal] internal

Reviewed By: JoshuaGross

Differential Revision: D22877265

fbshipit-source-id: 717487aacb392d0f08530763a16a638b8021d501
2020-08-05 19:02:08 -07:00
Joshua Gross 774dec1e17 Introduce general API for setting C++ State from the View layer and getting a notification if it fails, with Android impl
Summary:
iOS will need to be implemented separately, but the shared C++ bits are in place.

Explanation: there is currently no way for the View layer to /know/ if an UpdateState call has succeeded or failed. Generally we just assume it succeeds, but if it fails we have no way of knowing or retrying.

This can cause some UI bugs. To mitigate this, I'm introducing a "failure" notification callback mechanism. The JNI bridging for this is a little complicated to avoid passing Runnable across the JNI, but it
should be much simpler on iOS.

In development this seems to make View components much more reliable.

Changelog: [Internal]

Reviewed By: mdvacca

Differential Revision: D22940187

fbshipit-source-id: 917f2932ae22d421f91fe8f4fca3f07dc089f820
2020-08-05 06:35:41 -07:00
David Vacca 1ae76bf0dd Remove inner folders of react/renderer/core
Summary:
This diff removes the inner folder of react/renderer/core, moving all its files into react/renderer/core

This is necessary to simplify the compilation of Fabric in OSS

More details: https://fb.quip.com/amaRA631DX3K

changelog: [internal] Internal

Reviewed By: fkgozali, JoshuaGross

Differential Revision: D22875854

fbshipit-source-id: e2d969c3ec67eab1bbdc9288e5a4285c740fa944
2020-08-01 13:31:03 -07:00
David Vacca 3093010ea5 move fabric to ReactCommon/react/renderer
Summary:
This diff moves fabric C++ code from ReactCommon/fabric to ReactCommon/react/renderer
As part of this diff I also refactored components, codegen and callsites on CatalystApp, FB4A and venice

Script: P137350694

changelog: [internal] internal refactor

Reviewed By: fkgozali

Differential Revision: D22852139

fbshipit-source-id: f85310ba858b6afd81abfd9cbe6d70b28eca7415
2020-07-31 13:34:29 -07:00