Skip to content

[0.71] Picking Fabric fixes from main #1898

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Aug 7, 2023
Merged
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
7 changes: 1 addition & 6 deletions Libraries/Image/RCTUIImageViewAnimated.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,5 @@
#import <React/RCTAnimatedImage.h>
#import <React/RCTDefines.h>

#if !TARGET_OS_OSX // [macOS]
@interface RCTUIImageViewAnimated : UIImageView
#else // [macOS
@interface RCTUIImageViewAnimated : NSImageView
#endif // macOS]

@interface RCTUIImageViewAnimated : RCTUIImageView // [macOS]
@end
1 change: 1 addition & 0 deletions Libraries/Text/TextInput/Multiline/RCTUITextView.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, copy) NSString *text;
@property (nonatomic, assign) NSTextAlignment textAlignment;
@property (nonatomic, copy, nullable) NSAttributedString *attributedText;
@property (nonatomic, assign) CGFloat pointScaleFactor;
- (NSSize)sizeThatFits:(NSSize)size;
- (void)setReadablePasteBoardTypes:(NSArray<NSPasteboardType> *)readablePasteboardTypes;
#endif // macOS]
Expand Down
2 changes: 1 addition & 1 deletion Libraries/Text/TextInput/Multiline/RCTUITextView.m
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ - (CGSize)placeholderSize
.size;
placeholderSize = CGSizeMake(RCTCeilPixelValue(placeholderSize.width), RCTCeilPixelValue(placeholderSize.height));
#else // [macOS
CGFloat scale = self.window.backingScaleFactor;
CGFloat scale = _pointScaleFactor ?: self.window.backingScaleFactor;
CGSize placeholderSize = [placeholder sizeWithAttributes:[self _placeholderTextAttributes]];
placeholderSize = CGSizeMake(RCTCeilPixelValue(placeholderSize.width, scale), RCTCeilPixelValue(placeholderSize.height, scale));
#endif // macOS]
Expand Down
3 changes: 3 additions & 0 deletions Libraries/Text/TextInput/RCTBackedTextInputViewProtocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, assign, readonly) CGFloat zoomScale;
@property (nonatomic, assign, readonly) CGPoint contentOffset;
@property (nonatomic, assign, readonly) UIEdgeInsets contentInset;
#if TARGET_OS_OSX // [macOS
@property (nonatomic, assign) CGFloat pointScaleFactor;
#endif // macOS]

// This protocol disallows direct access to `selectedTextRange` property because
// unwise usage of it can break the `delegate` behavior. So, we always have to
Expand Down
1 change: 1 addition & 0 deletions Libraries/Text/TextInput/Singleline/RCTUITextField.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, assign) BOOL enableFocusRing;
@property (nonatomic, strong, nullable) RCTUIColor *selectionColor;
@property (weak, nullable) id<RCTUITextFieldDelegate> delegate;
@property (nonatomic, assign) CGFloat pointScaleFactor;
#endif // macOS]

@property (nonatomic, getter=isGhostTextChanging) BOOL ghostTextChanging; // [macOS]
Expand Down
2 changes: 1 addition & 1 deletion Libraries/Text/TextInput/Singleline/RCTUITextField.m
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,7 @@ - (CGSize)intrinsicContentSize
size = CGSizeMake(RCTCeilPixelValue(size.width), RCTCeilPixelValue(size.height));
#else // [macOS
CGSize size = [text sizeWithAttributes:@{NSFontAttributeName: self.font}];
CGFloat scale = self.window.backingScaleFactor;
CGFloat scale = _pointScaleFactor ?: self.window.backingScaleFactor;
RCTAssert(scale != 0.0, @"Layout occurs before the view is in a window?");
if (scale == 0) {
scale = [[NSScreen mainScreen] backingScaleFactor];
Expand Down
19 changes: 14 additions & 5 deletions React/Base/RCTUIKit.h
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,6 @@ CGPathRef UIBezierPathCreateCGPathRef(UIBezierPath *path);
- (void)layoutIfNeeded;

- (void)layoutSubviews;
- (NSArray<RCTUIView *> *)reactZIndexSortedSubviews; // [macOS]

- (void)setNeedsDisplay;

Expand All @@ -417,10 +416,6 @@ CGPathRef UIBezierPathCreateCGPathRef(UIBezierPath *path);
* Specifies whether focus ring should be drawn when the view has the first responder status.
*/
@property (nonatomic, assign) BOOL enableFocusRing;
/**
* The z-index of the view.
*/
@property (nonatomic, assign) NSInteger reactZIndex;

@end

Expand Down Expand Up @@ -586,3 +581,17 @@ typedef UITouch RCTUITouch;
@interface RCTUITouch : NSEvent
@end
#endif

// RCTUIImageView

#if !TARGET_OS_OSX
typedef UIImageView RCTUIImageView;
#else
@interface RCTUIImageView : NSImageView
NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, assign) BOOL clipsToBounds;
@property (nonatomic, strong) RCTUIColor *tintColor;
@property (nonatomic, assign) UIViewContentMode contentMode;
NS_ASSUME_NONNULL_END
@end
#endif
114 changes: 93 additions & 21 deletions React/Base/macOS/RCTUIKit.m
Original file line number Diff line number Diff line change
Expand Up @@ -416,27 +416,6 @@ - (void)layoutSubviews
[super layout];
}

- (NSArray<RCTUIView *> *)reactZIndexSortedSubviews
{
// Check if sorting is required - in most cases it won't be.
BOOL sortingRequired = NO;
for (RCTUIView *subview in self.subviews) {
if (subview.reactZIndex != 0) {
sortingRequired = YES;
break;
}
}
return sortingRequired ? [self.subviews sortedArrayUsingComparator:^NSComparisonResult(RCTUIView *a, RCTUIView *b) {
if (a.reactZIndex > b.reactZIndex) {
return NSOrderedDescending;
} else {
// Ensure sorting is stable by treating equal zIndex as ascending so
// that original order is preserved.
return NSOrderedAscending;
}
}] : self.subviews;
}

- (void)setNeedsDisplay
{
self.needsDisplay = YES;
Expand Down Expand Up @@ -472,6 +451,7 @@ - (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
self.scrollEnabled = YES;
self.drawsBackground = NO;
}

return self;
Expand Down Expand Up @@ -781,4 +761,96 @@ - (void)setHidden:(BOOL)hidden

@end

// RCTUIImageView

@implementation RCTUIImageView {
CALayer *_tintingLayer;
}

- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
[self setLayer:[[CALayer alloc] init]];
[self setWantsLayer:YES];
}

return self;
}

- (BOOL)clipsToBounds
{
return [[self layer] masksToBounds];
}

- (void)setClipsToBounds:(BOOL)clipsToBounds
{
[[self layer] setMasksToBounds:clipsToBounds];
}

- (void)setContentMode:(UIViewContentMode)contentMode
{
_contentMode = contentMode;

CALayer *layer = [self layer];
switch (contentMode) {
case UIViewContentModeScaleAspectFill:
[layer setContentsGravity:kCAGravityResizeAspectFill];
break;

case UIViewContentModeScaleAspectFit:
[layer setContentsGravity:kCAGravityResizeAspect];
break;

case UIViewContentModeScaleToFill:
[layer setContentsGravity:kCAGravityResize];
break;

case UIViewContentModeCenter:
[layer setContentsGravity:kCAGravityCenter];
break;

default:
break;
}
}

- (UIImage *)image
{
return [[self layer] contents];
}

- (void)setImage:(UIImage *)image
{
CALayer *layer = [self layer];

if ([layer contents] != image || [layer backgroundColor] != nil) {
if (_tintColor) {
if (!_tintingLayer) {
_tintingLayer = [CALayer new];
[_tintingLayer setFrame:self.bounds];
[_tintingLayer setAutoresizingMask:kCALayerWidthSizable | kCALayerHeightSizable];
[_tintingLayer setZPosition:1.0];
CIFilter *sourceInCompositingFilter = [CIFilter filterWithName:@"CISourceInCompositing"];
[sourceInCompositingFilter setDefaults];
[_tintingLayer setCompositingFilter:sourceInCompositingFilter];
[layer addSublayer:_tintingLayer];
}
[_tintingLayer setBackgroundColor:_tintColor.CGColor];
} else {
[_tintingLayer removeFromSuperlayer];
_tintingLayer = nil;
}

if (image != nil && [image resizingMode] == NSImageResizingModeTile) {
[layer setContents:nil];
[layer setBackgroundColor:[NSColor colorWithPatternImage:image].CGColor];
} else {
[layer setContents:image];
[layer setBackgroundColor:nil];
}
}
}

@end

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,8 @@ - (instancetype)initWithFrame:(CGRect)frame
_props = defaultProps;

_imageView = [RCTUIImageViewAnimated new];
#if !TARGET_OS_OSX // [macOS]
_imageView.clipsToBounds = YES;
_imageView.contentMode = RCTContentModeFromImageResizeMode(defaultProps->resizeMode);
#endif // [macOS]
_imageView.layer.minificationFilter = kCAFilterTrilinear;
_imageView.layer.magnificationFilter = kCAFilterTrilinear;

Expand All @@ -58,7 +56,6 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &
auto const &oldImageProps = *std::static_pointer_cast<ImageProps const>(_props);
auto const &newImageProps = *std::static_pointer_cast<ImageProps const>(props);

#if !TARGET_OS_OSX // [macOS]
// `resizeMode`
if (oldImageProps.resizeMode != newImageProps.resizeMode) {
_imageView.contentMode = RCTContentModeFromImageResizeMode(newImageProps.resizeMode);
Expand All @@ -68,7 +65,6 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &
if (oldImageProps.tintColor != newImageProps.tintColor) {
_imageView.tintColor = RCTUIColorFromSharedColor(newImageProps.tintColor);
}
#endif // [macOS]

[super updateProps:props oldProps:oldProps];
}
Expand Down Expand Up @@ -149,6 +145,11 @@ - (void)didReceiveImage:(UIImage *)image metadata:(id)metadata fromObserver:(voi
image = [image resizableImageWithCapInsets:RCTUIEdgeInsetsFromEdgeInsets(imageProps.capInsets)
resizingMode:UIImageResizingModeStretch];
}
#else
if (imageProps.resizeMode == ImageResizeMode::Repeat) {
image.capInsets = RCTUIEdgeInsetsFromEdgeInsets(imageProps.capInsets);
image.resizingMode = NSImageResizingModeTile;
}
#endif // [macOS]

if (imageProps.blurRadius > __FLT_EPSILON__) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,22 +54,22 @@ - (void)_updateStateIfNecessary
}

UIEdgeInsets insets = [self _safeAreaInsets];
CGFloat scale = _layoutMetrics.pointScaleFactor; // [macOS]
#if !TARGET_OS_OSX // [macOS]
insets.left = RCTRoundPixelValue(insets.left);
insets.top = RCTRoundPixelValue(insets.top);
insets.right = RCTRoundPixelValue(insets.right);
insets.bottom = RCTRoundPixelValue(insets.bottom);
#else // [macOS
CGFloat scale = [[NSScreen mainScreen] backingScaleFactor];;
insets.left = RCTRoundPixelValue(insets.left, scale);
insets.top = RCTRoundPixelValue(insets.top, scale);
insets.right = RCTRoundPixelValue(insets.right, scale);
insets.bottom = RCTRoundPixelValue(insets.bottom, scale);
#endif // macOS]

auto newPadding = RCTEdgeInsetsFromUIEdgeInsets(insets);
auto threshold = 1.0 / RCTScreenScale() + 0.01; // Size of a pixel plus some small threshold.

auto threshold = 1.0 / scale + 0.01; // Size of a pixel plus some small threshold. [macOS]
_state->updateState(
[=](SafeAreaViewShadowNode::ConcreteState::Data const &oldData)
-> SafeAreaViewShadowNode::ConcreteState::SharedData {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,9 @@ - (void)updateLayoutMetrics:(LayoutMetrics const &)layoutMetrics
{
[super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics];

#if TARGET_OS_OSX // [macOS
_backedTextInputView.pointScaleFactor = layoutMetrics.pointScaleFactor;
#endif // macOS]
_backedTextInputView.frame =
UIEdgeInsetsInsetRect(self.bounds, RCTUIEdgeInsetsFromEdgeInsets(layoutMetrics.borderWidth));
_backedTextInputView.textContainerInset =
Expand Down
61 changes: 3 additions & 58 deletions React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,6 @@ - (void)setPropKeysManagedByAnimated_DO_NOT_USE_THIS_IS_BROKEN:(NSSet<NSString *
return _propKeysManagedByAnimated_DO_NOT_USE_THIS_IS_BROKEN;
}

#if !TARGET_OS_OSX // [macOS]
- (RCTUIView *)betterHitTest:(CGPoint)point withEvent:(UIEvent *)event // [macOS]
{
// This is a classic textbook implementation of `hitTest:` with a couple of improvements:
Expand Down Expand Up @@ -511,60 +510,6 @@ - (RCTUIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event // [macOS]
return view != self ? view : nil;
}
}
#else // [macOS

- (RCTUIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event // [macOS]
{
BOOL canReceiveTouchEvents = ([self isUserInteractionEnabled] && ![self isHidden]);
if (!canReceiveTouchEvents) {
return nil;
}

// `hitSubview` is the topmost subview which was hit. The hit point can
// be outside the bounds of `view` (e.g., if -clipsToBounds is NO).
RCTUIView *hitSubview = nil; // [macOS]
BOOL isPointInside = [self pointInside:point withEvent:event];
BOOL needsHitSubview = !(_props->pointerEvents == PointerEventsMode::None || _props->pointerEvents == PointerEventsMode::BoxOnly);
if (needsHitSubview && (![self clipsToBounds] || isPointInside)) {
// Take z-index into account when calculating the touch target.
NSArray<RCTUIView *> *sortedSubviews = [self reactZIndexSortedSubviews]; // [macOS]

// The default behaviour of UIKit is that if a view does not contain a point,
// then no subviews will be returned from hit testing, even if they contain
// the hit point. By doing hit testing directly on the subviews, we bypass
// the strict containment policy (i.e., UIKit guarantees that every ancestor
// of the hit view will return YES from -pointInside:withEvent:). See:
// - https://developer.apple.com/library/ios/qa/qa2013/qa1812.html
for (RCTUIView *subview in [sortedSubviews reverseObjectEnumerator]) { // [macOS]
CGPoint pointForHitTest = CGPointZero;
if ([subview isKindOfClass:[RCTUIView class]]) { // [macOS]
pointForHitTest = [subview convertPoint:point fromView:self];
} else {
pointForHitTest = point;
}
hitSubview = (RCTUIView *)[subview hitTest:pointForHitTest]; // [macOS]
if (hitSubview != nil) {
break;
}
}
}

RCTUIView *hitView = (isPointInside ? self : nil); // [macOS]

switch (_props->pointerEvents) {
case PointerEventsMode::None:
return nil;
case PointerEventsMode::Auto:
return hitSubview ?: hitView;
case PointerEventsMode::BoxOnly:
return hitView;
case PointerEventsMode::BoxNone:
return hitSubview;
default:
return hitSubview ?: hitView;
}
}
#endif // macOS]

static RCTCornerRadii RCTCornerRadiiFromBorderRadii(BorderRadii borderRadii)
{
Expand Down Expand Up @@ -689,7 +634,7 @@ - (void)invalidateLayer
RCTBorderColors borderColors = RCTCreateRCTBorderColorsFromBorderColors(borderMetrics.borderColors);

#if TARGET_OS_OSX // [macOS
CGFloat scaleFactor = self.window.backingScaleFactor;
CGFloat scaleFactor = _layoutMetrics.pointScaleFactor;
#else
// On iOS setting the scaleFactor to 0.0 will default to the device's native scale factor.
CGFloat scaleFactor = 0.0;
Expand All @@ -714,13 +659,13 @@ - (void)invalidateLayer
CGRect contentsCenter = CGRect{
CGPoint{imageCapInsets.left / imageSize.width, imageCapInsets.top / imageSize.height},
CGSize{(CGFloat)1.0 / imageSize.width, (CGFloat)1.0 / imageSize.height}};

#if !TARGET_OS_OSX // [macOS]
_borderLayer.contents = (id)image.CGImage;
_borderLayer.contentsScale = image.scale;
#else // [macOS
_borderLayer.contents = [image layerContentsForContentsScale:scaleFactor];
_borderLayer.contentsScale = RCTScreenScale();
_borderLayer.contentsScale = scaleFactor;
#endif // macOS]

BOOL isResizable = !UIEdgeInsetsEqualToEdgeInsets(image.capInsets, UIEdgeInsetsZero);
Expand Down
Loading