Skip to content

Commit 28dcf61

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. Changelog: [Internal] Reviewed By: lenaic Differential Revision: D68744811
1 parent a99223f commit 28dcf61

File tree

2 files changed

+491
-0
lines changed

2 files changed

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

0 commit comments

Comments
 (0)