📄 accessibilityrenderobject.cpp
字号:
viewRect.intersect(contentRect); return viewRect.isEmpty();}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()->getOrCreate(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; if (node->hasTagName(h2Tag)) return 2; if (node->hasTagName(h3Tag)) return 3; if (node->hasTagName(h4Tag)) return 4; if (node->hasTagName(h5Tag)) return 5; if (node->hasTagName(h6Tag)) return 6; return 0;}bool AccessibilityRenderObject::isHeading() const{ return roleValue() == HeadingRole;} bool AccessibilityRenderObject::isLink() const{ return roleValue() == WebCoreLinkRole;} bool AccessibilityRenderObject::isControl() const{ if (!m_renderer) return false; Node* node = m_renderer->node(); return node && ((node->isElementNode() && static_cast<Element*>(node)->isFormControlElement()) || AccessibilityObject::isARIAControl(ariaRoleAttribute()));}bool AccessibilityRenderObject::isFieldset() const{ if (!m_renderer) return false; return m_renderer->isFieldset();} bool AccessibilityRenderObject::isGroup() const{ return roleValue() == GroupRole;} const AtomicString& AccessibilityRenderObject::getAttribute(const QualifiedName& attribute) const{ Node* node = m_renderer->node(); if (!node) return nullAtom; if (!node->isElementNode()) return nullAtom; Element* element = static_cast<Element*>(node); return element->getAttribute(attribute);}Element* AccessibilityRenderObject::anchorElement() const{ if (!m_renderer) return 0; AXObjectCache* cache = axObjectCache(); RenderObject* currRenderer; // Search up the render tree for a RenderObject with a DOM node. Defer to an earlier continuation, though. for (currRenderer = m_renderer; currRenderer && !currRenderer->node(); currRenderer = currRenderer->parent()) { if (currRenderer->isRenderBlock()) { RenderInline* continuation = toRenderBlock(currRenderer)->inlineContinuation(); if (continuation) return cache->getOrCreate(continuation)->anchorElement(); } } // bail if none found if (!currRenderer) return 0; // search up the DOM tree for an anchor element // NOTE: this assumes that any non-image with an anchor is an HTMLAnchorElement Node* node = currRenderer->node(); for ( ; node; node = node->parentNode()) { if (node->hasTagName(aTag) || (node->renderer() && cache->getOrCreate(node->renderer())->isAnchor())) return static_cast<Element*>(node); } return 0;}Element* AccessibilityRenderObject::actionElement() const{ if (!m_renderer) return 0; Node* node = m_renderer->node(); if (node) { if (node->hasTagName(inputTag)) { HTMLInputElement* input = static_cast<HTMLInputElement*>(node); if (!input->disabled() && (isCheckboxOrRadio() || input->isTextButton())) return input; } else if (node->hasTagName(buttonTag)) return static_cast<Element*>(node); } if (isFileUploadButton()) return static_cast<Element*>(m_renderer->node()); if (AccessibilityObject::isARIAInput(ariaRoleAttribute())) return static_cast<Element*>(m_renderer->node()); if (isImageButton()) return static_cast<Element*>(m_renderer->node()); if (m_renderer->isMenuList()) return static_cast<RenderMenuList*>(m_renderer)->selectElement(); Element* elt = anchorElement(); if (!elt) elt = mouseButtonListener(); return elt;}Element* AccessibilityRenderObject::mouseButtonListener() const{ Node* node = m_renderer->node(); if (!node) return 0; if (!node->isElementNode()) return 0; // FIXME: Do the continuation search like anchorElement does for (Element* element = static_cast<Element*>(node); element; element = element->parentElement()) { if (element->inlineEventListenerForType(eventNames().clickEvent) || element->inlineEventListenerForType(eventNames().mousedownEvent) || element->inlineEventListenerForType(eventNames().mouseupEvent)) return element; } return 0;}static Element* siblingWithAriaRole(String role, Node* node){ Node* sibling = node->parent()->firstChild(); while (sibling) { if (sibling->isElementNode()) { String siblingAriaRole = static_cast<Element*>(sibling)->getAttribute(roleAttr).string(); if (equalIgnoringCase(siblingAriaRole, role)) return static_cast<Element*>(sibling); } sibling = sibling->nextSibling(); } return 0;}Element* AccessibilityRenderObject::menuElementForMenuButton() const{ if (ariaRoleAttribute() != MenuButtonRole) return 0; return siblingWithAriaRole("menu", renderer()->node());}AccessibilityObject* AccessibilityRenderObject::menuForMenuButton() const{ Element* menu = menuElementForMenuButton(); if (menu && menu->renderer()) return m_renderer->document()->axObjectCache()->getOrCreate(menu->renderer()); return 0;}Element* AccessibilityRenderObject::menuItemElementForMenu() const{ if (ariaRoleAttribute() != MenuRole) return 0; return siblingWithAriaRole("menuitem", renderer()->node()); }AccessibilityObject* AccessibilityRenderObject::menuButtonForMenu() const{ Element* menuItem = menuItemElementForMenu(); if (menuItem && menuItem->renderer()) { // ARIA just has generic menu items. AppKit needs to know if this is a top level items like MenuBarButton or MenuBarItem AccessibilityObject* menuItemAX = m_renderer->document()->axObjectCache()->getOrCreate(menuItem->renderer()); if (menuItemAX->isMenuButton()) return menuItemAX; } return 0;}String AccessibilityRenderObject::helpText() const{ if (!m_renderer) return String(); for (RenderObject* curr = m_renderer; curr; curr = curr->parent()) { if (curr->node() && curr->node()->isHTMLElement()) { const AtomicString& summary = static_cast<Element*>(curr->node())->getAttribute(summaryAttr); if (!summary.isEmpty()) return summary; const AtomicString& title = static_cast<Element*>(curr->node())->getAttribute(titleAttr); if (!title.isEmpty()) return title; } } return String();}String AccessibilityRenderObject::textUnderElement() const{ if (!m_renderer) return String(); if (isFileUploadButton()) { RenderFileUploadControl* uploadControl = static_cast<RenderFileUploadControl*>(m_renderer); return uploadControl->buttonValue(); } Node* node = m_renderer->node(); if (node) { if (Frame* frame = node->document()->frame()) { // catch stale WebCoreAXObject (see <rdar://problem/3960196>) if (frame->document() != node->document()) return String(); return plainText(rangeOfContents(node).get()); } } // return the null string for anonymous text because it is non-trivial to get // the actual text and, so far, that is not needed return String();}bool AccessibilityRenderObject::hasIntValue() const{ if (isHeading()) return true; if (m_renderer->node() && isCheckboxOrRadio()) return true; return false;}int AccessibilityRenderObject::intValue() const{ if (!m_renderer || isPasswordField()) return 0; if (isHeading()) return headingLevel(m_renderer->node()); Node* node = m_renderer->node(); 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 static_cast<HTMLInputElement*>(node)->checked();}float AccessibilityRenderObject::valueForRange() const{ if (!isProgressIndicator() && !isSlider()) return 0.0f; return getAttribute(aria_valuenowAttr).toFloat();}float AccessibilityRenderObject::maxValueForRange() const{ if (!isProgressIndicator() && !isSlider()) return 0.0f; return getAttribute(aria_valuemaxAttr).toFloat();}float AccessibilityRenderObject::minValueForRange() const{ if (!isProgressIndicator() && !isSlider()) return 0.0f; return getAttribute(aria_valueminAttr).toFloat();}String AccessibilityRenderObject::stringValue() const{ if (!m_renderer || isPasswordField()) return String(); if (m_renderer->isText()) return textUnderElement(); if (m_renderer->isMenuList()) return static_cast<RenderMenuList*>(m_renderer)->text(); if (m_renderer->isListMarker()) return static_cast<RenderListMarker*>(m_renderer)->text(); if (isWebArea()) { if (m_renderer->document()->frame()) return String(); // FIXME: should use startOfDocument and endOfDocument (or rangeForDocument?) here VisiblePosition startVisiblePosition = m_renderer->positionForCoordinates(0, 0); VisiblePosition endVisiblePosition = m_renderer->positionForCoordinates(INT_MAX, INT_MAX); if (startVisiblePosition.isNull() || endVisiblePosition.isNull()) return String(); return plainText(makeRange(startVisiblePosition, endVisiblePosition).get()); } if (isTextControl()) return text(); if (isFileUploadButton()) { RenderFileUploadControl* uploadControl = static_cast<RenderFileUploadControl*>(m_renderer); return uploadControl->fileTextValue(); } // FIXME: We might need to implement a value here for more types // FIXME: It would be better not to advertise a value at all for the types for which we don't implement one; // this would require subclassing or making accessibilityAttributeNames do something other than return a // single static array. return String();}// This function implements the ARIA accessible name as described by the Mozilla// ARIA Implementer's Guide.static String accessibleNameForNode(Node* node){ if (node->isTextNode()) return static_cast<Text*>(node)->data(); if (node->hasTagName(inputTag)) return static_cast<HTMLInputElement*>(node)->value(); if (node->isHTMLElement()) { const AtomicString& alt = static_cast<HTMLElement*>(node)->getAttribute(altAttr); if (!alt.isEmpty()) return alt; } return String();}String AccessibilityRenderObject::ariaAccessiblityName(const String& s) const{ Document* document = m_renderer->document(); if (!document) return String(); String idList = s; idList.replace('\n', ' '); Vector<String> idVector; idList.split(' ', idVector); Vector<UChar> ariaLabel; unsigned size = idVector.size(); for (unsigned i = 0; i < size; ++i) { String idName = idVector[i]; Element* idElement = document->getElementById(idName); if (idElement) { String nameFragment = accessibleNameForNode(idElement); ariaLabel.append(nameFragment.characters(), nameFragment.length()); for (Node* n = idElement->firstChild(); n; n = n->traverseNextNode(idElement->nextSibling())) { nameFragment = accessibleNameForNode(n); ariaLabel.append(nameFragment.characters(), nameFragment.length()); } ariaLabel.append(' '); } } return String::adopt(ariaLabel);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -