diff --git a/Libraries/Image/RCTImageLoader.mm b/Libraries/Image/RCTImageLoader.mm index 6052cebcbe0..5bb3b124867 100644 --- a/Libraries/Image/RCTImageLoader.mm +++ b/Libraries/Image/RCTImageLoader.mm @@ -15,6 +15,7 @@ #import #import #import +#import #import #import #import @@ -22,13 +23,15 @@ #import "RCTImagePlugins.h" +using namespace facebook::react; + static NSInteger RCTImageBytesForImage(UIImage *image) { NSInteger singleImageBytes = image.size.width * image.size.height * image.scale * image.scale * 4; return image.images ? image.images.count * singleImageBytes : singleImageBytes; } -@interface RCTImageLoader() +@interface RCTImageLoader() @end @@ -288,11 +291,32 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image, scale:1 clipped:YES resizeMode:RCTResizeModeStretch + attribution:{} progressBlock:nil partialLoadBlock:nil completionBlock:callback]; } +- (RCTImageLoaderCancellationBlock)loadImageWithURLRequest:(NSURLRequest *)imageURLRequest + size:(CGSize)size + scale:(CGFloat)scale + clipped:(BOOL)clipped + resizeMode:(RCTResizeMode)resizeMode + progressBlock:(RCTImageLoaderProgressBlock)progressBlock + partialLoadBlock:(RCTImageLoaderPartialLoadBlock)partialLoadBlock + completionBlock:(RCTImageLoaderCompletionBlock)completionBlock +{ + return [self loadImageWithURLRequest:imageURLRequest + size:size + scale:scale + clipped:clipped + resizeMode:resizeMode + attribution:{} + progressBlock:progressBlock + partialLoadBlock:partialLoadBlock + completionBlock:completionBlock]; +} + - (void)dequeueTasks { dispatch_async(_URLRequestQueue, ^{ @@ -363,6 +387,7 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image, size:(CGSize)size scale:(CGFloat)scale resizeMode:(RCTResizeMode)resizeMode + attribution:(const ImageURLLoaderAttribution &)attribution progressBlock:(RCTImageLoaderProgressBlock)progressHandler partialLoadBlock:(RCTImageLoaderPartialLoadBlock)partialLoadHandler completionBlock:(void (^)(NSError *error, id imageOrData, BOOL cacheResult, NSURLResponse *response))completionBlock @@ -383,6 +408,9 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image, request = mutableRequest; } + // Create a copy here so the value is retained when accessed in the blocks below. + ImageURLLoaderAttribution attributionCopy(attribution); + // Find suitable image URL loader id loadHandler = [self imageURLLoaderForURL:request.URL]; BOOL requiresScheduling = [loadHandler respondsToSelector:@selector(requiresScheduling)] ? @@ -417,13 +445,25 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image, // If the loader doesn't require scheduling we call it directly on // the main queue. if (loadHandler && !requiresScheduling) { + if ([loadHandler conformsToProtocol:@protocol(RCTImageURLLoaderWithAttribution)]) { + return [(id)loadHandler loadImageForURL:request.URL + size:size + scale:scale + resizeMode:resizeMode + attribution:attributionCopy + progressHandler:progressHandler + partialLoadHandler:partialLoadHandler + completionHandler:^(NSError *error, UIImage *image) { + completionHandler(error, image, nil); + }]; + } return [loadHandler loadImageForURL:request.URL size:size scale:scale resizeMode:resizeMode progressHandler:progressHandler partialLoadHandler:partialLoadHandler - completionHandler:^(NSError *error, UIImage *image){ + completionHandler:^(NSError *error, UIImage *image) { completionHandler(error, image, nil); }]; } @@ -441,15 +481,29 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image, } if (loadHandler) { - dispatch_block_t cancelLoadLocal = [loadHandler loadImageForURL:request.URL - size:size - scale:scale - resizeMode:resizeMode - progressHandler:progressHandler - partialLoadHandler:partialLoadHandler - completionHandler:^(NSError *error, UIImage *image) { - completionHandler(error, image, nil); - }]; + dispatch_block_t cancelLoadLocal; + if ([loadHandler conformsToProtocol:@protocol(RCTImageURLLoaderWithAttribution)]) { + cancelLoadLocal = [(id)loadHandler loadImageForURL:request.URL + size:size + scale:scale + resizeMode:resizeMode + attribution:attributionCopy + progressHandler:progressHandler + partialLoadHandler:partialLoadHandler + completionHandler:^(NSError *error, UIImage *image) { + completionHandler(error, image, nil); + }]; + } else { + cancelLoadLocal = [loadHandler loadImageForURL:request.URL + size:size + scale:scale + resizeMode:resizeMode + progressHandler:progressHandler + partialLoadHandler:partialLoadHandler + completionHandler:^(NSError *error, UIImage *image) { + completionHandler(error, image, nil); + }]; + } [cancelLoadLock lock]; cancelLoad = cancelLoadLocal; [cancelLoadLock unlock]; @@ -607,6 +661,7 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image, scale:(CGFloat)scale clipped:(BOOL)clipped resizeMode:(RCTResizeMode)resizeMode + attribution:(const ImageURLLoaderAttribution &)attribution progressBlock:(RCTImageLoaderProgressBlock)progressBlock partialLoadBlock:(RCTImageLoaderPartialLoadBlock)partialLoadBlock completionBlock:(RCTImageLoaderCompletionBlock)completionBlock @@ -673,6 +728,7 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image, size:size scale:scale resizeMode:resizeMode + attribution:attribution progressBlock:progressBlock partialLoadBlock:partialLoadBlock completionBlock:completionHandler]; @@ -830,6 +886,7 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image, size:CGSizeZero scale:1 resizeMode:RCTResizeModeStretch + attribution:{} progressBlock:NULL partialLoadBlock:NULL completionBlock:completion]; diff --git a/Libraries/Image/RCTImageLoaderProtocol.h b/Libraries/Image/RCTImageLoaderProtocol.h index 801f77f4090..6b17cc7bcb9 100644 --- a/Libraries/Image/RCTImageLoaderProtocol.h +++ b/Libraries/Image/RCTImageLoaderProtocol.h @@ -113,4 +113,5 @@ * protocol. This method should be called in bridgeDidInitializeModule. */ - (void)setImageCache:(id)cache; + @end diff --git a/Libraries/Image/RCTImageLoaderWithAttributionProtocol.h b/Libraries/Image/RCTImageLoaderWithAttributionProtocol.h new file mode 100644 index 00000000000..2e9d20ec543 --- /dev/null +++ b/Libraries/Image/RCTImageLoaderWithAttributionProtocol.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import +#import + +@protocol RCTImageLoaderWithAttributionProtocol + +/** + * Same as the variant in RCTImageURLLoaderProtocol, but allows passing attribution + * information that each image URL loader can process. + */ +- (RCTImageLoaderCancellationBlock)loadImageWithURLRequest:(NSURLRequest *)imageURLRequest + size:(CGSize)size + scale:(CGFloat)scale + clipped:(BOOL)clipped + resizeMode:(RCTResizeMode)resizeMode + attribution:(const facebook::react::ImageURLLoaderAttribution &)attribution + progressBlock:(RCTImageLoaderProgressBlock)progressBlock + partialLoadBlock:(RCTImageLoaderPartialLoadBlock)partialLoadBlock + completionBlock:(RCTImageLoaderCompletionBlock)completionBlock; + +@end diff --git a/Libraries/Image/RCTImageURLLoaderWithAttribution.h b/Libraries/Image/RCTImageURLLoaderWithAttribution.h new file mode 100644 index 00000000000..9de3e31f420 --- /dev/null +++ b/Libraries/Image/RCTImageURLLoaderWithAttribution.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +namespace facebook { +namespace react { + +struct ImageURLLoaderAttribution { + int32_t surfaceId = 0; +}; + +} // namespace react +} // namespace facebook + +/** + * Same as the RCTImageURLLoader interface, but allows passing in optional `attribution` information. + * This is useful for per-app logging and other instrumentation. + */ +@protocol RCTImageURLLoaderWithAttribution + +/** + * Same as the RCTImageURLLoader variant above, but allows optional `attribution` information. + */ +- (RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL + size:(CGSize)size + scale:(CGFloat)scale + resizeMode:(RCTResizeMode)resizeMode + attribution:(const facebook::react::ImageURLLoaderAttribution &)attribution + progressHandler:(RCTImageLoaderProgressBlock)progressHandler + partialLoadHandler:(RCTImageLoaderPartialLoadBlock)partialLoadHandler + completionHandler:(RCTImageLoaderCompletionBlock)completionHandler; + +@end diff --git a/Libraries/Image/RCTImageView.m b/Libraries/Image/RCTImageView.mm similarity index 100% rename from Libraries/Image/RCTImageView.m rename to Libraries/Image/RCTImageView.mm diff --git a/Libraries/Image/RCTImageViewManager.m b/Libraries/Image/RCTImageViewManager.mm similarity index 100% rename from Libraries/Image/RCTImageViewManager.m rename to Libraries/Image/RCTImageViewManager.mm