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