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
38 changes: 19 additions & 19 deletions Sources/OpenSwiftUICore/View/Text/Resolve/ResolvedText.swift
Original file line number Diff line number Diff line change
Expand Up @@ -137,27 +137,27 @@ extension Text {
// MARK: - Text.Style [WIP]

package struct Style {
private var baseFont: TextStyleFont
private var fontModifiers: [AnyFontModifier]
private var color: TextStyleColor
private var backgroundColor: Color?
private var baselineOffset: CGFloat?
private var kerning: CGFloat?
private var tracking: CGFloat?
private var strikethrough: LineStyle
private var underline: LineStyle
// private var encapsulation: Text.Encapsulation?
private var speech: AccessibilitySpeechAttributes?
internal var baseFont: TextStyleFont
internal var fontModifiers: [AnyFontModifier]
internal var color: TextStyleColor
internal var backgroundColor: Color?
internal var baselineOffset: CGFloat?
internal var kerning: CGFloat?
internal var tracking: CGFloat?
internal var strikethrough: LineStyle
internal var underline: LineStyle
internal var encapsulation: Text.Encapsulation?
internal var speech: AccessibilitySpeechAttributes?
package var accessibility: AccessibilityTextAttributes?
// private var glyphInfo: CTGlyphInfo?
// private var shadow: TextShadowModifier?
// private var transition: TextTransitionModifier?
// private var scale: Text.Scale?
// private var superscript: Text.Superscript?
// private var typesettingConfiguration: TypesettingConfiguration
// private var customAttributes: [TextAttributeModifierBase]
// internal var glyphInfo: CTGlyphInfo?
// internal var shadow: TextShadowModifier?
// internal var transition: TextTransitionModifier?
// internal var scale: Text.Scale?
// internal var superscript: Text.Superscript?
internal var typesettingConfiguration: TypesettingConfiguration
// internal var customAttributes: [TextAttributeModifierBase]
#if canImport(Darwin)
// private var adaptiveImageGlyph: AttributedString.AdaptiveImageGlyph?
// internal var adaptiveImageGlyph: AttributedString.AdaptiveImageGlyph?
#endif
package var clearedFontModifiers: Set<ObjectIdentifier>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// TypesettingConfiguration.swift
// OpenSwiftUICore
//
// Audited for 6.5.4
// Status: Complete

// MARK: - TypesettingConfiguration

package struct TypesettingConfiguration: Equatable {
package var language: TypesettingLanguage

package var languageAwareLineHeightRatio: TypesettingLanguageAwareLineHeightRatio

package init(
language: TypesettingLanguage = .automatic,
languageAwareLineHeightRatio: TypesettingLanguageAwareLineHeightRatio = .automatic
) {
self.language = language
self.languageAwareLineHeightRatio = languageAwareLineHeightRatio
}
}

package struct TypesettingConfigurationKey: EnvironmentKey {
package static let defaultValue: TypesettingConfiguration = .init()
}

extension EnvironmentValues {
package var typesettingConfiguration: TypesettingConfiguration {
get { self[TypesettingConfigurationKey.self] }
set { self[TypesettingConfigurationKey.self] = newValue }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
//
// TypesettingLanguage.swift
// OpenSwiftUICore
//
// Audited for 6.5.4
// Status: Complete

public import Foundation

// MARK: - TypesettingLanguage

/// Defines how typesetting language is determined for text.
///
/// Use a modifier like ``View/typesettingLanguage(_:isEnabled:)``
/// to specify the typesetting language.
@available(OpenSwiftUI_v5_0, *)
public struct TypesettingLanguage: Sendable, Equatable {
package struct Flags: OptionSet {
package var rawValue: UInt8

package init(rawValue: UInt8) {
self.rawValue = rawValue
}

package static let modifyFont: TypesettingLanguage.Flags = .init(rawValue: 1 << 0)
}

package enum Storage: Equatable {
case automatic
case contentAware
case explicit(Locale.Language, TypesettingLanguage.Flags)
}

package var storage: TypesettingLanguage.Storage

/// Automatic language behavior.
///
/// When determining the language to use for typesetting the current UI
/// language and preferred languages will be considered. For example, if
/// the current UI locale is for English and Thai is included in the
/// preferred languages then line heights will be taller to accommodate the
/// taller glyphs used by Thai.
public static let automatic: TypesettingLanguage = .init(storage: .automatic)

/// Use explicit language.
///
/// An explicit language will be used for typesetting. For example, if used
/// with Thai language the line heights will be as tall as needed to
/// accommodate Thai.
///
/// - Parameters:
/// - language: The language to use for typesetting.
/// - Returns: A `TypesettingLanguage`.
public static func explicit(_ language: Locale.Language) -> TypesettingLanguage {
.init(storage: .explicit(language, .modifyFont))
}
}

@_spi(Private)
@available(OpenSwiftUI_v5_0, *)
extension TypesettingLanguage {
@_spi(Private)
@available(OpenSwiftUI_v5_0, *)
public static let contentAware: TypesettingLanguage = .init(storage: .contentAware)
}

// MARK: - View + typesettingLanguage

@available(OpenSwiftUI_v1_0, *)
extension View {

/// Specifies the language for typesetting.
///
/// In some cases `Text` may contain text of a particular language which
/// doesn't match the device UI language. In that case it's useful to
/// specify a language so line height, line breaking and spacing will
/// respect the script used for that language. For example:
///
/// Text(verbatim: "แอปเปิล")
/// .typesettingLanguage(.init(languageCode: .thai))
///
/// Note: this language does not affect text localization.
///
/// - Parameters:
/// - language: The explicit language to use for typesetting.
/// - isEnabled: A Boolean value that indicates whether text language is
/// added
/// - Returns: A view with the typesetting language set to the value you
/// supply.
@available(OpenSwiftUI_v5_0, *)
nonisolated public func typesettingLanguage(
_ language: Locale.Language,
isEnabled: Bool = true
) -> some View {
typesettingLanguage(.explicit(language), isEnabled: isEnabled)
}

/// Specifies the language for typesetting.
///
/// In some cases `Text` may contain text of a particular language which
/// doesn't match the device UI language. In that case it's useful to
/// specify a language so line height, line breaking and spacing will
/// respect the script used for that language. For example:
///
/// Text(verbatim: "แอปเปิล").typesettingLanguage(
/// .explicit(.init(languageCode: .thai)))
///
/// Note: this language does not affect text localized localization.
///
/// - Parameters:
/// - language: The language to use for typesetting.
/// - isEnabled: A Boolean value that indicates whether text language is
/// added
/// - Returns: A view with the typesetting language set to the value you
/// supply.
@available(OpenSwiftUI_v5_0, *)
nonisolated public func typesettingLanguage(
_ language: TypesettingLanguage,
isEnabled: Bool = true
) -> some View {
transformEnvironment(\.typesettingConfiguration) {
if isEnabled {
$0.language = language
}
}
}
}

// MARK: - LanguageTextModifier

class LanguageTextModifier: AnyTextModifier {
let language: TypesettingLanguage

init(language: TypesettingLanguage) {
self.language = language
}

override func modify(style: inout Text.Style, environment: EnvironmentValues) {
// NOTE: This also set languageAwareLineHeightRatio to automatic
style.typesettingConfiguration = .init(language: language)
}

override func isEqual(to other: AnyTextModifier) -> Bool {
guard let other = other as? LanguageTextModifier else {
return false
}
return language == other.language
}
}

// MARK: - Text + typesettingLanguage

@available(OpenSwiftUI_v1_0, *)
extension Text {

/// Specifies the language for typesetting.
///
/// In some cases `Text` may contain text of a particular language which
/// doesn't match the device UI language. In that case it's useful to
/// specify a language so line height, line breaking and spacing will
/// respect the script used for that language. For example:
///
/// Text(verbatim: "แอปเปิล")
/// .typesettingLanguage(.init(languageCode: .thai))
///
/// Note: this language does not affect text localization.
///
/// - Parameters:
/// - language: The explicit language to use for typesetting.
/// - isEnabled: A Boolean value that indicates whether text language is
/// added
/// - Returns: Text with the typesetting language set to the value you
/// supply.
@available(OpenSwiftUI_v5_0, *)
public func typesettingLanguage(
_ language: Locale.Language,
isEnabled: Bool = true
) -> Text {
typesettingLanguage(.explicit(language), isEnabled: isEnabled)
}

/// Specifies the language for typesetting.
///
/// In some cases `Text` may contain text of a particular language which
/// doesn't match the device UI language. In that case it's useful to
/// specify a language so line height, line breaking and spacing will
/// respect the script used for that language. For example:
///
/// Text(verbatim: "แอปเปิล").typesettingLanguage(
/// .explicit(.init(languageCode: .thai)))
///
/// Note: this language does not affect text localized localization.
///
/// - Parameters:
/// - language: The language to use for typesetting.
/// - isEnabled: A Boolean value that indicates whether text language is
/// added
/// - Returns: Text with the typesetting language set to the value you
/// supply.
@available(OpenSwiftUI_v5_0, *)
public func typesettingLanguage(
_ language: TypesettingLanguage,
isEnabled: Bool = true
) -> Text {
guard isEnabled else {
return self
}
let modifier: Text.Modifier = .anyTextModifier(LanguageTextModifier(language: language))
return modified(with: modifier)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//
// TypesettingLanguageAwareLineHeightRatio.swift
// OpenSwiftUICore
//
// Audited for 6.5.4
// Status: Complete

// MARK: - TypesettingLanguageAwareLineHeightRatio

@_spi(Private)
@available(OpenSwiftUI_v5_0, *)
public struct TypesettingLanguageAwareLineHeightRatio: Sendable, Equatable {
enum Storage: Equatable {
case custom(Double)
case automatic
case disable
case legacy
}

var storage: TypesettingLanguageAwareLineHeightRatio.Storage
Comment on lines +13 to +20
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency with TypesettingLanguage.Storage (line 28 of TypesettingLanguage.swift), this enum should be declared as package enum Storage: Equatable. Similarly, the storage property on line 20 should be package var storage to match the pattern in TypesettingLanguage.

Suggested change
enum Storage: Equatable {
case custom(Double)
case automatic
case disable
case legacy
}
var storage: TypesettingLanguageAwareLineHeightRatio.Storage
package enum Storage: Equatable {
case custom(Double)
case automatic
case disable
case legacy
}
package var storage: TypesettingLanguageAwareLineHeightRatio.Storage

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency with TypesettingLanguage.storage (line 34 of TypesettingLanguage.swift), this should be declared as package var storage.

Suggested change
var storage: TypesettingLanguageAwareLineHeightRatio.Storage
package var storage: TypesettingLanguageAwareLineHeightRatio.Storage

Copilot uses AI. Check for mistakes.

public static let automatic: TypesettingLanguageAwareLineHeightRatio = .init(storage: .automatic)

public static let disable: TypesettingLanguageAwareLineHeightRatio = .init(storage: .disable)

public static let legacy: TypesettingLanguageAwareLineHeightRatio = .init(storage: .legacy)

public static func custom(_ ratio: Double) -> TypesettingLanguageAwareLineHeightRatio {
.init(storage: .custom(ratio.clamp(min: 0.0, max: 1.0)))
}
}

// MARK: - View + typesettingLanguageAwareLineHeightRatio

@available(OpenSwiftUI_v1_0, *)
extension View {
@_spi(Private)
@available(OpenSwiftUI_v5_0, *)
nonisolated public func typesettingLanguageAwareLineHeightRatio(
_ ratio: TypesettingLanguageAwareLineHeightRatio,
isEnabled: Bool = true
) -> some View {
transformEnvironment(\.typesettingConfiguration) {
if isEnabled {
$0.languageAwareLineHeightRatio = ratio
}
}
}
}

// MARK: - LanguageAwareLineHeightRatioTextModifier

class LanguageAwareLineHeightRatioTextModifier: AnyTextModifier {
let ratio: TypesettingLanguageAwareLineHeightRatio

init(ratio: TypesettingLanguageAwareLineHeightRatio) {
self.ratio = ratio
}

override func modify(style: inout Text.Style, environment: EnvironmentValues) {
style.typesettingConfiguration.languageAwareLineHeightRatio = ratio
}

override func isEqual(to other: AnyTextModifier) -> Bool {
guard let other = other as? LanguageAwareLineHeightRatioTextModifier else {
return false
}
return ratio == other.ratio
}
}

// MARK: - Text + typesettingLanguageAwareLineHeightRatio

@available(OpenSwiftUI_v1_0, *)
extension Text {
@_spi(Private)
@available(OpenSwiftUI_v5_0, *)
public func typesettingLanguageAwareLineHeightRatio(
_ ratio: TypesettingLanguageAwareLineHeightRatio,
isEnabled: Bool = true
) -> Text {
guard isEnabled else {
return self
}
return modified(with: .anyTextModifier(LanguageAwareLineHeightRatioTextModifier(ratio: ratio)))
}
}
Loading