feat(RCTUIKit): Shim RCTUIGraphicsImageRenderer (#2209)
* feat(RCTUIKit): Shim RCTUIGraphicsImageRenderer * Update RCTBorderDrawing.m * `[RCTUIGraphicsImageRendererFormat defaultFormat]` doesn't return a singleton * `[NSImage lockFocus]` is deprecated. Use a newer API. * fix typo * Implement `format.opaque`
This commit is contained in:
Родитель
3ebf897664
Коммит
2d866c826b
|
@ -25,23 +25,22 @@ UIImage *RCTBlurredImageWithRadius(UIImage *inputImage, CGFloat radius)
|
|||
|
||||
// convert to ARGB if it isn't
|
||||
if (CGImageGetBitsPerPixel(imageRef) != 32 || !((CGImageGetBitmapInfo(imageRef) & kCGBitmapAlphaInfoMask))) {
|
||||
#if !TARGET_OS_OSX // [macOS]
|
||||
UIGraphicsImageRendererFormat *const rendererFormat = [UIGraphicsImageRendererFormat defaultFormat];
|
||||
rendererFormat.scale = inputImage.scale;
|
||||
UIGraphicsImageRenderer *const renderer = [[UIGraphicsImageRenderer alloc] initWithSize:inputImage.size
|
||||
format:rendererFormat];
|
||||
RCTUIGraphicsImageRendererFormat *const rendererFormat = [RCTUIGraphicsImageRendererFormat defaultFormat]; // [macOS]
|
||||
rendererFormat.scale = UIImageGetScale(inputImage); // [macOS]
|
||||
RCTUIGraphicsImageRenderer *const renderer = [[RCTUIGraphicsImageRenderer alloc] initWithSize:inputImage.size // [macOS]
|
||||
format:rendererFormat];
|
||||
|
||||
#if !TARGET_OS_OSX // [macOS]
|
||||
imageRef = [renderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull context) {
|
||||
[inputImage drawAtPoint:CGPointZero];
|
||||
}].CGImage;
|
||||
#else // [macOS
|
||||
UIGraphicsBeginImageContextWithOptions(inputImage.size, NO, imageScale);
|
||||
[inputImage drawAtPoint:CGPointZero fromRect:NSZeroRect operation:NSCompositingOperationSourceOver fraction:1.0];
|
||||
imageRef = (CGImageRef)CFAutorelease(CGBitmapContextCreateImage(UIGraphicsGetCurrentContext()));
|
||||
UIGraphicsEndImageContext();
|
||||
NSImage *image = [renderer imageWithActions:^(RCTUIGraphicsImageRendererContext *_Nonnull context) {
|
||||
[inputImage drawAtPoint:CGPointZero fromRect:NSZeroRect operation:NSCompositingOperationSourceOver fraction:1.0];
|
||||
}];
|
||||
imageRef = UIImageGetCGImageRef(image);
|
||||
#endif // macOS]
|
||||
}
|
||||
|
||||
vImage_Buffer buffer1, buffer2;
|
||||
buffer1.width = buffer2.width = CGImageGetWidth(imageRef);
|
||||
buffer1.height = buffer2.height = CGImageGetHeight(imageRef);
|
||||
|
|
|
@ -382,25 +382,19 @@ UIImage *__nullable RCTTransformImage(UIImage *image, CGSize destSize, CGFloat d
|
|||
}
|
||||
|
||||
BOOL opaque = !RCTUIImageHasAlpha(image); // [macOS]
|
||||
#if !TARGET_OS_OSX // [macOS]
|
||||
UIGraphicsImageRendererFormat *const rendererFormat = [UIGraphicsImageRendererFormat defaultFormat];
|
||||
RCTUIGraphicsImageRendererFormat *const rendererFormat = [RCTUIGraphicsImageRendererFormat defaultFormat]; // [macOS]
|
||||
rendererFormat.opaque = opaque;
|
||||
rendererFormat.scale = destScale;
|
||||
UIGraphicsImageRenderer *const renderer = [[UIGraphicsImageRenderer alloc] initWithSize:destSize
|
||||
RCTUIGraphicsImageRenderer *const renderer = [[RCTUIGraphicsImageRenderer alloc] initWithSize:destSize // [macOS]
|
||||
format:rendererFormat];
|
||||
return [renderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull context) {
|
||||
return [renderer imageWithActions:^(RCTUIGraphicsImageRendererContext *_Nonnull context) { // [macOS]
|
||||
CGContextConcatCTM(context.CGContext, transform);
|
||||
#if !TARGET_OS_OSX // [macOS]
|
||||
[image drawAtPoint:CGPointZero];
|
||||
}];
|
||||
#else // [macOS
|
||||
UIGraphicsBeginImageContextWithOptions(destSize, opaque, destScale);
|
||||
CGContextRef currentContext = UIGraphicsGetCurrentContext();
|
||||
CGContextConcatCTM(currentContext, transform);
|
||||
[image drawAtPoint:CGPointZero fromRect:NSZeroRect operation:NSCompositingOperationSourceOver fraction:1.0];
|
||||
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
return result;
|
||||
[image drawAtPoint:CGPointZero fromRect:NSZeroRect operation:NSCompositingOperationSourceOver fraction:1.0];
|
||||
#endif // macOS]
|
||||
}];
|
||||
}
|
||||
|
||||
BOOL RCTImageHasAlpha(CGImageRef image)
|
||||
|
|
|
@ -269,9 +269,6 @@ extern "C" {
|
|||
|
||||
// UIGraphics.h
|
||||
CGContextRef UIGraphicsGetCurrentContext(void);
|
||||
void UIGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale);
|
||||
NSImage *UIGraphicsGetImageFromCurrentImageContext(void);
|
||||
void UIGraphicsEndImageContext(void);
|
||||
CGImageRef UIImageGetCGImageRef(NSImage *image);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -641,3 +638,31 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
NS_ASSUME_NONNULL_END
|
||||
@end
|
||||
#endif
|
||||
|
||||
#if !TARGET_OS_OSX
|
||||
typedef UIGraphicsImageRendererContext RCTUIGraphicsImageRendererContext;
|
||||
typedef UIGraphicsImageDrawingActions RCTUIGraphicsImageDrawingActions;
|
||||
typedef UIGraphicsImageRendererFormat RCTUIGraphicsImageRendererFormat;
|
||||
typedef UIGraphicsImageRenderer RCTUIGraphicsImageRenderer;
|
||||
#else
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
typedef NSGraphicsContext RCTUIGraphicsImageRendererContext;
|
||||
typedef void (^RCTUIGraphicsImageDrawingActions)(RCTUIGraphicsImageRendererContext *rendererContext);
|
||||
|
||||
@interface RCTUIGraphicsImageRendererFormat : NSObject
|
||||
|
||||
+ (instancetype)defaultFormat;
|
||||
|
||||
@property (nonatomic) CGFloat scale;
|
||||
@property (nonatomic) BOOL opaque;
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTUIGraphicsImageRenderer : NSObject
|
||||
|
||||
- (instancetype)initWithSize:(CGSize)size format:(RCTUIGraphicsImageRendererFormat *)format;
|
||||
- (NSImage *)imageWithActions:(NS_NOESCAPE RCTUIGraphicsImageDrawingActions)actions;
|
||||
|
||||
@end
|
||||
NS_ASSUME_NONNULL_END
|
||||
#endif
|
||||
|
|
|
@ -32,37 +32,6 @@ CGContextRef UIGraphicsGetCurrentContext(void)
|
|||
return [[NSGraphicsContext currentContext] CGContext];
|
||||
}
|
||||
|
||||
void UIGraphicsBeginImageContextWithOptions(CGSize size, __unused BOOL opaque, CGFloat scale)
|
||||
{
|
||||
if (scale == 0.0)
|
||||
{
|
||||
// TODO: Assert. We can't assume a display scale on macOS
|
||||
scale = 1.0;
|
||||
}
|
||||
|
||||
size_t width = ceilf(size.width * scale);
|
||||
size_t height = ceilf(size.height * scale);
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGContextRef ctx = CGBitmapContextCreate(NULL, width, height, 8/*bitsPerComponent*/, width * 4/*bytesPerRow*/, colorSpace, kCGImageAlphaPremultipliedFirst);
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
|
||||
if (ctx != NULL)
|
||||
{
|
||||
// flip the context (top left at 0, 0) and scale it
|
||||
CGContextTranslateCTM(ctx, 0.0, height);
|
||||
CGContextScaleCTM(ctx, scale, -scale);
|
||||
|
||||
NSGraphicsContext *graphicsContext = [NSGraphicsContext graphicsContextWithCGContext:ctx flipped:YES];
|
||||
objc_setAssociatedObject(graphicsContext, &RCTGraphicsContextSizeKey, [NSValue valueWithSize:size], OBJC_ASSOCIATION_COPY_NONATOMIC);
|
||||
|
||||
[NSGraphicsContext saveGraphicsState];
|
||||
[NSGraphicsContext setCurrentContext:graphicsContext];
|
||||
|
||||
CFRelease(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
NSImage *UIGraphicsGetImageFromCurrentImageContext(void)
|
||||
{
|
||||
NSImage *image = nil;
|
||||
|
@ -83,12 +52,6 @@ NSImage *UIGraphicsGetImageFromCurrentImageContext(void)
|
|||
return image;
|
||||
}
|
||||
|
||||
void UIGraphicsEndImageContext(void)
|
||||
{
|
||||
RCTAssert(objc_getAssociatedObject([NSGraphicsContext currentContext], &RCTGraphicsContextSizeKey), @"The current graphics context is not a React image context!");
|
||||
[NSGraphicsContext restoreGraphicsState];
|
||||
}
|
||||
|
||||
//
|
||||
// functionally equivalent types
|
||||
//
|
||||
|
@ -1040,4 +1003,45 @@ BOOL RCTUIViewSetClipsToBounds(RCTPlatformView *view)
|
|||
|
||||
@end
|
||||
|
||||
@implementation RCTUIGraphicsImageRendererFormat
|
||||
|
||||
+ (nonnull instancetype)defaultFormat {
|
||||
RCTUIGraphicsImageRendererFormat *format = [RCTUIGraphicsImageRendererFormat new];
|
||||
return format;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTUIGraphicsImageRenderer
|
||||
{
|
||||
CGSize _size;
|
||||
RCTUIGraphicsImageRendererFormat *_format;
|
||||
}
|
||||
|
||||
- (nonnull instancetype)initWithSize:(CGSize)size format:(nonnull RCTUIGraphicsImageRendererFormat *)format {
|
||||
if (self = [super init]) {
|
||||
self->_size = size;
|
||||
self->_format = format;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (nonnull NSImage *)imageWithActions:(NS_NOESCAPE RCTUIGraphicsImageDrawingActions)actions {
|
||||
|
||||
NSImage *image = [NSImage imageWithSize:_size
|
||||
flipped:YES
|
||||
drawingHandler:^BOOL(NSRect dstRect) {
|
||||
|
||||
RCTUIGraphicsImageRendererContext *context = [NSGraphicsContext currentContext];
|
||||
if (self->_format.opaque) {
|
||||
CGContextSetAlpha([context CGContext], 1.0);
|
||||
}
|
||||
actions(context);
|
||||
return YES;
|
||||
}];
|
||||
return image;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
|
|
@ -171,27 +171,16 @@ static CGPathRef RCTPathCreateOuterOutline(BOOL drawToEdge, CGRect rect, RCTCorn
|
|||
return RCTPathCreateWithRoundedRect(rect, RCTGetCornerInsets(cornerRadii, UIEdgeInsetsZero), NULL);
|
||||
}
|
||||
|
||||
#if !TARGET_OS_OSX // [macOS]
|
||||
static UIGraphicsImageRenderer *
|
||||
RCTUIGraphicsImageRenderer(CGSize size, CGColorRef backgroundColor, BOOL hasCornerRadii, BOOL drawToEdge)
|
||||
static RCTUIGraphicsImageRenderer * // [macOS]
|
||||
RCTMakeUIGraphicsImageRenderer(CGSize size, CGColorRef backgroundColor, BOOL hasCornerRadii, BOOL drawToEdge) // [macOS]
|
||||
{
|
||||
const CGFloat alpha = CGColorGetAlpha(backgroundColor);
|
||||
const BOOL opaque = (drawToEdge || !hasCornerRadii) && alpha == 1.0;
|
||||
UIGraphicsImageRendererFormat *const rendererFormat = [UIGraphicsImageRendererFormat defaultFormat];
|
||||
RCTUIGraphicsImageRendererFormat *const rendererFormat = [RCTUIGraphicsImageRendererFormat defaultFormat]; // [macOS]
|
||||
rendererFormat.opaque = opaque;
|
||||
UIGraphicsImageRenderer *const renderer = [[UIGraphicsImageRenderer alloc] initWithSize:size format:rendererFormat];
|
||||
RCTUIGraphicsImageRenderer *const renderer = [[RCTUIGraphicsImageRenderer alloc] initWithSize:size format:rendererFormat]; // [macOS]
|
||||
return renderer;
|
||||
}
|
||||
#else // [macOS
|
||||
static CGContextRef
|
||||
RCTUIGraphicsBeginImageContext(CGSize size, CGColorRef backgroundColor, BOOL hasCornerRadii, BOOL drawToEdge, CGFloat scaleFactor)
|
||||
{
|
||||
const CGFloat alpha = CGColorGetAlpha(backgroundColor);
|
||||
const BOOL opaque = (drawToEdge || !hasCornerRadii) && alpha == 1.0;
|
||||
UIGraphicsBeginImageContextWithOptions(size, opaque, scaleFactor);
|
||||
return UIGraphicsGetCurrentContext();
|
||||
}
|
||||
#endif // macOS]
|
||||
|
||||
static UIImage *RCTGetSolidBorderImage(
|
||||
RCTCornerRadii cornerRadii,
|
||||
|
@ -237,16 +226,11 @@ static UIImage *RCTGetSolidBorderImage(
|
|||
return nil;
|
||||
} // macOS]
|
||||
|
||||
#if !TARGET_OS_OSX // [macOS]
|
||||
UIGraphicsImageRenderer *const imageRenderer =
|
||||
RCTUIGraphicsImageRenderer(size, backgroundColor, hasCornerRadii, drawToEdge);
|
||||
UIImage *image = [imageRenderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull rendererContext) {
|
||||
RCTUIGraphicsImageRenderer *const imageRenderer =
|
||||
RCTMakeUIGraphicsImageRenderer(size, backgroundColor, hasCornerRadii, drawToEdge); // [macOS]
|
||||
CGColorRetain(backgroundColor); // [macOS] CGColorRefs are not atuomtically retained when passed into a block
|
||||
UIImage *image = [imageRenderer imageWithActions:^(RCTUIGraphicsImageRendererContext *_Nonnull rendererContext) { // [macOS]
|
||||
const CGContextRef context = rendererContext.CGContext;
|
||||
#else // [macOS
|
||||
CGContextRef context = RCTUIGraphicsBeginImageContext(size, backgroundColor, hasCornerRadii, drawToEdge, scaleFactor);
|
||||
// Add extra braces for scope to match the indentation level of the iOS block
|
||||
{
|
||||
#endif // macOS]
|
||||
const CGRect rect = {.size = size};
|
||||
CGPathRef path = RCTPathCreateOuterOutline(drawToEdge, rect, cornerRadii);
|
||||
|
||||
|
@ -255,6 +239,7 @@ static UIImage *RCTGetSolidBorderImage(
|
|||
CGContextAddPath(context, path);
|
||||
CGContextFillPath(context);
|
||||
}
|
||||
CGColorRelease(backgroundColor); // [macOS]
|
||||
|
||||
CGContextAddPath(context, path);
|
||||
CGPathRelease(path);
|
||||
|
@ -402,13 +387,7 @@ static UIImage *RCTGetSolidBorderImage(
|
|||
}
|
||||
|
||||
CGPathRelease(insetPath);
|
||||
#if !TARGET_OS_OSX // [macOS]
|
||||
}];
|
||||
#else // [macOS
|
||||
}
|
||||
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
#endif // macOS]
|
||||
|
||||
if (makeStretchable) {
|
||||
#if !TARGET_OS_OSX // [macOS]
|
||||
|
@ -509,16 +488,10 @@ static UIImage *RCTGetDashedOrDottedBorderImage(
|
|||
} // macOS]
|
||||
|
||||
const BOOL hasCornerRadii = RCTCornerRadiiAreAboveThreshold(cornerRadii);
|
||||
#if !TARGET_OS_OSX // [macOS]
|
||||
UIGraphicsImageRenderer *const imageRenderer =
|
||||
RCTUIGraphicsImageRenderer(viewSize, backgroundColor, hasCornerRadii, drawToEdge);
|
||||
return [imageRenderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull rendererContext) {
|
||||
RCTUIGraphicsImageRenderer *const imageRenderer = // [macOS]
|
||||
RCTMakeUIGraphicsImageRenderer(viewSize, backgroundColor, hasCornerRadii, drawToEdge); // [macOS]
|
||||
return [imageRenderer imageWithActions:^(RCTUIGraphicsImageRendererContext *_Nonnull rendererContext) { // [macOS]
|
||||
const CGContextRef context = rendererContext.CGContext;
|
||||
#else // [macOS
|
||||
CGContextRef context = RCTUIGraphicsBeginImageContext(viewSize, backgroundColor, hasCornerRadii, drawToEdge, scaleFactor);
|
||||
// Add extra braces for scope to match the indentation level of the iOS block
|
||||
{
|
||||
#endif // macOS]
|
||||
const CGRect rect = {.size = viewSize};
|
||||
|
||||
if (backgroundColor) {
|
||||
|
@ -549,14 +522,7 @@ static UIImage *RCTGetDashedOrDottedBorderImage(
|
|||
CGContextStrokePath(context);
|
||||
|
||||
CGPathRelease(path);
|
||||
#if !TARGET_OS_OSX // [macOS]
|
||||
}];
|
||||
#else // [macOS
|
||||
}
|
||||
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
return image;
|
||||
#endif // macOS]
|
||||
}
|
||||
|
||||
UIImage *RCTGetBorderImage(
|
||||
|
|
|
@ -16,20 +16,13 @@
|
|||
}
|
||||
CGSize imageSize = CGSizeMake(MAX(self.size.width, image.size.width), MAX(self.size.height, image.size.height));
|
||||
|
||||
#if !TARGET_OS_OSX // [macOS]
|
||||
UIGraphicsImageRendererFormat *const rendererFormat = [UIGraphicsImageRendererFormat defaultFormat];
|
||||
RCTUIGraphicsImageRendererFormat *const rendererFormat = [RCTUIGraphicsImageRendererFormat defaultFormat]; // [macOS]
|
||||
rendererFormat.opaque = YES;
|
||||
UIGraphicsImageRenderer *const renderer = [[UIGraphicsImageRenderer alloc] initWithSize:imageSize
|
||||
format:rendererFormat];
|
||||
RCTUIGraphicsImageRenderer *const renderer = [[RCTUIGraphicsImageRenderer alloc] initWithSize:imageSize // [macOS]
|
||||
format:rendererFormat];
|
||||
|
||||
return [renderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull rendererContext) {
|
||||
return [renderer imageWithActions:^(RCTUIGraphicsImageRendererContext *_Nonnull rendererContext) { // [macOS]
|
||||
const CGContextRef context = rendererContext.CGContext;
|
||||
#else // [macOS
|
||||
UIGraphicsBeginImageContextWithOptions(imageSize, YES, 0.0);
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
// Add extra braces for scope to match the indentation level of the iOS block
|
||||
{
|
||||
#endif // macOS]
|
||||
[self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)];
|
||||
CGContextSetAlpha(context, 0.5f);
|
||||
CGContextBeginTransparencyLayer(context, NULL);
|
||||
|
@ -38,14 +31,7 @@
|
|||
CGContextSetFillColorWithColor(context, [RCTUIColor whiteColor].CGColor);
|
||||
CGContextFillRect(context, CGRectMake(0, 0, self.size.width, self.size.height));
|
||||
CGContextEndTransparencyLayer(context);
|
||||
#if !TARGET_OS_OSX // [macOS]
|
||||
}];
|
||||
#else // [macOS
|
||||
}
|
||||
UIImage *returnImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
return returnImage;
|
||||
#endif // macOS]
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
Загрузка…
Ссылка в новой задаче