Changeset 252022 in webkit


Ignore:
Timestamp:
Nov 4, 2019 3:48:46 PM (5 years ago)
Author:
Wenson Hsieh
Message:

REGRESSION (r248750): Drop-down menu for Walgreens 2FA unresponsive to touch
https://bugs.webkit.org/show_bug.cgi?id=203821
<rdar://problem/56550488>

Reviewed by Zalan Bujtas.

The dropdown in question in the Walgreens app uses UIWebView. In this report, tapping the dropdown menu (which
installs DOMTimers upon touchstart) no longer dispatches a click event. This reproduces in WebKit1, but not in
WebKit2.

After r248750, we no longer transition from IndeterminateChange to NoChange before calling out to the client
layer to report a deferred content observation change (in legacy WebKit, this is a call to the delegate method
-webView:didObserveDeferredContentChange:forFrame:).

In WebKit2, logic in WebPage::handleSyntheticClick handles indeterminate content changes after dispatching
mousemove by starting a fixed 32ms content observation timer, after the end of which we transition from
indeterminate to either NoChange or VisibilityChange, and call out to the client. This logic is absent in
WebKitLegacy, where we directly report the current content observation state to the client.

As such, the content change is still indeterminate when we finally call out to the client layer in the runloop
after dispatching the mousemove event in EventHandler::mouseMoved(). Client code in UIKit does not expect this,
and assumes that the given WKContentChange must either be NoChange or VisibilityChange; thus, it handles
indeterminate change as VisibilityChange and does not dispatch a click.

This legacy-WebKit-specific call to didFinishContentChangeObserving is intended to act as a failsafe to stop
content observation after mousemove, if any active timers scheduled during touchstart have already finished
executing. To fix this bug, instead of calling out to WebChromeClient::didFinishContentChangeObserving directly,
add a new method to ContentChangeObserver to inform it that a mousemove event has been handled; here, we call
notifyClientIfNeeded, which will transition the content change state from indeterminate to NoChange if needed
before calling out to the client.

No new test, because we don't have any mechanism for simulating user interaction in UIWebView (and inventing one
at this stage would have diminishing returns at best).

  • page/ios/ContentChangeObserver.cpp:

(WebCore::ContentChangeObserver::willNotProceedWithFixedObservationTimeWindow):
(WebCore::ContentChangeObserver::adjustObservedState):

  • page/ios/ContentChangeObserver.h:
  • page/ios/EventHandlerIOS.mm:

(WebCore::EventHandler::mouseMoved):

Replace the call to WebChromeClient::didFinishContentChangeObserving with a ContentChangeObserver method that
turns around and calls into notifyClientIfNeeded, via ContentChangeObserver::adjustObservedState.

Location:
trunk/Source/WebCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r252016 r252022  
     12019-11-04  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        REGRESSION (r248750): Drop-down menu for Walgreens 2FA unresponsive to touch
     4        https://bugs.webkit.org/show_bug.cgi?id=203821
     5        <rdar://problem/56550488>
     6
     7        Reviewed by Zalan Bujtas.
     8
     9        The dropdown in question in the Walgreens app uses UIWebView. In this report, tapping the dropdown menu (which
     10        installs DOMTimers upon touchstart) no longer dispatches a click event. This reproduces in WebKit1, but not in
     11        WebKit2.
     12
     13        After r248750, we no longer transition from IndeterminateChange to NoChange before calling out to the client
     14        layer to report a deferred content observation change (in legacy WebKit, this is a call to the delegate method
     15        -webView:didObserveDeferredContentChange:forFrame:).
     16
     17        In WebKit2, logic in WebPage::handleSyntheticClick handles indeterminate content changes after dispatching
     18        mousemove by starting a fixed 32ms content observation timer, after the end of which we transition from
     19        indeterminate to either NoChange or VisibilityChange, and call out to the client. This logic is absent in
     20        WebKitLegacy, where we directly report the current content observation state to the client.
     21
     22        As such, the content change is still indeterminate when we finally call out to the client layer in the runloop
     23        after dispatching the mousemove event in EventHandler::mouseMoved(). Client code in UIKit does not expect this,
     24        and assumes that the given WKContentChange must either be NoChange or VisibilityChange; thus, it handles
     25        indeterminate change as VisibilityChange and does not dispatch a click.
     26
     27        This legacy-WebKit-specific call to didFinishContentChangeObserving is intended to act as a failsafe to stop
     28        content observation after mousemove, if any active timers scheduled during touchstart have already finished
     29        executing. To fix this bug, instead of calling out to WebChromeClient::didFinishContentChangeObserving directly,
     30        add a new method to ContentChangeObserver to inform it that a mousemove event has been handled; here, we call
     31        notifyClientIfNeeded, which will transition the content change state from indeterminate to NoChange if needed
     32        before calling out to the client.
     33
     34        No new test, because we don't have any mechanism for simulating user interaction in UIWebView (and inventing one
     35        at this stage would have diminishing returns at best).
     36
     37        * page/ios/ContentChangeObserver.cpp:
     38        (WebCore::ContentChangeObserver::willNotProceedWithFixedObservationTimeWindow):
     39        (WebCore::ContentChangeObserver::adjustObservedState):
     40        * page/ios/ContentChangeObserver.h:
     41        * page/ios/EventHandlerIOS.mm:
     42        (WebCore::EventHandler::mouseMoved):
     43
     44        Replace the call to WebChromeClient::didFinishContentChangeObserving with a ContentChangeObserver method that
     45        turns around and calls into notifyClientIfNeeded, via ContentChangeObserver::adjustObservedState.
     46
    1472019-11-04  Chris Dumez  <cdumez@apple.com>
    248
  • trunk/Source/WebCore/page/ios/ContentChangeObserver.cpp

    r250326 r252022  
    471471}
    472472
     473void ContentChangeObserver::willNotProceedWithFixedObservationTimeWindow()
     474{
     475    ASSERT(!isMouseMovedEventBeingDispatched());
     476    adjustObservedState(Event::WillNotProceedWithFixedObservationTimeWindow);
     477}
     478
    473479void ContentChangeObserver::setShouldObserveNextStyleRecalc(bool shouldObserve)
    474480{
     
    562568            return;
    563569        }
     570        if (event == Event::WillNotProceedWithFixedObservationTimeWindow) {
     571            notifyClientIfNeeded();
     572            return;
     573        }
    564574    }
    565575    // These events (DOM timer, transition and style recalc) could trigger style changes that are candidates to visibility checking.
  • trunk/Source/WebCore/page/ios/ContentChangeObserver.h

    r248790 r252022  
    7272    void willNotProceedWithClick();
    7373
     74    void willNotProceedWithFixedObservationTimeWindow();
     75
    7476    void setHiddenTouchTarget(Element& targetElement) { m_hiddenTouchTargetElement = makeWeakPtr(targetElement); }
    7577    void resetHiddenTouchTarget() { m_hiddenTouchTargetElement = { }; }
     
    198200        StartedFixedObservationTimeWindow,
    199201        EndedFixedObservationTimeWindow,
     202        WillNotProceedWithFixedObservationTimeWindow,
    200203        ElementDidBecomeVisible
    201204    };
  • trunk/Source/WebCore/page/ios/EventHandlerIOS.mm

    r247926 r252022  
    504504            // This is called by WebKitLegacy only.
    505505            if (auto* document = protectedFrame->document())
    506                 document->page()->chrome().client().didFinishContentChangeObserving(*document->frame(), document->contentChangeObserver().observedContentChange());
     506                document->contentChangeObserver().willNotProceedWithFixedObservationTimeWindow();
    507507        });
    508508    }
Note: See TracChangeset for help on using the changeset viewer.