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 318988 f8c51f0d7cd47fe6e7e65dd88d54f3f6fce79d91
parent 318987 318888301328d03b717b26036c248bf69420aef2
child 318989 c14e6cfb20dd844b82b1e5e7bb70a9cfec193f77
push id8951
push userbenj@benj.me
push dateTue, 05 Jan 2016 13:08:54 +0000
reviewersbas
bugs1156742
milestone46.0a1
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;