⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 249006 in webkit


Ignore:
Timestamp:
Aug 22, 2019, 8:09:48 AM (7 years ago)
Author:
Wenson Hsieh
Message:

Typing Korean in title field after typing in the body inserts extraneous characters on blog.naver.com
https://bugs.webkit.org/show_bug.cgi?id=201023
<rdar://problem/54294794>

Reviewed by Ryosuke Niwa.

Source/WebCore:

Ensures that we recognize the blog editor on blog.naver.com to be a hidden editable area. This website places
focus inside an editable body element of a subframe that is completely empty (width: 0 and border: 0). See the
WebKit ChangeLog for more details.

Test: editing/selection/ios/do-not-show-selection-in-empty-borderless-subframe.html

  • rendering/RenderLayer.cpp:

(WebCore::RenderLayer::calculateClipRects const):

Source/WebKit:

After r242833, we began to avoid sending redundant ElementDidFocus updates in the case where a focused element
was blurred and refocused within the same runloop. This was done to prevent the input view from flickering due
to input view reloading, as well as scrolling to reveal the focused element, when tapping to change selection on
Microsoft Word online.

However, on blog.naver.com, these ElementDidFocus messages were necessary in order to ensure that the platform
input context changes when moving between the title and body fields, or when tapping to change selection. This
is because blog.naver.com uses a hidden contenteditable area under a subframe (see WebCore ChangeLog for more
detail here). While text is never directly inserted into this hidden contenteditable, the events are observed
and used to "play back" editing in the main visible content area.

Thus, when moving between the title and body fields (or when changing selection within either), the only hint we
get is that the hidden editable element is blurred and immediately refocused. Since we no longer send
ElementDidFocus updates in this scenario, UIKeyboardImpl and kbd are not aware that the page has effectively
changed input contexts.

Combined with the fact that Korean IME on iOS may insert additional text given the document context (i.e. text
that the input manager, kbd, thinks we've previously inserted), this means that when typing several characters
into the body field on naver and then switching to edit the title, initial keystrokes may insert unexpected
text in the title field.

To fix this, we add some hooks to notify the UI process when an element that was blurred has been immediately
refocused. Upon receiving this message, the UI process then tells UIKeyboardImpl to re-retrieve its input
context, which calls into -requestAutocorrectionContextWithCompletionHandler: in WKContentView. While notorious
for being synchronous IPC, this is mitigated by (1) being limiting to only instances where we have a hidden
editable area, and (2) being limited by a batching mechanism in the web process, such that if the focused
element is blurred, refocused, re-blurred, and refocused many times in the same runloop, we'll only send a
single UpdateInputContextAfterBlurringAndRefocusingElement message (as opposed to the many ElementDidFocus
messages we would've sent in previous releases).

  • Platform/spi/ios/UIKitSPI.h:
  • UIProcess/PageClient.h:
  • UIProcess/WebPageProxy.h:
  • UIProcess/WebPageProxy.messages.in:

Add a new mechanism to update the platform input context (on iOS, UIKeyboardImpl's document state) when focus
moves away from and immediately returns to a hidden editable element.

  • UIProcess/ios/PageClientImplIOS.h:
  • UIProcess/ios/PageClientImplIOS.mm:

(WebKit::PageClientImpl::updateInputContextAfterBlurringAndRefocusingElement):

  • UIProcess/ios/WKContentViewInteraction.h:
  • UIProcess/ios/WKContentViewInteraction.mm:

(-[WKContentView _updateInputContextAfterBlurringAndRefocusingElement]):

Tell the active UIKeyboardImpl to refetch document state from the WKContentView. While this does result in a new
autocorrection context request (which, unfortunately, triggers synchronous IPC to the web process), this request
would've still happened anyways in the case where we would previously have sent an ElementDidFocus message.

  • UIProcess/ios/WebPageProxyIOS.mm:

(WebKit::WebPageProxy::updateInputContextAfterBlurringAndRefocusingElement):

  • WebProcess/WebPage/WebPage.cpp:

(WebKit::WebPage::elementDidFocus):

In the case where we avoid sending a full ElementDidFocus message to the UI process due to refocusing the same
element, we should still notify the UI process so that it can synchronize state between the application process
and kbd. See above for more details.

(WebKit::WebPage::elementDidBlur):
(WebKit::WebPage::updateInputContextAfterBlurringAndRefocusingElementIfNeeded):

  • WebProcess/WebPage/WebPage.h:
  • WebProcess/WebPage/ios/WebPageIOS.mm:

(WebKit::WebPage::updateInputContextAfterBlurringAndRefocusingElementIfNeeded):

LayoutTests:

Add a new layout test to verify that we suppress text interactions when focusing an editable element inside an
empty, borderless subframe.

  • editing/selection/ios/do-not-show-selection-in-empty-borderless-subframe-expected.txt: Added.
  • editing/selection/ios/do-not-show-selection-in-empty-borderless-subframe.html: Added.
Location:
trunk
Files:
2 added
16 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r249001 r249006  
     12019-08-22  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        Typing Korean in title field after typing in the body inserts extraneous characters on blog.naver.com
     4        https://bugs.webkit.org/show_bug.cgi?id=201023
     5        <rdar://problem/54294794>
     6
     7        Reviewed by Ryosuke Niwa.
     8
     9        Add a new layout test to verify that we suppress text interactions when focusing an editable element inside an
     10        empty, borderless subframe.
     11
     12        * editing/selection/ios/do-not-show-selection-in-empty-borderless-subframe-expected.txt: Added.
     13        * editing/selection/ios/do-not-show-selection-in-empty-borderless-subframe.html: Added.
     14
    1152019-08-22  Youenn Fablet  <youenn@apple.com>
    216
  • trunk/Source/WebCore/ChangeLog

    r249002 r249006  
     12019-08-22  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        Typing Korean in title field after typing in the body inserts extraneous characters on blog.naver.com
     4        https://bugs.webkit.org/show_bug.cgi?id=201023
     5        <rdar://problem/54294794>
     6
     7        Reviewed by Ryosuke Niwa.
     8
     9        Ensures that we recognize the blog editor on blog.naver.com to be a hidden editable area. This website places
     10        focus inside an editable body element of a subframe that is completely empty (width: 0 and border: 0). See the
     11        WebKit ChangeLog for more details.
     12
     13        Test: editing/selection/ios/do-not-show-selection-in-empty-borderless-subframe.html
     14
     15        * rendering/RenderLayer.cpp:
     16        (WebCore::RenderLayer::calculateClipRects const):
     17
    1182019-08-22  Youenn Fablet  <youenn@apple.com>
    219
  • trunk/Source/WebCore/rendering/RenderLayer.cpp

    r248977 r249006  
    68196819            return false;
    68206820
     6821        if (is<HTMLFrameOwnerElement>(layer.renderer().element()) && layer.visibleSize().isEmpty())
     6822            return true;
     6823
    68216824        LayoutRect layerBounds;
    68226825        ClipRect backgroundRect;
  • trunk/Source/WebKit/ChangeLog

    r249001 r249006  
     12019-08-22  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        Typing Korean in title field after typing in the body inserts extraneous characters on blog.naver.com
     4        https://bugs.webkit.org/show_bug.cgi?id=201023
     5        <rdar://problem/54294794>
     6
     7        Reviewed by Ryosuke Niwa.
     8
     9        After r242833, we began to avoid sending redundant ElementDidFocus updates in the case where a focused element
     10        was blurred and refocused within the same runloop. This was done to prevent the input view from flickering due
     11        to input view reloading, as well as scrolling to reveal the focused element, when tapping to change selection on
     12        Microsoft Word online.
     13
     14        However, on blog.naver.com, these ElementDidFocus messages were necessary in order to ensure that the platform
     15        input context changes when moving between the title and body fields, or when tapping to change selection. This
     16        is because blog.naver.com uses a hidden contenteditable area under a subframe (see WebCore ChangeLog for more
     17        detail here). While text is never directly inserted into this hidden contenteditable, the events are observed
     18        and used to "play back" editing in the main visible content area.
     19
     20        Thus, when moving between the title and body fields (or when changing selection within either), the only hint we
     21        get is that the hidden editable element is blurred and immediately refocused. Since we no longer send
     22        ElementDidFocus updates in this scenario, UIKeyboardImpl and kbd are not aware that the page has effectively
     23        changed input contexts.
     24
     25        Combined with the fact that Korean IME on iOS may insert additional text given the document context (i.e. text
     26        that the input manager, kbd, thinks we've previously inserted), this means that when typing several characters
     27        into the body field on naver and then switching to edit the title, initial keystrokes may insert unexpected
     28        text in the title field.
     29
     30        To fix this, we add some hooks to notify the UI process when an element that was blurred has been immediately
     31        refocused. Upon receiving this message, the UI process then tells UIKeyboardImpl to re-retrieve its input
     32        context, which calls into -requestAutocorrectionContextWithCompletionHandler: in WKContentView. While notorious
     33        for being synchronous IPC, this is mitigated by (1) being limiting to only instances where we have a hidden
     34        editable area, and (2) being limited by a batching mechanism in the web process, such that if the focused
     35        element is blurred, refocused, re-blurred, and refocused many times in the same runloop, we'll only send a
     36        single UpdateInputContextAfterBlurringAndRefocusingElement message (as opposed to the many ElementDidFocus
     37        messages we would've sent in previous releases).
     38
     39        * Platform/spi/ios/UIKitSPI.h:
     40        * UIProcess/PageClient.h:
     41        * UIProcess/WebPageProxy.h:
     42        * UIProcess/WebPageProxy.messages.in:
     43
     44        Add a new mechanism to update the platform input context (on iOS, UIKeyboardImpl's document state) when focus
     45        moves away from and immediately returns to a hidden editable element.
     46
     47        * UIProcess/ios/PageClientImplIOS.h:
     48        * UIProcess/ios/PageClientImplIOS.mm:
     49        (WebKit::PageClientImpl::updateInputContextAfterBlurringAndRefocusingElement):
     50        * UIProcess/ios/WKContentViewInteraction.h:
     51        * UIProcess/ios/WKContentViewInteraction.mm:
     52        (-[WKContentView _updateInputContextAfterBlurringAndRefocusingElement]):
     53
     54        Tell the active UIKeyboardImpl to refetch document state from the WKContentView. While this does result in a new
     55        autocorrection context request (which, unfortunately, triggers synchronous IPC to the web process), this request
     56        would've still happened anyways in the case where we would previously have sent an ElementDidFocus message.
     57
     58        * UIProcess/ios/WebPageProxyIOS.mm:
     59        (WebKit::WebPageProxy::updateInputContextAfterBlurringAndRefocusingElement):
     60        * WebProcess/WebPage/WebPage.cpp:
     61        (WebKit::WebPage::elementDidFocus):
     62
     63        In the case where we avoid sending a full ElementDidFocus message to the UI process due to refocusing the same
     64        element, we should still notify the UI process so that it can synchronize state between the application process
     65        and kbd. See above for more details.
     66
     67        (WebKit::WebPage::elementDidBlur):
     68        (WebKit::WebPage::updateInputContextAfterBlurringAndRefocusingElementIfNeeded):
     69        * WebProcess/WebPage/WebPage.h:
     70        * WebProcess/WebPage/ios/WebPageIOS.mm:
     71        (WebKit::WebPage::updateInputContextAfterBlurringAndRefocusingElementIfNeeded):
     72
    1732019-08-22  Youenn Fablet  <youenn@apple.com>
    274
  • trunk/Source/WebKit/Platform/spi/ios/UIKitSPI.h

    r248535 r249006  
    271271@interface UIKeyboardImpl : UIView <UIKeyboardCandidateListDelegate>
    272272- (BOOL)smartInsertDeleteIsEnabled;
     273- (void)updateForChangedSelection;
    273274@end
    274275
  • trunk/Source/WebKit/UIProcess/PageClient.h

    r248762 r249006  
    387387
    388388    virtual void elementDidFocus(const FocusedElementInformation&, bool userIsInteracting, bool blurPreviousNode, OptionSet<WebCore::ActivityState::Flag> activityStateChanges, API::Object* userData) = 0;
     389    virtual void updateInputContextAfterBlurringAndRefocusingElement() = 0;
    389390    virtual void elementDidBlur() = 0;
    390391    virtual void focusedElementDidChangeInputMode(WebCore::InputMode) = 0;
  • trunk/Source/WebKit/UIProcess/WebPageProxy.h

    r248847 r249006  
    19451945    void elementDidFocus(const FocusedElementInformation&, bool userIsInteracting, bool blurPreviousNode, OptionSet<WebCore::ActivityState::Flag> activityStateChanges, const UserData&);
    19461946    void elementDidBlur();
     1947    void updateInputContextAfterBlurringAndRefocusingElement();
    19471948    void focusedElementDidChangeInputMode(WebCore::InputMode);
    19481949    void didReleaseAllTouchPoints();
  • trunk/Source/WebKit/UIProcess/WebPageProxy.messages.in

    r248847 r249006  
    409409    ElementDidFocus(struct WebKit::FocusedElementInformation information, bool userIsInteracting, bool blurPreviousNode, OptionSet<WebCore::ActivityState::Flag> activityStateChanges, WebKit::UserData userData)
    410410    ElementDidBlur()
     411    UpdateInputContextAfterBlurringAndRefocusingElement()
    411412    FocusedElementDidChangeInputMode(enum:uint8_t WebCore::InputMode mode)
    412413    ScrollingNodeScrollWillStartScroll()
  • trunk/Source/WebKit/UIProcess/ios/PageClientImplIOS.h

    r247866 r249006  
    150150
    151151    void elementDidFocus(const FocusedElementInformation&, bool userIsInteracting, bool blurPreviousNode, OptionSet<WebCore::ActivityState::Flag> activityStateChanges, API::Object* userData) override;
     152    void updateInputContextAfterBlurringAndRefocusingElement() final;
    152153    void elementDidBlur() override;
    153154    void focusedElementDidChangeInputMode(WebCore::InputMode) override;
  • trunk/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm

    r248828 r249006  
    559559}
    560560
     561void PageClientImpl::updateInputContextAfterBlurringAndRefocusingElement()
     562{
     563    [m_contentView _updateInputContextAfterBlurringAndRefocusingElement];
     564}
     565
    561566bool PageClientImpl::isFocusingElement()
    562567{
  • trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h

    r248733 r249006  
    460460- (void)_handleSmartMagnificationInformationForPotentialTap:(uint64_t)requestID renderRect:(const WebCore::FloatRect&)renderRect fitEntireRect:(BOOL)fitEntireRect viewportMinimumScale:(double)viewportMinimumScale viewportMaximumScale:(double)viewportMaximumScale;
    461461- (void)_elementDidFocus:(const WebKit::FocusedElementInformation&)information userIsInteracting:(BOOL)userIsInteracting blurPreviousNode:(BOOL)blurPreviousNode activityStateChanges:(OptionSet<WebCore::ActivityState::Flag>)activityStateChanges userObject:(NSObject <NSSecureCoding> *)userObject;
     462- (void)_updateInputContextAfterBlurringAndRefocusingElement;
    462463- (void)_elementDidBlur;
    463464- (void)_hideContextMenuHintContainer;
  • trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm

    r248900 r249006  
    54935493}
    54945494
     5495- (void)_updateInputContextAfterBlurringAndRefocusingElement
     5496{
     5497    if (!hasFocusedElement(_focusedElementInformation) || !_suppressSelectionAssistantReasons)
     5498        return;
     5499
     5500    [UIKeyboardImpl.activeInstance updateForChangedSelection];
     5501}
     5502
    54955503- (BOOL)shouldIgnoreKeyboardWillHideNotification
    54965504{
  • trunk/Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm

    r248846 r249006  
    905905}
    906906
     907void WebPageProxy::updateInputContextAfterBlurringAndRefocusingElement()
     908{
     909    pageClient().updateInputContextAfterBlurringAndRefocusingElement();
     910}
     911
    907912void WebPageProxy::elementDidFocus(const FocusedElementInformation& information, bool userIsInteracting, bool blurPreviousNode, OptionSet<WebCore::ActivityState::Flag> activityStateChanges, const UserData& userData)
    908913{
  • trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp

    r248901 r249006  
    54705470{
    54715471    if (!shouldDispatchUpdateAfterFocusingElement(element)) {
     5472        updateInputContextAfterBlurringAndRefocusingElementIfNeeded(element);
    54725473        m_focusedElement = &element;
    54735474        m_recentlyBlurredElement = nullptr;
     
    54775478    if (is<HTMLSelectElement>(element) || isTextFormControlOrEditableContent(element)) {
    54785479        m_focusedElement = &element;
     5480        m_hasPendingInputContextUpdateAfterBlurringAndRefocusingElement = false;
    54795481
    54805482#if PLATFORM(IOS_FAMILY)
     
    55185520            protectedThis->m_recentlyBlurredElement = nullptr;
    55195521        });
     5522        m_hasPendingInputContextUpdateAfterBlurringAndRefocusingElement = false;
    55205523    }
    55215524}
     
    66946697}
    66956698
     6699void WebPage::updateInputContextAfterBlurringAndRefocusingElementIfNeeded(Element&)
     6700{
     6701}
     6702
    66966703#endif // !PLATFORM(IOS_FAMILY)
    66976704
  • trunk/Source/WebKit/WebProcess/WebPage/WebPage.h

    r248974 r249006  
    607607    void focusedElementDidChangeInputMode(WebCore::Element&, WebCore::InputMode);
    608608    void resetFocusedElementForFrame(WebFrame*);
     609    void updateInputContextAfterBlurringAndRefocusingElementIfNeeded(WebCore::Element&);
    609610
    610611    void disabledAdaptationsDidChange(const OptionSet<WebCore::DisabledAdaptations>&);
     
    18271828    RefPtr<WebCore::Element> m_focusedElement;
    18281829    RefPtr<WebCore::Element> m_recentlyBlurredElement;
     1830    bool m_hasPendingInputContextUpdateAfterBlurringAndRefocusingElement { false };
    18291831    bool m_hasPendingEditorStateUpdate { false };
    18301832
  • trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm

    r248928 r249006  
    11701170}
    11711171
     1172void WebPage::updateInputContextAfterBlurringAndRefocusingElementIfNeeded(Element& element)
     1173{
     1174    if (m_recentlyBlurredElement != &element || !m_isShowingInputViewForFocusedElement)
     1175        return;
     1176
     1177    m_hasPendingInputContextUpdateAfterBlurringAndRefocusingElement = true;
     1178    callOnMainThread([this, protectedThis = makeRefPtr(this)] {
     1179        if (m_hasPendingInputContextUpdateAfterBlurringAndRefocusingElement)
     1180            send(Messages::WebPageProxy::UpdateInputContextAfterBlurringAndRefocusingElement());
     1181        m_hasPendingInputContextUpdateAfterBlurringAndRefocusingElement = false;
     1182    });
     1183}
     1184
    11721185void WebPage::blurFocusedElement()
    11731186{
Note: See TracChangeset for help on using the changeset viewer.