[ContentChangeObserver] clearContentChangeObservers should be internal to ContentChan...
[WebKit-https.git] / Source / WebKitLegacy / ios / WebCoreSupport / WebChromeClientIOS.mm
1 /*
2  * Copyright (C) 2008-2017 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 "WebChromeClientIOS.h"
27
28 #if PLATFORM(IOS_FAMILY)
29
30 #import "DOMNodeInternal.h"
31 #import "PopupMenuIOS.h"
32 #import "SearchPopupMenuIOS.h"
33 #import "WebDelegateImplementationCaching.h"
34 #import "WebFixedPositionContent.h"
35 #import "WebFixedPositionContentInternal.h"
36 #import "WebFormDelegate.h"
37 #import "WebFrameIOS.h"
38 #import "WebFrameInternal.h"
39 #import "WebHistoryItemInternal.h"
40 #import "WebOpenPanelResultListener.h"
41 #import "WebUIDelegate.h"
42 #import "WebUIDelegatePrivate.h"
43 #import "WebUIKitDelegate.h"
44 #import "WebView.h"
45 #import "WebViewInternal.h"
46 #import "WebViewPrivate.h"
47 #import <WebCore/ContentChangeObserver.h>
48 #import <WebCore/DisabledAdaptations.h>
49 #import <WebCore/FileChooser.h>
50 #import <WebCore/FloatRect.h>
51 #import <WebCore/Frame.h>
52 #import <WebCore/GraphicsLayer.h>
53 #import <WebCore/HTMLInputElement.h>
54 #import <WebCore/HTMLNames.h>
55 #import <WebCore/IntRect.h>
56 #import <WebCore/Node.h>
57 #import <WebCore/PlatformScreen.h>
58 #import <WebCore/RenderBox.h>
59 #import <WebCore/RenderObject.h>
60 #import <WebCore/RuntimeApplicationChecks.h>
61 #import <WebCore/ScrollingConstraints.h>
62 #import <WebCore/WAKWindow.h>
63 #import <WebCore/WebCoreThreadMessage.h>
64 #import <wtf/HashMap.h>
65 #import <wtf/RefPtr.h>
66
67 NSString * const WebOpenPanelConfigurationAllowMultipleFilesKey = @"WebOpenPanelConfigurationAllowMultipleFilesKey";
68 NSString * const WebOpenPanelConfigurationMediaCaptureTypeKey = @"WebOpenPanelConfigurationMediaCaptureTypeKey";
69 NSString * const WebOpenPanelConfigurationMimeTypesKey = @"WebOpenPanelConfigurationMimeTypesKey";
70
71 using namespace WebCore;
72
73 #if ENABLE(MEDIA_CAPTURE)
74
75 static WebMediaCaptureType webMediaCaptureType(MediaCaptureType type)
76 {
77     switch (type) {
78     case MediaCaptureTypeNone:
79         return WebMediaCaptureTypeNone;
80     case MediaCaptureTypeUser:
81         return WebMediaCaptureTypeUser;
82     case MediaCaptureTypeEnvironment:
83         return WebMediaCaptureTypeEnvironment;
84     }
85
86     ASSERT_NOT_REACHED();
87     return WebMediaCaptureTypeNone;
88 }
89
90 #endif
91
92 void WebChromeClientIOS::setWindowRect(const WebCore::FloatRect& r)
93 {
94     [[webView() _UIDelegateForwarder] webView:webView() setFrame:r];
95 }
96
97 FloatRect WebChromeClientIOS::windowRect()
98 {
99     CGRect windowRect = [[webView() _UIDelegateForwarder] webViewFrame:webView()];
100     return enclosingIntRect(windowRect);
101 }
102
103 void WebChromeClientIOS::focus()
104 {
105     [[webView() _UIDelegateForwarder] webViewFocus:webView()];
106 }
107
108 void WebChromeClientIOS::runJavaScriptAlert(Frame& frame, const WTF::String& message)
109 {
110     WebThreadLockPushModal();
111     [[webView() _UIDelegateForwarder] webView:webView() runJavaScriptAlertPanelWithMessage:message initiatedByFrame:kit(&frame)];
112     WebThreadLockPopModal();
113 }
114
115 bool WebChromeClientIOS::runJavaScriptConfirm(Frame& frame, const WTF::String& message)
116 {
117     WebThreadLockPushModal();
118     bool result = [[webView() _UIDelegateForwarder] webView:webView() runJavaScriptConfirmPanelWithMessage:message initiatedByFrame:kit(&frame)];
119     WebThreadLockPopModal();
120     return result;
121 }
122
123 bool WebChromeClientIOS::runJavaScriptPrompt(Frame& frame, const WTF::String& prompt, const WTF::String& defaultText, WTF::String& result)
124 {
125     WebThreadLockPushModal();
126     result = [[webView() _UIDelegateForwarder] webView:webView() runJavaScriptTextInputPanelWithPrompt:prompt defaultText:defaultText initiatedByFrame:kit(&frame)];
127     WebThreadLockPopModal();
128     return !result.isNull();
129 }
130
131 void WebChromeClientIOS::runOpenPanel(Frame&, FileChooser& chooser)
132 {
133     auto& settings = chooser.settings();
134     BOOL allowMultipleFiles = settings.allowsMultipleFiles;
135     WebOpenPanelResultListener *listener = [[WebOpenPanelResultListener alloc] initWithChooser:chooser];
136
137     NSMutableArray *mimeTypes = [NSMutableArray arrayWithCapacity:settings.acceptMIMETypes.size()];
138     for (auto& type : settings.acceptMIMETypes)
139         [mimeTypes addObject:type];
140
141     WebMediaCaptureType captureType = WebMediaCaptureTypeNone;
142 #if ENABLE(MEDIA_CAPTURE)
143     captureType = webMediaCaptureType(settings.mediaCaptureType);
144 #endif
145     NSDictionary *configuration = @{
146         WebOpenPanelConfigurationAllowMultipleFilesKey: @(allowMultipleFiles),
147         WebOpenPanelConfigurationMimeTypesKey: mimeTypes,
148         WebOpenPanelConfigurationMediaCaptureTypeKey: @(captureType)
149     };
150
151     if (WebThreadIsCurrent()) {
152         dispatch_async(dispatch_get_main_queue(), ^{
153             [[webView() _UIKitDelegateForwarder] webView:webView() runOpenPanelForFileButtonWithResultListener:listener configuration:configuration];
154         });
155     } else
156         [[webView() _UIKitDelegateForwarder] webView:webView() runOpenPanelForFileButtonWithResultListener:listener configuration:configuration];
157
158     [listener release];
159 }
160
161 void WebChromeClientIOS::showShareSheet(ShareDataWithParsedURL&, CompletionHandler<void(bool)>&&)
162 {
163 }
164
165 #if ENABLE(IOS_TOUCH_EVENTS)
166
167 void WebChromeClientIOS::didPreventDefaultForEvent()
168 {
169     [[webView() _UIKitDelegateForwarder] webViewDidPreventDefaultForEvent:webView()];
170 }
171
172 #endif
173
174 void WebChromeClientIOS::didReceiveMobileDocType(bool isMobileDoctype)
175 {
176     if (isMobileDoctype)
177         [[webView() _UIKitDelegateForwarder] webViewDidReceiveMobileDocType:webView()];
178 }
179
180 void WebChromeClientIOS::setNeedsScrollNotifications(WebCore::Frame& frame, bool flag)
181 {
182     [[webView() _UIKitDelegateForwarder] webView:webView() needsScrollNotifications:[NSNumber numberWithBool:flag] forFrame:kit(&frame)];
183 }
184
185 void WebChromeClientIOS::observedContentChange(WebCore::Frame& frame)
186 {
187     if (!frame.page())
188         return;
189     [[webView() _UIKitDelegateForwarder] webView:webView() didObserveDeferredContentChange:frame.page()->contentChangeObserver().observedContentChange() forFrame:kit(&frame)];
190 }
191
192 static inline NSString *nameForViewportFitValue(ViewportFit value)
193 {
194     switch (value) {
195     case ViewportFit::Auto:
196         return WebViewportFitAutoValue;
197     case ViewportFit::Contain:
198         return WebViewportFitContainValue;
199     case ViewportFit::Cover:
200         return WebViewportFitCoverValue;
201     }
202     return WebViewportFitAutoValue;
203 }
204
205 static inline NSDictionary *dictionaryForViewportArguments(const WebCore::ViewportArguments& arguments)
206 {
207     return @{ WebViewportInitialScaleKey: @(arguments.zoom),
208               WebViewportMinimumScaleKey: @(arguments.minZoom),
209               WebViewportMaximumScaleKey: @(arguments.maxZoom),
210               WebViewportUserScalableKey: @(arguments.userZoom),
211               WebViewportShrinkToFitKey: @(0),
212               WebViewportFitKey: nameForViewportFitValue(arguments.viewportFit),
213               WebViewportWidthKey: @(arguments.width),
214               WebViewportHeightKey: @(arguments.height) };
215 }
216
217 FloatSize WebChromeClientIOS::screenSize() const
218 {
219     return FloatSize(WebCore::screenSize());
220 }
221
222 FloatSize WebChromeClientIOS::availableScreenSize() const
223 {
224     // WebKit1 code should query the WAKWindow for the available screen size.
225     ASSERT_NOT_REACHED();
226     return FloatSize();
227 }
228
229 FloatSize WebChromeClientIOS::overrideScreenSize() const
230 {
231     return screenSize();
232 }
233
234 void WebChromeClientIOS::dispatchViewportPropertiesDidChange(const WebCore::ViewportArguments& arguments) const
235 {
236     [[webView() _UIKitDelegateForwarder] webView:webView() didReceiveViewportArguments:dictionaryForViewportArguments(arguments)];
237 }
238
239 void WebChromeClientIOS::dispatchDisabledAdaptationsDidChange(const OptionSet<WebCore::DisabledAdaptations>&) const
240 {
241 }
242
243 void WebChromeClientIOS::notifyRevealedSelectionByScrollingFrame(WebCore::Frame& frame)
244 {
245     [[webView() _UIKitDelegateForwarder] revealedSelectionByScrollingWebFrame:kit(&frame)];
246 }
247
248 bool WebChromeClientIOS::isStopping()
249 {
250     return [webView() _isStopping];
251 }
252
253 void WebChromeClientIOS::didLayout(LayoutType changeType)
254 {
255     [[webView() _UIKitDelegate] webThreadWebViewDidLayout:webView() byScrolling:(changeType == ChromeClient::Scroll)];
256 }
257
258 void WebChromeClientIOS::didStartOverflowScroll()
259 {
260     [[[webView() _UIKitDelegateForwarder] asyncForwarder] webViewDidStartOverflowScroll:webView()];
261 }
262
263 void WebChromeClientIOS::didEndOverflowScroll()
264 {
265     [[[webView() _UIKitDelegateForwarder] asyncForwarder] webViewDidEndOverflowScroll:webView()];
266 }
267
268 void WebChromeClientIOS::suppressFormNotifications() 
269 {
270     m_formNotificationSuppressions++;
271 }
272
273 void WebChromeClientIOS::restoreFormNotifications() 
274 {
275     m_formNotificationSuppressions--;
276     ASSERT(m_formNotificationSuppressions >= 0);
277     if (m_formNotificationSuppressions < 0)
278         m_formNotificationSuppressions = 0;
279 }
280
281 void WebChromeClientIOS::elementDidFocus(WebCore::Element& element)
282 {
283     if (m_formNotificationSuppressions <= 0)
284         [[webView() _UIKitDelegateForwarder] webView:webView() elementDidFocusNode:kit(&element)];
285 }
286
287 void WebChromeClientIOS::elementDidBlur(WebCore::Element& element)
288 {
289     if (m_formNotificationSuppressions <= 0)
290         [[webView() _UIKitDelegateForwarder] webView:webView() elementDidBlurNode:kit(&element)];
291 }
292
293 bool WebChromeClientIOS::selectItemWritingDirectionIsNatural()
294 {
295     return false;
296 }
297
298 bool WebChromeClientIOS::selectItemAlignmentFollowsMenuWritingDirection()
299 {
300     return true;
301 }
302
303 RefPtr<WebCore::PopupMenu> WebChromeClientIOS::createPopupMenu(WebCore::PopupMenuClient& client) const
304 {
305     return adoptRef(new PopupMenuIOS(&client));
306 }
307
308 RefPtr<WebCore::SearchPopupMenu> WebChromeClientIOS::createSearchPopupMenu(WebCore::PopupMenuClient& client) const
309 {
310     return adoptRef(new SearchPopupMenuIOS(&client));
311 }
312
313 void WebChromeClientIOS::attachRootGraphicsLayer(Frame&, GraphicsLayer* graphicsLayer)
314 {
315     // FIXME: for non-root frames we rely on RenderView positioning the root layer,
316     // which is a hack. <rdar://problem/5906146>
317     // Send the delegate message on the web thread to avoid <rdar://problem/8567677>
318     [[webView() _UIKitDelegate] _webthread_webView:webView() attachRootLayer:graphicsLayer ? graphicsLayer->platformLayer() : 0];
319 }
320
321 void WebChromeClientIOS::didFlushCompositingLayers()
322 {
323     [[[webView() _UIKitDelegateForwarder] asyncForwarder] webViewDidCommitCompositingLayerChanges:webView()];
324 }
325
326 bool WebChromeClientIOS::fetchCustomFixedPositionLayoutRect(IntRect& rect)
327 {
328     NSRect updatedRect;
329     if ([webView() _fetchCustomFixedPositionLayoutRect:&updatedRect]) {
330         rect = enclosingIntRect(updatedRect);
331         return true;
332     }
333
334     return false;
335 }
336
337 void WebChromeClientIOS::updateViewportConstrainedLayers(HashMap<PlatformLayer*, std::unique_ptr<ViewportConstraints>>& layerMap, const HashMap<PlatformLayer*, PlatformLayer*>& stickyContainers)
338 {
339     [[webView() _fixedPositionContent] setViewportConstrainedLayers:layerMap stickyContainerMap:stickyContainers];
340 }
341
342 void WebChromeClientIOS::addOrUpdateScrollingLayer(Node* node, PlatformLayer* scrollingLayer, PlatformLayer* contentsLayer, const IntSize& scrollSize, bool allowHorizontalScrollbar, bool allowVerticalScrollbar)
343 {
344     DOMNode *domNode = kit(node);
345
346     [[[webView() _UIKitDelegateForwarder] asyncForwarder] webView:webView() didCreateOrUpdateScrollingLayer:scrollingLayer withContentsLayer:contentsLayer scrollSize:[NSValue valueWithSize:scrollSize] forNode:domNode
347         allowHorizontalScrollbar:allowHorizontalScrollbar allowVerticalScrollbar:allowVerticalScrollbar];
348 }
349
350 void WebChromeClientIOS::removeScrollingLayer(Node* node, PlatformLayer* scrollingLayer, PlatformLayer* contentsLayer)
351 {
352     DOMNode *domNode = kit(node);
353     [[[webView() _UIKitDelegateForwarder] asyncForwarder] webView:webView() willRemoveScrollingLayer:scrollingLayer withContentsLayer:contentsLayer forNode:domNode];
354 }
355
356 void WebChromeClientIOS::webAppOrientationsUpdated()
357 {
358     [[webView() _UIDelegateForwarder] webViewSupportedOrientationsUpdated:webView()];
359 }
360
361 void WebChromeClientIOS::focusedElementChanged(Element* element)
362 {
363     if (!is<HTMLInputElement>(element))
364         return;
365
366     HTMLInputElement& inputElement = downcast<HTMLInputElement>(*element);
367     if (!inputElement.isText())
368         return;
369
370     CallFormDelegate(webView(), @selector(didFocusTextField:inFrame:), kit(&inputElement), kit(inputElement.document().frame()));
371 }
372
373 void WebChromeClientIOS::showPlaybackTargetPicker(bool hasVideo, WebCore::RouteSharingPolicy, const String&)
374 {
375     CGPoint point = [[webView() _UIKitDelegateForwarder] interactionLocation];
376     CGRect elementRect = [[webView() mainFrame] elementRectAtPoint:point];
377     [[webView() _UIKitDelegateForwarder] showPlaybackTargetPicker:hasVideo fromRect:elementRect];
378 }
379
380 RefPtr<Icon> WebChromeClientIOS::createIconForFiles(const Vector<String>& filenames)
381 {
382     return Icon::createIconForFiles(filenames);
383 }
384
385 #if ENABLE(ORIENTATION_EVENTS)
386 int WebChromeClientIOS::deviceOrientation() const
387 {
388     return [webView() _deviceOrientation];
389 }
390 #endif
391
392 #endif // PLATFORM(IOS_FAMILY)