Fabric: New two ShadowNode Traits: FormsStackingContext & FormsView

Summary:
This diff introduces two new `ShadowNodeTrait`s that we will use in the future in the new (slightly tweaked) view-flattening algorithm. (Note: this diff does not enable the new flattening, it's just preparation.)
The idea is that we split the notion of `isLayoutOnlyView` into two traits:
* `FormsView`: `ShadowNode`s with this trait must be represented as `ShadowView`s. Normal "visible" ShadowNodes will have this trait, but "layout only views" in old nomenclature will not.
* `FormsStackingContext`: `ShadowNode`s with this thread not only must be represented as `ShadowView`s but also have to form a "stacking context" which means that their children must be mounted as `ShadowView`'s children.

Our implementation does not exactly follow W3C spec in terms of sets of props that create the stacking context (because of historical reasons and mobile specifics) but ideologically it's the same. We start from the very conservative implementation where only views with background-color and borders do not form stacking context and then we probably extend that to more props.

Most importantly for us now, we will enforce the absence of ``FormsStackingContext` for `ParagraphShadowNode` and the presence of `FormsView` for `TextShadowNode` on Android where it's essential for mounting layer.

Read more about stacking context here: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context

Changelog: [Internal] Fabric-specific internal change.

Reviewed By: sammy-SC

Differential Revision: D20212253

fbshipit-source-id: 0fbaee214ce2c5886cb0232843a2a3c7bb20655d
This commit is contained in:
Valentin Shergin 2020-03-04 12:30:01 -08:00 коммит произвёл Facebook Github Bot
Родитель fc45530ded
Коммит b5117bf6ea
7 изменённых файлов: 87 добавлений и 1 удалений

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

@ -41,6 +41,7 @@ class ParagraphShadowNode : public ConcreteViewShadowNode<
static ShadowNodeTraits BaseTraits() {
auto traits = ConcreteViewShadowNode::BaseTraits();
traits.set(ShadowNodeTraits::Trait::LeafYogaNode);
return traits;
}

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

@ -26,6 +26,17 @@ class TextShadowNode : public ConcreteShadowNode<
TextEventEmitter>,
public BaseTextShadowNode {
public:
static ShadowNodeTraits BaseTraits() {
auto traits = ConcreteShadowNode::BaseTraits();
#ifdef ANDROID
traits.set(ShadowNodeTraits::Trait::FormsView);
traits.set(ShadowNodeTraits::Trait::FormsStackingContext);
#endif
return traits;
}
using ConcreteShadowNode::ConcreteShadowNode;
};

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

@ -59,6 +59,8 @@ class ConcreteViewShadowNode : public ConcreteShadowNode<
static ShadowNodeTraits BaseTraits() {
auto traits = BaseShadowNode::BaseTraits();
traits.set(ShadowNodeTraits::Trait::ViewKind);
traits.set(ShadowNodeTraits::Trait::FormsStackingContext);
traits.set(ShadowNodeTraits::Trait::FormsView);
return traits;
}

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

@ -33,5 +33,58 @@ bool ViewShadowNode::isLayoutOnly() const {
getLayoutMetrics().borderWidth == EdgeInsets{};
}
ViewShadowNode::ViewShadowNode(
ShadowNodeFragment const &fragment,
ShadowNodeFamily::Shared const &family,
ShadowNodeTraits traits)
: ConcreteViewShadowNode(fragment, family, traits) {
updateTraits();
}
ViewShadowNode::ViewShadowNode(
ShadowNode const &sourceShadowNode,
ShadowNodeFragment const &fragment)
: ConcreteViewShadowNode(sourceShadowNode, fragment) {
updateTraits();
}
static bool isColorMeaningful(SharedColor const &color) {
if (!color) {
return false;
}
return colorComponentsFromColor(color).alpha > 0;
}
void ViewShadowNode::updateTraits() {
auto &viewProps = static_cast<ViewProps const &>(*props_);
bool formsStackingContext = !viewProps.collapsable ||
viewProps.pointerEvents == PointerEventsMode::None ||
!viewProps.nativeId.empty() || viewProps.accessible ||
viewProps.opacity != 1.0 || viewProps.transform != Transform{} ||
viewProps.zIndex != 0 || viewProps.getClipsContentToBounds() ||
viewProps.yogaStyle.positionType() == YGPositionTypeAbsolute;
bool formsView = isColorMeaningful(viewProps.backgroundColor) ||
isColorMeaningful(viewProps.foregroundColor) ||
isColorMeaningful(viewProps.shadowColor) ||
!(viewProps.yogaStyle.border() == YGStyle::Edges{});
formsView = formsView || formsStackingContext;
if (formsView) {
traits_.set(ShadowNodeTraits::Trait::FormsView);
} else {
traits_.unset(ShadowNodeTraits::Trait::FormsView);
}
if (formsStackingContext) {
traits_.set(ShadowNodeTraits::Trait::FormsStackingContext);
} else {
traits_.unset(ShadowNodeTraits::Trait::FormsStackingContext);
}
}
} // namespace react
} // namespace facebook

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

@ -23,9 +23,19 @@ class ViewShadowNode final : public ConcreteViewShadowNode<
ViewProps,
ViewEventEmitter> {
public:
using ConcreteViewShadowNode::ConcreteViewShadowNode;
ViewShadowNode(
ShadowNodeFragment const &fragment,
ShadowNodeFamily::Shared const &family,
ShadowNodeTraits traits);
ViewShadowNode(
ShadowNode const &sourceShadowNode,
ShadowNodeFragment const &fragment);
bool isLayoutOnly() const;
private:
void updateTraits();
};
} // namespace react

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

@ -207,6 +207,7 @@ class ShadowNode : public Sealable, public DebugStringConvertible {
*/
ShadowNodeFamily::Shared family_;
protected:
/*
* Traits associated with the particular `ShadowNode` class and an instance of
* that class.

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

@ -57,6 +57,14 @@ class ShadowNodeTraits {
// Inherits `LayoutableShadowNode` and calls `measure()`.
HasMeasure = 1 << 11,
// Indicates that the `ShadowNode` must form a stacking context (a level
// of the hierarchy; `ShadowView`s formed by descendants the node will be
// descendants of a `ShadowView` formed by the node).
FormsStackingContext = 1 << 13,
// Indicates that the node must form a `ShadowView`.
FormsView = 1 << 14,
// Internal to `ShadowNode`; do not use it outside.
// Indicates that `children` list is shared between nodes and need
// to be cloned before the first mutation.