Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: b17b549e3fbe4a929404b037e1888f4db2dbb91f
https://github.com/WebKit/WebKit/commit/b17b549e3fbe4a929404b037e1888f4db2dbb91f
Author: Megan Gardner <[email protected]>
Date: 2026-06-29 (Mon, 29 Jun 2026)
Changed paths:
M Source/WebCore/editing/cocoa/AttributedString.h
M Source/WebCore/editing/cocoa/AttributedString.mm
M Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
A Tools/TestWebKitAPI/Tests/WebCore/cocoa/AttributedStringFontCache.mm
Log Message:
-----------
Typing in complicated Mail replies lags.
https://bugs.webkit.org/show_bug.cgi?id=317589
rdar://175785816
Reviewed by Abrar Rahman Protyasha.
When the same font appears in many attribute runs of an NSAttributedString —
the typical shape of styled mail content
— AttributedString::fromNSAttributedString and
AttributedString::nsAttributedString redo expensive font work for every
run. On the encode side that means Font::create + platformGlyphInit +
determinePitch, which queries
kCTFontIsUserInstalledAttribute via uncached XT property lookups; on the decode
side it means
CTFontDescriptorCreateWithAttributesAndOptions +
CTFontCreateWithFontDescriptor. In a sample taken while typing into a
complex Mail message, that work dominated the IPC dispatch CPU.
Add a per-call cache in each direction. The encode-side cache is keyed on
CTFontRef identity because
NSAttributedString interns shared font attributes, so the same pointer recurs
across runs. The decode-side cache is
keyed on a stringified summary of InstalledFont content (postScriptName,
descriptor options, point size, plus traits,
opticalSize, and variations content) because each AttributeValue carries its
own copy. Both caches live for one
fromNSAttributedString / nsAttributedString call and are threaded through the
existing parameter pattern that already
passes the table/list/block ID maps.
The decode-side key omits matrix, paletteColors, and featureSettings; when any
of those is set on the source font the
call falls through to the slow path uncached. Those are uncommon in mail and
including them in a stringified key would
be either lossy (matrix is opaque CFData; palette colors are CGColors) or
expensive enough to defeat the cache.
Adds two miss counters with WEBCORE_EXPORT accessors for testing, and a
TestWebKitAPI test that round-trips a
200-run NSMutableAttributedString whose runs all share one NSFont (alternated
by foreground color so the runs don't
coalesce) and asserts each direction's miss counter advanced by exactly 1.
Test: Tools/TestWebKitAPI/Tests/WebCore/cocoa/AttributedStringFontCache.mm
* Source/WebCore/editing/cocoa/AttributedString.h:
* Source/WebCore/editing/cocoa/AttributedString.mm:
(WebCore::AttributedString::encodeFontCacheMissesForTesting):
(WebCore::AttributedString::decodeFontCacheMissesForTesting):
(WebCore::stringifyCFNumber):
(WebCore::stringifyCFBoolean):
(WebCore::cacheKeyForInstalledFont):
(WebCore::toNSObject):
(WebCore::toNSDictionary):
(WebCore::AttributedString::documentAttributesAsNSDictionary const):
(WebCore::AttributedString::nsAttributedString const):
(WebCore::extractValue):
(WebCore::extractDictionary):
(WebCore::AttributedString::fromNSAttributedStringAndDocumentAttributes):
* Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* Tools/TestWebKitAPI/Tests/WebCore/cocoa/AttributedStringFontCache.mm: Added.
(TestWebKitAPI::TEST(AttributedStringFontCache,
RoundTripDeduplicatesSharedFont)):
(TestWebKitAPI::fontWithBaselineAdjust):
(TestWebKitAPI::baselineAdjustForFont):
(TestWebKitAPI::TEST(AttributedStringFontCache,
PostScriptFontsDifferingInBaselineAdjustDoNotCollide)):
Canonical link: https://commits.webkit.org/316044@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications