diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-05-15 10:20:33 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-05-15 10:28:57 +0000 |
commit | d17ea114e5ef69ad5d5d7413280a13e6428098aa (patch) | |
tree | 2c01a75df69f30d27b1432467cfe7c1467a498da /chromium/third_party/blink/renderer/core/page/chrome_client_impl.cc | |
parent | 8c5c43c7b138c9b4b0bf56d946e61d3bbc111bec (diff) | |
download | qtwebengine-chromium-d17ea114e5ef69ad5d5d7413280a13e6428098aa.tar.gz |
BASELINE: Update Chromium to 67.0.3396.47
Change-Id: Idcb1341782e417561a2473eeecc82642dafda5b7
Reviewed-by: Michal Klocek <michal.klocek@qt.io>
Diffstat (limited to 'chromium/third_party/blink/renderer/core/page/chrome_client_impl.cc')
-rw-r--r-- | chromium/third_party/blink/renderer/core/page/chrome_client_impl.cc | 1123 |
1 files changed, 1123 insertions, 0 deletions
diff --git a/chromium/third_party/blink/renderer/core/page/chrome_client_impl.cc b/chromium/third_party/blink/renderer/core/page/chrome_client_impl.cc new file mode 100644 index 00000000000..0d4aad18278 --- /dev/null +++ b/chromium/third_party/blink/renderer/core/page/chrome_client_impl.cc @@ -0,0 +1,1123 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "third_party/blink/renderer/core/page/chrome_client_impl.h" + +#include <memory> +#include <utility> + +#include "build/build_config.h" +#include "third_party/blink/public/platform/web_cursor_info.h" +#include "third_party/blink/public/platform/web_float_rect.h" +#include "third_party/blink/public/platform/web_rect.h" +#include "third_party/blink/public/platform/web_url_request.h" +#include "third_party/blink/public/web/blink.h" +#include "third_party/blink/public/web/web_autofill_client.h" +#include "third_party/blink/public/web/web_console_message.h" +#include "third_party/blink/public/web/web_frame_client.h" +#include "third_party/blink/public/web/web_input_element.h" +#include "third_party/blink/public/web/web_node.h" +#include "third_party/blink/public/web/web_plugin.h" +#include "third_party/blink/public/web/web_popup_menu_info.h" +#include "third_party/blink/public/web/web_selection.h" +#include "third_party/blink/public/web/web_settings.h" +#include "third_party/blink/public/web/web_text_direction.h" +#include "third_party/blink/public/web/web_user_gesture_indicator.h" +#include "third_party/blink/public/web/web_user_gesture_token.h" +#include "third_party/blink/public/web/web_view_client.h" +#include "third_party/blink/public/web/web_window_features.h" +#include "third_party/blink/renderer/bindings/core/v8/script_controller.h" +#include "third_party/blink/renderer/core/dom/document.h" +#include "third_party/blink/renderer/core/dom/node.h" +#include "third_party/blink/renderer/core/events/web_input_event_conversion.h" +#include "third_party/blink/renderer/core/exported/web_file_chooser_completion_impl.h" +#include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h" +#include "third_party/blink/renderer/core/exported/web_remote_frame_impl.h" +#include "third_party/blink/renderer/core/exported/web_settings_impl.h" +#include "third_party/blink/renderer/core/exported/web_view_impl.h" +#include "third_party/blink/renderer/core/frame/browser_controls.h" +#include "third_party/blink/renderer/core/frame/local_frame_view.h" +#include "third_party/blink/renderer/core/frame/settings.h" +#include "third_party/blink/renderer/core/frame/use_counter.h" +#include "third_party/blink/renderer/core/frame/visual_viewport.h" +#include "third_party/blink/renderer/core/frame/web_frame_widget_base.h" +#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" +#include "third_party/blink/renderer/core/fullscreen/fullscreen.h" +#include "third_party/blink/renderer/core/html/forms/color_chooser.h" +#include "third_party/blink/renderer/core/html/forms/color_chooser_client.h" +#include "third_party/blink/renderer/core/html/forms/color_chooser_popup_ui_controller.h" +#include "third_party/blink/renderer/core/html/forms/color_chooser_ui_controller.h" +#include "third_party/blink/renderer/core/html/forms/date_time_chooser.h" +#include "third_party/blink/renderer/core/html/forms/date_time_chooser_client.h" +#include "third_party/blink/renderer/core/html/forms/date_time_chooser_impl.h" +#include "third_party/blink/renderer/core/html/forms/external_date_time_chooser.h" +#include "third_party/blink/renderer/core/html/forms/external_popup_menu.h" +#include "third_party/blink/renderer/core/html/forms/file_chooser.h" +#include "third_party/blink/renderer/core/html/forms/html_input_element.h" +#include "third_party/blink/renderer/core/html/forms/internal_popup_menu.h" +#include "third_party/blink/renderer/core/inspector/dev_tools_emulator.h" +#include "third_party/blink/renderer/core/layout/hit_test_result.h" +#include "third_party/blink/renderer/core/layout/layout_embedded_content.h" +#include "third_party/blink/renderer/core/loader/document_loader.h" +#include "third_party/blink/renderer/core/loader/frame_load_request.h" +#include "third_party/blink/renderer/core/page/chrome_client.h" +#include "third_party/blink/renderer/core/page/page.h" +#include "third_party/blink/renderer/core/page/popup_opening_observer.h" +#include "third_party/blink/renderer/core/paint/compositing/composited_selection.h" +#include "third_party/blink/renderer/platform/animation/compositor_animation_host.h" +#include "third_party/blink/renderer/platform/cursor.h" +#include "third_party/blink/renderer/platform/exported/wrapped_resource_request.h" +#include "third_party/blink/renderer/platform/geometry/int_rect.h" +#include "third_party/blink/renderer/platform/graphics/graphics_layer.h" +#include "third_party/blink/renderer/platform/graphics/touch_action.h" +#include "third_party/blink/renderer/platform/histogram.h" +#include "third_party/blink/renderer/platform/layout_test_support.h" +#include "third_party/blink/renderer/platform/runtime_enabled_features.h" +#include "third_party/blink/renderer/platform/weborigin/security_origin.h" +#include "third_party/blink/renderer/platform/wtf/optional.h" +#include "third_party/blink/renderer/platform/wtf/text/character_names.h" +#include "third_party/blink/renderer/platform/wtf/text/cstring.h" +#include "third_party/blink/renderer/platform/wtf/text/string_builder.h" +#include "third_party/blink/renderer/platform/wtf/text/string_concatenate.h" + +namespace blink { + +namespace { + +const char* DialogTypeToString(ChromeClient::DialogType dialog_type) { + switch (dialog_type) { + case ChromeClient::kAlertDialog: + return "alert"; + case ChromeClient::kConfirmDialog: + return "confirm"; + case ChromeClient::kPromptDialog: + return "prompt"; + case ChromeClient::kPrintDialog: + return "print"; + case ChromeClient::kHTMLDialog: + NOTREACHED(); + } + NOTREACHED(); + return ""; +} + +const char* DismissalTypeToString(Document::PageDismissalType dismissal_type) { + switch (dismissal_type) { + case Document::kBeforeUnloadDismissal: + return "beforeunload"; + case Document::kPageHideDismissal: + return "pagehide"; + case Document::kUnloadVisibilityChangeDismissal: + return "visibilitychange"; + case Document::kUnloadDismissal: + return "unload"; + case Document::kNoDismissal: + NOTREACHED(); + } + NOTREACHED(); + return ""; +} + +} // namespace + +class CompositorAnimationTimeline; + +ChromeClientImpl::ChromeClientImpl(WebViewImpl* web_view) + : web_view_(web_view), + cursor_overridden_(false), + did_request_non_empty_tool_tip_(false) {} + +ChromeClientImpl::~ChromeClientImpl() = default; + +ChromeClientImpl* ChromeClientImpl::Create(WebViewImpl* web_view) { + return new ChromeClientImpl(web_view); +} + +WebViewImpl* ChromeClientImpl::GetWebView() const { + return web_view_; +} + +void ChromeClientImpl::ChromeDestroyed() { + // Our lifetime is bound to the WebViewImpl. +} + +void ChromeClientImpl::SetWindowRect(const IntRect& r, LocalFrame& frame) { + DCHECK_EQ(&frame, web_view_->MainFrameImpl()->GetFrame()); + WebWidgetClient* client = + WebLocalFrameImpl::FromFrame(&frame)->FrameWidgetImpl()->Client(); + client->SetWindowRect(r); +} + +IntRect ChromeClientImpl::RootWindowRect() { + WebRect rect; + if (web_view_->Client()) { + rect = web_view_->Client()->RootWindowRect(); + } else { + // These numbers will be fairly wrong. The window's x/y coordinates will + // be the top left corner of the screen and the size will be the content + // size instead of the window size. + rect.width = web_view_->Size().width; + rect.height = web_view_->Size().height; + } + return IntRect(rect); +} + +IntRect ChromeClientImpl::PageRect() { + // We hide the details of the window's border thickness from the web page by + // simple re-using the window position here. So, from the point-of-view of + // the web page, the window has no border. + return RootWindowRect(); +} + +void ChromeClientImpl::Focus(LocalFrame* calling_frame) { + if (web_view_->Client()) { + web_view_->Client()->DidFocus( + calling_frame ? WebLocalFrameImpl::FromFrame(calling_frame) : nullptr); + } +} + +bool ChromeClientImpl::CanTakeFocus(WebFocusType) { + // For now the browser can always take focus if we're not running layout + // tests. + return !LayoutTestSupport::IsRunningLayoutTest(); +} + +void ChromeClientImpl::TakeFocus(WebFocusType type) { + if (!web_view_->Client()) + return; + if (type == kWebFocusTypeBackward) + web_view_->Client()->FocusPrevious(); + else + web_view_->Client()->FocusNext(); +} + +void ChromeClientImpl::FocusedNodeChanged(Node* from_node, Node* to_node) { + if (!web_view_->Client()) + return; + + web_view_->Client()->FocusedNodeChanged(WebNode(from_node), WebNode(to_node)); + + WebURL focus_url; + if (to_node && to_node->IsElementNode() && ToElement(to_node)->IsLiveLink() && + to_node->ShouldHaveFocusAppearance()) + focus_url = ToElement(to_node)->HrefURL(); + web_view_->Client()->SetKeyboardFocusURL(focus_url); +} + +bool ChromeClientImpl::HadFormInteraction() const { + return web_view_->PageImportanceSignals() && + web_view_->PageImportanceSignals()->HadFormInteraction(); +} + +void ChromeClientImpl::StartDragging(LocalFrame* frame, + const WebDragData& drag_data, + WebDragOperationsMask mask, + const WebImage& drag_image, + const WebPoint& drag_image_offset) { + WebLocalFrameImpl* web_frame = WebLocalFrameImpl::FromFrame(frame); + WebReferrerPolicy policy = web_frame->GetDocument().GetReferrerPolicy(); + web_frame->LocalRootFrameWidget()->StartDragging( + policy, drag_data, mask, drag_image, drag_image_offset); +} + +bool ChromeClientImpl::AcceptsLoadDrops() const { + return !web_view_->Client() || web_view_->Client()->AcceptsLoadDrops(); +} + +Page* ChromeClientImpl::CreateWindow(LocalFrame* frame, + const FrameLoadRequest& r, + const WebWindowFeatures& features, + NavigationPolicy navigation_policy, + SandboxFlags sandbox_flags) { + if (!web_view_->Client()) + return nullptr; + + if (!frame->GetPage() || frame->GetPage()->Paused()) + return nullptr; + + const AtomicString& frame_name = + !EqualIgnoringASCIICase(r.FrameName(), "_blank") ? r.FrameName() + : g_empty_atom; + WebViewImpl* new_view = + static_cast<WebViewImpl*>(web_view_->Client()->CreateView( + WebLocalFrameImpl::FromFrame(frame), + WrappedResourceRequest(r.GetResourceRequest()), features, frame_name, + static_cast<WebNavigationPolicy>(navigation_policy), + r.GetShouldSetOpener() == kNeverSetOpener, + static_cast<WebSandboxFlags>(sandbox_flags))); + if (!new_view) + return nullptr; + return new_view->GetPage(); +} + +void ChromeClientImpl::DidOverscroll(const FloatSize& overscroll_delta, + const FloatSize& accumulated_overscroll, + const FloatPoint& position_in_viewport, + const FloatSize& velocity_in_viewport, + const WebOverscrollBehavior& behavior) { + if (!web_view_->Client()) + return; + + web_view_->Client()->DidOverscroll(overscroll_delta, accumulated_overscroll, + position_in_viewport, velocity_in_viewport, + behavior); +} + +void ChromeClientImpl::Show(NavigationPolicy navigation_policy) { + if (web_view_->Client()) { + web_view_->Client()->Show( + static_cast<WebNavigationPolicy>(navigation_policy)); + } +} + +bool ChromeClientImpl::ShouldReportDetailedMessageForSource( + LocalFrame& local_frame, + const String& url) { + WebLocalFrameImpl* webframe = + WebLocalFrameImpl::FromFrame(&local_frame.LocalFrameRoot()); + return webframe && webframe->Client() && + webframe->Client()->ShouldReportDetailedMessageForSource(url); +} + +void ChromeClientImpl::AddMessageToConsole(LocalFrame* local_frame, + MessageSource source, + MessageLevel level, + const String& message, + unsigned line_number, + const String& source_id, + const String& stack_trace) { + WebLocalFrameImpl* frame = WebLocalFrameImpl::FromFrame(local_frame); + if (frame && frame->Client()) { + frame->Client()->DidAddMessageToConsole( + WebConsoleMessage(static_cast<WebConsoleMessage::Level>(level), + message), + source_id, line_number, stack_trace); + } +} + +bool ChromeClientImpl::CanOpenBeforeUnloadConfirmPanel() { + return !!web_view_->Client(); +} + +bool ChromeClientImpl::OpenBeforeUnloadConfirmPanelDelegate(LocalFrame* frame, + bool is_reload) { + NotifyPopupOpeningObservers(); + WebLocalFrameImpl* webframe = WebLocalFrameImpl::FromFrame(frame); + return webframe->Client() && + webframe->Client()->RunModalBeforeUnloadDialog(is_reload); +} + +void ChromeClientImpl::CloseWindowSoon() { + if (web_view_->Client()) + web_view_->Client()->CloseWidgetSoon(); +} + +// Although a LocalFrame is passed in, we don't actually use it, since we +// already know our own m_webView. +bool ChromeClientImpl::OpenJavaScriptAlertDelegate(LocalFrame* frame, + const String& message) { + NotifyPopupOpeningObservers(); + WebLocalFrameImpl* webframe = WebLocalFrameImpl::FromFrame(frame); + if (webframe->Client()) { + // (TODO(mustaq): why is it going through the web layer? crbug.com/781328 + if (WebUserGestureIndicator::IsProcessingUserGesture(webframe)) + WebUserGestureIndicator::DisableTimeout(); + webframe->Client()->RunModalAlertDialog(message); + return true; + } + return false; +} + +// See comments for openJavaScriptAlertDelegate(). +bool ChromeClientImpl::OpenJavaScriptConfirmDelegate(LocalFrame* frame, + const String& message) { + NotifyPopupOpeningObservers(); + WebLocalFrameImpl* webframe = WebLocalFrameImpl::FromFrame(frame); + if (webframe->Client()) { + // (TODO(mustaq): why is it going through the web layer? crbug.com/781328 + if (WebUserGestureIndicator::IsProcessingUserGesture(webframe)) + WebUserGestureIndicator::DisableTimeout(); + return webframe->Client()->RunModalConfirmDialog(message); + } + return false; +} + +// See comments for openJavaScriptAlertDelegate(). +bool ChromeClientImpl::OpenJavaScriptPromptDelegate(LocalFrame* frame, + const String& message, + const String& default_value, + String& result) { + NotifyPopupOpeningObservers(); + WebLocalFrameImpl* webframe = WebLocalFrameImpl::FromFrame(frame); + if (webframe->Client()) { + // (TODO(mustaq): why is it going through the web layer? + if (WebUserGestureIndicator::IsProcessingUserGesture(webframe)) + WebUserGestureIndicator::DisableTimeout(); + WebString actual_value; + bool ok = webframe->Client()->RunModalPromptDialog(message, default_value, + &actual_value); + if (ok) + result = actual_value; + return ok; + } + return false; +} +bool ChromeClientImpl::TabsToLinks() { + return web_view_->TabsToLinks(); +} + +void ChromeClientImpl::InvalidateRect(const IntRect& update_rect) { + if (!update_rect.IsEmpty()) + web_view_->InvalidateRect(update_rect); +} + +void ChromeClientImpl::ScheduleAnimation( + const PlatformFrameView* platform_frame_view) { + DCHECK(platform_frame_view->IsLocalFrameView()); + LocalFrame& frame = ToLocalFrameView(platform_frame_view)->GetFrame(); + WebLocalFrameImpl* web_frame = WebLocalFrameImpl::FromFrame(&frame); + DCHECK(web_frame); + // If the frame is still being created, it might not yet have a WebWidget. + // TODO(dcheng): Is this the right thing to do? Is there a way to avoid having + // a local frame root that doesn't have a WebWidget? During initialization + // there is no content to draw so this call serves no purpose. Maybe the + // WebFrameWidget needs to be initialized before initializing the core frame? + if (!web_frame->LocalRootFrameWidget()) + return; + web_frame->LocalRootFrameWidget()->ScheduleAnimation(); +} + +IntRect ChromeClientImpl::ViewportToScreen( + const IntRect& rect_in_viewport, + const PlatformFrameView* platform_frame_view) const { + WebRect screen_rect(rect_in_viewport); + + LocalFrame& frame = ToLocalFrameView(platform_frame_view)->GetFrame(); + + WebWidgetClient* client = + WebLocalFrameImpl::FromFrame(&frame)->LocalRootFrameWidget()->Client(); + + // TODO(dcheng): Is this null check needed? + if (client) { + client->ConvertViewportToWindow(&screen_rect); + WebRect view_rect = client->ViewRect(); + screen_rect.x += view_rect.x; + screen_rect.y += view_rect.y; + } + + return screen_rect; +} + +float ChromeClientImpl::WindowToViewportScalar(const float scalar_value) const { + if (!web_view_->Client()) + return scalar_value; + WebFloatRect viewport_rect(0, 0, scalar_value, 0); + web_view_->Client()->ConvertWindowToViewport(&viewport_rect); + return viewport_rect.width; +} + +WebScreenInfo ChromeClientImpl::GetScreenInfo() const { + return web_view_->Client() ? web_view_->Client()->GetScreenInfo() + : WebScreenInfo(); +} + +WTF::Optional<IntRect> ChromeClientImpl::VisibleContentRectForPainting() const { + return web_view_->GetDevToolsEmulator()->VisibleContentRectForPainting(); +} + +void ChromeClientImpl::ContentsSizeChanged(LocalFrame* frame, + const IntSize& size) const { + web_view_->DidChangeContentsSize(); + + WebLocalFrameImpl* webframe = WebLocalFrameImpl::FromFrame(frame); + webframe->DidChangeContentsSize(size); +} + +void ChromeClientImpl::PageScaleFactorChanged() const { + web_view_->PageScaleFactorChanged(); +} + +void ChromeClientImpl::MainFrameScrollOffsetChanged() const { + web_view_->MainFrameScrollOffsetChanged(); +} + +float ChromeClientImpl::ClampPageScaleFactorToLimits(float scale) const { + return web_view_->ClampPageScaleFactorToLimits(scale); +} + +void ChromeClientImpl::ResizeAfterLayout() const { + web_view_->ResizeAfterLayout(); +} + +void ChromeClientImpl::LayoutUpdated() const { + web_view_->LayoutUpdated(); +} + +void ChromeClientImpl::ShowMouseOverURL(const HitTestResult& result) { + if (!web_view_->Client()) + return; + + WebURL url; + + // Ignore URL if hitTest include scrollbar since we might have both a + // scrollbar and an element in the case of overlay scrollbars. + if (!result.GetScrollbar()) { + // Find out if the mouse is over a link, and if so, let our UI know... + if (result.IsLiveLink() && + !result.AbsoluteLinkURL().GetString().IsEmpty()) { + url = result.AbsoluteLinkURL(); + } else if (result.InnerNode() && + (IsHTMLObjectElement(*result.InnerNode()) || + IsHTMLEmbedElement(*result.InnerNode()))) { + LayoutObject* object = result.InnerNode()->GetLayoutObject(); + if (object && object->IsLayoutEmbeddedContent()) { + WebPluginContainerImpl* plugin_view = + ToLayoutEmbeddedContent(object)->Plugin(); + if (plugin_view) { + url = plugin_view->Plugin()->LinkAtPosition( + result.RoundedPointInInnerNodeFrame()); + } + } + } + } + + web_view_->Client()->SetMouseOverURL(url); +} + +void ChromeClientImpl::SetToolTip(LocalFrame& frame, + const String& tooltip_text, + TextDirection dir) { + WebLocalFrameImpl* web_frame = WebLocalFrameImpl::FromFrame(&frame); + if (!tooltip_text.IsEmpty()) { + web_frame->LocalRootFrameWidget()->Client()->SetToolTipText( + tooltip_text, ToWebTextDirection(dir)); + did_request_non_empty_tool_tip_ = true; + } else if (did_request_non_empty_tool_tip_) { + // WebWidgetClient::setToolTipText will send an IPC message. We'd like to + // reduce the number of setToolTipText calls. + web_frame->LocalRootFrameWidget()->Client()->SetToolTipText( + tooltip_text, ToWebTextDirection(dir)); + did_request_non_empty_tool_tip_ = false; + } +} + +void ChromeClientImpl::DispatchViewportPropertiesDidChange( + const ViewportDescription& description) const { + web_view_->UpdatePageDefinedViewportConstraints(description); +} + +void ChromeClientImpl::PrintDelegate(LocalFrame* frame) { + NotifyPopupOpeningObservers(); + if (web_view_->Client()) + web_view_->Client()->PrintPage(WebLocalFrameImpl::FromFrame(frame)); +} + +ColorChooser* ChromeClientImpl::OpenColorChooser( + LocalFrame* frame, + ColorChooserClient* chooser_client, + const Color&) { + NotifyPopupOpeningObservers(); + ColorChooserUIController* controller = nullptr; + + // TODO(crbug.com/779126): add support for the chooser in immersive mode. + if (frame->GetDocument()->GetSettings()->GetImmersiveModeEnabled()) + return nullptr; + + if (RuntimeEnabledFeatures::PagePopupEnabled()) { + controller = + ColorChooserPopupUIController::Create(frame, this, chooser_client); + } else { + controller = ColorChooserUIController::Create(frame, chooser_client); + } + controller->OpenUI(); + return controller; +} + +DateTimeChooser* ChromeClientImpl::OpenDateTimeChooser( + DateTimeChooserClient* picker_client, + const DateTimeChooserParameters& parameters) { + // TODO(crbug.com/779126): add support for the chooser in immersive mode. + if (picker_client->OwnerElement() + .GetDocument() + .GetSettings() + ->GetImmersiveModeEnabled()) + return nullptr; + + NotifyPopupOpeningObservers(); + if (RuntimeEnabledFeatures::InputMultipleFieldsUIEnabled()) + return DateTimeChooserImpl::Create(this, picker_client, parameters); + return ExternalDateTimeChooser::Create(this, web_view_->Client(), + picker_client, parameters); +} + +void ChromeClientImpl::OpenFileChooser( + LocalFrame* frame, + scoped_refptr<FileChooser> file_chooser) { + NotifyPopupOpeningObservers(); + WebFrameClient* client = WebLocalFrameImpl::FromFrame(frame)->Client(); + if (!client) + return; + + Document* doc = frame->GetDocument(); + if (doc) + doc->MaybeQueueSendDidEditFieldInInsecureContext(); + const WebFileChooserParams& params = file_chooser->Params(); + WebFileChooserCompletionImpl* chooser_completion = + new WebFileChooserCompletionImpl(std::move(file_chooser)); + if (client->RunFileChooser(params, chooser_completion)) + return; + // Choosing failed, so do callback with an empty list. + chooser_completion->DidChooseFile(WebVector<WebString>()); +} + +void ChromeClientImpl::EnumerateChosenDirectory(FileChooser* file_chooser) { + WebViewClient* client = web_view_->Client(); + if (!client) + return; + + WebFileChooserCompletionImpl* chooser_completion = + new WebFileChooserCompletionImpl(file_chooser); + + DCHECK(file_chooser); + DCHECK(file_chooser->Params().selected_files.size()); + + // If the enumeration can't happen, call the callback with an empty list. + if (!client->EnumerateChosenDirectory( + file_chooser->Params().selected_files[0], chooser_completion)) + chooser_completion->DidChooseFile(WebVector<WebString>()); +} + +Cursor ChromeClientImpl::LastSetCursorForTesting() const { + return last_set_mouse_cursor_for_testing_; +} + +void ChromeClientImpl::SetCursor(const Cursor& cursor, + LocalFrame* local_frame) { + last_set_mouse_cursor_for_testing_ = cursor; + SetCursor(WebCursorInfo(cursor), local_frame); +} + +void ChromeClientImpl::SetCursor(const WebCursorInfo& cursor, + LocalFrame* local_frame) { + if (cursor_overridden_) + return; + +#if defined(OS_MACOSX) + // On Mac the mousemove event propagates to both the popup and main window. + // If a popup is open we don't want the main window to change the cursor. + if (web_view_->HasOpenedPopup()) + return; +#endif + + // TODO(dcheng): Why is this null check necessary? + if (WebFrameWidgetBase* widget = + WebLocalFrameImpl::FromFrame(local_frame)->LocalRootFrameWidget()) + widget->Client()->DidChangeCursor(cursor); +} + +void ChromeClientImpl::SetCursorForPlugin(const WebCursorInfo& cursor, + LocalFrame* local_frame) { + SetCursor(cursor, local_frame); +} + +void ChromeClientImpl::SetCursorOverridden(bool overridden) { + cursor_overridden_ = overridden; +} + +void ChromeClientImpl::AutoscrollStart(WebFloatPoint viewport_point, + LocalFrame* local_frame) { + if (WebFrameWidgetBase* widget = + WebLocalFrameImpl::FromFrame(local_frame)->LocalRootFrameWidget()) + widget->Client()->AutoscrollStart(viewport_point); +} + +void ChromeClientImpl::AutoscrollFling(WebFloatSize velocity, + LocalFrame* local_frame) { + if (WebFrameWidgetBase* widget = + WebLocalFrameImpl::FromFrame(local_frame)->LocalRootFrameWidget()) + widget->Client()->AutoscrollFling(velocity); +} + +void ChromeClientImpl::AutoscrollEnd(LocalFrame* local_frame) { + if (WebFrameWidgetBase* widget = + WebLocalFrameImpl::FromFrame(local_frame)->LocalRootFrameWidget()) + widget->Client()->AutoscrollEnd(); +} + +String ChromeClientImpl::AcceptLanguages() { + return web_view_->Client()->AcceptLanguages(); +} + +void ChromeClientImpl::AttachRootGraphicsLayer(GraphicsLayer* root_layer, + LocalFrame* local_frame) { + DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()); + // TODO(dcheng): This seems wrong. Non-local roots shouldn't be calling this + // function. + WebLocalFrameImpl* web_frame = + WebLocalFrameImpl::FromFrame(local_frame)->LocalRoot(); + DCHECK(WebLocalFrameImpl::FromFrame(local_frame) == web_frame); + + // This method can be called while the frame is being detached. In that + // case, the rootLayer is null, and the widget is already destroyed. + // TODO(dcheng): This should be called before the widget is gone... + DCHECK(web_frame->FrameWidgetImpl() || !root_layer); + if (web_frame->FrameWidgetImpl()) + web_frame->FrameWidgetImpl()->SetRootGraphicsLayer(root_layer); +} + +void ChromeClientImpl::AttachRootLayer(WebLayer* root_layer, + LocalFrame* local_frame) { + // TODO(dcheng): This seems wrong. Non-local roots shouldn't be calling this + // function. + WebLocalFrameImpl* web_frame = + WebLocalFrameImpl::FromFrame(local_frame)->LocalRoot(); + DCHECK(WebLocalFrameImpl::FromFrame(local_frame) == web_frame); + + // This method can be called while the frame is being detached. In that + // case, the rootLayer is null, and the widget is already destroyed. + // TODO(dcheng): This should be called before the widget is gone... + DCHECK(web_frame->FrameWidget() || !root_layer); + if (web_frame->FrameWidgetImpl()) + web_frame->FrameWidgetImpl()->SetRootLayer(root_layer); +} + +void ChromeClientImpl::AttachCompositorAnimationTimeline( + CompositorAnimationTimeline* compositor_timeline, + LocalFrame* local_frame) { + WebLocalFrameImpl* web_frame = WebLocalFrameImpl::FromFrame(local_frame); + if (CompositorAnimationHost* animation_host = + web_frame->LocalRootFrameWidget()->AnimationHost()) + animation_host->AddTimeline(*compositor_timeline); +} + +void ChromeClientImpl::DetachCompositorAnimationTimeline( + CompositorAnimationTimeline* compositor_timeline, + LocalFrame* local_frame) { + WebLocalFrameImpl* web_frame = WebLocalFrameImpl::FromFrame(local_frame); + + // This method can be called when the frame is being detached, after the + // widget is destroyed. + // TODO(dcheng): This should be called before the widget is gone... + if (web_frame->LocalRootFrameWidget()) { + if (CompositorAnimationHost* animation_host = + web_frame->LocalRootFrameWidget()->AnimationHost()) + animation_host->RemoveTimeline(*compositor_timeline); + } +} + +void ChromeClientImpl::EnterFullscreen(LocalFrame& frame) { + web_view_->EnterFullscreen(frame); +} + +void ChromeClientImpl::ExitFullscreen(LocalFrame& frame) { + web_view_->ExitFullscreen(frame); +} + +void ChromeClientImpl::FullscreenElementChanged(Element* old_element, + Element* new_element) { + web_view_->FullscreenElementChanged(old_element, new_element); +} + +void ChromeClientImpl::ClearCompositedSelection(LocalFrame* frame) { + WebFrameWidgetBase* widget = + WebLocalFrameImpl::FromFrame(frame)->LocalRootFrameWidget(); + WebWidgetClient* client = widget->Client(); + // TODO(dcheng): This shouldn't be called on detached frames? + if (!client) + return; + + if (WebLayerTreeView* layer_tree_view = widget->GetLayerTreeView()) + layer_tree_view->ClearSelection(); +} + +void ChromeClientImpl::UpdateCompositedSelection( + LocalFrame* frame, + const CompositedSelection& selection) { + WebFrameWidgetBase* widget = + WebLocalFrameImpl::FromFrame(frame)->LocalRootFrameWidget(); + WebWidgetClient* client = widget->Client(); + // TODO(dcheng): This shouldn't be called on detached frames? + if (!client) + return; + + if (WebLayerTreeView* layer_tree_view = widget->GetLayerTreeView()) + layer_tree_view->RegisterSelection(WebSelection(selection)); +} + +bool ChromeClientImpl::HasOpenedPopup() const { + return web_view_->HasOpenedPopup(); +} + +PopupMenu* ChromeClientImpl::OpenPopupMenu(LocalFrame& frame, + HTMLSelectElement& select) { + NotifyPopupOpeningObservers(); + if (WebViewImpl::UseExternalPopupMenus()) + return new ExternalPopupMenu(frame, select, *web_view_); + + DCHECK(RuntimeEnabledFeatures::PagePopupEnabled()); + return InternalPopupMenu::Create(this, select); +} + +PagePopup* ChromeClientImpl::OpenPagePopup(PagePopupClient* client) { + return web_view_->OpenPagePopup(client); +} + +void ChromeClientImpl::ClosePagePopup(PagePopup* popup) { + web_view_->ClosePagePopup(popup); +} + +DOMWindow* ChromeClientImpl::PagePopupWindowForTesting() const { + return web_view_->PagePopupWindow(); +} + +void ChromeClientImpl::SetBrowserControlsState(float top_height, + float bottom_height, + bool shrinks_layout) { + WebSize size = web_view_->Size(); + if (shrinks_layout) + size.height -= top_height + bottom_height; + + web_view_->ResizeWithBrowserControls(size, top_height, bottom_height, + shrinks_layout); +} + +void ChromeClientImpl::SetBrowserControlsShownRatio(float ratio) { + web_view_->GetBrowserControls().SetShownRatio(ratio); + web_view_->DidUpdateBrowserControls(); +} + +bool ChromeClientImpl::ShouldOpenModalDialogDuringPageDismissal( + LocalFrame& frame, + DialogType dialog_type, + const String& dialog_message, + Document::PageDismissalType dismissal_type) const { + String message = String("Blocked ") + DialogTypeToString(dialog_type) + "('" + + dialog_message + "') during " + + DismissalTypeToString(dismissal_type) + "."; + WebLocalFrameImpl::FromFrame(frame)->AddMessageToConsole( + WebConsoleMessage(WebConsoleMessage::kLevelError, message)); + + return false; +} + +WebLayerTreeView* ChromeClientImpl::GetWebLayerTreeView(LocalFrame* frame) { + WebLocalFrameImpl* web_frame = WebLocalFrameImpl::FromFrame(frame); + if (WebFrameWidgetBase* frame_widget = web_frame->LocalRootFrameWidget()) + return frame_widget->GetLayerTreeView(); + return nullptr; +} + +void ChromeClientImpl::RequestDecode(LocalFrame* frame, + const PaintImage& image, + base::OnceCallback<void(bool)> callback) { + WebLocalFrameImpl* web_frame = WebLocalFrameImpl::FromFrame(frame); + web_frame->LocalRootFrameWidget()->RequestDecode(image, std::move(callback)); +} + +void ChromeClientImpl::SetEventListenerProperties( + LocalFrame* frame, + WebEventListenerClass event_class, + WebEventListenerProperties properties) { + // |frame| might be null if called via TreeScopeAdopter:: + // moveNodeToNewDocument() and the new document has no frame attached. + // Since a document without a frame cannot attach one later, it is safe to + // exit early. + if (!frame) + return; + + WebLocalFrameImpl* web_frame = WebLocalFrameImpl::FromFrame(frame); + // The widget may be nullptr if the frame is provisional. + // TODO(dcheng): This needs to be cleaned up at some point. + // https://crbug.com/578349 + if (web_frame->IsProvisional()) { + // If we hit a provisional frame, we expect it to be during initialization + // in which case the |properties| should be 'nothing'. + DCHECK(properties == WebEventListenerProperties::kNothing); + return; + } + WebFrameWidgetBase* widget = web_frame->LocalRootFrameWidget(); + // TODO(https://crbug.com/820787): When creating a local root, the widget + // won't be set yet. While notifications in this case are technically + // redundant, it adds an awkward special case. + if (!widget) { + return; + } + + // This relies on widget always pointing to a WebFrameWidgetBase when + // |frame| points to an OOPIF frame, i.e. |frame|'s mainFrame() is + // remote. + WebWidgetClient* client = widget->Client(); + if (WebLayerTreeView* tree_view = widget->GetLayerTreeView()) { + tree_view->SetEventListenerProperties(event_class, properties); + if (event_class == WebEventListenerClass::kTouchStartOrMove) { + client->HasTouchEventHandlers( + properties != WebEventListenerProperties::kNothing || + tree_view->EventListenerProperties( + WebEventListenerClass::kTouchEndOrCancel) != + WebEventListenerProperties::kNothing); + } else if (event_class == WebEventListenerClass::kTouchEndOrCancel) { + client->HasTouchEventHandlers( + properties != WebEventListenerProperties::kNothing || + tree_view->EventListenerProperties( + WebEventListenerClass::kTouchStartOrMove) != + WebEventListenerProperties::kNothing); + } + } else { + client->HasTouchEventHandlers(true); + } +} + +void ChromeClientImpl::BeginLifecycleUpdates() { + if (WebLayerTreeView* tree_view = web_view_->LayerTreeView()) { + tree_view->SetDeferCommits(false); + tree_view->SetNeedsBeginFrame(); + } +} + +WebEventListenerProperties ChromeClientImpl::EventListenerProperties( + LocalFrame* frame, + WebEventListenerClass event_class) const { + if (!frame) + return WebEventListenerProperties::kNothing; + + WebFrameWidgetBase* widget = + WebLocalFrameImpl::FromFrame(frame)->LocalRootFrameWidget(); + + if (!widget || !widget->GetLayerTreeView()) + return WebEventListenerProperties::kNothing; + return widget->GetLayerTreeView()->EventListenerProperties(event_class); +} + +void ChromeClientImpl::SetHasScrollEventHandlers(LocalFrame* frame, + bool has_event_handlers) { + // |frame| might be null if called via TreeScopeAdopter:: + // moveNodeToNewDocument() and the new document has no frame attached. + // Since a document without a frame cannot attach one later, it is safe to + // exit early. + if (!frame) + return; + + WebFrameWidgetBase* widget = + WebLocalFrameImpl::FromFrame(frame)->LocalRootFrameWidget(); + // While a frame is shutting down, we may get called after the layerTreeView + // is gone: in this case we always expect |hasEventHandlers| to be false. + DCHECK(!widget || widget->GetLayerTreeView() || !has_event_handlers); + if (widget && widget->GetLayerTreeView()) + widget->GetLayerTreeView()->SetHaveScrollEventHandlers(has_event_handlers); +} + +void ChromeClientImpl::SetNeedsLowLatencyInput(LocalFrame* frame, + bool needs_low_latency) { + DCHECK(frame); + WebLocalFrameImpl* web_frame = WebLocalFrameImpl::FromFrame(frame); + WebFrameWidgetBase* widget = web_frame->LocalRootFrameWidget(); + if (!widget) + return; + + if (WebWidgetClient* client = widget->Client()) + client->SetNeedsLowLatencyInput(needs_low_latency); +} + +void ChromeClientImpl::RequestUnbufferedInputEvents(LocalFrame* frame) { + DCHECK(frame); + WebLocalFrameImpl* web_frame = WebLocalFrameImpl::FromFrame(frame); + WebFrameWidgetBase* widget = web_frame->LocalRootFrameWidget(); + if (!widget) + return; + + if (WebWidgetClient* client = widget->Client()) + client->RequestUnbufferedInputEvents(); +} + +void ChromeClientImpl::SetTouchAction(LocalFrame* frame, + TouchAction touch_action) { + DCHECK(frame); + WebLocalFrameImpl* web_frame = WebLocalFrameImpl::FromFrame(frame); + WebFrameWidgetBase* widget = web_frame->LocalRootFrameWidget(); + if (!widget) + return; + + if (WebWidgetClient* client = widget->Client()) + client->SetTouchAction(static_cast<TouchAction>(touch_action)); +} + +bool ChromeClientImpl::RequestPointerLock(LocalFrame* frame) { + return WebLocalFrameImpl::FromFrame(frame) + ->LocalRootFrameWidget() + ->Client() + ->RequestPointerLock(); +} + +void ChromeClientImpl::RequestPointerUnlock(LocalFrame* frame) { + return WebLocalFrameImpl::FromFrame(frame) + ->LocalRootFrameWidget() + ->Client() + ->RequestPointerUnlock(); +} + +void ChromeClientImpl::DidAssociateFormControlsAfterLoad(LocalFrame* frame) { + if (auto* fill_client = AutofillClientFromFrame(frame)) + fill_client->DidAssociateFormControlsDynamically(); +} + +void ChromeClientImpl::ShowVirtualKeyboardOnElementFocus(LocalFrame& frame) { + WebLocalFrameImpl::FromFrame(frame) + ->LocalRootFrameWidget() + ->Client() + ->ShowVirtualKeyboardOnElementFocus(); +} + +void ChromeClientImpl::OnMouseDown(Node& mouse_down_node) { + if (auto* fill_client = + AutofillClientFromFrame(mouse_down_node.GetDocument().GetFrame())) { + fill_client->DidReceiveLeftMouseDownOrGestureTapInNode( + WebNode(&mouse_down_node)); + } +} + +void ChromeClientImpl::HandleKeyboardEventOnTextField( + HTMLInputElement& input_element, + KeyboardEvent& event) { + if (auto* fill_client = + AutofillClientFromFrame(input_element.GetDocument().GetFrame())) { + fill_client->TextFieldDidReceiveKeyDown(WebInputElement(&input_element), + WebKeyboardEventBuilder(event)); + } +} + +void ChromeClientImpl::DidChangeValueInTextField( + HTMLFormControlElement& element) { + Document& doc = element.GetDocument(); + if (auto* fill_client = AutofillClientFromFrame(doc.GetFrame())) + fill_client->TextFieldDidChange(WebFormControlElement(&element)); + + // Value changes caused by |document.execCommand| calls should not be + // interpreted as a user action. See https://crbug.com/764760. + if (!doc.IsRunningExecCommand()) { + UseCounter::Count(doc, doc.IsSecureContext() + ? WebFeature::kFieldEditInSecureContext + : WebFeature::kFieldEditInNonSecureContext); + doc.MaybeQueueSendDidEditFieldInInsecureContext(); + web_view_->PageImportanceSignals()->SetHadFormInteraction(); + } +} + +void ChromeClientImpl::DidEndEditingOnTextField( + HTMLInputElement& input_element) { + if (auto* fill_client = + AutofillClientFromFrame(input_element.GetDocument().GetFrame())) { + fill_client->TextFieldDidEndEditing(WebInputElement(&input_element)); + } +} + +void ChromeClientImpl::OpenTextDataListChooser(HTMLInputElement& input) { + NotifyPopupOpeningObservers(); + if (auto* fill_client = + AutofillClientFromFrame(input.GetDocument().GetFrame())) { + fill_client->OpenTextDataListChooser(WebInputElement(&input)); + } +} + +void ChromeClientImpl::TextFieldDataListChanged(HTMLInputElement& input) { + if (auto* fill_client = + AutofillClientFromFrame(input.GetDocument().GetFrame())) { + fill_client->DataListOptionsChanged(WebInputElement(&input)); + } +} + +void ChromeClientImpl::DidChangeSelectionInSelectControl( + HTMLFormControlElement& element) { + Document& doc = element.GetDocument(); + if (auto* fill_client = AutofillClientFromFrame(doc.GetFrame())) + fill_client->SelectControlDidChange(WebFormControlElement(&element)); +} + +void ChromeClientImpl::SelectFieldOptionsChanged( + HTMLFormControlElement& element) { + Document& doc = element.GetDocument(); + if (auto* fill_client = AutofillClientFromFrame(doc.GetFrame())) + fill_client->SelectFieldOptionsChanged(WebFormControlElement(&element)); +} + +void ChromeClientImpl::AjaxSucceeded(LocalFrame* frame) { + if (auto* fill_client = AutofillClientFromFrame(frame)) + fill_client->AjaxSucceeded(); +} + +void ChromeClientImpl::RegisterViewportLayers() const { + if (web_view_->RootGraphicsLayer() && web_view_->LayerTreeView()) + web_view_->RegisterViewportLayersWithCompositor(); +} + +void ChromeClientImpl::DidUpdateBrowserControls() const { + web_view_->DidUpdateBrowserControls(); +} + +void ChromeClientImpl::SetOverscrollBehavior( + const WebOverscrollBehavior& overscroll_behavior) { + web_view_->SetOverscrollBehavior(overscroll_behavior); +} + +void ChromeClientImpl::RegisterPopupOpeningObserver( + PopupOpeningObserver* observer) { + DCHECK(observer); + popup_opening_observers_.push_back(observer); +} + +void ChromeClientImpl::UnregisterPopupOpeningObserver( + PopupOpeningObserver* observer) { + size_t index = popup_opening_observers_.Find(observer); + DCHECK_NE(index, kNotFound); + popup_opening_observers_.EraseAt(index); +} + +void ChromeClientImpl::NotifyPopupOpeningObservers() const { + const Vector<PopupOpeningObserver*> observers(popup_opening_observers_); + for (const auto& observer : observers) + observer->WillOpenPopup(); +} + +FloatSize ChromeClientImpl::ElasticOverscroll() const { + return web_view_->ElasticOverscroll(); +} + +WebAutofillClient* ChromeClientImpl::AutofillClientFromFrame( + LocalFrame* frame) { + if (!frame) { + // It is possible to pass nullptr to this method. For instance the call from + // OnMouseDown might be nullptr. See https://crbug.com/739199. + return nullptr; + } + + return WebLocalFrameImpl::FromFrame(frame)->AutofillClient(); +} + +} // namespace blink |