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