diff options
Diffstat (limited to '')
-rw-r--r-- | gfx/2d/NativeFontResourceDWrite.cpp | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/gfx/2d/NativeFontResourceDWrite.cpp b/gfx/2d/NativeFontResourceDWrite.cpp new file mode 100644 index 0000000000..e0b599fa76 --- /dev/null +++ b/gfx/2d/NativeFontResourceDWrite.cpp @@ -0,0 +1,269 @@ +/* -*- 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 "UnscaledFontDWrite.h" + +#include <unordered_map> + +#include "Logging.h" +#include "mozilla/RefPtr.h" +#include "mozilla/StaticMutex.h" +#include "nsTArray.h" + +namespace mozilla { +namespace gfx { + +static StaticMutex sFontFileStreamsMutex MOZ_UNANNOTATED; +static uint64_t sNextFontFileKey = 0; +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(); + Factory::GetDWriteFactory()->RegisterFontFileLoader(mInstance); + } + return mInstance; + } + + private: + static IDWriteFontFileLoader* mInstance; +}; + +class DWriteFontFileStream final : public IDWriteFontFileStream { + public: + explicit DWriteFontFileStream(uint64_t aFontFileKey); + + /** + * 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 + */ + bool Initialize(uint8_t* aData, uint32_t aSize); + + // 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)() { return ++mRefCnt; } + + IFACEMETHOD_(ULONG, Release)() { + uint32_t count = --mRefCnt; + if (count == 0) { + // Avoid locking unless necessary. Verify the refcount hasn't changed + // while locked. Delete within the scope of the lock when zero. + StaticMutexAutoLock lock(sFontFileStreamsMutex); + if (0 != mRefCnt) { + return mRefCnt; + } + delete this; + } + return count; + } + + // 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: + nsTArray<uint8_t> mData; + Atomic<uint32_t> mRefCnt; + uint64_t mFontFileKey; + + ~DWriteFontFileStream(); +}; + +IDWriteFontFileLoader* DWriteFontFileLoader::mInstance = nullptr; + +HRESULT STDMETHODCALLTYPE DWriteFontFileLoader::CreateStreamFromKey( + const void* fontFileReferenceKey, UINT32 fontFileReferenceKeySize, + IDWriteFontFileStream** fontFileStream) { + if (!fontFileReferenceKey || !fontFileStream) { + return E_POINTER; + } + + StaticMutexAutoLock lock(sFontFileStreamsMutex); + 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(uint64_t aFontFileKey) + : mRefCnt(0), mFontFileKey(aFontFileKey) {} + +DWriteFontFileStream::~DWriteFontFileStream() { + sFontFileStreams.erase(mFontFileKey); +} + +bool DWriteFontFileStream::Initialize(uint8_t* aData, uint32_t aSize) { + if (!mData.SetLength(aSize, fallible)) { + return false; + } + memcpy(mData.Elements(), aData, aSize); + return true; +} + +HRESULT STDMETHODCALLTYPE DWriteFontFileStream::GetFileSize(UINT64* fileSize) { + *fileSize = mData.Length(); + 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.Length()) { + 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) { + RefPtr<IDWriteFactory> factory = Factory::GetDWriteFactory(); + if (!factory) { + gfxWarning() << "Failed to get DWrite Factory."; + return nullptr; + } + + sFontFileStreamsMutex.Lock(); + uint64_t fontFileKey = sNextFontFileKey++; + RefPtr<DWriteFontFileStream> ffsRef = new DWriteFontFileStream(fontFileKey); + if (!ffsRef->Initialize(aFontData, aDataLength)) { + sFontFileStreamsMutex.Unlock(); + gfxWarning() << "Failed to create DWriteFontFileStream."; + return nullptr; + } + sFontFileStreams[fontFileKey] = ffsRef; + sFontFileStreamsMutex.Unlock(); + + 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(), ffsRef.forget(), + faceType, numberOfFaces, aDataLength); + return fontResource.forget(); +} + +already_AddRefed<UnscaledFont> NativeFontResourceDWrite::CreateUnscaledFont( + uint32_t aIndex, 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<UnscaledFont> unscaledFont = new UnscaledFontDWrite(fontFace, nullptr); + + return unscaledFont.forget(); +} + +} // namespace gfx +} // namespace mozilla |