Bug 1706464 [wpt PR 28605] - Off-thread CSS paint: handle no-op animation, a=testonly
[gecko.git] / gfx / 2d / NativeFontResourceDWrite.cpp
blobfa646e91b332ea2b692efa64be846c4fd2e709f0
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>
12 #include "Logging.h"
13 #include "mozilla/RefPtr.h"
14 #include "mozilla/StaticMutex.h"
15 #include "nsTArray.h"
17 namespace mozilla {
18 namespace gfx {
20 static StaticMutex sFontFileStreamsMutex;
21 static uint64_t sNextFontFileKey = 0;
22 static std::unordered_map<uint64_t, IDWriteFontFileStream*> sFontFileStreams;
24 class DWriteFontFileLoader : public IDWriteFontFileLoader {
25 public:
26 DWriteFontFileLoader() {}
28 // IUnknown interface
29 IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) {
30 if (iid == __uuidof(IDWriteFontFileLoader)) {
31 *ppObject = static_cast<IDWriteFontFileLoader*>(this);
32 return S_OK;
33 } else if (iid == __uuidof(IUnknown)) {
34 *ppObject = static_cast<IUnknown*>(this);
35 return S_OK;
36 } else {
37 return E_NOINTERFACE;
41 IFACEMETHOD_(ULONG, AddRef)() { return 1; }
43 IFACEMETHOD_(ULONG, Release)() { return 1; }
45 // IDWriteFontFileLoader methods
46 /**
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);
54 /**
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
57 * sNextFontFileKey.
58 * Also note that this is _not_ threadsafe.
60 static IDWriteFontFileLoader* Instance() {
61 if (!mInstance) {
62 mInstance = new DWriteFontFileLoader();
63 Factory::GetDWriteFactory()->RegisterFontFileLoader(mInstance);
65 return mInstance;
68 private:
69 static IDWriteFontFileLoader* mInstance;
72 class DWriteFontFileStream final : public IDWriteFontFileStream {
73 public:
74 explicit DWriteFontFileStream(uint64_t aFontFileKey);
76 /**
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
80 * copied internally.
82 * @param aData Font data
84 bool Initialize(uint8_t* aData, uint32_t aSize);
86 // IUnknown interface
87 IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) {
88 if (iid == __uuidof(IDWriteFontFileStream)) {
89 *ppObject = static_cast<IDWriteFontFileStream*>(this);
90 return S_OK;
91 } else if (iid == __uuidof(IUnknown)) {
92 *ppObject = static_cast<IUnknown*>(this);
93 return S_OK;
94 } else {
95 return E_NOINTERFACE;
99 IFACEMETHOD_(ULONG, AddRef)() { return ++mRefCnt; }
101 IFACEMETHOD_(ULONG, Release)() {
102 uint32_t count = --mRefCnt;
103 if (count == 0) {
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);
107 if (0 != mRefCnt) {
108 return mRefCnt;
110 delete this;
112 return count;
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);
126 private:
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) {
140 return E_POINTER;
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;
148 return E_FAIL;
151 found->second->AddRef();
152 *fontFileStream = found->second;
153 return S_OK;
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)) {
165 return false;
167 memcpy(mData.Elements(), aData, aSize);
168 return true;
171 HRESULT STDMETHODCALLTYPE DWriteFontFileStream::GetFileSize(UINT64* fileSize) {
172 *fileSize = mData.Length();
173 return S_OK;
176 HRESULT STDMETHODCALLTYPE
177 DWriteFontFileStream::GetLastWriteTime(UINT64* lastWriteTime) {
178 return E_NOTIMPL;
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()) {
186 return E_FAIL;
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;
195 return S_OK;
198 void STDMETHODCALLTYPE
199 DWriteFontFileStream::ReleaseFileFragment(void* fragmentContext) {}
201 /* static */
202 already_AddRefed<NativeFontResourceDWrite> NativeFontResourceDWrite::Create(
203 uint8_t* aFontData, uint32_t aDataLength) {
204 RefPtr<IDWriteFactory> factory = Factory::GetDWriteFactory();
205 if (!factory) {
206 gfxWarning() << "Failed to get DWrite Factory.";
207 return nullptr;
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.";
216 return nullptr;
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));
225 if (FAILED(hr)) {
226 gfxWarning() << "Failed to load font file from data!";
227 return nullptr;
230 BOOL isSupported;
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.";
237 return nullptr;
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.";
251 return nullptr;
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.";
260 return nullptr;
263 RefPtr<UnscaledFont> unscaledFont = new UnscaledFontDWrite(fontFace, nullptr);
265 return unscaledFont.forget();
268 } // namespace gfx
269 } // namespace mozilla