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 #ifndef GFX_USER_FONT_SET_H
7 #define GFX_USER_FONT_SET_H
10 #include "nsRefPtrHashtable.h"
11 #include "nsAutoPtr.h"
14 #include "nsIPrincipal.h"
15 #include "nsIScriptError.h"
16 #include "nsURIHashKey.h"
18 class nsFontFaceLoader
;
20 //#define DEBUG_USERFONT_CACHE
22 // parsed CSS @font-face rule information
23 // lifetime: from when @font-face rule processed until font is loaded
24 struct gfxFontFaceSrc
{
25 bool mIsLocal
; // url or local
27 // if url, whether to use the origin principal or not
28 bool mUseOriginPrincipal
;
30 // format hint flags, union of all possible formats
31 // (e.g. TrueType, EOT, SVG, etc.)
32 // see FLAG_FORMAT_* enum values below
33 uint32_t mFormatFlags
;
35 nsString mLocalName
; // full font name if local
36 nsCOMPtr
<nsIURI
> mURI
; // uri if url
37 nsCOMPtr
<nsIURI
> mReferrer
; // referrer url if url
38 nsCOMPtr
<nsIPrincipal
> mOriginPrincipal
; // principal if url
42 operator==(const gfxFontFaceSrc
& a
, const gfxFontFaceSrc
& b
)
45 return (a
.mIsLocal
&& b
.mIsLocal
&&
46 a
.mLocalName
== b
.mLocalName
) ||
47 (!a
.mIsLocal
&& !b
.mIsLocal
&&
48 a
.mUseOriginPrincipal
== b
.mUseOriginPrincipal
&&
49 a
.mFormatFlags
== b
.mFormatFlags
&&
50 NS_SUCCEEDED(a
.mURI
->Equals(b
.mURI
, &equals
)) && equals
&&
51 NS_SUCCEEDED(a
.mReferrer
->Equals(b
.mReferrer
, &equals
)) && equals
&&
52 a
.mOriginPrincipal
->Equals(b
.mOriginPrincipal
));
55 // Subclassed to store platform-specific code cleaned out when font entry is
57 // Lifetime: from when platform font is created until it is deactivated.
58 // If the platform does not need to add any platform-specific code/data here,
59 // then the gfxUserFontSet will allocate a base gfxUserFontData and attach
60 // to the entry to track the basic user font info fields here.
61 class gfxUserFontData
{
64 : mSrcIndex(0), mFormat(0), mMetaOrigLen(0),
65 mCRC32(0), mLength(0), mPrivate(false)
67 virtual ~gfxUserFontData() { }
69 nsTArray
<uint8_t> mMetadata
; // woff metadata block (compressed), if any
70 nsCOMPtr
<nsIURI
> mURI
; // URI of the source, if it was url()
71 nsCOMPtr
<nsIPrincipal
> mPrincipal
; // principal for the download, if url()
72 nsString mLocalName
; // font name used for the source, if local()
73 nsString mRealName
; // original fullname from the font resource
74 uint32_t mSrcIndex
; // index in the rule's source list
75 uint32_t mFormat
; // format hint for the source used, if any
76 uint32_t mMetaOrigLen
; // length needed to decompress metadata
77 uint32_t mCRC32
; // Checksum
78 uint32_t mLength
; // Font length
79 bool mPrivate
; // whether font belongs to a private window
82 // initially contains a set of proxy font entry objects, replaced with
83 // platform/user fonts as downloaded
85 class gfxMixedFontFamily
: public gfxFontFamily
{
87 friend class gfxUserFontSet
;
89 explicit gfxMixedFontFamily(const nsAString
& aName
)
90 : gfxFontFamily(aName
) { }
92 virtual ~gfxMixedFontFamily() { }
94 // Add the given font entry to the end of the family's list.
95 // Any earlier occurrence is removed, so this has the effect of "advancing"
96 // the entry to the end of the list.
97 void AddFontEntry(gfxFontEntry
*aFontEntry
) {
98 // We append to mAvailableFonts -before- searching for and removing
99 // any existing reference to avoid the risk that we'll remove the last
100 // reference to the font entry, and thus delete it.
101 mAvailableFonts
.AppendElement(aFontEntry
);
102 uint32_t i
= mAvailableFonts
.Length() - 1;
104 if (mAvailableFonts
[--i
] == aFontEntry
) {
105 mAvailableFonts
.RemoveElementAt(i
);
109 if (aFontEntry
->mFamilyName
.IsEmpty()) {
110 aFontEntry
->mFamilyName
= Name();
113 nsString thisName
= Name();
114 nsString entryName
= aFontEntry
->mFamilyName
;
115 ToLowerCase(thisName
);
116 ToLowerCase(entryName
);
117 MOZ_ASSERT(thisName
.Equals(entryName
));
123 // Replace aProxyFontEntry in the family's list with aRealFontEntry.
124 void ReplaceFontEntry(gfxFontEntry
*aProxyFontEntry
,
125 gfxFontEntry
*aRealFontEntry
) {
126 uint32_t numFonts
= mAvailableFonts
.Length();
128 for (i
= 0; i
< numFonts
; i
++) {
129 gfxFontEntry
*fe
= mAvailableFonts
[i
];
130 if (fe
== aProxyFontEntry
) {
131 // Note that this may delete aProxyFontEntry, if there's no
132 // other reference to it except from its family.
133 mAvailableFonts
[i
] = aRealFontEntry
;
134 if (aRealFontEntry
->mFamilyName
.IsEmpty()) {
135 aRealFontEntry
->mFamilyName
= Name();
138 nsString thisName
= Name();
139 nsString entryName
= aRealFontEntry
->mFamilyName
;
140 ToLowerCase(thisName
);
141 ToLowerCase(entryName
);
142 MOZ_ASSERT(thisName
.Equals(entryName
));
148 NS_ASSERTION(i
< numFonts
, "font entry not found in family!");
152 // Remove all font entries from the family
153 void DetachFontEntries() {
154 mAvailableFonts
.Clear();
158 class gfxProxyFontEntry
;
161 class gfxUserFontSet
{
162 friend class gfxProxyFontEntry
;
163 friend class gfxOTSContext
;
167 NS_INLINE_DECL_REFCOUNTING(gfxUserFontSet
)
172 // no flags ==> no hint set
173 // unknown ==> unknown format hint set
174 FLAG_FORMAT_UNKNOWN
= 1,
175 FLAG_FORMAT_OPENTYPE
= 1 << 1,
176 FLAG_FORMAT_TRUETYPE
= 1 << 2,
177 FLAG_FORMAT_TRUETYPE_AAT
= 1 << 3,
178 FLAG_FORMAT_EOT
= 1 << 4,
179 FLAG_FORMAT_SVG
= 1 << 5,
180 FLAG_FORMAT_WOFF
= 1 << 6,
182 // mask of all unused bits, update when adding new formats
183 FLAG_FORMAT_NOT_USED
= ~((1 << 7)-1)
187 // creates a font face without adding it to a particular family
188 // weight - [100, 900] (multiples of 100)
189 // stretch = [NS_FONT_STRETCH_ULTRA_CONDENSED, NS_FONT_STRETCH_ULTRA_EXPANDED]
190 // italic style = constants in gfxFontConstants.h, e.g. NS_FONT_STYLE_NORMAL
191 // language override = result of calling gfxFontStyle::ParseFontLanguageOverride
192 // TODO: support for unicode ranges not yet implemented
193 already_AddRefed
<gfxProxyFontEntry
> CreateFontFace(
194 const nsTArray
<gfxFontFaceSrc
>& aFontFaceSrcList
,
197 uint32_t aItalicStyle
,
198 const nsTArray
<gfxFontFeature
>& aFeatureSettings
,
199 uint32_t aLanguageOverride
,
200 gfxSparseBitSet
* aUnicodeRanges
);
202 // creates a font face for the specified family, or returns an existing
203 // matching entry on the family if there is one
204 already_AddRefed
<gfxProxyFontEntry
> FindOrCreateFontFace(
205 const nsAString
& aFamilyName
,
206 const nsTArray
<gfxFontFaceSrc
>& aFontFaceSrcList
,
209 uint32_t aItalicStyle
,
210 const nsTArray
<gfxFontFeature
>& aFeatureSettings
,
211 uint32_t aLanguageOverride
,
212 gfxSparseBitSet
* aUnicodeRanges
);
214 // add in a font face for which we have the gfxFontEntry already
215 void AddFontFace(const nsAString
& aFamilyName
, gfxFontEntry
* aFontEntry
);
217 // Whether there is a face with this family name
218 bool HasFamily(const nsAString
& aFamilyName
) const
220 return LookupFamily(aFamilyName
) != nullptr;
223 // Look up and return the gfxMixedFontFamily in mFontFamilies with
225 gfxMixedFontFamily
* LookupFamily(const nsAString
& aName
) const;
227 // Lookup a font entry for a given style, returns null if not loaded.
228 // aFamily must be a family returned by our LookupFamily method.
229 gfxFontEntry
*FindFontEntry(gfxFontFamily
*aFamily
,
230 const gfxFontStyle
& aFontStyle
,
232 bool& aWaitForUserFont
);
234 // Find a family (possibly one of several!) that owns the given entry.
235 // This may be somewhat expensive, as it enumerates all the fonts in
236 // the set. Currently used only by the Linux (gfxPangoFontGroup) backend,
237 // which does not directly track families in the font group's list.
238 gfxFontFamily
*FindFamilyFor(gfxFontEntry
*aFontEntry
) const;
240 // check whether the given source is allowed to be loaded;
241 // returns the Principal (for use in the key when caching the loaded font),
242 // and whether the load should bypass the cache (force-reload).
243 virtual nsresult
CheckFontLoad(const gfxFontFaceSrc
*aFontFaceSrc
,
244 nsIPrincipal
**aPrincipal
,
245 bool *aBypassCache
) = 0;
247 // initialize the process that loads external font data, which upon
248 // completion will call OnLoadComplete method
249 virtual nsresult
StartLoad(gfxMixedFontFamily
*aFamily
,
250 gfxProxyFontEntry
*aProxy
,
251 const gfxFontFaceSrc
*aFontFaceSrc
) = 0;
253 // when download has been completed, pass back data here
254 // aDownloadStatus == NS_OK ==> download succeeded, error otherwise
255 // returns true if platform font creation sucessful (or local()
256 // reference was next in line)
257 // Ownership of aFontData is passed in here; the font set must
258 // ensure that it is eventually deleted with NS_Free().
259 bool OnLoadComplete(gfxMixedFontFamily
*aFamily
,
260 gfxProxyFontEntry
*aProxy
,
261 const uint8_t *aFontData
, uint32_t aLength
,
262 nsresult aDownloadStatus
);
264 // Replace a proxy with a real fontEntry; this is implemented in
265 // nsUserFontSet in order to keep track of the entry corresponding
266 // to each @font-face rule.
267 virtual void ReplaceFontEntry(gfxMixedFontFamily
*aFamily
,
268 gfxProxyFontEntry
*aProxy
,
269 gfxFontEntry
*aFontEntry
) = 0;
271 // generation - each time a face is loaded, generation is
272 // incremented so that the change can be recognized
273 uint64_t GetGeneration() { return mGeneration
; }
275 // increment the generation on font load
276 void IncrementGeneration();
278 // rebuild if local rules have been used
279 void RebuildLocalRules();
281 class UserFontCache
{
283 // Flag passed when caching a font entry, to specify whether the entry
284 // should persist in the cache or be discardable.
290 // Record a loaded user-font in the cache. This requires that the
291 // font-entry's userFontData has been set up already, as it relies
292 // on the URI and Principal recorded there.
293 // If aPersistence is Persistent, the entry will remain in the cache
294 // across cacheservice:empty-cache notifications. This is used for
295 // "preloaded hidden fonts" on FxOS.
296 static void CacheFont(gfxFontEntry
*aFontEntry
,
297 EntryPersistence aPersistence
= kDiscardable
);
299 // The given gfxFontEntry is being destroyed, so remove any record that
301 static void ForgetFont(gfxFontEntry
*aFontEntry
);
303 // Return the gfxFontEntry corresponding to a given URI and principal,
304 // and the features of the given proxy, or nullptr if none is available.
305 // The aPrivate flag is set for requests coming from private windows,
306 // so we can avoid leaking fonts cached in private windows mode out to
308 static gfxFontEntry
* GetFont(nsIURI
*aSrcURI
,
309 nsIPrincipal
*aPrincipal
,
310 gfxProxyFontEntry
*aProxy
,
313 // Clear everything so that we don't leak URIs and Principals.
314 static void Shutdown();
316 #ifdef DEBUG_USERFONT_CACHE
322 // Helper that we use to observe the empty-cache notification
323 // from nsICacheService.
324 class Flusher
: public nsIObserver
326 virtual ~Flusher() {}
333 // Key used to look up entries in the user-font cache.
334 // Note that key comparison does *not* use the mFontEntry field
335 // as a whole; it only compares specific fields within the entry
336 // (weight/width/style/features) that could affect font selection
337 // or rendering, and that must match between a font-set's proxy
338 // entry and the corresponding "real" font entry.
340 nsCOMPtr
<nsIURI
> mURI
;
341 nsCOMPtr
<nsIPrincipal
> mPrincipal
; // use nullptr with data: URLs
342 gfxFontEntry
*mFontEntry
;
346 EntryPersistence mPersistence
;
348 Key(nsIURI
* aURI
, nsIPrincipal
* aPrincipal
,
349 gfxFontEntry
* aFontEntry
, bool aPrivate
,
350 EntryPersistence aPersistence
= kDiscardable
)
352 mPrincipal(aPrincipal
),
353 mFontEntry(aFontEntry
),
357 mPersistence(aPersistence
)
360 Key(uint32_t aCRC32
, uint32_t aLength
,
361 gfxFontEntry
* aFontEntry
, bool aPrivate
,
362 EntryPersistence aPersistence
= kDiscardable
)
365 mFontEntry(aFontEntry
),
369 mPersistence(aPersistence
)
373 class Entry
: public PLDHashEntryHdr
{
375 typedef const Key
& KeyType
;
376 typedef const Key
* KeyTypePointer
;
378 explicit Entry(KeyTypePointer aKey
)
380 mPrincipal(aKey
->mPrincipal
),
381 mCRC32(aKey
->mCRC32
),
382 mLength(aKey
->mLength
),
383 mFontEntry(aKey
->mFontEntry
),
384 mPrivate(aKey
->mPrivate
),
385 mPersistence(aKey
->mPersistence
)
388 Entry(const Entry
& aOther
)
390 mPrincipal(aOther
.mPrincipal
),
391 mCRC32(aOther
.mCRC32
),
392 mLength(aOther
.mLength
),
393 mFontEntry(aOther
.mFontEntry
),
394 mPrivate(aOther
.mPrivate
),
395 mPersistence(aOther
.mPersistence
)
400 bool KeyEquals(const KeyTypePointer aKey
) const;
402 static KeyTypePointer
KeyToPointer(KeyType aKey
) { return &aKey
; }
404 static PLDHashNumber
HashKey(const KeyTypePointer aKey
) {
408 uint32_t principalHash
= 0;
409 if (aKey
->mPrincipal
) {
410 aKey
->mPrincipal
->GetHashValue(&principalHash
);
412 return mozilla::HashGeneric(principalHash
+ int(aKey
->mPrivate
),
413 nsURIHashKey::HashKey(aKey
->mURI
),
414 HashFeatures(aKey
->mFontEntry
->mFeatureSettings
),
415 mozilla::HashString(aKey
->mFontEntry
->mFamilyName
),
416 ((uint32_t)aKey
->mFontEntry
->mItalic
|
417 (aKey
->mFontEntry
->mWeight
<< 1) |
418 (aKey
->mFontEntry
->mStretch
<< 10) ) ^
419 aKey
->mFontEntry
->mLanguageOverride
);
422 enum { ALLOW_MEMMOVE
= false };
424 gfxFontEntry
* GetFontEntry() const { return mFontEntry
; }
426 static PLDHashOperator
427 RemoveUnlessPersistent(Entry
* aEntry
, void* aUserData
);
428 static PLDHashOperator
429 RemoveIfPrivate(Entry
* aEntry
, void* aUserData
);
430 static PLDHashOperator
431 RemoveIfMatches(Entry
* aEntry
, void* aUserData
);
432 static PLDHashOperator
433 DisconnectSVG(Entry
* aEntry
, void* aUserData
);
435 #ifdef DEBUG_USERFONT_CACHE
436 static PLDHashOperator
DumpEntry(Entry
* aEntry
, void* aUserData
);
441 HashFeatures(const nsTArray
<gfxFontFeature
>& aFeatures
) {
442 return mozilla::HashBytes(aFeatures
.Elements(),
443 aFeatures
.Length() * sizeof(gfxFontFeature
));
446 nsCOMPtr
<nsIURI
> mURI
;
447 nsCOMPtr
<nsIPrincipal
> mPrincipal
; // or nullptr for data: URLs
452 // The "real" font entry corresponding to this downloaded font.
453 // The font entry MUST notify the cache when it is destroyed
454 // (by calling Forget()).
455 gfxFontEntry
*mFontEntry
;
457 // Whether this font was loaded from a private window.
460 // Whether this entry should survive cache-flushing.
461 EntryPersistence mPersistence
;
464 static nsTHashtable
<Entry
> *sUserFonts
;
468 // Protected destructor, to discourage deletion outside of Release():
469 virtual ~gfxUserFontSet();
471 // Return whether the font set is associated with a private-browsing tab.
472 virtual bool GetPrivateBrowsing() = 0;
474 // parse data for a data URL
475 virtual nsresult
SyncLoadFontData(gfxProxyFontEntry
*aFontToLoad
,
476 const gfxFontFaceSrc
*aFontFaceSrc
,
478 uint32_t &aBufferLength
) = 0;
480 // report a problem of some kind (implemented in nsUserFontSet)
481 virtual nsresult
LogMessage(gfxMixedFontFamily
*aFamily
,
482 gfxProxyFontEntry
*aProxy
,
483 const char *aMessage
,
484 uint32_t aFlags
= nsIScriptError::errorFlag
,
485 nsresult aStatus
= NS_OK
) = 0;
487 // helper method for performing the actual userfont set rebuild
488 virtual void DoRebuildUserFontSet() = 0;
490 // helper method for FindOrCreateFontFace
491 gfxProxyFontEntry
* FindExistingProxyEntry(
492 gfxMixedFontFamily
* aFamily
,
493 const nsTArray
<gfxFontFaceSrc
>& aFontFaceSrcList
,
496 uint32_t aItalicStyle
,
497 const nsTArray
<gfxFontFeature
>& aFeatureSettings
,
498 uint32_t aLanguageOverride
,
499 gfxSparseBitSet
* aUnicodeRanges
);
501 // creates a new gfxMixedFontFamily in mFontFamilies, or returns an existing
502 // family if there is one
503 gfxMixedFontFamily
* GetFamily(const nsAString
& aFamilyName
);
505 // font families defined by @font-face rules
506 nsRefPtrHashtable
<nsStringHashKey
, gfxMixedFontFamily
> mFontFamilies
;
508 uint64_t mGeneration
;
510 // true when local names have been looked up, false otherwise
511 bool mLocalRulesUsed
;
513 static PRLogModuleInfo
* GetUserFontsLog();
516 // acts a placeholder until the real font is downloaded
518 class gfxProxyFontEntry
: public gfxFontEntry
{
519 friend class gfxUserFontSet
;
520 friend class nsUserFontSet
;
521 friend class nsFontFaceLoader
;
522 friend class gfxOTSContext
;
528 STATUS_FORMAT_NOT_SUPPORTED
,
533 gfxProxyFontEntry(gfxUserFontSet
*aFontSet
,
534 const nsTArray
<gfxFontFaceSrc
>& aFontFaceSrcList
,
537 uint32_t aItalicStyle
,
538 const nsTArray
<gfxFontFeature
>& aFeatureSettings
,
539 uint32_t aLanguageOverride
,
540 gfxSparseBitSet
*aUnicodeRanges
);
542 virtual ~gfxProxyFontEntry();
544 // Return whether the entry matches the given list of attributes
545 bool Matches(const nsTArray
<gfxFontFaceSrc
>& aFontFaceSrcList
,
548 uint32_t aItalicStyle
,
549 const nsTArray
<gfxFontFeature
>& aFeatureSettings
,
550 uint32_t aLanguageOverride
,
551 gfxSparseBitSet
*aUnicodeRanges
);
553 virtual gfxFont
*CreateFontInstance(const gfxFontStyle
*aFontStyle
, bool aNeedsBold
);
556 const uint8_t* SanitizeOpenTypeData(gfxMixedFontFamily
*aFamily
,
557 const uint8_t* aData
,
559 uint32_t& aSaneLength
,
562 // Attempt to load the next resource in the src list.
563 // aLocalRules is set to true if an attempt was made to load a
564 // local() font was loaded, and left as it is otherwise.
565 LoadStatus
LoadNext(gfxMixedFontFamily
*aFamily
,
566 bool& aLocalRulesUsed
);
568 // helper method for creating a platform font
569 // returns font entry if platform font creation successful
570 // Ownership of aFontData is passed in here; the font must
571 // ensure that it is eventually deleted with NS_Free().
572 gfxFontEntry
* LoadFont(gfxMixedFontFamily
*aFamily
,
573 const uint8_t *aFontData
, uint32_t &aLength
);
575 // store metadata and src details for current src into aFontEntry
576 void StoreUserFontData(gfxFontEntry
* aFontEntry
,
578 const nsAString
& aOriginalName
,
579 FallibleTArray
<uint8_t>* aMetadata
,
580 uint32_t aMetaOrigLen
);
582 // note that code depends on the ordering of these values!
584 NOT_LOADING
= 0, // not started to load any font resources yet
585 LOADING_STARTED
, // loading has started; hide fallback font
586 LOADING_ALMOST_DONE
, // timeout happened but we're nearly done,
587 // so keep hiding fallback font
588 LOADING_SLOWLY
, // timeout happened and we're not nearly done,
589 // so use the fallback font
590 LOADING_FAILED
// failed to load any source: use fallback
592 LoadingState mLoadingState
;
593 bool mUnsupportedFormat
;
595 nsTArray
<gfxFontFaceSrc
> mSrcList
;
596 uint32_t mSrcIndex
; // index of loading src item
597 nsFontFaceLoader
*mLoader
; // current loader for this entry, if any
598 gfxUserFontSet
*mFontSet
; // font-set to which the proxy belongs
599 nsCOMPtr
<nsIPrincipal
> mPrincipal
;
603 #endif /* GFX_USER_FONT_SET_H */