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/frame/web_frame_widget_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/frame/web_frame_widget_impl.cc')
-rw-r--r-- | chromium/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc | 1209 |
1 files changed, 1209 insertions, 0 deletions
diff --git a/chromium/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc b/chromium/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc new file mode 100644 index 00000000000..1ea89451aef --- /dev/null +++ b/chromium/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc @@ -0,0 +1,1209 @@ +/* + * Copyright (C) 2014 Google Inc. All rights reserved. + * + * 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/frame/web_frame_widget_impl.h" + +#include <memory> +#include <utility> + +#include "build/build_config.h" +#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-blink.h" +#include "third_party/blink/public/platform/web_scroll_into_view_params.h" +#include "third_party/blink/public/web/web_autofill_client.h" +#include "third_party/blink/public/web/web_element.h" +#include "third_party/blink/public/web/web_plugin.h" +#include "third_party/blink/public/web/web_range.h" +#include "third_party/blink/public/web/web_widget_client.h" +#include "third_party/blink/renderer/core/dom/user_gesture_indicator.h" +#include "third_party/blink/renderer/core/editing/editing_utilities.h" +#include "third_party/blink/renderer/core/editing/editor.h" +#include "third_party/blink/renderer/core/editing/ephemeral_range.h" +#include "third_party/blink/renderer/core/editing/frame_selection.h" +#include "third_party/blink/renderer/core/editing/ime/input_method_controller.h" +#include "third_party/blink/renderer/core/editing/plain_text_range.h" +#include "third_party/blink/renderer/core/editing/selection_template.h" +#include "third_party/blink/renderer/core/events/current_input_event.h" +#include "third_party/blink/renderer/core/events/web_input_event_conversion.h" +#include "third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h" +#include "third_party/blink/renderer/core/exported/web_page_popup_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_view_impl.h" +#include "third_party/blink/renderer/core/frame/local_frame.h" +#include "third_party/blink/renderer/core/frame/local_frame_view.h" +#include "third_party/blink/renderer/core/frame/remote_frame.h" +#include "third_party/blink/renderer/core/frame/settings.h" +#include "third_party/blink/renderer/core/frame/visual_viewport.h" +#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" +#include "third_party/blink/renderer/core/frame/web_view_frame_widget.h" +#include "third_party/blink/renderer/core/html/forms/html_text_area_element.h" +#include "third_party/blink/renderer/core/input/context_menu_allowed_scope.h" +#include "third_party/blink/renderer/core/input/event_handler.h" +#include "third_party/blink/renderer/core/layout/layout_view.h" +#include "third_party/blink/renderer/core/loader/document_loader.h" +#include "third_party/blink/renderer/core/page/context_menu_controller.h" +#include "third_party/blink/renderer/core/page/focus_controller.h" +#include "third_party/blink/renderer/core/page/page.h" +#include "third_party/blink/renderer/core/page/page_popup.h" +#include "third_party/blink/renderer/core/page/pointer_lock_controller.h" +#include "third_party/blink/renderer/core/page/validation_message_client.h" +#include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h" +#include "third_party/blink/renderer/platform/animation/compositor_animation_host.h" +#include "third_party/blink/renderer/platform/graphics/color.h" +#include "third_party/blink/renderer/platform/graphics/compositor_mutator_client.h" +#include "third_party/blink/renderer/platform/graphics/compositor_mutator_impl.h" +#include "third_party/blink/renderer/platform/keyboard_codes.h" +#include "third_party/blink/renderer/platform/wtf/auto_reset.h" +#include "third_party/blink/renderer/platform/wtf/optional.h" + +namespace blink { +namespace { +const int kCaretPadding = 10; +const float kIdealPaddingRatio = 0.3f; + +// Returns a rect which is offset and scaled accordingly to |base_rect|'s +// location and size. +FloatRect NormalizeRect(const FloatRect& to_normalize, + const FloatRect& base_rect) { + FloatRect result(to_normalize); + result.SetLocation(to_normalize.Location() + (-base_rect.Location())); + result.Scale(1.0 / base_rect.Width(), 1.0 / base_rect.Height()); + return result; +} + +} // namespace + +// WebFrameWidget ------------------------------------------------------------ + +WebFrameWidget* WebFrameWidget::Create(WebWidgetClient* client, + WebLocalFrame* local_root) { + DCHECK(client) << "A valid WebWidgetClient must be supplied."; + if (!local_root->Parent()) { + // Note: this isn't a leak, as the object has a self-reference that the + // caller needs to release by calling Close(). + WebLocalFrameImpl& main_frame = ToWebLocalFrameImpl(*local_root); + DCHECK(main_frame.ViewImpl()); + // Note: this can't DCHECK that the view's main frame points to + // |main_frame|, as provisional frames violate this precondition. + // TODO(dcheng): Remove the special bridge class for main frame widgets. + return new WebViewFrameWidget(*client, *main_frame.ViewImpl(), main_frame); + } + + DCHECK(local_root->Parent()->IsWebRemoteFrame()) + << "Only local roots can have web frame widgets."; + // Note: this isn't a leak, as the object has a self-reference that the + // caller needs to release by calling Close(). + return WebFrameWidgetImpl::Create(client, local_root); +} + +WebFrameWidgetImpl* WebFrameWidgetImpl::Create(WebWidgetClient* client, + WebLocalFrame* local_root) { + DCHECK(client) << "A valid WebWidgetClient must be supplied."; + // Pass the WebFrameWidgetImpl's self-reference to the caller. + return new WebFrameWidgetImpl( + client, local_root); // SelfKeepAlive is set in constructor. +} + +WebFrameWidgetImpl::WebFrameWidgetImpl(WebWidgetClient* client, + WebLocalFrame* local_root) + : client_(client), + local_root_(ToWebLocalFrameImpl(local_root)), + mutator_(nullptr), + layer_tree_view_(nullptr), + root_layer_(nullptr), + root_graphics_layer_(nullptr), + is_accelerated_compositing_active_(false), + layer_tree_view_closed_(false), + suppress_next_keypress_event_(false), + background_color_override_enabled_(false), + background_color_override_(Color::kTransparent), + base_background_color_override_enabled_(false), + base_background_color_override_(Color::kTransparent), + ime_accept_events_(true), + self_keep_alive_(this) { + DCHECK(local_root_->GetFrame()->IsLocalRoot()); + InitializeLayerTreeView(); + local_root_->SetFrameWidget(this); + + if (local_root->Parent()) + SetBackgroundColorOverride(Color::kTransparent); +} + +WebFrameWidgetImpl::~WebFrameWidgetImpl() = default; + +void WebFrameWidgetImpl::Trace(blink::Visitor* visitor) { + visitor->Trace(local_root_); + visitor->Trace(mouse_capture_node_); + WebFrameWidgetBase::Trace(visitor); +} + +// WebWidget ------------------------------------------------------------------ + +void WebFrameWidgetImpl::Close() { + local_root_->SetFrameWidget(nullptr); + local_root_ = nullptr; + // Reset the delegate to prevent notifications being sent as we're being + // deleted. + client_ = nullptr; + + mutator_ = nullptr; + layer_tree_view_ = nullptr; + root_layer_ = nullptr; + root_graphics_layer_ = nullptr; + animation_host_ = nullptr; + + self_keep_alive_.Clear(); +} + +WebSize WebFrameWidgetImpl::Size() { + return size_ ? *size_ : WebSize(); +} + +void WebFrameWidgetImpl::Resize(const WebSize& new_size) { + if (size_ && *size_ == new_size) + return; + + if (did_suspend_parsing_) { + did_suspend_parsing_ = false; + local_root_->GetFrame()->Loader().GetDocumentLoader()->ResumeParser(); + } + + LocalFrameView* view = local_root_->GetFrameView(); + if (!view) + return; + + size_ = new_size; + + UpdateMainFrameLayoutSize(); + + view->Resize(*size_); + + // FIXME: In WebViewImpl this layout was a precursor to setting the minimum + // scale limit. It is not clear if this is necessary for frame-level widget + // resize. + if (view->NeedsLayout()) + view->UpdateLayout(); + + // FIXME: Investigate whether this is needed; comment from eseidel suggests + // that this function is flawed. + SendResizeEventAndRepaint(); +} + +void WebFrameWidgetImpl::SendResizeEventAndRepaint() { + // FIXME: This is wrong. The LocalFrameView is responsible sending a + // resizeEvent as part of layout. Layout is also responsible for sending + // invalidations to the embedder. This method and all callers may be wrong. -- + // eseidel. + if (local_root_->GetFrameView()) { + // Enqueues the resize event. + local_root_->GetFrame()->GetDocument()->EnqueueResizeEvent(); + } + + DCHECK(client_); + if (IsAcceleratedCompositingActive()) { + UpdateLayerTreeViewport(); + } else { + WebRect damaged_rect(0, 0, size_->width, size_->height); + client_->DidInvalidateRect(damaged_rect); + } +} + +void WebFrameWidgetImpl::ResizeVisualViewport(const WebSize& new_size) { + if (!local_root_) { + // We should figure out why we get here when there is no local root + // (https://crbug.com/792345). + return; + } + + // TODO(alexmos, kenrb): resizing behavior such as this should be changed + // to use Page messages. This uses the visual viewport size to set size on + // both the WebViewImpl size and the Page's VisualViewport. If there are + // multiple OOPIFs on a page, this will currently be set redundantly by + // each of them. See https://crbug.com/599688. + View()->Resize(new_size); + + View()->DidUpdateFullscreenSize(); +} + +void WebFrameWidgetImpl::UpdateMainFrameLayoutSize() { + if (!local_root_) + return; + + LocalFrameView* view = local_root_->GetFrameView(); + if (!view) + return; + + WebSize layout_size = *size_; + + view->SetLayoutSize(layout_size); +} + +void WebFrameWidgetImpl::DidEnterFullscreen() { + View()->DidEnterFullscreen(); +} + +void WebFrameWidgetImpl::DidExitFullscreen() { + View()->DidExitFullscreen(); +} + +void WebFrameWidgetImpl::SetSuppressFrameRequestsWorkaroundFor704763Only( + bool suppress_frame_requests) { + GetPage()->Animator().SetSuppressFrameRequestsWorkaroundFor704763Only( + suppress_frame_requests); +} +void WebFrameWidgetImpl::BeginFrame(double last_frame_time_monotonic) { + TRACE_EVENT1("blink", "WebFrameWidgetImpl::beginFrame", "frameTime", + last_frame_time_monotonic); + DCHECK(last_frame_time_monotonic); + + if (!local_root_) + return; + + UpdateGestureAnimation(last_frame_time_monotonic); + + DocumentLifecycle::AllowThrottlingScope throttling_scope( + local_root_->GetFrame()->GetDocument()->Lifecycle()); + PageWidgetDelegate::Animate(*GetPage(), last_frame_time_monotonic); + // Animate can cause the local frame to detach. + if (local_root_) + GetPage()->GetValidationMessageClient().LayoutOverlay(); +} + +void WebFrameWidgetImpl::UpdateLifecycle(LifecycleUpdate requested_update) { + TRACE_EVENT0("blink", "WebFrameWidgetImpl::updateAllLifecyclePhases"); + if (!local_root_) + return; + + bool pre_paint_only = requested_update == LifecycleUpdate::kPrePaint; + + WebDevToolsAgentImpl* devtools = local_root_->DevToolsAgentImpl(); + if (devtools && !pre_paint_only) + devtools->PaintOverlay(); + + DocumentLifecycle::AllowThrottlingScope throttling_scope( + local_root_->GetFrame()->GetDocument()->Lifecycle()); + PageWidgetDelegate::UpdateLifecycle(*GetPage(), *local_root_->GetFrame(), + requested_update); + UpdateLayerTreeBackgroundColor(); +} + +void WebFrameWidgetImpl::UpdateAllLifecyclePhasesAndCompositeForTesting() { + if (layer_tree_view_) + layer_tree_view_->SynchronouslyCompositeNoRasterForTesting(); +} + +void WebFrameWidgetImpl::Paint(WebCanvas* canvas, const WebRect& rect) { + // Out-of-process iframes require compositing. + NOTREACHED(); +} + +void WebFrameWidgetImpl::UpdateLayerTreeViewport() { + if (!GetPage() || !layer_tree_view_) + return; + + // Pass the limits even though this is for subframes, as the limits will be + // needed in setting the raster scale. + layer_tree_view_->SetPageScaleFactorAndLimits( + 1, View()->MinimumPageScaleFactor(), View()->MaximumPageScaleFactor()); +} + +void WebFrameWidgetImpl::UpdateLayerTreeBackgroundColor() { + if (!layer_tree_view_) + return; + + WebColor color = BackgroundColor(); + layer_tree_view_->SetBackgroundColor(color); +} + +void WebFrameWidgetImpl::SetBackgroundColorOverride(WebColor color) { + background_color_override_enabled_ = true; + background_color_override_ = color; + UpdateLayerTreeBackgroundColor(); +} + +void WebFrameWidgetImpl::ClearBackgroundColorOverride() { + background_color_override_enabled_ = false; + UpdateLayerTreeBackgroundColor(); +} + +void WebFrameWidgetImpl::SetBaseBackgroundColorOverride(WebColor color) { + if (base_background_color_override_enabled_ && + base_background_color_override_ == color) { + return; + } + + base_background_color_override_enabled_ = true; + base_background_color_override_ = color; + // Force lifecycle update to ensure we're good to call + // LocalFrameView::setBaseBackgroundColor(). + local_root_->GetFrameView()->UpdateLifecycleToCompositingCleanPlusScrolling(); + UpdateBaseBackgroundColor(); +} + +void WebFrameWidgetImpl::ClearBaseBackgroundColorOverride() { + if (!base_background_color_override_enabled_) + return; + + base_background_color_override_enabled_ = false; + // Force lifecycle update to ensure we're good to call + // LocalFrameView::setBaseBackgroundColor(). + local_root_->GetFrameView()->UpdateLifecycleToCompositingCleanPlusScrolling(); + UpdateBaseBackgroundColor(); +} + +void WebFrameWidgetImpl::LayoutAndPaintAsync( + WebLayoutAndPaintAsyncCallback* callback) { + layer_tree_view_->LayoutAndPaintAsync(callback); +} + +void WebFrameWidgetImpl::CompositeAndReadbackAsync( + WebCompositeAndReadbackAsyncCallback* callback) { + layer_tree_view_->CompositeAndReadbackAsync(callback); +} + +void WebFrameWidgetImpl::ThemeChanged() { + LocalFrameView* view = local_root_->GetFrameView(); + + WebRect damaged_rect(0, 0, size_->width, size_->height); + view->InvalidateRect(damaged_rect); +} + +WebHitTestResult WebFrameWidgetImpl::HitTestResultAt(const WebPoint& point) { + return CoreHitTestResultAt(point); +} + +WebInputEventResult WebFrameWidgetImpl::DispatchBufferedTouchEvents() { + if (doing_drag_and_drop_) + return WebInputEventResult::kHandledSuppressed; + + if (!GetPage()) + return WebInputEventResult::kNotHandled; + + if (local_root_) { + if (WebDevToolsAgentImpl* devtools = local_root_->DevToolsAgentImpl()) + devtools->DispatchBufferedTouchEvents(); + } + if (IgnoreInputEvents()) + return WebInputEventResult::kNotHandled; + + return local_root_->GetFrame() + ->GetEventHandler() + .DispatchBufferedTouchEvents(); +} + +WebInputEventResult WebFrameWidgetImpl::HandleInputEvent( + const WebCoalescedInputEvent& coalesced_event) { + const WebInputEvent& input_event = coalesced_event.Event(); + TRACE_EVENT1("input", "WebFrameWidgetImpl::handleInputEvent", "type", + WebInputEvent::GetName(input_event.GetType())); + DCHECK(!WebInputEvent::IsTouchEventType(input_event.GetType())); + + // If a drag-and-drop operation is in progress, ignore input events. + if (doing_drag_and_drop_) + return WebInputEventResult::kHandledSuppressed; + + // Don't handle events once we've started shutting down. + if (!GetPage()) + return WebInputEventResult::kNotHandled; + + if (local_root_) { + if (WebDevToolsAgentImpl* devtools = local_root_->DevToolsAgentImpl()) { + if (devtools->HandleInputEvent(input_event)) + return WebInputEventResult::kHandledSuppressed; + } + } + + // Report the event to be NOT processed by WebKit, so that the browser can + // handle it appropriately. + if (IgnoreInputEvents()) + return WebInputEventResult::kNotHandled; + + // FIXME: pass event to m_localRoot's WebDevToolsAgentImpl once available. + + AutoReset<const WebInputEvent*> current_event_change( + &CurrentInputEvent::current_input_event_, &input_event); + + DCHECK(client_); + if (client_->IsPointerLocked() && + WebInputEvent::IsMouseEventType(input_event.GetType())) { + PointerLockMouseEvent(coalesced_event); + return WebInputEventResult::kHandledSystem; + } + + if (mouse_capture_node_ && + WebInputEvent::IsMouseEventType(input_event.GetType())) { + TRACE_EVENT1("input", "captured mouse event", "type", + input_event.GetType()); + // Save m_mouseCaptureNode since mouseCaptureLost() will clear it. + Node* node = mouse_capture_node_; + + // Not all platforms call mouseCaptureLost() directly. + if (input_event.GetType() == WebInputEvent::kMouseUp) + MouseCaptureLost(); + + std::unique_ptr<UserGestureIndicator> gesture_indicator; + + AtomicString event_type; + switch (input_event.GetType()) { + case WebInputEvent::kMouseEnter: + event_type = EventTypeNames::mouseover; + break; + case WebInputEvent::kMouseMove: + event_type = EventTypeNames::mousemove; + break; + case WebInputEvent::kMouseLeave: + event_type = EventTypeNames::mouseout; + break; + case WebInputEvent::kMouseDown: + event_type = EventTypeNames::mousedown; + gesture_indicator = Frame::NotifyUserActivation( + node->GetDocument().GetFrame(), UserGestureToken::kNewGesture); + mouse_capture_gesture_token_ = gesture_indicator->CurrentToken(); + break; + case WebInputEvent::kMouseUp: + event_type = EventTypeNames::mouseup; + gesture_indicator = std::make_unique<UserGestureIndicator>( + std::move(mouse_capture_gesture_token_)); + break; + default: + NOTREACHED(); + } + + WebMouseEvent transformed_event = + TransformWebMouseEvent(local_root_->GetFrameView(), + static_cast<const WebMouseEvent&>(input_event)); + node->DispatchMouseEvent(transformed_event, event_type, + transformed_event.click_count); + return WebInputEventResult::kHandledSystem; + } + + return PageWidgetDelegate::HandleInputEvent(*this, coalesced_event, + local_root_->GetFrame()); +} + +void WebFrameWidgetImpl::SetCursorVisibilityState(bool is_visible) { + GetPage()->SetIsCursorVisible(is_visible); +} + +Color WebFrameWidgetImpl::BaseBackgroundColor() const { + return base_background_color_override_enabled_ + ? base_background_color_override_ + : base_background_color_; +} + +void WebFrameWidgetImpl::SetBaseBackgroundColor(WebColor color) { + if (base_background_color_ == color) + return; + + base_background_color_ = color; + UpdateBaseBackgroundColor(); +} + +void WebFrameWidgetImpl::UpdateBaseBackgroundColor() { + local_root_->GetFrameView()->SetBaseBackgroundColor(BaseBackgroundColor()); +} + +WebInputMethodController* +WebFrameWidgetImpl::GetActiveWebInputMethodController() const { + WebLocalFrameImpl* local_frame = + WebLocalFrameImpl::FromFrame(FocusedLocalFrameInWidget()); + return local_frame ? local_frame->GetInputMethodController() : nullptr; +} + +bool WebFrameWidgetImpl::ScrollFocusedEditableElementIntoView() { + Element* element = FocusedElement(); + if (!element || !WebElement(element).IsEditable()) + return false; + + if (!element->GetLayoutObject()) + return false; + + LayoutRect rect_to_scroll; + WebScrollIntoViewParams params; + GetScrollParamsForFocusedEditableElement(*element, rect_to_scroll, params); + element->GetLayoutObject()->ScrollRectToVisible(rect_to_scroll, params); + return true; +} + +void WebFrameWidgetImpl::ScheduleAnimation() { + if (layer_tree_view_) { + layer_tree_view_->SetNeedsBeginFrame(); + return; + } + DCHECK(client_); + client_->ScheduleAnimation(); +} + +void WebFrameWidgetImpl::IntrinsicSizingInfoChanged( + const IntrinsicSizingInfo& sizing_info) { + WebIntrinsicSizingInfo web_sizing_info; + web_sizing_info.size = sizing_info.size; + web_sizing_info.aspect_ratio = sizing_info.aspect_ratio; + web_sizing_info.has_width = sizing_info.has_width; + web_sizing_info.has_height = sizing_info.has_height; + client_->IntrinsicSizingInfoChanged(web_sizing_info); +} + +base::WeakPtr<CompositorMutatorImpl> +WebFrameWidgetImpl::EnsureCompositorMutator( + scoped_refptr<base::SingleThreadTaskRunner>* mutator_task_runner) { + if (!mutator_task_runner_) { + layer_tree_view_->SetMutatorClient( + CompositorMutatorImpl::CreateClient(&mutator_, &mutator_task_runner_)); + } + + DCHECK(mutator_task_runner_); + *mutator_task_runner = mutator_task_runner_; + return mutator_; +} + +void WebFrameWidgetImpl::ApplyViewportDeltas( + const WebFloatSize& visual_viewport_delta, + const WebFloatSize& main_frame_delta, + const WebFloatSize& elastic_overscroll_delta, + float page_scale_delta, + float browser_controls_delta) { + // FIXME: To be implemented. +} + +void WebFrameWidgetImpl::MouseCaptureLost() { + TRACE_EVENT_ASYNC_END0("input", "capturing mouse", this); + mouse_capture_node_ = nullptr; +} + +void WebFrameWidgetImpl::SetFocus(bool enable) { + if (enable) + GetPage()->GetFocusController().SetActive(true); + GetPage()->GetFocusController().SetFocused(enable); + if (enable) { + LocalFrame* focused_frame = GetPage()->GetFocusController().FocusedFrame(); + if (focused_frame) { + Element* element = focused_frame->GetDocument()->FocusedElement(); + if (element && focused_frame->Selection() + .ComputeVisibleSelectionInDOMTreeDeprecated() + .IsNone()) { + // If the selection was cleared while the WebView was not + // focused, then the focus element shows with a focus ring but + // no caret and does respond to keyboard inputs. + focused_frame->GetDocument()->UpdateStyleAndLayoutTree(); + if (element->IsTextControl()) { + element->UpdateFocusAppearance(SelectionBehaviorOnFocus::kRestore); + } else if (HasEditableStyle(*element)) { + // updateFocusAppearance() selects all the text of + // contentseditable DIVs. So we set the selection explicitly + // instead. Note that this has the side effect of moving the + // caret back to the beginning of the text. + Position position(element, 0); + focused_frame->Selection().SetSelectionAndEndTyping( + SelectionInDOMTree::Builder().Collapse(position).Build()); + } + } + } + ime_accept_events_ = true; + } else { + LocalFrame* focused_frame = FocusedLocalFrameInWidget(); + if (focused_frame) { + // Finish an ongoing composition to delete the composition node. + if (focused_frame->GetInputMethodController().HasComposition()) { + // TODO(editing-dev): The use of + // updateStyleAndLayoutIgnorePendingStylesheets needs to be audited. + // See http://crbug.com/590369 for more details. + focused_frame->GetDocument() + ->UpdateStyleAndLayoutIgnorePendingStylesheets(); + + focused_frame->GetInputMethodController().FinishComposingText( + InputMethodController::kKeepSelection); + } + ime_accept_events_ = false; + } + } +} + +WebColor WebFrameWidgetImpl::BackgroundColor() const { + if (background_color_override_enabled_) + return background_color_override_; + if (!local_root_->GetFrameView()) + return base_background_color_; + LocalFrameView* view = local_root_->GetFrameView(); + return view->DocumentBackgroundColor().Rgb(); +} + +bool WebFrameWidgetImpl::SelectionBounds(WebRect& anchor_web, + WebRect& focus_web) const { + const LocalFrame* local_frame = FocusedLocalFrameInWidget(); + if (!local_frame) + return false; + + IntRect anchor; + IntRect focus; + if (!local_frame->Selection().ComputeAbsoluteBounds(anchor, focus)) + return false; + + // FIXME: This doesn't apply page scale. This should probably be contents to + // viewport. crbug.com/459293. + anchor_web = local_frame->View()->ContentsToRootFrame(anchor); + focus_web = local_frame->View()->ContentsToRootFrame(focus); + return true; +} + +bool WebFrameWidgetImpl::IsAcceleratedCompositingActive() const { + return is_accelerated_compositing_active_; +} + +void WebFrameWidgetImpl::WillCloseLayerTreeView() { + if (layer_tree_view_) { + GetPage()->WillCloseLayerTreeView(*layer_tree_view_, + local_root_->GetFrame()->View()); + } + + SetIsAcceleratedCompositingActive(false); + mutator_ = nullptr; + layer_tree_view_ = nullptr; + animation_host_ = nullptr; + layer_tree_view_closed_ = true; +} + +void WebFrameWidgetImpl::SetRemoteViewportIntersection( + const WebRect& viewport_intersection) { + // Remote viewports are only applicable to local frames with remote ancestors. + DCHECK(local_root_->Parent() && local_root_->Parent()->IsWebRemoteFrame() && + local_root_->GetFrame()); + + local_root_->GetFrame()->SetViewportIntersectionFromParent( + viewport_intersection); +} + +void WebFrameWidgetImpl::SetIsInert(bool inert) { + DCHECK(local_root_->Parent()); + DCHECK(local_root_->Parent()->IsWebRemoteFrame()); + local_root_->GetFrame()->SetIsInert(inert); +} + +void WebFrameWidgetImpl::UpdateRenderThrottlingStatus(bool is_throttled, + bool subtree_throttled) { + DCHECK(local_root_->Parent()); + DCHECK(local_root_->Parent()->IsWebRemoteFrame()); + local_root_->GetFrameView()->UpdateRenderThrottlingStatus(is_throttled, + subtree_throttled); +} + +void WebFrameWidgetImpl::HandleMouseLeave(LocalFrame& main_frame, + const WebMouseEvent& event) { + // FIXME: WebWidget doesn't have the method below. + // m_client->setMouseOverURL(WebURL()); + PageWidgetEventHandler::HandleMouseLeave(main_frame, event); +} + +void WebFrameWidgetImpl::HandleMouseDown(LocalFrame& main_frame, + const WebMouseEvent& event) { + WebViewImpl* view_impl = View(); + // If there is a popup open, close it as the user is clicking on the page + // (outside of the popup). We also save it so we can prevent a click on an + // element from immediately reopening the same popup. + scoped_refptr<WebPagePopupImpl> page_popup; + if (event.button == WebMouseEvent::Button::kLeft) { + page_popup = view_impl->GetPagePopup(); + view_impl->HidePopups(); + } + + // Take capture on a mouse down on a plugin so we can send it mouse events. + // If the hit node is a plugin but a scrollbar is over it don't start mouse + // capture because it will interfere with the scrollbar receiving events. + LayoutPoint point(event.PositionInWidget().x, event.PositionInWidget().y); + if (event.button == WebMouseEvent::Button::kLeft) { + point = local_root_->GetFrameView()->RootFrameToContents(point); + HitTestResult result( + local_root_->GetFrame()->GetEventHandler().HitTestResultAtPoint(point)); + result.SetToShadowHostIfInRestrictedShadowRoot(); + Node* hit_node = result.InnerNode(); + + if (!result.GetScrollbar() && hit_node && hit_node->GetLayoutObject() && + hit_node->GetLayoutObject()->IsEmbeddedObject()) { + mouse_capture_node_ = hit_node; + TRACE_EVENT_ASYNC_BEGIN0("input", "capturing mouse", this); + } + } + + PageWidgetEventHandler::HandleMouseDown(main_frame, event); + + if (event.button == WebMouseEvent::Button::kLeft && mouse_capture_node_) { + mouse_capture_gesture_token_ = + main_frame.GetEventHandler().TakeLastMouseDownGestureToken(); + } + + if (view_impl->GetPagePopup() && page_popup && + view_impl->GetPagePopup()->HasSamePopupClient(page_popup.get())) { + // That click triggered a page popup that is the same as the one we just + // closed. It needs to be closed. + view_impl->HidePopups(); + } + + // Dispatch the contextmenu event regardless of if the click was swallowed. + if (!GetPage()->GetSettings().GetShowContextMenuOnMouseUp()) { +#if defined(OS_MACOSX) + if (event.button == WebMouseEvent::Button::kRight || + (event.button == WebMouseEvent::Button::kLeft && + event.GetModifiers() & WebMouseEvent::kControlKey)) + MouseContextMenu(event); +#else + if (event.button == WebMouseEvent::Button::kRight) + MouseContextMenu(event); +#endif + } +} + +void WebFrameWidgetImpl::MouseContextMenu(const WebMouseEvent& event) { + GetPage()->GetContextMenuController().ClearContextMenu(); + + WebMouseEvent transformed_event = + TransformWebMouseEvent(local_root_->GetFrameView(), event); + transformed_event.menu_source_type = kMenuSourceMouse; + IntPoint position_in_root_frame = + FlooredIntPoint(transformed_event.PositionInRootFrame()); + + // Find the right target frame. See issue 1186900. + HitTestResult result = HitTestResultForRootFramePos(position_in_root_frame); + Frame* target_frame; + if (result.InnerNodeOrImageMapImage()) + target_frame = result.InnerNodeOrImageMapImage()->GetDocument().GetFrame(); + else + target_frame = GetPage()->GetFocusController().FocusedOrMainFrame(); + + // This will need to be changed to a nullptr check when focus control + // is refactored, at which point focusedOrMainFrame will never return a + // RemoteFrame. + // See https://crbug.com/341918. + if (!target_frame->IsLocalFrame()) + return; + + LocalFrame* target_local_frame = ToLocalFrame(target_frame); + + { + ContextMenuAllowedScope scope; + target_local_frame->GetEventHandler().SendContextMenuEvent( + transformed_event, nullptr); + } + // Actually showing the context menu is handled by the ContextMenuClient + // implementation... +} + +void WebFrameWidgetImpl::HandleMouseUp(LocalFrame& main_frame, + const WebMouseEvent& event) { + PageWidgetEventHandler::HandleMouseUp(main_frame, event); + + if (GetPage()->GetSettings().GetShowContextMenuOnMouseUp()) { + // Dispatch the contextmenu event regardless of if the click was swallowed. + // On Mac/Linux, we handle it on mouse down, not up. + if (event.button == WebMouseEvent::Button::kRight) + MouseContextMenu(event); + } +} + +WebInputEventResult WebFrameWidgetImpl::HandleMouseWheel( + LocalFrame& frame, + const WebMouseWheelEvent& event) { + // Halt an in-progress fling on a wheel tick. + if (!event.has_precise_scrolling_deltas) + EndActiveFlingAnimation(); + + View()->HidePopups(); + return PageWidgetEventHandler::HandleMouseWheel(frame, event); +} + +WebInputEventResult WebFrameWidgetImpl::HandleGestureEvent( + const WebGestureEvent& event) { + DCHECK(client_); + WebInputEventResult event_result = WebInputEventResult::kNotHandled; + bool event_cancelled = false; + WTF::Optional<ContextMenuAllowedScope> maybe_context_menu_scope; + + WebViewImpl* view_impl = View(); + switch (event.GetType()) { + case WebInputEvent::kGestureScrollBegin: + case WebInputEvent::kGestureScrollEnd: + case WebInputEvent::kGestureScrollUpdate: + case WebInputEvent::kGestureTap: + case WebInputEvent::kGestureTapUnconfirmed: + case WebInputEvent::kGestureTapDown: + // Touch pinch zoom and scroll on the page (outside of a popup) must hide + // the popup. In case of a touch scroll or pinch zoom, this function is + // called with GestureTapDown rather than a GSB/GSU/GSE or GPB/GPU/GPE. + // When we close a popup because of a GestureTapDown, we also save it so + // we can prevent the following GestureTap from immediately reopening the + // same popup. + view_impl->SetLastHiddenPagePopup(view_impl->GetPagePopup()); + View()->HidePopups(); + FALLTHROUGH; + case WebInputEvent::kGestureTapCancel: + View()->SetLastHiddenPagePopup(nullptr); + break; + case WebInputEvent::kGestureShowPress: + case WebInputEvent::kGestureDoubleTap: + break; + case WebInputEvent::kGestureTwoFingerTap: + case WebInputEvent::kGestureLongPress: + case WebInputEvent::kGestureLongTap: + GetPage()->GetContextMenuController().ClearContextMenu(); + maybe_context_menu_scope.emplace(); + break; + case WebInputEvent::kGestureFlingStart: + case WebInputEvent::kGestureFlingCancel: + event_result = HandleGestureFlingEvent(event); + client_->DidHandleGestureEvent(event, event_cancelled); + return event_result; + default: + NOTREACHED(); + } + LocalFrame* frame = local_root_->GetFrame(); + WebGestureEvent scaled_event = TransformWebGestureEvent(frame->View(), event); + event_result = frame->GetEventHandler().HandleGestureEvent(scaled_event); + client_->DidHandleGestureEvent(event, event_cancelled); + return event_result; +} + +PageWidgetEventHandler* WebFrameWidgetImpl::GetPageWidgetEventHandler() { + return this; +} + +WebInputEventResult WebFrameWidgetImpl::HandleKeyEvent( + const WebKeyboardEvent& event) { + DCHECK((event.GetType() == WebInputEvent::kRawKeyDown) || + (event.GetType() == WebInputEvent::kKeyDown) || + (event.GetType() == WebInputEvent::kKeyUp)); + + // Please refer to the comments explaining the m_suppressNextKeypressEvent + // member. + // The m_suppressNextKeypressEvent is set if the KeyDown is handled by + // Webkit. A keyDown event is typically associated with a keyPress(char) + // event and a keyUp event. We reset this flag here as this is a new keyDown + // event. + suppress_next_keypress_event_ = false; + + Frame* focused_frame = FocusedCoreFrame(); + if (!focused_frame || !focused_frame->IsLocalFrame()) + return WebInputEventResult::kNotHandled; + + LocalFrame* frame = ToLocalFrame(focused_frame); + + WebInputEventResult result = frame->GetEventHandler().KeyEvent(event); + if (result != WebInputEventResult::kNotHandled) { + if (WebInputEvent::kRawKeyDown == event.GetType()) { + // Suppress the next keypress event unless the focused node is a plugin + // node. (Flash needs these keypress events to handle non-US keyboards.) + Element* element = FocusedElement(); + if (!element || !element->GetLayoutObject() || + !element->GetLayoutObject()->IsEmbeddedObject()) + suppress_next_keypress_event_ = true; + } + return result; + } + +#if !defined(OS_MACOSX) + const WebInputEvent::Type kContextMenuKeyTriggeringEventType = +#if defined(OS_WIN) + WebInputEvent::kKeyUp; +#else + WebInputEvent::kRawKeyDown; +#endif + const WebInputEvent::Type kShiftF10TriggeringEventType = + WebInputEvent::kRawKeyDown; + + bool is_unmodified_menu_key = + !(event.GetModifiers() & WebInputEvent::kInputModifiers) && + event.windows_key_code == VKEY_APPS; + bool is_shift_f10 = (event.GetModifiers() & WebInputEvent::kInputModifiers) == + WebInputEvent::kShiftKey && + event.windows_key_code == VKEY_F10; + if ((is_unmodified_menu_key && + event.GetType() == kContextMenuKeyTriggeringEventType) || + (is_shift_f10 && event.GetType() == kShiftF10TriggeringEventType)) { + View()->SendContextMenuEvent(); + return WebInputEventResult::kHandledSystem; + } +#endif // !defined(OS_MACOSX) + + return WebInputEventResult::kNotHandled; +} + +WebInputEventResult WebFrameWidgetImpl::HandleCharEvent( + const WebKeyboardEvent& event) { + DCHECK_EQ(event.GetType(), WebInputEvent::kChar); + + // Please refer to the comments explaining the m_suppressNextKeypressEvent + // member. The m_suppressNextKeypressEvent is set if the KeyDown is + // handled by Webkit. A keyDown event is typically associated with a + // keyPress(char) event and a keyUp event. We reset this flag here as it + // only applies to the current keyPress event. + bool suppress = suppress_next_keypress_event_; + suppress_next_keypress_event_ = false; + + LocalFrame* frame = ToLocalFrame(FocusedCoreFrame()); + if (!frame) { + return suppress ? WebInputEventResult::kHandledSuppressed + : WebInputEventResult::kNotHandled; + } + + EventHandler& handler = frame->GetEventHandler(); + + if (!event.IsCharacterKey()) + return WebInputEventResult::kHandledSuppressed; + + // Accesskeys are triggered by char events and can't be suppressed. + // It is unclear whether a keypress should be dispatched as well + // crbug.com/563507 + if (handler.HandleAccessKey(event)) + return WebInputEventResult::kHandledSystem; + + // Safari 3.1 does not pass off windows system key messages (WM_SYSCHAR) to + // the eventHandler::keyEvent. We mimic this behavior on all platforms since + // for now we are converting other platform's key events to windows key + // events. + if (event.is_system_key) + return WebInputEventResult::kNotHandled; + + if (suppress) + return WebInputEventResult::kHandledSuppressed; + + WebInputEventResult result = handler.KeyEvent(event); + if (result != WebInputEventResult::kNotHandled) + return result; + + return WebInputEventResult::kNotHandled; +} + +Frame* WebFrameWidgetImpl::FocusedCoreFrame() const { + return GetPage() ? GetPage()->GetFocusController().FocusedOrMainFrame() + : nullptr; +} + +Element* WebFrameWidgetImpl::FocusedElement() const { + LocalFrame* frame = GetPage()->GetFocusController().FocusedFrame(); + if (!frame) + return nullptr; + + Document* document = frame->GetDocument(); + if (!document) + return nullptr; + + return document->FocusedElement(); +} + +void WebFrameWidgetImpl::InitializeLayerTreeView() { + DCHECK(client_); + DCHECK(!mutator_); + layer_tree_view_ = client_->InitializeLayerTreeView(); + if (layer_tree_view_ && layer_tree_view_->CompositorAnimationHost()) { + animation_host_ = std::make_unique<CompositorAnimationHost>( + layer_tree_view_->CompositorAnimationHost()); + } + + GetPage()->GetSettings().SetAcceleratedCompositingEnabled(layer_tree_view_); + if (layer_tree_view_) { + GetPage()->LayerTreeViewInitialized(*layer_tree_view_, + local_root_->GetFrame()->View()); + + // TODO(kenrb): Currently GPU rasterization is always enabled for OOPIFs. + // This is okay because it is only necessarily to set the trigger to false + // for certain cases that affect the top-level frame, but it would be better + // to be consistent with the top-level frame. Ideally the logic should + // be moved from WebViewImpl into WebFrameWidget and used for all local + // frame roots. https://crbug.com/712794 + layer_tree_view_->HeuristicsForGpuRasterizationUpdated(true); + } + + // FIXME: only unittests, click to play, Android priting, and printing (for + // headers and footers) make this assert necessary. We should make them not + // hit this code and then delete allowsBrokenNullLayerTreeView. + DCHECK(layer_tree_view_ || client_->AllowsBrokenNullLayerTreeView()); +} + +void WebFrameWidgetImpl::SetIsAcceleratedCompositingActive(bool active) { + // In the middle of shutting down; don't try to spin back up a compositor. + // FIXME: compositing startup/shutdown should be refactored so that it + // turns on explicitly rather than lazily, which causes this awkwardness. + if (layer_tree_view_closed_) + return; + + DCHECK(!active || layer_tree_view_); + + if (is_accelerated_compositing_active_ == active) + return; + + if (active) { + TRACE_EVENT0("blink", + "WebViewImpl::setIsAcceleratedCompositingActive(true)"); + layer_tree_view_->SetRootLayer(*root_layer_); + + layer_tree_view_->SetVisible(GetPage()->IsPageVisible()); + UpdateLayerTreeBackgroundColor(); + UpdateLayerTreeViewport(); + is_accelerated_compositing_active_ = true; + } +} + +PaintLayerCompositor* WebFrameWidgetImpl::Compositor() const { + LocalFrame* frame = local_root_->GetFrame(); + if (!frame || !frame->GetDocument() || !frame->GetDocument()->GetLayoutView()) + return nullptr; + + return frame->GetDocument()->GetLayoutView()->Compositor(); +} + +void WebFrameWidgetImpl::SetRootGraphicsLayer(GraphicsLayer* layer) { + root_graphics_layer_ = layer; + root_layer_ = layer ? layer->PlatformLayer() : nullptr; + + SetIsAcceleratedCompositingActive(layer); + + if (!layer_tree_view_) + return; + + if (root_layer_) + layer_tree_view_->SetRootLayer(*root_layer_); + else + layer_tree_view_->ClearRootLayer(); +} + +void WebFrameWidgetImpl::SetRootLayer(WebLayer* layer) { + root_layer_ = layer; + + SetIsAcceleratedCompositingActive(layer); + + if (!layer_tree_view_) + return; + + if (root_layer_) + layer_tree_view_->SetRootLayer(*root_layer_); + else + layer_tree_view_->ClearRootLayer(); +} + +WebLayerTreeView* WebFrameWidgetImpl::GetLayerTreeView() const { + return layer_tree_view_; +} + +CompositorAnimationHost* WebFrameWidgetImpl::AnimationHost() const { + return animation_host_.get(); +} + +HitTestResult WebFrameWidgetImpl::CoreHitTestResultAt( + const WebPoint& point_in_viewport) { + DocumentLifecycle::AllowThrottlingScope throttling_scope( + local_root_->GetFrame()->GetDocument()->Lifecycle()); + LocalFrameView* view = local_root_->GetFrameView(); + IntPoint point_in_root_frame = + view->ContentsToFrame(view->ViewportToContents(point_in_viewport)); + return HitTestResultForRootFramePos(point_in_root_frame); +} + +void WebFrameWidgetImpl::SetVisibilityState( + mojom::PageVisibilityState visibility_state) { + if (layer_tree_view_) { + layer_tree_view_->SetVisible(visibility_state == + mojom::PageVisibilityState::kVisible); + } +} + +HitTestResult WebFrameWidgetImpl::HitTestResultForRootFramePos( + const LayoutPoint& pos_in_root_frame) { + LayoutPoint doc_point( + local_root_->GetFrame()->View()->RootFrameToContents(pos_in_root_frame)); + HitTestResult result = + local_root_->GetFrame()->GetEventHandler().HitTestResultAtPoint( + doc_point, HitTestRequest::kReadOnly | HitTestRequest::kActive); + result.SetToShadowHostIfInRestrictedShadowRoot(); + return result; +} + +LocalFrame* WebFrameWidgetImpl::FocusedLocalFrameAvailableForIme() const { + if (!ime_accept_events_) + return nullptr; + return FocusedLocalFrameInWidget(); +} + +void WebFrameWidgetImpl::DidCreateLocalRootView() { + // If this WebWidget still hasn't received its size from the embedder, block + // the parser. This is necessary, because the parser can cause layout to + // happen, which needs to be done with the correct size. + if (!size_) { + did_suspend_parsing_ = true; + local_root_->GetFrame()->Loader().GetDocumentLoader()->BlockParser(); + } +} + +void WebFrameWidgetImpl::GetScrollParamsForFocusedEditableElement( + const Element& element, + LayoutRect& rect_to_scroll, + WebScrollIntoViewParams& params) { + LocalFrameView& frame_view = *element.GetDocument().View(); + IntRect absolute_element_bounds = + element.GetLayoutObject()->AbsoluteBoundingBoxRect(); + IntRect absolute_caret_bounds = + element.GetDocument().GetFrame()->Selection().AbsoluteCaretBounds(); + // Ideally, the chosen rectangle includes the element box and caret bounds + // plus some margin on the left. If this does not work (i.e., does not fit + // inside the frame view), then choose a subrect which includes the caret + // bounds. It is preferrable to also include element bounds' location and left + // align the scroll. If this cant be satisfied, the scroll will be right + // aligned. + IntRect maximal_rect = + UnionRect(absolute_element_bounds, absolute_caret_bounds); + + // Set the ideal margin. + maximal_rect.ShiftXEdgeTo( + maximal_rect.X() - + static_cast<int>(kIdealPaddingRatio * absolute_element_bounds.Width())); + + bool maximal_rect_fits_in_frame = + !(frame_view.Size() - maximal_rect.Size()).IsEmpty(); + + if (!maximal_rect_fits_in_frame) { + IntRect frame_rect(maximal_rect.Location(), frame_view.Size()); + maximal_rect.Intersect(frame_rect); + IntPoint point_forced_to_be_visible = + absolute_caret_bounds.MaxXMaxYCorner() + + IntSize(kCaretPadding, kCaretPadding); + if (!maximal_rect.Contains(point_forced_to_be_visible)) { + // Move the rect towards the point until the point is barely contained. + maximal_rect.Move(point_forced_to_be_visible - + maximal_rect.MaxXMaxYCorner()); + } + } + + params.zoom_into_rect = View()->ShouldZoomToLegibleScale(element); + params.relative_element_bounds = NormalizeRect( + Intersection(absolute_element_bounds, maximal_rect), maximal_rect); + params.relative_caret_bounds = NormalizeRect( + Intersection(absolute_caret_bounds, maximal_rect), maximal_rect); + params.behavior = WebScrollIntoViewParams::kInstant; + rect_to_scroll = LayoutRect(maximal_rect); +} + +} // namespace blink |