From e31a2e6ea148b44e271787375dc094f855b86c3a Mon Sep 17 00:00:00 2001 From: Rajdeep Kwatra Date: Wed, 30 Aug 2023 14:08:45 +1000 Subject: [PATCH] Revised logic for matchTextExact for background style (#220) --- .../Sources/Swift/Base/BackgroundStyle.swift | 2 +- Proton/Sources/Swift/Core/LayoutManager.swift | 20 ++++++++++++------ ...leWithOverlappingLineExactTextHeight.1.png | Bin 12759 -> 12372 bytes 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Proton/Sources/Swift/Base/BackgroundStyle.swift b/Proton/Sources/Swift/Base/BackgroundStyle.swift index aa1523d5..8c6fdb99 100644 --- a/Proton/Sources/Swift/Base/BackgroundStyle.swift +++ b/Proton/Sources/Swift/Base/BackgroundStyle.swift @@ -77,7 +77,7 @@ public enum RoundedCornerStyle { public enum BackgroundMode { /// Background matches the height/width of text with font leading padding all around case matchText - /// Background matches the height of text with minimal padding all around + /// Background matches the height of text based on font with minimal padding all around. case matchTextExact /// Background matches entire line irrespective of font height/used character width in the given line case matchLine diff --git a/Proton/Sources/Swift/Core/LayoutManager.swift b/Proton/Sources/Swift/Core/LayoutManager.swift index d86c5235..edf11b52 100644 --- a/Proton/Sources/Swift/Core/LayoutManager.swift +++ b/Proton/Sources/Swift/Core/LayoutManager.swift @@ -56,6 +56,10 @@ class LayoutManager: NSLayoutManager { return layoutManagerDelegate?.paragraphStyle ?? NSParagraphStyle() } + var defaultFont: UIFont { + return layoutManagerDelegate?.font ?? UIFont.preferredFont(forTextStyle: .body) + } + private func drawListMarkers(textStorage: NSTextStorage, listRange: NSRange, attributeValue: Any?) { var lastLayoutRect: CGRect? var lastLayoutParaStyle: NSParagraphStyle? @@ -281,6 +285,7 @@ class LayoutManager: NSLayoutManager { let usedRect = usedRect.integral 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 let lineHeightMultipleOffset = (rect.size.height - rect.size.height/lineHeightMultiple) @@ -291,13 +296,15 @@ class LayoutManager: NSLayoutManager { rect.size.width = contentWidth } + let inset = self.layoutManagerDelegate?.textContainerInset ?? .zero switch backgroundStyle.heightMode { - case .matchText, - .matchTextExact: + 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) + case .matchText: let styledText = textStorage.attributedSubstring(from: bgStyleGlyphRange) - let drawingOptions = backgroundStyle.heightMode == .matchText ? NSStringDrawingOptions.usesFontLeading : [] - - let textRect = styledText.boundingRect(with: rect.size, options: drawingOptions, context: nil) + let textRect = styledText.boundingRect(with: rect.size, options: .usesFontLeading, context: nil) rect.origin.y = usedRect.origin.y + (rect.size.height - textRect.height) + lineHeightMultipleOffset - lineSpacing rect.size.height = textRect.height - lineHeightMultipleOffset @@ -306,10 +313,9 @@ class LayoutManager: NSLayoutManager { // So it is best to restrict the height just to the line fragment. rect.origin.y = usedRect.origin.y rect.size.height = usedRect.height - } - let inset = self.layoutManagerDelegate?.textContainerInset ?? .zero + rects.append(rect.offsetBy(dx: inset.left, dy: inset.top)) } drawBackground(backgroundStyle: backgroundStyle, rects: rects, currentCGContext: currentCGContext) diff --git a/Proton/Tests/Editor/__Snapshots__/EditorSnapshotTests/testBackgroundStyleWithOverlappingLineExactTextHeight.1.png b/Proton/Tests/Editor/__Snapshots__/EditorSnapshotTests/testBackgroundStyleWithOverlappingLineExactTextHeight.1.png index 174f8902595cd8e24c8b0174ef55af2da4672027..21b62c3c1ee07bb2e863962028f2da3c86104a87 100644 GIT binary patch literal 12372 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 F{{gG6FJu4! literal 12759 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 Gm;VQ#QRbHb