Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "content/renderer/dwrite_font_proxy_init_win.h" | |
| 6 | |
| 7 #include <dwrite.h> | |
| 8 | |
| 9 #include "base/callback.h" | |
| 10 #include "base/debug/alias.h" | |
| 11 #include "base/win/iat_patch_function.h" | |
| 12 #include "base/win/windows_version.h" | |
| 13 #include "content/renderer/dwrite_font_proxy_win.h" | |
| 14 #include "skia/ext/fontmgr_default_win.h" | |
| 15 #include "third_party/WebKit/public/web/win/WebFontRendering.h" | |
| 16 #include "third_party/skia/include/ports/SkTypeface_win.h" | |
| 17 | |
| 18 namespace mswr = Microsoft::WRL; | |
| 19 | |
| 20 namespace content { | |
| 21 | |
| 22 namespace { | |
| 23 mswr::ComPtr<DWriteFontCollectionProxy> g_font_collection; | |
| 24 base::win::IATPatchFunction g_iat_patch_open_sc_manager; | |
| 25 base::win::IATPatchFunction g_iat_patch_close_service_handle; | |
| 26 base::win::IATPatchFunction g_iat_patch_open_service; | |
| 27 base::win::IATPatchFunction g_iat_patch_start_service; | |
| 28 base::win::IATPatchFunction g_iat_patch_nt_connect_port; | |
| 29 IPC::Sender* g_senderOverride = nullptr; | |
| 30 } | |
| 31 | |
| 32 // These are from ntddk.h | |
| 33 #if !defined(STATUS_ACCESS_DENIED) | |
| 34 #define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L) | |
| 35 #endif | |
| 36 | |
| 37 typedef LONG NTSTATUS; | |
| 38 | |
| 39 const uintptr_t kFakeSCMHandle = 0xdead0001; | |
| 40 const uintptr_t kFakeServiceHandle = 0xdead0002; | |
| 41 | |
| 42 SC_HANDLE WINAPI OpenSCManagerWPatch(const wchar_t* machine_name, | |
| 43 const wchar_t* database_name, | |
| 44 DWORD access_mask) { | |
| 45 ::SetLastError(0); | |
| 46 return reinterpret_cast<SC_HANDLE>(kFakeSCMHandle); | |
| 47 } | |
| 48 | |
| 49 SC_HANDLE WINAPI OpenServiceWPatch(SC_HANDLE sc_manager, | |
| 50 const wchar_t* service_name, | |
| 51 DWORD access_mask) { | |
| 52 ::SetLastError(0); | |
| 53 return reinterpret_cast<SC_HANDLE>(kFakeServiceHandle); | |
| 54 } | |
| 55 | |
| 56 BOOL WINAPI CloseServiceHandlePatch(SC_HANDLE service_handle) { | |
| 57 if (service_handle != reinterpret_cast<SC_HANDLE>(kFakeServiceHandle) && | |
| 58 service_handle != reinterpret_cast<SC_HANDLE>(kFakeSCMHandle)) | |
| 59 CHECK(false); | |
| 60 ::SetLastError(0); | |
| 61 return TRUE; | |
| 62 } | |
| 63 | |
| 64 BOOL WINAPI StartServiceWPatch(SC_HANDLE service, | |
| 65 DWORD args, | |
| 66 const wchar_t** arg_vectors) { | |
| 67 if (service != reinterpret_cast<SC_HANDLE>(kFakeServiceHandle)) | |
| 68 CHECK(false); | |
| 69 ::SetLastError(ERROR_ACCESS_DENIED); | |
| 70 return FALSE; | |
| 71 } | |
| 72 | |
| 73 NTSTATUS WINAPI NtALpcConnectPortPatch(HANDLE* port_handle, | |
| 74 void* port_name, | |
| 75 void* object_attribs, | |
| 76 void* port_attribs, | |
| 77 DWORD flags, | |
| 78 void* server_sid, | |
| 79 void* message, | |
| 80 DWORD* buffer_length, | |
| 81 void* out_message_attributes, | |
| 82 void* in_message_attributes, | |
| 83 void* time_out) { | |
| 84 return STATUS_ACCESS_DENIED; | |
| 85 } | |
| 86 | |
| 87 // Directwrite connects to the font cache service to retrieve information about | |
|
jam
2015/11/20 17:39:31
why is there copied code here? i.e. why isn't this
Ilya Kulshin
2015/11/20 22:10:58
This whole file was moved to content/child/. Not s
| |
| 88 // fonts installed on the system etc. This works well outside the sandbox and | |
| 89 // within the sandbox as long as the lpc connection maintained by the current | |
| 90 // process with the font cache service remains valid. It appears that there | |
| 91 // are cases when this connection is dropped after which directwrite is unable | |
| 92 // to connect to the font cache service which causes problems with characters | |
| 93 // disappearing. | |
| 94 // Directwrite has fallback code to enumerate fonts if it is unable to connect | |
| 95 // to the font cache service. We need to intercept the following APIs to | |
| 96 // ensure that it does not connect to the font cache service. | |
| 97 // NtALpcConnectPort | |
| 98 // OpenSCManagerW | |
| 99 // OpenServiceW | |
| 100 // StartServiceW | |
| 101 // CloseServiceHandle. | |
| 102 // These are all IAT patched. | |
| 103 void PatchServiceManagerCalls() { | |
| 104 static bool is_patched = false; | |
| 105 if (is_patched) | |
| 106 return; | |
| 107 const char* service_provider_dll = | |
| 108 (base::win::GetVersion() >= base::win::VERSION_WIN8 | |
| 109 ? "api-ms-win-service-management-l1-1-0.dll" | |
| 110 : "advapi32.dll"); | |
| 111 | |
| 112 is_patched = true; | |
| 113 | |
| 114 DWORD patched = | |
| 115 g_iat_patch_open_sc_manager.Patch(L"dwrite.dll", service_provider_dll, | |
| 116 "OpenSCManagerW", OpenSCManagerWPatch); | |
| 117 DCHECK(patched == 0); | |
| 118 | |
| 119 patched = g_iat_patch_close_service_handle.Patch( | |
| 120 L"dwrite.dll", service_provider_dll, "CloseServiceHandle", | |
| 121 CloseServiceHandlePatch); | |
| 122 DCHECK(patched == 0); | |
| 123 | |
| 124 patched = g_iat_patch_open_service.Patch(L"dwrite.dll", service_provider_dll, | |
| 125 "OpenServiceW", OpenServiceWPatch); | |
| 126 DCHECK(patched == 0); | |
| 127 | |
| 128 patched = g_iat_patch_start_service.Patch( | |
| 129 L"dwrite.dll", service_provider_dll, "StartServiceW", StartServiceWPatch); | |
| 130 DCHECK(patched == 0); | |
| 131 | |
| 132 patched = g_iat_patch_nt_connect_port.Patch( | |
| 133 L"dwrite.dll", "ntdll.dll", "NtAlpcConnectPort", NtALpcConnectPortPatch); | |
| 134 DCHECK(patched == 0); | |
| 135 } | |
| 136 | |
| 137 // Copied from content/common/font_warmup_win.cc | |
| 138 // Windows-only DirectWrite support. These warm up the DirectWrite paths | |
| 139 // before sandbox lock down to allow Skia access to the Font Manager service. | |
| 140 void CreateDirectWriteFactory(IDWriteFactory** factory) { | |
| 141 typedef decltype(DWriteCreateFactory)* DWriteCreateFactoryProc; | |
| 142 HMODULE dwrite_dll = LoadLibraryW(L"dwrite.dll"); | |
| 143 // TODO(scottmg): Temporary code to track crash in http://crbug.com/387867. | |
| 144 if (!dwrite_dll) { | |
| 145 DWORD load_library_get_last_error = GetLastError(); | |
| 146 base::debug::Alias(&dwrite_dll); | |
| 147 base::debug::Alias(&load_library_get_last_error); | |
| 148 CHECK(false); | |
| 149 } | |
| 150 | |
| 151 // TODO(kulshin): This shouldn't be necessary, but not having this causes | |
| 152 // breakage in content_browsertests, and possibly other high-stress cases. | |
| 153 PatchServiceManagerCalls(); | |
| 154 | |
| 155 DWriteCreateFactoryProc dwrite_create_factory_proc = | |
| 156 reinterpret_cast<DWriteCreateFactoryProc>( | |
| 157 GetProcAddress(dwrite_dll, "DWriteCreateFactory")); | |
| 158 // TODO(scottmg): Temporary code to track crash in http://crbug.com/387867. | |
| 159 if (!dwrite_create_factory_proc) { | |
| 160 DWORD get_proc_address_get_last_error = GetLastError(); | |
| 161 base::debug::Alias(&dwrite_create_factory_proc); | |
| 162 base::debug::Alias(&get_proc_address_get_last_error); | |
| 163 CHECK(false); | |
| 164 } | |
| 165 CHECK(SUCCEEDED(dwrite_create_factory_proc( | |
| 166 DWRITE_FACTORY_TYPE_ISOLATED, __uuidof(IDWriteFactory), | |
| 167 reinterpret_cast<IUnknown**>(factory)))); | |
| 168 } | |
| 169 | |
| 170 HRESULT STDMETHODCALLTYPE StubFontCollection(IDWriteFactory* factory, | |
| 171 IDWriteFontCollection** col, | |
| 172 BOOL checkUpdates) { | |
| 173 DCHECK(g_font_collection != nullptr); | |
| 174 g_font_collection.CopyTo(col); | |
| 175 return S_OK; | |
| 176 } | |
| 177 | |
| 178 // Copied from content/common/font_warmup_win.cc | |
| 179 // TODO(kulshin): eventually, make Skia deal with custom font collections and | |
| 180 // get rid of this altogether. | |
| 181 void PatchDWriteFactory(IDWriteFactory* factory) { | |
| 182 const unsigned int kGetSystemFontCollectionVTableIndex = 3; | |
| 183 | |
| 184 PROC* vtable = *reinterpret_cast<PROC**>(factory); | |
| 185 PROC* function_ptr = &vtable[kGetSystemFontCollectionVTableIndex]; | |
| 186 void* stub_function = &StubFontCollection; | |
| 187 base::win::ModifyCode(function_ptr, &stub_function, sizeof(PROC)); | |
| 188 } | |
| 189 | |
| 190 void InitializeDWriteFontProxy( | |
| 191 const base::Callback<IPC::Sender(void)>& getSender) { | |
| 192 mswr::ComPtr<IDWriteFactory> factory; | |
| 193 | |
| 194 CreateDirectWriteFactory(&factory); | |
| 195 | |
| 196 if (g_font_collection == nullptr) { | |
| 197 mswr::MakeAndInitialize<DWriteFontCollectionProxy>( | |
| 198 &g_font_collection, factory.Get(), getSender); | |
| 199 } | |
| 200 | |
| 201 PatchDWriteFactory(factory.Get()); | |
| 202 | |
| 203 blink::WebFontRendering::setDirectWriteFactory(factory.Get()); | |
| 204 SkFontMgr* skiaFontManager = SkFontMgr_New_DirectWrite(factory.Get()); | |
| 205 SetDefaultSkiaFactory(skiaFontManager); | |
| 206 } | |
| 207 | |
| 208 void UninitializeDWriteFontProxy() { | |
| 209 if (g_font_collection != nullptr) | |
| 210 g_font_collection->Unregister(); | |
| 211 } | |
| 212 | |
| 213 void SetDWriteFontProxyTestModeSender(IPC::Sender* sender) { | |
| 214 g_senderOverride = sender; | |
| 215 } | |
| 216 | |
| 217 } // namespace content | |
| OLD | NEW |