Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(11)

Unified Diff: sky/engine/core/page/TouchAdjustment.cpp

Issue 774053003: Remove TouchAdjustment. (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « sky/engine/core/page/TouchAdjustment.h ('k') | sky/engine/platform/PlatformGestureEvent.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sky/engine/core/page/TouchAdjustment.cpp
diff --git a/sky/engine/core/page/TouchAdjustment.cpp b/sky/engine/core/page/TouchAdjustment.cpp
deleted file mode 100644
index 64182b648c1e2e3649def80e894145eeede1634d..0000000000000000000000000000000000000000
--- a/sky/engine/core/page/TouchAdjustment.cpp
+++ /dev/null
@@ -1,339 +0,0 @@
-/*
- * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "sky/engine/config.h"
-
-#include "sky/engine/core/page/TouchAdjustment.h"
-
-#include "sky/engine/core/dom/ContainerNode.h"
-#include "sky/engine/core/dom/Node.h"
-#include "sky/engine/core/dom/NodeRenderStyle.h"
-#include "sky/engine/core/dom/Text.h"
-#include "sky/engine/core/editing/Editor.h"
-#include "sky/engine/core/frame/FrameView.h"
-#include "sky/engine/core/frame/LocalFrame.h"
-#include "sky/engine/core/rendering/RenderBox.h"
-#include "sky/engine/core/rendering/RenderObject.h"
-#include "sky/engine/core/rendering/RenderText.h"
-#include "sky/engine/core/rendering/style/RenderStyle.h"
-#include "sky/engine/platform/geometry/FloatPoint.h"
-#include "sky/engine/platform/geometry/FloatQuad.h"
-#include "sky/engine/platform/geometry/IntSize.h"
-#include "sky/engine/platform/text/TextBreakIterator.h"
-
-namespace blink {
-
-namespace TouchAdjustment {
-
-const float zeroTolerance = 1e-6f;
-
-// Class for remembering absolute quads of a target node and what node they represent.
-class SubtargetGeometry {
- ALLOW_ONLY_INLINE_ALLOCATION();
-public:
- SubtargetGeometry(Node* node, const FloatQuad& quad)
- : m_node(node)
- , m_quad(quad)
- { }
-
- Node* node() const { return m_node; }
- FloatQuad quad() const { return m_quad; }
- IntRect boundingBox() const { return m_quad.enclosingBoundingBox(); }
-
-private:
- RawPtr<Node> m_node;
- FloatQuad m_quad;
-};
-
-}
-
-}
-
-WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(blink::TouchAdjustment::SubtargetGeometry)
-
-namespace blink {
-
-namespace TouchAdjustment {
-
-typedef Vector<SubtargetGeometry> SubtargetGeometryList;
-typedef bool (*NodeFilter)(Node*);
-typedef void (*AppendSubtargetsForNode)(Node*, SubtargetGeometryList&);
-typedef float (*DistanceFunction)(const IntPoint&, const IntRect&, const SubtargetGeometry&);
-
-// Takes non-const Node* because isContentEditable is a non-const function.
-bool nodeRespondsToTapGesture(Node* node)
-{
- if (node->willRespondToMouseClickEvents() || node->willRespondToMouseMoveEvents())
- return true;
- if (node->isElementNode()) {
- Element* element = toElement(node);
- // Tapping on a text field or other focusable item should trigger adjustment, except
- // that iframe elements are hard-coded to support focus but the effect is often invisible
- // so they should be excluded.
- if (element->isMouseFocusable())
- return true;
- }
- if (RenderStyle* renderStyle = node->renderStyle()) {
- if (renderStyle->affectedByActive() || renderStyle->affectedByHover())
- return true;
- }
- return false;
-}
-
-static inline void appendQuadsToSubtargetList(Vector<FloatQuad>& quads, Node* node, SubtargetGeometryList& subtargets)
-{
- Vector<FloatQuad>::const_iterator it = quads.begin();
- const Vector<FloatQuad>::const_iterator end = quads.end();
- for (; it != end; ++it)
- subtargets.append(SubtargetGeometry(node, *it));
-}
-
-static inline void appendBasicSubtargetsForNode(Node* node, SubtargetGeometryList& subtargets)
-{
- // Node guaranteed to have renderer due to check in node filter.
- ASSERT(node->renderer());
-
- Vector<FloatQuad> quads;
- node->renderer()->absoluteQuads(quads);
-
- appendQuadsToSubtargetList(quads, node, subtargets);
-}
-
-// Compiles a list of subtargets of all the relevant target nodes.
-void compileSubtargetList(const Vector<RefPtr<Node> >& intersectedNodes, SubtargetGeometryList& subtargets, NodeFilter nodeFilter, AppendSubtargetsForNode appendSubtargetsForNode)
-{
- // Find candidates responding to tap gesture events in O(n) time.
- HashMap<RawPtr<Node>, RawPtr<Node> > responderMap;
- HashSet<RawPtr<Node> > ancestorsToRespondersSet;
- Vector<RawPtr<Node> > candidates;
- HashSet<RawPtr<Node> > editableAncestors;
-
- // A node matching the NodeFilter is called a responder. Candidate nodes must either be a
- // responder or have an ancestor that is a responder.
- // This iteration tests all ancestors at most once by caching earlier results.
- for (unsigned i = 0; i < intersectedNodes.size(); ++i) {
- Node* node = intersectedNodes[i].get();
- Vector<RawPtr<Node> > visitedNodes;
- Node* respondingNode = 0;
- for (Node* visitedNode = node; visitedNode; visitedNode = visitedNode->parentOrShadowHostNode()) {
- // Check if we already have a result for a common ancestor from another candidate.
- respondingNode = responderMap.get(visitedNode);
- if (respondingNode)
- break;
- visitedNodes.append(visitedNode);
- // Check if the node filter applies, which would mean we have found a responding node.
- if (nodeFilter(visitedNode)) {
- respondingNode = visitedNode;
- // Continue the iteration to collect the ancestors of the responder, which we will need later.
- for (visitedNode = visitedNode->parentOrShadowHostNode(); visitedNode; visitedNode = visitedNode->parentOrShadowHostNode()) {
- HashSet<RawPtr<Node> >::AddResult addResult = ancestorsToRespondersSet.add(visitedNode);
- if (!addResult.isNewEntry)
- break;
- }
- break;
- }
- }
- // Insert the detected responder for all the visited nodes.
- for (unsigned j = 0; j < visitedNodes.size(); j++)
- responderMap.add(visitedNodes[j], respondingNode);
-
- if (respondingNode)
- candidates.append(node);
- }
-
- // We compile the list of component absolute quads instead of using the bounding rect
- // to be able to perform better hit-testing on inline links on line-breaks.
- for (unsigned i = 0; i < candidates.size(); i++) {
- Node* candidate = candidates[i];
- // Skip nodes who's responders are ancestors of other responders. This gives preference to
- // the inner-most event-handlers. So that a link is always preferred even when contained
- // in an element that monitors all click-events.
- Node* respondingNode = responderMap.get(candidate);
- ASSERT(respondingNode);
- if (ancestorsToRespondersSet.contains(respondingNode))
- continue;
- // Consolidate bounds for editable content.
- if (editableAncestors.contains(candidate))
- continue;
- if (candidate->isContentEditable()) {
- Node* replacement = candidate;
- Node* parent = candidate->parentOrShadowHostNode();
- while (parent && parent->isContentEditable()) {
- replacement = parent;
- if (editableAncestors.contains(replacement)) {
- replacement = 0;
- break;
- }
- editableAncestors.add(replacement);
- parent = parent->parentOrShadowHostNode();
- }
- candidate = replacement;
- }
- if (candidate)
- appendSubtargetsForNode(candidate, subtargets);
- }
-}
-
-// Uses a hybrid of distance to adjust and intersect ratio, normalizing each score between 0 and 1
-// and combining them. The distance to adjust works best for disambiguating clicks on targets such
-// as links, where the width may be significantly larger than the touch width. Using area of overlap
-// in such cases can lead to a bias towards shorter links. Conversely, percentage of overlap can
-// provide strong confidence in tapping on a small target, where the overlap is often quite high,
-// and works well for tightly packed controls.
-float hybridDistanceFunction(const IntPoint& touchHotspot, const IntRect& touchRect, const SubtargetGeometry& subtarget)
-{
- IntRect rect = subtarget.boundingBox();
-
- // Convert from frame coordinates to window coordinates.
- rect = subtarget.node()->document().view()->contentsToWindow(rect);
-
- float radiusSquared = 0.25f * (touchRect.size().diagonalLengthSquared());
- float distanceToAdjustScore = rect.distanceSquaredToPoint(touchHotspot) / radiusSquared;
-
- int maxOverlapWidth = std::min(touchRect.width(), rect.width());
- int maxOverlapHeight = std::min(touchRect.height(), rect.height());
- float maxOverlapArea = std::max(maxOverlapWidth * maxOverlapHeight, 1);
- rect.intersect(touchRect);
- float intersectArea = rect.size().area();
- float intersectionScore = 1 - intersectArea / maxOverlapArea;
-
- float hybridScore = intersectionScore + distanceToAdjustScore;
-
- return hybridScore;
-}
-
-FloatPoint contentsToWindow(FrameView *view, FloatPoint pt)
-{
- int x = static_cast<int>(pt.x() + 0.5f);
- int y = static_cast<int>(pt.y() + 0.5f);
- IntPoint adjusted = view->contentsToWindow(IntPoint(x, y));
- return FloatPoint(adjusted.x(), adjusted.y());
-}
-
-// Adjusts 'point' to the nearest point inside rect, and leaves it unchanged if already inside.
-void adjustPointToRect(FloatPoint& point, const FloatRect& rect)
-{
- if (point.x() < rect.x())
- point.setX(rect.x());
- else if (point.x() > rect.maxX())
- point.setX(rect.maxX());
-
- if (point.y() < rect.y())
- point.setY(rect.y());
- else if (point.y() > rect.maxY())
- point.setY(rect.maxY());
-}
-
-bool snapTo(const SubtargetGeometry& geom, const IntPoint& touchPoint, const IntRect& touchArea, IntPoint& adjustedPoint)
-{
- FrameView* view = geom.node()->document().view();
- FloatQuad quad = geom.quad();
-
- if (quad.isRectilinear()) {
- IntRect contentBounds = geom.boundingBox();
- // Convert from frame coordinates to window coordinates.
- IntRect bounds = view->contentsToWindow(contentBounds);
- if (bounds.contains(touchPoint)) {
- adjustedPoint = touchPoint;
- return true;
- }
- if (bounds.intersects(touchArea)) {
- bounds.intersect(touchArea);
- adjustedPoint = bounds.center();
- return true;
- }
- return false;
- }
-
- // The following code tries to adjust the point to place inside a both the touchArea and the non-rectilinear quad.
- // FIXME: This will return the point inside the touch area that is the closest to the quad center, but does not
- // guarantee that the point will be inside the quad. Corner-cases exist where the quad will intersect but this
- // will fail to adjust the point to somewhere in the intersection.
-
- // Convert quad from content to window coordinates.
- FloatPoint p1 = contentsToWindow(view, quad.p1());
- FloatPoint p2 = contentsToWindow(view, quad.p2());
- FloatPoint p3 = contentsToWindow(view, quad.p3());
- FloatPoint p4 = contentsToWindow(view, quad.p4());
- quad = FloatQuad(p1, p2, p3, p4);
-
- if (quad.containsPoint(touchPoint)) {
- adjustedPoint = touchPoint;
- return true;
- }
-
- // Pull point towards the center of the element.
- FloatPoint center = quad.center();
-
- adjustPointToRect(center, touchArea);
- adjustedPoint = roundedIntPoint(center);
-
- return quad.containsPoint(adjustedPoint);
-}
-
-// A generic function for finding the target node with the lowest distance metric. A distance metric here is the result
-// of a distance-like function, that computes how well the touch hits the node.
-// Distance functions could for instance be distance squared or area of intersection.
-bool findNodeWithLowestDistanceMetric(Node*& targetNode, IntPoint& targetPoint, IntRect& targetArea, const IntPoint& touchHotspot, const IntRect& touchArea, SubtargetGeometryList& subtargets, DistanceFunction distanceFunction)
-{
- targetNode = 0;
- float bestDistanceMetric = std::numeric_limits<float>::infinity();
- SubtargetGeometryList::const_iterator it = subtargets.begin();
- const SubtargetGeometryList::const_iterator end = subtargets.end();
- IntPoint adjustedPoint;
-
- for (; it != end; ++it) {
- Node* node = it->node();
- float distanceMetric = distanceFunction(touchHotspot, touchArea, *it);
- if (distanceMetric < bestDistanceMetric) {
- if (snapTo(*it, touchHotspot, touchArea, adjustedPoint)) {
- targetPoint = adjustedPoint;
- targetArea = it->boundingBox();
- targetNode = node;
- bestDistanceMetric = distanceMetric;
- }
- } else if (distanceMetric - bestDistanceMetric < zeroTolerance) {
- if (snapTo(*it, touchHotspot, touchArea, adjustedPoint)) {
- if (node->isDescendantOf(targetNode)) {
- // Try to always return the inner-most element.
- targetPoint = adjustedPoint;
- targetNode = node;
- targetArea = it->boundingBox();
- }
- }
- }
- }
-
- if (targetNode) {
- targetArea = targetNode->document().view()->contentsToWindow(targetArea);
- }
- return (targetNode);
-}
-
-} // namespace TouchAdjustment
-
-bool findBestClickableCandidate(Node*& targetNode, IntPoint& targetPoint, const IntPoint& touchHotspot, const IntRect& touchArea, const Vector<RefPtr<Node> >& nodes)
-{
- IntRect targetArea;
- TouchAdjustment::SubtargetGeometryList subtargets;
- TouchAdjustment::compileSubtargetList(nodes, subtargets, TouchAdjustment::nodeRespondsToTapGesture, TouchAdjustment::appendBasicSubtargetsForNode);
- return TouchAdjustment::findNodeWithLowestDistanceMetric(targetNode, targetPoint, targetArea, touchHotspot, touchArea, subtargets, TouchAdjustment::hybridDistanceFunction);
-}
-
-} // namespace blink
« no previous file with comments | « sky/engine/core/page/TouchAdjustment.h ('k') | sky/engine/platform/PlatformGestureEvent.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698