| Index: chrome/browser/page_load_metrics/page_load_tracker.cc
|
| diff --git a/chrome/browser/page_load_metrics/page_load_tracker.cc b/chrome/browser/page_load_metrics/page_load_tracker.cc
|
| index 77d31f62cb34f6d1d91ea4d8c66f759988976674..fbad01c9140dc1c3af69ab4836c1ac571d5dae3e 100644
|
| --- a/chrome/browser/page_load_metrics/page_load_tracker.cc
|
| +++ b/chrome/browser/page_load_metrics/page_load_tracker.cc
|
| @@ -63,6 +63,8 @@ const char kPageLoadStartedInForeground[] =
|
| "PageLoad.Internal.NavigationStartedInForeground";
|
| const char kPageLoadPrerender[] = "PageLoad.Internal.Prerender";
|
| const char kPageLoadTimingStatus[] = "PageLoad.Internal.PageLoadTimingStatus";
|
| +const char kPageLoadTimingDispatchStatus[] =
|
| + "PageLoad.Internal.PageLoadTimingStatus.AtTimingCallbackDispatch";
|
|
|
| } // namespace internal
|
|
|
| @@ -642,19 +644,10 @@ void PageLoadTracker::UpdateSubFrameTiming(
|
| }
|
|
|
| base::TimeDelta navigation_start_offset = it->second;
|
| - const PageLoadTiming last_timing = merged_page_timing_;
|
| MergePaintTiming(navigation_start_offset, new_timing.paint_timing,
|
| false /* is_main_frame */);
|
|
|
| - if (last_timing == merged_page_timing_)
|
| - return;
|
| -
|
| - const PageLoadExtraInfo info = ComputePageLoadExtraInfo();
|
| - for (const auto& observer : observers_) {
|
| - DispatchObserverTimingCallbacks(observer.get(), last_timing,
|
| - merged_page_timing_, main_frame_metadata_,
|
| - info);
|
| - }
|
| + DispatchTimingUpdates();
|
| }
|
|
|
| void PageLoadTracker::MergePaintTiming(
|
| @@ -733,22 +726,56 @@ void PageLoadTracker::UpdateTiming(const PageLoadTiming& new_timing,
|
| // Thus, we make a copy of timing here, update timing_ and
|
| // main_frame_metadata_, and then proceed to dispatch the observer timing
|
| // callbacks.
|
| - const PageLoadTiming last_timing = merged_page_timing_;
|
| + const PaintTiming last_paint_timing = merged_page_timing_.paint_timing;
|
|
|
| // Update the merged_page_timing_, making sure to merge the previously
|
| // observed |paint_timing|, which is tracked across all frames in the page.
|
| merged_page_timing_ = new_timing;
|
| - merged_page_timing_.paint_timing = last_timing.paint_timing;
|
| + merged_page_timing_.paint_timing = last_paint_timing;
|
| MergePaintTiming(base::TimeDelta(), new_timing.paint_timing,
|
| true /* is_main_frame */);
|
|
|
| - const PageLoadMetadata last_metadata = main_frame_metadata_;
|
| main_frame_metadata_ = new_metadata;
|
| +
|
| + DispatchTimingUpdates();
|
| +}
|
| +
|
| +void PageLoadTracker::DispatchTimingUpdates() {
|
| + if (last_dispatched_merged_page_timing_ == merged_page_timing_ &&
|
| + last_dispatched_main_frame_metadata_ == main_frame_metadata_) {
|
| + return;
|
| + }
|
| +
|
| + if (merged_page_timing_.paint_timing.first_paint) {
|
| + if (!merged_page_timing_.parse_timing.parse_start ||
|
| + !merged_page_timing_.document_timing.first_layout) {
|
| + // When merging paint events across frames, we can sometimes encounter
|
| + // cases where we've received a first paint event for a child frame before
|
| + // receiving required earlier events in the main frame, due to buffering
|
| + // in the render process which results in out of order delivery. For
|
| + // example, we may receive a notification for a first paint in a child
|
| + // frame before we've received a notification for parse start or first
|
| + // layout in the main frame. In these cases, we delay sending timing
|
| + // updates until we've received all expected events (e.g. wait to receive
|
| + // a parse or layout event before dispatching a paint event), so observers
|
| + // can make assumptions about ordering of these events in their callbacks.
|
| + return;
|
| + }
|
| + }
|
| +
|
| + internal::PageLoadTimingStatus status =
|
| + IsValidPageLoadTiming(merged_page_timing_);
|
| + UMA_HISTOGRAM_ENUMERATION(internal::kPageLoadTimingDispatchStatus, status,
|
| + internal::LAST_PAGE_LOAD_TIMING_STATUS);
|
| +
|
| const PageLoadExtraInfo info = ComputePageLoadExtraInfo();
|
| for (const auto& observer : observers_) {
|
| - DispatchObserverTimingCallbacks(observer.get(), last_timing,
|
| - merged_page_timing_, last_metadata, info);
|
| + DispatchObserverTimingCallbacks(
|
| + observer.get(), last_dispatched_merged_page_timing_,
|
| + merged_page_timing_, last_dispatched_main_frame_metadata_, info);
|
| }
|
| + last_dispatched_merged_page_timing_ = merged_page_timing_;
|
| + last_dispatched_main_frame_metadata_ = main_frame_metadata_;
|
| }
|
|
|
| void PageLoadTracker::OnStartedResource(
|
|
|