12020-07-08 Wenson Hsieh <wenson_hsieh@apple.com>
2
3 autocapitalize="words" capitalizes every word's second character
4 https://bugs.webkit.org/show_bug.cgi?id=148504
5 <rdar://problem/57814304>
6
7 Reviewed by NOBODY (OOPS!).
8
9 This bug resurfaced in iOS 13 due to timing changes that caused a task added to UIKeyboardTaskQueue to no longer
10 get dequeued after the next editor state update is received in the UI process; as a result, UIKit asks us for
11 the context before the caret selection (i.e. `characterBeforeSelection`) before we have a chance to update it,
12 which means that UIKeyboardImpl's autoshift state will always be off by one character whie typing.
13
14 Note that solely deferring this update until after the next editor state update is received is insufficient to
15 fix this bug, since the keyboard's shift state will still be incorrect when typing characters very quickly (or
16 if the web process is unresponsive).
17
18 Instead, completely address this bug by adding a mechanism for WKContentView to cache the last character in the
19 string that is currently being inserted using `-insertText:`, and return it in `-_characterBeforeCaretSelection`
20 until the next editor state update comes in with the real character before the selection. This way, we're able
21 to respond to UIKit's requests immediately with a (reasonable) guess of what the character before the selection
22 should be, and then follow it up with the actual up-to-date value from the web process during the next editor
23 state update (invalidating the stale shift state if necessary). This cached last character should only be
24 incorrect in the case where the page uses script to influence what was typed, or the typed character was never
25 inserted at all (e.g. typing a newline character in a single line input element).
26
27 Test: fast/forms/ios/autocapitalize-words.html
28
29 * Platform/spi/ios/UIKitSPI.h:
30 * UIProcess/ios/WKContentViewInteraction.h:
31 * UIProcess/ios/WKContentViewInteraction.mm:
32 (-[WKContentView cleanUpInteraction]):
33 (-[WKContentView _characterBeforeCaretSelection]):
34
35 Use `_lastInsertedCharacterToOverrideCharacterBeforeSelection`, if it is set.
36
37 (-[WKContentView _characterInRelationToCaretSelection:]):
38 (-[WKContentView insertText:]):
39
40 Update `_lastInsertedCharacterToOverrideCharacterBeforeSelection` and ensure an editor state update immediately
41 after text is inserted, if we're currently editing an element with `autocapitalize="words"`. The editor state
42 update could be unnecessarily expensive, so we don't want to do this unconditionally. Also,
43 `autocapitalize="words"` is special in the sense that it is the only autocapitalization type where the platform
44 (UIKit) will ask for the last character immediately and use it to unshift the keyboard. Even in the case of
45 `autocapitalize="sentences"`, UIKit makes the decision to unshift using information from `kbd` instead.
46
47 (-[WKContentView _elementDidBlur]):
48 (-[WKContentView _selectionChanged]):
49
50 Clear out `_lastInsertedCharacterToOverrideCharacterBeforeSelection` when the next editor state update is
51 received, and invalidate the current keyboard shift state by calling `-clearShiftState`. This SPI method
52 automatically schedules a shift state update, as well.
53
54 Note the extra `_usingGestureForSelection` check here, which prevents the keyboard from autoshifting and
55 unshifting while changing the selection via loupe gesture.
56