RESOLVED FIXED 110742
selectionStart/selectionEnd return "obsolete" values when requested during "input" event
https://bugs.webkit.org/show_bug.cgi?id=110742
Summary selectionStart/selectionEnd return "obsolete" values when requested during "i...
Eugene Klyuchnikov
Reported 2013-02-25 02:39:01 PST
Steps to reproduce: 1) Create input element 2) Attach "input" listener 3) Log input value and selectionStart/selectionEnd when event is fired Result: 1) After first key is typed (after focusing input control) value.length = selectionStart = selectionEnd = 1 (correct) 2) After consequent keys selectionStart = selectionEnd = value.length - 1 (incorrect) Expected result: typing resets selection, so if cursor is at the end of input, then we expect value.length = selectionStart = selectionEnd Note: after "Delete" is hit cursor position is reported correctly. But insert/replace behave the same way as typing. Analysis: we fire "input" event before selection is updated.
Attachments
Patch (4.52 KB, patch)
2013-02-25 02:41 PST, Eugene Klyuchnikov
no flags
Patch (5.59 KB, patch)
2013-03-01 03:19 PST, Eugene Klyuchnikov
no flags
Patch (5.47 KB, patch)
2013-03-04 01:07 PST, Eugene Klyuchnikov
no flags
Patch (5.79 KB, patch)
2013-03-11 05:18 PDT, Eugene Klyuchnikov
no flags
Patch (6.41 KB, patch)
2013-04-09 02:31 PDT, Eugene Klyuchnikov
no flags
Patch (8.75 KB, patch)
2013-05-30 06:32 PDT, Eugene Klyuchnikov
no flags
Patch (8.75 KB, patch)
2013-05-30 07:32 PDT, Eugene Klyuchnikov
no flags
Archive of layout-test-results from webkit-ews-15 for mac-mountainlion-wk2 (559.57 KB, application/zip)
2013-05-30 09:06 PDT, Build Bot
no flags
Patch (2.68 KB, patch)
2013-06-03 02:30 PDT, Eugene Klyuchnikov
rniwa: review-
Eugene Klyuchnikov
Comment 1 2013-02-25 02:41:17 PST
Build Bot
Comment 2 2013-02-25 04:30:38 PST
Comment on attachment 190024 [details] Patch Attachment 190024 [details] did not pass mac-wk2-ews (mac-wk2): Output: http://queues.webkit.org/results/16749177 New failing tests: editing/selection/caret-after-keypress.html
Alexey Proskuryakov
Comment 3 2013-02-25 09:53:13 PST
What do other browsers do? Should the event be async? Cancellable?
Eugene Klyuchnikov
Comment 4 2013-02-25 21:38:50 PST
(In reply to comment #3) > What do other browsers do? Should the event be async? Cancellable? In MSDN it is said: Synchronous No; Bubbles No; Cancelable No In Mozilla Event reference it is said: Bubbles Yes; Cancelable No In current Firefox release selectionStart/selectionEnd is coherent with input content. In whatwg.org specs it is mentioned that firing event must be queued on input content change (so, implicitly, caret/selection during dispatching will be actual). Also several "input" events could be collapsed (to denote that user stopped typing).
Ryosuke Niwa
Comment 5 2013-02-27 01:11:09 PST
Comment on attachment 190024 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=190024&action=review I'm somewhat nervous about changing the timing of this event because of the way copy & paste uses webkitEditableContentChangedEvent and how alternative text controller may depends on events firing in advance but I can't think of bugs that this change will introduce off the top of my head. > LayoutTests/editing/selection/caret-after-keypress-expected.txt:6 > +[] 0 0 > +[a] 1 1 > +[ab] 2 2 Instead of just logging values like this, can we use shouldBe and other functions in js-test-pre.js to make the test more explicit? As is, it's hard to tell when the test is passing or why these outputs ought to be correct.
Eugene Klyuchnikov
Comment 6 2013-02-28 02:33:59 PST
(In reply to comment #5) > ...and how alternative text controller may depends on events firing in advance but I can't think of bugs that this change will introduce off the top of my head. IMHO controller couldn't depend on receiving notification "in advance" because in other cases it receives notifications after selection is fixed (known cases are: first keypress after input is focused; user deleted char in input). As a best effort we could implement deferred "onInput" notifications...
Eugene Klyuchnikov
Comment 7 2013-03-01 03:07:06 PST
Comment on attachment 190024 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=190024&action=review >> LayoutTests/editing/selection/caret-after-keypress-expected.txt:6 >> +[ab] 2 2 > > Instead of just logging values like this, can we use shouldBe and other functions in js-test-pre.js to make the test more explicit? > As is, it's hard to tell when the test is passing or why these outputs ought to be correct. Fixed.
Eugene Klyuchnikov
Comment 8 2013-03-01 03:19:28 PST
Ryosuke Niwa
Comment 9 2013-03-01 12:00:47 PST
Comment on attachment 190922 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=190922&action=review > LayoutTests/editing/selection/caret-after-keypress.html:46 > + test.addEventListener("input", step); I really don't understand why we need to make this test asynchronous given that input event fires synchronously. We can run all the steps synchronously.
Eugene Klyuchnikov
Comment 10 2013-03-04 01:06:17 PST
(In reply to comment #9) > I really don't understand why we need to make this test asynchronous given that input event fires synchronously. > We can run all the steps synchronously. OK, I'll make test synchronous. But as I mentioned, in HTML5 spec it is not yet determined if "input" event is synchronous or asynchronous. So making test asynchronous shields us from details of implementation that could change.
Eugene Klyuchnikov
Comment 11 2013-03-04 01:07:20 PST
Ryosuke Niwa
Comment 12 2013-03-09 00:25:04 PST
Comment on attachment 191167 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=191167&action=review > LayoutTests/editing/selection/caret-after-keypress-expected.txt:12 > +PASS 0 > +PASS 1 > +PASS 2 > +PASS 3 > +PASS 4 > +PASS 5 > +PASS 6 I'm sorry but this output is not exactly helpful. It doesn't tell me what each test case is testing and why they're passing. > LayoutTests/editing/selection/caret-after-keypress.html:27 > + assertEquals(test.value, output.join(""), "value"); > + assertEquals(test.selectionStart, output.length, "selectionStart"); > + assertEquals(test.selectionEnd, output.length, "selectionEnd"); It seems like all we need to do is to use shouldBe instead of assertEquals. > LayoutTests/editing/selection/caret-after-keypress.html:28 > + testPassed("" + pass++); This is going to output PASS regardless of whether tests have passed or not. > LayoutTests/editing/selection/caret-after-keypress.html:34 > + var key = input.shift(); > + if (key === backSpace) > + output.pop(); > + else > + output.push(key); This makes it really hard to understand what's happening in the test. I would have preferred to hard code the expected output instead. It's very important for tests to be obvious and self-evidently correct. Unfortunately, this test isn't so self-evident to me and I think we can do better.
Eugene Klyuchnikov
Comment 13 2013-03-11 05:12:27 PDT
Comment on attachment 191167 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=191167&action=review >> LayoutTests/editing/selection/caret-after-keypress.html:27 >> + assertEquals(test.selectionEnd, output.length, "selectionEnd"); > > It seems like all we need to do is to use shouldBe instead of assertEquals. OK >> LayoutTests/editing/selection/caret-after-keypress.html:28 >> + testPassed("" + pass++); > > This is going to output PASS regardless of whether tests have passed or not. oops. fixed. >> LayoutTests/editing/selection/caret-after-keypress.html:34 >> + output.push(key); > > This makes it really hard to understand what's happening in the test. I would have preferred to hard code the expected output instead. > It's very important for tests to be obvious and self-evidently correct. > Unfortunately, this test isn't so self-evident to me and I think we can do better. Done
Eugene Klyuchnikov
Comment 14 2013-03-11 05:18:03 PDT
Eugene Klyuchnikov
Comment 15 2013-03-28 00:28:56 PDT
Comment on attachment 192444 [details] Patch Any news?
Ryosuke Niwa
Comment 16 2013-03-28 00:49:48 PDT
Comment on attachment 192444 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=192444&action=review > Source/WebCore/ChangeLog:3 > + [Editor] selectionStart/selectionEnd return "obsolete" values when requested during "input" event. We don't prefix a bug with "[Editor]". > Source/WebCore/ChangeLog:7 > + This patch changes the timing at which webkitEditableContentChangedEvent is fired. You should explain why that results in "input" event being fired at the right time.
Ryosuke Niwa
Comment 17 2013-03-28 00:49:49 PDT
Comment on attachment 192444 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=192444&action=review > Source/WebCore/ChangeLog:3 > + [Editor] selectionStart/selectionEnd return "obsolete" values when requested during "input" event. We don't prefix a bug with "[Editor]". > Source/WebCore/ChangeLog:7 > + This patch changes the timing at which webkitEditableContentChangedEvent is fired. You should explain why that results in "input" event being fired at the right time.
Eugene Klyuchnikov
Comment 18 2013-03-29 02:21:07 PDT
Analysis: after key-press there are 2 possibilities 1) We recently focused input, so new CompositeEditCommand is created and applied. 2) We have done some editing already, so insertion command is appended. Here are two scenarios in time/nesting cut. First (good) scenario. keypress event dispatching { textInput event dispatching { CompositeEditCommand::apply creates scope { Editor::appliedEditing invoked { dispatchEditableContentChangedEvents invoked { webkitEditableContentChanged dispatched { input event enqueued (because it is scoped event) } } * FrameSelection::setSelection invoked } } * input event is dispatched because scope is closed } } Second (bad) scenario. keypress event dispatching { textInput event dispatching { Editor::appliedEditing invoked { dispatchEditableContentChangedEvents invoked { webkitEditableContentChanged dispatched { * input event dispatched (no scope this time) } } * FrameSelection::setSelection invoked (too late) } } } So I see 3 possible solutions 1) Invoke dispatchEditableContentChangedEvents after setSelection (but you are right, this should be done for all 3 methods: applied/unapplied/reapplied editing). 2) Create scope in those 3 methods; actually this will save order of execution of webkitEditableContentChanged and setSelection and just pull out dispatching of input event. 3) Place more coarse scope (several stack levels up), but we can't predict how it will affect execution. Overall (2) solution looks like least invasive.
Ryosuke Niwa
Comment 19 2013-03-29 10:12:28 PDT
Why don't we have EditCommand in the stack in the second scenario?
Eugene Klyuchnikov
Comment 20 2013-04-01 00:32:17 PDT
As I said earlier 2 paths are "create composition" and "append to composition". Details. Both paths has common point: TypingCommand::insertText(document, text, selection, options, compositionType) Condition "if (lastTypingCommandIfStillOpenForTyping(...))" splits them. First (good) scenarion we create typing command, and then: TextInsertionBaseCommand::applyTextInsertionCommand applyCommand [CompositeEditCommand.cpp:170] * CompositeEditCommand::apply TypingCommand::doApply = TypingCommand::insertText = forEachLineInString [TextInsertionBaseCommand.h:61] = TypingCommandLineOperation::operator() = TypingCommand::insertTextRunWithoutNewlines = TypingCommand::typingAddedToOpenCommand = Editor::appliedEditing "*" is where scope create. Second scenario is shorter: it consists only of lines marked with "=". So the answer is: we do not apply command because we do not create one.
Eugene Klyuchnikov
Comment 21 2013-04-07 22:44:16 PDT
to Ryosuke Niwa: any thoughts how this should be fixed?
Ryosuke Niwa
Comment 22 2013-04-07 22:46:06 PDT
We should fix this but I don't think the patch posted here is correct.
Eugene Klyuchnikov
Comment 23 2013-04-08 04:59:00 PDT
(In reply to comment #22) > We should fix this but I don't think the patch posted here is correct. Surely. Earlier I've proposed 3 patch ideas. Personally I like this one: create EventQueueScope in 3 Editor methods: appliedEditing, unappliedEditing, reappliedEditing. This is least invasive solution, because it will affect only on time when "input" event is dispatched (in case it is fired). It is up to you to choose the best way to fix. Just post a comment with decision and I'll implement corresponding patch.
Ryosuke Niwa
Comment 24 2013-04-08 07:22:49 PDT
If we were to use the event scope to resolve this bug, I'd instantiate the scope object in TypingCommand::insertText and other static functions of TypingCommand since the event scope was invented to delay firing of mutation events. On the other hand, it's strange that the event scope is needed for correctness of ordering of events. Ordering of the events should be correct regardless of whether we define the scope or not.
Eugene Klyuchnikov
Comment 25 2013-04-08 09:20:32 PDT
(In reply to comment #24) > If we were to use the event scope to resolve this bug, I'd instantiate the scope object in TypingCommand::insertText and other static functions of TypingCommand since the event scope was invented to delay firing of mutation events. > > On the other hand, it's strange that the event scope is needed for correctness of ordering of events. Ordering of the events should be correct regardless of whether we define the scope or not. That is what we began with. I've proposed to move "setSelection" before "dispatchEvent". Because that is what expected by user. But it turned out that scoping could be an alternate solution. This solution looks in terms of "how alternative text controller may depends on events firing in advance". Summary. We have to care about 2 message types: "webkitEditableContentChanged" and "input". The later one is fired from the first. We are aimed to make "input" be dispatched after setSelection, but it not known how change of "webkitEditableContentChanged" firing time will affect different aspects of editing.
Ryosuke Niwa
Comment 26 2013-04-08 09:27:49 PDT
We need to look at each place we listen to webkitEditableContentChanged, and make sure that code still works when we change the order. I'm sorry I sound like blocking your patch but we need to verify the correctness regardless of which approach we take. And the burden of the proof is on each patch author. I can't, as a reviewer, tell you which approach is better, let alone correct.
Eugene Klyuchnikov
Comment 27 2013-04-09 01:56:32 PDT
(In reply to comment #26) > We need to look at each place we listen to webkitEditableContentChanged, and make sure that code still works when we change the order. I'm sorry I sound like blocking your patch but we need to verify the correctness regardless of which approach we take. And the burden of the proof is on each patch author. I can't, as a reviewer, tell you which approach is better, let alone correct. I quite agree with you =) But your expertise in the area is very valuable! I've checked: we have no explicit listeners of webkitEditableContentChanged, but some handlers process this message specifically. As I see none of work with selection. When Node dispatches "webkitEditableContentChanged" it create "input" event and dispatches it as scoped. So it is at least suggested that scope is placed. There are two distinct invocations of Editor::appliedEditing. One from composite command, other one from typing command. un-/re-appliedEditing is invoked only from composite command. To be honest, none of those calls are wrapped directly by scope. So, what I see: 1) commands do not care about "input" event at all, and it is implementation detail of editor, when to dispatch this event; 2) webkitEditableContentChanged dispatchers do not depend on selection As a result, I propose to swap setSelection and dispatch of event in aforementioned 3 methods. I'll upload patch soon.
Eugene Klyuchnikov
Comment 28 2013-04-09 02:31:26 PDT
Eugene Klyuchnikov
Comment 29 2013-05-30 06:32:10 PDT
Eugene Klyuchnikov
Comment 30 2013-05-30 07:32:11 PDT
Build Bot
Comment 31 2013-05-30 09:06:15 PDT
Comment on attachment 203355 [details] Patch Attachment 203355 [details] did not pass mac-wk2-ews (mac-wk2): Output: http://webkit-queues.appspot.com/results/661182 New failing tests: fast/dom/location-new-window-no-crash.html
Build Bot
Comment 32 2013-05-30 09:06:18 PDT
Created attachment 203363 [details] Archive of layout-test-results from webkit-ews-15 for mac-mountainlion-wk2 The attached test failures were seen while running run-webkit-tests on the mac-wk2-ews. Bot: webkit-ews-15 Port: mac-mountainlion-wk2 Platform: Mac OS X 10.8.3
Ryosuke Niwa
Comment 33 2013-05-30 12:25:39 PDT
(In reply to comment #27) > (In reply to comment #26) > > We need to look at each place we listen to webkitEditableContentChanged, and make sure that code still works when we change the order. I'm sorry I sound like blocking your patch but we need to verify the correctness regardless of which approach we take. And the burden of the proof is on each patch author. I can't, as a reviewer, tell you which approach is better, let alone correct. > > I quite agree with you =) But your expertise in the area is very valuable! > > I've checked: we have no explicit listeners of webkitEditableContentChanged, but some handlers process this message specifically. As I see none of work with selection. > > When Node dispatches "webkitEditableContentChanged" it create "input" event and dispatches it as scoped. So it is at least suggested that scope is placed. > > There are two distinct invocations of Editor::appliedEditing. One from composite command, other one from typing command. un-/re-appliedEditing is invoked only from composite command. To be honest, none of those calls are wrapped directly by scope. > > So, what I see: > 1) commands do not care about "input" event at all, and it is implementation detail of editor, when to dispatch this event; > 2) webkitEditableContentChanged dispatchers do not depend on selection > > As a result, I propose to swap setSelection and dispatch of event in aforementioned 3 methods. Thanks for the investigation.
Eugene Klyuchnikov
Comment 34 2013-05-30 22:15:19 PDT
Eugene Klyuchnikov
Comment 35 2013-06-03 02:30:36 PDT
Reopening to attach new patch.
Eugene Klyuchnikov
Comment 36 2013-06-03 02:30:41 PDT
Eugene Klyuchnikov
Comment 37 2013-06-03 02:52:46 PDT
Ooops. Attached to wrong bug. (In reply to comment #36) > Created an attachment (id=203563) [details] > Patch
Alexey Proskuryakov
Comment 38 2013-06-03 08:53:21 PDT
Where should this patch be attached? Bug 117070?
Ryosuke Niwa
Comment 39 2013-06-03 09:35:19 PDT
Comment on attachment 203563 [details] Patch Please post this patch on a new bug.
Note You need to log in before you can comment on or make changes to this bug.