Changeset 88421 in webkit
- Timestamp:
- Jun 8, 2011 10:33:12 PM (13 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r88418 r88421 1 2011-06-08 Hayato Ito <hayato@chromium.org> 2 3 Reviewed by Dimitri Glazkov. 4 5 A forward/backward tab traversal now visits focusable elements in a shadow root. 6 https://bugs.webkit.org/show_bug.cgi?id=61410 7 8 Like a iframe element, a shadow host becomes a scope of 9 tabindex. That means all descendant elements in a shadow root are 10 skipped if the host node of the shadow root is not focusable. 11 12 The patch doesn't affect HTMLInputElement and HTMLTextAreaElement, 13 which uses a shadow root and do extra works in their focus() 14 method. 15 16 A shadow root's <content> is not considered in this patch. 17 That will be addressed in a following patch. 18 19 * fast/dom/shadow/tab-order-iframe-and-shadow-expected.txt: Added. 20 * fast/dom/shadow/tab-order-iframe-and-shadow.html: Added. 21 1 22 2011-06-08 Hayato Ito <hayato@chromium.org> 2 23 -
trunk/Source/WebCore/ChangeLog
r88418 r88421 1 2011-06-08 Hayato Ito <hayato@chromium.org> 2 3 Reviewed by Dimitri Glazkov. 4 5 A forward/backward tab traversal now visits focusable elements in a shadow root. 6 https://bugs.webkit.org/show_bug.cgi?id=61410 7 8 Test: fast/dom/shadow/tab-order-iframe-and-shadow.html 9 10 Like a iframe element, a shadow host becomes a scope of 11 tabindex. That means all descendant elements in a shadow root are 12 skipped if the host node of the shadow root is not focusable. 13 14 The patch doesn't affect HTMLInputElement and HTMLTextAreaElement, 15 which uses a shadow root and do extra works in their focus() 16 method. 17 18 A shadow root's <content> is not considered in this patch. 19 That will be addressed in a following patch. 20 21 * page/FocusController.cpp: 22 (WebCore::shadowRoot): 23 (WebCore::isTreeScopeOwner): 24 (WebCore::FocusController::deepFocusableNode): 25 (WebCore::FocusController::advanceFocusInDocumentOrder): 26 (WebCore::FocusController::findFocusableNodeAcrossTreeScope): 27 (WebCore::FocusController::findFocusableNode): 28 (WebCore::FocusController::nextFocusableNode): 29 (WebCore::FocusController::previousFocusableNode): 30 (WebCore::FocusController::ownerOfTreeScope): 31 * page/FocusController.h: 32 1 33 2011-06-08 Hayato Ito <hayato@chromium.org> 2 34 -
trunk/Source/WebCore/page/FocusController.cpp
r87874 r88421 54 54 #include "ScrollAnimator.h" 55 55 #include "Settings.h" 56 #include "ShadowRoot.h" 56 57 #include "SpatialNavigation.h" 57 58 #include "Widget.h" … … 146 147 } 147 148 149 inline static ShadowRoot* shadowRoot(Node* node) 150 { 151 return node->isElementNode() ? toElement(node)->shadowRoot() : 0; 152 } 153 154 inline static bool isTreeScopeOwner(Node* node) 155 { 156 return node && (node->isFrameOwnerElement() || shadowRoot(node)); 157 } 158 148 159 Node* FocusController::deepFocusableNode(FocusDirection direction, Node* node, KeyboardEvent* event) 149 160 { 150 // The node we found might be a HTMLFrameOwnerElement , so descend down the frame tree until we find either:161 // The node we found might be a HTMLFrameOwnerElement or a shadow host, so descend down the tree until we find either: 151 162 // 1) a focusable node, or 152 // 2) the deepest-nested HTMLFrameOwnerElement 153 while (node && node->isFrameOwnerElement()) { 154 HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(node); 155 if (!owner->contentFrame()) 163 // 2) the deepest-nested HTMLFrameOwnerElement or shadow host. 164 while (isTreeScopeOwner(node)) { 165 Node* foundNode; 166 if (node->isFrameOwnerElement()) { 167 HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(node); 168 if (!owner->contentFrame()) 169 break; 170 Document* document = owner->contentFrame()->document(); 171 foundNode = findFocusableNode(direction, document, 0, event); 172 } else { 173 ASSERT(shadowRoot(node)); 174 // FIXME: Some elements (e.g. HTMLInputElement and HTMLTextAreaElement) do extra work in their focus() methods. 175 // Skipping these elements is the safest fix until we find a better way. 176 if (node->hasTagName(inputTag) || node->hasTagName(textareaTag)) 177 break; 178 foundNode = findFocusableNode(direction, shadowRoot(node), 0, event); 179 } 180 if (!foundNode) 156 181 break; 157 158 Document* document = owner->contentFrame()->document(); 159 160 node = (direction == FocusDirectionForward) 161 ? nextFocusableNode(document, 0, event) 162 : previousFocusableNode(document, 0, event); 163 if (!node) { 164 node = owner; 165 break; 166 } 167 } 168 182 ASSERT(node != foundNode); 183 node = foundNode; 184 } 169 185 return node; 170 186 } … … 216 232 document->updateLayoutIgnorePendingStylesheets(); 217 233 218 Node* node = (direction == FocusDirectionForward) 219 ? nextFocusableNode(document, currentNode, event) 220 : previousFocusableNode(document, currentNode, event); 221 222 // If there's no focusable node to advance to, move up the frame tree until we find one. 223 while (!node && frame) { 224 Frame* parentFrame = frame->tree()->parent(); 225 if (!parentFrame) 226 break; 227 228 Document* parentDocument = parentFrame->document(); 229 230 HTMLFrameOwnerElement* owner = frame->ownerElement(); 231 if (!owner) 232 break; 233 234 node = (direction == FocusDirectionForward) 235 ? nextFocusableNode(parentDocument, owner, event) 236 : previousFocusableNode(parentDocument, owner, event); 237 238 frame = parentFrame; 239 } 240 241 node = deepFocusableNode(direction, node, event); 234 Node* node = findFocusableNodeAcrossTreeScope(direction, currentNode ? currentNode->treeScope() : document, currentNode, event); 242 235 243 236 if (!node) { … … 251 244 252 245 // Chrome doesn't want focus, so we should wrap focus. 253 Document* d = m_page->mainFrame()->document(); 254 node = (direction == FocusDirectionForward) 255 ? nextFocusableNode(d, 0, event) 256 : previousFocusableNode(d, 0, event); 257 246 node = findFocusableNode(direction, m_page->mainFrame()->document(), 0, event); 258 247 node = deepFocusableNode(direction, node, event); 259 248 … … 306 295 static_cast<Element*>(node)->focus(false); 307 296 return true; 297 } 298 299 Node* FocusController::findFocusableNodeAcrossTreeScope(FocusDirection direction, TreeScope* scope, Node* currentNode, KeyboardEvent* event) 300 { 301 Node* node = findFocusableNode(direction, scope, currentNode, event); 302 // If there's no focusable node to advance to, move up the tree scopes until we find one. 303 while (!node && scope) { 304 Node* owner = ownerOfTreeScope(scope); 305 if (!owner) 306 break; 307 node = findFocusableNode(direction, owner->treeScope(), owner, event); 308 scope = owner->treeScope(); 309 } 310 node = deepFocusableNode(direction, node, event); 311 return node; 312 } 313 314 315 Node* FocusController::findFocusableNode(FocusDirection direction, TreeScope* scope, Node* node, KeyboardEvent* event) 316 { 317 return (direction == FocusDirectionForward) 318 ? nextFocusableNode(scope, node, event) 319 : previousFocusableNode(scope, node, event); 308 320 } 309 321 … … 356 368 } 357 369 358 Node* FocusController::nextFocusableNode(TreeScope* within, Node* start, KeyboardEvent* event)370 Node* FocusController::nextFocusableNode(TreeScope* scope, Node* start, KeyboardEvent* event) 359 371 { 360 372 if (start) { … … 366 378 } 367 379 368 // First try to find a node with the same tabindex as start that comes after start in the treescope.380 // First try to find a node with the same tabindex as start that comes after start in the scope. 369 381 if (Node* winner = nextNodeWithExactTabIndex(start->traverseNextNode(), start->tabIndex(), event)) 370 382 return winner; … … 375 387 } 376 388 377 // Look for the first node in the treescope that:389 // Look for the first node in the scope that: 378 390 // 1) has the lowest tabindex that is higher than start's tabindex (or 0, if start is null), and 379 // 2) comes first in the treescope, if there's a tie.380 if (Node* winner = nextNodeWithGreaterTabIndex( within, start ? start->tabIndex() : 0, event))391 // 2) comes first in the scope, if there's a tie. 392 if (Node* winner = nextNodeWithGreaterTabIndex(scope, start ? start->tabIndex() : 0, event)) 381 393 return winner; 382 394 383 395 // There are no nodes with a tabindex greater than start's tabindex, 384 396 // so find the first node with a tabindex of 0. 385 return nextNodeWithExactTabIndex( within, 0, event);386 } 387 388 Node* FocusController::previousFocusableNode(TreeScope* within, Node* start, KeyboardEvent* event)397 return nextNodeWithExactTabIndex(scope, 0, event); 398 } 399 400 Node* FocusController::previousFocusableNode(TreeScope* scope, Node* start, KeyboardEvent* event) 389 401 { 390 402 Node* last; 391 for (last = within; last->lastChild(); last = last->lastChild()) { }392 393 // First try to find the last node in the treescope that comes before start and has the same tabindex as start.394 // If start is null, find the last node in the treescope with a tabindex of 0.403 for (last = scope; last->lastChild(); last = last->lastChild()) { } 404 405 // First try to find the last node in the scope that comes before start and has the same tabindex as start. 406 // If start is null, find the last node in the scope with a tabindex of 0. 395 407 Node* startingNode; 396 408 int startingTabIndex; … … 415 427 // There are no nodes before start with the same tabindex as start, so look for a node that: 416 428 // 1) has the highest non-zero tabindex (that is less than start's tabindex), and 417 // 2) comes last in the treescope, if there's a tie.429 // 2) comes last in the scope, if there's a tie. 418 430 startingTabIndex = (start && start->tabIndex()) ? start->tabIndex() : std::numeric_limits<short>::max(); 419 431 return previousNodeWithLowerTabIndex(last, startingTabIndex, event); 432 } 433 434 Node* FocusController::ownerOfTreeScope(TreeScope* scope) 435 { 436 ASSERT(scope); 437 if (scope->isShadowRoot()) 438 return scope->shadowHost(); 439 if (scope->document()->frame()) 440 return scope->document()->frame()->ownerElement(); 441 return 0; 420 442 } 421 443 -
trunk/Source/WebCore/page/FocusController.h
r87874 r88421 66 66 bool advanceFocusInDocumentOrder(FocusDirection, KeyboardEvent*, bool initialFocus); 67 67 68 Node* findFocusableNodeAcrossTreeScope(FocusDirection, TreeScope* startScope, Node* start, KeyboardEvent*); 68 69 Node* deepFocusableNode(FocusDirection, Node*, KeyboardEvent*); 70 Node* ownerOfTreeScope(TreeScope*); 71 72 // Searches through the given tree scope, starting from start node, for the next/previous selectable element that comes after/before start node. 73 // The order followed is as specified in section 17.11.1 of the HTML4 spec, which is elements with tab indexes 74 // first (from lowest to highest), and then elements without tab indexes (in document order). 75 // 76 // @param start The node from which to start searching. The node after this will be focused. May be null. 77 // 78 // @return The focus node that comes after/before start node. 79 // 80 // See http://www.w3.org/TR/html4/interact/forms.html#h-17.11.1 81 inline Node* findFocusableNode(FocusDirection, TreeScope*, Node* start, KeyboardEvent*); 82 83 Node* nextFocusableNode(TreeScope*, Node* start, KeyboardEvent*); 84 Node* previousFocusableNode(TreeScope*, Node* start, KeyboardEvent*); 69 85 70 86 bool advanceFocusDirectionallyInContainer(Node* container, const IntRect& startingRect, FocusDirection, KeyboardEvent*); … … 77 93 bool m_isChangingFocusedFrame; 78 94 79 // Searches through the document, starting from start node, for the next selectable element that comes after start node.80 // The order followed is as specified in section 17.11.1 of the HTML4 spec, which is elements with tab indexes81 // first (from lowest to highest), and then elements without tab indexes (in document order).82 //83 // @param within The tree scope where a search is executed.84 // @param start The node from which to start searching. The node before this will be focused. May be null.85 //86 // @return The focus node that comes after start node.87 //88 // See http://www.w3.org/TR/html4/interact/forms.html#h-17.11.189 Node* nextFocusableNode(TreeScope* within, Node* start, KeyboardEvent*);90 91 // Searches through the document, starting from start node, for the previous selectable element that comes before start node.92 // The order followed is as specified in section 17.11.1 of the HTML4 spec, which is elements with tab indexes93 // first (from lowest to highest), and then elements without tab indexes (in document order).94 //95 // @param within The tree scope where a search is executed.96 // @param start The node from which to start searching. The node before this will be focused. May be null.97 //98 // @return The focus node that comes before start node.99 //100 // See http://www.w3.org/TR/html4/interact/forms.html#h-17.11.1101 Node* previousFocusableNode(TreeScope* within, Node* start, KeyboardEvent*);102 95 }; 103 96
Note: See TracChangeset
for help on using the changeset viewer.