8576dd66150662be1aae1c124aef4f7f9c6c0e8e
[WebKit-https.git] / Source / WebCore / accessibility / AccessibilityScrollView.cpp
1 /*
2  * Copyright (C) 2011 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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "AccessibilityScrollView.h"
28
29 #include "AXObjectCache.h"
30 #include "AccessibilityScrollbar.h"
31 #include "Frame.h"
32 #include "FrameView.h"
33 #include "HTMLFrameOwnerElement.h"
34 #include "RenderElement.h"
35 #include "ScrollView.h"
36 #include "Widget.h"
37
38 namespace WebCore {
39     
40 AccessibilityScrollView::AccessibilityScrollView(ScrollView* view)
41     : m_scrollView(view)
42     , m_childrenDirty(false)
43 {
44 }
45
46 AccessibilityScrollView::~AccessibilityScrollView()
47 {
48     ASSERT(isDetached());
49 }
50
51 void AccessibilityScrollView::detach(AccessibilityDetachmentType detachmentType, AXObjectCache* cache)
52 {
53     AccessibilityObject::detach(detachmentType, cache);
54     m_scrollView = nullptr;
55 }
56
57 PassRefPtr<AccessibilityScrollView> AccessibilityScrollView::create(ScrollView* view)
58 {
59     return adoptRef(new AccessibilityScrollView(view));
60 }
61     
62 AccessibilityObject* AccessibilityScrollView::scrollBar(AccessibilityOrientation orientation)
63 {
64     updateScrollbars();
65     
66     switch (orientation) {
67     case AccessibilityOrientationVertical:
68         return m_verticalScrollbar ? m_verticalScrollbar.get() : 0;
69     case AccessibilityOrientationHorizontal:
70         return m_horizontalScrollbar ? m_horizontalScrollbar.get() : 0;
71     }
72     
73     return nullptr;
74 }
75
76 // If this is WebKit1 then the native scroll view needs to return the
77 // AX information (because there are no scroll bar children in the ScrollView object in WK1).
78 // In WebKit2, the ScrollView object will return the AX information (because there are no platform widgets).
79 bool AccessibilityScrollView::isAttachment() const
80 {
81     return m_scrollView && m_scrollView->platformWidget();
82 }
83
84 Widget* AccessibilityScrollView::widgetForAttachmentView() const
85 {
86     return m_scrollView;
87 }
88     
89 bool AccessibilityScrollView::canSetFocusAttribute() const
90 {
91     AccessibilityObject* webArea = webAreaObject();
92     return webArea && webArea->canSetFocusAttribute();
93 }
94     
95 bool AccessibilityScrollView::isFocused() const
96 {
97     AccessibilityObject* webArea = webAreaObject();
98     return webArea && webArea->isFocused();
99 }
100     
101 void AccessibilityScrollView::setFocused(bool focused)
102 {
103     if (AccessibilityObject* webArea = webAreaObject())
104         webArea->setFocused(focused);
105 }
106
107 void AccessibilityScrollView::updateChildrenIfNecessary()
108 {
109     // Always update our children when asked for them so that we don't inadvertently cache them after
110     // a new web area has been created for this scroll view (like when moving back and forth through history).
111     // Since a ScrollViews children will always be relatively small and limited this should not be a performance problem.
112     clearChildren();
113     addChildren();
114 }
115
116 void AccessibilityScrollView::updateScrollbars()
117 {
118     if (!m_scrollView)
119         return;
120
121     if (m_scrollView->horizontalScrollbar() && !m_horizontalScrollbar)
122         m_horizontalScrollbar = addChildScrollbar(m_scrollView->horizontalScrollbar());
123     else if (!m_scrollView->horizontalScrollbar() && m_horizontalScrollbar) {
124         removeChildScrollbar(m_horizontalScrollbar.get());
125         m_horizontalScrollbar = nullptr;
126     }
127
128     if (m_scrollView->verticalScrollbar() && !m_verticalScrollbar)
129         m_verticalScrollbar = addChildScrollbar(m_scrollView->verticalScrollbar());
130     else if (!m_scrollView->verticalScrollbar() && m_verticalScrollbar) {
131         removeChildScrollbar(m_verticalScrollbar.get());
132         m_verticalScrollbar = nullptr;
133     }
134 }
135     
136 void AccessibilityScrollView::removeChildScrollbar(AccessibilityObject* scrollbar)
137 {
138     size_t pos = m_children.find(scrollbar);
139     if (pos != WTF::notFound) {
140         m_children[pos]->detachFromParent();
141         m_children.remove(pos);
142     }
143 }
144     
145 AccessibilityScrollbar* AccessibilityScrollView::addChildScrollbar(Scrollbar* scrollbar)
146 {
147     if (!scrollbar)
148         return nullptr;
149     
150     AXObjectCache* cache = axObjectCache();
151     if (!cache)
152         return nullptr;
153
154     AccessibilityScrollbar* scrollBarObject = toAccessibilityScrollbar(cache->getOrCreate(scrollbar));
155     scrollBarObject->setParent(this);
156     m_children.append(scrollBarObject);
157     return scrollBarObject;
158 }
159         
160 void AccessibilityScrollView::clearChildren()
161 {
162     AccessibilityObject::clearChildren();
163     m_verticalScrollbar = nullptr;
164     m_horizontalScrollbar = nullptr;
165 }
166
167 bool AccessibilityScrollView::computeAccessibilityIsIgnored() const
168 {
169     AccessibilityObject* webArea = webAreaObject();
170     if (!webArea)
171         return true;
172     
173     return webArea->accessibilityIsIgnored();
174 }
175
176 void AccessibilityScrollView::addChildren()
177 {
178     ASSERT(!m_haveChildren);
179     m_haveChildren = true;
180     
181     AccessibilityObject* webArea = webAreaObject();
182     if (webArea && !webArea->accessibilityIsIgnored())
183         m_children.append(webArea);
184     
185     updateScrollbars();
186 }
187
188 AccessibilityObject* AccessibilityScrollView::webAreaObject() const
189 {
190     if (!is<FrameView>(m_scrollView))
191         return nullptr;
192     
193     Document* document = downcast<FrameView>(*m_scrollView).frame().document();
194     if (!document || !document->hasLivingRenderTree())
195         return nullptr;
196
197     if (AXObjectCache* cache = axObjectCache())
198         return cache->getOrCreate(document);
199     
200     return nullptr;
201 }
202
203 AccessibilityObject* AccessibilityScrollView::accessibilityHitTest(const IntPoint& point) const
204 {
205     AccessibilityObject* webArea = webAreaObject();
206     if (!webArea)
207         return nullptr;
208     
209     if (m_horizontalScrollbar && m_horizontalScrollbar->elementRect().contains(point))
210         return m_horizontalScrollbar.get();
211     if (m_verticalScrollbar && m_verticalScrollbar->elementRect().contains(point))
212         return m_verticalScrollbar.get();
213     
214     return webArea->accessibilityHitTest(point);
215 }
216
217 LayoutRect AccessibilityScrollView::elementRect() const
218 {
219     if (!m_scrollView)
220         return LayoutRect();
221
222     LayoutRect rect = m_scrollView->frameRect();
223     float topContentInset = m_scrollView->topContentInset();
224     // Top content inset pushes the frame down and shrinks it.
225     rect.move(0, topContentInset);
226     rect.contract(0, topContentInset);
227     return rect;
228 }
229
230 FrameView* AccessibilityScrollView::documentFrameView() const
231 {
232     if (!is<FrameView>(m_scrollView))
233         return nullptr;
234     
235     return downcast<FrameView>(m_scrollView);
236 }    
237
238 AccessibilityObject* AccessibilityScrollView::parentObject() const
239 {
240     if (!is<FrameView>(m_scrollView))
241         return nullptr;
242
243     AXObjectCache* cache = axObjectCache();
244     if (!cache)
245         return nullptr;
246
247     HTMLFrameOwnerElement* owner = downcast<FrameView>(*m_scrollView).frame().ownerElement();
248     if (owner && owner->renderer())
249         return cache->getOrCreate(owner);
250
251     return nullptr;
252 }
253     
254 AccessibilityObject* AccessibilityScrollView::parentObjectIfExists() const
255 {
256     if (!is<FrameView>(m_scrollView))
257         return nullptr;
258     
259     AXObjectCache* cache = axObjectCache();
260     if (!cache)
261         return nullptr;
262
263     HTMLFrameOwnerElement* owner = downcast<FrameView>(m_scrollView)->frame().ownerElement();
264     if (owner && owner->renderer())
265         return cache->get(owner);
266     
267     return nullptr;
268 }
269
270 ScrollableArea* AccessibilityScrollView::getScrollableAreaIfScrollable() const
271 {
272     return m_scrollView;
273 }
274
275 void AccessibilityScrollView::scrollTo(const IntPoint& point) const
276 {
277     if (m_scrollView)
278         m_scrollView->setScrollPosition(point);
279 }
280
281 } // namespace WebCore