summaryrefslogtreecommitdiffstats
path: root/gfx/2d/NativeFontResourceDWrite.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/2d/NativeFontResourceDWrite.cpp')
-rw-r--r--gfx/2d/NativeFontResourceDWrite.cpp288
1 files changed, 288 insertions, 0 deletions
diff --git a/gfx/2d/NativeFontResourceDWrite.cpp b/gfx/2d/NativeFontResourceDWrite.cpp
new file mode 100644
index 000000000..e4d12ad87
--- /dev/null
+++ b/gfx/2d/NativeFontResourceDWrite.cpp
@@ -0,0 +1,288 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "NativeFontResourceDWrite.h"
+
+#include <unordered_map>
+
+#include "DrawTargetD2D1.h"
+#include "Logging.h"
+#include "mozilla/RefPtr.h"
+
+namespace mozilla {
+namespace gfx {
+
+static Atomic<uint64_t> sNextFontFileKey;
+static std::unordered_map<uint64_t, IDWriteFontFileStream*> sFontFileStreams;
+
+class DWriteFontFileLoader : public IDWriteFontFileLoader
+{
+public:
+ DWriteFontFileLoader()
+ {
+ }
+
+ // IUnknown interface
+ IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject)
+ {
+ if (iid == __uuidof(IDWriteFontFileLoader)) {
+ *ppObject = static_cast<IDWriteFontFileLoader*>(this);
+ return S_OK;
+ } else if (iid == __uuidof(IUnknown)) {
+ *ppObject = static_cast<IUnknown*>(this);
+ return S_OK;
+ } else {
+ return E_NOINTERFACE;
+ }
+ }
+
+ IFACEMETHOD_(ULONG, AddRef)()
+ {
+ return 1;
+ }
+
+ IFACEMETHOD_(ULONG, Release)()
+ {
+ return 1;
+ }
+
+ // IDWriteFontFileLoader methods
+ /**
+ * Important! Note the key here has to be a uint64_t that will have been
+ * generated by incrementing sNextFontFileKey.
+ */
+ 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 uint64_t that has been generated by incrementing
+ * sNextFontFileKey.
+ * Also note that this is _not_ threadsafe.
+ */
+ static IDWriteFontFileLoader* Instance()
+ {
+ if (!mInstance) {
+ mInstance = new DWriteFontFileLoader();
+ DrawTargetD2D1::GetDWriteFactory()->
+ RegisterFontFileLoader(mInstance);
+ }
+ return mInstance;
+ }
+
+private:
+ static IDWriteFontFileLoader* mInstance;
+};
+
+class DWriteFontFileStream : 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
+ */
+ DWriteFontFileStream(uint8_t *aData, uint32_t aSize, uint64_t aFontFileKey);
+ ~DWriteFontFileStream();
+
+ // 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)()
+ {
+ ++mRefCnt;
+ return mRefCnt;
+ }
+
+ IFACEMETHOD_(ULONG, 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:
+ std::vector<uint8_t> mData;
+ uint32_t mRefCnt;
+ uint64_t mFontFileKey;
+};
+
+IDWriteFontFileLoader* DWriteFontFileLoader::mInstance = nullptr;
+
+HRESULT STDMETHODCALLTYPE
+DWriteFontFileLoader::CreateStreamFromKey(const void *fontFileReferenceKey,
+ UINT32 fontFileReferenceKeySize,
+ IDWriteFontFileStream **fontFileStream)
+{
+ if (!fontFileReferenceKey || !fontFileStream) {
+ return E_POINTER;
+ }
+
+ uint64_t fontFileKey = *static_cast<const uint64_t*>(fontFileReferenceKey);
+ auto found = sFontFileStreams.find(fontFileKey);
+ if (found == sFontFileStreams.end()) {
+ *fontFileStream = nullptr;
+ return E_FAIL;
+ }
+
+ found->second->AddRef();
+ *fontFileStream = found->second;
+ return S_OK;
+}
+
+DWriteFontFileStream::DWriteFontFileStream(uint8_t *aData, uint32_t aSize,
+ uint64_t aFontFileKey)
+ : mRefCnt(0)
+ , mFontFileKey(aFontFileKey)
+{
+ mData.resize(aSize);
+ memcpy(&mData.front(), aData, aSize);
+}
+
+DWriteFontFileStream::~DWriteFontFileStream()
+{
+ sFontFileStreams.erase(mFontFileKey);
+}
+
+HRESULT STDMETHODCALLTYPE
+DWriteFontFileStream::GetFileSize(UINT64 *fileSize)
+{
+ *fileSize = mData.size();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE
+DWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE
+DWriteFontFileStream::ReadFileFragment(const void **fragmentStart,
+ UINT64 fileOffset,
+ UINT64 fragmentSize,
+ void **fragmentContext)
+{
+ // We are required to do bounds checking.
+ if (fileOffset + fragmentSize > mData.size()) {
+ return E_FAIL;
+ }
+
+ // truncate the 64 bit fileOffset to size_t sized index into mData
+ size_t index = static_cast<size_t>(fileOffset);
+
+ // We should be alive for the duration of this.
+ *fragmentStart = &mData[index];
+ *fragmentContext = nullptr;
+ return S_OK;
+}
+
+void STDMETHODCALLTYPE
+DWriteFontFileStream::ReleaseFileFragment(void *fragmentContext)
+{
+}
+
+/* static */
+already_AddRefed<NativeFontResourceDWrite>
+NativeFontResourceDWrite::Create(uint8_t *aFontData, uint32_t aDataLength,
+ bool aNeedsCairo)
+{
+ IDWriteFactory *factory = DrawTargetD2D1::GetDWriteFactory();
+ if (!factory) {
+ gfxWarning() << "Failed to get DWrite Factory.";
+ return nullptr;
+ }
+
+ uint64_t fontFileKey = sNextFontFileKey++;
+ RefPtr<IDWriteFontFileStream> ffsRef =
+ new DWriteFontFileStream(aFontData, aDataLength, fontFileKey);
+ sFontFileStreams[fontFileKey] = ffsRef;
+
+ RefPtr<IDWriteFontFile> fontFile;
+ HRESULT hr =
+ factory->CreateCustomFontFileReference(&fontFileKey, sizeof(fontFileKey),
+ DWriteFontFileLoader::Instance(),
+ getter_AddRefs(fontFile));
+ if (FAILED(hr)) {
+ gfxWarning() << "Failed to load font file from data!";
+ return nullptr;
+ }
+
+ BOOL isSupported;
+ DWRITE_FONT_FILE_TYPE fileType;
+ DWRITE_FONT_FACE_TYPE faceType;
+ UINT32 numberOfFaces;
+ hr = fontFile->Analyze(&isSupported, &fileType, &faceType, &numberOfFaces);
+ if (FAILED(hr) || !isSupported) {
+ gfxWarning() << "Font file is not supported.";
+ return nullptr;
+ }
+
+ RefPtr<NativeFontResourceDWrite> fontResource =
+ new NativeFontResourceDWrite(factory, fontFile.forget(), faceType,
+ numberOfFaces, aNeedsCairo);
+ return fontResource.forget();
+}
+
+already_AddRefed<ScaledFont>
+NativeFontResourceDWrite::CreateScaledFont(uint32_t aIndex, Float aGlyphSize,
+ const uint8_t* aInstanceData, uint32_t aInstanceDataLength)
+{
+ if (aIndex >= mNumberOfFaces) {
+ gfxWarning() << "Font face index is too high for font resource.";
+ return nullptr;
+ }
+
+ IDWriteFontFile *fontFile = mFontFile;
+ RefPtr<IDWriteFontFace> fontFace;
+ if (FAILED(mFactory->CreateFontFace(mFaceType, 1, &fontFile, aIndex,
+ DWRITE_FONT_SIMULATIONS_NONE, getter_AddRefs(fontFace)))) {
+ gfxWarning() << "Failed to create font face from font file data.";
+ return nullptr;
+ }
+
+ RefPtr<ScaledFontBase> scaledFont = new ScaledFontDWrite(fontFace, aGlyphSize);
+ if (mNeedsCairo && !scaledFont->PopulateCairoScaledFont()) {
+ gfxWarning() << "Unable to create cairo scaled font DWrite font.";
+ return nullptr;
+ }
+
+ return scaledFont.forget();
+}
+
+} // gfx
+} // mozilla