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