yeet
This commit is contained in:
38
node_modules/react-native/Libraries/Image/AssetRegistry.js
generated
vendored
Normal file
38
node_modules/react-native/Libraries/Image/AssetRegistry.js
generated
vendored
Normal file
@ -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.
|
||||
*
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
export type PackagerAsset = {
|
||||
+__packager_asset: boolean,
|
||||
+fileSystemLocation: string,
|
||||
+httpServerLocation: string,
|
||||
+width: ?number,
|
||||
+height: ?number,
|
||||
+scales: Array<number>,
|
||||
+hash: string,
|
||||
+name: string,
|
||||
+type: string,
|
||||
...
|
||||
};
|
||||
|
||||
const assets: Array<PackagerAsset> = [];
|
||||
|
||||
function registerAsset(asset: PackagerAsset): number {
|
||||
// `push` returns new array length, so the first asset will
|
||||
// get id 1 (not 0) to make the value truthy
|
||||
return assets.push(asset);
|
||||
}
|
||||
|
||||
function getAssetByID(assetId: number): PackagerAsset {
|
||||
return assets[assetId - 1];
|
||||
}
|
||||
|
||||
module.exports = {registerAsset, getAssetByID};
|
176
node_modules/react-native/Libraries/Image/AssetSourceResolver.js
generated
vendored
Normal file
176
node_modules/react-native/Libraries/Image/AssetSourceResolver.js
generated
vendored
Normal file
@ -0,0 +1,176 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
export type ResolvedAssetSource = {|
|
||||
+__packager_asset: boolean,
|
||||
+width: ?number,
|
||||
+height: ?number,
|
||||
+uri: string,
|
||||
+scale: number,
|
||||
|};
|
||||
|
||||
import type {PackagerAsset} from './AssetRegistry';
|
||||
|
||||
const PixelRatio = require('../Utilities/PixelRatio');
|
||||
const Platform = require('../Utilities/Platform');
|
||||
|
||||
const assetPathUtils = require('./assetPathUtils');
|
||||
const invariant = require('invariant');
|
||||
|
||||
/**
|
||||
* Returns a path like 'assets/AwesomeModule/icon@2x.png'
|
||||
*/
|
||||
function getScaledAssetPath(asset): string {
|
||||
const scale = AssetSourceResolver.pickScale(asset.scales, PixelRatio.get());
|
||||
const scaleSuffix = scale === 1 ? '' : '@' + scale + 'x';
|
||||
const assetDir = assetPathUtils.getBasePath(asset);
|
||||
return assetDir + '/' + asset.name + scaleSuffix + '.' + asset.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a path like 'drawable-mdpi/icon.png'
|
||||
*/
|
||||
function getAssetPathInDrawableFolder(asset): string {
|
||||
const scale = AssetSourceResolver.pickScale(asset.scales, PixelRatio.get());
|
||||
const drawbleFolder = assetPathUtils.getAndroidResourceFolderName(
|
||||
asset,
|
||||
scale,
|
||||
);
|
||||
const fileName = assetPathUtils.getAndroidResourceIdentifier(asset);
|
||||
return drawbleFolder + '/' + fileName + '.' + asset.type;
|
||||
}
|
||||
|
||||
class AssetSourceResolver {
|
||||
serverUrl: ?string;
|
||||
// where the jsbundle is being run from
|
||||
jsbundleUrl: ?string;
|
||||
// the asset to resolve
|
||||
asset: PackagerAsset;
|
||||
|
||||
constructor(serverUrl: ?string, jsbundleUrl: ?string, asset: PackagerAsset) {
|
||||
this.serverUrl = serverUrl;
|
||||
this.jsbundleUrl = jsbundleUrl;
|
||||
this.asset = asset;
|
||||
}
|
||||
|
||||
isLoadedFromServer(): boolean {
|
||||
return !!this.serverUrl;
|
||||
}
|
||||
|
||||
isLoadedFromFileSystem(): boolean {
|
||||
return !!(this.jsbundleUrl && this.jsbundleUrl.startsWith('file://'));
|
||||
}
|
||||
|
||||
defaultAsset(): ResolvedAssetSource {
|
||||
if (this.isLoadedFromServer()) {
|
||||
return this.assetServerURL();
|
||||
}
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
return this.isLoadedFromFileSystem()
|
||||
? this.drawableFolderInBundle()
|
||||
: this.resourceIdentifierWithoutScale();
|
||||
} else {
|
||||
return this.scaledAssetURLNearBundle();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an absolute URL which can be used to fetch the asset
|
||||
* from the devserver
|
||||
*/
|
||||
assetServerURL(): ResolvedAssetSource {
|
||||
invariant(!!this.serverUrl, 'need server to load from');
|
||||
return this.fromSource(
|
||||
this.serverUrl +
|
||||
getScaledAssetPath(this.asset) +
|
||||
'?platform=' +
|
||||
Platform.OS +
|
||||
'&hash=' +
|
||||
this.asset.hash,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to just the scaled asset filename
|
||||
* E.g. 'assets/AwesomeModule/icon@2x.png'
|
||||
*/
|
||||
scaledAssetPath(): ResolvedAssetSource {
|
||||
return this.fromSource(getScaledAssetPath(this.asset));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to where the bundle is running from, with a scaled asset filename
|
||||
* E.g. 'file:///sdcard/bundle/assets/AwesomeModule/icon@2x.png'
|
||||
*/
|
||||
scaledAssetURLNearBundle(): ResolvedAssetSource {
|
||||
const path = this.jsbundleUrl || 'file://';
|
||||
return this.fromSource(
|
||||
// Assets can have relative paths outside of the project root.
|
||||
// When bundling them we replace `../` with `_` to make sure they
|
||||
// don't end up outside of the expected assets directory.
|
||||
path + getScaledAssetPath(this.asset).replace(/\.\.\//g, '_'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The default location of assets bundled with the app, located by
|
||||
* resource identifier
|
||||
* The Android resource system picks the correct scale.
|
||||
* E.g. 'assets_awesomemodule_icon'
|
||||
*/
|
||||
resourceIdentifierWithoutScale(): ResolvedAssetSource {
|
||||
invariant(
|
||||
Platform.OS === 'android',
|
||||
'resource identifiers work on Android',
|
||||
);
|
||||
return this.fromSource(
|
||||
assetPathUtils.getAndroidResourceIdentifier(this.asset),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the jsbundle is running from a sideload location, this resolves assets
|
||||
* relative to its location
|
||||
* E.g. 'file:///sdcard/AwesomeModule/drawable-mdpi/icon.png'
|
||||
*/
|
||||
drawableFolderInBundle(): ResolvedAssetSource {
|
||||
const path = this.jsbundleUrl || 'file://';
|
||||
return this.fromSource(path + getAssetPathInDrawableFolder(this.asset));
|
||||
}
|
||||
|
||||
fromSource(source: string): ResolvedAssetSource {
|
||||
return {
|
||||
__packager_asset: true,
|
||||
width: this.asset.width,
|
||||
height: this.asset.height,
|
||||
uri: source,
|
||||
scale: AssetSourceResolver.pickScale(this.asset.scales, PixelRatio.get()),
|
||||
};
|
||||
}
|
||||
|
||||
static pickScale(scales: Array<number>, deviceScale: number): number {
|
||||
// Packager guarantees that `scales` array is sorted
|
||||
for (let i = 0; i < scales.length; i++) {
|
||||
if (scales[i] >= deviceScale) {
|
||||
return scales[i];
|
||||
}
|
||||
}
|
||||
|
||||
// If nothing matches, device scale is larger than any available
|
||||
// scales, so we return the biggest one. Unless the array is empty,
|
||||
// in which case we default to 1
|
||||
return scales[scales.length - 1] || 1;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AssetSourceResolver;
|
407
node_modules/react-native/Libraries/Image/Image.android.js
generated
vendored
Normal file
407
node_modules/react-native/Libraries/Image/Image.android.js
generated
vendored
Normal file
@ -0,0 +1,407 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const DeprecatedImageStylePropTypes = require('../DeprecatedPropTypes/DeprecatedImageStylePropTypes');
|
||||
const DeprecatedStyleSheetPropType = require('../DeprecatedPropTypes/DeprecatedStyleSheetPropType');
|
||||
const DeprecatedViewPropTypes = require('../DeprecatedPropTypes/DeprecatedViewPropTypes');
|
||||
import ImageViewNativeComponent from './ImageViewNativeComponent';
|
||||
const PropTypes = require('prop-types');
|
||||
const React = require('react');
|
||||
const ReactNative = require('../Renderer/shims/ReactNative'); // eslint-disable-line no-unused-vars
|
||||
const StyleSheet = require('../StyleSheet/StyleSheet');
|
||||
const TextAncestor = require('../Text/TextAncestor');
|
||||
|
||||
const ImageAnalyticsTagContext = require('./ImageAnalyticsTagContext').default;
|
||||
const flattenStyle = require('../StyleSheet/flattenStyle');
|
||||
const resolveAssetSource = require('./resolveAssetSource');
|
||||
|
||||
import NativeImageLoaderAndroid from './NativeImageLoaderAndroid';
|
||||
|
||||
const TextInlineImageNativeComponent = require('./TextInlineImageNativeComponent');
|
||||
|
||||
import type {ImageProps as ImagePropsType} from './ImageProps';
|
||||
|
||||
let _requestId = 1;
|
||||
function generateRequestId() {
|
||||
return _requestId++;
|
||||
}
|
||||
|
||||
const ImageProps = {
|
||||
...DeprecatedViewPropTypes,
|
||||
style: (DeprecatedStyleSheetPropType(
|
||||
DeprecatedImageStylePropTypes,
|
||||
): ReactPropsCheckType),
|
||||
/**
|
||||
* See https://reactnative.dev/docs/image.html#source
|
||||
*/
|
||||
source: (PropTypes.oneOfType([
|
||||
PropTypes.shape({
|
||||
uri: PropTypes.string,
|
||||
headers: PropTypes.objectOf(PropTypes.string),
|
||||
}),
|
||||
// Opaque type returned by require('./image.jpg')
|
||||
PropTypes.number,
|
||||
// Multiple sources
|
||||
PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
uri: PropTypes.string,
|
||||
width: PropTypes.number,
|
||||
height: PropTypes.number,
|
||||
headers: PropTypes.objectOf(PropTypes.string),
|
||||
}),
|
||||
),
|
||||
]): React$PropType$Primitive<
|
||||
| {
|
||||
headers?: {[string]: string, ...},
|
||||
uri?: string,
|
||||
...
|
||||
}
|
||||
| number
|
||||
| Array<{
|
||||
headers?: {[string]: string, ...},
|
||||
height?: number,
|
||||
uri?: string,
|
||||
width?: number,
|
||||
...
|
||||
}>,
|
||||
>),
|
||||
/**
|
||||
* blurRadius: the blur radius of the blur filter added to the image
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#blurradius
|
||||
*/
|
||||
blurRadius: PropTypes.number,
|
||||
/**
|
||||
* See https://reactnative.dev/docs/image.html#defaultsource
|
||||
*/
|
||||
defaultSource: PropTypes.number,
|
||||
/**
|
||||
* See https://reactnative.dev/docs/image.html#loadingindicatorsource
|
||||
*/
|
||||
loadingIndicatorSource: (PropTypes.oneOfType([
|
||||
PropTypes.shape({
|
||||
uri: PropTypes.string,
|
||||
}),
|
||||
// Opaque type returned by require('./image.jpg')
|
||||
PropTypes.number,
|
||||
]): React$PropType$Primitive<{uri?: string, ...} | number>),
|
||||
progressiveRenderingEnabled: PropTypes.bool,
|
||||
fadeDuration: PropTypes.number,
|
||||
/**
|
||||
* Analytics Tag used by this Image
|
||||
*/
|
||||
internal_analyticTag: PropTypes.string,
|
||||
/**
|
||||
* Invoked on load start
|
||||
*/
|
||||
onLoadStart: PropTypes.func,
|
||||
/**
|
||||
* Invoked on load error
|
||||
*/
|
||||
onError: PropTypes.func,
|
||||
/**
|
||||
* Invoked when load completes successfully
|
||||
*/
|
||||
onLoad: PropTypes.func,
|
||||
/**
|
||||
* Invoked when load either succeeds or fails
|
||||
*/
|
||||
onLoadEnd: PropTypes.func,
|
||||
/**
|
||||
* Used to locate this view in end-to-end tests.
|
||||
*/
|
||||
testID: PropTypes.string,
|
||||
/**
|
||||
* The mechanism that should be used to resize the image when the image's dimensions
|
||||
* differ from the image view's dimensions. Defaults to `auto`.
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#resizemethod
|
||||
*/
|
||||
resizeMethod: (PropTypes.oneOf([
|
||||
'auto',
|
||||
'resize',
|
||||
'scale',
|
||||
]): React$PropType$Primitive<'auto' | 'resize' | 'scale'>),
|
||||
/**
|
||||
* Determines how to resize the image when the frame doesn't match the raw
|
||||
* image dimensions.
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#resizemode
|
||||
*/
|
||||
resizeMode: (PropTypes.oneOf([
|
||||
'cover',
|
||||
'contain',
|
||||
'stretch',
|
||||
'repeat',
|
||||
'center',
|
||||
]): React$PropType$Primitive<
|
||||
'cover' | 'contain' | 'stretch' | 'repeat' | 'center',
|
||||
>),
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the width and height (in pixels) of an image prior to displaying it
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#getsize
|
||||
*/
|
||||
function getSize(
|
||||
url: string,
|
||||
success: (width: number, height: number) => void,
|
||||
failure?: (error: any) => void,
|
||||
): any {
|
||||
return NativeImageLoaderAndroid.getSize(url)
|
||||
.then(function(sizes) {
|
||||
success(sizes.width, sizes.height);
|
||||
})
|
||||
.catch(
|
||||
failure ||
|
||||
function() {
|
||||
console.warn('Failed to get size for image: ' + url);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the width and height (in pixels) of an image prior to displaying it
|
||||
* with the ability to provide the headers for the request
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#getsizewithheaders
|
||||
*/
|
||||
function getSizeWithHeaders(
|
||||
url: string,
|
||||
headers: {[string]: string, ...},
|
||||
success: (width: number, height: number) => void,
|
||||
failure?: (error: any) => void,
|
||||
): any {
|
||||
return NativeImageLoaderAndroid.getSizeWithHeaders(url, headers)
|
||||
.then(function(sizes) {
|
||||
success(sizes.width, sizes.height);
|
||||
})
|
||||
.catch(
|
||||
failure ||
|
||||
function() {
|
||||
console.warn('Failed to get size for image: ' + url);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function prefetch(url: string, callback: ?Function): any {
|
||||
const requestId = generateRequestId();
|
||||
callback && callback(requestId);
|
||||
return NativeImageLoaderAndroid.prefetchImage(url, requestId);
|
||||
}
|
||||
|
||||
function abortPrefetch(requestId: number) {
|
||||
NativeImageLoaderAndroid.abortRequest(requestId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform cache interrogation.
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#querycache
|
||||
*/
|
||||
async function queryCache(
|
||||
urls: Array<string>,
|
||||
): Promise<{[string]: 'memory' | 'disk' | 'disk/memory', ...}> {
|
||||
return await NativeImageLoaderAndroid.queryCache(urls);
|
||||
}
|
||||
|
||||
type ImageComponentStatics = $ReadOnly<{|
|
||||
getSize: typeof getSize,
|
||||
getSizeWithHeaders: typeof getSizeWithHeaders,
|
||||
prefetch: typeof prefetch,
|
||||
abortPrefetch: typeof abortPrefetch,
|
||||
queryCache: typeof queryCache,
|
||||
resolveAssetSource: typeof resolveAssetSource,
|
||||
propTypes: typeof ImageProps,
|
||||
|}>;
|
||||
|
||||
/**
|
||||
* A React component for displaying different types of images,
|
||||
* including network images, static resources, temporary local images, and
|
||||
* images from local disk, such as the camera roll.
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html
|
||||
*/
|
||||
let Image = (props: ImagePropsType, forwardedRef) => {
|
||||
let source = resolveAssetSource(props.source);
|
||||
const defaultSource = resolveAssetSource(props.defaultSource);
|
||||
const loadingIndicatorSource = resolveAssetSource(
|
||||
props.loadingIndicatorSource,
|
||||
);
|
||||
|
||||
if (source && source.uri === '') {
|
||||
console.warn('source.uri should not be an empty string');
|
||||
}
|
||||
|
||||
if (props.src) {
|
||||
console.warn(
|
||||
'The <Image> component requires a `source` property rather than `src`.',
|
||||
);
|
||||
}
|
||||
|
||||
if (props.children) {
|
||||
throw new Error(
|
||||
'The <Image> component cannot contain children. If you want to render content on top of the image, consider using the <ImageBackground> component or absolute positioning.',
|
||||
);
|
||||
}
|
||||
|
||||
if (props.defaultSource && props.loadingIndicatorSource) {
|
||||
throw new Error(
|
||||
'The <Image> component cannot have defaultSource and loadingIndicatorSource at the same time. Please use either defaultSource or loadingIndicatorSource.',
|
||||
);
|
||||
}
|
||||
|
||||
if (source && !source.uri && !Array.isArray(source)) {
|
||||
source = null;
|
||||
}
|
||||
|
||||
let style;
|
||||
let sources;
|
||||
if (source?.uri != null) {
|
||||
const {width, height} = source;
|
||||
style = flattenStyle([{width, height}, styles.base, props.style]);
|
||||
sources = [{uri: source.uri}];
|
||||
} else {
|
||||
style = flattenStyle([styles.base, props.style]);
|
||||
sources = source;
|
||||
}
|
||||
|
||||
const {onLoadStart, onLoad, onLoadEnd, onError} = props;
|
||||
const nativeProps = {
|
||||
...props,
|
||||
style,
|
||||
shouldNotifyLoadEvents: !!(onLoadStart || onLoad || onLoadEnd || onError),
|
||||
src: sources,
|
||||
/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
|
||||
* when making Flow check .android.js files. */
|
||||
headers: source?.headers,
|
||||
defaultSrc: defaultSource ? defaultSource.uri : null,
|
||||
loadingIndicatorSrc: loadingIndicatorSource
|
||||
? loadingIndicatorSource.uri
|
||||
: null,
|
||||
ref: forwardedRef,
|
||||
};
|
||||
|
||||
return (
|
||||
<ImageAnalyticsTagContext.Consumer>
|
||||
{analyticTag => {
|
||||
const nativePropsWithAnalytics =
|
||||
analyticTag !== null
|
||||
? {
|
||||
...nativeProps,
|
||||
internal_analyticTag: analyticTag,
|
||||
}
|
||||
: nativeProps;
|
||||
return (
|
||||
<TextAncestor.Consumer>
|
||||
{hasTextAncestor =>
|
||||
hasTextAncestor ? (
|
||||
<TextInlineImageNativeComponent {...nativePropsWithAnalytics} />
|
||||
) : (
|
||||
<ImageViewNativeComponent {...nativePropsWithAnalytics} />
|
||||
)
|
||||
}
|
||||
</TextAncestor.Consumer>
|
||||
);
|
||||
}}
|
||||
</ImageAnalyticsTagContext.Consumer>
|
||||
);
|
||||
};
|
||||
|
||||
Image = React.forwardRef<
|
||||
ImagePropsType,
|
||||
| React.ElementRef<typeof TextInlineImageNativeComponent>
|
||||
| React.ElementRef<typeof ImageViewNativeComponent>,
|
||||
>(Image);
|
||||
|
||||
Image.displayName = 'Image';
|
||||
|
||||
/**
|
||||
* Retrieve the width and height (in pixels) of an image prior to displaying it
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#getsize
|
||||
*/
|
||||
/* $FlowFixMe(>=0.89.0 site=react_native_android_fb) This comment suppresses an
|
||||
* error found when Flow v0.89 was deployed. To see the error, delete this
|
||||
* comment and run Flow. */
|
||||
Image.getSize = getSize;
|
||||
|
||||
/**
|
||||
* Retrieve the width and height (in pixels) of an image prior to displaying it
|
||||
* with the ability to provide the headers for the request
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#getsizewithheaders
|
||||
*/
|
||||
/* $FlowFixMe(>=0.89.0 site=react_native_android_fb) This comment suppresses an
|
||||
* error found when Flow v0.89 was deployed. To see the error, delete this
|
||||
* comment and run Flow. */
|
||||
Image.getSizeWithHeaders = getSizeWithHeaders;
|
||||
|
||||
/**
|
||||
* Prefetches a remote image for later use by downloading it to the disk
|
||||
* cache
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#prefetch
|
||||
*/
|
||||
/* $FlowFixMe(>=0.89.0 site=react_native_android_fb) This comment suppresses an
|
||||
* error found when Flow v0.89 was deployed. To see the error, delete this
|
||||
* comment and run Flow. */
|
||||
Image.prefetch = prefetch;
|
||||
|
||||
/**
|
||||
* Abort prefetch request.
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#abortprefetch
|
||||
*/
|
||||
/* $FlowFixMe(>=0.89.0 site=react_native_android_fb) This comment suppresses an
|
||||
* error found when Flow v0.89 was deployed. To see the error, delete this
|
||||
* comment and run Flow. */
|
||||
Image.abortPrefetch = abortPrefetch;
|
||||
|
||||
/**
|
||||
* Perform cache interrogation.
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#querycache
|
||||
*/
|
||||
/* $FlowFixMe(>=0.89.0 site=react_native_android_fb) This comment suppresses an
|
||||
* error found when Flow v0.89 was deployed. To see the error, delete this
|
||||
* comment and run Flow. */
|
||||
Image.queryCache = queryCache;
|
||||
|
||||
/**
|
||||
* Resolves an asset reference into an object.
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#resolveassetsource
|
||||
*/
|
||||
/* $FlowFixMe(>=0.89.0 site=react_native_android_fb) This comment suppresses an
|
||||
* error found when Flow v0.89 was deployed. To see the error, delete this
|
||||
* comment and run Flow. */
|
||||
Image.resolveAssetSource = resolveAssetSource;
|
||||
|
||||
/* $FlowFixMe(>=0.89.0 site=react_native_android_fb) This comment suppresses an
|
||||
* error found when Flow v0.89 was deployed. To see the error, delete this
|
||||
* comment and run Flow. */
|
||||
Image.propTypes = ImageProps;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
base: {
|
||||
overflow: 'hidden',
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = ((Image: any): React.AbstractComponent<
|
||||
ImagePropsType,
|
||||
| React.ElementRef<typeof TextInlineImageNativeComponent>
|
||||
| React.ElementRef<typeof ImageViewNativeComponent>,
|
||||
> &
|
||||
ImageComponentStatics);
|
211
node_modules/react-native/Libraries/Image/Image.ios.js
generated
vendored
Normal file
211
node_modules/react-native/Libraries/Image/Image.ios.js
generated
vendored
Normal file
@ -0,0 +1,211 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const DeprecatedImagePropType = require('../DeprecatedPropTypes/DeprecatedImagePropType');
|
||||
const React = require('react');
|
||||
const ReactNative = require('../Renderer/shims/ReactNative'); // eslint-disable-line no-unused-vars
|
||||
const StyleSheet = require('../StyleSheet/StyleSheet');
|
||||
|
||||
const flattenStyle = require('../StyleSheet/flattenStyle');
|
||||
const resolveAssetSource = require('./resolveAssetSource');
|
||||
|
||||
import type {ImageProps as ImagePropsType} from './ImageProps';
|
||||
|
||||
import type {ImageStyleProp} from '../StyleSheet/StyleSheet';
|
||||
import NativeImageLoaderIOS from './NativeImageLoaderIOS';
|
||||
|
||||
import ImageViewNativeComponent from './ImageViewNativeComponent';
|
||||
|
||||
function getSize(
|
||||
uri: string,
|
||||
success: (width: number, height: number) => void,
|
||||
failure?: (error: any) => void,
|
||||
) {
|
||||
NativeImageLoaderIOS.getSize(uri)
|
||||
.then(([width, height]) => success(width, height))
|
||||
.catch(
|
||||
failure ||
|
||||
function() {
|
||||
console.warn('Failed to get size for image ' + uri);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function getSizeWithHeaders(
|
||||
uri: string,
|
||||
headers: {[string]: string, ...},
|
||||
success: (width: number, height: number) => void,
|
||||
failure?: (error: any) => void,
|
||||
): any {
|
||||
return NativeImageLoaderIOS.getSizeWithHeaders(uri, headers)
|
||||
.then(function(sizes) {
|
||||
success(sizes.width, sizes.height);
|
||||
})
|
||||
.catch(
|
||||
failure ||
|
||||
function() {
|
||||
console.warn('Failed to get size for image: ' + uri);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function prefetch(url: string): any {
|
||||
return NativeImageLoaderIOS.prefetchImage(url);
|
||||
}
|
||||
|
||||
async function queryCache(
|
||||
urls: Array<string>,
|
||||
): Promise<{[string]: 'memory' | 'disk' | 'disk/memory', ...}> {
|
||||
return await NativeImageLoaderIOS.queryCache(urls);
|
||||
}
|
||||
|
||||
type ImageComponentStatics = $ReadOnly<{|
|
||||
getSize: typeof getSize,
|
||||
getSizeWithHeaders: typeof getSizeWithHeaders,
|
||||
prefetch: typeof prefetch,
|
||||
queryCache: typeof queryCache,
|
||||
resolveAssetSource: typeof resolveAssetSource,
|
||||
propTypes: typeof DeprecatedImagePropType,
|
||||
|}>;
|
||||
|
||||
/**
|
||||
* A React component for displaying different types of images,
|
||||
* including network images, static resources, temporary local images, and
|
||||
* images from local disk, such as the camera roll.
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html
|
||||
*/
|
||||
let Image = (props: ImagePropsType, forwardedRef) => {
|
||||
const source = resolveAssetSource(props.source) || {
|
||||
uri: undefined,
|
||||
width: undefined,
|
||||
height: undefined,
|
||||
};
|
||||
|
||||
let sources;
|
||||
let style: ImageStyleProp;
|
||||
if (Array.isArray(source)) {
|
||||
// $FlowFixMe flattenStyle is not strong enough
|
||||
style = flattenStyle([styles.base, props.style]) || {};
|
||||
sources = source;
|
||||
} else {
|
||||
const {width, height, uri} = source;
|
||||
// $FlowFixMe flattenStyle is not strong enough
|
||||
style = flattenStyle([{width, height}, styles.base, props.style]) || {};
|
||||
sources = [source];
|
||||
|
||||
if (uri === '') {
|
||||
console.warn('source.uri should not be an empty string');
|
||||
}
|
||||
}
|
||||
|
||||
const resizeMode = props.resizeMode || style.resizeMode || 'cover';
|
||||
const tintColor = style.tintColor;
|
||||
|
||||
if (props.src != null) {
|
||||
console.warn(
|
||||
'The <Image> component requires a `source` property rather than `src`.',
|
||||
);
|
||||
}
|
||||
|
||||
if (props.children != null) {
|
||||
throw new Error(
|
||||
'The <Image> component cannot contain children. If you want to render content on top of the image, consider using the <ImageBackground> component or absolute positioning.',
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ImageViewNativeComponent
|
||||
{...props}
|
||||
ref={forwardedRef}
|
||||
style={style}
|
||||
resizeMode={resizeMode}
|
||||
tintColor={tintColor}
|
||||
source={sources}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
Image = React.forwardRef<
|
||||
ImagePropsType,
|
||||
React.ElementRef<typeof ImageViewNativeComponent>,
|
||||
>(Image);
|
||||
Image.displayName = 'Image';
|
||||
|
||||
/**
|
||||
* Retrieve the width and height (in pixels) of an image prior to displaying it.
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#getsize
|
||||
*/
|
||||
/* $FlowFixMe(>=0.89.0 site=react_native_ios_fb) This comment suppresses an
|
||||
* error found when Flow v0.89 was deployed. To see the error, delete this
|
||||
* comment and run Flow. */
|
||||
Image.getSize = getSize;
|
||||
|
||||
/**
|
||||
* Retrieve the width and height (in pixels) of an image prior to displaying it
|
||||
* with the ability to provide the headers for the request.
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#getsizewithheaders
|
||||
*/
|
||||
/* $FlowFixMe(>=0.89.0 site=react_native_ios_fb) This comment suppresses an
|
||||
* error found when Flow v0.89 was deployed. To see the error, delete this
|
||||
* comment and run Flow. */
|
||||
Image.getSizeWithHeaders = getSizeWithHeaders;
|
||||
|
||||
/**
|
||||
* Prefetches a remote image for later use by downloading it to the disk
|
||||
* cache.
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#prefetch
|
||||
*/
|
||||
/* $FlowFixMe(>=0.89.0 site=react_native_ios_fb) This comment suppresses an
|
||||
* error found when Flow v0.89 was deployed. To see the error, delete this
|
||||
* comment and run Flow. */
|
||||
Image.prefetch = prefetch;
|
||||
|
||||
/**
|
||||
* Performs cache interrogation.
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#querycache
|
||||
*/
|
||||
/* $FlowFixMe(>=0.89.0 site=react_native_ios_fb) This comment suppresses an
|
||||
* error found when Flow v0.89 was deployed. To see the error, delete this
|
||||
* comment and run Flow. */
|
||||
Image.queryCache = queryCache;
|
||||
|
||||
/**
|
||||
* Resolves an asset reference into an object.
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#resolveassetsource
|
||||
*/
|
||||
/* $FlowFixMe(>=0.89.0 site=react_native_ios_fb) This comment suppresses an
|
||||
* error found when Flow v0.89 was deployed. To see the error, delete this
|
||||
* comment and run Flow. */
|
||||
Image.resolveAssetSource = resolveAssetSource;
|
||||
|
||||
/* $FlowFixMe(>=0.89.0 site=react_native_ios_fb) This comment suppresses an
|
||||
* error found when Flow v0.89 was deployed. To see the error, delete this
|
||||
* comment and run Flow. */
|
||||
Image.propTypes = DeprecatedImagePropType;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
base: {
|
||||
overflow: 'hidden',
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = ((Image: any): React.AbstractComponent<
|
||||
ImagePropsType,
|
||||
React.ElementRef<typeof ImageViewNativeComponent>,
|
||||
> &
|
||||
ImageComponentStatics);
|
21
node_modules/react-native/Libraries/Image/ImageAnalyticsTagContext.js
generated
vendored
Normal file
21
node_modules/react-native/Libraries/Image/ImageAnalyticsTagContext.js
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as React from 'react';
|
||||
|
||||
type ContextType = ?string;
|
||||
|
||||
const Context: React.Context<ContextType> = React.createContext<ContextType>(
|
||||
null,
|
||||
);
|
||||
|
||||
export default Context;
|
90
node_modules/react-native/Libraries/Image/ImageBackground.js
generated
vendored
Normal file
90
node_modules/react-native/Libraries/Image/ImageBackground.js
generated
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const Image = require('./Image');
|
||||
const React = require('react');
|
||||
const StyleSheet = require('../StyleSheet/StyleSheet');
|
||||
const View = require('../Components/View/View');
|
||||
|
||||
/**
|
||||
* Very simple drop-in replacement for <Image> which supports nesting views.
|
||||
*
|
||||
* ```ReactNativeWebPlayer
|
||||
* import React, { Component } from 'react';
|
||||
* import { AppRegistry, View, ImageBackground, Text } from 'react-native';
|
||||
*
|
||||
* class DisplayAnImageBackground extends Component {
|
||||
* render() {
|
||||
* return (
|
||||
* <ImageBackground
|
||||
* style={{width: 50, height: 50}}
|
||||
* source={{uri: 'https://reactnative.dev/img/opengraph.png'}}
|
||||
* >
|
||||
* <Text>React</Text>
|
||||
* </ImageBackground>
|
||||
* );
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* // App registration and rendering
|
||||
* AppRegistry.registerComponent('DisplayAnImageBackground', () => DisplayAnImageBackground);
|
||||
* ```
|
||||
*/
|
||||
class ImageBackground extends React.Component<$FlowFixMeProps> {
|
||||
setNativeProps(props: Object) {
|
||||
// Work-around flow
|
||||
const viewRef = this._viewRef;
|
||||
if (viewRef) {
|
||||
viewRef.setNativeProps(props);
|
||||
}
|
||||
}
|
||||
|
||||
_viewRef: ?React.ElementRef<typeof View> = null;
|
||||
|
||||
_captureRef = ref => {
|
||||
this._viewRef = ref;
|
||||
};
|
||||
|
||||
render(): React.Node {
|
||||
const {children, style, imageStyle, imageRef, ...props} = this.props;
|
||||
|
||||
return (
|
||||
<View
|
||||
accessibilityIgnoresInvertColors={true}
|
||||
style={style}
|
||||
ref={this._captureRef}>
|
||||
<Image
|
||||
{...props}
|
||||
style={[
|
||||
StyleSheet.absoluteFill,
|
||||
{
|
||||
// Temporary Workaround:
|
||||
// Current (imperfect yet) implementation of <Image> overwrites width and height styles
|
||||
// (which is not quite correct), and these styles conflict with explicitly set styles
|
||||
// of <ImageBackground> and with our internal layout model here.
|
||||
// So, we have to proxy/reapply these styles explicitly for actual <Image> component.
|
||||
// This workaround should be removed after implementing proper support of
|
||||
// intrinsic content size of the <Image>.
|
||||
width: style.width,
|
||||
height: style.height,
|
||||
},
|
||||
imageStyle,
|
||||
]}
|
||||
ref={imageRef}
|
||||
/>
|
||||
{children}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ImageBackground;
|
105
node_modules/react-native/Libraries/Image/ImagePickerIOS.js
generated
vendored
Normal file
105
node_modules/react-native/Libraries/Image/ImagePickerIOS.js
generated
vendored
Normal file
@ -0,0 +1,105 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @format
|
||||
* @flow strict-local
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import NativeImagePickerIOS from './NativeImagePickerIOS';
|
||||
import invariant from 'invariant';
|
||||
|
||||
const ImagePickerIOS = {
|
||||
canRecordVideos: function(callback: (result: boolean) => void): void {
|
||||
invariant(NativeImagePickerIOS, 'ImagePickerIOS is not available');
|
||||
return NativeImagePickerIOS.canRecordVideos(callback);
|
||||
},
|
||||
canUseCamera: function(callback: (result: boolean) => void): void {
|
||||
invariant(NativeImagePickerIOS, 'ImagePickerIOS is not available');
|
||||
return NativeImagePickerIOS.canUseCamera(callback);
|
||||
},
|
||||
openCameraDialog: function(
|
||||
config: $ReadOnly<{|
|
||||
unmirrorFrontFacingCamera?: boolean,
|
||||
videoMode?: boolean,
|
||||
|}>,
|
||||
successCallback: (imageURL: string, height: number, width: number) => void,
|
||||
cancelCallback: () => void,
|
||||
): void {
|
||||
invariant(NativeImagePickerIOS, 'ImagePickerIOS is not available');
|
||||
|
||||
var newConfig = {
|
||||
videoMode: true,
|
||||
unmirrorFrontFacingCamera: false,
|
||||
};
|
||||
|
||||
if (config.videoMode != null) {
|
||||
newConfig.videoMode = config.videoMode;
|
||||
}
|
||||
|
||||
if (config.unmirrorFrontFacingCamera != null) {
|
||||
newConfig.unmirrorFrontFacingCamera = config.unmirrorFrontFacingCamera;
|
||||
}
|
||||
|
||||
return NativeImagePickerIOS.openCameraDialog(
|
||||
newConfig,
|
||||
successCallback,
|
||||
cancelCallback,
|
||||
);
|
||||
},
|
||||
openSelectDialog: function(
|
||||
config: $ReadOnly<{|
|
||||
showImages?: boolean,
|
||||
showVideos?: boolean,
|
||||
|}>,
|
||||
successCallback: (imageURL: string, height: number, width: number) => void,
|
||||
cancelCallback: () => void,
|
||||
): void {
|
||||
invariant(NativeImagePickerIOS, 'ImagePickerIOS is not available');
|
||||
|
||||
var newConfig = {
|
||||
showImages: true,
|
||||
showVideos: false,
|
||||
};
|
||||
|
||||
if (config.showImages != null) {
|
||||
newConfig.showImages = config.showImages;
|
||||
}
|
||||
|
||||
if (config.showVideos != null) {
|
||||
newConfig.showVideos = config.showVideos;
|
||||
}
|
||||
|
||||
return NativeImagePickerIOS.openSelectDialog(
|
||||
newConfig,
|
||||
successCallback,
|
||||
cancelCallback,
|
||||
);
|
||||
},
|
||||
/**
|
||||
* In iOS 13, the video URLs returned by the Image Picker are invalidated when
|
||||
* the picker is dismissed, unless reference to it is held. This API allows
|
||||
* the application to signal when it's finished with the video so that the
|
||||
* reference can be cleaned up.
|
||||
* It is safe to call this method for urlsthat aren't video URLs;
|
||||
* it will be a no-op.
|
||||
*/
|
||||
removePendingVideo: function(url: string): void {
|
||||
invariant(NativeImagePickerIOS, 'ImagePickerIOS is not available');
|
||||
NativeImagePickerIOS.removePendingVideo(url);
|
||||
},
|
||||
/**
|
||||
* WARNING: In most cases, removePendingVideo should be used instead because
|
||||
* clearAllPendingVideos could clear out pending videos made by other callers.
|
||||
*/
|
||||
clearAllPendingVideos: function(): void {
|
||||
invariant(NativeImagePickerIOS, 'ImagePickerIOS is not available');
|
||||
NativeImagePickerIOS.clearAllPendingVideos();
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = ImagePickerIOS;
|
174
node_modules/react-native/Libraries/Image/ImageProps.js
generated
vendored
Normal file
174
node_modules/react-native/Libraries/Image/ImageProps.js
generated
vendored
Normal file
@ -0,0 +1,174 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {SyntheticEvent, LayoutEvent} from '../Types/CoreEventTypes';
|
||||
import type {EdgeInsetsProp} from '../StyleSheet/EdgeInsetsPropType';
|
||||
import type {ImageSource} from './ImageSource';
|
||||
import type {ViewStyleProp, ImageStyleProp} from '../StyleSheet/StyleSheet';
|
||||
import type {ViewProps} from '../Components/View/ViewPropTypes';
|
||||
|
||||
export type ImageLoadEvent = SyntheticEvent<
|
||||
$ReadOnly<{|
|
||||
source: $ReadOnly<{|
|
||||
width: number,
|
||||
height: number,
|
||||
url: string,
|
||||
|}>,
|
||||
uri?: string, // Only on Android
|
||||
|}>,
|
||||
>;
|
||||
|
||||
type IOSImageProps = $ReadOnly<{|
|
||||
/**
|
||||
* A static image to display while loading the image source.
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#defaultsource
|
||||
*/
|
||||
defaultSource?: ?ImageSource,
|
||||
/**
|
||||
* Invoked when a partial load of the image is complete.
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#onpartialload
|
||||
*/
|
||||
onPartialLoad?: ?() => void,
|
||||
/**
|
||||
* Invoked on download progress with `{nativeEvent: {loaded, total}}`.
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#onprogress
|
||||
*/
|
||||
onProgress?: ?(
|
||||
event: SyntheticEvent<$ReadOnly<{|loaded: number, total: number|}>>,
|
||||
) => void,
|
||||
|}>;
|
||||
|
||||
type AndroidImageProps = $ReadOnly<{|
|
||||
loadingIndicatorSource?: ?(number | $ReadOnly<{|uri: string|}>),
|
||||
progressiveRenderingEnabled?: ?boolean,
|
||||
fadeDuration?: ?number,
|
||||
|}>;
|
||||
|
||||
export type ImageProps = {|
|
||||
...$Diff<ViewProps, $ReadOnly<{|style: ?ViewStyleProp|}>>,
|
||||
...IOSImageProps,
|
||||
...AndroidImageProps,
|
||||
|
||||
/**
|
||||
* When true, indicates the image is an accessibility element.
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#accessible
|
||||
*/
|
||||
accessible?: ?boolean,
|
||||
|
||||
/**
|
||||
* Internal prop to set an "Analytics Tag" that can will be set on the Image
|
||||
*/
|
||||
internal_analyticTag?: ?string,
|
||||
|
||||
/**
|
||||
* The text that's read by the screen reader when the user interacts with
|
||||
* the image.
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#accessibilitylabel
|
||||
*/
|
||||
accessibilityLabel?: ?Stringish,
|
||||
|
||||
/**
|
||||
* blurRadius: the blur radius of the blur filter added to the image
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#blurradius
|
||||
*/
|
||||
blurRadius?: ?number,
|
||||
|
||||
/**
|
||||
* See https://reactnative.dev/docs/image.html#capinsets
|
||||
*/
|
||||
capInsets?: ?EdgeInsetsProp,
|
||||
|
||||
/**
|
||||
* Invoked on load error with `{nativeEvent: {error}}`.
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#onerror
|
||||
*/
|
||||
onError?: ?(
|
||||
event: SyntheticEvent<
|
||||
$ReadOnly<{|
|
||||
error: string,
|
||||
|}>,
|
||||
>,
|
||||
) => void,
|
||||
|
||||
/**
|
||||
* Invoked on mount and layout changes with
|
||||
* `{nativeEvent: {layout: {x, y, width, height}}}`.
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#onlayout
|
||||
*/
|
||||
|
||||
onLayout?: ?(event: LayoutEvent) => mixed,
|
||||
|
||||
/**
|
||||
* Invoked when load completes successfully.
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#onload
|
||||
*/
|
||||
onLoad?: ?(event: ImageLoadEvent) => void,
|
||||
|
||||
/**
|
||||
* Invoked when load either succeeds or fails.
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#onloadend
|
||||
*/
|
||||
onLoadEnd?: ?() => void,
|
||||
|
||||
/**
|
||||
* Invoked on load start.
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#onloadstart
|
||||
*/
|
||||
onLoadStart?: ?() => void,
|
||||
|
||||
/**
|
||||
* See https://reactnative.dev/docs/image.html#resizemethod
|
||||
*/
|
||||
resizeMethod?: ?('auto' | 'resize' | 'scale'),
|
||||
|
||||
/**
|
||||
* The image source (either a remote URL or a local file resource).
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#source
|
||||
*/
|
||||
source?: ?ImageSource,
|
||||
|
||||
/**
|
||||
* See https://reactnative.dev/docs/image.html#style
|
||||
*/
|
||||
style?: ?ImageStyleProp,
|
||||
|
||||
/**
|
||||
* Determines how to resize the image when the frame doesn't match the raw
|
||||
* image dimensions.
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#resizemode
|
||||
*/
|
||||
resizeMode?: ?('cover' | 'contain' | 'stretch' | 'repeat' | 'center'),
|
||||
|
||||
/**
|
||||
* A unique identifier for this element to be used in UI Automation
|
||||
* testing scripts.
|
||||
*
|
||||
* See https://reactnative.dev/docs/image.html#testid
|
||||
*/
|
||||
testID?: ?string,
|
||||
|
||||
src?: empty,
|
||||
children?: empty,
|
||||
|};
|
36
node_modules/react-native/Libraries/Image/ImageResizeMode.js
generated
vendored
Normal file
36
node_modules/react-native/Libraries/Image/ImageResizeMode.js
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* ImageResizeMode defines valid values for different image resizing modes set
|
||||
* via the `resizeMode` style property on `<Image>`.
|
||||
*/
|
||||
export type ImageResizeMode =
|
||||
// Resize by scaling down such that it is completely visible, if bigger than
|
||||
// the area of the view. The image will not be scaled up.
|
||||
| 'center'
|
||||
|
||||
// Resize such that it will be completely visible, contained within the frame
|
||||
// of the View.
|
||||
| 'contain'
|
||||
|
||||
// Resize such that the entire area of the view is covered by the image,
|
||||
// potentially clipping parts of the image.
|
||||
| 'cover'
|
||||
|
||||
// Resize by repeating to cover the frame of the View. The image will keep its
|
||||
// size and aspect ratio.
|
||||
| 'repeat'
|
||||
|
||||
// Resize by stretching it to fill the entire frame of the view without
|
||||
// clipping. This may change the aspect ratio of the image, distorting it.
|
||||
| 'stretch';
|
85
node_modules/react-native/Libraries/Image/ImageSource.js
generated
vendored
Normal file
85
node_modules/react-native/Libraries/Image/ImageSource.js
generated
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
// This is to sync with ImageSourcePropTypes.js.
|
||||
// We explicitly don't want this to be strict so that we can pass in objects
|
||||
// that might have more keys. This also has to be inexact to support taking
|
||||
// instances of classes like FBIcon.
|
||||
// https://fburl.com/8lynhvtw
|
||||
export type ImageURISource = $ReadOnly<{
|
||||
/**
|
||||
* `uri` is a string representing the resource identifier for the image, which
|
||||
* could be an http address, a local file path, or the name of a static image
|
||||
* resource (which should be wrapped in the `require('./path/to/image.png')`
|
||||
* function).
|
||||
*/
|
||||
uri?: ?string,
|
||||
/**
|
||||
* `bundle` is the iOS asset bundle which the image is included in. This
|
||||
* will default to [NSBundle mainBundle] if not set.
|
||||
* @platform ios
|
||||
*/
|
||||
bundle?: ?string,
|
||||
/**
|
||||
* `method` is the HTTP Method to use. Defaults to GET if not specified.
|
||||
*/
|
||||
method?: ?string,
|
||||
/**
|
||||
* `headers` is an object representing the HTTP headers to send along with the
|
||||
* request for a remote image.
|
||||
*/
|
||||
headers?: ?Object,
|
||||
/**
|
||||
* `body` is the HTTP body to send with the request. This must be a valid
|
||||
* UTF-8 string, and will be sent exactly as specified, with no
|
||||
* additional encoding (e.g. URL-escaping or base64) applied.
|
||||
*/
|
||||
body?: ?string,
|
||||
/**
|
||||
* `cache` determines how the requests handles potentially cached
|
||||
* responses.
|
||||
*
|
||||
* - `default`: Use the native platforms default strategy. `useProtocolCachePolicy` on iOS.
|
||||
*
|
||||
* - `reload`: The data for the URL will be loaded from the originating source.
|
||||
* No existing cache data should be used to satisfy a URL load request.
|
||||
*
|
||||
* - `force-cache`: The existing cached data will be used to satisfy the request,
|
||||
* regardless of its age or expiration date. If there is no existing data in the cache
|
||||
* corresponding the request, the data is loaded from the originating source.
|
||||
*
|
||||
* - `only-if-cached`: The existing cache data will be used to satisfy a request, regardless of
|
||||
* its age or expiration date. If there is no existing data in the cache corresponding
|
||||
* to a URL load request, no attempt is made to load the data from the originating source,
|
||||
* and the load is considered to have failed.
|
||||
*
|
||||
* @platform ios
|
||||
*/
|
||||
cache?: ?('default' | 'reload' | 'force-cache' | 'only-if-cached'),
|
||||
/**
|
||||
* `width` and `height` can be specified if known at build time, in which case
|
||||
* these will be used to set the default `<Image/>` component dimensions.
|
||||
*/
|
||||
width?: ?number,
|
||||
height?: ?number,
|
||||
/**
|
||||
* `scale` is used to indicate the scale factor of the image. Defaults to 1.0 if
|
||||
* unspecified, meaning that one image pixel equates to one display point / DIP.
|
||||
*/
|
||||
scale?: ?number,
|
||||
...
|
||||
}>;
|
||||
|
||||
// We have to export any because of an issue in Flow with objects that come from Relay:
|
||||
// https://fburl.com/8ljo5tmr
|
||||
// https://fb.facebook.com/groups/flow/permalink/1824103160971624/
|
||||
export type ImageSource = ImageURISource | number | Array<ImageURISource>;
|
56
node_modules/react-native/Libraries/Image/ImageViewNativeComponent.js
generated
vendored
Normal file
56
node_modules/react-native/Libraries/Image/ImageViewNativeComponent.js
generated
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @format
|
||||
* @flow strict-local
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const requireNativeComponent = require('../ReactNative/requireNativeComponent');
|
||||
|
||||
import type {DangerouslyImpreciseStyle} from '../StyleSheet/StyleSheet';
|
||||
import type {ResolvedAssetSource} from './AssetSourceResolver';
|
||||
import type {HostComponent} from '../Renderer/shims/ReactNativeTypes';
|
||||
import type {ImageProps} from './ImageProps';
|
||||
import type {ViewProps} from '../Components/View/ViewPropTypes';
|
||||
import type {ImageStyleProp} from '../StyleSheet/StyleSheet';
|
||||
import type {ColorValue} from '../StyleSheet/StyleSheetTypes';
|
||||
|
||||
import ImageViewViewConfig from './ImageViewViewConfig';
|
||||
const ReactNativeViewConfigRegistry = require('../Renderer/shims/ReactNativeViewConfigRegistry');
|
||||
|
||||
type NativeProps = $ReadOnly<{|
|
||||
...ImageProps,
|
||||
...ViewProps,
|
||||
|
||||
style?: ImageStyleProp | DangerouslyImpreciseStyle,
|
||||
|
||||
// iOS native props
|
||||
tintColor?: ColorValue,
|
||||
|
||||
// Android native props
|
||||
shouldNotifyLoadEvents?: boolean,
|
||||
src?: ?ResolvedAssetSource | $ReadOnlyArray<{uri: string, ...}>,
|
||||
headers?: ?string,
|
||||
defaultSrc?: ?string,
|
||||
loadingIndicatorSrc?: ?string,
|
||||
|}>;
|
||||
|
||||
let ImageViewNativeComponent;
|
||||
if (global.RN$Bridgeless) {
|
||||
ReactNativeViewConfigRegistry.register('RCTImageView', () => {
|
||||
return ImageViewViewConfig;
|
||||
});
|
||||
ImageViewNativeComponent = 'RCTImageView';
|
||||
} else {
|
||||
ImageViewNativeComponent = requireNativeComponent<NativeProps>(
|
||||
'RCTImageView',
|
||||
);
|
||||
}
|
||||
|
||||
// flowlint-next-line unclear-type:off
|
||||
export default ((ImageViewNativeComponent: any): HostComponent<NativeProps>);
|
68
node_modules/react-native/Libraries/Image/ImageViewViewConfig.js
generated
vendored
Normal file
68
node_modules/react-native/Libraries/Image/ImageViewViewConfig.js
generated
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @format
|
||||
* @flow strict-local
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import ReactNativeViewViewConfig from '../Components/View/ReactNativeViewViewConfig';
|
||||
import type {ReactNativeBaseComponentViewConfig} from '../Renderer/shims/ReactNativeTypes';
|
||||
|
||||
const ImageViewViewConfig = {
|
||||
uiViewClassName: 'RCTImageView',
|
||||
bubblingEventTypes: {},
|
||||
directEventTypes: {
|
||||
topLoadStart: {
|
||||
registrationName: 'onLoadStart',
|
||||
},
|
||||
topProgress: {
|
||||
registrationName: 'onProgress',
|
||||
},
|
||||
topError: {
|
||||
registrationName: 'onError',
|
||||
},
|
||||
topPartialLoad: {
|
||||
registrationName: 'onPartialLoad',
|
||||
},
|
||||
topLoad: {
|
||||
registrationName: 'onLoad',
|
||||
},
|
||||
topLoadEnd: {
|
||||
registrationName: 'onLoadEnd',
|
||||
},
|
||||
},
|
||||
validAttributes: {
|
||||
...ReactNativeViewViewConfig.validAttributes,
|
||||
blurRadius: true,
|
||||
// flowlint-next-line unclear-type:off
|
||||
capInsets: {diff: (require('../Utilities/differ/insetsDiffer'): any)},
|
||||
defaultSource: {
|
||||
process: require('./resolveAssetSource'),
|
||||
},
|
||||
defaultSrc: true,
|
||||
fadeDuration: true,
|
||||
headers: true,
|
||||
loadingIndicatorSrc: true,
|
||||
onError: true,
|
||||
onLoad: true,
|
||||
onLoadEnd: true,
|
||||
onLoadStart: true,
|
||||
onPartialLoad: true,
|
||||
onProgress: true,
|
||||
overlayColor: {process: require('../StyleSheet/processColor')},
|
||||
progressiveRenderingEnabled: true,
|
||||
resizeMethod: true,
|
||||
resizeMode: true,
|
||||
shouldNotifyLoadEvents: true,
|
||||
source: true,
|
||||
src: true,
|
||||
tintColor: {process: require('../StyleSheet/processColor')},
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = (ImageViewViewConfig: ReactNativeBaseComponentViewConfig<>);
|
40
node_modules/react-native/Libraries/Image/NativeImageLoaderAndroid.js
generated
vendored
Normal file
40
node_modules/react-native/Libraries/Image/NativeImageLoaderAndroid.js
generated
vendored
Normal file
@ -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.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {TurboModule} from '../TurboModule/RCTExport';
|
||||
import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry';
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
+abortRequest: (requestId: number) => void;
|
||||
+getConstants: () => {||};
|
||||
+getSize: (
|
||||
uri: string,
|
||||
) => Promise<
|
||||
$ReadOnly<{
|
||||
width: number,
|
||||
height: number,
|
||||
...
|
||||
}>,
|
||||
>;
|
||||
+getSizeWithHeaders: (
|
||||
uri: string,
|
||||
headers: Object,
|
||||
) => Promise<{
|
||||
width: number,
|
||||
height: number,
|
||||
...
|
||||
}>;
|
||||
+prefetchImage: (uri: string, requestId: number) => Promise<boolean>;
|
||||
+queryCache: (uris: Array<string>) => Promise<Object>;
|
||||
}
|
||||
|
||||
export default (TurboModuleRegistry.getEnforcing<Spec>('ImageLoader'): Spec);
|
32
node_modules/react-native/Libraries/Image/NativeImageLoaderIOS.js
generated
vendored
Normal file
32
node_modules/react-native/Libraries/Image/NativeImageLoaderIOS.js
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {TurboModule} from '../TurboModule/RCTExport';
|
||||
import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry';
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
+getConstants: () => {||};
|
||||
// Return [width, height] of image uri
|
||||
+getSize: (uri: string) => Promise<$ReadOnlyArray<number>>;
|
||||
+getSizeWithHeaders: (
|
||||
uri: string,
|
||||
headers: Object,
|
||||
) => Promise<{
|
||||
width: number,
|
||||
height: number,
|
||||
...
|
||||
}>;
|
||||
+prefetchImage: (uri: string) => Promise<boolean>;
|
||||
+queryCache: (uris: Array<string>) => Promise<Object>;
|
||||
}
|
||||
|
||||
export default (TurboModuleRegistry.getEnforcing<Spec>('ImageLoader'): Spec);
|
40
node_modules/react-native/Libraries/Image/NativeImagePickerIOS.js
generated
vendored
Normal file
40
node_modules/react-native/Libraries/Image/NativeImagePickerIOS.js
generated
vendored
Normal file
@ -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.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {TurboModule} from '../TurboModule/RCTExport';
|
||||
import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry';
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
+getConstants: () => {||};
|
||||
+canRecordVideos: (callback: (result: boolean) => void) => void;
|
||||
+canUseCamera: (callback: (result: boolean) => void) => void;
|
||||
+openCameraDialog: (
|
||||
config: {|
|
||||
unmirrorFrontFacingCamera: boolean,
|
||||
videoMode: boolean,
|
||||
|},
|
||||
successCallback: (imageURL: string, height: number, width: number) => void,
|
||||
cancelCallback: () => void,
|
||||
) => void;
|
||||
+openSelectDialog: (
|
||||
config: {|
|
||||
showImages: boolean,
|
||||
showVideos: boolean,
|
||||
|},
|
||||
successCallback: (imageURL: string, height: number, width: number) => void,
|
||||
cancelCallback: () => void,
|
||||
) => void;
|
||||
+clearAllPendingVideos: () => void;
|
||||
+removePendingVideo: (url: string) => void;
|
||||
}
|
||||
|
||||
export default (TurboModuleRegistry.get<Spec>('ImagePickerIOS'): ?Spec);
|
21
node_modules/react-native/Libraries/Image/RCTAnimatedImage.h
generated
vendored
Normal file
21
node_modules/react-native/Libraries/Image/RCTAnimatedImage.h
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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 <UIKit/UIKit.h>
|
||||
|
||||
@protocol RCTAnimatedImage <NSObject>
|
||||
@property (nonatomic, assign, readonly) NSUInteger animatedImageFrameCount;
|
||||
@property (nonatomic, assign, readonly) NSUInteger animatedImageLoopCount;
|
||||
|
||||
- (nullable UIImage *)animatedImageFrameAtIndex:(NSUInteger)index;
|
||||
- (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index;
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTAnimatedImage : UIImage <RCTAnimatedImage>
|
||||
|
||||
@end
|
169
node_modules/react-native/Libraries/Image/RCTAnimatedImage.m
generated
vendored
Normal file
169
node_modules/react-native/Libraries/Image/RCTAnimatedImage.m
generated
vendored
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* 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 <ImageIO/ImageIO.h>
|
||||
#import <React/RCTAnimatedImage.h>
|
||||
|
||||
@interface RCTGIFCoderFrame : NSObject
|
||||
|
||||
@property (nonatomic, assign) NSUInteger index;
|
||||
@property (nonatomic, assign) NSTimeInterval duration;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTGIFCoderFrame
|
||||
@end
|
||||
|
||||
@implementation RCTAnimatedImage {
|
||||
CGImageSourceRef _imageSource;
|
||||
CGFloat _scale;
|
||||
NSUInteger _loopCount;
|
||||
NSUInteger _frameCount;
|
||||
NSArray<RCTGIFCoderFrame *> *_frames;
|
||||
}
|
||||
|
||||
- (instancetype)initWithData:(NSData *)data scale:(CGFloat)scale
|
||||
{
|
||||
if (self = [super init]) {
|
||||
CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
|
||||
if (!imageSource) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
BOOL framesValid = [self scanAndCheckFramesValidWithSource:imageSource];
|
||||
if (!framesValid) {
|
||||
CFRelease(imageSource);
|
||||
return nil;
|
||||
}
|
||||
|
||||
_imageSource = imageSource;
|
||||
|
||||
// grab image at the first index
|
||||
UIImage *image = [self animatedImageFrameAtIndex:0];
|
||||
if (!image) {
|
||||
return nil;
|
||||
}
|
||||
self = [super initWithCGImage:image.CGImage scale:MAX(scale, 1) orientation:image.imageOrientation];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)scanAndCheckFramesValidWithSource:(CGImageSourceRef)imageSource
|
||||
{
|
||||
if (!imageSource) {
|
||||
return NO;
|
||||
}
|
||||
NSUInteger frameCount = CGImageSourceGetCount(imageSource);
|
||||
NSUInteger loopCount = [self imageLoopCountWithSource:imageSource];
|
||||
NSMutableArray<RCTGIFCoderFrame *> *frames = [NSMutableArray array];
|
||||
|
||||
for (size_t i = 0; i < frameCount; i++) {
|
||||
RCTGIFCoderFrame *frame = [[RCTGIFCoderFrame alloc] init];
|
||||
frame.index = i;
|
||||
frame.duration = [self frameDurationAtIndex:i source:imageSource];
|
||||
[frames addObject:frame];
|
||||
}
|
||||
|
||||
_frameCount = frameCount;
|
||||
_loopCount = loopCount;
|
||||
_frames = [frames copy];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSUInteger)imageLoopCountWithSource:(CGImageSourceRef)source
|
||||
{
|
||||
NSUInteger loopCount = 1;
|
||||
NSDictionary *imageProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyProperties(source, nil);
|
||||
NSDictionary *gifProperties = imageProperties[(__bridge NSString *)kCGImagePropertyGIFDictionary];
|
||||
if (gifProperties) {
|
||||
NSNumber *gifLoopCount = gifProperties[(__bridge NSString *)kCGImagePropertyGIFLoopCount];
|
||||
if (gifLoopCount != nil) {
|
||||
loopCount = gifLoopCount.unsignedIntegerValue;
|
||||
// A loop count of 1 means it should repeat twice, 2 means, thrice, etc.
|
||||
if (loopCount != 0) {
|
||||
loopCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return loopCount;
|
||||
}
|
||||
|
||||
- (float)frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source
|
||||
{
|
||||
float frameDuration = 0.1f;
|
||||
CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil);
|
||||
if (!cfFrameProperties) {
|
||||
return frameDuration;
|
||||
}
|
||||
NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties;
|
||||
NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary];
|
||||
|
||||
NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
|
||||
if (delayTimeUnclampedProp != nil && [delayTimeUnclampedProp floatValue] != 0.0f) {
|
||||
frameDuration = [delayTimeUnclampedProp floatValue];
|
||||
} else {
|
||||
NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime];
|
||||
if (delayTimeProp != nil) {
|
||||
frameDuration = [delayTimeProp floatValue];
|
||||
}
|
||||
}
|
||||
|
||||
CFRelease(cfFrameProperties);
|
||||
return frameDuration;
|
||||
}
|
||||
|
||||
- (NSUInteger)animatedImageLoopCount
|
||||
{
|
||||
return _loopCount;
|
||||
}
|
||||
|
||||
- (NSUInteger)animatedImageFrameCount
|
||||
{
|
||||
return _frameCount;
|
||||
}
|
||||
|
||||
- (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index
|
||||
{
|
||||
if (index >= _frameCount) {
|
||||
return 0;
|
||||
}
|
||||
return _frames[index].duration;
|
||||
}
|
||||
|
||||
- (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index
|
||||
{
|
||||
CGImageRef imageRef = CGImageSourceCreateImageAtIndex(_imageSource, index, NULL);
|
||||
if (!imageRef) {
|
||||
return nil;
|
||||
}
|
||||
UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale orientation:UIImageOrientationUp];
|
||||
CGImageRelease(imageRef);
|
||||
return image;
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning:(NSNotification *)notification
|
||||
{
|
||||
if (_imageSource) {
|
||||
for (size_t i = 0; i < _frameCount; i++) {
|
||||
CGImageSourceRemoveCacheAtIndex(_imageSource, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (_imageSource) {
|
||||
CFRelease(_imageSource);
|
||||
_imageSource = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
22
node_modules/react-native/Libraries/Image/RCTDisplayWeakRefreshable.h
generated
vendored
Normal file
22
node_modules/react-native/Libraries/Image/RCTDisplayWeakRefreshable.h
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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 <Foundation/Foundation.h>
|
||||
|
||||
@protocol RCTDisplayRefreshable
|
||||
|
||||
- (void)displayDidRefresh:(CADisplayLink *)displayLink;
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTDisplayWeakRefreshable : NSObject
|
||||
|
||||
@property (nonatomic, weak) id<RCTDisplayRefreshable> refreshable;
|
||||
|
||||
+ (CADisplayLink *)displayLinkWithWeakRefreshable:(id<RCTDisplayRefreshable>)refreshable;
|
||||
|
||||
@end
|
29
node_modules/react-native/Libraries/Image/RCTDisplayWeakRefreshable.m
generated
vendored
Normal file
29
node_modules/react-native/Libraries/Image/RCTDisplayWeakRefreshable.m
generated
vendored
Normal file
@ -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 "RCTDisplayWeakRefreshable.h"
|
||||
|
||||
@implementation RCTDisplayWeakRefreshable
|
||||
|
||||
+ (CADisplayLink *)displayLinkWithWeakRefreshable:(id<RCTDisplayRefreshable>)refreshable {
|
||||
RCTDisplayWeakRefreshable *target = [[RCTDisplayWeakRefreshable alloc] initWithRefreshable:refreshable];
|
||||
return [CADisplayLink displayLinkWithTarget:target selector:@selector(displayDidRefresh:)];
|
||||
}
|
||||
|
||||
- (instancetype)initWithRefreshable:(id<RCTDisplayRefreshable>)refreshable
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_refreshable = refreshable;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)displayDidRefresh:(CADisplayLink *)displayLink {
|
||||
[_refreshable displayDidRefresh:displayLink];
|
||||
}
|
||||
|
||||
@end
|
12
node_modules/react-native/Libraries/Image/RCTGIFImageDecoder.h
generated
vendored
Normal file
12
node_modules/react-native/Libraries/Image/RCTGIFImageDecoder.h
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
/*
|
||||
* 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 <React/RCTImageDataDecoder.h>
|
||||
|
||||
@interface RCTGIFImageDecoder : NSObject <RCTImageDataDecoder>
|
||||
|
||||
@end
|
54
node_modules/react-native/Libraries/Image/RCTGIFImageDecoder.mm
generated
vendored
Normal file
54
node_modules/react-native/Libraries/Image/RCTGIFImageDecoder.mm
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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 <React/RCTGIFImageDecoder.h>
|
||||
|
||||
#import <ImageIO/ImageIO.h>
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#import <React/RCTAnimatedImage.h>
|
||||
#import <React/RCTUtils.h>
|
||||
#import <ReactCommon/RCTTurboModule.h>
|
||||
|
||||
#import "RCTImagePlugins.h"
|
||||
|
||||
@interface RCTGIFImageDecoder() <RCTTurboModule>
|
||||
@end
|
||||
|
||||
@implementation RCTGIFImageDecoder
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (BOOL)canDecodeImageData:(NSData *)imageData
|
||||
{
|
||||
char header[7] = {};
|
||||
[imageData getBytes:header length:6];
|
||||
|
||||
return !strcmp(header, "GIF87a") || !strcmp(header, "GIF89a");
|
||||
}
|
||||
|
||||
- (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)imageData
|
||||
size:(CGSize)size
|
||||
scale:(CGFloat)scale
|
||||
resizeMode:(RCTResizeMode)resizeMode
|
||||
completionHandler:(RCTImageLoaderCompletionBlock)completionHandler
|
||||
{
|
||||
RCTAnimatedImage *image = [[RCTAnimatedImage alloc] initWithData:imageData scale:scale];
|
||||
|
||||
if (!image) {
|
||||
completionHandler(nil, nil);
|
||||
return ^{};
|
||||
}
|
||||
|
||||
completionHandler(nil, image);
|
||||
return ^{};
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Class RCTGIFImageDecoderCls() {
|
||||
return RCTGIFImageDecoder.class;
|
||||
}
|
13
node_modules/react-native/Libraries/Image/RCTImageBlurUtils.h
generated
vendored
Normal file
13
node_modules/react-native/Libraries/Image/RCTImageBlurUtils.h
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* 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 <Accelerate/Accelerate.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import <React/RCTDefines.h>
|
||||
|
||||
RCT_EXTERN UIImage *RCTBlurredImageWithRadius(UIImage *inputImage, CGFloat radius);
|
87
node_modules/react-native/Libraries/Image/RCTImageBlurUtils.m
generated
vendored
Normal file
87
node_modules/react-native/Libraries/Image/RCTImageBlurUtils.m
generated
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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 <React/RCTImageBlurUtils.h>
|
||||
|
||||
UIImage *RCTBlurredImageWithRadius(UIImage *inputImage, CGFloat radius)
|
||||
{
|
||||
CGImageRef imageRef = inputImage.CGImage;
|
||||
CGFloat imageScale = inputImage.scale;
|
||||
UIImageOrientation imageOrientation = inputImage.imageOrientation;
|
||||
|
||||
// Image must be nonzero size
|
||||
if (CGImageGetWidth(imageRef) * CGImageGetHeight(imageRef) == 0) {
|
||||
return inputImage;
|
||||
}
|
||||
|
||||
//convert to ARGB if it isn't
|
||||
if (CGImageGetBitsPerPixel(imageRef) != 32 ||
|
||||
CGImageGetBitsPerComponent(imageRef) != 8 ||
|
||||
!((CGImageGetBitmapInfo(imageRef) & kCGBitmapAlphaInfoMask))) {
|
||||
UIGraphicsBeginImageContextWithOptions(inputImage.size, NO, inputImage.scale);
|
||||
[inputImage drawAtPoint:CGPointZero];
|
||||
imageRef = UIGraphicsGetImageFromCurrentImageContext().CGImage;
|
||||
UIGraphicsEndImageContext();
|
||||
}
|
||||
|
||||
vImage_Buffer buffer1, buffer2;
|
||||
buffer1.width = buffer2.width = CGImageGetWidth(imageRef);
|
||||
buffer1.height = buffer2.height = CGImageGetHeight(imageRef);
|
||||
buffer1.rowBytes = buffer2.rowBytes = CGImageGetBytesPerRow(imageRef);
|
||||
size_t bytes = buffer1.rowBytes * buffer1.height;
|
||||
buffer1.data = malloc(bytes);
|
||||
buffer2.data = malloc(bytes);
|
||||
if (!buffer1.data || !buffer2.data) {
|
||||
// CWE - 391 : Unchecked error condition
|
||||
// https://www.cvedetails.com/cwe-details/391/Unchecked-Error-Condition.html
|
||||
// https://eli.thegreenplace.net/2009/10/30/handling-out-of-memory-conditions-in-c
|
||||
abort();
|
||||
}
|
||||
|
||||
// A description of how to compute the box kernel width from the Gaussian
|
||||
// radius (aka standard deviation) appears in the SVG spec:
|
||||
// http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement
|
||||
uint32_t boxSize = floor((radius * imageScale * 3 * sqrt(2 * M_PI) / 4 + 0.5) / 2);
|
||||
boxSize |= 1; // Ensure boxSize is odd
|
||||
|
||||
//create temp buffer
|
||||
void *tempBuffer = malloc((size_t)vImageBoxConvolve_ARGB8888(&buffer1, &buffer2, NULL, 0, 0, boxSize, boxSize,
|
||||
NULL, kvImageEdgeExtend + kvImageGetTempBufferSize));
|
||||
if (!tempBuffer) {
|
||||
// CWE - 391 : Unchecked error condition
|
||||
// https://www.cvedetails.com/cwe-details/391/Unchecked-Error-Condition.html
|
||||
// https://eli.thegreenplace.net/2009/10/30/handling-out-of-memory-conditions-in-c
|
||||
abort();
|
||||
}
|
||||
|
||||
//copy image data
|
||||
CFDataRef dataSource = CGDataProviderCopyData(CGImageGetDataProvider(imageRef));
|
||||
memcpy(buffer1.data, CFDataGetBytePtr(dataSource), bytes);
|
||||
CFRelease(dataSource);
|
||||
|
||||
//perform blur
|
||||
vImageBoxConvolve_ARGB8888(&buffer1, &buffer2, tempBuffer, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend);
|
||||
vImageBoxConvolve_ARGB8888(&buffer2, &buffer1, tempBuffer, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend);
|
||||
vImageBoxConvolve_ARGB8888(&buffer1, &buffer2, tempBuffer, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend);
|
||||
|
||||
//free buffers
|
||||
free(buffer2.data);
|
||||
free(tempBuffer);
|
||||
|
||||
//create image context from buffer
|
||||
CGContextRef ctx = CGBitmapContextCreate(buffer1.data, buffer1.width, buffer1.height,
|
||||
8, buffer1.rowBytes, CGImageGetColorSpace(imageRef),
|
||||
CGImageGetBitmapInfo(imageRef));
|
||||
|
||||
//create image from context
|
||||
imageRef = CGBitmapContextCreateImage(ctx);
|
||||
UIImage *outputImage = [UIImage imageWithCGImage:imageRef scale:imageScale orientation:imageOrientation];
|
||||
CGImageRelease(imageRef);
|
||||
CGContextRelease(ctx);
|
||||
free(buffer1.data);
|
||||
return outputImage;
|
||||
}
|
42
node_modules/react-native/Libraries/Image/RCTImageCache.h
generated
vendored
Normal file
42
node_modules/react-native/Libraries/Image/RCTImageCache.h
generated
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 <UIKit/UIKit.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <React/RCTResizeMode.h>
|
||||
|
||||
@interface UIImage (React)
|
||||
|
||||
/**
|
||||
* Memory bytes of the image with the default calculation of static image or GIF. Custom calculations of decoded bytes can be assigned manually.
|
||||
*/
|
||||
@property (nonatomic, assign) NSInteger reactDecodedImageBytes;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
* Provides an interface to use for providing a image caching strategy.
|
||||
*/
|
||||
@protocol RCTImageCache <NSObject>
|
||||
|
||||
- (UIImage *)imageForUrl:(NSString *)url
|
||||
size:(CGSize)size
|
||||
scale:(CGFloat)scale
|
||||
resizeMode:(RCTResizeMode)resizeMode;
|
||||
|
||||
- (void)addImageToCache:(UIImage *)image
|
||||
URL:(NSString *)url
|
||||
size:(CGSize)size
|
||||
scale:(CGFloat)scale
|
||||
resizeMode:(RCTResizeMode)resizeMode
|
||||
response:(NSURLResponse *)response;
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTImageCache : NSObject <RCTImageCache>
|
||||
@end
|
163
node_modules/react-native/Libraries/Image/RCTImageCache.m
generated
vendored
Normal file
163
node_modules/react-native/Libraries/Image/RCTImageCache.m
generated
vendored
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* 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 <React/RCTImageCache.h>
|
||||
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#import <ImageIO/ImageIO.h>
|
||||
|
||||
#import <React/RCTConvert.h>
|
||||
#import <React/RCTNetworking.h>
|
||||
#import <React/RCTUtils.h>
|
||||
#import <React/RCTResizeMode.h>
|
||||
|
||||
#import <React/RCTImageUtils.h>
|
||||
|
||||
static const NSUInteger RCTMaxCachableDecodedImageSizeInBytes = 2097152; // 2 MB
|
||||
|
||||
static NSString *RCTCacheKeyForImage(NSString *imageTag, CGSize size, CGFloat scale,
|
||||
RCTResizeMode resizeMode)
|
||||
{
|
||||
return [NSString stringWithFormat:@"%@|%g|%g|%g|%lld",
|
||||
imageTag, size.width, size.height, scale, (long long)resizeMode];
|
||||
}
|
||||
|
||||
@implementation RCTImageCache
|
||||
{
|
||||
NSOperationQueue *_imageDecodeQueue;
|
||||
NSCache *_decodedImageCache;
|
||||
NSMutableDictionary *_cacheStaleTimes;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_decodedImageCache = [NSCache new];
|
||||
_decodedImageCache.totalCostLimit = 20 * 1024 * 1024; // 20 MB
|
||||
_cacheStaleTimes = [[NSMutableDictionary alloc] init];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(clearCache)
|
||||
name:UIApplicationDidReceiveMemoryWarningNotification
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(clearCache)
|
||||
name:UIApplicationWillResignActiveNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)clearCache
|
||||
{
|
||||
[_decodedImageCache removeAllObjects];
|
||||
@synchronized(_cacheStaleTimes) {
|
||||
[_cacheStaleTimes removeAllObjects];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)addImageToCache:(UIImage *)image
|
||||
forKey:(NSString *)cacheKey
|
||||
{
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
NSInteger bytes = image.reactDecodedImageBytes;
|
||||
if (bytes <= RCTMaxCachableDecodedImageSizeInBytes) {
|
||||
[self->_decodedImageCache setObject:image
|
||||
forKey:cacheKey
|
||||
cost:bytes];
|
||||
}
|
||||
}
|
||||
|
||||
- (UIImage *)imageForUrl:(NSString *)url
|
||||
size:(CGSize)size
|
||||
scale:(CGFloat)scale
|
||||
resizeMode:(RCTResizeMode)resizeMode
|
||||
{
|
||||
NSString *cacheKey = RCTCacheKeyForImage(url, size, scale, resizeMode);
|
||||
@synchronized(_cacheStaleTimes) {
|
||||
id staleTime = _cacheStaleTimes[cacheKey];
|
||||
if (staleTime) {
|
||||
if ([[NSDate new] compare:(NSDate *)staleTime] == NSOrderedDescending) {
|
||||
// cached image has expired, clear it out to make room for others
|
||||
[_cacheStaleTimes removeObjectForKey:cacheKey];
|
||||
[_decodedImageCache removeObjectForKey:cacheKey];
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
return [_decodedImageCache objectForKey:cacheKey];
|
||||
}
|
||||
|
||||
- (void)addImageToCache:(UIImage *)image
|
||||
URL:(NSString *)url
|
||||
size:(CGSize)size
|
||||
scale:(CGFloat)scale
|
||||
resizeMode:(RCTResizeMode)resizeMode
|
||||
response:(NSURLResponse *)response
|
||||
{
|
||||
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
|
||||
NSString *cacheKey = RCTCacheKeyForImage(url, size, scale, resizeMode);
|
||||
BOOL shouldCache = YES;
|
||||
NSString *responseDate = ((NSHTTPURLResponse *)response).allHeaderFields[@"Date"];
|
||||
NSDate *originalDate = [self dateWithHeaderString:responseDate];
|
||||
NSString *cacheControl = ((NSHTTPURLResponse *)response).allHeaderFields[@"Cache-Control"];
|
||||
NSDate *staleTime;
|
||||
NSArray<NSString *> *components = [cacheControl componentsSeparatedByString:@","];
|
||||
for (NSString *component in components) {
|
||||
if ([component containsString:@"no-cache"] || [component containsString:@"no-store"] || [component hasSuffix:@"max-age=0"]) {
|
||||
shouldCache = NO;
|
||||
break;
|
||||
} else {
|
||||
NSRange range = [component rangeOfString:@"max-age="];
|
||||
if (range.location != NSNotFound) {
|
||||
NSInteger seconds = [[component substringFromIndex:range.location + range.length] integerValue];
|
||||
staleTime = [originalDate dateByAddingTimeInterval:(NSTimeInterval)seconds];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (shouldCache) {
|
||||
if (!staleTime && originalDate) {
|
||||
NSString *expires = ((NSHTTPURLResponse *)response).allHeaderFields[@"Expires"];
|
||||
NSString *lastModified = ((NSHTTPURLResponse *)response).allHeaderFields[@"Last-Modified"];
|
||||
if (expires) {
|
||||
staleTime = [self dateWithHeaderString:expires];
|
||||
} else if (lastModified) {
|
||||
NSDate *lastModifiedDate = [self dateWithHeaderString:lastModified];
|
||||
if (lastModifiedDate) {
|
||||
NSTimeInterval interval = [originalDate timeIntervalSinceDate:lastModifiedDate] / 10;
|
||||
staleTime = [originalDate dateByAddingTimeInterval:interval];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (staleTime) {
|
||||
@synchronized(_cacheStaleTimes) {
|
||||
_cacheStaleTimes[cacheKey] = staleTime;
|
||||
}
|
||||
}
|
||||
return [self addImageToCache:image forKey:cacheKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (NSDate *)dateWithHeaderString:(NSString *)headerDateString {
|
||||
static NSDateFormatter *formatter;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
formatter = [[NSDateFormatter alloc] init];
|
||||
formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
|
||||
formatter.dateFormat = @"EEE',' dd MMM yyyy HH':'mm':'ss 'GMT'";
|
||||
formatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
|
||||
});
|
||||
|
||||
return [formatter dateFromString:headerDateString];
|
||||
}
|
||||
|
||||
@end
|
53
node_modules/react-native/Libraries/Image/RCTImageDataDecoder.h
generated
vendored
Normal file
53
node_modules/react-native/Libraries/Image/RCTImageDataDecoder.h
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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 <UIKit/UIKit.h>
|
||||
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTResizeMode.h>
|
||||
#import <React/RCTURLRequestHandler.h>
|
||||
#import <React/RCTImageURLLoader.h>
|
||||
|
||||
/**
|
||||
* Provides the interface needed to register an image decoder. Image decoders
|
||||
* are also bridge modules, so should be registered using RCT_EXPORT_MODULE().
|
||||
*/
|
||||
@protocol RCTImageDataDecoder <RCTBridgeModule>
|
||||
|
||||
/**
|
||||
* Indicates whether this handler is capable of decoding the specified data.
|
||||
* Typically the handler would examine some sort of header data to determine
|
||||
* this.
|
||||
*/
|
||||
- (BOOL)canDecodeImageData:(NSData *)imageData;
|
||||
|
||||
/**
|
||||
* Decode an image from the data object. The method should call the
|
||||
* completionHandler when the decoding operation has finished. The method
|
||||
* should also return a cancellation block, if applicable.
|
||||
*
|
||||
* If you provide a custom image decoder, you most implement scheduling yourself,
|
||||
* to avoid decoding large amounts of images at the same time.
|
||||
*/
|
||||
- (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)imageData
|
||||
size:(CGSize)size
|
||||
scale:(CGFloat)scale
|
||||
resizeMode:(RCTResizeMode)resizeMode
|
||||
completionHandler:(RCTImageLoaderCompletionBlock)completionHandler;
|
||||
|
||||
@optional
|
||||
|
||||
/**
|
||||
* If more than one RCTImageDataDecoder responds YES to `-canDecodeImageData:`
|
||||
* then `decoderPriority` is used to determine which one to use. The decoder
|
||||
* with the highest priority will be selected. Default priority is zero.
|
||||
* If two or more valid decoders have the same priority, the selection order is
|
||||
* undefined.
|
||||
*/
|
||||
- (float)decoderPriority;
|
||||
|
||||
@end
|
12
node_modules/react-native/Libraries/Image/RCTImageEditingManager.h
generated
vendored
Normal file
12
node_modules/react-native/Libraries/Image/RCTImageEditingManager.h
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
/*
|
||||
* 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 <React/RCTBridgeModule.h>
|
||||
|
||||
@interface RCTImageEditingManager : NSObject <RCTBridgeModule>
|
||||
|
||||
@end
|
107
node_modules/react-native/Libraries/Image/RCTImageEditingManager.mm
generated
vendored
Normal file
107
node_modules/react-native/Libraries/Image/RCTImageEditingManager.mm
generated
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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 <React/RCTImageEditingManager.h>
|
||||
|
||||
#import <FBReactNativeSpec/FBReactNativeSpec.h>
|
||||
#import <React/RCTConvert.h>
|
||||
#import <React/RCTImageLoader.h>
|
||||
#import <React/RCTImageStoreManager.h>
|
||||
#import <React/RCTImageUtils.h>
|
||||
#import <React/RCTImageLoaderProtocol.h>
|
||||
#import <React/RCTLog.h>
|
||||
#import <React/RCTUtils.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RCTImagePlugins.h"
|
||||
|
||||
@interface RCTImageEditingManager() <NativeImageEditorSpec>
|
||||
@end
|
||||
|
||||
@implementation RCTImageEditingManager
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
@synthesize bridge = _bridge;
|
||||
|
||||
/**
|
||||
* Crops an image and adds the result to the image store.
|
||||
*
|
||||
* @param imageRequest An image URL
|
||||
* @param cropData Dictionary with `offset`, `size` and `displaySize`.
|
||||
* `offset` and `size` are relative to the full-resolution image size.
|
||||
* `displaySize` is an optimization - if specified, the image will
|
||||
* be scaled down to `displaySize` rather than `size`.
|
||||
* All units are in px (not points).
|
||||
*/
|
||||
RCT_EXPORT_METHOD(cropImage:(NSURLRequest *)imageRequest
|
||||
cropData:(JS::NativeImageEditor::Options &)cropData
|
||||
successCallback:(RCTResponseSenderBlock)successCallback
|
||||
errorCallback:(RCTResponseSenderBlock)errorCallback)
|
||||
{
|
||||
CGRect rect = {
|
||||
[RCTConvert CGPoint:@{
|
||||
@"x": @(cropData.offset().x()),
|
||||
@"y": @(cropData.offset().y()),
|
||||
}],
|
||||
[RCTConvert CGSize:@{
|
||||
@"width": @(cropData.size().width()),
|
||||
@"height": @(cropData.size().height()),
|
||||
}]
|
||||
};
|
||||
|
||||
// We must keep a copy of cropData so that we can access data from it at a later time
|
||||
JS::NativeImageEditor::Options cropDataCopy = cropData;
|
||||
|
||||
[[_bridge moduleForName:@"ImageLoader" lazilyLoadIfNecessary:YES]
|
||||
loadImageWithURLRequest:imageRequest callback:^(NSError *error, UIImage *image) {
|
||||
if (error) {
|
||||
errorCallback(@[RCTJSErrorFromNSError(error)]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Crop image
|
||||
CGSize targetSize = rect.size;
|
||||
CGRect targetRect = {{-rect.origin.x, -rect.origin.y}, image.size};
|
||||
CGAffineTransform transform = RCTTransformFromTargetRect(image.size, targetRect);
|
||||
UIImage *croppedImage = RCTTransformImage(image, targetSize, image.scale, transform);
|
||||
|
||||
// Scale image
|
||||
if (cropDataCopy.displaySize()) {
|
||||
targetSize = [RCTConvert CGSize:@{@"width": @(cropDataCopy.displaySize()->width()), @"height": @(cropDataCopy.displaySize()->height())}]; // in pixels
|
||||
RCTResizeMode resizeMode = [RCTConvert RCTResizeMode:cropDataCopy.resizeMode() ?: @"contain"];
|
||||
targetRect = RCTTargetRect(croppedImage.size, targetSize, 1, resizeMode);
|
||||
transform = RCTTransformFromTargetRect(croppedImage.size, targetRect);
|
||||
croppedImage = RCTTransformImage(croppedImage, targetSize, image.scale, transform);
|
||||
}
|
||||
|
||||
// Store image
|
||||
[self->_bridge.imageStoreManager storeImage:croppedImage withBlock:^(NSString *croppedImageTag) {
|
||||
if (!croppedImageTag) {
|
||||
NSString *errorMessage = @"Error storing cropped image in RCTImageStoreManager";
|
||||
RCTLogWarn(@"%@", errorMessage);
|
||||
errorCallback(@[RCTJSErrorFromNSError(RCTErrorWithMessage(errorMessage))]);
|
||||
return;
|
||||
}
|
||||
successCallback(@[croppedImageTag]);
|
||||
}];
|
||||
}];
|
||||
}
|
||||
|
||||
- (std::shared_ptr<facebook::react::TurboModule>)
|
||||
getTurboModuleWithJsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
|
||||
nativeInvoker:(std::shared_ptr<facebook::react::CallInvoker>)nativeInvoker
|
||||
perfLogger:(id<RCTTurboModulePerformanceLogger>)perfLogger
|
||||
{
|
||||
return std::make_shared<facebook::react::NativeImageEditorSpecJSI>(self, jsInvoker, nativeInvoker, perfLogger);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Class RCTImageEditingManagerCls() {
|
||||
return RCTImageEditingManager.class;
|
||||
}
|
35
node_modules/react-native/Libraries/Image/RCTImageLoader.h
generated
vendored
Normal file
35
node_modules/react-native/Libraries/Image/RCTImageLoader.h
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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 <UIKit/UIKit.h>
|
||||
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTDefines.h>
|
||||
#import <React/RCTResizeMode.h>
|
||||
#import <React/RCTURLRequestHandler.h>
|
||||
#import <React/RCTImageDataDecoder.h>
|
||||
#import <React/RCTImageURLLoader.h>
|
||||
#import <React/RCTImageCache.h>
|
||||
#import <React/RCTImageLoaderProtocol.h>
|
||||
|
||||
@interface RCTImageLoader : NSObject <RCTBridgeModule, RCTImageLoaderProtocol>
|
||||
- (instancetype)init;
|
||||
- (instancetype)initWithRedirectDelegate:(id<RCTImageRedirectProtocol>)redirectDelegate NS_DESIGNATED_INITIALIZER;
|
||||
- (instancetype)initWithRedirectDelegate:(id<RCTImageRedirectProtocol>)redirectDelegate
|
||||
loadersProvider:(NSArray<id<RCTImageURLLoader>> * (^)(void))getLoaders
|
||||
decodersProvider:(NSArray<id<RCTImageDataDecoder>> * (^)(void))getDecoders;
|
||||
@end
|
||||
|
||||
/**
|
||||
* DEPRECATED!! DO NOT USE
|
||||
* Instead use `[_bridge moduleForClass:[RCTImageLoader class]]`
|
||||
*/
|
||||
@interface RCTBridge (RCTImageLoader)
|
||||
|
||||
@property (nonatomic, readonly) RCTImageLoader *imageLoader;
|
||||
|
||||
@end
|
1212
node_modules/react-native/Libraries/Image/RCTImageLoader.mm
generated
vendored
Normal file
1212
node_modules/react-native/Libraries/Image/RCTImageLoader.mm
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
134
node_modules/react-native/Libraries/Image/RCTImageLoaderProtocol.h
generated
vendored
Normal file
134
node_modules/react-native/Libraries/Image/RCTImageLoaderProtocol.h
generated
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* 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 <UIKit/UIKit.h>
|
||||
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTResizeMode.h>
|
||||
#import <React/RCTURLRequestHandler.h>
|
||||
#import <React/RCTImageDataDecoder.h>
|
||||
#import <React/RCTImageURLLoader.h>
|
||||
#import <React/RCTImageCache.h>
|
||||
|
||||
/**
|
||||
* If available, RCTImageRedirectProtocol is invoked before loading an asset.
|
||||
* Implementation should return either a new URL or nil when redirection is
|
||||
* not needed.
|
||||
*/
|
||||
|
||||
@protocol RCTImageRedirectProtocol
|
||||
|
||||
- (NSURL *)redirectAssetsURL:(NSURL *)URL;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
* Image Downloading priority.
|
||||
* Use PriorityImmediate to download images at the highest priority.
|
||||
* Use PriorityPrefetch to prefetch images at a lower priority.
|
||||
* The priority logic is up to each @RCTImageLoaderProtocol implementation
|
||||
*/
|
||||
typedef NS_ENUM(NSUInteger, RCTImageLoaderPriority) {
|
||||
RCTImageLoaderPriorityImmediate,
|
||||
RCTImageLoaderPriorityPrefetch
|
||||
};
|
||||
|
||||
@protocol RCTImageLoaderProtocol<RCTURLRequestHandler>
|
||||
|
||||
/**
|
||||
* The maximum number of concurrent image loading tasks. Loading and decoding
|
||||
* images can consume a lot of memory, so setting this to a higher value may
|
||||
* cause memory to spike. If you are seeing out-of-memory crashes, try reducing
|
||||
* this value.
|
||||
*/
|
||||
@property (nonatomic, assign) NSUInteger maxConcurrentLoadingTasks;
|
||||
|
||||
/**
|
||||
* The maximum number of concurrent image decoding tasks. Decoding large
|
||||
* images can be especially CPU and memory intensive, so if your are decoding a
|
||||
* lot of large images in your app, you may wish to adjust this value.
|
||||
*/
|
||||
@property (nonatomic, assign) NSUInteger maxConcurrentDecodingTasks;
|
||||
|
||||
/**
|
||||
* Decoding large images can use a lot of memory, and potentially cause the app
|
||||
* to crash. This value allows you to throttle the amount of memory used by the
|
||||
* decoder independently of the number of concurrent threads. This means you can
|
||||
* still decode a lot of small images in parallel, without allowing the decoder
|
||||
* to try to decompress multiple huge images at once. Note that this value is
|
||||
* only a hint, and not an indicator of the total memory used by the app.
|
||||
*/
|
||||
@property (nonatomic, assign) NSUInteger maxConcurrentDecodingBytes;
|
||||
|
||||
/**
|
||||
* Loads the specified image at the highest available resolution.
|
||||
* Can be called from any thread, will call back on an unspecified thread.
|
||||
*/
|
||||
- (nullable RCTImageLoaderCancellationBlock)loadImageWithURLRequest:(NSURLRequest *)imageURLRequest
|
||||
callback:(RCTImageLoaderCompletionBlock)callback;
|
||||
/**
|
||||
* As above, but includes download `priority`.
|
||||
*/
|
||||
- (nullable RCTImageLoaderCancellationBlock)loadImageWithURLRequest:(NSURLRequest *)imageURLRequest
|
||||
priority:(RCTImageLoaderPriority)priority
|
||||
callback:(RCTImageLoaderCompletionBlock)callback;
|
||||
|
||||
/**
|
||||
* As above, but includes target `size`, `scale` and `resizeMode`, which are used to
|
||||
* select the optimal dimensions for the loaded image. The `clipped` option
|
||||
* controls whether the image will be clipped to fit the specified size exactly,
|
||||
* or if the original aspect ratio should be retained.
|
||||
* `partialLoadBlock` is meant for custom image loaders that do not ship with the core RN library.
|
||||
* It is meant to be called repeatedly while loading the image as higher quality versions are decoded,
|
||||
* for instance with progressive JPEGs.
|
||||
*/
|
||||
- (nullable 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;
|
||||
|
||||
/**
|
||||
* Finds an appropriate image decoder and passes the target `size`, `scale` and
|
||||
* `resizeMode` for optimal image decoding. The `clipped` option controls
|
||||
* whether the image will be clipped to fit the specified size exactly, or
|
||||
* if the original aspect ratio should be retained. Can be called from any
|
||||
* thread, will call callback on an unspecified thread.
|
||||
*/
|
||||
- (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)imageData
|
||||
size:(CGSize)size
|
||||
scale:(CGFloat)scale
|
||||
clipped:(BOOL)clipped
|
||||
resizeMode:(RCTResizeMode)resizeMode
|
||||
completionBlock:(RCTImageLoaderCompletionBlock)completionBlock;
|
||||
|
||||
/**
|
||||
* Get image size, in pixels. This method will do the least work possible to get
|
||||
* the information, and won't decode the image if it doesn't have to.
|
||||
*/
|
||||
- (RCTImageLoaderCancellationBlock)getImageSizeForURLRequest:(NSURLRequest *)imageURLRequest
|
||||
block:(void(^)(NSError *error, CGSize size))completionBlock;
|
||||
/**
|
||||
* Determines whether given image URLs are cached locally. The `requests` array is expected
|
||||
* to contain objects convertible to NSURLRequest. The return value maps URLs to strings:
|
||||
* "disk" for images known to be cached in non-volatile storage, "memory" for images known
|
||||
* to be cached in memory. Dictionary items corresponding to images that are not known to be
|
||||
* cached are simply missing.
|
||||
*/
|
||||
- (NSDictionary *)getImageCacheStatus:(NSArray *)requests;
|
||||
|
||||
/**
|
||||
* Allows developers to set their own caching implementation for
|
||||
* decoded images as long as it conforms to the RCTImageCache
|
||||
* protocol. This method should be called in bridgeDidInitializeModule.
|
||||
*/
|
||||
- (void)setImageCache:(id<RCTImageCache>)cache;
|
||||
|
||||
@end
|
53
node_modules/react-native/Libraries/Image/RCTImageLoaderWithAttributionProtocol.h
generated
vendored
Normal file
53
node_modules/react-native/Libraries/Image/RCTImageLoaderWithAttributionProtocol.h
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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 <UIKit/UIKit.h>
|
||||
|
||||
#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>
|
||||
|
||||
// TODO (T61325135): Remove C++ checks
|
||||
#ifdef __cplusplus
|
||||
/**
|
||||
* Same as the variant in RCTImageURLLoaderProtocol, but allows passing attribution
|
||||
* information that each image URL loader can process.
|
||||
*/
|
||||
- (RCTImageURLLoaderRequest *)loadImageWithURLRequest:(NSURLRequest *)imageURLRequest
|
||||
size:(CGSize)size
|
||||
scale:(CGFloat)scale
|
||||
clipped:(BOOL)clipped
|
||||
resizeMode:(RCTResizeMode)resizeMode
|
||||
priority: (RCTImageLoaderPriority)priority
|
||||
attribution:(const facebook::react::ImageURLLoaderAttribution &)attribution
|
||||
progressBlock:(RCTImageLoaderProgressBlock)progressBlock
|
||||
partialLoadBlock:(RCTImageLoaderPartialLoadBlock)partialLoadBlock
|
||||
completionBlock:(RCTImageLoaderCompletionBlock)completionBlock;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Image instrumentation - notify that the image content (UIImage) has been set on the native view.
|
||||
*/
|
||||
- (void)trackURLImageContentDidSetForRequest:(RCTImageURLLoaderRequest *)loaderRequest;
|
||||
|
||||
/**
|
||||
* Image instrumentation - start tracking the on-screen visibility of the native image view.
|
||||
*/
|
||||
- (void)trackURLImageVisibilityForRequest:(RCTImageURLLoaderRequest *)loaderRequest imageView:(UIView *)imageView;
|
||||
|
||||
/**
|
||||
* Image instrumentation - notify that the native image view was destroyed.
|
||||
*/
|
||||
- (void)trackURLImageDidDestroy:(RCTImageURLLoaderRequest *)loaderRequest;
|
||||
|
||||
@end
|
44
node_modules/react-native/Libraries/Image/RCTImagePlugins.h
generated
vendored
Normal file
44
node_modules/react-native/Libraries/Image/RCTImagePlugins.h
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @generated by an internal plugin build system
|
||||
*/
|
||||
|
||||
#ifdef RN_DISABLE_OSS_PLUGIN_HEADER
|
||||
|
||||
// FB Internal: FBRCTImagePlugins.h is autogenerated by the build system.
|
||||
#import <React/FBRCTImagePlugins.h>
|
||||
|
||||
#else
|
||||
|
||||
// OSS-compatibility layer
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wreturn-type-c-linkage"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// RCTTurboModuleManagerDelegate should call this to resolve module classes.
|
||||
Class RCTImageClassProvider(const char *name);
|
||||
|
||||
// Lookup functions
|
||||
Class RCTGIFImageDecoderCls(void) __attribute__((used));
|
||||
Class RCTImageEditingManagerCls(void) __attribute__((used));
|
||||
Class RCTImageLoaderCls(void) __attribute__((used));
|
||||
Class RCTImageStoreManagerCls(void) __attribute__((used));
|
||||
Class RCTLocalAssetImageLoaderCls(void) __attribute__((used));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#endif // RN_DISABLE_OSS_PLUGIN_HEADER
|
36
node_modules/react-native/Libraries/Image/RCTImagePlugins.mm
generated
vendored
Normal file
36
node_modules/react-native/Libraries/Image/RCTImagePlugins.mm
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @generated by an internal plugin build system
|
||||
*/
|
||||
|
||||
#ifndef RN_DISABLE_OSS_PLUGIN_HEADER
|
||||
|
||||
// OSS-compatibility layer
|
||||
|
||||
#import "RCTImagePlugins.h"
|
||||
|
||||
#import <string>
|
||||
#import <unordered_map>
|
||||
|
||||
Class RCTImageClassProvider(const char *name) {
|
||||
static std::unordered_map<std::string, Class (*)(void)> sCoreModuleClassMap = {
|
||||
{"GIFImageDecoder", RCTGIFImageDecoderCls},
|
||||
{"ImageEditingManager", RCTImageEditingManagerCls},
|
||||
{"ImageLoader", RCTImageLoaderCls},
|
||||
{"ImageStoreManager", RCTImageStoreManagerCls},
|
||||
{"LocalAssetImageLoader", RCTLocalAssetImageLoaderCls},
|
||||
};
|
||||
|
||||
auto p = sCoreModuleClassMap.find(name);
|
||||
if (p != sCoreModuleClassMap.end()) {
|
||||
auto classFunc = p->second;
|
||||
return classFunc();
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
#endif // RN_DISABLE_OSS_PLUGIN_HEADER
|
12
node_modules/react-native/Libraries/Image/RCTImageShadowView.h
generated
vendored
Normal file
12
node_modules/react-native/Libraries/Image/RCTImageShadowView.h
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
/*
|
||||
* 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 <React/RCTShadowView.h>
|
||||
|
||||
@interface RCTImageShadowView : RCTShadowView
|
||||
|
||||
@end
|
24
node_modules/react-native/Libraries/Image/RCTImageShadowView.m
generated
vendored
Normal file
24
node_modules/react-native/Libraries/Image/RCTImageShadowView.m
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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 <React/RCTImageShadowView.h>
|
||||
|
||||
#import <React/RCTLog.h>
|
||||
|
||||
@implementation RCTImageShadowView
|
||||
|
||||
- (BOOL)isYogaLeafNode
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)canHaveSubviews
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
46
node_modules/react-native/Libraries/Image/RCTImageStoreManager.h
generated
vendored
Normal file
46
node_modules/react-native/Libraries/Image/RCTImageStoreManager.h
generated
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 <UIKit/UIKit.h>
|
||||
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTURLRequestHandler.h>
|
||||
|
||||
@interface RCTImageStoreManager : NSObject <RCTURLRequestHandler>
|
||||
|
||||
/**
|
||||
* Set and get cached image data asynchronously. It is safe to call these from any
|
||||
* thread. The callbacks will be called on an unspecified thread.
|
||||
*/
|
||||
- (void)removeImageForTag:(NSString *)imageTag withBlock:(void (^)(void))block;
|
||||
- (void)storeImageData:(NSData *)imageData withBlock:(void (^)(NSString *imageTag))block;
|
||||
- (void)getImageDataForTag:(NSString *)imageTag withBlock:(void (^)(NSData *imageData))block;
|
||||
|
||||
/**
|
||||
* Convenience method to store an image directly (image is converted to data
|
||||
* internally, so any metadata such as scale or orientation will be lost).
|
||||
*/
|
||||
- (void)storeImage:(UIImage *)image withBlock:(void (^)(NSString *imageTag))block;
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTImageStoreManager (Deprecated)
|
||||
|
||||
/**
|
||||
* These methods are deprecated - use the data-based alternatives instead.
|
||||
*/
|
||||
- (NSString *)storeImage:(UIImage *)image __deprecated;
|
||||
- (UIImage *)imageForTag:(NSString *)imageTag __deprecated;
|
||||
- (void)getImageForTag:(NSString *)imageTag withBlock:(void (^)(UIImage *image))block __deprecated;
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTBridge (RCTImageStoreManager)
|
||||
|
||||
@property (nonatomic, readonly) RCTImageStoreManager *imageStoreManager;
|
||||
|
||||
@end
|
258
node_modules/react-native/Libraries/Image/RCTImageStoreManager.mm
generated
vendored
Normal file
258
node_modules/react-native/Libraries/Image/RCTImageStoreManager.mm
generated
vendored
Normal file
@ -0,0 +1,258 @@
|
||||
/*
|
||||
* 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 <React/RCTImageStoreManager.h>
|
||||
|
||||
#import <atomic>
|
||||
#import <memory>
|
||||
|
||||
#import <FBReactNativeSpec/FBReactNativeSpec.h>
|
||||
#import <ImageIO/ImageIO.h>
|
||||
#import <MobileCoreServices/UTType.h>
|
||||
#import <React/RCTAssert.h>
|
||||
#import <React/RCTLog.h>
|
||||
#import <React/RCTUtils.h>
|
||||
#import <React/RCTImageUtils.h>
|
||||
|
||||
#import "RCTImagePlugins.h"
|
||||
|
||||
static NSString *const RCTImageStoreURLScheme = @"rct-image-store";
|
||||
|
||||
@interface RCTImageStoreManager() <NativeImageStoreSpec>
|
||||
@end
|
||||
|
||||
@implementation RCTImageStoreManager
|
||||
{
|
||||
NSMutableDictionary<NSString *, NSData *> *_store;
|
||||
NSUInteger _id;
|
||||
}
|
||||
|
||||
@synthesize methodQueue = _methodQueue;
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (float)handlerPriority
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
- (void)removeImageForTag:(NSString *)imageTag withBlock:(void (^)(void))block
|
||||
{
|
||||
dispatch_async(_methodQueue, ^{
|
||||
[self removeImageForTag:imageTag];
|
||||
if (block) {
|
||||
block();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (NSString *)_storeImageData:(NSData *)imageData
|
||||
{
|
||||
RCTAssertThread(_methodQueue, @"Must be called on RCTImageStoreManager thread");
|
||||
|
||||
if (!_store) {
|
||||
_store = [NSMutableDictionary new];
|
||||
_id = 0;
|
||||
}
|
||||
|
||||
NSString *imageTag = [NSString stringWithFormat:@"%@://%tu", RCTImageStoreURLScheme, _id++];
|
||||
_store[imageTag] = imageData;
|
||||
return imageTag;
|
||||
}
|
||||
|
||||
- (void)storeImageData:(NSData *)imageData withBlock:(void (^)(NSString *imageTag))block
|
||||
{
|
||||
RCTAssertParam(block);
|
||||
dispatch_async(_methodQueue, ^{
|
||||
block([self _storeImageData:imageData]);
|
||||
});
|
||||
}
|
||||
|
||||
- (void)getImageDataForTag:(NSString *)imageTag withBlock:(void (^)(NSData *imageData))block
|
||||
{
|
||||
RCTAssertParam(block);
|
||||
dispatch_async(_methodQueue, ^{
|
||||
block(self->_store[imageTag]);
|
||||
});
|
||||
}
|
||||
|
||||
- (void)storeImage:(UIImage *)image withBlock:(void (^)(NSString *imageTag))block
|
||||
{
|
||||
RCTAssertParam(block);
|
||||
dispatch_async(_methodQueue, ^{
|
||||
NSString *imageTag = [self _storeImageData:RCTGetImageData(image, 0.75)];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
block(imageTag);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(removeImageForTag:(NSString *)imageTag)
|
||||
{
|
||||
[_store removeObjectForKey:imageTag];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(hasImageForTag:(NSString *)imageTag
|
||||
callback:(RCTResponseSenderBlock)callback)
|
||||
{
|
||||
callback(@[@(_store[imageTag] != nil)]);
|
||||
}
|
||||
|
||||
// TODO (#5906496): Name could be more explicit - something like getBase64EncodedDataForTag:?
|
||||
RCT_EXPORT_METHOD(getBase64ForTag:(NSString *)imageTag
|
||||
successCallback:(RCTResponseSenderBlock)successCallback
|
||||
errorCallback:(RCTResponseSenderBlock)errorCallback)
|
||||
{
|
||||
NSData *imageData = _store[imageTag];
|
||||
if (!imageData) {
|
||||
errorCallback(@[RCTJSErrorFromNSError(RCTErrorWithMessage([NSString stringWithFormat:@"Invalid imageTag: %@", imageTag]))]);
|
||||
return;
|
||||
}
|
||||
// Dispatching to a background thread to perform base64 encoding
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
successCallback(@[[imageData base64EncodedStringWithOptions:0]]);
|
||||
});
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(addImageFromBase64:(NSString *)base64String
|
||||
successCallback:(RCTResponseSenderBlock)successCallback
|
||||
errorCallback:(RCTResponseSenderBlock)errorCallback)
|
||||
|
||||
{
|
||||
// Dispatching to a background thread to perform base64 decoding
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
NSData *imageData = [[NSData alloc] initWithBase64EncodedString:base64String options:0];
|
||||
if (imageData) {
|
||||
dispatch_async(self->_methodQueue, ^{
|
||||
successCallback(@[[self _storeImageData:imageData]]);
|
||||
});
|
||||
} else {
|
||||
errorCallback(@[RCTJSErrorFromNSError(RCTErrorWithMessage(@"Failed to add image from base64String"))]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - RCTURLRequestHandler
|
||||
|
||||
- (BOOL)canHandleRequest:(NSURLRequest *)request
|
||||
{
|
||||
return [request.URL.scheme caseInsensitiveCompare:RCTImageStoreURLScheme] == NSOrderedSame;
|
||||
}
|
||||
|
||||
- (id)sendRequest:(NSURLRequest *)request withDelegate:(id<RCTURLRequestDelegate>)delegate
|
||||
{
|
||||
__block auto cancelled = std::make_shared<std::atomic<bool>>(false);
|
||||
void (^cancellationBlock)(void) = ^{
|
||||
cancelled->store(true);
|
||||
};
|
||||
|
||||
// Dispatch async to give caller time to cancel the request
|
||||
dispatch_async(_methodQueue, ^{
|
||||
if (cancelled->load()) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *imageTag = request.URL.absoluteString;
|
||||
NSData *imageData = self->_store[imageTag];
|
||||
if (!imageData) {
|
||||
NSError *error = RCTErrorWithMessage([NSString stringWithFormat:@"Invalid imageTag: %@", imageTag]);
|
||||
[delegate URLRequest:cancellationBlock didCompleteWithError:error];
|
||||
return;
|
||||
}
|
||||
|
||||
CGImageSourceRef sourceRef = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL);
|
||||
if (!sourceRef) {
|
||||
NSError *error = RCTErrorWithMessage([NSString stringWithFormat:@"Unable to decode data for imageTag: %@", imageTag]);
|
||||
[delegate URLRequest:cancellationBlock didCompleteWithError:error];
|
||||
return;
|
||||
}
|
||||
CFStringRef UTI = CGImageSourceGetType(sourceRef);
|
||||
CFRelease(sourceRef);
|
||||
|
||||
NSString *MIMEType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass(UTI, kUTTagClassMIMEType);
|
||||
NSURLResponse *response = [[NSURLResponse alloc] initWithURL:request.URL
|
||||
MIMEType:MIMEType
|
||||
expectedContentLength:imageData.length
|
||||
textEncodingName:nil];
|
||||
CFRelease(UTI);
|
||||
|
||||
[delegate URLRequest:cancellationBlock didReceiveResponse:response];
|
||||
[delegate URLRequest:cancellationBlock didReceiveData:imageData];
|
||||
[delegate URLRequest:cancellationBlock didCompleteWithError:nil];
|
||||
|
||||
});
|
||||
|
||||
return cancellationBlock;
|
||||
}
|
||||
|
||||
- (void)cancelRequest:(id)requestToken
|
||||
{
|
||||
if (requestToken) {
|
||||
((void (^)(void))requestToken)();
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTImageStoreManager (Deprecated)
|
||||
|
||||
- (NSString *)storeImage:(UIImage *)image
|
||||
{
|
||||
RCTAssertMainQueue();
|
||||
RCTLogWarn(@"RCTImageStoreManager.storeImage() is deprecated and has poor performance. Use an alternative method instead.");
|
||||
__block NSString *imageTag;
|
||||
dispatch_sync(_methodQueue, ^{
|
||||
imageTag = [self _storeImageData:RCTGetImageData(image, 0.75)];
|
||||
});
|
||||
return imageTag;
|
||||
}
|
||||
|
||||
- (UIImage *)imageForTag:(NSString *)imageTag
|
||||
{
|
||||
RCTAssertMainQueue();
|
||||
RCTLogWarn(@"RCTImageStoreManager.imageForTag() is deprecated and has poor performance. Use an alternative method instead.");
|
||||
__block NSData *imageData;
|
||||
dispatch_sync(_methodQueue, ^{
|
||||
imageData = self->_store[imageTag];
|
||||
});
|
||||
return [UIImage imageWithData:imageData];
|
||||
}
|
||||
|
||||
- (void)getImageForTag:(NSString *)imageTag withBlock:(void (^)(UIImage *image))block
|
||||
{
|
||||
RCTAssertParam(block);
|
||||
dispatch_async(_methodQueue, ^{
|
||||
NSData *imageData = self->_store[imageTag];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// imageWithData: is not thread-safe, so we can't do this on methodQueue
|
||||
block([UIImage imageWithData:imageData]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
- (std::shared_ptr<facebook::react::TurboModule>)
|
||||
getTurboModuleWithJsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
|
||||
nativeInvoker:(std::shared_ptr<facebook::react::CallInvoker>)nativeInvoker
|
||||
perfLogger:(id<RCTTurboModulePerformanceLogger>)perfLogger
|
||||
{
|
||||
return std::make_shared<facebook::react::NativeImageStoreSpecJSI>(self, jsInvoker, nativeInvoker, perfLogger);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTBridge (RCTImageStoreManager)
|
||||
|
||||
- (RCTImageStoreManager *)imageStoreManager
|
||||
{
|
||||
return [self moduleForClass:[RCTImageStoreManager class]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Class RCTImageStoreManagerCls(void) {
|
||||
return RCTImageStoreManager.class;
|
||||
}
|
73
node_modules/react-native/Libraries/Image/RCTImageURLLoader.h
generated
vendored
Normal file
73
node_modules/react-native/Libraries/Image/RCTImageURLLoader.h
generated
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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 <UIKit/UIKit.h>
|
||||
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTResizeMode.h>
|
||||
|
||||
typedef void (^RCTImageLoaderProgressBlock)(int64_t progress, int64_t total);
|
||||
typedef void (^RCTImageLoaderPartialLoadBlock)(UIImage *image);
|
||||
typedef void (^RCTImageLoaderCompletionBlock)(NSError *error, UIImage *image);
|
||||
typedef dispatch_block_t RCTImageLoaderCancellationBlock;
|
||||
|
||||
/**
|
||||
* Provides the interface needed to register an image loader. Image data
|
||||
* loaders are also bridge modules, so should be registered using
|
||||
* RCT_EXPORT_MODULE().
|
||||
*/
|
||||
@protocol RCTImageURLLoader <RCTBridgeModule>
|
||||
|
||||
/**
|
||||
* Indicates whether this data loader is capable of processing the specified
|
||||
* request URL. Typically the handler would examine the scheme/protocol of the
|
||||
* URL to determine this.
|
||||
*/
|
||||
- (BOOL)canLoadImageURL:(NSURL *)requestURL;
|
||||
|
||||
/**
|
||||
* Send a network request to load the request URL. The method should call the
|
||||
* progressHandler (if applicable) and the completionHandler when the request
|
||||
* has finished. The method should also return a cancellation block, if
|
||||
* applicable.
|
||||
*/
|
||||
- (nullable RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL
|
||||
size:(CGSize)size
|
||||
scale:(CGFloat)scale
|
||||
resizeMode:(RCTResizeMode)resizeMode
|
||||
progressHandler:(RCTImageLoaderProgressBlock)progressHandler
|
||||
partialLoadHandler:(RCTImageLoaderPartialLoadBlock)partialLoadHandler
|
||||
completionHandler:(RCTImageLoaderCompletionBlock)completionHandler;
|
||||
|
||||
@optional
|
||||
|
||||
/**
|
||||
* If more than one RCTImageURLLoader responds YES to `-canLoadImageURL:`
|
||||
* then `loaderPriority` is used to determine which one to use. The loader
|
||||
* with the highest priority will be selected. Default priority is zero. If
|
||||
* two or more valid loaders have the same priority, the selection order is
|
||||
* undefined.
|
||||
*/
|
||||
- (float)loaderPriority;
|
||||
|
||||
/**
|
||||
* If the loader must be called on the serial url cache queue, and whether the completion
|
||||
* block should be dispatched off the main thread. If this is NO, the loader will be
|
||||
* called from the main queue. Defaults to YES.
|
||||
*
|
||||
* Use with care: disabling scheduling will reduce RCTImageLoader's ability to throttle
|
||||
* network requests.
|
||||
*/
|
||||
- (BOOL)requiresScheduling;
|
||||
|
||||
/**
|
||||
* If images loaded by the loader should be cached in the decoded image cache.
|
||||
* Defaults to YES.
|
||||
*/
|
||||
- (BOOL)shouldCacheLoadedImages;
|
||||
|
||||
@end
|
75
node_modules/react-native/Libraries/Image/RCTImageURLLoaderWithAttribution.h
generated
vendored
Normal file
75
node_modules/react-native/Libraries/Image/RCTImageURLLoaderWithAttribution.h
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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 <React/RCTImageURLLoader.h>
|
||||
#import <React/RCTImageLoaderProtocol.h>
|
||||
|
||||
// TODO (T61325135): Remove C++ checks
|
||||
#ifdef __cplusplus
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
struct ImageURLLoaderAttribution {
|
||||
int32_t nativeViewTag = 0;
|
||||
int32_t surfaceId = 0;
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
#endif
|
||||
|
||||
@interface RCTImageURLLoaderRequest : NSObject
|
||||
|
||||
@property (nonatomic, strong, readonly) NSString *requestId;
|
||||
@property (nonatomic, strong, readonly) NSURL *imageURL;
|
||||
@property (nonatomic, copy, readonly) RCTImageLoaderCancellationBlock cancellationBlock;
|
||||
|
||||
- (instancetype)initWithRequestId:(NSString *)requestId imageURL:(NSURL *)imageURL cancellationBlock:(RCTImageLoaderCancellationBlock)cancellationBlock;
|
||||
- (void)cancel;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
* Same as the RCTImageURLLoader interface, but allows passing in optional `attribution` information.
|
||||
* This is useful for per-app logging and other instrumentation.
|
||||
*/
|
||||
@protocol RCTImageURLLoaderWithAttribution <RCTImageURLLoader>
|
||||
|
||||
// TODO (T61325135): Remove C++ checks
|
||||
#ifdef __cplusplus
|
||||
/**
|
||||
* Same as the RCTImageURLLoader variant above, but allows optional `attribution` information.
|
||||
* Caller may also specify a preferred requestId for tracking purpose.
|
||||
*/
|
||||
- (RCTImageURLLoaderRequest *)loadImageForURL:(NSURL *)imageURL
|
||||
size:(CGSize)size
|
||||
scale:(CGFloat)scale
|
||||
resizeMode:(RCTResizeMode)resizeMode
|
||||
requestId:(NSString *)requestId
|
||||
priority: (RCTImageLoaderPriority)priority
|
||||
attribution:(const facebook::react::ImageURLLoaderAttribution &)attribution
|
||||
progressHandler:(RCTImageLoaderProgressBlock)progressHandler
|
||||
partialLoadHandler:(RCTImageLoaderPartialLoadBlock)partialLoadHandler
|
||||
completionHandler:(RCTImageLoaderCompletionBlock)completionHandler;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Image instrumentation - notify that the image content (UIImage) has been set on the native view.
|
||||
*/
|
||||
- (void)trackURLImageContentDidSetForRequest:(RCTImageURLLoaderRequest *)loaderRequest;
|
||||
|
||||
/**
|
||||
* Image instrumentation - start tracking the on-screen visibility of the native image view.
|
||||
*/
|
||||
- (void)trackURLImageVisibilityForRequest:(RCTImageURLLoaderRequest *)loaderRequest imageView:(UIView *)imageView;
|
||||
|
||||
/**
|
||||
* Image instrumentation - notify that the native image view was destroyed.
|
||||
*/
|
||||
- (void)trackURLImageDidDestroy:(RCTImageURLLoaderRequest *)loaderRequest;
|
||||
|
||||
@end
|
30
node_modules/react-native/Libraries/Image/RCTImageURLLoaderWithAttribution.mm
generated
vendored
Normal file
30
node_modules/react-native/Libraries/Image/RCTImageURLLoaderWithAttribution.mm
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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 "RCTImageURLLoaderWithAttribution.h"
|
||||
|
||||
@implementation RCTImageURLLoaderRequest
|
||||
|
||||
- (instancetype)initWithRequestId:(NSString *)requestId imageURL:(NSURL *)imageURL cancellationBlock:(RCTImageLoaderCancellationBlock)cancellationBlock
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_requestId = requestId;
|
||||
_imageURL = imageURL;
|
||||
_cancellationBlock = cancellationBlock;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)cancel
|
||||
{
|
||||
if (_cancellationBlock) {
|
||||
_cancellationBlock();
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
93
node_modules/react-native/Libraries/Image/RCTImageUtils.h
generated
vendored
Normal file
93
node_modules/react-native/Libraries/Image/RCTImageUtils.h
generated
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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 <UIKit/UIKit.h>
|
||||
|
||||
#import <React/RCTDefines.h>
|
||||
#import <React/RCTResizeMode.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
* This function takes an source size (typically from an image), a target size
|
||||
* and scale that it will be drawn at (typically in a CGContext) and then
|
||||
* calculates the rectangle to draw the image into so that it will be sized and
|
||||
* positioned correctly according to the specified resizeMode.
|
||||
*/
|
||||
RCT_EXTERN CGRect RCTTargetRect(CGSize sourceSize, CGSize destSize,
|
||||
CGFloat destScale, RCTResizeMode resizeMode);
|
||||
|
||||
/**
|
||||
* This function takes a source size (typically from an image), a target rect
|
||||
* that it will be drawn into (typically relative to a CGContext), and works out
|
||||
* the transform needed to draw the image at the correct scale and position.
|
||||
*/
|
||||
RCT_EXTERN CGAffineTransform RCTTransformFromTargetRect(CGSize sourceSize,
|
||||
CGRect targetRect);
|
||||
|
||||
/**
|
||||
* This function takes an input content size & scale (typically from an image),
|
||||
* a target size & scale at which it will be displayed (typically in a
|
||||
* UIImageView) and then calculates the optimal size at which to redraw the
|
||||
* image so that it will be displayed correctly with the specified resizeMode.
|
||||
*/
|
||||
RCT_EXTERN CGSize RCTTargetSize(CGSize sourceSize, CGFloat sourceScale,
|
||||
CGSize destSize, CGFloat destScale,
|
||||
RCTResizeMode resizeMode, BOOL allowUpscaling);
|
||||
|
||||
/**
|
||||
* This function takes an input content size & scale (typically from an image),
|
||||
* a target size & scale that it will be displayed at, and determines if the
|
||||
* source will need to be upscaled to fit (which may result in pixelization).
|
||||
*/
|
||||
RCT_EXTERN BOOL RCTUpscalingRequired(CGSize sourceSize, CGFloat sourceScale,
|
||||
CGSize destSize, CGFloat destScale,
|
||||
RCTResizeMode resizeMode);
|
||||
|
||||
/**
|
||||
* This function takes the source data for an image and decodes it at the
|
||||
* specified size. If the original image is smaller than the destination size,
|
||||
* the resultant image's scale will be decreased to compensate, so the
|
||||
* width/height of the returned image is guaranteed to be >= destSize.
|
||||
* Pass a destSize of CGSizeZero to decode the image at its original size.
|
||||
*/
|
||||
RCT_EXTERN UIImage *__nullable RCTDecodeImageWithData(NSData *data,
|
||||
CGSize destSize,
|
||||
CGFloat destScale,
|
||||
RCTResizeMode resizeMode);
|
||||
|
||||
/**
|
||||
* This function takes the source data for an image and decodes just the
|
||||
* metadata, without decompressing the image itself.
|
||||
*/
|
||||
RCT_EXTERN NSDictionary<NSString *, id> *__nullable RCTGetImageMetadata(NSData *data);
|
||||
|
||||
/**
|
||||
* Convert an image back into data. Images with an alpha channel will be
|
||||
* converted to lossless PNG data. Images without alpha will be converted to
|
||||
* JPEG. The `quality` argument controls the compression ratio of the JPEG
|
||||
* conversion, with 1.0 being maximum quality. It has no effect for images
|
||||
* using PNG compression.
|
||||
*/
|
||||
RCT_EXTERN NSData *__nullable RCTGetImageData(UIImage *image, float quality);
|
||||
|
||||
/**
|
||||
* This function transforms an image. `destSize` is the size of the final image,
|
||||
* and `destScale` is its scale. The `transform` argument controls how the
|
||||
* source image will be mapped to the destination image.
|
||||
*/
|
||||
RCT_EXTERN UIImage *__nullable RCTTransformImage(UIImage *image,
|
||||
CGSize destSize,
|
||||
CGFloat destScale,
|
||||
CGAffineTransform transform);
|
||||
|
||||
/*
|
||||
* Return YES if image has an alpha component
|
||||
*/
|
||||
RCT_EXTERN BOOL RCTImageHasAlpha(CGImageRef image);
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
392
node_modules/react-native/Libraries/Image/RCTImageUtils.m
generated
vendored
Normal file
392
node_modules/react-native/Libraries/Image/RCTImageUtils.m
generated
vendored
Normal file
@ -0,0 +1,392 @@
|
||||
/*
|
||||
* 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 <React/RCTImageUtils.h>
|
||||
|
||||
#import <tgmath.h>
|
||||
|
||||
#import <ImageIO/ImageIO.h>
|
||||
#import <MobileCoreServices/UTCoreTypes.h>
|
||||
|
||||
#import <React/RCTLog.h>
|
||||
#import <React/RCTUtils.h>
|
||||
|
||||
static CGFloat RCTCeilValue(CGFloat value, CGFloat scale)
|
||||
{
|
||||
return ceil(value * scale) / scale;
|
||||
}
|
||||
|
||||
static CGFloat RCTFloorValue(CGFloat value, CGFloat scale)
|
||||
{
|
||||
return floor(value * scale) / scale;
|
||||
}
|
||||
|
||||
static CGSize RCTCeilSize(CGSize size, CGFloat scale)
|
||||
{
|
||||
return (CGSize){
|
||||
RCTCeilValue(size.width, scale),
|
||||
RCTCeilValue(size.height, scale)
|
||||
};
|
||||
}
|
||||
|
||||
static CGImagePropertyOrientation CGImagePropertyOrientationFromUIImageOrientation(UIImageOrientation imageOrientation)
|
||||
{
|
||||
// see https://stackoverflow.com/a/6699649/496389
|
||||
switch (imageOrientation) {
|
||||
case UIImageOrientationUp: return kCGImagePropertyOrientationUp;
|
||||
case UIImageOrientationDown: return kCGImagePropertyOrientationDown;
|
||||
case UIImageOrientationLeft: return kCGImagePropertyOrientationLeft;
|
||||
case UIImageOrientationRight: return kCGImagePropertyOrientationRight;
|
||||
case UIImageOrientationUpMirrored: return kCGImagePropertyOrientationUpMirrored;
|
||||
case UIImageOrientationDownMirrored: return kCGImagePropertyOrientationDownMirrored;
|
||||
case UIImageOrientationLeftMirrored: return kCGImagePropertyOrientationLeftMirrored;
|
||||
case UIImageOrientationRightMirrored: return kCGImagePropertyOrientationRightMirrored;
|
||||
default: return kCGImagePropertyOrientationUp;
|
||||
}
|
||||
}
|
||||
|
||||
CGRect RCTTargetRect(CGSize sourceSize, CGSize destSize,
|
||||
CGFloat destScale, RCTResizeMode resizeMode)
|
||||
{
|
||||
if (CGSizeEqualToSize(destSize, CGSizeZero)) {
|
||||
// Assume we require the largest size available
|
||||
return (CGRect){CGPointZero, sourceSize};
|
||||
}
|
||||
|
||||
CGFloat aspect = sourceSize.width / sourceSize.height;
|
||||
// If only one dimension in destSize is non-zero (for example, an Image
|
||||
// with `flex: 1` whose height is indeterminate), calculate the unknown
|
||||
// dimension based on the aspect ratio of sourceSize
|
||||
if (destSize.width == 0) {
|
||||
destSize.width = destSize.height * aspect;
|
||||
}
|
||||
if (destSize.height == 0) {
|
||||
destSize.height = destSize.width / aspect;
|
||||
}
|
||||
|
||||
// Calculate target aspect ratio if needed
|
||||
CGFloat targetAspect = 0.0;
|
||||
if (resizeMode != RCTResizeModeCenter &&
|
||||
resizeMode != RCTResizeModeStretch) {
|
||||
targetAspect = destSize.width / destSize.height;
|
||||
if (aspect == targetAspect) {
|
||||
resizeMode = RCTResizeModeStretch;
|
||||
}
|
||||
}
|
||||
|
||||
switch (resizeMode) {
|
||||
case RCTResizeModeStretch:
|
||||
case RCTResizeModeRepeat:
|
||||
|
||||
return (CGRect){CGPointZero, RCTCeilSize(destSize, destScale)};
|
||||
|
||||
case RCTResizeModeContain:
|
||||
|
||||
if (targetAspect <= aspect) { // target is taller than content
|
||||
|
||||
sourceSize.width = destSize.width;
|
||||
sourceSize.height = sourceSize.width / aspect;
|
||||
|
||||
} else { // target is wider than content
|
||||
|
||||
sourceSize.height = destSize.height;
|
||||
sourceSize.width = sourceSize.height * aspect;
|
||||
}
|
||||
return (CGRect){
|
||||
{
|
||||
RCTFloorValue((destSize.width - sourceSize.width) / 2, destScale),
|
||||
RCTFloorValue((destSize.height - sourceSize.height) / 2, destScale),
|
||||
},
|
||||
RCTCeilSize(sourceSize, destScale)
|
||||
};
|
||||
|
||||
case RCTResizeModeCover:
|
||||
|
||||
if (targetAspect <= aspect) { // target is taller than content
|
||||
|
||||
sourceSize.height = destSize.height;
|
||||
sourceSize.width = sourceSize.height * aspect;
|
||||
destSize.width = destSize.height * targetAspect;
|
||||
return (CGRect){
|
||||
{RCTFloorValue((destSize.width - sourceSize.width) / 2, destScale), 0},
|
||||
RCTCeilSize(sourceSize, destScale)
|
||||
};
|
||||
|
||||
} else { // target is wider than content
|
||||
|
||||
sourceSize.width = destSize.width;
|
||||
sourceSize.height = sourceSize.width / aspect;
|
||||
destSize.height = destSize.width / targetAspect;
|
||||
return (CGRect){
|
||||
{0, RCTFloorValue((destSize.height - sourceSize.height) / 2, destScale)},
|
||||
RCTCeilSize(sourceSize, destScale)
|
||||
};
|
||||
}
|
||||
|
||||
case RCTResizeModeCenter:
|
||||
|
||||
// Make sure the image is not clipped by the target.
|
||||
if (sourceSize.height > destSize.height) {
|
||||
sourceSize.width = destSize.width;
|
||||
sourceSize.height = sourceSize.width / aspect;
|
||||
}
|
||||
if (sourceSize.width > destSize.width) {
|
||||
sourceSize.height = destSize.height;
|
||||
sourceSize.width = sourceSize.height * aspect;
|
||||
}
|
||||
|
||||
return (CGRect){
|
||||
{
|
||||
RCTFloorValue((destSize.width - sourceSize.width) / 2, destScale),
|
||||
RCTFloorValue((destSize.height - sourceSize.height) / 2, destScale),
|
||||
},
|
||||
RCTCeilSize(sourceSize, destScale)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
CGAffineTransform RCTTransformFromTargetRect(CGSize sourceSize, CGRect targetRect)
|
||||
{
|
||||
CGAffineTransform transform = CGAffineTransformIdentity;
|
||||
transform = CGAffineTransformTranslate(transform,
|
||||
targetRect.origin.x,
|
||||
targetRect.origin.y);
|
||||
transform = CGAffineTransformScale(transform,
|
||||
targetRect.size.width / sourceSize.width,
|
||||
targetRect.size.height / sourceSize.height);
|
||||
return transform;
|
||||
}
|
||||
|
||||
CGSize RCTTargetSize(CGSize sourceSize, CGFloat sourceScale,
|
||||
CGSize destSize, CGFloat destScale,
|
||||
RCTResizeMode resizeMode,
|
||||
BOOL allowUpscaling)
|
||||
{
|
||||
switch (resizeMode) {
|
||||
case RCTResizeModeCenter:
|
||||
|
||||
return RCTTargetRect(sourceSize, destSize, destScale, resizeMode).size;
|
||||
|
||||
case RCTResizeModeStretch:
|
||||
|
||||
if (!allowUpscaling) {
|
||||
CGFloat scale = sourceScale / destScale;
|
||||
destSize.width = MIN(sourceSize.width * scale, destSize.width);
|
||||
destSize.height = MIN(sourceSize.height * scale, destSize.height);
|
||||
}
|
||||
return RCTCeilSize(destSize, destScale);
|
||||
|
||||
default: {
|
||||
|
||||
// Get target size
|
||||
CGSize size = RCTTargetRect(sourceSize, destSize, destScale, resizeMode).size;
|
||||
if (!allowUpscaling) {
|
||||
// return sourceSize if target size is larger
|
||||
if (sourceSize.width * sourceScale < size.width * destScale) {
|
||||
return sourceSize;
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOL RCTUpscalingRequired(CGSize sourceSize, CGFloat sourceScale,
|
||||
CGSize destSize, CGFloat destScale,
|
||||
RCTResizeMode resizeMode)
|
||||
{
|
||||
if (CGSizeEqualToSize(destSize, CGSizeZero)) {
|
||||
// Assume we require the largest size available
|
||||
return YES;
|
||||
}
|
||||
|
||||
// Precompensate for scale
|
||||
CGFloat scale = sourceScale / destScale;
|
||||
sourceSize.width *= scale;
|
||||
sourceSize.height *= scale;
|
||||
|
||||
// Calculate aspect ratios if needed (don't bother if resizeMode == stretch)
|
||||
CGFloat aspect = 0.0, targetAspect = 0.0;
|
||||
if (resizeMode != UIViewContentModeScaleToFill) {
|
||||
aspect = sourceSize.width / sourceSize.height;
|
||||
targetAspect = destSize.width / destSize.height;
|
||||
if (aspect == targetAspect) {
|
||||
resizeMode = RCTResizeModeStretch;
|
||||
}
|
||||
}
|
||||
|
||||
switch (resizeMode) {
|
||||
case RCTResizeModeStretch:
|
||||
|
||||
return destSize.width > sourceSize.width || destSize.height > sourceSize.height;
|
||||
|
||||
case RCTResizeModeContain:
|
||||
|
||||
if (targetAspect <= aspect) { // target is taller than content
|
||||
|
||||
return destSize.width > sourceSize.width;
|
||||
|
||||
} else { // target is wider than content
|
||||
|
||||
return destSize.height > sourceSize.height;
|
||||
}
|
||||
|
||||
case RCTResizeModeCover:
|
||||
|
||||
if (targetAspect <= aspect) { // target is taller than content
|
||||
|
||||
return destSize.height > sourceSize.height;
|
||||
|
||||
} else { // target is wider than content
|
||||
|
||||
return destSize.width > sourceSize.width;
|
||||
}
|
||||
|
||||
case RCTResizeModeRepeat:
|
||||
case RCTResizeModeCenter:
|
||||
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
UIImage *__nullable RCTDecodeImageWithData(NSData *data,
|
||||
CGSize destSize,
|
||||
CGFloat destScale,
|
||||
RCTResizeMode resizeMode)
|
||||
{
|
||||
CGImageSourceRef sourceRef = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
|
||||
if (!sourceRef) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Get original image size
|
||||
CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(sourceRef, 0, NULL);
|
||||
if (!imageProperties) {
|
||||
CFRelease(sourceRef);
|
||||
return nil;
|
||||
}
|
||||
NSNumber *width = CFDictionaryGetValue(imageProperties, kCGImagePropertyPixelWidth);
|
||||
NSNumber *height = CFDictionaryGetValue(imageProperties, kCGImagePropertyPixelHeight);
|
||||
CGSize sourceSize = {width.doubleValue, height.doubleValue};
|
||||
CFRelease(imageProperties);
|
||||
|
||||
if (CGSizeEqualToSize(destSize, CGSizeZero)) {
|
||||
destSize = sourceSize;
|
||||
if (!destScale) {
|
||||
destScale = 1;
|
||||
}
|
||||
} else if (!destScale) {
|
||||
destScale = RCTScreenScale();
|
||||
}
|
||||
|
||||
if (resizeMode == UIViewContentModeScaleToFill) {
|
||||
// Decoder cannot change aspect ratio, so RCTResizeModeStretch is equivalent
|
||||
// to RCTResizeModeCover for our purposes
|
||||
resizeMode = RCTResizeModeCover;
|
||||
}
|
||||
|
||||
// Calculate target size
|
||||
CGSize targetSize = RCTTargetSize(sourceSize, 1, destSize, destScale, resizeMode, NO);
|
||||
CGSize targetPixelSize = RCTSizeInPixels(targetSize, destScale);
|
||||
CGFloat maxPixelSize = fmax(fmin(sourceSize.width, targetPixelSize.width),
|
||||
fmin(sourceSize.height, targetPixelSize.height));
|
||||
|
||||
NSDictionary<NSString *, NSNumber *> *options = @{
|
||||
(id)kCGImageSourceShouldAllowFloat: @YES,
|
||||
(id)kCGImageSourceCreateThumbnailWithTransform: @YES,
|
||||
(id)kCGImageSourceCreateThumbnailFromImageAlways: @YES,
|
||||
(id)kCGImageSourceThumbnailMaxPixelSize: @(maxPixelSize),
|
||||
};
|
||||
|
||||
// Get thumbnail
|
||||
CGImageRef imageRef = CGImageSourceCreateThumbnailAtIndex(sourceRef, 0, (__bridge CFDictionaryRef)options);
|
||||
CFRelease(sourceRef);
|
||||
if (!imageRef) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Return image
|
||||
UIImage *image = [UIImage imageWithCGImage:imageRef
|
||||
scale:destScale
|
||||
orientation:UIImageOrientationUp];
|
||||
CGImageRelease(imageRef);
|
||||
return image;
|
||||
}
|
||||
|
||||
NSDictionary<NSString *, id> *__nullable RCTGetImageMetadata(NSData *data)
|
||||
{
|
||||
CGImageSourceRef sourceRef = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
|
||||
if (!sourceRef) {
|
||||
return nil;
|
||||
}
|
||||
CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(sourceRef, 0, NULL);
|
||||
CFRelease(sourceRef);
|
||||
return (__bridge_transfer id)imageProperties;
|
||||
}
|
||||
|
||||
NSData *__nullable RCTGetImageData(UIImage *image, float quality)
|
||||
{
|
||||
CGImageRef cgImage = image.CGImage;
|
||||
if (!cgImage) {
|
||||
return NULL;
|
||||
}
|
||||
NSMutableDictionary *properties = [[NSMutableDictionary alloc] initWithDictionary:@{
|
||||
(id)kCGImagePropertyOrientation : @(CGImagePropertyOrientationFromUIImageOrientation(image.imageOrientation))
|
||||
}];
|
||||
CGImageDestinationRef destination;
|
||||
CFMutableDataRef imageData = CFDataCreateMutable(NULL, 0);
|
||||
if (RCTImageHasAlpha(cgImage)) {
|
||||
// get png data
|
||||
destination = CGImageDestinationCreateWithData(imageData, kUTTypePNG, 1, NULL);
|
||||
} else {
|
||||
// get jpeg data
|
||||
destination = CGImageDestinationCreateWithData(imageData, kUTTypeJPEG, 1, NULL);
|
||||
[properties setValue:@(quality) forKey:(id)kCGImageDestinationLossyCompressionQuality];
|
||||
}
|
||||
if (!destination) {
|
||||
CFRelease(imageData);
|
||||
return NULL;
|
||||
}
|
||||
CGImageDestinationAddImage(destination, cgImage, (__bridge CFDictionaryRef)properties);
|
||||
if (!CGImageDestinationFinalize(destination)) {
|
||||
CFRelease(imageData);
|
||||
imageData = NULL;
|
||||
}
|
||||
CFRelease(destination);
|
||||
return (__bridge_transfer NSData *)imageData;
|
||||
}
|
||||
|
||||
UIImage *__nullable RCTTransformImage(UIImage *image,
|
||||
CGSize destSize,
|
||||
CGFloat destScale,
|
||||
CGAffineTransform transform)
|
||||
{
|
||||
if (destSize.width <= 0 | destSize.height <= 0 || destScale <= 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
BOOL opaque = !RCTImageHasAlpha(image.CGImage);
|
||||
UIGraphicsBeginImageContextWithOptions(destSize, opaque, destScale);
|
||||
CGContextRef currentContext = UIGraphicsGetCurrentContext();
|
||||
CGContextConcatCTM(currentContext, transform);
|
||||
[image drawAtPoint:CGPointZero];
|
||||
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL RCTImageHasAlpha(CGImageRef image)
|
||||
{
|
||||
switch (CGImageGetAlphaInfo(image)) {
|
||||
case kCGImageAlphaNone:
|
||||
case kCGImageAlphaNoneSkipLast:
|
||||
case kCGImageAlphaNoneSkipFirst:
|
||||
return NO;
|
||||
default:
|
||||
return YES;
|
||||
}
|
||||
}
|
26
node_modules/react-native/Libraries/Image/RCTImageView.h
generated
vendored
Normal file
26
node_modules/react-native/Libraries/Image/RCTImageView.h
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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 <UIKit/UIKit.h>
|
||||
#import <React/RCTView.h>
|
||||
#import <React/RCTResizeMode.h>
|
||||
|
||||
@class RCTBridge;
|
||||
@class RCTImageSource;
|
||||
|
||||
@interface RCTImageView : RCTView
|
||||
|
||||
- (instancetype)initWithBridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@property (nonatomic, assign) UIEdgeInsets capInsets;
|
||||
@property (nonatomic, strong) UIImage *defaultImage;
|
||||
@property (nonatomic, assign) UIImageRenderingMode renderingMode;
|
||||
@property (nonatomic, copy) NSArray<RCTImageSource *> *imageSources;
|
||||
@property (nonatomic, assign) CGFloat blurRadius;
|
||||
@property (nonatomic, assign) RCTResizeMode resizeMode;
|
||||
|
||||
@end
|
475
node_modules/react-native/Libraries/Image/RCTImageView.mm
generated
vendored
Normal file
475
node_modules/react-native/Libraries/Image/RCTImageView.mm
generated
vendored
Normal file
@ -0,0 +1,475 @@
|
||||
/*
|
||||
* 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 <React/RCTImageView.h>
|
||||
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTConvert.h>
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTImageBlurUtils.h>
|
||||
#import <React/RCTImageSource.h>
|
||||
#import <React/RCTImageUtils.h>
|
||||
#import <React/RCTImageLoaderWithAttributionProtocol.h>
|
||||
#import <React/RCTUIImageViewAnimated.h>
|
||||
#import <React/RCTUtils.h>
|
||||
#import <React/UIView+React.h>
|
||||
|
||||
/**
|
||||
* Determines whether an image of `currentSize` should be reloaded for display
|
||||
* at `idealSize`.
|
||||
*/
|
||||
static BOOL RCTShouldReloadImageForSizeChange(CGSize currentSize, CGSize idealSize)
|
||||
{
|
||||
static const CGFloat upscaleThreshold = 1.2;
|
||||
static const CGFloat downscaleThreshold = 0.5;
|
||||
|
||||
CGFloat widthMultiplier = idealSize.width / currentSize.width;
|
||||
CGFloat heightMultiplier = idealSize.height / currentSize.height;
|
||||
|
||||
return widthMultiplier > upscaleThreshold || widthMultiplier < downscaleThreshold ||
|
||||
heightMultiplier > upscaleThreshold || heightMultiplier < downscaleThreshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* See RCTConvert (ImageSource). We want to send down the source as a similar
|
||||
* JSON parameter.
|
||||
*/
|
||||
static NSDictionary *onLoadParamsForSource(RCTImageSource *source)
|
||||
{
|
||||
NSDictionary *dict = @{
|
||||
@"width": @(source.size.width),
|
||||
@"height": @(source.size.height),
|
||||
@"url": source.request.URL.absoluteString,
|
||||
};
|
||||
return @{ @"source": dict };
|
||||
}
|
||||
|
||||
@interface RCTImageView ()
|
||||
|
||||
@property (nonatomic, copy) RCTDirectEventBlock onLoadStart;
|
||||
@property (nonatomic, copy) RCTDirectEventBlock onProgress;
|
||||
@property (nonatomic, copy) RCTDirectEventBlock onError;
|
||||
@property (nonatomic, copy) RCTDirectEventBlock onPartialLoad;
|
||||
@property (nonatomic, copy) RCTDirectEventBlock onLoad;
|
||||
@property (nonatomic, copy) RCTDirectEventBlock onLoadEnd;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTImageView
|
||||
{
|
||||
// Weak reference back to the bridge, for image loading
|
||||
__weak RCTBridge *_bridge;
|
||||
|
||||
// The image source that's currently displayed
|
||||
RCTImageSource *_imageSource;
|
||||
|
||||
// The image source that's being loaded from the network
|
||||
RCTImageSource *_pendingImageSource;
|
||||
|
||||
// Size of the image loaded / being loaded, so we can determine when to issue a reload to accommodate a changing size.
|
||||
CGSize _targetSize;
|
||||
|
||||
// A block that can be invoked to cancel the most recent call to -reloadImage, if any
|
||||
RCTImageLoaderCancellationBlock _reloadImageCancellationBlock;
|
||||
|
||||
// Whether the latest change of props requires the image to be reloaded
|
||||
BOOL _needsReload;
|
||||
|
||||
RCTUIImageViewAnimated *_imageView;
|
||||
}
|
||||
|
||||
- (instancetype)initWithBridge:(RCTBridge *)bridge
|
||||
{
|
||||
if ((self = [super initWithFrame:CGRectZero])) {
|
||||
_bridge = bridge;
|
||||
_imageView = [[RCTUIImageViewAnimated alloc] init];
|
||||
_imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
[self addSubview:_imageView];
|
||||
|
||||
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
||||
[center addObserver:self
|
||||
selector:@selector(clearImageIfDetached)
|
||||
name:UIApplicationDidReceiveMemoryWarningNotification
|
||||
object:nil];
|
||||
[center addObserver:self
|
||||
selector:@selector(clearImageIfDetached)
|
||||
name:UIApplicationDidEnterBackgroundNotification
|
||||
object:nil];
|
||||
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
|
||||
if (@available(iOS 13.0, *)) {
|
||||
[center addObserver:self
|
||||
selector:@selector(clearImageIfDetached)
|
||||
|
||||
name:UISceneDidEnterBackgroundNotification
|
||||
object:nil];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
||||
|
||||
RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
|
||||
|
||||
RCT_NOT_IMPLEMENTED(- (instancetype)initWithFrame:(CGRect)frame)
|
||||
|
||||
- (void)updateWithImage:(UIImage *)image
|
||||
{
|
||||
if (!image) {
|
||||
_imageView.image = nil;
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply rendering mode
|
||||
if (_renderingMode != image.renderingMode) {
|
||||
image = [image imageWithRenderingMode:_renderingMode];
|
||||
}
|
||||
|
||||
if (_resizeMode == RCTResizeModeRepeat) {
|
||||
image = [image resizableImageWithCapInsets:_capInsets resizingMode:UIImageResizingModeTile];
|
||||
} else if (!UIEdgeInsetsEqualToEdgeInsets(UIEdgeInsetsZero, _capInsets)) {
|
||||
// Applying capInsets of 0 will switch the "resizingMode" of the image to "tile" which is undesired
|
||||
image = [image resizableImageWithCapInsets:_capInsets resizingMode:UIImageResizingModeStretch];
|
||||
}
|
||||
|
||||
// Apply trilinear filtering to smooth out mis-sized images
|
||||
_imageView.layer.minificationFilter = kCAFilterTrilinear;
|
||||
_imageView.layer.magnificationFilter = kCAFilterTrilinear;
|
||||
|
||||
_imageView.image = image;
|
||||
}
|
||||
|
||||
- (void)setImage:(UIImage *)image
|
||||
{
|
||||
image = image ?: _defaultImage;
|
||||
if (image != self.image) {
|
||||
[self updateWithImage:image];
|
||||
}
|
||||
}
|
||||
|
||||
- (UIImage *)image {
|
||||
return _imageView.image;
|
||||
}
|
||||
|
||||
- (void)setBlurRadius:(CGFloat)blurRadius
|
||||
{
|
||||
if (blurRadius != _blurRadius) {
|
||||
_blurRadius = blurRadius;
|
||||
_needsReload = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setCapInsets:(UIEdgeInsets)capInsets
|
||||
{
|
||||
if (!UIEdgeInsetsEqualToEdgeInsets(_capInsets, capInsets)) {
|
||||
if (UIEdgeInsetsEqualToEdgeInsets(_capInsets, UIEdgeInsetsZero) ||
|
||||
UIEdgeInsetsEqualToEdgeInsets(capInsets, UIEdgeInsetsZero)) {
|
||||
_capInsets = capInsets;
|
||||
// Need to reload image when enabling or disabling capInsets
|
||||
_needsReload = YES;
|
||||
} else {
|
||||
_capInsets = capInsets;
|
||||
[self updateWithImage:self.image];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setRenderingMode:(UIImageRenderingMode)renderingMode
|
||||
{
|
||||
if (_renderingMode != renderingMode) {
|
||||
_renderingMode = renderingMode;
|
||||
[self updateWithImage:self.image];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setImageSources:(NSArray<RCTImageSource *> *)imageSources
|
||||
{
|
||||
if (![imageSources isEqual:_imageSources]) {
|
||||
_imageSources = [imageSources copy];
|
||||
_needsReload = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setResizeMode:(RCTResizeMode)resizeMode
|
||||
{
|
||||
if (_resizeMode != resizeMode) {
|
||||
_resizeMode = resizeMode;
|
||||
|
||||
if (_resizeMode == RCTResizeModeRepeat) {
|
||||
// Repeat resize mode is handled by the UIImage. Use scale to fill
|
||||
// so the repeated image fills the UIImageView.
|
||||
_imageView.contentMode = UIViewContentModeScaleToFill;
|
||||
} else {
|
||||
_imageView.contentMode = (UIViewContentMode)resizeMode;
|
||||
}
|
||||
|
||||
if ([self shouldReloadImageSourceAfterResize]) {
|
||||
_needsReload = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cancelImageLoad
|
||||
{
|
||||
RCTImageLoaderCancellationBlock previousCancellationBlock = _reloadImageCancellationBlock;
|
||||
if (previousCancellationBlock) {
|
||||
previousCancellationBlock();
|
||||
_reloadImageCancellationBlock = nil;
|
||||
}
|
||||
|
||||
_pendingImageSource = nil;
|
||||
}
|
||||
|
||||
- (void)clearImage
|
||||
{
|
||||
[self cancelImageLoad];
|
||||
self.image = nil;
|
||||
_imageSource = nil;
|
||||
}
|
||||
|
||||
- (void)clearImageIfDetached
|
||||
{
|
||||
if (!self.window) {
|
||||
[self clearImage];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)hasMultipleSources
|
||||
{
|
||||
return _imageSources.count > 1;
|
||||
}
|
||||
|
||||
- (RCTImageSource *)imageSourceForSize:(CGSize)size
|
||||
{
|
||||
if (![self hasMultipleSources]) {
|
||||
return _imageSources.firstObject;
|
||||
}
|
||||
|
||||
// Need to wait for layout pass before deciding.
|
||||
if (CGSizeEqualToSize(size, CGSizeZero)) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
const CGFloat scale = RCTScreenScale();
|
||||
const CGFloat targetImagePixels = size.width * size.height * scale * scale;
|
||||
|
||||
RCTImageSource *bestSource = nil;
|
||||
CGFloat bestFit = CGFLOAT_MAX;
|
||||
for (RCTImageSource *source in _imageSources) {
|
||||
CGSize imgSize = source.size;
|
||||
const CGFloat imagePixels =
|
||||
imgSize.width * imgSize.height * source.scale * source.scale;
|
||||
const CGFloat fit = ABS(1 - (imagePixels / targetImagePixels));
|
||||
|
||||
if (fit < bestFit) {
|
||||
bestFit = fit;
|
||||
bestSource = source;
|
||||
}
|
||||
}
|
||||
return bestSource;
|
||||
}
|
||||
|
||||
- (BOOL)shouldReloadImageSourceAfterResize
|
||||
{
|
||||
// If capInsets are set, image doesn't need reloading when resized
|
||||
return UIEdgeInsetsEqualToEdgeInsets(_capInsets, UIEdgeInsetsZero);
|
||||
}
|
||||
|
||||
- (BOOL)shouldChangeImageSource
|
||||
{
|
||||
// We need to reload if the desired image source is different from the current image
|
||||
// source AND the image load that's pending
|
||||
RCTImageSource *desiredImageSource = [self imageSourceForSize:self.frame.size];
|
||||
return ![desiredImageSource isEqual:_imageSource] &&
|
||||
![desiredImageSource isEqual:_pendingImageSource];
|
||||
}
|
||||
|
||||
- (void)reloadImage
|
||||
{
|
||||
[self cancelImageLoad];
|
||||
_needsReload = NO;
|
||||
|
||||
RCTImageSource *source = [self imageSourceForSize:self.frame.size];
|
||||
_pendingImageSource = source;
|
||||
|
||||
if (source && self.frame.size.width > 0 && self.frame.size.height > 0) {
|
||||
if (_onLoadStart) {
|
||||
_onLoadStart(nil);
|
||||
}
|
||||
|
||||
RCTImageLoaderProgressBlock progressHandler = nil;
|
||||
if (_onProgress) {
|
||||
progressHandler = ^(int64_t loaded, int64_t total) {
|
||||
self->_onProgress(@{
|
||||
@"loaded": @((double)loaded),
|
||||
@"total": @((double)total),
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
__weak RCTImageView *weakSelf = self;
|
||||
RCTImageLoaderPartialLoadBlock partialLoadHandler = ^(UIImage *image) {
|
||||
[weakSelf imageLoaderLoadedImage:image error:nil forImageSource:source partial:YES];
|
||||
};
|
||||
|
||||
CGSize imageSize = self.bounds.size;
|
||||
CGFloat imageScale = RCTScreenScale();
|
||||
if (!UIEdgeInsetsEqualToEdgeInsets(_capInsets, UIEdgeInsetsZero)) {
|
||||
// Don't resize images that use capInsets
|
||||
imageSize = CGSizeZero;
|
||||
imageScale = source.scale;
|
||||
}
|
||||
|
||||
RCTImageLoaderCompletionBlock completionHandler = ^(NSError *error, UIImage *loadedImage) {
|
||||
[weakSelf imageLoaderLoadedImage:loadedImage error:error forImageSource:source partial:NO];
|
||||
};
|
||||
|
||||
id<RCTImageLoaderWithAttributionProtocol> imageLoader = [_bridge moduleForName:@"ImageLoader"
|
||||
lazilyLoadIfNecessary:YES];
|
||||
RCTImageURLLoaderRequest *loaderRequest = [imageLoader loadImageWithURLRequest:source.request
|
||||
size:imageSize
|
||||
scale:imageScale
|
||||
clipped:NO
|
||||
resizeMode:_resizeMode
|
||||
priority:RCTImageLoaderPriorityImmediate
|
||||
attribution:{
|
||||
.nativeViewTag = [self.reactTag intValue],
|
||||
.surfaceId = [self.rootTag intValue],
|
||||
}
|
||||
progressBlock:progressHandler
|
||||
partialLoadBlock:partialLoadHandler
|
||||
completionBlock:completionHandler];
|
||||
_reloadImageCancellationBlock = loaderRequest.cancellationBlock;
|
||||
} else {
|
||||
[self clearImage];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)imageLoaderLoadedImage:(UIImage *)loadedImage error:(NSError *)error forImageSource:(RCTImageSource *)source partial:(BOOL)isPartialLoad
|
||||
{
|
||||
if (![source isEqual:_pendingImageSource]) {
|
||||
// Bail out if source has changed since we started loading
|
||||
return;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
RCTExecuteOnMainQueue(^{
|
||||
self.image = nil;
|
||||
});
|
||||
|
||||
if (_onError) {
|
||||
_onError(@{ @"error": error.localizedDescription });
|
||||
}
|
||||
if (_onLoadEnd) {
|
||||
_onLoadEnd(nil);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void (^setImageBlock)(UIImage *) = ^(UIImage *image) {
|
||||
if (!isPartialLoad) {
|
||||
self->_imageSource = source;
|
||||
self->_pendingImageSource = nil;
|
||||
}
|
||||
|
||||
self.image = image;
|
||||
|
||||
if (isPartialLoad) {
|
||||
if (self->_onPartialLoad) {
|
||||
self->_onPartialLoad(nil);
|
||||
}
|
||||
} else {
|
||||
if (self->_onLoad) {
|
||||
RCTImageSource *sourceLoaded = [source imageSourceWithSize:image.size scale:source.scale];
|
||||
self->_onLoad(onLoadParamsForSource(sourceLoaded));
|
||||
}
|
||||
if (self->_onLoadEnd) {
|
||||
self->_onLoadEnd(nil);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (_blurRadius > __FLT_EPSILON__) {
|
||||
// Blur on a background thread to avoid blocking interaction
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
UIImage *blurredImage = RCTBlurredImageWithRadius(loadedImage, self->_blurRadius);
|
||||
RCTExecuteOnMainQueue(^{
|
||||
setImageBlock(blurredImage);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// No blur, so try to set the image on the main thread synchronously to minimize image
|
||||
// flashing. (For instance, if this view gets attached to a window, then -didMoveToWindow
|
||||
// calls -reloadImage, and we want to set the image synchronously if possible so that the
|
||||
// image property is set in the same CATransaction that attaches this view to the window.)
|
||||
RCTExecuteOnMainQueue(^{
|
||||
setImageBlock(loadedImage);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (void)reactSetFrame:(CGRect)frame
|
||||
{
|
||||
[super reactSetFrame:frame];
|
||||
|
||||
// If we didn't load an image yet, or the new frame triggers a different image source
|
||||
// to be loaded, reload to swap to the proper image source.
|
||||
if ([self shouldChangeImageSource]) {
|
||||
_targetSize = frame.size;
|
||||
[self reloadImage];
|
||||
} else if ([self shouldReloadImageSourceAfterResize]) {
|
||||
CGSize imageSize = self.image.size;
|
||||
CGFloat imageScale = self.image.scale;
|
||||
CGSize idealSize = RCTTargetSize(imageSize, imageScale, frame.size, RCTScreenScale(),
|
||||
(RCTResizeMode)self.contentMode, YES);
|
||||
|
||||
// Don't reload if the current image or target image size is close enough
|
||||
if (!RCTShouldReloadImageForSizeChange(imageSize, idealSize) ||
|
||||
!RCTShouldReloadImageForSizeChange(_targetSize, idealSize)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't reload if the current image size is the maximum size of either the pending image source or image source
|
||||
CGSize imageSourceSize = (_imageSource ? _imageSource : _pendingImageSource).size;
|
||||
if (imageSize.width * imageScale == imageSourceSize.width * _imageSource.scale &&
|
||||
imageSize.height * imageScale == imageSourceSize.height * _imageSource.scale) {
|
||||
return;
|
||||
}
|
||||
|
||||
RCTLogInfo(@"Reloading image %@ as size %@", _imageSource.request.URL.absoluteString, NSStringFromCGSize(idealSize));
|
||||
|
||||
// If the existing image or an image being loaded are not the right
|
||||
// size, reload the asset in case there is a better size available.
|
||||
_targetSize = idealSize;
|
||||
[self reloadImage];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)didSetProps:(NSArray<NSString *> *)changedProps
|
||||
{
|
||||
if (_needsReload) {
|
||||
[self reloadImage];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)didMoveToWindow
|
||||
{
|
||||
[super didMoveToWindow];
|
||||
|
||||
if (!self.window) {
|
||||
// Cancel loading the image if we've moved offscreen. In addition to helping
|
||||
// prioritise image requests that are actually on-screen, this removes
|
||||
// requests that have gotten "stuck" from the queue, unblocking other images
|
||||
// from loading.
|
||||
[self cancelImageLoad];
|
||||
} else if ([self shouldChangeImageSource]) {
|
||||
[self reloadImage];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
12
node_modules/react-native/Libraries/Image/RCTImageViewManager.h
generated
vendored
Normal file
12
node_modules/react-native/Libraries/Image/RCTImageViewManager.h
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
/*
|
||||
* 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 <React/RCTViewManager.h>
|
||||
|
||||
@interface RCTImageViewManager : RCTViewManager
|
||||
|
||||
@end
|
111
node_modules/react-native/Libraries/Image/RCTImageViewManager.mm
generated
vendored
Normal file
111
node_modules/react-native/Libraries/Image/RCTImageViewManager.mm
generated
vendored
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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 <React/RCTImageViewManager.h>
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import <React/RCTConvert.h>
|
||||
#import <React/RCTImageSource.h>
|
||||
|
||||
#import <React/RCTImageShadowView.h>
|
||||
#import <React/RCTImageView.h>
|
||||
#import <React/RCTImageLoaderProtocol.h>
|
||||
|
||||
@implementation RCTImageViewManager
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (RCTShadowView *)shadowView
|
||||
{
|
||||
return [RCTImageShadowView new];
|
||||
}
|
||||
|
||||
- (UIView *)view
|
||||
{
|
||||
return [[RCTImageView alloc] initWithBridge:self.bridge];
|
||||
}
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(blurRadius, CGFloat)
|
||||
RCT_EXPORT_VIEW_PROPERTY(capInsets, UIEdgeInsets)
|
||||
RCT_REMAP_VIEW_PROPERTY(defaultSource, defaultImage, UIImage)
|
||||
RCT_EXPORT_VIEW_PROPERTY(onLoadStart, RCTDirectEventBlock)
|
||||
RCT_EXPORT_VIEW_PROPERTY(onProgress, RCTDirectEventBlock)
|
||||
RCT_EXPORT_VIEW_PROPERTY(onError, RCTDirectEventBlock)
|
||||
RCT_EXPORT_VIEW_PROPERTY(onPartialLoad, RCTDirectEventBlock)
|
||||
RCT_EXPORT_VIEW_PROPERTY(onLoad, RCTDirectEventBlock)
|
||||
RCT_EXPORT_VIEW_PROPERTY(onLoadEnd, RCTDirectEventBlock)
|
||||
RCT_EXPORT_VIEW_PROPERTY(resizeMode, RCTResizeMode)
|
||||
RCT_REMAP_VIEW_PROPERTY(source, imageSources, NSArray<RCTImageSource *>);
|
||||
RCT_CUSTOM_VIEW_PROPERTY(tintColor, UIColor, RCTImageView)
|
||||
{
|
||||
// Default tintColor isn't nil - it's inherited from the superView - but we
|
||||
// want to treat a null json value for `tintColor` as meaning 'disable tint',
|
||||
// so we toggle `renderingMode` here instead of in `-[RCTImageView setTintColor:]`
|
||||
view.tintColor = [RCTConvert UIColor:json] ?: defaultView.tintColor;
|
||||
view.renderingMode = json ? UIImageRenderingModeAlwaysTemplate : defaultView.renderingMode;
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(getSize:(NSURLRequest *)request
|
||||
successBlock:(RCTResponseSenderBlock)successBlock
|
||||
errorBlock:(RCTResponseErrorBlock)errorBlock)
|
||||
{
|
||||
[[self.bridge moduleForName:@"ImageLoader" lazilyLoadIfNecessary:YES]
|
||||
getImageSizeForURLRequest:request
|
||||
block:^(NSError *error, CGSize size) {
|
||||
if (error) {
|
||||
errorBlock(error);
|
||||
} else {
|
||||
successBlock(@[@(size.width), @(size.height)]);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(getSizeWithHeaders:(RCTImageSource *)source
|
||||
resolve:(RCTPromiseResolveBlock)resolve
|
||||
reject:(RCTPromiseRejectBlock)reject)
|
||||
{
|
||||
[[self.bridge moduleForName:@"ImageLoader" lazilyLoadIfNecessary:YES]
|
||||
getImageSizeForURLRequest:source.request
|
||||
block:^(NSError *error, CGSize size) {
|
||||
if (error) {
|
||||
reject(@"E_GET_SIZE_FAILURE", nil, error);
|
||||
return;
|
||||
}
|
||||
resolve(@{@"width":@(size.width),@"height":@(size.height)});
|
||||
}];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(prefetchImage:(NSURLRequest *)request
|
||||
resolve:(RCTPromiseResolveBlock)resolve
|
||||
reject:(RCTPromiseRejectBlock)reject)
|
||||
{
|
||||
if (!request) {
|
||||
reject(@"E_INVALID_URI", @"Cannot prefetch an image for an empty URI", nil);
|
||||
return;
|
||||
}
|
||||
id<RCTImageLoaderProtocol> imageLoader = (id<RCTImageLoaderProtocol>)[self.bridge
|
||||
moduleForName:@"ImageLoader" lazilyLoadIfNecessary:YES];
|
||||
[imageLoader loadImageWithURLRequest:request
|
||||
priority:RCTImageLoaderPriorityPrefetch
|
||||
callback:^(NSError *error, UIImage *image) {
|
||||
if (error) {
|
||||
reject(@"E_PREFETCH_FAILURE", nil, error);
|
||||
return;
|
||||
}
|
||||
resolve(@YES);
|
||||
}];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(queryCache:(NSArray *)requests
|
||||
resolve:(RCTPromiseResolveBlock)resolve
|
||||
reject:(RCTPromiseRejectBlock)reject)
|
||||
{
|
||||
resolve([[self.bridge moduleForName:@"ImageLoader"] getImageCacheStatus:requests]);
|
||||
}
|
||||
|
||||
@end
|
12
node_modules/react-native/Libraries/Image/RCTLocalAssetImageLoader.h
generated
vendored
Normal file
12
node_modules/react-native/Libraries/Image/RCTLocalAssetImageLoader.h
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
/*
|
||||
* 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 <React/RCTImageURLLoader.h>
|
||||
|
||||
@interface RCTLocalAssetImageLoader : NSObject <RCTImageURLLoader>
|
||||
|
||||
@end
|
71
node_modules/react-native/Libraries/Image/RCTLocalAssetImageLoader.mm
generated
vendored
Normal file
71
node_modules/react-native/Libraries/Image/RCTLocalAssetImageLoader.mm
generated
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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 <React/RCTLocalAssetImageLoader.h>
|
||||
|
||||
#import <atomic>
|
||||
#import <memory>
|
||||
|
||||
#import <React/RCTUtils.h>
|
||||
#import <ReactCommon/RCTTurboModule.h>
|
||||
|
||||
#import "RCTImagePlugins.h"
|
||||
|
||||
@interface RCTLocalAssetImageLoader() <RCTTurboModule>
|
||||
@end
|
||||
|
||||
@implementation RCTLocalAssetImageLoader
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (BOOL)canLoadImageURL:(NSURL *)requestURL
|
||||
{
|
||||
return RCTIsLocalAssetURL(requestURL);
|
||||
}
|
||||
|
||||
- (BOOL)requiresScheduling
|
||||
{
|
||||
// Don't schedule this loader on the URL queue so we can load the
|
||||
// local assets synchronously to avoid flickers.
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)shouldCacheLoadedImages
|
||||
{
|
||||
// UIImage imageNamed handles the caching automatically so we don't want
|
||||
// to add it to the image cache.
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (nullable RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL
|
||||
size:(CGSize)size
|
||||
scale:(CGFloat)scale
|
||||
resizeMode:(RCTResizeMode)resizeMode
|
||||
progressHandler:(RCTImageLoaderProgressBlock)progressHandler
|
||||
partialLoadHandler:(RCTImageLoaderPartialLoadBlock)partialLoadHandler
|
||||
completionHandler:(RCTImageLoaderCompletionBlock)completionHandler
|
||||
{
|
||||
UIImage *image = RCTImageFromLocalAssetURL(imageURL);
|
||||
if (image) {
|
||||
if (progressHandler) {
|
||||
progressHandler(1, 1);
|
||||
}
|
||||
completionHandler(nil, image);
|
||||
} else {
|
||||
NSString *message = [NSString stringWithFormat:@"Could not find image %@", imageURL];
|
||||
RCTLogWarn(@"%@", message);
|
||||
completionHandler(RCTErrorWithMessage(message), nil);
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Class RCTLocalAssetImageLoaderCls(void) {
|
||||
return RCTLocalAssetImageLoader.class;
|
||||
}
|
22
node_modules/react-native/Libraries/Image/RCTResizeMode.h
generated
vendored
Normal file
22
node_modules/react-native/Libraries/Image/RCTResizeMode.h
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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 <React/RCTConvert.h>
|
||||
|
||||
typedef NS_ENUM(NSInteger, RCTResizeMode) {
|
||||
RCTResizeModeCover = UIViewContentModeScaleAspectFill,
|
||||
RCTResizeModeContain = UIViewContentModeScaleAspectFit,
|
||||
RCTResizeModeStretch = UIViewContentModeScaleToFill,
|
||||
RCTResizeModeCenter = UIViewContentModeCenter,
|
||||
RCTResizeModeRepeat = -1, // Use negative values to avoid conflicts with iOS enum values.
|
||||
};
|
||||
|
||||
@interface RCTConvert(RCTResizeMode)
|
||||
|
||||
+ (RCTResizeMode)RCTResizeMode:(id)json;
|
||||
|
||||
@end
|
20
node_modules/react-native/Libraries/Image/RCTResizeMode.m
generated
vendored
Normal file
20
node_modules/react-native/Libraries/Image/RCTResizeMode.m
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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 <React/RCTResizeMode.h>
|
||||
|
||||
@implementation RCTConvert(RCTResizeMode)
|
||||
|
||||
RCT_ENUM_CONVERTER(RCTResizeMode, (@{
|
||||
@"cover": @(RCTResizeModeCover),
|
||||
@"contain": @(RCTResizeModeContain),
|
||||
@"stretch": @(RCTResizeModeStretch),
|
||||
@"center": @(RCTResizeModeCenter),
|
||||
@"repeat": @(RCTResizeModeRepeat),
|
||||
}), RCTResizeModeStretch, integerValue)
|
||||
|
||||
@end
|
13
node_modules/react-native/Libraries/Image/RCTUIImageViewAnimated.h
generated
vendored
Normal file
13
node_modules/react-native/Libraries/Image/RCTUIImageViewAnimated.h
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* 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 <React/RCTAnimatedImage.h>
|
||||
#import <React/RCTDefines.h>
|
||||
|
||||
@interface RCTUIImageViewAnimated : UIImageView
|
||||
|
||||
@end
|
335
node_modules/react-native/Libraries/Image/RCTUIImageViewAnimated.m
generated
vendored
Normal file
335
node_modules/react-native/Libraries/Image/RCTUIImageViewAnimated.m
generated
vendored
Normal file
@ -0,0 +1,335 @@
|
||||
/*
|
||||
* 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 <React/RCTUIImageViewAnimated.h>
|
||||
#import <React/RCTDisplayWeakRefreshable.h>
|
||||
|
||||
#import <mach/mach.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
static NSUInteger RCTDeviceTotalMemory() {
|
||||
return (NSUInteger)[[NSProcessInfo processInfo] physicalMemory];
|
||||
}
|
||||
|
||||
static NSUInteger RCTDeviceFreeMemory() {
|
||||
mach_port_t host_port = mach_host_self();
|
||||
mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
|
||||
vm_size_t page_size;
|
||||
vm_statistics_data_t vm_stat;
|
||||
kern_return_t kern;
|
||||
|
||||
kern = host_page_size(host_port, &page_size);
|
||||
if (kern != KERN_SUCCESS) return 0;
|
||||
kern = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
|
||||
if (kern != KERN_SUCCESS) return 0;
|
||||
return (vm_stat.free_count - vm_stat.speculative_count) * page_size;
|
||||
}
|
||||
|
||||
@interface RCTUIImageViewAnimated () <CALayerDelegate, RCTDisplayRefreshable>
|
||||
|
||||
@property (nonatomic, assign) NSUInteger maxBufferSize;
|
||||
@property (nonatomic, strong, readwrite) UIImage *currentFrame;
|
||||
@property (nonatomic, assign, readwrite) NSUInteger currentFrameIndex;
|
||||
@property (nonatomic, assign, readwrite) NSUInteger currentLoopCount;
|
||||
@property (nonatomic, assign) NSUInteger totalFrameCount;
|
||||
@property (nonatomic, assign) NSUInteger totalLoopCount;
|
||||
@property (nonatomic, strong) UIImage<RCTAnimatedImage> *animatedImage;
|
||||
@property (nonatomic, strong) NSMutableDictionary<NSNumber *, UIImage *> *frameBuffer;
|
||||
@property (nonatomic, assign) NSTimeInterval currentTime;
|
||||
@property (nonatomic, assign) BOOL bufferMiss;
|
||||
@property (nonatomic, assign) NSUInteger maxBufferCount;
|
||||
@property (nonatomic, strong) NSOperationQueue *fetchQueue;
|
||||
@property (nonatomic, strong) dispatch_semaphore_t lock;
|
||||
@property (nonatomic, assign) CGFloat animatedImageScale;
|
||||
@property (nonatomic, strong) CADisplayLink *displayLink;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTUIImageViewAnimated
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
self.lock = dispatch_semaphore_create(1);
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)resetAnimatedImage
|
||||
{
|
||||
self.animatedImage = nil;
|
||||
self.totalFrameCount = 0;
|
||||
self.totalLoopCount = 0;
|
||||
self.currentFrame = nil;
|
||||
self.currentFrameIndex = 0;
|
||||
self.currentLoopCount = 0;
|
||||
self.currentTime = 0;
|
||||
self.bufferMiss = NO;
|
||||
self.maxBufferCount = 0;
|
||||
self.animatedImageScale = 1;
|
||||
[_fetchQueue cancelAllOperations];
|
||||
_fetchQueue = nil;
|
||||
dispatch_semaphore_wait(self.lock, DISPATCH_TIME_FOREVER);
|
||||
[_frameBuffer removeAllObjects];
|
||||
_frameBuffer = nil;
|
||||
dispatch_semaphore_signal(self.lock);
|
||||
}
|
||||
|
||||
- (void)setImage:(UIImage *)image
|
||||
{
|
||||
if (self.image == image) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self stop];
|
||||
[self resetAnimatedImage];
|
||||
|
||||
if ([image respondsToSelector:@selector(animatedImageFrameAtIndex:)]) {
|
||||
NSUInteger animatedImageFrameCount = ((UIImage<RCTAnimatedImage> *)image).animatedImageFrameCount;
|
||||
|
||||
// In case frame count is 0, there is no reason to continue.
|
||||
if (animatedImageFrameCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.animatedImage = (UIImage<RCTAnimatedImage> *)image;
|
||||
self.totalFrameCount = animatedImageFrameCount;
|
||||
|
||||
// Get the current frame and loop count.
|
||||
self.totalLoopCount = self.animatedImage.animatedImageLoopCount;
|
||||
|
||||
self.animatedImageScale = image.scale;
|
||||
|
||||
self.currentFrame = image;
|
||||
|
||||
dispatch_semaphore_wait(self.lock, DISPATCH_TIME_FOREVER);
|
||||
self.frameBuffer[@(self.currentFrameIndex)] = self.currentFrame;
|
||||
dispatch_semaphore_signal(self.lock);
|
||||
|
||||
// Calculate max buffer size
|
||||
[self calculateMaxBufferCount];
|
||||
|
||||
if ([self paused]) {
|
||||
[self start];
|
||||
}
|
||||
|
||||
[self.layer setNeedsDisplay];
|
||||
} else {
|
||||
super.image = image;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (NSOperationQueue *)fetchQueue
|
||||
{
|
||||
if (!_fetchQueue) {
|
||||
_fetchQueue = [[NSOperationQueue alloc] init];
|
||||
_fetchQueue.maxConcurrentOperationCount = 1;
|
||||
}
|
||||
return _fetchQueue;
|
||||
}
|
||||
|
||||
- (NSMutableDictionary<NSNumber *,UIImage *> *)frameBuffer
|
||||
{
|
||||
if (!_frameBuffer) {
|
||||
_frameBuffer = [NSMutableDictionary dictionary];
|
||||
}
|
||||
return _frameBuffer;
|
||||
}
|
||||
|
||||
- (CADisplayLink *)displayLink
|
||||
{
|
||||
// We only need a displayLink in the case of animated images, so short-circuit this code and don't create one for most of the use cases.
|
||||
// Since this class is used for all RCTImageView's, this is especially important.
|
||||
if (!_animatedImage) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (!_displayLink) {
|
||||
_displayLink = [RCTDisplayWeakRefreshable displayLinkWithWeakRefreshable:self];
|
||||
NSString *runLoopMode = [NSProcessInfo processInfo].activeProcessorCount > 1 ? NSRunLoopCommonModes : NSDefaultRunLoopMode;
|
||||
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:runLoopMode];
|
||||
}
|
||||
return _displayLink;
|
||||
}
|
||||
|
||||
#pragma mark - Animation
|
||||
|
||||
- (void)start
|
||||
{
|
||||
self.displayLink.paused = NO;
|
||||
}
|
||||
|
||||
- (void)stop
|
||||
{
|
||||
self.displayLink.paused = YES;
|
||||
}
|
||||
|
||||
- (BOOL)paused
|
||||
{
|
||||
return self.displayLink.isPaused;
|
||||
}
|
||||
|
||||
- (void)displayDidRefresh:(CADisplayLink *)displayLink
|
||||
{
|
||||
#if TARGET_OS_UIKITFORMAC
|
||||
// TODO: `displayLink.frameInterval` is not available on UIKitForMac
|
||||
NSTimeInterval duration = displayLink.duration;
|
||||
#else
|
||||
NSTimeInterval duration = displayLink.duration * displayLink.frameInterval;
|
||||
#endif
|
||||
NSUInteger totalFrameCount = self.totalFrameCount;
|
||||
NSUInteger currentFrameIndex = self.currentFrameIndex;
|
||||
NSUInteger nextFrameIndex = (currentFrameIndex + 1) % totalFrameCount;
|
||||
|
||||
// Check if we have the frame buffer firstly to improve performance
|
||||
if (!self.bufferMiss) {
|
||||
// Then check if timestamp is reached
|
||||
self.currentTime += duration;
|
||||
NSTimeInterval currentDuration = [self.animatedImage animatedImageDurationAtIndex:currentFrameIndex];
|
||||
if (self.currentTime < currentDuration) {
|
||||
// Current frame timestamp not reached, return
|
||||
return;
|
||||
}
|
||||
self.currentTime -= currentDuration;
|
||||
NSTimeInterval nextDuration = [self.animatedImage animatedImageDurationAtIndex:nextFrameIndex];
|
||||
if (self.currentTime > nextDuration) {
|
||||
// Do not skip frame
|
||||
self.currentTime = nextDuration;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the current frame
|
||||
UIImage *currentFrame;
|
||||
UIImage *fetchFrame;
|
||||
dispatch_semaphore_wait(self.lock, DISPATCH_TIME_FOREVER);
|
||||
currentFrame = self.frameBuffer[@(currentFrameIndex)];
|
||||
fetchFrame = currentFrame ? self.frameBuffer[@(nextFrameIndex)] : nil;
|
||||
dispatch_semaphore_signal(self.lock);
|
||||
BOOL bufferFull = NO;
|
||||
if (currentFrame) {
|
||||
dispatch_semaphore_wait(self.lock, DISPATCH_TIME_FOREVER);
|
||||
// Remove the frame buffer if need
|
||||
if (self.frameBuffer.count > self.maxBufferCount) {
|
||||
self.frameBuffer[@(currentFrameIndex)] = nil;
|
||||
}
|
||||
// Check whether we can stop fetch
|
||||
if (self.frameBuffer.count == totalFrameCount) {
|
||||
bufferFull = YES;
|
||||
}
|
||||
dispatch_semaphore_signal(self.lock);
|
||||
self.currentFrame = currentFrame;
|
||||
self.currentFrameIndex = nextFrameIndex;
|
||||
self.bufferMiss = NO;
|
||||
[self.layer setNeedsDisplay];
|
||||
} else {
|
||||
self.bufferMiss = YES;
|
||||
}
|
||||
|
||||
// Update the loop count when last frame rendered
|
||||
if (nextFrameIndex == 0 && !self.bufferMiss) {
|
||||
// Update the loop count
|
||||
self.currentLoopCount++;
|
||||
// if reached the max loop count, stop animating, 0 means loop indefinitely
|
||||
NSUInteger maxLoopCount = self.totalLoopCount;
|
||||
if (maxLoopCount != 0 && (self.currentLoopCount >= maxLoopCount)) {
|
||||
[self stop];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we should prefetch next frame or current frame
|
||||
NSUInteger fetchFrameIndex;
|
||||
if (self.bufferMiss) {
|
||||
// When buffer miss, means the decode speed is slower than render speed, we fetch current miss frame
|
||||
fetchFrameIndex = currentFrameIndex;
|
||||
} else {
|
||||
// Or, most cases, the decode speed is faster than render speed, we fetch next frame
|
||||
fetchFrameIndex = nextFrameIndex;
|
||||
}
|
||||
|
||||
if (!fetchFrame && !bufferFull && self.fetchQueue.operationCount == 0) {
|
||||
// Prefetch next frame in background queue
|
||||
UIImage<RCTAnimatedImage> *animatedImage = self.animatedImage;
|
||||
NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
|
||||
UIImage *frame = [animatedImage animatedImageFrameAtIndex:fetchFrameIndex];
|
||||
dispatch_semaphore_wait(self.lock, DISPATCH_TIME_FOREVER);
|
||||
self.frameBuffer[@(fetchFrameIndex)] = frame;
|
||||
dispatch_semaphore_signal(self.lock);
|
||||
}];
|
||||
[self.fetchQueue addOperation:operation];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - CALayerDelegate
|
||||
|
||||
- (void)displayLayer:(CALayer *)layer
|
||||
{
|
||||
if (_currentFrame) {
|
||||
layer.contentsScale = self.animatedImageScale;
|
||||
layer.contents = (__bridge id)_currentFrame.CGImage;
|
||||
} else {
|
||||
[super displayLayer:layer];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Util
|
||||
|
||||
- (void)calculateMaxBufferCount
|
||||
{
|
||||
NSUInteger bytes = CGImageGetBytesPerRow(self.currentFrame.CGImage) * CGImageGetHeight(self.currentFrame.CGImage);
|
||||
if (bytes == 0) bytes = 1024;
|
||||
|
||||
NSUInteger max = 0;
|
||||
if (self.maxBufferSize > 0) {
|
||||
max = self.maxBufferSize;
|
||||
} else {
|
||||
// Calculate based on current memory, these factors are by experience
|
||||
NSUInteger total = RCTDeviceTotalMemory();
|
||||
NSUInteger free = RCTDeviceFreeMemory();
|
||||
max = MIN(total * 0.2, free * 0.6);
|
||||
}
|
||||
|
||||
NSUInteger maxBufferCount = (double)max / (double)bytes;
|
||||
if (!maxBufferCount) {
|
||||
// At least 1 frame
|
||||
maxBufferCount = 1;
|
||||
}
|
||||
|
||||
self.maxBufferCount = maxBufferCount;
|
||||
}
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
// Removes the display link from all run loop modes.
|
||||
[_displayLink invalidate];
|
||||
_displayLink = nil;
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning:(NSNotification *)notification
|
||||
{
|
||||
[_fetchQueue cancelAllOperations];
|
||||
[_fetchQueue addOperationWithBlock:^{
|
||||
NSNumber *currentFrameIndex = @(self.currentFrameIndex);
|
||||
dispatch_semaphore_wait(self.lock, DISPATCH_TIME_FOREVER);
|
||||
NSArray *keys = self.frameBuffer.allKeys;
|
||||
// only keep the next frame for later rendering
|
||||
for (NSNumber * key in keys) {
|
||||
if (![key isEqualToNumber:currentFrameIndex]) {
|
||||
[self.frameBuffer removeObjectForKey:key];
|
||||
}
|
||||
}
|
||||
dispatch_semaphore_signal(self.lock);
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
49
node_modules/react-native/Libraries/Image/React-RCTImage.podspec
generated
vendored
Normal file
49
node_modules/react-native/Libraries/Image/React-RCTImage.podspec
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
# 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.
|
||||
|
||||
require "json"
|
||||
|
||||
package = JSON.parse(File.read(File.join(__dir__, "..", "..", "package.json")))
|
||||
version = package['version']
|
||||
|
||||
source = { :git => 'https://github.com/facebook/react-native.git' }
|
||||
if version == '1000.0.0'
|
||||
# This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in.
|
||||
source[:commit] = `git rev-parse HEAD`.strip
|
||||
else
|
||||
source[:tag] = "v#{version}"
|
||||
end
|
||||
|
||||
folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
|
||||
folly_version = '2020.01.13.00'
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "React-RCTImage"
|
||||
s.version = version
|
||||
s.summary = "A React component for displaying different types of images."
|
||||
s.homepage = "https://reactnative.dev/"
|
||||
s.documentation_url = "https://reactnative.dev/docs/image"
|
||||
s.license = package["license"]
|
||||
s.author = "Facebook, Inc. and its affiliates"
|
||||
s.platforms = { :ios => "10.0", :tvos => "10.0" }
|
||||
s.compiler_flags = folly_compiler_flags + ' -Wno-nullability-completeness'
|
||||
s.source = source
|
||||
s.source_files = "*.{m,mm}"
|
||||
s.preserve_paths = "package.json", "LICENSE", "LICENSE-docs"
|
||||
s.header_dir = "RCTImage"
|
||||
s.pod_target_xcconfig = {
|
||||
"USE_HEADERMAP" => "YES",
|
||||
"CLANG_CXX_LANGUAGE_STANDARD" => "c++14",
|
||||
"HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/Folly\""
|
||||
}
|
||||
|
||||
s.dependency "Folly", folly_version
|
||||
s.dependency "FBReactNativeSpec", version
|
||||
s.dependency "RCTTypeSafety", version
|
||||
s.dependency "ReactCommon/turbomodule/core", version
|
||||
s.dependency "React-jsi", version
|
||||
s.dependency "React-Core/RCTImageHeaders", version
|
||||
s.dependency "React-RCTNetwork", version
|
||||
end
|
28
node_modules/react-native/Libraries/Image/RelativeImageStub.js
generated
vendored
Normal file
28
node_modules/react-native/Libraries/Image/RelativeImageStub.js
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @format
|
||||
* @flow strict
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
// This is a stub for flow to make it understand require('./icon.png')
|
||||
// See metro/src/Bundler/index.js
|
||||
|
||||
const AssetRegistry = require('./AssetRegistry');
|
||||
|
||||
module.exports = (AssetRegistry.registerAsset({
|
||||
__packager_asset: true,
|
||||
fileSystemLocation: '/full/path/to/directory',
|
||||
httpServerLocation: '/assets/full/path/to/directory',
|
||||
width: 100,
|
||||
height: 100,
|
||||
scales: [1, 2, 3],
|
||||
hash: 'nonsense',
|
||||
name: 'icon',
|
||||
type: 'png',
|
||||
}): number);
|
20
node_modules/react-native/Libraries/Image/TextInlineImageNativeComponent.js
generated
vendored
Normal file
20
node_modules/react-native/Libraries/Image/TextInlineImageNativeComponent.js
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @format
|
||||
* @flow strict-local
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const requireNativeComponent = require('../ReactNative/requireNativeComponent');
|
||||
import type {HostComponent} from '../Renderer/shims/ReactNativeTypes';
|
||||
|
||||
const TextInlineImage: HostComponent<mixed> = requireNativeComponent<mixed>(
|
||||
'RCTTextInlineImage',
|
||||
);
|
||||
|
||||
module.exports = TextInlineImage;
|
91
node_modules/react-native/Libraries/Image/assetPathUtils.js
generated
vendored
Normal file
91
node_modules/react-native/Libraries/Image/assetPathUtils.js
generated
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @format
|
||||
* @flow strict
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {PackagerAsset} from './AssetRegistry';
|
||||
|
||||
const androidScaleSuffix = {
|
||||
'0.75': 'ldpi',
|
||||
'1': 'mdpi',
|
||||
'1.5': 'hdpi',
|
||||
'2': 'xhdpi',
|
||||
'3': 'xxhdpi',
|
||||
'4': 'xxxhdpi',
|
||||
};
|
||||
|
||||
/**
|
||||
* FIXME: using number to represent discrete scale numbers is fragile in essence because of
|
||||
* floating point numbers imprecision.
|
||||
*/
|
||||
function getAndroidAssetSuffix(scale: number): string {
|
||||
if (scale.toString() in androidScaleSuffix) {
|
||||
return androidScaleSuffix[scale.toString()];
|
||||
}
|
||||
|
||||
throw new Error('no such scale ' + scale.toString());
|
||||
}
|
||||
|
||||
// See https://developer.android.com/guide/topics/resources/drawable-resource.html
|
||||
const drawableFileTypes = new Set([
|
||||
'gif',
|
||||
'jpeg',
|
||||
'jpg',
|
||||
'png',
|
||||
'svg',
|
||||
'webp',
|
||||
'xml',
|
||||
]);
|
||||
|
||||
function getAndroidResourceFolderName(
|
||||
asset: PackagerAsset,
|
||||
scale: number,
|
||||
): string | $TEMPORARY$string<'raw'> {
|
||||
if (!drawableFileTypes.has(asset.type)) {
|
||||
return 'raw';
|
||||
}
|
||||
var suffix = getAndroidAssetSuffix(scale);
|
||||
if (!suffix) {
|
||||
throw new Error(
|
||||
"Don't know which android drawable suffix to use for scale: " +
|
||||
scale +
|
||||
'\nAsset: ' +
|
||||
JSON.stringify(asset, null, '\t') +
|
||||
'\nPossible scales are:' +
|
||||
JSON.stringify(androidScaleSuffix, null, '\t'),
|
||||
);
|
||||
}
|
||||
const androidFolder = 'drawable-' + suffix;
|
||||
return androidFolder;
|
||||
}
|
||||
|
||||
function getAndroidResourceIdentifier(asset: PackagerAsset): string {
|
||||
var folderPath = getBasePath(asset);
|
||||
return (folderPath + '/' + asset.name)
|
||||
.toLowerCase()
|
||||
.replace(/\//g, '_') // Encode folder structure in file name
|
||||
.replace(/([^a-z0-9_])/g, '') // Remove illegal chars
|
||||
.replace(/^assets_/, ''); // Remove "assets_" prefix
|
||||
}
|
||||
|
||||
function getBasePath(asset: PackagerAsset): string {
|
||||
var basePath = asset.httpServerLocation;
|
||||
if (basePath[0] === '/') {
|
||||
basePath = basePath.substr(1);
|
||||
}
|
||||
return basePath;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getAndroidAssetSuffix: getAndroidAssetSuffix,
|
||||
getAndroidResourceFolderName: getAndroidResourceFolderName,
|
||||
getAndroidResourceIdentifier: getAndroidResourceIdentifier,
|
||||
getBasePath: getBasePath,
|
||||
};
|
66
node_modules/react-native/Libraries/Image/nativeImageSource.js
generated
vendored
Normal file
66
node_modules/react-native/Libraries/Image/nativeImageSource.js
generated
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import Platform from '../Utilities/Platform';
|
||||
|
||||
import type {ImageURISource} from './ImageSource';
|
||||
|
||||
type NativeImageSourceSpec = $ReadOnly<{|
|
||||
android?: string,
|
||||
ios?: string,
|
||||
default?: string,
|
||||
|
||||
// For more details on width and height, see
|
||||
// https://reactnative.dev/docs/images.html#why-not-automatically-size-everything
|
||||
height: number,
|
||||
width: number,
|
||||
|}>;
|
||||
|
||||
/**
|
||||
* In hybrid apps, use `nativeImageSource` to access images that are already
|
||||
* available on the native side, for example in Xcode Asset Catalogs or
|
||||
* Android's drawable folder.
|
||||
*
|
||||
* However, keep in mind that React Native Packager does not guarantee that the
|
||||
* image exists. If the image is missing you'll get an empty box. When adding
|
||||
* new images your app needs to be recompiled.
|
||||
*
|
||||
* Prefer Static Image Resources system which provides more guarantees,
|
||||
* automates measurements and allows adding new images without rebuilding the
|
||||
* native app. For more details visit:
|
||||
*
|
||||
* https://reactnative.dev/docs/images.html
|
||||
*
|
||||
*/
|
||||
function nativeImageSource(spec: NativeImageSourceSpec): ImageURISource {
|
||||
let uri = Platform.select({
|
||||
android: spec.android,
|
||||
default: spec.default,
|
||||
ios: spec.ios,
|
||||
});
|
||||
if (uri == null) {
|
||||
console.warn(
|
||||
'nativeImageSource(...): No image name supplied for `%s`:\n%s',
|
||||
Platform.OS,
|
||||
JSON.stringify(spec, null, 2),
|
||||
);
|
||||
uri = '';
|
||||
}
|
||||
return {
|
||||
deprecated: true,
|
||||
height: spec.height,
|
||||
uri,
|
||||
width: spec.width,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = nativeImageSource;
|
109
node_modules/react-native/Libraries/Image/resolveAssetSource.js
generated
vendored
Normal file
109
node_modules/react-native/Libraries/Image/resolveAssetSource.js
generated
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
// Resolves an asset into a `source` for `Image`.
|
||||
|
||||
'use strict';
|
||||
|
||||
const AssetRegistry = require('./AssetRegistry');
|
||||
const AssetSourceResolver = require('./AssetSourceResolver');
|
||||
|
||||
import type {ResolvedAssetSource} from './AssetSourceResolver';
|
||||
|
||||
let _customSourceTransformer, _serverURL, _scriptURL;
|
||||
|
||||
let _sourceCodeScriptURL: ?string;
|
||||
function getSourceCodeScriptURL(): ?string {
|
||||
if (_sourceCodeScriptURL) {
|
||||
return _sourceCodeScriptURL;
|
||||
}
|
||||
|
||||
let sourceCode =
|
||||
global.nativeExtensions && global.nativeExtensions.SourceCode;
|
||||
if (!sourceCode) {
|
||||
sourceCode = require('../NativeModules/specs/NativeSourceCode').default;
|
||||
}
|
||||
_sourceCodeScriptURL = sourceCode.getConstants().scriptURL;
|
||||
return _sourceCodeScriptURL;
|
||||
}
|
||||
|
||||
function getDevServerURL(): ?string {
|
||||
if (_serverURL === undefined) {
|
||||
const sourceCodeScriptURL = getSourceCodeScriptURL();
|
||||
const match =
|
||||
sourceCodeScriptURL && sourceCodeScriptURL.match(/^https?:\/\/.*?\//);
|
||||
if (match) {
|
||||
// jsBundle was loaded from network
|
||||
_serverURL = match[0];
|
||||
} else {
|
||||
// jsBundle was loaded from file
|
||||
_serverURL = null;
|
||||
}
|
||||
}
|
||||
return _serverURL;
|
||||
}
|
||||
|
||||
function _coerceLocalScriptURL(scriptURL: ?string): ?string {
|
||||
if (scriptURL) {
|
||||
if (scriptURL.startsWith('assets://')) {
|
||||
// android: running from within assets, no offline path to use
|
||||
return null;
|
||||
}
|
||||
scriptURL = scriptURL.substring(0, scriptURL.lastIndexOf('/') + 1);
|
||||
if (!scriptURL.includes('://')) {
|
||||
// Add file protocol in case we have an absolute file path and not a URL.
|
||||
// This shouldn't really be necessary. scriptURL should be a URL.
|
||||
scriptURL = 'file://' + scriptURL;
|
||||
}
|
||||
}
|
||||
return scriptURL;
|
||||
}
|
||||
|
||||
function getScriptURL(): ?string {
|
||||
if (_scriptURL === undefined) {
|
||||
_scriptURL = _coerceLocalScriptURL(getSourceCodeScriptURL());
|
||||
}
|
||||
return _scriptURL;
|
||||
}
|
||||
|
||||
function setCustomSourceTransformer(
|
||||
transformer: (resolver: AssetSourceResolver) => ResolvedAssetSource,
|
||||
): void {
|
||||
_customSourceTransformer = transformer;
|
||||
}
|
||||
|
||||
/**
|
||||
* `source` is either a number (opaque type returned by require('./foo.png'))
|
||||
* or an `ImageSource` like { uri: '<http location || file path>' }
|
||||
*/
|
||||
function resolveAssetSource(source: any): ?ResolvedAssetSource {
|
||||
if (typeof source === 'object') {
|
||||
return source;
|
||||
}
|
||||
|
||||
const asset = AssetRegistry.getAssetByID(source);
|
||||
if (!asset) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const resolver = new AssetSourceResolver(
|
||||
getDevServerURL(),
|
||||
getScriptURL(),
|
||||
asset,
|
||||
);
|
||||
if (_customSourceTransformer) {
|
||||
return _customSourceTransformer(resolver);
|
||||
}
|
||||
return resolver.defaultAsset();
|
||||
}
|
||||
|
||||
module.exports = resolveAssetSource;
|
||||
module.exports.pickScale = AssetSourceResolver.pickScale;
|
||||
module.exports.setCustomSourceTransformer = setCustomSourceTransformer;
|
Reference in New Issue
Block a user