Diff
Modified: trunk/LayoutTests/ChangeLog (195948 => 195949)
--- trunk/LayoutTests/ChangeLog 2016-02-01 03:10:00 UTC (rev 195948)
+++ trunk/LayoutTests/ChangeLog 2016-02-01 04:09:02 UTC (rev 195949)
@@ -1,3 +1,16 @@
+2016-01-31 Doug Russell <[email protected]>
+
+ AX: Add a boundary value to AXTextStateChangeType
+ https://bugs.webkit.org/show_bug.cgi?id=153085
+
+ Reviewed by Darin Adler.
+
+ Post an AT notification when navigation is attempted past
+ an editable element's boundaries.
+
+ * accessibility/mac/selection-boundary-userinfo-expected.txt: Added.
+ * accessibility/mac/selection-boundary-userinfo.html: Added.
+
2016-01-31 Daniel Bates <[email protected]>
CSP: Use the served CSP header for dedicated workers
Added: trunk/LayoutTests/accessibility/mac/selection-boundary-userinfo-expected.txt (0 => 195949)
--- trunk/LayoutTests/accessibility/mac/selection-boundary-userinfo-expected.txt (rev 0)
+++ trunk/LayoutTests/accessibility/mac/selection-boundary-userinfo-expected.txt 2016-02-01 04:09:02 UTC (rev 195949)
@@ -0,0 +1,97 @@
+This tests selection change notifications at text boundaries.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS addedNotification is true
+PASS results[i] is AXTextStateChangeTypeSelectionMove
+PASS results[i] is AXTextSelectionDirectionDiscontiguous
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionPrevious
+PASS results[i] is AXTextSelectionGranularityCharacter
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionNext
+PASS results[i] is AXTextSelectionGranularityCharacter
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionPrevious
+PASS results[i] is AXTextSelectionGranularityLine
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionNext
+PASS results[i] is AXTextSelectionGranularityLine
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionPrevious
+PASS results[i] is AXTextSelectionGranularityWord
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionNext
+PASS results[i] is AXTextSelectionGranularityWord
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionBeginning
+PASS results[i] is AXTextSelectionGranularityLine
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionEnd
+PASS results[i] is AXTextSelectionGranularityLine
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionPrevious
+PASS results[i] is AXTextSelectionGranularityDocument
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionNext
+PASS results[i] is AXTextSelectionGranularityDocument
+PASS results[i] is AXTextStateChangeTypeSelectionMove
+PASS results[i] is AXTextSelectionDirectionDiscontiguous
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionPrevious
+PASS results[i] is AXTextSelectionGranularityCharacter
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionNext
+PASS results[i] is AXTextSelectionGranularityCharacter
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionPrevious
+PASS results[i] is AXTextSelectionGranularityWord
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionNext
+PASS results[i] is AXTextSelectionGranularityWord
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionBeginning
+PASS results[i] is AXTextSelectionGranularityLine
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionEnd
+PASS results[i] is AXTextSelectionGranularityLine
+PASS results[i] is AXTextStateChangeTypeSelectionMove
+PASS results[i] is AXTextSelectionDirectionDiscontiguous
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionPrevious
+PASS results[i] is AXTextSelectionGranularityCharacter
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionNext
+PASS results[i] is AXTextSelectionGranularityCharacter
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionPrevious
+PASS results[i] is AXTextSelectionGranularityLine
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionNext
+PASS results[i] is AXTextSelectionGranularityLine
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionPrevious
+PASS results[i] is AXTextSelectionGranularityWord
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionNext
+PASS results[i] is AXTextSelectionGranularityWord
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionBeginning
+PASS results[i] is AXTextSelectionGranularityLine
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionEnd
+PASS results[i] is AXTextSelectionGranularityLine
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionPrevious
+PASS results[i] is AXTextSelectionGranularityDocument
+PASS results[i] is AXTextStateChangeTypeSelectionBoundary
+PASS results[i] is AXTextSelectionDirectionNext
+PASS results[i] is AXTextSelectionGranularityDocument
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
+
+
+
Added: trunk/LayoutTests/accessibility/mac/selection-boundary-userinfo.html (0 => 195949)
--- trunk/LayoutTests/accessibility/mac/selection-boundary-userinfo.html (rev 0)
+++ trunk/LayoutTests/accessibility/mac/selection-boundary-userinfo.html 2016-02-01 04:09:02 UTC (rev 195949)
@@ -0,0 +1,185 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body id="body">
+
+<div role="textbox" tabindex=0 id="textbox" contenteditable=true>
+ <p><br>
+</div>
+
+<br>
+
+<input type="text" id="input">
+
+<br>
+
+<textarea id="textarea"></textarea>
+
+<script>
+
+ description("This tests selection change notifications at text boundaries.");
+
+ var AXTextStateChangeTypeSelectionMove = 2;
+ var AXTextStateChangeTypeSelectionExtend = AXTextStateChangeTypeSelectionMove + 1;
+ var AXTextStateChangeTypeSelectionBoundary = AXTextStateChangeTypeSelectionExtend + 1;
+
+ var AXTextSelectionDirectionBeginning = 1;
+ var AXTextSelectionDirectionEnd = AXTextSelectionDirectionBeginning + 1;
+ var AXTextSelectionDirectionPrevious = AXTextSelectionDirectionEnd + 1;
+ var AXTextSelectionDirectionNext = AXTextSelectionDirectionPrevious + 1;
+ var AXTextSelectionDirectionDiscontiguous = AXTextSelectionDirectionNext + 1;
+
+ var AXTextSelectionGranularityCharacter = 1;
+ var AXTextSelectionGranularityWord = AXTextSelectionGranularityCharacter + 1;
+ var AXTextSelectionGranularityLine = AXTextSelectionGranularityWord + 1;
+ var AXTextSelectionGranularitySentence = AXTextSelectionGranularityLine + 1;
+ var AXTextSelectionGranularityParagraph = AXTextSelectionGranularitySentence + 1;
+ var AXTextSelectionGranularityDocument = AXTextSelectionGranularityParagraph + 2;
+
+ function move(includeVertical) {
+ // Move by character
+ eventSender.keyDown("leftArrow");
+ eventSender.keyDown("rightArrow");
+ if (includeVertical) {
+ // Move by line
+ eventSender.keyDown("upArrow");
+ eventSender.keyDown("downArrow");
+ }
+ // Move by word
+ eventSender.keyDown("leftArrow", ["altKey"]);
+ eventSender.keyDown("rightArrow", ["altKey"]);
+ // Move to beginning/end of line
+ eventSender.keyDown("leftArrow", ["metaKey"]);
+ eventSender.keyDown("rightArrow", ["metaKey"]);
+ if (includeVertical) {
+ // Move to beginning/end of document
+ eventSender.keyDown("upArrow", ["metaKey"]);
+ eventSender.keyDown("downArrow", ["metaKey"]);
+ }
+ }
+
+ var webArea = 0;
+ var count = 0;
+ var results = [];
+ var i = 0;
+ function notificationCallback(notification, userInfo) {
+ if (notification == "AXSelectedTextChanged") {
+ count++;
+ if (userInfo) {
+ results.push(userInfo["AXTextStateChangeType"]);
+ if (userInfo["AXTextSelectionDirection"])
+ results.push(userInfo["AXTextSelectionDirection"]);
+ if (userInfo["AXTextSelectionGranularity"])
+ results.push(userInfo["AXTextSelectionGranularity"]);
+ }
+ if (count == 29) {
+
+ function shouldBeResults(includeVertical) {
+ // Focusing into the textbox
+ shouldBe("results[i]", "AXTextStateChangeTypeSelectionMove"); i++;
+ shouldBe("results[i]", "AXTextSelectionDirectionDiscontiguous"); i++;
+
+ // Left Arrow
+ shouldBe("results[i]", "AXTextStateChangeTypeSelectionBoundary"); i++;
+ shouldBe("results[i]", "AXTextSelectionDirectionPrevious"); i++;
+ shouldBe("results[i]", "AXTextSelectionGranularityCharacter"); i++;
+
+ // Right Arrow
+ shouldBe("results[i]", "AXTextStateChangeTypeSelectionBoundary"); i++;
+ shouldBe("results[i]", "AXTextSelectionDirectionNext"); i++;
+ shouldBe("results[i]", "AXTextSelectionGranularityCharacter"); i++;
+
+ if (includeVertical) {
+ // Up Arrow
+ shouldBe("results[i]", "AXTextStateChangeTypeSelectionBoundary"); i++;
+ shouldBe("results[i]", "AXTextSelectionDirectionPrevious"); i++;
+ shouldBe("results[i]", "AXTextSelectionGranularityLine"); i++;
+
+ // Down Arrow
+ shouldBe("results[i]", "AXTextStateChangeTypeSelectionBoundary"); i++;
+ shouldBe("results[i]", "AXTextSelectionDirectionNext"); i++;
+ shouldBe("results[i]", "AXTextSelectionGranularityLine"); i++;
+ }
+
+ // Option Left Arrow
+ shouldBe("results[i]", "AXTextStateChangeTypeSelectionBoundary"); i++;
+ shouldBe("results[i]", "AXTextSelectionDirectionPrevious"); i++;
+ shouldBe("results[i]", "AXTextSelectionGranularityWord"); i++;
+
+ // Option Right Arrow
+ shouldBe("results[i]", "AXTextStateChangeTypeSelectionBoundary"); i++;
+ shouldBe("results[i]", "AXTextSelectionDirectionNext"); i++;
+ shouldBe("results[i]", "AXTextSelectionGranularityWord"); i++;
+
+ // Command Left Arrow
+ shouldBe("results[i]", "AXTextStateChangeTypeSelectionBoundary"); i++;
+ shouldBe("results[i]", "AXTextSelectionDirectionBeginning"); i++;
+ shouldBe("results[i]", "AXTextSelectionGranularityLine"); i++;
+
+ // Command Right Arrow
+ shouldBe("results[i]", "AXTextStateChangeTypeSelectionBoundary"); i++;
+ shouldBe("results[i]", "AXTextSelectionDirectionEnd"); i++;
+ shouldBe("results[i]", "AXTextSelectionGranularityLine"); i++;
+
+ if (includeVertical) {
+ // Command Up Arrow
+ shouldBe("results[i]", "AXTextStateChangeTypeSelectionBoundary"); i++;
+ // FIXME: This should be AXTextSelectionDirectionBeginning.
+ shouldBe("results[i]", "AXTextSelectionDirectionPrevious"); i++;
+ shouldBe("results[i]", "AXTextSelectionGranularityDocument"); i++;
+
+ // Command Down Arrow
+ shouldBe("results[i]", "AXTextStateChangeTypeSelectionBoundary"); i++;
+ // FIXME: This should be AXTextSelectionDirectionEnd.
+ shouldBe("results[i]", "AXTextSelectionDirectionNext"); i++;
+ shouldBe("results[i]", "AXTextSelectionGranularityDocument"); i++;
+ }
+ }
+
+ // Content Editable Div
+ shouldBeResults(true);
+
+ // Text Field
+ shouldBeResults(false);
+
+ // Text Area
+ shouldBeResults(true);
+
+ webArea.removeNotificationListener();
+ window.testRunner.notifyDone();
+ }
+ }
+ }
+
+ if (window.accessibilityController) {
+ window.testRunner.waitUntilDone();
+
+ accessibilityController.enableEnhancedAccessibility(true);
+
+ webArea = accessibilityController.rootElement.childAtIndex(0);
+ var addedNotification = webArea.addNotificationListener(notificationCallback);
+ shouldBe("addedNotification", "true");
+
+ textbox = document.getElementById("textbox");
+ textbox.focus();
+
+ move(true);
+
+ textbox = document.getElementById("input");
+ textbox.focus();
+
+ move(false);
+
+ textbox = document.getElementById("textarea");
+ textbox.focus();
+
+ move(true);
+ }
+
+</script>
+
+<script src=""
+</body>
+</html>
Modified: trunk/Source/WebCore/ChangeLog (195948 => 195949)
--- trunk/Source/WebCore/ChangeLog 2016-02-01 03:10:00 UTC (rev 195948)
+++ trunk/Source/WebCore/ChangeLog 2016-02-01 04:09:02 UTC (rev 195949)
@@ -1,3 +1,53 @@
+2016-01-31 Doug Russell <[email protected]>
+
+ AX: Add a boundary value to AXTextStateChangeType
+ https://bugs.webkit.org/show_bug.cgi?id=153085
+
+ Reviewed by Darin Adler.
+
+ Post an AT notification when navigation is attempted past
+ an editable element's boundaries.
+
+ Test: accessibility/mac/selection-boundary-userinfo.html
+
+ * accessibility/AXObjectCache.cpp:
+ (WebCore::AXObjectCache::showIntent):
+ * accessibility/AXTextStateChangeIntent.h:
+ * accessibility/mac/AXObjectCacheMac.mm:
+ (platformChangeTypeForWebCoreChangeType):
+ (WebCore::AXObjectCache::postTextStateChangePlatformNotification):
+ * editing/FrameSelection.cpp:
+ (WebCore::FrameSelection::modifyMovingRight):
+ (WebCore::FrameSelection::modifyMovingForward):
+ (WebCore::FrameSelection::modifyMovingLeft):
+ (WebCore::FrameSelection::modifyMovingBackward):
+ (WebCore::textSelectionWithDirectionAndGranularity):
+ (WebCore::FrameSelection::modify):
+ (WebCore::FrameSelection::modifyExtendingBackward): Deleted.
+ (WebCore::FrameSelection::textSelectionIntent): Deleted.
+ * editing/FrameSelection.h:
+ * editing/VisiblePosition.cpp:
+ (WebCore::VisiblePosition::next):
+ (WebCore::VisiblePosition::previous):
+ (WebCore::VisiblePosition::left):
+ (WebCore::VisiblePosition::right):
+ (WebCore::VisiblePosition::honorEditingBoundaryAtOrBefore):
+ (WebCore::VisiblePosition::honorEditingBoundaryAtOrAfter):
+ (WebCore::VisiblePosition::leftVisuallyDistinctCandidate): Deleted.
+ (WebCore::VisiblePosition::rightVisuallyDistinctCandidate): Deleted.
+ * editing/VisiblePosition.h:
+ * editing/VisibleUnits.cpp:
+ (WebCore::startOfLine):
+ (WebCore::logicalStartOfLine):
+ (WebCore::endOfLine):
+ (WebCore::logicalEndOfLine):
+ (WebCore::leftBoundaryOfLine):
+ (WebCore::rightBoundaryOfLine):
+ (WebCore::inSameLogicalLine): Deleted.
+ (WebCore::endOfEditableContent): Deleted.
+ (WebCore::isEndOfEditableOrNonEditableContent): Deleted.
+ * editing/VisibleUnits.h:
+
2016-01-31 Daniel Bates <[email protected]>
CSP: Use the served CSP header for dedicated workers
Modified: trunk/Source/WebCore/accessibility/AXObjectCache.cpp (195948 => 195949)
--- trunk/Source/WebCore/accessibility/AXObjectCache.cpp 2016-02-01 03:10:00 UTC (rev 195948)
+++ trunk/Source/WebCore/accessibility/AXObjectCache.cpp 2016-02-01 04:09:02 UTC (rev 195949)
@@ -995,6 +995,9 @@
case AXTextStateChangeTypeSelectionExtend:
dataLog("Extend::");
break;
+ case AXTextStateChangeTypeSelectionBoundary:
+ dataLog("Boundary::");
+ break;
}
switch (intent.type) {
case AXTextStateChangeTypeUnknown:
@@ -1029,6 +1032,7 @@
break;
case AXTextStateChangeTypeSelectionMove:
case AXTextStateChangeTypeSelectionExtend:
+ case AXTextStateChangeTypeSelectionBoundary:
switch (intent.selection.direction) {
case AXTextSelectionDirectionUnknown:
dataLog("Unknown::");
Modified: trunk/Source/WebCore/accessibility/AXTextStateChangeIntent.h (195948 => 195949)
--- trunk/Source/WebCore/accessibility/AXTextStateChangeIntent.h 2016-02-01 03:10:00 UTC (rev 195948)
+++ trunk/Source/WebCore/accessibility/AXTextStateChangeIntent.h 2016-02-01 04:09:02 UTC (rev 195949)
@@ -32,7 +32,8 @@
AXTextStateChangeTypeUnknown,
AXTextStateChangeTypeEdit,
AXTextStateChangeTypeSelectionMove,
- AXTextStateChangeTypeSelectionExtend
+ AXTextStateChangeTypeSelectionExtend,
+ AXTextStateChangeTypeSelectionBoundary
};
enum AXTextEditType {
Modified: trunk/Source/WebCore/accessibility/mac/AXObjectCacheMac.mm (195948 => 195949)
--- trunk/Source/WebCore/accessibility/mac/AXObjectCacheMac.mm 2016-02-01 03:10:00 UTC (rev 195948)
+++ trunk/Source/WebCore/accessibility/mac/AXObjectCacheMac.mm 2016-02-01 04:09:02 UTC (rev 195949)
@@ -158,6 +158,8 @@
return kAXTextStateChangeTypeSelectionMove;
case WebCore::AXTextStateChangeTypeSelectionExtend:
return kAXTextStateChangeTypeSelectionExtend;
+ case WebCore::AXTextStateChangeTypeSelectionBoundary:
+ return kAXTextStateChangeTypeSelectionBoundary;
}
}
@@ -365,6 +367,7 @@
switch (intent.type) {
case AXTextStateChangeTypeSelectionMove:
case AXTextStateChangeTypeSelectionExtend:
+ case AXTextStateChangeTypeSelectionBoundary:
[userInfo setObject:@(platformDirectionForWebCoreDirection(intent.selection.direction)) forKey:NSAccessibilityTextSelectionDirection];
switch (intent.selection.direction) {
case AXTextSelectionDirectionUnknown:
@@ -378,13 +381,13 @@
case AXTextSelectionDirectionDiscontiguous:
break;
}
+ if (intent.selection.focusChange)
+ [userInfo setObject:@(intent.selection.focusChange) forKey:NSAccessibilityTextSelectionChangedFocus];
break;
case AXTextStateChangeTypeUnknown:
case AXTextStateChangeTypeEdit:
break;
}
- if (intent.selection.focusChange)
- [userInfo setObject:[NSNumber numberWithBool:intent.selection.focusChange] forKey:NSAccessibilityTextSelectionChangedFocus];
}
if (!selection.isNone()) {
if (id textMarkerRange = [object->wrapper() textMarkerRangeFromVisiblePositions:selection.visibleStart() endPosition:selection.visibleEnd()])
Modified: trunk/Source/WebCore/editing/FrameSelection.cpp (195948 => 195949)
--- trunk/Source/WebCore/editing/FrameSelection.cpp 2016-02-01 03:10:00 UTC (rev 195948)
+++ trunk/Source/WebCore/editing/FrameSelection.cpp 2016-02-01 04:09:02 UTC (rev 195949)
@@ -760,8 +760,10 @@
return pos;
}
-VisiblePosition FrameSelection::modifyMovingRight(TextGranularity granularity)
+VisiblePosition FrameSelection::modifyMovingRight(TextGranularity granularity, bool* reachedBoundary)
{
+ if (reachedBoundary)
+ *reachedBoundary = false;
VisiblePosition pos;
switch (granularity) {
case CharacterGranularity:
@@ -771,11 +773,14 @@
else
pos = VisiblePosition(m_selection.start(), m_selection.affinity());
} else
- pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).right(true);
+ pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).right(true, reachedBoundary);
break;
case WordGranularity: {
bool skipsSpaceWhenMovingRight = m_frame && m_frame->editor().behavior().shouldSkipSpaceWhenMovingRight();
- pos = rightWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()), skipsSpaceWhenMovingRight);
+ VisiblePosition currentPosition(m_selection.extent(), m_selection.affinity());
+ pos = rightWordPosition(currentPosition, skipsSpaceWhenMovingRight);
+ if (reachedBoundary)
+ *reachedBoundary = pos == currentPosition;
break;
}
case SentenceGranularity:
@@ -785,10 +790,10 @@
case ParagraphBoundary:
case DocumentBoundary:
// FIXME: Implement all of the above.
- pos = modifyMovingForward(granularity);
+ pos = modifyMovingForward(granularity, reachedBoundary);
break;
case LineBoundary:
- pos = rightBoundaryOfLine(startForPlatform(), directionOfEnclosingBlock());
+ pos = rightBoundaryOfLine(startForPlatform(), directionOfEnclosingBlock(), reachedBoundary);
break;
case DocumentGranularity:
ASSERT_NOT_REACHED();
@@ -797,8 +802,26 @@
return pos;
}
-VisiblePosition FrameSelection::modifyMovingForward(TextGranularity granularity)
+VisiblePosition FrameSelection::modifyMovingForward(TextGranularity granularity, bool* reachedBoundary)
{
+ if (reachedBoundary)
+ *reachedBoundary = false;
+ VisiblePosition currentPosition;
+ switch (granularity) {
+ case WordGranularity:
+ case SentenceGranularity:
+ currentPosition = VisiblePosition(m_selection.extent(), m_selection.affinity());
+ break;
+ case LineGranularity:
+ case ParagraphGranularity:
+ case SentenceBoundary:
+ case ParagraphBoundary:
+ case DocumentBoundary:
+ currentPosition = endForPlatform();
+ break;
+ default:
+ break;
+ }
VisiblePosition pos;
// FIXME: Stay in editable content for the less common granularities.
switch (granularity) {
@@ -806,45 +829,59 @@
if (isRange())
pos = VisiblePosition(m_selection.end(), m_selection.affinity());
else
- pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).next(CannotCrossEditingBoundary);
+ pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).next(CannotCrossEditingBoundary, reachedBoundary);
break;
case WordGranularity:
- pos = nextWordPositionForPlatform(VisiblePosition(m_selection.extent(), m_selection.affinity()));
+ pos = nextWordPositionForPlatform(currentPosition);
break;
case SentenceGranularity:
- pos = nextSentencePosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
+ pos = nextSentencePosition(currentPosition);
break;
case LineGranularity: {
// down-arrowing from a range selection that ends at the start of a line needs
// to leave the selection at that line start (no need to call nextLinePosition!)
- pos = endForPlatform();
+ pos = currentPosition;
if (!isRange() || !isStartOfLine(pos))
pos = nextLinePosition(pos, lineDirectionPointForBlockDirectionNavigation(START));
break;
}
case ParagraphGranularity:
- pos = nextParagraphPosition(endForPlatform(), lineDirectionPointForBlockDirectionNavigation(START));
+ pos = nextParagraphPosition(currentPosition, lineDirectionPointForBlockDirectionNavigation(START));
break;
case DocumentGranularity:
ASSERT_NOT_REACHED();
break;
case SentenceBoundary:
- pos = endOfSentence(endForPlatform());
+ pos = endOfSentence(currentPosition);
break;
case LineBoundary:
- pos = logicalEndOfLine(endForPlatform());
+ pos = logicalEndOfLine(endForPlatform(), reachedBoundary);
break;
case ParagraphBoundary:
- pos = endOfParagraph(endForPlatform());
+ pos = endOfParagraph(currentPosition);
break;
case DocumentBoundary:
- pos = endForPlatform();
+ pos = currentPosition;
if (isEditablePosition(pos.deepEquivalent()))
pos = endOfEditableContent(pos);
else
pos = endOfDocument(pos);
break;
}
+ switch (granularity) {
+ case WordGranularity:
+ case SentenceGranularity:
+ case LineGranularity:
+ case ParagraphGranularity:
+ case SentenceBoundary:
+ case ParagraphBoundary:
+ case DocumentBoundary:
+ if (reachedBoundary)
+ *reachedBoundary = pos == currentPosition;
+ break;
+ default:
+ break;
+ }
return pos;
}
@@ -944,8 +981,10 @@
return pos;
}
-VisiblePosition FrameSelection::modifyMovingLeft(TextGranularity granularity)
+VisiblePosition FrameSelection::modifyMovingLeft(TextGranularity granularity, bool* reachedBoundary)
{
+ if (reachedBoundary)
+ *reachedBoundary = false;
VisiblePosition pos;
switch (granularity) {
case CharacterGranularity:
@@ -955,11 +994,14 @@
else
pos = VisiblePosition(m_selection.end(), m_selection.affinity());
else
- pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).left(true);
+ pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).left(true, reachedBoundary);
break;
case WordGranularity: {
bool skipsSpaceWhenMovingRight = m_frame && m_frame->editor().behavior().shouldSkipSpaceWhenMovingRight();
- pos = leftWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()), skipsSpaceWhenMovingRight);
+ VisiblePosition currentPosition(m_selection.extent(), m_selection.affinity());
+ pos = leftWordPosition(currentPosition, skipsSpaceWhenMovingRight);
+ if (reachedBoundary)
+ *reachedBoundary = pos == currentPosition;
break;
}
case SentenceGranularity:
@@ -969,10 +1011,10 @@
case ParagraphBoundary:
case DocumentBoundary:
// FIXME: Implement all of the above.
- pos = modifyMovingBackward(granularity);
+ pos = modifyMovingBackward(granularity, reachedBoundary);
break;
case LineBoundary:
- pos = leftBoundaryOfLine(startForPlatform(), directionOfEnclosingBlock());
+ pos = leftBoundaryOfLine(startForPlatform(), directionOfEnclosingBlock(), reachedBoundary);
break;
case DocumentGranularity:
ASSERT_NOT_REACHED();
@@ -981,39 +1023,57 @@
return pos;
}
-VisiblePosition FrameSelection::modifyMovingBackward(TextGranularity granularity)
+VisiblePosition FrameSelection::modifyMovingBackward(TextGranularity granularity, bool* reachedBoundary)
{
+ if (reachedBoundary)
+ *reachedBoundary = false;
+ VisiblePosition currentPosition;
+ switch (granularity) {
+ case WordGranularity:
+ case SentenceGranularity:
+ currentPosition = VisiblePosition(m_selection.extent(), m_selection.affinity());
+ break;
+ case LineGranularity:
+ case ParagraphGranularity:
+ case SentenceBoundary:
+ case ParagraphBoundary:
+ case DocumentBoundary:
+ currentPosition = startForPlatform();
+ break;
+ default:
+ break;
+ }
VisiblePosition pos;
switch (granularity) {
case CharacterGranularity:
if (isRange())
pos = VisiblePosition(m_selection.start(), m_selection.affinity());
else
- pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).previous(CannotCrossEditingBoundary);
+ pos = VisiblePosition(m_selection.extent(), m_selection.affinity()).previous(CannotCrossEditingBoundary, reachedBoundary);
break;
case WordGranularity:
- pos = previousWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
+ pos = previousWordPosition(currentPosition);
break;
case SentenceGranularity:
- pos = previousSentencePosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
+ pos = previousSentencePosition(currentPosition);
break;
case LineGranularity:
- pos = previousLinePosition(startForPlatform(), lineDirectionPointForBlockDirectionNavigation(START));
+ pos = previousLinePosition(currentPosition, lineDirectionPointForBlockDirectionNavigation(START));
break;
case ParagraphGranularity:
- pos = previousParagraphPosition(startForPlatform(), lineDirectionPointForBlockDirectionNavigation(START));
+ pos = previousParagraphPosition(currentPosition, lineDirectionPointForBlockDirectionNavigation(START));
break;
case SentenceBoundary:
- pos = startOfSentence(startForPlatform());
+ pos = startOfSentence(currentPosition);
break;
case LineBoundary:
- pos = logicalStartOfLine(startForPlatform());
+ pos = logicalStartOfLine(startForPlatform(), reachedBoundary);
break;
case ParagraphBoundary:
- pos = startOfParagraph(startForPlatform());
+ pos = startOfParagraph(currentPosition);
break;
case DocumentBoundary:
- pos = startForPlatform();
+ pos = currentPosition;
if (isEditablePosition(pos.deepEquivalent()))
pos = startOfEditableContent(pos);
else
@@ -1023,6 +1083,20 @@
ASSERT_NOT_REACHED();
break;
}
+ switch (granularity) {
+ case WordGranularity:
+ case SentenceGranularity:
+ case LineGranularity:
+ case ParagraphGranularity:
+ case SentenceBoundary:
+ case ParagraphBoundary:
+ case DocumentBoundary:
+ if (reachedBoundary)
+ *reachedBoundary = pos == currentPosition;
+ break;
+ default:
+ break;
+ }
return pos;
}
@@ -1099,6 +1173,68 @@
return intent;
}
+static AXTextSelection textSelectionWithDirectionAndGranularity(SelectionDirection direction, TextGranularity granularity)
+{
+ // FIXME: Account for BIDI in DirectionRight & DirectionLeft. (In a RTL block, Right would map to Previous/Beginning and Left to Next/End.)
+ AXTextSelectionDirection intentDirection = AXTextSelectionDirectionUnknown;
+ switch (direction) {
+ case DirectionForward:
+ intentDirection = AXTextSelectionDirectionNext;
+ break;
+ case DirectionRight:
+ intentDirection = AXTextSelectionDirectionNext;
+ break;
+ case DirectionBackward:
+ intentDirection = AXTextSelectionDirectionPrevious;
+ break;
+ case DirectionLeft:
+ intentDirection = AXTextSelectionDirectionPrevious;
+ break;
+ }
+ AXTextSelectionGranularity intentGranularity = AXTextSelectionGranularityUnknown;
+ switch (granularity) {
+ case CharacterGranularity:
+ intentGranularity = AXTextSelectionGranularityCharacter;
+ break;
+ case WordGranularity:
+ intentGranularity = AXTextSelectionGranularityWord;
+ break;
+ case SentenceGranularity:
+ case SentenceBoundary: // FIXME: Boundary should affect direction.
+ intentGranularity = AXTextSelectionGranularitySentence;
+ break;
+ case LineGranularity:
+ intentGranularity = AXTextSelectionGranularityLine;
+ break;
+ case ParagraphGranularity:
+ case ParagraphBoundary: // FIXME: Boundary should affect direction.
+ intentGranularity = AXTextSelectionGranularityParagraph;
+ break;
+ case DocumentGranularity:
+ case DocumentBoundary: // FIXME: Boundary should affect direction.
+ intentGranularity = AXTextSelectionGranularityDocument;
+ break;
+ case LineBoundary:
+ intentGranularity = AXTextSelectionGranularityLine;
+ switch (direction) {
+ case DirectionForward:
+ intentDirection = AXTextSelectionDirectionEnd;
+ break;
+ case DirectionRight:
+ intentDirection = AXTextSelectionDirectionEnd;
+ break;
+ case DirectionBackward:
+ intentDirection = AXTextSelectionDirectionBeginning;
+ break;
+ case DirectionLeft:
+ intentDirection = AXTextSelectionDirectionBeginning;
+ break;
+ }
+ break;
+ }
+ return { intentDirection, intentGranularity, false };
+}
+
bool FrameSelection::modify(EAlteration alter, SelectionDirection direction, TextGranularity granularity, EUserTriggered userTriggered)
{
if (userTriggered == UserTriggered) {
@@ -1116,13 +1252,14 @@
willBeModified(alter, direction);
+ bool shouldNotify = false;
bool wasRange = m_selection.isRange();
Position originalStartPosition = m_selection.start();
VisiblePosition position;
switch (direction) {
case DirectionRight:
if (alter == AlterationMove)
- position = modifyMovingRight(granularity);
+ position = modifyMovingRight(granularity, &shouldNotify);
else
position = modifyExtendingRight(granularity);
break;
@@ -1130,11 +1267,11 @@
if (alter == AlterationExtend)
position = modifyExtendingForward(granularity);
else
- position = modifyMovingForward(granularity);
+ position = modifyMovingForward(granularity, &shouldNotify);
break;
case DirectionLeft:
if (alter == AlterationMove)
- position = modifyMovingLeft(granularity);
+ position = modifyMovingLeft(granularity, &shouldNotify);
else
position = modifyExtendingLeft(granularity);
break;
@@ -1142,9 +1279,14 @@
if (alter == AlterationExtend)
position = modifyExtendingBackward(granularity);
else
- position = modifyMovingBackward(granularity);
+ position = modifyMovingBackward(granularity, &shouldNotify);
break;
}
+
+ if (shouldNotify && userTriggered == UserTriggered && m_frame && AXObjectCache::accessibilityEnabled()) {
+ notifyAccessibilityForSelectionChange({ AXTextStateChangeTypeSelectionBoundary, textSelectionWithDirectionAndGranularity(direction, granularity) });
+ return true;
+ }
if (position.isNull())
return false;
Modified: trunk/Source/WebCore/editing/FrameSelection.h (195948 => 195949)
--- trunk/Source/WebCore/editing/FrameSelection.h 2016-02-01 03:10:00 UTC (rev 195948)
+++ trunk/Source/WebCore/editing/FrameSelection.h 2016-02-01 04:09:02 UTC (rev 195949)
@@ -291,12 +291,12 @@
VisiblePosition modifyExtendingRight(TextGranularity);
VisiblePosition modifyExtendingForward(TextGranularity);
- VisiblePosition modifyMovingRight(TextGranularity);
- VisiblePosition modifyMovingForward(TextGranularity);
+ VisiblePosition modifyMovingRight(TextGranularity, bool* reachedBoundary = nullptr);
+ VisiblePosition modifyMovingForward(TextGranularity, bool* reachedBoundary = nullptr);
VisiblePosition modifyExtendingLeft(TextGranularity);
VisiblePosition modifyExtendingBackward(TextGranularity);
- VisiblePosition modifyMovingLeft(TextGranularity);
- VisiblePosition modifyMovingBackward(TextGranularity);
+ VisiblePosition modifyMovingLeft(TextGranularity, bool* reachedBoundary = nullptr);
+ VisiblePosition modifyMovingBackward(TextGranularity, bool* reachedBoundary = nullptr);
LayoutUnit lineDirectionPointForBlockDirectionNavigation(EPositionType);
Modified: trunk/Source/WebCore/editing/VisiblePosition.cpp (195948 => 195949)
--- trunk/Source/WebCore/editing/VisiblePosition.cpp 2016-02-01 03:10:00 UTC (rev 195948)
+++ trunk/Source/WebCore/editing/VisiblePosition.cpp 2016-02-01 04:09:02 UTC (rev 195949)
@@ -63,8 +63,10 @@
m_affinity = DOWNSTREAM;
}
-VisiblePosition VisiblePosition::next(EditingBoundaryCrossingRule rule) const
+VisiblePosition VisiblePosition::next(EditingBoundaryCrossingRule rule, bool* reachedBoundary) const
{
+ if (reachedBoundary)
+ *reachedBoundary = false;
// FIXME: Support CanSkipEditingBoundary
ASSERT(rule == CanCrossEditingBoundary || rule == CannotCrossEditingBoundary);
VisiblePosition next(nextVisuallyDistinctCandidate(m_deepPosition), m_affinity);
@@ -72,19 +74,24 @@
if (rule == CanCrossEditingBoundary)
return next;
- return honorEditingBoundaryAtOrAfter(next);
+ return honorEditingBoundaryAtOrAfter(next, reachedBoundary);
}
-VisiblePosition VisiblePosition::previous(EditingBoundaryCrossingRule rule) const
+VisiblePosition VisiblePosition::previous(EditingBoundaryCrossingRule rule, bool* reachedBoundary) const
{
+ if (reachedBoundary)
+ *reachedBoundary = false;
// FIXME: Support CanSkipEditingBoundary
ASSERT(rule == CanCrossEditingBoundary || rule == CannotCrossEditingBoundary);
// find first previous DOM position that is visible
Position pos = previousVisuallyDistinctCandidate(m_deepPosition);
// return null visible position if there is no previous visible position
- if (pos.atStartOfTree())
+ if (pos.atStartOfTree()) {
+ if (reachedBoundary)
+ *reachedBoundary = true;
return VisiblePosition();
+ }
VisiblePosition prev = VisiblePosition(pos, DOWNSTREAM);
ASSERT(prev != *this);
@@ -102,7 +109,7 @@
if (rule == CanCrossEditingBoundary)
return prev;
- return honorEditingBoundaryAtOrBefore(prev);
+ return honorEditingBoundaryAtOrBefore(prev, reachedBoundary);
}
Position VisiblePosition::leftVisuallyDistinctCandidate() const
@@ -253,12 +260,17 @@
}
}
-VisiblePosition VisiblePosition::left(bool stayInEditableContent) const
+VisiblePosition VisiblePosition::left(bool stayInEditableContent, bool* reachedBoundary) const
{
+ if (reachedBoundary)
+ *reachedBoundary = false;
Position pos = leftVisuallyDistinctCandidate();
// FIXME: Why can't we move left from the last position in a tree?
- if (pos.atStartOfTree() || pos.atEndOfTree())
+ if (pos.atStartOfTree() || pos.atEndOfTree()) {
+ if (reachedBoundary)
+ *reachedBoundary = true;
return VisiblePosition();
+ }
VisiblePosition left = VisiblePosition(pos, DOWNSTREAM);
ASSERT(left != *this);
@@ -267,7 +279,7 @@
return left;
// FIXME: This may need to do something different from "before".
- return honorEditingBoundaryAtOrBefore(left);
+ return honorEditingBoundaryAtOrBefore(left, reachedBoundary);
}
Position VisiblePosition::rightVisuallyDistinctCandidate() const
@@ -421,12 +433,17 @@
}
}
-VisiblePosition VisiblePosition::right(bool stayInEditableContent) const
+VisiblePosition VisiblePosition::right(bool stayInEditableContent, bool* reachedBoundary) const
{
+ if (reachedBoundary)
+ *reachedBoundary = false;
Position pos = rightVisuallyDistinctCandidate();
// FIXME: Why can't we move left from the last position in a tree?
- if (pos.atStartOfTree() || pos.atEndOfTree())
+ if (pos.atStartOfTree() || pos.atEndOfTree()) {
+ if (reachedBoundary)
+ *reachedBoundary = true;
return VisiblePosition();
+ }
VisiblePosition right = VisiblePosition(pos, DOWNSTREAM);
ASSERT(right != *this);
@@ -435,56 +452,78 @@
return right;
// FIXME: This may need to do something different from "after".
- return honorEditingBoundaryAtOrAfter(right);
+ return honorEditingBoundaryAtOrAfter(right, reachedBoundary);
}
-VisiblePosition VisiblePosition::honorEditingBoundaryAtOrBefore(const VisiblePosition &pos) const
+VisiblePosition VisiblePosition::honorEditingBoundaryAtOrBefore(const VisiblePosition &pos, bool* reachedBoundary) const
{
+ if (reachedBoundary)
+ *reachedBoundary = false;
if (pos.isNull())
return pos;
Node* highestRoot = highestEditableRoot(deepEquivalent());
// Return empty position if pos is not somewhere inside the editable region containing this position
- if (highestRoot && !pos.deepEquivalent().deprecatedNode()->isDescendantOf(highestRoot))
+ if (highestRoot && !pos.deepEquivalent().deprecatedNode()->isDescendantOf(highestRoot)) {
+ if (reachedBoundary)
+ *reachedBoundary = true;
return VisiblePosition();
-
+ }
+
// Return pos itself if the two are from the very same editable region, or both are non-editable
// FIXME: In the non-editable case, just because the new position is non-editable doesn't mean movement
// to it is allowed. VisibleSelection::adjustForEditableContent has this problem too.
- if (highestEditableRoot(pos.deepEquivalent()) == highestRoot)
+ if (highestEditableRoot(pos.deepEquivalent()) == highestRoot) {
+ if (reachedBoundary)
+ *reachedBoundary = *this == pos;
return pos;
+ }
// Return empty position if this position is non-editable, but pos is editable
// FIXME: Move to the previous non-editable region.
- if (!highestRoot)
+ if (!highestRoot) {
+ if (reachedBoundary)
+ *reachedBoundary = true;
return VisiblePosition();
+ }
// Return the last position before pos that is in the same editable region as this position
return lastEditablePositionBeforePositionInRoot(pos.deepEquivalent(), highestRoot);
}
-VisiblePosition VisiblePosition::honorEditingBoundaryAtOrAfter(const VisiblePosition &pos) const
+VisiblePosition VisiblePosition::honorEditingBoundaryAtOrAfter(const VisiblePosition &pos, bool* reachedBoundary) const
{
+ if (reachedBoundary)
+ *reachedBoundary = false;
if (pos.isNull())
return pos;
Node* highestRoot = highestEditableRoot(deepEquivalent());
// Return empty position if pos is not somewhere inside the editable region containing this position
- if (highestRoot && !pos.deepEquivalent().deprecatedNode()->isDescendantOf(highestRoot))
+ if (highestRoot && !pos.deepEquivalent().deprecatedNode()->isDescendantOf(highestRoot)) {
+ if (reachedBoundary)
+ *reachedBoundary = true;
return VisiblePosition();
+ }
// Return pos itself if the two are from the very same editable region, or both are non-editable
// FIXME: In the non-editable case, just because the new position is non-editable doesn't mean movement
// to it is allowed. VisibleSelection::adjustForEditableContent has this problem too.
- if (highestEditableRoot(pos.deepEquivalent()) == highestRoot)
+ if (highestEditableRoot(pos.deepEquivalent()) == highestRoot) {
+ if (reachedBoundary)
+ *reachedBoundary = *this == pos;
return pos;
+ }
// Return empty position if this position is non-editable, but pos is editable
// FIXME: Move to the next non-editable region.
- if (!highestRoot)
+ if (!highestRoot) {
+ if (reachedBoundary)
+ *reachedBoundary = true;
return VisiblePosition();
+ }
// Return the next position after pos that is in the same editable region as this position
return firstEditablePositionAfterPositionInRoot(pos.deepEquivalent(), highestRoot);
Modified: trunk/Source/WebCore/editing/VisiblePosition.h (195948 => 195949)
--- trunk/Source/WebCore/editing/VisiblePosition.h 2016-02-01 03:10:00 UTC (rev 195948)
+++ trunk/Source/WebCore/editing/VisiblePosition.h 2016-02-01 04:09:02 UTC (rev 195949)
@@ -69,13 +69,13 @@
// FIXME: Change the following functions' parameter from a boolean to StayInEditableContent.
// next() and previous() will increment/decrement by a character cluster.
- WEBCORE_EXPORT VisiblePosition next(EditingBoundaryCrossingRule = CanCrossEditingBoundary) const;
- WEBCORE_EXPORT VisiblePosition previous(EditingBoundaryCrossingRule = CanCrossEditingBoundary) const;
- VisiblePosition honorEditingBoundaryAtOrBefore(const VisiblePosition&) const;
- VisiblePosition honorEditingBoundaryAtOrAfter(const VisiblePosition&) const;
+ WEBCORE_EXPORT VisiblePosition next(EditingBoundaryCrossingRule = CanCrossEditingBoundary, bool* reachedBoundary = nullptr) const;
+ WEBCORE_EXPORT VisiblePosition previous(EditingBoundaryCrossingRule = CanCrossEditingBoundary, bool* reachedBoundary = nullptr) const;
+ VisiblePosition honorEditingBoundaryAtOrBefore(const VisiblePosition&, bool* reachedBoundary = nullptr) const;
+ VisiblePosition honorEditingBoundaryAtOrAfter(const VisiblePosition&, bool* reachedBoundary = nullptr) const;
- WEBCORE_EXPORT VisiblePosition left(bool stayInEditableContent = false) const;
- WEBCORE_EXPORT VisiblePosition right(bool stayInEditableContent = false) const;
+ WEBCORE_EXPORT VisiblePosition left(bool stayInEditableContent = false, bool* reachedBoundary = nullptr) const;
+ WEBCORE_EXPORT VisiblePosition right(bool stayInEditableContent = false, bool* reachedBoundary = nullptr) const;
WEBCORE_EXPORT UChar32 characterAfter() const;
UChar32 characterBefore() const { return previous().characterAfter(); }
Modified: trunk/Source/WebCore/editing/VisibleUnits.cpp (195948 => 195949)
--- trunk/Source/WebCore/editing/VisibleUnits.cpp 2016-02-01 03:10:00 UTC (rev 195948)
+++ trunk/Source/WebCore/editing/VisibleUnits.cpp 2016-02-01 04:09:02 UTC (rev 195949)
@@ -774,31 +774,37 @@
: positionBeforeNode(startNode);
}
-static VisiblePosition startOfLine(const VisiblePosition& c, LineEndpointComputationMode mode)
+static VisiblePosition startOfLine(const VisiblePosition& c, LineEndpointComputationMode mode, bool* reachedBoundary)
{
+ if (reachedBoundary)
+ *reachedBoundary = false;
// TODO: this is the current behavior that might need to be fixed.
// Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail.
VisiblePosition visPos = startPositionForLine(c, mode);
if (mode == UseLogicalOrdering) {
if (Node* editableRoot = highestEditableRoot(c.deepEquivalent())) {
- if (!editableRoot->contains(visPos.deepEquivalent().containerNode()))
- return firstPositionInNode(editableRoot);
+ if (!editableRoot->contains(visPos.deepEquivalent().containerNode())) {
+ VisiblePosition newPosition = firstPositionInNode(editableRoot);
+ if (reachedBoundary)
+ *reachedBoundary = c == newPosition;
+ return newPosition;
+ }
}
}
- return c.honorEditingBoundaryAtOrBefore(visPos);
+ return c.honorEditingBoundaryAtOrBefore(visPos, reachedBoundary);
}
// FIXME: Rename this function to reflect the fact it ignores bidi levels.
VisiblePosition startOfLine(const VisiblePosition& currentPosition)
{
- return startOfLine(currentPosition, UseInlineBoxOrdering);
+ return startOfLine(currentPosition, UseInlineBoxOrdering, nullptr);
}
-VisiblePosition logicalStartOfLine(const VisiblePosition& currentPosition)
+VisiblePosition logicalStartOfLine(const VisiblePosition& currentPosition, bool* reachedBoundary)
{
- return startOfLine(currentPosition, UseLogicalOrdering);
+ return startOfLine(currentPosition, UseLogicalOrdering, reachedBoundary);
}
static VisiblePosition endPositionForLine(const VisiblePosition& c, LineEndpointComputationMode mode)
@@ -858,8 +864,10 @@
return a.isNotNull() && logicalStartOfLine(a) == logicalStartOfLine(b);
}
-static VisiblePosition endOfLine(const VisiblePosition& c, LineEndpointComputationMode mode)
+static VisiblePosition endOfLine(const VisiblePosition& c, LineEndpointComputationMode mode, bool* reachedBoundary)
{
+ if (reachedBoundary)
+ *reachedBoundary = false;
// TODO: this is the current behavior that might need to be fixed.
// Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail.
VisiblePosition visPos = endPositionForLine(c, mode);
@@ -874,11 +882,15 @@
visPos = visPos.previous();
if (Node* editableRoot = highestEditableRoot(c.deepEquivalent())) {
- if (!editableRoot->contains(visPos.deepEquivalent().containerNode()))
- return lastPositionInNode(editableRoot);
+ if (!editableRoot->contains(visPos.deepEquivalent().containerNode())) {
+ VisiblePosition newPosition = lastPositionInNode(editableRoot);
+ if (reachedBoundary)
+ *reachedBoundary = c == newPosition;
+ return newPosition;
+ }
}
- return c.honorEditingBoundaryAtOrAfter(visPos);
+ return c.honorEditingBoundaryAtOrAfter(visPos, reachedBoundary);
}
// Make sure the end of line is at the same line as the given input position. Else use the previous position to
@@ -893,18 +905,18 @@
visPos = endPositionForLine(visPos, UseInlineBoxOrdering);
}
- return c.honorEditingBoundaryAtOrAfter(visPos);
+ return c.honorEditingBoundaryAtOrAfter(visPos, reachedBoundary);
}
// FIXME: Rename this function to reflect the fact it ignores bidi levels.
VisiblePosition endOfLine(const VisiblePosition& currentPosition)
{
- return endOfLine(currentPosition, UseInlineBoxOrdering);
+ return endOfLine(currentPosition, UseInlineBoxOrdering, nullptr);
}
-VisiblePosition logicalEndOfLine(const VisiblePosition& currentPosition)
+VisiblePosition logicalEndOfLine(const VisiblePosition& currentPosition, bool* reachedBoundary)
{
- return endOfLine(currentPosition, UseLogicalOrdering);
+ return endOfLine(currentPosition, UseLogicalOrdering, reachedBoundary);
}
bool inSameLine(const VisiblePosition& a, const VisiblePosition& b)
@@ -1440,14 +1452,14 @@
return p.isNotNull() && p.next().isNull();
}
-VisiblePosition leftBoundaryOfLine(const VisiblePosition& c, TextDirection direction)
+VisiblePosition leftBoundaryOfLine(const VisiblePosition& c, TextDirection direction, bool* reachedBoundary)
{
- return direction == LTR ? logicalStartOfLine(c) : logicalEndOfLine(c);
+ return direction == LTR ? logicalStartOfLine(c, reachedBoundary) : logicalEndOfLine(c, reachedBoundary);
}
-VisiblePosition rightBoundaryOfLine(const VisiblePosition& c, TextDirection direction)
+VisiblePosition rightBoundaryOfLine(const VisiblePosition& c, TextDirection direction, bool* reachedBoundary)
{
- return direction == LTR ? logicalEndOfLine(c) : logicalStartOfLine(c);
+ return direction == LTR ? logicalEndOfLine(c, reachedBoundary) : logicalStartOfLine(c, reachedBoundary);
}
static bool directionIsDownstream(SelectionDirection direction)
Modified: trunk/Source/WebCore/editing/VisibleUnits.h (195948 => 195949)
--- trunk/Source/WebCore/editing/VisibleUnits.h 2016-02-01 03:10:00 UTC (rev 195948)
+++ trunk/Source/WebCore/editing/VisibleUnits.h 2016-02-01 04:09:02 UTC (rev 195949)
@@ -60,11 +60,11 @@
WEBCORE_EXPORT bool inSameLine(const VisiblePosition &, const VisiblePosition &);
WEBCORE_EXPORT bool isStartOfLine(const VisiblePosition &);
WEBCORE_EXPORT bool isEndOfLine(const VisiblePosition &);
-VisiblePosition logicalStartOfLine(const VisiblePosition &);
-VisiblePosition logicalEndOfLine(const VisiblePosition &);
+VisiblePosition logicalStartOfLine(const VisiblePosition &, bool* reachedBoundary = nullptr);
+VisiblePosition logicalEndOfLine(const VisiblePosition &, bool* reachedBoundary = nullptr);
bool isLogicalEndOfLine(const VisiblePosition &);
-VisiblePosition leftBoundaryOfLine(const VisiblePosition&, TextDirection);
-VisiblePosition rightBoundaryOfLine(const VisiblePosition&, TextDirection);
+VisiblePosition leftBoundaryOfLine(const VisiblePosition&, TextDirection, bool* reachedBoundary);
+VisiblePosition rightBoundaryOfLine(const VisiblePosition&, TextDirection, bool* reachedBoundary);
// paragraphs (perhaps a misnomer, can be divided by line break elements)
WEBCORE_EXPORT VisiblePosition startOfParagraph(const VisiblePosition&, EditingBoundaryCrossingRule = CannotCrossEditingBoundary);