blob: 5de1bcc845af80c21101cde424ffb1403fb05d35 [file] [log] [blame]
// Copyright 2014 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/browser/renderer_host/delegated_frame_host.h"
#include <algorithm>
#include <string>
#include <utility>
#include <vector>
#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/memory/ptr_util.h"
#include "base/time/default_tick_clock.h"
#include "cc/base/switches.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/quads/compositor_frame.h"
#include "components/viz/common/resources/single_release_callback.h"
#include "components/viz/common/switches.h"
#include "components/viz/host/host_frame_sink_manager.h"
#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
#include "components/viz/service/surfaces/surface_hittest.h"
#include "content/browser/compositor/surface_utils.h"
#include "content/browser/gpu/compositor_util.h"
#include "content/browser/renderer_host/compositor_resize_lock.h"
#include "content/public/common/content_switches.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/geometry/dip_util.h"
namespace content {
////////////////////////////////////////////////////////////////////////////////
// DelegatedFrameHost
DelegatedFrameHost::DelegatedFrameHost(const viz::FrameSinkId& frame_sink_id,
DelegatedFrameHostClient* client,
bool enable_surface_synchronization,
bool enable_viz)
: frame_sink_id_(frame_sink_id),
client_(client),
enable_surface_synchronization_(enable_surface_synchronization),
enable_viz_(enable_viz),
tick_clock_(base::DefaultTickClock::GetInstance()),
frame_evictor_(std::make_unique<viz::FrameEvictor>(this)) {
ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
factory->GetContextFactory()->AddObserver(this);
viz::HostFrameSinkManager* host_frame_sink_manager =
factory->GetContextFactoryPrivate()->GetHostFrameSinkManager();
host_frame_sink_manager->RegisterFrameSinkId(frame_sink_id_, this);
host_frame_sink_manager->EnableSynchronizationReporting(
frame_sink_id_, "Compositing.MainFrameSynchronization.Duration");
host_frame_sink_manager->SetFrameSinkDebugLabel(frame_sink_id_,
"DelegatedFrameHost");
CreateCompositorFrameSinkSupport();
}
DelegatedFrameHost::~DelegatedFrameHost() {
DCHECK(!compositor_);
ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
factory->GetContextFactory()->RemoveObserver(this);
ResetCompositorFrameSinkSupport();
viz::HostFrameSinkManager* host_frame_sink_manager =
factory->GetContextFactoryPrivate()->GetHostFrameSinkManager();
host_frame_sink_manager->InvalidateFrameSinkId(frame_sink_id_);
}
void DelegatedFrameHost::WasShown(
const viz::LocalSurfaceId& new_pending_local_surface_id,
const gfx::Size& new_pending_dip_size,
const ui::LatencyInfo& latency_info) {
frame_evictor_->SetVisible(true);
if (!enable_surface_synchronization_ && !HasFallbackSurface() &&
!released_front_lock_.get()) {
if (compositor_)
released_front_lock_ = compositor_->GetCompositorLock(nullptr);
}
if (compositor_)
compositor_->SetLatencyInfo(latency_info);
// Use the default deadline to synchronize web content with browser UI.
// TODO(fsamuel): Investigate if there is a better deadline to use here.
WasResized(new_pending_local_surface_id, new_pending_dip_size,
cc::DeadlinePolicy::UseDefaultDeadline());
}
bool DelegatedFrameHost::HasSavedFrame() const {
return frame_evictor_->HasFrame();
}
void DelegatedFrameHost::WasHidden() {
frame_evictor_->SetVisible(false);
released_front_lock_ = nullptr;
}
void DelegatedFrameHost::MaybeCreateResizeLock() {
DCHECK(!resize_lock_);
if (!compositor_)
return;
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableResizeLock))
return;
if (!HasFallbackSurface())
return;
if (!client_->DelegatedFrameCanCreateResizeLock())
return;
gfx::Size desired_size = pending_surface_dip_size_;
if (desired_size.IsEmpty())
return;
if (desired_size == current_frame_size_in_dip_)
return;
resize_lock_ = client_->DelegatedFrameHostCreateResizeLock();
bool locked = resize_lock_->Lock();
DCHECK(locked);
}
void DelegatedFrameHost::CopyFromCompositingSurface(
const gfx::Rect& src_subrect,
const gfx::Size& output_size,
const ReadbackRequestCallback& callback,
const SkColorType preferred_color_type) {
// TODO(crbug/759310): Only NavigationEntryScreenshotManager needs grayscale.
// Move that transformation to there; and then remove |preferred_color_type|
// from this API and the end-to-end code path.
DCHECK(preferred_color_type == kN32_SkColorType ||
preferred_color_type == kAlpha_8_SkColorType);
if (!CanCopyFromCompositingSurface() ||
current_frame_size_in_dip_.IsEmpty()) {
callback.Run(SkBitmap(), content::READBACK_SURFACE_UNAVAILABLE);
return;
}
std::unique_ptr<viz::CopyOutputRequest> request =
std::make_unique<viz::CopyOutputRequest>(
viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP,
base::BindOnce(&CopyFromCompositingSurfaceHasResult, gfx::Size(),
preferred_color_type, callback));
if (src_subrect.IsEmpty()) {
request->set_area(gfx::Rect(current_frame_size_in_dip_));
} else {
request->set_area(src_subrect);
}
// If VIZ display compositing is disabled, the request will be issued directly
// to CompositorFrameSinkSupport, which requires Surface pixel coordinates.
if (!enable_viz_) {
request->set_area(
gfx::ScaleToRoundedRect(request->area(), active_device_scale_factor_));
}
if (!output_size.IsEmpty()) {
request->set_result_selection(gfx::Rect(output_size));
request->SetScaleRatio(
gfx::Vector2d(request->area().width(), request->area().height()),
gfx::Vector2d(output_size.width(), output_size.height()));
}
if (enable_viz_) {
client_->DelegatedFrameHostGetLayer()->RequestCopyOfOutput(
std::move(request));
} else {
support_->RequestCopyOfSurface(std::move(request));
}
}
bool DelegatedFrameHost::CanCopyFromCompositingSurface() const {
return (enable_viz_ || support_) && HasFallbackSurface() &&
active_device_scale_factor_ != 0.f;
}
viz::FrameSinkId DelegatedFrameHost::GetFrameSinkId() {
return frame_sink_id_;
}
bool DelegatedFrameHost::TransformPointToLocalCoordSpace(
const gfx::PointF& point,
const viz::SurfaceId& original_surface,
gfx::PointF* transformed_point) {
viz::SurfaceId surface_id(frame_sink_id_, active_local_surface_id_);
if (!surface_id.is_valid() || enable_viz_)
return false;
*transformed_point = point;
if (original_surface == surface_id)
return true;
viz::SurfaceHittest hittest(nullptr,
GetFrameSinkManager()->surface_manager());
return hittest.TransformPointToTargetSurface(original_surface, surface_id,
transformed_point);
}
bool DelegatedFrameHost::TransformPointToCoordSpaceForView(
const gfx::PointF& point,
RenderWidgetHostViewBase* target_view,
gfx::PointF* transformed_point) {
if (!HasFallbackSurface())
return false;
return target_view->TransformPointToLocalCoordSpace(
point, viz::SurfaceId(frame_sink_id_, active_local_surface_id_),
transformed_point);
}
void DelegatedFrameHost::SetNeedsBeginFrames(bool needs_begin_frames) {
if (enable_viz_) {
NOTIMPLEMENTED();
return;
}
needs_begin_frame_ = needs_begin_frames;
support_->SetNeedsBeginFrame(needs_begin_frames);
}
void DelegatedFrameHost::SetWantsAnimateOnlyBeginFrames() {
if (enable_viz_) {
NOTIMPLEMENTED();
return;
}
support_->SetWantsAnimateOnlyBeginFrames();
}
void DelegatedFrameHost::DidNotProduceFrame(const viz::BeginFrameAck& ack) {
if (enable_viz_) {
NOTIMPLEMENTED();
return;
}
DCHECK(!ack.has_damage);
support_->DidNotProduceFrame(ack);
}
bool DelegatedFrameHost::HasPrimarySurface() const {
const viz::SurfaceId* primary_surface_id =
client_->DelegatedFrameHostGetLayer()->GetPrimarySurfaceId();
return primary_surface_id && primary_surface_id->is_valid();
}
bool DelegatedFrameHost::HasFallbackSurface() const {
const viz::SurfaceId* fallback_surface_id =
client_->DelegatedFrameHostGetLayer()->GetFallbackSurfaceId();
return fallback_surface_id && fallback_surface_id->is_valid();
}
bool DelegatedFrameHost::ShouldSkipFrame(const gfx::Size& size_in_dip) {
if (!resize_lock_)
return false;
// Allow a single renderer frame through even though there's a resize lock
// currently in place.
if (allow_one_renderer_frame_during_resize_lock_) {
allow_one_renderer_frame_during_resize_lock_ = false;
return false;
}
return size_in_dip != resize_lock_->expected_size();
}
void DelegatedFrameHost::WasResized(
const viz::LocalSurfaceId& new_pending_local_surface_id,
const gfx::Size& new_pending_dip_size,
const cc::DeadlinePolicy& deadline_policy) {
const viz::SurfaceId* primary_surface_id =
client_->DelegatedFrameHostGetLayer()->GetPrimarySurfaceId();
pending_local_surface_id_ = new_pending_local_surface_id;
pending_surface_dip_size_ = new_pending_dip_size;
if (enable_surface_synchronization_ &&
client_->DelegatedFrameHostIsVisible() &&
(!primary_surface_id ||
primary_surface_id->local_surface_id() != pending_local_surface_id_)) {
current_frame_size_in_dip_ = pending_surface_dip_size_;
viz::SurfaceId surface_id(frame_sink_id_, pending_local_surface_id_);
client_->DelegatedFrameHostGetLayer()->SetShowPrimarySurface(
surface_id, current_frame_size_in_dip_, GetGutterColor(),
deadline_policy);
if (compositor_ && !base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableResizeLock)) {
compositor_->OnChildResizing();
}
// Input throttling and guttering are handled differently when surface
// synchronization is enabled so exit early here.
return;
}
if (pending_surface_dip_size_ != current_frame_size_in_dip_ &&
!client_->DelegatedFrameHostIsVisible()) {
EvictDelegatedFrame();
}
// If |create_resize_lock_after_commit_| is true, we're waiting to recreate
// an expired resize lock after the next UI frame is submitted, so don't
// make a lock here.
if (!resize_lock_ && !create_resize_lock_after_commit_)
MaybeCreateResizeLock();
UpdateGutters();
}
SkColor DelegatedFrameHost::GetGutterColor() const {
// In fullscreen mode resizing is uncommon, so it makes more sense to
// make the initial switch to fullscreen mode look better by using black as
// the gutter color.
return client_->DelegatedFrameHostGetGutterColor();
}
void DelegatedFrameHost::UpdateGutters() {
if (!HasFallbackSurface() || enable_surface_synchronization_) {
right_gutter_.reset();
bottom_gutter_.reset();
return;
}
gfx::Size size_in_dip = pending_surface_dip_size_;
if (current_frame_size_in_dip_.width() < size_in_dip.width()) {
right_gutter_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR));
right_gutter_->SetColor(GetGutterColor());
int width = size_in_dip.width() - current_frame_size_in_dip_.width();
// The right gutter also includes the bottom-right corner, if necessary.
int height = size_in_dip.height();
right_gutter_->SetBounds(
gfx::Rect(current_frame_size_in_dip_.width(), 0, width, height));
client_->DelegatedFrameHostGetLayer()->Add(right_gutter_.get());
} else {
right_gutter_.reset();
}
if (current_frame_size_in_dip_.height() < size_in_dip.height()) {
bottom_gutter_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR));
bottom_gutter_->SetColor(GetGutterColor());
int width = current_frame_size_in_dip_.width();
int height = size_in_dip.height() - current_frame_size_in_dip_.height();
bottom_gutter_->SetBounds(
gfx::Rect(0, current_frame_size_in_dip_.height(), width, height));
client_->DelegatedFrameHostGetLayer()->Add(bottom_gutter_.get());
} else {
bottom_gutter_.reset();
}
}
gfx::Size DelegatedFrameHost::GetRequestedRendererSize() const {
if (resize_lock_)
return resize_lock_->expected_size();
else
return pending_surface_dip_size_;
}
void DelegatedFrameHost::CheckResizeLock() {
if (!resize_lock_ ||
resize_lock_->expected_size() != current_frame_size_in_dip_)
return;
// Since we got the size we were looking for, unlock the compositor. But delay
// the release of the lock until we've kicked a frame with the new texture, to
// avoid resizing the UI before we have a chance to draw a "good" frame.
resize_lock_->UnlockCompositor();
}
void DelegatedFrameHost::DidCreateNewRendererCompositorFrameSink(
viz::mojom::CompositorFrameSinkClient* renderer_compositor_frame_sink) {
ResetCompositorFrameSinkSupport();
renderer_compositor_frame_sink_ = renderer_compositor_frame_sink;
CreateCompositorFrameSinkSupport();
}
void DelegatedFrameHost::SubmitCompositorFrame(
const viz::LocalSurfaceId& local_surface_id,
viz::CompositorFrame frame,
viz::mojom::HitTestRegionListPtr hit_test_region_list) {
#if defined(OS_CHROMEOS)
DCHECK(!resize_lock_ || !client_->IsAutoResizeEnabled());
#endif
float frame_device_scale_factor = frame.metadata.device_scale_factor;
viz::BeginFrameAck ack(frame.metadata.begin_frame_ack);
DCHECK(!frame.render_pass_list.empty());
viz::RenderPass* root_pass = frame.render_pass_list.back().get();
gfx::Size frame_size = root_pass->output_rect.size();
gfx::Size frame_size_in_dip =
gfx::ConvertSizeToDIP(frame_device_scale_factor, frame_size);
if (ShouldSkipFrame(frame_size_in_dip)) {
std::vector<viz::ReturnedResource> resources =
viz::TransferableResource::ReturnResources(frame.resource_list);
skipped_latency_info_list_.insert(skipped_latency_info_list_.end(),
frame.metadata.latency_info.begin(),
frame.metadata.latency_info.end());
renderer_compositor_frame_sink_->DidReceiveCompositorFrameAck(resources);
skipped_frames_ = true;
ack.has_damage = false;
DidNotProduceFrame(ack);
return;
}
// If we are allowing one renderer frame through, this would ensure the frame
// gets through even if we regrab the lock after the UI compositor makes one
// frame. If the renderer frame beats the UI compositor, then we don't need to
// allow any more, though.
allow_one_renderer_frame_during_resize_lock_ = false;
if (skipped_frames_) {
skipped_frames_ = false;
// Give the same damage rect to the compositor.
viz::RenderPass* root_pass = frame.render_pass_list.back().get();
root_pass->damage_rect = gfx::Rect(frame_size);
}
frame.metadata.latency_info.insert(frame.metadata.latency_info.end(),
skipped_latency_info_list_.begin(),
skipped_latency_info_list_.end());
skipped_latency_info_list_.clear();
// If surface synchronization is off, then OnFirstSurfaceActivation will be
// called in the same call stack.
support_->SubmitCompositorFrame(local_surface_id, std::move(frame),
std::move(hit_test_region_list));
}
void DelegatedFrameHost::ClearDelegatedFrame() {
// Ensure that we are able to swap in a new blank frame to replace any old
// content. This will result in a white flash if we switch back to this
// content.
// https://crbug.com/739621
released_front_lock_.reset();
EvictDelegatedFrame();
}
void DelegatedFrameHost::DidReceiveCompositorFrameAck(
const std::vector<viz::ReturnedResource>& resources) {
renderer_compositor_frame_sink_->DidReceiveCompositorFrameAck(resources);
}
void DelegatedFrameHost::DidPresentCompositorFrame(uint32_t presentation_token,
base::TimeTicks time,
base::TimeDelta refresh,
uint32_t flags) {
renderer_compositor_frame_sink_->DidPresentCompositorFrame(
presentation_token, time, refresh, flags);
}
void DelegatedFrameHost::DidDiscardCompositorFrame(
uint32_t presentation_token) {
renderer_compositor_frame_sink_->DidDiscardCompositorFrame(
presentation_token);
}
void DelegatedFrameHost::ReclaimResources(
const std::vector<viz::ReturnedResource>& resources) {
renderer_compositor_frame_sink_->ReclaimResources(resources);
}
void DelegatedFrameHost::OnBeginFramePausedChanged(bool paused) {
if (renderer_compositor_frame_sink_)
renderer_compositor_frame_sink_->OnBeginFramePausedChanged(paused);
}
void DelegatedFrameHost::OnFirstSurfaceActivation(
const viz::SurfaceInfo& surface_info) {
gfx::Size frame_size_in_dip = gfx::ConvertSizeToDIP(
surface_info.device_scale_factor(), surface_info.size_in_pixels());
if (enable_surface_synchronization_) {
// If this is the first Surface created after navigation, notify |client_|.
// If the Surface was created before navigation, drop it.
uint32_t parent_sequence_number =
surface_info.id().local_surface_id().parent_sequence_number();
uint32_t latest_parent_sequence_number =
pending_local_surface_id_.parent_sequence_number();
// If |latest_parent_sequence_number| is less than
// |first_parent_sequence_number_after_navigation_|, then the parent id has
// wrapped around. Make sure that case is covered.
if (parent_sequence_number >=
first_parent_sequence_number_after_navigation_ ||
(latest_parent_sequence_number <
first_parent_sequence_number_after_navigation_ &&
parent_sequence_number <= latest_parent_sequence_number)) {
if (!received_frame_after_navigation_) {
received_frame_after_navigation_ = true;
client_->DidReceiveFirstFrameAfterNavigation();
}
} else {
ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
viz::HostFrameSinkManager* host_frame_sink_manager =
factory->GetContextFactoryPrivate()->GetHostFrameSinkManager();
host_frame_sink_manager->DropTemporaryReference(surface_info.id());
return;
}
// If there's no primary surface, then we don't wish to display content at
// this time (e.g. the view is hidden) and so we don't need a fallback
// surface either. Since we won't use the fallback surface, we drop the
// temporary reference here to save resources.
if (!HasPrimarySurface()) {
ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
viz::HostFrameSinkManager* host_frame_sink_manager =
factory->GetContextFactoryPrivate()->GetHostFrameSinkManager();
host_frame_sink_manager->DropTemporaryReference(surface_info.id());
return;
}
} else {
client_->DelegatedFrameHostGetLayer()->SetShowPrimarySurface(
surface_info.id(), frame_size_in_dip, GetGutterColor(),
cc::DeadlinePolicy::UseDefaultDeadline());
}
client_->DelegatedFrameHostGetLayer()->SetFallbackSurfaceId(
surface_info.id());
active_local_surface_id_ = surface_info.id().local_surface_id();
active_device_scale_factor_ = surface_info.device_scale_factor();
// Surface synchronization deals with resizes in WasResized().
if (!enable_surface_synchronization_) {
released_front_lock_ = nullptr;
current_frame_size_in_dip_ = frame_size_in_dip;
CheckResizeLock();
UpdateGutters();
}
// This is used by macOS' unique resize path.
client_->OnFirstSurfaceActivation(surface_info);
frame_evictor_->SwappedFrame(client_->DelegatedFrameHostIsVisible());
// Note: the frame may have been evicted immediately.
}
void DelegatedFrameHost::OnFrameTokenChanged(uint32_t frame_token) {
client_->OnFrameTokenChanged(frame_token);
}
void DelegatedFrameHost::OnBeginFrame(const viz::BeginFrameArgs& args) {
if (renderer_compositor_frame_sink_)
renderer_compositor_frame_sink_->OnBeginFrame(args);
client_->OnBeginFrame(args.frame_time);
}
void DelegatedFrameHost::EvictDelegatedFrame() {
if (!HasFallbackSurface())
return;
std::vector<viz::SurfaceId> surface_ids = {
*client_->DelegatedFrameHostGetLayer()->GetFallbackSurfaceId()};
GetHostFrameSinkManager()->EvictSurfaces(surface_ids);
if (enable_surface_synchronization_) {
client_->DelegatedFrameHostGetLayer()->SetFallbackSurfaceId(
viz::SurfaceId());
} else {
client_->DelegatedFrameHostGetLayer()->SetShowSolidColorContent();
resize_lock_.reset();
UpdateGutters();
}
frame_evictor_->DiscardedFrame();
}
////////////////////////////////////////////////////////////////////////////////
// DelegatedFrameHost, ui::CompositorObserver implementation:
void DelegatedFrameHost::OnCompositingDidCommit(ui::Compositor* compositor) {
// If |create_resize_lock_after_commit_| then we should have popped the old
// lock already.
DCHECK(!resize_lock_ || !create_resize_lock_after_commit_);
if (resize_lock_ &&
resize_lock_->expected_size() == current_frame_size_in_dip_) {
resize_lock_.reset();
// We had a lock but the UI may have resized in the meantime.
create_resize_lock_after_commit_ = true;
}
if (create_resize_lock_after_commit_) {
create_resize_lock_after_commit_ = false;
MaybeCreateResizeLock();
}
}
void DelegatedFrameHost::OnCompositingStarted(ui::Compositor* compositor,
base::TimeTicks start_time) {
last_draw_ended_ = start_time;
}
void DelegatedFrameHost::OnCompositingEnded(ui::Compositor* compositor) {}
void DelegatedFrameHost::OnCompositingLockStateChanged(
ui::Compositor* compositor) {
if (resize_lock_ && resize_lock_->timed_out()) {
// A compositor lock that is part of a resize lock timed out. We allow
// the UI to produce a frame before locking it again, so we don't lock here.
// We release the |resize_lock_| though to allow any other resizes that are
// desired at the same time since we're allowing the UI to make a frame
// which will gutter anyways.
resize_lock_.reset();
create_resize_lock_after_commit_ = true;
// Because this timed out, we're going to allow the UI to update and lock
// again. We would allow renderer frames through during this time if they
// came late, but would stop them again once the UI finished its frame. We
// want to allow the slow renderer to show us one frame even if its wrong
// since we're guttering anyways, but not unlimited number of frames as that
// would be a waste of power.
allow_one_renderer_frame_during_resize_lock_ = true;
}
}
void DelegatedFrameHost::OnCompositingChildResizing(
ui::Compositor* compositor) {}
void DelegatedFrameHost::OnCompositingShuttingDown(ui::Compositor* compositor) {
DCHECK_EQ(compositor, compositor_);
ResetCompositor();
DCHECK(!compositor_);
}
////////////////////////////////////////////////////////////////////////////////
// DelegatedFrameHost, ImageTransportFactoryObserver implementation:
void DelegatedFrameHost::OnLostResources() {
EvictDelegatedFrame();
}
////////////////////////////////////////////////////////////////////////////////
// DelegatedFrameHost, private:
void DelegatedFrameHost::SetCompositor(ui::Compositor* compositor) {
DCHECK(!compositor_);
if (!compositor)
return;
compositor_ = compositor;
compositor_->AddObserver(this);
compositor_->AddFrameSink(frame_sink_id_);
}
void DelegatedFrameHost::ResetCompositor() {
if (!compositor_)
return;
resize_lock_.reset();
if (compositor_->HasObserver(this))
compositor_->RemoveObserver(this);
compositor_->RemoveFrameSink(frame_sink_id_);
compositor_ = nullptr;
}
void DelegatedFrameHost::LockResources() {
DCHECK(active_local_surface_id_.is_valid());
frame_evictor_->LockFrame();
}
void DelegatedFrameHost::UnlockResources() {
DCHECK(active_local_surface_id_.is_valid());
frame_evictor_->UnlockFrame();
}
void DelegatedFrameHost::CreateCompositorFrameSinkSupport() {
if (enable_viz_)
return;
DCHECK(!support_);
constexpr bool is_root = false;
constexpr bool needs_sync_points = true;
ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
support_ = factory->GetContextFactoryPrivate()
->GetHostFrameSinkManager()
->CreateCompositorFrameSinkSupport(this, frame_sink_id_,
is_root, needs_sync_points);
if (compositor_)
compositor_->AddFrameSink(frame_sink_id_);
if (needs_begin_frame_)
support_->SetNeedsBeginFrame(true);
}
void DelegatedFrameHost::ResetCompositorFrameSinkSupport() {
if (!support_)
return;
if (compositor_)
compositor_->RemoveFrameSink(frame_sink_id_);
support_.reset();
}
void DelegatedFrameHost::DidNavigate() {
first_parent_sequence_number_after_navigation_ =
pending_local_surface_id_.parent_sequence_number();
received_frame_after_navigation_ = false;
}
bool DelegatedFrameHost::IsPrimarySurfaceEvicted() const {
return active_local_surface_id_ == pending_local_surface_id_ &&
!HasSavedFrame();
}
} // namespace content