Index: Source/core/page/SpatialNavigation.cpp |
diff --git a/Source/core/page/SpatialNavigation.cpp b/Source/core/page/SpatialNavigation.cpp |
index 8e5a04e73224bfe466b569d5c52f4934121c2977..6a8112cb6c787cc811602b52a92332af8cba13f2 100644 |
--- a/Source/core/page/SpatialNavigation.cpp |
+++ b/Source/core/page/SpatialNavigation.cpp |
@@ -51,7 +51,6 @@ static bool areRectsMoreThanFullScreenApart(FocusType, const LayoutRect& curRect |
static bool isRectInDirection(FocusType, const LayoutRect&, const LayoutRect&); |
static void deflateIfOverlapped(LayoutRect&, LayoutRect&); |
static LayoutRect rectToAbsoluteCoordinates(LocalFrame* initialFrame, const LayoutRect&); |
-static void entryAndExitPointsForDirection(FocusType, const LayoutRect& startingRect, const LayoutRect& potentialRect, LayoutPoint& exitPoint, LayoutPoint& entryPoint); |
static bool isScrollableNode(const Node*); |
FocusCandidate::FocusCandidate(Node* node, FocusType type) |
@@ -144,11 +143,11 @@ static bool areRectsFullyAligned(FocusType type, const LayoutRect& a, const Layo |
switch (type) { |
case FocusTypeLeft: |
aStart = a.x(); |
- bEnd = b.maxX(); |
+ bEnd = b.x(); |
break; |
case FocusTypeRight: |
aStart = b.x(); |
- bEnd = a.maxX(); |
+ bEnd = a.x(); |
break; |
case FocusTypeUp: |
aStart = a.y(); |
@@ -188,32 +187,21 @@ static bool areRectsFullyAligned(FocusType type, const LayoutRect& a, const Layo |
// * * * * * * |
// **************************** ***************************** |
- // Horizontal Vertical Horizontal Vertical |
- // **************************** ***************************** |
- // * _......_ * _ _ _ _ * * _ * _ _ _ _ * |
- // * |_| |_| * |_|_|_|_| * * |_| _ * |_|_|_|_| * |
- // * |_| |_| * . * * |_| |_| * . * |
- // * |_| (3) . * * |_|....|_| (4) . * |
- // * * ._ _ * * * _ _. * |
- // * * |_|_| * * * |_|_| * |
- // * * * * * * |
- // **************************** ***************************** |
- |
- return ((bMiddle >= aStart && bMiddle <= aEnd) // (1) |
- || (aMiddle >= bStart && aMiddle <= bEnd) // (2) |
- || (bStart == aStart) // (3) |
- || (bEnd == aEnd)); // (4) |
+ return (bMiddle >= aStart && bMiddle <= aEnd) // (1) |
+ || (aMiddle >= bStart && aMiddle <= bEnd); // (2) |
} |
-// This method checks if |start| and |dest| have a partial intersection, either |
-// horizontally or vertically. |
+// 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(FocusType type, const LayoutRect& a, const LayoutRect& b) |
{ |
LayoutUnit aStart = start(type, a); |
LayoutUnit bStart = start(type, b); |
- LayoutUnit bMiddle = middle(type, b); |
LayoutUnit aEnd = end(type, a); |
LayoutUnit bEnd = end(type, b); |
@@ -232,9 +220,8 @@ static bool areRectsPartiallyAligned(FocusType type, const LayoutRect& a, const |
// ******************************** |
// |
// ... and variants of the above cases. |
- return ((bStart >= aStart && bStart <= aEnd) |
- || (bEnd >= aStart && bEnd <= aEnd) |
- || (bMiddle >= aStart && bMiddle <= aEnd)); |
+ return (bStart >= aStart && bStart <= aEnd) |
+ || (bEnd >= aStart && bEnd <= aEnd); |
} |
static bool areRectsMoreThanFullScreenApart(FocusType type, const LayoutRect& curRect, const LayoutRect& targetRect, const LayoutSize& viewSize) |
@@ -257,28 +244,34 @@ static bool areRectsMoreThanFullScreenApart(FocusType type, const LayoutRect& cu |
} |
// Return true if rect |a| is below |b|. False otherwise. |
+// For overlapping rects, |a| is considered to be below |b| |
+// if both edges of |a| are below the respective ones of |b| |
static inline bool below(const LayoutRect& a, const LayoutRect& b) |
{ |
- return a.y() > b.maxY(); |
+ return a.y() >= b.maxY() |
+ || (a.y() >= b.y() && a.maxY() > b.maxY()); |
} |
// Return true if rect |a| is on the right of |b|. False otherwise. |
+// For overlapping rects, |a| is considered to be on the right of |b| |
+// if both edges of |a| are on the right of the respective ones of |b| |
static inline bool rightOf(const LayoutRect& a, const LayoutRect& b) |
{ |
- return a.x() > b.maxX(); |
+ return a.x() >= b.maxX() |
+ || (a.x() >= b.x() && a.maxX() > b.maxX()); |
} |
static bool isRectInDirection(FocusType type, const LayoutRect& curRect, const LayoutRect& targetRect) |
{ |
switch (type) { |
case FocusTypeLeft: |
- return targetRect.maxX() <= curRect.x(); |
+ return rightOf(curRect, targetRect); |
case FocusTypeRight: |
- return targetRect.x() >= curRect.maxX(); |
+ return rightOf(targetRect, curRect); |
case FocusTypeUp: |
- return targetRect.maxY() <= curRect.y(); |
+ return below(curRect, targetRect); |
case FocusTypeDown: |
- return targetRect.y() >= curRect.maxY(); |
+ return below(targetRect, curRect); |
default: |
ASSERT_NOT_REACHED(); |
return false; |
@@ -539,24 +532,38 @@ LayoutRect frameRectInAbsoluteCoordinates(LocalFrame* frame) |
// This method calculates the exitPoint from the startingRect and the entryPoint into the candidate rect. |
// The line between those 2 points is the closest distance between the 2 rects. |
+// Takes care of overlapping rects, defining points so that the distance between them |
+// is zero where necessary |
void entryAndExitPointsForDirection(FocusType type, const LayoutRect& startingRect, const LayoutRect& potentialRect, LayoutPoint& exitPoint, LayoutPoint& entryPoint) |
{ |
switch (type) { |
case FocusTypeLeft: |
exitPoint.setX(startingRect.x()); |
- entryPoint.setX(potentialRect.maxX()); |
+ if (potentialRect.maxX() < startingRect.x()) |
+ entryPoint.setX(potentialRect.maxX()); |
+ else |
+ entryPoint.setX(startingRect.x()); |
break; |
case FocusTypeUp: |
exitPoint.setY(startingRect.y()); |
- entryPoint.setY(potentialRect.maxY()); |
+ if (potentialRect.maxY() < startingRect.y()) |
+ entryPoint.setY(potentialRect.maxY()); |
+ else |
+ entryPoint.setY(startingRect.y()); |
break; |
case FocusTypeRight: |
exitPoint.setX(startingRect.maxX()); |
- entryPoint.setX(potentialRect.x()); |
+ if (potentialRect.x() > startingRect.maxX()) |
+ entryPoint.setX(potentialRect.x()); |
+ else |
+ entryPoint.setX(startingRect.maxX()); |
break; |
case FocusTypeDown: |
exitPoint.setY(startingRect.maxY()); |
- entryPoint.setY(potentialRect.y()); |
+ if (potentialRect.y() > startingRect.maxY()) |
+ entryPoint.setY(potentialRect.y()); |
+ else |
+ entryPoint.setY(startingRect.maxY()); |
break; |
default: |
ASSERT_NOT_REACHED(); |
@@ -567,10 +574,16 @@ void entryAndExitPointsForDirection(FocusType type, const LayoutRect& startingRe |
case FocusTypeRight: |
if (below(startingRect, potentialRect)) { |
exitPoint.setY(startingRect.y()); |
- entryPoint.setY(potentialRect.maxY()); |
+ if (potentialRect.maxY() < startingRect.y()) |
+ entryPoint.setY(potentialRect.maxY()); |
+ else |
+ entryPoint.setY(startingRect.y()); |
} else if (below(potentialRect, startingRect)) { |
exitPoint.setY(startingRect.maxY()); |
- entryPoint.setY(potentialRect.y()); |
+ if (potentialRect.y() > startingRect.maxY()) |
+ entryPoint.setY(potentialRect.y()); |
+ else |
+ entryPoint.setY(startingRect.maxY()); |
} else { |
exitPoint.setY(max(startingRect.y(), potentialRect.y())); |
entryPoint.setY(exitPoint.y()); |
@@ -580,10 +593,16 @@ void entryAndExitPointsForDirection(FocusType type, const LayoutRect& startingRe |
case FocusTypeDown: |
if (rightOf(startingRect, potentialRect)) { |
exitPoint.setX(startingRect.x()); |
- entryPoint.setX(potentialRect.maxX()); |
+ if (potentialRect.maxX() < startingRect.x()) |
+ entryPoint.setX(potentialRect.maxX()); |
+ else |
+ entryPoint.setX(startingRect.x()); |
} else if (rightOf(potentialRect, startingRect)) { |
exitPoint.setX(startingRect.maxX()); |
- entryPoint.setX(potentialRect.x()); |
+ if (potentialRect.x() > startingRect.maxX()) |
+ entryPoint.setX(potentialRect.x()); |
+ else |
+ entryPoint.setX(startingRect.maxX()); |
} else { |
exitPoint.setX(max(startingRect.x(), potentialRect.x())); |
entryPoint.setX(exitPoint.x()); |
@@ -636,42 +655,37 @@ void distanceDataForNode(FocusType type, const FocusCandidate& current, FocusCan |
LayoutPoint exitPoint; |
LayoutPoint entryPoint; |
- LayoutUnit sameAxisDistance = 0; |
- LayoutUnit otherAxisDistance = 0; |
entryAndExitPointsForDirection(type, currentRect, nodeRect, exitPoint, entryPoint); |
+ LayoutUnit xAxis = exitPoint.x() - entryPoint.x(); |
+ LayoutUnit yAxis = exitPoint.y() - entryPoint.y(); |
+ |
+ LayoutUnit navigationAxisDistance; |
+ LayoutUnit orthogonalAxisDistance; |
+ |
switch (type) { |
case FocusTypeLeft: |
- sameAxisDistance = exitPoint.x() - entryPoint.x(); |
- otherAxisDistance = absoluteValue(exitPoint.y() - entryPoint.y()); |
- break; |
- case FocusTypeUp: |
- sameAxisDistance = exitPoint.y() - entryPoint.y(); |
- otherAxisDistance = absoluteValue(exitPoint.x() - entryPoint.x()); |
- break; |
case FocusTypeRight: |
- sameAxisDistance = entryPoint.x() - exitPoint.x(); |
- otherAxisDistance = absoluteValue(entryPoint.y() - exitPoint.y()); |
+ navigationAxisDistance = xAxis.abs(); |
+ orthogonalAxisDistance = yAxis.abs(); |
break; |
+ case FocusTypeUp: |
case FocusTypeDown: |
- sameAxisDistance = entryPoint.y() - exitPoint.y(); |
- otherAxisDistance = absoluteValue(entryPoint.x() - exitPoint.x()); |
+ navigationAxisDistance = yAxis.abs(); |
+ orthogonalAxisDistance = xAxis.abs(); |
break; |
default: |
ASSERT_NOT_REACHED(); |
return; |
} |
- float x = ((entryPoint.x() - exitPoint.x()) * (entryPoint.x() - exitPoint.x())).toFloat(); |
- float y = ((entryPoint.y() - exitPoint.y()) * (entryPoint.y() - exitPoint.y())).toFloat(); |
- |
- float euclidianDistance = sqrt(x + y); |
+ double euclidianDistancePow2 = (xAxis * xAxis + yAxis * yAxis).toDouble(); |
+ LayoutRect intersectionRect = intersection(currentRect, nodeRect); |
+ double overlap = (intersectionRect.width() * intersectionRect.height()).toDouble(); |
- // Loosely based on http://www.w3.org/TR/WICD/#focus-handling |
- // df = dotDist + dx + dy + 2 * (xdisplacement + ydisplacement) - sqrt(Overlap) |
+ // Distance calculation is based on http://www.w3.org/TR/WICD/#focus-handling |
+ candidate.distance = sqrt(euclidianDistancePow2) + navigationAxisDistance+ orthogonalAxisDistance * 2 - sqrt(overlap); |
- float distance = euclidianDistance + sameAxisDistance + 2 * otherAxisDistance; |
- candidate.distance = roundf(distance); |
LayoutSize viewSize = candidate.visibleNode->document().page()->mainFrame()->view()->visibleContentRect().size(); |
candidate.alignment = alignmentForRects(type, currentRect, nodeRect, viewSize); |
} |