initial import
[vuplus_webkit] / Tools / DumpRenderTree / win / EditingDelegate.cpp
1 /*
2  * Copyright (C) 2007 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 "EditingDelegate.h"
31
32 #include "DumpRenderTree.h"
33 #include "LayoutTestController.h"
34 #include <WebCore/COMPtr.h>
35 #include <wtf/Platform.h>
36 #include <JavaScriptCore/Assertions.h>
37 #include <string>
38 #include <tchar.h>
39
40 using std::wstring;
41
42 EditingDelegate::EditingDelegate()
43     : m_refCount(1)
44     , m_acceptsEditing(true)
45 {
46 }
47
48 // IUnknown
49 HRESULT STDMETHODCALLTYPE EditingDelegate::QueryInterface(REFIID riid, void** ppvObject)
50 {
51     *ppvObject = 0;
52     if (IsEqualGUID(riid, IID_IUnknown))
53         *ppvObject = static_cast<IWebEditingDelegate*>(this);
54     else if (IsEqualGUID(riid, IID_IWebEditingDelegate))
55         *ppvObject = static_cast<IWebEditingDelegate*>(this);
56     else
57         return E_NOINTERFACE;
58
59     AddRef();
60     return S_OK;
61 }
62
63 ULONG STDMETHODCALLTYPE EditingDelegate::AddRef(void)
64 {
65     return ++m_refCount;
66 }
67
68 ULONG STDMETHODCALLTYPE EditingDelegate::Release(void)
69 {
70     ULONG newRef = --m_refCount;
71     if (!newRef)
72         delete this;
73
74     return newRef;
75 }
76
77 static wstring dumpPath(IDOMNode* node)
78 {
79     ASSERT(node);
80
81     wstring result;
82
83     BSTR name;
84     if (FAILED(node->nodeName(&name)))
85         return result;
86     result.assign(name, SysStringLen(name));
87     SysFreeString(name);
88
89     COMPtr<IDOMNode> parent;
90     if (SUCCEEDED(node->parentNode(&parent)))
91         result += TEXT(" > ") + dumpPath(parent.get());
92
93     return result;
94 }
95
96 static wstring dump(IDOMRange* range)
97 {
98     ASSERT(range);
99
100     int startOffset;
101     if (FAILED(range->startOffset(&startOffset)))
102         return 0;
103
104     int endOffset;
105     if (FAILED(range->endOffset(&endOffset)))
106         return 0;
107
108     COMPtr<IDOMNode> startContainer;
109     if (FAILED(range->startContainer(&startContainer)))
110         return 0;
111
112     COMPtr<IDOMNode> endContainer;
113     if (FAILED(range->endContainer(&endContainer)))
114         return 0;
115
116     wchar_t buffer[1024];
117     _snwprintf(buffer, ARRAYSIZE(buffer), L"range from %ld of %s to %ld of %s", startOffset, dumpPath(startContainer.get()), endOffset, dumpPath(endContainer.get()));
118     return buffer;
119 }
120
121 HRESULT STDMETHODCALLTYPE EditingDelegate::shouldBeginEditingInDOMRange( 
122     /* [in] */ IWebView* webView,
123     /* [in] */ IDOMRange* range,
124     /* [retval][out] */ BOOL* result)
125 {
126     if (!result) {
127         ASSERT_NOT_REACHED();
128         return E_POINTER;
129     }
130
131     if (::gLayoutTestController->dumpEditingCallbacks() && !done)
132         _tprintf(TEXT("EDITING DELEGATE: shouldBeginEditingInDOMRange:%s\n"), dump(range));
133
134     *result = m_acceptsEditing;
135     return S_OK;
136 }
137
138 HRESULT STDMETHODCALLTYPE EditingDelegate::shouldEndEditingInDOMRange( 
139     /* [in] */ IWebView* webView,
140     /* [in] */ IDOMRange* range,
141     /* [retval][out] */ BOOL* result)
142 {
143     if (!result) {
144         ASSERT_NOT_REACHED();
145         return E_POINTER;
146     }
147
148     if (::gLayoutTestController->dumpEditingCallbacks() && !done)
149         _tprintf(TEXT("EDITING DELEGATE: shouldEndEditingInDOMRange:%s\n"), dump(range));
150
151     *result = m_acceptsEditing;
152     return S_OK;
153 }
154
155 HRESULT STDMETHODCALLTYPE EditingDelegate::shouldInsertNode( 
156     /* [in] */ IWebView* webView,
157     /* [in] */ IDOMNode* node,
158     /* [in] */ IDOMRange* range,
159     /* [in] */ WebViewInsertAction action)
160 {
161     static LPCTSTR insertactionstring[] = {
162         TEXT("WebViewInsertActionTyped"),
163         TEXT("WebViewInsertActionPasted"),
164         TEXT("WebViewInsertActionDropped"),
165     };
166
167     if (::gLayoutTestController->dumpEditingCallbacks() && !done)
168         _tprintf(TEXT("EDITING DELEGATE: shouldInsertNode:%s replacingDOMRange:%s givenAction:%s\n"), dumpPath(node), dump(range), insertactionstring[action]);
169
170     return S_OK;
171 }
172
173 HRESULT STDMETHODCALLTYPE EditingDelegate::shouldInsertText( 
174     /* [in] */ IWebView* webView,
175     /* [in] */ BSTR text,
176     /* [in] */ IDOMRange* range,
177     /* [in] */ WebViewInsertAction action,
178     /* [retval][out] */ BOOL* result)
179 {
180     if (!result) {
181         ASSERT_NOT_REACHED();
182         return E_POINTER;
183     }
184
185     static LPCTSTR insertactionstring[] = {
186         TEXT("WebViewInsertActionTyped"),
187         TEXT("WebViewInsertActionPasted"),
188         TEXT("WebViewInsertActionDropped"),
189     };
190
191     if (::gLayoutTestController->dumpEditingCallbacks() && !done)
192         _tprintf(TEXT("EDITING DELEGATE: shouldInsertText:%s replacingDOMRange:%s givenAction:%s\n"), text ? text : TEXT(""), dump(range), insertactionstring[action]);
193
194     *result = m_acceptsEditing;
195     return S_OK;
196 }
197
198 HRESULT STDMETHODCALLTYPE EditingDelegate::shouldDeleteDOMRange( 
199     /* [in] */ IWebView* webView,
200     /* [in] */ IDOMRange* range,
201     /* [retval][out] */ BOOL* result)
202 {
203     if (!result) {
204         ASSERT_NOT_REACHED();
205         return E_POINTER;
206     }
207
208     if (::gLayoutTestController->dumpEditingCallbacks() && !done)
209         _tprintf(TEXT("EDITING DELEGATE: shouldDeleteDOMRange:%s\n"), dump(range));
210
211     *result = m_acceptsEditing;
212     return S_OK;
213 }
214
215 HRESULT STDMETHODCALLTYPE EditingDelegate::shouldChangeSelectedDOMRange( 
216     /* [in] */ IWebView* webView,
217     /* [in] */ IDOMRange* currentRange,
218     /* [in] */ IDOMRange* proposedRange,
219     /* [in] */ WebSelectionAffinity selectionAffinity,
220     /* [in] */ BOOL stillSelecting,
221     /* [retval][out] */ BOOL* result)
222 {
223     if (!result) {
224         ASSERT_NOT_REACHED();
225         return E_POINTER;
226     }
227
228     static LPCTSTR affinitystring[] = {
229         TEXT("NSSelectionAffinityUpstream"),
230         TEXT("NSSelectionAffinityDownstream")
231     };
232     static LPCTSTR boolstring[] = {
233         TEXT("FALSE"),
234         TEXT("TRUE")
235     };
236
237     if (::gLayoutTestController->dumpEditingCallbacks() && !done)
238         _tprintf(TEXT("EDITING DELEGATE: shouldChangeSelectedDOMRange:%s toDOMRange:%s affinity:%s stillSelecting:%s\n"), dump(currentRange), dump(proposedRange), affinitystring[selectionAffinity], boolstring[stillSelecting]);
239
240     *result = m_acceptsEditing;
241     return S_OK;
242 }
243
244 HRESULT STDMETHODCALLTYPE EditingDelegate::shouldApplyStyle( 
245     /* [in] */ IWebView* webView,
246     /* [in] */ IDOMCSSStyleDeclaration* style,
247     /* [in] */ IDOMRange* range,
248     /* [retval][out] */ BOOL* result)
249 {
250     if (!result) {
251         ASSERT_NOT_REACHED();
252         return E_POINTER;
253     }
254
255     if (::gLayoutTestController->dumpEditingCallbacks() && !done)
256         _tprintf(TEXT("EDITING DELEGATE: shouldApplyStyle:%s toElementsInDOMRange:%s\n"), TEXT("'style description'")/*[[style description] UTF8String]*/, dump(range));
257
258     *result = m_acceptsEditing;
259     return S_OK;
260 }
261
262 HRESULT STDMETHODCALLTYPE EditingDelegate::shouldChangeTypingStyle( 
263     /* [in] */ IWebView* webView,
264     /* [in] */ IDOMCSSStyleDeclaration* currentStyle,
265     /* [in] */ IDOMCSSStyleDeclaration* proposedStyle,
266     /* [retval][out] */ BOOL* result)
267 {
268     if (!result) {
269         ASSERT_NOT_REACHED();
270         return E_POINTER;
271     }
272
273     if (::gLayoutTestController->dumpEditingCallbacks() && !done)
274         _tprintf(TEXT("EDITING DELEGATE: shouldChangeTypingStyle:%s toStyle:%s\n"), TEXT("'currentStyle description'"), TEXT("'proposedStyle description'"));
275
276     *result = m_acceptsEditing;
277     return S_OK;
278 }
279
280 HRESULT STDMETHODCALLTYPE EditingDelegate::doPlatformCommand( 
281     /* [in] */ IWebView *webView,
282     /* [in] */ BSTR command,
283     /* [retval][out] */ BOOL *result)
284 {
285     if (!result) {
286         ASSERT_NOT_REACHED();
287         return E_POINTER;
288     }
289
290     if (::gLayoutTestController->dumpEditingCallbacks() && !done)
291         _tprintf(TEXT("EDITING DELEGATE: doPlatformCommand:%s\n"), command ? command : TEXT(""));
292
293     *result = m_acceptsEditing;
294     return S_OK;
295 }
296
297 HRESULT STDMETHODCALLTYPE EditingDelegate::webViewDidBeginEditing( 
298     /* [in] */ IWebNotification* notification)
299 {
300     if (::gLayoutTestController->dumpEditingCallbacks() && !done) {
301         BSTR name;
302         notification->name(&name);
303         _tprintf(TEXT("EDITING DELEGATE: webViewDidBeginEditing:%s\n"), name ? name : TEXT(""));
304         SysFreeString(name);
305     }
306     return S_OK;
307 }
308
309 HRESULT STDMETHODCALLTYPE EditingDelegate::webViewDidChange( 
310     /* [in] */ IWebNotification *notification)
311 {
312     if (::gLayoutTestController->dumpEditingCallbacks() && !done) {
313         BSTR name;
314         notification->name(&name);
315         _tprintf(TEXT("EDITING DELEGATE: webViewDidBeginEditing:%s\n"), name ? name : TEXT(""));
316         SysFreeString(name);
317     }
318     return S_OK;
319 }
320
321 HRESULT STDMETHODCALLTYPE EditingDelegate::webViewDidEndEditing( 
322     /* [in] */ IWebNotification *notification)
323 {
324     if (::gLayoutTestController->dumpEditingCallbacks() && !done) {
325         BSTR name;
326         notification->name(&name);
327         _tprintf(TEXT("EDITING DELEGATE: webViewDidEndEditing:%s\n"), name ? name : TEXT(""));
328         SysFreeString(name);
329     }
330     return S_OK;
331 }
332
333 HRESULT STDMETHODCALLTYPE EditingDelegate::webViewDidChangeTypingStyle( 
334     /* [in] */ IWebNotification *notification)
335 {
336     if (::gLayoutTestController->dumpEditingCallbacks() && !done) {
337         BSTR name;
338         notification->name(&name);
339         _tprintf(TEXT("EDITING DELEGATE: webViewDidChangeTypingStyle:%s\n"), name ? name : TEXT(""));
340         SysFreeString(name);
341     }
342     return S_OK;
343 }
344
345 HRESULT STDMETHODCALLTYPE EditingDelegate::webViewDidChangeSelection( 
346     /* [in] */ IWebNotification *notification)
347 {
348     if (::gLayoutTestController->dumpEditingCallbacks() && !done) {
349         BSTR name;
350         notification->name(&name);
351         _tprintf(TEXT("EDITING DELEGATE: webViewDidChangeSelection:%s\n"), name ? name : TEXT(""));
352         SysFreeString(name);
353     }
354     return S_OK;
355 }
356
357 static int indexOfFirstWordCharacter(const TCHAR* text)
358 {
359     const TCHAR* cursor = text;
360     while (*cursor && !iswalpha(*cursor))
361         ++cursor;
362     return *cursor ? (cursor - text) : -1;
363 };
364
365 static int wordLength(const TCHAR* text)
366 {
367     const TCHAR* cursor = text;
368     while (*cursor && iswalpha(*cursor))
369         ++cursor;
370     return cursor - text;
371 };
372
373 HRESULT STDMETHODCALLTYPE EditingDelegate::checkSpellingOfString(
374             /* [in] */ IWebView* view,
375             /* [in] */ LPCTSTR text,
376             /* [in] */ int length,
377             /* [out] */ int* misspellingLocation,
378             /* [out] */ int* misspellingLength)
379 {
380     static const TCHAR* misspelledWords[] = {
381         // These words are known misspelled words in webkit tests.
382         // If there are other misspelled words in webkit tests, please add them in
383         // this array.
384         TEXT("foo"),
385         TEXT("Foo"),
386         TEXT("baz"),
387         TEXT("fo"),
388         TEXT("LibertyF"),
389         TEXT("chello"),
390         TEXT("xxxtestxxx"),
391         TEXT("XXxxx"),
392         TEXT("Textx"),
393         TEXT("blockquoted"),
394         TEXT("asd"),
395         TEXT("Lorem"),
396         TEXT("Nunc"),
397         TEXT("Curabitur"),
398         TEXT("eu"),
399         TEXT("adlj"),
400         TEXT("adaasj"),
401         TEXT("sdklj"),
402         TEXT("jlkds"),
403         TEXT("jsaada"),
404         TEXT("jlda"),
405         TEXT("zz"),
406         TEXT("contentEditable"),
407         0,
408     };
409
410     wstring textString(text, length);
411     int wordStart = indexOfFirstWordCharacter(textString.c_str());
412     if (-1 == wordStart)
413         return S_OK;
414     wstring word = textString.substr(wordStart, wordLength(textString.c_str() + wordStart));
415     for (size_t i = 0; misspelledWords[i]; ++i) {
416         if (word == misspelledWords[i]) {
417             *misspellingLocation = wordStart;
418             *misspellingLength = word.size();
419             break;
420         }
421     }
422
423     return S_OK;
424 }