Skip to content

Commit 44547bb

Browse files
coadometa-codesync[bot]
authored andcommitted
Move leaf View parsers out of headers (#58785)
Summary: Pull Request resolved: #58785 Move View CSS parsing implementation details for color and length coercion, box shadows, and filters from exported headers into compiled source files. Keep only the supported `coerceColor`, `coerceLength`, and `fromRawValue` declarations in public headers while preserving existing parsing behavior. This change is necessary to remove CSS headers leaks as visibility of CSS module will be changed to `for frameworks` eventually. Update existing conversion tests to exercise the same paths through the public entry points, and regenerate the C++ API snapshots to remove private helper declarations. Changelog: [Internal] Reviewed By: javache Differential Revision: D119507169
1 parent b735789 commit 44547bb

17 files changed

Lines changed: 851 additions & 867 deletions

‎packages/react-native/ReactCommon/react/renderer/components/view/BackgroundImagePropsConversions.cpp‎

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -438,20 +438,32 @@ void fromCSSColorStop(
438438
// first stop with start position
439439
colorStops.push_back(
440440
ColorStop{
441-
.color = fromCSSColor(colorStop.color),
441+
.color = colorFromRGBA(
442+
colorStop.color.r,
443+
colorStop.color.g,
444+
colorStop.color.b,
445+
colorStop.color.a),
442446
.position = convertLengthPercentageToValueUnit(
443447
*colorStop.startPosition)});
444448

445449
// second stop with end position (same color)
446450
colorStops.push_back(
447451
ColorStop{
448-
.color = fromCSSColor(colorStop.color),
452+
.color = colorFromRGBA(
453+
colorStop.color.r,
454+
colorStop.color.g,
455+
colorStop.color.b,
456+
colorStop.color.a),
449457
.position =
450458
convertLengthPercentageToValueUnit(*colorStop.endPosition)});
451459
} else {
452460
// single color stop
453461
ColorStop stop;
454-
stop.color = fromCSSColor(colorStop.color);
462+
stop.color = colorFromRGBA(
463+
colorStop.color.r,
464+
colorStop.color.g,
465+
colorStop.color.b,
466+
colorStop.color.a);
455467

456468
// handle start position if present
457469
if (colorStop.startPosition.has_value()) {
Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#include "BoxShadowPropsConversions.h"
9+
10+
#include <react/debug/react_native_expect.h>
11+
#include <react/featureflags/ReactNativeFeatureFlags.h>
12+
#include <react/renderer/components/view/CSSConversions.h>
13+
#include <react/renderer/css/CSSShadow.h>
14+
#include <react/renderer/css/CSSValueParser.h>
15+
#include <react/renderer/graphics/PlatformColorParser.h>
16+
#include <optional>
17+
#include <string>
18+
#include <unordered_map>
19+
20+
namespace facebook::react {
21+
22+
namespace {
23+
24+
void parseProcessedBoxShadow(
25+
const PropsParserContext& context,
26+
const RawValue& value,
27+
std::vector<BoxShadow>& result) {
28+
react_native_expect(value.hasType<std::vector<RawValue>>());
29+
if (!value.hasType<std::vector<RawValue>>()) {
30+
result = {};
31+
return;
32+
}
33+
34+
std::vector<BoxShadow> boxShadows{};
35+
auto rawBoxShadows = static_cast<std::vector<RawValue>>(value);
36+
for (const auto& rawBoxShadow : rawBoxShadows) {
37+
bool isMap =
38+
rawBoxShadow.hasType<std::unordered_map<std::string, RawValue>>();
39+
react_native_expect(isMap);
40+
if (!isMap) {
41+
// If any box shadow is malformed then we should not apply any of them
42+
// which is the web behavior.
43+
result = {};
44+
return;
45+
}
46+
47+
auto rawBoxShadowMap =
48+
static_cast<std::unordered_map<std::string, RawValue>>(rawBoxShadow);
49+
BoxShadow boxShadow{};
50+
auto offsetX = rawBoxShadowMap.find("offsetX");
51+
react_native_expect(offsetX != rawBoxShadowMap.end());
52+
if (offsetX == rawBoxShadowMap.end()) {
53+
result = {};
54+
return;
55+
}
56+
react_native_expect(offsetX->second.hasType<Float>());
57+
if (!offsetX->second.hasType<Float>()) {
58+
result = {};
59+
return;
60+
}
61+
boxShadow.offsetX = (Float)offsetX->second;
62+
63+
auto offsetY = rawBoxShadowMap.find("offsetY");
64+
react_native_expect(offsetY != rawBoxShadowMap.end());
65+
if (offsetY == rawBoxShadowMap.end()) {
66+
result = {};
67+
return;
68+
}
69+
react_native_expect(offsetY->second.hasType<Float>());
70+
if (!offsetY->second.hasType<Float>()) {
71+
result = {};
72+
return;
73+
}
74+
boxShadow.offsetY = (Float)offsetY->second;
75+
76+
auto blurRadius = rawBoxShadowMap.find("blurRadius");
77+
if (blurRadius != rawBoxShadowMap.end()) {
78+
react_native_expect(blurRadius->second.hasType<Float>());
79+
if (!blurRadius->second.hasType<Float>()) {
80+
result = {};
81+
return;
82+
}
83+
boxShadow.blurRadius = (Float)blurRadius->second;
84+
}
85+
86+
auto spreadDistance = rawBoxShadowMap.find("spreadDistance");
87+
if (spreadDistance != rawBoxShadowMap.end()) {
88+
react_native_expect(spreadDistance->second.hasType<Float>());
89+
if (!spreadDistance->second.hasType<Float>()) {
90+
result = {};
91+
return;
92+
}
93+
boxShadow.spreadDistance = (Float)spreadDistance->second;
94+
}
95+
96+
auto inset = rawBoxShadowMap.find("inset");
97+
if (inset != rawBoxShadowMap.end()) {
98+
react_native_expect(inset->second.hasType<bool>());
99+
if (!inset->second.hasType<bool>()) {
100+
result = {};
101+
return;
102+
}
103+
boxShadow.inset = (bool)inset->second;
104+
}
105+
106+
auto color = rawBoxShadowMap.find("color");
107+
if (color != rawBoxShadowMap.end()) {
108+
fromRawValue(
109+
context.contextContainer,
110+
context.surfaceId,
111+
color->second,
112+
boxShadow.color);
113+
}
114+
115+
boxShadows.push_back(boxShadow);
116+
}
117+
118+
result = boxShadows;
119+
}
120+
121+
std::optional<BoxShadow> fromCSSShadow(const CSSShadow& cssShadow) {
122+
// TODO: handle non-px values
123+
if (cssShadow.offsetX.unit != CSSLengthUnit::Px ||
124+
cssShadow.offsetY.unit != CSSLengthUnit::Px ||
125+
cssShadow.blurRadius.unit != CSSLengthUnit::Px ||
126+
cssShadow.spreadDistance.unit != CSSLengthUnit::Px) {
127+
return {};
128+
}
129+
130+
return BoxShadow{
131+
.offsetX = cssShadow.offsetX.value,
132+
.offsetY = cssShadow.offsetY.value,
133+
.blurRadius = cssShadow.blurRadius.value,
134+
.spreadDistance = cssShadow.spreadDistance.value,
135+
.color = colorFromRGBA(
136+
cssShadow.color.r,
137+
cssShadow.color.g,
138+
cssShadow.color.b,
139+
cssShadow.color.a),
140+
.inset = cssShadow.inset,
141+
};
142+
}
143+
144+
void parseUnprocessedBoxShadowString(
145+
std::string&& value,
146+
std::vector<BoxShadow>& result) {
147+
auto boxShadowList = parseCSSProperty<CSSShadowList>((std::string)value);
148+
if (!std::holds_alternative<CSSShadowList>(boxShadowList)) {
149+
result = {};
150+
return;
151+
}
152+
153+
for (const auto& cssShadow : std::get<CSSShadowList>(boxShadowList)) {
154+
if (auto boxShadow = fromCSSShadow(cssShadow)) {
155+
result.push_back(*boxShadow);
156+
} else {
157+
result = {};
158+
return;
159+
}
160+
}
161+
}
162+
163+
std::optional<BoxShadow> parseBoxShadowRawValue(
164+
const PropsParserContext& context,
165+
const RawValue& value) {
166+
if (!value.hasType<std::unordered_map<std::string, RawValue>>()) {
167+
return {};
168+
}
169+
170+
auto boxShadow = std::unordered_map<std::string, RawValue>(value);
171+
auto rawOffsetX = boxShadow.find("offsetX");
172+
if (rawOffsetX == boxShadow.end()) {
173+
return {};
174+
}
175+
auto offsetX = coerceLength(rawOffsetX->second);
176+
if (!offsetX.has_value()) {
177+
return {};
178+
}
179+
180+
auto rawOffsetY = boxShadow.find("offsetY");
181+
if (rawOffsetY == boxShadow.end()) {
182+
return {};
183+
}
184+
auto offsetY = coerceLength(rawOffsetY->second);
185+
if (!offsetY.has_value()) {
186+
return {};
187+
}
188+
189+
Float blurRadius = 0;
190+
auto rawBlurRadius = boxShadow.find("blurRadius");
191+
if (rawBlurRadius != boxShadow.end()) {
192+
if (auto blurRadiusValue = coerceLength(rawBlurRadius->second)) {
193+
if (*blurRadiusValue < 0) {
194+
return {};
195+
}
196+
blurRadius = *blurRadiusValue;
197+
} else {
198+
return {};
199+
}
200+
}
201+
202+
Float spreadDistance = 0;
203+
auto rawSpreadDistance = boxShadow.find("spreadDistance");
204+
if (rawSpreadDistance != boxShadow.end()) {
205+
if (auto spreadDistanceValue = coerceLength(rawSpreadDistance->second)) {
206+
spreadDistance = *spreadDistanceValue;
207+
} else {
208+
return {};
209+
}
210+
}
211+
212+
bool inset = false;
213+
auto rawInset = boxShadow.find("inset");
214+
if (rawInset != boxShadow.end()) {
215+
if (rawInset->second.hasType<bool>()) {
216+
inset = (bool)rawInset->second;
217+
} else {
218+
return {};
219+
}
220+
}
221+
222+
SharedColor color;
223+
auto rawColor = boxShadow.find("color");
224+
if (rawColor != boxShadow.end()) {
225+
color = coerceColor(rawColor->second, context);
226+
if (!color) {
227+
return {};
228+
}
229+
}
230+
231+
return BoxShadow{
232+
.offsetX = *offsetX,
233+
.offsetY = *offsetY,
234+
.blurRadius = blurRadius,
235+
.spreadDistance = spreadDistance,
236+
.color = color,
237+
.inset = inset};
238+
}
239+
240+
void parseUnprocessedBoxShadowList(
241+
const PropsParserContext& context,
242+
std::vector<RawValue>&& value,
243+
std::vector<BoxShadow>& result) {
244+
for (const auto& rawValue : value) {
245+
if (auto boxShadow = parseBoxShadowRawValue(context, rawValue)) {
246+
result.push_back(*boxShadow);
247+
} else {
248+
result = {};
249+
return;
250+
}
251+
}
252+
}
253+
254+
void parseUnprocessedBoxShadow(
255+
const PropsParserContext& context,
256+
const RawValue& value,
257+
std::vector<BoxShadow>& result) {
258+
if (value.hasType<std::string>()) {
259+
parseUnprocessedBoxShadowString((std::string)value, result);
260+
} else if (value.hasType<std::vector<RawValue>>()) {
261+
parseUnprocessedBoxShadowList(
262+
context, (std::vector<RawValue>)value, result);
263+
} else {
264+
result = {};
265+
}
266+
}
267+
268+
} // namespace
269+
270+
void fromRawValue(
271+
const PropsParserContext& context,
272+
const RawValue& value,
273+
std::vector<BoxShadow>& result) {
274+
if (ReactNativeFeatureFlags::enableNativeCSSParsing()) {
275+
parseUnprocessedBoxShadow(context, value, result);
276+
} else {
277+
parseProcessedBoxShadow(context, value, result);
278+
}
279+
}
280+
281+
} // namespace facebook::react

0 commit comments

Comments
 (0)