📄 accessibilityrenderobject.cpp
字号:
}String AccessibilityRenderObject::ariaLabeledByAttribute() const{ Node* node = m_renderer->node(); 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. String idList = getAttribute(aria_labeledbyAttr).string(); if (idList.isEmpty()) { idList = getAttribute(aria_labelledbyAttr).string(); if (idList.isEmpty()) return String(); } return ariaAccessiblityName(idList);}static HTMLLabelElement* labelForElement(Element* element){ RefPtr<NodeList> list = element->document()->getElementsByTagName("label"); unsigned len = list->length(); for (unsigned i = 0; i < len; i++) { if (list->item(i)->hasTagName(labelTag)) { HTMLLabelElement* label = static_cast<HTMLLabelElement*>(list->item(i)); if (label->correspondingControl() == element) return label; } } return 0;} HTMLLabelElement* AccessibilityRenderObject::labelElementContainer() const{ if (!m_renderer) return false; // the control element should not be considered part of the label if (isControl()) return false; // find if this has a parent that is a label for (Node* parentNode = m_renderer->node(); parentNode; parentNode = parentNode->parentNode()) { if (parentNode->hasTagName(labelTag)) return static_cast<HTMLLabelElement*>(parentNode); } return 0;}String AccessibilityRenderObject::title() const{ AccessibilityRole ariaRole = ariaRoleAttribute(); if (!m_renderer) return String(); Node* node = m_renderer->node(); if (!node) return String(); String ariaLabel = ariaLabeledByAttribute(); if (!ariaLabel.isEmpty()) return ariaLabel; const AtomicString& title = getAttribute(titleAttr); if (!title.isEmpty()) return title; bool isInputTag = node->hasTagName(inputTag); if (isInputTag) { HTMLInputElement* input = static_cast<HTMLInputElement*>(node); if (input->isTextButton()) return input->value(); } if (isInputTag || AccessibilityObject::isARIAInput(ariaRole) || isControl()) { HTMLLabelElement* label = labelForElement(static_cast<Element*>(node)); if (label && !titleUIElement()) return label->innerText(); } if (roleValue() == ButtonRole || ariaRole == ListBoxOptionRole || ariaRole == MenuItemRole || ariaRole == MenuButtonRole || isHeading()) return textUnderElement(); if (isLink()) return textUnderElement(); return String();}String AccessibilityRenderObject::ariaDescribedByAttribute() const{ String idList = getAttribute(aria_describedbyAttr).string(); if (idList.isEmpty()) return String(); return ariaAccessiblityName(idList);}String AccessibilityRenderObject::accessibilityDescription() const{ if (!m_renderer) return String(); String ariaDescription = ariaDescribedByAttribute(); if (!ariaDescription.isEmpty()) return ariaDescription; if (isImage() || isInputImage()) { Node* node = m_renderer->node(); if (node && node->isHTMLElement()) { const AtomicString& alt = static_cast<HTMLElement*>(node)->getAttribute(altAttr); if (alt.isEmpty()) return String(); return alt; } } if (isWebArea()) { Document *document = m_renderer->document(); Node* owner = document->ownerElement(); if (owner) { if (owner->hasTagName(frameTag) || owner->hasTagName(iframeTag)) { const AtomicString& title = static_cast<HTMLFrameElementBase*>(owner)->getAttribute(titleAttr); if (!title.isEmpty()) return title; return static_cast<HTMLFrameElementBase*>(owner)->name(); } if (owner->isHTMLElement()) return static_cast<HTMLElement*>(owner)->getAttribute(nameAttr); } owner = document->body(); if (owner && owner->isHTMLElement()) return static_cast<HTMLElement*>(owner)->getAttribute(nameAttr); } if (roleValue() == DefinitionListTermRole) return AXDefinitionListTermText(); if (roleValue() == DefinitionListDefinitionRole) return AXDefinitionListDefinitionText(); return String();}IntRect AccessibilityRenderObject::boundingBoxRect() const{ IntRect rect; RenderObject* obj = m_renderer; if (!obj) return IntRect(); if (obj->node()) // If we are a continuation, we want to make sure to use the primary renderer. obj = obj->node()->renderer(); // FIXME: This doesn't work correctly with transforms. Vector<IntRect> rects; FloatPoint absPos = obj->localToAbsolute(); obj->absoluteRects(rects, absPos.x(), absPos.y()); const size_t n = rects.size(); for (size_t i = 0; i < n; ++i) { IntRect r = rects[i]; if (!r.isEmpty()) { if (obj->style()->hasAppearance()) theme()->adjustRepaintRect(obj, r); rect.unite(r); } } return rect;} IntRect AccessibilityRenderObject::checkboxOrRadioRect() const{ if (!m_renderer) return IntRect(); HTMLLabelElement* label = labelForElement(static_cast<Element*>(m_renderer->node())); if (!label || !label->renderer()) return boundingBoxRect(); IntRect labelRect = axObjectCache()->getOrCreate(label->renderer())->elementRect(); labelRect.unite(boundingBoxRect()); return labelRect;}IntRect AccessibilityRenderObject::elementRect() const{ // a checkbox or radio button should encompass its label if (isCheckboxOrRadio()) return checkboxOrRadioRect(); return boundingBoxRect();}IntSize AccessibilityRenderObject::size() const{ IntRect rect = elementRect(); return rect.size();}AccessibilityObject* AccessibilityRenderObject::internalLinkElement() const{ Element* element = anchorElement(); if (!element) return 0; // Right now, we do not support ARIA links as internal link elements if (!element->hasTagName(aTag)) return 0; HTMLAnchorElement* anchor = static_cast<HTMLAnchorElement*>(element); KURL linkURL = anchor->href(); String ref = linkURL.ref(); if (ref.isEmpty()) return 0; // check if URL is the same as current URL linkURL.removeRef(); if (m_renderer->document()->url() != linkURL) return 0; Node* linkedNode = m_renderer->document()->findAnchor(ref); if (!linkedNode) return 0; // the element we find may not be accessible, keep searching until we find a good one AccessibilityObject* linkedAXElement = m_renderer->document()->axObjectCache()->getOrCreate(linkedNode->renderer()); while (linkedAXElement && linkedAXElement->accessibilityIsIgnored()) { linkedNode = linkedNode->traverseNextNode(); while (linkedNode && !linkedNode->renderer()) linkedNode = linkedNode->traverseNextSibling(); if (!linkedNode) return 0; linkedAXElement = m_renderer->document()->axObjectCache()->getOrCreate(linkedNode->renderer()); } return linkedAXElement;} void AccessibilityRenderObject::addRadioButtonGroupMembers(AccessibilityChildrenVector& linkedUIElements) const{ if (!m_renderer || roleValue() != RadioButtonRole) return; Node* node = m_renderer->node(); if (!node || !node->hasTagName(inputTag)) return; HTMLInputElement* input = static_cast<HTMLInputElement*>(node); // if there's a form, then this is easy if (input->form()) { Vector<RefPtr<Node> > formElements; input->form()->getNamedElements(input->name(), formElements); unsigned len = formElements.size(); for (unsigned i = 0; i < len; ++i) { Node* associateElement = formElements[i].get(); if (AccessibilityObject* object = m_renderer->document()->axObjectCache()->getOrCreate(associateElement->renderer())) linkedUIElements.append(object); } } else { RefPtr<NodeList> list = node->document()->getElementsByTagName("input"); unsigned len = list->length(); for (unsigned i = 0; i < len; ++i) { if (list->item(i)->hasTagName(inputTag)) { HTMLInputElement* associateElement = static_cast<HTMLInputElement*>(list->item(i)); if (associateElement->isRadioButton() && associateElement->name() == input->name()) { if (AccessibilityObject* object = m_renderer->document()->axObjectCache()->getOrCreate(associateElement->renderer())) linkedUIElements.append(object); } } } }} // linked ui elements could be all the related radio buttons in a group// or an internal anchor connectionvoid AccessibilityRenderObject::linkedUIElements(AccessibilityChildrenVector& linkedUIElements) const{ if (isAnchor()) { AccessibilityObject* linkedAXElement = internalLinkElement(); if (linkedAXElement) linkedUIElements.append(linkedAXElement); } if (roleValue() == RadioButtonRole) addRadioButtonGroupMembers(linkedUIElements);}AccessibilityObject* AccessibilityRenderObject::titleUIElement() const{ if (!m_renderer) return 0; // if isFieldset is true, the renderer is guaranteed to be a RenderFieldset if (isFieldset()) return axObjectCache()->getOrCreate(static_cast<RenderFieldset*>(m_renderer)->findLegend()); // checkbox and radio hide their labels. Only controls get titleUIElements for now if (isCheckboxOrRadio() || !isControl()) return 0; Node* element = m_renderer->node(); HTMLLabelElement* label = labelForElement(static_cast<Element*>(element)); if (label && label->renderer()) return axObjectCache()->getOrCreate(label->renderer()); return 0; } bool AccessibilityRenderObject::accessibilityIsIgnored() const{ // ignore invisible element if (!m_renderer || m_renderer->style()->visibility() != VISIBLE) return true; if (isPresentationalChildOfAriaRole()) return true; // ignore popup menu items because AppKit does for (RenderObject* parent = m_renderer->parent(); parent; parent = parent->parent()) { if (parent->isMenuList()) return true; } // find out if this element is inside of a label element. // if so, it may be ignored because it's the label for a checkbox or radio button HTMLLabelElement* labelElement = labelElementContainer(); if (labelElement) { HTMLElement* correspondingControl = labelElement->correspondingControl(); if (correspondingControl && correspondingControl->renderer()) { AccessibilityObject* controlObject = axObjectCache()->getOrCreate(correspondingControl->renderer()); if (controlObject->isCheckboxOrRadio()) return true; } } AccessibilityRole ariaRole = ariaRoleAttribute(); if (ariaRole == TextAreaRole || ariaRole == StaticTextRole) { String ariaText = text(); return ariaText.isNull() || ariaText.isEmpty(); } // NOTE: BRs always have text boxes now, so the text box check here can be removed if (m_renderer->isText()) { // static text beneath MenuItems and MenuButtons are just reported along with the menu item, so it's ignored on an individual level if (parentObjectUnignored()->ariaRoleAttribute() == MenuItemRole || parentObjectUnignored()->ariaRoleAttribute() == MenuButtonRole) return true; return m_renderer->isBR() || !toRenderText(m_renderer)->firstTextBox(); } if (isHeading()) return false; if (isLink()) return false; // all controls are accessible if (isControl()) return false; // don't ignore labels, because they serve as TitleUIElements Node* node = m_renderer->node(); if (node && node->hasTagName(labelTag)) return false; if (m_renderer->isBlockFlow() && m_renderer->childrenInline()) return !toRenderBlock(m_renderer)->firstLineBox() && !mouseButtonListener(); // ignore images seemingly used as spacers if (isImage()) { if (node && node->isElementNode()) { Element* elt = static_cast<Element*>(node); const AtomicString& alt = elt->getAttribute(altAttr); // don't ignore an image that has an alt tag if (!alt.isEmpty()) return false; // informal standard is to ignore images with zero-length alt strings if (!alt.isNull()) return true; } // check for one-dimensional image RenderImage* image = toRenderImage(m_renderer); if (image->height() <= 1 || image->width() <= 1) return true; // check whether rendered image was stretched from one-dimensional file image if (isNativeImage()) { if (image->cachedImage()) { IntSize imageSize = image->cachedImage()->imageSize(image->view()->zoomFactor()); return imageSize.height() <= 1 || imageSize.width() <= 1; } } return false; } if (ariaRole != UnknownRole)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -