Use is<>() / downcast<>() for Accessibility objects
[WebKit-https.git] / Source / WebCore / accessibility / AccessibilityNodeObject.cpp
index 1c3739c..07966cf 100644 (file)
@@ -42,6 +42,7 @@
 #include "FrameSelection.h"
 #include "FrameView.h"
 #include "HTMLAreaElement.h"
+#include "HTMLCanvasElement.h"
 #include "HTMLFieldSetElement.h"
 #include "HTMLFormElement.h"
 #include "HTMLFrameElementBase.h"
@@ -63,6 +64,7 @@
 #include "HitTestResult.h"
 #include "LabelableElement.h"
 #include "LocalizedStrings.h"
+#include "MathMLElement.h"
 #include "MathMLNames.h"
 #include "NodeList.h"
 #include "NodeTraversal.h"
@@ -290,7 +292,7 @@ AccessibilityRole AccessibilityNodeObject::determineAccessibilityRole()
         return StaticTextRole;
     if (node()->hasTagName(buttonTag))
         return buttonRoleType();
-    if (is<HTMLInputElement>(node())) {
+    if (is<HTMLInputElement>(*node())) {
         HTMLInputElement& input = downcast<HTMLInputElement>(*node());
         if (input.isCheckbox())
             return CheckBoxRole;
@@ -313,7 +315,7 @@ AccessibilityRole AccessibilityNodeObject::determineAccessibilityRole()
         HTMLSelectElement& selectElement = downcast<HTMLSelectElement>(*node());
         return selectElement.multiple() ? ListBoxRole : PopUpButtonRole;
     }
-    if (is<HTMLTextAreaElement>(node()))
+    if (is<HTMLTextAreaElement>(*node()))
         return TextAreaRole;
     if (headingLevel())
         return HeadingRole;
@@ -321,9 +323,9 @@ AccessibilityRole AccessibilityNodeObject::determineAccessibilityRole()
         return DivRole;
     if (node()->hasTagName(pTag))
         return ParagraphRole;
-    if (is<HTMLLabelElement>(node()))
+    if (is<HTMLLabelElement>(*node()))
         return LabelRole;
-    if (node()->isElementNode() && toElement(node())->isFocusable())
+    if (is<Element>(*node()) && downcast<Element>(*node()).isFocusable())
         return GroupRole;
     
     return UnknownRole;
@@ -440,9 +442,9 @@ bool AccessibilityNodeObject::computeAccessibilityIsIgnored() const
 bool AccessibilityNodeObject::canvasHasFallbackContent() const
 {
     Node* node = this->node();
-    if (!node || !node->hasTagName(canvasTag))
+    if (!is<HTMLCanvasElement>(node))
         return false;
-    Element& canvasElement = toElement(*node);
+    HTMLCanvasElement& canvasElement = downcast<HTMLCanvasElement>(*node);
     // If it has any children that are elements, we'll assume it might be fallback
     // content. If it has no children or its only children are not elements
     // (e.g. just text nodes), it doesn't have fallback content.
@@ -465,10 +467,10 @@ bool AccessibilityNodeObject::isNativeTextControl() const
     if (!node)
         return false;
 
-    if (is<HTMLTextAreaElement>(node))
+    if (is<HTMLTextAreaElement>(*node))
         return true;
 
-    if (is<HTMLInputElement>(node)) {
+    if (is<HTMLInputElement>(*node)) {
         HTMLInputElement& input = downcast<HTMLInputElement>(*node);
         return input.isText() || input.isNumberField();
     }
@@ -512,13 +514,13 @@ bool AccessibilityNodeObject::isNativeImage() const
     if (!node)
         return false;
 
-    if (is<HTMLImageElement>(node))
+    if (is<HTMLImageElement>(*node))
         return true;
 
     if (node->hasTagName(appletTag) || node->hasTagName(embedTag) || node->hasTagName(objectTag))
         return true;
 
-    if (is<HTMLInputElement>(node)) {
+    if (is<HTMLInputElement>(*node)) {
         HTMLInputElement& input = downcast<HTMLInputElement>(*node);
         return input.isImageButton();
     }
@@ -550,10 +552,7 @@ bool AccessibilityNodeObject::isPasswordField() const
 bool AccessibilityNodeObject::isInputImage() const
 {
     Node* node = this->node();
-    if (!node)
-        return false;
-    if (roleValue() == ButtonRole && is<HTMLInputElement>(node)) {
+    if (is<HTMLInputElement>(node) && roleValue() == ButtonRole) {
         HTMLInputElement& input = downcast<HTMLInputElement>(*node);
         return input.isImageButton();
     }
@@ -641,10 +640,10 @@ bool AccessibilityNodeObject::isEnabled() const
         return false;
     
     Node* node = this->node();
-    if (!node || !node->isElementNode())
+    if (!is<Element>(node))
         return true;
 
-    return !toElement(node)->isDisabledFormControl();
+    return !downcast<Element>(*node).isDisabledFormControl();
 }
 
 bool AccessibilityNodeObject::isIndeterminate() const
@@ -676,9 +675,9 @@ bool AccessibilityNodeObject::isPressed() const
         return false;
     }
 
-    if (!node->isElementNode())
+    if (!is<Element>(*node))
         return false;
-    return toElement(node)->active();
+    return downcast<Element>(*node).active();
 }
 
 bool AccessibilityNodeObject::isChecked() const
@@ -715,10 +714,7 @@ bool AccessibilityNodeObject::isChecked() const
 bool AccessibilityNodeObject::isHovered() const
 {
     Node* node = this->node();
-    if (!node)
-        return false;
-
-    return node->isElementNode() && toElement(node)->hovered();
+    return is<Element>(node) && downcast<Element>(*node).hovered();
 }
 
 bool AccessibilityNodeObject::isMultiSelectable() const
@@ -738,10 +734,10 @@ bool AccessibilityNodeObject::isReadOnly() const
     if (!node)
         return true;
 
-    if (is<HTMLTextAreaElement>(node))
-        return downcast<HTMLTextAreaElement>(node)->isReadOnly();
+    if (is<HTMLTextAreaElement>(*node))
+        return downcast<HTMLTextAreaElement>(*node).isReadOnly();
 
-    if (is<HTMLInputElement>(node)) {
+    if (is<HTMLInputElement>(*node)) {
         HTMLInputElement& input = downcast<HTMLInputElement>(*node);
         if (input.isTextField())
             return input.isReadOnly();
@@ -760,8 +756,8 @@ bool AccessibilityNodeObject::isRequired() const
         return false;
 
     Node* n = this->node();
-    if (n && is<HTMLFormControlElement>(n))
-        return downcast<HTMLFormControlElement>(n)->isRequired();
+    if (is<HTMLFormControlElement>(n))
+        return downcast<HTMLFormControlElement>(*n).isRequired();
 
     return false;
 }
@@ -837,7 +833,7 @@ String AccessibilityNodeObject::valueDescription() const
 
 float AccessibilityNodeObject::valueForRange() const
 {
-    if (node() && is<HTMLInputElement>(node())) {
+    if (is<HTMLInputElement>(node())) {
         HTMLInputElement& input = downcast<HTMLInputElement>(*node());
         if (input.isRangeControl())
             return input.valueAsNumber();
@@ -851,7 +847,7 @@ float AccessibilityNodeObject::valueForRange() const
 
 float AccessibilityNodeObject::maxValueForRange() const
 {
-    if (node() && is<HTMLInputElement>(node())) {
+    if (is<HTMLInputElement>(node())) {
         HTMLInputElement& input = downcast<HTMLInputElement>(*node());
         if (input.isRangeControl())
             return input.maximum();
@@ -865,7 +861,7 @@ float AccessibilityNodeObject::maxValueForRange() const
 
 float AccessibilityNodeObject::minValueForRange() const
 {
-    if (node() && is<HTMLInputElement>(node())) {
+    if (is<HTMLInputElement>(node())) {
         HTMLInputElement& input = downcast<HTMLInputElement>(*node());
         if (input.isRangeControl())
             return input.minimum();
@@ -898,7 +894,7 @@ bool AccessibilityNodeObject::isControl() const
     if (!node)
         return false;
 
-    return is<HTMLFormControlElement>(node) || AccessibilityObject::isARIAControl(ariaRoleAttribute());
+    return is<HTMLFormControlElement>(*node) || AccessibilityObject::isARIAControl(ariaRoleAttribute());
 }
 
 bool AccessibilityNodeObject::isFieldset() const
@@ -963,8 +959,8 @@ Element* AccessibilityNodeObject::anchorElement() const
     // search up the DOM tree for an anchor element
     // NOTE: this assumes that any non-image with an anchor is an HTMLAnchorElement
     for ( ; node; node = node->parentNode()) {
-        if (is<HTMLAnchorElement>(node) || (node->renderer() && cache->getOrCreate(node->renderer())->isAnchor()))
-            return toElement(node);
+        if (is<HTMLAnchorElement>(*node) || (node->renderer() && cache->getOrCreate(node->renderer())->isAnchor()))
+            return downcast<Element>(node);
     }
 
     return nullptr;
@@ -972,7 +968,7 @@ Element* AccessibilityNodeObject::anchorElement() const
 
 static bool isNodeActionElement(Node* node)
 {
-    if (is<HTMLInputElement>(node)) {
+    if (is<HTMLInputElement>(*node)) {
         HTMLInputElement& input = downcast<HTMLInputElement>(*node);
         if (!input.isDisabledFormControl() && (input.isRadioButton() || input.isCheckbox() || input.isTextButton() || input.isFileUpload() || input.isImageButton()))
             return true;
@@ -993,7 +989,7 @@ static Element* nativeActionElement(Node* start)
     
     for (Node* child = start->firstChild(); child; child = child->nextSibling()) {
         if (isNodeActionElement(child))
-            return toElement(child);
+            return downcast<Element>(child);
 
         if (Element* subChild = nativeActionElement(child))
             return subChild;
@@ -1008,10 +1004,10 @@ Element* AccessibilityNodeObject::actionElement() const
         return nullptr;
 
     if (isNodeActionElement(node))
-        return toElement(node);
+        return downcast<Element>(node);
     
     if (AccessibilityObject::isARIAInput(ariaRoleAttribute()))
-        return toElement(node);
+        return downcast<Element>(node);
 
     switch (roleValue()) {
     case ButtonRole:
@@ -1025,7 +1021,7 @@ Element* AccessibilityNodeObject::actionElement() const
         // Check if the author is hiding the real control element inside the ARIA element.
         if (Element* nativeElement = nativeActionElement(node))
             return nativeElement;
-        return toElement(node);
+        return downcast<Element>(node);
     default:
         break;
     }
@@ -1044,7 +1040,7 @@ Element* AccessibilityNodeObject::mouseButtonListener(MouseButtonListenerResultF
 
     // check if our parent is a mouse button listener
     // FIXME: Do the continuation search like anchorElement does
-    for (auto& element : elementLineage(node->isElementNode() ? toElement(node) : node->parentElement())) {
+    for (auto& element : elementLineage(is<Element>(*node) ? downcast<Element>(node) : node->parentElement())) {
         // If we've reached the body and this is not a control element, do not expose press action for this element unless filter is IncludeBodyElement.
         // It can cause false positives, where every piece of text is labeled as accepting press actions.
         if (element.hasTagName(bodyTag) && isStaticText() && filter == ExcludeBodyElement)
@@ -1080,13 +1076,13 @@ void AccessibilityNodeObject::alterSliderValue(bool increase)
     
 void AccessibilityNodeObject::increment()
 {
-    UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
+    UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture, document());
     alterSliderValue(true);
 }
 
 void AccessibilityNodeObject::decrement()
 {
-    UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
+    UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture, document());
     alterSliderValue(false);
 }
 
@@ -1159,7 +1155,7 @@ bool AccessibilityNodeObject::isGenericFocusableElement() const
 
 HTMLLabelElement* AccessibilityNodeObject::labelForElement(Element* element) const
 {
-    if (!is<HTMLElement>(element) || !downcast<HTMLElement>(element)->isLabelable())
+    if (!is<HTMLElement>(*element) || !downcast<HTMLElement>(*element).isLabelable())
         return nullptr;
 
     const AtomicString& id = element->getIdAttribute();
@@ -1250,10 +1246,9 @@ void AccessibilityNodeObject::titleElementText(Vector<AccessibilityText>& textOr
     if (!node)
         return;
     
-    bool isInputTag = is<HTMLInputElement>(node);
+    bool isInputTag = is<HTMLInputElement>(*node);
     if (isInputTag || AccessibilityObject::isARIAInput(ariaRoleAttribute()) || isControl()) {
-        HTMLLabelElement* label = labelForElement(toElement(node));
-        if (label) {
+        if (HTMLLabelElement* label = labelForElement(downcast<Element>(node))) {
             AccessibilityObject* labelObject = axObjectCache()->getOrCreate(label);
             String innerText = label->innerText();
             // Only use the <label> text if there's no ARIA override.
@@ -1284,8 +1279,8 @@ void AccessibilityNodeObject::alternativeText(Vector<AccessibilityText>& textOrd
         textOrder.append(AccessibilityText(ariaLabel, AlternativeText));
     
     if (usesAltTagForTextComputation()) {
-        if (renderer() && renderer()->isRenderImage()) {
-            String renderAltText = toRenderImage(renderer())->altText();
+        if (is<RenderImage>(renderer())) {
+            String renderAltText = downcast<RenderImage>(*renderer()).altText();
 
             // RenderImage will return title as a fallback from altText, but we don't want title here because we consider that in helpText.
             if (!renderAltText.isEmpty() && renderAltText != getAttribute(titleAttr)) {
@@ -1305,7 +1300,7 @@ void AccessibilityNodeObject::alternativeText(Vector<AccessibilityText>& textOrd
         return;
     
     // The fieldset element derives its alternative text from the first associated legend element if one is available.
-    if (is<HTMLFieldSetElement>(node)) {
+    if (is<HTMLFieldSetElement>(*node)) {
         AccessibilityObject* object = axObjectCache()->getOrCreate(downcast<HTMLFieldSetElement>(*node).legend());
         if (object && !object->isHidden())
             textOrder.append(AccessibilityText(accessibleNameForNode(object->node()), AlternativeText));
@@ -1327,7 +1322,7 @@ void AccessibilityNodeObject::visibleText(Vector<AccessibilityText>& textOrder)
     if (!node)
         return;
     
-    bool isInputTag = is<HTMLInputElement>(node);
+    bool isInputTag = is<HTMLInputElement>(*node);
     if (isInputTag) {
         HTMLInputElement& input = downcast<HTMLInputElement>(*node);
         if (input.isTextButton()) {
@@ -1502,7 +1497,7 @@ String AccessibilityNodeObject::accessibilityDescription() const
         return downcast<SVGElement>(*m_node).title();
     
 #if ENABLE(MATHML)
-    if (m_node && m_node->isMathMLElement())
+    if (is<MathMLElement>(m_node))
         return getAttribute(MathMLNames::alttextAttr);
 #endif
 
@@ -1531,21 +1526,22 @@ String AccessibilityNodeObject::helpText() const
         return describedBy;
     
     String description = accessibilityDescription();
-    for (Node* curr = node; curr; curr = curr->parentNode()) {
-        if (curr->isHTMLElement()) {
-            const AtomicString& summary = toElement(curr)->getAttribute(summaryAttr);
+    for (Node* ancestor = node; ancestor; ancestor = ancestor->parentNode()) {
+        if (is<HTMLElement>(*ancestor)) {
+            HTMLElement& element = downcast<HTMLElement>(*ancestor);
+            const AtomicString& summary = element.getAttribute(summaryAttr);
             if (!summary.isEmpty())
                 return summary;
             
             // The title attribute should be used as help text unless it is already being used as descriptive text.
-            const AtomicString& title = toElement(curr)->getAttribute(titleAttr);
+            const AtomicString& title = element.getAttribute(titleAttr);
             if (!title.isEmpty() && description != title)
                 return title;
         }
         
         // Only take help text from an ancestor element if its a group or an unknown role. If help was 
         // added to those kinds of elements, it is likely it was meant for a child element.
-        AccessibilityObject* axObj = axObjectCache()->getOrCreate(curr);
+        AccessibilityObject* axObj = axObjectCache()->getOrCreate(ancestor);
         if (axObj) {
             AccessibilityRole role = axObj->roleValue();
             if (role != GroupRole && role != UnknownRole)
@@ -1559,10 +1555,10 @@ String AccessibilityNodeObject::helpText() const
 unsigned AccessibilityNodeObject::hierarchicalLevel() const
 {
     Node* node = this->node();
-    if (!node || !node->isElementNode())
+    if (!is<Element>(node))
         return 0;
-    Element* element = toElement(node);
-    const AtomicString& ariaLevel = element->fastGetAttribute(aria_levelAttr);
+    Element& element = downcast<Element>(*node);
+    const AtomicString& ariaLevel = element.fastGetAttribute(aria_levelAttr);
     if (!ariaLevel.isEmpty())
         return ariaLevel.toInt();
     
@@ -1652,7 +1648,7 @@ static void appendNameToStringBuilder(StringBuilder& builder, const String& text
 String AccessibilityNodeObject::textUnderElement(AccessibilityTextUnderElementMode mode) const
 {
     Node* node = this->node();
-    if (node && is<Text>(node))
+    if (is<Text>(node))
         return downcast<Text>(*node).wholeText();
 
     // The render tree should be stable before going ahead. Otherwise, further uses of the
@@ -1673,9 +1669,9 @@ String AccessibilityNodeObject::textUnderElement(AccessibilityTextUnderElementMo
         if (!shouldUseAccessiblityObjectInnerText(child, mode))
             continue;
 
-        if (child->isAccessibilityNodeObject()) {
+        if (is<AccessibilityNodeObject>(*child)) {
             Vector<AccessibilityText> textOrder;
-            toAccessibilityNodeObject(child)->alternativeText(textOrder);
+            downcast<AccessibilityNodeObject>(*child).alternativeText(textOrder);
             if (textOrder.size() > 0 && textOrder[0].text.length()) {
                 appendNameToStringBuilder(builder, textOrder[0].text);
                 continue;
@@ -1696,7 +1692,7 @@ String AccessibilityNodeObject::title() const
     if (!node)
         return String();
 
-    bool isInputTag = is<HTMLInputElement>(node);
+    bool isInputTag = is<HTMLInputElement>(*node);
     if (isInputTag) {
         HTMLInputElement& input = downcast<HTMLInputElement>(*node);
         if (input.isTextButton())
@@ -1704,7 +1700,7 @@ String AccessibilityNodeObject::title() const
     }
 
     if (isInputTag || AccessibilityObject::isARIAInput(ariaRoleAttribute()) || isControl()) {
-        HTMLLabelElement* label = labelForElement(toElement(node));
+        HTMLLabelElement* label = labelForElement(downcast<Element>(node));
         // Use the label text as the title if 1) the title element is NOT an exposed element and 2) there's no ARIA override.
         if (label && !exposesTitleUIElement() && !ariaAccessibilityDescription().length())
             return label->innerText();
@@ -1770,7 +1766,7 @@ String AccessibilityNodeObject::text() const
     if (!node->isElementNode())
         return String();
 
-    return toElement(node)->innerText();
+    return downcast<Element>(node)->innerText();
 }
 
 String AccessibilityNodeObject::stringValue() const
@@ -1822,7 +1818,7 @@ void AccessibilityNodeObject::colorValue(int& r, int& g, int& b) const
     if (!isColorWell())
         return;
 
-    if (!node() || !is<HTMLInputElement>(node()))
+    if (!is<HTMLInputElement>(node()))
         return;
 
     HTMLInputElement& input = downcast<HTMLInputElement>(*node());
@@ -1842,15 +1838,15 @@ void AccessibilityNodeObject::colorValue(int& r, int& g, int& b) const
 static String accessibleNameForNode(Node* node)
 {
     ASSERT(node);
-    if (!node || !node->isElementNode())
+    if (!is<Element>(node))
         return String();
     
-    Element* element = toElement(node);
-    const AtomicString& ariaLabel = element->fastGetAttribute(aria_labelAttr);
+    Element& element = downcast<Element>(*node);
+    const AtomicString& ariaLabel = element.fastGetAttribute(aria_labelAttr);
     if (!ariaLabel.isEmpty())
         return ariaLabel;
     
-    const AtomicString& alt = element->fastGetAttribute(altAttr);
+    const AtomicString& alt = element.fastGetAttribute(altAttr);
     if (!alt.isEmpty())
         return alt;
 
@@ -1863,7 +1859,7 @@ static String accessibleNameForNode(Node* node)
             return valueDescription;
     }
     
-    if (is<HTMLInputElement>(node))
+    if (is<HTMLInputElement>(*node))
         return downcast<HTMLInputElement>(*node).value();
     
     String text;
@@ -1871,12 +1867,12 @@ static String accessibleNameForNode(Node* node)
         if (axObject->accessibleNameDerivesFromContent())
             text = axObject->textUnderElement(AccessibilityTextUnderElementMode(AccessibilityTextUnderElementMode::TextUnderElementModeIncludeNameFromContentsChildren, true));
     } else
-        text = element->innerText();
+        text = element.innerText();
 
     if (!text.isEmpty())
         return text;
     
-    const AtomicString& title = element->fastGetAttribute(titleAttr);
+    const AtomicString& title = element.fastGetAttribute(titleAttr);
     if (!title.isEmpty())
         return title;
     
@@ -1939,18 +1935,15 @@ bool AccessibilityNodeObject::canSetFocusAttribute() const
     // NOTE: It would be more accurate to ask the document whether setFocusedElement() would
     // do anything. For example, setFocusedElement() will do nothing if the current focused
     // node will not relinquish the focus.
-    if (!node)
-        return false;
-
-    if (!node->isElementNode())
+    if (!is<Element>(node))
         return false;
 
-    Element* element = toElement(node);
+    Element& element = downcast<Element>(*node);
 
-    if (element->isDisabledFormControl())
+    if (element.isDisabledFormControl())
         return false;
 
-    return element->supportsFocus();
+    return element.supportsFocus();
 }
 
 AccessibilityRole AccessibilityNodeObject::determineAriaRoleAttribute() const