зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1471951 - Support expand selection with caret (2/2). r=yzen r=jchen
This commit is contained in:
Родитель
ffbf9af4d8
Коммит
6d59d60177
|
@ -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, {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче