diff --git a/libcef/browser/browser_host_impl.cc b/libcef/browser/browser_host_impl.cc index 4fcb53d9c..28f5a1bb6 100644 --- a/libcef/browser/browser_host_impl.cc +++ b/libcef/browser/browser_host_impl.cc @@ -1079,7 +1079,7 @@ void CefBrowserHostImpl::WasResized() { if (!web_contents() || !platform_delegate_) return; - platform_delegate_->SynchronizeVisualProperties(); + platform_delegate_->WasResized(); } void CefBrowserHostImpl::WasHidden(bool hidden) { diff --git a/libcef/browser/browser_platform_delegate.h b/libcef/browser/browser_platform_delegate.h index 2b7a110a7..a14c7ff4e 100644 --- a/libcef/browser/browser_platform_delegate.h +++ b/libcef/browser/browser_platform_delegate.h @@ -145,7 +145,7 @@ class CefBrowserPlatformDelegate { virtual bool CanUseExternalBeginFrame() const = 0; // Notify the window that it was resized. - virtual void SynchronizeVisualProperties() = 0; + virtual void WasResized() = 0; // Send input events. virtual void SendKeyEvent(const CefKeyEvent& event) = 0; diff --git a/libcef/browser/extensions/browser_platform_delegate_background.cc b/libcef/browser/extensions/browser_platform_delegate_background.cc index ae2ac9525..ac542b9bf 100644 --- a/libcef/browser/extensions/browser_platform_delegate_background.cc +++ b/libcef/browser/extensions/browser_platform_delegate_background.cc @@ -47,7 +47,7 @@ SkColor CefBrowserPlatformDelegateBackground::GetBackgroundColor() const { return native_delegate_->GetBackgroundColor(); } -void CefBrowserPlatformDelegateBackground::SynchronizeVisualProperties() { +void CefBrowserPlatformDelegateBackground::WasResized() { // Nothing to do here. } diff --git a/libcef/browser/extensions/browser_platform_delegate_background.h b/libcef/browser/extensions/browser_platform_delegate_background.h index a8df4f5e6..2ded3736c 100644 --- a/libcef/browser/extensions/browser_platform_delegate_background.h +++ b/libcef/browser/extensions/browser_platform_delegate_background.h @@ -24,7 +24,7 @@ class CefBrowserPlatformDelegateBackground SkColor GetBackgroundColor() const override; bool CanUseSharedTexture() const override; bool CanUseExternalBeginFrame() const override; - void SynchronizeVisualProperties() override; + void WasResized() override; void SendKeyEvent(const CefKeyEvent& event) override; void SendMouseClickEvent(const CefMouseEvent& event, CefBrowserHost::MouseButtonType type, diff --git a/libcef/browser/native/browser_platform_delegate_native.cc b/libcef/browser/native/browser_platform_delegate_native.cc index 0236dde32..f7c0cb7ed 100644 --- a/libcef/browser/native/browser_platform_delegate_native.cc +++ b/libcef/browser/native/browser_platform_delegate_native.cc @@ -33,7 +33,7 @@ bool CefBrowserPlatformDelegateNative::CanUseExternalBeginFrame() const { return use_external_begin_frame_; } -void CefBrowserPlatformDelegateNative::SynchronizeVisualProperties() { +void CefBrowserPlatformDelegateNative::WasResized() { content::RenderViewHost* host = browser_->web_contents()->GetRenderViewHost(); if (host) host->GetWidget()->SynchronizeVisualProperties(); diff --git a/libcef/browser/native/browser_platform_delegate_native.h b/libcef/browser/native/browser_platform_delegate_native.h index dc04cb513..a7c3003ca 100644 --- a/libcef/browser/native/browser_platform_delegate_native.h +++ b/libcef/browser/native/browser_platform_delegate_native.h @@ -28,7 +28,7 @@ class CefBrowserPlatformDelegateNative : public CefBrowserPlatformDelegate { bool CanUseSharedTexture() const override; bool CanUseExternalBeginFrame() const override; SkColor GetBackgroundColor() const override; - void SynchronizeVisualProperties() override; + void WasResized() override; bool IsWindowless() const override; bool IsViewsHosted() const override; diff --git a/libcef/browser/osr/browser_platform_delegate_osr.cc b/libcef/browser/osr/browser_platform_delegate_osr.cc index b41690e3d..42e003db5 100644 --- a/libcef/browser/osr/browser_platform_delegate_osr.cc +++ b/libcef/browser/osr/browser_platform_delegate_osr.cc @@ -85,10 +85,10 @@ SkColor CefBrowserPlatformDelegateOsr::GetBackgroundColor() const { return native_delegate_->GetBackgroundColor(); } -void CefBrowserPlatformDelegateOsr::SynchronizeVisualProperties() { +void CefBrowserPlatformDelegateOsr::WasResized() { CefRenderWidgetHostViewOSR* view = GetOSRHostView(); if (view) - view->SynchronizeVisualProperties(); + view->WasResized(); } void CefBrowserPlatformDelegateOsr::SendKeyEvent(const CefKeyEvent& event) { diff --git a/libcef/browser/osr/browser_platform_delegate_osr.h b/libcef/browser/osr/browser_platform_delegate_osr.h index b5fb8d504..ffb6d855a 100644 --- a/libcef/browser/osr/browser_platform_delegate_osr.h +++ b/libcef/browser/osr/browser_platform_delegate_osr.h @@ -30,7 +30,7 @@ class CefBrowserPlatformDelegateOsr SkColor GetBackgroundColor() const override; bool CanUseSharedTexture() const override; bool CanUseExternalBeginFrame() const override; - void SynchronizeVisualProperties() override; + void WasResized() override; void SendKeyEvent(const CefKeyEvent& event) override; void SendMouseClickEvent(const CefMouseEvent& event, CefBrowserHost::MouseButtonType type, diff --git a/libcef/browser/osr/render_widget_host_view_osr.cc b/libcef/browser/osr/render_widget_host_view_osr.cc index 5dae32e03..2b8d0c2bb 100644 --- a/libcef/browser/osr/render_widget_host_view_osr.cc +++ b/libcef/browser/osr/render_widget_host_view_osr.cc @@ -149,6 +149,36 @@ ui::LatencyInfo CreateLatencyInfo(const blink::WebInputEvent& event) { return latency_info; } +gfx::Rect GetViewBounds(CefBrowserHostImpl* browser) { + if (!browser) + return gfx::Rect(); + + CefRect rc; + CefRefPtr handler = + browser->GetClient()->GetRenderHandler(); + CHECK(handler); + + handler->GetViewRect(browser, rc); + CHECK_GT(rc.width, 0); + CHECK_GT(rc.height, 0); + + return gfx::Rect(rc.x, rc.y, rc.width, rc.height); +} + +float GetDeviceScaleFactor(CefBrowserHostImpl* browser) { + if (!browser) + return kDefaultScaleFactor; + + CefScreenInfo screen_info(kDefaultScaleFactor, 0, 0, false, CefRect(), + CefRect()); + CefRefPtr handler = browser->client()->GetRenderHandler(); + CHECK(handler); + if (!handler->GetScreenInfo(browser, screen_info)) + return kDefaultScaleFactor; + + return screen_info.device_scale_factor; +} + } // namespace CefRenderWidgetHostViewOSR::CefRenderWidgetHostViewOSR( @@ -159,23 +189,12 @@ CefRenderWidgetHostViewOSR::CefRenderWidgetHostViewOSR( CefRenderWidgetHostViewOSR* parent_host_view) : content::RenderWidgetHostViewBase(widget), background_color_(background_color), - frame_rate_threshold_us_(0), - host_display_client_(nullptr), - hold_resize_(false), - pending_resize_(false), - pending_resize_force_(false), render_widget_host_(content::RenderWidgetHostImpl::From(widget)), has_parent_(parent_host_view != nullptr), parent_host_view_(parent_host_view), - popup_host_view_(nullptr), - child_host_view_(nullptr), - is_showing_(false), - is_destroyed_(false), pinch_zoom_enabled_(content::IsPinchToZoomEnabled()), - is_scroll_offset_changed_pending_(false), mouse_wheel_phase_handler_(this), gesture_provider_(CreateGestureProviderConfig(), this), - forward_touch_to_popup_(false), weak_ptr_factory_(this) { DCHECK(render_widget_host_); DCHECK(!render_widget_host_->GetView()); @@ -191,9 +210,6 @@ CefRenderWidgetHostViewOSR::CefRenderWidgetHostViewOSR( content::RenderViewHost::From(render_widget_host_)); } - local_surface_id_allocator_.GenerateId(); - local_surface_id_allocation_ = - local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation(); delegated_frame_host_client_.reset(new CefDelegatedFrameHostClient(this)); // Matching the attributes from BrowserCompositorMac. @@ -231,12 +247,9 @@ CefRenderWidgetHostViewOSR::CefRenderWidgetHostViewOSR( if (render_widget_host_impl) render_widget_host_impl->SetCompositorForFlingScheduler(compositor_.get()); - if (browser_impl_.get()) - ResizeRootLayer(false); - cursor_manager_.reset(new content::CursorManager(this)); - // Do this last because it may result in a call to SetNeedsBeginFrames. + // This may result in a call to GetFrameSinkId(). render_widget_host_->SetView(this); if (GetTextInputManager()) @@ -248,15 +261,12 @@ CefRenderWidgetHostViewOSR::CefRenderWidgetHostViewOSR( GetFrameSinkId(), this); } - if (!render_widget_host_->is_hidden()) { - Show(); - } - - if (!content::GpuDataManagerImpl::GetInstance()->IsGpuCompositingDisabled()) { - video_consumer_.reset(new CefVideoConsumerOSR(this)); - video_consumer_->SetActive(true); - video_consumer_->SetFrameRate( - base::TimeDelta::FromMicroseconds(frame_rate_threshold_us_)); + if (browser_impl_ && !parent_host_view_) { + // For child/popup views this will be called from the associated InitAs*() + // method. + SetRootLayerSize(false /* force */); + if (!render_widget_host_->is_hidden()) + Show(); } } @@ -297,7 +307,7 @@ void CefRenderWidgetHostViewOSR::InitAsChild(gfx::NativeView parent_view) { // The parent view should not render while the full-screen view exists. parent_host_view_->Hide(); - ResizeRootLayer(false); + SetRootLayerSize(false /* force */); Show(); } @@ -321,7 +331,7 @@ bool CefRenderWidgetHostViewOSR::HasFocus() { } bool CefRenderWidgetHostViewOSR::IsSurfaceAvailableForCopy() { - return GetDelegatedFrameHost()->CanCopyFromCompositingSurface(); + return delegated_frame_host_->CanCopyFromCompositingSurface(); } void CefRenderWidgetHostViewOSR::Show() { @@ -330,16 +340,40 @@ void CefRenderWidgetHostViewOSR::Show() { is_showing_ = true; - delegated_frame_host_->AttachToCompositor(compositor_.get()); - delegated_frame_host_->WasShown( - GetLocalSurfaceIdAllocation().local_surface_id(), - GetRootLayer()->bounds().size(), base::nullopt); + // If the viz::LocalSurfaceIdAllocation is invalid, we may have been evicted, + // and no other visual properties have since been changed. Allocate a new id + // and start synchronizing. + if (!GetLocalSurfaceIdAllocation().IsValid()) { + AllocateLocalSurfaceId(); + SynchronizeVisualProperties(cc::DeadlinePolicy::UseDefaultDeadline(), + GetLocalSurfaceIdAllocation()); + } - // Note that |render_widget_host_| will retrieve size parameters from the - // DelegatedFrameHost, so it must have WasShown called after. - if (render_widget_host_) + if (render_widget_host_) { render_widget_host_->WasShown( base::nullopt /* record_tab_switch_time_request */); + } + + delegated_frame_host_->AttachToCompositor(compositor_.get()); + delegated_frame_host_->WasShown( + GetLocalSurfaceIdAllocation().local_surface_id(), GetViewBounds().size(), + base::nullopt); + + if (!content::GpuDataManagerImpl::GetInstance()->IsGpuCompositingDisabled()) { + // Start generating frames when we're visible and at the correct size. + if (!video_consumer_) { + video_consumer_.reset(new CefVideoConsumerOSR(this)); + UpdateFrameRate(); + + // Call OnRenderFrameMetadataChangedAfterActivation for every frame. + content::RenderFrameMetadataProviderImpl* provider = + content::RenderWidgetHostImpl::From(render_widget_host_) + ->render_frame_metadata_provider(); + provider->ReportAllFrameSubmissionsForTesting(true); + } else { + video_consumer_->SetActive(true); + } + } } void CefRenderWidgetHostViewOSR::Hide() { @@ -351,12 +385,16 @@ void CefRenderWidgetHostViewOSR::Hide() { if (browser_impl_.get()) browser_impl_->CancelContextMenu(); + if (video_consumer_) { + video_consumer_->SetActive(false); + } + if (render_widget_host_) render_widget_host_->WasHidden(); - GetDelegatedFrameHost()->WasHidden( + delegated_frame_host_->WasHidden( content::DelegatedFrameHost::HiddenCause::kOther); - GetDelegatedFrameHost()->DetachFromCompositor(); + delegated_frame_host_->DetachFromCompositor(); } bool CefRenderWidgetHostViewOSR::IsShowing() { @@ -365,26 +403,15 @@ bool CefRenderWidgetHostViewOSR::IsShowing() { void CefRenderWidgetHostViewOSR::EnsureSurfaceSynchronizedForWebTest() { ++latest_capture_sequence_number_; - SynchronizeVisualProperties(); + SynchronizeVisualProperties(cc::DeadlinePolicy::UseInfiniteDeadline(), + base::nullopt); } gfx::Rect CefRenderWidgetHostViewOSR::GetViewBounds() { if (IsPopupWidget()) return popup_position_; - if (!browser_impl_.get()) - return gfx::Rect(); - - CefRect rc; - CefRefPtr handler = - browser_impl_->GetClient()->GetRenderHandler(); - CHECK(handler); - - handler->GetViewRect(browser_impl_.get(), rc); - CHECK_GT(rc.width, 0); - CHECK_GT(rc.height, 0); - - return gfx::Rect(rc.x, rc.y, rc.width, rc.height); + return current_view_bounds_; } void CefRenderWidgetHostViewOSR::SetBackgroundColor(SkColor color) { @@ -416,9 +443,9 @@ void CefRenderWidgetHostViewOSR::TakeFallbackContentFrom( CefRenderWidgetHostViewOSR* view_cef = static_cast(view); SetBackgroundColor(view_cef->background_color_); - if (GetDelegatedFrameHost() && view_cef->GetDelegatedFrameHost()) { - GetDelegatedFrameHost()->TakeFallbackContentFrom( - view_cef->GetDelegatedFrameHost()); + if (delegated_frame_host_ && view_cef->delegated_frame_host_) { + delegated_frame_host_->TakeFallbackContentFrom( + view_cef->delegated_frame_host_.get()); } host()->GetContentRenderingTimeoutFrom(view_cef->host()); } @@ -432,13 +459,55 @@ void CefRenderWidgetHostViewOSR::OnPresentCompositorFrame() {} void CefRenderWidgetHostViewOSR::OnDidUpdateVisualPropertiesComplete( const cc::RenderFrameMetadata& metadata) { - bool force = false; - if (metadata.local_surface_id_allocation) { - force = local_surface_id_allocator_.UpdateFromChild( - *metadata.local_surface_id_allocation); + if (host()->is_hidden()) { + // When an embedded child responds, we want to accept its changes to the + // viz::LocalSurfaceId. However we do not want to embed surfaces while + // hidden. Nor do we want to embed invalid ids when we are evicted. Becoming + // visible will generate a new id, if necessary, and begin embedding. + UpdateLocalSurfaceIdFromEmbeddedClient( + metadata.local_surface_id_allocation); + } else { + SynchronizeVisualProperties(cc::DeadlinePolicy::UseDefaultDeadline(), + metadata.local_surface_id_allocation); } +} - SynchronizeVisualProperties(force); +void CefRenderWidgetHostViewOSR::AllocateLocalSurfaceId() { + if (!parent_local_surface_id_allocator_) { + parent_local_surface_id_allocator_ = + std::make_unique(); + } + parent_local_surface_id_allocator_->GenerateId(); +} + +const viz::LocalSurfaceIdAllocation& +CefRenderWidgetHostViewOSR::GetCurrentLocalSurfaceIdAllocation() const { + return parent_local_surface_id_allocator_ + ->GetCurrentLocalSurfaceIdAllocation(); +} + +void CefRenderWidgetHostViewOSR::UpdateLocalSurfaceIdFromEmbeddedClient( + const base::Optional& + embedded_client_local_surface_id_allocation) { + if (embedded_client_local_surface_id_allocation) { + parent_local_surface_id_allocator_->UpdateFromChild( + *embedded_client_local_surface_id_allocation); + } else { + AllocateLocalSurfaceId(); + } +} + +const viz::LocalSurfaceIdAllocation& +CefRenderWidgetHostViewOSR::GetOrCreateLocalSurfaceIdAllocation() { + if (!parent_local_surface_id_allocator_) + AllocateLocalSurfaceId(); + return GetCurrentLocalSurfaceIdAllocation(); +} + +void CefRenderWidgetHostViewOSR::InvalidateLocalSurfaceId() { + if (!parent_local_surface_id_allocator_) + return; + parent_local_surface_id_allocator_->Invalidate(); } void CefRenderWidgetHostViewOSR::AddDamageRect(uint32_t sequence, @@ -465,7 +534,7 @@ void CefRenderWidgetHostViewOSR::SubmitCompositorFrame( } void CefRenderWidgetHostViewOSR::ResetFallbackToFirstNavigationSurface() { - GetDelegatedFrameHost()->ResetFallbackToFirstNavigationSurface(); + delegated_frame_host_->ResetFallbackToFirstNavigationSurface(); } void CefRenderWidgetHostViewOSR::InitAsPopup( @@ -493,12 +562,9 @@ void CefRenderWidgetHostViewOSR::InitAsPopup( if (handler.get()) handler->OnPopupSize(browser_impl_.get(), widget_pos); - if (video_consumer_) { - video_consumer_->SizeChanged(); - } - - ResizeRootLayer(false); - + // The size doesn't change for popups so we need to force the + // initialization. + SetRootLayerSize(true /* force */); Show(); } @@ -635,8 +701,8 @@ void CefRenderWidgetHostViewOSR::CopyFromSurface( const gfx::Rect& src_rect, const gfx::Size& output_size, base::OnceCallback callback) { - GetDelegatedFrameHost()->CopyFromCompositingSurface(src_rect, output_size, - std::move(callback)); + delegated_frame_host_->CopyFromCompositingSurface(src_rect, output_size, + std::move(callback)); } void CefRenderWidgetHostViewOSR::GetScreenInfo(content::ScreenInfo* results) { @@ -702,9 +768,8 @@ CefRenderWidgetHostViewOSR::DidUpdateVisualProperties( #endif viz::SurfaceId CefRenderWidgetHostViewOSR::GetCurrentSurfaceId() const { - return GetDelegatedFrameHost() - ? GetDelegatedFrameHost()->GetCurrentSurfaceId() - : viz::SurfaceId(); + return delegated_frame_host_ ? delegated_frame_host_->GetCurrentSurfaceId() + : viz::SurfaceId(); } content::BrowserAccessibilityManager* @@ -806,17 +871,28 @@ void CefRenderWidgetHostViewOSR::SelectionChanged(const base::string16& text, const viz::LocalSurfaceIdAllocation& CefRenderWidgetHostViewOSR::GetLocalSurfaceIdAllocation() const { - return local_surface_id_allocation_; + return const_cast(this) + ->GetOrCreateLocalSurfaceIdAllocation(); } const viz::FrameSinkId& CefRenderWidgetHostViewOSR::GetFrameSinkId() const { - return GetDelegatedFrameHost()->frame_sink_id(); + return delegated_frame_host_->frame_sink_id(); } viz::FrameSinkId CefRenderWidgetHostViewOSR::GetRootFrameSinkId() { return compositor_->frame_sink_id(); } +void CefRenderWidgetHostViewOSR::OnRenderFrameMetadataChangedAfterActivation() { + if (video_consumer_) { + // Need to wait for the first frame of the new size before calling + // SizeChanged. Otherwise, the video frame will be letterboxed. + auto metadata = + host_->render_frame_metadata_provider()->LastRenderFrameMetadata(); + video_consumer_->SizeChanged(metadata.viewport_size_in_pixels); + } +} + std::unique_ptr CefRenderWidgetHostViewOSR::CreateSyntheticGestureTarget() { return std::make_unique(host()); @@ -831,8 +907,8 @@ void CefRenderWidgetHostViewOSR::SetNeedsBeginFrames(bool enabled) { } void CefRenderWidgetHostViewOSR::SetWantsAnimateOnlyBeginFrames() { - if (GetDelegatedFrameHost()) { - GetDelegatedFrameHost()->SetWantsAnimateOnlyBeginFrames(); + if (delegated_frame_host_) { + delegated_frame_host_->SetWantsAnimateOnlyBeginFrames(); } } @@ -850,11 +926,25 @@ bool CefRenderWidgetHostViewOSR::TransformPointToCoordSpaceForView( } void CefRenderWidgetHostViewOSR::DidNavigate() { - // With surface synchronization enabled we need to force synchronization on - // first navigation. - ResizeRootLayer(true); + if (!IsShowing()) { + // Navigating while hidden should not allocate a new LocalSurfaceID. Once + // sizes are ready, or we begin to Show, we can then allocate the new + // LocalSurfaceId. + InvalidateLocalSurfaceId(); + } else { + if (is_first_navigation_) { + // The first navigation does not need a new LocalSurfaceID. The renderer + // can use the ID that was already provided. + SynchronizeVisualProperties(cc::DeadlinePolicy::UseExistingDeadline(), + GetLocalSurfaceIdAllocation()); + } else { + SynchronizeVisualProperties(cc::DeadlinePolicy::UseExistingDeadline(), + base::nullopt); + } + } if (delegated_frame_host_) delegated_frame_host_->DidNavigate(); + is_first_navigation_ = false; } void CefRenderWidgetHostViewOSR::OnFrameComplete( @@ -881,16 +971,53 @@ bool CefRenderWidgetHostViewOSR::InstallTransparency() { return false; } -void CefRenderWidgetHostViewOSR::SynchronizeVisualProperties(bool force) { +void CefRenderWidgetHostViewOSR::WasResized() { + // Only one resize will be in-flight at a time. if (hold_resize_) { if (!pending_resize_) pending_resize_ = true; - if (force) - pending_resize_force_ = true; return; } - ResizeRootLayer(force); + SynchronizeVisualProperties(cc::DeadlinePolicy::UseExistingDeadline(), + base::nullopt); +} + +void CefRenderWidgetHostViewOSR::SynchronizeVisualProperties( + const cc::DeadlinePolicy& deadline_policy, + const base::Optional& + child_local_surface_id_allocation) { + SetFrameRate(); + + const bool resized = ResizeRootLayer(); + bool surface_id_updated = false; + + if (!resized && child_local_surface_id_allocation) { + // Update the current surface ID. + parent_local_surface_id_allocator_->UpdateFromChild( + *child_local_surface_id_allocation); + surface_id_updated = true; + } + + // Allocate a new surface ID if the surface has been resized or if the current + // ID is invalid (meaning we may have been evicted). + if (resized || !GetCurrentLocalSurfaceIdAllocation().IsValid()) { + AllocateLocalSurfaceId(); + surface_id_updated = true; + } + + if (surface_id_updated) { + delegated_frame_host_->EmbedSurface( + GetCurrentLocalSurfaceIdAllocation().local_surface_id(), + GetViewBounds().size(), deadline_policy); + + // |render_widget_host_| will retrieve resize parameters from the + // DelegatedFrameHost and this view, so SynchronizeVisualProperties must be + // called last. + if (render_widget_host_) { + render_widget_host_->SynchronizeVisualProperties(); + } + } } void CefRenderWidgetHostViewOSR::OnScreenInfoChanged() { @@ -898,7 +1025,8 @@ void CefRenderWidgetHostViewOSR::OnScreenInfoChanged() { if (!render_widget_host_) return; - SynchronizeVisualProperties(); + SynchronizeVisualProperties(cc::DeadlinePolicy::UseDefaultDeadline(), + base::nullopt); if (render_widget_host_->delegate()) render_widget_host_->delegate()->SendScreenRects(); @@ -1259,32 +1387,16 @@ void CefRenderWidgetHostViewOSR::UpdateFrameRate() { frame_rate_threshold_us_ = 0; SetFrameRate(); + if (video_consumer_) { + video_consumer_->SetFrameRate( + base::TimeDelta::FromMicroseconds(frame_rate_threshold_us_)); + } + // Notify the guest hosts if any. for (auto guest_host_view : guest_host_views_) guest_host_view->UpdateFrameRate(); } -void CefRenderWidgetHostViewOSR::HoldResize() { - if (!hold_resize_) - hold_resize_ = true; -} - -void CefRenderWidgetHostViewOSR::ReleaseResize() { - if (!hold_resize_) - return; - - hold_resize_ = false; - if (pending_resize_) { - bool force = pending_resize_force_; - pending_resize_ = false; - pending_resize_force_ = false; - CEF_POST_TASK( - CEF_UIT, - base::Bind(&CefRenderWidgetHostViewOSR::SynchronizeVisualProperties, - weak_ptr_factory_.GetWeakPtr(), force)); - } -} - gfx::Size CefRenderWidgetHostViewOSR::SizeInPixels() { return gfx::ConvertSizeToPixel(current_device_scale_factor_, GetViewBounds().size()); @@ -1316,10 +1428,6 @@ void CefRenderWidgetHostViewOSR::OnPaint(const gfx::Rect& damage_rect, browser_impl_->client()->GetRenderHandler(); CHECK(handler); - // Don't execute SynchronizeVisualProperties while the OnPaint callback is - // pending. - HoldResize(); - gfx::Rect rect_in_pixels(0, 0, pixel_size.width(), pixel_size.height()); rect_in_pixels.Intersect(damage_rect); @@ -1330,18 +1438,15 @@ void CefRenderWidgetHostViewOSR::OnPaint(const gfx::Rect& damage_rect, handler->OnPaint(browser_impl_.get(), IsPopupWidget() ? PET_POPUP : PET_VIEW, rcList, pixels, pixel_size.width(), pixel_size.height()); - ReleaseResize(); + // Release the resize hold when we reach the desired size. + if (hold_resize_ && pixel_size == SizeInPixels()) + ReleaseResizeHold(); } ui::Layer* CefRenderWidgetHostViewOSR::GetRootLayer() const { return root_layer_.get(); } -content::DelegatedFrameHost* CefRenderWidgetHostViewOSR::GetDelegatedFrameHost() - const { - return delegated_frame_host_.get(); -} - void CefRenderWidgetHostViewOSR::SetFrameRate() { CefRefPtr browser; if (parent_host_view_) { @@ -1373,19 +1478,13 @@ void CefRenderWidgetHostViewOSR::SetFrameRate() { } } -void CefRenderWidgetHostViewOSR::SetDeviceScaleFactor() { - float new_scale_factor = kDefaultScaleFactor; +bool CefRenderWidgetHostViewOSR::SetDeviceScaleFactor() { + // This method should not be called while the resize hold is active. + DCHECK(!hold_resize_); - if (browser_impl_.get()) { - CefScreenInfo screen_info(kDefaultScaleFactor, 0, 0, false, CefRect(), - CefRect()); - CefRefPtr handler = - browser_impl_->client()->GetRenderHandler(); - CHECK(handler); - if (handler->GetScreenInfo(browser_impl_.get(), screen_info)) { - new_scale_factor = screen_info.device_scale_factor; - } - } + const float new_scale_factor = ::GetDeviceScaleFactor(browser_impl_.get()); + if (new_scale_factor == current_device_scale_factor_) + return false; current_device_scale_factor_ = new_scale_factor; @@ -1397,52 +1496,69 @@ void CefRenderWidgetHostViewOSR::SetDeviceScaleFactor() { if (rwhi->GetView()) rwhi->GetView()->set_current_device_scale_factor(new_scale_factor); } + + return true; } -void CefRenderWidgetHostViewOSR::ResizeRootLayer(bool force) { - SetFrameRate(); +bool CefRenderWidgetHostViewOSR::SetViewBounds() { + // This method should not be called while the resize hold is active. + DCHECK(!hold_resize_); - const float orgScaleFactor = current_device_scale_factor_; - SetDeviceScaleFactor(); - const bool scaleFactorDidChange = - (orgScaleFactor != current_device_scale_factor_); + // Popup bounds are set in InitAsPopup. + if (IsPopupWidget()) + return false; - gfx::Size size; - if (!IsPopupWidget()) - size = GetViewBounds().size(); - else - size = popup_position_.size(); + const gfx::Rect& new_bounds = ::GetViewBounds(browser_impl_.get()); + if (new_bounds == current_view_bounds_) + return false; - if (!force && !scaleFactorDidChange && - size == GetRootLayer()->bounds().size()) { - return; - } + current_view_bounds_ = new_bounds; + return true; +} - GetRootLayer()->SetBounds(gfx::Rect(size)); +bool CefRenderWidgetHostViewOSR::SetRootLayerSize(bool force) { + const bool scale_factor_changed = SetDeviceScaleFactor(); + const bool view_bounds_changed = SetViewBounds(); + if (!force && !scale_factor_changed && !view_bounds_changed) + return false; - const gfx::Size& size_in_pixels = - gfx::ConvertSizeToPixel(current_device_scale_factor_, size); - - local_surface_id_allocator_.GenerateId(); - local_surface_id_allocation_ = - local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation(); + GetRootLayer()->SetBounds(gfx::Rect(GetViewBounds().size())); if (compositor_) { compositor_local_surface_id_allocator_.GenerateId(); - compositor_->SetScaleAndSize(current_device_scale_factor_, size_in_pixels, + compositor_->SetScaleAndSize(current_device_scale_factor_, SizeInPixels(), compositor_local_surface_id_allocator_ .GetCurrentLocalSurfaceIdAllocation()); } - GetDelegatedFrameHost()->EmbedSurface( - local_surface_id_allocation_.local_surface_id(), size, - cc::DeadlinePolicy::UseDefaultDeadline()); + return (scale_factor_changed || view_bounds_changed); +} - // Note that |render_widget_host_| will retrieve resize parameters from the - // DelegatedFrameHost, so it must have SynchronizeVisualProperties called - // after. - if (render_widget_host_) - render_widget_host_->SynchronizeVisualProperties(); +bool CefRenderWidgetHostViewOSR::ResizeRootLayer() { + if (!hold_resize_) { + // The resize hold is not currently active. + if (SetRootLayerSize(false /* force */)) { + // The size has changed. Avoid resizing again until ReleaseResizeHold() is + // called. + hold_resize_ = true; + return true; + } + } else if (!pending_resize_) { + // The resize hold is currently active. Another resize will be triggered + // from ReleaseResizeHold(). + pending_resize_ = true; + } + return false; +} + +void CefRenderWidgetHostViewOSR::ReleaseResizeHold() { + DCHECK(hold_resize_); + hold_resize_ = false; + if (pending_resize_) { + pending_resize_ = false; + CEF_POST_TASK(CEF_UIT, base::Bind(&CefRenderWidgetHostViewOSR::WasResized, + weak_ptr_factory_.GetWeakPtr())); + } } void CefRenderWidgetHostViewOSR::CancelWidget() { @@ -1509,7 +1625,7 @@ void CefRenderWidgetHostViewOSR::RemoveGuestHostView( void CefRenderWidgetHostViewOSR::InvalidateInternal( const gfx::Rect& bounds_in_pixels) { if (video_consumer_) { - video_consumer_->SizeChanged(); + video_consumer_->RequestRefreshFrame(bounds_in_pixels); } else if (host_display_client_) { OnPaint(bounds_in_pixels, host_display_client_->GetPixelSize(), host_display_client_->GetPixelMemory()); diff --git a/libcef/browser/osr/render_widget_host_view_osr.h b/libcef/browser/osr/render_widget_host_view_osr.h index 67e8874d6..c853bbab6 100644 --- a/libcef/browser/osr/render_widget_host_view_osr.h +++ b/libcef/browser/osr/render_widget_host_view_osr.h @@ -21,6 +21,7 @@ #include "base/memory/weak_ptr.h" #include "base/optional.h" #include "build/build_config.h" +#include "cc/layers/deadline_policy.h" #include "components/viz/common/frame_sinks/begin_frame_source.h" #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h" #include "content/browser/renderer_host/input/mouse_wheel_phase_handler.h" @@ -189,6 +190,7 @@ class CefRenderWidgetHostViewOSR : public content::RenderWidgetHostViewBase, const override; const viz::FrameSinkId& GetFrameSinkId() const override; viz::FrameSinkId GetRootFrameSinkId() override; + void OnRenderFrameMetadataChangedAfterActivation() override; void OnFrameComplete(const viz::BeginFrameAck& ack); @@ -208,7 +210,11 @@ class CefRenderWidgetHostViewOSR : public content::RenderWidgetHostViewBase, bool InstallTransparency(); - void SynchronizeVisualProperties(bool force = false); + void WasResized(); + void SynchronizeVisualProperties( + const cc::DeadlinePolicy& deadline_policy, + const base::Optional& + child_local_surface_id_allocation); void OnScreenInfoChanged(); void Invalidate(CefBrowserHost::PaintElementType type); void SendExternalBeginFrame(); @@ -220,9 +226,6 @@ class CefRenderWidgetHostViewOSR : public content::RenderWidgetHostViewBase, void SendFocusEvent(bool focus); void UpdateFrameRate(); - void HoldResize(); - void ReleaseResize(); - gfx::Size SizeInPixels(); void OnPaint(const gfx::Rect& damage_rect, const gfx::Size& pixel_size, @@ -269,11 +272,14 @@ class CefRenderWidgetHostViewOSR : public content::RenderWidgetHostViewBase, const cc::RenderFrameMetadata& metadata); private: - content::DelegatedFrameHost* GetDelegatedFrameHost() const; - void SetFrameRate(); - void SetDeviceScaleFactor(); - void ResizeRootLayer(bool force); + bool SetDeviceScaleFactor(); + bool SetViewBounds(); + bool SetRootLayerSize(bool force); + + // Manages resizing so that only one resize request is in-flight at a time. + bool ResizeRootLayer(); + void ReleaseResizeHold(); void CancelWidget(); @@ -296,6 +302,27 @@ class CefRenderWidgetHostViewOSR : public content::RenderWidgetHostViewBase, viz::FrameSinkId AllocateFrameSinkId(); + // Forces the view to allocate a new viz::LocalSurfaceId for the next + // CompositorFrame submission in anticipation of a synchronization operation + // that does not involve a resize or a device scale factor change. + void AllocateLocalSurfaceId(); + const viz::LocalSurfaceIdAllocation& GetCurrentLocalSurfaceIdAllocation() + const; + + // Sets the current viz::LocalSurfaceId, in cases where the embedded client + // has allocated one. Also sets child sequence number component of the + // viz::LocalSurfaceId allocator. + void UpdateLocalSurfaceIdFromEmbeddedClient( + const base::Optional& + local_surface_id_allocation); + + // Returns the current viz::LocalSurfaceIdAllocation. + const viz::LocalSurfaceIdAllocation& GetOrCreateLocalSurfaceIdAllocation(); + + // Marks the current viz::LocalSurfaceId as invalid. AllocateLocalSurfaceId + // must be called before submitting new CompositorFrames. + void InvalidateLocalSurfaceId(); + void AddDamageRect(uint32_t sequence, const gfx::Rect& rect); // Applies background color without notifying the RenderWidget about @@ -309,15 +336,17 @@ class CefRenderWidgetHostViewOSR : public content::RenderWidgetHostViewBase, // The background color of the web content. SkColor background_color_; - int frame_rate_threshold_us_; + int frame_rate_threshold_us_ = 0; std::unique_ptr compositor_; std::unique_ptr delegated_frame_host_; std::unique_ptr delegated_frame_host_client_; std::unique_ptr root_layer_; - viz::LocalSurfaceIdAllocation local_surface_id_allocation_; - viz::ParentLocalSurfaceIdAllocator local_surface_id_allocator_; + + // Used to allocate LocalSurfaceIds when this is embedding external content. + std::unique_ptr + parent_local_surface_id_allocator_; viz::ParentLocalSurfaceIdAllocator compositor_local_surface_id_allocator_; #if defined(USE_X11) @@ -334,12 +363,11 @@ class CefRenderWidgetHostViewOSR : public content::RenderWidgetHostViewBase, bool external_begin_frame_enabled_ = false; bool needs_external_begin_frames_ = false; - CefHostDisplayClientOSR* host_display_client_; + CefHostDisplayClientOSR* host_display_client_ = nullptr; std::unique_ptr video_consumer_; - bool hold_resize_; - bool pending_resize_; - bool pending_resize_force_; + bool hold_resize_ = false; + bool pending_resize_ = false; // The associated Model. While |this| is being Destroyed, // |render_widget_host_| is NULL and the message loop is run one last time @@ -348,14 +376,16 @@ class CefRenderWidgetHostViewOSR : public content::RenderWidgetHostViewBase, bool has_parent_; CefRenderWidgetHostViewOSR* parent_host_view_; - CefRenderWidgetHostViewOSR* popup_host_view_; - CefRenderWidgetHostViewOSR* child_host_view_; + CefRenderWidgetHostViewOSR* popup_host_view_ = nullptr; + CefRenderWidgetHostViewOSR* child_host_view_ = nullptr; std::set guest_host_views_; CefRefPtr browser_impl_; - bool is_showing_; - bool is_destroyed_; + bool is_showing_ = false; + bool is_destroyed_ = false; + bool is_first_navigation_ = true; + gfx::Rect current_view_bounds_; gfx::Rect popup_position_; base::Lock damage_rect_lock_; std::map damage_rects_; @@ -366,7 +396,7 @@ class CefRenderWidgetHostViewOSR : public content::RenderWidgetHostViewBase, // The last scroll offset of the view. gfx::Vector2dF last_scroll_offset_; - bool is_scroll_offset_changed_pending_; + bool is_scroll_offset_changed_pending_ = false; content::MouseWheelPhaseHandler mouse_wheel_phase_handler_; @@ -382,7 +412,7 @@ class CefRenderWidgetHostViewOSR : public content::RenderWidgetHostViewBase, ui::FilteredGestureProvider gesture_provider_; CefMotionEventOSR pointer_state_; - bool forward_touch_to_popup_; + bool forward_touch_to_popup_ = false; base::WeakPtrFactory weak_ptr_factory_; diff --git a/libcef/browser/osr/video_consumer_osr.cc b/libcef/browser/osr/video_consumer_osr.cc index 857a524c3..66e656d4c 100644 --- a/libcef/browser/osr/video_consumer_osr.cc +++ b/libcef/browser/osr/video_consumer_osr.cc @@ -11,16 +11,35 @@ #include "media/capture/mojom/video_capture_types.mojom.h" #include "ui/gfx/skbitmap_operations.h" +namespace { + +// Helper to always call Done() at the end of OnFrameCaptured(). +class ScopedVideoFrameDone { + public: + explicit ScopedVideoFrameDone( + mojo::PendingRemote + callbacks) + : callbacks_(std::move(callbacks)) {} + ~ScopedVideoFrameDone() { callbacks_->Done(); } + + private: + mojo::Remote callbacks_; +}; + +} // namespace + CefVideoConsumerOSR::CefVideoConsumerOSR(CefRenderWidgetHostViewOSR* view) - : view_(view), - video_capturer_(view->CreateVideoCapturer()), - weak_ptr_factory_(this) { - const gfx::Size view_size = view_->SizeInPixels(); - video_capturer_->SetResolutionConstraints(view_size, view_size, true); - video_capturer_->SetAutoThrottlingEnabled(false); - video_capturer_->SetMinSizeChangePeriod(base::TimeDelta()); + : view_(view), video_capturer_(view->CreateVideoCapturer()) { video_capturer_->SetFormat(media::PIXEL_FORMAT_ARGB, gfx::ColorSpace::CreateREC709()); + + // Always use the highest resolution within constraints that doesn't exceed + // the source size. + video_capturer_->SetAutoThrottlingEnabled(false); + video_capturer_->SetMinSizeChangePeriod(base::TimeDelta()); + + SizeChanged(view_->SizeInPixels()); + SetActive(true); } CefVideoConsumerOSR::~CefVideoConsumerOSR() = default; @@ -37,42 +56,49 @@ void CefVideoConsumerOSR::SetFrameRate(base::TimeDelta frame_rate) { video_capturer_->SetMinCapturePeriod(frame_rate); } -void CefVideoConsumerOSR::SizeChanged() { - const gfx::Size view_size = view_->SizeInPixels(); - video_capturer_->SetResolutionConstraints(view_size, view_size, true); +void CefVideoConsumerOSR::SizeChanged(const gfx::Size& size_in_pixels) { + if (size_in_pixels_ == size_in_pixels) + return; + size_in_pixels_ = size_in_pixels; + + // Capture resolution will be held constant. + video_capturer_->SetResolutionConstraints(size_in_pixels, size_in_pixels, + true /* use_fixed_aspect_ratio */); +} + +void CefVideoConsumerOSR::RequestRefreshFrame( + const base::Optional& bounds_in_pixels) { + bounds_in_pixels_ = bounds_in_pixels; video_capturer_->RequestRefreshFrame(); } +// Frame size values are as follows: +// info->coded_size = Width and height of the video frame. Not all pixels in +// this region are valid. +// info->visible_rect = Region of coded_size that contains image data, also +// known as the clean aperture. +// content_rect = Region of the frame that contains the captured content, with +// the rest of the frame having been letterboxed to adhere to resolution +// constraints. void CefVideoConsumerOSR::OnFrameCaptured( base::ReadOnlySharedMemoryRegion data, ::media::mojom::VideoFrameInfoPtr info, const gfx::Rect& content_rect, mojo::PendingRemote callbacks) { - const gfx::Size view_size = view_->SizeInPixels(); - if (view_size != content_rect.size()) { - video_capturer_->SetResolutionConstraints(view_size, view_size, true); - video_capturer_->RequestRefreshFrame(); - return; - } + ScopedVideoFrameDone scoped_done(std::move(callbacks)); - mojo::Remote - callbacks_remote(std::move(callbacks)); - - if (!data.IsValid()) { - callbacks_remote->Done(); + if (!data.IsValid()) return; - } + base::ReadOnlySharedMemoryMapping mapping = data.Map(); if (!mapping.IsValid()) { DLOG(ERROR) << "Shared memory mapping failed."; - callbacks_remote->Done(); return; } if (mapping.size() < media::VideoFrame::AllocationSize(info->pixel_format, info->coded_size)) { DLOG(ERROR) << "Shared memory size was less than expected."; - callbacks_remote->Done(); return; } @@ -84,15 +110,27 @@ void CefVideoConsumerOSR::OnFrameCaptured( metadata.MergeInternalValuesFrom(info->metadata); gfx::Rect damage_rect; - if (!metadata.GetRect(media::VideoFrameMetadata::CAPTURE_UPDATE_RECT, - &damage_rect) || - damage_rect.IsEmpty()) { - damage_rect = content_rect; + if (bounds_in_pixels_) { + // Use the bounds passed to RequestRefreshFrame(). + damage_rect = gfx::Rect(info->coded_size); + damage_rect.Intersect(*bounds_in_pixels_); + bounds_in_pixels_ = base::nullopt; + } else { + // Retrieve the rectangular region of the frame that has changed since the + // frame with the directly preceding CAPTURE_COUNTER. If that frame was not + // received, typically because it was dropped during transport from the + // producer, clients must assume that the entire frame has changed. + // This rectangle is relative to the full frame data, i.e. [0, 0, + // coded_size.width(), coded_size.height()]. It does not have to be + // fully contained within visible_rect. + if (!metadata.GetRect(media::VideoFrameMetadata::CAPTURE_UPDATE_RECT, + &damage_rect) || + damage_rect.IsEmpty()) { + damage_rect = gfx::Rect(info->coded_size); + } } view_->OnPaint(damage_rect, info->coded_size, pixels); - - callbacks_remote->Done(); } void CefVideoConsumerOSR::OnStopped() {} diff --git a/libcef/browser/osr/video_consumer_osr.h b/libcef/browser/osr/video_consumer_osr.h index 479f75aed..e78973b91 100644 --- a/libcef/browser/osr/video_consumer_osr.h +++ b/libcef/browser/osr/video_consumer_osr.h @@ -2,7 +2,7 @@ #define LIBCEF_BROWSER_OSR_VIDEO_CONSUMER_OSR_H_ #include "base/callback.h" -#include "base/memory/weak_ptr.h" +#include "base/optional.h" #include "components/viz/host/client_frame_sink_video_capturer.h" #include "media/capture/mojom/video_capture_types.mojom.h" @@ -15,7 +15,8 @@ class CefVideoConsumerOSR : public viz::mojom::FrameSinkVideoConsumer { void SetActive(bool active); void SetFrameRate(base::TimeDelta frame_rate); - void SizeChanged(); + void SizeChanged(const gfx::Size& size_in_pixels); + void RequestRefreshFrame(const base::Optional& bounds_in_pixels); private: // viz::mojom::FrameSinkVideoConsumer implementation. @@ -30,7 +31,8 @@ class CefVideoConsumerOSR : public viz::mojom::FrameSinkVideoConsumer { CefRenderWidgetHostViewOSR* const view_; std::unique_ptr video_capturer_; - base::WeakPtrFactory weak_ptr_factory_; + gfx::Size size_in_pixels_; + base::Optional bounds_in_pixels_; DISALLOW_COPY_AND_ASSIGN(CefVideoConsumerOSR); }; diff --git a/libcef/browser/views/browser_platform_delegate_views.cc b/libcef/browser/views/browser_platform_delegate_views.cc index 3c7e649bc..48c09f712 100644 --- a/libcef/browser/views/browser_platform_delegate_views.cc +++ b/libcef/browser/views/browser_platform_delegate_views.cc @@ -184,8 +184,8 @@ SkColor CefBrowserPlatformDelegateViews::GetBackgroundColor() const { return native_delegate_->GetBackgroundColor(); } -void CefBrowserPlatformDelegateViews::SynchronizeVisualProperties() { - native_delegate_->SynchronizeVisualProperties(); +void CefBrowserPlatformDelegateViews::WasResized() { + native_delegate_->WasResized(); } void CefBrowserPlatformDelegateViews::SendKeyEvent(const CefKeyEvent& event) { diff --git a/libcef/browser/views/browser_platform_delegate_views.h b/libcef/browser/views/browser_platform_delegate_views.h index c723f3d2c..d10619488 100644 --- a/libcef/browser/views/browser_platform_delegate_views.h +++ b/libcef/browser/views/browser_platform_delegate_views.h @@ -42,7 +42,7 @@ class CefBrowserPlatformDelegateViews bool CanUseSharedTexture() const override; bool CanUseExternalBeginFrame() const override; SkColor GetBackgroundColor() const override; - void SynchronizeVisualProperties() override; + void WasResized() override; void SendKeyEvent(const CefKeyEvent& event) override; void SendMouseClickEvent(const CefMouseEvent& event, CefBrowserHost::MouseButtonType type, diff --git a/tests/ceftests/os_rendering_unittest.cc b/tests/ceftests/os_rendering_unittest.cc index 4bdab30f7..5f5f46d1f 100644 --- a/tests/ceftests/os_rendering_unittest.cc +++ b/tests/ceftests/os_rendering_unittest.cc @@ -626,12 +626,17 @@ class OSRTestHandler : public RoutingTestHandler, case OSR_TEST_RESIZE: if (StartTest()) { browser->GetHost()->WasResized(); - // There may be some partial repaints before the full repaint. - } else if (IsFullRepaint(dirtyRects[0], width, height)) { - EXPECT_EQ(GetScaledInt(kOsrWidth) * 2, width); - EXPECT_EQ(GetScaledInt(kOsrHeight) * 2, height); + } else { + // There may be some partial repaints before the full repaint at the + // desired size. + const int desired_width = GetScaledInt(kOsrWidth) * 2; + const int desired_height = GetScaledInt(kOsrHeight) * 2; + EXPECT_EQ(dirtyRects.size(), 1U); - DestroySucceededTestSoon(); + if (width == desired_width && height == desired_height && + IsFullRepaint(dirtyRects[0], width, height)) { + DestroySucceededTestSoon(); + } } break; case OSR_TEST_INVALIDATE: {