Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<d824f6746b2cc7d4560164c04d123988>>
* @generated SignedSource<<eb0bafceba60cb439a4be3d68b890725>>
*/

/**
Expand Down Expand Up @@ -390,6 +390,12 @@ public object ReactNativeFeatureFlags {
@JvmStatic
public fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean = accessor.fixMappingOfEventPrioritiesBetweenFabricAndReact()

/**
* Re-measures text and re-sends padding and overflow insets to mounted views when the pixel density changes, so text and padded views do not keep sizes from the old density.
*/
@JvmStatic
public fun fixTextLayoutOnPixelDensityChange(): Boolean = accessor.fixTextLayoutOnPixelDensityChange()

/**
* Fix flex basis computation to not apply FitContent constraint in the main axis for non-measure container nodes, preventing unnecessary re-measurement in scroll containers.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<ea771505a9f0b070dd8b2c4b50411c6e>>
* @generated SignedSource<<0107593110db613063b6f4ceb50d8e58>>
*/

/**
Expand Down Expand Up @@ -80,6 +80,7 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
private var enableVirtualViewContainerStateExperimentalCache: Boolean? = null
private var fixBorderlessRippleAndroidCache: Boolean? = null
private var fixMappingOfEventPrioritiesBetweenFabricAndReactCache: Boolean? = null
private var fixTextLayoutOnPixelDensityChangeCache: Boolean? = null
private var fixYogaFlexBasisFitContentInMainAxisCache: Boolean? = null
private var fuseboxAssertSingleHostStateCache: Boolean? = null
private var fuseboxEnabledReleaseCache: Boolean? = null
Expand Down Expand Up @@ -653,6 +654,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
return cached
}

override fun fixTextLayoutOnPixelDensityChange(): Boolean {
var cached = fixTextLayoutOnPixelDensityChangeCache
if (cached == null) {
cached = ReactNativeFeatureFlagsCxxInterop.fixTextLayoutOnPixelDensityChange()
fixTextLayoutOnPixelDensityChangeCache = cached
}
return cached
}

override fun fixYogaFlexBasisFitContentInMainAxis(): Boolean {
var cached = fixYogaFlexBasisFitContentInMainAxisCache
if (cached == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<51b7baf7b3c2758ec619c77cb4fa637d>>
* @generated SignedSource<<fa0374808e3cbe7122ca993780c0b627>>
*/

/**
Expand Down Expand Up @@ -148,6 +148,8 @@ public object ReactNativeFeatureFlagsCxxInterop {

@DoNotStrip @JvmStatic public external fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean

@DoNotStrip @JvmStatic public external fun fixTextLayoutOnPixelDensityChange(): Boolean

@DoNotStrip @JvmStatic public external fun fixYogaFlexBasisFitContentInMainAxis(): Boolean

@DoNotStrip @JvmStatic public external fun fuseboxAssertSingleHostState(): Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<e8540d339cda9300ee0eac6e2ce316d2>>
* @generated SignedSource<<768077a22c110aa98ab02bc96eec695b>>
*/

/**
Expand Down Expand Up @@ -143,6 +143,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi

override fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean = false

override fun fixTextLayoutOnPixelDensityChange(): Boolean = false

override fun fixYogaFlexBasisFitContentInMainAxis(): Boolean = false

override fun fuseboxAssertSingleHostState(): Boolean = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<3e94c46a8a6fda2a4c0378e326291d73>>
* @generated SignedSource<<86ebc7307e7ebe2023e909a868ed3117>>
*/

/**
Expand Down Expand Up @@ -84,6 +84,7 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
private var enableVirtualViewContainerStateExperimentalCache: Boolean? = null
private var fixBorderlessRippleAndroidCache: Boolean? = null
private var fixMappingOfEventPrioritiesBetweenFabricAndReactCache: Boolean? = null
private var fixTextLayoutOnPixelDensityChangeCache: Boolean? = null
private var fixYogaFlexBasisFitContentInMainAxisCache: Boolean? = null
private var fuseboxAssertSingleHostStateCache: Boolean? = null
private var fuseboxEnabledReleaseCache: Boolean? = null
Expand Down Expand Up @@ -717,6 +718,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
return cached
}

override fun fixTextLayoutOnPixelDensityChange(): Boolean {
var cached = fixTextLayoutOnPixelDensityChangeCache
if (cached == null) {
cached = currentProvider.fixTextLayoutOnPixelDensityChange()
accessedFeatureFlags.add("fixTextLayoutOnPixelDensityChange")
fixTextLayoutOnPixelDensityChangeCache = cached
}
return cached
}

override fun fixYogaFlexBasisFitContentInMainAxis(): Boolean {
var cached = fixYogaFlexBasisFitContentInMainAxisCache
if (cached == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<0c7d62679814835a3ef86a63174c7f7f>>
* @generated SignedSource<<c83fba10dc6f7d596e3bcd9725c64e6e>>
*/

/**
Expand Down Expand Up @@ -143,6 +143,8 @@ public interface ReactNativeFeatureFlagsProvider {

@DoNotStrip public fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean

@DoNotStrip public fun fixTextLayoutOnPixelDensityChange(): Boolean

@DoNotStrip public fun fixYogaFlexBasisFitContentInMainAxis(): Boolean

@DoNotStrip public fun fuseboxAssertSingleHostState(): Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,8 @@ void FabricMountingManager::executeMount(

bool maintainMutationOrder =
ReactNativeFeatureFlags::disableMountItemReorderingAndroid();
bool updateViewsOnDensityChange =
ReactNativeFeatureFlags::fixTextLayoutOnPixelDensityChange();

auto revisionNumber = telemetry.getRevisionNumber();

Expand Down Expand Up @@ -688,12 +690,19 @@ void FabricMountingManager::executeMount(
CppMountItem::UpdateStateMountItem(newChildShadowView));
}

bool pointScaleChanged = updateViewsOnDensityChange &&
oldChildShadowView.layoutMetrics.pointScaleFactor !=
newChildShadowView.layoutMetrics.pointScaleFactor;

// Padding: padding mountItems must be executed before layout props
// are updated in the view. This is necessary to ensure that events
// (resulting from layout changes) are dispatched with the correct
// padding information.
if (oldChildShadowView.layoutMetrics.contentInsets !=
newChildShadowView.layoutMetrics.contentInsets) {
newChildShadowView.layoutMetrics.contentInsets ||
(pointScaleChanged &&
newChildShadowView.layoutMetrics.contentInsets !=
EdgeInsets::ZERO)) {
(maintainMutationOrder ? cppCommonMountItems
: cppUpdatePaddingMountItems)
.push_back(
Expand All @@ -713,8 +722,11 @@ void FabricMountingManager::executeMount(
// children of the current view. The layout of current view may not
// change, and we separate this part from layout mount items to not
// pack too much data there.
if ((oldChildShadowView.layoutMetrics.overflowInset !=
newChildShadowView.layoutMetrics.overflowInset)) {
if (oldChildShadowView.layoutMetrics.overflowInset !=
newChildShadowView.layoutMetrics.overflowInset ||
(pointScaleChanged &&
newChildShadowView.layoutMetrics.overflowInset !=
EdgeInsets::ZERO)) {
(maintainMutationOrder ? cppCommonMountItems
: cppUpdateOverflowInsetMountItems)
.push_back(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,60 @@

#include "FabricMountingManagerTestHelper.h"

#include <react/featureflags/ReactNativeFeatureFlags.h>
#include <react/featureflags/ReactNativeFeatureFlagsDefaults.h>
#include <react/renderer/animationbackend/AnimatedProps.h>
#include <react/renderer/components/view/ViewComponentDescriptor.h>
#include <react/renderer/components/view/ViewProps.h>
#include <react/renderer/core/ComponentDescriptor.h>
#include <react/renderer/core/PropsParserContext.h>
#include <react/renderer/core/RawProps.h>
#include <react/renderer/mounting/ShadowView.h>

namespace facebook::react {

static LayoutConstraints makeLayoutConstraints(
jfloat widthDp,
jfloat heightDp) {
Size size{.width = widthDp, .height = heightDp};
return LayoutConstraints{
.minimumSize = size,
.maximumSize = size,
.layoutDirection = LayoutDirection::LeftToRight};
}

FabricMountingManagerTestHelper::FabricMountingManagerTestHelper(
jni::alias_ref<JFabricUIManager::javaobject> jFabricUIManager)
: javaUIManager_(jni::make_global(jFabricUIManager)) {
mountingManager_ = std::make_shared<FabricMountingManager>(javaUIManager_);

contextContainer_ = std::make_shared<ContextContainer>();
auto params = ComponentDescriptorParameters{
.eventDispatcher = EventDispatcher::Shared{},
.contextContainer = std::make_shared<ContextContainer>(),
.contextContainer = contextContainer_,
.flavor = nullptr};
viewComponentDescriptor_ = std::make_unique<ViewComponentDescriptor>(params);

class TestShadowTreeDelegate : public ShadowTreeDelegate {
public:
RootShadowNode::Unshared shadowTreeWillCommit(
[[maybe_unused]] const ShadowTree& shadowTree,
[[maybe_unused]] const RootShadowNode::Shared& oldRootShadowNode,
const RootShadowNode::Unshared& newRootShadowNode,
[[maybe_unused]] const ShadowTreeCommitOptions& commitOptions)
const override {
return newRootShadowNode;
}

void shadowTreeDidFinishTransaction(
[[maybe_unused]] std::shared_ptr<const MountingCoordinator>
mountingCoordinator,
[[maybe_unused]] bool mountSynchronously) const override {}

void shadowTreeDidFinishReactCommit(
[[maybe_unused]] const ShadowTree& shadowTree) const override {}
};
shadowTreeDelegate_ = std::make_unique<TestShadowTreeDelegate>();
}

void FabricMountingManagerTestHelper::initHybrid(
Expand Down Expand Up @@ -81,6 +117,112 @@ void FabricMountingManagerTestHelper::synchronouslyUpdateAnimatedProps(
mountingManager_->synchronouslyUpdateAnimatedProps(updates);
}

void FabricMountingManagerTestHelper::startSurfaceWithConstraints(
jint surfaceId,
jfloat widthDp,
jfloat heightDp,
jfloat pointScaleFactor) {
shadowTree_ = std::make_unique<ShadowTree>(
surfaceId,
makeLayoutConstraints(widthDp, heightDp),
LayoutContext{.pointScaleFactor = pointScaleFactor},
*shadowTreeDelegate_,
*contextContainer_);
mountingManager_->onSurfaceStart(surfaceId);
}

void FabricMountingManagerTestHelper::mountViewWithPadding(
jint surfaceId,
jint tag,
jfloat padding) {
using ShadowNodeList = std::vector<std::shared_ptr<const ShadowNode>>;
PropsParserContext parserContext{surfaceId, *contextContainer_};
auto createView = [&](Tag viewTag,
folly::dynamic style,
ShadowNodeList children) {
auto family = viewComponentDescriptor_->createFamily(
{.tag = viewTag, .surfaceId = surfaceId, .instanceHandle = nullptr});
auto props = viewComponentDescriptor_->cloneProps(
parserContext, nullptr, RawProps(std::move(style)));
return viewComponentDescriptor_->createShadowNode(
{.props = props,
.children =
std::make_shared<const ShadowNodeList>(std::move(children)),
.state = viewComponentDescriptor_->createInitialState(props, family)},
family);
};

auto overflowingChild = createView(
tag + 1,
folly::dynamic::object("collapsable", false)("position", "absolute")(
"left", -padding)("top", -padding)("width", 100 + 2 * padding)(
"height", 100 + 2 * padding),
{});
auto paddedView = createView(
tag,
folly::dynamic::object("collapsable", false)("width", 100)("height", 100)(
"padding", padding),
{overflowingChild});

shadowTree_->commit(
[&](const RootShadowNode& oldRootShadowNode) {
return std::static_pointer_cast<RootShadowNode>(
oldRootShadowNode.ShadowNode::clone(
{.children = std::make_shared<const ShadowNodeList>(
ShadowNodeList{paddedView})}));
},
{});
mountPendingTransaction();
}

void FabricMountingManagerTestHelper::updateSurfaceConstraints(
jint surfaceId,
jfloat widthDp,
jfloat heightDp,
jfloat pointScaleFactor) {
PropsParserContext parserContext{surfaceId, *contextContainer_};
shadowTree_->commit(
[&](const RootShadowNode& oldRootShadowNode) {
return oldRootShadowNode.clone(
parserContext,
makeLayoutConstraints(widthDp, heightDp),
LayoutContext{.pointScaleFactor = pointScaleFactor});
},
{});
mountPendingTransaction();
}

void FabricMountingManagerTestHelper::overrideFeatureFlags(
jboolean fixTextLayoutOnPixelDensityChange) {
class TestFeatureFlags : public ReactNativeFeatureFlagsDefaults {
public:
explicit TestFeatureFlags(bool fixTextLayoutOnPixelDensityChange)
: fixTextLayoutOnPixelDensityChange_(
fixTextLayoutOnPixelDensityChange) {}

bool fixTextLayoutOnPixelDensityChange() override {
return fixTextLayoutOnPixelDensityChange_;
}

private:
bool fixTextLayoutOnPixelDensityChange_;
};
ReactNativeFeatureFlags::dangerouslyForceOverride(
std::make_unique<TestFeatureFlags>(
fixTextLayoutOnPixelDensityChange != 0));
}

void FabricMountingManagerTestHelper::resetFeatureFlags() {
ReactNativeFeatureFlags::dangerouslyReset();
}

void FabricMountingManagerTestHelper::mountPendingTransaction() {
auto transaction = shadowTree_->getMountingCoordinator()->pullTransaction();
if (transaction.has_value()) {
mountingManager_->executeMount(*transaction);
}
}

void FabricMountingManagerTestHelper::registerNatives() {
registerHybrid({
makeNativeMethod(
Expand All @@ -99,6 +241,21 @@ void FabricMountingManagerTestHelper::registerNatives() {
makeNativeMethod(
"synchronouslyUpdateAnimatedProps",
FabricMountingManagerTestHelper::synchronouslyUpdateAnimatedProps),
makeNativeMethod(
"startSurfaceWithConstraints",
FabricMountingManagerTestHelper::startSurfaceWithConstraints),
makeNativeMethod(
"mountViewWithPadding",
FabricMountingManagerTestHelper::mountViewWithPadding),
makeNativeMethod(
"updateSurfaceConstraints",
FabricMountingManagerTestHelper::updateSurfaceConstraints),
makeNativeMethod(
"overrideFeatureFlags",
FabricMountingManagerTestHelper::overrideFeatureFlags),
makeNativeMethod(
"resetFeatureFlags",
FabricMountingManagerTestHelper::resetFeatureFlags),
});
}

Expand Down
Loading
Loading