Skip to content

Commit 62fd7a1

Browse files
NickGerlemanmeta-codesync[bot]
authored andcommitted
Wire native CSS parsing for fontVariant (#55684)
Summary: Pull Request resolved: #55684 Gate `processFontVariant` behind `enableNativeCSSParsing()`. When the flag is on, CSS font-variant strings like `"small-caps oldstyle-nums"` are parsed natively using the existing CSS font-variant parser instead of being preprocessed in JS. Also removes `react_native_expect(false)` hard error on unknown font variant values, replacing it with a graceful skip. Changelog: [Internal] Reviewed By: jorge-cab Differential Revision: D94052733 fbshipit-source-id: 160f8d97723e42aa9d63b868df84dcd68fca9a2f
1 parent df5d42e commit 62fd7a1

File tree

3 files changed

+128
-3
lines changed

3 files changed

+128
-3
lines changed

packages/react-native/Libraries/Components/View/ReactNativeStyleAttributes.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ export const aspectRatioAttribute: AnyAttributeType = nativeCSSParsing
7171
? true
7272
: {process: processAspectRatio};
7373

74+
export const fontVariantAttribute: AnyAttributeType = nativeCSSParsing
75+
? true
76+
: {process: processFontVariant};
77+
7478
const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = {
7579
/**
7680
* Layout
@@ -252,7 +256,7 @@ const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = {
252256
fontFamily: true,
253257
fontSize: true,
254258
fontStyle: true,
255-
fontVariant: {process: processFontVariant},
259+
fontVariant: fontVariantAttribute,
256260
fontWeight: true,
257261
includeFontPadding: true,
258262
letterSpacing: true,

packages/react-native/ReactCommon/react/renderer/attributedstring/conversions.h

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include <folly/dynamic.h>
1111
#include <react/debug/react_native_expect.h>
12+
#include <react/featureflags/ReactNativeFeatureFlags.h>
1213
#include <react/renderer/attributedstring/AttributedString.h>
1314
#include <react/renderer/attributedstring/ParagraphAttributes.h>
1415
#include <react/renderer/attributedstring/TextAttributes.h>
@@ -21,6 +22,8 @@
2122
#include <react/renderer/core/conversions.h>
2223
#include <react/renderer/core/graphicsConversions.h>
2324
#include <react/renderer/core/propsConversions.h>
25+
#include <react/renderer/css/CSSFontVariant.h>
26+
#include <react/renderer/css/CSSValueParser.h>
2427
#include <unordered_map>
2528

2629
#ifdef RN_SERIALIZABLE_STATE
@@ -317,7 +320,66 @@ inline std::string toString(const FontStyle &fontStyle)
317320
return "normal";
318321
}
319322

320-
inline void fromRawValue(const PropsParserContext &context, const RawValue &value, FontVariant &result)
323+
inline std::optional<FontVariant> fontVariantFromCSSFontVariant(CSSFontVariant cssVariant)
324+
{
325+
switch (cssVariant) {
326+
case CSSFontVariant::SmallCaps:
327+
return FontVariant::SmallCaps;
328+
case CSSFontVariant::OldstyleNums:
329+
return FontVariant::OldstyleNums;
330+
case CSSFontVariant::LiningNums:
331+
return FontVariant::LiningNums;
332+
case CSSFontVariant::TabularNums:
333+
return FontVariant::TabularNums;
334+
case CSSFontVariant::ProportionalNums:
335+
return FontVariant::ProportionalNums;
336+
case CSSFontVariant::StylisticOne:
337+
return FontVariant::StylisticOne;
338+
case CSSFontVariant::StylisticTwo:
339+
return FontVariant::StylisticTwo;
340+
case CSSFontVariant::StylisticThree:
341+
return FontVariant::StylisticThree;
342+
case CSSFontVariant::StylisticFour:
343+
return FontVariant::StylisticFour;
344+
case CSSFontVariant::StylisticFive:
345+
return FontVariant::StylisticFive;
346+
case CSSFontVariant::StylisticSix:
347+
return FontVariant::StylisticSix;
348+
case CSSFontVariant::StylisticSeven:
349+
return FontVariant::StylisticSeven;
350+
case CSSFontVariant::StylisticEight:
351+
return FontVariant::StylisticEight;
352+
case CSSFontVariant::StylisticNine:
353+
return FontVariant::StylisticNine;
354+
case CSSFontVariant::StylisticTen:
355+
return FontVariant::StylisticTen;
356+
case CSSFontVariant::StylisticEleven:
357+
return FontVariant::StylisticEleven;
358+
case CSSFontVariant::StylisticTwelve:
359+
return FontVariant::StylisticTwelve;
360+
case CSSFontVariant::StylisticThirteen:
361+
return FontVariant::StylisticThirteen;
362+
case CSSFontVariant::StylisticFourteen:
363+
return FontVariant::StylisticFourteen;
364+
case CSSFontVariant::StylisticFifteen:
365+
return FontVariant::StylisticFifteen;
366+
case CSSFontVariant::StylisticSixteen:
367+
return FontVariant::StylisticSixteen;
368+
case CSSFontVariant::StylisticSeventeen:
369+
return FontVariant::StylisticSeventeen;
370+
case CSSFontVariant::StylisticEighteen:
371+
return FontVariant::StylisticEighteen;
372+
case CSSFontVariant::StylisticNineteen:
373+
return FontVariant::StylisticNineteen;
374+
case CSSFontVariant::StylisticTwenty:
375+
return FontVariant::StylisticTwenty;
376+
default:
377+
// Ligature variants (CommonLigatures, etc.) have no FontVariant equivalent
378+
return std::nullopt;
379+
}
380+
}
381+
382+
inline void parseProcessedFontVariant(const PropsParserContext &context, const RawValue &value, FontVariant &result)
321383
{
322384
result = FontVariant::Default;
323385
react_native_expect(value.hasType<std::vector<std::string>>());
@@ -376,14 +438,47 @@ inline void fromRawValue(const PropsParserContext &context, const RawValue &valu
376438
result = (FontVariant)((int)result | (int)FontVariant::StylisticTwenty);
377439
} else {
378440
LOG(ERROR) << "Unsupported FontVariant value: " << item;
379-
react_native_expect(false);
380441
}
381442
}
382443
} else {
383444
LOG(ERROR) << "Unsupported FontVariant type";
384445
}
385446
}
386447

448+
inline void parseUnprocessedFontVariantString(const std::string &value, FontVariant &result)
449+
{
450+
auto fontVariantList = parseCSSProperty<CSSFontVariantList>(value);
451+
if (!std::holds_alternative<CSSFontVariantList>(fontVariantList)) {
452+
result = FontVariant::Default;
453+
return;
454+
}
455+
456+
result = FontVariant::Default;
457+
for (const auto &cssVariant : std::get<CSSFontVariantList>(fontVariantList)) {
458+
if (auto fv = fontVariantFromCSSFontVariant(cssVariant)) {
459+
result = (FontVariant)((int)result | (int)*fv);
460+
}
461+
}
462+
}
463+
464+
inline void parseUnprocessedFontVariant(const PropsParserContext &context, const RawValue &value, FontVariant &result)
465+
{
466+
if (value.hasType<std::string>()) {
467+
parseUnprocessedFontVariantString((std::string)value, result);
468+
} else {
469+
parseProcessedFontVariant(context, value, result);
470+
}
471+
}
472+
473+
inline void fromRawValue(const PropsParserContext &context, const RawValue &value, FontVariant &result)
474+
{
475+
if (ReactNativeFeatureFlags::enableNativeCSSParsing()) {
476+
parseUnprocessedFontVariant(context, value, result);
477+
} else {
478+
parseProcessedFontVariant(context, value, result);
479+
}
480+
}
481+
387482
inline std::string toString(const FontVariant &fontVariant)
388483
{
389484
auto result = std::string{};

packages/react-native/ReactCommon/react/renderer/components/view/tests/ConversionsTest.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include <gtest/gtest.h>
99

10+
#include <react/renderer/attributedstring/conversions.h>
1011
#include <react/renderer/components/view/BoxShadowPropsConversions.h>
1112
#include <react/renderer/components/view/FilterPropsConversions.h>
1213
#include <react/renderer/components/view/conversions.h>
@@ -514,4 +515,29 @@ TEST(ConversionsTest, float_optional_undefined_for_string) {
514515
EXPECT_TRUE(result.isUndefined());
515516
}
516517

518+
TEST(ConversionsTest, unprocessed_font_variant_string_single) {
519+
FontVariant result;
520+
parseUnprocessedFontVariantString("small-caps", result);
521+
522+
EXPECT_EQ((int)result, (int)FontVariant::SmallCaps);
523+
}
524+
525+
TEST(ConversionsTest, unprocessed_font_variant_string_multiple) {
526+
FontVariant result;
527+
parseUnprocessedFontVariantString(
528+
"small-caps oldstyle-nums tabular-nums", result);
529+
530+
EXPECT_EQ(
531+
(int)result,
532+
(int)FontVariant::SmallCaps | (int)FontVariant::OldstyleNums |
533+
(int)FontVariant::TabularNums);
534+
}
535+
536+
TEST(ConversionsTest, unprocessed_font_variant_string_invalid) {
537+
FontVariant result;
538+
parseUnprocessedFontVariantString("not-a-variant", result);
539+
540+
EXPECT_EQ((int)result, (int)FontVariant::Default);
541+
}
542+
517543
} // namespace facebook::react

0 commit comments

Comments
 (0)