| 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/common/font_warmup_win.h" | |
| 6 | |
| 7 #include <dwrite.h> | |
| 8 #include <stdint.h> | |
| 9 #include <map> | |
| 10 | |
| 11 #include "base/debug/alias.h" | |
| 12 #include "base/files/file_path.h" | |
| 13 #include "base/lazy_instance.h" | |
| 14 #include "base/logging.h" | |
| 15 #include "base/macros.h" | |
| 16 #include "base/memory/ref_counted.h" | |
| 17 #include "base/numerics/safe_conversions.h" | |
| 18 #include "base/numerics/safe_math.h" | |
| 19 #include "base/strings/utf_string_conversions.h" | |
| 20 #include "base/synchronization/lock.h" | |
| 21 #include "base/sys_byteorder.h" | |
| 22 #include "base/trace_event/trace_event.h" | |
| 23 #include "base/win/iat_patch_function.h" | |
| 24 #include "base/win/windows_version.h" | |
| 25 #include "content/public/common/dwrite_font_platform_win.h" | |
| 26 #include "ppapi/shared_impl/proxy_lock.h" | |
| 27 #include "skia/ext/fontmgr_default_win.h" | |
| 28 #include "skia/ext/refptr.h" | |
| 29 #include "third_party/WebKit/public/web/win/WebFontRendering.h" | |
| 30 #include "third_party/skia/include/core/SkPaint.h" | |
| 31 #include "third_party/skia/include/ports/SkFontMgr.h" | |
| 32 #include "third_party/skia/include/ports/SkTypeface_win.h" | |
| 33 #include "ui/gfx/hud_font.h" | |
| 34 | |
| 35 namespace content { | |
| 36 | |
| 37 namespace { | |
| 38 | |
| 39 // The Skia font manager, used for the life of the process (leaked at the end). | |
| 40 SkFontMgr* g_warmup_fontmgr = nullptr; | |
| 41 | |
| 42 base::win::IATPatchFunction g_iat_patch_open_sc_manager; | |
| 43 base::win::IATPatchFunction g_iat_patch_close_service_handle; | |
| 44 base::win::IATPatchFunction g_iat_patch_open_service; | |
| 45 base::win::IATPatchFunction g_iat_patch_start_service; | |
| 46 base::win::IATPatchFunction g_iat_patch_nt_connect_port; | |
| 47 | |
| 48 // These are from ntddk.h | |
| 49 #if !defined(STATUS_ACCESS_DENIED) | |
| 50 #define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L) | |
| 51 #endif | |
| 52 | |
| 53 typedef LONG NTSTATUS; | |
| 54 | |
| 55 const uintptr_t kFakeSCMHandle = 0xdead0001; | |
| 56 const uintptr_t kFakeServiceHandle = 0xdead0002; | |
| 57 | |
| 58 SC_HANDLE WINAPI OpenSCManagerWPatch(const wchar_t* machine_name, | |
| 59 const wchar_t* database_name, | |
| 60 DWORD access_mask) { | |
| 61 ::SetLastError(0); | |
| 62 return reinterpret_cast<SC_HANDLE>(kFakeSCMHandle); | |
| 63 } | |
| 64 | |
| 65 SC_HANDLE WINAPI OpenServiceWPatch(SC_HANDLE sc_manager, | |
| 66 const wchar_t* service_name, | |
| 67 DWORD access_mask) { | |
| 68 ::SetLastError(0); | |
| 69 return reinterpret_cast<SC_HANDLE>(kFakeServiceHandle); | |
| 70 } | |
| 71 | |
| 72 BOOL WINAPI CloseServiceHandlePatch(SC_HANDLE service_handle) { | |
| 73 if (service_handle != reinterpret_cast<SC_HANDLE>(kFakeServiceHandle) && | |
| 74 service_handle != reinterpret_cast<SC_HANDLE>(kFakeSCMHandle)) | |
| 75 CHECK(false); | |
| 76 ::SetLastError(0); | |
| 77 return TRUE; | |
| 78 } | |
| 79 | |
| 80 BOOL WINAPI StartServiceWPatch(SC_HANDLE service, | |
| 81 DWORD args, | |
| 82 const wchar_t** arg_vectors) { | |
| 83 if (service != reinterpret_cast<SC_HANDLE>(kFakeServiceHandle)) | |
| 84 CHECK(false); | |
| 85 ::SetLastError(ERROR_ACCESS_DENIED); | |
| 86 return FALSE; | |
| 87 } | |
| 88 | |
| 89 NTSTATUS WINAPI NtALpcConnectPortPatch(HANDLE* port_handle, | |
| 90 void* port_name, | |
| 91 void* object_attribs, | |
| 92 void* port_attribs, | |
| 93 DWORD flags, | |
| 94 void* server_sid, | |
| 95 void* message, | |
| 96 DWORD* buffer_length, | |
| 97 void* out_message_attributes, | |
| 98 void* in_message_attributes, | |
| 99 void* time_out) { | |
| 100 return STATUS_ACCESS_DENIED; | |
| 101 } | |
| 102 | |
| 103 // Windows-only DirectWrite support. These warm up the DirectWrite paths | |
| 104 // before sandbox lock down to allow Skia access to the Font Manager service. | |
| 105 void CreateDirectWriteFactory(IDWriteFactory** factory) { | |
| 106 typedef decltype(DWriteCreateFactory)* DWriteCreateFactoryProc; | |
| 107 HMODULE dwrite_dll = LoadLibraryW(L"dwrite.dll"); | |
| 108 // TODO(scottmg): Temporary code to track crash in http://crbug.com/387867. | |
| 109 if (!dwrite_dll) { | |
| 110 DWORD load_library_get_last_error = GetLastError(); | |
| 111 base::debug::Alias(&dwrite_dll); | |
| 112 base::debug::Alias(&load_library_get_last_error); | |
| 113 CHECK(false); | |
| 114 } | |
| 115 | |
| 116 PatchServiceManagerCalls(); | |
| 117 | |
| 118 DWriteCreateFactoryProc dwrite_create_factory_proc = | |
| 119 reinterpret_cast<DWriteCreateFactoryProc>( | |
| 120 GetProcAddress(dwrite_dll, "DWriteCreateFactory")); | |
| 121 // TODO(scottmg): Temporary code to track crash in http://crbug.com/387867. | |
| 122 if (!dwrite_create_factory_proc) { | |
| 123 DWORD get_proc_address_get_last_error = GetLastError(); | |
| 124 base::debug::Alias(&dwrite_create_factory_proc); | |
| 125 base::debug::Alias(&get_proc_address_get_last_error); | |
| 126 CHECK(false); | |
| 127 } | |
| 128 CHECK(SUCCEEDED(dwrite_create_factory_proc( | |
| 129 DWRITE_FACTORY_TYPE_ISOLATED, __uuidof(IDWriteFactory), | |
| 130 reinterpret_cast<IUnknown**>(factory)))); | |
| 131 } | |
| 132 | |
| 133 HRESULT STDMETHODCALLTYPE StubFontCollection(IDWriteFactory* factory, | |
| 134 IDWriteFontCollection** col, | |
| 135 BOOL checkUpdates) { | |
| 136 // We always return pre-created font collection from here. | |
| 137 IDWriteFontCollection* custom_collection = GetCustomFontCollection(factory); | |
| 138 DCHECK(custom_collection != nullptr); | |
| 139 *col = custom_collection; | |
| 140 return S_OK; | |
| 141 } | |
| 142 | |
| 143 void PatchDWriteFactory(IDWriteFactory* factory) { | |
| 144 const unsigned int kGetSystemFontCollectionVTableIndex = 3; | |
| 145 | |
| 146 PROC* vtable = *reinterpret_cast<PROC**>(factory); | |
| 147 PROC* function_ptr = &vtable[kGetSystemFontCollectionVTableIndex]; | |
| 148 void* stub_function = &StubFontCollection; | |
| 149 base::win::ModifyCode(function_ptr, &stub_function, sizeof(PROC)); | |
| 150 } | |
| 151 | |
| 152 // Class to fake out a DC or a Font object. Maintains a reference to a | |
| 153 // SkTypeFace to emulate the simple operation of a DC and Font. | |
| 154 class FakeGdiObject : public base::RefCountedThreadSafe<FakeGdiObject> { | |
| 155 public: | |
| 156 FakeGdiObject(uint32_t magic, void* handle) | |
| 157 : handle_(handle), magic_(magic) {} | |
| 158 | |
| 159 void set_typeface(const skia::RefPtr<SkTypeface>& typeface) { | |
| 160 typeface_ = typeface; | |
| 161 } | |
| 162 | |
| 163 skia::RefPtr<SkTypeface> typeface() { return typeface_; } | |
| 164 void* handle() { return handle_; } | |
| 165 uint32_t magic() { return magic_; } | |
| 166 | |
| 167 private: | |
| 168 friend class base::RefCountedThreadSafe<FakeGdiObject>; | |
| 169 ~FakeGdiObject() {} | |
| 170 | |
| 171 void* handle_; | |
| 172 uint32_t magic_; | |
| 173 skia::RefPtr<SkTypeface> typeface_; | |
| 174 | |
| 175 DISALLOW_COPY_AND_ASSIGN(FakeGdiObject); | |
| 176 }; | |
| 177 | |
| 178 // This class acts as a factory for creating new fake GDI objects. It also maps | |
| 179 // the new instances of the FakeGdiObject class to an incrementing handle value | |
| 180 // which is passed to the caller of the emulated GDI function for later | |
| 181 // reference. We can't be sure that this won't be used in a multi-threaded | |
| 182 // environment so we need to ensure a lock is taken before accessing the map of | |
| 183 // issued objects. | |
| 184 class FakeGdiObjectFactory { | |
| 185 public: | |
| 186 FakeGdiObjectFactory() : curr_handle_(0) {} | |
| 187 | |
| 188 // Find a corresponding fake GDI object and verify its magic value. | |
| 189 // The returned value is either nullptr or the validated object. | |
| 190 scoped_refptr<FakeGdiObject> Validate(void* obj, uint32_t magic) { | |
| 191 if (obj) { | |
| 192 base::AutoLock scoped_lock(objects_lock_); | |
| 193 auto handle_entry = objects_.find(obj); | |
| 194 if (handle_entry != objects_.end() && | |
| 195 handle_entry->second->magic() == magic) { | |
| 196 return handle_entry->second; | |
| 197 } | |
| 198 } | |
| 199 return nullptr; | |
| 200 } | |
| 201 | |
| 202 scoped_refptr<FakeGdiObject> Create(uint32_t magic) { | |
| 203 base::AutoLock scoped_lock(objects_lock_); | |
| 204 curr_handle_++; | |
| 205 // We don't support wrapping the fake handle value. | |
| 206 void* handle = reinterpret_cast<void*>(curr_handle_.ValueOrDie()); | |
| 207 scoped_refptr<FakeGdiObject> object(new FakeGdiObject(magic, handle)); | |
| 208 objects_[handle] = object; | |
| 209 return object; | |
| 210 } | |
| 211 | |
| 212 bool DeleteObject(void* obj, uint32_t magic) { | |
| 213 base::AutoLock scoped_lock(objects_lock_); | |
| 214 auto handle_entry = objects_.find(obj); | |
| 215 if (handle_entry != objects_.end() && | |
| 216 handle_entry->second->magic() == magic) { | |
| 217 objects_.erase(handle_entry); | |
| 218 return true; | |
| 219 } | |
| 220 return false; | |
| 221 } | |
| 222 | |
| 223 size_t GetObjectCount() { | |
| 224 base::AutoLock scoped_lock(objects_lock_); | |
| 225 return objects_.size(); | |
| 226 } | |
| 227 | |
| 228 void ResetObjectHandles() { | |
| 229 base::AutoLock scoped_lock(objects_lock_); | |
| 230 curr_handle_ = 0; | |
| 231 objects_.clear(); | |
| 232 } | |
| 233 | |
| 234 private: | |
| 235 base::CheckedNumeric<uintptr_t> curr_handle_; | |
| 236 std::map<void*, scoped_refptr<FakeGdiObject>> objects_; | |
| 237 base::Lock objects_lock_; | |
| 238 | |
| 239 DISALLOW_COPY_AND_ASSIGN(FakeGdiObjectFactory); | |
| 240 }; | |
| 241 | |
| 242 base::LazyInstance<FakeGdiObjectFactory>::Leaky g_fake_gdi_object_factory = | |
| 243 LAZY_INSTANCE_INITIALIZER; | |
| 244 | |
| 245 // Magic values for the fake GDI objects. | |
| 246 const uint32_t kFakeDCMagic = 'fkdc'; | |
| 247 const uint32_t kFakeFontMagic = 'fkft'; | |
| 248 | |
| 249 skia::RefPtr<SkTypeface> GetTypefaceFromLOGFONT(const LOGFONTW* log_font) { | |
| 250 CHECK(g_warmup_fontmgr); | |
| 251 int weight = log_font->lfWeight; | |
| 252 if (weight == FW_DONTCARE) | |
| 253 weight = SkFontStyle::kNormal_Weight; | |
| 254 | |
| 255 SkFontStyle style(weight, log_font->lfWidth, | |
| 256 log_font->lfItalic ? SkFontStyle::kItalic_Slant | |
| 257 : SkFontStyle::kUpright_Slant); | |
| 258 | |
| 259 std::string family_name = base::WideToUTF8(log_font->lfFaceName); | |
| 260 ppapi::ProxyAutoLock lock; // Needed for DirectWrite font proxy. | |
| 261 return skia::AdoptRef( | |
| 262 g_warmup_fontmgr->matchFamilyStyle(family_name.c_str(), style)); | |
| 263 } | |
| 264 | |
| 265 HDC WINAPI CreateCompatibleDCPatch(HDC dc_handle) { | |
| 266 scoped_refptr<FakeGdiObject> ret = | |
| 267 g_fake_gdi_object_factory.Get().Create(kFakeDCMagic); | |
| 268 return static_cast<HDC>(ret->handle()); | |
| 269 } | |
| 270 | |
| 271 HFONT WINAPI CreateFontIndirectWPatch(const LOGFONTW* log_font) { | |
| 272 if (!log_font) | |
| 273 return nullptr; | |
| 274 | |
| 275 skia::RefPtr<SkTypeface> typeface = GetTypefaceFromLOGFONT(log_font); | |
| 276 if (!typeface) | |
| 277 return nullptr; | |
| 278 | |
| 279 scoped_refptr<FakeGdiObject> ret = | |
| 280 g_fake_gdi_object_factory.Get().Create(kFakeFontMagic); | |
| 281 ret->set_typeface(typeface); | |
| 282 | |
| 283 return static_cast<HFONT>(ret->handle()); | |
| 284 } | |
| 285 | |
| 286 BOOL WINAPI DeleteDCPatch(HDC dc_handle) { | |
| 287 return g_fake_gdi_object_factory.Get().DeleteObject(dc_handle, kFakeDCMagic); | |
| 288 } | |
| 289 | |
| 290 BOOL WINAPI DeleteObjectPatch(HGDIOBJ object_handle) { | |
| 291 return g_fake_gdi_object_factory.Get().DeleteObject(object_handle, | |
| 292 kFakeFontMagic); | |
| 293 } | |
| 294 | |
| 295 int WINAPI EnumFontFamiliesExWPatch(HDC dc_handle, | |
| 296 LPLOGFONTW log_font, | |
| 297 FONTENUMPROCW enum_callback, | |
| 298 LPARAM callback_param, | |
| 299 DWORD flags) { | |
| 300 scoped_refptr<FakeGdiObject> dc_obj = | |
| 301 g_fake_gdi_object_factory.Get().Validate(dc_handle, kFakeDCMagic); | |
| 302 if (!dc_obj) | |
| 303 return 1; | |
| 304 | |
| 305 if (!log_font || !enum_callback) | |
| 306 return 1; | |
| 307 | |
| 308 skia::RefPtr<SkTypeface> typeface = GetTypefaceFromLOGFONT(log_font); | |
| 309 if (!typeface) | |
| 310 return 1; | |
| 311 | |
| 312 ENUMLOGFONTEXDVW enum_log_font = {}; | |
| 313 enum_log_font.elfEnumLogfontEx.elfLogFont = *log_font; | |
| 314 // TODO: Fill in the rest of the text metric structure. Not yet needed for | |
| 315 // Flash support but might be in the future. | |
| 316 NEWTEXTMETRICEXW text_metric = {}; | |
| 317 text_metric.ntmTm.ntmFlags = NTM_PS_OPENTYPE; | |
| 318 | |
| 319 return enum_callback(&enum_log_font.elfEnumLogfontEx.elfLogFont, | |
| 320 reinterpret_cast<TEXTMETRIC*>(&text_metric), | |
| 321 TRUETYPE_FONTTYPE, callback_param); | |
| 322 } | |
| 323 | |
| 324 DWORD WINAPI GetFontDataPatch(HDC dc_handle, | |
| 325 DWORD table_tag, | |
| 326 DWORD table_offset, | |
| 327 LPVOID buffer, | |
| 328 DWORD buffer_length) { | |
| 329 scoped_refptr<FakeGdiObject> dc_obj = | |
| 330 g_fake_gdi_object_factory.Get().Validate(dc_handle, kFakeDCMagic); | |
| 331 if (!dc_obj) | |
| 332 return GDI_ERROR; | |
| 333 | |
| 334 skia::RefPtr<SkTypeface> typeface = dc_obj->typeface(); | |
| 335 if (!typeface) | |
| 336 return GDI_ERROR; | |
| 337 | |
| 338 // |getTableData| handles |buffer| being nullptr. However if it is nullptr | |
| 339 // then set the size to INT32_MAX otherwise |getTableData| will return the | |
| 340 // minimum value between the table entry size and the size passed in. The | |
| 341 // common Windows idiom is to pass 0 as |buffer_length| when passing nullptr, | |
| 342 // which would in this case result in |getTableData| returning 0 which isn't | |
| 343 // the correct answer for emulating GDI. |table_tag| must also have its | |
| 344 // byte order swapped to counter the swap which occurs in the called method. | |
| 345 size_t length = typeface->getTableData( | |
| 346 base::ByteSwap(base::strict_cast<uint32_t>(table_tag)), table_offset, | |
| 347 buffer ? buffer_length : INT32_MAX, buffer); | |
| 348 // We can't distinguish between an empty table and an error. | |
| 349 if (length == 0) | |
| 350 return GDI_ERROR; | |
| 351 | |
| 352 return base::checked_cast<DWORD>(length); | |
| 353 } | |
| 354 | |
| 355 HGDIOBJ WINAPI SelectObjectPatch(HDC dc_handle, HGDIOBJ object_handle) { | |
| 356 scoped_refptr<FakeGdiObject> dc_obj = | |
| 357 g_fake_gdi_object_factory.Get().Validate(dc_handle, kFakeDCMagic); | |
| 358 if (!dc_obj) | |
| 359 return nullptr; | |
| 360 | |
| 361 scoped_refptr<FakeGdiObject> font_obj = | |
| 362 g_fake_gdi_object_factory.Get().Validate(object_handle, kFakeFontMagic); | |
| 363 if (!font_obj) | |
| 364 return nullptr; | |
| 365 | |
| 366 // Construct a new fake font object to handle the old font if there's one. | |
| 367 scoped_refptr<FakeGdiObject> new_font_obj; | |
| 368 skia::RefPtr<SkTypeface> old_typeface = dc_obj->typeface(); | |
| 369 if (old_typeface) { | |
| 370 new_font_obj = g_fake_gdi_object_factory.Get().Create(kFakeFontMagic); | |
| 371 new_font_obj->set_typeface(old_typeface); | |
| 372 } | |
| 373 dc_obj->set_typeface(font_obj->typeface()); | |
| 374 | |
| 375 if (new_font_obj) | |
| 376 return static_cast<HGDIOBJ>(new_font_obj->handle()); | |
| 377 return nullptr; | |
| 378 } | |
| 379 | |
| 380 void DoSingleGdiPatch(base::win::IATPatchFunction& patch, | |
| 381 const base::FilePath& path, | |
| 382 const char* function_name, | |
| 383 void* new_function) { | |
| 384 patch.Patch(path.value().c_str(), "gdi32.dll", function_name, new_function); | |
| 385 } | |
| 386 | |
| 387 class GdiFontPatchDataImpl : public content::GdiFontPatchData { | |
| 388 public: | |
| 389 GdiFontPatchDataImpl(const base::FilePath& path); | |
| 390 | |
| 391 private: | |
| 392 base::win::IATPatchFunction create_compatible_dc_patch_; | |
| 393 base::win::IATPatchFunction create_font_indirect_patch_; | |
| 394 base::win::IATPatchFunction create_delete_dc_patch_; | |
| 395 base::win::IATPatchFunction create_delete_object_patch_; | |
| 396 base::win::IATPatchFunction create_enum_font_families_patch_; | |
| 397 base::win::IATPatchFunction create_get_font_data_patch_; | |
| 398 base::win::IATPatchFunction create_select_object_patch_; | |
| 399 }; | |
| 400 | |
| 401 GdiFontPatchDataImpl::GdiFontPatchDataImpl(const base::FilePath& path) { | |
| 402 DoSingleGdiPatch(create_compatible_dc_patch_, path, "CreateCompatibleDC", | |
| 403 CreateCompatibleDCPatch); | |
| 404 DoSingleGdiPatch(create_font_indirect_patch_, path, "CreateFontIndirectW", | |
| 405 CreateFontIndirectWPatch); | |
| 406 DoSingleGdiPatch(create_delete_dc_patch_, path, "DeleteDC", DeleteDCPatch); | |
| 407 DoSingleGdiPatch(create_delete_object_patch_, path, "DeleteObject", | |
| 408 DeleteObjectPatch); | |
| 409 DoSingleGdiPatch(create_enum_font_families_patch_, path, | |
| 410 "EnumFontFamiliesExW", EnumFontFamiliesExWPatch); | |
| 411 DoSingleGdiPatch(create_get_font_data_patch_, path, "GetFontData", | |
| 412 GetFontDataPatch); | |
| 413 DoSingleGdiPatch(create_select_object_patch_, path, "SelectObject", | |
| 414 SelectObjectPatch); | |
| 415 } | |
| 416 | |
| 417 } // namespace | |
| 418 | |
| 419 // Directwrite connects to the font cache service to retrieve information about | |
| 420 // fonts installed on the system etc. This works well outside the sandbox and | |
| 421 // within the sandbox as long as the lpc connection maintained by the current | |
| 422 // process with the font cache service remains valid. It appears that there | |
| 423 // are cases when this connection is dropped after which directwrite is unable | |
| 424 // to connect to the font cache service which causes problems with characters | |
| 425 // disappearing. | |
| 426 // Directwrite has fallback code to enumerate fonts if it is unable to connect | |
| 427 // to the font cache service. We need to intercept the following APIs to | |
| 428 // ensure that it does not connect to the font cache service. | |
| 429 // NtALpcConnectPort | |
| 430 // OpenSCManagerW | |
| 431 // OpenServiceW | |
| 432 // StartServiceW | |
| 433 // CloseServiceHandle. | |
| 434 // These are all IAT patched. | |
| 435 void PatchServiceManagerCalls() { | |
| 436 static bool is_patched = false; | |
| 437 if (is_patched) | |
| 438 return; | |
| 439 const char* service_provider_dll = | |
| 440 (base::win::GetVersion() >= base::win::VERSION_WIN8 | |
| 441 ? "api-ms-win-service-management-l1-1-0.dll" | |
| 442 : "advapi32.dll"); | |
| 443 | |
| 444 is_patched = true; | |
| 445 | |
| 446 DWORD patched = | |
| 447 g_iat_patch_open_sc_manager.Patch(L"dwrite.dll", service_provider_dll, | |
| 448 "OpenSCManagerW", OpenSCManagerWPatch); | |
| 449 DCHECK(patched == 0); | |
| 450 | |
| 451 patched = g_iat_patch_close_service_handle.Patch( | |
| 452 L"dwrite.dll", service_provider_dll, "CloseServiceHandle", | |
| 453 CloseServiceHandlePatch); | |
| 454 DCHECK(patched == 0); | |
| 455 | |
| 456 patched = g_iat_patch_open_service.Patch(L"dwrite.dll", service_provider_dll, | |
| 457 "OpenServiceW", OpenServiceWPatch); | |
| 458 DCHECK(patched == 0); | |
| 459 | |
| 460 patched = g_iat_patch_start_service.Patch( | |
| 461 L"dwrite.dll", service_provider_dll, "StartServiceW", StartServiceWPatch); | |
| 462 DCHECK(patched == 0); | |
| 463 | |
| 464 patched = g_iat_patch_nt_connect_port.Patch( | |
| 465 L"dwrite.dll", "ntdll.dll", "NtAlpcConnectPort", NtALpcConnectPortPatch); | |
| 466 DCHECK(patched == 0); | |
| 467 } | |
| 468 | |
| 469 void DoPreSandboxWarmupForTypeface(SkTypeface* typeface) { | |
| 470 SkPaint paint_warmup; | |
| 471 paint_warmup.setTypeface(typeface); | |
| 472 wchar_t glyph = L'S'; | |
| 473 paint_warmup.measureText(&glyph, 2); | |
| 474 } | |
| 475 | |
| 476 SkFontMgr* GetPreSandboxWarmupFontMgr() { | |
| 477 if (!g_warmup_fontmgr) { | |
| 478 IDWriteFactory* factory; | |
| 479 CreateDirectWriteFactory(&factory); | |
| 480 | |
| 481 GetCustomFontCollection(factory); | |
| 482 | |
| 483 PatchDWriteFactory(factory); | |
| 484 | |
| 485 blink::WebFontRendering::setDirectWriteFactory(factory); | |
| 486 g_warmup_fontmgr = SkFontMgr_New_DirectWrite(factory); | |
| 487 } | |
| 488 return g_warmup_fontmgr; | |
| 489 } | |
| 490 | |
| 491 GdiFontPatchData* PatchGdiFontEnumeration(const base::FilePath& path) { | |
| 492 if (ShouldUseDirectWriteFontProxyFieldTrial() && !g_warmup_fontmgr) | |
| 493 g_warmup_fontmgr = SkFontMgr_New_DirectWrite(); | |
| 494 // If not using the font proxy, we assume |g_warmup_fontmgr| is already | |
| 495 // initialized before this function is called. | |
| 496 DCHECK(g_warmup_fontmgr); | |
| 497 return new GdiFontPatchDataImpl(path); | |
| 498 } | |
| 499 | |
| 500 size_t GetEmulatedGdiHandleCountForTesting() { | |
| 501 return g_fake_gdi_object_factory.Get().GetObjectCount(); | |
| 502 } | |
| 503 | |
| 504 void ResetEmulatedGdiHandlesForTesting() { | |
| 505 g_fake_gdi_object_factory.Get().ResetObjectHandles(); | |
| 506 } | |
| 507 | |
| 508 void SetPreSandboxWarmupFontMgrForTesting(SkFontMgr* fontmgr) { | |
| 509 g_warmup_fontmgr = fontmgr; | |
| 510 } | |
| 511 | |
| 512 void WarmupDirectWrite() { | |
| 513 TRACE_EVENT0("startup", "content::WarmupDirectWrite"); | |
| 514 | |
| 515 // The objects used here are intentionally not freed as we want the Skia | |
| 516 // code to use these objects after warmup. | |
| 517 SetDefaultSkiaFactory(GetPreSandboxWarmupFontMgr()); | |
| 518 | |
| 519 // We need to warm up *some* font for DirectWrite. We also need to pass one | |
| 520 // down for the CC HUD code, so use the same one here. Note that we don't use | |
| 521 // a monospace as would be nice in an attempt to avoid a small startup time | |
| 522 // regression, see http://crbug.com/463613. | |
| 523 skia::RefPtr<SkTypeface> hud_typeface = skia::AdoptRef( | |
| 524 GetPreSandboxWarmupFontMgr()->legacyCreateTypeface("Times New Roman", 0)); | |
| 525 DoPreSandboxWarmupForTypeface(hud_typeface.get()); | |
| 526 gfx::SetHudTypeface(hud_typeface); | |
| 527 } | |
| 528 | |
| 529 } // namespace content | |
| OLD | NEW |