1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "NativeFontResourceDWrite.h"
8 #include "UnscaledFontDWrite.h"
10 #include <unordered_map>
13 #include "mozilla/RefPtr.h"
14 #include "mozilla/StaticMutex.h"
20 static StaticMutex sFontFileStreamsMutex
;
21 static uint64_t sNextFontFileKey
= 0;
22 static std::unordered_map
<uint64_t, IDWriteFontFileStream
*> sFontFileStreams
;
24 class DWriteFontFileLoader
: public IDWriteFontFileLoader
{
26 DWriteFontFileLoader() {}
29 IFACEMETHOD(QueryInterface
)(IID
const& iid
, OUT
void** ppObject
) {
30 if (iid
== __uuidof(IDWriteFontFileLoader
)) {
31 *ppObject
= static_cast<IDWriteFontFileLoader
*>(this);
33 } else if (iid
== __uuidof(IUnknown
)) {
34 *ppObject
= static_cast<IUnknown
*>(this);
41 IFACEMETHOD_(ULONG
, AddRef
)() { return 1; }
43 IFACEMETHOD_(ULONG
, Release
)() { return 1; }
45 // IDWriteFontFileLoader methods
47 * Important! Note the key here has to be a uint64_t that will have been
48 * generated by incrementing sNextFontFileKey.
50 virtual HRESULT STDMETHODCALLTYPE
CreateStreamFromKey(
51 void const* fontFileReferenceKey
, UINT32 fontFileReferenceKeySize
,
52 OUT IDWriteFontFileStream
** fontFileStream
);
55 * Gets the singleton loader instance. Note that when using this font
56 * loader, the key must be a uint64_t that has been generated by incrementing
58 * Also note that this is _not_ threadsafe.
60 static IDWriteFontFileLoader
* Instance() {
62 mInstance
= new DWriteFontFileLoader();
63 Factory::GetDWriteFactory()->RegisterFontFileLoader(mInstance
);
69 static IDWriteFontFileLoader
* mInstance
;
72 class DWriteFontFileStream final
: public IDWriteFontFileStream
{
74 explicit DWriteFontFileStream(uint64_t aFontFileKey
);
77 * Used by the FontFileLoader to create a new font stream,
78 * this font stream is created from data in memory. The memory
79 * passed may be released after object creation, it will be
82 * @param aData Font data
84 bool Initialize(uint8_t* aData
, uint32_t aSize
);
87 IFACEMETHOD(QueryInterface
)(IID
const& iid
, OUT
void** ppObject
) {
88 if (iid
== __uuidof(IDWriteFontFileStream
)) {
89 *ppObject
= static_cast<IDWriteFontFileStream
*>(this);
91 } else if (iid
== __uuidof(IUnknown
)) {
92 *ppObject
= static_cast<IUnknown
*>(this);
99 IFACEMETHOD_(ULONG
, AddRef
)() { return ++mRefCnt
; }
101 IFACEMETHOD_(ULONG
, Release
)() {
102 uint32_t count
= --mRefCnt
;
104 // Avoid locking unless necessary. Verify the refcount hasn't changed
105 // while locked. Delete within the scope of the lock when zero.
106 StaticMutexAutoLock
lock(sFontFileStreamsMutex
);
115 // IDWriteFontFileStream methods
116 virtual HRESULT STDMETHODCALLTYPE
117 ReadFileFragment(void const** fragmentStart
, UINT64 fileOffset
,
118 UINT64 fragmentSize
, OUT
void** fragmentContext
);
120 virtual void STDMETHODCALLTYPE
ReleaseFileFragment(void* fragmentContext
);
122 virtual HRESULT STDMETHODCALLTYPE
GetFileSize(OUT UINT64
* fileSize
);
124 virtual HRESULT STDMETHODCALLTYPE
GetLastWriteTime(OUT UINT64
* lastWriteTime
);
127 nsTArray
<uint8_t> mData
;
128 Atomic
<uint32_t> mRefCnt
;
129 uint64_t mFontFileKey
;
131 ~DWriteFontFileStream();
134 IDWriteFontFileLoader
* DWriteFontFileLoader::mInstance
= nullptr;
136 HRESULT STDMETHODCALLTYPE
DWriteFontFileLoader::CreateStreamFromKey(
137 const void* fontFileReferenceKey
, UINT32 fontFileReferenceKeySize
,
138 IDWriteFontFileStream
** fontFileStream
) {
139 if (!fontFileReferenceKey
|| !fontFileStream
) {
143 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
;
156 DWriteFontFileStream::DWriteFontFileStream(uint64_t aFontFileKey
)
157 : mRefCnt(0), mFontFileKey(aFontFileKey
) {}
159 DWriteFontFileStream::~DWriteFontFileStream() {
160 sFontFileStreams
.erase(mFontFileKey
);
163 bool DWriteFontFileStream::Initialize(uint8_t* aData
, uint32_t aSize
) {
164 if (!mData
.SetLength(aSize
, fallible
)) {
167 memcpy(mData
.Elements(), aData
, aSize
);
171 HRESULT STDMETHODCALLTYPE
DWriteFontFileStream::GetFileSize(UINT64
* fileSize
) {
172 *fileSize
= mData
.Length();
176 HRESULT STDMETHODCALLTYPE
177 DWriteFontFileStream::GetLastWriteTime(UINT64
* lastWriteTime
) {
181 HRESULT STDMETHODCALLTYPE
DWriteFontFileStream::ReadFileFragment(
182 const void** fragmentStart
, UINT64 fileOffset
, UINT64 fragmentSize
,
183 void** fragmentContext
) {
184 // We are required to do bounds checking.
185 if (fileOffset
+ fragmentSize
> mData
.Length()) {
189 // truncate the 64 bit fileOffset to size_t sized index into mData
190 size_t index
= static_cast<size_t>(fileOffset
);
192 // We should be alive for the duration of this.
193 *fragmentStart
= &mData
[index
];
194 *fragmentContext
= nullptr;
198 void STDMETHODCALLTYPE
199 DWriteFontFileStream::ReleaseFileFragment(void* fragmentContext
) {}
202 already_AddRefed
<NativeFontResourceDWrite
> NativeFontResourceDWrite::Create(
203 uint8_t* aFontData
, uint32_t aDataLength
) {
204 RefPtr
<IDWriteFactory
> factory
= Factory::GetDWriteFactory();
206 gfxWarning() << "Failed to get DWrite Factory.";
210 sFontFileStreamsMutex
.Lock();
211 uint64_t fontFileKey
= sNextFontFileKey
++;
212 RefPtr
<DWriteFontFileStream
> ffsRef
= new DWriteFontFileStream(fontFileKey
);
213 if (!ffsRef
->Initialize(aFontData
, aDataLength
)) {
214 sFontFileStreamsMutex
.Unlock();
215 gfxWarning() << "Failed to create DWriteFontFileStream.";
218 sFontFileStreams
[fontFileKey
] = ffsRef
;
219 sFontFileStreamsMutex
.Unlock();
221 RefPtr
<IDWriteFontFile
> fontFile
;
222 HRESULT hr
= factory
->CreateCustomFontFileReference(
223 &fontFileKey
, sizeof(fontFileKey
), DWriteFontFileLoader::Instance(),
224 getter_AddRefs(fontFile
));
226 gfxWarning() << "Failed to load font file from data!";
231 DWRITE_FONT_FILE_TYPE fileType
;
232 DWRITE_FONT_FACE_TYPE faceType
;
233 UINT32 numberOfFaces
;
234 hr
= fontFile
->Analyze(&isSupported
, &fileType
, &faceType
, &numberOfFaces
);
235 if (FAILED(hr
) || !isSupported
) {
236 gfxWarning() << "Font file is not supported.";
240 RefPtr
<NativeFontResourceDWrite
> fontResource
=
241 new NativeFontResourceDWrite(factory
, fontFile
.forget(), ffsRef
.forget(),
242 faceType
, numberOfFaces
, aDataLength
);
243 return fontResource
.forget();
246 already_AddRefed
<UnscaledFont
> NativeFontResourceDWrite::CreateUnscaledFont(
247 uint32_t aIndex
, const uint8_t* aInstanceData
,
248 uint32_t aInstanceDataLength
) {
249 if (aIndex
>= mNumberOfFaces
) {
250 gfxWarning() << "Font face index is too high for font resource.";
254 IDWriteFontFile
* fontFile
= mFontFile
;
255 RefPtr
<IDWriteFontFace
> fontFace
;
256 if (FAILED(mFactory
->CreateFontFace(mFaceType
, 1, &fontFile
, aIndex
,
257 DWRITE_FONT_SIMULATIONS_NONE
,
258 getter_AddRefs(fontFace
)))) {
259 gfxWarning() << "Failed to create font face from font file data.";
263 RefPtr
<UnscaledFont
> unscaledFont
= new UnscaledFontDWrite(fontFace
, nullptr);
265 return unscaledFont
.forget();
269 } // namespace mozilla