WebKit/mac:
[WebKit.git] / WebKit / win / WebView.cpp
1 /*
2  * Copyright (C) 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  * 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 COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "WebKitDLL.h"
28 #include "WebView.h"
29
30 #include "CFDictionaryPropertyBag.h"
31 #include "DOMCoreClasses.h"
32 #include "MarshallingHelpers.h"
33 #include "WebDatabaseManager.h"
34 #include "WebDocumentLoader.h"
35 #include "WebEditorClient.h"
36 #include "WebElementPropertyBag.h"
37 #include "WebFrame.h"
38 #include "WebBackForwardList.h"
39 #include "WebChromeClient.h"
40 #include "WebContextMenuClient.h"
41 #include "WebCoreTextRenderer.h"
42 #include "WebDragClient.h"
43 #include "WebIconDatabase.h"
44 #include "WebInspector.h"
45 #include "WebInspectorClient.h"
46 #include "WebKit.h"
47 #include "WebKitStatisticsPrivate.h"
48 #include "WebKitSystemBits.h"
49 #include "WebMutableURLRequest.h"
50 #include "WebNotificationCenter.h"
51 #include "WebPreferences.h"
52 #pragma warning( push, 0 )
53 #include <WebCore/ApplicationCacheStorage.h>
54 #include <WebCore/AXObjectCache.h>
55 #include <WebCore/BString.h>
56 #include <WebCore/Cache.h>
57 #include <WebCore/ContextMenu.h>
58 #include <WebCore/ContextMenuController.h>
59 #include <WebCore/CookieStorageWin.h>
60 #include <WebCore/CString.h>
61 #include <WebCore/Cursor.h>
62 #include <WebCore/Document.h>
63 #include <WebCore/DragController.h>
64 #include <WebCore/DragData.h>
65 #include <WebCore/Editor.h>
66 #include <WebCore/EventHandler.h>
67 #include <WebCore/EventNames.h>
68 #include <WebCore/FileSystem.h>
69 #include <WebCore/FocusController.h>
70 #include <WebCore/FloatQuad.h>
71 #include <WebCore/FrameLoader.h>
72 #include <WebCore/FrameTree.h>
73 #include <WebCore/FrameView.h>
74 #include <WebCore/FrameWin.h>
75 #include <WebCore/GDIObjectCounter.h>
76 #include <WebCore/GraphicsContext.h>
77 #include <WebCore/HistoryItem.h>
78 #include <WebCore/HitTestResult.h>
79 #include <WebCore/IntRect.h>
80 #include <WebCore/KeyboardEvent.h>
81 #include <WebCore/Language.h>
82 #include <WebCore/Logging.h>
83 #include <WebCore/MIMETypeRegistry.h>
84 #include <WebCore/Page.h>
85 #include <WebCore/PageCache.h>
86 #include <WebCore/PlatformKeyboardEvent.h>
87 #include <WebCore/PlatformMouseEvent.h>
88 #include <WebCore/PlatformWheelEvent.h>
89 #include <WebCore/PluginDatabase.h>
90 #include <WebCore/PluginInfoStore.h>
91 #include <WebCore/PluginView.h>
92 #include <WebCore/ProgressTracker.h>
93 #include <WebCore/RenderTheme.h>
94 #include <WebCore/ResourceHandle.h>
95 #include <WebCore/ResourceHandleClient.h>
96 #include <WebCore/ScriptValue.h>
97 #include <WebCore/ScrollbarTheme.h>
98 #include <WebCore/SelectionController.h>
99 #include <WebCore/Settings.h>
100 #include <WebCore/SimpleFontData.h>
101 #include <WebCore/TypingCommand.h>
102 #include <WebCore/WindowMessageBroadcaster.h>
103 #pragma warning(pop)
104 #include <JavaScriptCore/InitializeThreading.h>
105 #include <JavaScriptCore/JSLock.h>
106 #include <JavaScriptCore/JSValue.h>
107
108 #if PLATFORM(CG)
109 #include <CoreGraphics/CGContext.h>
110 #endif
111
112 #if PLATFORM(CF)
113 #include <CoreFoundation/CoreFoundation.h>
114 #endif
115
116 #if USE(CFNETWORK)
117 #include <CFNetwork/CFURLCachePriv.h>
118 #include <CFNetwork/CFURLProtocolPriv.h>
119 #include <WebKitSystemInterface/WebKitSystemInterface.h> 
120 #endif
121
122 #include <wtf/HashSet.h>
123 #include <dimm.h>
124 #include <oleacc.h>
125 #include <ShlObj.h>
126 #include <tchar.h>
127 #include <windowsx.h>
128
129 using namespace WebCore;
130 using JSC::JSLock;
131 using std::min;
132 using std::max;
133
134 static HMODULE accessibilityLib;
135 static HashSet<WebView*> pendingDeleteBackingStoreSet;
136
137 static String osVersion();
138 static String webKitVersion();
139
140 WebView* kit(Page* page)
141 {
142     return page ? static_cast<WebChromeClient*>(page->chrome()->client())->webView() : 0;
143 }
144
145 class PreferencesChangedOrRemovedObserver : public IWebNotificationObserver {
146 public:
147     static PreferencesChangedOrRemovedObserver* sharedInstance();
148
149 private:
150     PreferencesChangedOrRemovedObserver() {}
151     ~PreferencesChangedOrRemovedObserver() {}
152
153     virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, void**) { return E_FAIL; }
154     virtual ULONG STDMETHODCALLTYPE AddRef(void) { return 0; }
155     virtual ULONG STDMETHODCALLTYPE Release(void) { return 0; }
156
157 public:
158     // IWebNotificationObserver
159     virtual HRESULT STDMETHODCALLTYPE onNotify( 
160         /* [in] */ IWebNotification* notification);
161
162 private:
163     HRESULT notifyPreferencesChanged(WebCacheModel);
164     HRESULT notifyPreferencesRemoved(WebCacheModel);
165 };
166
167 PreferencesChangedOrRemovedObserver* PreferencesChangedOrRemovedObserver::sharedInstance()
168 {
169     static PreferencesChangedOrRemovedObserver* shared = new PreferencesChangedOrRemovedObserver;
170     return shared;
171 }
172
173 HRESULT PreferencesChangedOrRemovedObserver::onNotify(IWebNotification* notification)
174 {
175     HRESULT hr = S_OK;
176
177     COMPtr<IUnknown> unkPrefs;
178     hr = notification->getObject(&unkPrefs);
179     if (FAILED(hr))
180         return hr;
181
182     COMPtr<IWebPreferences> preferences(Query, unkPrefs);
183     if (!preferences)
184         return E_NOINTERFACE;
185
186     WebCacheModel cacheModel;
187     hr = preferences->cacheModel(&cacheModel);
188     if (FAILED(hr))
189         return hr;
190
191     BSTR nameBSTR;
192     hr = notification->name(&nameBSTR);
193     if (FAILED(hr))
194         return hr;
195     BString name;
196     name.adoptBSTR(nameBSTR);
197
198     if (wcscmp(name, WebPreferences::webPreferencesChangedNotification()) == 0)
199         return notifyPreferencesChanged(cacheModel);
200
201     if (wcscmp(name, WebPreferences::webPreferencesRemovedNotification()) == 0)
202         return notifyPreferencesRemoved(cacheModel);
203
204     ASSERT_NOT_REACHED();
205     return E_FAIL;
206 }
207
208 HRESULT PreferencesChangedOrRemovedObserver::notifyPreferencesChanged(WebCacheModel cacheModel)
209 {
210     HRESULT hr = S_OK;
211
212     if (!WebView::didSetCacheModel() || cacheModel > WebView::cacheModel())
213         WebView::setCacheModel(cacheModel);
214     else if (cacheModel < WebView::cacheModel()) {
215         WebCacheModel sharedPreferencesCacheModel;
216         hr = WebPreferences::sharedStandardPreferences()->cacheModel(&sharedPreferencesCacheModel);
217         if (FAILED(hr))
218             return hr;
219         WebView::setCacheModel(max(sharedPreferencesCacheModel, WebView::maxCacheModelInAnyInstance()));
220     }
221
222     return hr;
223 }
224
225 HRESULT PreferencesChangedOrRemovedObserver::notifyPreferencesRemoved(WebCacheModel cacheModel)
226 {
227     HRESULT hr = S_OK;
228
229     if (cacheModel == WebView::cacheModel()) {
230         WebCacheModel sharedPreferencesCacheModel;
231         hr = WebPreferences::sharedStandardPreferences()->cacheModel(&sharedPreferencesCacheModel);
232         if (FAILED(hr))
233             return hr;
234         WebView::setCacheModel(max(sharedPreferencesCacheModel, WebView::maxCacheModelInAnyInstance()));
235     }
236
237     return hr;
238 }
239
240
241 const LPCWSTR kWebViewWindowClassName = L"WebViewWindowClass";
242
243 const int WM_XP_THEMECHANGED = 0x031A;
244 const int WM_VISTA_MOUSEHWHEEL = 0x020E;
245
246 static const int maxToolTipWidth = 250;
247
248 static const int delayBeforeDeletingBackingStoreMsec = 5000;
249
250 static ATOM registerWebView();
251 static LRESULT CALLBACK WebViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
252
253 static void initializeStaticObservers();
254
255 static HRESULT updateSharedSettingsFromPreferencesIfNeeded(IWebPreferences*);
256
257 HRESULT createMatchEnumerator(Vector<IntRect>* rects, IEnumTextMatches** matches);
258
259 static bool continuousSpellCheckingEnabled;
260 static bool grammarCheckingEnabled;
261
262 static bool s_didSetCacheModel;
263 static WebCacheModel s_cacheModel = WebCacheModelDocumentViewer;
264
265 enum {
266     UpdateActiveStateTimer = 1,
267     DeleteBackingStoreTimer = 2,
268 };
269
270 // WebView ----------------------------------------------------------------
271
272 bool WebView::s_allowSiteSpecificHacks = false;
273
274 WebView::WebView()
275 : m_refCount(0)
276 , m_hostWindow(0)
277 , m_viewWindow(0)
278 , m_mainFrame(0)
279 , m_page(0)
280 , m_hasCustomDropTarget(false)
281 , m_useBackForwardList(true)
282 , m_userAgentOverridden(false)
283 , m_zoomMultiplier(1.0f)
284 , m_mouseActivated(false)
285 , m_dragData(0)
286 , m_currentCharacterCode(0)
287 , m_isBeingDestroyed(false)
288 , m_paintCount(0)
289 , m_hasSpellCheckerDocumentTag(false)
290 , m_smartInsertDeleteEnabled(false)
291 , m_didClose(false)
292 , m_inIMEComposition(0)
293 , m_toolTipHwnd(0)
294 , m_closeWindowTimer(this, &WebView::closeWindowTimerFired)
295 , m_topLevelParent(0)
296 , m_deleteBackingStoreTimerActive(false)
297 , m_transparent(false)
298 , m_selectTrailingWhitespaceEnabled(false)
299 {
300     JSC::initializeThreading();
301
302     m_backingStoreSize.cx = m_backingStoreSize.cy = 0;
303
304     CoCreateInstance(CLSID_DragDropHelper, 0, CLSCTX_INPROC_SERVER, IID_IDropTargetHelper,(void**)&m_dropTargetHelper);
305
306     initializeStaticObservers();
307
308     WebPreferences* sharedPreferences = WebPreferences::sharedStandardPreferences();
309     BOOL enabled;
310     if (SUCCEEDED(sharedPreferences->continuousSpellCheckingEnabled(&enabled)))
311         continuousSpellCheckingEnabled = !!enabled;
312     if (SUCCEEDED(sharedPreferences->grammarCheckingEnabled(&enabled)))
313         grammarCheckingEnabled = !!enabled;
314
315     WebViewCount++;
316     gClassCount++;
317     gClassNameCount.add("WebView");
318 }
319
320 WebView::~WebView()
321 {
322     deleteBackingStore();
323
324     // <rdar://4958382> m_viewWindow will be destroyed when m_hostWindow is destroyed, but if
325     // setHostWindow was never called we will leak our HWND. If we still have a valid HWND at
326     // this point, we should just destroy it ourselves.
327     if (!isBeingDestroyed() && ::IsWindow(m_viewWindow))
328         ::DestroyWindow(m_viewWindow);
329
330     // the tooltip window needs to be explicitly destroyed since it isn't a WS_CHILD
331     if (::IsWindow(m_toolTipHwnd))
332         ::DestroyWindow(m_toolTipHwnd);
333
334     ASSERT(!m_page);
335     ASSERT(!m_preferences);
336
337     WebViewCount--;
338     gClassCount--;
339     gClassNameCount.remove("WebView");
340 }
341
342 WebView* WebView::createInstance()
343 {
344     WebView* instance = new WebView();
345     instance->AddRef();
346     return instance;
347 }
348
349 void initializeStaticObservers()
350 {
351     static bool initialized;
352     if (initialized)
353         return;
354     initialized = true;
355
356     IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal();
357     notifyCenter->addObserver(PreferencesChangedOrRemovedObserver::sharedInstance(), WebPreferences::webPreferencesChangedNotification(), 0);
358     notifyCenter->addObserver(PreferencesChangedOrRemovedObserver::sharedInstance(), WebPreferences::webPreferencesRemovedNotification(), 0);
359 }
360
361 static HashSet<WebView*>& allWebViewsSet()
362 {
363     static HashSet<WebView*> allWebViewsSet;
364     return allWebViewsSet;
365 }
366
367 void WebView::addToAllWebViewsSet()
368 {
369     allWebViewsSet().add(this);
370 }
371
372 void WebView::removeFromAllWebViewsSet()
373 {
374     allWebViewsSet().remove(this);
375 }
376
377 void WebView::setCacheModel(WebCacheModel cacheModel)
378 {
379 #if USE(CFNETWORK)
380     if (s_didSetCacheModel && cacheModel == s_cacheModel)
381         return;
382
383     RetainPtr<CFURLCacheRef> cfurlCache(AdoptCF, CFURLCacheCopySharedURLCache());
384     RetainPtr<CFStringRef> cfurlCacheDirectory(AdoptCF, wkCopyFoundationCacheDirectory());
385     if (!cfurlCacheDirectory)
386         cfurlCacheDirectory.adoptCF(WebCore::localUserSpecificStorageDirectory().createCFString());
387
388     // As a fudge factor, use 1000 instead of 1024, in case the reported byte 
389     // count doesn't align exactly to a megabyte boundary.
390     unsigned long long memSize = WebMemorySize() / 1024 / 1000;
391     unsigned long long diskFreeSize = WebVolumeFreeSize(cfurlCacheDirectory.get()) / 1024 / 1000;
392
393     unsigned cacheTotalCapacity = 0;
394     unsigned cacheMinDeadCapacity = 0;
395     unsigned cacheMaxDeadCapacity = 0;
396     double deadDecodedDataDeletionInterval = 0;
397
398     unsigned pageCacheCapacity = 0;
399
400     CFIndex cfurlCacheMemoryCapacity = 0;
401     CFIndex cfurlCacheDiskCapacity = 0;
402
403     switch (cacheModel) {
404     case WebCacheModelDocumentViewer: {
405         // Page cache capacity (in pages)
406         pageCacheCapacity = 0;
407
408         // Object cache capacities (in bytes)
409         if (memSize >= 2048)
410             cacheTotalCapacity = 96 * 1024 * 1024;
411         else if (memSize >= 1536)
412             cacheTotalCapacity = 64 * 1024 * 1024;
413         else if (memSize >= 1024)
414             cacheTotalCapacity = 32 * 1024 * 1024;
415         else if (memSize >= 512)
416             cacheTotalCapacity = 16 * 1024 * 1024; 
417
418         cacheMinDeadCapacity = 0;
419         cacheMaxDeadCapacity = 0;
420
421         // Foundation memory cache capacity (in bytes)
422         cfurlCacheMemoryCapacity = 0;
423
424         // Foundation disk cache capacity (in bytes)
425         cfurlCacheDiskCapacity = CFURLCacheDiskCapacity(cfurlCache.get());
426
427         break;
428     }
429     case WebCacheModelDocumentBrowser: {
430         // Page cache capacity (in pages)
431         if (memSize >= 1024)
432             pageCacheCapacity = 3;
433         else if (memSize >= 512)
434             pageCacheCapacity = 2;
435         else if (memSize >= 256)
436             pageCacheCapacity = 1;
437         else
438             pageCacheCapacity = 0;
439
440         // Object cache capacities (in bytes)
441         if (memSize >= 2048)
442             cacheTotalCapacity = 96 * 1024 * 1024;
443         else if (memSize >= 1536)
444             cacheTotalCapacity = 64 * 1024 * 1024;
445         else if (memSize >= 1024)
446             cacheTotalCapacity = 32 * 1024 * 1024;
447         else if (memSize >= 512)
448             cacheTotalCapacity = 16 * 1024 * 1024; 
449
450         cacheMinDeadCapacity = cacheTotalCapacity / 8;
451         cacheMaxDeadCapacity = cacheTotalCapacity / 4;
452
453         // Foundation memory cache capacity (in bytes)
454         if (memSize >= 2048)
455             cfurlCacheMemoryCapacity = 4 * 1024 * 1024;
456         else if (memSize >= 1024)
457             cfurlCacheMemoryCapacity = 2 * 1024 * 1024;
458         else if (memSize >= 512)
459             cfurlCacheMemoryCapacity = 1 * 1024 * 1024;
460         else
461             cfurlCacheMemoryCapacity =      512 * 1024; 
462
463         // Foundation disk cache capacity (in bytes)
464         if (diskFreeSize >= 16384)
465             cfurlCacheDiskCapacity = 50 * 1024 * 1024;
466         else if (diskFreeSize >= 8192)
467             cfurlCacheDiskCapacity = 40 * 1024 * 1024;
468         else if (diskFreeSize >= 4096)
469             cfurlCacheDiskCapacity = 30 * 1024 * 1024;
470         else
471             cfurlCacheDiskCapacity = 20 * 1024 * 1024;
472
473         break;
474     }
475     case WebCacheModelPrimaryWebBrowser: {
476         // Page cache capacity (in pages)
477         // (Research indicates that value / page drops substantially after 3 pages.)
478         if (memSize >= 2048)
479             pageCacheCapacity = 5;
480         else if (memSize >= 1024)
481             pageCacheCapacity = 4;
482         else if (memSize >= 512)
483             pageCacheCapacity = 3;
484         else if (memSize >= 256)
485             pageCacheCapacity = 2;
486         else
487             pageCacheCapacity = 1;
488
489         // Object cache capacities (in bytes)
490         // (Testing indicates that value / MB depends heavily on content and
491         // browsing pattern. Even growth above 128MB can have substantial 
492         // value / MB for some content / browsing patterns.)
493         if (memSize >= 2048)
494             cacheTotalCapacity = 128 * 1024 * 1024;
495         else if (memSize >= 1536)
496             cacheTotalCapacity = 96 * 1024 * 1024;
497         else if (memSize >= 1024)
498             cacheTotalCapacity = 64 * 1024 * 1024;
499         else if (memSize >= 512)
500             cacheTotalCapacity = 32 * 1024 * 1024; 
501
502         cacheMinDeadCapacity = cacheTotalCapacity / 4;
503         cacheMaxDeadCapacity = cacheTotalCapacity / 2;
504
505         // This code is here to avoid a PLT regression. We can remove it if we
506         // can prove that the overall system gain would justify the regression.
507         cacheMaxDeadCapacity = max(24u, cacheMaxDeadCapacity);
508
509         deadDecodedDataDeletionInterval = 60;
510
511         // Foundation memory cache capacity (in bytes)
512         // (These values are small because WebCore does most caching itself.)
513         if (memSize >= 1024)
514             cfurlCacheMemoryCapacity = 4 * 1024 * 1024;
515         else if (memSize >= 512)
516             cfurlCacheMemoryCapacity = 2 * 1024 * 1024;
517         else if (memSize >= 256)
518             cfurlCacheMemoryCapacity = 1 * 1024 * 1024;
519         else
520             cfurlCacheMemoryCapacity =      512 * 1024; 
521
522         // Foundation disk cache capacity (in bytes)
523         if (diskFreeSize >= 16384)
524             cfurlCacheDiskCapacity = 175 * 1024 * 1024;
525         else if (diskFreeSize >= 8192)
526             cfurlCacheDiskCapacity = 150 * 1024 * 1024;
527         else if (diskFreeSize >= 4096)
528             cfurlCacheDiskCapacity = 125 * 1024 * 1024;
529         else if (diskFreeSize >= 2048)
530             cfurlCacheDiskCapacity = 100 * 1024 * 1024;
531         else if (diskFreeSize >= 1024)
532             cfurlCacheDiskCapacity = 75 * 1024 * 1024;
533         else
534             cfurlCacheDiskCapacity = 50 * 1024 * 1024;
535
536         break;
537     }
538     default:
539         ASSERT_NOT_REACHED();
540     }
541
542     // Don't shrink a big disk cache, since that would cause churn.
543     cfurlCacheDiskCapacity = max(cfurlCacheDiskCapacity, CFURLCacheDiskCapacity(cfurlCache.get()));
544
545     cache()->setCapacities(cacheMinDeadCapacity, cacheMaxDeadCapacity, cacheTotalCapacity);
546     cache()->setDeadDecodedDataDeletionInterval(deadDecodedDataDeletionInterval);
547     pageCache()->setCapacity(pageCacheCapacity);
548
549     CFURLCacheSetMemoryCapacity(cfurlCache.get(), cfurlCacheMemoryCapacity);
550     CFURLCacheSetDiskCapacity(cfurlCache.get(), cfurlCacheDiskCapacity);
551
552     s_didSetCacheModel = true;
553     s_cacheModel = cacheModel;
554     return;
555 #endif
556 }
557
558 WebCacheModel WebView::cacheModel()
559 {
560     return s_cacheModel;
561 }
562
563 bool WebView::didSetCacheModel()
564 {
565     return s_didSetCacheModel;
566 }
567
568 WebCacheModel WebView::maxCacheModelInAnyInstance()
569 {
570     WebCacheModel cacheModel = WebCacheModelDocumentViewer;
571
572     HashSet<WebView*>::iterator end = allWebViewsSet().end();
573     for (HashSet<WebView*>::iterator it = allWebViewsSet().begin(); it != end; ++it) {
574         COMPtr<IWebPreferences> pref;
575         if (FAILED((*it)->preferences(&pref)))
576             continue;
577         WebCacheModel prefCacheModel = WebCacheModelDocumentViewer;
578         if (FAILED(pref->cacheModel(&prefCacheModel)))
579             continue;
580
581         cacheModel = max(cacheModel, prefCacheModel);
582     }
583
584     return cacheModel;
585 }
586
587 HRESULT STDMETHODCALLTYPE WebView::close()
588 {
589     if (m_didClose)
590         return S_OK;
591
592     m_didClose = true;
593
594     if (m_uiDelegatePrivate) {
595         COMPtr<IWebUIDelegatePrivate5> uiDelegatePrivate5(Query, m_uiDelegatePrivate);
596         if (uiDelegatePrivate5)
597             uiDelegatePrivate5->webViewClosing(this);
598     }
599
600     removeFromAllWebViewsSet();
601
602     Frame* frame = m_page->mainFrame();
603     if (frame)
604         frame->loader()->detachFromParent();
605
606     if (m_mouseOutTracker) {
607         m_mouseOutTracker->dwFlags = TME_CANCEL;
608         ::TrackMouseEvent(m_mouseOutTracker.get());
609         m_mouseOutTracker.set(0);
610     }
611     
612     setHostWindow(0);
613
614     setDownloadDelegate(0);
615     setEditingDelegate(0);
616     setFrameLoadDelegate(0);
617     setFrameLoadDelegatePrivate(0);
618     setPolicyDelegate(0);
619     setResourceLoadDelegate(0);
620     setUIDelegate(0);
621     setFormDelegate(0);
622
623     if (m_webInspector)
624         m_webInspector->webViewClosed();
625
626     delete m_page;
627     m_page = 0;
628
629     registerForIconNotification(false);
630     IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal();
631     notifyCenter->removeObserver(this, WebPreferences::webPreferencesChangedNotification(), static_cast<IWebPreferences*>(m_preferences.get()));
632
633     BSTR identifier = 0;
634     m_preferences->identifier(&identifier);
635
636     COMPtr<WebPreferences> preferences = m_preferences;
637     m_preferences = 0;
638     preferences->didRemoveFromWebView();
639     // Make sure we release the reference, since WebPreferences::removeReferenceForIdentifier will check for last reference to WebPreferences
640     preferences = 0;
641     if (identifier) {
642         WebPreferences::removeReferenceForIdentifier(identifier);
643         SysFreeString(identifier);
644     }
645
646     deleteBackingStore();
647     return S_OK;
648 }
649
650 void WebView::repaint(const WebCore::IntRect& windowRect, bool contentChanged, bool immediate, bool repaintContentOnly)
651 {
652     if (!repaintContentOnly) {
653         RECT rect = windowRect;
654         ::InvalidateRect(m_viewWindow, &rect, false);
655     }
656     if (contentChanged)
657         addToDirtyRegion(windowRect);
658     if (immediate) {
659         if (repaintContentOnly)
660             updateBackingStore(core(topLevelFrame())->view());
661         else
662             ::UpdateWindow(m_viewWindow);
663     }
664 }
665
666 void WebView::deleteBackingStore()
667 {
668     pendingDeleteBackingStoreSet.remove(this);
669
670     if (m_deleteBackingStoreTimerActive) {
671         KillTimer(m_viewWindow, DeleteBackingStoreTimer);
672         m_deleteBackingStoreTimerActive = false;
673     }
674     m_backingStoreBitmap.clear();
675     m_backingStoreDirtyRegion.clear();
676
677     m_backingStoreSize.cx = m_backingStoreSize.cy = 0;
678 }
679
680 bool WebView::ensureBackingStore()
681 {
682     RECT windowRect;
683     ::GetClientRect(m_viewWindow, &windowRect);
684     LONG width = windowRect.right - windowRect.left;
685     LONG height = windowRect.bottom - windowRect.top;
686     if (width > 0 && height > 0 && (width != m_backingStoreSize.cx || height != m_backingStoreSize.cy)) {
687         deleteBackingStore();
688
689         m_backingStoreSize.cx = width;
690         m_backingStoreSize.cy = height;
691         BITMAPINFO bitmapInfo;
692         bitmapInfo.bmiHeader.biSize          = sizeof(BITMAPINFOHEADER);
693         bitmapInfo.bmiHeader.biWidth         = width; 
694         bitmapInfo.bmiHeader.biHeight        = -height;
695         bitmapInfo.bmiHeader.biPlanes        = 1;
696         bitmapInfo.bmiHeader.biBitCount      = 32;
697         bitmapInfo.bmiHeader.biCompression   = BI_RGB;
698         bitmapInfo.bmiHeader.biSizeImage     = 0;
699         bitmapInfo.bmiHeader.biXPelsPerMeter = 0;
700         bitmapInfo.bmiHeader.biYPelsPerMeter = 0;
701         bitmapInfo.bmiHeader.biClrUsed       = 0;
702         bitmapInfo.bmiHeader.biClrImportant  = 0;
703
704         void* pixels = NULL;
705         m_backingStoreBitmap.set(::CreateDIBSection(NULL, &bitmapInfo, DIB_RGB_COLORS, &pixels, NULL, 0));
706         return true;
707     }
708
709     return false;
710 }
711
712 void WebView::addToDirtyRegion(const IntRect& dirtyRect)
713 {
714     HRGN newRegion = ::CreateRectRgn(dirtyRect.x(), dirtyRect.y(),
715                                      dirtyRect.right(), dirtyRect.bottom());
716     addToDirtyRegion(newRegion);
717 }
718
719 void WebView::addToDirtyRegion(HRGN newRegion)
720 {
721     LOCAL_GDI_COUNTER(0, __FUNCTION__);
722
723     if (m_backingStoreDirtyRegion) {
724         HRGN combinedRegion = ::CreateRectRgn(0,0,0,0);
725         ::CombineRgn(combinedRegion, m_backingStoreDirtyRegion.get(), newRegion, RGN_OR);
726         ::DeleteObject(newRegion);
727         m_backingStoreDirtyRegion.set(combinedRegion);
728     } else
729         m_backingStoreDirtyRegion.set(newRegion);
730
731     COMPtr<IWebUIDelegatePrivate5> delegate(Query, m_uiDelegatePrivate);
732     if (delegate)
733         delegate->webViewDidInvalidate(this);
734 }
735
736 void WebView::scrollBackingStore(FrameView* frameView, int dx, int dy, const IntRect& scrollViewRect, const IntRect& clipRect)
737 {
738     LOCAL_GDI_COUNTER(0, __FUNCTION__);
739
740     // If there's no backing store we don't need to update it
741     if (!m_backingStoreBitmap) {
742         if (m_uiDelegatePrivate)
743             m_uiDelegatePrivate->webViewScrolled(this);
744
745         return;
746     }
747
748     // Make a region to hold the invalidated scroll area.
749     HRGN updateRegion = ::CreateRectRgn(0, 0, 0, 0);
750
751     // Collect our device context info and select the bitmap to scroll.
752     HDC windowDC = ::GetDC(m_viewWindow);
753     HDC bitmapDC = ::CreateCompatibleDC(windowDC);
754     ::SelectObject(bitmapDC, m_backingStoreBitmap.get());
755     
756     // Scroll the bitmap.
757     RECT scrollRectWin(scrollViewRect);
758     RECT clipRectWin(clipRect);
759     ::ScrollDC(bitmapDC, dx, dy, &scrollRectWin, &clipRectWin, updateRegion, 0);
760     RECT regionBox;
761     ::GetRgnBox(updateRegion, &regionBox);
762
763     // Flush.
764     GdiFlush();
765
766     // Add the dirty region to the backing store's dirty region.
767     addToDirtyRegion(updateRegion);
768
769     if (m_uiDelegatePrivate)
770         m_uiDelegatePrivate->webViewScrolled(this);
771
772     // Update the backing store.
773     updateBackingStore(frameView, bitmapDC, false);
774
775     // Clean up.
776     ::DeleteDC(bitmapDC);
777     ::ReleaseDC(m_viewWindow, windowDC);
778
779 }
780
781 // This emulates the Mac smarts for painting rects intelligently.  This is very
782 // important for us, since we double buffer based off dirty rects.
783 static void getUpdateRects(HRGN region, const IntRect& dirtyRect, Vector<IntRect>& rects)
784 {
785     ASSERT_ARG(region, region);
786
787     const int cRectThreshold = 10;
788     const float cWastedSpaceThreshold = 0.75f;
789
790     rects.clear();
791
792     DWORD regionDataSize = GetRegionData(region, sizeof(RGNDATA), NULL);
793     if (!regionDataSize) {
794         rects.append(dirtyRect);
795         return;
796     }
797
798     Vector<unsigned char> buffer(regionDataSize);
799     RGNDATA* regionData = reinterpret_cast<RGNDATA*>(buffer.data());
800     GetRegionData(region, regionDataSize, regionData);
801     if (regionData->rdh.nCount > cRectThreshold) {
802         rects.append(dirtyRect);
803         return;
804     }
805
806     double singlePixels = 0.0;
807     unsigned i;
808     RECT* rect;
809     for (i = 0, rect = reinterpret_cast<RECT*>(regionData->Buffer); i < regionData->rdh.nCount; i++, rect++)
810         singlePixels += (rect->right - rect->left) * (rect->bottom - rect->top);
811
812     double unionPixels = dirtyRect.width() * dirtyRect.height();
813     double wastedSpace = 1.0 - (singlePixels / unionPixels);
814     if (wastedSpace <= cWastedSpaceThreshold) {
815         rects.append(dirtyRect);
816         return;
817     }
818
819     for (i = 0, rect = reinterpret_cast<RECT*>(regionData->Buffer); i < regionData->rdh.nCount; i++, rect++)
820         rects.append(*rect);
821 }
822
823 void WebView::updateBackingStore(FrameView* frameView, HDC dc, bool backingStoreCompletelyDirty, WindowsToPaint windowsToPaint)
824 {
825     LOCAL_GDI_COUNTER(0, __FUNCTION__);
826
827     HDC windowDC = 0;
828     HDC bitmapDC = dc;
829     if (!dc) {
830         windowDC = ::GetDC(m_viewWindow);
831         bitmapDC = ::CreateCompatibleDC(windowDC);
832         ::SelectObject(bitmapDC, m_backingStoreBitmap.get());
833     }
834
835     if (m_backingStoreBitmap && (m_backingStoreDirtyRegion || backingStoreCompletelyDirty)) {
836         // Do a layout first so that everything we render to the backing store is always current.
837         if (Frame* coreFrame = core(m_mainFrame))
838             if (FrameView* view = coreFrame->view())
839                 view->layoutIfNeededRecursive();
840
841         Vector<IntRect> paintRects;
842         if (!backingStoreCompletelyDirty) {
843             RECT regionBox;
844             ::GetRgnBox(m_backingStoreDirtyRegion.get(), &regionBox);
845             getUpdateRects(m_backingStoreDirtyRegion.get(), regionBox, paintRects);
846         } else {
847             RECT clientRect;
848             ::GetClientRect(m_viewWindow, &clientRect);
849             paintRects.append(clientRect);
850         }
851
852         for (unsigned i = 0; i < paintRects.size(); ++i)
853             paintIntoBackingStore(frameView, bitmapDC, paintRects[i], windowsToPaint);
854
855         if (m_uiDelegatePrivate) {
856             COMPtr<IWebUIDelegatePrivate2> uiDelegatePrivate2(Query, m_uiDelegatePrivate);
857             if (uiDelegatePrivate2)
858                 uiDelegatePrivate2->webViewPainted(this);
859         }
860
861         m_backingStoreDirtyRegion.clear();
862     }
863
864     if (!dc) {
865         ::DeleteDC(bitmapDC);
866         ::ReleaseDC(m_viewWindow, windowDC);
867     }
868
869     GdiFlush();
870 }
871
872 void WebView::paint(HDC dc, LPARAM options)
873 {
874     LOCAL_GDI_COUNTER(0, __FUNCTION__);
875
876     Frame* coreFrame = core(m_mainFrame);
877     if (!coreFrame)
878         return;
879     FrameView* frameView = coreFrame->view();
880
881     m_paintCount++;
882
883     RECT rcPaint;
884     HDC hdc;
885     OwnPtr<HRGN> region;
886     int regionType = NULLREGION;
887     PAINTSTRUCT ps;
888     WindowsToPaint windowsToPaint;
889     if (!dc) {
890         region.set(CreateRectRgn(0,0,0,0));
891         regionType = GetUpdateRgn(m_viewWindow, region.get(), false);
892         hdc = BeginPaint(m_viewWindow, &ps);
893         rcPaint = ps.rcPaint;
894         // We're painting to the screen, and our child windows can handle
895         // painting themselves to the screen.
896         windowsToPaint = PaintWebViewOnly;
897     } else {
898         hdc = dc;
899         ::GetClientRect(m_viewWindow, &rcPaint);
900         if (options & PRF_ERASEBKGND)
901             ::FillRect(hdc, &rcPaint, (HBRUSH)GetStockObject(WHITE_BRUSH));
902         // Since we aren't painting to the screen, we want to paint all our
903         // children into the HDC.
904         windowsToPaint = PaintWebViewAndChildren;
905     }
906
907     HDC bitmapDC = ::CreateCompatibleDC(hdc);
908     bool backingStoreCompletelyDirty = ensureBackingStore();
909     ::SelectObject(bitmapDC, m_backingStoreBitmap.get());
910
911     // Update our backing store if needed.
912     updateBackingStore(frameView, bitmapDC, backingStoreCompletelyDirty, windowsToPaint);
913
914     // Now we blit the updated backing store
915     IntRect windowDirtyRect = rcPaint;
916     
917     // Apply the same heuristic for this update region too.
918     Vector<IntRect> blitRects;
919     if (region && regionType == COMPLEXREGION)
920         getUpdateRects(region.get(), windowDirtyRect, blitRects);
921     else
922         blitRects.append(windowDirtyRect);
923
924     for (unsigned i = 0; i < blitRects.size(); ++i)
925         paintIntoWindow(bitmapDC, hdc, blitRects[i]);
926
927     ::DeleteDC(bitmapDC);
928
929     // Paint the gripper.
930     COMPtr<IWebUIDelegate> ui;
931     if (SUCCEEDED(uiDelegate(&ui))) {
932         COMPtr<IWebUIDelegatePrivate> uiPrivate;
933         if (SUCCEEDED(ui->QueryInterface(IID_IWebUIDelegatePrivate, (void**)&uiPrivate))) {
934             RECT r;
935             if (SUCCEEDED(uiPrivate->webViewResizerRect(this, &r))) {
936                 LOCAL_GDI_COUNTER(2, __FUNCTION__" webViewDrawResizer delegate call");
937                 uiPrivate->webViewDrawResizer(this, hdc, (frameView->containsScrollbarsAvoidingResizer() ? true : false), &r);
938             }
939         }
940     }
941
942     if (!dc)
943         EndPaint(m_viewWindow, &ps);
944
945     m_paintCount--;
946
947     if (active())
948         cancelDeleteBackingStoreSoon();
949     else
950         deleteBackingStoreSoon();
951 }
952
953 void WebView::paintIntoBackingStore(FrameView* frameView, HDC bitmapDC, const IntRect& dirtyRect, WindowsToPaint windowsToPaint)
954 {
955     LOCAL_GDI_COUNTER(0, __FUNCTION__);
956
957     RECT rect = dirtyRect;
958
959 #if FLASH_BACKING_STORE_REDRAW
960     HDC dc = ::GetDC(m_viewWindow);
961     OwnPtr<HBRUSH> yellowBrush = CreateSolidBrush(RGB(255, 255, 0));
962     FillRect(dc, &rect, yellowBrush.get());
963     GdiFlush();
964     Sleep(50);
965     paintIntoWindow(bitmapDC, dc, dirtyRect);
966     ::ReleaseDC(m_viewWindow, dc);
967 #endif
968
969     GraphicsContext gc(bitmapDC, m_transparent);
970     gc.setShouldIncludeChildWindows(windowsToPaint == PaintWebViewAndChildren);
971     gc.save();
972     if (m_transparent)
973         gc.clearRect(dirtyRect);
974     else
975         FillRect(bitmapDC, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
976     if (frameView && frameView->frame() && frameView->frame()->contentRenderer()) {
977         gc.clip(dirtyRect);
978         frameView->paint(&gc, dirtyRect);
979     }
980     gc.restore();
981 }
982
983 void WebView::paintIntoWindow(HDC bitmapDC, HDC windowDC, const IntRect& dirtyRect)
984 {
985     LOCAL_GDI_COUNTER(0, __FUNCTION__);
986 #if FLASH_WINDOW_REDRAW
987     OwnPtr<HBRUSH> greenBrush = CreateSolidBrush(RGB(0, 255, 0));
988     RECT rect = dirtyRect;
989     FillRect(windowDC, &rect, greenBrush.get());
990     GdiFlush();
991     Sleep(50);
992 #endif
993
994     // Blit the dirty rect from the backing store into the same position
995     // in the destination DC.
996     BitBlt(windowDC, dirtyRect.x(), dirtyRect.y(), dirtyRect.width(), dirtyRect.height(), bitmapDC,
997            dirtyRect.x(), dirtyRect.y(), SRCCOPY);
998 }
999
1000 void WebView::frameRect(RECT* rect)
1001 {
1002     ::GetWindowRect(m_viewWindow, rect);
1003 }
1004
1005 void WebView::closeWindowSoon()
1006 {
1007     m_closeWindowTimer.startOneShot(0);
1008     AddRef();
1009 }
1010
1011 void WebView::closeWindowTimerFired(WebCore::Timer<WebView>*)
1012 {
1013     closeWindow();
1014     Release();
1015 }
1016
1017 void WebView::closeWindow()
1018 {
1019     if (m_hasSpellCheckerDocumentTag) {
1020         if (m_editingDelegate)
1021             m_editingDelegate->closeSpellDocument(this);
1022         m_hasSpellCheckerDocumentTag = false;
1023     }
1024
1025     COMPtr<IWebUIDelegate> ui;
1026     if (SUCCEEDED(uiDelegate(&ui)))
1027         ui->webViewClose(this);
1028 }
1029
1030 bool WebView::canHandleRequest(const WebCore::ResourceRequest& request)
1031 {
1032     // On the mac there's an about url protocol implementation but CFNetwork doesn't have that.
1033     if (equalIgnoringCase(String(request.url().protocol()), "about"))
1034         return true;
1035
1036 #if USE(CFNETWORK)
1037     if (CFURLProtocolCanHandleRequest(request.cfURLRequest()))
1038         return true;
1039
1040     // FIXME: Mac WebKit calls _representationExistsForURLScheme here
1041     return false;
1042 #else
1043     return true;
1044 #endif
1045 }
1046
1047 String WebView::standardUserAgentWithApplicationName(const String& applicationName)
1048 {
1049     return String::format("Mozilla/5.0 (Windows; U; %s; %s) AppleWebKit/%s (KHTML, like Gecko)%s%s", osVersion().latin1().data(), defaultLanguage().latin1().data(), webKitVersion().latin1().data(), (applicationName.length() ? " " : ""), applicationName.latin1().data());
1050 }
1051
1052 Page* WebView::page()
1053 {
1054     return m_page;
1055 }
1056
1057 bool WebView::handleContextMenuEvent(WPARAM wParam, LPARAM lParam)
1058 {
1059     static const int contextMenuMargin = 1;
1060
1061     // Translate the screen coordinates into window coordinates
1062     POINT coords = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
1063     if (coords.x == -1 || coords.y == -1) {
1064         FrameView* view = m_page->mainFrame()->view();
1065         if (!view)
1066             return false;
1067
1068         int rightAligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT);
1069         IntPoint location;
1070
1071         // The context menu event was generated from the keyboard, so show the context menu by the current selection.
1072         Position start = m_page->mainFrame()->selection()->selection().start();
1073         Position end = m_page->mainFrame()->selection()->selection().end();
1074
1075         if (!start.node() || !end.node())
1076             location = IntPoint(rightAligned ? view->contentsWidth() - contextMenuMargin : contextMenuMargin, contextMenuMargin);
1077         else {
1078             RenderObject* renderer = start.node()->renderer();
1079             if (!renderer)
1080                 return false;
1081
1082             // Calculate the rect of the first line of the selection (cribbed from -[WebCoreFrameBridge firstRectForDOMRange:],
1083             // now Frame::firstRectForRange(), which perhaps this should call).
1084             int extraWidthToEndOfLine = 0;
1085
1086             InlineBox* startInlineBox;
1087             int startCaretOffset;
1088             start.getInlineBoxAndOffset(DOWNSTREAM, startInlineBox, startCaretOffset);
1089             IntRect startCaretRect = renderer->localCaretRect(startInlineBox, startCaretOffset, &extraWidthToEndOfLine);
1090             if (startCaretRect != IntRect())
1091                 startCaretRect = renderer->localToAbsoluteQuad(FloatRect(startCaretRect)).enclosingBoundingBox();
1092
1093             InlineBox* endInlineBox;
1094             int endCaretOffset;
1095             end.getInlineBoxAndOffset(UPSTREAM, endInlineBox, endCaretOffset);
1096             IntRect endCaretRect = renderer->localCaretRect(endInlineBox, endCaretOffset);
1097             if (endCaretRect != IntRect())
1098                 endCaretRect = renderer->localToAbsoluteQuad(FloatRect(endCaretRect)).enclosingBoundingBox();
1099
1100             IntRect firstRect;
1101             if (startCaretRect.y() == endCaretRect.y())
1102                 firstRect = IntRect(min(startCaretRect.x(), endCaretRect.x()), startCaretRect.y(), abs(endCaretRect.x() - startCaretRect.x()), max(startCaretRect.height(), endCaretRect.height()));
1103             else
1104                 firstRect = IntRect(startCaretRect.x(), startCaretRect.y(), startCaretRect.width() + extraWidthToEndOfLine, startCaretRect.height());
1105
1106             location = IntPoint(rightAligned ? firstRect.right() : firstRect.x(), firstRect.bottom());
1107         }
1108
1109         location = view->contentsToWindow(location);
1110         // FIXME: The IntSize(0, -1) is a hack to get the hit-testing to result in the selected element.
1111         // Ideally we'd have the position of a context menu event be separate from its target node.
1112         coords = location + IntSize(0, -1);
1113     } else {
1114         if (!::ScreenToClient(m_viewWindow, &coords))
1115             return false;
1116     }
1117
1118     lParam = MAKELPARAM(coords.x, coords.y);
1119
1120     // The contextMenuController() holds onto the last context menu that was popped up on the
1121     // page until a new one is created. We need to clear this menu before propagating the event
1122     // through the DOM so that we can detect if we create a new menu for this event, since we
1123     // won't create a new menu if the DOM swallows the event and the defaultEventHandler does
1124     // not run.
1125     m_page->contextMenuController()->clearContextMenu();
1126
1127     IntPoint documentPoint(m_page->mainFrame()->view()->windowToContents(coords));
1128     HitTestResult result = m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(documentPoint, false);
1129     Frame* targetFrame = result.innerNonSharedNode() ? result.innerNonSharedNode()->document()->frame() : m_page->focusController()->focusedOrMainFrame();
1130
1131     targetFrame->view()->setCursor(pointerCursor());
1132     PlatformMouseEvent mouseEvent(m_viewWindow, WM_RBUTTONUP, wParam, lParam);
1133     bool handledEvent = targetFrame->eventHandler()->sendContextMenuEvent(mouseEvent);
1134     if (!handledEvent)
1135         return false;
1136
1137     // Show the menu
1138     ContextMenu* coreMenu = m_page->contextMenuController()->contextMenu();
1139     if (!coreMenu)
1140         return false;
1141
1142     Node* node = coreMenu->hitTestResult().innerNonSharedNode();
1143     if (!node)
1144         return false;
1145
1146     Frame* frame = node->document()->frame();
1147     if (!frame)
1148         return false;
1149
1150     FrameView* view = frame->view();
1151     if (!view)
1152         return false;
1153
1154     POINT point(view->contentsToWindow(coreMenu->hitTestResult().point()));
1155
1156     // Translate the point to screen coordinates
1157     if (!::ClientToScreen(m_viewWindow, &point))
1158         return false;
1159
1160     BOOL hasCustomMenus = false;
1161     if (m_uiDelegate)
1162         m_uiDelegate->hasCustomMenuImplementation(&hasCustomMenus);
1163
1164     if (hasCustomMenus)
1165         m_uiDelegate->trackCustomPopupMenu((IWebView*)this, (OLE_HANDLE)(ULONG64)coreMenu->platformDescription(), &point);
1166     else {
1167         // Surprisingly, TPM_RIGHTBUTTON means that items are selectable with either the right OR left mouse button
1168         UINT flags = TPM_RIGHTBUTTON | TPM_TOPALIGN | TPM_VERPOSANIMATION | TPM_HORIZONTAL
1169             | TPM_LEFTALIGN | TPM_HORPOSANIMATION;
1170         ::TrackPopupMenuEx(coreMenu->platformDescription(), flags, point.x, point.y, m_viewWindow, 0);
1171     }
1172
1173     return true;
1174 }
1175
1176 bool WebView::onMeasureItem(WPARAM /*wParam*/, LPARAM lParam)
1177 {
1178     if (!m_uiDelegate)
1179         return false;
1180
1181     BOOL hasCustomMenus = false;
1182     m_uiDelegate->hasCustomMenuImplementation(&hasCustomMenus);
1183     if (!hasCustomMenus)
1184         return false;
1185
1186     m_uiDelegate->measureCustomMenuItem((IWebView*)this, (void*)lParam);
1187     return true;
1188 }
1189
1190 bool WebView::onDrawItem(WPARAM /*wParam*/, LPARAM lParam)
1191 {
1192     if (!m_uiDelegate)
1193         return false;
1194
1195     BOOL hasCustomMenus = false;
1196     m_uiDelegate->hasCustomMenuImplementation(&hasCustomMenus);
1197     if (!hasCustomMenus)
1198         return false;
1199
1200     m_uiDelegate->drawCustomMenuItem((IWebView*)this, (void*)lParam);
1201     return true;
1202 }
1203
1204 bool WebView::onInitMenuPopup(WPARAM wParam, LPARAM /*lParam*/)
1205 {
1206     if (!m_uiDelegate)
1207         return false;
1208
1209     HMENU menu = (HMENU)wParam;
1210     if (!menu)
1211         return false;
1212
1213     BOOL hasCustomMenus = false;
1214     m_uiDelegate->hasCustomMenuImplementation(&hasCustomMenus);
1215     if (!hasCustomMenus)
1216         return false;
1217
1218     m_uiDelegate->addCustomMenuDrawingData((IWebView*)this, (OLE_HANDLE)(ULONG64)menu);
1219     return true;
1220 }
1221
1222 bool WebView::onUninitMenuPopup(WPARAM wParam, LPARAM /*lParam*/)
1223 {
1224     if (!m_uiDelegate)
1225         return false;
1226
1227     HMENU menu = (HMENU)wParam;
1228     if (!menu)
1229         return false;
1230
1231     BOOL hasCustomMenus = false;
1232     m_uiDelegate->hasCustomMenuImplementation(&hasCustomMenus);
1233     if (!hasCustomMenus)
1234         return false;
1235
1236     m_uiDelegate->cleanUpCustomMenuDrawingData((IWebView*)this, (OLE_HANDLE)(ULONG64)menu);
1237     return true;
1238 }
1239
1240 void WebView::performContextMenuAction(WPARAM wParam, LPARAM lParam, bool byPosition)
1241 {
1242     ContextMenu* menu = m_page->contextMenuController()->contextMenu();
1243     ASSERT(menu);
1244
1245     ContextMenuItem* item = byPosition ? menu->itemAtIndex((unsigned)wParam, (HMENU)lParam) : menu->itemWithAction((ContextMenuAction)wParam);
1246     if (!item)
1247         return;
1248     m_page->contextMenuController()->contextMenuItemSelected(item);
1249     delete item;
1250 }
1251
1252 bool WebView::handleMouseEvent(UINT message, WPARAM wParam, LPARAM lParam)
1253 {
1254     static LONG globalClickCount;
1255     static IntPoint globalPrevPoint;
1256     static MouseButton globalPrevButton;
1257     static LONG globalPrevMouseDownTime;
1258
1259     // Create our event.
1260     // On WM_MOUSELEAVE we need to create a mouseout event, so we force the position
1261     // of the event to be at (MINSHORT, MINSHORT).
1262     LPARAM position = (message == WM_MOUSELEAVE) ? ((MINSHORT << 16) | MINSHORT) : lParam;
1263     PlatformMouseEvent mouseEvent(m_viewWindow, message, wParam, position, m_mouseActivated);
1264    
1265     bool insideThreshold = abs(globalPrevPoint.x() - mouseEvent.pos().x()) < ::GetSystemMetrics(SM_CXDOUBLECLK) &&
1266                            abs(globalPrevPoint.y() - mouseEvent.pos().y()) < ::GetSystemMetrics(SM_CYDOUBLECLK);
1267     LONG messageTime = ::GetMessageTime();
1268
1269     if (inResizer(position)) {
1270         if (m_uiDelegate) {
1271             COMPtr<IWebUIDelegatePrivate4> uiPrivate(Query, m_uiDelegate);
1272
1273             if (uiPrivate)
1274                 uiPrivate->webViewSendResizeMessage(message, wParam, position);
1275         }
1276         return true;
1277     }
1278
1279     bool handled = false;
1280
1281     if (message == WM_LBUTTONDOWN || message == WM_MBUTTONDOWN || message == WM_RBUTTONDOWN) {
1282         // FIXME: I'm not sure if this is the "right" way to do this
1283         // but without this call, we never become focused since we don't allow
1284         // the default handling of mouse events.
1285         SetFocus(m_viewWindow);
1286
1287         // Always start capturing events when the mouse goes down in our HWND.
1288         ::SetCapture(m_viewWindow);
1289
1290         if (((messageTime - globalPrevMouseDownTime) < (LONG)::GetDoubleClickTime()) && 
1291             insideThreshold &&
1292             mouseEvent.button() == globalPrevButton)
1293             globalClickCount++;
1294         else
1295             // Reset the click count.
1296             globalClickCount = 1;
1297         globalPrevMouseDownTime = messageTime;
1298         globalPrevButton = mouseEvent.button();
1299         globalPrevPoint = mouseEvent.pos();
1300         
1301         mouseEvent.setClickCount(globalClickCount);
1302         handled = m_page->mainFrame()->eventHandler()->handleMousePressEvent(mouseEvent);
1303     } else if (message == WM_LBUTTONDBLCLK || message == WM_MBUTTONDBLCLK || message == WM_RBUTTONDBLCLK) {
1304         globalClickCount++;
1305         mouseEvent.setClickCount(globalClickCount);
1306         handled = m_page->mainFrame()->eventHandler()->handleMousePressEvent(mouseEvent);
1307     } else if (message == WM_LBUTTONUP || message == WM_MBUTTONUP || message == WM_RBUTTONUP) {
1308         // Record the global position and the button of the up.
1309         globalPrevButton = mouseEvent.button();
1310         globalPrevPoint = mouseEvent.pos();
1311         mouseEvent.setClickCount(globalClickCount);
1312         m_page->mainFrame()->eventHandler()->handleMouseReleaseEvent(mouseEvent);
1313         ::ReleaseCapture();
1314     } else if (message == WM_MOUSELEAVE && m_mouseOutTracker) {
1315         // Once WM_MOUSELEAVE is fired windows clears this tracker
1316         // so there is no need to disable it ourselves.
1317         m_mouseOutTracker.set(0);
1318         m_page->mainFrame()->eventHandler()->mouseMoved(mouseEvent);
1319         handled = true;
1320     } else if (message == WM_MOUSEMOVE) {
1321         if (!insideThreshold)
1322             globalClickCount = 0;
1323         mouseEvent.setClickCount(globalClickCount);
1324         handled = m_page->mainFrame()->eventHandler()->mouseMoved(mouseEvent);
1325         if (!m_mouseOutTracker) {
1326             m_mouseOutTracker.set(new TRACKMOUSEEVENT);
1327             m_mouseOutTracker->cbSize = sizeof(TRACKMOUSEEVENT);
1328             m_mouseOutTracker->dwFlags = TME_LEAVE;
1329             m_mouseOutTracker->hwndTrack = m_viewWindow;
1330             ::TrackMouseEvent(m_mouseOutTracker.get());
1331         }
1332     }
1333     setMouseActivated(false);
1334     return handled;
1335 }
1336
1337 bool WebView::mouseWheel(WPARAM wParam, LPARAM lParam, bool isMouseHWheel)
1338 {
1339     // Ctrl+Mouse wheel doesn't ever go into WebCore.  It is used to
1340     // zoom instead (Mac zooms the whole Desktop, but Windows browsers trigger their
1341     // own local zoom modes for Ctrl+wheel).
1342     if (wParam & MK_CONTROL) {
1343         short delta = short(HIWORD(wParam));
1344         if (delta < 0)
1345             makeTextLarger(0);
1346         else
1347             makeTextSmaller(0);
1348         return true;
1349     }
1350
1351     PlatformWheelEvent wheelEvent(m_viewWindow, wParam, lParam, isMouseHWheel);
1352     Frame* coreFrame = core(m_mainFrame);
1353     if (!coreFrame)
1354         return false;
1355
1356     return coreFrame->eventHandler()->handleWheelEvent(wheelEvent);
1357 }
1358
1359 bool WebView::execCommand(WPARAM wParam, LPARAM /*lParam*/)
1360 {
1361     Frame* frame = m_page->focusController()->focusedOrMainFrame();
1362     switch (LOWORD(wParam)) {
1363         case SelectAll:
1364             return frame->editor()->command("SelectAll").execute();
1365         case Undo:
1366             return frame->editor()->command("Undo").execute();
1367         case Redo:
1368             return frame->editor()->command("Redo").execute();
1369     }
1370     return false;
1371 }
1372
1373 bool WebView::keyUp(WPARAM virtualKeyCode, LPARAM keyData, bool systemKeyDown)
1374 {
1375     PlatformKeyboardEvent keyEvent(m_viewWindow, virtualKeyCode, keyData, PlatformKeyboardEvent::KeyUp, systemKeyDown);
1376
1377     Frame* frame = m_page->focusController()->focusedOrMainFrame();
1378     m_currentCharacterCode = 0;
1379
1380     return frame->eventHandler()->keyEvent(keyEvent);
1381 }
1382
1383 static const unsigned CtrlKey = 1 << 0;
1384 static const unsigned AltKey = 1 << 1;
1385 static const unsigned ShiftKey = 1 << 2;
1386
1387
1388 struct KeyDownEntry {
1389     unsigned virtualKey;
1390     unsigned modifiers;
1391     const char* name;
1392 };
1393
1394 struct KeyPressEntry {
1395     unsigned charCode;
1396     unsigned modifiers;
1397     const char* name;
1398 };
1399
1400 static const KeyDownEntry keyDownEntries[] = {
1401     { VK_LEFT,   0,                  "MoveLeft"                                    },
1402     { VK_LEFT,   ShiftKey,           "MoveLeftAndModifySelection"                  },
1403     { VK_LEFT,   CtrlKey,            "MoveWordLeft"                                },
1404     { VK_LEFT,   CtrlKey | ShiftKey, "MoveWordLeftAndModifySelection"              },
1405     { VK_RIGHT,  0,                  "MoveRight"                                   },
1406     { VK_RIGHT,  ShiftKey,           "MoveRightAndModifySelection"                 },
1407     { VK_RIGHT,  CtrlKey,            "MoveWordRight"                               },
1408     { VK_RIGHT,  CtrlKey | ShiftKey, "MoveWordRightAndModifySelection"             },
1409     { VK_UP,     0,                  "MoveUp"                                      },
1410     { VK_UP,     ShiftKey,           "MoveUpAndModifySelection"                    },
1411     { VK_PRIOR,  ShiftKey,           "MovePageUpAndModifySelection"                },
1412     { VK_DOWN,   0,                  "MoveDown"                                    },
1413     { VK_DOWN,   ShiftKey,           "MoveDownAndModifySelection"                  },
1414     { VK_NEXT,   ShiftKey,           "MovePageDownAndModifySelection"              },
1415     { VK_PRIOR,  0,                  "MovePageUp"                                  },
1416     { VK_NEXT,   0,                  "MovePageDown"                                },
1417     { VK_HOME,   0,                  "MoveToBeginningOfLine"                       },
1418     { VK_HOME,   ShiftKey,           "MoveToBeginningOfLineAndModifySelection"     },
1419     { VK_HOME,   CtrlKey,            "MoveToBeginningOfDocument"                   },
1420     { VK_HOME,   CtrlKey | ShiftKey, "MoveToBeginningOfDocumentAndModifySelection" },
1421
1422     { VK_END,    0,                  "MoveToEndOfLine"                             },
1423     { VK_END,    ShiftKey,           "MoveToEndOfLineAndModifySelection"           },
1424     { VK_END,    CtrlKey,            "MoveToEndOfDocument"                         },
1425     { VK_END,    CtrlKey | ShiftKey, "MoveToEndOfDocumentAndModifySelection"       },
1426
1427     { VK_BACK,   0,                  "DeleteBackward"                              },
1428     { VK_BACK,   ShiftKey,           "DeleteBackward"                              },
1429     { VK_DELETE, 0,                  "DeleteForward"                               },
1430     { VK_BACK,   CtrlKey,            "DeleteWordBackward"                          },
1431     { VK_DELETE, CtrlKey,            "DeleteWordForward"                           },
1432     
1433     { 'B',       CtrlKey,            "ToggleBold"                                  },
1434     { 'I',       CtrlKey,            "ToggleItalic"                                },
1435
1436     { VK_ESCAPE, 0,                  "Cancel"                                      },
1437     { VK_OEM_PERIOD, CtrlKey,        "Cancel"                                      },
1438     { VK_TAB,    0,                  "InsertTab"                                   },
1439     { VK_TAB,    ShiftKey,           "InsertBacktab"                               },
1440     { VK_RETURN, 0,                  "InsertNewline"                               },
1441     { VK_RETURN, CtrlKey,            "InsertNewline"                               },
1442     { VK_RETURN, AltKey,             "InsertNewline"                               },
1443     { VK_RETURN, AltKey | ShiftKey,  "InsertNewline"                               },
1444
1445     // It's not quite clear whether clipboard shortcuts and Undo/Redo should be handled
1446     // in the application or in WebKit. We chose WebKit.
1447     { 'C',       CtrlKey,            "Copy"                                        },
1448     { 'V',       CtrlKey,            "Paste"                                       },
1449     { 'X',       CtrlKey,            "Cut"                                         },
1450     { 'A',       CtrlKey,            "SelectAll"                                   },
1451     { VK_INSERT, CtrlKey,            "Copy"                                        },
1452     { VK_DELETE, ShiftKey,           "Cut"                                         },
1453     { VK_INSERT, ShiftKey,           "Paste"                                       },
1454     { 'Z',       CtrlKey,            "Undo"                                        },
1455     { 'Z',       CtrlKey | ShiftKey, "Redo"                                        },
1456 };
1457
1458 static const KeyPressEntry keyPressEntries[] = {
1459     { '\t',   0,                  "InsertTab"                                   },
1460     { '\t',   ShiftKey,           "InsertBacktab"                               },
1461     { '\r',   0,                  "InsertNewline"                               },
1462     { '\r',   CtrlKey,            "InsertNewline"                               },
1463     { '\r',   AltKey,             "InsertNewline"                               },
1464     { '\r',   AltKey | ShiftKey,  "InsertNewline"                               },
1465 };
1466
1467 const char* WebView::interpretKeyEvent(const KeyboardEvent* evt)
1468 {
1469     ASSERT(evt->type() == eventNames().keydownEvent || evt->type() == eventNames().keypressEvent);
1470
1471     static HashMap<int, const char*>* keyDownCommandsMap = 0;
1472     static HashMap<int, const char*>* keyPressCommandsMap = 0;
1473
1474     if (!keyDownCommandsMap) {
1475         keyDownCommandsMap = new HashMap<int, const char*>;
1476         keyPressCommandsMap = new HashMap<int, const char*>;
1477
1478         for (unsigned i = 0; i < _countof(keyDownEntries); i++)
1479             keyDownCommandsMap->set(keyDownEntries[i].modifiers << 16 | keyDownEntries[i].virtualKey, keyDownEntries[i].name);
1480
1481         for (unsigned i = 0; i < _countof(keyPressEntries); i++)
1482             keyPressCommandsMap->set(keyPressEntries[i].modifiers << 16 | keyPressEntries[i].charCode, keyPressEntries[i].name);
1483     }
1484
1485     unsigned modifiers = 0;
1486     if (evt->shiftKey())
1487         modifiers |= ShiftKey;
1488     if (evt->altKey())
1489         modifiers |= AltKey;
1490     if (evt->ctrlKey())
1491         modifiers |= CtrlKey;
1492
1493     if (evt->type() == eventNames().keydownEvent) {
1494         int mapKey = modifiers << 16 | evt->keyCode();
1495         return mapKey ? keyDownCommandsMap->get(mapKey) : 0;
1496     }
1497
1498     int mapKey = modifiers << 16 | evt->charCode();
1499     return mapKey ? keyPressCommandsMap->get(mapKey) : 0;
1500 }
1501
1502 bool WebView::handleEditingKeyboardEvent(KeyboardEvent* evt)
1503 {
1504     Node* node = evt->target()->toNode();
1505     ASSERT(node);
1506     Frame* frame = node->document()->frame();
1507     ASSERT(frame);
1508
1509     const PlatformKeyboardEvent* keyEvent = evt->keyEvent();
1510     if (!keyEvent || keyEvent->isSystemKey())  // do not treat this as text input if it's a system key event
1511         return false;
1512
1513     Editor::Command command = frame->editor()->command(interpretKeyEvent(evt));
1514
1515     if (keyEvent->type() == PlatformKeyboardEvent::RawKeyDown) {
1516         // WebKit doesn't have enough information about mode to decide how commands that just insert text if executed via Editor should be treated,
1517         // so we leave it upon WebCore to either handle them immediately (e.g. Tab that changes focus) or let a keypress event be generated
1518         // (e.g. Tab that inserts a Tab character, or Enter).
1519         return !command.isTextInsertion() && command.execute(evt);
1520     }
1521
1522      if (command.execute(evt))
1523         return true;
1524
1525     // Don't insert null or control characters as they can result in unexpected behaviour
1526     if (evt->charCode() < ' ')
1527         return false;
1528
1529     return frame->editor()->insertText(evt->keyEvent()->text(), evt);
1530 }
1531
1532 bool WebView::keyDown(WPARAM virtualKeyCode, LPARAM keyData, bool systemKeyDown)
1533 {
1534     Frame* frame = m_page->focusController()->focusedOrMainFrame();
1535     if (virtualKeyCode == VK_CAPITAL)
1536         frame->eventHandler()->capsLockStateMayHaveChanged();
1537
1538     PlatformKeyboardEvent keyEvent(m_viewWindow, virtualKeyCode, keyData, PlatformKeyboardEvent::RawKeyDown, systemKeyDown);
1539     bool handled = frame->eventHandler()->keyEvent(keyEvent);
1540
1541     // These events cannot be canceled, and we have no default handling for them.
1542     // FIXME: match IE list more closely, see <http://msdn2.microsoft.com/en-us/library/ms536938.aspx>.
1543     if (systemKeyDown && virtualKeyCode != VK_RETURN)
1544         return false;
1545
1546     if (handled) {
1547         // FIXME: remove WM_UNICHAR, too
1548         MSG msg;
1549         // WM_SYSCHAR events should not be removed, because access keys are implemented in WebCore in WM_SYSCHAR handler.
1550         if (!systemKeyDown)
1551             ::PeekMessage(&msg, m_viewWindow, WM_CHAR, WM_CHAR, PM_REMOVE);
1552         return true;
1553     }
1554
1555     // We need to handle back/forward using either Backspace(+Shift) or Ctrl+Left/Right Arrow keys.
1556     if ((virtualKeyCode == VK_BACK && keyEvent.shiftKey()) || (virtualKeyCode == VK_RIGHT && keyEvent.ctrlKey()))
1557         m_page->goForward();
1558     else if (virtualKeyCode == VK_BACK || (virtualKeyCode == VK_LEFT && keyEvent.ctrlKey()))
1559         m_page->goBack();
1560     
1561     // Need to scroll the page if the arrow keys, pgup/dn, or home/end are hit.
1562     ScrollDirection direction;
1563     ScrollGranularity granularity;
1564     switch (virtualKeyCode) {
1565         case VK_LEFT:
1566             granularity = ScrollByLine;
1567             direction = ScrollLeft;
1568             break;
1569         case VK_RIGHT:
1570             granularity = ScrollByLine;
1571             direction = ScrollRight;
1572             break;
1573         case VK_UP:
1574             granularity = ScrollByLine;
1575             direction = ScrollUp;
1576             break;
1577         case VK_DOWN:
1578             granularity = ScrollByLine;
1579             direction = ScrollDown;
1580             break;
1581         case VK_HOME:
1582             granularity = ScrollByDocument;
1583             direction = ScrollUp;
1584             break;
1585         case VK_END:
1586             granularity = ScrollByDocument;
1587             direction = ScrollDown;
1588             break;
1589         case VK_PRIOR:
1590             granularity = ScrollByPage;
1591             direction = ScrollUp;
1592             break;
1593         case VK_NEXT:
1594             granularity = ScrollByPage;
1595             direction = ScrollDown;
1596             break;
1597         default:
1598             return false;
1599     }
1600
1601     if (!frame->eventHandler()->scrollOverflow(direction, granularity)) {
1602         handled = frame->view()->scroll(direction, granularity);
1603         Frame* parent = frame->tree()->parent();
1604         while(!handled && parent) {
1605             handled = parent->view()->scroll(direction, granularity);
1606             parent = parent->tree()->parent();
1607         }
1608     }
1609     return handled;
1610 }
1611
1612 bool WebView::keyPress(WPARAM charCode, LPARAM keyData, bool systemKeyDown)
1613 {
1614     Frame* frame = m_page->focusController()->focusedOrMainFrame();
1615
1616     PlatformKeyboardEvent keyEvent(m_viewWindow, charCode, keyData, PlatformKeyboardEvent::Char, systemKeyDown);
1617     // IE does not dispatch keypress event for WM_SYSCHAR.
1618     if (systemKeyDown)
1619         return frame->eventHandler()->handleAccessKey(keyEvent);
1620     return frame->eventHandler()->keyEvent(keyEvent);
1621 }
1622
1623 bool WebView::inResizer(LPARAM lParam)
1624 {
1625     if (!m_uiDelegatePrivate)
1626         return false;
1627
1628     RECT r;
1629     if (FAILED(m_uiDelegatePrivate->webViewResizerRect(this, &r)))
1630         return false;
1631
1632     POINT pt;
1633     pt.x = LOWORD(lParam);
1634     pt.y = HIWORD(lParam);
1635     return !!PtInRect(&r, pt);
1636 }
1637
1638 static bool registerWebViewWindowClass()
1639 {
1640     static bool haveRegisteredWindowClass = false;
1641     if (haveRegisteredWindowClass)
1642         return true;
1643
1644     haveRegisteredWindowClass = true;
1645
1646     WNDCLASSEX wcex;
1647
1648     wcex.cbSize = sizeof(WNDCLASSEX);
1649
1650     wcex.style          = CS_DBLCLKS;
1651     wcex.lpfnWndProc    = WebViewWndProc;
1652     wcex.cbClsExtra     = 0;
1653     wcex.cbWndExtra     = 4; // 4 bytes for the IWebView pointer
1654     wcex.hInstance      = gInstance;
1655     wcex.hIcon          = 0;
1656     wcex.hCursor        = ::LoadCursor(0, IDC_ARROW);
1657     wcex.hbrBackground  = 0;
1658     wcex.lpszMenuName   = 0;
1659     wcex.lpszClassName  = kWebViewWindowClassName;
1660     wcex.hIconSm        = 0;
1661
1662     return !!RegisterClassEx(&wcex);
1663 }
1664
1665 namespace WebCore {
1666     extern HCURSOR lastSetCursor;
1667 }
1668
1669 static HWND findTopLevelParent(HWND window)
1670 {
1671     if (!window)
1672         return 0;
1673
1674     HWND current = window;
1675     for (HWND parent = GetParent(current); current; current = parent, parent = GetParent(parent))
1676         if (!parent || !(GetWindowLongPtr(current, GWL_STYLE) & (WS_POPUP | WS_CHILD)))
1677             return current;
1678     ASSERT_NOT_REACHED();
1679     return 0;
1680 }
1681
1682 static LRESULT CALLBACK WebViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1683 {
1684     LRESULT lResult = 0;
1685     LONG_PTR longPtr = GetWindowLongPtr(hWnd, 0);
1686     WebView* webView = reinterpret_cast<WebView*>(longPtr);
1687     WebFrame* mainFrameImpl = webView ? webView->topLevelFrame() : 0;
1688     if (!mainFrameImpl || webView->isBeingDestroyed())
1689         return DefWindowProc(hWnd, message, wParam, lParam);
1690
1691     // hold a ref, since the WebView could go away in an event handler.
1692     COMPtr<WebView> protector(webView);
1693     ASSERT(webView);
1694
1695     // Windows Media Player has a modal message loop that will deliver messages
1696     // to us at inappropriate times and we will crash if we handle them when
1697     // they are delivered. We repost paint messages so that we eventually get
1698     // a chance to paint once the modal loop has exited, but other messages
1699     // aren't safe to repost, so we just drop them.
1700     if (PluginView::isCallingPlugin()) {
1701         if (message == WM_PAINT)
1702             PostMessage(hWnd, message, wParam, lParam);
1703         return 0;
1704     }
1705
1706     bool handled = true;
1707
1708     switch (message) {
1709         case WM_PAINT: {
1710             webView->paint(0, 0);
1711             break;
1712         }
1713         case WM_PRINTCLIENT:
1714             webView->paint((HDC)wParam, lParam);
1715             break;
1716         case WM_DESTROY:
1717             webView->close();
1718             webView->setIsBeingDestroyed();
1719             webView->revokeDragDrop();
1720             break;
1721         case WM_MOUSEMOVE:
1722         case WM_LBUTTONDOWN:
1723         case WM_MBUTTONDOWN:
1724         case WM_RBUTTONDOWN:
1725         case WM_LBUTTONDBLCLK:
1726         case WM_MBUTTONDBLCLK:
1727         case WM_RBUTTONDBLCLK:
1728         case WM_LBUTTONUP:
1729         case WM_MBUTTONUP:
1730         case WM_RBUTTONUP:
1731         case WM_MOUSELEAVE:
1732             if (Frame* coreFrame = core(mainFrameImpl))
1733                 if (coreFrame->view()->didFirstLayout())
1734                     handled = webView->handleMouseEvent(message, wParam, lParam);
1735             break;
1736         case WM_MOUSEWHEEL:
1737         case WM_VISTA_MOUSEHWHEEL:
1738             if (Frame* coreFrame = core(mainFrameImpl))
1739                 if (coreFrame->view()->didFirstLayout())
1740                     handled = webView->mouseWheel(wParam, lParam, message == WM_VISTA_MOUSEHWHEEL);
1741             break;
1742         case WM_SYSKEYDOWN:
1743             handled = webView->keyDown(wParam, lParam, true);
1744             break;
1745         case WM_KEYDOWN:
1746             handled = webView->keyDown(wParam, lParam);
1747             break;
1748         case WM_SYSKEYUP:
1749             handled = webView->keyUp(wParam, lParam, true);
1750             break;
1751         case WM_KEYUP:
1752             handled = webView->keyUp(wParam, lParam);
1753             break;
1754         case WM_SYSCHAR:
1755             handled = webView->keyPress(wParam, lParam, true);
1756             break;
1757         case WM_CHAR:
1758             handled = webView->keyPress(wParam, lParam);
1759             break;
1760         // FIXME: We need to check WM_UNICHAR to support supplementary characters (that don't fit in 16 bits).
1761         case WM_SIZE:
1762             if (webView->isBeingDestroyed())
1763                 // If someone has sent us this message while we're being destroyed, we should bail out so we don't crash.
1764                 break;
1765
1766             if (lParam != 0) {
1767                 webView->deleteBackingStore();
1768                 if (Frame* coreFrame = core(mainFrameImpl))
1769                     coreFrame->view()->resize(LOWORD(lParam), HIWORD(lParam));
1770             }
1771             break;
1772         case WM_SHOWWINDOW:
1773             lResult = DefWindowProc(hWnd, message, wParam, lParam);
1774             if (wParam == 0)
1775                 // The window is being hidden (e.g., because we switched tabs.
1776                 // Null out our backing store.
1777                 webView->deleteBackingStore();
1778             break;
1779         case WM_SETFOCUS: {
1780             COMPtr<IWebUIDelegate> uiDelegate;
1781             COMPtr<IWebUIDelegatePrivate> uiDelegatePrivate;
1782             if (SUCCEEDED(webView->uiDelegate(&uiDelegate)) && uiDelegate &&
1783                 SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**) &uiDelegatePrivate)) && uiDelegatePrivate)
1784                 uiDelegatePrivate->webViewReceivedFocus(webView);
1785
1786             FocusController* focusController = webView->page()->focusController();
1787             if (Frame* frame = focusController->focusedFrame()) {
1788                 // Send focus events unless the previously focused window is a
1789                 // child of ours (for example a plugin).
1790                 if (!IsChild(hWnd, reinterpret_cast<HWND>(wParam)))
1791                     frame->selection()->setFocused(true);
1792             } else
1793                 focusController->setFocusedFrame(webView->page()->mainFrame());
1794             break;
1795         }
1796         case WM_KILLFOCUS: {
1797             COMPtr<IWebUIDelegate> uiDelegate;
1798             COMPtr<IWebUIDelegatePrivate> uiDelegatePrivate;
1799             HWND newFocusWnd = reinterpret_cast<HWND>(wParam);
1800             if (SUCCEEDED(webView->uiDelegate(&uiDelegate)) && uiDelegate &&
1801                 SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**) &uiDelegatePrivate)) && uiDelegatePrivate)
1802                 uiDelegatePrivate->webViewLostFocus(webView, (OLE_HANDLE)(ULONG64)newFocusWnd);
1803
1804             FocusController* focusController = webView->page()->focusController();
1805             Frame* frame = focusController->focusedOrMainFrame();
1806             webView->resetIME(frame);
1807             // Send blur events unless we're losing focus to a child of ours.
1808             if (!IsChild(hWnd, newFocusWnd))
1809                 frame->selection()->setFocused(false);
1810             break;
1811         }
1812         case WM_WINDOWPOSCHANGED:
1813             if (reinterpret_cast<WINDOWPOS*>(lParam)->flags & SWP_SHOWWINDOW)
1814                 webView->updateActiveStateSoon();
1815             handled = false;
1816             break;
1817         case WM_CUT:
1818             webView->cut(0);
1819             break;
1820         case WM_COPY:
1821             webView->copy(0);
1822             break;
1823         case WM_PASTE:
1824             webView->paste(0);
1825             break;
1826         case WM_CLEAR:
1827             webView->delete_(0);
1828             break;
1829         case WM_COMMAND:
1830             if (HIWORD(wParam))
1831                 handled = webView->execCommand(wParam, lParam);
1832             else // If the high word of wParam is 0, the message is from a menu
1833                 webView->performContextMenuAction(wParam, lParam, false);
1834             break;
1835         case WM_MENUCOMMAND:
1836             webView->performContextMenuAction(wParam, lParam, true);
1837             break;
1838         case WM_CONTEXTMENU:
1839             handled = webView->handleContextMenuEvent(wParam, lParam);
1840             break;
1841         case WM_INITMENUPOPUP:
1842             handled = webView->onInitMenuPopup(wParam, lParam);
1843             break;
1844         case WM_MEASUREITEM:
1845             handled = webView->onMeasureItem(wParam, lParam);
1846             break;
1847         case WM_DRAWITEM:
1848             handled = webView->onDrawItem(wParam, lParam);
1849             break;
1850         case WM_UNINITMENUPOPUP:
1851             handled = webView->onUninitMenuPopup(wParam, lParam);
1852             break;
1853         case WM_XP_THEMECHANGED:
1854             if (Frame* coreFrame = core(mainFrameImpl)) {
1855                 webView->deleteBackingStore();
1856                 theme()->themeChanged();
1857                 ScrollbarTheme::nativeTheme()->themeChanged();
1858                 RECT windowRect;
1859                 ::GetClientRect(hWnd, &windowRect);
1860                 ::InvalidateRect(hWnd, &windowRect, false);
1861             }
1862             break;
1863         case WM_MOUSEACTIVATE:
1864             webView->setMouseActivated(true);
1865             break;
1866         case WM_GETDLGCODE: {
1867             COMPtr<IWebUIDelegate> uiDelegate;
1868             COMPtr<IWebUIDelegatePrivate> uiDelegatePrivate;
1869             LONG_PTR dlgCode = 0;
1870             UINT keyCode = 0;
1871             if (lParam) {
1872                 LPMSG lpMsg = (LPMSG)lParam;
1873                 if (lpMsg->message == WM_KEYDOWN)
1874                     keyCode = (UINT) lpMsg->wParam;
1875             }
1876             if (SUCCEEDED(webView->uiDelegate(&uiDelegate)) && uiDelegate &&
1877                 SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**) &uiDelegatePrivate)) && uiDelegatePrivate &&
1878                 SUCCEEDED(uiDelegatePrivate->webViewGetDlgCode(webView, keyCode, &dlgCode)))
1879                 return dlgCode;
1880             handled = false;
1881             break;
1882         }
1883         case WM_GETOBJECT:
1884             handled = webView->onGetObject(wParam, lParam, lResult);
1885             break;
1886         case WM_IME_STARTCOMPOSITION:
1887             handled = webView->onIMEStartComposition();
1888             break;
1889         case WM_IME_REQUEST:
1890             webView->onIMERequest(wParam, lParam, &lResult);
1891             break;
1892         case WM_IME_COMPOSITION:
1893             handled = webView->onIMEComposition(lParam);
1894             break;
1895         case WM_IME_ENDCOMPOSITION:
1896             handled = webView->onIMEEndComposition();
1897             break;
1898         case WM_IME_CHAR:
1899             handled = webView->onIMEChar(wParam, lParam);
1900             break;
1901         case WM_IME_NOTIFY:
1902             handled = webView->onIMENotify(wParam, lParam, &lResult);
1903             break;
1904         case WM_IME_SELECT:
1905             handled = webView->onIMESelect(wParam, lParam);
1906             break;
1907         case WM_IME_SETCONTEXT:
1908             handled = webView->onIMESetContext(wParam, lParam);
1909             break;
1910         case WM_TIMER:
1911             switch (wParam) {
1912                 case UpdateActiveStateTimer:
1913                     KillTimer(hWnd, UpdateActiveStateTimer);
1914                     webView->updateActiveState();
1915                     break;
1916                 case DeleteBackingStoreTimer:
1917                     webView->deleteBackingStore();
1918                     break;
1919             }
1920             break;
1921         case WM_SETCURSOR:
1922             if (handled = webView->page()->chrome()->setCursor(lastSetCursor))
1923                 break;
1924
1925             __fallthrough;
1926         default:
1927             handled = false;
1928             break;
1929     }
1930
1931     if (!handled)
1932         lResult = DefWindowProc(hWnd, message, wParam, lParam);
1933     
1934     // Let the client know whether we consider this message handled.
1935     return (message == WM_KEYDOWN || message == WM_SYSKEYDOWN || message == WM_KEYUP || message == WM_SYSKEYUP) ? !handled : lResult;
1936 }
1937
1938 bool WebView::developerExtrasEnabled() const
1939 {
1940     if (m_preferences->developerExtrasDisabledByOverride())
1941         return false;
1942
1943 #ifdef NDEBUG
1944     BOOL enabled;
1945     return SUCCEEDED(m_preferences->developerExtrasEnabled(&enabled)) && enabled;
1946 #else
1947     return true;
1948 #endif
1949 }
1950
1951 static String osVersion()
1952 {
1953     String osVersion;
1954     OSVERSIONINFO versionInfo = {0};
1955     versionInfo.dwOSVersionInfoSize = sizeof(versionInfo);
1956     GetVersionEx(&versionInfo);
1957
1958     if (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1959         if (versionInfo.dwMajorVersion == 4) {
1960             if (versionInfo.dwMinorVersion == 0)
1961                 osVersion = "Windows 95";
1962             else if (versionInfo.dwMinorVersion == 10)
1963                 osVersion = "Windows 98";
1964             else if (versionInfo.dwMinorVersion == 90)
1965                 osVersion = "Windows 98; Win 9x 4.90";
1966         }
1967     } else if (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
1968         osVersion = String::format("Windows NT %d.%d", versionInfo.dwMajorVersion, versionInfo.dwMinorVersion);
1969
1970     if (!osVersion.length())
1971         osVersion = String::format("Windows %d.%d", versionInfo.dwMajorVersion, versionInfo.dwMinorVersion);
1972
1973     return osVersion;
1974 }
1975
1976 static String webKitVersion()
1977 {
1978     String versionStr = "420+";
1979     void* data = 0;
1980
1981     struct LANGANDCODEPAGE {
1982         WORD wLanguage;
1983         WORD wCodePage;
1984     } *lpTranslate;
1985
1986     TCHAR path[MAX_PATH];
1987     GetModuleFileName(gInstance, path, ARRAYSIZE(path));
1988     DWORD handle;
1989     DWORD versionSize = GetFileVersionInfoSize(path, &handle);
1990     if (!versionSize)
1991         goto exit;
1992     data = malloc(versionSize);
1993     if (!data)
1994         goto exit;
1995     if (!GetFileVersionInfo(path, 0, versionSize, data))
1996         goto exit;
1997     UINT cbTranslate;
1998     if (!VerQueryValue(data, TEXT("\\VarFileInfo\\Translation"), (LPVOID*)&lpTranslate, &cbTranslate))
1999         goto exit;
2000     TCHAR key[256];
2001     _stprintf_s(key, ARRAYSIZE(key), TEXT("\\StringFileInfo\\%04x%04x\\ProductVersion"), lpTranslate[0].wLanguage, lpTranslate[0].wCodePage);
2002     LPCTSTR productVersion;
2003     UINT productVersionLength;
2004     if (!VerQueryValue(data, (LPTSTR)(LPCTSTR)key, (void**)&productVersion, &productVersionLength))
2005         goto exit;
2006     versionStr = String(productVersion, productVersionLength);
2007
2008 exit:
2009     if (data)
2010         free(data);
2011     return versionStr;
2012 }
2013
2014 const String& WebView::userAgentForKURL(const KURL& url)
2015 {
2016     if (m_userAgentOverridden)
2017         return m_userAgentCustom;
2018
2019     if (allowSiteSpecificHacks()) {
2020         if (url.host() == "ads.pointroll.com") {
2021             // <rdar://problem/6899044> Can't see Apple ad on nytimes.com unless I spoof the user agent
2022             DEFINE_STATIC_LOCAL(const String, uaForAdsPointroll, ("Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/525.28.3 (KHTML, like Gecko) Version/3.2.3 Safari/525.29"));
2023             return uaForAdsPointroll;
2024         }
2025     }
2026
2027     if (!m_userAgentStandard.length())
2028         m_userAgentStandard = WebView::standardUserAgentWithApplicationName(m_applicationName);
2029     return m_userAgentStandard;
2030 }
2031
2032 // IUnknown -------------------------------------------------------------------
2033
2034 HRESULT STDMETHODCALLTYPE WebView::QueryInterface(REFIID riid, void** ppvObject)
2035 {
2036     *ppvObject = 0;
2037     if (IsEqualGUID(riid, CLSID_WebView))
2038         *ppvObject = this;
2039     else if (IsEqualGUID(riid, IID_IUnknown))
2040         *ppvObject = static_cast<IWebView*>(this);
2041     else if (IsEqualGUID(riid, IID_IWebView))
2042         *ppvObject = static_cast<IWebView*>(this);
2043     else if (IsEqualGUID(riid, IID_IWebViewPrivate))
2044         *ppvObject = static_cast<IWebViewPrivate*>(this);
2045     else if (IsEqualGUID(riid, IID_IWebIBActions))
2046         *ppvObject = static_cast<IWebIBActions*>(this);
2047     else if (IsEqualGUID(riid, IID_IWebViewCSS))
2048         *ppvObject = static_cast<IWebViewCSS*>(this);
2049     else if (IsEqualGUID(riid, IID_IWebViewEditing))
2050         *ppvObject = static_cast<IWebViewEditing*>(this);
2051     else if (IsEqualGUID(riid, IID_IWebViewUndoableEditing))
2052         *ppvObject = static_cast<IWebViewUndoableEditing*>(this);
2053     else if (IsEqualGUID(riid, IID_IWebViewEditingActions))
2054         *ppvObject = static_cast<IWebViewEditingActions*>(this);
2055     else if (IsEqualGUID(riid, IID_IWebNotificationObserver))
2056         *ppvObject = static_cast<IWebNotificationObserver*>(this);
2057     else if (IsEqualGUID(riid, IID_IDropTarget))
2058         *ppvObject = static_cast<IDropTarget*>(this);
2059     else
2060         return E_NOINTERFACE;
2061
2062     AddRef();
2063     return S_OK;
2064 }
2065
2066 ULONG STDMETHODCALLTYPE WebView::AddRef(void)
2067 {
2068     return ++m_refCount;
2069 }
2070
2071 ULONG STDMETHODCALLTYPE WebView::Release(void)
2072 {
2073     ULONG newRef = --m_refCount;
2074     if (!newRef)
2075         delete(this);
2076
2077     return newRef;
2078 }
2079
2080 // IWebView --------------------------------------------------------------------
2081
2082 HRESULT STDMETHODCALLTYPE WebView::canShowMIMEType( 
2083     /* [in] */ BSTR mimeType,
2084     /* [retval][out] */ BOOL* canShow)
2085 {
2086     String mimeTypeStr(mimeType, SysStringLen(mimeType));
2087
2088     if (!canShow)
2089         return E_POINTER;
2090
2091     *canShow = MIMETypeRegistry::isSupportedImageMIMEType(mimeTypeStr) ||
2092         MIMETypeRegistry::isSupportedNonImageMIMEType(mimeTypeStr) ||
2093         PluginInfoStore::supportsMIMEType(mimeTypeStr) ||
2094         shouldUseEmbeddedView(mimeTypeStr);
2095     
2096     return S_OK;
2097 }
2098
2099 HRESULT STDMETHODCALLTYPE WebView::canShowMIMETypeAsHTML( 
2100     /* [in] */ BSTR /*mimeType*/,
2101     /* [retval][out] */ BOOL* canShow)
2102 {
2103     // FIXME
2104     *canShow = TRUE;
2105     return S_OK;
2106 }
2107
2108 HRESULT STDMETHODCALLTYPE WebView::MIMETypesShownAsHTML( 
2109     /* [retval][out] */ IEnumVARIANT** /*enumVariant*/)
2110 {
2111     ASSERT_NOT_REACHED();
2112     return E_NOTIMPL;
2113 }
2114
2115 HRESULT STDMETHODCALLTYPE WebView::setMIMETypesShownAsHTML( 
2116         /* [size_is][in] */ BSTR* /*mimeTypes*/,
2117         /* [in] */ int /*cMimeTypes*/)
2118 {
2119     ASSERT_NOT_REACHED();
2120     return E_NOTIMPL;
2121 }
2122
2123 HRESULT STDMETHODCALLTYPE WebView::URLFromPasteboard( 
2124     /* [in] */ IDataObject* /*pasteboard*/,
2125     /* [retval][out] */ BSTR* /*url*/)
2126 {
2127     ASSERT_NOT_REACHED();
2128     return E_NOTIMPL;
2129 }
2130
2131 HRESULT STDMETHODCALLTYPE WebView::URLTitleFromPasteboard( 
2132     /* [in] */ IDataObject* /*pasteboard*/,
2133     /* [retval][out] */ BSTR* /*urlTitle*/)
2134 {
2135     ASSERT_NOT_REACHED();
2136     return E_NOTIMPL;
2137 }
2138
2139 static void WebKitSetApplicationCachePathIfNecessary()
2140 {
2141     static bool initialized = false;
2142     if (initialized)
2143         return;
2144
2145     String path = localUserSpecificStorageDirectory();
2146     if (!path.isNull())
2147         cacheStorage().setCacheDirectory(path);
2148
2149     initialized = true;
2150 }
2151     
2152 HRESULT STDMETHODCALLTYPE WebView::initWithFrame( 
2153     /* [in] */ RECT frame,
2154     /* [in] */ BSTR frameName,
2155     /* [in] */ BSTR groupName)
2156 {
2157     HRESULT hr = S_OK;
2158
2159     if (m_viewWindow)
2160         return E_FAIL;
2161
2162     registerWebViewWindowClass();
2163
2164     if (!::IsWindow(m_hostWindow)) {
2165         ASSERT_NOT_REACHED();
2166         return E_FAIL;
2167     }
2168
2169     m_viewWindow = CreateWindowEx(0, kWebViewWindowClassName, 0, WS_CHILD | WS_CLIPCHILDREN,
2170         frame.left, frame.top, frame.right - frame.left, frame.bottom - frame.top, m_hostWindow, 0, gInstance, 0);
2171     ASSERT(::IsWindow(m_viewWindow));
2172
2173     hr = registerDragDrop();
2174     if (FAILED(hr))
2175         return hr;
2176
2177     WebPreferences* sharedPreferences = WebPreferences::sharedStandardPreferences();
2178     sharedPreferences->willAddToWebView();
2179     m_preferences = sharedPreferences;
2180
2181     InitializeLoggingChannelsIfNecessary();
2182 #if ENABLE(DATABASE)
2183     WebKitSetWebDatabasesPathIfNecessary();
2184 #endif
2185     WebKitSetApplicationCachePathIfNecessary();
2186     
2187     m_page = new Page(new WebChromeClient(this), new WebContextMenuClient(this), new WebEditorClient(this), new WebDragClient(this), new WebInspectorClient(this));
2188
2189     BSTR localStoragePath;
2190     if (SUCCEEDED(m_preferences->localStorageDatabasePath(&localStoragePath))) {
2191         m_page->settings()->setLocalStorageDatabasePath(String(localStoragePath, SysStringLen(localStoragePath)));
2192         SysFreeString(localStoragePath);
2193     }
2194
2195     if (m_uiDelegate) {
2196         COMPtr<IWebUIDelegate2> uiDelegate2;
2197         if (SUCCEEDED(m_uiDelegate->QueryInterface(IID_IWebUIDelegate2, (void**)&uiDelegate2))) {
2198             BSTR path;
2199             if (SUCCEEDED(uiDelegate2->ftpDirectoryTemplatePath(this, &path))) {
2200                 m_page->settings()->setFTPDirectoryTemplatePath(String(path, SysStringLen(path)));
2201                 SysFreeString(path);
2202             }
2203         }
2204     }
2205
2206     WebFrame* webFrame = WebFrame::createInstance();
2207     RefPtr<Frame> coreFrame = webFrame->init(this, m_page, 0);
2208     m_mainFrame = webFrame;
2209     webFrame->Release(); // The WebFrame is owned by the Frame, so release our reference to it.
2210
2211     coreFrame->tree()->setName(String(frameName, SysStringLen(frameName)));
2212     coreFrame->init();
2213     setGroupName(groupName);
2214
2215     addToAllWebViewsSet();
2216
2217     #pragma warning(suppress: 4244)
2218     SetWindowLongPtr(m_viewWindow, 0, (LONG_PTR)this);
2219     ShowWindow(m_viewWindow, SW_SHOW);
2220
2221     initializeToolTipWindow();
2222     windowAncestryDidChange();
2223
2224     IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal();
2225     notifyCenter->addObserver(this, WebPreferences::webPreferencesChangedNotification(), static_cast<IWebPreferences*>(m_preferences.get()));
2226     m_preferences->postPreferencesChangesNotification();
2227
2228     setSmartInsertDeleteEnabled(TRUE);
2229     return hr;
2230 }
2231
2232 static bool initCommonControls()
2233 {
2234     static bool haveInitialized = false;
2235     if (haveInitialized)
2236         return true;
2237
2238     INITCOMMONCONTROLSEX init;
2239     init.dwSize = sizeof(init);
2240     init.dwICC = ICC_TREEVIEW_CLASSES;
2241     haveInitialized = !!::InitCommonControlsEx(&init);
2242     return haveInitialized;
2243 }
2244
2245 void WebView::initializeToolTipWindow()
2246 {
2247     if (!initCommonControls())
2248         return;
2249
2250     m_toolTipHwnd = CreateWindowEx(0, TOOLTIPS_CLASS, 0, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
2251                                    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
2252                                    m_viewWindow, 0, 0, 0);
2253     if (!m_toolTipHwnd)
2254         return;
2255
2256     TOOLINFO info = {0};
2257     info.cbSize = sizeof(info);
2258     info.uFlags = TTF_IDISHWND | TTF_SUBCLASS ;
2259     info.uId = reinterpret_cast<UINT_PTR>(m_viewWindow);
2260
2261     ::SendMessage(m_toolTipHwnd, TTM_ADDTOOL, 0, reinterpret_cast<LPARAM>(&info));
2262     ::SendMessage(m_toolTipHwnd, TTM_SETMAXTIPWIDTH, 0, maxToolTipWidth);
2263
2264     ::SetWindowPos(m_toolTipHwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
2265 }
2266
2267 void WebView::setToolTip(const String& toolTip)
2268 {
2269     if (!m_toolTipHwnd)
2270         return;
2271
2272     if (toolTip == m_toolTip)
2273         return;
2274
2275     m_toolTip = toolTip;
2276
2277     if (!m_toolTip.isEmpty()) {
2278         TOOLINFO info = {0};
2279         info.cbSize = sizeof(info);
2280         info.uFlags = TTF_IDISHWND;
2281         info.uId = reinterpret_cast<UINT_PTR>(m_viewWindow);
2282         info.lpszText = const_cast<UChar*>(m_toolTip.charactersWithNullTermination());
2283         ::SendMessage(m_toolTipHwnd, TTM_UPDATETIPTEXT, 0, reinterpret_cast<LPARAM>(&info));
2284     }
2285
2286     ::SendMessage(m_toolTipHwnd, TTM_ACTIVATE, !m_toolTip.isEmpty(), 0);
2287 }
2288
2289 HRESULT WebView::notifyDidAddIcon(IWebNotification* notification)
2290 {
2291     COMPtr<IPropertyBag> propertyBag;
2292     HRESULT hr = notification->userInfo(&propertyBag);
2293     if (FAILED(hr))
2294         return hr;
2295     if (!propertyBag)
2296         return E_FAIL;
2297
2298     COMPtr<CFDictionaryPropertyBag> dictionaryPropertyBag;
2299     hr = propertyBag->QueryInterface(&dictionaryPropertyBag);
2300     if (FAILED(hr))
2301         return hr;
2302
2303     CFDictionaryRef dictionary = dictionaryPropertyBag->dictionary();
2304     if (!dictionary)
2305         return E_FAIL;
2306
2307     CFTypeRef value = CFDictionaryGetValue(dictionary, WebIconDatabase::iconDatabaseNotificationUserInfoURLKey());
2308     if (!value)
2309         return E_FAIL;
2310     if (CFGetTypeID(value) != CFStringGetTypeID())
2311         return E_FAIL;
2312
2313     String mainFrameURL;
2314     if (m_mainFrame)
2315         mainFrameURL = m_mainFrame->url().string();
2316
2317     if (!mainFrameURL.isEmpty() && mainFrameURL == String((CFStringRef)value))
2318         dispatchDidReceiveIconFromWebFrame(m_mainFrame);
2319
2320     return hr;
2321 }
2322
2323 void WebView::registerForIconNotification(bool listen)
2324 {
2325     IWebNotificationCenter* nc = WebNotificationCenter::defaultCenterInternal();
2326     if (listen)
2327         nc->addObserver(this, WebIconDatabase::iconDatabaseDidAddIconNotification(), 0);
2328     else
2329         nc->removeObserver(this, WebIconDatabase::iconDatabaseDidAddIconNotification(), 0);
2330 }
2331
2332 void WebView::dispatchDidReceiveIconFromWebFrame(WebFrame* frame)
2333 {
2334     registerForIconNotification(false);
2335
2336     if (m_frameLoadDelegate)
2337         // FIXME: <rdar://problem/5491010> - Pass in the right HBITMAP. 
2338         m_frameLoadDelegate->didReceiveIcon(this, 0, frame);
2339 }
2340
2341 HRESULT STDMETHODCALLTYPE WebView::setUIDelegate( 
2342     /* [in] */ IWebUIDelegate* d)
2343 {
2344     m_uiDelegate = d;
2345
2346     if (m_uiDelegatePrivate)
2347         m_uiDelegatePrivate = 0;
2348
2349     if (d) {
2350         if (FAILED(d->QueryInterface(IID_IWebUIDelegatePrivate, (void**)&m_uiDelegatePrivate)))
2351             m_uiDelegatePrivate = 0;
2352     }
2353
2354     return S_OK;
2355 }
2356
2357 HRESULT STDMETHODCALLTYPE WebView::uiDelegate( 
2358     /* [out][retval] */ IWebUIDelegate** d)
2359 {
2360     if (!m_uiDelegate)
2361         return E_FAIL;
2362
2363     return m_uiDelegate.copyRefTo(d);
2364 }
2365
2366 HRESULT STDMETHODCALLTYPE WebView::setResourceLoadDelegate( 
2367     /* [in] */ IWebResourceLoadDelegate* d)
2368 {
2369     m_resourceLoadDelegate = d;
2370     return S_OK;
2371 }
2372
2373 HRESULT STDMETHODCALLTYPE WebView::resourceLoadDelegate( 
2374     /* [out][retval] */ IWebResourceLoadDelegate** d)
2375 {
2376     if (!m_resourceLoadDelegate)
2377         return E_FAIL;
2378
2379     return m_resourceLoadDelegate.copyRefTo(d);
2380 }
2381
2382 HRESULT STDMETHODCALLTYPE WebView::setDownloadDelegate( 
2383     /* [in] */ IWebDownloadDelegate* d)
2384 {
2385     m_downloadDelegate = d;
2386     return S_OK;
2387 }
2388
2389 HRESULT STDMETHODCALLTYPE WebView::downloadDelegate( 
2390     /* [out][retval] */ IWebDownloadDelegate** d)
2391 {
2392     if (!m_downloadDelegate)
2393         return E_FAIL;
2394
2395     return m_downloadDelegate.copyRefTo(d);
2396 }
2397
2398 HRESULT STDMETHODCALLTYPE WebView::setFrameLoadDelegate( 
2399     /* [in] */ IWebFrameLoadDelegate* d)
2400 {
2401     m_frameLoadDelegate = d;
2402     return S_OK;
2403 }
2404
2405 HRESULT STDMETHODCALLTYPE WebView::frameLoadDelegate( 
2406     /* [out][retval] */ IWebFrameLoadDelegate** d)
2407 {
2408     if (!m_frameLoadDelegate)
2409         return E_FAIL;
2410
2411     return m_frameLoadDelegate.copyRefTo(d);
2412 }
2413
2414 HRESULT STDMETHODCALLTYPE WebView::setPolicyDelegate( 
2415     /* [in] */ IWebPolicyDelegate* d)
2416 {
2417     m_policyDelegate = d;
2418     return S_OK;
2419 }
2420
2421 HRESULT STDMETHODCALLTYPE WebView::policyDelegate( 
2422     /* [out][retval] */ IWebPolicyDelegate** d)
2423 {
2424     if (!m_policyDelegate)
2425         return E_FAIL;
2426     return m_policyDelegate.copyRefTo(d);
2427 }
2428
2429 HRESULT STDMETHODCALLTYPE WebView::mainFrame( 
2430     /* [out][retval] */ IWebFrame** frame)
2431 {
2432     if (!frame) {
2433         ASSERT_NOT_REACHED();
2434         return E_POINTER;
2435     }
2436
2437     *frame = m_mainFrame;
2438     if (!m_mainFrame)
2439         return E_FAIL;
2440
2441     m_mainFrame->AddRef();
2442     return S_OK;
2443 }
2444
2445 HRESULT STDMETHODCALLTYPE WebView::focusedFrame( 
2446     /* [out][retval] */ IWebFrame** frame)
2447 {
2448     if (!frame) {
2449         ASSERT_NOT_REACHED();
2450         return E_POINTER;
2451     }
2452
2453     *frame = 0;
2454     Frame* f = m_page->focusController()->focusedFrame();
2455     if (!f)
2456         return E_FAIL;
2457
2458     WebFrame* webFrame = kit(f);
2459     if (!webFrame)
2460         return E_FAIL;
2461
2462     return webFrame->QueryInterface(IID_IWebFrame, (void**) frame);
2463 }
2464 HRESULT STDMETHODCALLTYPE WebView::backForwardList( 
2465     /* [out][retval] */ IWebBackForwardList** list)
2466 {
2467     if (!m_useBackForwardList)
2468         return E_FAIL;
2469  
2470     *list = WebBackForwardList::createInstance(m_page->backForwardList());
2471
2472     return S_OK;
2473 }
2474
2475 HRESULT STDMETHODCALLTYPE WebView::setMaintainsBackForwardList( 
2476     /* [in] */ BOOL flag)
2477 {
2478     m_useBackForwardList = !!flag;
2479     return S_OK;
2480 }
2481
2482 HRESULT STDMETHODCALLTYPE WebView::goBack( 
2483     /* [retval][out] */ BOOL* succeeded)
2484 {
2485     *succeeded = m_page->goBack();
2486     return S_OK;
2487 }
2488
2489 HRESULT STDMETHODCALLTYPE WebView::goForward( 
2490     /* [retval][out] */ BOOL* succeeded)
2491 {
2492     *succeeded = m_page->goForward();
2493     return S_OK;
2494 }
2495
2496 HRESULT STDMETHODCALLTYPE WebView::goToBackForwardItem( 
2497     /* [in] */ IWebHistoryItem* item,
2498     /* [retval][out] */ BOOL* succeeded)
2499 {
2500     *succeeded = FALSE;
2501
2502     COMPtr<WebHistoryItem> webHistoryItem;
2503     HRESULT hr = item->QueryInterface(&webHistoryItem);
2504     if (FAILED(hr))
2505         return hr;
2506
2507     m_page->goToItem(webHistoryItem->historyItem(), FrameLoadTypeIndexedBackForward);
2508     *succeeded = TRUE;
2509
2510     return S_OK;
2511 }
2512
2513 HRESULT STDMETHODCALLTYPE WebView::setTextSizeMultiplier( 
2514     /* [in] */ float multiplier)
2515 {
2516     if (!m_mainFrame)
2517         return E_FAIL;
2518     setZoomMultiplier(multiplier, true);
2519     return S_OK;
2520 }
2521
2522 HRESULT STDMETHODCALLTYPE WebView::setPageSizeMultiplier( 
2523     /* [in] */ float multiplier)
2524 {
2525     if (!m_mainFrame)
2526         return E_FAIL;
2527     setZoomMultiplier(multiplier, false);
2528     return S_OK;
2529 }
2530
2531 void WebView::setZoomMultiplier(float multiplier, bool isTextOnly)
2532 {
2533     m_zoomMultiplier = multiplier;
2534     m_page->settings()->setZoomsTextOnly(isTextOnly);
2535     if (Frame* coreFrame = core(m_mainFrame))
2536         coreFrame->setZoomFactor(multiplier, isTextOnly);
2537 }
2538
2539 HRESULT STDMETHODCALLTYPE WebView::textSizeMultiplier( 
2540     /* [retval][out] */ float* multiplier)
2541 {
2542     *multiplier = zoomMultiplier(true);
2543     return S_OK;
2544 }
2545
2546 HRESULT STDMETHODCALLTYPE WebView::pageSizeMultiplier( 
2547     /* [retval][out] */ float* multiplier)
2548 {
2549     *multiplier = zoomMultiplier(false);
2550     return S_OK;
2551 }
2552
2553 float WebView::zoomMultiplier(bool isTextOnly)
2554 {
2555     if (isTextOnly != m_page->settings()->zoomsTextOnly())
2556         return 1.0f;
2557     return m_zoomMultiplier;
2558 }
2559
2560 HRESULT STDMETHODCALLTYPE WebView::setApplicationNameForUserAgent( 
2561     /* [in] */ BSTR applicationName)
2562 {
2563     m_applicationName = String(applicationName, SysStringLen(applicationName));
2564     m_userAgentStandard = String();
2565     return S_OK;
2566 }
2567
2568 HRESULT STDMETHODCALLTYPE WebView::applicationNameForUserAgent( 
2569     /* [retval][out] */ BSTR* applicationName)
2570 {
2571     *applicationName = SysAllocStringLen(m_applicationName.characters(), m_applicationName.length());
2572     if (!*applicationName && m_applicationName.length())
2573         return E_OUTOFMEMORY;
2574     return S_OK;
2575 }
2576
2577 HRESULT STDMETHODCALLTYPE WebView::setCustomUserAgent( 
2578     /* [in] */ BSTR userAgentString)
2579 {
2580     m_userAgentOverridden = userAgentString;
2581     m_userAgentCustom = String(userAgentString, SysStringLen(userAgentString));
2582     return S_OK;
2583 }
2584
2585 HRESULT STDMETHODCALLTYPE WebView::customUserAgent( 
2586     /* [retval][out] */ BSTR* userAgentString)
2587 {
2588     *userAgentString = 0;
2589     if (!m_userAgentOverridden)
2590         return S_OK;
2591     *userAgentString = SysAllocStringLen(m_userAgentCustom.characters(), m_userAgentCustom.length());
2592     if (!*userAgentString && m_userAgentCustom.length())
2593         return E_OUTOFMEMORY;
2594     return S_OK;
2595 }
2596
2597 HRESULT STDMETHODCALLTYPE WebView::userAgentForURL( 
2598     /* [in] */ BSTR url,
2599     /* [retval][out] */ BSTR* userAgent)
2600 {
2601     String userAgentString = userAgentForKURL(MarshallingHelpers::BSTRToKURL(url));
2602     *userAgent = SysAllocStringLen(userAgentString.characters(), userAgentString.length());
2603     if (!*userAgent && userAgentString.length())
2604         return E_OUTOFMEMORY;
2605     return S_OK;
2606 }
2607
2608 HRESULT STDMETHODCALLTYPE WebView::supportsTextEncoding( 
2609     /* [retval][out] */ BOOL* supports)
2610 {
2611     *supports = TRUE;
2612     return S_OK;
2613 }
2614
2615 HRESULT STDMETHODCALLTYPE WebView::setCustomTextEncodingName( 
2616     /* [in] */ BSTR encodingName)
2617 {
2618     if (!m_mainFrame)
2619         return E_FAIL;
2620
2621     HRESULT hr;
2622     BSTR oldEncoding;
2623     hr = customTextEncodingName(&oldEncoding);
2624     if (FAILED(hr))
2625         return hr;
2626
2627     if (oldEncoding != encodingName && (!oldEncoding || !encodingName || _tcscmp(oldEncoding, encodingName))) {
2628         if (Frame* coreFrame = core(m_mainFrame))
2629             coreFrame->loader()->reloadWithOverrideEncoding(String(encodingName, SysStringLen(encodingName)));
2630     }
2631
2632     return S_OK;
2633 }
2634
2635 HRESULT STDMETHODCALLTYPE WebView::customTextEncodingName( 
2636     /* [retval][out] */ BSTR* encodingName)
2637 {
2638     HRESULT hr = S_OK;
2639     COMPtr<IWebDataSource> dataSource;
2640     COMPtr<WebDataSource> dataSourceImpl;
2641     *encodingName = 0;
2642
2643     if (!m_mainFrame)
2644         return E_FAIL;
2645
2646     if (FAILED(m_mainFrame->provisionalDataSource(&dataSource)) || !dataSource) {
2647         hr = m_mainFrame->dataSource(&dataSource);
2648         if (FAILED(hr) || !dataSource)
2649             return hr;
2650     }
2651
2652     hr = dataSource->QueryInterface(IID_WebDataSource, (void**)&dataSourceImpl);
2653     if (FAILED(hr))
2654         return hr;
2655
2656     BString str = dataSourceImpl->documentLoader()->overrideEncoding();
2657     if (FAILED(hr))
2658         return hr;
2659
2660     if (!*encodingName)
2661         *encodingName = SysAllocStringLen(m_overrideEncoding.characters(), m_overrideEncoding.length());
2662
2663     if (!*encodingName && m_overrideEncoding.length())
2664         return E_OUTOFMEMORY;
2665
2666     return S_OK;
2667 }
2668
2669 HRESULT STDMETHODCALLTYPE WebView::setMediaStyle( 
2670     /* [in] */ BSTR /*media*/)
2671 {
2672     ASSERT_NOT_REACHED();
2673     return E_NOTIMPL;
2674 }
2675
2676 HRESULT STDMETHODCALLTYPE WebView::mediaStyle( 
2677     /* [retval][out] */ BSTR* /*media*/)
2678 {
2679     ASSERT_NOT_REACHED();
2680     return E_NOTIMPL;
2681 }
2682
2683 HRESULT STDMETHODCALLTYPE WebView::stringByEvaluatingJavaScriptFromString( 
2684     /* [in] */ BSTR script, // assumes input does not have "JavaScript" at the begining.
2685     /* [retval][out] */ BSTR* result)
2686 {
2687     if (!result) {
2688         ASSERT_NOT_REACHED();
2689         return E_POINTER;
2690     }
2691
2692     *result = 0;
2693
2694     Frame* coreFrame = core(m_mainFrame);
2695     if (!coreFrame)
2696         return E_FAIL;
2697
2698     JSC::JSValue scriptExecutionResult = coreFrame->loader()->executeScript(WebCore::String(script), true).jsValue();
2699     if (!scriptExecutionResult)
2700         return E_FAIL;
2701     else if (scriptExecutionResult.isString()) {
2702         JSLock lock(false);
2703         *result = BString(String(scriptExecutionResult.getString()));
2704     }
2705
2706     return S_OK;
2707 }
2708
2709 HRESULT STDMETHODCALLTYPE WebView::windowScriptObject( 
2710     /* [retval][out] */ IWebScriptObject** /*webScriptObject*/)
2711 {
2712     ASSERT_NOT_REACHED();
2713     return E_NOTIMPL;
2714 }
2715
2716 HRESULT STDMETHODCALLTYPE WebView::setPreferences( 
2717     /* [in] */ IWebPreferences* prefs)
2718 {
2719     if (!prefs)
2720         prefs = WebPreferences::sharedStandardPreferences();
2721
2722     if (m_preferences == prefs)
2723         return S_OK;
2724
2725     COMPtr<WebPreferences> webPrefs(Query, prefs);
2726     if (!webPrefs)
2727         return E_NOINTERFACE;
2728     webPrefs->willAddToWebView();
2729
2730     COMPtr<WebPreferences> oldPrefs = m_preferences;
2731
2732     IWebNotificationCenter* nc = WebNotificationCenter::defaultCenterInternal();
2733     nc->removeObserver(this, WebPreferences::webPreferencesChangedNotification(), static_cast<IWebPreferences*>(m_preferences.get()));
2734
2735     BSTR identifier = 0;
2736     oldPrefs->identifier(&identifier);
2737     oldPrefs->didRemoveFromWebView();
2738     oldPrefs = 0; // Make sure we release the reference, since WebPreferences::removeReferenceForIdentifier will check for last reference to WebPreferences
2739
2740     m_preferences = webPrefs;
2741
2742     if (identifier) {
2743         WebPreferences::removeReferenceForIdentifier(identifier);
2744         SysFreeString(identifier);
2745     }
2746
2747     nc->addObserver(this, WebPreferences::webPreferencesChangedNotification(), static_cast<IWebPreferences*>(m_preferences.get()));
2748
2749     m_preferences->postPreferencesChangesNotification();
2750
2751     return S_OK;
2752 }
2753
2754 HRESULT STDMETHODCALLTYPE WebView::preferences( 
2755     /* [retval][out] */ IWebPreferences** prefs)
2756 {
2757     if (!prefs)
2758         return E_POINTER;
2759     *prefs = m_preferences.get();
2760     if (m_preferences)
2761         m_preferences->AddRef();
2762     return S_OK;
2763 }
2764
2765 HRESULT STDMETHODCALLTYPE WebView::setPreferencesIdentifier( 
2766     /* [in] */ BSTR /*anIdentifier*/)
2767 {
2768     ASSERT_NOT_REACHED();
2769     return E_NOTIMPL;
2770 }
2771
2772 HRESULT STDMETHODCALLTYPE WebView::preferencesIdentifier( 
2773     /* [retval][out] */ BSTR* /*anIdentifier*/)
2774 {
2775     ASSERT_NOT_REACHED();
2776     return E_NOTIMPL;
2777 }
2778
2779 void WebView::windowReceivedMessage(HWND, UINT message, WPARAM wParam, LPARAM)
2780 {
2781     switch (message) {
2782     case WM_NCACTIVATE:
2783         updateActiveStateSoon();
2784         if (!wParam)
2785             deleteBackingStoreSoon();
2786         break;
2787     }
2788 }
2789
2790 void WebView::updateActiveStateSoon() const
2791 {
2792     // This function is called while processing the WM_NCACTIVATE message.
2793     // While processing WM_NCACTIVATE when we are being deactivated, GetActiveWindow() will
2794     // still return our window. If we were to call updateActiveState() in that case, we would
2795     // wrongly think that we are still the active window. To work around this, we update our
2796     // active state after a 0-delay timer fires, at which point GetActiveWindow() will return
2797     // the newly-activated window.
2798
2799     SetTimer(m_viewWindow, UpdateActiveStateTimer, 0, 0);
2800 }
2801
2802 void WebView::deleteBackingStoreSoon()
2803 {
2804     if (pendingDeleteBackingStoreSet.size() > 2) {
2805         Vector<WebView*> views;
2806         HashSet<WebView*>::iterator end = pendingDeleteBackingStoreSet.end();
2807         for (HashSet<WebView*>::iterator it = pendingDeleteBackingStoreSet.begin(); it != end; ++it)
2808             views.append(*it);
2809         for (int i = 0; i < views.size(); ++i)
2810             views[i]->deleteBackingStore();
2811         ASSERT(pendingDeleteBackingStoreSet.isEmpty());
2812     }
2813
2814     pendingDeleteBackingStoreSet.add(this);
2815     m_deleteBackingStoreTimerActive = true;
2816     SetTimer(m_viewWindow, DeleteBackingStoreTimer, delayBeforeDeletingBackingStoreMsec, 0);
2817 }
2818
2819 void WebView::cancelDeleteBackingStoreSoon()
2820 {
2821     if (!m_deleteBackingStoreTimerActive)
2822         return;
2823     pendingDeleteBackingStoreSet.remove(this);
2824     m_deleteBackingStoreTimerActive = false;
2825     KillTimer(m_viewWindow, DeleteBackingStoreTimer);
2826 }
2827
2828 HRESULT STDMETHODCALLTYPE WebView::setHostWindow( 
2829     /* [in] */ OLE_HANDLE oleWindow)
2830 {
2831     HWND window = (HWND)(ULONG64)oleWindow;
2832     if (m_viewWindow && window)
2833         SetParent(m_viewWindow, window);
2834
2835     m_hostWindow = window;
2836
2837     if (m_viewWindow)
2838         windowAncestryDidChange();
2839
2840     return S_OK;
2841 }
2842
2843 HRESULT STDMETHODCALLTYPE WebView::hostWindow( 
2844     /* [retval][out] */ OLE_HANDLE* window)
2845 {
2846     *window = (OLE_HANDLE)(ULONG64)m_hostWindow;
2847     return S_OK;
2848 }
2849
2850
2851 static Frame *incrementFrame(Frame *curr, bool forward, bool wrapFlag)
2852 {
2853     return forward
2854         ? curr->tree()->traverseNextWithWrap(wrapFlag)
2855         : curr->tree()->traversePreviousWithWrap(wrapFlag);
2856 }
2857
2858 HRESULT STDMETHODCALLTYPE WebView::searchFor( 
2859     /* [in] */ BSTR str,
2860     /* [in] */ BOOL forward,
2861     /* [in] */ BOOL caseFlag,
2862     /* [in] */ BOOL wrapFlag,
2863     /* [retval][out] */ BOOL* found)
2864 {
2865     if (!found)
2866         return E_INVALIDARG;
2867     
2868     if (!m_page || !m_page->mainFrame())
2869         return E_UNEXPECTED;
2870
2871     if (!str || !SysStringLen(str))
2872         return E_INVALIDARG;
2873
2874     *found = m_page->findString(String(str, SysStringLen(str)), caseFlag ? TextCaseSensitive : TextCaseInsensitive, forward ? FindDirectionForward : FindDirectionBackward, wrapFlag);
2875     return S_OK;
2876 }
2877
2878 bool WebView::active()
2879 {
2880     HWND activeWindow = GetActiveWindow();
2881     return (activeWindow && m_topLevelParent == findTopLevelParent(activeWindow));
2882 }
2883
2884 void WebView::updateActiveState()
2885 {
2886     m_page->focusController()->setActive(active());
2887 }
2888
2889 HRESULT STDMETHODCALLTYPE WebView::updateFocusedAndActiveState()
2890 {
2891     updateActiveState();
2892
2893     bool active = m_page->focusController()->isActive();
2894     Frame* mainFrame = m_page->mainFrame();
2895     Frame* focusedFrame = m_page->focusController()->focusedOrMainFrame();
2896     mainFrame->selection()->setFocused(active && mainFrame == focusedFrame);
2897
2898     return S_OK;
2899 }
2900
2901 HRESULT STDMETHODCALLTYPE WebView::executeCoreCommandByName(BSTR bName, BSTR bValue)
2902 {
2903     String name(bName, SysStringLen(bName));
2904     String value(bValue, SysStringLen(bValue));
2905
2906     m_page->focusController()->focusedOrMainFrame()->editor()->command(name).execute(value);
2907
2908     return S_OK;
2909 }
2910
2911 HRESULT STDMETHODCALLTYPE WebView::clearMainFrameName()
2912 {
2913     m_page->mainFrame()->tree()->clearName();
2914
2915     return S_OK;
2916 }
2917
2918 HRESULT STDMETHODCALLTYPE WebView::markAllMatchesForText(
2919     BSTR str, BOOL caseSensitive, BOOL highlight, UINT limit, UINT* matches)
2920 {
2921     if (!matches)
2922         return E_INVALIDARG;
2923
2924     if (!m_page || !m_page->mainFrame())
2925         return E_UNEXPECTED;
2926
2927     if (!str || !SysStringLen(str))
2928         return E_INVALIDARG;
2929
2930     *matches = m_page->markAllMatchesForText(String(str, SysStringLen(str)), caseSensitive ? TextCaseSensitive : TextCaseInsensitive, highlight, limit);
2931     return S_OK;
2932 }
2933
2934 HRESULT STDMETHODCALLTYPE WebView::unmarkAllTextMatches()
2935 {
2936     if (!m_page || !m_page->mainFrame())
2937         return E_UNEXPECTED;
2938
2939     m_page->unmarkAllTextMatches();
2940     return S_OK;
2941 }
2942
2943 HRESULT STDMETHODCALLTYPE WebView::rectsForTextMatches(
2944     IEnumTextMatches** pmatches)
2945 {
2946     Vector<IntRect> allRects;
2947     WebCore::Frame* frame = m_page->mainFrame();
2948     do {
2949         if (Document* document = frame->document()) {
2950             IntRect visibleRect = frame->view()->visibleContentRect();
2951             Vector<IntRect> frameRects = document->renderedRectsForMarkers(DocumentMarker::TextMatch);
2952             IntPoint frameOffset(-frame->view()->scrollOffset().width(), -frame->view()->scrollOffset().height());
2953             frameOffset = frame->view()->convertToContainingWindow(frameOffset);
2954
2955             Vector<IntRect>::iterator end = frameRects.end();
2956             for (Vector<IntRect>::iterator it = frameRects.begin(); it < end; it++) {
2957                 it->intersect(visibleRect);
2958                 it->move(frameOffset.x(), frameOffset.y());
2959                 allRects.append(*it);
2960             }
2961         }
2962         frame = incrementFrame(frame, true, false);
2963     } while (frame);
2964
2965     return createMatchEnumerator(&allRects, pmatches);
2966 }
2967
2968 HRESULT STDMETHODCALLTYPE WebView::generateSelectionImage(BOOL forceWhiteText, OLE_HANDLE* hBitmap)
2969 {
2970     *hBitmap = 0;
2971
2972     WebCore::Frame* frame = m_page->focusController()->focusedOrMainFrame();
2973
2974     if (frame) {
2975         HBITMAP bitmap = imageFromSelection(frame, forceWhiteText ? TRUE : FALSE);
2976         *hBitmap = (OLE_HANDLE)(ULONG64)bitmap;
2977     }
2978
2979     return S_OK;
2980 }
2981
2982 HRESULT STDMETHODCALLTYPE WebView::selectionRect(RECT* rc)
2983 {
2984     WebCore::Frame* frame = m_page->focusController()->focusedOrMainFrame();
2985
2986     if (frame) {
2987         IntRect ir = enclosingIntRect(frame->selectionBounds());
2988         ir = frame->view()->convertToContainingWindow(ir);
2989         ir.move(-frame->view()->scrollOffset().width(), -frame->view()->scrollOffset().height());
2990         rc->left = ir.x();
2991         rc->top = ir.y();
2992         rc->bottom = rc->top + ir.height();
2993         rc->right = rc->left + ir.width();
2994     }
2995
2996     return S_OK;
2997 }
2998
2999 HRESULT STDMETHODCALLTYPE WebView::registerViewClass( 
3000     /* [in] */ IWebDocumentView* /*view*/,
3001     /* [in] */ IWebDocumentRepresentation* /*representation*/,
3002     /* [in] */ BSTR /*forMIMEType*/)
3003 {
3004     ASSERT_NOT_REACHED();
3005     return E_NOTIMPL;
3006 }
3007
3008 HRESULT STDMETHODCALLTYPE WebView::setGroupName( 
3009         /* [in] */ BSTR groupName)
3010 {
3011     if (!m_page)
3012         return S_OK;
3013     m_page->setGroupName(String(groupName, SysStringLen(groupName)));
3014     return S_OK;
3015 }
3016     
3017 HRESULT STDMETHODCALLTYPE WebView::groupName( 
3018         /* [retval][out] */ BSTR* groupName)
3019 {
3020     *groupName = 0;
3021     if (!m_page)
3022         return S_OK;
3023     String groupNameString = m_page->groupName();
3024     *groupName = SysAllocStringLen(groupNameString.characters(), groupNameString.length());
3025     if (!*groupName && groupNameString.length())
3026         return E_OUTOFMEMORY;
3027     return S_OK;
3028 }
3029     
3030 HRESULT STDMETHODCALLTYPE WebView::estimatedProgress( 
3031         /* [retval][out] */ double* estimatedProgress)
3032 {
3033     *estimatedProgress = m_page->progress()->estimatedProgress();
3034     return S_OK;
3035 }
3036     
3037 HRESULT STDMETHODCALLTYPE WebView::isLoading( 
3038         /* [retval][out] */ BOOL* isLoading)
3039 {
3040     COMPtr<IWebDataSource> dataSource;
3041     COMPtr<IWebDataSource> provisionalDataSource;
3042
3043     if (!isLoading)
3044         return E_POINTER;
3045
3046     *isLoading = FALSE;
3047
3048     if (SUCCEEDED(m_mainFrame->dataSource(&dataSource)))
3049         dataSource->isLoading(isLoading);
3050
3051     if (*isLoading)
3052         return S_OK;
3053
3054     if (SUCCEEDED(m_mainFrame->provisionalDataSource(&provisionalDataSource)))
3055         provisionalDataSource->isLoading(isLoading);
3056     return S_OK;
3057 }
3058     
3059 HRESULT STDMETHODCALLTYPE WebView::elementAtPoint( 
3060         /* [in] */ LPPOINT point,
3061         /* [retval][out] */ IPropertyBag** elementDictionary)
3062 {
3063     if (!elementDictionary) {
3064         ASSERT_NOT_REACHED();
3065         return E_POINTER;
3066     }
3067
3068     *elementDictionary = 0;
3069
3070     Frame* frame = core(m_mainFrame);
3071     if (!frame)
3072         return E_FAIL;
3073
3074     IntPoint webCorePoint = IntPoint(point->x, point->y);
3075     HitTestResult result = HitTestResult(webCorePoint);
3076     if (frame->contentRenderer())
3077         result = frame->eventHandler()->hitTestResultAtPoint(webCorePoint, false);
3078     *elementDictionary = WebElementPropertyBag::createInstance(result);
3079     return S_OK;
3080 }
3081     
3082 HRESULT STDMETHODCALLTYPE WebView::pasteboardTypesForSelection( 
3083     /* [retval][out] */ IEnumVARIANT** /*enumVariant*/)
3084 {
3085     ASSERT_NOT_REACHED();
3086     return E_NOTIMPL;
3087 }
3088     
3089 HRESULT STDMETHODCALLTYPE WebView::writeSelectionWithPasteboardTypes( 
3090         /* [size_is][in] */ BSTR* /*types*/,
3091         /* [in] */ int /*cTypes*/,
3092         /* [in] */ IDataObject* /*pasteboard*/)
3093 {
3094     ASSERT_NOT_REACHED();
3095     return E_NOTIMPL;
3096 }
3097     
3098 HRESULT STDMETHODCALLTYPE WebView::pasteboardTypesForElement( 
3099     /* [in] */ IPropertyBag* /*elementDictionary*/,
3100     /* [retval][out] */ IEnumVARIANT** /*enumVariant*/)
3101 {
3102     ASSERT_NOT_REACHED();
3103     return E_NOTIMPL;
3104 }
3105     
3106 HRESULT STDMETHODCALLTYPE WebView::writeElement( 
3107         /* [in] */ IPropertyBag* /*elementDictionary*/,
3108         /* [size_is][in] */ BSTR* /*withPasteboardTypes*/,
3109         /* [in] */ int /*cWithPasteboardTypes*/,
3110         /* [in] */ IDataObject* /*pasteboard*/)
3111 {
3112     ASSERT_NOT_REACHED();
3113     return E_NOTIMPL;
3114 }
3115     
3116 HRESULT STDMETHODCALLTYPE WebView::selectedText(
3117         /* [out, retval] */ BSTR* text)
3118 {
3119     if (!text) {
3120         ASSERT_NOT_REACHED();
3121         return E_POINTER;
3122     }
3123
3124     *text = 0;
3125
3126     Frame* focusedFrame = (m_page && m_page->focusController()) ? m_page->focusController()->focusedOrMainFrame() : 0;
3127     if (!focusedFrame)
3128         return E_FAIL;
3129
3130     String frameSelectedText = focusedFrame->selectedText();
3131     *text = SysAllocStringLen(frameSelectedText.characters(), frameSelectedText.length());
3132     if (!*text && frameSelectedText.length())
3133         return E_OUTOFMEMORY;
3134     return S_OK;
3135 }
3136
3137 HRESULT STDMETHODCALLTYPE WebView::centerSelectionInVisibleArea(
3138         /* [in] */ IUnknown* /* sender */)
3139 {
3140     Frame* coreFrame = core(m_mainFrame);
3141     if (!coreFrame)
3142         return E_FAIL;
3143
3144     coreFrame->revealSelection(ScrollAlignment::alignCenterAlways);
3145     return S_OK;
3146 }
3147
3148
3149 HRESULT STDMETHODCALLTYPE WebView::moveDragCaretToPoint( 
3150         /* [in] */ LPPOINT /*point*/)
3151 {
3152     ASSERT_NOT_REACHED();
3153     return E_NOTIMPL;
3154 }
3155     
3156 HRESULT STDMETHODCALLTYPE WebView::removeDragCaret( void)
3157 {
3158     ASSERT_NOT_REACHED();
3159     return E_NOTIMPL;
3160 }
3161     
3162 HRESULT STDMETHODCALLTYPE WebView::setDrawsBackground( 
3163         /* [in] */ BOOL /*drawsBackground*/)
3164 {
3165     ASSERT_NOT_REACHED();
3166     return E_NOTIMPL;
3167 }
3168     
3169 HRESULT STDMETHODCALLTYPE WebView::drawsBackground( 
3170         /* [retval][out] */ BOOL* /*drawsBackground*/)
3171 {
3172     ASSERT_NOT_REACHED();
3173     return E_NOTIMPL;
3174 }
3175     
3176 HRESULT STDMETHODCALLTYPE WebView::setMainFrameURL( 
3177         /* [in] */ BSTR /*urlString*/)
3178 {
3179     ASSERT_NOT_REACHED();
3180     return E_NOTIMPL;
3181 }
3182     
3183 HRESULT STDMETHODCALLTYPE WebView::mainFrameURL( 
3184         /* [retval][out] */ BSTR* /*urlString*/)
3185 {
3186     ASSERT_NOT_REACHED();
3187     return E_NOTIMPL;
3188 }
3189     
3190 HRESULT STDMETHODCALLTYPE WebView::mainFrameDocument( 
3191         /* [retval][out] */ IDOMDocument** document)
3192 {
3193     if (document)
3194         *document = 0;
3195     if (!m_mainFrame)
3196         return E_FAIL;
3197     return m_mainFrame->DOMDocument(document);
3198 }
3199     
3200 HRESULT STDMETHODCALLTYPE WebView::mainFrameTitle( 
3201         /* [retval][out] */ BSTR* /*title*/)
3202 {
3203     ASSERT_NOT_REACHED();
3204     return E_NOTIMPL;
3205 }
3206     
3207 HRESULT STDMETHODCALLTYPE WebView::mainFrameIcon( 
3208         /* [retval][out] */ OLE_HANDLE* /*hBitmap*/)
3209 {
3210     ASSERT_NOT_REACHED();
3211     return E_NOTIMPL;
3212 }
3213
3214 HRESULT STDMETHODCALLTYPE WebView::registerURLSchemeAsLocal( 
3215         /* [in] */ BSTR scheme)
3216 {
3217     if (!scheme)
3218         return E_POINTER;
3219
3220     FrameLoader::registerURLSchemeAsLocal(String(scheme, ::SysStringLen(scheme)));
3221
3222     return S_OK;
3223 }
3224
3225 // IWebIBActions ---------------------------------------------------------------
3226
3227 HRESULT STDMETHODCALLTYPE WebView::takeStringURLFrom( 
3228         /* [in] */ IUnknown* /*sender*/)
3229 {
3230     ASSERT_NOT_REACHED();
3231     return E_NOTIMPL;
3232 }
3233     
3234 HRESULT STDMETHODCALLTYPE WebView::stopLoading( 
3235         /* [in] */ IUnknown* /*sender*/)
3236 {
3237     if (!m_mainFrame)
3238         return E_FAIL;
3239
3240     return m_mainFrame->stopLoading();
3241 }
3242     
3243 HRESULT STDMETHODCALLTYPE WebView::reload( 
3244         /* [in] */ IUnknown* /*sender*/)
3245 {
3246     if (!m_mainFrame)
3247         return E_FAIL;
3248
3249     return m_mainFrame->reload();
3250 }
3251     
3252 HRESULT STDMETHODCALLTYPE WebView::canGoBack( 
3253         /* [in] */ IUnknown* /*sender*/,
3254         /* [retval][out] */ BOOL* result)
3255 {
3256     *result = !!m_page->backForwardList()->backItem();
3257     return S_OK;
3258 }
3259     
3260 HRESULT STDMETHODCALLTYPE WebView::goBack( 
3261         /* [in] */ IUnknown* /*sender*/)
3262 {
3263     ASSERT_NOT_REACHED();
3264     return E_NOTIMPL;
3265 }
3266     
3267 HRESULT STDMETHODCALLTYPE WebView::canGoForward( 
3268         /* [in] */ IUnknown* /*sender*/,
3269         /* [retval][out] */ BOOL* result)
3270 {
3271     *result = !!m_page->backForwardList()->forwardItem();
3272     return S_OK;
3273 }
3274     
3275 HRESULT STDMETHODCALLTYPE WebView::goForward( 
3276         /* [in] */ IUnknown* /*sender*/)
3277 {
3278     ASSERT_NOT_REACHED();
3279     return E_NOTIMPL;
3280 }
3281
3282 // FIXME: This code should move into WebCore so it can be shared by all the WebKits.
3283 #define MinimumZoomMultiplier   0.5f
3284 #define MaximumZoomMultiplier   3.0f
3285 #define ZoomMultiplierRatio     1.2f
3286
3287 HRESULT STDMETHODCALLTYPE WebView::canMakeTextLarger( 
3288         /* [in] */ IUnknown* /*sender*/,
3289         /* [retval][out] */ BOOL* result)
3290 {
3291     bool canGrowMore = canZoomIn(m_page->settings()->zoomsTextOnly());
3292     *result = canGrowMore ? TRUE : FALSE;
3293     return S_OK;
3294 }
3295
3296 HRESULT STDMETHODCALLTYPE WebView::canZoomPageIn( 
3297         /* [in] */ IUnknown* /*sender*/,
3298         /* [retval][out] */ BOOL* result)
3299 {
3300     bool canGrowMore = canZoomIn(false);
3301     *result = canGrowMore ? TRUE : FALSE;
3302     return S_OK;
3303 }
3304
3305 bool WebView::canZoomIn(bool isTextOnly)
3306 {
3307     return zoomMultiplier(isTextOnly) * ZoomMultiplierRatio < MaximumZoomMultiplier;
3308 }
3309     
3310 HRESULT STDMETHODCALLTYPE WebView::makeTextLarger( 
3311         /* [in] */ IUnknown* /*sender*/)
3312 {
3313     return zoomIn(m_page->settings()->zoomsTextOnly());
3314 }
3315
3316 HRESULT STDMETHODCALLTYPE WebView::zoomPageIn( 
3317         /* [in] */ IUnknown* /*sender*/)
3318 {
3319     return zoomIn(false);
3320 }
3321
3322 HRESULT WebView::zoomIn(bool isTextOnly)
3323 {
3324     if (!canZoomIn(isTextOnly))
3325         return E_FAIL;
3326     setZoomMultiplier(zoomMultiplier(isTextOnly) * ZoomMultiplierRatio, isTextOnly);
3327     return S_OK;
3328 }
3329
3330 HRESULT STDMETHODCALLTYPE WebView::canMakeTextSmaller( 
3331         /* [in] */ IUnknown* /*sender*/,
3332         /* [retval][out] */ BOOL* result)
3333 {
3334     bool canShrinkMore = canZoomOut(m_page->settings()->zoomsTextOnly());
3335     *result = canShrinkMore ? TRUE : FALSE;
3336     return S_OK;
3337 }
3338
3339 HRESULT STDMETHODCALLTYPE WebView::canZoomPageOut( 
3340         /* [in] */ IUnknown* /*sender*/,
3341         /* [retval][out] */ BOOL* result)
3342 {
3343     bool canShrinkMore = canZoomOut(false);
3344     *result = canShrinkMore ? TRUE : FALSE;
3345     return S_OK;
3346 }
3347
3348 bool WebView::canZoomOut(bool isTextOnly)
3349 {
3350     return zoomMultiplier(isTextOnly) / ZoomMultiplierRatio > MinimumZoomMultiplier;
3351 }
3352
3353 HRESULT STDMETHODCALLTYPE WebView::makeTextSmaller( 
3354         /* [in] */ IUnknown* /*sender*/)
3355 {
3356     return zoomOut(m_page->settings()->zoomsTextOnly());
3357 }
3358
3359 HRESULT STDMETHODCALLTYPE WebView::zoomPageOut( 
3360         /* [in] */ IUnknown* /*sender*/)
3361 {
3362     return zoomOut(false);
3363 }
3364
3365 HRESULT WebView::zoomOut(bool isTextOnly)
3366 {
3367     if (!canZoomOut(isTextOnly))
3368         return E_FAIL;
3369     setZoomMultiplier(zoomMultiplier(isTextOnly) / ZoomMultiplierRatio, isTextOnly);
3370     return S_OK;
3371 }
3372
3373 HRESULT STDMETHODCALLTYPE WebView::canMakeTextStandardSize( 
3374     /* [in] */ IUnknown* /*sender*/,
3375     /* [retval][out] */ BOOL* result)
3376 {
3377     // Since we always reset text zoom and page zoom together, this should continue to return an answer about text zoom even if its not enabled.
3378     bool notAlreadyStandard = canResetZoom(true);
3379     *result = notAlreadyStandard ? TRUE : FALSE;
3380     return S_OK;
3381 }
3382
3383 HRESULT STDMETHODCALLTYPE WebView::canResetPageZoom( 
3384     /* [in] */ IUnknown* /*sender*/,
3385     /* [retval][out] */ BOOL* result)
3386 {
3387     bool notAlreadyStandard = canResetZoom(false);
3388     *result = notAlreadyStandard ? TRUE : FALSE;
3389     return S_OK;
3390 }
3391
3392 bool WebView::canResetZoom(bool isTextOnly)
3393 {
3394     return zoomMultiplier(isTextOnly) != 1.0f;
3395 }
3396
3397 HRESULT STDMETHODCALLTYPE WebView::makeTextStandardSize( 
3398     /* [in] */ IUnknown* /*sender*/)
3399 {
3400     return resetZoom(true);
3401 }
3402
3403 HRESULT STDMETHODCALLTYPE WebView::resetPageZoom( 
3404     /* [in] */ IUnknown* /*sender*/)
3405 {
3406     return resetZoom(false);
3407 }
3408
3409 HRESULT WebView::resetZoom(bool isTextOnly)
3410 {
3411     if (!canResetZoom(isTextOnly))
3412         return E_FAIL;
3413     setZoomMultiplier(1.0f, isTextOnly);
3414     return S_OK;
3415 }
3416
3417 HRESULT STDMETHODCALLTYPE WebView::toggleContinuousSpellChecking( 
3418     /* [in] */ IUnknown* /*sender*/)
3419 {
3420     HRESULT hr;
3421     BOOL enabled;
3422     if (FAILED(hr = isContinuousSpellCheckingEnabled(&enabled)))
3423         return hr;
3424     return setContinuousSpellCheckingEnabled(enabled ? FALSE : TRUE);
3425 }
3426
3427 HRESULT STDMETHODCALLTYPE WebView::toggleSmartInsertDelete( 
3428     /* [in] */ IUnknown* /*sender*/)
3429 {
3430     BOOL enabled = FALSE;
3431     HRESULT hr = smartInsertDeleteEnabled(&enabled);
3432     if (FAILED(hr))
3433         return hr;
3434
3435     return setSmartInsertDeleteEnabled(enabled ? FALSE : TRUE);
3436 }
3437
3438 HRESULT STDMETHODCALLTYPE WebView::toggleGrammarChecking( 
3439     /* [in] */ IUnknown* /*sender*/)
3440 {
3441     BOOL enabled;
3442     HRESULT hr = isGrammarCheckingEnabled(&enabled);
3443     if (FAILED(hr))
3444         return hr;
3445
3446     return setGrammarCheckingEnabled(enabled ? FALSE : TRUE);
3447 }
3448
3449 // IWebViewCSS -----------------------------------------------------------------
3450
3451 HRESULT STDMETHODCALLTYPE WebView::computedStyleForElement( 
3452         /* [in] */ IDOMElement* /*element*/,
3453         /* [in] */ BSTR /*pseudoElement*/,
3454         /* [retval][out] */ IDOMCSSStyleDeclaration** /*style*/)
3455 {
3456     ASSERT_NOT_REACHED();
3457     return E_NOTIMPL;
3458 }
3459
3460 // IWebViewEditing -------------------------------------------------------------
3461
3462 HRESULT STDMETHODCALLTYPE WebView::editableDOMRangeForPoint( 
3463         /* [in] */ LPPOINT /*point*/,
3464         /* [retval][out] */ IDOMRange** /*range*/)
3465 {
3466     ASSERT_NOT_REACHED();
3467     return E_NOTIMPL;
3468 }
3469     
3470 HRESULT STDMETHODCALLTYPE WebView::setSelectedDOMRange( 
3471         /* [in] */ IDOMRange* /*range*/,
3472         /* [in] */ WebSelectionAffinity /*affinity*/)
3473 {
3474     ASSERT_NOT_REACHED();
3475     return E_NOTIMPL;
3476 }
3477     
3478 HRESULT STDMETHODCALLTYPE WebView::selectedDOMRange( 
3479         /* [retval][out] */ IDOMRange** /*range*/)
3480 {
3481     ASSERT_NOT_REACHED();
3482     return E_NOTIMPL;
3483 }
3484     
3485 HRESULT STDMETHODCALLTYPE WebView::selectionAffinity( 
3486         /* [retval][out][retval][out] */ WebSelectionAffinity* /*affinity*/)
3487 {
3488     ASSERT_NOT_REACHED();
3489     return E_NOTIMPL;
3490 }
3491     
3492 HRESULT STDMETHODCALLTYPE WebView::setEditable( 
3493         /* [in] */ BOOL /*flag*/)
3494 {
3495     ASSERT_NOT_REACHED();
3496     return E_NOTIMPL;
3497 }
3498     
3499 HRESULT STDMETHODCALLTYPE WebView::isEditable( 
3500         /* [retval][out] */ BOOL* /*isEditable*/)
3501 {
3502     ASSERT_NOT_REACHED();
3503     return E_NOTIMPL;
3504 }
3505     
3506 HRESULT STDMETHODCALLTYPE WebView::setTypingStyle( 
3507         /* [in] */ IDOMCSSStyleDeclaration* /*style*/)
3508 {
3509     ASSERT_NOT_REACHED();
3510     return E_NOTIMPL;
3511 }
3512     
3513 HRESULT STDMETHODCALLTYPE WebView::typingStyle( 
3514         /* [retval][out] */ IDOMCSSStyleDeclaration** /*style*/)
3515 {
3516     ASSERT_NOT_REACHED();
3517     return E_NOTIMPL;
3518 }
3519     
3520 HRESULT STDMETHODCALLTYPE WebView::setSmartInsertDeleteEnabled( 
3521         /* [in] */ BOOL flag)
3522 {
3523     m_smartInsertDeleteEnabled = !!flag;
3524     if (m_smartInsertDeleteEnabled)
3525         setSelectTrailingWhitespaceEnabled(false);
3526     return S_OK;
3527 }
3528     
3529 HRESULT STDMETHODCALLTYPE WebView::smartInsertDeleteEnabled( 
3530         /* [retval][out] */ BOOL* enabled)
3531 {
3532     *enabled = m_smartInsertDeleteEnabled ? TRUE : FALSE;
3533     return S_OK;
3534 }
3535  
3536 HRESULT STDMETHODCALLTYPE WebView::setSelectTrailingWhitespaceEnabled( 
3537         /* [in] */ BOOL flag)
3538 {
3539     m_selectTrailingWhitespaceEnabled = !!flag;
3540     if (m_selectTrailingWhitespaceEnabled)
3541         setSmartInsertDeleteEnabled(false);
3542     return S_OK;
3543 }
3544     
3545 HRESULT STDMETHODCALLTYPE WebView::isSelectTrailingWhitespaceEnabled( 
3546         /* [retval][out] */ BOOL* enabled)
3547 {
3548     *enabled = m_selectTrailingWhitespaceEnabled ? TRUE : FALSE;
3549     return S_OK;
3550 }
3551
3552 HRESULT STDMETHODCALLTYPE WebView::setContinuousSpellCheckingEnabled( 
3553         /* [in] */ BOOL flag)
3554 {
3555     if (continuousSpellCheckingEnabled != !!flag) {
3556         continuousSpellCheckingEnabled = !!flag;
3557         COMPtr<IWebPreferences> prefs;
3558         if (SUCCEEDED(preferences(&prefs)))
3559             prefs->setContinuousSpellCheckingEnabled(flag);
3560     }
3561     
3562     BOOL spellCheckingEnabled;
3563     if (SUCCEEDED(isContinuousSpellCheckingEnabled(&spellCheckingEnabled)) && spellCheckingEnabled)
3564         preflightSpellChecker();
3565     else
3566         m_mainFrame->unmarkAllMisspellings();
3567
3568     return S_OK;
3569 }
3570     
3571 HRESULT STDMETHODCALLTYPE WebView::isContinuousSpellCheckingEnabled( 
3572         /* [retval][out] */ BOOL* enabled)
3573 {
3574     *enabled = (continuousSpellCheckingEnabled && continuousCheckingAllowed()) ? TRUE : FALSE;
3575     return S_OK;
3576 }
3577     
3578 HRESULT STDMETHODCALLTYPE WebView::spellCheckerDocumentTag( 
3579         /* [retval][out] */ int* tag)
3580 {
3581     // we just use this as a flag to indicate that we've spell checked the document
3582     // and need to close the spell checker out when the view closes.
3583     *tag = 0;
3584     m_hasSpellCheckerDocumentTag = true;
3585     return S_OK;
3586 }
3587
3588 static COMPtr<IWebEditingDelegate> spellingDelegateForTimer;
3589
3590 static void preflightSpellCheckerNow()
3591 {
3592     spellingDelegateForTimer->preflightChosenSpellServer();
3593     spellingDelegateForTimer = 0;
3594 }
3595
3596 static void CALLBACK preflightSpellCheckerTimerCallback(HWND, UINT, UINT_PTR id, DWORD)
3597 {
3598     ::KillTimer(0, id);
3599     preflightSpellCheckerNow();
3600 }
3601
3602 void WebView::preflightSpellChecker()
3603 {
3604     // As AppKit does, we wish to delay tickling the shared spellchecker into existence on application launch.
3605     if (!m_editingDelegate)
3606         return;
3607
3608     BOOL exists;
3609     spellingDelegateForTimer = m_editingDelegate;
3610     if (SUCCEEDED(m_editingDelegate->sharedSpellCheckerExists(&exists)) && exists)
3611         preflightSpellCheckerNow();
3612     else
3613         ::SetTimer(0, 0, 2000, preflightSpellCheckerTimerCallback);
3614 }
3615
3616 bool WebView::continuousCheckingAllowed()
3617 {
3618     static bool allowContinuousSpellChecking = true;
3619     static bool readAllowContinuousSpellCheckingDefault = false;
3620     if (!readAllowContinuousSpellCheckingDefault) {
3621         COMPtr<IWebPreferences> prefs;
3622         if (SUCCEEDED(preferences(&prefs))) {
3623             BOOL allowed;
3624             prefs->allowContinuousSpellChecking(&allowed);
3625             allowContinuousSpellChecking = !!allowed;
3626         }
3627         readAllowContinuousSpellCheckingDefault = true;
3628     }
3629     return allowContinuousSpellChecking;
3630 }
3631
3632 HRESULT STDMETHODCALLTYPE WebView::undoManager( 
3633         /* [retval][out] */ IWebUndoManager** /*manager*/)
3634 {
3635     ASSERT_NOT_REACHED();
3636     return E_NOTIMPL;
3637 }
3638     
3639 HRESULT STDMETHODCALLTYPE WebView::setEditingDelegate( 
3640         /* [in] */ IWebEditingDelegate* d)
3641 {
3642     m_editingDelegate = d;
3643     return S_OK;
3644 }
3645     
3646 HRESULT STDMETHODCALLTYPE WebView::editingDelegate( 
3647         /* [retval][out] */ IWebEditingDelegate** d)
3648 {
3649     if (!d) {
3650         ASSERT_NOT_REACHED();
3651         return E_POINTER;
3652     }
3653
3654     *d = m_editingDelegate.get();
3655     if (!*d)
3656         return E_FAIL;
3657
3658     (*d)->AddRef();
3659     return S_OK;
3660 }
3661     
3662 HRESULT STDMETHODCALLTYPE WebView::styleDeclarationWithText( 
3663         /* [in] */ BSTR /*text*/,
3664         /* [retval][out] */ IDOMCSSStyleDeclaration** /*style*/)
3665 {
3666     ASSERT_NOT_REACHED();
3667     return E_NOTIMPL;
3668 }
3669     
3670 HRESULT STDMETHODCALLTYPE WebView::hasSelectedRange( 
3671         /* [retval][out] */ BOOL* hasSelectedRange)
3672 {
3673     *hasSelectedRange = m_page->mainFrame()->selection()->isRange();
3674     return S_OK;
3675 }
3676     
3677 HRESULT STDMETHODCALLTYPE WebView::cutEnabled( 
3678         /* [retval][out] */ BOOL* enabled)
3679 {
3680     Editor* editor = m_page->focusController()->focusedOrMainFrame()->editor();
3681     *enabled = editor->canCut() || editor->canDHTMLCut();
3682     return S_OK;
3683 }
3684     
3685 HRESULT STDMETHODCALLTYPE WebView::copyEnabled( 
3686         /* [retval][out] */ BOOL* enabled)
3687 {
3688     Editor* editor = m_page->focusController()->focusedOrMainFrame()->editor();
3689     *enabled = editor->canCopy() || editor->canDHTMLCopy();
3690     return S_OK;
3691 }
3692     
3693 HRESULT STDMETHODCALLTYPE WebView::pasteEnabled( 
3694         /* [retval][out] */ BOOL* enabled)
3695 {
3696     Editor* editor = m_page->focusController()->focusedOrMainFrame()->editor();
3697     *enabled = editor->canPaste() || editor->canDHTMLPaste();
3698     return S_OK;
3699 }
3700     
3701 HRESULT STDMETHODCALLTYPE WebView::deleteEnabled( 
3702         /* [retval][out] */ BOOL* enabled)
3703 {
3704     *enabled = m_page->focusController()->focusedOrMainFrame()->editor()->canDelete();
3705     return S_OK;
3706 }
3707     
3708 HRESULT STDMETHODCALLTYPE WebView::editingEnabled( 
3709         /* [retval][out] */ BOOL* enabled)
3710 {
3711     *enabled = m_page->focusController()->focusedOrMainFrame()->editor()->canEdit();
3712     return S_OK;
3713 }
3714
3715 HRESULT STDMETHODCALLTYPE WebView::isGrammarCheckingEnabled( 
3716     /* [retval][out] */ BOOL* enabled)
3717 {
3718     *enabled = grammarCheckingEnabled ? TRUE : FALSE;
3719     return S_OK;
3720 }
3721
3722 HRESULT STDMETHODCALLTYPE WebView::setGrammarCheckingEnabled( 
3723     BOOL enabled)
3724 {
3725     if (!m_editingDelegate) {
3726         LOG_ERROR("No NSSpellChecker");
3727         return E_FAIL;
3728     }
3729
3730     if (grammarCheckingEnabled == !!enabled)
3731         return S_OK;
3732     
3733     grammarCheckingEnabled = !!enabled;
3734     COMPtr<IWebPreferences> prefs;
3735     if (SUCCEEDED(preferences(&prefs)))
3736         prefs->setGrammarCheckingEnabled(enabled);
3737     
3738     m_editingDelegate->updateGrammar();
3739
3740     // We call _preflightSpellChecker when turning continuous spell checking on, but we don't need to do that here
3741     // because grammar checking only occurs on code paths that already preflight spell checking appropriately.
3742     
3743     BOOL grammarEnabled;
3744     if (SUCCEEDED(isGrammarCheckingEnabled(&grammarEnabled)) && !grammarEnabled)
3745         m_mainFrame->unmarkAllBadGrammar();
3746
3747     return S_OK;
3748 }
3749
3750 // IWebViewUndoableEditing -----------------------------------------------------
3751
3752 HRESULT STDMETHODCALLTYPE WebView::replaceSelectionWithNode( 
3753         /* [in] */ IDOMNode* /*node*/)
3754 {
3755     ASSERT_NOT_REACHED();
3756     return E_NOTIMPL;
3757 }
3758     
3759 HRESULT STDMETHODCALLTYPE WebView::replaceSelectionWithText( 
3760         /* [in] */ BSTR text)
3761 {
3762     String textString(text, ::SysStringLen(text));
3763     Position start = m_page->mainFrame()->selection()->selection().start();
3764     m_page->focusController()->focusedOrMainFrame()->editor()->insertText(textString, 0);
3765     m_page->mainFrame()->selection()->setBase(start);
3766     return S_OK;
3767 }
3768     
3769 HRESULT STDMETHODCALLTYPE WebView::replaceSelectionWithMarkupString( 
3770         /* [in] */ BSTR /*markupString*/)
3771 {
3772     ASSERT_NOT_REACHED();
3773     return E_NOTIMPL;
3774 }
3775     
3776 HRESULT STDMETHODCALLTYPE WebView::replaceSelectionWithArchive( 
3777         /* [in] */ IWebArchive* /*archive*/)
3778 {
3779     ASSERT_NOT_REACHED();
3780     return E_NOTIMPL;
3781 }
3782     
3783 HRESULT STDMETHODCALLTYPE WebView::deleteSelection( void)
3784 {
3785     Editor* editor = m_page->focusController()->focusedOrMainFrame()->editor();
3786     editor->deleteSelectionWithSmartDelete(editor->canSmartCopyOrDelete());
3787     return S_OK;
3788 }
3789
3790 HRESULT STDMETHODCALLTYPE WebView::clearSelection( void)
3791 {
3792     m_page->focusController()->focusedOrMainFrame()->selection()->clear();
3793     return S_OK;
3794 }
3795     
3796 HRESULT STDMETHODCALLTYPE WebView::applyStyle( 
3797         /* [in] */ IDOMCSSStyleDeclaration* /*style*/)
3798 {
3799     ASSERT_NOT_REACHED();
3800     return E_NOTIMPL;
3801 }
3802
3803 // IWebViewEditingActions ------------------------------------------------------
3804
3805 HRESULT STDMETHODCALLTYPE WebView::copy( 
3806         /* [in] */ IUnknown* /*sender*/)
3807 {
3808     m_page->focusController()->focusedOrMainFrame()->editor()->command("Copy").execute();
3809     return S_OK;
3810 }
3811
3812 HRESULT STDMETHODCALLTYPE WebView::cut( 
3813         /* [in] */ IUnknown* /*sender*/)
3814 {
3815     m_page->focusController()->focusedOrMainFrame()->editor()->command("Cut").execute();
3816     return S_OK;
3817 }
3818
3819 HRESULT STDMETHODCALLTYPE WebView::paste( 
3820         /* [in] */ IUnknown* /*sender*/)
3821 {
3822     m_page->focusController()->focusedOrMainFrame()->editor()->command("Paste").execute();
3823     return S_OK;
3824 }
3825
3826 HRESULT STDMETHODCALLTYPE WebView::copyURL( 
3827         /* [in] */ BSTR url)