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 "ScaledFontDWrite.h"
8 #include "DrawTargetD2D.h"
22 class DWriteFontFileLoader
: public IDWriteFontFileLoader
25 DWriteFontFileLoader()
30 IFACEMETHOD(QueryInterface
)(IID
const& iid
, OUT
void** ppObject
)
32 if (iid
== __uuidof(IDWriteFontFileLoader
)) {
33 *ppObject
= static_cast<IDWriteFontFileLoader
*>(this);
35 } else if (iid
== __uuidof(IUnknown
)) {
36 *ppObject
= static_cast<IUnknown
*>(this);
43 IFACEMETHOD_(ULONG
, AddRef
)()
48 IFACEMETHOD_(ULONG
, Release
)()
53 // IDWriteFontFileLoader methods
55 * Important! Note the key here -has- to be a pointer to an
56 * ffReferenceKey object.
58 virtual HRESULT STDMETHODCALLTYPE
59 CreateStreamFromKey(void const* fontFileReferenceKey
,
60 UINT32 fontFileReferenceKeySize
,
61 OUT IDWriteFontFileStream
** fontFileStream
);
64 * Gets the singleton loader instance. Note that when using this font
65 * loader, the key must be a pointer to an FallibleTArray<uint8_t>. This
66 * array will be empty when the function returns.
68 static IDWriteFontFileLoader
* Instance()
71 mInstance
= new DWriteFontFileLoader();
72 DrawTargetD2D::GetDWriteFactory()->
73 RegisterFontFileLoader(mInstance
);
79 static IDWriteFontFileLoader
* mInstance
;
82 class DWriteFontFileStream
: public IDWriteFontFileStream
86 * Used by the FontFileLoader to create a new font stream,
87 * this font stream is created from data in memory. The memory
88 * passed may be released after object creation, it will be
91 * @param aData Font data
93 DWriteFontFileStream(uint8_t *aData
, uint32_t aSize
);
94 ~DWriteFontFileStream();
97 IFACEMETHOD(QueryInterface
)(IID
const& iid
, OUT
void** ppObject
)
99 if (iid
== __uuidof(IDWriteFontFileStream
)) {
100 *ppObject
= static_cast<IDWriteFontFileStream
*>(this);
102 } else if (iid
== __uuidof(IUnknown
)) {
103 *ppObject
= static_cast<IUnknown
*>(this);
106 return E_NOINTERFACE
;
110 IFACEMETHOD_(ULONG
, AddRef
)()
116 IFACEMETHOD_(ULONG
, Release
)()
126 // IDWriteFontFileStream methods
127 virtual HRESULT STDMETHODCALLTYPE
ReadFileFragment(void const** fragmentStart
,
130 OUT
void** fragmentContext
);
132 virtual void STDMETHODCALLTYPE
ReleaseFileFragment(void* fragmentContext
);
134 virtual HRESULT STDMETHODCALLTYPE
GetFileSize(OUT UINT64
* fileSize
);
136 virtual HRESULT STDMETHODCALLTYPE
GetLastWriteTime(OUT UINT64
* lastWriteTime
);
139 std::vector
<uint8_t> mData
;
144 GetSystemTextQuality()
149 if (!SystemParametersInfo(SPI_GETFONTSMOOTHING
, 0, &font_smoothing
, 0)) {
150 return DEFAULT_QUALITY
;
153 if (font_smoothing
) {
154 if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE
,
155 0, &smoothing_type
, 0)) {
156 return DEFAULT_QUALITY
;
159 if (smoothing_type
== FE_FONTSMOOTHINGCLEARTYPE
) {
160 return CLEARTYPE_QUALITY
;
163 return ANTIALIASED_QUALITY
;
166 return DEFAULT_QUALITY
;
169 #define GASP_TAG 0x70736167
170 #define GASP_DOGRAY 0x2
172 static inline unsigned short
173 readShort(const char *aBuf
)
175 return (*aBuf
<< 8) | *(aBuf
+ 1);
179 DoGrayscale(IDWriteFontFace
*aDWFace
, Float ppem
)
185 aDWFace
->TryGetFontTable(GASP_TAG
, (const void**)&tableData
, &tableSize
, &tableContext
, &exists
);
189 aDWFace
->ReleaseFontTable(tableContext
);
193 unsigned short maxPPEM
; // Stored big-endian
194 unsigned short behavior
; // Stored big-endian
196 unsigned short numRanges
= readShort(tableData
+ 2);
197 if (tableSize
< (UINT
)4 + numRanges
* 4) {
198 aDWFace
->ReleaseFontTable(tableContext
);
201 gaspRange
*ranges
= (gaspRange
*)(tableData
+ 4);
202 for (int i
= 0; i
< numRanges
; i
++) {
203 if (readShort((char*)&ranges
[i
].maxPPEM
) > ppem
) {
204 if (!(readShort((char*)&ranges
[i
].behavior
) & GASP_DOGRAY
)) {
205 aDWFace
->ReleaseFontTable(tableContext
);
211 aDWFace
->ReleaseFontTable(tableContext
);
216 IDWriteFontFileLoader
* DWriteFontFileLoader::mInstance
= nullptr;
218 HRESULT STDMETHODCALLTYPE
219 DWriteFontFileLoader::CreateStreamFromKey(const void *fontFileReferenceKey
,
220 UINT32 fontFileReferenceKeySize
,
221 IDWriteFontFileStream
**fontFileStream
)
223 if (!fontFileReferenceKey
|| !fontFileStream
) {
227 const ffReferenceKey
*key
= static_cast<const ffReferenceKey
*>(fontFileReferenceKey
);
229 new DWriteFontFileStream(key
->mData
, key
->mSize
);
231 if (!*fontFileStream
) {
232 return E_OUTOFMEMORY
;
234 (*fontFileStream
)->AddRef();
238 DWriteFontFileStream::DWriteFontFileStream(uint8_t *aData
, uint32_t aSize
)
242 memcpy(&mData
.front(), aData
, aSize
);
245 DWriteFontFileStream::~DWriteFontFileStream()
249 HRESULT STDMETHODCALLTYPE
250 DWriteFontFileStream::GetFileSize(UINT64
*fileSize
)
252 *fileSize
= mData
.size();
256 HRESULT STDMETHODCALLTYPE
257 DWriteFontFileStream::GetLastWriteTime(UINT64
*lastWriteTime
)
262 HRESULT STDMETHODCALLTYPE
263 DWriteFontFileStream::ReadFileFragment(const void **fragmentStart
,
266 void **fragmentContext
)
268 // We are required to do bounds checking.
269 if (fileOffset
+ fragmentSize
> mData
.size()) {
273 // truncate the 64 bit fileOffset to size_t sized index into mData
274 size_t index
= static_cast<size_t>(fileOffset
);
276 // We should be alive for the duration of this.
277 *fragmentStart
= &mData
[index
];
278 *fragmentContext
= nullptr;
282 void STDMETHODCALLTYPE
283 DWriteFontFileStream::ReleaseFileFragment(void *fragmentContext
)
287 ScaledFontDWrite::ScaledFontDWrite(uint8_t *aData
, uint32_t aSize
,
288 uint32_t aIndex
, Float aGlyphSize
)
289 : ScaledFontBase(aGlyphSize
)
291 IDWriteFactory
*factory
= DrawTargetD2D::GetDWriteFactory();
297 RefPtr
<IDWriteFontFile
> fontFile
;
298 if (FAILED(factory
->CreateCustomFontFileReference(&key
, sizeof(ffReferenceKey
), DWriteFontFileLoader::Instance(), byRef(fontFile
)))) {
299 gfxWarning() << "Failed to load font file from data!";
303 IDWriteFontFile
*ff
= fontFile
;
304 if (FAILED(factory
->CreateFontFace(DWRITE_FONT_FACE_TYPE_TRUETYPE
, 1, &ff
, aIndex
, DWRITE_FONT_SIMULATIONS_NONE
, byRef(mFontFace
)))) {
305 gfxWarning() << "Failed to create font face from font file data!";
310 ScaledFontDWrite::GetPathForGlyphs(const GlyphBuffer
&aBuffer
, const DrawTarget
*aTarget
)
312 if (aTarget
->GetType() != BACKEND_DIRECT2D
) {
313 return ScaledFontBase::GetPathForGlyphs(aBuffer
, aTarget
);
316 RefPtr
<PathBuilder
> pathBuilder
= aTarget
->CreatePathBuilder();
318 PathBuilderD2D
*pathBuilderD2D
=
319 static_cast<PathBuilderD2D
*>(pathBuilder
.get());
321 CopyGlyphsToSink(aBuffer
, pathBuilderD2D
->GetSink());
323 return pathBuilder
->Finish();
327 ScaledFontDWrite::CopyGlyphsToBuilder(const GlyphBuffer
&aBuffer
, PathBuilder
*aBuilder
, const Matrix
*)
329 // XXX - Check path builder type!
330 PathBuilderD2D
*pathBuilderD2D
=
331 static_cast<PathBuilderD2D
*>(aBuilder
);
333 CopyGlyphsToSink(aBuffer
, pathBuilderD2D
->GetSink());
337 ScaledFontDWrite::CopyGlyphsToSink(const GlyphBuffer
&aBuffer
, ID2D1GeometrySink
*aSink
)
339 std::vector
<UINT16
> indices
;
340 std::vector
<FLOAT
> advances
;
341 std::vector
<DWRITE_GLYPH_OFFSET
> offsets
;
342 indices
.resize(aBuffer
.mNumGlyphs
);
343 advances
.resize(aBuffer
.mNumGlyphs
);
344 offsets
.resize(aBuffer
.mNumGlyphs
);
346 memset(&advances
.front(), 0, sizeof(FLOAT
) * aBuffer
.mNumGlyphs
);
347 for (unsigned int i
= 0; i
< aBuffer
.mNumGlyphs
; i
++) {
348 indices
[i
] = aBuffer
.mGlyphs
[i
].mIndex
;
349 offsets
[i
].advanceOffset
= aBuffer
.mGlyphs
[i
].mPosition
.x
;
350 offsets
[i
].ascenderOffset
= -aBuffer
.mGlyphs
[i
].mPosition
.y
;
353 mFontFace
->GetGlyphRunOutline(mSize
, &indices
.front(), &advances
.front(),
354 &offsets
.front(), aBuffer
.mNumGlyphs
,
355 FALSE
, FALSE
, aSink
);
359 ScaledFontDWrite::GetFontFileData(FontFileDataOutput aDataCallback
, void *aBaton
)
361 UINT32 fileCount
= 0;
362 mFontFace
->GetFiles(&fileCount
, nullptr);
369 RefPtr
<IDWriteFontFile
> file
;
370 mFontFace
->GetFiles(&fileCount
, byRef(file
));
372 const void *referenceKey
;
374 // XXX - This can currently crash for webfonts, as when we get the reference
375 // key out of the file, that can be an invalid reference key for the loader
376 // we use it with. The fix to this is not obvious but it will probably
377 // have to happen inside thebes.
378 file
->GetReferenceKey(&referenceKey
, &refKeySize
);
380 RefPtr
<IDWriteFontFileLoader
> loader
;
381 file
->GetLoader(byRef(loader
));
383 RefPtr
<IDWriteFontFileStream
> stream
;
384 loader
->CreateStreamFromKey(referenceKey
, refKeySize
, byRef(stream
));
387 stream
->GetFileSize(&fileSize64
);
388 if (fileSize64
> UINT32_MAX
) {
393 uint32_t fileSize
= static_cast<uint32_t>(fileSize64
);
394 const void *fragmentStart
;
396 stream
->ReadFileFragment(&fragmentStart
, 0, fileSize
, &context
);
398 aDataCallback((uint8_t*)fragmentStart
, fileSize
, mFontFace
->GetIndex(), mSize
, aBaton
);
400 stream
->ReleaseFileFragment(context
);
406 ScaledFontDWrite::GetDefaultAAMode()
408 AntialiasMode defaultMode
= AA_SUBPIXEL
;
410 switch (GetSystemTextQuality()) {
411 case CLEARTYPE_QUALITY
:
412 defaultMode
= AA_SUBPIXEL
;
414 case ANTIALIASED_QUALITY
:
415 defaultMode
= AA_GRAY
;
417 case DEFAULT_QUALITY
:
418 defaultMode
= AA_NONE
;
422 if (defaultMode
== AA_GRAY
) {
423 if (!DoGrayscale(mFontFace
, mSize
)) {
424 defaultMode
= AA_NONE
;