| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 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/public/renderer/render_font_warmup_win.h" | |
| 6 | |
| 7 #include <dwrite.h> | |
| 8 | |
| 9 #include "base/debug/alias.h" | |
| 10 #include "base/logging.h" | |
| 11 #include "base/win/iat_patch_function.h" | |
| 12 #include "base/win/windows_version.h" | |
| 13 #include "content/public/common/dwrite_font_platform_win.h" | |
| 14 #include "third_party/WebKit/public/web/win/WebFontRendering.h" | |
| 15 #include "third_party/skia/include/core/SkPaint.h" | |
| 16 #include "third_party/skia/include/ports/SkFontMgr.h" | |
| 17 #include "third_party/skia/include/ports/SkTypeface_win.h" | |
| 18 | |
| 19 namespace content { | |
| 20 | |
| 21 namespace { | |
| 22 | |
| 23 SkFontMgr* g_warmup_fontmgr = NULL; | |
| 24 | |
| 25 base::win::IATPatchFunction g_iat_patch_open_sc_manager; | |
| 26 base::win::IATPatchFunction g_iat_patch_close_service_handle; | |
| 27 base::win::IATPatchFunction g_iat_patch_open_service; | |
| 28 base::win::IATPatchFunction g_iat_patch_start_service; | |
| 29 base::win::IATPatchFunction g_iat_patch_nt_connect_port; | |
| 30 | |
| 31 // These are from ntddk.h | |
| 32 #if !defined(STATUS_ACCESS_DENIED) | |
| 33 #define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L) | |
| 34 #endif | |
| 35 | |
| 36 typedef LONG NTSTATUS; | |
| 37 | |
| 38 SC_HANDLE WINAPI OpenSCManagerWPatch(const wchar_t* machine_name, | |
| 39 const wchar_t* database_name, | |
| 40 DWORD access_mask) { | |
| 41 ::SetLastError(0); | |
| 42 return reinterpret_cast<SC_HANDLE>(0xdeadbeef); | |
| 43 } | |
| 44 | |
| 45 SC_HANDLE WINAPI OpenServiceWPatch(SC_HANDLE sc_manager, | |
| 46 const wchar_t* service_name, | |
| 47 DWORD access_mask) { | |
| 48 ::SetLastError(0); | |
| 49 return reinterpret_cast<SC_HANDLE>(0xdeadbabe); | |
| 50 } | |
| 51 | |
| 52 BOOL WINAPI CloseServiceHandlePatch(SC_HANDLE service_handle) { | |
| 53 if (service_handle != reinterpret_cast<SC_HANDLE>(0xdeadbabe) && | |
| 54 service_handle != reinterpret_cast<SC_HANDLE>(0xdeadbeef)) | |
| 55 CHECK(false); | |
| 56 ::SetLastError(0); | |
| 57 return TRUE; | |
| 58 } | |
| 59 | |
| 60 BOOL WINAPI StartServiceWPatch(SC_HANDLE service, | |
| 61 DWORD args, | |
| 62 const wchar_t** arg_vectors) { | |
| 63 if (service != reinterpret_cast<SC_HANDLE>(0xdeadbabe)) | |
| 64 CHECK(false); | |
| 65 ::SetLastError(ERROR_ACCESS_DENIED); | |
| 66 return FALSE; | |
| 67 } | |
| 68 | |
| 69 NTSTATUS WINAPI NtALpcConnectPortPatch(HANDLE* port_handle, | |
| 70 void* port_name, | |
| 71 void* object_attribs, | |
| 72 void* port_attribs, | |
| 73 DWORD flags, | |
| 74 void* server_sid, | |
| 75 void* message, | |
| 76 DWORD* buffer_length, | |
| 77 void* out_message_attributes, | |
| 78 void* in_message_attributes, | |
| 79 void* time_out) { | |
| 80 return STATUS_ACCESS_DENIED; | |
| 81 } | |
| 82 | |
| 83 // Directwrite connects to the font cache service to retrieve information about | |
| 84 // fonts installed on the system etc. This works well outside the sandbox and | |
| 85 // within the sandbox as long as the lpc connection maintained by the current | |
| 86 // process with the font cache service remains valid. It appears that there | |
| 87 // are cases when this connection is dropped after which directwrite is unable | |
| 88 // to connect to the font cache service which causes problems with characters | |
| 89 // disappearing. | |
| 90 // Directwrite has fallback code to enumerate fonts if it is unable to connect | |
| 91 // to the font cache service. We need to intercept the following APIs to | |
| 92 // ensure that it does not connect to the font cache service. | |
| 93 // NtALpcConnectPort | |
| 94 // OpenSCManagerW | |
| 95 // OpenServiceW | |
| 96 // StartServiceW | |
| 97 // CloseServiceHandle. | |
| 98 // These are all IAT patched. | |
| 99 void PatchServiceManagerCalls() { | |
| 100 static bool is_patched = false; | |
| 101 if (is_patched) | |
| 102 return; | |
| 103 const char* service_provider_dll = | |
| 104 (base::win::GetVersion() >= base::win::VERSION_WIN8 ? | |
| 105 "api-ms-win-service-management-l1-1-0.dll" : "advapi32.dll"); | |
| 106 | |
| 107 is_patched = true; | |
| 108 | |
| 109 DWORD patched = g_iat_patch_open_sc_manager.Patch(L"dwrite.dll", | |
| 110 service_provider_dll, "OpenSCManagerW", OpenSCManagerWPatch); | |
| 111 DCHECK(patched == 0); | |
| 112 | |
| 113 patched = g_iat_patch_close_service_handle.Patch(L"dwrite.dll", | |
| 114 service_provider_dll, "CloseServiceHandle", CloseServiceHandlePatch); | |
| 115 DCHECK(patched == 0); | |
| 116 | |
| 117 patched = g_iat_patch_open_service.Patch(L"dwrite.dll", | |
| 118 service_provider_dll, "OpenServiceW", OpenServiceWPatch); | |
| 119 DCHECK(patched == 0); | |
| 120 | |
| 121 patched = g_iat_patch_start_service.Patch(L"dwrite.dll", | |
| 122 service_provider_dll, "StartServiceW", StartServiceWPatch); | |
| 123 DCHECK(patched == 0); | |
| 124 | |
| 125 patched = g_iat_patch_nt_connect_port.Patch(L"dwrite.dll", | |
| 126 "ntdll.dll", "NtAlpcConnectPort", NtALpcConnectPortPatch); | |
| 127 DCHECK(patched == 0); | |
| 128 } | |
| 129 | |
| 130 // Windows-only DirectWrite support. These warm up the DirectWrite paths | |
| 131 // before sandbox lock down to allow Skia access to the Font Manager service. | |
| 132 void CreateDirectWriteFactory(IDWriteFactory** factory) { | |
| 133 typedef decltype(DWriteCreateFactory)* DWriteCreateFactoryProc; | |
| 134 HMODULE dwrite_dll = LoadLibraryW(L"dwrite.dll"); | |
| 135 // TODO(scottmg): Temporary code to track crash in http://crbug.com/387867. | |
| 136 if (!dwrite_dll) { | |
| 137 DWORD load_library_get_last_error = GetLastError(); | |
| 138 base::debug::Alias(&dwrite_dll); | |
| 139 base::debug::Alias(&load_library_get_last_error); | |
| 140 CHECK(false); | |
| 141 } | |
| 142 | |
| 143 PatchServiceManagerCalls(); | |
| 144 | |
| 145 DWriteCreateFactoryProc dwrite_create_factory_proc = | |
| 146 reinterpret_cast<DWriteCreateFactoryProc>( | |
| 147 GetProcAddress(dwrite_dll, "DWriteCreateFactory")); | |
| 148 // TODO(scottmg): Temporary code to track crash in http://crbug.com/387867. | |
| 149 if (!dwrite_create_factory_proc) { | |
| 150 DWORD get_proc_address_get_last_error = GetLastError(); | |
| 151 base::debug::Alias(&dwrite_create_factory_proc); | |
| 152 base::debug::Alias(&get_proc_address_get_last_error); | |
| 153 CHECK(false); | |
| 154 } | |
| 155 CHECK(SUCCEEDED( | |
| 156 dwrite_create_factory_proc(DWRITE_FACTORY_TYPE_ISOLATED, | |
| 157 __uuidof(IDWriteFactory), | |
| 158 reinterpret_cast<IUnknown**>(factory)))); | |
| 159 } | |
| 160 | |
| 161 HRESULT STDMETHODCALLTYPE StubFontCollection(IDWriteFactory* factory, | |
| 162 IDWriteFontCollection** col, | |
| 163 BOOL checkUpdates) { | |
| 164 // We always return pre-created font collection from here. | |
| 165 IDWriteFontCollection* custom_collection = GetCustomFontCollection(factory); | |
| 166 DCHECK(custom_collection != NULL); | |
| 167 *col = custom_collection; | |
| 168 return S_OK; | |
| 169 } | |
| 170 | |
| 171 void PatchDWriteFactory(IDWriteFactory* factory) { | |
| 172 const unsigned int kGetSystemFontCollectionVTableIndex = 3; | |
| 173 | |
| 174 PROC* vtable = *reinterpret_cast<PROC**>(factory); | |
| 175 PROC* function_ptr = &vtable[kGetSystemFontCollectionVTableIndex]; | |
| 176 void* stub_function = &StubFontCollection; | |
| 177 base::win::ModifyCode(function_ptr, &stub_function, sizeof(PROC)); | |
| 178 } | |
| 179 | |
| 180 } // namespace | |
| 181 | |
| 182 void DoPreSandboxWarmupForTypeface(SkTypeface* typeface) { | |
| 183 SkPaint paint_warmup; | |
| 184 paint_warmup.setTypeface(typeface); | |
| 185 wchar_t glyph = L'S'; | |
| 186 paint_warmup.measureText(&glyph, 2); | |
| 187 } | |
| 188 | |
| 189 SkFontMgr* GetPreSandboxWarmupFontMgr() { | |
| 190 if (!g_warmup_fontmgr) { | |
| 191 IDWriteFactory* factory; | |
| 192 CreateDirectWriteFactory(&factory); | |
| 193 | |
| 194 GetCustomFontCollection(factory); | |
| 195 | |
| 196 PatchDWriteFactory(factory); | |
| 197 | |
| 198 blink::WebFontRendering::setDirectWriteFactory(factory); | |
| 199 g_warmup_fontmgr = SkFontMgr_New_DirectWrite(factory); | |
| 200 } | |
| 201 return g_warmup_fontmgr; | |
| 202 } | |
| 203 | |
| 204 } // namespace content | |
| OLD | NEW |