OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/common/font_warmup_win.h" | 5 #include "content/common/font_warmup_win.h" |
6 | 6 |
7 #include <dwrite.h> | 7 #include <dwrite.h> |
8 #include <map> | |
8 | 9 |
9 #include "base/debug/alias.h" | 10 #include "base/debug/alias.h" |
11 #include "base/files/file_path.h" | |
12 #include "base/lazy_instance.h" | |
10 #include "base/logging.h" | 13 #include "base/logging.h" |
14 #include "base/memory/ref_counted.h" | |
15 #include "base/numerics/safe_conversions.h" | |
16 #include "base/numerics/safe_math.h" | |
17 #include "base/strings/utf_string_conversions.h" | |
18 #include "base/synchronization/lock.h" | |
19 #include "base/sys_byteorder.h" | |
11 #include "base/win/iat_patch_function.h" | 20 #include "base/win/iat_patch_function.h" |
12 #include "base/win/windows_version.h" | 21 #include "base/win/windows_version.h" |
13 #include "content/public/common/dwrite_font_platform_win.h" | 22 #include "content/public/common/dwrite_font_platform_win.h" |
14 #include "skia/ext/fontmgr_default_win.h" | 23 #include "skia/ext/fontmgr_default_win.h" |
15 #include "skia/ext/refptr.h" | 24 #include "skia/ext/refptr.h" |
16 #include "third_party/WebKit/public/web/win/WebFontRendering.h" | 25 #include "third_party/WebKit/public/web/win/WebFontRendering.h" |
17 #include "third_party/skia/include/core/SkPaint.h" | 26 #include "third_party/skia/include/core/SkPaint.h" |
18 #include "third_party/skia/include/ports/SkFontMgr.h" | 27 #include "third_party/skia/include/ports/SkFontMgr.h" |
19 #include "third_party/skia/include/ports/SkTypeface_win.h" | 28 #include "third_party/skia/include/ports/SkTypeface_win.h" |
20 #include "ui/gfx/hud_font.h" | 29 #include "ui/gfx/hud_font.h" |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
178 | 187 |
179 void PatchDWriteFactory(IDWriteFactory* factory) { | 188 void PatchDWriteFactory(IDWriteFactory* factory) { |
180 const unsigned int kGetSystemFontCollectionVTableIndex = 3; | 189 const unsigned int kGetSystemFontCollectionVTableIndex = 3; |
181 | 190 |
182 PROC* vtable = *reinterpret_cast<PROC**>(factory); | 191 PROC* vtable = *reinterpret_cast<PROC**>(factory); |
183 PROC* function_ptr = &vtable[kGetSystemFontCollectionVTableIndex]; | 192 PROC* function_ptr = &vtable[kGetSystemFontCollectionVTableIndex]; |
184 void* stub_function = &StubFontCollection; | 193 void* stub_function = &StubFontCollection; |
185 base::win::ModifyCode(function_ptr, &stub_function, sizeof(PROC)); | 194 base::win::ModifyCode(function_ptr, &stub_function, sizeof(PROC)); |
186 } | 195 } |
187 | 196 |
197 // Class to fake out a DC or a Font object. Maintains a reference to a | |
198 // SkTypeFace to emulate the simple operation of a DC and Font. We can't | |
199 // be sure that this won't be used in a multi-threaded environment so we | |
200 // need to ensure a lock is taken before updating the static table of | |
201 // issued objects. | |
202 class FakeGdiObject : public base::RefCountedThreadSafe<FakeGdiObject> { | |
203 public: | |
204 FakeGdiObject(uint32_t magic, void* handle) | |
205 : magic_(magic), handle_(handle) {} | |
206 ~FakeGdiObject() {} | |
207 | |
208 void SetTypeface(const skia::RefPtr<SkTypeface>& typeface) { | |
nasko
2015/09/21 22:58:19
set_typeface(...)
forshaw
2015/09/21 23:28:23
Acknowledged.
| |
209 typeface_ = typeface; | |
210 } | |
211 | |
212 skia::RefPtr<SkTypeface> GetTypeface() { return typeface_; } | |
nasko
2015/09/21 22:58:19
Simple accessors are just named after the variable
forshaw
2015/09/21 23:28:23
Acknowledged.
| |
213 void* GetHandle() { return handle_; } | |
214 uint32_t GetMagic() { return magic_; } | |
215 | |
216 private: | |
217 friend class base::RefCountedThreadSafe<FakeGdiObject>; | |
218 | |
219 void* handle_; | |
220 uint32_t magic_; | |
221 skia::RefPtr<SkTypeface> typeface_; | |
222 | |
223 DISALLOW_COPY_AND_ASSIGN(FakeGdiObject); | |
224 }; | |
225 | |
226 // Magic values for the fake GDI objects. | |
227 const uint32_t kFakeDCMagic = 'fkdc'; | |
228 const uint32_t kFakeFontMagic = 'fkft'; | |
229 | |
230 class FakeGdiObjectFactory { | |
nasko
2015/09/21 22:58:19
A small class level comment explaining the goal of
forshaw
2015/09/21 23:28:23
Acknowledged.
| |
231 public: | |
232 FakeGdiObjectFactory() : curr_handle_(0) {} | |
233 | |
234 // Find a corresponding fake GDI object and verify its magic value. | |
235 // The returned value is either nullptr or the validated object. | |
236 scoped_refptr<FakeGdiObject> Validate(void* obj, uint32_t magic) { | |
237 if (obj) { | |
238 base::AutoLock scoped_lock(objects_lock_); | |
239 auto handle_entry = objects_.find(obj); | |
240 if (handle_entry != objects_.end() && | |
241 handle_entry->second->GetMagic() == magic) { | |
242 return handle_entry->second; | |
243 } | |
244 } | |
245 return nullptr; | |
246 } | |
247 | |
248 scoped_refptr<FakeGdiObject> Create(uint32_t magic) { | |
249 base::AutoLock scoped_lock(objects_lock_); | |
250 curr_handle_++; | |
251 // We don't support wrapping the fake handle value. | |
252 void* handle = reinterpret_cast<void*>(curr_handle_.ValueOrDie()); | |
253 scoped_refptr<FakeGdiObject> object(new FakeGdiObject(magic, handle)); | |
254 objects_[handle] = object; | |
255 return object; | |
256 } | |
257 | |
258 bool DeleteObject(void* obj, uint32_t magic) { | |
259 base::AutoLock scoped_lock(objects_lock_); | |
260 auto handle_entry = objects_.find(obj); | |
261 if (handle_entry != objects_.end() && | |
262 handle_entry->second->GetMagic() == magic) { | |
263 objects_.erase(handle_entry); | |
264 return true; | |
265 } | |
266 return false; | |
267 } | |
268 | |
269 size_t GetObjectCount() { | |
270 base::AutoLock scoped_lock(objects_lock_); | |
271 return objects_.size(); | |
272 } | |
273 | |
274 void ResetObjectHandles() { | |
275 base::AutoLock scoped_lock(objects_lock_); | |
276 curr_handle_ = 0; | |
277 objects_.clear(); | |
278 } | |
279 | |
280 private: | |
281 base::CheckedNumeric<uintptr_t> curr_handle_; | |
282 std::map<void*, scoped_refptr<FakeGdiObject>> objects_; | |
283 base::Lock objects_lock_; | |
284 | |
285 DISALLOW_COPY_AND_ASSIGN(FakeGdiObjectFactory); | |
286 }; | |
287 | |
288 base::LazyInstance<FakeGdiObjectFactory>::Leaky g_fake_gdi_object_factory = | |
nasko
2015/09/21 22:58:19
I'd move this right above where the other constant
forshaw
2015/09/21 23:28:24
Hopefully I've moved it to where you expected, wel
| |
289 LAZY_INSTANCE_INITIALIZER; | |
290 | |
291 skia::RefPtr<SkTypeface> GetTypefaceFromLOGFONT(const LOGFONTW* log_font) { | |
292 CHECK(g_warmup_fontmgr); | |
293 int weight = log_font->lfWeight; | |
294 if (weight == FW_DONTCARE) | |
295 weight = SkFontStyle::kNormal_Weight; | |
296 | |
297 SkFontStyle style(weight, log_font->lfWidth, | |
298 log_font->lfItalic ? SkFontStyle::kItalic_Slant | |
299 : SkFontStyle::kUpright_Slant); | |
300 | |
301 std::string family_name = base::WideToUTF8(log_font->lfFaceName); | |
302 return skia::AdoptRef( | |
303 g_warmup_fontmgr->matchFamilyStyle(family_name.c_str(), style)); | |
304 } | |
305 | |
306 HDC WINAPI CreateCompatibleDCPatch(HDC dc_handle) { | |
307 scoped_refptr<FakeGdiObject> ret = | |
308 g_fake_gdi_object_factory.Get().Create(kFakeDCMagic); | |
309 return static_cast<HDC>(ret->GetHandle()); | |
310 } | |
311 | |
312 HFONT WINAPI CreateFontIndirectWPatch(const LOGFONTW* log_font) { | |
313 if (!log_font) | |
314 return nullptr; | |
315 | |
316 skia::RefPtr<SkTypeface> typeface = GetTypefaceFromLOGFONT(log_font); | |
317 if (!typeface) | |
318 return nullptr; | |
319 | |
320 scoped_refptr<FakeGdiObject> ret = | |
321 g_fake_gdi_object_factory.Get().Create(kFakeFontMagic); | |
322 ret->SetTypeface(typeface); | |
323 | |
324 return static_cast<HFONT>(ret->GetHandle()); | |
325 } | |
326 | |
327 BOOL WINAPI DeleteDCPatch(HDC dc_handle) { | |
328 return g_fake_gdi_object_factory.Get().DeleteObject(dc_handle, kFakeDCMagic); | |
329 } | |
330 | |
331 BOOL WINAPI DeleteObjectPatch(HGDIOBJ object_handle) { | |
332 return g_fake_gdi_object_factory.Get().DeleteObject(object_handle, | |
333 kFakeFontMagic); | |
334 } | |
335 | |
336 int WINAPI EnumFontFamiliesExWPatch(HDC dc_handle, | |
337 LPLOGFONTW log_font, | |
338 FONTENUMPROCW enum_callback, | |
339 LPARAM callback_param, | |
340 DWORD flags) { | |
341 scoped_refptr<FakeGdiObject> dc_obj = | |
342 g_fake_gdi_object_factory.Get().Validate(dc_handle, kFakeDCMagic); | |
343 if (!dc_obj) | |
344 return 1; | |
345 | |
346 if (!log_font || !enum_callback) | |
347 return 1; | |
348 | |
349 skia::RefPtr<SkTypeface> typeface = GetTypefaceFromLOGFONT(log_font); | |
350 if (!typeface) | |
351 return 1; | |
352 | |
353 ENUMLOGFONTEXDVW enum_log_font = {0}; | |
354 enum_log_font.elfEnumLogfontEx.elfLogFont = *log_font; | |
355 // TODO: Fill in the rest of the text metric structure. Not yet needed for | |
356 // Flash support but might be in the future. | |
357 NEWTEXTMETRICEXW text_metric = {0}; | |
358 text_metric.ntmTm.ntmFlags = NTM_PS_OPENTYPE; | |
359 | |
360 return enum_callback(&enum_log_font.elfEnumLogfontEx.elfLogFont, | |
361 reinterpret_cast<TEXTMETRIC*>(&text_metric), | |
362 TRUETYPE_FONTTYPE, callback_param); | |
363 } | |
364 | |
365 DWORD WINAPI GetFontDataPatch(HDC dc_handle, | |
366 DWORD table_tag, | |
367 DWORD table_offset, | |
368 LPVOID buffer, | |
369 DWORD buffer_length) { | |
370 scoped_refptr<FakeGdiObject> dc_obj = | |
371 g_fake_gdi_object_factory.Get().Validate(dc_handle, kFakeDCMagic); | |
372 if (!dc_obj) | |
373 return GDI_ERROR; | |
374 | |
375 skia::RefPtr<SkTypeface> typeface = dc_obj->GetTypeface(); | |
376 if (!typeface) | |
377 return GDI_ERROR; | |
378 | |
379 // |getTableData| handles |buffer| being nullptr. However if it is nullptr | |
380 // then set the size to INT32_MAX otherwise |getTableData| will return the | |
381 // minimum value between the table entry size and the size passed in. The | |
382 // common Windows idiom is to pass 0 as |buffer_length| when passing nullptr, | |
383 // which would in this case result in |getTableData| returning 0 which isn't | |
384 // the correct answer for emulating GDI. |table_tag| must also have its | |
385 // byte order swapped to counter the swap which occurs in the called method. | |
386 size_t length = typeface->getTableData( | |
387 base::ByteSwap(base::strict_cast<uint32_t>(table_tag)), table_offset, | |
388 buffer ? buffer_length : INT32_MAX, buffer); | |
389 // We can't distinguish between an empty table and an error. | |
390 if (length == 0) | |
391 return GDI_ERROR; | |
392 | |
393 return base::checked_cast<DWORD>(length); | |
394 } | |
395 | |
396 HGDIOBJ WINAPI SelectObjectPatch(HDC dc_handle, HGDIOBJ object_handle) { | |
397 scoped_refptr<FakeGdiObject> dc_obj = | |
398 g_fake_gdi_object_factory.Get().Validate(dc_handle, kFakeDCMagic); | |
399 if (!dc_obj) | |
400 return nullptr; | |
401 | |
402 scoped_refptr<FakeGdiObject> font_obj = | |
403 g_fake_gdi_object_factory.Get().Validate(object_handle, kFakeFontMagic); | |
404 if (!font_obj) | |
405 return nullptr; | |
406 | |
407 // Construct a new fake font object to handle the old font if there's one. | |
408 scoped_refptr<FakeGdiObject> new_font_obj; | |
409 skia::RefPtr<SkTypeface> old_typeface = dc_obj->GetTypeface(); | |
410 if (old_typeface) { | |
411 new_font_obj = g_fake_gdi_object_factory.Get().Create(kFakeFontMagic); | |
412 new_font_obj->SetTypeface(old_typeface); | |
413 } | |
414 dc_obj->SetTypeface(font_obj->GetTypeface()); | |
415 | |
416 if (new_font_obj) | |
417 return static_cast<HGDIOBJ>(new_font_obj->GetHandle()); | |
418 return nullptr; | |
419 } | |
420 | |
421 void DoSingleGdiPatch(base::win::IATPatchFunction& patch, | |
422 const base::FilePath& path, | |
423 const char* function_name, | |
424 void* new_function) { | |
425 patch.Patch(path.value().c_str(), "gdi32.dll", function_name, new_function); | |
426 } | |
427 | |
428 class GdiFontPatchDataImpl : public content::GdiFontPatchData { | |
429 public: | |
430 GdiFontPatchDataImpl(const base::FilePath& path); | |
431 | |
432 private: | |
433 base::win::IATPatchFunction create_compatible_dc_patch_; | |
434 base::win::IATPatchFunction create_font_indirect_patch_; | |
435 base::win::IATPatchFunction create_delete_dc_patch_; | |
436 base::win::IATPatchFunction create_delete_object_patch_; | |
437 base::win::IATPatchFunction create_enum_font_families_patch_; | |
438 base::win::IATPatchFunction create_get_font_data_patch_; | |
439 base::win::IATPatchFunction create_select_object_patch_; | |
440 }; | |
441 | |
442 GdiFontPatchDataImpl::GdiFontPatchDataImpl(const base::FilePath& path) { | |
443 DoSingleGdiPatch(create_compatible_dc_patch_, path, "CreateCompatibleDC", | |
444 CreateCompatibleDCPatch); | |
445 DoSingleGdiPatch(create_font_indirect_patch_, path, "CreateFontIndirectW", | |
446 CreateFontIndirectWPatch); | |
447 DoSingleGdiPatch(create_delete_dc_patch_, path, "DeleteDC", DeleteDCPatch); | |
448 DoSingleGdiPatch(create_delete_object_patch_, path, "DeleteObject", | |
449 DeleteObjectPatch); | |
450 DoSingleGdiPatch(create_enum_font_families_patch_, path, | |
451 "EnumFontFamiliesExW", EnumFontFamiliesExWPatch); | |
452 DoSingleGdiPatch(create_get_font_data_patch_, path, "GetFontData", | |
453 GetFontDataPatch); | |
454 DoSingleGdiPatch(create_select_object_patch_, path, "SelectObject", | |
455 SelectObjectPatch); | |
456 } | |
457 | |
188 } // namespace | 458 } // namespace |
189 | 459 |
190 void DoPreSandboxWarmupForTypeface(SkTypeface* typeface) { | 460 void DoPreSandboxWarmupForTypeface(SkTypeface* typeface) { |
191 SkPaint paint_warmup; | 461 SkPaint paint_warmup; |
192 paint_warmup.setTypeface(typeface); | 462 paint_warmup.setTypeface(typeface); |
193 wchar_t glyph = L'S'; | 463 wchar_t glyph = L'S'; |
194 paint_warmup.measureText(&glyph, 2); | 464 paint_warmup.measureText(&glyph, 2); |
195 } | 465 } |
196 | 466 |
197 SkFontMgr* GetPreSandboxWarmupFontMgr() { | 467 SkFontMgr* GetPreSandboxWarmupFontMgr() { |
198 if (!g_warmup_fontmgr) { | 468 if (!g_warmup_fontmgr) { |
199 IDWriteFactory* factory; | 469 IDWriteFactory* factory; |
200 CreateDirectWriteFactory(&factory); | 470 CreateDirectWriteFactory(&factory); |
201 | 471 |
202 GetCustomFontCollection(factory); | 472 GetCustomFontCollection(factory); |
203 | 473 |
204 PatchDWriteFactory(factory); | 474 PatchDWriteFactory(factory); |
205 | 475 |
206 blink::WebFontRendering::setDirectWriteFactory(factory); | 476 blink::WebFontRendering::setDirectWriteFactory(factory); |
207 g_warmup_fontmgr = SkFontMgr_New_DirectWrite(factory); | 477 g_warmup_fontmgr = SkFontMgr_New_DirectWrite(factory); |
208 } | 478 } |
209 return g_warmup_fontmgr; | 479 return g_warmup_fontmgr; |
210 } | 480 } |
211 | 481 |
482 GdiFontPatchData* PatchGdiFontEnumeration(const base::FilePath& path) { | |
483 // We assume the fontmgr is already warmed up before calling this. | |
484 DCHECK(g_warmup_fontmgr); | |
485 return new GdiFontPatchDataImpl(path); | |
486 } | |
487 | |
488 size_t GetEmulatedGdiHandleCountForTesting() { | |
489 return g_fake_gdi_object_factory.Get().GetObjectCount(); | |
490 } | |
491 | |
492 void ResetEmulatedGdiHandlesForTesting() { | |
493 g_fake_gdi_object_factory.Get().ResetObjectHandles(); | |
494 } | |
495 | |
496 void SetPreSandboxWarmupFontMgrForTesting(SkFontMgr* fontmgr) { | |
497 g_warmup_fontmgr = fontmgr; | |
498 } | |
499 | |
212 void WarmupDirectWrite() { | 500 void WarmupDirectWrite() { |
213 // The objects used here are intentionally not freed as we want the Skia | 501 // The objects used here are intentionally not freed as we want the Skia |
214 // code to use these objects after warmup. | 502 // code to use these objects after warmup. |
215 SetDefaultSkiaFactory(GetPreSandboxWarmupFontMgr()); | 503 SetDefaultSkiaFactory(GetPreSandboxWarmupFontMgr()); |
216 | 504 |
217 // We need to warm up *some* font for DirectWrite. We also need to pass one | 505 // We need to warm up *some* font for DirectWrite. We also need to pass one |
218 // down for the CC HUD code, so use the same one here. Note that we don't use | 506 // down for the CC HUD code, so use the same one here. Note that we don't use |
219 // a monospace as would be nice in an attempt to avoid a small startup time | 507 // a monospace as would be nice in an attempt to avoid a small startup time |
220 // regression, see http://crbug.com/463613. | 508 // regression, see http://crbug.com/463613. |
221 skia::RefPtr<SkTypeface> hud_typeface = skia::AdoptRef( | 509 skia::RefPtr<SkTypeface> hud_typeface = skia::AdoptRef( |
222 GetPreSandboxWarmupFontMgr()->legacyCreateTypeface("Times New Roman", 0)); | 510 GetPreSandboxWarmupFontMgr()->legacyCreateTypeface("Times New Roman", 0)); |
223 DoPreSandboxWarmupForTypeface(hud_typeface.get()); | 511 DoPreSandboxWarmupForTypeface(hud_typeface.get()); |
224 gfx::SetHudTypeface(hud_typeface); | 512 gfx::SetHudTypeface(hud_typeface); |
225 } | 513 } |
226 | 514 |
227 } // namespace content | 515 } // namespace content |
OLD | NEW |