Chromium Code Reviews| Index: Source/modules/accessibility/AXLayoutObject.cpp |
| diff --git a/Source/modules/accessibility/AXLayoutObject.cpp b/Source/modules/accessibility/AXLayoutObject.cpp |
| index 1d0564acb34df125560efc3e34a5c7654acad84e..b26b6cbc5a8822358ca75685bbc9f7228f04786e 100644 |
| --- a/Source/modules/accessibility/AXLayoutObject.cpp |
| +++ b/Source/modules/accessibility/AXLayoutObject.cpp |
| @@ -1834,46 +1834,192 @@ Widget* AXLayoutObject::widgetForAttachmentView() const |
| } |
| // |
| -// Selected text. |
| +// Get the current selection. |
| // |
| -AXObject::PlainTextRange AXLayoutObject::selectedTextRange() const |
| +AXObject::AXRange AXLayoutObject::selection() const |
| { |
| - if (!isTextControl()) |
| - return PlainTextRange(); |
| + AXRange textSelection = textControlSelection(); |
| + if (!textSelection.isNull()) |
| + return textSelection; |
| + |
| + if (!layoutObject() || !layoutObject()->frame()) |
| + return AXRange(); |
| + |
| + VisibleSelection selection = layoutObject()->frame()->selection().selection(); |
| + RefPtrWillBeRawPtr<Range> selectionRange = selection.firstRange(); |
| + if (!selectionRange) |
| + return AXRange(); |
| + |
| + Node* anchorNode = selectionRange->startContainer(); |
| + ASSERT(anchorNode); |
| + |
| + RefPtrWillBeRawPtr<AXObject> anchorObject = nullptr; |
| + // Find the closest node that has a corresponding AXObject. |
| + while (anchorObject = axObjectCache()->get(anchorNode) |
|
dmazzoni
2015/06/24 00:11:01
This loop doesn't seem right because if axObjectCa
|
| + && (!anchorObject->isAXLayoutObject() || !anchorObject->node() |
| + || anchorObject->accessibilityIsIgnored())) { |
|
dmazzoni
2015/06/24 00:11:01
Blink has no 80 column line limit - you should wra
|
| + if (anchorNode->nextSibling()) |
| + anchorNode = anchorNode->nextSibling(); |
| + else |
| + anchorNode = anchorNode->parentNode(); |
| + } |
| + |
| + Node* focusNode = selectionRange->endContainer(); |
| + ASSERT(focusNode); |
| - if (m_layoutObject->isTextControl()) { |
| - HTMLTextFormControlElement* textControl = toLayoutTextControl(m_layoutObject)->textFormControlElement(); |
| - return PlainTextRange(textControl->selectionStart(), textControl->selectionEnd() - textControl->selectionStart()); |
| + RefPtrWillBeRawPtr<AXObject> focusObject = nullptr; |
| + while (focusObject = axObjectCache()->get(focusNode) |
| + && (!focusObject->isAXLayoutObject() || !focusObject->node() |
| + || focusObject->accessibilityIsIgnored())) { |
| + if (focusNode->previousSibling()) |
| + focusNode = focusNode->previousSibling(); |
| + else |
| + focusNode = focusNode->parentNode(); |
| } |
| - return visibleSelectionUnderObject(); |
| + if (!anchorObject || !focusObject) |
| + return AXRange(); |
| + |
| + int anchorOffset = selectionRange->startOffset(); |
| + ASSERT(anchorOffset >= 0); |
| + int focusOffset = selectionRange->endOffset(); |
| + ASSERT(focusOffset >= 0); |
| + |
| + return AXRange( |
| + anchorObject, anchorOffset, |
| + focusObject, focusOffset); |
| } |
| -VisibleSelection AXLayoutObject::selection() const |
| +// Gets only the start and end offsets of the selection computed using the |
| +// current object as the starting point. Returns a null selection if there is |
| +// no selection in the subtree rooted at this object. |
| +AXObject::AXRange AXLayoutObject::selectionUnderObject() const |
| { |
| - return m_layoutObject->frame()->selection().selection(); |
| + AXRange textSelection = textControlSelection(); |
| + if (!textSelection.isNull()) |
| + return textSelection; |
| + |
| + if (!layoutObject() || !layoutObject()->frame()) |
| + return AXRange(); |
| + |
| + VisibleSelection selection = layoutObject()->frame()->selection().selection(); |
| + RefPtrWillBeRawPtr<Range> selectionRange = selection.firstRange(); |
| + if (!selectionRange |
| + || selectionRange->compareNode(node(), IGNORE_EXCEPTION) != NODE_BEFORE_AND_AFTER) |
| + return AXRange(); |
| + |
| + int start = indexForVisiblePosition(selection.visibleStart()); |
| + ASSERT(start >= 0); |
| + int end = indexForVisiblePosition(selection.visibleEnd()); |
| + ASSERT(end >= 0); |
| + |
| + return AXRange(start, end); |
| +} |
| + |
| +AXObject::AXRange AXLayoutObject::textControlSelection() const |
| +{ |
| + if (!layoutObject()) |
| + return AXRange(); |
| + |
| + Node* node = isHTMLTextFormControlElement(node()) ? node() : |
| + document()->focusedElement(); |
| + |
| + if (!node) |
| + return AXRange(); |
| + |
| + AXObject axObject = axObjectCache()->get(node); |
| + if (!axObject) |
| + return AXRange(); |
| + |
| + HTMLTextFormControlElement* textControl = toHTMLTextFormControlElement(node); |
| + int start = textControl->selectionStart(); |
| + int end = textControl->selectionEnd(); |
| + return AXRange(axObject, start, axObject, end); |
| +} |
| + |
| +int AXLayoutObject::indexForVisiblePosition(const VisiblePosition& position) const |
| +{ |
| + if (layoutObject() && layoutObject()->isTextControl()) { |
| + HTMLTextFormControlElement* textControl = toLayoutTextControl( |
| + layoutObject())->textFormControlElement(); |
| + return textControl->indexForVisiblePosition(position); |
| + } |
| + |
| + if (!node()) |
| + return 0; |
| + |
| + Position indexPosition = position.deepEquivalent(); |
| + if (indexPosition.isNull()) |
| + return 0; |
| + |
| + RefPtrWillBeRawPtr<Range> range = Range::create(*document()); |
| + range->setStart(node(), 0, IGNORE_EXCEPTION); |
| + range->setEnd(indexPosition, IGNORE_EXCEPTION); |
| + |
| + return TextIterator::rangeLength(range->startPosition(), range->endPosition()); |
| } |
| // |
| // Modify or take an action on an object. |
| // |
| -void AXLayoutObject::setSelectedTextRange(const PlainTextRange& range) |
| +void AXLayoutObject::setSelection(const AXRange& selection) |
| { |
| - if (m_layoutObject->isTextControl()) { |
| - HTMLTextFormControlElement* textControl = toLayoutTextControl(m_layoutObject)->textFormControlElement(); |
| - textControl->setSelectionRange(range.start, range.start + range.length, SelectionHasNoDirection, NotDispatchSelectEvent); |
| + if (!layoutObject() || selection.isNull()) |
| + return; |
| + |
| + if (selection.anchorObject |
| + && (selection.anchorObject->isDetached() |
| + || !selection.anchorObject->isAXLayoutObject() |
| + || selection.anchorObject->layoutObject()->frame() != layoutObject()->frame() |
| + || selection.anchorObject->axObjectCache() != axObjectCache())) |
| + return; |
| + |
| + if (selection.focusObject |
| + && (selection.focusObject->isDetached() |
| + || !selection.focusObject->isAXLayoutObject() |
| + || selection.focusObject->layoutObject()->frame() != layoutObject()->frame() |
| + || selection.focusObject->axObjectCache() != axObjectCache())) |
| + return; |
| + |
| + AXObject* anchorObject = selection.anchorObject != null ? |
| + selection.anchorObject.get() : this; |
| + AXObject* focusObject = selection.focusObject != null ? |
| + selection.focusObject.get() : this; |
| + |
| + if (anchorObject == this && anchorObject == focusObject |
| + && layoutObject()->isTextControl()) { |
| + HTMLTextFormControlElement* textControl = toLayoutTextControl( |
| + layoutObject())->textFormControlElement(); |
| + textControl->setSelectionRange(selection.anchorOffset, selection.focusOffset, |
| + SelectionHasNoDirection, NotDispatchSelectEvent); |
| return; |
| } |
| - Document& document = m_layoutObject->document(); |
| - LocalFrame* frame = document.frame(); |
| + Node* anchorNode = nullptr; |
| + while (anchorObject && !anchorNode) { |
| + anchorNode = anchorObject->node(); |
| + anchorObject = anchorObject->parentObject(); |
| + } |
| + |
| + Node* focusNode = nullptr; |
| + while (focusObject && !focusNode) { |
| + focusNode = focusObject->node(); |
| + focusObject = focusObject->parentObject(); |
| + } |
| + |
| + if (!anchorNode || !focusNode) |
| + return; |
| + |
| + LocalFrame* frame = layoutObject()->frame(); |
| if (!frame) |
| return; |
| - Node* node = m_layoutObject->node(); |
| - frame->selection().setSelection(VisibleSelection(Position(node, range.start, Position::PositionIsOffsetInAnchor), |
| - Position(node, range.start + range.length, Position::PositionIsOffsetInAnchor), DOWNSTREAM)); |
| + |
| + frame->selection().setSelection(VisibleSelection(Position(anchorNode, |
| + selection.anchorOffset, Position::PositionIsOffsetInAnchor), |
| + Position(focusNode, selection.focusOffset, |
| + Position::PositionIsOffsetInAnchor), DOWNSTREAM)); |
| } |
| void AXLayoutObject::setValue(const String& string) |
| @@ -2008,33 +2154,6 @@ VisiblePosition AXLayoutObject::visiblePositionForIndex(int index) const |
| return VisiblePosition(Position(it.currentContainer(), it.endOffset(), Position::PositionIsOffsetInAnchor), UPSTREAM); |
| } |
| -int AXLayoutObject::indexForVisiblePosition(const VisiblePosition& pos) const |
| -{ |
| - if (m_layoutObject->isTextControl()) { |
| - HTMLTextFormControlElement* textControl = toLayoutTextControl(m_layoutObject)->textFormControlElement(); |
| - return textControl->indexForVisiblePosition(pos); |
| - } |
| - |
| - if (!isTextControl()) |
| - return 0; |
| - |
| - Node* node = m_layoutObject->node(); |
| - if (!node) |
| - return 0; |
| - |
| - Position indexPosition = pos.deepEquivalent(); |
| - if (indexPosition.isNull() |
| - || (highestEditableRoot(indexPosition) != node |
| - && highestEditableRoot(indexPosition, HasEditableAXRole) != node)) |
| - return 0; |
| - |
| - RefPtrWillBeRawPtr<Range> range = Range::create(m_layoutObject->document()); |
| - range->setStart(node, 0, IGNORE_EXCEPTION); |
| - range->setEnd(indexPosition, IGNORE_EXCEPTION); |
| - |
| - return TextIterator::rangeLength(range->startPosition(), range->endPosition()); |
| -} |
| - |
| void AXLayoutObject::addInlineTextBoxChildren(bool force) |
| { |
| Settings* settings = document()->settings(); |
| @@ -2116,23 +2235,6 @@ void AXLayoutObject::ariaListboxSelectedChildren(AccessibilityChildrenVector& re |
| } |
| } |
| -AXObject::PlainTextRange AXLayoutObject::visibleSelectionUnderObject() const |
| -{ |
| - Node* node = m_layoutObject->node(); |
| - if (!node) |
| - return PlainTextRange(); |
| - |
| - VisibleSelection visibleSelection = selection(); |
| - RefPtrWillBeRawPtr<Range> currentSelectionRange = visibleSelection.toNormalizedRange(); |
| - if (!currentSelectionRange || !currentSelectionRange->intersectsNode(node, IGNORE_EXCEPTION)) |
| - return PlainTextRange(); |
| - |
| - int start = indexForVisiblePosition(visibleSelection.visibleStart()); |
| - int end = indexForVisiblePosition(visibleSelection.visibleEnd()); |
| - |
| - return PlainTextRange(start, end - start); |
| -} |
| - |
| bool AXLayoutObject::nodeIsTextControl(const Node* node) const |
| { |
| if (!node) |