Skip to content

Commit

Permalink
Add option to resolve all asset scales for sources (#45989)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #45989

Some React Native platforms have multiple display resolutions to contend with. In such cases, the PixelRatio API, which assumes a single display resolution value for the whole app, does not correctly resolve the scale for a particular Image.

Adding an API to resolve each scale variant to a packaged asset allows other platforms to override the Image component to pass all scale options to the Image native component, rather than only the one matching the value from PixelRatio.

## Changelog

[General][Added] Capability to resolve specific asset scale

Differential Revision: D61172622
  • Loading branch information
rozele authored and facebook-github-bot committed Aug 13, 2024
1 parent a622a43 commit 103e53c
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 12 deletions.
20 changes: 11 additions & 9 deletions packages/react-native/Libraries/Image/AssetSourceResolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ const invariant = require('invariant');
/**
* Returns a path like 'assets/AwesomeModule/icon@2x.png'
*/
function getScaledAssetPath(asset: PackagerAsset): string {
const scale = pickScale(asset.scales, PixelRatio.get());
const scaleSuffix = scale === 1 ? '' : '@' + scale + 'x';
function getScaledAssetPath(asset: PackagerAsset, scale?: number): string {
const resolvedScale = scale ?? pickScale(asset.scales, PixelRatio.get());
const scaleSuffix = resolvedScale === 1 ? '' : '@' + resolvedScale + 'x';
const assetDir = getBasePath(asset);
return assetDir + '/' + asset.name + scaleSuffix + '.' + asset.type;
}
Expand Down Expand Up @@ -116,15 +116,16 @@ class AssetSourceResolver {
* Returns an absolute URL which can be used to fetch the asset
* from the devserver
*/
assetServerURL(): ResolvedAssetSource {
assetServerURL(scale?: number): ResolvedAssetSource {
invariant(this.serverUrl != null, 'need server to load from');
return this.fromSource(
this.serverUrl +
getScaledAssetPath(this.asset) +
getScaledAssetPath(this.asset, scale) +
'?platform=' +
Platform.OS +
'&hash=' +
this.asset.hash,
scale,
);
}

Expand All @@ -140,13 +141,14 @@ class AssetSourceResolver {
* 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 {
scaledAssetURLNearBundle(scale?: number): 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, '_'),
path + getScaledAssetPath(this.asset, scale).replace(/\.\.\//g, '_'),
scale,
);
}

Expand Down Expand Up @@ -174,13 +176,13 @@ class AssetSourceResolver {
return this.fromSource(path + getAssetPathInDrawableFolder(this.asset));
}

fromSource(source: string): ResolvedAssetSource {
fromSource(source: string, scale?: number): ResolvedAssetSource {
return {
__packager_asset: true,
width: this.asset.width,
height: this.asset.height,
uri: source,
scale: pickScale(this.asset.scales, PixelRatio.get()),
scale: scale ?? pickScale(this.asset.scales, PixelRatio.get()),
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4751,12 +4751,12 @@ declare class AssetSourceResolver {
isLoadedFromFileSystem(): boolean;
defaultAsset(): ResolvedAssetSource;
getAssetUsingResolver(resolver: AssetDestPathResolver): ResolvedAssetSource;
assetServerURL(): ResolvedAssetSource;
assetServerURL(scale?: number): ResolvedAssetSource;
scaledAssetPath(): ResolvedAssetSource;
scaledAssetURLNearBundle(): ResolvedAssetSource;
scaledAssetURLNearBundle(scale?: number): ResolvedAssetSource;
resourceIdentifierWithoutScale(): ResolvedAssetSource;
drawableFolderInBundle(): ResolvedAssetSource;
fromSource(source: string): ResolvedAssetSource;
fromSource(source: string, scale?: number): ResolvedAssetSource;
static pickScale: (scales: Array<number>, deviceScale?: number) => number;
}
declare module.exports: AssetSourceResolver;
Expand Down

0 comments on commit 103e53c

Please sign in to comment.