FloatSize AutoscrollController::calculateAutoscrollDelta() { LocalFrame* frame = m_autoscrollLayoutObject->frame(); if (!frame) return FloatSize(); IntPoint lastKnownMousePosition = frame->eventHandler().lastKnownMousePosition(); // We need to check if the last known mouse position is out of the window. // When the mouse is out of the window, the position is incoherent static IntPoint previousMousePosition; if (lastKnownMousePosition.x() < 0 || lastKnownMousePosition.y() < 0) lastKnownMousePosition = previousMousePosition; else previousMousePosition = lastKnownMousePosition; IntSize delta = lastKnownMousePosition - m_middleClickAutoscrollStartPos; // at the center we let the space for the icon. if (abs(delta.width()) <= noMiddleClickAutoscrollRadius) delta.setWidth(0); if (abs(delta.height()) <= noMiddleClickAutoscrollRadius) delta.setHeight(0); return FloatSize(adjustedScrollDelta(delta)); }
void RenderLayerScrollableArea::setScrollOffset(const IntPoint& newScrollOffset) { // Ensure that the dimensions will be computed if they need to be (for overflow:hidden blocks). if (m_scrollDimensionsDirty) computeScrollDimensions(); if (scrollOffset() == toIntSize(newScrollOffset)) return; setScrollOffset(toIntSize(newScrollOffset)); LocalFrame* frame = box().frame(); ASSERT(frame); RefPtr<FrameView> frameView = box().frameView(); TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "ScrollLayer", "data", InspectorScrollLayerEvent::data(&box())); const RenderLayerModelObject* paintInvalidationContainer = box().containerForPaintInvalidation(); // Update the positions of our child layers (if needed as only fixed layers should be impacted by a scroll). // We don't update compositing layers, because we need to do a deep update from the compositing ancestor. if (!frameView->isInPerformLayout()) { // If we're in the middle of layout, we'll just update layers once layout has finished. layer()->clipper().clearClipRectsIncludingDescendants(); box().setPreviousPaintInvalidationRect(box().boundsRectForPaintInvalidation(paintInvalidationContainer)); updateCompositingLayersAfterScroll(); } // The caret rect needs to be invalidated after scrolling frame->selection().setCaretRectNeedsUpdate(); FloatQuad quadForFakeMouseMoveEvent = FloatQuad(layer()->renderer()->previousPaintInvalidationRect()); quadForFakeMouseMoveEvent = paintInvalidationContainer->localToAbsoluteQuad(quadForFakeMouseMoveEvent); frame->eventHandler().dispatchFakeMouseMoveEventSoonInQuad(quadForFakeMouseMoveEvent); // For querying RenderLayer::compositingState() // This code appears correct, since scrolling outside of layout happens during activities that do not dirty compositing state. DisableCompositingQueryAsserts disabler; if (box().frameView()->isInPerformLayout()) box().setShouldDoFullPaintInvalidation(true); else box().invalidatePaintUsingContainer(paintInvalidationContainer, layer()->renderer()->previousPaintInvalidationRect(), InvalidationScroll); // Schedule the scroll DOM event. if (box().node()) box().node()->document().enqueueScrollEventForNode(box().node()); }
// Used to insert/replace text during composition update and confirm // composition. // Procedure: // 1. Fire 'beforeinput' event for (TODO(chongz): deleted composed text) and // inserted text // 2. Fire 'compositionupdate' event // 3. Fire TextEvent and modify DOM // TODO(chongz): 4. Fire 'input' event void insertTextDuringCompositionWithEvents( LocalFrame& frame, const String& text, TypingCommand::Options options, TypingCommand::TextCompositionType compositionType) { DCHECK(compositionType == TypingCommand::TextCompositionType::TextCompositionUpdate || compositionType == TypingCommand::TextCompositionType::TextCompositionConfirm) << "compositionType should be TextCompositionUpdate or " "TextCompositionConfirm, but got " << static_cast<int>(compositionType); if (!frame.document()) return; Element* target = frame.document()->focusedElement(); if (!target) return; // TODO(chongz): Fire 'beforeinput' for the composed text being // replaced/deleted. // Only the last confirmed text is cancelable. InputEvent::EventCancelable beforeInputCancelable = (compositionType == TypingCommand::TextCompositionType::TextCompositionUpdate) ? InputEvent::EventCancelable::NotCancelable : InputEvent::EventCancelable::IsCancelable; DispatchEventResult result = dispatchBeforeInputFromComposition( target, InputEvent::InputType::InsertText, text, beforeInputCancelable); if (beforeInputCancelable == InputEvent::EventCancelable::IsCancelable && result != DispatchEventResult::NotCanceled) return; // 'beforeinput' event handler may destroy document. if (!frame.document()) return; dispatchCompositionUpdateEvent(frame, text); // 'compositionupdate' event handler may destroy document. if (!frame.document()) return; switch (compositionType) { case TypingCommand::TextCompositionType::TextCompositionUpdate: TypingCommand::insertText(*frame.document(), text, options, compositionType); break; case TypingCommand::TextCompositionType::TextCompositionConfirm: // TODO(chongz): Use TypingCommand::insertText after TextEvent was // removed. (Removed from spec since 2012) // See TextEvent.idl. frame.eventHandler().handleTextInputEvent(text, 0, TextEventInputComposition); break; default: NOTREACHED(); } // TODO(chongz): Fire 'input' event. }
static bool executeInsertNewline(LocalFrame& frame, Event* event, EditorCommandSource, const String&) { LocalFrame* targetFrame = blink::targetFrame(frame, event); return targetFrame->eventHandler().handleTextInputEvent("\n", event, targetFrame->editor().canEditRichly() ? TextEventInputKeyboard : TextEventInputLineBreak); }
void TouchActionTest::runTestOnTree(ContainerNode* root, WebView* webView, TouchActionTrackingWebViewClient& client) { // Find all elements to test the touch-action of in the document. TrackExceptionState es; // Oilpan: see runTouchActionTest() comment why these are persistent // references. Persistent<StaticElementList> elements = root->querySelectorAll("[expected-action]", es); ASSERT_FALSE(es.hadException()); for (unsigned index = 0; index < elements->length(); index++) { Element* element = elements->item(index); element->scrollIntoViewIfNeeded(); std::string failureContext("Test case: "); if (element->hasID()) { failureContext.append(element->getIdAttribute().ascii().data()); } else if (element->firstChild()) { failureContext.append("\""); failureContext.append(element->firstChild() ->textContent(false) .stripWhiteSpace() .ascii() .data()); failureContext.append("\""); } else { failureContext += "<missing ID>"; } // Run each test three times at different positions in the element. // Note that we don't want the bounding box because our tests sometimes have // elements with multiple border boxes with other elements in between. Use // the first border box (which we can easily visualize in a browser for // debugging). Persistent<ClientRectList> rects = element->getClientRects(); ASSERT_GE(rects->length(), 0u) << failureContext; Persistent<ClientRect> r = rects->item(0); FloatRect clientFloatRect = FloatRect(r->left(), r->top(), r->width(), r->height()); IntRect clientRect = enclosedIntRect(clientFloatRect); for (int locIdx = 0; locIdx < 3; locIdx++) { IntPoint framePoint; std::stringstream contextStream; contextStream << failureContext << " ("; switch (locIdx) { case 0: framePoint = clientRect.center(); contextStream << "center"; break; case 1: framePoint = clientRect.location(); contextStream << "top-left"; break; case 2: framePoint = clientRect.maxXMaxYCorner(); framePoint.move(-1, -1); contextStream << "bottom-right"; break; default: FAIL() << "Invalid location index."; } IntPoint windowPoint = root->document().frame()->view()->convertToRootFrame(framePoint); contextStream << "=" << windowPoint.x() << "," << windowPoint.y() << ")."; std::string failureContextPos = contextStream.str(); LocalFrame* mainFrame = static_cast<LocalFrame*>(webView->mainFrame()->toImplBase()->frame()); FrameView* mainFrameView = mainFrame->view(); IntRect visibleRect = windowClipRect(*mainFrameView); ASSERT_TRUE(visibleRect.contains(windowPoint)) << failureContextPos << " Test point not contained in visible area: " << visibleRect.x() << "," << visibleRect.y() << "-" << visibleRect.maxX() << "," << visibleRect.maxY(); // First validate that a hit test at this point will really hit the // element we intended. This is the easiest way for a test to be broken, // but has nothing really to do with touch action. Note that we can't use // WebView's hit test API because it doesn't look into shadow DOM. IntPoint docPoint(mainFrameView->frameToContents(windowPoint)); HitTestResult result = mainFrame->eventHandler().hitTestResultAtPoint( docPoint, HitTestRequest::ReadOnly | HitTestRequest::Active); ASSERT_EQ(element, result.innerElement()) << "Unexpected hit test result " << failureContextPos << " Got element: \"" << result.innerElement() ->outerHTML() .stripWhiteSpace() .left(80) .ascii() .data() << "\"" << std::endl << "Document render tree:" << std::endl << externalRepresentation(root->document().frame()).utf8().data(); // Now send the touch event and check any touch action result. sendTouchEvent(webView, WebInputEvent::TouchStart, windowPoint); AtomicString expectedAction = element->getAttribute("expected-action"); if (expectedAction == "auto") { // Auto is the default - no action set. EXPECT_EQ(0, client.touchActionSetCount()) << failureContextPos; EXPECT_EQ(WebTouchActionAuto, client.lastTouchAction()) << failureContextPos; } else { // Should have received exactly one touch action. EXPECT_EQ(1, client.touchActionSetCount()) << failureContextPos; if (client.touchActionSetCount()) { if (expectedAction == "none") { EXPECT_EQ(WebTouchActionNone, client.lastTouchAction()) << failureContextPos; } else if (expectedAction == "pan-x") { EXPECT_EQ(WebTouchActionPanX, client.lastTouchAction()) << failureContextPos; } else if (expectedAction == "pan-y") { EXPECT_EQ(WebTouchActionPanY, client.lastTouchAction()) << failureContextPos; } else if (expectedAction == "pan-x-y") { EXPECT_EQ((WebTouchActionPan), client.lastTouchAction()) << failureContextPos; } else if (expectedAction == "manipulation") { EXPECT_EQ((WebTouchActionManipulation), client.lastTouchAction()) << failureContextPos; } else { FAIL() << "Unrecognized expected-action \"" << expectedAction.ascii().data() << "\" " << failureContextPos; } } } // Reset webview touch state. client.reset(); sendTouchEvent(webView, WebInputEvent::TouchCancel, windowPoint); EXPECT_EQ(0, client.touchActionSetCount()); } } }
bool PageWidgetEventHandler::handleTouchEvent(LocalFrame& mainFrame, const WebTouchEvent& event) { return mainFrame.eventHandler().handleTouchEvent(PlatformTouchEventBuilder(mainFrame.view(), event)); }
bool PageWidgetEventHandler::handleMouseWheel(LocalFrame& mainFrame, const WebMouseWheelEvent& event) { return mainFrame.eventHandler().handleWheelEvent(PlatformWheelEventBuilder(mainFrame.view(), event)); }
void PageWidgetEventHandler::handleMouseUp(LocalFrame& mainFrame, const WebMouseEvent& event) { mainFrame.eventHandler().handleMouseReleaseEvent(PlatformMouseEventBuilder(mainFrame.view(), event)); }