1 /*
2 * Copyright (C) 2005, 2006, 2007, 2008 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 Computer, 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 "LayoutTestController.h"
36
37 #include <WebCore/COMPtr.h>
38 #include <wtf/Platform.h>
39 #include <wtf/Vector.h>
40 #include <JavaScriptCore/Assertions.h>
41 #include <JavaScriptCore/JavaScriptCore.h>
42 #include <WebKit/WebKit.h>
43 #include <stdio.h>
44
45 using std::wstring;
46
47 class DRTUndoObject {
48 public:
DRTUndoObject(IWebUndoTarget * target,BSTR actionName,IUnknown * obj)49 DRTUndoObject(IWebUndoTarget* target, BSTR actionName, IUnknown* obj)
50 : m_target(target)
51 , m_actionName(SysAllocString(actionName))
52 , m_obj(obj)
53 {
54 }
55
~DRTUndoObject()56 ~DRTUndoObject()
57 {
58 SysFreeString(m_actionName);
59 }
60
invoke()61 void invoke()
62 {
63 m_target->invoke(m_actionName, m_obj.get());
64 }
65
66 private:
67 IWebUndoTarget* m_target;
68 BSTR m_actionName;
69 COMPtr<IUnknown> m_obj;
70 };
71
72 class DRTUndoStack {
73 public:
~DRTUndoStack()74 ~DRTUndoStack() { deleteAllValues(m_undoVector); }
75
isEmpty() const76 bool isEmpty() const { return m_undoVector.isEmpty(); }
clear()77 void clear() { deleteAllValues(m_undoVector); m_undoVector.clear(); }
78
push(DRTUndoObject * undoObject)79 void push(DRTUndoObject* undoObject) { m_undoVector.append(undoObject); }
pop()80 DRTUndoObject* pop() { DRTUndoObject* top = m_undoVector.last(); m_undoVector.removeLast(); return top; }
81
82 private:
83 Vector<DRTUndoObject*> m_undoVector;
84 };
85
86 class DRTUndoManager {
87 public:
88 DRTUndoManager();
89
90 void removeAllActions();
91 void registerUndoWithTarget(IWebUndoTarget* target, BSTR actionName, IUnknown* obj);
92 void redo();
93 void undo();
canRedo()94 bool canRedo() { return !m_redoStack->isEmpty(); }
canUndo()95 bool canUndo() { return !m_undoStack->isEmpty(); }
96
97 private:
98 OwnPtr<DRTUndoStack> m_redoStack;
99 OwnPtr<DRTUndoStack> m_undoStack;
100 bool m_isRedoing;
101 bool m_isUndoing;
102 };
103
DRTUndoManager()104 DRTUndoManager::DRTUndoManager()
105 : m_redoStack(new DRTUndoStack)
106 , m_undoStack(new DRTUndoStack)
107 , m_isRedoing(false)
108 , m_isUndoing(false)
109 {
110 }
111
removeAllActions()112 void DRTUndoManager::removeAllActions()
113 {
114 m_redoStack->clear();
115 m_undoStack->clear();
116 }
117
registerUndoWithTarget(IWebUndoTarget * target,BSTR actionName,IUnknown * obj)118 void DRTUndoManager::registerUndoWithTarget(IWebUndoTarget* target, BSTR actionName, IUnknown* obj)
119 {
120 if (!m_isUndoing && !m_isRedoing)
121 m_redoStack->clear();
122
123 DRTUndoStack* stack = m_isUndoing ? m_redoStack.get() : m_undoStack.get();
124 stack->push(new DRTUndoObject(target, actionName, obj));
125 }
126
redo()127 void DRTUndoManager::redo()
128 {
129 if (!canRedo())
130 return;
131
132 m_isRedoing = true;
133
134 DRTUndoObject* redoObject = m_redoStack->pop();
135 redoObject->invoke();
136 delete redoObject;
137
138 m_isRedoing = false;
139 }
140
undo()141 void DRTUndoManager::undo()
142 {
143 if (!canUndo())
144 return;
145
146 m_isUndoing = true;
147
148 DRTUndoObject* undoObject = m_undoStack->pop();
149 undoObject->invoke();
150 delete undoObject;
151
152 m_isUndoing = false;
153 }
154
UIDelegate()155 UIDelegate::UIDelegate()
156 : m_refCount(1)
157 , m_undoManager(new DRTUndoManager)
158 {
159 m_frame.bottom = 0;
160 m_frame.top = 0;
161 m_frame.left = 0;
162 m_frame.right = 0;
163 }
164
resetUndoManager()165 void UIDelegate::resetUndoManager()
166 {
167 m_undoManager.set(new DRTUndoManager);
168 }
169
QueryInterface(REFIID riid,void ** ppvObject)170 HRESULT STDMETHODCALLTYPE UIDelegate::QueryInterface(REFIID riid, void** ppvObject)
171 {
172 *ppvObject = 0;
173 if (IsEqualGUID(riid, IID_IUnknown))
174 *ppvObject = static_cast<IWebUIDelegate*>(this);
175 else if (IsEqualGUID(riid, IID_IWebUIDelegate))
176 *ppvObject = static_cast<IWebUIDelegate*>(this);
177 else if (IsEqualGUID(riid, IID_IWebUIDelegatePrivate))
178 *ppvObject = static_cast<IWebUIDelegatePrivate*>(this);
179 else if (IsEqualGUID(riid, IID_IWebUIDelegatePrivate2))
180 *ppvObject = static_cast<IWebUIDelegatePrivate2*>(this);
181 else if (IsEqualGUID(riid, IID_IWebUIDelegatePrivate3))
182 *ppvObject = static_cast<IWebUIDelegatePrivate3*>(this);
183 else
184 return E_NOINTERFACE;
185
186 AddRef();
187 return S_OK;
188 }
189
AddRef()190 ULONG STDMETHODCALLTYPE UIDelegate::AddRef()
191 {
192 return ++m_refCount;
193 }
194
Release()195 ULONG STDMETHODCALLTYPE UIDelegate::Release()
196 {
197 ULONG newRef = --m_refCount;
198 if (!newRef)
199 delete(this);
200
201 return newRef;
202 }
203
hasCustomMenuImplementation(BOOL * hasCustomMenus)204 HRESULT STDMETHODCALLTYPE UIDelegate::hasCustomMenuImplementation(
205 /* [retval][out] */ BOOL *hasCustomMenus)
206 {
207 *hasCustomMenus = TRUE;
208
209 return S_OK;
210 }
211
trackCustomPopupMenu(IWebView * sender,OLE_HANDLE menu,LPPOINT point)212 HRESULT STDMETHODCALLTYPE UIDelegate::trackCustomPopupMenu(
213 /* [in] */ IWebView *sender,
214 /* [in] */ OLE_HANDLE menu,
215 /* [in] */ LPPOINT point)
216 {
217 // Do nothing
218 return S_OK;
219 }
220
registerUndoWithTarget(IWebUndoTarget * target,BSTR actionName,IUnknown * actionArg)221 HRESULT STDMETHODCALLTYPE UIDelegate::registerUndoWithTarget(
222 /* [in] */ IWebUndoTarget* target,
223 /* [in] */ BSTR actionName,
224 /* [in] */ IUnknown* actionArg)
225 {
226 m_undoManager->registerUndoWithTarget(target, actionName, actionArg);
227 return S_OK;
228 }
229
removeAllActionsWithTarget(IWebUndoTarget *)230 HRESULT STDMETHODCALLTYPE UIDelegate::removeAllActionsWithTarget(
231 /* [in] */ IWebUndoTarget*)
232 {
233 m_undoManager->removeAllActions();
234 return S_OK;
235 }
236
setActionTitle(BSTR actionTitle)237 HRESULT STDMETHODCALLTYPE UIDelegate::setActionTitle(
238 /* [in] */ BSTR actionTitle)
239 {
240 // It is not neccessary to implement this for DRT because there is
241 // menu to write out the title to.
242 return S_OK;
243 }
244
undo()245 HRESULT STDMETHODCALLTYPE UIDelegate::undo()
246 {
247 m_undoManager->undo();
248 return S_OK;
249 }
250
redo()251 HRESULT STDMETHODCALLTYPE UIDelegate::redo()
252 {
253 m_undoManager->redo();
254 return S_OK;
255 }
256
canUndo(BOOL * result)257 HRESULT STDMETHODCALLTYPE UIDelegate::canUndo(
258 /* [retval][out] */ BOOL* result)
259 {
260 if (!result)
261 return E_POINTER;
262
263 *result = m_undoManager->canUndo();
264 return S_OK;
265 }
266
canRedo(BOOL * result)267 HRESULT STDMETHODCALLTYPE UIDelegate::canRedo(
268 /* [retval][out] */ BOOL* result)
269 {
270 if (!result)
271 return E_POINTER;
272
273 *result = m_undoManager->canRedo();
274 return S_OK;
275 }
276
setFrame(IWebView *,RECT * frame)277 HRESULT STDMETHODCALLTYPE UIDelegate::setFrame(
278 /* [in] */ IWebView* /*sender*/,
279 /* [in] */ RECT* frame)
280 {
281 m_frame = *frame;
282 return S_OK;
283 }
284
webViewFrame(IWebView *,RECT * frame)285 HRESULT STDMETHODCALLTYPE UIDelegate::webViewFrame(
286 /* [in] */ IWebView* /*sender*/,
287 /* [retval][out] */ RECT* frame)
288 {
289 *frame = m_frame;
290 return S_OK;
291 }
292
runJavaScriptAlertPanelWithMessage(IWebView *,BSTR message)293 HRESULT STDMETHODCALLTYPE UIDelegate::runJavaScriptAlertPanelWithMessage(
294 /* [in] */ IWebView* /*sender*/,
295 /* [in] */ BSTR message)
296 {
297 printf("ALERT: %S\n", message ? message : L"");
298
299 return S_OK;
300 }
301
runJavaScriptConfirmPanelWithMessage(IWebView * sender,BSTR message,BOOL * result)302 HRESULT STDMETHODCALLTYPE UIDelegate::runJavaScriptConfirmPanelWithMessage(
303 /* [in] */ IWebView* sender,
304 /* [in] */ BSTR message,
305 /* [retval][out] */ BOOL* result)
306 {
307 printf("CONFIRM: %S\n", message ? message : L"");
308 *result = TRUE;
309
310 return S_OK;
311 }
312
runJavaScriptTextInputPanelWithPrompt(IWebView * sender,BSTR message,BSTR defaultText,BSTR * result)313 HRESULT STDMETHODCALLTYPE UIDelegate::runJavaScriptTextInputPanelWithPrompt(
314 /* [in] */ IWebView *sender,
315 /* [in] */ BSTR message,
316 /* [in] */ BSTR defaultText,
317 /* [retval][out] */ BSTR *result)
318 {
319 printf("PROMPT: %S, default text: %S\n", message ? message : L"", defaultText ? defaultText : L"");
320 *result = SysAllocString(defaultText);
321
322 return S_OK;
323 }
324
runBeforeUnloadConfirmPanelWithMessage(IWebView *,BSTR,IWebFrame *,BOOL * result)325 HRESULT STDMETHODCALLTYPE UIDelegate::runBeforeUnloadConfirmPanelWithMessage(
326 /* [in] */ IWebView* /*sender*/,
327 /* [in] */ BSTR /*message*/,
328 /* [in] */ IWebFrame* /*initiatedByFrame*/,
329 /* [retval][out] */ BOOL* result)
330 {
331 if (!result)
332 return E_POINTER;
333 *result = TRUE;
334 return E_NOTIMPL;
335 }
336
webViewAddMessageToConsole(IWebView * sender,BSTR message,int lineNumber,BSTR url,BOOL isError)337 HRESULT STDMETHODCALLTYPE UIDelegate::webViewAddMessageToConsole(
338 /* [in] */ IWebView* sender,
339 /* [in] */ BSTR message,
340 /* [in] */ int lineNumber,
341 /* [in] */ BSTR url,
342 /* [in] */ BOOL isError)
343 {
344 wstring newMessage;
345 if (message) {
346 newMessage = message;
347 size_t fileProtocol = newMessage.find(L"file://");
348 if (fileProtocol != wstring::npos)
349 newMessage = newMessage.substr(0, fileProtocol) + urlSuitableForTestResult(newMessage.substr(fileProtocol));
350 }
351
352 printf("CONSOLE MESSAGE: line %d: %S\n", lineNumber, newMessage.c_str());
353 return S_OK;
354 }
355
doDragDrop(IWebView * sender,IDataObject * object,IDropSource * source,DWORD okEffect,DWORD * performedEffect)356 HRESULT STDMETHODCALLTYPE UIDelegate::doDragDrop(
357 /* [in] */ IWebView* sender,
358 /* [in] */ IDataObject* object,
359 /* [in] */ IDropSource* source,
360 /* [in] */ DWORD okEffect,
361 /* [retval][out] */ DWORD* performedEffect)
362 {
363 if (!performedEffect)
364 return E_POINTER;
365
366 *performedEffect = 0;
367
368 draggingInfo = new DraggingInfo(object, source);
369 replaySavedEvents();
370 return S_OK;
371 }
372
webViewGetDlgCode(IWebView *,UINT,LONG_PTR * code)373 HRESULT STDMETHODCALLTYPE UIDelegate::webViewGetDlgCode(
374 /* [in] */ IWebView* /*sender*/,
375 /* [in] */ UINT /*keyCode*/,
376 /* [retval][out] */ LONG_PTR *code)
377 {
378 if (!code)
379 return E_POINTER;
380 *code = 0;
381 return E_NOTIMPL;
382 }
383
createWebViewWithRequest(IWebView * sender,IWebURLRequest * request,IWebView ** newWebView)384 HRESULT STDMETHODCALLTYPE UIDelegate::createWebViewWithRequest(
385 /* [in] */ IWebView *sender,
386 /* [in] */ IWebURLRequest *request,
387 /* [retval][out] */ IWebView **newWebView)
388 {
389 if (!::gLayoutTestController->canOpenWindows())
390 return E_FAIL;
391 *newWebView = createWebViewAndOffscreenWindow();
392 return S_OK;
393 }
394
webViewClose(IWebView * sender)395 HRESULT STDMETHODCALLTYPE UIDelegate::webViewClose(
396 /* [in] */ IWebView *sender)
397 {
398 HWND hostWindow;
399 sender->hostWindow(reinterpret_cast<OLE_HANDLE*>(&hostWindow));
400 DestroyWindow(hostWindow);
401 return S_OK;
402 }
403
webViewFocus(IWebView * sender)404 HRESULT STDMETHODCALLTYPE UIDelegate::webViewFocus(
405 /* [in] */ IWebView *sender)
406 {
407 HWND hostWindow;
408 sender->hostWindow(reinterpret_cast<OLE_HANDLE*>(&hostWindow));
409 SetForegroundWindow(hostWindow);
410 return S_OK;
411 }
412
webViewUnfocus(IWebView * sender)413 HRESULT STDMETHODCALLTYPE UIDelegate::webViewUnfocus(
414 /* [in] */ IWebView *sender)
415 {
416 SetForegroundWindow(GetDesktopWindow());
417 return S_OK;
418 }
419
webViewPainted(IWebView * sender)420 HRESULT STDMETHODCALLTYPE UIDelegate::webViewPainted(
421 /* [in] */ IWebView *sender)
422 {
423 return S_OK;
424 }
425
exceededDatabaseQuota(IWebView * sender,IWebFrame * frame,IWebSecurityOrigin * origin,BSTR databaseIdentifier)426 HRESULT STDMETHODCALLTYPE UIDelegate::exceededDatabaseQuota(
427 /* [in] */ IWebView *sender,
428 /* [in] */ IWebFrame *frame,
429 /* [in] */ IWebSecurityOrigin *origin,
430 /* [in] */ BSTR databaseIdentifier)
431 {
432 static const unsigned long long defaultQuota = 5 * 1024 * 1024;
433 origin->setQuota(defaultQuota);
434
435 return S_OK;
436 }
437
438
setStatusText(IWebView *,BSTR text)439 HRESULT STDMETHODCALLTYPE UIDelegate::setStatusText(IWebView*, BSTR text)
440 {
441 if (gLayoutTestController->dumpStatusCallbacks())
442 printf("UI DELEGATE STATUS CALLBACK: setStatusText:%S\n", text ? text : L"");
443 return S_OK;
444 }
445