Backed out 7 changesets (bug 1599160) for damp failures. CLOSED TREE

Backed out changeset edb0e17f3c98 (bug 1599160)
Backed out changeset 64b42ac358e6 (bug 1599160)
Backed out changeset ce1521b895e1 (bug 1599160)
Backed out changeset 0b0ff0ad8db7 (bug 1599160)
Backed out changeset c7ef05dae614 (bug 1599160)
Backed out changeset 466cfd0ad5db (bug 1599160)
Backed out changeset b3f28494f0e7 (bug 1599160)
This commit is contained in:
Razvan Maries 2020-06-12 02:40:38 +03:00
Родитель 33374e402c
Коммит 7b30d6e82e
39 изменённых файлов: 842 добавлений и 1484 удалений

Просмотреть файл

@ -172,8 +172,6 @@ async function doTest(aBrowser) {
};
await SpecialPowers.spawn(aBrowser, [argObj], async function(arg) {
content.windowUtils.clearSharedStyleSheetCache();
let videoURL = arg.urlPrefix + "file_thirdPartyChild.video.ogv";
let audioURL = arg.urlPrefix + "file_thirdPartyChild.audio.ogg";
let trackURL = arg.urlPrefix + "file_thirdPartyChild.track.vtt";

Просмотреть файл

@ -2352,6 +2352,10 @@ nsresult Document::Init() {
static_cast<nsIMutationObserver*>(this));
mOnloadBlocker = new OnloadBlocker();
mCSSLoader = new css::Loader(this);
// Assume we're not quirky, until we know otherwise
mCSSLoader->SetCompatibilityMode(eCompatibility_FullStandards);
mStyleImageLoader = new css::ImageLoader(this);
mNodeInfoManager = new nsNodeInfoManager();
@ -2366,10 +2370,6 @@ nsresult Document::Init() {
NS_ASSERTION(OwnerDoc() == this, "Our nodeinfo is busted!");
mCSSLoader = new css::Loader(this);
// Assume we're not quirky, until we know otherwise
mCSSLoader->SetCompatibilityMode(eCompatibility_FullStandards);
// If after creation the owner js global is not set for a document
// we use the default compartment for this document, instead of creating
// wrapper in some random compartment when the document is exposed to js
@ -3727,14 +3727,9 @@ void Document::SetPrincipals(nsIPrincipal* aNewPrincipal,
mAllowDNSPrefetch = false;
}
}
mCSSLoader->DeregisterFromSheetCache();
mNodeInfoManager->SetDocumentPrincipal(aNewPrincipal);
mPartitionedPrincipal = aNewPartitionedPrincipal;
mCSSLoader->RegisterInSheetCache();
ContentBlockingAllowList::ComputePrincipal(
aNewPrincipal, getter_AddRefs(mContentBlockingAllowListPrincipal));

Просмотреть файл

@ -153,7 +153,6 @@
#include "nsHTMLTags.h"
#include "nsIAnonymousContentCreator.h"
#include "nsIAsyncVerifyRedirectCallback.h"
#include "nsICacheInfoChannel.h"
#include "nsICategoryManager.h"
#include "nsIChannelEventSink.h"
#include "nsIConsoleService.h"
@ -10358,37 +10357,3 @@ ScreenIntMargin nsContentUtils::GetWindowSafeAreaInsets(
return windowSafeAreaInsets;
}
/* static */
nsContentUtils::SubresourceCacheValidationInfo
nsContentUtils::GetSubresourceCacheValidationInfo(nsIRequest* aRequest) {
SubresourceCacheValidationInfo info;
if (nsCOMPtr<nsICacheInfoChannel> cache = do_QueryInterface(aRequest)) {
uint32_t value = 0;
if (NS_SUCCEEDED(cache->GetCacheTokenExpirationTime(&value))) {
info.mExpirationTime.emplace(value);
}
}
// Determine whether the cache entry must be revalidated when we try to use
// it. Currently, only HTTP specifies this information...
if (nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest)) {
Unused << httpChannel->IsNoStoreResponse(&info.mMustRevalidate);
if (!info.mMustRevalidate) {
Unused << httpChannel->IsNoCacheResponse(&info.mMustRevalidate);
}
// FIXME(bug 1644173): Why this check?
if (!info.mMustRevalidate) {
nsAutoCString cacheHeader;
Unused << httpChannel->GetResponseHeader(
NS_LITERAL_CSTRING("Cache-Control"), cacheHeader);
if (PL_strcasestr(cacheHeader.get(), "must-revalidate")) {
info.mMustRevalidate = true;
}
}
}
return info;
}

Просмотреть файл

@ -48,7 +48,6 @@
#include "mozilla/dom/Document.h"
#include "nsPIDOMWindow.h"
#include "nsRFPService.h"
#include "prtime.h"
#if defined(XP_WIN)
// Undefine LoadImage to prevent naming conflict with Windows.
@ -3247,23 +3246,6 @@ class nsContentUtils {
nsIScreen* aScreen, const mozilla::ScreenIntMargin& aSafeareaInsets,
const mozilla::LayoutDeviceIntRect& aWindowRect);
struct SubresourceCacheValidationInfo {
// The expiration time, in seconds, if known.
Maybe<uint32_t> mExpirationTime;
bool mMustRevalidate = false;
};
/**
* Gets cache validation info for subresources such as images or CSS
* stylesheets.
*/
static SubresourceCacheValidationInfo GetSubresourceCacheValidationInfo(
nsIRequest*);
static uint32_t SecondsFromPRTime(PRTime aTime) {
return uint32_t(int64_t(aTime) / int64_t(PR_USEC_PER_SEC));
}
private:
static bool InitializeEventTable();

Просмотреть файл

@ -25,7 +25,6 @@
#include "mozilla/dom/Touch.h"
#include "mozilla/dom/UserActivation.h"
#include "mozilla/PendingAnimationTracker.h"
#include "mozilla/SharedStyleSheetCache.h"
#include "nsIObjectLoadingContent.h"
#include "nsFrame.h"
#include "mozilla/layers/APZCCallbackHelper.h"
@ -988,23 +987,6 @@ nsDOMWindowUtils::SuppressAnimation(bool aSuppress) {
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::ClearSharedStyleSheetCache() {
SharedStyleSheetCache::ClearForTest();
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetParsedStyleSheets(uint32_t* aSheets) {
RefPtr<Document> doc = GetDocument();
if (!doc) {
return NS_ERROR_UNEXPECTED;
}
*aSheets = doc->CSSLoader()->ParsedSheetCount();
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::ClearNativeTouchSequence(nsIObserver* aObserver) {
nsCOMPtr<nsIWidget> widget = GetWidget();

Просмотреть файл

@ -655,17 +655,6 @@ interface nsIDOMWindowUtils : nsISupports {
*/
void clearNativeTouchSequence([optional] in nsIObserver aObserver);
/**
* Clears the SharedStyleSheetCache.
*/
void clearSharedStyleSheetCache();
/**
* Returns the number of stylesheets that have been parsed on this document.
* Useful to test caching.
*/
readonly attribute unsigned long parsedStyleSheets;
/**
* See nsIWidget::ActivateNativeMenuItemAt
*

Просмотреть файл

@ -147,18 +147,15 @@ void PerformanceMainThread::AddEntry(nsIHttpChannel* channel,
if (!performanceTimingData) {
return;
}
AddRawEntry(std::move(performanceTimingData), initiatorType, entryName);
}
void PerformanceMainThread::AddRawEntry(UniquePtr<PerformanceTimingData> aData,
const nsAString& aInitiatorType,
const nsAString& aEntryName) {
// The PerformanceResourceTiming object will use the PerformanceTimingData
// object to get all the required timings.
auto entry =
MakeRefPtr<PerformanceResourceTiming>(std::move(aData), this, aEntryName);
entry->SetInitiatorType(aInitiatorType);
InsertResourceEntry(entry);
RefPtr<PerformanceResourceTiming> performanceEntry =
new PerformanceResourceTiming(std::move(performanceTimingData), this,
entryName);
performanceEntry->SetInitiatorType(initiatorType);
InsertResourceEntry(performanceEntry);
}
// To be removed once bug 1124165 lands

Просмотреть файл

@ -35,10 +35,6 @@ class PerformanceMainThread final : public Performance,
virtual void AddEntry(nsIHttpChannel* channel,
nsITimedChannel* timedChannel) override;
void AddRawEntry(UniquePtr<PerformanceTimingData>,
const nsAString& aInitiatorType,
const nsAString& aEntryName);
TimeStamp CreationTimeStamp() const override;
DOMHighResTimeStamp CreationTime() const override;

Просмотреть файл

@ -10,7 +10,6 @@ with Files("**"):
EXPORTS.mozilla.dom += [
'Performance.h',
'PerformanceEntry.h',
'PerformanceMainThread.h',
'PerformanceMark.h',
'PerformanceMeasure.h',
'PerformanceNavigation.h',

Просмотреть файл

@ -60,7 +60,6 @@
}
async function clearCache(){
info("Clearing Cache");
SpecialPowers.DOMWindowUtils.clearSharedStyleSheetCache();
await ChromeTask.spawn(null,(()=>{
Services.cache2.clear();
}));

Просмотреть файл

@ -6,7 +6,7 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="http://mochi.test:8888/tests/SimpleTest/test.css?resource-timing-nocors"/>
<link rel="stylesheet" type="text/css" href="http://mochi.test:8888/tests/SimpleTest/test.css"/>
<!--
This document has the origin http://mochi.test:8888.
@ -109,7 +109,7 @@ function isnot(received, notExpected, message) {
}
var allResources = {
"http://mochi.test:8888/tests/SimpleTest/test.css?resource-timing-nocors" : "link",
"http://mochi.test:8888/tests/SimpleTest/test.css" : "link",
// 1
"http://mochi.test:8888/tests/dom/tests/mochitest/general/generateCss.sjs?A" : "link",

Просмотреть файл

@ -6,7 +6,7 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/tests/SimpleTest/test.css?performance-timeline-main-test"/>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
function ok(cond, message) {

Просмотреть файл

@ -45,7 +45,7 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/tests/SimpleTest/test.css?resource-timing-main-test"/>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
var mainWindowTestsDone = false;
@ -67,7 +67,7 @@ var bufferFullCounter = 0;
const expectedBufferFullEvents = 1;
var allResources = {
"http://mochi.test:8888/tests/SimpleTest/test.css?resource-timing-main-test": "link",
"http://mochi.test:8888/tests/SimpleTest/test.css": "link",
"http://mochi.test:8888/tests/image/test/mochitest/blue.png" : "img",
"http://mochi.test:8888/tests/image/test/mochitest/red.png" : "object",
"http://mochi.test:8888/tests/image/test/mochitest/big.png" : "embed",

Просмотреть файл

@ -960,11 +960,11 @@ static nsresult NewImageChannel(
return NS_OK;
}
static uint32_t SecondsFromPRTime(PRTime aTime) {
return nsContentUtils::SecondsFromPRTime(aTime);
/* static */
uint32_t imgCacheEntry::SecondsFromPRTime(PRTime prTime) {
return uint32_t(int64_t(prTime) / int64_t(PR_USEC_PER_SEC));
}
/* static */
imgCacheEntry::imgCacheEntry(imgLoader* loader, imgRequest* request,
bool forcePrincipalCheck)
: mLoader(loader),
@ -1822,8 +1822,8 @@ bool imgLoader::ValidateEntry(
// If the expiration time is zero, then the request has not gotten far enough
// to know when it will expire.
uint32_t expiryTime = aEntry->GetExpiryTime();
bool hasExpired =
expiryTime != 0 && expiryTime <= SecondsFromPRTime(PR_Now());
bool hasExpired = expiryTime != 0 &&
expiryTime <= imgCacheEntry::SecondsFromPRTime(PR_Now());
nsresult rv;
@ -1840,7 +1840,8 @@ bool imgLoader::ValidateEntry(
if (NS_SUCCEEDED(rv)) {
// nsIFile uses millisec, NSPR usec
fileLastMod *= 1000;
hasExpired = SecondsFromPRTime((PRTime)fileLastMod) > lastModTime;
hasExpired =
imgCacheEntry::SecondsFromPRTime((PRTime)fileLastMod) > lastModTime;
}
}
}

Просмотреть файл

@ -39,6 +39,8 @@ namespace image {} // namespace image
class imgCacheEntry {
public:
static uint32_t SecondsFromPRTime(PRTime prTime);
imgCacheEntry(imgLoader* loader, imgRequest* request,
bool aForcePrincipalCheck);
~imgCacheEntry();

Просмотреть файл

@ -517,26 +517,53 @@ void imgRequest::UpdateCacheEntrySize() {
void imgRequest::SetCacheValidation(imgCacheEntry* aCacheEntry,
nsIRequest* aRequest) {
/* get the expires info */
if (!aCacheEntry || aCacheEntry->GetExpiryTime() != 0) {
return;
}
if (aCacheEntry) {
// Expiration time defaults to 0. We set the expiration time on our
// entry if it hasn't been set yet.
if (aCacheEntry->GetExpiryTime() == 0) {
uint32_t expiration = 0;
nsCOMPtr<nsICacheInfoChannel> cacheChannel(do_QueryInterface(aRequest));
if (cacheChannel) {
/* get the expiration time from the caching channel's token */
cacheChannel->GetCacheTokenExpirationTime(&expiration);
}
if (expiration == 0) {
// If the channel doesn't support caching, then ensure this expires the
// next time it is used.
expiration = imgCacheEntry::SecondsFromPRTime(PR_Now()) - 1;
}
aCacheEntry->SetExpiryTime(expiration);
}
auto info = nsContentUtils::GetSubresourceCacheValidationInfo(aRequest);
// Determine whether the cache entry must be revalidated when we try to use
// it. Currently, only HTTP specifies this information...
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest));
if (httpChannel) {
bool bMustRevalidate = false;
// Expiration time defaults to 0. We set the expiration time on our entry if
// it hasn't been set yet.
if (!info.mExpirationTime) {
// If the channel doesn't support caching, then ensure this expires the
// next time it is used.
info.mExpirationTime.emplace(nsContentUtils::SecondsFromPRTime(PR_Now()) -
1);
}
aCacheEntry->SetExpiryTime(*info.mExpirationTime);
// Cache entries default to not needing to validate. We ensure that
// multiple calls to this function don't override an earlier decision to
// validate by making validation a one-way decision.
if (info.mMustRevalidate) {
aCacheEntry->SetMustValidate(info.mMustRevalidate);
Unused << httpChannel->IsNoStoreResponse(&bMustRevalidate);
if (!bMustRevalidate) {
Unused << httpChannel->IsNoCacheResponse(&bMustRevalidate);
}
if (!bMustRevalidate) {
nsAutoCString cacheHeader;
Unused << httpChannel->GetResponseHeader(
NS_LITERAL_CSTRING("Cache-Control"), cacheHeader);
if (PL_strcasestr(cacheHeader.get(), "must-revalidate")) {
bMustRevalidate = true;
}
}
// Cache entries default to not needing to validate. We ensure that
// multiple calls to this function don't override an earlier decision to
// validate by making validation a one-way decision.
if (bMustRevalidate) {
aCacheEntry->SetMustValidate(bMustRevalidate);
}
}
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -22,8 +22,6 @@
#include "nsStringFwd.h"
#include "nsTArray.h"
#include "nsTObserverArray.h"
#include "nsURIHashKey.h"
#include "nsRefPtrHashtable.h"
class nsICSSLoaderObserver;
class nsIConsoleReportCollector;
@ -32,8 +30,6 @@ class nsIPrincipal;
namespace mozilla {
class SharedStyleSheetCache;
class SheetLoadDataHashKey;
class StyleSheet;
namespace dom {
@ -41,186 +37,10 @@ class DocGroup;
class Element;
} // namespace dom
// The load data for a <link> or @import style-sheet.
//
// This must contain all the state that affects CSS parsing.
class SheetLoadDataHashKey : public PLDHashEntryHdr {
public:
enum class IsPreload : uint8_t {
No,
// This is a speculative load initiated by a <link rel=stylesheet> tag
// scanned by the parser, or @import rules found in a <style> tag.
FromParser,
// This is a speculative load as well, but initiated by
// <link rel="preload" as="style">
FromLink,
};
using KeyType = const SheetLoadDataHashKey&;
using KeyTypePointer = const SheetLoadDataHashKey*;
explicit SheetLoadDataHashKey(const SheetLoadDataHashKey* aKey)
: mURI(aKey->mURI),
mPrincipal(aKey->mPrincipal),
mLoaderPrincipal(aKey->mLoaderPrincipal),
mReferrerInfo(aKey->mReferrerInfo),
mEncodingGuess(aKey->mEncodingGuess),
mCORSMode(aKey->mCORSMode),
mParsingMode(aKey->mParsingMode),
mCompatMode(aKey->mCompatMode),
mSRIMetadata(aKey->mSRIMetadata),
mIsLinkPreload(aKey->mIsLinkPreload) {
MOZ_COUNT_CTOR(SheetLoadDataHashKey);
}
SheetLoadDataHashKey(nsIURI* aURI, nsIPrincipal* aPrincipal,
nsIPrincipal* aLoaderPrincipal,
nsIReferrerInfo* aReferrerInfo,
NotNull<const Encoding*> aEncodingGuess,
CORSMode aCORSMode, css::SheetParsingMode aParsingMode,
nsCompatibility aCompatMode,
const dom::SRIMetadata& aSRIMetadata,
IsPreload aIsPreload)
: mURI(aURI),
mPrincipal(aPrincipal),
mLoaderPrincipal(aLoaderPrincipal),
mReferrerInfo(aReferrerInfo),
mEncodingGuess(aEncodingGuess),
mCORSMode(aCORSMode),
mParsingMode(aParsingMode),
mCompatMode(aCompatMode),
mSRIMetadata(aSRIMetadata),
mIsLinkPreload(aIsPreload == IsPreload::FromLink) {
MOZ_ASSERT(aURI);
MOZ_ASSERT(aPrincipal);
MOZ_ASSERT(aLoaderPrincipal);
MOZ_COUNT_CTOR(SheetLoadDataHashKey);
}
SheetLoadDataHashKey(SheetLoadDataHashKey&& toMove)
: mURI(std::move(toMove.mURI)),
mPrincipal(std::move(toMove.mPrincipal)),
mLoaderPrincipal(std::move(toMove.mLoaderPrincipal)),
mReferrerInfo(std::move(toMove.mReferrerInfo)),
mEncodingGuess(std::move(toMove.mEncodingGuess)),
mCORSMode(std::move(toMove.mCORSMode)),
mParsingMode(std::move(toMove.mParsingMode)),
mCompatMode(std::move(toMove.mCompatMode)),
mSRIMetadata(std::move(toMove.mSRIMetadata)),
mIsLinkPreload(std::move(toMove.mIsLinkPreload)) {
MOZ_COUNT_CTOR(SheetLoadDataHashKey);
}
explicit SheetLoadDataHashKey(const css::SheetLoadData&);
MOZ_COUNTED_DTOR(SheetLoadDataHashKey)
const SheetLoadDataHashKey& GetKey() const { return *this; }
const SheetLoadDataHashKey* GetKeyPointer() const { return this; }
bool KeyEquals(const SheetLoadDataHashKey* aKey) const {
return KeyEquals(*aKey);
}
bool KeyEquals(const SheetLoadDataHashKey& aKey) const {
{
bool eq;
if (NS_FAILED(mURI->Equals(aKey.mURI, &eq)) || !eq) {
return false;
}
}
// The loader principal doesn't really need to match to be a cache hit, it's
// just useful for cache-eviction purposes.
if (!mPrincipal->Equals(aKey.mPrincipal)) {
return false;
}
if (mCORSMode != aKey.mCORSMode) {
return false;
}
if (mParsingMode != aKey.mParsingMode) {
return false;
}
if (mCompatMode != aKey.mCompatMode) {
return false;
}
// If encoding differs, then don't reuse the cache.
//
// TODO(emilio): When the encoding is determined from the request (either
// BOM or Content-Length or @charset), we could do a bit better,
// theoretically.
if (mEncodingGuess != aKey.mEncodingGuess) {
return false;
}
// FIXME: Should we _really_ miss the cache here for different referrer
// policies? Missing the cache for different referrers would be sad.
if (mReferrerInfo->ReferrerPolicy() !=
aKey.mReferrerInfo->ReferrerPolicy()) {
return false;
}
// Consuming stylesheet tags must never coalesce to <link preload> initiated
// speculative loads with a weaker SRI hash or its different value. This
// check makes sure that regular loads will never find such a weaker preload
// and rather start a new, independent load with new, stronger SRI checker
// set up, so that integrity is ensured.
if (mIsLinkPreload != aKey.mIsLinkPreload) {
const auto& linkPreloadMetadata =
mIsLinkPreload ? mSRIMetadata : aKey.mSRIMetadata;
const auto& consumerPreloadMetadata =
mIsLinkPreload ? aKey.mSRIMetadata : mSRIMetadata;
if (!consumerPreloadMetadata.CanTrustBeDelegatedTo(linkPreloadMetadata)) {
return false;
}
}
return true;
}
static const SheetLoadDataHashKey* KeyToPointer(
const SheetLoadDataHashKey& aKey) {
return &aKey;
}
static PLDHashNumber HashKey(const SheetLoadDataHashKey* aKey) {
return nsURIHashKey::HashKey(aKey->mURI);
}
nsIURI* URI() const { return mURI; }
nsIPrincipal* Principal() const { return mPrincipal; }
nsIPrincipal* LoaderPrincipal() const { return mLoaderPrincipal; }
css::SheetParsingMode ParsingMode() const { return mParsingMode; }
enum { ALLOW_MEMMOVE = true };
protected:
const nsCOMPtr<nsIURI> mURI;
const nsCOMPtr<nsIPrincipal> mPrincipal;
const nsCOMPtr<nsIPrincipal> mLoaderPrincipal;
const nsCOMPtr<nsIReferrerInfo> mReferrerInfo;
// The encoding guess is the encoding the sheet would get if the request
// didn't have any encoding information like @charset or a Content-Encoding
// header.
const NotNull<const Encoding*> mEncodingGuess;
const CORSMode mCORSMode;
const css::SheetParsingMode mParsingMode;
const nsCompatibility mCompatMode;
dom::SRIMetadata mSRIMetadata;
const bool mIsLinkPreload;
};
namespace css {
class SheetLoadData;
class SheetCache;
class ImportRule;
/*********************
@ -292,9 +112,6 @@ class Loader final {
void DropDocumentReference(); // notification that doc is going away
void DeregisterFromSheetCache();
void RegisterInSheetCache();
void SetCompatibilityMode(nsCompatibility aCompatMode) {
mCompatMode = aCompatMode;
}
@ -358,11 +175,6 @@ class Loader final {
nsIURI* aURL, dom::MediaList* aMedia,
LoaderReusableStyleSheets* aSavedSheets);
/**
* Called when we hit the internal memory cache with a complete stylesheet.
*/
void DidHitCompleteSheetCache(SheetLoadData&);
enum class UseSystemPrincipal { No, Yes };
/**
@ -390,7 +202,15 @@ class Loader final {
nsIURI*, SheetParsingMode = eAuthorSheetFeatures,
UseSystemPrincipal = UseSystemPrincipal::No);
using IsPreload = SheetLoadDataHashKey::IsPreload;
enum class IsPreload : uint8_t {
No,
// This is a speculative load initiated by a <link rel=stylesheet> tag
// scanned by the parser, or @import rules found in a <style> tag.
FromParser,
// This is a speculative load as well, but initiated by
// <link rel="preload" as="style">
FromLink,
};
/**
* Asynchronously load the stylesheet at aURL. If a successful result is
@ -447,8 +267,6 @@ class Loader final {
bool GetEnabled() { return mEnabled; }
void SetEnabled(bool aEnabled) { mEnabled = aEnabled; }
uint32_t ParsedSheetCount() const { return mParsedSheetCount; }
/**
* Get the document we live for. May return null.
*/
@ -494,21 +312,11 @@ class Loader final {
// Measure our size.
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
enum class SheetState : uint8_t {
NeedsParser = 0,
Pending,
Loading,
Complete
};
// The loader principal is the document's node principal, if this loader is
// owned by a document, or the system principal otherwise.
nsIPrincipal* LoaderPrincipal() const;
bool ShouldBypassCache() const;
private:
friend class mozilla::SharedStyleSheetCache;
friend class SheetLoadData;
friend class StreamLoader;
@ -525,15 +333,19 @@ class Loader final {
nsIURI* aTargetURI, nsINode* aRequestingNode,
const nsAString& aNonce, IsPreload);
enum class SheetState : uint8_t {
NeedsParser = 0,
Pending,
Loading,
Complete
};
std::tuple<RefPtr<StyleSheet>, SheetState> CreateSheet(
const SheetInfo& aInfo, css::SheetParsingMode aParsingMode,
bool aSyncLoad, IsPreload aIsPreload) {
nsIPrincipal* triggeringPrincipal = aInfo.mTriggeringPrincipal
? aInfo.mTriggeringPrincipal.get()
: LoaderPrincipal();
return CreateSheet(aInfo.mURI, aInfo.mContent, triggeringPrincipal,
const SheetInfo& aInfo, nsIPrincipal* aTriggeringPrincipal,
css::SheetParsingMode aParsingMode, bool aSyncLoad,
IsPreload aIsPreload) {
return CreateSheet(aInfo.mURI, aInfo.mContent, aTriggeringPrincipal,
aParsingMode, aInfo.mCORSMode, aInfo.mReferrerInfo,
/* aPreloadOrParentDataEncoding = */ nullptr,
aInfo.mIntegrity, aSyncLoad, aIsPreload);
}
@ -543,8 +355,7 @@ class Loader final {
std::tuple<RefPtr<StyleSheet>, SheetState> CreateSheet(
nsIURI* aURI, nsIContent* aLinkingContent,
nsIPrincipal* aTriggeringPrincipal, css::SheetParsingMode, CORSMode,
nsIReferrerInfo* aLoadingReferrerInfo,
const Encoding* aPreloadOrParentDataEncoding, const nsAString& aIntegrity,
nsIReferrerInfo* aLoadingReferrerInfo, const nsAString& aIntegrity,
bool aSyncLoad, IsPreload aIsPreload);
// Pass in either a media string or the MediaList from the CSSParser. Don't
@ -566,8 +377,6 @@ class Loader final {
nsIReferrerInfo* aReferrerInfo, nsICSSLoaderObserver* aObserver,
CORSMode aCORSMode, const nsAString& aIntegrity);
RefPtr<StyleSheet> LookupInlineSheetInCache(const nsAString&);
// Post a load event for aObserver to be notified about aSheet. The
// notification will be sent with status NS_OK unless the load event is
// canceled at some point (in which case it will be sent with
@ -599,29 +408,20 @@ class Loader final {
// The load of the sheet in the load data is done, one way or another.
// Do final cleanup.
void SheetComplete(SheetLoadData&, nsresult);
void SheetComplete(SheetLoadData&, nsresult aStatus);
// Notify observers on an individual data. This is different from
// SheetComplete for loads that are shared.
void NotifyObservers(SheetLoadData&, nsresult);
// The guts of SheetComplete. This may be called recursively on parent datas
// or datas that had glommed on to a single load. The array is there so load
// datas whose observers need to be notified can be added to it.
void DoSheetComplete(SheetLoadData&, LoadDataArray& aDatasToNotify);
// Mark the given SheetLoadData, as well as any of its siblings, parents, etc
// transitively, as failed. The idea is to mark as failed any load that was
// directly or indirectly @importing the sheet this SheetLoadData represents.
//
// if aOnlyForLoader is non-null, then only loads for a given loader will be
// marked as failing. This is useful to only cancel loads associated to a
// given loader, in case they were marked as canceled.
static void MarkLoadTreeFailed(SheetLoadData&,
Loader* aOnlyForLoader = nullptr);
void MarkLoadTreeFailed(SheetLoadData&);
nsRefPtrHashtable<nsStringHashKey, StyleSheet> mInlineSheets;
// A set with all the different loads we've done in a given document, for the
// purpose of not posting duplicate performance entries for them.
nsTHashtable<const SheetLoadDataHashKey> mLoadsPerformed;
RefPtr<SharedStyleSheetCache> mSheets;
struct Sheets;
UniquePtr<Sheets> mSheets;
// The array of posted stylesheet loaded events (SheetLoadDatas) we have.
// Note that these are rare.
@ -637,22 +437,18 @@ class Loader final {
// For dispatching events via DocGroup::Dispatch() when mDocument is nullptr.
RefPtr<dom::DocGroup> mDocGroup;
// Number of datas still waiting to be notified on if we're notifying on a
// whole bunch at once (e.g. in one of the stop methods). This is used to
// make sure that HasPendingLoads() won't return false until we're notifying
// on the last data we're working with.
uint32_t mDatasToNotifyOn;
nsCompatibility mCompatMode;
bool mEnabled; // is enabled to load new styles
nsCOMPtr<nsIConsoleReportCollector> mReporter;
// Number of datas still waiting to be notified. This includes pending
// stylesheets whose load hasn't started yet but which we need to.
uint32_t mOngoingLoadCount = 0;
// The number of sheets that have been deferred / are in a pending state.
uint32_t mPendingLoadCount = 0;
// The number of stylesheets that we have parsed, for testing purposes.
uint32_t mParsedSheetCount = 0;
bool mEnabled = true;
#ifdef DEBUG
// Whether we're in a necko callback atm.
bool mSyncCallback = false;

Просмотреть файл

@ -1,509 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "SharedStyleSheetCache.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/css/SheetLoadData.h"
#include "nsXULPrototypeCache.h"
extern mozilla::LazyLogModule sCssLoaderLog;
#define LOG(args) MOZ_LOG(sCssLoaderLog, mozilla::LogLevel::Debug, args)
namespace mozilla {
using css::SheetLoadData;
using SheetState = css::Loader::SheetState;
using LoadDataArray = css::Loader::LoadDataArray;
using IsAlternate = css::Loader::IsAlternate;
SharedStyleSheetCache* SharedStyleSheetCache::sInstance;
void SharedStyleSheetCache::ClearForTest() {
if (sInstance) {
sInstance->mCompleteSheets.Clear();
}
}
already_AddRefed<SharedStyleSheetCache> SharedStyleSheetCache::Create() {
MOZ_DIAGNOSTIC_ASSERT(!sInstance);
RefPtr<SharedStyleSheetCache> cache = new SharedStyleSheetCache();
sInstance = cache.get();
RegisterWeakMemoryReporter(cache.get());
return cache.forget();
}
SharedStyleSheetCache::~SharedStyleSheetCache() {
MOZ_DIAGNOSTIC_ASSERT(sInstance == this);
UnregisterWeakMemoryReporter(this);
sInstance = nullptr;
}
NS_IMPL_ISUPPORTS(SharedStyleSheetCache, nsIMemoryReporter)
MOZ_DEFINE_MALLOC_SIZE_OF(SharedStyleSheetCacheMallocSizeOf)
NS_IMETHODIMP
SharedStyleSheetCache::CollectReports(nsIHandleReportCallback* aHandleReport,
nsISupports* aData, bool aAnonymize) {
MOZ_COLLECT_REPORT("explicit/layout/style-sheet-cache/document-shared",
KIND_HEAP, UNITS_BYTES,
SizeOfIncludingThis(SharedStyleSheetCacheMallocSizeOf),
"Memory used for SharedStyleSheetCache to share style "
"sheets across documents (not to be confused with "
"GlobalStyleSheetCache)");
return NS_OK;
}
static RefPtr<StyleSheet> CloneSheet(StyleSheet& aSheet) {
return aSheet.Clone(nullptr, nullptr, nullptr, nullptr);
}
static void AssertComplete(const StyleSheet& aSheet) {
// This sheet came from the XUL cache or SharedStyleSheetCache; it better be a
// complete sheet.
MOZ_ASSERT(aSheet.IsComplete(),
"Sheet thinks it's not complete while we think it is");
}
static void AssertIncompleteSheetMatches(const SheetLoadData& aData,
const SheetLoadDataHashKey& aKey) {
MOZ_ASSERT(aKey.Principal()->Equals(aData.mTriggeringPrincipal),
"Principals should be the same");
MOZ_ASSERT(!aData.mSheet->HasForcedUniqueInner(),
"CSSOM shouldn't allow access to incomplete sheets");
}
bool SharedStyleSheetCache::CompleteSheet::Expired() const {
return mExpirationTime &&
mExpirationTime <= nsContentUtils::SecondsFromPRTime(PR_Now());
}
SharedStyleSheetCache::CacheResult SharedStyleSheetCache::Lookup(
css::Loader& aLoader, const SheetLoadDataHashKey& aKey, bool aSyncLoad) {
nsIURI* uri = aKey.URI();
LOG(("SharedStyleSheetCache::Lookup(%s)", uri->GetSpecOrDefault().get()));
// Try to find first in the XUL prototype cache.
if (dom::IsChromeURI(uri)) {
nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
if (cache && cache->IsEnabled()) {
if (StyleSheet* sheet = cache->GetStyleSheet(uri)) {
LOG((" From XUL cache: %p", sheet));
AssertComplete(*sheet);
// See below, we always clone on insertion so we can guarantee the
// stylesheet is not modified.
MOZ_ASSERT(!sheet->HasForcedUniqueInner());
// We need to check the parsing mode manually because the XUL cache only
// keys off the URI. But we should fix that!
if (sheet->ParsingMode() == aKey.ParsingMode()) {
return {CloneSheet(*sheet), SheetState::Complete};
}
LOG((" Not cloning due to mismatched parsing mode"));
}
}
}
// Now complete sheets.
if (auto lookup = mCompleteSheets.Lookup(aKey)) {
const CompleteSheet& completeSheet = lookup.Data();
// We can assert the stylesheet has not been modified, as we clone it on
// insertion.
StyleSheet& cachedSheet = *completeSheet.mSheet;
LOG((" From completed: %p", &cachedSheet));
if ((!aLoader.ShouldBypassCache() && !completeSheet.Expired()) ||
aLoader.mLoadsPerformed.Contains(aKey)) {
LOG(
(" Not expired yet, or previously loaded already in "
"that document"));
AssertComplete(cachedSheet);
MOZ_ASSERT(cachedSheet.ParsingMode() == aKey.ParsingMode());
MOZ_ASSERT(!cachedSheet.HasForcedUniqueInner());
MOZ_ASSERT(!cachedSheet.HasModifiedRules());
RefPtr<StyleSheet> clone = CloneSheet(cachedSheet);
MOZ_ASSERT(!clone->HasForcedUniqueInner());
MOZ_ASSERT(!clone->HasModifiedRules());
return {std::move(clone), SheetState::Complete};
}
}
if (aSyncLoad) {
return {};
}
if (SheetLoadData* data = mLoadingDatas.Get(aKey)) {
LOG((" From loading: %p", data->mSheet.get()));
AssertIncompleteSheetMatches(*data, aKey);
return {CloneSheet(*data->mSheet), SheetState::Loading};
}
if (SheetLoadData* data = mPendingDatas.GetWeak(aKey)) {
LOG((" From pending: %p", data->mSheet.get()));
AssertIncompleteSheetMatches(*data, aKey);
return {CloneSheet(*data->mSheet), SheetState::Pending};
}
return {};
}
bool SharedStyleSheetCache::CoalesceLoad(const SheetLoadDataHashKey& aKey,
SheetLoadData& aNewLoad,
SheetState aExistingLoadState) {
MOZ_ASSERT(SheetLoadDataHashKey(aNewLoad).KeyEquals(aKey));
SheetLoadData* existingData = nullptr;
if (aExistingLoadState == SheetState::Loading) {
existingData = mLoadingDatas.Get(aKey);
MOZ_ASSERT(existingData, "CreateSheet lied about the state");
} else if (aExistingLoadState == SheetState::Pending) {
existingData = mPendingDatas.GetWeak(aKey);
MOZ_ASSERT(existingData, "CreateSheet lied about the state");
}
if (!existingData) {
return false;
}
if (aExistingLoadState == SheetState::Pending && !aNewLoad.ShouldDefer()) {
// Kick the load off; someone cares about it right away
RefPtr<SheetLoadData> removedData;
mPendingDatas.Remove(aKey, getter_AddRefs(removedData));
MOZ_ASSERT(removedData == existingData, "Bad loading table");
// We insert to the front instead of the back, to keep the invariant that
// the front sheet always is the one that triggers the load.
aNewLoad.mNext = std::move(removedData);
LOG((" Forcing load of pending data"));
return false;
}
LOG((" Glomming on to existing load"));
SheetLoadData* data = existingData;
while (data->mNext) {
data = data->mNext;
}
data->mNext = &aNewLoad;
return true;
}
size_t SharedStyleSheetCache::SizeOfIncludingThis(
MallocSizeOf aMallocSizeOf) const {
size_t n = aMallocSizeOf(this);
n += mCompleteSheets.ShallowSizeOfExcludingThis(aMallocSizeOf);
for (auto iter = mCompleteSheets.ConstIter(); !iter.Done(); iter.Next()) {
n += iter.UserData().mSheet->SizeOfIncludingThis(aMallocSizeOf);
}
// Measurement of the following members may be added later if DMD finds it is
// worthwhile:
// - mLoadingDatas: transient, and should be small
// - mPendingDatas: transient, and should be small
return n;
}
void SharedStyleSheetCache::DeferSheetLoad(SheetLoadData& aData) {
SheetLoadDataHashKey key(aData);
aData.mMustNotify = true;
mPendingDatas.Put(key, RefPtr{&aData});
}
void SharedStyleSheetCache::LoadStarted(const SheetLoadDataHashKey& aKey,
SheetLoadData& aData) {
MOZ_ASSERT(aData.mURI, "No load required?");
MOZ_ASSERT(!aData.mIsLoading, "Already loading? How?");
MOZ_ASSERT(SheetLoadDataHashKey(aData).KeyEquals(aKey));
aData.mIsLoading = true;
mLoadingDatas.Put(aKey, &aData);
}
void SharedStyleSheetCache::LoadCompleted(SharedStyleSheetCache* aCache,
SheetLoadData& aData,
nsresult aStatus) {
// If aStatus is a failure we need to mark this data failed. We also need to
// mark any ancestors of a failing data as failed and any sibling of a
// failing data as failed. Note that SheetComplete is never called on a
// SheetLoadData that is the mNext of some other SheetLoadData.
nsresult cancelledStatus = aStatus;
if (NS_FAILED(aStatus)) {
css::Loader::MarkLoadTreeFailed(aData);
} else {
cancelledStatus = NS_BINDING_ABORTED;
SheetLoadData* data = &aData;
do {
if (data->mIsCancelled) {
// We only need to mark loads for this loader as cancelled, so as to not
// fire error events in unrelated documents.
css::Loader::MarkLoadTreeFailed(*data, data->mLoader);
}
} while ((data = data->mNext));
}
// 8 is probably big enough for all our common cases. It's not likely that
// imports will nest more than 8 deep, and multiple sheets with the same URI
// are rare.
AutoTArray<RefPtr<SheetLoadData>, 8> datasToNotify;
LoadCompletedInternal(aCache, aData, datasToNotify);
// Now it's safe to go ahead and notify observers
for (RefPtr<SheetLoadData>& data : datasToNotify) {
auto status = data->mIsCancelled ? cancelledStatus : aStatus;
data->mLoader->NotifyObservers(*data, status);
}
}
void SharedStyleSheetCache::LoadCompletedInternal(
SharedStyleSheetCache* aCache, SheetLoadData& aData,
nsTArray<RefPtr<SheetLoadData>>& aDatasToNotify) {
if (aData.mIsLoading) {
MOZ_ASSERT(aCache);
SheetLoadDataHashKey key(aData);
Maybe<SheetLoadData*> loadingData = aCache->mLoadingDatas.GetAndRemove(key);
MOZ_DIAGNOSTIC_ASSERT(loadingData);
MOZ_DIAGNOSTIC_ASSERT(loadingData.value() == &aData);
Unused << loadingData;
aData.mIsLoading = false;
}
// Go through and deal with the whole linked list.
SheetLoadData* data = &aData;
do {
MOZ_DIAGNOSTIC_ASSERT(!data->mSheetCompleteCalled);
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
data->mSheetCompleteCalled = true;
#endif
if (!data->mSheetAlreadyComplete) {
// If mSheetAlreadyComplete, then the sheet could well be modified between
// when we posted the async call to SheetComplete and now, since the sheet
// was page-accessible during that whole time.
// HasForcedUniqueInner() is okay if the sheet is constructed, because
// constructed sheets are always unique and they may be set to complete
// multiple times if their rules are replaced via Replace()
MOZ_ASSERT(data->mSheet->IsConstructed() ||
!data->mSheet->HasForcedUniqueInner(),
"should not get a forced unique inner during parsing");
data->mSheet->SetComplete();
data->ScheduleLoadEventIfNeeded();
}
aDatasToNotify.AppendElement(data);
NS_ASSERTION(!data->mParentData || data->mParentData->mPendingChildren != 0,
"Broken pending child count on our parent");
// If we have a parent, our parent is no longer being parsed, and
// we are the last pending child, then our load completion
// completes the parent too. Note that the parent _can_ still be
// being parsed (eg if the child (us) failed to open the channel
// or some such).
if (data->mParentData && --(data->mParentData->mPendingChildren) == 0 &&
!data->mParentData->mIsBeingParsed) {
LoadCompletedInternal(aCache, *data->mParentData, aDatasToNotify);
}
data = data->mNext;
} while (data);
if (aCache) {
aCache->InsertIntoCompleteCacheIfNeeded(aData);
}
}
void SharedStyleSheetCache::InsertIntoCompleteCacheIfNeeded(
SheetLoadData& aData) {
MOZ_ASSERT(aData.mLoader->GetDocument(),
"We only cache document-associated sheets");
LOG(("SharedStyleSheetCache::InsertIntoCompleteCacheIfNeeded"));
// If we ever start doing this for failed loads, we'll need to adjust the
// PostLoadEvent code that thinks anything already complete must have loaded
// succesfully.
if (aData.mLoadFailed) {
LOG((" Load failed, bailing"));
return;
}
// If this sheet came from the cache already, there's no need to override
// anything.
if (aData.mSheetAlreadyComplete) {
LOG((" Sheet came from the cache, bailing"));
return;
}
if (!aData.mURI) {
LOG((" Inline style sheet, bailing"));
// Inline sheet caching happens in Loader::mInlineSheets.
return;
}
if (aData.mSheet->IsConstructed()) {
LOG((" Constructable style sheet, bailing"));
// Constructable sheets are not worth caching, they're always unique.
return;
}
// We need to clone the sheet on insertion to the cache because otherwise the
// stylesheets can keep alive full windows alive via either their JS wrapper,
// or via StyleSheet::mRelevantGlobal.
//
// If this ever changes, then you also need to fix up the memory reporting in
// both SizeOfIncludingThis and nsXULPrototypeCache::CollectMemoryReports.
RefPtr<StyleSheet> sheet = CloneSheet(*aData.mSheet);
if (dom::IsChromeURI(aData.mURI)) {
nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
if (cache && cache->IsEnabled()) {
if (!cache->GetStyleSheet(aData.mURI)) {
LOG((" Putting sheet in XUL prototype cache"));
NS_ASSERTION(sheet->IsComplete(),
"Should only be caching complete sheets");
// NOTE: If we stop cloning sheets before insertion, we need to change
// nsXULPrototypeCache::CollectMemoryReports() to stop using
// SizeOfIncludingThis() because it will no longer own the sheets.
cache->PutStyleSheet(std::move(sheet));
}
}
} else {
LOG((" Putting style sheet in shared cache: %s",
aData.mURI->GetSpecOrDefault().get()));
SheetLoadDataHashKey key(aData);
MOZ_ASSERT(sheet->IsComplete(), "Should only be caching complete sheets");
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
for (const auto& entry : mCompleteSheets) {
if (!key.KeyEquals(entry.GetKey())) {
MOZ_DIAGNOSTIC_ASSERT(entry.GetData().mSheet != sheet,
"Same sheet, different keys?");
} else {
MOZ_DIAGNOSTIC_ASSERT(
entry.GetData().Expired() || aData.mLoader->ShouldBypassCache(),
"Overriding existing complete entry?");
}
}
#endif
mCompleteSheets.Put(key, {aData.mExpirationTime, std::move(sheet)});
}
}
void SharedStyleSheetCache::StartDeferredLoadsForLoader(
css::Loader& aLoader, StartLoads aStartLoads) {
LoadDataArray arr;
for (auto iter = mPendingDatas.Iter(); !iter.Done(); iter.Next()) {
bool startIt = false;
SheetLoadData* data = iter.UserData();
do {
if (data->mLoader == &aLoader) {
// Note that we don't want to affect what the selected style set is, so
// use true for aHasAlternateRel.
if (aStartLoads != StartLoads::IfNonAlternate ||
aLoader.IsAlternateSheet(iter.Data()->mTitle, true) !=
IsAlternate::Yes) {
startIt = true;
break;
}
}
} while ((data = data->mNext));
if (startIt) {
arr.AppendElement(std::move(iter.Data()));
iter.Remove();
}
}
for (auto& data : arr) {
data->mLoader->LoadSheet(*data, SheetState::NeedsParser);
}
}
void SharedStyleSheetCache::CancelDeferredLoadsForLoader(css::Loader& aLoader) {
LoadDataArray arr;
for (auto iter = mPendingDatas.Iter(); !iter.Done(); iter.Next()) {
RefPtr<SheetLoadData>& first = iter.Data();
SheetLoadData* prev = nullptr;
SheetLoadData* current = iter.UserData();
do {
if (current->mLoader != &aLoader) {
prev = current;
current = current->mNext;
continue;
}
// Detach the load from the list, mark it as cancelled, and then below
// call SheetComplete on it.
RefPtr<SheetLoadData> strong =
prev ? std::move(prev->mNext) : std::move(first);
MOZ_ASSERT(strong == current);
if (prev) {
prev->mNext = std::move(strong->mNext);
current = prev->mNext;
} else {
first = std::move(strong->mNext);
current = first;
}
strong->mIsCancelled = true;
arr.AppendElement(std::move(strong));
} while (current);
if (!first) {
iter.Remove();
}
}
for (auto& data : arr) {
aLoader.SheetComplete(*data, NS_BINDING_ABORTED);
}
}
void SharedStyleSheetCache::CancelLoadsForLoader(css::Loader& aLoader) {
CancelDeferredLoadsForLoader(aLoader);
// We can't stop in-progress loads because some other loader may care about
// them.
for (auto iter = mLoadingDatas.Iter(); !iter.Done(); iter.Next()) {
SheetLoadData* data = iter.UserData();
do {
if (data->mLoader == &aLoader) {
data->mIsCancelled = true;
}
} while ((data = data->mNext));
}
}
void SharedStyleSheetCache::RegisterLoader(css::Loader& aLoader) {
MOZ_ASSERT(aLoader.GetDocument());
mLoaderPrincipalRefCnt.LookupForAdd(aLoader.GetDocument()->NodePrincipal())
.OrInsert([] { return 0; }) += 1;
}
void SharedStyleSheetCache::UnregisterLoader(css::Loader& aLoader) {
MOZ_ASSERT(aLoader.GetDocument());
nsIPrincipal* prin = aLoader.GetDocument()->NodePrincipal();
auto lookup = mLoaderPrincipalRefCnt.Lookup(prin);
MOZ_RELEASE_ASSERT(lookup);
MOZ_RELEASE_ASSERT(lookup.Data());
if (!--lookup.Data()) {
lookup.Remove();
// TODO(emilio): Do this off a timer or something maybe.
for (auto iter = mCompleteSheets.Iter(); !iter.Done(); iter.Next()) {
if (iter.Key().LoaderPrincipal()->Equals(prin)) {
iter.Remove();
}
}
}
}
} // namespace mozilla
#undef LOG

Просмотреть файл

@ -1,139 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_SharedStyleSheetCache_h__
#define mozilla_SharedStyleSheetCache_h__
// The shared style sheet cache is a cache that allows us to share sheets across
// documents.
//
// It's generally a singleton, but it is different from GlobalStyleSheetCache in
// the sense that:
//
// * It needs to be cycle-collectable, as it can keep alive style sheets from
// various documents.
//
// * It is conceptually a singleton, but given its cycle-collectable nature, we
// might re-create it.
#include "mozilla/PrincipalHashKey.h"
#include "mozilla/css/Loader.h"
#include "nsDataHashtable.h"
#include "nsIMemoryReporter.h"
#include "nsRefPtrHashtable.h"
#include "nsURIHashKey.h"
namespace mozilla {
namespace css {
class SheetLoadData;
}
class SharedStyleSheetCache final : public nsIMemoryReporter {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIMEMORYREPORTER
SharedStyleSheetCache(const SharedStyleSheetCache&) = delete;
SharedStyleSheetCache(SharedStyleSheetCache&&) = delete;
static already_AddRefed<SharedStyleSheetCache> Get() {
if (sInstance) {
return do_AddRef(sInstance);
}
return Create();
}
public:
// TODO(emilio): Maybe cache inline sheets here rather than in the loader?
// But that is a bit dubious, because for inline sheets, the sheet URI is the
// document URI, so it is basically document-specific... Maybe we can cache
// the RawServoStyleSheetContents or something, but...
// A cache hit or miss. It is a miss if the `StyleSheet` is null.
using CacheResult = std::tuple<RefPtr<StyleSheet>, css::Loader::SheetState>;
CacheResult Lookup(css::Loader&, const SheetLoadDataHashKey&, bool aSyncLoad);
// Tries to coalesce with an already existing load. The sheet state must be
// the one that Lookup returned, if it returned a sheet.
//
// TODO(emilio): Maybe try to merge this with the lookup? Most consumers could
// have a data there already.
MOZ_MUST_USE bool CoalesceLoad(const SheetLoadDataHashKey&,
css::SheetLoadData& aNewLoad,
css::Loader::SheetState aExistingLoadState);
size_t SizeOfIncludingThis(MallocSizeOf) const;
// Puts the load into the "loading" set.
void LoadStarted(const SheetLoadDataHashKey&, css::SheetLoadData&);
// Puts a load into the "pending" set.
void DeferSheetLoad(css::SheetLoadData&);
enum class StartLoads {
Always,
IfNonAlternate,
};
void StartDeferredLoadsForLoader(css::Loader&, StartLoads);
void CancelLoadsForLoader(css::Loader&);
// This has to be static because it's also called for loaders that don't have
// a sheet cache (loaders that are not owned by a document).
static void LoadCompleted(SharedStyleSheetCache*, css::SheetLoadData&,
nsresult);
// Register a loader into the cache. This has the effect of keeping alive all
// stylesheets for the origin of the loader's document until UnregisterLoader
// is called.
void RegisterLoader(css::Loader&);
// Unregister a loader from the cache.
//
// If this is the loader for the last document of a given origin, then all the
// stylesheets for that document will be removed from the cache. This needs to
// be called when the document goes away, or when its principal changes.
void UnregisterLoader(css::Loader&);
static void ClearForTest();
private:
static already_AddRefed<SharedStyleSheetCache> Create();
void CancelDeferredLoadsForLoader(css::Loader&);
static void LoadCompletedInternal(SharedStyleSheetCache*, css::SheetLoadData&,
nsTArray<RefPtr<css::SheetLoadData>>&);
void InsertIntoCompleteCacheIfNeeded(css::SheetLoadData&);
SharedStyleSheetCache() = default;
~SharedStyleSheetCache();
struct CompleteSheet {
uint32_t mExpirationTime = 0;
RefPtr<StyleSheet> mSheet;
bool Expired() const;
};
nsDataHashtable<SheetLoadDataHashKey, CompleteSheet> mCompleteSheets;
nsRefPtrHashtable<SheetLoadDataHashKey, css::SheetLoadData> mPendingDatas;
// The SheetLoadData pointers in mLoadingDatas below are weak references.
//
// Note that we hold on to all sheet loads, even if in the end they happen not
// to be cacheable.
nsDataHashtable<SheetLoadDataHashKey, css::SheetLoadData*> mLoadingDatas;
// An origin-to-number-of-registered-documents count, in order to manage cache
// eviction as described in RegisterLoader / UnregisterLoader.
nsDataHashtable<PrincipalHashKey, uint32_t> mLoaderPrincipalRefCnt;
static SharedStyleSheetCache* sInstance;
};
} // namespace mozilla
#endif

Просмотреть файл

@ -67,12 +67,12 @@ class SheetLoadData final : public nsIRunnable, public nsIThreadObserver {
nsIPrincipal* aTriggeringPrincipal,
nsIReferrerInfo* aReferrerInfo, nsINode* aRequestingNode);
nsIReferrerInfo* ReferrerInfo() const { return mReferrerInfo; }
nsIReferrerInfo* ReferrerInfo() { return mReferrerInfo; }
void ScheduleLoadEventIfNeeded();
NotNull<const Encoding*> DetermineNonBOMEncoding(const nsACString& aSegment,
nsIChannel*) const;
NotNull<const Encoding*> DetermineNonBOMEncoding(nsACString const& aSegment,
nsIChannel* aChannel);
// The caller may have the bytes for the stylesheet split across two strings,
// so aBytes1 and aBytes2 refer to those pieces.
@ -111,10 +111,6 @@ class SheetLoadData final : public nsIRunnable, public nsIThreadObserver {
// during the parse
const RefPtr<SheetLoadData> mParentData;
// The expiration time of the channel that has loaded this data, if
// applicable.
uint32_t mExpirationTime = 0;
// Number of sheets we @import-ed that are still loading
uint32_t mPendingChildren;
@ -206,11 +202,9 @@ class SheetLoadData final : public nsIRunnable, public nsIThreadObserver {
// The node that identifies who started loading us.
const nsCOMPtr<nsINode> mRequestingNode;
// The encoding guessed from attributes and the document character set.
const NotNull<const Encoding*> mGuessedEncoding;
// The quirks mode of the loader at the time the load was triggered.
const nsCompatibility mCompatMode;
// The encoding to use for preloading Must be empty if mOwningElement
// is non-null.
const Encoding* const mPreloadEncoding;
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
// Whether SheetComplete was called.

Просмотреть файл

@ -8,7 +8,6 @@
#include "mozilla/Encoding.h"
#include "mozilla/ScopeExit.h"
#include "nsContentUtils.h"
#include "nsIChannel.h"
#include "nsIInputStream.h"
#include "nsISupportsPriority.h"
@ -133,15 +132,6 @@ StreamLoader::OnStopRequest(nsIRequest* aRequest, nsresult aStatus) {
}
} // run destructor for `bytes`
auto info = nsContentUtils::GetSubresourceCacheValidationInfo(aRequest);
// For now, we never cache entries that we have to revalidate.
if (!info.mExpirationTime || info.mMustRevalidate) {
info.mExpirationTime =
Some(nsContentUtils::SecondsFromPRTime(PR_Now()) - 1);
}
mSheetLoadData->mExpirationTime = *info.mExpirationTime;
// For reasons I don't understand, factoring the below lines into
// a method on SheetLoadData resulted in a linker error. Hence,
// accessing fields of mSheetLoadData from here.

Просмотреть файл

@ -1193,7 +1193,7 @@ RefPtr<StyleSheetParsePromise> StyleSheet::ParseSheet(
RefPtr<RawServoStyleSheetContents> contents =
Servo_StyleSheet_FromUTF8Bytes(
&aLoader, this, &aLoadData, &aBytes, mParsingMode, Inner().mURLData,
aLoadData.mLineNumber, aLoadData.mCompatMode,
aLoadData.mLineNumber, aLoader.GetCompatibilityMode(),
/* reusable_sheets = */ nullptr, useCounters, allowImportRules,
StyleSanitizationKind::None,
/* sanitized_output = */ nullptr)
@ -1203,7 +1203,7 @@ RefPtr<StyleSheetParsePromise> StyleSheet::ParseSheet(
auto holder = MakeRefPtr<css::SheetLoadDataHolder>(__func__, &aLoadData);
Servo_StyleSheet_FromUTF8BytesAsync(
holder, Inner().mURLData, &aBytes, mParsingMode, aLoadData.mLineNumber,
aLoadData.mCompatMode,
aLoader.GetCompatibilityMode(),
/* should_record_use_counters = */ !!useCounters, allowImportRules);
}

Просмотреть файл

@ -107,7 +107,6 @@ EXPORTS.mozilla += [
'ServoTypes.h',
'ServoUtils.h',
'ShadowParts.h',
'SharedStyleSheetCache.h',
'StyleAnimationValue.h',
'StyleColorInlines.h',
'StyleSheet.h',
@ -223,7 +222,6 @@ UNIFIED_SOURCES += [
'ServoElementSnapshot.cpp',
'ServoStyleSet.cpp',
'ShadowParts.cpp',
'SharedStyleSheetCache.cpp',
'StreamLoader.cpp',
'StyleAnimationValue.cpp',
'StyleColor.cpp',

Просмотреть файл

@ -354,6 +354,3 @@ StyleFontDisplay nsFontFaceLoader::GetFontDisplay() {
}
return mUserFontEntry->GetFontDisplay();
}
#undef LOG
#undef LOG_ENABLED

Просмотреть файл

@ -1,3 +0,0 @@
:root {
background-color: lime;
}

Просмотреть файл

@ -1,12 +0,0 @@
<!doctype html>
<meta charset="utf-8">
<link rel="stylesheet" href="file_shared_sheet_caching.css">
<script>
onload = function() {
if (parent != window) {
parent.childWindowLoaded(window);
} else {
window.opener.childWindowLoaded(window);
}
}
</script>

Просмотреть файл

@ -323,8 +323,6 @@ support-files = redundant_font_download.sjs
[test_selectors.html]
[test_setPropertyWithNull.html]
[test_shape_outside_CORS.html]
[test_shared_sheet_caching.html]
support-files = file_shared_sheet_caching.css file_shared_sheet_caching.html
[test_shorthand_property_getters.html]
[test_specified_value_serialization.html]
support-files = file_specified_value_serialization_individual_transforms.html

Просмотреть файл

@ -1,35 +0,0 @@
<!doctype html>
<meta charset="utf-8">
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script>
function childWindowLoaded(childWin) {
is(
childWin.getComputedStyle(childWin.document.documentElement).backgroundColor,
"rgb(0, 255, 0)",
"Sheet should apply",
)
is(
SpecialPowers.getDOMWindowUtils(childWin).parsedStyleSheets,
0,
`Shouldn't need to parse the stylesheet ${childWin.parent == window ? "frame" : "top"}`
);
if (childWin.top == childWin) {
SimpleTest.finish();
}
}
</script>
<link rel="stylesheet" href="file_shared_sheet_caching.css">
<iframe src="file_shared_sheet_caching.html"></iframe>
<a rel="opener" href="file_shared_sheet_caching.html" target="_blank">Navigation</a>
<script>
SimpleTest.waitForExplicitFinish();
onload = function() {
info("Sheets parsed: " + SpecialPowers.DOMWindowUtils.parsedStyleSheets);
is(
getComputedStyle(document.documentElement).backgroundColor,
"rgb(0, 255, 0)",
"Sheet should apply",
)
document.querySelector("a").click();
}
</script>

Просмотреть файл

@ -16,13 +16,11 @@ const { reloadConsoleAndLog } = require("./webconsole-helpers");
const { AppConstants } = require("resource://gre/modules/AppConstants.jsm");
const EXPECTED_MESSAGES = [
// We don't wait for these due to bug 1645180.
//
// {
// text: `This page uses the non standard property “zoom”`,
// count: isFissionEnabled() ? 2 : 4,
// visibleWhenFissionEnabled: true,
// },
{
text: `This page uses the non standard property “zoom”`,
count: isFissionEnabled() ? 2 : 4,
visibleWhenFissionEnabled: true,
},
{
text: `Layout was forced before the page was fully loaded.`,
visibleWhenFissionEnabled: true,

Просмотреть файл

@ -44,9 +44,7 @@ async function checkCache(suffixes, originAttributes) {
);
ok(
foundEntryCount > 0,
`Cache entries expected for ${suffix} and OA=${JSON.stringify(
originAttributes
)}`
`Cache entries expected for ${suffix} and OA=${originAttributes}`
);
}
}
@ -99,9 +97,6 @@ add_task(async function() {
};
await SpecialPowers.spawn(tab.linkedBrowser, [argObj], async function(arg) {
// The CSS cache needs to be cleared in-process.
content.windowUtils.clearSharedStyleSheetCache();
let videoURL = arg.urlPrefix + "file_thirdPartyChild.video.ogv";
let audioURL = arg.urlPrefix + "file_thirdPartyChild.audio.ogg";
let URLSuffix = "?r=" + arg.randomSuffix;

Просмотреть файл

@ -1 +0,0 @@
:root { color: green; }

Просмотреть файл

@ -1,3 +0,0 @@
<!doctype html>
<meta charset=utf-8>
<link rel=stylesheet href=file_stylesheet_cache.css>

Просмотреть файл

@ -1,19 +0,0 @@
<!doctype html>
<meta charset=utf-8>
<!-- The first one should hit the cache, the second one should not. -->
<link rel=stylesheet href=file_stylesheet_cache.css>
<script>
"use strict";
// This script guarantees that the load of the above stylesheet has happened
// by now.
//
// Now we can go ahead and load the other one programmatically. It's
// important that we don't just throw a <link> in the markup below to
// guarantee
// that the load happens afterwards (that is, to cheat the parser's speculative
// load mechanism).
const link = document.createElement("link");
link.rel = "stylesheet";
link.href = "file_stylesheet_cache.css?2";
document.head.appendChild(link);
</script>

Просмотреть файл

@ -1,49 +0,0 @@
"use strict";
const BASE = "http://example.com/data/";
const server = createHttpServer({ hosts: ["example.com"] });
server.registerDirectory("/data/", do_get_file("data"));
add_task(async function test_stylesheet_cache() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
permissions: ["webRequest", "webRequestBlocking", "<all_urls>"],
},
background() {
const SHEET_URI = "http://example.com/data/file_stylesheet_cache.css";
let firstFound = false;
browser.webRequest.onBeforeRequest.addListener(
details => {
browser.test.assertEq(
details.url,
firstFound ? SHEET_URI + "?2" : SHEET_URI
);
firstFound = true;
browser.test.sendMessage("stylesheet found");
},
{ urls: ["<all_urls>"], types: ["stylesheet"] },
["blocking"]
);
},
});
await extension.startup();
let cp = await ExtensionTestUtils.loadContentPage(
BASE + "file_stylesheet_cache.html"
);
await extension.awaitMessage("stylesheet found");
// Need to use the same ContentPage so that the remote process the page ends
// up in is the same.
await cp.loadURL(BASE + "file_stylesheet_cache_2.html");
await extension.awaitMessage("stylesheet found");
await cp.close();
await extension.unload();
});

Просмотреть файл

@ -73,18 +73,6 @@ function compareLists(list1, list2, kind) {
equal(String(list1), String(list2), `${kind} URLs correct`);
}
async function openAndCloseContentPage(url) {
let contentPage = await ExtensionTestUtils.loadContentPage(URL);
// Clear the sheet cache so that it doesn't interact with following tests: A
// stylesheet with the same URI loaded from the same origin doesn't otherwise
// guarantee that onBeforeRequest and so on happen, because it may not need
// to go through necko at all.
await contentPage.spawn(null, () =>
content.windowUtils.clearSharedStyleSheetCache()
);
await contentPage.close();
}
add_task(async function setup() {
// Disable rcwn to make cache behavior deterministic.
Services.prefs.setBoolPref("network.http.rcwn.enabled", false);
@ -103,7 +91,8 @@ add_task(async function filter_urls() {
]);
WebRequest.onResponseStarted.addListener(onResponseStarted, filter);
await openAndCloseContentPage(URL);
let contentPage = await ExtensionTestUtils.loadContentPage(URL);
await contentPage.close();
compareLists(requested, expected_urls, "requested");
compareLists(sendHeaders, expected_urls, "sendHeaders");
@ -124,7 +113,8 @@ add_task(async function filter_types() {
]);
WebRequest.onResponseStarted.addListener(onResponseStarted, filter);
await openAndCloseContentPage(URL);
let contentPage = await ExtensionTestUtils.loadContentPage(URL);
await contentPage.close();
compareLists(requested, expected_urls, "requested");
compareLists(sendHeaders, expected_urls, "sendHeaders");
@ -147,7 +137,8 @@ add_task(async function filter_windowId() {
]);
WebRequest.onResponseStarted.addListener(onResponseStarted, filter);
await openAndCloseContentPage(URL);
let contentPage = await ExtensionTestUtils.loadContentPage(URL);
await contentPage.close();
compareLists(requested, [], "requested");
compareLists(sendHeaders, [], "sendHeaders");
@ -170,7 +161,8 @@ add_task(async function filter_tabId() {
]);
WebRequest.onResponseStarted.addListener(onResponseStarted, filter);
await openAndCloseContentPage(URL);
let contentPage = await ExtensionTestUtils.loadContentPage(URL);
await contentPage.close();
compareLists(requested, [], "requested");
compareLists(sendHeaders, [], "sendHeaders");

Просмотреть файл

@ -201,7 +201,6 @@ skip-if = os == "android" && debug
skip-if = appname == "thunderbird" || (os == "android" && debug)
[test_ext_webRequest_startup.js]
skip-if = os == "android" && debug
[test_ext_webRequest_style_cache.js]
[test_ext_webRequest_suspend.js]
[test_ext_webRequest_userContextId.js]
[test_ext_webRequest_webSocket.js]

Просмотреть файл

@ -78,7 +78,6 @@ function reset() {
// This test has to come before testPositiveCache to ensure gethash server doesn't
// contain completions.
function testNegativeCache() {
SpecialPowers.DOMWindowUtils.clearSharedStyleSheetCache();
shouldLoad = true;
async function setup() {
@ -107,7 +106,6 @@ function testNegativeCache() {
}
function testPositiveCache() {
SpecialPowers.DOMWindowUtils.clearSharedStyleSheetCache();
shouldLoad = false;
async function setup() {

Просмотреть файл

@ -80,8 +80,6 @@ async function runTests() {
await SpecialPowers.pushPrefEnv({set: [
[ "privacy.trackingprotection.annotate_channels", true],
]});
// Ensure we clear the stylesheet cache so that we re-classify.
SpecialPowers.DOMWindowUtils.clearSharedStyleSheetCache();
await loadTestWindow(false);