1/*
2 * Copyright (C) 2006, 2007, 2008, 2009, 2010 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 "WebView.h"
28
29#include "CFDictionaryPropertyBag.h"
30#include "DOMCoreClasses.h"
31#include "FullscreenVideoController.h"
32#include "MarshallingHelpers.h"
33#include "SoftLinking.h"
34#include "WebBackForwardList.h"
35#include "WebChromeClient.h"
36#include "WebContextMenuClient.h"
37#include "WebCoreTextRenderer.h"
38#include "WebDatabaseManager.h"
39#include "WebDocumentLoader.h"
40#include "WebDownload.h"
41#include "WebDragClient.h"
42#include "WebEditorClient.h"
43#include "WebElementPropertyBag.h"
44#include "WebFrame.h"
45#include "WebGeolocationClient.h"
46#include "WebGeolocationPosition.h"
47#include "WebIconDatabase.h"
48#include "WebInspector.h"
49#include "WebInspectorClient.h"
50#include "WebKit.h"
51#include "WebKitDLL.h"
52#include "WebKitLogging.h"
53#include "WebKitStatisticsPrivate.h"
54#include "WebKitSystemBits.h"
55#include "WebMutableURLRequest.h"
56#include "WebNotificationCenter.h"
57#include "WebPlatformStrategies.h"
58#include "WebPluginHalterClient.h"
59#include "WebPreferences.h"
60#include "WebScriptWorld.h"
61#include "resource.h"
62#include <JavaScriptCore/APICast.h>
63#include <JavaScriptCore/InitializeThreading.h>
64#include <JavaScriptCore/JSLock.h>
65#include <JavaScriptCore/JSValue.h>
66#include <WebCore/AbstractDatabase.h>
67#include <WebCore/AXObjectCache.h>
68#include <WebCore/ApplicationCacheStorage.h>
69#include <WebCore/BString.h>
70#include <WebCore/BackForwardListImpl.h>
71#include <WebCore/BitmapInfo.h>
72#include <WebCore/MemoryCache.h>
73#include <WebCore/Chrome.h>
74#include <WebCore/ContextMenu.h>
75#include <WebCore/ContextMenuController.h>
76#include <WebCore/Cursor.h>
77#include <WebCore/Document.h>
78#include <WebCore/DocumentMarkerController.h>
79#include <WebCore/DragController.h>
80#include <WebCore/DragData.h>
81#include <WebCore/Editor.h>
82#include <WebCore/EventHandler.h>
83#include <WebCore/EventNames.h>
84#include <WebCore/FileSystem.h>
85#include <WebCore/FloatQuad.h>
86#include <WebCore/FocusController.h>
87#include <WebCore/FrameLoader.h>
88#include <WebCore/FrameTree.h>
89#include <WebCore/FrameView.h>
90#include <WebCore/FrameWin.h>
91#include <WebCore/GDIObjectCounter.h>
92#include <WebCore/GraphicsContext.h>
93#include <WebCore/HTMLMediaElement.h>
94#include <WebCore/HTMLNames.h>
95#include <WebCore/HistoryItem.h>
96#include <WebCore/HitTestRequest.h>
97#include <WebCore/HitTestResult.h>
98#include <WebCore/IntRect.h>
99#include <WebCore/JSElement.h>
100#include <WebCore/KeyboardEvent.h>
101#include <WebCore/Logging.h>
102#include <WebCore/MIMETypeRegistry.h>
103#include <WebCore/Page.h>
104#include <WebCore/PageCache.h>
105#include <WebCore/PageGroup.h>
106#include <WebCore/PlatformKeyboardEvent.h>
107#include <WebCore/PlatformMouseEvent.h>
108#include <WebCore/PlatformWheelEvent.h>
109#include <WebCore/PluginData.h>
110#include <WebCore/PluginDatabase.h>
111#include <WebCore/PluginView.h>
112#include <WebCore/PopupMenu.h>
113#include <WebCore/PopupMenuWin.h>
114#include <WebCore/ProgressTracker.h>
115#include <WebCore/RenderLayer.h>
116#include <WebCore/RenderTheme.h>
117#include <WebCore/RenderTreeAsText.h>
118#include <WebCore/RenderView.h>
119#include <WebCore/RenderWidget.h>
120#include <WebCore/ResourceHandle.h>
121#include <WebCore/ResourceHandleClient.h>
122#include <WebCore/SchemeRegistry.h>
123#include <WebCore/ScriptValue.h>
124#include <WebCore/Scrollbar.h>
125#include <WebCore/ScrollbarTheme.h>
126#include <WebCore/SecurityOrigin.h>
127#include <WebCore/SelectionController.h>
128#include <WebCore/Settings.h>
129#include <WebCore/SimpleFontData.h>
130#include <WebCore/SystemInfo.h>
131#include <WebCore/TypingCommand.h>
132#include <WebCore/WindowMessageBroadcaster.h>
133#include <WebCore/WindowsTouch.h>
134#include <wtf/Threading.h>
135
136#if ENABLE(CLIENT_BASED_GEOLOCATION)
137#include <WebCore/GeolocationController.h>
138#include <WebCore/GeolocationError.h>
139#endif
140
141#if USE(CG)
142#include <CoreGraphics/CGContext.h>
143#endif
144
145#if USE(CF)
146#include <CoreFoundation/CoreFoundation.h>
147#endif
148
149#if USE(CFNETWORK)
150#include <CFNetwork/CFURLCachePriv.h>
151#include <CFNetwork/CFURLProtocolPriv.h>
152#include <WebCore/CookieStorageCFNet.h>
153#include <WebKitSystemInterface/WebKitSystemInterface.h>
154#endif
155
156#if USE(ACCELERATED_COMPOSITING)
157#include <WebCore/CACFLayerTreeHost.h>
158#include <WebCore/PlatformCALayer.h>
159#endif
160
161#include <ShlObj.h>
162#include <comutil.h>
163#include <dimm.h>
164#include <oleacc.h>
165#include <wchar.h>
166#include <windowsx.h>
167#include <wtf/HashSet.h>
168#include <wtf/text/CString.h>
169#include <wtf/text/StringConcatenate.h>
170
171// Soft link functions for gestures and panning feedback
172SOFT_LINK_LIBRARY(USER32);
173SOFT_LINK_OPTIONAL(USER32, GetGestureInfo, BOOL, WINAPI, (HGESTUREINFO, PGESTUREINFO));
174SOFT_LINK_OPTIONAL(USER32, SetGestureConfig, BOOL, WINAPI, (HWND, DWORD, UINT, PGESTURECONFIG, UINT));
175SOFT_LINK_OPTIONAL(USER32, CloseGestureInfoHandle, BOOL, WINAPI, (HGESTUREINFO));
176SOFT_LINK_LIBRARY(Uxtheme);
177SOFT_LINK_OPTIONAL(Uxtheme, BeginPanningFeedback, BOOL, WINAPI, (HWND));
178SOFT_LINK_OPTIONAL(Uxtheme, EndPanningFeedback, BOOL, WINAPI, (HWND, BOOL));
179SOFT_LINK_OPTIONAL(Uxtheme, UpdatePanningFeedback, BOOL, WINAPI, (HWND, LONG, LONG, BOOL));
180
181using namespace WebCore;
182using namespace std;
183using JSC::JSLock;
184
185static HMODULE accessibilityLib;
186static HashSet<WebView*> pendingDeleteBackingStoreSet;
187
188static String webKitVersionString();
189
190WebView* kit(Page* page)
191{
192    return page ? static_cast<WebChromeClient*>(page->chrome()->client())->webView() : 0;
193}
194
195class PreferencesChangedOrRemovedObserver : public IWebNotificationObserver {
196public:
197    static PreferencesChangedOrRemovedObserver* sharedInstance();
198
199private:
200    PreferencesChangedOrRemovedObserver() {}
201    ~PreferencesChangedOrRemovedObserver() {}
202
203    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, void**) { return E_FAIL; }
204    virtual ULONG STDMETHODCALLTYPE AddRef(void) { return 0; }
205    virtual ULONG STDMETHODCALLTYPE Release(void) { return 0; }
206
207public:
208    // IWebNotificationObserver
209    virtual HRESULT STDMETHODCALLTYPE onNotify(
210        /* [in] */ IWebNotification* notification);
211
212private:
213    HRESULT notifyPreferencesChanged(WebCacheModel);
214    HRESULT notifyPreferencesRemoved(WebCacheModel);
215};
216
217PreferencesChangedOrRemovedObserver* PreferencesChangedOrRemovedObserver::sharedInstance()
218{
219    static PreferencesChangedOrRemovedObserver* shared = new PreferencesChangedOrRemovedObserver;
220    return shared;
221}
222
223HRESULT PreferencesChangedOrRemovedObserver::onNotify(IWebNotification* notification)
224{
225    HRESULT hr = S_OK;
226
227    COMPtr<IUnknown> unkPrefs;
228    hr = notification->getObject(&unkPrefs);
229    if (FAILED(hr))
230        return hr;
231
232    COMPtr<IWebPreferences> preferences(Query, unkPrefs);
233    if (!preferences)
234        return E_NOINTERFACE;
235
236    WebCacheModel cacheModel;
237    hr = preferences->cacheModel(&cacheModel);
238    if (FAILED(hr))
239        return hr;
240
241    BSTR nameBSTR;
242    hr = notification->name(&nameBSTR);
243    if (FAILED(hr))
244        return hr;
245    BString name;
246    name.adoptBSTR(nameBSTR);
247
248    if (wcscmp(name, WebPreferences::webPreferencesChangedNotification()) == 0)
249        return notifyPreferencesChanged(cacheModel);
250
251    if (wcscmp(name, WebPreferences::webPreferencesRemovedNotification()) == 0)
252        return notifyPreferencesRemoved(cacheModel);
253
254    ASSERT_NOT_REACHED();
255    return E_FAIL;
256}
257
258HRESULT PreferencesChangedOrRemovedObserver::notifyPreferencesChanged(WebCacheModel cacheModel)
259{
260    HRESULT hr = S_OK;
261
262    if (!WebView::didSetCacheModel() || cacheModel > WebView::cacheModel())
263        WebView::setCacheModel(cacheModel);
264    else if (cacheModel < WebView::cacheModel()) {
265        WebCacheModel sharedPreferencesCacheModel;
266        hr = WebPreferences::sharedStandardPreferences()->cacheModel(&sharedPreferencesCacheModel);
267        if (FAILED(hr))
268            return hr;
269        WebView::setCacheModel(max(sharedPreferencesCacheModel, WebView::maxCacheModelInAnyInstance()));
270    }
271
272    return hr;
273}
274
275HRESULT PreferencesChangedOrRemovedObserver::notifyPreferencesRemoved(WebCacheModel cacheModel)
276{
277    HRESULT hr = S_OK;
278
279    if (cacheModel == WebView::cacheModel()) {
280        WebCacheModel sharedPreferencesCacheModel;
281        hr = WebPreferences::sharedStandardPreferences()->cacheModel(&sharedPreferencesCacheModel);
282        if (FAILED(hr))
283            return hr;
284        WebView::setCacheModel(max(sharedPreferencesCacheModel, WebView::maxCacheModelInAnyInstance()));
285    }
286
287    return hr;
288}
289
290
291const LPCWSTR kWebViewWindowClassName = L"WebViewWindowClass";
292
293const int WM_XP_THEMECHANGED = 0x031A;
294const int WM_VISTA_MOUSEHWHEEL = 0x020E;
295
296static const int maxToolTipWidth = 250;
297
298static const int delayBeforeDeletingBackingStoreMsec = 5000;
299
300static ATOM registerWebView();
301
302static void initializeStaticObservers();
303
304static HRESULT updateSharedSettingsFromPreferencesIfNeeded(IWebPreferences*);
305
306HRESULT createMatchEnumerator(Vector<IntRect>* rects, IEnumTextMatches** matches);
307
308static bool continuousSpellCheckingEnabled;
309static bool grammarCheckingEnabled;
310
311static bool s_didSetCacheModel;
312static WebCacheModel s_cacheModel = WebCacheModelDocumentViewer;
313
314enum {
315    UpdateActiveStateTimer = 1,
316    DeleteBackingStoreTimer = 2,
317};
318
319// WebView ----------------------------------------------------------------
320
321bool WebView::s_allowSiteSpecificHacks = false;
322
323WebView::WebView()
324    : m_refCount(0)
325#if !ASSERT_DISABLED
326    , m_deletionHasBegun(false)
327#endif
328    , m_hostWindow(0)
329    , m_viewWindow(0)
330    , m_mainFrame(0)
331    , m_page(0)
332    , m_hasCustomDropTarget(false)
333    , m_useBackForwardList(true)
334    , m_userAgentOverridden(false)
335    , m_zoomMultiplier(1.0f)
336    , m_zoomsTextOnly(false)
337    , m_mouseActivated(false)
338    , m_dragData(0)
339    , m_currentCharacterCode(0)
340    , m_isBeingDestroyed(false)
341    , m_paintCount(0)
342    , m_hasSpellCheckerDocumentTag(false)
343    , m_smartInsertDeleteEnabled(false)
344    , m_didClose(false)
345    , m_inIMEComposition(0)
346    , m_toolTipHwnd(0)
347    , m_closeWindowTimer(0)
348    , m_topLevelParent(0)
349    , m_deleteBackingStoreTimerActive(false)
350    , m_transparent(false)
351    , m_selectTrailingWhitespaceEnabled(false)
352    , m_lastPanX(0)
353    , m_lastPanY(0)
354    , m_xOverpan(0)
355    , m_yOverpan(0)
356#if USE(ACCELERATED_COMPOSITING)
357    , m_isAcceleratedCompositing(false)
358#endif
359    , m_nextDisplayIsSynchronous(false)
360    , m_lastSetCursor(0)
361{
362    JSC::initializeThreading();
363    WTF::initializeMainThread();
364
365    m_backingStoreSize.cx = m_backingStoreSize.cy = 0;
366
367    CoCreateInstance(CLSID_DragDropHelper, 0, CLSCTX_INPROC_SERVER, IID_IDropTargetHelper,(void**)&m_dropTargetHelper);
368
369    initializeStaticObservers();
370
371    WebPreferences* sharedPreferences = WebPreferences::sharedStandardPreferences();
372    BOOL enabled;
373    if (SUCCEEDED(sharedPreferences->continuousSpellCheckingEnabled(&enabled)))
374        continuousSpellCheckingEnabled = !!enabled;
375    if (SUCCEEDED(sharedPreferences->grammarCheckingEnabled(&enabled)))
376        grammarCheckingEnabled = !!enabled;
377
378    WebViewCount++;
379    gClassCount++;
380    gClassNameCount.add("WebView");
381}
382
383WebView::~WebView()
384{
385    deleteBackingStore();
386
387    // the tooltip window needs to be explicitly destroyed since it isn't a WS_CHILD
388    if (::IsWindow(m_toolTipHwnd))
389        ::DestroyWindow(m_toolTipHwnd);
390
391    ASSERT(!m_page);
392    ASSERT(!m_preferences);
393    ASSERT(!m_viewWindow);
394
395#if USE(ACCELERATED_COMPOSITING)
396    ASSERT(!m_layerTreeHost);
397    ASSERT(!m_backingLayer);
398#endif
399
400    WebViewCount--;
401    gClassCount--;
402    gClassNameCount.remove("WebView");
403}
404
405WebView* WebView::createInstance()
406{
407    WebView* instance = new WebView();
408    instance->AddRef();
409    return instance;
410}
411
412void initializeStaticObservers()
413{
414    static bool initialized;
415    if (initialized)
416        return;
417    initialized = true;
418
419    IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal();
420    notifyCenter->addObserver(PreferencesChangedOrRemovedObserver::sharedInstance(), WebPreferences::webPreferencesChangedNotification(), 0);
421    notifyCenter->addObserver(PreferencesChangedOrRemovedObserver::sharedInstance(), WebPreferences::webPreferencesRemovedNotification(), 0);
422}
423
424static HashSet<WebView*>& allWebViewsSet()
425{
426    static HashSet<WebView*> allWebViewsSet;
427    return allWebViewsSet;
428}
429
430void WebView::addToAllWebViewsSet()
431{
432    allWebViewsSet().add(this);
433}
434
435void WebView::removeFromAllWebViewsSet()
436{
437    allWebViewsSet().remove(this);
438}
439
440void WebView::setCacheModel(WebCacheModel cacheModel)
441{
442#if USE(CFNETWORK)
443    if (s_didSetCacheModel && cacheModel == s_cacheModel)
444        return;
445
446    RetainPtr<CFURLCacheRef> cfurlCache(AdoptCF, CFURLCacheCopySharedURLCache());
447    RetainPtr<CFStringRef> cfurlCacheDirectory(AdoptCF, wkCopyFoundationCacheDirectory());
448    if (!cfurlCacheDirectory)
449        cfurlCacheDirectory.adoptCF(WebCore::localUserSpecificStorageDirectory().createCFString());
450
451    // As a fudge factor, use 1000 instead of 1024, in case the reported byte
452    // count doesn't align exactly to a megabyte boundary.
453    unsigned long long memSize = WebMemorySize() / 1024 / 1000;
454    unsigned long long diskFreeSize = WebVolumeFreeSize(cfurlCacheDirectory.get()) / 1024 / 1000;
455
456    unsigned cacheTotalCapacity = 0;
457    unsigned cacheMinDeadCapacity = 0;
458    unsigned cacheMaxDeadCapacity = 0;
459    double deadDecodedDataDeletionInterval = 0;
460
461    unsigned pageCacheCapacity = 0;
462
463    CFIndex cfurlCacheMemoryCapacity = 0;
464    CFIndex cfurlCacheDiskCapacity = 0;
465
466    switch (cacheModel) {
467    case WebCacheModelDocumentViewer: {
468        // Page cache capacity (in pages)
469        pageCacheCapacity = 0;
470
471        // Object cache capacities (in bytes)
472        if (memSize >= 2048)
473            cacheTotalCapacity = 96 * 1024 * 1024;
474        else if (memSize >= 1536)
475            cacheTotalCapacity = 64 * 1024 * 1024;
476        else if (memSize >= 1024)
477            cacheTotalCapacity = 32 * 1024 * 1024;
478        else if (memSize >= 512)
479            cacheTotalCapacity = 16 * 1024 * 1024;
480
481        cacheMinDeadCapacity = 0;
482        cacheMaxDeadCapacity = 0;
483
484        // Foundation memory cache capacity (in bytes)
485        cfurlCacheMemoryCapacity = 0;
486
487        // Foundation disk cache capacity (in bytes)
488        cfurlCacheDiskCapacity = CFURLCacheDiskCapacity(cfurlCache.get());
489
490        break;
491    }
492    case WebCacheModelDocumentBrowser: {
493        // Page cache capacity (in pages)
494        if (memSize >= 1024)
495            pageCacheCapacity = 3;
496        else if (memSize >= 512)
497            pageCacheCapacity = 2;
498        else if (memSize >= 256)
499            pageCacheCapacity = 1;
500        else
501            pageCacheCapacity = 0;
502
503        // Object cache capacities (in bytes)
504        if (memSize >= 2048)
505            cacheTotalCapacity = 96 * 1024 * 1024;
506        else if (memSize >= 1536)
507            cacheTotalCapacity = 64 * 1024 * 1024;
508        else if (memSize >= 1024)
509            cacheTotalCapacity = 32 * 1024 * 1024;
510        else if (memSize >= 512)
511            cacheTotalCapacity = 16 * 1024 * 1024;
512
513        cacheMinDeadCapacity = cacheTotalCapacity / 8;
514        cacheMaxDeadCapacity = cacheTotalCapacity / 4;
515
516        // Foundation memory cache capacity (in bytes)
517        if (memSize >= 2048)
518            cfurlCacheMemoryCapacity = 4 * 1024 * 1024;
519        else if (memSize >= 1024)
520            cfurlCacheMemoryCapacity = 2 * 1024 * 1024;
521        else if (memSize >= 512)
522            cfurlCacheMemoryCapacity = 1 * 1024 * 1024;
523        else
524            cfurlCacheMemoryCapacity =      512 * 1024;
525
526        // Foundation disk cache capacity (in bytes)
527        if (diskFreeSize >= 16384)
528            cfurlCacheDiskCapacity = 50 * 1024 * 1024;
529        else if (diskFreeSize >= 8192)
530            cfurlCacheDiskCapacity = 40 * 1024 * 1024;
531        else if (diskFreeSize >= 4096)
532            cfurlCacheDiskCapacity = 30 * 1024 * 1024;
533        else
534            cfurlCacheDiskCapacity = 20 * 1024 * 1024;
535
536        break;
537    }
538    case WebCacheModelPrimaryWebBrowser: {
539        // Page cache capacity (in pages)
540        // (Research indicates that value / page drops substantially after 3 pages.)
541        if (memSize >= 2048)
542            pageCacheCapacity = 5;
543        else if (memSize >= 1024)
544            pageCacheCapacity = 4;
545        else if (memSize >= 512)
546            pageCacheCapacity = 3;
547        else if (memSize >= 256)
548            pageCacheCapacity = 2;
549        else
550            pageCacheCapacity = 1;
551
552        // Object cache capacities (in bytes)
553        // (Testing indicates that value / MB depends heavily on content and
554        // browsing pattern. Even growth above 128MB can have substantial
555        // value / MB for some content / browsing patterns.)
556        if (memSize >= 2048)
557            cacheTotalCapacity = 128 * 1024 * 1024;
558        else if (memSize >= 1536)
559            cacheTotalCapacity = 96 * 1024 * 1024;
560        else if (memSize >= 1024)
561            cacheTotalCapacity = 64 * 1024 * 1024;
562        else if (memSize >= 512)
563            cacheTotalCapacity = 32 * 1024 * 1024;
564
565        cacheMinDeadCapacity = cacheTotalCapacity / 4;
566        cacheMaxDeadCapacity = cacheTotalCapacity / 2;
567
568        // This code is here to avoid a PLT regression. We can remove it if we
569        // can prove that the overall system gain would justify the regression.
570        cacheMaxDeadCapacity = max(24u, cacheMaxDeadCapacity);
571
572        deadDecodedDataDeletionInterval = 60;
573
574        // Foundation memory cache capacity (in bytes)
575        // (These values are small because WebCore does most caching itself.)
576        if (memSize >= 1024)
577            cfurlCacheMemoryCapacity = 4 * 1024 * 1024;
578        else if (memSize >= 512)
579            cfurlCacheMemoryCapacity = 2 * 1024 * 1024;
580        else if (memSize >= 256)
581            cfurlCacheMemoryCapacity = 1 * 1024 * 1024;
582        else
583            cfurlCacheMemoryCapacity =      512 * 1024;
584
585        // Foundation disk cache capacity (in bytes)
586        if (diskFreeSize >= 16384)
587            cfurlCacheDiskCapacity = 175 * 1024 * 1024;
588        else if (diskFreeSize >= 8192)
589            cfurlCacheDiskCapacity = 150 * 1024 * 1024;
590        else if (diskFreeSize >= 4096)
591            cfurlCacheDiskCapacity = 125 * 1024 * 1024;
592        else if (diskFreeSize >= 2048)
593            cfurlCacheDiskCapacity = 100 * 1024 * 1024;
594        else if (diskFreeSize >= 1024)
595            cfurlCacheDiskCapacity = 75 * 1024 * 1024;
596        else
597            cfurlCacheDiskCapacity = 50 * 1024 * 1024;
598
599        break;
600    }
601    default:
602        ASSERT_NOT_REACHED();
603    }
604
605    // Don't shrink a big disk cache, since that would cause churn.
606    cfurlCacheDiskCapacity = max(cfurlCacheDiskCapacity, CFURLCacheDiskCapacity(cfurlCache.get()));
607
608    memoryCache()->setCapacities(cacheMinDeadCapacity, cacheMaxDeadCapacity, cacheTotalCapacity);
609    memoryCache()->setDeadDecodedDataDeletionInterval(deadDecodedDataDeletionInterval);
610    pageCache()->setCapacity(pageCacheCapacity);
611
612    CFURLCacheSetMemoryCapacity(cfurlCache.get(), cfurlCacheMemoryCapacity);
613    CFURLCacheSetDiskCapacity(cfurlCache.get(), cfurlCacheDiskCapacity);
614
615    s_didSetCacheModel = true;
616    s_cacheModel = cacheModel;
617    return;
618#endif
619}
620
621WebCacheModel WebView::cacheModel()
622{
623    return s_cacheModel;
624}
625
626bool WebView::didSetCacheModel()
627{
628    return s_didSetCacheModel;
629}
630
631WebCacheModel WebView::maxCacheModelInAnyInstance()
632{
633    WebCacheModel cacheModel = WebCacheModelDocumentViewer;
634
635    HashSet<WebView*>::iterator end = allWebViewsSet().end();
636    for (HashSet<WebView*>::iterator it = allWebViewsSet().begin(); it != end; ++it) {
637        COMPtr<IWebPreferences> pref;
638        if (FAILED((*it)->preferences(&pref)))
639            continue;
640        WebCacheModel prefCacheModel = WebCacheModelDocumentViewer;
641        if (FAILED(pref->cacheModel(&prefCacheModel)))
642            continue;
643
644        cacheModel = max(cacheModel, prefCacheModel);
645    }
646
647    return cacheModel;
648}
649
650HRESULT STDMETHODCALLTYPE WebView::close()
651{
652    if (m_didClose)
653        return S_OK;
654
655    m_didClose = true;
656
657#if USE(ACCELERATED_COMPOSITING)
658    setAcceleratedCompositing(false);
659#endif
660
661    WebNotificationCenter::defaultCenterInternal()->postNotificationName(_bstr_t(WebViewWillCloseNotification).GetBSTR(), static_cast<IWebView*>(this), 0);
662
663    if (m_uiDelegatePrivate)
664        m_uiDelegatePrivate->webViewClosing(this);
665
666    removeFromAllWebViewsSet();
667
668    if (m_page) {
669        if (Frame* frame = m_page->mainFrame())
670            frame->loader()->detachFromParent();
671    }
672
673    if (m_mouseOutTracker) {
674        m_mouseOutTracker->dwFlags = TME_CANCEL;
675        ::TrackMouseEvent(m_mouseOutTracker.get());
676        m_mouseOutTracker.set(0);
677    }
678
679    revokeDragDrop();
680
681    if (m_viewWindow) {
682        // We can't check IsWindow(m_viewWindow) here, because that will return true even while
683        // we're already handling WM_DESTROY. So we check !isBeingDestroyed() instead.
684        if (!isBeingDestroyed())
685            DestroyWindow(m_viewWindow);
686        // Either we just destroyed m_viewWindow, or it's in the process of being destroyed. Either
687        // way, we clear it out to make sure we don't try to use it later.
688        m_viewWindow = 0;
689    }
690
691    setHostWindow(0);
692
693    setDownloadDelegate(0);
694    setEditingDelegate(0);
695    setFrameLoadDelegate(0);
696    setFrameLoadDelegatePrivate(0);
697    setHistoryDelegate(0);
698    setPolicyDelegate(0);
699    setResourceLoadDelegate(0);
700    setUIDelegate(0);
701    setFormDelegate(0);
702    setPluginHalterDelegate(0);
703
704    if (m_webInspector)
705        m_webInspector->webViewClosed();
706
707    delete m_page;
708    m_page = 0;
709
710    registerForIconNotification(false);
711    IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal();
712    notifyCenter->removeObserver(this, WebPreferences::webPreferencesChangedNotification(), static_cast<IWebPreferences*>(m_preferences.get()));
713
714    if (COMPtr<WebPreferences> preferences = m_preferences) {
715        BSTR identifier = 0;
716        preferences->identifier(&identifier);
717
718        m_preferences = 0;
719        preferences->didRemoveFromWebView();
720        // Make sure we release the reference, since WebPreferences::removeReferenceForIdentifier will check for last reference to WebPreferences
721        preferences = 0;
722        if (identifier) {
723            WebPreferences::removeReferenceForIdentifier(identifier);
724            SysFreeString(identifier);
725        }
726    }
727
728    deleteBackingStore();
729    return S_OK;
730}
731
732void WebView::repaint(const WebCore::IntRect& windowRect, bool contentChanged, bool immediate, bool repaintContentOnly)
733{
734#if USE(ACCELERATED_COMPOSITING)
735    if (isAcceleratedCompositing()) {
736        // The contentChanged, immediate, and repaintContentOnly parameters are all based on a non-
737        // compositing painting/scrolling model.
738        addToDirtyRegion(windowRect);
739        return;
740    }
741#endif
742
743    if (!repaintContentOnly) {
744        RECT rect = windowRect;
745        ::InvalidateRect(m_viewWindow, &rect, false);
746    }
747    if (contentChanged)
748        addToDirtyRegion(windowRect);
749    if (immediate) {
750        if (repaintContentOnly)
751            updateBackingStore(core(topLevelFrame())->view());
752        else
753            ::UpdateWindow(m_viewWindow);
754    }
755}
756
757void WebView::deleteBackingStore()
758{
759    pendingDeleteBackingStoreSet.remove(this);
760
761    if (m_deleteBackingStoreTimerActive) {
762        KillTimer(m_viewWindow, DeleteBackingStoreTimer);
763        m_deleteBackingStoreTimerActive = false;
764    }
765    m_backingStoreBitmap.clear();
766    m_backingStoreDirtyRegion.clear();
767    m_backingStoreSize.cx = m_backingStoreSize.cy = 0;
768}
769
770bool WebView::ensureBackingStore()
771{
772    RECT windowRect;
773    ::GetClientRect(m_viewWindow, &windowRect);
774    LONG width = windowRect.right - windowRect.left;
775    LONG height = windowRect.bottom - windowRect.top;
776    if (width > 0 && height > 0 && (width != m_backingStoreSize.cx || height != m_backingStoreSize.cy)) {
777        deleteBackingStore();
778
779        m_backingStoreSize.cx = width;
780        m_backingStoreSize.cy = height;
781        BitmapInfo bitmapInfo = BitmapInfo::createBottomUp(IntSize(m_backingStoreSize));
782
783        void* pixels = NULL;
784        m_backingStoreBitmap = RefCountedHBITMAP::create(::CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0));
785        return true;
786    }
787
788    return false;
789}
790
791void WebView::addToDirtyRegion(const IntRect& dirtyRect)
792{
793    // FIXME: We want an assert here saying that the dirtyRect is inside the clienRect,
794    // but it was being hit during our layout tests, and is being investigated in
795    // http://webkit.org/b/29350.
796
797#if USE(ACCELERATED_COMPOSITING)
798    if (isAcceleratedCompositing()) {
799        m_backingLayer->setNeedsDisplayInRect(dirtyRect);
800        return;
801    }
802#endif
803
804    HRGN newRegion = ::CreateRectRgn(dirtyRect.x(), dirtyRect.y(),
805                                     dirtyRect.maxX(), dirtyRect.maxY());
806    addToDirtyRegion(newRegion);
807}
808
809void WebView::addToDirtyRegion(HRGN newRegion)
810{
811#if USE(ACCELERATED_COMPOSITING)
812    ASSERT(!isAcceleratedCompositing());
813#endif
814
815    LOCAL_GDI_COUNTER(0, __FUNCTION__);
816
817    if (m_backingStoreDirtyRegion) {
818        HRGN combinedRegion = ::CreateRectRgn(0,0,0,0);
819        ::CombineRgn(combinedRegion, m_backingStoreDirtyRegion->handle(), newRegion, RGN_OR);
820        ::DeleteObject(newRegion);
821        m_backingStoreDirtyRegion = RefCountedHRGN::create(combinedRegion);
822    } else
823        m_backingStoreDirtyRegion = RefCountedHRGN::create(newRegion);
824
825    if (m_uiDelegatePrivate)
826        m_uiDelegatePrivate->webViewDidInvalidate(this);
827}
828
829void WebView::scrollBackingStore(FrameView* frameView, int dx, int dy, const IntRect& scrollViewRect, const IntRect& clipRect)
830{
831#if USE(ACCELERATED_COMPOSITING)
832    if (isAcceleratedCompositing()) {
833        // FIXME: We should be doing something smarter here, like moving tiles around and painting
834        // any newly-exposed tiles. <http://webkit.org/b/52714>
835        m_backingLayer->setNeedsDisplayInRect(scrollViewRect);
836        return;
837    }
838#endif
839
840    LOCAL_GDI_COUNTER(0, __FUNCTION__);
841
842    // If there's no backing store we don't need to update it
843    if (!m_backingStoreBitmap) {
844        if (m_uiDelegatePrivate)
845            m_uiDelegatePrivate->webViewScrolled(this);
846
847        return;
848    }
849
850    // Make a region to hold the invalidated scroll area.
851    HRGN updateRegion = ::CreateRectRgn(0, 0, 0, 0);
852
853    // Collect our device context info and select the bitmap to scroll.
854    HDC windowDC = ::GetDC(m_viewWindow);
855    HDC bitmapDC = ::CreateCompatibleDC(windowDC);
856    HGDIOBJ oldBitmap = ::SelectObject(bitmapDC, m_backingStoreBitmap->handle());
857
858    // Scroll the bitmap.
859    RECT scrollRectWin(scrollViewRect);
860    RECT clipRectWin(clipRect);
861    ::ScrollDC(bitmapDC, dx, dy, &scrollRectWin, &clipRectWin, updateRegion, 0);
862    RECT regionBox;
863    ::GetRgnBox(updateRegion, &regionBox);
864
865    // Flush.
866    GdiFlush();
867
868    // Add the dirty region to the backing store's dirty region.
869    addToDirtyRegion(updateRegion);
870
871    if (m_uiDelegatePrivate)
872        m_uiDelegatePrivate->webViewScrolled(this);
873
874    // Update the backing store.
875    updateBackingStore(frameView, bitmapDC, false);
876
877    // Clean up.
878    ::SelectObject(bitmapDC, oldBitmap);
879    ::DeleteDC(bitmapDC);
880    ::ReleaseDC(m_viewWindow, windowDC);
881}
882
883void WebView::sizeChanged(const IntSize& newSize)
884{
885    deleteBackingStore();
886
887    if (Frame* coreFrame = core(topLevelFrame()))
888        coreFrame->view()->resize(newSize);
889
890#if USE(ACCELERATED_COMPOSITING)
891    if (m_layerTreeHost)
892        m_layerTreeHost->resize();
893    if (m_backingLayer) {
894        m_backingLayer->setSize(newSize);
895        m_backingLayer->setNeedsDisplay();
896    }
897#endif
898}
899
900// This emulates the Mac smarts for painting rects intelligently.  This is very
901// important for us, since we double buffer based off dirty rects.
902static void getUpdateRects(HRGN region, const IntRect& dirtyRect, Vector<IntRect>& rects)
903{
904    ASSERT_ARG(region, region);
905
906    const int cRectThreshold = 10;
907    const float cWastedSpaceThreshold = 0.75f;
908
909    rects.clear();
910
911    DWORD regionDataSize = GetRegionData(region, sizeof(RGNDATA), NULL);
912    if (!regionDataSize) {
913        rects.append(dirtyRect);
914        return;
915    }
916
917    Vector<unsigned char> buffer(regionDataSize);
918    RGNDATA* regionData = reinterpret_cast<RGNDATA*>(buffer.data());
919    GetRegionData(region, regionDataSize, regionData);
920    if (regionData->rdh.nCount > cRectThreshold) {
921        rects.append(dirtyRect);
922        return;
923    }
924
925    double singlePixels = 0.0;
926    unsigned i;
927    RECT* rect;
928    for (i = 0, rect = reinterpret_cast<RECT*>(regionData->Buffer); i < regionData->rdh.nCount; i++, rect++)
929        singlePixels += (rect->right - rect->left) * (rect->bottom - rect->top);
930
931    double unionPixels = dirtyRect.width() * dirtyRect.height();
932    double wastedSpace = 1.0 - (singlePixels / unionPixels);
933    if (wastedSpace <= cWastedSpaceThreshold) {
934        rects.append(dirtyRect);
935        return;
936    }
937
938    for (i = 0, rect = reinterpret_cast<RECT*>(regionData->Buffer); i < regionData->rdh.nCount; i++, rect++)
939        rects.append(*rect);
940}
941
942void WebView::updateBackingStore(FrameView* frameView, HDC dc, bool backingStoreCompletelyDirty, WindowsToPaint windowsToPaint)
943{
944#if USE(ACCELERATED_COMPOSITING)
945    ASSERT(!isAcceleratedCompositing());
946#endif
947
948    LOCAL_GDI_COUNTER(0, __FUNCTION__);
949
950    HDC windowDC = 0;
951    HDC bitmapDC = dc;
952    if (!dc) {
953        windowDC = ::GetDC(m_viewWindow);
954        bitmapDC = ::CreateCompatibleDC(windowDC);
955        ::SelectObject(bitmapDC, m_backingStoreBitmap->handle());
956    }
957
958    if (m_backingStoreBitmap && (m_backingStoreDirtyRegion || backingStoreCompletelyDirty)) {
959        // Do a layout first so that everything we render to the backing store is always current.
960        if (Frame* coreFrame = core(m_mainFrame))
961            if (FrameView* view = coreFrame->view())
962                view->updateLayoutAndStyleIfNeededRecursive();
963
964        Vector<IntRect> paintRects;
965        if (!backingStoreCompletelyDirty && m_backingStoreDirtyRegion) {
966            RECT regionBox;
967            ::GetRgnBox(m_backingStoreDirtyRegion->handle(), &regionBox);
968            getUpdateRects(m_backingStoreDirtyRegion->handle(), regionBox, paintRects);
969        } else {
970            RECT clientRect;
971            ::GetClientRect(m_viewWindow, &clientRect);
972            paintRects.append(clientRect);
973        }
974
975        for (unsigned i = 0; i < paintRects.size(); ++i)
976            paintIntoBackingStore(frameView, bitmapDC, paintRects[i], windowsToPaint);
977
978        if (m_uiDelegatePrivate)
979            m_uiDelegatePrivate->webViewPainted(this);
980
981        m_backingStoreDirtyRegion.clear();
982    }
983
984    if (!dc) {
985        ::DeleteDC(bitmapDC);
986        ::ReleaseDC(m_viewWindow, windowDC);
987    }
988
989    GdiFlush();
990}
991
992void WebView::paint(HDC dc, LPARAM options)
993{
994    LOCAL_GDI_COUNTER(0, __FUNCTION__);
995
996#if USE(ACCELERATED_COMPOSITING)
997    if (isAcceleratedCompositing()) {
998        m_layerTreeHost->flushPendingLayerChangesNow();
999        // Flushing might have taken us out of compositing mode.
1000        if (isAcceleratedCompositing()) {
1001            // FIXME: We need to paint into dc (if provided). <http://webkit.org/b/52578>
1002            m_layerTreeHost->paint();
1003            ::ValidateRect(m_viewWindow, 0);
1004            return;
1005        }
1006    }
1007#endif
1008
1009    Frame* coreFrame = core(m_mainFrame);
1010    if (!coreFrame)
1011        return;
1012    FrameView* frameView = coreFrame->view();
1013
1014    RECT rcPaint;
1015    HDC hdc;
1016    OwnPtr<HRGN> region;
1017    int regionType = NULLREGION;
1018    PAINTSTRUCT ps;
1019    WindowsToPaint windowsToPaint;
1020    if (!dc) {
1021        region.set(CreateRectRgn(0,0,0,0));
1022        regionType = GetUpdateRgn(m_viewWindow, region.get(), false);
1023        hdc = BeginPaint(m_viewWindow, &ps);
1024        rcPaint = ps.rcPaint;
1025        // We're painting to the screen, and our child windows can handle
1026        // painting themselves to the screen.
1027        windowsToPaint = PaintWebViewOnly;
1028    } else {
1029        hdc = dc;
1030        ::GetClientRect(m_viewWindow, &rcPaint);
1031        if (options & PRF_ERASEBKGND)
1032            ::FillRect(hdc, &rcPaint, (HBRUSH)GetStockObject(WHITE_BRUSH));
1033        // Since we aren't painting to the screen, we want to paint all our
1034        // children into the HDC.
1035        windowsToPaint = PaintWebViewAndChildren;
1036    }
1037
1038    bool backingStoreCompletelyDirty = ensureBackingStore();
1039    if (!m_backingStoreBitmap) {
1040        if (!dc)
1041            EndPaint(m_viewWindow, &ps);
1042        return;
1043    }
1044
1045    m_paintCount++;
1046
1047    HDC bitmapDC = ::CreateCompatibleDC(hdc);
1048    HGDIOBJ oldBitmap = ::SelectObject(bitmapDC, m_backingStoreBitmap->handle());
1049
1050    // Update our backing store if needed.
1051    updateBackingStore(frameView, bitmapDC, backingStoreCompletelyDirty, windowsToPaint);
1052
1053    // Now we blit the updated backing store
1054    IntRect windowDirtyRect = rcPaint;
1055
1056    // Apply the same heuristic for this update region too.
1057    Vector<IntRect> blitRects;
1058    if (region && regionType == COMPLEXREGION)
1059        getUpdateRects(region.get(), windowDirtyRect, blitRects);
1060    else
1061        blitRects.append(windowDirtyRect);
1062
1063    for (unsigned i = 0; i < blitRects.size(); ++i)
1064        paintIntoWindow(bitmapDC, hdc, blitRects[i]);
1065
1066    ::SelectObject(bitmapDC, oldBitmap);
1067    ::DeleteDC(bitmapDC);
1068
1069    if (!dc)
1070        EndPaint(m_viewWindow, &ps);
1071
1072    m_paintCount--;
1073
1074    if (active())
1075        cancelDeleteBackingStoreSoon();
1076    else
1077        deleteBackingStoreSoon();
1078}
1079
1080void WebView::paintIntoBackingStore(FrameView* frameView, HDC bitmapDC, const IntRect& dirtyRect, WindowsToPaint windowsToPaint)
1081{
1082    // FIXME: This function should never be called in accelerated compositing mode, and we should
1083    // assert as such. But currently it *is* sometimes called, so we can't assert yet. See
1084    // <http://webkit.org/b/58539>.
1085
1086    LOCAL_GDI_COUNTER(0, __FUNCTION__);
1087
1088    // FIXME: We want an assert here saying that the dirtyRect is inside the clienRect,
1089    // but it was being hit during our layout tests, and is being investigated in
1090    // http://webkit.org/b/29350.
1091
1092    RECT rect = dirtyRect;
1093
1094#if FLASH_BACKING_STORE_REDRAW
1095    HDC dc = ::GetDC(m_viewWindow);
1096    OwnPtr<HBRUSH> yellowBrush(CreateSolidBrush(RGB(255, 255, 0)));
1097    FillRect(dc, &rect, yellowBrush.get());
1098    GdiFlush();
1099    Sleep(50);
1100    paintIntoWindow(bitmapDC, dc, dirtyRect);
1101    ::ReleaseDC(m_viewWindow, dc);
1102#endif
1103
1104    GraphicsContext gc(bitmapDC, m_transparent);
1105    gc.setShouldIncludeChildWindows(windowsToPaint == PaintWebViewAndChildren);
1106    gc.save();
1107    if (m_transparent)
1108        gc.clearRect(dirtyRect);
1109    else
1110        FillRect(bitmapDC, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
1111
1112    COMPtr<IWebUIDelegatePrivate2> uiPrivate(Query, m_uiDelegate);
1113    if (uiPrivate)
1114        uiPrivate->drawBackground(this, reinterpret_cast<OLE_HANDLE>(bitmapDC), &rect);
1115
1116    if (frameView && frameView->frame() && frameView->frame()->contentRenderer()) {
1117        gc.clip(dirtyRect);
1118        frameView->paint(&gc, dirtyRect);
1119    }
1120    gc.restore();
1121}
1122
1123void WebView::paintIntoWindow(HDC bitmapDC, HDC windowDC, const IntRect& dirtyRect)
1124{
1125    // FIXME: This function should never be called in accelerated compositing mode, and we should
1126    // assert as such. But currently it *is* sometimes called, so we can't assert yet. See
1127    // <http://webkit.org/b/58539>.
1128
1129    LOCAL_GDI_COUNTER(0, __FUNCTION__);
1130#if FLASH_WINDOW_REDRAW
1131    OwnPtr<HBRUSH> greenBrush = CreateSolidBrush(RGB(0, 255, 0));
1132    RECT rect = dirtyRect;
1133    FillRect(windowDC, &rect, greenBrush.get());
1134    GdiFlush();
1135    Sleep(50);
1136#endif
1137
1138    // Blit the dirty rect from the backing store into the same position
1139    // in the destination DC.
1140    BitBlt(windowDC, dirtyRect.x(), dirtyRect.y(), dirtyRect.width(), dirtyRect.height(), bitmapDC,
1141           dirtyRect.x(), dirtyRect.y(), SRCCOPY);
1142}
1143
1144void WebView::frameRect(RECT* rect)
1145{
1146    ::GetWindowRect(m_viewWindow, rect);
1147}
1148
1149class WindowCloseTimer : public WebCore::SuspendableTimer {
1150public:
1151    static WindowCloseTimer* create(WebView*);
1152
1153private:
1154    WindowCloseTimer(ScriptExecutionContext*, WebView*);
1155    virtual void contextDestroyed();
1156    virtual void fired();
1157
1158    WebView* m_webView;
1159};
1160
1161WindowCloseTimer* WindowCloseTimer::create(WebView* webView)
1162{
1163    ASSERT_ARG(webView, webView);
1164    Frame* frame = core(webView->topLevelFrame());
1165    ASSERT(frame);
1166    if (!frame)
1167        return 0;
1168
1169    Document* document = frame->document();
1170    ASSERT(document);
1171    if (!document)
1172        return 0;
1173
1174    return new WindowCloseTimer(document, webView);
1175}
1176
1177WindowCloseTimer::WindowCloseTimer(ScriptExecutionContext* context, WebView* webView)
1178    : SuspendableTimer(context)
1179    , m_webView(webView)
1180{
1181    ASSERT_ARG(context, context);
1182    ASSERT_ARG(webView, webView);
1183}
1184
1185void WindowCloseTimer::contextDestroyed()
1186{
1187    SuspendableTimer::contextDestroyed();
1188    delete this;
1189}
1190
1191void WindowCloseTimer::fired()
1192{
1193    m_webView->closeWindowTimerFired();
1194}
1195
1196void WebView::closeWindowSoon()
1197{
1198    if (m_closeWindowTimer)
1199        return;
1200
1201    m_closeWindowTimer = WindowCloseTimer::create(this);
1202    if (!m_closeWindowTimer)
1203        return;
1204    m_closeWindowTimer->startOneShot(0);
1205
1206    AddRef();
1207}
1208
1209void WebView::closeWindowTimerFired()
1210{
1211    closeWindow();
1212    Release();
1213}
1214
1215void WebView::closeWindow()
1216{
1217    if (m_hasSpellCheckerDocumentTag) {
1218        if (m_editingDelegate)
1219            m_editingDelegate->closeSpellDocument(this);
1220        m_hasSpellCheckerDocumentTag = false;
1221    }
1222
1223    COMPtr<IWebUIDelegate> ui;
1224    if (SUCCEEDED(uiDelegate(&ui)))
1225        ui->webViewClose(this);
1226}
1227
1228bool WebView::canHandleRequest(const WebCore::ResourceRequest& request)
1229{
1230    // On the mac there's an about url protocol implementation but CFNetwork doesn't have that.
1231    if (equalIgnoringCase(String(request.url().protocol()), "about"))
1232        return true;
1233
1234#if USE(CFNETWORK)
1235    if (CFURLProtocolCanHandleRequest(request.cfURLRequest()))
1236        return true;
1237
1238    // FIXME: Mac WebKit calls _representationExistsForURLScheme here
1239    return false;
1240#else
1241    return true;
1242#endif
1243}
1244
1245String WebView::standardUserAgentWithApplicationName(const String& applicationName)
1246{
1247    DEFINE_STATIC_LOCAL(String, osVersion, (windowsVersionForUAString()));
1248    DEFINE_STATIC_LOCAL(String, webKitVersion, (webKitVersionString()));
1249
1250    return makeString("Mozilla/5.0 (", osVersion, ") AppleWebKit/", webKitVersion, " (KHTML, like Gecko)", applicationName.isEmpty() ? "" : " ", applicationName);
1251}
1252
1253Page* WebView::page()
1254{
1255    return m_page;
1256}
1257
1258bool WebView::handleContextMenuEvent(WPARAM wParam, LPARAM lParam)
1259{
1260    // Translate the screen coordinates into window coordinates
1261    POINT coords = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
1262    if (coords.x == -1 || coords.y == -1) {
1263        // The contextMenuController() holds onto the last context menu that was popped up on the
1264        // page until a new one is created. We need to clear this menu before propagating the event
1265        // through the DOM so that we can detect if we create a new menu for this event, since we
1266        // won't create a new menu if the DOM swallows the event and the defaultEventHandler does
1267        // not run.
1268        m_page->contextMenuController()->clearContextMenu();
1269
1270        Frame* focusedFrame = m_page->focusController()->focusedOrMainFrame();
1271        return focusedFrame->eventHandler()->sendContextMenuEventForKey();
1272
1273    } else {
1274        if (!::ScreenToClient(m_viewWindow, &coords))
1275            return false;
1276    }
1277
1278    lParam = MAKELPARAM(coords.x, coords.y);
1279
1280    m_page->contextMenuController()->clearContextMenu();
1281
1282    IntPoint documentPoint(m_page->mainFrame()->view()->windowToContents(coords));
1283    HitTestResult result = m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(documentPoint, false);
1284    Frame* targetFrame = result.innerNonSharedNode() ? result.innerNonSharedNode()->document()->frame() : m_page->focusController()->focusedOrMainFrame();
1285
1286    targetFrame->view()->setCursor(pointerCursor());
1287    PlatformMouseEvent mouseEvent(m_viewWindow, WM_RBUTTONUP, wParam, lParam);
1288    bool handledEvent = targetFrame->eventHandler()->sendContextMenuEvent(mouseEvent);
1289    if (!handledEvent)
1290        return false;
1291
1292    ContextMenuController* contextMenuController = m_page->contextMenuController();
1293
1294    // Show the menu
1295    ContextMenu* coreMenu = contextMenuController->contextMenu();
1296    if (!coreMenu)
1297        return false;
1298
1299    Node* node = contextMenuController->hitTestResult().innerNonSharedNode();
1300    if (!node)
1301        return false;
1302
1303    Frame* frame = node->document()->frame();
1304    if (!frame)
1305        return false;
1306
1307    FrameView* view = frame->view();
1308    if (!view)
1309        return false;
1310
1311    POINT point(view->contentsToWindow(contextMenuController->hitTestResult().point()));
1312
1313    // Translate the point to screen coordinates
1314    if (!::ClientToScreen(m_viewWindow, &point))
1315        return false;
1316
1317    BOOL hasCustomMenus = false;
1318    if (m_uiDelegate)
1319        m_uiDelegate->hasCustomMenuImplementation(&hasCustomMenus);
1320
1321    if (hasCustomMenus)
1322        m_uiDelegate->trackCustomPopupMenu((IWebView*)this, (OLE_HANDLE)(ULONG64)coreMenu->nativeMenu(), &point);
1323    else {
1324        // Surprisingly, TPM_RIGHTBUTTON means that items are selectable with either the right OR left mouse button
1325        UINT flags = TPM_RIGHTBUTTON | TPM_TOPALIGN | TPM_VERPOSANIMATION | TPM_HORIZONTAL
1326            | TPM_LEFTALIGN | TPM_HORPOSANIMATION;
1327        ::TrackPopupMenuEx(coreMenu->nativeMenu(), flags, point.x, point.y, m_viewWindow, 0);
1328    }
1329
1330    return true;
1331}
1332
1333bool WebView::onMeasureItem(WPARAM /*wParam*/, LPARAM lParam)
1334{
1335    if (!m_uiDelegate)
1336        return false;
1337
1338    BOOL hasCustomMenus = false;
1339    m_uiDelegate->hasCustomMenuImplementation(&hasCustomMenus);
1340    if (!hasCustomMenus)
1341        return false;
1342
1343    m_uiDelegate->measureCustomMenuItem((IWebView*)this, (void*)lParam);
1344    return true;
1345}
1346
1347bool WebView::onDrawItem(WPARAM /*wParam*/, LPARAM lParam)
1348{
1349    if (!m_uiDelegate)
1350        return false;
1351
1352    BOOL hasCustomMenus = false;
1353    m_uiDelegate->hasCustomMenuImplementation(&hasCustomMenus);
1354    if (!hasCustomMenus)
1355        return false;
1356
1357    m_uiDelegate->drawCustomMenuItem((IWebView*)this, (void*)lParam);
1358    return true;
1359}
1360
1361bool WebView::onInitMenuPopup(WPARAM wParam, LPARAM /*lParam*/)
1362{
1363    if (!m_uiDelegate)
1364        return false;
1365
1366    HMENU menu = (HMENU)wParam;
1367    if (!menu)
1368        return false;
1369
1370    BOOL hasCustomMenus = false;
1371    m_uiDelegate->hasCustomMenuImplementation(&hasCustomMenus);
1372    if (!hasCustomMenus)
1373        return false;
1374
1375    m_uiDelegate->addCustomMenuDrawingData((IWebView*)this, (OLE_HANDLE)(ULONG64)menu);
1376    return true;
1377}
1378
1379bool WebView::onUninitMenuPopup(WPARAM wParam, LPARAM /*lParam*/)
1380{
1381    if (!m_uiDelegate)
1382        return false;
1383
1384    HMENU menu = (HMENU)wParam;
1385    if (!menu)
1386        return false;
1387
1388    BOOL hasCustomMenus = false;
1389    m_uiDelegate->hasCustomMenuImplementation(&hasCustomMenus);
1390    if (!hasCustomMenus)
1391        return false;
1392
1393    m_uiDelegate->cleanUpCustomMenuDrawingData((IWebView*)this, (OLE_HANDLE)(ULONG64)menu);
1394    return true;
1395}
1396
1397void WebView::performContextMenuAction(WPARAM wParam, LPARAM lParam, bool byPosition)
1398{
1399    ContextMenu* menu = m_page->contextMenuController()->contextMenu();
1400    ASSERT(menu);
1401
1402    ContextMenuItem* item = byPosition ? menu->itemAtIndex((unsigned)wParam) : menu->itemWithAction((ContextMenuAction)wParam);
1403    if (!item)
1404        return;
1405    m_page->contextMenuController()->contextMenuItemSelected(item);
1406}
1407
1408bool WebView::handleMouseEvent(UINT message, WPARAM wParam, LPARAM lParam)
1409{
1410    static LONG globalClickCount;
1411    static IntPoint globalPrevPoint;
1412    static MouseButton globalPrevButton;
1413    static LONG globalPrevMouseDownTime;
1414
1415    if (message == WM_CANCELMODE) {
1416        m_page->mainFrame()->eventHandler()->lostMouseCapture();
1417        return true;
1418    }
1419
1420    // Create our event.
1421    // On WM_MOUSELEAVE we need to create a mouseout event, so we force the position
1422    // of the event to be at (MINSHORT, MINSHORT).
1423    LPARAM position = (message == WM_MOUSELEAVE) ? ((MINSHORT << 16) | MINSHORT) : lParam;
1424    PlatformMouseEvent mouseEvent(m_viewWindow, message, wParam, position, m_mouseActivated);
1425
1426    setMouseActivated(false);
1427
1428    bool insideThreshold = abs(globalPrevPoint.x() - mouseEvent.pos().x()) < ::GetSystemMetrics(SM_CXDOUBLECLK) &&
1429                           abs(globalPrevPoint.y() - mouseEvent.pos().y()) < ::GetSystemMetrics(SM_CYDOUBLECLK);
1430    LONG messageTime = ::GetMessageTime();
1431
1432    bool handled = false;
1433
1434    if (message == WM_LBUTTONDOWN || message == WM_MBUTTONDOWN || message == WM_RBUTTONDOWN) {
1435        // FIXME: I'm not sure if this is the "right" way to do this
1436        // but without this call, we never become focused since we don't allow
1437        // the default handling of mouse events.
1438        SetFocus(m_viewWindow);
1439
1440        // Always start capturing events when the mouse goes down in our HWND.
1441        ::SetCapture(m_viewWindow);
1442
1443        if (((messageTime - globalPrevMouseDownTime) < (LONG)::GetDoubleClickTime()) &&
1444            insideThreshold &&
1445            mouseEvent.button() == globalPrevButton)
1446            globalClickCount++;
1447        else
1448            // Reset the click count.
1449            globalClickCount = 1;
1450        globalPrevMouseDownTime = messageTime;
1451        globalPrevButton = mouseEvent.button();
1452        globalPrevPoint = mouseEvent.pos();
1453
1454        mouseEvent.setClickCount(globalClickCount);
1455        handled = m_page->mainFrame()->eventHandler()->handleMousePressEvent(mouseEvent);
1456    } else if (message == WM_LBUTTONDBLCLK || message == WM_MBUTTONDBLCLK || message == WM_RBUTTONDBLCLK) {
1457        globalClickCount++;
1458        mouseEvent.setClickCount(globalClickCount);
1459        handled = m_page->mainFrame()->eventHandler()->handleMousePressEvent(mouseEvent);
1460    } else if (message == WM_LBUTTONUP || message == WM_MBUTTONUP || message == WM_RBUTTONUP) {
1461        // Record the global position and the button of the up.
1462        globalPrevButton = mouseEvent.button();
1463        globalPrevPoint = mouseEvent.pos();
1464        mouseEvent.setClickCount(globalClickCount);
1465        m_page->mainFrame()->eventHandler()->handleMouseReleaseEvent(mouseEvent);
1466        ::ReleaseCapture();
1467    } else if (message == WM_MOUSELEAVE && m_mouseOutTracker) {
1468        // Once WM_MOUSELEAVE is fired windows clears this tracker
1469        // so there is no need to disable it ourselves.
1470        m_mouseOutTracker.set(0);
1471        m_page->mainFrame()->eventHandler()->mouseMoved(mouseEvent);
1472        handled = true;
1473    } else if (message == WM_MOUSEMOVE) {
1474        if (!insideThreshold)
1475            globalClickCount = 0;
1476        mouseEvent.setClickCount(globalClickCount);
1477        handled = m_page->mainFrame()->eventHandler()->mouseMoved(mouseEvent);
1478        if (!m_mouseOutTracker) {
1479            m_mouseOutTracker.set(new TRACKMOUSEEVENT);
1480            m_mouseOutTracker->cbSize = sizeof(TRACKMOUSEEVENT);
1481            m_mouseOutTracker->dwFlags = TME_LEAVE;
1482            m_mouseOutTracker->hwndTrack = m_viewWindow;
1483            ::TrackMouseEvent(m_mouseOutTracker.get());
1484        }
1485    }
1486    return handled;
1487}
1488
1489bool WebView::gestureNotify(WPARAM wParam, LPARAM lParam)
1490{
1491    GESTURENOTIFYSTRUCT* gn = reinterpret_cast<GESTURENOTIFYSTRUCT*>(lParam);
1492
1493    Frame* coreFrame = core(m_mainFrame);
1494    if (!coreFrame)
1495        return false;
1496
1497    ScrollView* view = coreFrame->view();
1498    if (!view)
1499        return false;
1500
1501    // If we don't have this function, we shouldn't be receiving this message
1502    ASSERT(SetGestureConfigPtr());
1503
1504    bool hitScrollbar = false;
1505    POINT gestureBeginPoint = {gn->ptsLocation.x, gn->ptsLocation.y};
1506    HitTestRequest request(HitTestRequest::ReadOnly);
1507    for (Frame* childFrame = m_page->mainFrame(); childFrame; childFrame = EventHandler::subframeForTargetNode(m_gestureTargetNode.get())) {
1508        FrameView* frameView = childFrame->view();
1509        if (!frameView)
1510            break;
1511        RenderView* renderView = childFrame->document()->renderView();
1512        if (!renderView)
1513            break;
1514        RenderLayer* layer = renderView->layer();
1515        if (!layer)
1516            break;
1517
1518        HitTestResult result(frameView->screenToContents(gestureBeginPoint));
1519        layer->hitTest(request, result);
1520        m_gestureTargetNode = result.innerNode();
1521
1522        if (!hitScrollbar)
1523            hitScrollbar = result.scrollbar();
1524    }
1525
1526    if (!hitScrollbar) {
1527        // The hit testing above won't detect if we've hit the main frame's vertical scrollbar. Check that manually now.
1528        RECT webViewRect;
1529        GetWindowRect(m_viewWindow, &webViewRect);
1530        hitScrollbar = view->verticalScrollbar() && (gestureBeginPoint.x > (webViewRect.right - view->verticalScrollbar()->theme()->scrollbarThickness()));
1531    }
1532
1533    bool canBeScrolled = false;
1534    if (m_gestureTargetNode) {
1535        for (RenderObject* renderer = m_gestureTargetNode->renderer(); renderer; renderer = renderer->parent()) {
1536            if (renderer->isBox() && toRenderBox(renderer)->canBeScrolledAndHasScrollableArea()) {
1537                canBeScrolled = true;
1538                break;
1539            }
1540        }
1541    }
1542
1543    // We always allow two-fingered panning with inertia and a gutter (which limits movement to one
1544    // direction in most cases).
1545    DWORD dwPanWant = GC_PAN | GC_PAN_WITH_INERTIA | GC_PAN_WITH_GUTTER;
1546    // We never allow single-fingered horizontal panning. That gesture is reserved for creating text
1547    // selections. This matches IE.
1548    DWORD dwPanBlock = GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY;
1549
1550    if (hitScrollbar || !canBeScrolled) {
1551        // The part of the page under the gesture can't be scrolled, or the gesture is on a scrollbar.
1552        // Disallow single-fingered vertical panning in this case, too, so we'll fall back to the default
1553        // behavior (which allows the scrollbar thumb to be dragged, text selections to be made, etc.).
1554        dwPanBlock |= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY;
1555    } else {
1556        // The part of the page the gesture is under can be scrolled, and we're not under a scrollbar.
1557        // Allow single-fingered vertical panning in this case, so the user will be able to pan the page
1558        // with one or two fingers.
1559        dwPanWant |= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY;
1560    }
1561
1562    GESTURECONFIG gc = { GID_PAN, dwPanWant, dwPanBlock };
1563    return SetGestureConfigPtr()(m_viewWindow, 0, 1, &gc, sizeof(GESTURECONFIG));
1564}
1565
1566bool WebView::gesture(WPARAM wParam, LPARAM lParam)
1567{
1568    // We want to bail out if we don't have either of these functions
1569    if (!GetGestureInfoPtr() || !CloseGestureInfoHandlePtr())
1570        return false;
1571
1572    HGESTUREINFO gestureHandle = reinterpret_cast<HGESTUREINFO>(lParam);
1573
1574    GESTUREINFO gi = {0};
1575    gi.cbSize = sizeof(GESTUREINFO);
1576
1577    if (!GetGestureInfoPtr()(gestureHandle, reinterpret_cast<PGESTUREINFO>(&gi)))
1578        return false;
1579
1580    switch (gi.dwID) {
1581    case GID_BEGIN:
1582        m_lastPanX = gi.ptsLocation.x;
1583        m_lastPanY = gi.ptsLocation.y;
1584
1585        break;
1586    case GID_END:
1587        m_gestureTargetNode = 0;
1588        break;
1589    case GID_PAN: {
1590        // Where are the fingers currently?
1591        long currentX = gi.ptsLocation.x;
1592        long currentY = gi.ptsLocation.y;
1593        // How far did we pan in each direction?
1594        long deltaX = currentX - m_lastPanX;
1595        long deltaY = currentY - m_lastPanY;
1596        // Calculate the overpan for window bounce
1597        m_yOverpan -= m_lastPanY - currentY;
1598        m_xOverpan -= m_lastPanX - currentX;
1599        // Update our class variables with updated values
1600        m_lastPanX = currentX;
1601        m_lastPanY = currentY;
1602
1603        Frame* coreFrame = core(m_mainFrame);
1604        if (!coreFrame) {
1605            CloseGestureInfoHandlePtr()(gestureHandle);
1606            return false;
1607        }
1608
1609        if (!m_gestureTargetNode || !m_gestureTargetNode->renderer())
1610            return false;
1611
1612        // We negate here since panning up moves the content up, but moves the scrollbar down.
1613        m_gestureTargetNode->renderer()->enclosingLayer()->scrollByRecursively(-deltaX, -deltaY);
1614
1615        if (!(UpdatePanningFeedbackPtr() && BeginPanningFeedbackPtr() && EndPanningFeedbackPtr())) {
1616            CloseGestureInfoHandlePtr()(gestureHandle);
1617            return true;
1618        }
1619
1620        if (gi.dwFlags & GF_BEGIN) {
1621            BeginPanningFeedbackPtr()(m_viewWindow);
1622            m_yOverpan = 0;
1623        } else if (gi.dwFlags & GF_END) {
1624            EndPanningFeedbackPtr()(m_viewWindow, true);
1625            m_yOverpan = 0;
1626        }
1627
1628        ScrollView* view = coreFrame->view();
1629        if (!view) {
1630            CloseGestureInfoHandlePtr()(gestureHandle);
1631            return true;
1632        }
1633        Scrollbar* vertScrollbar = view->verticalScrollbar();
1634        if (!vertScrollbar) {
1635            CloseGestureInfoHandlePtr()(gestureHandle);
1636            return true;
1637        }
1638
1639        // FIXME: Support Horizontal Window Bounce. <https://webkit.org/b/28500>.
1640        // FIXME: If the user starts panning down after a window bounce has started, the window doesn't bounce back
1641        // until they release their finger. <https://webkit.org/b/28501>.
1642        if (vertScrollbar->currentPos() == 0)
1643            UpdatePanningFeedbackPtr()(m_viewWindow, 0, m_yOverpan, gi.dwFlags & GF_INERTIA);
1644        else if (vertScrollbar->currentPos() >= vertScrollbar->maximum())
1645            UpdatePanningFeedbackPtr()(m_viewWindow, 0, m_yOverpan, gi.dwFlags & GF_INERTIA);
1646
1647        CloseGestureInfoHandlePtr()(gestureHandle);
1648        return true;
1649    }
1650    default:
1651        break;
1652    }
1653
1654    // If we get to this point, the gesture has not been handled. We forward
1655    // the call to DefWindowProc by returning false, and we don't need to
1656    // to call CloseGestureInfoHandle.
1657    // http://msdn.microsoft.com/en-us/library/dd353228(VS.85).aspx
1658    return false;
1659}
1660
1661bool WebView::mouseWheel(WPARAM wParam, LPARAM lParam, bool isMouseHWheel)
1662{
1663    // Ctrl+Mouse wheel doesn't ever go into WebCore.  It is used to
1664    // zoom instead (Mac zooms the whole Desktop, but Windows browsers trigger their
1665    // own local zoom modes for Ctrl+wheel).
1666    if (wParam & MK_CONTROL) {
1667        short delta = short(HIWORD(wParam));
1668        if (delta < 0)
1669            makeTextSmaller(0);
1670        else
1671            makeTextLarger(0);
1672        return true;
1673    }
1674
1675    // FIXME: This doesn't fix https://bugs.webkit.org/show_bug.cgi?id=28217. This only fixes https://bugs.webkit.org/show_bug.cgi?id=28203.
1676    HWND focusedWindow = GetFocus();
1677    if (focusedWindow && focusedWindow != m_viewWindow) {
1678        // Our focus is on a different hwnd, see if it's a PopupMenu and if so, set the focus back on us (which will hide the popup).
1679        WCHAR className[256];
1680
1681        // Make sure truncation won't affect the comparison.
1682        ASSERT(WTF_ARRAY_LENGTH(className) > wcslen(PopupMenuWin::popupClassName()));
1683
1684        if (GetClassNameW(focusedWindow, className, WTF_ARRAY_LENGTH(className)) && !wcscmp(className, PopupMenuWin::popupClassName())) {
1685            // We don't let the WebView scroll here for two reasons - 1) To match Firefox behavior, 2) If we do scroll, we lose the
1686            // focus ring around the select menu.
1687            SetFocus(m_viewWindow);
1688            return true;
1689        }
1690    }
1691
1692    PlatformWheelEvent wheelEvent(m_viewWindow, wParam, lParam, isMouseHWheel);
1693    Frame* coreFrame = core(m_mainFrame);
1694    if (!coreFrame)
1695        return false;
1696
1697    return coreFrame->eventHandler()->handleWheelEvent(wheelEvent);
1698}
1699
1700bool WebView::verticalScroll(WPARAM wParam, LPARAM /*lParam*/)
1701{
1702    ScrollDirection direction;
1703    ScrollGranularity granularity;
1704    switch (LOWORD(wParam)) {
1705    case SB_LINEDOWN:
1706        granularity = ScrollByLine;
1707        direction = ScrollDown;
1708        break;
1709    case SB_LINEUP:
1710        granularity = ScrollByLine;
1711        direction = ScrollUp;
1712        break;
1713    case SB_PAGEDOWN:
1714        granularity = ScrollByDocument;
1715        direction = ScrollDown;
1716        break;
1717    case SB_PAGEUP:
1718        granularity = ScrollByDocument;
1719        direction = ScrollUp;
1720        break;
1721    default:
1722        return false;
1723        break;
1724    }
1725
1726    Frame* frame = m_page->focusController()->focusedOrMainFrame();
1727    return frame->eventHandler()->scrollRecursively(direction, granularity);
1728}
1729
1730bool WebView::horizontalScroll(WPARAM wParam, LPARAM /*lParam*/)
1731{
1732    ScrollDirection direction;
1733    ScrollGranularity granularity;
1734    switch (LOWORD(wParam)) {
1735    case SB_LINELEFT:
1736        granularity = ScrollByLine;
1737        direction = ScrollLeft;
1738        break;
1739    case SB_LINERIGHT:
1740        granularity = ScrollByLine;
1741        direction = ScrollRight;
1742        break;
1743    case SB_PAGELEFT:
1744        granularity = ScrollByDocument;
1745        direction = ScrollLeft;
1746        break;
1747    case SB_PAGERIGHT:
1748        granularity = ScrollByDocument;
1749        direction = ScrollRight;
1750        break;
1751    default:
1752        return false;
1753    }
1754
1755    Frame* frame = m_page->focusController()->focusedOrMainFrame();
1756    return frame->eventHandler()->scrollRecursively(direction, granularity);
1757}
1758
1759
1760bool WebView::execCommand(WPARAM wParam, LPARAM /*lParam*/)
1761{
1762    Frame* frame = m_page->focusController()->focusedOrMainFrame();
1763    switch (LOWORD(wParam)) {
1764        case SelectAll:
1765            return frame->editor()->command("SelectAll").execute();
1766        case Undo:
1767            return frame->editor()->command("Undo").execute();
1768        case Redo:
1769            return frame->editor()->command("Redo").execute();
1770    }
1771    return false;
1772}
1773
1774bool WebView::keyUp(WPARAM virtualKeyCode, LPARAM keyData, bool systemKeyDown)
1775{
1776    PlatformKeyboardEvent keyEvent(m_viewWindow, virtualKeyCode, keyData, PlatformKeyboardEvent::KeyUp, systemKeyDown);
1777
1778    Frame* frame = m_page->focusController()->focusedOrMainFrame();
1779    m_currentCharacterCode = 0;
1780
1781    return frame->eventHandler()->keyEvent(keyEvent);
1782}
1783
1784static const unsigned CtrlKey = 1 << 0;
1785static const unsigned AltKey = 1 << 1;
1786static const unsigned ShiftKey = 1 << 2;
1787
1788
1789struct KeyDownEntry {
1790    unsigned virtualKey;
1791    unsigned modifiers;
1792    const char* name;
1793};
1794
1795struct KeyPressEntry {
1796    unsigned charCode;
1797    unsigned modifiers;
1798    const char* name;
1799};
1800
1801static const KeyDownEntry keyDownEntries[] = {
1802    { VK_LEFT,   0,                  "MoveLeft"                                    },
1803    { VK_LEFT,   ShiftKey,           "MoveLeftAndModifySelection"                  },
1804    { VK_LEFT,   CtrlKey,            "MoveWordLeft"                                },
1805    { VK_LEFT,   CtrlKey | ShiftKey, "MoveWordLeftAndModifySelection"              },
1806    { VK_RIGHT,  0,                  "MoveRight"                                   },
1807    { VK_RIGHT,  ShiftKey,           "MoveRightAndModifySelection"                 },
1808    { VK_RIGHT,  CtrlKey,            "MoveWordRight"                               },
1809    { VK_RIGHT,  CtrlKey | ShiftKey, "MoveWordRightAndModifySelection"             },
1810    { VK_UP,     0,                  "MoveUp"                                      },
1811    { VK_UP,     ShiftKey,           "MoveUpAndModifySelection"                    },
1812    { VK_PRIOR,  ShiftKey,           "MovePageUpAndModifySelection"                },
1813    { VK_DOWN,   0,                  "MoveDown"                                    },
1814    { VK_DOWN,   ShiftKey,           "MoveDownAndModifySelection"                  },
1815    { VK_NEXT,   ShiftKey,           "MovePageDownAndModifySelection"              },
1816    { VK_PRIOR,  0,                  "MovePageUp"                                  },
1817    { VK_NEXT,   0,                  "MovePageDown"                                },
1818    { VK_HOME,   0,                  "MoveToBeginningOfLine"                       },
1819    { VK_HOME,   ShiftKey,           "MoveToBeginningOfLineAndModifySelection"     },
1820    { VK_HOME,   CtrlKey,            "MoveToBeginningOfDocument"                   },
1821    { VK_HOME,   CtrlKey | ShiftKey, "MoveToBeginningOfDocumentAndModifySelection" },
1822
1823    { VK_END,    0,                  "MoveToEndOfLine"                             },
1824    { VK_END,    ShiftKey,           "MoveToEndOfLineAndModifySelection"           },
1825    { VK_END,    CtrlKey,            "MoveToEndOfDocument"                         },
1826    { VK_END,    CtrlKey | ShiftKey, "MoveToEndOfDocumentAndModifySelection"       },
1827
1828    { VK_BACK,   0,                  "DeleteBackward"                              },
1829    { VK_BACK,   ShiftKey,           "DeleteBackward"                              },
1830    { VK_DELETE, 0,                  "DeleteForward"                               },
1831    { VK_BACK,   CtrlKey,            "DeleteWordBackward"                          },
1832    { VK_DELETE, CtrlKey,            "DeleteWordForward"                           },
1833
1834    { 'B',       CtrlKey,            "ToggleBold"                                  },
1835    { 'I',       CtrlKey,            "ToggleItalic"                                },
1836
1837    { VK_ESCAPE, 0,                  "Cancel"                                      },
1838    { VK_OEM_PERIOD, CtrlKey,        "Cancel"                                      },
1839    { VK_TAB,    0,                  "InsertTab"                                   },
1840    { VK_TAB,    ShiftKey,           "InsertBacktab"                               },
1841    { VK_RETURN, 0,                  "InsertNewline"                               },
1842    { VK_RETURN, CtrlKey,            "InsertNewline"                               },
1843    { VK_RETURN, AltKey,             "InsertNewline"                               },
1844    { VK_RETURN, ShiftKey,           "InsertNewline"                               },
1845    { VK_RETURN, AltKey | ShiftKey,  "InsertNewline"                               },
1846
1847    // It's not quite clear whether clipboard shortcuts and Undo/Redo should be handled
1848    // in the application or in WebKit. We chose WebKit.
1849    { 'C',       CtrlKey,            "Copy"                                        },
1850    { 'V',       CtrlKey,            "Paste"                                       },
1851    { 'X',       CtrlKey,            "Cut"                                         },
1852    { 'A',       CtrlKey,            "SelectAll"                                   },
1853    { VK_INSERT, CtrlKey,            "Copy"                                        },
1854    { VK_DELETE, ShiftKey,           "Cut"                                         },
1855    { VK_INSERT, ShiftKey,           "Paste"                                       },
1856    { 'Z',       CtrlKey,            "Undo"                                        },
1857    { 'Z',       CtrlKey | ShiftKey, "Redo"                                        },
1858};
1859
1860static const KeyPressEntry keyPressEntries[] = {
1861    { '\t',   0,                  "InsertTab"                                   },
1862    { '\t',   ShiftKey,           "InsertBacktab"                               },
1863    { '\r',   0,                  "InsertNewline"                               },
1864    { '\r',   CtrlKey,            "InsertNewline"                               },
1865    { '\r',   AltKey,             "InsertNewline"                               },
1866    { '\r',   ShiftKey,           "InsertNewline"                               },
1867    { '\r',   AltKey | ShiftKey,  "InsertNewline"                               },
1868};
1869
1870const char* WebView::interpretKeyEvent(const KeyboardEvent* evt)
1871{
1872    ASSERT(evt->type() == eventNames().keydownEvent || evt->type() == eventNames().keypressEvent);
1873
1874    static HashMap<int, const char*>* keyDownCommandsMap = 0;
1875    static HashMap<int, const char*>* keyPressCommandsMap = 0;
1876
1877    if (!keyDownCommandsMap) {
1878        keyDownCommandsMap = new HashMap<int, const char*>;
1879        keyPressCommandsMap = new HashMap<int, const char*>;
1880
1881        for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyDownEntries); ++i)
1882            keyDownCommandsMap->set(keyDownEntries[i].modifiers << 16 | keyDownEntries[i].virtualKey, keyDownEntries[i].name);
1883
1884        for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyPressEntries); ++i)
1885            keyPressCommandsMap->set(keyPressEntries[i].modifiers << 16 | keyPressEntries[i].charCode, keyPressEntries[i].name);
1886    }
1887
1888    unsigned modifiers = 0;
1889    if (evt->shiftKey())
1890        modifiers |= ShiftKey;
1891    if (evt->altKey())
1892        modifiers |= AltKey;
1893    if (evt->ctrlKey())
1894        modifiers |= CtrlKey;
1895
1896    if (evt->type() == eventNames().keydownEvent) {
1897        int mapKey = modifiers << 16 | evt->keyCode();
1898        return mapKey ? keyDownCommandsMap->get(mapKey) : 0;
1899    }
1900
1901    int mapKey = modifiers << 16 | evt->charCode();
1902    return mapKey ? keyPressCommandsMap->get(mapKey) : 0;
1903}
1904
1905bool WebView::handleEditingKeyboardEvent(KeyboardEvent* evt)
1906{
1907    Node* node = evt->target()->toNode();
1908    ASSERT(node);
1909    Frame* frame = node->document()->frame();
1910    ASSERT(frame);
1911
1912    const PlatformKeyboardEvent* keyEvent = evt->keyEvent();
1913    if (!keyEvent || keyEvent->isSystemKey())  // do not treat this as text input if it's a system key event
1914        return false;
1915
1916    Editor::Command command = frame->editor()->command(interpretKeyEvent(evt));
1917
1918    if (keyEvent->type() == PlatformKeyboardEvent::RawKeyDown) {
1919        // WebKit doesn't have enough information about mode to decide how commands that just insert text if executed via Editor should be treated,
1920        // so we leave it upon WebCore to either handle them immediately (e.g. Tab that changes focus) or let a keypress event be generated
1921        // (e.g. Tab that inserts a Tab character, or Enter).
1922        return !command.isTextInsertion() && command.execute(evt);
1923    }
1924
1925     if (command.execute(evt))
1926        return true;
1927
1928    // Don't insert null or control characters as they can result in unexpected behaviour
1929    if (evt->charCode() < ' ')
1930        return false;
1931
1932    return frame->editor()->insertText(evt->keyEvent()->text(), evt);
1933}
1934
1935bool WebView::keyDown(WPARAM virtualKeyCode, LPARAM keyData, bool systemKeyDown)
1936{
1937    Frame* frame = m_page->focusController()->focusedOrMainFrame();
1938
1939    PlatformKeyboardEvent keyEvent(m_viewWindow, virtualKeyCode, keyData, PlatformKeyboardEvent::RawKeyDown, systemKeyDown);
1940    bool handled = frame->eventHandler()->keyEvent(keyEvent);
1941
1942    // These events cannot be canceled, and we have no default handling for them.
1943    // FIXME: match IE list more closely, see <http://msdn2.microsoft.com/en-us/library/ms536938.aspx>.
1944    if (systemKeyDown && virtualKeyCode != VK_RETURN)
1945        return false;
1946
1947    if (handled) {
1948        // FIXME: remove WM_UNICHAR, too
1949        MSG msg;
1950        // WM_SYSCHAR events should not be removed, because access keys are implemented in WebCore in WM_SYSCHAR handler.
1951        if (!systemKeyDown)
1952            ::PeekMessage(&msg, m_viewWindow, WM_CHAR, WM_CHAR, PM_REMOVE);
1953        return true;
1954    }
1955
1956    // We need to handle back/forward using either Ctrl+Left/Right Arrow keys.
1957    // FIXME: This logic should probably be in EventHandler::defaultArrowEventHandler().
1958    // FIXME: Should check that other modifiers aren't pressed.
1959    if (virtualKeyCode == VK_RIGHT && keyEvent.ctrlKey())
1960        return m_page->goForward();
1961    if (virtualKeyCode == VK_LEFT && keyEvent.ctrlKey())
1962        return m_page->goBack();
1963
1964    // Need to scroll the page if the arrow keys, pgup/dn, or home/end are hit.
1965    ScrollDirection direction;
1966    ScrollGranularity granularity;
1967    switch (virtualKeyCode) {
1968        case VK_LEFT:
1969            granularity = ScrollByLine;
1970            direction = ScrollLeft;
1971            break;
1972        case VK_RIGHT:
1973            granularity = ScrollByLine;
1974            direction = ScrollRight;
1975            break;
1976        case VK_UP:
1977            granularity = ScrollByLine;
1978            direction = ScrollUp;
1979            break;
1980        case VK_DOWN:
1981            granularity = ScrollByLine;
1982            direction = ScrollDown;
1983            break;
1984        case VK_HOME:
1985            granularity = ScrollByDocument;
1986            direction = ScrollUp;
1987            break;
1988        case VK_END:
1989            granularity = ScrollByDocument;
1990            direction = ScrollDown;
1991            break;
1992        case VK_PRIOR:
1993            granularity = ScrollByPage;
1994            direction = ScrollUp;
1995            break;
1996        case VK_NEXT:
1997            granularity = ScrollByPage;
1998            direction = ScrollDown;
1999            break;
2000        default:
2001            return false;
2002    }
2003
2004    return frame->eventHandler()->scrollRecursively(direction, granularity);
2005}
2006
2007bool WebView::keyPress(WPARAM charCode, LPARAM keyData, bool systemKeyDown)
2008{
2009    Frame* frame = m_page->focusController()->focusedOrMainFrame();
2010
2011    PlatformKeyboardEvent keyEvent(m_viewWindow, charCode, keyData, PlatformKeyboardEvent::Char, systemKeyDown);
2012    // IE does not dispatch keypress event for WM_SYSCHAR.
2013    if (systemKeyDown)
2014        return frame->eventHandler()->handleAccessKey(keyEvent);
2015    return frame->eventHandler()->keyEvent(keyEvent);
2016}
2017
2018void WebView::setIsBeingDestroyed()
2019{
2020    m_isBeingDestroyed = true;
2021
2022    // Remove our this pointer from the window so we won't try to handle any more window messages.
2023    // See <http://webkit.org/b/55054>.
2024    ::SetWindowLongPtrW(m_viewWindow, 0, 0);
2025}
2026
2027bool WebView::registerWebViewWindowClass()
2028{
2029    static bool haveRegisteredWindowClass = false;
2030    if (haveRegisteredWindowClass)
2031        return true;
2032
2033    haveRegisteredWindowClass = true;
2034
2035    WNDCLASSEX wcex;
2036
2037    wcex.cbSize = sizeof(WNDCLASSEX);
2038
2039    wcex.style          = CS_DBLCLKS;
2040    wcex.lpfnWndProc    = WebViewWndProc;
2041    wcex.cbClsExtra     = 0;
2042    wcex.cbWndExtra     = 4; // 4 bytes for the IWebView pointer
2043    wcex.hInstance      = gInstance;
2044    wcex.hIcon          = 0;
2045    wcex.hCursor        = ::LoadCursor(0, IDC_ARROW);
2046    wcex.hbrBackground  = 0;
2047    wcex.lpszMenuName   = 0;
2048    wcex.lpszClassName  = kWebViewWindowClassName;
2049    wcex.hIconSm        = 0;
2050
2051    return !!RegisterClassEx(&wcex);
2052}
2053
2054static HWND findTopLevelParent(HWND window)
2055{
2056    if (!window)
2057        return 0;
2058
2059    HWND current = window;
2060    for (HWND parent = GetParent(current); current; current = parent, parent = GetParent(parent))
2061        if (!parent || !(GetWindowLongPtr(current, GWL_STYLE) & (WS_POPUP | WS_CHILD)))
2062            return current;
2063    ASSERT_NOT_REACHED();
2064    return 0;
2065}
2066
2067LRESULT CALLBACK WebView::WebViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
2068{
2069    LRESULT lResult = 0;
2070    LONG_PTR longPtr = GetWindowLongPtr(hWnd, 0);
2071    WebView* webView = reinterpret_cast<WebView*>(longPtr);
2072    WebFrame* mainFrameImpl = webView ? webView->topLevelFrame() : 0;
2073    if (!mainFrameImpl)
2074        return DefWindowProc(hWnd, message, wParam, lParam);
2075
2076    // We shouldn't be trying to handle any window messages after WM_DESTROY.
2077    // See <http://webkit.org/b/55054>.
2078    ASSERT(!webView->isBeingDestroyed());
2079
2080    // hold a ref, since the WebView could go away in an event handler.
2081    COMPtr<WebView> protector(webView);
2082    ASSERT(webView);
2083
2084    // Windows Media Player has a modal message loop that will deliver messages
2085    // to us at inappropriate times and we will crash if we handle them when
2086    // they are delivered. We repost paint messages so that we eventually get
2087    // a chance to paint once the modal loop has exited, but other messages
2088    // aren't safe to repost, so we just drop them.
2089    if (PluginView::isCallingPlugin()) {
2090        if (message == WM_PAINT)
2091            PostMessage(hWnd, message, wParam, lParam);
2092        return 0;
2093    }
2094
2095    bool handled = true;
2096
2097    switch (message) {
2098        case WM_PAINT: {
2099            webView->paint(0, 0);
2100            break;
2101        }
2102        case WM_PRINTCLIENT:
2103            webView->paint((HDC)wParam, lParam);
2104            break;
2105        case WM_DESTROY:
2106            webView->setIsBeingDestroyed();
2107            webView->close();
2108            break;
2109        case WM_GESTURENOTIFY:
2110            handled = webView->gestureNotify(wParam, lParam);
2111            break;
2112        case WM_GESTURE:
2113            handled = webView->gesture(wParam, lParam);
2114            break;
2115        case WM_MOUSEMOVE:
2116        case WM_LBUTTONDOWN:
2117        case WM_MBUTTONDOWN:
2118        case WM_RBUTTONDOWN:
2119        case WM_LBUTTONDBLCLK:
2120        case WM_MBUTTONDBLCLK:
2121        case WM_RBUTTONDBLCLK:
2122        case WM_LBUTTONUP:
2123        case WM_MBUTTONUP:
2124        case WM_RBUTTONUP:
2125        case WM_MOUSELEAVE:
2126        case WM_CANCELMODE:
2127            if (Frame* coreFrame = core(mainFrameImpl))
2128                if (coreFrame->view()->didFirstLayout())
2129                    handled = webView->handleMouseEvent(message, wParam, lParam);
2130            break;
2131        case WM_MOUSEWHEEL:
2132        case WM_VISTA_MOUSEHWHEEL:
2133            if (Frame* coreFrame = core(mainFrameImpl))
2134                if (coreFrame->view()->didFirstLayout())
2135                    handled = webView->mouseWheel(wParam, lParam, message == WM_VISTA_MOUSEHWHEEL);
2136            break;
2137        case WM_SYSKEYDOWN:
2138            handled = webView->keyDown(wParam, lParam, true);
2139            break;
2140        case WM_KEYDOWN:
2141            handled = webView->keyDown(wParam, lParam);
2142            break;
2143        case WM_SYSKEYUP:
2144            handled = webView->keyUp(wParam, lParam, true);
2145            break;
2146        case WM_KEYUP:
2147            handled = webView->keyUp(wParam, lParam);
2148            break;
2149        case WM_SYSCHAR:
2150            handled = webView->keyPress(wParam, lParam, true);
2151            break;
2152        case WM_CHAR:
2153            handled = webView->keyPress(wParam, lParam);
2154            break;
2155        // FIXME: We need to check WM_UNICHAR to support supplementary characters (that don't fit in 16 bits).
2156        case WM_SIZE:
2157            if (lParam != 0)
2158                webView->sizeChanged(IntSize(LOWORD(lParam), HIWORD(lParam)));
2159            break;
2160        case WM_SHOWWINDOW:
2161            lResult = DefWindowProc(hWnd, message, wParam, lParam);
2162            if (wParam == 0) {
2163                // The window is being hidden (e.g., because we switched tabs).
2164                // Null out our backing store.
2165                webView->deleteBackingStore();
2166            }
2167            break;
2168        case WM_SETFOCUS: {
2169            COMPtr<IWebUIDelegate> uiDelegate;
2170            COMPtr<IWebUIDelegatePrivate> uiDelegatePrivate;
2171            if (SUCCEEDED(webView->uiDelegate(&uiDelegate)) && uiDelegate
2172                && SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**) &uiDelegatePrivate)) && uiDelegatePrivate)
2173                uiDelegatePrivate->webViewReceivedFocus(webView);
2174
2175            FocusController* focusController = webView->page()->focusController();
2176            if (Frame* frame = focusController->focusedFrame()) {
2177                // Send focus events unless the previously focused window is a
2178                // child of ours (for example a plugin).
2179                if (!IsChild(hWnd, reinterpret_cast<HWND>(wParam)))
2180                    focusController->setFocused(true);
2181            } else
2182                focusController->setFocused(true);
2183            break;
2184        }
2185        case WM_KILLFOCUS: {
2186            COMPtr<IWebUIDelegate> uiDelegate;
2187            COMPtr<IWebUIDelegatePrivate> uiDelegatePrivate;
2188            HWND newFocusWnd = reinterpret_cast<HWND>(wParam);
2189            if (SUCCEEDED(webView->uiDelegate(&uiDelegate)) && uiDelegate
2190                && SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**) &uiDelegatePrivate)) && uiDelegatePrivate)
2191                uiDelegatePrivate->webViewLostFocus(webView, (OLE_HANDLE)(ULONG64)newFocusWnd);
2192
2193            FocusController* focusController = webView->page()->focusController();
2194            Frame* frame = focusController->focusedOrMainFrame();
2195            webView->resetIME(frame);
2196            // Send blur events unless we're losing focus to a child of ours.
2197            if (!IsChild(hWnd, newFocusWnd))
2198                focusController->setFocused(false);
2199
2200            // If we are pan-scrolling when we lose focus, stop the pan scrolling.
2201            frame->eventHandler()->stopAutoscrollTimer();
2202
2203            break;
2204        }
2205        case WM_WINDOWPOSCHANGED:
2206            if (reinterpret_cast<WINDOWPOS*>(lParam)->flags & SWP_SHOWWINDOW)
2207                webView->updateActiveStateSoon();
2208            handled = false;
2209            break;
2210        case WM_CUT:
2211            webView->cut(0);
2212            break;
2213        case WM_COPY:
2214            webView->copy(0);
2215            break;
2216        case WM_PASTE:
2217            webView->paste(0);
2218            break;
2219        case WM_CLEAR:
2220            webView->delete_(0);
2221            break;
2222        case WM_COMMAND:
2223            if (HIWORD(wParam))
2224                handled = webView->execCommand(wParam, lParam);
2225            else // If the high word of wParam is 0, the message is from a menu
2226                webView->performContextMenuAction(wParam, lParam, false);
2227            break;
2228        case WM_MENUCOMMAND:
2229            webView->performContextMenuAction(wParam, lParam, true);
2230            break;
2231        case WM_CONTEXTMENU:
2232            handled = webView->handleContextMenuEvent(wParam, lParam);
2233            break;
2234        case WM_INITMENUPOPUP:
2235            handled = webView->onInitMenuPopup(wParam, lParam);
2236            break;
2237        case WM_MEASUREITEM:
2238            handled = webView->onMeasureItem(wParam, lParam);
2239            break;
2240        case WM_DRAWITEM:
2241            handled = webView->onDrawItem(wParam, lParam);
2242            break;
2243        case WM_UNINITMENUPOPUP:
2244            handled = webView->onUninitMenuPopup(wParam, lParam);
2245            break;
2246        case WM_XP_THEMECHANGED:
2247            if (Frame* coreFrame = core(mainFrameImpl)) {
2248                webView->deleteBackingStore();
2249                coreFrame->page()->theme()->themeChanged();
2250                ScrollbarTheme::nativeTheme()->themeChanged();
2251                RECT windowRect;
2252                ::GetClientRect(hWnd, &windowRect);
2253                ::InvalidateRect(hWnd, &windowRect, false);
2254#if USE(ACCELERATED_COMPOSITING)
2255                if (webView->isAcceleratedCompositing())
2256                    webView->m_backingLayer->setNeedsDisplay();
2257#endif
2258           }
2259            break;
2260        case WM_MOUSEACTIVATE:
2261            webView->setMouseActivated(true);
2262            handled = false;
2263            break;
2264        case WM_GETDLGCODE: {
2265            COMPtr<IWebUIDelegate> uiDelegate;
2266            COMPtr<IWebUIDelegatePrivate> uiDelegatePrivate;
2267            LONG_PTR dlgCode = 0;
2268            UINT keyCode = 0;
2269            if (lParam) {
2270                LPMSG lpMsg = (LPMSG)lParam;
2271                if (lpMsg->message == WM_KEYDOWN)
2272                    keyCode = (UINT) lpMsg->wParam;
2273            }
2274            if (SUCCEEDED(webView->uiDelegate(&uiDelegate)) && uiDelegate
2275                && SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**) &uiDelegatePrivate)) && uiDelegatePrivate
2276                && SUCCEEDED(uiDelegatePrivate->webViewGetDlgCode(webView, keyCode, &dlgCode)))
2277                return dlgCode;
2278            handled = false;
2279            break;
2280        }
2281        case WM_GETOBJECT:
2282            handled = webView->onGetObject(wParam, lParam, lResult);
2283            break;
2284        case WM_IME_STARTCOMPOSITION:
2285            handled = webView->onIMEStartComposition();
2286            break;
2287        case WM_IME_REQUEST:
2288            lResult = webView->onIMERequest(wParam, lParam);
2289            break;
2290        case WM_IME_COMPOSITION:
2291            handled = webView->onIMEComposition(lParam);
2292            break;
2293        case WM_IME_ENDCOMPOSITION:
2294            handled = webView->onIMEEndComposition();
2295            break;
2296        case WM_IME_CHAR:
2297            handled = webView->onIMEChar(wParam, lParam);
2298            break;
2299        case WM_IME_NOTIFY:
2300            handled = webView->onIMENotify(wParam, lParam, &lResult);
2301            break;
2302        case WM_IME_SELECT:
2303            handled = webView->onIMESelect(wParam, lParam);
2304            break;
2305        case WM_IME_SETCONTEXT:
2306            handled = webView->onIMESetContext(wParam, lParam);
2307            break;
2308        case WM_TIMER:
2309            switch (wParam) {
2310                case UpdateActiveStateTimer:
2311                    KillTimer(hWnd, UpdateActiveStateTimer);
2312                    webView->updateActiveState();
2313                    break;
2314                case DeleteBackingStoreTimer:
2315                    webView->deleteBackingStore();
2316                    break;
2317            }
2318            break;
2319        case WM_SETCURSOR:
2320            handled = ::SetCursor(webView->m_lastSetCursor);
2321            break;
2322        case WM_VSCROLL:
2323            handled = webView->verticalScroll(wParam, lParam);
2324            break;
2325        case WM_HSCROLL:
2326            handled = webView->horizontalScroll(wParam, lParam);
2327            break;
2328        default:
2329            handled = false;
2330            break;
2331    }
2332
2333    if (!handled)
2334        lResult = DefWindowProc(hWnd, message, wParam, lParam);
2335
2336    // Let the client know whether we consider this message handled.
2337    return (message == WM_KEYDOWN || message == WM_SYSKEYDOWN || message == WM_KEYUP || message == WM_SYSKEYUP) ? !handled : lResult;
2338}
2339
2340bool WebView::developerExtrasEnabled() const
2341{
2342    if (m_preferences->developerExtrasDisabledByOverride())
2343        return false;
2344
2345#ifdef NDEBUG
2346    BOOL enabled;
2347    return SUCCEEDED(m_preferences->developerExtrasEnabled(&enabled)) && enabled;
2348#else
2349    return true;
2350#endif
2351}
2352
2353static String webKitVersionString()
2354{
2355    LPWSTR buildNumberStringPtr;
2356    if (!::LoadStringW(gInstance, BUILD_NUMBER, reinterpret_cast<LPWSTR>(&buildNumberStringPtr), 0) || !buildNumberStringPtr)
2357        return "534+";
2358
2359    return buildNumberStringPtr;
2360}
2361
2362const String& WebView::userAgentForKURL(const KURL&)
2363{
2364    if (m_userAgentOverridden)
2365        return m_userAgentCustom;
2366
2367    if (!m_userAgentStandard.length())
2368        m_userAgentStandard = WebView::standardUserAgentWithApplicationName(m_applicationName);
2369    return m_userAgentStandard;
2370}
2371
2372// IUnknown -------------------------------------------------------------------
2373
2374HRESULT STDMETHODCALLTYPE WebView::QueryInterface(REFIID riid, void** ppvObject)
2375{
2376    *ppvObject = 0;
2377    if (IsEqualGUID(riid, CLSID_WebView))
2378        *ppvObject = this;
2379    else if (IsEqualGUID(riid, IID_IUnknown))
2380        *ppvObject = static_cast<IWebView*>(this);
2381    else if (IsEqualGUID(riid, IID_IWebView))
2382        *ppvObject = static_cast<IWebView*>(this);
2383    else if (IsEqualGUID(riid, IID_IWebViewPrivate))
2384        *ppvObject = static_cast<IWebViewPrivate*>(this);
2385    else if (IsEqualGUID(riid, IID_IWebIBActions))
2386        *ppvObject = static_cast<IWebIBActions*>(this);
2387    else if (IsEqualGUID(riid, IID_IWebViewCSS))
2388        *ppvObject = static_cast<IWebViewCSS*>(this);
2389    else if (IsEqualGUID(riid, IID_IWebViewEditing))
2390        *ppvObject = static_cast<IWebViewEditing*>(this);
2391    else if (IsEqualGUID(riid, IID_IWebViewUndoableEditing))
2392        *ppvObject = static_cast<IWebViewUndoableEditing*>(this);
2393    else if (IsEqualGUID(riid, IID_IWebViewEditingActions))
2394        *ppvObject = static_cast<IWebViewEditingActions*>(this);
2395    else if (IsEqualGUID(riid, IID_IWebNotificationObserver))
2396        *ppvObject = static_cast<IWebNotificationObserver*>(this);
2397    else if (IsEqualGUID(riid, IID_IDropTarget))
2398        *ppvObject = static_cast<IDropTarget*>(this);
2399    else
2400        return E_NOINTERFACE;
2401
2402    AddRef();
2403    return S_OK;
2404}
2405
2406ULONG STDMETHODCALLTYPE WebView::AddRef(void)
2407{
2408    ASSERT(!m_deletionHasBegun);
2409    return ++m_refCount;
2410}
2411
2412ULONG STDMETHODCALLTYPE WebView::Release(void)
2413{
2414    ASSERT(!m_deletionHasBegun);
2415
2416    if (m_refCount == 1) {
2417        // Call close() now so that clients don't have to. (It's harmless to call close() multiple
2418        // times.) We do this here instead of in our destructor because close() can cause AddRef()
2419        // and Release() to be called, and if that happened in our destructor we would be destroyed
2420        // more than once.
2421        close();
2422    }
2423
2424    ULONG newRef = --m_refCount;
2425    if (!newRef) {
2426#if !ASSERT_DISABLED
2427        m_deletionHasBegun = true;
2428#endif
2429        delete(this);
2430    }
2431
2432    return newRef;
2433}
2434
2435// IWebView --------------------------------------------------------------------
2436
2437HRESULT STDMETHODCALLTYPE WebView::canShowMIMEType(
2438    /* [in] */ BSTR mimeType,
2439    /* [retval][out] */ BOOL* canShow)
2440{
2441    String mimeTypeStr(mimeType, SysStringLen(mimeType));
2442
2443    if (!canShow)
2444        return E_POINTER;
2445
2446    *canShow = MIMETypeRegistry::isSupportedImageMIMEType(mimeTypeStr) ||
2447        MIMETypeRegistry::isSupportedNonImageMIMEType(mimeTypeStr) ||
2448        (m_page && m_page->pluginData() && m_page->pluginData()->supportsMimeType(mimeTypeStr)) ||
2449        shouldUseEmbeddedView(mimeTypeStr);
2450
2451    return S_OK;
2452}
2453
2454HRESULT STDMETHODCALLTYPE WebView::canShowMIMETypeAsHTML(
2455    /* [in] */ BSTR /*mimeType*/,
2456    /* [retval][out] */ BOOL* canShow)
2457{
2458    // FIXME
2459    *canShow = TRUE;
2460    return S_OK;
2461}
2462
2463HRESULT STDMETHODCALLTYPE WebView::MIMETypesShownAsHTML(
2464    /* [retval][out] */ IEnumVARIANT** /*enumVariant*/)
2465{
2466    ASSERT_NOT_REACHED();
2467    return E_NOTIMPL;
2468}
2469
2470HRESULT STDMETHODCALLTYPE WebView::setMIMETypesShownAsHTML(
2471        /* [size_is][in] */ BSTR* /*mimeTypes*/,
2472        /* [in] */ int /*cMimeTypes*/)
2473{
2474    ASSERT_NOT_REACHED();
2475    return E_NOTIMPL;
2476}
2477
2478HRESULT STDMETHODCALLTYPE WebView::URLFromPasteboard(
2479    /* [in] */ IDataObject* /*pasteboard*/,
2480    /* [retval][out] */ BSTR* /*url*/)
2481{
2482    ASSERT_NOT_REACHED();
2483    return E_NOTIMPL;
2484}
2485
2486HRESULT STDMETHODCALLTYPE WebView::URLTitleFromPasteboard(
2487    /* [in] */ IDataObject* /*pasteboard*/,
2488    /* [retval][out] */ BSTR* /*urlTitle*/)
2489{
2490    ASSERT_NOT_REACHED();
2491    return E_NOTIMPL;
2492}
2493
2494static void WebKitSetApplicationCachePathIfNecessary()
2495{
2496    static bool initialized = false;
2497    if (initialized)
2498        return;
2499
2500    String path = localUserSpecificStorageDirectory();
2501    if (!path.isNull())
2502        cacheStorage().setCacheDirectory(path);
2503
2504    initialized = true;
2505}
2506
2507bool WebView::shouldInitializeTrackPointHack()
2508{
2509    static bool shouldCreateScrollbars;
2510    static bool hasRunTrackPointCheck;
2511
2512    if (hasRunTrackPointCheck)
2513        return shouldCreateScrollbars;
2514
2515    hasRunTrackPointCheck = true;
2516    const WCHAR trackPointKeys[][50] = { L"Software\\Lenovo\\TrackPoint",
2517        L"Software\\Lenovo\\UltraNav",
2518        L"Software\\Alps\\Apoint\\TrackPoint",
2519        L"Software\\Synaptics\\SynTPEnh\\UltraNavUSB",
2520        L"Software\\Synaptics\\SynTPEnh\\UltraNavPS2" };
2521
2522    for (int i = 0; i < 5; ++i) {
2523        HKEY trackPointKey;
2524        int readKeyResult = ::RegOpenKeyExW(HKEY_CURRENT_USER, trackPointKeys[i], 0, KEY_READ, &trackPointKey);
2525        ::RegCloseKey(trackPointKey);
2526        if (readKeyResult == ERROR_SUCCESS) {
2527            shouldCreateScrollbars = true;
2528            return shouldCreateScrollbars;
2529        }
2530    }
2531
2532    return shouldCreateScrollbars;
2533}
2534
2535HRESULT STDMETHODCALLTYPE WebView::initWithFrame(
2536    /* [in] */ RECT frame,
2537    /* [in] */ BSTR frameName,
2538    /* [in] */ BSTR groupName)
2539{
2540    HRESULT hr = S_OK;
2541
2542    if (m_viewWindow)
2543        return E_FAIL;
2544
2545    registerWebViewWindowClass();
2546
2547    m_viewWindow = CreateWindowEx(0, kWebViewWindowClassName, 0, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
2548        frame.left, frame.top, frame.right - frame.left, frame.bottom - frame.top, m_hostWindow ? m_hostWindow : HWND_MESSAGE, 0, gInstance, 0);
2549    ASSERT(::IsWindow(m_viewWindow));
2550
2551    if (shouldInitializeTrackPointHack()) {
2552        // If we detected a registry key belonging to a TrackPoint driver, then create fake trackpoint
2553        // scrollbars, so the WebView will receive WM_VSCROLL and WM_HSCROLL messages. We create one
2554        // vertical scrollbar and one horizontal to allow for receiving both types of messages.
2555        ::CreateWindowW(L"SCROLLBAR", L"FAKETRACKPOINTHSCROLLBAR", WS_CHILD | WS_VISIBLE | SBS_HORZ, 0, 0, 0, 0, m_viewWindow, 0, gInstance, 0);
2556        ::CreateWindowW(L"SCROLLBAR", L"FAKETRACKPOINTVSCROLLBAR", WS_CHILD | WS_VISIBLE | SBS_VERT, 0, 0, 0, 0, m_viewWindow, 0, gInstance, 0);
2557    }
2558
2559    hr = registerDragDrop();
2560    if (FAILED(hr))
2561        return hr;
2562
2563    WebPreferences* sharedPreferences = WebPreferences::sharedStandardPreferences();
2564    sharedPreferences->willAddToWebView();
2565    m_preferences = sharedPreferences;
2566
2567    static bool didOneTimeInitialization;
2568    if (!didOneTimeInitialization) {
2569        InitializeLoggingChannelsIfNecessary();
2570#if ENABLE(DATABASE)
2571        WebKitInitializeWebDatabasesIfNecessary();
2572#endif
2573        WebKitSetApplicationCachePathIfNecessary();
2574        WebPlatformStrategies::initialize();
2575        Settings::setDefaultMinDOMTimerInterval(0.004);
2576
2577        didOneTimeInitialization = true;
2578     }
2579
2580#if USE(SAFARI_THEME)
2581    BOOL shouldPaintNativeControls;
2582    if (SUCCEEDED(m_preferences->shouldPaintNativeControls(&shouldPaintNativeControls)))
2583        Settings::setShouldPaintNativeControls(shouldPaintNativeControls);
2584#endif
2585
2586    BOOL useHighResolutionTimer;
2587    if (SUCCEEDED(m_preferences->shouldUseHighResolutionTimers(&useHighResolutionTimer)))
2588        Settings::setShouldUseHighResolutionTimers(useHighResolutionTimer);
2589
2590    Page::PageClients pageClients;
2591    pageClients.chromeClient = new WebChromeClient(this);
2592    pageClients.contextMenuClient = new WebContextMenuClient(this);
2593    pageClients.editorClient = new WebEditorClient(this);
2594    pageClients.dragClient = new WebDragClient(this);
2595    pageClients.inspectorClient = new WebInspectorClient(this);
2596    pageClients.pluginHalterClient = new WebPluginHalterClient(this);
2597#if ENABLE(CLIENT_BASED_GEOLOCATION)
2598    pageClients.geolocationClient = new WebGeolocationClient(this);
2599#endif
2600    m_page = new Page(pageClients);
2601
2602    BSTR localStoragePath;
2603    if (SUCCEEDED(m_preferences->localStorageDatabasePath(&localStoragePath))) {
2604        m_page->settings()->setLocalStorageDatabasePath(String(localStoragePath, SysStringLen(localStoragePath)));
2605        SysFreeString(localStoragePath);
2606    }
2607
2608    if (m_uiDelegate) {
2609        BSTR path;
2610        if (SUCCEEDED(m_uiDelegate->ftpDirectoryTemplatePath(this, &path))) {
2611            m_page->settings()->setFTPDirectoryTemplatePath(String(path, SysStringLen(path)));
2612            SysFreeString(path);
2613        }
2614    }
2615
2616    WebFrame* webFrame = WebFrame::createInstance();
2617    RefPtr<Frame> coreFrame = webFrame->init(this, m_page, 0);
2618    m_mainFrame = webFrame;
2619    webFrame->Release(); // The WebFrame is owned by the Frame, so release our reference to it.
2620
2621    coreFrame->tree()->setName(String(frameName, SysStringLen(frameName)));
2622    coreFrame->init();
2623    setGroupName(groupName);
2624
2625    addToAllWebViewsSet();
2626
2627    #pragma warning(suppress: 4244)
2628    SetWindowLongPtr(m_viewWindow, 0, (LONG_PTR)this);
2629    ShowWindow(m_viewWindow, SW_SHOW);
2630
2631    initializeToolTipWindow();
2632    windowAncestryDidChange();
2633
2634    IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal();
2635    notifyCenter->addObserver(this, WebPreferences::webPreferencesChangedNotification(), static_cast<IWebPreferences*>(m_preferences.get()));
2636    m_preferences->postPreferencesChangesNotification();
2637
2638    setSmartInsertDeleteEnabled(TRUE);
2639    return hr;
2640}
2641
2642static bool initCommonControls()
2643{
2644    static bool haveInitialized = false;
2645    if (haveInitialized)
2646        return true;
2647
2648    INITCOMMONCONTROLSEX init;
2649    init.dwSize = sizeof(init);
2650    init.dwICC = ICC_TREEVIEW_CLASSES;
2651    haveInitialized = !!::InitCommonControlsEx(&init);
2652    return haveInitialized;
2653}
2654
2655void WebView::initializeToolTipWindow()
2656{
2657    if (!initCommonControls())
2658        return;
2659
2660    m_toolTipHwnd = CreateWindowEx(WS_EX_TRANSPARENT, TOOLTIPS_CLASS, 0, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
2661                                   CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
2662                                   m_viewWindow, 0, 0, 0);
2663    if (!m_toolTipHwnd)
2664        return;
2665
2666    TOOLINFO info = {0};
2667    info.cbSize = sizeof(info);
2668    info.uFlags = TTF_IDISHWND | TTF_SUBCLASS ;
2669    info.uId = reinterpret_cast<UINT_PTR>(m_viewWindow);
2670
2671    ::SendMessage(m_toolTipHwnd, TTM_ADDTOOL, 0, reinterpret_cast<LPARAM>(&info));
2672    ::SendMessage(m_toolTipHwnd, TTM_SETMAXTIPWIDTH, 0, maxToolTipWidth);
2673
2674    ::SetWindowPos(m_toolTipHwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
2675}
2676
2677void WebView::setToolTip(const String& toolTip)
2678{
2679    if (!m_toolTipHwnd)
2680        return;
2681
2682    if (toolTip == m_toolTip)
2683        return;
2684
2685    m_toolTip = toolTip;
2686
2687    if (!m_toolTip.isEmpty()) {
2688        TOOLINFO info = {0};
2689        info.cbSize = sizeof(info);
2690        info.uFlags = TTF_IDISHWND;
2691        info.uId = reinterpret_cast<UINT_PTR>(m_viewWindow);
2692        info.lpszText = const_cast<UChar*>(m_toolTip.charactersWithNullTermination());
2693        ::SendMessage(m_toolTipHwnd, TTM_UPDATETIPTEXT, 0, reinterpret_cast<LPARAM>(&info));
2694    }
2695
2696    ::SendMessage(m_toolTipHwnd, TTM_ACTIVATE, !m_toolTip.isEmpty(), 0);
2697}
2698
2699HRESULT WebView::notifyDidAddIcon(IWebNotification* notification)
2700{
2701    COMPtr<IPropertyBag> propertyBag;
2702    HRESULT hr = notification->userInfo(&propertyBag);
2703    if (FAILED(hr))
2704        return hr;
2705    if (!propertyBag)
2706        return E_FAIL;
2707
2708    COMPtr<CFDictionaryPropertyBag> dictionaryPropertyBag;
2709    hr = propertyBag->QueryInterface(&dictionaryPropertyBag);
2710    if (FAILED(hr))
2711        return hr;
2712
2713    CFDictionaryRef dictionary = dictionaryPropertyBag->dictionary();
2714    if (!dictionary)
2715        return E_FAIL;
2716
2717    CFTypeRef value = CFDictionaryGetValue(dictionary, WebIconDatabase::iconDatabaseNotificationUserInfoURLKey());
2718    if (!value)
2719        return E_FAIL;
2720    if (CFGetTypeID(value) != CFStringGetTypeID())
2721        return E_FAIL;
2722
2723    String mainFrameURL;
2724    if (m_mainFrame)
2725        mainFrameURL = m_mainFrame->url().string();
2726
2727    if (!mainFrameURL.isEmpty() && mainFrameURL == String((CFStringRef)value))
2728        dispatchDidReceiveIconFromWebFrame(m_mainFrame);
2729
2730    return hr;
2731}
2732
2733void WebView::registerForIconNotification(bool listen)
2734{
2735    IWebNotificationCenter* nc = WebNotificationCenter::defaultCenterInternal();
2736    if (listen)
2737        nc->addObserver(this, WebIconDatabase::iconDatabaseDidAddIconNotification(), 0);
2738    else
2739        nc->removeObserver(this, WebIconDatabase::iconDatabaseDidAddIconNotification(), 0);
2740}
2741
2742void WebView::dispatchDidReceiveIconFromWebFrame(WebFrame* frame)
2743{
2744    registerForIconNotification(false);
2745
2746    if (m_frameLoadDelegate)
2747        // FIXME: <rdar://problem/5491010> - Pass in the right HBITMAP.
2748        m_frameLoadDelegate->didReceiveIcon(this, 0, frame);
2749}
2750
2751HRESULT STDMETHODCALLTYPE WebView::setUIDelegate(
2752    /* [in] */ IWebUIDelegate* d)
2753{
2754    m_uiDelegate = d;
2755
2756    if (m_uiDelegatePrivate)
2757        m_uiDelegatePrivate = 0;
2758
2759    if (d) {
2760        if (FAILED(d->QueryInterface(IID_IWebUIDelegatePrivate, (void**)&m_uiDelegatePrivate)))
2761            m_uiDelegatePrivate = 0;
2762    }
2763
2764    return S_OK;
2765}
2766
2767HRESULT STDMETHODCALLTYPE WebView::uiDelegate(
2768    /* [out][retval] */ IWebUIDelegate** d)
2769{
2770    if (!m_uiDelegate)
2771        return E_FAIL;
2772
2773    return m_uiDelegate.copyRefTo(d);
2774}
2775
2776HRESULT STDMETHODCALLTYPE WebView::setResourceLoadDelegate(
2777    /* [in] */ IWebResourceLoadDelegate* d)
2778{
2779    m_resourceLoadDelegate = d;
2780    return S_OK;
2781}
2782
2783HRESULT STDMETHODCALLTYPE WebView::resourceLoadDelegate(
2784    /* [out][retval] */ IWebResourceLoadDelegate** d)
2785{
2786    if (!m_resourceLoadDelegate)
2787        return E_FAIL;
2788
2789    return m_resourceLoadDelegate.copyRefTo(d);
2790}
2791
2792HRESULT STDMETHODCALLTYPE WebView::setDownloadDelegate(
2793    /* [in] */ IWebDownloadDelegate* d)
2794{
2795    m_downloadDelegate = d;
2796    return S_OK;
2797}
2798
2799HRESULT STDMETHODCALLTYPE WebView::downloadDelegate(
2800    /* [out][retval] */ IWebDownloadDelegate** d)
2801{
2802    if (!m_downloadDelegate)
2803        return E_FAIL;
2804
2805    return m_downloadDelegate.copyRefTo(d);
2806}
2807
2808HRESULT STDMETHODCALLTYPE WebView::setFrameLoadDelegate(
2809    /* [in] */ IWebFrameLoadDelegate* d)
2810{
2811    m_frameLoadDelegate = d;
2812    return S_OK;
2813}
2814
2815HRESULT STDMETHODCALLTYPE WebView::frameLoadDelegate(
2816    /* [out][retval] */ IWebFrameLoadDelegate** d)
2817{
2818    if (!m_frameLoadDelegate)
2819        return E_FAIL;
2820
2821    return m_frameLoadDelegate.copyRefTo(d);
2822}
2823
2824HRESULT STDMETHODCALLTYPE WebView::setPolicyDelegate(
2825    /* [in] */ IWebPolicyDelegate* d)
2826{
2827    m_policyDelegate = d;
2828    return S_OK;
2829}
2830
2831HRESULT STDMETHODCALLTYPE WebView::policyDelegate(
2832    /* [out][retval] */ IWebPolicyDelegate** d)
2833{
2834    if (!m_policyDelegate)
2835        return E_FAIL;
2836    return m_policyDelegate.copyRefTo(d);
2837}
2838
2839HRESULT STDMETHODCALLTYPE WebView::mainFrame(
2840    /* [out][retval] */ IWebFrame** frame)
2841{
2842    if (!frame) {
2843        ASSERT_NOT_REACHED();
2844        return E_POINTER;
2845    }
2846
2847    *frame = m_mainFrame;
2848    if (!m_mainFrame)
2849        return E_FAIL;
2850
2851    m_mainFrame->AddRef();
2852    return S_OK;
2853}
2854
2855HRESULT STDMETHODCALLTYPE WebView::focusedFrame(
2856    /* [out][retval] */ IWebFrame** frame)
2857{
2858    if (!frame) {
2859        ASSERT_NOT_REACHED();
2860        return E_POINTER;
2861    }
2862
2863    *frame = 0;
2864    Frame* f = m_page->focusController()->focusedFrame();
2865    if (!f)
2866        return E_FAIL;
2867
2868    WebFrame* webFrame = kit(f);
2869    if (!webFrame)
2870        return E_FAIL;
2871
2872    return webFrame->QueryInterface(IID_IWebFrame, (void**) frame);
2873}
2874
2875HRESULT STDMETHODCALLTYPE WebView::backForwardList(
2876    /* [out][retval] */ IWebBackForwardList** list)
2877{
2878    if (!m_useBackForwardList)
2879        return E_FAIL;
2880
2881    *list = WebBackForwardList::createInstance(static_cast<WebCore::BackForwardListImpl*>(m_page->backForwardList()));
2882
2883    return S_OK;
2884}
2885
2886HRESULT STDMETHODCALLTYPE WebView::setMaintainsBackForwardList(
2887    /* [in] */ BOOL flag)
2888{
2889    m_useBackForwardList = !!flag;
2890    return S_OK;
2891}
2892
2893HRESULT STDMETHODCALLTYPE WebView::goBack(
2894    /* [retval][out] */ BOOL* succeeded)
2895{
2896    *succeeded = m_page->goBack();
2897    return S_OK;
2898}
2899
2900HRESULT STDMETHODCALLTYPE WebView::goForward(
2901    /* [retval][out] */ BOOL* succeeded)
2902{
2903    *succeeded = m_page->goForward();
2904    return S_OK;
2905}
2906
2907HRESULT STDMETHODCALLTYPE WebView::goToBackForwardItem(
2908    /* [in] */ IWebHistoryItem* item,
2909    /* [retval][out] */ BOOL* succeeded)
2910{
2911    *succeeded = FALSE;
2912
2913    COMPtr<WebHistoryItem> webHistoryItem;
2914    HRESULT hr = item->QueryInterface(&webHistoryItem);
2915    if (FAILED(hr))
2916        return hr;
2917
2918    m_page->goToItem(webHistoryItem->historyItem(), FrameLoadTypeIndexedBackForward);
2919    *succeeded = TRUE;
2920
2921    return S_OK;
2922}
2923
2924HRESULT STDMETHODCALLTYPE WebView::setTextSizeMultiplier(
2925    /* [in] */ float multiplier)
2926{
2927    if (!m_mainFrame)
2928        return E_FAIL;
2929    setZoomMultiplier(multiplier, true);
2930    return S_OK;
2931}
2932
2933HRESULT STDMETHODCALLTYPE WebView::setPageSizeMultiplier(
2934    /* [in] */ float multiplier)
2935{
2936    if (!m_mainFrame)
2937        return E_FAIL;
2938    setZoomMultiplier(multiplier, false);
2939    return S_OK;
2940}
2941
2942void WebView::setZoomMultiplier(float multiplier, bool isTextOnly)
2943{
2944    m_zoomMultiplier = multiplier;
2945    m_zoomsTextOnly = isTextOnly;
2946
2947    if (Frame* coreFrame = core(m_mainFrame)) {
2948        if (m_zoomsTextOnly)
2949            coreFrame->setPageAndTextZoomFactors(1, multiplier);
2950        else
2951            coreFrame->setPageAndTextZoomFactors(multiplier, 1);
2952    }
2953}
2954
2955HRESULT STDMETHODCALLTYPE WebView::textSizeMultiplier(
2956    /* [retval][out] */ float* multiplier)
2957{
2958    *multiplier = zoomMultiplier(true);
2959    return S_OK;
2960}
2961
2962HRESULT STDMETHODCALLTYPE WebView::pageSizeMultiplier(
2963    /* [retval][out] */ float* multiplier)
2964{
2965    *multiplier = zoomMultiplier(false);
2966    return S_OK;
2967}
2968
2969float WebView::zoomMultiplier(bool isTextOnly)
2970{
2971    if (isTextOnly != m_zoomsTextOnly)
2972        return 1.0f;
2973    return m_zoomMultiplier;
2974}
2975
2976HRESULT STDMETHODCALLTYPE WebView::setApplicationNameForUserAgent(
2977    /* [in] */ BSTR applicationName)
2978{
2979    m_applicationName = String(applicationName, SysStringLen(applicationName));
2980    m_userAgentStandard = String();
2981    return S_OK;
2982}
2983
2984HRESULT STDMETHODCALLTYPE WebView::applicationNameForUserAgent(
2985    /* [retval][out] */ BSTR* applicationName)
2986{
2987    *applicationName = SysAllocStringLen(m_applicationName.characters(), m_applicationName.length());
2988    if (!*applicationName && m_applicationName.length())
2989        return E_OUTOFMEMORY;
2990    return S_OK;
2991}
2992
2993HRESULT STDMETHODCALLTYPE WebView::setCustomUserAgent(
2994    /* [in] */ BSTR userAgentString)
2995{
2996    m_userAgentOverridden = userAgentString;
2997    m_userAgentCustom = String(userAgentString, SysStringLen(userAgentString));
2998    return S_OK;
2999}
3000
3001HRESULT STDMETHODCALLTYPE WebView::customUserAgent(
3002    /* [retval][out] */ BSTR* userAgentString)
3003{
3004    *userAgentString = 0;
3005    if (!m_userAgentOverridden)
3006        return S_OK;
3007    *userAgentString = SysAllocStringLen(m_userAgentCustom.characters(), m_userAgentCustom.length());
3008    if (!*userAgentString && m_userAgentCustom.length())
3009        return E_OUTOFMEMORY;
3010    return S_OK;
3011}
3012
3013HRESULT STDMETHODCALLTYPE WebView::userAgentForURL(
3014    /* [in] */ BSTR url,
3015    /* [retval][out] */ BSTR* userAgent)
3016{
3017    String userAgentString = userAgentForKURL(MarshallingHelpers::BSTRToKURL(url));
3018    *userAgent = SysAllocStringLen(userAgentString.characters(), userAgentString.length());
3019    if (!*userAgent && userAgentString.length())
3020        return E_OUTOFMEMORY;
3021    return S_OK;
3022}
3023
3024HRESULT STDMETHODCALLTYPE WebView::supportsTextEncoding(
3025    /* [retval][out] */ BOOL* supports)
3026{
3027    *supports = TRUE;
3028    return S_OK;
3029}
3030
3031HRESULT STDMETHODCALLTYPE WebView::setCustomTextEncodingName(
3032    /* [in] */ BSTR encodingName)
3033{
3034    if (!m_mainFrame)
3035        return E_FAIL;
3036
3037    HRESULT hr;
3038    BSTR oldEncoding;
3039    hr = customTextEncodingName(&oldEncoding);
3040    if (FAILED(hr))
3041        return hr;
3042
3043    if (oldEncoding != encodingName && (!oldEncoding || !encodingName || wcscmp(oldEncoding, encodingName))) {
3044        if (Frame* coreFrame = core(m_mainFrame))
3045            coreFrame->loader()->reloadWithOverrideEncoding(String(encodingName, SysStringLen(encodingName)));
3046    }
3047
3048    return S_OK;
3049}
3050
3051HRESULT STDMETHODCALLTYPE WebView::customTextEncodingName(
3052    /* [retval][out] */ BSTR* encodingName)
3053{
3054    HRESULT hr = S_OK;
3055    COMPtr<IWebDataSource> dataSource;
3056    COMPtr<WebDataSource> dataSourceImpl;
3057    *encodingName = 0;
3058
3059    if (!m_mainFrame)
3060        return E_FAIL;
3061
3062    if (FAILED(m_mainFrame->provisionalDataSource(&dataSource)) || !dataSource) {
3063        hr = m_mainFrame->dataSource(&dataSource);
3064        if (FAILED(hr) || !dataSource)
3065            return hr;
3066    }
3067
3068    hr = dataSource->QueryInterface(IID_WebDataSource, (void**)&dataSourceImpl);
3069    if (FAILED(hr))
3070        return hr;
3071
3072    BString str = dataSourceImpl->documentLoader()->overrideEncoding();
3073    if (FAILED(hr))
3074        return hr;
3075
3076    if (!*encodingName)
3077        *encodingName = SysAllocStringLen(m_overrideEncoding.characters(), m_overrideEncoding.length());
3078
3079    if (!*encodingName && m_overrideEncoding.length())
3080        return E_OUTOFMEMORY;
3081
3082    return S_OK;
3083}
3084
3085HRESULT STDMETHODCALLTYPE WebView::setMediaStyle(
3086    /* [in] */ BSTR /*media*/)
3087{
3088    ASSERT_NOT_REACHED();
3089    return E_NOTIMPL;
3090}
3091
3092HRESULT STDMETHODCALLTYPE WebView::mediaStyle(
3093    /* [retval][out] */ BSTR* /*media*/)
3094{
3095    ASSERT_NOT_REACHED();
3096    return E_NOTIMPL;
3097}
3098
3099HRESULT STDMETHODCALLTYPE WebView::stringByEvaluatingJavaScriptFromString(
3100    /* [in] */ BSTR script, // assumes input does not have "JavaScript" at the begining.
3101    /* [retval][out] */ BSTR* result)
3102{
3103    if (!result) {
3104        ASSERT_NOT_REACHED();
3105        return E_POINTER;
3106    }
3107
3108    *result = 0;
3109
3110    Frame* coreFrame = core(m_mainFrame);
3111    if (!coreFrame)
3112        return E_FAIL;
3113
3114    JSC::JSValue scriptExecutionResult = coreFrame->script()->executeScript(WTF::String(script), true).jsValue();
3115    if (!scriptExecutionResult)
3116        return E_FAIL;
3117    else if (scriptExecutionResult.isString()) {
3118        JSLock lock(JSC::SilenceAssertionsOnly);
3119        JSC::ExecState* exec = coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec();
3120        *result = BString(ustringToString(scriptExecutionResult.getString(exec)));
3121    }
3122
3123    return S_OK;
3124}
3125
3126HRESULT STDMETHODCALLTYPE WebView::windowScriptObject(
3127    /* [retval][out] */ IWebScriptObject** /*webScriptObject*/)
3128{
3129    ASSERT_NOT_REACHED();
3130    return E_NOTIMPL;
3131}
3132
3133HRESULT STDMETHODCALLTYPE WebView::setPreferences(
3134    /* [in] */ IWebPreferences* prefs)
3135{
3136    if (!prefs)
3137        prefs = WebPreferences::sharedStandardPreferences();
3138
3139    if (m_preferences == prefs)
3140        return S_OK;
3141
3142    COMPtr<WebPreferences> webPrefs(Query, prefs);
3143    if (!webPrefs)
3144        return E_NOINTERFACE;
3145    webPrefs->willAddToWebView();
3146
3147    COMPtr<WebPreferences> oldPrefs = m_preferences;
3148
3149    IWebNotificationCenter* nc = WebNotificationCenter::defaultCenterInternal();
3150    nc->removeObserver(this, WebPreferences::webPreferencesChangedNotification(), static_cast<IWebPreferences*>(m_preferences.get()));
3151
3152    BSTR identifier = 0;
3153    oldPrefs->identifier(&identifier);
3154    oldPrefs->didRemoveFromWebView();
3155    oldPrefs = 0; // Make sure we release the reference, since WebPreferences::removeReferenceForIdentifier will check for last reference to WebPreferences
3156
3157    m_preferences = webPrefs;
3158
3159    if (identifier) {
3160        WebPreferences::removeReferenceForIdentifier(identifier);
3161        SysFreeString(identifier);
3162    }
3163
3164    nc->addObserver(this, WebPreferences::webPreferencesChangedNotification(), static_cast<IWebPreferences*>(m_preferences.get()));
3165
3166    m_preferences->postPreferencesChangesNotification();
3167
3168    return S_OK;
3169}
3170
3171HRESULT STDMETHODCALLTYPE WebView::preferences(
3172    /* [retval][out] */ IWebPreferences** prefs)
3173{
3174    if (!prefs)
3175        return E_POINTER;
3176    *prefs = m_preferences.get();
3177    if (m_preferences)
3178        m_preferences->AddRef();
3179    return S_OK;
3180}
3181
3182HRESULT STDMETHODCALLTYPE WebView::setPreferencesIdentifier(
3183    /* [in] */ BSTR /*anIdentifier*/)
3184{
3185    ASSERT_NOT_REACHED();
3186    return E_NOTIMPL;
3187}
3188
3189HRESULT STDMETHODCALLTYPE WebView::preferencesIdentifier(
3190    /* [retval][out] */ BSTR* /*anIdentifier*/)
3191{
3192    ASSERT_NOT_REACHED();
3193    return E_NOTIMPL;
3194}
3195
3196static void systemParameterChanged(WPARAM parameter)
3197{
3198#if USE(CG)
3199    if (parameter == SPI_SETFONTSMOOTHING || parameter == SPI_SETFONTSMOOTHINGTYPE || parameter == SPI_SETFONTSMOOTHINGCONTRAST || parameter == SPI_SETFONTSMOOTHINGORIENTATION)
3200        wkSystemFontSmoothingChanged();
3201#endif
3202}
3203
3204void WebView::windowReceivedMessage(HWND, UINT message, WPARAM wParam, LPARAM)
3205{
3206    switch (message) {
3207    case WM_NCACTIVATE:
3208        updateActiveStateSoon();
3209        if (!wParam)
3210            deleteBackingStoreSoon();
3211        break;
3212    case WM_SETTINGCHANGE:
3213        systemParameterChanged(wParam);
3214        break;
3215    }
3216}
3217
3218void WebView::updateActiveStateSoon() const
3219{
3220    // This function is called while processing the WM_NCACTIVATE message.
3221    // While processing WM_NCACTIVATE when we are being deactivated, GetActiveWindow() will
3222    // still return our window. If we were to call updateActiveState() in that case, we would
3223    // wrongly think that we are still the active window. To work around this, we update our
3224    // active state after a 0-delay timer fires, at which point GetActiveWindow() will return
3225    // the newly-activated window.
3226
3227    SetTimer(m_viewWindow, UpdateActiveStateTimer, 0, 0);
3228}
3229
3230void WebView::deleteBackingStoreSoon()
3231{
3232    if (pendingDeleteBackingStoreSet.size() > 2) {
3233        Vector<WebView*> views;
3234        HashSet<WebView*>::iterator end = pendingDeleteBackingStoreSet.end();
3235        for (HashSet<WebView*>::iterator it = pendingDeleteBackingStoreSet.begin(); it != end; ++it)
3236            views.append(*it);
3237        for (int i = 0; i < views.size(); ++i)
3238            views[i]->deleteBackingStore();
3239        ASSERT(pendingDeleteBackingStoreSet.isEmpty());
3240    }
3241
3242    pendingDeleteBackingStoreSet.add(this);
3243    m_deleteBackingStoreTimerActive = true;
3244    SetTimer(m_viewWindow, DeleteBackingStoreTimer, delayBeforeDeletingBackingStoreMsec, 0);
3245}
3246
3247void WebView::cancelDeleteBackingStoreSoon()
3248{
3249    if (!m_deleteBackingStoreTimerActive)
3250        return;
3251    pendingDeleteBackingStoreSet.remove(this);
3252    m_deleteBackingStoreTimerActive = false;
3253    KillTimer(m_viewWindow, DeleteBackingStoreTimer);
3254}
3255
3256HRESULT STDMETHODCALLTYPE WebView::setHostWindow(
3257    /* [in] */ OLE_HANDLE oleWindow)
3258{
3259    HWND window = (HWND)(ULONG64)oleWindow;
3260    if (m_viewWindow) {
3261        if (window)
3262            SetParent(m_viewWindow, window);
3263        else if (!isBeingDestroyed()) {
3264            // Turn the WebView into a message-only window so it will no longer be a child of the
3265            // old host window and will be hidden from screen. We only do this when
3266            // isBeingDestroyed() is false because doing this while handling WM_DESTROY can leave
3267            // m_viewWindow in a weird state (see <http://webkit.org/b/29337>).
3268            SetParent(m_viewWindow, HWND_MESSAGE);
3269        }
3270    }
3271
3272    m_hostWindow = window;
3273
3274    windowAncestryDidChange();
3275
3276    return S_OK;
3277}
3278
3279HRESULT STDMETHODCALLTYPE WebView::hostWindow(
3280    /* [retval][out] */ OLE_HANDLE* window)
3281{
3282    *window = (OLE_HANDLE)(ULONG64)m_hostWindow;
3283    return S_OK;
3284}
3285
3286
3287static Frame *incrementFrame(Frame *curr, bool forward, bool wrapFlag)
3288{
3289    return forward
3290        ? curr->tree()->traverseNextWithWrap(wrapFlag)
3291        : curr->tree()->traversePreviousWithWrap(wrapFlag);
3292}
3293
3294HRESULT STDMETHODCALLTYPE WebView::searchFor(
3295    /* [in] */ BSTR str,
3296    /* [in] */ BOOL forward,
3297    /* [in] */ BOOL caseFlag,
3298    /* [in] */ BOOL wrapFlag,
3299    /* [retval][out] */ BOOL* found)
3300{
3301    if (!found)
3302        return E_INVALIDARG;
3303
3304    if (!m_page || !m_page->mainFrame())
3305        return E_UNEXPECTED;
3306
3307    if (!str || !SysStringLen(str))
3308        return E_INVALIDARG;
3309
3310    *found = m_page->findString(String(str, SysStringLen(str)), caseFlag ? TextCaseSensitive : TextCaseInsensitive, forward ? FindDirectionForward : FindDirectionBackward, wrapFlag);
3311    return S_OK;
3312}
3313
3314bool WebView::active()
3315{
3316    HWND activeWindow = GetActiveWindow();
3317    return (activeWindow && m_topLevelParent == findTopLevelParent(activeWindow));
3318}
3319
3320void WebView::updateActiveState()
3321{
3322    m_page->focusController()->setActive(active());
3323}
3324
3325HRESULT STDMETHODCALLTYPE WebView::updateFocusedAndActiveState()
3326{
3327    updateActiveState();
3328
3329    bool active = m_page->focusController()->isActive();
3330    Frame* mainFrame = m_page->mainFrame();
3331    Frame* focusedFrame = m_page->focusController()->focusedOrMainFrame();
3332    mainFrame->selection()->setFocused(active && mainFrame == focusedFrame);
3333
3334    return S_OK;
3335}
3336
3337HRESULT STDMETHODCALLTYPE WebView::executeCoreCommandByName(BSTR bName, BSTR bValue)
3338{
3339    String name(bName, SysStringLen(bName));
3340    String value(bValue, SysStringLen(bValue));
3341
3342    m_page->focusController()->focusedOrMainFrame()->editor()->command(name).execute(value);
3343
3344    return S_OK;
3345}
3346
3347HRESULT STDMETHODCALLTYPE WebView::clearMainFrameName()
3348{
3349    m_page->mainFrame()->tree()->clearName();
3350
3351    return S_OK;
3352}
3353
3354HRESULT STDMETHODCALLTYPE WebView::markAllMatchesForText(
3355    BSTR str, BOOL caseSensitive, BOOL highlight, UINT limit, UINT* matches)
3356{
3357    if (!matches)
3358        return E_INVALIDARG;
3359
3360    if (!m_page || !m_page->mainFrame())
3361        return E_UNEXPECTED;
3362
3363    if (!str || !SysStringLen(str))
3364        return E_INVALIDARG;
3365
3366    *matches = m_page->markAllMatchesForText(String(str, SysStringLen(str)), caseSensitive ? TextCaseSensitive : TextCaseInsensitive, highlight, limit);
3367    return S_OK;
3368}
3369
3370HRESULT STDMETHODCALLTYPE WebView::unmarkAllTextMatches()
3371{
3372    if (!m_page || !m_page->mainFrame())
3373        return E_UNEXPECTED;
3374
3375    m_page->unmarkAllTextMatches();
3376    return S_OK;
3377}
3378
3379HRESULT STDMETHODCALLTYPE WebView::rectsForTextMatches(
3380    IEnumTextMatches** pmatches)
3381{
3382    Vector<IntRect> allRects;
3383    WebCore::Frame* frame = m_page->mainFrame();
3384    do {
3385        if (Document* document = frame->document()) {
3386            IntRect visibleRect = frame->view()->visibleContentRect();
3387            Vector<IntRect> frameRects = document->markers()->renderedRectsForMarkers(DocumentMarker::TextMatch);
3388            IntPoint frameOffset(-frame->view()->scrollOffset().width(), -frame->view()->scrollOffset().height());
3389            frameOffset = frame->view()->convertToContainingWindow(frameOffset);
3390
3391            Vector<IntRect>::iterator end = frameRects.end();
3392            for (Vector<IntRect>::iterator it = frameRects.begin(); it < end; it++) {
3393                it->intersect(visibleRect);
3394                it->move(frameOffset.x(), frameOffset.y());
3395                allRects.append(*it);
3396            }
3397        }
3398        frame = incrementFrame(frame, true, false);
3399    } while (frame);
3400
3401    return createMatchEnumerator(&allRects, pmatches);
3402}
3403
3404HRESULT STDMETHODCALLTYPE WebView::generateSelectionImage(BOOL forceWhiteText, OLE_HANDLE* hBitmap)
3405{
3406    *hBitmap = 0;
3407
3408    WebCore::Frame* frame = m_page->focusController()->focusedOrMainFrame();
3409
3410    if (frame) {
3411        HBITMAP bitmap = imageFromSelection(frame, forceWhiteText ? TRUE : FALSE);
3412        *hBitmap = (OLE_HANDLE)(ULONG64)bitmap;
3413    }
3414
3415    return S_OK;
3416}
3417
3418HRESULT STDMETHODCALLTYPE WebView::selectionRect(RECT* rc)
3419{
3420    WebCore::Frame* frame = m_page->focusController()->focusedOrMainFrame();
3421
3422    if (frame) {
3423        IntRect ir = enclosingIntRect(frame->selection()->bounds());
3424        ir = frame->view()->convertToContainingWindow(ir);
3425        ir.move(-frame->view()->scrollOffset().width(), -frame->view()->scrollOffset().height());
3426        rc->left = ir.x();
3427        rc->top = ir.y();
3428        rc->bottom = rc->top + ir.height();
3429        rc->right = rc->left + ir.width();
3430    }
3431
3432    return S_OK;
3433}
3434
3435HRESULT STDMETHODCALLTYPE WebView::registerViewClass(
3436    /* [in] */ IWebDocumentView* /*view*/,
3437    /* [in] */ IWebDocumentRepresentation* /*representation*/,
3438    /* [in] */ BSTR /*forMIMEType*/)
3439{
3440    ASSERT_NOT_REACHED();
3441    return E_NOTIMPL;
3442}
3443
3444HRESULT STDMETHODCALLTYPE WebView::setGroupName(
3445        /* [in] */ BSTR groupName)
3446{
3447    if (!m_page)
3448        return S_OK;
3449    m_page->setGroupName(String(groupName, SysStringLen(groupName)));
3450    return S_OK;
3451}
3452
3453HRESULT STDMETHODCALLTYPE WebView::groupName(
3454        /* [retval][out] */ BSTR* groupName)
3455{
3456    *groupName = 0;
3457    if (!m_page)
3458        return S_OK;
3459    String groupNameString = m_page->groupName();
3460    *groupName = SysAllocStringLen(groupNameString.characters(), groupNameString.length());
3461    if (!*groupName && groupNameString.length())
3462        return E_OUTOFMEMORY;
3463    return S_OK;
3464}
3465
3466HRESULT STDMETHODCALLTYPE WebView::estimatedProgress(
3467        /* [retval][out] */ double* estimatedProgress)
3468{
3469    *estimatedProgress = m_page->progress()->estimatedProgress();
3470    return S_OK;
3471}
3472
3473HRESULT STDMETHODCALLTYPE WebView::isLoading(
3474        /* [retval][out] */ BOOL* isLoading)
3475{
3476    COMPtr<IWebDataSource> dataSource;
3477    COMPtr<IWebDataSource> provisionalDataSource;
3478
3479    if (!isLoading)
3480        return E_POINTER;
3481
3482    *isLoading = FALSE;
3483
3484    if (!m_mainFrame)
3485        return E_FAIL;
3486
3487    if (SUCCEEDED(m_mainFrame->dataSource(&dataSource)))
3488        dataSource->isLoading(isLoading);
3489
3490    if (*isLoading)
3491        return S_OK;
3492
3493    if (SUCCEEDED(m_mainFrame->provisionalDataSource(&provisionalDataSource)))
3494        provisionalDataSource->isLoading(isLoading);
3495    return S_OK;
3496}
3497
3498HRESULT STDMETHODCALLTYPE WebView::elementAtPoint(
3499        /* [in] */ LPPOINT point,
3500        /* [retval][out] */ IPropertyBag** elementDictionary)
3501{
3502    if (!elementDictionary) {
3503        ASSERT_NOT_REACHED();
3504        return E_POINTER;
3505    }
3506
3507    *elementDictionary = 0;
3508
3509    Frame* frame = core(m_mainFrame);
3510    if (!frame)
3511        return E_FAIL;
3512
3513    IntPoint webCorePoint = IntPoint(point->x, point->y);
3514    HitTestResult result = HitTestResult(webCorePoint);
3515    if (frame->contentRenderer())
3516        result = frame->eventHandler()->hitTestResultAtPoint(webCorePoint, false);
3517    *elementDictionary = WebElementPropertyBag::createInstance(result);
3518    return S_OK;
3519}
3520
3521HRESULT STDMETHODCALLTYPE WebView::pasteboardTypesForSelection(
3522    /* [retval][out] */ IEnumVARIANT** /*enumVariant*/)
3523{
3524    ASSERT_NOT_REACHED();
3525    return E_NOTIMPL;
3526}
3527
3528HRESULT STDMETHODCALLTYPE WebView::writeSelectionWithPasteboardTypes(
3529        /* [size_is][in] */ BSTR* /*types*/,
3530        /* [in] */ int /*cTypes*/,
3531        /* [in] */ IDataObject* /*pasteboard*/)
3532{
3533    ASSERT_NOT_REACHED();
3534    return E_NOTIMPL;
3535}
3536
3537HRESULT STDMETHODCALLTYPE WebView::pasteboardTypesForElement(
3538    /* [in] */ IPropertyBag* /*elementDictionary*/,
3539    /* [retval][out] */ IEnumVARIANT** /*enumVariant*/)
3540{
3541    ASSERT_NOT_REACHED();
3542    return E_NOTIMPL;
3543}
3544
3545HRESULT STDMETHODCALLTYPE WebView::writeElement(
3546        /* [in] */ IPropertyBag* /*elementDictionary*/,
3547        /* [size_is][in] */ BSTR* /*withPasteboardTypes*/,
3548        /* [in] */ int /*cWithPasteboardTypes*/,
3549        /* [in] */ IDataObject* /*pasteboard*/)
3550{
3551    ASSERT_NOT_REACHED();
3552    return E_NOTIMPL;
3553}
3554
3555HRESULT STDMETHODCALLTYPE WebView::selectedText(
3556        /* [out, retval] */ BSTR* text)
3557{
3558    if (!text) {
3559        ASSERT_NOT_REACHED();
3560        return E_POINTER;
3561    }
3562
3563    *text = 0;
3564
3565    Frame* focusedFrame = (m_page && m_page->focusController()) ? m_page->focusController()->focusedOrMainFrame() : 0;
3566    if (!focusedFrame)
3567        return E_FAIL;
3568
3569    String frameSelectedText = focusedFrame->editor()->selectedText();
3570    *text = SysAllocStringLen(frameSelectedText.characters(), frameSelectedText.length());
3571    if (!*text && frameSelectedText.length())
3572        return E_OUTOFMEMORY;
3573    return S_OK;
3574}
3575
3576HRESULT STDMETHODCALLTYPE WebView::centerSelectionInVisibleArea(
3577        /* [in] */ IUnknown* /* sender */)
3578{
3579    Frame* coreFrame = core(m_mainFrame);
3580    if (!coreFrame)
3581        return E_FAIL;
3582
3583    coreFrame->selection()->revealSelection(ScrollAlignment::alignCenterAlways);
3584    return S_OK;
3585}
3586
3587
3588HRESULT STDMETHODCALLTYPE WebView::moveDragCaretToPoint(
3589        /* [in] */ LPPOINT /*point*/)
3590{
3591    ASSERT_NOT_REACHED();
3592    return E_NOTIMPL;
3593}
3594
3595HRESULT STDMETHODCALLTYPE WebView::removeDragCaret( void)
3596{
3597    ASSERT_NOT_REACHED();
3598    return E_NOTIMPL;
3599}
3600
3601HRESULT STDMETHODCALLTYPE WebView::setDrawsBackground(
3602        /* [in] */ BOOL /*drawsBackground*/)
3603{
3604    ASSERT_NOT_REACHED();
3605    return E_NOTIMPL;
3606}
3607
3608HRESULT STDMETHODCALLTYPE WebView::drawsBackground(
3609        /* [retval][out] */ BOOL* /*drawsBackground*/)
3610{
3611    ASSERT_NOT_REACHED();
3612    return E_NOTIMPL;
3613}
3614
3615HRESULT STDMETHODCALLTYPE WebView::setMainFrameURL(
3616        /* [in] */ BSTR /*urlString*/)
3617{
3618    ASSERT_NOT_REACHED();
3619    return E_NOTIMPL;
3620}
3621
3622HRESULT STDMETHODCALLTYPE WebView::mainFrameURL(
3623        /* [retval][out] */ BSTR* urlString)
3624{
3625    if (!urlString)
3626        return E_POINTER;
3627
3628    if (!m_mainFrame)
3629        return E_FAIL;
3630
3631    COMPtr<IWebDataSource> dataSource;
3632
3633    if (FAILED(m_mainFrame->provisionalDataSource(&dataSource))) {
3634        if (FAILED(m_mainFrame->dataSource(&dataSource)))
3635            return E_FAIL;
3636    }
3637
3638    if (!dataSource) {
3639        *urlString = 0;
3640        return S_OK;
3641    }
3642
3643    COMPtr<IWebMutableURLRequest> request;
3644    if (FAILED(dataSource->request(&request)) || !request)
3645        return E_FAIL;
3646
3647    if (FAILED(request->URL(urlString)))
3648        return E_FAIL;
3649
3650    return S_OK;
3651}
3652
3653HRESULT STDMETHODCALLTYPE WebView::mainFrameDocument(
3654        /* [retval][out] */ IDOMDocument** document)
3655{
3656    if (document)
3657        *document = 0;
3658    if (!m_mainFrame)
3659        return E_FAIL;
3660    return m_mainFrame->DOMDocument(document);
3661}
3662
3663HRESULT STDMETHODCALLTYPE WebView::mainFrameTitle(
3664        /* [retval][out] */ BSTR* /*title*/)
3665{
3666    ASSERT_NOT_REACHED();
3667    return E_NOTIMPL;
3668}
3669
3670HRESULT STDMETHODCALLTYPE WebView::mainFrameIcon(
3671        /* [retval][out] */ OLE_HANDLE* /*hBitmap*/)
3672{
3673    ASSERT_NOT_REACHED();
3674    return E_NOTIMPL;
3675}
3676
3677HRESULT STDMETHODCALLTYPE WebView::registerURLSchemeAsLocal(
3678        /* [in] */ BSTR scheme)
3679{
3680    if (!scheme)
3681        return E_POINTER;
3682
3683    SchemeRegistry::registerURLSchemeAsLocal(String(scheme, ::SysStringLen(scheme)));
3684
3685    return S_OK;
3686}
3687
3688// IWebIBActions ---------------------------------------------------------------
3689
3690HRESULT STDMETHODCALLTYPE WebView::takeStringURLFrom(
3691        /* [in] */ IUnknown* /*sender*/)
3692{
3693    ASSERT_NOT_REACHED();
3694    return E_NOTIMPL;
3695}
3696
3697HRESULT STDMETHODCALLTYPE WebView::stopLoading(
3698        /* [in] */ IUnknown* /*sender*/)
3699{
3700    if (!m_mainFrame)
3701        return E_FAIL;
3702
3703    return m_mainFrame->stopLoading();
3704}
3705
3706HRESULT STDMETHODCALLTYPE WebView::reload(
3707        /* [in] */ IUnknown* /*sender*/)
3708{
3709    if (!m_mainFrame)
3710        return E_FAIL;
3711
3712    return m_mainFrame->reload();
3713}
3714
3715HRESULT STDMETHODCALLTYPE WebView::canGoBack(
3716        /* [in] */ IUnknown* /*sender*/,
3717        /* [retval][out] */ BOOL* result)
3718{
3719    *result = !!(m_page->backForwardList()->backItem() && !m_page->defersLoading());
3720    return S_OK;
3721}
3722
3723HRESULT STDMETHODCALLTYPE WebView::goBack(
3724        /* [in] */ IUnknown* /*sender*/)
3725{
3726    ASSERT_NOT_REACHED();
3727    return E_NOTIMPL;
3728}
3729
3730HRESULT STDMETHODCALLTYPE WebView::canGoForward(
3731        /* [in] */ IUnknown* /*sender*/,
3732        /* [retval][out] */ BOOL* result)
3733{
3734    *result = !!(m_page->backForwardList()->forwardItem() && !m_page->defersLoading());
3735    return S_OK;
3736}
3737
3738HRESULT STDMETHODCALLTYPE WebView::goForward(
3739        /* [in] */ IUnknown* /*sender*/)
3740{
3741    ASSERT_NOT_REACHED();
3742    return E_NOTIMPL;
3743}
3744
3745// FIXME: This code should move into WebCore so it can be shared by all the WebKits.
3746#define MinimumZoomMultiplier   0.5f
3747#define MaximumZoomMultiplier   3.0f
3748#define ZoomMultiplierRatio     1.2f
3749
3750HRESULT STDMETHODCALLTYPE WebView::canMakeTextLarger(
3751        /* [in] */ IUnknown* /*sender*/,
3752        /* [retval][out] */ BOOL* result)
3753{
3754    bool canGrowMore = canZoomIn(m_zoomsTextOnly);
3755    *result = canGrowMore ? TRUE : FALSE;
3756    return S_OK;
3757}
3758
3759HRESULT STDMETHODCALLTYPE WebView::canZoomPageIn(
3760        /* [in] */ IUnknown* /*sender*/,
3761        /* [retval][out] */ BOOL* result)
3762{
3763    bool canGrowMore = canZoomIn(false);
3764    *result = canGrowMore ? TRUE : FALSE;
3765    return S_OK;
3766}
3767
3768bool WebView::canZoomIn(bool isTextOnly)
3769{
3770    return zoomMultiplier(isTextOnly) * ZoomMultiplierRatio < MaximumZoomMultiplier;
3771}
3772
3773HRESULT STDMETHODCALLTYPE WebView::makeTextLarger(
3774        /* [in] */ IUnknown* /*sender*/)
3775{
3776    return zoomIn(m_zoomsTextOnly);
3777}
3778
3779HRESULT STDMETHODCALLTYPE WebView::zoomPageIn(
3780        /* [in] */ IUnknown* /*sender*/)
3781{
3782    return zoomIn(false);
3783}
3784
3785HRESULT WebView::zoomIn(bool isTextOnly)
3786{
3787    if (!canZoomIn(isTextOnly))
3788        return E_FAIL;
3789    setZoomMultiplier(zoomMultiplier(isTextOnly) * ZoomMultiplierRatio, isTextOnly);
3790    return S_OK;
3791}
3792
3793HRESULT STDMETHODCALLTYPE WebView::canMakeTextSmaller(
3794        /* [in] */ IUnknown* /*sender*/,
3795        /* [retval][out] */ BOOL* result)
3796{
3797    bool canShrinkMore = canZoomOut(m_zoomsTextOnly);
3798    *result = canShrinkMore ? TRUE : FALSE;
3799    return S_OK;
3800}
3801
3802HRESULT STDMETHODCALLTYPE WebView::canZoomPageOut(
3803        /* [in] */ IUnknown* /*sender*/,
3804        /* [retval][out] */ BOOL* result)
3805{
3806    bool canShrinkMore = canZoomOut(false);
3807    *result = canShrinkMore ? TRUE : FALSE;
3808    return S_OK;
3809}
3810
3811bool WebView::canZoomOut(bool isTextOnly)
3812{
3813    return zoomMultiplier(isTextOnly) / ZoomMultiplierRatio > MinimumZoomMultiplier;
3814}
3815
3816HRESULT STDMETHODCALLTYPE WebView::makeTextSmaller(
3817        /* [in] */ IUnknown* /*sender*/)
3818{
3819    return zoomOut(m_zoomsTextOnly);
3820}
3821
3822HRESULT STDMETHODCALLTYPE WebView::zoomPageOut(
3823        /* [in] */ IUnknown* /*sender*/)
3824{
3825    return zoomOut(false);
3826}
3827
3828HRESULT WebView::zoomOut(bool isTextOnly)
3829{
3830    if (!canZoomOut(isTextOnly))
3831        return E_FAIL;
3832    setZoomMultiplier(zoomMultiplier(isTextOnly) / ZoomMultiplierRatio, isTextOnly);
3833    return S_OK;
3834}
3835
3836HRESULT STDMETHODCALLTYPE WebView::canMakeTextStandardSize(
3837    /* [in] */ IUnknown* /*sender*/,
3838    /* [retval][out] */ BOOL* result)
3839{
3840    // Since we always reset text zoom and page zoom together, this should continue to return an answer about text zoom even if its not enabled.
3841    bool notAlreadyStandard = canResetZoom(true);
3842    *result = notAlreadyStandard ? TRUE : FALSE;
3843    return S_OK;
3844}
3845
3846HRESULT STDMETHODCALLTYPE WebView::canResetPageZoom(
3847    /* [in] */ IUnknown* /*sender*/,
3848    /* [retval][out] */ BOOL* result)
3849{
3850    bool notAlreadyStandard = canResetZoom(false);
3851    *result = notAlreadyStandard ? TRUE : FALSE;
3852    return S_OK;
3853}
3854
3855bool WebView::canResetZoom(bool isTextOnly)
3856{
3857    return zoomMultiplier(isTextOnly) != 1.0f;
3858}
3859
3860HRESULT STDMETHODCALLTYPE WebView::makeTextStandardSize(
3861    /* [in] */ IUnknown* /*sender*/)
3862{
3863    return resetZoom(true);
3864}
3865
3866HRESULT STDMETHODCALLTYPE WebView::resetPageZoom(
3867    /* [in] */ IUnknown* /*sender*/)
3868{
3869    return resetZoom(false);
3870}
3871
3872HRESULT WebView::resetZoom(bool isTextOnly)
3873{
3874    if (!canResetZoom(isTextOnly))
3875        return E_FAIL;
3876    setZoomMultiplier(1.0f, isTextOnly);
3877    return S_OK;
3878}
3879
3880HRESULT STDMETHODCALLTYPE WebView::toggleContinuousSpellChecking(
3881    /* [in] */ IUnknown* /*sender*/)
3882{
3883    HRESULT hr;
3884    BOOL enabled;
3885    if (FAILED(hr = isContinuousSpellCheckingEnabled(&enabled)))
3886        return hr;
3887    return setContinuousSpellCheckingEnabled(enabled ? FALSE : TRUE);
3888}
3889
3890HRESULT STDMETHODCALLTYPE WebView::toggleSmartInsertDelete(
3891    /* [in] */ IUnknown* /*sender*/)
3892{
3893    BOOL enabled = FALSE;
3894    HRESULT hr = smartInsertDeleteEnabled(&enabled);
3895    if (FAILED(hr))
3896        return hr;
3897
3898    return setSmartInsertDeleteEnabled(enabled ? FALSE : TRUE);
3899}
3900
3901HRESULT STDMETHODCALLTYPE WebView::toggleGrammarChecking(
3902    /* [in] */ IUnknown* /*sender*/)
3903{
3904    BOOL enabled;
3905    HRESULT hr = isGrammarCheckingEnabled(&enabled);
3906    if (FAILED(hr))
3907        return hr;
3908
3909    return setGrammarCheckingEnabled(enabled ? FALSE : TRUE);
3910}
3911
3912HRESULT STDMETHODCALLTYPE WebView::reloadFromOrigin(
3913        /* [in] */ IUnknown* /*sender*/)
3914{
3915    if (!m_mainFrame)
3916        return E_FAIL;
3917
3918    return m_mainFrame->reloadFromOrigin();
3919}
3920
3921// IWebViewCSS -----------------------------------------------------------------
3922
3923HRESULT STDMETHODCALLTYPE WebView::computedStyleForElement(
3924        /* [in] */ IDOMElement* /*element*/,
3925        /* [in] */ BSTR /*pseudoElement*/,
3926        /* [retval][out] */ IDOMCSSStyleDeclaration** /*style*/)
3927{
3928    ASSERT_NOT_REACHED();
3929    return E_NOTIMPL;
3930}
3931
3932// IWebViewEditing -------------------------------------------------------------
3933
3934HRESULT STDMETHODCALLTYPE WebView::editableDOMRangeForPoint(
3935        /* [in] */ LPPOINT /*point*/,
3936        /* [retval][out] */ IDOMRange** /*range*/)
3937{
3938    ASSERT_NOT_REACHED();
3939    return E_NOTIMPL;
3940}
3941
3942HRESULT STDMETHODCALLTYPE WebView::setSelectedDOMRange(
3943        /* [in] */ IDOMRange* /*range*/,
3944        /* [in] */ WebSelectionAffinity /*affinity*/)
3945{
3946    ASSERT_NOT_REACHED();
3947    return E_NOTIMPL;
3948}
3949
3950HRESULT STDMETHODCALLTYPE WebView::selectedDOMRange(
3951        /* [retval][out] */ IDOMRange** /*range*/)
3952{
3953    ASSERT_NOT_REACHED();
3954    return E_NOTIMPL;
3955}
3956
3957HRESULT STDMETHODCALLTYPE WebView::selectionAffinity(
3958        /* [retval][out][retval][out] */ WebSelectionAffinity* /*affinity*/)
3959{
3960    ASSERT_NOT_REACHED();
3961    return E_NOTIMPL;
3962}
3963
3964HRESULT STDMETHODCALLTYPE WebView::setEditable(
3965        /* [in] */ BOOL /*flag*/)
3966{
3967    ASSERT_NOT_REACHED();
3968    return E_NOTIMPL;
3969}
3970
3971HRESULT STDMETHODCALLTYPE WebView::isEditable(
3972        /* [retval][out] */ BOOL* /*isEditable*/)
3973{
3974    ASSERT_NOT_REACHED();
3975    return E_NOTIMPL;
3976}
3977
3978HRESULT STDMETHODCALLTYPE WebView::setTypingStyle(
3979        /* [in] */ IDOMCSSStyleDeclaration* /*style*/)
3980{
3981    ASSERT_NOT_REACHED();
3982    return E_NOTIMPL;
3983}
3984
3985HRESULT STDMETHODCALLTYPE WebView::typingStyle(
3986        /* [retval][out] */ IDOMCSSStyleDeclaration** /*style*/)
3987{
3988    ASSERT_NOT_REACHED();
3989    return E_NOTIMPL;
3990}
3991
3992HRESULT STDMETHODCALLTYPE WebView::setSmartInsertDeleteEnabled(
3993        /* [in] */ BOOL flag)
3994{
3995    m_smartInsertDeleteEnabled = !!flag;
3996    if (m_smartInsertDeleteEnabled)
3997        setSelectTrailingWhitespaceEnabled(false);
3998    return S_OK;
3999}
4000
4001HRESULT STDMETHODCALLTYPE WebView::smartInsertDeleteEnabled(
4002        /* [retval][out] */ BOOL* enabled)
4003{
4004    *enabled = m_smartInsertDeleteEnabled ? TRUE : FALSE;
4005    return S_OK;
4006}
4007
4008HRESULT STDMETHODCALLTYPE WebView::setSelectTrailingWhitespaceEnabled(
4009        /* [in] */ BOOL flag)
4010{
4011    m_selectTrailingWhitespaceEnabled = !!flag;
4012    if (m_selectTrailingWhitespaceEnabled)
4013        setSmartInsertDeleteEnabled(false);
4014    return S_OK;
4015}
4016
4017HRESULT STDMETHODCALLTYPE WebView::isSelectTrailingWhitespaceEnabled(
4018        /* [retval][out] */ BOOL* enabled)
4019{
4020    *enabled = m_selectTrailingWhitespaceEnabled ? TRUE : FALSE;
4021    return S_OK;
4022}
4023
4024HRESULT STDMETHODCALLTYPE WebView::setContinuousSpellCheckingEnabled(
4025        /* [in] */ BOOL flag)
4026{
4027    if (continuousSpellCheckingEnabled != !!flag) {
4028        continuousSpellCheckingEnabled = !!flag;
4029        COMPtr<IWebPreferences> prefs;
4030        if (SUCCEEDED(preferences(&prefs)))
4031            prefs->setContinuousSpellCheckingEnabled(flag);
4032    }
4033
4034    BOOL spellCheckingEnabled;
4035    if (SUCCEEDED(isContinuousSpellCheckingEnabled(&spellCheckingEnabled)) && spellCheckingEnabled)
4036        preflightSpellChecker();
4037    else
4038        m_mainFrame->unmarkAllMisspellings();
4039
4040    return S_OK;
4041}
4042
4043HRESULT STDMETHODCALLTYPE WebView::isContinuousSpellCheckingEnabled(
4044        /* [retval][out] */ BOOL* enabled)
4045{
4046    *enabled = (continuousSpellCheckingEnabled && continuousCheckingAllowed()) ? TRUE : FALSE;
4047    return S_OK;
4048}
4049
4050HRESULT STDMETHODCALLTYPE WebView::spellCheckerDocumentTag(
4051        /* [retval][out] */ int* tag)
4052{
4053    // we just use this as a flag to indicate that we've spell checked the document
4054    // and need to close the spell checker out when the view closes.
4055    *tag = 0;
4056    m_hasSpellCheckerDocumentTag = true;
4057    return S_OK;
4058}
4059
4060static COMPtr<IWebEditingDelegate> spellingDelegateForTimer;
4061
4062static void preflightSpellCheckerNow()
4063{
4064    spellingDelegateForTimer->preflightChosenSpellServer();
4065    spellingDelegateForTimer = 0;
4066}
4067
4068static void CALLBACK preflightSpellCheckerTimerCallback(HWND, UINT, UINT_PTR id, DWORD)
4069{
4070    ::KillTimer(0, id);
4071    preflightSpellCheckerNow();
4072}
4073
4074void WebView::preflightSpellChecker()
4075{
4076    // As AppKit does, we wish to delay tickling the shared spellchecker into existence on application launch.
4077    if (!m_editingDelegate)
4078        return;
4079
4080    BOOL exists;
4081    spellingDelegateForTimer = m_editingDelegate;
4082    if (SUCCEEDED(m_editingDelegate->sharedSpellCheckerExists(&exists)) && exists)
4083        preflightSpellCheckerNow();
4084    else
4085        ::SetTimer(0, 0, 2000, preflightSpellCheckerTimerCallback);
4086}
4087
4088bool WebView::continuousCheckingAllowed()
4089{
4090    static bool allowContinuousSpellChecking = true;
4091    static bool readAllowContinuousSpellCheckingDefault = false;
4092    if (!readAllowContinuousSpellCheckingDefault) {
4093        COMPtr<IWebPreferences> prefs;
4094        if (SUCCEEDED(preferences(&prefs))) {
4095            BOOL allowed;
4096            prefs->allowContinuousSpellChecking(&allowed);
4097            allowContinuousSpellChecking = !!allowed;
4098        }
4099        readAllowContinuousSpellCheckingDefault = true;
4100    }
4101    return allowContinuousSpellChecking;
4102}
4103
4104HRESULT STDMETHODCALLTYPE WebView::undoManager(
4105        /* [retval][out] */ IWebUndoManager** /*manager*/)
4106{
4107    ASSERT_NOT_REACHED();
4108    return E_NOTIMPL;
4109}
4110
4111HRESULT STDMETHODCALLTYPE WebView::setEditingDelegate(
4112        /* [in] */ IWebEditingDelegate* d)
4113{
4114    m_editingDelegate = d;
4115    return S_OK;
4116}
4117
4118HRESULT STDMETHODCALLTYPE WebView::editingDelegate(
4119        /* [retval][out] */ IWebEditingDelegate** d)
4120{
4121    if (!d) {
4122        ASSERT_NOT_REACHED();
4123        return E_POINTER;
4124    }
4125
4126    *d = m_editingDelegate.get();
4127    if (!*d)
4128        return E_FAIL;
4129
4130    (*d)->AddRef();
4131    return S_OK;
4132}
4133
4134HRESULT STDMETHODCALLTYPE WebView::styleDeclarationWithText(
4135        /* [in] */ BSTR /*text*/,
4136        /* [retval][out] */ IDOMCSSStyleDeclaration** /*style*/)
4137{
4138    ASSERT_NOT_REACHED();
4139    return E_NOTIMPL;
4140}
4141
4142HRESULT STDMETHODCALLTYPE WebView::hasSelectedRange(
4143        /* [retval][out] */ BOOL* hasSelectedRange)
4144{
4145    *hasSelectedRange = m_page->mainFrame()->selection()->isRange();
4146    return S_OK;
4147}
4148
4149HRESULT STDMETHODCALLTYPE WebView::cutEnabled(
4150        /* [retval][out] */ BOOL* enabled)
4151{
4152    Editor* editor = m_page->focusController()->focusedOrMainFrame()->editor();
4153    *enabled = editor->canCut() || editor->canDHTMLCut();
4154    return S_OK;
4155}
4156
4157HRESULT STDMETHODCALLTYPE WebView::copyEnabled(
4158        /* [retval][out] */ BOOL* enabled)
4159{
4160    Editor* editor = m_page->focusController()->focusedOrMainFrame()->editor();
4161    *enabled = editor->canCopy() || editor->canDHTMLCopy();
4162    return S_OK;
4163}
4164
4165HRESULT STDMETHODCALLTYPE WebView::pasteEnabled(
4166        /* [retval][out] */ BOOL* enabled)
4167{
4168    Editor* editor = m_page->focusController()->focusedOrMainFrame()->editor();
4169    *enabled = editor->canPaste() || editor->canDHTMLPaste();
4170    return S_OK;
4171}
4172
4173HRESULT STDMETHODCALLTYPE WebView::deleteEnabled(
4174        /* [retval][out] */ BOOL* enabled)
4175{
4176    *enabled = m_page->focusController()->focusedOrMainFrame()->editor()->canDelete();
4177    return S_OK;
4178}
4179
4180HRESULT STDMETHODCALLTYPE WebView::editingEnabled(
4181        /* [retval][out] */ BOOL* enabled)
4182{
4183    *enabled = m_page->focusController()->focusedOrMainFrame()->editor()->canEdit();
4184    return S_OK;
4185}
4186
4187HRESULT STDMETHODCALLTYPE WebView::isGrammarCheckingEnabled(
4188    /* [retval][out] */ BOOL* enabled)
4189{
4190    *enabled = grammarCheckingEnabled ? TRUE : FALSE;
4191    return S_OK;
4192}
4193
4194HRESULT STDMETHODCALLTYPE WebView::setGrammarCheckingEnabled(
4195    BOOL enabled)
4196{
4197    if (!m_editingDelegate) {
4198        LOG_ERROR("No NSSpellChecker");
4199        return E_FAIL;
4200    }
4201
4202    if (grammarCheckingEnabled == !!enabled)
4203        return S_OK;
4204
4205    grammarCheckingEnabled = !!enabled;
4206    COMPtr<IWebPreferences> prefs;
4207    if (SUCCEEDED(preferences(&prefs)))
4208        prefs->setGrammarCheckingEnabled(enabled);
4209
4210    m_editingDelegate->updateGrammar();
4211
4212    // We call _preflightSpellChecker when turning continuous spell checking on, but we don't need to do that here
4213    // because grammar checking only occurs on code paths that already preflight spell checking appropriately.
4214
4215    BOOL grammarEnabled;
4216    if (SUCCEEDED(isGrammarCheckingEnabled(&grammarEnabled)) && !grammarEnabled)
4217        m_mainFrame->unmarkAllBadGrammar();
4218
4219    return S_OK;
4220}
4221
4222// IWebViewUndoableEditing -----------------------------------------------------
4223
4224HRESULT STDMETHODCALLTYPE WebView::replaceSelectionWithNode(
4225        /* [in] */ IDOMNode* /*node*/)
4226{
4227    ASSERT_NOT_REACHED();
4228    return E_NOTIMPL;
4229}
4230
4231HRESULT STDMETHODCALLTYPE WebView::replaceSelectionWithText(
4232        /* [in] */ BSTR text)
4233{
4234    String textString(text, ::SysStringLen(text));
4235    Position start = m_page->mainFrame()->selection()->selection().start();
4236    m_page->focusController()->focusedOrMainFrame()->editor()->insertText(textString, 0);
4237    m_page->mainFrame()->selection()->setBase(start);
4238    return S_OK;
4239}
4240
4241HRESULT STDMETHODCALLTYPE WebView::replaceSelectionWithMarkupString(
4242        /* [in] */ BSTR /*markupString*/)
4243{
4244    ASSERT_NOT_REACHED();
4245    return E_NOTIMPL;
4246}
4247
4248HRESULT STDMETHODCALLTYPE WebView::replaceSelectionWithArchive(
4249        /* [in] */ IWebArchive* /*archive*/)
4250{
4251    ASSERT_NOT_REACHED();
4252    return E_NOTIMPL;
4253}
4254
4255HRESULT STDMETHODCALLTYPE WebView::deleteSelection( void)
4256{
4257    Editor* editor = m_page->focusController()->focusedOrMainFrame()->editor();
4258    editor->deleteSelectionWithSmartDelete(editor->canSmartCopyOrDelete());
4259    return S_OK;
4260}
4261
4262HRESULT STDMETHODCALLTYPE WebView::clearSelection( void)
4263{
4264    m_page->focusController()->focusedOrMainFrame()->selection()->clear();
4265    return S_OK;
4266}
4267
4268HRESULT STDMETHODCALLTYPE WebView::applyStyle(
4269        /* [in] */ IDOMCSSStyleDeclaration* /*style*/)
4270{
4271    ASSERT_NOT_REACHED();
4272    return E_NOTIMPL;
4273}
4274
4275// IWebViewEditingActions ------------------------------------------------------
4276
4277HRESULT STDMETHODCALLTYPE WebView::copy(
4278        /* [in] */ IUnknown* /*sender*/)
4279{
4280    m_page->focusController()->focusedOrMainFrame()->editor()->command("Copy").execute();
4281    return S_OK;
4282}
4283
4284HRESULT STDMETHODCALLTYPE WebView::cut(
4285        /* [in] */ IUnknown* /*sender*/)
4286{
4287    m_page->focusController()->focusedOrMainFrame()->editor()->command("Cut").execute();
4288    return S_OK;
4289}
4290
4291HRESULT STDMETHODCALLTYPE WebView::paste(
4292        /* [in] */ IUnknown* /*sender*/)
4293{
4294    m_page->focusController()->focusedOrMainFrame()->editor()->command("Paste").execute();
4295    return S_OK;
4296}
4297
4298HRESULT STDMETHODCALLTYPE WebView::copyURL(
4299        /* [in] */ BSTR url)
4300{
4301    m_page->focusController()->focusedOrMainFrame()->editor()->copyURL(MarshallingHelpers::BSTRToKURL(url), "");
4302    return S_OK;
4303}
4304
4305
4306HRESULT STDMETHODCALLTYPE WebView::copyFont(
4307        /* [in] */ IUnknown* /*sender*/)
4308{
4309    ASSERT_NOT_REACHED();
4310    return E_NOTIMPL;
4311}
4312
4313HRESULT STDMETHODCALLTYPE WebView::pasteFont(
4314        /* [in] */ IUnknown* /*sender*/)
4315{
4316    ASSERT_NOT_REACHED();
4317    return E_NOTIMPL;
4318}
4319
4320HRESULT STDMETHODCALLTYPE WebView::delete_(
4321        /* [in] */ IUnknown* /*sender*/)
4322{
4323    m_page->focusController()->focusedOrMainFrame()->editor()->command("Delete").execute();
4324    return S_OK;
4325}
4326
4327HRESULT STDMETHODCALLTYPE WebView::pasteAsPlainText(
4328        /* [in] */ IUnknown* /*sender*/)
4329{
4330    ASSERT_NOT_REACHED();
4331    return E_NOTIMPL;
4332}
4333
4334HRESULT STDMETHODCALLTYPE WebView::pasteAsRichText(
4335        /* [in] */ IUnknown* /*sender*/)
4336{
4337    ASSERT_NOT_REACHED();
4338    return E_NOTIMPL;
4339}
4340
4341HRESULT STDMETHODCALLTYPE WebView::changeFont(
4342        /* [in] */ IUnknown* /*sender*/)
4343{
4344    ASSERT_NOT_REACHED();
4345    return E_NOTIMPL;
4346}
4347
4348HRESULT STDMETHODCALLTYPE WebView::changeAttributes(
4349        /* [in] */ IUnknown* /*sender*/)
4350{
4351    ASSERT_NOT_REACHED();
4352    return E_NOTIMPL;
4353}
4354
4355HRESULT STDMETHODCALLTYPE WebView::changeDocumentBackgroundColor(
4356        /* [in] */ IUnknown* /*sender*/)
4357{
4358    ASSERT_NOT_REACHED();
4359    return E_NOTIMPL;
4360}
4361
4362HRESULT STDMETHODCALLTYPE WebView::changeColor(
4363        /* [in] */ IUnknown* /*sender*/)
4364{
4365    ASSERT_NOT_REACHED();
4366    return E_NOTIMPL;
4367}
4368
4369HRESULT STDMETHODCALLTYPE WebView::alignCenter(
4370        /* [in] */ IUnknown* /*sender*/)
4371{
4372    ASSERT_NOT_REACHED();
4373    return E_NOTIMPL;
4374}
4375
4376HRESULT STDMETHODCALLTYPE WebView::alignJustified(
4377        /* [in] */ IUnknown* /*sender*/)
4378{
4379    ASSERT_NOT_REACHED();
4380    return E_NOTIMPL;
4381}
4382
4383HRESULT STDMETHODCALLTYPE WebView::alignLeft(
4384        /* [in] */ IUnknown* /*sender*/)
4385{
4386    ASSERT_NOT_REACHED();
4387    return E_NOTIMPL;
4388}
4389
4390HRESULT STDMETHODCALLTYPE WebView::alignRight(
4391        /* [in] */ IUnknown* /*sender*/)
4392{
4393    ASSERT_NOT_REACHED();
4394    return E_NOTIMPL;
4395}
4396
4397HRESULT STDMETHODCALLTYPE WebView::checkSpelling(
4398        /* [in] */ IUnknown* /*sender*/)
4399{
4400    if (!m_editingDelegate) {
4401        LOG_ERROR("No NSSpellChecker");
4402        return E_FAIL;
4403    }
4404
4405    core(m_mainFrame)->editor()->advanceToNextMisspelling();
4406    return S_OK;
4407}
4408
4409HRESULT STDMETHODCALLTYPE WebView::showGuessPanel(
4410        /* [in] */ IUnknown* /*sender*/)
4411{
4412    if (!m_editingDelegate) {
4413        LOG_ERROR("No NSSpellChecker");
4414        return E_FAIL;
4415    }
4416
4417    // Post-Tiger, this menu item is a show/hide toggle, to match AppKit. Leave Tiger behavior alone
4418    // to match rest of OS X.
4419    BOOL showing;
4420    if (SUCCEEDED(m_editingDelegate->spellingUIIsShowing(&showing)) && showing) {
4421        m_editingDelegate->showSpellingUI(FALSE);
4422    }
4423
4424    core(m_mainFrame)->editor()->advanceToNextMisspelling(true);
4425    m_editingDelegate->showSpellingUI(TRUE);
4426    return S_OK;
4427}
4428
4429HRESULT STDMETHODCALLTYPE WebView::performFindPanelAction(
4430        /* [in] */ IUnknown* /*sender*/)
4431{
4432    ASSERT_NOT_REACHED();
4433    return E_NOTIMPL;
4434}
4435
4436HRESULT STDMETHODCALLTYPE WebView::startSpeaking(
4437        /* [in] */ IUnknown* /*sender*/)
4438{
4439    ASSERT_NOT_REACHED();
4440    return E_NOTIMPL;
4441}
4442
4443HRESULT STDMETHODCALLTYPE WebView::stopSpeaking(
4444        /* [in] */ IUnknown* /*sender*/)
4445{
4446    ASSERT_NOT_REACHED();
4447    return E_NOTIMPL;
4448}
4449
4450// IWebNotificationObserver -----------------------------------------------------------------
4451
4452HRESULT STDMETHODCALLTYPE WebView::onNotify(
4453    /* [in] */ IWebNotification* notification)
4454{
4455    BSTR nameBSTR;
4456    HRESULT hr = notification->name(&nameBSTR);
4457    if (FAILED(hr))
4458        return hr;
4459
4460    BString name;
4461    name.adoptBSTR(nameBSTR);
4462
4463    if (!wcscmp(name, WebIconDatabase::iconDatabaseDidAddIconNotification()))
4464        return notifyDidAddIcon(notification);
4465
4466    if (!wcscmp(name, WebPreferences::webPreferencesChangedNotification()))
4467        return notifyPreferencesChanged(notification);
4468
4469    return hr;
4470}
4471
4472HRESULT WebView::notifyPreferencesChanged(IWebNotification* notification)
4473{
4474    HRESULT hr;
4475
4476    COMPtr<IUnknown> unkPrefs;
4477    hr = notification->getObject(&unkPrefs);
4478    if (FAILED(hr))
4479        return hr;
4480
4481    COMPtr<IWebPreferences> preferences(Query, unkPrefs);
4482    if (!preferences)
4483        return E_NOINTERFACE;
4484
4485    ASSERT(preferences == m_preferences);
4486
4487    BSTR str;
4488    int size;
4489    BOOL enabled;
4490
4491    Settings* settings = m_page->settings();
4492
4493    hr = preferences->cursiveFontFamily(&str);
4494    if (FAILED(hr))
4495        return hr;
4496    settings->setCursiveFontFamily(AtomicString(str, SysStringLen(str)));
4497    SysFreeString(str);
4498
4499    hr = preferences->defaultFixedFontSize(&size);
4500    if (FAILED(hr))
4501        return hr;
4502    settings->setDefaultFixedFontSize(size);
4503
4504    hr = preferences->defaultFontSize(&size);
4505    if (FAILED(hr))
4506        return hr;
4507    settings->setDefaultFontSize(size);
4508
4509    hr = preferences->defaultTextEncodingName(&str);
4510    if (FAILED(hr))
4511        return hr;
4512    settings->setDefaultTextEncodingName(String(str, SysStringLen(str)));
4513    SysFreeString(str);
4514
4515    hr = preferences->fantasyFontFamily(&str);
4516    if (FAILED(hr))
4517        return hr;
4518    settings->setFantasyFontFamily(AtomicString(str, SysStringLen(str)));
4519    SysFreeString(str);
4520
4521    hr = preferences->fixedFontFamily(&str);
4522    if (FAILED(hr))
4523        return hr;
4524    settings->setFixedFontFamily(AtomicString(str, SysStringLen(str)));
4525    SysFreeString(str);
4526
4527    hr = preferences->isJavaEnabled(&enabled);
4528    if (FAILED(hr))
4529        return hr;
4530    settings->setJavaEnabled(!!enabled);
4531
4532    hr = preferences->isJavaScriptEnabled(&enabled);
4533    if (FAILED(hr))
4534        return hr;
4535    settings->setJavaScriptEnabled(!!enabled);
4536
4537    hr = preferences->javaScriptCanOpenWindowsAutomatically(&enabled);
4538    if (FAILED(hr))
4539        return hr;
4540    settings->setJavaScriptCanOpenWindowsAutomatically(!!enabled);
4541
4542    hr = preferences->minimumFontSize(&size);
4543    if (FAILED(hr))
4544        return hr;
4545    settings->setMinimumFontSize(size);
4546
4547    hr = preferences->minimumLogicalFontSize(&size);
4548    if (FAILED(hr))
4549        return hr;
4550    settings->setMinimumLogicalFontSize(size);
4551
4552    hr = preferences->arePlugInsEnabled(&enabled);
4553    if (FAILED(hr))
4554        return hr;
4555    settings->setPluginsEnabled(!!enabled);
4556
4557    hr = preferences->privateBrowsingEnabled(&enabled);
4558    if (FAILED(hr))
4559        return hr;
4560    settings->setPrivateBrowsingEnabled(!!enabled);
4561
4562    hr = preferences->sansSerifFontFamily(&str);
4563    if (FAILED(hr))
4564        return hr;
4565    settings->setSansSerifFontFamily(AtomicString(str, SysStringLen(str)));
4566    SysFreeString(str);
4567
4568    hr = preferences->serifFontFamily(&str);
4569    if (FAILED(hr))
4570        return hr;
4571    settings->setSerifFontFamily(AtomicString(str, SysStringLen(str)));
4572    SysFreeString(str);
4573
4574    hr = preferences->standardFontFamily(&str);
4575    if (FAILED(hr))
4576        return hr;
4577    settings->setStandardFontFamily(AtomicString(str, SysStringLen(str)));
4578    SysFreeString(str);
4579
4580    hr = preferences->loadsImagesAutomatically(&enabled);
4581    if (FAILED(hr))
4582        return hr;
4583    settings->setLoadsImagesAutomatically(!!enabled);
4584
4585    hr = preferences->userStyleSheetEnabled(&enabled);
4586    if (FAILED(hr))
4587        return hr;
4588    if (enabled) {
4589        hr = preferences->userStyleSheetLocation(&str);
4590        if (FAILED(hr))
4591            return hr;
4592
4593        RetainPtr<CFStringRef> urlString(AdoptCF, String(str, SysStringLen(str)).createCFString());
4594        RetainPtr<CFURLRef> url(AdoptCF, CFURLCreateWithString(kCFAllocatorDefault, urlString.get(), 0));
4595
4596        // Check if the passed in string is a path and convert it to a URL.
4597        // FIXME: This is a workaround for nightly builds until we can get Safari to pass
4598        // in an URL here. See <rdar://problem/5478378>
4599        if (!url) {
4600            DWORD len = SysStringLen(str) + 1;
4601
4602            int result = WideCharToMultiByte(CP_UTF8, 0, str, len, 0, 0, 0, 0);
4603            Vector<UInt8> utf8Path(result);
4604            if (!WideCharToMultiByte(CP_UTF8, 0, str, len, (LPSTR)utf8Path.data(), result, 0, 0))
4605                return E_FAIL;
4606
4607            url.adoptCF(CFURLCreateFromFileSystemRepresentation(0, utf8Path.data(), result - 1, false));
4608        }
4609
4610        settings->setUserStyleSheetLocation(url.get());
4611        SysFreeString(str);
4612    } else {
4613        settings->setUserStyleSheetLocation(KURL());
4614    }
4615
4616    hr = preferences->shouldPrintBackgrounds(&enabled);
4617    if (FAILED(hr))
4618        return hr;
4619    settings->setShouldPrintBackgrounds(!!enabled);
4620
4621    hr = preferences->textAreasAreResizable(&enabled);
4622    if (FAILED(hr))
4623        return hr;
4624    settings->setTextAreasAreResizable(!!enabled);
4625
4626    WebKitEditableLinkBehavior behavior;
4627    hr = preferences->editableLinkBehavior(&behavior);
4628    if (FAILED(hr))
4629        return hr;
4630    settings->setEditableLinkBehavior((EditableLinkBehavior)behavior);
4631
4632    WebKitEditingBehavior editingBehavior;
4633    hr = preferences->editingBehavior(&editingBehavior);
4634    if (FAILED(hr))
4635        return hr;
4636    settings->setEditingBehaviorType((EditingBehaviorType)editingBehavior);
4637
4638    hr = preferences->usesPageCache(&enabled);
4639    if (FAILED(hr))
4640        return hr;
4641    settings->setUsesPageCache(!!enabled);
4642
4643    hr = preferences->isDOMPasteAllowed(&enabled);
4644    if (FAILED(hr))
4645        return hr;
4646    settings->setDOMPasteAllowed(!!enabled);
4647
4648    hr = preferences->shouldPaintCustomScrollbars(&enabled);
4649    if (FAILED(hr))
4650        return hr;
4651    settings->setShouldPaintCustomScrollbars(!!enabled);
4652
4653    hr = preferences->zoomsTextOnly(&enabled);
4654    if (FAILED(hr))
4655        return hr;
4656
4657    if (m_zoomsTextOnly != !!enabled)
4658        setZoomMultiplier(m_zoomMultiplier, enabled);
4659
4660    settings->setShowsURLsInToolTips(false);
4661    settings->setForceFTPDirectoryListings(true);
4662    settings->setDeveloperExtrasEnabled(developerExtrasEnabled());
4663    settings->setNeedsSiteSpecificQuirks(s_allowSiteSpecificHacks);
4664
4665    FontSmoothingType smoothingType;
4666    hr = preferences->fontSmoothing(&smoothingType);
4667    if (FAILED(hr))
4668        return hr;
4669    settings->setFontRenderingMode(smoothingType != FontSmoothingTypeWindows ? NormalRenderingMode : AlternateRenderingMode);
4670
4671    COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
4672    if (prefsPrivate) {
4673        hr = prefsPrivate->authorAndUserStylesEnabled(&enabled);
4674        if (FAILED(hr))
4675            return hr;
4676        settings->setAuthorAndUserStylesEnabled(enabled);
4677    }
4678
4679    hr = prefsPrivate->inApplicationChromeMode(&enabled);
4680    if (FAILED(hr))
4681        return hr;
4682    settings->setApplicationChromeMode(enabled);
4683
4684    hr = prefsPrivate->offlineWebApplicationCacheEnabled(&enabled);
4685    if (FAILED(hr))
4686        return hr;
4687    settings->setOfflineWebApplicationCacheEnabled(enabled);
4688
4689#if ENABLE(DATABASE)
4690    hr = prefsPrivate->databasesEnabled(&enabled);
4691    if (FAILED(hr))
4692        return hr;
4693    AbstractDatabase::setIsAvailable(enabled);
4694#endif
4695
4696    hr = prefsPrivate->localStorageEnabled(&enabled);
4697    if (FAILED(hr))
4698        return hr;
4699    settings->setLocalStorageEnabled(enabled);
4700
4701    hr = prefsPrivate->experimentalNotificationsEnabled(&enabled);
4702    if (FAILED(hr))
4703        return hr;
4704    settings->setExperimentalNotificationsEnabled(enabled);
4705
4706    hr = prefsPrivate->isWebSecurityEnabled(&enabled);
4707    if (FAILED(hr))
4708        return hr;
4709    settings->setWebSecurityEnabled(!!enabled);
4710
4711    hr = prefsPrivate->allowUniversalAccessFromFileURLs(&enabled);
4712    if (FAILED(hr))
4713        return hr;
4714    settings->setAllowUniversalAccessFromFileURLs(!!enabled);
4715
4716    hr = prefsPrivate->allowFileAccessFromFileURLs(&enabled);
4717    if (FAILED(hr))
4718        return hr;
4719    settings->setAllowFileAccessFromFileURLs(!!enabled);
4720
4721    hr = prefsPrivate->javaScriptCanAccessClipboard(&enabled);
4722    if (FAILED(hr))
4723        return hr;
4724    settings->setJavaScriptCanAccessClipboard(!!enabled);
4725
4726    hr = prefsPrivate->isXSSAuditorEnabled(&enabled);
4727    if (FAILED(hr))
4728        return hr;
4729    settings->setXSSAuditorEnabled(!!enabled);
4730
4731#if USE(SAFARI_THEME)
4732    hr = prefsPrivate->shouldPaintNativeControls(&enabled);
4733    if (FAILED(hr))
4734        return hr;
4735    settings->setShouldPaintNativeControls(!!enabled);
4736#endif
4737
4738    hr = prefsPrivate->shouldUseHighResolutionTimers(&enabled);
4739    if (FAILED(hr))
4740        return hr;
4741    settings->setShouldUseHighResolutionTimers(enabled);
4742
4743    UINT runTime;
4744    hr = prefsPrivate->pluginAllowedRunTime(&runTime);
4745    if (FAILED(hr))
4746        return hr;
4747    settings->setPluginAllowedRunTime(runTime);
4748
4749    hr = prefsPrivate->isFrameFlatteningEnabled(&enabled);
4750    if (FAILED(hr))
4751        return hr;
4752    settings->setFrameFlatteningEnabled(enabled);
4753
4754#if USE(ACCELERATED_COMPOSITING)
4755    hr = prefsPrivate->acceleratedCompositingEnabled(&enabled);
4756    if (FAILED(hr))
4757        return hr;
4758    settings->setAcceleratedCompositingEnabled(enabled);
4759#endif
4760
4761    hr = prefsPrivate->showDebugBorders(&enabled);
4762    if (FAILED(hr))
4763        return hr;
4764    settings->setShowDebugBorders(enabled);
4765
4766    hr = prefsPrivate->showRepaintCounter(&enabled);
4767    if (FAILED(hr))
4768        return hr;
4769    settings->setShowRepaintCounter(enabled);
4770
4771#if ENABLE(WEB_AUDIO)
4772    settings->setWebAudioEnabled(true);
4773#endif // ENABLE(WEB_AUDIO)
4774
4775#if ENABLE(WEBGL)
4776    settings->setWebGLEnabled(true);
4777#endif // ENABLE(WEBGL)
4778
4779    hr = prefsPrivate->isDNSPrefetchingEnabled(&enabled);
4780    if (FAILED(hr))
4781        return hr;
4782    settings->setDNSPrefetchingEnabled(enabled);
4783
4784    hr = prefsPrivate->memoryInfoEnabled(&enabled);
4785    if (FAILED(hr))
4786        return hr;
4787    settings->setMemoryInfoEnabled(enabled);
4788
4789    hr = prefsPrivate->hyperlinkAuditingEnabled(&enabled);
4790    if (FAILED(hr))
4791        return hr;
4792    settings->setHyperlinkAuditingEnabled(enabled);
4793
4794    hr = prefsPrivate->loadsSiteIconsIgnoringImageLoadingPreference(&enabled);
4795    if (FAILED(hr))
4796        return hr;
4797    settings->setLoadsSiteIconsIgnoringImageLoadingSetting(!!enabled);
4798
4799    if (!m_closeWindowTimer)
4800        m_mainFrame->invalidate(); // FIXME
4801
4802    hr = updateSharedSettingsFromPreferencesIfNeeded(preferences.get());
4803    if (FAILED(hr))
4804        return hr;
4805
4806    return S_OK;
4807}
4808
4809HRESULT updateSharedSettingsFromPreferencesIfNeeded(IWebPreferences* preferences)
4810{
4811    if (preferences != WebPreferences::sharedStandardPreferences())
4812        return S_OK;
4813
4814    WebKitCookieStorageAcceptPolicy acceptPolicy;
4815    HRESULT hr = preferences->cookieStorageAcceptPolicy(&acceptPolicy);
4816    if (FAILED(hr))
4817        return hr;
4818
4819#if USE(CFNETWORK)
4820    // Set cookie storage accept policy
4821    if (CFHTTPCookieStorageRef cookieStorage = currentCookieStorage())
4822        CFHTTPCookieStorageSetCookieAcceptPolicy(cookieStorage, acceptPolicy);
4823#endif
4824
4825    return S_OK;
4826}
4827
4828// IWebViewPrivate ------------------------------------------------------------
4829
4830HRESULT STDMETHODCALLTYPE WebView::MIMETypeForExtension(
4831    /* [in] */ BSTR extension,
4832    /* [retval][out] */ BSTR* mimeType)
4833{
4834    if (!mimeType)
4835        return E_POINTER;
4836
4837    String extensionStr(extension, SysStringLen(extension));
4838
4839    *mimeType = BString(MIMETypeRegistry::getMIMETypeForExtension(extensionStr)).release();
4840
4841    return S_OK;
4842}
4843
4844HRESULT STDMETHODCALLTYPE WebView::setCustomDropTarget(
4845    /* [in] */ IDropTarget* dt)
4846{
4847    ASSERT(::IsWindow(m_viewWindow));
4848    if (!dt)
4849        return E_POINTER;
4850    m_hasCustomDropTarget = true;
4851    revokeDragDrop();
4852    return ::RegisterDragDrop(m_viewWindow,dt);
4853}
4854
4855HRESULT STDMETHODCALLTYPE WebView::removeCustomDropTarget()
4856{
4857    if (!m_hasCustomDropTarget)
4858        return S_OK;
4859    m_hasCustomDropTarget = false;
4860    revokeDragDrop();
4861    return registerDragDrop();
4862}
4863
4864HRESULT STDMETHODCALLTYPE WebView::setInViewSourceMode(
4865        /* [in] */ BOOL flag)
4866{
4867    if (!m_mainFrame)
4868        return E_FAIL;
4869
4870    return m_mainFrame->setInViewSourceMode(flag);
4871}
4872
4873HRESULT STDMETHODCALLTYPE WebView::inViewSourceMode(
4874        /* [retval][out] */ BOOL* flag)
4875{
4876    if (!m_mainFrame)
4877        return E_FAIL;
4878
4879    return m_mainFrame->inViewSourceMode(flag);
4880}
4881
4882HRESULT STDMETHODCALLTYPE WebView::viewWindow(
4883        /* [retval][out] */ OLE_HANDLE *window)
4884{
4885    *window = (OLE_HANDLE)(ULONG64)m_viewWindow;
4886    return S_OK;
4887}
4888
4889HRESULT STDMETHODCALLTYPE WebView::setFormDelegate(
4890    /* [in] */ IWebFormDelegate *formDelegate)
4891{
4892    m_formDelegate = formDelegate;
4893    return S_OK;
4894}
4895
4896HRESULT STDMETHODCALLTYPE WebView::formDelegate(
4897    /* [retval][out] */ IWebFormDelegate **formDelegate)
4898{
4899    if (!m_formDelegate)
4900        return E_FAIL;
4901
4902    return m_formDelegate.copyRefTo(formDelegate);
4903}
4904
4905HRESULT STDMETHODCALLTYPE WebView::setFrameLoadDelegatePrivate(
4906    /* [in] */ IWebFrameLoadDelegatePrivate* d)
4907{
4908    m_frameLoadDelegatePrivate = d;
4909    return S_OK;
4910}
4911
4912HRESULT STDMETHODCALLTYPE WebView::frameLoadDelegatePrivate(
4913    /* [out][retval] */ IWebFrameLoadDelegatePrivate** d)
4914{
4915    if (!m_frameLoadDelegatePrivate)
4916        return E_FAIL;
4917
4918    return m_frameLoadDelegatePrivate.copyRefTo(d);
4919}
4920
4921HRESULT STDMETHODCALLTYPE WebView::scrollOffset(
4922    /* [retval][out] */ LPPOINT offset)
4923{
4924    if (!offset)
4925        return E_POINTER;
4926    IntSize offsetIntSize = m_page->mainFrame()->view()->scrollOffset();
4927    offset->x = offsetIntSize.width();
4928    offset->y = offsetIntSize.height();
4929    return S_OK;
4930}
4931
4932HRESULT STDMETHODCALLTYPE WebView::scrollBy(
4933    /* [in] */ LPPOINT offset)
4934{
4935    if (!offset)
4936        return E_POINTER;
4937    m_page->mainFrame()->view()->scrollBy(IntSize(offset->x, offset->y));
4938    return S_OK;
4939}
4940
4941HRESULT STDMETHODCALLTYPE WebView::visibleContentRect(
4942    /* [retval][out] */ LPRECT rect)
4943{
4944    if (!rect)
4945        return E_POINTER;
4946    FloatRect visibleContent = m_page->mainFrame()->view()->visibleContentRect();
4947    rect->left = (LONG) visibleContent.x();
4948    rect->top = (LONG) visibleContent.y();
4949    rect->right = (LONG) visibleContent.maxX();
4950    rect->bottom = (LONG) visibleContent.maxY();
4951    return S_OK;
4952}
4953
4954static DWORD dragOperationToDragCursor(DragOperation op) {
4955    DWORD res = DROPEFFECT_NONE;
4956    if (op & DragOperationCopy)
4957        res = DROPEFFECT_COPY;
4958    else if (op & DragOperationLink)
4959        res = DROPEFFECT_LINK;
4960    else if (op & DragOperationMove)
4961        res = DROPEFFECT_MOVE;
4962    else if (op & DragOperationGeneric)
4963        res = DROPEFFECT_MOVE; //This appears to be the Firefox behaviour
4964    return res;
4965}
4966
4967DragOperation WebView::keyStateToDragOperation(DWORD grfKeyState) const
4968{
4969    if (!m_page)
4970        return DragOperationNone;
4971
4972    // Conforms to Microsoft's key combinations as documented for
4973    // IDropTarget::DragOver. Note, grfKeyState is the current
4974    // state of the keyboard modifier keys on the keyboard. See:
4975    // <http://msdn.microsoft.com/en-us/library/ms680129(VS.85).aspx>.
4976    DragOperation operation = m_page->dragController()->sourceDragOperation();
4977
4978    if ((grfKeyState & (MK_CONTROL | MK_SHIFT)) == (MK_CONTROL | MK_SHIFT))
4979        operation = DragOperationLink;
4980    else if ((grfKeyState & MK_CONTROL) == MK_CONTROL)
4981        operation = DragOperationCopy;
4982    else if ((grfKeyState & MK_SHIFT) == MK_SHIFT)
4983        operation = DragOperationGeneric;
4984
4985    return operation;
4986}
4987
4988HRESULT STDMETHODCALLTYPE WebView::DragEnter(
4989        IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
4990{
4991    m_dragData = 0;
4992
4993    if (m_dropTargetHelper)
4994        m_dropTargetHelper->DragEnter(m_viewWindow, pDataObject, (POINT*)&pt, *pdwEffect);
4995
4996    POINTL localpt = pt;
4997    ::ScreenToClient(m_viewWindow, (LPPOINT)&localpt);
4998    DragData data(pDataObject, IntPoint(localpt.x, localpt.y),
4999        IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState));
5000    *pdwEffect = dragOperationToDragCursor(m_page->dragController()->dragEntered(&data));
5001
5002    m_lastDropEffect = *pdwEffect;
5003    m_dragData = pDataObject;
5004
5005    return S_OK;
5006}
5007
5008HRESULT STDMETHODCALLTYPE WebView::DragOver(
5009        DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
5010{
5011    if (m_dropTargetHelper)
5012        m_dropTargetHelper->DragOver((POINT*)&pt, *pdwEffect);
5013
5014    if (m_dragData) {
5015        POINTL localpt = pt;
5016        ::ScreenToClient(m_viewWindow, (LPPOINT)&localpt);
5017        DragData data(m_dragData.get(), IntPoint(localpt.x, localpt.y),
5018            IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState));
5019        *pdwEffect = dragOperationToDragCursor(m_page->dragController()->dragUpdated(&data));
5020    } else
5021        *pdwEffect = DROPEFFECT_NONE;
5022
5023    m_lastDropEffect = *pdwEffect;
5024    return S_OK;
5025}
5026
5027HRESULT STDMETHODCALLTYPE WebView::DragLeave()
5028{
5029    if (m_dropTargetHelper)
5030        m_dropTargetHelper->DragLeave();
5031
5032    if (m_dragData) {
5033        DragData data(m_dragData.get(), IntPoint(), IntPoint(),
5034            DragOperationNone);
5035        m_page->dragController()->dragExited(&data);
5036        m_dragData = 0;
5037    }
5038    return S_OK;
5039}
5040
5041HRESULT STDMETHODCALLTYPE WebView::Drop(
5042        IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
5043{
5044    if (m_dropTargetHelper)
5045        m_dropTargetHelper->Drop(pDataObject, (POINT*)&pt, *pdwEffect);
5046
5047    m_dragData = 0;
5048    *pdwEffect = m_lastDropEffect;
5049    POINTL localpt = pt;
5050    ::ScreenToClient(m_viewWindow, (LPPOINT)&localpt);
5051    DragData data(pDataObject, IntPoint(localpt.x, localpt.y),
5052        IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState));
5053    m_page->dragController()->performDrag(&data);
5054    return S_OK;
5055}
5056
5057HRESULT STDMETHODCALLTYPE WebView::canHandleRequest(
5058    IWebURLRequest *request,
5059    BOOL *result)
5060{
5061    COMPtr<WebMutableURLRequest> requestImpl;
5062
5063    HRESULT hr = request->QueryInterface(&requestImpl);
5064    if (FAILED(hr))
5065        return hr;
5066
5067    *result = !!canHandleRequest(requestImpl->resourceRequest());
5068    return S_OK;
5069}
5070
5071HRESULT STDMETHODCALLTYPE WebView::standardUserAgentWithApplicationName(
5072    BSTR applicationName,
5073    BSTR* groupName)
5074{
5075    if (!groupName) {
5076        ASSERT_NOT_REACHED();
5077        return E_POINTER;
5078    }
5079
5080    *groupName;
5081
5082    if (!applicationName) {
5083        ASSERT_NOT_REACHED();
5084        return E_POINTER;
5085    }
5086
5087    BString applicationNameBString(applicationName);
5088    *groupName = BString(standardUserAgentWithApplicationName(String(applicationNameBString, SysStringLen(applicationNameBString)))).release();
5089    return S_OK;
5090}
5091
5092HRESULT STDMETHODCALLTYPE WebView::clearFocusNode()
5093{
5094    if (m_page && m_page->focusController())
5095        m_page->focusController()->setFocusedNode(0, 0);
5096    return S_OK;
5097}
5098
5099HRESULT STDMETHODCALLTYPE WebView::setInitialFocus(
5100    /* [in] */ BOOL forward)
5101{
5102    if (m_page && m_page->focusController()) {
5103        Frame* frame = m_page->focusController()->focusedOrMainFrame();
5104        frame->document()->setFocusedNode(0);
5105        m_page->focusController()->setInitialFocus(forward ? FocusDirectionForward : FocusDirectionBackward, 0);
5106    }
5107    return S_OK;
5108}
5109
5110HRESULT STDMETHODCALLTYPE WebView::setTabKeyCyclesThroughElements(
5111    /* [in] */ BOOL cycles)
5112{
5113    if (m_page)
5114        m_page->setTabKeyCyclesThroughElements(!!cycles);
5115
5116    return S_OK;
5117}
5118
5119HRESULT STDMETHODCALLTYPE WebView::tabKeyCyclesThroughElements(
5120    /* [retval][out] */ BOOL* result)
5121{
5122    if (!result) {
5123        ASSERT_NOT_REACHED();
5124        return E_POINTER;
5125    }
5126
5127    *result = m_page && m_page->tabKeyCyclesThroughElements() ? TRUE : FALSE;
5128    return S_OK;
5129}
5130
5131HRESULT STDMETHODCALLTYPE WebView::setAllowSiteSpecificHacks(
5132    /* [in] */ BOOL allow)
5133{
5134    s_allowSiteSpecificHacks = !!allow;
5135    // FIXME: This sets a global so it needs to call notifyPreferencesChanged
5136    // on all WebView objects (not just itself).
5137    return S_OK;
5138}
5139
5140HRESULT STDMETHODCALLTYPE WebView::addAdditionalPluginDirectory(
5141        /* [in] */ BSTR directory)
5142{
5143    PluginDatabase::installedPlugins()->addExtraPluginDirectory(String(directory, SysStringLen(directory)));
5144    return S_OK;
5145}
5146
5147HRESULT STDMETHODCALLTYPE WebView::loadBackForwardListFromOtherView(
5148    /* [in] */ IWebView* otherView)
5149{
5150    if (!m_page)
5151        return E_FAIL;
5152
5153    // It turns out the right combination of behavior is done with the back/forward load
5154    // type.  (See behavior matrix at the top of WebFramePrivate.)  So we copy all the items
5155    // in the back forward list, and go to the current one.
5156    BackForwardList* backForwardList = m_page->backForwardList();
5157    ASSERT(!backForwardList->currentItem()); // destination list should be empty
5158
5159    COMPtr<WebView> otherWebView;
5160    if (FAILED(otherView->QueryInterface(&otherWebView)))
5161        return E_FAIL;
5162    BackForwardList* otherBackForwardList = otherWebView->m_page->backForwardList();
5163    if (!otherBackForwardList->currentItem())
5164        return S_OK; // empty back forward list, bail
5165
5166    HistoryItem* newItemToGoTo = 0;
5167
5168    int lastItemIndex = otherBackForwardList->forwardListCount();
5169    for (int i = -otherBackForwardList->backListCount(); i <= lastItemIndex; ++i) {
5170        if (!i) {
5171            // If this item is showing , save away its current scroll and form state,
5172            // since that might have changed since loading and it is normally not saved
5173            // until we leave that page.
5174            otherWebView->m_page->mainFrame()->loader()->history()->saveDocumentAndScrollState();
5175        }
5176        RefPtr<HistoryItem> newItem = otherBackForwardList->itemAtIndex(i)->copy();
5177        if (!i)
5178            newItemToGoTo = newItem.get();
5179        backForwardList->addItem(newItem.release());
5180    }
5181
5182    ASSERT(newItemToGoTo);
5183    m_page->goToItem(newItemToGoTo, FrameLoadTypeIndexedBackForward);
5184    return S_OK;
5185}
5186
5187HRESULT STDMETHODCALLTYPE WebView::clearUndoRedoOperations()
5188{
5189    if (Frame* frame = m_page->focusController()->focusedOrMainFrame())
5190        frame->editor()->clearUndoRedoOperations();
5191    return S_OK;
5192}
5193
5194HRESULT STDMETHODCALLTYPE WebView::shouldClose(
5195    /* [retval][out] */ BOOL* result)
5196{
5197    if (!result) {
5198        ASSERT_NOT_REACHED();
5199        return E_POINTER;
5200    }
5201
5202    *result = TRUE;
5203    if (Frame* frame = m_page->mainFrame())
5204        *result = frame->loader()->shouldClose();
5205    return S_OK;
5206}
5207
5208HRESULT WebView::registerDragDrop()
5209{
5210    ASSERT(::IsWindow(m_viewWindow));
5211    return ::RegisterDragDrop(m_viewWindow, this);
5212}
5213
5214HRESULT WebView::revokeDragDrop()
5215{
5216    if (!m_viewWindow)
5217        return S_OK;
5218
5219    return ::RevokeDragDrop(m_viewWindow);
5220}
5221
5222HRESULT WebView::setProhibitsMainFrameScrolling(BOOL b)
5223{
5224    if (!m_page)
5225        return E_FAIL;
5226
5227    m_page->mainFrame()->view()->setProhibitsScrolling(b);
5228    return S_OK;
5229}
5230
5231HRESULT WebView::setShouldApplyMacFontAscentHack(BOOL b)
5232{
5233    SimpleFontData::setShouldApplyMacAscentHack(b);
5234    return S_OK;
5235}
5236
5237class IMMDict {
5238    typedef HIMC (CALLBACK *getContextPtr)(HWND);
5239    typedef BOOL (CALLBACK *releaseContextPtr)(HWND, HIMC);
5240    typedef LONG (CALLBACK *getCompositionStringPtr)(HIMC, DWORD, LPVOID, DWORD);
5241    typedef BOOL (CALLBACK *setCandidateWindowPtr)(HIMC, LPCANDIDATEFORM);
5242    typedef BOOL (CALLBACK *setOpenStatusPtr)(HIMC, BOOL);
5243    typedef BOOL (CALLBACK *notifyIMEPtr)(HIMC, DWORD, DWORD, DWORD);
5244    typedef BOOL (CALLBACK *associateContextExPtr)(HWND, HIMC, DWORD);
5245
5246public:
5247    getContextPtr getContext;
5248    releaseContextPtr releaseContext;
5249    getCompositionStringPtr getCompositionString;
5250    setCandidateWindowPtr setCandidateWindow;
5251    setOpenStatusPtr setOpenStatus;
5252    notifyIMEPtr notifyIME;
5253    associateContextExPtr associateContextEx;
5254
5255    static const IMMDict& dict();
5256private:
5257    IMMDict();
5258    HMODULE m_instance;
5259};
5260
5261const IMMDict& IMMDict::dict()
5262{
5263    static IMMDict instance;
5264    return instance;
5265}
5266
5267IMMDict::IMMDict()
5268{
5269    m_instance = ::LoadLibraryW(L"IMM32.DLL");
5270    getContext = reinterpret_cast<getContextPtr>(::GetProcAddress(m_instance, "ImmGetContext"));
5271    ASSERT(getContext);
5272    releaseContext = reinterpret_cast<releaseContextPtr>(::GetProcAddress(m_instance, "ImmReleaseContext"));
5273    ASSERT(releaseContext);
5274    getCompositionString = reinterpret_cast<getCompositionStringPtr>(::GetProcAddress(m_instance, "ImmGetCompositionStringW"));
5275    ASSERT(getCompositionString);
5276    setCandidateWindow = reinterpret_cast<setCandidateWindowPtr>(::GetProcAddress(m_instance, "ImmSetCandidateWindow"));
5277    ASSERT(setCandidateWindow);
5278    setOpenStatus = reinterpret_cast<setOpenStatusPtr>(::GetProcAddress(m_instance, "ImmSetOpenStatus"));
5279    ASSERT(setOpenStatus);
5280    notifyIME = reinterpret_cast<notifyIMEPtr>(::GetProcAddress(m_instance, "ImmNotifyIME"));
5281    ASSERT(notifyIME);
5282    associateContextEx = reinterpret_cast<associateContextExPtr>(::GetProcAddress(m_instance, "ImmAssociateContextEx"));
5283    ASSERT(associateContextEx);
5284}
5285
5286HIMC WebView::getIMMContext()
5287{
5288    HIMC context = IMMDict::dict().getContext(m_viewWindow);
5289    return context;
5290}
5291
5292void WebView::releaseIMMContext(HIMC hIMC)
5293{
5294    if (!hIMC)
5295        return;
5296    IMMDict::dict().releaseContext(m_viewWindow, hIMC);
5297}
5298
5299void WebView::prepareCandidateWindow(Frame* targetFrame, HIMC hInputContext)
5300{
5301    IntRect caret;
5302    if (RefPtr<Range> range = targetFrame->selection()->selection().toNormalizedRange()) {
5303        ExceptionCode ec = 0;
5304        RefPtr<Range> tempRange = range->cloneRange(ec);
5305        caret = targetFrame->editor()->firstRectForRange(tempRange.get());
5306    }
5307    caret = targetFrame->view()->contentsToWindow(caret);
5308    CANDIDATEFORM form;
5309    form.dwIndex = 0;
5310    form.dwStyle = CFS_EXCLUDE;
5311    form.ptCurrentPos.x = caret.x();
5312    form.ptCurrentPos.y = caret.y() + caret.height();
5313    form.rcArea.top = caret.y();
5314    form.rcArea.bottom = caret.maxY();
5315    form.rcArea.left = caret.x();
5316    form.rcArea.right = caret.maxX();
5317    IMMDict::dict().setCandidateWindow(hInputContext, &form);
5318}
5319
5320void WebView::resetIME(Frame* targetFrame)
5321{
5322    if (targetFrame)
5323        targetFrame->editor()->confirmCompositionWithoutDisturbingSelection();
5324
5325    if (HIMC hInputContext = getIMMContext()) {
5326        IMMDict::dict().notifyIME(hInputContext, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
5327        releaseIMMContext(hInputContext);
5328    }
5329}
5330
5331void WebView::updateSelectionForIME()
5332{
5333    Frame* targetFrame = m_page->focusController()->focusedOrMainFrame();
5334    if (!targetFrame || !targetFrame->editor()->hasComposition())
5335        return;
5336
5337    if (targetFrame->editor()->ignoreCompositionSelectionChange())
5338        return;
5339
5340    unsigned start;
5341    unsigned end;
5342    if (!targetFrame->editor()->getCompositionSelection(start, end))
5343        resetIME(targetFrame);
5344}
5345
5346void WebView::setInputMethodState(bool enabled)
5347{
5348    IMMDict::dict().associateContextEx(m_viewWindow, 0, enabled ? IACE_DEFAULT : 0);
5349}
5350
5351void WebView::selectionChanged()
5352{
5353    updateSelectionForIME();
5354}
5355
5356bool WebView::onIMEStartComposition()
5357{
5358    LOG(TextInput, "onIMEStartComposition");
5359    m_inIMEComposition++;
5360    Frame* targetFrame = m_page->focusController()->focusedOrMainFrame();
5361    if (!targetFrame)
5362        return true;
5363
5364    HIMC hInputContext = getIMMContext();
5365    prepareCandidateWindow(targetFrame, hInputContext);
5366    releaseIMMContext(hInputContext);
5367    return true;
5368}
5369
5370static bool getCompositionString(HIMC hInputContext, DWORD type, String& result)
5371{
5372    int compositionLength = IMMDict::dict().getCompositionString(hInputContext, type, 0, 0);
5373    if (compositionLength <= 0)
5374        return false;
5375    Vector<UChar> compositionBuffer(compositionLength / 2);
5376    compositionLength = IMMDict::dict().getCompositionString(hInputContext, type, (LPVOID)compositionBuffer.data(), compositionLength);
5377    result = String(compositionBuffer.data(), compositionLength / 2);
5378    ASSERT(!compositionLength || compositionBuffer[0]);
5379    ASSERT(!compositionLength || compositionBuffer[compositionLength / 2 - 1]);
5380    return true;
5381}
5382
5383static void compositionToUnderlines(const Vector<DWORD>& clauses, const Vector<BYTE>& attributes, Vector<CompositionUnderline>& underlines)
5384{
5385    if (clauses.isEmpty()) {
5386        underlines.clear();
5387        return;
5388    }
5389
5390    const size_t numBoundaries = clauses.size() - 1;
5391    underlines.resize(numBoundaries);
5392    for (unsigned i = 0; i < numBoundaries; i++) {
5393        underlines[i].startOffset = clauses[i];
5394        underlines[i].endOffset = clauses[i + 1];
5395        BYTE attribute = attributes[clauses[i]];
5396        underlines[i].thick = attribute == ATTR_TARGET_CONVERTED || attribute == ATTR_TARGET_NOTCONVERTED;
5397        underlines[i].color = Color(0,0,0);
5398    }
5399}
5400
5401#if !LOG_DISABLED
5402#define APPEND_ARGUMENT_NAME(name) \
5403    if (lparam & name) { \
5404        if (needsComma) \
5405            result += ", "; \
5406            result += #name; \
5407        needsComma = true; \
5408    }
5409
5410static String imeCompositionArgumentNames(LPARAM lparam)
5411{
5412    String result;
5413    bool needsComma = false;
5414    if (lparam & GCS_COMPATTR) {
5415        result = "GCS_COMPATTR";
5416        needsComma = true;
5417    }
5418    APPEND_ARGUMENT_NAME(GCS_COMPCLAUSE);
5419    APPEND_ARGUMENT_NAME(GCS_COMPREADSTR);
5420    APPEND_ARGUMENT_NAME(GCS_COMPREADATTR);
5421    APPEND_ARGUMENT_NAME(GCS_COMPREADCLAUSE);
5422    APPEND_ARGUMENT_NAME(GCS_COMPSTR);
5423    APPEND_ARGUMENT_NAME(GCS_CURSORPOS);
5424    APPEND_ARGUMENT_NAME(GCS_DELTASTART);
5425    APPEND_ARGUMENT_NAME(GCS_RESULTCLAUSE);
5426    APPEND_ARGUMENT_NAME(GCS_RESULTREADCLAUSE);
5427    APPEND_ARGUMENT_NAME(GCS_RESULTREADSTR);
5428    APPEND_ARGUMENT_NAME(GCS_RESULTSTR);
5429    APPEND_ARGUMENT_NAME(CS_INSERTCHAR);
5430    APPEND_ARGUMENT_NAME(CS_NOMOVECARET);
5431
5432    return result;
5433}
5434
5435static String imeNotificationName(WPARAM wparam)
5436{
5437    switch (wparam) {
5438    case IMN_CHANGECANDIDATE:
5439        return "IMN_CHANGECANDIDATE";
5440    case IMN_CLOSECANDIDATE:
5441        return "IMN_CLOSECANDIDATE";
5442    case IMN_CLOSESTATUSWINDOW:
5443        return "IMN_CLOSESTATUSWINDOW";
5444    case IMN_GUIDELINE:
5445        return "IMN_GUIDELINE";
5446    case IMN_OPENCANDIDATE:
5447        return "IMN_OPENCANDIDATE";
5448    case IMN_OPENSTATUSWINDOW:
5449        return "IMN_OPENSTATUSWINDOW";
5450    case IMN_SETCANDIDATEPOS:
5451        return "IMN_SETCANDIDATEPOS";
5452    case IMN_SETCOMPOSITIONFONT:
5453        return "IMN_SETCOMPOSITIONFONT";
5454    case IMN_SETCOMPOSITIONWINDOW:
5455        return "IMN_SETCOMPOSITIONWINDOW";
5456    case IMN_SETCONVERSIONMODE:
5457        return "IMN_SETCONVERSIONMODE";
5458    case IMN_SETOPENSTATUS:
5459        return "IMN_SETOPENSTATUS";
5460    case IMN_SETSENTENCEMODE:
5461        return "IMN_SETSENTENCEMODE";
5462    case IMN_SETSTATUSWINDOWPOS:
5463        return "IMN_SETSTATUSWINDOWPOS";
5464    default:
5465        return "Unknown (" + String::number(wparam) + ")";
5466    }
5467}
5468
5469static String imeRequestName(WPARAM wparam)
5470{
5471    switch (wparam) {
5472    case IMR_CANDIDATEWINDOW:
5473        return "IMR_CANDIDATEWINDOW";
5474    case IMR_COMPOSITIONFONT:
5475        return "IMR_COMPOSITIONFONT";
5476    case IMR_COMPOSITIONWINDOW:
5477        return "IMR_COMPOSITIONWINDOW";
5478    case IMR_CONFIRMRECONVERTSTRING:
5479        return "IMR_CONFIRMRECONVERTSTRING";
5480    case IMR_DOCUMENTFEED:
5481        return "IMR_DOCUMENTFEED";
5482    case IMR_QUERYCHARPOSITION:
5483        return "IMR_QUERYCHARPOSITION";
5484    case IMR_RECONVERTSTRING:
5485        return "IMR_RECONVERTSTRING";
5486    default:
5487        return "Unknown (" + String::number(wparam) + ")";
5488    }
5489}
5490#endif
5491
5492bool WebView::onIMEComposition(LPARAM lparam)
5493{
5494    LOG(TextInput, "onIMEComposition %s", imeCompositionArgumentNames(lparam).latin1().data());
5495    HIMC hInputContext = getIMMContext();
5496    if (!hInputContext)
5497        return true;
5498
5499    Frame* targetFrame = m_page->focusController()->focusedOrMainFrame();
5500    if (!targetFrame || !targetFrame->editor()->canEdit())
5501        return true;
5502
5503    prepareCandidateWindow(targetFrame, hInputContext);
5504
5505    if (lparam & GCS_RESULTSTR || !lparam) {
5506        String compositionString;
5507        if (!getCompositionString(hInputContext, GCS_RESULTSTR, compositionString) && lparam)
5508            return true;
5509
5510        targetFrame->editor()->confirmComposition(compositionString);
5511    } else {
5512        String compositionString;
5513        if (!getCompositionString(hInputContext, GCS_COMPSTR, compositionString))
5514            return true;
5515
5516        // Composition string attributes
5517        int numAttributes = IMMDict::dict().getCompositionString(hInputContext, GCS_COMPATTR, 0, 0);
5518        Vector<BYTE> attributes(numAttributes);
5519        IMMDict::dict().getCompositionString(hInputContext, GCS_COMPATTR, attributes.data(), numAttributes);
5520
5521        // Get clauses
5522        int numClauses = IMMDict::dict().getCompositionString(hInputContext, GCS_COMPCLAUSE, 0, 0);
5523        Vector<DWORD> clauses(numClauses / sizeof(DWORD));
5524        IMMDict::dict().getCompositionString(hInputContext, GCS_COMPCLAUSE, clauses.data(), numClauses);
5525
5526        Vector<CompositionUnderline> underlines;
5527        compositionToUnderlines(clauses, attributes, underlines);
5528
5529        int cursorPosition = LOWORD(IMMDict::dict().getCompositionString(hInputContext, GCS_CURSORPOS, 0, 0));
5530
5531        targetFrame->editor()->setComposition(compositionString, underlines, cursorPosition, 0);
5532    }
5533
5534    return true;
5535}
5536
5537bool WebView::onIMEEndComposition()
5538{
5539    LOG(TextInput, "onIMEEndComposition");
5540    // If the composition hasn't been confirmed yet, it needs to be cancelled.
5541    // This happens after deleting the last character from inline input hole.
5542    Frame* targetFrame = m_page->focusController()->focusedOrMainFrame();
5543    if (targetFrame && targetFrame->editor()->hasComposition())
5544        targetFrame->editor()->confirmComposition(String());
5545
5546    if (m_inIMEComposition)
5547        m_inIMEComposition--;
5548
5549    return true;
5550}
5551
5552bool WebView::onIMEChar(WPARAM wparam, LPARAM lparam)
5553{
5554    UNUSED_PARAM(wparam);
5555    UNUSED_PARAM(lparam);
5556    LOG(TextInput, "onIMEChar U+%04X %08X", wparam, lparam);
5557    return true;
5558}
5559
5560bool WebView::onIMENotify(WPARAM wparam, LPARAM, LRESULT*)
5561{
5562    UNUSED_PARAM(wparam);
5563    LOG(TextInput, "onIMENotify %s", imeNotificationName(wparam).latin1().data());
5564    return false;
5565}
5566
5567LRESULT WebView::onIMERequestCharPosition(Frame* targetFrame, IMECHARPOSITION* charPos)
5568{
5569    if (charPos->dwCharPos && !targetFrame->editor()->hasComposition())
5570        return 0;
5571    IntRect caret;
5572    if (RefPtr<Range> range = targetFrame->editor()->hasComposition() ? targetFrame->editor()->compositionRange() : targetFrame->selection()->selection().toNormalizedRange()) {
5573        ExceptionCode ec = 0;
5574        RefPtr<Range> tempRange = range->cloneRange(ec);
5575        tempRange->setStart(tempRange->startContainer(ec), tempRange->startOffset(ec) + charPos->dwCharPos, ec);
5576        caret = targetFrame->editor()->firstRectForRange(tempRange.get());
5577    }
5578    caret = targetFrame->view()->contentsToWindow(caret);
5579    charPos->pt.x = caret.x();
5580    charPos->pt.y = caret.y();
5581    ::ClientToScreen(m_viewWindow, &charPos->pt);
5582    charPos->cLineHeight = caret.height();
5583    ::GetWindowRect(m_viewWindow, &charPos->rcDocument);
5584    return true;
5585}
5586
5587LRESULT WebView::onIMERequestReconvertString(Frame* targetFrame, RECONVERTSTRING* reconvertString)
5588{
5589    RefPtr<Range> selectedRange = targetFrame->selection()->toNormalizedRange();
5590    String text = selectedRange->text();
5591    if (!reconvertString)
5592        return sizeof(RECONVERTSTRING) + text.length() * sizeof(UChar);
5593
5594    unsigned totalSize = sizeof(RECONVERTSTRING) + text.length() * sizeof(UChar);
5595    if (totalSize > reconvertString->dwSize)
5596        return 0;
5597    reconvertString->dwCompStrLen = text.length();
5598    reconvertString->dwStrLen = text.length();
5599    reconvertString->dwTargetStrLen = text.length();
5600    reconvertString->dwStrOffset = sizeof(RECONVERTSTRING);
5601    memcpy(reconvertString + 1, text.characters(), text.length() * sizeof(UChar));
5602    return totalSize;
5603}
5604
5605LRESULT WebView::onIMERequest(WPARAM request, LPARAM data)
5606{
5607    LOG(TextInput, "onIMERequest %s", imeRequestName(request).latin1().data());
5608    Frame* targetFrame = m_page->focusController()->focusedOrMainFrame();
5609    if (!targetFrame || !targetFrame->editor()->canEdit())
5610        return 0;
5611
5612    switch (request) {
5613        case IMR_RECONVERTSTRING:
5614            return onIMERequestReconvertString(targetFrame, (RECONVERTSTRING*)data);
5615
5616        case IMR_QUERYCHARPOSITION:
5617            return onIMERequestCharPosition(targetFrame, (IMECHARPOSITION*)data);
5618    }
5619    return 0;
5620}
5621
5622bool WebView::onIMESelect(WPARAM wparam, LPARAM lparam)
5623{
5624    UNUSED_PARAM(wparam);
5625    UNUSED_PARAM(lparam);
5626    LOG(TextInput, "onIMESelect locale %ld %s", lparam, wparam ? "select" : "deselect");
5627    return false;
5628}
5629
5630bool WebView::onIMESetContext(WPARAM wparam, LPARAM)
5631{
5632    LOG(TextInput, "onIMESetContext %s", wparam ? "active" : "inactive");
5633    return false;
5634}
5635
5636HRESULT STDMETHODCALLTYPE WebView::inspector(IWebInspector** inspector)
5637{
5638    if (!m_webInspector)
5639        m_webInspector.adoptRef(WebInspector::createInstance(this));
5640
5641    return m_webInspector.copyRefTo(inspector);
5642}
5643
5644HRESULT STDMETHODCALLTYPE WebView::windowAncestryDidChange()
5645{
5646    HWND newParent;
5647    if (m_viewWindow)
5648        newParent = findTopLevelParent(m_hostWindow);
5649    else {
5650        // There's no point in tracking active state changes of our parent window if we don't have
5651        // a window ourselves.
5652        newParent = 0;
5653    }
5654
5655    if (newParent == m_topLevelParent)
5656        return S_OK;
5657
5658    if (m_topLevelParent)
5659        WindowMessageBroadcaster::removeListener(m_topLevelParent, this);
5660
5661    m_topLevelParent = newParent;
5662
5663    if (m_topLevelParent)
5664        WindowMessageBroadcaster::addListener(m_topLevelParent, this);
5665
5666    updateActiveState();
5667
5668    return S_OK;
5669}
5670
5671HRESULT STDMETHODCALLTYPE WebView::paintDocumentRectToContext(
5672    /* [in] */ RECT rect,
5673    /* [in] */ OLE_HANDLE deviceContext)
5674{
5675    if (!deviceContext)
5676        return E_POINTER;
5677
5678    if (!m_mainFrame)
5679        return E_FAIL;
5680
5681    return m_mainFrame->paintDocumentRectToContext(rect, deviceContext);
5682}
5683
5684HRESULT STDMETHODCALLTYPE WebView::paintScrollViewRectToContextAtPoint(
5685    /* [in] */ RECT rect,
5686    /* [in] */ POINT pt,
5687    /* [in] */ OLE_HANDLE deviceContext)
5688{
5689    if (!deviceContext)
5690        return E_POINTER;
5691
5692    if (!m_mainFrame)
5693        return E_FAIL;
5694
5695    return m_mainFrame->paintScrollViewRectToContextAtPoint(rect, pt, deviceContext);
5696}
5697
5698HRESULT STDMETHODCALLTYPE WebView::reportException(
5699    /* [in] */ JSContextRef context,
5700    /* [in] */ JSValueRef exception)
5701{
5702    if (!context || !exception)
5703        return E_FAIL;
5704
5705    JSLock lock(JSC::SilenceAssertionsOnly);
5706    JSC::ExecState* execState = toJS(context);
5707
5708    // Make sure the context has a DOMWindow global object, otherwise this context didn't originate from a WebView.
5709    if (!toJSDOMWindow(execState->lexicalGlobalObject()))
5710        return E_FAIL;
5711
5712    WebCore::reportException(execState, toJS(execState, exception));
5713    return S_OK;
5714}
5715
5716HRESULT STDMETHODCALLTYPE WebView::elementFromJS(
5717    /* [in] */ JSContextRef context,
5718    /* [in] */ JSValueRef nodeObject,
5719    /* [retval][out] */ IDOMElement **element)
5720{
5721    if (!element)
5722        return E_POINTER;
5723
5724    *element = 0;
5725
5726    if (!context)
5727        return E_FAIL;
5728
5729    if (!nodeObject)
5730        return E_FAIL;
5731
5732    JSLock lock(JSC::SilenceAssertionsOnly);
5733    Element* elt = toElement(toJS(toJS(context), nodeObject));
5734    if (!elt)
5735        return E_FAIL;
5736
5737    *element = DOMElement::createInstance(elt);
5738    return S_OK;
5739}
5740
5741HRESULT STDMETHODCALLTYPE WebView::setCustomHTMLTokenizerTimeDelay(
5742    /* [in] */ double timeDelay)
5743{
5744    if (!m_page)
5745        return E_FAIL;
5746
5747    m_page->setCustomHTMLTokenizerTimeDelay(timeDelay);
5748    return S_OK;
5749}
5750
5751HRESULT STDMETHODCALLTYPE WebView::setCustomHTMLTokenizerChunkSize(
5752    /* [in] */ int chunkSize)
5753{
5754    if (!m_page)
5755        return E_FAIL;
5756
5757    m_page->setCustomHTMLTokenizerChunkSize(chunkSize);
5758    return S_OK;
5759}
5760
5761HRESULT STDMETHODCALLTYPE WebView::backingStore(
5762    /* [out, retval] */ OLE_HANDLE* hBitmap)
5763{
5764    if (!hBitmap)
5765        return E_POINTER;
5766    if (!m_backingStoreBitmap)
5767        return E_FAIL;
5768    *hBitmap = reinterpret_cast<OLE_HANDLE>(m_backingStoreBitmap->handle());
5769    return S_OK;
5770}
5771
5772HRESULT STDMETHODCALLTYPE WebView::setTransparent(BOOL transparent)
5773{
5774    if (m_transparent == !!transparent)
5775        return S_OK;
5776
5777    m_transparent = transparent;
5778    m_mainFrame->updateBackground();
5779    return S_OK;
5780}
5781
5782HRESULT STDMETHODCALLTYPE WebView::transparent(BOOL* transparent)
5783{
5784    if (!transparent)
5785        return E_POINTER;
5786
5787    *transparent = this->transparent() ? TRUE : FALSE;
5788    return S_OK;
5789}
5790
5791HRESULT STDMETHODCALLTYPE WebView::setCookieEnabled(BOOL enable)
5792{
5793    if (!m_page)
5794        return E_FAIL;
5795
5796    m_page->setCookieEnabled(enable);
5797    return S_OK;
5798}
5799
5800HRESULT STDMETHODCALLTYPE WebView::cookieEnabled(BOOL* enabled)
5801{
5802    if (!enabled)
5803        return E_POINTER;
5804
5805    if (!m_page)
5806        return E_FAIL;
5807
5808    *enabled = m_page->cookieEnabled();
5809    return S_OK;
5810}
5811
5812HRESULT STDMETHODCALLTYPE WebView::setMediaVolume(float volume)
5813{
5814    if (!m_page)
5815        return E_FAIL;
5816
5817    m_page->setMediaVolume(volume);
5818    return S_OK;
5819}
5820
5821HRESULT STDMETHODCALLTYPE WebView::mediaVolume(float* volume)
5822{
5823    if (!volume)
5824        return E_POINTER;
5825
5826    if (!m_page)
5827        return E_FAIL;
5828
5829    *volume = m_page->mediaVolume();
5830    return S_OK;
5831}
5832
5833HRESULT STDMETHODCALLTYPE WebView::setDefersCallbacks(BOOL defersCallbacks)
5834{
5835    if (!m_page)
5836        return E_FAIL;
5837
5838    m_page->setDefersLoading(defersCallbacks);
5839    return S_OK;
5840}
5841
5842HRESULT STDMETHODCALLTYPE WebView::defersCallbacks(BOOL* defersCallbacks)
5843{
5844    if (!defersCallbacks)
5845        return E_POINTER;
5846
5847    if (!m_page)
5848        return E_FAIL;
5849
5850    *defersCallbacks = m_page->defersLoading();
5851    return S_OK;
5852}
5853
5854HRESULT STDMETHODCALLTYPE WebView::globalHistoryItem(IWebHistoryItem** item)
5855{
5856    if (!item)
5857        return E_POINTER;
5858
5859    if (!m_page)
5860        return E_FAIL;
5861
5862    if (!m_globalHistoryItem) {
5863        *item = 0;
5864        return S_OK;
5865    }
5866
5867    *item = WebHistoryItem::createInstance(m_globalHistoryItem);
5868    return S_OK;
5869}
5870
5871HRESULT STDMETHODCALLTYPE WebView::setAlwaysUsesComplexTextCodePath(BOOL complex)
5872{
5873    WebCoreSetAlwaysUsesComplexTextCodePath(complex);
5874
5875    return S_OK;
5876}
5877
5878HRESULT STDMETHODCALLTYPE WebView::alwaysUsesComplexTextCodePath(BOOL* complex)
5879{
5880    if (!complex)
5881        return E_POINTER;
5882
5883    *complex = WebCoreAlwaysUsesComplexTextCodePath();
5884    return S_OK;
5885}
5886
5887HRESULT STDMETHODCALLTYPE WebView::registerEmbeddedViewMIMEType(BSTR mimeType)
5888{
5889    if (!mimeType)
5890        return E_POINTER;
5891
5892    if (!m_embeddedViewMIMETypes)
5893        m_embeddedViewMIMETypes.set(new HashSet<String>);
5894
5895    m_embeddedViewMIMETypes->add(String(mimeType, ::SysStringLen(mimeType)));
5896    return S_OK;
5897}
5898
5899bool WebView::shouldUseEmbeddedView(const WTF::String& mimeType) const
5900{
5901    if (!m_embeddedViewMIMETypes)
5902        return false;
5903
5904    return m_embeddedViewMIMETypes->contains(mimeType);
5905}
5906
5907bool WebView::onGetObject(WPARAM wParam, LPARAM lParam, LRESULT& lResult) const
5908{
5909    lResult = 0;
5910
5911    if (lParam != OBJID_CLIENT)
5912        return false;
5913
5914    AXObjectCache::enableAccessibility();
5915
5916    // Get the accessible object for the top-level frame.
5917    WebFrame* mainFrameImpl = topLevelFrame();
5918    if (!mainFrameImpl)
5919        return false;
5920
5921    COMPtr<IAccessible> accessible = mainFrameImpl->accessible();
5922    if (!accessible)
5923        return false;
5924
5925    if (!accessibilityLib) {
5926        if (!(accessibilityLib = ::LoadLibraryW(L"oleacc.dll")))
5927            return false;
5928    }
5929
5930    static LPFNLRESULTFROMOBJECT procPtr = reinterpret_cast<LPFNLRESULTFROMOBJECT>(::GetProcAddress(accessibilityLib, "LresultFromObject"));
5931    if (!procPtr)
5932        return false;
5933
5934    // LresultFromObject returns a reference to the accessible object, stored
5935    // in an LRESULT. If this call is not successful, Windows will handle the
5936    // request through DefWindowProc.
5937    return SUCCEEDED(lResult = procPtr(__uuidof(IAccessible), wParam, accessible.get()));
5938}
5939
5940STDMETHODIMP WebView::AccessibleObjectFromWindow(HWND hwnd, DWORD objectID, REFIID riid, void** ppObject)
5941{
5942    ASSERT(accessibilityLib);
5943    static LPFNACCESSIBLEOBJECTFROMWINDOW procPtr = reinterpret_cast<LPFNACCESSIBLEOBJECTFROMWINDOW>(::GetProcAddress(accessibilityLib, "AccessibleObjectFromWindow"));
5944    if (!procPtr)
5945        return E_FAIL;
5946    return procPtr(hwnd, objectID, riid, ppObject);
5947}
5948
5949HRESULT WebView::setMemoryCacheDelegateCallsEnabled(BOOL enabled)
5950{
5951    m_page->setMemoryCacheClientCallsEnabled(enabled);
5952    return S_OK;
5953}
5954
5955HRESULT WebView::setJavaScriptURLsAreAllowed(BOOL areAllowed)
5956{
5957    m_page->setJavaScriptURLsAreAllowed(areAllowed);
5958    return S_OK;
5959}
5960
5961HRESULT WebView::setCanStartPlugins(BOOL canStartPlugins)
5962{
5963    m_page->setCanStartMedia(canStartPlugins);
5964    return S_OK;
5965}
5966
5967static String toString(BSTR bstr)
5968{
5969    return String(bstr, SysStringLen(bstr));
5970}
5971
5972static KURL toKURL(BSTR bstr)
5973{
5974    return KURL(KURL(), toString(bstr));
5975}
5976
5977void WebView::enterFullscreenForNode(Node* node)
5978{
5979    if (!node->hasTagName(HTMLNames::videoTag))
5980        return;
5981
5982#if ENABLE(VIDEO)
5983    HTMLMediaElement* videoElement = static_cast<HTMLMediaElement*>(node);
5984
5985    if (m_fullscreenController) {
5986        if (m_fullscreenController->mediaElement() == videoElement) {
5987            // The backend may just warn us that the underlaying plaftormMovie()
5988            // has changed. Just force an update.
5989            m_fullscreenController->setMediaElement(videoElement);
5990            return; // No more to do.
5991        }
5992
5993        // First exit Fullscreen for the old mediaElement.
5994        m_fullscreenController->mediaElement()->exitFullscreen();
5995        // This previous call has to trigger exitFullscreen,
5996        // which has to clear m_fullscreenController.
5997        ASSERT(!m_fullscreenController);
5998    }
5999
6000    m_fullscreenController = new FullscreenVideoController;
6001    m_fullscreenController->setMediaElement(videoElement);
6002    m_fullscreenController->enterFullscreen();
6003#endif
6004}
6005
6006void WebView::exitFullscreen()
6007{
6008#if ENABLE(VIDEO)
6009    if (m_fullscreenController)
6010        m_fullscreenController->exitFullscreen();
6011    m_fullscreenController = 0;
6012#endif
6013}
6014
6015static PassOwnPtr<Vector<String> > toStringVector(unsigned patternsCount, BSTR* patterns)
6016{
6017    // Convert the patterns into a Vector.
6018    if (patternsCount == 0)
6019        return 0;
6020    Vector<String>* patternsVector = new Vector<String>;
6021    for (unsigned i = 0; i < patternsCount; ++i)
6022        patternsVector->append(toString(patterns[i]));
6023    return patternsVector;
6024}
6025
6026HRESULT WebView::addUserScriptToGroup(BSTR groupName, IWebScriptWorld* iWorld, BSTR source, BSTR url,
6027                                      unsigned whitelistCount, BSTR* whitelist,
6028                                      unsigned blacklistCount, BSTR* blacklist,
6029                                      WebUserScriptInjectionTime injectionTime)
6030{
6031    COMPtr<WebScriptWorld> world(Query, iWorld);
6032    if (!world)
6033        return E_POINTER;
6034
6035    String group = toString(groupName);
6036    if (group.isEmpty())
6037        return E_INVALIDARG;
6038
6039    PageGroup* pageGroup = PageGroup::pageGroup(group);
6040    ASSERT(pageGroup);
6041    if (!pageGroup)
6042        return E_FAIL;
6043
6044    pageGroup->addUserScriptToWorld(world->world(), toString(source), toKURL(url),
6045                                    toStringVector(whitelistCount, whitelist), toStringVector(blacklistCount, blacklist),
6046                                    injectionTime == WebInjectAtDocumentStart ? InjectAtDocumentStart : InjectAtDocumentEnd,
6047                                    InjectInAllFrames);
6048
6049    return S_OK;
6050}
6051
6052HRESULT WebView::addUserStyleSheetToGroup(BSTR groupName, IWebScriptWorld* iWorld, BSTR source, BSTR url,
6053                                          unsigned whitelistCount, BSTR* whitelist,
6054                                          unsigned blacklistCount, BSTR* blacklist)
6055{
6056    COMPtr<WebScriptWorld> world(Query, iWorld);
6057    if (!world)
6058        return E_POINTER;
6059
6060    String group = toString(groupName);
6061    if (group.isEmpty())
6062        return E_INVALIDARG;
6063
6064    PageGroup* pageGroup = PageGroup::pageGroup(group);
6065    ASSERT(pageGroup);
6066    if (!pageGroup)
6067        return E_FAIL;
6068
6069    pageGroup->addUserStyleSheetToWorld(world->world(), toString(source), toKURL(url),
6070                                        toStringVector(whitelistCount, whitelist), toStringVector(blacklistCount, blacklist),
6071                                        InjectInAllFrames);
6072
6073    return S_OK;
6074}
6075
6076HRESULT WebView::removeUserScriptFromGroup(BSTR groupName, IWebScriptWorld* iWorld, BSTR url)
6077{
6078    COMPtr<WebScriptWorld> world(Query, iWorld);
6079    if (!world)
6080        return E_POINTER;
6081
6082    String group = toString(groupName);
6083    if (group.isEmpty())
6084        return E_INVALIDARG;
6085
6086    PageGroup* pageGroup = PageGroup::pageGroup(group);
6087    ASSERT(pageGroup);
6088    if (!pageGroup)
6089        return E_FAIL;
6090
6091    pageGroup->removeUserScriptFromWorld(world->world(), toKURL(url));
6092
6093    return S_OK;
6094}
6095
6096HRESULT WebView::removeUserStyleSheetFromGroup(BSTR groupName, IWebScriptWorld* iWorld, BSTR url)
6097{
6098    COMPtr<WebScriptWorld> world(Query, iWorld);
6099    if (!world)
6100        return E_POINTER;
6101
6102    String group = toString(groupName);
6103    if (group.isEmpty())
6104        return E_INVALIDARG;
6105
6106    PageGroup* pageGroup = PageGroup::pageGroup(group);
6107    ASSERT(pageGroup);
6108    if (!pageGroup)
6109        return E_FAIL;
6110
6111    pageGroup->removeUserStyleSheetFromWorld(world->world(), toKURL(url));
6112
6113    return S_OK;
6114}
6115
6116HRESULT WebView::removeUserScriptsFromGroup(BSTR groupName, IWebScriptWorld* iWorld)
6117{
6118    COMPtr<WebScriptWorld> world(Query, iWorld);
6119    if (!world)
6120        return E_POINTER;
6121
6122    String group = toString(groupName);
6123    if (group.isEmpty())
6124        return E_INVALIDARG;
6125
6126    PageGroup* pageGroup = PageGroup::pageGroup(group);
6127    ASSERT(pageGroup);
6128    if (!pageGroup)
6129        return E_FAIL;
6130
6131    pageGroup->removeUserScriptsFromWorld(world->world());
6132    return S_OK;
6133}
6134
6135HRESULT WebView::removeUserStyleSheetsFromGroup(BSTR groupName, IWebScriptWorld* iWorld)
6136{
6137    COMPtr<WebScriptWorld> world(Query, iWorld);
6138    if (!world)
6139        return E_POINTER;
6140
6141    String group = toString(groupName);
6142    if (group.isEmpty())
6143        return E_INVALIDARG;
6144
6145    PageGroup* pageGroup = PageGroup::pageGroup(group);
6146    ASSERT(pageGroup);
6147    if (!pageGroup)
6148        return E_FAIL;
6149
6150    pageGroup->removeUserStyleSheetsFromWorld(world->world());
6151    return S_OK;
6152}
6153
6154HRESULT WebView::removeAllUserContentFromGroup(BSTR groupName)
6155{
6156    String group = toString(groupName);
6157    if (group.isEmpty())
6158        return E_INVALIDARG;
6159
6160    PageGroup* pageGroup = PageGroup::pageGroup(group);
6161    ASSERT(pageGroup);
6162    if (!pageGroup)
6163        return E_FAIL;
6164
6165    pageGroup->removeAllUserContent();
6166    return S_OK;
6167}
6168
6169HRESULT WebView::invalidateBackingStore(const RECT* rect)
6170{
6171    if (!IsWindow(m_viewWindow))
6172        return S_OK;
6173
6174    RECT clientRect;
6175    if (!GetClientRect(m_viewWindow, &clientRect))
6176        return E_FAIL;
6177
6178    RECT rectToInvalidate;
6179    if (!rect)
6180        rectToInvalidate = clientRect;
6181    else if (!IntersectRect(&rectToInvalidate, &clientRect, rect))
6182        return S_OK;
6183
6184    repaint(rectToInvalidate, true);
6185    return S_OK;
6186}
6187
6188HRESULT WebView::addOriginAccessWhitelistEntry(BSTR sourceOrigin, BSTR destinationProtocol, BSTR destinationHost, BOOL allowDestinationSubdomains)
6189{
6190    SecurityOrigin::addOriginAccessWhitelistEntry(*SecurityOrigin::createFromString(String(sourceOrigin, SysStringLen(sourceOrigin))), String(destinationProtocol, SysStringLen(destinationProtocol)), String(destinationHost, SysStringLen(destinationHost)), allowDestinationSubdomains);
6191    return S_OK;
6192}
6193
6194HRESULT WebView::removeOriginAccessWhitelistEntry(BSTR sourceOrigin, BSTR destinationProtocol, BSTR destinationHost, BOOL allowDestinationSubdomains)
6195{
6196    SecurityOrigin::removeOriginAccessWhitelistEntry(*SecurityOrigin::createFromString(String(sourceOrigin, SysStringLen(sourceOrigin))), String(destinationProtocol, SysStringLen(destinationProtocol)), String(destinationHost, SysStringLen(destinationHost)), allowDestinationSubdomains);
6197    return S_OK;
6198}
6199
6200HRESULT WebView::resetOriginAccessWhitelists()
6201{
6202    SecurityOrigin::resetOriginAccessWhitelists();
6203    return S_OK;
6204}
6205
6206HRESULT WebView::setHistoryDelegate(IWebHistoryDelegate* historyDelegate)
6207{
6208    m_historyDelegate = historyDelegate;
6209    return S_OK;
6210}
6211
6212HRESULT WebView::historyDelegate(IWebHistoryDelegate** historyDelegate)
6213{
6214    if (!historyDelegate)
6215        return E_POINTER;
6216
6217    return m_historyDelegate.copyRefTo(historyDelegate);
6218}
6219
6220HRESULT WebView::addVisitedLinks(BSTR* visitedURLs, unsigned visitedURLCount)
6221{
6222    PageGroup& group = core(this)->group();
6223
6224    for (unsigned i = 0; i < visitedURLCount; ++i) {
6225        BSTR url = visitedURLs[i];
6226        unsigned length = SysStringLen(url);
6227        group.addVisitedLink(url, length);
6228    }
6229
6230    return S_OK;
6231}
6232
6233void WebView::downloadURL(const KURL& url)
6234{
6235    // It's the delegate's job to ref the WebDownload to keep it alive - otherwise it will be
6236    // destroyed when this function returns.
6237    COMPtr<WebDownload> download(AdoptCOM, WebDownload::createInstance(url, m_downloadDelegate.get()));
6238    download->start();
6239}
6240
6241#if USE(ACCELERATED_COMPOSITING)
6242void WebView::setRootChildLayer(GraphicsLayer* layer)
6243{
6244    setAcceleratedCompositing(layer ? true : false);
6245    if (!m_backingLayer)
6246        return;
6247    m_backingLayer->addChild(layer);
6248}
6249
6250void WebView::flushPendingGraphicsLayerChangesSoon()
6251{
6252    if (!m_layerTreeHost)
6253        return;
6254    m_layerTreeHost->flushPendingGraphicsLayerChangesSoon();
6255}
6256
6257void WebView::setAcceleratedCompositing(bool accelerated)
6258{
6259    if (m_isAcceleratedCompositing == accelerated || !CACFLayerTreeHost::acceleratedCompositingAvailable())
6260        return;
6261
6262    if (accelerated) {
6263        m_layerTreeHost = CACFLayerTreeHost::create();
6264        if (m_layerTreeHost) {
6265            m_isAcceleratedCompositing = true;
6266
6267            m_layerTreeHost->setClient(this);
6268            ASSERT(m_viewWindow);
6269            m_layerTreeHost->setWindow(m_viewWindow);
6270
6271            // FIXME: We could perhaps get better performance by never allowing this layer to
6272            // become tiled (or choosing a higher-than-normal tiling threshold).
6273            // <http://webkit.org/b/52603>
6274            m_backingLayer = GraphicsLayer::create(this);
6275            m_backingLayer->setDrawsContent(true);
6276            m_backingLayer->setContentsOpaque(true);
6277            RECT clientRect;
6278            ::GetClientRect(m_viewWindow, &clientRect);
6279            m_backingLayer->setSize(IntRect(clientRect).size());
6280            m_backingLayer->setNeedsDisplay();
6281
6282            m_layerTreeHost->setRootChildLayer(PlatformCALayer::platformCALayer(m_backingLayer->platformLayer()));
6283
6284            // We aren't going to be using our backing store while we're in accelerated compositing
6285            // mode. But don't delete it immediately, in case we switch out of accelerated
6286            // compositing mode soon (e.g., if we're only compositing for a :hover animation).
6287            deleteBackingStoreSoon();
6288        }
6289    } else {
6290        ASSERT(m_layerTreeHost);
6291        m_layerTreeHost->setClient(0);
6292        m_layerTreeHost->setWindow(0);
6293        m_layerTreeHost = 0;
6294        m_backingLayer = 0;
6295        m_isAcceleratedCompositing = false;
6296    }
6297}
6298#endif
6299
6300HRESULT STDMETHODCALLTYPE WebView::setPluginHalterDelegate(IWebPluginHalterDelegate* d)
6301{
6302    m_pluginHalterDelegate = d;
6303    return S_OK;
6304}
6305
6306HRESULT STDMETHODCALLTYPE WebView::pluginHalterDelegate(IWebPluginHalterDelegate** d)
6307{
6308    if (!d)
6309        return E_POINTER;
6310
6311    if (!m_pluginHalterDelegate)
6312        return E_FAIL;
6313
6314    return m_pluginHalterDelegate.copyRefTo(d);
6315}
6316
6317static PluginView* pluginViewForNode(IDOMNode* domNode)
6318{
6319    COMPtr<DOMNode> webKitDOMNode(Query, domNode);
6320    if (!webKitDOMNode)
6321        return 0;
6322
6323    Node* node = webKitDOMNode->node();
6324    if (!node)
6325        return 0;
6326
6327    RenderObject* renderer = node->renderer();
6328    if (!renderer || !renderer->isWidget())
6329        return 0;
6330
6331    Widget* widget = toRenderWidget(renderer)->widget();
6332    if (!widget || !widget->isPluginView())
6333        return 0;
6334
6335    return static_cast<PluginView*>(widget);
6336}
6337
6338HRESULT WebView::isNodeHaltedPlugin(IDOMNode* domNode, BOOL* result)
6339{
6340    if (!domNode || !result)
6341        return E_POINTER;
6342
6343    *result = FALSE;
6344
6345    PluginView* view = pluginViewForNode(domNode);
6346    if (!view)
6347        return E_FAIL;
6348
6349    *result = view->isHalted();
6350    return S_OK;
6351}
6352
6353HRESULT WebView::restartHaltedPluginForNode(IDOMNode* domNode)
6354{
6355    if (!domNode)
6356        return E_POINTER;
6357
6358    PluginView* view = pluginViewForNode(domNode);
6359    if (!view)
6360        return E_FAIL;
6361
6362    view->restart();
6363    return S_OK;
6364}
6365
6366HRESULT WebView::hasPluginForNodeBeenHalted(IDOMNode* domNode, BOOL* result)
6367{
6368    if (!domNode || !result)
6369        return E_POINTER;
6370
6371    *result = FALSE;
6372
6373    PluginView* view = pluginViewForNode(domNode);
6374    if (!view)
6375        return E_FAIL;
6376
6377    *result = view->hasBeenHalted();
6378    return S_OK;
6379}
6380
6381HRESULT WebView::setGeolocationProvider(IWebGeolocationProvider* locationProvider)
6382{
6383    m_geolocationProvider = locationProvider;
6384    return S_OK;
6385}
6386
6387HRESULT WebView::geolocationProvider(IWebGeolocationProvider** locationProvider)
6388{
6389    if (!locationProvider)
6390        return E_POINTER;
6391
6392    if (!m_geolocationProvider)
6393        return E_FAIL;
6394
6395    return m_geolocationProvider.copyRefTo(locationProvider);
6396}
6397
6398HRESULT WebView::geolocationDidChangePosition(IWebGeolocationPosition* position)
6399{
6400#if ENABLE(CLIENT_BASED_GEOLOCATION)
6401    if (!m_page)
6402        return E_FAIL;
6403    m_page->geolocationController()->positionChanged(core(position));
6404    return S_OK;
6405#else
6406    return E_NOTIMPL;
6407#endif
6408}
6409
6410HRESULT WebView::geolocationDidFailWithError(IWebError* error)
6411{
6412#if ENABLE(CLIENT_BASED_GEOLOCATION)
6413    if (!m_page)
6414        return E_FAIL;
6415    if (!error)
6416        return E_POINTER;
6417
6418    BSTR descriptionBSTR;
6419    if (FAILED(error->localizedDescription(&descriptionBSTR)))
6420        return E_FAIL;
6421    String descriptionString(descriptionBSTR, SysStringLen(descriptionBSTR));
6422    SysFreeString(descriptionBSTR);
6423
6424    RefPtr<GeolocationError> geolocationError = GeolocationError::create(GeolocationError::PositionUnavailable, descriptionString);
6425    m_page->geolocationController()->errorOccurred(geolocationError.get());
6426    return S_OK;
6427#else
6428    return E_NOTIMPL;
6429#endif
6430}
6431
6432HRESULT WebView::setDomainRelaxationForbiddenForURLScheme(BOOL forbidden, BSTR scheme)
6433{
6434    SecurityOrigin::setDomainRelaxationForbiddenForURLScheme(forbidden, String(scheme, SysStringLen(scheme)));
6435    return S_OK;
6436}
6437
6438HRESULT WebView::registerURLSchemeAsSecure(BSTR scheme)
6439{
6440    SchemeRegistry::registerURLSchemeAsSecure(toString(scheme));
6441    return S_OK;
6442}
6443
6444HRESULT WebView::nextDisplayIsSynchronous()
6445{
6446    m_nextDisplayIsSynchronous = true;
6447    return S_OK;
6448}
6449
6450#if USE(ACCELERATED_COMPOSITING)
6451void WebView::notifyAnimationStarted(const GraphicsLayer*, double)
6452{
6453    // We never set any animations on our backing layer.
6454    ASSERT_NOT_REACHED();
6455}
6456
6457void WebView::notifySyncRequired(const GraphicsLayer*)
6458{
6459    flushPendingGraphicsLayerChangesSoon();
6460}
6461
6462void WebView::paintContents(const GraphicsLayer*, GraphicsContext& context, GraphicsLayerPaintingPhase, const IntRect& inClip)
6463{
6464    Frame* frame = core(m_mainFrame);
6465    if (!frame)
6466        return;
6467
6468    context.save();
6469    context.clip(inClip);
6470    frame->view()->paint(&context, inClip);
6471    context.restore();
6472}
6473
6474bool WebView::showDebugBorders() const
6475{
6476    return m_page->settings()->showDebugBorders();
6477}
6478
6479bool WebView::showRepaintCounter() const
6480{
6481    return m_page->settings()->showRepaintCounter();
6482}
6483
6484void WebView::flushPendingGraphicsLayerChanges()
6485{
6486    Frame* coreFrame = core(m_mainFrame);
6487    if (!coreFrame)
6488        return;
6489    FrameView* view = coreFrame->view();
6490    if (!view)
6491        return;
6492    if (!m_backingLayer)
6493        return;
6494
6495    view->updateLayoutAndStyleIfNeededRecursive();
6496
6497    // Updating layout might have taken us out of compositing mode.
6498    if (m_backingLayer)
6499        m_backingLayer->syncCompositingStateForThisLayerOnly();
6500
6501    view->syncCompositingStateIncludingSubframes();
6502}
6503
6504#endif
6505
6506class EnumTextMatches : public IEnumTextMatches
6507{
6508    long m_ref;
6509    UINT m_index;
6510    Vector<IntRect> m_rects;
6511public:
6512    EnumTextMatches(Vector<IntRect>* rects) : m_index(0), m_ref(1)
6513    {
6514        m_rects = *rects;
6515    }
6516
6517    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv)
6518    {
6519        if (IsEqualGUID(riid, IID_IUnknown) || IsEqualGUID(riid, IID_IEnumTextMatches)) {
6520            *ppv = this;
6521            AddRef();
6522        }
6523
6524        return *ppv?S_OK:E_NOINTERFACE;
6525    }
6526
6527    virtual ULONG STDMETHODCALLTYPE AddRef()
6528    {
6529        return m_ref++;
6530    }
6531
6532    virtual ULONG STDMETHODCALLTYPE Release()
6533    {
6534        if (m_ref == 1) {
6535            delete this;
6536            return 0;
6537        }
6538        else
6539            return m_ref--;
6540    }
6541
6542    virtual HRESULT STDMETHODCALLTYPE Next(ULONG, RECT* rect, ULONG* pceltFetched)
6543    {
6544        if (m_index < m_rects.size()) {
6545            if (pceltFetched)
6546                *pceltFetched = 1;
6547            *rect = m_rects[m_index];
6548            m_index++;
6549            return S_OK;
6550        }
6551
6552        if (pceltFetched)
6553            *pceltFetched = 0;
6554
6555        return S_FALSE;
6556    }
6557    virtual HRESULT STDMETHODCALLTYPE Skip(ULONG celt)
6558    {
6559        m_index += celt;
6560        return S_OK;
6561    }
6562    virtual HRESULT STDMETHODCALLTYPE Reset(void)
6563    {
6564        m_index = 0;
6565        return S_OK;
6566    }
6567    virtual HRESULT STDMETHODCALLTYPE Clone(IEnumTextMatches**)
6568    {
6569        return E_NOTIMPL;
6570    }
6571};
6572
6573HRESULT createMatchEnumerator(Vector<IntRect>* rects, IEnumTextMatches** matches)
6574{
6575    *matches = new EnumTextMatches(rects);
6576    return (*matches)?S_OK:E_OUTOFMEMORY;
6577}
6578
6579Page* core(IWebView* iWebView)
6580{
6581    Page* page = 0;
6582
6583    COMPtr<WebView> webView;
6584    if (SUCCEEDED(iWebView->QueryInterface(&webView)) && webView)
6585        page = webView->page();
6586
6587    return page;
6588}
6589
6590HRESULT WebView::defaultMinimumTimerInterval(double* interval)
6591{
6592    if (!interval)
6593        return E_POINTER;
6594    *interval = Settings::defaultMinDOMTimerInterval();
6595    return S_OK;
6596}
6597
6598HRESULT WebView::setMinimumTimerInterval(double interval)
6599{
6600    page()->settings()->setMinDOMTimerInterval(interval);
6601    return S_OK;
6602}
6603
6604void WebView::setGlobalHistoryItem(HistoryItem* historyItem)
6605{
6606    m_globalHistoryItem = historyItem;
6607}
6608