/* -*- 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" #include "mozilla/gfx/Logging.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; } 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; } /* static */ HRESULT gfxDWriteFontFileLoader::CreateCustomFontFile(FallibleTArray<uint8_t>& aFontData, IDWriteFontFile** aFontFile, IDWriteFontFileStream** aFontFileStream) { MOZ_ASSERT(aFontFile); MOZ_ASSERT(aFontFileStream); IDWriteFactory *factory = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory(); if (!factory) { gfxCriticalError() << "Failed to get DWrite Factory in CreateCustomFontFile."; return E_FAIL; } 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; }