| // Copyright 2018 The Chromium Embedded Framework 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 "tests/cefclient/browser/osr_render_handler_win_d3d11.h" |
| |
| #include "include/base/cef_bind.h" |
| #include "include/wrapper/cef_closure_task.h" |
| #include "include/wrapper/cef_helpers.h" |
| #include "tests/shared/browser/util_win.h" |
| |
| namespace client { |
| |
| BrowserLayer::BrowserLayer(const std::shared_ptr<d3d11::Device>& device) |
| : d3d11::Layer(device, true /* flip */) { |
| frame_buffer_ = std::make_shared<d3d11::FrameBuffer>(device_); |
| } |
| |
| void BrowserLayer::render(const std::shared_ptr<d3d11::Context>& ctx) { |
| // Use the base class method to draw our texture. |
| render_texture(ctx, frame_buffer_->texture()); |
| } |
| |
| void BrowserLayer::on_paint(void* share_handle) { |
| frame_buffer_->on_paint(share_handle); |
| } |
| |
| std::pair<uint32_t, uint32_t> BrowserLayer::texture_size() const { |
| const auto texture = frame_buffer_->texture(); |
| return std::make_pair(texture->width(), texture->height()); |
| } |
| |
| PopupLayer::PopupLayer(const std::shared_ptr<d3d11::Device>& device) |
| : BrowserLayer(device) {} |
| |
| void PopupLayer::set_bounds(const CefRect& bounds) { |
| const auto comp = composition(); |
| if (!comp) |
| return; |
| |
| const auto outer_width = comp->width(); |
| const auto outer_height = comp->height(); |
| if (outer_width == 0 || outer_height == 0) |
| return; |
| |
| original_bounds_ = bounds; |
| bounds_ = bounds; |
| |
| // If x or y are negative, move them to 0. |
| if (bounds_.x < 0) |
| bounds_.x = 0; |
| if (bounds_.y < 0) |
| bounds_.y = 0; |
| // If popup goes outside the view, try to reposition origin |
| if (bounds_.x + bounds_.width > outer_width) |
| bounds_.x = outer_width - bounds_.width; |
| if (bounds_.y + bounds_.height > outer_height) |
| bounds_.y = outer_height - bounds_.height; |
| // If x or y became negative, move them to 0 again. |
| if (bounds_.x < 0) |
| bounds_.x = 0; |
| if (bounds_.y < 0) |
| bounds_.y = 0; |
| |
| const auto x = bounds_.x / float(outer_width); |
| const auto y = bounds_.y / float(outer_height); |
| const auto w = bounds_.width / float(outer_width); |
| const auto h = bounds_.height / float(outer_height); |
| move(x, y, w, h); |
| } |
| |
| OsrRenderHandlerWinD3D11::OsrRenderHandlerWinD3D11( |
| const OsrRendererSettings& settings, |
| HWND hwnd) |
| : OsrRenderHandlerWin(settings, hwnd), start_time_(0) {} |
| |
| bool OsrRenderHandlerWinD3D11::Initialize(CefRefPtr<CefBrowser> browser, |
| int width, |
| int height) { |
| CEF_REQUIRE_UI_THREAD(); |
| |
| // Create a D3D11 device instance. |
| device_ = d3d11::Device::create(); |
| DCHECK(device_); |
| if (!device_) |
| return false; |
| |
| // Create a D3D11 swapchain for the window. |
| swap_chain_ = device_->create_swapchain(hwnd()); |
| DCHECK(swap_chain_); |
| if (!swap_chain_) |
| return false; |
| |
| // Create the browser layer. |
| browser_layer_ = std::make_shared<BrowserLayer>(device_); |
| |
| // Set up the composition. |
| composition_ = std::make_shared<d3d11::Composition>(device_, width, height); |
| composition_->add_layer(browser_layer_); |
| |
| // Size to the whole composition. |
| browser_layer_->move(0.0f, 0.0f, 1.0f, 1.0f); |
| |
| start_time_ = GetTimeNow(); |
| |
| SetBrowser(browser); |
| return true; |
| } |
| |
| void OsrRenderHandlerWinD3D11::SetSpin(float spinX, float spinY) { |
| CEF_REQUIRE_UI_THREAD(); |
| // Spin support is not implemented. |
| } |
| |
| void OsrRenderHandlerWinD3D11::IncrementSpin(float spinDX, float spinDY) { |
| CEF_REQUIRE_UI_THREAD(); |
| // Spin support is not implemented. |
| } |
| |
| bool OsrRenderHandlerWinD3D11::IsOverPopupWidget(int x, int y) const { |
| CEF_REQUIRE_UI_THREAD(); |
| return popup_layer_ && popup_layer_->contains(x, y); |
| } |
| |
| int OsrRenderHandlerWinD3D11::GetPopupXOffset() const { |
| CEF_REQUIRE_UI_THREAD(); |
| if (popup_layer_) |
| return popup_layer_->xoffset(); |
| return 0; |
| } |
| |
| int OsrRenderHandlerWinD3D11::GetPopupYOffset() const { |
| CEF_REQUIRE_UI_THREAD(); |
| if (popup_layer_) |
| return popup_layer_->yoffset(); |
| return 0; |
| } |
| |
| void OsrRenderHandlerWinD3D11::OnPopupShow(CefRefPtr<CefBrowser> browser, |
| bool show) { |
| CEF_REQUIRE_UI_THREAD(); |
| |
| if (show) { |
| DCHECK(!popup_layer_); |
| |
| // Create a new layer. |
| popup_layer_ = std::make_shared<PopupLayer>(device_); |
| composition_->add_layer(popup_layer_); |
| } else { |
| DCHECK(popup_layer_); |
| |
| composition_->remove_layer(popup_layer_); |
| popup_layer_ = nullptr; |
| |
| Render(); |
| } |
| } |
| |
| void OsrRenderHandlerWinD3D11::OnPopupSize(CefRefPtr<CefBrowser> browser, |
| const CefRect& rect) { |
| CEF_REQUIRE_UI_THREAD(); |
| popup_layer_->set_bounds(rect); |
| } |
| |
| void OsrRenderHandlerWinD3D11::OnPaint( |
| CefRefPtr<CefBrowser> browser, |
| CefRenderHandler::PaintElementType type, |
| const CefRenderHandler::RectList& dirtyRects, |
| const void* buffer, |
| int width, |
| int height) { |
| // Not used with this implementation. |
| NOTREACHED(); |
| } |
| |
| void OsrRenderHandlerWinD3D11::OnAcceleratedPaint( |
| CefRefPtr<CefBrowser> browser, |
| CefRenderHandler::PaintElementType type, |
| const CefRenderHandler::RectList& dirtyRects, |
| void* share_handle) { |
| CEF_REQUIRE_UI_THREAD(); |
| |
| if (type == PET_POPUP) { |
| popup_layer_->on_paint(share_handle); |
| } else { |
| browser_layer_->on_paint(share_handle); |
| } |
| |
| Render(); |
| } |
| |
| void OsrRenderHandlerWinD3D11::Render() { |
| // Update composition + layers based on time. |
| const auto t = (GetTimeNow() - start_time_) / 1000000.0; |
| composition_->tick(t); |
| |
| auto ctx = device_->immedidate_context(); |
| swap_chain_->bind(ctx); |
| |
| const auto texture_size = browser_layer_->texture_size(); |
| |
| // Resize the composition and swap chain to match the texture if necessary. |
| composition_->resize(!send_begin_frame(), texture_size.first, |
| texture_size.second); |
| swap_chain_->resize(texture_size.first, texture_size.second); |
| |
| // Clear the render target. |
| swap_chain_->clear(0.0f, 0.0f, 1.0f, 1.0f); |
| |
| // Render the scene. |
| composition_->render(ctx); |
| |
| // Present to window. |
| swap_chain_->present(send_begin_frame() ? 0 : 1); |
| } |
| |
| } // namespace client |