Bug 1306634 Part 1 - Handle a long press to select a word in an unfocused iframe. r=mats,marionette-reviewers,whimboo

Long-pressing on a text in an unfocused iframe to select a word never
works. Currently, you need to single tap to focus the iframe first.

Each PresShell has an associated AccessibleCaretEventHub. This patch
fixes this bug by routing the event to the AccessibleCaretEventHub under
the event point, and handle it there. If the event is not handled, then
we handle it by the focused AccessibleCaretEventHub as before.

I've experimented with only routing the event to the
AccessibleCaretEventHub under the event point, without routing to the
fallback focused AccessibleCaretEventHub. However, caret dragging didn't
work in iframes. I didn't debug further.

Differential Revision: https://phabricator.services.mozilla.com/D52767

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Ting-Yu Lin 2020-01-16 05:08:36 +00:00
Родитель 5a611b020b
Коммит 2e68f8780b
4 изменённых файлов: 62 добавлений и 11 удалений

Просмотреть файл

@ -6459,7 +6459,8 @@ nsresult PresShell::EventHandler::HandleEvent(nsIFrame* aFrameForPresShell,
mPresShell->RecordMouseLocation(aGUIEvent); mPresShell->RecordMouseLocation(aGUIEvent);
if (MaybeHandleEventWithAccessibleCaret(aGUIEvent, aEventStatus)) { if (MaybeHandleEventWithAccessibleCaret(aFrameForPresShell, aGUIEvent,
aEventStatus)) {
// Probably handled by AccessibleCaretEventHub. // Probably handled by AccessibleCaretEventHub.
return NS_OK; return NS_OK;
} }
@ -6870,7 +6871,8 @@ bool PresShell::EventHandler::DispatchPrecedingPointerEvent(
} }
bool PresShell::EventHandler::MaybeHandleEventWithAccessibleCaret( bool PresShell::EventHandler::MaybeHandleEventWithAccessibleCaret(
WidgetGUIEvent* aGUIEvent, nsEventStatus* aEventStatus) { nsIFrame* aFrameForPresShell, WidgetGUIEvent* aGUIEvent,
nsEventStatus* aEventStatus) {
MOZ_ASSERT(aGUIEvent); MOZ_ASSERT(aGUIEvent);
MOZ_ASSERT(aEventStatus); MOZ_ASSERT(aEventStatus);
@ -6886,8 +6888,37 @@ bool PresShell::EventHandler::MaybeHandleEventWithAccessibleCaret(
return false; return false;
} }
// We have to target the focus window because regardless of where the // First, try the event hub at the event point to handle a long press to
// touch goes, we want to access the copy paste manager. // select a word in an unfocused window.
do {
EventTargetData eventTargetData(nullptr);
if (!ComputeEventTargetFrameAndPresShellAtEventPoint(
aFrameForPresShell, aGUIEvent, &eventTargetData)) {
break;
}
if (!eventTargetData.mPresShell) {
break;
}
RefPtr<AccessibleCaretEventHub> eventHub =
eventTargetData.mPresShell->GetAccessibleCaretEventHub();
if (!eventHub) {
break;
}
*aEventStatus = eventHub->HandleEvent(aGUIEvent);
if (*aEventStatus != nsEventStatus_eConsumeNoDefault) {
break;
}
// If the event is consumed, cancel APZC panning by setting
// mMultipleActionsPrevented.
aGUIEvent->mFlags.mMultipleActionsPrevented = true;
return true;
} while (false);
// Then, we target the event to the event hub at the focused window.
nsCOMPtr<nsPIDOMWindowOuter> window = GetFocusedDOMWindowInOurWindow(); nsCOMPtr<nsPIDOMWindowOuter> window = GetFocusedDOMWindowInOurWindow();
if (!window) { if (!window) {
return false; return false;

Просмотреть файл

@ -2292,13 +2292,16 @@ class PresShell final : public nsStubDocumentObserver,
* MaybeHandleEventWithAccessibleCaret() may handle aGUIEvent with * MaybeHandleEventWithAccessibleCaret() may handle aGUIEvent with
* AccessibleCaretEventHub if it's necessary. * AccessibleCaretEventHub if it's necessary.
* *
* @param aFrameForPresShell The frame for PresShell. See explanation of
* HandleEvent() for the details.
* @param aGUIEvent Event may be handled by AccessibleCaretEventHub. * @param aGUIEvent Event may be handled by AccessibleCaretEventHub.
* @param aEventStatus [in/out] EventStatus of aGUIEvent. * @param aEventStatus [in/out] EventStatus of aGUIEvent.
* @return true if AccessibleCaretEventHub handled the * @return true if AccessibleCaretEventHub handled the
* event and caller shouldn't keep handling it. * event and caller shouldn't keep handling it.
*/ */
MOZ_CAN_RUN_SCRIPT MOZ_CAN_RUN_SCRIPT
bool MaybeHandleEventWithAccessibleCaret(WidgetGUIEvent* aGUIEvent, bool MaybeHandleEventWithAccessibleCaret(nsIFrame* aFrameForPresShell,
WidgetGUIEvent* aGUIEvent,
nsEventStatus* aEventStatus); nsEventStatus* aEventStatus);
/** /**

Просмотреть файл

@ -520,6 +520,28 @@ class AccessibleCaretSelectionModeTestCase(MarionetteTestCase):
self.assertNotEqual(self.to_unix_line_ending(sel.selected_content), '') self.assertNotEqual(self.to_unix_line_ending(sel.selected_content), '')
def test_select_word_inside_an_unfocused_iframe(self):
'''Bug 1306634: Test we can long press to select a word in an unfocused iframe.'''
self.open_test_html(self._iframe_html)
el = self.marionette.find_element(By.ID, self._input_id)
sel = SelectionManager(el)
# First, we select the first word in the input of the parent document.
el_first_word = sel.content.split()[0] # first world is "ABC"
self.long_press_on_word(el, 0)
self.assertEqual(el_first_word, sel.selected_content)
# Then, we long press on the center of the iframe. It should select a
# word inside of the document, not the placehoder in the parent
# document.
iframe = self.marionette.find_element(By.ID, 'frame')
self.long_press_on_location(iframe)
self.marionette.switch_to_frame(iframe)
body = self.marionette.find_element(By.ID, 'bd')
sel = SelectionManager(body)
self.assertNotEqual('', sel.selected_content)
def test_carets_initialized_in_display_none(self): def test_carets_initialized_in_display_none(self):
'''Test AccessibleCaretEventHub is properly initialized on a <html> with '''Test AccessibleCaretEventHub is properly initialized on a <html> with
display: none. display: none.

Просмотреть файл

@ -9,12 +9,7 @@
<title>Marionette tests for AccessibleCaret in selection mode (iframe)</title> <title>Marionette tests for AccessibleCaret in selection mode (iframe)</title>
</head> </head>
<body> <body>
<style>
*
{
-moz-user-select:none;
}
</style>
<iframe id="frame" src="test_carets_longtext.html" style="width: 10em; height: 8em;"></iframe> <iframe id="frame" src="test_carets_longtext.html" style="width: 10em; height: 8em;"></iframe>
<input id="input" value="ABC DEF GHI">
</body> </body>
</html> </html>