Bug 32904

Summary: Mismatched textField editing callbacks are sent after window loses & regains focus
Product: WebKit Reporter: John Sullivan <sullivan>
Component: FormsAssignee: Nobody <webkit-unassigned>
Status: NEW ---    
Severity: Normal CC: arv, darin, dbates
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: All   
OS: All   

Description John Sullivan 2009-12-23 10:34:38 PST
To reproduce:

1. Put breakpoints on Frame::textFieldDidBeginEditing(), Frame::textFieldDidEndEditing(), and Frame::textDidChangeInTextField()
2. In Safari, visit a page with a simple form textfield (e.g., a Bugzilla page like this one) and click in an empty textfield
3. type a character -> this hits the textFieldDidBeginEditing() breakpoint
4. continue in the debugger -> this hits the textDidChangeInTextField() breakpoint
5. continue in the debugger -> this hits the textFieldDidEndEditing() breakpoint as a side effect of switching to the debugger, which makes the Safari window lose key status, which makes the text field go through the "blur" codepath
6. continue in the debugger
7. switch back to Safari -> the form field still appears focused, as it should
8. type a character

Since a textFieldDidEndEditing() callback was most recently sent, the text field should be in the "not editing" state, and the next callback should be textFieldDidBeginEditing(), followed by textDidChangeInTextField(). But the textFieldDidBeginEditing() callback is not sent. The client receives a textDidChangeInTextField() callback without having received a previous textFieldDidBeginEditing() callback.

This is a regression from earlier WebKit behavior. I believe it is caused by <http://trac.webkit.org/changeset/48257>, which introduced the "blur" codepath when the window loses key status in step 5. RenderTextControlSingleLine::subtreeHasChanged() is the code that calls textFieldDidBeginEditing() and textDidChangeInTextField() for form fields. In step 8, wasChangedSinceLastChangeEvent() returns true, so RenderTextControlSingleLine::subtreeHasChanged() does not send the textFieldDidBeginEditing() function.

This could be fixed in at least three ways:

(1) revoking the change in 48257
(2) redoing that change to avoid sending the textFieldDidEndEditing() callback while still performing other blur-related work
(3) redoing that change to also change whatever state is causing "wasChangedSinceLastChangeEvent()" to return true after step 8

I found this issue while tracking down a Safari autocompletion regression that was also affected by <http://trac.webkit.org/changeset/50618>. However, I will work around this issue in Safari, so I don't know of any actual symptoms caused by these mismatched callbacks.