Changeset 247530 in webkit


Ignore:
Timestamp:
Jul 17, 2019 1:06:04 PM (5 years ago)
Author:
dbates@webkit.org
Message:

Typing into a cell in a Google Sheet lags behind by one character
https://bugs.webkit.org/show_bug.cgi?id=199587
<rdar://problem/51616845>

Reviewed by Brent Fulgham.

Source/WebCore:

Add a Google Sheets quirk. Put all DOM timers scheduled from keydown and keypress event listeners
into a holding tank. The timers continue to tick, but are barred from executing their action until
the next text insertion or deletion or 32 ms (on device) have elapsed, whichever is sooner. We only
allocate a holding tank once per document, only if the quirk is active, and this allocation is done
when the document schedules a timer on keydown or keypress. The holding tank lives for the lifetime
of the document.

The story behind the quirk:

On keypress Google Sheets schedules timers and expects that a DOM update will occur (i.e. text
will be inserted or deleted) within the same event loop iteration as the dispatched keypress. The
UI Events spec. [1] makes no such guarantee of when a DOM update must occur in relation to the keypress
event. It could happen in the same event loop iteration as the key press (as Google expects), the
next iteration, 500ms later, 2 minutes later, etc. What the spec does guarantee is that by the time
a DOM input event is dispatched that the DOM will be updated. And this is the solution to the problem
Google Sheets is trying to solve, but is doing so using pre-IE 9 technology (though similar
functionality was available via onpropertychange in IE < 9).

See also <https://github.com/w3c/uievents/issues/238>, which is tracking a spec. text update for
this quirk.

Test: fast/events/ios/dom-update-on-keydown-quirk.html

[1] <https://w3c.github.io/uievents/> (Editor's Draft, 14 October 2018)

  • SourcesCocoa.txt:
  • WebCore.xcodeproj/project.pbxproj:

Add some files to the project.

  • dom/Document.cpp:

(WebCore::Document::domTimerHoldingTank): Added.

  • dom/Document.h:

(WebCore::Document::domTimerHoldingTankIfExists): Added.

  • page/DOMTimer.cpp:

(WebCore::DOMTimer::install): Put the newly instantiated timer into the holding tank.
(WebCore::DOMTimer::removeById): Remove the timer from the holding tank.
(WebCore::DOMTimer::fired): Check if the timer is in the holding tank. If it is and it is a one-
shot timer then schedule it for the next event loop iteration. If it's a repeating timer just
let it continue ticking. Otherwise, do what we no now and execute the timer's action. The reason
we do not suspend timers in the holding tank is because:

  1. Far out timers (Google Sheets registers timers as far out as 5 minutes!) are not penalized. Though smart supension logic could avoid this. See (3).
  1. Empirical observations indicate that the keyboard will perform the insertion or deletion reasonably quickly (not the same event loop iteration as the keydown, but within two iterations out). So, the timers in the holding tank are short-lived.
  1. Simplifies the code. There is no need to keep additional bookkeeping to track multiple timer suspension reasons (timers currently can only have one suspension reason) or alternatively defer scheduling a timer until a later time and computing a new "fair" firing time when scheduled.
  • page/EventHandler.cpp:

(WebCore::EventHandler::internalKeyEvent): Place a token on the stack to put all DOM timers
scheduled on keydown and keypress into the holding tank if the quirk is enabled.

  • page/Quirks.cpp:

(WebCore::Quirks::needsDeferKeyDownAndKeyPressTimersUntilNextEditingCommand const): Added.

  • page/Quirks.h:
  • page/Settings.yaml: Added setting so that this quirk can be enabled from a layout test. This setting

also lets us enable the quirk for all sites or for certain third-party apps if desired.

  • page/ios/DOMTimerHoldingTank.cpp: Added.

(WebCore::DOMTimerHoldingTank::DOMTimerHoldingTank):
(WebCore::DOMTimerHoldingTank::add):
(WebCore::DOMTimerHoldingTank::remove):
(WebCore::DOMTimerHoldingTank::contains):
(WebCore::DOMTimerHoldingTank::removeAll):
(WebCore::DOMTimerHoldingTank::stopExceededMaximumHoldTimer):

  • page/ios/DOMTimerHoldingTank.h: Added.

(WebCore::DeferDOMTimersForScope::DeferDOMTimersForScope):
(WebCore::DeferDOMTimersForScope::~DeferDOMTimersForScope):
(WebCore::DeferDOMTimersForScope::isDeferring):

Source/WebKit:

Remove all timers from the holding tank on text insertion or deletion (represented as an
editing command). Timers that were in the holding tank never stopped ticking and will now
be able to execute their action.

  • WebProcess/WebPage/WebPage.cpp:

(WebKit::WebPage::executeEditingCommand):
(WebKit::WebPage::insertTextAsync):
(WebKit::WebPage::setCompositionAsync):
(WebKit::WebPage::confirmCompositionAsync):
Call platformWillPerformEditingCommand().

  • WebProcess/WebPage/WebPage.h:

(WebKit::WebPage::platformWillPerformEditingCommand): Added.

  • WebProcess/WebPage/ios/WebPageIOS.mm:

(WebKit::WebPage::platformWillPerformEditingCommand): Remove all the timers from the holding
tank if we have a holding tank.

LayoutTests:

Add a test that enables the quirk and ensures that the DOM is up-to-date on expiration of a
zero timer scheduled from keydown, keypress, keyup, and input.

  • fast/events/ios/dom-update-on-keydown-quirk-expected.txt: Added.
  • fast/events/ios/dom-update-on-keydown-quirk.html: Added.
Location:
trunk
Files:
4 added
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r247528 r247530  
     12019-07-17  Daniel Bates  <dabates@apple.com>
     2
     3        Typing into a cell in a Google Sheet lags behind by one character
     4        https://bugs.webkit.org/show_bug.cgi?id=199587
     5        <rdar://problem/51616845>
     6
     7        Reviewed by Brent Fulgham.
     8
     9        Add a test that enables the quirk and ensures that the DOM is up-to-date on expiration of a
     10        zero timer scheduled from keydown, keypress, keyup, and input.
     11
     12        * fast/events/ios/dom-update-on-keydown-quirk-expected.txt: Added.
     13        * fast/events/ios/dom-update-on-keydown-quirk.html: Added.
     14
    1152019-07-17  Myles C. Maxfield  <mmaxfield@apple.com>
    216
  • trunk/Source/WebCore/ChangeLog

    r247529 r247530  
     12019-07-17  Daniel Bates  <dabates@apple.com>
     2
     3        Typing into a cell in a Google Sheet lags behind by one character
     4        https://bugs.webkit.org/show_bug.cgi?id=199587
     5        <rdar://problem/51616845>
     6
     7        Reviewed by Brent Fulgham.
     8
     9        Add a Google Sheets quirk. Put all DOM timers scheduled from keydown and keypress event listeners
     10        into a holding tank. The timers continue to tick, but are barred from executing their action until
     11        the next text insertion or deletion or 32 ms (on device) have elapsed, whichever is sooner. We only
     12        allocate a holding tank once per document, only if the quirk is active, and this allocation is done
     13        when the document schedules a timer on keydown or keypress. The holding tank lives for the lifetime
     14        of the document.
     15
     16        The story behind the quirk:
     17
     18        On keypress Google Sheets schedules timers and expects that a DOM update will occur (i.e. text
     19        will be inserted or deleted) within the same event loop iteration as the dispatched keypress. The
     20        UI Events spec. [1] makes no such guarantee of when a DOM update must occur in relation to the keypress
     21        event. It could happen in the same event loop iteration as the key press (as Google expects), the
     22        next iteration, 500ms later, 2 minutes later, etc. What the spec does guarantee is that by the time
     23        a DOM input event is dispatched that the DOM will be updated. And this is the solution to the problem
     24        Google Sheets is trying to solve, but is doing so using pre-IE 9 technology (though similar
     25        functionality was available via onpropertychange in IE < 9).
     26
     27        See also <https://github.com/w3c/uievents/issues/238>, which is tracking a spec. text update for
     28        this quirk.
     29
     30        Test: fast/events/ios/dom-update-on-keydown-quirk.html
     31
     32        [1] <https://w3c.github.io/uievents/> (Editor's Draft, 14 October 2018)
     33
     34        * SourcesCocoa.txt:
     35        * WebCore.xcodeproj/project.pbxproj:
     36        Add some files to the project.
     37
     38        * dom/Document.cpp:
     39        (WebCore::Document::domTimerHoldingTank): Added.
     40        * dom/Document.h:
     41        (WebCore::Document::domTimerHoldingTankIfExists): Added.
     42
     43        * page/DOMTimer.cpp:
     44        (WebCore::DOMTimer::install): Put the newly instantiated timer into the holding tank.
     45        (WebCore::DOMTimer::removeById): Remove the timer from the holding tank.
     46        (WebCore::DOMTimer::fired): Check if the timer is in the holding tank. If it is and it is a one-
     47        shot timer then schedule it for the next event loop iteration. If it's a repeating timer just
     48        let it continue ticking. Otherwise, do what we no now and execute the timer's action. The reason
     49        we do not suspend timers in the holding tank is because:
     50            1. Far out timers (Google Sheets registers timers as far out as 5 minutes!) are not penalized.
     51            Though smart supension logic could avoid this. See (3).
     52
     53            2. Empirical observations indicate that the keyboard will perform the insertion or deletion
     54            reasonably quickly (not the same event loop iteration as the keydown, but within two iterations out).
     55            So, the timers in the holding tank are short-lived.
     56
     57            3. Simplifies the code. There is no need to keep additional bookkeeping to track multiple timer
     58            suspension reasons (timers currently can only have one suspension reason) or alternatively defer
     59            scheduling a timer until a later time and computing a new "fair" firing time when scheduled.
     60        * page/EventHandler.cpp:
     61        (WebCore::EventHandler::internalKeyEvent): Place a token on the stack to put all DOM timers
     62        scheduled on keydown and keypress into the holding tank if the quirk is enabled.
     63        * page/Quirks.cpp:
     64        (WebCore::Quirks::needsDeferKeyDownAndKeyPressTimersUntilNextEditingCommand const): Added.
     65        * page/Quirks.h:
     66        * page/Settings.yaml: Added setting so that this quirk can be enabled from a layout test. This setting
     67        also lets us enable the quirk for all sites or for certain third-party apps if desired.
     68        * page/ios/DOMTimerHoldingTank.cpp: Added.
     69        (WebCore::DOMTimerHoldingTank::DOMTimerHoldingTank):
     70        (WebCore::DOMTimerHoldingTank::add):
     71        (WebCore::DOMTimerHoldingTank::remove):
     72        (WebCore::DOMTimerHoldingTank::contains):
     73        (WebCore::DOMTimerHoldingTank::removeAll):
     74        (WebCore::DOMTimerHoldingTank::stopExceededMaximumHoldTimer):
     75        * page/ios/DOMTimerHoldingTank.h: Added.
     76        (WebCore::DeferDOMTimersForScope::DeferDOMTimersForScope):
     77        (WebCore::DeferDOMTimersForScope::~DeferDOMTimersForScope):
     78        (WebCore::DeferDOMTimersForScope::isDeferring):
     79
    1802019-07-17  Darin Adler  <darin@apple.com>
    281
  • trunk/Source/WebCore/SourcesCocoa.txt

    r247472 r247530  
    132132
    133133page/ios/ContentChangeObserver.cpp
     134page/ios/DOMTimerHoldingTank.cpp
    134135page/ios/EventHandlerIOS.mm
    135136page/ios/FrameIOS.mm
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r247527 r247530  
    41484148                CE08C3D2152B599A0021B8C2 /* AlternativeTextController.h in Headers */ = {isa = PBXBuildFile; fileRef = CE08C3D0152B599A0021B8C2 /* AlternativeTextController.h */; settings = {ATTRIBUTES = (); }; };
    41494149                CE1866451F72E5B400A0CAB6 /* MarkedText.h in Headers */ = {isa = PBXBuildFile; fileRef = CE1866431F72E5B400A0CAB6 /* MarkedText.h */; settings = {ATTRIBUTES = (Private, ); }; };
     4150                CE1A501F22D5350900CBC927 /* DOMTimerHoldingTank.h in Headers */ = {isa = PBXBuildFile; fileRef = CE1A501D22D5350900CBC927 /* DOMTimerHoldingTank.h */; settings = {ATTRIBUTES = (Private, ); }; };
    41504151                CE2849871CA360DF00B4A57F /* ContentSecurityPolicyDirectiveNames.h in Headers */ = {isa = PBXBuildFile; fileRef = CE2849861CA360DF00B4A57F /* ContentSecurityPolicyDirectiveNames.h */; };
    41514152                CE5169E721F1B84700EA4F78 /* ColorIOS.h in Headers */ = {isa = PBXBuildFile; fileRef = CE5169E521F1B84700EA4F78 /* ColorIOS.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    1381313814                CE1866421F72E5B400A0CAB6 /* MarkedText.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MarkedText.cpp; sourceTree = "<group>"; };
    1381413815                CE1866431F72E5B400A0CAB6 /* MarkedText.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MarkedText.h; sourceTree = "<group>"; };
     13816                CE1A501D22D5350900CBC927 /* DOMTimerHoldingTank.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DOMTimerHoldingTank.h; sourceTree = "<group>"; };
     13817                CE1A501E22D5350900CBC927 /* DOMTimerHoldingTank.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DOMTimerHoldingTank.cpp; sourceTree = "<group>"; };
    1381513818                CE2849861CA360DF00B4A57F /* ContentSecurityPolicyDirectiveNames.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ContentSecurityPolicyDirectiveNames.h; path = csp/ContentSecurityPolicyDirectiveNames.h; sourceTree = "<group>"; };
    1381613819                CE2849881CA3614600B4A57F /* ContentSecurityPolicyDirectiveNames.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ContentSecurityPolicyDirectiveNames.cpp; path = csp/ContentSecurityPolicyDirectiveNames.cpp; sourceTree = "<group>"; };
     
    1654816551                                6FE9F09222211035004C5082 /* ContentChangeObserver.cpp */,
    1654916552                                6FB5E212221F2447003989CF /* ContentChangeObserver.h */,
     16553                                CE1A501E22D5350900CBC927 /* DOMTimerHoldingTank.cpp */,
     16554                                CE1A501D22D5350900CBC927 /* DOMTimerHoldingTank.h */,
    1655016555                                FE6938B51045D67E008EABB6 /* EventHandlerIOS.mm */,
    1655116556                                FED13D3B0CEA936A00D89466 /* FrameIOS.mm */,
     
    2901229017                                BC64640A11D7F304006455B0 /* DOMStringMap.h in Headers */,
    2901329018                                188604B40F2E654A000B6443 /* DOMTimer.h in Headers */,
     29019                                CE1A501F22D5350900CBC927 /* DOMTimerHoldingTank.h in Headers */,
    2901429020                                05FD69E012845D4300B2BEB3 /* DOMTimeStamp.h in Headers */,
    2901529021                                76FC2B0C12370DA0006A991A /* DOMTokenList.h in Headers */,
  • trunk/Source/WebCore/dom/Document.cpp

    r247529 r247530  
    263263#include "ContentChangeObserver.h"
    264264#include "CSSFontSelector.h"
     265#include "DOMTimerHoldingTank.h"
    265266#include "DeviceMotionClientIOS.h"
    266267#include "DeviceMotionController.h"
     
    81838184
    81848185#if PLATFORM(IOS_FAMILY)
     8186
    81858187ContentChangeObserver& Document::contentChangeObserver()
    81868188{
     
    81898191    return *m_contentChangeObserver;
    81908192}
     8193
     8194DOMTimerHoldingTank& Document::domTimerHoldingTank()
     8195{
     8196    if (m_domTimerHoldingTank)
     8197        return *m_domTimerHoldingTank;
     8198    m_domTimerHoldingTank = std::make_unique<DOMTimerHoldingTank>();
     8199    return *m_domTimerHoldingTank;
     8200}
     8201
    81918202#endif
    81928203
  • trunk/Source/WebCore/dom/Document.h

    r247472 r247530  
    107107class DOMImplementation;
    108108class DOMSelection;
     109class DOMTimerHoldingTank;
    109110class DOMWindow;
    110111class DOMWrapperWorld;
     
    884885
    885886    WEBCORE_EXPORT ContentChangeObserver& contentChangeObserver();
     887
     888    DOMTimerHoldingTank* domTimerHoldingTankIfExists() { return m_domTimerHoldingTank.get(); }
     889    DOMTimerHoldingTank& domTimerHoldingTank();
    886890#endif
    887891   
     
    20452049#if PLATFORM(IOS_FAMILY)
    20462050    std::unique_ptr<ContentChangeObserver> m_contentChangeObserver;
     2051    std::unique_ptr<DOMTimerHoldingTank> m_domTimerHoldingTank;
    20472052#endif
    20482053
  • trunk/Source/WebCore/page/DOMTimer.cpp

    r247472 r247530  
    4444#if PLATFORM(IOS_FAMILY)
    4545#include "ContentChangeObserver.h"
     46#include "DOMTimerHoldingTank.h"
    4647#endif
    4748
     
    197198        nestedTimers->add(timer->m_timeoutId, *timer);
    198199#if PLATFORM(IOS_FAMILY)
    199     if (is<Document>(context))
    200         downcast<Document>(context).contentChangeObserver().didInstallDOMTimer(*timer, timeout, singleShot);
     200    if (is<Document>(context)) {
     201        auto& document = downcast<Document>(context);
     202        document.contentChangeObserver().didInstallDOMTimer(*timer, timeout, singleShot);
     203        if (DeferDOMTimersForScope::isDeferring())
     204            document.domTimerHoldingTank().add(*timer);
     205    }
    201206#endif
    202207    return timer->m_timeoutId;
     
    214219    if (is<Document>(context)) {
    215220        auto& document = downcast<Document>(context);
    216         if (auto* timer = document.findTimeout(timeoutId))
     221        if (auto* timer = document.findTimeout(timeoutId)) {
    217222            document.contentChangeObserver().didRemoveDOMTimer(*timer);
     223            if (auto* holdingTank = document.domTimerHoldingTankIfExists())
     224                holdingTank->remove(*timer);
     225        }
    218226    }
    219227#endif
     
    284292    ASSERT(scriptExecutionContext());
    285293    ScriptExecutionContext& context = *scriptExecutionContext();
     294
     295#if PLATFORM(IOS_FAMILY)
     296    if (is<Document>(context)) {
     297        auto& document = downcast<Document>(context);
     298        if (auto* holdingTank = document.domTimerHoldingTankIfExists(); holdingTank && holdingTank->contains(*this)) {
     299            if (!repeatInterval())
     300                startOneShot(0_s);
     301            return;
     302        }
     303    }
     304#endif
    286305
    287306    DOMTimerFireState fireState(context, std::min(m_nestingLevel + 1, maxTimerNestingLevel));
  • trunk/Source/WebCore/page/EventHandler.cpp

    r247472 r247530  
    132132#endif
    133133
     134#if PLATFORM(IOS_FAMILY)
     135#include "DOMTimerHoldingTank.h"
     136#endif
     137
    134138namespace WebCore {
    135139
     
    33423346        keydown->stopPropagation();
    33433347
     3348#if PLATFORM(IOS_FAMILY)
     3349    DeferDOMTimersForScope deferralScope { m_frame.document()->quirks().needsDeferKeyDownAndKeyPressTimersUntilNextEditingCommand() };
     3350#endif
     3351
    33443352    element->dispatchEvent(keydown);
    33453353    if (handledByInputMethod)
  • trunk/Source/WebCore/page/Quirks.cpp

    r247472 r247530  
    318318}
    319319
     320bool Quirks::needsDeferKeyDownAndKeyPressTimersUntilNextEditingCommand() const
     321{
     322#if PLATFORM(IOS_FAMILY)
     323    if (m_document->settings().needsDeferKeyDownAndKeyPressTimersUntilNextEditingCommandQuirk())
     324        return true;
     325
     326    if (!needsQuirks())
     327        return false;
     328
     329    auto& url = m_document->topDocument().url();
     330    return equalLettersIgnoringASCIICase(url.host(), "docs.google.com") && url.path().startsWithIgnoringASCIICase("/spreadsheets/");
     331#else
     332    return false;
     333#endif
     334}
     335
    320336// FIXME(<rdar://problem/50394969>): Remove after desmos.com adopts inputmode="none".
    321337bool Quirks::needsInputModeNoneImplicitly(const HTMLElement& element) const
  • trunk/Source/WebCore/page/Quirks.h

    r247472 r247530  
    5555    bool shouldDisablePointerEventsQuirk() const;
    5656    bool needsInputModeNoneImplicitly(const HTMLElement&) const;
     57    bool needsDeferKeyDownAndKeyPressTimersUntilNextEditingCommand() const;
    5758
    5859    WEBCORE_EXPORT bool shouldDispatchSyntheticMouseEventsWhenModifyingSelection() const;
  • trunk/Source/WebCore/page/Settings.yaml

    r247472 r247530  
    163163  initial: false
    164164
     165# This is an iOS-specific quirk. Unlike Mac, keyboard operations are asynchronous and hence a DOM update as
     166# a result of text insertion or deletion does not occur within the same event loop iteration as a dispatched
     167# DOM keydown event. Some sites, notably Google Sheets, schedule timers on keypress and expect on a DOM update
     168# to have occurred on expiration. When enabled, this quirk puts all such scheduled timers in a holding tank
     169# until the keyboard performs the insertion or deletion. This gives Google Sheets the illusion that the DOM
     170# update happened within the same event loop iteration that the keypress event was dispatched in.
     171needsDeferKeyDownAndKeyPressTimersUntilNextEditingCommandQuirk:
     172  initial: false
     173
    165174treatsAnyTextCSSLinkAsStylesheet:
    166175  initial: false
  • trunk/Source/WebKit/ChangeLog

    r247529 r247530  
     12019-07-17  Daniel Bates  <dabates@apple.com>
     2
     3        Typing into a cell in a Google Sheet lags behind by one character
     4        https://bugs.webkit.org/show_bug.cgi?id=199587
     5        <rdar://problem/51616845>
     6
     7        Reviewed by Brent Fulgham.
     8
     9        Remove all timers from the holding tank on text insertion or deletion (represented as an
     10        editing command). Timers that were in the holding tank never stopped ticking and will now
     11        be able to execute their action.
     12
     13        * WebProcess/WebPage/WebPage.cpp:
     14        (WebKit::WebPage::executeEditingCommand):
     15        (WebKit::WebPage::insertTextAsync):
     16        (WebKit::WebPage::setCompositionAsync):
     17        (WebKit::WebPage::confirmCompositionAsync):
     18        Call platformWillPerformEditingCommand().
     19
     20        * WebProcess/WebPage/WebPage.h:
     21        (WebKit::WebPage::platformWillPerformEditingCommand): Added.
     22        * WebProcess/WebPage/ios/WebPageIOS.mm:
     23        (WebKit::WebPage::platformWillPerformEditingCommand): Remove all the timers from the holding
     24        tank if we have a holding tank.
     25
    1262019-07-17  Darin Adler  <darin@apple.com>
    227
  • trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp

    r247490 r247530  
    12611261void WebPage::executeEditingCommand(const String& commandName, const String& argument)
    12621262{
    1263     Frame& frame = m_page->focusController().focusedOrMainFrame();
     1263    platformWillPerformEditingCommand();
     1264
     1265    auto& frame = m_page->focusController().focusedOrMainFrame();
    12641266
    12651267    if (PluginView* pluginView = focusedPluginViewForFrame(frame)) {
     
    51765178void WebPage::insertTextAsync(const String& text, const EditingRange& replacementEditingRange, InsertTextOptions&& options)
    51775179{
    5178     Frame& frame = m_page->focusController().focusedOrMainFrame();
     5180    platformWillPerformEditingCommand();
     5181
     5182    auto& frame = m_page->focusController().focusedOrMainFrame();
    51795183
    51805184    Ref<Frame> protector(frame);
     
    52505254void WebPage::setCompositionAsync(const String& text, const Vector<CompositionUnderline>& underlines, const EditingRange& selection, const EditingRange& replacementEditingRange)
    52515255{
    5252     Frame& frame = m_page->focusController().focusedOrMainFrame();
     5256    platformWillPerformEditingCommand();
     5257
     5258    auto& frame = m_page->focusController().focusedOrMainFrame();
    52535259
    52545260    if (frame.selection().selection().isContentEditable()) {
     
    52665272void WebPage::confirmCompositionAsync()
    52675273{
     5274    platformWillPerformEditingCommand();
     5275
    52685276    Frame& frame = m_page->focusController().focusedOrMainFrame();
    52695277    frame.editor().confirmComposition();
  • trunk/Source/WebKit/WebProcess/WebPage/WebPage.h

    r247490 r247530  
    12261226    void platformDetach();
    12271227    void platformEditorState(WebCore::Frame&, EditorState& result, IncludePostLayoutDataHint) const;
     1228    void platformWillPerformEditingCommand();
    12281229    void sendEditorStateUpdate();
    12291230
     
    19581959};
    19591960
     1961#if !PLATFORM(IOS_FAMILY)
     1962inline void WebPage::platformWillPerformEditingCommand() { }
     1963#endif
     1964
    19601965} // namespace WebKit
    19611966
  • trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm

    r247483 r247530  
    6464#import <WebCore/Chrome.h>
    6565#import <WebCore/ContentChangeObserver.h>
     66#import <WebCore/DOMTimerHoldingTank.h>
    6667#import <WebCore/DataDetection.h>
    6768#import <WebCore/DiagnosticLoggingClient.h>
     
    276277}
    277278
     279void WebPage::platformWillPerformEditingCommand()
     280{
     281    auto& frame = m_page->focusController().focusedOrMainFrame();
     282    if (auto* document = frame.document()) {
     283        if (auto* holdingTank = document->domTimerHoldingTankIfExists())
     284            holdingTank->removeAll();
     285    }
     286}
     287
    278288FloatSize WebPage::screenSize() const
    279289{
Note: See TracChangeset for help on using the changeset viewer.