• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "cef/libcef/browser/osr/software_output_device_proxy.h"
6 
7 #include "base/memory/shared_memory_mapping.h"
8 #include "base/trace_event/trace_event.h"
9 #include "components/viz/common/resources/resource_sizes.h"
10 #include "mojo/public/cpp/system/platform_handle.h"
11 #include "skia/ext/platform_canvas.h"
12 #include "third_party/skia/include/core/SkCanvas.h"
13 #include "ui/gfx/skia_util.h"
14 
15 #if BUILDFLAG(IS_WIN)
16 #include <windows.h>
17 #include "skia/ext/skia_utils_win.h"
18 #include "ui/gfx/gdi_util.h"
19 #include "ui/gfx/win/hwnd_util.h"
20 #endif
21 
22 namespace viz {
23 
24 SoftwareOutputDeviceProxy::~SoftwareOutputDeviceProxy() = default;
25 
SoftwareOutputDeviceProxy(mojom::LayeredWindowUpdaterPtr layered_window_updater)26 SoftwareOutputDeviceProxy::SoftwareOutputDeviceProxy(
27     mojom::LayeredWindowUpdaterPtr layered_window_updater)
28     : layered_window_updater_(std::move(layered_window_updater)) {
29   DCHECK(layered_window_updater_.is_bound());
30 }
31 
OnSwapBuffers(SwapBuffersCallback swap_ack_callback)32 void SoftwareOutputDeviceProxy::OnSwapBuffers(
33     SwapBuffersCallback swap_ack_callback) {
34   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
35   DCHECK(swap_ack_callback_.is_null());
36 
37   // We aren't waiting on DrawAck() and can immediately run the callback.
38   if (!waiting_on_draw_ack_) {
39     task_runner_->PostTask(
40         FROM_HERE,
41         base::BindOnce(std::move(swap_ack_callback), viewport_pixel_size_));
42     return;
43   }
44 
45   swap_ack_callback_ =
46       base::BindOnce(std::move(swap_ack_callback), viewport_pixel_size_);
47 }
48 
Resize(const gfx::Size & viewport_pixel_size,float scale_factor)49 void SoftwareOutputDeviceProxy::Resize(const gfx::Size& viewport_pixel_size,
50                                        float scale_factor) {
51   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
52   DCHECK(!in_paint_);
53 
54   if (viewport_pixel_size_ == viewport_pixel_size)
55     return;
56 
57   viewport_pixel_size_ = viewport_pixel_size;
58 
59   canvas_.reset();
60 
61   size_t required_bytes;
62   if (!ResourceSizes::MaybeSizeInBytes(
63           viewport_pixel_size_, ResourceFormat::RGBA_8888, &required_bytes)) {
64     DLOG(ERROR) << "Invalid viewport size " << viewport_pixel_size_.ToString();
65     return;
66   }
67 
68   base::UnsafeSharedMemoryRegion region =
69       base::UnsafeSharedMemoryRegion::Create(required_bytes);
70   if (!region.IsValid()) {
71     DLOG(ERROR) << "Failed to allocate " << required_bytes << " bytes";
72     return;
73   }
74 
75 #if !BUILDFLAG(IS_WIN)
76   auto shm = base::ReadOnlySharedMemoryRegion::Create(required_bytes);
77   if (!shm.IsValid()) {
78     DLOG(ERROR) << "Failed to allocate " << required_bytes << " bytes";
79     return;
80   }
81 
82   shm_ = region.Map();
83   if (!shm_.IsValid()) {
84     DLOG(ERROR) << "Failed to map " << required_bytes << " bytes";
85     return;
86   }
87 
88   canvas_ = skia::CreatePlatformCanvasWithPixels(
89       viewport_pixel_size_.width(), viewport_pixel_size_.height(), false,
90       static_cast<uint8_t*>(shm_.memory()), skia::CRASH_ON_FAILURE);
91 #else
92   canvas_ = skia::CreatePlatformCanvasWithSharedSection(
93       viewport_pixel_size_.width(), viewport_pixel_size_.height(), false,
94       region.GetPlatformHandle(), skia::CRASH_ON_FAILURE);
95 #endif
96 
97   // Transfer region ownership to the browser process.
98   layered_window_updater_->OnAllocatedSharedMemory(viewport_pixel_size_,
99                                                    std::move(region));
100 }
101 
BeginPaint(const gfx::Rect & damage_rect)102 SkCanvas* SoftwareOutputDeviceProxy::BeginPaint(const gfx::Rect& damage_rect) {
103   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
104   DCHECK(!in_paint_);
105 
106   damage_rect_ = damage_rect;
107   in_paint_ = true;
108 
109   return canvas_.get();
110 }
111 
EndPaint()112 void SoftwareOutputDeviceProxy::EndPaint() {
113   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
114   DCHECK(in_paint_);
115   DCHECK(!waiting_on_draw_ack_);
116 
117   in_paint_ = false;
118 
119   gfx::Rect intersected_damage_rect = damage_rect_;
120   intersected_damage_rect.Intersect(gfx::Rect(viewport_pixel_size_));
121   if (intersected_damage_rect.IsEmpty())
122     return;
123 
124   if (!canvas_)
125     return;
126 
127   layered_window_updater_->Draw(
128       damage_rect_, base::BindOnce(&SoftwareOutputDeviceProxy::DrawAck,
129                                    base::Unretained(this)));
130   waiting_on_draw_ack_ = true;
131 
132   TRACE_EVENT_ASYNC_BEGIN0("viz", "SoftwareOutputDeviceProxy::Draw", this);
133 }
134 
DrawAck()135 void SoftwareOutputDeviceProxy::DrawAck() {
136   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
137   DCHECK(waiting_on_draw_ack_);
138   DCHECK(!swap_ack_callback_.is_null());
139 
140   TRACE_EVENT_ASYNC_END0("viz", "SoftwareOutputDeviceProxy::Draw", this);
141 
142   waiting_on_draw_ack_ = false;
143   std::move(swap_ack_callback_).Run();
144 }
145 
146 }  // namespace viz
147