Commit Graph

21 Commits

Author SHA1 Message Date
Ahmed El-Helw fc10d0d3bf Fix modals freezing on close with Nodes
Summary:
Modals were doing nothing (and sometimes crashing) when they were
being closed. The reason for this was due to the fact that the parent being
removed was not necessarily the view's parent. Consequently, trying to inform
said parent that its child was removed failed, because said parent wasn't a
view, and therefore had no record in mViewsToTags.

Reviewed By: sriramramani

Differential Revision: D3928850
2016-12-19 13:40:34 -08:00
Ahmed El-Helw 147989cd96 Fix a Nodes crash when double detaching a clipped view
Summary:
This fixes a crash for the case when we try to drop a view that has already been dropped.

**The Problem**

We got reports of a crash (t12912526) that occurs when the resolveViewManager method can't resolve a ViewManager for a View being dropped.

Investigating this, one thing in common between all the stack traces for this is that dropView is called from line 210 of FlatNativeViewHierarchyManager. This part of the code is specifically the part we added to remove strong references to any clipped children (from views that have subview clipping enabled).

So this is a problem specifically with Nodes and clipSubviews, which brings up some questions:

**when can this happen?**

The only situation this can possibly happen is when we drop a child (which is clipped) followed by dropping its parent in the same cycle. Consider a tree where each view only has one child, such as:  A - B - C - D. This crash would happen if D is clipped, and we removed it, followed by removing any of its parents in the same frame.

**if the removes happen in different frames, does this bug occur?**

No - the reason is that before we execute the DropView operations, we run through StateBuilder, which traverses the shadow tree and marks updates, thus removing the view going away (such that the delete in the next frame doesn't try to re-delete it).

So why doesn't this happen when we're dropping in the same frame? The reason is that manageChildren (where this all starts) asks to remove some views. We handle this by removing said Nodes and their children from the shadow tree. Consequently, when StateBuilder iterates over the shadow tree, it can't do the right thing because said nodes no longer exist.

As a more concrete example, consider A - B - C - D again, and consider that both D and B are removed. StateBuilder only sees A, and realizes that it now has 0 children (whereas before it has 1), so it removes B from its children. However, this process isn't recursive, so C never gets cleaned up.

**why doesn't this happen with Nodes without clipping containers?**

The answer to this is that NativeViewHierarchyManager's dropView method checks the existance of each child before deeply dropping that child and its subtree. So in this case, we drop D and all its children, and when we come to drop B, we try to drop C (which exists) and then its children (D, which doesn't exist because we already dropped it, so we ignore it).

**why doesn't this happen with non-Nodes?**

The reason is that non-Nodes handles removes differently - every remove is enqueued in a call to NativeViewHierarchy's manageChildren, which explicitly asks the parent to remove said child. Consequently, we never try to remove a child that is already removed.

**Fix**

The initial fix was to check whether or not the view exists, but this updated patch just does the right thing at drop time - i.e. whenever a view is dropped, we notify the parent of this fact so that it can clear the reference from clipped views.

**One last Note**

There are two reasons for switching `super.dropView` to `dropView` - first, the comment is only partially correct - calling `super.dropView` will avoid looking at clipped children (as an aside, that could cause a leak in the case of nested clipping subviews), but will look at clipped grandchildren, because of the super class's iteration across the set of children.

Reviewed By: astreet

Differential Revision: D3815485
2016-12-19 13:40:34 -08:00
Seth Kirby 4a12efad02 Separate Node bounds and hit bounds within node region where needed.
Summary: Node region bounds are assumed to equal the underlying node bounds.  In the case of hit slop, these need to be abstracted.

Reviewed By: ahmedre

Differential Revision: D3713430
2016-12-19 13:40:32 -08:00
Seth Kirby 192c99a4f6 Gather command and node region information off the UI thread.
Summary: This optimizes node region searches in clipping cases, and does position calculation for drawCommands off of the UI thread.

Reviewed By: ahmedre

Differential Revision: D3665301
2016-12-19 13:40:31 -08:00
Seth Kirby 28654aef65 Remove logical adjustments from FlatViewGroup.
Summary: These were needed until recent changes in DrawView.

Reviewed By: ahmedre

Differential Revision: D3646707
2016-12-19 13:40:30 -08:00
Seth Kirby 1d034cf91d Delay dropping root views until the drop views step of StateBuilder.
Summary: @public Make UIOperation public so that custom implementations can expose instances of it.

Reviewed By: ahmedre

Differential Revision: D3618197
2016-12-19 13:40:30 -08:00
Seth Kirby 95ae936aa6 Fix for ViewManager commands being run before view updates.
Summary: Since Nodes' manageChildren doesn't enqueue the child updates immediately, commands were being directed to non-updated views.  Previously we applied updates for the shadow node before dispatching the command, but we can instead wait to fire commands until after we update the view hierarchy.

Reviewed By: ahmedre

Differential Revision: D3568541
2016-12-19 13:40:28 -08:00
Ahmed El-Helw 9a28701bd8 Fix measureInWindow when using Nodes
Summary:
The results from measureInWindow were always wrong the first time it
was called. This was due to the fact that the view in question was not
actually a view yet, so the results were incorrect. This patch uses the
existing measure functionality (which can measure virtual nodes) to measure
the view, while modifying it to properly get the results relative to the
window instead of relative to the root view.

Reviewed By: sriramramani

Differential Revision: D3501544
2016-12-19 13:40:28 -08:00
Ahmed El-Helw 4ecfa0c800 Fix touch inspector when using Nodes
Summary:
Fix touch inspector when using Nodes by implementing custom logic.
This logic now takes into account that non-View nodes need to be clickable.

Reviewed By: astreet

Differential Revision: D3433927
2016-12-19 13:40:26 -08:00
Ahmed El-Helw e1ece03593 Improve removeClippedSubviews for overflowing views
Summary:
Historically, removeClippedSubviews for Nodes would not clip views
that overflowed their parent. This patch changes that, so that Nodes can
properly clip views when they are off screen (even if they have descendants
that overflow the bounds of their parent).

This is done by calculating a set of offsets from the actual width and
height of the view, and using those in the clipping calculations.

Reviewed By: sriramramani

Differential Revision: D3409859
2016-12-19 13:40:26 -08:00
Ahmed El-Helw 9d67989001 Don't clip overflowing Nodes
Summary:
As of D3235050, Nodes supports the optimization of removing clipped
subviews from the hierarchy. However, because Nodes supports overflow:visible,
this could cause issues when DrawCommands overflow the bounds of their parent
container. This patch fixes this by not clipping any overflowing Nodes.

Reviewed By: astreet

Differential Revision: D3235072
2016-12-19 13:40:26 -08:00
Ahmed El-Helw 5f162ca119 Implement RemoveClippedSubviews for Nodes
Summary:
RN has an optimization in which a ScrollView (or similar ViewGroups)
can ask to remove clipped subviews from the View hierarchy. This patch
implements this optimization for Nodes, but instead of adding and removing the
Views, it attaches and detaches Views instead.

Note that this patch does not handle overflow: visible. This is addressed in a
stacked patch on top of this patch (to simplify the review process).

Reviewed By: astreet

Differential Revision: D3235050
2016-12-19 13:40:25 -08:00
Denis Koroskin e7d8d2c3ab Don't use NodeRegion to update View bounds
Summary: NodeRegions are touch regions within hosting View, and while in most cases they are the same as View boundaries, there is one case where it's not true: TextNodeRegion. When mounted to a View, TextNodeRegion will have a bounds of (0,0,width,height) which is clearly different from (left,top,right,bottom). Initially I assumed they would always be the same so we could use information stored in NodeRegion (should probably be called TouchRegion) to update node's View boundaries, but it breaks RCTTextView when it mount to a View (because it would either contain incorrect bounds, or View will be laid out incorrectly). Right now touch is not working on RCTView that mounts to a View. To fix the issue, separate the 2 concepts.

Reviewed By: ahmedre

Differential Revision: D2816268
2016-12-19 13:40:19 -08:00
Denis Koroskin 05544f6bca Make FlatUIImplementation.measure() work with virtual views (shadow nodes that don't map to a View)
Summary: UIImplementation.measure() can only measure shadow nodes that map to native Views. As a result of this, every time we tried to measure a shadow node that doesn't map to a View, we trigger callback with no data (to indicate an error). To fix this issue, walk up until we find a node that maps to a View, then measure that View and adjust for the bounds of a virtual child.

Reviewed By: ahmedre

Differential Revision: D2800960
2016-12-19 13:40:19 -08:00
Denis Koroskin 529390b87c Fix children of AndroidView not being re-laid out after they call requestLayout
Summary:
In ReactNative, we are fully controlling layout of all the Views, not allowing Android to layout anything for us. This is done by making onLayout() of the top-level View in the hierarchy to be empty. This works fine because we explicitly call measure/layout for all the Views when they need to be re-measured or re-laid out. There is however one case where this doesn't happen automatically: some Android Views such as DrawerLayout or ActionBar have children that don't have shadow nodes associated with them (such as a title in ActionBar). This results in situations where children of AndroidView will call requestLayout but they will never get relaid out, because shadow hierarchy doesn't know about them. Example: ActionBar has a seTitle method that will internally call TextView.setTitle() and that TextView will call requestLayout because its size may have changed. However, that TextView will never be remeasured or relaid out.

This diff is fixing it by keeping track of everyone who called requestLayout. Then, at the end of the update loop we go over the list a manually remeasure and relayout those Views.

Not a huge fan of how this is implemented (there MUST be a better way) but this works with least efforts. I'll see if I can improve it later.

Reviewed By: ahmedre

Differential Revision: D2757485
2016-12-19 13:40:16 -08:00
Denis Koroskin ad65b2a9e1 Remove referenced to dropped views
Summary:
There is currently a bug where we never release any Views that no longer display, still storing hard references in NativeViewHierarchyManager. This diff is fixing this bug, and here is how:

a) there is already logic in place to drop FlatShadowNodes (UIImplementation.removeShadowNode).
b) there is already logic in place to drop Views (NativeViewHierarchyManager.dropView(int reactTag) - used to private but needs to be protected so I can call it)
c) (the missing part) when we are about to drop a FlatShadowNode, check if it mount to a View (i.e. there is a View associated with that node), put it into a ArrayList. When we finished updates to a nodes hierarchy (which happens in non-UI thread), collect ids from those nodes and enqueue a UIOperation that will drop all the Views. We can either forward nodes as FlatShadowNode[], or only ids as int[]. Both should be fine, but as a rule of thumb we don't touch shadow node hierarchy from UI thread (as we don't touch Views from non-UI thread) so passing int[] is what this code is doing.

Reviewed By: ahmedre

Differential Revision: D2757310
2016-12-19 13:40:16 -08:00
Denis Koroskin 312f04d2b7 Apply FlatShadowNode padding to View
Summary: Any padding that a FlatShadowNode is assigned by React runtime should be translated to a backing Android View so it looks correct and lays out children accordingly.

Reviewed By: sriramramani

Differential Revision: D2756562
2016-12-19 13:40:16 -08:00
Denis Koroskin dad378e394 Add NodeRegion to allow any FlatShadowNode to respond to touch events
Summary: @public When Android dispatches `MotionEvent` to `ReactRootView`, it needs to find a correspoding react node that should receive it. To be able to do it, we need to store boundaries of every `FlatShadowNode` in `FlatViewGroup`. Then we can iterate over node boundaries and find one that contains the touch event coordinates.

Reviewed By: sriramramani

Differential Revision: D2694197
2016-12-19 13:40:16 -08:00
Denis Koroskin 8de2acd3a9 Allow FlatShadowNode mouting to its own view
Summary: @public This diff adds a `FlatShadowNode.forceMountToView()` method that will render its contents in it own `View`.

Reviewed By: sriramramani

Differential Revision: D2564502
2016-12-19 13:40:16 -08:00
Denis Koroskin 760422525e Add support for RCTImageView in FlatShadowHierarchyManager
Summary: @public This patch adds basic support for RCTImageView (only 'src', 'tintColor' and 'resizeMode' properties are supported for now), and a concept of AttachDetachListener that is required to support it to FlatUIImplementations.

Reviewed By: sriramramani

Differential Revision: D2564389
2016-12-19 13:40:15 -08:00
Denis Koroskin 5c2f536e9a Add support for RCTText under FlatUIImplementation
Summary: @public Initial version of FlatUIImplementation lacks any primitives support (such as RCTText, RCTImageView or RCTView). This diff add the first part, RCTText (alongside with RCTVirtualText and RCTRawText).

Reviewed By: sriramramani

Differential Revision: D2693348
2016-12-19 13:40:15 -08:00