mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
c2a089fddf
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/36258 This fixes a few instances where YogaLayoutableShadowNode (or general shadownode casting) could offer better memory safety. 1. The reference form of traitCast() now terminates on invalid cast, instead of debug assert, since it is better to crash in production than to corrupt memory (which will crash somewhere later, in a much more confusing way). 2. We use traitCast() in more places where we previously would static_cast. This means needing to formally add a mutable version. 3. We bounds-check yoga children access in a single place by using `std::vector` `at()` instead of `[]`. 4. Removed `Trait::UnreservedTrait1` API, since multiple libraries using it can collide and we lose the memory safety benefits of `traitCast`. This change is in response to a bug where `YogaLayoutableShadowNode` may perform an invalid `static_cast` of `RawTextShadowNode` if a text or number is rendered directly inside of a `<View>` (instead of a `<Text>` element). This does not yet fix the underlying logic of YogaLayoutableShadowNode to act gracefully when a RawTextShadowNode makes its way into children. We just terminate, instead of corrupting memory. Changelog: [General][Breaking] - Better Fabric ShadowNode Memory Safety (Removes `Trait::UnreservedTrait` API) Reviewed By: javache Differential Revision: D43271779 fbshipit-source-id: 727c1230f72664bf4d261871c66ca61ddf0d5ffa
170 lines
5.0 KiB
C++
170 lines
5.0 KiB
C++
/*
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <array>
|
|
#include <cmath>
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
#include <butter/small_vector.h>
|
|
#include <react/debug/react_native_assert.h>
|
|
#include <react/renderer/core/LayoutMetrics.h>
|
|
#include <react/renderer/core/ShadowNode.h>
|
|
#include <react/renderer/core/ShadowNodeFragment.h>
|
|
#include <react/renderer/debug/DebugStringConvertible.h>
|
|
#include <react/renderer/graphics/Transform.h>
|
|
|
|
namespace facebook {
|
|
namespace react {
|
|
|
|
struct LayoutConstraints;
|
|
struct LayoutContext;
|
|
|
|
/*
|
|
* Describes all sufficient layout API (in approach-agnostic way)
|
|
* which makes a concurrent layout possible.
|
|
*/
|
|
class LayoutableShadowNode : public ShadowNode {
|
|
public:
|
|
LayoutableShadowNode(
|
|
ShadowNodeFragment const &fragment,
|
|
ShadowNodeFamily::Shared const &family,
|
|
ShadowNodeTraits traits);
|
|
|
|
LayoutableShadowNode(
|
|
ShadowNode const &sourceShadowNode,
|
|
ShadowNodeFragment const &fragment);
|
|
|
|
static ShadowNodeTraits BaseTraits();
|
|
static ShadowNodeTraits::Trait IdentifierTrait();
|
|
|
|
struct LayoutInspectingPolicy {
|
|
bool includeTransform{true};
|
|
bool includeViewportOffset{false};
|
|
};
|
|
|
|
using UnsharedList = butter::
|
|
small_vector<LayoutableShadowNode *, kShadowNodeChildrenSmallVectorSize>;
|
|
|
|
/*
|
|
* Returns layout metrics of a node represented as `descendantNodeFamily`
|
|
* computed relatively to given `ancestorNode`. Returns `EmptyLayoutMetrics`
|
|
* if the nodes don't form an ancestor-descender relationship in the same
|
|
* tree.
|
|
*/
|
|
static LayoutMetrics computeRelativeLayoutMetrics(
|
|
ShadowNodeFamily const &descendantNodeFamily,
|
|
LayoutableShadowNode const &ancestorNode,
|
|
LayoutInspectingPolicy policy);
|
|
|
|
/*
|
|
* Performs layout of the tree starting from this node. Usually is being
|
|
* called on the root node.
|
|
* Default implementation does nothing.
|
|
*/
|
|
virtual void layoutTree(
|
|
LayoutContext layoutContext,
|
|
LayoutConstraints layoutConstraints) = 0;
|
|
|
|
/*
|
|
* Measures the node (and node content, probably recursively) with
|
|
* given constrains and relying on possible layout.
|
|
* Default implementation returns zero size.
|
|
*/
|
|
virtual Size measureContent(
|
|
LayoutContext const &layoutContext,
|
|
LayoutConstraints const &layoutConstraints) const;
|
|
|
|
/*
|
|
* Measures the node with given `layoutContext` and `layoutConstraints`.
|
|
* The size of nested content and the padding should be included, the margin
|
|
* should *not* be included. Default implementation returns zero size.
|
|
*/
|
|
virtual Size measure(
|
|
LayoutContext const &layoutContext,
|
|
LayoutConstraints const &layoutConstraints) const;
|
|
|
|
/*
|
|
* Computes layout recursively.
|
|
* Additional environmental constraints might be provided via `layoutContext`
|
|
* argument.
|
|
*
|
|
* The typical concrete-layout-specific implementation of this method should:
|
|
* - Measure children with `LayoutConstraints` calculated from its size using
|
|
* a particular layout approach;
|
|
* - Calculate and assign `LayoutMetrics` for the children;
|
|
* - Call itself recursively on every child if needed.
|
|
*/
|
|
virtual void layout(LayoutContext layoutContext) = 0;
|
|
|
|
/*
|
|
* Returns layout metrics computed during previous layout pass.
|
|
*/
|
|
LayoutMetrics getLayoutMetrics() const;
|
|
|
|
/*
|
|
* Returns a transform object that represents transformations that will/should
|
|
* be applied on top of regular layout metrics by mounting layer.
|
|
* The `transform` value modifies a coordinate space of a layout system.
|
|
* Default implementation returns `Identity` transform.
|
|
*/
|
|
virtual Transform getTransform() const;
|
|
|
|
/*
|
|
* Returns offset which is applied to children's origin in
|
|
* `LayoutableShadowNode::getRelativeLayoutMetrics` and
|
|
* `LayoutableShadowNode::findNodeAtPoint`.
|
|
*/
|
|
virtual Point getContentOriginOffset() const;
|
|
|
|
/*
|
|
* Sets layout metrics for the shadow node.
|
|
*/
|
|
void setLayoutMetrics(LayoutMetrics layoutMetrics);
|
|
|
|
/*
|
|
* Returns the ShadowNode that is rendered at the Point received as a
|
|
* parameter.
|
|
*/
|
|
static ShadowNode::Shared findNodeAtPoint(
|
|
ShadowNode::Shared const &node,
|
|
Point point);
|
|
|
|
/*
|
|
* Clean or Dirty layout state:
|
|
* Indicates whether all nodes (and possibly their subtrees) along the path
|
|
* to the root node should be re-laid out.
|
|
*/
|
|
virtual void cleanLayout() = 0;
|
|
virtual void dirtyLayout() = 0;
|
|
virtual bool getIsLayoutClean() const = 0;
|
|
|
|
/*
|
|
* Unifed methods to access text layout metrics.
|
|
*/
|
|
virtual Float firstBaseline(Size size) const;
|
|
virtual Float lastBaseline(Size size) const;
|
|
|
|
/*
|
|
* Returns layoutable children to interate on.
|
|
*/
|
|
LayoutableShadowNode::UnsharedList getLayoutableChildNodes() const;
|
|
|
|
#pragma mark - DebugStringConvertible
|
|
|
|
#if RN_DEBUG_STRING_CONVERTIBLE
|
|
SharedDebugStringConvertibleList getDebugProps() const;
|
|
#endif
|
|
|
|
LayoutMetrics layoutMetrics_;
|
|
};
|
|
|
|
} // namespace react
|
|
} // namespace facebook
|