AXObjectCacheAtk.cpp [plain text]
#include "config.h"
#include "AXObjectCache.h"
#include "AccessibilityObject.h"
#include "Document.h"
#include "Element.h"
#include <wtf/gobject/GOwnPtr.h>
#include "HTMLSelectElement.h"
#include "Range.h"
#include "TextIterator.h"
#include "WebKitAccessibleWrapperAtk.h"
namespace WebCore {
void AXObjectCache::detachWrapper(AccessibilityObject* obj)
{
webkitAccessibleDetach(WEBKIT_ACCESSIBLE(obj->wrapper()));
}
void AXObjectCache::attachWrapper(AccessibilityObject* obj)
{
AtkObject* atkObj = ATK_OBJECT(webkitAccessibleNew(obj));
obj->setWrapper(atkObj);
g_object_unref(atkObj);
}
static AccessibilityObject* getListObject(AccessibilityObject* object)
{
if (!object->isListBox() && !object->isMenuList())
return 0;
if (object->isListBox())
return object;
AccessibilityObject::AccessibilityChildrenVector children = object->children();
if (!children.size())
return 0;
AccessibilityObject* listObject = children.at(0).get();
if (!listObject->isMenuListPopup())
return 0;
return listObject;
}
static void notifyChildrenSelectionChange(AccessibilityObject* object)
{
DEFINE_STATIC_LOCAL(RefPtr<AccessibilityObject>, oldListObject, ());
DEFINE_STATIC_LOCAL(RefPtr<AccessibilityObject>, oldFocusedObject, ());
if (!object || !(object->isListBox() || object->isMenuList()))
return;
g_signal_emit_by_name(object->wrapper(), "selection-changed");
HTMLSelectElement* select = toHTMLSelectElement(object->node());
if (!select)
return;
int changedItemIndex = select->activeSelectionStartListIndex();
AccessibilityObject* listObject = getListObject(object);
if (!listObject) {
oldListObject = 0;
return;
}
AccessibilityObject::AccessibilityChildrenVector items = listObject->children();
if (changedItemIndex < 0 || changedItemIndex >= static_cast<int>(items.size()))
return;
AccessibilityObject* item = items.at(changedItemIndex).get();
if (oldListObject != listObject)
oldFocusedObject = 0;
AtkObject* axItem = item ? item->wrapper() : 0;
AtkObject* axOldFocusedObject = oldFocusedObject ? oldFocusedObject->wrapper() : 0;
if (axOldFocusedObject && axItem != axOldFocusedObject) {
g_signal_emit_by_name(axOldFocusedObject, "focus-event", false);
g_signal_emit_by_name(axOldFocusedObject, "state-change", "focused", false);
}
if (axItem) {
bool isSelected = item->isSelected();
g_signal_emit_by_name(axItem, "state-change", "selected", isSelected);
g_signal_emit_by_name(axItem, "focus-event", isSelected);
g_signal_emit_by_name(axItem, "state-change", "focused", isSelected);
}
oldListObject = listObject;
oldFocusedObject = item;
}
void AXObjectCache::postPlatformNotification(AccessibilityObject* coreObject, AXNotification notification)
{
AtkObject* axObject = coreObject->wrapper();
if (!axObject)
return;
if (notification == AXCheckedStateChanged) {
if (!coreObject->isCheckboxOrRadio())
return;
g_signal_emit_by_name(axObject, "state-change", "checked", coreObject->isChecked());
} else if (notification == AXSelectedChildrenChanged || notification == AXMenuListValueChanged) {
if (notification == AXMenuListValueChanged && coreObject->isMenuList()) {
g_signal_emit_by_name(axObject, "focus-event", true);
g_signal_emit_by_name(axObject, "state-change", "focused", true);
}
notifyChildrenSelectionChange(coreObject);
} else if (notification == AXValueChanged) {
if (!ATK_IS_VALUE(axObject))
return;
AtkPropertyValues propertyValues;
propertyValues.property_name = "accessible-value";
memset(&propertyValues.new_value, 0, sizeof(GValue));
atk_value_get_current_value(ATK_VALUE(axObject), &propertyValues.new_value);
g_signal_emit_by_name(ATK_OBJECT(axObject), "property-change::accessible-value", &propertyValues, NULL);
}
}
static void emitTextChanged(AccessibilityObject* object, AXObjectCache::AXTextChange textChange, unsigned offset, const String& text)
{
AtkObject* wrapper = object->parentObjectUnignored()->wrapper();
if (!wrapper || !ATK_IS_TEXT(wrapper))
return;
CString detail;
switch (textChange) {
case AXObjectCache::AXTextInserted:
detail = "text-insert";
break;
case AXObjectCache::AXTextDeleted:
detail = "text-remove";
break;
}
if (!detail.isNull())
g_signal_emit_by_name(wrapper, detail.data(), offset, text.length(), text.utf8().data());
}
void AXObjectCache::nodeTextChangePlatformNotification(AccessibilityObject* object, AXTextChange textChange, unsigned offset, const String& text)
{
if (!object || !object->isAccessibilityRenderObject() || text.isEmpty())
return;
Node* node = object->node();
RefPtr<Range> range = Range::create(node->document(), node->parentNode(), 0, node, 0);
emitTextChanged(object, textChange, offset + TextIterator::rangeLength(range.get()), text);
}
void AXObjectCache::frameLoadingEventPlatformNotification(AccessibilityObject* object, AXLoadingEvent loadingEvent)
{
if (!object)
return;
AtkObject* axObject = object->wrapper();
if (!axObject || !ATK_IS_DOCUMENT(axObject))
return;
switch (loadingEvent) {
case AXObjectCache::AXLoadingStarted:
g_signal_emit_by_name(axObject, "state-change", "busy", true);
break;
case AXObjectCache::AXLoadingReloaded:
g_signal_emit_by_name(axObject, "state-change", "busy", true);
g_signal_emit_by_name(axObject, "reload");
break;
case AXObjectCache::AXLoadingFailed:
g_signal_emit_by_name(axObject, "load-stopped");
g_signal_emit_by_name(axObject, "state-change", "busy", false);
break;
case AXObjectCache::AXLoadingFinished:
g_signal_emit_by_name(axObject, "load-complete");
g_signal_emit_by_name(axObject, "state-change", "busy", false);
break;
}
}
void AXObjectCache::handleFocusedUIElementChanged(RenderObject* oldFocusedRender, RenderObject* newFocusedRender)
{
RefPtr<AccessibilityObject> oldObject = getOrCreate(oldFocusedRender);
if (oldObject) {
g_signal_emit_by_name(oldObject->wrapper(), "focus-event", false);
g_signal_emit_by_name(oldObject->wrapper(), "state-change", "focused", false);
}
RefPtr<AccessibilityObject> newObject = getOrCreate(newFocusedRender);
if (newObject) {
g_signal_emit_by_name(newObject->wrapper(), "focus-event", true);
g_signal_emit_by_name(newObject->wrapper(), "state-change", "focused", true);
}
}
void AXObjectCache::handleScrolledToAnchor(const Node*)
{
}
}