7a128c8da72e98b160910d25dc99e4ebbeeb5466
[WebKit-https.git] / Tools / DumpRenderTree / win / UIDelegate.cpp
1 /*
2  * Copyright (C) 2005, 2006, 2007, 2008, 2014 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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "UIDelegate.h"
31
32 #include "DumpRenderTree.h"
33 #include "DraggingInfo.h"
34 #include "EventSender.h"
35 #include "DRTDesktopNotificationPresenter.h"
36 #include "TestRunner.h"
37 #include <WebCore/COMPtr.h>
38 #include <wtf/Assertions.h>
39 #include <wtf/Platform.h>
40 #include <wtf/Vector.h>
41 #include <JavaScriptCore/JavaScriptCore.h>
42 #include <WebKit/WebKit.h>
43 #include <WebKit/WebKitCOMAPI.h>
44 #include <comutil.h>
45 #include <stdio.h>
46
47 using std::wstring;
48
49 class DRTUndoObject {
50 public:
51     DRTUndoObject(IWebUndoTarget* target, BSTR actionName, IUnknown* obj)
52         : m_target(target)
53         , m_actionName(actionName)
54         , m_obj(obj)
55     {
56     }
57
58     ~DRTUndoObject()
59     {
60     }
61
62     void invoke()
63     {
64         m_target->invoke(m_actionName, m_obj.get());
65     }
66
67 private:
68     IWebUndoTarget* m_target;
69     _bstr_t m_actionName;
70     COMPtr<IUnknown> m_obj;
71 };
72
73 class DRTUndoStack {
74 public:
75     bool isEmpty() const { return m_undoVector.isEmpty(); }
76     void clear() { m_undoVector.clear(); }
77
78     void push(DRTUndoObject* undoObject) { m_undoVector.append(undoObject); }
79     std::unique_ptr<DRTUndoObject> pop() { return m_undoVector.takeLast(); }
80
81 private:
82     Vector<std::unique_ptr<DRTUndoObject>> m_undoVector;
83 };
84
85 class DRTUndoManager {
86 public:
87     DRTUndoManager();
88
89     void removeAllActions();
90     void registerUndoWithTarget(IWebUndoTarget* target, BSTR actionName, IUnknown* obj);
91     void redo();
92     void undo();
93     bool canRedo() { return !m_redoStack->isEmpty(); }
94     bool canUndo() { return !m_undoStack->isEmpty(); }
95
96 private:
97     std::unique_ptr<DRTUndoStack> m_redoStack;
98     std::unique_ptr<DRTUndoStack> m_undoStack;
99     bool m_isRedoing;
100     bool m_isUndoing;
101 };
102
103 DRTUndoManager::DRTUndoManager()
104     : m_redoStack(std::make_unique<DRTUndoStack>())
105     , m_undoStack(std::make_unique<DRTUndoStack>())
106     , m_isRedoing(false)
107     , m_isUndoing(false)
108 {
109 }
110
111 void DRTUndoManager::removeAllActions()
112 {
113     m_redoStack->clear();
114     m_undoStack->clear();
115 }
116
117 void DRTUndoManager::registerUndoWithTarget(IWebUndoTarget* target, BSTR actionName, IUnknown* obj)
118 {
119     if (!m_isUndoing && !m_isRedoing)
120         m_redoStack->clear();
121
122     DRTUndoStack* stack = m_isUndoing ? m_redoStack.get() : m_undoStack.get();
123     stack->push(new DRTUndoObject(target, actionName, obj));
124 }
125
126 void DRTUndoManager::redo()
127 {
128     if (!canRedo())
129         return;
130
131     m_isRedoing = true;
132
133     m_redoStack->pop()->invoke();
134
135     m_isRedoing = false;
136 }
137
138 void DRTUndoManager::undo()
139 {
140     if (!canUndo())
141         return;
142
143     m_isUndoing = true;
144
145     m_undoStack->pop()->invoke();
146
147     m_isUndoing = false;
148 }
149
150 UIDelegate::UIDelegate()
151     : m_refCount(1)
152     , m_undoManager(std::make_unique<DRTUndoManager>())
153     , m_desktopNotifications(new DRTDesktopNotificationPresenter)
154 {
155     m_frame.bottom = 0;
156     m_frame.top = 0;
157     m_frame.left = 0;
158     m_frame.right = 0;
159 }
160
161 void UIDelegate::resetUndoManager()
162 {
163     m_undoManager = std::make_unique<DRTUndoManager>();
164 }
165
166 HRESULT UIDelegate::QueryInterface(REFIID riid, void** ppvObject)
167 {
168     *ppvObject = 0;
169     if (IsEqualGUID(riid, IID_IUnknown))
170         *ppvObject = static_cast<IWebUIDelegate*>(this);
171     else if (IsEqualGUID(riid, IID_IWebUIDelegate))
172         *ppvObject = static_cast<IWebUIDelegate*>(this);
173     else if (IsEqualGUID(riid, IID_IWebUIDelegate2))
174         *ppvObject = static_cast<IWebUIDelegate2*>(this);
175     else if (IsEqualGUID(riid, IID_IWebUIDelegatePrivate))
176         *ppvObject = static_cast<IWebUIDelegatePrivate*>(this);
177     else if (IsEqualGUID(riid, IID_IWebUIDelegatePrivate2))
178         *ppvObject = static_cast<IWebUIDelegatePrivate2*>(this);
179     else if (IsEqualGUID(riid, IID_IWebUIDelegatePrivate3))
180         *ppvObject = static_cast<IWebUIDelegatePrivate3*>(this);
181     else
182         return E_NOINTERFACE;
183
184     AddRef();
185     return S_OK;
186 }
187
188 ULONG UIDelegate::AddRef()
189 {
190     return ++m_refCount;
191 }
192
193 ULONG UIDelegate::Release()
194 {
195     ULONG newRef = --m_refCount;
196     if (!newRef)
197         delete(this);
198
199     return newRef;
200 }
201
202 HRESULT UIDelegate::hasCustomMenuImplementation(BOOL* hasCustomMenus)
203 {
204     *hasCustomMenus = TRUE;
205
206     return S_OK;
207 }
208
209 HRESULT UIDelegate::trackCustomPopupMenu(IWebView* /*sender*/, OLE_HANDLE /*menu*/, LPPOINT /*point*/)
210 {
211     // Do nothing
212     return S_OK;
213 }
214
215 HRESULT UIDelegate::registerUndoWithTarget(IWebUndoTarget* target, BSTR actionName, IUnknown* actionArg)
216 {
217     m_undoManager->registerUndoWithTarget(target, actionName, actionArg);
218     return S_OK;
219 }
220
221 HRESULT UIDelegate::removeAllActionsWithTarget(IWebUndoTarget*)
222 {
223     m_undoManager->removeAllActions();
224     return S_OK;
225 }
226
227 HRESULT UIDelegate::setActionTitle(BSTR /*actionTitle*/)
228 {
229     // It is not neccessary to implement this for DRT because there is
230     // menu to write out the title to.
231     return S_OK;
232 }
233
234 HRESULT UIDelegate::undo()
235 {
236     m_undoManager->undo();
237     return S_OK;
238 }
239
240 HRESULT UIDelegate::redo()
241 {
242     m_undoManager->redo();
243     return S_OK;
244 }
245
246 HRESULT UIDelegate::canUndo(BOOL* result)
247 {
248     if (!result)
249         return E_POINTER;
250
251     *result = m_undoManager->canUndo();
252     return S_OK;
253 }
254
255 HRESULT UIDelegate::canRedo(BOOL* result)
256 {
257     if (!result)
258         return E_POINTER;
259
260     *result = m_undoManager->canRedo();
261     return S_OK;
262 }
263
264 HRESULT UIDelegate::printFrame(IWebView* /*webView*/, IWebFrame* /*frame*/)
265 {
266     return E_NOTIMPL;
267 }
268
269 HRESULT UIDelegate::ftpDirectoryTemplatePath(IWebView* /*webView*/, BSTR* path)
270 {
271     if (!path)
272         return E_POINTER;
273     *path = 0;
274     return E_NOTIMPL;
275 }
276
277
278 HRESULT UIDelegate::webViewHeaderHeight(IWebView* /*webView*/, float* result)
279 {
280     if (!result)
281         return E_POINTER;
282     *result = 0;
283     return E_NOTIMPL;
284 }
285
286 HRESULT UIDelegate::webViewFooterHeight(IWebView* /*webView*/, float* result)
287 {
288     if (!result)
289         return E_POINTER;
290     *result = 0;
291     return E_NOTIMPL;
292 }
293
294 HRESULT UIDelegate::drawHeaderInRect(IWebView* /*webView*/, RECT* /*rect*/, OLE_HANDLE /*drawingContext*/)
295 {
296     return E_NOTIMPL;
297 }
298
299 HRESULT UIDelegate::drawFooterInRect(IWebView* /*webView*/, RECT* /*rect*/, OLE_HANDLE /*drawingContext*/, UINT /*pageIndex*/, UINT /*pageCount*/)
300 {
301     return E_NOTIMPL;
302 }
303
304 HRESULT UIDelegate::webViewPrintingMarginRect(IWebView* /*webView*/, RECT* /*rect*/)
305 {
306     return E_NOTIMPL;
307 }
308
309 HRESULT UIDelegate::canRunModal(IWebView* /*webView*/, BOOL* /*canRunBoolean*/)
310 {
311     return E_NOTIMPL;
312 }
313
314 HRESULT UIDelegate::createModalDialog(IWebView* /*sender*/, IWebURLRequest* /*request*/, IWebView** /*newWebView*/)
315 {
316     return E_NOTIMPL;
317 }
318
319 HRESULT UIDelegate::runModal(IWebView* /*webView*/)
320 {
321     return E_NOTIMPL;
322 }
323
324 HRESULT UIDelegate::isMenuBarVisible(IWebView* /*webView*/, BOOL* visible)
325 {
326     if (!visible)
327         return E_POINTER;
328     *visible = false;
329     return E_NOTIMPL;
330 }
331
332 HRESULT UIDelegate::setMenuBarVisible(IWebView* /*webView*/, BOOL /*visible*/)
333 {
334     return E_NOTIMPL;
335 }
336
337 HRESULT UIDelegate::runDatabaseSizeLimitPrompt(IWebView* /*webView*/, BSTR /*displayName*/, IWebFrame* /*initiatedByFrame*/, BOOL* allowed)
338 {
339     if (!allowed)
340         return E_POINTER;
341     *allowed = false;
342     return E_NOTIMPL;
343 }
344
345 HRESULT UIDelegate::paintCustomScrollbar(IWebView* /*webView*/, HDC /*hDC*/, RECT /*rect*/, WebScrollBarControlSize /*size*/, WebScrollbarControlState /*state*/,
346     WebScrollbarControlPart /*pressedPart*/, BOOL /*vertical*/, float /*value*/, float /*proportion*/, WebScrollbarControlPartMask /*parts*/)
347 {
348     return E_NOTIMPL;
349 }
350
351 HRESULT UIDelegate::paintCustomScrollCorner(IWebView* /*webView*/, HDC /*hDC*/, RECT /*rect*/)
352 {
353     return E_NOTIMPL;
354 }
355
356 HRESULT UIDelegate::setFrame(IWebView* /*sender*/, RECT* frame)
357 {
358     m_frame = *frame;
359     return S_OK;
360 }
361
362 HRESULT UIDelegate::webViewFrame(IWebView* /*sender*/, RECT* frame)
363 {
364     *frame = m_frame;
365     return S_OK;
366 }
367
368 HRESULT UIDelegate::runJavaScriptAlertPanelWithMessage(IWebView* /*sender*/, BSTR message)
369 {
370     printf("ALERT: %S\n", message ? message : L"");
371     fflush(stdout);
372
373     return S_OK;
374 }
375
376 HRESULT UIDelegate::runJavaScriptConfirmPanelWithMessage(IWebView* /*sender*/, BSTR message, BOOL* result)
377 {
378     printf("CONFIRM: %S\n", message ? message : L"");
379     *result = TRUE;
380
381     return S_OK;
382 }
383
384 HRESULT UIDelegate::runJavaScriptTextInputPanelWithPrompt(IWebView* /*sender*/, BSTR message, BSTR defaultText, BSTR* result)
385 {
386     printf("PROMPT: %S, default text: %S\n", message ? message : L"", defaultText ? defaultText : L"");
387     *result = SysAllocString(defaultText);
388
389     return S_OK;
390 }
391
392 HRESULT UIDelegate::runBeforeUnloadConfirmPanelWithMessage(IWebView* /*sender*/, BSTR message, IWebFrame* /*initiatedByFrame*/, BOOL* result)
393 {
394     if (!result)
395         return E_POINTER;
396     printf("CONFIRM NAVIGATION: %S\n", message ? message : L"");
397     *result = !gTestRunner->shouldStayOnPageAfterHandlingBeforeUnload();
398     return S_OK;
399 }
400
401 HRESULT UIDelegate::webViewAddMessageToConsole(IWebView* /*sender*/, BSTR message, int lineNumber, BSTR url, BOOL isError)
402 {
403     wstring newMessage;
404     if (message) {
405         newMessage = message;
406         size_t fileProtocol = newMessage.find(L"file://");
407         if (fileProtocol != wstring::npos)
408             newMessage = newMessage.substr(0, fileProtocol) + lastPathComponent(newMessage.substr(fileProtocol));
409     }
410
411     printf("CONSOLE MESSAGE: ");
412     if (lineNumber)
413         printf("line %d: ", lineNumber);
414     printf("%s\n", toUTF8(newMessage).c_str());
415     return S_OK;
416 }
417
418 HRESULT UIDelegate::doDragDrop(IWebView* /*sender*/, IDataObject* object, IDropSource* source, DWORD /*okEffect*/, DWORD* performedEffect)
419 {
420     if (!performedEffect)
421         return E_POINTER;
422
423     *performedEffect = 0;
424
425     draggingInfo = new DraggingInfo(object, source);
426     HRESULT oleDragAndDropReturnValue = DRAGDROP_S_CANCEL;
427     replaySavedEvents(&oleDragAndDropReturnValue);
428     if (draggingInfo) {
429         *performedEffect = draggingInfo->performedDropEffect();
430         delete draggingInfo;
431         draggingInfo = 0;
432     }
433     return oleDragAndDropReturnValue;
434 }
435
436 HRESULT UIDelegate::webViewGetDlgCode(IWebView* /*sender*/, UINT /*keyCode*/, LONG_PTR* code)
437 {
438     if (!code)
439         return E_POINTER;
440     *code = 0;
441     return E_NOTIMPL;
442 }
443
444 HRESULT UIDelegate::createWebViewWithRequest(IWebView* /*sender*/, IWebURLRequest* /*request*/, IWebView** newWebView)
445 {
446     if (!::gTestRunner->canOpenWindows())
447         return E_FAIL;
448     *newWebView = createWebViewAndOffscreenWindow();
449     return S_OK;
450 }
451
452 HRESULT UIDelegate::webViewClose(IWebView* sender)
453 {
454     HWND hostWindow;
455     sender->hostWindow(reinterpret_cast<OLE_HANDLE*>(&hostWindow));
456     DestroyWindow(hostWindow);
457     return S_OK;
458 }
459
460 HRESULT UIDelegate::webViewFocus(IWebView* sender)
461 {
462     HWND hostWindow;
463     sender->hostWindow(reinterpret_cast<OLE_HANDLE*>(&hostWindow));
464     SetForegroundWindow(hostWindow);
465     return S_OK; 
466 }
467
468 HRESULT UIDelegate::webViewUnfocus(IWebView* /*sender*/)
469 {
470     SetForegroundWindow(GetDesktopWindow());
471     return S_OK; 
472 }
473
474 HRESULT UIDelegate::webViewPainted(IWebView* /*sender*/)
475 {
476     return S_OK;
477 }
478
479 HRESULT UIDelegate::exceededDatabaseQuota(IWebView* sender, IWebFrame* frame, IWebSecurityOrigin* origin, BSTR databaseIdentifier)
480 {
481     _bstr_t protocol;
482     _bstr_t host;
483     unsigned short port;
484
485     origin->protocol(&protocol.GetBSTR());
486     origin->host(&host.GetBSTR());
487     origin->port(&port);
488
489     if (!done && gTestRunner->dumpDatabaseCallbacks())
490         printf("UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:{%S, %S, %i} database:%S\n", protocol, host, port, databaseIdentifier);
491
492     unsigned long long defaultQuota = 5 * 1024 * 1024;
493     double testDefaultQuota = gTestRunner->databaseDefaultQuota();
494     if (testDefaultQuota >= 0)
495         defaultQuota = testDefaultQuota;
496
497     COMPtr<IWebDatabaseManager> databaseManager;
498     COMPtr<IWebDatabaseManager> tmpDatabaseManager;
499
500     if (FAILED(WebKitCreateInstance(CLSID_WebDatabaseManager, 0, IID_IWebDatabaseManager, (void**)&tmpDatabaseManager))) {
501         origin->setQuota(defaultQuota);
502         return S_OK;
503     }
504     if (FAILED(tmpDatabaseManager->sharedWebDatabaseManager(&databaseManager))) {
505         origin->setQuota(defaultQuota);
506         return S_OK;
507     }
508     IPropertyBag* detailsBag;
509     if (FAILED(databaseManager->detailsForDatabase(databaseIdentifier, origin, &detailsBag))) {
510         origin->setQuota(defaultQuota);
511         return S_OK;
512     }
513     VARIANT var;
514     detailsBag->Read(WebDatabaseUsageKey, &var, 0);
515     unsigned long long expectedSize = V_UI8(&var);
516     unsigned long long newQuota = defaultQuota;
517
518     double maxQuota = gTestRunner->databaseMaxQuota();
519     if (maxQuota >= 0) {
520         if (defaultQuota < expectedSize && expectedSize <= maxQuota) {
521             newQuota = expectedSize;
522             printf("UI DELEGATE DATABASE CALLBACK: increased quota to %llu\n", newQuota);
523         }
524     }
525     origin->setQuota(newQuota);
526
527     return S_OK;
528 }
529
530 HRESULT UIDelegate::embeddedViewWithArguments(IWebView* /*sender*/, IWebFrame* /*frame*/, IPropertyBag* /*arguments*/, IWebEmbeddedView** view)
531 {
532     if (!view)
533         return E_POINTER;
534     *view = 0;
535     return E_NOTIMPL;
536 }
537
538 HRESULT UIDelegate::webViewClosing(IWebView* /*sender*/)
539 {
540     return E_NOTIMPL;
541 }
542
543 HRESULT UIDelegate::webViewSetCursor(IWebView* /*sender*/, OLE_HANDLE /*cursor*/)
544 {
545     return E_NOTIMPL;
546 }
547
548 HRESULT UIDelegate::webViewDidInvalidate(IWebView* /*sender*/)
549 {
550     return E_NOTIMPL;
551 }
552
553 HRESULT UIDelegate::setStatusText(IWebView*, BSTR text)
554
555     if (gTestRunner->dumpStatusCallbacks())
556         printf("UI DELEGATE STATUS CALLBACK: setStatusText:%S\n", text ? text : L"");
557     return S_OK;
558 }
559
560 HRESULT UIDelegate::desktopNotificationsDelegate(IWebDesktopNotificationsDelegate** result)
561 {
562     m_desktopNotifications.copyRefTo(result);
563     return S_OK;
564 }
565
566 HRESULT UIDelegate::createWebViewWithRequest(IWebView* /*sender*/, IWebURLRequest* /*request*/, IPropertyBag* /*windowFeatures*/, IWebView** /*newWebView*/)
567 {
568     return E_NOTIMPL;
569 }
570
571 HRESULT UIDelegate::drawBackground(IWebView* /*sender*/, OLE_HANDLE hdc, const RECT* dirtyRect)
572 {
573     return E_NOTIMPL;
574 }
575
576 HRESULT UIDelegate::decidePolicyForGeolocationRequest(IWebView* /*sender*/, IWebFrame* frame, IWebSecurityOrigin* /*origin*/, IWebGeolocationPolicyListener* /*listener*/)
577 {
578     return E_NOTIMPL;
579 }
580
581 HRESULT UIDelegate::didPressMissingPluginButton(IDOMElement* /*element*/)
582 {
583     printf("MISSING PLUGIN BUTTON PRESSED\n");
584     return S_OK;
585 }
586