// 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/cefclient/browser/main_context.h" #include "tests/shared/browser/util_win.h" namespace client { BrowserLayer::BrowserLayer(const std::shared_ptr& device) : d3d11::Layer(device, true /* flip */) { frame_buffer_ = std::make_shared(device_); } void BrowserLayer::render(const std::shared_ptr& 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 BrowserLayer::texture_size() const { const auto texture = frame_buffer_->texture(); return std::make_pair(texture->width(), texture->height()); } PopupLayer::PopupLayer(const std::shared_ptr& 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 browser, int width, int height) { CEF_REQUIRE_UI_THREAD(); // Retrieve the shared D3D11 device instance. device_ = MainContext::Get()->GetD3D11Device(); 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(device_); // Set up the composition. composition_ = std::make_shared(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 browser, bool show) { CEF_REQUIRE_UI_THREAD(); if (show) { DCHECK(!popup_layer_); // Create a new layer. popup_layer_ = std::make_shared(device_); composition_->add_layer(popup_layer_); } else { DCHECK(popup_layer_); composition_->remove_layer(popup_layer_); popup_layer_ = nullptr; Render(); } } void OsrRenderHandlerWinD3D11::OnPopupSize(CefRefPtr browser, const CefRect& rect) { CEF_REQUIRE_UI_THREAD(); popup_layer_->set_bounds(rect); } void OsrRenderHandlerWinD3D11::OnPaint( CefRefPtr 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 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