Changeset 252062 in webkit


Ignore:
Timestamp:
Nov 5, 2019 10:52:12 AM (4 years ago)
Author:
Wenson Hsieh
Message:

Native text substitutions interfere with HTML <datalist> options resulting in crash
https://bugs.webkit.org/show_bug.cgi?id=203116
<rdar://problem/49875932>

Reviewed by Tim Horton.

Source/WebKit:

On macOS, an NSTableView inside a separate window is used to render suggestions when showing a datalist. The
crash happens when this table view is reloaded while clicking a datalist suggestion; that is, if -[NSTableView
reloadData] is invoked after the user sends a platform MouseDown event on the table view cell but before the
MouseUp is received, the selected row of the table view will be -1 when the action, -selectedRow:, is invoked.

In this particular case, the table view reload is triggered as a result of hiding the autocorrection bubble on
macOS, thereby committing the alternative text suggestion and changing the value of the text field via an
editing command.

To avoid crashing, we simply make -selectedRow: robust in the case where the index is invalid.

Test: fast/forms/datalist/datalist-click-crash.html

  • UIProcess/mac/WebDataListSuggestionsDropdownMac.mm:

(-[WKDataListSuggestionsController selectedRow:]):

Tools:

Add a new testing hook to wait for datalist suggestions to show up and choose the suggestion at the given index.

  • DumpRenderTree/mac/UIScriptControllerMac.h:
  • DumpRenderTree/mac/UIScriptControllerMac.mm:

(WTR::UIScriptControllerMac::activateDataListSuggestion):

  • TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl:
  • TestRunnerShared/UIScriptContext/UIScriptController.h:

(WTR::UIScriptController::activateDataListSuggestion):

  • WebKitTestRunner/ios/UIScriptControllerIOS.h:
  • WebKitTestRunner/ios/UIScriptControllerIOS.mm:

(WTR::UIScriptControllerIOS::activateDataListSuggestion):

  • WebKitTestRunner/mac/UIScriptControllerMac.h:
  • WebKitTestRunner/mac/UIScriptControllerMac.mm:

(WTR::UIScriptControllerMac::isShowingDataListSuggestions const):
(WTR::UIScriptControllerMac::activateDataListSuggestion):

Dig through the view hierarchy of the NSWindow subclass used to show datalist suggestions for the table view
containing the suggestions; then, select the given row, and invoke the action on the target.

(WTR::UIScriptControllerMac::dataListSuggestionsTableView const):

LayoutTests:

Add a new layout test to exercise the crash.

  • fast/forms/datalist/datalist-click-crash-expected.txt: Added.
  • fast/forms/datalist/datalist-click-crash.html: Added.
  • resources/ui-helper.js:

(window.UIHelper.activateDataListSuggestion):

Location:
trunk
Files:
2 added
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r252057 r252062  
     12019-11-05  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        Native text substitutions interfere with HTML <datalist> options resulting in crash
     4        https://bugs.webkit.org/show_bug.cgi?id=203116
     5        <rdar://problem/49875932>
     6
     7        Reviewed by Tim Horton.
     8
     9        Add a new layout test to exercise the crash.
     10
     11        * fast/forms/datalist/datalist-click-crash-expected.txt: Added.
     12        * fast/forms/datalist/datalist-click-crash.html: Added.
     13        * resources/ui-helper.js:
     14        (window.UIHelper.activateDataListSuggestion):
     15
    1162019-11-05  Andy Estes  <aestes@apple.com>
    217
  • trunk/LayoutTests/resources/ui-helper.js

    r251522 r252062  
    667667    }
    668668
     669    static activateDataListSuggestion(index) {
     670        const script = `uiController.activateDataListSuggestion(${index}, () => {
     671            uiController.uiScriptComplete("");
     672        });`;
     673        return new Promise(resolve => testRunner.runUIScript(script, resolve));
     674    }
     675
    669676    static isShowingDataListSuggestions()
    670677    {
  • trunk/Source/WebKit/ChangeLog

    r252060 r252062  
     12019-11-05  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        Native text substitutions interfere with HTML <datalist> options resulting in crash
     4        https://bugs.webkit.org/show_bug.cgi?id=203116
     5        <rdar://problem/49875932>
     6
     7        Reviewed by Tim Horton.
     8
     9        On macOS, an NSTableView inside a separate window is used to render suggestions when showing a datalist. The
     10        crash happens when this table view is reloaded while clicking a datalist suggestion; that is, if -[NSTableView
     11        reloadData] is invoked after the user sends a platform MouseDown event on the table view cell but before the
     12        MouseUp is received, the selected row of the table view will be -1 when the action, `-selectedRow:`, is invoked.
     13
     14        In this particular case, the table view reload is triggered as a result of hiding the autocorrection bubble on
     15        macOS, thereby committing the alternative text suggestion and changing the value of the text field via an
     16        editing command.
     17
     18        To avoid crashing, we simply make `-selectedRow:` robust in the case where the index is invalid.
     19
     20        Test: fast/forms/datalist/datalist-click-crash.html
     21
     22        * UIProcess/mac/WebDataListSuggestionsDropdownMac.mm:
     23        (-[WKDataListSuggestionsController selectedRow:]):
     24
    1252019-11-05  Sihui Liu  <sihui_liu@apple.com>
    226
  • trunk/Source/WebKit/UIProcess/mac/WebDataListSuggestionsDropdownMac.mm

    r250260 r252062  
    403403- (void)selectedRow:(NSTableView *)sender
    404404{
    405     _dropdown->didSelectOption(_suggestions.at([sender selectedRow]));
     405    auto selectedString = self.currentSelectedString;
     406    if (!selectedString)
     407        return;
     408
     409    _dropdown->didSelectOption(selectedString);
    406410}
    407411
  • trunk/Tools/ChangeLog

    r252061 r252062  
     12019-11-05  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        Native text substitutions interfere with HTML <datalist> options resulting in crash
     4        https://bugs.webkit.org/show_bug.cgi?id=203116
     5        <rdar://problem/49875932>
     6
     7        Reviewed by Tim Horton.
     8
     9        Add a new testing hook to wait for datalist suggestions to show up and choose the suggestion at the given index.
     10
     11        * DumpRenderTree/mac/UIScriptControllerMac.h:
     12        * DumpRenderTree/mac/UIScriptControllerMac.mm:
     13        (WTR::UIScriptControllerMac::activateDataListSuggestion):
     14        * TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl:
     15        * TestRunnerShared/UIScriptContext/UIScriptController.h:
     16        (WTR::UIScriptController::activateDataListSuggestion):
     17        * WebKitTestRunner/ios/UIScriptControllerIOS.h:
     18        * WebKitTestRunner/ios/UIScriptControllerIOS.mm:
     19        (WTR::UIScriptControllerIOS::activateDataListSuggestion):
     20        * WebKitTestRunner/mac/UIScriptControllerMac.h:
     21        * WebKitTestRunner/mac/UIScriptControllerMac.mm:
     22        (WTR::UIScriptControllerMac::isShowingDataListSuggestions const):
     23        (WTR::UIScriptControllerMac::activateDataListSuggestion):
     24
     25        Dig through the view hierarchy of the NSWindow subclass used to show datalist suggestions for the table view
     26        containing the suggestions; then, select the given row, and invoke the action on the target.
     27
     28        (WTR::UIScriptControllerMac::dataListSuggestionsTableView const):
     29
    1302019-11-05  Daniel Bates  <dabates@apple.com>
    231
  • trunk/Tools/DumpRenderTree/mac/UIScriptControllerMac.h

    r251377 r252062  
    5151    NSUndoManager *platformUndoManager() const override;
    5252    void copyText(JSStringRef) override;
     53    void activateDataListSuggestion(long, JSValueRef) override;
    5354};
    5455
  • trunk/Tools/DumpRenderTree/mac/UIScriptControllerMac.mm

    r251377 r252062  
    101101}
    102102
     103void UIScriptControllerMac::activateDataListSuggestion(long index, JSValueRef callback)
     104{
     105    // FIXME: Not implemented.
     106    UNUSED_PARAM(index);
     107
     108    unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);
     109    dispatch_async(dispatch_get_main_queue(), ^{
     110        if (!m_context)
     111            return;
     112        m_context->asyncTaskComplete(callbackID);
     113    });
     114}
     115
    103116void UIScriptControllerMac::overridePreference(JSStringRef preferenceRef, JSStringRef valueRef)
    104117{
  • trunk/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl

    r251522 r252062  
    220220    // <datalist>
    221221    readonly attribute boolean isShowingDataListSuggestions;
     222    void activateDataListSuggestion(unsigned long index, object callback);
    222223
    223224    void keyboardAccessoryBarNext();
  • trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h

    r251522 r252062  
    202202    virtual void setDefaultCalendarType(JSStringRef calendarIdentifier) { notImplemented(); }
    203203    virtual JSObjectRef inputViewBounds() const { notImplemented(); return nullptr; }
     204    virtual void activateDataListSuggestion(long, JSValueRef) { notImplemented(); }
    204205
    205206    // Share Sheet
  • trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.h

    r252012 r252062  
    130130    void completeBackSwipe(JSValueRef) override;
    131131    bool isShowingDataListSuggestions() const override;
     132    void activateDataListSuggestion(long, JSValueRef) override;
    132133    void drawSquareInEditableImage() override;
    133134    long numberOfStrokesInEditableImage() override;
  • trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm

    r252012 r252062  
    10331033}
    10341034
     1035void UIScriptControllerIOS::activateDataListSuggestion(long index, JSValueRef callback)
     1036{
     1037    // FIXME: Not implemented.
     1038    UNUSED_PARAM(index);
     1039
     1040    unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);
     1041    dispatch_async(dispatch_get_main_queue(), ^{
     1042        if (!m_context)
     1043            return;
     1044        m_context->asyncTaskComplete(callbackID);
     1045    });
     1046}
     1047
    10351048bool UIScriptControllerIOS::isShowingDataListSuggestions() const
    10361049{
  • trunk/Tools/WebKitTestRunner/mac/UIScriptControllerMac.h

    r251279 r252062  
    4444    void simulateAccessibilitySettingsChangeNotification(JSValueRef) override;
    4545    bool isShowingDataListSuggestions() const override;
     46    void activateDataListSuggestion(long index, JSValueRef callback) override;
    4647    void beginBackSwipe(JSValueRef) override;
    4748    void completeBackSwipe(JSValueRef) override;
     
    5859
    5960    void activateAtPoint(long x, long y, JSValueRef callback) override;
     61
     62private:
     63    NSTableView *dataListSuggestionsTableView() const;
    6064};
    6165
  • trunk/Tools/WebKitTestRunner/mac/UIScriptControllerMac.mm

    r251279 r252062  
    2929#import "EventSenderProxy.h"
    3030#import "EventSerializerMac.h"
     31#import "PlatformViewHelpers.h"
    3132#import "PlatformWebView.h"
    3233#import "SharedEventStreamsMac.h"
     
    9798bool UIScriptControllerMac::isShowingDataListSuggestions() const
    9899{
     100    return dataListSuggestionsTableView();
     101}
     102
     103void UIScriptControllerMac::activateDataListSuggestion(long index, JSValueRef callback)
     104{
     105    unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);
     106
     107    RetainPtr<NSTableView> table;
     108    do {
     109        table = dataListSuggestionsTableView();
     110    } while (index >= [table numberOfRows] && [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]]);
     111
     112    [table selectRowIndexes:[NSIndexSet indexSetWithIndex:index] byExtendingSelection:NO];
     113
     114    // Send the action after a short delay to simulate normal user interaction.
     115    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_main_queue(), [this, protectedThis = makeRefPtr(*this), callbackID, table] {
     116        if ([table window])
     117            [table sendAction:[table action] to:[table target]];
     118
     119        if (!m_context)
     120            return;
     121        m_context->asyncTaskComplete(callbackID);
     122    });
     123}
     124
     125NSTableView *UIScriptControllerMac::dataListSuggestionsTableView() const
     126{
    99127    for (NSWindow *childWindow in webView().window.childWindows) {
    100128        if ([childWindow isKindOfClass:NSClassFromString(@"WKDataListSuggestionWindow")])
    101             return true;
    102     }
    103     return false;
     129            return (NSTableView *)[findAllViewsInHierarchyOfType(childWindow.contentView, NSClassFromString(@"WKDataListSuggestionTableView")) firstObject];
     130    }
     131    return nil;
    104132}
    105133
Note: See TracChangeset for help on using the changeset viewer.