Browse Source

fix: port OSR code to new viz compositor codepath (backport: 5-0-x) (#17572)

* fix: make OSR work with viz compositor

* fix: update OSR patch

* fix: update patch again

* fix: update viz_osr.patch for macOS

* fix: gn check warnings

* chore: no need to change SoftwareOutputDeviceWinProxy

* chore: add check in case we missed something

* fix: consider scale factor when compare size

* fix: make GPU OSR work

* fix: autofill popups with OSR

* chore: use UNIX line ending for osr_video_consumer

* chore: code is already in defined(OS_MACOSX)

* fix: share same OSR implementation on macOS

This should also fix the crash when there is navigation on macOS.

* test: osr window should not crash after navigation

* fix: make osr work on Mac properly

* fix: software osr on windows

* fix: software osr on Linux

* fix: split local surface id allocation into two

* fix: update patch for 5-0-x

* fix: patch and update VideoConsumer to report proper damage_rect

* fix: update patch to resolve compilation error on Linux

* fix: compilation error on mac

* Update osr_host_display_client_mac.mm

* chore: update copyright year
Heilig Benedek 6 years ago
parent
commit
1e31bfe287

+ 10 - 3
BUILD.gn

@@ -422,11 +422,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",
@@ -600,6 +602,11 @@ if (is_mac) {
       "ServiceManagement.framework",
       "StoreKit.framework",
     ]
+
+    if (enable_osr) {
+      libs += [ "IOSurface.framework" ]
+    }
+
     ldflags = [
       "-F",
       rebase_path("external_binaries", root_build_dir),

+ 0 - 1
atom/browser/api/atom_api_web_contents.cc

@@ -87,7 +87,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

+ 4 - 1
atom/browser/native_window_mac.mm

@@ -233,7 +233,10 @@ namespace atom {
 namespace {
 
 bool IsFramelessWindow(NSView* view) {
-  NativeWindow* window = [static_cast<AtomNSWindow*>([view window]) shell];
+  NSWindow* nswindow = [view window];
+  if (![nswindow respondsToSelector:@selector(shell)])
+    return false;
+  NativeWindow* window = [static_cast<AtomNSWindow*>(nswindow) shell];
   return window && !window->has_frame();
 }
 

+ 121 - 0
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 <utility>
+
+#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<uint8_t*>(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<LayeredWindowUpdater>(std::move(request), callback_);
+  layered_window_updater_->SetActive(active_);
+}
+
+}  // namespace atom

+ 77 - 0
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 <memory>
+
+#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<void(const gfx::Rect&, const SkBitmap&)> 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<viz::mojom::LayeredWindowUpdater> binding_;
+  std::unique_ptr<SkCanvas> 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<LayeredWindowUpdater> layered_window_updater_;
+  OnPaintCallback callback_;
+  bool active_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(OffScreenHostDisplayClient);
+};
+
+}  // namespace atom
+
+#endif  // ATOM_BROWSER_OSR_OSR_HOST_DISPLAY_CLIENT_H_

+ 35 - 0
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 <IOSurface/IOSurface.h>
+
+namespace atom {
+
+void OffScreenHostDisplayClient::OnDisplayReceivedCALayerParams(
+    const gfx::CALayerParams& ca_layer_params) {
+  if (!ca_layer_params.is_empty) {
+    base::ScopedCFTypeRef<IOSurfaceRef> io_surface(
+        IOSurfaceLookupFromMachPort(ca_layer_params.io_surface_mach_port));
+
+    gfx::Size pixel_size_ = ca_layer_params.pixel_size;
+    void* pixels = static_cast<void*>(IOSurfaceGetBaseAddress(io_surface));
+    size_t stride = IOSurfaceGetBytesPerRow(io_surface);
+
+    struct IOSurfacePinner {
+      base::ScopedCFTypeRef<IOSurfaceRef> 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

+ 0 - 101
atom/browser/osr/osr_output_device.cc

@@ -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

+ 0 - 47
atom/browser/osr/osr_output_device.h

@@ -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 <memory>
-
-#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<void(const gfx::Rect&, const SkBitmap&)> 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<SkCanvas> canvas_;
-  std::unique_ptr<SkBitmap> bitmap_;
-  gfx::Rect pending_damage_rect_;
-
-  DISALLOW_COPY_AND_ASSIGN(OffScreenOutputDevice);
-};
-
-}  // namespace atom
-
-#endif  // ATOM_BROWSER_OSR_OSR_OUTPUT_DEVICE_H_

+ 160 - 295
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>(
-        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<viz::CopyOutputResult> result) {
-    if (result->IsEmpty() || result->size().IsEmpty() ||
-        !view_->render_widget_host()) {
-      OnCopyFrameCaptureFailure(damage_rect);
-      return;
-    }
-
-    DCHECK(!result->IsEmpty());
-    auto source = std::make_unique<SkBitmap>(result->AsSkBitmap());
-    DCHECK(source->readyToDraw());
-    if (source) {
-      base::AutoLock autolock(lock_);
-      std::shared_ptr<SkBitmap> 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<SkBitmap>& 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<AtomCopyFrameGenerator> 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<content::DelegatedFrameHost>(
       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<viz::HitTestRegionList> 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<content::SyntheticGestureTarget>
+OffScreenRenderWidgetHostView::CreateSyntheticGestureTarget() {
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
 void OffScreenRenderWidgetHostView::ImeCompositionRangeChanged(
     const gfx::Range&,
     const std::vector<gfx::Rect>&) {}
@@ -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(
@@ -847,7 +697,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 +739,21 @@ void OffScreenRenderWidgetHostView::ProxyViewDestroyed(
   Invalidate();
 }
 
-std::unique_ptr<viz::SoftwareOutputDevice>
-OffScreenRenderWidgetHostView::CreateSoftwareOutputDevice(
+std::unique_ptr<viz::HostDisplayClient>
+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 +762,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) {
-  HoldResize();
+  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);
+  }
+}
 
-  if (parent_callback_) {
-    parent_callback_.Run(damage_rect, bitmap);
+gfx::Size OffScreenRenderWidgetHostView::SizeInPixels() {
+  if (IsPopupWidget()) {
+    return gfx::ConvertSizeToPixel(current_device_scale_factor_,
+                                   popup_position_.size());
   } else {
-    gfx::Rect damage(damage_rect);
+    return gfx::ConvertSizeToPixel(current_device_scale_factor_,
+                                   GetViewBounds().size());
+  }
+}
 
-    gfx::Size size_in_pixels = gfx::ConvertSizeToPixel(
-        current_device_scale_factor_, GetViewBounds().size());
+void OffScreenRenderWidgetHostView::CompositeFrame(
+    const gfx::Rect& damage_rect) {
+  HoldResize();
 
-    SkBitmap backing;
-    backing.allocN32Pixels(size_in_pixels.width(), size_in_pixels.height(),
-                           false);
-    SkCanvas canvas(backing);
+  gfx::Size size_in_pixels = SizeInPixels();
 
-    canvas.writePixels(bitmap, 0, 0);
+  SkBitmap frame;
 
-    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());
-    }
+  // Optimize for the case when there is no popup
+  if (proxy_views_.size() == 0 && !popup_host_view_) {
+    frame = GetBacking();
+  } else {
+    frame.allocN32Pixels(size_in_pixels.width(), size_in_pixels.height(),
+                         false);
+    if (!GetBacking().drawsNothing()) {
+      SkCanvas canvas(frame);
+      canvas.writePixels(GetBacking(), 0, 0);
+
+      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());
+      }
 
-    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());
+      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());
+      }
     }
-
-    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 +884,7 @@ void OffScreenRenderWidgetHostView::SynchronizeVisualProperties() {
     return;
   }
 
-  ResizeRootLayer(false);
+  ResizeRootLayer(true);
 }
 
 void OffScreenRenderWidgetHostView::SendMouseEvent(
@@ -1147,8 +1011,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 +1046,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 +1058,6 @@ int OffScreenRenderWidgetHostView::GetFrameRate() const {
   return frame_rate_;
 }
 
-#if !defined(OS_MACOSX)
 ui::Compositor* OffScreenRenderWidgetHostView::GetCompositor() const {
   return compositor_.get();
 }
@@ -1190,18 +1066,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 +1082,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 +1093,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 +1123,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

+ 38 - 72
atom/browser/osr/osr_render_widget_host_view.h

@@ -14,7 +14,8 @@
 #include <windows.h>
 #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<void(const gfx::Rect&, const SkBitmap&)> OnPaintCallback;
+typedef base::Callback<void(const gfx::Rect&)> 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<content::SyntheticGestureTarget>
+  CreateSyntheticGestureTarget() override;
   void ImeCompositionRangeChanged(const gfx::Range&,
                                   const std::vector<gfx::Rect>&) 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*,
@@ -183,7 +173,7 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase,
       viz::EventSource source = viz::EventSource::ANY) override;
 
   // ui::CompositorDelegate:
-  std::unique_ptr<viz::SoftwareOutputDevice> CreateSoftwareOutputDevice(
+  std::unique_ptr<viz::HostDisplayClient> CreateHostDisplayClient(
       ui::Compositor* compositor) override;
 
   bool InstallTransparency();
@@ -191,14 +181,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 +189,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 +218,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 +238,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 +252,13 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase,
 
   OffScreenRenderWidgetHostView* parent_host_view_ = nullptr;
   OffScreenRenderWidgetHostView* popup_host_view_ = nullptr;
-  std::unique_ptr<SkBitmap> popup_bitmap_;
   OffScreenRenderWidgetHostView* child_host_view_ = nullptr;
   std::set<OffScreenRenderWidgetHostView*> guest_host_views_;
   std::set<OffscreenViewProxy*> 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 +278,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<ui::Layer> root_layer_;
   std::unique_ptr<ui::Compositor> compositor_;
@@ -314,27 +290,15 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase,
 
   std::unique_ptr<content::CursorManager> cursor_manager_;
 
-  std::unique_ptr<AtomCopyFrameGenerator> copy_frame_generator_;
   std::unique_ptr<AtomBeginFrameTimer> begin_frame_timer_;
+  OffScreenHostDisplayClient* host_display_client_;
+  std::unique_ptr<OffScreenVideoConsumer> 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<content::BrowserCompositorMac> 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<AtomDelegatedFrameHostClient> delegated_frame_host_client_;
-#endif
 
   content::MouseWheelPhaseHandler mouse_wheel_phase_handler_;
 
@@ -348,6 +312,8 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase,
 
   SkColor background_color_ = SkColor();
 
+  std::unique_ptr<SkBitmap> backing_;
+
   base::WeakPtrFactory<OffScreenRenderWidgetHostView> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(OffScreenRenderWidgetHostView);

+ 0 - 150
atom/browser/osr/osr_render_widget_host_view_mac.mm

@@ -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 <Cocoa/Cocoa.h>
-
-#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<viz::SurfaceId> 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<void()> 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

+ 132 - 0
atom/browser/osr/osr_video_consumer.cc

@@ -0,0 +1,132 @@
+// 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 <utility>
+
+#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& update_rect,
+    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<void*>(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<FramePinner*>(context);
+      },
+      new FramePinner{std::move(mapping), std::move(callbacks)});
+  bitmap.setImmutable();
+
+  media::VideoFrameMetadata metadata;
+  metadata.MergeInternalValuesFrom(info->metadata);
+
+  callback_.Run(update_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

+ 54 - 0
atom/browser/osr/osr_video_consumer.h

@@ -0,0 +1,54 @@
+// 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 <memory>
+
+#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<void(const gfx::Rect&, const SkBitmap&)> 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& update_rect,
+      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<viz::ClientFrameSinkVideoCapturer> video_capturer_;
+
+  base::WeakPtrFactory<OffScreenVideoConsumer> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(OffScreenVideoConsumer);
+};
+
+}  // namespace atom
+
+#endif  // ATOM_BROWSER_OSR_OSR_VIDEO_CONSUMER_H_

+ 4 - 6
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());
 }
@@ -189,10 +189,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 +206,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;
   }
 }
 

+ 2 - 2
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)

+ 3 - 1
atom/browser/ui/autofill_popup.cc

@@ -134,7 +134,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) {
@@ -148,6 +147,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() {

+ 5 - 1
atom/browser/ui/views/autofill_popup_view.cc

@@ -56,7 +56,11 @@ AutofillPopupView::~AutofillPopupView() {
 }
 
 void AutofillPopupView::Show() {
-  if (!popup_)
+  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();

+ 1 - 1
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
 

+ 2 - 1
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,5 @@ color_chooser_win.patch
 fix_disable_usage_of_abort_report_np_in_mas_builds.patch
 fix_disable_usage_of_pthread_fchdir_np_and_pthread_chdir_np_in_mas.patch
 fix_disable_usage_of_setapplicationisdaemon_and.patch
+viz_osr.patch
+video_capturer_dirty_rect.patch

+ 0 - 80
patches/common/chromium/compositor_delegate.patch

@@ -1,80 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Anonymous <[email protected]>
-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 5aeda7bd9caf6b5b9e2a95293e4409dc7f9a6d2d..d15e1462babe97b5d68014f4d67236653046aa5f 100644
---- a/content/browser/compositor/gpu_process_transport_factory.cc
-+++ b/content/browser/compositor/gpu_process_transport_factory.cc
-@@ -485,10 +485,20 @@ void GpuProcessTransportFactory::EstablishedGpuChannel(
-         // surfaces as they are not following the correct mode.
-         DisableGpuCompositing(compositor.get());
-       }
-+
-+      std::unique_ptr<viz::SoftwareOutputDevice> 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<SoftwareBrowserCompositorOutputSurface>(
--              CreateSoftwareOutputDevice(compositor->widget(),
--                                         compositor->task_runner()),
-+              std::move(output_device),
-               std::move(vsync_callback));
-     } else {
-       DCHECK(context_provider);
-diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h
-index 313431f82ee7e181dad2c48dd27950129afbb223..b8c2632e49b7b96adbb06a03678961823f0790f6 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.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<viz::SoftwareOutputDevice> 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
-@@ -232,6 +242,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
-@@ -442,6 +455,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;
- 

+ 148 - 0
patches/common/chromium/video_capturer_dirty_rect.patch

@@ -0,0 +1,148 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Heilig Benedek <[email protected]>
+Date: Wed, 27 Mar 2019 13:52:53 +0100
+Subject: fix: report correct dirty rect in FrameSinkVideoCapturerImpl
+
+This patch is only necessary for 5-0-x, there is an upstream
+patch that achieves the same thing (already on master), but
+that patch is huge compared to this, with no other real benefits.
+
+diff --git a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
+index 521ce7e9de52a80571f17003f18e14554d299357..bfca10c864b27da5994319427b5410981b25bbde 100644
+--- a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
++++ b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
+@@ -533,14 +533,14 @@ void FrameSinkVideoCapturerImpl::MaybeCaptureFrame(
+     }
+     dirty_rect_ = gfx::Rect();
+     DidCaptureFrame(frame_number, oracle_frame_number, gfx::Rect(),
+-                    std::move(frame));
++                    dirty_rect_, std::move(frame));
+     return;
+   }
+ 
+   // For passive refreshes, just deliver the resurrected frame.
+   if (dirty_rect_.IsEmpty()) {
+     DidCaptureFrame(frame_number, oracle_frame_number, content_rect,
+-                    std::move(frame));
++                    dirty_rect_, std::move(frame));
+     return;
+   }
+ 
+@@ -551,7 +551,7 @@ void FrameSinkVideoCapturerImpl::MaybeCaptureFrame(
+           : CopyOutputRequest::ResultFormat::RGBA_BITMAP,
+       base::BindOnce(&FrameSinkVideoCapturerImpl::DidCopyFrame,
+                      capture_weak_factory_.GetWeakPtr(), frame_number,
+-                     oracle_frame_number, content_rect,
++                     oracle_frame_number, content_rect, dirty_rect_,
+                      VideoCaptureOverlay::MakeCombinedRenderer(
+                          GetOverlaysInOrder(), content_rect, frame->format()),
+                      std::move(frame))));
+@@ -572,6 +572,7 @@ void FrameSinkVideoCapturerImpl::DidCopyFrame(
+     int64_t frame_number,
+     OracleFrameNumber oracle_frame_number,
+     const gfx::Rect& content_rect,
++    const gfx::Rect& dirty_rect,
+     VideoCaptureOverlay::OnceRenderer overlay_renderer,
+     scoped_refptr<VideoFrame> frame,
+     std::unique_ptr<CopyOutputResult> result) {
+@@ -637,13 +638,14 @@ void FrameSinkVideoCapturerImpl::DidCopyFrame(
+   }
+ 
+   DidCaptureFrame(frame_number, oracle_frame_number, content_rect,
+-                  std::move(frame));
++                  dirty_rect, std::move(frame));
+ }
+ 
+ void FrameSinkVideoCapturerImpl::DidCaptureFrame(
+     int64_t frame_number,
+     OracleFrameNumber oracle_frame_number,
+     const gfx::Rect& content_rect,
++    const gfx::Rect& dirty_rect,
+     scoped_refptr<VideoFrame> frame) {
+   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+   DCHECK_GE(frame_number, next_delivery_frame_number_);
+@@ -656,11 +658,11 @@ void FrameSinkVideoCapturerImpl::DidCaptureFrame(
+   // Ensure frames are delivered in-order by using a min-heap, and only
+   // deliver the next frame(s) in-sequence when they are found at the top.
+   delivery_queue_.emplace(frame_number, oracle_frame_number, content_rect,
+-                          std::move(frame));
++                          dirty_rect, std::move(frame));
+   while (delivery_queue_.top().frame_number == next_delivery_frame_number_) {
+     auto& next = delivery_queue_.top();
+     MaybeDeliverFrame(next.oracle_frame_number, next.content_rect,
+-                      std::move(next.frame));
++                      next.dirty_rect, std::move(next.frame));
+     ++next_delivery_frame_number_;
+     delivery_queue_.pop();
+     if (delivery_queue_.empty()) {
+@@ -672,6 +674,7 @@ void FrameSinkVideoCapturerImpl::DidCaptureFrame(
+ void FrameSinkVideoCapturerImpl::MaybeDeliverFrame(
+     OracleFrameNumber oracle_frame_number,
+     const gfx::Rect& content_rect,
++    const gfx::Rect& dirty_rect,
+     scoped_refptr<VideoFrame> frame) {
+   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ 
+@@ -724,7 +727,7 @@ void FrameSinkVideoCapturerImpl::MaybeDeliverFrame(
+   info->visible_rect = frame->visible_rect();
+   DCHECK(frame->ColorSpace().IsValid());  // Ensure it was set by this point.
+   info->color_space = frame->ColorSpace();
+-  const gfx::Rect update_rect = frame->visible_rect();
++  const gfx::Rect update_rect = dirty_rect;
+ 
+   // Create an InFlightFrameDelivery for this frame, owned by its mojo binding.
+   // It responds to the consumer's Done() notification by returning the video
+@@ -771,10 +774,12 @@ FrameSinkVideoCapturerImpl::CapturedFrame::CapturedFrame(
+     int64_t frame_number,
+     OracleFrameNumber oracle_frame_number,
+     const gfx::Rect& content_rect,
++    const gfx::Rect& dirty_rect,
+     scoped_refptr<media::VideoFrame> frame)
+     : frame_number(frame_number),
+       oracle_frame_number(oracle_frame_number),
+       content_rect(content_rect),
++      dirty_rect(dirty_rect),
+       frame(std::move(frame)) {}
+ 
+ FrameSinkVideoCapturerImpl::CapturedFrame::CapturedFrame(
+diff --git a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h
+index 69f25dab2aaabbcd6760972b85b94c527b5d3667..38218ae3b1cd8bf05ce97c655a1b06483975a8b1 100644
+--- a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h
++++ b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h
+@@ -189,6 +189,7 @@ class VIZ_SERVICE_EXPORT FrameSinkVideoCapturerImpl final
+   void DidCopyFrame(int64_t frame_number,
+                     OracleFrameNumber oracle_frame_number,
+                     const gfx::Rect& content_rect,
++                    const gfx::Rect& dirty_rect,
+                     VideoCaptureOverlay::OnceRenderer overlay_renderer,
+                     scoped_refptr<media::VideoFrame> frame,
+                     std::unique_ptr<CopyOutputResult> result);
+@@ -199,6 +200,7 @@ class VIZ_SERVICE_EXPORT FrameSinkVideoCapturerImpl final
+   void DidCaptureFrame(int64_t frame_number,
+                        OracleFrameNumber oracle_frame_number,
+                        const gfx::Rect& content_rect,
++                       const gfx::Rect& dirty_rect,
+                        scoped_refptr<media::VideoFrame> frame);
+ 
+   // Delivers a |frame| to the consumer, if the VideoCaptureOracle allows
+@@ -207,6 +209,7 @@ class VIZ_SERVICE_EXPORT FrameSinkVideoCapturerImpl final
+   // consumer.
+   void MaybeDeliverFrame(OracleFrameNumber oracle_frame_number,
+                          const gfx::Rect& content_rect,
++                         const gfx::Rect& dirty_rect,
+                          scoped_refptr<media::VideoFrame> frame);
+ 
+   // For ARGB format, ensures that every dimension of |size| is positive. For
+@@ -278,10 +281,12 @@ class VIZ_SERVICE_EXPORT FrameSinkVideoCapturerImpl final
+     int64_t frame_number;
+     OracleFrameNumber oracle_frame_number;
+     gfx::Rect content_rect;
++    gfx::Rect dirty_rect;
+     scoped_refptr<media::VideoFrame> frame;
+     CapturedFrame(int64_t frame_number,
+                   OracleFrameNumber oracle_frame_number,
+                   const gfx::Rect& content_rect,
++                  const gfx::Rect& dirty_rect,
+                   scoped_refptr<media::VideoFrame> frame);
+     CapturedFrame(const CapturedFrame& other);
+     ~CapturedFrame();

+ 641 - 0
patches/common/chromium/viz_osr.patch

@@ -0,0 +1,641 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Heilig Benedek <[email protected]>
+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<LayeredWindowUpdaterImpl>(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 7fd5a4a9a6e1b70c3f07fd7c2c72b380ff6eb4ce..b6b800ee8de8ac56fed665c0686ddd05a9829e8c 100644
+--- a/components/viz/host/host_display_client.h
++++ b/components/viz/host/host_display_client.h
+@@ -30,20 +30,20 @@ class VIZ_HOST_EXPORT HostDisplayClient : public mojom::DisplayClient {
+   mojom::DisplayClientPtr GetBoundPtr(
+       scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+ 
+- private:
++ protected:
+   // mojom::DisplayClient implementation:
+   void DidSwapAfterSnapshotRequestReceived(
+       const std::vector<ui::LatencyInfo>& latency_info) override;
+ 
++  void IsOffscreen(IsOffscreenCallback callback) override;
++
+ #if defined(OS_MACOSX)
+   void OnDisplayReceivedCALayerParams(
+       const gfx::CALayerParams& ca_layer_params) override;
+ #endif
+ 
+-#if defined(OS_WIN)
+   void CreateLayeredWindowUpdater(
+       mojom::LayeredWindowUpdaterRequest request) override;
+-#endif
+ 
+   mojo::Binding<mojom::DisplayClient> 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 3ecb373d91b9346c040b7c237adf981f7cc7f390..2bda9eac40aec141c086e8546cbe0b4488a4b332 100644
+--- a/components/viz/service/BUILD.gn
++++ b/components/viz/service/BUILD.gn
+@@ -111,6 +111,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 53053fceb49c812d2a231acdd9eca9dd121598c6..767c475dcc82d570743f6ac2312acff7341f5a56 100644
+--- a/components/viz/service/display_embedder/gpu_display_provider.cc
++++ b/components/viz/service/display_embedder/gpu_display_provider.cc
+@@ -18,6 +18,7 @@
+ #include "components/viz/service/display_embedder/gl_output_surface_offscreen.h"
+ #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/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"
+@@ -244,6 +245,19 @@ GpuDisplayProvider::CreateSoftwareOutputDeviceForPlatform(
+   if (headless_)
+     return std::make_unique<SoftwareOutputDevice>();
+ 
++#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<SoftwareOutputDeviceProxy>(
++        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<uint8_t*>(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 <windows.h>
++#endif
++
++#include <memory>
++
++#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<SkCanvas> 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 740d4edb3cefe2658104b989ed3a12fc7f0796c2..fd9f8130128c770a813c721ad1b02e645ce403a7 100644
+--- a/components/viz/service/display_embedder/software_output_device_win.cc
++++ b/components/viz/service/display_embedder/software_output_device_win.cc
+@@ -10,6 +10,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"
+@@ -316,7 +317,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;
+ 
+@@ -357,8 +358,13 @@ std::unique_ptr<SoftwareOutputDevice> CreateSoftwareOutputDeviceWinGpu(
+     display_client->CreateLayeredWindowUpdater(
+         mojo::MakeRequest(&layered_window_updater));
+ 
+-    return std::make_unique<SoftwareOutputDeviceWinProxy>(
+-        hwnd, std::move(layered_window_updater));
++    bool offscreen = false;
++    if (display_client->IsOffscreen(&offscreen) && offscreen)
++      return std::make_unique<SoftwareOutputDeviceProxy>(
++          std::move(layered_window_updater));
++    else
++      return std::make_unique<SoftwareOutputDeviceWinProxy>(
++          hwnd, std::move(layered_window_updater));
+   } else {
+     return std::make_unique<SoftwareOutputDeviceWinDirect>(hwnd, backing);
+   }
+diff --git a/services/viz/privileged/interfaces/compositing/display_private.mojom b/services/viz/privileged/interfaces/compositing/display_private.mojom
+index b7c138978ae2556a2b7035351e0167c1c3449282..4d74cdbfcca2ee0142ac5529a26a8561d6d7537a 100644
+--- a/services/viz/privileged/interfaces/compositing/display_private.mojom
++++ b/services/viz/privileged/interfaces/compositing/display_private.mojom
+@@ -58,12 +58,14 @@ interface DisplayClient {
+   // component reached the display.
+   DidSwapAfterSnapshotRequestReceived(array<ui.mojom.LatencyInfo> latency_info);
+ 
++  [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 313431f82ee7e181dad2c48dd27950129afbb223..34a208c1b7159b3444c947684d8aaee110244585 100644
+--- a/ui/compositor/compositor.h
++++ b/ui/compositor/compositor.h
+@@ -67,6 +67,7 @@ namespace viz {
+ class FrameSinkManagerImpl;
+ class ContextProvider;
+ class HostFrameSinkManager;
++class HostDisplayClient;
+ }
+ 
+ namespace ui {
+@@ -193,6 +194,15 @@ class COMPOSITOR_EXPORT ContextFactory {
+   virtual bool SyncTokensRequiredForDisplayCompositor() = 0;
+ };
+ 
++class COMPOSITOR_EXPORT CompositorDelegate {
++ public:
++  virtual std::unique_ptr<viz::HostDisplayClient> 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
+@@ -232,6 +242,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
+@@ -442,6 +455,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<viz::HostDisplayClient>(compositor->widget());
++  if (compositor->delegate())
++    compositor_data.display_client = compositor->delegate()->CreateHostDisplayClient(
++        compositor);
++  else
++    compositor_data.display_client =
++        std::make_unique<viz::HostDisplayClient>(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<gfx::mojom::CALayerParamsDataView, gfx::CALayerParams>::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<gfx::mojom::CALayerParamsDataView, gfx::CALayerParams> {
+     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;
+   }

+ 7 - 3
spec/api-browser-window-spec.js

@@ -3600,14 +3600,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'))