cef/libcef/browser/osr/browser_platform_delegate_osr.cc
Marshall Greenblatt a12c2ab3e1 Add support for MimeHandlerViewInCrossProcessFrame (fixes issue #2727)
The PDF loading documentation in extension_system.cc has be updated to
describe the new code paths.

To support delivery of input events to the mime handler renderer process it is
now necessary to route events via the correct RWHV interface. For Aura-based
platforms (Windows/Linux) this means RWHVAura::On*Event and for macOS this
means RWHVMac::RouteOrProcess*Event. Since Aura uses UI event types these have
become the source of truth on Aura-based platforms with conversion to Web event
types when needed (primarily for OSR).

This change also adds a timeout for CefProcessHostMsg_GetNewBrowserInfo to
avoid a hung renderer process if the guest WebContents route is not
registered via CefMimeHandlerViewGuestDelegate::OnGuestDetached as expected
prior to CefBrowserInfoManager::OnGetNewBrowserInfo being called. This
timeout can be disabled for testing purposes by passing the
`--disable-new-browser-info-timeout` command-line flag.

The `--disable-features=MimeHandlerViewInCrossProcessFrame` command-line
flag can be used for a limited time to restore the previous implementation
based on BrowserPlugin. That implementation will be deleted starting with
the 3897 branch update.

Known issues:
- ExecuteJavaScript calls on the frame hosting the PDF extension will not
  be routed to the mime handler renderer process.
- The PDF extension will not load successfully if blocked by
  ChromePluginPlaceholder and then manually continued via the "Run this
  plugin" context menu option (see https://crbug.com/533069#c41).
2020-01-24 20:16:47 -05:00

600 lines
20 KiB
C++

// Copyright 2015 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 "libcef/browser/osr/browser_platform_delegate_osr.h"
#include <utility>
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/image_impl.h"
#include "libcef/browser/osr/osr_accessibility_util.h"
#include "libcef/browser/osr/render_widget_host_view_osr.h"
#include "libcef/browser/osr/web_contents_view_osr.h"
#include "libcef/common/drag_data_impl.h"
#include "base/message_loop/message_loop_current.h"
#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/render_view_host.h"
#include "ui/events/base_event_utils.h"
CefBrowserPlatformDelegateOsr::CefBrowserPlatformDelegateOsr(
std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate)
: native_delegate_(std::move(native_delegate)), view_osr_(nullptr) {
native_delegate_->set_windowless_handler(this);
}
void CefBrowserPlatformDelegateOsr::CreateViewForWebContents(
content::WebContentsView** view,
content::RenderViewHostDelegateView** delegate_view) {
DCHECK(!view_osr_);
// Use the OSR view instead of the default platform view.
view_osr_ = new CefWebContentsViewOSR(
GetBackgroundColor(), CanUseSharedTexture(), CanUseExternalBeginFrame());
*view = view_osr_;
*delegate_view = view_osr_;
}
void CefBrowserPlatformDelegateOsr::WebContentsCreated(
content::WebContents* web_contents) {
CefBrowserPlatformDelegate::WebContentsCreated(web_contents);
DCHECK(view_osr_);
DCHECK(!view_osr_->web_contents());
// Associate the WebContents with the OSR view.
view_osr_->WebContentsCreated(web_contents);
}
void CefBrowserPlatformDelegateOsr::BrowserCreated(
CefBrowserHostImpl* browser) {
CefBrowserPlatformDelegate::BrowserCreated(browser);
if (browser->IsPopup()) {
// Associate the RenderWidget host view with the browser now because the
// browser wasn't known at the time that the host view was created.
content::RenderViewHost* host =
browser->web_contents()->GetRenderViewHost();
DCHECK(host);
CefRenderWidgetHostViewOSR* view =
static_cast<CefRenderWidgetHostViewOSR*>(host->GetWidget()->GetView());
// |view| will be null if the popup is a DevTools window.
if (view)
view->set_browser_impl(browser);
}
}
void CefBrowserPlatformDelegateOsr::BrowserDestroyed(
CefBrowserHostImpl* browser) {
CefBrowserPlatformDelegate::BrowserDestroyed(browser);
view_osr_ = nullptr;
}
bool CefBrowserPlatformDelegateOsr::CanUseSharedTexture() const {
return native_delegate_->CanUseSharedTexture();
}
bool CefBrowserPlatformDelegateOsr::CanUseExternalBeginFrame() const {
return native_delegate_->CanUseExternalBeginFrame();
}
SkColor CefBrowserPlatformDelegateOsr::GetBackgroundColor() const {
return native_delegate_->GetBackgroundColor();
}
void CefBrowserPlatformDelegateOsr::SynchronizeVisualProperties() {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (view)
view->SynchronizeVisualProperties();
}
void CefBrowserPlatformDelegateOsr::SendKeyEvent(const CefKeyEvent& event) {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (!view)
return;
content::NativeWebKeyboardEvent web_event =
native_delegate_->TranslateWebKeyEvent(event);
view->SendKeyEvent(web_event);
}
void CefBrowserPlatformDelegateOsr::SendMouseClickEvent(
const CefMouseEvent& event,
CefBrowserHost::MouseButtonType type,
bool mouseUp,
int clickCount) {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (!view)
return;
blink::WebMouseEvent web_event = native_delegate_->TranslateWebClickEvent(
event, type, mouseUp, clickCount);
view->SendMouseEvent(web_event);
}
void CefBrowserPlatformDelegateOsr::SendMouseMoveEvent(
const CefMouseEvent& event,
bool mouseLeave) {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (!view)
return;
blink::WebMouseEvent web_event =
native_delegate_->TranslateWebMoveEvent(event, mouseLeave);
view->SendMouseEvent(web_event);
}
void CefBrowserPlatformDelegateOsr::SendMouseWheelEvent(
const CefMouseEvent& event,
int deltaX,
int deltaY) {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (!view)
return;
blink::WebMouseWheelEvent web_event =
native_delegate_->TranslateWebWheelEvent(event, deltaX, deltaY);
view->SendMouseWheelEvent(web_event);
}
void CefBrowserPlatformDelegateOsr::SendTouchEvent(const CefTouchEvent& event) {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (view)
view->SendTouchEvent(event);
}
void CefBrowserPlatformDelegateOsr::SendFocusEvent(bool setFocus) {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (view)
view->SendFocusEvent(setFocus);
}
gfx::Point CefBrowserPlatformDelegateOsr::GetScreenPoint(
const gfx::Point& view) const {
CefRefPtr<CefRenderHandler> handler = browser_->client()->GetRenderHandler();
if (handler.get()) {
int screenX = 0, screenY = 0;
if (handler->GetScreenPoint(browser_, view.x(), view.y(), screenX,
screenY)) {
return gfx::Point(screenX, screenY);
}
}
return view;
}
void CefBrowserPlatformDelegateOsr::ViewText(const std::string& text) {
native_delegate_->ViewText(text);
}
bool CefBrowserPlatformDelegateOsr::HandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event) {
return native_delegate_->HandleKeyboardEvent(event);
}
CefEventHandle CefBrowserPlatformDelegateOsr::GetEventHandle(
const content::NativeWebKeyboardEvent& event) const {
return native_delegate_->GetEventHandle(event);
}
std::unique_ptr<CefFileDialogRunner>
CefBrowserPlatformDelegateOsr::CreateFileDialogRunner() {
return native_delegate_->CreateFileDialogRunner();
}
std::unique_ptr<CefJavaScriptDialogRunner>
CefBrowserPlatformDelegateOsr::CreateJavaScriptDialogRunner() {
return native_delegate_->CreateJavaScriptDialogRunner();
}
std::unique_ptr<CefMenuRunner>
CefBrowserPlatformDelegateOsr::CreateMenuRunner() {
return native_delegate_->CreateMenuRunner();
}
bool CefBrowserPlatformDelegateOsr::IsWindowless() const {
return true;
}
bool CefBrowserPlatformDelegateOsr::IsViewsHosted() const {
return false;
}
void CefBrowserPlatformDelegateOsr::WasHidden(bool hidden) {
// The WebContentsImpl will notify the OSR view.
content::WebContentsImpl* web_contents =
static_cast<content::WebContentsImpl*>(browser_->web_contents());
if (web_contents) {
if (hidden)
web_contents->WasHidden();
else
web_contents->WasShown();
}
}
void CefBrowserPlatformDelegateOsr::NotifyScreenInfoChanged() {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (view)
view->OnScreenInfoChanged();
}
void CefBrowserPlatformDelegateOsr::Invalidate(cef_paint_element_type_t type) {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (view)
view->Invalidate(type);
}
void CefBrowserPlatformDelegateOsr::SendExternalBeginFrame() {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (view)
view->SendExternalBeginFrame();
}
void CefBrowserPlatformDelegateOsr::SetWindowlessFrameRate(int frame_rate) {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (view)
view->UpdateFrameRate();
}
void CefBrowserPlatformDelegateOsr::ImeSetComposition(
const CefString& text,
const std::vector<CefCompositionUnderline>& underlines,
const CefRange& replacement_range,
const CefRange& selection_range) {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (view) {
view->ImeSetComposition(text, underlines, replacement_range,
selection_range);
}
}
void CefBrowserPlatformDelegateOsr::ImeCommitText(
const CefString& text,
const CefRange& replacement_range,
int relative_cursor_pos) {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (view)
view->ImeCommitText(text, replacement_range, relative_cursor_pos);
}
void CefBrowserPlatformDelegateOsr::ImeFinishComposingText(
bool keep_selection) {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (view)
view->ImeFinishComposingText(keep_selection);
}
void CefBrowserPlatformDelegateOsr::ImeCancelComposition() {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (view)
view->ImeCancelComposition();
}
void CefBrowserPlatformDelegateOsr::DragTargetDragEnter(
CefRefPtr<CefDragData> drag_data,
const CefMouseEvent& event,
cef_drag_operations_mask_t allowed_ops) {
content::WebContentsImpl* web_contents =
static_cast<content::WebContentsImpl*>(browser_->web_contents());
if (!web_contents)
return;
if (current_rvh_for_drag_)
DragTargetDragLeave();
const gfx::Point client_pt(event.x, event.y);
gfx::PointF transformed_pt;
current_rwh_for_drag_ =
web_contents->GetInputEventRouter()
->GetRenderWidgetHostAtPoint(
web_contents->GetRenderViewHost()->GetWidget()->GetView(),
gfx::PointF(client_pt), &transformed_pt)
->GetWeakPtr();
current_rvh_for_drag_ = web_contents->GetRenderViewHost();
drag_data_ = drag_data;
drag_allowed_ops_ = allowed_ops;
CefDragDataImpl* data_impl = static_cast<CefDragDataImpl*>(drag_data.get());
base::AutoLock lock_scope(data_impl->lock());
content::DropData* drop_data = data_impl->drop_data();
const gfx::Point& screen_pt = GetScreenPoint(client_pt);
blink::WebDragOperationsMask ops =
static_cast<blink::WebDragOperationsMask>(allowed_ops);
int modifiers = TranslateWebEventModifiers(event.modifiers);
current_rwh_for_drag_->FilterDropData(drop_data);
// Give the delegate an opportunity to cancel the drag.
if (web_contents->GetDelegate() && !web_contents->GetDelegate()->CanDragEnter(
web_contents, *drop_data, ops)) {
drag_data_ = nullptr;
return;
}
current_rwh_for_drag_->DragTargetDragEnter(
*drop_data, transformed_pt, gfx::PointF(screen_pt), ops, modifiers);
}
void CefBrowserPlatformDelegateOsr::DragTargetDragOver(
const CefMouseEvent& event,
cef_drag_operations_mask_t allowed_ops) {
if (!drag_data_)
return;
content::WebContentsImpl* web_contents =
static_cast<content::WebContentsImpl*>(browser_->web_contents());
if (!web_contents)
return;
const gfx::Point client_pt(event.x, event.y);
const gfx::Point& screen_pt = GetScreenPoint(client_pt);
gfx::PointF transformed_pt;
content::RenderWidgetHostImpl* target_rwh =
web_contents->GetInputEventRouter()->GetRenderWidgetHostAtPoint(
web_contents->GetRenderViewHost()->GetWidget()->GetView(),
gfx::PointF(client_pt), &transformed_pt);
if (target_rwh != current_rwh_for_drag_.get()) {
if (current_rwh_for_drag_) {
gfx::PointF transformed_leave_point(client_pt);
gfx::PointF transformed_screen_point(screen_pt);
static_cast<content::RenderWidgetHostViewBase*>(
web_contents->GetRenderWidgetHostView())
->TransformPointToCoordSpaceForView(
gfx::PointF(client_pt),
static_cast<content::RenderWidgetHostViewBase*>(
current_rwh_for_drag_->GetView()),
&transformed_leave_point);
static_cast<content::RenderWidgetHostViewBase*>(
web_contents->GetRenderWidgetHostView())
->TransformPointToCoordSpaceForView(
gfx::PointF(screen_pt),
static_cast<content::RenderWidgetHostViewBase*>(
current_rwh_for_drag_->GetView()),
&transformed_screen_point);
current_rwh_for_drag_->DragTargetDragLeave(transformed_leave_point,
transformed_screen_point);
}
DragTargetDragEnter(drag_data_, event, drag_allowed_ops_);
}
if (!drag_data_)
return;
blink::WebDragOperationsMask ops =
static_cast<blink::WebDragOperationsMask>(allowed_ops);
int modifiers = TranslateWebEventModifiers(event.modifiers);
target_rwh->DragTargetDragOver(transformed_pt, gfx::PointF(screen_pt), ops,
modifiers);
}
void CefBrowserPlatformDelegateOsr::DragTargetDragLeave() {
if (current_rvh_for_drag_ != browser_->web_contents()->GetRenderViewHost() ||
!drag_data_) {
return;
}
if (current_rwh_for_drag_) {
current_rwh_for_drag_->DragTargetDragLeave(gfx::PointF(), gfx::PointF());
current_rwh_for_drag_.reset();
}
drag_data_ = nullptr;
}
void CefBrowserPlatformDelegateOsr::DragTargetDrop(const CefMouseEvent& event) {
if (!drag_data_)
return;
content::WebContentsImpl* web_contents =
static_cast<content::WebContentsImpl*>(browser_->web_contents());
if (!web_contents)
return;
gfx::Point client_pt(event.x, event.y);
const gfx::Point& screen_pt = GetScreenPoint(client_pt);
gfx::PointF transformed_pt;
content::RenderWidgetHostImpl* target_rwh =
web_contents->GetInputEventRouter()->GetRenderWidgetHostAtPoint(
web_contents->GetRenderViewHost()->GetWidget()->GetView(),
gfx::PointF(client_pt), &transformed_pt);
if (target_rwh != current_rwh_for_drag_.get()) {
if (current_rwh_for_drag_) {
gfx::PointF transformed_leave_point(client_pt);
gfx::PointF transformed_screen_point(screen_pt);
static_cast<content::RenderWidgetHostViewBase*>(
web_contents->GetRenderWidgetHostView())
->TransformPointToCoordSpaceForView(
gfx::PointF(client_pt),
static_cast<content::RenderWidgetHostViewBase*>(
current_rwh_for_drag_->GetView()),
&transformed_leave_point);
static_cast<content::RenderWidgetHostViewBase*>(
web_contents->GetRenderWidgetHostView())
->TransformPointToCoordSpaceForView(
gfx::PointF(screen_pt),
static_cast<content::RenderWidgetHostViewBase*>(
current_rwh_for_drag_->GetView()),
&transformed_screen_point);
current_rwh_for_drag_->DragTargetDragLeave(transformed_leave_point,
transformed_screen_point);
}
DragTargetDragEnter(drag_data_, event, drag_allowed_ops_);
}
if (!drag_data_)
return;
{
CefDragDataImpl* data_impl =
static_cast<CefDragDataImpl*>(drag_data_.get());
base::AutoLock lock_scope(data_impl->lock());
content::DropData* drop_data = data_impl->drop_data();
int modifiers = TranslateWebEventModifiers(event.modifiers);
target_rwh->DragTargetDrop(*drop_data, transformed_pt,
gfx::PointF(screen_pt), modifiers);
}
drag_data_ = nullptr;
}
void CefBrowserPlatformDelegateOsr::StartDragging(
const content::DropData& drop_data,
blink::WebDragOperationsMask allowed_ops,
const gfx::ImageSkia& image,
const gfx::Vector2d& image_offset,
const content::DragEventSourceInfo& event_info,
content::RenderWidgetHostImpl* source_rwh) {
drag_start_rwh_ = source_rwh->GetWeakPtr();
bool handled = false;
CefRefPtr<CefRenderHandler> handler =
browser_->GetClient()->GetRenderHandler();
if (handler.get()) {
CefRefPtr<CefImage> cef_image(new CefImageImpl(image));
CefPoint cef_image_pos(image_offset.x(), image_offset.y());
CefRefPtr<CefDragDataImpl> drag_data(
new CefDragDataImpl(drop_data, cef_image, cef_image_pos));
drag_data->SetReadOnly(true);
base::MessageLoopCurrent::ScopedNestableTaskAllower allow;
handled = handler->StartDragging(
browser_, drag_data.get(),
static_cast<CefRenderHandler::DragOperationsMask>(allowed_ops),
event_info.event_location.x(), event_info.event_location.y());
}
if (!handled)
DragSourceSystemDragEnded();
}
void CefBrowserPlatformDelegateOsr::UpdateDragCursor(
blink::WebDragOperation operation) {
CefRefPtr<CefRenderHandler> handler =
browser_->GetClient()->GetRenderHandler();
if (handler.get()) {
handler->UpdateDragCursor(
browser_, static_cast<CefRenderHandler::DragOperation>(operation));
}
}
void CefBrowserPlatformDelegateOsr::DragSourceEndedAt(
int x,
int y,
cef_drag_operations_mask_t op) {
if (!drag_start_rwh_)
return;
content::WebContentsImpl* web_contents =
static_cast<content::WebContentsImpl*>(browser_->web_contents());
if (!web_contents)
return;
content::RenderWidgetHostImpl* source_rwh = drag_start_rwh_.get();
const gfx::Point client_loc(gfx::Point(x, y));
const gfx::Point& screen_loc = GetScreenPoint(client_loc);
blink::WebDragOperation drag_op = static_cast<blink::WebDragOperation>(op);
// |client_loc| and |screen_loc| are in the root coordinate space, for
// non-root RenderWidgetHosts they need to be transformed.
gfx::PointF transformed_point(client_loc);
gfx::PointF transformed_screen_point(screen_loc);
if (source_rwh && web_contents->GetRenderWidgetHostView()) {
static_cast<content::RenderWidgetHostViewBase*>(
web_contents->GetRenderWidgetHostView())
->TransformPointToCoordSpaceForView(
gfx::PointF(client_loc),
static_cast<content::RenderWidgetHostViewBase*>(
source_rwh->GetView()),
&transformed_point);
static_cast<content::RenderWidgetHostViewBase*>(
web_contents->GetRenderWidgetHostView())
->TransformPointToCoordSpaceForView(
gfx::PointF(screen_loc),
static_cast<content::RenderWidgetHostViewBase*>(
source_rwh->GetView()),
&transformed_screen_point);
}
web_contents->DragSourceEndedAt(transformed_point.x(), transformed_point.y(),
transformed_screen_point.x(),
transformed_screen_point.y(), drag_op,
source_rwh);
}
void CefBrowserPlatformDelegateOsr::DragSourceSystemDragEnded() {
if (!drag_start_rwh_)
return;
content::WebContents* web_contents = browser_->web_contents();
if (!web_contents)
return;
web_contents->SystemDragEnded(drag_start_rwh_.get());
drag_start_rwh_ = nullptr;
}
void CefBrowserPlatformDelegateOsr::AccessibilityEventReceived(
const content::AXEventNotificationDetails& eventData) {
CefRefPtr<CefRenderHandler> handler = browser_->client()->GetRenderHandler();
if (handler.get()) {
CefRefPtr<CefAccessibilityHandler> acchandler =
handler->GetAccessibilityHandler();
if (acchandler.get()) {
acchandler->OnAccessibilityTreeChange(
osr_accessibility_util::ParseAccessibilityEventData(eventData));
}
}
}
void CefBrowserPlatformDelegateOsr::AccessibilityLocationChangesReceived(
const std::vector<content::AXLocationChangeNotificationDetails>& locData) {
CefRefPtr<CefRenderHandler> handler = browser_->client()->GetRenderHandler();
if (handler.get()) {
CefRefPtr<CefAccessibilityHandler> acchandler =
handler->GetAccessibilityHandler();
if (acchandler.get()) {
acchandler->OnAccessibilityLocationChange(
osr_accessibility_util::ParseAccessibilityLocationData(locData));
}
}
}
CefWindowHandle CefBrowserPlatformDelegateOsr::GetParentWindowHandle() const {
return GetHostWindowHandle();
}
gfx::Point CefBrowserPlatformDelegateOsr::GetParentScreenPoint(
const gfx::Point& view) const {
return GetScreenPoint(view);
}
CefRenderWidgetHostViewOSR* CefBrowserPlatformDelegateOsr::GetOSRHostView()
const {
content::WebContents* web_contents = browser_->web_contents();
CefRenderWidgetHostViewOSR* fs_view =
static_cast<CefRenderWidgetHostViewOSR*>(
web_contents->GetFullscreenRenderWidgetHostView());
if (fs_view)
return fs_view;
content::RenderViewHost* host = web_contents->GetRenderViewHost();
if (host) {
return static_cast<CefRenderWidgetHostViewOSR*>(
host->GetWidget()->GetView());
}
return nullptr;
}