mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Fix incorrect view flattening when using a specific not fully transparent color (#51379)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/51379 Changelog: [General][Fixed] Fix incorrect flattening / non-rendering of views with backgroundColor set to `rgba(255, 255, 255, 127/256)` Fixes #51378. ## Context When testing some unrelated things with Fantom is realized that the color for some text that I wasn't explicitly defining was being set to `rgba(255, 255, 255, 127)`, like here: https://github.com/facebook/react-native/blob/249a24ac756275eadbe3b4df1ff9c974af1671d2/packages/react-native-fantom/src/__tests__/Fantom-itest.js#L540-L542 When digging a bit more about why, I realized that was actually the value for `UndefinedColor`. When looking a bit deeper, I saw that the value for that constant was being set like this: ``` using Color = int32_t; namespace HostPlatformColor { static const facebook::react::Color UndefinedColor = std::numeric_limits<facebook::react::Color>::max(); } ``` I'm not sure what the logic could've been here: - Defining it as a value out of bounds for all valid colors? In this case, it's a 32 bit value so all the range of values are actually valid RGBA colors. - Defining it as a fully opaque white? Seems dangerous for a default because you wouldn't be able to distinguish a explicitly set white color from a non-set color, relevant if you're seeing a white background color in a view on top of another view with any other background color. The result of this existing logic was actually setting `UndefinedColor` to `rgba(255, 255, 255, 127)` because the alpha channel is defined in the first bits of the value, and `Color` being a signed int with 32 bits, the largest value is `01111....1`, so extracting the first 8 bits, you get 127. ## Changes This changes the value set for the `UndefinedColor` constant (which is used, among other things, to determine if a view sets a background color, or otherwise could potentially be flattened). The new value, instead of white with a 127/256 opacity, is black with 0% opacity (or simply the number 0 in `int32_t`). Reviewed By: javache Differential Revision: D74869311 fbshipit-source-id: 5582b4803b0b5c72cb3c1b33720c4542c5e3f1de
This commit is contained in:
committed by
Facebook GitHub Bot
parent
6581c69e10
commit
b1e8729f4d
@@ -538,7 +538,7 @@ describe('Fantom', () => {
|
||||
},
|
||||
],
|
||||
props: {
|
||||
foregroundColor: 'rgba(255, 255, 255, 127)',
|
||||
foregroundColor: 'rgba(0, 0, 0, 0)',
|
||||
},
|
||||
type: 'Paragraph',
|
||||
});
|
||||
|
||||
@@ -33,9 +33,7 @@ describe('<Button>', () => {
|
||||
).toEqual(
|
||||
// Upper case on Android (also used by Fantom)
|
||||
<rn-view backgroundColor="rgba(33, 150, 243, 255)">
|
||||
<rn-paragraph
|
||||
backgroundColor="rgba(255, 255, 255, 127)"
|
||||
foregroundColor="rgba(255, 255, 255, 255)">
|
||||
<rn-paragraph foregroundColor="rgba(255, 255, 255, 255)">
|
||||
HELLO
|
||||
</rn-paragraph>
|
||||
</rn-view>,
|
||||
@@ -57,9 +55,7 @@ describe('<Button>', () => {
|
||||
.toJSX(),
|
||||
).toEqual(
|
||||
<rn-view backgroundColor="rgba(0, 0, 255, 255)">
|
||||
<rn-paragraph
|
||||
backgroundColor="rgba(255, 255, 255, 127)"
|
||||
foregroundColor="rgba(255, 255, 255, 255)">
|
||||
<rn-paragraph foregroundColor="rgba(255, 255, 255, 255)">
|
||||
HELLO
|
||||
</rn-paragraph>
|
||||
</rn-view>,
|
||||
@@ -105,9 +101,7 @@ describe('<Button>', () => {
|
||||
.toJSX(),
|
||||
).toEqual(
|
||||
<rn-view backgroundColor="rgba(223, 223, 223, 255)">
|
||||
<rn-paragraph
|
||||
backgroundColor="rgba(255, 255, 255, 127)"
|
||||
foregroundColor="rgba(161, 161, 161, 255)">
|
||||
<rn-paragraph foregroundColor="rgba(161, 161, 161, 255)">
|
||||
HELLO
|
||||
</rn-paragraph>
|
||||
</rn-view>,
|
||||
@@ -189,9 +183,7 @@ describe('<Button>', () => {
|
||||
.toJSX(),
|
||||
).toEqual(
|
||||
<rn-view backgroundColor="rgba(33, 150, 243, 255)">
|
||||
<rn-paragraph
|
||||
backgroundColor="rgba(255, 255, 255, 127)"
|
||||
foregroundColor="rgba(255, 255, 255, 255)">
|
||||
<rn-paragraph foregroundColor="rgba(255, 255, 255, 255)">
|
||||
HELLO
|
||||
</rn-paragraph>
|
||||
</rn-view>,
|
||||
@@ -233,9 +225,7 @@ describe('<Button>', () => {
|
||||
.toJSX(),
|
||||
).toEqual(
|
||||
<rn-view backgroundColor="rgba(223, 223, 223, 255)">
|
||||
<rn-paragraph
|
||||
backgroundColor="rgba(255, 255, 255, 127)"
|
||||
foregroundColor="rgba(161, 161, 161, 255)">
|
||||
<rn-paragraph foregroundColor="rgba(161, 161, 161, 255)">
|
||||
HELLO
|
||||
</rn-paragraph>
|
||||
</rn-view>,
|
||||
|
||||
+1
-2
@@ -15,8 +15,7 @@ namespace facebook::react {
|
||||
using Color = int32_t;
|
||||
|
||||
namespace HostPlatformColor {
|
||||
static const facebook::react::Color UndefinedColor =
|
||||
std::numeric_limits<facebook::react::Color>::max();
|
||||
constexpr facebook::react::Color UndefinedColor = 0;
|
||||
}
|
||||
|
||||
inline Color
|
||||
|
||||
+1
-2
@@ -16,8 +16,7 @@ namespace facebook::react {
|
||||
using Color = int32_t;
|
||||
|
||||
namespace HostPlatformColor {
|
||||
static const facebook::react::Color UndefinedColor =
|
||||
std::numeric_limits<facebook::react::Color>::max();
|
||||
constexpr facebook::react::Color UndefinedColor = 0;
|
||||
}
|
||||
|
||||
inline Color
|
||||
|
||||
+133
-99
@@ -231,125 +231,159 @@ describe('ViewFlattening', () => {
|
||||
'Insert {type: "View", parentNativeID: "J", index: 1, nativeID: "B"}',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
test('parent-child switching from unflattened-flattened to flattened-unflattened', () => {
|
||||
const root = Fantom.createRoot();
|
||||
test('parent-child switching from unflattened-flattened to flattened-unflattened', () => {
|
||||
const root = Fantom.createRoot();
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
style={{
|
||||
marginTop: 100,
|
||||
opacity: 0,
|
||||
}}>
|
||||
Fantom.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
style={{
|
||||
marginTop: 50,
|
||||
}}>
|
||||
<View
|
||||
nativeID={'child'}
|
||||
style={{height: 10, width: 10, backgroundColor: 'red'}}
|
||||
/>
|
||||
</View>
|
||||
</View>,
|
||||
);
|
||||
});
|
||||
|
||||
expect(root.takeMountingManagerLogs()).toEqual([
|
||||
'Update {type: "RootView", nativeID: (root)}',
|
||||
'Create {type: "View", nativeID: (N/A)}',
|
||||
'Create {type: "View", nativeID: "child"}',
|
||||
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}',
|
||||
'Insert {type: "View", parentNativeID: (root), index: 0, nativeID: (N/A)}',
|
||||
]);
|
||||
|
||||
// force view to be flattened.
|
||||
Fantom.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
style={{
|
||||
marginTop: 100,
|
||||
}}>
|
||||
<View
|
||||
style={{
|
||||
marginTop: 50,
|
||||
marginTop: 100,
|
||||
opacity: 0,
|
||||
}}>
|
||||
<View
|
||||
nativeID={'child'}
|
||||
style={{height: 10, width: 10, backgroundColor: 'red'}}
|
||||
/>
|
||||
</View>
|
||||
</View>,
|
||||
);
|
||||
});
|
||||
style={{
|
||||
marginTop: 50,
|
||||
}}>
|
||||
<View
|
||||
nativeID={'child'}
|
||||
style={{height: 10, width: 10, backgroundColor: 'red'}}
|
||||
/>
|
||||
</View>
|
||||
</View>,
|
||||
);
|
||||
});
|
||||
|
||||
expect(root.takeMountingManagerLogs()).toEqual([
|
||||
'Update {type: "View", nativeID: "child"}',
|
||||
'Remove {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}',
|
||||
'Remove {type: "View", parentNativeID: (root), index: 0, nativeID: (N/A)}',
|
||||
'Delete {type: "View", nativeID: (N/A)}',
|
||||
'Create {type: "View", nativeID: (N/A)}',
|
||||
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}',
|
||||
'Insert {type: "View", parentNativeID: (root), index: 0, nativeID: (N/A)}',
|
||||
]);
|
||||
});
|
||||
expect(root.takeMountingManagerLogs()).toEqual([
|
||||
'Update {type: "RootView", nativeID: (root)}',
|
||||
'Create {type: "View", nativeID: (N/A)}',
|
||||
'Create {type: "View", nativeID: "child"}',
|
||||
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}',
|
||||
'Insert {type: "View", parentNativeID: (root), index: 0, nativeID: (N/A)}',
|
||||
]);
|
||||
|
||||
test('parent-child switching from flattened-unflattened to unflattened-flattened', () => {
|
||||
const root = Fantom.createRoot();
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
style={{
|
||||
marginTop: 100,
|
||||
}}>
|
||||
// force view to be flattened.
|
||||
Fantom.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
style={{
|
||||
marginTop: 50,
|
||||
marginTop: 100,
|
||||
}}>
|
||||
<View
|
||||
style={{
|
||||
marginTop: 50,
|
||||
opacity: 0,
|
||||
}}>
|
||||
<View
|
||||
nativeID={'child'}
|
||||
style={{height: 10, width: 10, backgroundColor: 'red'}}
|
||||
/>
|
||||
</View>
|
||||
</View>,
|
||||
);
|
||||
});
|
||||
|
||||
expect(root.takeMountingManagerLogs()).toEqual([
|
||||
'Update {type: "View", nativeID: "child"}',
|
||||
'Remove {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}',
|
||||
'Remove {type: "View", parentNativeID: (root), index: 0, nativeID: (N/A)}',
|
||||
'Delete {type: "View", nativeID: (N/A)}',
|
||||
'Create {type: "View", nativeID: (N/A)}',
|
||||
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}',
|
||||
'Insert {type: "View", parentNativeID: (root), index: 0, nativeID: (N/A)}',
|
||||
]);
|
||||
});
|
||||
|
||||
test('parent-child switching from flattened-unflattened to unflattened-flattened', () => {
|
||||
const root = Fantom.createRoot();
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
style={{
|
||||
marginTop: 100,
|
||||
}}>
|
||||
<View
|
||||
style={{
|
||||
marginTop: 50,
|
||||
opacity: 0,
|
||||
}}>
|
||||
<View nativeID={'child'} style={{height: 10, width: 10}} />
|
||||
</View>
|
||||
</View>,
|
||||
);
|
||||
});
|
||||
|
||||
expect(root.takeMountingManagerLogs()).toEqual([
|
||||
'Update {type: "RootView", nativeID: (root)}',
|
||||
'Create {type: "View", nativeID: (N/A)}',
|
||||
'Create {type: "View", nativeID: "child"}',
|
||||
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}',
|
||||
'Insert {type: "View", parentNativeID: (root), index: 0, nativeID: (N/A)}',
|
||||
]);
|
||||
|
||||
// force view to be flattened.
|
||||
Fantom.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
style={{
|
||||
marginTop: 100,
|
||||
opacity: 0,
|
||||
}}>
|
||||
<View nativeID={'child'} style={{height: 10, width: 10}} />
|
||||
</View>
|
||||
</View>,
|
||||
);
|
||||
<View
|
||||
style={{
|
||||
marginTop: 50,
|
||||
}}>
|
||||
<View nativeID={'child'} style={{height: 10, width: 10}} />
|
||||
</View>
|
||||
</View>,
|
||||
);
|
||||
});
|
||||
expect(root.takeMountingManagerLogs()).toEqual([
|
||||
'Update {type: "View", nativeID: "child"}',
|
||||
'Remove {type: "View", parentNativeID: (root), index: 0, nativeID: (N/A)}',
|
||||
'Remove {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}',
|
||||
'Delete {type: "View", nativeID: (N/A)}',
|
||||
'Create {type: "View", nativeID: (N/A)}',
|
||||
'Insert {type: "View", parentNativeID: (root), index: 0, nativeID: (N/A)}',
|
||||
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}',
|
||||
]);
|
||||
});
|
||||
|
||||
expect(root.takeMountingManagerLogs()).toEqual([
|
||||
'Update {type: "RootView", nativeID: (root)}',
|
||||
'Create {type: "View", nativeID: (N/A)}',
|
||||
'Create {type: "View", nativeID: "child"}',
|
||||
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}',
|
||||
'Insert {type: "View", parentNativeID: (root), index: 0, nativeID: (N/A)}',
|
||||
]);
|
||||
test('#51378: view with rgba(255,255,255,127/256) background color is not flattened', () => {
|
||||
const root = Fantom.createRoot();
|
||||
|
||||
// force view to be flattened.
|
||||
Fantom.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
style={{
|
||||
marginTop: 100,
|
||||
opacity: 0,
|
||||
}}>
|
||||
Fantom.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
style={{
|
||||
marginTop: 50,
|
||||
}}>
|
||||
<View nativeID={'child'} style={{height: 10, width: 10}} />
|
||||
</View>
|
||||
</View>,
|
||||
width: 100,
|
||||
height: 100,
|
||||
backgroundColor: `rgba(255, 255, 255, ${127 / 256})`,
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
|
||||
expect(root.takeMountingManagerLogs()).toEqual([
|
||||
'Update {type: "RootView", nativeID: (root)}',
|
||||
'Create {type: "View", nativeID: (N/A)}',
|
||||
'Insert {type: "View", parentNativeID: (root), index: 0, nativeID: (N/A)}',
|
||||
]);
|
||||
|
||||
expect(
|
||||
root
|
||||
.getRenderedOutput({props: ['width', 'height', 'backgroundColor']})
|
||||
.toJSX(),
|
||||
).toEqual(
|
||||
<rn-view
|
||||
width="100.000000"
|
||||
height="100.000000"
|
||||
backgroundColor="rgba(255, 255, 255, 127)"
|
||||
/>,
|
||||
);
|
||||
});
|
||||
expect(root.takeMountingManagerLogs()).toEqual([
|
||||
'Update {type: "View", nativeID: "child"}',
|
||||
'Remove {type: "View", parentNativeID: (root), index: 0, nativeID: (N/A)}',
|
||||
'Remove {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}',
|
||||
'Delete {type: "View", nativeID: (N/A)}',
|
||||
'Create {type: "View", nativeID: (N/A)}',
|
||||
'Insert {type: "View", parentNativeID: (root), index: 0, nativeID: (N/A)}',
|
||||
'Insert {type: "View", parentNativeID: (N/A), index: 0, nativeID: "child"}',
|
||||
]);
|
||||
});
|
||||
|
||||
describe('reconciliation of setNativeProps and React commit', () => {
|
||||
|
||||
Reference in New Issue
Block a user