/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsDOMNavigationTiming.h" #include "GeckoProfiler.h" #include "nsCOMPtr.h" #include "nsContentUtils.h" #include "nsIScriptSecurityManager.h" #include "prtime.h" #include "nsIURI.h" #include "nsPrintfCString.h" #include "mozilla/dom/PerformanceNavigation.h" #include "mozilla/TimeStamp.h" #include "mozilla/Telemetry.h" using namespace mozilla; nsDOMNavigationTiming::nsDOMNavigationTiming() { Clear(); } nsDOMNavigationTiming::~nsDOMNavigationTiming() { } void nsDOMNavigationTiming::Clear() { mNavigationType = TYPE_RESERVED; mNavigationStartHighRes = 0; mBeforeUnloadStart = TimeStamp(); mUnloadStart = TimeStamp(); mUnloadEnd = TimeStamp(); mLoadEventStart = TimeStamp(); mLoadEventEnd = TimeStamp(); mDOMLoading = TimeStamp(); mDOMInteractive = TimeStamp(); mDOMContentLoadedEventStart = TimeStamp(); mDOMContentLoadedEventEnd = TimeStamp(); mDOMComplete = TimeStamp(); mDocShellHasBeenActiveSinceNavigationStart = false; } DOMTimeMilliSec nsDOMNavigationTiming::TimeStampToDOM(TimeStamp aStamp) const { if (aStamp.IsNull()) { return 0; } TimeDuration duration = aStamp - mNavigationStart; return GetNavigationStart() + static_cast<int64_t>(duration.ToMilliseconds()); } void nsDOMNavigationTiming::NotifyNavigationStart(DocShellState aDocShellState) { mNavigationStartHighRes = (double)PR_Now() / PR_USEC_PER_MSEC; mNavigationStart = TimeStamp::Now(); mDocShellHasBeenActiveSinceNavigationStart = (aDocShellState == DocShellState::eActive); } void nsDOMNavigationTiming::NotifyFetchStart(nsIURI* aURI, Type aNavigationType) { 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::NotifyBeforeUnload() { mBeforeUnloadStart = TimeStamp::Now(); } void nsDOMNavigationTiming::NotifyUnloadAccepted(nsIURI* aOldURI) { mUnloadStart = mBeforeUnloadStart; mUnloadedURI = aOldURI; } void nsDOMNavigationTiming::NotifyUnloadEventStart() { mUnloadStart = TimeStamp::Now(); } void nsDOMNavigationTiming::NotifyUnloadEventEnd() { mUnloadEnd = TimeStamp::Now(); } void nsDOMNavigationTiming::NotifyLoadEventStart() { if (!mLoadEventStart.IsNull()) { return; } mLoadEventStart = TimeStamp::Now(); } void nsDOMNavigationTiming::NotifyLoadEventEnd() { if (!mLoadEventEnd.IsNull()) { return; } mLoadEventEnd = TimeStamp::Now(); } void nsDOMNavigationTiming::SetDOMLoadingTimeStamp(nsIURI* aURI, TimeStamp aValue) { if (!mDOMLoading.IsNull()) { return; } mLoadedURI = aURI; mDOMLoading = aValue; } void nsDOMNavigationTiming::NotifyDOMLoading(nsIURI* aURI) { if (!mDOMLoading.IsNull()) { return; } mLoadedURI = aURI; mDOMLoading = TimeStamp::Now(); } void nsDOMNavigationTiming::NotifyDOMInteractive(nsIURI* aURI) { if (!mDOMInteractive.IsNull()) { return; } mLoadedURI = aURI; mDOMInteractive = TimeStamp::Now(); } void nsDOMNavigationTiming::NotifyDOMComplete(nsIURI* aURI) { if (!mDOMComplete.IsNull()) { return; } mLoadedURI = aURI; mDOMComplete = TimeStamp::Now(); } void nsDOMNavigationTiming::NotifyDOMContentLoadedStart(nsIURI* aURI) { if (!mDOMContentLoadedEventStart.IsNull()) { return; } mLoadedURI = aURI; mDOMContentLoadedEventStart = TimeStamp::Now(); } void nsDOMNavigationTiming::NotifyDOMContentLoadedEnd(nsIURI* aURI) { if (!mDOMContentLoadedEventEnd.IsNull()) { return; } mLoadedURI = aURI; mDOMContentLoadedEventEnd = TimeStamp::Now(); } void nsDOMNavigationTiming::NotifyNonBlankPaintForRootContentDocument() { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(!mNavigationStart.IsNull()); if (!mNonBlankPaint.IsNull()) { return; } mNonBlankPaint = TimeStamp::Now(); TimeDuration elapsed = mNonBlankPaint - mNavigationStart; if (profiler_is_active()) { nsAutoCString spec; if (mLoadedURI) { mLoadedURI->GetSpec(spec); } nsPrintfCString marker("Non-blank paint after %dms for URL %s, %s", int(elapsed.ToMilliseconds()), spec.get(), mDocShellHasBeenActiveSinceNavigationStart ? "foreground tab" : "this tab was inactive some of the time between navigation start and first non-blank paint"); PROFILER_MARKER(marker.get()); } if (mDocShellHasBeenActiveSinceNavigationStart) { Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_NON_BLANK_PAINT_MS, mNavigationStart, mNonBlankPaint); } } void nsDOMNavigationTiming::NotifyDocShellStateChanged(DocShellState aDocShellState) { mDocShellHasBeenActiveSinceNavigationStart &= (aDocShellState == DocShellState::eActive); } mozilla::TimeStamp nsDOMNavigationTiming::GetUnloadEventStartTimeStamp() const { nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); nsresult rv = ssm->CheckSameOriginURI(mLoadedURI, mUnloadedURI, false); if (NS_SUCCEEDED(rv)) { return mUnloadStart; } return mozilla::TimeStamp(); } mozilla::TimeStamp nsDOMNavigationTiming::GetUnloadEventEndTimeStamp() const { nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); nsresult rv = ssm->CheckSameOriginURI(mLoadedURI, mUnloadedURI, false); if (NS_SUCCEEDED(rv)) { return mUnloadEnd; } return mozilla::TimeStamp(); }