Bug 1156742 Part 18: Fix the way we hold custom font data so that they can be recorded with Moz2D. r=bas
authorBob Owen <bobowencode@gmail.com>
Tue, 05 Jan 2016 10:08:57 +0000
changeset 313628 f8c51f0d7cd47fe6e7e65dd88d54f3f6fce79d91
parent 313627 318888301328d03b717b26036c248bf69420aef2
child 313629 c14e6cfb20dd844b82b1e5e7bb70a9cfec193f77
push id5703
push userraliiev@mozilla.com
push dateMon, 07 Mar 2016 14:18:41 +0000
treeherdermozilla-beta@31e373ad5b5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
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 18: Fix the way we hold custom font data so that they can be recorded with Moz2D. r=bas
gfx/thebes/gfxDWriteCommon.cpp
gfx/thebes/gfxDWriteCommon.h
gfx/thebes/gfxDWriteFontList.cpp
gfx/thebes/gfxDWriteFontList.h
--- a/gfx/thebes/gfxDWriteCommon.cpp
+++ b/gfx/thebes/gfxDWriteCommon.cpp
@@ -1,71 +1,177 @@
 /* -*- 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/. */
 
 #include "gfxDWriteCommon.h"
 
+#include <unordered_map>
+
+#include "mozilla/Atomics.h"
+
+static mozilla::Atomic<uint64_t> sNextFontFileKey;
+static std::unordered_map<uint64_t, IDWriteFontFileStream*> sFontFileStreams;
+
 IDWriteFontFileLoader* gfxDWriteFontFileLoader::mInstance = nullptr;
 
+class gfxDWriteFontFileStream final : public IDWriteFontFileStream
+{
+public:
+  /**
+  * Used by the FontFileLoader to create a new font stream,
+  * this font stream is created from data in memory. The memory
+  * passed may be released after object creation, it will be
+  * copied internally.
+  *
+  * @param aData Font data
+  */
+  gfxDWriteFontFileStream(FallibleTArray<uint8_t> *aData,
+                          uint64_t aFontFileKey);
+  ~gfxDWriteFontFileStream();
+
+  // IUnknown interface
+  IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject)
+  {
+    if (iid == __uuidof(IDWriteFontFileStream)) {
+      *ppObject = static_cast<IDWriteFontFileStream*>(this);
+      return S_OK;
+    }
+    else if (iid == __uuidof(IUnknown)) {
+      *ppObject = static_cast<IUnknown*>(this);
+      return S_OK;
+    }
+    else {
+      return E_NOINTERFACE;
+    }
+  }
+
+  IFACEMETHOD_(ULONG, AddRef)()
+  {
+    NS_PRECONDITION(int32_t(mRefCnt) >= 0, "illegal refcnt");
+    ++mRefCnt;
+    return mRefCnt;
+  }
+
+  IFACEMETHOD_(ULONG, Release)()
+  {
+    NS_PRECONDITION(0 != mRefCnt, "dup release");
+    --mRefCnt;
+    if (mRefCnt == 0) {
+      delete this;
+      return 0;
+    }
+    return mRefCnt;
+  }
+
+  // IDWriteFontFileStream methods
+  virtual HRESULT STDMETHODCALLTYPE ReadFileFragment(void const** fragmentStart,
+                                                     UINT64 fileOffset,
+                                                     UINT64 fragmentSize,
+                                                     OUT void** fragmentContext);
+
+  virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* fragmentContext);
+
+  virtual HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64* fileSize);
+
+  virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64* lastWriteTime);
+
+private:
+  FallibleTArray<uint8_t> mData;
+  nsAutoRefCnt mRefCnt;
+  uint64_t mFontFileKey;
+};
+
+gfxDWriteFontFileStream::gfxDWriteFontFileStream(FallibleTArray<uint8_t> *aData,
+                                                 uint64_t aFontFileKey)
+  : mFontFileKey(aFontFileKey)
+{
+  mData.SwapElements(*aData);
+}
+
+gfxDWriteFontFileStream::~gfxDWriteFontFileStream()
+{
+  sFontFileStreams.erase(mFontFileKey);
+}
+
+HRESULT STDMETHODCALLTYPE
+gfxDWriteFontFileStream::GetFileSize(UINT64 *fileSize)
+{
+  *fileSize = mData.Length();
+  return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE
+gfxDWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE
+gfxDWriteFontFileStream::ReadFileFragment(const void **fragmentStart,
+                                          UINT64 fileOffset,
+                                          UINT64 fragmentSize,
+                                          void **fragmentContext)
+{
+  // We are required to do bounds checking.
+  if (fileOffset + fragmentSize > (UINT64)mData.Length()) {
+    return E_FAIL;
+  }
+  // We should be alive for the duration of this.
+  *fragmentStart = &mData[fileOffset];
+  *fragmentContext = nullptr;
+  return S_OK;
+}
+
+void STDMETHODCALLTYPE
+gfxDWriteFontFileStream::ReleaseFileFragment(void *fragmentContext)
+{
+}
+
 HRESULT STDMETHODCALLTYPE
 gfxDWriteFontFileLoader::CreateStreamFromKey(const void *fontFileReferenceKey, 
                                              UINT32 fontFileReferenceKeySize, 
                                              IDWriteFontFileStream **fontFileStream)
 {
     if (!fontFileReferenceKey || !fontFileStream) {
         return E_POINTER;
     }
 
-    *fontFileStream = 
-        new gfxDWriteFontFileStream(
-        static_cast<const ffReferenceKey*>(fontFileReferenceKey)->mArray);
-
-    if (!*fontFileStream) {
-        return E_OUTOFMEMORY;
+    uint64_t fontFileKey = *static_cast<const uint64_t*>(fontFileReferenceKey);
+    auto found = sFontFileStreams.find(fontFileKey);
+    if (found == sFontFileStreams.end()) {
+      *fontFileStream = nullptr;
+      return E_FAIL;
     }
-    (*fontFileStream)->AddRef();
-    return S_OK;
-}
 
-gfxDWriteFontFileStream::gfxDWriteFontFileStream(FallibleTArray<uint8_t> *aData)
-{
-    mData.SwapElements(*aData);
-}
-
-gfxDWriteFontFileStream::~gfxDWriteFontFileStream()
-{
-}
-
-HRESULT STDMETHODCALLTYPE
-gfxDWriteFontFileStream::GetFileSize(UINT64 *fileSize)
-{
-    *fileSize = mData.Length();
+    found->second->AddRef();
+    *fontFileStream = found->second;
     return S_OK;
 }
 
-HRESULT STDMETHODCALLTYPE
-gfxDWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime)
-{
-    return E_NOTIMPL;
-}
-
-HRESULT STDMETHODCALLTYPE
-gfxDWriteFontFileStream::ReadFileFragment(const void **fragmentStart,
-                                          UINT64 fileOffset,
-                                          UINT64 fragmentSize,
-                                          void **fragmentContext)
+/* static */
+HRESULT
+gfxDWriteFontFileLoader::CreateCustomFontFile(FallibleTArray<uint8_t>& aFontData,
+                                              IDWriteFontFile** aFontFile,
+                                              IDWriteFontFileStream** aFontFileStream)
 {
-    // We are required to do bounds checking.
-    if (fileOffset + fragmentSize > (UINT64)mData.Length()) {
-        return E_FAIL;
-    }
-    // We should be alive for the duration of this.
-    *fragmentStart = &mData[fileOffset];
-    *fragmentContext = nullptr;
-    return S_OK;
+  MOZ_ASSERT(aFontFile);
+  MOZ_ASSERT(aFontFileStream);
+
+  IDWriteFactory *factory = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory();
+
+  uint64_t fontFileKey = sNextFontFileKey++;
+  RefPtr<IDWriteFontFileStream> ffsRef = new gfxDWriteFontFileStream(&aFontData, fontFileKey);
+  sFontFileStreams[fontFileKey] = ffsRef;
+
+  RefPtr<IDWriteFontFile> fontFile;
+  HRESULT hr = factory->CreateCustomFontFileReference(&fontFileKey, sizeof(fontFileKey), Instance(), getter_AddRefs(fontFile));
+  if (FAILED(hr)) {
+    NS_WARNING("Failed to load font file from data!");
+    return hr;
+  }
+
+  fontFile.forget(aFontFile);
+  ffsRef.forget(aFontFileStream);
+
+  return S_OK;
 }
-
-void STDMETHODCALLTYPE
-gfxDWriteFontFileStream::ReleaseFileFragment(void *fragmentContext)
-{
-}
--- a/gfx/thebes/gfxDWriteCommon.h
+++ b/gfx/thebes/gfxDWriteCommon.h
@@ -108,99 +108,47 @@ public:
 
     IFACEMETHOD_(ULONG, Release)()
     {
         return 1;
     }
 
     // IDWriteFontFileLoader methods
     /**
-     * Important! Note the key here -has- to be a pointer to an
-     * FallibleTArray<uint8_t>.
+     * Important! Note the key here -has- to be a pointer to a uint64_t.
      */
     virtual HRESULT STDMETHODCALLTYPE 
         CreateStreamFromKey(void const* fontFileReferenceKey,
                             UINT32 fontFileReferenceKeySize,
                             OUT IDWriteFontFileStream** fontFileStream);
 
     /**
      * Gets the singleton loader instance. Note that when using this font
-     * loader, the key must be a pointer to an FallibleTArray<uint8_t>. This
-     * array will be empty when the function returns.
+     * loader, the key must be a pointer to a unint64_t.
      */
     static IDWriteFontFileLoader* Instance()
     {
         if (!mInstance) {
             mInstance = new gfxDWriteFontFileLoader();
             gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
                 RegisterFontFileLoader(mInstance);
         }
         return mInstance;
     }
 
+    /**
+     * Creates a IDWriteFontFile and IDWriteFontFileStream from aFontData.
+     * aFontData will be empty on return as it swaps out the data.
+     *
+     * @param aFontData the font data for the custom font file
+     * @param aFontFile out param for the created font file
+     * @param aFontFileStream out param for the corresponding stream
+     * @return HRESULT of internal calls
+     */
+    static HRESULT CreateCustomFontFile(FallibleTArray<uint8_t>& aFontData,
+                                        IDWriteFontFile** aFontFile,
+                                        IDWriteFontFileStream** aFontFileStream);
+
 private:
     static IDWriteFontFileLoader* mInstance;
 }; 
 
-class gfxDWriteFontFileStream final : public IDWriteFontFileStream
-{
-public:
-    /**
-     * Used by the FontFileLoader to create a new font stream,
-     * this font stream is created from data in memory. The memory
-     * passed may be released after object creation, it will be
-     * copied internally.
-     *
-     * @param aData Font data
-     */
-    gfxDWriteFontFileStream(FallibleTArray<uint8_t> *aData);
-    ~gfxDWriteFontFileStream();
-
-    // IUnknown interface
-    IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject)
-    {
-        if (iid == __uuidof(IDWriteFontFileStream)) {
-            *ppObject = static_cast<IDWriteFontFileStream*>(this);
-            return S_OK;
-        } else if (iid == __uuidof(IUnknown)) {
-            *ppObject = static_cast<IUnknown*>(this);
-            return S_OK;
-        } else {
-            return E_NOINTERFACE;
-        }
-    }
-
-    IFACEMETHOD_(ULONG, AddRef)()
-    {
-        NS_PRECONDITION(int32_t(mRefCnt) >= 0, "illegal refcnt");
-        ++mRefCnt;
-        return mRefCnt;
-    }
-
-    IFACEMETHOD_(ULONG, Release)()
-    {
-        NS_PRECONDITION(0 != mRefCnt, "dup release");
-        --mRefCnt;
-        if (mRefCnt == 0) {
-            delete this;
-            return 0;
-        }
-        return mRefCnt;
-    }
-
-    // IDWriteFontFileStream methods
-    virtual HRESULT STDMETHODCALLTYPE ReadFileFragment(void const** fragmentStart,
-                                                       UINT64 fileOffset,
-                                                       UINT64 fragmentSize,
-                                                       OUT void** fragmentContext);
-
-    virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* fragmentContext);
-
-    virtual HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64* fileSize);
-
-    virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64* lastWriteTime);
-
-private:
-    FallibleTArray<uint8_t> mData;
-    nsAutoRefCnt mRefCnt;
-}; 
-
 #endif /* GFX_DWRITECOMMON_H */
--- a/gfx/thebes/gfxDWriteFontList.cpp
+++ b/gfx/thebes/gfxDWriteFontList.cpp
@@ -784,58 +784,36 @@ gfxDWriteFontList::MakePlatformFont(cons
 
     rv = gfxFontUtils::RenameFont(uniqueName, aFontData, aLength, &newFontData);
     free((void*)aFontData);
 
     if (NS_FAILED(rv)) {
         return nullptr;
     }
     
+    RefPtr<IDWriteFontFileStream> fontFileStream;
     RefPtr<IDWriteFontFile> fontFile;
-    HRESULT hr;
-
-    /**
-     * We pass in a pointer to a structure containing a pointer to the array
-     * containing the font data and a unique identifier. DWrite will
-     * internally copy what is at that pointer, and pass that to
-     * CreateStreamFromKey. The array will be empty when the function 
-     * succesfully returns since it swaps out the data.
-     */
-    ffReferenceKey key;
-    key.mArray = &newFontData;
-    nsCOMPtr<nsIUUIDGenerator> uuidgen =
-      do_GetService("@mozilla.org/uuid-generator;1");
-    if (!uuidgen) {
-        return nullptr;
-    }
-
-    rv = uuidgen->GenerateUUIDInPlace(&key.mGUID);
-
-    if (NS_FAILED(rv)) {
-        return nullptr;
-    }
-
-    hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
-        CreateCustomFontFileReference(&key,
-                                      sizeof(key),
-                                      gfxDWriteFontFileLoader::Instance(),
-                                      getter_AddRefs(fontFile));
+    HRESULT hr =
+      gfxDWriteFontFileLoader::CreateCustomFontFile(newFontData,
+                                                    getter_AddRefs(fontFile),
+                                                    getter_AddRefs(fontFileStream));
 
     if (FAILED(hr)) {
         NS_WARNING("Failed to create custom font file reference.");
         return nullptr;
     }
 
     BOOL isSupported;
     DWRITE_FONT_FILE_TYPE fileType;
     UINT32 numFaces;
 
     gfxDWriteFontEntry *entry = 
         new gfxDWriteFontEntry(uniqueName, 
                                fontFile,
+                               fontFileStream,
                                aWeight,
                                aStretch,
                                aStyle);
 
     fontFile->Analyze(&isSupported, &fileType, &entry->mFaceType, &numFaces);
     if (!isSupported || numFaces > 1) {
         // We don't know how to deal with 0 faces either.
         delete entry;
--- a/gfx/thebes/gfxDWriteFontList.h
+++ b/gfx/thebes/gfxDWriteFontList.h
@@ -121,27 +121,29 @@ public:
         mIsCJK = UNINITIALIZED_VALUE;
     }
 
     /**
      * Constructs a font entry using a font file.
      *
      * \param aFaceName The name of the corresponding font face.
      * \param aFontFile DirectWrite fontfile object
+     * \param aFontFileStream DirectWrite fontfile stream object
      * \param aWeight Weight of the font
      * \param aStretch Stretch of the font
      * \param aStyle italic or oblique of font
      */
     gfxDWriteFontEntry(const nsAString& aFaceName,
                               IDWriteFontFile *aFontFile,
+                              IDWriteFontFileStream *aFontFileStream,
                               uint16_t aWeight,
                               int16_t aStretch,
                               uint8_t aStyle)
       : gfxFontEntry(aFaceName), mFont(nullptr), mFontFile(aFontFile),
-        mForceGDIClassic(false)
+        mFontFileStream(aFontFileStream), mForceGDIClassic(false)
     {
         mWeight = aWeight;
         mStretch = aStretch;
         mStyle = aStyle;
         mIsDataUserFont = true;
         mIsCJK = UNINITIALIZED_VALUE;
     }
 
@@ -181,16 +183,20 @@ protected:
 
     /**
      * A fontentry only needs to have either of these. If it has both only
      * the IDWriteFont will be used.
      */
     RefPtr<IDWriteFont> mFont;
     RefPtr<IDWriteFontFile> mFontFile;
 
+    // For custom fonts, we hold a reference to the IDWriteFontFileStream for
+    // for the IDWriteFontFile, so that the data is available.
+    RefPtr<IDWriteFontFileStream> mFontFileStream;
+
     // font face corresponding to the mFont/mFontFile *without* any DWrite
     // style simulations applied
     RefPtr<IDWriteFontFace> mFontFace;
 
     DWRITE_FONT_FACE_TYPE mFaceType;
 
     int8_t mIsCJK;
     bool mForceGDIClassic;