Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1474)

Unified Diff: Source/modules/accessibility/AXLayoutObject.cpp

Issue 1185343003: Implements the ability to get and set the caret position and the current selection from anywhere in… (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Addressed more comments from reviewer. Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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)

Powered by Google App Engine
This is Rietveld 408576698