зеркало из https://github.com/mozilla/gecko-dev.git
216 строки
6.4 KiB
C++
216 строки
6.4 KiB
C++
/* -*- 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"
|
|
|
|
class gfxDWriteFontFileStream;
|
|
|
|
static mozilla::Atomic<uint64_t> sNextFontFileKey;
|
|
static std::unordered_map<uint64_t, gfxDWriteFontFileStream*> 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(const uint8_t* aData,
|
|
uint32_t aLength,
|
|
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);
|
|
|
|
size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
|
|
return mData.ShallowSizeOfExcludingThis(mallocSizeOf);
|
|
}
|
|
|
|
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
|
|
return mallocSizeOf(this) + SizeOfExcludingThis(mallocSizeOf);
|
|
}
|
|
|
|
private:
|
|
FallibleTArray<uint8_t> mData;
|
|
nsAutoRefCnt mRefCnt;
|
|
uint64_t mFontFileKey;
|
|
};
|
|
|
|
gfxDWriteFontFileStream::gfxDWriteFontFileStream(const uint8_t* aData,
|
|
uint32_t aLength,
|
|
uint64_t aFontFileKey)
|
|
: mFontFileKey(aFontFileKey)
|
|
{
|
|
// If this fails, mData will remain empty. That's OK: GetFileSize()
|
|
// will then return 0, etc., and the font just won't load.
|
|
if (!mData.AppendElements(aData, aLength, mozilla::fallible_t())) {
|
|
NS_WARNING("Failed to store data in gfxDWriteFontFileStream");
|
|
}
|
|
}
|
|
|
|
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(const uint8_t* aFontData,
|
|
uint32_t aLength,
|
|
IDWriteFontFile** aFontFile,
|
|
IDWriteFontFileStream** aFontFileStream)
|
|
{
|
|
MOZ_ASSERT(aFontFile);
|
|
MOZ_ASSERT(aFontFileStream);
|
|
|
|
RefPtr<IDWriteFactory> factory = mozilla::gfx::Factory::GetDWriteFactory();
|
|
if (!factory) {
|
|
gfxCriticalError() << "Failed to get DWrite Factory in CreateCustomFontFile.";
|
|
return E_FAIL;
|
|
}
|
|
|
|
uint64_t fontFileKey = sNextFontFileKey++;
|
|
RefPtr<gfxDWriteFontFileStream> ffsRef =
|
|
new gfxDWriteFontFileStream(aFontData, aLength, 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;
|
|
}
|
|
|
|
size_t
|
|
gfxDWriteFontFileLoader::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
|
|
{
|
|
size_t sizes = mallocSizeOf(this);
|
|
|
|
// We are a singleton type that is effective owner of sFontFileStreams.
|
|
MOZ_ASSERT(this == mInstance);
|
|
for (const auto& entry : sFontFileStreams) {
|
|
gfxDWriteFontFileStream* fileStream = entry.second;
|
|
sizes += fileStream->SizeOfIncludingThis(mallocSizeOf);
|
|
}
|
|
|
|
return sizes;
|
|
}
|