/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// The Init and Destroy methods are necessary because it's not // safe to call AddObserver from a constructor or RemoveObserver // from a destructor. That should be fixed. void nsFontCache::Init(nsPresContext* aContext) {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
mContext = aContext; // register as a memory-pressure observer to free font resources // in low-memory situations.
nsCOMPtr<nsIObserverService> obs = GetObserverService(); if (obs) {
obs->AddObserver(this, "memory-pressure", false);
}
already_AddRefed<nsFontMetrics> nsFontCache::GetMetricsFor( const nsFont& aFont, const nsFontMetrics::Params& aParams) { // We may eventually want to put an nsFontCache on canvas2d workers, but for // now it is only used by the main-thread layout code and stylo.
mozilla::AssertIsMainThreadOrServoFontMetricsLocked();
nsAtom* language = aParams.language && !aParams.language->IsEmpty()
? aParams.language
: mLocaleLanguage.get();
// First check our cache // start from the end, which is where we put the most-recent-used element const int32_t n = mFontMetrics.Length() - 1; for (int32_t i = n; i >= 0; --i) {
nsFontMetrics* fm = mFontMetrics.Elements()[i]; if (fm->Font().Equals(aFont) &&
fm->GetUserFontSet() == aParams.userFontSet &&
fm->Language() == language &&
fm->Orientation() == aParams.orientation && #ifdef XP_WIN
fm->AllowForceGDIClassic() == aParams.allowForceGDIClassic && #endif
fm->ExplicitLanguage() == aParams.explicitLanguage) { if (i != n) { // promote it to the end of the cache
mFontMetrics.RemoveElementAtUnsafe(i);
mFontMetrics.AppendElement(fm);
}
fm->GetThebesFontGroup()->UpdateUserFonts(); return do_AddRef(fm);
}
}
if (!mReportedProbableFingerprinting) { // We try to detect font fingerprinting attempts by recognizing a large // number of cache misses in a short amount of time, which indicates the // usage of an unreasonable amount of different fonts by the web page.
PRTime now = PR_Now(); if (now - mLastCacheMiss > kFingerprintingTimeout) {
mCacheMisses = 0;
}
mCacheMisses++;
mLastCacheMiss = now; if (NS_IsMainThread() && mCacheMisses > kFingerprintingCacheMissThreshold) {
mContext->Document()->RecordFontFingerprinting();
mReportedProbableFingerprinting = true;
}
}
// It's not in the cache. Get font metrics and then cache them. // If the cache has reached its size limit, drop the older half of the // entries; but if we're on a stylo thread (the usual case), we have // to post a task back to the main thread to do the flush. if (n >= kMaxCacheEntries - 1 && !mFlushPending) { if (NS_IsMainThread()) {
Flush(mFontMetrics.Length() - kMaxCacheEntries / 2);
} else {
mFlushPending = true;
nsCOMPtr<nsIRunnable> flushTask = new FlushFontMetricsTask(this);
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(flushTask));
}
}
nsFontMetrics::Params params = aParams;
params.language = language;
RefPtr<nsFontMetrics> fm = new nsFontMetrics(aFont, params, mContext); // the mFontMetrics list has the "head" at the end, because append // is cheaper than insert
mFontMetrics.AppendElement(do_AddRef(fm).take()); return fm.forget();
}
void nsFontCache::UpdateUserFonts(gfxUserFontSet* aUserFontSet) {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread()); for (nsFontMetrics* fm : mFontMetrics) {
gfxFontGroup* fg = fm->GetThebesFontGroup(); if (fg->GetUserFontSet() == aUserFontSet) {
fg->UpdateUserFonts();
}
}
}
void nsFontCache::Compact() {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread()); // Need to loop backward because the running element can be removed on // the way for (int32_t i = mFontMetrics.Length() - 1; i >= 0; --i) {
nsFontMetrics* fm = mFontMetrics[i];
nsFontMetrics* oldfm = fm; // Destroy() isn't here because we want our device context to be // notified
NS_RELEASE(fm); // this will reset fm to nullptr // if the font is really gone, it would have called back in // FontMetricsDeleted() and would have removed itself if (mFontMetrics.IndexOf(oldfm) != mFontMetrics.NoIndex) { // nope, the font is still there, so let's hold onto it too
NS_ADDREF(oldfm);
}
}
}
// Flush the aFlushCount oldest entries, or all if (aFlushCount < 0) void nsFontCache::Flush(int32_t aFlushCount) {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
int32_t n = aFlushCount < 0
? mFontMetrics.Length()
: std::min<int32_t>(aFlushCount, mFontMetrics.Length()); for (int32_t i = n - 1; i >= 0; --i) {
nsFontMetrics* fm = mFontMetrics[i]; // Destroy() will unhook our device context from the fm so that we // won't waste time in triggering the notification of // FontMetricsDeleted() in the subsequent release
fm->Destroy();
NS_RELEASE(fm);
}
mFontMetrics.RemoveElementsAt(0, n);
mLastCacheMiss = 0;
mCacheMisses = 0;
}
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.