Skip to content

Commit

Permalink
Resolve fonts considering the environment's size category (#94)
Browse files Browse the repository at this point in the history
* Resolve fonts considering the environment's size category

* Fix generation of README images
  • Loading branch information
gonzalezreal authored Feb 26, 2022
1 parent 3c6b679 commit b6e88f1
Show file tree
Hide file tree
Showing 25 changed files with 77 additions and 15 deletions.
1 change: 1 addition & 0 deletions Sources/MarkdownUI/Markdown.swift
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ public struct Markdown: View {
layoutDirection: self.layoutDirection,
textAlignment: self.textAlignment
),
sizeCategory: self.sizeCategory,
style: self.style,
imageHandlers: self.imageHandlers
)
Expand Down
9 changes: 5 additions & 4 deletions Sources/MarkdownUI/Rendering/AttributedStringRenderer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ struct AttributedStringRenderer {
let baseURL: URL?
let baseWritingDirection: NSWritingDirection
let alignment: NSTextAlignment
let sizeCategory: ContentSizeCategory
let style: MarkdownStyle

func renderDocument(_ document: Document) -> NSAttributedString {
Expand Down Expand Up @@ -174,7 +175,7 @@ extension AttributedStringRenderer {
style.measurements.headIndentStep,
NSAttributedString(
string: "\(highestNumber).",
attributes: [.font: state.font.monospacedDigit().resolve()]
attributes: [.font: state.font.monospacedDigit().resolve(sizeCategory: sizeCategory)]
).em() + style.measurements.listMarkerSpacing
)

Expand Down Expand Up @@ -341,7 +342,7 @@ extension AttributedStringRenderer {
.init(
string: .nbsp,
attributes: [
.font: state.font.resolve(),
.font: state.font.resolve(sizeCategory: sizeCategory),
.strikethroughStyle: NSUnderlineStyle.single.rawValue,
.strikethroughColor: PlatformColor.separator,
]
Expand Down Expand Up @@ -424,7 +425,7 @@ extension AttributedStringRenderer {
NSAttributedString(
string: text,
attributes: [
.font: state.font.resolve(),
.font: state.font.resolve(sizeCategory: sizeCategory),
.foregroundColor: PlatformColor(state.foregroundColor),
]
)
Expand Down Expand Up @@ -490,7 +491,7 @@ extension AttributedStringRenderer {
}

private func paragraphStyle(state: State) -> NSParagraphStyle {
let pointSize = state.font.resolve().pointSize
let pointSize = state.font.resolve(sizeCategory: sizeCategory).pointSize
let result = NSMutableParagraphStyle()
result.setParagraphStyle(.default)
result.baseWritingDirection = baseWritingDirection
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ extension Document {
baseURL: URL?,
baseWritingDirection: NSWritingDirection,
alignment: NSTextAlignment,
sizeCategory: ContentSizeCategory,
style: MarkdownStyle
) -> NSAttributedString {
AttributedStringRenderer(
baseURL: baseURL,
baseWritingDirection: baseWritingDirection,
alignment: alignment,
sizeCategory: sizeCategory,
style: style
).renderDocument(self)
}
Expand All @@ -21,6 +23,7 @@ extension Document {
baseURL: URL?,
baseWritingDirection: NSWritingDirection,
alignment: NSTextAlignment,
sizeCategory: ContentSizeCategory,
style: MarkdownStyle,
imageHandlers: [String: MarkdownImageHandler]
) -> AnyPublisher<NSAttributedString, Never> {
Expand All @@ -30,6 +33,7 @@ extension Document {
baseURL: baseURL,
baseWritingDirection: baseWritingDirection,
alignment: alignment,
sizeCategory: sizeCategory,
style: style
)
)
Expand Down
62 changes: 51 additions & 11 deletions Sources/MarkdownUI/Style/Font.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ extension MarkdownStyle {
public struct Font: Hashable {
private var provider: AnyHashable

func resolve() -> PlatformFont {
func resolve(sizeCategory: ContentSizeCategory = .large) -> PlatformFont {
guard let fontProvider = self.provider.base as? FontProvider else {
fatalError("provider should conform to FontProvider")
}
#if os(macOS)
return .init(descriptor: fontProvider.fontDescriptor(), size: 0)
return .init(descriptor: fontProvider.fontDescriptor(compatibleWith: sizeCategory), size: 0)
?? .preferredFont(forTextStyle: .body)
#elseif os(iOS) || os(tvOS)
return .init(descriptor: fontProvider.fontDescriptor(), size: 0)
return .init(descriptor: fontProvider.fontDescriptor(compatibleWith: sizeCategory), size: 0)
#endif
}
}
Expand Down Expand Up @@ -150,21 +150,22 @@ extension MarkdownStyle.Font {
// MARK: - FontProvider

private protocol FontProvider {
func fontDescriptor() -> PlatformFontDescriptor
func fontDescriptor(compatibleWith sizeCategory: ContentSizeCategory) -> PlatformFontDescriptor
}

private struct TextStyleFontProvider: Hashable, FontProvider {
var style: SwiftUI.Font.TextStyle
var design: SwiftUI.Font.Design

func fontDescriptor() -> PlatformFontDescriptor {
func fontDescriptor(compatibleWith sizeCategory: ContentSizeCategory) -> PlatformFontDescriptor {
#if os(macOS)
let fontDescriptor = PlatformFontDescriptor.preferredFontDescriptor(
forTextStyle: .init(style)
)
#elseif os(iOS) || os(tvOS)
let fontDescriptor = PlatformFontDescriptor.preferredFontDescriptor(
withTextStyle: .init(style)
withTextStyle: .init(style),
compatibleWith: .init(preferredContentSizeCategory: .init(sizeCategory))
)
#endif

Expand All @@ -177,7 +178,7 @@ private struct SystemFontProvider: Hashable, FontProvider {
var weight: SwiftUI.Font.Weight
var design: SwiftUI.Font.Design

func fontDescriptor() -> PlatformFontDescriptor {
func fontDescriptor(compatibleWith _: ContentSizeCategory) -> PlatformFontDescriptor {
let fontDescriptor = PlatformFont.systemFont(ofSize: size, weight: .init(weight))
.fontDescriptor
return fontDescriptor.withDesign(.init(design)) ?? fontDescriptor
Expand All @@ -189,12 +190,16 @@ private struct CustomFontProvider: Hashable, FontProvider {
var size: CGFloat
var textStyle: SwiftUI.Font.TextStyle?

func fontDescriptor() -> PlatformFontDescriptor {
func fontDescriptor(compatibleWith sizeCategory: ContentSizeCategory) -> PlatformFontDescriptor {
var size = self.size

#if os(iOS) || os(tvOS)
if let textStyle = self.textStyle {
size = UIFontMetrics(forTextStyle: .init(textStyle)).scaledValue(for: size)
size = UIFontMetrics(forTextStyle: .init(textStyle))
.scaledValue(
for: size,
compatibleWith: .init(preferredContentSizeCategory: .init(sizeCategory))
)
}
#endif

Expand All @@ -211,11 +216,11 @@ private struct FontModifierProvider<M>: Hashable, FontProvider where M: Hashable
var base: AnyHashable
var modifier: M

func fontDescriptor() -> PlatformFontDescriptor {
func fontDescriptor(compatibleWith sizeCategory: ContentSizeCategory) -> PlatformFontDescriptor {
guard let fontProvider = self.base.base as? FontProvider else {
fatalError("base should conform to FontProvider")
}
var fontDescriptor = fontProvider.fontDescriptor()
var fontDescriptor = fontProvider.fontDescriptor(compatibleWith: sizeCategory)
modifier.modify(&fontDescriptor)
return fontDescriptor
}
Expand Down Expand Up @@ -399,3 +404,38 @@ extension PlatformFontDescriptor.SystemDesign {
}
}
}

#if os(iOS) || os(tvOS)
extension UIContentSizeCategory {
fileprivate init(_ contentSizeCategory: ContentSizeCategory) {
switch contentSizeCategory {
case .extraSmall:
self = .extraSmall
case .small:
self = .small
case .medium:
self = .medium
case .large:
self = .large
case .extraLarge:
self = .extraLarge
case .extraExtraLarge:
self = .extraExtraLarge
case .extraExtraExtraLarge:
self = .extraExtraExtraLarge
case .accessibilityMedium:
self = .accessibilityMedium
case .accessibilityLarge:
self = .accessibilityLarge
case .accessibilityExtraLarge:
self = .accessibilityExtraLarge
case .accessibilityExtraExtraLarge:
self = .accessibilityExtraExtraLarge
case .accessibilityExtraExtraExtraLarge:
self = .accessibilityExtraExtraExtraLarge
@unknown default:
self = .large
}
}
}
#endif
15 changes: 15 additions & 0 deletions Tests/MarkdownUITests/MarkdownTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -449,5 +449,20 @@

assertSnapshot(matching: view, as: .image(layout: layout), named: platformName)
}

#if os(iOS)
func testSizeCategory() {
let view = VStack {
ForEach(ContentSizeCategory.allCases, id: \.self) { sizeCategory in
Markdown("Markdown**UI**")
.environment(\.sizeCategory, sizeCategory)
}
}
.background(Color.orange)
.padding()

assertSnapshot(matching: view, as: .image(layout: layout), named: platformName)
}
#endif
}
#endif
1 change: 1 addition & 0 deletions Tests/MarkdownUITests/ReadMeImagesTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
)
}

@available(iOS 15.0, *)
func testMarkdownStyle() {
let view = Markdown(
#"""
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.

0 comments on commit b6e88f1

Please sign in to comment.