Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions Sources/OpenSwiftUICore/Shim/TextNonDarwinShims.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ public import UIFoundation_Private

public typealias NSInteger = Int

class NSStringDrawingContext: NSObject {
var wrapsForTruncationMode = false
var wantsBaselineOffset = false
var wantsScaledLineHeight = false
var wantsScaledBaselineOffset = false
var cachesLayout = false
}

package enum NSWritingDirection: Int {
case natural = -1
case leftToRight = 0
Expand Down Expand Up @@ -83,6 +91,12 @@ package class NSTextLineFragment: NSObject {
}

extension NSAttributedString {
// Work around https://github.com/swiftlang/swift/issues/71874.
@_nonoverride
public convenience init() {
self.init(string: "")
}

public convenience init(_ attributedString: AttributedString) {
self.init(string: String(attributedString))
}
Expand Down
19 changes: 19 additions & 0 deletions Sources/OpenSwiftUICore/Test/AttributeCountInfoKey.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// AttributeCountInfoKey.swift
// OpenSwiftUICore
//
// Audited for 6.5.4
// Status: Complete

// MARK: - AttributeCountInfoKey

package struct AttributeCountInfoKey: HostPreferenceKey {
package static let defaultValue = AttributeCountTestInfo()

package static func reduce(
value: inout AttributeCountTestInfo,
nextValue: () -> AttributeCountTestInfo
) {
value.merge(nextValue())
}
}
17 changes: 2 additions & 15 deletions Sources/OpenSwiftUICore/Test/AttributeCountTestInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
// AttributeCountTestInfo.swift
// OpenSwiftUICore
//
// Audited for 6.5.4
// Status: Complete

// MARK: - AttributeCountTestInfo [6.4.41]
// MARK: - AttributeCountTestInfo

package struct AttributeCountTestInfo: Equatable {
var attributeCounts: [String: UInt32] = [:]
Expand All @@ -19,17 +20,3 @@ package struct AttributeCountTestInfo: Equatable {
history.merge(other.history) { $0 + $1 }
}
}

// MARK: - AttributeCountInfoKey [6.4.41]

package struct AttributeCountInfoKey: HostPreferenceKey {
package static let defaultValue = AttributeCountTestInfo()

package static func reduce(
value: inout AttributeCountTestInfo,
nextValue: () -> AttributeCountTestInfo
) {
value.merge(nextValue())
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

package import Foundation
package import UIFoundation_Private
#if canImport(CoreText)
package import CoreText
#endif

package func makeParagraphStyle(environment: EnvironmentValues) -> NSMutableParagraphStyle {
let paragraphStyle = NSMutableParagraphStyle()
Expand Down Expand Up @@ -107,10 +110,81 @@ extension NSAttributedString {
package struct EncodedFontMetrics {
package var capHeight: CGFloat, ascender: CGFloat, descender: CGFloat, leading: CGFloat
package var outsets: EdgeInsets

init(capHeight: CGFloat, ascender: CGFloat, descender: CGFloat, leading: CGFloat, outsets: EdgeInsets) {
self.capHeight = capHeight
self.ascender = ascender
self.descender = descender
self.leading = leading
self.outsets = outsets
}

init() {
self.capHeight = .zero
self.ascender = .zero
self.descender = .zero
self.leading = .zero
self.outsets = .zero
}
}

package var maxFontMetrics: EncodedFontMetrics {
_openSwiftUIUnimplementedFailure()
#if canImport(CoreText)
var capHeight: CGFloat = 0
var ascender: CGFloat = 0
var descender: CGFloat = 0
var leading: CGFloat?
var outsets = EdgeInsets.zero
let hasOversizedScalars = string.rangeOfCharacter(from: Self.oversizedScalars) != nil
let usesTextRenderingMetrics = Semantics.TextRenderingMetrics.isEnabled
enumerateAttribute(
.kitFont,
in: NSRange(location: 0, length: length),
options: .longestEffectiveRangeNotRequired
) { value, _, _ in
guard let value else {
return
}
let font = value as! CTFont
let fontAscender = font.ascender
let fontDescender = font.descender
capHeight = max(capHeight, font.capHeight)
ascender = max(ascender, fontAscender)
descender = max(descender, fontDescender)
leading = leading.map { max($0, font.leading) } ?? font.leading
if hasOversizedScalars || font.mayRequireLanguageAwareOutsets {
var left: CGFloat = 0
var top: CGFloat = 0
var right: CGFloat = 0
var bottom: CGFloat = 0
if CTFontGetLanguageAwareOutsets(font, &left, &top, &right, &bottom) {
outsets.top = max(outsets.top, top)
outsets.leading = max(outsets.leading, left)
outsets.bottom = max(outsets.bottom, bottom)
outsets.trailing = max(outsets.trailing, right)
return
}
}
if usesTextRenderingMetrics, !font.isSystemUIFont {
var clippingAscender = fontAscender
var clippingDescender = fontDescender
if CTFontGetClippingMetrics(font, &clippingAscender, &clippingDescender) {
outsets.top = max(outsets.top, max(0, clippingAscender - fontAscender))
outsets.bottom = max(outsets.bottom, max(0, clippingDescender - fontDescender))
}
}
}
return EncodedFontMetrics(
capHeight: capHeight,
ascender: ascender,
descender: -descender,
leading: leading ?? 0,
outsets: outsets
)
#else
_openSwiftUIPlatformUnimplementedWarning()
return EncodedFontMetrics()
#endif
}
}

Expand Down
19 changes: 19 additions & 0 deletions Sources/OpenSwiftUICore/View/Text/Font/CoreText+Private.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,25 @@ package func CTFontDescriptorCreateForUIType(

// MARK: - CTFont private API

@_silgen_name("CTFontCopySystemUIFontExcessiveLineHeightCharacterSet")
package func CTFontCopySystemUIFontExcessiveLineHeightCharacterSet() -> CFCharacterSet?

@_silgen_name("CTFontGetLanguageAwareOutsets")
package func CTFontGetLanguageAwareOutsets(
_ font: CTFont,
_ left: UnsafeMutablePointer<CGFloat>,
_ top: UnsafeMutablePointer<CGFloat>,
_ right: UnsafeMutablePointer<CGFloat>,
_ bottom: UnsafeMutablePointer<CGFloat>
) -> Bool

@_silgen_name("CTFontGetClippingMetrics")
package func CTFontGetClippingMetrics(
_ font: CTFont,
_ ascent: UnsafeMutablePointer<CGFloat>,
_ descent: UnsafeMutablePointer<CGFloat>
) -> Bool

@_silgen_name("CTFontIsSystemUIFont")
package func CTFontIsSystemUIFont(_ font: CTFont) -> Bool

Expand Down
10 changes: 3 additions & 7 deletions Sources/OpenSwiftUICore/View/Text/Font/CoreTextUtil.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ extension CTFont {
}

package var stylisticClass: CTFontStylisticClass {
.init(rawValue: CTFontGetSymbolicTraits(self).rawValue & CTFontSymbolicTraits.traitClassMask.rawValue)
.init(rawValue: symbolicTraits.rawValue & CTFontSymbolicTraits.traitClassMask.rawValue)
}

package func scaled(
Expand Down Expand Up @@ -85,14 +85,10 @@ extension CTFont {
}

package var mayRequireLanguageAwareOutsets: Bool {
guard symbolicTraits.isEmpty else {
guard !symbolicTraits.contains(.italicTrait), weight <= kCTFontWeightHeavy else {
return true
}
guard weight <= kCTFontWeightHeavy else {
return true
}
let stylisticClass = stylisticClass
return stylisticClass == [.modernSerifsClass] || stylisticClass == [.oldStyleSerifsClass, .modernSerifsClass]
return [CTFontStylisticClass.scriptsClass, .ornamentalsClass].contains(stylisticClass)
}
}

Expand Down
122 changes: 122 additions & 0 deletions Sources/OpenSwiftUICore/View/Text/Text/Text+Measure.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
//
// Text+StringDrawingContext.swift
// OpenSwiftUICore
//
// Audited for 6.5.4
// Status: WIP
// ID: 68D51D45BC7225E72FB030F887E5A492 (SwiftUICore)

public import Foundation

@available(OpenSwiftUI_v6_0, *)
extension NSAttributedString {
@usableFromInline
package struct Metrics: Equatable {
package var size: CGSize
package let scale: CGFloat
package var firstBaseline: CGFloat
package var lastBaseline: CGFloat
package var baselineAdjustment: CGFloat
package var requestedWidth: CGFloat
package var numberOfLines: UInt?
package var hasTruncatedRanges: Bool

package init(
size: CGSize,
scale: CGFloat,
firstBaseline: CGFloat,
lastBaseline: CGFloat,
baselineAdjustment: CGFloat,
requestedWidth: CGFloat,
numberOfLines: UInt?,
hasTruncatedRanges: Bool
) {
self.size = size
self.scale = scale
self.firstBaseline = firstBaseline
self.lastBaseline = lastBaseline
self.baselineAdjustment = baselineAdjustment
self.requestedWidth = requestedWidth
self.numberOfLines = numberOfLines
self.hasTruncatedRanges = hasTruncatedRanges
}
}

struct MetricsCache {
var kitCache: AnyObject?
let string: NSAttributedString
let lineLimit: Int?
let lowerLineLimit: Int?
let minScaleFactor: CGFloat
let bodyHeadOutdent: CGFloat
let pixelLength: CGFloat
let widthIsFlexible: Bool
let drawWithRequestedWidth: Bool
let isCollapsible: Bool
var entries: [(CGSize, Metrics)]

init(
_ string: NSAttributedString?,
scaleFactorOverride: CGFloat?,
lineLimit: Int?,
lowerLineLimit: Int?,
minScaleFactor: CGFloat,
bodyHeadOutdent: CGFloat,
pixelLength: CGFloat,
widthIsFlexible: Bool,
drawWithRequestedWidth: Bool,
isCollapsible: Bool
) {
self.kitCache = nil
self.string = string?.scaled(by: scaleFactorOverride ?? 1) ?? .emptyString
self.lineLimit = lineLimit
self.lowerLineLimit = lowerLineLimit
// A scale override has already been baked into `string`, so the drawing
// context must not apply the original minimum scale factor a second time.
self.minScaleFactor = scaleFactorOverride == nil ? minScaleFactor : 1
self.bodyHeadOutdent = bodyHeadOutdent
self.pixelLength = pixelLength
self.widthIsFlexible = widthIsFlexible
self.drawWithRequestedWidth = drawWithRequestedWidth
self.isCollapsible = isCollapsible
self.entries = []
}

mutating func metrics(
requestedSize: CGSize,
layoutMargins: EdgeInsets,
wantsNumberOfLineFragments: Bool,
context: TextDrawingContext
) -> Metrics {
_openSwiftUIUnimplementedFailure()
}
}

private static let emptyString = NSAttributedString()

private func measured(
requestedSize: CGSize,
lineLimit: Int?,
lowerLineLimit: Int?,
minScaleFactor: CGFloat,
bodyHeadOutdent: CGFloat,
widthIsFlexible: Bool,
kitCache: inout AnyObject?,
isCollapsible: Bool,
wantsNumberOfLineFragments: Bool,
context: TextDrawingContext
) -> NSAttributedString.Metrics {
_openSwiftUIUnimplementedFailure()
}
}

@available(*, unavailable)
extension NSAttributedString.Metrics: Sendable {}

extension ResolvedStyledText {
// FIXME
package class StringDrawing: ResolvedStyledText {}
Comment thread
Kyle-Ye marked this conversation as resolved.

// FIXME
package class TextLayoutManager: ResolvedStyledText {}
}
Loading
Loading