mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-02 01:48:05 +00:00
309 lines
8.6 KiB
C++
309 lines
8.6 KiB
C++
/* -*- 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;
|
|
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) {
|
|
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()
|
|
{
|
|
StaticMutexAutoLock lock(sFontFileStreamsMutex);
|
|
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,
|
|
bool aNeedsCairo)
|
|
{
|
|
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(), faceType,
|
|
numberOfFaces, aNeedsCairo);
|
|
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,
|
|
DWRITE_FONT_SIMULATIONS_NONE,
|
|
mNeedsCairo);
|
|
|
|
return unscaledFont.forget();
|
|
}
|
|
|
|
} // gfx
|
|
} // mozilla
|