Merge commit '54016faa7dfdde321023e729636a45b5bb682856' into amgleitman/0.64-merge-head

This commit is contained in:
Adam Gleitman 2021-09-22 13:05:18 -07:00
Родитель 3e0ced8068 54016faa7d
Коммит 100b98f8ab
36 изменённых файлов: 440 добавлений и 311 удалений

Просмотреть файл

@ -80,4 +80,4 @@ untyped-import
untyped-type-import untyped-type-import
[version] [version]
^0.133.0 ^0.134.0

Просмотреть файл

@ -83,4 +83,4 @@ untyped-import
untyped-type-import untyped-type-import
[version] [version]
^0.133.0 ^0.134.0

Просмотреть файл

@ -81,4 +81,4 @@ untyped-import
untyped-type-import untyped-type-import
[version] [version]
^0.133.0 ^0.134.0

Просмотреть файл

@ -5,6 +5,10 @@
LOCAL_PATH := $(call my-dir) LOCAL_PATH := $(call my-dir)
#########################
### callinvokerholder ###
#########################
include $(CLEAR_VARS) include $(CLEAR_VARS)
# Header search path for all source files in this module. # Header search path for all source files in this module.
@ -15,10 +19,10 @@ LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
LOCAL_CFLAGS += -fexceptions -frtti -std=c++14 -Wall LOCAL_CFLAGS += -fexceptions -frtti -std=c++14 -Wall
LOCAL_STATIC_LIBRARIES = libcallinvoker libreactperfloggerjni
LOCAL_SHARED_LIBRARIES = libfb libfbjni LOCAL_SHARED_LIBRARIES = libfb libfbjni
LOCAL_STATIC_LIBRARIES = libcallinvoker libreactperfloggerjni
# Name of this module. # Name of this module.
LOCAL_MODULE := callinvokerholder LOCAL_MODULE := callinvokerholder
@ -27,3 +31,30 @@ LOCAL_SRC_FILES := $(LOCAL_PATH)/ReactCommon/CallInvokerHolder.cpp
# Build the files in this directory as a shared library # Build the files in this directory as a shared library
include $(BUILD_STATIC_LIBRARY) include $(BUILD_STATIC_LIBRARY)
##################################
### react_nativemodule_manager ###
##################################
include $(CLEAR_VARS)
# Name of this module.
LOCAL_MODULE := react_nativemodule_manager
# Header search path for all source files in this module.
LOCAL_C_INCLUDES := $(LOCAL_PATH)/ReactCommon
# Header search path for modules that depend on this module
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
LOCAL_CFLAGS += -fexceptions -frtti -std=c++14 -Wall
LOCAL_SHARED_LIBRARIES = libfb libfbjni libreact_nativemodule_core
LOCAL_STATIC_LIBRARIES = libcallinvokerholder libreactperfloggerjni
# Compile all local c++ files
LOCAL_SRC_FILES := $(LOCAL_PATH)/ReactCommon/TurboModuleManager.cpp $(LOCAL_PATH)/ReactCommon/OnLoad.cpp
# Build the files in this directory as a shared library
include $(BUILD_SHARED_LIBRARY)

Просмотреть файл

@ -80,7 +80,7 @@ LOCAL_LDLIBS += -landroid
LOCAL_SHARED_LIBRARIES := libreactnativeutilsjni libfolly_json libfb libfbjni libglog_init libyoga LOCAL_SHARED_LIBRARIES := libreactnativeutilsjni libfolly_json libfb libfbjni libglog_init libyoga
# The static libraries (.a files) that this module depends on. # The static libraries (.a files) that this module depends on.
LOCAL_STATIC_LIBRARIES := libreactnative libcallinvokerholder libruntimeexecutor LOCAL_STATIC_LIBRARIES := libreactnative libruntimeexecutor libcallinvokerholder
# Name of this module. # Name of this module.
# #
@ -128,8 +128,11 @@ $(call import-module,callinvoker)
$(call import-module,reactperflogger) $(call import-module,reactperflogger)
$(call import-module,hermes) $(call import-module,hermes)
$(call import-module,runtimeexecutor) $(call import-module,runtimeexecutor)
$(call import-module,react/nativemodule/core)
include $(REACT_SRC_DIR)/reactperflogger/jni/Android.mk include $(REACT_SRC_DIR)/reactperflogger/jni/Android.mk
# TODO (T48588859): Restructure this target to align with dir structure: "react/nativemodule/..."
# Note: Update this only when ready to minimize breaking changes.
include $(REACT_SRC_DIR)/turbomodule/core/jni/Android.mk include $(REACT_SRC_DIR)/turbomodule/core/jni/Android.mk
ifeq ($(BUILD_FABRIC),true) ifeq ($(BUILD_FABRIC),true)

Просмотреть файл

@ -49,13 +49,13 @@ Pod::Spec.new do |s|
ss.dependency "glog" ss.dependency "glog"
ss.subspec "core" do |sss| ss.subspec "core" do |sss|
sss.source_files = "react/nativemodule/core/*.{cpp,h}", sss.source_files = "react/nativemodule/core/ReactCommon/**/*.{cpp,h}",
"react/nativemodule/core/platform/ios/*.{mm,cpp,h}" "react/nativemodule/core/platform/ios/**/*.{mm,cpp,h}"
end end
ss.subspec "samples" do |sss| ss.subspec "samples" do |sss|
sss.source_files = "react/nativemodule/samples/*.{cpp,h}", sss.source_files = "react/nativemodule/samples/*.{cpp,h}",
"react/nativemodule/samples/platform/ios/*.{mm,cpp,h}" "react/nativemodule/samples/platform/ios/**/*.{mm,cpp,h}"
sss.dependency "ReactCommon/turbomodule/core", version sss.dependency "ReactCommon/turbomodule/core", version
end end
end end

Просмотреть файл

@ -0,0 +1,31 @@
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := react_nativemodule_core
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../ $(LOCAL_PATH)/ReactCommon $(LOCAL_PATH)/platform/android/ReactCommon
LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/ReactCommon/*.cpp) $(wildcard $(LOCAL_PATH)/platform/android/ReactCommon/*.cpp)
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) $(LOCAL_PATH)/platform/android/
LOCAL_SHARED_LIBRARIES := libfbjni libfolly_json libreactnativejni
LOCAL_STATIC_LIBRARIES := libjsi libreactperflogger
LOCAL_CFLAGS := \
-DLOG_TAG=\"ReactNative\"
LOCAL_CFLAGS += -fexceptions -frtti -std=c++14 -Wall
include $(BUILD_SHARED_LIBRARY)
$(call import-module,folly)
$(call import-module,jsi)
$(call import-module,reactperflogger)

Просмотреть файл

@ -4,12 +4,12 @@ load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", "FBJNI_TARGET", "
rn_xplat_cxx_library( rn_xplat_cxx_library(
name = "core", name = "core",
srcs = glob( srcs = glob(
["*.cpp"], ["ReactCommon/**/*.cpp"],
), ),
header_namespace = "", header_namespace = "",
exported_headers = subdir_glob( exported_headers = subdir_glob(
[ [
("", "*.h"), ("ReactCommon", "*.h"),
], ],
prefix = "ReactCommon", prefix = "ReactCommon",
), ),
@ -26,13 +26,13 @@ rn_xplat_cxx_library(
], ],
fbandroid_exported_headers = subdir_glob( fbandroid_exported_headers = subdir_glob(
[ [
("platform/android", "*.h"), ("platform/android/ReactCommon", "*.h"),
], ],
prefix = "ReactCommon", prefix = "ReactCommon",
), ),
fbandroid_srcs = glob( fbandroid_srcs = glob(
[ [
"platform/android/**/*.cpp", "platform/android/ReactCommon/*.cpp",
], ],
), ),
fbobjc_compiler_flags = [ fbobjc_compiler_flags = [

Просмотреть файл

@ -19,6 +19,7 @@
#include <react/renderer/core/Props.h> #include <react/renderer/core/Props.h>
#include <react/renderer/core/RawValue.h> #include <react/renderer/core/RawValue.h>
#include <react/renderer/mounting/MountingCoordinator.h> #include <react/renderer/mounting/MountingCoordinator.h>
#include <react/renderer/mounting/ShadowViewMutation.h>
#include <react/renderer/mounting/Differentiator.h> #include <react/renderer/mounting/Differentiator.h>
#include <react/renderer/mounting/ShadowTreeRevision.h> #include <react/renderer/mounting/ShadowTreeRevision.h>
@ -396,9 +397,12 @@ void LayoutAnimationKeyFrameManager::
adjustImmediateMutationIndicesForDelayedMutations( adjustImmediateMutationIndicesForDelayedMutations(
SurfaceId surfaceId, SurfaceId surfaceId,
ShadowViewMutation &mutation, ShadowViewMutation &mutation,
ShadowViewMutationList *auxiliaryMutations) const { ConsecutiveAdjustmentMetadata &consecutiveAdjustmentMetadata,
bool skipLastAnimation,
bool lastAnimationOnly) const {
bool isRemoveMutation = mutation.type == ShadowViewMutation::Type::Remove; bool isRemoveMutation = mutation.type == ShadowViewMutation::Type::Remove;
assert(isRemoveMutation || mutation.type == ShadowViewMutation::Type::Insert); bool isInsertMutation = mutation.type == ShadowViewMutation::Type::Insert;
assert(isRemoveMutation || isInsertMutation);
// TODO: turn all of this into a lambda and share code? // TODO: turn all of this into a lambda and share code?
if (mutatedViewIsVirtual(mutation)) { if (mutatedViewIsVirtual(mutation)) {
@ -412,36 +416,35 @@ void LayoutAnimationKeyFrameManager::
"[IndexAdjustment] Calling adjustImmediateMutationIndicesForDelayedMutations for:", "[IndexAdjustment] Calling adjustImmediateMutationIndicesForDelayedMutations for:",
mutation); mutation);
// When adjusting INSERTs, we want to batch adjacent inserts so they're all
// adjacent to each other in the resulting view. For instance, if we're
// processing INSERTS into positions 2,3,4,5,6, etc, it is possible that
// delayed mutations would otherwise cause the inserts to be adjusted to
// positions 2, 4, 6, 8... etc, creating a striping effect. We want to prevent
// that.
if (isInsertMutation &&
mutation.parentShadowView.tag ==
consecutiveAdjustmentMetadata.lastAdjustedParent &&
mutation.index == (consecutiveAdjustmentMetadata.lastIndexOriginal + 1)) {
PrintMutationInstruction(
std::string(
"[IndexAdjustment] adjustImmediateMutationIndicesForDelayedMutations: Adjusting consecutive INSERT mutation by ") +
std::to_string(consecutiveAdjustmentMetadata.lastAdjustedDelta),
mutation);
consecutiveAdjustmentMetadata.lastIndexOriginal = mutation.index;
mutation.index += consecutiveAdjustmentMetadata.lastAdjustedDelta;
return;
}
// First, collect all final mutations that could impact this immediate // First, collect all final mutations that could impact this immediate
// mutation. // mutation.
std::vector<ShadowViewMutation *> candidateMutations{}; std::vector<ShadowViewMutation *> candidateMutations{};
if (auxiliaryMutations != nullptr) { for (auto inflightAnimationIt =
for (auto &auxMutation : *auxiliaryMutations) { inflightAnimations_.rbegin() + (skipLastAnimation ? 1 : 0);
if (auxMutation.parentShadowView.tag != mutation.parentShadowView.tag) { inflightAnimationIt != inflightAnimations_.rend();
continue; inflightAnimationIt++) {
} auto &inflightAnimation = *inflightAnimationIt;
if (auxMutation.type != ShadowViewMutation::Type::Remove) {
continue;
}
if (mutatedViewIsVirtual(auxMutation)) {
continue;
}
if (auxMutation.oldChildShadowView.tag ==
(isRemoveMutation ? mutation.oldChildShadowView.tag
: mutation.newChildShadowView.tag)) {
continue;
}
PrintMutationInstructionRelative(
"[IndexAdjustment] adjustImmediateMutationIndicesForDelayedMutations auxiliary CANDIDATE for:",
mutation,
auxMutation);
candidateMutations.push_back(&auxMutation);
}
}
for (auto &inflightAnimation : inflightAnimations_) {
if (inflightAnimation.surfaceId != surfaceId) { if (inflightAnimation.surfaceId != surfaceId) {
continue; continue;
} }
@ -464,9 +467,6 @@ void LayoutAnimationKeyFrameManager::
continue; continue;
} }
if (animatedKeyFrame.type != AnimationConfigurationType::Noop) {
continue;
}
if (!animatedKeyFrame.finalMutationForKeyFrame.has_value()) { if (!animatedKeyFrame.finalMutationForKeyFrame.has_value()) {
continue; continue;
} }
@ -491,21 +491,33 @@ void LayoutAnimationKeyFrameManager::
delayedMutation); delayedMutation);
candidateMutations.push_back(&delayedMutation); candidateMutations.push_back(&delayedMutation);
} }
if (lastAnimationOnly) {
break;
}
} }
// While the mutation keeps being affected, keep checking. We use the vector // While the mutation keeps being affected, keep checking. We use the vector
// so we only perform one adjustment per delayed mutation. See comments at // so we only perform one adjustment per delayed mutation. See comments at
// bottom of adjustDelayedMutationIndicesForMutation for further explanation. // bottom of adjustDelayedMutationIndicesForMutation for further explanation.
bool changed = true; bool changed = true;
int adjustedDelta = 0;
if (isInsertMutation) {
consecutiveAdjustmentMetadata.lastAdjustedParent =
mutation.parentShadowView.tag;
consecutiveAdjustmentMetadata.lastIndexOriginal = mutation.index;
}
while (changed) { while (changed) {
changed = false; changed = false;
candidateMutations.erase( candidateMutations.erase(
std::remove_if( std::remove_if(
candidateMutations.begin(), candidateMutations.begin(),
candidateMutations.end(), candidateMutations.end(),
[&mutation, &changed](ShadowViewMutation *candidateMutation) { [&](ShadowViewMutation *candidateMutation) {
if (candidateMutation->index <= mutation.index) { bool indexConflicts = candidateMutation->index <= mutation.index;
if (indexConflicts) {
mutation.index++; mutation.index++;
adjustedDelta++;
changed = true; changed = true;
PrintMutationInstructionRelative( PrintMutationInstructionRelative(
"[IndexAdjustment] adjustImmediateMutationIndicesForDelayedMutations: Adjusting mutation UPWARD", "[IndexAdjustment] adjustImmediateMutationIndicesForDelayedMutations: Adjusting mutation UPWARD",
@ -517,19 +529,17 @@ void LayoutAnimationKeyFrameManager::
}), }),
candidateMutations.end()); candidateMutations.end());
} }
} if (isInsertMutation) {
consecutiveAdjustmentMetadata.lastAdjustedDelta = adjustedDelta;
void LayoutAnimationKeyFrameManager:: } else {
adjustLastAnimationDelayedMutationIndicesForMutation( consecutiveAdjustmentMetadata.lastAdjustedParent = -1;
SurfaceId surfaceId, }
ShadowViewMutation const &mutation) const {
adjustDelayedMutationIndicesForMutation(surfaceId, mutation, true);
} }
void LayoutAnimationKeyFrameManager::adjustDelayedMutationIndicesForMutation( void LayoutAnimationKeyFrameManager::adjustDelayedMutationIndicesForMutation(
SurfaceId surfaceId, SurfaceId surfaceId,
ShadowViewMutation const &mutation, ShadowViewMutation const &mutation,
bool lastAnimationOnly) const { bool skipLastAnimation) const {
bool isRemoveMutation = mutation.type == ShadowViewMutation::Type::Remove; bool isRemoveMutation = mutation.type == ShadowViewMutation::Type::Remove;
bool isInsertMutation = mutation.type == ShadowViewMutation::Type::Insert; bool isInsertMutation = mutation.type == ShadowViewMutation::Type::Insert;
assert(isRemoveMutation || isInsertMutation); assert(isRemoveMutation || isInsertMutation);
@ -545,7 +555,8 @@ void LayoutAnimationKeyFrameManager::adjustDelayedMutationIndicesForMutation(
// mutation. // mutation.
std::vector<ShadowViewMutation *> candidateMutations{}; std::vector<ShadowViewMutation *> candidateMutations{};
for (auto inflightAnimationIt = inflightAnimations_.rbegin(); for (auto inflightAnimationIt =
inflightAnimations_.rbegin() + (skipLastAnimation ? 1 : 0);
inflightAnimationIt != inflightAnimations_.rend(); inflightAnimationIt != inflightAnimations_.rend();
inflightAnimationIt++) { inflightAnimationIt++) {
auto &inflightAnimation = *inflightAnimationIt; auto &inflightAnimation = *inflightAnimationIt;
@ -572,9 +583,6 @@ void LayoutAnimationKeyFrameManager::adjustDelayedMutationIndicesForMutation(
continue; continue;
} }
if (animatedKeyFrame.type != AnimationConfigurationType::Noop) {
continue;
}
if (!animatedKeyFrame.finalMutationForKeyFrame.has_value()) { if (!animatedKeyFrame.finalMutationForKeyFrame.has_value()) {
continue; continue;
} }
@ -587,19 +595,19 @@ void LayoutAnimationKeyFrameManager::adjustDelayedMutationIndicesForMutation(
continue; continue;
} }
if (!mutatedViewIsVirtual(*animatedKeyFrame.finalMutationForKeyFrame) && if (finalAnimationMutation.type != ShadowViewMutation::Type::Remove) {
finalAnimationMutation.type == ShadowViewMutation::Type::Remove) { continue;
PrintMutationInstructionRelative( }
"[IndexAdjustment] adjustDelayedMutationIndicesForMutation: CANDIDATE:", if (mutatedViewIsVirtual(*animatedKeyFrame.finalMutationForKeyFrame)) {
mutation, continue;
*animatedKeyFrame.finalMutationForKeyFrame);
candidateMutations.push_back(
animatedKeyFrame.finalMutationForKeyFrame.get_pointer());
} }
}
if (lastAnimationOnly) { PrintMutationInstructionRelative(
break; "[IndexAdjustment] adjustDelayedMutationIndicesForMutation: CANDIDATE:",
mutation,
*animatedKeyFrame.finalMutationForKeyFrame);
candidateMutations.push_back(
animatedKeyFrame.finalMutationForKeyFrame.get_pointer());
} }
} }
@ -685,18 +693,6 @@ LayoutAnimationKeyFrameManager::getAndEraseConflictingAnimations(
continue; continue;
} }
// bool hasFinalMutation =
// animatedKeyFrame.finalMutationForKeyFrame.hasValue();
// int finalMutationTag = hasFinalMutation
// ? (((*animatedKeyFrame.finalMutationForKeyFrame).type ==
// ShadowViewMutation::Create ||
// (*animatedKeyFrame.finalMutationForKeyFrame).type ==
// ShadowViewMutation::Insert)
// ? (*animatedKeyFrame.finalMutationForKeyFrame)
// .newChildShadowView.tag
// : (*animatedKeyFrame.finalMutationForKeyFrame)
// .oldChildShadowView.tag)
// : -1;
bool conflicting = animatedKeyFrame.tag == baselineShadowView.tag || bool conflicting = animatedKeyFrame.tag == baselineShadowView.tag ||
((mutation.type == ShadowViewMutation::Type::Delete || ((mutation.type == ShadowViewMutation::Type::Delete ||
mutation.type == ShadowViewMutation::Type::Create) && mutation.type == ShadowViewMutation::Type::Create) &&
@ -704,20 +700,6 @@ LayoutAnimationKeyFrameManager::getAndEraseConflictingAnimations(
finalMutationTag == baselineShadowView.tag*/ finalMutationTag == baselineShadowView.tag*/
; ;
// In some bizarre situations, there can be an ongoing Delete
// animation, and then a conflicting mutation to create and/or delete
// the same tag. In actuality this "bizarre" situation is just the
// animation of repeatedly flattening and unflattening a view; but
// it's not clear how to gracefully recover from this, so we just
// ensure that the Deletion is never executed in those cases. In these
// cases, the ongoing animation will stop; the view still exists; and
// then either a "Create" or "delete" animation will be recreated and
// executed for that tag.
bool shouldExecuteFinalMutation =
!(animatedKeyFrame.finalMutationForKeyFrame.hasValue() &&
(*animatedKeyFrame.finalMutationForKeyFrame).type ==
ShadowViewMutation::Delete);
// Conflicting animation detected: if we're mutating a tag under // Conflicting animation detected: if we're mutating a tag under
// animation, or deleting the parent of a tag under animation, or // animation, or deleting the parent of a tag under animation, or
// reparenting. // reparenting.
@ -735,7 +717,9 @@ LayoutAnimationKeyFrameManager::getAndEraseConflictingAnimations(
animatedKeyFrame.invalidated = true; animatedKeyFrame.invalidated = true;
if (shouldExecuteFinalMutation) { if (animatedKeyFrame.finalMutationForKeyFrame.has_value() &&
!mutatedViewIsVirtual(
*animatedKeyFrame.finalMutationForKeyFrame)) {
conflictingAnimations.push_back(std::make_tuple( conflictingAnimations.push_back(std::make_tuple(
animatedKeyFrame, *mutationConfig, &inflightAnimation)); animatedKeyFrame, *mutationConfig, &inflightAnimation));
} }
@ -748,7 +732,7 @@ LayoutAnimationKeyFrameManager::getAndEraseConflictingAnimations(
*animatedKeyFrame.finalMutationForKeyFrame); *animatedKeyFrame.finalMutationForKeyFrame);
} else { } else {
PrintMutationInstruction( PrintMutationInstruction(
"Found mutation that conflicts with existing in-flight animation:", "Found mutation that conflicts with existing in-flight animation (no final mutation):",
mutation); mutation);
} }
#endif #endif
@ -756,13 +740,6 @@ LayoutAnimationKeyFrameManager::getAndEraseConflictingAnimations(
// Delete from existing animation // Delete from existing animation
it = inflightAnimation.keyFrames.erase(it); it = inflightAnimation.keyFrames.erase(it);
} else { } else {
//#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
// if (hasFinalMutation) {
// PrintMutationInstructionRelative("getAndEraseConflictingAnimations,
// NOT erasing non-conflicting mutation of ", mutation,
// *animatedKeyFrame.finalMutationForKeyFrame);
// }
//#endif
it++; it++;
} }
} }
@ -844,7 +821,8 @@ LayoutAnimationKeyFrameManager::pullTransaction(
if (keyframe.invalidated) { if (keyframe.invalidated) {
continue; continue;
} }
if (keyframe.finalMutationForKeyFrame) { if (keyframe.finalMutationForKeyFrame &&
!mutatedViewIsVirtual(*keyframe.finalMutationForKeyFrame)) {
std::string msg = "Animation " + std::to_string(i) + " keyframe " + std::string msg = "Animation " + std::to_string(i) + " keyframe " +
std::to_string(j) + ": Final Animation"; std::to_string(j) + ": Final Animation";
PrintMutationInstruction(msg, *keyframe.finalMutationForKeyFrame); PrintMutationInstruction(msg, *keyframe.finalMutationForKeyFrame);
@ -899,15 +877,23 @@ LayoutAnimationKeyFrameManager::pullTransaction(
// being moves on the Differ level, since we know that there? We could use // being moves on the Differ level, since we know that there? We could use
// TinyMap here, but it's not exposed by Differentiator (yet). // TinyMap here, but it's not exposed by Differentiator (yet).
std::vector<Tag> insertedTags; std::vector<Tag> insertedTags;
std::vector<Tag> createdTags; std::vector<Tag> deletedTags;
std::vector<Tag> reparentedTags; // tags that are deleted and recreated
std::unordered_map<Tag, ShadowViewMutation> movedTags; std::unordered_map<Tag, ShadowViewMutation> movedTags;
std::vector<Tag> reparentedTags;
for (const auto &mutation : mutations) { for (const auto &mutation : mutations) {
if (mutation.type == ShadowViewMutation::Type::Insert) { if (mutation.type == ShadowViewMutation::Type::Insert) {
insertedTags.push_back(mutation.newChildShadowView.tag); insertedTags.push_back(mutation.newChildShadowView.tag);
} }
if (mutation.type == ShadowViewMutation::Type::Delete) {
deletedTags.push_back(mutation.oldChildShadowView.tag);
}
if (mutation.type == ShadowViewMutation::Type::Create) { if (mutation.type == ShadowViewMutation::Type::Create) {
createdTags.push_back(mutation.newChildShadowView.tag); if (std::find(
deletedTags.begin(),
deletedTags.end(),
mutation.newChildShadowView.tag) != deletedTags.end()) {
reparentedTags.push_back(mutation.newChildShadowView.tag);
}
} }
} }
@ -954,26 +940,15 @@ LayoutAnimationKeyFrameManager::pullTransaction(
// This should eventually be optimized out of the diffing algorithm, but // This should eventually be optimized out of the diffing algorithm, but
// for now we detect reparenting and prevent the corresponding // for now we detect reparenting and prevent the corresponding
// Delete/Create instructions from being animated. // Delete/Create instructions from being animated.
bool isReparented = bool isReparented = std::find(
(mutation.type == ShadowViewMutation::Delete && reparentedTags.begin(),
std::find( reparentedTags.end(),
createdTags.begin(), baselineShadowView.tag) != reparentedTags.end();
createdTags.end(),
mutation.oldChildShadowView.tag) != createdTags.end()) ||
(mutation.type == ShadowViewMutation::Create &&
std::find(
reparentedTags.begin(),
reparentedTags.end(),
mutation.newChildShadowView.tag) != reparentedTags.end());
if (isRemoveReinserted) { if (isRemoveReinserted) {
movedTags.insert({mutation.oldChildShadowView.tag, mutation}); movedTags.insert({mutation.oldChildShadowView.tag, mutation});
} }
if (isReparented && mutation.type == ShadowViewMutation::Delete) {
reparentedTags.push_back(mutation.oldChildShadowView.tag);
}
// Inserts that follow a "remove" of the same tag should be treated as // Inserts that follow a "remove" of the same tag should be treated as
// an update (move) animation. // an update (move) animation.
bool wasInsertedTagRemoved = false; bool wasInsertedTagRemoved = false;
@ -1205,30 +1180,31 @@ LayoutAnimationKeyFrameManager::pullTransaction(
} }
#ifdef RN_SHADOW_TREE_INTROSPECTION #ifdef RN_SHADOW_TREE_INTROSPECTION
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
{ {
std::stringstream ss(getDebugDescription(immediateMutations, {})); int idx = 0;
std::string to; for (auto &mutation : immediateMutations) {
while (std::getline(ss, to, '\n')) { PrintMutationInstruction(
LOG(ERROR) std::string("IMMEDIATE list: ") + std::to_string(idx) + "/" +
<< "LayoutAnimationKeyFrameManager.cpp: got IMMEDIATE list: Line: " std::to_string(immediateMutations.size()),
<< to; mutation);
idx++;
} }
} }
{ {
int idx = 0;
for (const auto &keyframe : keyFramesToAnimate) { for (const auto &keyframe : keyFramesToAnimate) {
if (keyframe.finalMutationForKeyFrame) { if (keyframe.finalMutationForKeyFrame.has_value()) {
std::stringstream ss( PrintMutationInstruction(
getDebugDescription(*keyframe.finalMutationForKeyFrame, {})); std::string("FINAL list: ") + std::to_string(idx) + "/" +
std::string to; std::to_string(keyFramesToAnimate.size()),
while (std::getline(ss, to, '\n')) { *keyframe.finalMutationForKeyFrame);
LOG(ERROR)
<< "LayoutAnimationKeyFrameManager.cpp: got FINAL list: Line: "
<< to;
}
} }
idx++;
} }
} }
#endif
#endif #endif
auto finalConflictingMutations = ShadowViewMutationList{}; auto finalConflictingMutations = ShadowViewMutationList{};
@ -1247,59 +1223,121 @@ LayoutAnimationKeyFrameManager::pullTransaction(
finalConflictingMutations.end(), finalConflictingMutations.end(),
&shouldFirstComeBeforeSecondMutation); &shouldFirstComeBeforeSecondMutation);
// Use "final conflicting mutations" to adjust delayed mutations *before*
// we adjust immediate mutations based on delayed mutations
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
LOG(ERROR)
<< "Adjust delayed mutations based on finalConflictingMutations";
#endif
for (auto &mutation : finalConflictingMutations) {
if (mutation.type == ShadowViewMutation::Remove ||
mutation.type == ShadowViewMutation::Insert) {
adjustDelayedMutationIndicesForMutation(surfaceId, mutation);
}
}
// Adjust keyframes based on already-delayed, existing animations, before
// queueing. We adjust them as if finalConflictingMutations have already
// been executed - in all cases, finalConflictingMutations will be
// executed before any of these delayed mutations are.
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
LOG(ERROR)
<< "Adjust immediate keyFramesToAnimate based on delayed mutations and finalConflictingMutations";
#endif
for (auto &keyframe : keyFramesToAnimate) {
if (keyframe.finalMutationForKeyFrame.has_value()) {
auto &delayedMutation = *keyframe.finalMutationForKeyFrame;
if (delayedMutation.type == ShadowViewMutation::Type::Remove) {
adjustImmediateMutationIndicesForDelayedMutations(
surfaceId, delayedMutation /*, &finalConflictingMutations*/);
}
}
}
// REMOVE mutations from this animation batch *cannot* be impacted by
// other REMOVEs from this batch, since they're already taken into
// account. INSERTs can impact delayed REMOVEs; see below.
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
LOG(ERROR)
<< "Adjust immediateMutations REMOVEs only, based on previously delayed mutations, without most-recent animation";
#endif
std::stable_sort( std::stable_sort(
immediateMutations.begin(), immediateMutations.begin(),
immediateMutations.end(), immediateMutations.end(),
&shouldFirstComeBeforeSecondRemovesOnly); &shouldFirstComeBeforeSecondRemovesOnly);
for (auto &mutation : immediateMutations) {
if (mutation.type == ShadowViewMutation::Type::Remove) {
adjustImmediateMutationIndicesForDelayedMutations(
surfaceId, mutation);
adjustDelayedMutationIndicesForMutation(surfaceId, mutation);
}
}
animation.keyFrames = keyFramesToAnimate; animation.keyFrames = keyFramesToAnimate;
inflightAnimations_.push_back(std::move(animation)); inflightAnimations_.push_back(std::move(animation));
// At this point, we have the following information and knowledge graph:
// Knowledge Graph:
// [ImmediateMutations] -> assumes [FinalConflicting], [FrameDelayed],
// [Delayed] already executed [FrameDelayed] -> assumes
// [FinalConflicting], [Delayed] already executed [FinalConflicting] -> is
// adjusted based on [Delayed], no dependency on [FinalConflicting],
// [FrameDelayed] [Delayed] -> assumes [FinalConflicting],
// [ImmediateMutations] not executed yet
ConsecutiveAdjustmentMetadata consecutiveAdjustmentMetadata{};
// Adjust [Delayed] based on [FinalConflicting]
// Knowledge Graph:
// [ImmediateMutations] -> assumes [FinalConflicting], [FrameDelayed],
// [Delayed] already executed [FrameDelayed] -> assumes
// [FinalConflicting], [Delayed] already executed [FinalConflicting] -> is
// adjusted based on [Delayed], no dependency on [FinalConflicting],
// [FrameDelayed] [Delayed] -> adjusted for [FinalConflicting]; assumes
// [ImmediateMutations] not executed yet
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
LOG(ERROR) << "Adjust [Delayed] based on [FinalConflicting]";
#endif
for (auto &mutation : finalConflictingMutations) {
if (mutation.type == ShadowViewMutation::Type::Insert ||
mutation.type == ShadowViewMutation::Type::Remove) {
adjustDelayedMutationIndicesForMutation(surfaceId, mutation, true);
}
}
// Adjust [FrameDelayed] based on [Delayed]
// Knowledge Graph:
// [ImmediateExecutions] -> assumes [FinalConflicting], [Delayed],
// [FrameDelayed] already executed [FrameDelayed] -> adjusted for
// [Delayed]; assumes [FinalConflicting] already executed
// [FinalConflicting] -> is adjusted based on [Delayed], no dependency on
// [FinalConflicting], [FrameDelayed] [Delayed] -> adjusted for
// [FinalConflicting]; assumes [ImmediateExecutions] not executed yet
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
LOG(ERROR) << "Adjust [FrameDelayed] based on [Delayed]";
#endif
for (auto &keyframe : inflightAnimations_.back().keyFrames) {
if (keyframe.finalMutationForKeyFrame.has_value()) {
auto &mutation = *keyframe.finalMutationForKeyFrame;
if (mutation.type == ShadowViewMutation::Type::Insert ||
mutation.type == ShadowViewMutation::Type::Remove) {
// When adjusting, skip adjusting against last animation - because
// all `mutation`s here come from the last animation, so we can't
// adjust a batch against itself.
adjustImmediateMutationIndicesForDelayedMutations(
surfaceId, mutation, consecutiveAdjustmentMetadata, true);
}
}
}
// Adjust [ImmediateExecutions] based on [Delayed]
// Knowledge Graph:
// [ImmediateExecutions] -> adjusted for [FrameDelayed], [Delayed];
// assumes [FinalConflicting] already executed [FrameDelayed] -> adjusted
// for [Delayed]; assumes [FinalConflicting] already executed
// [FinalConflicting] -> is adjusted based on [Delayed], no dependency on
// [FinalConflicting], [FrameDelayed] [Delayed] -> adjusted for
// [FinalConflicting]; assumes [ImmediateExecutions] not executed yet
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
LOG(ERROR) << "Adjust [ImmediateExecutions] based on [Delayed]";
#endif
consecutiveAdjustmentMetadata = ConsecutiveAdjustmentMetadata{};
for (auto &mutation : immediateMutations) {
// Note: when adjusting [ImmediateExecutions] based on [FrameDelayed],
// we need only adjust Inserts. Since inserts are executed
// highest-index-first, lower indices being delayed does not impact the
// higher-index removals; and conversely, higher indices being delayed
// cannot impact lower index removal, regardless of order.
if (mutation.type == ShadowViewMutation::Type::Insert ||
mutation.type == ShadowViewMutation::Type::Remove) {
adjustImmediateMutationIndicesForDelayedMutations(
surfaceId,
mutation,
consecutiveAdjustmentMetadata,
mutation.type == ShadowViewMutation::Type::Remove);
}
}
// Adjust [Delayed] based on [ImmediateExecutions] and [FinalConflicting]
// Knowledge Graph:
// [ImmediateExecutions] -> adjusted for [FrameDelayed], [Delayed];
// assumes [FinalConflicting] already executed [FrameDelayed] -> adjusted
// for [Delayed]; assumes [FinalConflicting] already executed
// [FinalConflicting] -> is adjusted based on [Delayed], no dependency on
// [FinalConflicting], [FrameDelayed] [Delayed] -> adjusted for
// [FinalConflicting], [ImmediateExecutions]
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
LOG(ERROR)
<< "Adjust [Delayed] based on [ImmediateExecutions] and [FinalConflicting]";
#endif
for (auto &mutation : immediateMutations) {
if (mutation.type == ShadowViewMutation::Type::Insert ||
mutation.type == ShadowViewMutation::Type::Remove) {
// Here we need to adjust both Delayed and FrameDelayed mutations.
// Delayed Removes can be impacted by non-delayed Inserts from the
// same frame.
adjustDelayedMutationIndicesForMutation(surfaceId, mutation);
}
}
// If the knowledge graph progression above is correct, it is now safe to
// execute finalConflictingMutations and immediateMutations in that order,
// and to queue the delayed animations from this frame.
//
// Execute the conflicting, delayed operations immediately. Any UPDATE // Execute the conflicting, delayed operations immediately. Any UPDATE
// operations that smoothly transition into another animation will be // operations that smoothly transition into another animation will be
// overridden by generated UPDATE operations at the end of the list, and // overridden by generated UPDATE operations at the end of the list, and
@ -1307,60 +1345,24 @@ LayoutAnimationKeyFrameManager::pullTransaction(
// Additionally, this should allow us to avoid performing index adjustment // Additionally, this should allow us to avoid performing index adjustment
// between this list of conflicting animations and the batch we're about // between this list of conflicting animations and the batch we're about
// to execute. // to execute.
mutations = ShadowViewMutationList{}; finalConflictingMutations.insert(
for (auto &mutation : finalConflictingMutations) { finalConflictingMutations.end(),
mutations.push_back(mutation);
}
// Before computing mutations based on animations / final mutations for
// this frame, we want to update any pending final mutations since they
// will execute *after* this batch of immediate mutations. Important case
// to consider (as an example, there are other interesting cases): there's
// a delayed "Remove", then an immediate "insert" is scheduled for an
// earlier index with the same parent. The remove needs to be adjusted
// upward here. Conversely, Inserts at later indices will assume the
// remove has already been executed, which may not be the case.
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
LOG(ERROR)
<< "Adjust immediateMutations and delayed mutations, including just-queued animations, based on each one";
#endif
for (auto &mutation : immediateMutations) {
if (mutation.type == ShadowViewMutation::Type::Remove) {
adjustLastAnimationDelayedMutationIndicesForMutation(
surfaceId, mutation);
} else if (mutation.type == ShadowViewMutation::Type::Insert) {
adjustImmediateMutationIndicesForDelayedMutations(
surfaceId, mutation);
adjustDelayedMutationIndicesForMutation(surfaceId, mutation);
}
}
// These will be executed immediately. These should already be sorted
// properly.
mutations.insert(
mutations.end(),
immediateMutations.begin(), immediateMutations.begin(),
immediateMutations.end()); immediateMutations.end());
mutations = finalConflictingMutations;
} /* if (currentAnimation) */ else { } /* if (currentAnimation) */ else {
// The ShadowTree layer doesn't realize that certain operations have been
// delayed, so we must adjust all Remove and Insert operations based on
// what else has been deferred, whether we are executing this immediately
// or later.
for (auto &mutation : mutations) {
if (mutation.type == ShadowViewMutation::Type::Remove ||
mutation.type == ShadowViewMutation::Type::Insert) {
adjustImmediateMutationIndicesForDelayedMutations(
surfaceId, mutation);
adjustDelayedMutationIndicesForMutation(surfaceId, mutation);
}
}
// If there's no "next" animation, make sure we queue up "final" // If there's no "next" animation, make sure we queue up "final"
// operations from all ongoing, conflicting animations. // operations from all ongoing, conflicting animations.
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
LOG(ERROR) << "No Animation: Queue up final conflicting animations";
#endif
ShadowViewMutationList finalMutationsForConflictingAnimations{}; ShadowViewMutationList finalMutationsForConflictingAnimations{};
for (auto &conflictingKeyframeTuple : conflictingAnimations) { for (auto &conflictingKeyframeTuple : conflictingAnimations) {
auto &keyFrame = std::get<0>(conflictingKeyframeTuple); auto &keyFrame = std::get<0>(conflictingKeyframeTuple);
if (keyFrame.finalMutationForKeyFrame.hasValue()) { if (keyFrame.finalMutationForKeyFrame.hasValue()) {
PrintMutationInstruction(
"No Animation: Queueing final mutation instruction",
*keyFrame.finalMutationForKeyFrame);
finalMutationsForConflictingAnimations.push_back( finalMutationsForConflictingAnimations.push_back(
*keyFrame.finalMutationForKeyFrame); *keyFrame.finalMutationForKeyFrame);
} }
@ -1373,6 +1375,45 @@ LayoutAnimationKeyFrameManager::pullTransaction(
finalMutationsForConflictingAnimations.end(), finalMutationsForConflictingAnimations.end(),
&shouldFirstComeBeforeSecondMutation); &shouldFirstComeBeforeSecondMutation);
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
LOG(ERROR)
<< "No Animation: Adjust delayed mutations based on all finalMutationsForConflictingAnimations";
#endif
for (auto &mutation : finalMutationsForConflictingAnimations) {
if (mutation.type == ShadowViewMutation::Type::Remove ||
mutation.type == ShadowViewMutation::Type::Insert) {
adjustDelayedMutationIndicesForMutation(surfaceId, mutation);
}
}
// The ShadowTree layer doesn't realize that certain operations have been
// delayed, so we must adjust all Remove and Insert operations based on
// what else has been deferred, whether we are executing this immediately
// or later.
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
LOG(ERROR)
<< "No Animation: Adjust mutations based on remaining delayed mutations";
#endif
ConsecutiveAdjustmentMetadata consecutiveAdjustmentMetadata{};
for (auto &mutation : mutations) {
if (mutation.type == ShadowViewMutation::Type::Remove ||
mutation.type == ShadowViewMutation::Type::Insert) {
adjustImmediateMutationIndicesForDelayedMutations(
surfaceId, mutation, consecutiveAdjustmentMetadata);
}
}
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
LOG(ERROR)
<< "No Animation: Adjust delayed mutations based on all immediate mutations";
#endif
for (auto &mutation : mutations) {
if (mutation.type == ShadowViewMutation::Type::Remove ||
mutation.type == ShadowViewMutation::Type::Insert) {
adjustDelayedMutationIndicesForMutation(surfaceId, mutation);
}
}
// Append mutations to this list and swap - so that the final // Append mutations to this list and swap - so that the final
// conflicting mutations happen before any other mutations // conflicting mutations happen before any other mutations
finalMutationsForConflictingAnimations.insert( finalMutationsForConflictingAnimations.insert(
@ -1392,13 +1433,6 @@ LayoutAnimationKeyFrameManager::pullTransaction(
ShadowViewMutationList mutationsForAnimation{}; ShadowViewMutationList mutationsForAnimation{};
animationMutationsForFrame(surfaceId, mutationsForAnimation, now); animationMutationsForFrame(surfaceId, mutationsForAnimation, now);
// Erase any remaining animations that conflict with these mutations
// In some marginal cases, a DELETE animation can be queued up and a final
// DELETE mutation be executed by the animation driver. These cases deserve
// further scrutiny, but for now to prevent crashes, just make sure the queued
// DELETE operations are removed.
getAndEraseConflictingAnimations(surfaceId, mutationsForAnimation, true);
// If any delayed removes were executed, update remaining delayed keyframes // If any delayed removes were executed, update remaining delayed keyframes
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING #ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
LOG(ERROR) LOG(ERROR)
@ -1431,7 +1465,8 @@ LayoutAnimationKeyFrameManager::pullTransaction(
if (keyframe.invalidated) { if (keyframe.invalidated) {
continue; continue;
} }
if (keyframe.finalMutationForKeyFrame) { if (keyframe.finalMutationForKeyFrame &&
!mutatedViewIsVirtual(*keyframe.finalMutationForKeyFrame)) {
std::string msg = "Animation " + std::to_string(i) + " keyframe " + std::string msg = "Animation " + std::to_string(i) + " keyframe " +
std::to_string(j) + ": Final Animation"; std::to_string(j) + ": Final Animation";
PrintMutationInstruction(msg, *keyframe.finalMutationForKeyFrame); PrintMutationInstruction(msg, *keyframe.finalMutationForKeyFrame);

Просмотреть файл

@ -110,6 +110,12 @@ struct AnimationKeyFrame {
bool invalidated{false}; bool invalidated{false};
}; };
struct ConsecutiveAdjustmentMetadata {
Tag lastAdjustedParent{-1};
int lastAdjustedDelta{0};
int lastIndexOriginal{0};
};
class LayoutAnimationCallbackWrapper { class LayoutAnimationCallbackWrapper {
public: public:
LayoutAnimationCallbackWrapper(jsi::Function &&callback) LayoutAnimationCallbackWrapper(jsi::Function &&callback)
@ -212,16 +218,14 @@ class LayoutAnimationKeyFrameManager : public UIManagerAnimationDelegate,
void adjustImmediateMutationIndicesForDelayedMutations( void adjustImmediateMutationIndicesForDelayedMutations(
SurfaceId surfaceId, SurfaceId surfaceId,
ShadowViewMutation &mutation, ShadowViewMutation &mutation,
ShadowViewMutationList *auxiliaryMutations = nullptr) const; ConsecutiveAdjustmentMetadata &consecutiveAdjustmentMetadata,
bool skipLastAnimation = false,
bool lastAnimationOnly = false) const;
void adjustDelayedMutationIndicesForMutation( void adjustDelayedMutationIndicesForMutation(
SurfaceId surfaceId, SurfaceId surfaceId,
ShadowViewMutation const &mutation, ShadowViewMutation const &mutation,
bool lastAnimationOnly = false) const; bool skipLastAnimation = false) const;
void adjustLastAnimationDelayedMutationIndicesForMutation(
SurfaceId surfaceId,
ShadowViewMutation const &mutation) const;
std::vector<std::tuple<AnimationKeyFrame, AnimationConfig, LayoutAnimation *>> std::vector<std::tuple<AnimationKeyFrame, AnimationConfig, LayoutAnimation *>>
getAndEraseConflictingAnimations( getAndEraseConflictingAnimations(

Просмотреть файл

@ -38,12 +38,17 @@ static jsi::Value linesMeasurementsPayload(
void ParagraphEventEmitter::onTextLayout( void ParagraphEventEmitter::onTextLayout(
LinesMeasurements const &linesMeasurements) const { LinesMeasurements const &linesMeasurements) const {
dispatchEvent( {
"textLayout", std::lock_guard<std::mutex> guard(linesMeasurementsMutex_);
[linesMeasurements](jsi::Runtime &runtime) { if (linesMeasurementsMetrics_ == linesMeasurements) {
return linesMeasurementsPayload(runtime, linesMeasurements); return;
}, }
EventPriority::AsynchronousBatched); linesMeasurementsMetrics_ = linesMeasurements;
}
dispatchEvent("textLayout", [linesMeasurements](jsi::Runtime &runtime) {
return linesMeasurementsPayload(runtime, linesMeasurements);
});
} }
} // namespace react } // namespace react

Просмотреть файл

@ -18,6 +18,10 @@ class ParagraphEventEmitter : public ViewEventEmitter {
using ViewEventEmitter::ViewEventEmitter; using ViewEventEmitter::ViewEventEmitter;
void onTextLayout(LinesMeasurements const &linesMeasurements) const; void onTextLayout(LinesMeasurements const &linesMeasurements) const;
private:
mutable std::mutex linesMeasurementsMutex_;
mutable LinesMeasurements linesMeasurementsMetrics_;
}; };
} // namespace react } // namespace react

Просмотреть файл

@ -164,18 +164,6 @@ void ParagraphShadowNode::layout(LayoutContext layoutContext) {
updateStateIfNeeded(content); updateStateIfNeeded(content);
if (content.attachments.empty()) {
#ifndef ANDROID
if (getConcreteProps().onTextLayout) {
// `onTextLayout` needs to be called even if text is empty
// to be compatible with Paper.
getConcreteEventEmitter().onTextLayout({});
}
#endif
// No attachments, nothing to layout.
return;
}
auto measurement = textLayoutManager_->measure( auto measurement = textLayoutManager_->measure(
AttributedStringBox{content.attributedString}, AttributedStringBox{content.attributedString},
content.paragraphAttributes, content.paragraphAttributes,
@ -191,6 +179,11 @@ void ParagraphShadowNode::layout(LayoutContext layoutContext) {
} }
#endif #endif
if (content.attachments.empty()) {
// No attachments to layout.
return;
}
// Iterating on attachments, we clone shadow nodes and moving // Iterating on attachments, we clone shadow nodes and moving
// `paragraphShadowNode` that represents clones of `this` object. // `paragraphShadowNode` that represents clones of `this` object.
auto paragraphShadowNode = static_cast<ParagraphShadowNode *>(this); auto paragraphShadowNode = static_cast<ParagraphShadowNode *>(this);

Просмотреть файл

@ -1076,11 +1076,7 @@ static void calculateShadowViewMutationsV2(
for (auto &oldFlattenedNode : oldFlattenedNodes) { for (auto &oldFlattenedNode : oldFlattenedNodes) {
auto unvisitedOldChildPairIt = unvisitedOldChildPairs.find( auto unvisitedOldChildPairIt = unvisitedOldChildPairs.find(
oldFlattenedNode.shadowView.tag); oldFlattenedNode.shadowView.tag);
if (unvisitedOldChildPairIt != unvisitedOldChildPairs.end()) { if (unvisitedOldChildPairIt == unvisitedOldChildPairs.end()) {
// Node unvisited - delete it entirely
deleteMutations.push_back(ShadowViewMutation::DeleteMutation(
oldFlattenedNode.shadowView));
} else {
// Node was visited - make sure to remove it from // Node was visited - make sure to remove it from
// "newRemainingPairs" map // "newRemainingPairs" map
auto newRemainingIt = auto newRemainingIt =
@ -1202,11 +1198,7 @@ static void calculateShadowViewMutationsV2(
for (auto &oldFlattenedNode : oldFlattenedNodes) { for (auto &oldFlattenedNode : oldFlattenedNodes) {
auto unvisitedOldChildPairIt = unvisitedOldChildPairs.find( auto unvisitedOldChildPairIt = unvisitedOldChildPairs.find(
oldFlattenedNode.shadowView.tag); oldFlattenedNode.shadowView.tag);
if (unvisitedOldChildPairIt != unvisitedOldChildPairs.end()) { if (unvisitedOldChildPairIt == unvisitedOldChildPairs.end()) {
// Node unvisited - delete it entirely
deleteMutations.push_back(ShadowViewMutation::DeleteMutation(
oldFlattenedNode.shadowView));
} else {
// Node was visited - make sure to remove it from // Node was visited - make sure to remove it from
// "newRemainingPairs" map // "newRemainingPairs" map
auto newRemainingIt = auto newRemainingIt =

Просмотреть файл

@ -83,13 +83,15 @@ void StubViewTree::mutate(
STUB_VIEW_ASSERT(registry.find(parentTag) != registry.end()); STUB_VIEW_ASSERT(registry.find(parentTag) != registry.end());
auto parentStubView = registry[parentTag]; auto parentStubView = registry[parentTag];
auto childTag = mutation.newChildShadowView.tag; auto childTag = mutation.newChildShadowView.tag;
STUB_VIEW_LOG({
LOG(ERROR) << "StubView: Insert: " << childTag << " into "
<< parentTag << " at " << mutation.index;
});
STUB_VIEW_ASSERT(registry.find(childTag) != registry.end()); STUB_VIEW_ASSERT(registry.find(childTag) != registry.end());
auto childStubView = registry[childTag]; auto childStubView = registry[childTag];
childStubView->update(mutation.newChildShadowView); childStubView->update(mutation.newChildShadowView);
STUB_VIEW_LOG({
LOG(ERROR) << "StubView: Insert: " << childTag << " into "
<< parentTag << " at " << mutation.index << "("
<< parentStubView->children.size() << " children)";
});
STUB_VIEW_ASSERT(parentStubView->children.size() >= mutation.index);
parentStubView->children.insert( parentStubView->children.insert(
parentStubView->children.begin() + mutation.index, childStubView); parentStubView->children.begin() + mutation.index, childStubView);
break; break;
@ -106,6 +108,7 @@ void StubViewTree::mutate(
<< parentTag << " at index " << mutation.index << " with " << parentTag << " at index " << mutation.index << " with "
<< parentStubView->children.size() << " children"; << parentStubView->children.size() << " children";
}); });
STUB_VIEW_ASSERT(parentStubView->children.size() > mutation.index);
STUB_VIEW_ASSERT(registry.find(childTag) != registry.end()); STUB_VIEW_ASSERT(registry.find(childTag) != registry.end());
auto childStubView = registry[childTag]; auto childStubView = registry[childTag];
bool childIsCorrect = bool childIsCorrect =
@ -130,8 +133,15 @@ void StubViewTree::mutate(
STUB_VIEW_LOG({ STUB_VIEW_LOG({
LOG(ERROR) << "StubView: Update: " << mutation.newChildShadowView.tag; LOG(ERROR) << "StubView: Update: " << mutation.newChildShadowView.tag;
}); });
// We don't have a strict requirement that oldChildShadowView has any
// data. In particular, LayoutAnimations can produce UPDATEs with only a
// new node.
STUB_VIEW_ASSERT( STUB_VIEW_ASSERT(
mutation.newChildShadowView.tag == mutation.oldChildShadowView.tag); mutation.newChildShadowView.tag ==
mutation.oldChildShadowView.tag ||
mutation.oldChildShadowView.tag == 0);
STUB_VIEW_ASSERT( STUB_VIEW_ASSERT(
registry.find(mutation.newChildShadowView.tag) != registry.end()); registry.find(mutation.newChildShadowView.tag) != registry.end());
auto stubView = registry[mutation.newChildShadowView.tag]; auto stubView = registry[mutation.newChildShadowView.tag];

Просмотреть файл

@ -8,5 +8,24 @@
#include "TextMeasureCache.h" #include "TextMeasureCache.h"
namespace facebook { namespace facebook {
namespace react {} // namespace react namespace react {
bool LineMeasurement::operator==(LineMeasurement const &rhs) const {
return std::tie(
this->text,
this->frame,
this->descender,
this->capHeight,
this->ascender,
this->xHeight) ==
std::tie(
rhs.text,
rhs.frame,
rhs.descender,
rhs.capHeight,
rhs.ascender,
rhs.xHeight);
}
} // namespace react
} // namespace facebook } // namespace facebook

Просмотреть файл

@ -23,6 +23,8 @@ struct LineMeasurement {
Float capHeight; Float capHeight;
Float ascender; Float ascender;
Float xHeight; Float xHeight;
bool operator==(LineMeasurement const &rhs) const;
}; };
using LinesMeasurements = std::vector<LineMeasurement>; using LinesMeasurements = std::vector<LineMeasurement>;

Просмотреть файл

@ -123,7 +123,7 @@
"ws": "^6.1.4" "ws": "^6.1.4"
}, },
"devDependencies": { "devDependencies": {
"flow-bin": "^0.133.0", "flow-bin": "^0.134.0",
"react": "16.13.1" "react": "16.13.1"
}, },
"detox": { "detox": {

Просмотреть файл

@ -510,8 +510,8 @@ SPEC CHECKSUMS:
CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845 CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845
CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f
DoubleConversion: 2b45d0f8e156a5b02354c8a4062de64d41ccb4e0 DoubleConversion: 2b45d0f8e156a5b02354c8a4062de64d41ccb4e0
FBLazyVector: 6840df244b2930eadc86dfddd63dd586de8fbf4b FBLazyVector: a2e74b28704250f5c2840b8ac0c36a550fc58c5c
FBReactNativeSpec: 6a5b272a87d8fba0a0267169a9c69104a33f4104 FBReactNativeSpec: f32ba61faf46d74f93ee06325baab8f1f160cd4d
Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365 Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365
Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41 Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41
Flipper-Folly: c12092ea368353b58e992843a990a3225d4533c3 Flipper-Folly: c12092ea368353b58e992843a990a3225d4533c3
@ -522,33 +522,33 @@ SPEC CHECKSUMS:
glog: 789873d01e4b200777d0a09bc23d548446758699 glog: 789873d01e4b200777d0a09bc23d548446758699
OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355 OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355
RCT-Folly: 55d0039b24e192081ec0b2257f7bd9f42e382fb7 RCT-Folly: 55d0039b24e192081ec0b2257f7bd9f42e382fb7
RCTRequired: 8aab7fd83973da16ad4a7c320ab60d95daaf3a49 RCTRequired: f69bc029b4e19411dd37c82521ee7f40451c39bd
RCTTypeSafety: 1b9fcfa91c95a819c8ee11b2d78792a1a0c9f008 RCTTypeSafety: eac4bf166ab078acc91d836bf91c19227a52b5cb
React: 0d0bbc598d4e4a42c2d8f501e2d85bf68f4b4c58 React: e3ead01467fceb6371308544f0e94f35052230e7
React-callinvoker: 7171dcdb2310bc9843acfd9e9d1ad4432f069343 React-callinvoker: 14f7c592814aa4ed38de8ee15c87fb3284affcf0
React-Core: f9261d49de3292529f426b0337589cf85cbd2be5 React-Core: 56999fc712186d46fcd3b82563dbc1cdcfbbab47
React-CoreModules: 6cd34c4feb240e2243a2b766ac42b4922a43f272 React-CoreModules: 4f16f6042a515d575c6a8e745345403527c6b292
React-cxxreact: 1d94eae472a7d96512c9616b79755f17b7d9e60d React-cxxreact: efd175939ed4f9ed26c39ae528151841e785187c
React-jsi: 738aad53cef29cda532eb60393636882b048aa63 React-jsi: 52b19336123975495cc71d6f8881f599ad5fc301
React-jsiexecutor: 4f307d9cf526c904c6a29a492ee0d0a56a3955ac React-jsiexecutor: 75e0be97411644e306e86ff043bc35eb9bf57f5d
React-jsinspector: 9a11ad30cee910a8f9af0f93863b3583512ea3ca React-jsinspector: 9ca47f83b073fba6c03b1271403d9a3cb811e46c
React-perflogger: 869de521c7b7dbdbb1b0ef973a3c00f7c8046ff8 React-perflogger: f3c3ce0e1e370cf52418687d585e283daa1f00a2
React-RCTActionSheet: a0bd6037f343183655817e8ccfb517d227ce89c6 React-RCTActionSheet: 2e56a81fedeab83a4c143f5edebafd960a0486c5
React-RCTAnimation: b89077f33ada3bc4d37b4b431810a90bce548395 React-RCTAnimation: 0aa022dd8a649fd9c120e11b674a771d69a941b8
React-RCTBlob: ee093fdd17bea7fccea6b7798112d70f32e14590 React-RCTBlob: ce8f9f12e944a62845982fa0ffbb9be8c622cbe6
React-RCTImage: 6260a130d38065a6b6a0053b066b693b88bfcfb1 React-RCTImage: f7cdc51bac96c263278fa86ed20d4c9d4b5b3bd3
React-RCTLinking: 455be7c2c9b567d1e8225d28cefbf0d6c3364f85 React-RCTLinking: bdc37257824e77aab193cb26b0dab9b99a31fd51
React-RCTNetwork: a1d28da57b4d322b4dfd7c036da4e3fddc220ef1 React-RCTNetwork: 48fc780d995fc21ce459c9e081f9dd0d20aa774f
React-RCTPushNotification: 843cd5fdc428814ad09eef327f5e069e2962e5bc React-RCTPushNotification: 1ddbd932094081df005382c448bab53246e7ed21
React-RCTSettings: 2fd29ce8818a57f6016243ca3857a36dfda3f73a React-RCTSettings: 29752424f95d45c3540e98a1e6c6c22fce064679
React-RCTTest: f5e9ca6222f647dde3ca536ce5d983da1028cbb8 React-RCTTest: 3365b714e83c56defc48bf8b42643221db2bbc07
React-RCTText: ae07257137eb22d788947b76d7176418c18d7f8b React-RCTText: 5b09d89d4e07910d36e2ffd74c3a876aac00e67f
React-RCTVibration: 96e1d2916264a8787a2a409e9a3dd1ded5f2a404 React-RCTVibration: 2cfcfe6f1688d04da1ae34a5c35261dfa3bfad04
React-runtimeexecutor: 165044764bc0b6176e07f654f57d3c84567107b8 React-runtimeexecutor: 6ec1f9d6106b9f0b041a41c89abc7dd040b39437
React-TurboModuleCxx-RNW: 18bb71af41fe34c8b12a56bef60aae7ee32b0817 React-TurboModuleCxx-RNW: 18bb71af41fe34c8b12a56bef60aae7ee32b0817
React-TurboModuleCxx-WinRTPort: 8a81b72f4adac4e05a468c73e399c32a65bfcee9 React-TurboModuleCxx-WinRTPort: c95d24f313b49e94af9111d0a42a84ff64a4a8ae
ReactCommon: f4ea3975534282e48263f282d0d6deb8a7e546a1 ReactCommon: 77f4858f4785302af8b5d4d8abd93b8a6a431a88
Yoga: a55415d3b511bbb13a9689678be7e18a6cac73d2 Yoga: 3da5d46e05d2f7cd9a30618090e0d0fdee43e279
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
PODFILE CHECKSUM: cb260f8f7765c910b68f8267cbd74709f6ae6e54 PODFILE CHECKSUM: cb260f8f7765c910b68f8267cbd74709f6ae6e54

Просмотреть файл

@ -35,7 +35,7 @@
"eslint-plugin-react-hooks": "^4.0.7", "eslint-plugin-react-hooks": "^4.0.7",
"eslint-plugin-react-native": "3.8.1", "eslint-plugin-react-native": "3.8.1",
"eslint-plugin-relay": "1.7.1", "eslint-plugin-relay": "1.7.1",
"flow-bin": "^0.133.0", "flow-bin": "^0.134.0",
"flow-remove-types": "1.2.3", "flow-remove-types": "1.2.3",
"hermes-engine-darwin": "~0.5.0", "hermes-engine-darwin": "~0.5.0",
"jest": "^26.0.1", "jest": "^26.0.1",

Просмотреть файл

@ -66,4 +66,4 @@ untyped-import
untyped-type-import untyped-type-import
[version] [version]
^0.133.0 ^0.134.0

Просмотреть файл

@ -4170,10 +4170,10 @@ flatted@^2.0.0:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138"
integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==
flow-bin@^0.133.0: flow-bin@^0.134.0:
version "0.133.0" version "0.134.0"
resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.133.0.tgz#2ee44e3f5d0c0256cfe8e99d9a85e9801c281c50" resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.134.0.tgz#e98e5724f6ed5a1265cf904bbb5e4c096ea3a026"
integrity sha512-01T5g8GdhtJEn+lhAwuv5zkrMStrmkuHrY3Nn9/aS9y6waNmNgimMKlzRpFH66S0F6Ez9EqU9psz5QaRveSJIA== integrity sha512-j5aCugO3jmwDsUKc+7KReArgnL6aVjHLo6DlozKhxKYN+TaP8BY+mintPSISjSQtKZFJyvoNAc1oXA79X5WjIA==
flow-parser@0.*: flow-parser@0.*:
version "0.89.0" version "0.89.0"