Bug 1156742 Part 19: Implement GetFontFileData for ScaledFontWin. r=bas
authorBob Owen <bobowencode@gmail.com>
Tue, 05 Jan 2016 10:08:58 +0000
changeset 300951 c14e6cfb20dd844b82b1e5e7bb70a9cfec193f77
parent 300950 f8c51f0d7cd47fe6e7e65dd88d54f3f6fce79d91
child 300952 fa6b129da39a29b1ea3dd5e5eac5b73cb83f308f
push idunknown
push userunknown
push dateunknown
reviewersbas
bugs1156742
milestone46.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1156742 Part 19: Implement GetFontFileData for ScaledFontWin. r=bas
gfx/2d/AutoHelpersWin.h
gfx/2d/RecordedEvent.cpp
gfx/2d/RecordedEvent.h
gfx/2d/ScaledFontWin.cpp
gfx/2d/ScaledFontWin.h
new file mode 100644
--- /dev/null
+++ b/gfx/2d/AutoHelpersWin.h
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.0. If a copy of the MPL was not distributed with this
+* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_gfx_AutoHelpersWin_h
+#define mozilla_gfx_AutoHelpersWin_h
+
+#include <windows.h>
+
+namespace mozilla {
+namespace gfx {
+
+// Get the global device context, and auto-release it on destruction.
+class AutoDC
+{
+public:
+  AutoDC() {
+    mDC = ::GetDC(nullptr);
+  }
+
+  ~AutoDC() {
+    ::ReleaseDC(nullptr, mDC);
+  }
+
+  HDC GetDC() {
+    return mDC;
+  }
+
+private:
+  HDC mDC;
+};
+
+// Select a font into the given DC, and auto-restore.
+class AutoSelectFont
+{
+public:
+  AutoSelectFont(HDC aDC, LOGFONTW *aLogFont)
+    : mOwnsFont(false)
+  {
+    mFont = ::CreateFontIndirectW(aLogFont);
+    if (mFont) {
+      mOwnsFont = true;
+      mDC = aDC;
+      mOldFont = (HFONT)::SelectObject(aDC, mFont);
+    } else {
+      mOldFont = nullptr;
+    }
+  }
+
+  AutoSelectFont(HDC aDC, HFONT aFont)
+    : mOwnsFont(false)
+  {
+    mDC = aDC;
+    mFont = aFont;
+    mOldFont = (HFONT)::SelectObject(aDC, aFont);
+  }
+
+  ~AutoSelectFont() {
+    if (mOldFont) {
+      ::SelectObject(mDC, mOldFont);
+      if (mOwnsFont) {
+        ::DeleteObject(mFont);
+      }
+    }
+  }
+
+  bool IsValid() const {
+    return mFont != nullptr;
+  }
+
+  HFONT GetFont() const {
+    return mFont;
+  }
+
+private:
+  HDC mDC;
+  HFONT mFont;
+  HFONT mOldFont;
+  bool mOwnsFont;
+};
+
+} // gfx
+} // mozilla
+
+#endif // mozilla_gfx_AutoHelpersWin_h
--- a/gfx/2d/RecordedEvent.cpp
+++ b/gfx/2d/RecordedEvent.cpp
@@ -1399,16 +1399,22 @@ RecordedScaledFontCreation::PlayEvent(Tr
     Factory::CreateScaledFontForTrueTypeData(mData, mSize, mIndex, mGlyphSize,
                                              aTranslator->GetDesiredFontType());
   aTranslator->AddScaledFont(mRefPtr, scaledFont);
 }
 
 void
 RecordedScaledFontCreation::RecordToStream(std::ostream &aStream) const
 {
+  if (!mGetFontFileDataSucceeded) {
+    gfxWarning()
+      << "Unable to record ScaledFont creation as no data was retrieved.";
+    return;
+  }
+
   WriteElement(aStream, mRefPtr);
   WriteElement(aStream, mIndex);
   WriteElement(aStream, mGlyphSize);
   WriteElement(aStream, mSize);
   aStream.write((const char*)mData, mSize);
 }
 
 void
--- a/gfx/2d/RecordedEvent.h
+++ b/gfx/2d/RecordedEvent.h
@@ -942,17 +942,17 @@ public:
   static void FontDataProc(const uint8_t *aData, uint32_t aSize, uint32_t aIndex, Float aGlyphSize, void* aBaton)
   {
     static_cast<RecordedScaledFontCreation*>(aBaton)->SetFontData(aData, aSize, aIndex, aGlyphSize);
   }
 
   RecordedScaledFontCreation(ReferencePtr aRefPtr, ScaledFont *aScaledFont)
     : RecordedEvent(SCALEDFONTCREATION), mRefPtr(aRefPtr), mData(nullptr)
   {
-    aScaledFont->GetFontFileData(&FontDataProc, this);
+    mGetFontFileDataSucceeded = aScaledFont->GetFontFileData(&FontDataProc, this);
   }
 
   ~RecordedScaledFontCreation();
 
   virtual void PlayEvent(Translator *aTranslator) const;
 
   virtual void RecordToStream(std::ostream &aStream) const;
   virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
@@ -965,16 +965,17 @@ public:
 private:
   friend class RecordedEvent;
 
   ReferencePtr mRefPtr;
   uint8_t *mData;
   uint32_t mSize;
   Float mGlyphSize;
   uint32_t mIndex;
+  bool mGetFontFileDataSucceeded = false;
 
   MOZ_IMPLICIT RecordedScaledFontCreation(std::istream &aStream);
 };
 
 class RecordedScaledFontDestruction : public RecordedEvent {
 public:
   MOZ_IMPLICIT RecordedScaledFontDestruction(ReferencePtr aRefPtr)
     : RecordedEvent(SCALEDFONTDESTRUCTION), mRefPtr(aRefPtr)
--- a/gfx/2d/ScaledFontWin.cpp
+++ b/gfx/2d/ScaledFontWin.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ScaledFontWin.h"
 #include "ScaledFontBase.h"
 
+#include "AutoHelpersWin.h"
 #include "Logging.h"
 #include "SFNTData.h"
 
 #ifdef USE_SKIA
 #include "skia/include/ports/SkTypeface_win.h"
 #endif
 
 #ifdef USE_CAIRO_SCALED_FONT
@@ -72,16 +73,65 @@ ScaledFontWin::ScaledFontWin(uint8_t* aF
   HANDLE fontHandle = ::AddFontMemResourceEx(aFontData, aFontDataLength, 0,
                                              &numberOfFontsAdded);
   if (fontHandle) {
     mMemoryFontRemover.reset(new MemoryFontRemover(fontHandle));
   }
 
 }
 
+bool
+ScaledFontWin::GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton)
+{
+  AutoDC dc;
+  AutoSelectFont font(dc.GetDC(), &mLogFont);
+
+  // Check for a font collection first.
+  uint32_t table = 0x66637474; // 'ttcf'
+  uint32_t tableSize = ::GetFontData(dc.GetDC(), table, 0, nullptr, 0);
+  if (tableSize == GDI_ERROR) {
+    // Try as if just a single font.
+    table = 0;
+    tableSize = ::GetFontData(dc.GetDC(), table, 0, nullptr, 0);
+    if (tableSize == GDI_ERROR) {
+      return false;
+    }
+  }
+
+  UniquePtr<uint8_t[]> fontData(new uint8_t[tableSize]);
+
+  uint32_t sizeGot =
+    ::GetFontData(dc.GetDC(), table, 0, fontData.get(), tableSize);
+  if (sizeGot != tableSize) {
+    return false;
+  }
+
+  // If it's a font collection then attempt to get the index.
+  uint32_t index = 0;
+  if (table != 0) {
+    UniquePtr<SFNTData> sfntData = SFNTData::Create(fontData.get(),
+                                                    tableSize);
+    if (!sfntData) {
+      gfxWarning() << "Failed to create SFNTData for GetFontFileData.";
+      return false;
+    }
+
+    // We cast here because for VS2015 char16_t != wchar_t, even though they are
+    // both 16 bit.
+    if (!sfntData->GetIndexForU16Name(
+          reinterpret_cast<char16_t*>(mLogFont.lfFaceName), &index)) {
+      gfxWarning() << "Failed to get index for face name.";
+      return false;
+    }
+  }
+
+  aDataCallback(fontData.get(), tableSize, index, mSize, aBaton);
+  return true;
+}
+
 #ifdef USE_SKIA
 SkTypeface* ScaledFontWin::GetSkTypeface()
 {
   if (!mTypeface) {
     mTypeface = SkCreateTypefaceFromLOGFONT(mLogFont);
   }
   return mTypeface;
 }
--- a/gfx/2d/ScaledFontWin.h
+++ b/gfx/2d/ScaledFontWin.h
@@ -19,16 +19,19 @@ class ScaledFontWin : public ScaledFontB
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontWin)
   ScaledFontWin(LOGFONT* aFont, Float aSize);
 
   ScaledFontWin(uint8_t* aFontData, uint32_t aFontDataLength, uint32_t aIndex,
                 Float aGlyphSize);
 
   virtual FontType GetType() const { return FontType::GDI; }
+
+  bool GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton) override;
+
 #ifdef USE_SKIA
   virtual SkTypeface* GetSkTypeface();
 #endif
 
 protected:
 #ifdef USE_CAIRO_SCALED_FONT
   cairo_font_face_t* GetCairoFontFace() override;
 #endif