Bug 1852740: add tests for the `fetchpriority` attribute in Link headers. r=necko...
[gecko.git] / dom / base / nsDOMNavigationTiming.cpp
blob1db54e1ed7a246475117f6b3572dac9586e18c79
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsDOMNavigationTiming.h"
9 #include "GeckoProfiler.h"
10 #include "ipc/IPCMessageUtilsSpecializations.h"
11 #include "mozilla/ProfilerMarkers.h"
12 #include "mozilla/Telemetry.h"
13 #include "mozilla/TimeStamp.h"
14 #include "mozilla/dom/Document.h"
15 #include "mozilla/dom/PerformanceNavigation.h"
16 #include "mozilla/ipc/IPDLParamTraits.h"
17 #include "mozilla/ipc/URIUtils.h"
18 #include "nsCOMPtr.h"
19 #include "nsContentUtils.h"
20 #include "nsDocShell.h"
21 #include "nsHttp.h"
22 #include "nsIScriptSecurityManager.h"
23 #include "nsIURI.h"
24 #include "nsPrintfCString.h"
25 #include "prtime.h"
27 using namespace mozilla;
29 namespace mozilla {
31 LazyLogModule gPageLoadLog("PageLoad");
32 #define PAGELOAD_LOG(args) MOZ_LOG(gPageLoadLog, LogLevel::Debug, args)
33 #define PAGELOAD_LOG_ENABLED() MOZ_LOG_TEST(gPageLoadLog, LogLevel::Error)
35 } // namespace mozilla
37 nsDOMNavigationTiming::nsDOMNavigationTiming(nsDocShell* aDocShell) {
38 Clear();
40 mDocShell = aDocShell;
43 nsDOMNavigationTiming::~nsDOMNavigationTiming() = default;
45 void nsDOMNavigationTiming::Clear() {
46 mNavigationType = TYPE_RESERVED;
47 mNavigationStartHighRes = 0;
49 mBeforeUnloadStart = TimeStamp();
50 mUnloadStart = TimeStamp();
51 mUnloadEnd = TimeStamp();
52 mLoadEventStart = TimeStamp();
53 mLoadEventEnd = TimeStamp();
54 mDOMLoading = TimeStamp();
55 mDOMInteractive = TimeStamp();
56 mDOMContentLoadedEventStart = TimeStamp();
57 mDOMContentLoadedEventEnd = TimeStamp();
58 mDOMComplete = TimeStamp();
59 mContentfulComposite = TimeStamp();
60 mNonBlankPaint = TimeStamp();
62 mDocShellHasBeenActiveSinceNavigationStart = false;
65 void nsDOMNavigationTiming::Anonymize(nsIURI* aFinalURI) {
66 mLoadedURI = aFinalURI;
67 mUnloadedURI = nullptr;
68 mBeforeUnloadStart = TimeStamp();
69 mUnloadStart = TimeStamp();
70 mUnloadEnd = TimeStamp();
73 DOMTimeMilliSec nsDOMNavigationTiming::TimeStampToDOM(TimeStamp aStamp) const {
74 if (aStamp.IsNull()) {
75 return 0;
78 TimeDuration duration = aStamp - mNavigationStart;
79 return GetNavigationStart() + static_cast<int64_t>(duration.ToMilliseconds());
82 void nsDOMNavigationTiming::NotifyNavigationStart(
83 DocShellState aDocShellState) {
84 mNavigationStartHighRes = (double)PR_Now() / PR_USEC_PER_MSEC;
85 mNavigationStart = TimeStamp::Now();
86 mDocShellHasBeenActiveSinceNavigationStart =
87 (aDocShellState == DocShellState::eActive);
88 PROFILER_MARKER_UNTYPED("Navigation::Start", DOM,
89 MarkerInnerWindowIdFromDocShell(mDocShell));
92 void nsDOMNavigationTiming::NotifyFetchStart(nsIURI* aURI,
93 Type aNavigationType) {
94 mNavigationType = aNavigationType;
95 // At the unload event time we don't really know the loading uri.
96 // Need it for later check for unload timing access.
97 mLoadedURI = aURI;
100 void nsDOMNavigationTiming::NotifyRestoreStart() {
101 mNavigationType = TYPE_BACK_FORWARD;
104 void nsDOMNavigationTiming::NotifyBeforeUnload() {
105 mBeforeUnloadStart = TimeStamp::Now();
108 void nsDOMNavigationTiming::NotifyUnloadAccepted(nsIURI* aOldURI) {
109 mUnloadStart = mBeforeUnloadStart;
110 mUnloadedURI = aOldURI;
113 void nsDOMNavigationTiming::NotifyUnloadEventStart() {
114 mUnloadStart = TimeStamp::Now();
115 PROFILER_MARKER("Unload", NETWORK,
116 MarkerOptions(MarkerTiming::IntervalStart(),
117 MarkerInnerWindowIdFromDocShell(mDocShell)),
118 Tracing, "Navigation");
121 void nsDOMNavigationTiming::NotifyUnloadEventEnd() {
122 mUnloadEnd = TimeStamp::Now();
123 PROFILER_MARKER("Unload", NETWORK,
124 MarkerOptions(MarkerTiming::IntervalEnd(),
125 MarkerInnerWindowIdFromDocShell(mDocShell)),
126 Tracing, "Navigation");
129 void nsDOMNavigationTiming::NotifyLoadEventStart() {
130 if (!mLoadEventStart.IsNull()) {
131 return;
133 mLoadEventStart = TimeStamp::Now();
135 PROFILER_MARKER("Load", NETWORK,
136 MarkerOptions(MarkerTiming::IntervalStart(),
137 MarkerInnerWindowIdFromDocShell(mDocShell)),
138 Tracing, "Navigation");
140 if (IsTopLevelContentDocumentInContentProcess()) {
141 TimeStamp now = TimeStamp::Now();
143 Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_LOAD_EVENT_START_MS,
144 mNavigationStart, now);
146 if (mDocShellHasBeenActiveSinceNavigationStart) {
147 if (net::nsHttp::IsBeforeLastActiveTabLoadOptimization(
148 mNavigationStart)) {
149 Telemetry::AccumulateTimeDelta(
150 Telemetry::TIME_TO_LOAD_EVENT_START_ACTIVE_NETOPT_MS,
151 mNavigationStart, now);
152 } else {
153 Telemetry::AccumulateTimeDelta(
154 Telemetry::TIME_TO_LOAD_EVENT_START_ACTIVE_MS, mNavigationStart,
155 now);
161 void nsDOMNavigationTiming::NotifyLoadEventEnd() {
162 if (!mLoadEventEnd.IsNull()) {
163 return;
165 mLoadEventEnd = TimeStamp::Now();
167 PROFILER_MARKER("Load", NETWORK,
168 MarkerOptions(MarkerTiming::IntervalEnd(),
169 MarkerInnerWindowIdFromDocShell(mDocShell)),
170 Tracing, "Navigation");
172 if (IsTopLevelContentDocumentInContentProcess()) {
173 if (profiler_thread_is_being_profiled_for_markers() ||
174 PAGELOAD_LOG_ENABLED()) {
175 TimeDuration elapsed = mLoadEventEnd - mNavigationStart;
176 TimeDuration duration = mLoadEventEnd - mLoadEventStart;
177 nsPrintfCString marker(
178 "Document %s loaded after %dms, load event duration %dms",
179 nsContentUtils::TruncatedURLForDisplay(mLoadedURI).get(),
180 int(elapsed.ToMilliseconds()), int(duration.ToMilliseconds()));
181 PAGELOAD_LOG(("%s", marker.get()));
182 PROFILER_MARKER_TEXT(
183 "DocumentLoad", DOM,
184 MarkerOptions(MarkerTiming::Interval(mNavigationStart, mLoadEventEnd),
185 MarkerInnerWindowIdFromDocShell(mDocShell)),
186 marker);
188 Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_LOAD_EVENT_END_MS,
189 mNavigationStart);
193 void nsDOMNavigationTiming::SetDOMLoadingTimeStamp(nsIURI* aURI,
194 TimeStamp aValue) {
195 if (!mDOMLoading.IsNull()) {
196 return;
198 mLoadedURI = aURI;
199 mDOMLoading = aValue;
202 void nsDOMNavigationTiming::NotifyDOMLoading(nsIURI* aURI) {
203 if (!mDOMLoading.IsNull()) {
204 return;
206 mLoadedURI = aURI;
207 mDOMLoading = TimeStamp::Now();
209 PROFILER_MARKER_UNTYPED("Navigation::DOMLoading", DOM,
210 MarkerInnerWindowIdFromDocShell(mDocShell));
213 void nsDOMNavigationTiming::NotifyDOMInteractive(nsIURI* aURI) {
214 if (!mDOMInteractive.IsNull()) {
215 return;
217 mLoadedURI = aURI;
218 mDOMInteractive = TimeStamp::Now();
220 PROFILER_MARKER_UNTYPED("Navigation::DOMInteractive", DOM,
221 MarkerInnerWindowIdFromDocShell(mDocShell));
224 void nsDOMNavigationTiming::NotifyDOMComplete(nsIURI* aURI) {
225 if (!mDOMComplete.IsNull()) {
226 return;
228 mLoadedURI = aURI;
229 mDOMComplete = TimeStamp::Now();
231 PROFILER_MARKER_UNTYPED("Navigation::DOMComplete", DOM,
232 MarkerInnerWindowIdFromDocShell(mDocShell));
235 void nsDOMNavigationTiming::NotifyDOMContentLoadedStart(nsIURI* aURI) {
236 if (!mDOMContentLoadedEventStart.IsNull()) {
237 return;
240 mLoadedURI = aURI;
241 mDOMContentLoadedEventStart = TimeStamp::Now();
243 PROFILER_MARKER("DOMContentLoaded", NETWORK,
244 MarkerOptions(MarkerTiming::IntervalStart(),
245 MarkerInnerWindowIdFromDocShell(mDocShell)),
246 Tracing, "Navigation");
248 if (IsTopLevelContentDocumentInContentProcess()) {
249 TimeStamp now = TimeStamp::Now();
251 Telemetry::AccumulateTimeDelta(
252 Telemetry::TIME_TO_DOM_CONTENT_LOADED_START_MS, mNavigationStart, now);
254 if (mDocShellHasBeenActiveSinceNavigationStart) {
255 if (net::nsHttp::IsBeforeLastActiveTabLoadOptimization(
256 mNavigationStart)) {
257 Telemetry::AccumulateTimeDelta(
258 Telemetry::TIME_TO_DOM_CONTENT_LOADED_START_ACTIVE_NETOPT_MS,
259 mNavigationStart, now);
260 } else {
261 Telemetry::AccumulateTimeDelta(
262 Telemetry::TIME_TO_DOM_CONTENT_LOADED_START_ACTIVE_MS,
263 mNavigationStart, now);
269 void nsDOMNavigationTiming::NotifyDOMContentLoadedEnd(nsIURI* aURI) {
270 if (!mDOMContentLoadedEventEnd.IsNull()) {
271 return;
274 mLoadedURI = aURI;
275 mDOMContentLoadedEventEnd = TimeStamp::Now();
277 PROFILER_MARKER("DOMContentLoaded", NETWORK,
278 MarkerOptions(MarkerTiming::IntervalEnd(),
279 MarkerInnerWindowIdFromDocShell(mDocShell)),
280 Tracing, "Navigation");
282 if (IsTopLevelContentDocumentInContentProcess()) {
283 Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_DOM_CONTENT_LOADED_END_MS,
284 mNavigationStart);
288 // static
289 void nsDOMNavigationTiming::TTITimeoutCallback(nsITimer* aTimer,
290 void* aClosure) {
291 nsDOMNavigationTiming* self = static_cast<nsDOMNavigationTiming*>(aClosure);
292 self->TTITimeout(aTimer);
295 #define TTI_WINDOW_SIZE_MS (5 * 1000)
297 void nsDOMNavigationTiming::TTITimeout(nsITimer* aTimer) {
298 // Check TTI: see if it's been 5 seconds since the last Long Task
299 TimeStamp now = TimeStamp::Now();
300 MOZ_RELEASE_ASSERT(!mContentfulComposite.IsNull(),
301 "TTI timeout with no contentful-composite?");
303 nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
304 TimeStamp lastLongTaskEnded;
305 mainThread->GetLastLongNonIdleTaskEnd(&lastLongTaskEnded);
306 // Window starts at mContentfulComposite; any long task before that is ignored
307 if (lastLongTaskEnded.IsNull() || lastLongTaskEnded < mContentfulComposite) {
308 PAGELOAD_LOG(
309 ("no longtask (last was %g ms before ContentfulComposite)",
310 lastLongTaskEnded.IsNull()
312 : (mContentfulComposite - lastLongTaskEnded).ToMilliseconds()));
313 lastLongTaskEnded = mContentfulComposite;
315 TimeDuration delta = now - lastLongTaskEnded;
316 PAGELOAD_LOG(("TTI delta: %g ms", delta.ToMilliseconds()));
317 if (delta.ToMilliseconds() < TTI_WINDOW_SIZE_MS) {
318 // Less than 5 seconds since the last long task or start of the window.
319 // Schedule another check.
320 PAGELOAD_LOG(("TTI: waiting additional %g ms",
321 (TTI_WINDOW_SIZE_MS + 100) - delta.ToMilliseconds()));
322 aTimer->InitWithNamedFuncCallback(
323 TTITimeoutCallback, this,
324 (TTI_WINDOW_SIZE_MS + 100) -
325 delta.ToMilliseconds(), // slightly after the window ends
326 nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY,
327 "nsDOMNavigationTiming::TTITimeout");
328 return;
331 // To correctly implement TTI/TTFI as proposed, we'd need to not
332 // fire it until there are no more than 2 network loads. By the
333 // proposed definition, without that we're closer to
334 // TimeToFirstInteractive. There are also arguments about what sort
335 // of loads should qualify.
337 // XXX check number of network loads, and if > 2 mark to check if loads
338 // decreases to 2 (or record that point and let the normal timer here
339 // handle it)
341 // TTI has occurred! TTI is either FCP (if there are no longtasks and no
342 // DCLEnd in the window that starts at FCP), or at the end of the last
343 // Long Task or DOMContentLoadedEnd (whichever is later). lastLongTaskEnded
344 // is >= FCP here.
346 if (mTTFI.IsNull()) {
347 // lastLongTaskEnded is >= mContentfulComposite
348 mTTFI = (mDOMContentLoadedEventEnd.IsNull() ||
349 lastLongTaskEnded > mDOMContentLoadedEventEnd)
350 ? lastLongTaskEnded
351 : mDOMContentLoadedEventEnd;
352 PAGELOAD_LOG(
353 ("TTFI after %dms (LongTask was at %dms, DCL was %dms)",
354 int((mTTFI - mNavigationStart).ToMilliseconds()),
355 lastLongTaskEnded.IsNull()
357 : int((lastLongTaskEnded - mNavigationStart).ToMilliseconds()),
358 mDOMContentLoadedEventEnd.IsNull()
360 : int((mDOMContentLoadedEventEnd - mNavigationStart)
361 .ToMilliseconds())));
363 // XXX Implement TTI via check number of network loads, and if > 2 mark
364 // to check if loads decreases to 2 (or record that point and let the
365 // normal timer here handle it)
367 mTTITimer = nullptr;
369 if (profiler_thread_is_being_profiled_for_markers() ||
370 PAGELOAD_LOG_ENABLED()) {
371 TimeDuration elapsed = mTTFI - mNavigationStart;
372 MOZ_ASSERT(elapsed.ToMilliseconds() > 0);
373 TimeDuration elapsedLongTask =
374 lastLongTaskEnded.IsNull() ? 0 : lastLongTaskEnded - mNavigationStart;
375 nsPrintfCString marker(
376 "TTFI after %dms (LongTask was at %dms) for URL %s",
377 int(elapsed.ToMilliseconds()), int(elapsedLongTask.ToMilliseconds()),
378 nsContentUtils::TruncatedURLForDisplay(mLoadedURI).get());
380 PROFILER_MARKER_TEXT(
381 "TimeToFirstInteractive (TTFI)", DOM,
382 MarkerOptions(MarkerTiming::Interval(mNavigationStart, mTTFI),
383 MarkerInnerWindowIdFromDocShell(mDocShell)),
384 marker);
388 void nsDOMNavigationTiming::NotifyNonBlankPaintForRootContentDocument() {
389 MOZ_ASSERT(NS_IsMainThread());
390 MOZ_ASSERT(!mNavigationStart.IsNull());
392 if (!mNonBlankPaint.IsNull()) {
393 return;
396 mNonBlankPaint = TimeStamp::Now();
398 if (profiler_thread_is_being_profiled_for_markers() ||
399 PAGELOAD_LOG_ENABLED()) {
400 TimeDuration elapsed = mNonBlankPaint - mNavigationStart;
401 nsPrintfCString marker(
402 "Non-blank paint after %dms for URL %s, %s",
403 int(elapsed.ToMilliseconds()),
404 nsContentUtils::TruncatedURLForDisplay(mLoadedURI).get(),
405 mDocShellHasBeenActiveSinceNavigationStart
406 ? "foreground tab"
407 : "this tab was inactive some of the time between navigation start "
408 "and first non-blank paint");
409 PAGELOAD_LOG(("%s", marker.get()));
410 PROFILER_MARKER_TEXT(
411 "FirstNonBlankPaint", DOM,
412 MarkerOptions(MarkerTiming::Interval(mNavigationStart, mNonBlankPaint),
413 MarkerInnerWindowIdFromDocShell(mDocShell)),
414 marker);
417 if (mDocShellHasBeenActiveSinceNavigationStart) {
418 if (net::nsHttp::IsBeforeLastActiveTabLoadOptimization(mNavigationStart)) {
419 Telemetry::AccumulateTimeDelta(
420 Telemetry::TIME_TO_NON_BLANK_PAINT_NETOPT_MS, mNavigationStart,
421 mNonBlankPaint);
422 } else {
423 Telemetry::AccumulateTimeDelta(
424 Telemetry::TIME_TO_NON_BLANK_PAINT_NO_NETOPT_MS, mNavigationStart,
425 mNonBlankPaint);
428 Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_NON_BLANK_PAINT_MS,
429 mNavigationStart, mNonBlankPaint);
433 void nsDOMNavigationTiming::NotifyContentfulCompositeForRootContentDocument(
434 const mozilla::TimeStamp& aCompositeEndTime) {
435 MOZ_ASSERT(NS_IsMainThread());
436 MOZ_ASSERT(!mNavigationStart.IsNull());
438 if (!mContentfulComposite.IsNull()) {
439 return;
442 mContentfulComposite = aCompositeEndTime;
444 if (profiler_thread_is_being_profiled_for_markers() ||
445 PAGELOAD_LOG_ENABLED()) {
446 TimeDuration elapsed = mContentfulComposite - mNavigationStart;
447 nsPrintfCString marker(
448 "Contentful composite after %dms for URL %s, %s",
449 int(elapsed.ToMilliseconds()),
450 nsContentUtils::TruncatedURLForDisplay(mLoadedURI).get(),
451 mDocShellHasBeenActiveSinceNavigationStart
452 ? "foreground tab"
453 : "this tab was inactive some of the time between navigation start "
454 "and first non-blank paint");
455 PAGELOAD_LOG(("%s", marker.get()));
456 PROFILER_MARKER_TEXT(
457 "FirstContentfulComposite", DOM,
458 MarkerOptions(
459 MarkerTiming::Interval(mNavigationStart, mContentfulComposite),
460 MarkerInnerWindowIdFromDocShell(mDocShell)),
461 marker);
464 if (!mTTITimer) {
465 mTTITimer = NS_NewTimer();
468 // TTI is first checked 5 seconds after the FCP (non-blank-paint is very close
469 // to FCP).
470 mTTITimer->InitWithNamedFuncCallback(TTITimeoutCallback, this,
471 TTI_WINDOW_SIZE_MS,
472 nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY,
473 "nsDOMNavigationTiming::TTITimeout");
475 if (mDocShellHasBeenActiveSinceNavigationStart) {
476 Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_FIRST_CONTENTFUL_PAINT_MS,
477 mNavigationStart, mContentfulComposite);
481 void nsDOMNavigationTiming::NotifyDOMContentFlushedForRootContentDocument() {
482 MOZ_ASSERT(NS_IsMainThread());
483 MOZ_ASSERT(!mNavigationStart.IsNull());
485 if (!mDOMContentFlushed.IsNull()) {
486 return;
489 mDOMContentFlushed = TimeStamp::Now();
491 if (profiler_thread_is_being_profiled_for_markers() ||
492 PAGELOAD_LOG_ENABLED()) {
493 TimeDuration elapsed = mDOMContentFlushed - mNavigationStart;
494 nsPrintfCString marker(
495 "DOMContentFlushed after %dms for URL %s, %s",
496 int(elapsed.ToMilliseconds()),
497 nsContentUtils::TruncatedURLForDisplay(mLoadedURI).get(),
498 mDocShellHasBeenActiveSinceNavigationStart
499 ? "foreground tab"
500 : "this tab was inactive some of the time between navigation start "
501 "and DOMContentFlushed");
502 PAGELOAD_LOG(("%s", marker.get()));
503 PROFILER_MARKER_TEXT(
504 "DOMContentFlushed", DOM,
505 MarkerOptions(
506 MarkerTiming::Interval(mNavigationStart, mDOMContentFlushed),
507 MarkerInnerWindowIdFromDocShell(mDocShell)),
508 marker);
512 void nsDOMNavigationTiming::NotifyDocShellStateChanged(
513 DocShellState aDocShellState) {
514 mDocShellHasBeenActiveSinceNavigationStart &=
515 (aDocShellState == DocShellState::eActive);
518 mozilla::TimeStamp nsDOMNavigationTiming::GetUnloadEventStartTimeStamp() const {
519 nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
520 // todo: if you intend to update CheckSameOriginURI to log the error to the
521 // console you also need to update the 'aFromPrivateWindow' argument.
522 nsresult rv = ssm->CheckSameOriginURI(mLoadedURI, mUnloadedURI, false, false);
523 if (NS_SUCCEEDED(rv)) {
524 return mUnloadStart;
526 return mozilla::TimeStamp();
529 mozilla::TimeStamp nsDOMNavigationTiming::GetUnloadEventEndTimeStamp() const {
530 nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
531 // todo: if you intend to update CheckSameOriginURI to log the error to the
532 // console you also need to update the 'aFromPrivateWindow' argument.
533 nsresult rv = ssm->CheckSameOriginURI(mLoadedURI, mUnloadedURI, false, false);
534 if (NS_SUCCEEDED(rv)) {
535 return mUnloadEnd;
537 return mozilla::TimeStamp();
540 bool nsDOMNavigationTiming::IsTopLevelContentDocumentInContentProcess() const {
541 if (!mDocShell) {
542 return false;
544 if (!XRE_IsContentProcess()) {
545 return false;
547 return mDocShell->GetBrowsingContext()->IsTopContent();
550 nsDOMNavigationTiming::nsDOMNavigationTiming(nsDocShell* aDocShell,
551 nsDOMNavigationTiming* aOther)
552 : mDocShell(aDocShell),
553 mUnloadedURI(aOther->mUnloadedURI),
554 mLoadedURI(aOther->mLoadedURI),
555 mNavigationType(aOther->mNavigationType),
556 mNavigationStartHighRes(aOther->mNavigationStartHighRes),
557 mNavigationStart(aOther->mNavigationStart),
558 mNonBlankPaint(aOther->mNonBlankPaint),
559 mContentfulComposite(aOther->mContentfulComposite),
560 mDOMContentFlushed(aOther->mDOMContentFlushed),
561 mBeforeUnloadStart(aOther->mBeforeUnloadStart),
562 mUnloadStart(aOther->mUnloadStart),
563 mUnloadEnd(aOther->mUnloadEnd),
564 mLoadEventStart(aOther->mLoadEventStart),
565 mLoadEventEnd(aOther->mLoadEventEnd),
566 mDOMLoading(aOther->mDOMLoading),
567 mDOMInteractive(aOther->mDOMInteractive),
568 mDOMContentLoadedEventStart(aOther->mDOMContentLoadedEventStart),
569 mDOMContentLoadedEventEnd(aOther->mDOMContentLoadedEventEnd),
570 mDOMComplete(aOther->mDOMComplete),
571 mTTFI(aOther->mTTFI),
572 mDocShellHasBeenActiveSinceNavigationStart(
573 aOther->mDocShellHasBeenActiveSinceNavigationStart) {}
575 /* static */
576 void mozilla::ipc::IPDLParamTraits<nsDOMNavigationTiming*>::Write(
577 IPC::MessageWriter* aWriter, IProtocol* aActor,
578 nsDOMNavigationTiming* aParam) {
579 bool isNull = !aParam;
580 WriteIPDLParam(aWriter, aActor, isNull);
581 if (isNull) {
582 return;
585 RefPtr<nsIURI> unloadedURI = aParam->mUnloadedURI.get();
586 RefPtr<nsIURI> loadedURI = aParam->mLoadedURI.get();
587 WriteIPDLParam(aWriter, aActor, unloadedURI ? Some(unloadedURI) : Nothing());
588 WriteIPDLParam(aWriter, aActor, loadedURI ? Some(loadedURI) : Nothing());
589 WriteIPDLParam(aWriter, aActor, uint32_t(aParam->mNavigationType));
590 WriteIPDLParam(aWriter, aActor, aParam->mNavigationStartHighRes);
591 WriteIPDLParam(aWriter, aActor, aParam->mNavigationStart);
592 WriteIPDLParam(aWriter, aActor, aParam->mNonBlankPaint);
593 WriteIPDLParam(aWriter, aActor, aParam->mContentfulComposite);
594 WriteIPDLParam(aWriter, aActor, aParam->mDOMContentFlushed);
595 WriteIPDLParam(aWriter, aActor, aParam->mBeforeUnloadStart);
596 WriteIPDLParam(aWriter, aActor, aParam->mUnloadStart);
597 WriteIPDLParam(aWriter, aActor, aParam->mUnloadEnd);
598 WriteIPDLParam(aWriter, aActor, aParam->mLoadEventStart);
599 WriteIPDLParam(aWriter, aActor, aParam->mLoadEventEnd);
600 WriteIPDLParam(aWriter, aActor, aParam->mDOMLoading);
601 WriteIPDLParam(aWriter, aActor, aParam->mDOMInteractive);
602 WriteIPDLParam(aWriter, aActor, aParam->mDOMContentLoadedEventStart);
603 WriteIPDLParam(aWriter, aActor, aParam->mDOMContentLoadedEventEnd);
604 WriteIPDLParam(aWriter, aActor, aParam->mDOMComplete);
605 WriteIPDLParam(aWriter, aActor, aParam->mTTFI);
606 WriteIPDLParam(aWriter, aActor,
607 aParam->mDocShellHasBeenActiveSinceNavigationStart);
610 /* static */
611 bool mozilla::ipc::IPDLParamTraits<nsDOMNavigationTiming*>::Read(
612 IPC::MessageReader* aReader, IProtocol* aActor,
613 RefPtr<nsDOMNavigationTiming>* aResult) {
614 bool isNull;
615 if (!ReadIPDLParam(aReader, aActor, &isNull)) {
616 return false;
618 if (isNull) {
619 *aResult = nullptr;
620 return true;
623 auto timing = MakeRefPtr<nsDOMNavigationTiming>(nullptr);
624 uint32_t type;
625 Maybe<RefPtr<nsIURI>> unloadedURI;
626 Maybe<RefPtr<nsIURI>> loadedURI;
627 if (!ReadIPDLParam(aReader, aActor, &unloadedURI) ||
628 !ReadIPDLParam(aReader, aActor, &loadedURI) ||
629 !ReadIPDLParam(aReader, aActor, &type) ||
630 !ReadIPDLParam(aReader, aActor, &timing->mNavigationStartHighRes) ||
631 !ReadIPDLParam(aReader, aActor, &timing->mNavigationStart) ||
632 !ReadIPDLParam(aReader, aActor, &timing->mNonBlankPaint) ||
633 !ReadIPDLParam(aReader, aActor, &timing->mContentfulComposite) ||
634 !ReadIPDLParam(aReader, aActor, &timing->mDOMContentFlushed) ||
635 !ReadIPDLParam(aReader, aActor, &timing->mBeforeUnloadStart) ||
636 !ReadIPDLParam(aReader, aActor, &timing->mUnloadStart) ||
637 !ReadIPDLParam(aReader, aActor, &timing->mUnloadEnd) ||
638 !ReadIPDLParam(aReader, aActor, &timing->mLoadEventStart) ||
639 !ReadIPDLParam(aReader, aActor, &timing->mLoadEventEnd) ||
640 !ReadIPDLParam(aReader, aActor, &timing->mDOMLoading) ||
641 !ReadIPDLParam(aReader, aActor, &timing->mDOMInteractive) ||
642 !ReadIPDLParam(aReader, aActor, &timing->mDOMContentLoadedEventStart) ||
643 !ReadIPDLParam(aReader, aActor, &timing->mDOMContentLoadedEventEnd) ||
644 !ReadIPDLParam(aReader, aActor, &timing->mDOMComplete) ||
645 !ReadIPDLParam(aReader, aActor, &timing->mTTFI) ||
646 !ReadIPDLParam(aReader, aActor,
647 &timing->mDocShellHasBeenActiveSinceNavigationStart)) {
648 return false;
650 timing->mNavigationType = nsDOMNavigationTiming::Type(type);
651 if (unloadedURI) {
652 timing->mUnloadedURI = std::move(*unloadedURI);
654 if (loadedURI) {
655 timing->mLoadedURI = std::move(*loadedURI);
657 *aResult = std::move(timing);
658 return true;