CTRunGetImageBounds returns bounds with a wrong x origin

Originator:st
Number:rdar://33251252 Date Originated:July 12 2017
Status:Closed Resolved:Yes
Product:CoreText Product Version:iOS < 11 Beta 4
Classification: Reproducible:Always
 
CTRunGetImageBounds is documented in the header to return the bounds for the  "union of all non-empty glyph bounding rects, each positioned as it would be if drawn using CTRunDraw using the current context. " However, the bounds calculated by CTRunGetImageBounds do not account for the offset of the CTRun within the CTLine, even though CTRunDraw does add this offset to the text position. 

Steps to Reproduce:
Copy and paste the following Swift code into an Xcode 9 playground, run it and enable the live view (in the assistant editor).


import UIKit
import CoreText

let font = UIFont.systemFont(ofSize: 20)

let string = NSMutableAttributedString(
               string: "x", attributes: [.font: font,
                                         .foregroundColor: UIColor.red])
string.append(NSAttributedString(
                string: "x", attributes: [.font: font,
                                          .foregroundColor: UIColor.black]))

let line = CTLineCreateWithAttributedString(string)

let size = CGSize(width: 100, height: 50)
let image = UIGraphicsImageRenderer(size: size).image { ctx in
  UIColor.white.setFill()
  ctx.fill(CGRect(origin: .zero, size: size))

  ctx.cgContext.translateBy(x: 0, y: 30)
  ctx.cgContext.scaleBy(x: 1, y: -1)

  let runs = CTLineGetGlyphRuns(line) as! [CTRun]

  ctx.cgContext.textPosition = CGPoint(x: 0, y: 0)
  print(CTRunGetImageBounds(runs[0], ctx.cgContext, CFRange()))
  CTRunDraw(runs[0], ctx.cgContext, CFRange())

  ctx.cgContext.textPosition = CGPoint(x: 0, y: 0)
  print(CTRunGetImageBounds(runs[1], ctx.cgContext, CFRange()))
  CTRunDraw(runs[1], ctx.cgContext, CFRange())
}

import PlaygroundSupport
PlaygroundPage.current.liveView =  UIImageView(image: image)

Expected Results:
The printed image bounds (see the output at the bottom) for the two runs should have different x coordinates, since they are drawn at different positions.

Observed Results:
The printed image bounds for the two runs are identical, which suggests that the bounds for the second run do not reflect the x-offset of the run within the line.

Comments

The bug was fixed within a few days and in time for iOS 11 Beta 4!


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!