OSDN Git Service

Merge WebKit at r73109: Initial merge by git.
[android-x86/external-webkit.git] / WebCore / accessibility / gtk / AXObjectCacheAtk.cpp
1 /*
2  * Copyright (C) 2008 Nuanti Ltd.
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 "AXObjectCache.h"
22
23 #include "AccessibilityObject.h"
24 #include "AccessibilityObjectWrapperAtk.h"
25 #include "AccessibilityRenderObject.h"
26 #include "GOwnPtr.h"
27 #include "Range.h"
28 #include "SelectElement.h"
29 #include "TextIterator.h"
30
31 namespace WebCore {
32
33 void AXObjectCache::detachWrapper(AccessibilityObject* obj)
34 {
35     webkit_accessible_detach(WEBKIT_ACCESSIBLE(obj->wrapper()));
36 }
37
38 void AXObjectCache::attachWrapper(AccessibilityObject* obj)
39 {
40     AtkObject* atkObj = ATK_OBJECT(webkit_accessible_new(obj));
41     obj->setWrapper(atkObj);
42     g_object_unref(atkObj);
43 }
44
45 static void notifyChildrenSelectionChange(AccessibilityObject* object)
46 {
47     // This static variable is needed to keep track of the old focused
48     // object as per previous calls to this function, in order to
49     // properly decide whether to emit some signals or not.
50     static RefPtr<AccessibilityObject> oldFocusedObject = 0;
51
52     // Only list boxes supported so far.
53     if (!object || !object->isListBox())
54         return;
55
56     // Emit signal from the listbox's point of view first.
57     g_signal_emit_by_name(object->wrapper(), "selection-changed");
58
59     // Find the item where the selection change was triggered from.
60     AccessibilityObject::AccessibilityChildrenVector items = object->children();
61     SelectElement* select = toSelectElement(static_cast<Element*>(object->node()));
62     if (!select)
63         return;
64     int changedItemIndex = select->activeSelectionStartListIndex();
65     if (changedItemIndex < 0 || changedItemIndex >= static_cast<int>(items.size()))
66         return;
67     AccessibilityObject* item = items.at(changedItemIndex).get();
68
69     // Ensure the oldFocusedObject belongs to the same document that
70     // the current item so further comparisons make sense. Otherwise,
71     // just reset oldFocusedObject so it won't be taken into account.
72     if (item && oldFocusedObject && item->document() != oldFocusedObject->document())
73         oldFocusedObject = 0;
74
75     AtkObject* axItem = item ? item->wrapper() : 0;
76     AtkObject* axOldFocusedObject = oldFocusedObject ? oldFocusedObject->wrapper() : 0;
77
78     // Old focused object just lost focus, so emit the events.
79     if (axOldFocusedObject && axItem != axOldFocusedObject) {
80         g_signal_emit_by_name(axOldFocusedObject, "focus-event", false);
81         g_signal_emit_by_name(axOldFocusedObject, "state-change", "focused", false);
82     }
83
84     // Emit needed events for the currently (un)selected item.
85     if (axItem) {
86         bool isSelected = item->isSelected();
87         g_signal_emit_by_name(axItem, "state-change", "selected", isSelected);
88         g_signal_emit_by_name(axItem, "focus-event", isSelected);
89         g_signal_emit_by_name(axItem, "state-change", "focused", isSelected);
90     }
91
92     // Update pointer to the previously focused object.
93     oldFocusedObject = item;
94 }
95
96 void AXObjectCache::postPlatformNotification(AccessibilityObject* coreObject, AXNotification notification)
97 {
98     AtkObject* axObject = coreObject->wrapper();
99     if (!axObject)
100         return;
101
102     if (notification == AXCheckedStateChanged) {
103         if (!coreObject->isCheckboxOrRadio())
104             return;
105         g_signal_emit_by_name(axObject, "state-change", "checked", coreObject->isChecked());
106     } else if (notification == AXMenuListValueChanged) {
107         if (!coreObject->isMenuList())
108             return;
109         g_signal_emit_by_name(axObject, "focus-event", true);
110         g_signal_emit_by_name(axObject, "state-change", "focused", true);
111     } else if (notification == AXSelectedChildrenChanged)
112         notifyChildrenSelectionChange(coreObject);
113 }
114
115 static void emitTextChanged(AccessibilityRenderObject* object, AXObjectCache::AXTextChange textChange, unsigned offset, unsigned count)
116 {
117     // Get the axObject for the parent object
118     AtkObject* wrapper = object->parentObjectUnignored()->wrapper();
119     if (!wrapper || !ATK_IS_TEXT(wrapper))
120         return;
121
122     // Select the right signal to be emitted
123     CString detail;
124     switch (textChange) {
125     case AXObjectCache::AXTextInserted:
126         detail = "text-changed::insert";
127         break;
128     case AXObjectCache::AXTextDeleted:
129         detail = "text-changed::delete";
130         break;
131     }
132
133     if (!detail.isNull())
134         g_signal_emit_by_name(wrapper, detail.data(), offset, count);
135 }
136
137 void AXObjectCache::nodeTextChangePlatformNotification(AccessibilityObject* object, AXTextChange textChange, unsigned offset, unsigned count)
138 {
139     // Sanity check
140     if (count < 1 || !object || !object->isAccessibilityRenderObject())
141         return;
142
143     Node* node = object->node();
144     RefPtr<Range> range = Range::create(node->document(),  Position(node->parentNode(), 0), Position(node, 0));
145     emitTextChanged(toAccessibilityRenderObject(object), textChange, offset + TextIterator::rangeLength(range.get()), count);
146 }
147
148 void AXObjectCache::handleFocusedUIElementChanged(RenderObject* oldFocusedRender, RenderObject* newFocusedRender)
149 {
150     RefPtr<AccessibilityObject> oldObject = getOrCreate(oldFocusedRender);
151     if (oldObject) {
152         g_signal_emit_by_name(oldObject->wrapper(), "focus-event", false);
153         g_signal_emit_by_name(oldObject->wrapper(), "state-change", "focused", false);
154     }
155     RefPtr<AccessibilityObject> newObject = getOrCreate(newFocusedRender);
156     if (newObject) {
157         g_signal_emit_by_name(newObject->wrapper(), "focus-event", true);
158         g_signal_emit_by_name(newObject->wrapper(), "state-change", "focused", true);
159     }
160 }
161
162 void AXObjectCache::handleScrolledToAnchor(const Node*)
163 {
164 }
165
166 } // namespace WebCore