iOS Fabric: added support for image instrumentation [1]

Summary:
Added basic hook to enable image instrumentation. The hook passes information to the existing image loader, where instrumentation is done, specific for each app, if any.

Changelog: [Internal]

Reviewed By: mdvacca

Differential Revision: D19047899

fbshipit-source-id: 6c013806cce98bcf1ea240d696a7ede9697e5cd9
This commit is contained in:
Kevin Gozali
2019-12-16 22:50:44 -08:00
committed by Facebook Github Bot
parent 743074d09c
commit 55142efd3a
12 changed files with 197 additions and 14 deletions
-5
View File
@@ -16,11 +16,6 @@
#import <React/RCTImageCache.h>
#import <React/RCTImageLoaderProtocol.h>
RCT_EXTERN BOOL RCTImageLoadingInstrumentationEnabled(void);
RCT_EXTERN BOOL RCTImageLoadingPerfInstrumentationEnabled(void);
RCT_EXTERN void RCTEnableImageLoadingInstrumentation(BOOL enabled);
RCT_EXTERN void RCTEnableImageLoadingPerfInstrumentation(BOOL enabled);
@interface RCTImageLoader : NSObject <RCTBridgeModule, RCTImageLoaderProtocol>
- (instancetype)init;
- (instancetype)initWithRedirectDelegate:(id<RCTImageRedirectProtocol>)redirectDelegate NS_DESIGNATED_INITIALIZER;
@@ -10,6 +10,11 @@
#import <React/RCTImageLoaderProtocol.h>
#import <React/RCTImageURLLoaderWithAttribution.h>
RCT_EXTERN BOOL RCTImageLoadingInstrumentationEnabled(void);
RCT_EXTERN BOOL RCTImageLoadingPerfInstrumentationEnabled(void);
RCT_EXTERN void RCTEnableImageLoadingInstrumentation(BOOL enabled);
RCT_EXTERN void RCTEnableImageLoadingPerfInstrumentation(BOOL enabled);
@protocol RCTImageLoaderWithAttributionProtocol<RCTImageLoaderProtocol>
/**
@@ -13,7 +13,9 @@
#import <react/components/image/ImageEventEmitter.h>
#import <react/components/image/ImageLocalData.h>
#import <react/components/image/ImageProps.h>
#import <react/imagemanager/ImageInstrumentation.h>
#import <react/imagemanager/ImageRequest.h>
#import <react/imagemanager/RCTImageInstrumentationProxy.h>
#import <react/imagemanager/RCTImagePrimitivesConversions.h>
#import "RCTConversions.h"
@@ -100,6 +102,12 @@
// Loading actually starts a little before this, but this is the first time we know
// the image is loading and can fire an event from this component
std::static_pointer_cast<ImageEventEmitter const>(_eventEmitter)->onLoadStart();
// TODO (T58941612): Tracking for visibility should be done directly on this class.
// For now, we consolidate instrumentation logic in the image loader, so that pre-Fabric gets the same treatment.
auto instrumentation = std::static_pointer_cast<const RCTImageInstrumentationProxy>(
_imageLocalData->getImageRequest().getSharedImageInstrumentation());
instrumentation->trackNativeImageView(self);
}
}
@@ -161,6 +169,8 @@
// Apply trilinear filtering to smooth out mis-sized images.
self->_imageView.layer.minificationFilter = kCAFilterTrilinear;
self->_imageView.layer.magnificationFilter = kCAFilterTrilinear;
_imageLocalData->getImageRequest().getImageInstrumentation().didSetImage();
}
- (void)didReceiveProgress:(float)progress fromObserver:(void const *)observer
+1
View File
@@ -64,6 +64,7 @@ rn_xplat_cxx_library(
ios_exported_headers = subdir_glob(
[
("", "*.h"),
("platform/ios", "RCTImageInstrumentationProxy.h"),
("platform/ios", "RCTImagePrimitivesConversions.h"),
],
prefix = "react/imagemanager",
@@ -0,0 +1,40 @@
/*
* 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.
*/
#pragma once
#include <react/core/ReactPrimitives.h>
namespace facebook {
namespace react {
/*
* A base class for performing image loading instrumentation.
* The actual instrumentation is app, platform, and image loader-specific.
*/
class ImageInstrumentation {
public:
virtual ~ImageInstrumentation() noexcept = default;
/**
* Mark that the image content is set on the native image component on screen.
*/
virtual void didSetImage() const = 0;
/**
* Mark that the image view starts to be visible on screen.
*/
virtual void didEnterVisibilityRange() const = 0;
/**
* Mark that the image view is no longer visible on screen.
*/
virtual void didExitVisibilityRange() const = 0;
};
} // namespace react
} // namespace facebook
+23 -2
View File
@@ -7,6 +7,7 @@
#pragma once
#include <react/imagemanager/ImageInstrumentation.h>
#include <react/imagemanager/ImageResponse.h>
#include <react/imagemanager/ImageResponseObserver.h>
#include <react/imagemanager/ImageResponseObserverCoordinator.h>
@@ -24,11 +25,12 @@ namespace react {
*/
class ImageRequest final {
public:
/*
* The default constructor
*/
ImageRequest(const ImageSource &imageSource);
ImageRequest(
const ImageSource &imageSource,
std::shared_ptr<const ImageInstrumentation> instrumentation);
/*
* The move constructor.
@@ -61,6 +63,20 @@ class ImageRequest final {
*/
const ImageResponseObserverCoordinator &getObserverCoordinator() const;
/*
* Returns stored image instrumentation object as a shared pointer.
* Retain this *or* `ImageRequest` to ensure a correct lifetime of the object.
*/
const std::shared_ptr<const ImageInstrumentation>
&getSharedImageInstrumentation() const;
/*
* Returns the image instrumentation object specific to this request.
* Use this if a correct lifetime of the object is ensured in some other way
* (e.g. by retaining an `ImageRequest`).
*/
const ImageInstrumentation &getImageInstrumentation() const;
private:
/*
* Image source associated with the request.
@@ -72,6 +88,11 @@ class ImageRequest final {
*/
std::shared_ptr<const ImageResponseObserverCoordinator> coordinator_{};
/*
* Image instrumentation specific to the request.
*/
std::shared_ptr<const ImageInstrumentation> instrumentation_;
/*
* Function we can call to cancel image request (see destructor).
*/
@@ -24,7 +24,7 @@ ImageRequest ImageManager::requestImage(
const ImageSource &imageSource,
SurfaceId surfaceId) const {
// Not implemented.
return ImageRequest(imageSource);
return ImageRequest(imageSource, nullptr);
}
} // namespace react
@@ -10,8 +10,10 @@
namespace facebook {
namespace react {
ImageRequest::ImageRequest(const ImageSource &imageSource)
: imageSource_(imageSource) {
ImageRequest::ImageRequest(
const ImageSource &imageSource,
std::shared_ptr<const ImageInstrumentation> instrumentation)
: imageSource_(imageSource), instrumentation_(instrumentation) {
// Not implemented.
}
@@ -10,17 +10,21 @@
namespace facebook {
namespace react {
ImageRequest::ImageRequest(const ImageSource &imageSource)
: imageSource_(imageSource) {
ImageRequest::ImageRequest(
const ImageSource &imageSource,
std::shared_ptr<const ImageInstrumentation> instrumentation)
: imageSource_(imageSource), instrumentation_(instrumentation) {
coordinator_ = std::make_shared<ImageResponseObserverCoordinator>();
}
ImageRequest::ImageRequest(ImageRequest &&other) noexcept
: imageSource_(std::move(other.imageSource_)),
coordinator_(std::move(other.coordinator_)) {
coordinator_(std::move(other.coordinator_)),
instrumentation_(std::move(other.instrumentation_)) {
other.moved_ = true;
other.coordinator_ = nullptr;
other.cancelRequest_ = nullptr;
other.instrumentation_ = nullptr;
}
ImageRequest::~ImageRequest() {
@@ -44,5 +48,14 @@ const std::shared_ptr<const ImageResponseObserverCoordinator>
return coordinator_;
}
const std::shared_ptr<const ImageInstrumentation>
&ImageRequest::getSharedImageInstrumentation() const {
return instrumentation_;
}
const ImageInstrumentation &ImageRequest::getImageInstrumentation() const {
return *instrumentation_;
}
} // namespace react
} // namespace facebook
@@ -0,0 +1,37 @@
/*
* 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.
*/
#pragma once
#include <React/RCTImageLoaderWithAttributionProtocol.h>
#include <react/core/ReactPrimitives.h>
#include <react/imagemanager/ImageInstrumentation.h>
NS_ASSUME_NONNULL_BEGIN
namespace facebook {
namespace react {
class RCTImageInstrumentationProxy final : public ImageInstrumentation {
public:
RCTImageInstrumentationProxy(id<RCTImageLoaderWithAttributionProtocol> imageLoader);
void didSetImage() const override;
void didEnterVisibilityRange() const override;
void didExitVisibilityRange() const override;
void trackNativeImageView(UIView *imageView) const;
private:
__weak id<RCTImageLoaderWithAttributionProtocol> imageLoader_;
};
} // namespace react
} // namespace facebook
NS_ASSUME_NONNULL_END
@@ -0,0 +1,57 @@
/*
* 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 "RCTImageInstrumentationProxy.h"
namespace facebook {
namespace react {
RCTImageInstrumentationProxy::RCTImageInstrumentationProxy(id<RCTImageLoaderWithAttributionProtocol> imageLoader)
: imageLoader_(imageLoader)
{
}
void RCTImageInstrumentationProxy::didSetImage() const
{
if (!RCTImageLoadingPerfInstrumentationEnabled()) {
return;
}
// TODO (T58941612): Not yet supported.
if (imageLoader_) {
}
}
void RCTImageInstrumentationProxy::didEnterVisibilityRange() const
{
if (!RCTImageLoadingPerfInstrumentationEnabled()) {
return;
}
// TODO (T58941612): Not yet supported.
}
void RCTImageInstrumentationProxy::didExitVisibilityRange() const
{
if (!RCTImageLoadingPerfInstrumentationEnabled()) {
return;
}
// TODO (T58941612): Not yet supported.
}
void RCTImageInstrumentationProxy::trackNativeImageView(UIView *imageView) const
{
if (!RCTImageLoadingPerfInstrumentationEnabled()) {
return;
}
// TODO (T58941612): Not yet supported.
}
} // namespace react
} // namespace facebook
@@ -12,9 +12,11 @@
#import <react/utils/SharedFunction.h>
#import <React/RCTImageLoaderWithAttributionProtocol.h>
#import <react/imagemanager/ImageResponse.h>
#import <react/imagemanager/ImageResponseObserver.h>
#import "RCTImageInstrumentationProxy.h"
#import "RCTImagePrimitivesConversions.h"
using namespace facebook::react;
@@ -39,7 +41,7 @@ using namespace facebook::react;
{
SystraceSection s("RCTImageManager::requestImage");
auto imageRequest = ImageRequest(imageSource);
auto imageRequest = ImageRequest(imageSource, std::make_unique<RCTImageInstrumentationProxy>(_imageLoader));
auto weakObserverCoordinator =
(std::weak_ptr<const ImageResponseObserverCoordinator>)imageRequest.getSharedObserverCoordinator();