Bug 1471951 - Support expand selection with caret (2/2). r=yzen r=jchen

This commit is contained in:
Eitan Isaacson 2018-07-12 08:33:15 -07:00
parent ffbf9af4d8
commit 6d59d60177
5 changed files with 48 additions and 74 deletions

View File

@ -22,7 +22,6 @@ var EXPORTED_SYMBOLS = ["ContentControl"];
const MOVEMENT_GRANULARITY_CHARACTER = 1;
const MOVEMENT_GRANULARITY_WORD = 2;
const MOVEMENT_GRANULARITY_PARAGRAPH = 8;
const CLIPBOARD_COPY = 0x4000;
const CLIPBOARD_PASTE = 0x8000;
@ -307,11 +306,16 @@ this.ContentControl.prototype = {
},
handleMoveByGranularity: function cc_handleMoveByGranularity(aMessage) {
let { direction, granularity } = aMessage.json;
let focusedAcc = Utils.AccService.getAccessibleFor(this.document.activeElement);
if (focusedAcc && Utils.getState(focusedAcc).contains(States.EDITABLE)) {
this.moveCaret(focusedAcc, direction, granularity);
return;
const { direction, granularity, select } = aMessage.json;
const focusedAcc =
Utils.AccService.getAccessibleFor(this.document.activeElement);
const editable =
focusedAcc && Utils.getState(focusedAcc).contains(States.EDITABLE) ?
focusedAcc.QueryInterface(Ci.nsIAccessibleText) : null;
if (editable) {
const caretOffset = editable.caretOffset;
this.vc.setTextRange(editable, caretOffset, caretOffset, false);
}
let pivotGranularity;
@ -331,6 +335,21 @@ this.ContentControl.prototype = {
} else if (direction === "Next") {
this.vc.moveNextByText(pivotGranularity);
}
if (editable) {
const newOffset = direction === "Next" ?
this.vc.endOffset : this.vc.startOffset;
if (select) {
let anchor = editable.caretOffset;
if (editable.selectionCount) {
const [startSel, endSel] = Utils.getTextSelection(editable);
anchor = startSel == anchor ? endSel : startSel;
}
editable.setSelectionBounds(0, anchor, newOffset);
} else {
editable.caretOffset = newOffset;
}
}
},
handleSetSelection: function cc_handleSetSelection(aMessage) {
@ -384,47 +403,6 @@ this.ContentControl.prototype = {
}
},
moveCaret: function cc_moveCaret(accessible, direction, granularity) {
let accText = accessible.QueryInterface(Ci.nsIAccessibleText);
let oldOffset = accText.caretOffset;
let text = accText.getText(0, accText.characterCount);
let start = {}, end = {};
if (direction === "Previous" && oldOffset > 0) {
switch (granularity) {
case MOVEMENT_GRANULARITY_CHARACTER:
accText.caretOffset--;
break;
case MOVEMENT_GRANULARITY_WORD:
accText.getTextBeforeOffset(accText.caretOffset,
Ci.nsIAccessibleText.BOUNDARY_WORD_START, start, end);
accText.caretOffset = end.value === accText.caretOffset ?
start.value : end.value;
break;
case MOVEMENT_GRANULARITY_PARAGRAPH:
let startOfParagraph = text.lastIndexOf("\n", accText.caretOffset - 1);
accText.caretOffset = startOfParagraph !== -1 ? startOfParagraph : 0;
break;
}
} else if (direction === "Next" && oldOffset < accText.characterCount) {
switch (granularity) {
case MOVEMENT_GRANULARITY_CHARACTER:
accText.caretOffset++;
break;
case MOVEMENT_GRANULARITY_WORD:
accText.getTextAtOffset(accText.caretOffset,
Ci.nsIAccessibleText.BOUNDARY_WORD_END, start, end);
accText.caretOffset = end.value;
break;
case MOVEMENT_GRANULARITY_PARAGRAPH:
accText.caretOffset = text.indexOf("\n", accText.caretOffset + 1);
break;
}
}
this.presentCaretChange(text, oldOffset, accText.caretOffset);
},
getChildCursor: function cc_getChildCursor(aAccessible) {
let acc = aAccessible || this.vc.position;
if (Utils.isAliveAndVisible(acc) && acc.role === Roles.INTERNAL_FRAME) {
@ -497,7 +475,7 @@ this.ContentControl.prototype = {
this._contentScope.get().sendAsyncMessage(
"AccessFu:Present", Presentation.pivotChanged(
vc.position, null, Ci.nsIAccessiblePivot.REASON_NONE,
vc.startOffset, vc.endOffset, false));
vc.startOffset, vc.endOffset));
}
};
@ -518,11 +496,11 @@ this.ContentControl.prototype = {
if (!moveFirstOrLast || acc) {
// We either need next/previous or there is an anchor we need to use.
moved = vc[moveFirstOrLast ? "moveNext" : moveMethod](rule, acc, true,
false);
true);
}
if (moveFirstOrLast && !moved) {
// We move to first/last after no anchor move happened or succeeded.
moved = vc[moveMethod](rule, false);
moved = vc[moveMethod](rule, true);
}
let sentToChild = this.sendToChild(vc, {

View File

@ -136,23 +136,27 @@ this.EventManager.prototype = {
switch (aEvent.eventType) {
case Events.VIRTUALCURSOR_CHANGED:
{
let pivot = aEvent.accessible.
QueryInterface(Ci.nsIAccessibleDocument).virtualCursor;
let position = pivot.position;
if (position && position.role == Roles.INTERNAL_FRAME)
if (!aEvent.isFromUserInput) {
break;
let event = aEvent.
QueryInterface(Ci.nsIAccessibleVirtualCursorChangeEvent);
let reason = event.reason;
let oldAccessible = event.oldAccessible;
}
const event = aEvent.
QueryInterface(Ci.nsIAccessibleVirtualCursorChangeEvent);
const position = event.newAccessible;
// We pass control to the vc in the embedded frame.
if (position && position.role == Roles.INTERNAL_FRAME) {
break;
}
// Blur to document if new position is not explicitly focused.
if (!Utils.getState(position).contains(States.FOCUSED)) {
aEvent.accessibleDocument.takeFocus();
}
this.present(
Presentation.pivotChanged(position, oldAccessible, reason,
pivot.startOffset, pivot.endOffset,
aEvent.isFromUserInput));
Presentation.pivotChanged(position, event.oldAccessible, event.reason,
event.newStartOffset, event.newEndOffset));
break;
}

View File

@ -38,7 +38,7 @@ class AndroidPresentor {
* See nsIAccessiblePivot.
* @param {bool} aIsFromUserInput the pivot change was invoked by the user
*/
pivotChanged(aPosition, aOldPosition, aReason, aStartOffset, aEndOffset, aIsUserInput) {
pivotChanged(aPosition, aOldPosition, aReason, aStartOffset, aEndOffset) {
let context = new PivotContext(
aPosition, aOldPosition, aStartOffset, aEndOffset);
if (!context.accessible) {

View File

@ -65,7 +65,7 @@
evt = await runner.moveNextByGranularity(MovementGranularity.WORD,
AndroidEvents.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED);
checkMoveCaret(...evt, 29, 36);
checkMoveCaret(...evt, 30, 36);
evt = await runner.moveNextByGranularity(MovementGranularity.CHARACTER,
AndroidEvents.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
@ -77,16 +77,6 @@
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED);
checkMoveCaret(...evt, 37, 38);
evt = await runner.moveNextByGranularity(MovementGranularity.PARAGRAPH,
AndroidEvents.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED);
checkMoveCaret(...evt, 38, 59);
evt = await runner.movePreviousByGranularity(MovementGranularity.WORD,
AndroidEvents.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED);
checkMoveCaret(...evt, 59, 53);
evt = await runner.blur(AndroidEvents.VIEW_FOCUSED);
is(evt.editable, false, "Focused out of editable");
}

View File

@ -221,9 +221,11 @@ public class SessionAccessibility {
data.putInt("keyIndex", keyIndex);
mSession.getEventDispatcher().dispatch("GeckoView:AccessibilityActivate", data);
} else if (granularity > 0) {
data = new GeckoBundle(2);
boolean extendSelection = arguments.getBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN);
data = new GeckoBundle(3);
data.putString("direction", action == AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY ? "Next" : "Previous");
data.putInt("granularity", granularity);
data.putBoolean("select", extendSelection);
mSession.getEventDispatcher().dispatch("GeckoView:AccessibilityByGranularity", data);
}
return true;