Global Metrics
path: .metrics.cognitive.average
old: null
new: 1.5
path: .metrics.cognitive.sum
old: 0.0
new: 27.0
path: .metrics.halstead.effort
old: 831.2045094254761
new: 397411.0552276002
path: .metrics.halstead.level
old: 0.21768707482993196
new: 0.024039133473095737
path: .metrics.halstead.purity_ratio
old: 2.0912871113600806
new: 1.1236606717563349
path: .metrics.halstead.time
old: 46.17802830141534
new: 22078.391957088905
path: .metrics.halstead.volume
old: 180.94247824228052
new: 9553.417400300104
path: .metrics.halstead.N2
old: 21.0
new: 530.0
path: .metrics.halstead.n1
old: 7.0
new: 27.0
path: .metrics.halstead.N1
old: 19.0
new: 721.0
path: .metrics.halstead.bugs
old: 0.029468000760988843
new: 1.8017949889327456
path: .metrics.halstead.n2
old: 16.0
new: 172.0
path: .metrics.halstead.vocabulary
old: 23.0
new: 199.0
path: .metrics.halstead.estimated_program_length
old: 83.65148445440323
new: 1405.6995003671746
path: .metrics.halstead.difficulty
old: 4.59375
new: 41.59883720930232
path: .metrics.halstead.length
old: 40.0
new: 1251.0
path: .metrics.nargs.sum
old: 0.0
new: 51.0
path: .metrics.nargs.average
old: null
new: 2.8333333333333335
path: .metrics.cyclomatic.average
old: 1.0
new: 2.5789473684210527
path: .metrics.cyclomatic.sum
old: 2.0
new: 49.0
path: .metrics.mi.mi_original
old: 88.41007067592315
new: 21.25980462138125
path: .metrics.mi.mi_sei
old: 83.98704878844356
new: -20.637218203154976
path: .metrics.mi.mi_visual_studio
old: 51.70179571691412
new: 12.432634281509502
path: .metrics.nexits.average
old: null
new: 1.2222222222222223
path: .metrics.nexits.sum
old: 0.0
new: 22.0
path: .metrics.nom.closures
old: 0.0
new: 1.0
path: .metrics.nom.total
old: 0.0
new: 18.0
path: .metrics.nom.functions
old: 0.0
new: 17.0
path: .metrics.loc.cloc
old: 6.0
new: 18.0
path: .metrics.loc.lloc
old: 0.0
new: 86.0
path: .metrics.loc.ploc
old: 15.0
new: 215.0
path: .metrics.loc.sloc
old: 30.0
new: 272.0
path: .metrics.loc.blank
old: 9.0
new: 39.0
Spaces Data
Minimal test - lines (18, 272)
path: .spaces[0].metrics.halstead.n1
old: 4.0
new: 27.0
path: .spaces[0].metrics.halstead.difficulty
old: 2.25
new: 43.333333333333336
path: .spaces[0].metrics.halstead.n2
old: 8.0
new: 162.0
path: .spaces[0].metrics.halstead.time
old: 6.721804688852168
new: 22592.89944999233
path: .spaces[0].metrics.halstead.vocabulary
old: 12.0
new: 189.0
path: .spaces[0].metrics.halstead.estimated_program_length
old: 32.0
new: 1317.437663025723
path: .spaces[0].metrics.halstead.purity_ratio
old: 2.1333333333333333
new: 1.061593604372057
path: .spaces[0].metrics.halstead.volume
old: 53.77443751081734
new: 9384.74284845835
path: .spaces[0].metrics.halstead.bugs
old: 0.008154255994324386
new: 1.82967966629573
path: .spaces[0].metrics.halstead.N2
old: 9.0
new: 520.0
path: .spaces[0].metrics.halstead.level
old: 0.4444444444444444
new: 0.023076923076923075
path: .spaces[0].metrics.halstead.effort
old: 120.99248439933902
new: 406672.1900998619
path: .spaces[0].metrics.halstead.N1
old: 6.0
new: 721.0
path: .spaces[0].metrics.halstead.length
old: 15.0
new: 1241.0
path: .spaces[0].metrics.mi.mi_visual_studio
old: 70.77341864342087
new: 13.232724980635474
path: .spaces[0].metrics.mi.mi_sei
old: 98.999594644585
new: -21.03323380094112
path: .spaces[0].metrics.mi.mi_original
old: 121.02254588024968
new: 22.627959716886664
path: .spaces[0].metrics.loc.ploc
old: 5.0
new: 205.0
path: .spaces[0].metrics.loc.blank
old: 1.0
new: 37.0
path: .spaces[0].metrics.loc.lloc
old: 0.0
new: 86.0
path: .spaces[0].metrics.loc.sloc
old: 6.0
new: 255.0
path: .spaces[0].metrics.loc.cloc
old: 0.0
new: 13.0
path: .spaces[0].metrics.nargs.sum
old: 0.0
new: 51.0
path: .spaces[0].metrics.nargs.average
old: null
new: 2.8333333333333335
path: .spaces[0].metrics.nexits.average
old: null
new: 1.2222222222222223
path: .spaces[0].metrics.nexits.sum
old: 0.0
new: 22.0
path: .spaces[0].metrics.nom.functions
old: 0.0
new: 17.0
path: .spaces[0].metrics.nom.total
old: 0.0
new: 18.0
path: .spaces[0].metrics.nom.closures
old: 0.0
new: 1.0
path: .spaces[0].metrics.cognitive.average
old: null
new: 1.5
path: .spaces[0].metrics.cognitive.sum
old: 0.0
new: 27.0
path: .spaces[0].metrics.cyclomatic.sum
old: 1.0
new: 48.0
path: .spaces[0].metrics.cyclomatic.average
old: 1.0
new: 2.6666666666666665
Code
namespace mozilla {
PreloadService::PreloadService(dom::Document* aDoc) : mDocument(aDoc) {}
PreloadService::~PreloadService() = default;
bool PreloadService::RegisterPreload(const PreloadHashKey& aKey,
PreloaderBase* aPreload) {
return mPreloads.WithEntryHandle(aKey, [&](auto&& lookup) {
if (lookup) {
lookup.Data() = aPreload;
return true;
}
lookup.Insert(aPreload);
return false;
});
}
void PreloadService::DeregisterPreload(const PreloadHashKey& aKey) {
mPreloads.Remove(aKey);
}
void PreloadService::ClearAllPreloads() { mPreloads.Clear(); }
bool PreloadService::PreloadExists(const PreloadHashKey& aKey) {
return mPreloads.Contains(aKey);
}
already_AddRefed PreloadService::LookupPreload(
const PreloadHashKey& aKey) const {
return mPreloads.Get(aKey);
}
already_AddRefed PreloadService::GetPreloadURI(const nsAString& aURL) {
nsIURI* base = BaseURIForPreload();
auto encoding = mDocument->GetDocumentCharacterSet();
nsCOMPtr uri;
nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, encoding, base);
if (NS_FAILED(rv)) {
return nullptr;
}
return uri.forget();
}
already_AddRefed PreloadService::PreloadLinkElement(
dom::HTMLLinkElement* aLinkElement, nsContentPolicyType aPolicyType) {
if (aPolicyType == nsIContentPolicy::TYPE_INVALID) {
MOZ_ASSERT_UNREACHABLE("Caller should check");
return nullptr;
}
if (!StaticPrefs::network_preload()) {
return nullptr;
}
nsAutoString as, charset, crossOrigin, integrity, referrerPolicy, srcset,
sizes, type, url;
nsCOMPtr uri = aLinkElement->GetURI();
aLinkElement->GetAs(as);
aLinkElement->GetCharset(charset);
aLinkElement->GetImageSrcset(srcset);
aLinkElement->GetImageSizes(sizes);
aLinkElement->GetHref(url);
aLinkElement->GetCrossOrigin(crossOrigin);
aLinkElement->GetIntegrity(integrity);
aLinkElement->GetReferrerPolicy(referrerPolicy);
aLinkElement->GetType(type);
auto result = PreloadOrCoalesce(uri, url, aPolicyType, as, type, charset,
srcset, sizes, integrity, crossOrigin,
referrerPolicy, /* aFromHeader = */ false);
if (!result.mPreloader) {
NotifyNodeEvent(aLinkElement, result.mAlreadyComplete);
return nullptr;
}
result.mPreloader->AddLinkPreloadNode(aLinkElement);
return result.mPreloader.forget();
}
void PreloadService::PreloadLinkHeader(
nsIURI* aURI, const nsAString& aURL, nsContentPolicyType aPolicyType,
const nsAString& aAs, const nsAString& aType, const nsAString& aIntegrity,
const nsAString& aSrcset, const nsAString& aSizes, const nsAString& aCORS,
const nsAString& aReferrerPolicy) {
if (aPolicyType == nsIContentPolicy::TYPE_INVALID) {
MOZ_ASSERT_UNREACHABLE("Caller should check");
return;
}
if (!StaticPrefs::network_preload()) {
return;
}
PreloadOrCoalesce(aURI, aURL, aPolicyType, aAs, aType, u""_ns, aSrcset,
aSizes, aIntegrity, aCORS, aReferrerPolicy,
/* aFromHeader = */ true);
}
PreloadService::PreloadOrCoalesceResult PreloadService::PreloadOrCoalesce(
nsIURI* aURI, const nsAString& aURL, nsContentPolicyType aPolicyType,
const nsAString& aAs, const nsAString& aType, const nsAString& aCharset,
const nsAString& aSrcset, const nsAString& aSizes,
const nsAString& aIntegrity, const nsAString& aCORS,
const nsAString& aReferrerPolicy, bool aFromHeader) {
if (!aURI) {
MOZ_ASSERT_UNREACHABLE("Should not pass null nsIURI");
return {nullptr, false};
}
bool isImgSet = false;
PreloadHashKey preloadKey;
nsCOMPtr uri = aURI;
if (aAs.LowerCaseEqualsASCII("script")) {
preloadKey = PreloadHashKey::CreateAsScript(uri, aCORS, aType);
} else if (aAs.LowerCaseEqualsASCII("style")) {
preloadKey = PreloadHashKey::CreateAsStyle(
uri, mDocument->NodePrincipal(), dom::Element::StringToCORSMode(aCORS),
css::eAuthorSheetFeatures /* see Loader::LoadSheet */);
} else if (aAs.LowerCaseEqualsASCII("image")) {
uri = mDocument->ResolvePreloadImage(BaseURIForPreload(), aURL, aSrcset,
aSizes, &isImgSet);
if (!uri) {
return {nullptr, false};
}
preloadKey = PreloadHashKey::CreateAsImage(
uri, mDocument->NodePrincipal(), dom::Element::StringToCORSMode(aCORS));
} else if (aAs.LowerCaseEqualsASCII("font")) {
preloadKey = PreloadHashKey::CreateAsFont(
uri, dom::Element::StringToCORSMode(aCORS));
} else if (aAs.LowerCaseEqualsASCII("fetch")) {
preloadKey = PreloadHashKey::CreateAsFetch(
uri, dom::Element::StringToCORSMode(aCORS));
} else {
return {nullptr, false};
}
if (RefPtr preload = LookupPreload(preloadKey)) {
return {std::move(preload), false};
}
if (aAs.LowerCaseEqualsASCII("script")) {
PreloadScript(uri, aType, aCharset, aCORS, aReferrerPolicy, aIntegrity,
true /* isInHead - TODO */);
} else if (aAs.LowerCaseEqualsASCII("style")) {
auto status = mDocument->PreloadStyle(
aURI, Encoding::ForLabel(aCharset), aCORS,
PreloadReferrerPolicy(aReferrerPolicy), aIntegrity,
aFromHeader ? css::StylePreloadKind::FromLinkRelPreloadHeader
: css::StylePreloadKind::FromLinkRelPreloadElement);
switch (status) {
case dom::SheetPreloadStatus::AlreadyComplete:
return {nullptr, /* already_complete = */ true};
case dom::SheetPreloadStatus::Errored:
case dom::SheetPreloadStatus::InProgress:
break;
}
} else if (aAs.LowerCaseEqualsASCII("image")) {
PreloadImage(uri, aCORS, aReferrerPolicy, isImgSet);
} else if (aAs.LowerCaseEqualsASCII("font")) {
PreloadFont(uri, aCORS, aReferrerPolicy);
} else if (aAs.LowerCaseEqualsASCII("fetch")) {
PreloadFetch(uri, aCORS, aReferrerPolicy);
}
return {LookupPreload(preloadKey), false};
}
void PreloadService::PreloadScript(nsIURI* aURI, const nsAString& aType,
const nsAString& aCharset,
const nsAString& aCrossOrigin,
const nsAString& aReferrerPolicy,
const nsAString& aIntegrity,
bool aScriptFromHead) {
mDocument->ScriptLoader()->PreloadURI(
aURI, aCharset, aType, aCrossOrigin, aIntegrity, aScriptFromHead, false,
false, false, true, PreloadReferrerPolicy(aReferrerPolicy));
}
void PreloadService::PreloadImage(nsIURI* aURI, const nsAString& aCrossOrigin,
const nsAString& aImageReferrerPolicy,
bool aIsImgSet) {
mDocument->PreLoadImage(aURI, aCrossOrigin,
PreloadReferrerPolicy(aImageReferrerPolicy),
aIsImgSet, true);
}
void PreloadService::PreloadFont(nsIURI* aURI, const nsAString& aCrossOrigin,
const nsAString& aReferrerPolicy) {
CORSMode cors = dom::Element::StringToCORSMode(aCrossOrigin);
auto key = PreloadHashKey::CreateAsFont(aURI, cors);
// * Bug 1618549: Depending on where we decide to do the deduplication, we may
// want to check if the font is already being preloaded here.
RefPtr preloader = new FontPreloader();
dom::ReferrerPolicy referrerPolicy = PreloadReferrerPolicy(aReferrerPolicy);
preloader->OpenChannel(key, aURI, cors, referrerPolicy, mDocument);
}
void PreloadService::PreloadFetch(nsIURI* aURI, const nsAString& aCrossOrigin,
const nsAString& aReferrerPolicy) {
CORSMode cors = dom::Element::StringToCORSMode(aCrossOrigin);
auto key = PreloadHashKey::CreateAsFetch(aURI, cors);
// * Bug 1618549: Depending on where we decide to do the deduplication, we may
// want to check if a fetch is already being preloaded here.
RefPtr preloader = new FetchPreloader();
dom::ReferrerPolicy referrerPolicy = PreloadReferrerPolicy(aReferrerPolicy);
preloader->OpenChannel(key, aURI, cors, referrerPolicy, mDocument);
}
// static
void PreloadService::NotifyNodeEvent(nsINode* aNode, bool aSuccess) {
if (!aNode->IsInComposedDoc()) {
return;
}
// We don't dispatch synchronously since |node| might be in a DocGroup
// that we're not allowed to touch. (Our network request happens in the
// DocGroup of one of the mSources nodes--not necessarily this one).
RefPtr dispatcher = new AsyncEventDispatcher(
aNode, aSuccess ? u"load"_ns : u"error"_ns, CanBubble::eNo);
dispatcher->RequireNodeInDocument();
dispatcher->PostDOMEvent();
}
dom::ReferrerPolicy PreloadService::PreloadReferrerPolicy(
const nsAString& aReferrerPolicy) {
dom::ReferrerPolicy referrerPolicy =
dom::ReferrerInfo::ReferrerPolicyAttributeFromString(aReferrerPolicy);
if (referrerPolicy == dom::ReferrerPolicy::_empty) {
referrerPolicy = mDocument->GetPreloadReferrerInfo()->ReferrerPolicy();
}
return referrerPolicy;
}
nsIURI* PreloadService::BaseURIForPreload() {
nsIURI* documentURI = mDocument->GetDocumentURI();
nsIURI* documentBaseURI = mDocument->GetDocBaseURI();
return (documentURI == documentBaseURI)
? (mSpeculationBaseURI ? mSpeculationBaseURI.get() : documentURI)
: documentBaseURI;
}
} // namespace mozilla