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

Unified Diff: Source/core/page/SpatialNavigation.cpp

Issue 797463003: spatnav: Allow focus move to a close-by not-fully-aligned node over a distant but fully-aligned nod… (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: rebaseline Created 5 years, 11 months 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 | « Source/core/page/SpatialNavigation.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/page/SpatialNavigation.cpp
diff --git a/Source/core/page/SpatialNavigation.cpp b/Source/core/page/SpatialNavigation.cpp
index b18a7ec1d7569ce2478d0052aecb3f1130b59bb2..31a70ec6557fade88ced2e765db5eb9675eff3a6 100644
--- a/Source/core/page/SpatialNavigation.cpp
+++ b/Source/core/page/SpatialNavigation.cpp
@@ -45,11 +45,6 @@ namespace blink {
using namespace HTMLNames;
-static RectsAlignment alignmentForRects(WebFocusType, const LayoutRect&, const LayoutRect&, const LayoutSize& viewSize);
-static bool areRectsFullyAligned(WebFocusType, const LayoutRect&, const LayoutRect&);
-static bool areRectsPartiallyAligned(WebFocusType, const LayoutRect&, const LayoutRect&);
-static bool areRectsMoreThanFullScreenApart(WebFocusType, const LayoutRect& curRect, const LayoutRect& targetRect, const LayoutSize& viewSize);
-static bool isRectInDirection(WebFocusType, const LayoutRect&, const LayoutRect&);
static void deflateIfOverlapped(LayoutRect&, LayoutRect&);
static LayoutRect rectToAbsoluteCoordinates(LocalFrame* initialFrame, const LayoutRect&);
static bool isScrollableNode(const Node*);
@@ -59,7 +54,6 @@ FocusCandidate::FocusCandidate(Node* node, WebFocusType type)
, focusableNode(nullptr)
, enclosingScrollableBox(nullptr)
, distance(maxDistance())
- , alignment(None)
, isOffscreen(true)
, isOffscreenAfterScrolling(true)
{
@@ -92,154 +86,19 @@ bool isSpatialNavigationEnabled(const LocalFrame* frame)
return (frame && frame->settings() && frame->settings()->spatialNavigationEnabled());
}
-static RectsAlignment alignmentForRects(WebFocusType type, const LayoutRect& curRect, const LayoutRect& targetRect, const LayoutSize& viewSize)
+static bool rectsIntersectOnOrthogonalAxis(WebFocusType type, const LayoutRect& a, const LayoutRect& b)
{
- // If we found a node in full alignment, but it is too far away, ignore it.
- if (areRectsMoreThanFullScreenApart(type, curRect, targetRect, viewSize))
- return None;
-
- if (areRectsFullyAligned(type, curRect, targetRect))
- return Full;
-
- if (areRectsPartiallyAligned(type, curRect, targetRect))
- return Partial;
-
- return None;
-}
-
-static inline bool isHorizontalMove(WebFocusType type)
-{
- return type == WebFocusTypeLeft || type == WebFocusTypeRight;
-}
-
-static inline LayoutUnit start(WebFocusType type, const LayoutRect& rect)
-{
- return isHorizontalMove(type) ? rect.y() : rect.x();
-}
-
-static inline LayoutUnit middle(WebFocusType type, const LayoutRect& rect)
-{
- LayoutPoint center(rect.center());
- return isHorizontalMove(type) ? center.y(): center.x();
-}
-
-static inline LayoutUnit end(WebFocusType type, const LayoutRect& rect)
-{
- return isHorizontalMove(type) ? rect.maxY() : rect.maxX();
-}
-
-// This method checks if rects |a| and |b| are fully aligned either vertically or
-// horizontally. In general, rects whose central point falls between the top or
-// bottom of each other are considered fully aligned.
-// Rects that match this criteria are preferable target nodes in move focus changing
-// operations.
-// * a = Current focused node's rect.
-// * b = Focus candidate node's rect.
-static bool areRectsFullyAligned(WebFocusType type, const LayoutRect& a, const LayoutRect& b)
-{
- LayoutUnit aStart, bStart, aEnd, bEnd;
-
switch (type) {
case WebFocusTypeLeft:
- aStart = a.x();
- bEnd = b.x();
- break;
case WebFocusTypeRight:
- aStart = b.x();
- bEnd = a.x();
- break;
+ return a.maxY() > b.y() && a.y() < b.maxY();
case WebFocusTypeUp:
- aStart = a.y();
- bEnd = b.y();
- break;
case WebFocusTypeDown:
- aStart = b.y();
- bEnd = a.y();
- break;
+ return a.maxX() > b.x() && a.x() < b.maxX();
default:
ASSERT_NOT_REACHED();
return false;
}
-
- if (aStart < bEnd)
- return false;
-
- aStart = start(type, a);
- bStart = start(type, b);
-
- LayoutUnit aMiddle = middle(type, a);
- LayoutUnit bMiddle = middle(type, b);
-
- aEnd = end(type, a);
- bEnd = end(type, b);
-
- // Picture of the totally aligned logic:
- //
- // Horizontal Vertical Horizontal Vertical
- // **************************** *****************************
- // * _ * _ _ _ _ * * _ * _ _ *
- // * |_| _ * |_|_|_|_| * * _ |_| * |_|_| *
- // * |_|....|_| * . * * |_|....|_| * . *
- // * |_| |_| (1) . * * |_| |_| (2) . *
- // * |_| * _._ * * |_| * _ _._ _ *
- // * * |_|_| * * * |_|_|_|_| *
- // * * * * * *
- // **************************** *****************************
-
- return (bMiddle >= aStart && bMiddle <= aEnd) // (1)
- || (aMiddle >= bStart && aMiddle <= bEnd); // (2)
-}
-
-// This method checks if rects |a| and |b| are partially aligned either vertically or
-// horizontally. In general, rects whose either of edges falls between the top or
-// bottom of each other are considered partially-aligned.
-// This is a separate set of conditions from "fully-aligned" and do not include cases
-// that satisfy the former.
-// * a = Current focused node's rect.
-// * b = Focus candidate node's rect.
-static bool areRectsPartiallyAligned(WebFocusType type, const LayoutRect& a, const LayoutRect& b)
-{
- LayoutUnit aStart = start(type, a);
- LayoutUnit bStart = start(type, b);
- LayoutUnit aEnd = end(type, a);
- LayoutUnit bEnd = end(type, b);
-
- // Picture of the partially aligned logic:
- //
- // Horizontal Vertical
- // ********************************
- // * _ * _ _ _ *
- // * |_| * |_|_|_| *
- // * |_|.... _ * . . *
- // * |_| |_| * . . *
- // * |_|....|_| * ._._ _ *
- // * |_| * |_|_|_| *
- // * |_| * *
- // * * *
- // ********************************
- //
- // ... and variants of the above cases.
- return (bStart >= aStart && bStart <= aEnd)
- || (bEnd >= aStart && bEnd <= aEnd);
-}
-
-static bool areRectsMoreThanFullScreenApart(WebFocusType type, const LayoutRect& curRect, const LayoutRect& targetRect, const LayoutSize& viewSize)
-{
- ASSERT(isRectInDirection(type, curRect, targetRect));
-
- switch (type) {
- case WebFocusTypeLeft:
- return curRect.x() - targetRect.maxX() > viewSize.width();
- case WebFocusTypeRight:
- return targetRect.x() - curRect.maxX() > viewSize.width();
- case WebFocusTypeUp:
- return curRect.y() - targetRect.maxY() > viewSize.height();
- case WebFocusTypeDown:
- return targetRect.y() - curRect.maxY() > viewSize.height();
- default:
- ASSERT_NOT_REACHED();
- return true;
- }
}
// Return true if rect |a| is below |b|. False otherwise.
@@ -644,7 +503,6 @@ void distanceDataForNode(WebFocusType type, const FocusCandidate& current, Focus
if (areElementsOnSameLine(current, candidate)) {
if ((type == WebFocusTypeUp && current.rect.y() > candidate.rect.y()) || (type == WebFocusTypeDown && candidate.rect.y() > current.rect.y())) {
candidate.distance = 0;
- candidate.alignment = Full;
return;
}
}
@@ -660,22 +518,37 @@ void distanceDataForNode(WebFocusType type, const FocusCandidate& current, Focus
LayoutPoint entryPoint;
entryAndExitPointsForDirection(type, currentRect, nodeRect, exitPoint, entryPoint);
- LayoutUnit xAxis = exitPoint.x() - entryPoint.x();
- LayoutUnit yAxis = exitPoint.y() - entryPoint.y();
+ LayoutUnit xAxis = (exitPoint.x() - entryPoint.x()).abs();
+ LayoutUnit yAxis = (exitPoint.y() - entryPoint.y()).abs();
LayoutUnit navigationAxisDistance;
- LayoutUnit orthogonalAxisDistance;
+ LayoutUnit weightedOrthogonalAxisDistance;
+
+ // Bias and weights are put to the orthogonal axis distance calculation
+ // so aligned candidates would have advantage over partially-aligned ones
+ // and then over not-aligned candidates. The bias is given to not-aligned
+ // candidates with respect to size of the current rect. The weight for
+ // left/right direction is given a higher value to allow navigation on
+ // common horizonally-aligned elements. The hardcoded values are based on
+ // tests and experiments.
+ const int orthogonalWeightForLeftRight = 30;
+ const int orthogonalWeightForUpDown = 2;
+ int orthogonalBias = 0;
switch (type) {
case WebFocusTypeLeft:
case WebFocusTypeRight:
- navigationAxisDistance = xAxis.abs();
- orthogonalAxisDistance = yAxis.abs();
+ navigationAxisDistance = xAxis;
+ if (!rectsIntersectOnOrthogonalAxis(type, currentRect, nodeRect))
+ orthogonalBias = currentRect.height() / 2;
+ weightedOrthogonalAxisDistance = (yAxis + orthogonalBias) * orthogonalWeightForLeftRight;
break;
case WebFocusTypeUp:
case WebFocusTypeDown:
- navigationAxisDistance = yAxis.abs();
- orthogonalAxisDistance = xAxis.abs();
+ navigationAxisDistance = yAxis;
+ if (!rectsIntersectOnOrthogonalAxis(type, currentRect, nodeRect))
+ orthogonalBias = currentRect.width() / 2;
+ weightedOrthogonalAxisDistance = (xAxis + orthogonalBias) * orthogonalWeightForUpDown;
break;
default:
ASSERT_NOT_REACHED();
@@ -687,10 +560,7 @@ void distanceDataForNode(WebFocusType type, const FocusCandidate& current, Focus
double overlap = (intersectionRect.width() * intersectionRect.height()).toDouble();
// Distance calculation is based on http://www.w3.org/TR/WICD/#focus-handling
- candidate.distance = sqrt(euclidianDistancePow2) + navigationAxisDistance+ orthogonalAxisDistance * 2 - sqrt(overlap);
-
- LayoutSize viewSize = LayoutSize(candidate.visibleNode->document().page()->deprecatedLocalMainFrame()->view()->visibleContentRect().size());
- candidate.alignment = alignmentForRects(type, currentRect, nodeRect, viewSize);
+ candidate.distance = sqrt(euclidianDistancePow2) + navigationAxisDistance + weightedOrthogonalAxisDistance - sqrt(overlap);
}
bool canBeScrolledIntoView(WebFocusType type, const FocusCandidate& candidate)
« no previous file with comments | « Source/core/page/SpatialNavigation.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698