Bug 659126 - Implement additional NavigationTiming properties
authorIgor Bazarny <igor.bazarny@gmail.com>
Mon, 04 Jul 2011 18:44:00 +0200
changeset 72276 d7275a8a0b2aeef800ffe1264c8cf1bc319a867c
parent 72275 3d6a355a81766eda4a9892c578ed99ccd80a4ce5
child 72277 128d2f9f7ac38e9dbef776d6787f0025a201500a
push id20686
push usercbiesinger@gmail.com
push dateMon, 04 Jul 2011 16:44:41 +0000
treeherdermozilla-central@d7275a8a0b2a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs659126
milestone7.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 659126 - Implement additional NavigationTiming properties r=smaug
docshell/base/nsDocShell.cpp
dom/base/nsDOMNavigationTiming.cpp
dom/base/nsDOMNavigationTiming.h
dom/base/nsGlobalWindow.cpp
dom/base/nsPerformance.cpp
dom/base/nsPerformance.h
dom/interfaces/base/nsIDOMPerformanceTiming.idl
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -229,16 +229,17 @@ static NS_DEFINE_CID(kAppShellCID, NS_AP
 
 #include "nsContentErrors.h"
 #include "nsIChannelPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 
 #include "nsXULAppAPI.h"
 
 #include "nsDOMNavigationTiming.h"
+#include "nsITimedChannel.h"
 
 using namespace mozilla;
 
 // Number of documents currently loading
 static PRInt32 gNumberOfDocumentsLoading = 0;
 
 // Global count of existing docshells.
 static PRInt32 gDocShellCount = 0;
@@ -9073,16 +9074,23 @@ nsDocShell::DoURILoad(nsIURI * aURI,
         nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(channel);
         if (props) {
             props->SetPropertyAsBool(
                 NS_LITERAL_STRING("docshell.newWindowTarget"),
                 PR_TRUE);
         }
     }
 
+    if (Preferences::GetBool("dom.enable_performance", PR_FALSE)) {
+        nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(channel));
+        if (timedChannel) {
+            timedChannel->SetTimingEnabled(PR_TRUE);
+        }
+    }
+
     rv = DoChannelLoad(channel, uriLoader, aBypassClassifier);
 
     //
     // If the channel load failed, we failed and nsIWebProgress just ain't
     // gonna happen.
     //
     if (NS_SUCCEEDED(rv)) {
         if (aDocShell) {
--- a/dom/base/nsDOMNavigationTiming.cpp
+++ b/dom/base/nsDOMNavigationTiming.cpp
@@ -73,19 +73,33 @@ nsDOMNavigationTiming::Clear()
   mDOMLoading = 0;
   mDOMInteractive = 0;
   mDOMContentLoadedEventStart = 0;
   mDOMContentLoadedEventEnd = 0;
   mDOMComplete = 0;
   mRedirectCheck = NOT_CHECKED;
 }
 
+nsresult 
+nsDOMNavigationTiming::TimeStampToDOM(mozilla::TimeStamp aStamp, 
+                                      DOMTimeMilliSec* aResult)
+{
+  if (aStamp.IsNull()) {
+    *aResult = 0;
+    return NS_OK;
+  }
+  mozilla::TimeDuration duration = aStamp - mNavigationStartTimeStamp;
+  *aResult = mNavigationStart + static_cast<PRInt32>(duration.ToMilliseconds());
+  return NS_OK;
+}
+
 DOMTimeMilliSec nsDOMNavigationTiming::DurationFromStart(){
-  mozilla::TimeDuration duration = mozilla::TimeStamp::Now() - mNavigationStartTimeStamp;
-  return mNavigationStart + static_cast<PRInt32>(duration.ToMilliseconds());
+  DOMTimeMilliSec result; 
+  TimeStampToDOM(mozilla::TimeStamp::Now(), &result);
+  return result;
 }
 
 void
 nsDOMNavigationTiming::NotifyNavigationStart()
 {
   mNavigationStart = PR_Now() / PR_USEC_PER_MSEC;
   mNavigationStartTimeStamp = mozilla::TimeStamp::Now();
 }
@@ -178,18 +192,17 @@ nsDOMNavigationTiming::ReportRedirects()
   }
   return mRedirectCheck == CHECK_PASSED;
 }
 
 void
 nsDOMNavigationTiming::SetDOMLoadingTimeStamp(nsIURI* aURI, mozilla::TimeStamp aValue)
 {
   mLoadedURI = aURI;
-  mozilla::TimeDuration duration = aValue - mNavigationStartTimeStamp;
-  mDOMLoading = mNavigationStart + (int)(duration.ToMilliseconds());
+  TimeStampToDOM(aValue, &mDOMLoading);
 }
 
 void
 nsDOMNavigationTiming::NotifyDOMLoading(nsIURI* aURI)
 {
   mLoadedURI = aURI;
   mDOMLoading = DurationFromStart();
 }
@@ -217,207 +230,132 @@ nsDOMNavigationTiming::NotifyDOMContentL
 
 void
 nsDOMNavigationTiming::NotifyDOMContentLoadedEnd(nsIURI* aURI)
 {
   mLoadedURI = aURI;
   mDOMContentLoadedEventEnd = DurationFromStart();
 }
 
-
-NS_IMPL_ADDREF(nsDOMNavigationTiming)
-NS_IMPL_RELEASE(nsDOMNavigationTiming)
-
-// QueryInterface implementation for nsDOMNavigationTiming
-NS_INTERFACE_MAP_BEGIN(nsDOMNavigationTiming)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMPerformanceTiming)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMPerformanceTiming)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMPerformanceNavigation)
-NS_INTERFACE_MAP_END
-
-NS_IMETHODIMP
+nsresult
 nsDOMNavigationTiming::GetType(
     nsDOMPerformanceNavigationType* aNavigationType)
 {
   *aNavigationType = mNavigationType;
   return NS_OK;
 }
 
-NS_IMETHODIMP
+nsresult
 nsDOMNavigationTiming::GetRedirectCount(PRUint16* aRedirectCount)
 {
   *aRedirectCount = 0;
   if (ReportRedirects()) {
     *aRedirectCount = mRedirectCount;
   }
   return NS_OK;
 }
 
-NS_IMETHODIMP
+nsresult
 nsDOMNavigationTiming::GetRedirectStart(DOMTimeMilliSec* aRedirectStart)
 {
   *aRedirectStart = 0;
   if (ReportRedirects()) {
     *aRedirectStart = mRedirectStart;
   }
   return NS_OK;
 }
 
-NS_IMETHODIMP
+nsresult
 nsDOMNavigationTiming::GetRedirectEnd(DOMTimeMilliSec* aEnd)
 {
   *aEnd = 0;
   if (ReportRedirects()) {
     *aEnd = mRedirectEnd;
   }
   return NS_OK;
 }
 
-NS_IMETHODIMP
+nsresult
 nsDOMNavigationTiming::GetNavigationStart(DOMTimeMilliSec* aNavigationStart)
 {
   *aNavigationStart = mNavigationStart;
   return NS_OK;
 }
 
-NS_IMETHODIMP
+nsresult
 nsDOMNavigationTiming::GetUnloadEventStart(DOMTimeMilliSec* aStart)
 {
   *aStart = 0;
   nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
   nsresult rv = ssm->CheckSameOriginURI(mLoadedURI, mUnloadedURI, PR_FALSE);
   if (NS_SUCCEEDED(rv)) {
     *aStart = mUnloadStart;
   }
   return NS_OK;
 }
 
-NS_IMETHODIMP
+nsresult
 nsDOMNavigationTiming::GetUnloadEventEnd(DOMTimeMilliSec* aEnd)
 {
   *aEnd = 0;
   nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
   nsresult rv = ssm->CheckSameOriginURI(mLoadedURI, mUnloadedURI, PR_FALSE);
   if (NS_SUCCEEDED(rv)) {
     *aEnd = mUnloadEnd;
   }
   return NS_OK;
 }
 
-NS_IMETHODIMP
+nsresult
 nsDOMNavigationTiming::GetFetchStart(DOMTimeMilliSec* aStart)
 {
   *aStart = mFetchStart;
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDOMNavigationTiming::GetDomainLookupStart(DOMTimeMilliSec* aStart)
-{
-  // TODO: Implement me! (bug 659126)
-  *aStart = mFetchStart;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMNavigationTiming::GetDomainLookupEnd(DOMTimeMilliSec* aEnd)
-{
-  // TODO: Implement me! (bug 659126)
-  *aEnd = mFetchStart;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMNavigationTiming::GetConnectStart(DOMTimeMilliSec* aStart)
-{
-  // TODO: Implement me! (bug 659126)
-  *aStart = mFetchStart;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMNavigationTiming::GetConnectEnd(DOMTimeMilliSec* aEnd)
-{
-  // TODO: Implement me! (bug 659126)
-  *aEnd = mFetchStart;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMNavigationTiming::GetHandshakeStart(DOMTimeMilliSec* aStart)
-{
-  // TODO: Implement me! (bug 659126)
-  *aStart = mFetchStart;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMNavigationTiming::GetRequestStart(DOMTimeMilliSec* aStart)
-{
-  // TODO: Implement me! (bug 659126)
-  *aStart = mFetchStart;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMNavigationTiming::GetResponseStart(DOMTimeMilliSec* aStart)
-{
-  // TODO: Implement me! (bug 659126)
-  *aStart = mFetchStart;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMNavigationTiming::GetResponseEnd(DOMTimeMilliSec* aEnd)
-{
-  // TODO: Implement me! (bug 659126)
-  *aEnd = mFetchStart;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
+nsresult
 nsDOMNavigationTiming::GetDomLoading(DOMTimeMilliSec* aTime)
 {
   *aTime = mDOMLoading;
   return NS_OK;
 }
 
-NS_IMETHODIMP
+nsresult
 nsDOMNavigationTiming::GetDomInteractive(DOMTimeMilliSec* aTime)
 {
   *aTime = mDOMInteractive;
   return NS_OK;
 }
 
-NS_IMETHODIMP
+nsresult
 nsDOMNavigationTiming::GetDomContentLoadedEventStart(DOMTimeMilliSec* aStart)
 {
   *aStart = mDOMContentLoadedEventStart;
   return NS_OK;
 }
 
-NS_IMETHODIMP
+nsresult
 nsDOMNavigationTiming::GetDomContentLoadedEventEnd(DOMTimeMilliSec* aEnd)
 {
   *aEnd = mDOMContentLoadedEventEnd;
   return NS_OK;
 }
 
-NS_IMETHODIMP
+nsresult
 nsDOMNavigationTiming::GetDomComplete(DOMTimeMilliSec* aTime)
 {
   *aTime = mDOMComplete;
   return NS_OK;
 }
 
-NS_IMETHODIMP
+nsresult
 nsDOMNavigationTiming::GetLoadEventStart(DOMTimeMilliSec* aStart)
 {
   *aStart = mLoadEventStart;
   return NS_OK;
 }
 
-NS_IMETHODIMP
+nsresult
 nsDOMNavigationTiming::GetLoadEventEnd(DOMTimeMilliSec* aEnd)
 {
   *aEnd = mLoadEventEnd;
   return NS_OK;
 }
--- a/dom/base/nsDOMNavigationTiming.h
+++ b/dom/base/nsDOMNavigationTiming.h
@@ -46,25 +46,38 @@
 #include "nsCOMPtr.h"
 #include "nsCOMArray.h"
 #include "TimeStamp.h"
 
 class nsDOMNavigationTimingClock;
 class nsIURI;
 class nsIDocument;
 
-class nsDOMNavigationTiming : public nsIDOMPerformanceTiming,
-                              public nsIDOMPerformanceNavigation
+class nsDOMNavigationTiming
 {
 public:
   nsDOMNavigationTiming();
 
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIDOMPERFORMANCETIMING
-  NS_DECL_NSIDOMPERFORMANCENAVIGATION
+  NS_INLINE_DECL_REFCOUNTING(nsDOMNavigationTiming)
+  nsresult GetType(nsDOMPerformanceNavigationType* aNavigationType);
+  nsresult GetRedirectCount(PRUint16* aCount);
+
+  nsresult GetRedirectStart(DOMTimeMilliSec* aRedirectStart);
+  nsresult GetRedirectEnd(DOMTimeMilliSec* aEnd);
+  nsresult GetNavigationStart(DOMTimeMilliSec* aNavigationStart);
+  nsresult GetUnloadEventStart(DOMTimeMilliSec* aStart);
+  nsresult GetUnloadEventEnd(DOMTimeMilliSec* aEnd);
+  nsresult GetFetchStart(DOMTimeMilliSec* aStart);
+  nsresult GetDomLoading(DOMTimeMilliSec* aTime);
+  nsresult GetDomInteractive(DOMTimeMilliSec* aTime);
+  nsresult GetDomContentLoadedEventStart(DOMTimeMilliSec* aStart);
+  nsresult GetDomContentLoadedEventEnd(DOMTimeMilliSec* aEnd);
+  nsresult GetDomComplete(DOMTimeMilliSec* aTime);
+  nsresult GetLoadEventStart(DOMTimeMilliSec* aStart);
+  nsresult GetLoadEventEnd(DOMTimeMilliSec* aEnd);
 
   void NotifyNavigationStart();
   void NotifyFetchStart(nsIURI* aURI, nsDOMPerformanceNavigationType aNavigationType);
   void NotifyRedirect(nsIURI* aOldURI, nsIURI* aNewURI);
   void NotifyBeforeUnload();
   void NotifyUnloadAccepted(nsIURI* aOldURI);
   void NotifyUnloadEventStart();
   void NotifyUnloadEventEnd();
@@ -73,16 +86,17 @@ public:
 
   // Document changes state to 'loading' before connecting to timing
   void SetDOMLoadingTimeStamp(nsIURI* aURI, mozilla::TimeStamp aValue);
   void NotifyDOMLoading(nsIURI* aURI);
   void NotifyDOMInteractive(nsIURI* aURI);
   void NotifyDOMComplete(nsIURI* aURI);
   void NotifyDOMContentLoadedStart(nsIURI* aURI);
   void NotifyDOMContentLoadedEnd(nsIURI* aURI);
+  nsresult TimeStampToDOM(mozilla::TimeStamp aStamp, DOMTimeMilliSec* aResult);
 
 private:
   nsDOMNavigationTiming(const nsDOMNavigationTiming &){};
   ~nsDOMNavigationTiming();
 
   void Clear();
   PRBool ReportRedirects();
 
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -184,16 +184,17 @@
 #include "nsCDefaultURIFixup.h"
 #include "nsEventDispatcher.h"
 #include "nsIObserverService.h"
 #include "nsIXULAppInfo.h"
 #include "nsNetUtil.h"
 #include "nsFocusManager.h"
 #include "nsIXULWindow.h"
 #include "nsEventStateManager.h"
+#include "nsITimedChannel.h"
 #ifdef MOZ_XUL
 #include "nsXULPopupManager.h"
 #include "nsIDOMXULControlElement.h"
 #include "nsMenuPopupFrame.h"
 #endif
 
 #include "xpcprivate.h"
 
@@ -2997,18 +2998,25 @@ nsGlobalWindow::GetPerformance(nsIDOMPer
   *aPerformance = nsnull;
 
   if (nsGlobalWindow::HasPerformanceSupport()) {
     if (!mPerformance) {
       if (!mDoc) {
         return NS_OK;
       }
       nsRefPtr<nsDOMNavigationTiming> timing = mDoc->GetNavigationTiming();
+      nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(mDoc->GetChannel()));
+      PRBool timingEnabled = PR_FALSE;
+      if (!timedChannel ||
+          !NS_SUCCEEDED(timedChannel->GetTimingEnabled(&timingEnabled)) ||
+          !timingEnabled) {
+        timedChannel = nsnull;
+      }
       if (timing) {
-        mPerformance = new nsPerformance(timing);
+        mPerformance = new nsPerformance(timing, timedChannel);
       }
     }
     NS_IF_ADDREF(*aPerformance = mPerformance);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/dom/base/nsPerformance.cpp
+++ b/dom/base/nsPerformance.cpp
@@ -33,168 +33,211 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsPerformance.h"
+#include "TimeStamp.h"
 #include "nsCOMPtr.h"
 #include "nscore.h"
 #include "nsIDocShell.h"
+#include "nsITimedChannel.h"
 #include "nsDOMClassInfo.h"
 #include "nsDOMNavigationTiming.h"
 
 DOMCI_DATA(PerformanceTiming, nsPerformanceTiming)
 
 NS_IMPL_ADDREF(nsPerformanceTiming)
 NS_IMPL_RELEASE(nsPerformanceTiming)
 
 // QueryInterface implementation for nsPerformanceTiming
 NS_INTERFACE_MAP_BEGIN(nsPerformanceTiming)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMPerformanceTiming)
   NS_INTERFACE_MAP_ENTRY(nsIDOMPerformanceTiming)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(PerformanceTiming)
 NS_INTERFACE_MAP_END
 
-nsPerformanceTiming::nsPerformanceTiming(nsDOMNavigationTiming* aData)
+nsPerformanceTiming::nsPerformanceTiming(nsDOMNavigationTiming* aDOMTiming, 
+                                         nsITimedChannel* aChannel)
 {
-  NS_ASSERTION(aData, "Timing data should be provided");
-  mData = aData;
+  NS_ASSERTION(aDOMTiming, "DOM timing data should be provided");
+  mDOMTiming = aDOMTiming;
+  mChannel = aChannel;  
 }
 
 nsPerformanceTiming::~nsPerformanceTiming()
 {
 }
 
 NS_IMETHODIMP
 nsPerformanceTiming::GetNavigationStart(DOMTimeMilliSec* aTime)
 {
-  return mData->GetNavigationStart(aTime);
+  return mDOMTiming->GetNavigationStart(aTime);
 }
 
 NS_IMETHODIMP
 nsPerformanceTiming::GetUnloadEventStart(DOMTimeMilliSec* aTime)
 {
-  return mData->GetUnloadEventStart(aTime);
+  return mDOMTiming->GetUnloadEventStart(aTime);
 }
 
 NS_IMETHODIMP
 nsPerformanceTiming::GetUnloadEventEnd(DOMTimeMilliSec* aTime)
 {
-  return mData->GetUnloadEventEnd(aTime);
+  return mDOMTiming->GetUnloadEventEnd(aTime);
 }
 
 NS_IMETHODIMP
 nsPerformanceTiming::GetRedirectStart(DOMTimeMilliSec* aTime)
 {
-  return mData->GetRedirectStart(aTime);
+  return mDOMTiming->GetRedirectStart(aTime);
 }
 
 NS_IMETHODIMP
 nsPerformanceTiming::GetRedirectEnd(DOMTimeMilliSec* aTime)
 {
-  return mData->GetRedirectEnd(aTime);
+  return mDOMTiming->GetRedirectEnd(aTime);
 }
 
 NS_IMETHODIMP
 nsPerformanceTiming::GetFetchStart(DOMTimeMilliSec* aTime)
 {
-  return mData->GetFetchStart(aTime);
+  return mDOMTiming->GetFetchStart(aTime);
 }
 
 NS_IMETHODIMP
 nsPerformanceTiming::GetDomainLookupStart(DOMTimeMilliSec* aTime)
 {
-  return mData->GetDomainLookupStart(aTime);
+  if (!mChannel) {
+    return GetFetchStart(aTime);
+  }
+  mozilla::TimeStamp stamp;
+  mChannel->GetDomainLookupStart(&stamp);
+  return mDOMTiming->TimeStampToDOM(stamp, aTime);
 }
 
 NS_IMETHODIMP
 nsPerformanceTiming::GetDomainLookupEnd(DOMTimeMilliSec* aTime)
 {
-  return mData->GetDomainLookupEnd(aTime);
+  if (!mChannel) {
+    return GetFetchStart(aTime);
+  }
+  mozilla::TimeStamp stamp;
+  mChannel->GetDomainLookupEnd(&stamp);
+  return mDOMTiming->TimeStampToDOM(stamp, aTime);
 }
 
 NS_IMETHODIMP
 nsPerformanceTiming::GetConnectStart(DOMTimeMilliSec* aTime)
 {
-  return mData->GetConnectStart(aTime);
+  if (!mChannel) {
+    return GetFetchStart(aTime);
+  }
+  mozilla::TimeStamp stamp;
+  mChannel->GetConnectStart(&stamp);
+  return mDOMTiming->TimeStampToDOM(stamp, aTime);
 }
 
 NS_IMETHODIMP
 nsPerformanceTiming::GetConnectEnd(DOMTimeMilliSec* aTime)
 {
-  return mData->GetConnectEnd(aTime);
-}
-
-NS_IMETHODIMP
-nsPerformanceTiming::GetHandshakeStart(DOMTimeMilliSec* aTime)
-{
-  return mData->GetHandshakeStart(aTime);
+  if (!mChannel) {
+    return GetFetchStart(aTime);
+  }
+  mozilla::TimeStamp stamp;
+  mChannel->GetConnectEnd(&stamp);
+  return mDOMTiming->TimeStampToDOM(stamp, aTime);
 }
 
 NS_IMETHODIMP
 nsPerformanceTiming::GetRequestStart(DOMTimeMilliSec* aTime)
 {
-  return mData->GetRequestStart(aTime);
+  if (!mChannel) {
+    return GetFetchStart(aTime);
+  }
+  mozilla::TimeStamp stamp;
+  mChannel->GetRequestStart(&stamp);
+  return mDOMTiming->TimeStampToDOM(stamp, aTime);
 }
 
 NS_IMETHODIMP
 nsPerformanceTiming::GetResponseStart(DOMTimeMilliSec* aTime)
 {
-  return mData->GetResponseStart(aTime);
+  if (!mChannel) {
+    return GetFetchStart(aTime);
+  }
+  mozilla::TimeStamp stamp;
+  mChannel->GetResponseStart(&stamp);
+  mozilla::TimeStamp cacheStamp;
+  mChannel->GetCacheReadStart(&cacheStamp);
+  if (stamp.IsNull() || (!cacheStamp.IsNull() && cacheStamp < stamp)) {
+    stamp = cacheStamp;
+  }
+  return mDOMTiming->TimeStampToDOM(stamp, aTime);
 }
 
 NS_IMETHODIMP
 nsPerformanceTiming::GetResponseEnd(DOMTimeMilliSec* aTime)
 {
-  return mData->GetResponseEnd(aTime);
+  if (!mChannel) {
+    return GetFetchStart(aTime);
+  }
+  mozilla::TimeStamp stamp;
+  mChannel->GetResponseEnd(&stamp);
+  mozilla::TimeStamp cacheStamp;
+  mChannel->GetCacheReadEnd(&cacheStamp);
+  if (stamp.IsNull() || (!cacheStamp.IsNull() && cacheStamp < stamp)) {
+    stamp = cacheStamp;
+  }
+  return mDOMTiming->TimeStampToDOM(stamp, aTime);
 }
 
 NS_IMETHODIMP
 nsPerformanceTiming::GetDomLoading(DOMTimeMilliSec* aTime)
 {
-  return mData->GetDomLoading(aTime);
+  return mDOMTiming->GetDomLoading(aTime);
 }
 
 NS_IMETHODIMP
 nsPerformanceTiming::GetDomInteractive(DOMTimeMilliSec* aTime)
 {
-  return mData->GetDomInteractive(aTime);
+  return mDOMTiming->GetDomInteractive(aTime);
 }
 
 NS_IMETHODIMP
 nsPerformanceTiming::GetDomContentLoadedEventStart(DOMTimeMilliSec* aTime)
 {
-  return mData->GetDomContentLoadedEventStart(aTime);
+  return mDOMTiming->GetDomContentLoadedEventStart(aTime);
 }
 
 NS_IMETHODIMP
 nsPerformanceTiming::GetDomContentLoadedEventEnd(DOMTimeMilliSec* aTime)
 {
-  return mData->GetDomContentLoadedEventEnd(aTime);
+  return mDOMTiming->GetDomContentLoadedEventEnd(aTime);
 }
 
 NS_IMETHODIMP
 nsPerformanceTiming::GetDomComplete(DOMTimeMilliSec* aTime)
 {
-  return mData->GetDomComplete(aTime);
+  return mDOMTiming->GetDomComplete(aTime);
 }
 
 NS_IMETHODIMP
 nsPerformanceTiming::GetLoadEventStart(DOMTimeMilliSec* aTime)
 {
-  return mData->GetLoadEventStart(aTime);
+  return mDOMTiming->GetLoadEventStart(aTime);
 }
 
 NS_IMETHODIMP
 nsPerformanceTiming::GetLoadEventEnd(DOMTimeMilliSec* aTime)
 {
-  return mData->GetLoadEventEnd(aTime);
+  return mDOMTiming->GetLoadEventEnd(aTime);
 }
 
 
 
 DOMCI_DATA(PerformanceNavigation, nsPerformanceNavigation)
 
 NS_IMPL_ADDREF(nsPerformanceNavigation)
 NS_IMPL_RELEASE(nsPerformanceNavigation)
@@ -230,20 +273,22 @@ nsPerformanceNavigation::GetRedirectCoun
 }
 
 
 DOMCI_DATA(Performance, nsPerformance)
 
 NS_IMPL_ADDREF(nsPerformance)
 NS_IMPL_RELEASE(nsPerformance)
 
-nsPerformance::nsPerformance(nsDOMNavigationTiming* aTiming)
+nsPerformance::nsPerformance(nsDOMNavigationTiming* aDOMTiming, 
+                             nsITimedChannel* aChannel)
 {
-  NS_ASSERTION(aTiming, "Timing data should be provided");
-  mData = aTiming;
+  NS_ASSERTION(aDOMTiming, "DOM timing data should be provided");
+  mDOMTiming = aDOMTiming;
+  mChannel = aChannel;  
 }
 
 nsPerformance::~nsPerformance()
 {
 }
 
 // QueryInterface implementation for nsPerformance
 NS_INTERFACE_MAP_BEGIN(nsPerformance)
@@ -254,23 +299,23 @@ NS_INTERFACE_MAP_END
 
 //
 // nsIDOMPerformance methods
 //
 NS_IMETHODIMP
 nsPerformance::GetTiming(nsIDOMPerformanceTiming** aTiming)
 {
   if (!mTiming) {
-    mTiming = new nsPerformanceTiming(mData);
+    mTiming = new nsPerformanceTiming(mDOMTiming, mChannel);
   }
   NS_IF_ADDREF(*aTiming = mTiming);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsPerformance::GetNavigation(nsIDOMPerformanceNavigation** aNavigation)
 {
   if (!mNavigation) {
-    mNavigation = new nsPerformanceNavigation(mData);
+    mNavigation = new nsPerformanceNavigation(mDOMTiming);
   }
   NS_IF_ADDREF(*aNavigation = mNavigation);
   return NS_OK;
 }
--- a/dom/base/nsPerformance.h
+++ b/dom/base/nsPerformance.h
@@ -44,27 +44,29 @@
 #include "nsIDOMPerformanceNavigation.h"
 #include "nscore.h"
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 
 class nsIDocument;
 class nsIURI;
 class nsDOMNavigationTiming;
+class nsITimedChannel;
 
 // Script "performance.timing" object
 class nsPerformanceTiming : public nsIDOMPerformanceTiming
 {
 public:
-  nsPerformanceTiming(nsDOMNavigationTiming* data);
+  nsPerformanceTiming(nsDOMNavigationTiming* aDOMTiming, nsITimedChannel* aChannel);
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMPERFORMANCETIMING
 private:
   ~nsPerformanceTiming();
-  nsRefPtr<nsDOMNavigationTiming> mData;
+  nsRefPtr<nsDOMNavigationTiming> mDOMTiming;
+  nsCOMPtr<nsITimedChannel> mChannel;
 };
 
 // Script "performance.navigation" object
 class nsPerformanceNavigation : public nsIDOMPerformanceNavigation
 {
 public:
   nsPerformanceNavigation(nsDOMNavigationTiming* data);
   NS_DECL_ISUPPORTS
@@ -73,23 +75,24 @@ private:
   ~nsPerformanceNavigation();
   nsRefPtr<nsDOMNavigationTiming> mData;
 };
 
 // Script "performance" object
 class nsPerformance : public nsIDOMPerformance
 {
 public:
-  nsPerformance(nsDOMNavigationTiming* timing);
+  nsPerformance(nsDOMNavigationTiming* aDOMTiming, nsITimedChannel* aChannel);
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMPERFORMANCE
 
 private:
   ~nsPerformance();
 
-  nsRefPtr<nsDOMNavigationTiming> mData;
+  nsRefPtr<nsDOMNavigationTiming> mDOMTiming;
+  nsCOMPtr<nsITimedChannel> mChannel;
   nsCOMPtr<nsIDOMPerformanceTiming> mTiming;
   nsCOMPtr<nsIDOMPerformanceNavigation> mNavigation;
 };
 
 #endif /* nsPerformance_h___ */
 
--- a/dom/interfaces/base/nsIDOMPerformanceTiming.idl
+++ b/dom/interfaces/base/nsIDOMPerformanceTiming.idl
@@ -34,30 +34,29 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "domstubs.idl"
 
-[scriptable, uuid(2a630b50-61b6-41b3-996d-70be67fbbcb0)]
+[scriptable, uuid(8e09c825-da49-4a39-876b-ce2ff767dbe1)]
 interface nsIDOMPerformanceTiming : nsISupports
 {
   readonly attribute DOMTimeMilliSec navigationStart;
   readonly attribute DOMTimeMilliSec unloadEventStart;
   readonly attribute DOMTimeMilliSec unloadEventEnd;
   readonly attribute DOMTimeMilliSec redirectStart;
   readonly attribute DOMTimeMilliSec redirectEnd;
   readonly attribute DOMTimeMilliSec fetchStart;
   readonly attribute DOMTimeMilliSec domainLookupStart;
   readonly attribute DOMTimeMilliSec domainLookupEnd;
   readonly attribute DOMTimeMilliSec connectStart;
   readonly attribute DOMTimeMilliSec connectEnd;
-  readonly attribute DOMTimeMilliSec handshakeStart;
   readonly attribute DOMTimeMilliSec requestStart;
   readonly attribute DOMTimeMilliSec responseStart;
   readonly attribute DOMTimeMilliSec responseEnd;
   readonly attribute DOMTimeMilliSec domLoading;
   readonly attribute DOMTimeMilliSec domInteractive;
   readonly attribute DOMTimeMilliSec domContentLoadedEventStart;
   readonly attribute DOMTimeMilliSec domContentLoadedEventEnd;
   readonly attribute DOMTimeMilliSec domComplete;