OSDN Git Service

Merge WebKit at r73109: Initial merge by git.
[android-x86/external-webkit.git] / WebCore / accessibility / gtk / AXObjectCacheAtk.cpp
index 25665b1..c341a2d 100644 (file)
 
 #include "AccessibilityObject.h"
 #include "AccessibilityObjectWrapperAtk.h"
+#include "AccessibilityRenderObject.h"
+#include "GOwnPtr.h"
+#include "Range.h"
+#include "SelectElement.h"
+#include "TextIterator.h"
 
 namespace WebCore {
 
@@ -37,15 +42,110 @@ void AXObjectCache::attachWrapper(AccessibilityObject* obj)
     g_object_unref(atkObj);
 }
 
-void AXObjectCache::postPlatformNotification(AccessibilityObject*, const String&)
+static void notifyChildrenSelectionChange(AccessibilityObject* object)
 {
+    // This static variable is needed to keep track of the old focused
+    // object as per previous calls to this function, in order to
+    // properly decide whether to emit some signals or not.
+    static RefPtr<AccessibilityObject> oldFocusedObject = 0;
+
+    // Only list boxes supported so far.
+    if (!object || !object->isListBox())
+        return;
+
+    // Emit signal from the listbox's point of view first.
+    g_signal_emit_by_name(object->wrapper(), "selection-changed");
+
+    // Find the item where the selection change was triggered from.
+    AccessibilityObject::AccessibilityChildrenVector items = object->children();
+    SelectElement* select = toSelectElement(static_cast<Element*>(object->node()));
+    if (!select)
+        return;
+    int changedItemIndex = select->activeSelectionStartListIndex();
+    if (changedItemIndex < 0 || changedItemIndex >= static_cast<int>(items.size()))
+        return;
+    AccessibilityObject* item = items.at(changedItemIndex).get();
+
+    // Ensure the oldFocusedObject belongs to the same document that
+    // the current item so further comparisons make sense. Otherwise,
+    // just reset oldFocusedObject so it won't be taken into account.
+    if (item && oldFocusedObject && item->document() != oldFocusedObject->document())
+        oldFocusedObject = 0;
+
+    AtkObject* axItem = item ? item->wrapper() : 0;
+    AtkObject* axOldFocusedObject = oldFocusedObject ? oldFocusedObject->wrapper() : 0;
+
+    // Old focused object just lost focus, so emit the events.
+    if (axOldFocusedObject && axItem != axOldFocusedObject) {
+        g_signal_emit_by_name(axOldFocusedObject, "focus-event", false);
+        g_signal_emit_by_name(axOldFocusedObject, "state-change", "focused", false);
+    }
+
+    // Emit needed events for the currently (un)selected item.
+    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);
+    }
+
+    // Update pointer to the previously focused object.
+    oldFocusedObject = item;
 }
-    
-void AXObjectCache::handleFocusedUIElementChanged()
+
+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 == AXMenuListValueChanged) {
+        if (!coreObject->isMenuList())
+            return;
+        g_signal_emit_by_name(axObject, "focus-event", true);
+        g_signal_emit_by_name(axObject, "state-change", "focused", true);
+    } else if (notification == AXSelectedChildrenChanged)
+        notifyChildrenSelectionChange(coreObject);
 }
 
-void AXObjectCache::handleFocusedUIElementChangedWithRenderers(RenderObject* oldFocusedRender, RenderObject* newFocusedRender)
+static void emitTextChanged(AccessibilityRenderObject* object, AXObjectCache::AXTextChange textChange, unsigned offset, unsigned count)
+{
+    // Get the axObject for the parent object
+    AtkObject* wrapper = object->parentObjectUnignored()->wrapper();
+    if (!wrapper || !ATK_IS_TEXT(wrapper))
+        return;
+
+    // Select the right signal to be emitted
+    CString detail;
+    switch (textChange) {
+    case AXObjectCache::AXTextInserted:
+        detail = "text-changed::insert";
+        break;
+    case AXObjectCache::AXTextDeleted:
+        detail = "text-changed::delete";
+        break;
+    }
+
+    if (!detail.isNull())
+        g_signal_emit_by_name(wrapper, detail.data(), offset, count);
+}
+
+void AXObjectCache::nodeTextChangePlatformNotification(AccessibilityObject* object, AXTextChange textChange, unsigned offset, unsigned count)
+{
+    // Sanity check
+    if (count < 1 || !object || !object->isAccessibilityRenderObject())
+        return;
+
+    Node* node = object->node();
+    RefPtr<Range> range = Range::create(node->document(),  Position(node->parentNode(), 0), Position(node, 0));
+    emitTextChanged(toAccessibilityRenderObject(object), textChange, offset + TextIterator::rangeLength(range.get()), count);
+}
+
+void AXObjectCache::handleFocusedUIElementChanged(RenderObject* oldFocusedRender, RenderObject* newFocusedRender)
 {
     RefPtr<AccessibilityObject> oldObject = getOrCreate(oldFocusedRender);
     if (oldObject) {
@@ -59,4 +159,8 @@ void AXObjectCache::handleFocusedUIElementChangedWithRenderers(RenderObject* old
     }
 }
 
+void AXObjectCache::handleScrolledToAnchor(const Node*)
+{
+}
+
 } // namespace WebCore