Merge commit '54016faa7dfdde321023e729636a45b5bb682856' into amgleitman/0.64-merge-head
This commit is contained in:
Коммит
100b98f8ab
|
@ -80,4 +80,4 @@ untyped-import
|
|||
untyped-type-import
|
||||
|
||||
[version]
|
||||
^0.133.0
|
||||
^0.134.0
|
||||
|
|
|
@ -83,4 +83,4 @@ untyped-import
|
|||
untyped-type-import
|
||||
|
||||
[version]
|
||||
^0.133.0
|
||||
^0.134.0
|
||||
|
|
|
@ -81,4 +81,4 @@ untyped-import
|
|||
untyped-type-import
|
||||
|
||||
[version]
|
||||
^0.133.0
|
||||
^0.134.0
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
#########################
|
||||
### callinvokerholder ###
|
||||
#########################
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
# 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_STATIC_LIBRARIES = libcallinvoker libreactperfloggerjni
|
||||
|
||||
LOCAL_SHARED_LIBRARIES = libfb libfbjni
|
||||
|
||||
LOCAL_STATIC_LIBRARIES = libcallinvoker libreactperfloggerjni
|
||||
|
||||
# Name of this module.
|
||||
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
|
||||
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
|
||||
|
||||
# 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.
|
||||
#
|
||||
|
@ -128,8 +128,11 @@ $(call import-module,callinvoker)
|
|||
$(call import-module,reactperflogger)
|
||||
$(call import-module,hermes)
|
||||
$(call import-module,runtimeexecutor)
|
||||
$(call import-module,react/nativemodule/core)
|
||||
|
||||
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
|
||||
|
||||
ifeq ($(BUILD_FABRIC),true)
|
||||
|
|
|
@ -49,13 +49,13 @@ Pod::Spec.new do |s|
|
|||
ss.dependency "glog"
|
||||
|
||||
ss.subspec "core" do |sss|
|
||||
sss.source_files = "react/nativemodule/core/*.{cpp,h}",
|
||||
"react/nativemodule/core/platform/ios/*.{mm,cpp,h}"
|
||||
sss.source_files = "react/nativemodule/core/ReactCommon/**/*.{cpp,h}",
|
||||
"react/nativemodule/core/platform/ios/**/*.{mm,cpp,h}"
|
||||
end
|
||||
|
||||
ss.subspec "samples" do |sss|
|
||||
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
|
||||
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(
|
||||
name = "core",
|
||||
srcs = glob(
|
||||
["*.cpp"],
|
||||
["ReactCommon/**/*.cpp"],
|
||||
),
|
||||
header_namespace = "",
|
||||
exported_headers = subdir_glob(
|
||||
[
|
||||
("", "*.h"),
|
||||
("ReactCommon", "*.h"),
|
||||
],
|
||||
prefix = "ReactCommon",
|
||||
),
|
||||
|
@ -26,13 +26,13 @@ rn_xplat_cxx_library(
|
|||
],
|
||||
fbandroid_exported_headers = subdir_glob(
|
||||
[
|
||||
("platform/android", "*.h"),
|
||||
("platform/android/ReactCommon", "*.h"),
|
||||
],
|
||||
prefix = "ReactCommon",
|
||||
),
|
||||
fbandroid_srcs = glob(
|
||||
[
|
||||
"platform/android/**/*.cpp",
|
||||
"platform/android/ReactCommon/*.cpp",
|
||||
],
|
||||
),
|
||||
fbobjc_compiler_flags = [
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <react/renderer/core/Props.h>
|
||||
#include <react/renderer/core/RawValue.h>
|
||||
#include <react/renderer/mounting/MountingCoordinator.h>
|
||||
#include <react/renderer/mounting/ShadowViewMutation.h>
|
||||
|
||||
#include <react/renderer/mounting/Differentiator.h>
|
||||
#include <react/renderer/mounting/ShadowTreeRevision.h>
|
||||
|
@ -396,9 +397,12 @@ void LayoutAnimationKeyFrameManager::
|
|||
adjustImmediateMutationIndicesForDelayedMutations(
|
||||
SurfaceId surfaceId,
|
||||
ShadowViewMutation &mutation,
|
||||
ShadowViewMutationList *auxiliaryMutations) const {
|
||||
ConsecutiveAdjustmentMetadata &consecutiveAdjustmentMetadata,
|
||||
bool skipLastAnimation,
|
||||
bool lastAnimationOnly) const {
|
||||
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?
|
||||
if (mutatedViewIsVirtual(mutation)) {
|
||||
|
@ -412,36 +416,35 @@ void LayoutAnimationKeyFrameManager::
|
|||
"[IndexAdjustment] Calling adjustImmediateMutationIndicesForDelayedMutations for:",
|
||||
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
|
||||
// mutation.
|
||||
std::vector<ShadowViewMutation *> candidateMutations{};
|
||||
|
||||
if (auxiliaryMutations != nullptr) {
|
||||
for (auto &auxMutation : *auxiliaryMutations) {
|
||||
if (auxMutation.parentShadowView.tag != mutation.parentShadowView.tag) {
|
||||
continue;
|
||||
}
|
||||
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_) {
|
||||
for (auto inflightAnimationIt =
|
||||
inflightAnimations_.rbegin() + (skipLastAnimation ? 1 : 0);
|
||||
inflightAnimationIt != inflightAnimations_.rend();
|
||||
inflightAnimationIt++) {
|
||||
auto &inflightAnimation = *inflightAnimationIt;
|
||||
if (inflightAnimation.surfaceId != surfaceId) {
|
||||
continue;
|
||||
}
|
||||
|
@ -464,9 +467,6 @@ void LayoutAnimationKeyFrameManager::
|
|||
continue;
|
||||
}
|
||||
|
||||
if (animatedKeyFrame.type != AnimationConfigurationType::Noop) {
|
||||
continue;
|
||||
}
|
||||
if (!animatedKeyFrame.finalMutationForKeyFrame.has_value()) {
|
||||
continue;
|
||||
}
|
||||
|
@ -491,21 +491,33 @@ void LayoutAnimationKeyFrameManager::
|
|||
delayedMutation);
|
||||
candidateMutations.push_back(&delayedMutation);
|
||||
}
|
||||
|
||||
if (lastAnimationOnly) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// While the mutation keeps being affected, keep checking. We use the vector
|
||||
// so we only perform one adjustment per delayed mutation. See comments at
|
||||
// bottom of adjustDelayedMutationIndicesForMutation for further explanation.
|
||||
bool changed = true;
|
||||
int adjustedDelta = 0;
|
||||
if (isInsertMutation) {
|
||||
consecutiveAdjustmentMetadata.lastAdjustedParent =
|
||||
mutation.parentShadowView.tag;
|
||||
consecutiveAdjustmentMetadata.lastIndexOriginal = mutation.index;
|
||||
}
|
||||
while (changed) {
|
||||
changed = false;
|
||||
candidateMutations.erase(
|
||||
std::remove_if(
|
||||
candidateMutations.begin(),
|
||||
candidateMutations.end(),
|
||||
[&mutation, &changed](ShadowViewMutation *candidateMutation) {
|
||||
if (candidateMutation->index <= mutation.index) {
|
||||
[&](ShadowViewMutation *candidateMutation) {
|
||||
bool indexConflicts = candidateMutation->index <= mutation.index;
|
||||
if (indexConflicts) {
|
||||
mutation.index++;
|
||||
adjustedDelta++;
|
||||
changed = true;
|
||||
PrintMutationInstructionRelative(
|
||||
"[IndexAdjustment] adjustImmediateMutationIndicesForDelayedMutations: Adjusting mutation UPWARD",
|
||||
|
@ -517,19 +529,17 @@ void LayoutAnimationKeyFrameManager::
|
|||
}),
|
||||
candidateMutations.end());
|
||||
}
|
||||
}
|
||||
|
||||
void LayoutAnimationKeyFrameManager::
|
||||
adjustLastAnimationDelayedMutationIndicesForMutation(
|
||||
SurfaceId surfaceId,
|
||||
ShadowViewMutation const &mutation) const {
|
||||
adjustDelayedMutationIndicesForMutation(surfaceId, mutation, true);
|
||||
if (isInsertMutation) {
|
||||
consecutiveAdjustmentMetadata.lastAdjustedDelta = adjustedDelta;
|
||||
} else {
|
||||
consecutiveAdjustmentMetadata.lastAdjustedParent = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void LayoutAnimationKeyFrameManager::adjustDelayedMutationIndicesForMutation(
|
||||
SurfaceId surfaceId,
|
||||
ShadowViewMutation const &mutation,
|
||||
bool lastAnimationOnly) const {
|
||||
bool skipLastAnimation) const {
|
||||
bool isRemoveMutation = mutation.type == ShadowViewMutation::Type::Remove;
|
||||
bool isInsertMutation = mutation.type == ShadowViewMutation::Type::Insert;
|
||||
assert(isRemoveMutation || isInsertMutation);
|
||||
|
@ -545,7 +555,8 @@ void LayoutAnimationKeyFrameManager::adjustDelayedMutationIndicesForMutation(
|
|||
// mutation.
|
||||
std::vector<ShadowViewMutation *> candidateMutations{};
|
||||
|
||||
for (auto inflightAnimationIt = inflightAnimations_.rbegin();
|
||||
for (auto inflightAnimationIt =
|
||||
inflightAnimations_.rbegin() + (skipLastAnimation ? 1 : 0);
|
||||
inflightAnimationIt != inflightAnimations_.rend();
|
||||
inflightAnimationIt++) {
|
||||
auto &inflightAnimation = *inflightAnimationIt;
|
||||
|
@ -572,9 +583,6 @@ void LayoutAnimationKeyFrameManager::adjustDelayedMutationIndicesForMutation(
|
|||
continue;
|
||||
}
|
||||
|
||||
if (animatedKeyFrame.type != AnimationConfigurationType::Noop) {
|
||||
continue;
|
||||
}
|
||||
if (!animatedKeyFrame.finalMutationForKeyFrame.has_value()) {
|
||||
continue;
|
||||
}
|
||||
|
@ -587,19 +595,19 @@ void LayoutAnimationKeyFrameManager::adjustDelayedMutationIndicesForMutation(
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!mutatedViewIsVirtual(*animatedKeyFrame.finalMutationForKeyFrame) &&
|
||||
finalAnimationMutation.type == ShadowViewMutation::Type::Remove) {
|
||||
PrintMutationInstructionRelative(
|
||||
"[IndexAdjustment] adjustDelayedMutationIndicesForMutation: CANDIDATE:",
|
||||
mutation,
|
||||
*animatedKeyFrame.finalMutationForKeyFrame);
|
||||
candidateMutations.push_back(
|
||||
animatedKeyFrame.finalMutationForKeyFrame.get_pointer());
|
||||
if (finalAnimationMutation.type != ShadowViewMutation::Type::Remove) {
|
||||
continue;
|
||||
}
|
||||
if (mutatedViewIsVirtual(*animatedKeyFrame.finalMutationForKeyFrame)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastAnimationOnly) {
|
||||
break;
|
||||
PrintMutationInstructionRelative(
|
||||
"[IndexAdjustment] adjustDelayedMutationIndicesForMutation: CANDIDATE:",
|
||||
mutation,
|
||||
*animatedKeyFrame.finalMutationForKeyFrame);
|
||||
candidateMutations.push_back(
|
||||
animatedKeyFrame.finalMutationForKeyFrame.get_pointer());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -685,18 +693,6 @@ LayoutAnimationKeyFrameManager::getAndEraseConflictingAnimations(
|
|||
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 ||
|
||||
((mutation.type == ShadowViewMutation::Type::Delete ||
|
||||
mutation.type == ShadowViewMutation::Type::Create) &&
|
||||
|
@ -704,20 +700,6 @@ LayoutAnimationKeyFrameManager::getAndEraseConflictingAnimations(
|
|||
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
|
||||
// animation, or deleting the parent of a tag under animation, or
|
||||
// reparenting.
|
||||
|
@ -735,7 +717,9 @@ LayoutAnimationKeyFrameManager::getAndEraseConflictingAnimations(
|
|||
|
||||
animatedKeyFrame.invalidated = true;
|
||||
|
||||
if (shouldExecuteFinalMutation) {
|
||||
if (animatedKeyFrame.finalMutationForKeyFrame.has_value() &&
|
||||
!mutatedViewIsVirtual(
|
||||
*animatedKeyFrame.finalMutationForKeyFrame)) {
|
||||
conflictingAnimations.push_back(std::make_tuple(
|
||||
animatedKeyFrame, *mutationConfig, &inflightAnimation));
|
||||
}
|
||||
|
@ -748,7 +732,7 @@ LayoutAnimationKeyFrameManager::getAndEraseConflictingAnimations(
|
|||
*animatedKeyFrame.finalMutationForKeyFrame);
|
||||
} else {
|
||||
PrintMutationInstruction(
|
||||
"Found mutation that conflicts with existing in-flight animation:",
|
||||
"Found mutation that conflicts with existing in-flight animation (no final mutation):",
|
||||
mutation);
|
||||
}
|
||||
#endif
|
||||
|
@ -756,13 +740,6 @@ LayoutAnimationKeyFrameManager::getAndEraseConflictingAnimations(
|
|||
// Delete from existing animation
|
||||
it = inflightAnimation.keyFrames.erase(it);
|
||||
} else {
|
||||
//#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
|
||||
// if (hasFinalMutation) {
|
||||
// PrintMutationInstructionRelative("getAndEraseConflictingAnimations,
|
||||
// NOT erasing non-conflicting mutation of ", mutation,
|
||||
// *animatedKeyFrame.finalMutationForKeyFrame);
|
||||
// }
|
||||
//#endif
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
@ -844,7 +821,8 @@ LayoutAnimationKeyFrameManager::pullTransaction(
|
|||
if (keyframe.invalidated) {
|
||||
continue;
|
||||
}
|
||||
if (keyframe.finalMutationForKeyFrame) {
|
||||
if (keyframe.finalMutationForKeyFrame &&
|
||||
!mutatedViewIsVirtual(*keyframe.finalMutationForKeyFrame)) {
|
||||
std::string msg = "Animation " + std::to_string(i) + " keyframe " +
|
||||
std::to_string(j) + ": Final Animation";
|
||||
PrintMutationInstruction(msg, *keyframe.finalMutationForKeyFrame);
|
||||
|
@ -899,15 +877,23 @@ LayoutAnimationKeyFrameManager::pullTransaction(
|
|||
// being moves on the Differ level, since we know that there? We could use
|
||||
// TinyMap here, but it's not exposed by Differentiator (yet).
|
||||
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::vector<Tag> reparentedTags;
|
||||
for (const auto &mutation : mutations) {
|
||||
if (mutation.type == ShadowViewMutation::Type::Insert) {
|
||||
insertedTags.push_back(mutation.newChildShadowView.tag);
|
||||
}
|
||||
if (mutation.type == ShadowViewMutation::Type::Delete) {
|
||||
deletedTags.push_back(mutation.oldChildShadowView.tag);
|
||||
}
|
||||
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
|
||||
// for now we detect reparenting and prevent the corresponding
|
||||
// Delete/Create instructions from being animated.
|
||||
bool isReparented =
|
||||
(mutation.type == ShadowViewMutation::Delete &&
|
||||
std::find(
|
||||
createdTags.begin(),
|
||||
createdTags.end(),
|
||||
mutation.oldChildShadowView.tag) != createdTags.end()) ||
|
||||
(mutation.type == ShadowViewMutation::Create &&
|
||||
std::find(
|
||||
reparentedTags.begin(),
|
||||
reparentedTags.end(),
|
||||
mutation.newChildShadowView.tag) != reparentedTags.end());
|
||||
bool isReparented = std::find(
|
||||
reparentedTags.begin(),
|
||||
reparentedTags.end(),
|
||||
baselineShadowView.tag) != reparentedTags.end();
|
||||
|
||||
if (isRemoveReinserted) {
|
||||
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
|
||||
// an update (move) animation.
|
||||
bool wasInsertedTagRemoved = false;
|
||||
|
@ -1205,30 +1180,31 @@ LayoutAnimationKeyFrameManager::pullTransaction(
|
|||
}
|
||||
|
||||
#ifdef RN_SHADOW_TREE_INTROSPECTION
|
||||
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
|
||||
{
|
||||
std::stringstream ss(getDebugDescription(immediateMutations, {}));
|
||||
std::string to;
|
||||
while (std::getline(ss, to, '\n')) {
|
||||
LOG(ERROR)
|
||||
<< "LayoutAnimationKeyFrameManager.cpp: got IMMEDIATE list: Line: "
|
||||
<< to;
|
||||
int idx = 0;
|
||||
for (auto &mutation : immediateMutations) {
|
||||
PrintMutationInstruction(
|
||||
std::string("IMMEDIATE list: ") + std::to_string(idx) + "/" +
|
||||
std::to_string(immediateMutations.size()),
|
||||
mutation);
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int idx = 0;
|
||||
for (const auto &keyframe : keyFramesToAnimate) {
|
||||
if (keyframe.finalMutationForKeyFrame) {
|
||||
std::stringstream ss(
|
||||
getDebugDescription(*keyframe.finalMutationForKeyFrame, {}));
|
||||
std::string to;
|
||||
while (std::getline(ss, to, '\n')) {
|
||||
LOG(ERROR)
|
||||
<< "LayoutAnimationKeyFrameManager.cpp: got FINAL list: Line: "
|
||||
<< to;
|
||||
}
|
||||
if (keyframe.finalMutationForKeyFrame.has_value()) {
|
||||
PrintMutationInstruction(
|
||||
std::string("FINAL list: ") + std::to_string(idx) + "/" +
|
||||
std::to_string(keyFramesToAnimate.size()),
|
||||
*keyframe.finalMutationForKeyFrame);
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
auto finalConflictingMutations = ShadowViewMutationList{};
|
||||
|
@ -1247,59 +1223,121 @@ LayoutAnimationKeyFrameManager::pullTransaction(
|
|||
finalConflictingMutations.end(),
|
||||
&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(
|
||||
immediateMutations.begin(),
|
||||
immediateMutations.end(),
|
||||
&shouldFirstComeBeforeSecondRemovesOnly);
|
||||
for (auto &mutation : immediateMutations) {
|
||||
if (mutation.type == ShadowViewMutation::Type::Remove) {
|
||||
adjustImmediateMutationIndicesForDelayedMutations(
|
||||
surfaceId, mutation);
|
||||
adjustDelayedMutationIndicesForMutation(surfaceId, mutation);
|
||||
}
|
||||
}
|
||||
|
||||
animation.keyFrames = keyFramesToAnimate;
|
||||
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
|
||||
// operations that smoothly transition into another animation will be
|
||||
// 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
|
||||
// between this list of conflicting animations and the batch we're about
|
||||
// to execute.
|
||||
mutations = ShadowViewMutationList{};
|
||||
for (auto &mutation : finalConflictingMutations) {
|
||||
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(),
|
||||
finalConflictingMutations.insert(
|
||||
finalConflictingMutations.end(),
|
||||
immediateMutations.begin(),
|
||||
immediateMutations.end());
|
||||
mutations = finalConflictingMutations;
|
||||
} /* 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"
|
||||
// operations from all ongoing, conflicting animations.
|
||||
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
|
||||
LOG(ERROR) << "No Animation: Queue up final conflicting animations";
|
||||
#endif
|
||||
ShadowViewMutationList finalMutationsForConflictingAnimations{};
|
||||
for (auto &conflictingKeyframeTuple : conflictingAnimations) {
|
||||
auto &keyFrame = std::get<0>(conflictingKeyframeTuple);
|
||||
if (keyFrame.finalMutationForKeyFrame.hasValue()) {
|
||||
PrintMutationInstruction(
|
||||
"No Animation: Queueing final mutation instruction",
|
||||
*keyFrame.finalMutationForKeyFrame);
|
||||
finalMutationsForConflictingAnimations.push_back(
|
||||
*keyFrame.finalMutationForKeyFrame);
|
||||
}
|
||||
|
@ -1373,6 +1375,45 @@ LayoutAnimationKeyFrameManager::pullTransaction(
|
|||
finalMutationsForConflictingAnimations.end(),
|
||||
&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
|
||||
// conflicting mutations happen before any other mutations
|
||||
finalMutationsForConflictingAnimations.insert(
|
||||
|
@ -1392,13 +1433,6 @@ LayoutAnimationKeyFrameManager::pullTransaction(
|
|||
ShadowViewMutationList mutationsForAnimation{};
|
||||
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
|
||||
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
|
||||
LOG(ERROR)
|
||||
|
@ -1431,7 +1465,8 @@ LayoutAnimationKeyFrameManager::pullTransaction(
|
|||
if (keyframe.invalidated) {
|
||||
continue;
|
||||
}
|
||||
if (keyframe.finalMutationForKeyFrame) {
|
||||
if (keyframe.finalMutationForKeyFrame &&
|
||||
!mutatedViewIsVirtual(*keyframe.finalMutationForKeyFrame)) {
|
||||
std::string msg = "Animation " + std::to_string(i) + " keyframe " +
|
||||
std::to_string(j) + ": Final Animation";
|
||||
PrintMutationInstruction(msg, *keyframe.finalMutationForKeyFrame);
|
||||
|
|
|
@ -110,6 +110,12 @@ struct AnimationKeyFrame {
|
|||
bool invalidated{false};
|
||||
};
|
||||
|
||||
struct ConsecutiveAdjustmentMetadata {
|
||||
Tag lastAdjustedParent{-1};
|
||||
int lastAdjustedDelta{0};
|
||||
int lastIndexOriginal{0};
|
||||
};
|
||||
|
||||
class LayoutAnimationCallbackWrapper {
|
||||
public:
|
||||
LayoutAnimationCallbackWrapper(jsi::Function &&callback)
|
||||
|
@ -212,16 +218,14 @@ class LayoutAnimationKeyFrameManager : public UIManagerAnimationDelegate,
|
|||
void adjustImmediateMutationIndicesForDelayedMutations(
|
||||
SurfaceId surfaceId,
|
||||
ShadowViewMutation &mutation,
|
||||
ShadowViewMutationList *auxiliaryMutations = nullptr) const;
|
||||
ConsecutiveAdjustmentMetadata &consecutiveAdjustmentMetadata,
|
||||
bool skipLastAnimation = false,
|
||||
bool lastAnimationOnly = false) const;
|
||||
|
||||
void adjustDelayedMutationIndicesForMutation(
|
||||
SurfaceId surfaceId,
|
||||
ShadowViewMutation const &mutation,
|
||||
bool lastAnimationOnly = false) const;
|
||||
|
||||
void adjustLastAnimationDelayedMutationIndicesForMutation(
|
||||
SurfaceId surfaceId,
|
||||
ShadowViewMutation const &mutation) const;
|
||||
bool skipLastAnimation = false) const;
|
||||
|
||||
std::vector<std::tuple<AnimationKeyFrame, AnimationConfig, LayoutAnimation *>>
|
||||
getAndEraseConflictingAnimations(
|
||||
|
|
|
@ -38,12 +38,17 @@ static jsi::Value linesMeasurementsPayload(
|
|||
|
||||
void ParagraphEventEmitter::onTextLayout(
|
||||
LinesMeasurements const &linesMeasurements) const {
|
||||
dispatchEvent(
|
||||
"textLayout",
|
||||
[linesMeasurements](jsi::Runtime &runtime) {
|
||||
return linesMeasurementsPayload(runtime, linesMeasurements);
|
||||
},
|
||||
EventPriority::AsynchronousBatched);
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(linesMeasurementsMutex_);
|
||||
if (linesMeasurementsMetrics_ == linesMeasurements) {
|
||||
return;
|
||||
}
|
||||
linesMeasurementsMetrics_ = linesMeasurements;
|
||||
}
|
||||
|
||||
dispatchEvent("textLayout", [linesMeasurements](jsi::Runtime &runtime) {
|
||||
return linesMeasurementsPayload(runtime, linesMeasurements);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
|
|
|
@ -18,6 +18,10 @@ class ParagraphEventEmitter : public ViewEventEmitter {
|
|||
using ViewEventEmitter::ViewEventEmitter;
|
||||
|
||||
void onTextLayout(LinesMeasurements const &linesMeasurements) const;
|
||||
|
||||
private:
|
||||
mutable std::mutex linesMeasurementsMutex_;
|
||||
mutable LinesMeasurements linesMeasurementsMetrics_;
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
|
|
|
@ -164,18 +164,6 @@ void ParagraphShadowNode::layout(LayoutContext layoutContext) {
|
|||
|
||||
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(
|
||||
AttributedStringBox{content.attributedString},
|
||||
content.paragraphAttributes,
|
||||
|
@ -191,6 +179,11 @@ void ParagraphShadowNode::layout(LayoutContext layoutContext) {
|
|||
}
|
||||
#endif
|
||||
|
||||
if (content.attachments.empty()) {
|
||||
// No attachments to layout.
|
||||
return;
|
||||
}
|
||||
|
||||
// Iterating on attachments, we clone shadow nodes and moving
|
||||
// `paragraphShadowNode` that represents clones of `this` object.
|
||||
auto paragraphShadowNode = static_cast<ParagraphShadowNode *>(this);
|
||||
|
|
|
@ -1076,11 +1076,7 @@ static void calculateShadowViewMutationsV2(
|
|||
for (auto &oldFlattenedNode : oldFlattenedNodes) {
|
||||
auto unvisitedOldChildPairIt = unvisitedOldChildPairs.find(
|
||||
oldFlattenedNode.shadowView.tag);
|
||||
if (unvisitedOldChildPairIt != unvisitedOldChildPairs.end()) {
|
||||
// Node unvisited - delete it entirely
|
||||
deleteMutations.push_back(ShadowViewMutation::DeleteMutation(
|
||||
oldFlattenedNode.shadowView));
|
||||
} else {
|
||||
if (unvisitedOldChildPairIt == unvisitedOldChildPairs.end()) {
|
||||
// Node was visited - make sure to remove it from
|
||||
// "newRemainingPairs" map
|
||||
auto newRemainingIt =
|
||||
|
@ -1202,11 +1198,7 @@ static void calculateShadowViewMutationsV2(
|
|||
for (auto &oldFlattenedNode : oldFlattenedNodes) {
|
||||
auto unvisitedOldChildPairIt = unvisitedOldChildPairs.find(
|
||||
oldFlattenedNode.shadowView.tag);
|
||||
if (unvisitedOldChildPairIt != unvisitedOldChildPairs.end()) {
|
||||
// Node unvisited - delete it entirely
|
||||
deleteMutations.push_back(ShadowViewMutation::DeleteMutation(
|
||||
oldFlattenedNode.shadowView));
|
||||
} else {
|
||||
if (unvisitedOldChildPairIt == unvisitedOldChildPairs.end()) {
|
||||
// Node was visited - make sure to remove it from
|
||||
// "newRemainingPairs" map
|
||||
auto newRemainingIt =
|
||||
|
|
|
@ -83,13 +83,15 @@ void StubViewTree::mutate(
|
|||
STUB_VIEW_ASSERT(registry.find(parentTag) != registry.end());
|
||||
auto parentStubView = registry[parentTag];
|
||||
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());
|
||||
auto childStubView = registry[childTag];
|
||||
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.begin() + mutation.index, childStubView);
|
||||
break;
|
||||
|
@ -106,6 +108,7 @@ void StubViewTree::mutate(
|
|||
<< parentTag << " at index " << mutation.index << " with "
|
||||
<< parentStubView->children.size() << " children";
|
||||
});
|
||||
STUB_VIEW_ASSERT(parentStubView->children.size() > mutation.index);
|
||||
STUB_VIEW_ASSERT(registry.find(childTag) != registry.end());
|
||||
auto childStubView = registry[childTag];
|
||||
bool childIsCorrect =
|
||||
|
@ -130,8 +133,15 @@ void StubViewTree::mutate(
|
|||
STUB_VIEW_LOG({
|
||||
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(
|
||||
mutation.newChildShadowView.tag == mutation.oldChildShadowView.tag);
|
||||
mutation.newChildShadowView.tag ==
|
||||
mutation.oldChildShadowView.tag ||
|
||||
mutation.oldChildShadowView.tag == 0);
|
||||
|
||||
STUB_VIEW_ASSERT(
|
||||
registry.find(mutation.newChildShadowView.tag) != registry.end());
|
||||
auto stubView = registry[mutation.newChildShadowView.tag];
|
||||
|
|
|
@ -8,5 +8,24 @@
|
|||
#include "TextMeasureCache.h"
|
||||
|
||||
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
|
||||
|
|
|
@ -23,6 +23,8 @@ struct LineMeasurement {
|
|||
Float capHeight;
|
||||
Float ascender;
|
||||
Float xHeight;
|
||||
|
||||
bool operator==(LineMeasurement const &rhs) const;
|
||||
};
|
||||
|
||||
using LinesMeasurements = std::vector<LineMeasurement>;
|
||||
|
|
|
@ -123,7 +123,7 @@
|
|||
"ws": "^6.1.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"flow-bin": "^0.133.0",
|
||||
"flow-bin": "^0.134.0",
|
||||
"react": "16.13.1"
|
||||
},
|
||||
"detox": {
|
||||
|
|
|
@ -510,8 +510,8 @@ SPEC CHECKSUMS:
|
|||
CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845
|
||||
CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f
|
||||
DoubleConversion: 2b45d0f8e156a5b02354c8a4062de64d41ccb4e0
|
||||
FBLazyVector: 6840df244b2930eadc86dfddd63dd586de8fbf4b
|
||||
FBReactNativeSpec: 6a5b272a87d8fba0a0267169a9c69104a33f4104
|
||||
FBLazyVector: a2e74b28704250f5c2840b8ac0c36a550fc58c5c
|
||||
FBReactNativeSpec: f32ba61faf46d74f93ee06325baab8f1f160cd4d
|
||||
Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365
|
||||
Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41
|
||||
Flipper-Folly: c12092ea368353b58e992843a990a3225d4533c3
|
||||
|
@ -522,33 +522,33 @@ SPEC CHECKSUMS:
|
|||
glog: 789873d01e4b200777d0a09bc23d548446758699
|
||||
OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355
|
||||
RCT-Folly: 55d0039b24e192081ec0b2257f7bd9f42e382fb7
|
||||
RCTRequired: 8aab7fd83973da16ad4a7c320ab60d95daaf3a49
|
||||
RCTTypeSafety: 1b9fcfa91c95a819c8ee11b2d78792a1a0c9f008
|
||||
React: 0d0bbc598d4e4a42c2d8f501e2d85bf68f4b4c58
|
||||
React-callinvoker: 7171dcdb2310bc9843acfd9e9d1ad4432f069343
|
||||
React-Core: f9261d49de3292529f426b0337589cf85cbd2be5
|
||||
React-CoreModules: 6cd34c4feb240e2243a2b766ac42b4922a43f272
|
||||
React-cxxreact: 1d94eae472a7d96512c9616b79755f17b7d9e60d
|
||||
React-jsi: 738aad53cef29cda532eb60393636882b048aa63
|
||||
React-jsiexecutor: 4f307d9cf526c904c6a29a492ee0d0a56a3955ac
|
||||
React-jsinspector: 9a11ad30cee910a8f9af0f93863b3583512ea3ca
|
||||
React-perflogger: 869de521c7b7dbdbb1b0ef973a3c00f7c8046ff8
|
||||
React-RCTActionSheet: a0bd6037f343183655817e8ccfb517d227ce89c6
|
||||
React-RCTAnimation: b89077f33ada3bc4d37b4b431810a90bce548395
|
||||
React-RCTBlob: ee093fdd17bea7fccea6b7798112d70f32e14590
|
||||
React-RCTImage: 6260a130d38065a6b6a0053b066b693b88bfcfb1
|
||||
React-RCTLinking: 455be7c2c9b567d1e8225d28cefbf0d6c3364f85
|
||||
React-RCTNetwork: a1d28da57b4d322b4dfd7c036da4e3fddc220ef1
|
||||
React-RCTPushNotification: 843cd5fdc428814ad09eef327f5e069e2962e5bc
|
||||
React-RCTSettings: 2fd29ce8818a57f6016243ca3857a36dfda3f73a
|
||||
React-RCTTest: f5e9ca6222f647dde3ca536ce5d983da1028cbb8
|
||||
React-RCTText: ae07257137eb22d788947b76d7176418c18d7f8b
|
||||
React-RCTVibration: 96e1d2916264a8787a2a409e9a3dd1ded5f2a404
|
||||
React-runtimeexecutor: 165044764bc0b6176e07f654f57d3c84567107b8
|
||||
RCTRequired: f69bc029b4e19411dd37c82521ee7f40451c39bd
|
||||
RCTTypeSafety: eac4bf166ab078acc91d836bf91c19227a52b5cb
|
||||
React: e3ead01467fceb6371308544f0e94f35052230e7
|
||||
React-callinvoker: 14f7c592814aa4ed38de8ee15c87fb3284affcf0
|
||||
React-Core: 56999fc712186d46fcd3b82563dbc1cdcfbbab47
|
||||
React-CoreModules: 4f16f6042a515d575c6a8e745345403527c6b292
|
||||
React-cxxreact: efd175939ed4f9ed26c39ae528151841e785187c
|
||||
React-jsi: 52b19336123975495cc71d6f8881f599ad5fc301
|
||||
React-jsiexecutor: 75e0be97411644e306e86ff043bc35eb9bf57f5d
|
||||
React-jsinspector: 9ca47f83b073fba6c03b1271403d9a3cb811e46c
|
||||
React-perflogger: f3c3ce0e1e370cf52418687d585e283daa1f00a2
|
||||
React-RCTActionSheet: 2e56a81fedeab83a4c143f5edebafd960a0486c5
|
||||
React-RCTAnimation: 0aa022dd8a649fd9c120e11b674a771d69a941b8
|
||||
React-RCTBlob: ce8f9f12e944a62845982fa0ffbb9be8c622cbe6
|
||||
React-RCTImage: f7cdc51bac96c263278fa86ed20d4c9d4b5b3bd3
|
||||
React-RCTLinking: bdc37257824e77aab193cb26b0dab9b99a31fd51
|
||||
React-RCTNetwork: 48fc780d995fc21ce459c9e081f9dd0d20aa774f
|
||||
React-RCTPushNotification: 1ddbd932094081df005382c448bab53246e7ed21
|
||||
React-RCTSettings: 29752424f95d45c3540e98a1e6c6c22fce064679
|
||||
React-RCTTest: 3365b714e83c56defc48bf8b42643221db2bbc07
|
||||
React-RCTText: 5b09d89d4e07910d36e2ffd74c3a876aac00e67f
|
||||
React-RCTVibration: 2cfcfe6f1688d04da1ae34a5c35261dfa3bfad04
|
||||
React-runtimeexecutor: 6ec1f9d6106b9f0b041a41c89abc7dd040b39437
|
||||
React-TurboModuleCxx-RNW: 18bb71af41fe34c8b12a56bef60aae7ee32b0817
|
||||
React-TurboModuleCxx-WinRTPort: 8a81b72f4adac4e05a468c73e399c32a65bfcee9
|
||||
ReactCommon: f4ea3975534282e48263f282d0d6deb8a7e546a1
|
||||
Yoga: a55415d3b511bbb13a9689678be7e18a6cac73d2
|
||||
React-TurboModuleCxx-WinRTPort: c95d24f313b49e94af9111d0a42a84ff64a4a8ae
|
||||
ReactCommon: 77f4858f4785302af8b5d4d8abd93b8a6a431a88
|
||||
Yoga: 3da5d46e05d2f7cd9a30618090e0d0fdee43e279
|
||||
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
|
||||
|
||||
PODFILE CHECKSUM: cb260f8f7765c910b68f8267cbd74709f6ae6e54
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
"eslint-plugin-react-hooks": "^4.0.7",
|
||||
"eslint-plugin-react-native": "3.8.1",
|
||||
"eslint-plugin-relay": "1.7.1",
|
||||
"flow-bin": "^0.133.0",
|
||||
"flow-bin": "^0.134.0",
|
||||
"flow-remove-types": "1.2.3",
|
||||
"hermes-engine-darwin": "~0.5.0",
|
||||
"jest": "^26.0.1",
|
||||
|
|
|
@ -66,4 +66,4 @@ untyped-import
|
|||
untyped-type-import
|
||||
|
||||
[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"
|
||||
integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==
|
||||
|
||||
flow-bin@^0.133.0:
|
||||
version "0.133.0"
|
||||
resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.133.0.tgz#2ee44e3f5d0c0256cfe8e99d9a85e9801c281c50"
|
||||
integrity sha512-01T5g8GdhtJEn+lhAwuv5zkrMStrmkuHrY3Nn9/aS9y6waNmNgimMKlzRpFH66S0F6Ez9EqU9psz5QaRveSJIA==
|
||||
flow-bin@^0.134.0:
|
||||
version "0.134.0"
|
||||
resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.134.0.tgz#e98e5724f6ed5a1265cf904bbb5e4c096ea3a026"
|
||||
integrity sha512-j5aCugO3jmwDsUKc+7KReArgnL6aVjHLo6DlozKhxKYN+TaP8BY+mintPSISjSQtKZFJyvoNAc1oXA79X5WjIA==
|
||||
|
||||
flow-parser@0.*:
|
||||
version "0.89.0"
|
||||
|
|
Загрузка…
Ссылка в новой задаче