diff --git a/packages/react-native/React/Tests/Text/RCTAttributedTextUtilsTest.mm b/packages/react-native/React/Tests/Text/RCTAttributedTextUtilsTest.mm index 902f61e11ed1..26ffe6bbd79a 100644 --- a/packages/react-native/React/Tests/Text/RCTAttributedTextUtilsTest.mm +++ b/packages/react-native/React/Tests/Text/RCTAttributedTextUtilsTest.mm @@ -12,6 +12,7 @@ #include #include +#include using namespace facebook::react; @@ -45,6 +46,70 @@ - (void)testTextAlignmentStartAndEndResolveWithLayoutDirection XCTAssertEqual(NSTextAlignmentFromTextAlign(@"end", LayoutDirection::RightToLeft), NSTextAlignmentLeft); } +- (void)testDefaultClearBackgroundIsOmitted +{ + TextAttributes textAttributes = TextAttributes::defaultTextAttributes(); + + NSDictionary *attributes = RCTNSTextAttributesFromTextAttributes(textAttributes); + + XCTAssertNil(attributes[NSBackgroundColorAttributeName]); + XCTAssertEqualObjects(attributes[NSForegroundColorAttributeName], [UIColor colorWithRed:0 green:0 blue:0 alpha:1]); +} + +- (void)testOpacityDoesNotAddBackgroundColor +{ + TextAttributes textAttributes; + textAttributes.opacity = 0.5; + + NSDictionary *attributes = RCTNSTextAttributesFromTextAttributes(textAttributes); + + XCTAssertNil(attributes[NSBackgroundColorAttributeName]); + XCTAssertEqualObjects(attributes[NSForegroundColorAttributeName], [UIColor colorWithWhite:0 alpha:0.5]); +} + +- (void)testDefaultClearBackgroundWithOpacityIsOmitted +{ + TextAttributes textAttributes = TextAttributes::defaultTextAttributes(); + textAttributes.opacity = 0.5; + + NSDictionary *attributes = RCTNSTextAttributesFromTextAttributes(textAttributes); + + XCTAssertNil(attributes[NSBackgroundColorAttributeName]); + XCTAssertEqualObjects(attributes[NSForegroundColorAttributeName], [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5]); +} + +- (void)testVisibleBackgroundColorPreservesAlphaWithOpacity +{ + TextAttributes textAttributes; + textAttributes.backgroundColor = colorFromComponents({.red = 1, .alpha = 0.5, .colorSpace = ColorSpace::sRGB}); + + NSDictionary *attributes = RCTNSTextAttributesFromTextAttributes(textAttributes); + + XCTAssertEqualObjects(attributes[NSBackgroundColorAttributeName], [UIColor colorWithRed:1 green:0 blue:0 alpha:0.5]); + + textAttributes.opacity = 0.5; + attributes = RCTNSTextAttributesFromTextAttributes(textAttributes); + + XCTAssertEqualObjects(attributes[NSBackgroundColorAttributeName], [UIColor colorWithRed:1 green:0 blue:0 alpha:0.25]); +} + +- (void)testForegroundColorPreservesAlphaWithOpacity +{ + TextAttributes textAttributes = TextAttributes::defaultTextAttributes(); + textAttributes.foregroundColor = colorFromComponents({.blue = 1, .alpha = 0.5, .colorSpace = ColorSpace::sRGB}); + + NSDictionary *attributes = RCTNSTextAttributesFromTextAttributes(textAttributes); + + XCTAssertNil(attributes[NSBackgroundColorAttributeName]); + XCTAssertEqualObjects(attributes[NSForegroundColorAttributeName], [UIColor colorWithRed:0 green:0 blue:1 alpha:0.5]); + + textAttributes.opacity = 0.5; + attributes = RCTNSTextAttributesFromTextAttributes(textAttributes); + + XCTAssertNil(attributes[NSBackgroundColorAttributeName]); + XCTAssertEqualObjects(attributes[NSForegroundColorAttributeName], [UIColor colorWithRed:0 green:0 blue:1 alpha:0.25]); +} + - (void)testSamenessOfEmptyAttributedStrings { NSAttributedString *attributedString1 = [[NSAttributedString alloc] initWithString:@""]; diff --git a/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm b/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm index 9e1b3e6dde85..9840d2155b3f 100644 --- a/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm +++ b/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm @@ -200,7 +200,8 @@ inline static CGFloat RCTEffectiveFontSizeMultiplierFromTextAttributes(const Tex attributes[NSForegroundColorAttributeName] = effectiveForegroundColor; } - if (textAttributes.backgroundColor || !isnan(textAttributes.opacity)) { + // A clear background draws nothing, but TextKit still computes and fills its rects on every draw. + if (textAttributes.backgroundColor && textAttributes.backgroundColor != clearColor()) { attributes[NSBackgroundColorAttributeName] = RCTEffectiveBackgroundColorFromTextAttributes(textAttributes); }