Commit Graph

8960 Commits

Author SHA1 Message Date
Ahmed El-Helw 45472fe400 Fix detaching dropped views in Nodes
Summary:
Groups had a crash when running with React with Nodes when returning
from a search screen. This was due to the fact that the node representing a
ShimmerFrameLayout was being dropped, and then later we were trying to detach
it. Since the view was already dropped, we shouldn't try to detach it since
it's already dropped and removed from the view hierarchy.

Reviewed By: sriramramani

Differential Revision: D3004541
2016-12-19 13:40:23 -08:00
Denis Koroskin 0b560d3d3d Don't try to remove Views that about to be removed with the root View
Summary:
We keep a list of FlatShadowNodes that mount to Views that we want to delete, and only flush it at the end of an update cycle. This results in a situation where a root view is being removed before children are removed, which results in a crash in NativeViewHierarchyManager because a View that we are trying to remove no longer exists. There are a few approaches to fix the issue:
a) make a check if a View exists before removing it. While works, it removes a bug protection when we erroneously trying to remove a View that no longer exists (such as this). I'd prefer to keep the check in place
b) flush the views-to-drop queue. This works, but does some extra work in UI thread (namely, removing Views that would be removed anyway)
c) trim the views-to-drop queue to remove any Views that will be removed anyway. This does a tiny bit of extra work in BG thread, but less work in UI thread.

This diff implements option c).

Reviewed By: ahmedre

Differential Revision: D2990105
2016-12-19 13:40:23 -08:00
Ahmed El-Helw 75117fc91a Minor code improvements for RCTTextInput
Summary: @public Expose hasUnseenUpdates in ReactShadowNode. Various text input cleanup and fixes.

Differential Revision: D2975870
2016-12-19 13:40:23 -08:00
Ahmed El-Helw df382e986c Implement alignment for nodes Text
Summary: Alignment wasn't implemented for Text, this patch supports it.

Differential Revision: D2980358
2016-12-19 13:40:23 -08:00
Denis Koroskin 848bae2e95 Fix FlatUIImplementation.manageChildren() failing when moveFrom is not sorted
Summary:
Code in FlatUIImplementation.manageChildren() incorrectly assumed that moveFrom is sorted and moveTo is not, which is actually reverse: moveFrom is not sorted, and moveTo is. This means that we need to sort moveFrom before we can traverse it, and that we no longer need to sort moveTo (we did it by moving nodes to mNodesToMove first and then sorting it).

The sorting algorithm used is borrowed from Android implementation of insertion sort used in DualPivotQuicksort.doSort() when number of elements < INSERTION_SORT_THRESHOLD(32) which is 99.999% the case in UIImplementation.manageChildren() (most of the time this array is either empty or only contains 1 element).

Another (very rare) bug this is fixing is that the code only worked for FlatShadowNodes, but not all shadow nodes are FlatShadowNodes (there are rare exceptions, such as ARTShape, ARTGroup etc). New code works with all types of shadow nodes.

Reviewed By: ahmedre

Differential Revision: D2975787
2016-12-19 13:40:23 -08:00
Denis Koroskin 42fb9a3d91 Only collect state from nodes that have been updated
Summary: We are currently traversing entire tree every time there is any update to any of the nodes, which is hugely inefficient. Instead, we can early out for nodes that are known to contain no updates. This saves a lof of CPU. This optimization can be turned off, and an Exception will be thrown if there was an unexpected update.

Reviewed By: ahmedre

Differential Revision: D2975706
2016-12-19 13:40:23 -08:00
Ahmed El-Helw 7055c52288 Fix screenshot tests for React with nodes
Summary:
Fix screenshot tests for React with nodes. It was broken due to
calling clipRect with bounds of [-∞, ∞], which, due to a bug in Canvas that
appeared in screenshot tests, caused the view not to draw. Since this is a
no-op anyway, this patch just doesn't call clipRect when we have infinite
bounds.

Differential Revision: D2975494
2016-12-19 13:40:23 -08:00
Denis Koroskin b9e3ef2d5f Add @Nullable annotation to FlatShadowNode.obtainLayoutEvent()
Summary: Lint tool raised a warning. This diff is fixing it.

Reviewed By: sriramramani

Differential Revision: D2977649
2016-12-19 13:40:23 -08:00
Denis Koroskin ca7a3519cf Store \"dirty\" and \"dirty descendant\" flags in every node instead of only marking root node as invalid
Summary: Right now invalidate always tell the root node that the tree is dirty, and next update will traverse the entire tree in search of changes. While this works correctly, it's not the most efficient implementation. It is more efficient to store dirty flag in every node, and skip entire subtrees if this node and all descendants are already up to date. This diff is a first step towards that optimization.

Reviewed By: ahmedre

Differential Revision: D2955197
2016-12-19 13:40:22 -08:00
Ahmed El-Helw 4c92a0b962 Support setText in RCTTextInput
Summary:
Examples that use defaultValue as part of their declaration (such as
those examples under UIExplorerApp's TextInput) were being ignored. This patch
supports having text set directly on RCTTextInput and handles it properly.
Note that this patch depends on D2962643 and D2964847, without which the
TextInput example will look wrong.

Differential Revision: D2968002
2016-12-19 13:40:22 -08:00
Denis Koroskin a9c88bce14 Fix 2 bugs in FlatUIImplementation.removeChild()
Summary:
There are 2 issues in removeChild() implementation.

a) There is a chance that a node that we are removing will be mounting to a View, but the create view request has not be created  so there is no backing View for it yet. In that case, FlatNativeViewHierarchyManager.dropView() will throw an Exception failing to find the View. The fix is to only dropView() if one was (requested to be) created.
b) If the shadow node that we are removing doesn't mount to a View, but one or more of its children do, those Views will leak because noone is removing them. The fix is to recursively call removeChild() until we find a node that mounts to a View.

Reviewed By: ahmedre

Differential Revision: D2974938
2016-12-19 13:40:22 -08:00
Denis Koroskin 5305f3b68e Fix OnLayoutEvent dispatching wrong x/y coordinates
Summary:
OnLayoutEvent was incorrectly dispatching x/y coordinates relative to native View instead of relative to parent. This was causing issues in many cases, such as when Node was mounting to a View, in which case x/y would always be 0. This diff is fixing it.

This diff also caches last OnLayoutEvent to avoid dispatching the event on every layout even when layout didn't chance.

Reviewed By: ahmedre

Differential Revision: D2955087
2016-12-19 13:40:22 -08:00
Denis Koroskin c36d4593fd Revert \"[react-native][nodes] Split StateBuilder.ensureBackingViewIsCreated into 2 different methods\"
Summary: Reverts D2916697 that landed twice.

Differential Revision: D2974199
2016-12-19 13:40:22 -08:00
Ahmed El-Helw 827989f572 Fix TextInput text color not applying
Summary:
Setting the color for a TextInput with nodes was broken. The text color was
not being applied due to an optimization that prevented setting spans if
begin and end were the same (which is the case for an empty TextInput).
This patch depends on D2962643.

Differential Revision: D2962394
2016-12-19 13:40:22 -08:00
Ahmed El-Helw b4100ef246 Fix spannable flags in RCTVirtualText
Summary:
The spannable flags for RCTVirtualText were always being set to
INCLUSIVE_EXCLUSIVE - this is different than the behavior that is found in
ReactTextShadowNode, which sets EXCLUSIVE_INCLUSIVE as the default flag
unless the text is at the beginning.

This is needed to fix various problems with TextInput, including the handling
of empty spans (see also D2962394 which depends on this patch), and making the
behavior consistent when styled children of a TextInput are changed.

Differential Revision: D2962643
2016-12-19 13:40:22 -08:00
Ahmed El-Helw 055b31a165 Implement measure for nodes TextInput
Summary:
Implement measure for RCTTextInput. This is (almost) the same as
the one implemented for ReactTextInputShadowNode.

Differential Revision: D2964847
2016-12-19 13:40:22 -08:00
Denis Koroskin 64e050793e Split StateBuilder.ensureBackingViewIsCreated into 2 different methods
Summary:
There are 2 reasons why someone would call StateBuilder.ensureBackingViewIsCreated():
1) to make sure a View is created, because we are going to use it NOW
2) make sure react styles are applied to View, which doesn't really need the View to be created immediately

This diff is splitting the method into 2, without changing behavior. Difference between the methods' signatures is coming from the fact that 1) never takes styles and 2) possibly takes styles.

This is a pure refactoring diff and should have no change in functionality or behavior.

Reviewed By: ahmedre

Differential Revision: D2916697
2016-12-19 13:40:22 -08:00
Denis Koroskin ada5234b0e Lazily create/update views
Summary:
There is a rare case in React Native when a hierarchy is created and then *immediately* discarded all in one transaction. This is causing a View leak, because a View is created and then never attached to a hierarchy because it shadow node got detached. Since we never attached the View to the hierarchy, we cannot do a detach either and the View is kept in NativeViewHierarchyManager forever, causing a View leak. To fix the issue, don't create a backing View whenever a shadow node mounts to a View. Instead, put the create request into a queue and ONLY execute it if a shadow node is still attached to a hierarchy. This is fixing the View leak because will not create a View unless it's going to be attached somewhere.

The same logic applies to View style update (we don't want to update a View that is going to be detached from a hierarchy).

Reviewed By: ahmedre

Differential Revision: D2916826
2016-12-19 13:40:22 -08:00
Denis Koroskin bb04967986 Split StateBuilder.ensureBackingViewIsCreated into 2 different methods
Summary:
There are 2 reasons why someone would call StateBuilder.ensureBackingViewIsCreated():
1) to make sure a View is created, because we are going to use it NOW
2) make sure react styles are applied to View, which doesn't really need the View to be created immediately

This diff is splitting the method into 2, without changing behavior. Difference between the methods' signatures is coming from the fact that 1) never takes styles and 2) possibly takes styles.

This is a pure refactoring diff and should have no change in functionality or behavior.

Reviewed By: ahmedre

Differential Revision: D2916697
2016-12-19 13:40:22 -08:00
Denis Koroskin 44b6200392 Round ShadowNode layout coordinates to a pixel boundary
Summary:
When layout happens, left/top/right/bottom coordinates (and thus clip-*, too) are sometimes not at a pixel boundary for 2 reasons:
a) width/height in Flexbox are floats, and can contain any value, not just a whole pixel. E.g. style={{width: 3.1415926}} is perfectly valid
b) floating point arithmetics sometimes leads to values barely outside of pixel boundaries (width 18.0f can become 18.000001f when a sibling/child size changes).

a) is \"breaking\" screenshot tests, which slightly but differ from reference implementation
b) causes extra View updates/redraws for no reason

This patch is rounding DrawCommand bounds to a whole pixel to avoid these 2 issues.

Reviewed By: ahmedre

Differential Revision: D2934401
2016-12-19 13:40:22 -08:00
Andrei Coman addd233d31 Use nanoTime instead of currentTimeMillis for events
Summary:
Public
We wanted to do this before, but couldn't because touch events had timestamps
set by the system (and matched System.currentTimeMillis), but now we set those
timestamps! The idea behind this change is that System.currentTimeMillis is
unreliable, but nanoTime isn't, and it also guarantees that we will never have two events with the same
timestamp.
We're still seeing crashes with touch events not ending correctly in JS, this
might be the cause of that.

Reviewed By: foghina

Differential Revision: D2953917
2016-12-19 13:40:21 -08:00
Denis Koroskin 3e30b70e29 Don't pass tag alongside node in StateBuilder methods
Summary:
Many of StateBuilder methods take a lot of arguments, which makes it hard to read. This patch is doing a bit of cleanup by removing tag from the method signatures, because tag can be easily obtained from the node itself.

This is a pure refactoring diff and should have no functional changes.

Reviewed By: ahmedre

Differential Revision: D2915815
2016-12-19 13:40:21 -08:00
Denis Koroskin 3b63d7c3bc Extract rect clipping logic into AbstractClippingDrawCommand
Summary: Both DrawView and AbstractDrawCommand have clipping logic, this diff is moving out logic into a common base class. This also reverts the screenshot tests fix, which was causing issues with overflow: visible.

Reviewed By: ahmedre

Differential Revision: D2933780
2016-12-19 13:40:21 -08:00
Ahmed El-Helw f0535152ab Make AndroidView an interface
Summary:
The current AndroidView stipulates that the backing shadow node can't
be a FlatShadowNode. In some cases, however, we want to apply some of the same
logic (ex not adding NodeRegions, etc) to other ViewManagers that have a
FlatShadowNode backing (and that don't necessarily create a FlatViewGroup).
This commit renames AndroidView to NativeViewWrapper, and re-introduces
AndroidView as an interface, so that logic for padding, NodeRegions, etc can
be shared.

Differential Revision: D2942387
2016-12-19 13:40:21 -08:00
Denis Koroskin b461c70b76 Fix StateBuilder incorrectly casting a child to FlatShadowNode
Summary: Not every CSSNode in a hierarchy is a FlatShadowNode, some virtual nodes can be ReactShadowNodes for compatibility with ART nodes. This diff fixes StateBuilder unconditionally casting a node to FlatShadowNode, which is causing a crash in Groups.

Reviewed By: nickholub

Differential Revision: D2941031
2016-12-19 13:40:21 -08:00
Denis Koroskin d1ccb6d23d Finalize many of FlatShadowNode methods
Summary: These methods (mostly getters/setters) are not meant to be overriden, so let's make them final. Hopefully, they will inline better, too.

Reviewed By: ahmedre

Differential Revision: D2933869
2016-12-19 13:40:21 -08:00
Ahmed El-Helw 99d95d8168 Fix TextInput in React Nodes
Summary:
@public Relax the constraint on ReactTextInputManager.
The TextInput Advanced screen looked different with and without
nodes, namely child Text items were not being rendered on the Nodes version.
This patch fixes that.

Differential Revision: D2930800
2016-12-19 13:40:21 -08:00
Denis Koroskin 253cb8c2b5 Add @Override to FlatUIImplementation.handleCreateView
Summary: FlatUIImplementation.handleCreateView was missing an Override annotation. This diff fixes it.

Reviewed By: sriramramani

Differential Revision: D2919596
2016-12-19 13:40:21 -08:00
Denis Koroskin 8702a75b96 Don't wrap unknown virtual nodes with AndroidView
Summary: Currently, we wrap all unknown shadow nodes with AndroidView. This works great, except when the shadow node is virtual, i.e. it *doesn't* mount to a View. In this case, we just need to keep it in the hierarchy as is. Fixes ARTSurfaceView not working correctly in groups.

Reviewed By: ahmedre

Differential Revision: D2933325
2016-12-19 13:40:21 -08:00
Denis Koroskin 4bff818706 Workaround for a bug in software Canvas that incorrectly computed clip boundaries (fixes screenshot tests)
Summary: Software Canvas uses ints to represents boundaries (because it is backed by Bitmap that has scalar size), whereas Hardware Canvas uses floats to represent boundaries. This results in a bug in Software Canvas where clipping with floats close to or outside of int range results in int overflows and incorrect clipping. To fix the issue, compute the clip boundaries manually instead of using Canvas.clipRect() method (that contains the bug).

Reviewed By: sriramramani

Differential Revision: D2919509
2016-12-19 13:40:21 -08:00
Denis Koroskin 44c814c94d Fix border not drawing when there is a background color set
Summary: There is a bug in border drawing code that will not draw the border if the element has a background color. This diff fixes it.

Reviewed By: sriramramani

Differential Revision: D2919549
2016-12-19 13:40:21 -08:00
Denis Koroskin 0b6436b637 Add support for data: Uri scheme to RCTImageView (e.g. base64-encoded images)
Summary: ImageRequestHelper was not handling data: scheme correctly, which resulted in images failing to load. This diff is fixing it by considering \"data:\" as a Uri resource, and piping it appropriately.

Reviewed By: sriramramani

Differential Revision: D2919403
2016-12-19 13:40:20 -08:00
Denis Koroskin 88ebce0512 Fix RCTImageView always clipping to bounds even if overflow is visible
Summary: Previously, RCTImageView/DrawCommand would always clip for specific scale types (such as CENTER_CROP), but this is incorrect if we want to allow overflow: visible on RCTImageView (which iOS allows). This patch tweaks the clipping condition from paddingLeft/paddingTop < 0 (i.e. image wants to draw outside of its bounds) to actual image rect being outside of clip rect. Previously, that would mean exact same thing, but now that clip rect is aware of overflow: visible, it matters, allowing RCTImage to not clip when we want it to draw outside of the boundaries.

Reviewed By: ahmedre

Differential Revision: D2873350
2016-12-19 13:40:20 -08:00
Denis Koroskin 674e74a963 Only clip node against its own boundaries IFF clipToBounds() is set to true (i.e. overflow is visible)
Summary:
Previously, every node would be clipped by its own boundaries. This made sense, because
a) RCTView cannot draw outside of its bounds, so clipping is harmless
b) all other node types were not allowed to control overflow behavior, and for them overflow was implicitly set to hidden, which means it should clip.

This diff changes the logic so that overflow can be set on any node (image, text, view etc).

The change has an important implication that make the diff a little trickier that it could be: AbstractDrawCommand clipping logic needs to be relaxed. Previously, clip bounds were *always* intersected with node bounds, which means that clip rect was always within node rect. This is no longer true, and thus shouldClip() logic needs to be modified.

Because of the above, RCTText no longer needs to artificially clip bounds against layout width/height.

Note: RCTImage is still not working with overflow: visible correctly (it still always clips). This is fixed in a follow up diff.

Reviewed By: ahmedre

Differential Revision: D2867849
2016-12-19 13:40:20 -08:00
Denis Koroskin 05e8ff1fe0 Remove bogus assert
Summary:
There is an assert in FlatViewGroup.reactTagForTouch() that says that TouchTargetHelper should not allow returning getId() when pointer events are BOX_NONE. This is not entirely accurate.

This acturally method is invoked in 2 different contexts. Main context is to find a touch target, and in that context the method indeed should never return getId() if pointer events are BOX_NONE. There is however a TouchTargetHelper which actually expects that reactTagForTouch() *may* return getId(), in which case it will perform logic to not all this method be invoked again from main context.

In other words, this assert needs to be removed because it is entirely possible to return getId() when pointer events are BOX_NONE. Ideally, these would be 2 different methods, but ReactCompoundView interface only defines a single reactTagForTouch() method.

Reviewed By: ahmedre

Differential Revision: D2873931
2016-12-19 13:40:20 -08:00
Denis Koroskin d9ed1a84c5 Apply padding to RCTText
Summary: When padding is applied to RCTText, the text it renders should be offset by that padding. This is what iOS is doing.

Reviewed By: sriramramani

Differential Revision: D2872039
2016-12-19 13:40:20 -08:00
Ahmed El-Helw d854a17d2a Support fade for remote images in React with nodes.
Summary:
Support fade for DrawImageWithPipeline so that images are faded in
when they are remotely fetched.

Differential Revision: D2804997
2016-12-19 13:40:20 -08:00
Denis Koroskin 74c72111f1 Rename mIsOverflowVisible to a more descriptive mClipToBounds
Summary: A simple refactoring diff that should make code a little easier to read. No functional changes.

Reviewed By: ahmedre

Differential Revision: D2867718
2016-12-19 13:40:20 -08:00
Denis Koroskin a52c89b01d Extract UIImplementationProvider for Nodes into a helper class
Summary: Exact same class is needed for Groups, and probably for other apps that want to work with Nodes, too, so let's extract it into a helper class to simplify coding.

Reviewed By: sriramramani

Differential Revision: D2873943
2016-12-19 13:40:20 -08:00
Denis Koroskin 461871364b Manually assign id of the top-level View to match top-level react tag
Summary:
Nodes create a FlatViewGroup for a root node element, and NativeViewHierarchyManager assigns it an id that matches root node it. Now this top-level FlatViewGroup is added to a ReactRootView. In non-nodes, this ReactRootView has an id that matches root View id, and when this ReactRootView gets detached from Window, it sends an event to NativeViewHierarchyManager that says that all the children of this View must be removed recursively. This works great in non-Nodes, but fails in Nodes because ReactRootView has no id (-1) and NativeViewHierarchyManager fails to find a corresponding ReactShadowNode, throwing an Exception. To fix the issue and make it work again we need to assign this View id of the top level shadow node. This creates a minor issue, where 2 Views (ReactRootView and its only child) share the same id, but that is not a problem because we don't enforce uniqueness of the ids, and don't rely on getViewById().

This was originally implemented, but then I removed it because I thought it wasn't truly needed. Turns out, it is needed.

Reviewed By: sriramramani

Differential Revision: D2873995
2016-12-19 13:40:20 -08:00
Martin Konicek 0b79d44dcf Less Catalyst, more React
Summary:
Catalyst is the old project name. Rename a few files.

@public

Reviewed By: bestander

Differential Revision: D2859553
2016-12-19 13:40:20 -08:00
Denis Koroskin 59fe71caff Add support for ImageLoadEvents to RCTImageView
Summary: This diff implements ImageLoadEvents (ON_LOAD, ON_LOAD_END and ON_LOAD_START) in RCTImageView. ON_ERROR and ON_PROGRESS are easy to implement, too, but these 2 are supposed to carry extra information (error message and progress) but ImageLoadEvent doesn't support a payload yet (I'll add them in a separate patch).

Reviewed By: ahmedre

Differential Revision: D2824772
2016-12-19 13:40:20 -08:00
Denis Koroskin 76abec8894 Add support for shadows to RCTVirtualText
Summary: React provides properties to support shadows for Text, this diff implements it for Nodes.

Reviewed By: ahmedre

Differential Revision: D2817212
2016-12-19 13:40:20 -08:00
Denis Koroskin f98a288c2a Don't create an instance of FontStylingSpan until any of the properties changed
Summary: Minor optimization/cleanup: instead of creating an instance of FontStylingSpan for every RCTVirtualText, start with a global immutable instance of use copy-on-write when any of the properties change.

Reviewed By: ahmedre

Differential Revision: D2817156
2016-12-19 13:40:19 -08:00
Denis Koroskin c43d8409c0 Fix RTCText incorrectly clipping its background
Summary: Wrong order or top/right -> right/top means that clipping can be incorrect. I didn't notice it because visual result in many cases would still be the same (especially with overflow: visible being default and clipping being mostly disabled). Also only background was clipped incorrectly, and most texts don't have a background.

Reviewed By: ahmedre

Differential Revision: D2816432
2016-12-19 13:40:19 -08:00
Denis Koroskin 03637dc70d Don't add empty NodeRegion, because it will never receive touch events anyway
Summary: Small optimization that prevents empty NodeRegions from being collected. Those will never receive touch events anyway, so why bother allocating memory and iterating over them?

Reviewed By: ahmedre

Differential Revision: D2816355
2016-12-19 13:40:19 -08:00
Denis Koroskin 584cbd3b99 Update/Add NodeRegion after collectState()
Summary: RCTText may modify its DrawCommand on collectState(), which updateNodeRegion() relies on. This means that order of the two is important: call collectState() first, followed by updateNodeRegion(). This fixes the bug where am RCTText may sometimes not respond to clicks (because its NodeRegion would be empty).

Reviewed By: ahmedre

Differential Revision: D2816295
2016-12-19 13:40:19 -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 2fb7ebfb7b Reset NodeRegion when a node gets mounted to a View
Summary: Small optimization. Once we mount a Node to a View, its NodeRegion is not used anymore with RCTText being an exception, but it will correct itself automatically upon updateNodeRegion call. This patch allows the dead object to get garbage collected.

Reviewed By: ahmedre

Differential Revision: D2816331
2016-12-19 13:40:19 -08:00
Denis Koroskin 7075744b94 Implement DrawImage using Drawee
Summary: Alternative implementation of DrawImage using DraweeHierarchy instead of ImagePipeline directly. Yields same results, but potentially more stable. We'll run tests to measure performance of both.

Reviewed By: ahmedre

Differential Revision: D2746197
2016-12-19 13:40:19 -08:00