diff options
Diffstat (limited to 'gfx/2d/NativeFontResourceDWrite.cpp')
-rw-r--r-- | gfx/2d/NativeFontResourceDWrite.cpp | 288 |
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 |