[iOS] Keyups for non-modifier keys identified as "Dead" when not focused in a content...
[WebKit-https.git] / Source / WebCore / platform / ios / PlatformEventFactoryIOS.mm
1 /*
2  * Copyright (C) 2004, 2006-2011, 2014, 2019 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "PlatformEventFactoryIOS.h"
28
29 #if PLATFORM(IOS_FAMILY)
30
31 #import "IntPoint.h"
32 #import "KeyEventCocoa.h"
33 #import "KeyEventCodesIOS.h"
34 #import "Logging.h"
35 #import "WAKAppKitStubs.h"
36 #import "WebEvent.h"
37 #import "WindowsKeyboardCodes.h"
38 #import <wtf/Optional.h>
39 #import <wtf/WallTime.h>
40
41 namespace WebCore {
42
43 static OptionSet<PlatformEvent::Modifier> modifiersForEvent(WebEvent *event)
44 {
45     OptionSet<PlatformEvent::Modifier> modifiers;
46
47     if (event.modifierFlags & WebEventFlagMaskShiftKey)
48         modifiers.add(PlatformEvent::Modifier::ShiftKey);
49     if (event.modifierFlags & WebEventFlagMaskControlKey)
50         modifiers.add(PlatformEvent::Modifier::CtrlKey);
51     if (event.modifierFlags & WebEventFlagMaskOptionKey)
52         modifiers.add(PlatformEvent::Modifier::AltKey);
53     if (event.modifierFlags & WebEventFlagMaskCommandKey)
54         modifiers.add(PlatformEvent::Modifier::MetaKey);
55     if (event.modifierFlags & WebEventFlagMaskLeftCapsLockKey)
56         modifiers.add(PlatformEvent::Modifier::CapsLockKey);
57
58     return modifiers;
59 }
60
61 static inline IntPoint pointForEvent(WebEvent *event)
62 {
63     return IntPoint(event.locationInWindow);
64 }
65
66 static inline IntPoint globalPointForEvent(WebEvent *event)
67 {
68     // iOS WebKit works as if it is full screen. Therefore Web coords are Global coords.
69     return pointForEvent(event);
70 }
71
72 static PlatformEvent::Type mouseEventType(WebEvent *event)
73 {
74     switch (event.type) {
75     case WebEventMouseDown:
76         return PlatformEvent::MousePressed;
77     case WebEventMouseUp:
78         return PlatformEvent::MouseReleased;
79     case WebEventMouseMoved:
80         return PlatformEvent::MouseMoved;
81     default:
82         ASSERT_NOT_REACHED();
83         return PlatformEvent::MousePressed;
84     }
85 }
86
87 class PlatformMouseEventBuilder : public PlatformMouseEvent {
88 public:
89     PlatformMouseEventBuilder(WebEvent *event)
90     {
91         m_type = mouseEventType(event);
92         m_timestamp = WallTime::now();
93
94         m_position = pointForEvent(event);
95         m_globalPosition = globalPointForEvent(event);
96         m_button = LeftButton; // This has always been the LeftButton on iOS.
97         m_clickCount = 1; // This has always been 1 on iOS.
98     }
99 };
100
101 PlatformMouseEvent PlatformEventFactory::createPlatformMouseEvent(WebEvent *event)
102 {
103     return PlatformMouseEventBuilder(event);
104 }
105
106 class PlatformWheelEventBuilder : public PlatformWheelEvent {
107 public:
108     PlatformWheelEventBuilder(WebEvent *event)
109     {
110         ASSERT(event.type == WebEventScrollWheel);
111
112         m_type = PlatformEvent::Wheel;
113         m_timestamp = WallTime::now();
114
115         m_position = pointForEvent(event);
116         m_globalPosition = globalPointForEvent(event);
117         m_deltaX = event.deltaX;
118         m_deltaY = event.deltaY;
119         m_granularity = ScrollByPixelWheelEvent; // iOS only supports continuous (pixel-mode) scrolling.
120     }
121 };
122
123 PlatformWheelEvent PlatformEventFactory::createPlatformWheelEvent(WebEvent *event)
124 {
125     return PlatformWheelEventBuilder(event);
126 }
127
128 String keyIdentifierForKeyEvent(WebEvent *event)
129 {
130     if (event.keyboardFlags & WebEventKeyboardInputModifierFlagsChanged) {
131         switch (event.keyCode) {
132         case VK_LWIN: // Left Command
133         case VK_APPS: // Right Command
134             return "Meta"_s;
135
136         case VK_CAPITAL: // Caps Lock
137             return "CapsLock"_s;
138
139         case VK_LSHIFT: // Left Shift
140         case VK_RSHIFT: // Right Shift
141             return "Shift"_s;
142
143         case VK_LMENU: // Left Alt
144         case VK_RMENU: // Right Alt
145             return "Alt"_s;
146
147         case VK_LCONTROL: // Left Ctrl
148         case VK_RCONTROL: // Right Ctrl
149             return "Control"_s;
150
151         default:
152             ASSERT_NOT_REACHED();
153             return emptyString();
154         }
155     }
156     NSString *characters = event.charactersIgnoringModifiers;
157     if ([characters length] != 1) {
158         LOG(Events, "received an unexpected number of characters in key event: %u", [characters length]);
159         return "Unidentified"_s;
160     }
161     return keyIdentifierForCharCode([characters characterAtIndex:0]);
162 }
163
164 String keyForKeyEvent(WebEvent *event)
165 {
166     if (event.keyboardFlags & WebEventKeyboardInputModifierFlagsChanged) {
167         switch (event.keyCode) {
168         case VK_LWIN: // Left Command
169         case VK_APPS: // Right Command
170             return "Meta"_s;
171
172         case VK_CAPITAL: // Caps Lock
173             return "CapsLock"_s;
174
175         case VK_LSHIFT: // Left Shift
176         case VK_RSHIFT: // Right Shift
177             return "Shift"_s;
178
179         case VK_LMENU: // Left Alt
180         case VK_RMENU: // Right Alt
181             return "Alt"_s;
182
183         case VK_LCONTROL: // Left Ctrl
184         case VK_RCONTROL: // Right Ctrl
185             return "Control"_s;
186
187         default:
188             ASSERT_NOT_REACHED();
189             return "Unidentified"_s;
190         }
191     }
192
193     // If more than one key is being pressed and the key combination includes one or more modifier keys
194     // that result in the key no longer producing a printable character (e.g., Control + a), then the
195     // key value should be the printable key value that would have been produced if the key had been
196     // typed with the default keyboard layout with no modifier keys except for Shift and AltGr applied.
197     // See <https://www.w3.org/TR/2015/WD-uievents-20151215/#keys-guidelines>.
198     bool isControlDown = event.modifierFlags & WebEventFlagMaskControlKey;
199     NSString *characters = isControlDown ? event.charactersIgnoringModifiers : event.characters;
200     auto length = [characters length];
201     // characters return an empty string for dead keys.
202     // https://developer.apple.com/reference/appkit/nsevent/1534183-characters
203     // "Dead" is defined here https://w3c.github.io/uievents-key/#keys-composition.
204     if (!length)
205         return "Dead"_s;
206     if (length > 1)
207         return characters;
208     return keyForCharCode([characters characterAtIndex:0]);
209 }
210
211 // https://w3c.github.io/uievents-code/
212 String codeForKeyEvent(WebEvent *event)
213 {
214     switch (event.keyCode) {
215     // Keys in the alphanumeric section.
216     case VK_OEM_3: return "Backquote"_s;
217     case VK_OEM_5: return "Backslash"_s;
218     case VK_BACK: return "Backspace"_s;
219     case VK_OEM_4: return "BracketLeft"_s;
220     case VK_OEM_6: return "BracketRight"_s;
221     case VK_OEM_COMMA: return "Comma"_s;
222     case VK_0: return "Digit0"_s;
223     case VK_1: return "Digit1"_s;
224     case VK_2: return "Digit2"_s;
225     case VK_3: return "Digit3"_s;
226     case VK_4: return "Digit4"_s;
227     case VK_5: return "Digit5"_s;
228     case VK_6: return "Digit6"_s;
229     case VK_7: return "Digit7"_s;
230     case VK_8: return "Digit8"_s;
231     case VK_9: return "Digit9"_s;
232     case VK_OEM_PLUS: return "Equal"_s;
233     case VK_OEM_102: return "IntlBackslash"_s;
234     // IntlRo.
235     // IntlYen.
236     case VK_A: return "KeyA"_s;
237     case VK_B: return "KeyB"_s;
238     case VK_C: return "KeyC"_s;
239     case VK_D: return "KeyD"_s;
240     case VK_E: return "KeyE"_s;
241     case VK_F: return "KeyF"_s;
242     case VK_G: return "KeyG"_s;
243     case VK_H: return "KeyH"_s;
244     case VK_I: return "KeyI"_s;
245     case VK_J: return "KeyJ"_s;
246     case VK_K: return "KeyK"_s;
247     case VK_L: return "KeyL"_s;
248     case VK_M: return "KeyM"_s;
249     case VK_N: return "KeyN"_s;
250     case VK_O: return "KeyO"_s;
251     case VK_P: return "KeyP"_s;
252     case VK_Q: return "KeyQ"_s;
253     case VK_R: return "KeyR"_s;
254     case VK_S: return "KeyS"_s;
255     case VK_T: return "KeyT"_s;
256     case VK_U: return "KeyU"_s;
257     case VK_V: return "KeyV"_s;
258     case VK_W: return "KeyW"_s;
259     case VK_X: return "KeyX"_s;
260     case VK_Y: return "KeyY"_s;
261     case VK_Z: return "KeyZ"_s;
262     case VK_OEM_MINUS: return "Minus"_s;
263     case VK_OEM_PERIOD: return "Period"_s;
264     case VK_OEM_7: return "Quote"_s;
265     case VK_OEM_1: return "Semicolon"_s;
266     case VK_OEM_2: return "Slash"_s;
267
268     // Functional keys in alphanumeric section.
269     case VK_MENU: return "AltLeft"_s;
270     // AltRight.
271     case VK_CAPITAL: return "CapsLock"_s;
272     // ContextMenu.
273     case VK_LCONTROL: return "ControlLeft"_s;
274     case VK_RCONTROL: return "ControlRight"_s;
275     case VK_RETURN: return "Enter"_s; //  Labeled Return on Apple keyboards.
276     case VK_LWIN: return "MetaLeft"_s;
277     case VK_RWIN: return "MetaRight"_s;
278     case VK_LSHIFT: return "ShiftLeft"_s;
279     case VK_RSHIFT: return "ShiftRight"_s;
280     case VK_SPACE: return "Space"_s;
281     case VK_TAB: return "Tab"_s;
282
283     // Functional keys found on Japanese and Korean keyboards.
284     // Convert.
285     case VK_KANA: return "KanaMode"_s;
286     // Lang1.
287     // Lang2.
288     // Lang3.
289     // Lang4.
290     // Lang5.
291     // NonConvert.
292
293     // Keys in the ControlPad section.
294     // Delete
295     case VK_END: return "End"_s;
296     case VK_HELP: return "Help"_s;
297     case VK_HOME: return "Home"_s;
298     // Insert: Not present on Apple keyboards.
299     case VK_NEXT: return "PageDown"_s;
300     case VK_PRIOR: return "PageUp"_s;
301
302     // Keys in the ArrowPad section.
303     case VK_DOWN: return "ArrowDown"_s;
304     case VK_LEFT: return "ArrowLeft"_s;
305     case VK_RIGHT: return "ArrowRight"_s;
306     case VK_UP: return "ArrowUp"_s;
307
308     // Keys in the Numpad section.
309     case VK_NUMLOCK: return "NumLock"_s;
310     case VK_NUMPAD0: return "Numpad0"_s;
311     case VK_NUMPAD1: return "Numpad1"_s;
312     case VK_NUMPAD2: return "Numpad2"_s;
313     case VK_NUMPAD3: return "Numpad3"_s;
314     case VK_NUMPAD4: return "Numpad4"_s;
315     case VK_NUMPAD5: return "Numpad5"_s;
316     case VK_NUMPAD6: return "Numpad6"_s;
317     case VK_NUMPAD7: return "Numpad7"_s;
318     case VK_NUMPAD8: return "Numpad8"_s;
319     case VK_NUMPAD9: return "Numpad9"_s;
320     case VK_ADD: return "NumpadAdd"_s;
321     // NumpadBackspace.
322     // NumpadClear.
323     // NumpadClearEntry.
324     case VK_SEPARATOR: return "NumpadComma"_s;
325     case VK_DECIMAL: return "NumpadDecimal"_s;
326     case VK_DIVIDE: return "NumpadDivide"_s;
327     // NumpadEnter.
328     case VK_CLEAR: return "NumpadEqual"_s;
329     // NumpadHash.
330     // NumpadMemoryAdd.
331     // NumpadMemoryClear.
332     // NumpadMemoryRecall.
333     // NumpadMemoryStore.
334     // NumpadMemorySubtract.
335     case VK_MULTIPLY: return "NumpadMultiply"_s;
336     // NumpadParenLeft.
337     // NumpadParenRight.
338     // NumpadStar: The specification says to use "NumpadMultiply" for the * key on numeric keypads.
339     case VK_SUBTRACT: return "NumpadSubtract"_s;
340
341     // Keys in the Function section.
342     case VK_ESCAPE: return "Escape"_s;
343     case VK_F1: return "F1"_s;
344     case VK_F2: return "F2"_s;
345     case VK_F3: return "F3"_s;
346     case VK_F4: return "F4"_s;
347     case VK_F5: return "F5"_s;
348     case VK_F6: return "F6"_s;
349     case VK_F7: return "F7"_s;
350     case VK_F8: return "F8"_s;
351     case VK_F9: return "F9"_s;
352     case VK_F10: return "F10"_s;
353     case VK_F11: return "F11"_s;
354     case VK_F12: return "F12"_s;
355     case VK_F13: return "F13"_s;
356     case VK_F14: return "F14"_s;
357     case VK_F15: return "F15"_s;
358     case VK_F16: return "F16"_s;
359     case VK_F17: return "F17"_s;
360     case VK_F18: return "F18"_s;
361     case VK_F19: return "F19"_s;
362     case VK_F20: return "F20"_s;
363     // Fn: This is typically a hardware key that does not generate a separate code.
364     // FnLock.
365     // PrintScreen.
366     // ScrollLock.
367     // Pause.
368
369     // Media keys.
370     // BrowserBack.
371     // BrowserFavorites.
372     // BrowserForward.
373     // BrowserHome.
374     // BrowserRefresh.
375     // BrowserSearch.
376     // BrowserStop.
377     // Eject.
378     // LaunchApp1.
379     // LaunchApp2.
380     // LaunchMail.
381     // MediaPlayPause.
382     // MediaSelect.
383     // MediaStop.
384     // MediaTrackNext.
385     // MediaTrackPrevious.
386     // Power.
387     // Sleep.
388     case VK_VOLUME_DOWN: return "AudioVolumeDown"_s;
389     case VK_VOLUME_MUTE: return "AudioVolumeMute"_s;
390     case VK_VOLUME_UP: return "AudioVolumeUp"_s;
391     // WakeUp.
392
393     // Legacy modifier keys.
394     // Hyper.
395     // Super.
396     // Turbo.
397
398     // Legacy process control keys.
399     // Abort.
400     // Resume.
401     // Suspend.
402
403     // Legacy editing keys.
404     // Again.
405     // Copy.
406     // Cut.
407     // Find.
408     // Open.
409     // Paste.
410     // Props.
411     // Select.
412     // Undo.
413
414     // Keys found on international keyboards.
415     // Hiragana.
416     // Katakana.
417
418     default:
419         return "Unidentified"_s;
420     }
421 }
422
423 static bool isKeypadEvent(WebEvent* event)
424 {
425     // Check that this is the type of event that has a keyCode.
426     if (event.type != WebEventKeyDown && event.type != WebEventKeyUp)
427         return false;
428
429     // With the exception of keypad comma, the following corresponds to the criterion for UIKeyModifierNumericPad.
430     // FIXME: Recognize keypad comma.
431     switch (event.keyCode) {
432     case VK_CLEAR: // Num Pad Clear
433     case VK_OEM_PLUS: // Num Pad =
434     case VK_DIVIDE:
435     case VK_MULTIPLY:
436     case VK_SUBTRACT:
437     case VK_ADD:
438     case VK_RETURN: // Num Pad Enter
439     case VK_DECIMAL: // Num Pad .
440     case VK_NUMPAD0:
441     case VK_NUMPAD1:
442     case VK_NUMPAD2:
443     case VK_NUMPAD3:
444     case VK_NUMPAD4:
445     case VK_NUMPAD5:
446     case VK_NUMPAD6:
447     case VK_NUMPAD7:
448     case VK_NUMPAD8:
449     case VK_NUMPAD9:
450         return true;
451     }
452     return false;
453 }
454
455 int windowsKeyCodeForKeyEvent(WebEvent* event)
456 {
457     if (event.keyboardFlags & WebEventKeyboardInputModifierFlagsChanged)
458         return event.keyCode;
459
460     // There are several kinds of characters for which we produce key code from char code:
461     // 1. Roman letters. Windows keyboard layouts affect both virtual key codes and character codes for these,
462     //    so e.g. 'A' gets the same keyCode on QWERTY, AZERTY or Dvorak layouts.
463     // 2. Keys for which there is no known iOS virtual key codes, like PrintScreen.
464     // 3. Certain punctuation keys. On Windows, these are also remapped depending on current keyboard layout,
465     //    but see comment in windowsKeyCodeForCharCode().
466     if (!isKeypadEvent(event) && (event.type == WebEventKeyDown || event.type == WebEventKeyUp)) {
467         // Cmd switches Roman letters for Dvorak-QWERTY layout, so try modified characters first.
468         NSString *string = event.characters;
469         int code = string.length > 0 ? windowsKeyCodeForCharCode([string characterAtIndex:0]) : 0;
470         if (code)
471             return code;
472
473         // Ctrl+A on an AZERTY keyboard would get VK_Q keyCode if we relied on -[WebEvent keyCode] below.
474         string = event.charactersIgnoringModifiers;
475         code = string.length > 0 ? windowsKeyCodeForCharCode([string characterAtIndex:0]) : 0;
476         if (code)
477             return code;
478     }
479
480     // Use iOS virtual key code directly for any keys not handled above.
481     // E.g. the key next to Caps Lock has the same Event.keyCode on U.S. keyboard ('A') and on
482     // Russian keyboard (CYRILLIC LETTER EF).
483     return event.keyCode;
484 }
485
486 class PlatformKeyboardEventBuilder : public PlatformKeyboardEvent {
487 public:
488     PlatformKeyboardEventBuilder(WebEvent *event)
489     {
490         ASSERT(event.type == WebEventKeyDown || event.type == WebEventKeyUp);
491
492         m_type = (event.type == WebEventKeyUp ? PlatformEvent::KeyUp : PlatformEvent::KeyDown);
493         m_modifiers = modifiersForEvent(event);
494         m_timestamp = WallTime::now();
495
496         if (event.keyboardFlags & WebEventKeyboardInputModifierFlagsChanged) {
497             m_text = emptyString();
498             m_unmodifiedText = emptyString();
499             m_autoRepeat = false;
500         } else {
501             m_text = event.characters;
502             m_unmodifiedText = event.charactersIgnoringModifiers;
503             m_autoRepeat = event.isKeyRepeating;
504         }
505         m_key = keyForKeyEvent(event);
506         m_code = codeForKeyEvent(event);
507         m_keyIdentifier = keyIdentifierForKeyEvent(event);
508         m_windowsVirtualKeyCode = windowsKeyCodeForKeyEvent(event);
509         m_isKeypad = false; // iOS does not distinguish the numpad. See <rdar://problem/7190835>.
510         m_isSystemKey = false;
511         m_Event = event;
512
513         // Always use 13 for Enter/Return -- we don't want to use AppKit's different character for Enter.
514         if (m_windowsVirtualKeyCode == '\r') {
515             m_text = "\r";
516             m_unmodifiedText = "\r";
517         }
518
519         // The adjustments below are only needed in backward compatibility mode, but we cannot tell what mode we are in from here.
520
521         // Turn 0x7F into 8, because backspace needs to always be 8.
522         if (m_text == "\x7F")
523             m_text = "\x8";
524         if (m_unmodifiedText == "\x7F")
525             m_unmodifiedText = "\x8";
526         // Always use 9 for tab -- we don't want to use AppKit's different character for shift-tab.
527         if (m_windowsVirtualKeyCode == 9) {
528             m_text = "\x9";
529             m_unmodifiedText = "\x9";
530         }
531     }
532 };
533
534 PlatformKeyboardEvent PlatformEventFactory::createPlatformKeyboardEvent(WebEvent *event)
535 {
536     return PlatformKeyboardEventBuilder(event);
537 }
538
539 #if ENABLE(TOUCH_EVENTS)
540 static PlatformTouchPoint::TouchPhaseType convertTouchPhase(NSNumber *touchPhaseNumber)
541 {
542     WebEventTouchPhaseType touchPhase = static_cast<WebEventTouchPhaseType>([touchPhaseNumber unsignedIntValue]);
543     switch (touchPhase) {
544     case WebEventTouchPhaseBegan:
545         return PlatformTouchPoint::TouchPhaseBegan;
546     case WebEventTouchPhaseMoved:
547         return PlatformTouchPoint::TouchPhaseMoved;
548     case WebEventTouchPhaseStationary:
549         return PlatformTouchPoint::TouchPhaseStationary;
550     case WebEventTouchPhaseEnded:
551         return PlatformTouchPoint::TouchPhaseEnded;
552     case WebEventTouchPhaseCancelled:
553         return PlatformTouchPoint::TouchPhaseCancelled;
554     default:
555         ASSERT_NOT_REACHED();
556     }
557     return PlatformTouchPoint::TouchPhaseBegan;
558 }
559
560 static PlatformEvent::Type touchEventType(WebEvent *event)
561 {
562     switch (event.type) {
563     case WebEventTouchBegin:
564         return PlatformEvent::TouchStart;
565     case WebEventTouchEnd:
566         return PlatformEvent::TouchEnd;
567     case WebEventTouchCancel:
568         return PlatformEvent::TouchCancel;
569     case WebEventTouchChange:
570         return PlatformEvent::TouchMove;
571     default:
572         ASSERT_NOT_REACHED();
573         return PlatformEvent::TouchCancel;
574     }
575 }
576     
577 static PlatformTouchPoint::TouchPhaseType touchPhaseFromPlatformEventType(PlatformEvent::Type type)
578 {
579     switch (type) {
580     case PlatformEvent::TouchStart:
581         return PlatformTouchPoint::TouchPhaseBegan;
582     case PlatformEvent::TouchMove:
583         return PlatformTouchPoint::TouchPhaseMoved;
584     case PlatformEvent::TouchEnd:
585         return PlatformTouchPoint::TouchPhaseEnded;
586     default:
587         ASSERT_NOT_REACHED();
588         return PlatformTouchPoint::TouchPhaseCancelled;
589     }
590 }
591
592 class PlatformTouchPointBuilder : public PlatformTouchPoint {
593 public:
594     PlatformTouchPointBuilder(unsigned identifier, const IntPoint& location, TouchPhaseType phase)
595         : PlatformTouchPoint(identifier, location, phase)
596     {
597     }
598 };
599
600 class PlatformTouchEventBuilder : public PlatformTouchEvent {
601 public:
602     PlatformTouchEventBuilder(WebEvent *event)
603     {
604         m_type = touchEventType(event);
605         m_modifiers = modifiersForEvent(event);
606         m_timestamp = WallTime::fromRawSeconds(event.timestamp);
607
608         m_gestureScale = event.gestureScale;
609         m_gestureRotation = event.gestureRotation;
610         m_isGesture = event.isGesture;
611         m_position = pointForEvent(event);
612         m_globalPosition = globalPointForEvent(event);
613
614         unsigned touchCount = event.touchCount;
615         m_touchPoints.reserveInitialCapacity(touchCount);
616         for (unsigned i = 0; i < touchCount; ++i) {
617             unsigned identifier = [(NSNumber *)[event.touchIdentifiers objectAtIndex:i] unsignedIntValue];
618             IntPoint location = IntPoint([(NSValue *)[event.touchLocations objectAtIndex:i] pointValue]);
619             PlatformTouchPoint::TouchPhaseType touchPhase = convertTouchPhase([event.touchPhases objectAtIndex:i]);
620             m_touchPoints.uncheckedAppend(PlatformTouchPointBuilder(identifier, location, touchPhase));
621         }
622     }
623     
624     PlatformTouchEventBuilder(PlatformEvent::Type type, IntPoint location)
625     {
626         m_type = type;
627         m_timestamp = WallTime::now();
628         
629         m_gestureScale = 1;
630         m_gestureRotation = 0;
631         m_isGesture = 0;
632         m_position = location;
633         m_globalPosition = location;
634         m_isPotentialTap = true;
635         
636         unsigned touchCount = 1;
637         m_touchPoints.reserveInitialCapacity(touchCount);
638         for (unsigned i = 0; i < touchCount; ++i)
639             m_touchPoints.uncheckedAppend(PlatformTouchPointBuilder(1, location, touchPhaseFromPlatformEventType(type)));
640     }
641 };
642
643 PlatformTouchEvent PlatformEventFactory::createPlatformTouchEvent(WebEvent *event)
644 {
645     return PlatformTouchEventBuilder(event);
646 }
647     
648 PlatformTouchEvent PlatformEventFactory::createPlatformSimulatedTouchEvent(PlatformEvent::Type type, IntPoint location)
649 {
650     return PlatformTouchEventBuilder(type, location);
651 }
652
653 #endif // ENABLE(TOUCH_EVENTS)
654
655 } // namespace WebCore
656
657 #endif // PLATFORM(IOS_FAMILY)