Skip to content

Commit

Permalink
resolve transform function
Browse files Browse the repository at this point in the history
  • Loading branch information
intergalacticspacehighway committed Jun 9, 2023
1 parent 5cc8cee commit f39ba67
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = {
* Transform
*/
transform: {process: processTransform},
transformOrigin: true,

/**
* View
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ const validAttributesForNonEventProps = {
// @ReactProps from BaseViewManager
backgroundColor: {process: require('../StyleSheet/processColor').default},
transform: true,
transformOrigin: true,
opacity: true,
elevation: true,
shadowColor: {process: require('../StyleSheet/processColor').default},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ const validAttributesForNonEventProps = {
overflow: true,
shouldRasterizeIOS: true,
transform: {diff: require('../Utilities/differ/matricesDiffer')},
transformOrigin: true,
accessibilityRole: true,
accessibilityState: true,
nativeID: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export default function splitLayoutProps(props: ?____ViewStyle_Internal): {
case 'bottom':
case 'top':
case 'transform':
case 'transformOrigin':
case 'rowGap':
case 'columnGap':
case 'gap':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,9 +260,10 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &
}

// `transform`
if (oldViewProps.transform != newViewProps.transform &&
![_propKeysManagedByAnimated_DO_NOT_USE_THIS_IS_BROKEN containsObject:@"transform"]) {
self.layer.transform = RCTCATransform3DFromTransformMatrix(newViewProps.transform);
if ((oldViewProps.transform != newViewProps.transform || oldViewProps.transformOrigin != newViewProps.transformOrigin)
&& ![_propKeysManagedByAnimated_DO_NOT_USE_THIS_IS_BROKEN containsObject:@"transform"]) {
auto newTransform = newViewProps.resolveTransform(_layoutMetrics);
self.layer.transform = RCTCATransform3DFromTransformMatrix(newTransform);
self.layer.allowsEdgeAntialiasing = newViewProps.transform != Transform::Identity();
}

Expand Down Expand Up @@ -396,6 +397,12 @@ - (void)updateLayoutMetrics:(LayoutMetrics const &)layoutMetrics
if (_contentView) {
_contentView.frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame());
}

if (_props->transformOrigin.length() > 0) {
auto newTransform = _props->resolveTransform(layoutMetrics);
self.layer.transform = RCTCATransform3DFromTransformMatrix(newTransform);
}

}

- (BOOL)isJSResponder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,10 +318,14 @@ - (void)synchronouslyUpdateViewOnUIThread:(ReactTag)reactTag

const auto &newViewProps = *std::static_pointer_cast<const ViewProps>(newProps);

if (props[@"transform"] &&
!CATransform3DEqualToTransform(
RCTCATransform3DFromTransformMatrix(newViewProps.transform), componentView.layer.transform)) {
componentView.layer.transform = RCTCATransform3DFromTransformMatrix(newViewProps.transform);
if (props[@"transform"]) {
auto layoutMetrics = LayoutMetrics();
layoutMetrics.frame.size.width = componentView.layer.bounds.size.width;
layoutMetrics.frame.size.height = componentView.layer.bounds.size.height;
CATransform3D newTransform = RCTCATransform3DFromTransformMatrix(newViewProps.resolveTransform(layoutMetrics));
if (!CATransform3DEqualToTransform(newTransform, componentView.layer.transform)) {
componentView.layer.transform = newTransform;
}
}
if (props[@"opacity"] && componentView.layer.opacity != (float)newViewProps.opacity) {
componentView.layer.opacity = newViewProps.opacity;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ class ConcreteViewShadowNode : public ConcreteShadowNode<
}

Transform getTransform() const override {
return BaseShadowNode::getConcreteProps().transform;
auto layoutMetrics = BaseShadowNode::getLayoutMetrics();
return BaseShadowNode::getConcreteProps().resolveTransform(layoutMetrics);
}

private:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <react/renderer/core/graphicsConversions.h>
#include <react/renderer/core/propsConversions.h>
#include <react/renderer/debug/debugStringConvertibleUtils.h>
#include <react/renderer/core/LayoutMetrics.h>

namespace facebook::react {

Expand Down Expand Up @@ -119,6 +120,14 @@ ViewProps::ViewProps(
"transform",
sourceProps.transform,
{})),
transformOrigin(
CoreFeatures::enablePropIteratorSetter ? sourceProps.transformOrigin
: convertRawProp(
context,
rawProps,
"transformOrigin",
sourceProps.transformOrigin,
{})),
backfaceVisibility(
CoreFeatures::enablePropIteratorSetter
? sourceProps.backfaceVisibility
Expand Down Expand Up @@ -292,6 +301,7 @@ void ViewProps::setProp(
RAW_SET_PROP_SWITCH_CASE_BASIC(shadowOpacity);
RAW_SET_PROP_SWITCH_CASE_BASIC(shadowRadius);
RAW_SET_PROP_SWITCH_CASE_BASIC(transform);
RAW_SET_PROP_SWITCH_CASE_BASIC(transformOrigin);
RAW_SET_PROP_SWITCH_CASE_BASIC(backfaceVisibility);
RAW_SET_PROP_SWITCH_CASE_BASIC(shouldRasterize);
RAW_SET_PROP_SWITCH_CASE_BASIC(zIndex);
Expand Down Expand Up @@ -412,6 +422,56 @@ BorderMetrics ViewProps::resolveBorderMetrics(
};
}

Transform ViewProps::resolveTransform(
LayoutMetrics const &layoutMetrics) const {
float viewWidth = layoutMetrics.frame.size.width;
float viewHeight = layoutMetrics.frame.size.height;
if (transformOrigin.empty() || (viewWidth == 0 && viewHeight == 0)) {
return transform;
}
auto newTransform = Transform{};
std::array<float, 3> translateOffsets = getTranslateForTransformOrigin(viewWidth, viewHeight);
newTransform = newTransform * Transform::Translate(translateOffsets[0], translateOffsets[1], translateOffsets[2]);
newTransform = newTransform * transform;
newTransform = newTransform * Transform::Translate(-translateOffsets[0], -translateOffsets[1], -translateOffsets[2]);
return newTransform;
}

// https://drafts.csswg.org/css-transforms/#transform-origin-property
std::array<float, 3> ViewProps::getTranslateForTransformOrigin(float viewWidth, float viewHeight) const {
float viewCenterX = viewWidth / 2;
float viewCenterY = viewHeight / 2;

std::array<float, 3> origin = {viewCenterX, viewCenterY, 0.0f};
std::istringstream iss(transformOrigin);
std::string part;
for (int i = 0; std::getline(iss, part, ' ') && i < 3; i++) {
auto percentPos = part.find('%');
bool isPercent = percentPos != std::string::npos;
if (isPercent) {
origin[i] = (i == 0 ? viewWidth : viewHeight) * std::stof(part.substr(0, percentPos)) / 100.0f;
} else if (part == "top") {
origin[1] = 0.0f;
} else if (part == "bottom") {
origin[1] = static_cast<float>(viewHeight);
} else if (part == "left") {
origin[0] = 0.0f;
} else if (part == "right") {
origin[0] = static_cast<float>(viewWidth);
} else if (part == "center") {
continue;
} else {
origin[i] = std::stof(part);
}
}

float newTranslateX = -viewCenterX + origin[0];
float newTranslateY = -viewCenterY + origin[1];
float newTranslateZ = origin[2];

return std::array{newTranslateX, newTranslateY, newTranslateZ};
}

bool ViewProps::getClipsContentToBounds() const {
return yogaStyle.overflow() != YGOverflowVisible;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <react/renderer/core/PropsParserContext.h>
#include <react/renderer/graphics/Color.h>
#include <react/renderer/graphics/Transform.h>
#include <react/renderer/core/LayoutMetrics.h>

#include <optional>

Expand Down Expand Up @@ -64,6 +65,8 @@ class ViewProps : public YogaStylableProps, public AccessibilityProps {

// Transform
Transform transform{};
std::string transformOrigin;

BackfaceVisibility backfaceVisibility{};
bool shouldRasterize{};
std::optional<int> zIndex{};
Expand Down Expand Up @@ -96,6 +99,8 @@ class ViewProps : public YogaStylableProps, public AccessibilityProps {
#pragma mark - Convenience Methods

BorderMetrics resolveBorderMetrics(LayoutMetrics const &layoutMetrics) const;
Transform resolveTransform(LayoutMetrics const &layoutMetrics) const;
std::array<float, 3> getTranslateForTransformOrigin(float viewWidth, float viewHeight) const;
bool getClipsContentToBounds() const;

#ifdef ANDROID
Expand Down

0 comments on commit f39ba67

Please sign in to comment.