boundingRectWithSize returning different values for macOS on Catalina 10.15, XCode 11

Hello,


As of Catalina (10.15.2 for this writing) and XCode 11 (11.3 11C29), the function boundingRectWithSize in AppKit is returning a different value than in previous versions of XCode. I don't see any explanation within the various release notes for this change. Unfortunately, this is impacting previous UI layouts, designs, and constraints for existing applications. At first, I thought it might be a difference between the now deprecated function and the new API, however both return the same results across all tests. Another thought was that perhaps light and dark modes were impacting the fonts rendering, but this also appeared to be a non-factor. Additionally, this appears to affect all fonts and font sizes, but these differences are not a common ratio. Additionally, using the latest API's NSStringDrawingContext, there are no differences between the dimensions of the drawingContext.totalBounds and the boundingRect either. Both are returning the same result, which is different between Xcode 10 and Xcode 11.


Is this a bug or regression? Or is this a known, documented change? What is the recommended approach to handle and account for this difference?


The code used for the test (latest API, not deprecated):


- (void)testBoundingRect {
    NSString* string = @"The quick brown fox jumps over the lazy dog";
    NSFont* font = [NSFont fontWithName:@"Tahoma" size:17];
   
    NSDictionary *stringAttributes =
    [NSDictionary dictionaryWithObjectsAndKeys:
     font, NSFontAttributeName,
     [NSColor textColor], NSForegroundColorAttributeName,
     nil];
   
    NSSize maxSize = NSMakeSize(CGFLOAT_MAX, 0.0);
   
    // Latest API
    NSStringDrawingContext *drawingContext = [[NSStringDrawingContext alloc] init];
    NSRect boundingRect =
        [string boundingRectWithSize:maxSize
                             options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
                          attributes:stringAttributes
                             context:drawingContext];
   
    NSLog(@"Height: %f", boundingRect.size.height);
//    XCTAssert(boundingRect.size.height == 26); // Expected (MacOS 10.14-, XC 10.3-)
//    XCTAssert(boundingRect.size.height == 21); // Actual (MacOS 10.15, XC 11+)
    NSLog(@"Height: %f", drawingContext.totalBounds.size.height);
//    XCTAssert(drawingContext.totalBounds.size.height == 26); // Expected (MacOS 10.14-, XC 10.3-)
//    XCTAssert(drawingContext.totalBounds.size.height == 21); // Actual (MacOS 10.15, XC 11+)
}

The results:


XC 9.4.1 (Mojave) Target API 10.13

XC 10.3 (Mojave) Target API 10.13

XC 10.3 (Mojave) Target API 10.14

XC 10.3 (Catalina) Target API 10.13

XC 10.3 (Catalina) Target API 10.14

XC 11.3 (Catalina) Target API 10.14

XC 11.3 (Catalina) Target API 10.15

Light Mode








boundingRect.size.height

26

26

26

26

26

21

21









Dark Mode








boundingRect.size.height

26

26

26

26

26

21

21

Replies

Hi @taylor211. Did you ever find an answer or workaround to this? I have the same issue, and am not looking forward to coming up with a workaround.

Not sure what attributes you're using, but it seems to be ignoring, or perhaps a different defaulting, of line heights.

I will add however that it is not specifically Xcode 11. If you set the target platform to a minimum of macOS 10.13 in Xcode 11, you will get the original behaviour, even on 10.14 and 10.15. Change it to a minimum of 10.14, and you once again get the new changed behaviour. To me this sounds like the 10.14+ libraries are the issue.
I fixed this problem by adding an explicit lineHeightMultiple (in my case varying from 1.0-1.2), in the paragraph style (that I had already added) spanning the entire attributed string, instead of letting lineHeightMultiple default.
Hi,

There was a documented change to the default typesetter behavior in macOS 10.14 that affects apps under the following conditions:
  1. Compiled with 10.14 SDK or later

  2. Deployment target of 10.14 or later

This typesetter behavior change corrects a long-standing floating-point rounding error that resulted in an extra pixel being added to the default ascender, so text might now measure 1 point smaller than it did previously.

The 5 point difference you're seeing here does seem larger than expected, and that could be a bug. Could you please file a bug for the typesetter via the feedback assistant?