Skip to content

Commit d536de6

Browse files
NickGerlemanfacebook-github-bot
authored andcommitted
Support parsing <shadow> (#48991)
Summary: This adds support for parsing the `<shadow>` data type. In combination with `CSSCommaSeparatedList`, we can now parse box shadow expressions. Reviewed By: lenaic Differential Revision: D68744811
1 parent acd19a5 commit d536de6

File tree

2 files changed

+484
-0
lines changed

2 files changed

+484
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
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+
#pragma once
9+
10+
#include <optional>
11+
#include <tuple>
12+
13+
#include <react/renderer/css/CSSColor.h>
14+
#include <react/renderer/css/CSSDataType.h>
15+
#include <react/renderer/css/CSSKeyword.h>
16+
#include <react/renderer/css/CSSLength.h>
17+
#include <react/renderer/css/CSSValueParser.h>
18+
#include <react/utils/to_underlying.h>
19+
20+
namespace facebook::react {
21+
22+
/**
23+
* Representation of CSS <shadow> data type
24+
* https://drafts.csswg.org/css-backgrounds/#typedef-shadow
25+
*/
26+
struct CSSShadow {
27+
CSSLength offsetX{};
28+
CSSLength offsetY{};
29+
CSSLength blurRadius{};
30+
CSSLength spreadDistance{};
31+
CSSColor color{CSSColor::black()};
32+
bool inset{false};
33+
34+
constexpr bool operator==(const CSSShadow& rhs) const = default;
35+
};
36+
37+
/**
38+
* Represents a keyword for an inset shadow.
39+
*/
40+
enum class CSSInsetShadowKeyword : std::underlying_type_t<CSSKeyword> {
41+
Inset = to_underlying(CSSKeyword::Inset),
42+
};
43+
44+
static_assert(CSSDataType<CSSInsetShadowKeyword>);
45+
46+
template <>
47+
struct CSSDataTypeParser<CSSShadow> {
48+
static constexpr auto consume(CSSSyntaxParser& parser)
49+
-> std::optional<CSSShadow> {
50+
std::optional<CSSColor> color{};
51+
bool inset{false};
52+
std::optional<std::tuple<CSSLength, CSSLength, CSSLength, CSSLength>>
53+
lengths{};
54+
55+
for (auto nextValue =
56+
parseNextCSSValue<CSSLength, CSSColor, CSSInsetShadowKeyword>(
57+
parser);
58+
!std::holds_alternative<std::monostate>(nextValue);
59+
nextValue =
60+
parseNextCSSValue<CSSLength, CSSColor, CSSInsetShadowKeyword>(
61+
parser, CSSDelimiter::Whitespace)) {
62+
if (std::holds_alternative<CSSLength>(nextValue)) {
63+
if (lengths.has_value()) {
64+
return {};
65+
}
66+
lengths = parseRestLengths(std::get<CSSLength>(nextValue), parser);
67+
if (!lengths.has_value()) {
68+
return {};
69+
}
70+
continue;
71+
}
72+
73+
if (std::holds_alternative<CSSColor>(nextValue)) {
74+
if (color.has_value()) {
75+
return {};
76+
}
77+
color = std::get<CSSColor>(nextValue);
78+
continue;
79+
}
80+
81+
if (std::holds_alternative<CSSInsetShadowKeyword>(nextValue)) {
82+
if (inset) {
83+
return {};
84+
}
85+
inset = true;
86+
continue;
87+
}
88+
}
89+
90+
if (!lengths.has_value()) {
91+
return {};
92+
}
93+
94+
return CSSShadow{
95+
.offsetX = std::get<0>(*lengths),
96+
.offsetY = std::get<1>(*lengths),
97+
.blurRadius = std::get<2>(*lengths),
98+
.spreadDistance = std::get<3>(*lengths),
99+
.color = color.value_or(CSSColor::black()),
100+
.inset = inset,
101+
};
102+
}
103+
104+
private:
105+
static constexpr auto parseRestLengths(
106+
CSSLength offsetX,
107+
CSSSyntaxParser& parser)
108+
-> std::optional<std::tuple<CSSLength, CSSLength, CSSLength, CSSLength>> {
109+
auto offsetY =
110+
parseNextCSSValue<CSSLength>(parser, CSSDelimiter::Whitespace);
111+
if (std::holds_alternative<std::monostate>(offsetY)) {
112+
return {};
113+
}
114+
115+
auto blurRadius =
116+
parseNextCSSValue<CSSLength>(parser, CSSDelimiter::Whitespace);
117+
if (std::holds_alternative<std::monostate>(blurRadius)) {
118+
return std::make_tuple(
119+
offsetX, std::get<CSSLength>(offsetY), CSSLength{}, CSSLength{});
120+
}
121+
if (std::get<CSSLength>(blurRadius).value < 0) {
122+
return {};
123+
}
124+
125+
auto spreadDistance =
126+
parseNextCSSValue<CSSLength>(parser, CSSDelimiter::Whitespace);
127+
if (std::holds_alternative<std::monostate>(spreadDistance)) {
128+
return std::make_tuple(
129+
offsetX,
130+
std::get<CSSLength>(offsetY),
131+
std::get<CSSLength>(blurRadius),
132+
CSSLength{});
133+
}
134+
135+
return std::make_tuple(
136+
offsetX,
137+
std::get<CSSLength>(offsetY),
138+
std::get<CSSLength>(blurRadius),
139+
std::get<CSSLength>(spreadDistance));
140+
}
141+
};
142+
143+
static_assert(CSSDataType<CSSShadow>);
144+
145+
} // namespace facebook::react

0 commit comments

Comments
 (0)