378141d2cccd24dcbb7e8d87c6112ce59b2ee21e
[WebKit-https.git] / Tools / WebKitTestRunner / gtk / EventSenderProxyGtk.cpp
1 /*
2  * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
3  * Copyright (C) 2009 Zan Dobersek <zandobersek@gmail.com>
4  * Copyright (C) 2009 Holger Hans Peter Freyther
5  * Copyright (C) 2010 Igalia S.L.
6  * Copyright (c) 2010 Motorola Mobility, Inc.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1.  Redistributions of source code must retain the above copyright
13  *     notice, this list of conditions and the following disclaimer.
14  * 2.  Redistributions in binary form must reproduce the above copyright
15  *     notice, this list of conditions and the following disclaimer in the
16  *     documentation and/or other materials provided with the distribution.
17  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
18  *     its contributors may be used to endorse or promote products derived
19  *     from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
22  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
25  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include "config.h"
34 #include "EventSenderProxy.h"
35
36 #include "NotImplemented.h"
37 #include "PlatformWebView.h"
38 #include "TestController.h"
39 #include <gdk/gdkkeysyms.h>
40 #include <gtk/gtk.h>
41 #include <wtf/StdLibExtras.h>
42 #include <wtf/glib/GUniquePtr.h>
43 #include <wtf/text/WTFString.h>
44
45 namespace WTR {
46
47 // WebCore and layout tests assume this value
48 static const float pixelsPerScrollTick = 40;
49
50 // Key event location code defined in DOM Level 3.
51 enum KeyLocationCode {
52     DOMKeyLocationStandard      = 0x00,
53     DOMKeyLocationLeft          = 0x01,
54     DOMKeyLocationRight         = 0x02,
55     DOMKeyLocationNumpad        = 0x03
56 };
57
58
59 struct WTREventQueueItem {
60     GdkEvent* event;
61     gulong delay;
62
63     WTREventQueueItem()
64         : event(0)
65         , delay(0)
66     {
67     }
68     WTREventQueueItem(GdkEvent* event, gulong delay)
69         : event(event)
70         , delay(delay)
71     {
72     }
73 };
74
75 EventSenderProxy::EventSenderProxy(TestController* testController)
76     : m_testController(testController)
77     , m_time(0)
78     , m_leftMouseButtonDown(false)
79     , m_clickCount(0)
80     , m_clickTime(0)
81     , m_clickButton(kWKEventMouseButtonNoButton)
82     , m_mouseButtonCurrentlyDown(0)
83 {
84 }
85
86 EventSenderProxy::~EventSenderProxy()
87 {
88 }
89
90 static guint getMouseButtonModifiers(int gdkButton)
91 {
92     if (gdkButton == 1)
93         return GDK_BUTTON1_MASK;
94     if (gdkButton == 2)
95         return GDK_BUTTON2_MASK;
96     if (gdkButton == 3)
97         return GDK_BUTTON3_MASK;
98     return 0;
99 }
100
101 static unsigned eventSenderButtonToGDKButton(unsigned button)
102 {
103     int mouseButton = 3;
104     if (button <= 2)
105         mouseButton = button + 1;
106     // fast/events/mouse-click-events expects the 4th button to be treated as the middle button.
107     else if (button == 3)
108         mouseButton = 2;
109
110     return mouseButton;
111 }
112
113 static guint webkitModifiersToGDKModifiers(WKEventModifiers wkModifiers)
114 {
115     guint modifiers = 0;
116
117     if (wkModifiers & kWKEventModifiersControlKey)
118         modifiers |= GDK_CONTROL_MASK;
119     if (wkModifiers & kWKEventModifiersShiftKey)
120         modifiers |= GDK_SHIFT_MASK;
121     if (wkModifiers & kWKEventModifiersAltKey)
122         modifiers |= GDK_MOD1_MASK;
123     if (wkModifiers & kWKEventModifiersMetaKey)
124         modifiers |= GDK_META_MASK;
125     if (wkModifiers & kWKEventModifiersCapsLockKey)
126         modifiers |= GDK_LOCK_MASK;
127
128     return modifiers;
129 }
130
131 GdkEvent* EventSenderProxy::createMouseButtonEvent(GdkEventType eventType, unsigned button, WKEventModifiers modifiers)
132 {
133     GdkEvent* mouseEvent = gdk_event_new(eventType);
134
135     mouseEvent->button.button = eventSenderButtonToGDKButton(button);
136     mouseEvent->button.x = m_position.x;
137     mouseEvent->button.y = m_position.y;
138     mouseEvent->button.window = gtk_widget_get_window(GTK_WIDGET(m_testController->mainWebView()->platformView()));
139     g_object_ref(mouseEvent->button.window);
140     gdk_event_set_device(mouseEvent, gdk_device_manager_get_client_pointer(gdk_display_get_device_manager(gdk_window_get_display(mouseEvent->button.window))));
141     mouseEvent->button.state = webkitModifiersToGDKModifiers(modifiers) | getMouseButtonModifiers(mouseEvent->button.button);
142     mouseEvent->button.time = GDK_CURRENT_TIME;
143     mouseEvent->button.axes = 0;
144
145     int xRoot, yRoot;
146     gdk_window_get_root_coords(mouseEvent->button.window, m_position.x, m_position.y, &xRoot, &yRoot);
147     mouseEvent->button.x_root = xRoot;
148     mouseEvent->button.y_root = yRoot;
149
150     return mouseEvent;
151 }
152
153 void EventSenderProxy::updateClickCountForButton(int button)
154 {
155     if (m_time - m_clickTime < 1 && m_position == m_clickPosition && button == m_clickButton) {
156         ++m_clickCount;
157         m_clickTime = m_time;
158         return;
159     }
160
161     m_clickCount = 1;
162     m_clickTime = m_time;
163     m_clickPosition = m_position;
164     m_clickButton = button;
165 }
166
167 void EventSenderProxy::dispatchEvent(GdkEvent* event)
168 {
169     ASSERT(m_testController->mainWebView());
170     gtk_main_do_event(event);
171     gdk_event_free(event);
172 }
173
174 void EventSenderProxy::replaySavedEvents()
175 {
176     while (!m_eventQueue.isEmpty()) {
177         WTREventQueueItem item = m_eventQueue.takeFirst();
178         if (item.delay)
179             g_usleep(item.delay * 1000);
180
181         dispatchEvent(item.event);
182     }
183 }
184
185 void EventSenderProxy::sendOrQueueEvent(GdkEvent* event)
186 {
187     if (m_eventQueue.isEmpty() || !m_eventQueue.last().delay) {
188         dispatchEvent(event);
189         return;
190     }
191
192     m_eventQueue.last().event = event;
193     replaySavedEvents();
194 }
195
196 int getGDKKeySymForKeyRef(WKStringRef keyRef, unsigned location, guint* modifiers)
197 {
198     if (location == DOMKeyLocationNumpad) {
199         if (WKStringIsEqualToUTF8CString(keyRef, "leftArrow"))
200             return GDK_KEY_KP_Left;
201         if (WKStringIsEqualToUTF8CString(keyRef, "rightArror"))
202             return GDK_KEY_KP_Right;
203         if (WKStringIsEqualToUTF8CString(keyRef, "upArrow"))
204             return GDK_KEY_KP_Up;
205         if (WKStringIsEqualToUTF8CString(keyRef, "downArrow"))
206             return GDK_KEY_KP_Down;
207         if (WKStringIsEqualToUTF8CString(keyRef, "pageUp"))
208             return GDK_KEY_KP_Page_Up;
209         if (WKStringIsEqualToUTF8CString(keyRef, "pageDown"))
210             return GDK_KEY_KP_Page_Down;
211         if (WKStringIsEqualToUTF8CString(keyRef, "home"))
212             return GDK_KEY_KP_Home;
213         if (WKStringIsEqualToUTF8CString(keyRef, "end"))
214             return GDK_KEY_KP_End;
215         if (WKStringIsEqualToUTF8CString(keyRef, "insert"))
216             return GDK_KEY_KP_Insert;
217         if (WKStringIsEqualToUTF8CString(keyRef, "delete"))
218             return GDK_KEY_KP_Delete;
219
220         return GDK_KEY_VoidSymbol;
221     }
222
223     if (WKStringIsEqualToUTF8CString(keyRef, "leftControl"))
224         return GDK_KEY_Control_L;
225     if (WKStringIsEqualToUTF8CString(keyRef, "rightControl"))
226         return GDK_KEY_Control_R;
227     if (WKStringIsEqualToUTF8CString(keyRef, "leftShift"))
228         return GDK_KEY_Shift_L;
229     if (WKStringIsEqualToUTF8CString(keyRef, "rightShift"))
230         return GDK_KEY_Shift_R;
231     if (WKStringIsEqualToUTF8CString(keyRef, "leftAlt"))
232         return GDK_KEY_Alt_L;
233     if (WKStringIsEqualToUTF8CString(keyRef, "rightAlt"))
234         return GDK_KEY_Alt_R;
235     if (WKStringIsEqualToUTF8CString(keyRef, "leftArrow"))
236         return GDK_KEY_Left;
237     if (WKStringIsEqualToUTF8CString(keyRef, "rightArrow"))
238         return GDK_KEY_Right;
239     if (WKStringIsEqualToUTF8CString(keyRef, "upArrow"))
240         return GDK_KEY_Up;
241     if (WKStringIsEqualToUTF8CString(keyRef, "downArrow"))
242         return GDK_KEY_Down;
243     if (WKStringIsEqualToUTF8CString(keyRef, "pageUp"))
244         return GDK_KEY_Page_Up;
245     if (WKStringIsEqualToUTF8CString(keyRef, "pageDown"))
246         return GDK_KEY_Page_Down;
247     if (WKStringIsEqualToUTF8CString(keyRef, "home"))
248         return GDK_KEY_Home;
249     if (WKStringIsEqualToUTF8CString(keyRef, "end"))
250         return GDK_KEY_End;
251     if (WKStringIsEqualToUTF8CString(keyRef, "insert"))
252         return GDK_KEY_Insert;
253     if (WKStringIsEqualToUTF8CString(keyRef, "delete"))
254         return GDK_KEY_Delete;
255     if (WKStringIsEqualToUTF8CString(keyRef, "printScreen"))
256         return GDK_KEY_Print;
257     if (WKStringIsEqualToUTF8CString(keyRef, "menu"))
258         return GDK_KEY_Menu;
259     if (WKStringIsEqualToUTF8CString(keyRef, "F1"))
260         return GDK_KEY_F1;
261     if (WKStringIsEqualToUTF8CString(keyRef, "F2"))
262         return GDK_KEY_F2;
263     if (WKStringIsEqualToUTF8CString(keyRef, "F3"))
264         return GDK_KEY_F3;
265     if (WKStringIsEqualToUTF8CString(keyRef, "F4"))
266         return GDK_KEY_F4;
267     if (WKStringIsEqualToUTF8CString(keyRef, "F5"))
268         return GDK_KEY_F5;
269     if (WKStringIsEqualToUTF8CString(keyRef, "F6"))
270         return GDK_KEY_F6;
271     if (WKStringIsEqualToUTF8CString(keyRef, "F7"))
272         return GDK_KEY_F7;
273     if (WKStringIsEqualToUTF8CString(keyRef, "F8"))
274         return GDK_KEY_F8;
275     if (WKStringIsEqualToUTF8CString(keyRef, "F9"))
276         return GDK_KEY_F9;
277     if (WKStringIsEqualToUTF8CString(keyRef, "F10"))
278         return GDK_KEY_F10;
279     if (WKStringIsEqualToUTF8CString(keyRef, "F11"))
280         return GDK_KEY_F11;
281     if (WKStringIsEqualToUTF8CString(keyRef, "F12"))
282         return GDK_KEY_F12;
283
284     size_t bufferSize = WKStringGetMaximumUTF8CStringSize(keyRef);
285     auto buffer = std::make_unique<char[]>(bufferSize);
286     WKStringGetUTF8CString(keyRef, buffer.get(), bufferSize);
287     char charCode = buffer.get()[0];
288
289     if (charCode == '\n' || charCode == '\r')
290         return GDK_KEY_Return;
291     if (charCode == '\t')
292         return GDK_KEY_Tab;
293     if (charCode == '\x8')
294         return GDK_KEY_BackSpace;
295     if (charCode == 0x001B)
296         return GDK_KEY_Escape;
297
298     if (WTF::isASCIIUpper(charCode))
299         *modifiers |= GDK_SHIFT_MASK;
300
301     return gdk_unicode_to_keyval(static_cast<guint32>(buffer.get()[0]));
302 }
303
304 void EventSenderProxy::keyDown(WKStringRef keyRef, WKEventModifiers wkModifiers, unsigned location)
305 {
306     guint modifiers = webkitModifiersToGDKModifiers(wkModifiers);
307     int gdkKeySym = getGDKKeySymForKeyRef(keyRef, location, &modifiers);
308
309     GdkEvent* pressEvent = gdk_event_new(GDK_KEY_PRESS);
310     pressEvent->key.keyval = gdkKeySym;
311     pressEvent->key.state = modifiers;
312     pressEvent->key.window = gtk_widget_get_window(GTK_WIDGET(m_testController->mainWebView()->platformWindow()));
313     g_object_ref(pressEvent->key.window);
314     gdk_event_set_device(pressEvent, gdk_device_manager_get_client_pointer(gdk_display_get_device_manager(gdk_window_get_display(pressEvent->key.window))));
315
316     GUniqueOutPtr<GdkKeymapKey> keys;
317     gint nKeys;
318     if (gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), gdkKeySym, &keys.outPtr(), &nKeys) && nKeys)
319         pressEvent->key.hardware_keycode = keys.get()[0].keycode;
320
321     GdkEvent* releaseEvent = gdk_event_copy(pressEvent);
322     dispatchEvent(pressEvent);
323     releaseEvent->key.type = GDK_KEY_RELEASE;
324     dispatchEvent(releaseEvent);
325 }
326
327 void EventSenderProxy::mouseDown(unsigned button, WKEventModifiers wkModifiers)
328 {
329     // If the same mouse button is already in the down position don't
330     // send another event as it may confuse Xvfb.
331     unsigned gdkButton = eventSenderButtonToGDKButton(button);
332     if (m_mouseButtonCurrentlyDown == gdkButton)
333         return;
334
335     m_mouseButtonCurrentlyDown = gdkButton;
336
337     // Normally GDK will send both GDK_BUTTON_PRESS and GDK_2BUTTON_PRESS for
338     // the second button press during double-clicks. WebKit GTK+ selectively
339     // ignores the first GDK_BUTTON_PRESS of that pair using gdk_event_peek.
340     // Since our events aren't ever going onto the GDK event queue, WebKit won't
341     // be able to filter out the first GDK_BUTTON_PRESS, so we just don't send
342     // it here. Eventually this code should probably figure out a way to get all
343     // appropriate events onto the event queue and this work-around should be
344     // removed.
345     updateClickCountForButton(button);
346
347     GdkEventType eventType;
348     if (m_clickCount == 2)
349         eventType = GDK_2BUTTON_PRESS;
350     else if (m_clickCount == 3)
351         eventType = GDK_3BUTTON_PRESS;
352     else
353         eventType = GDK_BUTTON_PRESS;
354
355     GdkEvent* event = createMouseButtonEvent(eventType, button, wkModifiers);
356     sendOrQueueEvent(event);
357 }
358
359 void EventSenderProxy::mouseUp(unsigned button, WKEventModifiers wkModifiers)
360 {
361     m_clickButton = kWKEventMouseButtonNoButton;
362     GdkEvent* event = createMouseButtonEvent(GDK_BUTTON_RELEASE, button, wkModifiers);
363     sendOrQueueEvent(event);
364
365     if (m_mouseButtonCurrentlyDown == event->button.button)
366         m_mouseButtonCurrentlyDown = 0;
367     m_clickPosition = m_position;
368     m_clickTime = GDK_CURRENT_TIME;
369 }
370
371 void EventSenderProxy::mouseMoveTo(double x, double y)
372 {
373     m_position.x = x;
374     m_position.y = y;
375
376     GdkEvent* event = gdk_event_new(GDK_MOTION_NOTIFY);
377     event->motion.x = m_position.x;
378     event->motion.y = m_position.y;
379
380     event->motion.time = GDK_CURRENT_TIME;
381     event->motion.window = gtk_widget_get_window(GTK_WIDGET(m_testController->mainWebView()->platformView()));
382     g_object_ref(event->motion.window);
383     gdk_event_set_device(event, gdk_device_manager_get_client_pointer(gdk_display_get_device_manager(gdk_window_get_display(event->motion.window))));
384     event->motion.state = 0 | getMouseButtonModifiers(m_mouseButtonCurrentlyDown);
385     event->motion.axes = 0;
386
387     int xRoot, yRoot;
388     gdk_window_get_root_coords(gtk_widget_get_window(GTK_WIDGET(m_testController->mainWebView()->platformView())), m_position.x, m_position.y , &xRoot, &yRoot);
389     event->motion.x_root = xRoot;
390     event->motion.y_root = yRoot;
391
392     sendOrQueueEvent(event);
393 }
394
395 void EventSenderProxy::mouseScrollBy(int horizontal, int vertical)
396 {
397     // Copy behaviour of Qt and EFL - just return in case of (0,0) mouse scroll
398     if (!horizontal && !vertical)
399         return;
400
401     GdkEvent* event = gdk_event_new(GDK_SCROLL);
402     event->scroll.x = m_position.x;
403     event->scroll.y = m_position.y;
404     event->scroll.time = GDK_CURRENT_TIME;
405     event->scroll.window = gtk_widget_get_window(GTK_WIDGET(m_testController->mainWebView()->platformView()));
406     g_object_ref(event->scroll.window);
407     gdk_event_set_device(event, gdk_device_manager_get_client_pointer(gdk_display_get_device_manager(gdk_window_get_display(event->scroll.window))));
408
409     // For more than one tick in a scroll, we need smooth scroll event
410     if ((horizontal && vertical) || horizontal > 1 || horizontal < -1 || vertical > 1 || vertical < -1) {
411         event->scroll.direction = GDK_SCROLL_SMOOTH;
412         event->scroll.delta_x = -horizontal;
413         event->scroll.delta_y = -vertical;
414
415         sendOrQueueEvent(event);
416         return;
417     }
418
419     if (horizontal < 0)
420         event->scroll.direction = GDK_SCROLL_RIGHT;
421     else if (horizontal > 0)
422         event->scroll.direction = GDK_SCROLL_LEFT;
423     else if (vertical < 0)
424         event->scroll.direction = GDK_SCROLL_DOWN;
425     else if (vertical > 0)
426         event->scroll.direction = GDK_SCROLL_UP;
427     else
428         g_assert_not_reached();
429
430     sendOrQueueEvent(event);
431 }
432
433 void EventSenderProxy::continuousMouseScrollBy(int horizontal, int vertical, bool paged)
434 {
435     // Gtk+ does not support paged scroll events.
436     if (paged) {
437         WTFLogAlways("EventSenderProxy::continuousMouseScrollBy not implemented for paged scroll events");
438         return;
439     }
440
441     GdkEvent* event = gdk_event_new(GDK_SCROLL);
442     event->scroll.x = m_position.x;
443     event->scroll.y = m_position.y;
444     event->scroll.time = GDK_CURRENT_TIME;
445     event->scroll.window = gtk_widget_get_window(GTK_WIDGET(m_testController->mainWebView()->platformView()));
446     g_object_ref(event->scroll.window);
447     gdk_event_set_device(event, gdk_device_manager_get_client_pointer(gdk_display_get_device_manager(gdk_window_get_display(event->scroll.window))));
448
449     event->scroll.direction = GDK_SCROLL_SMOOTH;
450     event->scroll.delta_x = -horizontal / pixelsPerScrollTick;
451     event->scroll.delta_y = -vertical / pixelsPerScrollTick;
452
453     sendOrQueueEvent(event);
454 }
455
456 void EventSenderProxy::mouseScrollByWithWheelAndMomentumPhases(int x, int y, int /*phase*/, int /*momentum*/)
457 {
458     // Gtk+ does not have the concept of wheel gesture phases or momentum. Just relay to
459     // the mouse wheel handler.
460     mouseScrollBy(x, y);
461 }
462
463 void EventSenderProxy::leapForward(int milliseconds)
464 {
465     if (m_eventQueue.isEmpty())
466         m_eventQueue.append(WTREventQueueItem());
467
468     m_eventQueue.last().delay = milliseconds;
469     m_time += milliseconds / 1000.0;
470 }
471
472 void updateEventCoordinates(GdkEvent* touchEvent, int x, int y)
473 {
474     touchEvent->touch.x = x;
475     touchEvent->touch.y = y;
476
477     int xRoot, yRoot;
478     gdk_window_get_root_coords(touchEvent->touch.window, x, y, &xRoot, &yRoot);
479     touchEvent->touch.x_root = xRoot;
480     touchEvent->touch.y_root = yRoot;
481 }
482
483 GUniquePtr<GdkEvent> EventSenderProxy::createTouchEvent(GdkEventType eventType, int id)
484 {
485     GUniquePtr<GdkEvent> touchEvent(gdk_event_new(eventType));
486
487     touchEvent->touch.sequence = static_cast<GdkEventSequence*>(GINT_TO_POINTER(id));
488     touchEvent->touch.window = gtk_widget_get_window(GTK_WIDGET(m_testController->mainWebView()->platformView()));
489     g_object_ref(touchEvent->touch.window);
490     gdk_event_set_device(touchEvent.get(), gdk_device_manager_get_client_pointer(gdk_display_get_device_manager(gdk_window_get_display(touchEvent->button.window))));
491     touchEvent->touch.time = GDK_CURRENT_TIME;
492
493     return touchEvent;
494 }
495
496 #if ENABLE(TOUCH_EVENTS)
497 void EventSenderProxy::addTouchPoint(int x, int y)
498 {
499     // Touch ID is array index plus one, so 0 is skipped.
500     GUniquePtr<GdkEvent> event = createTouchEvent(static_cast<GdkEventType>(GDK_TOUCH_BEGIN), m_touchEvents.size() + 1);
501     updateEventCoordinates(event.get(), x, y);
502     m_updatedTouchEvents.add(GPOINTER_TO_INT(event->touch.sequence));
503     m_touchEvents.append(std::move(event));
504 }
505
506 void EventSenderProxy::updateTouchPoint(int index, int x, int y)
507 {
508     ASSERT(index >= 0 && static_cast<size_t>(index) < m_touchEvents.size());
509
510     const auto& event = m_touchEvents[index];
511     ASSERT(event);
512
513     event->type = GDK_TOUCH_UPDATE;
514     updateEventCoordinates(event.get(), x, y);
515     m_updatedTouchEvents.add(GPOINTER_TO_INT(event->touch.sequence));
516 }
517
518 void EventSenderProxy::sendUpdatedTouchEvents()
519 {
520     for (auto id : m_updatedTouchEvents)
521         sendOrQueueEvent(gdk_event_copy(m_touchEvents[id - 1].get()));
522
523     m_updatedTouchEvents.clear();
524 }
525
526 void EventSenderProxy::touchStart()
527 {
528     sendUpdatedTouchEvents();
529 }
530
531 void EventSenderProxy::touchMove()
532 {
533     sendUpdatedTouchEvents();
534 }
535
536 void EventSenderProxy::touchEnd()
537 {
538     sendUpdatedTouchEvents();
539 }
540
541 void EventSenderProxy::touchCancel()
542 {
543     notImplemented();
544 }
545
546 void EventSenderProxy::clearTouchPoints()
547 {
548     m_updatedTouchEvents.clear();
549     m_touchEvents.clear();
550 }
551
552 void EventSenderProxy::releaseTouchPoint(int index)
553 {
554     ASSERT(index >= 0 && static_cast<size_t>(index) < m_touchEvents.size());
555
556     const auto& event = m_touchEvents[index];
557     event->type = GDK_TOUCH_END;
558     m_updatedTouchEvents.add(GPOINTER_TO_INT(event->touch.sequence));
559 }
560
561 void EventSenderProxy::cancelTouchPoint(int index)
562 {
563     notImplemented();
564 }
565
566 void EventSenderProxy::setTouchPointRadius(int radiusX, int radiusY)
567 {
568     notImplemented();
569 }
570
571 void EventSenderProxy::setTouchModifier(WKEventModifiers modifier, bool enable)
572 {
573     guint state = webkitModifiersToGDKModifiers(modifier);
574
575     for (const auto& event : m_touchEvents) {
576         if (event->type == GDK_TOUCH_END)
577             continue;
578
579         if (enable)
580             event->touch.state |= state;
581         else
582             event->touch.state &= ~(state);
583
584         m_updatedTouchEvents.add(GPOINTER_TO_INT(event->touch.sequence));
585     }
586 }
587 #endif // ENABLE(TOUCH_EVENTS)
588
589 } // namespace WTR