diff --git a/Frameworks/UIKit/NSString+UIKitAdditions.mm b/Frameworks/UIKit/NSString+UIKitAdditions.mm index 891a6b7b6e..95e1105885 100644 --- a/Frameworks/UIKit/NSString+UIKitAdditions.mm +++ b/Frameworks/UIKit/NSString+UIKitAdditions.mm @@ -244,6 +244,11 @@ - (CGSize)drawAtPoint:(CGPoint)point // Returns the bounding box size this string would occupy when drawn as specified // All sizeWith... functions in this file funnel to this - (CGSize)_sizeWithAttributes:(NSDictionary*)attributes constrainedToSize:(CGSize)size { + UIFont* font = attributes[NSFontAttributeName]; + if (font == nil) { + return CGSizeZero; + } + if ([attributes objectForKey:NSParagraphStyleAttributeName]) { NSMutableDictionary* copied = [NSMutableDictionary dictionaryWithDictionary:attributes]; woc::unique_cf @@ -263,7 +268,13 @@ - (CGSize)_sizeWithAttributes:(NSDictionary*)attributes constrain size.height = std::numeric_limits::max(); } - return CTFramesetterSuggestFrameSizeWithConstraints(framesetter.get(), CFRangeMake(0, self.length), nullptr, size, nullptr); + CGSize ret = CTFramesetterSuggestFrameSizeWithConstraints(framesetter.get(), CFRangeMake(0, self.length), nullptr, size, nullptr); + + // If the constrained height is less than a line height sizeWithFont will increase the returned size to fit at least one line + CGFloat lineHeight = [font ascender] - [font descender]; + ret.height = std::max(ret.height, lineHeight); + + return ret; } // Private helper that converts a UILineBreakMode -> NSParagraphStyle diff --git a/tests/unittests/UIKit/NSString+UIKitAdditionsTests.mm b/tests/unittests/UIKit/NSString+UIKitAdditionsTests.mm index 7c15abdab2..1b9bd25667 100644 --- a/tests/unittests/UIKit/NSString+UIKitAdditionsTests.mm +++ b/tests/unittests/UIKit/NSString+UIKitAdditionsTests.mm @@ -16,10 +16,28 @@ #import #import +#import +static constexpr double c_errorDelta = .0001; TEST(NSString_UIKitAdditions, ShouldNotReturnSizeOfZeroWidth) { CGSize size = [@"TEST" sizeWithFont:[UIFont systemFontOfSize:12.0f] constrainedToSize:CGSizeZero lineBreakMode:NSLineBreakByWordWrapping]; EXPECT_LT(0.0, size.width); EXPECT_LT(0.0, size.height); +} + +TEST(NSString_UIKitAdditions, SizeWithFontShouldReturnLineHeightWhenConstrainedHeightIsTooSmall) { + CGSize givenSize = { 0, 15 }; + UIFont* font = [UIFont systemFontOfSize:144]; + CGFloat lineHeight = [font ascender] - [font descender]; + CGSize size = [@"TEST" sizeWithFont:font constrainedToSize:givenSize]; + EXPECT_NEAR(lineHeight, size.height, c_errorDelta); + + size = [@"TEST\nTEST" sizeWithFont:font constrainedToSize:givenSize]; + EXPECT_NEAR(lineHeight, size.height, c_errorDelta); +} + +TEST(NSString_UIKitAdditions, SizeWithNoFontShouldReturnCGSizeZero) { + CGSize arbitrarySize = { 100, 150 }; + EXPECT_EQ(CGSizeZero, [@"TEST" sizeWithFont:nil constrainedToSize:arbitrarySize]); } \ No newline at end of file