Skip to content

Commit 4d66a26

Browse files
NickGerlemanmeta-codesync[bot]
authored andcommitted
Replace CSSSyntaxParser with CSSValueParser in data type sinks
Summary: Previously, CSSDataTypeParser sinks received a raw CSSSyntaxParser& reference, which exposed low-level tokenization APIs (consumeComponentValue with lambdas, consumeToken, etc.) that data type parsers should not use directly. This made it unclear what operations are appropriate when implementing a new CSS data type. This change promotes detail::CSSValueParser to a public CSSValueParser class that wraps CSSSyntaxParser and exposes only value-level parsing operations: parseNextValue, peekNextValue, consumeWhitespace, consumeDelimiter, isFinished, peekNextTokenIs, and saveState/restoreState for lookahead patterns. All CSSDataTypeParser sink methods now receive CSSValueParser& instead of CSSSyntaxParser&, and use parser.parseNextValue<T>() instead of the free function parseNextCSSValue<T>(parser). Direct consumeComponentValue calls in gradient parsers (CSSBackgroundImage.h) are replaced with keyword set parsing via parseNextValue<KeywordEnum>, with new To/At keywords added to CSSKeyword. The free functions parseCSSProperty, parseNextCSSValue, and peekNextCSSValue remain as convenience wrappers for backward compatibility. Changelog: [Internal] Reviewed By: jorge-cab Differential Revision: D94357104 fbshipit-source-id: 3ba2ba236c9c6e82673e2759a6c7af803599b7f0
1 parent 36212c2 commit 4d66a26

File tree

15 files changed

+312
-310
lines changed

15 files changed

+312
-310
lines changed

packages/react-native/ReactCommon/react/renderer/css/CSSBackgroundImage.h

Lines changed: 110 additions & 127 deletions
Large diffs are not rendered by default.

packages/react-native/ReactCommon/react/renderer/css/CSSColor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ struct CSSDataTypeParser<CSSColor> {
4747
return {};
4848
}
4949

50-
static constexpr auto consumeFunctionBlock(const CSSFunctionBlock &func, CSSSyntaxParser &parser)
50+
static constexpr auto consumeFunctionBlock(const CSSFunctionBlock &func, CSSValueParser &parser)
5151
-> std::optional<CSSColor>
5252
{
5353
return parseCSSColorFunction<CSSColor>(func.name, parser);

packages/react-native/ReactCommon/react/renderer/css/CSSColorFunction.h

Lines changed: 38 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
#include <react/renderer/css/CSSAngle.h>
1818
#include <react/renderer/css/CSSNumber.h>
1919
#include <react/renderer/css/CSSPercentage.h>
20-
#include <react/renderer/css/CSSSyntaxParser.h>
2120
#include <react/renderer/css/CSSValueParser.h>
2221
#include <react/utils/PackTraits.h>
2322
#include <react/utils/fnv1a.h>
@@ -154,16 +153,19 @@ constexpr std::optional<float> normalizeComponent(
154153
}
155154

156155
template <CSSDataType... FirstComponentAllowedTypesT>
157-
constexpr bool isLegacyColorFunction(CSSSyntaxParser &parser)
156+
constexpr bool isLegacyColorFunction(CSSValueParser &parser)
158157
{
159-
auto lookahead = parser;
160-
auto next = parseNextCSSValue<FirstComponentAllowedTypesT...>(lookahead);
158+
auto saved = parser.syntaxParser();
159+
auto next = parser.parseNextValue<FirstComponentAllowedTypesT...>();
161160
if (std::holds_alternative<std::monostate>(next)) {
161+
parser.syntaxParser() = saved;
162162
return false;
163163
}
164164

165-
return lookahead.consumeComponentValue<bool>(
166-
CSSDelimiter::OptionalWhitespace, [](CSSPreservedToken token) { return token.type() == CSSTokenType::Comma; });
165+
parser.syntaxParser().consumeWhitespace();
166+
bool isLegacy = parser.syntaxParser().peek().type() == CSSTokenType::Comma;
167+
parser.syntaxParser() = saved;
168+
return isLegacy;
167169
}
168170

169171
/**
@@ -172,29 +174,29 @@ constexpr bool isLegacyColorFunction(CSSSyntaxParser &parser)
172174
* https://www.w3.org/TR/css-color-4/#typedef-legacy-rgb-syntax
173175
*/
174176
template <typename CSSColor>
175-
constexpr std::optional<CSSColor> parseLegacyRgbFunction(CSSSyntaxParser &parser)
177+
constexpr std::optional<CSSColor> parseLegacyRgbFunction(CSSValueParser &parser)
176178
{
177-
auto rawRed = parseNextCSSValue<CSSNumber, CSSPercentage>(parser);
179+
auto rawRed = parser.parseNextValue<CSSNumber, CSSPercentage>();
178180
bool usesNumber = std::holds_alternative<CSSNumber>(rawRed);
179181

180182
auto red = normalizeComponent(rawRed, 255.0f);
181183
if (!red.has_value()) {
182184
return {};
183185
}
184186

185-
auto green = usesNumber ? normalizeNumberComponent(parseNextCSSValue<CSSNumber>(parser, CSSDelimiter::Comma))
186-
: normalizeComponent(parseNextCSSValue<CSSPercentage>(parser, CSSDelimiter::Comma), 255.0f);
187+
auto green = usesNumber ? normalizeNumberComponent(parser.parseNextValue<CSSNumber>(CSSDelimiter::Comma))
188+
: normalizeComponent(parser.parseNextValue<CSSPercentage>(CSSDelimiter::Comma), 255.0f);
187189
if (!green.has_value()) {
188190
return {};
189191
}
190192

191-
auto blue = usesNumber ? normalizeNumberComponent(parseNextCSSValue<CSSNumber>(parser, CSSDelimiter::Comma))
192-
: normalizeComponent(parseNextCSSValue<CSSPercentage>(parser, CSSDelimiter::Comma), 255.0f);
193+
auto blue = usesNumber ? normalizeNumberComponent(parser.parseNextValue<CSSNumber>(CSSDelimiter::Comma))
194+
: normalizeComponent(parser.parseNextValue<CSSPercentage>(CSSDelimiter::Comma), 255.0f);
193195
if (!blue.has_value()) {
194196
return {};
195197
}
196198

197-
auto alpha = normalizeComponent(parseNextCSSValue<CSSNumber, CSSPercentage>(parser, CSSDelimiter::Comma), 1.0f);
199+
auto alpha = normalizeComponent(parser.parseNextValue<CSSNumber, CSSPercentage>(CSSDelimiter::Comma), 1.0f);
198200

199201
return CSSColor{
200202
.r = clamp255Component(*red),
@@ -210,26 +212,25 @@ constexpr std::optional<CSSColor> parseLegacyRgbFunction(CSSSyntaxParser &parser
210212
* https://www.w3.org/TR/css-color-4/#typedef-modern-rgb-syntax
211213
*/
212214
template <typename CSSColor>
213-
constexpr std::optional<CSSColor> parseModernRgbFunction(CSSSyntaxParser &parser)
215+
constexpr std::optional<CSSColor> parseModernRgbFunction(CSSValueParser &parser)
214216
{
215-
auto red = normalizeComponent(parseNextCSSValue<CSSNumber, CSSPercentage>(parser), 255.0f);
217+
auto red = normalizeComponent(parser.parseNextValue<CSSNumber, CSSPercentage>(), 255.0f);
216218
if (!red.has_value()) {
217219
return {};
218220
}
219221

220-
auto green =
221-
normalizeComponent(parseNextCSSValue<CSSNumber, CSSPercentage>(parser, CSSDelimiter::Whitespace), 255.0f);
222+
auto green = normalizeComponent(parser.parseNextValue<CSSNumber, CSSPercentage>(CSSDelimiter::Whitespace), 255.0f);
222223
if (!green.has_value()) {
223224
return {};
224225
}
225226

226-
auto blue = normalizeComponent(parseNextCSSValue<CSSNumber, CSSPercentage>(parser, CSSDelimiter::Whitespace), 255.0f);
227+
auto blue = normalizeComponent(parser.parseNextValue<CSSNumber, CSSPercentage>(CSSDelimiter::Whitespace), 255.0f);
227228
if (!blue.has_value()) {
228229
return {};
229230
}
230231

231232
auto alpha =
232-
normalizeComponent(parseNextCSSValue<CSSNumber, CSSPercentage>(parser, CSSDelimiter::SolidusOrWhitespace), 1.0f);
233+
normalizeComponent(parser.parseNextValue<CSSNumber, CSSPercentage>(CSSDelimiter::SolidusOrWhitespace), 1.0f);
233234

234235
return CSSColor{
235236
.r = clamp255Component(*red),
@@ -244,7 +245,7 @@ constexpr std::optional<CSSColor> parseModernRgbFunction(CSSSyntaxParser &parser
244245
* https://www.w3.org/TR/css-color-4/#funcdef-rgb
245246
*/
246247
template <typename CSSColor>
247-
constexpr std::optional<CSSColor> parseRgbFunction(CSSSyntaxParser &parser)
248+
constexpr std::optional<CSSColor> parseRgbFunction(CSSValueParser &parser)
248249
{
249250
if (isLegacyColorFunction<CSSNumber, CSSPercentage>(parser)) {
250251
return parseLegacyRgbFunction<CSSColor>(parser);
@@ -259,24 +260,24 @@ constexpr std::optional<CSSColor> parseRgbFunction(CSSSyntaxParser &parser)
259260
* https://www.w3.org/TR/css-color-4/#typedef-legacy-hsl-syntax
260261
*/
261262
template <typename CSSColor>
262-
inline std::optional<CSSColor> parseLegacyHslFunction(CSSSyntaxParser &parser)
263+
inline std::optional<CSSColor> parseLegacyHslFunction(CSSValueParser &parser)
263264
{
264-
auto h = normalizeHueComponent(parseNextCSSValue<CSSNumber, CSSAngle>(parser));
265+
auto h = normalizeHueComponent(parser.parseNextValue<CSSNumber, CSSAngle>());
265266
if (!h.has_value()) {
266267
return {};
267268
}
268269

269-
auto s = normalizeComponent(parseNextCSSValue<CSSPercentage>(parser, CSSDelimiter::Comma), 100.0f);
270+
auto s = normalizeComponent(parser.parseNextValue<CSSPercentage>(CSSDelimiter::Comma), 100.0f);
270271
if (!s.has_value()) {
271272
return {};
272273
}
273274

274-
auto l = normalizeComponent(parseNextCSSValue<CSSPercentage>(parser, CSSDelimiter::Comma), 100.0f);
275+
auto l = normalizeComponent(parser.parseNextValue<CSSPercentage>(CSSDelimiter::Comma), 100.0f);
275276
if (!l.has_value()) {
276277
return {};
277278
}
278279

279-
auto a = normalizeComponent(parseNextCSSValue<CSSNumber, CSSPercentage>(parser, CSSDelimiter::Comma), 1.0f);
280+
auto a = normalizeComponent(parser.parseNextValue<CSSNumber, CSSPercentage>(CSSDelimiter::Comma), 1.0f);
280281

281282
auto [r, g, b] = hslToRgb(*h, *s, *l);
282283

@@ -293,25 +294,24 @@ inline std::optional<CSSColor> parseLegacyHslFunction(CSSSyntaxParser &parser)
293294
* it is valid. https://www.w3.org/TR/css-color-4/#typedef-modern-hsl-syntax
294295
*/
295296
template <typename CSSColor>
296-
inline std::optional<CSSColor> parseModernHslFunction(CSSSyntaxParser &parser)
297+
inline std::optional<CSSColor> parseModernHslFunction(CSSValueParser &parser)
297298
{
298-
auto h = normalizeHueComponent(parseNextCSSValue<CSSNumber, CSSAngle>(parser));
299+
auto h = normalizeHueComponent(parser.parseNextValue<CSSNumber, CSSAngle>());
299300
if (!h.has_value()) {
300301
return {};
301302
}
302303

303-
auto s = normalizeComponent(parseNextCSSValue<CSSNumber, CSSPercentage>(parser, CSSDelimiter::Whitespace), 100.0f);
304+
auto s = normalizeComponent(parser.parseNextValue<CSSNumber, CSSPercentage>(CSSDelimiter::Whitespace), 100.0f);
304305
if (!s.has_value()) {
305306
return {};
306307
}
307308

308-
auto l = normalizeComponent(parseNextCSSValue<CSSNumber, CSSPercentage>(parser, CSSDelimiter::Whitespace), 100.0f);
309+
auto l = normalizeComponent(parser.parseNextValue<CSSNumber, CSSPercentage>(CSSDelimiter::Whitespace), 100.0f);
309310
if (!l.has_value()) {
310311
return {};
311312
}
312313

313-
auto a =
314-
normalizeComponent(parseNextCSSValue<CSSNumber, CSSPercentage>(parser, CSSDelimiter::SolidusOrWhitespace), 1.0f);
314+
auto a = normalizeComponent(parser.parseNextValue<CSSNumber, CSSPercentage>(CSSDelimiter::SolidusOrWhitespace), 1.0f);
315315

316316
auto [r, g, b] = hslToRgb(*h, *s, *l);
317317

@@ -328,7 +328,7 @@ inline std::optional<CSSColor> parseModernHslFunction(CSSSyntaxParser &parser)
328328
* https://www.w3.org/TR/css-color-4/#funcdef-hsl
329329
*/
330330
template <typename CSSColor>
331-
inline std::optional<CSSColor> parseHslFunction(CSSSyntaxParser &parser)
331+
inline std::optional<CSSColor> parseHslFunction(CSSValueParser &parser)
332332
{
333333
if (isLegacyColorFunction<CSSNumber, CSSAngle>(parser)) {
334334
return parseLegacyHslFunction<CSSColor>(parser);
@@ -342,25 +342,24 @@ inline std::optional<CSSColor> parseHslFunction(CSSSyntaxParser &parser)
342342
* https://www.w3.org/TR/css-color-4/#funcdef-hwb
343343
*/
344344
template <typename CSSColor>
345-
inline std::optional<CSSColor> parseHwbFunction(CSSSyntaxParser &parser)
345+
inline std::optional<CSSColor> parseHwbFunction(CSSValueParser &parser)
346346
{
347-
auto h = normalizeHueComponent(parseNextCSSValue<CSSNumber, CSSAngle>(parser));
347+
auto h = normalizeHueComponent(parser.parseNextValue<CSSNumber, CSSAngle>());
348348
if (!h.has_value()) {
349349
return {};
350350
}
351351

352-
auto w = normalizeComponent(parseNextCSSValue<CSSNumber, CSSPercentage>(parser, CSSDelimiter::Whitespace), 100.0f);
352+
auto w = normalizeComponent(parser.parseNextValue<CSSNumber, CSSPercentage>(CSSDelimiter::Whitespace), 100.0f);
353353
if (!w.has_value()) {
354354
return {};
355355
}
356356

357-
auto b = normalizeComponent(parseNextCSSValue<CSSNumber, CSSPercentage>(parser, CSSDelimiter::Whitespace), 100.0f);
357+
auto b = normalizeComponent(parser.parseNextValue<CSSNumber, CSSPercentage>(CSSDelimiter::Whitespace), 100.0f);
358358
if (!b.has_value()) {
359359
return {};
360360
}
361361

362-
auto a =
363-
normalizeComponent(parseNextCSSValue<CSSNumber, CSSPercentage>(parser, CSSDelimiter::SolidusOrWhitespace), 1.0f);
362+
auto a = normalizeComponent(parser.parseNextValue<CSSNumber, CSSPercentage>(CSSDelimiter::SolidusOrWhitespace), 1.0f);
364363

365364
auto [red, green, blue] = hwbToRgb(*h, *w, *b);
366365

@@ -380,7 +379,7 @@ inline std::optional<CSSColor> parseHwbFunction(CSSSyntaxParser &parser)
380379
* https://www.w3.org/TR/css-color-4/#typedef-color-function
381380
*/
382381
template <typename CSSColor>
383-
constexpr std::optional<CSSColor> parseCSSColorFunction(std::string_view colorFunction, CSSSyntaxParser &parser)
382+
constexpr std::optional<CSSColor> parseCSSColorFunction(std::string_view colorFunction, CSSValueParser &parser)
384383
{
385384
switch (fnv1aLowercase(colorFunction)) {
386385
// CSS Color Module Level 4 treats the alpha variants of functions as the

packages/react-native/ReactCommon/react/renderer/css/CSSDataType.h

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
namespace facebook::react {
1818

19+
class CSSValueParser;
20+
1921
/**
2022
* May be specialized to instruct the CSS value parser how to parse a given data
2123
* type, according to CSSValidDataTypeParser.
@@ -24,37 +26,40 @@ template <typename CSSDataTypeT>
2426
struct CSSDataTypeParser {};
2527

2628
/**
27-
* Accepts a CSS function block and may parse it (and future syntax) into a
28-
* concrete representation.
29+
* Accepts a CSS function block and may parse it into a concrete representation.
30+
* The CSSValueParser provides methods for parsing sub-values within the
31+
* function block scope.
2932
*/
3033
template <typename T, typename ReturnT = std::any>
31-
concept CSSFunctionBlockSink = requires(const CSSFunctionBlock &func, CSSSyntaxParser &parser) {
34+
concept CSSFunctionBlockSink = requires(const CSSFunctionBlock &func, CSSValueParser &parser) {
3235
{ T::consumeFunctionBlock(func, parser) } -> std::convertible_to<ReturnT>;
3336
};
3437

3538
/**
36-
* Accepts a CSS simple block and may parse it (and future syntax) into a
37-
* concrete representation.
39+
* Accepts a CSS simple block and may parse it into a concrete representation.
40+
* The CSSValueParser provides methods for parsing sub-values within the
41+
* block scope.
3842
*/
3943
template <typename T, typename ReturnT = std::any>
40-
concept CSSSimpleBlockSink = requires(const CSSSimpleBlock &block, CSSSyntaxParser &parser) {
44+
concept CSSSimpleBlockSink = requires(const CSSSimpleBlock &block, CSSValueParser &parser) {
4145
{ T::consumeSimpleBlock(block, parser) } -> std::convertible_to<ReturnT>;
4246
};
4347

4448
/**
45-
* Accepts a CSS preserved token and may parse it (and future syntax) into a
46-
* concrete representation.
49+
* Accepts a CSS preserved token and may parse it into a concrete
50+
* representation.
4751
*/
4852
template <typename T, typename ReturnT = std::any>
4953
concept CSSPreservedTokenSink = requires(const CSSPreservedToken &token) {
5054
{ T::consumePreservedToken(token) } -> std::convertible_to<ReturnT>;
5155
};
5256

5357
/**
54-
* Accepts a raw syntax parser, to be able to parse compounded values
58+
* Accepts a CSSValueParser to be able to parse compounded values spanning
59+
* multiple component values.
5560
*/
5661
template <typename T, typename ReturnT = std::any>
57-
concept CSSParserSink = requires(CSSSyntaxParser &parser) {
62+
concept CSSParserSink = requires(CSSValueParser &parser) {
5863
{ T::consume(parser) } -> std::convertible_to<ReturnT>;
5964
};
6065

packages/react-native/ReactCommon/react/renderer/css/CSSFilter.h

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@ namespace detail {
2828
template <typename DataT, TemplateStringLiteral Name>
2929
requires(std::is_same_v<decltype(DataT::amount), float>)
3030
struct CSSFilterSimpleAmountParser {
31-
static constexpr auto consumeFunctionBlock(const CSSFunctionBlock &func, CSSSyntaxParser &parser)
31+
static constexpr auto consumeFunctionBlock(const CSSFunctionBlock &func, CSSValueParser &parser)
3232
-> std::optional<DataT>
3333
{
3434
if (!iequals(func.name, Name)) {
3535
return {};
3636
}
3737

38-
auto amount = parseNextCSSValue<CSSNumber, CSSPercentage>(parser);
38+
auto amount = parser.parseNextValue<CSSNumber, CSSPercentage>();
3939
if (std::holds_alternative<CSSNumber>(amount)) {
4040
if (std::get<CSSNumber>(amount).value < 0.0f) {
4141
return {};
@@ -65,14 +65,14 @@ struct CSSBlurFilter {
6565

6666
template <>
6767
struct CSSDataTypeParser<CSSBlurFilter> {
68-
static constexpr auto consumeFunctionBlock(const CSSFunctionBlock &func, CSSSyntaxParser &parser)
68+
static constexpr auto consumeFunctionBlock(const CSSFunctionBlock &func, CSSValueParser &parser)
6969
-> std::optional<CSSBlurFilter>
7070
{
7171
if (!iequals(func.name, "blur")) {
7272
return {};
7373
}
7474

75-
auto len = parseNextCSSValue<CSSLength>(parser);
75+
auto len = parser.parseNextValue<CSSLength>();
7676
return CSSBlurFilter{std::holds_alternative<CSSLength>(len) ? std::get<CSSLength>(len) : CSSLength{}};
7777
}
7878
};
@@ -123,7 +123,7 @@ struct CSSDropShadowFilter {
123123

124124
template <>
125125
struct CSSDataTypeParser<CSSDropShadowFilter> {
126-
static constexpr auto consumeFunctionBlock(const CSSFunctionBlock &func, CSSSyntaxParser &parser)
126+
static constexpr auto consumeFunctionBlock(const CSSFunctionBlock &func, CSSValueParser &parser)
127127
-> std::optional<CSSDropShadowFilter>
128128
{
129129
if (!iequals(func.name, "drop-shadow")) {
@@ -133,7 +133,7 @@ struct CSSDataTypeParser<CSSDropShadowFilter> {
133133
std::optional<CSSColor> color{};
134134
std::optional<std::array<CSSLength, 3>> lengths{};
135135

136-
auto firstVal = parseNextCSSValue<CSSColor, CSSLength>(parser);
136+
auto firstVal = parser.parseNextValue<CSSColor, CSSLength>();
137137
if (std::holds_alternative<std::monostate>(firstVal)) {
138138
return {};
139139
}
@@ -147,7 +147,7 @@ struct CSSDataTypeParser<CSSDropShadowFilter> {
147147
}
148148
}
149149

150-
auto secondVal = parseNextCSSValue<CSSColor, CSSLength>(parser, CSSDelimiter::Whitespace);
150+
auto secondVal = parser.parseNextValue<CSSColor, CSSLength>(CSSDelimiter::Whitespace);
151151
if (std::holds_alternative<CSSColor>(secondVal)) {
152152
if (color.has_value()) {
153153
return {};
@@ -173,14 +173,14 @@ struct CSSDataTypeParser<CSSDropShadowFilter> {
173173
}
174174

175175
private:
176-
static constexpr std::optional<std::array<CSSLength, 3>> parseLengths(CSSLength offsetX, CSSSyntaxParser &parser)
176+
static constexpr std::optional<std::array<CSSLength, 3>> parseLengths(CSSLength offsetX, CSSValueParser &parser)
177177
{
178-
auto offsetY = parseNextCSSValue<CSSLength>(parser, CSSDelimiter::Whitespace);
178+
auto offsetY = parser.parseNextValue<CSSLength>(CSSDelimiter::Whitespace);
179179
if (!std::holds_alternative<CSSLength>(offsetY)) {
180180
return {};
181181
}
182182

183-
auto standardDeviation = parseNextCSSValue<CSSLength>(parser, CSSDelimiter::Whitespace);
183+
auto standardDeviation = parser.parseNextValue<CSSLength>(CSSDelimiter::Whitespace);
184184
if (std::holds_alternative<CSSLength>(standardDeviation) && std::get<CSSLength>(standardDeviation).value < 0.0f) {
185185
return {};
186186
}
@@ -220,14 +220,14 @@ struct CSSHueRotateFilter {
220220

221221
template <>
222222
struct CSSDataTypeParser<CSSHueRotateFilter> {
223-
static constexpr auto consumeFunctionBlock(const CSSFunctionBlock &func, CSSSyntaxParser &parser)
223+
static constexpr auto consumeFunctionBlock(const CSSFunctionBlock &func, CSSValueParser &parser)
224224
-> std::optional<CSSHueRotateFilter>
225225
{
226226
if (!iequals(func.name, "hue-rotate")) {
227227
return {};
228228
}
229229

230-
auto angle = parseNextCSSValue<CSSAngle, CSSZero>(parser);
230+
auto angle = parser.parseNextValue<CSSAngle, CSSZero>();
231231
return CSSHueRotateFilter{std::holds_alternative<CSSAngle>(angle) ? std::get<CSSAngle>(angle).degrees : 0.0f};
232232
}
233233
};

0 commit comments

Comments
 (0)