diff --git a/BUILD.gn b/BUILD.gn index 6d09a61c16e3..ba8f857c02e9 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -632,11 +632,13 @@ static_library("electron_lib") { if (enable_osr) { sources += [ - "atom/browser/osr/osr_output_device.cc", - "atom/browser/osr/osr_output_device.h", + "atom/browser/osr/osr_host_display_client.cc", + "atom/browser/osr/osr_host_display_client.h", + "atom/browser/osr/osr_host_display_client_mac.mm", "atom/browser/osr/osr_render_widget_host_view.cc", "atom/browser/osr/osr_render_widget_host_view.h", - "atom/browser/osr/osr_render_widget_host_view_mac.mm", + "atom/browser/osr/osr_video_consumer.cc", + "atom/browser/osr/osr_video_consumer.h", "atom/browser/osr/osr_view_proxy.cc", "atom/browser/osr/osr_view_proxy.h", "atom/browser/osr/osr_web_contents_view.cc", @@ -811,6 +813,11 @@ if (is_mac) { "ServiceManagement.framework", "StoreKit.framework", ] + + if (enable_osr) { + libs += [ "IOSurface.framework" ] + } + ldflags = [ "-F", rebase_path("external_binaries", root_build_dir), diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index c98381cef637..c7e78e9813ce 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -91,7 +91,6 @@ #include "ui/events/base_event_utils.h" #if BUILDFLAG(ENABLE_OSR) -#include "atom/browser/osr/osr_output_device.h" #include "atom/browser/osr/osr_render_widget_host_view.h" #include "atom/browser/osr/osr_web_contents_view.h" #endif diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 83bc53f746e4..6ee746121df0 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -233,7 +233,10 @@ namespace atom { namespace { bool IsFramelessWindow(NSView* view) { - NativeWindow* window = [static_cast([view window]) shell]; + NSWindow* nswindow = [view window]; + if (![nswindow respondsToSelector:@selector(shell)]) + return false; + NativeWindow* window = [static_cast(nswindow) shell]; return window && !window->has_frame(); } diff --git a/atom/browser/osr/osr_host_display_client.cc b/atom/browser/osr/osr_host_display_client.cc new file mode 100644 index 000000000000..98709b13751e --- /dev/null +++ b/atom/browser/osr/osr_host_display_client.cc @@ -0,0 +1,121 @@ +// Copyright (c) 2019 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/osr/osr_host_display_client.h" + +#include + +#include "components/viz/common/resources/resource_format.h" +#include "components/viz/common/resources/resource_sizes.h" +#include "mojo/public/cpp/system/platform_handle.h" +#include "skia/ext/platform_canvas.h" +#include "third_party/skia/include/core/SkColor.h" +#include "third_party/skia/include/core/SkRect.h" +#include "third_party/skia/src/core/SkDevice.h" +#include "ui/gfx/skia_util.h" + +#if defined(OS_WIN) +#include "skia/ext/skia_utils_win.h" +#endif + +namespace atom { + +LayeredWindowUpdater::LayeredWindowUpdater( + viz::mojom::LayeredWindowUpdaterRequest request, + OnPaintCallback callback) + : callback_(callback), binding_(this, std::move(request)) {} + +LayeredWindowUpdater::~LayeredWindowUpdater() = default; + +void LayeredWindowUpdater::SetActive(bool active) { + active_ = active; +} + +void LayeredWindowUpdater::OnAllocatedSharedMemory( + const gfx::Size& pixel_size, + mojo::ScopedSharedBufferHandle scoped_buffer_handle) { + canvas_.reset(); + + // Make sure |pixel_size| is sane. + size_t expected_bytes; + bool size_result = viz::ResourceSizes::MaybeSizeInBytes( + pixel_size, viz::ResourceFormat::RGBA_8888, &expected_bytes); + if (!size_result) + return; + +#if defined(WIN32) + base::SharedMemoryHandle shm_handle; + size_t required_bytes; + MojoResult unwrap_result = mojo::UnwrapSharedMemoryHandle( + std::move(scoped_buffer_handle), &shm_handle, &required_bytes, nullptr); + if (unwrap_result != MOJO_RESULT_OK) + return; + + base::SharedMemory shm(shm_handle, false); + if (!shm.Map(required_bytes)) { + DLOG(ERROR) << "Failed to map " << required_bytes << " bytes"; + return; + } + + canvas_ = skia::CreatePlatformCanvasWithSharedSection( + pixel_size.width(), pixel_size.height(), false, shm.handle().GetHandle(), + skia::CRASH_ON_FAILURE); +#else + auto shm = + mojo::UnwrapWritableSharedMemoryRegion(std::move(scoped_buffer_handle)); + if (!shm.IsValid()) { + DLOG(ERROR) << "Failed to unwrap shared memory region"; + return; + } + + shm_mapping_ = shm.Map(); + if (!shm_mapping_.IsValid()) { + DLOG(ERROR) << "Failed to map shared memory region"; + return; + } + + canvas_ = skia::CreatePlatformCanvasWithPixels( + pixel_size.width(), pixel_size.height(), false, + static_cast(shm_mapping_.memory()), skia::CRASH_ON_FAILURE); +#endif +} + +void LayeredWindowUpdater::Draw(const gfx::Rect& damage_rect, + DrawCallback draw_callback) { + SkPixmap pixmap; + SkBitmap bitmap; + + if (active_ && canvas_->peekPixels(&pixmap)) { + bitmap.installPixels(pixmap); + callback_.Run(damage_rect, bitmap); + } + + std::move(draw_callback).Run(); +} + +OffScreenHostDisplayClient::OffScreenHostDisplayClient( + gfx::AcceleratedWidget widget, + OnPaintCallback callback) + : viz::HostDisplayClient(widget), callback_(callback) {} +OffScreenHostDisplayClient::~OffScreenHostDisplayClient() {} + +void OffScreenHostDisplayClient::SetActive(bool active) { + active_ = active; + if (layered_window_updater_) { + layered_window_updater_->SetActive(active_); + } +} + +void OffScreenHostDisplayClient::IsOffscreen(IsOffscreenCallback callback) { + std::move(callback).Run(true); +} + +void OffScreenHostDisplayClient::CreateLayeredWindowUpdater( + viz::mojom::LayeredWindowUpdaterRequest request) { + layered_window_updater_ = + std::make_unique(std::move(request), callback_); + layered_window_updater_->SetActive(active_); +} + +} // namespace atom diff --git a/atom/browser/osr/osr_host_display_client.h b/atom/browser/osr/osr_host_display_client.h new file mode 100644 index 000000000000..7f7ee44d5eaa --- /dev/null +++ b/atom/browser/osr/osr_host_display_client.h @@ -0,0 +1,77 @@ +// Copyright (c) 2019 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_OSR_OSR_HOST_DISPLAY_CLIENT_H_ +#define ATOM_BROWSER_OSR_OSR_HOST_DISPLAY_CLIENT_H_ + +#include + +#include "base/callback.h" +#include "base/memory/shared_memory.h" +#include "components/viz/host/host_display_client.h" +#include "services/viz/privileged/interfaces/compositing/layered_window_updater.mojom.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "ui/gfx/native_widget_types.h" + +namespace atom { + +typedef base::Callback OnPaintCallback; + +class LayeredWindowUpdater : public viz::mojom::LayeredWindowUpdater { + public: + explicit LayeredWindowUpdater(viz::mojom::LayeredWindowUpdaterRequest request, + OnPaintCallback callback); + ~LayeredWindowUpdater() override; + + void SetActive(bool active); + + // viz::mojom::LayeredWindowUpdater implementation. + void OnAllocatedSharedMemory( + const gfx::Size& pixel_size, + mojo::ScopedSharedBufferHandle scoped_buffer_handle) override; + void Draw(const gfx::Rect& damage_rect, DrawCallback draw_callback) override; + + private: + OnPaintCallback callback_; + mojo::Binding binding_; + std::unique_ptr canvas_; + bool active_ = false; + +#if !defined(WIN32) + base::WritableSharedMemoryMapping shm_mapping_; +#endif + + DISALLOW_COPY_AND_ASSIGN(LayeredWindowUpdater); +}; + +class OffScreenHostDisplayClient : public viz::HostDisplayClient { + public: + explicit OffScreenHostDisplayClient(gfx::AcceleratedWidget widget, + OnPaintCallback callback); + ~OffScreenHostDisplayClient() override; + + void SetActive(bool active); + + private: + void IsOffscreen(IsOffscreenCallback callback) override; + +#if defined(OS_MACOSX) + void OnDisplayReceivedCALayerParams( + const gfx::CALayerParams& ca_layer_params) override; +#endif + + void CreateLayeredWindowUpdater( + viz::mojom::LayeredWindowUpdaterRequest request) override; + + std::unique_ptr layered_window_updater_; + OnPaintCallback callback_; + bool active_ = false; + + DISALLOW_COPY_AND_ASSIGN(OffScreenHostDisplayClient); +}; + +} // namespace atom + +#endif // ATOM_BROWSER_OSR_OSR_HOST_DISPLAY_CLIENT_H_ diff --git a/atom/browser/osr/osr_host_display_client_mac.mm b/atom/browser/osr/osr_host_display_client_mac.mm new file mode 100644 index 000000000000..0e1bea2763e9 --- /dev/null +++ b/atom/browser/osr/osr_host_display_client_mac.mm @@ -0,0 +1,35 @@ +// Copyright (c) 2019 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/osr/osr_host_display_client.h" + +#include + +namespace atom { + +void OffScreenHostDisplayClient::OnDisplayReceivedCALayerParams( + const gfx::CALayerParams& ca_layer_params) { + if (!ca_layer_params.is_empty) { + base::ScopedCFTypeRef io_surface( + IOSurfaceLookupFromMachPort(ca_layer_params.io_surface_mach_port)); + + gfx::Size pixel_size_ = ca_layer_params.pixel_size; + void* pixels = static_cast(IOSurfaceGetBaseAddress(io_surface)); + size_t stride = IOSurfaceGetBytesPerRow(io_surface); + + struct IOSurfacePinner { + base::ScopedCFTypeRef io_surface; + }; + + SkBitmap bitmap; + bitmap.installPixels( + SkImageInfo::MakeN32(pixel_size_.width(), pixel_size_.height(), + kPremul_SkAlphaType), + pixels, stride); + bitmap.setImmutable(); + callback_.Run(ca_layer_params.damage, bitmap); + } +} + +} // namespace atom diff --git a/atom/browser/osr/osr_output_device.cc b/atom/browser/osr/osr_output_device.cc deleted file mode 100644 index e5c1e7fd95fc..000000000000 --- a/atom/browser/osr/osr_output_device.cc +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/osr/osr_output_device.h" - -#include "third_party/skia/include/core/SkColor.h" -#include "third_party/skia/include/core/SkRect.h" -#include "third_party/skia/src/core/SkDevice.h" -#include "ui/gfx/skia_util.h" - -namespace atom { - -OffScreenOutputDevice::OffScreenOutputDevice(bool transparent, - const OnPaintCallback& callback) - : transparent_(transparent), callback_(callback) { - DCHECK(!callback_.is_null()); -} - -OffScreenOutputDevice::~OffScreenOutputDevice() {} - -void OffScreenOutputDevice::Resize(const gfx::Size& pixel_size, - float scale_factor) { - if (viewport_pixel_size_ == pixel_size) - return; - viewport_pixel_size_ = pixel_size; - - canvas_.reset(); - bitmap_.reset(new SkBitmap); - bitmap_->allocN32Pixels(viewport_pixel_size_.width(), - viewport_pixel_size_.height(), !transparent_); - if (bitmap_->drawsNothing()) { - NOTREACHED(); - bitmap_.reset(); - return; - } - - if (transparent_) { - bitmap_->eraseColor(SK_ColorTRANSPARENT); - } else { - bitmap_->eraseColor(SK_ColorWHITE); - } - - canvas_.reset(new SkCanvas(*bitmap_)); -} - -SkCanvas* OffScreenOutputDevice::BeginPaint(const gfx::Rect& damage_rect) { - DCHECK(canvas_.get()); - DCHECK(bitmap_.get()); - - damage_rect_ = damage_rect; - SkIRect damage = - SkIRect::MakeXYWH(damage_rect_.x(), damage_rect_.y(), - damage_rect_.width(), damage_rect_.height()); - - if (transparent_) { - bitmap_->erase(SK_ColorTRANSPARENT, damage); - } else { - bitmap_->erase(SK_ColorWHITE, damage); - } - - return canvas_.get(); -} - -void OffScreenOutputDevice::EndPaint() { - DCHECK(canvas_.get()); - DCHECK(bitmap_.get()); - - if (!bitmap_.get()) - return; - - viz::SoftwareOutputDevice::EndPaint(); - - if (active_) - OnPaint(damage_rect_); -} - -void OffScreenOutputDevice::SetActive(bool active, bool paint) { - if (active == active_) - return; - active_ = active; - - if (!active_ && !pending_damage_rect_.IsEmpty() && paint) - OnPaint(gfx::Rect(viewport_pixel_size_)); -} - -void OffScreenOutputDevice::OnPaint(const gfx::Rect& damage_rect) { - gfx::Rect rect = damage_rect; - if (!pending_damage_rect_.IsEmpty()) { - rect.Union(pending_damage_rect_); - pending_damage_rect_.SetRect(0, 0, 0, 0); - } - - rect.Intersect(gfx::Rect(viewport_pixel_size_)); - if (rect.IsEmpty()) - return; - - callback_.Run(rect, *bitmap_); -} - -} // namespace atom diff --git a/atom/browser/osr/osr_output_device.h b/atom/browser/osr/osr_output_device.h deleted file mode 100644 index c38c8f3f2c5b..000000000000 --- a/atom/browser/osr/osr_output_device.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_OSR_OSR_OUTPUT_DEVICE_H_ -#define ATOM_BROWSER_OSR_OSR_OUTPUT_DEVICE_H_ - -#include - -#include "base/callback.h" -#include "components/viz/service/display/software_output_device.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "third_party/skia/include/core/SkCanvas.h" - -namespace atom { - -typedef base::Callback OnPaintCallback; - -class OffScreenOutputDevice : public viz::SoftwareOutputDevice { - public: - OffScreenOutputDevice(bool transparent, const OnPaintCallback& callback); - ~OffScreenOutputDevice() override; - - // viz::SoftwareOutputDevice: - void Resize(const gfx::Size& pixel_size, float scale_factor) override; - SkCanvas* BeginPaint(const gfx::Rect& damage_rect) override; - void EndPaint() override; - - void SetActive(bool active, bool paint); - void OnPaint(const gfx::Rect& damage_rect); - - private: - const bool transparent_; - OnPaintCallback callback_; - - bool active_ = false; - - std::unique_ptr canvas_; - std::unique_ptr bitmap_; - gfx::Rect pending_damage_rect_; - - DISALLOW_COPY_AND_ASSIGN(OffScreenOutputDevice); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_OSR_OSR_OUTPUT_DEVICE_H_ diff --git a/atom/browser/osr/osr_render_widget_host_view.cc b/atom/browser/osr/osr_render_widget_host_view.cc index 48582705a430..9dff65aca782 100644 --- a/atom/browser/osr/osr_render_widget_host_view.cc +++ b/atom/browser/osr/osr_render_widget_host_view.cc @@ -20,14 +20,15 @@ #include "components/viz/common/frame_sinks/delay_based_time_source.h" #include "components/viz/common/gl_helper.h" #include "components/viz/common/quads/render_pass.h" -#include "content/browser/renderer_host/cursor_manager.h" -#include "content/browser/renderer_host/render_widget_host_delegate.h" -#include "content/browser/renderer_host/render_widget_host_impl.h" -#include "content/browser/renderer_host/render_widget_host_owner_delegate.h" +#include "content/browser/renderer_host/cursor_manager.h" // nogncheck +#include "content/browser/renderer_host/input/synthetic_gesture_target.h" // nogncheck +#include "content/browser/renderer_host/render_widget_host_delegate.h" // nogncheck +#include "content/browser/renderer_host/render_widget_host_owner_delegate.h" // nogncheck #include "content/common/view_messages.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/context_factory.h" +#include "content/public/browser/gpu_data_manager.h" #include "content/public/browser/render_process_host.h" #include "media/base/video_frame.h" #include "third_party/blink/public/platform/web_input_event.h" @@ -50,7 +51,6 @@ namespace atom { namespace { const float kDefaultScaleFactor = 1.0; -const int kFrameRetryLimit = 2; ui::MouseEvent UiMouseEventFromWebMouseEvent(blink::WebMouseEvent event) { ui::EventType type = ui::EventType::ET_UNKNOWN; @@ -120,105 +120,6 @@ ui::MouseWheelEvent UiMouseWheelEventFromWebMouseEvent( } // namespace -class AtomCopyFrameGenerator { - public: - AtomCopyFrameGenerator(OffScreenRenderWidgetHostView* view, - int frame_rate_threshold_us) - : view_(view), - frame_duration_( - base::TimeDelta::FromMicroseconds(frame_rate_threshold_us)), - weak_ptr_factory_(this) { - last_time_ = base::Time::Now(); - } - - void GenerateCopyFrame(const gfx::Rect& damage_rect) { - if (!view_->render_widget_host() || !view_->IsPainting()) - return; - - auto request = std::make_unique( - viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP, - base::BindOnce( - &AtomCopyFrameGenerator::CopyFromCompositingSurfaceHasResult, - weak_ptr_factory_.GetWeakPtr(), damage_rect)); - - request->set_area(gfx::Rect(view_->GetCompositorViewportPixelSize())); - view_->GetRootLayer()->RequestCopyOfOutput(std::move(request)); - } - - void set_frame_rate_threshold_us(int frame_rate_threshold_us) { - frame_duration_ = - base::TimeDelta::FromMicroseconds(frame_rate_threshold_us); - } - - private: - void CopyFromCompositingSurfaceHasResult( - const gfx::Rect& damage_rect, - std::unique_ptr result) { - if (result->IsEmpty() || result->size().IsEmpty() || - !view_->render_widget_host()) { - OnCopyFrameCaptureFailure(damage_rect); - return; - } - - DCHECK(!result->IsEmpty()); - auto source = std::make_unique(result->AsSkBitmap()); - DCHECK(source->readyToDraw()); - if (source) { - base::AutoLock autolock(lock_); - std::shared_ptr bitmap(source.release()); - - base::TimeTicks now = base::TimeTicks::Now(); - base::TimeDelta next_frame_in = next_frame_time_ - now; - if (next_frame_in > frame_duration_ / 4) { - next_frame_time_ += frame_duration_; - base::PostDelayedTaskWithTraits( - FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(&AtomCopyFrameGenerator::OnCopyFrameCaptureSuccess, - weak_ptr_factory_.GetWeakPtr(), damage_rect, bitmap), - next_frame_in); - } else { - next_frame_time_ = now + frame_duration_; - OnCopyFrameCaptureSuccess(damage_rect, bitmap); - } - - frame_retry_count_ = 0; - } else { - OnCopyFrameCaptureFailure(damage_rect); - } - } - - void OnCopyFrameCaptureFailure(const gfx::Rect& damage_rect) { - const bool force_frame = (++frame_retry_count_ <= kFrameRetryLimit); - if (force_frame) { - // Retry with the same |damage_rect|. - base::PostTaskWithTraits( - FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(&AtomCopyFrameGenerator::GenerateCopyFrame, - weak_ptr_factory_.GetWeakPtr(), damage_rect)); - } - } - - void OnCopyFrameCaptureSuccess(const gfx::Rect& damage_rect, - const std::shared_ptr& bitmap) { - base::AutoLock lock(onPaintLock_); - view_->OnPaint(damage_rect, *bitmap); - } - - base::Lock lock_; - base::Lock onPaintLock_; - OffScreenRenderWidgetHostView* view_; - - base::Time last_time_; - - int frame_retry_count_ = 0; - base::TimeTicks next_frame_time_ = base::TimeTicks::Now(); - base::TimeDelta frame_duration_; - - base::WeakPtrFactory weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(AtomCopyFrameGenerator); -}; - class AtomBeginFrameTimer : public viz::DelayBasedTimeSourceClient { public: AtomBeginFrameTimer(int frame_rate_threshold_us, @@ -253,7 +154,6 @@ class AtomBeginFrameTimer : public viz::DelayBasedTimeSourceClient { DISALLOW_COPY_AND_ASSIGN(AtomBeginFrameTimer); }; -#if !defined(OS_MACOSX) class AtomDelegatedFrameHostClient : public content::DelegatedFrameHostClient { public: explicit AtomDelegatedFrameHostClient(OffScreenRenderWidgetHostView* view) @@ -297,7 +197,6 @@ class AtomDelegatedFrameHostClient : public content::DelegatedFrameHostClient { DISALLOW_COPY_AND_ASSIGN(AtomDelegatedFrameHostClient); }; -#endif // !defined(OS_MACOSX) OffScreenRenderWidgetHostView::OffScreenRenderWidgetHostView( bool transparent, @@ -315,19 +214,23 @@ OffScreenRenderWidgetHostView::OffScreenRenderWidgetHostView( frame_rate_(frame_rate), size_(initial_size), painting_(painting), - is_showing_(!render_widget_host_->is_hidden()), + is_showing_(false), cursor_manager_(new content::CursorManager(this)), mouse_wheel_phase_handler_(this), + backing_(new SkBitmap), weak_ptr_factory_(this) { DCHECK(render_widget_host_); bool is_guest_view_hack = parent_host_view_ != nullptr; current_device_scale_factor_ = kDefaultScaleFactor; -#if !defined(OS_MACOSX) - local_surface_id_allocator_.GenerateId(); - local_surface_id_allocation_ = - local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation(); + delegated_frame_host_allocator_.GenerateId(); + delegated_frame_host_allocation_ = + delegated_frame_host_allocator_.GetCurrentLocalSurfaceIdAllocation(); + compositor_allocator_.GenerateId(); + compositor_allocation_ = + compositor_allocator_.GetCurrentLocalSurfaceIdAllocation(); + delegated_frame_host_client_.reset(new AtomDelegatedFrameHostClient(this)); delegated_frame_host_ = std::make_unique( AllocateFrameSinkId(is_guest_view_hack), @@ -335,59 +238,49 @@ OffScreenRenderWidgetHostView::OffScreenRenderWidgetHostView( true /* should_register_frame_sink_id */); root_layer_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR)); -#endif - -#if defined(OS_MACOSX) - last_frame_root_background_color_ = SK_ColorTRANSPARENT; - CreatePlatformWidget(is_guest_view_hack); -#endif bool opaque = SkColorGetA(background_color_) == SK_AlphaOPAQUE; GetRootLayer()->SetFillsBoundsOpaquely(opaque); GetRootLayer()->SetColor(background_color_); -#if !defined(OS_MACOSX) - // On macOS the ui::Compositor is created/owned by the platform view. content::ImageTransportFactory* factory = content::ImageTransportFactory::GetInstance(); + ui::ContextFactoryPrivate* context_factory_private = factory->GetContextFactoryPrivate(); - compositor_.reset(new ui::Compositor( - context_factory_private->AllocateFrameSinkId(), - content::GetContextFactory(), context_factory_private, - base::ThreadTaskRunnerHandle::Get(), false /* enable_pixel_canvas */)); + compositor_.reset( + new ui::Compositor(context_factory_private->AllocateFrameSinkId(), + content::GetContextFactory(), context_factory_private, + base::ThreadTaskRunnerHandle::Get(), + false /* enable_pixel_canvas */, this)); compositor_->SetAcceleratedWidget(gfx::kNullAcceleratedWidget); compositor_->SetRootLayer(root_layer_.get()); -#endif + GetCompositor()->SetDelegate(this); ResizeRootLayer(false); render_widget_host_->SetView(this); InstallTransparency(); + + if (content::GpuDataManager::GetInstance()->HardwareAccelerationEnabled()) { + video_consumer_.reset(new OffScreenVideoConsumer( + this, base::Bind(&OffScreenRenderWidgetHostView::OnPaint, + weak_ptr_factory_.GetWeakPtr()))); + video_consumer_->SetActive(IsPainting()); + video_consumer_->SetFrameRate(GetFrameRate()); + } } OffScreenRenderWidgetHostView::~OffScreenRenderWidgetHostView() { -#if defined(OS_MACOSX) - if (is_showing_) - browser_compositor_->SetRenderWidgetHostIsHidden(true); -#else // Marking the DelegatedFrameHost as removed from the window hierarchy is // necessary to remove all connections to its old ui::Compositor. if (is_showing_) delegated_frame_host_->WasHidden(); delegated_frame_host_->DetachFromCompositor(); -#endif - if (copy_frame_generator_.get()) - copy_frame_generator_.reset(NULL); - -#if defined(OS_MACOSX) - DestroyPlatformWidget(); -#else delegated_frame_host_.reset(NULL); compositor_.reset(NULL); root_layer_.reset(NULL); -#endif } content::BrowserAccessibilityManager* @@ -422,8 +315,17 @@ void OffScreenRenderWidgetHostView::SendBeginFrame( DCHECK(begin_frame_args.IsValid()); begin_frame_number_++; - if (renderer_compositor_frame_sink_) - renderer_compositor_frame_sink_->OnBeginFrame(begin_frame_args, {}); + compositor_->context_factory_private()->IssueExternalBeginFrame( + compositor_.get(), begin_frame_args); +} + +void OffScreenRenderWidgetHostView::OnDisplayDidFinishFrame( + const viz::BeginFrameAck& ack) {} + +void OffScreenRenderWidgetHostView::OnNeedsExternalBeginFrames( + bool needs_begin_frames) { + SetupFrameRate(true); + begin_frame_timer_->SetActive(needs_begin_frames); } void OffScreenRenderWidgetHostView::InitAsChild(gfx::NativeView) { @@ -437,7 +339,7 @@ void OffScreenRenderWidgetHostView::InitAsChild(gfx::NativeView) { parent_host_view_->Hide(); ResizeRootLayer(false); - Show(); + SetPainting(parent_host_view_->IsPainting()); } void OffScreenRenderWidgetHostView::SetSize(const gfx::Size& size) { @@ -478,14 +380,10 @@ void OffScreenRenderWidgetHostView::Show() { is_showing_ = true; -#if defined(OS_MACOSX) - browser_compositor_->SetRenderWidgetHostIsHidden(false); -#else delegated_frame_host_->AttachToCompositor(compositor_.get()); delegated_frame_host_->WasShown( GetLocalSurfaceIdAllocation().local_surface_id(), GetRootLayer()->bounds().size(), false); -#endif if (render_widget_host_) render_widget_host_->WasShown(false); @@ -498,12 +396,8 @@ void OffScreenRenderWidgetHostView::Hide() { if (render_widget_host_) render_widget_host_->WasHidden(); -#if defined(OS_MACOSX) - browser_compositor_->SetRenderWidgetHostIsHidden(true); -#else GetDelegatedFrameHost()->WasHidden(); GetDelegatedFrameHost()->DetachFromCompositor(); -#endif is_showing_ = false; } @@ -576,67 +470,17 @@ void OffScreenRenderWidgetHostView::DidCreateNewRendererCompositorFrameSink( viz::mojom::CompositorFrameSinkClient* renderer_compositor_frame_sink) { renderer_compositor_frame_sink_ = renderer_compositor_frame_sink; -#if defined(OS_MACOSX) - browser_compositor_->DidCreateNewRendererCompositorFrameSink( - renderer_compositor_frame_sink_); -#else if (GetDelegatedFrameHost()) { GetDelegatedFrameHost()->DidCreateNewRendererCompositorFrameSink( renderer_compositor_frame_sink_); } -#endif } void OffScreenRenderWidgetHostView::SubmitCompositorFrame( const viz::LocalSurfaceId& local_surface_id, viz::CompositorFrame frame, base::Optional hit_test_region_list) { -#if defined(OS_MACOSX) - last_frame_root_background_color_ = frame.metadata.root_background_color; -#endif - - if (frame.metadata.root_scroll_offset != last_scroll_offset_) { - last_scroll_offset_ = frame.metadata.root_scroll_offset; - } - - if (!frame.render_pass_list.empty()) { - if (software_output_device_) { - if (!begin_frame_timer_.get() || IsPopupWidget()) { - software_output_device_->SetActive(painting_, false); - } - - // The compositor will draw directly to the SoftwareOutputDevice which - // then calls OnPaint. - // We would normally call BrowserCompositorMac::SubmitCompositorFrame on - // macOS, however it contains compositor resize logic that we don't want. - // Consequently we instead call the SubmitCompositorFrame method directly. - GetDelegatedFrameHost()->SubmitCompositorFrame( - local_surface_id, std::move(frame), std::move(hit_test_region_list)); - } else { - if (!copy_frame_generator_.get()) { - copy_frame_generator_.reset( - new AtomCopyFrameGenerator(this, frame_rate_threshold_us_)); - } - - // Determine the damage rectangle for the current frame. This is the same - // calculation that SwapDelegatedFrame uses. - viz::RenderPass* root_pass = frame.render_pass_list.back().get(); - gfx::Size frame_size = root_pass->output_rect.size(); - gfx::Rect damage_rect = - gfx::ToEnclosingRect(gfx::RectF(root_pass->damage_rect)); - damage_rect.Intersect(gfx::Rect(frame_size)); - - // We would normally call BrowserCompositorMac::SubmitCompositorFrame on - // macOS, however it contains compositor resize logic that we don't want. - // Consequently we instead call the SubmitCompositorFrame method directly. - GetDelegatedFrameHost()->SubmitCompositorFrame( - local_surface_id, std::move(frame), std::move(hit_test_region_list)); - - // Request a copy of the last compositor frame which will eventually call - // OnPaint asynchronously. - copy_frame_generator_->GenerateCopyFrame(damage_rect); - } - } + NOTREACHED(); } void OffScreenRenderWidgetHostView::ClearCompositorFrame() { @@ -651,13 +495,13 @@ void OffScreenRenderWidgetHostView::InitAsPopup( content::RenderWidgetHostView* parent_host_view, const gfx::Rect& pos) { DCHECK_EQ(parent_host_view_, parent_host_view); + DCHECK_EQ(widget_type_, content::WidgetType::kPopup); if (parent_host_view_->popup_host_view_) { parent_host_view_->popup_host_view_->CancelWidget(); } parent_host_view_->set_popup_host_view(this); - parent_host_view_->popup_bitmap_.reset(new SkBitmap); parent_callback_ = base::Bind(&OffScreenRenderWidgetHostView::OnPopupPaint, parent_host_view_->weak_ptr_factory_.GetWeakPtr()); @@ -665,6 +509,10 @@ void OffScreenRenderWidgetHostView::InitAsPopup( popup_position_ = pos; ResizeRootLayer(false); + SetPainting(parent_host_view_->IsPainting()); + if (video_consumer_) { + video_consumer_->SizeChanged(); + } Show(); } @@ -698,7 +546,6 @@ void OffScreenRenderWidgetHostView::Destroy() { } else { if (popup_host_view_) popup_host_view_->CancelWidget(); - popup_bitmap_.reset(); if (child_host_view_) child_host_view_->CancelWidget(); if (!guest_host_views_.empty()) { @@ -748,6 +595,7 @@ void OffScreenRenderWidgetHostView::InitAsGuest( content::RenderWidgetHostView* parent_host_view, content::RenderWidgetHostViewGuest* guest_view) { parent_host_view_->AddGuestHostView(this); + SetPainting(parent_host_view_->IsPainting()); } void OffScreenRenderWidgetHostView::TransformPointToRootSurface( @@ -763,6 +611,12 @@ viz::SurfaceId OffScreenRenderWidgetHostView::GetCurrentSurfaceId() const { : viz::SurfaceId(); } +std::unique_ptr +OffScreenRenderWidgetHostView::CreateSyntheticGestureTarget() { + NOTIMPLEMENTED(); + return nullptr; +} + void OffScreenRenderWidgetHostView::ImeCompositionRangeChanged( const gfx::Range&, const std::vector&) {} @@ -800,12 +654,8 @@ const viz::FrameSinkId& OffScreenRenderWidgetHostView::GetFrameSinkId() const { void OffScreenRenderWidgetHostView::DidNavigate() { ResizeRootLayer(true); -#if defined(OS_MACOSX) - browser_compositor_->DidNavigate(); -#else if (delegated_frame_host_) delegated_frame_host_->DidNavigate(); -#endif } bool OffScreenRenderWidgetHostView::TransformPointToLocalCoordSpaceLegacy( @@ -829,8 +679,7 @@ bool OffScreenRenderWidgetHostView::TransformPointToLocalCoordSpaceLegacy( bool OffScreenRenderWidgetHostView::TransformPointToCoordSpaceForView( const gfx::PointF& point, RenderWidgetHostViewBase* target_view, - gfx::PointF* transformed_point, - viz::EventSource source) { + gfx::PointF* transformed_point) { if (target_view == this) { *transformed_point = point; return true; @@ -847,7 +696,6 @@ void OffScreenRenderWidgetHostView::CancelWidget() { if (parent_host_view_) { if (parent_host_view_->popup_host_view_ == this) { parent_host_view_->set_popup_host_view(NULL); - parent_host_view_->popup_bitmap_.reset(); } else if (parent_host_view_->child_host_view_ == this) { parent_host_view_->set_child_host_view(NULL); parent_host_view_->Show(); @@ -890,29 +738,21 @@ void OffScreenRenderWidgetHostView::ProxyViewDestroyed( Invalidate(); } -std::unique_ptr -OffScreenRenderWidgetHostView::CreateSoftwareOutputDevice( +std::unique_ptr +OffScreenRenderWidgetHostView::CreateHostDisplayClient( ui::Compositor* compositor) { - DCHECK_EQ(GetCompositor(), compositor); - DCHECK(!copy_frame_generator_); - DCHECK(!software_output_device_); - - ResizeRootLayer(false); - - software_output_device_ = new OffScreenOutputDevice( - transparent_, base::Bind(&OffScreenRenderWidgetHostView::OnPaint, - weak_ptr_factory_.GetWeakPtr())); - return base::WrapUnique(software_output_device_); + host_display_client_ = new OffScreenHostDisplayClient( + gfx::kNullAcceleratedWidget, + base::Bind(&OffScreenRenderWidgetHostView::OnPaint, + weak_ptr_factory_.GetWeakPtr())); + host_display_client_->SetActive(IsPainting()); + return base::WrapUnique(host_display_client_); } bool OffScreenRenderWidgetHostView::InstallTransparency() { if (transparent_) { SetBackgroundColor(SkColor()); -#if defined(OS_MACOSX) - browser_compositor_->SetBackgroundColor(SK_ColorTRANSPARENT); -#else compositor_->SetBackgroundColor(SK_ColorTRANSPARENT); -#endif return true; } return false; @@ -921,76 +761,99 @@ bool OffScreenRenderWidgetHostView::InstallTransparency() { void OffScreenRenderWidgetHostView::SetNeedsBeginFrames( bool needs_begin_frames) { SetupFrameRate(true); - begin_frame_timer_->SetActive(needs_begin_frames); - - if (software_output_device_) { - software_output_device_->SetActive(painting_, false); - } } -void OffScreenRenderWidgetHostView::SetWantsAnimateOnlyBeginFrames() { - if (GetDelegatedFrameHost()) { - GetDelegatedFrameHost()->SetWantsAnimateOnlyBeginFrames(); - } +void OffScreenRenderWidgetHostView::SetWantsAnimateOnlyBeginFrames() {} + +#if defined(OS_MACOSX) +void OffScreenRenderWidgetHostView::SetActive(bool active) {} + +void OffScreenRenderWidgetHostView::ShowDefinitionForSelection() {} + +void OffScreenRenderWidgetHostView::SpeakSelection() {} + +bool OffScreenRenderWidgetHostView::UpdateNSViewAndDisplay() { + return false; } +#endif void OffScreenRenderWidgetHostView::OnPaint(const gfx::Rect& damage_rect, const SkBitmap& bitmap) { + backing_.reset(new SkBitmap()); + backing_->allocN32Pixels(bitmap.width(), bitmap.height(), !transparent_); + bitmap.readPixels(backing_->pixmap()); + + if (IsPopupWidget() && parent_callback_) { + parent_callback_.Run(this->popup_position_); + } else { + CompositeFrame(damage_rect); + } +} + +gfx::Size OffScreenRenderWidgetHostView::SizeInPixels() { + if (IsPopupWidget()) { + return gfx::ConvertSizeToPixel(current_device_scale_factor_, + popup_position_.size()); + } else { + return gfx::ConvertSizeToPixel(current_device_scale_factor_, + GetViewBounds().size()); + } +} + +void OffScreenRenderWidgetHostView::CompositeFrame( + const gfx::Rect& damage_rect) { HoldResize(); - if (parent_callback_) { - parent_callback_.Run(damage_rect, bitmap); + gfx::Size size_in_pixels = SizeInPixels(); + + SkBitmap frame; + + // Optimize for the case when there is no popup + if (proxy_views_.size() == 0 && !popup_host_view_) { + frame = GetBacking(); } else { - gfx::Rect damage(damage_rect); + frame.allocN32Pixels(size_in_pixels.width(), size_in_pixels.height(), + false); + if (!GetBacking().drawsNothing()) { + SkCanvas canvas(frame); + canvas.writePixels(GetBacking(), 0, 0); - gfx::Size size_in_pixels = gfx::ConvertSizeToPixel( - current_device_scale_factor_, GetViewBounds().size()); + if (popup_host_view_ && !popup_host_view_->GetBacking().drawsNothing()) { + gfx::Rect rect = popup_host_view_->popup_position_; + gfx::Point origin_in_pixels = gfx::ConvertPointToPixel( + current_device_scale_factor_, rect.origin()); + canvas.writePixels(popup_host_view_->GetBacking(), origin_in_pixels.x(), + origin_in_pixels.y()); + } - SkBitmap backing; - backing.allocN32Pixels(size_in_pixels.width(), size_in_pixels.height(), - false); - SkCanvas canvas(backing); - - canvas.writePixels(bitmap, 0, 0); - - if (popup_host_view_ && popup_bitmap_.get()) { - gfx::Rect rect = popup_host_view_->popup_position_; - gfx::Point origin_in_pixels = - gfx::ConvertPointToPixel(current_device_scale_factor_, rect.origin()); - damage.Union(rect); - canvas.writePixels(*popup_bitmap_.get(), origin_in_pixels.x(), - origin_in_pixels.y()); + for (auto* proxy_view : proxy_views_) { + gfx::Rect rect = proxy_view->GetBounds(); + gfx::Point origin_in_pixels = gfx::ConvertPointToPixel( + current_device_scale_factor_, rect.origin()); + canvas.writePixels(*proxy_view->GetBitmap(), origin_in_pixels.x(), + origin_in_pixels.y()); + } } - - for (auto* proxy_view : proxy_views_) { - gfx::Rect rect = proxy_view->GetBounds(); - gfx::Point origin_in_pixels = - gfx::ConvertPointToPixel(current_device_scale_factor_, rect.origin()); - damage.Union(rect); - canvas.writePixels(*proxy_view->GetBitmap(), origin_in_pixels.x(), - origin_in_pixels.y()); - } - - damage.Intersect(GetViewBounds()); - paint_callback_running_ = true; - callback_.Run(damage, backing); - paint_callback_running_ = false; } + paint_callback_running_ = true; + callback_.Run(gfx::IntersectRects(gfx::Rect(size_in_pixels), damage_rect), + frame); + paint_callback_running_ = false; + ReleaseResize(); } -void OffScreenRenderWidgetHostView::OnPopupPaint(const gfx::Rect& damage_rect, - const SkBitmap& bitmap) { - if (popup_host_view_ && popup_bitmap_.get()) - popup_bitmap_.reset(new SkBitmap(bitmap)); - InvalidateBounds(popup_host_view_->popup_position_); +void OffScreenRenderWidgetHostView::OnPopupPaint(const gfx::Rect& damage_rect) { + InvalidateBounds( + gfx::ConvertRectToPixel(current_device_scale_factor_, damage_rect)); } void OffScreenRenderWidgetHostView::OnProxyViewPaint( const gfx::Rect& damage_rect) { - InvalidateBounds(damage_rect); + InvalidateBounds( + gfx::ConvertRectToPixel(current_device_scale_factor_, damage_rect)); } void OffScreenRenderWidgetHostView::HoldResize() { @@ -1020,7 +883,7 @@ void OffScreenRenderWidgetHostView::SynchronizeVisualProperties() { return; } - ResizeRootLayer(false); + ResizeRootLayer(true); } void OffScreenRenderWidgetHostView::SendMouseEvent( @@ -1147,8 +1010,17 @@ void OffScreenRenderWidgetHostView::SendMouseWheelEvent( void OffScreenRenderWidgetHostView::SetPainting(bool painting) { painting_ = painting; - if (software_output_device_) { - software_output_device_->SetActive(painting_, !paint_callback_running_); + if (popup_host_view_) { + popup_host_view_->SetPainting(painting); + } + + for (auto* guest_host_view : guest_host_views_) + guest_host_view->SetPainting(painting); + + if (video_consumer_) { + video_consumer_->SetActive(IsPainting()); + } else if (host_display_client_) { + host_display_client_->SetActive(IsPainting()); } } @@ -1173,6 +1045,10 @@ void OffScreenRenderWidgetHostView::SetFrameRate(int frame_rate) { SetupFrameRate(true); + if (video_consumer_) { + video_consumer_->SetFrameRate(GetFrameRate()); + } + for (auto* guest_host_view : guest_host_views_) guest_host_view->SetFrameRate(frame_rate); } @@ -1181,7 +1057,6 @@ int OffScreenRenderWidgetHostView::GetFrameRate() const { return frame_rate_; } -#if !defined(OS_MACOSX) ui::Compositor* OffScreenRenderWidgetHostView::GetCompositor() const { return compositor_.get(); } @@ -1190,18 +1065,15 @@ ui::Layer* OffScreenRenderWidgetHostView::GetRootLayer() const { return root_layer_.get(); } -#if !defined(OS_MACOSX) const viz::LocalSurfaceIdAllocation& OffScreenRenderWidgetHostView::GetLocalSurfaceIdAllocation() const { - return local_surface_id_allocation_; + return delegated_frame_host_allocation_; } -#endif // defined(OS_MACOSX) content::DelegatedFrameHost* OffScreenRenderWidgetHostView::GetDelegatedFrameHost() const { return delegated_frame_host_.get(); } -#endif void OffScreenRenderWidgetHostView::SetupFrameRate(bool force) { if (!force && frame_rate_threshold_us_ != 0) @@ -1209,11 +1081,6 @@ void OffScreenRenderWidgetHostView::SetupFrameRate(bool force) { frame_rate_threshold_us_ = 1000000 / frame_rate_; - if (copy_frame_generator_.get()) { - copy_frame_generator_->set_frame_rate_threshold_us( - frame_rate_threshold_us_); - } - if (begin_frame_timer_.get()) { begin_frame_timer_->SetFrameRateThresholdUs(frame_rate_threshold_us_); } else { @@ -1225,15 +1092,11 @@ void OffScreenRenderWidgetHostView::SetupFrameRate(bool force) { } void OffScreenRenderWidgetHostView::Invalidate() { - InvalidateBounds(GetViewBounds()); + InvalidateBounds(gfx::Rect(GetRequestedRendererSize())); } void OffScreenRenderWidgetHostView::InvalidateBounds(const gfx::Rect& bounds) { - if (software_output_device_) { - software_output_device_->OnPaint(bounds); - } else if (copy_frame_generator_) { - copy_frame_generator_->GenerateCopyFrame(bounds); - } + CompositeFrame(bounds); } void OffScreenRenderWidgetHostView::ResizeRootLayer(bool force) { @@ -1259,23 +1122,24 @@ void OffScreenRenderWidgetHostView::ResizeRootLayer(bool force) { GetRootLayer()->SetBounds(gfx::Rect(size)); -#if defined(OS_MACOSX) - bool resized = UpdateNSViewAndDisplay(); -#else 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(); + compositor_allocator_.GenerateId(); + compositor_allocation_ = + compositor_allocator_.GetCurrentLocalSurfaceIdAllocation(); GetCompositor()->SetScaleAndSize(current_device_scale_factor_, size_in_pixels, - local_surface_id_allocation_); + compositor_allocation_); + + delegated_frame_host_allocator_.GenerateId(); + delegated_frame_host_allocation_ = + delegated_frame_host_allocator_.GetCurrentLocalSurfaceIdAllocation(); + bool resized = true; GetDelegatedFrameHost()->EmbedSurface( - local_surface_id_allocation_.local_surface_id(), size, + delegated_frame_host_allocation_.local_surface_id(), size, cc::DeadlinePolicy::UseDefaultDeadline()); -#endif // Note that |render_widget_host_| will retrieve resize parameters from the // DelegatedFrameHost, so it must have SynchronizeVisualProperties called diff --git a/atom/browser/osr/osr_render_widget_host_view.h b/atom/browser/osr/osr_render_widget_host_view.h index 4f33182c25df..1f5f9f8861eb 100644 --- a/atom/browser/osr/osr_render_widget_host_view.h +++ b/atom/browser/osr/osr_render_widget_host_view.h @@ -14,7 +14,8 @@ #include #endif -#include "atom/browser/osr/osr_output_device.h" +#include "atom/browser/osr/osr_host_display_client.h" +#include "atom/browser/osr/osr_video_consumer.h" #include "atom/browser/osr/osr_view_proxy.h" #include "base/process/kill.h" #include "base/threading/thread.h" @@ -23,12 +24,12 @@ #include "components/viz/common/frame_sinks/begin_frame_source.h" #include "components/viz/common/quads/compositor_frame.h" #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h" -#include "content/browser/frame_host/render_widget_host_view_guest.h" -#include "content/browser/renderer_host/delegated_frame_host.h" -#include "content/browser/renderer_host/input/mouse_wheel_phase_handler.h" -#include "content/browser/renderer_host/render_widget_host_impl.h" -#include "content/browser/renderer_host/render_widget_host_view_base.h" -#include "content/browser/web_contents/web_contents_view.h" +#include "content/browser/frame_host/render_widget_host_view_guest.h" // nogncheck +#include "content/browser/renderer_host/delegated_frame_host.h" // nogncheck +#include "content/browser/renderer_host/input/mouse_wheel_phase_handler.h" // nogncheck +#include "content/browser/renderer_host/render_widget_host_impl.h" // nogncheck +#include "content/browser/renderer_host/render_widget_host_view_base.h" // nogncheck +#include "content/browser/web_contents/web_contents_view.h" // nogncheck #include "third_party/blink/public/platform/web_vector.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/ime/text_input_client.h" @@ -37,24 +38,13 @@ #include "ui/compositor/layer_owner.h" #include "ui/gfx/geometry/point.h" +#include "components/viz/host/host_display_client.h" +#include "ui/compositor/external_begin_frame_client.h" + #if defined(OS_WIN) #include "ui/gfx/win/window_impl.h" #endif -#if defined(OS_MACOSX) -#include "content/browser/renderer_host/browser_compositor_view_mac.h" -#endif - -#if defined(OS_MACOSX) -#ifdef __OBJC__ -@class CALayer; -@class NSWindow; -#else -class CALayer; -class NSWindow; -#endif -#endif - namespace content { class CursorManager; } // namespace content @@ -64,13 +54,13 @@ namespace atom { class AtomCopyFrameGenerator; class AtomBeginFrameTimer; -#if defined(OS_MACOSX) -class MacHelper; -#else class AtomDelegatedFrameHostClient; -#endif + +typedef base::Callback OnPaintCallback; +typedef base::Callback OnPopupPaintCallback; class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase, + public ui::ExternalBeginFrameClient, public ui::CompositorDelegate, public OffscreenViewProxyObserver { public: @@ -87,6 +77,9 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase, content::BrowserAccessibilityDelegate*, bool) override; + void OnDisplayDidFinishFrame(const viz::BeginFrameAck& ack) override; + void OnNeedsExternalBeginFrames(bool needs_begin_frames) override; + // content::RenderWidgetHostView: void InitAsChild(gfx::NativeView) override; void SetSize(const gfx::Size&) override; @@ -152,15 +145,12 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase, void TransformPointToRootSurface(gfx::PointF* point) override; gfx::Rect GetBoundsInRootWindow(void) override; viz::SurfaceId GetCurrentSurfaceId() const override; + std::unique_ptr + CreateSyntheticGestureTarget() override; void ImeCompositionRangeChanged(const gfx::Range&, const std::vector&) override; gfx::Size GetCompositorViewportPixelSize() const override; -#if defined(OS_MACOSX) - viz::ScopedSurfaceIdAllocator DidUpdateVisualProperties( - const cc::RenderFrameMetadata& metadata) override; -#endif - content::RenderWidgetHostViewBase* CreateViewForWidget( content::RenderWidgetHost*, content::RenderWidgetHost*, @@ -179,11 +169,10 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase, bool TransformPointToCoordSpaceForView( const gfx::PointF& point, RenderWidgetHostViewBase* target_view, - gfx::PointF* transformed_point, - viz::EventSource source = viz::EventSource::ANY) override; + gfx::PointF* transformed_point) override; // ui::CompositorDelegate: - std::unique_ptr CreateSoftwareOutputDevice( + std::unique_ptr CreateHostDisplayClient( ui::Compositor* compositor) override; bool InstallTransparency(); @@ -191,14 +180,6 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase, void OnBeginFrameTimerTick(); void SendBeginFrame(base::TimeTicks frame_time, base::TimeDelta vsync_period); -#if defined(OS_MACOSX) - void CreatePlatformWidget(bool is_guest_view_hack); - void DestroyPlatformWidget(); - SkColor last_frame_root_background_color() const { - return last_frame_root_background_color_; - } -#endif - void CancelWidget(); void AddGuestHostView(OffScreenRenderWidgetHostView* guest_host); void RemoveGuestHostView(OffScreenRenderWidgetHostView* guest_host); @@ -207,13 +188,19 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase, void ProxyViewDestroyed(OffscreenViewProxy* proxy) override; void OnPaint(const gfx::Rect& damage_rect, const SkBitmap& bitmap); - void OnPopupPaint(const gfx::Rect& damage_rect, const SkBitmap& bitmap); + void OnPopupPaint(const gfx::Rect& damage_rect); void OnProxyViewPaint(const gfx::Rect& damage_rect) override; + gfx::Size SizeInPixels(); + + void CompositeFrame(const gfx::Rect& damage_rect); + bool IsPopupWidget() const { return widget_type_ == content::WidgetType::kPopup; } + const SkBitmap& GetBacking() { return *backing_.get(); } + void HoldResize(); void ReleaseResize(); void SynchronizeVisualProperties(); @@ -230,12 +217,6 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase, ui::Compositor* GetCompositor() const; ui::Layer* GetRootLayer() const; -#if defined(OS_MACOSX) - content::BrowserCompositorMac* browser_compositor() const { - return browser_compositor_.get(); - } -#endif - content::DelegatedFrameHost* GetDelegatedFrameHost() const; void Invalidate(); @@ -256,12 +237,6 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase, } private: -#if defined(OS_MACOSX) - display::Display GetDisplay(); - void OnDidUpdateVisualPropertiesComplete( - const cc::RenderFrameMetadata& metadata); -#endif - void SetupFrameRate(bool force); void ResizeRootLayer(bool force); @@ -276,16 +251,13 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase, OffScreenRenderWidgetHostView* parent_host_view_ = nullptr; OffScreenRenderWidgetHostView* popup_host_view_ = nullptr; - std::unique_ptr popup_bitmap_; OffScreenRenderWidgetHostView* child_host_view_ = nullptr; std::set guest_host_views_; std::set proxy_views_; - OffScreenOutputDevice* software_output_device_ = nullptr; - const bool transparent_; OnPaintCallback callback_; - OnPaintCallback parent_callback_; + OnPopupPaintCallback parent_callback_; int frame_rate_ = 0; int frame_rate_threshold_us_ = 0; @@ -305,8 +277,11 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase, bool paint_callback_running_ = false; - viz::LocalSurfaceIdAllocation local_surface_id_allocation_; - viz::ParentLocalSurfaceIdAllocator local_surface_id_allocator_; + viz::LocalSurfaceIdAllocation delegated_frame_host_allocation_; + viz::ParentLocalSurfaceIdAllocator delegated_frame_host_allocator_; + + viz::LocalSurfaceIdAllocation compositor_allocation_; + viz::ParentLocalSurfaceIdAllocator compositor_allocator_; std::unique_ptr root_layer_; std::unique_ptr compositor_; @@ -314,27 +289,15 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase, std::unique_ptr cursor_manager_; - std::unique_ptr copy_frame_generator_; std::unique_ptr begin_frame_timer_; + OffScreenHostDisplayClient* host_display_client_; + std::unique_ptr video_consumer_; // Provides |source_id| for BeginFrameArgs that we create. viz::StubBeginFrameSource begin_frame_source_; uint64_t begin_frame_number_ = viz::BeginFrameArgs::kStartingFrameNumber; -#if defined(OS_MACOSX) - std::unique_ptr browser_compositor_; - - SkColor last_frame_root_background_color_; - - // Can not be managed by smart pointer because its header can not be included - // in the file that has the destructor. - MacHelper* mac_helper_; - - // Selected text on the renderer. - std::string selected_text_; -#else std::unique_ptr delegated_frame_host_client_; -#endif content::MouseWheelPhaseHandler mouse_wheel_phase_handler_; @@ -348,6 +311,8 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase, SkColor background_color_ = SkColor(); + std::unique_ptr backing_; + base::WeakPtrFactory weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(OffScreenRenderWidgetHostView); diff --git a/atom/browser/osr/osr_render_widget_host_view_mac.mm b/atom/browser/osr/osr_render_widget_host_view_mac.mm deleted file mode 100644 index cddce27fd649..000000000000 --- a/atom/browser/osr/osr_render_widget_host_view_mac.mm +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/osr/osr_render_widget_host_view.h" - -#import - -#include "base/strings/utf_string_conversions.h" -#include "content/common/view_messages.h" -#include "ui/accelerated_widget_mac/accelerated_widget_mac.h" -#include "ui/display/screen.h" - -#include "components/viz/common/features.h" - -namespace atom { - -class MacHelper : public content::BrowserCompositorMacClient, - public ui::AcceleratedWidgetMacNSView { - public: - explicit MacHelper(OffScreenRenderWidgetHostView* view) : view_(view) { - [view_->GetNativeView().GetNativeNSView() setWantsLayer:YES]; - } - - virtual ~MacHelper() {} - - // content::BrowserCompositorMacClient: - SkColor BrowserCompositorMacGetGutterColor() const override { - // When making an element on the page fullscreen the element's background - // may not match the page's, so use black as the gutter color to avoid - // flashes of brighter colors during the transition. - if (view_->render_widget_host()->delegate() && - view_->render_widget_host()->delegate()->IsFullscreenForCurrentTab()) { - return SK_ColorBLACK; - } - return view_->last_frame_root_background_color(); - } - - void BrowserCompositorMacOnBeginFrame(base::TimeTicks frame_time) override {} - - void OnFrameTokenChanged(uint32_t frame_token) override { - view_->render_widget_host()->DidProcessFrame(frame_token); - } - - void AcceleratedWidgetCALayerParamsUpdated() override {} - - void DestroyCompositorForShutdown() override {} - - bool OnBrowserCompositorSurfaceIdChanged() override { - return view_->render_widget_host()->SynchronizeVisualProperties(); - } - - std::vector CollectSurfaceIdsForEviction() override { - return view_->render_widget_host()->CollectSurfaceIdsForEviction(); - } - - private: - OffScreenRenderWidgetHostView* view_; - - DISALLOW_COPY_AND_ASSIGN(MacHelper); -}; - -void OffScreenRenderWidgetHostView::SetActive(bool active) {} - -void OffScreenRenderWidgetHostView::ShowDefinitionForSelection() {} - -void OffScreenRenderWidgetHostView::SpeakSelection() {} - -bool OffScreenRenderWidgetHostView::UpdateNSViewAndDisplay() { - return browser_compositor_->UpdateSurfaceFromNSView( - GetRootLayer()->bounds().size(), GetDisplay()); -} - -void OffScreenRenderWidgetHostView::CreatePlatformWidget( - bool is_guest_view_hack) { - mac_helper_ = new MacHelper(this); - browser_compositor_.reset(new content::BrowserCompositorMac( - mac_helper_, mac_helper_, render_widget_host_->is_hidden(), GetDisplay(), - AllocateFrameSinkId(is_guest_view_hack))); - - if (!base::FeatureList::IsEnabled(features::kVizDisplayCompositor)) { - SetNeedsBeginFrames(true); - } -} - -void OffScreenRenderWidgetHostView::DestroyPlatformWidget() { - browser_compositor_.reset(); - delete mac_helper_; -} - -viz::ScopedSurfaceIdAllocator -OffScreenRenderWidgetHostView::DidUpdateVisualProperties( - const cc::RenderFrameMetadata& metadata) { - base::OnceCallback allocation_task = base::BindOnce( - base::IgnoreResult( - &OffScreenRenderWidgetHostView::OnDidUpdateVisualPropertiesComplete), - weak_ptr_factory_.GetWeakPtr(), metadata); - return browser_compositor_->GetScopedRendererSurfaceIdAllocator( - std::move(allocation_task)); -} - -display::Display OffScreenRenderWidgetHostView::GetDisplay() { - content::ScreenInfo screen_info; - GetScreenInfo(&screen_info); - - // Start with a reasonable display representation. - display::Display display = - display::Screen::GetScreen()->GetDisplayNearestView(nullptr); - - // Populate attributes based on |screen_info|. - display.set_bounds(screen_info.rect); - display.set_work_area(screen_info.available_rect); - display.set_device_scale_factor(screen_info.device_scale_factor); - display.set_color_space(screen_info.color_space); - display.set_color_depth(screen_info.depth); - display.set_depth_per_component(screen_info.depth_per_component); - display.set_is_monochrome(screen_info.is_monochrome); - display.SetRotationAsDegree(screen_info.orientation_angle); - - return display; -} - -void OffScreenRenderWidgetHostView::OnDidUpdateVisualPropertiesComplete( - const cc::RenderFrameMetadata& metadata) { - DCHECK_EQ(current_device_scale_factor_, metadata.device_scale_factor); - browser_compositor_->UpdateSurfaceFromChild( - metadata.device_scale_factor, metadata.viewport_size_in_pixels, - metadata.local_surface_id_allocation.value_or( - viz::LocalSurfaceIdAllocation())); -} - -const viz::LocalSurfaceIdAllocation& -OffScreenRenderWidgetHostView::GetLocalSurfaceIdAllocation() const { - return browser_compositor_->GetRendererLocalSurfaceIdAllocation(); -} - -ui::Compositor* OffScreenRenderWidgetHostView::GetCompositor() const { - return browser_compositor_->GetCompositor(); -} - -ui::Layer* OffScreenRenderWidgetHostView::GetRootLayer() const { - return browser_compositor_->GetRootLayer(); -} - -content::DelegatedFrameHost* -OffScreenRenderWidgetHostView::GetDelegatedFrameHost() const { - return browser_compositor_->GetDelegatedFrameHost(); -} - -} // namespace atom diff --git a/atom/browser/osr/osr_video_consumer.cc b/atom/browser/osr/osr_video_consumer.cc new file mode 100644 index 000000000000..aa265a12221b --- /dev/null +++ b/atom/browser/osr/osr_video_consumer.cc @@ -0,0 +1,137 @@ +// Copyright (c) 2019 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/osr/osr_video_consumer.h" + +#include + +#include "atom/browser/osr/osr_render_widget_host_view.h" +#include "media/base/video_frame_metadata.h" +#include "media/capture/mojom/video_capture_types.mojom.h" +#include "ui/gfx/skbitmap_operations.h" + +namespace atom { + +OffScreenVideoConsumer::OffScreenVideoConsumer( + OffScreenRenderWidgetHostView* view, + OnPaintCallback callback) + : callback_(callback), + view_(view), + video_capturer_(view->CreateVideoCapturer()), + weak_ptr_factory_(this) { + video_capturer_->SetResolutionConstraints(view_->SizeInPixels(), + view_->SizeInPixels(), true); + video_capturer_->SetAutoThrottlingEnabled(false); + video_capturer_->SetMinSizeChangePeriod(base::TimeDelta()); + video_capturer_->SetFormat(media::PIXEL_FORMAT_ARGB, + gfx::ColorSpace::CreateREC709()); + SetFrameRate(view_->GetFrameRate()); +} + +OffScreenVideoConsumer::~OffScreenVideoConsumer() = default; + +void OffScreenVideoConsumer::SetActive(bool active) { + if (active) { + video_capturer_->Start(this); + } else { + video_capturer_->Stop(); + } +} + +void OffScreenVideoConsumer::SetFrameRate(int frame_rate) { + video_capturer_->SetMinCapturePeriod(base::TimeDelta::FromSeconds(1) / + frame_rate); +} + +void OffScreenVideoConsumer::SizeChanged() { + video_capturer_->SetResolutionConstraints(view_->SizeInPixels(), + view_->SizeInPixels(), true); + video_capturer_->RequestRefreshFrame(); +} + +void OffScreenVideoConsumer::OnFrameCaptured( + base::ReadOnlySharedMemoryRegion data, + ::media::mojom::VideoFrameInfoPtr info, + const gfx::Rect& content_rect, + viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks) { + if (!CheckContentRect(content_rect)) { + gfx::Size view_size = view_->SizeInPixels(); + video_capturer_->SetResolutionConstraints(view_size, view_size, true); + video_capturer_->RequestRefreshFrame(); + return; + } + + if (!data.IsValid()) { + callbacks->Done(); + return; + } + base::ReadOnlySharedMemoryMapping mapping = data.Map(); + if (!mapping.IsValid()) { + DLOG(ERROR) << "Shared memory mapping failed."; + return; + } + if (mapping.size() < + media::VideoFrame::AllocationSize(info->pixel_format, info->coded_size)) { + DLOG(ERROR) << "Shared memory size was less than expected."; + return; + } + + // The SkBitmap's pixels will be marked as immutable, but the installPixels() + // API requires a non-const pointer. So, cast away the const. + void* const pixels = const_cast(mapping.memory()); + + // Call installPixels() with a |releaseProc| that: 1) notifies the capturer + // that this consumer has finished with the frame, and 2) releases the shared + // memory mapping. + struct FramePinner { + // Keeps the shared memory that backs |frame_| mapped. + base::ReadOnlySharedMemoryMapping mapping; + // Prevents FrameSinkVideoCapturer from recycling the shared memory that + // backs |frame_|. + viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr releaser; + }; + + SkBitmap bitmap; + bitmap.installPixels( + SkImageInfo::MakeN32(content_rect.width(), content_rect.height(), + kPremul_SkAlphaType), + pixels, + media::VideoFrame::RowBytes(media::VideoFrame::kARGBPlane, + info->pixel_format, info->coded_size.width()), + [](void* addr, void* context) { + delete static_cast(context); + }, + new FramePinner{std::move(mapping), std::move(callbacks)}); + bitmap.setImmutable(); + + media::VideoFrameMetadata metadata; + metadata.MergeInternalValuesFrom(info->metadata); + gfx::Rect damage_rect; + + auto UPDATE_RECT = media::VideoFrameMetadata::CAPTURE_UPDATE_RECT; + if (!metadata.GetRect(UPDATE_RECT, &damage_rect)) { + damage_rect = content_rect; + } + + callback_.Run(damage_rect, bitmap); +} + +void OffScreenVideoConsumer::OnStopped() {} + +bool OffScreenVideoConsumer::CheckContentRect(const gfx::Rect& content_rect) { + gfx::Size view_size = view_->SizeInPixels(); + gfx::Size content_size = content_rect.size(); + + if (std::abs(view_size.width() - content_size.width()) > 2) { + return false; + } + + if (std::abs(view_size.height() - content_size.height()) > 2) { + return false; + } + + return true; +} + +} // namespace atom diff --git a/atom/browser/osr/osr_video_consumer.h b/atom/browser/osr/osr_video_consumer.h new file mode 100644 index 000000000000..45068373a78e --- /dev/null +++ b/atom/browser/osr/osr_video_consumer.h @@ -0,0 +1,53 @@ +// Copyright (c) 2019 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_OSR_OSR_VIDEO_CONSUMER_H_ +#define ATOM_BROWSER_OSR_OSR_VIDEO_CONSUMER_H_ + +#include + +#include "base/callback.h" +#include "base/memory/weak_ptr.h" +#include "components/viz/host/client_frame_sink_video_capturer.h" + +namespace atom { + +class OffScreenRenderWidgetHostView; + +typedef base::Callback OnPaintCallback; + +class OffScreenVideoConsumer : public viz::mojom::FrameSinkVideoConsumer { + public: + OffScreenVideoConsumer(OffScreenRenderWidgetHostView* view, + OnPaintCallback callback); + ~OffScreenVideoConsumer() override; + + void SetActive(bool active); + void SetFrameRate(int frame_rate); + void SizeChanged(); + + private: + // viz::mojom::FrameSinkVideoConsumer implementation. + void OnFrameCaptured( + base::ReadOnlySharedMemoryRegion data, + ::media::mojom::VideoFrameInfoPtr info, + const gfx::Rect& content_rect, + viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks) override; + void OnStopped() override; + + bool CheckContentRect(const gfx::Rect& content_rect); + + OnPaintCallback callback_; + + OffScreenRenderWidgetHostView* view_; + std::unique_ptr video_capturer_; + + base::WeakPtrFactory weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(OffScreenVideoConsumer); +}; + +} // namespace atom + +#endif // ATOM_BROWSER_OSR_OSR_VIDEO_CONSUMER_H_ diff --git a/atom/browser/osr/osr_web_contents_view.cc b/atom/browser/osr/osr_web_contents_view.cc index 5df7e9d96a82..03cf5980c42c 100644 --- a/atom/browser/osr/osr_web_contents_view.cc +++ b/atom/browser/osr/osr_web_contents_view.cc @@ -5,7 +5,7 @@ #include "atom/browser/osr/osr_web_contents_view.h" #include "atom/common/api/api_messages.h" -#include "content/browser/web_contents/web_contents_impl.h" +#include "content/browser/web_contents/web_contents_impl.h" // nogncheck #include "content/public/browser/render_view_host.h" #include "third_party/blink/public/platform/web_screen_info.h" #include "ui/display/screen.h" @@ -140,7 +140,7 @@ OffScreenWebContentsView::CreateViewForChildWidget( ->GetRenderWidgetHostView() : web_contents_impl->GetRenderWidgetHostView()); - return new OffScreenRenderWidgetHostView(transparent_, true, + return new OffScreenRenderWidgetHostView(transparent_, painting_, view->GetFrameRate(), callback_, render_widget_host, view, GetSize()); } @@ -166,11 +166,9 @@ void OffScreenWebContentsView::RenderViewHostChanged( void OffScreenWebContentsView::SetOverscrollControllerEnabled(bool enabled) {} #if defined(OS_MACOSX) -bool OffScreenWebContentsView::IsEventTracking() const { +bool OffScreenWebContentsView::CloseTabAfterEventTrackingIfNeeded() { return false; } - -void OffScreenWebContentsView::CloseTabAfterEventTracking() {} #endif // defined(OS_MACOSX) void OffScreenWebContentsView::StartDragging( @@ -189,10 +187,9 @@ void OffScreenWebContentsView::UpdateDragCursor( void OffScreenWebContentsView::SetPainting(bool painting) { auto* view = GetView(); + painting_ = painting; if (view != nullptr) { view->SetPainting(painting); - } else { - painting_ = painting; } } @@ -207,10 +204,9 @@ bool OffScreenWebContentsView::IsPainting() const { void OffScreenWebContentsView::SetFrameRate(int frame_rate) { auto* view = GetView(); + frame_rate_ = frame_rate; if (view != nullptr) { view->SetFrameRate(frame_rate); - } else { - frame_rate_ = frame_rate; } } diff --git a/atom/browser/osr/osr_web_contents_view.h b/atom/browser/osr/osr_web_contents_view.h index 5a4348434d5f..7509e5b968b5 100644 --- a/atom/browser/osr/osr_web_contents_view.h +++ b/atom/browser/osr/osr_web_contents_view.h @@ -9,8 +9,8 @@ #include "atom/browser/native_window_observer.h" #include "atom/browser/osr/osr_render_widget_host_view.h" -#include "content/browser/renderer_host/render_view_host_delegate_view.h" -#include "content/browser/web_contents/web_contents_view.h" +#include "content/browser/renderer_host/render_view_host_delegate_view.h" // nogncheck +#include "content/browser/web_contents/web_contents_view.h" // nogncheck #include "content/public/browser/web_contents.h" #if defined(OS_MACOSX) @@ -67,8 +67,7 @@ class OffScreenWebContentsView : public content::WebContentsView, void SetOverscrollControllerEnabled(bool enabled) override; #if defined(OS_MACOSX) - bool IsEventTracking() const override; - void CloseTabAfterEventTracking() override; + bool CloseTabAfterEventTrackingIfNeeded() override; #endif // content::RenderViewHostDelegateView diff --git a/atom/browser/ui/autofill_popup.cc b/atom/browser/ui/autofill_popup.cc index ddae9b121950..7cf2e7e94502 100644 --- a/atom/browser/ui/autofill_popup.cc +++ b/atom/browser/ui/autofill_popup.cc @@ -69,7 +69,6 @@ void AutofillPopup::CreateView(content::RenderFrameHost* frame_host, parent_->AddObserver(this); view_ = new AutofillPopupView(this, parent->GetWidget()); - view_->Show(); #if BUILDFLAG(ENABLE_OSR) if (offscreen) { @@ -83,6 +82,9 @@ void AutofillPopup::CreateView(content::RenderFrameHost* frame_host, osr_rwhv->AddViewProxy(view_->view_proxy_.get()); } #endif + + // Do this after OSR setup, we check for view_proxy_ when showing + view_->Show(); } void AutofillPopup::Hide() { diff --git a/atom/browser/ui/views/autofill_popup_view.cc b/atom/browser/ui/views/autofill_popup_view.cc index 7558611c0eac..0e9d3f8bef3f 100644 --- a/atom/browser/ui/views/autofill_popup_view.cc +++ b/atom/browser/ui/views/autofill_popup_view.cc @@ -56,7 +56,11 @@ AutofillPopupView::~AutofillPopupView() { } void AutofillPopupView::Show() { - if (!popup_ || !parent_widget_->IsVisible() || parent_widget_->IsClosed()) + bool visible = parent_widget_->IsVisible(); +#if BUILDFLAG(ENABLE_OSR) + visible = visible || view_proxy_; +#endif + if (!popup_ || !visible || parent_widget_->IsClosed()) return; const bool initialize_widget = !GetWidget(); diff --git a/buildflags/buildflags.gni b/buildflags/buildflags.gni index 2fdca8657493..2425b927b389 100644 --- a/buildflags/buildflags.gni +++ b/buildflags/buildflags.gni @@ -8,7 +8,7 @@ declare_args() { # Allow running Electron as a node binary. enable_run_as_node = true - enable_osr = false + enable_osr = true enable_view_api = false diff --git a/patches/common/chromium/.patches b/patches/common/chromium/.patches index eae36f0ff5de..9c2958fbd2b5 100644 --- a/patches/common/chromium/.patches +++ b/patches/common/chromium/.patches @@ -7,7 +7,6 @@ blink_local_frame.patch blink_world_context.patch browser_compositor_mac.patch can_create_window.patch -compositor_delegate.patch disable_hidden.patch dom_storage_limits.patch frame_host_manager.patch @@ -74,3 +73,4 @@ disable_custom_libcxx_on_windows.patch fix_retain_compatibility_with_msvc.patch disable_network_services_by_default.patch unsandboxed_ppapi_processes_skip_zygote.patch +viz_osr.patch diff --git a/patches/common/chromium/compositor_delegate.patch b/patches/common/chromium/compositor_delegate.patch deleted file mode 100644 index 94db91b26abb..000000000000 --- a/patches/common/chromium/compositor_delegate.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Anonymous -Date: Thu, 20 Sep 2018 17:45:36 -0700 -Subject: compositor_delegate.patch - - -diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc -index ff4e3109b11fea4e0a732ebf9ac9c17e4b5d5e8e..09eee0aae0306545af49258a8f11813c06655023 100644 ---- a/content/browser/compositor/gpu_process_transport_factory.cc -+++ b/content/browser/compositor/gpu_process_transport_factory.cc -@@ -451,11 +451,20 @@ void GpuProcessTransportFactory::EstablishedGpuChannel( - // surfaces as they are not following the correct mode. - DisableGpuCompositing(compositor.get()); - } -+ -+ std::unique_ptr output_device; -+ if (compositor->delegate()) { -+ output_device = -+ compositor->delegate()->CreateSoftwareOutputDevice(compositor.get()); -+ } -+ if (!output_device) { -+ output_device = CreateSoftwareOutputDevice(compositor->widget(), -+ compositor->task_runner()); -+ } -+ - display_output_surface = - std::make_unique( -- CreateSoftwareOutputDevice(compositor->widget(), -- compositor->task_runner()), -- std::move(vsync_callback)); -+ std::move(output_device), std::move(vsync_callback)); - } else { - DCHECK(context_provider); - const auto& capabilities = context_provider->ContextCapabilities(); -diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h -index 29784c677f4be6e4fd7cfb298ab3554d22e1beaa..07b61abe7ce666b5eb6448ef795f838ddb805947 100644 ---- a/ui/compositor/compositor.h -+++ b/ui/compositor/compositor.h -@@ -25,6 +25,7 @@ - #include "components/viz/common/surfaces/frame_sink_id.h" - #include "components/viz/common/surfaces/local_surface_id_allocation.h" - #include "components/viz/host/host_frame_sink_client.h" -+#include "components/viz/service/display/software_output_device.h" - #include "third_party/skia/include/core/SkColor.h" - #include "third_party/skia/include/core/SkMatrix44.h" - #include "ui/compositor/compositor_animation_observer.h" -@@ -193,6 +194,15 @@ class COMPOSITOR_EXPORT ContextFactory { - virtual bool SyncTokensRequiredForDisplayCompositor() = 0; - }; - -+class COMPOSITOR_EXPORT CompositorDelegate { -+ public: -+ virtual std::unique_ptr CreateSoftwareOutputDevice( -+ ui::Compositor* compositor) = 0; -+ -+ protected: -+ virtual ~CompositorDelegate() {} -+}; -+ - // Compositor object to take care of GPU painting. - // A Browser compositor object is responsible for generating the final - // displayable form of pixels comprising a single widget's contents. It draws an -@@ -235,6 +245,9 @@ class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient, - // Schedules a redraw of the layer tree associated with this compositor. - void ScheduleDraw(); - -+ CompositorDelegate* delegate() const { return delegate_; } -+ void SetDelegate(CompositorDelegate* delegate) { delegate_ = delegate; } -+ - // Sets the root of the layer tree drawn by this Compositor. The root layer - // must have no parent. The compositor's root layer is reset if the root layer - // is destroyed. NULL can be passed to reset the root layer, in which case the -@@ -458,6 +471,8 @@ class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient, - ui::ContextFactory* context_factory_; - ui::ContextFactoryPrivate* context_factory_private_; - -+ CompositorDelegate* delegate_ = nullptr; -+ - // The root of the Layer tree drawn by this compositor. - Layer* root_layer_ = nullptr; - diff --git a/patches/common/chromium/viz_osr.patch b/patches/common/chromium/viz_osr.patch new file mode 100644 index 000000000000..628a7e367616 --- /dev/null +++ b/patches/common/chromium/viz_osr.patch @@ -0,0 +1,638 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Heilig Benedek +Date: Wed, 20 Mar 2019 20:30:44 +0100 +Subject: feat: offscreen rendering with viz compositor + + +diff --git a/components/viz/host/host_display_client.cc b/components/viz/host/host_display_client.cc +index bdd1e8bde77ac458639d2b6064c58a133becc5ee..b21917e760c9bf183a75d1ed4e4104eeeb8948ad 100644 +--- a/components/viz/host/host_display_client.cc ++++ b/components/viz/host/host_display_client.cc +@@ -18,6 +18,10 @@ + + namespace viz { + ++void HostDisplayClient::IsOffscreen(IsOffscreenCallback callback) { ++ std::move(callback).Run(false); ++} ++ + HostDisplayClient::HostDisplayClient(gfx::AcceleratedWidget widget) + : binding_(this) { + #if defined(OS_MACOSX) || defined(OS_WIN) +@@ -49,9 +53,9 @@ void HostDisplayClient::OnDisplayReceivedCALayerParams( + } + #endif + +-#if defined(OS_WIN) + void HostDisplayClient::CreateLayeredWindowUpdater( + mojom::LayeredWindowUpdaterRequest request) { ++#if defined(OS_WIN) + if (!NeedsToUseLayerWindow(widget_)) { + DLOG(ERROR) << "HWND shouldn't be using a layered window"; + return; +@@ -59,7 +63,11 @@ void HostDisplayClient::CreateLayeredWindowUpdater( + + layered_window_updater_ = + std::make_unique(widget_, std::move(request)); +-} ++#else ++ CHECK(false) << "Chromium is calling CreateLayeredWindowUpdater for non-OSR " ++ "windows on POSIX platforms, something is wrong with " ++ "Electron's OSR implementation."; + #endif ++} + + } // namespace viz +diff --git a/components/viz/host/host_display_client.h b/components/viz/host/host_display_client.h +index af64385aa93f7abc7a85e1f6eec3c99134e0d2b5..011007ba451e71d46d02cb2d28f6489fe2a805ec 100644 +--- a/components/viz/host/host_display_client.h ++++ b/components/viz/host/host_display_client.h +@@ -30,17 +30,17 @@ class VIZ_HOST_EXPORT HostDisplayClient : public mojom::DisplayClient { + mojom::DisplayClientPtr GetBoundPtr( + scoped_refptr task_runner); + +- private: ++ protected: + // mojom::DisplayClient implementation: + #if defined(OS_MACOSX) + void OnDisplayReceivedCALayerParams( + const gfx::CALayerParams& ca_layer_params) override; + #endif + +-#if defined(OS_WIN) ++ void IsOffscreen(IsOffscreenCallback callback) override; ++ + void CreateLayeredWindowUpdater( + mojom::LayeredWindowUpdaterRequest request) override; +-#endif + + mojo::Binding binding_; + #if defined(OS_MACOSX) || defined(OS_WIN) +diff --git a/components/viz/host/layered_window_updater_impl.cc b/components/viz/host/layered_window_updater_impl.cc +index d3a49ed8be8dc11b86af67cdd600b05ddc0fc486..88bf86f3938b8267d731b52c8c3baa35d3128c7a 100644 +--- a/components/viz/host/layered_window_updater_impl.cc ++++ b/components/viz/host/layered_window_updater_impl.cc +@@ -47,7 +47,9 @@ void LayeredWindowUpdaterImpl::OnAllocatedSharedMemory( + shm_handle.Close(); + } + +-void LayeredWindowUpdaterImpl::Draw(DrawCallback draw_callback) { ++void LayeredWindowUpdaterImpl::Draw( ++ const gfx::Rect& damage_rect, ++ DrawCallback draw_callback) { + TRACE_EVENT0("viz", "LayeredWindowUpdaterImpl::Draw"); + + if (!canvas_) { +diff --git a/components/viz/host/layered_window_updater_impl.h b/components/viz/host/layered_window_updater_impl.h +index 93c52d2b928cba6e98723e19b005fb7bd7089a58..4dc645e770a2a039ed8e4ff4de555767fee34a3a 100644 +--- a/components/viz/host/layered_window_updater_impl.h ++++ b/components/viz/host/layered_window_updater_impl.h +@@ -33,7 +33,7 @@ class VIZ_HOST_EXPORT LayeredWindowUpdaterImpl + void OnAllocatedSharedMemory( + const gfx::Size& pixel_size, + mojo::ScopedSharedBufferHandle scoped_buffer_handle) override; +- void Draw(DrawCallback draw_callback) override; ++ void Draw(const gfx::Rect& damage_rect, DrawCallback draw_callback) override; + + private: + const HWND hwnd_; +diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn +index 1ac721a2781faecd0c7ee5709e8ed20b227bf298..dd7ae27ececbe2a81d9dc62f7e49dc520916d58c 100644 +--- a/components/viz/service/BUILD.gn ++++ b/components/viz/service/BUILD.gn +@@ -113,6 +113,8 @@ viz_component("service") { + "display_embedder/in_process_gpu_memory_buffer_manager.h", + "display_embedder/server_shared_bitmap_manager.cc", + "display_embedder/server_shared_bitmap_manager.h", ++ "display_embedder/software_output_device_proxy.cc", ++ "display_embedder/software_output_device_proxy.h", + "display_embedder/software_output_surface.cc", + "display_embedder/software_output_surface.h", + "display_embedder/viz_process_context_provider.cc", +diff --git a/components/viz/service/display_embedder/gpu_display_provider.cc b/components/viz/service/display_embedder/gpu_display_provider.cc +index 72e6374ccb67b625fa5936a08cc948c653d71e0e..71b1c7e16ea7a48fee3a9c17c66d5d6927c2783a 100644 +--- a/components/viz/service/display_embedder/gpu_display_provider.cc ++++ b/components/viz/service/display_embedder/gpu_display_provider.cc +@@ -19,6 +19,7 @@ + #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" + #include "components/viz/service/display_embedder/skia_output_surface_impl.h" + #include "components/viz/service/display_embedder/skia_output_surface_impl_non_ddl.h" ++#include "components/viz/service/display_embedder/software_output_device_proxy.h" + #include "components/viz/service/display_embedder/software_output_surface.h" + #include "components/viz/service/display_embedder/viz_process_context_provider.h" + #include "components/viz/service/gl/gpu_service_impl.h" +@@ -279,6 +280,19 @@ GpuDisplayProvider::CreateSoftwareOutputDeviceForPlatform( + if (headless_) + return std::make_unique(); + ++#if !defined(OS_MACOSX) ++ DCHECK(display_client); ++ bool offscreen = false; ++ if (display_client->IsOffscreen(&offscreen) && offscreen) { ++ mojom::LayeredWindowUpdaterPtr layered_window_updater; ++ display_client->CreateLayeredWindowUpdater( ++ mojo::MakeRequest(&layered_window_updater)); ++ ++ return std::make_unique( ++ std::move(layered_window_updater)); ++ } ++#endif ++ + #if defined(OS_WIN) + return CreateSoftwareOutputDeviceWinGpu( + surface_handle, &output_device_backing_, display_client); +diff --git a/components/viz/service/display_embedder/software_output_device_mac.cc b/components/viz/service/display_embedder/software_output_device_mac.cc +index b9357082293cc55650144ccbc8bada8fe6d1cac4..b4cb07e26d1504719f80e5835c1cb5f138b9f1ab 100644 +--- a/components/viz/service/display_embedder/software_output_device_mac.cc ++++ b/components/viz/service/display_embedder/software_output_device_mac.cc +@@ -102,6 +102,8 @@ void SoftwareOutputDeviceMac::UpdateAndCopyBufferDamage( + + SkCanvas* SoftwareOutputDeviceMac::BeginPaint( + const gfx::Rect& new_damage_rect) { ++ last_damage = new_damage_rect; ++ + // Record the previous paint buffer. + Buffer* previous_paint_buffer = + buffer_queue_.empty() ? nullptr : buffer_queue_.back().get(); +@@ -184,6 +186,7 @@ void SoftwareOutputDeviceMac::EndPaint() { + ca_layer_params.is_empty = false; + ca_layer_params.scale_factor = scale_factor_; + ca_layer_params.pixel_size = pixel_size_; ++ ca_layer_params.damage = last_damage; + ca_layer_params.io_surface_mach_port.reset( + IOSurfaceCreateMachPort(current_paint_buffer_->io_surface)); + client_->SoftwareDeviceUpdatedCALayerParams(ca_layer_params); +diff --git a/components/viz/service/display_embedder/software_output_device_mac.h b/components/viz/service/display_embedder/software_output_device_mac.h +index f3867356e3d641416e00e6d115ae9ae2a0be90ab..b1d192d2b20ccb63fba07093101d745e5ffe86dd 100644 +--- a/components/viz/service/display_embedder/software_output_device_mac.h ++++ b/components/viz/service/display_embedder/software_output_device_mac.h +@@ -56,6 +56,7 @@ class VIZ_SERVICE_EXPORT SoftwareOutputDeviceMac : public SoftwareOutputDevice { + void UpdateAndCopyBufferDamage(Buffer* previous_paint_buffer, + const SkRegion& new_damage_rect); + ++ gfx::Rect last_damage; + gfx::Size pixel_size_; + float scale_factor_ = 1; + +diff --git a/components/viz/service/display_embedder/software_output_device_proxy.cc b/components/viz/service/display_embedder/software_output_device_proxy.cc +new file mode 100644 +index 0000000000000000000000000000000000000000..c784a841f74e7a6215595fd8b1166655857f3e31 +--- /dev/null ++++ b/components/viz/service/display_embedder/software_output_device_proxy.cc +@@ -0,0 +1,167 @@ ++// 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 "components/viz/service/display_embedder/software_output_device_proxy.h" ++ ++#include "base/memory/shared_memory.h" ++#include "base/threading/thread_checker.h" ++#include "components/viz/common/resources/resource_sizes.h" ++#include "components/viz/service/display_embedder/output_device_backing.h" ++#include "mojo/public/cpp/system/platform_handle.h" ++#include "services/viz/privileged/interfaces/compositing/layered_window_updater.mojom.h" ++#include "skia/ext/platform_canvas.h" ++#include "third_party/skia/include/core/SkCanvas.h" ++#include "ui/gfx/skia_util.h" ++ ++#if defined(OS_WIN) ++#include "skia/ext/skia_utils_win.h" ++#include "ui/gfx/gdi_util.h" ++#include "ui/gfx/win/hwnd_util.h" ++#else ++#include "mojo/public/cpp/base/shared_memory_utils.h" ++#endif ++ ++namespace viz { ++ ++SoftwareOutputDeviceBase::~SoftwareOutputDeviceBase() { ++ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); ++ DCHECK(!in_paint_); ++} ++ ++void SoftwareOutputDeviceBase::Resize(const gfx::Size& viewport_pixel_size, ++ float scale_factor) { ++ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); ++ DCHECK(!in_paint_); ++ ++ if (viewport_pixel_size_ == viewport_pixel_size) ++ return; ++ ++ viewport_pixel_size_ = viewport_pixel_size; ++ ResizeDelegated(); ++} ++ ++SkCanvas* SoftwareOutputDeviceBase::BeginPaint( ++ const gfx::Rect& damage_rect) { ++ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); ++ DCHECK(!in_paint_); ++ ++ damage_rect_ = damage_rect; ++ in_paint_ = true; ++ return BeginPaintDelegated(); ++} ++ ++void SoftwareOutputDeviceBase::EndPaint() { ++ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); ++ DCHECK(in_paint_); ++ ++ in_paint_ = false; ++ ++ gfx::Rect intersected_damage_rect = damage_rect_; ++ intersected_damage_rect.Intersect(gfx::Rect(viewport_pixel_size_)); ++ if (intersected_damage_rect.IsEmpty()) ++ return; ++ ++ EndPaintDelegated(intersected_damage_rect); ++} ++ ++SoftwareOutputDeviceProxy::~SoftwareOutputDeviceProxy() = default; ++ ++SoftwareOutputDeviceProxy::SoftwareOutputDeviceProxy( ++ mojom::LayeredWindowUpdaterPtr layered_window_updater) ++ : layered_window_updater_(std::move(layered_window_updater)) { ++ DCHECK(layered_window_updater_.is_bound()); ++} ++ ++void SoftwareOutputDeviceProxy::OnSwapBuffers( ++ base::OnceClosure swap_ack_callback) { ++ DCHECK(swap_ack_callback_.is_null()); ++ ++ // We aren't waiting on DrawAck() and can immediately run the callback. ++ if (!waiting_on_draw_ack_) { ++ task_runner_->PostTask(FROM_HERE, std::move(swap_ack_callback)); ++ return; ++ } ++ ++ swap_ack_callback_ = std::move(swap_ack_callback); ++} ++ ++void SoftwareOutputDeviceProxy::ResizeDelegated() { ++ canvas_.reset(); ++ ++ size_t required_bytes; ++ if (!ResourceSizes::MaybeSizeInBytes( ++ viewport_pixel_size_, ResourceFormat::RGBA_8888, &required_bytes)) { ++ DLOG(ERROR) << "Invalid viewport size " << viewport_pixel_size_.ToString(); ++ return; ++ } ++ ++ #if defined(WIN32) ++ base::SharedMemory shm; ++ if (!shm.CreateAnonymous(required_bytes)) { ++ DLOG(ERROR) << "Failed to allocate " << required_bytes << " bytes"; ++ return; ++ } ++ ++ canvas_ = skia::CreatePlatformCanvasWithSharedSection( ++ viewport_pixel_size_.width(), viewport_pixel_size_.height(), false, ++ shm.handle().GetHandle(), skia::CRASH_ON_FAILURE); ++ ++ // Transfer handle ownership to the browser process. ++ mojo::ScopedSharedBufferHandle scoped_handle = mojo::WrapSharedMemoryHandle( ++ shm.TakeHandle(), required_bytes, ++ mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite); ++ #else ++ auto shm = mojo::CreateWritableSharedMemoryRegion(required_bytes); ++ if (!shm.IsValid()) { ++ DLOG(ERROR) << "Failed to allocate " << required_bytes << " bytes"; ++ return; ++ } ++ ++ shm_mapping_ = shm.Map(); ++ if (!shm_mapping_.IsValid()) { ++ DLOG(ERROR) << "Failed to map " << required_bytes << " bytes"; ++ return; ++ } ++ ++ canvas_ = skia::CreatePlatformCanvasWithPixels( ++ viewport_pixel_size_.width(), viewport_pixel_size_.height(), false, ++ static_cast(shm_mapping_.memory()), skia::CRASH_ON_FAILURE); ++ ++ mojo::ScopedSharedBufferHandle scoped_handle = ++ mojo::WrapWritableSharedMemoryRegion(std::move(shm)); ++ #endif ++ ++ layered_window_updater_->OnAllocatedSharedMemory(viewport_pixel_size_, ++ std::move(scoped_handle)); ++} ++ ++SkCanvas* SoftwareOutputDeviceProxy::BeginPaintDelegated() { ++ return canvas_.get(); ++} ++ ++void SoftwareOutputDeviceProxy::EndPaintDelegated( ++ const gfx::Rect& damage_rect) { ++ DCHECK(!waiting_on_draw_ack_); ++ ++ if (!canvas_) ++ return; ++ ++ layered_window_updater_->Draw(damage_rect, base::BindOnce( ++ &SoftwareOutputDeviceProxy::DrawAck, base::Unretained(this))); ++ waiting_on_draw_ack_ = true; ++ ++ TRACE_EVENT_ASYNC_BEGIN0("viz", "SoftwareOutputDeviceProxy::Draw", this); ++} ++ ++void SoftwareOutputDeviceProxy::DrawAck() { ++ DCHECK(waiting_on_draw_ack_); ++ DCHECK(!swap_ack_callback_.is_null()); ++ ++ TRACE_EVENT_ASYNC_END0("viz", "SoftwareOutputDeviceProxy::Draw", this); ++ ++ waiting_on_draw_ack_ = false; ++ std::move(swap_ack_callback_).Run(); ++} ++ ++} // namespace viz +diff --git a/components/viz/service/display_embedder/software_output_device_proxy.h b/components/viz/service/display_embedder/software_output_device_proxy.h +new file mode 100644 +index 0000000000000000000000000000000000000000..01e1e2f0860faa1afe42c342c8905a7f838bd363 +--- /dev/null ++++ b/components/viz/service/display_embedder/software_output_device_proxy.h +@@ -0,0 +1,88 @@ ++// 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. ++ ++#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SOFTWARE_OUTPUT_DEVICE_PROXY_H_ ++#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SOFTWARE_OUTPUT_DEVICE_PROXY_H_ ++ ++#if defined(OS_WIN) ++#include ++#endif ++ ++#include ++ ++#include "components/viz/host/host_display_client.h" ++#include "components/viz/service/display/software_output_device.h" ++#include "components/viz/service/viz_service_export.h" ++#include "services/viz/privileged/interfaces/compositing/display_private.mojom.h" ++#include "services/viz/privileged/interfaces/compositing/layered_window_updater.mojom.h" ++ ++namespace viz { ++ ++// Shared base class for SoftwareOutputDevice implementations. ++class SoftwareOutputDeviceBase : public SoftwareOutputDevice { ++ public: ++ SoftwareOutputDeviceBase() = default; ++ ~SoftwareOutputDeviceBase() override; ++ ++ // SoftwareOutputDevice implementation. ++ void Resize(const gfx::Size& viewport_pixel_size, ++ float scale_factor) override; ++ SkCanvas* BeginPaint(const gfx::Rect& damage_rect) override; ++ void EndPaint() override; ++ ++ // Called from Resize() if |viewport_pixel_size_| has changed. ++ virtual void ResizeDelegated() = 0; ++ ++ // Called from BeginPaint() and should return an SkCanvas. ++ virtual SkCanvas* BeginPaintDelegated() = 0; ++ ++ // Called from EndPaint() if there is damage. ++ virtual void EndPaintDelegated(const gfx::Rect& damage_rect) = 0; ++ ++ private: ++ bool in_paint_ = false; ++ ++ THREAD_CHECKER(thread_checker_); ++ ++ DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceBase); ++}; ++ ++// SoftwareOutputDevice implementation that draws indirectly. An implementation ++// of mojom::LayeredWindowUpdater in the browser process handles the actual ++// drawing. Pixel backing is in SharedMemory so no copying between processes ++// is required. ++class SoftwareOutputDeviceProxy : public SoftwareOutputDeviceBase { ++ public: ++ explicit SoftwareOutputDeviceProxy( ++ mojom::LayeredWindowUpdaterPtr layered_window_updater); ++ ~SoftwareOutputDeviceProxy() override; ++ ++ // SoftwareOutputDevice implementation. ++ void OnSwapBuffers(base::OnceClosure swap_ack_callback) override; ++ ++ // SoftwareOutputDeviceBase implementation. ++ void ResizeDelegated() override; ++ SkCanvas* BeginPaintDelegated() override; ++ void EndPaintDelegated(const gfx::Rect& rect) override; ++ ++ private: ++ // Runs |swap_ack_callback_| after draw has happened. ++ void DrawAck(); ++ ++ mojom::LayeredWindowUpdaterPtr layered_window_updater_; ++ ++ std::unique_ptr canvas_; ++ bool waiting_on_draw_ack_ = false; ++ base::OnceClosure swap_ack_callback_; ++ ++#if !defined(WIN32) ++ base::WritableSharedMemoryMapping shm_mapping_; ++#endif ++ ++ DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceProxy); ++}; ++ ++} // namespace viz ++ ++#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SOFTWARE_OUTPUT_DEVICE_PROXY_H_ +diff --git a/components/viz/service/display_embedder/software_output_device_win.cc b/components/viz/service/display_embedder/software_output_device_win.cc +index a339eaa4dc9ccec292b3df9f31adf1ad45119a77..33146bbe7bb01fbe24cea10d79cad2748dd04a24 100644 +--- a/components/viz/service/display_embedder/software_output_device_win.cc ++++ b/components/viz/service/display_embedder/software_output_device_win.cc +@@ -11,6 +11,7 @@ + #include "components/viz/common/display/use_layered_window.h" + #include "components/viz/common/resources/resource_sizes.h" + #include "components/viz/service/display_embedder/output_device_backing.h" ++#include "components/viz/service/display_embedder/software_output_device_proxy.h" + #include "mojo/public/cpp/system/platform_handle.h" + #include "services/viz/privileged/interfaces/compositing/layered_window_updater.mojom.h" + #include "skia/ext/platform_canvas.h" +@@ -321,7 +322,7 @@ void SoftwareOutputDeviceWinProxy::EndPaintDelegated( + if (!canvas_) + return; + +- layered_window_updater_->Draw(base::BindOnce( ++ layered_window_updater_->Draw(damage_rect, base::BindOnce( + &SoftwareOutputDeviceWinProxy::DrawAck, base::Unretained(this))); + waiting_on_draw_ack_ = true; + +@@ -362,8 +363,13 @@ std::unique_ptr CreateSoftwareOutputDeviceWinGpu( + display_client->CreateLayeredWindowUpdater( + mojo::MakeRequest(&layered_window_updater)); + +- return std::make_unique( +- hwnd, std::move(layered_window_updater)); ++ bool offscreen = false; ++ if (display_client->IsOffscreen(&offscreen) && offscreen) ++ return std::make_unique( ++ std::move(layered_window_updater)); ++ else ++ return std::make_unique( ++ hwnd, std::move(layered_window_updater)); + } else { + return std::make_unique(hwnd, backing); + } +diff --git a/services/viz/privileged/interfaces/compositing/display_private.mojom b/services/viz/privileged/interfaces/compositing/display_private.mojom +index 4c29f4ec2cde99749d4642928ff52ad3d4842f4a..5db220422bbc0ec6384c98681c245502a6442d6d 100644 +--- a/services/viz/privileged/interfaces/compositing/display_private.mojom ++++ b/services/viz/privileged/interfaces/compositing/display_private.mojom +@@ -58,12 +58,14 @@ interface DisplayPrivate { + }; + + interface DisplayClient { ++ [Sync] ++ IsOffscreen() => (bool success); ++ + [EnableIf=is_mac] + OnDisplayReceivedCALayerParams(gfx.mojom.CALayerParams ca_layer_params); + + // Creates a LayeredWindowUpdater implementation to draw into a layered + // window. +- [EnableIf=is_win] + CreateLayeredWindowUpdater(LayeredWindowUpdater& layered_window_updater); + + // Notifies that a swap has occurred and provides information about the pixel +diff --git a/services/viz/privileged/interfaces/compositing/layered_window_updater.mojom b/services/viz/privileged/interfaces/compositing/layered_window_updater.mojom +index 360cab3eee4c5189a55269d76daa1d78a98ed3d3..6834242f23d27fd6d428c2cd6040206a79d5097b 100644 +--- a/services/viz/privileged/interfaces/compositing/layered_window_updater.mojom ++++ b/services/viz/privileged/interfaces/compositing/layered_window_updater.mojom +@@ -22,5 +22,5 @@ interface LayeredWindowUpdater { + // Draws to the HWND by copying pixels from shared memory. Callback must be + // called after draw operation is complete to signal shared memory can be + // modified. +- Draw() => (); ++ Draw(gfx.mojom.Rect damage_rect) => (); + }; +diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h +index 29784c677f4be6e4fd7cfb298ab3554d22e1beaa..5d7da6481ebedb706c1dd31de1f7dfe4735433e8 100644 +--- a/ui/compositor/compositor.h ++++ b/ui/compositor/compositor.h +@@ -24,6 +24,7 @@ + #include "components/viz/common/frame_sinks/begin_frame_args.h" + #include "components/viz/common/surfaces/frame_sink_id.h" + #include "components/viz/common/surfaces/local_surface_id_allocation.h" ++#include "components/viz/host/host_display_client.h" + #include "components/viz/host/host_frame_sink_client.h" + #include "third_party/skia/include/core/SkColor.h" + #include "third_party/skia/include/core/SkMatrix44.h" +@@ -193,6 +194,15 @@ class COMPOSITOR_EXPORT ContextFactory { + virtual bool SyncTokensRequiredForDisplayCompositor() = 0; + }; + ++class COMPOSITOR_EXPORT CompositorDelegate { ++ public: ++ virtual std::unique_ptr CreateHostDisplayClient( ++ ui::Compositor* compositor) = 0; ++ ++ protected: ++ virtual ~CompositorDelegate() {} ++}; ++ + // Compositor object to take care of GPU painting. + // A Browser compositor object is responsible for generating the final + // displayable form of pixels comprising a single widget's contents. It draws an +@@ -235,6 +245,9 @@ class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient, + // Schedules a redraw of the layer tree associated with this compositor. + void ScheduleDraw(); + ++ CompositorDelegate* delegate() const { return delegate_; } ++ void SetDelegate(CompositorDelegate* delegate) { delegate_ = delegate; } ++ + // Sets the root of the layer tree drawn by this Compositor. The root layer + // must have no parent. The compositor's root layer is reset if the root layer + // is destroyed. NULL can be passed to reset the root layer, in which case the +@@ -458,6 +471,8 @@ class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient, + ui::ContextFactory* context_factory_; + ui::ContextFactoryPrivate* context_factory_private_; + ++ CompositorDelegate* delegate_ = nullptr; ++ + // The root of the Layer tree drawn by this compositor. + Layer* root_layer_ = nullptr; + +diff --git a/ui/compositor/host/host_context_factory_private.cc b/ui/compositor/host/host_context_factory_private.cc +index 8297e1aabe3b29698a965407e24d1e987be679d3..a78d455e99eb27730b6ac42cd5fd9469caa4a7de 100644 +--- a/ui/compositor/host/host_context_factory_private.cc ++++ b/ui/compositor/host/host_context_factory_private.cc +@@ -70,8 +70,12 @@ void HostContextFactoryPrivate::ConfigureCompositor( + mojo::MakeRequest(&root_params->compositor_frame_sink_client); + root_params->display_private = + mojo::MakeRequest(&compositor_data.display_private); +- compositor_data.display_client = +- std::make_unique(compositor->widget()); ++ if (compositor->delegate()) ++ compositor_data.display_client = compositor->delegate()->CreateHostDisplayClient( ++ compositor); ++ else ++ compositor_data.display_client = ++ std::make_unique(compositor->widget()); + root_params->display_client = + compositor_data.display_client->GetBoundPtr(resize_task_runner_) + .PassInterface(); +diff --git a/ui/gfx/ca_layer_params.h b/ui/gfx/ca_layer_params.h +index 4014e64a75da88cf66c02e8adb71171c2666cab7..25e57784e1a1ffc546b003daa4cd0059c468432f 100644 +--- a/ui/gfx/ca_layer_params.h ++++ b/ui/gfx/ca_layer_params.h +@@ -6,6 +6,7 @@ + #define UI_GFX_CA_LAYER_PARAMS_H_ + + #include "build/build_config.h" ++#include "ui/gfx/geometry/rect.h" + #include "ui/gfx/geometry/size.h" + #include "ui/gfx/gfx_export.h" + +@@ -41,6 +42,8 @@ struct GFX_EXPORT CALayerParams { + gfx::ScopedRefCountedIOSurfaceMachPort io_surface_mach_port; + #endif + ++ gfx::Rect damage; ++ + // The geometry of the frame. + gfx::Size pixel_size; + float scale_factor = 1.f; +diff --git a/ui/gfx/mojo/ca_layer_params.mojom b/ui/gfx/mojo/ca_layer_params.mojom +index 7bf735643541b18bafffe645d3ff37e96caa4dea..f7eaf10ffd665789f10a587142fac0c0c79b9798 100644 +--- a/ui/gfx/mojo/ca_layer_params.mojom ++++ b/ui/gfx/mojo/ca_layer_params.mojom +@@ -18,5 +18,6 @@ struct CALayerParams { + bool is_empty; + CALayerContent content; + gfx.mojom.Size pixel_size; ++ gfx.mojom.Rect damage; + float scale_factor; + }; +diff --git a/ui/gfx/mojo/ca_layer_params_struct_traits.cc b/ui/gfx/mojo/ca_layer_params_struct_traits.cc +index dd553996b5c6ff5ec0c210a020a18a6a843b8aae..26d1e0bda2640052d42ea4e691c3df73074dea08 100644 +--- a/ui/gfx/mojo/ca_layer_params_struct_traits.cc ++++ b/ui/gfx/mojo/ca_layer_params_struct_traits.cc +@@ -52,6 +52,9 @@ bool StructTraits::Read( + if (!data.ReadPixelSize(&out->pixel_size)) + return false; + ++ if (!data.ReadDamage(&out->damage)) ++ return false; ++ + out->scale_factor = data.scale_factor(); + return true; + } +diff --git a/ui/gfx/mojo/ca_layer_params_struct_traits.h b/ui/gfx/mojo/ca_layer_params_struct_traits.h +index 94127a0d5b50b052318e9e5a360755fe771f87e9..348fa26c5c95a13d1ddd0ff2545aca3a35841a77 100644 +--- a/ui/gfx/mojo/ca_layer_params_struct_traits.h ++++ b/ui/gfx/mojo/ca_layer_params_struct_traits.h +@@ -20,6 +20,10 @@ struct StructTraits { + return ca_layer_params.pixel_size; + } + ++ static gfx::Rect damage(const gfx::CALayerParams& ca_layer_params) { ++ return ca_layer_params.damage; ++ } ++ + static float scale_factor(const gfx::CALayerParams& ca_layer_params) { + return ca_layer_params.scale_factor; + } diff --git a/spec/api-browser-window-spec.js b/spec/api-browser-window-spec.js index 9f746ad6d9a7..16a47715a101 100644 --- a/spec/api-browser-window-spec.js +++ b/spec/api-browser-window-spec.js @@ -3702,14 +3702,18 @@ describe('BrowserWindow module', () => { w.webContents.once('paint', function (event, rect, data) { assert.notStrictEqual(data.length, 0) const size = data.getSize() - const scale = process.platform === 'darwin' ? devicePixelRatio : 1 - assertWithinDelta(size.width, 100 * scale, 2, 'width') - assertWithinDelta(size.height, 100 * scale, 2, 'height') + assertWithinDelta(size.width, 100 * devicePixelRatio, 2, 'width') + assertWithinDelta(size.height, 100 * devicePixelRatio, 2, 'height') done() }) w.loadFile(path.join(fixtures, 'api', 'offscreen-rendering.html')) }) + it('does not crash after navigation', () => { + w.webContents.loadURL('about:blank') + w.loadFile(path.join(fixtures, 'api', 'offscreen-rendering.html')) + }) + describe('window.webContents.isOffscreen()', () => { it('is true for offscreen type', () => { w.loadFile(path.join(fixtures, 'api', 'offscreen-rendering.html'))