Created
March 9, 2024 14:46
-
-
Save ShikiSuen/bca950297afb15fdeba6d677647d83c2 to your computer and use it in GitHub Desktop.
NSString.getRenderedDimension().
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// (c) 2022 and onwards The vChewing Project (MIT-NTL License). | |
// ==================== | |
// This code is released under the MIT license (SPDX-License-Identifier: MIT) | |
// ... with NTL restriction stating that: | |
// No trademark license is granted to use the trade names, trademarks, service | |
// marks, or product names of Contributor, except as required to fulfill notice | |
// requirements defined in MIT License. | |
import CoreText | |
import Foundation | |
public extension String { | |
func getRenderedDimension( | |
using givenFont: CTFont? = nil, | |
size: CGFloat? = 13, /* NSFont.systemFontSize defaults to 13. */ | |
orientation: CTFontOrientation = .horizontal, | |
locale localeIdentifier: String? = nil | |
) -> CGSize { | |
let size = size ?? 13 | |
let baseFont = givenFont ?? CTFont(.system, size: size) | |
func createMatchedFont(char: Character) -> CTFont { | |
var cfLocaleIdentifier: CFString? | |
if let localeIdentifier = localeIdentifier { | |
cfLocaleIdentifier = localeIdentifier as CFString | |
} | |
return CTFontCreateForStringWithLanguage( | |
baseFont, | |
char.description as CFString, | |
CFRange(location: 0, length: char.utf16.count), | |
cfLocaleIdentifier | |
) | |
} | |
let emojiFallbackSize = size * 1.25 | |
var finalWidth: CGFloat = 0 | |
var finalHeight: CGFloat = 0 | |
switch orientation { | |
case .horizontal: finalHeight = emojiFallbackSize | |
case .vertical: finalWidth = emojiFallbackSize | |
default: break | |
} | |
forEach { char in | |
let uniChars = Array(char.utf16) | |
let matchedFont = createMatchedFont(char: char) | |
// The subCount needs to be 1, considering that this is the only literal scalar amount to show. | |
// Otherwise, incorrect results will be generated while parsing NFD compositions. | |
let subCount = 1 | |
var fetchedGlyphs = [CGGlyph](repeating: 0, count: subCount) | |
let result = CTFontGetGlyphsForCharacters(matchedFont, uniChars, &fetchedGlyphs, subCount) | |
guard result, !fetchedGlyphs.isEmpty else { | |
switch orientation { | |
case .horizontal: finalWidth += emojiFallbackSize | |
case .vertical: finalHeight += emojiFallbackSize | |
default: break | |
} | |
return | |
} | |
let advance = CTFontGetAdvancesForGlyphs(matchedFont, orientation, fetchedGlyphs, nil, subCount) | |
switch orientation { | |
case .horizontal: finalWidth += advance | |
case .vertical: finalHeight += advance | |
default: break | |
} | |
} | |
return .init(width: ceil(finalWidth), height: ceil(finalHeight)) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment