Skip to content

Commit

Permalink
Revised logic for exact text background calculations (#278)
Browse files Browse the repository at this point in the history
  • Loading branch information
rajdeep authored Feb 19, 2024
1 parent 3d00fe0 commit adf90db
Show file tree
Hide file tree
Showing 43 changed files with 96 additions and 10 deletions.
48 changes: 39 additions & 9 deletions Proton/Sources/Swift/Core/LayoutManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,22 @@ class LayoutManager: NSLayoutManager {
return stringRect
}

override func drawsOutsideLineFragment(forGlyphAt glyphIndex: Int) -> Bool {
true
}

var hasLineSpacing: Bool {
var lineCount = 0
guard let textStorage else { return false}
enumerateLineFragments(forGlyphRange: textStorage.fullRange, using: { _, _, _, _, stop in
lineCount += 1
if lineCount > 1 {
stop.pointee = true
}
})
return lineCount > 1 || (lineCount > 0 && extraLineFragmentRect.height > 0)
}

override func drawBackground(forGlyphRange glyphsToShow: NSRange, at origin: CGPoint) {
super.drawBackground(forGlyphRange: glyphsToShow, at: origin)
guard let textStorage = textStorage,
Expand All @@ -308,13 +324,12 @@ class LayoutManager: NSLayoutManager {
var rects = [CGRect]()
if let backgroundStyle = attr as? BackgroundStyle {
let bgStyleGlyphRange = self.glyphRange(forCharacterRange: bgStyleRange, actualCharacterRange: nil)
enumerateLineFragments(forGlyphRange: bgStyleGlyphRange) { _, usedRect, textContainer, lineRange, _ in
let usedRect = usedRect.integral
enumerateLineFragments(forGlyphRange: bgStyleGlyphRange) { rect1, usedRect, textContainer, lineRange, _ in
let rangeIntersection = NSIntersectionRange(bgStyleGlyphRange, lineRange)
let paragraphStyle = textStorage.attribute(.paragraphStyle, at: rangeIntersection.location, effectiveRange: nil) as? NSParagraphStyle ?? self.defaultParagraphStyle
let font = textStorage.attribute(.font, at: rangeIntersection.location, effectiveRange: nil) as? UIFont ?? self.defaultFont
let lineHeightMultiple = max(paragraphStyle.lineHeightMultiple, 1)
var rect = self.boundingRect(forGlyphRange: rangeIntersection, in: textContainer).integral
var rect = self.boundingRect(forGlyphRange: rangeIntersection, in: textContainer)
let lineHeightMultipleOffset = (rect.size.height - rect.size.height/lineHeightMultiple)
let lineSpacing = paragraphStyle.lineSpacing
if backgroundStyle.widthMode == .matchText {
Expand All @@ -323,12 +338,25 @@ class LayoutManager: NSLayoutManager {
rect.size.width = contentWidth
}

let inset = self.layoutManagerDelegate?.textContainerInset ?? .zero
switch backgroundStyle.heightMode {
case .matchTextExact:
rect.origin.y = usedRect.origin.y - (font.pointSize - font.ascender)
rect.origin.y += (font.ascender - font.capHeight)
rect.size.height = font.capHeight + abs(font.descender)
let styledText = textStorage.attributedSubstring(from: bgStyleGlyphRange)
var textRect = styledText.boundingRect(with: rect.size, options: [.usesFontLeading, .usesDeviceMetrics], context: nil)
textRect.origin = rect.origin
textRect.size.width = rect.width

textRect.origin.y += abs(font.descender)

let delta = usedRect.height - (font.lineHeight + font.leading)
textRect.origin.y += delta
let hasLineSpacing = (usedRect.height - font.lineHeight) == paragraphStyle.lineSpacing
let isExtraLineHeight = ((usedRect.height - font.lineHeight) - font.leading) > 0.001

if hasLineSpacing || isExtraLineHeight {
textRect.origin.y -= (paragraphStyle.lineSpacing - font.leading)
}

rect = textRect
case .matchText:
let styledText = textStorage.attributedSubstring(from: bgStyleGlyphRange)
let textRect = styledText.boundingRect(with: rect.size, options: .usesFontLeading, context: nil)
Expand All @@ -342,8 +370,10 @@ class LayoutManager: NSLayoutManager {
rect.size.height = usedRect.height
}


rects.append(rect.offsetBy(dx: inset.left, dy: inset.top))
// if lineRange.endLocation == textStorage.length, font.leading == 0 {
// rect.origin.y += abs(font.descender/2)
// }
rects.append(rect.offsetBy(dx: origin.x, dy: origin.y))
}
drawBackground(backgroundStyle: backgroundStyle, rects: rects, currentCGContext: currentCGContext)
}
Expand Down
58 changes: 57 additions & 1 deletion Proton/Tests/Editor/EditorSnapshotTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ class EditorSnapshotTests: SnapshotTestCase {

override func setUp() {
super.setUp()
recordMode = false
mockLineNumberProvider.indexOffSet = 0
}

Expand Down Expand Up @@ -1044,6 +1043,63 @@ class EditorSnapshotTests: SnapshotTestCase {
assertSnapshot(matching: viewController.view, as: .image, record: recordMode)
}

func testBackgroundStyleWithParagraphAndLineSpacing() {
let viewController = EditorTestViewController()
let editor = viewController.editor
editor.paragraphStyle.paragraphSpacing = 13
editor.paragraphStyle.lineSpacing = 4
// editor.font = UIFont.systemFont(ofSize: 30, weight: .medium)

let text =
"""
Line 1 text Line 1 text Line 1 text Line 2 text Line 2 text Line 2 text Line 3 text Line 3
"""

let rangeToUpdate = NSRange(location: 20, length: 58)

editor.appendCharacters(NSAttributedString(string: text))

let textField = AutogrowingTextField()
textField.backgroundColor = .cyan
textField.addBorder()
textField.font = editor.font
textField.text = "in1"

let offsetProvider = MockAttachmentOffsetProvider()
offsetProvider.offset = CGPoint(x: 0, y: -4)

let attachment = Attachment(textField, size: .matchContent)
attachment.offsetProvider = offsetProvider
textField.boundsObserver = attachment

editor.insertAttachment(in: editor.textEndRange, attachment: attachment)


let textField1 = AutogrowingTextField()
textField1.backgroundColor = .cyan
textField1.addBorder()
textField1.font = editor.font
textField1.text = "in2"

let attachment1 = Attachment(textField1, size: .matchContent)
attachment1.offsetProvider = offsetProvider
textField1.boundsObserver = attachment1

editor.insertAttachment(in: NSRange(location: 52, length: 0), attachment: attachment1)

viewController.render(size: CGSize(width: 300, height: 350))
let backgroundStyle = BackgroundStyle(color: .cyan,
roundedCornerStyle: .absolute(value: 5),
border: BorderStyle(lineWidth: 1, color: .blue),
heightMode: .matchTextExact, insets: UIEdgeInsets(top: -5, left: -2, bottom: -5, right: -2))
editor.addAttributes([
.backgroundStyle: backgroundStyle
], at: rangeToUpdate)

viewController.render(size: CGSize(width: 300, height: 350))
assertSnapshot(matching: viewController.view, as: .image, record: recordMode)
}

func testBackgroundStyleWithIncreasedFontSize() {
let viewController = EditorTestViewController()
let editor = viewController.editor
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit adf90db

Please sign in to comment.