1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "gfxDWriteCommon.h"
8 #include <unordered_map>
10 #include "mozilla/Atomics.h"
11 #include "mozilla/StaticMutex.h"
12 #include "mozilla/gfx/Logging.h"
14 class gfxDWriteFontFileStream
;
16 static mozilla::StaticMutex sFontFileStreamsMutex MOZ_UNANNOTATED
;
17 static uint64_t sNextFontFileKey
= 0;
18 static std::unordered_map
<uint64_t, gfxDWriteFontFileStream
*> sFontFileStreams
;
20 IDWriteFontFileLoader
* gfxDWriteFontFileLoader::mInstance
= nullptr;
22 class gfxDWriteFontFileStream final
: public IDWriteFontFileStream
{
25 * Used by the FontFileLoader to create a new font stream,
26 * this font stream is created from data in memory. The memory
27 * passed may be released after object creation, it will be
30 * @param aData Font data
32 gfxDWriteFontFileStream(const uint8_t* aData
, uint32_t aLength
,
33 uint64_t aFontFileKey
);
34 ~gfxDWriteFontFileStream();
37 IFACEMETHOD(QueryInterface
)(IID
const& iid
, OUT
void** ppObject
) {
38 if (iid
== __uuidof(IDWriteFontFileStream
)) {
39 *ppObject
= static_cast<IDWriteFontFileStream
*>(this);
41 } else if (iid
== __uuidof(IUnknown
)) {
42 *ppObject
= static_cast<IUnknown
*>(this);
49 IFACEMETHOD_(ULONG
, AddRef
)() {
50 MOZ_ASSERT(int32_t(mRefCnt
) >= 0, "illegal refcnt");
54 IFACEMETHOD_(ULONG
, Release
)() {
55 MOZ_ASSERT(0 != mRefCnt
, "dup release");
56 uint32_t count
= --mRefCnt
;
58 // Avoid locking unless necessary. Verify the refcount hasn't changed
59 // while locked. Delete within the scope of the lock when zero.
60 mozilla::StaticMutexAutoLock
lock(sFontFileStreamsMutex
);
69 // IDWriteFontFileStream methods
70 virtual HRESULT STDMETHODCALLTYPE
71 ReadFileFragment(void const** fragmentStart
, UINT64 fileOffset
,
72 UINT64 fragmentSize
, OUT
void** fragmentContext
);
74 virtual void STDMETHODCALLTYPE
ReleaseFileFragment(void* fragmentContext
);
76 virtual HRESULT STDMETHODCALLTYPE
GetFileSize(OUT UINT64
* fileSize
);
78 virtual HRESULT STDMETHODCALLTYPE
GetLastWriteTime(OUT UINT64
* lastWriteTime
);
80 size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf
) const {
81 return mData
.ShallowSizeOfExcludingThis(mallocSizeOf
);
84 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
) const {
85 return mallocSizeOf(this) + SizeOfExcludingThis(mallocSizeOf
);
89 FallibleTArray
<uint8_t> mData
;
90 mozilla::Atomic
<uint32_t> mRefCnt
;
91 uint64_t mFontFileKey
;
94 gfxDWriteFontFileStream::gfxDWriteFontFileStream(const uint8_t* aData
,
96 uint64_t aFontFileKey
)
97 : mFontFileKey(aFontFileKey
) {
98 // If this fails, mData will remain empty. That's OK: GetFileSize()
99 // will then return 0, etc., and the font just won't load.
100 if (!mData
.AppendElements(aData
, aLength
, mozilla::fallible_t())) {
101 NS_WARNING("Failed to store data in gfxDWriteFontFileStream");
105 gfxDWriteFontFileStream::~gfxDWriteFontFileStream() {
106 sFontFileStreams
.erase(mFontFileKey
);
109 HRESULT STDMETHODCALLTYPE
110 gfxDWriteFontFileStream::GetFileSize(UINT64
* fileSize
) {
111 *fileSize
= mData
.Length();
115 HRESULT STDMETHODCALLTYPE
116 gfxDWriteFontFileStream::GetLastWriteTime(UINT64
* lastWriteTime
) {
120 HRESULT STDMETHODCALLTYPE
gfxDWriteFontFileStream::ReadFileFragment(
121 const void** fragmentStart
, UINT64 fileOffset
, UINT64 fragmentSize
,
122 void** fragmentContext
) {
123 // We are required to do bounds checking.
124 if (fileOffset
+ fragmentSize
> (UINT64
)mData
.Length()) {
127 // We should be alive for the duration of this.
128 *fragmentStart
= &mData
[fileOffset
];
129 *fragmentContext
= nullptr;
133 void STDMETHODCALLTYPE
134 gfxDWriteFontFileStream::ReleaseFileFragment(void* fragmentContext
) {}
136 HRESULT STDMETHODCALLTYPE
gfxDWriteFontFileLoader::CreateStreamFromKey(
137 const void* fontFileReferenceKey
, UINT32 fontFileReferenceKeySize
,
138 IDWriteFontFileStream
** fontFileStream
) {
139 if (!fontFileReferenceKey
|| !fontFileStream
) {
143 mozilla::StaticMutexAutoLock
lock(sFontFileStreamsMutex
);
144 uint64_t fontFileKey
= *static_cast<const uint64_t*>(fontFileReferenceKey
);
145 auto found
= sFontFileStreams
.find(fontFileKey
);
146 if (found
== sFontFileStreams
.end()) {
147 *fontFileStream
= nullptr;
151 found
->second
->AddRef();
152 *fontFileStream
= found
->second
;
158 gfxDWriteFontFileLoader::CreateCustomFontFile(
159 const uint8_t* aFontData
, uint32_t aLength
, IDWriteFontFile
** aFontFile
,
160 IDWriteFontFileStream
** aFontFileStream
) {
161 MOZ_ASSERT(aFontFile
);
162 MOZ_ASSERT(aFontFileStream
);
164 RefPtr
<IDWriteFactory
> factory
= mozilla::gfx::Factory::GetDWriteFactory();
167 << "Failed to get DWrite Factory in CreateCustomFontFile.";
171 sFontFileStreamsMutex
.Lock();
172 uint64_t fontFileKey
= sNextFontFileKey
++;
173 RefPtr
<gfxDWriteFontFileStream
> ffsRef
=
174 new gfxDWriteFontFileStream(aFontData
, aLength
, fontFileKey
);
175 sFontFileStreams
[fontFileKey
] = ffsRef
;
176 sFontFileStreamsMutex
.Unlock();
178 RefPtr
<IDWriteFontFile
> fontFile
;
179 HRESULT hr
= factory
->CreateCustomFontFileReference(
180 &fontFileKey
, sizeof(fontFileKey
), Instance(), getter_AddRefs(fontFile
));
182 NS_WARNING("Failed to load font file from data!");
186 fontFile
.forget(aFontFile
);
187 ffsRef
.forget(aFontFileStream
);
192 size_t gfxDWriteFontFileLoader::SizeOfIncludingThis(
193 mozilla::MallocSizeOf mallocSizeOf
) const {
194 size_t sizes
= mallocSizeOf(this);
196 // We are a singleton type that is effective owner of sFontFileStreams.
197 MOZ_ASSERT(this == mInstance
);
198 for (const auto& entry
: sFontFileStreams
) {
199 gfxDWriteFontFileStream
* fileStream
= entry
.second
;
200 sizes
+= fileStream
->SizeOfIncludingThis(mallocSizeOf
);