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