diff options
Diffstat (limited to 'Source/WebCore/accessibility')
10 files changed, 183 insertions, 70 deletions
diff --git a/Source/WebCore/accessibility/AXObjectCache.cpp b/Source/WebCore/accessibility/AXObjectCache.cpp index a01cb59..b471201 100644 --- a/Source/WebCore/accessibility/AXObjectCache.cpp +++ b/Source/WebCore/accessibility/AXObjectCache.cpp @@ -616,7 +616,7 @@ void AXObjectCache::textMarkerDataForVisiblePosition(TextMarkerData& textMarkerD return; if (domNode->isHTMLElement()) { - InputElement* inputElement = toInputElement(static_cast<Element*>(domNode)); + InputElement* inputElement = domNode->toInputElement(); if (inputElement && inputElement->isPasswordField()) return; } diff --git a/Source/WebCore/accessibility/AXObjectCache.h b/Source/WebCore/accessibility/AXObjectCache.h index 4c231b5..4805a7f 100644 --- a/Source/WebCore/accessibility/AXObjectCache.h +++ b/Source/WebCore/accessibility/AXObjectCache.h @@ -96,7 +96,8 @@ public: void handleScrollbarUpdate(ScrollView*); static void enableAccessibility() { gAccessibilityEnabled = true; } - static void enableEnhancedUserInterfaceAccessibility() { gAccessibilityEnhancedUserInterfaceEnabled = true; } + // Enhanced user interface accessibility can be toggled by the assistive technology. + static void setEnhancedUserInterfaceAccessibility(bool flag) { gAccessibilityEnhancedUserInterfaceEnabled = flag; } static bool accessibilityEnabled() { return gAccessibilityEnabled; } static bool accessibilityEnhancedUserInterfaceEnabled() { return gAccessibilityEnhancedUserInterfaceEnabled; } diff --git a/Source/WebCore/accessibility/AccessibilityImageMapLink.cpp b/Source/WebCore/accessibility/AccessibilityImageMapLink.cpp index 0844d02..a41f228 100644 --- a/Source/WebCore/accessibility/AccessibilityImageMapLink.cpp +++ b/Source/WebCore/accessibility/AccessibilityImageMapLink.cpp @@ -42,6 +42,7 @@ using namespace HTMLNames; AccessibilityImageMapLink::AccessibilityImageMapLink() : m_areaElement(0) , m_mapElement(0) + , m_parent(0) { } diff --git a/Source/WebCore/accessibility/AccessibilityObject.h b/Source/WebCore/accessibility/AccessibilityObject.h index 4687cae..2d27e39 100644 --- a/Source/WebCore/accessibility/AccessibilityObject.h +++ b/Source/WebCore/accessibility/AccessibilityObject.h @@ -171,6 +171,10 @@ enum AccessibilityRole { ListItemRole, MenuListPopupRole, MenuListOptionRole, + ParagraphRole, + LabelRole, + DivRole, + FormRole, // ARIA Grouping roles LandmarkApplicationRole, diff --git a/Source/WebCore/accessibility/AccessibilityRenderObject.cpp b/Source/WebCore/accessibility/AccessibilityRenderObject.cpp index a626950..9b54a69 100644 --- a/Source/WebCore/accessibility/AccessibilityRenderObject.cpp +++ b/Source/WebCore/accessibility/AccessibilityRenderObject.cpp @@ -495,7 +495,7 @@ bool AccessibilityRenderObject::isPasswordField() const if (ariaRoleAttribute() != UnknownRole) return false; - InputElement* inputElement = toInputElement(static_cast<Element*>(m_renderer->node())); + InputElement* inputElement = m_renderer->node()->toInputElement(); if (!inputElement) return false; @@ -585,10 +585,10 @@ bool AccessibilityRenderObject::isPressed() const bool AccessibilityRenderObject::isIndeterminate() const { ASSERT(m_renderer); - if (!m_renderer->node() || !m_renderer->node()->isElementNode()) + if (!m_renderer->node()) return false; - InputElement* inputElement = toInputElement(static_cast<Element*>(m_renderer->node())); + InputElement* inputElement = m_renderer->node()->toInputElement(); if (!inputElement) return false; @@ -598,8 +598,8 @@ bool AccessibilityRenderObject::isIndeterminate() const bool AccessibilityRenderObject::isNativeCheckboxOrRadio() const { Node* elementNode = node(); - if (elementNode && elementNode->isElementNode()) { - InputElement* input = toInputElement(static_cast<Element*>(elementNode)); + if (elementNode) { + InputElement* input = elementNode->toInputElement(); if (input) return input->isCheckbox() || input->isRadioButton(); } @@ -610,11 +610,11 @@ bool AccessibilityRenderObject::isNativeCheckboxOrRadio() const bool AccessibilityRenderObject::isChecked() const { ASSERT(m_renderer); - if (!m_renderer->node() || !m_renderer->node()->isElementNode()) + if (!m_renderer->node()) return false; // First test for native checkedness semantics - InputElement* inputElement = toInputElement(static_cast<Element*>(m_renderer->node())); + InputElement* inputElement = m_renderer->node()->toInputElement(); if (inputElement) return inputElement->isChecked(); @@ -661,10 +661,10 @@ bool AccessibilityRenderObject::isReadOnly() const return true; HTMLElement* body = document->body(); - if (body && body->isContentEditable()) + if (body && body->rendererIsEditable()) return false; - return !document->inDesignMode(); + return !document->rendererIsEditable(); } if (m_renderer->isBoxModelObject()) { @@ -675,7 +675,7 @@ bool AccessibilityRenderObject::isReadOnly() const return static_cast<HTMLTextAreaElement*>(box->node())->readOnly(); } - return !m_renderer->node() || !m_renderer->node()->isContentEditable(); + return !m_renderer->node() || !m_renderer->node()->rendererIsEditable(); } bool AccessibilityRenderObject::isOffScreen() const @@ -1829,7 +1829,7 @@ bool AccessibilityRenderObject::accessibilityIsIgnored() const return false; // Anything that is content editable should not be ignored. - // However, one cannot just call node->isContentEditable() since that will ask if its parents + // However, one cannot just call node->rendererIsEditable() since that will ask if its parents // are also editable. Only the top level content editable region should be exposed. if (node && node->isElementNode()) { Element* element = static_cast<Element*>(node); @@ -1838,6 +1838,10 @@ bool AccessibilityRenderObject::accessibilityIsIgnored() const return false; } + // List items play an important role in defining the structure of lists. They should not be ignored. + if (roleValue() == ListItemRole) + return false; + // if this element has aria attributes on it, it should not be ignored. if (supportsARIAAttributes()) return false; @@ -2401,8 +2405,8 @@ VisiblePositionRange AccessibilityRenderObject::visiblePositionRange() const if (!node) return VisiblePositionRange(); - VisiblePosition startPos = firstDeepEditingPositionForNode(node); - VisiblePosition endPos = lastDeepEditingPositionForNode(node); + VisiblePosition startPos = firstPositionInOrBeforeNode(node); + VisiblePosition endPos = lastPositionInOrAfterNode(node); // the VisiblePositions are equal for nodes like buttons, so adjust for that // FIXME: Really? [button, 0] and [button, 1] are distinct (before and after the button) @@ -3083,9 +3087,24 @@ AccessibilityRole AccessibilityRenderObject::determineAccessibilityRole() #if PLATFORM(GTK) if (m_renderer->isHR()) return SplitterRole; + + if (node && node->hasTagName(pTag)) + return ParagraphRole; + + if (node && node->hasTagName(labelTag)) + return LabelRole; + + if (node && node->hasTagName(divTag)) + return DivRole; + + if (node && node->hasTagName(formTag)) + return FormRole; +#else + if (node && node->hasTagName(labelTag)) + return GroupRole; #endif - if (m_renderer->isBlockFlow() || (node && node->hasTagName(labelTag))) + if (m_renderer->isBlockFlow()) return GroupRole; // If the element does not have role, but it has ARIA attributes, accessibility should fallback to exposing it as a group. diff --git a/Source/WebCore/accessibility/gtk/AXObjectCacheAtk.cpp b/Source/WebCore/accessibility/gtk/AXObjectCacheAtk.cpp index 0701ece..f910ca6 100644 --- a/Source/WebCore/accessibility/gtk/AXObjectCacheAtk.cpp +++ b/Source/WebCore/accessibility/gtk/AXObjectCacheAtk.cpp @@ -143,6 +143,17 @@ void AXObjectCache::postPlatformNotification(AccessibilityObject* coreObject, AX 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); } } diff --git a/Source/WebCore/accessibility/gtk/AccessibilityObjectAtk.cpp b/Source/WebCore/accessibility/gtk/AccessibilityObjectAtk.cpp index c8c1951..850bcbe 100644 --- a/Source/WebCore/accessibility/gtk/AccessibilityObjectAtk.cpp +++ b/Source/WebCore/accessibility/gtk/AccessibilityObjectAtk.cpp @@ -43,17 +43,10 @@ AccessibilityObjectInclusion AccessibilityObject::accessibilityPlatformIncludesO if (roleValue() == SplitterRole) return IncludeObject; - if (isGroup()) { - // When a list item is made up entirely of children (e.g. paragraphs) - // the list item gets ignored. We need it. - if (parent->isList()) - return IncludeObject; - - // We expect the parent of a table cell to be a table. - AccessibilityObject* child = firstChild(); - if (child && child->roleValue() == CellRole) - return IgnoreObject; - } + // When a list item is made up entirely of children (e.g. paragraphs) + // the list item gets ignored. We need it. + if (isGroup() && parent->isList()) + return IncludeObject; // Entries and password fields have extraneous children which we want to ignore. if (parent->isPasswordField() || parent->isTextControl()) @@ -105,7 +98,13 @@ void AccessibilityObject::setWrapper(AccessibilityObjectWrapper* wrapper) bool AccessibilityObject::allowsTextRanges() const { - return isTextControl() || isWebArea() || isGroup() || isLink() || isHeading() || isListItem(); + // Check type for the AccessibilityObject. + if (isTextControl() || isWebArea() || isGroup() || isLink() || isHeading() || isListItem()) + return true; + + // Check roles as the last fallback mechanism. + AccessibilityRole role = roleValue(); + return role == ParagraphRole || role == LabelRole || role == DivRole || role == FormRole; } unsigned AccessibilityObject::getLengthForTextRange() const diff --git a/Source/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp b/Source/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp index 1d23612..7dff2e3 100644 --- a/Source/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp +++ b/Source/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp @@ -158,6 +158,11 @@ static AccessibilityObject* core(AtkDocument* document) return core(ATK_OBJECT(document)); } +static AccessibilityObject* core(AtkValue* value) +{ + return core(ATK_OBJECT(value)); +} + static gchar* webkit_accessible_text_get_text(AtkText* text, gint startOffset, gint endOffset); static const gchar* webkit_accessible_get_name(AtkObject* object) @@ -471,6 +476,14 @@ static AtkRole atkRole(AccessibilityRole role) case ListItemRole: case ListBoxOptionRole: return ATK_ROLE_LIST_ITEM; + case ParagraphRole: + return ATK_ROLE_PARAGRAPH; + case LabelRole: + return ATK_ROLE_LABEL; + case DivRole: + return ATK_ROLE_SECTION; + case FormRole: + return ATK_ROLE_FORM; default: return ATK_ROLE_UNKNOWN; } @@ -478,31 +491,16 @@ static AtkRole atkRole(AccessibilityRole role) static AtkRole webkit_accessible_get_role(AtkObject* object) { - AccessibilityObject* axObject = core(object); + AccessibilityObject* coreObject = core(object); - if (!axObject) + if (!coreObject) return ATK_ROLE_UNKNOWN; - // WebCore does not know about paragraph role, label role, or section role - if (axObject->isAccessibilityRenderObject()) { - Node* node = static_cast<AccessibilityRenderObject*>(axObject)->renderer()->node(); - if (node) { - if (node->hasTagName(HTMLNames::pTag)) - return ATK_ROLE_PARAGRAPH; - if (node->hasTagName(HTMLNames::labelTag)) - return ATK_ROLE_LABEL; - if (node->hasTagName(HTMLNames::divTag)) - return ATK_ROLE_SECTION; - if (node->hasTagName(HTMLNames::formTag)) - return ATK_ROLE_FORM; - } - } - // Note: Why doesn't WebCore have a password field for this - if (axObject->isPasswordField()) + if (coreObject->isPasswordField()) return ATK_ROLE_PASSWORD_TEXT; - return atkRole(axObject->roleValue()); + return atkRole(coreObject->roleValue()); } static bool selectionBelongsToObject(AccessibilityObject* coreObject, VisibleSelection& selection) @@ -2301,6 +2299,63 @@ static void atk_document_interface_init(AtkDocumentIface* iface) iface->get_document_locale = webkit_accessible_document_get_locale; } + +static void webkitAccessibleValueGetCurrentValue(AtkValue* value, GValue* gValue) +{ + memset(gValue, 0, sizeof(GValue)); + g_value_init(gValue, G_TYPE_DOUBLE); + g_value_set_double(gValue, core(value)->valueForRange()); +} + +static void webkitAccessibleValueGetMaximumValue(AtkValue* value, GValue* gValue) +{ + memset(gValue, 0, sizeof(GValue)); + g_value_init(gValue, G_TYPE_DOUBLE); + g_value_set_double(gValue, core(value)->maxValueForRange()); +} + +static void webkitAccessibleValueGetMinimumValue(AtkValue* value, GValue* gValue) +{ + memset(gValue, 0, sizeof(GValue)); + g_value_init(gValue, G_TYPE_DOUBLE); + g_value_set_double(gValue, core(value)->minValueForRange()); +} + +static gboolean webkitAccessibleValueSetCurrentValue(AtkValue* value, const GValue* gValue) +{ + if (!G_VALUE_HOLDS_DOUBLE(gValue) && !G_VALUE_HOLDS_INT(gValue)) + return FALSE; + + AccessibilityObject* coreObject = core(value); + if (!coreObject->canSetValueAttribute()) + return FALSE; + + if (G_VALUE_HOLDS_DOUBLE(gValue)) + coreObject->setValue(String::number(g_value_get_double(gValue))); + else + coreObject->setValue(String::number(g_value_get_int(gValue))); + + return TRUE; +} + +static void webkitAccessibleValueGetMinimumIncrement(AtkValue* value, GValue* gValue) +{ + memset(gValue, 0, sizeof(GValue)); + g_value_init(gValue, G_TYPE_DOUBLE); + + // There's not such a thing in the WAI-ARIA specification, thus return zero. + g_value_set_double(gValue, 0.0); +} + +static void atkValueInterfaceInit(AtkValueIface* iface) +{ + iface->get_current_value = webkitAccessibleValueGetCurrentValue; + iface->get_maximum_value = webkitAccessibleValueGetMaximumValue; + iface->get_minimum_value = webkitAccessibleValueGetMinimumValue; + iface->set_current_value = webkitAccessibleValueSetCurrentValue; + iface->get_minimum_increment = webkitAccessibleValueGetMinimumIncrement; +} + static const GInterfaceInfo AtkInterfacesInitFunctions[] = { {(GInterfaceInitFunc)atk_action_interface_init, (GInterfaceFinalizeFunc) 0, 0}, @@ -2321,6 +2376,8 @@ static const GInterfaceInfo AtkInterfacesInitFunctions[] = { {(GInterfaceInitFunc)atkHyperlinkImplInterfaceInit, (GInterfaceFinalizeFunc) 0, 0}, {(GInterfaceInitFunc)atk_document_interface_init, + (GInterfaceFinalizeFunc) 0, 0}, + {(GInterfaceInitFunc)atkValueInterfaceInit, (GInterfaceFinalizeFunc) 0, 0} }; @@ -2334,7 +2391,8 @@ enum WAIType { WAI_TABLE, WAI_HYPERTEXT, WAI_HYPERLINK, - WAI_DOCUMENT + WAI_DOCUMENT, + WAI_VALUE, }; static GType GetAtkInterfaceTypeFromWAIType(WAIType type) @@ -2360,6 +2418,8 @@ static GType GetAtkInterfaceTypeFromWAIType(WAIType type) return ATK_TYPE_HYPERLINK_IMPL; case WAI_DOCUMENT: return ATK_TYPE_DOCUMENT; + case WAI_VALUE: + return ATK_TYPE_VALUE; } return G_TYPE_INVALID; @@ -2431,6 +2491,10 @@ static guint16 getInterfaceMaskFromObject(AccessibilityObject* coreObject) if (role == WebAreaRole) interfaceMask |= 1 << WAI_DOCUMENT; + // Value + if (role == SliderRole) + interfaceMask |= 1 << WAI_VALUE; + return interfaceMask; } diff --git a/Source/WebCore/accessibility/gtk/WebKitAccessibleHyperlink.cpp b/Source/WebCore/accessibility/gtk/WebKitAccessibleHyperlink.cpp index 5927430..b9e483c 100644 --- a/Source/WebCore/accessibility/gtk/WebKitAccessibleHyperlink.cpp +++ b/Source/WebCore/accessibility/gtk/WebKitAccessibleHyperlink.cpp @@ -32,6 +32,7 @@ #include "RenderListMarker.h" #include "RenderObject.h" #include "TextIterator.h" +#include "htmlediting.h" #include <atk/atk.h> #include <glib.h> @@ -230,11 +231,19 @@ static gint webkitAccessibleHyperlinkGetStartIndex(AtkHyperlink* link) if (!coreObject) return 0; + AccessibilityObject* parentUnignored = coreObject->parentObjectUnignored(); + if (!parentUnignored) + return 0; + Node* node = coreObject->node(); if (!node) return 0; - RefPtr<Range> range = Range::create(node->document(), firstPositionInNode(node->parentNode()), firstPositionInNode(node)); + Node* parentNode = parentUnignored->node(); + if (!parentNode) + return 0; + + RefPtr<Range> range = Range::create(node->document(), firstPositionInOrBeforeNode(parentNode), firstPositionInOrBeforeNode(node)); return getRangeLengthForObject(coreObject, range.get()); } @@ -246,11 +255,19 @@ static gint webkitAccessibleHyperlinkGetEndIndex(AtkHyperlink* link) if (!coreObject) return 0; + AccessibilityObject* parentUnignored = coreObject->parentObjectUnignored(); + if (!parentUnignored) + return 0; + Node* node = coreObject->node(); if (!node) return 0; - RefPtr<Range> range = Range::create(node->document(), firstPositionInNode(node->parentNode()), lastPositionInNode(node)); + Node* parentNode = parentUnignored->node(); + if (!parentNode) + return 0; + + RefPtr<Range> range = Range::create(node->document(), firstPositionInOrBeforeNode(parentNode), lastPositionInOrAfterNode(node)); return getRangeLengthForObject(coreObject, range.get()); } diff --git a/Source/WebCore/accessibility/mac/AccessibilityObjectWrapper.mm b/Source/WebCore/accessibility/mac/AccessibilityObjectWrapper.mm index a71ccd4..c0dd795 100644 --- a/Source/WebCore/accessibility/mac/AccessibilityObjectWrapper.mm +++ b/Source/WebCore/accessibility/mac/AccessibilityObjectWrapper.mm @@ -41,6 +41,7 @@ #import "AccessibilityTableCell.h" #import "AccessibilityTableRow.h" #import "AccessibilityTableColumn.h" +#import "Chrome.h" #import "ColorMac.h" #import "Frame.h" #import "FrameLoaderClient.h" @@ -1286,7 +1287,11 @@ static const AccessibilityRoleMap& createAccessibilityRoleMap() { TabPanelRole, NSAccessibilityGroupRole }, { TreeRole, NSAccessibilityOutlineRole }, { TreeItemRole, NSAccessibilityRowRole }, - { ListItemRole, NSAccessibilityGroupRole } + { ListItemRole, NSAccessibilityGroupRole }, + { ParagraphRole, NSAccessibilityGroupRole }, + { LabelRole, NSAccessibilityGroupRole }, + { DivRole, NSAccessibilityGroupRole }, + { FormRole, NSAccessibilityGroupRole } }; AccessibilityRoleMap& roleMap = *new AccessibilityRoleMap; @@ -2330,28 +2335,20 @@ static NSString* roleValueToNSString(AccessibilityRole value) FrameView* frameView = m_object->documentFrameView(); if (!frameView) return; + Frame* frame = frameView->frame(); + if (!frame) + return; + Page* page = frame->page(); + if (!page) + return; - // simulate a click in the middle of the object + // Simulate a click in the middle of the object. IntPoint clickPoint = m_object->clickPoint(); - NSPoint nsClickPoint = NSMakePoint(clickPoint.x(), clickPoint.y()); - - NSView* view = nil; - if (m_object->isAttachment()) - view = [self attachmentView]; - else - view = frameView->documentView(); - - if (!view) - return; - - NSPoint nsScreenPoint = [view convertPoint:nsClickPoint toView:nil]; - - // Show the contextual menu for this event. - NSEvent* event = [NSEvent mouseEventWithType:NSRightMouseDown location:nsScreenPoint modifierFlags:0 timestamp:0 windowNumber:[[view window] windowNumber] context:0 eventNumber:0 clickCount:1 pressure:1]; - NSMenu* menu = [view menuForEvent:event]; - if (menu) - [NSMenu popUpContextMenu:menu withEvent:event forView:view]; + PlatformMouseEvent mouseEvent(clickPoint, clickPoint, RightButton, MouseEventPressed, 1, false, false, false, false, currentTime()); + bool handled = frame->eventHandler()->sendContextMenuEvent(mouseEvent); + if (handled) + page->chrome()->showContextMenu(); } - (void)accessibilityPerformAction:(NSString*)action |