diff --git a/change/react-native-windows-8d47b86f-35f7-4d54-af09-ac420cb892c1.json b/change/react-native-windows-8d47b86f-35f7-4d54-af09-ac420cb892c1.json new file mode 100644 index 00000000000..904845ff766 --- /dev/null +++ b/change/react-native-windows-8d47b86f-35f7-4d54-af09-ac420cb892c1.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "Support headers [crossOrigin and referralPolicy] in Image without srcset or src and only source.uri", + "packageName": "react-native-windows", + "email": "54227869+anupriya13@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/packages/e2e-test-app-fabric/test/__snapshots__/TextComponentTest.test.ts.snap b/packages/e2e-test-app-fabric/test/__snapshots__/TextComponentTest.test.ts.snap index 0b5b36534c7..ee2758f5472 100644 --- a/packages/e2e-test-app-fabric/test/__snapshots__/TextComponentTest.test.ts.snap +++ b/packages/e2e-test-app-fabric/test/__snapshots__/TextComponentTest.test.ts.snap @@ -204,12 +204,12 @@ exports[`Text Tests Text can have advanced borders 1`] = ` "__Children": [ { "Offset": "0, 0, 0", - "Size": "916, 40", + "Size": "916, 39", "Visual Type": "SpriteVisual", "__Children": [ { "Offset": "0, 0, 0", - "Size": "916, 40", + "Size": "916, 39", "Visual Type": "SpriteVisual", "__Children": [ { @@ -245,7 +245,7 @@ exports[`Text Tests Text can have advanced borders 1`] = ` "Color": "rgba(255, 0, 0, 255)", }, "Offset": "-10, 20, 0", - "Size": "10, 14", + "Size": "10, 13", "Visual Type": "SpriteVisual", }, { @@ -281,7 +281,7 @@ exports[`Text Tests Text can have advanced borders 1`] = ` "Color": "rgba(255, 0, 0, 255)", }, "Offset": "0, 22, 0", - "Size": "20, 10", + "Size": "20, 9", "Visual Type": "SpriteVisual", }, ], @@ -290,12 +290,12 @@ exports[`Text Tests Text can have advanced borders 1`] = ` }, { "Offset": "0, 38, 0", - "Size": "916, 39", + "Size": "916, 40", "Visual Type": "SpriteVisual", "__Children": [ { "Offset": "0, 0, 0", - "Size": "916, 39", + "Size": "916, 40", "Visual Type": "SpriteVisual", "__Children": [ { @@ -331,7 +331,7 @@ exports[`Text Tests Text can have advanced borders 1`] = ` "Color": "rgba(0, 0, 255, 255)", }, "Offset": "-10, 20, 0", - "Size": "10, 13", + "Size": "10, 14", "Visual Type": "SpriteVisual", }, { @@ -367,7 +367,7 @@ exports[`Text Tests Text can have advanced borders 1`] = ` "Color": "rgba(0, 0, 255, 255)", }, "Offset": "0, 22, 0", - "Size": "20, 9", + "Size": "20, 10", "Visual Type": "SpriteVisual", }, ], @@ -548,7 +548,7 @@ exports[`Text Tests Text can have borders 1`] = ` "Visual Tree": { "Comment": "text-border", "Offset": "0, 0, 0", - "Size": "916, 385", + "Size": "916, 384", "Visual Type": "SpriteVisual", "__Children": [ { @@ -661,12 +661,12 @@ exports[`Text Tests Text can have borders 1`] = ` }, { "Offset": "0, 365, 0", - "Size": "916, 19", + "Size": "916, 20", "Visual Type": "SpriteVisual", "__Children": [ { "Offset": "0, 0, 0", - "Size": "916, 19", + "Size": "916, 20", "Visual Type": "SpriteVisual", }, ], @@ -761,7 +761,7 @@ exports[`Text Tests Text can have inline views/images 1`] = ` "Visual Tree": { "Comment": "text-view", "Offset": "0, 0, 0", - "Size": "916, 26", + "Size": "916, 23", "Visual Type": "SpriteVisual", "__Children": [ { @@ -781,13 +781,13 @@ exports[`Text Tests Text can have inline views/images 1`] = ` ], }, { - "Offset": "384, 0, 0", - "Size": "34, 23", + "Offset": "384, 18, 0", + "Size": "1, 1", "Visual Type": "SpriteVisual", "__Children": [ { "Offset": "0, 0, 0", - "Size": "34, 23", + "Size": "1, 1", "Visual Type": "SpriteVisual", }, ], @@ -845,17 +845,17 @@ exports[`Text Tests Text can have nested views 1`] = ` "Visual Tree": { "Comment": "text-nested-view", "Offset": "0, 0, 0", - "Size": "916, 40", + "Size": "916, 41", "Visual Type": "SpriteVisual", "__Children": [ { "Offset": "0, 0, 0", - "Size": "916, 20", + "Size": "916, 19", "Visual Type": "SpriteVisual", "__Children": [ { "Offset": "0, 0, 0", - "Size": "916, 20", + "Size": "916, 19", "Visual Type": "SpriteVisual", }, ], @@ -913,7 +913,7 @@ exports[`Text Tests Text can have shadows 1`] = ` "Visual Tree": { "Comment": "text-shadow", "Offset": "0, 0, 0", - "Size": "916, 28", + "Size": "916, 27", "Visual Type": "SpriteVisual", }, } @@ -1031,7 +1031,7 @@ exports[`Text Tests Texts can clip inline View/Images 1`] = ` "Visual Tree": { "Comment": "text-view-images-clipped", "Offset": "0, 0, 0", - "Size": "916, 223", + "Size": "916, 222", "Visual Type": "SpriteVisual", "__Children": [ { @@ -1094,12 +1094,12 @@ exports[`Text Tests Texts can clip inline View/Images 1`] = ` }, { "Offset": "0, 103, 0", - "Size": "916, 19", + "Size": "916, 20", "Visual Type": "SpriteVisual", "__Children": [ { "Offset": "0, 0, 0", - "Size": "916, 19", + "Size": "916, 20", "Visual Type": "SpriteVisual", }, ], diff --git a/packages/playground/Samples/image.tsx b/packages/playground/Samples/image.tsx index 8cf7d11a17c..08368a47991 100644 --- a/packages/playground/Samples/image.tsx +++ b/packages/playground/Samples/image.tsx @@ -268,6 +268,9 @@ export default class Bootstrap extends React.Component< onLoadStart={() => console.log('onLoadStart')} onLoadEnd={() => console.log('onLoadEnd')} onProgress={this.handleOnProgress} + crossOrigin="use-credentials" + referrerPolicy="no-referrer" + /* srcSet={this.state.imageUri}*/ /> )} diff --git a/vnext/overrides.json b/vnext/overrides.json index d3210cae664..9b767df0b4a 100644 --- a/vnext/overrides.json +++ b/vnext/overrides.json @@ -462,6 +462,13 @@ "baseHash": "a5abee6de7dca3cb043b834925de3f6f0443c738", "issue": 4590 }, + { + "type": "patch", + "file": "src-win/Libraries/Image/ImageSourceUtils.js", + "baseFile": "packages/react-native/Libraries/Image/ImageSourceUtils.js", + "baseHash": "136d9dad53466468b288e2fb1b05adbb18c63ed1", + "issue": 14537 + }, { "type": "patch", "file": "src-win/Libraries/Image/resolveAssetSource.windows.js", diff --git a/vnext/src-win/Libraries/Image/ImageSourceUtils.js b/vnext/src-win/Libraries/Image/ImageSourceUtils.js new file mode 100644 index 00000000000..0cd2834c6e5 --- /dev/null +++ b/vnext/src-win/Libraries/Image/ImageSourceUtils.js @@ -0,0 +1,82 @@ +/** + * Copyright (c) Meta Platforms, Inc. and 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 {ResolvedAssetSource} from './AssetSourceResolver'; +import type {ImageProps} from './ImageProps'; + +import resolveAssetSource from './resolveAssetSource'; + +/** + * A function which returns the appropriate value for image source + * by resolving the `source`, `src` and `srcSet` props. + */ +export function getImageSourcesFromImageProps( + imageProps: ImageProps, +): ?ResolvedAssetSource | $ReadOnlyArray<{uri: string, ...}> { + let source = resolveAssetSource(imageProps.source); + + let sources; + + const {crossOrigin, referrerPolicy, src, srcSet, width, height} = imageProps; + + const headers: {[string]: string} = {}; + if (crossOrigin === 'use-credentials') { + headers['Access-Control-Allow-Credentials'] = 'true'; + } + if (referrerPolicy != null) { + headers['Referrer-Policy'] = referrerPolicy; + } + if (srcSet != null) { + const sourceList = []; + const srcSetList = srcSet.split(', '); + // `src` prop should be used with default scale if `srcSet` does not have 1x scale. + let shouldUseSrcForDefaultScale = true; + srcSetList.forEach(imageSrc => { + const [uri, xScale = '1x'] = imageSrc.split(' '); + if (!xScale.endsWith('x')) { + console.warn( + 'The provided format for scale is not supported yet. Please use scales like 1x, 2x, etc.', + ); + } else { + const scale = parseInt(xScale.split('x')[0], 10); + if (!isNaN(scale)) { + // 1x scale is provided in `srcSet` prop so ignore the `src` prop if provided. + shouldUseSrcForDefaultScale = + scale === 1 ? false : shouldUseSrcForDefaultScale; + sourceList.push({headers: headers, scale, uri, width, height}); + } + } + }); + + if (shouldUseSrcForDefaultScale && src != null) { + sourceList.push({ + headers: headers, + scale: 1, + uri: src, + width, + height, + }); + } + if (sourceList.length === 0) { + console.warn('The provided value for srcSet is not valid.'); + } + + sources = sourceList; + } else if (src != null) { + sources = [{uri: src, headers: headers, width, height}]; + } else if (source != null && source.uri) { + sources = [{...source, headers}]; + } else { + sources = source; + } + return sources; +}