| OLD | NEW |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/page_load_metrics/page_load_metrics_update_dispatcher.h
" | 5 #include "chrome/browser/page_load_metrics/page_load_metrics_update_dispatcher.h
" |
| 6 | 6 |
| 7 #include <ostream> | 7 #include <ostream> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/metrics/histogram_macros.h" | 11 #include "base/metrics/histogram_macros.h" |
| 12 #include "base/optional.h" | 12 #include "base/optional.h" |
| 13 #include "chrome/browser/page_load_metrics/browser_page_track_decider.h" | 13 #include "chrome/browser/page_load_metrics/browser_page_track_decider.h" |
| 14 #include "chrome/browser/page_load_metrics/page_load_metrics_embedder_interface.
h" | 14 #include "chrome/browser/page_load_metrics/page_load_metrics_embedder_interface.
h" |
| 15 #include "chrome/browser/page_load_metrics/page_load_metrics_util.h" | 15 #include "chrome/browser/page_load_metrics/page_load_metrics_util.h" |
| 16 #include "chrome/browser/page_load_metrics/page_load_tracker.h" | 16 #include "chrome/browser/page_load_metrics/page_load_tracker.h" |
| 17 #include "chrome/common/page_load_metrics/page_load_metrics_constants.h" | 17 #include "chrome/common/page_load_metrics/page_load_metrics_constants.h" |
| 18 #include "content/public/browser/navigation_handle.h" | 18 #include "content/public/browser/navigation_handle.h" |
| 19 #include "content/public/browser/render_frame_host.h" | 19 #include "content/public/browser/render_frame_host.h" |
| 20 | 20 |
| 21 namespace page_load_metrics { | 21 namespace page_load_metrics { |
| 22 | 22 |
| 23 namespace internal { | 23 namespace internal { |
| 24 | 24 |
| 25 const char kPageLoadTimingStatus[] = "PageLoad.Internal.PageLoadTimingStatus"; | 25 const char kPageLoadTimingStatus[] = "PageLoad.Internal.PageLoadTimingStatus"; |
| 26 const char kPageLoadTimingDispatchStatus[] = | 26 const char kPageLoadTimingDispatchStatus[] = |
| 27 "PageLoad.Internal.PageLoadTimingStatus.AtTimingCallbackDispatch"; | 27 "PageLoad.Internal.PageLoadTimingStatus.AtTimingCallbackDispatch"; |
| 28 const char kHistogramOutOfOrderTiming[] = |
| 29 "PageLoad.Internal.OutOfOrderInterFrameTiming"; |
| 30 const char kHistogramOutOfOrderTimingBuffered[] = |
| 31 "PageLoad.Internal.OutOfOrderInterFrameTiming.AfterBuffering"; |
| 28 | 32 |
| 29 } // namespace internal | 33 } // namespace internal |
| 30 | 34 |
| 31 namespace { | 35 namespace { |
| 32 | 36 |
| 33 // Helper to allow use of Optional<> values in LOG() messages. | 37 // Helper to allow use of Optional<> values in LOG() messages. |
| 34 std::ostream& operator<<(std::ostream& os, | 38 std::ostream& operator<<(std::ostream& os, |
| 35 const base::Optional<base::TimeDelta>& opt) { | 39 const base::Optional<base::TimeDelta>& opt) { |
| 36 if (opt) | 40 if (opt) |
| 37 os << opt.value(); | 41 os << opt.value(); |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 193 timing.paint_timing->first_meaningful_paint)) { | 197 timing.paint_timing->first_meaningful_paint)) { |
| 194 LOG(ERROR) << "Invalid first_paint " << timing.paint_timing->first_paint | 198 LOG(ERROR) << "Invalid first_paint " << timing.paint_timing->first_paint |
| 195 << " for first_meaningful_paint " | 199 << " for first_meaningful_paint " |
| 196 << timing.paint_timing->first_meaningful_paint; | 200 << timing.paint_timing->first_meaningful_paint; |
| 197 return internal::INVALID_ORDER_FIRST_PAINT_FIRST_MEANINGFUL_PAINT; | 201 return internal::INVALID_ORDER_FIRST_PAINT_FIRST_MEANINGFUL_PAINT; |
| 198 } | 202 } |
| 199 | 203 |
| 200 return internal::VALID; | 204 return internal::VALID; |
| 201 } | 205 } |
| 202 | 206 |
| 207 // If the updated value has an earlier time than the current value, log so we |
| 208 // can keep track of how often this happens. |
| 209 void LogIfOutOfOrderTiming(const base::Optional<base::TimeDelta>& current, |
| 210 const base::Optional<base::TimeDelta>& update) { |
| 211 if (!current || !update) |
| 212 return; |
| 213 |
| 214 if (update < current) { |
| 215 PAGE_LOAD_HISTOGRAM(internal::kHistogramOutOfOrderTimingBuffered, |
| 216 current.value() - update.value()); |
| 217 } |
| 218 } |
| 219 |
| 220 // PaintTimingMerger merges paint timing values received from different frames |
| 221 // together. |
| 222 class PaintTimingMerger { |
| 223 public: |
| 224 explicit PaintTimingMerger(mojom::PaintTiming* target) : target_(target) {} |
| 225 |
| 226 // Merge paint timing values from |new_paint_timing| into the target |
| 227 // PaintTiming. |
| 228 void Merge(base::TimeDelta navigation_start_offset, |
| 229 const mojom::PaintTiming& new_paint_timing, |
| 230 bool is_main_frame); |
| 231 |
| 232 // Whether we merged a new value, for a paint timing field we didn't |
| 233 // previously have a value for in the target PaintTiming. |
| 234 bool did_merge_new_timing_value() const { |
| 235 return did_merge_new_timing_value_; |
| 236 } |
| 237 |
| 238 private: |
| 239 void MaybeUpdateTimeDelta( |
| 240 base::Optional<base::TimeDelta>* inout_existing_value, |
| 241 base::TimeDelta navigation_start_offset, |
| 242 const base::Optional<base::TimeDelta>& optional_candidate_new_value); |
| 243 |
| 244 // The target PaintTiming we are merging values into. |
| 245 mojom::PaintTiming* const target_; |
| 246 |
| 247 // Whether we merged a new value, for a paint timing field we didn't |
| 248 // previously have a value for in |target_|. |
| 249 bool did_merge_new_timing_value_ = false; |
| 250 |
| 251 DISALLOW_COPY_AND_ASSIGN(PaintTimingMerger); |
| 252 }; |
| 253 |
| 203 // Updates *|inout_existing_value| with |optional_candidate_new_value|, if | 254 // Updates *|inout_existing_value| with |optional_candidate_new_value|, if |
| 204 // either *|inout_existing_value| isn't set, or |optional_candidate_new_value| < | 255 // either *|inout_existing_value| isn't set, or |optional_candidate_new_value| < |
| 205 // |inout_existing_value|. | 256 // |inout_existing_value|. |
| 206 void MaybeUpdateTimeDelta( | 257 void PaintTimingMerger::MaybeUpdateTimeDelta( |
| 207 base::Optional<base::TimeDelta>* inout_existing_value, | 258 base::Optional<base::TimeDelta>* inout_existing_value, |
| 208 base::TimeDelta navigation_start_offset, | 259 base::TimeDelta navigation_start_offset, |
| 209 const base::Optional<base::TimeDelta>& optional_candidate_new_value) { | 260 const base::Optional<base::TimeDelta>& optional_candidate_new_value) { |
| 210 // If we don't get a new value, there's nothing to do | 261 // If we don't get a new value, there's nothing to do |
| 211 if (!optional_candidate_new_value) | 262 if (!optional_candidate_new_value) |
| 212 return; | 263 return; |
| 213 | 264 |
| 214 // optional_candidate_new_value is relative to navigation start in its | 265 // optional_candidate_new_value is relative to navigation start in its |
| 215 // frame. We need to adjust it to be relative to navigation start in the main | 266 // frame. We need to adjust it to be relative to navigation start in the main |
| 216 // frame, so offset it by navigation_start_offset. | 267 // frame, so offset it by navigation_start_offset. |
| 217 base::TimeDelta candidate_new_value = | 268 base::TimeDelta candidate_new_value = |
| 218 navigation_start_offset + optional_candidate_new_value.value(); | 269 navigation_start_offset + optional_candidate_new_value.value(); |
| 219 | 270 |
| 220 if (*inout_existing_value) { | 271 if (*inout_existing_value) { |
| 221 // If we have a new value, but it is after the existing value, then keep the | 272 // If we have a new value, but it is after the existing value, then keep the |
| 222 // existing value. | 273 // existing value. |
| 223 if (*inout_existing_value <= candidate_new_value) | 274 if (*inout_existing_value <= candidate_new_value) |
| 224 return; | 275 return; |
| 225 | 276 |
| 226 // We received a new timing event, but with a timestamp before the timestamp | 277 // We received a new timing event, but with a timestamp before the timestamp |
| 227 // of a timing update we had received previously. We expect this to happen | 278 // of a timing update we had received previously. We expect this to happen |
| 228 // occasionally, as inter-frame updates can arrive out of order. Record a | 279 // occasionally, as inter-frame updates can arrive out of order. Record a |
| 229 // histogram to track how frequently it happens, along with the magnitude | 280 // histogram to track how frequently it happens, along with the magnitude |
| 230 // of the delta. | 281 // of the delta. |
| 231 PAGE_LOAD_HISTOGRAM("PageLoad.Internal.OutOfOrderInterFrameTiming", | 282 PAGE_LOAD_HISTOGRAM(internal::kHistogramOutOfOrderTiming, |
| 232 inout_existing_value->value() - candidate_new_value); | 283 inout_existing_value->value() - candidate_new_value); |
| 284 } else { |
| 285 did_merge_new_timing_value_ = true; |
| 233 } | 286 } |
| 234 | 287 |
| 235 *inout_existing_value = candidate_new_value; | 288 *inout_existing_value = candidate_new_value; |
| 236 } | 289 } |
| 237 | 290 |
| 291 void PaintTimingMerger::Merge(base::TimeDelta navigation_start_offset, |
| 292 const mojom::PaintTiming& new_paint_timing, |
| 293 bool is_main_frame) { |
| 294 MaybeUpdateTimeDelta(&target_->first_paint, navigation_start_offset, |
| 295 new_paint_timing.first_paint); |
| 296 MaybeUpdateTimeDelta(&target_->first_text_paint, navigation_start_offset, |
| 297 new_paint_timing.first_text_paint); |
| 298 MaybeUpdateTimeDelta(&target_->first_image_paint, navigation_start_offset, |
| 299 new_paint_timing.first_image_paint); |
| 300 MaybeUpdateTimeDelta(&target_->first_contentful_paint, |
| 301 navigation_start_offset, |
| 302 new_paint_timing.first_contentful_paint); |
| 303 if (is_main_frame) { |
| 304 // First meaningful paint is only tracked in the main frame. |
| 305 target_->first_meaningful_paint = new_paint_timing.first_meaningful_paint; |
| 306 } |
| 307 } |
| 308 |
| 238 } // namespace | 309 } // namespace |
| 239 | 310 |
| 240 PageLoadMetricsUpdateDispatcher::PageLoadMetricsUpdateDispatcher( | 311 PageLoadMetricsUpdateDispatcher::PageLoadMetricsUpdateDispatcher( |
| 241 PageLoadMetricsUpdateDispatcher::Client* client, | 312 PageLoadMetricsUpdateDispatcher::Client* client, |
| 242 content::NavigationHandle* navigation_handle, | 313 content::NavigationHandle* navigation_handle, |
| 243 PageLoadMetricsEmbedderInterface* embedder_interface) | 314 PageLoadMetricsEmbedderInterface* embedder_interface) |
| 244 : client_(client), | 315 : client_(client), |
| 245 embedder_interface_(embedder_interface), | 316 embedder_interface_(embedder_interface), |
| 317 timer_(embedder_interface->CreateTimer()), |
| 246 navigation_start_(navigation_handle->NavigationStart()), | 318 navigation_start_(navigation_handle->NavigationStart()), |
| 247 current_merged_page_timing_(CreatePageLoadTiming()), | 319 current_merged_page_timing_(CreatePageLoadTiming()), |
| 248 pending_merged_page_timing_(CreatePageLoadTiming()), | 320 pending_merged_page_timing_(CreatePageLoadTiming()), |
| 249 main_frame_metadata_(mojom::PageLoadMetadata::New()), | 321 main_frame_metadata_(mojom::PageLoadMetadata::New()), |
| 250 subframe_metadata_(mojom::PageLoadMetadata::New()) {} | 322 subframe_metadata_(mojom::PageLoadMetadata::New()) {} |
| 251 | 323 |
| 252 PageLoadMetricsUpdateDispatcher::~PageLoadMetricsUpdateDispatcher() {} | 324 PageLoadMetricsUpdateDispatcher::~PageLoadMetricsUpdateDispatcher() { |
| 325 ShutDown(); |
| 326 } |
| 327 |
| 328 void PageLoadMetricsUpdateDispatcher::ShutDown() { |
| 329 if (timer_ && timer_->IsRunning()) { |
| 330 timer_->Stop(); |
| 331 DispatchTimingUpdates(); |
| 332 } |
| 333 timer_ = nullptr; |
| 334 } |
| 253 | 335 |
| 254 void PageLoadMetricsUpdateDispatcher::UpdateMetrics( | 336 void PageLoadMetricsUpdateDispatcher::UpdateMetrics( |
| 255 content::RenderFrameHost* render_frame_host, | 337 content::RenderFrameHost* render_frame_host, |
| 256 const mojom::PageLoadTiming& new_timing, | 338 const mojom::PageLoadTiming& new_timing, |
| 257 const mojom::PageLoadMetadata& new_metadata) { | 339 const mojom::PageLoadMetadata& new_metadata) { |
| 258 if (render_frame_host->GetParent() == nullptr) { | 340 if (render_frame_host->GetParent() == nullptr) { |
| 259 UpdateMainFrameMetadata(new_metadata); | 341 UpdateMainFrameMetadata(new_metadata); |
| 260 UpdateMainFrameTiming(new_timing); | 342 UpdateMainFrameTiming(new_timing); |
| 261 } else { | 343 } else { |
| 262 UpdateSubFrameMetadata(new_metadata); | 344 UpdateSubFrameMetadata(new_metadata); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 296 const auto it = subframe_navigation_start_offset_.find( | 378 const auto it = subframe_navigation_start_offset_.find( |
| 297 render_frame_host->GetFrameTreeNodeId()); | 379 render_frame_host->GetFrameTreeNodeId()); |
| 298 if (it == subframe_navigation_start_offset_.end()) { | 380 if (it == subframe_navigation_start_offset_.end()) { |
| 299 // We received timing information for an untracked load. Ignore it. | 381 // We received timing information for an untracked load. Ignore it. |
| 300 return; | 382 return; |
| 301 } | 383 } |
| 302 | 384 |
| 303 client_->OnSubFrameTimingChanged(new_timing); | 385 client_->OnSubFrameTimingChanged(new_timing); |
| 304 | 386 |
| 305 base::TimeDelta navigation_start_offset = it->second; | 387 base::TimeDelta navigation_start_offset = it->second; |
| 306 MergePaintTiming(navigation_start_offset, *(new_timing.paint_timing), | 388 PaintTimingMerger merger(pending_merged_page_timing_->paint_timing.get()); |
| 307 false /* is_main_frame */); | 389 merger.Merge(navigation_start_offset, *new_timing.paint_timing, |
| 390 false /* is_main_frame */); |
| 308 | 391 |
| 309 DispatchTimingUpdates(); | 392 MaybeDispatchTimingUpdates(merger.did_merge_new_timing_value()); |
| 310 } | |
| 311 | |
| 312 void PageLoadMetricsUpdateDispatcher::MergePaintTiming( | |
| 313 base::TimeDelta navigation_start_offset, | |
| 314 const mojom::PaintTiming& new_paint_timing, | |
| 315 bool is_main_frame) { | |
| 316 MaybeUpdateTimeDelta(&pending_merged_page_timing_->paint_timing->first_paint, | |
| 317 navigation_start_offset, new_paint_timing.first_paint); | |
| 318 MaybeUpdateTimeDelta( | |
| 319 &pending_merged_page_timing_->paint_timing->first_text_paint, | |
| 320 navigation_start_offset, new_paint_timing.first_text_paint); | |
| 321 MaybeUpdateTimeDelta( | |
| 322 &pending_merged_page_timing_->paint_timing->first_image_paint, | |
| 323 navigation_start_offset, new_paint_timing.first_image_paint); | |
| 324 MaybeUpdateTimeDelta( | |
| 325 &pending_merged_page_timing_->paint_timing->first_contentful_paint, | |
| 326 navigation_start_offset, new_paint_timing.first_contentful_paint); | |
| 327 if (is_main_frame) { | |
| 328 // first meaningful paint is only tracked in the main frame. | |
| 329 pending_merged_page_timing_->paint_timing->first_meaningful_paint = | |
| 330 new_paint_timing.first_meaningful_paint; | |
| 331 } | |
| 332 } | 393 } |
| 333 | 394 |
| 334 void PageLoadMetricsUpdateDispatcher::UpdateSubFrameMetadata( | 395 void PageLoadMetricsUpdateDispatcher::UpdateSubFrameMetadata( |
| 335 const mojom::PageLoadMetadata& subframe_metadata) { | 396 const mojom::PageLoadMetadata& subframe_metadata) { |
| 336 // Merge the subframe loading behavior flags with any we've already observed, | 397 // Merge the subframe loading behavior flags with any we've already observed, |
| 337 // possibly from other subframes. | 398 // possibly from other subframes. |
| 338 const int last_subframe_loading_behavior_flags = | 399 const int last_subframe_loading_behavior_flags = |
| 339 subframe_metadata_->behavior_flags; | 400 subframe_metadata_->behavior_flags; |
| 340 subframe_metadata_->behavior_flags |= subframe_metadata.behavior_flags; | 401 subframe_metadata_->behavior_flags |= subframe_metadata.behavior_flags; |
| 341 if (last_subframe_loading_behavior_flags == | 402 if (last_subframe_loading_behavior_flags == |
| (...skipping 25 matching lines...) Expand all Loading... |
| 367 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_TIMING); | 428 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_TIMING); |
| 368 return; | 429 return; |
| 369 } | 430 } |
| 370 | 431 |
| 371 mojom::PaintTimingPtr last_paint_timing = | 432 mojom::PaintTimingPtr last_paint_timing = |
| 372 std::move(pending_merged_page_timing_->paint_timing); | 433 std::move(pending_merged_page_timing_->paint_timing); |
| 373 // Update the pending_merged_page_timing_, making sure to merge the previously | 434 // Update the pending_merged_page_timing_, making sure to merge the previously |
| 374 // observed |paint_timing|, which is tracked across all frames in the page. | 435 // observed |paint_timing|, which is tracked across all frames in the page. |
| 375 pending_merged_page_timing_ = new_timing.Clone(); | 436 pending_merged_page_timing_ = new_timing.Clone(); |
| 376 pending_merged_page_timing_->paint_timing = std::move(last_paint_timing); | 437 pending_merged_page_timing_->paint_timing = std::move(last_paint_timing); |
| 377 MergePaintTiming(base::TimeDelta(), *new_timing.paint_timing, | |
| 378 true /* is_main_frame */); | |
| 379 | 438 |
| 380 DispatchTimingUpdates(); | 439 PaintTimingMerger merger(pending_merged_page_timing_->paint_timing.get()); |
| 440 merger.Merge(base::TimeDelta(), *new_timing.paint_timing, |
| 441 true /* is_main_frame */); |
| 442 |
| 443 MaybeDispatchTimingUpdates(merger.did_merge_new_timing_value()); |
| 381 } | 444 } |
| 382 | 445 |
| 383 void PageLoadMetricsUpdateDispatcher::UpdateMainFrameMetadata( | 446 void PageLoadMetricsUpdateDispatcher::UpdateMainFrameMetadata( |
| 384 const mojom::PageLoadMetadata& new_metadata) { | 447 const mojom::PageLoadMetadata& new_metadata) { |
| 385 if (main_frame_metadata_->Equals(new_metadata)) | 448 if (main_frame_metadata_->Equals(new_metadata)) |
| 386 return; | 449 return; |
| 387 | 450 |
| 388 // Ensure flags sent previously are still present in the new metadata fields. | 451 // Ensure flags sent previously are still present in the new metadata fields. |
| 389 const bool valid_behavior_descendent = | 452 const bool valid_behavior_descendent = |
| 390 (main_frame_metadata_->behavior_flags & new_metadata.behavior_flags) == | 453 (main_frame_metadata_->behavior_flags & new_metadata.behavior_flags) == |
| 391 main_frame_metadata_->behavior_flags; | 454 main_frame_metadata_->behavior_flags; |
| 392 if (!valid_behavior_descendent) { | 455 if (!valid_behavior_descendent) { |
| 393 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_BEHAVIOR_DESCENDENT); | 456 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_BEHAVIOR_DESCENDENT); |
| 394 return; | 457 return; |
| 395 } | 458 } |
| 396 | 459 |
| 397 main_frame_metadata_ = new_metadata.Clone(); | 460 main_frame_metadata_ = new_metadata.Clone(); |
| 398 client_->OnMainFrameMetadataChanged(); | 461 client_->OnMainFrameMetadataChanged(); |
| 399 } | 462 } |
| 400 | 463 |
| 464 void PageLoadMetricsUpdateDispatcher::MaybeDispatchTimingUpdates( |
| 465 bool did_merge_new_timing_value) { |
| 466 // If we merged a new timing value, then we should buffer updates for |
| 467 // |kBufferTimerDelayMillis|, to allow for any other out of order timings to |
| 468 // arrive before we dispatch the minimum observed timings to observers. |
| 469 if (did_merge_new_timing_value) { |
| 470 timer_->Start( |
| 471 FROM_HERE, base::TimeDelta::FromMilliseconds(kBufferTimerDelayMillis), |
| 472 base::Bind(&PageLoadMetricsUpdateDispatcher::DispatchTimingUpdates, |
| 473 base::Unretained(this))); |
| 474 } else if (!timer_->IsRunning()) { |
| 475 DispatchTimingUpdates(); |
| 476 } |
| 477 } |
| 478 |
| 401 void PageLoadMetricsUpdateDispatcher::DispatchTimingUpdates() { | 479 void PageLoadMetricsUpdateDispatcher::DispatchTimingUpdates() { |
| 480 DCHECK(!timer_->IsRunning()); |
| 481 |
| 402 if (pending_merged_page_timing_->paint_timing->first_paint) { | 482 if (pending_merged_page_timing_->paint_timing->first_paint) { |
| 403 if (!pending_merged_page_timing_->parse_timing->parse_start || | 483 if (!pending_merged_page_timing_->parse_timing->parse_start || |
| 404 !pending_merged_page_timing_->document_timing->first_layout) { | 484 !pending_merged_page_timing_->document_timing->first_layout) { |
| 405 // When merging paint events across frames, we can sometimes encounter | 485 // When merging paint events across frames, we can sometimes encounter |
| 406 // cases where we've received a first paint event for a child frame before | 486 // cases where we've received a first paint event for a child frame before |
| 407 // receiving required earlier events in the main frame, due to buffering | 487 // receiving required earlier events in the main frame, due to buffering |
| 408 // in the render process which results in out of order delivery. For | 488 // in the render process which results in out of order delivery. For |
| 409 // example, we may receive a notification for a first paint in a child | 489 // example, we may receive a notification for a first paint in a child |
| 410 // frame before we've received a notification for parse start or first | 490 // frame before we've received a notification for parse start or first |
| 411 // layout in the main frame. In these cases, we delay sending timing | 491 // layout in the main frame. In these cases, we delay sending timing |
| 412 // updates until we've received all expected events (e.g. wait to receive | 492 // updates until we've received all expected events (e.g. wait to receive |
| 413 // a parse or layout event before dispatching a paint event), so observers | 493 // a parse or layout event before dispatching a paint event), so observers |
| 414 // can make assumptions about ordering of these events in their callbacks. | 494 // can make assumptions about ordering of these events in their callbacks. |
| 415 return; | 495 return; |
| 416 } | 496 } |
| 417 } | 497 } |
| 418 | 498 |
| 419 if (current_merged_page_timing_->Equals(*pending_merged_page_timing_)) | 499 if (current_merged_page_timing_->Equals(*pending_merged_page_timing_)) |
| 420 return; | 500 return; |
| 501 |
| 502 LogIfOutOfOrderTiming(current_merged_page_timing_->paint_timing->first_paint, |
| 503 pending_merged_page_timing_->paint_timing->first_paint); |
| 504 LogIfOutOfOrderTiming( |
| 505 current_merged_page_timing_->paint_timing->first_text_paint, |
| 506 pending_merged_page_timing_->paint_timing->first_text_paint); |
| 507 LogIfOutOfOrderTiming( |
| 508 current_merged_page_timing_->paint_timing->first_image_paint, |
| 509 pending_merged_page_timing_->paint_timing->first_image_paint); |
| 510 LogIfOutOfOrderTiming( |
| 511 current_merged_page_timing_->paint_timing->first_contentful_paint, |
| 512 pending_merged_page_timing_->paint_timing->first_contentful_paint); |
| 513 |
| 421 current_merged_page_timing_ = pending_merged_page_timing_->Clone(); | 514 current_merged_page_timing_ = pending_merged_page_timing_->Clone(); |
| 422 | 515 |
| 423 internal::PageLoadTimingStatus status = | 516 internal::PageLoadTimingStatus status = |
| 424 IsValidPageLoadTiming(*pending_merged_page_timing_); | 517 IsValidPageLoadTiming(*pending_merged_page_timing_); |
| 425 UMA_HISTOGRAM_ENUMERATION(internal::kPageLoadTimingDispatchStatus, status, | 518 UMA_HISTOGRAM_ENUMERATION(internal::kPageLoadTimingDispatchStatus, status, |
| 426 internal::LAST_PAGE_LOAD_TIMING_STATUS); | 519 internal::LAST_PAGE_LOAD_TIMING_STATUS); |
| 427 | 520 |
| 428 client_->OnTimingChanged(); | 521 client_->OnTimingChanged(); |
| 429 } | 522 } |
| 430 | 523 |
| 431 } // namespace page_load_metrics | 524 } // namespace page_load_metrics |
| OLD | NEW |