Skip to content

Commit 1256d56

Browse files
authored
# Summary On `react-native-macos` 0.76, `UIGraphicsBeginImageContextWithOptions` and some other UIGraphics directives were removed so the temporary solution is to copy the removed functions here. More details here #2528 and here microsoft/react-native-macos#2209 Closes #2528 ## Test Plan Built the `fabric-macos-example` for with `[email protected]` ## Compatibility | OS | Implemented | | ------- | :---------: | | MacOS | ✅ | ## Checklist - [x] I have tested this on a device and a simulator
1 parent d0530e4 commit 1256d56

File tree

19 files changed

+2719
-1885
lines changed

19 files changed

+2719
-1885
lines changed

apple/Elements/RNSVGSvgView.mm

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
#import "RNSVGFabricConversions.h"
2020
#endif // RCT_NEW_ARCH_ENABLED
2121

22+
#if TARGET_OS_OSX // [macOS
23+
#import "RNSVGUIKit.h"
24+
#endif // macOS]
25+
2226
@implementation RNSVGSvgView {
2327
NSMutableDictionary<NSString *, RNSVGNode *> *_clipPaths;
2428
NSMutableDictionary<NSString *, RNSVGNode *> *_templates;
@@ -368,7 +372,7 @@ - (NSString *)getDataURLWithBounds:(CGRect)bounds
368372
UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:bounds.size];
369373
UIImage *image = [renderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull rendererContext) {
370374
#else // [macOS
371-
UIGraphicsBeginImageContextWithOptions(bounds.size, NO, 1);
375+
RNSVGUIGraphicsBeginImageContextWithOptions(bounds.size, NO, 1);
372376
#endif // macOS]
373377
[self clearChildCache];
374378
[self drawRect:bounds];
@@ -381,9 +385,9 @@ - (NSString *)getDataURLWithBounds:(CGRect)bounds
381385
NSData *imageData = UIImagePNGRepresentation(image);
382386
NSString *base64 = [imageData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
383387
#else // [macOS
384-
NSData *imageData = UIImagePNGRepresentation(UIGraphicsGetImageFromCurrentImageContext());
388+
NSData *imageData = UIImagePNGRepresentation(RNSVGUIGraphicsGetImageFromCurrentImageContext());
385389
NSString *base64 = [imageData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
386-
UIGraphicsEndImageContext();
390+
RNSVGUIGraphicsEndImageContext();
387391
#endif // macOS]
388392
return base64;
389393
}

apple/Filters/RNSVGFilter.mm

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
#import "RNSVGFabricConversions.h"
1212
#endif // RCT_NEW_ARCH_ENABLED
1313

14+
#if TARGET_OS_OSX // [macOS
15+
#import "RNSVGUIKit.h"
16+
#endif // macOS]
17+
1418
@implementation RNSVGFilter {
1519
NSMutableDictionary<NSString *, CIImage *> *resultsMap;
1620
}
@@ -142,7 +146,7 @@ - (CIImage *)applyFilter:(CIImage *)img
142146

143147
- (CGContext *)openContext:(CGSize)size
144148
{
145-
UIGraphicsBeginImageContextWithOptions(size, NO, 1.0);
149+
RNSVGUIGraphicsBeginImageContextWithOptions(size, NO, 1.0);
146150
CGContextRef cropContext = UIGraphicsGetCurrentContext();
147151
#if TARGET_OS_OSX
148152
CGFloat scale = [RNSVGRenderUtils getScreenScale];
@@ -156,7 +160,7 @@ - (CGContext *)openContext:(CGSize)size
156160

157161
- (void)endContext:(CGContext *)context
158162
{
159-
UIGraphicsEndImageContext();
163+
RNSVGUIGraphicsEndImageContext();
160164
}
161165

162166
- (CIImage *)getMaskFromRect:(CGContext *)context rect:(CGRect)rect ctm:(CGAffineTransform)ctm

apple/RNSVGRenderable.mm

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ - (void)renderTo:(CGContextRef)context rect:(CGRect)rect
406406
[blendedImage drawInRect:scaledRect];
407407
#else // [macOS
408408
// Blend current element and mask
409-
UIGraphicsBeginImageContextWithOptions(rect.size, NO, scale);
409+
RNSVGUIGraphicsBeginImageContextWithOptions(rect.size, NO, scale);
410410
CGContextRef newContext = UIGraphicsGetCurrentContext();
411411

412412
CGContextSetBlendMode(newContext, kCGBlendModeCopy);
@@ -415,7 +415,7 @@ - (void)renderTo:(CGContextRef)context rect:(CGRect)rect
415415
CGContextDrawImage(newContext, rect, contentImage);
416416

417417
CGImageRef blendedImage = CGBitmapContextCreateImage(newContext);
418-
UIGraphicsEndImageContext();
418+
RNSVGUIGraphicsEndImageContext();
419419

420420
// Invert the CTM and apply transformations to draw image in 1:1
421421
CGContextConcatCTM(context, CGAffineTransformInvert(currentCTM));

apple/RNSVGRenderableModule.mm

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,8 @@ @implementation RNSVGRenderableModule
155155
bounds = CGRectIntersection(bounds, clipBounds);
156156
}
157157
}
158-
if (CGRectIsNull(bounds)) bounds = CGRectZero;
158+
if (CGRectIsNull(bounds))
159+
bounds = CGRectZero;
159160
CGPoint origin = bounds.origin;
160161
CGSize size = bounds.size;
161162
return @{@"x" : @(origin.x), @"y" : @(origin.y), @"width" : @(size.width), @"height" : @(size.height)};

apple/RNSVGUIKit.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
#define RNSVGView UIView
1818
#endif // RCT_NEW_ARCH_ENABLED
1919

20+
#define RNSVGUIGraphicsBeginImageContextWithOptions UIGraphicsBeginImageContextWithOptions
21+
#define RNSVGUIGraphicsEndImageContext UIGraphicsEndImageContext
22+
#define RNSVGUIGraphicsGetImageFromCurrentImageContext UIGraphicsGetImageFromCurrentImageContext
23+
2024
#else // TARGET_OS_OSX [
2125

2226
// Due to name mangling, calling c-style functions from .mm files will fail, therefore we need to wrap them with extern
@@ -67,4 +71,11 @@ extern "C" {
6771
@property (readonly) CGPoint CGPointValue;
6872
@end
6973

74+
// These functions are copied from react-native-macos to enable compatibility with [email protected]+
75+
// https://github.com/microsoft/react-native-macos/blob/7361b165ef633d3d95dbdb69da58ff6119f07369/packages/react-native/React/Base/macOS/RCTUIKit.m
76+
// See https://github.com/software-mansion/react-native-svg/issues/2528
77+
void RNSVGUIGraphicsBeginImageContextWithOptions(CGSize size, __unused BOOL opaque, CGFloat scale);
78+
void RNSVGUIGraphicsEndImageContext(void);
79+
NSImage *RNSVGUIGraphicsGetImageFromCurrentImageContext(void);
80+
7081
#endif // ] TARGET_OS_OSX

apple/RNSVGUIKit.macos.mm

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#import "RNSVGUIKit.h"
2+
#import <objc/runtime.h>
23

34
@implementation RNSVGView {
45
}
@@ -57,3 +58,70 @@ - (CGPoint)CGPointValue
5758
}
5859

5960
@end
61+
62+
static char RCTGraphicsContextSizeKey;
63+
64+
void RNSVGUIGraphicsBeginImageContextWithOptions(CGSize size, __unused BOOL opaque, CGFloat scale)
65+
{
66+
if (scale == 0.0) {
67+
// TODO: Assert. We can't assume a display scale on macOS
68+
scale = 1.0;
69+
}
70+
71+
size_t width = ceilf(size.width * scale);
72+
size_t height = ceilf(size.height * scale);
73+
74+
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
75+
CGContextRef ctx = CGBitmapContextCreate(
76+
NULL,
77+
width,
78+
height,
79+
8 /*bitsPerComponent*/,
80+
width * 4 /*bytesPerRow*/,
81+
colorSpace,
82+
kCGImageAlphaPremultipliedFirst);
83+
CGColorSpaceRelease(colorSpace);
84+
85+
if (ctx != NULL) {
86+
// flip the context (top left at 0, 0) and scale it
87+
CGContextTranslateCTM(ctx, 0.0, height);
88+
CGContextScaleCTM(ctx, scale, -scale);
89+
90+
NSGraphicsContext *graphicsContext = [NSGraphicsContext graphicsContextWithCGContext:ctx flipped:YES];
91+
objc_setAssociatedObject(
92+
graphicsContext, &RCTGraphicsContextSizeKey, [NSValue valueWithSize:size], OBJC_ASSOCIATION_COPY_NONATOMIC);
93+
94+
[NSGraphicsContext saveGraphicsState];
95+
[NSGraphicsContext setCurrentContext:graphicsContext];
96+
97+
CFRelease(ctx);
98+
}
99+
}
100+
101+
void RNSVGUIGraphicsEndImageContext(void)
102+
{
103+
RCTAssert(
104+
objc_getAssociatedObject([NSGraphicsContext currentContext], &RCTGraphicsContextSizeKey),
105+
@"The current graphics context is not a React image context!");
106+
[NSGraphicsContext restoreGraphicsState];
107+
}
108+
109+
NSImage *RNSVGUIGraphicsGetImageFromCurrentImageContext(void)
110+
{
111+
NSImage *image = nil;
112+
NSGraphicsContext *graphicsContext = [NSGraphicsContext currentContext];
113+
114+
NSValue *sizeValue = objc_getAssociatedObject(graphicsContext, &RCTGraphicsContextSizeKey);
115+
if (sizeValue != nil) {
116+
CGImageRef cgImage = CGBitmapContextCreateImage([graphicsContext CGContext]);
117+
118+
if (cgImage != NULL) {
119+
NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage];
120+
image = [[NSImage alloc] initWithSize:[sizeValue sizeValue]];
121+
[image addRepresentation:imageRep];
122+
CFRelease(cgImage);
123+
}
124+
}
125+
126+
return image;
127+
}

apple/Utils/RNSVGRenderUtils.mm

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ + (CGImage *)renderToImage:(RNSVGRenderable *)renderable
3737
{
3838
CGFloat scale = [self getScreenScale];
3939
#if TARGET_OS_OSX // [macOS
40-
UIGraphicsBeginImageContextWithOptions(rect.size, NO, 1.0);
40+
RNSVGUIGraphicsBeginImageContextWithOptions(rect.size, NO, 1.0);
4141
#else // macOS]
42-
UIGraphicsBeginImageContextWithOptions(rect.size, NO, scale);
42+
RNSVGUIGraphicsBeginImageContextWithOptions(rect.size, NO, scale);
4343
#endif // [macOS]
4444
CGContextRef cgContext = UIGraphicsGetCurrentContext();
4545
CGContextConcatCTM(cgContext, CGAffineTransformInvert(CGContextGetCTM(cgContext)));
@@ -53,7 +53,7 @@ + (CGImage *)renderToImage:(RNSVGRenderable *)renderable
5353
}
5454
[renderable renderLayerTo:cgContext rect:rect];
5555
CGImageRef contentImage = CGBitmapContextCreateImage(cgContext);
56-
UIGraphicsEndImageContext();
56+
RNSVGUIGraphicsEndImageContext();
5757
return contentImage;
5858
}
5959

apps/fabric-macos-example/.gitignore

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ DerivedData
2020
*.hmap
2121
*.ipa
2222
*.xcuserstate
23-
ios/.xcode.env.local
23+
**/.xcode.env.local
2424

2525
# Android/IntelliJ
2626
#
@@ -56,11 +56,19 @@ yarn-error.log
5656
*.jsbundle
5757

5858
# Ruby / CocoaPods
59-
/ios/Pods/
59+
**/Pods/
6060
/vendor/bundle/
6161

6262
# Temporary files created by Metro to check the health of the file watcher
6363
.metro-health-check*
6464

6565
# testing
6666
/coverage
67+
68+
# Yarn
69+
.yarn/*
70+
!.yarn/patches
71+
!.yarn/plugins
72+
!.yarn/releases
73+
!.yarn/sdks
74+
!.yarn/versions

apps/fabric-macos-example/Gemfile

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ source 'https://rubygems.org'
33
# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
44
ruby ">= 2.6.10"
55

6-
# Cocoapods 1.15 introduced a bug which break the build. We will remove the upper
7-
# bound in the template on Cocoapods with next React Native release.
8-
gem 'cocoapods', '>= 1.13', '< 1.15'
9-
gem 'activesupport', '>= 6.1.7.5', '< 7.1.0'
6+
# Exclude problematic versions of cocoapods and activesupport that causes build failures.
7+
gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1'
8+
gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0'
9+
gem 'xcodeproj', '< 1.26.0'

apps/fabric-macos-example/Gemfile.lock

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,9 @@ PLATFORMS
9393
ruby
9494

9595
DEPENDENCIES
96-
activesupport (>= 6.1.7.5, < 7.1.0)
97-
cocoapods (>= 1.13, < 1.15)
96+
activesupport (>= 6.1.7.5, != 7.1.0)
97+
cocoapods (>= 1.13, != 1.15.1, != 1.15.0)
98+
xcodeproj (< 1.26.0)
9899

99100
RUBY VERSION
100101
ruby 2.7.6p219

0 commit comments

Comments
 (0)