gfx/thebes/gfxUserFontSet.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #ifdef MOZ_LOGGING
michael@0 7 #define FORCE_PR_LOG /* Allow logging in the release build */
michael@0 8 #endif /* MOZ_LOGGING */
michael@0 9 #include "prlog.h"
michael@0 10
michael@0 11 #include "gfxUserFontSet.h"
michael@0 12 #include "nsFont.h"
michael@0 13 #include "gfxPlatform.h"
michael@0 14 #include "nsUnicharUtils.h"
michael@0 15 #include "nsNetUtil.h"
michael@0 16 #include "nsICacheService.h"
michael@0 17 #include "nsIProtocolHandler.h"
michael@0 18 #include "nsIPrincipal.h"
michael@0 19 #include "gfxFontConstants.h"
michael@0 20 #include "mozilla/Services.h"
michael@0 21 #include "mozilla/gfx/2D.h"
michael@0 22 #include "gfxPlatformFontList.h"
michael@0 23
michael@0 24 #include "opentype-sanitiser.h"
michael@0 25 #include "ots-memory-stream.h"
michael@0 26
michael@0 27 using namespace mozilla;
michael@0 28
michael@0 29 #ifdef PR_LOGGING
michael@0 30 PRLogModuleInfo *
michael@0 31 gfxUserFontSet::GetUserFontsLog()
michael@0 32 {
michael@0 33 static PRLogModuleInfo *sLog;
michael@0 34 if (!sLog)
michael@0 35 sLog = PR_NewLogModule("userfonts");
michael@0 36 return sLog;
michael@0 37 }
michael@0 38 #endif /* PR_LOGGING */
michael@0 39
michael@0 40 #define LOG(args) PR_LOG(GetUserFontsLog(), PR_LOG_DEBUG, args)
michael@0 41 #define LOG_ENABLED() PR_LOG_TEST(GetUserFontsLog(), PR_LOG_DEBUG)
michael@0 42
michael@0 43 static uint64_t sFontSetGeneration = 0;
michael@0 44
michael@0 45 // TODO: support for unicode ranges not yet implemented
michael@0 46
michael@0 47 gfxProxyFontEntry::gfxProxyFontEntry(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
michael@0 48 uint32_t aWeight,
michael@0 49 int32_t aStretch,
michael@0 50 uint32_t aItalicStyle,
michael@0 51 const nsTArray<gfxFontFeature>& aFeatureSettings,
michael@0 52 uint32_t aLanguageOverride,
michael@0 53 gfxSparseBitSet *aUnicodeRanges)
michael@0 54 : gfxFontEntry(NS_LITERAL_STRING("Proxy")),
michael@0 55 mLoadingState(NOT_LOADING),
michael@0 56 mUnsupportedFormat(false),
michael@0 57 mLoader(nullptr)
michael@0 58 {
michael@0 59 mIsProxy = true;
michael@0 60 mSrcList = aFontFaceSrcList;
michael@0 61 mSrcIndex = 0;
michael@0 62 mWeight = aWeight;
michael@0 63 mStretch = aStretch;
michael@0 64 // XXX Currently, we don't distinguish 'italic' and 'oblique' styles;
michael@0 65 // we need to fix this. (Bug 543715)
michael@0 66 mItalic = (aItalicStyle & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE)) != 0;
michael@0 67 mFeatureSettings.AppendElements(aFeatureSettings);
michael@0 68 mLanguageOverride = aLanguageOverride;
michael@0 69 mIsUserFont = true;
michael@0 70 }
michael@0 71
michael@0 72 gfxProxyFontEntry::~gfxProxyFontEntry()
michael@0 73 {
michael@0 74 }
michael@0 75
michael@0 76 bool
michael@0 77 gfxProxyFontEntry::Matches(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
michael@0 78 uint32_t aWeight,
michael@0 79 int32_t aStretch,
michael@0 80 uint32_t aItalicStyle,
michael@0 81 const nsTArray<gfxFontFeature>& aFeatureSettings,
michael@0 82 uint32_t aLanguageOverride,
michael@0 83 gfxSparseBitSet *aUnicodeRanges)
michael@0 84 {
michael@0 85 // XXX font entries don't distinguish italic from oblique (bug 543715)
michael@0 86 bool isItalic =
michael@0 87 (aItalicStyle & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE)) != 0;
michael@0 88
michael@0 89 return mWeight == aWeight &&
michael@0 90 mStretch == aStretch &&
michael@0 91 mItalic == isItalic &&
michael@0 92 mFeatureSettings == aFeatureSettings &&
michael@0 93 mLanguageOverride == aLanguageOverride &&
michael@0 94 mSrcList == aFontFaceSrcList;
michael@0 95 // XXX once we support unicode-range (bug 475891),
michael@0 96 // we'll need to compare that here as well
michael@0 97 }
michael@0 98
michael@0 99 gfxFont*
michael@0 100 gfxProxyFontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold)
michael@0 101 {
michael@0 102 // cannot create an actual font for a proxy entry
michael@0 103 return nullptr;
michael@0 104 }
michael@0 105
michael@0 106 gfxUserFontSet::gfxUserFontSet()
michael@0 107 : mFontFamilies(5), mLocalRulesUsed(false)
michael@0 108 {
michael@0 109 IncrementGeneration();
michael@0 110 gfxPlatformFontList *fp = gfxPlatformFontList::PlatformFontList();
michael@0 111 if (fp) {
michael@0 112 fp->AddUserFontSet(this);
michael@0 113 }
michael@0 114 }
michael@0 115
michael@0 116 gfxUserFontSet::~gfxUserFontSet()
michael@0 117 {
michael@0 118 gfxPlatformFontList *fp = gfxPlatformFontList::PlatformFontList();
michael@0 119 if (fp) {
michael@0 120 fp->RemoveUserFontSet(this);
michael@0 121 }
michael@0 122 }
michael@0 123
michael@0 124 gfxFontEntry*
michael@0 125 gfxUserFontSet::AddFontFace(const nsAString& aFamilyName,
michael@0 126 const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
michael@0 127 uint32_t aWeight,
michael@0 128 int32_t aStretch,
michael@0 129 uint32_t aItalicStyle,
michael@0 130 const nsTArray<gfxFontFeature>& aFeatureSettings,
michael@0 131 const nsString& aLanguageOverride,
michael@0 132 gfxSparseBitSet *aUnicodeRanges)
michael@0 133 {
michael@0 134 nsAutoString key(aFamilyName);
michael@0 135 ToLowerCase(key);
michael@0 136
michael@0 137 bool found;
michael@0 138
michael@0 139 if (aWeight == 0)
michael@0 140 aWeight = NS_FONT_WEIGHT_NORMAL;
michael@0 141
michael@0 142 // stretch, italic/oblique ==> zero implies normal
michael@0 143
michael@0 144 gfxMixedFontFamily *family = mFontFamilies.GetWeak(key, &found);
michael@0 145 if (!family) {
michael@0 146 family = new gfxMixedFontFamily(aFamilyName);
michael@0 147 mFontFamilies.Put(key, family);
michael@0 148 }
michael@0 149
michael@0 150 uint32_t languageOverride =
michael@0 151 gfxFontStyle::ParseFontLanguageOverride(aLanguageOverride);
michael@0 152
michael@0 153 // If there's already a proxy in the family whose descriptors all match,
michael@0 154 // we can just move it to the end of the list instead of adding a new
michael@0 155 // face that will always "shadow" the old one.
michael@0 156 // Note that we can't do this for "real" (non-proxy) entries, even if the
michael@0 157 // style descriptors match, as they might have had a different source list,
michael@0 158 // but we no longer have the old source list available to check.
michael@0 159 nsTArray<nsRefPtr<gfxFontEntry> >& fontList = family->GetFontList();
michael@0 160 for (uint32_t i = 0, count = fontList.Length(); i < count; i++) {
michael@0 161 if (!fontList[i]->mIsProxy) {
michael@0 162 continue;
michael@0 163 }
michael@0 164
michael@0 165 gfxProxyFontEntry *existingProxyEntry =
michael@0 166 static_cast<gfxProxyFontEntry*>(fontList[i].get());
michael@0 167 if (!existingProxyEntry->Matches(aFontFaceSrcList,
michael@0 168 aWeight, aStretch, aItalicStyle,
michael@0 169 aFeatureSettings, languageOverride,
michael@0 170 aUnicodeRanges)) {
michael@0 171 continue;
michael@0 172 }
michael@0 173
michael@0 174 // We've found an entry that matches the new face exactly, so just add
michael@0 175 // it to the end of the list. gfxMixedFontFamily::AddFontEntry() will
michael@0 176 // automatically remove any earlier occurrence of the same proxy.
michael@0 177 family->AddFontEntry(existingProxyEntry);
michael@0 178 return existingProxyEntry;
michael@0 179 }
michael@0 180
michael@0 181 // construct a new face and add it into the family
michael@0 182 gfxProxyFontEntry *proxyEntry =
michael@0 183 new gfxProxyFontEntry(aFontFaceSrcList, aWeight, aStretch,
michael@0 184 aItalicStyle,
michael@0 185 aFeatureSettings,
michael@0 186 languageOverride,
michael@0 187 aUnicodeRanges);
michael@0 188 family->AddFontEntry(proxyEntry);
michael@0 189 #ifdef PR_LOGGING
michael@0 190 if (LOG_ENABLED()) {
michael@0 191 LOG(("userfonts (%p) added (%s) with style: %s weight: %d stretch: %d",
michael@0 192 this, NS_ConvertUTF16toUTF8(aFamilyName).get(),
michael@0 193 (aItalicStyle & NS_FONT_STYLE_ITALIC ? "italic" :
michael@0 194 (aItalicStyle & NS_FONT_STYLE_OBLIQUE ? "oblique" : "normal")),
michael@0 195 aWeight, aStretch));
michael@0 196 }
michael@0 197 #endif
michael@0 198
michael@0 199 return proxyEntry;
michael@0 200 }
michael@0 201
michael@0 202 void
michael@0 203 gfxUserFontSet::AddFontFace(const nsAString& aFamilyName,
michael@0 204 gfxFontEntry *aFontEntry)
michael@0 205 {
michael@0 206 nsAutoString key(aFamilyName);
michael@0 207 ToLowerCase(key);
michael@0 208
michael@0 209 bool found;
michael@0 210
michael@0 211 gfxMixedFontFamily *family = mFontFamilies.GetWeak(key, &found);
michael@0 212 if (!family) {
michael@0 213 family = new gfxMixedFontFamily(aFamilyName);
michael@0 214 mFontFamilies.Put(key, family);
michael@0 215 }
michael@0 216
michael@0 217 family->AddFontEntry(aFontEntry);
michael@0 218 }
michael@0 219
michael@0 220 gfxFontEntry*
michael@0 221 gfxUserFontSet::FindFontEntry(gfxFontFamily *aFamily,
michael@0 222 const gfxFontStyle& aFontStyle,
michael@0 223 bool& aNeedsBold,
michael@0 224 bool& aWaitForUserFont)
michael@0 225 {
michael@0 226 aWaitForUserFont = false;
michael@0 227 gfxMixedFontFamily *family = static_cast<gfxMixedFontFamily*>(aFamily);
michael@0 228
michael@0 229 gfxFontEntry* fe = family->FindFontForStyle(aFontStyle, aNeedsBold);
michael@0 230
michael@0 231 // if not a proxy, font has already been loaded
michael@0 232 if (!fe->mIsProxy) {
michael@0 233 return fe;
michael@0 234 }
michael@0 235
michael@0 236 gfxProxyFontEntry *proxyEntry = static_cast<gfxProxyFontEntry*> (fe);
michael@0 237
michael@0 238 // if currently loading, return null for now
michael@0 239 if (proxyEntry->mLoadingState > gfxProxyFontEntry::NOT_LOADING) {
michael@0 240 aWaitForUserFont =
michael@0 241 (proxyEntry->mLoadingState < gfxProxyFontEntry::LOADING_SLOWLY);
michael@0 242 return nullptr;
michael@0 243 }
michael@0 244
michael@0 245 // hasn't been loaded yet, start the load process
michael@0 246 LoadStatus status;
michael@0 247
michael@0 248 // NOTE that if all sources in the entry fail, this will delete proxyEntry,
michael@0 249 // so we cannot use it again if status==STATUS_END_OF_LIST
michael@0 250 status = LoadNext(family, proxyEntry);
michael@0 251
michael@0 252 // if the load succeeded immediately, the font entry was replaced so
michael@0 253 // search again
michael@0 254 if (status == STATUS_LOADED) {
michael@0 255 return family->FindFontForStyle(aFontStyle, aNeedsBold);
michael@0 256 }
michael@0 257
michael@0 258 // check whether we should wait for load to complete before painting
michael@0 259 // a fallback font -- but not if all sources failed (bug 633500)
michael@0 260 aWaitForUserFont = (status != STATUS_END_OF_LIST) &&
michael@0 261 (proxyEntry->mLoadingState < gfxProxyFontEntry::LOADING_SLOWLY);
michael@0 262
michael@0 263 // if either loading or an error occurred, return null
michael@0 264 return nullptr;
michael@0 265 }
michael@0 266
michael@0 267 // Based on ots::ExpandingMemoryStream from ots-memory-stream.h,
michael@0 268 // adapted to use Mozilla allocators and to allow the final
michael@0 269 // memory buffer to be adopted by the client.
michael@0 270 class ExpandingMemoryStream : public ots::OTSStream {
michael@0 271 public:
michael@0 272 ExpandingMemoryStream(size_t initial, size_t limit)
michael@0 273 : mLength(initial), mLimit(limit), mOff(0) {
michael@0 274 mPtr = NS_Alloc(mLength);
michael@0 275 }
michael@0 276
michael@0 277 ~ExpandingMemoryStream() {
michael@0 278 NS_Free(mPtr);
michael@0 279 }
michael@0 280
michael@0 281 // return the buffer, and give up ownership of it
michael@0 282 // so the caller becomes responsible to call NS_Free
michael@0 283 // when finished with it
michael@0 284 void* forget() {
michael@0 285 void* p = mPtr;
michael@0 286 mPtr = nullptr;
michael@0 287 return p;
michael@0 288 }
michael@0 289
michael@0 290 bool WriteRaw(const void *data, size_t length) {
michael@0 291 if ((mOff + length > mLength) ||
michael@0 292 (mLength > std::numeric_limits<size_t>::max() - mOff)) {
michael@0 293 if (mLength == mLimit) {
michael@0 294 return false;
michael@0 295 }
michael@0 296 size_t newLength = (mLength + 1) * 2;
michael@0 297 if (newLength < mLength) {
michael@0 298 return false;
michael@0 299 }
michael@0 300 if (newLength > mLimit) {
michael@0 301 newLength = mLimit;
michael@0 302 }
michael@0 303 mPtr = NS_Realloc(mPtr, newLength);
michael@0 304 mLength = newLength;
michael@0 305 return WriteRaw(data, length);
michael@0 306 }
michael@0 307 std::memcpy(static_cast<char*>(mPtr) + mOff, data, length);
michael@0 308 mOff += length;
michael@0 309 return true;
michael@0 310 }
michael@0 311
michael@0 312 bool Seek(off_t position) {
michael@0 313 if (position < 0) {
michael@0 314 return false;
michael@0 315 }
michael@0 316 if (static_cast<size_t>(position) > mLength) {
michael@0 317 return false;
michael@0 318 }
michael@0 319 mOff = position;
michael@0 320 return true;
michael@0 321 }
michael@0 322
michael@0 323 off_t Tell() const {
michael@0 324 return mOff;
michael@0 325 }
michael@0 326
michael@0 327 private:
michael@0 328 void* mPtr;
michael@0 329 size_t mLength;
michael@0 330 const size_t mLimit;
michael@0 331 off_t mOff;
michael@0 332 };
michael@0 333
michael@0 334 static ots::TableAction
michael@0 335 OTSTableAction(uint32_t aTag, void *aUserData)
michael@0 336 {
michael@0 337 // preserve Graphite and SVG tables
michael@0 338 if (aTag == TRUETYPE_TAG('S', 'i', 'l', 'f') ||
michael@0 339 aTag == TRUETYPE_TAG('S', 'i', 'l', 'l') ||
michael@0 340 aTag == TRUETYPE_TAG('G', 'l', 'o', 'c') ||
michael@0 341 aTag == TRUETYPE_TAG('G', 'l', 'a', 't') ||
michael@0 342 aTag == TRUETYPE_TAG('F', 'e', 'a', 't') ||
michael@0 343 aTag == TRUETYPE_TAG('S', 'V', 'G', ' ')) {
michael@0 344 return ots::TABLE_ACTION_PASSTHRU;
michael@0 345 }
michael@0 346 return ots::TABLE_ACTION_DEFAULT;
michael@0 347 }
michael@0 348
michael@0 349 struct OTSCallbackUserData {
michael@0 350 gfxUserFontSet *mFontSet;
michael@0 351 gfxMixedFontFamily *mFamily;
michael@0 352 gfxProxyFontEntry *mProxy;
michael@0 353 };
michael@0 354
michael@0 355 /* static */ bool
michael@0 356 gfxUserFontSet::OTSMessage(void *aUserData, const char *format, ...)
michael@0 357 {
michael@0 358 va_list va;
michael@0 359 va_start(va, format);
michael@0 360
michael@0 361 // buf should be more than adequate for any message OTS generates,
michael@0 362 // so we don't worry about checking the result of vsnprintf()
michael@0 363 char buf[512];
michael@0 364 (void)vsnprintf(buf, sizeof(buf), format, va);
michael@0 365
michael@0 366 va_end(va);
michael@0 367
michael@0 368 OTSCallbackUserData *d = static_cast<OTSCallbackUserData*>(aUserData);
michael@0 369 d->mFontSet->LogMessage(d->mFamily, d->mProxy, buf);
michael@0 370
michael@0 371 return false;
michael@0 372 }
michael@0 373
michael@0 374 // Call the OTS library to sanitize an sfnt before attempting to use it.
michael@0 375 // Returns a newly-allocated block, or nullptr in case of fatal errors.
michael@0 376 const uint8_t*
michael@0 377 gfxUserFontSet::SanitizeOpenTypeData(gfxMixedFontFamily *aFamily,
michael@0 378 gfxProxyFontEntry *aProxy,
michael@0 379 const uint8_t* aData, uint32_t aLength,
michael@0 380 uint32_t& aSaneLength, bool aIsCompressed)
michael@0 381 {
michael@0 382 // limit output/expansion to 256MB
michael@0 383 ExpandingMemoryStream output(aIsCompressed ? aLength * 2 : aLength,
michael@0 384 1024 * 1024 * 256);
michael@0 385
michael@0 386 OTSCallbackUserData userData;
michael@0 387 userData.mFontSet = this;
michael@0 388 userData.mFamily = aFamily;
michael@0 389 userData.mProxy = aProxy;
michael@0 390
michael@0 391 ots::SetTableActionCallback(&OTSTableAction, nullptr);
michael@0 392 ots::SetMessageCallback(&gfxUserFontSet::OTSMessage, &userData);
michael@0 393
michael@0 394 if (ots::Process(&output, aData, aLength)) {
michael@0 395 aSaneLength = output.Tell();
michael@0 396 return static_cast<uint8_t*>(output.forget());
michael@0 397 } else {
michael@0 398 aSaneLength = 0;
michael@0 399 return nullptr;
michael@0 400 }
michael@0 401 }
michael@0 402
michael@0 403 static void
michael@0 404 StoreUserFontData(gfxFontEntry* aFontEntry, gfxProxyFontEntry* aProxy,
michael@0 405 bool aPrivate, const nsAString& aOriginalName,
michael@0 406 FallibleTArray<uint8_t>* aMetadata, uint32_t aMetaOrigLen)
michael@0 407 {
michael@0 408 if (!aFontEntry->mUserFontData) {
michael@0 409 aFontEntry->mUserFontData = new gfxUserFontData;
michael@0 410 }
michael@0 411 gfxUserFontData* userFontData = aFontEntry->mUserFontData;
michael@0 412 userFontData->mSrcIndex = aProxy->mSrcIndex;
michael@0 413 const gfxFontFaceSrc& src = aProxy->mSrcList[aProxy->mSrcIndex];
michael@0 414 if (src.mIsLocal) {
michael@0 415 userFontData->mLocalName = src.mLocalName;
michael@0 416 } else {
michael@0 417 userFontData->mURI = src.mURI;
michael@0 418 userFontData->mPrincipal = aProxy->mPrincipal;
michael@0 419 }
michael@0 420 userFontData->mPrivate = aPrivate;
michael@0 421 userFontData->mFormat = src.mFormatFlags;
michael@0 422 userFontData->mRealName = aOriginalName;
michael@0 423 if (aMetadata) {
michael@0 424 userFontData->mMetadata.SwapElements(*aMetadata);
michael@0 425 userFontData->mMetaOrigLen = aMetaOrigLen;
michael@0 426 }
michael@0 427 }
michael@0 428
michael@0 429 struct WOFFHeader {
michael@0 430 AutoSwap_PRUint32 signature;
michael@0 431 AutoSwap_PRUint32 flavor;
michael@0 432 AutoSwap_PRUint32 length;
michael@0 433 AutoSwap_PRUint16 numTables;
michael@0 434 AutoSwap_PRUint16 reserved;
michael@0 435 AutoSwap_PRUint32 totalSfntSize;
michael@0 436 AutoSwap_PRUint16 majorVersion;
michael@0 437 AutoSwap_PRUint16 minorVersion;
michael@0 438 AutoSwap_PRUint32 metaOffset;
michael@0 439 AutoSwap_PRUint32 metaCompLen;
michael@0 440 AutoSwap_PRUint32 metaOrigLen;
michael@0 441 AutoSwap_PRUint32 privOffset;
michael@0 442 AutoSwap_PRUint32 privLen;
michael@0 443 };
michael@0 444
michael@0 445 void
michael@0 446 gfxUserFontSet::CopyWOFFMetadata(const uint8_t* aFontData,
michael@0 447 uint32_t aLength,
michael@0 448 FallibleTArray<uint8_t>* aMetadata,
michael@0 449 uint32_t* aMetaOrigLen)
michael@0 450 {
michael@0 451 // This function may be called with arbitrary, unvalidated "font" data
michael@0 452 // from @font-face, so it needs to be careful to bounds-check, etc.,
michael@0 453 // before trying to read anything.
michael@0 454 // This just saves a copy of the compressed data block; it does NOT check
michael@0 455 // that the block can be successfully decompressed, or that it contains
michael@0 456 // well-formed/valid XML metadata.
michael@0 457 if (aLength < sizeof(WOFFHeader)) {
michael@0 458 return;
michael@0 459 }
michael@0 460 const WOFFHeader* woff = reinterpret_cast<const WOFFHeader*>(aFontData);
michael@0 461 uint32_t metaOffset = woff->metaOffset;
michael@0 462 uint32_t metaCompLen = woff->metaCompLen;
michael@0 463 if (!metaOffset || !metaCompLen || !woff->metaOrigLen) {
michael@0 464 return;
michael@0 465 }
michael@0 466 if (metaOffset >= aLength || metaCompLen > aLength - metaOffset) {
michael@0 467 return;
michael@0 468 }
michael@0 469 if (!aMetadata->SetLength(woff->metaCompLen)) {
michael@0 470 return;
michael@0 471 }
michael@0 472 memcpy(aMetadata->Elements(), aFontData + metaOffset, metaCompLen);
michael@0 473 *aMetaOrigLen = woff->metaOrigLen;
michael@0 474 }
michael@0 475
michael@0 476 // This is called when a font download finishes.
michael@0 477 // Ownership of aFontData passes in here, and the font set must
michael@0 478 // ensure that it is eventually deleted via NS_Free().
michael@0 479 bool
michael@0 480 gfxUserFontSet::OnLoadComplete(gfxMixedFontFamily *aFamily,
michael@0 481 gfxProxyFontEntry *aProxy,
michael@0 482 const uint8_t *aFontData, uint32_t aLength,
michael@0 483 nsresult aDownloadStatus)
michael@0 484 {
michael@0 485 // forget about the loader, as we no longer potentially need to cancel it
michael@0 486 // if the entry is obsoleted
michael@0 487 aProxy->mLoader = nullptr;
michael@0 488
michael@0 489 // download successful, make platform font using font data
michael@0 490 if (NS_SUCCEEDED(aDownloadStatus)) {
michael@0 491 gfxFontEntry *fe = LoadFont(aFamily, aProxy, aFontData, aLength);
michael@0 492 aFontData = nullptr;
michael@0 493
michael@0 494 if (fe) {
michael@0 495 IncrementGeneration();
michael@0 496 return true;
michael@0 497 }
michael@0 498
michael@0 499 } else {
michael@0 500 // download failed
michael@0 501 LogMessage(aFamily, aProxy,
michael@0 502 "download failed", nsIScriptError::errorFlag,
michael@0 503 aDownloadStatus);
michael@0 504 }
michael@0 505
michael@0 506 if (aFontData) {
michael@0 507 NS_Free((void*)aFontData);
michael@0 508 }
michael@0 509
michael@0 510 // error occurred, load next src
michael@0 511 (void)LoadNext(aFamily, aProxy);
michael@0 512
michael@0 513 // We ignore the status returned by LoadNext();
michael@0 514 // even if loading failed, we need to bump the font-set generation
michael@0 515 // and return true in order to trigger reflow, so that fallback
michael@0 516 // will be used where the text was "masked" by the pending download
michael@0 517 IncrementGeneration();
michael@0 518 return true;
michael@0 519 }
michael@0 520
michael@0 521
michael@0 522 gfxUserFontSet::LoadStatus
michael@0 523 gfxUserFontSet::LoadNext(gfxMixedFontFamily *aFamily,
michael@0 524 gfxProxyFontEntry *aProxyEntry)
michael@0 525 {
michael@0 526 uint32_t numSrc = aProxyEntry->mSrcList.Length();
michael@0 527
michael@0 528 NS_ASSERTION(aProxyEntry->mSrcIndex < numSrc,
michael@0 529 "already at the end of the src list for user font");
michael@0 530
michael@0 531 if (aProxyEntry->mLoadingState == gfxProxyFontEntry::NOT_LOADING) {
michael@0 532 aProxyEntry->mLoadingState = gfxProxyFontEntry::LOADING_STARTED;
michael@0 533 aProxyEntry->mUnsupportedFormat = false;
michael@0 534 } else {
michael@0 535 // we were already loading; move to the next source,
michael@0 536 // but don't reset state - if we've already timed out,
michael@0 537 // that counts against the new download
michael@0 538 aProxyEntry->mSrcIndex++;
michael@0 539 }
michael@0 540
michael@0 541 /* If there are any urls, prefer them to local */
michael@0 542 bool listHasURL = false;
michael@0 543 for (uint32_t i = aProxyEntry->mSrcIndex; i < numSrc; i++) {
michael@0 544 const gfxFontFaceSrc& currSrc = aProxyEntry->mSrcList[i];
michael@0 545 if (!currSrc.mIsLocal) {
michael@0 546 listHasURL = true;
michael@0 547 break;
michael@0 548 }
michael@0 549 }
michael@0 550 nsPresContext *pres = GetPresContext();
michael@0 551 /* If we have no pres context, simply fail this load */
michael@0 552 if (!pres) listHasURL = true;
michael@0 553
michael@0 554 // load each src entry in turn, until a local face is found
michael@0 555 // or a download begins successfully
michael@0 556 while (aProxyEntry->mSrcIndex < numSrc) {
michael@0 557 const gfxFontFaceSrc& currSrc = aProxyEntry->mSrcList[aProxyEntry->mSrcIndex];
michael@0 558
michael@0 559 // src local ==> lookup and load immediately
michael@0 560
michael@0 561 if (!listHasURL && currSrc.mIsLocal) {
michael@0 562 nsFont font;
michael@0 563 font.name = currSrc.mLocalName;
michael@0 564 gfxFontEntry *fe =
michael@0 565 gfxPlatform::GetPlatform()->LookupLocalFont(aProxyEntry,
michael@0 566 currSrc.mLocalName);
michael@0 567 pres->AddFontAttempt(font);
michael@0 568
michael@0 569 /* No more fonts for you */
michael@0 570 if (pres->FontAttemptCountReached(font) ||
michael@0 571 pres->FontUseCountReached(font)) {
michael@0 572 break;
michael@0 573 }
michael@0 574
michael@0 575 mLocalRulesUsed = true;
michael@0 576 if (fe) {
michael@0 577 pres->AddFontUse(font);
michael@0 578 LOG(("userfonts (%p) [src %d] loaded local: (%s) for (%s) gen: %8.8x\n",
michael@0 579 this, aProxyEntry->mSrcIndex,
michael@0 580 NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(),
michael@0 581 NS_ConvertUTF16toUTF8(aFamily->Name()).get(),
michael@0 582 uint32_t(mGeneration)));
michael@0 583 fe->mFeatureSettings.AppendElements(aProxyEntry->mFeatureSettings);
michael@0 584 fe->mLanguageOverride = aProxyEntry->mLanguageOverride;
michael@0 585 // For src:local(), we don't care whether the request is from
michael@0 586 // a private window as there's no issue of caching resources;
michael@0 587 // local fonts are just available all the time.
michael@0 588 StoreUserFontData(fe, aProxyEntry, false, nsString(), nullptr, 0);
michael@0 589 ReplaceFontEntry(aFamily, aProxyEntry, fe);
michael@0 590 return STATUS_LOADED;
michael@0 591 } else {
michael@0 592 LOG(("userfonts (%p) [src %d] failed local: (%s) for (%s)\n",
michael@0 593 this, aProxyEntry->mSrcIndex,
michael@0 594 NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(),
michael@0 595 NS_ConvertUTF16toUTF8(aFamily->Name()).get()));
michael@0 596 }
michael@0 597 }
michael@0 598
michael@0 599 // src url ==> start the load process
michael@0 600 else {
michael@0 601 if (gfxPlatform::GetPlatform()->IsFontFormatSupported(currSrc.mURI,
michael@0 602 currSrc.mFormatFlags)) {
michael@0 603
michael@0 604 nsIPrincipal *principal = nullptr;
michael@0 605 bool bypassCache;
michael@0 606 nsresult rv = CheckFontLoad(&currSrc, &principal, &bypassCache);
michael@0 607
michael@0 608 if (NS_SUCCEEDED(rv) && principal != nullptr) {
michael@0 609 if (!bypassCache) {
michael@0 610 // see if we have an existing entry for this source
michael@0 611 gfxFontEntry *fe =
michael@0 612 UserFontCache::GetFont(currSrc.mURI, principal,
michael@0 613 aProxyEntry,
michael@0 614 GetPrivateBrowsing());
michael@0 615 if (fe) {
michael@0 616 ReplaceFontEntry(aFamily, aProxyEntry, fe);
michael@0 617 return STATUS_LOADED;
michael@0 618 }
michael@0 619 }
michael@0 620
michael@0 621 // record the principal returned by CheckFontLoad,
michael@0 622 // for use when creating a channel
michael@0 623 // and when caching the loaded entry
michael@0 624 aProxyEntry->mPrincipal = principal;
michael@0 625
michael@0 626 bool loadDoesntSpin = false;
michael@0 627 rv = NS_URIChainHasFlags(currSrc.mURI,
michael@0 628 nsIProtocolHandler::URI_SYNC_LOAD_IS_OK,
michael@0 629 &loadDoesntSpin);
michael@0 630 if (NS_SUCCEEDED(rv) && loadDoesntSpin) {
michael@0 631 uint8_t *buffer = nullptr;
michael@0 632 uint32_t bufferLength = 0;
michael@0 633
michael@0 634 // sync load font immediately
michael@0 635 rv = SyncLoadFontData(aProxyEntry, &currSrc,
michael@0 636 buffer, bufferLength);
michael@0 637 if (NS_SUCCEEDED(rv) && LoadFont(aFamily, aProxyEntry,
michael@0 638 buffer, bufferLength)) {
michael@0 639 return STATUS_LOADED;
michael@0 640 } else {
michael@0 641 LogMessage(aFamily, aProxyEntry,
michael@0 642 "font load failed",
michael@0 643 nsIScriptError::errorFlag, rv);
michael@0 644 }
michael@0 645 } else {
michael@0 646 // otherwise load font async
michael@0 647 rv = StartLoad(aFamily, aProxyEntry, &currSrc);
michael@0 648 if (NS_SUCCEEDED(rv)) {
michael@0 649 #ifdef PR_LOGGING
michael@0 650 if (LOG_ENABLED()) {
michael@0 651 nsAutoCString fontURI;
michael@0 652 currSrc.mURI->GetSpec(fontURI);
michael@0 653 LOG(("userfonts (%p) [src %d] loading uri: (%s) for (%s)\n",
michael@0 654 this, aProxyEntry->mSrcIndex, fontURI.get(),
michael@0 655 NS_ConvertUTF16toUTF8(aFamily->Name()).get()));
michael@0 656 }
michael@0 657 #endif
michael@0 658 return STATUS_LOADING;
michael@0 659 } else {
michael@0 660 LogMessage(aFamily, aProxyEntry,
michael@0 661 "download failed",
michael@0 662 nsIScriptError::errorFlag, rv);
michael@0 663 }
michael@0 664 }
michael@0 665 } else {
michael@0 666 LogMessage(aFamily, aProxyEntry, "download not allowed",
michael@0 667 nsIScriptError::errorFlag, rv);
michael@0 668 }
michael@0 669 } else {
michael@0 670 // We don't log a warning to the web console yet,
michael@0 671 // as another source may load successfully
michael@0 672 aProxyEntry->mUnsupportedFormat = true;
michael@0 673 }
michael@0 674 }
michael@0 675
michael@0 676 aProxyEntry->mSrcIndex++;
michael@0 677 }
michael@0 678
michael@0 679 if (aProxyEntry->mUnsupportedFormat) {
michael@0 680 LogMessage(aFamily, aProxyEntry, "no supported format found",
michael@0 681 nsIScriptError::warningFlag);
michael@0 682 }
michael@0 683
michael@0 684 // all src's failed; mark this entry as unusable (so fallback will occur)
michael@0 685 LOG(("userfonts (%p) failed all src for (%s)\n",
michael@0 686 this, NS_ConvertUTF16toUTF8(aFamily->Name()).get()));
michael@0 687 aProxyEntry->mLoadingState = gfxProxyFontEntry::LOADING_FAILED;
michael@0 688
michael@0 689 return STATUS_END_OF_LIST;
michael@0 690 }
michael@0 691
michael@0 692 void
michael@0 693 gfxUserFontSet::IncrementGeneration()
michael@0 694 {
michael@0 695 // add one, increment again if zero
michael@0 696 ++sFontSetGeneration;
michael@0 697 if (sFontSetGeneration == 0)
michael@0 698 ++sFontSetGeneration;
michael@0 699 mGeneration = sFontSetGeneration;
michael@0 700 }
michael@0 701
michael@0 702 void
michael@0 703 gfxUserFontSet::RebuildLocalRules()
michael@0 704 {
michael@0 705 if (mLocalRulesUsed) {
michael@0 706 DoRebuildUserFontSet();
michael@0 707 }
michael@0 708 }
michael@0 709
michael@0 710 gfxFontEntry*
michael@0 711 gfxUserFontSet::LoadFont(gfxMixedFontFamily *aFamily,
michael@0 712 gfxProxyFontEntry *aProxy,
michael@0 713 const uint8_t *aFontData, uint32_t &aLength)
michael@0 714 {
michael@0 715 gfxFontEntry *fe = nullptr;
michael@0 716
michael@0 717 gfxUserFontType fontType =
michael@0 718 gfxFontUtils::DetermineFontDataType(aFontData, aLength);
michael@0 719
michael@0 720 // Unwrap/decompress/sanitize or otherwise munge the downloaded data
michael@0 721 // to make a usable sfnt structure.
michael@0 722
michael@0 723 // Because platform font activation code may replace the name table
michael@0 724 // in the font with a synthetic one, we save the original name so that
michael@0 725 // it can be reported via the nsIDOMFontFace API.
michael@0 726 nsAutoString originalFullName;
michael@0 727
michael@0 728 // Call the OTS sanitizer; this will also decode WOFF to sfnt
michael@0 729 // if necessary. The original data in aFontData is left unchanged.
michael@0 730 uint32_t saneLen;
michael@0 731 const uint8_t* saneData =
michael@0 732 SanitizeOpenTypeData(aFamily, aProxy, aFontData, aLength, saneLen,
michael@0 733 fontType == GFX_USERFONT_WOFF);
michael@0 734 if (!saneData) {
michael@0 735 LogMessage(aFamily, aProxy, "rejected by sanitizer");
michael@0 736 }
michael@0 737 if (saneData) {
michael@0 738 // The sanitizer ensures that we have a valid sfnt and a usable
michael@0 739 // name table, so this should never fail unless we're out of
michael@0 740 // memory, and GetFullNameFromSFNT is not directly exposed to
michael@0 741 // arbitrary/malicious data from the web.
michael@0 742 gfxFontUtils::GetFullNameFromSFNT(saneData, saneLen,
michael@0 743 originalFullName);
michael@0 744 // Here ownership of saneData is passed to the platform,
michael@0 745 // which will delete it when no longer required
michael@0 746 fe = gfxPlatform::GetPlatform()->MakePlatformFont(aProxy,
michael@0 747 saneData,
michael@0 748 saneLen);
michael@0 749 if (!fe) {
michael@0 750 LogMessage(aFamily, aProxy, "not usable by platform");
michael@0 751 }
michael@0 752 }
michael@0 753
michael@0 754 if (fe) {
michael@0 755 // Save a copy of the metadata block (if present) for nsIDOMFontFace
michael@0 756 // to use if required. Ownership of the metadata block will be passed
michael@0 757 // to the gfxUserFontData record below.
michael@0 758 FallibleTArray<uint8_t> metadata;
michael@0 759 uint32_t metaOrigLen = 0;
michael@0 760 if (fontType == GFX_USERFONT_WOFF) {
michael@0 761 CopyWOFFMetadata(aFontData, aLength, &metadata, &metaOrigLen);
michael@0 762 }
michael@0 763
michael@0 764 // copy OpenType feature/language settings from the proxy to the
michael@0 765 // newly-created font entry
michael@0 766 fe->mFeatureSettings.AppendElements(aProxy->mFeatureSettings);
michael@0 767 fe->mLanguageOverride = aProxy->mLanguageOverride;
michael@0 768 StoreUserFontData(fe, aProxy, GetPrivateBrowsing(),
michael@0 769 originalFullName, &metadata, metaOrigLen);
michael@0 770 #ifdef PR_LOGGING
michael@0 771 if (LOG_ENABLED()) {
michael@0 772 nsAutoCString fontURI;
michael@0 773 aProxy->mSrcList[aProxy->mSrcIndex].mURI->GetSpec(fontURI);
michael@0 774 LOG(("userfonts (%p) [src %d] loaded uri: (%s) for (%s) gen: %8.8x\n",
michael@0 775 this, aProxy->mSrcIndex, fontURI.get(),
michael@0 776 NS_ConvertUTF16toUTF8(aFamily->Name()).get(),
michael@0 777 uint32_t(mGeneration)));
michael@0 778 }
michael@0 779 #endif
michael@0 780 ReplaceFontEntry(aFamily, aProxy, fe);
michael@0 781 UserFontCache::CacheFont(fe);
michael@0 782 } else {
michael@0 783 #ifdef PR_LOGGING
michael@0 784 if (LOG_ENABLED()) {
michael@0 785 nsAutoCString fontURI;
michael@0 786 aProxy->mSrcList[aProxy->mSrcIndex].mURI->GetSpec(fontURI);
michael@0 787 LOG(("userfonts (%p) [src %d] failed uri: (%s) for (%s)"
michael@0 788 " error making platform font\n",
michael@0 789 this, aProxy->mSrcIndex, fontURI.get(),
michael@0 790 NS_ConvertUTF16toUTF8(aFamily->Name()).get()));
michael@0 791 }
michael@0 792 #endif
michael@0 793 }
michael@0 794
michael@0 795 // The downloaded data can now be discarded; the font entry is using the
michael@0 796 // sanitized copy
michael@0 797 NS_Free((void*)aFontData);
michael@0 798
michael@0 799 return fe;
michael@0 800 }
michael@0 801
michael@0 802 gfxFontFamily*
michael@0 803 gfxUserFontSet::GetFamily(const nsAString& aFamilyName) const
michael@0 804 {
michael@0 805 nsAutoString key(aFamilyName);
michael@0 806 ToLowerCase(key);
michael@0 807
michael@0 808 return mFontFamilies.GetWeak(key);
michael@0 809 }
michael@0 810
michael@0 811 struct FindFamilyCallbackData {
michael@0 812 gfxFontEntry *mFontEntry;
michael@0 813 gfxFontFamily *mFamily;
michael@0 814 };
michael@0 815
michael@0 816 static PLDHashOperator
michael@0 817 FindFamilyCallback(const nsAString& aName,
michael@0 818 gfxMixedFontFamily* aFamily,
michael@0 819 void* aUserArg)
michael@0 820 {
michael@0 821 FindFamilyCallbackData *d = static_cast<FindFamilyCallbackData*>(aUserArg);
michael@0 822 if (aFamily->ContainsFace(d->mFontEntry)) {
michael@0 823 d->mFamily = aFamily;
michael@0 824 return PL_DHASH_STOP;
michael@0 825 }
michael@0 826
michael@0 827 return PL_DHASH_NEXT;
michael@0 828 }
michael@0 829
michael@0 830 gfxFontFamily*
michael@0 831 gfxUserFontSet::FindFamilyFor(gfxFontEntry* aFontEntry) const
michael@0 832 {
michael@0 833 FindFamilyCallbackData d = { aFontEntry, nullptr };
michael@0 834 mFontFamilies.EnumerateRead(FindFamilyCallback, &d);
michael@0 835 return d.mFamily;
michael@0 836 }
michael@0 837
michael@0 838 ///////////////////////////////////////////////////////////////////////////////
michael@0 839 // gfxUserFontSet::UserFontCache - re-use platform font entries for user fonts
michael@0 840 // across pages/fontsets rather than instantiating new platform fonts.
michael@0 841 //
michael@0 842 // Entries are added to this cache when a platform font is instantiated from
michael@0 843 // downloaded data, and removed when the platform font entry is destroyed.
michael@0 844 // We don't need to use a timed expiration scheme here because the gfxFontEntry
michael@0 845 // for a downloaded font will be kept alive by its corresponding gfxFont
michael@0 846 // instance(s) until they are deleted, and *that* happens using an expiration
michael@0 847 // tracker (gfxFontCache). The result is that the downloaded font instances
michael@0 848 // recorded here will persist between pages and can get reused (provided the
michael@0 849 // source URI and principal match, of course).
michael@0 850 ///////////////////////////////////////////////////////////////////////////////
michael@0 851
michael@0 852 nsTHashtable<gfxUserFontSet::UserFontCache::Entry>*
michael@0 853 gfxUserFontSet::UserFontCache::sUserFonts = nullptr;
michael@0 854
michael@0 855 NS_IMPL_ISUPPORTS(gfxUserFontSet::UserFontCache::Flusher, nsIObserver)
michael@0 856
michael@0 857 PLDHashOperator
michael@0 858 gfxUserFontSet::UserFontCache::Entry::RemoveIfPrivate(Entry* aEntry,
michael@0 859 void* aUserData)
michael@0 860 {
michael@0 861 return aEntry->mPrivate ? PL_DHASH_REMOVE : PL_DHASH_NEXT;
michael@0 862 }
michael@0 863
michael@0 864 PLDHashOperator
michael@0 865 gfxUserFontSet::UserFontCache::Entry::RemoveIfMatches(Entry* aEntry,
michael@0 866 void* aUserData)
michael@0 867 {
michael@0 868 return aEntry->GetFontEntry() == static_cast<gfxFontEntry*>(aUserData) ?
michael@0 869 PL_DHASH_REMOVE : PL_DHASH_NEXT;
michael@0 870 }
michael@0 871
michael@0 872 PLDHashOperator
michael@0 873 gfxUserFontSet::UserFontCache::Entry::DisconnectSVG(Entry* aEntry,
michael@0 874 void* aUserData)
michael@0 875 {
michael@0 876 aEntry->GetFontEntry()->DisconnectSVG();
michael@0 877 return PL_DHASH_NEXT;
michael@0 878 }
michael@0 879
michael@0 880 NS_IMETHODIMP
michael@0 881 gfxUserFontSet::UserFontCache::Flusher::Observe(nsISupports* aSubject,
michael@0 882 const char* aTopic,
michael@0 883 const char16_t* aData)
michael@0 884 {
michael@0 885 if (!sUserFonts) {
michael@0 886 return NS_OK;
michael@0 887 }
michael@0 888
michael@0 889 if (!strcmp(aTopic, NS_CACHESERVICE_EMPTYCACHE_TOPIC_ID)) {
michael@0 890 sUserFonts->Clear();
michael@0 891 } else if (!strcmp(aTopic, "last-pb-context-exited")) {
michael@0 892 sUserFonts->EnumerateEntries(Entry::RemoveIfPrivate, nullptr);
michael@0 893 } else if (!strcmp(aTopic, "xpcom-shutdown")) {
michael@0 894 sUserFonts->EnumerateEntries(Entry::DisconnectSVG, nullptr);
michael@0 895 } else {
michael@0 896 NS_NOTREACHED("unexpected topic");
michael@0 897 }
michael@0 898
michael@0 899 return NS_OK;
michael@0 900 }
michael@0 901
michael@0 902 bool
michael@0 903 gfxUserFontSet::UserFontCache::Entry::KeyEquals(const KeyTypePointer aKey) const
michael@0 904 {
michael@0 905 bool equal;
michael@0 906 if (NS_FAILED(mURI->Equals(aKey->mURI, &equal)) || !equal) {
michael@0 907 return false;
michael@0 908 }
michael@0 909
michael@0 910 if (NS_FAILED(mPrincipal->Equals(aKey->mPrincipal, &equal)) || !equal) {
michael@0 911 return false;
michael@0 912 }
michael@0 913
michael@0 914 if (mPrivate != aKey->mPrivate) {
michael@0 915 return false;
michael@0 916 }
michael@0 917
michael@0 918 const gfxFontEntry *fe = aKey->mFontEntry;
michael@0 919 if (mFontEntry->mItalic != fe->mItalic ||
michael@0 920 mFontEntry->mWeight != fe->mWeight ||
michael@0 921 mFontEntry->mStretch != fe->mStretch ||
michael@0 922 mFontEntry->mFeatureSettings != fe->mFeatureSettings ||
michael@0 923 mFontEntry->mLanguageOverride != fe->mLanguageOverride ||
michael@0 924 mFontEntry->mFamilyName != fe->mFamilyName) {
michael@0 925 return false;
michael@0 926 }
michael@0 927
michael@0 928 return true;
michael@0 929 }
michael@0 930
michael@0 931 void
michael@0 932 gfxUserFontSet::UserFontCache::CacheFont(gfxFontEntry *aFontEntry)
michael@0 933 {
michael@0 934 NS_ASSERTION(aFontEntry->mFamilyName.Length() != 0,
michael@0 935 "caching a font associated with no family yet");
michael@0 936 if (!sUserFonts) {
michael@0 937 sUserFonts = new nsTHashtable<Entry>;
michael@0 938
michael@0 939 nsCOMPtr<nsIObserverService> obs =
michael@0 940 mozilla::services::GetObserverService();
michael@0 941 if (obs) {
michael@0 942 Flusher *flusher = new Flusher;
michael@0 943 obs->AddObserver(flusher, NS_CACHESERVICE_EMPTYCACHE_TOPIC_ID,
michael@0 944 false);
michael@0 945 obs->AddObserver(flusher, "last-pb-context-exited", false);
michael@0 946 obs->AddObserver(flusher, "xpcom-shutdown", false);
michael@0 947 }
michael@0 948 }
michael@0 949
michael@0 950 gfxUserFontData *data = aFontEntry->mUserFontData;
michael@0 951 sUserFonts->PutEntry(Key(data->mURI, data->mPrincipal, aFontEntry,
michael@0 952 data->mPrivate));
michael@0 953
michael@0 954 #ifdef DEBUG_USERFONT_CACHE
michael@0 955 printf("userfontcache added fontentry: %p\n", aFontEntry);
michael@0 956 Dump();
michael@0 957 #endif
michael@0 958 }
michael@0 959
michael@0 960 void
michael@0 961 gfxUserFontSet::UserFontCache::ForgetFont(gfxFontEntry *aFontEntry)
michael@0 962 {
michael@0 963 if (!sUserFonts) {
michael@0 964 // if we've already deleted the cache (i.e. during shutdown),
michael@0 965 // just ignore this
michael@0 966 return;
michael@0 967 }
michael@0 968
michael@0 969 // We can't simply use RemoveEntry here because it's possible the principal
michael@0 970 // may have changed since the font was cached, in which case the lookup
michael@0 971 // would no longer find the entry (bug 838105).
michael@0 972 sUserFonts->EnumerateEntries(
michael@0 973 gfxUserFontSet::UserFontCache::Entry::RemoveIfMatches, aFontEntry);
michael@0 974
michael@0 975 #ifdef DEBUG_USERFONT_CACHE
michael@0 976 printf("userfontcache removed fontentry: %p\n", aFontEntry);
michael@0 977 Dump();
michael@0 978 #endif
michael@0 979 }
michael@0 980
michael@0 981 gfxFontEntry*
michael@0 982 gfxUserFontSet::UserFontCache::GetFont(nsIURI *aSrcURI,
michael@0 983 nsIPrincipal *aPrincipal,
michael@0 984 gfxProxyFontEntry *aProxy,
michael@0 985 bool aPrivate)
michael@0 986 {
michael@0 987 if (!sUserFonts) {
michael@0 988 return nullptr;
michael@0 989 }
michael@0 990
michael@0 991 Entry* entry = sUserFonts->GetEntry(Key(aSrcURI, aPrincipal, aProxy,
michael@0 992 aPrivate));
michael@0 993 if (entry) {
michael@0 994 return entry->GetFontEntry();
michael@0 995 }
michael@0 996
michael@0 997 return nullptr;
michael@0 998 }
michael@0 999
michael@0 1000 void
michael@0 1001 gfxUserFontSet::UserFontCache::Shutdown()
michael@0 1002 {
michael@0 1003 if (sUserFonts) {
michael@0 1004 delete sUserFonts;
michael@0 1005 sUserFonts = nullptr;
michael@0 1006 }
michael@0 1007 }
michael@0 1008
michael@0 1009 #ifdef DEBUG_USERFONT_CACHE
michael@0 1010
michael@0 1011 PLDHashOperator
michael@0 1012 gfxUserFontSet::UserFontCache::Entry::DumpEntry(Entry* aEntry, void* aUserData)
michael@0 1013 {
michael@0 1014 nsresult rv;
michael@0 1015
michael@0 1016 nsAutoCString principalURISpec;
michael@0 1017
michael@0 1018 nsCOMPtr<nsIURI> principalURI;
michael@0 1019 rv = aEntry->mPrincipal->GetURI(getter_AddRefs(principalURI));
michael@0 1020 if (NS_SUCCEEDED(rv)) {
michael@0 1021 principalURI->GetSpec(principalURISpec);
michael@0 1022 }
michael@0 1023
michael@0 1024 bool setDomain = false;
michael@0 1025 nsCOMPtr<nsIURI> domainURI;
michael@0 1026
michael@0 1027 aEntry->mPrincipal->GetDomain(getter_AddRefs(domainURI));
michael@0 1028 if (domainURI) {
michael@0 1029 setDomain = true;
michael@0 1030 }
michael@0 1031
michael@0 1032 NS_ASSERTION(aEntry->mURI, "null URI in userfont cache entry");
michael@0 1033
michael@0 1034 printf("userfontcache fontEntry: %p fonturihash: %8.8x family: %s domainset: %s principal: [%s]\n",
michael@0 1035 aEntry->mFontEntry,
michael@0 1036 nsURIHashKey::HashKey(aEntry->mURI),
michael@0 1037 NS_ConvertUTF16toUTF8(aEntry->mFontEntry->FamilyName()).get(),
michael@0 1038 (setDomain ? "true" : "false"),
michael@0 1039 principalURISpec.get()
michael@0 1040 );
michael@0 1041 return PL_DHASH_NEXT;
michael@0 1042 }
michael@0 1043
michael@0 1044 void
michael@0 1045 gfxUserFontSet::UserFontCache::Dump()
michael@0 1046 {
michael@0 1047 if (!sUserFonts) {
michael@0 1048 return;
michael@0 1049 }
michael@0 1050
michael@0 1051 printf("userfontcache dump count: %d ========\n", sUserFonts->Count());
michael@0 1052 sUserFonts->EnumerateEntries(Entry::DumpEntry, nullptr);
michael@0 1053 printf("userfontcache dump ==================\n");
michael@0 1054 }
michael@0 1055
michael@0 1056 #endif

mercurial