void distanceDataForNode(FocusDirection direction, const FocusCandidate& current, FocusCandidate& candidate) { if (areElementsOnSameLine(current, candidate)) { if ((direction == FocusDirectionUp && current.rect.y() > candidate.rect.y()) || (direction == FocusDirectionDown && candidate.rect.y() > current.rect.y())) { candidate.distance = 0; candidate.alignment = Full; return; } } IntRect nodeRect = candidate.rect; IntRect currentRect = current.rect; deflateIfOverlapped(currentRect, nodeRect); if (!isRectInDirection(direction, currentRect, nodeRect)) return; IntPoint exitPoint; IntPoint entryPoint; int sameAxisDistance = 0; int otherAxisDistance = 0; entryAndExitPointsForDirection(direction, currentRect, nodeRect, exitPoint, entryPoint); switch (direction) { case FocusDirectionLeft: sameAxisDistance = exitPoint.x() - entryPoint.x(); otherAxisDistance = abs(exitPoint.y() - entryPoint.y()); break; case FocusDirectionUp: sameAxisDistance = exitPoint.y() - entryPoint.y(); otherAxisDistance = abs(exitPoint.x() - entryPoint.x()); break; case FocusDirectionRight: sameAxisDistance = entryPoint.x() - exitPoint.x(); otherAxisDistance = abs(entryPoint.y() - exitPoint.y()); break; case FocusDirectionDown: sameAxisDistance = entryPoint.y() - exitPoint.y(); otherAxisDistance = abs(entryPoint.x() - exitPoint.x()); break; default: ASSERT_NOT_REACHED(); return; } int x = (entryPoint.x() - exitPoint.x()) * (entryPoint.x() - exitPoint.x()); int y = (entryPoint.y() - exitPoint.y()) * (entryPoint.y() - exitPoint.y()); float euclidianDistance = sqrt((x + y) * 1.0f); // Loosely based on http://www.w3.org/TR/WICD/#focus-handling // df = dotDist + dx + dy + 2 * (xdisplacement + ydisplacement) - sqrt(Overlap) float distance = euclidianDistance + sameAxisDistance + 2 * otherAxisDistance; candidate.distance = roundf(distance); IntSize viewSize = candidate.visibleNode->document()->page()->mainFrame()->view()->visibleContentRect().size(); candidate.alignment = alignmentForRects(direction, currentRect, nodeRect, viewSize); }
void distanceDataForNode(FocusDirection direction, Node* start, FocusCandidate& candidate) { RenderObject* startRender = start->renderer(); if (!startRender) { candidate.distance = maxDistance(); return; } RenderObject* destRender = candidate.node->renderer(); if (!destRender) { candidate.distance = maxDistance(); return; } IntRect curRect = renderRectRelativeToRootDocument(startRender); IntRect targetRect = renderRectRelativeToRootDocument(destRender); // The bounding rectangle of two consecutive nodes can overlap. In such cases, // deflate both. deflateIfOverlapped(curRect, targetRect); // If empty rects or negative width or height, bail out. if (curRect.isEmpty() || targetRect.isEmpty() || targetRect.width() <= 0 || targetRect.height() <= 0) { candidate.distance = maxDistance(); return; } // Negative coordinates can be used if node is scrolled up offscreen. if (!checkNegativeCoordsForNode(start, curRect)) { candidate.distance = maxDistance(); return; } if (!checkNegativeCoordsForNode(candidate.node, targetRect)) { candidate.distance = maxDistance(); return; } if (!isRectInDirection(direction, curRect, targetRect)) { candidate.distance = maxDistance(); return; } // The distance between two nodes is not to be considered alone when evaluating/looking // for the best focus candidate node. Alignment of rects can be also a good point to be // considered in order to make the algorithm to behavior in a more intuitive way. candidate.alignment = alignmentForRects(direction, curRect, targetRect); candidate.distance = spatialDistance(direction, curRect, targetRect); }