1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
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 "mozilla/Logging.h"
8 #include "gfxUserFontSet.h"
9 #include "gfxPlatform.h"
11 #include "nsIProtocolHandler.h"
12 #include "gfxFontConstants.h"
13 #include "mozilla/FontPropertyTypes.h"
14 #include "mozilla/Preferences.h"
15 #include "mozilla/Services.h"
16 #include "mozilla/Telemetry.h"
17 #include "mozilla/gfx/2D.h"
18 #include "gfxPlatformFontList.h"
19 #include "mozilla/ServoStyleSet.h"
20 #include "mozilla/PostTraversalTask.h"
22 #include "opentype-sanitiser.h"
23 #include "ots-memory-stream.h"
25 using namespace mozilla
;
28 gfxUserFontSet::GetUserFontsLog()
30 static LazyLogModule
sLog("userfonts");
34 #define LOG(args) MOZ_LOG(gfxUserFontSet::GetUserFontsLog(), mozilla::LogLevel::Debug, args)
35 #define LOG_ENABLED() MOZ_LOG_TEST(gfxUserFontSet::GetUserFontsLog(), mozilla::LogLevel::Debug)
37 static uint64_t sFontSetGeneration
= 0;
39 // Based on ots::ExpandingMemoryStream from ots-memory-stream.h,
40 // adapted to use Mozilla allocators and to allow the final
41 // memory buffer to be adopted by the client.
42 class ExpandingMemoryStream
: public ots::OTSStream
{
44 ExpandingMemoryStream(size_t initial
, size_t limit
)
45 : mLength(initial
), mLimit(limit
), mOff(0) {
46 mPtr
= moz_xmalloc(mLength
);
49 ~ExpandingMemoryStream() {
53 // Return the buffer, resized to fit its contents (as it may have been
54 // over-allocated during growth), and give up ownership of it so the
55 // caller becomes responsible to call free() when finished with it.
57 void* p
= moz_xrealloc(mPtr
, mOff
);
62 bool WriteRaw(const void* data
, size_t length
) override
{
63 if ((mOff
+ length
> mLength
) ||
64 (mLength
> std::numeric_limits
<size_t>::max() - mOff
)) {
65 if (mLength
== mLimit
) {
68 size_t newLength
= (mLength
+ 1) * 2;
69 if (newLength
< mLength
) {
72 if (newLength
> mLimit
) {
75 mPtr
= moz_xrealloc(mPtr
, newLength
);
77 return WriteRaw(data
, length
);
79 std::memcpy(static_cast<char*>(mPtr
) + mOff
, data
, length
);
84 bool Seek(off_t position
) override
{
88 if (static_cast<size_t>(position
) > mLength
) {
95 off_t
Tell() const override
{
106 gfxUserFontEntry::gfxUserFontEntry(gfxUserFontSet
* aFontSet
,
107 const nsTArray
<gfxFontFaceSrc
>& aFontFaceSrcList
,
109 StretchRange aStretch
,
110 SlantStyleRange aStyle
,
111 const nsTArray
<gfxFontFeature
>& aFeatureSettings
,
112 const nsTArray
<gfxFontVariation
>& aVariationSettings
,
113 uint32_t aLanguageOverride
,
114 gfxCharacterMap
* aUnicodeRanges
,
115 uint8_t aFontDisplay
,
116 RangeFlags aRangeFlags
)
117 : gfxFontEntry(NS_LITERAL_CSTRING("userfont")),
118 mUserFontLoadState(STATUS_NOT_LOADED
),
119 mFontDataLoadingState(NOT_LOADING
),
120 mUnsupportedFormat(false),
121 mFontDisplay(aFontDisplay
),
125 mIsUserFontContainer
= true;
126 mSrcList
= aFontFaceSrcList
;
128 mWeightRange
= aWeight
;
129 mStretchRange
= aStretch
;
130 mStyleRange
= aStyle
;
131 mFeatureSettings
.AppendElements(aFeatureSettings
);
132 mVariationSettings
.AppendElements(aVariationSettings
);
133 mLanguageOverride
= aLanguageOverride
;
134 mCharacterMap
= aUnicodeRanges
;
135 mRangeFlags
= aRangeFlags
;
138 gfxUserFontEntry::~gfxUserFontEntry()
140 // Assert that we don't drop any gfxUserFontEntry objects during a Servo
141 // traversal, since PostTraversalTask objects can hold raw pointers to
142 // gfxUserFontEntry objects.
143 MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal());
147 gfxUserFontEntry::Matches(const nsTArray
<gfxFontFaceSrc
>& aFontFaceSrcList
,
149 StretchRange aStretch
,
150 SlantStyleRange aStyle
,
151 const nsTArray
<gfxFontFeature
>& aFeatureSettings
,
152 const nsTArray
<gfxFontVariation
>& aVariationSettings
,
153 uint32_t aLanguageOverride
,
154 gfxCharacterMap
* aUnicodeRanges
,
155 uint8_t aFontDisplay
,
156 RangeFlags aRangeFlags
)
158 return Weight() == aWeight
&&
159 Stretch() == aStretch
&&
160 SlantStyle() == aStyle
&&
161 mFeatureSettings
== aFeatureSettings
&&
162 mVariationSettings
== aVariationSettings
&&
163 mLanguageOverride
== aLanguageOverride
&&
164 mSrcList
== aFontFaceSrcList
&&
165 mFontDisplay
== aFontDisplay
&&
166 mRangeFlags
== aRangeFlags
&&
167 ((!aUnicodeRanges
&& !mCharacterMap
) ||
168 (aUnicodeRanges
&& mCharacterMap
&& mCharacterMap
->Equals(aUnicodeRanges
)));
172 gfxUserFontEntry::CreateFontInstance(const gfxFontStyle
* aFontStyle
)
174 MOZ_ASSERT_UNREACHABLE("should only be creating a gfxFont"
175 " with an actual platform font entry");
177 // userfont entry is a container, can't create font from the container
181 class MOZ_STACK_CLASS gfxOTSContext
: public ots::OTSContext
{
183 explicit gfxOTSContext(gfxUserFontEntry
* aUserFontEntry
)
184 : mUserFontEntry(aUserFontEntry
)
186 // Whether to apply OTS validation to OpenType Layout tables
187 mCheckOTLTables
= gfxPrefs::ValidateOTLTables();
188 // Whether to preserve Variation tables in downloaded fonts
189 mCheckVariationTables
= gfxPrefs::ValidateVariationTables();
190 // Whether to preserve color bitmap glyphs
191 mKeepColorBitmaps
= gfxPrefs::KeepColorBitmaps();
194 virtual ots::TableAction
GetTableAction(uint32_t aTag
) override
{
195 // Preserve Graphite, color glyph and SVG tables,
196 // and possibly OTL and Variation tables (depending on prefs)
197 if ((!mCheckOTLTables
&&
198 (aTag
== TRUETYPE_TAG('G', 'D', 'E', 'F') ||
199 aTag
== TRUETYPE_TAG('G', 'P', 'O', 'S') ||
200 aTag
== TRUETYPE_TAG('G', 'S', 'U', 'B'))) ||
201 (!mCheckVariationTables
&&
202 (aTag
== TRUETYPE_TAG('a', 'v', 'a', 'r') ||
203 aTag
== TRUETYPE_TAG('c', 'v', 'a', 'r') ||
204 aTag
== TRUETYPE_TAG('f', 'v', 'a', 'r') ||
205 aTag
== TRUETYPE_TAG('g', 'v', 'a', 'r') ||
206 aTag
== TRUETYPE_TAG('H', 'V', 'A', 'R') ||
207 aTag
== TRUETYPE_TAG('M', 'V', 'A', 'R') ||
208 aTag
== TRUETYPE_TAG('S', 'T', 'A', 'T') ||
209 aTag
== TRUETYPE_TAG('V', 'V', 'A', 'R'))) ||
210 aTag
== TRUETYPE_TAG('S', 'V', 'G', ' ') ||
211 aTag
== TRUETYPE_TAG('C', 'O', 'L', 'R') ||
212 aTag
== TRUETYPE_TAG('C', 'P', 'A', 'L') ||
213 (mKeepColorBitmaps
&&
214 (aTag
== TRUETYPE_TAG('C', 'B', 'D', 'T') ||
215 aTag
== TRUETYPE_TAG('C', 'B', 'L', 'C'))) ||
217 return ots::TABLE_ACTION_PASSTHRU
;
219 return ots::TABLE_ACTION_DEFAULT
;
222 virtual void Message(int level
, const char* format
,
223 ...) MSGFUNC_FMT_ATTR override
{
225 va_start(va
, format
);
228 msg
.AppendPrintf(format
, va
);
233 // For warnings (rather than errors that cause the font to fail),
234 // we only report the first instance of any given message.
235 if (mWarningsIssued
.Contains(msg
)) {
238 mWarningsIssued
.PutEntry(msg
);
241 mUserFontEntry
->mFontSet
->LogMessage(mUserFontEntry
, msg
.get());
245 gfxUserFontEntry
* mUserFontEntry
;
246 nsTHashtable
<nsCStringHashKey
> mWarningsIssued
;
247 bool mCheckOTLTables
;
248 bool mCheckVariationTables
;
249 bool mKeepColorBitmaps
;
252 // Call the OTS library to sanitize an sfnt before attempting to use it.
253 // Returns a newly-allocated block, or nullptr in case of fatal errors.
255 gfxUserFontEntry::SanitizeOpenTypeData(const uint8_t* aData
,
257 uint32_t& aSaneLength
,
258 gfxUserFontType aFontType
)
260 if (aFontType
== GFX_USERFONT_UNKNOWN
) {
265 uint32_t lengthHint
= aLength
;
266 if (aFontType
== GFX_USERFONT_WOFF
) {
268 } else if (aFontType
== GFX_USERFONT_WOFF2
) {
272 // limit output/expansion to 256MB
273 ExpandingMemoryStream
output(lengthHint
, 1024 * 1024 * 256);
275 gfxOTSContext
otsContext(this);
276 if (!otsContext
.Process(&output
, aData
, aLength
)) {
277 // Failed to decode/sanitize the font, so discard it.
282 aSaneLength
= output
.Tell();
283 return static_cast<const uint8_t*>(output
.forget());
287 gfxUserFontEntry::StoreUserFontData(gfxFontEntry
* aFontEntry
,
289 const nsACString
& aOriginalName
,
290 FallibleTArray
<uint8_t>* aMetadata
,
291 uint32_t aMetaOrigLen
,
292 uint8_t aCompression
)
294 if (!aFontEntry
->mUserFontData
) {
295 aFontEntry
->mUserFontData
= MakeUnique
<gfxUserFontData
>();
297 gfxUserFontData
* userFontData
= aFontEntry
->mUserFontData
.get();
298 userFontData
->mSrcIndex
= mSrcIndex
;
299 const gfxFontFaceSrc
& src
= mSrcList
[mSrcIndex
];
300 switch (src
.mSourceType
) {
301 case gfxFontFaceSrc::eSourceType_Local
:
302 userFontData
->mLocalName
= src
.mLocalName
;
304 case gfxFontFaceSrc::eSourceType_URL
:
305 userFontData
->mURI
= src
.mURI
;
306 userFontData
->mPrincipal
= mPrincipal
;
308 case gfxFontFaceSrc::eSourceType_Buffer
:
309 userFontData
->mIsBuffer
= true;
312 userFontData
->mPrivate
= aPrivate
;
313 userFontData
->mFormat
= src
.mFormatFlags
;
314 userFontData
->mRealName
= aOriginalName
;
316 userFontData
->mMetadata
.SwapElements(*aMetadata
);
317 userFontData
->mMetaOrigLen
= aMetaOrigLen
;
318 userFontData
->mCompression
= aCompression
;
323 gfxUserFontData::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf
) const
325 return aMallocSizeOf(this)
326 + mMetadata
.ShallowSizeOfExcludingThis(aMallocSizeOf
)
327 + mLocalName
.SizeOfExcludingThisIfUnshared(aMallocSizeOf
)
328 + mRealName
.SizeOfExcludingThisIfUnshared(aMallocSizeOf
);
329 // Not counting mURI and mPrincipal, as those will be shared.
333 gfxUserFontFamily::~gfxUserFontFamily()
335 // Should not be dropped by stylo
336 MOZ_ASSERT(NS_IsMainThread());
340 gfxFontFaceSrc::LoadPrincipal(const gfxUserFontSet
& aFontSet
) const
342 MOZ_ASSERT(mSourceType
== eSourceType_URL
);
343 if (mUseOriginPrincipal
&& mOriginPrincipal
) {
344 return mOriginPrincipal
;
346 return aFontSet
.GetStandardFontLoadPrincipal();
350 gfxUserFontEntry::GetFamilyNameAndURIForLogging(nsACString
& aFamilyName
,
353 aFamilyName
= mFamilyName
;
356 if (mSrcIndex
== mSrcList
.Length()) {
357 aURI
.AppendLiteral("(end of source list)");
359 if (mSrcList
[mSrcIndex
].mURI
) {
360 mSrcList
[mSrcIndex
].mURI
->GetSpec(aURI
);
361 // If the source URI was very long, elide the middle of it.
362 // In principle, the byte-oriented chopping here could leave us
363 // with partial UTF-8 characters at the point where we cut it,
364 // but it really doesn't matter as this is just for logging.
365 const uint32_t kMaxURILengthForLogging
= 256;
366 // UTF-8 ellipsis, with spaces to allow additional wrap opportunities
367 // in the resulting log message
368 const char kEllipsis
[] = { ' ', '\xE2', '\x80', '\xA6', ' ' };
369 if (aURI
.Length() > kMaxURILengthForLogging
) {
370 aURI
.Replace(kMaxURILengthForLogging
/ 2,
371 aURI
.Length() - kMaxURILengthForLogging
,
372 kEllipsis
, ArrayLength(kEllipsis
));
375 aURI
.AppendLiteral("(invalid URI)");
381 AutoSwap_PRUint32 signature
;
382 AutoSwap_PRUint32 flavor
;
383 AutoSwap_PRUint32 length
;
384 AutoSwap_PRUint16 numTables
;
385 AutoSwap_PRUint16 reserved
;
386 AutoSwap_PRUint32 totalSfntSize
;
387 AutoSwap_PRUint16 majorVersion
;
388 AutoSwap_PRUint16 minorVersion
;
389 AutoSwap_PRUint32 metaOffset
;
390 AutoSwap_PRUint32 metaCompLen
;
391 AutoSwap_PRUint32 metaOrigLen
;
392 AutoSwap_PRUint32 privOffset
;
393 AutoSwap_PRUint32 privLen
;
397 AutoSwap_PRUint32 signature
;
398 AutoSwap_PRUint32 flavor
;
399 AutoSwap_PRUint32 length
;
400 AutoSwap_PRUint16 numTables
;
401 AutoSwap_PRUint16 reserved
;
402 AutoSwap_PRUint32 totalSfntSize
;
403 AutoSwap_PRUint32 totalCompressedSize
;
404 AutoSwap_PRUint16 majorVersion
;
405 AutoSwap_PRUint16 minorVersion
;
406 AutoSwap_PRUint32 metaOffset
;
407 AutoSwap_PRUint32 metaCompLen
;
408 AutoSwap_PRUint32 metaOrigLen
;
409 AutoSwap_PRUint32 privOffset
;
410 AutoSwap_PRUint32 privLen
;
413 template<typename HeaderT
>
415 CopyWOFFMetadata(const uint8_t* aFontData
,
417 FallibleTArray
<uint8_t>* aMetadata
,
418 uint32_t* aMetaOrigLen
)
420 // This function may be called with arbitrary, unvalidated "font" data
421 // from @font-face, so it needs to be careful to bounds-check, etc.,
422 // before trying to read anything.
423 // This just saves a copy of the compressed data block; it does NOT check
424 // that the block can be successfully decompressed, or that it contains
425 // well-formed/valid XML metadata.
426 if (aLength
< sizeof(HeaderT
)) {
429 const HeaderT
* woff
=
430 reinterpret_cast<const HeaderT
*>(aFontData
);
431 uint32_t metaOffset
= woff
->metaOffset
;
432 uint32_t metaCompLen
= woff
->metaCompLen
;
433 if (!metaOffset
|| !metaCompLen
|| !woff
->metaOrigLen
) {
436 if (metaOffset
>= aLength
|| metaCompLen
> aLength
- metaOffset
) {
439 if (!aMetadata
->SetLength(woff
->metaCompLen
, fallible
)) {
442 memcpy(aMetadata
->Elements(), aFontData
+ metaOffset
, metaCompLen
);
443 *aMetaOrigLen
= woff
->metaOrigLen
;
447 gfxUserFontEntry::LoadNextSrc()
449 NS_ASSERTION(mSrcIndex
< mSrcList
.Length(),
450 "already at the end of the src list for user font");
451 NS_ASSERTION((mUserFontLoadState
== STATUS_NOT_LOADED
||
452 mUserFontLoadState
== STATUS_LOAD_PENDING
||
453 mUserFontLoadState
== STATUS_LOADING
) &&
454 mFontDataLoadingState
< LOADING_FAILED
,
455 "attempting to load a font that has either completed or failed");
457 if (mUserFontLoadState
== STATUS_NOT_LOADED
) {
458 SetLoadState(STATUS_LOADING
);
459 mFontDataLoadingState
= LOADING_STARTED
;
460 mUnsupportedFormat
= false;
462 // we were already loading; move to the next source,
463 // but don't reset state - if we've already timed out,
464 // that counts against the new download
468 DoLoadNextSrc(false);
472 gfxUserFontEntry::ContinueLoad()
474 MOZ_ASSERT(mUserFontLoadState
== STATUS_LOAD_PENDING
);
475 MOZ_ASSERT(mSrcList
[mSrcIndex
].mSourceType
== gfxFontFaceSrc::eSourceType_URL
);
477 SetLoadState(STATUS_LOADING
);
479 if (LoadState() != STATUS_LOADING
) {
480 MOZ_ASSERT(mUserFontLoadState
!= STATUS_LOAD_PENDING
,
481 "Not in parallel traversal, shouldn't get LOAD_PENDING again");
482 // Loading is synchronously finished (loaded from cache or failed). We
483 // need to increment the generation so that we flush the style data to
484 // use the new loaded font face.
485 // Without parallel traversal, we would simply get the right font data
486 // after the first call to DoLoadNextSrc() in this case, so we don't need
487 // to touch the generation to trigger another restyle.
488 // XXX We may want to return synchronously in parallel traversal in those
489 // cases as well if possible, so that we don't have an additional restyle.
490 // That doesn't work currently because nsIDocument::GetDocShell (called
491 // from FontFaceSet::CheckFontLoad) dereferences a weak pointer, which is
492 // not allowed in parallel traversal.
493 IncrementGeneration();
498 IgnorePrincipal(gfxFontSrcURI
* aURI
)
500 return aURI
->InheritsSecurityContext();
504 gfxUserFontEntry::DoLoadNextSrc(bool aForceAsync
)
506 uint32_t numSrc
= mSrcList
.Length();
508 // load each src entry in turn, until a local face is found
509 // or a download begins successfully
510 while (mSrcIndex
< numSrc
) {
511 gfxFontFaceSrc
& currSrc
= mSrcList
[mSrcIndex
];
513 // src local ==> lookup and load immediately
515 if (currSrc
.mSourceType
== gfxFontFaceSrc::eSourceType_Local
) {
516 // Don't look up local fonts if the font whitelist is being used.
517 gfxPlatformFontList
* pfl
= gfxPlatformFontList::PlatformFontList();
518 gfxFontEntry
* fe
= pfl
&& pfl
->IsFontFamilyWhitelistActive() ?
520 gfxPlatform::GetPlatform()->LookupLocalFont(currSrc
.mLocalName
,
524 nsTArray
<gfxUserFontSet
*> fontSets
;
525 GetUserFontSets(fontSets
);
526 for (gfxUserFontSet
* fontSet
: fontSets
) {
527 // We need to note on each gfxUserFontSet that contains the user
528 // font entry that we used a local() rule.
529 fontSet
->SetLocalRulesUsed();
532 LOG(("userfonts (%p) [src %d] loaded local: (%s) for (%s) gen: %8.8x\n",
534 currSrc
.mLocalName
.get(),
536 uint32_t(mFontSet
->mGeneration
)));
537 fe
->mFeatureSettings
.AppendElements(mFeatureSettings
);
538 fe
->mVariationSettings
.AppendElements(mVariationSettings
);
539 fe
->mLanguageOverride
= mLanguageOverride
;
540 fe
->mFamilyName
= mFamilyName
;
541 fe
->mRangeFlags
= mRangeFlags
;
542 // For src:local(), we don't care whether the request is from
543 // a private window as there's no issue of caching resources;
544 // local fonts are just available all the time.
545 StoreUserFontData(fe
, false, nsCString(), nullptr, 0,
546 gfxUserFontData::kUnknownCompression
);
547 mPlatformFontEntry
= fe
;
548 SetLoadState(STATUS_LOADED
);
549 Telemetry::Accumulate(Telemetry::WEBFONT_SRCTYPE
,
550 currSrc
.mSourceType
+ 1);
553 LOG(("userfonts (%p) [src %d] failed local: (%s) for (%s)\n",
555 currSrc
.mLocalName
.get(),
560 // src url ==> start the load process
561 else if (currSrc
.mSourceType
== gfxFontFaceSrc::eSourceType_URL
) {
562 if (gfxPlatform::GetPlatform()->IsFontFormatSupported(
563 currSrc
.mFormatFlags
)) {
565 if (ServoStyleSet
* set
= ServoStyleSet::Current()) {
566 // Only support style worker threads synchronously getting
567 // entries from the font cache when it's not a data: URI
568 // @font-face that came from UA or user sheets, since we
569 // were not able to call IsFontLoadAllowed ahead of time
570 // for these entries.
571 if (currSrc
.mUseOriginPrincipal
&& IgnorePrincipal(currSrc
.mURI
)) {
572 set
->AppendTask(PostTraversalTask::LoadFontEntry(this));
573 SetLoadState(STATUS_LOAD_PENDING
);
578 // see if we have an existing entry for this source
580 gfxUserFontSet::UserFontCache::GetFont(currSrc
, *this);
582 mPlatformFontEntry
= fe
;
583 SetLoadState(STATUS_LOADED
);
585 LOG(("userfonts (%p) [src %d] "
586 "loaded uri from cache: (%s) for (%s)\n",
588 currSrc
.mURI
->GetSpecOrDefault().get(),
594 if (ServoStyleSet
* set
= ServoStyleSet::Current()) {
595 // If we need to start a font load and we're on a style
596 // worker thread, we have to defer it.
597 set
->AppendTask(PostTraversalTask::LoadFontEntry(this));
598 SetLoadState(STATUS_LOAD_PENDING
);
602 // record the principal we should use for the load for use when
603 // creating a channel and when caching the loaded entry.
604 mPrincipal
= currSrc
.LoadPrincipal(*mFontSet
);
606 bool loadDoesntSpin
=
607 !aForceAsync
&& currSrc
.mURI
->SyncLoadIsOK();
609 if (loadDoesntSpin
) {
610 uint8_t* buffer
= nullptr;
611 uint32_t bufferLength
= 0;
613 // sync load font immediately
614 nsresult rv
= mFontSet
->SyncLoadFontData(this, &currSrc
, buffer
,
617 if (NS_SUCCEEDED(rv
) &&
618 LoadPlatformFont(buffer
, bufferLength
)) {
619 SetLoadState(STATUS_LOADED
);
620 Telemetry::Accumulate(Telemetry::WEBFONT_SRCTYPE
,
621 currSrc
.mSourceType
+ 1);
624 mFontSet
->LogMessage(this,
626 nsIScriptError::errorFlag
,
631 // otherwise load font async
632 nsresult rv
= mFontSet
->StartLoad(this, &currSrc
);
633 bool loadOK
= NS_SUCCEEDED(rv
);
637 LOG(("userfonts (%p) [src %d] loading uri: (%s) for (%s)\n",
639 currSrc
.mURI
->GetSpecOrDefault().get(),
644 mFontSet
->LogMessage(this,
646 nsIScriptError::errorFlag
,
651 // We don't log a warning to the web console yet,
652 // as another source may load successfully
653 mUnsupportedFormat
= true;
657 // FontFace buffer ==> load immediately
660 MOZ_ASSERT(currSrc
.mSourceType
== gfxFontFaceSrc::eSourceType_Buffer
);
662 uint8_t* buffer
= nullptr;
663 uint32_t bufferLength
= 0;
665 // sync load font immediately
666 currSrc
.mBuffer
->TakeBuffer(buffer
, bufferLength
);
667 if (buffer
&& LoadPlatformFont(buffer
, bufferLength
)) {
668 // LoadPlatformFont takes ownership of the buffer, so no need
670 SetLoadState(STATUS_LOADED
);
671 Telemetry::Accumulate(Telemetry::WEBFONT_SRCTYPE
,
672 currSrc
.mSourceType
+ 1);
675 mFontSet
->LogMessage(this,
677 nsIScriptError::errorFlag
);
684 if (mUnsupportedFormat
) {
685 mFontSet
->LogMessage(this, "no supported format found",
686 nsIScriptError::warningFlag
);
689 // all src's failed; mark this entry as unusable (so fallback will occur)
690 LOG(("userfonts (%p) failed all src for (%s)\n",
691 mFontSet
, mFamilyName
.get()));
692 mFontDataLoadingState
= LOADING_FAILED
;
693 SetLoadState(STATUS_FAILED
);
697 gfxUserFontEntry::SetLoadState(UserFontLoadState aLoadState
)
699 mUserFontLoadState
= aLoadState
;
702 MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(UserFontMallocSizeOfOnAlloc
)
705 gfxUserFontEntry::LoadPlatformFont(const uint8_t* aFontData
, uint32_t& aLength
)
707 AUTO_PROFILER_LABEL("gfxUserFontEntry::LoadPlatformFont", OTHER
);
708 NS_ASSERTION((mUserFontLoadState
== STATUS_NOT_LOADED
||
709 mUserFontLoadState
== STATUS_LOAD_PENDING
||
710 mUserFontLoadState
== STATUS_LOADING
) &&
711 mFontDataLoadingState
< LOADING_FAILED
,
712 "attempting to load a font that has either completed or failed");
714 gfxFontEntry
* fe
= nullptr;
716 gfxUserFontType fontType
=
717 gfxFontUtils::DetermineFontDataType(aFontData
, aLength
);
718 Telemetry::Accumulate(Telemetry::WEBFONT_FONTTYPE
, uint32_t(fontType
));
720 // Unwrap/decompress/sanitize or otherwise munge the downloaded data
721 // to make a usable sfnt structure.
723 // Because platform font activation code may replace the name table
724 // in the font with a synthetic one, we save the original name so that
725 // it can be reported via the InspectorUtils API.
726 nsAutoCString originalFullName
;
728 // Call the OTS sanitizer; this will also decode WOFF to sfnt
729 // if necessary. The original data in aFontData is left unchanged.
731 uint32_t fontCompressionRatio
= 0;
732 size_t computedSize
= 0;
733 const uint8_t* saneData
=
734 SanitizeOpenTypeData(aFontData
, aLength
, saneLen
, fontType
);
736 mFontSet
->LogMessage(this, "rejected by sanitizer");
738 // Check whether saneData is a known OpenType format; it might be
739 // a TrueType Collection, which OTS would accept but we don't yet
740 // know how to handle. If so, discard.
741 if (gfxFontUtils::DetermineFontDataType(saneData
, saneLen
) !=
742 GFX_USERFONT_OPENTYPE
) {
743 mFontSet
->LogMessage(this, "not a supported OpenType format");
744 free((void*)saneData
);
750 fontCompressionRatio
= uint32_t(100.0 * aLength
/ saneLen
+ 0.5);
751 if (fontType
== GFX_USERFONT_WOFF
||
752 fontType
== GFX_USERFONT_WOFF2
) {
753 Telemetry::Accumulate(fontType
== GFX_USERFONT_WOFF
?
754 Telemetry::WEBFONT_COMPRESSION_WOFF
:
755 Telemetry::WEBFONT_COMPRESSION_WOFF2
,
756 fontCompressionRatio
);
760 // The sanitizer ensures that we have a valid sfnt and a usable
761 // name table, so this should never fail unless we're out of
762 // memory, and GetFullNameFromSFNT is not directly exposed to
763 // arbitrary/malicious data from the web.
764 gfxFontUtils::GetFullNameFromSFNT(saneData
, saneLen
,
767 // Record size for memory reporting purposes. We measure this now
768 // because by the time we potentially want to collect reports, this
769 // data block may have been handed off to opaque OS font APIs that
770 // don't allow us to retrieve or measure it directly.
771 // The *OnAlloc function will also tell DMD about this block, as the
772 // OS font code may hold on to it for an extended period.
773 computedSize
= UserFontMallocSizeOfOnAlloc(saneData
);
775 // Here ownership of saneData is passed to the platform,
776 // which will delete it when no longer required
777 fe
= gfxPlatform::GetPlatform()->MakePlatformFont(mName
,
784 mFontSet
->LogMessage(this, "not usable by platform");
789 fe
->mComputedSizeOfUserFont
= computedSize
;
791 // Save a copy of the metadata block (if present) for InspectorUtils
792 // to use if required. Ownership of the metadata block will be passed
793 // to the gfxUserFontData record below.
794 FallibleTArray
<uint8_t> metadata
;
795 uint32_t metaOrigLen
= 0;
796 uint8_t compression
= gfxUserFontData::kUnknownCompression
;
797 if (fontType
== GFX_USERFONT_WOFF
) {
798 CopyWOFFMetadata
<WOFFHeader
>(aFontData
, aLength
,
799 &metadata
, &metaOrigLen
);
800 compression
= gfxUserFontData::kZlibCompression
;
801 } else if (fontType
== GFX_USERFONT_WOFF2
) {
802 CopyWOFFMetadata
<WOFF2Header
>(aFontData
, aLength
,
803 &metadata
, &metaOrigLen
);
804 compression
= gfxUserFontData::kBrotliCompression
;
807 // copy OpenType feature/language settings from the userfont entry to the
808 // newly-created font entry
809 fe
->mFeatureSettings
.AppendElements(mFeatureSettings
);
810 fe
->mVariationSettings
.AppendElements(mVariationSettings
);
811 fe
->mLanguageOverride
= mLanguageOverride
;
812 fe
->mFamilyName
= mFamilyName
;
813 fe
->mRangeFlags
= mRangeFlags
;
814 StoreUserFontData(fe
, mFontSet
->GetPrivateBrowsing(), originalFullName
,
815 &metadata
, metaOrigLen
, compression
);
817 LOG(("userfonts (%p) [src %d] loaded uri: (%s) for (%s) "
818 "(%p) gen: %8.8x compress: %d%%\n",
820 mSrcList
[mSrcIndex
].mURI
->GetSpecOrDefault().get(),
822 this, uint32_t(mFontSet
->mGeneration
), fontCompressionRatio
));
824 mPlatformFontEntry
= fe
;
825 SetLoadState(STATUS_LOADED
);
826 gfxUserFontSet::UserFontCache::CacheFont(fe
);
829 LOG(("userfonts (%p) [src %d] failed uri: (%s) for (%s)"
830 " error making platform font\n",
832 mSrcList
[mSrcIndex
].mURI
->GetSpecOrDefault().get(),
837 // The downloaded data can now be discarded; the font entry is using the
839 free((void*)aFontData
);
841 return fe
!= nullptr;
845 gfxUserFontEntry::Load()
847 if (mUserFontLoadState
== STATUS_NOT_LOADED
) {
853 gfxUserFontEntry::IncrementGeneration()
855 nsTArray
<gfxUserFontSet
*> fontSets
;
856 GetUserFontSets(fontSets
);
857 for (gfxUserFontSet
* fontSet
: fontSets
) {
858 fontSet
->IncrementGeneration();
862 // This is called when a font download finishes.
863 // Ownership of aFontData passes in here, and the font set must
864 // ensure that it is eventually deleted via free().
866 gfxUserFontEntry::FontDataDownloadComplete(const uint8_t* aFontData
,
868 nsresult aDownloadStatus
)
870 // forget about the loader, as we no longer potentially need to cancel it
871 // if the entry is obsoleted
874 // download successful, make platform font using font data
875 if (NS_SUCCEEDED(aDownloadStatus
) &&
876 mFontDataLoadingState
!= LOADING_TIMED_OUT
) {
877 bool loaded
= LoadPlatformFont(aFontData
, aLength
);
881 IncrementGeneration();
887 mFontSet
->LogMessage(this,
888 (mFontDataLoadingState
!= LOADING_TIMED_OUT
?
889 "download failed" : "download timed out"),
890 nsIScriptError::errorFlag
,
895 free((void*)aFontData
);
898 // Error occurred. Make sure the FontFace's promise is rejected if the
899 // load timed out, or else load the next src.
900 if (mFontDataLoadingState
== LOADING_TIMED_OUT
) {
901 mFontDataLoadingState
= LOADING_FAILED
;
902 SetLoadState(STATUS_FAILED
);
907 // We ignore the status returned by LoadNext();
908 // even if loading failed, we need to bump the font-set generation
909 // and return true in order to trigger reflow, so that fallback
910 // will be used where the text was "masked" by the pending download
911 IncrementGeneration();
916 gfxUserFontEntry::GetUserFontSets(nsTArray
<gfxUserFontSet
*>& aResult
)
919 aResult
.AppendElement(mFontSet
);
922 gfxUserFontSet::gfxUserFontSet()
924 mRebuildGeneration(0),
925 mLocalRulesUsed(false),
926 mRebuildLocalRules(false),
930 IncrementGeneration(true);
931 gfxPlatformFontList
* fp
= gfxPlatformFontList::PlatformFontList();
933 fp
->AddUserFontSet(this);
937 gfxUserFontSet::~gfxUserFontSet()
939 gfxPlatformFontList
* fp
= gfxPlatformFontList::PlatformFontList();
941 fp
->RemoveUserFontSet(this);
945 already_AddRefed
<gfxUserFontEntry
>
946 gfxUserFontSet::FindOrCreateUserFontEntry(
947 const nsACString
& aFamilyName
,
948 const nsTArray
<gfxFontFaceSrc
>& aFontFaceSrcList
,
950 StretchRange aStretch
,
951 SlantStyleRange aStyle
,
952 const nsTArray
<gfxFontFeature
>& aFeatureSettings
,
953 const nsTArray
<gfxFontVariation
>& aVariationSettings
,
954 uint32_t aLanguageOverride
,
955 gfxCharacterMap
* aUnicodeRanges
,
956 uint8_t aFontDisplay
,
957 RangeFlags aRangeFlags
)
959 RefPtr
<gfxUserFontEntry
> entry
;
961 // If there's already a userfont entry in the family whose descriptors all match,
962 // we can just move it to the end of the list instead of adding a new
963 // face that will always "shadow" the old one.
964 // Note that we can't do this for platform font entries, even if the
965 // style descriptors match, as they might have had a different source list,
966 // but we no longer have the old source list available to check.
967 gfxUserFontFamily
* family
= LookupFamily(aFamilyName
);
969 entry
= FindExistingUserFontEntry(family
, aFontFaceSrcList
, aWeight
,
971 aFeatureSettings
, aVariationSettings
,
973 aUnicodeRanges
, aFontDisplay
,
978 entry
= CreateUserFontEntry(aFontFaceSrcList
, aWeight
, aStretch
,
979 aStyle
, aFeatureSettings
, aVariationSettings
,
980 aLanguageOverride
, aUnicodeRanges
,
981 aFontDisplay
, aRangeFlags
);
982 entry
->mFamilyName
= aFamilyName
;
985 return entry
.forget();
989 gfxUserFontSet::FindExistingUserFontEntry(
990 gfxUserFontFamily
* aFamily
,
991 const nsTArray
<gfxFontFaceSrc
>& aFontFaceSrcList
,
993 StretchRange aStretch
,
994 SlantStyleRange aStyle
,
995 const nsTArray
<gfxFontFeature
>& aFeatureSettings
,
996 const nsTArray
<gfxFontVariation
>& aVariationSettings
,
997 uint32_t aLanguageOverride
,
998 gfxCharacterMap
* aUnicodeRanges
,
999 uint8_t aFontDisplay
,
1000 RangeFlags aRangeFlags
)
1002 nsTArray
<RefPtr
<gfxFontEntry
>>& fontList
= aFamily
->GetFontList();
1004 for (size_t i
= 0, count
= fontList
.Length(); i
< count
; i
++) {
1005 if (!fontList
[i
]->mIsUserFontContainer
) {
1009 gfxUserFontEntry
* existingUserFontEntry
=
1010 static_cast<gfxUserFontEntry
*>(fontList
[i
].get());
1011 if (!existingUserFontEntry
->Matches(aFontFaceSrcList
,
1012 aWeight
, aStretch
, aStyle
,
1013 aFeatureSettings
, aVariationSettings
,
1015 aUnicodeRanges
, aFontDisplay
,
1020 return existingUserFontEntry
;
1027 gfxUserFontSet::AddUserFontEntry(const nsCString
& aFamilyName
,
1028 gfxUserFontEntry
* aUserFontEntry
)
1030 gfxUserFontFamily
* family
= GetFamily(aFamilyName
);
1031 family
->AddFontEntry(aUserFontEntry
);
1033 if (LOG_ENABLED()) {
1034 nsAutoCString weightString
;
1035 aUserFontEntry
->Weight().ToString(weightString
);
1036 nsAutoCString stretchString
;
1037 aUserFontEntry
->Stretch().ToString(stretchString
);
1038 LOG(("userfonts (%p) added to \"%s\" (%p) style: %s weight: %s "
1039 "stretch: %s display: %d",
1040 this, aFamilyName
.get(), aUserFontEntry
,
1041 (aUserFontEntry
->IsItalic() ? "italic" :
1042 (aUserFontEntry
->IsOblique() ? "oblique" : "normal")),
1044 stretchString
.get(),
1045 aUserFontEntry
->GetFontDisplay()));
1050 gfxUserFontSet::IncrementGeneration(bool aIsRebuild
)
1052 // add one, increment again if zero
1053 ++sFontSetGeneration
;
1054 if (sFontSetGeneration
== 0)
1055 ++sFontSetGeneration
;
1056 mGeneration
= sFontSetGeneration
;
1058 mRebuildGeneration
= mGeneration
;
1063 gfxUserFontSet::RebuildLocalRules()
1065 if (mLocalRulesUsed
) {
1066 mRebuildLocalRules
= true;
1067 DoRebuildUserFontSet();
1072 gfxUserFontSet::LookupFamily(const nsACString
& aFamilyName
) const
1074 nsAutoCString
key(aFamilyName
);
1077 return mFontFamilies
.GetWeak(key
);
1081 gfxUserFontSet::ContainsUserFontSetFonts(const FontFamilyList
& aFontList
) const
1083 for (const FontFamilyName
& name
: aFontList
.GetFontlist()->mNames
) {
1084 if (!name
.IsNamed()) {
1087 if (LookupFamily(nsAtomCString(name
.mName
))) {
1095 gfxUserFontSet::GetFamily(const nsACString
& aFamilyName
)
1097 nsAutoCString
key(aFamilyName
);
1100 gfxUserFontFamily
* family
= mFontFamilies
.GetWeak(key
);
1102 family
= new gfxUserFontFamily(aFamilyName
);
1103 mFontFamilies
.Put(key
, family
);
1108 ///////////////////////////////////////////////////////////////////////////////
1109 // gfxUserFontSet::UserFontCache - re-use platform font entries for user fonts
1110 // across pages/fontsets rather than instantiating new platform fonts.
1112 // Entries are added to this cache when a platform font is instantiated from
1113 // downloaded data, and removed when the platform font entry is destroyed.
1114 // We don't need to use a timed expiration scheme here because the gfxFontEntry
1115 // for a downloaded font will be kept alive by its corresponding gfxFont
1116 // instance(s) until they are deleted, and *that* happens using an expiration
1117 // tracker (gfxFontCache). The result is that the downloaded font instances
1118 // recorded here will persist between pages and can get reused (provided the
1119 // source URI and principal match, of course).
1120 ///////////////////////////////////////////////////////////////////////////////
1122 nsTHashtable
<gfxUserFontSet::UserFontCache::Entry
>*
1123 gfxUserFontSet::UserFontCache::sUserFonts
= nullptr;
1125 NS_IMPL_ISUPPORTS(gfxUserFontSet::UserFontCache::Flusher
, nsIObserver
)
1128 gfxUserFontSet::UserFontCache::Flusher::Observe(nsISupports
* aSubject
,
1130 const char16_t
* aData
)
1136 if (!strcmp(aTopic
, "cacheservice:empty-cache")) {
1137 for (auto i
= sUserFonts
->Iter(); !i
.Done(); i
.Next()) {
1140 } else if (!strcmp(aTopic
, "last-pb-context-exited")) {
1141 for (auto i
= sUserFonts
->Iter(); !i
.Done(); i
.Next()) {
1142 if (i
.Get()->IsPrivate()) {
1146 } else if (!strcmp(aTopic
, "xpcom-shutdown")) {
1147 for (auto i
= sUserFonts
->Iter(); !i
.Done(); i
.Next()) {
1148 i
.Get()->GetFontEntry()->DisconnectSVG();
1151 MOZ_ASSERT_UNREACHABLE("unexpected topic");
1158 gfxUserFontSet::UserFontCache::Entry::KeyEquals(const KeyTypePointer aKey
) const
1160 const gfxFontEntry
* fe
= aKey
->mFontEntry
;
1162 if (!mURI
->Equals(aKey
->mURI
)) {
1166 // For data: URIs, we don't care about the principal; otherwise, check it.
1167 if (!IgnorePrincipal(mURI
)) {
1168 NS_ASSERTION(mPrincipal
&& aKey
->mPrincipal
,
1169 "only data: URIs are allowed to omit the principal");
1170 if (!mPrincipal
->Equals(aKey
->mPrincipal
)) {
1175 if (mPrivate
!= aKey
->mPrivate
) {
1179 if (mFontEntry
->SlantStyle() != fe
->SlantStyle() ||
1180 mFontEntry
->Weight() != fe
->Weight() ||
1181 mFontEntry
->Stretch() != fe
->Stretch() ||
1182 mFontEntry
->mFeatureSettings
!= fe
->mFeatureSettings
||
1183 mFontEntry
->mVariationSettings
!= fe
->mVariationSettings
||
1184 mFontEntry
->mLanguageOverride
!= fe
->mLanguageOverride
||
1185 mFontEntry
->mFamilyName
!= fe
->mFamilyName
) {
1193 gfxUserFontSet::UserFontCache::CacheFont(gfxFontEntry
* aFontEntry
)
1195 NS_ASSERTION(aFontEntry
->mFamilyName
.Length() != 0,
1196 "caching a font associated with no family yet");
1198 // if caching is disabled, simply return
1199 if (Preferences::GetBool("gfx.downloadable_fonts.disable_cache")) {
1203 gfxUserFontData
* data
= aFontEntry
->mUserFontData
.get();
1204 if (data
->mIsBuffer
) {
1205 #ifdef DEBUG_USERFONT_CACHE
1206 printf("userfontcache skipped fontentry with buffer source: %p\n",
1213 sUserFonts
= new nsTHashtable
<Entry
>;
1215 nsCOMPtr
<nsIObserverService
> obs
=
1216 mozilla::services::GetObserverService();
1218 Flusher
* flusher
= new Flusher
;
1219 obs
->AddObserver(flusher
, "cacheservice:empty-cache",
1221 obs
->AddObserver(flusher
, "last-pb-context-exited", false);
1222 obs
->AddObserver(flusher
, "xpcom-shutdown", false);
1225 // Create and register a memory reporter for sUserFonts.
1226 // This reporter is never unregistered, but that's OK because
1227 // the reporter checks whether sUserFonts is null, so it would
1228 // be safe to call even after UserFontCache::Shutdown has deleted
1230 RegisterStrongMemoryReporter(new MemoryReporter());
1233 // For data: URIs, the principal is ignored; anyone who has the same
1234 // data: URI is able to load it and get an equivalent font.
1235 // Otherwise, the principal is used as part of the cache key.
1236 gfxFontSrcPrincipal
* principal
;
1237 if (IgnorePrincipal(data
->mURI
)) {
1238 principal
= nullptr;
1240 principal
= data
->mPrincipal
;
1242 sUserFonts
->PutEntry(Key(data
->mURI
, principal
, aFontEntry
,
1245 #ifdef DEBUG_USERFONT_CACHE
1246 printf("userfontcache added fontentry: %p\n", aFontEntry
);
1252 gfxUserFontSet::UserFontCache::ForgetFont(gfxFontEntry
* aFontEntry
)
1255 // if we've already deleted the cache (i.e. during shutdown),
1260 // We can't simply use RemoveEntry here because it's possible the principal
1261 // may have changed since the font was cached, in which case the lookup
1262 // would no longer find the entry (bug 838105).
1263 for (auto i
= sUserFonts
->Iter(); !i
.Done(); i
.Next()) {
1264 if (i
.Get()->GetFontEntry() == aFontEntry
) {
1269 #ifdef DEBUG_USERFONT_CACHE
1270 printf("userfontcache removed fontentry: %p\n", aFontEntry
);
1276 gfxUserFontSet::UserFontCache::GetFont(const gfxFontFaceSrc
& aSrc
,
1277 const gfxUserFontEntry
& aUserFontEntry
)
1280 aUserFontEntry
.mFontSet
->BypassCache() ||
1281 Preferences::GetBool("gfx.downloadable_fonts.disable_cache")) {
1285 // Ignore principal when looking up a data: URI.
1286 gfxFontSrcPrincipal
* principal
= IgnorePrincipal(aSrc
.mURI
)
1288 : aSrc
.LoadPrincipal(*aUserFontEntry
.mFontSet
);
1290 Entry
* entry
= sUserFonts
->GetEntry(
1293 const_cast<gfxUserFontEntry
*>(&aUserFontEntry
),
1294 aUserFontEntry
.mFontSet
->GetPrivateBrowsing()));
1299 // We have to perform another content policy check here to prevent
1300 // cache poisoning. E.g. a.com loads a font into the cache but
1301 // b.com has a CSP not allowing any fonts to be loaded.
1302 if (!aUserFontEntry
.mFontSet
->IsFontLoadAllowed(aSrc
)) {
1306 return entry
->GetFontEntry();
1310 gfxUserFontSet::UserFontCache::Shutdown()
1314 sUserFonts
= nullptr;
1318 MOZ_DEFINE_MALLOC_SIZE_OF(UserFontsMallocSizeOf
)
1321 gfxUserFontSet::UserFontCache::Entry::ReportMemory(
1322 nsIHandleReportCallback
* aHandleReport
, nsISupports
* aData
, bool aAnonymize
)
1324 MOZ_ASSERT(mFontEntry
);
1325 nsAutoCString
path("explicit/gfx/user-fonts/font(");
1328 path
.AppendPrintf("<anonymized-%p>", this);
1330 path
.AppendPrintf("family=%s", mFontEntry
->mFamilyName
.get());
1332 nsCString spec
= mURI
->GetSpecOrDefault();
1333 spec
.ReplaceChar('/', '\\');
1334 // Some fonts are loaded using horrendously-long data: URIs;
1335 // truncate those before reporting them.
1337 if (NS_SUCCEEDED(mURI
->get()->SchemeIs("data", &isData
)) && isData
&&
1338 spec
.Length() > 255) {
1340 spec
.AppendLiteral("...");
1342 path
.AppendPrintf(", url=%s", spec
.get());
1345 nsCOMPtr
<nsIURI
> uri
;
1346 mPrincipal
->get()->GetURI(getter_AddRefs(uri
));
1348 nsCString spec
= uri
->GetSpecOrDefault();
1349 if (!spec
.IsEmpty()) {
1350 // Include a clue as to who loaded this resource. (Note
1351 // that because of font entry sharing, other pages may now
1352 // be using this resource, and the original page may not
1353 // even be loaded any longer.)
1354 spec
.ReplaceChar('/', '\\');
1355 path
.AppendPrintf(", principal=%s", spec
.get());
1362 aHandleReport
->Callback(
1363 EmptyCString(), path
,
1364 nsIMemoryReporter::KIND_HEAP
, nsIMemoryReporter::UNITS_BYTES
,
1365 mFontEntry
->ComputedSizeOfExcludingThis(UserFontsMallocSizeOf
),
1366 NS_LITERAL_CSTRING("Memory used by @font-face resource."),
1370 NS_IMPL_ISUPPORTS(gfxUserFontSet::UserFontCache::MemoryReporter
,
1374 gfxUserFontSet::UserFontCache::MemoryReporter::CollectReports(
1375 nsIHandleReportCallback
* aHandleReport
, nsISupports
* aData
, bool aAnonymize
)
1381 for (auto it
= sUserFonts
->Iter(); !it
.Done(); it
.Next()) {
1382 it
.Get()->ReportMemory(aHandleReport
, aData
, aAnonymize
);
1386 "explicit/gfx/user-fonts/cache-overhead", KIND_HEAP
, UNITS_BYTES
,
1387 sUserFonts
->ShallowSizeOfIncludingThis(UserFontsMallocSizeOf
),
1388 "Memory used by the @font-face cache, not counting the actual font "
1394 #ifdef DEBUG_USERFONT_CACHE
1397 gfxUserFontSet::UserFontCache::Entry::Dump()
1401 nsAutoCString
principalURISpec("(null)");
1402 bool setDomain
= false;
1405 nsCOMPtr
<nsIURI
> principalURI
;
1406 rv
= mPrincipal
->get()->GetURI(getter_AddRefs(principalURI
));
1407 if (NS_SUCCEEDED(rv
)) {
1408 principalURI
->GetSpec(principalURISpec
);
1411 nsCOMPtr
<nsIURI
> domainURI
;
1412 mPrincipal
->get()->GetDomain(getter_AddRefs(domainURI
));
1418 NS_ASSERTION(mURI
, "null URI in userfont cache entry");
1420 printf("userfontcache fontEntry: %p fonturihash: %8.8x "
1421 "family: %s domainset: %s principal: [%s]\n",
1424 mFontEntry
->FamilyName().get(),
1425 setDomain
? "true" : "false",
1426 principalURISpec
.get());
1430 gfxUserFontSet::UserFontCache::Dump()
1436 printf("userfontcache dump count: %d ========\n", sUserFonts
->Count());
1437 for (auto it
= sUserFonts
->Iter(); !it
.Done(); it
.Next()) {
1440 printf("userfontcache dump ==================\n");