| Index: content/renderer/dwrite_font_proxy_init_win.cc
|
| diff --git a/content/renderer/dwrite_font_proxy_init_win.cc b/content/renderer/dwrite_font_proxy_init_win.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..b8d22f788bc90bafe490dfee1827803f5a08a6f0
|
| --- /dev/null
|
| +++ b/content/renderer/dwrite_font_proxy_init_win.cc
|
| @@ -0,0 +1,217 @@
|
| +// Copyright 2015 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/renderer/dwrite_font_proxy_init_win.h"
|
| +
|
| +#include <dwrite.h>
|
| +
|
| +#include "base/callback.h"
|
| +#include "base/debug/alias.h"
|
| +#include "base/win/iat_patch_function.h"
|
| +#include "base/win/windows_version.h"
|
| +#include "content/renderer/dwrite_font_proxy_win.h"
|
| +#include "skia/ext/fontmgr_default_win.h"
|
| +#include "third_party/WebKit/public/web/win/WebFontRendering.h"
|
| +#include "third_party/skia/include/ports/SkTypeface_win.h"
|
| +
|
| +namespace mswr = Microsoft::WRL;
|
| +
|
| +namespace content {
|
| +
|
| +namespace {
|
| +mswr::ComPtr<DWriteFontCollectionProxy> g_font_collection;
|
| +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;
|
| +IPC::Sender* g_senderOverride = nullptr;
|
| +}
|
| +
|
| +// 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;
|
| +}
|
| +
|
| +// 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);
|
| +}
|
| +
|
| +// Copied from content/common/font_warmup_win.cc
|
| +// 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);
|
| + }
|
| +
|
| + // TODO(kulshin): This shouldn't be necessary, but not having this causes
|
| + // breakage in content_browsertests, and possibly other high-stress cases.
|
| + 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) {
|
| + DCHECK(g_font_collection != nullptr);
|
| + g_font_collection.CopyTo(col);
|
| + return S_OK;
|
| +}
|
| +
|
| +// Copied from content/common/font_warmup_win.cc
|
| +// TODO(kulshin): eventually, make Skia deal with custom font collections and
|
| +// get rid of this altogether.
|
| +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));
|
| +}
|
| +
|
| +void InitializeDWriteFontProxy(
|
| + const base::Callback<IPC::Sender(void)>& getSender) {
|
| + mswr::ComPtr<IDWriteFactory> factory;
|
| +
|
| + CreateDirectWriteFactory(&factory);
|
| +
|
| + if (g_font_collection == nullptr) {
|
| + mswr::MakeAndInitialize<DWriteFontCollectionProxy>(
|
| + &g_font_collection, factory.Get(), getSender);
|
| + }
|
| +
|
| + PatchDWriteFactory(factory.Get());
|
| +
|
| + blink::WebFontRendering::setDirectWriteFactory(factory.Get());
|
| + SkFontMgr* skiaFontManager = SkFontMgr_New_DirectWrite(factory.Get());
|
| + SetDefaultSkiaFactory(skiaFontManager);
|
| +}
|
| +
|
| +void UninitializeDWriteFontProxy() {
|
| + if (g_font_collection != nullptr)
|
| + g_font_collection->Unregister();
|
| +}
|
| +
|
| +void SetDWriteFontProxyTestModeSender(IPC::Sender* sender) {
|
| + g_senderOverride = sender;
|
| +}
|
| +
|
| +} // namespace content
|
|
|