Skip to content

Commit

Permalink
Design an intentional way to invalidate platform font caches
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=241537

Reviewed by Cameron McCormack and Simon Fraser.

Our platform font invalidation code is fairly spotty - the choice of "what invalidates what" isn't
particularly deliberate. This patch reorganizes our platform font invalidation code to have this
design (where the arrows represent "A calls B" relationships):

FontCache::invalidateAllFontCaches()
              ||
              ||
              ||
              V
    FontCache::invalidate()
              ||           \\
              ||            \\
              ||              =====
              ||                   \\
              ||                    V
              ||                    SystemFontDatabase::invalidate()
              V                                   ||
FontCache::platformInvalidate()                   ||
                                                  ||
                                                  ||
                                                  V
                                SystemFontDatabase::platformInvalidate()

So now, there is one clear place that should be called whenever this stuff needs to be invalidated:
FontCache::invalidateAllFontCaches(). This greatly simplifies the calculus of "which invalidation function
do I need to run in which situations." Also, because these invalidation functions are only called during
situations like the memory pressure handler, or when system preferences change, performance isn't a concern
here, and it's way more important that the relevant invalidation actually happens than it is to
exactly minimize the set of specific things that need to be invalidated in every specific situation.

On Cocoa ports, SystemFontDatabase::platformInvalidate() is implemented by SystemFontDatabaseCoreText,
which already exists. Also, this patch updates the existing platform notification handlers to call
the top level entry point FontCache::invalidateAllFontCaches() as expected.

This is a defensive patch. There's no specific bug or change in behavior I'm aiming for; instead I'm just
trying to make it more likely that the right thing happens at the right time. I'm also trying to create
an infrastructure I can plug into when I implement https://bugs.webkit.org/show_bug.cgi?id=237817.

No tests because this is a defensive patch.

* Source/WebCore/page/Page.cpp:
(WebCore::Page::firstTimeInitialization):
* Source/WebCore/page/cocoa/MemoryReleaseCocoa.mm:
(WebCore::platformReleaseMemory):
* Source/WebCore/platform/graphics/FontCache.cpp:
(WebCore::FontCache::invalidate):
* Source/WebCore/platform/graphics/FontCache.h:
(WebCore::FontCache::generation const):
* Source/WebCore/platform/graphics/SystemFontDatabase.cpp:
(WebCore::SystemFontDatabase::invalidate):
(WebCore::SystemFontDatabase::clear): Deleted.
* Source/WebCore/platform/graphics/SystemFontDatabase.h:
* Source/WebCore/platform/graphics/cocoa/FontCacheCoreText.cpp:
(WebCore::fontCacheRegisteredFontsChangedNotificationCallback):
(WebCore::FontCache::platformInvalidate):
(WebCore::invalidateFontCache): Deleted.
* Source/WebCore/platform/graphics/cocoa/SystemFontDatabaseCoreText.cpp:
(WebCore::SystemFontDatabase::platformInvalidate):
(WebCore::SystemFontDatabaseCoreText::clear):
* Source/WebCore/platform/graphics/cocoa/SystemFontDatabaseCoreText.h:
* Source/WebCore/platform/graphics/freetype/FontCacheFreeType.cpp:
(WebCore::FontCache::platformInvalidate):
* Source/WebCore/platform/graphics/gtk/SystemFontDatabaseGTK.cpp:
(WebCore::SystemFontDatabase::platformInvalidate):
* Source/WebCore/platform/graphics/playstation/SystemFontDatabasePlayStation.cpp:
(WebCore::SystemFontDatabase::platformInvalidate):
* Source/WebCore/platform/graphics/win/FontCacheWin.cpp:
(WebCore::FontCache::platformInvalidate):
* Source/WebCore/platform/graphics/win/SystemFontDatabaseWin.cpp:
(WebCore::SystemFontDatabase::platformInvalidate):
* Source/WebCore/platform/graphics/wpe/SystemFontDatabaseWPE.cpp:
(WebCore::SystemFontDatabase::platformInvalidate):
* Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::WebPage::contentSizeCategoryDidChange):
* Source/WebKit/WebProcess/WebProcess.cpp:
(WebKit::WebProcess::terminate):
* Source/WebKit/WebProcess/cocoa/WebProcessCocoa.mm:
(WebKit::WebProcess::accessibilityPreferencesDidChange):

Canonical link: https://commits.webkit.org/251845@main
  • Loading branch information
litherum committed Jun 25, 2022
1 parent 9e683e6 commit 78afcc4
Show file tree
Hide file tree
Showing 18 changed files with 82 additions and 39 deletions.
4 changes: 1 addition & 3 deletions Source/WebCore/page/Page.cpp
Expand Up @@ -437,9 +437,7 @@ void Page::firstTimeInitialization()
platformStrategies()->loaderStrategy()->addOnlineStateChangeListener(&networkStateChanged);

FontCache::registerFontCacheInvalidationCallback([] {
forEachPage([](auto& page) {
page.setNeedsRecalcStyleInAllFrames();
});
updateStyleForAllPagesAfterGlobalChangeInEnvironment();
});
}

Expand Down
6 changes: 3 additions & 3 deletions Source/WebCore/page/cocoa/MemoryReleaseCocoa.mm
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2015 Apple Inc. All rights reserved.
* Copyright (C) 2011-2022 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
Expand All @@ -26,14 +26,14 @@
#import "config.h"
#import "MemoryRelease.h"

#import "FontCache.h"
#import "FontFamilySpecificationCoreText.h"
#import "GCController.h"
#import "HTMLNameCache.h"
#import "IOSurfacePool.h"
#import "LayerPool.h"
#import "LocaleCocoa.h"
#import "SubimageCacheWithTimer.h"
#import "SystemFontDatabaseCoreText.h"
#import <notify.h>
#import <pal/spi/ios/GraphicsServicesSPI.h>

Expand All @@ -47,7 +47,7 @@

void platformReleaseMemory(Critical)
{
SystemFontDatabaseCoreText::singleton().clear();
FontCache::invalidateAllFontCaches(FontCache::ShouldRunInvalidationCallback::No);
clearFontFamilySpecificationCoreTextCache();

#if PLATFORM(IOS_FAMILY) && !PLATFORM(IOS_FAMILY_SIMULATOR) && !PLATFORM(MACCATALYST)
Expand Down
11 changes: 8 additions & 3 deletions Source/WebCore/platform/graphics/FontCache.cpp
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2006-2021 Apple Inc. All rights reserved.
* Copyright (C) 2006-2022 Apple Inc. All rights reserved.
* Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com>
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -35,6 +35,7 @@
#include "FontPlatformData.h"
#include "FontSelector.h"
#include "Logging.h"
#include "SystemFontDatabase.h"
#include "ThreadGlobalData.h"
#include "WebKitFontFamilyNames.h"
#include "WorkerOrWorkletThread.h"
Expand Down Expand Up @@ -481,6 +482,10 @@ void FontCache::invalidate()
#endif
invalidateFontCascadeCache();

SystemFontDatabase::singleton().invalidate();

platformInvalidate();

++m_generation;

for (auto& client : copyToVectorOf<RefPtr<FontSelector>>(m_clients))
Expand All @@ -500,14 +505,14 @@ void FontCache::registerFontCacheInvalidationCallback(Function<void()>&& callbac
fontCacheInvalidationCallback() = WTFMove(callback);
}

void FontCache::invalidateAllFontCaches()
void FontCache::invalidateAllFontCaches(ShouldRunInvalidationCallback shouldRunInvalidationCallback)
{
ASSERT(isMainThread());

// FIXME: Invalidate FontCaches in workers too.
FontCache::forCurrentThread().invalidate();

if (fontCacheInvalidationCallback())
if (shouldRunInvalidationCallback == ShouldRunInvalidationCallback::Yes && fontCacheInvalidationCallback())
fontCacheInvalidationCallback()();
}

Expand Down
19 changes: 16 additions & 3 deletions Source/WebCore/platform/graphics/FontCache.h
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2006-2021 Apple Inc. All rights reserved.
* Copyright (C) 2006-2022 Apple Inc. All rights reserved.
* Copyright (C) 2007-2008 Torch Mobile, Inc.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -327,9 +327,19 @@ class FontCache {
void removeClient(FontSelector&);

unsigned short generation() const { return m_generation; }
WEBCORE_EXPORT void invalidate();
static void registerFontCacheInvalidationCallback(Function<void()>&&);
WEBCORE_EXPORT static void invalidateAllFontCaches();

// The invalidation callback runs a style recalc on the page.
// If we're invalidating because of memory pressure, we shouldn't run a style recalc.
// A style recalc would just allocate a bunch of the memory that we're trying to release.
// On the other hand, if we're invalidating because the set of installed fonts changed,
// or if some accessibility text settings were altered, we should run a style recalc
// so the user can immediately see the effect of the new environment.
enum class ShouldRunInvalidationCallback : bool {
No,
Yes
};
WEBCORE_EXPORT static void invalidateAllFontCaches(ShouldRunInvalidationCallback = ShouldRunInvalidationCallback::Yes);

WEBCORE_EXPORT size_t fontCount();
WEBCORE_EXPORT size_t inactiveFontCount();
Expand Down Expand Up @@ -369,6 +379,9 @@ class FontCache {
static void prewarmGlobally();

private:
void invalidate();
void platformInvalidate();

WEBCORE_EXPORT void purgeInactiveFontDataIfNeeded();
void pruneUnreferencedEntriesFromFontCascadeCache();
void pruneSystemFallbackFonts();
Expand Down
3 changes: 2 additions & 1 deletion Source/WebCore/platform/graphics/SystemFontDatabase.cpp
Expand Up @@ -53,10 +53,11 @@ FontSelectionValue SystemFontDatabase::systemFontShorthandWeight(FontShorthand f
return systemFontShorthandInfo(fontShorthand).weight;
}

void SystemFontDatabase::clear()
void SystemFontDatabase::invalidate()
{
for (auto& item : m_systemFontShorthandCache)
item.reset();
platformInvalidate();
}

} // namespace WebCore
7 changes: 5 additions & 2 deletions Source/WebCore/platform/graphics/SystemFontDatabase.h
Expand Up @@ -74,12 +74,15 @@ class SystemFontDatabase {
float systemFontShorthandSize(FontShorthand);
FontSelectionValue systemFontShorthandWeight(FontShorthand);

WEBCORE_EXPORT void clear();

protected:
SystemFontDatabase();

private:
friend class FontCache;

void invalidate();
void platformInvalidate();

struct SystemFontShorthandInfo {
AtomString family;
float size;
Expand Down
25 changes: 10 additions & 15 deletions Source/WebCore/platform/graphics/cocoa/FontCacheCoreText.cpp
Expand Up @@ -796,13 +796,13 @@ static float stretchFromCoreTextTraits(CFDictionaryRef traits)
}
#endif

static void invalidateFontCache();

static void fontCacheRegisteredFontsChangedNotificationCallback(CFNotificationCenterRef, void* observer, CFStringRef, const void *, CFDictionaryRef)
{
ASSERT_UNUSED(observer, isMainThread() && observer == &FontCache::forCurrentThread());

invalidateFontCache();
ensureOnMainThread([] {
FontCache::invalidateAllFontCaches();
});
}

void FontCache::platformInit()
Expand Down Expand Up @@ -1287,20 +1287,15 @@ static FontLookup platformFontLookupWithFamily(const AtomString& family, FontSel
return { nullptr };
}

static void invalidateFontCache()
void FontCache::platformInvalidate()
{
ensureOnMainThread([] {
// FIXME: Workers need to access SystemFontDatabaseCoreText.
SystemFontDatabaseCoreText::singleton().clear();
// FIXME: Workers need to access FontFamilySpecificationCoreTextCache.
clearFontFamilySpecificationCoreTextCache();
// FIXME: Workers need to access SystemFontDatabaseCoreText.
// FIXME: Workers need to access FontFamilySpecificationCoreTextCache.
clearFontFamilySpecificationCoreTextCache();

// FIXME: Workers need to access FontDatabase.
FontDatabase::singletonAllowingUserInstalledFonts().clear();
FontDatabase::singletonDisallowingUserInstalledFonts().clear();

FontCache::invalidateAllFontCaches();
});
// FIXME: Workers need to access FontDatabase.
FontDatabase::singletonAllowingUserInstalledFonts().clear();
FontDatabase::singletonDisallowingUserInstalledFonts().clear();
}

static RetainPtr<CTFontRef> fontWithFamilySpecialCase(const AtomString& family, const FontDescription& fontDescription, float size, AllowUserInstalledFonts allowUserInstalledFonts)
Expand Down
Expand Up @@ -130,15 +130,20 @@ Vector<RetainPtr<CTFontDescriptorRef>> SystemFontDatabaseCoreText::cascadeList(c
}).iterator->value;
}

void SystemFontDatabase::platformInvalidate()
{
SystemFontDatabaseCoreText::singleton().clear();
}

void SystemFontDatabaseCoreText::clear()
{
// Don't call this directly. Instead, you should be calling FontCache::invalidateAllFontCaches().
m_systemFontCache.clear();
m_serifFamilies.clear();
m_sansSeriferifFamilies.clear();
m_cursiveFamilies.clear();
m_fantasyFamilies.clear();
m_monospaceFamilies.clear();
SystemFontDatabase::clear();
}

RetainPtr<CTFontRef> SystemFontDatabaseCoreText::createFontByApplyingWeightWidthItalicsAndFallbackBehavior(CTFontRef font, CGFloat weight, CGFloat width, bool italic, float size, AllowUserInstalledFonts allowUserInstalledFonts, CFStringRef design)
Expand Down
Expand Up @@ -101,6 +101,7 @@ class SystemFontDatabaseCoreText : public SystemFontDatabase {
float systemFontShorthandSize(FontShorthand);
FontSelectionValue systemFontShorthandWeight(FontShorthand);

protected:
void clear();

private:
Expand Down
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2008 Alp Toker <alp@atoker.com>
* Copyright (C) 2010 Igalia S.L.
* Copyright (C) 2022 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
Expand Down Expand Up @@ -681,4 +682,8 @@ String buildVariationSettings(FT_Face face, const FontDescription& fontDescripti
}
#endif // ENABLE(VARIATION_FONTS)

void FontCache::platformInvalidate()
{
}

}
Expand Up @@ -62,4 +62,8 @@ auto SystemFontDatabase::platformSystemFontShorthandInfo(FontShorthand) -> Syste
return result;
}

void SystemFontDatabase::platformInvalidate()
{
}

} // namespace WebCore
Expand Up @@ -45,4 +45,8 @@ auto SystemFontDatabase::platformSystemFontShorthandInfo(FontShorthand fontShort
return { WebKitFontFamilyNames::standardFamily, 16, normalWeightValue() };
}

void SystemFontDatabase::platformInvalidate()
{
}

} // namespace WebCore
6 changes: 5 additions & 1 deletion Source/WebCore/platform/graphics/win/FontCacheWin.cpp
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2006-2008, 2013-2014 Apple Inc. All rights reserved.
* Copyright (C) 2006-2022 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
Expand Down Expand Up @@ -714,4 +714,8 @@ std::optional<ASCIILiteral> FontCache::platformAlternateFamilyName(const String&
return std::nullopt;
}

void FontCache::platformInvalidate()
{
}

}
Expand Up @@ -85,4 +85,8 @@ auto SystemFontDatabase::platformSystemFontShorthandInfo(FontShorthand fontShort
return { logFont.lfFaceName, size, weight };
}

void SystemFontDatabase::platformInvalidate()
{
}

} // namespace WebCore
Expand Up @@ -45,4 +45,8 @@ auto SystemFontDatabase::platformSystemFontShorthandInfo(FontShorthand) -> Syste
return { WebKitFontFamilyNames::standardFamily, 16, normalWeightValue() };
}

void SystemFontDatabase::platformInvalidate()
{
}

} // namespace WebCore
5 changes: 2 additions & 3 deletions Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm
Expand Up @@ -87,6 +87,7 @@
#import <WebCore/File.h>
#import <WebCore/FloatQuad.h>
#import <WebCore/FocusController.h>
#import <WebCore/FontCache.h>
#import <WebCore/FontCacheCoreText.h>
#import <WebCore/Frame.h>
#import <WebCore/FrameLoaderClient.h>
Expand Down Expand Up @@ -142,7 +143,6 @@
#import <WebCore/ShadowRoot.h>
#import <WebCore/SharedBuffer.h>
#import <WebCore/StyleProperties.h>
#import <WebCore/SystemFontDatabase.h>
#import <WebCore/TextIndicator.h>
#import <WebCore/TextIterator.h>
#import <WebCore/TextPlaceholderElement.h>
Expand Down Expand Up @@ -4395,8 +4395,7 @@ static bool selectionIsInsideFixedPositionContainer(Frame& frame)
void WebPage::contentSizeCategoryDidChange(const String& contentSizeCategory)
{
setContentSizeCategory(contentSizeCategory);
SystemFontDatabase::singleton().clear();
Page::updateStyleForAllPagesAfterGlobalChangeInEnvironment();
FontCache::invalidateAllFontCaches();
}

String WebPage::platformUserAgent(const URL&) const
Expand Down
2 changes: 1 addition & 1 deletion Source/WebKit/WebProcess/WebProcess.cpp
Expand Up @@ -893,7 +893,7 @@ void WebProcess::terminate()
#ifndef NDEBUG
// These are done in an attempt to reduce LEAK output.
GCController::singleton().garbageCollectNow();
FontCache::forCurrentThread().invalidate();
FontCache::invalidateAllFontCaches();
MemoryCache::singleton().setDisabled(true);
#endif

Expand Down
4 changes: 1 addition & 3 deletions Source/WebKit/WebProcess/cocoa/WebProcessCocoa.mm
Expand Up @@ -83,7 +83,6 @@
#import <WebCore/RuntimeEnabledFeatures.h>
#import <WebCore/SWContextManager.h>
#import <WebCore/SystemBattery.h>
#import <WebCore/SystemFontDatabase.h>
#import <WebCore/SystemSoundManager.h>
#import <WebCore/UTIUtilities.h>
#import <WebCore/WebMAudioUtilitiesCocoa.h>
Expand Down Expand Up @@ -1019,8 +1018,7 @@ static float currentBacklightLevel()
auto invertColorsEnabled = preferences.invertColorsEnabled;
if (_AXSInvertColorsEnabledApp(appID) != invertColorsEnabled)
_AXSInvertColorsSetEnabledApp(invertColorsEnabled, appID);
SystemFontDatabase::singleton().clear();
Page::updateStyleForAllPagesAfterGlobalChangeInEnvironment();
FontCache::invalidateAllFontCaches();
#endif
}

Expand Down

0 comments on commit 78afcc4

Please sign in to comment.