Bug 1895926 - Call ASystemFontIterator_open on background thread at start up. r=jfkthame
When Android 12+, `ASystemFontIterator_open` doesn't read font configuration XML file directly to support font update. So it causes that first call of it becomes too slow. So I would like to call it on background thread at start up to initialize internal data in Android. This fox improves 50-100ms on `gfxPlatform::Init`. Gecko already uses similar to it for macOS and Windows (DirectWrite). Differential Revision: https://phabricator.services.mozilla.com/D224896
This commit is contained in:
106
gfx/thebes/AndroidSystemFontIterator.cpp
Normal file
106
gfx/thebes/AndroidSystemFontIterator.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "AndroidSystemFontIterator.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "nsDebug.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
_ASystemFontIterator_open AndroidSystemFontIterator::sSystemFontIterator_open =
|
||||
nullptr;
|
||||
_ASystemFontIterator_next AndroidSystemFontIterator::sSystemFontIterator_next =
|
||||
nullptr;
|
||||
_ASystemFontIterator_close
|
||||
AndroidSystemFontIterator::sSystemFontIterator_close = nullptr;
|
||||
|
||||
_AFont_getFontFilePath AndroidFont::sFont_getFontFilePath = nullptr;
|
||||
_AFont_close AndroidFont::sFont_close = nullptr;
|
||||
|
||||
AndroidSystemFontIterator::~AndroidSystemFontIterator() {
|
||||
if (!sSystemFontIterator_open) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mIterator) {
|
||||
return;
|
||||
}
|
||||
|
||||
sSystemFontIterator_close(mIterator);
|
||||
}
|
||||
|
||||
bool AndroidSystemFontIterator::Init() {
|
||||
if (!sSystemFontIterator_open) {
|
||||
void* handle = dlopen("libandroid.so", RTLD_LAZY | RTLD_LOCAL);
|
||||
MOZ_ASSERT(handle);
|
||||
|
||||
sSystemFontIterator_open =
|
||||
(_ASystemFontIterator_open)dlsym(handle, "ASystemFontIterator_open");
|
||||
sSystemFontIterator_next =
|
||||
(_ASystemFontIterator_next)dlsym(handle, "ASystemFontIterator_next");
|
||||
sSystemFontIterator_close =
|
||||
(_ASystemFontIterator_close)dlsym(handle, "ASystemFontIterator_close");
|
||||
AndroidFont::sFont_getFontFilePath =
|
||||
(_AFont_getFontFilePath)dlsym(handle, "AFont_getFontFilePath");
|
||||
AndroidFont::sFont_close = (_AFont_close)dlsym(handle, "AFont_close");
|
||||
|
||||
if (NS_WARN_IF(!sSystemFontIterator_open) ||
|
||||
NS_WARN_IF(!sSystemFontIterator_next) ||
|
||||
NS_WARN_IF(!sSystemFontIterator_close) ||
|
||||
NS_WARN_IF(!AndroidFont::sFont_getFontFilePath) ||
|
||||
NS_WARN_IF(!AndroidFont::sFont_close)) {
|
||||
sSystemFontIterator_open = nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
mIterator = sSystemFontIterator_open();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Maybe<AndroidFont> AndroidSystemFontIterator::Next() {
|
||||
if (NS_WARN_IF(!sSystemFontIterator_open)) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
if (!mIterator) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
void* font = sSystemFontIterator_next(mIterator);
|
||||
if (!font) {
|
||||
sSystemFontIterator_close(mIterator);
|
||||
mIterator = nullptr;
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
return Some(AndroidFont(font));
|
||||
}
|
||||
|
||||
AndroidFont::~AndroidFont() {
|
||||
if (NS_WARN_IF(!sFont_close)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mFont) {
|
||||
return;
|
||||
}
|
||||
|
||||
sFont_close(mFont);
|
||||
}
|
||||
|
||||
const char* AndroidFont::GetFontFilePath() {
|
||||
if (NS_WARN_IF(!sFont_getFontFilePath) || NS_WARN_IF(!mFont)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return sFont_getFontFilePath(mFont);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
65
gfx/thebes/AndroidSystemFontIterator.h
Normal file
65
gfx/thebes/AndroidSystemFontIterator.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef AndroidSystemFontIterator_h__
|
||||
#define AndroidSystemFontIterator_h__
|
||||
|
||||
#include "mozilla/Maybe.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
typedef void* (*_ASystemFontIterator_open)();
|
||||
typedef void* (*_ASystemFontIterator_next)(void*);
|
||||
typedef void (*_ASystemFontIterator_close)(void*);
|
||||
|
||||
typedef const char* (*_AFont_getFontFilePath)(const void*);
|
||||
typedef void (*_AFont_close)(void*);
|
||||
|
||||
class AndroidFont final {
|
||||
public:
|
||||
explicit AndroidFont(void* aFont) : mFont(aFont) {};
|
||||
|
||||
AndroidFont() = delete;
|
||||
AndroidFont(AndroidFont&) = delete;
|
||||
|
||||
AndroidFont(AndroidFont&& aSrc) {
|
||||
mFont = aSrc.mFont;
|
||||
aSrc.mFont = nullptr;
|
||||
}
|
||||
|
||||
~AndroidFont();
|
||||
|
||||
const char* GetFontFilePath();
|
||||
|
||||
private:
|
||||
void* mFont;
|
||||
|
||||
static _AFont_getFontFilePath sFont_getFontFilePath;
|
||||
static _AFont_close sFont_close;
|
||||
|
||||
friend class AndroidSystemFontIterator;
|
||||
};
|
||||
|
||||
class AndroidSystemFontIterator final {
|
||||
public:
|
||||
AndroidSystemFontIterator() = default;
|
||||
|
||||
~AndroidSystemFontIterator();
|
||||
|
||||
bool Init();
|
||||
|
||||
Maybe<AndroidFont> Next();
|
||||
|
||||
private:
|
||||
void* mIterator = nullptr;
|
||||
|
||||
static _ASystemFontIterator_open sSystemFontIterator_open;
|
||||
static _ASystemFontIterator_next sSystemFontIterator_next;
|
||||
static _ASystemFontIterator_close sSystemFontIterator_close;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
@@ -20,6 +20,9 @@
|
||||
#include "mozilla/StaticPrefs_webgl.h"
|
||||
#include "mozilla/widget/AndroidVsync.h"
|
||||
|
||||
#include "AndroidBuild.h"
|
||||
#include "AndroidSystemFontIterator.h"
|
||||
#include "GeckoProfiler.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#include "gfxFT2FontList.h"
|
||||
#include "gfxImageSurface.h"
|
||||
@@ -73,6 +76,67 @@ NS_IMPL_ISUPPORTS(FreetypeReporter, nsIMemoryReporter)
|
||||
|
||||
static FT_MemoryRec_ sFreetypeMemoryRecord;
|
||||
|
||||
void gfxAndroidPlatform::FontAPIInitializeCallback(void* aUnused) {
|
||||
AUTO_PROFILER_REGISTER_THREAD("InitializingFontAPI");
|
||||
PR_SetCurrentThreadName("InitializingFontAPI");
|
||||
|
||||
// Call ASystemFontIterator_open
|
||||
AndroidSystemFontIterator iterator;
|
||||
iterator.Init();
|
||||
}
|
||||
|
||||
PRThread* gfxAndroidPlatform::sFontAPIInitializeThread = nullptr;
|
||||
nsCString gfxAndroidPlatform::sManufacturer;
|
||||
|
||||
// static
|
||||
bool gfxAndroidPlatform::IsFontAPIDisabled(bool aDontCheckPref) {
|
||||
if (!aDontCheckPref &&
|
||||
StaticPrefs::gfx_font_list_use_font_match_api_force_enabled_AtStartup()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// OPPO, realme and OnePlus device seem to crash when using font match API
|
||||
// (Bug 1787551).
|
||||
|
||||
if (sManufacturer.IsEmpty()) {
|
||||
sManufacturer = java::sdk::Build::MANUFACTURER()->ToCString();
|
||||
}
|
||||
return (sManufacturer.EqualsLiteral("OPPO") ||
|
||||
sManufacturer.EqualsLiteral("realme") ||
|
||||
sManufacturer.EqualsLiteral("OnePlus"));
|
||||
}
|
||||
|
||||
// static
|
||||
void gfxAndroidPlatform::InitializeFontAPI() {
|
||||
if (XRE_GetProcessType() != GeckoProcessType_Default) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Android 12+ doesn't read font configuration XML files directly.
|
||||
// It means that it is slow to call font API at first.
|
||||
if (jni::GetAPIVersion() < 31) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This will be called before XPCOM service isn't started. So don't check
|
||||
// preferences.
|
||||
if (IsFontAPIDisabled(true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
sFontAPIInitializeThread = PR_CreateThread(
|
||||
PR_USER_THREAD, FontAPIInitializeCallback, nullptr, PR_PRIORITY_NORMAL,
|
||||
PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
|
||||
}
|
||||
|
||||
// static
|
||||
void gfxAndroidPlatform::WaitForInitializeFontAPI() {
|
||||
if (sFontAPIInitializeThread) {
|
||||
PR_JoinThread(sFontAPIInitializeThread);
|
||||
sFontAPIInitializeThread = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
gfxAndroidPlatform::gfxAndroidPlatform() {
|
||||
// A custom allocator. It counts allocations, enabling memory reporting.
|
||||
sFreetypeMemoryRecord.user = nullptr;
|
||||
|
||||
@@ -42,13 +42,26 @@ class gfxAndroidPlatform final : public gfxPlatform {
|
||||
|
||||
static bool CheckVariationFontSupport();
|
||||
|
||||
// From Android 12, Font API doesn't read XML files only. To handle updated
|
||||
// font, initializing font API causes that it analyzes all font files. So we
|
||||
// have to call this API at start up on another thread to initialize it.
|
||||
static void InitializeFontAPI();
|
||||
static void WaitForInitializeFontAPI();
|
||||
|
||||
static bool IsFontAPIDisabled(bool aDontCheckPref = false);
|
||||
|
||||
protected:
|
||||
void InitAcceleration() override;
|
||||
|
||||
bool AccelerateLayersByDefault() override { return true; }
|
||||
|
||||
private:
|
||||
static void FontAPIInitializeCallback(void*);
|
||||
|
||||
gfxImageFormat mOffscreenFormat;
|
||||
|
||||
static PRThread* sFontAPIInitializeThread;
|
||||
static nsCString sManufacturer;
|
||||
};
|
||||
|
||||
#endif /* GFX_PLATFORM_ANDROID_H */
|
||||
|
||||
@@ -60,8 +60,8 @@
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
# include "AndroidBuild.h"
|
||||
# include "AndroidSystemFontIterator.h"
|
||||
# include "mozilla/jni/Utils.h"
|
||||
# include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
@@ -1556,19 +1556,6 @@ void gfxFT2FontList::FindFonts() {
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
// Android API 29+ provides system font and font matcher API for native code.
|
||||
typedef void* (*_ASystemFontIterator_open)();
|
||||
typedef void* (*_ASystemFontIterator_next)(void*);
|
||||
typedef void (*_ASystemFontIterator_close)(void*);
|
||||
typedef const char* (*_AFont_getFontFilePath)(const void*);
|
||||
typedef void (*_AFont_close)(void*);
|
||||
|
||||
static _ASystemFontIterator_open systemFontIterator_open = nullptr;
|
||||
static _ASystemFontIterator_next systemFontIterator_next = nullptr;
|
||||
static _ASystemFontIterator_close systemFontIterator_close = nullptr;
|
||||
static _AFont_getFontFilePath font_getFontFilePath = nullptr;
|
||||
static _AFont_close font_close = nullptr;
|
||||
|
||||
static bool firstTime = true;
|
||||
|
||||
nsAutoCString androidFontsRoot = [&] {
|
||||
// ANDROID_ROOT is the root of the android system, typically /system;
|
||||
@@ -1584,71 +1571,36 @@ void gfxFT2FontList::FindFonts() {
|
||||
return root;
|
||||
}();
|
||||
|
||||
if (firstTime) {
|
||||
if (jni::GetAPIVersion() >= 29) {
|
||||
void* handle = dlopen("libandroid.so", RTLD_LAZY | RTLD_LOCAL);
|
||||
MOZ_ASSERT(handle);
|
||||
|
||||
systemFontIterator_open =
|
||||
(_ASystemFontIterator_open)dlsym(handle, "ASystemFontIterator_open");
|
||||
systemFontIterator_next =
|
||||
(_ASystemFontIterator_next)dlsym(handle, "ASystemFontIterator_next");
|
||||
systemFontIterator_close = (_ASystemFontIterator_close)dlsym(
|
||||
handle, "ASystemFontIterator_close");
|
||||
font_getFontFilePath =
|
||||
(_AFont_getFontFilePath)dlsym(handle, "AFont_getFontFilePath");
|
||||
font_close = (_AFont_close)dlsym(handle, "AFont_close");
|
||||
|
||||
if (NS_WARN_IF(!systemFontIterator_next) ||
|
||||
NS_WARN_IF(!systemFontIterator_close) ||
|
||||
NS_WARN_IF(!font_getFontFilePath) || NS_WARN_IF(!font_close)) {
|
||||
// Since any functions aren't resolved, use old way to enumerate fonts.
|
||||
systemFontIterator_open = nullptr;
|
||||
}
|
||||
}
|
||||
firstTime = false;
|
||||
}
|
||||
|
||||
bool useSystemFontAPI = !!systemFontIterator_open;
|
||||
|
||||
if (useSystemFontAPI &&
|
||||
!StaticPrefs::
|
||||
gfx_font_list_use_font_match_api_force_enabled_AtStartup()) {
|
||||
// OPPO, realme and OnePlus device seem to crash when using font match API
|
||||
// (Bug 1787551).
|
||||
nsCString manufacturer = java::sdk::Build::MANUFACTURER()->ToCString();
|
||||
if (manufacturer.EqualsLiteral("OPPO") ||
|
||||
manufacturer.EqualsLiteral("realme") ||
|
||||
manufacturer.EqualsLiteral("OnePlus")) {
|
||||
useSystemFontAPI = false;
|
||||
}
|
||||
}
|
||||
bool useSystemFontAPI = !gfxAndroidPlatform::IsFontAPIDisabled();
|
||||
|
||||
if (useSystemFontAPI) {
|
||||
void* iter = systemFontIterator_open();
|
||||
if (iter) {
|
||||
void* font = systemFontIterator_next(iter);
|
||||
while (font) {
|
||||
nsDependentCString path(font_getFontFilePath(font));
|
||||
AppendFacesFromFontFile(path, mFontNameCache.get(), kStandard);
|
||||
font_close(font);
|
||||
font = systemFontIterator_next(iter);
|
||||
}
|
||||
gfxAndroidPlatform::WaitForInitializeFontAPI();
|
||||
|
||||
if (!StaticPrefs::gfx_font_rendering_colr_v1_enabled()) {
|
||||
// We turn off COLRv1 fonts support. Newer android versions have
|
||||
// COLRv1 emoji font, and a legacy and hidden CBDT font we understand,
|
||||
// so try to find NotoColorEmojiLegacy.ttf explicitly for now.
|
||||
nsAutoCString legacyEmojiFont(androidFontsRoot);
|
||||
legacyEmojiFont.Append("/NotoColorEmojiLegacy.ttf");
|
||||
AppendFacesFromFontFile(legacyEmojiFont, mFontNameCache.get(),
|
||||
kStandard);
|
||||
bool noFontByFontAPI = true;
|
||||
AndroidSystemFontIterator iter;
|
||||
if (iter.Init()) {
|
||||
while (Maybe<AndroidFont> androidFont = iter.Next()) {
|
||||
if (const char* fontPath = androidFont->GetFontFilePath()) {
|
||||
noFontByFontAPI = false;
|
||||
AppendFacesFromFontFile(nsDependentCString(fontPath),
|
||||
mFontNameCache.get(), kStandard);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
systemFontIterator_close(iter);
|
||||
} else {
|
||||
if (noFontByFontAPI) {
|
||||
// Font API doesn't seem to work. Use legacy way.
|
||||
useSystemFontAPI = false;
|
||||
}
|
||||
|
||||
if (!StaticPrefs::gfx_font_rendering_colr_v1_enabled()) {
|
||||
// We turn off COLRv1 fonts support. Newer android versions have
|
||||
// COLRv1 emoji font, and a legacy and hidden CBDT font we understand,
|
||||
// so try to find NotoColorEmojiLegacy.ttf explicitly for now.
|
||||
nsAutoCString legacyEmojiFont(androidFontsRoot);
|
||||
legacyEmojiFont.Append("/NotoColorEmojiLegacy.ttf");
|
||||
AppendFacesFromFontFile(legacyEmojiFont, mFontNameCache.get(), kStandard);
|
||||
}
|
||||
}
|
||||
|
||||
if (!useSystemFontAPI)
|
||||
|
||||
@@ -96,6 +96,9 @@ if CONFIG["MOZ_WIDGET_TOOLKIT"] == "android":
|
||||
"gfxFT2Utils.cpp",
|
||||
"PrintTargetPDF.cpp",
|
||||
]
|
||||
UNIFIED_SOURCES += [
|
||||
"AndroidSystemFontIterator.cpp",
|
||||
]
|
||||
elif CONFIG["MOZ_WIDGET_TOOLKIT"] in ("cocoa", "uikit"):
|
||||
EXPORTS += [
|
||||
"gfxMacUtils.h",
|
||||
|
||||
@@ -229,6 +229,7 @@
|
||||
#include "GTestRunner.h"
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
# include "gfxAndroidPlatform.h"
|
||||
# include "mozilla/java/GeckoAppShellWrappers.h"
|
||||
#endif
|
||||
|
||||
@@ -5845,6 +5846,12 @@ int XREMain::XRE_main(int argc, char* argv[], const BootstrapConfig& aConfig) {
|
||||
gfxPlatformMac::RegisterSupplementalFonts();
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
// We call the early because we run system font API on a background-thread
|
||||
// to initialize internal font API data in Android. (Bug 1895926)
|
||||
gfxAndroidPlatform::InitializeFontAPI();
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_CODE_COVERAGE
|
||||
CodeCoverageHandler::Init();
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user