Chromium Code Reviews| 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 |