Index: Source/modules/accessibility/AXLayoutObject.cpp |
diff --git a/Source/modules/accessibility/AXLayoutObject.cpp b/Source/modules/accessibility/AXLayoutObject.cpp |
index 1d0564acb34df125560efc3e34a5c7654acad84e..3e9628a0afd5b0d55f3de2e0ef7ea5e92f87f1dc 100644 |
--- a/Source/modules/accessibility/AXLayoutObject.cpp |
+++ b/Source/modules/accessibility/AXLayoutObject.cpp |
@@ -33,6 +33,7 @@ |
#include "core/CSSPropertyNames.h" |
#include "core/InputTypeNames.h" |
#include "core/dom/ElementTraversal.h" |
+#include "core/dom/Range.h" |
#include "core/dom/shadow/ShadowRoot.h" |
#include "core/editing/FrameSelection.h" |
#include "core/editing/RenderedPosition.h" |
@@ -57,6 +58,7 @@ |
#include "core/layout/LayoutListMarker.h" |
#include "core/layout/LayoutMenuList.h" |
#include "core/layout/LayoutPart.h" |
+#include "core/layout/LayoutTextControl.h" |
#include "core/layout/LayoutTextControlSingleLine.h" |
#include "core/layout/LayoutTextFragment.h" |
#include "core/layout/LayoutView.h" |
@@ -1834,46 +1836,199 @@ 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 (anchorNode && !(anchorObject = axObjectCache().getOrCreate(anchorNode)) |
+ && (!anchorObject->isAXLayoutObject() || !anchorObject->node() || anchorObject->accessibilityIsIgnored())) { |
+ if (anchorNode->nextSibling()) |
dmazzoni
2015/06/26 06:14:38
I think you should update anchorOffset here.
To t
|
+ 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 (focusNode && !(focusObject = axObjectCache().getOrCreate(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) != Range::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(); |
+ |
+ LayoutObject* layout = nullptr; |
+ if (layoutObject()->isTextControl()) { |
+ layout = layoutObject(); |
+ } else { |
+ Element* focusedElement = document()->focusedElement(); |
+ if (focusedElement && focusedElement->layoutObject() |
+ && focusedElement->layoutObject()->isTextControl()) |
+ layout = focusedElement->layoutObject(); |
+ } |
+ |
+ if (!layout) |
+ return AXRange(); |
+ |
+ AXObject* axObject = axObjectCache().getOrCreate(layout); |
+ if (!axObject || !axObject->isAXLayoutObject()) |
+ return AXRange(); |
+ |
+ HTMLTextFormControlElement* textControl = toLayoutTextControl( |
+ layout)->textFormControlElement(); |
+ ASSERT(textControl); |
+ 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 |
dmazzoni
2015/06/26 06:14:38
Nit: this could be a helper function like IsValidS
|
+ && (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 ? |
dmazzoni
2015/06/26 06:14:38
You could maybe combine this too - have the helper
|
+ selection.anchorObject.get() : this; |
+ AXObject* focusObject = selection.focusObject ? |
+ selection.focusObject.get() : this; |
+ |
+ if (anchorObject == this && anchorObject == focusObject |
+ && layoutObject()->isTextControl()) { |
+ HTMLTextFormControlElement* textControl = toLayoutTextControl( |
+ layoutObject())->textFormControlElement(); |
dmazzoni
2015/06/26 06:14:38
When the indentation is 4 spaces, I think the line
|
+ textControl->setSelectionRange(selection.anchorOffset, selection.focusOffset, |
+ SelectionHasNoDirection, NotDispatchSelectEvent); |
return; |
} |
- Document& document = m_layoutObject->document(); |
- LocalFrame* frame = document.frame(); |
+ Node* anchorNode = nullptr; |
dmazzoni
2015/06/26 06:14:38
Possibly a helper here, like nearestNodeFromAXObje
|
+ 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 +2163,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 +2244,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) |