Commit e7fcc1a5 authored by Dominik Röttsches's avatar Dominik Röttsches Committed by Commit Bot

Experiment: Schedule font unique name lookup table build at startup

Modify DWriteFontLookupTableBuilder to support off-main-thread
scheduling of the font unique name lookup table construction.

For now, schedule this as a USER_BLOCKING-prioritized startup task in a
separate SequencedTaskRunner. Synchronize using a WaitableEvent that the
DWriteFontProxyImpl can wait on when it receives an incoming Mojo
request from a renderer for this table.

Once the UpdatePriority() API for SequencedTaskRunners becomes
available, downgrade the priority to BEST_EFFORT, then bump it once the
renderer requests the table. This TODO is tracked in [1].

Background for font unique name local lookups in the design review doc
in https://crbug.com/828317. See also startup job scheduling discussion
in [2].

[1] https://crbug.com/931366
[2] https://groups.google.com/a/chromium.org/d/msg/chromium-dev/iDClDAsZnrE/bb5eZXkUFAAJ

Bug: 889864
Change-Id: I8e19d34520422fc9404ca01cb8357221d7a11495
Reviewed-on: https://chromium-review.googlesource.com/c/1459635
Commit-Queue: Dominik Röttsches <drott@chromium.org>
Reviewed-by: default avatarEmil A Eklund <eae@chromium.org>
Reviewed-by: default avatarGabriel Charette <gab@chromium.org>
Cr-Commit-Position: refs/heads/master@{#632008}
parent 5aa91af7
...@@ -133,6 +133,7 @@ class BrowserShutdownProfileDumper; ...@@ -133,6 +133,7 @@ class BrowserShutdownProfileDumper;
class BrowserTestBase; class BrowserTestBase;
class CategorizedWorkerPool; class CategorizedWorkerPool;
class DesktopCaptureDevice; class DesktopCaptureDevice;
class DWriteFontLookupTableBuilder;
class GpuProcessTransportFactory; class GpuProcessTransportFactory;
class NestedMessagePumpAndroid; class NestedMessagePumpAndroid;
class SandboxHostLinux; class SandboxHostLinux;
...@@ -374,6 +375,7 @@ class BASE_EXPORT ScopedAllowBaseSyncPrimitives { ...@@ -374,6 +375,7 @@ class BASE_EXPORT ScopedAllowBaseSyncPrimitives {
friend class base::GetAppOutputScopedAllowBaseSyncPrimitives; friend class base::GetAppOutputScopedAllowBaseSyncPrimitives;
friend class content::BrowserMainLoop; friend class content::BrowserMainLoop;
friend class content::BrowserProcessSubThread; friend class content::BrowserProcessSubThread;
friend class content::DWriteFontLookupTableBuilder;
friend class content::ServiceWorkerContextClient; friend class content::ServiceWorkerContextClient;
friend class content::SessionStorageDatabase; friend class content::SessionStorageDatabase;
friend class functions::ExecScriptScopedAllowBaseSyncPrimitives; friend class functions::ExecScriptScopedAllowBaseSyncPrimitives;
......
...@@ -188,6 +188,7 @@ ...@@ -188,6 +188,7 @@
#include <shellapi.h> #include <shellapi.h>
#include "base/memory/memory_pressure_monitor_win.h" #include "base/memory/memory_pressure_monitor_win.h"
#include "content/browser/renderer_host/dwrite_font_lookup_table_builder_win.h"
#include "net/base/winsock_init.h" #include "net/base/winsock_init.h"
#include "services/service_manager/sandbox/win/sandbox_win.h" #include "services/service_manager/sandbox/win/sandbox_win.h"
#include "ui/display/win/screen_win.h" #include "ui/display/win/screen_win.h"
...@@ -1440,6 +1441,11 @@ int BrowserMainLoop::BrowserThreadsStarted() { ...@@ -1440,6 +1441,11 @@ int BrowserMainLoop::BrowserThreadsStarted() {
switches::kDisableGpuProcessForDX12VulkanInfoCollection)) { switches::kDisableGpuProcessForDX12VulkanInfoCollection)) {
GpuDataManagerImpl::GetInstance()->RequestGpuSupportedRuntimeVersion(); GpuDataManagerImpl::GetInstance()->RequestGpuSupportedRuntimeVersion();
} }
if (base::FeatureList::IsEnabled(features::kFontSrcLocalMatching)) {
content::DWriteFontLookupTableBuilder::GetInstance()
->ScheduleBuildFontUniqueNameTable();
}
#endif #endif
if (MediaKeysListenerManager::IsMediaKeysListenerManagerEnabled()) { if (MediaKeysListenerManager::IsMediaKeysListenerManagerEnabled()) {
......
...@@ -8,12 +8,18 @@ ...@@ -8,12 +8,18 @@
#include <dwrite.h> #include <dwrite.h>
#include <dwrite_2.h> #include <dwrite_2.h>
#include <wrl.h> #include <wrl.h>
#include <memory>
#include <string>
#include <vector>
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/read_only_shared_memory_region.h" #include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/singleton.h" #include "base/memory/singleton.h"
#include "base/optional.h"
#include "base/synchronization/waitable_event.h" #include "base/synchronization/waitable_event.h"
#include "base/time/time.h"
#include "content/common/content_export.h" #include "content/common/content_export.h"
#include "third_party/blink/public/common/font_unique_name_lookup/font_unique_name_table.pb.h"
namespace base { namespace base {
template <typename T> template <typename T>
...@@ -25,47 +31,92 @@ namespace content { ...@@ -25,47 +31,92 @@ namespace content {
// Singleton class which encapsulates building the font unique name table lookup // Singleton class which encapsulates building the font unique name table lookup
// once, then serving the built table as a ReadOnlySharedMemoryRegion. Receives // once, then serving the built table as a ReadOnlySharedMemoryRegion. Receives
// requests for accessing this table from DWriteFontProxyImpl after Mojo IPC // requests for accessing this table from DWriteFontProxyImpl after Mojo IPC
// calls from the renderer. // calls from the renderer. A method ScheduleBuildFontUniqueNameTable() is
// provided to schedule building the font unique name lookup
// structure. EnsureFontUniqueNameTable() can be called on any thread to wait
// for the lookup table to be ready. After that, DuplicateMemoryRegion() can be
// used to retrieve the lookup structure. Thread-safe when used as described
// below.
class CONTENT_EXPORT DWriteFontLookupTableBuilder { class CONTENT_EXPORT DWriteFontLookupTableBuilder {
public: public:
static DWriteFontLookupTableBuilder* GetInstance(); static DWriteFontLookupTableBuilder* GetInstance();
void SetSlowDownIndexingForTesting(bool);
// Needed to trigger rebuilding the lookup table, when testing using
// slowed-down indexing. Otherwise, the test methods would use the already
// cached lookup table.
void ResetLookupTableForTesting();
// Retrieve the prepared memory region if it is available. // Retrieve the prepared memory region if it is available.
// EnsureFontUniqueNameTable() should be checked before. This method hits an // EnsureFontUniqueNameTable() must be checked before.
// assertion otherwise. base::ReadOnlySharedMemoryRegion DuplicateMemoryRegion();
base::ReadOnlySharedMemoryRegion DuplicatedMemoryRegion();
// Wait for the internal WaitableEvent to be signaled if needed and return // Wait for the internal WaitableEvent to be signaled if needed and return
// true if the font unique name lookup table was successfully constructed. // true if the font unique name lookup table was successfully
// constructed. Call only after ScheduleBuildFontUniqueNameTable().
bool EnsureFontUniqueNameTable(); bool EnsureFontUniqueNameTable();
// Posts a task to build the font unique name table index, should only be
// called once at browser startup, after that, use EnsureFontUniqueNameTable()
// and DuplicatedMemoryRegion() to retrieve the lookup structure buffer.
void ScheduleBuildFontUniqueNameTable();
enum class SlowDownMode { kDelayEachTask, kHangOneTask, kNoSlowdown };
// Slow down each family indexing step for testing the internal timeout.
void SetSlowDownIndexingForTesting(SlowDownMode slowdown_mode);
// Needed to trigger rebuilding the lookup table, when testing using
// slowed-down indexing. Otherwise, the test methods would use the already
// cached lookup table.
void ResetLookupTableForTesting();
// Signals hang_event_for_testing_ which is used in testing hanging one of the
// font name retrieval tasks.
void ResumeFromHangForTesting();
private: private:
friend class base::NoDestructor<DWriteFontLookupTableBuilder>; friend class base::NoDestructor<DWriteFontLookupTableBuilder>;
struct FontFileWithUniqueNames {
FontFileWithUniqueNames(blink::FontUniqueNameTable_UniqueFont&& font,
std::vector<std::string>&& names);
~FontFileWithUniqueNames();
FontFileWithUniqueNames(
DWriteFontLookupTableBuilder::FontFileWithUniqueNames&& other);
FontFileWithUniqueNames(const FontFileWithUniqueNames&) = delete;
FontFileWithUniqueNames& operator=(const FontFileWithUniqueNames&) = delete;
blink::FontUniqueNameTable_UniqueFont font_entry;
std::vector<std::string> extracted_names;
};
using FamilyResult = std::vector<FontFileWithUniqueNames>;
void BuildFontUniqueNameTable(); void BuildFontUniqueNameTable();
static FamilyResult ExtractPathAndNamesFromFamily(
Microsoft::WRL::ComPtr<IDWriteFontCollection> collection,
uint32_t family_index,
base::TimeTicks start_time,
SlowDownMode slow_down_mode,
base::WaitableEvent* hang_event_for_testing);
void AppendFamilyResultAndFinalizeIfNeeded(const FamilyResult& family_result);
void FinalizeFontTable();
void OnTimeout();
bool IsFontUniqueNameTableValid(); bool IsFontUniqueNameTableValid();
// Checks if the unique font table has been built already, and if not, builds
// it by enumerating fonts from the collection, extracting their file
// locations, ttc indices and names.
void InitializeDirectWrite(); void InitializeDirectWrite();
DWriteFontLookupTableBuilder(); DWriteFontLookupTableBuilder();
~DWriteFontLookupTableBuilder(); ~DWriteFontLookupTableBuilder();
// This can only be replaced from the construction sequence. Once // Protobuf structure temporarily used and shared during table construction.
// font_table_built_ is signaled, it can be read from everywhere. std::unique_ptr<blink::FontUniqueNameTable> font_unique_name_table_;
base::MappedReadOnlyRegion font_table_memory_; base::MappedReadOnlyRegion font_table_memory_;
base::WaitableEvent font_table_built_;
bool direct_write_initialized_ = false; bool direct_write_initialized_ = false;
Microsoft::WRL::ComPtr<IDWriteFontCollection> collection_; Microsoft::WRL::ComPtr<IDWriteFontCollection> collection_;
Microsoft::WRL::ComPtr<IDWriteFactory2> factory2_; Microsoft::WRL::ComPtr<IDWriteFactory2> factory2_;
bool slow_down_indexing_for_testing_ = false; SlowDownMode slow_down_mode_for_testing_ = SlowDownMode::kNoSlowdown;
uint32_t outstanding_family_results_ = 0;
base::TimeTicks start_time_;
base::Optional<base::WaitableEvent> hang_event_for_testing_;
DISALLOW_COPY_AND_ASSIGN(DWriteFontLookupTableBuilder); DISALLOW_COPY_AND_ASSIGN(DWriteFontLookupTableBuilder);
}; };
......
...@@ -9,7 +9,9 @@ ...@@ -9,7 +9,9 @@
#include <vector> #include <vector>
#include "base/files/file.h" #include "base/files/file.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/scoped_task_environment.h" #include "base/test/scoped_task_environment.h"
#include "content/public/common/content_features.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/font_unique_name_lookup/font_table_matcher.h" #include "third_party/blink/public/common/font_unique_name_lookup/font_table_matcher.h"
...@@ -25,57 +27,86 @@ std::vector<std::pair<std::string, uint32_t>> expected_test_fonts = { ...@@ -25,57 +27,86 @@ std::vector<std::pair<std::string, uint32_t>> expected_test_fonts = {
class DWriteFontLookupTableBuilderTest : public testing::Test { class DWriteFontLookupTableBuilderTest : public testing::Test {
public: public:
DWriteFontLookupTableBuilderTest() = default; DWriteFontLookupTableBuilderTest()
: scoped_task_environment_(
base::test::ScopedTaskEnvironment::ExecutionMode::ASYNC) {
feature_list_.InitAndEnableFeature(features::kFontSrcLocalMatching);
}
void SetUp() override {
font_lookup_table_builder_ = DWriteFontLookupTableBuilder::GetInstance();
font_lookup_table_builder_->ResetLookupTableForTesting();
}
protected:
DWriteFontLookupTableBuilder* font_lookup_table_builder_;
private: private:
base::test::ScopedFeatureList feature_list_;
base::test::ScopedTaskEnvironment scoped_task_environment_; base::test::ScopedTaskEnvironment scoped_task_environment_;
}; };
class DWriteFontLookupTableBuilderTimeoutTest
: public DWriteFontLookupTableBuilderTest,
public ::testing::WithParamInterface<
DWriteFontLookupTableBuilder::SlowDownMode> {};
} // namespace } // namespace
// Run a test similar to DWriteFontProxyImplUnitTest, TestFindUniqueFont but // Run a test similar to DWriteFontProxyImplUnitTest, TestFindUniqueFont but
// without going through Mojo and running it on the DWRiteFontLookupTableBuilder // without going through Mojo and running it on the DWRiteFontLookupTableBuilder
// class directly. // class directly.
TEST_F(DWriteFontLookupTableBuilderTest, TestFindUniqueFontDirect) { TEST_F(DWriteFontLookupTableBuilderTest, TestFindUniqueFontDirect) {
DWriteFontLookupTableBuilder* font_lookup_table_builder = font_lookup_table_builder_->ScheduleBuildFontUniqueNameTable();
DWriteFontLookupTableBuilder::GetInstance(); font_lookup_table_builder_->EnsureFontUniqueNameTable();
font_lookup_table_builder->EnsureFontUniqueNameTable();
base::ReadOnlySharedMemoryRegion font_table_memory = base::ReadOnlySharedMemoryRegion font_table_memory =
font_lookup_table_builder->DuplicatedMemoryRegion(); font_lookup_table_builder_->DuplicateMemoryRegion();
blink::FontTableMatcher font_table_matcher(font_table_memory.Map()); blink::FontTableMatcher font_table_matcher(font_table_memory.Map());
for (auto& test_font_name_index : expected_test_fonts) { for (auto& test_font_name_index : expected_test_fonts) {
base::Optional<blink::FontTableMatcher::MatchResult> match_result = base::Optional<blink::FontTableMatcher::MatchResult> match_result =
font_table_matcher.MatchName(test_font_name_index.first); font_table_matcher.MatchName(test_font_name_index.first);
CHECK(match_result) << "No font matched for font name: " ASSERT_TRUE(match_result)
<< test_font_name_index.first; << "No font matched for font name: " << test_font_name_index.first;
base::File unique_font_file( base::File unique_font_file(
base::FilePath::FromUTF8Unsafe(match_result->font_path), base::FilePath::FromUTF8Unsafe(match_result->font_path),
base::File::FLAG_OPEN | base::File::FLAG_READ); base::File::FLAG_OPEN | base::File::FLAG_READ);
CHECK(unique_font_file.IsValid()); ASSERT_TRUE(unique_font_file.IsValid());
CHECK_GT(unique_font_file.GetLength(), 0); ASSERT_GT(unique_font_file.GetLength(), 0);
CHECK_EQ(test_font_name_index.second, match_result->ttc_index); ASSERT_EQ(test_font_name_index.second, match_result->ttc_index);
} }
} }
TEST_F(DWriteFontLookupTableBuilderTest, TestTimeout) { TEST_P(DWriteFontLookupTableBuilderTimeoutTest, TestTimeout) {
DWriteFontLookupTableBuilder* font_lookup_table_builder = font_lookup_table_builder_->SetSlowDownIndexingForTesting(GetParam());
DWriteFontLookupTableBuilder::GetInstance(); font_lookup_table_builder_->ScheduleBuildFontUniqueNameTable();
font_lookup_table_builder->ResetLookupTableForTesting(); font_lookup_table_builder_->EnsureFontUniqueNameTable();
font_lookup_table_builder->SetSlowDownIndexingForTesting(true);
font_lookup_table_builder->EnsureFontUniqueNameTable();
base::ReadOnlySharedMemoryRegion font_table_memory = base::ReadOnlySharedMemoryRegion font_table_memory =
font_lookup_table_builder->DuplicatedMemoryRegion(); font_lookup_table_builder_->DuplicateMemoryRegion();
blink::FontTableMatcher font_table_matcher(font_table_memory.Map()); blink::FontTableMatcher font_table_matcher(font_table_memory.Map());
for (auto& test_font_name_index : expected_test_fonts) { for (auto& test_font_name_index : expected_test_fonts) {
base::Optional<blink::FontTableMatcher::MatchResult> match_result = base::Optional<blink::FontTableMatcher::MatchResult> match_result =
font_table_matcher.MatchName(test_font_name_index.first); font_table_matcher.MatchName(test_font_name_index.first);
CHECK(!match_result); ASSERT_TRUE(!match_result);
}
if (GetParam() == DWriteFontLookupTableBuilder::SlowDownMode::kHangOneTask)
font_lookup_table_builder_->ResumeFromHangForTesting();
}
INSTANTIATE_TEST_SUITE_P(
,
DWriteFontLookupTableBuilderTimeoutTest,
::testing::Values(
DWriteFontLookupTableBuilder::SlowDownMode::kDelayEachTask,
DWriteFontLookupTableBuilder::SlowDownMode::kHangOneTask));
TEST_F(DWriteFontLookupTableBuilderTest, RepeatedScheduling) {
for (unsigned i = 0; i < 3; ++i) {
font_lookup_table_builder_->ResetLookupTableForTesting();
font_lookup_table_builder_->ScheduleBuildFontUniqueNameTable();
font_lookup_table_builder_->EnsureFontUniqueNameTable();
} }
// Need to reset the table again so that it can be rebuilt successfully
// without the artificial timeout when running the next test.
font_lookup_table_builder->ResetLookupTableForTesting();
} }
} // namespace content } // namespace content
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "base/time/time.h" #include "base/time/time.h"
#include "content/browser/renderer_host/dwrite_font_file_util_win.h" #include "content/browser/renderer_host/dwrite_font_file_util_win.h"
#include "content/browser/renderer_host/dwrite_font_uma_logging_win.h" #include "content/browser/renderer_host/dwrite_font_uma_logging_win.h"
#include "content/public/common/content_features.h"
#include "mojo/public/cpp/bindings/callback_helpers.h" #include "mojo/public/cpp/bindings/callback_helpers.h"
#include "mojo/public/cpp/bindings/strong_binding.h" #include "mojo/public/cpp/bindings/strong_binding.h"
#include "third_party/blink/public/common/font_unique_name_lookup/font_unique_name_table.pb.h" #include "third_party/blink/public/common/font_unique_name_lookup/font_unique_name_table.pb.h"
...@@ -393,15 +394,19 @@ void DWriteFontProxyImpl::MapCharacters( ...@@ -393,15 +394,19 @@ void DWriteFontProxyImpl::MapCharacters(
void DWriteFontProxyImpl::GetUniqueNameLookupTable( void DWriteFontProxyImpl::GetUniqueNameLookupTable(
GetUniqueNameLookupTableCallback callback) { GetUniqueNameLookupTableCallback callback) {
DCHECK(base::FeatureList::IsEnabled(features::kFontSrcLocalMatching));
InitializeDirectWrite(); InitializeDirectWrite();
callback = mojo::WrapCallbackWithDefaultInvokeIfNotRun( callback = mojo::WrapCallbackWithDefaultInvokeIfNotRun(
std::move(callback), base::ReadOnlySharedMemoryRegion()); std::move(callback), base::ReadOnlySharedMemoryRegion());
// ScheduleBuildFontUniqueNameTable() is called early in browser startup
// before EnsureFontUniqueNameTable() can be called. See
// BrowserMainLoop::BrowserThreadsStarted().
if (!DWriteFontLookupTableBuilder::GetInstance()->EnsureFontUniqueNameTable()) if (!DWriteFontLookupTableBuilder::GetInstance()->EnsureFontUniqueNameTable())
return; return;
std::move(callback).Run( std::move(callback).Run(
DWriteFontLookupTableBuilder::GetInstance()->DuplicatedMemoryRegion()); DWriteFontLookupTableBuilder::GetInstance()->DuplicateMemoryRegion());
} }
void DWriteFontProxyImpl::InitializeDirectWrite() { void DWriteFontProxyImpl::InitializeDirectWrite() {
......
...@@ -12,9 +12,11 @@ ...@@ -12,9 +12,11 @@
#include "base/files/file.h" #include "base/files/file.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/scoped_task_environment.h" #include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "base/win/windows_version.h" #include "base/win/windows_version.h"
#include "content/public/common/content_features.h"
#include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/test_browser_thread_bundle.h"
#include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/binding.h"
#include "services/service_manager/public/cpp/bind_source_info.h" #include "services/service_manager/public/cpp/bind_source_info.h"
...@@ -47,6 +49,20 @@ class DWriteFontProxyImplUnitTest : public testing::Test { ...@@ -47,6 +49,20 @@ class DWriteFontProxyImplUnitTest : public testing::Test {
mojo::Binding<blink::mojom::DWriteFontProxy> binding_; mojo::Binding<blink::mojom::DWriteFontProxy> binding_;
}; };
class DWriteFontProxyUniqueNameMatchingTest
: public DWriteFontProxyImplUnitTest {
public:
DWriteFontProxyUniqueNameMatchingTest() {
feature_list_.InitAndEnableFeature(features::kFontSrcLocalMatching);
DWriteFontLookupTableBuilder::GetInstance()->ResetLookupTableForTesting();
DWriteFontLookupTableBuilder::GetInstance()
->ScheduleBuildFontUniqueNameTable();
}
private:
base::test::ScopedFeatureList feature_list_;
};
TEST_F(DWriteFontProxyImplUnitTest, GetFamilyCount) { TEST_F(DWriteFontProxyImplUnitTest, GetFamilyCount) {
UINT32 family_count = 0; UINT32 family_count = 0;
dwrite_font_proxy().GetFamilyCount(&family_count); dwrite_font_proxy().GetFamilyCount(&family_count);
...@@ -191,7 +207,7 @@ TEST_F(DWriteFontProxyImplUnitTest, TestCustomFontFiles) { ...@@ -191,7 +207,7 @@ TEST_F(DWriteFontProxyImplUnitTest, TestCustomFontFiles) {
} }
} }
TEST_F(DWriteFontProxyImplUnitTest, TestFindUniqueFont) { TEST_F(DWriteFontProxyUniqueNameMatchingTest, TestFindUniqueFont) {
base::ReadOnlySharedMemoryRegion font_table_memory; base::ReadOnlySharedMemoryRegion font_table_memory;
dwrite_font_proxy().GetUniqueNameLookupTable(&font_table_memory); dwrite_font_proxy().GetUniqueNameLookupTable(&font_table_memory);
blink::FontTableMatcher font_table_matcher(font_table_memory.Map()); blink::FontTableMatcher font_table_matcher(font_table_memory.Map());
...@@ -210,7 +226,6 @@ TEST_F(DWriteFontProxyImplUnitTest, TestFindUniqueFont) { ...@@ -210,7 +226,6 @@ TEST_F(DWriteFontProxyImplUnitTest, TestFindUniqueFont) {
} }
} }
} // namespace } // namespace
} // namespace content } // namespace content
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment