OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) | 2 * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) |
3 * | 3 * |
4 * This library is free software; you can redistribute it and/or | 4 * This library is free software; you can redistribute it and/or |
5 * modify it under the terms of the GNU Library General Public | 5 * modify it under the terms of the GNU Library General Public |
6 * License as published by the Free Software Foundation; either | 6 * License as published by the Free Software Foundation; either |
7 * version 2 of the License, or (at your option) any later version. | 7 * version 2 of the License, or (at your option) any later version. |
8 * | 8 * |
9 * This library is distributed in the hope that it will be useful, | 9 * This library is distributed in the hope that it will be useful, |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
(...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
325 Node* candidate = intersectedNodes[i].get(); | 325 Node* candidate = intersectedNodes[i].get(); |
326 if (nodeIsZoomTarget(candidate)) | 326 if (nodeIsZoomTarget(candidate)) |
327 appendZoomableSubtargets(candidate, subtargets); | 327 appendZoomableSubtargets(candidate, subtargets); |
328 } | 328 } |
329 } | 329 } |
330 | 330 |
331 // This returns quotient of the target area and its intersection with the touch
area. | 331 // This returns quotient of the target area and its intersection with the touch
area. |
332 // This will prioritize largest intersection and smallest area, while balancing
the two against each other. | 332 // This will prioritize largest intersection and smallest area, while balancing
the two against each other. |
333 float zoomableIntersectionQuotient(const IntPoint& touchHotspot, const IntRect&
touchArea, const SubtargetGeometry& subtarget) | 333 float zoomableIntersectionQuotient(const IntPoint& touchHotspot, const IntRect&
touchArea, const SubtargetGeometry& subtarget) |
334 { | 334 { |
335 IntRect rect = subtarget.boundingBox(); | 335 IntRect rect = subtarget.node()->document().view()->contentsToRootFrame(subt
arget.boundingBox()); |
336 | |
337 // Convert from frame coordinates to window coordinates. | |
338 rect = subtarget.node()->document().view()->contentsToWindow(rect); | |
339 | 336 |
340 // Check the rectangle is meaningful zoom target. It should at least contain
the hotspot. | 337 // Check the rectangle is meaningful zoom target. It should at least contain
the hotspot. |
341 if (!rect.contains(touchHotspot)) | 338 if (!rect.contains(touchHotspot)) |
342 return std::numeric_limits<float>::infinity(); | 339 return std::numeric_limits<float>::infinity(); |
343 IntRect intersection = rect; | 340 IntRect intersection = rect; |
344 intersection.intersect(touchArea); | 341 intersection.intersect(touchArea); |
345 | 342 |
346 // Return the quotient of the intersection. | 343 // Return the quotient of the intersection. |
347 return rect.size().area() / (float)intersection.size().area(); | 344 return rect.size().area() / (float)intersection.size().area(); |
348 } | 345 } |
349 | 346 |
350 // Uses a hybrid of distance to adjust and intersect ratio, normalizing each sco
re between 0 and 1 | 347 // Uses a hybrid of distance to adjust and intersect ratio, normalizing each sco
re between 0 and 1 |
351 // and combining them. The distance to adjust works best for disambiguating clic
ks on targets such | 348 // and combining them. The distance to adjust works best for disambiguating clic
ks on targets such |
352 // as links, where the width may be significantly larger than the touch width. U
sing area of overlap | 349 // as links, where the width may be significantly larger than the touch width. U
sing area of overlap |
353 // in such cases can lead to a bias towards shorter links. Conversely, percentag
e of overlap can | 350 // in such cases can lead to a bias towards shorter links. Conversely, percentag
e of overlap can |
354 // provide strong confidence in tapping on a small target, where the overlap is
often quite high, | 351 // provide strong confidence in tapping on a small target, where the overlap is
often quite high, |
355 // and works well for tightly packed controls. | 352 // and works well for tightly packed controls. |
356 float hybridDistanceFunction(const IntPoint& touchHotspot, const IntRect& touchR
ect, const SubtargetGeometry& subtarget) | 353 float hybridDistanceFunction(const IntPoint& touchHotspot, const IntRect& touchR
ect, const SubtargetGeometry& subtarget) |
357 { | 354 { |
358 IntRect rect = subtarget.boundingBox(); | 355 IntRect rect = subtarget.node()->document().view()->contentsToRootFrame(subt
arget.boundingBox()); |
359 | |
360 // Convert from frame coordinates to window coordinates. | |
361 rect = subtarget.node()->document().view()->contentsToWindow(rect); | |
362 | 356 |
363 float radiusSquared = 0.25f * (touchRect.size().diagonalLengthSquared()); | 357 float radiusSquared = 0.25f * (touchRect.size().diagonalLengthSquared()); |
364 float distanceToAdjustScore = rect.distanceSquaredToPoint(touchHotspot) / ra
diusSquared; | 358 float distanceToAdjustScore = rect.distanceSquaredToPoint(touchHotspot) / ra
diusSquared; |
365 | 359 |
366 int maxOverlapWidth = std::min(touchRect.width(), rect.width()); | 360 int maxOverlapWidth = std::min(touchRect.width(), rect.width()); |
367 int maxOverlapHeight = std::min(touchRect.height(), rect.height()); | 361 int maxOverlapHeight = std::min(touchRect.height(), rect.height()); |
368 float maxOverlapArea = std::max(maxOverlapWidth * maxOverlapHeight, 1); | 362 float maxOverlapArea = std::max(maxOverlapWidth * maxOverlapHeight, 1); |
369 rect.intersect(touchRect); | 363 rect.intersect(touchRect); |
370 float intersectArea = rect.size().area(); | 364 float intersectArea = rect.size().area(); |
371 float intersectionScore = 1 - intersectArea / maxOverlapArea; | 365 float intersectionScore = 1 - intersectArea / maxOverlapArea; |
372 | 366 |
373 float hybridScore = intersectionScore + distanceToAdjustScore; | 367 float hybridScore = intersectionScore + distanceToAdjustScore; |
374 | 368 |
375 return hybridScore; | 369 return hybridScore; |
376 } | 370 } |
377 | 371 |
378 FloatPoint contentsToWindow(FrameView *view, FloatPoint pt) | 372 FloatPoint contentsToRootFrame(FrameView *view, FloatPoint pt) |
379 { | 373 { |
380 int x = static_cast<int>(pt.x() + 0.5f); | 374 int x = static_cast<int>(pt.x() + 0.5f); |
381 int y = static_cast<int>(pt.y() + 0.5f); | 375 int y = static_cast<int>(pt.y() + 0.5f); |
382 IntPoint adjusted = view->contentsToWindow(IntPoint(x, y)); | 376 IntPoint adjusted = view->contentsToRootFrame(IntPoint(x, y)); |
383 return FloatPoint(adjusted.x(), adjusted.y()); | 377 return FloatPoint(adjusted.x(), adjusted.y()); |
384 } | 378 } |
385 | 379 |
386 // Adjusts 'point' to the nearest point inside rect, and leaves it unchanged if
already inside. | 380 // Adjusts 'point' to the nearest point inside rect, and leaves it unchanged if
already inside. |
387 void adjustPointToRect(FloatPoint& point, const FloatRect& rect) | 381 void adjustPointToRect(FloatPoint& point, const FloatRect& rect) |
388 { | 382 { |
389 if (point.x() < rect.x()) | 383 if (point.x() < rect.x()) |
390 point.setX(rect.x()); | 384 point.setX(rect.x()); |
391 else if (point.x() > rect.maxX()) | 385 else if (point.x() > rect.maxX()) |
392 point.setX(rect.maxX()); | 386 point.setX(rect.maxX()); |
393 | 387 |
394 if (point.y() < rect.y()) | 388 if (point.y() < rect.y()) |
395 point.setY(rect.y()); | 389 point.setY(rect.y()); |
396 else if (point.y() > rect.maxY()) | 390 else if (point.y() > rect.maxY()) |
397 point.setY(rect.maxY()); | 391 point.setY(rect.maxY()); |
398 } | 392 } |
399 | 393 |
400 bool snapTo(const SubtargetGeometry& geom, const IntPoint& touchPoint, const Int
Rect& touchArea, IntPoint& adjustedPoint) | 394 bool snapTo(const SubtargetGeometry& geom, const IntPoint& touchPoint, const Int
Rect& touchArea, IntPoint& adjustedPoint) |
401 { | 395 { |
402 FrameView* view = geom.node()->document().view(); | 396 FrameView* view = geom.node()->document().view(); |
403 FloatQuad quad = geom.quad(); | 397 FloatQuad quad = geom.quad(); |
404 | 398 |
405 if (quad.isRectilinear()) { | 399 if (quad.isRectilinear()) { |
406 IntRect contentBounds = geom.boundingBox(); | 400 IntRect bounds = view->contentsToRootFrame(geom.boundingBox()); |
407 // Convert from frame coordinates to window coordinates. | |
408 IntRect bounds = view->contentsToWindow(contentBounds); | |
409 if (bounds.contains(touchPoint)) { | 401 if (bounds.contains(touchPoint)) { |
410 adjustedPoint = touchPoint; | 402 adjustedPoint = touchPoint; |
411 return true; | 403 return true; |
412 } | 404 } |
413 if (bounds.intersects(touchArea)) { | 405 if (bounds.intersects(touchArea)) { |
414 bounds.intersect(touchArea); | 406 bounds.intersect(touchArea); |
415 adjustedPoint = bounds.center(); | 407 adjustedPoint = bounds.center(); |
416 return true; | 408 return true; |
417 } | 409 } |
418 return false; | 410 return false; |
419 } | 411 } |
420 | 412 |
421 // The following code tries to adjust the point to place inside a both the t
ouchArea and the non-rectilinear quad. | 413 // The following code tries to adjust the point to place inside a both the t
ouchArea and the non-rectilinear quad. |
422 // FIXME: This will return the point inside the touch area that is the close
st to the quad center, but does not | 414 // FIXME: This will return the point inside the touch area that is the close
st to the quad center, but does not |
423 // guarantee that the point will be inside the quad. Corner-cases exist wher
e the quad will intersect but this | 415 // guarantee that the point will be inside the quad. Corner-cases exist wher
e the quad will intersect but this |
424 // will fail to adjust the point to somewhere in the intersection. | 416 // will fail to adjust the point to somewhere in the intersection. |
425 | 417 |
426 // Convert quad from content to window coordinates. | 418 FloatPoint p1 = contentsToRootFrame(view, quad.p1()); |
427 FloatPoint p1 = contentsToWindow(view, quad.p1()); | 419 FloatPoint p2 = contentsToRootFrame(view, quad.p2()); |
428 FloatPoint p2 = contentsToWindow(view, quad.p2()); | 420 FloatPoint p3 = contentsToRootFrame(view, quad.p3()); |
429 FloatPoint p3 = contentsToWindow(view, quad.p3()); | 421 FloatPoint p4 = contentsToRootFrame(view, quad.p4()); |
430 FloatPoint p4 = contentsToWindow(view, quad.p4()); | |
431 quad = FloatQuad(p1, p2, p3, p4); | 422 quad = FloatQuad(p1, p2, p3, p4); |
432 | 423 |
433 if (quad.containsPoint(touchPoint)) { | 424 if (quad.containsPoint(touchPoint)) { |
434 adjustedPoint = touchPoint; | 425 adjustedPoint = touchPoint; |
435 return true; | 426 return true; |
436 } | 427 } |
437 | 428 |
438 // Pull point towards the center of the element. | 429 // Pull point towards the center of the element. |
439 FloatPoint center = quad.center(); | 430 FloatPoint center = quad.center(); |
440 | 431 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
474 targetArea = it->boundingBox(); | 465 targetArea = it->boundingBox(); |
475 } | 466 } |
476 } | 467 } |
477 } | 468 } |
478 } | 469 } |
479 | 470 |
480 // As for HitTestResult.innerNode, we skip over pseudo elements. | 471 // As for HitTestResult.innerNode, we skip over pseudo elements. |
481 if (targetNode && targetNode->isPseudoElement()) | 472 if (targetNode && targetNode->isPseudoElement()) |
482 targetNode = targetNode->parentOrShadowHostNode(); | 473 targetNode = targetNode->parentOrShadowHostNode(); |
483 | 474 |
484 if (targetNode) { | 475 if (targetNode) |
485 targetArea = targetNode->document().view()->contentsToWindow(targetArea)
; | 476 targetArea = targetNode->document().view()->contentsToRootFrame(targetAr
ea); |
486 } | 477 |
487 return (targetNode); | 478 return (targetNode); |
488 } | 479 } |
489 | 480 |
490 } // namespace TouchAdjustment | 481 } // namespace TouchAdjustment |
491 | 482 |
492 bool findBestClickableCandidate(Node*& targetNode, IntPoint& targetPoint, const
IntPoint& touchHotspot, const IntRect& touchArea, const WillBeHeapVector<RefPtrW
illBeMember<Node>>& nodes) | 483 bool findBestClickableCandidate(Node*& targetNode, IntPoint& targetPoint, const
IntPoint& touchHotspot, const IntRect& touchArea, const WillBeHeapVector<RefPtrW
illBeMember<Node>>& nodes) |
493 { | 484 { |
494 IntRect targetArea; | 485 IntRect targetArea; |
495 TouchAdjustment::SubtargetGeometryList subtargets; | 486 TouchAdjustment::SubtargetGeometryList subtargets; |
496 TouchAdjustment::compileSubtargetList(nodes, subtargets, TouchAdjustment::no
deRespondsToTapGesture, TouchAdjustment::appendBasicSubtargetsForNode); | 487 TouchAdjustment::compileSubtargetList(nodes, subtargets, TouchAdjustment::no
deRespondsToTapGesture, TouchAdjustment::appendBasicSubtargetsForNode); |
(...skipping 10 matching lines...) Expand all Loading... |
507 | 498 |
508 bool findBestZoomableArea(Node*& targetNode, IntRect& targetArea, const IntPoint
& touchHotspot, const IntRect& touchArea, const WillBeHeapVector<RefPtrWillBeMem
ber<Node>>& nodes) | 499 bool findBestZoomableArea(Node*& targetNode, IntRect& targetArea, const IntPoint
& touchHotspot, const IntRect& touchArea, const WillBeHeapVector<RefPtrWillBeMem
ber<Node>>& nodes) |
509 { | 500 { |
510 IntPoint targetPoint; | 501 IntPoint targetPoint; |
511 TouchAdjustment::SubtargetGeometryList subtargets; | 502 TouchAdjustment::SubtargetGeometryList subtargets; |
512 TouchAdjustment::compileZoomableSubtargets(nodes, subtargets); | 503 TouchAdjustment::compileZoomableSubtargets(nodes, subtargets); |
513 return TouchAdjustment::findNodeWithLowestDistanceMetric(targetNode, targetP
oint, targetArea, touchHotspot, touchArea, subtargets, TouchAdjustment::zoomable
IntersectionQuotient); | 504 return TouchAdjustment::findNodeWithLowestDistanceMetric(targetNode, targetP
oint, targetArea, touchHotspot, touchArea, subtargets, TouchAdjustment::zoomable
IntersectionQuotient); |
514 } | 505 } |
515 | 506 |
516 } // namespace blink | 507 } // namespace blink |
OLD | NEW |