1/*
2 * Copyright (C) 2010, 2011, 2012 Igalia S.L.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20#include "config.h"
21#include "WebKitAccessibleInterfaceHypertext.h"
22
23#if HAVE(ACCESSIBILITY)
24
25#include "AccessibilityObject.h"
26#include "WebKitAccessible.h"
27#include "WebKitAccessibleUtil.h"
28
29using namespace WebCore;
30
31static AccessibilityObject* core(AtkHypertext* hypertext)
32{
33 if (!WEBKIT_IS_ACCESSIBLE(hypertext))
34 return 0;
35
36 return &webkitAccessibleGetAccessibilityObject(WEBKIT_ACCESSIBLE(hypertext));
37}
38
39static AtkHyperlink* webkitAccessibleHypertextGetLink(AtkHypertext* hypertext, gint index)
40{
41 g_return_val_if_fail(ATK_HYPERTEXT(hypertext), 0);
42 returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(hypertext), 0);
43
44 const AccessibilityObject::AccessibilityChildrenVector& children = core(hypertext)->children();
45 if (index < 0 || static_cast<unsigned>(index) >= children.size())
46 return 0;
47
48 gint currentLink = -1;
49 for (const auto& child : children) {
50 AccessibilityObject* coreChild = child.get();
51 if (!coreChild->accessibilityIsIgnored()) {
52 auto* axObject = coreChild->wrapper();
53 if (!axObject || !ATK_IS_HYPERLINK_IMPL(axObject))
54 continue;
55
56 currentLink++;
57 if (index != currentLink)
58 continue;
59
60 return atk_hyperlink_impl_get_hyperlink(ATK_HYPERLINK_IMPL(axObject));
61 }
62 }
63
64 return 0;
65}
66
67static gint webkitAccessibleHypertextGetNLinks(AtkHypertext* hypertext)
68{
69 g_return_val_if_fail(ATK_HYPERTEXT(hypertext), 0);
70 returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(hypertext), 0);
71
72 const AccessibilityObject::AccessibilityChildrenVector& children = core(hypertext)->children();
73 gint linksFound = 0;
74 for (const auto& child : children) {
75 AccessibilityObject* coreChild = child.get();
76 if (!coreChild->accessibilityIsIgnored()) {
77 auto* axObject = coreChild->wrapper();
78 if (axObject && ATK_IS_HYPERLINK_IMPL(axObject))
79 linksFound++;
80 }
81 }
82
83 return linksFound;
84}
85
86static gint webkitAccessibleHypertextGetLinkIndex(AtkHypertext* hypertext, gint charIndex)
87{
88 g_return_val_if_fail(ATK_HYPERTEXT(hypertext), -1);
89 returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(hypertext), -1);
90
91 size_t linksCount = webkitAccessibleHypertextGetNLinks(hypertext);
92 if (!linksCount)
93 return -1;
94
95 for (size_t i = 0; i < linksCount; i++) {
96 AtkHyperlink* hyperlink = ATK_HYPERLINK(webkitAccessibleHypertextGetLink(hypertext, i));
97 gint startIndex = atk_hyperlink_get_start_index(hyperlink);
98 gint endIndex = atk_hyperlink_get_end_index(hyperlink);
99
100 // Check if the char index in the link's offset range
101 if (startIndex <= charIndex && charIndex < endIndex)
102 return i;
103 }
104
105 // Not found if reached
106 return -1;
107}
108
109void webkitAccessibleHypertextInterfaceInit(AtkHypertextIface* iface)
110{
111 iface->get_link = webkitAccessibleHypertextGetLink;
112 iface->get_n_links = webkitAccessibleHypertextGetNLinks;
113 iface->get_link_index = webkitAccessibleHypertextGetLinkIndex;
114}
115
116#endif
117