Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. | 2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. |
| 3 * Copyright (C) 2008 Nuanti Ltd. | 3 * Copyright (C) 2008 Nuanti Ltd. |
| 4 * | 4 * |
| 5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
| 7 * are met: | 7 * are met: |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 65 namespace { | 65 namespace { |
| 66 | 66 |
| 67 inline bool isShadowInsertionPointFocusScopeOwner(Element& element) | 67 inline bool isShadowInsertionPointFocusScopeOwner(Element& element) |
| 68 { | 68 { |
| 69 return isActiveShadowInsertionPoint(element) && toHTMLShadowElement(element) .olderShadowRoot(); | 69 return isActiveShadowInsertionPoint(element) && toHTMLShadowElement(element) .olderShadowRoot(); |
| 70 } | 70 } |
| 71 | 71 |
| 72 class FocusNavigationScope { | 72 class FocusNavigationScope { |
| 73 STACK_ALLOCATED(); | 73 STACK_ALLOCATED(); |
| 74 public: | 74 public: |
| 75 Node* rootNode() const; | 75 Element* firstElement() const; |
| 76 Element* lastElement() const; | |
| 76 Element* owner() const; | 77 Element* owner() const; |
| 77 static FocusNavigationScope focusNavigationScopeOf(const Element&); | 78 static FocusNavigationScope focusNavigationScopeOf(const Element&); |
| 78 static FocusNavigationScope ownedByNonFocusableFocusScopeOwner(Element&); | 79 static FocusNavigationScope ownedByNonFocusableFocusScopeOwner(Element&); |
| 79 static FocusNavigationScope ownedByShadowHost(const Element&); | 80 static FocusNavigationScope ownedByShadowHost(const Element&); |
| 80 static FocusNavigationScope ownedByShadowInsertionPoint(HTMLShadowElement&); | 81 static FocusNavigationScope ownedByShadowInsertionPoint(HTMLShadowElement&); |
| 81 static FocusNavigationScope ownedByIFrame(const HTMLFrameOwnerElement&); | 82 static FocusNavigationScope ownedByIFrame(const HTMLFrameOwnerElement&); |
| 82 | 83 |
| 83 private: | 84 private: |
| 84 explicit FocusNavigationScope(TreeScope*); | 85 explicit FocusNavigationScope(TreeScope*); |
| 86 ContainerNode& rootNode() const; | |
| 85 RawPtrWillBeMember<TreeScope> m_rootTreeScope; | 87 RawPtrWillBeMember<TreeScope> m_rootTreeScope; |
| 86 }; | 88 }; |
| 87 | 89 |
| 88 FocusNavigationScope::FocusNavigationScope(TreeScope* treeScope) | 90 FocusNavigationScope::FocusNavigationScope(TreeScope* treeScope) |
| 89 : m_rootTreeScope(treeScope) | 91 : m_rootTreeScope(treeScope) |
| 90 { | 92 { |
| 91 ASSERT(treeScope); | 93 ASSERT(treeScope); |
| 92 } | 94 } |
| 93 | 95 |
| 94 Node* FocusNavigationScope::rootNode() const | 96 ContainerNode& FocusNavigationScope::rootNode() const |
| 95 { | 97 { |
| 96 return &m_rootTreeScope->rootNode(); | 98 return m_rootTreeScope->rootNode(); |
| 99 } | |
| 100 | |
| 101 Element* FocusNavigationScope::firstElement() const | |
| 102 { | |
| 103 Node& root = m_rootTreeScope->rootNode(); | |
|
kochi
2016/02/19 07:25:35
nit: |ContainerNode&| ?
hayato
2016/02/19 07:47:44
Done.
| |
| 104 return root.isElementNode() ? &toElement(root) : ElementTraversal::next(root ); | |
| 105 } | |
| 106 | |
| 107 Element* FocusNavigationScope::lastElement() const | |
| 108 { | |
| 109 if (Node* last = NodeTraversal::lastWithin(rootNode())) | |
| 110 return last->isElementNode() ? toElement(last) : ElementTraversal::previ ous(*last); | |
|
kochi
2016/02/19 07:25:35
Can |ElementTraversal::lastWithin(rootNode())| ret
hayato
2016/02/19 07:47:44
It can not. A node can have the non-element last c
hayato
2016/02/19 08:21:28
I'm wrong. Looks ElementTraversal::lastWithin does
| |
| 111 return nullptr; | |
| 97 } | 112 } |
| 98 | 113 |
| 99 Element* FocusNavigationScope::owner() const | 114 Element* FocusNavigationScope::owner() const |
| 100 { | 115 { |
| 101 Node* root = rootNode(); | 116 Node& root = rootNode(); |
|
kochi
2016/02/19 07:25:35
nit: |ContainerNode&| ?
hayato
2016/02/19 07:47:44
Done.
| |
| 102 if (root->isShadowRoot()) { | 117 if (root.isShadowRoot()) { |
| 103 ShadowRoot* shadowRoot = toShadowRoot(root); | 118 ShadowRoot& shadowRoot = toShadowRoot(root); |
| 104 return shadowRoot->isYoungest() ? shadowRoot->host() : shadowRoot->shado wInsertionPointOfYoungerShadowRoot(); | 119 return shadowRoot.isYoungest() ? shadowRoot.host() : shadowRoot.shadowIn sertionPointOfYoungerShadowRoot(); |
| 105 } | 120 } |
| 106 // FIXME: Figure out the right thing for OOPI here. | 121 // FIXME: Figure out the right thing for OOPI here. |
| 107 if (Frame* frame = root->document().frame()) | 122 if (Frame* frame = root.document().frame()) |
| 108 return frame->deprecatedLocalOwner(); | 123 return frame->deprecatedLocalOwner(); |
| 109 return nullptr; | 124 return nullptr; |
| 110 } | 125 } |
| 111 | 126 |
| 112 FocusNavigationScope FocusNavigationScope::focusNavigationScopeOf(const Element& element) | 127 FocusNavigationScope FocusNavigationScope::focusNavigationScopeOf(const Element& element) |
| 113 { | 128 { |
| 114 return FocusNavigationScope(&element.treeScope()); | 129 return FocusNavigationScope(&element.treeScope()); |
| 115 } | 130 } |
| 116 | 131 |
| 117 FocusNavigationScope FocusNavigationScope::ownedByNonFocusableFocusScopeOwner(El ement& element) | 132 FocusNavigationScope FocusNavigationScope::ownedByNonFocusableFocusScopeOwner(El ement& element) |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 196 { | 211 { |
| 197 return element.isHTMLElement() && toHTMLElement(element).hasCustomFocusLogic (); | 212 return element.isHTMLElement() && toHTMLElement(element).hasCustomFocusLogic (); |
| 198 } | 213 } |
| 199 | 214 |
| 200 inline bool isShadowHostWithoutCustomFocusLogic(const Element& element) | 215 inline bool isShadowHostWithoutCustomFocusLogic(const Element& element) |
| 201 { | 216 { |
| 202 return isShadowHost(element) && !hasCustomFocusLogic(element); | 217 return isShadowHost(element) && !hasCustomFocusLogic(element); |
| 203 } | 218 } |
| 204 | 219 |
| 205 #if ENABLE(ASSERT) | 220 #if ENABLE(ASSERT) |
| 206 inline bool isNonFocusableShadowHost(const Node& node) | 221 inline bool isNonFocusableShadowHost(const Element& element) |
| 207 { | 222 { |
| 208 if (!node.isElementNode()) | |
| 209 return false; | |
| 210 const Element& element = toElement(node); | |
| 211 return isShadowHostWithoutCustomFocusLogic(element) && !element.isFocusable( ); | 223 return isShadowHostWithoutCustomFocusLogic(element) && !element.isFocusable( ); |
| 212 } | 224 } |
| 213 #endif | 225 #endif |
| 214 | 226 |
| 215 inline bool isNonKeyboardFocusableShadowHost(const Element& element) | 227 inline bool isNonKeyboardFocusableShadowHost(const Element& element) |
| 216 { | 228 { |
| 217 return isShadowHostWithoutCustomFocusLogic(element) && !element.isKeyboardFo cusable(); | 229 return isShadowHostWithoutCustomFocusLogic(element) && !element.isKeyboardFo cusable(); |
| 218 } | 230 } |
| 219 | 231 |
| 220 inline bool isKeyboardFocusableShadowHost(const Element& element) | 232 inline bool isKeyboardFocusableShadowHost(const Element& element) |
| 221 { | 233 { |
| 222 return isShadowHostWithoutCustomFocusLogic(element) && element.isKeyboardFoc usable(); | 234 return isShadowHostWithoutCustomFocusLogic(element) && element.isKeyboardFoc usable(); |
| 223 } | 235 } |
| 224 | 236 |
| 225 inline bool isNonFocusableFocusScopeOwner(Element& element) | 237 inline bool isNonFocusableFocusScopeOwner(Element& element) |
| 226 { | 238 { |
| 227 return isNonKeyboardFocusableShadowHost(element) || isShadowInsertionPointFo cusScopeOwner(element); | 239 return isNonKeyboardFocusableShadowHost(element) || isShadowInsertionPointFo cusScopeOwner(element); |
| 228 } | 240 } |
| 229 | 241 |
| 230 inline bool isShadowHostDelegatesFocus(const Element& element) | 242 inline bool isShadowHostDelegatesFocus(const Element& element) |
| 231 { | 243 { |
| 232 return element.authorShadowRoot() && element.authorShadowRoot()->delegatesFo cus(); | 244 return element.authorShadowRoot() && element.authorShadowRoot()->delegatesFo cus(); |
| 233 } | 245 } |
| 234 | 246 |
| 235 inline int adjustedTabIndex(Node& node) | 247 inline int adjustedTabIndex(Element& element) |
| 236 { | 248 { |
| 237 return node.isElementNode() && isNonFocusableFocusScopeOwner(toElement(node) ) ? 0 : node.tabIndex(); | 249 return isNonFocusableFocusScopeOwner(element) ? 0 : element.tabIndex(); |
| 238 } | 250 } |
| 239 | 251 |
| 240 inline bool shouldVisit(Node& node) | 252 inline bool shouldVisit(Element& element) |
| 241 { | 253 { |
| 242 if (!node.isElementNode()) | |
| 243 return false; | |
| 244 Element& element = toElement(node); | |
| 245 return element.isKeyboardFocusable() || isNonFocusableFocusScopeOwner(elemen t); | 254 return element.isKeyboardFocusable() || isNonFocusableFocusScopeOwner(elemen t); |
| 246 } | 255 } |
| 247 | 256 |
| 248 Element* findElementWithExactTabIndex(Node* start, int tabIndex, WebFocusType ty pe) | 257 Element* findElementWithExactTabIndex(Element* start, int tabIndex, WebFocusType type) |
| 249 { | 258 { |
| 250 // Search is inclusive of start | 259 // Search is inclusive of start |
| 251 for (Node* node = start; node; node = type == WebFocusTypeForward ? ElementT raversal::next(*node) : ElementTraversal::previous(*node)) { | 260 for (Element* element = start; element; element = type == WebFocusTypeForwar d ? ElementTraversal::next(*element) : ElementTraversal::previous(*element)) { |
| 252 if (shouldVisit(*node) && adjustedTabIndex(*node) == tabIndex) | 261 if (shouldVisit(*element) && adjustedTabIndex(*element) == tabIndex) |
| 253 return toElement(node); | 262 return element; |
| 254 } | 263 } |
| 255 return nullptr; | 264 return nullptr; |
| 256 } | 265 } |
| 257 | 266 |
| 258 Element* nextElementWithGreaterTabIndex(Node* start, int tabIndex) | 267 Element* nextElementWithGreaterTabIndex(Element* start, int tabIndex) |
| 259 { | 268 { |
| 260 // Search is inclusive of start | 269 // Search is inclusive of start |
| 261 int winningTabIndex = std::numeric_limits<short>::max() + 1; | 270 int winningTabIndex = std::numeric_limits<short>::max() + 1; |
| 262 Node* winner = nullptr; | 271 Element* winner = nullptr; |
| 263 for (Node& node : NodeTraversal::startsAt(start)) { | 272 for (Element& element : ElementTraversal::startsAt(start)) { |
| 264 int currentTabIndex = adjustedTabIndex(node); | 273 int currentTabIndex = adjustedTabIndex(element); |
| 265 if (shouldVisit(node) && currentTabIndex > tabIndex && currentTabIndex < winningTabIndex) { | 274 if (shouldVisit(element) && currentTabIndex > tabIndex && currentTabInde x < winningTabIndex) { |
| 266 winner = &node; | 275 winner = &element; |
| 267 winningTabIndex = currentTabIndex; | 276 winningTabIndex = currentTabIndex; |
| 268 } | 277 } |
| 269 } | 278 } |
| 270 ASSERT(!winner || winner->isElementNode()); | 279 return winner; |
| 271 return toElement(winner); | |
| 272 } | 280 } |
| 273 | 281 |
| 274 Element* previousElementWithLowerTabIndex(Node* start, int tabIndex) | 282 Element* previousElementWithLowerTabIndex(Element* start, int tabIndex) |
| 275 { | 283 { |
| 276 // Search is inclusive of start | 284 // Search is inclusive of start |
| 277 int winningTabIndex = 0; | 285 int winningTabIndex = 0; |
| 278 Node* winner = nullptr; | 286 Element* winner = nullptr; |
| 279 for (Node* node = start; node; node = ElementTraversal::previous(*node)) { | 287 for (Element* element = start; element; element = ElementTraversal::previous (*element)) { |
| 280 int currentTabIndex = adjustedTabIndex(*node); | 288 int currentTabIndex = adjustedTabIndex(*element); |
| 281 if (shouldVisit(*node) && currentTabIndex < tabIndex && currentTabIndex > winningTabIndex) { | 289 if (shouldVisit(*element) && currentTabIndex < tabIndex && currentTabInd ex > winningTabIndex) { |
| 282 winner = node; | 290 winner = element; |
| 283 winningTabIndex = currentTabIndex; | 291 winningTabIndex = currentTabIndex; |
| 284 } | 292 } |
| 285 } | 293 } |
| 286 ASSERT(!winner || winner->isElementNode()); | 294 return winner; |
| 287 return toElement(winner); | |
| 288 } | 295 } |
| 289 | 296 |
| 290 Element* nextFocusableElement(const FocusNavigationScope& scope, Node* start) | 297 Element* nextFocusableElement(const FocusNavigationScope& scope, Element* start) |
| 291 { | 298 { |
| 292 if (start) { | 299 if (start) { |
| 293 int tabIndex = adjustedTabIndex(*start); | 300 int tabIndex = adjustedTabIndex(*start); |
| 294 // If a node is excluded from the normal tabbing cycle, the next focusab le node is determined by tree order | 301 // If an element is excluded from the normal tabbing cycle, the next foc usable element is determined by tree order |
| 295 if (tabIndex < 0) { | 302 if (tabIndex < 0) { |
| 296 for (Node& node : NodeTraversal::startsAfter(*start)) { | 303 for (Element& element : ElementTraversal::startsAfter(*start)) { |
| 297 if (shouldVisit(node) && adjustedTabIndex(node) >= 0) | 304 if (shouldVisit(element) && adjustedTabIndex(element) >= 0) |
| 298 return &toElement(node); | 305 return &element; |
| 299 } | 306 } |
| 300 } else { | 307 } else { |
| 301 // First try to find a node with the same tabindex as start that com es after start in the scope. | 308 // First try to find an element with the same tabindex as start that comes after start in the scope. |
| 302 if (Element* winner = findElementWithExactTabIndex(ElementTraversal: :next(*start), tabIndex, WebFocusTypeForward)) | 309 if (Element* winner = findElementWithExactTabIndex(ElementTraversal: :next(*start), tabIndex, WebFocusTypeForward)) |
| 303 return winner; | 310 return winner; |
| 304 } | 311 } |
| 305 if (!tabIndex) { | 312 if (!tabIndex) { |
| 306 // We've reached the last node in the document with a tabindex of 0. This is the end of the tabbing order. | 313 // We've reached the last element in the document with a tabindex of 0. This is the end of the tabbing order. |
| 307 return nullptr; | 314 return nullptr; |
| 308 } | 315 } |
| 309 } | 316 } |
| 310 | 317 |
| 311 // Look for the first node in the scope that: | 318 // Look for the first element in the scope that: |
| 312 // 1) has the lowest tabindex that is higher than start's tabindex (or 0, if start is null), and | 319 // 1) has the lowest tabindex that is higher than start's tabindex (or 0, if start is null), and |
| 313 // 2) comes first in the scope, if there's a tie. | 320 // 2) comes first in the scope, if there's a tie. |
| 314 if (Element* winner = nextElementWithGreaterTabIndex(scope.rootNode(), start ? adjustedTabIndex(*start) : 0)) | 321 if (Element* winner = nextElementWithGreaterTabIndex(scope.firstElement(), s tart ? adjustedTabIndex(*start) : 0)) |
| 315 return winner; | 322 return winner; |
| 316 | 323 |
| 317 // There are no nodes with a tabindex greater than start's tabindex, | 324 // There are no elements with a tabindex greater than start's tabindex, |
| 318 // so find the first node with a tabindex of 0. | 325 // so find the first element with a tabindex of 0. |
| 319 return findElementWithExactTabIndex(scope.rootNode(), 0, WebFocusTypeForward ); | 326 return findElementWithExactTabIndex(scope.firstElement(), 0, WebFocusTypeFor ward); |
| 320 } | 327 } |
| 321 | 328 |
| 322 Element* previousFocusableElement(const FocusNavigationScope& scope, Node* start ) | 329 Element* previousFocusableElement(const FocusNavigationScope& scope, Element* st art) |
| 323 { | 330 { |
| 324 Node* last = nullptr; | 331 Element* lastElement = scope.lastElement(); |
| 325 for (Node* node = scope.rootNode(); node; node = node->lastChild()) | |
| 326 last = node; | |
| 327 ASSERT(last); | |
| 328 | 332 |
| 329 // First try to find the last node in the scope that comes before start and has the same tabindex as start. | 333 // First try to find the last element in the scope that comes before start a nd has the same tabindex as start. |
| 330 // If start is null, find the last node in the scope with a tabindex of 0. | 334 // If start is null, find the last element in the scope with a tabindex of 0 . |
| 331 Node* startingNode; | 335 Element* startElement; |
| 332 int startingTabIndex; | 336 int startTabIndex; |
| 333 if (start) { | 337 if (start) { |
| 334 startingNode = ElementTraversal::previous(*start); | 338 startElement = ElementTraversal::previous(*start); |
| 335 startingTabIndex = adjustedTabIndex(*start); | 339 startTabIndex = adjustedTabIndex(*start); |
| 336 } else { | 340 } else { |
| 337 startingNode = last; | 341 startElement = lastElement; |
| 338 startingTabIndex = 0; | 342 startTabIndex = 0; |
| 339 } | 343 } |
| 340 | 344 |
| 341 // However, if a node is excluded from the normal tabbing cycle, the previou s focusable node is determined by tree order | 345 // However, if an element is excluded from the normal tabbing cycle, the pre vious focusable element is determined by tree order |
| 342 if (startingTabIndex < 0) { | 346 if (startTabIndex < 0) { |
| 343 for (Node* node = startingNode; node; node = ElementTraversal::previous( *node)) { | 347 for (Element* element = startElement; element; element = ElementTraversa l::previous(*element)) { |
| 344 if (shouldVisit(*node) && adjustedTabIndex(*node) >= 0) | 348 if (shouldVisit(*element) && adjustedTabIndex(*element) >= 0) |
| 345 return toElement(node); | 349 return element; |
| 346 } | 350 } |
| 347 } else { | 351 } else { |
| 348 if (Element* winner = findElementWithExactTabIndex(startingNode, startin gTabIndex, WebFocusTypeBackward)) | 352 if (Element* winner = findElementWithExactTabIndex(startElement, startTa bIndex, WebFocusTypeBackward)) |
| 349 return winner; | 353 return winner; |
| 350 } | 354 } |
| 351 | 355 |
| 352 // There are no nodes before start with the same tabindex as start, so look for a node that: | 356 // There are no elements before start with the same tabindex as start, so lo ok for an element that: |
| 353 // 1) has the highest non-zero tabindex (that is less than start's tabindex) , and | 357 // 1) has the highest non-zero tabindex (that is less than start's tabindex) , and |
| 354 // 2) comes last in the scope, if there's a tie. | 358 // 2) comes last in the scope, if there's a tie. |
| 355 startingTabIndex = (start && startingTabIndex) ? startingTabIndex : std::num eric_limits<short>::max(); | 359 startTabIndex = (start && startTabIndex) ? startTabIndex : std::numeric_limi ts<short>::max(); |
| 356 return previousElementWithLowerTabIndex(last, startingTabIndex); | 360 return previousElementWithLowerTabIndex(lastElement, startTabIndex); |
| 357 } | 361 } |
| 358 | 362 |
| 359 // Searches through the given tree scope, starting from start node, for the next /previous | 363 // Searches through the given tree scope, starting from start element, for the n ext/previous |
| 360 // selectable element that comes after/before start node. | 364 // selectable element that comes after/before start element. |
| 361 // The order followed is as specified in the HTML spec[1], which is elements wit h tab indexes | 365 // The order followed is as specified in the HTML spec[1], which is elements wit h tab indexes |
| 362 // first (from lowest to highest), and then elements without tab indexes (in doc ument order). | 366 // first (from lowest to highest), and then elements without tab indexes (in doc ument order). |
| 363 // The search algorithm also conforms the Shadow DOM spec[2], which inserts sequ ence in a shadow | 367 // The search algorithm also conforms the Shadow DOM spec[2], which inserts sequ ence in a shadow |
| 364 // tree into its host. | 368 // tree into its host. |
| 365 // | 369 // |
| 366 // @param start The node from which to start searching. The node after this will be focused. | 370 // @param start The element from which to start searching. The element after thi s will be focused. |
| 367 // May be null. | 371 // May be null. |
| 368 // @return The focus element that comes after/before start node. | 372 // @return The focus element that comes after/before start element. |
| 369 // | 373 // |
| 370 // [1] https://html.spec.whatwg.org/multipage/interaction.html#sequential-focus- navigation | 374 // [1] https://html.spec.whatwg.org/multipage/interaction.html#sequential-focus- navigation |
| 371 // [2] https://w3c.github.io/webcomponents/spec/shadow/#focus-navigation | 375 // [2] https://w3c.github.io/webcomponents/spec/shadow/#focus-navigation |
| 372 inline Element* findFocusableElementInternal(WebFocusType type, const FocusNavig ationScope& scope, Node* node) | 376 inline Element* findFocusableElementInternal(WebFocusType type, const FocusNavig ationScope& scope, Element* element) |
| 373 { | 377 { |
| 374 Element* found = (type == WebFocusTypeForward) ? nextFocusableElement(scope, node) : previousFocusableElement(scope, node); | 378 Element* found = (type == WebFocusTypeForward) ? nextFocusableElement(scope, element) : previousFocusableElement(scope, element); |
| 375 return found; | 379 return found; |
| 376 } | 380 } |
| 377 | 381 |
| 378 Element* findFocusableElementRecursivelyForward(const FocusNavigationScope& scop e, Node* start) | 382 Element* findFocusableElementRecursivelyForward(const FocusNavigationScope& scop e, Element* start) |
| 379 { | 383 { |
| 380 // Starting node is exclusive. | 384 // Starting element is exclusive. |
| 381 Element* found = findFocusableElementInternal(WebFocusTypeForward, scope, st art); | 385 Element* found = findFocusableElementInternal(WebFocusTypeForward, scope, st art); |
| 382 while (found) { | 386 while (found) { |
| 383 if (isShadowHostDelegatesFocus(*found)) { | 387 if (isShadowHostDelegatesFocus(*found)) { |
| 384 // If tabindex is positive, find focusable node inside its shadow tr ee. | 388 // If tabindex is positive, find focusable element inside its shadow tree. |
| 385 if (found->tabIndex() >= 0 && isShadowHostWithoutCustomFocusLogic(*f ound)) { | 389 if (found->tabIndex() >= 0 && isShadowHostWithoutCustomFocusLogic(*f ound)) { |
| 386 FocusNavigationScope innerScope = FocusNavigationScope::ownedByS hadowHost(*found); | 390 FocusNavigationScope innerScope = FocusNavigationScope::ownedByS hadowHost(*found); |
| 387 if (Element* foundInInnerFocusScope = findFocusableElementRecurs ivelyForward(innerScope, nullptr)) | 391 if (Element* foundInInnerFocusScope = findFocusableElementRecurs ivelyForward(innerScope, nullptr)) |
| 388 return foundInInnerFocusScope; | 392 return foundInInnerFocusScope; |
| 389 } | 393 } |
| 390 // Skip to the next node in the same scope. | 394 // Skip to the next element in the same scope. |
| 391 found = findFocusableElementInternal(WebFocusTypeForward, scope, fou nd); | 395 found = findFocusableElementInternal(WebFocusTypeForward, scope, fou nd); |
| 392 continue; | 396 continue; |
| 393 } | 397 } |
| 394 if (!isNonFocusableFocusScopeOwner(*found)) | 398 if (!isNonFocusableFocusScopeOwner(*found)) |
| 395 return found; | 399 return found; |
| 396 | 400 |
| 397 // Now |found| is on a non focusable scope owner (either shadow host or <shadow>) | 401 // Now |found| is on a non focusable scope owner (either shadow host or <shadow>) |
| 398 // Find inside the inward scope and return it if found. Otherwise contin ue searching in the same | 402 // Find inside the inward scope and return it if found. Otherwise contin ue searching in the same |
| 399 // scope. | 403 // scope. |
| 400 FocusNavigationScope innerScope = FocusNavigationScope::ownedByNonFocusa bleFocusScopeOwner(*found); | 404 FocusNavigationScope innerScope = FocusNavigationScope::ownedByNonFocusa bleFocusScopeOwner(*found); |
| 401 if (Element* foundInInnerFocusScope = findFocusableElementRecursivelyFor ward(innerScope, nullptr)) | 405 if (Element* foundInInnerFocusScope = findFocusableElementRecursivelyFor ward(innerScope, nullptr)) |
| 402 return foundInInnerFocusScope; | 406 return foundInInnerFocusScope; |
| 403 | 407 |
| 404 found = findFocusableElementInternal(WebFocusTypeForward, scope, found); | 408 found = findFocusableElementInternal(WebFocusTypeForward, scope, found); |
| 405 } | 409 } |
| 406 return nullptr; | 410 return nullptr; |
| 407 } | 411 } |
| 408 | 412 |
| 409 Element* findFocusableElementRecursivelyBackward(const FocusNavigationScope& sco pe, Node* start) | 413 Element* findFocusableElementRecursivelyBackward(const FocusNavigationScope& sco pe, Element* start) |
| 410 { | 414 { |
| 411 // Starting node is exclusive. | 415 // Starting element is exclusive. |
| 412 Element* found = findFocusableElementInternal(WebFocusTypeBackward, scope, s tart); | 416 Element* found = findFocusableElementInternal(WebFocusTypeBackward, scope, s tart); |
| 413 while (found) { | 417 while (found) { |
| 414 // Now |found| is on a focusable shadow host. | 418 // Now |found| is on a focusable shadow host. |
| 415 // Find inside shadow backwards. If any focusable element is found, retu rn it, otherwise return | 419 // Find inside shadow backwards. If any focusable element is found, retu rn it, otherwise return |
| 416 // the host itself. | 420 // the host itself. |
| 417 if (isKeyboardFocusableShadowHost(*found)) { | 421 if (isKeyboardFocusableShadowHost(*found)) { |
| 418 FocusNavigationScope innerScope = FocusNavigationScope::ownedByShado wHost(*found); | 422 FocusNavigationScope innerScope = FocusNavigationScope::ownedByShado wHost(*found); |
| 419 Element* foundInInnerFocusScope = findFocusableElementRecursivelyBac kward(innerScope, nullptr); | 423 Element* foundInInnerFocusScope = findFocusableElementRecursivelyBac kward(innerScope, nullptr); |
| 420 if (foundInInnerFocusScope) | 424 if (foundInInnerFocusScope) |
| 421 return foundInInnerFocusScope; | 425 return foundInInnerFocusScope; |
| 422 if (isShadowHostDelegatesFocus(*found)) { | 426 if (isShadowHostDelegatesFocus(*found)) { |
| 423 found = findFocusableElementInternal(WebFocusTypeBackward, scope , found); | 427 found = findFocusableElementInternal(WebFocusTypeBackward, scope , found); |
| 424 continue; | 428 continue; |
| 425 } | 429 } |
| 426 return found; | 430 return found; |
| 427 } | 431 } |
| 428 | 432 |
| 429 // If delegatesFocus is true and tabindex is negative, skip the whole sh adow tree under the | 433 // If delegatesFocus is true and tabindex is negative, skip the whole sh adow tree under the |
| 430 // shadow host. | 434 // shadow host. |
| 431 if (isShadowHostDelegatesFocus(*found) && found->tabIndex() < 0) { | 435 if (isShadowHostDelegatesFocus(*found) && found->tabIndex() < 0) { |
| 432 found = findFocusableElementInternal(WebFocusTypeBackward, scope, fo und); | 436 found = findFocusableElementInternal(WebFocusTypeBackward, scope, fo und); |
| 433 continue; | 437 continue; |
| 434 } | 438 } |
| 435 | 439 |
| 436 // Now |found| is on a non focusable scope owner (either shadow host or <shadow>). | 440 // Now |found| is on a non focusable scope owner (either shadow host or <shadow>). |
| 437 // Find focusable node in descendant scope. If not found, find next focu sable node within the | 441 // Find focusable element in descendant scope. If not found, find next f ocusable element within the |
| 438 // current scope. | 442 // current scope. |
| 439 if (isNonFocusableFocusScopeOwner(*found)) { | 443 if (isNonFocusableFocusScopeOwner(*found)) { |
| 440 FocusNavigationScope innerScope = FocusNavigationScope::ownedByNonFo cusableFocusScopeOwner(*found); | 444 FocusNavigationScope innerScope = FocusNavigationScope::ownedByNonFo cusableFocusScopeOwner(*found); |
| 441 Element* foundInInnerFocusScope = findFocusableElementRecursivelyBac kward(innerScope, nullptr); | 445 Element* foundInInnerFocusScope = findFocusableElementRecursivelyBac kward(innerScope, nullptr); |
| 442 if (foundInInnerFocusScope) | 446 if (foundInInnerFocusScope) |
| 443 return foundInInnerFocusScope; | 447 return foundInInnerFocusScope; |
| 444 found = findFocusableElementInternal(WebFocusTypeBackward, scope, fo und); | 448 found = findFocusableElementInternal(WebFocusTypeBackward, scope, fo und); |
| 445 continue; | 449 continue; |
| 446 } | 450 } |
| 447 if (!isShadowHostDelegatesFocus(*found)) | 451 if (!isShadowHostDelegatesFocus(*found)) |
| 448 return found; | 452 return found; |
| 449 found = findFocusableElementInternal(WebFocusTypeBackward, scope, found) ; | 453 found = findFocusableElementInternal(WebFocusTypeBackward, scope, found) ; |
| 450 } | 454 } |
| 451 return nullptr; | 455 return nullptr; |
| 452 } | 456 } |
| 453 | 457 |
| 454 Element* findFocusableElementRecursively(WebFocusType type, const FocusNavigatio nScope& scope, Node* start) | 458 Element* findFocusableElementRecursively(WebFocusType type, const FocusNavigatio nScope& scope, Element* start) |
| 455 { | 459 { |
| 456 return (type == WebFocusTypeForward) ? | 460 return (type == WebFocusTypeForward) ? |
| 457 findFocusableElementRecursivelyForward(scope, start) : | 461 findFocusableElementRecursivelyForward(scope, start) : |
| 458 findFocusableElementRecursivelyBackward(scope, start); | 462 findFocusableElementRecursivelyBackward(scope, start); |
| 459 } | 463 } |
| 460 | 464 |
| 461 Element* findFocusableElementDescendingDownIntoFrameDocument(WebFocusType type, Element* element) | 465 Element* findFocusableElementDescendingDownIntoFrameDocument(WebFocusType type, Element* element) |
| 462 { | 466 { |
| 463 // The element we found might be a HTMLFrameOwnerElement, so descend down th e tree until we find either: | 467 // The element we found might be a HTMLFrameOwnerElement, so descend down th e tree until we find either: |
| 464 // 1) a focusable element, or | 468 // 1) a focusable element, or |
| 465 // 2) the deepest-nested HTMLFrameOwnerElement. | 469 // 2) the deepest-nested HTMLFrameOwnerElement. |
| 466 while (element && element->isFrameOwnerElement()) { | 470 while (element && element->isFrameOwnerElement()) { |
| 467 HTMLFrameOwnerElement& owner = toHTMLFrameOwnerElement(*element); | 471 HTMLFrameOwnerElement& owner = toHTMLFrameOwnerElement(*element); |
| 468 if (!owner.contentFrame() || !owner.contentFrame()->isLocalFrame()) | 472 if (!owner.contentFrame() || !owner.contentFrame()->isLocalFrame()) |
| 469 break; | 473 break; |
| 470 toLocalFrame(owner.contentFrame())->document()->updateLayoutIgnorePendin gStylesheets(); | 474 toLocalFrame(owner.contentFrame())->document()->updateLayoutIgnorePendin gStylesheets(); |
| 471 Element* foundElement = findFocusableElementRecursively(type, FocusNavig ationScope::ownedByIFrame(owner), nullptr); | 475 Element* foundElement = findFocusableElementRecursively(type, FocusNavig ationScope::ownedByIFrame(owner), nullptr); |
| 472 if (!foundElement) | 476 if (!foundElement) |
| 473 break; | 477 break; |
| 474 ASSERT(element != foundElement); | 478 ASSERT(element != foundElement); |
| 475 element = foundElement; | 479 element = foundElement; |
| 476 } | 480 } |
| 477 return element; | 481 return element; |
| 478 } | 482 } |
| 479 | 483 |
| 480 Element* findFocusableElementAcrossFocusScopesForward(const FocusNavigationScope & scope, Node* currentNode) | 484 Element* findFocusableElementAcrossFocusScopesForward(const FocusNavigationScope & scope, Element* current) |
| 481 { | 485 { |
| 482 ASSERT(!currentNode || !isNonFocusableShadowHost(*currentNode)); | 486 ASSERT(!current || !isNonFocusableShadowHost(*current)); |
| 483 Element* found; | 487 Element* found; |
| 484 if (currentNode && currentNode->isElementNode() && isShadowHostWithoutCustom FocusLogic(*toElement(currentNode))) { | 488 if (current && isShadowHostWithoutCustomFocusLogic(*current)) { |
| 485 FocusNavigationScope innerScope = FocusNavigationScope::ownedByShadowHos t(*toElement(currentNode)); | 489 FocusNavigationScope innerScope = FocusNavigationScope::ownedByShadowHos t(*current); |
| 486 Element* foundInInnerFocusScope = findFocusableElementRecursivelyForward (innerScope, nullptr); | 490 Element* foundInInnerFocusScope = findFocusableElementRecursivelyForward (innerScope, nullptr); |
| 487 found = foundInInnerFocusScope ? foundInInnerFocusScope : findFocusableE lementRecursivelyForward(scope, currentNode); | 491 found = foundInInnerFocusScope ? foundInInnerFocusScope : findFocusableE lementRecursivelyForward(scope, current); |
| 488 } else { | 492 } else { |
| 489 found = findFocusableElementRecursivelyForward(scope, currentNode); | 493 found = findFocusableElementRecursivelyForward(scope, current); |
| 490 } | 494 } |
| 491 | 495 |
| 492 // If there's no focusable node to advance to, move up the focus scopes unti l we find one. | 496 // If there's no focusable element to advance to, move up the focus scopes u ntil we find one. |
| 493 FocusNavigationScope currentScope = scope; | 497 FocusNavigationScope currentScope = scope; |
| 494 while (!found) { | 498 while (!found) { |
| 495 Element* owner = currentScope.owner(); | 499 Element* owner = currentScope.owner(); |
| 496 if (!owner) | 500 if (!owner) |
| 497 break; | 501 break; |
| 498 currentScope = FocusNavigationScope::focusNavigationScopeOf(*owner); | 502 currentScope = FocusNavigationScope::focusNavigationScopeOf(*owner); |
| 499 found = findFocusableElementRecursivelyForward(currentScope, owner); | 503 found = findFocusableElementRecursivelyForward(currentScope, owner); |
| 500 } | 504 } |
| 501 return findFocusableElementDescendingDownIntoFrameDocument(WebFocusTypeForwa rd, found); | 505 return findFocusableElementDescendingDownIntoFrameDocument(WebFocusTypeForwa rd, found); |
| 502 } | 506 } |
| 503 | 507 |
| 504 Element* findFocusableElementAcrossFocusScopesBackward(const FocusNavigationScop e& scope, Node* currentNode) | 508 Element* findFocusableElementAcrossFocusScopesBackward(const FocusNavigationScop e& scope, Element* current) |
| 505 { | 509 { |
| 506 ASSERT(!currentNode || !isNonFocusableShadowHost(*currentNode)); | 510 ASSERT(!current || !isNonFocusableShadowHost(*current)); |
| 507 Element* found = findFocusableElementRecursivelyBackward(scope, currentNode) ; | 511 Element* found = findFocusableElementRecursivelyBackward(scope, current); |
| 508 | 512 |
| 509 // If there's no focusable node to advance to, move up the focus scopes unti l we find one. | 513 // If there's no focusable element to advance to, move up the focus scopes u ntil we find one. |
| 510 FocusNavigationScope currentScope = scope; | 514 FocusNavigationScope currentScope = scope; |
| 511 while (!found) { | 515 while (!found) { |
| 512 Element* owner = currentScope.owner(); | 516 Element* owner = currentScope.owner(); |
| 513 if (!owner) | 517 if (!owner) |
| 514 break; | 518 break; |
| 515 currentScope = FocusNavigationScope::focusNavigationScopeOf(*owner); | 519 currentScope = FocusNavigationScope::focusNavigationScopeOf(*owner); |
| 516 if (isKeyboardFocusableShadowHost(*owner) && !isShadowHostDelegatesFocus (*owner)) { | 520 if (isKeyboardFocusableShadowHost(*owner) && !isShadowHostDelegatesFocus (*owner)) { |
| 517 found = owner; | 521 found = owner; |
| 518 break; | 522 break; |
| 519 } | 523 } |
| 520 found = findFocusableElementRecursivelyBackward(currentScope, owner); | 524 found = findFocusableElementRecursivelyBackward(currentScope, owner); |
| 521 } | 525 } |
| 522 return findFocusableElementDescendingDownIntoFrameDocument(WebFocusTypeBackw ard, found); | 526 return findFocusableElementDescendingDownIntoFrameDocument(WebFocusTypeBackw ard, found); |
| 523 } | 527 } |
| 524 | 528 |
| 525 Element* findFocusableElementAcrossFocusScopes(WebFocusType type, const FocusNav igationScope& scope, Node* currentNode) | 529 Element* findFocusableElementAcrossFocusScopes(WebFocusType type, const FocusNav igationScope& scope, Element* current) |
| 526 { | 530 { |
| 527 return (type == WebFocusTypeForward) ? | 531 return (type == WebFocusTypeForward) ? |
| 528 findFocusableElementAcrossFocusScopesForward(scope, currentNode) : | 532 findFocusableElementAcrossFocusScopesForward(scope, current) : |
| 529 findFocusableElementAcrossFocusScopesBackward(scope, currentNode); | 533 findFocusableElementAcrossFocusScopesBackward(scope, current); |
| 530 } | 534 } |
| 531 | 535 |
| 532 inline Element* adjustToElement(Node* node, WebFocusType type) | 536 inline Element* adjustToElement(Node* node, WebFocusType type) |
| 533 { | 537 { |
| 534 ASSERT(type == WebFocusTypeForward || type == WebFocusTypeBackward); | 538 ASSERT(type == WebFocusTypeForward || type == WebFocusTypeBackward); |
| 535 if (!node) | 539 if (!node) |
| 536 return nullptr; | 540 return nullptr; |
| 537 return (type == WebFocusTypeForward) ? ElementTraversal::next(*node) : Eleme ntTraversal::previous(*node); | 541 return (type == WebFocusTypeForward) ? ElementTraversal::next(*node) : Eleme ntTraversal::previous(*node); |
| 538 } | 542 } |
| 539 | 543 |
| (...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 772 element = findFocusableElementRecursively(type, FocusNavigationScope::fo cusNavigationScopeOf(*toLocalFrame(m_page->mainFrame())->document()->documentEle ment()), nullptr); | 776 element = findFocusableElementRecursively(type, FocusNavigationScope::fo cusNavigationScopeOf(*toLocalFrame(m_page->mainFrame())->document()->documentEle ment()), nullptr); |
| 773 element = findFocusableElementDescendingDownIntoFrameDocument(type, elem ent.get()); | 777 element = findFocusableElementDescendingDownIntoFrameDocument(type, elem ent.get()); |
| 774 | 778 |
| 775 if (!element) | 779 if (!element) |
| 776 return false; | 780 return false; |
| 777 } | 781 } |
| 778 | 782 |
| 779 ASSERT(element); | 783 ASSERT(element); |
| 780 | 784 |
| 781 if (element == document->focusedElement()) { | 785 if (element == document->focusedElement()) { |
| 782 // Focus wrapped around to the same node. | 786 // Focus wrapped around to the same element. |
| 783 return true; | 787 return true; |
| 784 } | 788 } |
| 785 | 789 |
| 786 if (element->isFrameOwnerElement() && (!isHTMLPlugInElement(*element) || !el ement->isKeyboardFocusable())) { | 790 if (element->isFrameOwnerElement() && (!isHTMLPlugInElement(*element) || !el ement->isKeyboardFocusable())) { |
| 787 // We focus frames rather than frame owners. | 791 // We focus frames rather than frame owners. |
| 788 // FIXME: We should not focus frames that have no scrollbars, as focusin g them isn't useful to the user. | 792 // FIXME: We should not focus frames that have no scrollbars, as focusin g them isn't useful to the user. |
| 789 HTMLFrameOwnerElement* owner = toHTMLFrameOwnerElement(element); | 793 HTMLFrameOwnerElement* owner = toHTMLFrameOwnerElement(element); |
| 790 if (!owner->contentFrame()) | 794 if (!owner->contentFrame()) |
| 791 return false; | 795 return false; |
| 792 | 796 |
| 793 document->clearFocusedElement(); | 797 document->clearFocusedElement(); |
| 794 setFocusedFrame(owner->contentFrame()); | 798 setFocusedFrame(owner->contentFrame()); |
| 795 | 799 |
| 796 // If contentFrame is remote, continue the search for focusable | 800 // If contentFrame is remote, continue the search for focusable |
| 797 // elements in that frame's process. | 801 // elements in that frame's process. |
| 798 // clearFocusedElement() fires events that might detach the | 802 // clearFocusedElement() fires events that might detach the |
| 799 // contentFrame, hence the need to null-check it again. | 803 // contentFrame, hence the need to null-check it again. |
| 800 if (owner->contentFrame() && owner->contentFrame()->isRemoteFrame()) | 804 if (owner->contentFrame() && owner->contentFrame()->isRemoteFrame()) |
| 801 toRemoteFrame(owner->contentFrame())->advanceFocus(type, frame); | 805 toRemoteFrame(owner->contentFrame())->advanceFocus(type, frame); |
| 802 | 806 |
| 803 return true; | 807 return true; |
| 804 } | 808 } |
| 805 | 809 |
| 806 // FIXME: It would be nice to just be able to call setFocusedElement(node) | 810 // FIXME: It would be nice to just be able to call setFocusedElement(element ) |
| 807 // here, but we can't do that because some elements (e.g. HTMLInputElement | 811 // here, but we can't do that because some elements (e.g. HTMLInputElement |
| 808 // and HTMLTextAreaElement) do extra work in their focus() methods. | 812 // and HTMLTextAreaElement) do extra work in their focus() methods. |
| 809 Document& newDocument = element->document(); | 813 Document& newDocument = element->document(); |
| 810 | 814 |
| 811 if (&newDocument != document) { | 815 if (&newDocument != document) { |
| 812 // Focus is going away from this document, so clear the focused node. | 816 // Focus is going away from this document, so clear the focused element. |
| 813 document->clearFocusedElement(); | 817 document->clearFocusedElement(); |
| 814 } | 818 } |
| 815 | 819 |
| 816 setFocusedFrame(newDocument.frame()); | 820 setFocusedFrame(newDocument.frame()); |
| 817 | 821 |
| 818 if (caretBrowsing) { | 822 if (caretBrowsing) { |
| 819 Position position = firstPositionInOrBeforeNode(element.get()); | 823 Position position = firstPositionInOrBeforeNode(element.get()); |
| 820 VisibleSelection newSelection(position, position); | 824 VisibleSelection newSelection(position, position); |
| 821 frame->selection().setSelection(newSelection); | 825 frame->selection().setSelection(newSelection); |
| 822 } | 826 } |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 907 | 911 |
| 908 if (oldDocument && oldDocument != newDocument) | 912 if (oldDocument && oldDocument != newDocument) |
| 909 oldDocument->clearFocusedElement(); | 913 oldDocument->clearFocusedElement(); |
| 910 | 914 |
| 911 if (newFocusedFrame && !newFocusedFrame->page()) { | 915 if (newFocusedFrame && !newFocusedFrame->page()) { |
| 912 setFocusedFrame(nullptr); | 916 setFocusedFrame(nullptr); |
| 913 return false; | 917 return false; |
| 914 } | 918 } |
| 915 setFocusedFrame(newFocusedFrame); | 919 setFocusedFrame(newFocusedFrame); |
| 916 | 920 |
| 917 // Setting the focused node can result in losing our last reft to node when JS event handlers fire. | 921 // Setting the focused element can result in losing our last reft to element when JS event handlers fire. |
| 918 RefPtrWillBeRawPtr<Element> protect = element; | 922 RefPtrWillBeRawPtr<Element> protect = element; |
| 919 ALLOW_UNUSED_LOCAL(protect); | 923 ALLOW_UNUSED_LOCAL(protect); |
| 920 if (newDocument) { | 924 if (newDocument) { |
| 921 bool successfullyFocused = newDocument->setFocusedElement(element, param s); | 925 bool successfullyFocused = newDocument->setFocusedElement(element, param s); |
| 922 if (!successfullyFocused) | 926 if (!successfullyFocused) |
| 923 return false; | 927 return false; |
| 924 } | 928 } |
| 925 | 929 |
| 926 return true; | 930 return true; |
| 927 } | 931 } |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1131 return consumed; | 1135 return consumed; |
| 1132 } | 1136 } |
| 1133 | 1137 |
| 1134 DEFINE_TRACE(FocusController) | 1138 DEFINE_TRACE(FocusController) |
| 1135 { | 1139 { |
| 1136 visitor->trace(m_page); | 1140 visitor->trace(m_page); |
| 1137 visitor->trace(m_focusedFrame); | 1141 visitor->trace(m_focusedFrame); |
| 1138 } | 1142 } |
| 1139 | 1143 |
| 1140 } // namespace blink | 1144 } // namespace blink |
| OLD | NEW |