1 // Copyright 2018 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4
5 #include "tests/cefclient/browser/osr_render_handler_win_d3d11.h"
6
7 #include "include/base/cef_callback.h"
8 #include "include/wrapper/cef_closure_task.h"
9 #include "include/wrapper/cef_helpers.h"
10 #include "tests/shared/browser/util_win.h"
11
12 namespace client {
13
BrowserLayer(const std::shared_ptr<d3d11::Device> & device)14 BrowserLayer::BrowserLayer(const std::shared_ptr<d3d11::Device>& device)
15 : d3d11::Layer(device, true /* flip */) {
16 frame_buffer_ = std::make_shared<d3d11::FrameBuffer>(device_);
17 }
18
render(const std::shared_ptr<d3d11::Context> & ctx)19 void BrowserLayer::render(const std::shared_ptr<d3d11::Context>& ctx) {
20 // Use the base class method to draw our texture.
21 render_texture(ctx, frame_buffer_->texture());
22 }
23
on_paint(void * share_handle)24 void BrowserLayer::on_paint(void* share_handle) {
25 frame_buffer_->on_paint(share_handle);
26 }
27
texture_size() const28 std::pair<uint32_t, uint32_t> BrowserLayer::texture_size() const {
29 const auto texture = frame_buffer_->texture();
30 return std::make_pair(texture->width(), texture->height());
31 }
32
PopupLayer(const std::shared_ptr<d3d11::Device> & device)33 PopupLayer::PopupLayer(const std::shared_ptr<d3d11::Device>& device)
34 : BrowserLayer(device) {}
35
set_bounds(const CefRect & bounds)36 void PopupLayer::set_bounds(const CefRect& bounds) {
37 const auto comp = composition();
38 if (!comp)
39 return;
40
41 const auto outer_width = comp->width();
42 const auto outer_height = comp->height();
43 if (outer_width == 0 || outer_height == 0)
44 return;
45
46 original_bounds_ = bounds;
47 bounds_ = bounds;
48
49 // If x or y are negative, move them to 0.
50 if (bounds_.x < 0)
51 bounds_.x = 0;
52 if (bounds_.y < 0)
53 bounds_.y = 0;
54 // If popup goes outside the view, try to reposition origin
55 if (bounds_.x + bounds_.width > outer_width)
56 bounds_.x = outer_width - bounds_.width;
57 if (bounds_.y + bounds_.height > outer_height)
58 bounds_.y = outer_height - bounds_.height;
59 // If x or y became negative, move them to 0 again.
60 if (bounds_.x < 0)
61 bounds_.x = 0;
62 if (bounds_.y < 0)
63 bounds_.y = 0;
64
65 const auto x = bounds_.x / float(outer_width);
66 const auto y = bounds_.y / float(outer_height);
67 const auto w = bounds_.width / float(outer_width);
68 const auto h = bounds_.height / float(outer_height);
69 move(x, y, w, h);
70 }
71
OsrRenderHandlerWinD3D11(const OsrRendererSettings & settings,HWND hwnd)72 OsrRenderHandlerWinD3D11::OsrRenderHandlerWinD3D11(
73 const OsrRendererSettings& settings,
74 HWND hwnd)
75 : OsrRenderHandlerWin(settings, hwnd), start_time_(0) {}
76
Initialize(CefRefPtr<CefBrowser> browser,int width,int height)77 bool OsrRenderHandlerWinD3D11::Initialize(CefRefPtr<CefBrowser> browser,
78 int width,
79 int height) {
80 CEF_REQUIRE_UI_THREAD();
81
82 // Create a D3D11 device instance.
83 device_ = d3d11::Device::create();
84 DCHECK(device_);
85 if (!device_)
86 return false;
87
88 // Create a D3D11 swapchain for the window.
89 swap_chain_ = device_->create_swapchain(hwnd());
90 DCHECK(swap_chain_);
91 if (!swap_chain_)
92 return false;
93
94 // Create the browser layer.
95 browser_layer_ = std::make_shared<BrowserLayer>(device_);
96
97 // Set up the composition.
98 composition_ = std::make_shared<d3d11::Composition>(device_, width, height);
99 composition_->add_layer(browser_layer_);
100
101 // Size to the whole composition.
102 browser_layer_->move(0.0f, 0.0f, 1.0f, 1.0f);
103
104 start_time_ = GetTimeNow();
105
106 SetBrowser(browser);
107 return true;
108 }
109
SetSpin(float spinX,float spinY)110 void OsrRenderHandlerWinD3D11::SetSpin(float spinX, float spinY) {
111 CEF_REQUIRE_UI_THREAD();
112 // Spin support is not implemented.
113 }
114
IncrementSpin(float spinDX,float spinDY)115 void OsrRenderHandlerWinD3D11::IncrementSpin(float spinDX, float spinDY) {
116 CEF_REQUIRE_UI_THREAD();
117 // Spin support is not implemented.
118 }
119
IsOverPopupWidget(int x,int y) const120 bool OsrRenderHandlerWinD3D11::IsOverPopupWidget(int x, int y) const {
121 CEF_REQUIRE_UI_THREAD();
122 return popup_layer_ && popup_layer_->contains(x, y);
123 }
124
GetPopupXOffset() const125 int OsrRenderHandlerWinD3D11::GetPopupXOffset() const {
126 CEF_REQUIRE_UI_THREAD();
127 if (popup_layer_)
128 return popup_layer_->xoffset();
129 return 0;
130 }
131
GetPopupYOffset() const132 int OsrRenderHandlerWinD3D11::GetPopupYOffset() const {
133 CEF_REQUIRE_UI_THREAD();
134 if (popup_layer_)
135 return popup_layer_->yoffset();
136 return 0;
137 }
138
OnPopupShow(CefRefPtr<CefBrowser> browser,bool show)139 void OsrRenderHandlerWinD3D11::OnPopupShow(CefRefPtr<CefBrowser> browser,
140 bool show) {
141 CEF_REQUIRE_UI_THREAD();
142
143 if (show) {
144 DCHECK(!popup_layer_);
145
146 // Create a new layer.
147 popup_layer_ = std::make_shared<PopupLayer>(device_);
148 composition_->add_layer(popup_layer_);
149 } else {
150 DCHECK(popup_layer_);
151
152 composition_->remove_layer(popup_layer_);
153 popup_layer_ = nullptr;
154
155 Render();
156 }
157 }
158
OnPopupSize(CefRefPtr<CefBrowser> browser,const CefRect & rect)159 void OsrRenderHandlerWinD3D11::OnPopupSize(CefRefPtr<CefBrowser> browser,
160 const CefRect& rect) {
161 CEF_REQUIRE_UI_THREAD();
162 popup_layer_->set_bounds(rect);
163 }
164
OnPaint(CefRefPtr<CefBrowser> browser,CefRenderHandler::PaintElementType type,const CefRenderHandler::RectList & dirtyRects,const void * buffer,int width,int height)165 void OsrRenderHandlerWinD3D11::OnPaint(
166 CefRefPtr<CefBrowser> browser,
167 CefRenderHandler::PaintElementType type,
168 const CefRenderHandler::RectList& dirtyRects,
169 const void* buffer,
170 int width,
171 int height) {
172 // Not used with this implementation.
173 NOTREACHED();
174 }
175
OnAcceleratedPaint(CefRefPtr<CefBrowser> browser,CefRenderHandler::PaintElementType type,const CefRenderHandler::RectList & dirtyRects,void * share_handle)176 void OsrRenderHandlerWinD3D11::OnAcceleratedPaint(
177 CefRefPtr<CefBrowser> browser,
178 CefRenderHandler::PaintElementType type,
179 const CefRenderHandler::RectList& dirtyRects,
180 void* share_handle) {
181 CEF_REQUIRE_UI_THREAD();
182
183 if (type == PET_POPUP) {
184 popup_layer_->on_paint(share_handle);
185 } else {
186 browser_layer_->on_paint(share_handle);
187 }
188
189 Render();
190 }
191
Render()192 void OsrRenderHandlerWinD3D11::Render() {
193 // Update composition + layers based on time.
194 const auto t = (GetTimeNow() - start_time_) / 1000000.0;
195 composition_->tick(t);
196
197 auto ctx = device_->immedidate_context();
198 swap_chain_->bind(ctx);
199
200 const auto texture_size = browser_layer_->texture_size();
201
202 // Resize the composition and swap chain to match the texture if necessary.
203 composition_->resize(!send_begin_frame(), texture_size.first,
204 texture_size.second);
205 swap_chain_->resize(texture_size.first, texture_size.second);
206
207 // Clear the render target.
208 swap_chain_->clear(0.0f, 0.0f, 1.0f, 1.0f);
209
210 // Render the scene.
211 composition_->render(ctx);
212
213 // Present to window.
214 swap_chain_->present(send_begin_frame() ? 0 : 1);
215 }
216
217 } // namespace client
218