📄 accessibilityrenderobject.cpp
字号:
if (isNativeTextControl()) return toRenderTextControl(m_renderer)->visiblePositionForIndex(index); if (!isTextControl() && !m_renderer->isText()) return VisiblePosition(); Node* node = m_renderer->node(); if (!node) return VisiblePosition(); if (index <= 0) return VisiblePosition(node, 0, DOWNSTREAM); ExceptionCode ec = 0; RefPtr<Range> range = Range::create(m_renderer->document()); range->selectNodeContents(node, ec); CharacterIterator it(range.get()); it.advance(index - 1); return VisiblePosition(it.range()->endContainer(ec), it.range()->endOffset(ec), UPSTREAM);} int AccessibilityRenderObject::indexForVisiblePosition(const VisiblePosition& pos) const{ if (isNativeTextControl()) return toRenderTextControl(m_renderer)->indexForVisiblePosition(pos); if (!isTextControl()) return 0; Node* node = m_renderer->node(); if (!node) return 0; Position indexPosition = pos.deepEquivalent(); if (!indexPosition.node() || indexPosition.node()->rootEditableElement() != node) return 0; ExceptionCode ec = 0; RefPtr<Range> range = Range::create(m_renderer->document()); range->setStart(node, 0, ec); range->setEnd(indexPosition.node(), indexPosition.offset(), ec); return TextIterator::rangeLength(range.get());}IntRect AccessibilityRenderObject::boundsForVisiblePositionRange(const VisiblePositionRange& visiblePositionRange) const{ if (visiblePositionRange.isNull()) return IntRect(); // Create a mutable VisiblePositionRange. VisiblePositionRange range(visiblePositionRange); IntRect rect1 = range.start.absoluteCaretBounds(); IntRect rect2 = range.end.absoluteCaretBounds(); // readjust for position at the edge of a line. This is to exclude line rect that doesn't need to be accounted in the range bounds if (rect2.y() != rect1.y()) { VisiblePosition endOfFirstLine = endOfLine(range.start); if (range.start == endOfFirstLine) { range.start.setAffinity(DOWNSTREAM); rect1 = range.start.absoluteCaretBounds(); } if (range.end == endOfFirstLine) { range.end.setAffinity(UPSTREAM); rect2 = range.end.absoluteCaretBounds(); } } IntRect ourrect = rect1; ourrect.unite(rect2); // if the rectangle spans lines and contains multiple text chars, use the range's bounding box intead if (rect1.bottom() != rect2.bottom()) { RefPtr<Range> dataRange = makeRange(range.start, range.end); IntRect boundingBox = dataRange->boundingBox(); String rangeString = plainText(dataRange.get()); if (rangeString.length() > 1 && !boundingBox.isEmpty()) ourrect = boundingBox; } #if PLATFORM(MAC) return m_renderer->document()->view()->contentsToScreen(ourrect);#else return ourrect;#endif} void AccessibilityRenderObject::setSelectedVisiblePositionRange(const VisiblePositionRange& range) const{ if (range.start.isNull() || range.end.isNull()) return; // make selection and tell the document to use it. if it's zero length, then move to that position if (range.start == range.end) { m_renderer->document()->frame()->selection()->moveTo(range.start, true); } else { VisibleSelection newSelection = VisibleSelection(range.start, range.end); m_renderer->document()->frame()->selection()->setSelection(newSelection); } }VisiblePosition AccessibilityRenderObject::visiblePositionForPoint(const IntPoint& point) const{ // convert absolute point to view coordinates FrameView* frameView = m_renderer->document()->topDocument()->renderer()->view()->frameView(); RenderView* renderView = topRenderer(); Node* innerNode = 0; // locate the node containing the point IntPoint pointResult; while (1) { IntPoint ourpoint;#if PLATFORM(MAC) ourpoint = frameView->screenToContents(point);#else ourpoint = point;#endif HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active); HitTestResult result(ourpoint); renderView->layer()->hitTest(request, result); innerNode = result.innerNode(); if (!innerNode || !innerNode->renderer()) return VisiblePosition(); pointResult = result.localPoint(); // done if hit something other than a widget RenderObject* renderer = innerNode->renderer(); if (!renderer->isWidget()) break; // descend into widget (FRAME, IFRAME, OBJECT...) Widget* widget = static_cast<RenderWidget*>(renderer)->widget(); if (!widget || !widget->isFrameView()) break; Frame* frame = static_cast<FrameView*>(widget)->frame(); if (!frame) break; renderView = frame->document()->renderView(); frameView = static_cast<FrameView*>(widget); } return innerNode->renderer()->positionForPoint(pointResult);}// NOTE: Consider providing this utility method as AX APIVisiblePosition AccessibilityRenderObject::visiblePositionForIndex(unsigned indexValue, bool lastIndexOK) const{ if (!isTextControl()) return VisiblePosition(); // lastIndexOK specifies whether the position after the last character is acceptable if (indexValue >= text().length()) { if (!lastIndexOK || indexValue > text().length()) return VisiblePosition(); } VisiblePosition position = visiblePositionForIndex(indexValue); position.setAffinity(DOWNSTREAM); return position;}// NOTE: Consider providing this utility method as AX APIint AccessibilityRenderObject::index(const VisiblePosition& position) const{ if (!isTextControl()) return -1; Node* node = position.deepEquivalent().node(); if (!node) return -1; for (RenderObject* renderer = node->renderer(); renderer && renderer->node(); renderer = renderer->parent()) { if (renderer == m_renderer) return indexForVisiblePosition(position); } return -1;}// Given a line number, the range of characters of the text associated with this accessibility// object that contains the line number.PlainTextRange AccessibilityRenderObject::doAXRangeForLine(unsigned lineNumber) const{ if (!isTextControl()) return PlainTextRange(); // iterate to the specified line VisiblePosition visiblePos = visiblePositionForIndex(0); VisiblePosition savedVisiblePos; for (unsigned lineCount = lineNumber; lineCount != 0; lineCount -= 1) { savedVisiblePos = visiblePos; visiblePos = nextLinePosition(visiblePos, 0); if (visiblePos.isNull() || visiblePos == savedVisiblePos) return PlainTextRange(); } // make a caret selection for the marker position, then extend it to the line // NOTE: ignores results of selection.modify because it returns false when // starting at an empty line. The resulting selection in that case // will be a caret at visiblePos. SelectionController selection; selection.setSelection(VisibleSelection(visiblePos)); selection.modify(SelectionController::EXTEND, SelectionController::LEFT, LineBoundary); selection.modify(SelectionController::EXTEND, SelectionController::RIGHT, LineBoundary); // calculate the indices for the selection start and end VisiblePosition startPosition = selection.selection().visibleStart(); VisiblePosition endPosition = selection.selection().visibleEnd(); int index1 = indexForVisiblePosition(startPosition); int index2 = indexForVisiblePosition(endPosition); // add one to the end index for a line break not caused by soft line wrap (to match AppKit) if (endPosition.affinity() == DOWNSTREAM && endPosition.next().isNotNull()) index2 += 1; // return nil rather than an zero-length range (to match AppKit) if (index1 == index2) return PlainTextRange(); return PlainTextRange(index1, index2 - index1);}// The composed character range in the text associated with this accessibility object that// is specified by the given index value. This parameterized attribute returns the complete// range of characters (including surrogate pairs of multi-byte glyphs) at the given index.PlainTextRange AccessibilityRenderObject::doAXRangeForIndex(unsigned index) const{ if (!isTextControl()) return PlainTextRange(); String elementText = text(); if (!elementText.length() || index > elementText.length() - 1) return PlainTextRange(); return PlainTextRange(index, 1);}// A substring of the text associated with this accessibility object that is// specified by the given character range.String AccessibilityRenderObject::doAXStringForRange(const PlainTextRange& range) const{ if (isPasswordField()) return String(); if (range.length == 0) return ""; if (!isTextControl()) return String(); String elementText = text(); if (range.start + range.length > elementText.length()) return String(); return elementText.substring(range.start, range.length);}// The bounding rectangle of the text associated with this accessibility object that is// specified by the given range. This is the bounding rectangle a sighted user would see// on the display screen, in pixels.IntRect AccessibilityRenderObject::doAXBoundsForRange(const PlainTextRange& range) const{ if (isTextControl()) return boundsForVisiblePositionRange(visiblePositionRangeForRange(range)); return IntRect();}AccessibilityObject* AccessibilityRenderObject::doAccessibilityHitTest(const IntPoint& point) const{ if (!m_renderer || !m_renderer->hasLayer()) return 0; RenderLayer* layer = toRenderBox(m_renderer)->layer(); HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active); HitTestResult hitTestResult = HitTestResult(point); layer->hitTest(request, hitTestResult); if (!hitTestResult.innerNode()) return 0; Node* node = hitTestResult.innerNode()->shadowAncestorNode(); RenderObject* obj = node->renderer(); if (!obj) return 0; AccessibilityObject *result = obj->document()->axObjectCache()->getOrCreate(obj); if (obj->isListBox()) return static_cast<AccessibilityListBox*>(result)->doAccessibilityHitTest(point); if (result->accessibilityIsIgnored()) result = result->parentObjectUnignored(); return result;}AccessibilityObject* AccessibilityRenderObject::focusedUIElement() const{ // get the focused node in the page Page* page = m_renderer->document()->page(); if (!page) return 0; Document* focusedDocument = page->focusController()->focusedOrMainFrame()->document(); Node* focusedNode = focusedDocument->focusedNode(); if (!focusedNode) focusedNode = focusedDocument; RenderObject* focusedNodeRenderer = focusedNode->renderer(); if (!focusedNodeRenderer) return 0; AccessibilityObject* obj = focusedNodeRenderer->document()->axObjectCache()->getOrCreate(focusedNodeRenderer); if (obj->shouldFocusActiveDescendant()) { if (AccessibilityObject* descendant = obj->activeDescendant()) obj = descendant; } // the HTML element, for example, is focusable but has an AX object that is ignored if (obj->accessibilityIsIgnored()) obj = obj->parentObjectUnignored(); return obj;}bool AccessibilityRenderObject::shouldFocusActiveDescendant() const{ switch (ariaRoleAttribute()) { case GroupRole: case ComboBoxRole: case ListBoxRole: case MenuRole: case MenuBarRole: case RadioGroupRole: case RowRole: case PopUpButtonRole: case ProgressIndicatorRole: case ToolbarRole: case OutlineRole: /* FIXME: replace these with actual roles when they are added to AccessibilityRole composite alert alertdialog grid status timer tree */ return true; default: return false; }}AccessibilityObject* AccessibilityRenderObject::activeDescendant() const{ if (renderer()->node() && !renderer()->node()->isElementNode()) return 0; Element* element = static_cast<Element*>(renderer()->node()); String activeDescendantAttrStr = element->getAttribute(aria_activedescendantAttr).string(); if (activeDescendantAttrStr.isNull() || activeDescendantAttrStr.isEmpty()) return 0; Element* target = renderer()->document()->getElementById(activeDescendantAttrStr); if (!target) return 0; AccessibilityObject* obj = renderer()->document()->axObjectCache()->getOrCreate(target->renderer()); if (obj->isAccessibilityRenderObject()) // an activedescendant is only useful if it has a renderer, because that's what's needed to post the notification return obj; return 0;}void AccessibilityRenderObject::handleActiveDescendantChanged(){ Element* element = static_cast<Element*>(renderer()->node()); if (!element) return; Document* doc = renderer()->document(); if (!doc->frame()->selection()->isFocusedAndActive() || doc->focusedNode() != element) return; AccessibilityRenderObject* activedescendant = static_cast<AccessibilityRenderObject*>(activeDescendant()); if (activedescendant && shouldFocusActiveDescendant()) doc->axObjectCache()->postNotificationToElement(activedescendant->renderer(), "AXFocusedUIElementChanged");}AccessibilityObject* AccessibilityRenderObject::observableObject() const{ for (RenderObject* renderer = m_renderer; renderer && renderer->node(); renderer = renderer->parent()) { if (renderer->isTextControl()) return renderer->document()->axObjectCache()->getOrCreate(renderer); } return 0;} typedef HashMap<String, AccessibilityRole, CaseFoldingHash> ARIARoleMap;static const ARIARoleMap& createARIARoleMap(){ struct RoleEntry { String
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -