2008-05-13 Beth Dakin <bdakin@apple.com>
authorbdakin@apple.com <bdakin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 15 May 2008 00:02:16 +0000 (00:02 +0000)
committerbdakin@apple.com <bdakin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 15 May 2008 00:02:16 +0000 (00:02 +0000)
        Reviewed by Brady.

        This patch adds support for the ARIA progressbar role and the
        following ARIA states (ie HTML attributes): aria-checked, aria-
        level, aria-pressed, aria-valuenow, aria-valuemin, and aria-
        valuemax.

        * html/HTMLAttributeNames.in:
        * page/AccessibilityObject.h:
        (WebCore::AccessibilityObject::isProgressIndicator):
        (WebCore::AccessibilityObject::valueForRange):
        (WebCore::AccessibilityObject::maxValueForRange):
        (WebCore::AccessibilityObject::minValueForRange):
        * page/AccessibilityRenderObject.cpp:
        (WebCore::AccessibilityRenderObject::isProgressIndicator):
        (WebCore::AccessibilityRenderObject::isPressed): Check the aria-
        pressed attribute if this is an ARIA button.
        (WebCore::AccessibilityRenderObject::headingLevel): Check the aria-
        level attribute if this is an ARIA heading.
        (WebCore::AccessibilityRenderObject::intValue): Check the aria-
        checked attribute if this is an ARIA radio button or checkbox.
        (WebCore::AccessibilityRenderObject::valueForRange):
        (WebCore::AccessibilityRenderObject::maxValueForRange):
        (WebCore::AccessibilityRenderObject::minValueForRange):
        (WebCore::RoleEntry::):
        (WebCore::AccessibilityRenderObject::canSetValueAttribute):
        * page/AccessibilityRenderObject.h:
        * page/mac/AccessibilityObjectWrapper.mm:
        (-[AccessibilityObjectWrapper accessibilityAttributeNames]):
        (-[AccessibilityObjectWrapper accessibilityAttributeValue:]):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@33465 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebCore/ChangeLog
WebCore/html/HTMLAttributeNames.in
WebCore/page/AccessibilityObject.h
WebCore/page/AccessibilityRenderObject.cpp
WebCore/page/AccessibilityRenderObject.h
WebCore/page/mac/AccessibilityObjectWrapper.mm

index 55ee150cb31d4cbe882fdb02e81b5bb03558d8fb..1415160b278cc76be20ec5fa7ca073d2cada02f4 100644 (file)
@@ -1,3 +1,37 @@
+2008-05-13  Beth Dakin  <bdakin@apple.com>
+
+        Reviewed by Brady.
+
+        This patch adds support for the ARIA progressbar role and the 
+        following ARIA states (ie HTML attributes): aria-checked, aria-
+        level, aria-pressed, aria-valuenow, aria-valuemin, and aria-
+        valuemax.
+
+        * html/HTMLAttributeNames.in:
+        * page/AccessibilityObject.h:
+        (WebCore::AccessibilityObject::isProgressIndicator):
+        (WebCore::AccessibilityObject::valueForRange):
+        (WebCore::AccessibilityObject::maxValueForRange):
+        (WebCore::AccessibilityObject::minValueForRange):
+        * page/AccessibilityRenderObject.cpp:
+        (WebCore::AccessibilityRenderObject::isProgressIndicator):
+        (WebCore::AccessibilityRenderObject::isPressed): Check the aria-
+        pressed attribute if this is an ARIA button.
+        (WebCore::AccessibilityRenderObject::headingLevel): Check the aria-
+        level attribute if this is an ARIA heading.
+        (WebCore::AccessibilityRenderObject::intValue): Check the aria-
+        checked attribute if this is an ARIA radio button or checkbox.
+        (WebCore::AccessibilityRenderObject::valueForRange):
+        (WebCore::AccessibilityRenderObject::maxValueForRange):
+        (WebCore::AccessibilityRenderObject::minValueForRange):
+        (WebCore::RoleEntry::):
+        (WebCore::AccessibilityRenderObject::canSetValueAttribute):
+        * page/AccessibilityRenderObject.h:
+        * page/mac/AccessibilityObjectWrapper.mm:
+        (-[AccessibilityObjectWrapper accessibilityAttributeNames]):
+        (-[AccessibilityObjectWrapper accessibilityAttributeValue:]):
+
+=======
 2008-05-14  Kevin McCullough  <kmccullough@apple.com>
 
         Reviewed by John.
index ae64c7fd0f45194fb8da10be4644c6c0a896ec87..26b9b6cae29bcfbee8aee1267921fe42c04fbbda 100644 (file)
@@ -7,9 +7,15 @@ align
 alink
 alt
 archive
+aria-checked
+aria-describedby
 aria-labeledby
 aria-labelledby
-aria-describedby
+aria-level
+aria-pressed
+aria-valuemax
+aria-valuemin
+aria-valuenow
 autocomplete
 autoplay
 autosave
index ce2226266c3db98cad9fd48fe00fc09e4f82d65d..bfc10de508930c9f8efb2510d7c8fa931ff55b4f 100644 (file)
@@ -199,6 +199,7 @@ public:
     virtual bool isCheckboxOrRadio() const { return false; };
     virtual bool isListBox() const { return false; };
     virtual bool isFileUploadButton() const { return false; };
+    virtual bool isProgressIndicator() const { return false; };
     
     virtual bool isChecked() const { return false; };
     virtual bool isEnabled() const { return false; };
@@ -223,6 +224,9 @@ public:
     virtual bool accessibilityIsIgnored() const  { return true; };
 
     virtual int intValue() const;
+    virtual float valueForRange() const { return 0.0f; }
+    virtual float maxValueForRange() const { return 0.0f; }
+    virtual float minValueForRange() const {return 0.0f; }
     virtual int layoutCount() const;
     static bool isARIAControl(AccessibilityRole);
     static bool isARIAInput(AccessibilityRole);
index 1071c06cf07a143f8627fe0758d5bd5a73f3eb56..f0d9f8e97847a9fc13df3217f5b207de74a078cf 100644 (file)
@@ -236,13 +236,30 @@ bool AccessibilityRenderObject::isFileUploadButton() const
     
     return false;
 }
+
+bool AccessibilityRenderObject::isProgressIndicator() const
+{
+    return roleValue() == ProgressIndicatorRole;
+}
     
 bool AccessibilityRenderObject::isPressed() const
 {
     ASSERT(m_renderer);
     if (roleValue() != ButtonRole)
         return false;
-    return m_renderer->node() && m_renderer->node()->active();
+
+    Node* node = m_renderer->node();
+    if (!node)
+        return false;
+
+    // If this is an ARIA button, check the aria-pressed attribute rather than node()->active()
+    if (ariaRoleAttribute() == ButtonRole) {
+        if (equalIgnoringCase(getAttribute(aria_pressedAttr).string(), "true"))
+            return true;
+        return false;
+    }
+
+    return node->active();
 }
 
 bool AccessibilityRenderObject::isIndeterminate() const
@@ -290,9 +307,19 @@ bool AccessibilityRenderObject::isOffScreen() const
 int AccessibilityRenderObject::headingLevel(Node* node)
 {
     // headings can be in block flow and non-block flow
-    
     if (!node)
         return 0;
+
+    if (RenderObject* renderer = node->renderer()) {
+        AccessibilityObject* axObjectForNode = node->document()->axObjectCache()->get(renderer);
+        if (axObjectForNode->ariaRoleAttribute() == HeadingRole) {
+            if (!node->isElementNode())
+                return 0;
+            Element* element = static_cast<Element*>(node);
+            return element->getAttribute(aria_levelAttr).toInt();
+        }
+    }
+            
     
     if (node->hasTagName(h1Tag))
         return 1;
@@ -312,15 +339,6 @@ int AccessibilityRenderObject::headingLevel(Node* node)
     if (node->hasTagName(h6Tag))
         return 6;
     
-    // FIXME: When we implement ARIA's level property, this needs to return that instead of 1.
-    RenderObject* renderer = node->renderer();
-    if (!renderer)
-        return 0;
-    
-    AccessibilityObject* axObjectForNode = node->document()->axObjectCache()->get(renderer);
-    if (axObjectForNode->ariaRoleAttribute() == HeadingRole)
-        return 1;    
-    
     return 0;
 }
 
@@ -334,6 +352,19 @@ bool AccessibilityRenderObject::isLink() const
     return roleValue() == WebCoreLinkRole;
 }    
 
+const AtomicString& AccessibilityRenderObject::getAttribute(const QualifiedName& attribute) const
+{
+    Node* node = m_renderer->element();
+    if (!node)
+        return nullAtom;
+
+    if (!node->isElementNode())
+        return nullAtom;
+
+    Element* element = static_cast<Element*>(node);
+    return element->getAttribute(attribute);
+}
+
 HTMLAnchorElement* AccessibilityRenderObject::anchorElement() const
 {
     // FIXME: In XHTML 2.0, any HTML element can have an href attribute. We will need to implement this to fully
@@ -479,10 +510,42 @@ int AccessibilityRenderObject::intValue() const
         return headingLevel(m_renderer->element());
     
     Node* node = m_renderer->element();
-    if (node && isCheckboxOrRadio() && ariaRoleAttribute() == UnknownRole)
-        return static_cast<HTMLInputElement*>(node)->checked();
+    if (!node || !isCheckboxOrRadio())
+        return 0;
+
+    // If this is an ARIA checkbox or radio, check the aria-checked attribute rather than node()->checked()
+    AccessibilityRole ariaRole = ariaRoleAttribute();
+    if (ariaRole == RadioButtonRole || ariaRole == CheckBoxRole) {
+        if (equalIgnoringCase(getAttribute(aria_checkedAttr).string(), "true"))
+            return true;
+        return false;
+    }
     
-    return 0;
+    return static_cast<HTMLInputElement*>(node)->checked();
+}
+
+float AccessibilityRenderObject::valueForRange() const
+{
+    if (!isProgressIndicator())
+        return 0.0f;
+
+    return getAttribute(aria_valuenowAttr).toFloat();
+}
+
+float AccessibilityRenderObject::maxValueForRange() const
+{
+    if (!isProgressIndicator())
+        return 0.0f;
+
+    return getAttribute(aria_valuemaxAttr).toFloat();
+}
+
+float AccessibilityRenderObject::minValueForRange() const
+{
+    if (!isProgressIndicator())
+        return 0.0f;
+
+    return getAttribute(aria_valueminAttr).toFloat();
 }
 
 String AccessibilityRenderObject::stringValue() const
@@ -578,15 +641,17 @@ String AccessibilityRenderObject::ariaAccessiblityName(const String& s) const
 String AccessibilityRenderObject::ariaLabeledByAttribute() const
 {
     Node* node = m_renderer->node();
-    if (!node || !node->isElementNode())
+    if (!node)
+        return String();
+
+    if (!node->isElementNode())
         return String();
 
     // The ARIA spec uses the British spelling: "labelled." It seems prudent to support the American
     // spelling ("labeled") as well.
-    Element* element = static_cast<Element*>(node);
-    String idList = element->getAttribute(aria_labeledbyAttr).string();
+    String idList = getAttribute(aria_labeledbyAttr).string();
     if (idList.isEmpty()) {
-        idList = element->getAttribute(aria_labelledbyAttr).string();
+        idList = getAttribute(aria_labelledbyAttr).string();
         if (idList.isEmpty())
             return String();
     }
@@ -639,8 +704,7 @@ String AccessibilityRenderObject::title() const
         return textUnderElement();
     
     if (isLink()) {
-        Element* element = static_cast<Element*>(node);    
-        const AtomicString& title = element->getAttribute(titleAttr);
+        const AtomicString& title = getAttribute(titleAttr);
         if (!title.isEmpty())
             return title;    
         
@@ -655,12 +719,7 @@ String AccessibilityRenderObject::title() const
 
 String AccessibilityRenderObject::ariaDescribedByAttribute() const
 {
-    Node* node = m_renderer->node();
-    if (!node || !node->isElementNode())
-        return String();
-
-    Element* element = static_cast<Element*>(node);
-    String idList = element->getAttribute(aria_describedbyAttr).string();
+    String idList = getAttribute(aria_describedbyAttr).string();
     if (idList.isEmpty())
         return String();
     
@@ -952,7 +1011,9 @@ String AccessibilityRenderObject::selectedText() const
 const AtomicString& AccessibilityRenderObject::accessKey() const
 {
     Node* node = m_renderer->element();
-    if (!node || !node->isElementNode())
+    if (!node)
+        return nullAtom;
+    if (!node->isElementNode())
         return nullAtom;
     return static_cast<Element*>(node)->getAttribute(accesskeyAttr);
 }
@@ -1539,6 +1600,7 @@ static const ARIARoleMap& createARIARoleMap()
         { String("heading"), HeadingRole },
         { String("img"), ImageRole },
         { String("link"), WebCoreLinkRole },
+        { String("progressbar"), ProgressIndicatorRole },
         { String("radio"), RadioButtonRole },
         { String("textbox"), TextAreaRole }
     };
@@ -1559,12 +1621,7 @@ static AccessibilityRole ariaRoleToWebCoreRole(String value)
 
 AccessibilityRole AccessibilityRenderObject::ariaRoleAttribute() const
 {
-    Node* node = m_renderer->node();
-    if (!node || !node->isElementNode())
-        return UnknownRole;
-    
-    Element* element = static_cast<Element*>(node);
-    String ariaRole = element->getAttribute(roleAttr).string();
+    String ariaRole = getAttribute(roleAttr).string();
     if (ariaRole.isNull() || ariaRole.isEmpty())
         return UnknownRole;
     
@@ -1712,7 +1769,7 @@ bool AccessibilityRenderObject::canSetFocusAttribute() const
 
 bool AccessibilityRenderObject::canSetValueAttribute() const
 {
-    return isTextControl();
+    return isTextControl() || isProgressIndicator();
 }
 
 bool AccessibilityRenderObject::canSetTextRangeAttributes() const
index f52deb4a7cddaba8f12d2b927ea9222285c32151..a95a74b031940ef362bb7274607b0811b14208cf 100644 (file)
@@ -74,6 +74,7 @@ public:
     virtual bool isWebArea() const;
     virtual bool isCheckboxOrRadio() const;
     virtual bool isFileUploadButton() const;
+    virtual bool isProgressIndicator() const;
     
     virtual bool isEnabled() const;
     virtual bool isSelected() const;
@@ -87,7 +88,8 @@ public:
     virtual bool isPressed() const;
     virtual bool isReadOnly() const;
     virtual bool isVisited() const;        
-    
+
+    const AtomicString& getAttribute(const QualifiedName&) const;
     virtual bool canSetFocusAttribute() const;
     virtual bool canSetTextRangeAttributes() const;
     virtual bool canSetValueAttribute() const;
@@ -99,6 +101,9 @@ public:
     
     static int headingLevel(Node*);
     virtual int intValue() const;
+    virtual float valueForRange() const;
+    virtual float maxValueForRange() const;
+    virtual float minValueForRange() const;
     virtual int layoutCount() const;
     
     virtual AccessibilityObject* doAccessibilityHitTest(const IntPoint&) const;
index 02bd13afc5163c0093a336bb0ccb2a4074dea24f..87f28e99f1251471df3fb230ddbe201c3d6e0fc1 100644 (file)
@@ -515,6 +515,7 @@ static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePositi
     static NSArray* webAreaAttrs = nil;
     static NSArray* textAttrs = nil;
     static NSArray* listBoxAttrs = nil;
+    static NSArray* progressIndicatorAttrs = nil;
     NSMutableArray* tempArray;
     if (attributes == nil) {
         attributes = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute,
@@ -573,6 +574,15 @@ static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePositi
         listBoxAttrs = [[NSArray alloc] initWithArray:tempArray];
         [tempArray release];
     }
+    if (progressIndicatorAttrs == nil) {
+        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
+        [tempArray addObject:NSAccessibilityTopLevelUIElementAttribute];
+        [tempArray addObject:NSAccessibilityValueAttribute];
+        [tempArray addObject:NSAccessibilityMinValueAttribute];
+        [tempArray addObject:NSAccessibilityMaxValueAttribute];
+        progressIndicatorAttrs = [[NSArray alloc] initWithArray:tempArray];
+        [tempArray release];
+    }
     
     if (m_object->isPasswordField())
         return attributes;
@@ -589,6 +599,9 @@ static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePositi
     if (m_object->isListBox())
         return listBoxAttrs;
 
+    if (m_object->isProgressIndicator())
+        return progressIndicatorAttrs;
+
     return attributes;
 }
 
@@ -919,12 +932,20 @@ static NSString* roleValueToNSString(AccessibilityRole value)
         if (m_object->isAttachment()) {
             if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityValueAttribute]) 
                 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityValueAttribute];
-        }    
+        }
+        if (m_object->isProgressIndicator())
+            return [NSNumber numberWithFloat:m_object->valueForRange()];
         if (m_object->hasIntValue())
             return [NSNumber numberWithInt:m_object->intValue()];
         return m_object->stringValue();
     }
 
+    if ([attributeName isEqualToString: NSAccessibilityMinValueAttribute])
+        return [NSNumber numberWithFloat:m_object->minValueForRange()];
+
+    if ([attributeName isEqualToString: NSAccessibilityMaxValueAttribute])
+        return [NSNumber numberWithFloat:m_object->maxValueForRange()];
+
     if ([attributeName isEqualToString: NSAccessibilityHelpAttribute])
         return m_object->helpText();
 
@@ -942,7 +963,8 @@ static NSString* roleValueToNSString(AccessibilityRole value)
     if ([attributeName isEqualToString: NSAccessibilityPositionAttribute])
         return [self position];
 
-    if ([attributeName isEqualToString: NSAccessibilityWindowAttribute]) {
+    if ([attributeName isEqualToString: NSAccessibilityWindowAttribute] ||
+        [attributeName isEqualToString: NSAccessibilityTopLevelUIElementAttribute]) {
         FrameView* fv = m_object->documentFrameView();
         if (fv)
             return [fv->getView() window];