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/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 Loading... | |
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 |
OLD | NEW |