Changeset 72522 in webkit
- Timestamp:
- Nov 22, 2010 5:49:09 AM (13 years ago)
- Location:
- trunk
- Files:
-
- 17 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r72521 r72522 1 2010-11-22 Yael Aharon <yael.aharon@nokia.com>, Chang Shu <chang.shu@nokia.com> 2 3 Reviewed by Antonio Gomes. 4 5 Spatial Navigation: issues with the node selection algorithm. 6 https://bugs.webkit.org/show_bug.cgi?id=49382 7 8 Replaced text in tests with images with fixed size to make them more cross platform and modified 9 test results to reflect that we can scroll container that do not include focusable content. 10 11 * fast/events/spatial-navigation/snav-clipped-overflowed-content-expected.txt: 12 * fast/events/spatial-navigation/snav-clipped-overflowed-content.html: 13 * fast/events/spatial-navigation/snav-div-scrollable-but-without-focusable-content-expected.txt: 14 * fast/events/spatial-navigation/snav-div-scrollable-but-without-focusable-content.html: 15 * fast/events/spatial-navigation/snav-iframe-no-focusable-content-expected.txt: 16 * fast/events/spatial-navigation/snav-iframe-no-focusable-content.html: 17 * fast/events/spatial-navigation/snav-iframe-no-scrollable-content-expected.txt: 18 * fast/events/spatial-navigation/snav-iframe-no-scrollable-content.html: 19 * fast/events/spatial-navigation/snav-iframe-with-offscreen-focusable-element-expected.txt: 20 * fast/events/spatial-navigation/snav-iframe-with-offscreen-focusable-element.html: 21 1 22 2010-11-22 Anton Muhin <antonm@chromium.org> 2 23 -
trunk/LayoutTests/fast/events/spatial-navigation/snav-clipped-overflowed-content-expected.txt
r71915 r72522 7 7 PASS gFocusedDocument.activeElement.getAttribute("id") is "1" 8 8 PASS gFocusedDocument.activeElement.getAttribute("id") is "2" 9 PASS gFocusedDocument.activeElement.getAttribute("id") is "2" 10 PASS gFocusedDocument.activeElement.getAttribute("id") is "2" 9 11 PASS gFocusedDocument.activeElement.getAttribute("id") is "3" 10 12 PASS gFocusedDocument.activeElement.getAttribute("id") is "2" 11 13 PASS gFocusedDocument.activeElement.getAttribute("id") is "2" 14 PASS gFocusedDocument.activeElement.getAttribute("id") is "2" 15 PASS gFocusedDocument.activeElement.getAttribute("id") is "1" 12 16 PASS gFocusedDocument.activeElement.getAttribute("id") is "1" 13 17 PASS gFocusedDocument.activeElement.getAttribute("id") is "start" -
trunk/LayoutTests/fast/events/spatial-navigation/snav-clipped-overflowed-content.html
r71915 r72522 37 37 ["Down", "1"], 38 38 ["Down", "2"], 39 ["Down", "2"], 40 ["Down", "2"], 39 41 ["Down", "3"], 40 42 ["Up", "2"], 41 43 ["Up", "2"], 44 ["Up", "2"], 45 ["Up", "1"], 42 46 ["Up", "1"], 43 47 ["Up", "start"], -
trunk/LayoutTests/fast/events/spatial-navigation/snav-div-scrollable-but-without-focusable-content-expected.txt
r61819 r72522 1 a2 This is a scrollable Div created with the CSS property overflow.3 4 It has no keyboard focusable elements ....5 1 6 2 7 3 8 4 9 10 11 12 13 14 15 16 17 18 ... and scrollbars! 19 20 This is another scrollable div created with the CSS property overflow. 21 22 It has also no keyboard focusable elements .... 23 24 25 26 27 28 29 30 ... as well as scrollbars! 31 32 e 5 PASS gFocusedDocument.activeElement.getAttribute("id") is "start" 6 PASS gFocusedDocument.activeElement.getAttribute("id") is "start" 7 PASS gFocusedDocument.activeElement.getAttribute("id") is "start" 8 PASS gFocusedDocument.activeElement.getAttribute("id") is "start" 9 PASS gFocusedDocument.activeElement.getAttribute("id") is "start" 10 PASS gFocusedDocument.activeElement.getAttribute("id") is "start" 11 PASS gFocusedDocument.activeElement.getAttribute("id") is "end" 12 PASS gFocusedDocument.activeElement.getAttribute("id") is "end" 13 PASS gFocusedDocument.activeElement.getAttribute("id") is "end" 14 PASS gFocusedDocument.activeElement.getAttribute("id") is "end" 15 PASS gFocusedDocument.activeElement.getAttribute("id") is "end" 16 PASS gFocusedDocument.activeElement.getAttribute("id") is "end" 33 17 PASS gFocusedDocument.activeElement.getAttribute("id") is "end" 34 18 PASS gFocusedDocument.activeElement.getAttribute("id") is "start" 35 19 This test is to test that a scrollable div can scroll and reveal its content even if it does not have any focusable content. -
trunk/LayoutTests/fast/events/spatial-navigation/snav-div-scrollable-but-without-focusable-content.html
r61134 r72522 29 29 30 30 var resultMap = [ 31 ["Down", "start"], 32 ["Down", "start"], 33 ["Down", "start"], 34 ["Down", "start"], 35 ["Down", "start"], 36 ["Down", "start"], 31 37 ["Down", "end"], 38 ["Up" , "end"], 39 ["Up" , "end"], 40 ["Up" , "end"], 41 ["Up" , "end"], 42 ["Up" , "end"], 43 ["Up" , "end"], 32 44 ["Up" , "start"], 33 45 ["DONE", "DONE"] … … 60 72 </head> 61 73 <body id="some-content" xmlns="http://www.w3.org/1999/xhtml"> 62 <div><a id="start" href="a"> a</a></div>74 <div><a id="start" href="a"><img src="resources/green.png" width=30 height=30></a></div> 63 75 <div class="scroll"> 64 <p>This is a scrollable Div created with the CSS property overflow.</p> 65 <p>It has no keyboard focusable elements ....</p> 66 <br><br><br><br><br><br> 67 <br><br><br><br><br><br> 68 <p>... and scrollbars!</p> 76 <img src="resources/green.png" width=240 height=300> 69 77 </div> 70 78 71 79 <div class="scroll"> 72 <p>This is another scrollable div created with the CSS property overflow.</p> 73 <p>It has also no keyboard focusable elements ....</p> 74 <br><br><br><br><br><br> 75 <p>... as well as scrollbars!</p> 80 <img src="resources/green.png" width=240 height=300> 76 81 </div> 77 <div><a id="end" href="a"> e</a></div>82 <div><a id="end" href="a"><img src="resources/green.png" width=30 height=30></a></div> 78 83 <div id="console"></div> 84 This test is to test that a scrollable div can scroll and reveal its content even if it does not have any focusable content. 79 85 </body> 80 86 </html> -
trunk/LayoutTests/fast/events/spatial-navigation/snav-iframe-no-focusable-content-expected.txt
r61819 r72522 3 3 4 4 e 5 PASS gFocusedDocument.activeElement.getAttribute("id") is "start" 6 PASS gFocusedDocument.activeElement.getAttribute("id") is "start" 7 PASS gFocusedDocument.activeElement.getAttribute("id") is "start" 8 PASS gFocusedDocument.activeElement.getAttribute("id") is "start" 9 PASS gFocusedDocument.activeElement.getAttribute("id") is "start" 10 PASS gFocusedDocument.activeElement.getAttribute("id") is "start" 11 PASS gFocusedDocument.activeElement.getAttribute("id") is "end" 12 PASS gFocusedDocument.activeElement.getAttribute("id") is "end" 13 PASS gFocusedDocument.activeElement.getAttribute("id") is "end" 14 PASS gFocusedDocument.activeElement.getAttribute("id") is "end" 15 PASS gFocusedDocument.activeElement.getAttribute("id") is "end" 16 PASS gFocusedDocument.activeElement.getAttribute("id") is "end" 5 17 PASS gFocusedDocument.activeElement.getAttribute("id") is "end" 6 18 PASS gFocusedDocument.activeElement.getAttribute("id") is "start" 7 19 This is to test that an iframe with no focusable content still scrolls -
trunk/LayoutTests/fast/events/spatial-navigation/snav-iframe-no-focusable-content.html
r58888 r72522 18 18 19 19 var resultMap = [ 20 ["Down", "start"], 21 ["Down", "start"], 22 ["Down", "start"], 23 ["Down", "start"], 24 ["Down", "start"], 25 ["Down", "start"], 20 26 ["Down", "end"], 27 ["Up" , "end"], 28 ["Up" , "end"], 29 ["Up" , "end"], 30 ["Up" , "end"], 31 ["Up" , "end"], 32 ["Up" , "end"], 21 33 ["Up" , "start"], 22 34 ["DONE", "DONE"] … … 53 65 <iframe width="80" height="80" scrolling="auto" src="data:text/html, 54 66 <body> 55 <div style='margin-top:120px'> 56 <p>This frame has some text and no focusable element ...</a> 57 </div> 58 <p>... and some more text ...</a> 67 <img width=120 height=200 src='resources/green.png'> 59 68 </body> 60 69 "></iframe><br> … … 62 71 <iframe scrolling="auto" src="data:text/html, 63 72 <body> 64 <div style='margin-top:120px'> 65 <p>This frame has some text and no focusable element ...</a> 66 </div> 67 <p>... and some more text ...</a> 73 <img width=120 height=200 src='resources/green.png'> 68 74 </body> 69 75 "></iframe><br> … … 71 77 <a id="end" href="a">e</a> 72 78 <div id="console"></div> 79 This is to test that an iframe with no focusable content still scrolls 73 80 </body> 74 81 </html> -
trunk/LayoutTests/fast/events/spatial-navigation/snav-iframe-no-scrollable-content-expected.txt
r61819 r72522 12 12 PASS gFocusedDocument.activeElement.getAttribute("id") is "5" 13 13 PASS gFocusedDocument.activeElement.getAttribute("id") is "6" 14 PASS gFocusedDocument.activeElement.getAttribute("id") is "3" 14 15 PASS gFocusedDocument.activeElement.getAttribute("id") is "7" 15 16 PASS gFocusedDocument.activeElement.getAttribute("id") is "3" -
trunk/LayoutTests/fast/events/spatial-navigation/snav-iframe-no-scrollable-content.html
r58888 r72522 28 28 ["Right", "5"], 29 29 ["Right", "6"], 30 ["Up", "3"], 30 31 ["Right", "7"], 31 32 ["Up", "3"], -
trunk/LayoutTests/fast/events/spatial-navigation/snav-iframe-with-offscreen-focusable-element-expected.txt
r61819 r72522 1 a2 1 3 e 2 3 PASS gFocusedDocument.activeElement.getAttribute("id") is "1" 4 PASS gFocusedDocument.activeElement.getAttribute("id") is "1" 5 PASS gFocusedDocument.activeElement.getAttribute("id") is "1" 6 PASS gFocusedDocument.activeElement.getAttribute("id") is "1" 4 7 PASS gFocusedDocument.activeElement.getAttribute("id") is "1" 5 8 PASS gFocusedDocument.activeElement.getAttribute("id") is "1" … … 10 13 PASS gFocusedDocument.activeElement.getAttribute("id") is "2" 11 14 PASS gFocusedDocument.activeElement.getAttribute("id") is "2" 15 PASS gFocusedDocument.activeElement.getAttribute("id") is "2" 16 PASS gFocusedDocument.activeElement.getAttribute("id") is "2" 17 PASS gFocusedDocument.activeElement.getAttribute("id") is "2" 18 PASS gFocusedDocument.activeElement.getAttribute("id") is "2" 12 19 PASS gFocusedDocument.activeElement.getAttribute("id") is "1" 13 20 PASS gFocusedDocument.activeElement.getAttribute("id") is "start" -
trunk/LayoutTests/fast/events/spatial-navigation/snav-iframe-with-offscreen-focusable-element.html
r58888 r72522 23 23 ["Down", "1"], 24 24 ["Down", "1"], 25 ["Down", "1"], 26 ["Down", "1"], 27 ["Down", "1"], 28 ["Down", "1"], 25 29 ["Down", "2"], 26 30 ["Down", "end"], 31 ["Up", "2"], 32 ["Up", "2"], 33 ["Up", "2"], 34 ["Up", "2"], 27 35 ["Up", "2"], 28 36 ["Up", "2"], … … 59 67 </head> 60 68 <body id="some-content" xmlns="http://www.w3.org/1999/xhtml"> 61 <div><a id="start" href="a"> a</a></div>69 <div><a id="start" href="a"><img src="resources/green.png" width=30 height=30></a></div> 62 70 63 71 <iframe width="80" height="80" scrolling="auto" src="data:text/html, 64 72 <body> 65 <a id='1' href='a'>b</a> 66 <div style='margin-top:120px'> 67 <a id='2' href='a'>d</a> 73 <a id='1' href='a'><img src='no_image' width=30 height=30></a> 74 <div> 75 <img src='no_image' width=50 height=300> 76 <a id='2' href='a'><img src='no_image' width=30 height=30></a> 68 77 </div> 69 78 </body> 70 79 "></iframe><br> 71 80 72 <div><a id="end" href="a"> e</a></div>81 <div><a id="end" href="a"><img src="resources/green.png" width=30 height=30></a></div> 73 82 <div id="console"></div> 74 83 </body> -
trunk/WebCore/ChangeLog
r72518 r72522 1 2010-11-22 Yael Aharon <yael.aharon@nokia.com>, Chang Shu <chang.shu@nokia.com> 2 3 Reviewed by Antonio Gomes. 4 5 Spatial Navigation: issues with the node selection algorithm. 6 https://bugs.webkit.org/show_bug.cgi?id=49382 7 8 Modify the Spatial Navigation algorithm, to better handle initial focus and 9 navigation between frames. 10 The new algorithm takes the rect of the focused node as the startingRect, 11 instead of the node itself. That allows us to construct a virtual rect if 12 there is no focused node, or if it is off the screen. 13 The virtual rect is the edge of the container in the direction of the navigation. 14 15 With this patch, scrollable containers and frames will scroll regardless of weather 16 they have focusable content. Users will be able to use arrow keys to view all the 17 content of such a container. The only exception is if the container has style overflow:hidden. 18 We will not scroll in that case. 19 20 With this patch, we handle z-index and positioning so that if there are 2 overlapping focusable nodes, 21 we do a hit test and only the node on top can get focus. 22 23 hasOffScreenRect() was modified so that it can check if a node will be off-screen even after we scrolled 24 its parent container. We do not add the scrolling conditions for containers that have overflow:hidden 25 and cannot scroll. 26 27 calculateScrollbarModesForLayout is used to decide if a frame can scroll or not. We cannot rely on 28 the exsistance of the scrollbar, because it could be removed via the API, while the frame is still 29 allowed to scroll. 30 31 * page/FocusController.cpp: 32 (WebCore::updateFocusCandidateIfNeeded): 33 (WebCore::FocusController::findFocusCandidateInContainer): 34 (WebCore::FocusController::advanceFocusDirectionallyInContainer): 35 (WebCore::FocusController::advanceFocusDirectionally): 36 * page/FocusController.h: 37 * page/FrameView.h: 38 * page/SpatialNavigation.cpp: 39 (WebCore::FocusCandidate::FocusCandidate): 40 (WebCore::distanceDataForNode): 41 (WebCore::alignmentForRects): 42 (WebCore::areRectsMoreThanFullScreenApart): 43 (WebCore::isRectInDirection): 44 (WebCore::hasOffscreenRect): 45 (WebCore::scrollInDirection): 46 (WebCore::isScrollableContainerNode): 47 (WebCore::scrollableEnclosingBoxOrParentFrameForNodeInDirection): 48 (WebCore::canScrollInDirection): 49 (WebCore::rectToAbsoluteCoordinates): 50 (WebCore::nodeRectInAbsoluteCoordinates): 51 (WebCore::frameRectInAbsoluteCoordinates): 52 (WebCore::entryAndExitPointsForDirection): 53 (WebCore::canBeScrolledIntoView): 54 (WebCore::virtualRectForDirection): 55 * page/SpatialNavigation.h: 56 1 57 2010-11-22 Nikolas Zimmermann <nzimmermann@rim.com> 2 58 -
trunk/WebCore/page/FocusController.cpp
r72259 r72522 41 41 #include "FrameTree.h" 42 42 #include "FrameView.h" 43 #include "HitTestResult.h" 43 44 #include "HTMLFrameOwnerElement.h" 44 45 #include "HTMLNames.h" … … 46 47 #include "Page.h" 47 48 #include "Range.h" 49 #include "RenderLayer.h" 48 50 #include "RenderObject.h" 49 51 #include "RenderWidget.h" … … 58 60 using namespace std; 59 61 62 static void updateFocusCandidateIfNeeded(FocusDirection direction, const IntRect& startingRect, FocusCandidate& candidate, FocusCandidate& closest); 60 63 static inline void dispatchEventsOnWindowAndFocusedNode(Document* document, bool focused) 61 64 { … … 290 293 } 291 294 292 bool FocusController::advanceFocusDirectionally(FocusDirection direction, KeyboardEvent* event)293 {294 Frame* frame = focusedOrMainFrame();295 ASSERT(frame);296 Document* focusedDocument = frame->document();297 if (!focusedDocument)298 return false;299 300 Node* focusedNode = focusedDocument->focusedNode();301 if (!focusedNode) {302 // Just move to the first focusable node.303 FocusDirection tabDirection = (direction == FocusDirectionUp || direction == FocusDirectionLeft) ?304 FocusDirectionBackward : FocusDirectionForward;305 // 'initialFocus' is set to true so the chrome is not focused.306 return advanceFocusInDocumentOrder(tabDirection, event, true);307 }308 309 // Move up in the chain of nested frames.310 frame = frame->tree()->top();311 312 FocusCandidate focusCandidate;313 findFocusableNodeInDirection(frame->document()->firstChild(), focusedNode, direction, event, focusCandidate);314 315 Node* node = focusCandidate.node;316 if (!node || !node->isElementNode()) {317 // FIXME: May need a way to focus a document here.318 Frame* frame = focusedOrMainFrame();319 scrollInDirection(frame, direction);320 return false;321 }322 323 // In order to avoid crazy jump between links that are either far away from each other,324 // or just not currently visible, lets do a scroll in the given direction and bail out325 // if |node| element is not in the viewport.326 if (hasOffscreenRect(node)) {327 Frame* frame = node->document()->view()->frame();328 scrollInDirection(frame, direction, focusCandidate);329 return true;330 }331 332 Document* newDocument = node->document();333 334 if (newDocument != focusedDocument) {335 // Focus is going away from the originally focused document, so clear the focused node.336 focusedDocument->setFocusedNode(0);337 }338 339 if (newDocument)340 setFocusedFrame(newDocument->frame());341 342 Element* element = static_cast<Element*>(node);343 ASSERT(element);344 345 scrollIntoView(element);346 element->focus(false);347 return true;348 }349 350 295 static void updateFocusCandidateInSameContainer(const FocusCandidate& candidate, FocusCandidate& closest) 351 296 { … … 659 604 } 660 605 606 void updateFocusCandidateIfNeeded(FocusDirection direction, const IntRect& startingRect, FocusCandidate& candidate, FocusCandidate& closest) 607 { 608 if (!candidate.node->isElementNode() || !candidate.node->renderer()) 609 return; 610 611 // Ignore iframes that don't have a src attribute 612 if (candidate.node->isFrameOwnerElement() && !static_cast<HTMLFrameOwnerElement*>(candidate.node)->contentFrame()) 613 return; 614 615 // Ignore off screen child nodes of containers that do not scroll (overflow:hidden) 616 if (hasOffscreenRect(candidate.node) && !canBeScrolledIntoView(direction, candidate)) 617 return; 618 619 FocusCandidate current; 620 current.rect = startingRect; 621 distanceDataForNode(direction, current, candidate); 622 if (candidate.distance == maxDistance()) 623 return; 624 625 if (hasOffscreenRect(candidate.node, direction) && candidate.alignment < Full) 626 return; 627 628 if (closest.isNull()) { 629 closest = candidate; 630 return; 631 } 632 633 IntRect intersectionRect = intersection(nodeRectInAbsoluteCoordinates(candidate.node, true), nodeRectInAbsoluteCoordinates(closest.node, true)); 634 if (!intersectionRect.isEmpty()) { 635 // If 2 nodes are intersecting, do hit test to find which node in on top. 636 int x = intersectionRect.x() + intersectionRect.width() / 2; 637 int y = intersectionRect.y() + intersectionRect.height() / 2; 638 HitTestResult result = candidate.node->document()->page()->mainFrame()->eventHandler()->hitTestResultAtPoint(IntPoint(x, y), false, true); 639 if (candidate.node->contains(result.innerNode())) { 640 closest = candidate; 641 return; 642 } 643 if (closest.node->contains(result.innerNode())) 644 return; 645 } 646 647 if (candidate.alignment == closest.alignment) { 648 if (candidate.distance < closest.distance) 649 closest = candidate; 650 return; 651 } 652 653 if (candidate.alignment > closest.alignment) 654 closest = candidate; 655 } 656 657 void FocusController::findFocusCandidateInContainer(Node* container, const IntRect& startingRect, FocusDirection direction, KeyboardEvent* event, FocusCandidate& closest) 658 { 659 ASSERT(container); 660 Node* focusedNode = (focusedFrame() && focusedFrame()->document()) ? focusedFrame()->document()->focusedNode() : 0; 661 662 Node* node = container->firstChild(); 663 for (; node; node = (node->isFrameOwnerElement() || canScrollInDirection(direction, node)) ? node->traverseNextSibling(container) : node->traverseNextNode(container)) { 664 if (node == focusedNode) 665 continue; 666 667 if (!node->renderer()) 668 continue; 669 670 if (!node->isKeyboardFocusable(event) && !node->isFrameOwnerElement() && !canScrollInDirection(direction, node)) 671 continue; 672 673 FocusCandidate candidate(node); 674 candidate.enclosingScrollableBox = container; 675 updateFocusCandidateIfNeeded(direction, startingRect, candidate, closest); 676 } 677 } 678 679 bool FocusController::advanceFocusDirectionallyInContainer(Node* container, const IntRect& startingRect, FocusDirection direction, KeyboardEvent* event) 680 { 681 if (!container || !container->document()) 682 return false; 683 684 IntRect newStartingRect = startingRect; 685 686 if (startingRect.isEmpty()) 687 newStartingRect = virtualRectForDirection(direction, nodeRectInAbsoluteCoordinates(container)); 688 689 // Find the closest node within current container in the direction of the navigation. 690 FocusCandidate focusCandidate; 691 findFocusCandidateInContainer(container, newStartingRect, direction, event, focusCandidate); 692 693 if (focusCandidate.isNull()) { 694 if (canScrollInDirection(direction, container)) { 695 // Nothing to focus, scroll if possible. 696 scrollInDirection(container, direction); 697 return true; 698 } 699 // Return false will cause a re-try, skipping this container. 700 return false; 701 } 702 if (focusCandidate.node->isFrameOwnerElement()) { 703 HTMLFrameOwnerElement* frameElement = static_cast<HTMLFrameOwnerElement*>(focusCandidate.node); 704 // If we have an iframe without the src attribute, it will not have a contentFrame(). 705 // We ASSERT here to make sure that 706 // updateFocusCandidateIfNeeded() will never consider such an iframe as a candidate. 707 ASSERT(frameElement->contentFrame()); 708 709 if (hasOffscreenRect(focusCandidate.node, direction)) { 710 scrollInDirection(focusCandidate.node->document(), direction); 711 return true; 712 } 713 // Navigate into a new frame. 714 IntRect rect; 715 Node* focusedNode = focusedOrMainFrame()->document()->focusedNode(); 716 if (focusedNode && !hasOffscreenRect(focusedNode)) 717 rect = nodeRectInAbsoluteCoordinates(focusedNode, true /* ignore border */); 718 frameElement->contentFrame()->document()->updateLayoutIgnorePendingStylesheets(); 719 if (!advanceFocusDirectionallyInContainer(frameElement->contentFrame()->document(), rect, direction, event)) { 720 // The new frame had nothing interesting, need to find another candidate. 721 return advanceFocusDirectionallyInContainer(container, nodeRectInAbsoluteCoordinates(focusCandidate.node, true), direction, event); 722 } 723 return true; 724 } 725 if (canScrollInDirection(direction, focusCandidate.node)) { 726 if (hasOffscreenRect(focusCandidate.node, direction)) { 727 scrollInDirection(focusCandidate.node, direction); 728 return true; 729 } 730 // Navigate into a new scrollable container. 731 IntRect startingRect; 732 Node* focusedNode = focusedOrMainFrame()->document()->focusedNode(); 733 if (focusedNode && !hasOffscreenRect(focusedNode)) 734 startingRect = nodeRectInAbsoluteCoordinates(focusedNode, true); 735 return advanceFocusDirectionallyInContainer(focusCandidate.node, startingRect, direction, event); 736 } 737 if (hasOffscreenRect(focusCandidate.node, direction)) { 738 Node* container = focusCandidate.enclosingScrollableBox; 739 scrollInDirection(container, direction); 740 return true; 741 } 742 743 // We found a new focus node, navigate to it. 744 Element* element = toElement(focusCandidate.node); 745 ASSERT(element); 746 747 element->focus(false); 748 return true; 749 } 750 751 bool FocusController::advanceFocusDirectionally(FocusDirection direction, KeyboardEvent* event) 752 { 753 Frame* curFrame = focusedOrMainFrame(); 754 ASSERT(curFrame); 755 756 Document* focusedDocument = curFrame->document(); 757 if (!focusedDocument) 758 return false; 759 760 Node* focusedNode = focusedDocument->focusedNode(); 761 Node* container = focusedDocument; 762 763 // Figure out the starting rect. 764 IntRect startingRect; 765 if (focusedNode && !hasOffscreenRect(focusedNode)) { 766 container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, focusedNode); 767 startingRect = nodeRectInAbsoluteCoordinates(focusedNode, true /* ignore border */); 768 } 769 770 bool consumed = false; 771 do { 772 if (container->isDocumentNode()) 773 static_cast<Document*>(container)->updateLayoutIgnorePendingStylesheets(); 774 consumed = advanceFocusDirectionallyInContainer(container, startingRect, direction, event); 775 startingRect = nodeRectInAbsoluteCoordinates(container, true /* ignore border */); 776 container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, container); 777 } while (!consumed && container); 778 779 return consumed; 780 } 781 661 782 } // namespace WebCore -
trunk/WebCore/page/FocusController.h
r67025 r72522 69 69 void deepFindFocusableNodeInDirection(Node* container, Node* focused, FocusDirection, KeyboardEvent*, FocusCandidate&); 70 70 71 bool advanceFocusDirectionallyInContainer(Node* container, const IntRect& startingRect, FocusDirection, KeyboardEvent*); 72 void findFocusCandidateInContainer(Node* container, const IntRect& startingRect, FocusDirection, KeyboardEvent*, FocusCandidate& closest); 73 71 74 Page* m_page; 72 75 RefPtr<Frame> m_focusedFrame; -
trunk/WebCore/page/FrameView.h
r72465 r72522 237 237 void invalidateScrollCorner(); 238 238 239 void calculateScrollbarModesForLayout(ScrollbarMode& hMode, ScrollbarMode& vMode); 240 239 241 // Normal delay 240 242 static void setRepaintThrottlingDeferredRepaintDelay(double p); … … 266 268 267 269 void applyOverflowToViewport(RenderObject*, ScrollbarMode& hMode, ScrollbarMode& vMode); 268 void calculateScrollbarModesForLayout(ScrollbarMode& hMode, ScrollbarMode& vMode);269 270 270 271 void updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow); -
trunk/WebCore/page/SpatialNavigation.cpp
r71479 r72522 44 44 static long long spatialDistance(FocusDirection, const IntRect&, const IntRect&); 45 45 static IntRect renderRectRelativeToRootDocument(RenderObject*); 46 static RectsAlignment alignmentForRects(FocusDirection, const IntRect&, const IntRect& );46 static RectsAlignment alignmentForRects(FocusDirection, const IntRect&, const IntRect&, const IntSize& viewSize); 47 47 static bool areRectsFullyAligned(FocusDirection, const IntRect&, const IntRect&); 48 48 static bool areRectsPartiallyAligned(FocusDirection, const IntRect&, const IntRect&); 49 static bool areRectsMoreThanFullScreenApart(FocusDirection direction, const IntRect& curRect, const IntRect& targetRect, const IntSize& viewSize); 49 50 static bool isRectInDirection(FocusDirection, const IntRect&, const IntRect&); 50 51 static void deflateIfOverlapped(IntRect&, IntRect&); 51 52 static bool checkNegativeCoordsForNode(Node*, const IntRect&); 53 static IntRect rectToAbsoluteCoordinates(Frame* initialFrame, const IntRect& rect); 54 static void entryAndExitPointsForDirection(FocusDirection direction, const IntRect& startingRect, const IntRect& potentialRect, IntPoint& exitPoint, IntPoint& entryPoint); 55 56 57 FocusCandidate::FocusCandidate(Node* n) 58 : node(n) 59 , enclosingScrollableBox(0) 60 , distance(maxDistance()) 61 , parentDistance(maxDistance()) 62 , alignment(None) 63 , parentAlignment(None) 64 , rect(nodeRectInAbsoluteCoordinates(n, true /* ignore border */)) 65 { 66 } 52 67 53 68 bool isSpatialNavigationEnabled(const Frame* frame) … … 103 118 // for the best focus candidate node. Alignment of rects can be also a good point to be 104 119 // considered in order to make the algorithm to behavior in a more intuitive way. 105 candidate.alignment = alignmentForRects(direction, curRect, targetRect); 120 IntSize viewSize = candidate.node->document()->page()->mainFrame()->view()->visibleContentRect().size(); 121 candidate.alignment = alignmentForRects(direction, curRect, targetRect, viewSize); 106 122 candidate.distance = spatialDistance(direction, curRect, targetRect); 107 123 } … … 137 153 } 138 154 139 static RectsAlignment alignmentForRects(FocusDirection direction, const IntRect& curRect, const IntRect& targetRect) 140 { 155 static RectsAlignment alignmentForRects(FocusDirection direction, const IntRect& curRect, const IntRect& targetRect, const IntSize& viewSize) 156 { 157 // If we found a node in full alignment, but it is too far away, ignore it. 158 if (areRectsMoreThanFullScreenApart(direction, curRect, targetRect, viewSize)) 159 return None; 160 141 161 if (areRectsFullyAligned(direction, curRect, targetRect)) 142 162 return Full; … … 278 298 } 279 299 300 static bool areRectsMoreThanFullScreenApart(FocusDirection direction, const IntRect& curRect, const IntRect& targetRect, const IntSize& viewSize) 301 { 302 ASSERT(isRectInDirection(direction, curRect, targetRect)); 303 304 switch (direction) { 305 case FocusDirectionLeft: 306 return curRect.x() - targetRect.right() > viewSize.width(); 307 case FocusDirectionRight: 308 return targetRect.x() - curRect.right() > viewSize.width(); 309 case FocusDirectionUp: 310 return curRect.y() - targetRect.bottom() > viewSize.height(); 311 case FocusDirectionDown: 312 return targetRect.y() - curRect.bottom() > viewSize.height(); 313 default: 314 ASSERT_NOT_REACHED(); 315 return true; 316 } 317 } 318 280 319 // Return true if rect |a| is below |b|. False otherwise. 281 320 static inline bool below(const IntRect& a, const IntRect& b) … … 404 443 static bool isRectInDirection(FocusDirection direction, const IntRect& curRect, const IntRect& targetRect) 405 444 { 406 IntPoint center(targetRect.center());407 int targetMiddle = isHorizontalMove(direction) ? center.x() : center.y();408 409 445 switch (direction) { 410 446 case FocusDirectionLeft: 411 return target Middle <curRect.x();447 return targetRect.right() <= curRect.x(); 412 448 case FocusDirectionRight: 413 return target Middle >curRect.right();449 return targetRect.x() >= curRect.right(); 414 450 case FocusDirectionUp: 415 return target Middle <curRect.y();451 return targetRect.bottom() <= curRect.y(); 416 452 case FocusDirectionDown: 417 return target Middle >curRect.bottom();453 return targetRect.y() >= curRect.bottom(); 418 454 default: 419 455 ASSERT_NOT_REACHED(); 420 } 421 422 return false; 456 return false; 457 } 423 458 } 424 459 … … 426 461 // document. In case it is, one can scroll in direction or take any different 427 462 // desired action later on. 428 bool hasOffscreenRect(Node* node )463 bool hasOffscreenRect(Node* node, FocusDirection direction) 429 464 { 430 465 // Get the FrameView in which |node| is (which means the current viewport if |node| … … 436 471 437 472 IntRect containerViewportRect = frameView->visibleContentRect(); 473 // We want to select a node if it is currently off screen, but will be 474 // exposed after we scroll. Adjust the viewport to post-scrolling position. 475 // If the container has overflow:hidden, we cannot scroll, so we do not pass direction 476 // and we do not adjust for scrolling. 477 switch (direction) { 478 case FocusDirectionLeft: 479 containerViewportRect.setX(containerViewportRect.x() - Scrollbar::pixelsPerLineStep()); 480 containerViewportRect.setWidth(containerViewportRect.width() + Scrollbar::pixelsPerLineStep()); 481 break; 482 case FocusDirectionRight: 483 containerViewportRect.setWidth(containerViewportRect.width() + Scrollbar::pixelsPerLineStep()); 484 break; 485 case FocusDirectionUp: 486 containerViewportRect.setY(containerViewportRect.y() - Scrollbar::pixelsPerLineStep()); 487 containerViewportRect.setHeight(containerViewportRect.height() + Scrollbar::pixelsPerLineStep()); 488 break; 489 case FocusDirectionDown: 490 containerViewportRect.setHeight(containerViewportRect.height() + Scrollbar::pixelsPerLineStep()); 491 break; 492 default: 493 break; 494 } 438 495 439 496 RenderObject* render = node->renderer(); … … 448 505 } 449 506 450 // In a bottom-up way, this method tries to scroll |frame| in a given direction 451 // |direction|, going up in the frame tree hierarchy in case it does not succeed. 452 bool scrollInDirection(Frame* frame, FocusDirection direction, const FocusCandidate& candidate) 453 { 454 if (!frame) 455 return false; 456 457 ScrollDirection scrollDirection; 458 459 switch (direction) { 460 case FocusDirectionLeft: 461 scrollDirection = ScrollLeft; 462 break; 463 case FocusDirectionRight: 464 scrollDirection = ScrollRight; 465 break; 466 case FocusDirectionUp: 467 scrollDirection = ScrollUp; 468 break; 469 case FocusDirectionDown: 470 scrollDirection = ScrollDown; 471 break; 472 default: 473 return false; 474 } 475 476 if (!candidate.isNull() && isScrollableContainerNode(candidate.enclosingScrollableBox)) 477 return frame->eventHandler()->scrollRecursively(scrollDirection, ScrollByLine, candidate.enclosingScrollableBox); 478 479 return frame->eventHandler()->scrollRecursively(scrollDirection, ScrollByLine); 507 bool scrollInDirection(Frame* frame, FocusDirection direction) 508 { 509 ASSERT(frame && canScrollInDirection(direction, frame->document())); 510 511 if (frame && canScrollInDirection(direction, frame->document())) { 512 int dx = 0; 513 int dy = 0; 514 switch (direction) { 515 case FocusDirectionLeft: 516 dx = - Scrollbar::pixelsPerLineStep(); 517 break; 518 case FocusDirectionRight: 519 dx = Scrollbar::pixelsPerLineStep(); 520 break; 521 case FocusDirectionUp: 522 dy = - Scrollbar::pixelsPerLineStep(); 523 break; 524 case FocusDirectionDown: 525 dy = Scrollbar::pixelsPerLineStep(); 526 break; 527 default: 528 ASSERT_NOT_REACHED(); 529 return false; 530 } 531 532 frame->view()->scrollBy(IntSize(dx, dy)); 533 return true; 534 } 535 return false; 536 } 537 538 bool scrollInDirection(Node* container, FocusDirection direction) 539 { 540 if (container->isDocumentNode()) 541 return scrollInDirection(static_cast<Document*>(container)->frame(), direction); 542 543 if (!container->renderBox()) 544 return false; 545 546 if (container && canScrollInDirection(direction, container)) { 547 int dx = 0; 548 int dy = 0; 549 switch (direction) { 550 case FocusDirectionLeft: 551 dx = - min(Scrollbar::pixelsPerLineStep(), container->renderBox()->scrollLeft()); 552 break; 553 case FocusDirectionRight: 554 ASSERT(container->renderBox()->scrollWidth() > (container->renderBox()->scrollLeft() + container->renderBox()->clientWidth())); 555 dx = min(Scrollbar::pixelsPerLineStep(), container->renderBox()->scrollWidth() - (container->renderBox()->scrollLeft() + container->renderBox()->clientWidth())); 556 break; 557 case FocusDirectionUp: 558 dy = - min(Scrollbar::pixelsPerLineStep(), container->renderBox()->scrollTop()); 559 break; 560 case FocusDirectionDown: 561 ASSERT(container->renderBox()->scrollHeight() - (container->renderBox()->scrollTop() + container->renderBox()->clientHeight())); 562 dy = min(Scrollbar::pixelsPerLineStep(), container->renderBox()->scrollHeight() - (container->renderBox()->scrollTop() + container->renderBox()->clientHeight())); 563 break; 564 default: 565 ASSERT_NOT_REACHED(); 566 return false; 567 } 568 569 container->renderBox()->enclosingLayer()->scrollByRecursively(dx, dy); 570 return true; 571 } 572 return false; 480 573 } 481 574 … … 535 628 } 536 629 537 bool isScrollableContainerNode( Node* node)630 bool isScrollableContainerNode(const Node* node) 538 631 { 539 632 if (!node) … … 568 661 } 569 662 663 Node* scrollableEnclosingBoxOrParentFrameForNodeInDirection(FocusDirection direction, Node* node) 664 { 665 ASSERT(node); 666 Node* parent = node; 667 do { 668 if (parent->isDocumentNode()) 669 parent = static_cast<Document*>(parent)->document()->frame()->ownerElement(); 670 else 671 parent = parent->parentNode(); 672 } while (parent && !canScrollInDirection(direction, parent) && !parent->isDocumentNode()); 673 674 return parent; 675 } 676 677 bool canScrollInDirection(FocusDirection direction, const Node* container) 678 { 679 ASSERT(container); 680 if (container->isDocumentNode()) 681 return canScrollInDirection(direction, static_cast<const Document*>(container)->frame()); 682 683 if (!isScrollableContainerNode(container)) 684 return false; 685 686 switch (direction) { 687 case FocusDirectionLeft: 688 return (container->renderer()->style()->overflowX() != OHIDDEN && container->renderBox()->scrollLeft() > 0); 689 case FocusDirectionUp: 690 return (container->renderer()->style()->overflowY() != OHIDDEN && container->renderBox()->scrollTop() > 0); 691 case FocusDirectionRight: 692 return (container->renderer()->style()->overflowX() != OHIDDEN && container->renderBox()->scrollLeft() + container->renderBox()->clientWidth() < container->renderBox()->scrollWidth()); 693 case FocusDirectionDown: 694 return (container->renderer()->style()->overflowY() != OHIDDEN && container->renderBox()->scrollTop() + container->renderBox()->clientHeight() < container->renderBox()->scrollHeight()); 695 default: 696 ASSERT_NOT_REACHED(); 697 return false; 698 } 699 } 700 701 bool canScrollInDirection(FocusDirection direction, const Frame* frame) 702 { 703 if (!frame->view()) 704 return false; 705 ScrollbarMode verticalMode; 706 ScrollbarMode horizontalMode; 707 frame->view()->calculateScrollbarModesForLayout(horizontalMode, verticalMode); 708 if ((direction == FocusDirectionLeft || direction == FocusDirectionRight) && ScrollbarAlwaysOff == horizontalMode) 709 return false; 710 if ((direction == FocusDirectionUp || direction == FocusDirectionDown) && ScrollbarAlwaysOff == verticalMode) 711 return false; 712 IntSize size = frame->view()->contentsSize(); 713 IntSize offset = frame->view()->scrollOffset(); 714 IntRect rect = frame->view()->visibleContentRect(true); 715 716 switch (direction) { 717 case FocusDirectionLeft: 718 return offset.width() > 0; 719 case FocusDirectionUp: 720 return offset.height() > 0; 721 case FocusDirectionRight: 722 return rect.width() + offset.width() < size.width(); 723 case FocusDirectionDown: 724 return rect.height() + offset.height() < size.height(); 725 default: 726 ASSERT_NOT_REACHED(); 727 return false; 728 } 729 } 730 731 static IntRect rectToAbsoluteCoordinates(Frame* initialFrame, const IntRect& initialRect) 732 { 733 IntRect rect = initialRect; 734 for (Frame* frame = initialFrame; frame; frame = frame->tree()->parent()) { 735 if (Element* element = static_cast<Element*>(frame->ownerElement())) { 736 do { 737 rect.move(element->offsetLeft(), element->offsetTop()); 738 } while ((element = element->offsetParent())); 739 rect.move((-frame->view()->scrollOffset())); 740 } 741 } 742 return rect; 743 } 744 745 IntRect nodeRectInAbsoluteCoordinates(Node* node, bool ignoreBorder) 746 { 747 ASSERT(node && node->renderer()); 748 749 if (node->isDocumentNode()) 750 return frameRectInAbsoluteCoordinates(static_cast<Document*>(node)->frame()); 751 IntRect rect = rectToAbsoluteCoordinates(node->document()->frame(), node->getRect()); 752 753 // For authors that use border instead of outline in their CSS, we compensate by ignoring the border when calculating 754 // the rect of the focused element. 755 if (ignoreBorder) { 756 rect.move(node->renderer()->style()->borderLeftWidth(), node->renderer()->style()->borderTopWidth()); 757 rect.setWidth(rect.width() - node->renderer()->style()->borderLeftWidth() - node->renderer()->style()->borderRightWidth()); 758 rect.setHeight(rect.height() - node->renderer()->style()->borderTopWidth() - node->renderer()->style()->borderBottomWidth()); 759 } 760 return rect; 761 } 762 763 IntRect frameRectInAbsoluteCoordinates(Frame* frame) 764 { 765 return rectToAbsoluteCoordinates(frame, frame->view()->visibleContentRect()); 766 } 767 768 // This method calculates the exitPoint from the startingRect and the entryPoint into the candidate rect. 769 // The line between those 2 points is the closest distance between the 2 rects. 770 void entryAndExitPointsForDirection(FocusDirection direction, const IntRect& startingRect, const IntRect& potentialRect, IntPoint& exitPoint, IntPoint& entryPoint) 771 { 772 switch (direction) { 773 case FocusDirectionLeft: 774 exitPoint.setX(startingRect.x()); 775 entryPoint.setX(potentialRect.right()); 776 break; 777 case FocusDirectionUp: 778 exitPoint.setY(startingRect.y()); 779 entryPoint.setY(potentialRect.bottom()); 780 break; 781 case FocusDirectionRight: 782 exitPoint.setX(startingRect.right()); 783 entryPoint.setX(potentialRect.x()); 784 break; 785 case FocusDirectionDown: 786 exitPoint.setY(startingRect.bottom()); 787 entryPoint.setY(potentialRect.y()); 788 break; 789 default: 790 ASSERT_NOT_REACHED(); 791 } 792 793 switch (direction) { 794 case FocusDirectionLeft: 795 case FocusDirectionRight: 796 if (below(startingRect, potentialRect)) { 797 exitPoint.setY(startingRect.y()); 798 entryPoint.setY(potentialRect.bottom()); 799 } else if (below(potentialRect, startingRect)) { 800 exitPoint.setY(startingRect.bottom()); 801 entryPoint.setY(potentialRect.y()); 802 } else { 803 exitPoint.setY(max(startingRect.y(), potentialRect.y())); 804 entryPoint.setY(exitPoint.y()); 805 } 806 break; 807 case FocusDirectionUp: 808 case FocusDirectionDown: 809 if (rightOf(startingRect, potentialRect)) { 810 exitPoint.setX(startingRect.x()); 811 entryPoint.setX(potentialRect.right()); 812 } else if (rightOf(potentialRect, startingRect)) { 813 exitPoint.setX(startingRect.right()); 814 entryPoint.setX(potentialRect.x()); 815 } else { 816 exitPoint.setX(max(startingRect.x(), potentialRect.x())); 817 entryPoint.setX(exitPoint.x()); 818 } 819 break; 820 default: 821 ASSERT_NOT_REACHED(); 822 } 823 } 824 825 void distanceDataForNode(FocusDirection direction, FocusCandidate& current, FocusCandidate& candidate) 826 { 827 if (candidate.isNull()) 828 return; 829 if (!candidate.node->renderer()) 830 return; 831 IntRect nodeRect = candidate.rect; 832 IntRect currentRect = current.rect; 833 deflateIfOverlapped(currentRect, nodeRect); 834 835 if (!isRectInDirection(direction, currentRect, nodeRect)) 836 return; 837 838 IntPoint exitPoint; 839 IntPoint entryPoint; 840 int sameAxisDistance = 0; 841 int otherAxisDistance = 0; 842 entryAndExitPointsForDirection(direction, currentRect, nodeRect, exitPoint, entryPoint); 843 844 switch (direction) { 845 case FocusDirectionLeft: 846 sameAxisDistance = exitPoint.x() - entryPoint.x(); 847 otherAxisDistance = abs(exitPoint.y() - entryPoint.y()); 848 break; 849 case FocusDirectionUp: 850 sameAxisDistance = exitPoint.y() - entryPoint.y(); 851 otherAxisDistance = abs(exitPoint.x() - entryPoint.x()); 852 break; 853 case FocusDirectionRight: 854 sameAxisDistance = entryPoint.x() - exitPoint.x(); 855 otherAxisDistance = abs(entryPoint.y() - exitPoint.y()); 856 break; 857 case FocusDirectionDown: 858 sameAxisDistance = entryPoint.y() - exitPoint.y(); 859 otherAxisDistance = abs(entryPoint.x() - exitPoint.x()); 860 break; 861 default: 862 ASSERT_NOT_REACHED(); 863 return; 864 } 865 866 int x = (entryPoint.x() - exitPoint.x()) * (entryPoint.x() - exitPoint.x()); 867 int y = (entryPoint.y() - exitPoint.y()) * (entryPoint.y() - exitPoint.y()); 868 869 float euclidianDistance = sqrt((x + y) * 1.0f); 870 871 // Loosely based on http://www.w3.org/TR/WICD/#focus-handling 872 // df = dotDist + dx + dy + 2 * (xdisplacement + ydisplacement) - sqrt(Overlap) 873 874 float distance = euclidianDistance + sameAxisDistance + 2 * otherAxisDistance; 875 candidate.distance = roundf(distance); 876 IntSize viewSize = candidate.node->document()->page()->mainFrame()->view()->visibleContentRect().size(); 877 candidate.alignment = alignmentForRects(direction, currentRect, nodeRect, viewSize); 878 } 879 880 bool canBeScrolledIntoView(FocusDirection direction, FocusCandidate& candidate) 881 { 882 ASSERT(candidate.node && hasOffscreenRect(candidate.node)); 883 IntRect candidateRect = candidate.rect; 884 for (Node* parentNode = candidate.node->parent(); parentNode; parentNode = parentNode->parent()) { 885 IntRect parentRect = nodeRectInAbsoluteCoordinates(parentNode); 886 if (!candidateRect.intersects(parentRect)) { 887 if (((direction == FocusDirectionLeft || direction == FocusDirectionRight) && parentNode->renderer()->style()->overflowX() == OHIDDEN) 888 || ((direction == FocusDirectionUp || direction == FocusDirectionDown) && parentNode->renderer()->style()->overflowY() == OHIDDEN)) 889 return false; 890 } 891 if (parentNode == candidate.enclosingScrollableBox) 892 return canScrollInDirection(direction, parentNode); 893 } 894 return true; 895 } 896 897 // The starting rect is the rect of the focused node, in document coordinates. 898 // Compose a virtual starting rect if there is no focused node or if it is off screen. 899 // The virtual rect is the edge of the container or frame. We select which 900 // edge depending on the direction of the navigation. 901 IntRect virtualRectForDirection(FocusDirection direction, const IntRect& startingRect) 902 { 903 IntRect virtualStartingRect = startingRect; 904 switch (direction) { 905 case FocusDirectionLeft: 906 virtualStartingRect.setX(virtualStartingRect.right()); 907 virtualStartingRect.setWidth(0); 908 break; 909 case FocusDirectionUp: 910 virtualStartingRect.setY(virtualStartingRect.bottom()); 911 virtualStartingRect.setHeight(0); 912 break; 913 case FocusDirectionRight: 914 virtualStartingRect.setWidth(0); 915 break; 916 case FocusDirectionDown: 917 virtualStartingRect.setHeight(0); 918 break; 919 default: 920 ASSERT_NOT_REACHED(); 921 } 922 923 return virtualStartingRect; 924 } 925 926 570 927 } // namespace WebCore -
trunk/WebCore/page/SpatialNavigation.h
r71479 r72522 23 23 24 24 #include "FocusDirection.h" 25 #include "IntRect.h" 25 26 #include "Node.h" 26 27 … … 108 109 } 109 110 110 FocusCandidate(Node* n) 111 : node(n) 112 , enclosingScrollableBox(0) 113 , distance(maxDistance()) 114 , parentDistance(maxDistance()) 115 , alignment(None) 116 , parentAlignment(None) 117 { 118 } 119 111 FocusCandidate(Node* n); 120 112 bool isNull() const { return !node; } 121 113 bool inScrollableContainer() const { return node && enclosingScrollableBox; } … … 128 120 RectsAlignment alignment; 129 121 RectsAlignment parentAlignment; 122 IntRect rect; 130 123 }; 131 124 132 125 void distanceDataForNode(FocusDirection direction, Node* start, FocusCandidate& candidate); 133 bool scrollInDirection(Frame*, FocusDirection, const FocusCandidate& candidate = FocusCandidate()); 126 bool scrollInDirection(Frame*, FocusDirection); 127 bool scrollInDirection(Node* container, FocusDirection); 134 128 void scrollIntoView(Element*); 135 bool hasOffscreenRect(Node* );129 bool hasOffscreenRect(Node*, FocusDirection direction = FocusDirectionNone); 136 130 bool isInRootDocument(Node*); 137 bool isScrollableContainerNode( Node*);131 bool isScrollableContainerNode(const Node*); 138 132 bool isNodeDeepDescendantOfDocument(Node*, Document*); 139 133 Node* scrollableEnclosingBoxOrParentFrameForNodeInDirection(FocusDirection, Node* node); 134 bool canScrollInDirection(FocusDirection, const Node* container); 135 bool canScrollInDirection(FocusDirection, const Frame*); 136 IntRect nodeRectInAbsoluteCoordinates(Node*, bool ignoreBorder = false); 137 IntRect frameRectInAbsoluteCoordinates(Frame*); 138 void distanceDataForNode(FocusDirection, FocusCandidate& current, FocusCandidate& candidate); 139 bool canBeScrolledIntoView(FocusDirection, FocusCandidate&); 140 IntRect virtualRectForDirection(FocusDirection, const IntRect& startingRect); 140 141 } // namspace WebCore 141 142
Note: See TracChangeset
for help on using the changeset viewer.