mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
Bug 822480 - Add in the Resource Timing API. r=honzab, r=jst
This commit is contained in:
parent
bfd9a489d3
commit
864ffca9e7
@ -654,6 +654,7 @@ public:
|
||||
nsIURI* aReferrer,
|
||||
imgINotificationObserver* aObserver,
|
||||
int32_t aLoadFlags,
|
||||
const nsAString& initiatorType,
|
||||
imgRequestProxy** aRequest);
|
||||
|
||||
/**
|
||||
@ -1847,6 +1848,14 @@ public:
|
||||
return sIsPerformanceTimingEnabled;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if the performance timing APIs are enabled.
|
||||
*/
|
||||
static bool IsResourceTimingEnabled()
|
||||
{
|
||||
return sIsResourceTimingEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the doc tree branch which contains aDoc contains any
|
||||
* plugins which we don't control event dispatch for, i.e. do any plugins
|
||||
@ -2221,6 +2230,7 @@ private:
|
||||
static uint32_t sHandlingInputTimeout;
|
||||
static bool sIsIdleObserverAPIEnabled;
|
||||
static bool sIsPerformanceTimingEnabled;
|
||||
static bool sIsResourceTimingEnabled;
|
||||
|
||||
static nsHtml5StringParser* sHTMLFragmentParser;
|
||||
static nsIParser* sXMLFragmentParser;
|
||||
|
@ -238,6 +238,7 @@ bool nsContentUtils::sTrustedFullScreenOnly = true;
|
||||
bool nsContentUtils::sFullscreenApiIsContentOnly = false;
|
||||
bool nsContentUtils::sIsIdleObserverAPIEnabled = false;
|
||||
bool nsContentUtils::sIsPerformanceTimingEnabled = false;
|
||||
bool nsContentUtils::sIsResourceTimingEnabled = false;
|
||||
|
||||
uint32_t nsContentUtils::sHandlingInputTimeout = 1000;
|
||||
|
||||
@ -439,6 +440,9 @@ nsContentUtils::Init()
|
||||
Preferences::AddBoolVarCache(&sIsPerformanceTimingEnabled,
|
||||
"dom.enable_performance", true);
|
||||
|
||||
Preferences::AddBoolVarCache(&sIsResourceTimingEnabled,
|
||||
"dom.enable_resource_timing", true);
|
||||
|
||||
Preferences::AddUintVarCache(&sHandlingInputTimeout,
|
||||
"dom.event.handling-user-input-time-limit",
|
||||
1000);
|
||||
@ -2711,6 +2715,7 @@ nsresult
|
||||
nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument,
|
||||
nsIPrincipal* aLoadingPrincipal, nsIURI* aReferrer,
|
||||
imgINotificationObserver* aObserver, int32_t aLoadFlags,
|
||||
const nsAString& initiatorType,
|
||||
imgRequestProxy** aRequest)
|
||||
{
|
||||
NS_PRECONDITION(aURI, "Must have a URI");
|
||||
@ -2760,6 +2765,7 @@ nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument,
|
||||
aLoadFlags, /* load flags */
|
||||
nullptr, /* cache key */
|
||||
channelPolicy, /* CSP info */
|
||||
initiatorType, /* the load initiator */
|
||||
aRequest);
|
||||
}
|
||||
|
||||
|
@ -9274,6 +9274,7 @@ nsDocument::MaybePreLoadImage(nsIURI* uri, const nsAString &aCrossOriginAttr)
|
||||
mDocumentURI, // uri of document used as referrer
|
||||
nullptr, // no observer
|
||||
loadFlags,
|
||||
NS_LITERAL_STRING("img"),
|
||||
getter_AddRefs(request));
|
||||
|
||||
// Pin image-reference to avoid evicting it from the img-cache before
|
||||
|
@ -822,12 +822,16 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
|
||||
|
||||
// Not blocked. Do the load.
|
||||
nsRefPtr<imgRequestProxy>& req = PrepareNextRequest();
|
||||
nsCOMPtr<nsIContent> content =
|
||||
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
|
||||
nsresult rv;
|
||||
rv = nsContentUtils::LoadImage(aNewURI, aDocument,
|
||||
aDocument->NodePrincipal(),
|
||||
aDocument->GetDocumentURI(),
|
||||
this, loadFlags,
|
||||
content->LocalName(),
|
||||
getter_AddRefs(req));
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
TrackImage(req);
|
||||
ResetAnimationIfNeeded();
|
||||
|
@ -2323,6 +2323,12 @@ nsObjectLoadingContent::OpenChannel()
|
||||
nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan));
|
||||
if (httpChan) {
|
||||
httpChan->SetReferrer(doc->GetDocumentURI());
|
||||
|
||||
// Set the initiator type
|
||||
nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(httpChan));
|
||||
if (timedChannel) {
|
||||
timedChannel->SetInitiatorType(thisContent->LocalName());
|
||||
}
|
||||
}
|
||||
|
||||
// Set up the channel's principal and such, like nsDocShell::DoURILoad does.
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "nsContentPolicyUtils.h"
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "nsIHttpChannelInternal.h"
|
||||
#include "nsITimedChannel.h"
|
||||
#include "nsIScriptElement.h"
|
||||
#include "nsIDOMHTMLScriptElement.h"
|
||||
#include "nsIDocShell.h"
|
||||
@ -338,6 +339,12 @@ nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType,
|
||||
mozilla::net::SeerLearn(aRequest->mURI, mDocument->GetDocumentURI(),
|
||||
nsINetworkSeer::LEARN_LOAD_SUBRESOURCE, loadContext);
|
||||
|
||||
// Set the initiator type
|
||||
nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(httpChannel));
|
||||
if (timedChannel) {
|
||||
timedChannel->SetInitiatorType(NS_LITERAL_STRING("script"));
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIStreamLoader> loader;
|
||||
rv = NS_NewStreamLoader(getter_AddRefs(loader), this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -68,6 +68,7 @@
|
||||
#include "nsFormData.h"
|
||||
#include "nsStreamListenerWrapper.h"
|
||||
#include "xpcjsid.h"
|
||||
#include "nsITimedChannel.h"
|
||||
|
||||
#include "nsWrapperCacheInlines.h"
|
||||
|
||||
@ -1703,6 +1704,12 @@ nsXMLHttpRequest::Open(const nsACString& inMethod, const nsACString& url,
|
||||
if (httpChannel) {
|
||||
rv = httpChannel->SetRequestMethod(method);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Set the initiator type
|
||||
nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(httpChannel));
|
||||
if (timedChannel) {
|
||||
timedChannel->SetInitiatorType(NS_LITERAL_STRING("xmlhttprequest"));
|
||||
}
|
||||
}
|
||||
|
||||
ChangeState(XML_HTTP_REQUEST_OPENED);
|
||||
|
@ -6818,14 +6818,6 @@ nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
|
||||
}
|
||||
}
|
||||
|
||||
// On session restore we get a redirect from page to itself. Don't count it.
|
||||
bool equals = false;
|
||||
if (mTiming &&
|
||||
!(mLoadType == LOAD_HISTORY &&
|
||||
NS_SUCCEEDED(newURI->Equals(oldURI, &equals)) && equals)) {
|
||||
mTiming->NotifyRedirect(oldURI, newURI);
|
||||
}
|
||||
|
||||
// Below a URI visit is saved (see AddURIVisit method doc).
|
||||
// The visit chain looks something like:
|
||||
// ...
|
||||
@ -10033,6 +10025,9 @@ nsDocShell::DoURILoad(nsIURI * aURI,
|
||||
nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(channel));
|
||||
if (timedChannel) {
|
||||
timedChannel->SetTimingEnabled(true);
|
||||
if (IsFrame()) {
|
||||
timedChannel->SetInitiatorType(NS_LITERAL_STRING("subdocument"));
|
||||
}
|
||||
}
|
||||
|
||||
rv = DoChannelLoad(channel, uriLoader, aBypassClassifier);
|
||||
|
37
dom/base/PerformanceEntry.cpp
Normal file
37
dom/base/PerformanceEntry.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "PerformanceEntry.h"
|
||||
#include "nsIURI.h"
|
||||
#include "mozilla/dom/PerformanceEntryBinding.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(PerformanceEntry, mPerformance)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(PerformanceEntry)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(PerformanceEntry)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PerformanceEntry)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
PerformanceEntry::PerformanceEntry(nsPerformance* aPerformance)
|
||||
: mPerformance(aPerformance)
|
||||
{
|
||||
MOZ_ASSERT(aPerformance, "Parent performance object should be provided");
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
PerformanceEntry::~PerformanceEntry()
|
||||
{
|
||||
}
|
||||
|
||||
JSObject*
|
||||
PerformanceEntry::WrapObject(JSContext* aCx)
|
||||
{
|
||||
return mozilla::dom::PerformanceEntryBinding::Wrap(aCx, this);
|
||||
}
|
82
dom/base/PerformanceEntry.h
Normal file
82
dom/base/PerformanceEntry.h
Normal file
@ -0,0 +1,82 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_PerformanceEntry_h___
|
||||
#define mozilla_dom_PerformanceEntry_h___
|
||||
|
||||
#include "nsPerformance.h"
|
||||
#include "nsDOMNavigationTiming.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
// http://www.w3.org/TR/performance-timeline/#performanceentry
|
||||
class PerformanceEntry : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
PerformanceEntry(nsPerformance* aPerformance);
|
||||
virtual ~PerformanceEntry();
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(PerformanceEntry)
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
|
||||
|
||||
nsPerformance* GetParentObject() const
|
||||
{
|
||||
return mPerformance;
|
||||
}
|
||||
|
||||
void GetName(nsAString& aName) const
|
||||
{
|
||||
aName = mName;
|
||||
}
|
||||
|
||||
const nsAString& GetName() const
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
void SetName(const nsAString& aName)
|
||||
{
|
||||
mName = aName;
|
||||
}
|
||||
|
||||
void GetEntryType(nsAString& aEntryType) const
|
||||
{
|
||||
aEntryType = mEntryType;
|
||||
}
|
||||
|
||||
const nsAString& GetEntryType()
|
||||
{
|
||||
return mEntryType;
|
||||
}
|
||||
|
||||
void SetEntryType(const nsAString& aEntryType)
|
||||
{
|
||||
mEntryType = aEntryType;
|
||||
}
|
||||
|
||||
virtual DOMHighResTimeStamp StartTime() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual DOMHighResTimeStamp Duration() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsRefPtr<nsPerformance> mPerformance;
|
||||
nsString mName;
|
||||
nsString mEntryType;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_dom_PerformanceEntry_h___ */
|
48
dom/base/PerformanceResourceTiming.cpp
Normal file
48
dom/base/PerformanceResourceTiming.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "PerformanceResourceTiming.h"
|
||||
#include "mozilla/dom/PerformanceResourceTimingBinding.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED_1(PerformanceResourceTiming,
|
||||
PerformanceEntry,
|
||||
mTiming)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(PerformanceResourceTiming,
|
||||
PerformanceEntry)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(PerformanceResourceTiming)
|
||||
NS_INTERFACE_MAP_END_INHERITING(PerformanceEntry)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(PerformanceResourceTiming, PerformanceEntry)
|
||||
NS_IMPL_RELEASE_INHERITED(PerformanceResourceTiming, PerformanceEntry)
|
||||
|
||||
PerformanceResourceTiming::PerformanceResourceTiming(nsPerformanceTiming* aPerformanceTiming,
|
||||
nsPerformance* aPerformance)
|
||||
: PerformanceEntry(aPerformance),
|
||||
mTiming(aPerformanceTiming)
|
||||
{
|
||||
MOZ_ASSERT(aPerformance, "Parent performance object should be provided");
|
||||
}
|
||||
|
||||
PerformanceResourceTiming::~PerformanceResourceTiming()
|
||||
{
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp
|
||||
PerformanceResourceTiming::StartTime() const
|
||||
{
|
||||
DOMHighResTimeStamp startTime = mTiming->RedirectStartHighRes();
|
||||
return startTime ? startTime : mTiming->FetchStartHighRes();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
PerformanceResourceTiming::WrapObject(JSContext* aCx)
|
||||
{
|
||||
return PerformanceResourceTimingBinding::Wrap(aCx, this);
|
||||
}
|
133
dom/base/PerformanceResourceTiming.h
Normal file
133
dom/base/PerformanceResourceTiming.h
Normal file
@ -0,0 +1,133 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_PerformanceResourceTiming_h___
|
||||
#define mozilla_dom_PerformanceResourceTiming_h___
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsPerformance.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsITimedChannel.h"
|
||||
#include "nsDOMNavigationTiming.h"
|
||||
#include "PerformanceEntry.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
// http://www.w3.org/TR/resource-timing/#performanceresourcetiming
|
||||
class PerformanceResourceTiming MOZ_FINAL : public PerformanceEntry
|
||||
{
|
||||
public:
|
||||
typedef mozilla::TimeStamp TimeStamp;
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(
|
||||
PerformanceResourceTiming,
|
||||
PerformanceEntry)
|
||||
|
||||
PerformanceResourceTiming(nsPerformanceTiming* aPerformanceTiming,
|
||||
nsPerformance* aPerformance);
|
||||
virtual ~PerformanceResourceTiming();
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
|
||||
|
||||
|
||||
virtual DOMHighResTimeStamp StartTime() const;
|
||||
|
||||
virtual DOMHighResTimeStamp Duration() const
|
||||
{
|
||||
return ResponseEnd() - StartTime();
|
||||
}
|
||||
|
||||
void GetInitiatorType(nsAString& aInitiatorType) const
|
||||
{
|
||||
aInitiatorType = mInitiatorType;
|
||||
}
|
||||
|
||||
void SetInitiatorType(const nsAString& aInitiatorType)
|
||||
{
|
||||
mInitiatorType = aInitiatorType;
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp FetchStart() const {
|
||||
return mTiming
|
||||
? mTiming->FetchStartHighRes()
|
||||
: 0;
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp RedirectStart() const {
|
||||
// We have to check if all the redirect URIs had the same origin (since
|
||||
// there is no check in RedirectEndHighRes())
|
||||
return mTiming && mTiming->IsSameOriginAsReferral()
|
||||
? mTiming->RedirectStartHighRes()
|
||||
: 0;
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp RedirectEnd() const {
|
||||
// We have to check if all the redirect URIs had the same origin (since
|
||||
// there is no check in RedirectEndHighRes())
|
||||
return mTiming && mTiming->IsSameOriginAsReferral()
|
||||
? mTiming->RedirectEndHighRes()
|
||||
: 0;
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp DomainLookupStart() const {
|
||||
return mTiming && mTiming->IsSameOriginAsReferral()
|
||||
? mTiming->DomainLookupStartHighRes()
|
||||
: 0;
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp DomainLookupEnd() const {
|
||||
return mTiming && mTiming->IsSameOriginAsReferral()
|
||||
? mTiming->DomainLookupEndHighRes()
|
||||
: 0;
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp ConnectStart() const {
|
||||
return mTiming && mTiming->IsSameOriginAsReferral()
|
||||
? mTiming->ConnectStartHighRes()
|
||||
: 0;
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp ConnectEnd() const {
|
||||
return mTiming && mTiming->IsSameOriginAsReferral()
|
||||
? mTiming->ConnectEndHighRes()
|
||||
: 0;
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp RequestStart() const {
|
||||
return mTiming && mTiming->IsSameOriginAsReferral()
|
||||
? mTiming->RequestStartHighRes()
|
||||
: 0;
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp ResponseStart() const {
|
||||
return mTiming && mTiming->IsSameOriginAsReferral()
|
||||
? mTiming->ResponseStartHighRes()
|
||||
: 0;
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp ResponseEnd() const {
|
||||
return mTiming
|
||||
? mTiming->ResponseEndHighRes()
|
||||
: 0;
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp SecureConnectionStart() const
|
||||
{
|
||||
// This measurement is not available for Navigation Timing either.
|
||||
// There is a different bug submitted for it.
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsString mInitiatorType;
|
||||
nsRefPtr<nsPerformanceTiming> mTiming;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_dom_PerformanceResourceTiming_h___ */
|
@ -59,6 +59,8 @@ EXPORTS.mozilla.dom += [
|
||||
'MessagePort.h',
|
||||
'MessagePortList.h',
|
||||
'Navigator.h',
|
||||
'PerformanceEntry.h',
|
||||
'PerformanceResourceTiming.h',
|
||||
'ScreenOrientation.h',
|
||||
'ScriptSettings.h',
|
||||
'StructuredCloneTags.h',
|
||||
@ -99,6 +101,8 @@ UNIFIED_SOURCES += [
|
||||
'nsWindowMemoryReporter.cpp',
|
||||
'nsWindowRoot.cpp',
|
||||
'nsWrapperCache.cpp',
|
||||
'PerformanceEntry.cpp',
|
||||
'PerformanceResourceTiming.cpp',
|
||||
'ScriptSettings.cpp',
|
||||
'URL.cpp',
|
||||
'URLSearchParams.cpp',
|
||||
|
@ -4,6 +4,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsDOMNavigationTiming.h"
|
||||
#include "nsPerformance.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
@ -24,11 +25,7 @@ void
|
||||
nsDOMNavigationTiming::Clear()
|
||||
{
|
||||
mNavigationType = mozilla::dom::PerformanceNavigation::TYPE_RESERVED;
|
||||
mNavigationStart = 0;
|
||||
mFetchStart = 0;
|
||||
mRedirectStart = 0;
|
||||
mRedirectEnd = 0;
|
||||
mRedirectCount = 0;
|
||||
mNavigationStartHighRes = 0;
|
||||
mBeforeUnloadStart = 0;
|
||||
mUnloadStart = 0;
|
||||
mUnloadEnd = 0;
|
||||
@ -39,7 +36,6 @@ nsDOMNavigationTiming::Clear()
|
||||
mDOMContentLoadedEventStart = 0;
|
||||
mDOMContentLoadedEventEnd = 0;
|
||||
mDOMComplete = 0;
|
||||
mRedirectCheck = NOT_CHECKED;
|
||||
|
||||
mLoadEventStartSet = false;
|
||||
mLoadEventEndSet = false;
|
||||
@ -57,17 +53,7 @@ nsDOMNavigationTiming::TimeStampToDOM(mozilla::TimeStamp aStamp) const
|
||||
return 0;
|
||||
}
|
||||
mozilla::TimeDuration duration = aStamp - mNavigationStartTimeStamp;
|
||||
return mNavigationStart + static_cast<int32_t>(duration.ToMilliseconds());
|
||||
}
|
||||
|
||||
DOMTimeMilliSec
|
||||
nsDOMNavigationTiming::TimeStampToDOMOrFetchStart(mozilla::TimeStamp aStamp) const
|
||||
{
|
||||
if (!aStamp.IsNull()) {
|
||||
return TimeStampToDOM(aStamp);
|
||||
} else {
|
||||
return GetFetchStart();
|
||||
}
|
||||
return GetNavigationStart() + static_cast<int64_t>(duration.ToMilliseconds());
|
||||
}
|
||||
|
||||
DOMTimeMilliSec nsDOMNavigationTiming::DurationFromStart(){
|
||||
@ -77,36 +63,19 @@ DOMTimeMilliSec nsDOMNavigationTiming::DurationFromStart(){
|
||||
void
|
||||
nsDOMNavigationTiming::NotifyNavigationStart()
|
||||
{
|
||||
mNavigationStart = PR_Now() / PR_USEC_PER_MSEC;
|
||||
mNavigationStartHighRes = (double)PR_Now() / PR_USEC_PER_MSEC;
|
||||
mNavigationStartTimeStamp = mozilla::TimeStamp::Now();
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMNavigationTiming::NotifyFetchStart(nsIURI* aURI, nsDOMPerformanceNavigationType aNavigationType)
|
||||
{
|
||||
mFetchStart = DurationFromStart();
|
||||
mNavigationType = aNavigationType;
|
||||
// At the unload event time we don't really know the loading uri.
|
||||
// Need it for later check for unload timing access.
|
||||
mLoadedURI = aURI;
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMNavigationTiming::NotifyRedirect(nsIURI* aOldURI, nsIURI* aNewURI)
|
||||
{
|
||||
if (mRedirects.Count() == 0) {
|
||||
mRedirectStart = mFetchStart;
|
||||
}
|
||||
mFetchStart = DurationFromStart();
|
||||
mRedirectEnd = mFetchStart;
|
||||
|
||||
// At the unload event time we don't really know the loading uri.
|
||||
// Need it for later check for unload timing access.
|
||||
mLoadedURI = aNewURI;
|
||||
|
||||
mRedirects.AppendObject(aOldURI);
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMNavigationTiming::NotifyBeforeUnload()
|
||||
{
|
||||
@ -150,32 +119,6 @@ nsDOMNavigationTiming::NotifyLoadEventEnd()
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsDOMNavigationTiming::ReportRedirects()
|
||||
{
|
||||
if (mRedirectCheck == NOT_CHECKED) {
|
||||
mRedirectCount = mRedirects.Count();
|
||||
if (mRedirects.Count() == 0) {
|
||||
mRedirectCheck = NO_REDIRECTS;
|
||||
} else {
|
||||
mRedirectCheck = CHECK_PASSED;
|
||||
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
|
||||
for (int i = mRedirects.Count() - 1; i >= 0; --i) {
|
||||
nsIURI * curr = mRedirects[i];
|
||||
nsresult rv = ssm->CheckSameOriginURI(curr, mLoadedURI, false);
|
||||
if (!NS_SUCCEEDED(rv)) {
|
||||
mRedirectCheck = CHECK_FAILED;
|
||||
mRedirectCount = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// All we need to know is in mRedirectCheck now. Clear history.
|
||||
mRedirects.Clear();
|
||||
}
|
||||
}
|
||||
return mRedirectCheck == CHECK_PASSED;
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMNavigationTiming::SetDOMLoadingTimeStamp(nsIURI* aURI, mozilla::TimeStamp aValue)
|
||||
{
|
||||
@ -236,33 +179,6 @@ nsDOMNavigationTiming::NotifyDOMContentLoadedEnd(nsIURI* aURI)
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t
|
||||
nsDOMNavigationTiming::GetRedirectCount()
|
||||
{
|
||||
if (ReportRedirects()) {
|
||||
return mRedirectCount;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DOMTimeMilliSec
|
||||
nsDOMNavigationTiming::GetRedirectStart()
|
||||
{
|
||||
if (ReportRedirects()) {
|
||||
return mRedirectStart;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DOMTimeMilliSec
|
||||
nsDOMNavigationTiming::GetRedirectEnd()
|
||||
{
|
||||
if (ReportRedirects()) {
|
||||
return mRedirectEnd;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DOMTimeMilliSec
|
||||
nsDOMNavigationTiming::GetUnloadEventStart()
|
||||
{
|
||||
|
@ -37,18 +37,17 @@ public:
|
||||
nsDOMPerformanceNavigationType GetType() const {
|
||||
return mNavigationType;
|
||||
}
|
||||
uint16_t GetRedirectCount();
|
||||
|
||||
DOMTimeMilliSec GetRedirectStart();
|
||||
DOMTimeMilliSec GetRedirectEnd();
|
||||
inline DOMHighResTimeStamp GetNavigationStartHighRes() const {
|
||||
return mNavigationStartHighRes;
|
||||
}
|
||||
DOMTimeMilliSec GetNavigationStart() const {
|
||||
return mNavigationStart;
|
||||
return static_cast<int64_t>(GetNavigationStartHighRes());
|
||||
}
|
||||
mozilla::TimeStamp GetNavigationStartTimeStamp() const {
|
||||
return mNavigationStartTimeStamp;
|
||||
}
|
||||
DOMTimeMilliSec GetUnloadEventStart();
|
||||
DOMTimeMilliSec GetUnloadEventEnd();
|
||||
DOMTimeMilliSec GetFetchStart() const {
|
||||
return mFetchStart;
|
||||
}
|
||||
DOMTimeMilliSec GetDomLoading() const {
|
||||
return mDOMLoading;
|
||||
}
|
||||
@ -73,7 +72,6 @@ public:
|
||||
|
||||
void NotifyNavigationStart();
|
||||
void NotifyFetchStart(nsIURI* aURI, nsDOMPerformanceNavigationType aNavigationType);
|
||||
void NotifyRedirect(nsIURI* aOldURI, nsIURI* aNewURI);
|
||||
void NotifyBeforeUnload();
|
||||
void NotifyUnloadAccepted(nsIURI* aOldURI);
|
||||
void NotifyUnloadEventStart();
|
||||
@ -89,7 +87,6 @@ public:
|
||||
void NotifyDOMContentLoadedStart(nsIURI* aURI);
|
||||
void NotifyDOMContentLoadedEnd(nsIURI* aURI);
|
||||
DOMTimeMilliSec TimeStampToDOM(mozilla::TimeStamp aStamp) const;
|
||||
DOMTimeMilliSec TimeStampToDOMOrFetchStart(mozilla::TimeStamp aStamp) const;
|
||||
|
||||
inline DOMHighResTimeStamp TimeStampToDOMHighRes(mozilla::TimeStamp aStamp)
|
||||
{
|
||||
@ -102,27 +99,15 @@ private:
|
||||
~nsDOMNavigationTiming();
|
||||
|
||||
void Clear();
|
||||
bool ReportRedirects();
|
||||
|
||||
nsCOMPtr<nsIURI> mUnloadedURI;
|
||||
nsCOMPtr<nsIURI> mLoadedURI;
|
||||
nsCOMArray<nsIURI> mRedirects;
|
||||
|
||||
typedef enum { NOT_CHECKED,
|
||||
CHECK_PASSED,
|
||||
NO_REDIRECTS,
|
||||
CHECK_FAILED} RedirectCheckState;
|
||||
RedirectCheckState mRedirectCheck;
|
||||
int16_t mRedirectCount;
|
||||
|
||||
nsDOMPerformanceNavigationType mNavigationType;
|
||||
DOMTimeMilliSec mNavigationStart;
|
||||
DOMHighResTimeStamp mNavigationStartHighRes;
|
||||
mozilla::TimeStamp mNavigationStartTimeStamp;
|
||||
DOMTimeMilliSec DurationFromStart();
|
||||
|
||||
DOMTimeMilliSec mFetchStart;
|
||||
DOMTimeMilliSec mRedirectStart;
|
||||
DOMTimeMilliSec mRedirectEnd;
|
||||
DOMTimeMilliSec mBeforeUnloadStart;
|
||||
DOMTimeMilliSec mUnloadStart;
|
||||
DOMTimeMilliSec mUnloadEnd;
|
||||
|
@ -2454,7 +2454,8 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
||||
newInnerWindow->mPerformance =
|
||||
new nsPerformance(newInnerWindow,
|
||||
currentInner->mPerformance->GetDOMTiming(),
|
||||
currentInner->mPerformance->GetChannel());
|
||||
currentInner->mPerformance->GetChannel(),
|
||||
currentInner->mPerformance->GetParentPerformance());
|
||||
}
|
||||
}
|
||||
|
||||
@ -3567,7 +3568,22 @@ nsPIDOMWindow::CreatePerformanceObjectIfNeeded()
|
||||
timedChannel = nullptr;
|
||||
}
|
||||
if (timing) {
|
||||
mPerformance = new nsPerformance(this, timing, timedChannel);
|
||||
// If we are dealing with an iframe, we will need the parent's performance
|
||||
// object (so we can add the iframe as a resource of that page).
|
||||
nsPerformance* parentPerformance = nullptr;
|
||||
nsCOMPtr<nsIDOMWindow> parentWindow;
|
||||
GetScriptableParent(getter_AddRefs(parentWindow));
|
||||
nsCOMPtr<nsPIDOMWindow> parentPWindow = do_GetInterface(parentWindow);
|
||||
if (GetOuterWindow() != parentPWindow) {
|
||||
if (parentPWindow && !parentPWindow->IsInnerWindow()) {
|
||||
parentPWindow = parentPWindow->GetCurrentInnerWindow();
|
||||
}
|
||||
if (parentPWindow) {
|
||||
parentPerformance = parentPWindow->GetPerformance();
|
||||
}
|
||||
}
|
||||
mPerformance =
|
||||
new nsPerformance(this, timing, timedChannel, parentPerformance);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,14 +5,20 @@
|
||||
|
||||
#include "nsPerformance.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "nsITimedChannel.h"
|
||||
#include "nsDOMNavigationTiming.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "nsIURI.h"
|
||||
#include "PerformanceEntry.h"
|
||||
#include "PerformanceResourceTiming.h"
|
||||
#include "mozilla/dom/PerformanceBinding.h"
|
||||
#include "mozilla/dom/PerformanceTimingBinding.h"
|
||||
#include "mozilla/dom/PerformanceNavigationBinding.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
@ -22,97 +28,257 @@ NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsPerformanceTiming, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsPerformanceTiming, Release)
|
||||
|
||||
nsPerformanceTiming::nsPerformanceTiming(nsPerformance* aPerformance,
|
||||
nsITimedChannel* aChannel)
|
||||
nsITimedChannel* aChannel,
|
||||
nsIHttpChannel* aHttpChannel,
|
||||
DOMHighResTimeStamp aZeroTime)
|
||||
: mPerformance(aPerformance),
|
||||
mChannel(aChannel)
|
||||
mChannel(aChannel),
|
||||
mFetchStart(0.0),
|
||||
mZeroTime(aZeroTime),
|
||||
mReportCrossOriginResources(true)
|
||||
{
|
||||
MOZ_ASSERT(aPerformance, "Parent performance object should be provided");
|
||||
SetIsDOMBinding();
|
||||
// The aHttpChannel argument is null if this nsPerformanceTiming object
|
||||
// is being used for the navigation timing (document) and has a non-null
|
||||
// value for the resource timing (any resources within the page).
|
||||
if (aHttpChannel) {
|
||||
CheckRedirectCrossOrigin(aHttpChannel);
|
||||
}
|
||||
}
|
||||
|
||||
nsPerformanceTiming::~nsPerformanceTiming()
|
||||
{
|
||||
}
|
||||
|
||||
DOMTimeMilliSec
|
||||
nsPerformanceTiming::DomainLookupStart() const
|
||||
DOMHighResTimeStamp
|
||||
nsPerformanceTiming::FetchStartHighRes()
|
||||
{
|
||||
if (!nsContentUtils::IsPerformanceTimingEnabled()) {
|
||||
if (!mFetchStart) {
|
||||
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
|
||||
return 0;
|
||||
}
|
||||
TimeStamp stamp;
|
||||
mChannel->GetAsyncOpen(&stamp);
|
||||
MOZ_ASSERT(!stamp.IsNull(), "The fetch start time stamp should always be "
|
||||
"valid if the performance timing is enabled");
|
||||
mFetchStart = (!stamp.IsNull())
|
||||
? TimeStampToDOMHighRes(stamp)
|
||||
: 0.0;
|
||||
}
|
||||
return mFetchStart;
|
||||
}
|
||||
|
||||
DOMTimeMilliSec
|
||||
nsPerformanceTiming::FetchStart()
|
||||
{
|
||||
return static_cast<int64_t>(FetchStartHighRes());
|
||||
}
|
||||
|
||||
// This method will implement the timing allow check algorithm
|
||||
// http://w3c-test.org/webperf/specs/ResourceTiming/#timing-allow-check
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=936814
|
||||
void
|
||||
nsPerformanceTiming::CheckRedirectCrossOrigin(nsIHttpChannel* aResourceChannel)
|
||||
{
|
||||
MOZ_ASSERT(mChannel, "The resource channel should not be null for any"
|
||||
"valid resource");
|
||||
uint16_t redirectCount;
|
||||
mChannel->GetRedirectCount(&redirectCount);
|
||||
if (redirectCount == 0) {
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIURI> resourceURI, referrerURI;
|
||||
aResourceChannel->GetReferrer(getter_AddRefs(referrerURI));
|
||||
aResourceChannel->GetURI(getter_AddRefs(resourceURI));
|
||||
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
|
||||
nsresult rv = ssm->CheckSameOriginURI(resourceURI, referrerURI, false);
|
||||
if (!NS_SUCCEEDED(rv)) {
|
||||
mReportCrossOriginResources = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsPerformanceTiming::IsSameOriginAsReferral() const
|
||||
{
|
||||
return mReportCrossOriginResources;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
nsPerformanceTiming::GetRedirectCount() const
|
||||
{
|
||||
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
|
||||
return 0;
|
||||
}
|
||||
if (!mChannel) {
|
||||
return FetchStart();
|
||||
bool sameOrigin;
|
||||
mChannel->GetAllRedirectsSameOrigin(&sameOrigin);
|
||||
if (!sameOrigin) {
|
||||
return 0;
|
||||
}
|
||||
uint16_t redirectCount;
|
||||
mChannel->GetRedirectCount(&redirectCount);
|
||||
return redirectCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* RedirectStartHighRes() is used by both the navigation timing and the
|
||||
* resource timing. Since, navigation timing and resource timing check and
|
||||
* interpret cross-domain redirects in a different manner,
|
||||
* RedirectStartHighRes() will make no checks for cross-domain redirect.
|
||||
* It's up to the consumers of this method (nsPerformanceTiming::RedirectStart()
|
||||
* and PerformanceResourceTiming::RedirectStart() to make such verifications.
|
||||
*
|
||||
* @return a valid timing if the Performance Timing is enabled
|
||||
*/
|
||||
DOMHighResTimeStamp
|
||||
nsPerformanceTiming::RedirectStartHighRes()
|
||||
{
|
||||
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
|
||||
return 0;
|
||||
}
|
||||
mozilla::TimeStamp stamp;
|
||||
mChannel->GetRedirectStart(&stamp);
|
||||
return TimeStampToDOMHighResOrFetchStart(stamp);
|
||||
}
|
||||
|
||||
DOMTimeMilliSec
|
||||
nsPerformanceTiming::RedirectStart()
|
||||
{
|
||||
// We have to check if all the redirect URIs had the same origin (since there
|
||||
// is no check in RedirectStartHighRes())
|
||||
bool sameOrigin;
|
||||
mChannel->GetAllRedirectsSameOrigin(&sameOrigin);
|
||||
if (sameOrigin) {
|
||||
return static_cast<int64_t>(RedirectStartHighRes());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* RedirectEndHighRes() is used by both the navigation timing and the resource
|
||||
* timing. Since, navigation timing and resource timing check and interpret
|
||||
* cross-domain redirects in a different manner, RedirectEndHighRes() will make
|
||||
* no checks for cross-domain redirect. It's up to the consumers of this method
|
||||
* (nsPerformanceTiming::RedirectEnd() and
|
||||
* PerformanceResourceTiming::RedirectEnd() to make such verifications.
|
||||
*
|
||||
* @return a valid timing if the Performance Timing is enabled
|
||||
*/
|
||||
DOMHighResTimeStamp
|
||||
nsPerformanceTiming::RedirectEndHighRes()
|
||||
{
|
||||
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
|
||||
return 0;
|
||||
}
|
||||
mozilla::TimeStamp stamp;
|
||||
mChannel->GetRedirectEnd(&stamp);
|
||||
return TimeStampToDOMHighResOrFetchStart(stamp);
|
||||
}
|
||||
|
||||
DOMTimeMilliSec
|
||||
nsPerformanceTiming::RedirectEnd()
|
||||
{
|
||||
// We have to check if all the redirect URIs had the same origin (since there
|
||||
// is no check in RedirectEndHighRes())
|
||||
bool sameOrigin;
|
||||
mChannel->GetAllRedirectsSameOrigin(&sameOrigin);
|
||||
if (sameOrigin) {
|
||||
return static_cast<int64_t>(RedirectEndHighRes());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp
|
||||
nsPerformanceTiming::DomainLookupStartHighRes()
|
||||
{
|
||||
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
|
||||
return 0;
|
||||
}
|
||||
mozilla::TimeStamp stamp;
|
||||
mChannel->GetDomainLookupStart(&stamp);
|
||||
return GetDOMTiming()->TimeStampToDOMOrFetchStart(stamp);
|
||||
return TimeStampToDOMHighResOrFetchStart(stamp);
|
||||
}
|
||||
|
||||
DOMTimeMilliSec
|
||||
nsPerformanceTiming::DomainLookupEnd() const
|
||||
nsPerformanceTiming::DomainLookupStart()
|
||||
{
|
||||
if (!nsContentUtils::IsPerformanceTimingEnabled()) {
|
||||
return static_cast<int64_t>(DomainLookupStartHighRes());
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp
|
||||
nsPerformanceTiming::DomainLookupEndHighRes()
|
||||
{
|
||||
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
|
||||
return 0;
|
||||
}
|
||||
if (!mChannel) {
|
||||
return FetchStart();
|
||||
}
|
||||
mozilla::TimeStamp stamp;
|
||||
mChannel->GetDomainLookupEnd(&stamp);
|
||||
return GetDOMTiming()->TimeStampToDOMOrFetchStart(stamp);
|
||||
return TimeStampToDOMHighResOrFetchStart(stamp);
|
||||
}
|
||||
|
||||
DOMTimeMilliSec
|
||||
nsPerformanceTiming::ConnectStart() const
|
||||
nsPerformanceTiming::DomainLookupEnd()
|
||||
{
|
||||
if (!nsContentUtils::IsPerformanceTimingEnabled()) {
|
||||
return static_cast<int64_t>(DomainLookupEndHighRes());
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp
|
||||
nsPerformanceTiming::ConnectStartHighRes()
|
||||
{
|
||||
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
|
||||
return 0;
|
||||
}
|
||||
if (!mChannel) {
|
||||
return FetchStart();
|
||||
}
|
||||
mozilla::TimeStamp stamp;
|
||||
mChannel->GetConnectStart(&stamp);
|
||||
return GetDOMTiming()->TimeStampToDOMOrFetchStart(stamp);
|
||||
return TimeStampToDOMHighResOrFetchStart(stamp);
|
||||
}
|
||||
|
||||
DOMTimeMilliSec
|
||||
nsPerformanceTiming::ConnectEnd() const
|
||||
nsPerformanceTiming::ConnectStart()
|
||||
{
|
||||
if (!nsContentUtils::IsPerformanceTimingEnabled()) {
|
||||
return static_cast<int64_t>(ConnectStartHighRes());
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp
|
||||
nsPerformanceTiming::ConnectEndHighRes()
|
||||
{
|
||||
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
|
||||
return 0;
|
||||
}
|
||||
if (!mChannel) {
|
||||
return FetchStart();
|
||||
}
|
||||
mozilla::TimeStamp stamp;
|
||||
mChannel->GetConnectEnd(&stamp);
|
||||
return GetDOMTiming()->TimeStampToDOMOrFetchStart(stamp);
|
||||
return TimeStampToDOMHighResOrFetchStart(stamp);
|
||||
}
|
||||
|
||||
DOMTimeMilliSec
|
||||
nsPerformanceTiming::RequestStart() const
|
||||
nsPerformanceTiming::ConnectEnd()
|
||||
{
|
||||
if (!nsContentUtils::IsPerformanceTimingEnabled()) {
|
||||
return static_cast<int64_t>(ConnectEndHighRes());
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp
|
||||
nsPerformanceTiming::RequestStartHighRes()
|
||||
{
|
||||
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
|
||||
return 0;
|
||||
}
|
||||
if (!mChannel) {
|
||||
return FetchStart();
|
||||
}
|
||||
mozilla::TimeStamp stamp;
|
||||
mChannel->GetRequestStart(&stamp);
|
||||
return GetDOMTiming()->TimeStampToDOMOrFetchStart(stamp);
|
||||
return TimeStampToDOMHighResOrFetchStart(stamp);
|
||||
}
|
||||
|
||||
DOMTimeMilliSec
|
||||
nsPerformanceTiming::ResponseStart() const
|
||||
nsPerformanceTiming::RequestStart()
|
||||
{
|
||||
if (!nsContentUtils::IsPerformanceTimingEnabled()) {
|
||||
return static_cast<int64_t>(RequestStartHighRes());
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp
|
||||
nsPerformanceTiming::ResponseStartHighRes()
|
||||
{
|
||||
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
|
||||
return 0;
|
||||
}
|
||||
if (!mChannel) {
|
||||
return FetchStart();
|
||||
}
|
||||
mozilla::TimeStamp stamp;
|
||||
mChannel->GetResponseStart(&stamp);
|
||||
mozilla::TimeStamp cacheStamp;
|
||||
@ -120,18 +286,21 @@ nsPerformanceTiming::ResponseStart() const
|
||||
if (stamp.IsNull() || (!cacheStamp.IsNull() && cacheStamp < stamp)) {
|
||||
stamp = cacheStamp;
|
||||
}
|
||||
return GetDOMTiming()->TimeStampToDOMOrFetchStart(stamp);
|
||||
return TimeStampToDOMHighResOrFetchStart(stamp);
|
||||
}
|
||||
|
||||
DOMTimeMilliSec
|
||||
nsPerformanceTiming::ResponseEnd() const
|
||||
nsPerformanceTiming::ResponseStart()
|
||||
{
|
||||
if (!nsContentUtils::IsPerformanceTimingEnabled()) {
|
||||
return static_cast<int64_t>(ResponseStartHighRes());
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp
|
||||
nsPerformanceTiming::ResponseEndHighRes()
|
||||
{
|
||||
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
|
||||
return 0;
|
||||
}
|
||||
if (!mChannel) {
|
||||
return FetchStart();
|
||||
}
|
||||
mozilla::TimeStamp stamp;
|
||||
mChannel->GetResponseEnd(&stamp);
|
||||
mozilla::TimeStamp cacheStamp;
|
||||
@ -139,7 +308,21 @@ nsPerformanceTiming::ResponseEnd() const
|
||||
if (stamp.IsNull() || (!cacheStamp.IsNull() && cacheStamp < stamp)) {
|
||||
stamp = cacheStamp;
|
||||
}
|
||||
return GetDOMTiming()->TimeStampToDOMOrFetchStart(stamp);
|
||||
return TimeStampToDOMHighResOrFetchStart(stamp);
|
||||
}
|
||||
|
||||
DOMTimeMilliSec
|
||||
nsPerformanceTiming::ResponseEnd()
|
||||
{
|
||||
return static_cast<int64_t>(ResponseEndHighRes());
|
||||
}
|
||||
|
||||
bool
|
||||
nsPerformanceTiming::IsInitialized() const
|
||||
{
|
||||
MOZ_ASSERT(mChannel, "The timed channel should not be null for any "
|
||||
"valid resource");
|
||||
return !!mChannel;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
@ -172,18 +355,23 @@ nsPerformanceNavigation::WrapObject(JSContext *cx)
|
||||
}
|
||||
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_3(nsPerformance,
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_5(nsPerformance,
|
||||
mWindow, mTiming,
|
||||
mNavigation)
|
||||
mNavigation, mEntries,
|
||||
mParentPerformance)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPerformance)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPerformance)
|
||||
|
||||
nsPerformance::nsPerformance(nsIDOMWindow* aWindow,
|
||||
nsDOMNavigationTiming* aDOMTiming,
|
||||
nsITimedChannel* aChannel)
|
||||
nsITimedChannel* aChannel,
|
||||
nsPerformance* aParentPerformance)
|
||||
: mWindow(aWindow),
|
||||
mDOMTiming(aDOMTiming),
|
||||
mChannel(aChannel)
|
||||
mChannel(aChannel),
|
||||
mParentPerformance(aParentPerformance),
|
||||
mBufferSizeSet(kDefaultBufferSize),
|
||||
mPrimaryBufferSize(kDefaultBufferSize)
|
||||
{
|
||||
MOZ_ASSERT(aWindow, "Parent window object should be provided");
|
||||
SetIsDOMBinding();
|
||||
@ -204,7 +392,12 @@ nsPerformanceTiming*
|
||||
nsPerformance::Timing()
|
||||
{
|
||||
if (!mTiming) {
|
||||
mTiming = new nsPerformanceTiming(this, mChannel);
|
||||
// For navigation timing, the third argument (an nsIHtttpChannel) is null
|
||||
// since the cross-domain redirect were already checked.
|
||||
// The last argument (zero time) for performance.timing is the navigation
|
||||
// start value.
|
||||
mTiming = new nsPerformanceTiming(this, mChannel, nullptr,
|
||||
mDOMTiming->GetNavigationStart());
|
||||
}
|
||||
return mTiming;
|
||||
}
|
||||
@ -230,3 +423,147 @@ nsPerformance::WrapObject(JSContext *cx)
|
||||
return dom::PerformanceBinding::Wrap(cx, this);
|
||||
}
|
||||
|
||||
void
|
||||
nsPerformance::GetEntries(nsTArray<nsRefPtr<PerformanceEntry> >& retval)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
retval.Clear();
|
||||
uint32_t count = mEntries.Length();
|
||||
if (count > mPrimaryBufferSize) {
|
||||
count = mPrimaryBufferSize;
|
||||
}
|
||||
retval.AppendElements(mEntries.Elements(), count);
|
||||
}
|
||||
|
||||
void
|
||||
nsPerformance::GetEntriesByType(const nsAString& entryType,
|
||||
nsTArray<nsRefPtr<PerformanceEntry> >& retval)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
retval.Clear();
|
||||
uint32_t count = mEntries.Length();
|
||||
for (uint32_t i = 0 ; i < count && i < mPrimaryBufferSize ; i++) {
|
||||
if (mEntries[i]->GetEntryType().Equals(entryType)) {
|
||||
retval.AppendElement(mEntries[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsPerformance::GetEntriesByName(const nsAString& name,
|
||||
const mozilla::dom::Optional<nsAString>& entryType,
|
||||
nsTArray<nsRefPtr<PerformanceEntry> >& retval)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
retval.Clear();
|
||||
uint32_t count = mEntries.Length();
|
||||
for (uint32_t i = 0 ; i < count && i < mPrimaryBufferSize ; i++) {
|
||||
if (mEntries[i]->GetName().Equals(name) &&
|
||||
(!entryType.WasPassed() ||
|
||||
mEntries[i]->GetEntryType().Equals(entryType.Value()))) {
|
||||
retval.AppendElement(mEntries[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsPerformance::ClearResourceTimings()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mPrimaryBufferSize = mBufferSizeSet;
|
||||
mEntries.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
nsPerformance::SetResourceTimingBufferSize(uint64_t maxSize)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mBufferSizeSet = maxSize;
|
||||
if (mBufferSizeSet < mEntries.Length()) {
|
||||
// call onresourcetimingbufferfull
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=936813
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An entry should be added only after the resource is loaded.
|
||||
* This method is not thread safe and can only be called on the main thread.
|
||||
*/
|
||||
void
|
||||
nsPerformance::AddEntry(nsIHttpChannel* channel,
|
||||
nsITimedChannel* timedChannel)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
// Check if resource timing is prefed off.
|
||||
if (!nsContentUtils::IsResourceTimingEnabled()) {
|
||||
return;
|
||||
}
|
||||
if (channel && timedChannel) {
|
||||
nsAutoCString name;
|
||||
nsAutoString initiatorType;
|
||||
nsCOMPtr<nsIURI> originalURI;
|
||||
|
||||
timedChannel->GetInitiatorType(initiatorType);
|
||||
|
||||
// According to the spec, "The name attribute must return the resolved URL
|
||||
// of the requested resource. This attribute must not change even if the
|
||||
// fetch redirected to a different URL."
|
||||
channel->GetOriginalURI(getter_AddRefs(originalURI));
|
||||
originalURI->GetSpec(name);
|
||||
NS_ConvertUTF8toUTF16 entryName(name);
|
||||
|
||||
// The nsITimedChannel argument will be used to gather all the timings.
|
||||
// The nsIHttpChannel argument will be used to check if any cross-origin
|
||||
// redirects occurred.
|
||||
// The last argument is the "zero time" (offset). Since we don't want
|
||||
// any offset for the resource timing, this will be set to "0" - the
|
||||
// resource timing returns a relative timing (no offset).
|
||||
nsRefPtr<nsPerformanceTiming> performanceTiming =
|
||||
new nsPerformanceTiming(this, timedChannel, channel,
|
||||
0);
|
||||
|
||||
// The PerformanceResourceTiming object will use the nsPerformanceTiming
|
||||
// object to get all the required timings.
|
||||
nsRefPtr<dom::PerformanceResourceTiming> performanceEntry =
|
||||
new dom::PerformanceResourceTiming(performanceTiming, this);
|
||||
|
||||
performanceEntry->SetName(entryName);
|
||||
performanceEntry->SetEntryType(NS_LITERAL_STRING("resource"));
|
||||
// If the initiator type had no valid value, then set it to the default
|
||||
// ("other") value.
|
||||
if (initiatorType.IsEmpty()) {
|
||||
initiatorType = NS_LITERAL_STRING("other");
|
||||
}
|
||||
performanceEntry->SetInitiatorType(initiatorType);
|
||||
|
||||
mEntries.InsertElementSorted(performanceEntry,
|
||||
PerformanceEntryComparator());
|
||||
if (mEntries.Length() > mPrimaryBufferSize) {
|
||||
// call onresourcetimingbufferfull
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=936813
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsPerformance::PerformanceEntryComparator::Equals(
|
||||
const PerformanceEntry* aElem1,
|
||||
const PerformanceEntry* aElem2) const
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aElem1 && aElem2,
|
||||
"Trying to compare null performance entries");
|
||||
return aElem1->StartTime() == aElem2->StartTime();
|
||||
}
|
||||
|
||||
bool
|
||||
nsPerformance::PerformanceEntryComparator::LessThan(
|
||||
const PerformanceEntry* aElem1,
|
||||
const PerformanceEntry* aElem2) const
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aElem1 && aElem2,
|
||||
"Trying to compare null performance entries");
|
||||
return aElem1->StartTime() < aElem2->StartTime();
|
||||
}
|
||||
|
@ -13,16 +13,47 @@
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "js/TypeDecls.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
|
||||
class nsITimedChannel;
|
||||
class nsPerformance;
|
||||
class nsIHttpChannel;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class PerformanceEntry;
|
||||
}
|
||||
}
|
||||
|
||||
// Script "performance.timing" object
|
||||
class nsPerformanceTiming MOZ_FINAL : public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
typedef mozilla::TimeStamp TimeStamp;
|
||||
|
||||
/**
|
||||
* @param aPerformance
|
||||
* The performance object (the JS parent).
|
||||
* This will allow access to "window.performance.timing" attribute for
|
||||
* the navigation timing (can't be null).
|
||||
* @param aChannel
|
||||
* An nsITimedChannel used to gather all the networking timings by both
|
||||
* the navigation timing and the resource timing (can't be null).
|
||||
* @param aHttpChannel
|
||||
* An nsIHttpChannel (the resource's http channel).
|
||||
* This will be used by the resource timing cross-domain check
|
||||
* algorithm.
|
||||
* Argument is null for the navigation timing (navigation timing uses
|
||||
* another algorithm for the cross-domain redirects).
|
||||
* @param aZeroTime
|
||||
* The offset that will be added to the timestamp of each event. This
|
||||
* argument should be equal to performance.navigationStart for
|
||||
* navigation timing and "0" for the resource timing.
|
||||
*/
|
||||
nsPerformanceTiming(nsPerformance* aPerformance,
|
||||
nsITimedChannel* aChannel);
|
||||
nsITimedChannel* aChannel,
|
||||
nsIHttpChannel* aHttpChannel,
|
||||
DOMHighResTimeStamp aZeroTime);
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsPerformanceTiming)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(nsPerformanceTiming)
|
||||
|
||||
@ -33,6 +64,57 @@ public:
|
||||
return mPerformance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param aStamp
|
||||
* The TimeStamp recorded for a specific event. This TimeStamp can
|
||||
* be null.
|
||||
* @return the duration of an event with a given TimeStamp, relative to the
|
||||
* navigationStart TimeStamp (the moment the user landed on the
|
||||
* page), if the given TimeStamp is valid. Otherwise, it will return
|
||||
* the FetchStart timing value.
|
||||
*/
|
||||
inline DOMHighResTimeStamp TimeStampToDOMHighResOrFetchStart(TimeStamp aStamp)
|
||||
{
|
||||
return (!aStamp.IsNull())
|
||||
? TimeStampToDOMHighRes(aStamp)
|
||||
: FetchStartHighRes();
|
||||
}
|
||||
|
||||
/**
|
||||
* The nsITimedChannel records an absolute timestamp for each event.
|
||||
* The nsDOMNavigationTiming will record the moment when the user landed on
|
||||
* the page. This is a window.performance unique timestamp, so it can be used
|
||||
* for all the events (navigation timing and resource timing events).
|
||||
*
|
||||
* The algorithm operates in 2 steps:
|
||||
* 1. The first step is to subtract the two timestamps: the argument (the
|
||||
* envet's timesramp) and the navigation start timestamp. This will result in
|
||||
* a relative timestamp of the event (relative to the navigation start -
|
||||
* window.performance.timing.navigationStart).
|
||||
* 2. The second step is to add any required offset (the mZeroTime). For now,
|
||||
* this offset value is either 0 (for the resource timing), or equal to
|
||||
* "performance.navigationStart" (for navigation timing).
|
||||
* For the resource timing, mZeroTime is set to 0, causing the result to be a
|
||||
* relative time.
|
||||
* For the navigation timing, mZeroTime is set to "performance.navigationStart"
|
||||
* causing the result be an absolute time.
|
||||
*
|
||||
* @param aStamp
|
||||
* The TimeStamp recorded for a specific event. This TimeStamp can't
|
||||
* be null.
|
||||
* @return number of milliseconds value as one of:
|
||||
* - relative to the navigation start time, time the user has landed on the
|
||||
* page
|
||||
* - an absolute wall clock time since the unix epoch
|
||||
*/
|
||||
inline DOMHighResTimeStamp TimeStampToDOMHighRes(TimeStamp aStamp) const
|
||||
{
|
||||
MOZ_ASSERT(!aStamp.IsNull());
|
||||
mozilla::TimeDuration duration =
|
||||
aStamp - GetDOMTiming()->GetNavigationStartTimeStamp();
|
||||
return duration.ToMilliseconds() + mZeroTime;
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE;
|
||||
|
||||
// PerformanceNavigation WebIDL methods
|
||||
@ -54,32 +136,36 @@ public:
|
||||
}
|
||||
return GetDOMTiming()->GetUnloadEventEnd();
|
||||
}
|
||||
DOMTimeMilliSec RedirectStart() {
|
||||
if (!nsContentUtils::IsPerformanceTimingEnabled()) {
|
||||
return 0;
|
||||
}
|
||||
return GetDOMTiming()->GetRedirectStart();
|
||||
}
|
||||
DOMTimeMilliSec RedirectEnd() {
|
||||
if (!nsContentUtils::IsPerformanceTimingEnabled()) {
|
||||
return 0;
|
||||
}
|
||||
return GetDOMTiming()->GetRedirectEnd();
|
||||
}
|
||||
DOMTimeMilliSec FetchStart() const {
|
||||
if (!nsContentUtils::IsPerformanceTimingEnabled()) {
|
||||
return 0;
|
||||
}
|
||||
return GetDOMTiming()->GetFetchStart();
|
||||
}
|
||||
DOMTimeMilliSec DomainLookupStart() const;
|
||||
DOMTimeMilliSec DomainLookupEnd() const;
|
||||
DOMTimeMilliSec ConnectStart() const;
|
||||
DOMTimeMilliSec ConnectEnd() const;
|
||||
DOMTimeMilliSec RequestStart() const;
|
||||
DOMTimeMilliSec ResponseStart() const;
|
||||
DOMTimeMilliSec ResponseEnd() const;
|
||||
DOMTimeMilliSec DomLoading() const {
|
||||
|
||||
uint16_t GetRedirectCount() const;
|
||||
bool IsSameOriginAsReferral() const;
|
||||
void CheckRedirectCrossOrigin(nsIHttpChannel* aResourceChannel);
|
||||
|
||||
// High resolution (used by resource timing)
|
||||
DOMHighResTimeStamp FetchStartHighRes();
|
||||
DOMHighResTimeStamp RedirectStartHighRes();
|
||||
DOMHighResTimeStamp RedirectEndHighRes();
|
||||
DOMHighResTimeStamp DomainLookupStartHighRes();
|
||||
DOMHighResTimeStamp DomainLookupEndHighRes();
|
||||
DOMHighResTimeStamp ConnectStartHighRes();
|
||||
DOMHighResTimeStamp ConnectEndHighRes();
|
||||
DOMHighResTimeStamp RequestStartHighRes();
|
||||
DOMHighResTimeStamp ResponseStartHighRes();
|
||||
DOMHighResTimeStamp ResponseEndHighRes();
|
||||
|
||||
// Low resolution (used by navigation timing)
|
||||
DOMTimeMilliSec FetchStart();
|
||||
DOMTimeMilliSec RedirectStart();
|
||||
DOMTimeMilliSec RedirectEnd();
|
||||
DOMTimeMilliSec DomainLookupStart();
|
||||
DOMTimeMilliSec DomainLookupEnd();
|
||||
DOMTimeMilliSec ConnectStart();
|
||||
DOMTimeMilliSec ConnectEnd();
|
||||
DOMTimeMilliSec RequestStart();
|
||||
DOMTimeMilliSec ResponseStart();
|
||||
DOMTimeMilliSec ResponseEnd();
|
||||
|
||||
DOMTimeMilliSec DomLoading() {
|
||||
if (!nsContentUtils::IsPerformanceTimingEnabled()) {
|
||||
return 0;
|
||||
}
|
||||
@ -124,8 +210,16 @@ public:
|
||||
|
||||
private:
|
||||
~nsPerformanceTiming();
|
||||
bool IsInitialized() const;
|
||||
nsRefPtr<nsPerformance> mPerformance;
|
||||
nsCOMPtr<nsITimedChannel> mChannel;
|
||||
DOMHighResTimeStamp mFetchStart;
|
||||
// This is an offset that will be added to each timing ([ms] resolution).
|
||||
// There are only 2 possible values: (1) logicaly equal to navigationStart
|
||||
// TimeStamp (results are absolute timstamps - wallclock); (2) "0" (results
|
||||
// are relative to the navigation start).
|
||||
DOMHighResTimeStamp mZeroTime;
|
||||
bool mReportCrossOriginResources;
|
||||
};
|
||||
|
||||
// Script "performance.navigation" object
|
||||
@ -137,6 +231,7 @@ public:
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(nsPerformanceNavigation)
|
||||
|
||||
nsDOMNavigationTiming* GetDOMTiming() const;
|
||||
nsPerformanceTiming* GetPerformanceTiming() const;
|
||||
|
||||
nsPerformance* GetParentObject() const
|
||||
{
|
||||
@ -150,7 +245,7 @@ public:
|
||||
return GetDOMTiming()->GetType();
|
||||
}
|
||||
uint16_t RedirectCount() const {
|
||||
return GetDOMTiming()->GetRedirectCount();
|
||||
return GetPerformanceTiming()->GetRedirectCount();
|
||||
}
|
||||
|
||||
private:
|
||||
@ -163,9 +258,11 @@ class nsPerformance MOZ_FINAL : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
typedef mozilla::dom::PerformanceEntry PerformanceEntry;
|
||||
nsPerformance(nsIDOMWindow* aWindow,
|
||||
nsDOMNavigationTiming* aDOMTiming,
|
||||
nsITimedChannel* aChannel);
|
||||
nsITimedChannel* aChannel,
|
||||
nsPerformance* aParentPerformance);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsPerformance)
|
||||
@ -180,6 +277,11 @@ public:
|
||||
return mChannel;
|
||||
}
|
||||
|
||||
nsPerformance* GetParentPerformance() const
|
||||
{
|
||||
return mParentPerformance;
|
||||
}
|
||||
|
||||
nsIDOMWindow* GetParentObject() const
|
||||
{
|
||||
return mWindow.get();
|
||||
@ -192,6 +294,17 @@ public:
|
||||
nsPerformanceTiming* Timing();
|
||||
nsPerformanceNavigation* Navigation();
|
||||
|
||||
void GetEntries(nsTArray<nsRefPtr<PerformanceEntry> >& retval);
|
||||
void GetEntriesByType(const nsAString& entryType,
|
||||
nsTArray<nsRefPtr<PerformanceEntry> >& retval);
|
||||
void GetEntriesByName(const nsAString& name,
|
||||
const mozilla::dom::Optional< nsAString >& entryType,
|
||||
nsTArray<nsRefPtr<PerformanceEntry> >& retval);
|
||||
void AddEntry(nsIHttpChannel* channel,
|
||||
nsITimedChannel* timedChannel);
|
||||
void ClearResourceTimings();
|
||||
void SetResourceTimingBufferSize(uint64_t maxSize);
|
||||
|
||||
private:
|
||||
~nsPerformance();
|
||||
|
||||
@ -200,6 +313,21 @@ private:
|
||||
nsCOMPtr<nsITimedChannel> mChannel;
|
||||
nsRefPtr<nsPerformanceTiming> mTiming;
|
||||
nsRefPtr<nsPerformanceNavigation> mNavigation;
|
||||
nsTArray<nsRefPtr<PerformanceEntry> > mEntries;
|
||||
nsRefPtr<nsPerformance> mParentPerformance;
|
||||
uint64_t mBufferSizeSet;
|
||||
uint64_t mPrimaryBufferSize;
|
||||
|
||||
static const uint64_t kDefaultBufferSize = 150;
|
||||
|
||||
// Helper classes
|
||||
class PerformanceEntryComparator {
|
||||
public:
|
||||
bool Equals(const PerformanceEntry* aElem1,
|
||||
const PerformanceEntry* aElem2) const;
|
||||
bool LessThan(const PerformanceEntry* aElem1,
|
||||
const PerformanceEntry* aElem2) const;
|
||||
};
|
||||
};
|
||||
|
||||
inline nsDOMNavigationTiming*
|
||||
@ -208,6 +336,12 @@ nsPerformanceNavigation::GetDOMTiming() const
|
||||
return mPerformance->GetDOMTiming();
|
||||
}
|
||||
|
||||
inline nsPerformanceTiming*
|
||||
nsPerformanceNavigation::GetPerformanceTiming() const
|
||||
{
|
||||
return mPerformance->Timing();
|
||||
}
|
||||
|
||||
inline nsDOMNavigationTiming*
|
||||
nsPerformanceTiming::GetDOMTiming() const
|
||||
{
|
||||
|
@ -12,6 +12,8 @@ support-files =
|
||||
file_moving_xhr.html
|
||||
file_showModalDialog.html
|
||||
historyframes.html
|
||||
resource_timing_iframe.html
|
||||
resource_timing_main_test.html
|
||||
|
||||
[test_497898.html]
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || toolkit == 'android' #Bug 931116, b2g desktop specific, initial triage
|
||||
@ -48,6 +50,7 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop spec
|
||||
[test_outerHTML.html]
|
||||
[test_outerHTML.xhtml]
|
||||
[test_paste_selection.html]
|
||||
[test_resource_timing.html]
|
||||
skip-if = buildapp == 'b2g' # b2g(No clipboard) b2g-debug(No clipboard) b2g-desktop(No clipboard)
|
||||
[test_performance_now.html]
|
||||
[test_showModalDialog.html]
|
||||
|
48
dom/tests/mochitest/general/resource_timing_iframe.html
Normal file
48
dom/tests/mochitest/general/resource_timing_iframe.html
Normal file
@ -0,0 +1,48 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
|
||||
<!--
|
||||
This file is a sub-test file for the Resource Timing and Performance Timeline
|
||||
APIs.
|
||||
These tests are focused on the iframe corner case.
|
||||
The first step is to check that the image from this document was added as
|
||||
an entry to this window.performance object.
|
||||
The second step is to check that this iframe was not added as an entry to its
|
||||
own window.performance object.
|
||||
As a final step, we do a double checking: no ifrmes were added as entries
|
||||
to this window.performance object.
|
||||
-->
|
||||
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 822480 - Add in the Resource Timing API</title>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<script>
|
||||
function doTest() {
|
||||
window.parent.ok(!!window.performance.getEntriesByName(
|
||||
"http://example.com/tests/image/test/mochitest/damon.jpg").length,
|
||||
"http://example.com/tests/image/test/mochitest/damon.jpg should be a valid entry name");
|
||||
window.parent.ok(!window.performance.getEntriesByName(
|
||||
"http://mochi.test:8888/tests/dom/tests/mochitest/general/resource_timing_iframe.html").length,
|
||||
"This iframe should NOT contain itself as an entry");
|
||||
|
||||
// Check that there are no iframes added as entries
|
||||
for (var i = 0 ; i < window.performance.getEntries().length ; i++) {
|
||||
var entry = window.performance.getEntries()[i];
|
||||
if (entry.initiatorType === "subdocument") {
|
||||
ok(false, "unexpected iframe " + entry.name);
|
||||
}
|
||||
}
|
||||
|
||||
window.parent.iframeTestsCompleted();
|
||||
}
|
||||
</script>
|
||||
<body onLoad="doTest()">
|
||||
<img src="http://example.com/tests/image/test/mochitest/damon.jpg"/>
|
||||
</body>
|
||||
</html>
|
258
dom/tests/mochitest/general/resource_timing_main_test.html
Normal file
258
dom/tests/mochitest/general/resource_timing_main_test.html
Normal file
@ -0,0 +1,258 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
|
||||
<!--
|
||||
This file contains test for the Resource Timing and Performance Timeline APIs.
|
||||
The test starts by checking that all the entries were added to the performance
|
||||
object.
|
||||
The next step is to check that the "performance" object and its "getEntries()"
|
||||
methods are available. We check all the 3 methods: getEntries,
|
||||
getEntriesByName() and getEntriesByType().
|
||||
|
||||
As a next step, we check that the entries contain the correct information
|
||||
("checkEntries()" method).
|
||||
The test checks that the entries contain all the required members, that the
|
||||
timings are sorted properly and that the entries were returned in
|
||||
chronological order with respect to startTime. In "checkEntries()", it is also
|
||||
checked if the order of the entries is the expected order (the expected order
|
||||
is hard-coded here).
|
||||
The last test from the "checkEntries()" method will verify the iframe case:
|
||||
the iframe must be added as an entry to this window's performance object,
|
||||
while the image from the iframe should not be added here.
|
||||
|
||||
Next tests will check the Performance API extensions introduced by the
|
||||
resource timing: window.performance.setResourceTimingBufferSize(1) and
|
||||
window.performance.clearResourceTimings();
|
||||
|
||||
The last tests will verify that the xhr resources are also added as entries
|
||||
to our performance object.
|
||||
|
||||
Meanwhile, the iframe from the page will get loaded
|
||||
(resource_timing_iframe.html).
|
||||
The iframe contains a second script that will do some tests, as well, plus
|
||||
an image - its own resource.
|
||||
The script from the iframe will check that the iframe itself was not added
|
||||
as an entry (to itself). Also, it will check that its image was added as
|
||||
entry to the iframe's performance object.
|
||||
The last check is a double check: check that no subdocuments were added as
|
||||
entries for this iframe's performance object.
|
||||
The parent's (this window) "ok_wrapper()" method will be called once the tests
|
||||
are completed.
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript">
|
||||
|
||||
var mainWindowTestsDone = false;
|
||||
var iframeTestsDone = false;
|
||||
|
||||
function ok(cond, message) {
|
||||
window.opener.ok(cond, message)
|
||||
}
|
||||
|
||||
function is(received, expected, message) {
|
||||
window.opener.is(received, expected, message);
|
||||
}
|
||||
|
||||
function isnot(received, notExpected, message) {
|
||||
window.opener.isnot(received, notExpected, message);
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
ok(!!window.performance, "Performance object should exist");
|
||||
ok(!!window.performance.getEntries, "Performance.getEntries() should exist");
|
||||
ok(!!window.performance.getEntriesByName, "Performance.getEntriesByName() should exist");
|
||||
ok(!!window.performance.getEntriesByType, "Performance.getEntriesByType() should exist");
|
||||
|
||||
// Here, we should have 6 entries (1 css, 3 png, 1 html) since the image was loaded.
|
||||
is(window.performance.getEntries().length, 5, "Performance.getEntries() returned wrong number of entries.");
|
||||
|
||||
ok(!!window.performance.getEntriesByType("resource").length,
|
||||
"Performance.getEntriesByType() should return some results");
|
||||
ok(!!window.performance.getEntriesByName("http://example.com/tests/image/test/mochitest/blue.png").length,
|
||||
"Performance.getEntriesByName() should return some results");
|
||||
|
||||
// Checks that two calls for "getEntries()" return a different array with the same
|
||||
// entries.
|
||||
ok(window.performance.getEntries() !== window.performance.getEntries(),
|
||||
"getEntries() should return a different array object every time.");
|
||||
ok(function (array1, array2) {
|
||||
if (array1.length != array2.length) {
|
||||
return false;
|
||||
}
|
||||
for (var i = 0 ; i < array1.length ; i++) {
|
||||
if (array1[i] !== array2[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}(window.performance.getEntries(), window.performance.getEntries()),
|
||||
"The arrays should have the same entries.");
|
||||
|
||||
checkEntries(window.performance.getEntries());
|
||||
|
||||
window.performance.setResourceTimingBufferSize(1);
|
||||
is(window.performance.getEntries().length, 5, "No entries should be " +
|
||||
"removed when setResourceTimingBufferSize is called.");
|
||||
|
||||
window.performance.setResourceTimingBufferSize(4);
|
||||
is(window.performance.getEntries().length, 5, "No entries should be " +
|
||||
"removed when setResourceTimingBufferSize is called.");
|
||||
|
||||
window.performance.setResourceTimingBufferSize(1);
|
||||
window.performance.clearResourceTimings();
|
||||
is(window.performance.getEntries().length, 0, "All the entries should " +
|
||||
"be removed when when clearResourceTimings is being called.");
|
||||
|
||||
makeXhr("test-data.json", firstCheck);
|
||||
}
|
||||
|
||||
function checkEntries(anEntryList) {
|
||||
// Check that all the entries have all the properties.
|
||||
for (var i = 0 ; i < anEntryList.length ; i++) {
|
||||
var entry = anEntryList[i];
|
||||
|
||||
ok(!!entry, "PerformanceEntry should not be null");
|
||||
ok(!!entry.name, "PerformanceEntry.name should be valid.");
|
||||
ok(entry.startTime > 0, "PerformanceEntry.startTime should be grater than 0");
|
||||
|
||||
// The entries list should be in chronological order with respect to startTime
|
||||
if (i > 0) {
|
||||
ok(anEntryList[i - 1].startTime <= anEntryList[i].startTime,
|
||||
"Entries list should be in chronological order with respect to startTime.");
|
||||
}
|
||||
|
||||
// Check that each entry has all the properties and that the timings were
|
||||
// returned in the expected order.
|
||||
if ("initiatorType" in entry) {
|
||||
ok("redirectStart" in entry, "PerformanceEntry.redirectStart should be part of PerformanceEntry");
|
||||
ok("redirectEnd" in entry, "PerformanceEntry.redirectEnd should be part of PerformanceEntry");
|
||||
ok("fetchStart" in entry, "PerformanceEntry.fetchStart should be part of PerformanceEntry");
|
||||
ok("domainLookupStart" in entry, "PerformanceEntry.domainLookupStart should be part of PerformanceEntry");
|
||||
ok("domainLookupEnd" in entry, "PerformanceEntry.domainLookupEnd should be part of PerformanceEntry");
|
||||
ok("connectStart" in entry, "PerformanceEntry.connectStart should be part of PerformanceEntry");
|
||||
ok("connectEnd" in entry, "PerformanceEntry.connectEnd should be part of PerformanceEntry");
|
||||
ok("secureConnectionStart" in entry, "PerformanceEntry.secureConnectionStart should be part of PerformanceEntry");
|
||||
ok("requestStart" in entry, "PerformanceEntry.requestStart should be part of PerformanceEntry");
|
||||
ok("responseStart" in entry, "PerformanceEntry.responseStart should be part of PerformanceEntry");
|
||||
ok("responseEnd" in entry, "PerformanceEntry.responseEnd should be part of PerformanceEntry");
|
||||
|
||||
// Check that timings are in proper order
|
||||
sequence = ['startTime', 'redirectStart', 'redirectEnd', 'fetchStart',
|
||||
'domainLookupStart', 'domainLookupEnd', 'connectStart',
|
||||
'connectEnd', 'requestStart', 'responseStart', 'responseEnd'];
|
||||
for (var j = 1; j < sequence.length; ++j) {
|
||||
var prop = sequence[j];
|
||||
var prevProp = sequence[j-1];
|
||||
ok(entry[prevProp] <= entry[prop],
|
||||
['Expected ', prevProp, ' to happen before ', prop,
|
||||
', got ', prevProp, ' = ', entry[prevProp],
|
||||
', ', prop, ' = ', entry[prop]].join(''));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the entries have the expected initiator type. We can't check
|
||||
// the order (the order might depend on the platform the tests are running).
|
||||
allResources = {
|
||||
"http://mochi.test:8888/tests/SimpleTest/test.css" : "link",
|
||||
"http://example.com/tests/image/test/mochitest/blue.png" : "img",
|
||||
"http://example.com/tests/image/test/mochitest/red.png" : "object",
|
||||
"http://example.com/tests/image/test/mochitest/big.png" : "embed",
|
||||
"http://mochi.test:8888/tests/dom/tests/mochitest/general/resource_timing_iframe.html" : "subdocument"};
|
||||
|
||||
for (resourceName in allResources) {
|
||||
// Check that we have a resource with the specific name.
|
||||
namedEntries = window.performance.getEntriesByName(resourceName);
|
||||
ok (!!namedEntries && (namedEntries.length == 1),
|
||||
"An entry with the name '" + resourceName + "' should be available");
|
||||
|
||||
// Double check for the entry name.
|
||||
is (namedEntries[0].name, resourceName, "The resource name is invalid");
|
||||
|
||||
// Check the initiator type.
|
||||
is (namedEntries[0].initiatorType, allResources[resourceName],
|
||||
"The initiator type for " + resourceName + " is invalid");
|
||||
}
|
||||
|
||||
// Check that the iframe's image was NOT added as an entry to this window's performance entry.
|
||||
ok(!window.performance.getEntriesByName("http://example.com/tests/image/test/mochitest/damon.jpg").length,
|
||||
"http://example.com/tests/image/test/mochitest/damon.jpg should be a valid entry name");
|
||||
}
|
||||
|
||||
function firstCheck() {
|
||||
is(window.performance.getEntries().length, 1, "The first xhr entry was not added.");
|
||||
is(window.performance.getEntries()[0].initiatorType, "xmlhttprequest",
|
||||
"The initiatorType is incorect for this entry");
|
||||
makeXhr("test-data2.json", secondCheck);
|
||||
}
|
||||
|
||||
function secondCheck() {
|
||||
// Since the buffer max size was set to '1', 'peformance.getEntries()' should
|
||||
// return only '1' entry (first xhr results).
|
||||
is(window.performance.getEntries().length, 1, "The second xhr entry should not be " +
|
||||
"returned since the buffer size was set to 1.");
|
||||
isnot(window.performance.getEntries()[0].name, "http://mochi.test:8888/tests/dom/tests/mochitest/general/test-data2.json",
|
||||
"We returned the second xhr instead of the first one");
|
||||
finishTest();
|
||||
}
|
||||
|
||||
function finishTest() {
|
||||
// Check if all the tests are completed.
|
||||
if (iframeTestsDone) {
|
||||
window.opener.finishTests();
|
||||
} else {
|
||||
mainWindowTestsDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
function makeXhr(aUrl, aCallback) {
|
||||
var xmlhttp = new XMLHttpRequest();
|
||||
xmlhttp.onload = aCallback;
|
||||
xmlhttp.open("get", aUrl, true);
|
||||
xmlhttp.send();
|
||||
}
|
||||
|
||||
function checkArraysHaveSameElementsInSameOrder(array1, array2) {
|
||||
if (array1.length != array2.length) {
|
||||
return false;
|
||||
}
|
||||
for (var i = 0 ; i < array1.length ; i++) {
|
||||
if (array1[i] !== array2[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function iframeTestsCompleted() {
|
||||
if (mainWindowTestsDone) {
|
||||
window.opener.finishTests();
|
||||
}
|
||||
else {
|
||||
iframeTestsDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=822480"
|
||||
title="Add resource timing API.">
|
||||
Bug #822480 - Add in the Resource Timing API
|
||||
</a>
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
<img src="http://example.com/tests/image/test/mochitest/blue.png">
|
||||
<object data="http://example.com/tests/image/test/mochitest/red.png" type="image/png"/>
|
||||
<embed src="http://example.com/tests/image/test/mochitest/big.png" type="image/png"/>
|
||||
<iframe sandbox="allow-same-origin allow-scripts" id="if_2" src="resource_timing_iframe.html" height="10" width="10"></iframe>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
1
dom/tests/mochitest/general/test-data.json
Normal file
1
dom/tests/mochitest/general/test-data.json
Normal file
@ -0,0 +1 @@
|
||||
{ id: "test JSON data", myArray: [ "foo", "bar", "baz", "biff" ] }
|
1
dom/tests/mochitest/general/test-data2.json
Normal file
1
dom/tests/mochitest/general/test-data2.json
Normal file
@ -0,0 +1 @@
|
||||
{ id: "test JSON data", myArray: [ "foo", "bar", "baz", "biff" ] }
|
@ -747,8 +747,12 @@ var interfaceNamesInGlobalScope =
|
||||
{ name: "Path2D", pref: "canvas.path.enabled" },
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"Performance",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"PerformanceEntry",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"PerformanceNavigation",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"PerformanceResourceTiming",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"PerformanceTiming",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
35
dom/tests/mochitest/general/test_resource_timing.html
Normal file
35
dom/tests/mochitest/general/test_resource_timing.html
Normal file
@ -0,0 +1,35 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=822480
|
||||
-->
|
||||
<head>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
// Resource timing is prefed off by default, so we had to use this workaround
|
||||
SpecialPowers.setBoolPref("dom.enable_resource_timing", true);
|
||||
var subwindow = window.open("resource_timing_main_test.html");
|
||||
|
||||
function finishTests() {
|
||||
subwindow.close();
|
||||
SpecialPowers.setBoolPref("dom.enable_resource_timing", false);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -11,6 +11,7 @@
|
||||
*/
|
||||
|
||||
typedef double DOMHighResTimeStamp;
|
||||
typedef sequence <PerformanceEntry> PerformanceEntryList;
|
||||
|
||||
interface Performance {
|
||||
DOMHighResTimeStamp now();
|
||||
@ -22,3 +23,17 @@ interface Performance {
|
||||
|
||||
jsonifier;
|
||||
};
|
||||
|
||||
// http://www.w3c-test.org/webperf/specs/PerformanceTimeline/#sec-window.performance-attribute
|
||||
partial interface Performance {
|
||||
PerformanceEntryList getEntries();
|
||||
PerformanceEntryList getEntriesByType(DOMString entryType);
|
||||
PerformanceEntryList getEntriesByName(DOMString name, optional DOMString
|
||||
entryType);
|
||||
};
|
||||
|
||||
// http://w3c-test.org/webperf/specs/ResourceTiming/#extensions-performance-interface
|
||||
partial interface Performance {
|
||||
void clearResourceTimings();
|
||||
void setResourceTimingBufferSize(unsigned long maxSize);
|
||||
};
|
||||
|
19
dom/webidl/PerformanceEntry.webidl
Normal file
19
dom/webidl/PerformanceEntry.webidl
Normal file
@ -0,0 +1,19 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* http://www.w3c-test.org/webperf/specs/PerformanceTimeline/#sec-PerformanceEntry-interface
|
||||
*
|
||||
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
interface PerformanceEntry
|
||||
{
|
||||
readonly attribute DOMString name;
|
||||
readonly attribute DOMString entryType;
|
||||
readonly attribute DOMHighResTimeStamp startTime;
|
||||
readonly attribute DOMHighResTimeStamp duration;
|
||||
};
|
33
dom/webidl/PerformanceResourceTiming.webidl
Normal file
33
dom/webidl/PerformanceResourceTiming.webidl
Normal file
@ -0,0 +1,33 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* http://w3c-test.org/webperf/specs/ResourceTiming/#performanceresourcetiming
|
||||
*
|
||||
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
interface PerformanceResourceTiming : PerformanceEntry
|
||||
{
|
||||
// A string with the name of that element that initiated the load.
|
||||
// If the initiator is a CSS resource, the initiatorType attribute must return
|
||||
// the string "css".
|
||||
// If the initiator is an XMLHttpRequest object, the initiatorType attribute
|
||||
// must return the string "xmlhttprequest".
|
||||
readonly attribute DOMString initiatorType;
|
||||
|
||||
readonly attribute DOMHighResTimeStamp redirectStart;
|
||||
readonly attribute DOMHighResTimeStamp redirectEnd;
|
||||
readonly attribute DOMHighResTimeStamp fetchStart;
|
||||
readonly attribute DOMHighResTimeStamp domainLookupStart;
|
||||
readonly attribute DOMHighResTimeStamp domainLookupEnd;
|
||||
readonly attribute DOMHighResTimeStamp connectStart;
|
||||
readonly attribute DOMHighResTimeStamp connectEnd;
|
||||
readonly attribute DOMHighResTimeStamp secureConnectionStart;
|
||||
readonly attribute DOMHighResTimeStamp requestStart;
|
||||
readonly attribute DOMHighResTimeStamp responseStart;
|
||||
readonly attribute DOMHighResTimeStamp responseEnd;
|
||||
};
|
@ -269,7 +269,9 @@ WEBIDL_FILES = [
|
||||
'PannerNode.webidl',
|
||||
'ParentNode.webidl',
|
||||
'Performance.webidl',
|
||||
'PerformanceEntry.webidl',
|
||||
'PerformanceNavigation.webidl',
|
||||
'PerformanceResourceTiming.webidl',
|
||||
'PerformanceTiming.webidl',
|
||||
'PeriodicWave.webidl',
|
||||
'PermissionSettings.webidl',
|
||||
|
@ -119,7 +119,7 @@ nsXBLResourceLoader::LoadResources(bool* aResult)
|
||||
// XXX: initialDocumentURI is nullptr!
|
||||
nsRefPtr<imgRequestProxy> req;
|
||||
nsContentUtils::LoadImage(url, doc, docPrincipal, docURL, nullptr,
|
||||
nsIRequest::LOAD_BACKGROUND,
|
||||
nsIRequest::LOAD_BACKGROUND, EmptyString(),
|
||||
getter_AddRefs(req));
|
||||
}
|
||||
else if (curr->mType == nsGkAtoms::stylesheet) {
|
||||
|
@ -310,7 +310,7 @@ nsContextMenuInfo::GetBackgroundImageRequestInternal(nsIDOMNode *aDOMNode, imgRe
|
||||
|
||||
return il->LoadImage(bgUri, nullptr, nullptr, principal, nullptr,
|
||||
nullptr, nullptr, nsIRequest::LOAD_NORMAL,
|
||||
nullptr, channelPolicy, aRequest);
|
||||
nullptr, channelPolicy, EmptyString(), aRequest);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1562,6 +1562,7 @@ NS_IMETHODIMP imgLoader::LoadImageXPCOM(nsIURI *aURI,
|
||||
aLoadFlags,
|
||||
aCacheKey,
|
||||
aPolicy,
|
||||
EmptyString(),
|
||||
&proxy);
|
||||
*_retval = proxy;
|
||||
return result;
|
||||
@ -1581,6 +1582,7 @@ nsresult imgLoader::LoadImage(nsIURI *aURI,
|
||||
nsLoadFlags aLoadFlags,
|
||||
nsISupports *aCacheKey,
|
||||
nsIChannelPolicy *aPolicy,
|
||||
const nsAString& initiatorType,
|
||||
imgRequestProxy **_retval)
|
||||
{
|
||||
VerifyCacheSizes();
|
||||
@ -1718,6 +1720,12 @@ nsresult imgLoader::LoadImage(nsIURI *aURI,
|
||||
request->Init(aURI, aURI, channelLoadGroup, newChannel, entry, aCX,
|
||||
aLoadingPrincipal, corsmode);
|
||||
|
||||
// Add the initiator type for this image load
|
||||
nsCOMPtr<nsITimedChannel> timedChannel = do_QueryInterface(newChannel);
|
||||
if (timedChannel) {
|
||||
timedChannel->SetInitiatorType(initiatorType);
|
||||
}
|
||||
|
||||
// Pass the inner window ID of the loading document, if possible.
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aCX);
|
||||
if (doc) {
|
||||
|
@ -255,6 +255,7 @@ public:
|
||||
nsLoadFlags aLoadFlags,
|
||||
nsISupports *aCacheKey,
|
||||
nsIChannelPolicy *aPolicy,
|
||||
const nsAString& initiatorType,
|
||||
imgRequestProxy **_retval);
|
||||
nsresult LoadImageWithChannel(nsIChannel *channel,
|
||||
imgINotificationObserver *aObserver,
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
|
||||
#include "imgRequest.h"
|
||||
|
||||
|
@ -1842,6 +1842,7 @@ nsImageFrame::LoadIcon(const nsAString& aSpec,
|
||||
loadFlags,
|
||||
nullptr,
|
||||
nullptr, /* channel policy not needed */
|
||||
EmptyString(),
|
||||
aRequest);
|
||||
}
|
||||
|
||||
|
@ -259,6 +259,7 @@ ImageLoader::LoadImage(nsIURI* aURI, nsIPrincipal* aOriginPrincipal,
|
||||
nsRefPtr<imgRequestProxy> request;
|
||||
nsContentUtils::LoadImage(aURI, mDocument, aOriginPrincipal, aReferrer,
|
||||
nullptr, nsIRequest::LOAD_NORMAL,
|
||||
NS_LITERAL_STRING("css"),
|
||||
getter_AddRefs(request));
|
||||
|
||||
if (!request) {
|
||||
|
@ -1546,6 +1546,16 @@ Loader::LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState)
|
||||
nsCOMPtr<nsIURI> referrerURI = aLoadData->GetReferrerURI();
|
||||
if (referrerURI)
|
||||
httpChannel->SetReferrer(referrerURI);
|
||||
|
||||
// Set the initiator type
|
||||
nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(httpChannel));
|
||||
if (timedChannel) {
|
||||
if (aLoadData->mParentData) {
|
||||
timedChannel->SetInitiatorType(NS_LITERAL_STRING("css"));
|
||||
} else {
|
||||
timedChannel->SetInitiatorType(NS_LITERAL_STRING("link"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now tell the channel we expect text/css data back.... We do
|
||||
|
@ -236,7 +236,7 @@ nsImageBoxFrame::UpdateImage()
|
||||
mContent->NodePrincipal())) {
|
||||
nsContentUtils::LoadImage(uri, doc, mContent->NodePrincipal(),
|
||||
doc->GetDocumentURI(), mListener, mLoadFlags,
|
||||
getter_AddRefs(mImageRequest));
|
||||
EmptyString(), getter_AddRefs(mImageRequest));
|
||||
|
||||
if (mImageRequest) {
|
||||
nsLayoutUtils::RegisterImageRequestIfAnimated(presContext,
|
||||
|
@ -2199,6 +2199,7 @@ nsTreeBodyFrame::GetImage(int32_t aRowIndex, nsTreeColumn* aCol, bool aUseContex
|
||||
doc->GetDocumentURI(),
|
||||
imgNotificationObserver,
|
||||
nsIRequest::LOAD_NORMAL,
|
||||
EmptyString(),
|
||||
getter_AddRefs(imageRequest));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -105,6 +105,9 @@ pref("dom.workers.sharedWorkers.enabled", true);
|
||||
// Whether nonzero values can be returned from performance.timing.*
|
||||
pref("dom.enable_performance", true);
|
||||
|
||||
// Whether resource timing will be gathered and returned by performance.GetEntries*
|
||||
pref("dom.enable_resource_timing", false);
|
||||
|
||||
// Whether the Gamepad API is enabled
|
||||
pref("dom.gamepad.enabled", true);
|
||||
#ifdef RELEASE_BUILD
|
||||
|
@ -12,13 +12,16 @@ class TimeStamp;
|
||||
native TimeStamp(mozilla::TimeStamp);
|
||||
|
||||
// All properties return zero if the value is not available
|
||||
[scriptable, uuid(c259b593-a9bf-4d08-8149-ef89e1977dc4)]
|
||||
[scriptable, uuid(E94AB245-B40D-4154-8B7F-B6E0F2461031)]
|
||||
interface nsITimedChannel : nsISupports {
|
||||
// Set this attribute to true to enable collection of timing data.
|
||||
// channelCreationTime will be available even with this attribute set to
|
||||
// false.
|
||||
attribute boolean timingEnabled;
|
||||
|
||||
// The number of redirects
|
||||
attribute uint16_t redirectCount;
|
||||
|
||||
[noscript] readonly attribute TimeStamp channelCreation;
|
||||
[noscript] readonly attribute TimeStamp asyncOpen;
|
||||
|
||||
@ -32,6 +35,17 @@ interface nsITimedChannel : nsISupports {
|
||||
[noscript] readonly attribute TimeStamp responseStart;
|
||||
[noscript] readonly attribute TimeStamp responseEnd;
|
||||
|
||||
// The redirect attributes timings must be writeble, se we can transfer
|
||||
// the data from one channel to the redirected channel.
|
||||
[noscript] attribute TimeStamp redirectStart;
|
||||
[noscript] attribute TimeStamp redirectEnd;
|
||||
|
||||
// The initiator type
|
||||
[noscript] attribute AString initiatorType;
|
||||
|
||||
// This flag should be set to false only if a cross-domain redirect occurred
|
||||
[noscript] attribute boolean allRedirectsSameOrigin;
|
||||
|
||||
// The following are only set if the document is (partially) read from the
|
||||
// cache
|
||||
[noscript] readonly attribute TimeStamp cacheReadStart;
|
||||
@ -49,4 +63,6 @@ interface nsITimedChannel : nsISupports {
|
||||
readonly attribute PRTime responseEndTime;
|
||||
readonly attribute PRTime cacheReadStartTime;
|
||||
readonly attribute PRTime cacheReadEndTime;
|
||||
readonly attribute PRTime redirectStartTime;
|
||||
readonly attribute PRTime redirectEndTime;
|
||||
};
|
||||
|
@ -26,6 +26,8 @@
|
||||
#include "nsICookieService.h"
|
||||
#include "nsIStreamConverterService.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsIObserverService.h"
|
||||
|
||||
#include <algorithm>
|
||||
@ -59,10 +61,12 @@ HttpBaseChannel::HttpBaseChannel()
|
||||
, mLoadAsBlocking(false)
|
||||
, mLoadUnblocked(false)
|
||||
, mResponseTimeoutEnabled(true)
|
||||
, mAllRedirectsSameOrigin(true)
|
||||
, mSuspendCount(0)
|
||||
, mProxyResolveFlags(0)
|
||||
, mContentDispositionHint(UINT32_MAX)
|
||||
, mHttpHandler(gHttpHandler)
|
||||
, mRedirectCount(0)
|
||||
{
|
||||
LOG(("Creating HttpBaseChannel @%x\n", this));
|
||||
|
||||
@ -1906,14 +1910,47 @@ HttpBaseChannel::SetupReplacementChannel(nsIURI *newURI,
|
||||
if (bag)
|
||||
mPropertyHash.EnumerateRead(CopyProperties, bag.get());
|
||||
|
||||
// transfer timed channel enabled status
|
||||
nsCOMPtr<nsITimedChannel> timed(do_QueryInterface(newChannel));
|
||||
if (timed)
|
||||
timed->SetTimingEnabled(mTimingEnabled);
|
||||
// Transfer the timing data (if we are dealing with an nsITimedChannel).
|
||||
nsCOMPtr<nsITimedChannel> newTimedChannel(do_QueryInterface(newChannel));
|
||||
nsCOMPtr<nsITimedChannel> oldTimedChannel(
|
||||
do_QueryInterface(static_cast<nsIHttpChannel*>(this)));
|
||||
if (oldTimedChannel && newTimedChannel) {
|
||||
newTimedChannel->SetTimingEnabled(mTimingEnabled);
|
||||
newTimedChannel->SetRedirectCount(mRedirectCount + 1);
|
||||
|
||||
// If the RedirectStart is null, we will use the AsyncOpen value of the
|
||||
// previous channel (this is the first redirect in the redirects chain).
|
||||
if (mRedirectStartTimeStamp.IsNull()) {
|
||||
TimeStamp asyncOpen;
|
||||
oldTimedChannel->GetAsyncOpen(&asyncOpen);
|
||||
newTimedChannel->SetRedirectStart(asyncOpen);
|
||||
}
|
||||
else {
|
||||
newTimedChannel->SetRedirectStart(mRedirectStartTimeStamp);
|
||||
}
|
||||
|
||||
// The RedirectEnd timestamp is equal to the previous channel response end.
|
||||
TimeStamp prevResponseEnd;
|
||||
oldTimedChannel->GetResponseEnd(&prevResponseEnd);
|
||||
newTimedChannel->SetRedirectEnd(prevResponseEnd);
|
||||
|
||||
// Check whether or not this was a cross-domain redirect.
|
||||
newTimedChannel->SetAllRedirectsSameOrigin(
|
||||
mAllRedirectsSameOrigin && SameOriginWithOriginalUri(newURI));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Redirect Tracking
|
||||
bool
|
||||
HttpBaseChannel::SameOriginWithOriginalUri(nsIURI *aURI)
|
||||
{
|
||||
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
|
||||
nsresult rv = ssm->CheckSameOriginURI(aURI, mOriginalURI, false);
|
||||
return (NS_SUCCEEDED(rv));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
} // namespace net
|
||||
|
@ -243,6 +243,10 @@ protected:
|
||||
getter_AddRefs(aResult));
|
||||
}
|
||||
|
||||
// Redirect tracking
|
||||
// Checks whether or not aURI and mOriginalURI share the same domain.
|
||||
bool SameOriginWithOriginalUri(nsIURI *aURI);
|
||||
|
||||
friend class PrivateBrowsingChannel<HttpBaseChannel>;
|
||||
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
@ -306,6 +310,8 @@ protected:
|
||||
uint32_t mLoadAsBlocking : 1;
|
||||
uint32_t mLoadUnblocked : 1;
|
||||
uint32_t mResponseTimeoutEnabled : 1;
|
||||
// A flag that should be false only if a cross-domain redirect occurred
|
||||
uint32_t mAllRedirectsSameOrigin : 1;
|
||||
|
||||
// Current suspension depth for this channel object
|
||||
uint32_t mSuspendCount;
|
||||
@ -320,6 +326,19 @@ protected:
|
||||
nsAutoPtr<nsString> mContentDispositionFilename;
|
||||
|
||||
nsRefPtr<nsHttpHandler> mHttpHandler; // keep gHttpHandler alive
|
||||
|
||||
// Performance tracking
|
||||
// The initiator type (for this resource) - how was the resource referenced in
|
||||
// the HTML file.
|
||||
nsString mInitiatorType;
|
||||
// Number of redirects that has occurred.
|
||||
int16_t mRedirectCount;
|
||||
// A time value equal to the starting time of the fetch that initiates the
|
||||
// redirect.
|
||||
mozilla::TimeStamp mRedirectStartTimeStamp;
|
||||
// A time value equal to the time immediately after receiving the last byte of
|
||||
// the response of the last redirect.
|
||||
mozilla::TimeStamp mRedirectEndTimeStamp;
|
||||
};
|
||||
|
||||
// Share some code while working around C++'s absurd inability to handle casting
|
||||
|
@ -62,6 +62,8 @@
|
||||
#include "nsIStreamConverterService.h"
|
||||
#include "nsISiteSecurityService.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsPerformance.h"
|
||||
#include "CacheObserver.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
@ -4774,6 +4776,66 @@ nsHttpChannel::GetAsyncOpen(TimeStamp* _retval) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of redirects. There is no check for cross-domain
|
||||
* redirects. This check must be done by the consumers.
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsHttpChannel::GetRedirectCount(uint16_t *aRedirectCount)
|
||||
{
|
||||
*aRedirectCount = mRedirectCount;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHttpChannel::SetRedirectCount(uint16_t aRedirectCount)
|
||||
{
|
||||
mRedirectCount = aRedirectCount;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHttpChannel::GetRedirectStart(TimeStamp* _retval)
|
||||
{
|
||||
*_retval = mRedirectStartTimeStamp;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHttpChannel::SetRedirectStart(TimeStamp aRedirectStart)
|
||||
{
|
||||
mRedirectStartTimeStamp = aRedirectStart;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHttpChannel::GetRedirectEnd(TimeStamp* _retval)
|
||||
{
|
||||
*_retval = mRedirectEndTimeStamp;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHttpChannel::SetRedirectEnd(TimeStamp aRedirectEnd)
|
||||
{
|
||||
mRedirectEndTimeStamp = aRedirectEnd;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHttpChannel::GetAllRedirectsSameOrigin(bool *aAllRedirectsSameOrigin)
|
||||
{
|
||||
*aAllRedirectsSameOrigin = mAllRedirectsSameOrigin;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHttpChannel::SetAllRedirectsSameOrigin(bool aAllRedirectsSameOrigin)
|
||||
{
|
||||
mAllRedirectsSameOrigin = aAllRedirectsSameOrigin;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHttpChannel::GetDomainLookupStart(TimeStamp* _retval) {
|
||||
if (mDNSPrefetch && mDNSPrefetch->TimingsValid())
|
||||
@ -4853,6 +4915,20 @@ nsHttpChannel::GetCacheReadEnd(TimeStamp* _retval) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHttpChannel::GetInitiatorType(nsAString & aInitiatorType)
|
||||
{
|
||||
aInitiatorType = mInitiatorType;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHttpChannel::SetInitiatorType(const nsAString & aInitiatorType)
|
||||
{
|
||||
mInitiatorType = aInitiatorType;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#define IMPL_TIMING_ATTR(name) \
|
||||
NS_IMETHODIMP \
|
||||
nsHttpChannel::Get##name##Time(PRTime* _retval) { \
|
||||
@ -4878,6 +4954,8 @@ IMPL_TIMING_ATTR(ResponseStart)
|
||||
IMPL_TIMING_ATTR(ResponseEnd)
|
||||
IMPL_TIMING_ATTR(CacheReadStart)
|
||||
IMPL_TIMING_ATTR(CacheReadEnd)
|
||||
IMPL_TIMING_ATTR(RedirectStart)
|
||||
IMPL_TIMING_ATTR(RedirectEnd)
|
||||
|
||||
#undef IMPL_TIMING_ATTR
|
||||
|
||||
@ -5240,6 +5318,12 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult st
|
||||
}
|
||||
}
|
||||
|
||||
// Register entry to the Performance resource timing
|
||||
nsPerformance* documentPerformance = GetPerformance();
|
||||
if (documentPerformance) {
|
||||
documentPerformance->AddEntry(this, this);
|
||||
}
|
||||
|
||||
if (mListener) {
|
||||
LOG((" calling OnStopRequest\n"));
|
||||
mListener->OnStopRequest(this, mListenerContext, status);
|
||||
@ -6218,6 +6302,46 @@ nsHttpChannel::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks)
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsPerformance*
|
||||
nsHttpChannel::GetPerformance()
|
||||
{
|
||||
// If performance timing is disabled, there is no need for the nsPerformance
|
||||
// object anymore.
|
||||
if (!mTimingEnabled) {
|
||||
return nullptr;
|
||||
}
|
||||
nsCOMPtr<nsILoadContext> loadContext;
|
||||
NS_QueryNotificationCallbacks(this, loadContext);
|
||||
if (!loadContext) {
|
||||
return nullptr;
|
||||
}
|
||||
nsCOMPtr<nsIDOMWindow> domWindow;
|
||||
loadContext->GetAssociatedWindow(getter_AddRefs(domWindow));
|
||||
if (!domWindow) {
|
||||
return nullptr;
|
||||
}
|
||||
nsCOMPtr<nsPIDOMWindow> pDomWindow = do_QueryInterface(domWindow);
|
||||
if (!pDomWindow) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!pDomWindow->IsInnerWindow()) {
|
||||
pDomWindow = pDomWindow->GetCurrentInnerWindow();
|
||||
if (!pDomWindow) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
nsPerformance* docPerformance = pDomWindow->GetPerformance();
|
||||
if (!docPerformance) {
|
||||
return nullptr;
|
||||
}
|
||||
// iframes should be added to the parent's entries list.
|
||||
if (mLoadFlags & LOAD_DOCUMENT_URI) {
|
||||
return docPerformance->GetParentPerformance();
|
||||
}
|
||||
return docPerformance;
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpChannel::ForcePending(bool aForcePending)
|
||||
{
|
||||
|
@ -30,6 +30,7 @@ class nsICacheEntryDescriptor;
|
||||
class nsICancelable;
|
||||
class nsIHttpChannelAuthProvider;
|
||||
class nsInputStreamPump;
|
||||
class nsPerformance;
|
||||
|
||||
namespace mozilla { namespace net {
|
||||
|
||||
@ -420,6 +421,7 @@ private:
|
||||
|
||||
protected:
|
||||
virtual void DoNotifyListenerCleanup();
|
||||
nsPerformance* GetPerformance();
|
||||
|
||||
private: // cache telemetry
|
||||
bool mDidReval;
|
||||
|
@ -241,7 +241,8 @@ OSXNotificationCenter::ShowAlertNotification(const nsAString & aImageUrl, const
|
||||
if (imageUri) {
|
||||
nsresult rv = il->LoadImage(imageUri, nullptr, nullptr, aPrincipal, nullptr,
|
||||
this, nullptr, nsIRequest::LOAD_NORMAL, nullptr,
|
||||
nullptr, getter_AddRefs(osxni->mIconRequest));
|
||||
nullptr, EmptyString(),
|
||||
getter_AddRefs(osxni->mIconRequest));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// Set a timer for six seconds. If we don't have an icon by the time this
|
||||
// goes off then we go ahead without an icon.
|
||||
|
@ -316,7 +316,7 @@ nsMenuItemIconX::LoadIcon(nsIURI* aIconURI)
|
||||
// not exposed to web content
|
||||
nsresult rv = loader->LoadImage(aIconURI, nullptr, nullptr, nullptr, loadGroup, this,
|
||||
nullptr, nsIRequest::LOAD_NORMAL, nullptr,
|
||||
nullptr, getter_AddRefs(mIconRequest));
|
||||
nullptr, EmptyString(), getter_AddRefs(mIconRequest));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// We need to request the icon be decoded (bug 573583, bug 705516).
|
||||
|
Loading…
Reference in New Issue
Block a user