Bug 1571530 - Cleanup confusing lifetime of SheetLoadData. r=heycam

Saving a refcount bump is not worth the churn. Use a proper RefPtr<>
everywhere instead of manual refcounting, and don't make DoSheetComplete call
NS_RELEASE unconditionally.

Also, make clear by using references where null is expected or not.

Also, properly use a RefPtr in mPendingDatas, since they are strong pointers,
in fact.

Finally, remove some unused macros from nsCSSValue of which this code was the
last consumer.

Differential Revision: https://phabricator.services.mozilla.com/D41090

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Emilio Cobos Álvarez 2019-08-16 10:56:09 +00:00
parent 588365a846
commit 36d3f1e1b9
9 changed files with 210 additions and 281 deletions

View File

@ -1747,7 +1747,7 @@ static already_AddRefed<StyleSheet> LoadImportSheet(
StyleSheet* previousFirstChild = aParent->GetFirstChild();
if (NS_SUCCEEDED(rv)) {
rv = aLoader->LoadChildSheet(aParent, aParentLoadData, uri, media,
rv = aLoader->LoadChildSheet(*aParent, aParentLoadData, uri, media,
aReusableSheets);
}

View File

@ -165,7 +165,7 @@ class SheetLoadDataHashKey : public nsURIHashKey {
MOZ_COUNT_CTOR(SheetLoadDataHashKey);
}
explicit SheetLoadDataHashKey(css::SheetLoadData* aLoadData);
explicit SheetLoadDataHashKey(css::SheetLoadData&);
~SheetLoadDataHashKey() { MOZ_COUNT_DTOR(SheetLoadDataHashKey); }
@ -224,12 +224,12 @@ class SheetLoadDataHashKey : public nsURIHashKey {
css::SheetParsingMode mParsingMode;
};
SheetLoadDataHashKey::SheetLoadDataHashKey(css::SheetLoadData* aLoadData)
: nsURIHashKey(aLoadData->mURI),
mPrincipal(aLoadData->mLoaderPrincipal),
mReferrerInfo(aLoadData->ReferrerInfo()),
mCORSMode(aLoadData->mSheet->GetCORSMode()),
mParsingMode(aLoadData->mSheet->ParsingMode()) {
SheetLoadDataHashKey::SheetLoadDataHashKey(css::SheetLoadData& aLoadData)
: nsURIHashKey(aLoadData.mURI),
mPrincipal(aLoadData.mLoaderPrincipal),
mReferrerInfo(aLoadData.ReferrerInfo()),
mCORSMode(aLoadData.mSheet->GetCORSMode()),
mParsingMode(aLoadData.mSheet->ParsingMode()) {
MOZ_COUNT_CTOR(SheetLoadDataHashKey);
}
} // namespace mozilla
@ -362,12 +362,16 @@ SheetLoadData::SheetLoadData(Loader* aLoader, nsIURI* aURI, StyleSheet* aSheet,
}
SheetLoadData::~SheetLoadData() {
NS_CSS_NS_RELEASE_LIST_MEMBER(SheetLoadData, this, mNext);
// Do this iteratively to avoid blowing up the stack.
RefPtr<SheetLoadData> next = mNext.forget();
while (next) {
next = next->mNext.forget();
}
}
NS_IMETHODIMP
SheetLoadData::Run() {
mLoader->HandleLoadEvent(this);
mLoader->HandleLoadEvent(*this);
return NS_OK;
}
@ -451,9 +455,11 @@ bool LoaderReusableStyleSheets::FindReusableStyleSheet(
// or already loaded (the later one for caching purposes).
struct Loader::Sheets {
nsRefPtrHashtable<SheetLoadDataHashKey, StyleSheet> mCompleteSheets;
// The SheetLoadData pointers below are weak references.
nsRefPtrHashtable<SheetLoadDataHashKey, SheetLoadData> mPendingDatas;
// The SheetLoadData pointers in mLoadingDatas below are weak references.
nsDataHashtable<SheetLoadDataHashKey, SheetLoadData*> mLoadingDatas;
nsDataHashtable<SheetLoadDataHashKey, SheetLoadData*> mPendingDatas;
// A cache hit or miss. It is a miss if the `StyleSheet` is null.
using CacheResult = Tuple<RefPtr<StyleSheet>, SheetState>;
@ -541,7 +547,7 @@ auto Loader::Sheets::Lookup(SheetLoadDataHashKey& aKey, bool aSyncLoad)
return MakeTuple(CloneSheet(*data->mSheet), SheetState::Loading);
}
if (SheetLoadData* data = mPendingDatas.Get(&aKey)) {
if (SheetLoadData* data = mPendingDatas.GetWeak(&aKey)) {
LOG((" From pending: %p", data->mSheet.get()));
AssertIncompleteSheetMatches(*data, aKey);
return MakeTuple(CloneSheet(*data->mSheet), SheetState::Pending);
@ -599,22 +605,22 @@ void Loader::DocumentStyleSheetSetChanged() {
LoadDataArray arr(mSheets->mPendingDatas.Count());
for (auto iter = mSheets->mPendingDatas.Iter(); !iter.Done(); iter.Next()) {
SheetLoadData* data = iter.Data();
RefPtr<SheetLoadData>& data = iter.Data();
MOZ_ASSERT(data, "Must have a data");
// Note that we don't want to affect what the selected style set is, so
// use true for aHasAlternateRel.
auto isAlternate = data->mLoader->IsAlternateSheet(data->mTitle, true);
if (isAlternate == IsAlternate::No) {
arr.AppendElement(data);
arr.AppendElement(std::move(data));
iter.Remove();
}
}
mDatasToNotifyOn += arr.Length();
for (uint32_t i = 0; i < arr.Length(); ++i) {
for (RefPtr<SheetLoadData>& data : arr) {
--mDatasToNotifyOn;
LoadSheet(arr[i], SheetState::NeedsParser, IsPreload::No);
LoadSheet(*data, SheetState::NeedsParser, IsPreload::No);
}
}
@ -763,7 +769,7 @@ nsresult SheetLoadData::VerifySheetReadyToParse(nsresult aStatus,
if (!mLoader->mDocument && !mIsNonDocumentSheet) {
// Sorry, we don't care about this load anymore
LOG_WARN((" No document and not non-document sheet; dropping load"));
mLoader->SheetComplete(this, NS_BINDING_ABORTED);
mLoader->SheetComplete(*this, NS_BINDING_ABORTED);
return NS_OK;
}
@ -788,12 +794,12 @@ nsresult SheetLoadData::VerifySheetReadyToParse(nsresult aStatus,
}
}
}
mLoader->SheetComplete(this, aStatus);
mLoader->SheetComplete(*this, aStatus);
return NS_OK;
}
if (!aChannel) {
mLoader->SheetComplete(this, NS_OK);
mLoader->SheetComplete(*this, NS_OK);
return NS_OK;
}
@ -811,7 +817,7 @@ nsresult SheetLoadData::VerifySheetReadyToParse(nsresult aStatus,
if (!channelURI || !originalURI) {
NS_ERROR("Someone just violated the nsIRequest contract");
LOG_WARN((" Channel without a URI. Bad!"));
mLoader->SheetComplete(this, NS_ERROR_UNEXPECTED);
mLoader->SheetComplete(*this, NS_ERROR_UNEXPECTED);
return NS_OK;
}
@ -829,7 +835,7 @@ nsresult SheetLoadData::VerifySheetReadyToParse(nsresult aStatus,
if (NS_FAILED(result)) {
LOG_WARN((" Couldn't get principal"));
mLoader->SheetComplete(this, result);
mLoader->SheetComplete(*this, result);
return NS_OK;
}
@ -851,7 +857,7 @@ nsresult SheetLoadData::VerifySheetReadyToParse(nsresult aStatus,
result = httpChannel->GetRequestSucceeded(&requestSucceeded);
if (NS_SUCCEEDED(result) && !requestSucceeded) {
LOG((" Load returned an error page"));
mLoader->SheetComplete(this, NS_ERROR_NOT_AVAILABLE);
mLoader->SheetComplete(*this, NS_ERROR_NOT_AVAILABLE);
return NS_OK;
}
@ -906,7 +912,7 @@ nsresult SheetLoadData::VerifySheetReadyToParse(nsresult aStatus,
if (errorFlag == nsIScriptError::errorFlag) {
LOG_WARN(
(" Ignoring sheet with improper MIME type %s", contentType.get()));
mLoader->SheetComplete(this, NS_ERROR_NOT_AVAILABLE);
mLoader->SheetComplete(*this, NS_ERROR_NOT_AVAILABLE);
return NS_OK;
}
}
@ -933,7 +939,7 @@ nsresult SheetLoadData::VerifySheetReadyToParse(nsresult aStatus,
LOG((" Load was blocked by SRI"));
MOZ_LOG(gSriPRLog, mozilla::LogLevel::Debug,
("css::Loader::OnStreamComplete, bad metadata"));
mLoader->SheetComplete(this, NS_ERROR_SRI_CORRUPT);
mLoader->SheetComplete(*this, NS_ERROR_SRI_CORRUPT);
return NS_OK;
}
}
@ -1232,22 +1238,21 @@ void Loader::InsertChildSheet(StyleSheet& aSheet, StyleSheet& aParentSheet) {
* existing load for this URI and piggyback on it. Failing all that,
* a new load is kicked off asynchronously.
*/
nsresult Loader::LoadSheet(SheetLoadData* aLoadData, SheetState aSheetState,
nsresult Loader::LoadSheet(SheetLoadData& aLoadData, SheetState aSheetState,
IsPreload aIsPreload) {
LOG(("css::Loader::LoadSheet"));
MOZ_ASSERT(aLoadData, "Need a load data");
MOZ_ASSERT(aLoadData->mURI, "Need a URI to load");
MOZ_ASSERT(aLoadData->mSheet, "Need a sheet to load into");
MOZ_ASSERT(aLoadData.mURI, "Need a URI to load");
MOZ_ASSERT(aLoadData.mSheet, "Need a sheet to load into");
MOZ_ASSERT(aSheetState != SheetState::Complete, "Why bother?");
MOZ_ASSERT(!aLoadData->mUseSystemPrincipal || aLoadData->mSyncLoad,
MOZ_ASSERT(!aLoadData.mUseSystemPrincipal || aLoadData.mSyncLoad,
"Shouldn't use system principal for async loads");
NS_ASSERTION(mSheets, "mLoadingDatas should be initialized by now.");
LOG_URI(" Load from: '%s'", aLoadData->mURI);
LOG_URI(" Load from: '%s'", aLoadData.mURI);
nsresult rv = NS_OK;
if (!mDocument && !aLoadData->mIsNonDocumentSheet) {
if (!mDocument && !aLoadData.mIsNonDocumentSheet) {
// No point starting the load; just release all the data and such.
LOG_WARN((" No document and not non-document sheet; pre-dropping load"));
SheetComplete(aLoadData, NS_BINDING_ABORTED);
@ -1255,11 +1260,11 @@ nsresult Loader::LoadSheet(SheetLoadData* aLoadData, SheetState aSheetState,
}
SRIMetadata sriMetadata;
aLoadData->mSheet->GetIntegrity(sriMetadata);
aLoadData.mSheet->GetIntegrity(sriMetadata);
if (aLoadData->mSyncLoad) {
if (aLoadData.mSyncLoad) {
LOG((" Synchronous load"));
NS_ASSERTION(!aLoadData->mObserver, "Observer for a sync load?");
NS_ASSERTION(!aLoadData.mObserver, "Observer for a sync load?");
NS_ASSERTION(aSheetState == SheetState::NeedsParser,
"Sync loads can't reuse existing async loads");
@ -1269,7 +1274,7 @@ nsresult Loader::LoadSheet(SheetLoadData* aLoadData, SheetState aSheetState,
nsCOMPtr<nsIStreamListener> streamLoader = new StreamLoader(aLoadData);
if (mDocument) {
mozilla::net::PredictorLearn(aLoadData->mURI, mDocument->GetDocumentURI(),
mozilla::net::PredictorLearn(aLoadData.mURI, mDocument->GetDocumentURI(),
nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE,
mDocument);
}
@ -1290,27 +1295,27 @@ nsresult Loader::LoadSheet(SheetLoadData* aLoadData, SheetState aSheetState,
// This is because of a case where the node is the document being styled and
// the principal is the stylesheet (perhaps from a different origin) that is
// applying the styles.
if (aLoadData->mRequestingNode && aLoadData->mLoaderPrincipal) {
if (aLoadData.mRequestingNode && aLoadData.mLoaderPrincipal) {
rv = NS_NewChannelWithTriggeringPrincipal(
getter_AddRefs(channel), aLoadData->mURI, aLoadData->mRequestingNode,
aLoadData->mLoaderPrincipal, securityFlags, contentPolicyType);
getter_AddRefs(channel), aLoadData.mURI, aLoadData.mRequestingNode,
aLoadData.mLoaderPrincipal, securityFlags, contentPolicyType);
} else {
// either we are loading something inside a document, in which case
// we should always have a requestingNode, or we are loading something
// outside a document, in which case the loadingPrincipal and the
// triggeringPrincipal should always be the systemPrincipal.
auto result = URLPreloader::ReadURI(aLoadData->mURI);
auto result = URLPreloader::ReadURI(aLoadData.mURI);
if (result.isOk()) {
nsCOMPtr<nsIInputStream> stream;
MOZ_TRY(
NS_NewCStringInputStream(getter_AddRefs(stream), result.unwrap()));
rv = NS_NewInputStreamChannel(getter_AddRefs(channel), aLoadData->mURI,
rv = NS_NewInputStreamChannel(getter_AddRefs(channel), aLoadData.mURI,
stream.forget(),
nsContentUtils::GetSystemPrincipal(),
securityFlags, contentPolicyType);
} else {
rv = NS_NewChannel(getter_AddRefs(channel), aLoadData->mURI,
rv = NS_NewChannel(getter_AddRefs(channel), aLoadData.mURI,
nsContentUtils::GetSystemPrincipal(), securityFlags,
contentPolicyType);
}
@ -1323,7 +1328,7 @@ nsresult Loader::LoadSheet(SheetLoadData* aLoadData, SheetState aSheetState,
// snapshot the nonce at load start time for performing CSP checks
if (contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_STYLESHEET) {
nsCOMPtr<Element> element = do_QueryInterface(aLoadData->mRequestingNode);
nsCOMPtr<Element> element = do_QueryInterface(aLoadData.mRequestingNode);
if (element && element->IsHTMLElement()) {
nsAutoString cspNonce;
element->GetAttribute(NS_LITERAL_STRING("nonce"), cspNonce);
@ -1359,10 +1364,10 @@ nsresult Loader::LoadSheet(SheetLoadData* aLoadData, SheetState aSheetState,
SheetLoadDataHashKey key(aLoadData);
if (aSheetState == SheetState::Loading) {
mSheets->mLoadingDatas.Get(&key, &existingData);
existingData = mSheets->mLoadingDatas.Get(&key);
NS_ASSERTION(existingData, "CreateSheet lied about the state");
} else if (aSheetState == SheetState::Pending) {
mSheets->mPendingDatas.Get(&key, &existingData);
existingData = mSheets->mPendingDatas.GetWeak(&key);
NS_ASSERTION(existingData, "CreateSheet lied about the state");
}
@ -1372,21 +1377,15 @@ nsresult Loader::LoadSheet(SheetLoadData* aLoadData, SheetState aSheetState,
while (data->mNext) {
data = data->mNext;
}
data->mNext = aLoadData; // transfer ownership
if (aSheetState == SheetState::Pending && !aLoadData->ShouldDefer()) {
data->mNext = &aLoadData;
if (aSheetState == SheetState::Pending && !aLoadData.ShouldDefer()) {
// Kick the load off; someone cares about it right away
#ifdef DEBUG
SheetLoadData* removedData;
NS_ASSERTION(mSheets->mPendingDatas.Get(&key, &removedData) &&
removedData == existingData,
"Bad pending table.");
#endif
mSheets->mPendingDatas.Remove(&key);
RefPtr<SheetLoadData> removedData;
mSheets->mPendingDatas.Remove(&key, getter_AddRefs(removedData));
MOZ_ASSERT(removedData == existingData, "Bad loading table");
LOG((" Forcing load of pending data"));
return LoadSheet(existingData, SheetState::NeedsParser, aIsPreload);
return LoadSheet(*removedData, SheetState::NeedsParser, aIsPreload);
}
// All done here; once the load completes we'll be marked complete
// automatically
@ -1413,7 +1412,7 @@ nsresult Loader::LoadSheet(SheetLoadData* aLoadData, SheetState aSheetState,
mSyncCallback = true;
#endif
CORSMode ourCORSMode = aLoadData->mSheet->GetCORSMode();
CORSMode ourCORSMode = aLoadData.mSheet->GetCORSMode();
nsSecurityFlags securityFlags =
ourCORSMode == CORS_NONE
? nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS
@ -1435,22 +1434,20 @@ nsresult Loader::LoadSheet(SheetLoadData* aLoadData, SheetState aSheetState,
// and a principal. This is because of a case where the node is the document
// being styled and the principal is the stylesheet (perhaps from a different
// origin) that is applying the styles.
if (aLoadData->mRequestingNode && aLoadData->mLoaderPrincipal) {
if (aLoadData.mRequestingNode && aLoadData.mLoaderPrincipal) {
rv = NS_NewChannelWithTriggeringPrincipal(
getter_AddRefs(channel), aLoadData->mURI, aLoadData->mRequestingNode,
aLoadData->mLoaderPrincipal, securityFlags, contentPolicyType,
nullptr, // Performancestorage
loadGroup);
getter_AddRefs(channel), aLoadData.mURI, aLoadData.mRequestingNode,
aLoadData.mLoaderPrincipal, securityFlags, contentPolicyType,
/* PerformanceStorage */ nullptr, loadGroup);
} else {
// either we are loading something inside a document, in which case
// we should always have a requestingNode, or we are loading something
// outside a document, in which case the loadingPrincipal and the
// triggeringPrincipal should always be the systemPrincipal.
rv = NS_NewChannel(getter_AddRefs(channel), aLoadData->mURI,
rv = NS_NewChannel(getter_AddRefs(channel), aLoadData.mURI,
nsContentUtils::GetSystemPrincipal(), securityFlags,
contentPolicyType, cookieSettings,
nullptr, // aPerformanceStorage
loadGroup);
/* aPerformanceStorage */ nullptr, loadGroup);
}
if (NS_FAILED(rv)) {
@ -1461,7 +1458,7 @@ nsresult Loader::LoadSheet(SheetLoadData* aLoadData, SheetState aSheetState,
// snapshot the nonce at load start time for performing CSP checks
if (contentPolicyType == nsIContentPolicy::TYPE_INTERNAL_STYLESHEET) {
nsCOMPtr<Element> element = do_QueryInterface(aLoadData->mRequestingNode);
nsCOMPtr<Element> element = do_QueryInterface(aLoadData.mRequestingNode);
if (element && element->IsHTMLElement()) {
nsAutoString cspNonce;
element->GetAttribute(NS_LITERAL_STRING("nonce"), cspNonce);
@ -1470,17 +1467,14 @@ nsresult Loader::LoadSheet(SheetLoadData* aLoadData, SheetState aSheetState,
}
}
if (!aLoadData->ShouldDefer()) {
nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
if (cos) {
if (!aLoadData.ShouldDefer()) {
if (nsCOMPtr<nsIClassOfService> cos = do_QueryInterface(channel)) {
cos->AddClassFlags(nsIClassOfService::Leader);
}
}
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
if (httpChannel) {
nsCOMPtr<nsIReferrerInfo> referrerInfo = aLoadData->ReferrerInfo();
if (referrerInfo) {
if (nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel)) {
if (nsCOMPtr<nsIReferrerInfo> referrerInfo = aLoadData.ReferrerInfo()) {
rv = httpChannel->SetReferrerInfo(referrerInfo);
Unused << NS_WARN_IF(NS_FAILED(rv));
}
@ -1494,9 +1488,9 @@ nsresult Loader::LoadSheet(SheetLoadData* aLoadData, SheetState aSheetState,
}
// Set the initiator type
nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(httpChannel));
if (timedChannel) {
if (aLoadData->mParentData) {
if (nsCOMPtr<nsITimedChannel> timedChannel =
do_QueryInterface(httpChannel)) {
if (aLoadData.mParentData) {
timedChannel->SetInitiatorType(NS_LITERAL_STRING("css"));
// This is a child sheet load.
@ -1520,11 +1514,11 @@ nsresult Loader::LoadSheet(SheetLoadData* aLoadData, SheetState aSheetState,
// sub-resource and so we set the flag on ourself too to propagate it
// on down.
//
if (aLoadData->mParentData->mIsCrossOriginNoCORS ||
aLoadData->mParentData->mBlockResourceTiming) {
if (aLoadData.mParentData->mIsCrossOriginNoCORS ||
aLoadData.mParentData->mBlockResourceTiming) {
// Set a flag so any other stylesheet triggered by this one will
// not be reported
aLoadData->mBlockResourceTiming = true;
aLoadData.mBlockResourceTiming = true;
// Mark the channel so PerformanceMainThread::AddEntry will not
// report the resource.
@ -1547,7 +1541,7 @@ nsresult Loader::LoadSheet(SheetLoadData* aLoadData, SheetState aSheetState,
nsCOMPtr<nsIStreamListener> streamLoader = new StreamLoader(aLoadData);
if (mDocument) {
mozilla::net::PredictorLearn(aLoadData->mURI, mDocument->GetDocumentURI(),
mozilla::net::PredictorLearn(aLoadData.mURI, mDocument->GetDocumentURI(),
nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE,
mDocument);
}
@ -1560,8 +1554,8 @@ nsresult Loader::LoadSheet(SheetLoadData* aLoadData, SheetState aSheetState,
return rv;
}
mSheets->mLoadingDatas.Put(&key, aLoadData);
aLoadData->mIsLoading = true;
mSheets->mLoadingDatas.Put(&key, &aLoadData);
aLoadData.mIsLoading = true;
return NS_OK;
}
@ -1570,33 +1564,32 @@ nsresult Loader::LoadSheet(SheetLoadData* aLoadData, SheetState aSheetState,
* ParseSheet handles parsing the data stream.
*/
Loader::Completed Loader::ParseSheet(const nsACString& aBytes,
SheetLoadData* aLoadData,
SheetLoadData& aLoadData,
AllowAsyncParse aAllowAsync) {
LOG(("css::Loader::ParseSheet"));
AUTO_PROFILER_LABEL("css::Loader::ParseSheet", LAYOUT_CSSParsing);
MOZ_ASSERT(aLoadData);
aLoadData->mIsBeingParsed = true;
aLoadData.mIsBeingParsed = true;
// Tell the record/replay system about any sheets that are being parsed,
// so that devtools code can find them later.
if (recordreplay::IsRecordingOrReplaying() && aLoadData->mURI) {
if (recordreplay::IsRecordingOrReplaying() && aLoadData.mURI) {
recordreplay::NoteContentParse(
aLoadData, aLoadData->mURI->GetSpecOrDefault().get(), "text/css",
&aLoadData, aLoadData.mURI->GetSpecOrDefault().get(), "text/css",
reinterpret_cast<const Utf8Unit*>(aBytes.BeginReading()),
aBytes.Length());
}
StyleSheet* sheet = aLoadData->mSheet;
StyleSheet* sheet = aLoadData.mSheet;
MOZ_ASSERT(sheet);
// Some cases, like inline style and UA stylesheets, need to be parsed
// synchronously. The former may trigger child loads, the latter must not.
if (aLoadData->mSyncLoad || aAllowAsync == AllowAsyncParse::No) {
sheet->ParseSheetSync(this, aBytes, aLoadData, aLoadData->mLineNumber);
aLoadData->mIsBeingParsed = false;
if (aLoadData.mSyncLoad || aAllowAsync == AllowAsyncParse::No) {
sheet->ParseSheetSync(this, aBytes, &aLoadData, aLoadData.mLineNumber);
aLoadData.mIsBeingParsed = false;
bool noPendingChildren = aLoadData->mPendingChildren == 0;
MOZ_ASSERT_IF(aLoadData->mSyncLoad, noPendingChildren);
bool noPendingChildren = aLoadData.mPendingChildren == 0;
MOZ_ASSERT_IF(aLoadData.mSyncLoad, noPendingChildren);
if (noPendingChildren) {
SheetComplete(aLoadData, NS_OK);
return Completed::Yes;
@ -1609,12 +1602,11 @@ Loader::Completed Loader::ParseSheet(const nsACString& aBytes,
// Note that we need to block onload because there may be no network requests
// pending.
BlockOnload();
RefPtr<SheetLoadData> loadData = aLoadData;
nsCOMPtr<nsISerialEventTarget> target = DispatchTarget();
sheet->ParseSheet(this, aBytes, aLoadData)
sheet->ParseSheet(*this, aBytes, aLoadData)
->Then(
target, __func__,
[loadData = std::move(loadData)](bool aDummy) {
[loadData = RefPtr<SheetLoadData>(&aLoadData)](bool aDummy) {
MOZ_ASSERT(NS_IsMainThread());
loadData->mIsBeingParsed = false;
loadData->mLoader->UnblockOnload(/* aFireSync = */ false);
@ -1622,7 +1614,7 @@ Loader::Completed Loader::ParseSheet(const nsACString& aBytes,
// Otherwise, the children are holding strong refs to the data
// and will call SheetComplete() on it when they complete.
if (loadData->mPendingChildren == 0) {
loadData->mLoader->SheetComplete(loadData, NS_OK);
loadData->mLoader->SheetComplete(*loadData, NS_OK);
}
},
[] { MOZ_CRASH("rejected parse promise"); });
@ -1637,7 +1629,7 @@ Loader::Completed Loader::ParseSheet(const nsACString& aBytes,
* blocked parent loads as needed, and most importantly calls
* NS_RELEASE on the load data to destroy the whole mess.
*/
void Loader::SheetComplete(SheetLoadData* aLoadData, nsresult aStatus) {
void Loader::SheetComplete(SheetLoadData& aLoadData, nsresult aStatus) {
LOG(("css::Loader::SheetComplete, status: 0x%" PRIx32,
static_cast<uint32_t>(aStatus)));
@ -1689,35 +1681,34 @@ void Loader::SheetComplete(SheetLoadData* aLoadData, nsresult aStatus) {
}
}
void Loader::DoSheetComplete(SheetLoadData* aLoadData,
void Loader::DoSheetComplete(SheetLoadData& aLoadData,
LoadDataArray& aDatasToNotify) {
LOG(("css::Loader::DoSheetComplete"));
MOZ_ASSERT(aLoadData, "Must have a load data!");
MOZ_ASSERT(aLoadData->mSheet, "Must have a sheet");
NS_ASSERTION(mSheets || !aLoadData->mURI,
MOZ_ASSERT(aLoadData.mSheet, "Must have a sheet");
NS_ASSERTION(mSheets || !aLoadData.mURI,
"mLoadingDatas should be initialized by now.");
// Twiddle the hashtables
if (aLoadData->mURI) {
LOG_URI(" Finished loading: '%s'", aLoadData->mURI);
if (aLoadData.mURI) {
LOG_URI(" Finished loading: '%s'", aLoadData.mURI);
// Remove the data from the list of loading datas
if (aLoadData->mIsLoading) {
if (aLoadData.mIsLoading) {
SheetLoadDataHashKey key(aLoadData);
#ifdef DEBUG
SheetLoadData* loadingData;
NS_ASSERTION(mSheets->mLoadingDatas.Get(&key, &loadingData) &&
loadingData == aLoadData,
loadingData == &aLoadData,
"Bad loading table");
#endif
mSheets->mLoadingDatas.Remove(&key);
aLoadData->mIsLoading = false;
aLoadData.mIsLoading = false;
}
}
// Go through and deal with the whole linked list.
SheetLoadData* data = aLoadData;
while (data) {
SheetLoadData* data = &aLoadData;
do {
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
@ -1746,35 +1737,36 @@ void Loader::DoSheetComplete(SheetLoadData* aLoadData,
// or some such).
if (data->mParentData && --(data->mParentData->mPendingChildren) == 0 &&
!data->mParentData->mIsBeingParsed) {
DoSheetComplete(data->mParentData, aDatasToNotify);
DoSheetComplete(*data->mParentData, aDatasToNotify);
}
data = data->mNext;
}
} while (data);
// Now that it's marked complete, put the sheet in our cache.
// 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 (!aLoadData->mLoadFailed && aLoadData->mURI) {
if (!aLoadData.mLoadFailed && aLoadData.mURI) {
// Pick our sheet to cache carefully. Ideally, we want to cache
// one of the sheets that will be kept alive by a document or
// parent sheet anyway, so that if someone then accesses it via
// CSSOM we won't have extra clones of the inner lying around.
data = aLoadData;
StyleSheet* sheet = aLoadData->mSheet;
while (data) {
data = &aLoadData;
StyleSheet* sheet = aLoadData.mSheet;
do {
if (data->mSheet->GetParentSheet() || data->mSheet->GetOwnerNode()) {
sheet = data->mSheet;
break;
}
data = data->mNext;
}
} while (data);
#ifdef MOZ_XUL
if (IsChromeURI(aLoadData->mURI)) {
if (IsChromeURI(aLoadData.mURI)) {
nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
if (cache && cache->IsEnabled()) {
if (!cache->GetStyleSheet(aLoadData->mURI)) {
if (!cache->GetStyleSheet(aLoadData.mURI)) {
LOG((" Putting sheet in XUL prototype cache"));
NS_ASSERTION(sheet->IsComplete(),
"Should only be caching complete sheets");
@ -1791,24 +1783,23 @@ void Loader::DoSheetComplete(SheetLoadData* aLoadData,
}
#endif
}
NS_RELEASE(aLoadData); // this will release parents and siblings and all that
}
void Loader::MarkLoadTreeFailed(SheetLoadData* aLoadData) {
if (aLoadData->mURI) {
LOG_URI(" Load failed: '%s'", aLoadData->mURI);
void Loader::MarkLoadTreeFailed(SheetLoadData& aLoadData) {
if (aLoadData.mURI) {
LOG_URI(" Load failed: '%s'", aLoadData.mURI);
}
SheetLoadData* data = &aLoadData;
do {
aLoadData->mLoadFailed = true;
data->mLoadFailed = true;
if (aLoadData->mParentData) {
MarkLoadTreeFailed(aLoadData->mParentData);
if (data->mParentData) {
MarkLoadTreeFailed(*data->mParentData);
}
aLoadData = aLoadData->mNext;
} while (aLoadData);
data = data->mNext;
} while (data);
}
Result<Loader::LoadSheetResult, nsresult> Loader::LoadInlineStyle(
@ -1866,14 +1857,12 @@ Result<Loader::LoadSheetResult, nsresult> Loader::LoadInlineStyle(
BasePrincipal::Cast(aInfo.mTriggeringPrincipal)->PrincipalToInherit();
}
SheetLoadData* data = new SheetLoadData(
auto data = MakeRefPtr<SheetLoadData>(
this, aInfo.mTitle, nullptr, sheet, false, owningElement, isAlternate,
matched, aObserver, nullptr, aInfo.mReferrerInfo, aInfo.mContent);
// We never actually load this, so just set its principal directly
sheet->SetPrincipal(principal);
NS_ADDREF(data);
data->mLineNumber = aLineNumber;
// Parse completion releases the load data.
//
@ -1881,9 +1870,8 @@ Result<Loader::LoadSheetResult, nsresult> Loader::LoadInlineStyle(
// effects of inline stylesheets are visible immediately (aside from
// @imports).
NS_ConvertUTF16toUTF8 utf8(aBuffer);
Completed completed = ParseSheet(utf8, data, AllowAsyncParse::No);
Completed completed = ParseSheet(utf8, *data, AllowAsyncParse::No);
// If the sheet is complete already, |data| may well be deleted by now.
if (completed == Completed::No) {
data->mMustNotify = true;
}
@ -1979,10 +1967,9 @@ Result<Loader::LoadSheetResult, nsresult> Loader::LoadStyleLink(
}
// Now we need to actually load it.
SheetLoadData* data = new SheetLoadData(
auto data = MakeRefPtr<SheetLoadData>(
this, aInfo.mTitle, aInfo.mURI, sheet, syncLoad, owningElement,
isAlternate, matched, aObserver, principal, aInfo.mReferrerInfo, context);
NS_ADDREF(data);
auto result = LoadSheetResult{Completed::No, isAlternate, matched};
@ -1993,14 +1980,14 @@ Result<Loader::LoadSheetResult, nsresult> Loader::LoadStyleLink(
if (!syncLoad && state == SheetState::NeedsParser &&
mSheets->mLoadingDatas.Count() != 0 && !result.ShouldBlock()) {
LOG((" Deferring sheet load"));
SheetLoadDataHashKey key(data);
SheetLoadDataHashKey key(*data);
mSheets->mPendingDatas.Put(&key, data);
data->mMustNotify = true;
return result;
}
// Load completion will free the data
rv = LoadSheet(data, state, IsPreload::No);
rv = LoadSheet(*data, state, IsPreload::No);
if (NS_FAILED(rv)) {
return Err(rv);
}
@ -2011,40 +1998,40 @@ Result<Loader::LoadSheetResult, nsresult> Loader::LoadStyleLink(
return result;
}
static bool HaveAncestorDataWithURI(SheetLoadData* aData, nsIURI* aURI) {
if (!aData->mURI) {
static bool HaveAncestorDataWithURI(SheetLoadData& aData, nsIURI* aURI) {
if (!aData.mURI) {
// Inline style; this won't have any ancestors
MOZ_ASSERT(!aData->mParentData, "How does inline style have a parent?");
MOZ_ASSERT(!aData.mParentData, "How does inline style have a parent?");
return false;
}
bool equal;
if (NS_FAILED(aData->mURI->Equals(aURI, &equal)) || equal) {
if (NS_FAILED(aData.mURI->Equals(aURI, &equal)) || equal) {
return true;
}
// Datas down the mNext chain have the same URI as aData, so we
// don't have to compare to them. But they might have different
// parents, and we have to check all of those.
while (aData) {
if (aData->mParentData &&
HaveAncestorDataWithURI(aData->mParentData, aURI)) {
SheetLoadData* data = &aData;
do {
if (data->mParentData &&
HaveAncestorDataWithURI(*data->mParentData, aURI)) {
return true;
}
aData = aData->mNext;
}
data = data->mNext;
} while (data);
return false;
}
nsresult Loader::LoadChildSheet(StyleSheet* aParentSheet,
nsresult Loader::LoadChildSheet(StyleSheet& aParentSheet,
SheetLoadData* aParentData, nsIURI* aURL,
dom::MediaList* aMedia,
LoaderReusableStyleSheets* aReusableSheets) {
LOG(("css::Loader::LoadChildSheet"));
MOZ_ASSERT(aURL, "Must have a URI to load");
MOZ_ASSERT(aParentSheet, "Must have a parent sheet");
if (!mEnabled) {
LOG_WARN((" Not enabled"));
@ -2057,8 +2044,8 @@ nsresult Loader::LoadChildSheet(StyleSheet* aParentSheet,
// Check for an associated document or shadow root: if none, don't bother
// walking up the parent sheets.
if (aParentSheet->GetAssociatedDocumentOrShadowRoot()) {
StyleSheet* topSheet = aParentSheet;
if (aParentSheet.GetAssociatedDocumentOrShadowRoot()) {
StyleSheet* topSheet = &aParentSheet;
while (StyleSheet* parent = topSheet->GetParentSheet()) {
topSheet = parent;
}
@ -2075,12 +2062,12 @@ nsresult Loader::LoadChildSheet(StyleSheet* aParentSheet,
loadingPrincipal = mDocument->NodePrincipal();
}
nsIPrincipal* principal = aParentSheet->Principal();
nsIPrincipal* principal = aParentSheet.Principal();
nsresult rv = CheckContentPolicy(loadingPrincipal, principal, aURL, context,
IsPreload::No);
if (NS_WARN_IF(NS_FAILED(rv))) {
if (aParentData) {
MarkLoadTreeFailed(aParentData);
MarkLoadTreeFailed(*aParentData);
}
return rv;
}
@ -2090,20 +2077,20 @@ nsresult Loader::LoadChildSheet(StyleSheet* aParentSheet,
if (aParentData) {
LOG((" Have a parent load"));
// Check for cycles
if (HaveAncestorDataWithURI(aParentData, aURL)) {
if (HaveAncestorDataWithURI(*aParentData, aURL)) {
// Houston, we have a loop, blow off this child and pretend this never
// happened
LOG_ERROR((" @import cycle detected, dropping load"));
return NS_OK;
}
NS_ASSERTION(aParentData->mSheet == aParentSheet,
NS_ASSERTION(aParentData->mSheet == &aParentSheet,
"Unexpected call to LoadChildSheet");
} else {
LOG((" No parent load; must be CSSOM"));
// No parent load data, so the sheet will need to be notified when
// we finish, if it can be, if we do the load asynchronously.
observer = aParentSheet;
observer = &aParentSheet;
}
// Now that we know it's safe to load this (passes security check and not a
@ -2115,8 +2102,8 @@ nsresult Loader::LoadChildSheet(StyleSheet* aParentSheet,
} else {
// For now, use CORS_NONE for child sheets
Tie(sheet, state) =
CreateSheet(aURL, nullptr, principal, aParentSheet->ParsingMode(),
CORS_NONE, aParentSheet->GetReferrerInfo(),
CreateSheet(aURL, nullptr, principal, aParentSheet.ParsingMode(),
CORS_NONE, aParentSheet.GetReferrerInfo(),
EmptyString(), // integrity is only checked on main sheet
aParentData ? aParentData->mSyncLoad : false);
PrepareSheet(sheet, EmptyString(), EmptyString(), aMedia, IsAlternate::No,
@ -2124,7 +2111,7 @@ nsresult Loader::LoadChildSheet(StyleSheet* aParentSheet,
}
MOZ_ASSERT(sheet);
InsertChildSheet(*sheet, *aParentSheet);
InsertChildSheet(*sheet, aParentSheet);
if (state == SheetState::Complete) {
LOG((" Sheet already complete"));
@ -2134,18 +2121,16 @@ nsresult Loader::LoadChildSheet(StyleSheet* aParentSheet,
return NS_OK;
}
SheetLoadData* data =
new SheetLoadData(this, aURL, sheet, aParentData, observer, principal,
aParentSheet->GetReferrerInfo(), context);
auto data = MakeRefPtr<SheetLoadData>(
this, aURL, sheet, aParentData, observer, principal,
aParentSheet.GetReferrerInfo(), context);
NS_ADDREF(data);
bool syncLoad = data->mSyncLoad;
// Load completion will release the data
rv = LoadSheet(data, state, IsPreload::No);
rv = LoadSheet(*data, state, IsPreload::No);
NS_ENSURE_SUCCESS(rv, rv);
// If syncLoad is true, |data| will be deleted by now.
if (!syncLoad) {
data->mMustNotify = true;
}
@ -2232,13 +2217,11 @@ Result<RefPtr<StyleSheet>, nsresult> Loader::InternalLoadNonDocumentSheet(
return sheet;
}
SheetLoadData* data = new SheetLoadData(
auto data = MakeRefPtr<SheetLoadData>(
this, aURL, sheet, syncLoad,
aUseSystemPrincipal == UseSystemPrincipal::Yes, aPreloadEncoding,
aObserver, aOriginPrincipal, aReferrerInfo, mDocument);
NS_ADDREF(data);
rv = LoadSheet(data, state, aIsPreload);
rv = LoadSheet(*data, state, aIsPreload);
if (NS_FAILED(rv)) {
return Err(rv);
}
@ -2300,59 +2283,50 @@ nsresult Loader::PostLoadEvent(nsIURI* aURI, StyleSheet* aSheet,
return rv;
}
void Loader::HandleLoadEvent(SheetLoadData* aEvent) {
void Loader::HandleLoadEvent(SheetLoadData& aEvent) {
// XXXbz can't assert this yet.... May not have an observer because
// we're unblocking the parser
// NS_ASSERTION(aEvent->mObserver, "Must have observer");
NS_ASSERTION(aEvent->mSheet, "Must have sheet");
NS_ASSERTION(aEvent.mSheet, "Must have sheet");
// Very important: this needs to come before the SheetComplete call
// below, so that HasPendingLoads() will test true as needed under
// notifications we send from that SheetComplete call.
mPostedEvents.RemoveElement(aEvent);
mPostedEvents.RemoveElement(&aEvent);
if (!aEvent->mIsCancelled) {
// SheetComplete will call Release(), so give it a reference to do
// that with.
NS_ADDREF(aEvent);
if (!aEvent.mIsCancelled) {
SheetComplete(aEvent, NS_OK);
}
UnblockOnload(true);
}
static void StopLoadingSheets(
nsDataHashtable<SheetLoadDataHashKey, SheetLoadData*>& aDatas,
Loader::LoadDataArray& aArr) {
for (auto iter = aDatas.Iter(); !iter.Done(); iter.Next()) {
SheetLoadData* data = iter.Data();
MOZ_ASSERT(data, "Must have a data!");
data->mIsLoading = false; // we will handle the removal right here
data->mIsCancelled = true;
aArr.AppendElement(data);
iter.Remove();
}
}
void Loader::Stop() {
uint32_t pendingCount = mSheets ? mSheets->mPendingDatas.Count() : 0;
uint32_t loadingCount = mSheets ? mSheets->mLoadingDatas.Count() : 0;
LoadDataArray arr(pendingCount + loadingCount + mPostedEvents.Length());
if (pendingCount) {
StopLoadingSheets(mSheets->mPendingDatas, arr);
for (auto iter = mSheets->mPendingDatas.Iter(); !iter.Done(); iter.Next()) {
RefPtr<SheetLoadData>& data = iter.Data();
data->mIsLoading = false; // we will handle the removal right here
data->mIsCancelled = true;
arr.AppendElement(std::move(data));
}
mSheets->mPendingDatas.Clear();
}
if (loadingCount) {
StopLoadingSheets(mSheets->mLoadingDatas, arr);
for (auto iter = mSheets->mLoadingDatas.Iter(); !iter.Done(); iter.Next()) {
SheetLoadData* data = iter.Data();
data->mIsLoading = false; // we will handle the removal right here
data->mIsCancelled = true;
arr.AppendElement(data);
}
mSheets->mLoadingDatas.Clear();
}
for (RefPtr<SheetLoadData>& data : mPostedEvents) {
data->mIsCancelled = true;
// SheetComplete() calls Release(), so give this an extra ref.
NS_ADDREF(data.get());
// Move since we're about to get rid of the array below.
arr.AppendElement(std::move(data));
}
@ -2361,7 +2335,7 @@ void Loader::Stop() {
mDatasToNotifyOn += arr.Length();
for (RefPtr<SheetLoadData>& data : arr) {
--mDatasToNotifyOn;
SheetComplete(data, NS_BINDING_ABORTED);
SheetComplete(*data, NS_BINDING_ABORTED);
}
}
@ -2389,9 +2363,9 @@ void Loader::StartDeferredLoads() {
}
mDatasToNotifyOn += arr.Length();
for (uint32_t i = 0; i < arr.Length(); ++i) {
for (RefPtr<SheetLoadData>& data : arr) {
--mDatasToNotifyOn;
LoadSheet(arr[i], SheetState::NeedsParser, IsPreload::No);
LoadSheet(*data, SheetState::NeedsParser, IsPreload::No);
}
}

View File

@ -168,13 +168,14 @@ class Loader final {
*
* @param aParentSheet the parent of this child sheet
* @param aParentData the SheetLoadData corresponding to the load of the
* parent sheet.
* parent sheet. May be null for @import rules inserted via
* CSSOM.
* @param aURL the URL of the child sheet
* @param aMedia the already-parsed media list for the child sheet
* @param aSavedSheets any saved style sheets which could be reused
* for this load
*/
nsresult LoadChildSheet(StyleSheet* aParentSheet, SheetLoadData* aParentData,
nsresult LoadChildSheet(StyleSheet& aParentSheet, SheetLoadData* aParentData,
nsIURI* aURL, dom::MediaList* aMedia,
LoaderReusableStyleSheets* aSavedSheets);
@ -385,12 +386,11 @@ class Loader final {
// Start the loads of all the sheets in mPendingDatas
void StartDeferredLoads();
// Handle an event posted by PostLoadEvent
void HandleLoadEvent(SheetLoadData* aEvent);
void HandleLoadEvent(SheetLoadData&);
// Note: LoadSheet is responsible for releasing the load data and setting the
// sheet to complete on failure.
nsresult LoadSheet(SheetLoadData*, SheetState, IsPreload);
// Note: LoadSheet is responsible for setting the sheet to complete on
// failure.
nsresult LoadSheet(SheetLoadData&, SheetState, IsPreload);
enum class AllowAsyncParse {
Yes,
@ -404,22 +404,21 @@ class Loader final {
//
// If this function returns Completed::Yes, then ParseSheet also called
// SheetComplete on aLoadData.
Completed ParseSheet(const nsACString& aBytes, SheetLoadData*,
AllowAsyncParse);
Completed ParseSheet(const nsACString&, SheetLoadData&, AllowAsyncParse);
// The load of the sheet in aLoadData is done, one way or another. Do final
// cleanup, including releasing aLoadData.
void SheetComplete(SheetLoadData* aLoadData, nsresult aStatus);
// The load of the sheet in the load data is done, one way or another.
// Do final cleanup.
void SheetComplete(SheetLoadData&, nsresult aStatus);
// 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* aLoadData, LoadDataArray& aDatasToNotify);
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.
void MarkLoadTreeFailed(SheetLoadData* aLoadData);
void MarkLoadTreeFailed(SheetLoadData&);
struct Sheets;
UniquePtr<Sheets> mSheets;

View File

@ -101,8 +101,8 @@ class SheetLoadData final : public nsIRunnable, public nsIThreadObserver {
// The sheet we're loading data for
RefPtr<StyleSheet> mSheet;
// Linked list of datas for the same URI as us
SheetLoadData* mNext; // strong ref
// Linked list of datas for the same URI as us.
RefPtr<SheetLoadData> mNext;
// Load data for the sheet that @import-ed us if we were @import-ed
// during the parse

View File

@ -16,8 +16,8 @@ using namespace mozilla;
namespace mozilla {
namespace css {
StreamLoader::StreamLoader(mozilla::css::SheetLoadData* aSheetLoadData)
: mSheetLoadData(aSheetLoadData), mStatus(NS_OK) {}
StreamLoader::StreamLoader(SheetLoadData& aSheetLoadData)
: mSheetLoadData(&aSheetLoadData), mStatus(NS_OK) {}
StreamLoader::~StreamLoader() {}
@ -106,7 +106,7 @@ StreamLoader::OnStopRequest(nsIRequest* aRequest, nsresult aStatus) {
// 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.
mSheetLoadData->mLoader->ParseSheet(utf8String, mSheetLoadData,
mSheetLoadData->mLoader->ParseSheet(utf8String, *mSheetLoadData,
Loader::AllowAsyncParse::Yes);
return NS_OK;
}

View File

@ -22,7 +22,7 @@ class StreamLoader : public nsIStreamListener {
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
explicit StreamLoader(mozilla::css::SheetLoadData* aSheetLoadData);
explicit StreamLoader(SheetLoadData&);
private:
virtual ~StreamLoader();
@ -35,7 +35,7 @@ class StreamLoader : public nsIStreamListener {
void HandleBOM();
RefPtr<mozilla::css::SheetLoadData> mSheetLoadData;
RefPtr<SheetLoadData> mSheetLoadData;
nsresult mStatus;
Maybe<const Encoding*> mEncodingFromBOM;

View File

@ -918,7 +918,7 @@ already_AddRefed<StyleSheet> StyleSheet::CreateEmptyChildSheet(
// (3) The stylesheet is a chrome stylesheet, since those can use
// -moz-bool-pref, which needs to access the pref service, which is not
// threadsafe.
static bool AllowParallelParse(css::Loader* aLoader, nsIURI* aSheetURI) {
static bool AllowParallelParse(css::Loader& aLoader, nsIURI* aSheetURI) {
// Check the pref.
if (!StaticPrefs::layout_css_parsing_parallel()) {
return false;
@ -926,7 +926,7 @@ static bool AllowParallelParse(css::Loader* aLoader, nsIURI* aSheetURI) {
// If the browser is recording CSS errors, we need to use the sequential path
// because the parallel path doesn't support that.
Document* doc = aLoader->GetDocument();
Document* doc = aLoader.GetDocument();
if (doc && css::ErrorReporter::ShouldReportErrors(*doc)) {
return false;
}
@ -946,32 +946,29 @@ static bool AllowParallelParse(css::Loader* aLoader, nsIURI* aSheetURI) {
}
RefPtr<StyleSheetParsePromise> StyleSheet::ParseSheet(
css::Loader* aLoader, const nsACString& aBytes,
css::SheetLoadData* aLoadData) {
MOZ_ASSERT(aLoader);
MOZ_ASSERT(aLoadData);
css::Loader& aLoader, const nsACString& aBytes,
css::SheetLoadData& aLoadData) {
MOZ_ASSERT(mParsePromise.IsEmpty());
RefPtr<StyleSheetParsePromise> p = mParsePromise.Ensure(__func__);
SetURLExtraData();
const StyleUseCounters* useCounters =
aLoader->GetDocument() ? aLoader->GetDocument()->GetStyleUseCounters()
: nullptr;
aLoader.GetDocument() ? aLoader.GetDocument()->GetStyleUseCounters()
: nullptr;
if (!AllowParallelParse(aLoader, GetSheetURI())) {
RefPtr<RawServoStyleSheetContents> contents =
Servo_StyleSheet_FromUTF8Bytes(
aLoader, this, aLoadData, &aBytes, mParsingMode, Inner().mURLData,
aLoadData->mLineNumber, aLoader->GetCompatibilityMode(),
&aLoader, this, &aLoadData, &aBytes, mParsingMode, Inner().mURLData,
aLoadData.mLineNumber, aLoader.GetCompatibilityMode(),
/* reusable_sheets = */ nullptr, useCounters)
.Consume();
FinishAsyncParse(contents.forget());
} else {
RefPtr<css::SheetLoadDataHolder> loadDataHolder =
new css::SheetLoadDataHolder(__func__, aLoadData);
auto holder = MakeRefPtr<css::SheetLoadDataHolder>(__func__, &aLoadData);
Servo_StyleSheet_FromUTF8BytesAsync(
loadDataHolder, Inner().mURLData, &aBytes, mParsingMode,
aLoadData->mLineNumber, aLoader->GetCompatibilityMode(),
holder, Inner().mURLData, &aBytes, mParsingMode, aLoadData.mLineNumber,
aLoader.GetCompatibilityMode(),
/* should_record_counters = */ !!useCounters);
}

View File

@ -100,11 +100,11 @@ class StyleSheet final : public nsICSSLoaderObserver, public nsWrapperCache {
bool HasRules() const;
// Parses a stylesheet. The aLoadData argument corresponds to the
// SheetLoadData for this stylesheet. It may be null in some cases.
RefPtr<StyleSheetParsePromise> ParseSheet(css::Loader* aLoader,
// Parses a stylesheet. The load data argument corresponds to the
// SheetLoadData for this stylesheet.
RefPtr<StyleSheetParsePromise> ParseSheet(css::Loader&,
const nsACString& aBytes,
css::SheetLoadData* aLoadData);
css::SheetLoadData&);
// Common code that needs to be called after servo finishes parsing. This is
// shared between the parallel and sequential paths.
@ -113,6 +113,8 @@ class StyleSheet final : public nsICSSLoaderObserver, public nsWrapperCache {
// Similar to the above, but guarantees that parsing will be performed
// synchronously.
//
// The load data may be null sometimes.
void ParseSheetSync(
css::Loader* aLoader, const nsACString& aBytes,
css::SheetLoadData* aLoadData, uint32_t aLineNumber,

View File

@ -46,49 +46,6 @@ namespace mozilla {
class CSSStyleSheet;
} // namespace mozilla
// Deletes a linked list iteratively to avoid blowing up the stack (bug 456196).
#define NS_CSS_DELETE_LIST_MEMBER(type_, ptr_, member_) \
{ \
type_* cur = (ptr_)->member_; \
(ptr_)->member_ = nullptr; \
while (cur) { \
type_* dlm_next = cur->member_; \
cur->member_ = nullptr; \
delete cur; \
cur = dlm_next; \
} \
}
// Ditto, but use NS_RELEASE instead of 'delete' (bug 1221902).
#define NS_CSS_NS_RELEASE_LIST_MEMBER(type_, ptr_, member_) \
{ \
type_* cur = (ptr_)->member_; \
(ptr_)->member_ = nullptr; \
while (cur) { \
type_* dlm_next = cur->member_; \
cur->member_ = nullptr; \
NS_RELEASE(cur); \
cur = dlm_next; \
} \
}
// Clones a linked list iteratively to avoid blowing up the stack.
// If it fails to clone the entire list then 'to_' is deleted and
// we return null.
#define NS_CSS_CLONE_LIST_MEMBER(type_, from_, member_, to_, args_) \
{ \
type_* dest = (to_); \
(to_)->member_ = nullptr; \
for (const type_* src = (from_)->member_; src; src = src->member_) { \
type_* clm_clone = src->Clone args_; \
if (!clm_clone) { \
delete (to_); \
return nullptr; \
} \
dest->member_ = clm_clone; \
dest = clm_clone; \
} \
}
// Forward declaration copied here since ServoBindings.h #includes nsCSSValue.h.
extern "C" {
mozilla::URLExtraData* Servo_CssUrlData_GetExtraData(const RawServoCssUrlData*);