blob: 1ef6c1e1e5c4ddc51cdee7fa8b826b33a755aabd [file] [log] [blame]
/*
* 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 "web/WebFrameWidgetImpl.h"
#include "core/InputTypeNames.h"
#include "core/editing/EditingUtilities.h"
#include "core/editing/Editor.h"
#include "core/editing/FrameSelection.h"
#include "core/editing/InputMethodController.h"
#include "core/editing/PlainTextRange.h"
#include "core/frame/FrameHost.h"
#include "core/frame/FrameView.h"
#include "core/frame/RemoteFrame.h"
#include "core/frame/Settings.h"
#include "core/frame/VisualViewport.h"
#include "core/html/HTMLInputElement.h"
#include "core/html/HTMLTextAreaElement.h"
#include "core/input/EventHandler.h"
#include "core/layout/LayoutView.h"
#include "core/layout/api/LayoutViewItem.h"
#include "core/layout/compositing/PaintLayerCompositor.h"
#include "core/page/ContextMenuController.h"
#include "core/page/FocusController.h"
#include "core/page/Page.h"
#include "core/page/PointerLockController.h"
#include "platform/KeyboardCodes.h"
#include "platform/graphics/CompositorMutatorClient.h"
#include "public/platform/WebFrameScheduler.h"
#include "public/web/WebAutofillClient.h"
#include "public/web/WebPlugin.h"
#include "public/web/WebRange.h"
#include "public/web/WebWidgetClient.h"
#include "web/CompositionUnderlineVectorBuilder.h"
#include "web/CompositorMutatorImpl.h"
#include "web/CompositorProxyClientImpl.h"
#include "web/ContextMenuAllowedScope.h"
#include "web/WebDevToolsAgentImpl.h"
#include "web/WebInputEventConversion.h"
#include "web/WebLocalFrameImpl.h"
#include "web/WebPluginContainerImpl.h"
#include "web/WebRemoteFrameImpl.h"
#include "web/WebViewFrameWidget.h"
#include "wtf/AutoReset.h"
#include "wtf/PtrUtil.h"
#include <memory>
namespace blink {
// WebFrameWidget ------------------------------------------------------------
WebFrameWidget* WebFrameWidget::create(WebWidgetClient* client,
WebLocalFrame* localRoot) {
// Pass the WebFrameWidget's self-reference to the caller.
return WebFrameWidgetImpl::create(client, localRoot);
}
WebFrameWidget* WebFrameWidget::create(WebWidgetClient* client,
WebView* webView,
WebLocalFrame* mainFrame) {
return new WebViewFrameWidget(client, toWebViewImpl(*webView),
toWebLocalFrameImpl(*mainFrame));
}
WebFrameWidgetImpl* WebFrameWidgetImpl::create(WebWidgetClient* client,
WebLocalFrame* localRoot) {
// Pass the WebFrameWidgetImpl's self-reference to the caller.
return new WebFrameWidgetImpl(
client, localRoot); // SelfKeepAlive is set in constructor.
}
// static
WebFrameWidgetsSet& WebFrameWidgetImpl::allInstances() {
DEFINE_STATIC_LOCAL(WebFrameWidgetsSet, allInstances, ());
return allInstances;
}
WebFrameWidgetImpl::WebFrameWidgetImpl(WebWidgetClient* client,
WebLocalFrame* localRoot)
: m_client(client),
m_localRoot(toWebLocalFrameImpl(localRoot)),
m_mutator(nullptr),
m_layerTreeView(nullptr),
m_rootLayer(nullptr),
m_rootGraphicsLayer(nullptr),
m_isAcceleratedCompositingActive(false),
m_layerTreeViewClosed(false),
m_suppressNextKeypressEvent(false),
m_ignoreInputEvents(false),
m_isTransparent(false),
m_imeAcceptEvents(true),
m_selfKeepAlive(this) {
DCHECK(m_localRoot->frame()->isLocalRoot());
initializeLayerTreeView();
m_localRoot->setFrameWidget(this);
allInstances().add(this);
if (localRoot->parent())
setIsTransparent(true);
}
WebFrameWidgetImpl::~WebFrameWidgetImpl() {}
DEFINE_TRACE(WebFrameWidgetImpl) {
visitor->trace(m_localRoot);
visitor->trace(m_mouseCaptureNode);
}
// WebWidget ------------------------------------------------------------------
void WebFrameWidgetImpl::close() {
WebDevToolsAgentImpl::webFrameWidgetImplClosed(this);
DCHECK(allInstances().contains(this));
allInstances().remove(this);
m_localRoot->setFrameWidget(nullptr);
m_localRoot = nullptr;
// Reset the delegate to prevent notifications being sent as we're being
// deleted.
m_client = nullptr;
m_mutator = nullptr;
m_layerTreeView = nullptr;
m_rootLayer = nullptr;
m_rootGraphicsLayer = nullptr;
m_selfKeepAlive.clear();
}
WebSize WebFrameWidgetImpl::size() {
return m_size;
}
void WebFrameWidgetImpl::resize(const WebSize& newSize) {
if (m_size == newSize)
return;
FrameView* view = m_localRoot->frameView();
if (!view)
return;
m_size = newSize;
updateMainFrameLayoutSize();
view->resize(m_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->layout();
// FIXME: Investigate whether this is needed; comment from eseidel suggests
// that this function is flawed.
sendResizeEventAndRepaint();
}
void WebFrameWidgetImpl::sendResizeEventAndRepaint() {
// FIXME: This is wrong. The FrameView 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 (m_localRoot->frameView()) {
// Enqueues the resize event.
m_localRoot->frame()->document()->enqueueResizeEvent();
}
if (m_client) {
if (isAcceleratedCompositingActive()) {
updateLayerTreeViewport();
} else {
WebRect damagedRect(0, 0, m_size.width, m_size.height);
m_client->didInvalidateRect(damagedRect);
}
}
}
void WebFrameWidgetImpl::resizeVisualViewport(const WebSize& newSize) {
// TODO(alexmos, kenrb): resizing behavior such as this should be changed
// to use Page messages. https://crbug.com/599688.
page()->frameHost().visualViewport().setSize(newSize);
page()->frameHost().visualViewport().clampToBoundaries();
view()->didUpdateFullscreenSize();
}
void WebFrameWidgetImpl::updateMainFrameLayoutSize() {
if (!m_localRoot)
return;
FrameView* view = m_localRoot->frameView();
if (!view)
return;
WebSize layoutSize = m_size;
view->setLayoutSize(layoutSize);
}
void WebFrameWidgetImpl::setIgnoreInputEvents(bool newValue) {
DCHECK_NE(m_ignoreInputEvents, newValue);
m_ignoreInputEvents = newValue;
}
void WebFrameWidgetImpl::didEnterFullscreen() {
view()->didEnterFullscreen();
}
void WebFrameWidgetImpl::didExitFullscreen() {
view()->didExitFullscreen();
}
void WebFrameWidgetImpl::beginFrame(double lastFrameTimeMonotonic) {
TRACE_EVENT1("blink", "WebFrameWidgetImpl::beginFrame", "frameTime",
lastFrameTimeMonotonic);
DCHECK(lastFrameTimeMonotonic);
PageWidgetDelegate::animate(*page(), lastFrameTimeMonotonic);
}
void WebFrameWidgetImpl::updateAllLifecyclePhases() {
TRACE_EVENT0("blink", "WebFrameWidgetImpl::updateAllLifecyclePhases");
if (!m_localRoot)
return;
PageWidgetDelegate::updateAllLifecyclePhases(*page(), *m_localRoot->frame());
updateLayerTreeBackgroundColor();
}
void WebFrameWidgetImpl::paint(WebCanvas* canvas, const WebRect& rect) {
// Out-of-process iframes require compositing.
NOTREACHED();
}
void WebFrameWidgetImpl::updateLayerTreeViewport() {
if (!page() || !m_layerTreeView)
return;
// FIXME: We need access to page scale information from the WebView.
m_layerTreeView->setPageScaleFactorAndLimits(1, 1, 1);
}
void WebFrameWidgetImpl::updateLayerTreeBackgroundColor() {
if (!m_layerTreeView)
return;
m_layerTreeView->setBackgroundColor(backgroundColor());
}
void WebFrameWidgetImpl::updateLayerTreeDeviceScaleFactor() {
DCHECK(page());
DCHECK(m_layerTreeView);
float deviceScaleFactor = page()->deviceScaleFactor();
m_layerTreeView->setDeviceScaleFactor(deviceScaleFactor);
}
void WebFrameWidgetImpl::setIsTransparent(bool isTransparent) {
m_isTransparent = isTransparent;
if (m_layerTreeView)
m_layerTreeView->setHasTransparentBackground(isTransparent);
}
bool WebFrameWidgetImpl::isTransparent() const {
return m_isTransparent;
}
void WebFrameWidgetImpl::layoutAndPaintAsync(
WebLayoutAndPaintAsyncCallback* callback) {
m_layerTreeView->layoutAndPaintAsync(callback);
}
void WebFrameWidgetImpl::compositeAndReadbackAsync(
WebCompositeAndReadbackAsyncCallback* callback) {
m_layerTreeView->compositeAndReadbackAsync(callback);
}
void WebFrameWidgetImpl::themeChanged() {
FrameView* view = m_localRoot->frameView();
WebRect damagedRect(0, 0, m_size.width, m_size.height);
view->invalidateRect(damagedRect);
}
const WebInputEvent* WebFrameWidgetImpl::m_currentInputEvent = nullptr;
WebInputEventResult WebFrameWidgetImpl::handleInputEvent(
const WebInputEvent& inputEvent) {
TRACE_EVENT1("input", "WebFrameWidgetImpl::handleInputEvent", "type",
WebInputEvent::GetName(inputEvent.type));
// Don't handle events once we've started shutting down.
if (!page())
return WebInputEventResult::NotHandled;
// Report the event to be NOT processed by WebKit, so that the browser can
// handle it appropriately.
if (m_ignoreInputEvents)
return WebInputEventResult::NotHandled;
// FIXME: pass event to m_localRoot's WebDevToolsAgentImpl once available.
AutoReset<const WebInputEvent*> currentEventChange(&m_currentInputEvent,
&inputEvent);
if (m_mouseCaptureNode && WebInputEvent::isMouseEventType(inputEvent.type)) {
TRACE_EVENT1("input", "captured mouse event", "type", inputEvent.type);
// Save m_mouseCaptureNode since mouseCaptureLost() will clear it.
Node* node = m_mouseCaptureNode;
// Not all platforms call mouseCaptureLost() directly.
if (inputEvent.type == WebInputEvent::MouseUp)
mouseCaptureLost();
std::unique_ptr<UserGestureIndicator> gestureIndicator;
AtomicString eventType;
switch (inputEvent.type) {
case WebInputEvent::MouseMove:
eventType = EventTypeNames::mousemove;
break;
case WebInputEvent::MouseLeave:
eventType = EventTypeNames::mouseout;
break;
case WebInputEvent::MouseDown:
eventType = EventTypeNames::mousedown;
gestureIndicator = wrapUnique(
new UserGestureIndicator(DefinitelyProcessingNewUserGesture));
m_mouseCaptureGestureToken = gestureIndicator->currentToken();
break;
case WebInputEvent::MouseUp:
eventType = EventTypeNames::mouseup;
gestureIndicator = wrapUnique(
new UserGestureIndicator(m_mouseCaptureGestureToken.release()));
break;
default:
NOTREACHED();
}
node->dispatchMouseEvent(
PlatformMouseEventBuilder(
m_localRoot->frameView(),
static_cast<const WebMouseEvent&>(inputEvent)),
eventType, static_cast<const WebMouseEvent&>(inputEvent).clickCount);
return WebInputEventResult::HandledSystem;
}
return PageWidgetDelegate::handleInputEvent(*this, inputEvent,
m_localRoot->frame());
}
void WebFrameWidgetImpl::setCursorVisibilityState(bool isVisible) {
page()->setIsCursorVisible(isVisible);
}
bool WebFrameWidgetImpl::hasTouchEventHandlersAt(const WebPoint& point) {
// FIXME: Implement this. Note that the point must be divided by
// pageScaleFactor.
return true;
}
void WebFrameWidgetImpl::setBaseBackgroundColor(WebColor color) {
if (m_baseBackgroundColor == color)
return;
m_baseBackgroundColor = color;
m_localRoot->frameView()->setBaseBackgroundColor(color);
}
void WebFrameWidgetImpl::scheduleAnimation() {
if (m_layerTreeView) {
m_layerTreeView->setNeedsBeginFrame();
return;
}
if (m_client)
m_client->scheduleAnimation();
}
CompositorProxyClient* WebFrameWidgetImpl::createCompositorProxyClient() {
if (!m_mutator) {
std::unique_ptr<CompositorMutatorClient> mutatorClient =
CompositorMutatorImpl::createClient();
m_mutator = static_cast<CompositorMutatorImpl*>(mutatorClient->mutator());
m_layerTreeView->setMutatorClient(std::move(mutatorClient));
}
return new CompositorProxyClientImpl(m_mutator);
}
void WebFrameWidgetImpl::applyViewportDeltas(
const WebFloatSize& visualViewportDelta,
const WebFloatSize& mainFrameDelta,
const WebFloatSize& elasticOverscrollDelta,
float pageScaleDelta,
float topControlsDelta) {
// FIXME: To be implemented.
}
void WebFrameWidgetImpl::mouseCaptureLost() {
TRACE_EVENT_ASYNC_END0("input", "capturing mouse", this);
m_mouseCaptureNode = nullptr;
}
void WebFrameWidgetImpl::setFocus(bool enable) {
page()->focusController().setFocused(enable);
if (enable) {
page()->focusController().setActive(true);
LocalFrame* focusedFrame = page()->focusController().focusedFrame();
if (focusedFrame) {
Element* element = focusedFrame->document()->focusedElement();
if (element && focusedFrame->selection().selection().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.
focusedFrame->document()->updateStyleAndLayoutTree();
if (element->isTextFormControl()) {
element->updateFocusAppearance(SelectionBehaviorOnFocus::Restore);
} 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);
focusedFrame->selection().setSelection(
createVisibleSelection(position, SelDefaultAffinity));
}
}
}
} else {
LocalFrame* focusedFrame = focusedLocalFrameInWidget();
if (focusedFrame) {
// Finish an ongoing composition to delete the composition node.
if (focusedFrame->inputMethodController().hasComposition()) {
WebAutofillClient* autofillClient =
WebLocalFrameImpl::fromFrame(focusedFrame)->autofillClient();
if (autofillClient)
autofillClient->setIgnoreTextChanges(true);
// TODO(xiaochengh): The use of
// updateStyleAndLayoutIgnorePendingStylesheets needs to be audited.
// See http://crbug.com/590369 for more details.
focusedFrame->document()
->updateStyleAndLayoutIgnorePendingStylesheets();
focusedFrame->inputMethodController().finishComposingText(
InputMethodController::KeepSelection);
if (autofillClient)
autofillClient->setIgnoreTextChanges(false);
}
m_imeAcceptEvents = false;
}
}
}
// TODO(ekaramad):This method is almost duplicated in WebViewImpl as well. This
// code needs to be refactored (http://crbug.com/629721).
bool WebFrameWidgetImpl::setComposition(
const WebString& text,
const WebVector<WebCompositionUnderline>& underlines,
int selectionStart,
int selectionEnd) {
LocalFrame* focused = focusedLocalFrameAvailableForIme();
if (!focused)
return false;
if (WebPlugin* plugin = focusedPluginIfInputMethodSupported(focused))
return plugin->setComposition(text, underlines, selectionStart,
selectionEnd);
// The input focus has been moved to another WebWidget object.
// We should use this |editor| object only to complete the ongoing
// composition.
InputMethodController& inputMethodController =
focused->inputMethodController();
if (!focused->editor().canEdit() && !inputMethodController.hasComposition())
return false;
// We should verify the parent node of this IME composition node are
// editable because JavaScript may delete a parent node of the composition
// node. In this case, WebKit crashes while deleting texts from the parent
// node, which doesn't exist any longer.
const EphemeralRange range =
inputMethodController.compositionEphemeralRange();
if (range.isNotNull()) {
Node* node = range.startPosition().computeContainerNode();
focused->document()->updateStyleAndLayoutTree();
if (!node || !hasEditableStyle(*node))
return false;
}
// A keypress event is canceled. If an ongoing composition exists, then the
// keydown event should have arisen from a handled key (e.g., backspace).
// In this case we ignore the cancellation and continue; otherwise (no
// ongoing composition) we exit and signal success only for attempts to
// clear the composition.
if (m_suppressNextKeypressEvent && !inputMethodController.hasComposition())
return text.isEmpty();
UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture);
// When the range of composition underlines overlap with the range between
// selectionStart and selectionEnd, WebKit somehow won't paint the selection
// at all (see InlineTextBox::paint() function in InlineTextBox.cpp).
// But the selection range actually takes effect.
inputMethodController.setComposition(
String(text), CompositionUnderlineVectorBuilder(underlines),
selectionStart, selectionEnd);
return text.isEmpty() || inputMethodController.hasComposition();
}
// TODO(ekaramad):These methods are almost duplicated in WebViewImpl as well.
// This code needs to be refactored (http://crbug.com/629721).
bool WebFrameWidgetImpl::commitText(const WebString& text,
int relativeCaretPosition) {
UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture);
LocalFrame* focused = focusedLocalFrameAvailableForIme();
if (!focused)
return false;
if (WebPlugin* plugin = focusedPluginIfInputMethodSupported(focused))
return plugin->commitText(text, relativeCaretPosition);
return focused->inputMethodController().commitText(text,
relativeCaretPosition);
}
bool WebFrameWidgetImpl::finishComposingText(
ConfirmCompositionBehavior selectionBehavior) {
LocalFrame* focused = focusedLocalFrameAvailableForIme();
if (!focused)
return false;
if (WebPlugin* plugin = focusedPluginIfInputMethodSupported(focused))
return plugin->finishComposingText(selectionBehavior);
// TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
// needs to be audited. See http://crbug.com/590369 for more details.
focused->document()->updateStyleAndLayoutIgnorePendingStylesheets();
return focused->inputMethodController().finishComposingText(
selectionBehavior == KeepSelection
? InputMethodController::KeepSelection
: InputMethodController::DoNotKeepSelection);
}
// TODO(ekaramad):This method is almost duplicated in WebViewImpl as well. This
// code needs to be refactored (http://crbug.com/629721).
WebRange WebFrameWidgetImpl::compositionRange() {
LocalFrame* focused = focusedLocalFrameAvailableForIme();
if (!focused)
return WebRange();
const EphemeralRange range =
focused->inputMethodController().compositionEphemeralRange();
if (range.isNull())
return WebRange();
Element* editable =
focused->selection().rootEditableElementOrDocumentElement();
DCHECK(editable);
// TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
// needs to be audited. See http://crbug.com/590369 for more details.
editable->document().updateStyleAndLayoutIgnorePendingStylesheets();
return PlainTextRange::create(*editable, range);
}
// TODO(ekaramad):This method is almost duplicated in WebViewImpl as well. This
// code needs to be refactored (http://crbug.com/629721).
WebTextInputInfo WebFrameWidgetImpl::textInputInfo() {
WebTextInputInfo info;
LocalFrame* focused = focusedLocalFrameInWidget();
if (!focused)
return info;
FrameSelection& selection = focused->selection();
if (!selection.isAvailable()) {
// plugins/mouse-capture-inside-shadow.html reaches here.
return info;
}
Element* element = selection.selection().rootEditableElement();
if (!element)
return info;
info.inputMode = inputModeOfFocusedElement();
info.type = textInputType();
info.flags = textInputFlags();
if (info.type == WebTextInputTypeNone)
return info;
if (!focused->editor().canEdit())
return info;
// TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
// needs to be audited. see http://crbug.com/590369 for more details.
focused->document()->updateStyleAndLayoutIgnorePendingStylesheets();
DocumentLifecycle::DisallowTransitionScope disallowTransition(
focused->document()->lifecycle());
// Emits an object replacement character for each replaced element so that
// it is exposed to IME and thus could be deleted by IME on android.
info.value = plainText(EphemeralRange::rangeOfContents(*element),
TextIteratorEmitsObjectReplacementCharacter);
if (info.value.isEmpty())
return info;
EphemeralRange firstRange = firstEphemeralRangeOf(selection.selection());
if (firstRange.isNotNull()) {
PlainTextRange plainTextRange(PlainTextRange::create(*element, firstRange));
if (plainTextRange.isNotNull()) {
info.selectionStart = plainTextRange.start();
info.selectionEnd = plainTextRange.end();
}
}
EphemeralRange range =
focused->inputMethodController().compositionEphemeralRange();
if (range.isNotNull()) {
PlainTextRange plainTextRange(PlainTextRange::create(*element, range));
if (plainTextRange.isNotNull()) {
info.compositionStart = plainTextRange.start();
info.compositionEnd = plainTextRange.end();
}
}
return info;
}
// TODO(ekaramad):This method is almost duplicated in WebViewImpl as well. This
// code needs to be refactored (http://crbug.com/629721).
WebTextInputType WebFrameWidgetImpl::textInputType() {
LocalFrame* focusedFrame = focusedLocalFrameInWidget();
if (!focusedFrame)
return WebTextInputTypeNone;
if (!focusedFrame->selection().isAvailable()) {
// "mouse-capture-inside-shadow.html" reaches here.
return WebTextInputTypeNone;
}
// It's important to preserve the equivalence of textInputInfo().type and
// textInputType(), so perform the same rootEditableElement() existence check
// here for consistency.
if (!focusedFrame->selection().selection().rootEditableElement())
return WebTextInputTypeNone;
Document* document = focusedFrame->document();
if (!document)
return WebTextInputTypeNone;
Element* element = document->focusedElement();
if (!element)
return WebTextInputTypeNone;
if (isHTMLInputElement(*element)) {
HTMLInputElement& input = toHTMLInputElement(*element);
const AtomicString& type = input.type();
if (input.isDisabledOrReadOnly())
return WebTextInputTypeNone;
if (type == InputTypeNames::password)
return WebTextInputTypePassword;
if (type == InputTypeNames::search)
return WebTextInputTypeSearch;
if (type == InputTypeNames::email)
return WebTextInputTypeEmail;
if (type == InputTypeNames::number)
return WebTextInputTypeNumber;
if (type == InputTypeNames::tel)
return WebTextInputTypeTelephone;
if (type == InputTypeNames::url)
return WebTextInputTypeURL;
if (type == InputTypeNames::text)
return WebTextInputTypeText;
return WebTextInputTypeNone;
}
if (isHTMLTextAreaElement(*element)) {
if (toHTMLTextAreaElement(*element).isDisabledOrReadOnly())
return WebTextInputTypeNone;
return WebTextInputTypeTextArea;
}
if (element->isHTMLElement()) {
if (toHTMLElement(element)->isDateTimeFieldElement())
return WebTextInputTypeDateTimeField;
}
document->updateStyleAndLayoutTree();
if (hasEditableStyle(*element))
return WebTextInputTypeContentEditable;
return WebTextInputTypeNone;
}
WebColor WebFrameWidgetImpl::backgroundColor() const {
if (isTransparent())
return Color::transparent;
if (!m_localRoot->frameView())
return m_baseBackgroundColor;
FrameView* view = m_localRoot->frameView();
return view->documentBackgroundColor().rgb();
}
// TODO(ekaramad):This method is almost duplicated in WebViewImpl as well. This
// code needs to be refactored (http://crbug.com/629721).
bool WebFrameWidgetImpl::selectionBounds(WebRect& anchor,
WebRect& focus) const {
const LocalFrame* localFrame = focusedLocalFrameInWidget();
if (!localFrame)
return false;
FrameSelection& selection = localFrame->selection();
if (selection.isNone())
return false;
// TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
// needs to be audited. See http://crbug.com/590369 for more details.
localFrame->document()->updateStyleAndLayoutIgnorePendingStylesheets();
DocumentLifecycle::DisallowTransitionScope disallowTransition(
localFrame->document()->lifecycle());
if (selection.isCaret()) {
anchor = focus = selection.absoluteCaretBounds();
} else {
const EphemeralRange selectedRange =
selection.selection().toNormalizedEphemeralRange();
if (selectedRange.isNull())
return false;
anchor = localFrame->editor().firstRectForRange(
EphemeralRange(selectedRange.startPosition()));
focus = localFrame->editor().firstRectForRange(
EphemeralRange(selectedRange.endPosition()));
}
// FIXME: This doesn't apply page scale. This should probably be contents to
// viewport. crbug.com/459293.
IntRect scaledAnchor(localFrame->view()->contentsToRootFrame(anchor));
IntRect scaledFocus(localFrame->view()->contentsToRootFrame(focus));
anchor = scaledAnchor;
focus = scaledFocus;
if (!selection.selection().isBaseFirst())
std::swap(anchor, focus);
return true;
}
// TODO(ekaramad):This method is almost duplicated in WebViewImpl as well. This
// code needs to be refactored (http://crbug.com/629721).
bool WebFrameWidgetImpl::selectionTextDirection(WebTextDirection& start,
WebTextDirection& end) const {
const LocalFrame* frame = focusedLocalFrameInWidget();
if (!frame)
return false;
FrameSelection& selection = frame->selection();
if (selection.selection().toNormalizedEphemeralRange().isNull())
return false;
start =
toWebTextDirection(primaryDirectionOf(*selection.start().anchorNode()));
end = toWebTextDirection(primaryDirectionOf(*selection.end().anchorNode()));
return true;
}
// TODO(ekaramad):This method is almost duplicated in WebViewImpl as well. This
// code needs to be refactored (http://crbug.com/629721).
bool WebFrameWidgetImpl::isSelectionAnchorFirst() const {
if (const LocalFrame* frame = focusedLocalFrameInWidget())
return frame->selection().selection().isBaseFirst();
return false;
}
// TODO(ekaramad):This method is almost duplicated in WebViewImpl as well. This
// code needs to be refactored (http://crbug.com/629721).
WebRange WebFrameWidgetImpl::caretOrSelectionRange() {
LocalFrame* focused = focusedLocalFrameInWidget();
if (!focused)
return WebRange();
// TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
// needs to be audited. See http://crbug.com/590369 for more details.
focused->document()->updateStyleAndLayoutIgnorePendingStylesheets();
return focused->inputMethodController().getSelectionOffsets();
}
void WebFrameWidgetImpl::setTextDirection(WebTextDirection direction) {
// The Editor::setBaseWritingDirection() function checks if we can change
// the text direction of the selected node and updates its DOM "dir"
// attribute and its CSS "direction" property.
// So, we just call the function as Safari does.
const LocalFrame* focused = focusedLocalFrameInWidget();
if (!focused)
return;
Editor& editor = focused->editor();
if (!editor.canEdit())
return;
switch (direction) {
case WebTextDirectionDefault:
editor.setBaseWritingDirection(NaturalWritingDirection);
break;
case WebTextDirectionLeftToRight:
editor.setBaseWritingDirection(LeftToRightWritingDirection);
break;
case WebTextDirectionRightToLeft:
editor.setBaseWritingDirection(RightToLeftWritingDirection);
break;
default:
NOTIMPLEMENTED();
break;
}
}
bool WebFrameWidgetImpl::isAcceleratedCompositingActive() const {
return m_isAcceleratedCompositingActive;
}
void WebFrameWidgetImpl::willCloseLayerTreeView() {
if (m_layerTreeView)
page()->willCloseLayerTreeView(*m_layerTreeView);
setIsAcceleratedCompositingActive(false);
m_mutator = nullptr;
m_layerTreeView = nullptr;
m_layerTreeViewClosed = true;
}
void WebFrameWidgetImpl::didChangeWindowResizerRect() {
if (m_localRoot->frameView())
m_localRoot->frameView()->windowResizerRectChanged();
}
void WebFrameWidgetImpl::didAcquirePointerLock() {
page()->pointerLockController().didAcquirePointerLock();
}
void WebFrameWidgetImpl::didNotAcquirePointerLock() {
page()->pointerLockController().didNotAcquirePointerLock();
}
void WebFrameWidgetImpl::didLosePointerLock() {
page()->pointerLockController().didLosePointerLock();
}
// TODO(ekaramad):This method is almost duplicated in WebViewImpl as well. This
// code needs to be refactored (http://crbug.com/629721).
bool WebFrameWidgetImpl::getCompositionCharacterBounds(
WebVector<WebRect>& bounds) {
WebRange range = compositionRange();
if (range.isEmpty())
return false;
LocalFrame* frame = focusedLocalFrameInWidget();
if (!frame)
return false;
WebLocalFrameImpl* webLocalFrame = WebLocalFrameImpl::fromFrame(frame);
size_t characterCount = range.length();
size_t offset = range.startOffset();
WebVector<WebRect> result(characterCount);
WebRect webrect;
for (size_t i = 0; i < characterCount; ++i) {
if (!webLocalFrame->firstRectForCharacterRange(offset + i, 1, webrect)) {
DLOG(ERROR) << "Could not retrieve character rectangle at " << i;
return false;
}
result[i] = webrect;
}
bounds.swap(result);
return true;
}
// TODO(ekaramad):This method is almost duplicated in WebViewImpl as well. This
// code needs to be refactored (http://crbug.com/629721).
void WebFrameWidgetImpl::applyReplacementRange(const WebRange& range) {
if (LocalFrame* frame = focusedLocalFrameInWidget()) {
// TODO(dglazkov): Going from LocalFrame to WebLocalFrameImpl seems
// silly. What is going on here?
WebLocalFrameImpl::fromFrame(frame)->selectRange(range);
}
}
void WebFrameWidgetImpl::handleMouseLeave(LocalFrame& mainFrame,
const WebMouseEvent& event) {
// FIXME: WebWidget doesn't have the method below.
// m_client->setMouseOverURL(WebURL());
PageWidgetEventHandler::handleMouseLeave(mainFrame, event);
}
void WebFrameWidgetImpl::handleMouseDown(LocalFrame& mainFrame,
const WebMouseEvent& event) {
// 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.
IntPoint point(event.x, event.y);
if (event.button == WebMouseEvent::Button::Left) {
point = m_localRoot->frameView()->rootFrameToContents(point);
HitTestResult result(
m_localRoot->frame()->eventHandler().hitTestResultAtPoint(point));
result.setToShadowHostIfInUserAgentShadowRoot();
Node* hitNode = result.innerNode();
if (!result.scrollbar() && hitNode && hitNode->layoutObject() &&
hitNode->layoutObject()->isEmbeddedObject()) {
m_mouseCaptureNode = hitNode;
TRACE_EVENT_ASYNC_BEGIN0("input", "capturing mouse", this);
}
}
PageWidgetEventHandler::handleMouseDown(mainFrame, event);
if (event.button == WebMouseEvent::Button::Left && m_mouseCaptureNode)
m_mouseCaptureGestureToken =
mainFrame.eventHandler().takeLastMouseDownGestureToken();
// Dispatch the contextmenu event regardless of if the click was swallowed.
if (!page()->settings().showContextMenuOnMouseUp()) {
#if OS(MACOSX)
if (event.button == WebMouseEvent::Button::Right ||
(event.button == WebMouseEvent::Button::Left &&
event.modifiers & WebMouseEvent::ControlKey))
mouseContextMenu(event);
#else
if (event.button == WebMouseEvent::Button::Right)
mouseContextMenu(event);
#endif
}
}
void WebFrameWidgetImpl::mouseContextMenu(const WebMouseEvent& event) {
page()->contextMenuController().clearContextMenu();
PlatformMouseEventBuilder pme(m_localRoot->frameView(), event);
// Find the right target frame. See issue 1186900.
HitTestResult result = hitTestResultForRootFramePos(pme.position());
Frame* targetFrame;
if (result.innerNodeOrImageMapImage())
targetFrame = result.innerNodeOrImageMapImage()->document().frame();
else
targetFrame = page()->focusController().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 (!targetFrame->isLocalFrame())
return;
LocalFrame* targetLocalFrame = toLocalFrame(targetFrame);
#if OS(WIN)
targetLocalFrame->view()->setCursor(pointerCursor());
#endif
{
ContextMenuAllowedScope scope;
targetLocalFrame->eventHandler().sendContextMenuEvent(pme, nullptr);
}
// Actually showing the context menu is handled by the ContextMenuClient
// implementation...
}
void WebFrameWidgetImpl::handleMouseUp(LocalFrame& mainFrame,
const WebMouseEvent& event) {
PageWidgetEventHandler::handleMouseUp(mainFrame, event);
if (page()->settings().showContextMenuOnMouseUp()) {
// 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::Right)
mouseContextMenu(event);
}
}
WebInputEventResult WebFrameWidgetImpl::handleMouseWheel(
LocalFrame& mainFrame,
const WebMouseWheelEvent& event) {
return PageWidgetEventHandler::handleMouseWheel(mainFrame, event);
}
WebInputEventResult WebFrameWidgetImpl::handleGestureEvent(
const WebGestureEvent& event) {
WebInputEventResult eventResult = WebInputEventResult::NotHandled;
bool eventCancelled = false;
switch (event.type) {
case WebInputEvent::GestureScrollBegin:
case WebInputEvent::GestureScrollEnd:
case WebInputEvent::GestureScrollUpdate:
case WebInputEvent::GestureTap:
case WebInputEvent::GestureTapUnconfirmed:
case WebInputEvent::GestureTapDown:
case WebInputEvent::GestureShowPress:
case WebInputEvent::GestureTapCancel:
case WebInputEvent::GestureDoubleTap:
case WebInputEvent::GestureTwoFingerTap:
case WebInputEvent::GestureLongPress:
case WebInputEvent::GestureLongTap:
break;
case WebInputEvent::GestureFlingStart:
case WebInputEvent::GestureFlingCancel:
m_client->didHandleGestureEvent(event, eventCancelled);
return WebInputEventResult::NotHandled;
default:
NOTREACHED();
}
LocalFrame* frame = m_localRoot->frame();
eventResult = frame->eventHandler().handleGestureEvent(
PlatformGestureEventBuilder(frame->view(), event));
m_client->didHandleGestureEvent(event, eventCancelled);
return eventResult;
}
WebInputEventResult WebFrameWidgetImpl::handleKeyEvent(
const WebKeyboardEvent& event) {
DCHECK((event.type == WebInputEvent::RawKeyDown) ||
(event.type == WebInputEvent::KeyDown) ||
(event.type == WebInputEvent::KeyUp));
// 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.
m_suppressNextKeypressEvent = false;
Frame* focusedFrame = focusedCoreFrame();
if (focusedFrame && focusedFrame->isRemoteFrame()) {
WebRemoteFrameImpl* webFrame =
WebRemoteFrameImpl::fromFrame(*toRemoteFrame(focusedFrame));
webFrame->client()->forwardInputEvent(&event);
return WebInputEventResult::HandledSystem;
}
if (!focusedFrame || !focusedFrame->isLocalFrame())
return WebInputEventResult::NotHandled;
LocalFrame* frame = toLocalFrame(focusedFrame);
WebInputEventResult result = frame->eventHandler().keyEvent(event);
if (result != WebInputEventResult::NotHandled) {
if (WebInputEvent::RawKeyDown == event.type) {
// 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->layoutObject() ||
!element->layoutObject()->isEmbeddedObject())
m_suppressNextKeypressEvent = true;
}
return result;
}
#if !OS(MACOSX)
const WebInputEvent::Type contextMenuKeyTriggeringEventType =
#if OS(WIN)
WebInputEvent::KeyUp;
#else
WebInputEvent::RawKeyDown;
#endif
const WebInputEvent::Type shiftF10TriggeringEventType =
WebInputEvent::RawKeyDown;
bool isUnmodifiedMenuKey =
!(event.modifiers & WebInputEvent::InputModifiers) &&
event.windowsKeyCode == VKEY_APPS;
bool isShiftF10 = (event.modifiers & WebInputEvent::InputModifiers) ==
WebInputEvent::ShiftKey &&
event.windowsKeyCode == VKEY_F10;
if ((isUnmodifiedMenuKey &&
event.type == contextMenuKeyTriggeringEventType) ||
(isShiftF10 && event.type == shiftF10TriggeringEventType)) {
view()->sendContextMenuEvent(event);
return WebInputEventResult::HandledSystem;
}
#endif // !OS(MACOSX)
return keyEventDefault(event);
}
WebInputEventResult WebFrameWidgetImpl::handleCharEvent(
const WebKeyboardEvent& event) {
DCHECK_EQ(event.type, WebInputEvent::Char);
// 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 = m_suppressNextKeypressEvent;
m_suppressNextKeypressEvent = false;
LocalFrame* frame = toLocalFrame(focusedCoreFrame());
if (!frame)
return suppress ? WebInputEventResult::HandledSuppressed
: WebInputEventResult::NotHandled;
EventHandler& handler = frame->eventHandler();
if (!event.isCharacterKey())
return WebInputEventResult::HandledSuppressed;
// 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::HandledSystem;
// 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.isSystemKey)
return WebInputEventResult::NotHandled;
if (suppress)
return WebInputEventResult::HandledSuppressed;
WebInputEventResult result = handler.keyEvent(event);
if (result != WebInputEventResult::NotHandled)
return result;
return keyEventDefault(event);
}
WebInputEventResult WebFrameWidgetImpl::keyEventDefault(
const WebKeyboardEvent& event) {
LocalFrame* frame = toLocalFrame(focusedCoreFrame());
if (!frame)
return WebInputEventResult::NotHandled;
switch (event.type) {
case WebInputEvent::Char:
if (event.windowsKeyCode == VKEY_SPACE) {
int keyCode = ((event.modifiers & WebInputEvent::ShiftKey) ? VKEY_PRIOR
: VKEY_NEXT);
return scrollViewWithKeyboard(keyCode, event.modifiers);
}
break;
case WebInputEvent::RawKeyDown:
if (event.modifiers == WebInputEvent::ControlKey) {
switch (event.windowsKeyCode) {
#if !OS(MACOSX)
case 'A':
WebFrame::fromFrame(focusedCoreFrame())
->toWebLocalFrame()
->executeCommand(WebString::fromUTF8("SelectAll"));
return WebInputEventResult::HandledSystem;
case VKEY_INSERT:
case 'C':
WebFrame::fromFrame(focusedCoreFrame())
->toWebLocalFrame()
->executeCommand(WebString::fromUTF8("Copy"));
return WebInputEventResult::HandledSystem;
#endif
// Match FF behavior in the sense that Ctrl+home/end are the only Ctrl
// key combinations which affect scrolling. Safari is buggy in the
// sense that it scrolls the page for all Ctrl+scrolling key
// combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc.
case VKEY_HOME:
case VKEY_END:
break;
default:
return WebInputEventResult::NotHandled;
}
}
if (!event.isSystemKey && !(event.modifiers & WebInputEvent::ShiftKey))
return scrollViewWithKeyboard(event.windowsKeyCode, event.modifiers);
break;
default:
break;
}
return WebInputEventResult::NotHandled;
}
WebInputEventResult WebFrameWidgetImpl::scrollViewWithKeyboard(int keyCode,
int modifiers) {
ScrollDirection scrollDirection;
ScrollGranularity scrollGranularity;
#if OS(MACOSX)
// Control-Up/Down should be PageUp/Down on Mac.
if (modifiers & WebMouseEvent::ControlKey) {
if (keyCode == VKEY_UP)
keyCode = VKEY_PRIOR;
else if (keyCode == VKEY_DOWN)
keyCode = VKEY_NEXT;
}
#endif
if (!mapKeyCodeForScroll(keyCode, &scrollDirection, &scrollGranularity))
return WebInputEventResult::NotHandled;
LocalFrame* frame = toLocalFrame(focusedCoreFrame());
if (frame &&
frame->eventHandler().bubblingScroll(scrollDirection, scrollGranularity))
return WebInputEventResult::HandledSystem;
return WebInputEventResult::NotHandled;
}
bool WebFrameWidgetImpl::mapKeyCodeForScroll(
int keyCode,
ScrollDirection* scrollDirection,
ScrollGranularity* scrollGranularity) {
switch (keyCode) {
case VKEY_LEFT:
*scrollDirection = ScrollLeftIgnoringWritingMode;
*scrollGranularity = ScrollByLine;
break;
case VKEY_RIGHT:
*scrollDirection = ScrollRightIgnoringWritingMode;
*scrollGranularity = ScrollByLine;
break;
case VKEY_UP:
*scrollDirection = ScrollUpIgnoringWritingMode;
*scrollGranularity = ScrollByLine;
break;
case VKEY_DOWN:
*scrollDirection = ScrollDownIgnoringWritingMode;
*scrollGranularity = ScrollByLine;
break;
case VKEY_HOME:
*scrollDirection = ScrollUpIgnoringWritingMode;
*scrollGranularity = ScrollByDocument;
break;
case VKEY_END:
*scrollDirection = ScrollDownIgnoringWritingMode;
*scrollGranularity = ScrollByDocument;
break;
case VKEY_PRIOR: // page up
*scrollDirection = ScrollUpIgnoringWritingMode;
*scrollGranularity = ScrollByPage;
break;
case VKEY_NEXT: // page down
*scrollDirection = ScrollDownIgnoringWritingMode;
*scrollGranularity = ScrollByPage;
break;
default:
return false;
}
return true;
}
Frame* WebFrameWidgetImpl::focusedCoreFrame() const {
return page() ? page()->focusController().focusedOrMainFrame() : nullptr;
}
Element* WebFrameWidgetImpl::focusedElement() const {
LocalFrame* frame = page()->focusController().focusedFrame();
if (!frame)
return nullptr;
Document* document = frame->document();
if (!document)
return nullptr;
return document->focusedElement();
}
void WebFrameWidgetImpl::initializeLayerTreeView() {
if (m_client) {
DCHECK(!m_mutator);
m_client->initializeLayerTreeView();
m_layerTreeView = m_client->layerTreeView();
}
if (WebDevToolsAgentImpl* devTools = m_localRoot->devToolsAgentImpl())
devTools->layerTreeViewChanged(m_layerTreeView);
page()->settings().setAcceleratedCompositingEnabled(m_layerTreeView);
if (m_layerTreeView)
page()->layerTreeViewInitialized(*m_layerTreeView);
// 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(m_layerTreeView || !m_client ||
m_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 (m_layerTreeViewClosed)
return;
DCHECK(!active || m_layerTreeView);
if (m_isAcceleratedCompositingActive == active)
return;
if (!m_client)
return;
if (active) {
TRACE_EVENT0("blink",
"WebViewImpl::setIsAcceleratedCompositingActive(true)");
m_layerTreeView->setRootLayer(*m_rootLayer);
m_layerTreeView->setVisible(page()->isPageVisible());
updateLayerTreeDeviceScaleFactor();
updateLayerTreeBackgroundColor();
m_layerTreeView->setHasTransparentBackground(isTransparent());
updateLayerTreeViewport();
m_isAcceleratedCompositingActive = true;
}
}
PaintLayerCompositor* WebFrameWidgetImpl::compositor() const {
LocalFrame* frame = m_localRoot->frame();
if (!frame || !frame->document() ||
frame->document()->layoutViewItem().isNull())
return nullptr;
return frame->document()->layoutViewItem().compositor();
}
void WebFrameWidgetImpl::setRootGraphicsLayer(GraphicsLayer* layer) {
m_rootGraphicsLayer = layer;
m_rootLayer = layer ? layer->platformLayer() : nullptr;
setIsAcceleratedCompositingActive(layer);
if (!m_layerTreeView)
return;
if (m_rootLayer)
m_layerTreeView->setRootLayer(*m_rootLayer);
else
m_layerTreeView->clearRootLayer();
}
void WebFrameWidgetImpl::setRootLayer(WebLayer* layer) {
m_rootLayer = layer;
setIsAcceleratedCompositingActive(layer);
if (!m_layerTreeView)
return;
if (m_rootLayer)
m_layerTreeView->setRootLayer(*m_rootLayer);
else
m_layerTreeView->clearRootLayer();
}
void WebFrameWidgetImpl::attachCompositorAnimationTimeline(
CompositorAnimationTimeline* compositorTimeline) {
if (m_layerTreeView)
m_layerTreeView->attachCompositorAnimationTimeline(
compositorTimeline->animationTimeline());
}
void WebFrameWidgetImpl::detachCompositorAnimationTimeline(
CompositorAnimationTimeline* compositorTimeline) {
if (m_layerTreeView)
m_layerTreeView->detachCompositorAnimationTimeline(
compositorTimeline->animationTimeline());
}
HitTestResult WebFrameWidgetImpl::coreHitTestResultAt(
const WebPoint& pointInViewport) {
DocumentLifecycle::AllowThrottlingScope throttlingScope(
m_localRoot->frame()->document()->lifecycle());
FrameView* view = m_localRoot->frameView();
IntPoint pointInRootFrame =
view->contentsToFrame(view->viewportToContents(pointInViewport));
return hitTestResultForRootFramePos(pointInRootFrame);
}
void WebFrameWidgetImpl::setVisibilityState(
WebPageVisibilityState visibilityState) {
if (m_layerTreeView)
m_layerTreeView->setVisible(visibilityState ==
WebPageVisibilityStateVisible);
}
HitTestResult WebFrameWidgetImpl::hitTestResultForRootFramePos(
const IntPoint& posInRootFrame) {
IntPoint docPoint(
m_localRoot->frame()->view()->rootFrameToContents(posInRootFrame));
HitTestResult result =
m_localRoot->frame()->eventHandler().hitTestResultAtPoint(
docPoint, HitTestRequest::ReadOnly | HitTestRequest::Active);
result.setToShadowHostIfInUserAgentShadowRoot();
return result;
}
LocalFrame* WebFrameWidgetImpl::focusedLocalFrameInWidget() const {
LocalFrame* frame = page()->focusController().focusedFrame();
return (frame && frame->localFrameRoot() == m_localRoot->frame()) ? frame
: nullptr;
}
WebPlugin* WebFrameWidgetImpl::focusedPluginIfInputMethodSupported(
LocalFrame* frame) const {
WebPluginContainerImpl* container =
WebLocalFrameImpl::currentPluginContainer(frame);
if (container && container->supportsInputMethod())
return container->plugin();
return nullptr;
}
WebString WebFrameWidgetImpl::inputModeOfFocusedElement() const {
if (!RuntimeEnabledFeatures::inputModeAttributeEnabled())
return WebString();
Element* element = focusedElement();
if (!element)
return WebString();
if (isHTMLInputElement(*element)) {
const HTMLInputElement& input = toHTMLInputElement(*element);
if (input.supportsInputModeAttribute())
return input.fastGetAttribute(HTMLNames::inputmodeAttr).lower();
return WebString();
}
if (isHTMLTextAreaElement(*element)) {
const HTMLTextAreaElement& textarea = toHTMLTextAreaElement(*element);
return textarea.fastGetAttribute(HTMLNames::inputmodeAttr).lower();
}
return WebString();
}
int WebFrameWidgetImpl::textInputFlags() const {
Element* element = focusedElement();
if (!element)
return WebTextInputFlagNone;
DEFINE_STATIC_LOCAL(AtomicString, autocompleteString, ("autocomplete"));
DEFINE_STATIC_LOCAL(AtomicString, autocorrectString, ("autocorrect"));
int flags = 0;
const AtomicString& autocomplete = element->getAttribute(autocompleteString);
if (autocomplete == "on")
flags |= WebTextInputFlagAutocompleteOn;
else if (autocomplete == "off")
flags |= WebTextInputFlagAutocompleteOff;
const AtomicString& autocorrect = element->getAttribute(autocorrectString);
if (autocorrect == "on")
flags |= WebTextInputFlagAutocorrectOn;
else if (autocorrect == "off")
flags |= WebTextInputFlagAutocorrectOff;
SpellcheckAttributeState spellcheck = element->spellcheckAttributeState();
if (spellcheck == SpellcheckAttributeTrue)
flags |= WebTextInputFlagSpellcheckOn;
else if (spellcheck == SpellcheckAttributeFalse)
flags |= WebTextInputFlagSpellcheckOff;
if (isHTMLTextFormControlElement(element)) {
HTMLTextFormControlElement* formElement =
static_cast<HTMLTextFormControlElement*>(element);
if (formElement->supportsAutocapitalize()) {
DEFINE_STATIC_LOCAL(const AtomicString, none, ("none"));
DEFINE_STATIC_LOCAL(const AtomicString, characters, ("characters"));
DEFINE_STATIC_LOCAL(const AtomicString, words, ("words"));
DEFINE_STATIC_LOCAL(const AtomicString, sentences, ("sentences"));
const AtomicString& autocapitalize = formElement->autocapitalize();
if (autocapitalize == none)
flags |= WebTextInputFlagAutocapitalizeNone;
else if (autocapitalize == characters)
flags |= WebTextInputFlagAutocapitalizeCharacters;
else if (autocapitalize == words)
flags |= WebTextInputFlagAutocapitalizeWords;
else if (autocapitalize == sentences)
flags |= WebTextInputFlagAutocapitalizeSentences;
else
NOTREACHED();
}
}
return flags;
}
LocalFrame* WebFrameWidgetImpl::focusedLocalFrameAvailableForIme() const {
if (!m_imeAcceptEvents)
return nullptr;
return focusedLocalFrameInWidget();
}
} // namespace blink