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