1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/thebes/gfxUserFontSet.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,494 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef GFX_USER_FONT_SET_H 1.10 +#define GFX_USER_FONT_SET_H 1.11 + 1.12 +#include "gfxFont.h" 1.13 +#include "nsPresContext.h" 1.14 +#include "nsRefPtrHashtable.h" 1.15 +#include "nsAutoPtr.h" 1.16 +#include "nsCOMPtr.h" 1.17 +#include "nsIURI.h" 1.18 +#include "nsIPrincipal.h" 1.19 +#include "nsIScriptError.h" 1.20 +#include "nsURIHashKey.h" 1.21 + 1.22 +class nsFontFaceLoader; 1.23 + 1.24 +//#define DEBUG_USERFONT_CACHE 1.25 + 1.26 +// parsed CSS @font-face rule information 1.27 +// lifetime: from when @font-face rule processed until font is loaded 1.28 +struct gfxFontFaceSrc { 1.29 + bool mIsLocal; // url or local 1.30 + 1.31 + // if url, whether to use the origin principal or not 1.32 + bool mUseOriginPrincipal; 1.33 + 1.34 + // format hint flags, union of all possible formats 1.35 + // (e.g. TrueType, EOT, SVG, etc.) 1.36 + // see FLAG_FORMAT_* enum values below 1.37 + uint32_t mFormatFlags; 1.38 + 1.39 + nsString mLocalName; // full font name if local 1.40 + nsCOMPtr<nsIURI> mURI; // uri if url 1.41 + nsCOMPtr<nsIURI> mReferrer; // referrer url if url 1.42 + nsCOMPtr<nsIPrincipal> mOriginPrincipal; // principal if url 1.43 +}; 1.44 + 1.45 +inline bool 1.46 +operator==(const gfxFontFaceSrc& a, const gfxFontFaceSrc& b) 1.47 +{ 1.48 + bool equals; 1.49 + return (a.mIsLocal && b.mIsLocal && 1.50 + a.mLocalName == b.mLocalName) || 1.51 + (!a.mIsLocal && !b.mIsLocal && 1.52 + a.mUseOriginPrincipal == b.mUseOriginPrincipal && 1.53 + a.mFormatFlags == b.mFormatFlags && 1.54 + NS_SUCCEEDED(a.mURI->Equals(b.mURI, &equals)) && equals && 1.55 + NS_SUCCEEDED(a.mReferrer->Equals(b.mReferrer, &equals)) && equals && 1.56 + a.mOriginPrincipal->Equals(b.mOriginPrincipal)); 1.57 +} 1.58 + 1.59 +// Subclassed to store platform-specific code cleaned out when font entry is 1.60 +// deleted. 1.61 +// Lifetime: from when platform font is created until it is deactivated. 1.62 +// If the platform does not need to add any platform-specific code/data here, 1.63 +// then the gfxUserFontSet will allocate a base gfxUserFontData and attach 1.64 +// to the entry to track the basic user font info fields here. 1.65 +class gfxUserFontData { 1.66 +public: 1.67 + gfxUserFontData() 1.68 + : mSrcIndex(0), mFormat(0), mMetaOrigLen(0) 1.69 + { } 1.70 + virtual ~gfxUserFontData() { } 1.71 + 1.72 + nsTArray<uint8_t> mMetadata; // woff metadata block (compressed), if any 1.73 + nsCOMPtr<nsIURI> mURI; // URI of the source, if it was url() 1.74 + nsCOMPtr<nsIPrincipal> mPrincipal; // principal for the download, if url() 1.75 + nsString mLocalName; // font name used for the source, if local() 1.76 + nsString mRealName; // original fullname from the font resource 1.77 + uint32_t mSrcIndex; // index in the rule's source list 1.78 + uint32_t mFormat; // format hint for the source used, if any 1.79 + uint32_t mMetaOrigLen; // length needed to decompress metadata 1.80 + bool mPrivate; // whether font belongs to a private window 1.81 +}; 1.82 + 1.83 +// initially contains a set of proxy font entry objects, replaced with 1.84 +// platform/user fonts as downloaded 1.85 + 1.86 +class gfxMixedFontFamily : public gfxFontFamily { 1.87 +public: 1.88 + friend class gfxUserFontSet; 1.89 + 1.90 + gfxMixedFontFamily(const nsAString& aName) 1.91 + : gfxFontFamily(aName) { } 1.92 + 1.93 + virtual ~gfxMixedFontFamily() { } 1.94 + 1.95 + // Add the given font entry to the end of the family's list. 1.96 + // Any earlier occurrence is removed, so this has the effect of "advancing" 1.97 + // the entry to the end of the list. 1.98 + void AddFontEntry(gfxFontEntry *aFontEntry) { 1.99 + // We append to mAvailableFonts -before- searching for and removing 1.100 + // any existing reference to avoid the risk that we'll remove the last 1.101 + // reference to the font entry, and thus delete it. 1.102 + mAvailableFonts.AppendElement(aFontEntry); 1.103 + uint32_t i = mAvailableFonts.Length() - 1; 1.104 + while (i > 0) { 1.105 + if (mAvailableFonts[--i] == aFontEntry) { 1.106 + mAvailableFonts.RemoveElementAt(i); 1.107 + break; 1.108 + } 1.109 + } 1.110 + aFontEntry->mFamilyName = Name(); 1.111 + ResetCharacterMap(); 1.112 + } 1.113 + 1.114 + // Replace aProxyFontEntry in the family's list with aRealFontEntry. 1.115 + void ReplaceFontEntry(gfxFontEntry *aProxyFontEntry, 1.116 + gfxFontEntry *aRealFontEntry) { 1.117 + uint32_t numFonts = mAvailableFonts.Length(); 1.118 + uint32_t i; 1.119 + for (i = 0; i < numFonts; i++) { 1.120 + gfxFontEntry *fe = mAvailableFonts[i]; 1.121 + if (fe == aProxyFontEntry) { 1.122 + // Note that this may delete aProxyFontEntry, if there's no 1.123 + // other reference to it except from its family. 1.124 + mAvailableFonts[i] = aRealFontEntry; 1.125 + aRealFontEntry->mFamilyName = Name(); 1.126 + break; 1.127 + } 1.128 + } 1.129 + NS_ASSERTION(i < numFonts, "font entry not found in family!"); 1.130 + ResetCharacterMap(); 1.131 + } 1.132 + 1.133 + // Remove all font entries from the family 1.134 + void DetachFontEntries() { 1.135 + mAvailableFonts.Clear(); 1.136 + } 1.137 +}; 1.138 + 1.139 +class gfxProxyFontEntry; 1.140 + 1.141 +class gfxUserFontSet { 1.142 + 1.143 +public: 1.144 + 1.145 + NS_INLINE_DECL_REFCOUNTING(gfxUserFontSet) 1.146 + 1.147 + gfxUserFontSet(); 1.148 + 1.149 + enum { 1.150 + // no flags ==> no hint set 1.151 + // unknown ==> unknown format hint set 1.152 + FLAG_FORMAT_UNKNOWN = 1, 1.153 + FLAG_FORMAT_OPENTYPE = 1 << 1, 1.154 + FLAG_FORMAT_TRUETYPE = 1 << 2, 1.155 + FLAG_FORMAT_TRUETYPE_AAT = 1 << 3, 1.156 + FLAG_FORMAT_EOT = 1 << 4, 1.157 + FLAG_FORMAT_SVG = 1 << 5, 1.158 + FLAG_FORMAT_WOFF = 1 << 6, 1.159 + 1.160 + // mask of all unused bits, update when adding new formats 1.161 + FLAG_FORMAT_NOT_USED = ~((1 << 7)-1) 1.162 + }; 1.163 + 1.164 + enum LoadStatus { 1.165 + STATUS_LOADING = 0, 1.166 + STATUS_LOADED, 1.167 + STATUS_FORMAT_NOT_SUPPORTED, 1.168 + STATUS_ERROR, 1.169 + STATUS_END_OF_LIST 1.170 + }; 1.171 + 1.172 + 1.173 + // add in a font face 1.174 + // weight - 0 == unknown, [100, 900] otherwise (multiples of 100) 1.175 + // stretch = [NS_FONT_STRETCH_ULTRA_CONDENSED, NS_FONT_STRETCH_ULTRA_EXPANDED] 1.176 + // italic style = constants in gfxFontConstants.h, e.g. NS_FONT_STYLE_NORMAL 1.177 + // TODO: support for unicode ranges not yet implemented 1.178 + gfxFontEntry *AddFontFace(const nsAString& aFamilyName, 1.179 + const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList, 1.180 + uint32_t aWeight, 1.181 + int32_t aStretch, 1.182 + uint32_t aItalicStyle, 1.183 + const nsTArray<gfxFontFeature>& aFeatureSettings, 1.184 + const nsString& aLanguageOverride, 1.185 + gfxSparseBitSet *aUnicodeRanges = nullptr); 1.186 + 1.187 + // add in a font face for which we have the gfxFontEntry already 1.188 + void AddFontFace(const nsAString& aFamilyName, gfxFontEntry* aFontEntry); 1.189 + 1.190 + // Whether there is a face with this family name 1.191 + bool HasFamily(const nsAString& aFamilyName) const 1.192 + { 1.193 + return GetFamily(aFamilyName) != nullptr; 1.194 + } 1.195 + 1.196 + gfxFontFamily *GetFamily(const nsAString& aName) const; 1.197 + 1.198 + // Lookup a font entry for a given style, returns null if not loaded. 1.199 + // aFamily must be a family returned by our GetFamily method. 1.200 + gfxFontEntry *FindFontEntry(gfxFontFamily *aFamily, 1.201 + const gfxFontStyle& aFontStyle, 1.202 + bool& aNeedsBold, 1.203 + bool& aWaitForUserFont); 1.204 + 1.205 + // Find a family (possibly one of several!) that owns the given entry. 1.206 + // This may be somewhat expensive, as it enumerates all the fonts in 1.207 + // the set. Currently used only by the Linux (gfxPangoFontGroup) backend, 1.208 + // which does not directly track families in the font group's list. 1.209 + gfxFontFamily *FindFamilyFor(gfxFontEntry *aFontEntry) const; 1.210 + 1.211 + // check whether the given source is allowed to be loaded; 1.212 + // returns the Principal (for use in the key when caching the loaded font), 1.213 + // and whether the load should bypass the cache (force-reload). 1.214 + virtual nsresult CheckFontLoad(const gfxFontFaceSrc *aFontFaceSrc, 1.215 + nsIPrincipal **aPrincipal, 1.216 + bool *aBypassCache) = 0; 1.217 + 1.218 + // initialize the process that loads external font data, which upon 1.219 + // completion will call OnLoadComplete method 1.220 + virtual nsresult StartLoad(gfxMixedFontFamily *aFamily, 1.221 + gfxProxyFontEntry *aProxy, 1.222 + const gfxFontFaceSrc *aFontFaceSrc) = 0; 1.223 + 1.224 + // when download has been completed, pass back data here 1.225 + // aDownloadStatus == NS_OK ==> download succeeded, error otherwise 1.226 + // returns true if platform font creation sucessful (or local() 1.227 + // reference was next in line) 1.228 + // Ownership of aFontData is passed in here; the font set must 1.229 + // ensure that it is eventually deleted with NS_Free(). 1.230 + bool OnLoadComplete(gfxMixedFontFamily *aFamily, 1.231 + gfxProxyFontEntry *aProxy, 1.232 + const uint8_t *aFontData, uint32_t aLength, 1.233 + nsresult aDownloadStatus); 1.234 + 1.235 + // Replace a proxy with a real fontEntry; this is implemented in 1.236 + // nsUserFontSet in order to keep track of the entry corresponding 1.237 + // to each @font-face rule. 1.238 + virtual void ReplaceFontEntry(gfxMixedFontFamily *aFamily, 1.239 + gfxProxyFontEntry *aProxy, 1.240 + gfxFontEntry *aFontEntry) = 0; 1.241 + 1.242 + // generation - each time a face is loaded, generation is 1.243 + // incremented so that the change can be recognized 1.244 + uint64_t GetGeneration() { return mGeneration; } 1.245 + 1.246 + // increment the generation on font load 1.247 + void IncrementGeneration(); 1.248 + 1.249 + // rebuild if local rules have been used 1.250 + void RebuildLocalRules(); 1.251 + 1.252 + virtual nsPresContext *GetPresContext() { return NULL; } 1.253 + 1.254 + class UserFontCache { 1.255 + public: 1.256 + // Record a loaded user-font in the cache. This requires that the 1.257 + // font-entry's userFontData has been set up already, as it relies 1.258 + // on the URI and Principal recorded there. 1.259 + static void CacheFont(gfxFontEntry *aFontEntry); 1.260 + 1.261 + // The given gfxFontEntry is being destroyed, so remove any record that 1.262 + // refers to it. 1.263 + static void ForgetFont(gfxFontEntry *aFontEntry); 1.264 + 1.265 + // Return the gfxFontEntry corresponding to a given URI and principal, 1.266 + // and the features of the given proxy, or nullptr if none is available. 1.267 + // The aPrivate flag is set for requests coming from private windows, 1.268 + // so we can avoid leaking fonts cached in private windows mode out to 1.269 + // normal windows. 1.270 + static gfxFontEntry* GetFont(nsIURI *aSrcURI, 1.271 + nsIPrincipal *aPrincipal, 1.272 + gfxProxyFontEntry *aProxy, 1.273 + bool aPrivate); 1.274 + 1.275 + // Clear everything so that we don't leak URIs and Principals. 1.276 + static void Shutdown(); 1.277 + 1.278 +#ifdef DEBUG_USERFONT_CACHE 1.279 + // dump contents 1.280 + static void Dump(); 1.281 +#endif 1.282 + 1.283 + private: 1.284 + // Helper that we use to observe the empty-cache notification 1.285 + // from nsICacheService. 1.286 + class Flusher : public nsIObserver 1.287 + { 1.288 + public: 1.289 + NS_DECL_ISUPPORTS 1.290 + NS_DECL_NSIOBSERVER 1.291 + Flusher() {} 1.292 + virtual ~Flusher() {} 1.293 + }; 1.294 + 1.295 + // Key used to look up entries in the user-font cache. 1.296 + // Note that key comparison does *not* use the mFontEntry field 1.297 + // as a whole; it only compares specific fields within the entry 1.298 + // (weight/width/style/features) that could affect font selection 1.299 + // or rendering, and that must match between a font-set's proxy 1.300 + // entry and the corresponding "real" font entry. 1.301 + struct Key { 1.302 + nsCOMPtr<nsIURI> mURI; 1.303 + nsCOMPtr<nsIPrincipal> mPrincipal; 1.304 + gfxFontEntry *mFontEntry; 1.305 + bool mPrivate; 1.306 + 1.307 + Key(nsIURI* aURI, nsIPrincipal* aPrincipal, 1.308 + gfxFontEntry* aFontEntry, bool aPrivate) 1.309 + : mURI(aURI), 1.310 + mPrincipal(aPrincipal), 1.311 + mFontEntry(aFontEntry), 1.312 + mPrivate(aPrivate) 1.313 + { } 1.314 + }; 1.315 + 1.316 + class Entry : public PLDHashEntryHdr { 1.317 + public: 1.318 + typedef const Key& KeyType; 1.319 + typedef const Key* KeyTypePointer; 1.320 + 1.321 + Entry(KeyTypePointer aKey) 1.322 + : mURI(aKey->mURI), 1.323 + mPrincipal(aKey->mPrincipal), 1.324 + mFontEntry(aKey->mFontEntry), 1.325 + mPrivate(aKey->mPrivate) 1.326 + { } 1.327 + 1.328 + Entry(const Entry& aOther) 1.329 + : mURI(aOther.mURI), 1.330 + mPrincipal(aOther.mPrincipal), 1.331 + mFontEntry(aOther.mFontEntry), 1.332 + mPrivate(aOther.mPrivate) 1.333 + { } 1.334 + 1.335 + ~Entry() { } 1.336 + 1.337 + bool KeyEquals(const KeyTypePointer aKey) const; 1.338 + 1.339 + static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } 1.340 + 1.341 + static PLDHashNumber HashKey(const KeyTypePointer aKey) { 1.342 + uint32_t principalHash; 1.343 + aKey->mPrincipal->GetHashValue(&principalHash); 1.344 + return mozilla::HashGeneric(principalHash + int(aKey->mPrivate), 1.345 + nsURIHashKey::HashKey(aKey->mURI), 1.346 + HashFeatures(aKey->mFontEntry->mFeatureSettings), 1.347 + mozilla::HashString(aKey->mFontEntry->mFamilyName), 1.348 + ((uint32_t)aKey->mFontEntry->mItalic | 1.349 + (aKey->mFontEntry->mWeight << 1) | 1.350 + (aKey->mFontEntry->mStretch << 10) ) ^ 1.351 + aKey->mFontEntry->mLanguageOverride); 1.352 + } 1.353 + 1.354 + enum { ALLOW_MEMMOVE = false }; 1.355 + 1.356 + gfxFontEntry* GetFontEntry() const { return mFontEntry; } 1.357 + 1.358 + static PLDHashOperator RemoveIfPrivate(Entry* aEntry, void* aUserData); 1.359 + static PLDHashOperator RemoveIfMatches(Entry* aEntry, void* aUserData); 1.360 + static PLDHashOperator DisconnectSVG(Entry* aEntry, void* aUserData); 1.361 + 1.362 +#ifdef DEBUG_USERFONT_CACHE 1.363 + static PLDHashOperator DumpEntry(Entry* aEntry, void* aUserData); 1.364 +#endif 1.365 + 1.366 + private: 1.367 + static uint32_t 1.368 + HashFeatures(const nsTArray<gfxFontFeature>& aFeatures) { 1.369 + return mozilla::HashBytes(aFeatures.Elements(), 1.370 + aFeatures.Length() * sizeof(gfxFontFeature)); 1.371 + } 1.372 + 1.373 + nsCOMPtr<nsIURI> mURI; 1.374 + nsCOMPtr<nsIPrincipal> mPrincipal; 1.375 + 1.376 + // The "real" font entry corresponding to this downloaded font. 1.377 + // The font entry MUST notify the cache when it is destroyed 1.378 + // (by calling Forget()). 1.379 + gfxFontEntry *mFontEntry; 1.380 + 1.381 + // Whether this font was loaded from a private window. 1.382 + bool mPrivate; 1.383 + }; 1.384 + 1.385 + static nsTHashtable<Entry> *sUserFonts; 1.386 + }; 1.387 + 1.388 +protected: 1.389 + // Protected destructor, to discourage deletion outside of Release(): 1.390 + virtual ~gfxUserFontSet(); 1.391 + 1.392 + // Return whether the font set is associated with a private-browsing tab. 1.393 + virtual bool GetPrivateBrowsing() = 0; 1.394 + 1.395 + // for a given proxy font entry, attempt to load the next resource 1.396 + // in the src list 1.397 + LoadStatus LoadNext(gfxMixedFontFamily *aFamily, 1.398 + gfxProxyFontEntry *aProxyEntry); 1.399 + 1.400 + // helper method for creating a platform font 1.401 + // returns font entry if platform font creation successful 1.402 + // Ownership of aFontData is passed in here; the font set must 1.403 + // ensure that it is eventually deleted with NS_Free(). 1.404 + gfxFontEntry* LoadFont(gfxMixedFontFamily *aFamily, 1.405 + gfxProxyFontEntry *aProxy, 1.406 + const uint8_t *aFontData, uint32_t &aLength); 1.407 + 1.408 + // parse data for a data URL 1.409 + virtual nsresult SyncLoadFontData(gfxProxyFontEntry *aFontToLoad, 1.410 + const gfxFontFaceSrc *aFontFaceSrc, 1.411 + uint8_t* &aBuffer, 1.412 + uint32_t &aBufferLength) = 0; 1.413 + 1.414 + // report a problem of some kind (implemented in nsUserFontSet) 1.415 + virtual nsresult LogMessage(gfxMixedFontFamily *aFamily, 1.416 + gfxProxyFontEntry *aProxy, 1.417 + const char *aMessage, 1.418 + uint32_t aFlags = nsIScriptError::errorFlag, 1.419 + nsresult aStatus = NS_OK) = 0; 1.420 + 1.421 + const uint8_t* SanitizeOpenTypeData(gfxMixedFontFamily *aFamily, 1.422 + gfxProxyFontEntry *aProxy, 1.423 + const uint8_t* aData, 1.424 + uint32_t aLength, 1.425 + uint32_t& aSaneLength, 1.426 + bool aIsCompressed); 1.427 + 1.428 + static bool OTSMessage(void *aUserData, const char *format, ...); 1.429 + 1.430 + // helper method for performing the actual userfont set rebuild 1.431 + virtual void DoRebuildUserFontSet() = 0; 1.432 + 1.433 + // font families defined by @font-face rules 1.434 + nsRefPtrHashtable<nsStringHashKey, gfxMixedFontFamily> mFontFamilies; 1.435 + 1.436 + uint64_t mGeneration; 1.437 + 1.438 + // true when local names have been looked up, false otherwise 1.439 + bool mLocalRulesUsed; 1.440 + 1.441 + static PRLogModuleInfo* GetUserFontsLog(); 1.442 + 1.443 +private: 1.444 + static void CopyWOFFMetadata(const uint8_t* aFontData, 1.445 + uint32_t aLength, 1.446 + FallibleTArray<uint8_t>* aMetadata, 1.447 + uint32_t* aMetaOrigLen); 1.448 +}; 1.449 + 1.450 +// acts a placeholder until the real font is downloaded 1.451 + 1.452 +class gfxProxyFontEntry : public gfxFontEntry { 1.453 + friend class gfxUserFontSet; 1.454 + 1.455 +public: 1.456 + gfxProxyFontEntry(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList, 1.457 + uint32_t aWeight, 1.458 + int32_t aStretch, 1.459 + uint32_t aItalicStyle, 1.460 + const nsTArray<gfxFontFeature>& aFeatureSettings, 1.461 + uint32_t aLanguageOverride, 1.462 + gfxSparseBitSet *aUnicodeRanges); 1.463 + 1.464 + virtual ~gfxProxyFontEntry(); 1.465 + 1.466 + // Return whether the entry matches the given list of attributes 1.467 + bool Matches(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList, 1.468 + uint32_t aWeight, 1.469 + int32_t aStretch, 1.470 + uint32_t aItalicStyle, 1.471 + const nsTArray<gfxFontFeature>& aFeatureSettings, 1.472 + uint32_t aLanguageOverride, 1.473 + gfxSparseBitSet *aUnicodeRanges); 1.474 + 1.475 + virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold); 1.476 + 1.477 + // note that code depends on the ordering of these values! 1.478 + enum LoadingState { 1.479 + NOT_LOADING = 0, // not started to load any font resources yet 1.480 + LOADING_STARTED, // loading has started; hide fallback font 1.481 + LOADING_ALMOST_DONE, // timeout happened but we're nearly done, 1.482 + // so keep hiding fallback font 1.483 + LOADING_SLOWLY, // timeout happened and we're not nearly done, 1.484 + // so use the fallback font 1.485 + LOADING_FAILED // failed to load any source: use fallback 1.486 + }; 1.487 + LoadingState mLoadingState; 1.488 + bool mUnsupportedFormat; 1.489 + 1.490 + nsTArray<gfxFontFaceSrc> mSrcList; 1.491 + uint32_t mSrcIndex; // index of loading src item 1.492 + nsFontFaceLoader *mLoader; // current loader for this entry, if any 1.493 + nsCOMPtr<nsIPrincipal> mPrincipal; 1.494 +}; 1.495 + 1.496 + 1.497 +#endif /* GFX_USER_FONT_SET_H */