mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
The Sky engine doesn't respond to gesture events itself. Instead, the framework will listen for gestures and respond to them. That means moving GestureEvents over to the NewEventDispatcher is relatively straightforward. R=eseidel@google.com, eseidel@chromium.org Review URL: https://codereview.chromium.org/874823002
168 lines
6.2 KiB
C++
168 lines
6.2 KiB
C++
// Copyright 2015 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "sky/engine/config.h"
|
|
#include "sky/engine/core/frame/NewEventHandler.h"
|
|
|
|
#include "sky/engine/core/dom/Document.h"
|
|
#include "sky/engine/core/dom/NodeRenderingTraversal.h"
|
|
#include "sky/engine/core/editing/Editor.h"
|
|
#include "sky/engine/core/editing/FrameSelection.h"
|
|
#include "sky/engine/core/editing/htmlediting.h"
|
|
#include "sky/engine/core/events/GestureEvent.h"
|
|
#include "sky/engine/core/events/PointerEvent.h"
|
|
#include "sky/engine/core/frame/LocalFrame.h"
|
|
#include "sky/engine/core/frame/FrameView.h"
|
|
#include "sky/engine/core/page/EventWithHitTestResults.h"
|
|
#include "sky/engine/core/rendering/RenderObject.h"
|
|
#include "sky/engine/core/rendering/RenderView.h"
|
|
#include "sky/engine/platform/geometry/FloatPoint.h"
|
|
#include "sky/engine/public/platform/WebInputEvent.h"
|
|
|
|
namespace blink {
|
|
|
|
static VisiblePosition visiblePositionForHitTestResult(const HitTestResult& hitTestResult)
|
|
{
|
|
Node* innerNode = hitTestResult.innerNode();
|
|
VisiblePosition position(innerNode->renderer()->positionForPoint(hitTestResult.localPoint()));
|
|
if (!position.isNull())
|
|
return position;
|
|
return VisiblePosition(firstPositionInOrBeforeNode(innerNode), DOWNSTREAM);
|
|
}
|
|
|
|
template<typename EventType>
|
|
static LayoutPoint positionForEvent(const EventType& event)
|
|
{
|
|
return roundedLayoutPoint(FloatPoint(event.x, event.y));
|
|
}
|
|
|
|
NewEventHandler::NewEventHandler(LocalFrame& frame)
|
|
: m_frame(frame)
|
|
{
|
|
}
|
|
|
|
NewEventHandler::~NewEventHandler()
|
|
{
|
|
}
|
|
|
|
Node* NewEventHandler::targetForHitTestResult(const HitTestResult& hitTestResult)
|
|
{
|
|
Node* node = hitTestResult.innerNode();
|
|
if (!node)
|
|
return m_frame.document();
|
|
if (node->isTextNode())
|
|
return NodeRenderingTraversal::parent(node);
|
|
return node;
|
|
}
|
|
|
|
HitTestResult NewEventHandler::performHitTest(const LayoutPoint& point)
|
|
{
|
|
HitTestResult result(point);
|
|
if (!m_frame.contentRenderer())
|
|
return result;
|
|
m_frame.contentRenderer()->hitTest(HitTestRequest(HitTestRequest::ReadOnly), result);
|
|
return result;
|
|
}
|
|
|
|
bool NewEventHandler::dispatchPointerEvent(Node& target, const WebPointerEvent& event)
|
|
{
|
|
RefPtr<PointerEvent> pointerEvent = PointerEvent::create(event);
|
|
// TODO(abarth): Keep track of how many pointers are targeting the same node
|
|
// and only mark the first one as primary.
|
|
return target.dispatchEvent(pointerEvent.release());
|
|
}
|
|
|
|
bool NewEventHandler::dispatchGestureEvent(Node& target, const WebGestureEvent& event)
|
|
{
|
|
RefPtr<GestureEvent> gestureEvent = GestureEvent::create(event);
|
|
return target.dispatchEvent(gestureEvent.release());
|
|
}
|
|
|
|
bool NewEventHandler::dispatchClickEvent(Node& capturingTarget, const WebPointerEvent& event)
|
|
{
|
|
ASSERT(event.type == WebInputEvent::PointerUp);
|
|
HitTestResult hitTestResult = performHitTest(positionForEvent(event));
|
|
Node* releaseTarget = targetForHitTestResult(hitTestResult);
|
|
Node* clickTarget = NodeRenderingTraversal::commonAncestor(*releaseTarget, capturingTarget);
|
|
if (!clickTarget)
|
|
return true;
|
|
// TODO(abarth): Make a proper gesture event that includes information from the event.
|
|
return clickTarget->dispatchEvent(Event::createCancelableBubble(EventTypeNames::click));
|
|
}
|
|
|
|
void NewEventHandler::updateSelectionForPointerDown(const HitTestResult& hitTestResult, const WebPointerEvent& event)
|
|
{
|
|
Node* innerNode = hitTestResult.innerNode();
|
|
if (!innerNode->renderer())
|
|
return;
|
|
if (Position::nodeIsUserSelectNone(innerNode))
|
|
return;
|
|
if (!innerNode->dispatchEvent(Event::createCancelableBubble(EventTypeNames::selectstart)))
|
|
return;
|
|
VisiblePosition position = visiblePositionForHitTestResult(hitTestResult);
|
|
// TODO(abarth): Can we change this to setSelectionIfNeeded?
|
|
m_frame.selection().setNonDirectionalSelectionIfNeeded(VisibleSelection(position), CharacterGranularity);
|
|
}
|
|
|
|
bool NewEventHandler::handlePointerEvent(const WebPointerEvent& event)
|
|
{
|
|
if (event.type == WebInputEvent::PointerDown)
|
|
return handlePointerDownEvent(event);
|
|
if (event.type == WebInputEvent::PointerUp)
|
|
return handlePointerUpEvent(event);
|
|
if (event.type == WebInputEvent::PointerMove)
|
|
return handlePointerMoveEvent(event);
|
|
ASSERT(event.type == WebInputEvent::PointerCancel);
|
|
return handlePointerCancelEvent(event);
|
|
}
|
|
|
|
bool NewEventHandler::handleGestureEvent(const WebGestureEvent& event)
|
|
{
|
|
HitTestResult hitTestResult = performHitTest(positionForEvent(event));
|
|
RefPtr<Node> target = targetForHitTestResult(hitTestResult);
|
|
return !dispatchGestureEvent(*target, event);
|
|
}
|
|
|
|
bool NewEventHandler::handlePointerDownEvent(const WebPointerEvent& event)
|
|
{
|
|
ASSERT(m_targetForPointer.find(event.pointer) == m_targetForPointer.end());
|
|
HitTestResult hitTestResult = performHitTest(positionForEvent(event));
|
|
RefPtr<Node> target = targetForHitTestResult(hitTestResult);
|
|
m_targetForPointer[event.pointer] = target;
|
|
bool eventSwallowed = !dispatchPointerEvent(*target, event);
|
|
// TODO(abarth): Set the target for the pointer to something determined when
|
|
// dispatching the event.
|
|
updateSelectionForPointerDown(hitTestResult, event);
|
|
return eventSwallowed;
|
|
}
|
|
|
|
bool NewEventHandler::handlePointerUpEvent(const WebPointerEvent& event)
|
|
{
|
|
RefPtr<Node> target = m_targetForPointer[event.pointer];
|
|
if (!target)
|
|
return false;
|
|
m_targetForPointer.erase(event.pointer);
|
|
bool eventSwallowed = !dispatchPointerEvent(*target, event);
|
|
// When the user releases the primary pointer, we need to dispatch a tap
|
|
// event to the common ancestor for where the pointer went down and where
|
|
// it came up.
|
|
if (!dispatchClickEvent(*target, event))
|
|
eventSwallowed = true;
|
|
return eventSwallowed;
|
|
}
|
|
|
|
bool NewEventHandler::handlePointerMoveEvent(const WebPointerEvent& event)
|
|
{
|
|
RefPtr<Node> target = m_targetForPointer[event.pointer];
|
|
return target && dispatchPointerEvent(*target.get(), event);
|
|
}
|
|
|
|
bool NewEventHandler::handlePointerCancelEvent(const WebPointerEvent& event)
|
|
{
|
|
RefPtr<Node> target = m_targetForPointer[event.pointer];
|
|
return target && dispatchPointerEvent(*target, event);
|
|
}
|
|
|
|
}
|