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

Reply via email to