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

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: Fixed from review. Created 5 years, 2 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
« no previous file with comments | « content/common/font_warmup_win.h ('k') | content/common/font_warmup_win_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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"
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
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
OLDNEW
« no previous file with comments | « content/common/font_warmup_win.h ('k') | content/common/font_warmup_win_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698