Skip to content

Commit ccca0c1

Browse files
committed
Add caching for imported fonts
1 parent 29c6e27 commit ccca0c1

File tree

2 files changed

+54
-1
lines changed

2 files changed

+54
-1
lines changed

ShapeScript/EvaluationContext.swift

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,15 @@ final class EvaluationContext {
4545
case value(Value)
4646
}
4747

48+
var fonts: [String] {
49+
store.values.compactMap {
50+
switch $0 {
51+
case let .value(.font(name)): name
52+
default: nil
53+
}
54+
}
55+
}
56+
4857
var store = [URL: Import]()
4958
}
5059

@@ -312,6 +321,9 @@ extension EvaluationContext {
312321
guard [".otf", ".ttf", ".ttc"].contains(where: {
313322
name.lowercased().hasSuffix($0)
314323
}) else {
324+
if importCache.fonts.contains(name) {
325+
return name
326+
}
315327
guard let font = CGFont(name as CFString) else {
316328
var options = [String]()
317329
options += CTFontManagerCopyAvailablePostScriptNames() as? [String] ?? []
@@ -323,6 +335,9 @@ extension EvaluationContext {
323335
return font.fullName as String? ?? name
324336
}
325337
let url = try resolveURL(for: name)
338+
if case let .value(.font(fullName)) = importCache.store[url] {
339+
return fullName
340+
}
326341
guard let dataProvider = CGDataProvider(url: url as CFURL) else {
327342
throw RuntimeErrorType.fileNotFound(for: name, at: url)
328343
}
@@ -331,7 +346,9 @@ extension EvaluationContext {
331346
else {
332347
throw RuntimeErrorType.fileParsingError(for: name, at: url, message: "")
333348
}
334-
return cgFont.fullName as String? ?? ""
349+
let fullName = cgFont.fullName as String? ?? ""
350+
importCache.store[url] = .value(.font(fullName))
351+
return fullName
335352
#else
336353
return name
337354
#endif

ShapeScriptTests/StandardLibraryTests.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,42 @@ final class StandardLibraryTests: XCTestCase {
719719
XCTAssertEqual(delegate.log, ["Arial"])
720720
}
721721

722+
func testLoadSameFontFileTwice() throws {
723+
#if canImport(CoreGraphics)
724+
let program = try parse("""
725+
font "EdgeOfTheGalaxyRegular-OVEa6.otf"
726+
print font
727+
font "Arial"
728+
print font
729+
font "EdgeOfTheGalaxyRegular-OVEa6.otf"
730+
print font
731+
""")
732+
let delegate = TestDelegate()
733+
let context = EvaluationContext(source: program.source, delegate: delegate)
734+
XCTAssertNoThrow(try program.evaluate(in: context))
735+
XCTAssertEqual(context.font, "Edge of the Galaxy Regular")
736+
XCTAssertEqual(delegate.log, ["Edge of the Galaxy Regular", "Arial", "Edge of the Galaxy Regular"])
737+
#endif
738+
}
739+
740+
func testSetFontWithNameAfterLoadingFromFile() throws {
741+
#if canImport(CoreGraphics)
742+
let program = try parse("""
743+
font "EdgeOfTheGalaxyRegular-OVEa6.otf"
744+
print font
745+
font "Arial"
746+
print font
747+
font "Edge of the Galaxy Regular"
748+
print font
749+
""")
750+
let delegate = TestDelegate()
751+
let context = EvaluationContext(source: program.source, delegate: delegate)
752+
XCTAssertNoThrow(try program.evaluate(in: context))
753+
XCTAssertEqual(context.font, "Edge of the Galaxy Regular")
754+
XCTAssertEqual(delegate.log, ["Edge of the Galaxy Regular", "Arial", "Edge of the Galaxy Regular"])
755+
#endif
756+
}
757+
722758
func testFontInBlock() throws {
723759
let program = try parse("""
724760
define foo {

0 commit comments

Comments
 (0)