diff options
Diffstat (limited to 'dom/base/nsDOMNavigationTiming.cpp')
-rw-r--r-- | dom/base/nsDOMNavigationTiming.cpp | 698 |
1 files changed, 698 insertions, 0 deletions
diff --git a/dom/base/nsDOMNavigationTiming.cpp b/dom/base/nsDOMNavigationTiming.cpp new file mode 100644 index 0000000000..ec70d2b1ac --- /dev/null +++ b/dom/base/nsDOMNavigationTiming.cpp @@ -0,0 +1,698 @@ +/* -*- 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 "ipc/IPCMessageUtilsSpecializations.h" +#include "mozilla/ProfilerMarkers.h" +#include "mozilla/Telemetry.h" +#include "mozilla/TimeStamp.h" +#include "mozilla/dom/Document.h" +#include "mozilla/dom/PerformanceNavigation.h" +#include "mozilla/ipc/IPDLParamTraits.h" +#include "mozilla/ipc/URIUtils.h" +#include "nsCOMPtr.h" +#include "nsContentUtils.h" +#include "nsDocShell.h" +#include "nsHttp.h" +#include "nsIScriptSecurityManager.h" +#include "nsIURI.h" +#include "nsPrintfCString.h" +#include "prtime.h" + +using namespace mozilla; + +namespace mozilla { + +LazyLogModule gPageLoadLog("PageLoad"); +#define PAGELOAD_LOG(args) MOZ_LOG(gPageLoadLog, LogLevel::Debug, args) +#define PAGELOAD_LOG_ENABLED() MOZ_LOG_TEST(gPageLoadLog, LogLevel::Error) + +} // namespace mozilla + +nsDOMNavigationTiming::nsDOMNavigationTiming(nsDocShell* aDocShell) { + Clear(); + + mDocShell = aDocShell; +} + +nsDOMNavigationTiming::~nsDOMNavigationTiming() = default; + +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(); + mContentfulComposite = TimeStamp(); + mLargestContentfulRender = TimeStamp(); + mNonBlankPaint = TimeStamp(); + + mDocShellHasBeenActiveSinceNavigationStart = false; +} + +void nsDOMNavigationTiming::Anonymize(nsIURI* aFinalURI) { + mLoadedURI = aFinalURI; + mUnloadedURI = nullptr; + mBeforeUnloadStart = TimeStamp(); + mUnloadStart = TimeStamp(); + mUnloadEnd = TimeStamp(); +} + +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); + PROFILER_MARKER_UNTYPED("Navigation::Start", DOM, + MarkerInnerWindowIdFromDocShell(mDocShell)); +} + +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::NotifyRestoreStart() { + mNavigationType = TYPE_BACK_FORWARD; +} + +void nsDOMNavigationTiming::NotifyBeforeUnload() { + mBeforeUnloadStart = TimeStamp::Now(); +} + +void nsDOMNavigationTiming::NotifyUnloadAccepted(nsIURI* aOldURI) { + mUnloadStart = mBeforeUnloadStart; + mUnloadedURI = aOldURI; +} + +void nsDOMNavigationTiming::NotifyUnloadEventStart() { + mUnloadStart = TimeStamp::Now(); + PROFILER_MARKER("Unload", NETWORK, + MarkerOptions(MarkerTiming::IntervalStart(), + MarkerInnerWindowIdFromDocShell(mDocShell)), + Tracing, "Navigation"); +} + +void nsDOMNavigationTiming::NotifyUnloadEventEnd() { + mUnloadEnd = TimeStamp::Now(); + PROFILER_MARKER("Unload", NETWORK, + MarkerOptions(MarkerTiming::IntervalEnd(), + MarkerInnerWindowIdFromDocShell(mDocShell)), + Tracing, "Navigation"); +} + +void nsDOMNavigationTiming::NotifyLoadEventStart() { + if (!mLoadEventStart.IsNull()) { + return; + } + mLoadEventStart = TimeStamp::Now(); + + PROFILER_MARKER("Load", NETWORK, + MarkerOptions(MarkerTiming::IntervalStart(), + MarkerInnerWindowIdFromDocShell(mDocShell)), + Tracing, "Navigation"); + + if (IsTopLevelContentDocumentInContentProcess()) { + TimeStamp now = TimeStamp::Now(); + + glean::performance_time::load_event_start.AccumulateRawDuration( + now - mNavigationStart); + + if (mDocShellHasBeenActiveSinceNavigationStart) { + if (net::nsHttp::IsBeforeLastActiveTabLoadOptimization( + mNavigationStart)) { + Telemetry::AccumulateTimeDelta( + Telemetry::TIME_TO_LOAD_EVENT_START_ACTIVE_NETOPT_MS, + mNavigationStart, now); + } else { + Telemetry::AccumulateTimeDelta( + Telemetry::TIME_TO_LOAD_EVENT_START_ACTIVE_MS, mNavigationStart, + now); + } + } + } +} + +void nsDOMNavigationTiming::NotifyLoadEventEnd() { + if (!mLoadEventEnd.IsNull()) { + return; + } + mLoadEventEnd = TimeStamp::Now(); + + PROFILER_MARKER("Load", NETWORK, + MarkerOptions(MarkerTiming::IntervalEnd(), + MarkerInnerWindowIdFromDocShell(mDocShell)), + Tracing, "Navigation"); + + if (IsTopLevelContentDocumentInContentProcess()) { + if (profiler_thread_is_being_profiled_for_markers() || + PAGELOAD_LOG_ENABLED()) { + TimeDuration elapsed = mLoadEventEnd - mNavigationStart; + TimeDuration duration = mLoadEventEnd - mLoadEventStart; + nsPrintfCString marker( + "Document %s loaded after %dms, load event duration %dms", + nsContentUtils::TruncatedURLForDisplay(mLoadedURI).get(), + int(elapsed.ToMilliseconds()), int(duration.ToMilliseconds())); + PAGELOAD_LOG(("%s", marker.get())); + PROFILER_MARKER_TEXT( + "DocumentLoad", DOM, + MarkerOptions(MarkerTiming::Interval(mNavigationStart, mLoadEventEnd), + MarkerInnerWindowIdFromDocShell(mDocShell)), + marker); + } + glean::performance_time::load_event_end.AccumulateRawDuration( + TimeStamp::Now() - mNavigationStart); + } +} + +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(); + + PROFILER_MARKER_UNTYPED("Navigation::DOMLoading", DOM, + MarkerInnerWindowIdFromDocShell(mDocShell)); +} + +void nsDOMNavigationTiming::NotifyDOMInteractive(nsIURI* aURI) { + if (!mDOMInteractive.IsNull()) { + return; + } + mLoadedURI = aURI; + mDOMInteractive = TimeStamp::Now(); + + PROFILER_MARKER_UNTYPED("Navigation::DOMInteractive", DOM, + MarkerInnerWindowIdFromDocShell(mDocShell)); +} + +void nsDOMNavigationTiming::NotifyDOMComplete(nsIURI* aURI) { + if (!mDOMComplete.IsNull()) { + return; + } + mLoadedURI = aURI; + mDOMComplete = TimeStamp::Now(); + + PROFILER_MARKER_UNTYPED("Navigation::DOMComplete", DOM, + MarkerInnerWindowIdFromDocShell(mDocShell)); +} + +void nsDOMNavigationTiming::NotifyDOMContentLoadedStart(nsIURI* aURI) { + if (!mDOMContentLoadedEventStart.IsNull()) { + return; + } + + mLoadedURI = aURI; + mDOMContentLoadedEventStart = TimeStamp::Now(); + + PROFILER_MARKER("DOMContentLoaded", NETWORK, + MarkerOptions(MarkerTiming::IntervalStart(), + MarkerInnerWindowIdFromDocShell(mDocShell)), + Tracing, "Navigation"); + + if (IsTopLevelContentDocumentInContentProcess()) { + TimeStamp now = TimeStamp::Now(); + + glean::performance_time::dom_content_loaded_start.AccumulateRawDuration( + now - mNavigationStart); + + if (mDocShellHasBeenActiveSinceNavigationStart) { + if (net::nsHttp::IsBeforeLastActiveTabLoadOptimization( + mNavigationStart)) { + Telemetry::AccumulateTimeDelta( + Telemetry::TIME_TO_DOM_CONTENT_LOADED_START_ACTIVE_NETOPT_MS, + mNavigationStart, now); + } else { + Telemetry::AccumulateTimeDelta( + Telemetry::TIME_TO_DOM_CONTENT_LOADED_START_ACTIVE_MS, + mNavigationStart, now); + } + } + } +} + +void nsDOMNavigationTiming::NotifyDOMContentLoadedEnd(nsIURI* aURI) { + if (!mDOMContentLoadedEventEnd.IsNull()) { + return; + } + + mLoadedURI = aURI; + mDOMContentLoadedEventEnd = TimeStamp::Now(); + + PROFILER_MARKER("DOMContentLoaded", NETWORK, + MarkerOptions(MarkerTiming::IntervalEnd(), + MarkerInnerWindowIdFromDocShell(mDocShell)), + Tracing, "Navigation"); + + if (IsTopLevelContentDocumentInContentProcess()) { + glean::performance_time::dom_content_loaded_end.AccumulateRawDuration( + TimeStamp::Now() - mNavigationStart); + } +} + +// static +void nsDOMNavigationTiming::TTITimeoutCallback(nsITimer* aTimer, + void* aClosure) { + nsDOMNavigationTiming* self = static_cast<nsDOMNavigationTiming*>(aClosure); + self->TTITimeout(aTimer); +} + +#define TTI_WINDOW_SIZE_MS (5 * 1000) + +void nsDOMNavigationTiming::TTITimeout(nsITimer* aTimer) { + // Check TTI: see if it's been 5 seconds since the last Long Task + TimeStamp now = TimeStamp::Now(); + MOZ_RELEASE_ASSERT(!mContentfulComposite.IsNull(), + "TTI timeout with no contentful-composite?"); + + nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); + TimeStamp lastLongTaskEnded; + mainThread->GetLastLongNonIdleTaskEnd(&lastLongTaskEnded); + // Window starts at mContentfulComposite; any long task before that is ignored + if (lastLongTaskEnded.IsNull() || lastLongTaskEnded < mContentfulComposite) { + PAGELOAD_LOG( + ("no longtask (last was %g ms before ContentfulComposite)", + lastLongTaskEnded.IsNull() + ? 0 + : (mContentfulComposite - lastLongTaskEnded).ToMilliseconds())); + lastLongTaskEnded = mContentfulComposite; + } + TimeDuration delta = now - lastLongTaskEnded; + PAGELOAD_LOG(("TTI delta: %g ms", delta.ToMilliseconds())); + if (delta.ToMilliseconds() < TTI_WINDOW_SIZE_MS) { + // Less than 5 seconds since the last long task or start of the window. + // Schedule another check. + PAGELOAD_LOG(("TTI: waiting additional %g ms", + (TTI_WINDOW_SIZE_MS + 100) - delta.ToMilliseconds())); + aTimer->InitWithNamedFuncCallback( + TTITimeoutCallback, this, + (TTI_WINDOW_SIZE_MS + 100) - + delta.ToMilliseconds(), // slightly after the window ends + nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY, + "nsDOMNavigationTiming::TTITimeout"); + return; + } + + // To correctly implement TTI/TTFI as proposed, we'd need to not + // fire it until there are no more than 2 network loads. By the + // proposed definition, without that we're closer to + // TimeToFirstInteractive. There are also arguments about what sort + // of loads should qualify. + + // XXX check number of network loads, and if > 2 mark to check if loads + // decreases to 2 (or record that point and let the normal timer here + // handle it) + + // TTI has occurred! TTI is either FCP (if there are no longtasks and no + // DCLEnd in the window that starts at FCP), or at the end of the last + // Long Task or DOMContentLoadedEnd (whichever is later). lastLongTaskEnded + // is >= FCP here. + + if (mTTFI.IsNull()) { + // lastLongTaskEnded is >= mContentfulComposite + mTTFI = (mDOMContentLoadedEventEnd.IsNull() || + lastLongTaskEnded > mDOMContentLoadedEventEnd) + ? lastLongTaskEnded + : mDOMContentLoadedEventEnd; + PAGELOAD_LOG( + ("TTFI after %dms (LongTask was at %dms, DCL was %dms)", + int((mTTFI - mNavigationStart).ToMilliseconds()), + lastLongTaskEnded.IsNull() + ? 0 + : int((lastLongTaskEnded - mNavigationStart).ToMilliseconds()), + mDOMContentLoadedEventEnd.IsNull() + ? 0 + : int((mDOMContentLoadedEventEnd - mNavigationStart) + .ToMilliseconds()))); + } + // XXX Implement TTI via check number of network loads, and if > 2 mark + // to check if loads decreases to 2 (or record that point and let the + // normal timer here handle it) + + mTTITimer = nullptr; + + if (profiler_thread_is_being_profiled_for_markers() || + PAGELOAD_LOG_ENABLED()) { + TimeDuration elapsed = mTTFI - mNavigationStart; + MOZ_ASSERT(elapsed.ToMilliseconds() > 0); + TimeDuration elapsedLongTask = + lastLongTaskEnded.IsNull() ? 0 : lastLongTaskEnded - mNavigationStart; + nsPrintfCString marker( + "TTFI after %dms (LongTask was at %dms) for URL %s", + int(elapsed.ToMilliseconds()), int(elapsedLongTask.ToMilliseconds()), + nsContentUtils::TruncatedURLForDisplay(mLoadedURI).get()); + + PROFILER_MARKER_TEXT( + "TimeToFirstInteractive (TTFI)", DOM, + MarkerOptions(MarkerTiming::Interval(mNavigationStart, mTTFI), + MarkerInnerWindowIdFromDocShell(mDocShell)), + marker); + } +} + +void nsDOMNavigationTiming::NotifyNonBlankPaintForRootContentDocument() { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!mNavigationStart.IsNull()); + + if (!mNonBlankPaint.IsNull()) { + return; + } + + mNonBlankPaint = TimeStamp::Now(); + + if (profiler_thread_is_being_profiled_for_markers() || + PAGELOAD_LOG_ENABLED()) { + TimeDuration elapsed = mNonBlankPaint - mNavigationStart; + nsPrintfCString marker( + "Non-blank paint after %dms for URL %s, %s", + int(elapsed.ToMilliseconds()), + nsContentUtils::TruncatedURLForDisplay(mLoadedURI).get(), + mDocShellHasBeenActiveSinceNavigationStart + ? "foreground tab" + : "this tab was inactive some of the time between navigation start " + "and first non-blank paint"); + PAGELOAD_LOG(("%s", marker.get())); + PROFILER_MARKER_TEXT( + "FirstNonBlankPaint", DOM, + MarkerOptions(MarkerTiming::Interval(mNavigationStart, mNonBlankPaint), + MarkerInnerWindowIdFromDocShell(mDocShell)), + marker); + } + + if (mDocShellHasBeenActiveSinceNavigationStart) { + if (net::nsHttp::IsBeforeLastActiveTabLoadOptimization(mNavigationStart)) { + Telemetry::AccumulateTimeDelta( + Telemetry::TIME_TO_NON_BLANK_PAINT_NETOPT_MS, mNavigationStart, + mNonBlankPaint); + } else { + Telemetry::AccumulateTimeDelta( + Telemetry::TIME_TO_NON_BLANK_PAINT_NO_NETOPT_MS, mNavigationStart, + mNonBlankPaint); + } + + glean::performance_page::non_blank_paint.AccumulateRawDuration( + mNonBlankPaint - mNavigationStart); + } +} + +void nsDOMNavigationTiming::NotifyContentfulCompositeForRootContentDocument( + const mozilla::TimeStamp& aCompositeEndTime) { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!mNavigationStart.IsNull()); + + if (!mContentfulComposite.IsNull()) { + return; + } + + mContentfulComposite = aCompositeEndTime; + + if (profiler_thread_is_being_profiled_for_markers() || + PAGELOAD_LOG_ENABLED()) { + TimeDuration elapsed = mContentfulComposite - mNavigationStart; + nsPrintfCString marker( + "Contentful composite after %dms for URL %s, %s", + int(elapsed.ToMilliseconds()), + nsContentUtils::TruncatedURLForDisplay(mLoadedURI).get(), + mDocShellHasBeenActiveSinceNavigationStart + ? "foreground tab" + : "this tab was inactive some of the time between navigation start " + "and first non-blank paint"); + PAGELOAD_LOG(("%s", marker.get())); + PROFILER_MARKER_TEXT( + "FirstContentfulComposite", DOM, + MarkerOptions( + MarkerTiming::Interval(mNavigationStart, mContentfulComposite), + MarkerInnerWindowIdFromDocShell(mDocShell)), + marker); + } + + if (!mTTITimer) { + mTTITimer = NS_NewTimer(); + } + + // TTI is first checked 5 seconds after the FCP (non-blank-paint is very close + // to FCP). + mTTITimer->InitWithNamedFuncCallback(TTITimeoutCallback, this, + TTI_WINDOW_SIZE_MS, + nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY, + "nsDOMNavigationTiming::TTITimeout"); + + if (mDocShellHasBeenActiveSinceNavigationStart) { + Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_FIRST_CONTENTFUL_PAINT_MS, + mNavigationStart, mContentfulComposite); + } +} + +void nsDOMNavigationTiming::NotifyLargestContentfulRenderForRootContentDocument( + const DOMHighResTimeStamp& aRenderTime) { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!mNavigationStart.IsNull()); + + // This can get called multiple times and updates over time. + mLargestContentfulRender = + mNavigationStart + TimeDuration::FromMilliseconds(aRenderTime); +} + +void nsDOMNavigationTiming::NotifyDOMContentFlushedForRootContentDocument() { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!mNavigationStart.IsNull()); + + if (!mDOMContentFlushed.IsNull()) { + return; + } + + mDOMContentFlushed = TimeStamp::Now(); + + if (profiler_thread_is_being_profiled_for_markers() || + PAGELOAD_LOG_ENABLED()) { + TimeDuration elapsed = mDOMContentFlushed - mNavigationStart; + nsPrintfCString marker( + "DOMContentFlushed after %dms for URL %s, %s", + int(elapsed.ToMilliseconds()), + nsContentUtils::TruncatedURLForDisplay(mLoadedURI).get(), + mDocShellHasBeenActiveSinceNavigationStart + ? "foreground tab" + : "this tab was inactive some of the time between navigation start " + "and DOMContentFlushed"); + PAGELOAD_LOG(("%s", marker.get())); + PROFILER_MARKER_TEXT( + "DOMContentFlushed", DOM, + MarkerOptions( + MarkerTiming::Interval(mNavigationStart, mDOMContentFlushed), + MarkerInnerWindowIdFromDocShell(mDocShell)), + marker); + } +} + +void nsDOMNavigationTiming::NotifyDocShellStateChanged( + DocShellState aDocShellState) { + mDocShellHasBeenActiveSinceNavigationStart &= + (aDocShellState == DocShellState::eActive); +} + +void nsDOMNavigationTiming::MaybeAddLCPProfilerMarker( + MarkerInnerWindowId aInnerWindowID) { + // This method might get called from outside of the main thread, so can't + // check `profiler_thread_is_being_profiled_for_markers()` here. + if (!profiler_is_active_and_unpaused()) { + return; + } + + TimeStamp navStartTime = GetNavigationStartTimeStamp(); + TimeStamp lcpTime = GetLargestContentfulRenderTimeStamp(); + + if (!navStartTime || !lcpTime) { + return; + } + + TimeDuration elapsed = lcpTime - navStartTime; + nsPrintfCString marker("Largest contentful paint after %dms", + int(elapsed.ToMilliseconds())); + PROFILER_MARKER_TEXT( + "LargestContentfulPaint", DOM, + // Putting this marker to the main thread even if it's called from another + // one. + MarkerOptions(MarkerThreadId::MainThread(), + MarkerTiming::Interval(navStartTime, lcpTime), + std::move(aInnerWindowID)), + marker); +} + +mozilla::TimeStamp nsDOMNavigationTiming::GetUnloadEventStartTimeStamp() const { + nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); + // todo: if you intend to update CheckSameOriginURI to log the error to the + // console you also need to update the 'aFromPrivateWindow' argument. + nsresult rv = ssm->CheckSameOriginURI(mLoadedURI, mUnloadedURI, false, false); + if (NS_SUCCEEDED(rv)) { + return mUnloadStart; + } + return mozilla::TimeStamp(); +} + +mozilla::TimeStamp nsDOMNavigationTiming::GetUnloadEventEndTimeStamp() const { + nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); + // todo: if you intend to update CheckSameOriginURI to log the error to the + // console you also need to update the 'aFromPrivateWindow' argument. + nsresult rv = ssm->CheckSameOriginURI(mLoadedURI, mUnloadedURI, false, false); + if (NS_SUCCEEDED(rv)) { + return mUnloadEnd; + } + return mozilla::TimeStamp(); +} + +bool nsDOMNavigationTiming::IsTopLevelContentDocumentInContentProcess() const { + if (!mDocShell) { + return false; + } + if (!XRE_IsContentProcess()) { + return false; + } + return mDocShell->GetBrowsingContext()->IsTopContent(); +} + +nsDOMNavigationTiming::nsDOMNavigationTiming(nsDocShell* aDocShell, + nsDOMNavigationTiming* aOther) + : mDocShell(aDocShell), + mUnloadedURI(aOther->mUnloadedURI), + mLoadedURI(aOther->mLoadedURI), + mNavigationType(aOther->mNavigationType), + mNavigationStartHighRes(aOther->mNavigationStartHighRes), + mNavigationStart(aOther->mNavigationStart), + mNonBlankPaint(aOther->mNonBlankPaint), + mContentfulComposite(aOther->mContentfulComposite), + mDOMContentFlushed(aOther->mDOMContentFlushed), + mBeforeUnloadStart(aOther->mBeforeUnloadStart), + mUnloadStart(aOther->mUnloadStart), + mUnloadEnd(aOther->mUnloadEnd), + mLoadEventStart(aOther->mLoadEventStart), + mLoadEventEnd(aOther->mLoadEventEnd), + mDOMLoading(aOther->mDOMLoading), + mDOMInteractive(aOther->mDOMInteractive), + mDOMContentLoadedEventStart(aOther->mDOMContentLoadedEventStart), + mDOMContentLoadedEventEnd(aOther->mDOMContentLoadedEventEnd), + mDOMComplete(aOther->mDOMComplete), + mTTFI(aOther->mTTFI), + mDocShellHasBeenActiveSinceNavigationStart( + aOther->mDocShellHasBeenActiveSinceNavigationStart) {} + +/* static */ +void mozilla::ipc::IPDLParamTraits<nsDOMNavigationTiming*>::Write( + IPC::MessageWriter* aWriter, IProtocol* aActor, + nsDOMNavigationTiming* aParam) { + bool isNull = !aParam; + WriteIPDLParam(aWriter, aActor, isNull); + if (isNull) { + return; + } + + RefPtr<nsIURI> unloadedURI = aParam->mUnloadedURI.get(); + RefPtr<nsIURI> loadedURI = aParam->mLoadedURI.get(); + WriteIPDLParam(aWriter, aActor, unloadedURI ? Some(unloadedURI) : Nothing()); + WriteIPDLParam(aWriter, aActor, loadedURI ? Some(loadedURI) : Nothing()); + WriteIPDLParam(aWriter, aActor, uint32_t(aParam->mNavigationType)); + WriteIPDLParam(aWriter, aActor, aParam->mNavigationStartHighRes); + WriteIPDLParam(aWriter, aActor, aParam->mNavigationStart); + WriteIPDLParam(aWriter, aActor, aParam->mNonBlankPaint); + WriteIPDLParam(aWriter, aActor, aParam->mContentfulComposite); + WriteIPDLParam(aWriter, aActor, aParam->mDOMContentFlushed); + WriteIPDLParam(aWriter, aActor, aParam->mBeforeUnloadStart); + WriteIPDLParam(aWriter, aActor, aParam->mUnloadStart); + WriteIPDLParam(aWriter, aActor, aParam->mUnloadEnd); + WriteIPDLParam(aWriter, aActor, aParam->mLoadEventStart); + WriteIPDLParam(aWriter, aActor, aParam->mLoadEventEnd); + WriteIPDLParam(aWriter, aActor, aParam->mDOMLoading); + WriteIPDLParam(aWriter, aActor, aParam->mDOMInteractive); + WriteIPDLParam(aWriter, aActor, aParam->mDOMContentLoadedEventStart); + WriteIPDLParam(aWriter, aActor, aParam->mDOMContentLoadedEventEnd); + WriteIPDLParam(aWriter, aActor, aParam->mDOMComplete); + WriteIPDLParam(aWriter, aActor, aParam->mTTFI); + WriteIPDLParam(aWriter, aActor, + aParam->mDocShellHasBeenActiveSinceNavigationStart); +} + +/* static */ +bool mozilla::ipc::IPDLParamTraits<nsDOMNavigationTiming*>::Read( + IPC::MessageReader* aReader, IProtocol* aActor, + RefPtr<nsDOMNavigationTiming>* aResult) { + bool isNull; + if (!ReadIPDLParam(aReader, aActor, &isNull)) { + return false; + } + if (isNull) { + *aResult = nullptr; + return true; + } + + auto timing = MakeRefPtr<nsDOMNavigationTiming>(nullptr); + uint32_t type; + Maybe<RefPtr<nsIURI>> unloadedURI; + Maybe<RefPtr<nsIURI>> loadedURI; + if (!ReadIPDLParam(aReader, aActor, &unloadedURI) || + !ReadIPDLParam(aReader, aActor, &loadedURI) || + !ReadIPDLParam(aReader, aActor, &type) || + !ReadIPDLParam(aReader, aActor, &timing->mNavigationStartHighRes) || + !ReadIPDLParam(aReader, aActor, &timing->mNavigationStart) || + !ReadIPDLParam(aReader, aActor, &timing->mNonBlankPaint) || + !ReadIPDLParam(aReader, aActor, &timing->mContentfulComposite) || + !ReadIPDLParam(aReader, aActor, &timing->mDOMContentFlushed) || + !ReadIPDLParam(aReader, aActor, &timing->mBeforeUnloadStart) || + !ReadIPDLParam(aReader, aActor, &timing->mUnloadStart) || + !ReadIPDLParam(aReader, aActor, &timing->mUnloadEnd) || + !ReadIPDLParam(aReader, aActor, &timing->mLoadEventStart) || + !ReadIPDLParam(aReader, aActor, &timing->mLoadEventEnd) || + !ReadIPDLParam(aReader, aActor, &timing->mDOMLoading) || + !ReadIPDLParam(aReader, aActor, &timing->mDOMInteractive) || + !ReadIPDLParam(aReader, aActor, &timing->mDOMContentLoadedEventStart) || + !ReadIPDLParam(aReader, aActor, &timing->mDOMContentLoadedEventEnd) || + !ReadIPDLParam(aReader, aActor, &timing->mDOMComplete) || + !ReadIPDLParam(aReader, aActor, &timing->mTTFI) || + !ReadIPDLParam(aReader, aActor, + &timing->mDocShellHasBeenActiveSinceNavigationStart)) { + return false; + } + timing->mNavigationType = nsDOMNavigationTiming::Type(type); + if (unloadedURI) { + timing->mUnloadedURI = std::move(*unloadedURI); + } + if (loadedURI) { + timing->mLoadedURI = std::move(*loadedURI); + } + *aResult = std::move(timing); + return true; +} |