blob: 9663f68e8914529541d78aa727db924869323c8e [file] [log] [blame]
commit-queue@webkit.org294ddcd2012-03-19 15:33:26 +00001/*
2 * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20#include "config.h"
21
22#include "TouchAdjustment.h"
23
24#include "ContainerNode.h"
25#include "FloatPoint.h"
26#include "FloatQuad.h"
commit-queue@webkit.org8b79f632012-03-23 12:23:57 +000027#include "FrameView.h"
commit-queue@webkit.org5d423222012-07-27 21:49:36 +000028#include "HTMLInputElement.h"
commit-queue@webkit.org294ddcd2012-03-19 15:33:26 +000029#include "HTMLLabelElement.h"
30#include "HTMLNames.h"
31#include "IntPoint.h"
32#include "IntSize.h"
33#include "Node.h"
ahf@0x90.dke2851952012-03-19 17:09:53 +000034#include "NodeRenderStyle.h"
commit-queue@webkit.org294ddcd2012-03-19 15:33:26 +000035#include "RenderBox.h"
36#include "RenderObject.h"
37#include "RenderStyle.h"
allan.jensen@nokia.comdbb31192012-08-22 10:23:55 +000038#include "RenderText.h"
commit-queue@webkit.orgcfdf5932012-07-27 17:59:36 +000039#include "ShadowRoot.h"
allan.jensen@nokia.comdbb31192012-08-22 10:23:55 +000040#include "Text.h"
41#include "TextBreakIterator.h"
commit-queue@webkit.org294ddcd2012-03-19 15:33:26 +000042
43namespace WebCore {
44
45namespace TouchAdjustment {
46
commit-queue@webkit.orgcfdf5932012-07-27 17:59:36 +000047const float zeroTolerance = 1e-6f;
48
commit-queue@webkit.org294ddcd2012-03-19 15:33:26 +000049// Class for remembering absolute quads of a target node and what node they represent.
50class SubtargetGeometry {
51public:
52 SubtargetGeometry(Node* node, const FloatQuad& quad)
53 : m_node(node)
54 , m_quad(quad)
55 { }
56
57 Node* node() const { return m_node; }
58 FloatQuad quad() const { return m_quad; }
59 IntRect boundingBox() const { return m_quad.enclosingBoundingBox(); }
60
61private:
62 Node* m_node;
63 FloatQuad m_quad;
64};
65
66typedef Vector<SubtargetGeometry> SubtargetGeometryList;
67typedef bool (*NodeFilter)(Node*);
allan.jensen@nokia.comdbb31192012-08-22 10:23:55 +000068typedef void (*AppendSubtargetsForNode)(Node*, SubtargetGeometryList&);
commit-queue@webkit.org294ddcd2012-03-19 15:33:26 +000069typedef float (*DistanceFunction)(const IntPoint&, const IntRect&, const SubtargetGeometry&);
70
71// Takes non-const Node* because isContentEditable is a non-const function.
72bool nodeRespondsToTapGesture(Node* node)
73{
allan.jensen@nokia.comd4a972d2012-07-30 13:33:14 +000074 if (node->isMouseFocusable())
commit-queue@webkit.org294ddcd2012-03-19 15:33:26 +000075 return true;
allan.jensen@nokia.comd4a972d2012-07-30 13:33:14 +000076 if (node->willRespondToMouseClickEvents() || node->willRespondToMouseMoveEvents())
commit-queue@webkit.org294ddcd2012-03-19 15:33:26 +000077 return true;
78 if (node->renderStyle()) {
79 // Accept nodes that has a CSS effect when touched.
80 if (node->renderStyle()->affectedByActiveRules() || node->renderStyle()->affectedByHoverRules())
81 return true;
82 }
83 return false;
84}
85
commit-queue@webkit.org6b849432012-03-30 15:47:04 +000086bool nodeIsZoomTarget(Node* node)
87{
88 if (node->isTextNode() || node->isShadowRoot())
89 return false;
90
91 ASSERT(node->renderer());
92 return node->renderer()->isBox();
93}
94
allan.jensen@nokia.com4a470ad2012-08-17 14:31:56 +000095bool providesContextMenuItems(Node* node)
96{
97 // This function tries to match the nodes that receive special context-menu items in
98 // ContextMenuController::populate(), and should be kept uptodate with those.
commit-queue@webkit.org7d426d82012-09-11 20:36:16 +000099 ASSERT(node->renderer() || node->isShadowRoot());
100 if (!node->renderer())
101 return false;
allan.jensen@nokia.com4a470ad2012-08-17 14:31:56 +0000102 if (node->isContentEditable())
103 return true;
104 if (node->isLink())
105 return true;
106 if (node->renderer()->isImage())
107 return true;
108 if (node->renderer()->isMedia())
109 return true;
110 if (node->renderer()->canBeSelectionLeaf()) {
allan.jensen@nokia.comdbb31192012-08-22 10:23:55 +0000111 // If the context menu gesture will trigger a selection all selectable nodes are valid targets.
allan.jensen@nokia.com4a470ad2012-08-17 14:31:56 +0000112 if (node->renderer()->frame()->editor()->behavior().shouldSelectOnContextualMenuClick())
113 return true;
allan.jensen@nokia.comdbb31192012-08-22 10:23:55 +0000114 // Only the selected part of the renderer is a valid target, but this will be corrected in
115 // appendContextSubtargetsForNode.
allan.jensen@nokia.com4a470ad2012-08-17 14:31:56 +0000116 if (node->renderer()->selectionState() != RenderObject::SelectionNone)
117 return true;
118 }
119 return false;
120}
121
allan.jensen@nokia.comdbb31192012-08-22 10:23:55 +0000122static inline void appendQuadsToSubtargetList(Vector<FloatQuad>& quads, Node* node, SubtargetGeometryList& subtargets)
123{
124 Vector<FloatQuad>::const_iterator it = quads.begin();
125 const Vector<FloatQuad>::const_iterator end = quads.end();
126 for (; it != end; ++it)
127 subtargets.append(SubtargetGeometry(node, *it));
128}
129
130static inline void appendBasicSubtargetsForNode(Node* node, SubtargetGeometryList& subtargets)
commit-queue@webkit.org294ddcd2012-03-19 15:33:26 +0000131{
commit-queue@webkit.org7d426d82012-09-11 20:36:16 +0000132 // Node guaranteed to have renderer due to check in node filter.
commit-queue@webkit.org294ddcd2012-03-19 15:33:26 +0000133 ASSERT(node->renderer());
134
135 Vector<FloatQuad> quads;
136 node->renderer()->absoluteQuads(quads);
137
allan.jensen@nokia.comdbb31192012-08-22 10:23:55 +0000138 appendQuadsToSubtargetList(quads, node, subtargets);
139}
140
141static inline void appendContextSubtargetsForNode(Node* node, SubtargetGeometryList& subtargets)
142{
143 // This is a variant of appendBasicSubtargetsForNode that adds special subtargets for
144 // selected or auto-selectable parts of text nodes.
145 ASSERT(node->renderer());
146
147 if (!node->isTextNode())
148 return appendBasicSubtargetsForNode(node, subtargets);
149
150 Text* textNode = static_cast<WebCore::Text*>(node);
151 RenderText* textRenderer = static_cast<RenderText*>(textNode->renderer());
152
153 if (textRenderer->frame()->editor()->behavior().shouldSelectOnContextualMenuClick()) {
154 // Make subtargets out of every word.
155 String textValue = textNode->data();
156 TextBreakIterator* wordIterator = wordBreakIterator(textValue.characters(), textValue.length());
157 int lastOffset = textBreakFirst(wordIterator);
158 if (lastOffset == -1)
159 return;
160 int offset;
161 while ((offset = textBreakNext(wordIterator)) != -1) {
162 if (isWordTextBreak(wordIterator)) {
163 Vector<FloatQuad> quads;
164 textRenderer->absoluteQuadsForRange(quads, lastOffset, offset);
165 appendQuadsToSubtargetList(quads, textNode, subtargets);
166 }
167 lastOffset = offset;
168 }
169 } else {
170 if (textRenderer->selectionState() == RenderObject::SelectionNone)
171 return appendBasicSubtargetsForNode(node, subtargets);
172 // If selected, make subtargets out of only the selected part of the text.
173 int startPos, endPos;
174 switch (textRenderer->selectionState()) {
175 case RenderObject::SelectionInside:
176 startPos = 0;
177 endPos = textRenderer->textLength();
178 break;
179 case RenderObject::SelectionStart:
180 textRenderer->selectionStartEnd(startPos, endPos);
181 endPos = textRenderer->textLength();
182 break;
183 case RenderObject::SelectionEnd:
184 textRenderer->selectionStartEnd(startPos, endPos);
185 startPos = 0;
186 break;
187 case RenderObject::SelectionBoth:
188 textRenderer->selectionStartEnd(startPos, endPos);
189 break;
190 default:
191 ASSERT_NOT_REACHED();
192 return;
193 }
194 Vector<FloatQuad> quads;
195 textRenderer->absoluteQuadsForRange(quads, startPos, endPos);
196 appendQuadsToSubtargetList(quads, textNode, subtargets);
197 }
commit-queue@webkit.org294ddcd2012-03-19 15:33:26 +0000198}
199
commit-queue@webkit.org6b849432012-03-30 15:47:04 +0000200static inline void appendZoomableSubtargets(Node* node, SubtargetGeometryList& subtargets)
201{
202 RenderBox* renderer = toRenderBox(node->renderer());
203 ASSERT(renderer);
204
205 Vector<FloatQuad> quads;
206 FloatRect borderBoxRect = renderer->borderBoxRect();
207 FloatRect contentBoxRect = renderer->contentBoxRect();
208 quads.append(renderer->localToAbsoluteQuad(borderBoxRect));
209 if (borderBoxRect != contentBoxRect)
210 quads.append(renderer->localToAbsoluteQuad(contentBoxRect));
211 // FIXME: For RenderBlocks, add column boxes and content boxes cleared for floats.
212
213 Vector<FloatQuad>::const_iterator it = quads.begin();
214 const Vector<FloatQuad>::const_iterator end = quads.end();
215 for (; it != end; ++it)
216 subtargets.append(SubtargetGeometry(node, *it));
217}
218
commit-queue@webkit.org294ddcd2012-03-19 15:33:26 +0000219// Compiles a list of subtargets of all the relevant target nodes.
allan.jensen@nokia.comdbb31192012-08-22 10:23:55 +0000220void compileSubtargetList(const NodeList& intersectedNodes, SubtargetGeometryList& subtargets, NodeFilter nodeFilter, AppendSubtargetsForNode appendSubtargetsForNode)
commit-queue@webkit.org294ddcd2012-03-19 15:33:26 +0000221{
222 // Find candidates responding to tap gesture events in O(n) time.
223 HashMap<Node*, Node*> responderMap;
224 HashSet<Node*> ancestorsToRespondersSet;
225 Vector<Node*> candidates;
226
227 // A node matching the NodeFilter is called a responder. Candidate nodes must either be a
228 // responder or have an ancestor that is a responder.
229 // This iteration tests all ancestors at most once by caching earlier results.
230 unsigned length = intersectedNodes.length();
231 for (unsigned i = 0; i < length; ++i) {
232 Node* const node = intersectedNodes.item(i);
commit-queue@webkit.org294ddcd2012-03-19 15:33:26 +0000233 Vector<Node*> visitedNodes;
234 Node* respondingNode = 0;
235 for (Node* visitedNode = node; visitedNode; visitedNode = visitedNode->parentOrHostNode()) {
236 // Check if we already have a result for a common ancestor from another candidate.
237 respondingNode = responderMap.get(visitedNode);
238 if (respondingNode)
239 break;
240 visitedNodes.append(visitedNode);
241 // Check if the node filter applies, which would mean we have found a responding node.
242 if (nodeFilter(visitedNode)) {
243 respondingNode = visitedNode;
244 // Continue the iteration to collect the ancestors of the responder, which we will need later.
245 for (visitedNode = visitedNode->parentOrHostNode(); visitedNode; visitedNode = visitedNode->parentOrHostNode()) {
caio.oliveira@openbossa.org4c11ee02012-03-29 18:48:23 +0000246 HashSet<Node*>::AddResult addResult = ancestorsToRespondersSet.add(visitedNode);
247 if (!addResult.isNewEntry)
commit-queue@webkit.org294ddcd2012-03-19 15:33:26 +0000248 break;
249 }
250 break;
251 }
252 }
253 // Insert the detected responder for all the visited nodes.
254 for (unsigned j = 0; j < visitedNodes.size(); j++)
255 responderMap.add(visitedNodes[j], respondingNode);
256
257 if (respondingNode)
258 candidates.append(node);
259 }
260
261 // We compile the list of component absolute quads instead of using the bounding rect
262 // to be able to perform better hit-testing on inline links on line-breaks.
263 length = candidates.size();
264 for (unsigned i = 0; i < length; i++) {
265 Node* candidate = candidates[i];
266 // Skip nodes who's responders are ancestors of other responders. This gives preference to
267 // the inner-most event-handlers. So that a link is always preferred even when contained
268 // in an element that monitors all click-events.
269 Node* respondingNode = responderMap.get(candidate);
270 ASSERT(respondingNode);
271 if (ancestorsToRespondersSet.contains(respondingNode))
272 continue;
allan.jensen@nokia.comdbb31192012-08-22 10:23:55 +0000273 appendSubtargetsForNode(candidate, subtargets);
commit-queue@webkit.org294ddcd2012-03-19 15:33:26 +0000274 }
275}
276
commit-queue@webkit.org6b849432012-03-30 15:47:04 +0000277// Compiles a list of zoomable subtargets.
278void compileZoomableSubtargets(const NodeList& intersectedNodes, SubtargetGeometryList& subtargets)
279{
280 unsigned length = intersectedNodes.length();
281 for (unsigned i = 0; i < length; ++i) {
282 Node* const candidate = intersectedNodes.item(i);
283 if (nodeIsZoomTarget(candidate))
284 appendZoomableSubtargets(candidate, subtargets);
285 }
286}
287
commit-queue@webkit.org98364e92012-04-04 12:47:54 +0000288// This returns quotient of the target area and its intersection with the touch area.
289// This will prioritize largest intersection and smallest area, while balancing the two against each other.
290float zoomableIntersectionQuotient(const IntPoint& touchHotspot, const IntRect& touchArea, const SubtargetGeometry& subtarget)
commit-queue@webkit.org6b849432012-03-30 15:47:04 +0000291{
commit-queue@webkit.org6b849432012-03-30 15:47:04 +0000292 IntRect rect = subtarget.boundingBox();
293
294 // Convert from frame coordinates to window coordinates.
295 rect = subtarget.node()->document()->view()->contentsToWindow(rect);
commit-queue@webkit.org6b849432012-03-30 15:47:04 +0000296
commit-queue@webkit.org98364e92012-04-04 12:47:54 +0000297 // Check the rectangle is meaningful zoom target. It should at least contain the hotspot.
298 if (!rect.contains(touchHotspot))
commit-queue@webkit.org83ccf412012-05-15 19:58:56 +0000299 return std::numeric_limits<float>::infinity();
commit-queue@webkit.org98364e92012-04-04 12:47:54 +0000300 IntRect intersection = rect;
301 intersection.intersect(touchArea);
302
303 // Return the quotient of the intersection.
304 return rect.size().area() / (float)intersection.size().area();
commit-queue@webkit.org6b849432012-03-30 15:47:04 +0000305}
306
allan.jensen@nokia.com467af092012-09-20 08:44:43 +0000307// Uses a hybrid of distance to adjust and intersect ratio, normalizing each score between 0 and 1
308// and combining them. The distance to adjust works best for disambiguating clicks on targets such
309// as links, where the width may be significantly larger than the touch width. Using area of overlap
310// in such cases can lead to a bias towards shorter links. Conversely, percentage of overlap can
311// provide strong confidence in tapping on a small target, where the overlap is often quite high,
312// and works well for tightly packed controls.
313float hybridDistanceFunction(const IntPoint& touchHotspot, const IntRect& touchRect, const SubtargetGeometry& subtarget)
commit-queue@webkit.orgcfdf5932012-07-27 17:59:36 +0000314{
315 IntRect rect = subtarget.boundingBox();
316
317 // Convert from frame coordinates to window coordinates.
318 rect = subtarget.node()->document()->view()->contentsToWindow(rect);
319
allan.jensen@nokia.com467af092012-09-20 08:44:43 +0000320 float radiusSquared = 0.25f * (touchRect.size().diagonalLengthSquared());
321 float distanceToAdjustScore = rect.distanceSquaredToPoint(touchHotspot) / radiusSquared;
commit-queue@webkit.orgcfdf5932012-07-27 17:59:36 +0000322
323 float targetArea = rect.size().area();
allan.jensen@nokia.com467af092012-09-20 08:44:43 +0000324 rect.intersect(touchRect);
commit-queue@webkit.orgcfdf5932012-07-27 17:59:36 +0000325 float intersectArea = rect.size().area();
326 float intersectionScore = 1 - intersectArea / targetArea;
327
allan.jensen@nokia.com467af092012-09-20 08:44:43 +0000328 float hybridScore = intersectionScore + distanceToAdjustScore;
329
330 return hybridScore;
commit-queue@webkit.orgcfdf5932012-07-27 17:59:36 +0000331}
332
commit-queue@webkit.org0e667c42012-07-18 14:47:40 +0000333FloatPoint contentsToWindow(FrameView *view, FloatPoint pt)
334{
335 int x = static_cast<int>(pt.x() + 0.5f);
336 int y = static_cast<int>(pt.y() + 0.5f);
337 IntPoint adjusted = view->contentsToWindow(IntPoint(x, y));
338 return FloatPoint(adjusted.x(), adjusted.y());
339}
340
allan.jensen@nokia.combc7608c2012-09-17 15:02:41 +0000341// Adjusts 'point' to the nearest point inside rect, and leaves it unchanged if already inside.
342void adjustPointToRect(FloatPoint& point, const FloatRect& rect)
343{
344 if (point.x() < rect.x())
345 point.setX(rect.x());
346 else if (point.x() > rect.maxX())
347 point.setX(rect.maxX());
348
349 if (point.y() < rect.y())
350 point.setY(rect.y());
351 else if (point.y() > rect.maxY())
352 point.setY(rect.maxY());
353}
354
commit-queue@webkit.org0e667c42012-07-18 14:47:40 +0000355bool snapTo(const SubtargetGeometry& geom, const IntPoint& touchPoint, const IntRect& touchArea, IntPoint& adjustedPoint)
356{
357 FrameView* view = geom.node()->document()->view();
358 FloatQuad quad = geom.quad();
359
360 if (quad.isRectilinear()) {
361 IntRect contentBounds = geom.boundingBox();
362 // Convert from frame coordinates to window coordinates.
363 IntRect bounds = view->contentsToWindow(contentBounds);
364 if (bounds.contains(touchPoint)) {
365 adjustedPoint = touchPoint;
366 return true;
367 }
368 if (bounds.intersects(touchArea)) {
369 bounds.intersect(touchArea);
370 adjustedPoint = bounds.center();
371 return true;
372 }
373 return false;
374 }
375
allan.jensen@nokia.combc7608c2012-09-17 15:02:41 +0000376 // The following code tries to adjust the point to place inside a both the touchArea and the non-rectilinear quad.
377 // FIXME: This will return the point inside the touch area that is the closest to the quad center, but does not
378 // guarantee that the point will be inside the quad. Corner-cases exist where the quad will intersect but this
379 // will fail to adjust the point to somewhere in the intersection.
380
commit-queue@webkit.org0e667c42012-07-18 14:47:40 +0000381 // Convert quad from content to window coordinates.
382 FloatPoint p1 = contentsToWindow(view, quad.p1());
383 FloatPoint p2 = contentsToWindow(view, quad.p2());
384 FloatPoint p3 = contentsToWindow(view, quad.p3());
385 FloatPoint p4 = contentsToWindow(view, quad.p4());
386 quad = FloatQuad(p1, p2, p3, p4);
387
388 if (quad.containsPoint(touchPoint)) {
389 adjustedPoint = touchPoint;
390 return true;
391 }
392
393 // Pull point towards the center of the element.
allan.jensen@nokia.combc7608c2012-09-17 15:02:41 +0000394 FloatPoint center = quad.center();
commit-queue@webkit.org0e667c42012-07-18 14:47:40 +0000395
allan.jensen@nokia.combc7608c2012-09-17 15:02:41 +0000396 adjustPointToRect(center, touchArea);
397 adjustedPoint = roundedIntPoint(center);
commit-queue@webkit.org0e667c42012-07-18 14:47:40 +0000398
allan.jensen@nokia.combc7608c2012-09-17 15:02:41 +0000399 return quad.containsPoint(adjustedPoint);
commit-queue@webkit.org0e667c42012-07-18 14:47:40 +0000400}
commit-queue@webkit.org6b849432012-03-30 15:47:04 +0000401
commit-queue@webkit.org294ddcd2012-03-19 15:33:26 +0000402// A generic function for finding the target node with the lowest distance metric. A distance metric here is the result
403// of a distance-like function, that computes how well the touch hits the node.
404// Distance functions could for instance be distance squared or area of intersection.
commit-queue@webkit.org98364e92012-04-04 12:47:54 +0000405bool findNodeWithLowestDistanceMetric(Node*& targetNode, IntPoint& targetPoint, IntRect& targetArea, const IntPoint& touchHotspot, const IntRect& touchArea, SubtargetGeometryList& subtargets, DistanceFunction distanceFunction)
commit-queue@webkit.org294ddcd2012-03-19 15:33:26 +0000406{
407 targetNode = 0;
commit-queue@webkit.org83ccf412012-05-15 19:58:56 +0000408 float bestDistanceMetric = std::numeric_limits<float>::infinity();
commit-queue@webkit.org294ddcd2012-03-19 15:33:26 +0000409 SubtargetGeometryList::const_iterator it = subtargets.begin();
410 const SubtargetGeometryList::const_iterator end = subtargets.end();
commit-queue@webkit.org0e667c42012-07-18 14:47:40 +0000411 IntPoint adjustedPoint;
commit-queue@webkit.orgcfdf5932012-07-27 17:59:36 +0000412
commit-queue@webkit.org294ddcd2012-03-19 15:33:26 +0000413 for (; it != end; ++it) {
414 Node* node = it->node();
415 float distanceMetric = distanceFunction(touchHotspot, touchArea, *it);
416 if (distanceMetric < bestDistanceMetric) {
commit-queue@webkit.org0e667c42012-07-18 14:47:40 +0000417 if (snapTo(*it, touchHotspot, touchArea, adjustedPoint)) {
418 targetPoint = adjustedPoint;
419 targetArea = it->boundingBox();
420 targetNode = node;
421 bestDistanceMetric = distanceMetric;
422 }
commit-queue@webkit.orgcfdf5932012-07-27 17:59:36 +0000423 } else if (distanceMetric - bestDistanceMetric < zeroTolerance) {
424 if (snapTo(*it, touchHotspot, touchArea, adjustedPoint)) {
425 if (node->isDescendantOf(targetNode)) {
426 // Try to always return the inner-most element.
427 targetPoint = adjustedPoint;
428 targetNode = node;
429 targetArea = it->boundingBox();
commit-queue@webkit.orgcfdf5932012-07-27 17:59:36 +0000430 }
commit-queue@webkit.org6b849432012-03-30 15:47:04 +0000431 }
432 }
433 }
commit-queue@webkit.org6b32da32012-05-10 16:17:53 +0000434 if (targetNode) {
435 targetArea = targetNode->document()->view()->contentsToWindow(targetArea);
commit-queue@webkit.org6b32da32012-05-10 16:17:53 +0000436 }
commit-queue@webkit.org6b849432012-03-30 15:47:04 +0000437 return (targetNode);
438}
439
commit-queue@webkit.org294ddcd2012-03-19 15:33:26 +0000440} // namespace TouchAdjustment
441
442bool findBestClickableCandidate(Node*& targetNode, IntPoint &targetPoint, const IntPoint &touchHotspot, const IntRect &touchArea, const NodeList& nodeList)
443{
commit-queue@webkit.org98364e92012-04-04 12:47:54 +0000444 IntRect targetArea;
commit-queue@webkit.org294ddcd2012-03-19 15:33:26 +0000445 TouchAdjustment::SubtargetGeometryList subtargets;
allan.jensen@nokia.comdbb31192012-08-22 10:23:55 +0000446 TouchAdjustment::compileSubtargetList(nodeList, subtargets, TouchAdjustment::nodeRespondsToTapGesture, TouchAdjustment::appendBasicSubtargetsForNode);
commit-queue@webkit.orgcfdf5932012-07-27 17:59:36 +0000447 return TouchAdjustment::findNodeWithLowestDistanceMetric(targetNode, targetPoint, targetArea, touchHotspot, touchArea, subtargets, TouchAdjustment::hybridDistanceFunction);
commit-queue@webkit.org294ddcd2012-03-19 15:33:26 +0000448}
449
allan.jensen@nokia.com4a470ad2012-08-17 14:31:56 +0000450bool findBestContextMenuCandidate(Node*& targetNode, IntPoint &targetPoint, const IntPoint &touchHotspot, const IntRect &touchArea, const NodeList& nodeList)
451{
452 IntRect targetArea;
453 TouchAdjustment::SubtargetGeometryList subtargets;
allan.jensen@nokia.comdbb31192012-08-22 10:23:55 +0000454 TouchAdjustment::compileSubtargetList(nodeList, subtargets, TouchAdjustment::providesContextMenuItems, TouchAdjustment::appendContextSubtargetsForNode);
allan.jensen@nokia.com4a470ad2012-08-17 14:31:56 +0000455 return TouchAdjustment::findNodeWithLowestDistanceMetric(targetNode, targetPoint, targetArea, touchHotspot, touchArea, subtargets, TouchAdjustment::hybridDistanceFunction);
456}
457
commit-queue@webkit.org6b849432012-03-30 15:47:04 +0000458bool findBestZoomableArea(Node*& targetNode, IntRect& targetArea, const IntPoint& touchHotspot, const IntRect& touchArea, const NodeList& nodeList)
459{
commit-queue@webkit.org98364e92012-04-04 12:47:54 +0000460 IntPoint targetPoint;
commit-queue@webkit.org6b849432012-03-30 15:47:04 +0000461 TouchAdjustment::SubtargetGeometryList subtargets;
462 TouchAdjustment::compileZoomableSubtargets(nodeList, subtargets);
commit-queue@webkit.org98364e92012-04-04 12:47:54 +0000463 return TouchAdjustment::findNodeWithLowestDistanceMetric(targetNode, targetPoint, targetArea, touchHotspot, touchArea, subtargets, TouchAdjustment::zoomableIntersectionQuotient);
commit-queue@webkit.org6b849432012-03-30 15:47:04 +0000464}
465
commit-queue@webkit.org294ddcd2012-03-19 15:33:26 +0000466} // namespace WebCore