Skip to content
Closed
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
93 changes: 55 additions & 38 deletions packages/react-native/Libraries/Image/RCTImageLoader.mm
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@ @implementation RCTImageLoader {
NSArray<id<RCTImageURLLoader>> * (^_loadersProvider)(RCTModuleRegistry *);
NSArray<id<RCTImageDataDecoder>> * (^_decodersProvider)(RCTModuleRegistry *);
NSArray<id<RCTImageURLLoader>> *_loaders;
std::atomic<BOOL> _loadersReady;
NSArray<id<RCTImageDataDecoder>> *_decoders;
std::atomic<BOOL> _decodersReady;
NSOperationQueue *_imageDecodeQueue;
dispatch_queue_t _URLRequestQueue;
id<RCTImageCache> _imageCache;
Expand Down Expand Up @@ -161,23 +163,17 @@ - (void)setImageCache:(id<RCTImageCache>)cache
_imageCache = cache;
}

- (id<RCTImageURLLoader>)imageURLLoaderForURL:(NSURL *)URL
- (NSArray<id<RCTImageURLLoader>> *)loaders
{
if (!_isLoaderSetup) {
[self setUp];
}

if (!_loaders) {
std::unique_lock<std::mutex> guard(_loadersMutex);
if (!_loaders) {
// Get loaders, sorted in reverse priority order (highest priority first)
if (!_loadersReady.load(std::memory_order_acquire)) {
std::lock_guard<std::mutex> guard(_loadersMutex);
if (!_loadersReady.load(std::memory_order_relaxed)) {
if (_loadersProvider) {
_loaders = _loadersProvider(self.moduleRegistry);
} else {
RCTAssert(_bridge, @"Trying to find RCTImageURLLoaders and bridge not set.");
_loaders = [_bridge modulesConformingToProtocol:@protocol(RCTImageURLLoader)];
}

_loaders =
[_loaders sortedArrayUsingComparator:^NSComparisonResult(id<RCTImageURLLoader> a, id<RCTImageURLLoader> b) {
float priorityA = [a respondsToSelector:@selector(loaderPriority)] ? [a loaderPriority] : 0;
Expand All @@ -190,14 +186,54 @@ - (void)setImageCache:(id<RCTImageCache>)cache
return NSOrderedSame;
}
}];
_loadersReady.store(YES, std::memory_order_release);
}
}
return _loaders;
}

- (NSArray<id<RCTImageDataDecoder>> *)decoders
{
if (!_decodersReady.load(std::memory_order_acquire)) {
std::lock_guard<std::mutex> guard(_loadersMutex);
if (!_decodersReady.load(std::memory_order_relaxed)) {
if (_decodersProvider) {
_decoders = _decodersProvider(self.moduleRegistry);
} else {
RCTAssert(_bridge, @"Trying to find RCTImageDataDecoders and bridge not set.");
_decoders = [_bridge modulesConformingToProtocol:@protocol(RCTImageDataDecoder)];
}
_decoders = [_decoders
sortedArrayUsingComparator:^NSComparisonResult(id<RCTImageDataDecoder> a, id<RCTImageDataDecoder> b) {
float priorityA = [a respondsToSelector:@selector(decoderPriority)] ? [a decoderPriority] : 0;
float priorityB = [b respondsToSelector:@selector(decoderPriority)] ? [b decoderPriority] : 0;
if (priorityA > priorityB) {
return NSOrderedAscending;
} else if (priorityA < priorityB) {
return NSOrderedDescending;
} else {
return NSOrderedSame;
}
}];
_decodersReady.store(YES, std::memory_order_release);
}
}
return _decoders;
}

- (id<RCTImageURLLoader>)imageURLLoaderForURL:(NSURL *)URL
{
if (!_isLoaderSetup) {
[self setUp];
}

NSArray<id<RCTImageURLLoader>> *loaders = [self loaders];

if (RCT_DEBUG) {
// Check for handler conflicts
float previousPriority = 0;
id<RCTImageURLLoader> previousLoader = nil;
for (id<RCTImageURLLoader> loader in _loaders) {
for (id<RCTImageURLLoader> loader in loaders) {
float priority = [loader respondsToSelector:@selector(loaderPriority)] ? [loader loaderPriority] : 0;
if (previousLoader && priority < previousPriority) {
return previousLoader;
Expand All @@ -224,7 +260,7 @@ - (void)setImageCache:(id<RCTImageCache>)cache
}

// Normal code path
for (id<RCTImageURLLoader> loader in _loaders) {
for (id<RCTImageURLLoader> loader in loaders) {
if ([loader canLoadImageURL:URL]) {
return loader;
}
Expand All @@ -240,35 +276,13 @@ - (void)setImageCache:(id<RCTImageCache>)cache
[self setUp];
}

if (!_decoders) {
// Get decoders, sorted in reverse priority order (highest priority first)

if (_decodersProvider) {
_decoders = _decodersProvider(self.moduleRegistry);
} else {
RCTAssert(_bridge, @"Trying to find RCTImageDataDecoders and bridge not set.");
_decoders = [_bridge modulesConformingToProtocol:@protocol(RCTImageDataDecoder)];
}

_decoders = [_decoders
sortedArrayUsingComparator:^NSComparisonResult(id<RCTImageDataDecoder> a, id<RCTImageDataDecoder> b) {
float priorityA = [a respondsToSelector:@selector(decoderPriority)] ? [a decoderPriority] : 0;
float priorityB = [b respondsToSelector:@selector(decoderPriority)] ? [b decoderPriority] : 0;
if (priorityA > priorityB) {
return NSOrderedAscending;
} else if (priorityA < priorityB) {
return NSOrderedDescending;
} else {
return NSOrderedSame;
}
}];
}
NSArray<id<RCTImageDataDecoder>> *decoders = [self decoders];

if (RCT_DEBUG) {
// Check for handler conflicts
float previousPriority = 0;
id<RCTImageDataDecoder> previousDecoder = nil;
for (id<RCTImageDataDecoder> decoder in _decoders) {
for (id<RCTImageDataDecoder> decoder in decoders) {
float priority = [decoder respondsToSelector:@selector(decoderPriority)] ? [decoder decoderPriority] : 0;
if (previousDecoder && priority < previousPriority) {
return previousDecoder;
Expand Down Expand Up @@ -297,7 +311,7 @@ - (void)setImageCache:(id<RCTImageCache>)cache
}

// Normal code path
for (id<RCTImageDataDecoder> decoder in _decoders) {
for (id<RCTImageDataDecoder> decoder in decoders) {
if ([decoder canDecodeImageData:data]) {
return decoder;
}
Expand Down Expand Up @@ -1173,7 +1187,10 @@ - (BOOL)canHandleRequest:(NSURLRequest *)request
return NO;
}

for (id<RCTImageURLLoader> loader in _loaders) {
if (!_isLoaderSetup) {
[self setUp];
}
for (id<RCTImageURLLoader> loader in [self loaders]) {
// Don't use RCTImageURLLoader protocol for modules that already conform to
// RCTURLRequestHandler as it's inefficient to decode an image and then
// convert it back into data
Expand Down
Loading