summaryrefslogtreecommitdiff
path: root/chromium/content/common/font_warmup_win.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/content/common/font_warmup_win.cc')
-rw-r--r--chromium/content/common/font_warmup_win.cc526
1 files changed, 0 insertions, 526 deletions
diff --git a/chromium/content/common/font_warmup_win.cc b/chromium/content/common/font_warmup_win.cc
deleted file mode 100644
index cdd1d0f2dba..00000000000
--- a/chromium/content/common/font_warmup_win.cc
+++ /dev/null
@@ -1,526 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/common/font_warmup_win.h"
-
-#include <dwrite.h>
-#include <stdint.h>
-#include <map>
-
-#include "base/debug/alias.h"
-#include "base/files/file_path.h"
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/numerics/safe_conversions.h"
-#include "base/numerics/safe_math.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/synchronization/lock.h"
-#include "base/sys_byteorder.h"
-#include "base/trace_event/trace_event.h"
-#include "base/win/iat_patch_function.h"
-#include "base/win/windows_version.h"
-#include "content/public/common/dwrite_font_platform_win.h"
-#include "ppapi/shared_impl/proxy_lock.h"
-#include "skia/ext/fontmgr_default_win.h"
-#include "skia/ext/refptr.h"
-#include "third_party/WebKit/public/web/win/WebFontRendering.h"
-#include "third_party/skia/include/core/SkPaint.h"
-#include "third_party/skia/include/ports/SkFontMgr.h"
-#include "third_party/skia/include/ports/SkTypeface_win.h"
-
-namespace content {
-
-namespace {
-
-// The Skia font manager, used for the life of the process (leaked at the end).
-SkFontMgr* g_warmup_fontmgr = nullptr;
-
-base::win::IATPatchFunction g_iat_patch_open_sc_manager;
-base::win::IATPatchFunction g_iat_patch_close_service_handle;
-base::win::IATPatchFunction g_iat_patch_open_service;
-base::win::IATPatchFunction g_iat_patch_start_service;
-base::win::IATPatchFunction g_iat_patch_nt_connect_port;
-
-// These are from ntddk.h
-#if !defined(STATUS_ACCESS_DENIED)
-#define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L)
-#endif
-
-typedef LONG NTSTATUS;
-
-const uintptr_t kFakeSCMHandle = 0xdead0001;
-const uintptr_t kFakeServiceHandle = 0xdead0002;
-
-SC_HANDLE WINAPI OpenSCManagerWPatch(const wchar_t* machine_name,
- const wchar_t* database_name,
- DWORD access_mask) {
- ::SetLastError(0);
- return reinterpret_cast<SC_HANDLE>(kFakeSCMHandle);
-}
-
-SC_HANDLE WINAPI OpenServiceWPatch(SC_HANDLE sc_manager,
- const wchar_t* service_name,
- DWORD access_mask) {
- ::SetLastError(0);
- return reinterpret_cast<SC_HANDLE>(kFakeServiceHandle);
-}
-
-BOOL WINAPI CloseServiceHandlePatch(SC_HANDLE service_handle) {
- if (service_handle != reinterpret_cast<SC_HANDLE>(kFakeServiceHandle) &&
- service_handle != reinterpret_cast<SC_HANDLE>(kFakeSCMHandle))
- CHECK(false);
- ::SetLastError(0);
- return TRUE;
-}
-
-BOOL WINAPI StartServiceWPatch(SC_HANDLE service,
- DWORD args,
- const wchar_t** arg_vectors) {
- if (service != reinterpret_cast<SC_HANDLE>(kFakeServiceHandle))
- CHECK(false);
- ::SetLastError(ERROR_ACCESS_DENIED);
- return FALSE;
-}
-
-NTSTATUS WINAPI NtALpcConnectPortPatch(HANDLE* port_handle,
- void* port_name,
- void* object_attribs,
- void* port_attribs,
- DWORD flags,
- void* server_sid,
- void* message,
- DWORD* buffer_length,
- void* out_message_attributes,
- void* in_message_attributes,
- void* time_out) {
- return STATUS_ACCESS_DENIED;
-}
-
-// Windows-only DirectWrite support. These warm up the DirectWrite paths
-// before sandbox lock down to allow Skia access to the Font Manager service.
-void CreateDirectWriteFactory(IDWriteFactory** factory) {
- typedef decltype(DWriteCreateFactory)* DWriteCreateFactoryProc;
- HMODULE dwrite_dll = LoadLibraryW(L"dwrite.dll");
- // TODO(scottmg): Temporary code to track crash in http://crbug.com/387867.
- if (!dwrite_dll) {
- DWORD load_library_get_last_error = GetLastError();
- base::debug::Alias(&dwrite_dll);
- base::debug::Alias(&load_library_get_last_error);
- CHECK(false);
- }
-
- PatchServiceManagerCalls();
-
- DWriteCreateFactoryProc dwrite_create_factory_proc =
- reinterpret_cast<DWriteCreateFactoryProc>(
- GetProcAddress(dwrite_dll, "DWriteCreateFactory"));
- // TODO(scottmg): Temporary code to track crash in http://crbug.com/387867.
- if (!dwrite_create_factory_proc) {
- DWORD get_proc_address_get_last_error = GetLastError();
- base::debug::Alias(&dwrite_create_factory_proc);
- base::debug::Alias(&get_proc_address_get_last_error);
- CHECK(false);
- }
- CHECK(SUCCEEDED(dwrite_create_factory_proc(
- DWRITE_FACTORY_TYPE_ISOLATED, __uuidof(IDWriteFactory),
- reinterpret_cast<IUnknown**>(factory))));
-}
-
-HRESULT STDMETHODCALLTYPE StubFontCollection(IDWriteFactory* factory,
- IDWriteFontCollection** col,
- BOOL checkUpdates) {
- // We always return pre-created font collection from here.
- IDWriteFontCollection* custom_collection = GetCustomFontCollection(factory);
- DCHECK(custom_collection != nullptr);
- *col = custom_collection;
- return S_OK;
-}
-
-void PatchDWriteFactory(IDWriteFactory* factory) {
- const unsigned int kGetSystemFontCollectionVTableIndex = 3;
-
- PROC* vtable = *reinterpret_cast<PROC**>(factory);
- PROC* function_ptr = &vtable[kGetSystemFontCollectionVTableIndex];
- void* stub_function = &StubFontCollection;
- base::win::ModifyCode(function_ptr, &stub_function, sizeof(PROC));
-}
-
-// Class to fake out a DC or a Font object. Maintains a reference to a
-// SkTypeFace to emulate the simple operation of a DC and Font.
-class FakeGdiObject : public base::RefCountedThreadSafe<FakeGdiObject> {
- public:
- FakeGdiObject(uint32_t magic, void* handle)
- : handle_(handle), magic_(magic) {}
-
- void set_typeface(const skia::RefPtr<SkTypeface>& typeface) {
- typeface_ = typeface;
- }
-
- skia::RefPtr<SkTypeface> typeface() { return typeface_; }
- void* handle() { return handle_; }
- uint32_t magic() { return magic_; }
-
- private:
- friend class base::RefCountedThreadSafe<FakeGdiObject>;
- ~FakeGdiObject() {}
-
- void* handle_;
- uint32_t magic_;
- skia::RefPtr<SkTypeface> typeface_;
-
- DISALLOW_COPY_AND_ASSIGN(FakeGdiObject);
-};
-
-// This class acts as a factory for creating new fake GDI objects. It also maps
-// the new instances of the FakeGdiObject class to an incrementing handle value
-// which is passed to the caller of the emulated GDI function for later
-// reference. We can't be sure that this won't be used in a multi-threaded
-// environment so we need to ensure a lock is taken before accessing the map of
-// issued objects.
-class FakeGdiObjectFactory {
- public:
- FakeGdiObjectFactory() : curr_handle_(0) {}
-
- // Find a corresponding fake GDI object and verify its magic value.
- // The returned value is either nullptr or the validated object.
- scoped_refptr<FakeGdiObject> Validate(void* obj, uint32_t magic) {
- if (obj) {
- base::AutoLock scoped_lock(objects_lock_);
- auto handle_entry = objects_.find(obj);
- if (handle_entry != objects_.end() &&
- handle_entry->second->magic() == magic) {
- return handle_entry->second;
- }
- }
- return nullptr;
- }
-
- scoped_refptr<FakeGdiObject> Create(uint32_t magic) {
- base::AutoLock scoped_lock(objects_lock_);
- curr_handle_++;
- // We don't support wrapping the fake handle value.
- void* handle = reinterpret_cast<void*>(curr_handle_.ValueOrDie());
- scoped_refptr<FakeGdiObject> object(new FakeGdiObject(magic, handle));
- objects_[handle] = object;
- return object;
- }
-
- bool DeleteObject(void* obj, uint32_t magic) {
- base::AutoLock scoped_lock(objects_lock_);
- auto handle_entry = objects_.find(obj);
- if (handle_entry != objects_.end() &&
- handle_entry->second->magic() == magic) {
- objects_.erase(handle_entry);
- return true;
- }
- return false;
- }
-
- size_t GetObjectCount() {
- base::AutoLock scoped_lock(objects_lock_);
- return objects_.size();
- }
-
- void ResetObjectHandles() {
- base::AutoLock scoped_lock(objects_lock_);
- curr_handle_ = 0;
- objects_.clear();
- }
-
- private:
- base::CheckedNumeric<uintptr_t> curr_handle_;
- std::map<void*, scoped_refptr<FakeGdiObject>> objects_;
- base::Lock objects_lock_;
-
- DISALLOW_COPY_AND_ASSIGN(FakeGdiObjectFactory);
-};
-
-base::LazyInstance<FakeGdiObjectFactory>::Leaky g_fake_gdi_object_factory =
- LAZY_INSTANCE_INITIALIZER;
-
-// Magic values for the fake GDI objects.
-const uint32_t kFakeDCMagic = 'fkdc';
-const uint32_t kFakeFontMagic = 'fkft';
-
-skia::RefPtr<SkTypeface> GetTypefaceFromLOGFONT(const LOGFONTW* log_font) {
- CHECK(g_warmup_fontmgr);
- int weight = log_font->lfWeight;
- if (weight == FW_DONTCARE)
- weight = SkFontStyle::kNormal_Weight;
-
- SkFontStyle style(weight, log_font->lfWidth,
- log_font->lfItalic ? SkFontStyle::kItalic_Slant
- : SkFontStyle::kUpright_Slant);
-
- std::string family_name = base::WideToUTF8(log_font->lfFaceName);
- ppapi::ProxyAutoLock lock; // Needed for DirectWrite font proxy.
- return skia::AdoptRef(
- g_warmup_fontmgr->matchFamilyStyle(family_name.c_str(), style));
-}
-
-HDC WINAPI CreateCompatibleDCPatch(HDC dc_handle) {
- scoped_refptr<FakeGdiObject> ret =
- g_fake_gdi_object_factory.Get().Create(kFakeDCMagic);
- return static_cast<HDC>(ret->handle());
-}
-
-HFONT WINAPI CreateFontIndirectWPatch(const LOGFONTW* log_font) {
- if (!log_font)
- return nullptr;
-
- skia::RefPtr<SkTypeface> typeface = GetTypefaceFromLOGFONT(log_font);
- if (!typeface)
- return nullptr;
-
- scoped_refptr<FakeGdiObject> ret =
- g_fake_gdi_object_factory.Get().Create(kFakeFontMagic);
- ret->set_typeface(typeface);
-
- return static_cast<HFONT>(ret->handle());
-}
-
-BOOL WINAPI DeleteDCPatch(HDC dc_handle) {
- return g_fake_gdi_object_factory.Get().DeleteObject(dc_handle, kFakeDCMagic);
-}
-
-BOOL WINAPI DeleteObjectPatch(HGDIOBJ object_handle) {
- return g_fake_gdi_object_factory.Get().DeleteObject(object_handle,
- kFakeFontMagic);
-}
-
-int WINAPI EnumFontFamiliesExWPatch(HDC dc_handle,
- LPLOGFONTW log_font,
- FONTENUMPROCW enum_callback,
- LPARAM callback_param,
- DWORD flags) {
- scoped_refptr<FakeGdiObject> dc_obj =
- g_fake_gdi_object_factory.Get().Validate(dc_handle, kFakeDCMagic);
- if (!dc_obj)
- return 1;
-
- if (!log_font || !enum_callback)
- return 1;
-
- skia::RefPtr<SkTypeface> typeface = GetTypefaceFromLOGFONT(log_font);
- if (!typeface)
- return 1;
-
- ENUMLOGFONTEXDVW enum_log_font = {};
- enum_log_font.elfEnumLogfontEx.elfLogFont = *log_font;
- // TODO: Fill in the rest of the text metric structure. Not yet needed for
- // Flash support but might be in the future.
- NEWTEXTMETRICEXW text_metric = {};
- text_metric.ntmTm.ntmFlags = NTM_PS_OPENTYPE;
-
- return enum_callback(&enum_log_font.elfEnumLogfontEx.elfLogFont,
- reinterpret_cast<TEXTMETRIC*>(&text_metric),
- TRUETYPE_FONTTYPE, callback_param);
-}
-
-DWORD WINAPI GetFontDataPatch(HDC dc_handle,
- DWORD table_tag,
- DWORD table_offset,
- LPVOID buffer,
- DWORD buffer_length) {
- scoped_refptr<FakeGdiObject> dc_obj =
- g_fake_gdi_object_factory.Get().Validate(dc_handle, kFakeDCMagic);
- if (!dc_obj)
- return GDI_ERROR;
-
- skia::RefPtr<SkTypeface> typeface = dc_obj->typeface();
- if (!typeface)
- return GDI_ERROR;
-
- // |getTableData| handles |buffer| being nullptr. However if it is nullptr
- // then set the size to INT32_MAX otherwise |getTableData| will return the
- // minimum value between the table entry size and the size passed in. The
- // common Windows idiom is to pass 0 as |buffer_length| when passing nullptr,
- // which would in this case result in |getTableData| returning 0 which isn't
- // the correct answer for emulating GDI. |table_tag| must also have its
- // byte order swapped to counter the swap which occurs in the called method.
- size_t length = typeface->getTableData(
- base::ByteSwap(base::strict_cast<uint32_t>(table_tag)), table_offset,
- buffer ? buffer_length : INT32_MAX, buffer);
- // We can't distinguish between an empty table and an error.
- if (length == 0)
- return GDI_ERROR;
-
- return base::checked_cast<DWORD>(length);
-}
-
-HGDIOBJ WINAPI SelectObjectPatch(HDC dc_handle, HGDIOBJ object_handle) {
- scoped_refptr<FakeGdiObject> dc_obj =
- g_fake_gdi_object_factory.Get().Validate(dc_handle, kFakeDCMagic);
- if (!dc_obj)
- return nullptr;
-
- scoped_refptr<FakeGdiObject> font_obj =
- g_fake_gdi_object_factory.Get().Validate(object_handle, kFakeFontMagic);
- if (!font_obj)
- return nullptr;
-
- // Construct a new fake font object to handle the old font if there's one.
- scoped_refptr<FakeGdiObject> new_font_obj;
- skia::RefPtr<SkTypeface> old_typeface = dc_obj->typeface();
- if (old_typeface) {
- new_font_obj = g_fake_gdi_object_factory.Get().Create(kFakeFontMagic);
- new_font_obj->set_typeface(old_typeface);
- }
- dc_obj->set_typeface(font_obj->typeface());
-
- if (new_font_obj)
- return static_cast<HGDIOBJ>(new_font_obj->handle());
- return nullptr;
-}
-
-void DoSingleGdiPatch(base::win::IATPatchFunction& patch,
- const base::FilePath& path,
- const char* function_name,
- void* new_function) {
- patch.Patch(path.value().c_str(), "gdi32.dll", function_name, new_function);
-}
-
-class GdiFontPatchDataImpl : public content::GdiFontPatchData {
- public:
- GdiFontPatchDataImpl(const base::FilePath& path);
-
- private:
- base::win::IATPatchFunction create_compatible_dc_patch_;
- base::win::IATPatchFunction create_font_indirect_patch_;
- base::win::IATPatchFunction create_delete_dc_patch_;
- base::win::IATPatchFunction create_delete_object_patch_;
- base::win::IATPatchFunction create_enum_font_families_patch_;
- base::win::IATPatchFunction create_get_font_data_patch_;
- base::win::IATPatchFunction create_select_object_patch_;
-};
-
-GdiFontPatchDataImpl::GdiFontPatchDataImpl(const base::FilePath& path) {
- DoSingleGdiPatch(create_compatible_dc_patch_, path, "CreateCompatibleDC",
- CreateCompatibleDCPatch);
- DoSingleGdiPatch(create_font_indirect_patch_, path, "CreateFontIndirectW",
- CreateFontIndirectWPatch);
- DoSingleGdiPatch(create_delete_dc_patch_, path, "DeleteDC", DeleteDCPatch);
- DoSingleGdiPatch(create_delete_object_patch_, path, "DeleteObject",
- DeleteObjectPatch);
- DoSingleGdiPatch(create_enum_font_families_patch_, path,
- "EnumFontFamiliesExW", EnumFontFamiliesExWPatch);
- DoSingleGdiPatch(create_get_font_data_patch_, path, "GetFontData",
- GetFontDataPatch);
- DoSingleGdiPatch(create_select_object_patch_, path, "SelectObject",
- SelectObjectPatch);
-}
-
-} // namespace
-
-// Directwrite connects to the font cache service to retrieve information about
-// fonts installed on the system etc. This works well outside the sandbox and
-// within the sandbox as long as the lpc connection maintained by the current
-// process with the font cache service remains valid. It appears that there
-// are cases when this connection is dropped after which directwrite is unable
-// to connect to the font cache service which causes problems with characters
-// disappearing.
-// Directwrite has fallback code to enumerate fonts if it is unable to connect
-// to the font cache service. We need to intercept the following APIs to
-// ensure that it does not connect to the font cache service.
-// NtALpcConnectPort
-// OpenSCManagerW
-// OpenServiceW
-// StartServiceW
-// CloseServiceHandle.
-// These are all IAT patched.
-void PatchServiceManagerCalls() {
- static bool is_patched = false;
- if (is_patched)
- return;
- const char* service_provider_dll =
- (base::win::GetVersion() >= base::win::VERSION_WIN8
- ? "api-ms-win-service-management-l1-1-0.dll"
- : "advapi32.dll");
-
- is_patched = true;
-
- DWORD patched =
- g_iat_patch_open_sc_manager.Patch(L"dwrite.dll", service_provider_dll,
- "OpenSCManagerW", OpenSCManagerWPatch);
- DCHECK(patched == 0);
-
- patched = g_iat_patch_close_service_handle.Patch(
- L"dwrite.dll", service_provider_dll, "CloseServiceHandle",
- CloseServiceHandlePatch);
- DCHECK(patched == 0);
-
- patched = g_iat_patch_open_service.Patch(L"dwrite.dll", service_provider_dll,
- "OpenServiceW", OpenServiceWPatch);
- DCHECK(patched == 0);
-
- patched = g_iat_patch_start_service.Patch(
- L"dwrite.dll", service_provider_dll, "StartServiceW", StartServiceWPatch);
- DCHECK(patched == 0);
-
- patched = g_iat_patch_nt_connect_port.Patch(
- L"dwrite.dll", "ntdll.dll", "NtAlpcConnectPort", NtALpcConnectPortPatch);
- DCHECK(patched == 0);
-}
-
-void DoPreSandboxWarmupForTypeface(SkTypeface* typeface) {
- SkPaint paint_warmup;
- paint_warmup.setTypeface(typeface);
- wchar_t glyph = L'S';
- paint_warmup.measureText(&glyph, 2);
-}
-
-SkFontMgr* GetPreSandboxWarmupFontMgr() {
- if (!g_warmup_fontmgr) {
- IDWriteFactory* factory;
- CreateDirectWriteFactory(&factory);
-
- GetCustomFontCollection(factory);
-
- PatchDWriteFactory(factory);
-
- blink::WebFontRendering::setDirectWriteFactory(factory);
- g_warmup_fontmgr = SkFontMgr_New_DirectWrite(factory);
- }
- return g_warmup_fontmgr;
-}
-
-GdiFontPatchData* PatchGdiFontEnumeration(const base::FilePath& path) {
- if (ShouldUseDirectWriteFontProxyFieldTrial() && !g_warmup_fontmgr)
- g_warmup_fontmgr = SkFontMgr_New_DirectWrite();
- // If not using the font proxy, we assume |g_warmup_fontmgr| is already
- // initialized before this function is called.
- DCHECK(g_warmup_fontmgr);
- return new GdiFontPatchDataImpl(path);
-}
-
-size_t GetEmulatedGdiHandleCountForTesting() {
- return g_fake_gdi_object_factory.Get().GetObjectCount();
-}
-
-void ResetEmulatedGdiHandlesForTesting() {
- g_fake_gdi_object_factory.Get().ResetObjectHandles();
-}
-
-void SetPreSandboxWarmupFontMgrForTesting(SkFontMgr* fontmgr) {
- g_warmup_fontmgr = fontmgr;
-}
-
-void WarmupDirectWrite() {
- TRACE_EVENT0("startup", "content::WarmupDirectWrite");
-
- // The objects used here are intentionally not freed as we want the Skia
- // code to use these objects after warmup.
- SetDefaultSkiaFactory(GetPreSandboxWarmupFontMgr());
-
- // We need to warm up *some* font for DirectWrite. Note that we don't use
- // a monospace as would be nice in an attempt to avoid a small startup time
- // regression, see http://crbug.com/463613.
- skia::RefPtr<SkTypeface> hud_typeface = skia::AdoptRef(
- GetPreSandboxWarmupFontMgr()->legacyCreateTypeface("Times New Roman", 0));
- DoPreSandboxWarmupForTypeface(hud_typeface.get());
-}
-
-} // namespace content