1/*
2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef FocusController_h
27#define FocusController_h
28
29#include "FocusDirection.h"
30#include "LayoutRect.h"
31#include <wtf/Forward.h>
32#include <wtf/Noncopyable.h>
33#include <wtf/RefPtr.h>
34
35namespace WebCore {
36
37struct FocusCandidate;
38class ContainerNode;
39class Document;
40class Element;
41class Frame;
42class HTMLFrameOwnerElement;
43class IntRect;
44class KeyboardEvent;
45class Node;
46class Page;
47class TreeScope;
48
49class FocusNavigationScope {
50public:
51    ContainerNode* rootNode() const;
52    Element* owner() const;
53    static FocusNavigationScope focusNavigationScopeOf(Node*);
54    static FocusNavigationScope focusNavigationScopeOwnedByShadowHost(Node*);
55    static FocusNavigationScope focusNavigationScopeOwnedByIFrame(HTMLFrameOwnerElement*);
56
57private:
58    explicit FocusNavigationScope(TreeScope*);
59    TreeScope* m_rootTreeScope;
60};
61
62class FocusController {
63    WTF_MAKE_NONCOPYABLE(FocusController); WTF_MAKE_FAST_ALLOCATED;
64public:
65    static PassOwnPtr<FocusController> create(Page*);
66
67    void setFocusedFrame(PassRefPtr<Frame>);
68    Frame* focusedFrame() const { return m_focusedFrame.get(); }
69    Frame* focusedOrMainFrame() const;
70
71    bool setInitialFocus(FocusDirection, KeyboardEvent*);
72    bool advanceFocus(FocusDirection, KeyboardEvent*, bool initialFocus = false);
73
74    bool setFocusedElement(Element*, PassRefPtr<Frame>, FocusDirection = FocusDirectionNone);
75
76    void setActive(bool);
77    bool isActive() const { return m_isActive; }
78
79    void setFocused(bool);
80    bool isFocused() const { return m_isFocused; }
81
82    void setContainingWindowIsVisible(bool);
83    bool containingWindowIsVisible() const { return m_containingWindowIsVisible; }
84
85private:
86    explicit FocusController(Page*);
87
88    bool advanceFocusDirectionally(FocusDirection, KeyboardEvent*);
89    bool advanceFocusInDocumentOrder(FocusDirection, KeyboardEvent*, bool initialFocus);
90
91    Element* findFocusableElementAcrossFocusScope(FocusDirection, FocusNavigationScope startScope, Node* start, KeyboardEvent*);
92    Element* findFocusableElementRecursively(FocusDirection, FocusNavigationScope, Node* start, KeyboardEvent*);
93    Element* findFocusableElementDescendingDownIntoFrameDocument(FocusDirection, Element*, KeyboardEvent*);
94
95    // Searches through the given tree scope, starting from start node, for the next/previous selectable element that comes after/before start node.
96    // The order followed is as specified in section 17.11.1 of the HTML4 spec, which is elements with tab indexes
97    // first (from lowest to highest), and then elements without tab indexes (in document order).
98    //
99    // @param start The node from which to start searching. The node after this will be focused. May be null.
100    //
101    // @return The focus node that comes after/before start node.
102    //
103    // See http://www.w3.org/TR/html4/interact/forms.html#h-17.11.1
104    Element* findFocusableElement(FocusDirection, FocusNavigationScope, Node* start, KeyboardEvent*);
105
106    Element* nextFocusableElement(FocusNavigationScope, Node* start, KeyboardEvent*);
107    Element* previousFocusableElement(FocusNavigationScope, Node* start, KeyboardEvent*);
108
109    Element* findElementWithExactTabIndex(Node* start, int tabIndex, KeyboardEvent*, FocusDirection);
110
111    bool advanceFocusDirectionallyInContainer(Node* container, const LayoutRect& startingRect, FocusDirection, KeyboardEvent*);
112    void findFocusCandidateInContainer(Node* container, const LayoutRect& startingRect, FocusDirection, KeyboardEvent*, FocusCandidate& closest);
113
114    Page* m_page;
115    RefPtr<Frame> m_focusedFrame;
116    bool m_isActive;
117    bool m_isFocused;
118    bool m_isChangingFocusedFrame;
119    bool m_containingWindowIsVisible;
120
121};
122
123} // namespace WebCore
124
125#endif // FocusController_h
126