[WTF] Import std::optional reference implementation as WTF::Optional
[WebKit-https.git] / Tools / WebKitTestRunner / ios / UIScriptControllerIOS.mm
1 /*
2  * Copyright (C) 2015 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 "UIScriptController.h"
28
29 #if PLATFORM(IOS)
30
31 #import "HIDEventGenerator.h"
32 #import "PlatformWebView.h"
33 #import "StringFunctions.h"
34 #import "TestController.h"
35 #import "TestRunnerWKWebView.h"
36 #import "UIKitSPI.h"
37 #import "UIScriptContext.h"
38 #import <JavaScriptCore/JavaScriptCore.h>
39 #import <JavaScriptCore/OpaqueJSString.h>
40 #import <UIKit/UIKit.h>
41 #import <WebCore/FloatRect.h>
42 #import <WebKit/WKWebViewPrivate.h>
43 #import <WebKit/WebKit.h>
44
45 namespace WTR {
46
47 void UIScriptController::doAsyncTask(JSValueRef callback)
48 {
49     unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);
50
51     dispatch_async(dispatch_get_main_queue(), ^{
52         if (!m_context)
53             return;
54         m_context->asyncTaskComplete(callbackID);
55     });
56 }
57
58 void UIScriptController::doAfterPresentationUpdate(JSValueRef callback)
59 {
60     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
61
62     unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);
63     [webView _doAfterNextPresentationUpdate:^{
64         if (!m_context)
65             return;
66         m_context->asyncTaskComplete(callbackID);
67     }];
68 }
69
70 void UIScriptController::zoomToScale(double scale, JSValueRef callback)
71 {
72     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
73
74     unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);
75
76     [webView zoomToScale:scale animated:YES completionHandler:^{
77         if (!m_context)
78             return;
79         m_context->asyncTaskComplete(callbackID);
80     }];
81 }
82
83 void UIScriptController::simulateAccessibilitySettingsChangeNotification(JSValueRef callback)
84 {
85     unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);
86
87     auto* webView = TestController::singleton().mainWebView()->platformView();
88     NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
89     [center postNotificationName:UIAccessibilityInvertColorsStatusDidChangeNotification object:webView];
90
91     [webView _doAfterNextPresentationUpdate: ^{
92         if (!m_context)
93             return;
94         m_context->asyncTaskComplete(callbackID);
95     }];
96 }
97
98 double UIScriptController::zoomScale() const
99 {
100     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
101     return webView.scrollView.zoomScale;
102 }
103
104 static CGPoint globalToContentCoordinates(TestRunnerWKWebView *webView, long x, long y)
105 {
106     CGPoint point = CGPointMake(x, y);
107     point = [webView _convertPointFromContentsToView:point];
108     point = [webView convertPoint:point toView:nil];
109     point = [webView.window convertPoint:point toWindow:nil];
110     return point;
111 }
112
113 void UIScriptController::touchDownAtPoint(long x, long y, long touchCount, JSValueRef callback)
114 {
115     unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);
116
117     auto location = globalToContentCoordinates(TestController::singleton().mainWebView()->platformView(), x, y);
118     [[HIDEventGenerator sharedHIDEventGenerator] touchDown:location touchCount:touchCount completionBlock:^{
119         if (!m_context)
120             return;
121         m_context->asyncTaskComplete(callbackID);
122     }];
123 }
124
125 void UIScriptController::liftUpAtPoint(long x, long y, long touchCount, JSValueRef callback)
126 {
127     unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);
128     
129     auto location = globalToContentCoordinates(TestController::singleton().mainWebView()->platformView(), x, y);
130     [[HIDEventGenerator sharedHIDEventGenerator] liftUp:location touchCount:touchCount completionBlock:^{
131         if (!m_context)
132             return;
133         m_context->asyncTaskComplete(callbackID);
134     }];
135 }
136
137 void UIScriptController::singleTapAtPoint(long x, long y, JSValueRef callback)
138 {
139     unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);
140
141     [[HIDEventGenerator sharedHIDEventGenerator] tap:globalToContentCoordinates(TestController::singleton().mainWebView()->platformView(), x, y) completionBlock:^{
142         if (!m_context)
143             return;
144         m_context->asyncTaskComplete(callbackID);
145     }];
146 }
147
148 void UIScriptController::doubleTapAtPoint(long x, long y, JSValueRef callback)
149 {
150     unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);
151
152     [[HIDEventGenerator sharedHIDEventGenerator] doubleTap:globalToContentCoordinates(TestController::singleton().mainWebView()->platformView(), x, y) completionBlock:^{
153         if (!m_context)
154             return;
155         m_context->asyncTaskComplete(callbackID);
156     }];
157 }
158
159 void UIScriptController::stylusDownAtPoint(long x, long y, float azimuthAngle, float altitudeAngle, float pressure, JSValueRef callback)
160 {
161     unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);
162
163     auto location = globalToContentCoordinates(TestController::singleton().mainWebView()->platformView(), x, y);
164     [[HIDEventGenerator sharedHIDEventGenerator] stylusDownAtPoint:location azimuthAngle:azimuthAngle altitudeAngle:altitudeAngle pressure:pressure completionBlock:^{
165         if (!m_context)
166             return;
167         m_context->asyncTaskComplete(callbackID);
168     }];
169 }
170
171 void UIScriptController::stylusMoveToPoint(long x, long y, float azimuthAngle, float altitudeAngle, float pressure, JSValueRef callback)
172 {
173     unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);
174
175     auto location = globalToContentCoordinates(TestController::singleton().mainWebView()->platformView(), x, y);
176     [[HIDEventGenerator sharedHIDEventGenerator] stylusMoveToPoint:location azimuthAngle:azimuthAngle altitudeAngle:altitudeAngle pressure:pressure completionBlock:^{
177         if (!m_context)
178             return;
179         m_context->asyncTaskComplete(callbackID);
180     }];
181 }
182
183 void UIScriptController::stylusUpAtPoint(long x, long y, JSValueRef callback)
184 {
185     unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);
186
187     auto location = globalToContentCoordinates(TestController::singleton().mainWebView()->platformView(), x, y);
188     [[HIDEventGenerator sharedHIDEventGenerator] stylusUpAtPoint:location completionBlock:^{
189         if (!m_context)
190             return;
191         m_context->asyncTaskComplete(callbackID);
192     }];
193 }
194
195 void UIScriptController::stylusTapAtPoint(long x, long y, float azimuthAngle, float altitudeAngle, float pressure, JSValueRef callback)
196 {
197     unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);
198
199     auto location = globalToContentCoordinates(TestController::singleton().mainWebView()->platformView(), x, y);
200     [[HIDEventGenerator sharedHIDEventGenerator] stylusTapAtPoint:location azimuthAngle:azimuthAngle altitudeAngle:altitudeAngle pressure:pressure completionBlock:^{
201         if (!m_context)
202             return;
203         m_context->asyncTaskComplete(callbackID);
204     }];
205 }
206
207 void UIScriptController::sendEventStream(JSStringRef eventsJSON, JSValueRef callback)
208 {
209     unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);
210
211     String jsonString = eventsJSON->string();
212     auto eventInfo = dynamic_objc_cast<NSDictionary>([NSJSONSerialization JSONObjectWithData:[(NSString *)jsonString dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil]);
213     if (!eventInfo || ![eventInfo isKindOfClass:[NSDictionary class]]) {
214         WTFLogAlways("JSON is not convertible to a dictionary");
215         return;
216     }
217     
218     [[HIDEventGenerator sharedHIDEventGenerator] sendEventStream:eventInfo completionBlock:^{
219         if (!m_context)
220             return;
221         m_context->asyncTaskComplete(callbackID);
222     }];
223 }
224
225 void UIScriptController::dragFromPointToPoint(long startX, long startY, long endX, long endY, double durationSeconds, JSValueRef callback)
226 {
227     unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);
228
229     CGPoint startPoint = globalToContentCoordinates(TestController::singleton().mainWebView()->platformView(), startX, startY);
230     CGPoint endPoint = globalToContentCoordinates(TestController::singleton().mainWebView()->platformView(), endX, endY);
231     
232     [[HIDEventGenerator sharedHIDEventGenerator] dragWithStartPoint:startPoint endPoint:endPoint duration:durationSeconds completionBlock:^{
233         if (!m_context)
234             return;
235         m_context->asyncTaskComplete(callbackID);
236     }];
237 }
238     
239 void UIScriptController::longPressAtPoint(long x, long y, JSValueRef callback)
240 {
241     unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);
242     
243     [[HIDEventGenerator sharedHIDEventGenerator] longPress:globalToContentCoordinates(TestController::singleton().mainWebView()->platformView(), x, y) completionBlock:^{
244         if (!m_context)
245             return;
246         m_context->asyncTaskComplete(callbackID);
247     }];
248 }
249
250 void UIScriptController::typeCharacterUsingHardwareKeyboard(JSStringRef character, JSValueRef callback)
251 {
252     unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);
253
254     // Assumes that the keyboard is already shown.
255     [[HIDEventGenerator sharedHIDEventGenerator] keyPress:toWTFString(toWK(character)) completionBlock:^{
256         if (!m_context)
257             return;
258         m_context->asyncTaskComplete(callbackID);
259     }];
260 }
261
262 void UIScriptController::keyDownUsingHardwareKeyboard(JSStringRef character, JSValueRef callback)
263 {
264     unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);
265
266     // Assumes that the keyboard is already shown.
267     [[HIDEventGenerator sharedHIDEventGenerator] keyDown:toWTFString(toWK(character)) completionBlock:^{
268         if (!m_context)
269             return;
270         m_context->asyncTaskComplete(callbackID);
271     }];
272 }
273
274 void UIScriptController::keyUpUsingHardwareKeyboard(JSStringRef character, JSValueRef callback)
275 {
276     unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);
277
278     // Assumes that the keyboard is already shown.
279     [[HIDEventGenerator sharedHIDEventGenerator] keyUp:toWTFString(toWK(character)) completionBlock:^{
280         if (!m_context)
281             return;
282         m_context->asyncTaskComplete(callbackID);
283     }];
284 }
285
286 void UIScriptController::selectTextCandidateAtIndex(long index, JSValueRef callback)
287 {
288 #if USE(APPLE_INTERNAL_SDK)
289     static const float textPredictionsPollingInterval = 0.1;
290     unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);
291     waitForTextPredictionsViewAndSelectCandidateAtIndex(index, callbackID, textPredictionsPollingInterval);
292 #else
293     // FIXME: This is a no-op on non-internal builds due to UIKeyboardPredictionView being unavailable. Ideally, there should be a better way to
294     // retrieve information and interact with the predictive text view that will be compatible with OpenSource.
295     UNUSED_PARAM(index);
296     UNUSED_PARAM(callback);
297 #endif
298 }
299
300 void UIScriptController::waitForTextPredictionsViewAndSelectCandidateAtIndex(long index, unsigned callbackID, float interval)
301 {
302     id UIKeyboardPredictionViewClass = NSClassFromString(@"UIKeyboardPredictionView");
303     if (!UIKeyboardPredictionViewClass)
304         return;
305
306 #if USE(APPLE_INTERNAL_SDK)
307     UIKeyboardPredictionView *predictionView = (UIKeyboardPredictionView *)[UIKeyboardPredictionViewClass activeInstance];
308     if (![predictionView hasPredictions]) {
309         dispatch_after(dispatch_time(DISPATCH_TIME_NOW, interval * NSEC_PER_SEC), dispatch_get_main_queue(), ^() {
310             waitForTextPredictionsViewAndSelectCandidateAtIndex(index, callbackID, interval);
311         });
312         return;
313     }
314
315     PlatformWKView webView = TestController::singleton().mainWebView()->platformView();
316     CGRect predictionViewFrame = [predictionView frame];
317     // This assumes there are 3 predicted text cells of equal width, which is the case on iOS.
318     float offsetX = (index * 2 + 1) * CGRectGetWidth(predictionViewFrame) / 6;
319     float offsetY = CGRectGetHeight(webView.window.frame) - CGRectGetHeight([[predictionView superview] frame]) + CGRectGetHeight(predictionViewFrame) / 2;
320     [[HIDEventGenerator sharedHIDEventGenerator] tap:CGPointMake(offsetX, offsetY) completionBlock:^{
321         if (m_context)
322             m_context->asyncTaskComplete(callbackID);
323     }];
324 #else
325     UNUSED_PARAM(index);
326     UNUSED_PARAM(callbackID);
327     UNUSED_PARAM(interval);
328 #endif
329 }
330
331 void UIScriptController::dismissFormAccessoryView()
332 {
333     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
334     [webView dismissFormAccessoryView];
335 }
336
337 void UIScriptController::selectFormAccessoryPickerRow(long rowIndex)
338 {
339     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
340     [webView selectFormAccessoryPickerRow:rowIndex];
341 }
342     
343 JSObjectRef UIScriptController::contentsOfUserInterfaceItem(JSStringRef interfaceItem) const
344 {
345     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
346     NSDictionary *contentDictionary = [webView _contentsOfUserInterfaceItem:toWTFString(toWK(interfaceItem))];
347     return JSValueToObject(m_context->jsContext(), [JSValue valueWithObject:contentDictionary inContext:[JSContext contextWithJSGlobalContextRef:m_context->jsContext()]].JSValueRef, nullptr);
348 }
349
350 static CGPoint contentOffsetBoundedInValidRange(UIScrollView *scrollView, CGPoint contentOffset)
351 {
352     UIEdgeInsets contentInsets = scrollView.contentInset;
353     CGSize contentSize = scrollView.contentSize;
354     CGSize scrollViewSize = scrollView.bounds.size;
355
356     CGFloat maxHorizontalOffset = contentSize.width + contentInsets.right - scrollViewSize.width;
357     contentOffset.x = std::min(maxHorizontalOffset, contentOffset.x);
358     contentOffset.x = std::max(-contentInsets.left, contentOffset.x);
359
360     CGFloat maxVerticalOffset = contentSize.height + contentInsets.bottom - scrollViewSize.height;
361     contentOffset.y = std::min(maxVerticalOffset, contentOffset.y);
362     contentOffset.y = std::max(-contentInsets.top, contentOffset.y);
363     return contentOffset;
364 }
365
366 void UIScriptController::scrollToOffset(long x, long y)
367 {
368     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
369     [webView.scrollView setContentOffset:contentOffsetBoundedInValidRange(webView.scrollView, CGPointMake(x, y)) animated:YES];
370 }
371
372 void UIScriptController::immediateScrollToOffset(long x, long y)
373 {
374     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
375     [webView.scrollView setContentOffset:contentOffsetBoundedInValidRange(webView.scrollView, CGPointMake(x, y)) animated:NO];
376 }
377
378 void UIScriptController::immediateZoomToScale(double scale)
379 {
380     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
381     [webView.scrollView setZoomScale:scale animated:NO];
382 }
383
384 void UIScriptController::keyboardAccessoryBarNext()
385 {
386     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
387     [webView keyboardAccessoryBarNext];
388 }
389
390 void UIScriptController::keyboardAccessoryBarPrevious()
391 {
392     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
393     [webView keyboardAccessoryBarPrevious];
394 }
395
396 double UIScriptController::minimumZoomScale() const
397 {
398     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
399     return webView.scrollView.minimumZoomScale;
400 }
401
402 double UIScriptController::maximumZoomScale() const
403 {
404     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
405     return webView.scrollView.maximumZoomScale;
406 }
407
408 std::optional<bool> UIScriptController::stableStateOverride() const
409 {
410     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
411     if (webView._stableStateOverride)
412         return webView._stableStateOverride.boolValue;
413
414     return std::nullopt;
415 }
416
417 void UIScriptController::setStableStateOverride(std::optional<bool> overrideValue)
418 {
419     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
420     if (overrideValue)
421         webView._stableStateOverride = @(overrideValue.value());
422     else
423         webView._stableStateOverride = nil;
424 }
425
426 JSObjectRef UIScriptController::contentVisibleRect() const
427 {
428     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
429
430     CGRect contentVisibleRect = webView._contentVisibleRect;
431     
432     WebCore::FloatRect rect(contentVisibleRect.origin.x, contentVisibleRect.origin.y, contentVisibleRect.size.width, contentVisibleRect.size.height);
433     return m_context->objectFromRect(rect);
434 }
435
436 JSObjectRef UIScriptController::selectionRangeViewRects() const
437 {
438     NSMutableArray *selectionRects = [[NSMutableArray alloc] init];
439     for (UIView *rectView in TestController::singleton().mainWebView()->platformView()._uiTextSelectionRectViews) {
440         if (rectView.hidden)
441             continue;
442
443         CGRect frame = rectView.frame;
444         [selectionRects addObject:@{
445             @"left": @(frame.origin.x),
446             @"top": @(frame.origin.y),
447             @"width": @(frame.size.width),
448             @"height": @(frame.size.height),
449         }];
450     }
451     return JSValueToObject(m_context->jsContext(), [JSValue valueWithObject:selectionRects inContext:[JSContext contextWithJSGlobalContextRef:m_context->jsContext()]].JSValueRef, nullptr);
452 }
453
454 void UIScriptController::removeAllDynamicDictionaries()
455 {
456     [UIKeyboard removeAllDynamicDictionaries];
457 }
458
459 JSRetainPtr<JSStringRef> UIScriptController::scrollingTreeAsText() const
460 {
461     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
462     return JSStringCreateWithCFString((CFStringRef)[webView _scrollingTreeAsText]);
463 }
464
465 void UIScriptController::platformSetDidStartFormControlInteractionCallback()
466 {
467     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
468     webView.didStartFormControlInteractionCallback = ^{
469         if (!m_context)
470             return;
471         m_context->fireCallback(CallbackTypeDidStartFormControlInteraction);
472     };
473 }
474
475 void UIScriptController::platformSetDidEndFormControlInteractionCallback()
476 {
477     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
478     webView.didEndFormControlInteractionCallback = ^{
479         if (!m_context)
480             return;
481         m_context->fireCallback(CallbackTypeDidEndFormControlInteraction);
482     };
483 }
484     
485 void UIScriptController::platformSetDidShowForcePressPreviewCallback()
486 {
487     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
488     webView.didShowForcePressPreviewCallback = ^ {
489         if (!m_context)
490             return;
491         m_context->fireCallback(CallbackTypeDidShowForcePressPreview);
492     };
493 }
494
495 void UIScriptController::platformSetDidDismissForcePressPreviewCallback()
496 {
497     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
498     webView.didDismissForcePressPreviewCallback = ^ {
499         if (!m_context)
500             return;
501         m_context->fireCallback(CallbackTypeDidEndFormControlInteraction);
502     };
503 }
504
505 void UIScriptController::platformSetWillBeginZoomingCallback()
506 {
507     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
508     webView.willBeginZoomingCallback = ^{
509         if (!m_context)
510             return;
511         m_context->fireCallback(CallbackTypeWillBeginZooming);
512     };
513 }
514
515 void UIScriptController::platformSetDidEndZoomingCallback()
516 {
517     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
518     webView.didEndZoomingCallback = ^{
519         if (!m_context)
520             return;
521         m_context->fireCallback(CallbackTypeDidEndZooming);
522     };
523 }
524
525 void UIScriptController::platformSetDidShowKeyboardCallback()
526 {
527     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
528     webView.didShowKeyboardCallback = ^{
529         if (!m_context)
530             return;
531         m_context->fireCallback(CallbackTypeDidShowKeyboard);
532     };
533 }
534
535 void UIScriptController::platformSetDidHideKeyboardCallback()
536 {
537     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
538     webView.didHideKeyboardCallback = ^{
539         if (!m_context)
540             return;
541         m_context->fireCallback(CallbackTypeDidHideKeyboard);
542     };
543 }
544
545 void UIScriptController::platformSetDidEndScrollingCallback()
546 {
547     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
548     webView.didEndScrollingCallback = ^{
549         if (!m_context)
550             return;
551         m_context->fireCallback(CallbackTypeDidEndScrolling);
552     };
553 }
554
555 void UIScriptController::platformClearAllCallbacks()
556 {
557     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
558     
559     webView.didStartFormControlInteractionCallback = nil;
560     webView.didEndFormControlInteractionCallback = nil;
561     webView.didShowForcePressPreviewCallback = nil;
562     webView.didDismissForcePressPreviewCallback = nil;
563     webView.didEndZoomingCallback = nil;
564     webView.willBeginZoomingCallback = nil;
565     webView.didHideKeyboardCallback = nil;
566     webView.didShowKeyboardCallback = nil;
567     webView.didEndScrollingCallback = nil;
568 }
569
570 }
571
572 #endif // PLATFORM(IOS)