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

Changeset 285781 in webkit


Ignore:
Timestamp:
Nov 13, 2021, 3:04:06 PM (5 years ago)
Author:
Simon Fraser
Message:

Implement UIScriptController.sendEventStream() for DumpRenderTree
https://bugs.webkit.org/show_bug.cgi?id=233090

Reviewed by Wenson Hsieh.
Tools:

Implement UIScriptControllerMac::sendEventStream(), sharing some event dispatching code from
EventSendingController.

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

(-[EventSendingController mouseScrollByX:andY:withWheel:andMomentumPhases:]):
(-[EventSendingController sendScrollEventAt:deltaX:deltaY:units:wheelPhase:momentumPhase:timestamp:]):

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

(WTR::gesturePhaseFromString):
(WTR::momentumPhaseFromString):
(WTR::eventSenderFromView):
(WTR::UIScriptControllerMac::sendEventStream):

LayoutTests:

Convert one test that runs in WK1 to use sendEventStream().

  • fast/scrolling/overflow-scroll-past-max.html:
  • resources/ui-helper.js:
Location:
trunk
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r285778 r285781  
     12021-11-13  Simon Fraser  <simon.fraser@apple.com>
     2
     3        Implement UIScriptController.sendEventStream() for DumpRenderTree
     4        https://bugs.webkit.org/show_bug.cgi?id=233090
     5
     6        Reviewed by Wenson Hsieh.
     7
     8        Convert one test that runs in WK1 to use sendEventStream().
     9
     10        * fast/scrolling/overflow-scroll-past-max.html:
     11        * resources/ui-helper.js:
     12
    1132021-11-13  Tyler Wilcock  <tyler_w@apple.com>
    214
  • trunk/LayoutTests/fast/scrolling/overflow-scroll-past-max.html

    r194486 r285781  
    1717        }
    1818    </style>
     19    <script src="../../resources/ui-helper.js"></script>
    1920    <script>
    2021        function checkForScroll()
     
    3132        }
    3233       
    33         function scrollTest()
     34        async function scrollTest()
    3435        {
    35             eventSender.mouseMoveTo(20, 20);
    36             eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -1, "began", "none");
    37             eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -100, "changed", "none");
    38             eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -100, "changed", "none");
    39             eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -1, "changed", "none");
    40             eventSender.mouseScrollByWithWheelAndMomentumPhases(0, 0, "ended", "none");
    41             eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -100, "none", "begin");
    42             eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -100, "none", "continue");
    43             eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -100, "none", "continue");
    44             eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -100, "none", "continue");
    45             eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -100, "none", "continue");
    46             eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -100, "none", "continue");
    47             eventSender.mouseScrollByWithWheelAndMomentumPhases(0, 0, "none", "end");
    48             eventSender.callAfterScrollingCompletes(checkForScroll);
     36            const events = [
     37                {
     38                    type : "wheel",
     39                    viewX : 20,
     40                    viewY : 20,
     41                    deltaY : -10,
     42                    phase : "began"
     43                },
     44                {
     45                    type : "wheel",
     46                    deltaY : -1000,
     47                    phase : "changed"
     48                },
     49                {
     50                    type : "wheel",
     51                    deltaY : -1000,
     52                    phase : "changed"
     53                },
     54                {
     55                    type : "wheel",
     56                    deltaY : -10,
     57                    phase : "changed"
     58                },
     59                {
     60                    type : "wheel",
     61                    phase : "ended"
     62                },
     63                {
     64                    type : "wheel",
     65                    deltaY : -1000,
     66                    momentumPhase : "began"
     67                },
     68                {
     69                    type : "wheel",
     70                    deltaY : -1000,
     71                    momentumPhase : "began"
     72                },
     73                {
     74                    type : "wheel",
     75                    deltaY : -1000,
     76                    momentumPhase : "began"
     77                },
     78                {
     79                    type : "wheel",
     80                    deltaY : -1000,
     81                    momentumPhase : "began"
     82                },
     83                {
     84                    type : "wheel",
     85                    deltaY : -1000,
     86                    momentumPhase : "began"
     87                },
     88                {
     89                    type : "wheel",
     90                    deltaY : -1000,
     91                    momentumPhase : "began"
     92                },
     93                {
     94                    type : "wheel",
     95                    momentumPhase : "ended"
     96                }
     97            ];
     98
     99            await UIHelper.mouseWheelSequence({ events: events });
     100            checkForScroll();
    49101        }
    50102
  • trunk/LayoutTests/resources/ui-helper.js

    r285498 r285781  
    111111    static async mouseWheelSequence(eventStream, { waitForCompletion = true } = {})
    112112    {
    113         if (!this.isWebKit2()) {
    114             console.log('UIHelper.mouseWheelSequence() does not work in DumpRenderTree')
    115             return Promise.resolve();
    116         }
    117 
    118113        if (waitForCompletion)
    119114            eventSender.monitorWheelEvents();
  • trunk/Tools/ChangeLog

    r285779 r285781  
     12021-11-13  Simon Fraser  <simon.fraser@apple.com>
     2
     3        Implement UIScriptController.sendEventStream() for DumpRenderTree
     4        https://bugs.webkit.org/show_bug.cgi?id=233090
     5
     6        Reviewed by Wenson Hsieh.
     7       
     8        Implement UIScriptControllerMac::sendEventStream(), sharing some event dispatching code from
     9        EventSendingController.
     10
     11        * DumpRenderTree/mac/EventSendingController.h:
     12        * DumpRenderTree/mac/EventSendingController.mm:
     13        (-[EventSendingController mouseScrollByX:andY:withWheel:andMomentumPhases:]):
     14        (-[EventSendingController sendScrollEventAt:deltaX:deltaY:units:wheelPhase:momentumPhase:timestamp:]):
     15        * DumpRenderTree/mac/UIScriptControllerMac.h:
     16        * DumpRenderTree/mac/UIScriptControllerMac.mm:
     17        (WTR::gesturePhaseFromString):
     18        (WTR::momentumPhaseFromString):
     19        (WTR::eventSenderFromView):
     20        (WTR::UIScriptControllerMac::sendEventStream):
     21
    1222021-11-13  Jonathan Bedard  <jbedard@apple.com>
    223
  • trunk/Tools/DumpRenderTree/mac/EventSendingController.h

    r260334 r285781  
    5959- (void)handleEvent:(DOMEvent *)event;
    6060
     61#if PLATFORM(MAC)
     62// Timestamp is mach_absolute_time() units.
     63- (void)sendScrollEventAt:(NSPoint)mouseLocation deltaX:(double)deltaX deltaY:(double)deltaY units:(CGScrollEventUnit)units wheelPhase:(CGGesturePhase)wheelPhase momentumPhase:(CGMomentumScrollPhase)momentumPhase timestamp:(uint64_t)timestamp;
     64#endif
     65
    6166@end
    6267
  • trunk/Tools/DumpRenderTree/mac/EventSendingController.mm

    r284575 r285781  
    842842}
    843843
    844 - (void)mouseScrollByX:(int)x andY:(int)y withWheel:(NSString*)phaseName andMomentumPhases:(NSString*)momentumName
     844- (void)mouseScrollByX:(int)x andY:(int)y withWheel:(NSString*)wheelPhase andMomentumPhases:(NSString*)momentumPhase
    845845{
    846846#if PLATFORM(MAC)
    847847    [[[mainFrame frameView] documentView] layout];
    848848
    849     uint32_t phase = 0;
    850     if ([phaseName isEqualToString: @"none"])
    851         phase = 0;
    852     else if ([phaseName isEqualToString: @"began"])
    853         phase = kCGScrollPhaseBegan;
    854     else if ([phaseName isEqualToString: @"changed"])
    855         phase = kCGScrollPhaseChanged;
    856     else if ([phaseName isEqualToString: @"ended"])
    857         phase = kCGScrollPhaseEnded;
    858     else if ([phaseName isEqualToString: @"cancelled"])
    859         phase = kCGScrollPhaseCancelled;
    860     else if ([phaseName isEqualToString: @"maybegin"])
    861         phase = kCGScrollPhaseMayBegin;
    862 
    863     uint32_t momentum = 0;
    864     if ([momentumName isEqualToString: @"none"])
     849    CGGesturePhase phase = kCGGesturePhaseNone;
     850    if ([wheelPhase isEqualToString: @"none"])
     851        phase = kCGGesturePhaseNone;
     852    else if ([wheelPhase isEqualToString: @"began"])
     853        phase = kCGGesturePhaseBegan;
     854    else if ([wheelPhase isEqualToString: @"changed"])
     855        phase = kCGGesturePhaseChanged;
     856    else if ([wheelPhase isEqualToString: @"ended"])
     857        phase = kCGGesturePhaseEnded;
     858    else if ([wheelPhase isEqualToString: @"cancelled"])
     859        phase = kCGGesturePhaseCancelled;
     860    else if ([wheelPhase isEqualToString: @"maybegin"])
     861        phase = kCGGesturePhaseMayBegin;
     862
     863    CGMomentumScrollPhase momentum = kCGMomentumScrollPhaseNone;
     864    if ([momentumPhase isEqualToString: @"none"])
    865865        momentum = kCGMomentumScrollPhaseNone;
    866     else if ([momentumName isEqualToString:@"begin"])
     866    else if ([momentumPhase isEqualToString:@"begin"])
    867867        momentum = kCGMomentumScrollPhaseBegin;
    868     else if ([momentumName isEqualToString:@"continue"])
     868    else if ([momentumPhase isEqualToString:@"continue"])
    869869        momentum = kCGMomentumScrollPhaseContinue;
    870     else if ([momentumName isEqualToString:@"end"])
     870    else if ([momentumPhase isEqualToString:@"end"])
    871871        momentum = kCGMomentumScrollPhaseEnd;
    872872
    873     if (phase == kCGScrollPhaseEnded || phase == kCGScrollPhaseCancelled)
     873    // FIXME: Maybe use a valid timestamp: webkit.org/b/232791.
     874    [self sendScrollEventAt:lastMousePosition deltaX:x deltaY:y units:kCGScrollEventUnitLine wheelPhase:phase momentumPhase:momentum timestamp:0];
     875#endif
     876}
     877
     878#if PLATFORM(MAC)
     879- (void)sendScrollEventAt:(NSPoint)mouseLocation deltaX:(double)deltaX deltaY:(double)deltaY units:(CGScrollEventUnit)units wheelPhase:(CGGesturePhase)wheelPhase momentumPhase:(CGMomentumScrollPhase)momentumPhase timestamp:(uint64_t)timestamp
     880{
     881    if (wheelPhase == kCGGesturePhaseEnded || wheelPhase == kCGGesturePhaseCancelled)
    874882        _sentWheelPhaseEndOrCancel = YES;
    875883
    876     if (momentum == kCGMomentumScrollPhaseEnd)
     884    if (momentumPhase == kCGMomentumScrollPhaseEnd)
    877885        _sentMomentumPhaseEnd = YES;
    878886
    879     auto cgScrollEvent = adoptCF(CGEventCreateScrollWheelEvent2(NULL, kCGScrollEventUnitLine, 2, y, x, 0));
     887    constexpr uint32_t wheelCount = 2;
     888    // Note that the delta get converted to integral values here. NSEvent has float deltas, CGEvent has integral deltas.
     889    auto cgScrollEvent = adoptCF(CGEventCreateScrollWheelEvent2(NULL, units, wheelCount, deltaY, deltaX, 0));
     890    CGEventSetTimestamp(cgScrollEvent.get(), timestamp);
    880891
    881892    // Set the CGEvent location in flipped coords relative to the first screen, which
    882893    // compensates for the behavior of +[NSEvent eventWithCGEvent:] when the event has
    883894    // no associated window. See <rdar://problem/17180591>.
    884     CGPoint lastGlobalMousePosition = CGPointMake(lastMousePosition.x, [[[NSScreen screens] objectAtIndex:0] frame].size.height - lastMousePosition.y);
    885     CGEventSetLocation(cgScrollEvent.get(), lastGlobalMousePosition);
     895    CGPoint globalMousePosition = CGPointMake(mouseLocation.x, [[[NSScreen screens] objectAtIndex:0] frame].size.height - mouseLocation.y);
     896    CGEventSetLocation(cgScrollEvent.get(), globalMousePosition);
    886897    CGEventSetIntegerValueField(cgScrollEvent.get(), kCGScrollWheelEventIsContinuous, 1);
    887     CGEventSetIntegerValueField(cgScrollEvent.get(), kCGScrollWheelEventScrollPhase, phase);
    888     CGEventSetIntegerValueField(cgScrollEvent.get(), kCGScrollWheelEventMomentumPhase, momentum);
     898    CGEventSetIntegerValueField(cgScrollEvent.get(), kCGScrollWheelEventScrollPhase, wheelPhase);
     899    CGEventSetIntegerValueField(cgScrollEvent.get(), kCGScrollWheelEventMomentumPhase, momentumPhase);
    889900   
    890901    NSEvent* scrollEvent = [NSEvent eventWithCGEvent:cgScrollEvent.get()];
     
    896907    } else
    897908        printf("mouseScrollByX...andMomentumPhases: Unable to locate target view for current mouse location.");
    898 #endif
    899 }
     909}
     910#endif
    900911
    901912- (NSArray *)contextClick
  • trunk/Tools/DumpRenderTree/mac/UIScriptControllerMac.h

    r265396 r285781  
    5353    void activateDataListSuggestion(unsigned, JSValueRef) override;
    5454    void setSpellCheckerResults(JSValueRef) override;
     55    void sendEventStream(JSStringRef, JSValueRef) override;
    5556};
    5657
  • trunk/Tools/DumpRenderTree/mac/UIScriptControllerMac.mm

    r282755 r285781  
    3030
    3131#import "DumpRenderTree.h"
     32#import "EventSendingController.h"
    3233#import "LayoutTestSpellChecker.h"
    3334#import "UIScriptContext.h"
     
    3839#import <WebKit/WebPreferences.h>
    3940#import <WebKit/WebViewPrivate.h>
     41#import <mach/mach_time.h>
    4042#import <pal/spi/mac/NSTextInputContextSPI.h>
    4143#import <wtf/WorkQueue.h>
     
    174176}
    175177
    176 }
     178static NSString *const TopLevelEventInfoKey = @"events";
     179static NSString *const EventTypeKey = @"type";
     180static NSString *const ViewRelativeXPositionKey = @"viewX";
     181static NSString *const ViewRelativeYPositionKey = @"viewY";
     182static NSString *const DeltaXKey = @"deltaX";
     183static NSString *const DeltaYKey = @"deltaY";
     184static NSString *const PhaseKey = @"phase";
     185static NSString *const MomentumPhaseKey = @"momentumPhase";
     186
     187static CGGesturePhase gesturePhaseFromString(NSString *phaseStr)
     188{
     189    if ([phaseStr isEqualToString:@"began"])
     190        return kCGGesturePhaseBegan;
     191
     192    if ([phaseStr isEqualToString:@"changed"])
     193        return kCGGesturePhaseChanged;
     194
     195    if ([phaseStr isEqualToString:@"ended"])
     196        return kCGGesturePhaseEnded;
     197
     198    if ([phaseStr isEqualToString:@"cancelled"])
     199        return kCGGesturePhaseCancelled;
     200
     201    if ([phaseStr isEqualToString:@"maybegin"])
     202        return kCGGesturePhaseMayBegin;
     203
     204    return kCGGesturePhaseNone;
     205}
     206
     207static CGMomentumScrollPhase momentumPhaseFromString(NSString *phaseStr)
     208{
     209    if ([phaseStr isEqualToString:@"began"])
     210        return kCGMomentumScrollPhaseBegin;
     211
     212    if ([phaseStr isEqualToString:@"changed"] || [phaseStr isEqualToString:@"continue"]) // Allow "continue" for ease of conversion from mouseScrollByWithWheelAndMomentumPhases values.
     213        return kCGMomentumScrollPhaseContinue;
     214
     215    if ([phaseStr isEqualToString:@"ended"])
     216        return kCGMomentumScrollPhaseEnd;
     217
     218    return kCGMomentumScrollPhaseNone;
     219}
     220
     221static EventSendingController *eventSenderFromView(WebView *webView)
     222{
     223    auto frame = [webView mainFrame];
     224    auto windowObject = [frame windowObject];
     225    return [windowObject valueForKey:@"eventSender"];
     226}
     227
     228void UIScriptControllerMac::sendEventStream(JSStringRef eventsJSON, JSValueRef callback)
     229{
     230    WebView *webView = [mainFrame webView];
     231
     232    // didClearWindowObjectInStandardWorldForFrame stashed EventSendingController on this window property.
     233    EventSendingController* eventSender = eventSenderFromView(webView);
     234    if (!eventSender) {
     235        ASSERT_NOT_REACHED();
     236        return;
     237    }
     238
     239    unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);
     240
     241    auto jsonString = eventsJSON->string();
     242    auto eventInfo = dynamic_objc_cast<NSDictionary>([NSJSONSerialization JSONObjectWithData:[(NSString *)jsonString dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers | NSJSONReadingMutableLeaves error:nil]);
     243    if (!eventInfo || ![eventInfo isKindOfClass:[NSDictionary class]]) {
     244        WTFLogAlways("JSON is not convertible to a dictionary");
     245        return;
     246    }
     247
     248    double currentViewRelativeX = 0;
     249    double currentViewRelativeY = 0;
     250
     251    constexpr uint64_t nanosecondsPerSecond = 1e9;
     252    constexpr uint64_t nanosecondsEventInterval = nanosecondsPerSecond / 60;
     253
     254    auto currentTime = mach_absolute_time();
     255
     256    for (NSMutableDictionary *event in eventInfo[TopLevelEventInfoKey]) {
     257
     258        id eventType = event[EventTypeKey];
     259        if (!event[EventTypeKey]) {
     260            WTFLogAlways("Missing event type");
     261            break;
     262        }
     263       
     264        if ([eventType isEqualToString:@"wheel"]) {
     265            auto phase = kCGGesturePhaseNone;
     266            auto momentumPhase = kCGMomentumScrollPhaseNone;
     267
     268            if (!event[PhaseKey] && !event[MomentumPhaseKey]) {
     269                WTFLogAlways("Event must specify phase or momentumPhase");
     270                break;
     271            }
     272
     273            if (id phaseString = event[PhaseKey])
     274                phase = gesturePhaseFromString(phaseString);
     275
     276            if (id phaseString = event[MomentumPhaseKey])
     277                momentumPhase = momentumPhaseFromString(phaseString);
     278
     279            ASSERT_IMPLIES(phase == kCGGesturePhaseNone, momentumPhase != kCGMomentumScrollPhaseNone);
     280            ASSERT_IMPLIES(momentumPhase == kCGMomentumScrollPhaseNone, phase != kCGGesturePhaseNone);
     281
     282            if (event[ViewRelativeXPositionKey])
     283                currentViewRelativeX = [event[ViewRelativeXPositionKey] floatValue];
     284
     285            if (event[ViewRelativeYPositionKey])
     286                currentViewRelativeY = [event[ViewRelativeYPositionKey] floatValue];
     287
     288            double deltaX = 0;
     289            double deltaY = 0;
     290
     291            if (event[DeltaXKey])
     292                deltaX = [event[DeltaXKey] floatValue];
     293
     294            if (event[DeltaYKey])
     295                deltaY = [event[DeltaYKey] floatValue];
     296
     297            auto windowPoint = [webView convertPoint:CGPointMake(currentViewRelativeX, [webView frame].size.height - currentViewRelativeY) toView:nil];
     298            [eventSender sendScrollEventAt:windowPoint deltaX:deltaX deltaY:deltaY units:kCGScrollEventUnitPixel wheelPhase:phase momentumPhase:momentumPhase timestamp:currentTime];
     299        }
     300
     301        currentTime += nanosecondsEventInterval;
     302    }
     303
     304    WorkQueue::main().dispatch([this, strongThis = Ref { *this }, callbackID] {
     305        if (!m_context)
     306            return;
     307        m_context->asyncTaskComplete(callbackID);
     308    });
     309}
     310
     311} // namespace WTR
    177312
    178313#endif // PLATFORM(MAC)
  • trunk/Tools/WebKitTestRunner/mac/UIScriptControllerMac.mm

    r285409 r285781  
    309309}
    310310
    311 static NSString* const TopLevelEventInfoKey = @"events";
    312 static NSString* const EventTypeKey = @"type";
    313 static NSString* const ViewRelativeXPositionKey = @"viewX";
    314 static NSString* const ViewRelativeYPositionKey = @"viewY";
    315 static NSString* const DeltaXKey = @"deltaX";
    316 static NSString* const DeltaYKey = @"deltaY";
    317 static NSString* const PhaseKey = @"phase";
    318 static NSString* const MomentumPhaseKey = @"momentumPhase";
     311static NSString *const TopLevelEventInfoKey = @"events";
     312static NSString *const EventTypeKey = @"type";
     313static NSString *const ViewRelativeXPositionKey = @"viewX";
     314static NSString *const ViewRelativeYPositionKey = @"viewY";
     315static NSString *const DeltaXKey = @"deltaX";
     316static NSString *const DeltaYKey = @"deltaY";
     317static NSString *const PhaseKey = @"phase";
     318static NSString *const MomentumPhaseKey = @"momentumPhase";
    319319
    320320static EventSenderProxy::WheelEventPhase eventPhaseFromString(NSString *phaseStr)
Note: See TracChangeset for help on using the changeset viewer.