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

Unified 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, 4 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 side-by-side diff with in-line comments
Download patch
Index: content/common/render_font_warmup_win.cc
diff --git a/content/common/render_font_warmup_win.cc b/content/common/render_font_warmup_win.cc
index c1f9405b85fdcc86bed086c4573f1b3b5bc87204..217a9dbe908d8afd79ca3edf8962e0756e9d12c2 100644
--- a/content/common/render_font_warmup_win.cc
+++ b/content/common/render_font_warmup_win.cc
@@ -5,17 +5,24 @@
#include "content/public/common/render_font_warmup_win.h"
#include <dwrite.h>
+#include <list>
#include "base/debug/alias.h"
+#include "base/files/file_path.h"
#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/lock.h"
#include "base/win/iat_patch_function.h"
#include "base/win/windows_version.h"
#include "content/public/common/dwrite_font_platform_win.h"
+#include "skia/ext/refptr.h"
#include "third_party/WebKit/public/web/win/WebFontRendering.h"
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/ports/SkFontMgr.h"
#include "third_party/skia/include/ports/SkTypeface_win.h"
+
namespace content {
namespace {
@@ -177,6 +184,284 @@ void PatchDWriteFactory(IDWriteFactory* factory) {
base::win::ModifyCode(function_ptr, &stub_function, sizeof(PROC));
}
+// Magic values for the fake GDI objects.
+const uint32_t kFakeDCMagic = 'fkdc';
+const uint32_t kFakeFontMagic = 'fkft';
+
+// Class to fake out a DC or a Font object. Maintains a reference to a
+// SkTypeFace to emulate the simple operation of a DC and Font. We can't
+// be sure that this won't be used in a multi-threaded environment so we
+// need to ensure a lock is taken before updating the static table of
+// issued objects.
+class FakeGdiObject : public base::RefCountedThreadSafe<FakeGdiObject> {
+ public:
+ // Find a corresponding fake GDI object and verify its magic value.
+ // The returned object is either NULL or the new object.
+ static scoped_refptr<FakeGdiObject> Validate(void* obj,
+ uint32_t magic) {
+ if (obj) {
+ base::AutoLock scoped_lock(objects_lock_);
+ uintptr_t handle = reinterpret_cast<uintptr_t>(obj);
+ for (const auto& currobj : objects_) {
+ if ((currobj->magic_ == magic) &&
+ (handle == currobj->handle_)) {
+ return currobj;
+ }
+ }
+ }
+
+ 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.
+ }
+
+ static scoped_refptr<FakeGdiObject> Create(uint32_t magic) {
+ base::AutoLock scoped_lock(objects_lock_);
+ scoped_refptr<FakeGdiObject> object(new FakeGdiObject(magic));
+ objects_.push_back(object);
+ return object;
+ }
+
+ static bool DeleteObject(void* obj, uint32_t magic) {
+ uintptr_t handle = reinterpret_cast<uintptr_t>(obj);
+ base::AutoLock scoped_lock(objects_lock_);
+ 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
+ const auto& fakeobj = *i;
+ if ((fakeobj->magic_ == magic) && (fakeobj->handle_ == handle)) {
+ objects_.erase(i);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void SetTypeface(const skia::RefPtr<SkTypeface>& typeface) {
+ typeface_ = typeface;
+ }
+
+ skia::RefPtr<SkTypeface> GetTypeface() {
+ return typeface_;
+ }
+
+ void* GetHandle() {
+ return reinterpret_cast<void*>(handle_);
+ }
+
+ private:
+ uint32_t magic_;
+ uintptr_t handle_;
+ skia::RefPtr<SkTypeface> typeface_;
+ static uintptr_t curr_handle_;
+ static std::list<scoped_refptr<FakeGdiObject>> objects_;
+ static base::Lock objects_lock_;
+ FakeGdiObject(uint32_t magic) : magic_(magic), handle_(++curr_handle_) {}
+ ~FakeGdiObject() {}
+ friend class base::RefCountedThreadSafe<FakeGdiObject>;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeGdiObject);
+};
+
+uintptr_t FakeGdiObject::curr_handle_ = 0;
+std::list<scoped_refptr<FakeGdiObject>> FakeGdiObject::objects_;
+base::Lock FakeGdiObject::objects_lock_;
+
+skia::RefPtr<SkTypeface> GetTypefaceFromLOGFONT(const LOGFONTW* logfont) {
+ CHECK(g_warmup_fontmgr);
+ int weight = logfont->lfWeight;
+ if (weight == FW_DONTCARE)
+ weight = SkFontStyle::kNormal_Weight;
+
+ SkFontStyle style(weight,
+ logfont->lfWidth,
+ logfont->lfItalic ?
+ SkFontStyle::kItalic_Slant :
+ SkFontStyle::kUpright_Slant);
+
+ std::string family_name = base::WideToUTF8(logfont->lfFaceName);
+ return skia::AdoptRef(g_warmup_fontmgr->matchFamilyStyle(family_name.c_str(),
+ style));
+}
+
+HDC WINAPI CreateCompatibleDCPatch(HDC hdc) {
+ scoped_refptr<FakeGdiObject> ret = FakeGdiObject::Create(kFakeDCMagic);
+ return static_cast<HDC>(ret->GetHandle());
+}
+
+HFONT WINAPI CreateFontIndirectWPatch(const LOGFONTW *lplf) {
+ if (!lplf)
+ return NULL;
+
+ skia::RefPtr<SkTypeface> typeface = GetTypefaceFromLOGFONT(lplf);
+ if (!typeface) {
+ return NULL;
+ }
+
+ scoped_refptr<FakeGdiObject> ret = FakeGdiObject::Create(kFakeFontMagic);
+ ret->SetTypeface(typeface);
+
+ return static_cast<HFONT>(ret->GetHandle());
+}
+
+BOOL WINAPI DeleteDCPatch(HDC hdc) {
+ if (hdc) {
+ return FakeGdiObject::DeleteObject(hdc, kFakeDCMagic);
+ }
+ return FALSE;
+}
+
+BOOL WINAPI DeleteObjectPatch(HGDIOBJ hObject) {
+ if (hObject) {
+ return FakeGdiObject::DeleteObject(hObject, kFakeFontMagic);
+ }
+ return FALSE;
+}
+
+int WINAPI EnumFontFamiliesExWPatch(
+ HDC hdc,
+ LPLOGFONTW lpLogfont,
+ FONTENUMPROCW lpEnumFontFamExProc,
+ LPARAM lParam,
+ DWORD dwFlags) {
+ scoped_refptr<FakeGdiObject> dcobj =
+ FakeGdiObject::Validate(hdc, kFakeDCMagic);
+ if (!dcobj) {
+ LOG(ERROR) << "Invalid DC Object";
+ return 1;
+ }
+ if (!lpLogfont || !lpEnumFontFamExProc) {
+ return 1;
+ }
+
+ skia::RefPtr<SkTypeface> typeface = GetTypefaceFromLOGFONT(lpLogfont);
+ if (!typeface) {
+ return 1;
+ }
+
+ // TODO: Fill in the rest of the text metric structure.
+ NEWTEXTMETRICEXW text_metric = {0};
+ text_metric.ntmTm.ntmFlags = NTM_PS_OPENTYPE;
+
+ return lpEnumFontFamExProc(lpLogfont,
+ reinterpret_cast<TEXTMETRIC*>(&text_metric),
+ TRUETYPE_FONTTYPE,
+ lParam);
+}
+
+DWORD WINAPI GetFontDataPatch(
+ HDC hdc,
+ DWORD dwTable,
+ DWORD dwOffset,
+ LPVOID lpvBuffer,
+ DWORD cbData) {
+ scoped_refptr<FakeGdiObject> dcobj =
+ FakeGdiObject::Validate(hdc, kFakeDCMagic);
+ if (!dcobj) {
+ LOG(ERROR) << "Invalid DC Object";
+ return GDI_ERROR;
+ }
+
+ skia::RefPtr<SkTypeface> typeface = dcobj->GetTypeface();
+ if (!typeface) {
+ return GDI_ERROR;
+ }
+
+ if (cbData > INT32_MAX) {
+ return GDI_ERROR;
+ }
+
+ // Swap endian of table identifier.
+ dwTable = ((dwTable & 0xFF) << 24) |
+ ((dwTable & 0xFF00) << 8) |
+ ((dwTable & 0xFF0000) >> 8) |
+ (dwTable >> 24);
+
+ // getTableData takes care of lpvBuffer being NULL. Swap tag to counter
+ // effect of the underlying implementation. Also if the buffer pointer
+ // is NULL then set length INT_MAX otherwise getTableData returns the minimum
+ // length between table size and passed length. If the caller passes 0
+ // as GetFontData allows it then 0 length is returned which is incorrect.
+ size_t length = typeface->getTableData(dwTable,
+ dwOffset,
+ lpvBuffer ? cbData : INT32_MAX,
+ lpvBuffer);
+ // We can't distinguish between an empty table and an error.
+ if (length == 0)
+ return GDI_ERROR;
+
+ // No truncation, we checked against INT_MAX above.
+ return static_cast<DWORD>(length);
+}
+
+HGDIOBJ WINAPI SelectObjectPatch(HDC hdc, HGDIOBJ hgdiobj) {
+ scoped_refptr<FakeGdiObject> dcobj =
+ FakeGdiObject::Validate(hdc, kFakeDCMagic);
+ if (!dcobj) {
+ LOG(ERROR) << "Invalid DC Object";
+ return NULL;
+ }
+
+ scoped_refptr<FakeGdiObject> fontobj =
+ FakeGdiObject::Validate(hgdiobj, kFakeFontMagic);
+ if (!fontobj) {
+ LOG(ERROR) << "Invalid Font Object";
+ return NULL;
+ }
+
+ // Construct a new fake font object to handle the old font if there's one.
+ scoped_refptr<FakeGdiObject> newfontobj;
+ skia::RefPtr<SkTypeface> oldfont = dcobj->GetTypeface();
+ if (oldfont) {
+ newfontobj = FakeGdiObject::Create(kFakeFontMagic);
+ newfontobj->SetTypeface(oldfont);
+ }
+ dcobj->SetTypeface(fontobj->GetTypeface());
+
+ if (newfontobj)
+ return static_cast<HGDIOBJ>(newfontobj->GetHandle());
+ return NULL;
+}
+
+void DoSingleGdiPatch(base::win::IATPatchFunction& patch,
+ const base::FilePath& path,
+ const char* function_name,
+ void* new_function) {
+ DWORD error = patch.Patch(path.value().c_str(),
+ "gdi32.dll",
+ function_name,
+ new_function);
+ if (error != 0) {
+ LOG(WARNING) << "Failed patching " << function_name << " " << error;
+ }
+}
+
+class GdiFontPatchDataImpl : public content::GdiFontPatchData {
+ public:
+ GdiFontPatchDataImpl(const base::FilePath& path);
+ private:
+ base::win::IATPatchFunction create_compatible_dc_patch_;
+ base::win::IATPatchFunction create_font_indirect_patch_;
+ base::win::IATPatchFunction create_delete_dc_patch_;
+ base::win::IATPatchFunction create_delete_object_patch_;
+ base::win::IATPatchFunction create_enum_font_families_patch_;
+ base::win::IATPatchFunction create_get_font_data_patch_;
+ base::win::IATPatchFunction create_select_object_patch_;
+};
+
+GdiFontPatchDataImpl::GdiFontPatchDataImpl(const base::FilePath& path) {
+ DoSingleGdiPatch(create_compatible_dc_patch_, path,
+ "CreateCompatibleDC", CreateCompatibleDCPatch);
+ DoSingleGdiPatch(create_font_indirect_patch_, path,
+ "CreateFontIndirectW", CreateFontIndirectWPatch);
+ DoSingleGdiPatch(create_delete_dc_patch_, path,
+ "DeleteDC", DeleteDCPatch);
+ DoSingleGdiPatch(create_delete_object_patch_, path,
+ "DeleteObject", DeleteObjectPatch);
+ DoSingleGdiPatch(create_enum_font_families_patch_, path,
+ "EnumFontFamiliesExW", EnumFontFamiliesExWPatch);
+ DoSingleGdiPatch(create_get_font_data_patch_, path,
+ "GetFontData", GetFontDataPatch);
+ DoSingleGdiPatch(create_select_object_patch_, path,
+ "SelectObject", SelectObjectPatch);
+}
+
} // namespace
void DoPreSandboxWarmupForTypeface(SkTypeface* typeface) {
@@ -201,4 +486,14 @@ SkFontMgr* GetPreSandboxWarmupFontMgr() {
return g_warmup_fontmgr;
}
+GdiFontPatchData* PatchGdiFontEnumeration(const base::FilePath& path) {
+ // We assume the fontmgr is already warmed up before calling this.
+ DCHECK(g_warmup_fontmgr);
+ return new GdiFontPatchDataImpl(path);
+}
+
+void SetPreSandboxWarmupFontMgr(SkFontMgr* fontmgr) {
+ g_warmup_fontmgr = fontmgr;
+}
+
} // namespace content
« 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