Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(185)

Side by Side Diff: content/common/font_warmup_win.cc

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

Powered by Google App Engine
This is Rietveld 408576698