Bug 114063 - Modifying DOMSelection causes mouse drag tracking code revert to default selection direction
Summary: Modifying DOMSelection causes mouse drag tracking code revert to default sele...
Status: UNCONFIRMED
Alias: None
Product: WebKit
Classification: Unclassified
Component: HTML Editing (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Nobody
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-04-05 14:01 PDT by Nathan Vander Wilt
Modified: 2013-04-05 16:36 PDT (History)
0 users

See Also:


Attachments
Example code that implements the splitText+workaround while logging selection state to console (877 bytes, text/html)
2013-04-05 14:01 PDT, Nathan Vander Wilt
no flags Details
Here is the sample output, annotated to explain the expected vs unexpected results (126.08 KB, image/png)
2013-04-05 14:03 PDT, Nathan Vander Wilt
no flags Details
Example demonstrating how the selection code loses track of drag direction when selection end is adjusted (1.13 KB, text/html)
2013-04-05 15:50 PDT, Nathan Vander Wilt
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Nathan Vander Wilt 2013-04-05 14:01:42 PDT
Created attachment 196677 [details]
Example code that implements the splitText+workaround while logging selection state to console

To reproduce:
1. Implement some code that periodically splits a text node at the beginning of the current user-selected text
2. Said code will trigger https://bugs.webkit.org/show_bug.cgi?id=114041 and the selection will get cleared when the text is split. So store a copy of the selection range before splitting, and set it as the current selection after splitting.

Expected results:
3. Profit!

Actual results:
3. If a mouse drag causes the "start" of a selection range to change (i.e. the users is selecting by dragging in a https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html#selections "backwards direction") the current range fixed in step #2 gets truncated at step #1's split point anyway.


I've attached a example and annotated console log that sort of shows this, but allow me to explain it here too:
backstory. I have some text "0123" displayed in my DOM, and I want to select the "12" part by dragging from the right of "2" to the left of "1"
1. [user] I select the "2" text by dragging across it right to left.
2. [code] My setInterval callback soon splits the original text node into two pieces  (in my real use caes this is so I can insert another node at the beginning of the selection)
3a. [code] Because this splitText has truncated the selection (i.e. https://bugs.webkit.org/show_bug.cgi?id=114041), I set it back to what it was — so far so good
3b. [user] As a user I don't notice anything, the "2" is still selected as I expect and of course I don't really see that the DOM now actually has the text split between two children  — so far so good
4. [user] As I continue dragging leftwards, however, to extend my selection to also include the "1" — as soon as I do so the "2" gets unselected as if step 3a never happened!

Hopefully this makes a little sense? This doesn't happen when using the keyboard (e.g. Shift+Left arrow) to make a backwards selection — the "reselect after splitText" workaround doesn't get undone. It almost seems as though the mouse tracking code is caching/modifying/applying its own selection state without regard to my JavaScript code's changes in the meantime.


Put another way, why in my attached demo is the behind-the-scenes text node splitting undetectable EXCEPT when I drag right to left?
Comment 1 Nathan Vander Wilt 2013-04-05 14:03:02 PDT
Created attachment 196678 [details]
Here is the sample output, annotated to explain the expected vs unexpected results
Comment 2 Nathan Vander Wilt 2013-04-05 15:50:17 PDT
Created attachment 196692 [details]
Example demonstrating how the selection code loses track of drag direction when selection end is adjusted

Okay, forget everything I said about splitText and https://bugs.webkit.org/show_bug.cgi?id=114041 — this bug is COMPLETELY UNRELATED and can be be isolated *much* more simply.


Steps to reproduce:
1. Change the selection range *end* while the user is using the mouse to select text.
2. On the next mouse movement, the end of the selection is forced back to the current mouse position, even if the drag direction was backwards!

I haven't fully untangled this web of code, but it appears to all center around http://trac.webkit.org/browser/trunk/Source/WebCore/page/EventHandler.cpp#L834 — the logic there doesn't *seem* to be affected by http://trac.webkit.org/browser/trunk/Source/WebCore/page/DOMSelection.cpp#L385 but I must be somewhat wrong on that because clearly changing the range programmatically resets whatever state the drag code was using to know that the selection *start* was being dragged instead of its *end*.

See the attached example, from JavaScript the start of the selection can be reliably adjusted but if the end of the selection is adjusted the selection gets collapsed underneath the mouse.
Comment 3 Nathan Vander Wilt 2013-04-05 16:36:03 PDT
Okay, looks like this is happening in addRange. When a range is added it is always ordered start/end and it is this that likely resets the mouse tracking code. http://trac.webkit.org/browser/trunk/Source/WebCore/page/DOMSelection.cpp#L385

(Note that unlike https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html#dom-selection-addrange the WIP W3C spec for this, WebKit interprets addRange as a sort of union rather than a set.)

Maybe the mouse tracking code should actually keep a copy of the selection direction state on its own?