Bumping manifests a=b2g-bump
[gecko.git] / gfx / thebes / gfxUserFontSet.h
blob47f3387750c249b3e55fb2de1457833edfa1bf86
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
9 #include "gfxFont.h"
10 #include "nsRefPtrHashtable.h"
11 #include "nsAutoPtr.h"
12 #include "nsCOMPtr.h"
13 #include "nsIURI.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
41 inline bool
42 operator==(const gfxFontFaceSrc& a, const gfxFontFaceSrc& b)
44 bool equals;
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
56 // deleted.
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 {
62 public:
63 gfxUserFontData()
64 : mSrcIndex(0), mFormat(0), mMetaOrigLen(0),
65 mCRC32(0), mLength(0), mPrivate(false)
66 { }
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 {
86 public:
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;
103 while (i > 0) {
104 if (mAvailableFonts[--i] == aFontEntry) {
105 mAvailableFonts.RemoveElementAt(i);
106 break;
109 if (aFontEntry->mFamilyName.IsEmpty()) {
110 aFontEntry->mFamilyName = Name();
111 } else {
112 #ifdef DEBUG
113 nsString thisName = Name();
114 nsString entryName = aFontEntry->mFamilyName;
115 ToLowerCase(thisName);
116 ToLowerCase(entryName);
117 MOZ_ASSERT(thisName.Equals(entryName));
118 #endif
120 ResetCharacterMap();
123 // Replace aProxyFontEntry in the family's list with aRealFontEntry.
124 void ReplaceFontEntry(gfxFontEntry *aProxyFontEntry,
125 gfxFontEntry *aRealFontEntry) {
126 uint32_t numFonts = mAvailableFonts.Length();
127 uint32_t i;
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();
136 } else {
137 #ifdef DEBUG
138 nsString thisName = Name();
139 nsString entryName = aRealFontEntry->mFamilyName;
140 ToLowerCase(thisName);
141 ToLowerCase(entryName);
142 MOZ_ASSERT(thisName.Equals(entryName));
143 #endif
145 break;
148 NS_ASSERTION(i < numFonts, "font entry not found in family!");
149 ResetCharacterMap();
152 // Remove all font entries from the family
153 void DetachFontEntries() {
154 mAvailableFonts.Clear();
158 class gfxProxyFontEntry;
159 class gfxOTSContext;
161 class gfxUserFontSet {
162 friend class gfxProxyFontEntry;
163 friend class gfxOTSContext;
165 public:
167 NS_INLINE_DECL_REFCOUNTING(gfxUserFontSet)
169 gfxUserFontSet();
171 enum {
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,
195 uint32_t aWeight,
196 int32_t aStretch,
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,
207 uint32_t aWeight,
208 int32_t aStretch,
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
224 // the given name
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,
231 bool& aNeedsBold,
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 {
282 public:
283 // Flag passed when caching a font entry, to specify whether the entry
284 // should persist in the cache or be discardable.
285 typedef enum {
286 kDiscardable,
287 kPersistent
288 } EntryPersistence;
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
300 // refers to it.
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
307 // normal windows.
308 static gfxFontEntry* GetFont(nsIURI *aSrcURI,
309 nsIPrincipal *aPrincipal,
310 gfxProxyFontEntry *aProxy,
311 bool aPrivate);
313 // Clear everything so that we don't leak URIs and Principals.
314 static void Shutdown();
316 #ifdef DEBUG_USERFONT_CACHE
317 // dump contents
318 static void Dump();
319 #endif
321 private:
322 // Helper that we use to observe the empty-cache notification
323 // from nsICacheService.
324 class Flusher : public nsIObserver
326 virtual ~Flusher() {}
327 public:
328 NS_DECL_ISUPPORTS
329 NS_DECL_NSIOBSERVER
330 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.
339 struct Key {
340 nsCOMPtr<nsIURI> mURI;
341 nsCOMPtr<nsIPrincipal> mPrincipal; // use nullptr with data: URLs
342 gfxFontEntry *mFontEntry;
343 uint32_t mCRC32;
344 uint32_t mLength;
345 bool mPrivate;
346 EntryPersistence mPersistence;
348 Key(nsIURI* aURI, nsIPrincipal* aPrincipal,
349 gfxFontEntry* aFontEntry, bool aPrivate,
350 EntryPersistence aPersistence = kDiscardable)
351 : mURI(aURI),
352 mPrincipal(aPrincipal),
353 mFontEntry(aFontEntry),
354 mCRC32(0),
355 mLength(0),
356 mPrivate(aPrivate),
357 mPersistence(aPersistence)
360 Key(uint32_t aCRC32, uint32_t aLength,
361 gfxFontEntry* aFontEntry, bool aPrivate,
362 EntryPersistence aPersistence = kDiscardable)
363 : mURI(nullptr),
364 mPrincipal(nullptr),
365 mFontEntry(aFontEntry),
366 mCRC32(aCRC32),
367 mLength(aLength),
368 mPrivate(aPrivate),
369 mPersistence(aPersistence)
373 class Entry : public PLDHashEntryHdr {
374 public:
375 typedef const Key& KeyType;
376 typedef const Key* KeyTypePointer;
378 explicit Entry(KeyTypePointer aKey)
379 : mURI(aKey->mURI),
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)
389 : mURI(aOther.mURI),
390 mPrincipal(aOther.mPrincipal),
391 mCRC32(aOther.mCRC32),
392 mLength(aOther.mLength),
393 mFontEntry(aOther.mFontEntry),
394 mPrivate(aOther.mPrivate),
395 mPersistence(aOther.mPersistence)
398 ~Entry() { }
400 bool KeyEquals(const KeyTypePointer aKey) const;
402 static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
404 static PLDHashNumber HashKey(const KeyTypePointer aKey) {
405 if (aKey->mLength) {
406 return aKey->mCRC32;
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);
437 #endif
439 private:
440 static uint32_t
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
449 uint32_t mCRC32;
450 uint32_t mLength;
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.
458 bool mPrivate;
460 // Whether this entry should survive cache-flushing.
461 EntryPersistence mPersistence;
464 static nsTHashtable<Entry> *sUserFonts;
467 protected:
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,
477 uint8_t* &aBuffer,
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,
494 uint32_t aWeight,
495 int32_t aStretch,
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;
524 public:
525 enum LoadStatus {
526 STATUS_LOADING = 0,
527 STATUS_LOADED,
528 STATUS_FORMAT_NOT_SUPPORTED,
529 STATUS_ERROR,
530 STATUS_END_OF_LIST
533 gfxProxyFontEntry(gfxUserFontSet *aFontSet,
534 const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
535 uint32_t aWeight,
536 int32_t aStretch,
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,
546 uint32_t aWeight,
547 int32_t aStretch,
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);
555 protected:
556 const uint8_t* SanitizeOpenTypeData(gfxMixedFontFamily *aFamily,
557 const uint8_t* aData,
558 uint32_t aLength,
559 uint32_t& aSaneLength,
560 bool aIsCompressed);
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,
577 bool aPrivate,
578 const nsAString& aOriginalName,
579 FallibleTArray<uint8_t>* aMetadata,
580 uint32_t aMetaOrigLen);
582 // note that code depends on the ordering of these values!
583 enum LoadingState {
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 */