Changeset 197439 in webkit


Ignore:
Timestamp:
Mar 1, 2016 9:31:28 PM (8 years ago)
Author:
rniwa@webkit.org
Message:

Contents inside a shadow host with a negative tabindex should not be tab focusable
https://bugs.webkit.org/show_bug.cgi?id=154769

Reviewed by Antti Koivisto.

Source/WebCore:

Contents inside a shadow host with a negative tabindex content attribute should not be included in
the sequential focus navigation order as discussed on https://github.com/w3c/webcomponents/issues/399.

Test: fast/shadow-dom/negative-tabindex-on-shadow-host.html

  • dom/Element.cpp:

(WebCore::Element::tabIndexSetExplicitly): Added.

  • dom/Element.h:
  • page/FocusController.cpp:

(WebCore::shadowAdjustedTabIndex): Renamed from adjustedTabIndex. Return 0 when tabindex content attribute
is not explicitly set since element.tabIndex() would return -1 for HTML elements in such case.
(WebCore::isFocusableOrHasShadowTreeWithoutCustomFocusLogic): Renamed from shouldVisit.
(WebCore::FocusController::findElementWithExactTabIndex):
(WebCore::nextElementWithGreaterTabIndex):
(WebCore::previousElementWithLowerTabIndex):
(WebCore::FocusController::nextFocusableElement):
(WebCore::FocusController::previousFocusableElement):

LayoutTests:

Added a test for navigating across shadow boundaries.

  • fast/shadow-dom/negative-tabindex-on-shadow-host-expected.txt: Added.
  • fast/shadow-dom/negative-tabindex-on-shadow-host.html: Added.
  • platform/ios-simulator/TestExpectations:
Location:
trunk
Files:
2 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r197435 r197439  
     12016-02-26  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        Contents inside a shadow host with a negative tabindex should not be tab focusable
     4        https://bugs.webkit.org/show_bug.cgi?id=154769
     5
     6        Reviewed by Antti Koivisto.
     7
     8        Added a test for navigating across shadow boundaries.
     9
     10        * fast/shadow-dom/negative-tabindex-on-shadow-host-expected.txt: Added.
     11        * fast/shadow-dom/negative-tabindex-on-shadow-host.html: Added.
     12        * platform/ios-simulator/TestExpectations:
     13
    1142016-03-01  Myles C. Maxfield  <mmaxfield@apple.com>
    215
  • trunk/LayoutTests/platform/ios-simulator/TestExpectations

    r197258 r197439  
    235235webkit.org/b/149441 fast/shadow-dom/css-scoping-shadow-slotted-rule.html [ ImageOnlyFailure ]
    236236webkit.org/b/149441 fast/shadow-dom/css-scoping-shadow-slot-display-override.html [ ImageOnlyFailure ]
     237
     238# No tab navigation support on iOS
     239fast/shadow-dom/negative-tabindex-on-shadow-host.html [ Failure ]
    237240
    238241webkit.org/b/150225 fast/custom-elements [ Pass ]
  • trunk/Source/WebCore/ChangeLog

    r197437 r197439  
     12016-02-26  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        Contents inside a shadow host with a negative tabindex should not be tab focusable
     4        https://bugs.webkit.org/show_bug.cgi?id=154769
     5
     6        Reviewed by Antti Koivisto.
     7
     8        Contents inside a shadow host with a negative tabindex content attribute should not be included in
     9        the sequential focus navigation order as discussed on https://github.com/w3c/webcomponents/issues/399.
     10
     11        Test: fast/shadow-dom/negative-tabindex-on-shadow-host.html
     12
     13        * dom/Element.cpp:
     14        (WebCore::Element::tabIndexSetExplicitly): Added.
     15        * dom/Element.h:
     16        * page/FocusController.cpp:
     17        (WebCore::shadowAdjustedTabIndex): Renamed from adjustedTabIndex. Return 0 when tabindex content attribute
     18        is not explicitly set since element.tabIndex() would return -1 for HTML elements in such case.
     19        (WebCore::isFocusableOrHasShadowTreeWithoutCustomFocusLogic): Renamed from shouldVisit.
     20        (WebCore::FocusController::findElementWithExactTabIndex):
     21        (WebCore::nextElementWithGreaterTabIndex):
     22        (WebCore::previousElementWithLowerTabIndex):
     23        (WebCore::FocusController::nextFocusableElement):
     24        (WebCore::FocusController::previousFocusableElement):
     25
    1262016-03-01  Michael Saboff  <msaboff@apple.com>
    227
  • trunk/Source/WebCore/dom/Element.cpp

    r197401 r197439  
    213213}
    214214
     215bool Element::tabIndexSetExplicitly() const
     216{
     217    return hasRareData() && elementRareData()->tabIndexSetExplicitly();
     218}
     219
    215220bool Element::supportsFocus() const
    216221{
    217     return hasRareData() && elementRareData()->tabIndexSetExplicitly();
     222    return tabIndexSetExplicitly();
    218223}
    219224
  • trunk/Source/WebCore/dom/Element.h

    r197401 r197439  
    267267    virtual void setFocus(bool flag);
    268268
     269    bool tabIndexSetExplicitly() const;
    269270    virtual bool supportsFocus() const;
    270271    virtual bool isFocusable() const;
  • trunk/Source/WebCore/page/FocusController.cpp

    r197055 r197439  
    215215}
    216216
    217 static inline int adjustedTabIndex(Node& node, KeyboardEvent& event)
    218 {
    219     if (!is<Element>(node))
    220         return 0;
    221     return isNonFocusableShadowHost(downcast<Element>(node), event) ? 0 : downcast<Element>(node).tabIndex();
    222 }
    223 
    224 static inline bool shouldVisit(Element& element, KeyboardEvent& event)
     217static inline int shadowAdjustedTabIndex(Element& element, KeyboardEvent& event)
     218{
     219    if (isNonFocusableShadowHost(element, event)) {
     220        if (!element.tabIndexSetExplicitly())
     221            return 0; // Treat a shadow host without tabindex if it has tabindex=0 even though HTMLElement::tabIndex returns -1 on such an element.
     222    }
     223    return element.tabIndex();
     224}
     225
     226static inline bool isFocusableOrHasShadowTreeWithoutCustomFocusLogic(Element& element, KeyboardEvent& event)
    225227{
    226228    return element.isKeyboardFocusable(&event) || isNonFocusableShadowHost(element, event);
     
    480482            continue;
    481483        Element& element = downcast<Element>(*node);
    482         if (shouldVisit(element, *event) && adjustedTabIndex(element, *event) == tabIndex)
     484        if (isFocusableOrHasShadowTreeWithoutCustomFocusLogic(element, *event) && shadowAdjustedTabIndex(element, *event) == tabIndex)
    483485            return &element;
    484486    }
     
    495497            continue;
    496498        Element& element = downcast<Element>(*node);
    497         if (shouldVisit(element, event) && element.tabIndex() > tabIndex && element.tabIndex() < winningTabIndex) {
     499        if (isFocusableOrHasShadowTreeWithoutCustomFocusLogic(element, event) && element.tabIndex() > tabIndex && element.tabIndex() < winningTabIndex) {
    498500            winner = &element;
    499501            winningTabIndex = element.tabIndex();
     
    513515            continue;
    514516        Element& element = downcast<Element>(*node);
    515         int currentTabIndex = adjustedTabIndex(element, event);
    516         if ((shouldVisit(element, event) || isNonFocusableShadowHost(element, event)) && currentTabIndex < tabIndex && currentTabIndex > winningTabIndex) {
     517        int currentTabIndex = shadowAdjustedTabIndex(element, event);
     518        if ((isFocusableOrHasShadowTreeWithoutCustomFocusLogic(element, event) || isNonFocusableShadowHost(element, event)) && currentTabIndex < tabIndex && currentTabIndex > winningTabIndex) {
    517519            winner = &element;
    518520            winningTabIndex = currentTabIndex;
     
    536538Element* FocusController::nextFocusableElement(const FocusNavigationScope& scope, Node* start, KeyboardEvent* event)
    537539{
     540    int startTabIndex = 0;
     541    if (start && is<Element>(*start))
     542        startTabIndex = shadowAdjustedTabIndex(downcast<Element>(*start), *event);
     543
    538544    if (start) {
    539         int tabIndex = adjustedTabIndex(*start, *event);
    540545        // If a node is excluded from the normal tabbing cycle, the next focusable node is determined by tree order
    541         if (tabIndex < 0) {
     546        if (startTabIndex < 0) {
    542547            for (Node* node = scope.nextInScope(start); node; node = scope.nextInScope(node)) {
    543548                if (!is<Element>(*node))
    544549                    continue;
    545550                Element& element = downcast<Element>(*node);
    546                 if (shouldVisit(element, *event) && adjustedTabIndex(element, *event) >= 0)
     551                if (isFocusableOrHasShadowTreeWithoutCustomFocusLogic(element, *event) && shadowAdjustedTabIndex(element, *event) >= 0)
    547552                    return &element;
    548553            }
     
    550555
    551556        // First try to find a node with the same tabindex as start that comes after start in the scope.
    552         if (Element* winner = findElementWithExactTabIndex(scope, scope.nextInScope(start), tabIndex, event, FocusDirectionForward))
     557        if (Element* winner = findElementWithExactTabIndex(scope, scope.nextInScope(start), startTabIndex, event, FocusDirectionForward))
    553558            return winner;
    554559
    555         if (!tabIndex)
    556             // We've reached the last node in the document with a tabindex of 0. This is the end of the tabbing order.
    557             return 0;
     560        if (!startTabIndex)
     561            return nullptr; // We've reached the last node in the document with a tabindex of 0. This is the end of the tabbing order.
    558562    }
    559563
     
    561565    // 1) has the lowest tabindex that is higher than start's tabindex (or 0, if start is null), and
    562566    // 2) comes first in the scope, if there's a tie.
    563     if (Element* winner = nextElementWithGreaterTabIndex(scope, start ? adjustedTabIndex(*start, *event) : 0, *event))
     567    if (Element* winner = nextElementWithGreaterTabIndex(scope, startTabIndex, *event))
    564568        return winner;
    565569
     
    579583    // If start is null, find the last node in the scope with a tabindex of 0.
    580584    Node* startingNode;
    581     int startingTabIndex;
     585    int startingTabIndex = 0;
    582586    if (start) {
    583587        startingNode = scope.previousInScope(start);
    584         startingTabIndex = adjustedTabIndex(*start, *event);
    585     } else {
     588        if (is<Element>(*start))
     589            startingTabIndex = shadowAdjustedTabIndex(downcast<Element>(*start), *event);
     590    } else
    586591        startingNode = last;
    587         startingTabIndex = 0;
    588     }
    589592
    590593    // However, if a node is excluded from the normal tabbing cycle, the previous focusable node is determined by tree order
     
    594597                continue;
    595598            Element& element = downcast<Element>(*node);
    596             if (shouldVisit(element, *event) && adjustedTabIndex(element, *event) >= 0)
     599            if (isFocusableOrHasShadowTreeWithoutCustomFocusLogic(element, *event) && shadowAdjustedTabIndex(element, *event) >= 0)
    597600                return &element;
    598601        }
Note: See TracChangeset for help on using the changeset viewer.