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/. */
6
7 #include "nsDOMNavigationTiming.h"
8
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"
26
27 using namespace mozilla;
28
29 namespace mozilla {
30
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)
34
35 } // namespace mozilla
36
nsDOMNavigationTiming(nsDocShell * aDocShell)37 nsDOMNavigationTiming::nsDOMNavigationTiming(nsDocShell* aDocShell) {
38 Clear();
39
40 mDocShell = aDocShell;
41 }
42
43 nsDOMNavigationTiming::~nsDOMNavigationTiming() = default;
44
Clear()45 void nsDOMNavigationTiming::Clear() {
46 mNavigationType = TYPE_RESERVED;
47 mNavigationStartHighRes = 0;
48
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 mContentfulPaint = TimeStamp();
60 mNonBlankPaint = TimeStamp();
61
62 mDocShellHasBeenActiveSinceNavigationStart = false;
63 }
64
Anonymize(nsIURI * aFinalURI)65 void nsDOMNavigationTiming::Anonymize(nsIURI* aFinalURI) {
66 mLoadedURI = aFinalURI;
67 mUnloadedURI = nullptr;
68 mBeforeUnloadStart = TimeStamp();
69 mUnloadStart = TimeStamp();
70 mUnloadEnd = TimeStamp();
71 }
72
TimeStampToDOM(TimeStamp aStamp) const73 DOMTimeMilliSec nsDOMNavigationTiming::TimeStampToDOM(TimeStamp aStamp) const {
74 if (aStamp.IsNull()) {
75 return 0;
76 }
77
78 TimeDuration duration = aStamp - mNavigationStart;
79 return GetNavigationStart() + static_cast<int64_t>(duration.ToMilliseconds());
80 }
81
NotifyNavigationStart(DocShellState aDocShellState)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));
90 }
91
NotifyFetchStart(nsIURI * aURI,Type aNavigationType)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;
98 }
99
NotifyRestoreStart()100 void nsDOMNavigationTiming::NotifyRestoreStart() {
101 mNavigationType = TYPE_BACK_FORWARD;
102 }
103
NotifyBeforeUnload()104 void nsDOMNavigationTiming::NotifyBeforeUnload() {
105 mBeforeUnloadStart = TimeStamp::Now();
106 }
107
NotifyUnloadAccepted(nsIURI * aOldURI)108 void nsDOMNavigationTiming::NotifyUnloadAccepted(nsIURI* aOldURI) {
109 mUnloadStart = mBeforeUnloadStart;
110 mUnloadedURI = aOldURI;
111 }
112
NotifyUnloadEventStart()113 void nsDOMNavigationTiming::NotifyUnloadEventStart() {
114 mUnloadStart = TimeStamp::Now();
115 PROFILER_MARKER("Unload", NETWORK,
116 MarkerOptions(MarkerTiming::IntervalStart(),
117 MarkerInnerWindowIdFromDocShell(mDocShell)),
118 Tracing, "Navigation");
119 }
120
NotifyUnloadEventEnd()121 void nsDOMNavigationTiming::NotifyUnloadEventEnd() {
122 mUnloadEnd = TimeStamp::Now();
123 PROFILER_MARKER("Unload", NETWORK,
124 MarkerOptions(MarkerTiming::IntervalEnd(),
125 MarkerInnerWindowIdFromDocShell(mDocShell)),
126 Tracing, "Navigation");
127 }
128
NotifyLoadEventStart()129 void nsDOMNavigationTiming::NotifyLoadEventStart() {
130 if (!mLoadEventStart.IsNull()) {
131 return;
132 }
133 mLoadEventStart = TimeStamp::Now();
134
135 PROFILER_MARKER("Load", NETWORK,
136 MarkerOptions(MarkerTiming::IntervalStart(),
137 MarkerInnerWindowIdFromDocShell(mDocShell)),
138 Tracing, "Navigation");
139
140 if (IsTopLevelContentDocumentInContentProcess()) {
141 TimeStamp now = TimeStamp::Now();
142
143 Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_LOAD_EVENT_START_MS,
144 mNavigationStart, now);
145
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);
156 }
157 }
158 }
159 }
160
NotifyLoadEventEnd()161 void nsDOMNavigationTiming::NotifyLoadEventEnd() {
162 if (!mLoadEventEnd.IsNull()) {
163 return;
164 }
165 mLoadEventEnd = TimeStamp::Now();
166
167 PROFILER_MARKER("Load", NETWORK,
168 MarkerOptions(MarkerTiming::IntervalEnd(),
169 MarkerInnerWindowIdFromDocShell(mDocShell)),
170 Tracing, "Navigation");
171
172 if (IsTopLevelContentDocumentInContentProcess()) {
173 if (profiler_can_accept_markers() || PAGELOAD_LOG_ENABLED()) {
174 TimeDuration elapsed = mLoadEventEnd - mNavigationStart;
175 TimeDuration duration = mLoadEventEnd - mLoadEventStart;
176 nsAutoCString spec;
177 if (mLoadedURI) {
178 mLoadedURI->GetSpec(spec);
179 }
180 nsPrintfCString marker(
181 "Document %s loaded after %dms, load event duration %dms", spec.get(),
182 int(elapsed.ToMilliseconds()), int(duration.ToMilliseconds()));
183 PAGELOAD_LOG(("%s", marker.get()));
184 PROFILER_MARKER_TEXT(
185 "DocumentLoad", DOM,
186 MarkerOptions(MarkerTiming::Interval(mNavigationStart, mLoadEventEnd),
187 MarkerInnerWindowIdFromDocShell(mDocShell)),
188 marker);
189 }
190 Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_LOAD_EVENT_END_MS,
191 mNavigationStart);
192 }
193 }
194
SetDOMLoadingTimeStamp(nsIURI * aURI,TimeStamp aValue)195 void nsDOMNavigationTiming::SetDOMLoadingTimeStamp(nsIURI* aURI,
196 TimeStamp aValue) {
197 if (!mDOMLoading.IsNull()) {
198 return;
199 }
200 mLoadedURI = aURI;
201 mDOMLoading = aValue;
202 }
203
NotifyDOMLoading(nsIURI * aURI)204 void nsDOMNavigationTiming::NotifyDOMLoading(nsIURI* aURI) {
205 if (!mDOMLoading.IsNull()) {
206 return;
207 }
208 mLoadedURI = aURI;
209 mDOMLoading = TimeStamp::Now();
210
211 PROFILER_MARKER_UNTYPED("Navigation::DOMLoading", DOM,
212 MarkerInnerWindowIdFromDocShell(mDocShell));
213 }
214
NotifyDOMInteractive(nsIURI * aURI)215 void nsDOMNavigationTiming::NotifyDOMInteractive(nsIURI* aURI) {
216 if (!mDOMInteractive.IsNull()) {
217 return;
218 }
219 mLoadedURI = aURI;
220 mDOMInteractive = TimeStamp::Now();
221
222 PROFILER_MARKER_UNTYPED("Navigation::DOMInteractive", DOM,
223 MarkerInnerWindowIdFromDocShell(mDocShell));
224 }
225
NotifyDOMComplete(nsIURI * aURI)226 void nsDOMNavigationTiming::NotifyDOMComplete(nsIURI* aURI) {
227 if (!mDOMComplete.IsNull()) {
228 return;
229 }
230 mLoadedURI = aURI;
231 mDOMComplete = TimeStamp::Now();
232
233 PROFILER_MARKER_UNTYPED("Navigation::DOMComplete", DOM,
234 MarkerInnerWindowIdFromDocShell(mDocShell));
235 }
236
NotifyDOMContentLoadedStart(nsIURI * aURI)237 void nsDOMNavigationTiming::NotifyDOMContentLoadedStart(nsIURI* aURI) {
238 if (!mDOMContentLoadedEventStart.IsNull()) {
239 return;
240 }
241
242 mLoadedURI = aURI;
243 mDOMContentLoadedEventStart = TimeStamp::Now();
244
245 PROFILER_MARKER("DOMContentLoaded", NETWORK,
246 MarkerOptions(MarkerTiming::IntervalStart(),
247 MarkerInnerWindowIdFromDocShell(mDocShell)),
248 Tracing, "Navigation");
249
250 if (IsTopLevelContentDocumentInContentProcess()) {
251 TimeStamp now = TimeStamp::Now();
252
253 Telemetry::AccumulateTimeDelta(
254 Telemetry::TIME_TO_DOM_CONTENT_LOADED_START_MS, mNavigationStart, now);
255
256 if (mDocShellHasBeenActiveSinceNavigationStart) {
257 if (net::nsHttp::IsBeforeLastActiveTabLoadOptimization(
258 mNavigationStart)) {
259 Telemetry::AccumulateTimeDelta(
260 Telemetry::TIME_TO_DOM_CONTENT_LOADED_START_ACTIVE_NETOPT_MS,
261 mNavigationStart, now);
262 } else {
263 Telemetry::AccumulateTimeDelta(
264 Telemetry::TIME_TO_DOM_CONTENT_LOADED_START_ACTIVE_MS,
265 mNavigationStart, now);
266 }
267 }
268 }
269 }
270
NotifyDOMContentLoadedEnd(nsIURI * aURI)271 void nsDOMNavigationTiming::NotifyDOMContentLoadedEnd(nsIURI* aURI) {
272 if (!mDOMContentLoadedEventEnd.IsNull()) {
273 return;
274 }
275
276 mLoadedURI = aURI;
277 mDOMContentLoadedEventEnd = TimeStamp::Now();
278
279 PROFILER_MARKER("DOMContentLoaded", NETWORK,
280 MarkerOptions(MarkerTiming::IntervalEnd(),
281 MarkerInnerWindowIdFromDocShell(mDocShell)),
282 Tracing, "Navigation");
283
284 if (IsTopLevelContentDocumentInContentProcess()) {
285 Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_DOM_CONTENT_LOADED_END_MS,
286 mNavigationStart);
287 }
288 }
289
290 // static
TTITimeoutCallback(nsITimer * aTimer,void * aClosure)291 void nsDOMNavigationTiming::TTITimeoutCallback(nsITimer* aTimer,
292 void* aClosure) {
293 nsDOMNavigationTiming* self = static_cast<nsDOMNavigationTiming*>(aClosure);
294 self->TTITimeout(aTimer);
295 }
296
297 #define TTI_WINDOW_SIZE_MS (5 * 1000)
298
TTITimeout(nsITimer * aTimer)299 void nsDOMNavigationTiming::TTITimeout(nsITimer* aTimer) {
300 // Check TTI: see if it's been 5 seconds since the last Long Task
301 TimeStamp now = TimeStamp::Now();
302 MOZ_RELEASE_ASSERT(!mContentfulPaint.IsNull(),
303 "TTI timeout with no contentful-paint?");
304
305 nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
306 TimeStamp lastLongTaskEnded;
307 mainThread->GetLastLongNonIdleTaskEnd(&lastLongTaskEnded);
308 // Window starts at mContentfulPaint; any long task before that is ignored
309 if (lastLongTaskEnded.IsNull() || lastLongTaskEnded < mContentfulPaint) {
310 PAGELOAD_LOG(
311 ("no longtask (last was %g ms before ContentfulPaint)",
312 lastLongTaskEnded.IsNull()
313 ? 0
314 : (mContentfulPaint - lastLongTaskEnded).ToMilliseconds()));
315 lastLongTaskEnded = mContentfulPaint;
316 }
317 TimeDuration delta = now - lastLongTaskEnded;
318 PAGELOAD_LOG(("TTI delta: %g ms", delta.ToMilliseconds()));
319 if (delta.ToMilliseconds() < TTI_WINDOW_SIZE_MS) {
320 // Less than 5 seconds since the last long task or start of the window.
321 // Schedule another check.
322 PAGELOAD_LOG(("TTI: waiting additional %g ms",
323 (TTI_WINDOW_SIZE_MS + 100) - delta.ToMilliseconds()));
324 aTimer->InitWithNamedFuncCallback(
325 TTITimeoutCallback, this,
326 (TTI_WINDOW_SIZE_MS + 100) -
327 delta.ToMilliseconds(), // slightly after the window ends
328 nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY,
329 "nsDOMNavigationTiming::TTITimeout");
330 return;
331 }
332
333 // To correctly implement TTI/TTFI as proposed, we'd need to not
334 // fire it until there are no more than 2 network loads. By the
335 // proposed definition, without that we're closer to
336 // TimeToFirstInteractive. There are also arguments about what sort
337 // of loads should qualify.
338
339 // XXX check number of network loads, and if > 2 mark to check if loads
340 // decreases to 2 (or record that point and let the normal timer here
341 // handle it)
342
343 // TTI has occurred! TTI is either FCP (if there are no longtasks and no
344 // DCLEnd in the window that starts at FCP), or at the end of the last
345 // Long Task or DOMContentLoadedEnd (whichever is later). lastLongTaskEnded
346 // is >= FCP here.
347
348 if (mTTFI.IsNull()) {
349 // lastLongTaskEnded is >= mContentfulPaint
350 mTTFI = (mDOMContentLoadedEventEnd.IsNull() ||
351 lastLongTaskEnded > mDOMContentLoadedEventEnd)
352 ? lastLongTaskEnded
353 : mDOMContentLoadedEventEnd;
354 PAGELOAD_LOG(
355 ("TTFI after %dms (LongTask was at %dms, DCL was %dms)",
356 int((mTTFI - mNavigationStart).ToMilliseconds()),
357 lastLongTaskEnded.IsNull()
358 ? 0
359 : int((lastLongTaskEnded - mNavigationStart).ToMilliseconds()),
360 mDOMContentLoadedEventEnd.IsNull()
361 ? 0
362 : int((mDOMContentLoadedEventEnd - mNavigationStart)
363 .ToMilliseconds())));
364 }
365 // XXX Implement TTI via check number of network loads, and if > 2 mark
366 // to check if loads decreases to 2 (or record that point and let the
367 // normal timer here handle it)
368
369 mTTITimer = nullptr;
370
371 if (profiler_can_accept_markers() || PAGELOAD_LOG_ENABLED()) {
372 TimeDuration elapsed = mTTFI - mNavigationStart;
373 MOZ_ASSERT(elapsed.ToMilliseconds() > 0);
374 TimeDuration elapsedLongTask =
375 lastLongTaskEnded.IsNull() ? 0 : lastLongTaskEnded - mNavigationStart;
376 nsAutoCString spec;
377 if (mLoadedURI) {
378 mLoadedURI->GetSpec(spec);
379 }
380 nsPrintfCString marker("TTFI after %dms (LongTask was at %dms) for URL %s",
381 int(elapsed.ToMilliseconds()),
382 int(elapsedLongTask.ToMilliseconds()), spec.get());
383
384 PROFILER_MARKER_TEXT(
385 "TimeToFirstInteractive (TTFI)", DOM,
386 MarkerOptions(MarkerTiming::Interval(mNavigationStart, mTTFI),
387 MarkerInnerWindowIdFromDocShell(mDocShell)),
388 marker);
389 }
390 }
391
NotifyNonBlankPaintForRootContentDocument()392 void nsDOMNavigationTiming::NotifyNonBlankPaintForRootContentDocument() {
393 MOZ_ASSERT(NS_IsMainThread());
394 MOZ_ASSERT(!mNavigationStart.IsNull());
395
396 if (!mNonBlankPaint.IsNull()) {
397 return;
398 }
399
400 mNonBlankPaint = TimeStamp::Now();
401
402 if (profiler_thread_is_being_profiled() || PAGELOAD_LOG_ENABLED()) {
403 TimeDuration elapsed = mNonBlankPaint - mNavigationStart;
404 nsAutoCString spec;
405 if (mLoadedURI) {
406 mLoadedURI->GetSpec(spec);
407 }
408 nsPrintfCString marker(
409 "Non-blank paint after %dms for URL %s, %s",
410 int(elapsed.ToMilliseconds()), spec.get(),
411 mDocShellHasBeenActiveSinceNavigationStart
412 ? "foreground tab"
413 : "this tab was inactive some of the time between navigation start "
414 "and first non-blank paint");
415 PAGELOAD_LOG(("%s", marker.get()));
416 PROFILER_MARKER_TEXT(
417 "FirstNonBlankPaint", DOM,
418 MarkerOptions(MarkerTiming::Interval(mNavigationStart, mNonBlankPaint),
419 MarkerInnerWindowIdFromDocShell(mDocShell)),
420 marker);
421 }
422
423 if (mDocShellHasBeenActiveSinceNavigationStart) {
424 if (net::nsHttp::IsBeforeLastActiveTabLoadOptimization(mNavigationStart)) {
425 Telemetry::AccumulateTimeDelta(
426 Telemetry::TIME_TO_NON_BLANK_PAINT_NETOPT_MS, mNavigationStart,
427 mNonBlankPaint);
428 } else {
429 Telemetry::AccumulateTimeDelta(
430 Telemetry::TIME_TO_NON_BLANK_PAINT_NO_NETOPT_MS, mNavigationStart,
431 mNonBlankPaint);
432 }
433
434 Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_NON_BLANK_PAINT_MS,
435 mNavigationStart, mNonBlankPaint);
436 }
437 }
438
NotifyContentfulPaintForRootContentDocument(const mozilla::TimeStamp & aCompositeEndTime)439 void nsDOMNavigationTiming::NotifyContentfulPaintForRootContentDocument(
440 const mozilla::TimeStamp& aCompositeEndTime) {
441 MOZ_ASSERT(NS_IsMainThread());
442 MOZ_ASSERT(!mNavigationStart.IsNull());
443
444 if (!mContentfulPaint.IsNull()) {
445 return;
446 }
447
448 mContentfulPaint = aCompositeEndTime;
449
450 if (profiler_can_accept_markers() || PAGELOAD_LOG_ENABLED()) {
451 TimeDuration elapsed = mContentfulPaint - mNavigationStart;
452 nsAutoCString spec;
453 if (mLoadedURI) {
454 mLoadedURI->GetSpec(spec);
455 }
456 nsPrintfCString marker(
457 "Contentful paint after %dms for URL %s, %s",
458 int(elapsed.ToMilliseconds()), spec.get(),
459 mDocShellHasBeenActiveSinceNavigationStart
460 ? "foreground tab"
461 : "this tab was inactive some of the time between navigation start "
462 "and first non-blank paint");
463 PAGELOAD_LOG(("%s", marker.get()));
464 PROFILER_MARKER_TEXT(
465 "FirstContentfulPaint", DOM,
466 MarkerOptions(
467 MarkerTiming::Interval(mNavigationStart, mContentfulPaint),
468 MarkerInnerWindowIdFromDocShell(mDocShell)),
469 marker);
470 }
471
472 if (!mTTITimer) {
473 mTTITimer = NS_NewTimer();
474 }
475
476 // TTI is first checked 5 seconds after the FCP (non-blank-paint is very close
477 // to FCP).
478 mTTITimer->InitWithNamedFuncCallback(TTITimeoutCallback, this,
479 TTI_WINDOW_SIZE_MS,
480 nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY,
481 "nsDOMNavigationTiming::TTITimeout");
482
483 if (mDocShellHasBeenActiveSinceNavigationStart) {
484 Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_FIRST_CONTENTFUL_PAINT_MS,
485 mNavigationStart, mContentfulPaint);
486 }
487 }
488
NotifyDOMContentFlushedForRootContentDocument()489 void nsDOMNavigationTiming::NotifyDOMContentFlushedForRootContentDocument() {
490 MOZ_ASSERT(NS_IsMainThread());
491 MOZ_ASSERT(!mNavigationStart.IsNull());
492
493 if (!mDOMContentFlushed.IsNull()) {
494 return;
495 }
496
497 mDOMContentFlushed = TimeStamp::Now();
498
499 if (profiler_thread_is_being_profiled() || PAGELOAD_LOG_ENABLED()) {
500 TimeDuration elapsed = mDOMContentFlushed - mNavigationStart;
501 nsAutoCString spec;
502 if (mLoadedURI) {
503 mLoadedURI->GetSpec(spec);
504 }
505 nsPrintfCString marker(
506 "DOMContentFlushed after %dms for URL %s, %s",
507 int(elapsed.ToMilliseconds()), spec.get(),
508 mDocShellHasBeenActiveSinceNavigationStart
509 ? "foreground tab"
510 : "this tab was inactive some of the time between navigation start "
511 "and DOMContentFlushed");
512 PAGELOAD_LOG(("%s", marker.get()));
513 PROFILER_MARKER_TEXT(
514 "DOMContentFlushed", DOM,
515 MarkerOptions(
516 MarkerTiming::Interval(mNavigationStart, mDOMContentFlushed),
517 MarkerInnerWindowIdFromDocShell(mDocShell)),
518 marker);
519 }
520 }
521
NotifyDocShellStateChanged(DocShellState aDocShellState)522 void nsDOMNavigationTiming::NotifyDocShellStateChanged(
523 DocShellState aDocShellState) {
524 mDocShellHasBeenActiveSinceNavigationStart &=
525 (aDocShellState == DocShellState::eActive);
526 }
527
GetUnloadEventStartTimeStamp() const528 mozilla::TimeStamp nsDOMNavigationTiming::GetUnloadEventStartTimeStamp() const {
529 nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
530 // todo: if you intend to update CheckSameOriginURI to log the error to the
531 // console you also need to update the 'aFromPrivateWindow' argument.
532 nsresult rv = ssm->CheckSameOriginURI(mLoadedURI, mUnloadedURI, false, false);
533 if (NS_SUCCEEDED(rv)) {
534 return mUnloadStart;
535 }
536 return mozilla::TimeStamp();
537 }
538
GetUnloadEventEndTimeStamp() const539 mozilla::TimeStamp nsDOMNavigationTiming::GetUnloadEventEndTimeStamp() const {
540 nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
541 // todo: if you intend to update CheckSameOriginURI to log the error to the
542 // console you also need to update the 'aFromPrivateWindow' argument.
543 nsresult rv = ssm->CheckSameOriginURI(mLoadedURI, mUnloadedURI, false, false);
544 if (NS_SUCCEEDED(rv)) {
545 return mUnloadEnd;
546 }
547 return mozilla::TimeStamp();
548 }
549
IsTopLevelContentDocumentInContentProcess() const550 bool nsDOMNavigationTiming::IsTopLevelContentDocumentInContentProcess() const {
551 if (!mDocShell) {
552 return false;
553 }
554 if (!XRE_IsContentProcess()) {
555 return false;
556 }
557 return mDocShell->GetBrowsingContext()->IsTopContent();
558 }
559
nsDOMNavigationTiming(nsDocShell * aDocShell,nsDOMNavigationTiming * aOther)560 nsDOMNavigationTiming::nsDOMNavigationTiming(nsDocShell* aDocShell,
561 nsDOMNavigationTiming* aOther)
562 : mDocShell(aDocShell),
563 mUnloadedURI(aOther->mUnloadedURI),
564 mLoadedURI(aOther->mLoadedURI),
565 mNavigationType(aOther->mNavigationType),
566 mNavigationStartHighRes(aOther->mNavigationStartHighRes),
567 mNavigationStart(aOther->mNavigationStart),
568 mNonBlankPaint(aOther->mNonBlankPaint),
569 mContentfulPaint(aOther->mContentfulPaint),
570 mDOMContentFlushed(aOther->mDOMContentFlushed),
571 mBeforeUnloadStart(aOther->mBeforeUnloadStart),
572 mUnloadStart(aOther->mUnloadStart),
573 mUnloadEnd(aOther->mUnloadEnd),
574 mLoadEventStart(aOther->mLoadEventStart),
575 mLoadEventEnd(aOther->mLoadEventEnd),
576 mDOMLoading(aOther->mDOMLoading),
577 mDOMInteractive(aOther->mDOMInteractive),
578 mDOMContentLoadedEventStart(aOther->mDOMContentLoadedEventStart),
579 mDOMContentLoadedEventEnd(aOther->mDOMContentLoadedEventEnd),
580 mDOMComplete(aOther->mDOMComplete),
581 mTTFI(aOther->mTTFI),
582 mDocShellHasBeenActiveSinceNavigationStart(
583 aOther->mDocShellHasBeenActiveSinceNavigationStart) {}
584
585 /* static */
Write(IPC::Message * aMsg,IProtocol * aActor,nsDOMNavigationTiming * aParam)586 void mozilla::ipc::IPDLParamTraits<nsDOMNavigationTiming*>::Write(
587 IPC::Message* aMsg, IProtocol* aActor, nsDOMNavigationTiming* aParam) {
588 RefPtr<nsIURI> unloadedURI = aParam->mUnloadedURI.get();
589 RefPtr<nsIURI> loadedURI = aParam->mLoadedURI.get();
590 WriteIPDLParam(aMsg, aActor, unloadedURI ? Some(unloadedURI) : Nothing());
591 WriteIPDLParam(aMsg, aActor, loadedURI ? Some(loadedURI) : Nothing());
592 WriteIPDLParam(aMsg, aActor, uint32_t(aParam->mNavigationType));
593 WriteIPDLParam(aMsg, aActor, aParam->mNavigationStartHighRes);
594 WriteIPDLParam(aMsg, aActor, aParam->mNavigationStart);
595 WriteIPDLParam(aMsg, aActor, aParam->mNonBlankPaint);
596 WriteIPDLParam(aMsg, aActor, aParam->mContentfulPaint);
597 WriteIPDLParam(aMsg, aActor, aParam->mDOMContentFlushed);
598 WriteIPDLParam(aMsg, aActor, aParam->mBeforeUnloadStart);
599 WriteIPDLParam(aMsg, aActor, aParam->mUnloadStart);
600 WriteIPDLParam(aMsg, aActor, aParam->mUnloadEnd);
601 WriteIPDLParam(aMsg, aActor, aParam->mLoadEventStart);
602 WriteIPDLParam(aMsg, aActor, aParam->mLoadEventEnd);
603 WriteIPDLParam(aMsg, aActor, aParam->mDOMLoading);
604 WriteIPDLParam(aMsg, aActor, aParam->mDOMInteractive);
605 WriteIPDLParam(aMsg, aActor, aParam->mDOMContentLoadedEventStart);
606 WriteIPDLParam(aMsg, aActor, aParam->mDOMContentLoadedEventEnd);
607 WriteIPDLParam(aMsg, aActor, aParam->mDOMComplete);
608 WriteIPDLParam(aMsg, aActor, aParam->mTTFI);
609 WriteIPDLParam(aMsg, aActor,
610 aParam->mDocShellHasBeenActiveSinceNavigationStart);
611 }
612
613 /* static */
Read(const IPC::Message * aMsg,PickleIterator * aIter,IProtocol * aActor,RefPtr<nsDOMNavigationTiming> * aResult)614 bool mozilla::ipc::IPDLParamTraits<nsDOMNavigationTiming*>::Read(
615 const IPC::Message* aMsg, PickleIterator* aIter, IProtocol* aActor,
616 RefPtr<nsDOMNavigationTiming>* aResult) {
617 auto timing = MakeRefPtr<nsDOMNavigationTiming>(nullptr);
618 uint32_t type;
619 Maybe<RefPtr<nsIURI>> unloadedURI;
620 Maybe<RefPtr<nsIURI>> loadedURI;
621 if (!ReadIPDLParam(aMsg, aIter, aActor, &unloadedURI) ||
622 !ReadIPDLParam(aMsg, aIter, aActor, &loadedURI) ||
623 !ReadIPDLParam(aMsg, aIter, aActor, &type) ||
624 !ReadIPDLParam(aMsg, aIter, aActor, &timing->mNavigationStartHighRes) ||
625 !ReadIPDLParam(aMsg, aIter, aActor, &timing->mNavigationStart) ||
626 !ReadIPDLParam(aMsg, aIter, aActor, &timing->mNonBlankPaint) ||
627 !ReadIPDLParam(aMsg, aIter, aActor, &timing->mContentfulPaint) ||
628 !ReadIPDLParam(aMsg, aIter, aActor, &timing->mDOMContentFlushed) ||
629 !ReadIPDLParam(aMsg, aIter, aActor, &timing->mBeforeUnloadStart) ||
630 !ReadIPDLParam(aMsg, aIter, aActor, &timing->mUnloadStart) ||
631 !ReadIPDLParam(aMsg, aIter, aActor, &timing->mUnloadEnd) ||
632 !ReadIPDLParam(aMsg, aIter, aActor, &timing->mLoadEventStart) ||
633 !ReadIPDLParam(aMsg, aIter, aActor, &timing->mLoadEventEnd) ||
634 !ReadIPDLParam(aMsg, aIter, aActor, &timing->mDOMLoading) ||
635 !ReadIPDLParam(aMsg, aIter, aActor, &timing->mDOMInteractive) ||
636 !ReadIPDLParam(aMsg, aIter, aActor,
637 &timing->mDOMContentLoadedEventStart) ||
638 !ReadIPDLParam(aMsg, aIter, aActor, &timing->mDOMContentLoadedEventEnd) ||
639 !ReadIPDLParam(aMsg, aIter, aActor, &timing->mDOMComplete) ||
640 !ReadIPDLParam(aMsg, aIter, aActor, &timing->mTTFI) ||
641 !ReadIPDLParam(aMsg, aIter, aActor,
642 &timing->mDocShellHasBeenActiveSinceNavigationStart)) {
643 return false;
644 }
645 timing->mNavigationType = nsDOMNavigationTiming::Type(type);
646 if (unloadedURI) {
647 timing->mUnloadedURI = std::move(*unloadedURI);
648 }
649 if (loadedURI) {
650 timing->mLoadedURI = std::move(*loadedURI);
651 }
652 *aResult = std::move(timing);
653 return true;
654 }
655