[GTK] Silence ATK_XY_PARENT warnings
[WebKit-https.git] / Source / WebCore / accessibility / atk / WebKitAccessibleUtil.cpp
1 /*
2  * Copyright (C) 2008 Nuanti Ltd.
3  * Copyright (C) 2009 Jan Alonzo
4  * Copyright (C) 2009, 2010, 2012 Igalia S.L.
5  *
6  * Portions from Mozilla a11y, copyright as follows:
7  *
8  * The Original Code is mozilla.org code.
9  *
10  * The Initial Developer of the Original Code is
11  * Sun Microsystems, Inc.
12  * Portions created by the Initial Developer are Copyright (C) 2002
13  * the Initial Developer. All Rights Reserved.
14  *
15  * This library is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU Library General Public
17  * License as published by the Free Software Foundation; either
18  * version 2 of the License, or (at your option) any later version.
19  *
20  * This library is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23  * Library General Public License for more details.
24  *
25  * You should have received a copy of the GNU Library General Public License
26  * along with this library; see the file COPYING.LIB.  If not, write to
27  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
28  * Boston, MA 02110-1301, USA.
29  */
30
31 #include "config.h"
32 #include "WebKitAccessibleUtil.h"
33
34 #if HAVE(ACCESSIBILITY)
35
36 #include "AccessibilityObject.h"
37 #include "FrameView.h"
38 #include "IntRect.h"
39 #include "Node.h"
40 #include "Range.h"
41 #include "VisibleSelection.h"
42
43 #include <wtf/text/AtomicString.h>
44 #include <wtf/text/CString.h>
45
46 using namespace WebCore;
47
48 AtkAttributeSet* addToAtkAttributeSet(AtkAttributeSet* attributeSet, const char* name, const char* value)
49 {
50     AtkAttribute* attribute = static_cast<AtkAttribute*>(g_malloc(sizeof(AtkAttribute)));
51     attribute->name = g_strdup(name);
52     attribute->value = g_strdup(value);
53     attributeSet = g_slist_prepend(attributeSet, attribute);
54     return attributeSet;
55 }
56
57 void contentsRelativeToAtkCoordinateType(AccessibilityObject* coreObject, AtkCoordType coordType, IntRect rect, gint* x, gint* y, gint* width, gint* height)
58 {
59     FrameView* frameView = coreObject->documentFrameView();
60
61     if (frameView) {
62         switch (coordType) {
63         case ATK_XY_WINDOW:
64             rect = frameView->contentsToWindow(rect);
65             break;
66         case ATK_XY_SCREEN:
67             rect = frameView->contentsToScreen(rect);
68             break;
69 #if ATK_CHECK_VERSION(2, 30, 0)
70         case ATK_XY_PARENT:
71             RELEASE_ASSERT_NOT_REACHED();
72 #endif
73         }
74     }
75
76     if (x)
77         *x = rect.x();
78     if (y)
79         *y = rect.y();
80     if (width)
81         *width = rect.width();
82     if (height)
83         *height = rect.height();
84 }
85
86 // FIXME: Different kinds of elements are putting the title tag to use
87 // in different AX fields. This might not be 100% correct but we will
88 // keep it now in order to achieve consistency with previous behavior.
89 static bool titleTagShouldBeUsedInDescriptionField(AccessibilityObject* coreObject)
90 {
91     return (coreObject->isLink() && !coreObject->isImageMapLink()) || coreObject->isImage();
92 }
93
94 // This should be the "visible" text that's actually on the screen if possible.
95 // If there's alternative text, that can override the title.
96 String accessibilityTitle(AccessibilityObject* coreObject)
97 {
98     Vector<AccessibilityText> textOrder;
99     coreObject->accessibilityText(textOrder);
100
101     for (const AccessibilityText& text : textOrder) {
102         // Once we encounter visible text, or the text from our children that should be used foremost.
103         if (text.textSource == AccessibilityTextSource::Visible || text.textSource == AccessibilityTextSource::Children)
104             return text.text;
105
106         // If there's an element that labels this object and it's not exposed, then we should use
107         // that text as our title.
108         if (text.textSource == AccessibilityTextSource::LabelByElement && !coreObject->exposesTitleUIElement())
109             return text.text;
110
111         // Elements of role AccessibilityRole::Toolbar will return its title as AccessibilityTextSource::Alternative.
112         if (coreObject->roleValue() == AccessibilityRole::Toolbar && text.textSource == AccessibilityTextSource::Alternative)
113             return text.text;
114
115         // FIXME: The title tag is used in certain cases for the title. This usage should
116         // probably be in the description field since it's not "visible".
117         if (text.textSource == AccessibilityTextSource::TitleTag && !titleTagShouldBeUsedInDescriptionField(coreObject))
118             return text.text;
119     }
120
121     return String();
122 }
123
124 String accessibilityDescription(AccessibilityObject* coreObject)
125 {
126     Vector<AccessibilityText> textOrder;
127     coreObject->accessibilityText(textOrder);
128
129     bool visibleTextAvailable = false;
130     for (const AccessibilityText& text : textOrder) {
131         if (text.textSource == AccessibilityTextSource::Alternative)
132             return text.text;
133
134         switch (text.textSource) {
135         case AccessibilityTextSource::Visible:
136         case AccessibilityTextSource::Children:
137         case AccessibilityTextSource::LabelByElement:
138             visibleTextAvailable = true;
139         default:
140             break;
141         }
142
143         if (text.textSource == AccessibilityTextSource::TitleTag && !visibleTextAvailable)
144             return text.text;
145     }
146
147     return String();
148 }
149
150 bool selectionBelongsToObject(AccessibilityObject* coreObject, VisibleSelection& selection)
151 {
152     if (!coreObject || !coreObject->isAccessibilityRenderObject())
153         return false;
154
155     if (selection.isNone())
156         return false;
157
158     RefPtr<Range> range = selection.toNormalizedRange();
159     if (!range)
160         return false;
161
162     // We want to check that both the selection intersects the node
163     // AND that the selection is not just "touching" one of the
164     // boundaries for the selected node. We want to check whether the
165     // node is actually inside the region, at least partially.
166     auto& node = *coreObject->node();
167     auto* lastDescendant = node.lastDescendant();
168     unsigned lastOffset = lastOffsetInNode(lastDescendant);
169     auto intersectsResult = range->intersectsNode(node);
170     return !intersectsResult.hasException()
171         && intersectsResult.releaseReturnValue()
172         && (&range->endContainer() != &node || range->endOffset())
173         && (&range->startContainer() != lastDescendant || range->startOffset() != lastOffset);
174 }
175
176 #endif