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 |