blob: 6d723113ca4efaf62ab0e979570c08a4af4e0cd9 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/renderer/render_frame_metadata_observer_impl.h"
#include <cmath>
#include "build/build_config.h"
#include "components/viz/common/quads/compositor_frame_metadata.h"
namespace content {
namespace {
#if defined(OS_ANDROID)
constexpr float kEdgeThreshold = 10.0f;
#endif
}
RenderFrameMetadataObserverImpl::RenderFrameMetadataObserverImpl(
mojom::RenderFrameMetadataObserverRequest request,
mojom::RenderFrameMetadataObserverClientPtrInfo client_info)
: request_(std::move(request)),
client_info_(std::move(client_info)),
render_frame_metadata_observer_binding_(this) {}
RenderFrameMetadataObserverImpl::~RenderFrameMetadataObserverImpl() {}
void RenderFrameMetadataObserverImpl::BindToCurrentThread() {
DCHECK(request_.is_pending());
render_frame_metadata_observer_binding_.Bind(std::move(request_));
render_frame_metadata_observer_client_.Bind(std::move(client_info_));
}
void RenderFrameMetadataObserverImpl::OnRenderFrameSubmission(
const cc::RenderFrameMetadata& render_frame_metadata,
viz::CompositorFrameMetadata* compositor_frame_metadata,
bool force_send) {
// By default only report metadata changes for fields which have a low
// frequency of change. However if there are changes in high frequency
// fields these can be reported while testing is enabled.
bool send_metadata = false;
bool needs_activation_notification = true;
if (render_frame_metadata_observer_client_) {
if (report_all_frame_submissions_for_testing_enabled_) {
last_frame_token_ = compositor_frame_metadata->frame_token;
compositor_frame_metadata->send_frame_token_to_embedder = true;
render_frame_metadata_observer_client_->OnFrameSubmissionForTesting(
last_frame_token_);
send_metadata = !last_render_frame_metadata_ ||
*last_render_frame_metadata_ != render_frame_metadata;
} else {
send_metadata = !last_render_frame_metadata_ ||
ShouldSendRenderFrameMetadata(
*last_render_frame_metadata_, render_frame_metadata,
&needs_activation_notification);
}
send_metadata |= force_send;
}
// Allways cache the full metadata, so that it can correctly be sent upon
// ReportAllFrameSubmissionsForTesting or
// ReportAllRootScrollsForAccessibility. This must only be done after we've
// compared the two for changes.
last_render_frame_metadata_ = render_frame_metadata;
// If the metadata is different, updates all the observers; or the metadata is
// generated for first time and same as the default value, update the default
// value to all the observers.
if (send_metadata && render_frame_metadata_observer_client_) {
auto metadata_copy = render_frame_metadata;
#if !defined(OS_ANDROID)
// On non-Android, sending |root_scroll_offset| outside of tests would
// leave the browser process with out of date information. It is an
// optional parameter which we clear here.
if (!report_all_frame_submissions_for_testing_enabled_)
metadata_copy.root_scroll_offset = base::nullopt;
#endif
last_frame_token_ = compositor_frame_metadata->frame_token;
compositor_frame_metadata->send_frame_token_to_embedder =
needs_activation_notification;
render_frame_metadata_observer_client_->OnRenderFrameMetadataChanged(
needs_activation_notification ? last_frame_token_ : 0u, metadata_copy);
TRACE_EVENT_WITH_FLOW1(
TRACE_DISABLED_BY_DEFAULT("viz.surface_id_flow"),
"RenderFrameMetadataObserverImpl::OnRenderFrameSubmission",
metadata_copy.local_surface_id_allocation &&
metadata_copy.local_surface_id_allocation->IsValid()
? metadata_copy.local_surface_id_allocation->local_surface_id()
.submission_trace_id() +
metadata_copy.local_surface_id_allocation->local_surface_id()
.embed_trace_id()
: 0,
TRACE_EVENT_FLAG_FLOW_OUT, "local_surface_id_allocation",
metadata_copy.local_surface_id_allocation
? metadata_copy.local_surface_id_allocation->local_surface_id()
.ToString()
: "null");
}
// Always cache the initial frame token, so that if a test connects later on
// it can be notified of the initial state.
if (!last_frame_token_) {
last_frame_token_ = compositor_frame_metadata->frame_token;
compositor_frame_metadata->send_frame_token_to_embedder =
needs_activation_notification;
}
}
#if defined(OS_ANDROID)
void RenderFrameMetadataObserverImpl::ReportAllRootScrollsForAccessibility(
bool enabled) {
report_all_root_scrolls_for_accessibility_enabled_ = enabled;
if (enabled)
SendLastRenderFrameMetadata();
}
#endif
void RenderFrameMetadataObserverImpl::ReportAllFrameSubmissionsForTesting(
bool enabled) {
report_all_frame_submissions_for_testing_enabled_ = enabled;
if (enabled)
SendLastRenderFrameMetadata();
}
void RenderFrameMetadataObserverImpl::SendLastRenderFrameMetadata() {
if (!last_frame_token_)
return;
// When enabled for testing send the cached metadata.
DCHECK(render_frame_metadata_observer_client_);
DCHECK(last_render_frame_metadata_.has_value());
render_frame_metadata_observer_client_->OnRenderFrameMetadataChanged(
last_frame_token_, *last_render_frame_metadata_);
}
bool RenderFrameMetadataObserverImpl::ShouldSendRenderFrameMetadata(
const cc::RenderFrameMetadata& rfm1,
const cc::RenderFrameMetadata& rfm2,
bool* needs_activation_notification) const {
if (rfm1.root_background_color != rfm2.root_background_color ||
rfm1.is_scroll_offset_at_top != rfm2.is_scroll_offset_at_top ||
rfm1.selection != rfm2.selection ||
rfm1.page_scale_factor != rfm2.page_scale_factor ||
rfm1.external_page_scale_factor != rfm2.external_page_scale_factor ||
rfm1.is_mobile_optimized != rfm2.is_mobile_optimized ||
rfm1.device_scale_factor != rfm2.device_scale_factor ||
rfm1.viewport_size_in_pixels != rfm2.viewport_size_in_pixels ||
rfm1.top_controls_height != rfm2.top_controls_height ||
rfm1.top_controls_shown_ratio != rfm2.top_controls_shown_ratio ||
rfm1.local_surface_id_allocation != rfm2.local_surface_id_allocation) {
*needs_activation_notification = true;
return true;
}
#if defined(OS_ANDROID)
bool need_send_root_scroll =
report_all_root_scrolls_for_accessibility_enabled_ &&
rfm1.root_scroll_offset != rfm2.root_scroll_offset;
if (rfm1.bottom_controls_height != rfm2.bottom_controls_height ||
rfm1.bottom_controls_shown_ratio != rfm2.bottom_controls_shown_ratio ||
rfm1.min_page_scale_factor != rfm2.min_page_scale_factor ||
rfm1.max_page_scale_factor != rfm2.max_page_scale_factor ||
rfm1.root_overflow_y_hidden != rfm2.root_overflow_y_hidden ||
rfm1.scrollable_viewport_size != rfm2.scrollable_viewport_size ||
rfm1.root_layer_size != rfm2.root_layer_size ||
rfm1.has_transparent_background != rfm2.has_transparent_background ||
need_send_root_scroll) {
*needs_activation_notification = true;
return true;
}
gfx::Vector2dF old_root_scroll_offset =
rfm1.root_scroll_offset.value_or(gfx::Vector2dF());
gfx::Vector2dF new_root_scroll_offset =
rfm2.root_scroll_offset.value_or(gfx::Vector2dF());
gfx::RectF old_viewport_rect(
gfx::PointF(old_root_scroll_offset.x(), old_root_scroll_offset.y()),
rfm1.scrollable_viewport_size);
gfx::RectF new_viewport_rect(
gfx::PointF(new_root_scroll_offset.x(), new_root_scroll_offset.y()),
rfm2.scrollable_viewport_size);
gfx::RectF new_root_layer_rect(rfm2.root_layer_size);
bool at_left_or_right_edge =
rfm2.root_layer_size.width() > rfm2.scrollable_viewport_size.width() &&
(std::abs(new_viewport_rect.right() - new_root_layer_rect.right()) <
kEdgeThreshold ||
std::abs(new_viewport_rect.x() - new_root_layer_rect.x()) <
kEdgeThreshold);
bool at_top_or_bottom_edge =
rfm2.root_layer_size.height() > rfm2.scrollable_viewport_size.height() &&
(std::abs(new_viewport_rect.y() - new_root_layer_rect.y()) <
kEdgeThreshold ||
std::abs(new_viewport_rect.bottom() - new_root_layer_rect.bottom()) <
kEdgeThreshold);
if (old_viewport_rect != new_viewport_rect &&
(at_left_or_right_edge || at_top_or_bottom_edge)) {
*needs_activation_notification = false;
return true;
}
#endif
*needs_activation_notification = false;
return false;
}
} // namespace content