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

Side by Side Diff: content/common/render_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: 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/public/common/render_font_warmup_win.h" 5 #include "content/public/common/render_font_warmup_win.h"
6 6
7 #include <dwrite.h> 7 #include <dwrite.h>
8 #include <list>
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/strings/utf_string_conversions.h"
15 #include "base/synchronization/lock.h"
11 #include "base/win/iat_patch_function.h" 16 #include "base/win/iat_patch_function.h"
12 #include "base/win/windows_version.h" 17 #include "base/win/windows_version.h"
13 #include "content/public/common/dwrite_font_platform_win.h" 18 #include "content/public/common/dwrite_font_platform_win.h"
19 #include "skia/ext/refptr.h"
14 #include "third_party/WebKit/public/web/win/WebFontRendering.h" 20 #include "third_party/WebKit/public/web/win/WebFontRendering.h"
15 #include "third_party/skia/include/core/SkPaint.h" 21 #include "third_party/skia/include/core/SkPaint.h"
16 #include "third_party/skia/include/ports/SkFontMgr.h" 22 #include "third_party/skia/include/ports/SkFontMgr.h"
17 #include "third_party/skia/include/ports/SkTypeface_win.h" 23 #include "third_party/skia/include/ports/SkTypeface_win.h"
18 24
25
19 namespace content { 26 namespace content {
20 27
21 namespace { 28 namespace {
22 29
23 SkFontMgr* g_warmup_fontmgr = NULL; 30 SkFontMgr* g_warmup_fontmgr = NULL;
24 31
25 base::win::IATPatchFunction g_iat_patch_open_sc_manager; 32 base::win::IATPatchFunction g_iat_patch_open_sc_manager;
26 base::win::IATPatchFunction g_iat_patch_close_service_handle; 33 base::win::IATPatchFunction g_iat_patch_close_service_handle;
27 base::win::IATPatchFunction g_iat_patch_open_service; 34 base::win::IATPatchFunction g_iat_patch_open_service;
28 base::win::IATPatchFunction g_iat_patch_start_service; 35 base::win::IATPatchFunction g_iat_patch_start_service;
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
170 177
171 void PatchDWriteFactory(IDWriteFactory* factory) { 178 void PatchDWriteFactory(IDWriteFactory* factory) {
172 const unsigned int kGetSystemFontCollectionVTableIndex = 3; 179 const unsigned int kGetSystemFontCollectionVTableIndex = 3;
173 180
174 PROC* vtable = *reinterpret_cast<PROC**>(factory); 181 PROC* vtable = *reinterpret_cast<PROC**>(factory);
175 PROC* function_ptr = &vtable[kGetSystemFontCollectionVTableIndex]; 182 PROC* function_ptr = &vtable[kGetSystemFontCollectionVTableIndex];
176 void* stub_function = &StubFontCollection; 183 void* stub_function = &StubFontCollection;
177 base::win::ModifyCode(function_ptr, &stub_function, sizeof(PROC)); 184 base::win::ModifyCode(function_ptr, &stub_function, sizeof(PROC));
178 } 185 }
179 186
187 // Magic values for the fake GDI objects.
188 const uint32_t kFakeDCMagic = 'fkdc';
189 const uint32_t kFakeFontMagic = 'fkft';
190
191 // Class to fake out a DC or a Font object. Maintains a reference to a
192 // SkTypeFace to emulate the simple operation of a DC and Font. We can't
193 // be sure that this won't be used in a multi-threaded environment so we
194 // need to ensure a lock is taken before updating the static table of
195 // issued objects.
196 class FakeGdiObject : public base::RefCountedThreadSafe<FakeGdiObject> {
197 public:
198 // Find a corresponding fake GDI object and verify its magic value.
199 // The returned object is either NULL or the new object.
200 static scoped_refptr<FakeGdiObject> Validate(void* obj,
201 uint32_t magic) {
202 if (obj) {
203 base::AutoLock scoped_lock(objects_lock_);
204 uintptr_t handle = reinterpret_cast<uintptr_t>(obj);
205 for (const auto& currobj : objects_) {
206 if ((currobj->magic_ == magic) &&
207 (handle == currobj->handle_)) {
208 return currobj;
209 }
210 }
211 }
212
213 return NULL;
palmer 2015/09/11 22:34:15 nullptr? I don't know if it's now-standard in Wind
forshaw 2015/09/15 10:27:57 Will change.
214 }
215
216 static scoped_refptr<FakeGdiObject> Create(uint32_t magic) {
217 base::AutoLock scoped_lock(objects_lock_);
218 scoped_refptr<FakeGdiObject> object(new FakeGdiObject(magic));
219 objects_.push_back(object);
220 return object;
221 }
222
223 static bool DeleteObject(void* obj, uint32_t magic) {
224 uintptr_t handle = reinterpret_cast<uintptr_t>(obj);
225 base::AutoLock scoped_lock(objects_lock_);
226 for (auto i = objects_.begin(); i != objects_.end(); ++i) {
palmer 2015/09/11 22:34:16 Does for (const auto& object : objects_) { ...
forshaw 2015/09/15 10:27:57 Unless I'm missing something I need the iterator t
227 const auto& fakeobj = *i;
228 if ((fakeobj->magic_ == magic) && (fakeobj->handle_ == handle)) {
229 objects_.erase(i);
230 return true;
231 }
232 }
233 return false;
234 }
235
236 void SetTypeface(const skia::RefPtr<SkTypeface>& typeface) {
237 typeface_ = typeface;
238 }
239
240 skia::RefPtr<SkTypeface> GetTypeface() {
241 return typeface_;
242 }
243
244 void* GetHandle() {
245 return reinterpret_cast<void*>(handle_);
246 }
247
248 private:
249 uint32_t magic_;
250 uintptr_t handle_;
251 skia::RefPtr<SkTypeface> typeface_;
252 static uintptr_t curr_handle_;
253 static std::list<scoped_refptr<FakeGdiObject>> objects_;
254 static base::Lock objects_lock_;
255 FakeGdiObject(uint32_t magic) : magic_(magic), handle_(++curr_handle_) {}
256 ~FakeGdiObject() {}
257 friend class base::RefCountedThreadSafe<FakeGdiObject>;
258
259 DISALLOW_COPY_AND_ASSIGN(FakeGdiObject);
260 };
261
262 uintptr_t FakeGdiObject::curr_handle_ = 0;
263 std::list<scoped_refptr<FakeGdiObject>> FakeGdiObject::objects_;
264 base::Lock FakeGdiObject::objects_lock_;
265
266 skia::RefPtr<SkTypeface> GetTypefaceFromLOGFONT(const LOGFONTW* logfont) {
267 CHECK(g_warmup_fontmgr);
268 int weight = logfont->lfWeight;
269 if (weight == FW_DONTCARE)
270 weight = SkFontStyle::kNormal_Weight;
271
272 SkFontStyle style(weight,
273 logfont->lfWidth,
274 logfont->lfItalic ?
275 SkFontStyle::kItalic_Slant :
276 SkFontStyle::kUpright_Slant);
277
278 std::string family_name = base::WideToUTF8(logfont->lfFaceName);
279 return skia::AdoptRef(g_warmup_fontmgr->matchFamilyStyle(family_name.c_str(),
280 style));
281 }
282
283 HDC WINAPI CreateCompatibleDCPatch(HDC hdc) {
284 scoped_refptr<FakeGdiObject> ret = FakeGdiObject::Create(kFakeDCMagic);
285 return static_cast<HDC>(ret->GetHandle());
286 }
287
288 HFONT WINAPI CreateFontIndirectWPatch(const LOGFONTW *lplf) {
289 if (!lplf)
290 return NULL;
291
292 skia::RefPtr<SkTypeface> typeface = GetTypefaceFromLOGFONT(lplf);
293 if (!typeface) {
294 return NULL;
295 }
296
297 scoped_refptr<FakeGdiObject> ret = FakeGdiObject::Create(kFakeFontMagic);
298 ret->SetTypeface(typeface);
299
300 return static_cast<HFONT>(ret->GetHandle());
301 }
302
303 BOOL WINAPI DeleteDCPatch(HDC hdc) {
304 if (hdc) {
305 return FakeGdiObject::DeleteObject(hdc, kFakeDCMagic);
306 }
307 return FALSE;
308 }
309
310 BOOL WINAPI DeleteObjectPatch(HGDIOBJ hObject) {
311 if (hObject) {
312 return FakeGdiObject::DeleteObject(hObject, kFakeFontMagic);
313 }
314 return FALSE;
315 }
316
317 int WINAPI EnumFontFamiliesExWPatch(
318 HDC hdc,
319 LPLOGFONTW lpLogfont,
320 FONTENUMPROCW lpEnumFontFamExProc,
321 LPARAM lParam,
322 DWORD dwFlags) {
323 scoped_refptr<FakeGdiObject> dcobj =
324 FakeGdiObject::Validate(hdc, kFakeDCMagic);
325 if (!dcobj) {
326 LOG(ERROR) << "Invalid DC Object";
327 return 1;
328 }
329 if (!lpLogfont || !lpEnumFontFamExProc) {
330 return 1;
331 }
332
333 skia::RefPtr<SkTypeface> typeface = GetTypefaceFromLOGFONT(lpLogfont);
334 if (!typeface) {
335 return 1;
336 }
337
338 // TODO: Fill in the rest of the text metric structure.
339 NEWTEXTMETRICEXW text_metric = {0};
340 text_metric.ntmTm.ntmFlags = NTM_PS_OPENTYPE;
341
342 return lpEnumFontFamExProc(lpLogfont,
343 reinterpret_cast<TEXTMETRIC*>(&text_metric),
344 TRUETYPE_FONTTYPE,
345 lParam);
346 }
347
348 DWORD WINAPI GetFontDataPatch(
349 HDC hdc,
350 DWORD dwTable,
351 DWORD dwOffset,
352 LPVOID lpvBuffer,
353 DWORD cbData) {
354 scoped_refptr<FakeGdiObject> dcobj =
355 FakeGdiObject::Validate(hdc, kFakeDCMagic);
356 if (!dcobj) {
357 LOG(ERROR) << "Invalid DC Object";
358 return GDI_ERROR;
359 }
360
361 skia::RefPtr<SkTypeface> typeface = dcobj->GetTypeface();
362 if (!typeface) {
363 return GDI_ERROR;
364 }
365
366 if (cbData > INT32_MAX) {
367 return GDI_ERROR;
368 }
369
370 // Swap endian of table identifier.
371 dwTable = ((dwTable & 0xFF) << 24) |
372 ((dwTable & 0xFF00) << 8) |
373 ((dwTable & 0xFF0000) >> 8) |
374 (dwTable >> 24);
375
376 // getTableData takes care of lpvBuffer being NULL. Swap tag to counter
377 // effect of the underlying implementation. Also if the buffer pointer
378 // is NULL then set length INT_MAX otherwise getTableData returns the minimum
379 // length between table size and passed length. If the caller passes 0
380 // as GetFontData allows it then 0 length is returned which is incorrect.
381 size_t length = typeface->getTableData(dwTable,
382 dwOffset,
383 lpvBuffer ? cbData : INT32_MAX,
384 lpvBuffer);
385 // We can't distinguish between an empty table and an error.
386 if (length == 0)
387 return GDI_ERROR;
388
389 // No truncation, we checked against INT_MAX above.
390 return static_cast<DWORD>(length);
391 }
392
393 HGDIOBJ WINAPI SelectObjectPatch(HDC hdc, HGDIOBJ hgdiobj) {
394 scoped_refptr<FakeGdiObject> dcobj =
395 FakeGdiObject::Validate(hdc, kFakeDCMagic);
396 if (!dcobj) {
397 LOG(ERROR) << "Invalid DC Object";
398 return NULL;
399 }
400
401 scoped_refptr<FakeGdiObject> fontobj =
402 FakeGdiObject::Validate(hgdiobj, kFakeFontMagic);
403 if (!fontobj) {
404 LOG(ERROR) << "Invalid Font Object";
405 return NULL;
406 }
407
408 // Construct a new fake font object to handle the old font if there's one.
409 scoped_refptr<FakeGdiObject> newfontobj;
410 skia::RefPtr<SkTypeface> oldfont = dcobj->GetTypeface();
411 if (oldfont) {
412 newfontobj = FakeGdiObject::Create(kFakeFontMagic);
413 newfontobj->SetTypeface(oldfont);
414 }
415 dcobj->SetTypeface(fontobj->GetTypeface());
416
417 if (newfontobj)
418 return static_cast<HGDIOBJ>(newfontobj->GetHandle());
419 return NULL;
420 }
421
422 void DoSingleGdiPatch(base::win::IATPatchFunction& patch,
423 const base::FilePath& path,
424 const char* function_name,
425 void* new_function) {
426 DWORD error = patch.Patch(path.value().c_str(),
427 "gdi32.dll",
428 function_name,
429 new_function);
430 if (error != 0) {
431 LOG(WARNING) << "Failed patching " << function_name << " " << error;
432 }
433 }
434
435 class GdiFontPatchDataImpl : public content::GdiFontPatchData {
436 public:
437 GdiFontPatchDataImpl(const base::FilePath& path);
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,
450 "CreateCompatibleDC", CreateCompatibleDCPatch);
451 DoSingleGdiPatch(create_font_indirect_patch_, path,
452 "CreateFontIndirectW", CreateFontIndirectWPatch);
453 DoSingleGdiPatch(create_delete_dc_patch_, path,
454 "DeleteDC", DeleteDCPatch);
455 DoSingleGdiPatch(create_delete_object_patch_, path,
456 "DeleteObject", DeleteObjectPatch);
457 DoSingleGdiPatch(create_enum_font_families_patch_, path,
458 "EnumFontFamiliesExW", EnumFontFamiliesExWPatch);
459 DoSingleGdiPatch(create_get_font_data_patch_, path,
460 "GetFontData", GetFontDataPatch);
461 DoSingleGdiPatch(create_select_object_patch_, path,
462 "SelectObject", SelectObjectPatch);
463 }
464
180 } // namespace 465 } // namespace
181 466
182 void DoPreSandboxWarmupForTypeface(SkTypeface* typeface) { 467 void DoPreSandboxWarmupForTypeface(SkTypeface* typeface) {
183 SkPaint paint_warmup; 468 SkPaint paint_warmup;
184 paint_warmup.setTypeface(typeface); 469 paint_warmup.setTypeface(typeface);
185 wchar_t glyph = L'S'; 470 wchar_t glyph = L'S';
186 paint_warmup.measureText(&glyph, 2); 471 paint_warmup.measureText(&glyph, 2);
187 } 472 }
188 473
189 SkFontMgr* GetPreSandboxWarmupFontMgr() { 474 SkFontMgr* GetPreSandboxWarmupFontMgr() {
190 if (!g_warmup_fontmgr) { 475 if (!g_warmup_fontmgr) {
191 IDWriteFactory* factory; 476 IDWriteFactory* factory;
192 CreateDirectWriteFactory(&factory); 477 CreateDirectWriteFactory(&factory);
193 478
194 GetCustomFontCollection(factory); 479 GetCustomFontCollection(factory);
195 480
196 PatchDWriteFactory(factory); 481 PatchDWriteFactory(factory);
197 482
198 blink::WebFontRendering::setDirectWriteFactory(factory); 483 blink::WebFontRendering::setDirectWriteFactory(factory);
199 g_warmup_fontmgr = SkFontMgr_New_DirectWrite(factory); 484 g_warmup_fontmgr = SkFontMgr_New_DirectWrite(factory);
200 } 485 }
201 return g_warmup_fontmgr; 486 return g_warmup_fontmgr;
202 } 487 }
203 488
489 GdiFontPatchData* PatchGdiFontEnumeration(const base::FilePath& path) {
490 // We assume the fontmgr is already warmed up before calling this.
491 DCHECK(g_warmup_fontmgr);
492 return new GdiFontPatchDataImpl(path);
493 }
494
495 void SetPreSandboxWarmupFontMgr(SkFontMgr* fontmgr) {
496 g_warmup_fontmgr = fontmgr;
497 }
498
204 } // namespace content 499 } // namespace content
OLDNEW
« no previous file with comments | « no previous file | content/common/render_font_warmup_win_unittest.cc » ('j') | content/common/render_font_warmup_win_unittest.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698