TextKit 2 Background drawing incorrect

Hi

I am drawing TextKit2 managed NSAttributedStrings into a NSBitmapImageRep successfully, enumerating the Text Layout Fragments is giving me bogus background drawing

This is the core drawing code, its pretty simple: I manage the flipped property myself since NSTextLayoutManager assumes a flipped coordinate.

  if let context = NSGraphicsContext(bitmapImageRep: self.textImageRep!)
        {
            NSGraphicsContext.current = context
            
            let rect = NSRect(origin: .zero, size: self.outputSize)
            NSColor.clear.set()
            rect.fill()
            
            // Flip the context
            context.cgContext.saveGState()
            
            context.cgContext.translateBy(x: 0, y: self.outputSize.height)
            context.cgContext.scaleBy(x: 1.0, y: -1.0)

            let textOrigin = CGPoint(x: 0.0, y: 0.0 )
            
            let titleRect = CGRect(origin: textOrigin, size: self.themeTextContainer.size)
            NSColor.orange.withAlphaComponent(1).set()
            titleRect.fill()

            self.layoutManager.enumerateTextLayoutFragments(from: nil, using: { textLayoutFragment in

                // Get the fragment's rendering bounds
                let fragmentBounds = textLayoutFragment.layoutFragmentFrame

                print("fragmentBounds: \(fragmentBounds)")
                // Render the fragment into the context
                
                textLayoutFragment.draw(at: fragmentBounds.origin, in: context.cgContext)
                
                return true
            })
           
            context.cgContext.restoreGState()
        }
        
        NSGraphicsContext.restoreGraphicsState()

I have a mutable string which has various paragraph styles which I add to the layout manager / text storage like so

 let titleParagraphStyle = NSMutableParagraphStyle()
        titleParagraphStyle.alignment = .center
        titleParagraphStyle.lineBreakMode = .byWordWrapping
        titleParagraphStyle.lineBreakStrategy = .standard
        
        var range = NSMakeRange(0, self.attributedProgrammingBlockTitle.length)
        self.attributedProgrammingBlockTitle.addAttribute(.foregroundColor, value: NSColor(red: 243.0/255.0, green: 97.0/255.0, blue: 97.0/255.0, alpha: 1.0), range:range)
        self.attributedProgrammingBlockTitle.addAttribute(.backgroundColor, value: NSColor.cyan, range:range)
        self.attributedProgrammingBlockTitle.addAttribute(.font, value: NSFont.systemFont(ofSize: 64), range:range)
        self.attributedProgrammingBlockTitle.addAttribute(.paragraphStyle, value:titleParagraphStyle, range:range)

        range = NSMakeRange(0, self.attributedThemeTitle.length)
        self.attributedThemeTitle.addAttribute(.foregroundColor, value: NSColor.white, range:range )
        self.attributedThemeTitle.addAttribute(.backgroundColor, value: NSColor.purple, range:range)
        self.attributedThemeTitle.addAttribute(.font, value: NSFont.systemFont(ofSize: 48), range:range)
        self.attributedThemeTitle.addAttribute(.paragraphStyle, value:NSParagraphStyle.default, range:range)

        range = NSMakeRange(0, self.attributedText.length)
        self.attributedText.addAttribute(.foregroundColor, value: NSColor.white, range:range )
        self.attributedText.addAttribute(.backgroundColor, value: NSColor.yellow, range:range)
        self.attributedText.addAttribute(.font, value: NSFont.systemFont(ofSize: 36), range:range)
        self.attributedText.addAttribute(.paragraphStyle, value:NSParagraphStyle.default, range:range)

        let allText = NSMutableAttributedString()
        
        allText.append(self.attributedProgrammingBlockTitle)
        allText.append(NSAttributedString(string: "\n\r"))
        allText.append(self.attributedThemeTitle)
        allText.append(NSAttributedString(string: "\n\r"))
        allText.append(self.attributedText)

        
        self.textStorage.textStorage?.beginEditing()
        self.textStorage.textStorage?.setAttributedString(allText)
        self.textStorage.textStorage?.endEditing()

        self.layoutManager.ensureLayout(for: self.layoutManager.documentRange)

however, i get incorrect drawing for the background color font attributes. Its origin is zero, and not correctly aligned at all with the text.

How can I get correct rendering of backgrounds from TextKit2?

Here is an image of my output:

Answered by DTS Engineer in 822556022

You might want to look at the following sample:

The sample demonstrates how to set up a TextKit 2 stack and draw text to layers (CALayer). From there, you should be able to render a layer to a bitmap context by calling CALayer.render(in:).

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

You might want to look at the following sample:

The sample demonstrates how to set up a TextKit 2 stack and draw text to layers (CALayer). From there, you should be able to render a layer to a bitmap context by calling CALayer.render(in:).

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

hi. Ive looked at that sample, and while I could refactor my drawing code to use CALayers, it's really not pertinent given my current pipeline.

Are the attributes for background simply not supported in TextKit 2?

Are the attributes for background simply not supported in TextKit 2?

The background does appear in your screenshot; it is just that the position, or layout, isn't right.

Simply calling textLayoutFragment.draw is not enough to render the text, because the process of laying out the text relies on the coordinate system of the text container and the delegate methods. If you set up a whole TextKit 2 stack, as demonstrated in the mentioned sample, and the issue is still there, please provide a minimal project and I'd be interested in taking a closer look.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

TextKit 2 Background drawing incorrect
 
 
Q