WebView.cpp revision 2bde8e466a4451c7319e3a072d118917957d6554
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 "WindowsTouch.h"
62#include "resource.h"
63#include <JavaScriptCore/APICast.h>
64#include <JavaScriptCore/InitializeThreading.h>
65#include <JavaScriptCore/JSLock.h>
66#include <JavaScriptCore/JSValue.h>
67#include <WebCore/AbstractDatabase.h>
68#include <WebCore/AXObjectCache.h>
69#include <WebCore/ApplicationCacheStorage.h>
70#include <WebCore/BString.h>
71#include <WebCore/BackForwardListImpl.h>
72#include <WebCore/BitmapInfo.h>
73#include <WebCore/MemoryCache.h>
74#include <WebCore/Chrome.h>
75#include <WebCore/ContextMenu.h>
76#include <WebCore/ContextMenuController.h>
77#include <WebCore/Cursor.h>
78#include <WebCore/Document.h>
79#include <WebCore/DocumentMarkerController.h>
80#include <WebCore/DragController.h>
81#include <WebCore/DragData.h>
82#include <WebCore/Editor.h>
83#include <WebCore/EventHandler.h>
84#include <WebCore/EventNames.h>
85#include <WebCore/FileSystem.h>
86#include <WebCore/FloatQuad.h>
87#include <WebCore/FocusController.h>
88#include <WebCore/FrameLoader.h>
89#include <WebCore/FrameTree.h>
90#include <WebCore/FrameView.h>
91#include <WebCore/FrameWin.h>
92#include <WebCore/GDIObjectCounter.h>
93#include <WebCore/GraphicsContext.h>
94#include <WebCore/HTMLMediaElement.h>
95#include <WebCore/HTMLNames.h>
96#include <WebCore/HistoryItem.h>
97#include <WebCore/HitTestRequest.h>
98#include <WebCore/HitTestResult.h>
99#include <WebCore/IntRect.h>
100#include <WebCore/JSElement.h>
101#include <WebCore/KeyboardEvent.h>
102#include <WebCore/Logging.h>
103#include <WebCore/MIMETypeRegistry.h>
104#include <WebCore/Page.h>
105#include <WebCore/PageCache.h>
106#include <WebCore/PageGroup.h>
107#include <WebCore/PlatformKeyboardEvent.h>
108#include <WebCore/PlatformMouseEvent.h>
109#include <WebCore/PlatformWheelEvent.h>
110#include <WebCore/PluginData.h>
111#include <WebCore/PluginDatabase.h>
112#include <WebCore/PluginView.h>
113#include <WebCore/PopupMenu.h>
114#include <WebCore/PopupMenuWin.h>
115#include <WebCore/ProgressTracker.h>
116#include <WebCore/RenderLayer.h>
117#include <WebCore/RenderTheme.h>
118#include <WebCore/RenderTreeAsText.h>
119#include <WebCore/RenderView.h>
120#include <WebCore/RenderWidget.h>
121#include <WebCore/ResourceHandle.h>
122#include <WebCore/ResourceHandleClient.h>
123#include <WebCore/SchemeRegistry.h>
124#include <WebCore/ScriptValue.h>
125#include <WebCore/Scrollbar.h>
126#include <WebCore/ScrollbarTheme.h>
127#include <WebCore/SecurityOrigin.h>
128#include <WebCore/SelectionController.h>
129#include <WebCore/Settings.h>
130#include <WebCore/SimpleFontData.h>
131#include <WebCore/SystemInfo.h>
132#include <WebCore/TypingCommand.h>
133#include <WebCore/WindowMessageBroadcaster.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 PLATFORM(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#if USE(ACCELERATED_COMPOSITING)
1083    ASSERT(!isAcceleratedCompositing());
1084#endif
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#if USE(ACCELERATED_COMPOSITING)
1126    ASSERT(!isAcceleratedCompositing());
1127#endif
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    if (virtualKeyCode == VK_CAPITAL)
1939        frame->eventHandler()->capsLockStateMayHaveChanged();
1940
1941    PlatformKeyboardEvent keyEvent(m_viewWindow, virtualKeyCode, keyData, PlatformKeyboardEvent::RawKeyDown, systemKeyDown);
1942    bool handled = frame->eventHandler()->keyEvent(keyEvent);
1943
1944    // These events cannot be canceled, and we have no default handling for them.
1945    // FIXME: match IE list more closely, see <http://msdn2.microsoft.com/en-us/library/ms536938.aspx>.
1946    if (systemKeyDown && virtualKeyCode != VK_RETURN)
1947        return false;
1948
1949    if (handled) {
1950        // FIXME: remove WM_UNICHAR, too
1951        MSG msg;
1952        // WM_SYSCHAR events should not be removed, because access keys are implemented in WebCore in WM_SYSCHAR handler.
1953        if (!systemKeyDown)
1954            ::PeekMessage(&msg, m_viewWindow, WM_CHAR, WM_CHAR, PM_REMOVE);
1955        return true;
1956    }
1957
1958    // We need to handle back/forward using either Backspace(+Shift) or Ctrl+Left/Right Arrow keys.
1959    if ((virtualKeyCode == VK_BACK && keyEvent.shiftKey()) || (virtualKeyCode == VK_RIGHT && keyEvent.ctrlKey()))
1960        return m_page->goForward();
1961    if (virtualKeyCode == VK_BACK || (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
2018bool WebView::registerWebViewWindowClass()
2019{
2020    static bool haveRegisteredWindowClass = false;
2021    if (haveRegisteredWindowClass)
2022        return true;
2023
2024    haveRegisteredWindowClass = true;
2025
2026    WNDCLASSEX wcex;
2027
2028    wcex.cbSize = sizeof(WNDCLASSEX);
2029
2030    wcex.style          = CS_DBLCLKS;
2031    wcex.lpfnWndProc    = WebViewWndProc;
2032    wcex.cbClsExtra     = 0;
2033    wcex.cbWndExtra     = 4; // 4 bytes for the IWebView pointer
2034    wcex.hInstance      = gInstance;
2035    wcex.hIcon          = 0;
2036    wcex.hCursor        = ::LoadCursor(0, IDC_ARROW);
2037    wcex.hbrBackground  = 0;
2038    wcex.lpszMenuName   = 0;
2039    wcex.lpszClassName  = kWebViewWindowClassName;
2040    wcex.hIconSm        = 0;
2041
2042    return !!RegisterClassEx(&wcex);
2043}
2044
2045static HWND findTopLevelParent(HWND window)
2046{
2047    if (!window)
2048        return 0;
2049
2050    HWND current = window;
2051    for (HWND parent = GetParent(current); current; current = parent, parent = GetParent(parent))
2052        if (!parent || !(GetWindowLongPtr(current, GWL_STYLE) & (WS_POPUP | WS_CHILD)))
2053            return current;
2054    ASSERT_NOT_REACHED();
2055    return 0;
2056}
2057
2058LRESULT CALLBACK WebView::WebViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
2059{
2060    LRESULT lResult = 0;
2061    LONG_PTR longPtr = GetWindowLongPtr(hWnd, 0);
2062    WebView* webView = reinterpret_cast<WebView*>(longPtr);
2063    WebFrame* mainFrameImpl = webView ? webView->topLevelFrame() : 0;
2064    if (!mainFrameImpl || webView->isBeingDestroyed())
2065        return DefWindowProc(hWnd, message, wParam, lParam);
2066
2067    // hold a ref, since the WebView could go away in an event handler.
2068    COMPtr<WebView> protector(webView);
2069    ASSERT(webView);
2070
2071    // Windows Media Player has a modal message loop that will deliver messages
2072    // to us at inappropriate times and we will crash if we handle them when
2073    // they are delivered. We repost paint messages so that we eventually get
2074    // a chance to paint once the modal loop has exited, but other messages
2075    // aren't safe to repost, so we just drop them.
2076    if (PluginView::isCallingPlugin()) {
2077        if (message == WM_PAINT)
2078            PostMessage(hWnd, message, wParam, lParam);
2079        return 0;
2080    }
2081
2082    bool handled = true;
2083
2084    switch (message) {
2085        case WM_PAINT: {
2086            webView->paint(0, 0);
2087            break;
2088        }
2089        case WM_PRINTCLIENT:
2090            webView->paint((HDC)wParam, lParam);
2091            break;
2092        case WM_DESTROY:
2093            webView->setIsBeingDestroyed();
2094            webView->close();
2095            break;
2096        case WM_GESTURENOTIFY:
2097            handled = webView->gestureNotify(wParam, lParam);
2098            break;
2099        case WM_GESTURE:
2100            handled = webView->gesture(wParam, lParam);
2101            break;
2102        case WM_MOUSEMOVE:
2103        case WM_LBUTTONDOWN:
2104        case WM_MBUTTONDOWN:
2105        case WM_RBUTTONDOWN:
2106        case WM_LBUTTONDBLCLK:
2107        case WM_MBUTTONDBLCLK:
2108        case WM_RBUTTONDBLCLK:
2109        case WM_LBUTTONUP:
2110        case WM_MBUTTONUP:
2111        case WM_RBUTTONUP:
2112        case WM_MOUSELEAVE:
2113        case WM_CANCELMODE:
2114            if (Frame* coreFrame = core(mainFrameImpl))
2115                if (coreFrame->view()->didFirstLayout())
2116                    handled = webView->handleMouseEvent(message, wParam, lParam);
2117            break;
2118        case WM_MOUSEWHEEL:
2119        case WM_VISTA_MOUSEHWHEEL:
2120            if (Frame* coreFrame = core(mainFrameImpl))
2121                if (coreFrame->view()->didFirstLayout())
2122                    handled = webView->mouseWheel(wParam, lParam, message == WM_VISTA_MOUSEHWHEEL);
2123            break;
2124        case WM_SYSKEYDOWN:
2125            handled = webView->keyDown(wParam, lParam, true);
2126            break;
2127        case WM_KEYDOWN:
2128            handled = webView->keyDown(wParam, lParam);
2129            break;
2130        case WM_SYSKEYUP:
2131            handled = webView->keyUp(wParam, lParam, true);
2132            break;
2133        case WM_KEYUP:
2134            handled = webView->keyUp(wParam, lParam);
2135            break;
2136        case WM_SYSCHAR:
2137            handled = webView->keyPress(wParam, lParam, true);
2138            break;
2139        case WM_CHAR:
2140            handled = webView->keyPress(wParam, lParam);
2141            break;
2142        // FIXME: We need to check WM_UNICHAR to support supplementary characters (that don't fit in 16 bits).
2143        case WM_SIZE:
2144            if (lParam != 0)
2145                webView->sizeChanged(IntSize(LOWORD(lParam), HIWORD(lParam)));
2146            break;
2147        case WM_SHOWWINDOW:
2148            lResult = DefWindowProc(hWnd, message, wParam, lParam);
2149            if (wParam == 0) {
2150                // The window is being hidden (e.g., because we switched tabs).
2151                // Null out our backing store.
2152                webView->deleteBackingStore();
2153            }
2154            break;
2155        case WM_SETFOCUS: {
2156            COMPtr<IWebUIDelegate> uiDelegate;
2157            COMPtr<IWebUIDelegatePrivate> uiDelegatePrivate;
2158            if (SUCCEEDED(webView->uiDelegate(&uiDelegate)) && uiDelegate
2159                && SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**) &uiDelegatePrivate)) && uiDelegatePrivate)
2160                uiDelegatePrivate->webViewReceivedFocus(webView);
2161
2162            FocusController* focusController = webView->page()->focusController();
2163            if (Frame* frame = focusController->focusedFrame()) {
2164                // Send focus events unless the previously focused window is a
2165                // child of ours (for example a plugin).
2166                if (!IsChild(hWnd, reinterpret_cast<HWND>(wParam)))
2167                    focusController->setFocused(true);
2168            } else
2169                focusController->setFocused(true);
2170            break;
2171        }
2172        case WM_KILLFOCUS: {
2173            COMPtr<IWebUIDelegate> uiDelegate;
2174            COMPtr<IWebUIDelegatePrivate> uiDelegatePrivate;
2175            HWND newFocusWnd = reinterpret_cast<HWND>(wParam);
2176            if (SUCCEEDED(webView->uiDelegate(&uiDelegate)) && uiDelegate
2177                && SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**) &uiDelegatePrivate)) && uiDelegatePrivate)
2178                uiDelegatePrivate->webViewLostFocus(webView, (OLE_HANDLE)(ULONG64)newFocusWnd);
2179
2180            FocusController* focusController = webView->page()->focusController();
2181            Frame* frame = focusController->focusedOrMainFrame();
2182            webView->resetIME(frame);
2183            // Send blur events unless we're losing focus to a child of ours.
2184            if (!IsChild(hWnd, newFocusWnd))
2185                focusController->setFocused(false);
2186
2187            // If we are pan-scrolling when we lose focus, stop the pan scrolling.
2188            frame->eventHandler()->stopAutoscrollTimer();
2189
2190            break;
2191        }
2192        case WM_WINDOWPOSCHANGED:
2193            if (reinterpret_cast<WINDOWPOS*>(lParam)->flags & SWP_SHOWWINDOW)
2194                webView->updateActiveStateSoon();
2195            handled = false;
2196            break;
2197        case WM_CUT:
2198            webView->cut(0);
2199            break;
2200        case WM_COPY:
2201            webView->copy(0);
2202            break;
2203        case WM_PASTE:
2204            webView->paste(0);
2205            break;
2206        case WM_CLEAR:
2207            webView->delete_(0);
2208            break;
2209        case WM_COMMAND:
2210            if (HIWORD(wParam))
2211                handled = webView->execCommand(wParam, lParam);
2212            else // If the high word of wParam is 0, the message is from a menu
2213                webView->performContextMenuAction(wParam, lParam, false);
2214            break;
2215        case WM_MENUCOMMAND:
2216            webView->performContextMenuAction(wParam, lParam, true);
2217            break;
2218        case WM_CONTEXTMENU:
2219            handled = webView->handleContextMenuEvent(wParam, lParam);
2220            break;
2221        case WM_INITMENUPOPUP:
2222            handled = webView->onInitMenuPopup(wParam, lParam);
2223            break;
2224        case WM_MEASUREITEM:
2225            handled = webView->onMeasureItem(wParam, lParam);
2226            break;
2227        case WM_DRAWITEM:
2228            handled = webView->onDrawItem(wParam, lParam);
2229            break;
2230        case WM_UNINITMENUPOPUP:
2231            handled = webView->onUninitMenuPopup(wParam, lParam);
2232            break;
2233        case WM_XP_THEMECHANGED:
2234            if (Frame* coreFrame = core(mainFrameImpl)) {
2235                webView->deleteBackingStore();
2236                coreFrame->page()->theme()->themeChanged();
2237                ScrollbarTheme::nativeTheme()->themeChanged();
2238                RECT windowRect;
2239                ::GetClientRect(hWnd, &windowRect);
2240                ::InvalidateRect(hWnd, &windowRect, false);
2241#if USE(ACCELERATED_COMPOSITING)
2242                if (webView->isAcceleratedCompositing())
2243                    webView->m_backingLayer->setNeedsDisplay();
2244#endif
2245           }
2246            break;
2247        case WM_MOUSEACTIVATE:
2248            webView->setMouseActivated(true);
2249            handled = false;
2250            break;
2251        case WM_GETDLGCODE: {
2252            COMPtr<IWebUIDelegate> uiDelegate;
2253            COMPtr<IWebUIDelegatePrivate> uiDelegatePrivate;
2254            LONG_PTR dlgCode = 0;
2255            UINT keyCode = 0;
2256            if (lParam) {
2257                LPMSG lpMsg = (LPMSG)lParam;
2258                if (lpMsg->message == WM_KEYDOWN)
2259                    keyCode = (UINT) lpMsg->wParam;
2260            }
2261            if (SUCCEEDED(webView->uiDelegate(&uiDelegate)) && uiDelegate
2262                && SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**) &uiDelegatePrivate)) && uiDelegatePrivate
2263                && SUCCEEDED(uiDelegatePrivate->webViewGetDlgCode(webView, keyCode, &dlgCode)))
2264                return dlgCode;
2265            handled = false;
2266            break;
2267        }
2268        case WM_GETOBJECT:
2269            handled = webView->onGetObject(wParam, lParam, lResult);
2270            break;
2271        case WM_IME_STARTCOMPOSITION:
2272            handled = webView->onIMEStartComposition();
2273            break;
2274        case WM_IME_REQUEST:
2275            lResult = webView->onIMERequest(wParam, lParam);
2276            break;
2277        case WM_IME_COMPOSITION:
2278            handled = webView->onIMEComposition(lParam);
2279            break;
2280        case WM_IME_ENDCOMPOSITION:
2281            handled = webView->onIMEEndComposition();
2282            break;
2283        case WM_IME_CHAR:
2284            handled = webView->onIMEChar(wParam, lParam);
2285            break;
2286        case WM_IME_NOTIFY:
2287            handled = webView->onIMENotify(wParam, lParam, &lResult);
2288            break;
2289        case WM_IME_SELECT:
2290            handled = webView->onIMESelect(wParam, lParam);
2291            break;
2292        case WM_IME_SETCONTEXT:
2293            handled = webView->onIMESetContext(wParam, lParam);
2294            break;
2295        case WM_TIMER:
2296            switch (wParam) {
2297                case UpdateActiveStateTimer:
2298                    KillTimer(hWnd, UpdateActiveStateTimer);
2299                    webView->updateActiveState();
2300                    break;
2301                case DeleteBackingStoreTimer:
2302                    webView->deleteBackingStore();
2303                    break;
2304            }
2305            break;
2306        case WM_SETCURSOR:
2307            handled = ::SetCursor(webView->m_lastSetCursor);
2308            break;
2309        case WM_VSCROLL:
2310            handled = webView->verticalScroll(wParam, lParam);
2311            break;
2312        case WM_HSCROLL:
2313            handled = webView->horizontalScroll(wParam, lParam);
2314            break;
2315        default:
2316            handled = false;
2317            break;
2318    }
2319
2320    if (!handled)
2321        lResult = DefWindowProc(hWnd, message, wParam, lParam);
2322
2323    // Let the client know whether we consider this message handled.
2324    return (message == WM_KEYDOWN || message == WM_SYSKEYDOWN || message == WM_KEYUP || message == WM_SYSKEYUP) ? !handled : lResult;
2325}
2326
2327bool WebView::developerExtrasEnabled() const
2328{
2329    if (m_preferences->developerExtrasDisabledByOverride())
2330        return false;
2331
2332#ifdef NDEBUG
2333    BOOL enabled;
2334    return SUCCEEDED(m_preferences->developerExtrasEnabled(&enabled)) && enabled;
2335#else
2336    return true;
2337#endif
2338}
2339
2340static String webKitVersionString()
2341{
2342    LPWSTR buildNumberStringPtr;
2343    if (!::LoadStringW(gInstance, BUILD_NUMBER, reinterpret_cast<LPWSTR>(&buildNumberStringPtr), 0) || !buildNumberStringPtr)
2344        return "534+";
2345
2346    return buildNumberStringPtr;
2347}
2348
2349const String& WebView::userAgentForKURL(const KURL&)
2350{
2351    if (m_userAgentOverridden)
2352        return m_userAgentCustom;
2353
2354    if (!m_userAgentStandard.length())
2355        m_userAgentStandard = WebView::standardUserAgentWithApplicationName(m_applicationName);
2356    return m_userAgentStandard;
2357}
2358
2359// IUnknown -------------------------------------------------------------------
2360
2361HRESULT STDMETHODCALLTYPE WebView::QueryInterface(REFIID riid, void** ppvObject)
2362{
2363    *ppvObject = 0;
2364    if (IsEqualGUID(riid, CLSID_WebView))
2365        *ppvObject = this;
2366    else if (IsEqualGUID(riid, IID_IUnknown))
2367        *ppvObject = static_cast<IWebView*>(this);
2368    else if (IsEqualGUID(riid, IID_IWebView))
2369        *ppvObject = static_cast<IWebView*>(this);
2370    else if (IsEqualGUID(riid, IID_IWebViewPrivate))
2371        *ppvObject = static_cast<IWebViewPrivate*>(this);
2372    else if (IsEqualGUID(riid, IID_IWebIBActions))
2373        *ppvObject = static_cast<IWebIBActions*>(this);
2374    else if (IsEqualGUID(riid, IID_IWebViewCSS))
2375        *ppvObject = static_cast<IWebViewCSS*>(this);
2376    else if (IsEqualGUID(riid, IID_IWebViewEditing))
2377        *ppvObject = static_cast<IWebViewEditing*>(this);
2378    else if (IsEqualGUID(riid, IID_IWebViewUndoableEditing))
2379        *ppvObject = static_cast<IWebViewUndoableEditing*>(this);
2380    else if (IsEqualGUID(riid, IID_IWebViewEditingActions))
2381        *ppvObject = static_cast<IWebViewEditingActions*>(this);
2382    else if (IsEqualGUID(riid, IID_IWebNotificationObserver))
2383        *ppvObject = static_cast<IWebNotificationObserver*>(this);
2384    else if (IsEqualGUID(riid, IID_IDropTarget))
2385        *ppvObject = static_cast<IDropTarget*>(this);
2386    else
2387        return E_NOINTERFACE;
2388
2389    AddRef();
2390    return S_OK;
2391}
2392
2393ULONG STDMETHODCALLTYPE WebView::AddRef(void)
2394{
2395    ASSERT(!m_deletionHasBegun);
2396    return ++m_refCount;
2397}
2398
2399ULONG STDMETHODCALLTYPE WebView::Release(void)
2400{
2401    ASSERT(!m_deletionHasBegun);
2402
2403    if (m_refCount == 1) {
2404        // Call close() now so that clients don't have to. (It's harmless to call close() multiple
2405        // times.) We do this here instead of in our destructor because close() can cause AddRef()
2406        // and Release() to be called, and if that happened in our destructor we would be destroyed
2407        // more than once.
2408        close();
2409    }
2410
2411    ULONG newRef = --m_refCount;
2412    if (!newRef) {
2413#if !ASSERT_DISABLED
2414        m_deletionHasBegun = true;
2415#endif
2416        delete(this);
2417    }
2418
2419    return newRef;
2420}
2421
2422// IWebView --------------------------------------------------------------------
2423
2424HRESULT STDMETHODCALLTYPE WebView::canShowMIMEType(
2425    /* [in] */ BSTR mimeType,
2426    /* [retval][out] */ BOOL* canShow)
2427{
2428    String mimeTypeStr(mimeType, SysStringLen(mimeType));
2429
2430    if (!canShow)
2431        return E_POINTER;
2432
2433    *canShow = MIMETypeRegistry::isSupportedImageMIMEType(mimeTypeStr) ||
2434        MIMETypeRegistry::isSupportedNonImageMIMEType(mimeTypeStr) ||
2435        (m_page && m_page->pluginData() && m_page->pluginData()->supportsMimeType(mimeTypeStr)) ||
2436        shouldUseEmbeddedView(mimeTypeStr);
2437
2438    return S_OK;
2439}
2440
2441HRESULT STDMETHODCALLTYPE WebView::canShowMIMETypeAsHTML(
2442    /* [in] */ BSTR /*mimeType*/,
2443    /* [retval][out] */ BOOL* canShow)
2444{
2445    // FIXME
2446    *canShow = TRUE;
2447    return S_OK;
2448}
2449
2450HRESULT STDMETHODCALLTYPE WebView::MIMETypesShownAsHTML(
2451    /* [retval][out] */ IEnumVARIANT** /*enumVariant*/)
2452{
2453    ASSERT_NOT_REACHED();
2454    return E_NOTIMPL;
2455}
2456
2457HRESULT STDMETHODCALLTYPE WebView::setMIMETypesShownAsHTML(
2458        /* [size_is][in] */ BSTR* /*mimeTypes*/,
2459        /* [in] */ int /*cMimeTypes*/)
2460{
2461    ASSERT_NOT_REACHED();
2462    return E_NOTIMPL;
2463}
2464
2465HRESULT STDMETHODCALLTYPE WebView::URLFromPasteboard(
2466    /* [in] */ IDataObject* /*pasteboard*/,
2467    /* [retval][out] */ BSTR* /*url*/)
2468{
2469    ASSERT_NOT_REACHED();
2470    return E_NOTIMPL;
2471}
2472
2473HRESULT STDMETHODCALLTYPE WebView::URLTitleFromPasteboard(
2474    /* [in] */ IDataObject* /*pasteboard*/,
2475    /* [retval][out] */ BSTR* /*urlTitle*/)
2476{
2477    ASSERT_NOT_REACHED();
2478    return E_NOTIMPL;
2479}
2480
2481static void WebKitSetApplicationCachePathIfNecessary()
2482{
2483    static bool initialized = false;
2484    if (initialized)
2485        return;
2486
2487    String path = localUserSpecificStorageDirectory();
2488    if (!path.isNull())
2489        cacheStorage().setCacheDirectory(path);
2490
2491    initialized = true;
2492}
2493
2494bool WebView::shouldInitializeTrackPointHack()
2495{
2496    static bool shouldCreateScrollbars;
2497    static bool hasRunTrackPointCheck;
2498
2499    if (hasRunTrackPointCheck)
2500        return shouldCreateScrollbars;
2501
2502    hasRunTrackPointCheck = true;
2503    const WCHAR trackPointKeys[][50] = { L"Software\\Lenovo\\TrackPoint",
2504        L"Software\\Lenovo\\UltraNav",
2505        L"Software\\Alps\\Apoint\\TrackPoint",
2506        L"Software\\Synaptics\\SynTPEnh\\UltraNavUSB",
2507        L"Software\\Synaptics\\SynTPEnh\\UltraNavPS2" };
2508
2509    for (int i = 0; i < 5; ++i) {
2510        HKEY trackPointKey;
2511        int readKeyResult = ::RegOpenKeyExW(HKEY_CURRENT_USER, trackPointKeys[i], 0, KEY_READ, &trackPointKey);
2512        ::RegCloseKey(trackPointKey);
2513        if (readKeyResult == ERROR_SUCCESS) {
2514            shouldCreateScrollbars = true;
2515            return shouldCreateScrollbars;
2516        }
2517    }
2518
2519    return shouldCreateScrollbars;
2520}
2521
2522HRESULT STDMETHODCALLTYPE WebView::initWithFrame(
2523    /* [in] */ RECT frame,
2524    /* [in] */ BSTR frameName,
2525    /* [in] */ BSTR groupName)
2526{
2527    HRESULT hr = S_OK;
2528
2529    if (m_viewWindow)
2530        return E_FAIL;
2531
2532    registerWebViewWindowClass();
2533
2534    m_viewWindow = CreateWindowEx(0, kWebViewWindowClassName, 0, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
2535        frame.left, frame.top, frame.right - frame.left, frame.bottom - frame.top, m_hostWindow ? m_hostWindow : HWND_MESSAGE, 0, gInstance, 0);
2536    ASSERT(::IsWindow(m_viewWindow));
2537
2538    if (shouldInitializeTrackPointHack()) {
2539        // If we detected a registry key belonging to a TrackPoint driver, then create fake trackpoint
2540        // scrollbars, so the WebView will receive WM_VSCROLL and WM_HSCROLL messages. We create one
2541        // vertical scrollbar and one horizontal to allow for receiving both types of messages.
2542        ::CreateWindowW(L"SCROLLBAR", L"FAKETRACKPOINTHSCROLLBAR", WS_CHILD | WS_VISIBLE | SBS_HORZ, 0, 0, 0, 0, m_viewWindow, 0, gInstance, 0);
2543        ::CreateWindowW(L"SCROLLBAR", L"FAKETRACKPOINTVSCROLLBAR", WS_CHILD | WS_VISIBLE | SBS_VERT, 0, 0, 0, 0, m_viewWindow, 0, gInstance, 0);
2544    }
2545
2546    hr = registerDragDrop();
2547    if (FAILED(hr))
2548        return hr;
2549
2550    WebPreferences* sharedPreferences = WebPreferences::sharedStandardPreferences();
2551    sharedPreferences->willAddToWebView();
2552    m_preferences = sharedPreferences;
2553
2554    static bool didOneTimeInitialization;
2555    if (!didOneTimeInitialization) {
2556        InitializeLoggingChannelsIfNecessary();
2557#if ENABLE(DATABASE)
2558        WebKitInitializeWebDatabasesIfNecessary();
2559#endif
2560        WebKitSetApplicationCachePathIfNecessary();
2561        WebPlatformStrategies::initialize();
2562        Settings::setDefaultMinDOMTimerInterval(0.004);
2563
2564        didOneTimeInitialization = true;
2565     }
2566
2567#if USE(SAFARI_THEME)
2568    BOOL shouldPaintNativeControls;
2569    if (SUCCEEDED(m_preferences->shouldPaintNativeControls(&shouldPaintNativeControls)))
2570        Settings::setShouldPaintNativeControls(shouldPaintNativeControls);
2571#endif
2572
2573    BOOL useHighResolutionTimer;
2574    if (SUCCEEDED(m_preferences->shouldUseHighResolutionTimers(&useHighResolutionTimer)))
2575        Settings::setShouldUseHighResolutionTimers(useHighResolutionTimer);
2576
2577    Page::PageClients pageClients;
2578    pageClients.chromeClient = new WebChromeClient(this);
2579    pageClients.contextMenuClient = new WebContextMenuClient(this);
2580    pageClients.editorClient = new WebEditorClient(this);
2581    pageClients.dragClient = new WebDragClient(this);
2582    pageClients.inspectorClient = new WebInspectorClient(this);
2583    pageClients.pluginHalterClient = new WebPluginHalterClient(this);
2584#if ENABLE(CLIENT_BASED_GEOLOCATION)
2585    pageClients.geolocationClient = new WebGeolocationClient(this);
2586#endif
2587    m_page = new Page(pageClients);
2588
2589    BSTR localStoragePath;
2590    if (SUCCEEDED(m_preferences->localStorageDatabasePath(&localStoragePath))) {
2591        m_page->settings()->setLocalStorageDatabasePath(String(localStoragePath, SysStringLen(localStoragePath)));
2592        SysFreeString(localStoragePath);
2593    }
2594
2595    if (m_uiDelegate) {
2596        BSTR path;
2597        if (SUCCEEDED(m_uiDelegate->ftpDirectoryTemplatePath(this, &path))) {
2598            m_page->settings()->setFTPDirectoryTemplatePath(String(path, SysStringLen(path)));
2599            SysFreeString(path);
2600        }
2601    }
2602
2603    WebFrame* webFrame = WebFrame::createInstance();
2604    RefPtr<Frame> coreFrame = webFrame->init(this, m_page, 0);
2605    m_mainFrame = webFrame;
2606    webFrame->Release(); // The WebFrame is owned by the Frame, so release our reference to it.
2607
2608    coreFrame->tree()->setName(String(frameName, SysStringLen(frameName)));
2609    coreFrame->init();
2610    setGroupName(groupName);
2611
2612    addToAllWebViewsSet();
2613
2614    #pragma warning(suppress: 4244)
2615    SetWindowLongPtr(m_viewWindow, 0, (LONG_PTR)this);
2616    ShowWindow(m_viewWindow, SW_SHOW);
2617
2618    initializeToolTipWindow();
2619    windowAncestryDidChange();
2620
2621    IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal();
2622    notifyCenter->addObserver(this, WebPreferences::webPreferencesChangedNotification(), static_cast<IWebPreferences*>(m_preferences.get()));
2623    m_preferences->postPreferencesChangesNotification();
2624
2625    setSmartInsertDeleteEnabled(TRUE);
2626    return hr;
2627}
2628
2629static bool initCommonControls()
2630{
2631    static bool haveInitialized = false;
2632    if (haveInitialized)
2633        return true;
2634
2635    INITCOMMONCONTROLSEX init;
2636    init.dwSize = sizeof(init);
2637    init.dwICC = ICC_TREEVIEW_CLASSES;
2638    haveInitialized = !!::InitCommonControlsEx(&init);
2639    return haveInitialized;
2640}
2641
2642void WebView::initializeToolTipWindow()
2643{
2644    if (!initCommonControls())
2645        return;
2646
2647    m_toolTipHwnd = CreateWindowEx(WS_EX_TRANSPARENT, TOOLTIPS_CLASS, 0, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
2648                                   CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
2649                                   m_viewWindow, 0, 0, 0);
2650    if (!m_toolTipHwnd)
2651        return;
2652
2653    TOOLINFO info = {0};
2654    info.cbSize = sizeof(info);
2655    info.uFlags = TTF_IDISHWND | TTF_SUBCLASS ;
2656    info.uId = reinterpret_cast<UINT_PTR>(m_viewWindow);
2657
2658    ::SendMessage(m_toolTipHwnd, TTM_ADDTOOL, 0, reinterpret_cast<LPARAM>(&info));
2659    ::SendMessage(m_toolTipHwnd, TTM_SETMAXTIPWIDTH, 0, maxToolTipWidth);
2660
2661    ::SetWindowPos(m_toolTipHwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
2662}
2663
2664void WebView::setToolTip(const String& toolTip)
2665{
2666    if (!m_toolTipHwnd)
2667        return;
2668
2669    if (toolTip == m_toolTip)
2670        return;
2671
2672    m_toolTip = toolTip;
2673
2674    if (!m_toolTip.isEmpty()) {
2675        TOOLINFO info = {0};
2676        info.cbSize = sizeof(info);
2677        info.uFlags = TTF_IDISHWND;
2678        info.uId = reinterpret_cast<UINT_PTR>(m_viewWindow);
2679        info.lpszText = const_cast<UChar*>(m_toolTip.charactersWithNullTermination());
2680        ::SendMessage(m_toolTipHwnd, TTM_UPDATETIPTEXT, 0, reinterpret_cast<LPARAM>(&info));
2681    }
2682
2683    ::SendMessage(m_toolTipHwnd, TTM_ACTIVATE, !m_toolTip.isEmpty(), 0);
2684}
2685
2686HRESULT WebView::notifyDidAddIcon(IWebNotification* notification)
2687{
2688    COMPtr<IPropertyBag> propertyBag;
2689    HRESULT hr = notification->userInfo(&propertyBag);
2690    if (FAILED(hr))
2691        return hr;
2692    if (!propertyBag)
2693        return E_FAIL;
2694
2695    COMPtr<CFDictionaryPropertyBag> dictionaryPropertyBag;
2696    hr = propertyBag->QueryInterface(&dictionaryPropertyBag);
2697    if (FAILED(hr))
2698        return hr;
2699
2700    CFDictionaryRef dictionary = dictionaryPropertyBag->dictionary();
2701    if (!dictionary)
2702        return E_FAIL;
2703
2704    CFTypeRef value = CFDictionaryGetValue(dictionary, WebIconDatabase::iconDatabaseNotificationUserInfoURLKey());
2705    if (!value)
2706        return E_FAIL;
2707    if (CFGetTypeID(value) != CFStringGetTypeID())
2708        return E_FAIL;
2709
2710    String mainFrameURL;
2711    if (m_mainFrame)
2712        mainFrameURL = m_mainFrame->url().string();
2713
2714    if (!mainFrameURL.isEmpty() && mainFrameURL == String((CFStringRef)value))
2715        dispatchDidReceiveIconFromWebFrame(m_mainFrame);
2716
2717    return hr;
2718}
2719
2720void WebView::registerForIconNotification(bool listen)
2721{
2722    IWebNotificationCenter* nc = WebNotificationCenter::defaultCenterInternal();
2723    if (listen)
2724        nc->addObserver(this, WebIconDatabase::iconDatabaseDidAddIconNotification(), 0);
2725    else
2726        nc->removeObserver(this, WebIconDatabase::iconDatabaseDidAddIconNotification(), 0);
2727}
2728
2729void WebView::dispatchDidReceiveIconFromWebFrame(WebFrame* frame)
2730{
2731    registerForIconNotification(false);
2732
2733    if (m_frameLoadDelegate)
2734        // FIXME: <rdar://problem/5491010> - Pass in the right HBITMAP.
2735        m_frameLoadDelegate->didReceiveIcon(this, 0, frame);
2736}
2737
2738HRESULT STDMETHODCALLTYPE WebView::setUIDelegate(
2739    /* [in] */ IWebUIDelegate* d)
2740{
2741    m_uiDelegate = d;
2742
2743    if (m_uiDelegatePrivate)
2744        m_uiDelegatePrivate = 0;
2745
2746    if (d) {
2747        if (FAILED(d->QueryInterface(IID_IWebUIDelegatePrivate, (void**)&m_uiDelegatePrivate)))
2748            m_uiDelegatePrivate = 0;
2749    }
2750
2751    return S_OK;
2752}
2753
2754HRESULT STDMETHODCALLTYPE WebView::uiDelegate(
2755    /* [out][retval] */ IWebUIDelegate** d)
2756{
2757    if (!m_uiDelegate)
2758        return E_FAIL;
2759
2760    return m_uiDelegate.copyRefTo(d);
2761}
2762
2763HRESULT STDMETHODCALLTYPE WebView::setResourceLoadDelegate(
2764    /* [in] */ IWebResourceLoadDelegate* d)
2765{
2766    m_resourceLoadDelegate = d;
2767    return S_OK;
2768}
2769
2770HRESULT STDMETHODCALLTYPE WebView::resourceLoadDelegate(
2771    /* [out][retval] */ IWebResourceLoadDelegate** d)
2772{
2773    if (!m_resourceLoadDelegate)
2774        return E_FAIL;
2775
2776    return m_resourceLoadDelegate.copyRefTo(d);
2777}
2778
2779HRESULT STDMETHODCALLTYPE WebView::setDownloadDelegate(
2780    /* [in] */ IWebDownloadDelegate* d)
2781{
2782    m_downloadDelegate = d;
2783    return S_OK;
2784}
2785
2786HRESULT STDMETHODCALLTYPE WebView::downloadDelegate(
2787    /* [out][retval] */ IWebDownloadDelegate** d)
2788{
2789    if (!m_downloadDelegate)
2790        return E_FAIL;
2791
2792    return m_downloadDelegate.copyRefTo(d);
2793}
2794
2795HRESULT STDMETHODCALLTYPE WebView::setFrameLoadDelegate(
2796    /* [in] */ IWebFrameLoadDelegate* d)
2797{
2798    m_frameLoadDelegate = d;
2799    return S_OK;
2800}
2801
2802HRESULT STDMETHODCALLTYPE WebView::frameLoadDelegate(
2803    /* [out][retval] */ IWebFrameLoadDelegate** d)
2804{
2805    if (!m_frameLoadDelegate)
2806        return E_FAIL;
2807
2808    return m_frameLoadDelegate.copyRefTo(d);
2809}
2810
2811HRESULT STDMETHODCALLTYPE WebView::setPolicyDelegate(
2812    /* [in] */ IWebPolicyDelegate* d)
2813{
2814    m_policyDelegate = d;
2815    return S_OK;
2816}
2817
2818HRESULT STDMETHODCALLTYPE WebView::policyDelegate(
2819    /* [out][retval] */ IWebPolicyDelegate** d)
2820{
2821    if (!m_policyDelegate)
2822        return E_FAIL;
2823    return m_policyDelegate.copyRefTo(d);
2824}
2825
2826HRESULT STDMETHODCALLTYPE WebView::mainFrame(
2827    /* [out][retval] */ IWebFrame** frame)
2828{
2829    if (!frame) {
2830        ASSERT_NOT_REACHED();
2831        return E_POINTER;
2832    }
2833
2834    *frame = m_mainFrame;
2835    if (!m_mainFrame)
2836        return E_FAIL;
2837
2838    m_mainFrame->AddRef();
2839    return S_OK;
2840}
2841
2842HRESULT STDMETHODCALLTYPE WebView::focusedFrame(
2843    /* [out][retval] */ IWebFrame** frame)
2844{
2845    if (!frame) {
2846        ASSERT_NOT_REACHED();
2847        return E_POINTER;
2848    }
2849
2850    *frame = 0;
2851    Frame* f = m_page->focusController()->focusedFrame();
2852    if (!f)
2853        return E_FAIL;
2854
2855    WebFrame* webFrame = kit(f);
2856    if (!webFrame)
2857        return E_FAIL;
2858
2859    return webFrame->QueryInterface(IID_IWebFrame, (void**) frame);
2860}
2861
2862HRESULT STDMETHODCALLTYPE WebView::backForwardList(
2863    /* [out][retval] */ IWebBackForwardList** list)
2864{
2865    if (!m_useBackForwardList)
2866        return E_FAIL;
2867
2868    *list = WebBackForwardList::createInstance(static_cast<WebCore::BackForwardListImpl*>(m_page->backForwardList()));
2869
2870    return S_OK;
2871}
2872
2873HRESULT STDMETHODCALLTYPE WebView::setMaintainsBackForwardList(
2874    /* [in] */ BOOL flag)
2875{
2876    m_useBackForwardList = !!flag;
2877    return S_OK;
2878}
2879
2880HRESULT STDMETHODCALLTYPE WebView::goBack(
2881    /* [retval][out] */ BOOL* succeeded)
2882{
2883    *succeeded = m_page->goBack();
2884    return S_OK;
2885}
2886
2887HRESULT STDMETHODCALLTYPE WebView::goForward(
2888    /* [retval][out] */ BOOL* succeeded)
2889{
2890    *succeeded = m_page->goForward();
2891    return S_OK;
2892}
2893
2894HRESULT STDMETHODCALLTYPE WebView::goToBackForwardItem(
2895    /* [in] */ IWebHistoryItem* item,
2896    /* [retval][out] */ BOOL* succeeded)
2897{
2898    *succeeded = FALSE;
2899
2900    COMPtr<WebHistoryItem> webHistoryItem;
2901    HRESULT hr = item->QueryInterface(&webHistoryItem);
2902    if (FAILED(hr))
2903        return hr;
2904
2905    m_page->goToItem(webHistoryItem->historyItem(), FrameLoadTypeIndexedBackForward);
2906    *succeeded = TRUE;
2907
2908    return S_OK;
2909}
2910
2911HRESULT STDMETHODCALLTYPE WebView::setTextSizeMultiplier(
2912    /* [in] */ float multiplier)
2913{
2914    if (!m_mainFrame)
2915        return E_FAIL;
2916    setZoomMultiplier(multiplier, true);
2917    return S_OK;
2918}
2919
2920HRESULT STDMETHODCALLTYPE WebView::setPageSizeMultiplier(
2921    /* [in] */ float multiplier)
2922{
2923    if (!m_mainFrame)
2924        return E_FAIL;
2925    setZoomMultiplier(multiplier, false);
2926    return S_OK;
2927}
2928
2929void WebView::setZoomMultiplier(float multiplier, bool isTextOnly)
2930{
2931    m_zoomMultiplier = multiplier;
2932    m_zoomsTextOnly = isTextOnly;
2933
2934    if (Frame* coreFrame = core(m_mainFrame)) {
2935        if (m_zoomsTextOnly)
2936            coreFrame->setPageAndTextZoomFactors(1, multiplier);
2937        else
2938            coreFrame->setPageAndTextZoomFactors(multiplier, 1);
2939    }
2940}
2941
2942HRESULT STDMETHODCALLTYPE WebView::textSizeMultiplier(
2943    /* [retval][out] */ float* multiplier)
2944{
2945    *multiplier = zoomMultiplier(true);
2946    return S_OK;
2947}
2948
2949HRESULT STDMETHODCALLTYPE WebView::pageSizeMultiplier(
2950    /* [retval][out] */ float* multiplier)
2951{
2952    *multiplier = zoomMultiplier(false);
2953    return S_OK;
2954}
2955
2956float WebView::zoomMultiplier(bool isTextOnly)
2957{
2958    if (isTextOnly != m_zoomsTextOnly)
2959        return 1.0f;
2960    return m_zoomMultiplier;
2961}
2962
2963HRESULT STDMETHODCALLTYPE WebView::setApplicationNameForUserAgent(
2964    /* [in] */ BSTR applicationName)
2965{
2966    m_applicationName = String(applicationName, SysStringLen(applicationName));
2967    m_userAgentStandard = String();
2968    return S_OK;
2969}
2970
2971HRESULT STDMETHODCALLTYPE WebView::applicationNameForUserAgent(
2972    /* [retval][out] */ BSTR* applicationName)
2973{
2974    *applicationName = SysAllocStringLen(m_applicationName.characters(), m_applicationName.length());
2975    if (!*applicationName && m_applicationName.length())
2976        return E_OUTOFMEMORY;
2977    return S_OK;
2978}
2979
2980HRESULT STDMETHODCALLTYPE WebView::setCustomUserAgent(
2981    /* [in] */ BSTR userAgentString)
2982{
2983    m_userAgentOverridden = userAgentString;
2984    m_userAgentCustom = String(userAgentString, SysStringLen(userAgentString));
2985    return S_OK;
2986}
2987
2988HRESULT STDMETHODCALLTYPE WebView::customUserAgent(
2989    /* [retval][out] */ BSTR* userAgentString)
2990{
2991    *userAgentString = 0;
2992    if (!m_userAgentOverridden)
2993        return S_OK;
2994    *userAgentString = SysAllocStringLen(m_userAgentCustom.characters(), m_userAgentCustom.length());
2995    if (!*userAgentString && m_userAgentCustom.length())
2996        return E_OUTOFMEMORY;
2997    return S_OK;
2998}
2999
3000HRESULT STDMETHODCALLTYPE WebView::userAgentForURL(
3001    /* [in] */ BSTR url,
3002    /* [retval][out] */ BSTR* userAgent)
3003{
3004    String userAgentString = userAgentForKURL(MarshallingHelpers::BSTRToKURL(url));
3005    *userAgent = SysAllocStringLen(userAgentString.characters(), userAgentString.length());
3006    if (!*userAgent && userAgentString.length())
3007        return E_OUTOFMEMORY;
3008    return S_OK;
3009}
3010
3011HRESULT STDMETHODCALLTYPE WebView::supportsTextEncoding(
3012    /* [retval][out] */ BOOL* supports)
3013{
3014    *supports = TRUE;
3015    return S_OK;
3016}
3017
3018HRESULT STDMETHODCALLTYPE WebView::setCustomTextEncodingName(
3019    /* [in] */ BSTR encodingName)
3020{
3021    if (!m_mainFrame)
3022        return E_FAIL;
3023
3024    HRESULT hr;
3025    BSTR oldEncoding;
3026    hr = customTextEncodingName(&oldEncoding);
3027    if (FAILED(hr))
3028        return hr;
3029
3030    if (oldEncoding != encodingName && (!oldEncoding || !encodingName || wcscmp(oldEncoding, encodingName))) {
3031        if (Frame* coreFrame = core(m_mainFrame))
3032            coreFrame->loader()->reloadWithOverrideEncoding(String(encodingName, SysStringLen(encodingName)));
3033    }
3034
3035    return S_OK;
3036}
3037
3038HRESULT STDMETHODCALLTYPE WebView::customTextEncodingName(
3039    /* [retval][out] */ BSTR* encodingName)
3040{
3041    HRESULT hr = S_OK;
3042    COMPtr<IWebDataSource> dataSource;
3043    COMPtr<WebDataSource> dataSourceImpl;
3044    *encodingName = 0;
3045
3046    if (!m_mainFrame)
3047        return E_FAIL;
3048
3049    if (FAILED(m_mainFrame->provisionalDataSource(&dataSource)) || !dataSource) {
3050        hr = m_mainFrame->dataSource(&dataSource);
3051        if (FAILED(hr) || !dataSource)
3052            return hr;
3053    }
3054
3055    hr = dataSource->QueryInterface(IID_WebDataSource, (void**)&dataSourceImpl);
3056    if (FAILED(hr))
3057        return hr;
3058
3059    BString str = dataSourceImpl->documentLoader()->overrideEncoding();
3060    if (FAILED(hr))
3061        return hr;
3062
3063    if (!*encodingName)
3064        *encodingName = SysAllocStringLen(m_overrideEncoding.characters(), m_overrideEncoding.length());
3065
3066    if (!*encodingName && m_overrideEncoding.length())
3067        return E_OUTOFMEMORY;
3068
3069    return S_OK;
3070}
3071
3072HRESULT STDMETHODCALLTYPE WebView::setMediaStyle(
3073    /* [in] */ BSTR /*media*/)
3074{
3075    ASSERT_NOT_REACHED();
3076    return E_NOTIMPL;
3077}
3078
3079HRESULT STDMETHODCALLTYPE WebView::mediaStyle(
3080    /* [retval][out] */ BSTR* /*media*/)
3081{
3082    ASSERT_NOT_REACHED();
3083    return E_NOTIMPL;
3084}
3085
3086HRESULT STDMETHODCALLTYPE WebView::stringByEvaluatingJavaScriptFromString(
3087    /* [in] */ BSTR script, // assumes input does not have "JavaScript" at the begining.
3088    /* [retval][out] */ BSTR* result)
3089{
3090    if (!result) {
3091        ASSERT_NOT_REACHED();
3092        return E_POINTER;
3093    }
3094
3095    *result = 0;
3096
3097    Frame* coreFrame = core(m_mainFrame);
3098    if (!coreFrame)
3099        return E_FAIL;
3100
3101    JSC::JSValue scriptExecutionResult = coreFrame->script()->executeScript(WTF::String(script), true).jsValue();
3102    if (!scriptExecutionResult)
3103        return E_FAIL;
3104    else if (scriptExecutionResult.isString()) {
3105        JSLock lock(JSC::SilenceAssertionsOnly);
3106        JSC::ExecState* exec = coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec();
3107        *result = BString(ustringToString(scriptExecutionResult.getString(exec)));
3108    }
3109
3110    return S_OK;
3111}
3112
3113HRESULT STDMETHODCALLTYPE WebView::windowScriptObject(
3114    /* [retval][out] */ IWebScriptObject** /*webScriptObject*/)
3115{
3116    ASSERT_NOT_REACHED();
3117    return E_NOTIMPL;
3118}
3119
3120HRESULT STDMETHODCALLTYPE WebView::setPreferences(
3121    /* [in] */ IWebPreferences* prefs)
3122{
3123    if (!prefs)
3124        prefs = WebPreferences::sharedStandardPreferences();
3125
3126    if (m_preferences == prefs)
3127        return S_OK;
3128
3129    COMPtr<WebPreferences> webPrefs(Query, prefs);
3130    if (!webPrefs)
3131        return E_NOINTERFACE;
3132    webPrefs->willAddToWebView();
3133
3134    COMPtr<WebPreferences> oldPrefs = m_preferences;
3135
3136    IWebNotificationCenter* nc = WebNotificationCenter::defaultCenterInternal();
3137    nc->removeObserver(this, WebPreferences::webPreferencesChangedNotification(), static_cast<IWebPreferences*>(m_preferences.get()));
3138
3139    BSTR identifier = 0;
3140    oldPrefs->identifier(&identifier);
3141    oldPrefs->didRemoveFromWebView();
3142    oldPrefs = 0; // Make sure we release the reference, since WebPreferences::removeReferenceForIdentifier will check for last reference to WebPreferences
3143
3144    m_preferences = webPrefs;
3145
3146    if (identifier) {
3147        WebPreferences::removeReferenceForIdentifier(identifier);
3148        SysFreeString(identifier);
3149    }
3150
3151    nc->addObserver(this, WebPreferences::webPreferencesChangedNotification(), static_cast<IWebPreferences*>(m_preferences.get()));
3152
3153    m_preferences->postPreferencesChangesNotification();
3154
3155    return S_OK;
3156}
3157
3158HRESULT STDMETHODCALLTYPE WebView::preferences(
3159    /* [retval][out] */ IWebPreferences** prefs)
3160{
3161    if (!prefs)
3162        return E_POINTER;
3163    *prefs = m_preferences.get();
3164    if (m_preferences)
3165        m_preferences->AddRef();
3166    return S_OK;
3167}
3168
3169HRESULT STDMETHODCALLTYPE WebView::setPreferencesIdentifier(
3170    /* [in] */ BSTR /*anIdentifier*/)
3171{
3172    ASSERT_NOT_REACHED();
3173    return E_NOTIMPL;
3174}
3175
3176HRESULT STDMETHODCALLTYPE WebView::preferencesIdentifier(
3177    /* [retval][out] */ BSTR* /*anIdentifier*/)
3178{
3179    ASSERT_NOT_REACHED();
3180    return E_NOTIMPL;
3181}
3182
3183static void systemParameterChanged(WPARAM parameter)
3184{
3185#if PLATFORM(CG)
3186    if (parameter == SPI_SETFONTSMOOTHING || parameter == SPI_SETFONTSMOOTHINGTYPE || parameter == SPI_SETFONTSMOOTHINGCONTRAST || parameter == SPI_SETFONTSMOOTHINGORIENTATION)
3187        wkSystemFontSmoothingChanged();
3188#endif
3189}
3190
3191void WebView::windowReceivedMessage(HWND, UINT message, WPARAM wParam, LPARAM)
3192{
3193    switch (message) {
3194    case WM_NCACTIVATE:
3195        updateActiveStateSoon();
3196        if (!wParam)
3197            deleteBackingStoreSoon();
3198        break;
3199    case WM_SETTINGCHANGE:
3200        systemParameterChanged(wParam);
3201        break;
3202    }
3203}
3204
3205void WebView::updateActiveStateSoon() const
3206{
3207    // This function is called while processing the WM_NCACTIVATE message.
3208    // While processing WM_NCACTIVATE when we are being deactivated, GetActiveWindow() will
3209    // still return our window. If we were to call updateActiveState() in that case, we would
3210    // wrongly think that we are still the active window. To work around this, we update our
3211    // active state after a 0-delay timer fires, at which point GetActiveWindow() will return
3212    // the newly-activated window.
3213
3214    SetTimer(m_viewWindow, UpdateActiveStateTimer, 0, 0);
3215}
3216
3217void WebView::deleteBackingStoreSoon()
3218{
3219    if (pendingDeleteBackingStoreSet.size() > 2) {
3220        Vector<WebView*> views;
3221        HashSet<WebView*>::iterator end = pendingDeleteBackingStoreSet.end();
3222        for (HashSet<WebView*>::iterator it = pendingDeleteBackingStoreSet.begin(); it != end; ++it)
3223            views.append(*it);
3224        for (int i = 0; i < views.size(); ++i)
3225            views[i]->deleteBackingStore();
3226        ASSERT(pendingDeleteBackingStoreSet.isEmpty());
3227    }
3228
3229    pendingDeleteBackingStoreSet.add(this);
3230    m_deleteBackingStoreTimerActive = true;
3231    SetTimer(m_viewWindow, DeleteBackingStoreTimer, delayBeforeDeletingBackingStoreMsec, 0);
3232}
3233
3234void WebView::cancelDeleteBackingStoreSoon()
3235{
3236    if (!m_deleteBackingStoreTimerActive)
3237        return;
3238    pendingDeleteBackingStoreSet.remove(this);
3239    m_deleteBackingStoreTimerActive = false;
3240    KillTimer(m_viewWindow, DeleteBackingStoreTimer);
3241}
3242
3243HRESULT STDMETHODCALLTYPE WebView::setHostWindow(
3244    /* [in] */ OLE_HANDLE oleWindow)
3245{
3246    HWND window = (HWND)(ULONG64)oleWindow;
3247    if (m_viewWindow) {
3248        if (window)
3249            SetParent(m_viewWindow, window);
3250        else if (!isBeingDestroyed()) {
3251            // Turn the WebView into a message-only window so it will no longer be a child of the
3252            // old host window and will be hidden from screen. We only do this when
3253            // isBeingDestroyed() is false because doing this while handling WM_DESTROY can leave
3254            // m_viewWindow in a weird state (see <http://webkit.org/b/29337>).
3255            SetParent(m_viewWindow, HWND_MESSAGE);
3256        }
3257    }
3258
3259    m_hostWindow = window;
3260
3261    windowAncestryDidChange();
3262
3263    return S_OK;
3264}
3265
3266HRESULT STDMETHODCALLTYPE WebView::hostWindow(
3267    /* [retval][out] */ OLE_HANDLE* window)
3268{
3269    *window = (OLE_HANDLE)(ULONG64)m_hostWindow;
3270    return S_OK;
3271}
3272
3273
3274static Frame *incrementFrame(Frame *curr, bool forward, bool wrapFlag)
3275{
3276    return forward
3277        ? curr->tree()->traverseNextWithWrap(wrapFlag)
3278        : curr->tree()->traversePreviousWithWrap(wrapFlag);
3279}
3280
3281HRESULT STDMETHODCALLTYPE WebView::searchFor(
3282    /* [in] */ BSTR str,
3283    /* [in] */ BOOL forward,
3284    /* [in] */ BOOL caseFlag,
3285    /* [in] */ BOOL wrapFlag,
3286    /* [retval][out] */ BOOL* found)
3287{
3288    if (!found)
3289        return E_INVALIDARG;
3290
3291    if (!m_page || !m_page->mainFrame())
3292        return E_UNEXPECTED;
3293
3294    if (!str || !SysStringLen(str))
3295        return E_INVALIDARG;
3296
3297    *found = m_page->findString(String(str, SysStringLen(str)), caseFlag ? TextCaseSensitive : TextCaseInsensitive, forward ? FindDirectionForward : FindDirectionBackward, wrapFlag);
3298    return S_OK;
3299}
3300
3301bool WebView::active()
3302{
3303    HWND activeWindow = GetActiveWindow();
3304    return (activeWindow && m_topLevelParent == findTopLevelParent(activeWindow));
3305}
3306
3307void WebView::updateActiveState()
3308{
3309    m_page->focusController()->setActive(active());
3310}
3311
3312HRESULT STDMETHODCALLTYPE WebView::updateFocusedAndActiveState()
3313{
3314    updateActiveState();
3315
3316    bool active = m_page->focusController()->isActive();
3317    Frame* mainFrame = m_page->mainFrame();
3318    Frame* focusedFrame = m_page->focusController()->focusedOrMainFrame();
3319    mainFrame->selection()->setFocused(active && mainFrame == focusedFrame);
3320
3321    return S_OK;
3322}
3323
3324HRESULT STDMETHODCALLTYPE WebView::executeCoreCommandByName(BSTR bName, BSTR bValue)
3325{
3326    String name(bName, SysStringLen(bName));
3327    String value(bValue, SysStringLen(bValue));
3328
3329    m_page->focusController()->focusedOrMainFrame()->editor()->command(name).execute(value);
3330
3331    return S_OK;
3332}
3333
3334HRESULT STDMETHODCALLTYPE WebView::clearMainFrameName()
3335{
3336    m_page->mainFrame()->tree()->clearName();
3337
3338    return S_OK;
3339}
3340
3341HRESULT STDMETHODCALLTYPE WebView::markAllMatchesForText(
3342    BSTR str, BOOL caseSensitive, BOOL highlight, UINT limit, UINT* matches)
3343{
3344    if (!matches)
3345        return E_INVALIDARG;
3346
3347    if (!m_page || !m_page->mainFrame())
3348        return E_UNEXPECTED;
3349
3350    if (!str || !SysStringLen(str))
3351        return E_INVALIDARG;
3352
3353    *matches = m_page->markAllMatchesForText(String(str, SysStringLen(str)), caseSensitive ? TextCaseSensitive : TextCaseInsensitive, highlight, limit);
3354    return S_OK;
3355}
3356
3357HRESULT STDMETHODCALLTYPE WebView::unmarkAllTextMatches()
3358{
3359    if (!m_page || !m_page->mainFrame())
3360        return E_UNEXPECTED;
3361
3362    m_page->unmarkAllTextMatches();
3363    return S_OK;
3364}
3365
3366HRESULT STDMETHODCALLTYPE WebView::rectsForTextMatches(
3367    IEnumTextMatches** pmatches)
3368{
3369    Vector<IntRect> allRects;
3370    WebCore::Frame* frame = m_page->mainFrame();
3371    do {
3372        if (Document* document = frame->document()) {
3373            IntRect visibleRect = frame->view()->visibleContentRect();
3374            Vector<IntRect> frameRects = document->markers()->renderedRectsForMarkers(DocumentMarker::TextMatch);
3375            IntPoint frameOffset(-frame->view()->scrollOffset().width(), -frame->view()->scrollOffset().height());
3376            frameOffset = frame->view()->convertToContainingWindow(frameOffset);
3377
3378            Vector<IntRect>::iterator end = frameRects.end();
3379            for (Vector<IntRect>::iterator it = frameRects.begin(); it < end; it++) {
3380                it->intersect(visibleRect);
3381                it->move(frameOffset.x(), frameOffset.y());
3382                allRects.append(*it);
3383            }
3384        }
3385        frame = incrementFrame(frame, true, false);
3386    } while (frame);
3387
3388    return createMatchEnumerator(&allRects, pmatches);
3389}
3390
3391HRESULT STDMETHODCALLTYPE WebView::generateSelectionImage(BOOL forceWhiteText, OLE_HANDLE* hBitmap)
3392{
3393    *hBitmap = 0;
3394
3395    WebCore::Frame* frame = m_page->focusController()->focusedOrMainFrame();
3396
3397    if (frame) {
3398        HBITMAP bitmap = imageFromSelection(frame, forceWhiteText ? TRUE : FALSE);
3399        *hBitmap = (OLE_HANDLE)(ULONG64)bitmap;
3400    }
3401
3402    return S_OK;
3403}
3404
3405HRESULT STDMETHODCALLTYPE WebView::selectionRect(RECT* rc)
3406{
3407    WebCore::Frame* frame = m_page->focusController()->focusedOrMainFrame();
3408
3409    if (frame) {
3410        IntRect ir = enclosingIntRect(frame->selection()->bounds());
3411        ir = frame->view()->convertToContainingWindow(ir);
3412        ir.move(-frame->view()->scrollOffset().width(), -frame->view()->scrollOffset().height());
3413        rc->left = ir.x();
3414        rc->top = ir.y();
3415        rc->bottom = rc->top + ir.height();
3416        rc->right = rc->left + ir.width();
3417    }
3418
3419    return S_OK;
3420}
3421
3422HRESULT STDMETHODCALLTYPE WebView::registerViewClass(
3423    /* [in] */ IWebDocumentView* /*view*/,
3424    /* [in] */ IWebDocumentRepresentation* /*representation*/,
3425    /* [in] */ BSTR /*forMIMEType*/)
3426{
3427    ASSERT_NOT_REACHED();
3428    return E_NOTIMPL;
3429}
3430
3431HRESULT STDMETHODCALLTYPE WebView::setGroupName(
3432        /* [in] */ BSTR groupName)
3433{
3434    if (!m_page)
3435        return S_OK;
3436    m_page->setGroupName(String(groupName, SysStringLen(groupName)));
3437    return S_OK;
3438}
3439
3440HRESULT STDMETHODCALLTYPE WebView::groupName(
3441        /* [retval][out] */ BSTR* groupName)
3442{
3443    *groupName = 0;
3444    if (!m_page)
3445        return S_OK;
3446    String groupNameString = m_page->groupName();
3447    *groupName = SysAllocStringLen(groupNameString.characters(), groupNameString.length());
3448    if (!*groupName && groupNameString.length())
3449        return E_OUTOFMEMORY;
3450    return S_OK;
3451}
3452
3453HRESULT STDMETHODCALLTYPE WebView::estimatedProgress(
3454        /* [retval][out] */ double* estimatedProgress)
3455{
3456    *estimatedProgress = m_page->progress()->estimatedProgress();
3457    return S_OK;
3458}
3459
3460HRESULT STDMETHODCALLTYPE WebView::isLoading(
3461        /* [retval][out] */ BOOL* isLoading)
3462{
3463    COMPtr<IWebDataSource> dataSource;
3464    COMPtr<IWebDataSource> provisionalDataSource;
3465
3466    if (!isLoading)
3467        return E_POINTER;
3468
3469    *isLoading = FALSE;
3470
3471    if (!m_mainFrame)
3472        return E_FAIL;
3473
3474    if (SUCCEEDED(m_mainFrame->dataSource(&dataSource)))
3475        dataSource->isLoading(isLoading);
3476
3477    if (*isLoading)
3478        return S_OK;
3479
3480    if (SUCCEEDED(m_mainFrame->provisionalDataSource(&provisionalDataSource)))
3481        provisionalDataSource->isLoading(isLoading);
3482    return S_OK;
3483}
3484
3485HRESULT STDMETHODCALLTYPE WebView::elementAtPoint(
3486        /* [in] */ LPPOINT point,
3487        /* [retval][out] */ IPropertyBag** elementDictionary)
3488{
3489    if (!elementDictionary) {
3490        ASSERT_NOT_REACHED();
3491        return E_POINTER;
3492    }
3493
3494    *elementDictionary = 0;
3495
3496    Frame* frame = core(m_mainFrame);
3497    if (!frame)
3498        return E_FAIL;
3499
3500    IntPoint webCorePoint = IntPoint(point->x, point->y);
3501    HitTestResult result = HitTestResult(webCorePoint);
3502    if (frame->contentRenderer())
3503        result = frame->eventHandler()->hitTestResultAtPoint(webCorePoint, false);
3504    *elementDictionary = WebElementPropertyBag::createInstance(result);
3505    return S_OK;
3506}
3507
3508HRESULT STDMETHODCALLTYPE WebView::pasteboardTypesForSelection(
3509    /* [retval][out] */ IEnumVARIANT** /*enumVariant*/)
3510{
3511    ASSERT_NOT_REACHED();
3512    return E_NOTIMPL;
3513}
3514
3515HRESULT STDMETHODCALLTYPE WebView::writeSelectionWithPasteboardTypes(
3516        /* [size_is][in] */ BSTR* /*types*/,
3517        /* [in] */ int /*cTypes*/,
3518        /* [in] */ IDataObject* /*pasteboard*/)
3519{
3520    ASSERT_NOT_REACHED();
3521    return E_NOTIMPL;
3522}
3523
3524HRESULT STDMETHODCALLTYPE WebView::pasteboardTypesForElement(
3525    /* [in] */ IPropertyBag* /*elementDictionary*/,
3526    /* [retval][out] */ IEnumVARIANT** /*enumVariant*/)
3527{
3528    ASSERT_NOT_REACHED();
3529    return E_NOTIMPL;
3530}
3531
3532HRESULT STDMETHODCALLTYPE WebView::writeElement(
3533        /* [in] */ IPropertyBag* /*elementDictionary*/,
3534        /* [size_is][in] */ BSTR* /*withPasteboardTypes*/,
3535        /* [in] */ int /*cWithPasteboardTypes*/,
3536        /* [in] */ IDataObject* /*pasteboard*/)
3537{
3538    ASSERT_NOT_REACHED();
3539    return E_NOTIMPL;
3540}
3541
3542HRESULT STDMETHODCALLTYPE WebView::selectedText(
3543        /* [out, retval] */ BSTR* text)
3544{
3545    if (!text) {
3546        ASSERT_NOT_REACHED();
3547        return E_POINTER;
3548    }
3549
3550    *text = 0;
3551
3552    Frame* focusedFrame = (m_page && m_page->focusController()) ? m_page->focusController()->focusedOrMainFrame() : 0;
3553    if (!focusedFrame)
3554        return E_FAIL;
3555
3556    String frameSelectedText = focusedFrame->editor()->selectedText();
3557    *text = SysAllocStringLen(frameSelectedText.characters(), frameSelectedText.length());
3558    if (!*text && frameSelectedText.length())
3559        return E_OUTOFMEMORY;
3560    return S_OK;
3561}
3562
3563HRESULT STDMETHODCALLTYPE WebView::centerSelectionInVisibleArea(
3564        /* [in] */ IUnknown* /* sender */)
3565{
3566    Frame* coreFrame = core(m_mainFrame);
3567    if (!coreFrame)
3568        return E_FAIL;
3569
3570    coreFrame->selection()->revealSelection(ScrollAlignment::alignCenterAlways);
3571    return S_OK;
3572}
3573
3574
3575HRESULT STDMETHODCALLTYPE WebView::moveDragCaretToPoint(
3576        /* [in] */ LPPOINT /*point*/)
3577{
3578    ASSERT_NOT_REACHED();
3579    return E_NOTIMPL;
3580}
3581
3582HRESULT STDMETHODCALLTYPE WebView::removeDragCaret( void)
3583{
3584    ASSERT_NOT_REACHED();
3585    return E_NOTIMPL;
3586}
3587
3588HRESULT STDMETHODCALLTYPE WebView::setDrawsBackground(
3589        /* [in] */ BOOL /*drawsBackground*/)
3590{
3591    ASSERT_NOT_REACHED();
3592    return E_NOTIMPL;
3593}
3594
3595HRESULT STDMETHODCALLTYPE WebView::drawsBackground(
3596        /* [retval][out] */ BOOL* /*drawsBackground*/)
3597{
3598    ASSERT_NOT_REACHED();
3599    return E_NOTIMPL;
3600}
3601
3602HRESULT STDMETHODCALLTYPE WebView::setMainFrameURL(
3603        /* [in] */ BSTR /*urlString*/)
3604{
3605    ASSERT_NOT_REACHED();
3606    return E_NOTIMPL;
3607}
3608
3609HRESULT STDMETHODCALLTYPE WebView::mainFrameURL(
3610        /* [retval][out] */ BSTR* urlString)
3611{
3612    if (!urlString)
3613        return E_POINTER;
3614
3615    if (!m_mainFrame)
3616        return E_FAIL;
3617
3618    COMPtr<IWebDataSource> dataSource;
3619
3620    if (FAILED(m_mainFrame->provisionalDataSource(&dataSource))) {
3621        if (FAILED(m_mainFrame->dataSource(&dataSource)))
3622            return E_FAIL;
3623    }
3624
3625    if (!dataSource) {
3626        *urlString = 0;
3627        return S_OK;
3628    }
3629
3630    COMPtr<IWebMutableURLRequest> request;
3631    if (FAILED(dataSource->request(&request)) || !request)
3632        return E_FAIL;
3633
3634    if (FAILED(request->URL(urlString)))
3635        return E_FAIL;
3636
3637    return S_OK;
3638}
3639
3640HRESULT STDMETHODCALLTYPE WebView::mainFrameDocument(
3641        /* [retval][out] */ IDOMDocument** document)
3642{
3643    if (document)
3644        *document = 0;
3645    if (!m_mainFrame)
3646        return E_FAIL;
3647    return m_mainFrame->DOMDocument(document);
3648}
3649
3650HRESULT STDMETHODCALLTYPE WebView::mainFrameTitle(
3651        /* [retval][out] */ BSTR* /*title*/)
3652{
3653    ASSERT_NOT_REACHED();
3654    return E_NOTIMPL;
3655}
3656
3657HRESULT STDMETHODCALLTYPE WebView::mainFrameIcon(
3658        /* [retval][out] */ OLE_HANDLE* /*hBitmap*/)
3659{
3660    ASSERT_NOT_REACHED();
3661    return E_NOTIMPL;
3662}
3663
3664HRESULT STDMETHODCALLTYPE WebView::registerURLSchemeAsLocal(
3665        /* [in] */ BSTR scheme)
3666{
3667    if (!scheme)
3668        return E_POINTER;
3669
3670    SchemeRegistry::registerURLSchemeAsLocal(String(scheme, ::SysStringLen(scheme)));
3671
3672    return S_OK;
3673}
3674
3675// IWebIBActions ---------------------------------------------------------------
3676
3677HRESULT STDMETHODCALLTYPE WebView::takeStringURLFrom(
3678        /* [in] */ IUnknown* /*sender*/)
3679{
3680    ASSERT_NOT_REACHED();
3681    return E_NOTIMPL;
3682}
3683
3684HRESULT STDMETHODCALLTYPE WebView::stopLoading(
3685        /* [in] */ IUnknown* /*sender*/)
3686{
3687    if (!m_mainFrame)
3688        return E_FAIL;
3689
3690    return m_mainFrame->stopLoading();
3691}
3692
3693HRESULT STDMETHODCALLTYPE WebView::reload(
3694        /* [in] */ IUnknown* /*sender*/)
3695{
3696    if (!m_mainFrame)
3697        return E_FAIL;
3698
3699    return m_mainFrame->reload();
3700}
3701
3702HRESULT STDMETHODCALLTYPE WebView::canGoBack(
3703        /* [in] */ IUnknown* /*sender*/,
3704        /* [retval][out] */ BOOL* result)
3705{
3706    *result = !!(m_page->backForwardList()->backItem() && !m_page->defersLoading());
3707    return S_OK;
3708}
3709
3710HRESULT STDMETHODCALLTYPE WebView::goBack(
3711        /* [in] */ IUnknown* /*sender*/)
3712{
3713    ASSERT_NOT_REACHED();
3714    return E_NOTIMPL;
3715}
3716
3717HRESULT STDMETHODCALLTYPE WebView::canGoForward(
3718        /* [in] */ IUnknown* /*sender*/,
3719        /* [retval][out] */ BOOL* result)
3720{
3721    *result = !!(m_page->backForwardList()->forwardItem() && !m_page->defersLoading());
3722    return S_OK;
3723}
3724
3725HRESULT STDMETHODCALLTYPE WebView::goForward(
3726        /* [in] */ IUnknown* /*sender*/)
3727{
3728    ASSERT_NOT_REACHED();
3729    return E_NOTIMPL;
3730}
3731
3732// FIXME: This code should move into WebCore so it can be shared by all the WebKits.
3733#define MinimumZoomMultiplier   0.5f
3734#define MaximumZoomMultiplier   3.0f
3735#define ZoomMultiplierRatio     1.2f
3736
3737HRESULT STDMETHODCALLTYPE WebView::canMakeTextLarger(
3738        /* [in] */ IUnknown* /*sender*/,
3739        /* [retval][out] */ BOOL* result)
3740{
3741    bool canGrowMore = canZoomIn(m_zoomsTextOnly);
3742    *result = canGrowMore ? TRUE : FALSE;
3743    return S_OK;
3744}
3745
3746HRESULT STDMETHODCALLTYPE WebView::canZoomPageIn(
3747        /* [in] */ IUnknown* /*sender*/,
3748        /* [retval][out] */ BOOL* result)
3749{
3750    bool canGrowMore = canZoomIn(false);
3751    *result = canGrowMore ? TRUE : FALSE;
3752    return S_OK;
3753}
3754
3755bool WebView::canZoomIn(bool isTextOnly)
3756{
3757    return zoomMultiplier(isTextOnly) * ZoomMultiplierRatio < MaximumZoomMultiplier;
3758}
3759
3760HRESULT STDMETHODCALLTYPE WebView::makeTextLarger(
3761        /* [in] */ IUnknown* /*sender*/)
3762{
3763    return zoomIn(m_zoomsTextOnly);
3764}
3765
3766HRESULT STDMETHODCALLTYPE WebView::zoomPageIn(
3767        /* [in] */ IUnknown* /*sender*/)
3768{
3769    return zoomIn(false);
3770}
3771
3772HRESULT WebView::zoomIn(bool isTextOnly)
3773{
3774    if (!canZoomIn(isTextOnly))
3775        return E_FAIL;
3776    setZoomMultiplier(zoomMultiplier(isTextOnly) * ZoomMultiplierRatio, isTextOnly);
3777    return S_OK;
3778}
3779
3780HRESULT STDMETHODCALLTYPE WebView::canMakeTextSmaller(
3781        /* [in] */ IUnknown* /*sender*/,
3782        /* [retval][out] */ BOOL* result)
3783{
3784    bool canShrinkMore = canZoomOut(m_zoomsTextOnly);
3785    *result = canShrinkMore ? TRUE : FALSE;
3786    return S_OK;
3787}
3788
3789HRESULT STDMETHODCALLTYPE WebView::canZoomPageOut(
3790        /* [in] */ IUnknown* /*sender*/,
3791        /* [retval][out] */ BOOL* result)
3792{
3793    bool canShrinkMore = canZoomOut(false);
3794    *result = canShrinkMore ? TRUE : FALSE;
3795    return S_OK;
3796}
3797
3798bool WebView::canZoomOut(bool isTextOnly)
3799{
3800    return zoomMultiplier(isTextOnly) / ZoomMultiplierRatio > MinimumZoomMultiplier;
3801}
3802
3803HRESULT STDMETHODCALLTYPE WebView::makeTextSmaller(
3804        /* [in] */ IUnknown* /*sender*/)
3805{
3806    return zoomOut(m_zoomsTextOnly);
3807}
3808
3809HRESULT STDMETHODCALLTYPE WebView::zoomPageOut(
3810        /* [in] */ IUnknown* /*sender*/)
3811{
3812    return zoomOut(false);
3813}
3814
3815HRESULT WebView::zoomOut(bool isTextOnly)
3816{
3817    if (!canZoomOut(isTextOnly))
3818        return E_FAIL;
3819    setZoomMultiplier(zoomMultiplier(isTextOnly) / ZoomMultiplierRatio, isTextOnly);
3820    return S_OK;
3821}
3822
3823HRESULT STDMETHODCALLTYPE WebView::canMakeTextStandardSize(
3824    /* [in] */ IUnknown* /*sender*/,
3825    /* [retval][out] */ BOOL* result)
3826{
3827    // 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.
3828    bool notAlreadyStandard = canResetZoom(true);
3829    *result = notAlreadyStandard ? TRUE : FALSE;
3830    return S_OK;
3831}
3832
3833HRESULT STDMETHODCALLTYPE WebView::canResetPageZoom(
3834    /* [in] */ IUnknown* /*sender*/,
3835    /* [retval][out] */ BOOL* result)
3836{
3837    bool notAlreadyStandard = canResetZoom(false);
3838    *result = notAlreadyStandard ? TRUE : FALSE;
3839    return S_OK;
3840}
3841
3842bool WebView::canResetZoom(bool isTextOnly)
3843{
3844    return zoomMultiplier(isTextOnly) != 1.0f;
3845}
3846
3847HRESULT STDMETHODCALLTYPE WebView::makeTextStandardSize(
3848    /* [in] */ IUnknown* /*sender*/)
3849{
3850    return resetZoom(true);
3851}
3852
3853HRESULT STDMETHODCALLTYPE WebView::resetPageZoom(
3854    /* [in] */ IUnknown* /*sender*/)
3855{
3856    return resetZoom(false);
3857}
3858
3859HRESULT WebView::resetZoom(bool isTextOnly)
3860{
3861    if (!canResetZoom(isTextOnly))
3862        return E_FAIL;
3863    setZoomMultiplier(1.0f, isTextOnly);
3864    return S_OK;
3865}
3866
3867HRESULT STDMETHODCALLTYPE WebView::toggleContinuousSpellChecking(
3868    /* [in] */ IUnknown* /*sender*/)
3869{
3870    HRESULT hr;
3871    BOOL enabled;
3872    if (FAILED(hr = isContinuousSpellCheckingEnabled(&enabled)))
3873        return hr;
3874    return setContinuousSpellCheckingEnabled(enabled ? FALSE : TRUE);
3875}
3876
3877HRESULT STDMETHODCALLTYPE WebView::toggleSmartInsertDelete(
3878    /* [in] */ IUnknown* /*sender*/)
3879{
3880    BOOL enabled = FALSE;
3881    HRESULT hr = smartInsertDeleteEnabled(&enabled);
3882    if (FAILED(hr))
3883        return hr;
3884
3885    return setSmartInsertDeleteEnabled(enabled ? FALSE : TRUE);
3886}
3887
3888HRESULT STDMETHODCALLTYPE WebView::toggleGrammarChecking(
3889    /* [in] */ IUnknown* /*sender*/)
3890{
3891    BOOL enabled;
3892    HRESULT hr = isGrammarCheckingEnabled(&enabled);
3893    if (FAILED(hr))
3894        return hr;
3895
3896    return setGrammarCheckingEnabled(enabled ? FALSE : TRUE);
3897}
3898
3899HRESULT STDMETHODCALLTYPE WebView::reloadFromOrigin(
3900        /* [in] */ IUnknown* /*sender*/)
3901{
3902    if (!m_mainFrame)
3903        return E_FAIL;
3904
3905    return m_mainFrame->reloadFromOrigin();
3906}
3907
3908// IWebViewCSS -----------------------------------------------------------------
3909
3910HRESULT STDMETHODCALLTYPE WebView::computedStyleForElement(
3911        /* [in] */ IDOMElement* /*element*/,
3912        /* [in] */ BSTR /*pseudoElement*/,
3913        /* [retval][out] */ IDOMCSSStyleDeclaration** /*style*/)
3914{
3915    ASSERT_NOT_REACHED();
3916    return E_NOTIMPL;
3917}
3918
3919// IWebViewEditing -------------------------------------------------------------
3920
3921HRESULT STDMETHODCALLTYPE WebView::editableDOMRangeForPoint(
3922        /* [in] */ LPPOINT /*point*/,
3923        /* [retval][out] */ IDOMRange** /*range*/)
3924{
3925    ASSERT_NOT_REACHED();
3926    return E_NOTIMPL;
3927}
3928
3929HRESULT STDMETHODCALLTYPE WebView::setSelectedDOMRange(
3930        /* [in] */ IDOMRange* /*range*/,
3931        /* [in] */ WebSelectionAffinity /*affinity*/)
3932{
3933    ASSERT_NOT_REACHED();
3934    return E_NOTIMPL;
3935}
3936
3937HRESULT STDMETHODCALLTYPE WebView::selectedDOMRange(
3938        /* [retval][out] */ IDOMRange** /*range*/)
3939{
3940    ASSERT_NOT_REACHED();
3941    return E_NOTIMPL;
3942}
3943
3944HRESULT STDMETHODCALLTYPE WebView::selectionAffinity(
3945        /* [retval][out][retval][out] */ WebSelectionAffinity* /*affinity*/)
3946{
3947    ASSERT_NOT_REACHED();
3948    return E_NOTIMPL;
3949}
3950
3951HRESULT STDMETHODCALLTYPE WebView::setEditable(
3952        /* [in] */ BOOL /*flag*/)
3953{
3954    ASSERT_NOT_REACHED();
3955    return E_NOTIMPL;
3956}
3957
3958HRESULT STDMETHODCALLTYPE WebView::isEditable(
3959        /* [retval][out] */ BOOL* /*isEditable*/)
3960{
3961    ASSERT_NOT_REACHED();
3962    return E_NOTIMPL;
3963}
3964
3965HRESULT STDMETHODCALLTYPE WebView::setTypingStyle(
3966        /* [in] */ IDOMCSSStyleDeclaration* /*style*/)
3967{
3968    ASSERT_NOT_REACHED();
3969    return E_NOTIMPL;
3970}
3971
3972HRESULT STDMETHODCALLTYPE WebView::typingStyle(
3973        /* [retval][out] */ IDOMCSSStyleDeclaration** /*style*/)
3974{
3975    ASSERT_NOT_REACHED();
3976    return E_NOTIMPL;
3977}
3978
3979HRESULT STDMETHODCALLTYPE WebView::setSmartInsertDeleteEnabled(
3980        /* [in] */ BOOL flag)
3981{
3982    m_smartInsertDeleteEnabled = !!flag;
3983    if (m_smartInsertDeleteEnabled)
3984        setSelectTrailingWhitespaceEnabled(false);
3985    return S_OK;
3986}
3987
3988HRESULT STDMETHODCALLTYPE WebView::smartInsertDeleteEnabled(
3989        /* [retval][out] */ BOOL* enabled)
3990{
3991    *enabled = m_smartInsertDeleteEnabled ? TRUE : FALSE;
3992    return S_OK;
3993}
3994
3995HRESULT STDMETHODCALLTYPE WebView::setSelectTrailingWhitespaceEnabled(
3996        /* [in] */ BOOL flag)
3997{
3998    m_selectTrailingWhitespaceEnabled = !!flag;
3999    if (m_selectTrailingWhitespaceEnabled)
4000        setSmartInsertDeleteEnabled(false);
4001    return S_OK;
4002}
4003
4004HRESULT STDMETHODCALLTYPE WebView::isSelectTrailingWhitespaceEnabled(
4005        /* [retval][out] */ BOOL* enabled)
4006{
4007    *enabled = m_selectTrailingWhitespaceEnabled ? TRUE : FALSE;
4008    return S_OK;
4009}
4010
4011HRESULT STDMETHODCALLTYPE WebView::setContinuousSpellCheckingEnabled(
4012        /* [in] */ BOOL flag)
4013{
4014    if (continuousSpellCheckingEnabled != !!flag) {
4015        continuousSpellCheckingEnabled = !!flag;
4016        COMPtr<IWebPreferences> prefs;
4017        if (SUCCEEDED(preferences(&prefs)))
4018            prefs->setContinuousSpellCheckingEnabled(flag);
4019    }
4020
4021    BOOL spellCheckingEnabled;
4022    if (SUCCEEDED(isContinuousSpellCheckingEnabled(&spellCheckingEnabled)) && spellCheckingEnabled)
4023        preflightSpellChecker();
4024    else
4025        m_mainFrame->unmarkAllMisspellings();
4026
4027    return S_OK;
4028}
4029
4030HRESULT STDMETHODCALLTYPE WebView::isContinuousSpellCheckingEnabled(
4031        /* [retval][out] */ BOOL* enabled)
4032{
4033    *enabled = (continuousSpellCheckingEnabled && continuousCheckingAllowed()) ? TRUE : FALSE;
4034    return S_OK;
4035}
4036
4037HRESULT STDMETHODCALLTYPE WebView::spellCheckerDocumentTag(
4038        /* [retval][out] */ int* tag)
4039{
4040    // we just use this as a flag to indicate that we've spell checked the document
4041    // and need to close the spell checker out when the view closes.
4042    *tag = 0;
4043    m_hasSpellCheckerDocumentTag = true;
4044    return S_OK;
4045}
4046
4047static COMPtr<IWebEditingDelegate> spellingDelegateForTimer;
4048
4049static void preflightSpellCheckerNow()
4050{
4051    spellingDelegateForTimer->preflightChosenSpellServer();
4052    spellingDelegateForTimer = 0;
4053}
4054
4055static void CALLBACK preflightSpellCheckerTimerCallback(HWND, UINT, UINT_PTR id, DWORD)
4056{
4057    ::KillTimer(0, id);
4058    preflightSpellCheckerNow();
4059}
4060
4061void WebView::preflightSpellChecker()
4062{
4063    // As AppKit does, we wish to delay tickling the shared spellchecker into existence on application launch.
4064    if (!m_editingDelegate)
4065        return;
4066
4067    BOOL exists;
4068    spellingDelegateForTimer = m_editingDelegate;
4069    if (SUCCEEDED(m_editingDelegate->sharedSpellCheckerExists(&exists)) && exists)
4070        preflightSpellCheckerNow();
4071    else
4072        ::SetTimer(0, 0, 2000, preflightSpellCheckerTimerCallback);
4073}
4074
4075bool WebView::continuousCheckingAllowed()
4076{
4077    static bool allowContinuousSpellChecking = true;
4078    static bool readAllowContinuousSpellCheckingDefault = false;
4079    if (!readAllowContinuousSpellCheckingDefault) {
4080        COMPtr<IWebPreferences> prefs;
4081        if (SUCCEEDED(preferences(&prefs))) {
4082            BOOL allowed;
4083            prefs->allowContinuousSpellChecking(&allowed);
4084            allowContinuousSpellChecking = !!allowed;
4085        }
4086        readAllowContinuousSpellCheckingDefault = true;
4087    }
4088    return allowContinuousSpellChecking;
4089}
4090
4091HRESULT STDMETHODCALLTYPE WebView::undoManager(
4092        /* [retval][out] */ IWebUndoManager** /*manager*/)
4093{
4094    ASSERT_NOT_REACHED();
4095    return E_NOTIMPL;
4096}
4097
4098HRESULT STDMETHODCALLTYPE WebView::setEditingDelegate(
4099        /* [in] */ IWebEditingDelegate* d)
4100{
4101    m_editingDelegate = d;
4102    return S_OK;
4103}
4104
4105HRESULT STDMETHODCALLTYPE WebView::editingDelegate(
4106        /* [retval][out] */ IWebEditingDelegate** d)
4107{
4108    if (!d) {
4109        ASSERT_NOT_REACHED();
4110        return E_POINTER;
4111    }
4112
4113    *d = m_editingDelegate.get();
4114    if (!*d)
4115        return E_FAIL;
4116
4117    (*d)->AddRef();
4118    return S_OK;
4119}
4120
4121HRESULT STDMETHODCALLTYPE WebView::styleDeclarationWithText(
4122        /* [in] */ BSTR /*text*/,
4123        /* [retval][out] */ IDOMCSSStyleDeclaration** /*style*/)
4124{
4125    ASSERT_NOT_REACHED();
4126    return E_NOTIMPL;
4127}
4128
4129HRESULT STDMETHODCALLTYPE WebView::hasSelectedRange(
4130        /* [retval][out] */ BOOL* hasSelectedRange)
4131{
4132    *hasSelectedRange = m_page->mainFrame()->selection()->isRange();
4133    return S_OK;
4134}
4135
4136HRESULT STDMETHODCALLTYPE WebView::cutEnabled(
4137        /* [retval][out] */ BOOL* enabled)
4138{
4139    Editor* editor = m_page->focusController()->focusedOrMainFrame()->editor();
4140    *enabled = editor->canCut() || editor->canDHTMLCut();
4141    return S_OK;
4142}
4143
4144HRESULT STDMETHODCALLTYPE WebView::copyEnabled(
4145        /* [retval][out] */ BOOL* enabled)
4146{
4147    Editor* editor = m_page->focusController()->focusedOrMainFrame()->editor();
4148    *enabled = editor->canCopy() || editor->canDHTMLCopy();
4149    return S_OK;
4150}
4151
4152HRESULT STDMETHODCALLTYPE WebView::pasteEnabled(
4153        /* [retval][out] */ BOOL* enabled)
4154{
4155    Editor* editor = m_page->focusController()->focusedOrMainFrame()->editor();
4156    *enabled = editor->canPaste() || editor->canDHTMLPaste();
4157    return S_OK;
4158}
4159
4160HRESULT STDMETHODCALLTYPE WebView::deleteEnabled(
4161        /* [retval][out] */ BOOL* enabled)
4162{
4163    *enabled = m_page->focusController()->focusedOrMainFrame()->editor()->canDelete();
4164    return S_OK;
4165}
4166
4167HRESULT STDMETHODCALLTYPE WebView::editingEnabled(
4168        /* [retval][out] */ BOOL* enabled)
4169{
4170    *enabled = m_page->focusController()->focusedOrMainFrame()->editor()->canEdit();
4171    return S_OK;
4172}
4173
4174HRESULT STDMETHODCALLTYPE WebView::isGrammarCheckingEnabled(
4175    /* [retval][out] */ BOOL* enabled)
4176{
4177    *enabled = grammarCheckingEnabled ? TRUE : FALSE;
4178    return S_OK;
4179}
4180
4181HRESULT STDMETHODCALLTYPE WebView::setGrammarCheckingEnabled(
4182    BOOL enabled)
4183{
4184    if (!m_editingDelegate) {
4185        LOG_ERROR("No NSSpellChecker");
4186        return E_FAIL;
4187    }
4188
4189    if (grammarCheckingEnabled == !!enabled)
4190        return S_OK;
4191
4192    grammarCheckingEnabled = !!enabled;
4193    COMPtr<IWebPreferences> prefs;
4194    if (SUCCEEDED(preferences(&prefs)))
4195        prefs->setGrammarCheckingEnabled(enabled);
4196
4197    m_editingDelegate->updateGrammar();
4198
4199    // We call _preflightSpellChecker when turning continuous spell checking on, but we don't need to do that here
4200    // because grammar checking only occurs on code paths that already preflight spell checking appropriately.
4201
4202    BOOL grammarEnabled;
4203    if (SUCCEEDED(isGrammarCheckingEnabled(&grammarEnabled)) && !grammarEnabled)
4204        m_mainFrame->unmarkAllBadGrammar();
4205
4206    return S_OK;
4207}
4208
4209// IWebViewUndoableEditing -----------------------------------------------------
4210
4211HRESULT STDMETHODCALLTYPE WebView::replaceSelectionWithNode(
4212        /* [in] */ IDOMNode* /*node*/)
4213{
4214    ASSERT_NOT_REACHED();
4215    return E_NOTIMPL;
4216}
4217
4218HRESULT STDMETHODCALLTYPE WebView::replaceSelectionWithText(
4219        /* [in] */ BSTR text)
4220{
4221    String textString(text, ::SysStringLen(text));
4222    Position start = m_page->mainFrame()->selection()->selection().start();
4223    m_page->focusController()->focusedOrMainFrame()->editor()->insertText(textString, 0);
4224    m_page->mainFrame()->selection()->setBase(start);
4225    return S_OK;
4226}
4227
4228HRESULT STDMETHODCALLTYPE WebView::replaceSelectionWithMarkupString(
4229        /* [in] */ BSTR /*markupString*/)
4230{
4231    ASSERT_NOT_REACHED();
4232    return E_NOTIMPL;
4233}
4234
4235HRESULT STDMETHODCALLTYPE WebView::replaceSelectionWithArchive(
4236        /* [in] */ IWebArchive* /*archive*/)
4237{
4238    ASSERT_NOT_REACHED();
4239    return E_NOTIMPL;
4240}
4241
4242HRESULT STDMETHODCALLTYPE WebView::deleteSelection( void)
4243{
4244    Editor* editor = m_page->focusController()->focusedOrMainFrame()->editor();
4245    editor->deleteSelectionWithSmartDelete(editor->canSmartCopyOrDelete());
4246    return S_OK;
4247}
4248
4249HRESULT STDMETHODCALLTYPE WebView::clearSelection( void)
4250{
4251    m_page->focusController()->focusedOrMainFrame()->selection()->clear();
4252    return S_OK;
4253}
4254
4255HRESULT STDMETHODCALLTYPE WebView::applyStyle(
4256        /* [in] */ IDOMCSSStyleDeclaration* /*style*/)
4257{
4258    ASSERT_NOT_REACHED();
4259    return E_NOTIMPL;
4260}
4261
4262// IWebViewEditingActions ------------------------------------------------------
4263
4264HRESULT STDMETHODCALLTYPE WebView::copy(
4265        /* [in] */ IUnknown* /*sender*/)
4266{
4267    m_page->focusController()->focusedOrMainFrame()->editor()->command("Copy").execute();
4268    return S_OK;
4269}
4270
4271HRESULT STDMETHODCALLTYPE WebView::cut(
4272        /* [in] */ IUnknown* /*sender*/)
4273{
4274    m_page->focusController()->focusedOrMainFrame()->editor()->command("Cut").execute();
4275    return S_OK;
4276}
4277
4278HRESULT STDMETHODCALLTYPE WebView::paste(
4279        /* [in] */ IUnknown* /*sender*/)
4280{
4281    m_page->focusController()->focusedOrMainFrame()->editor()->command("Paste").execute();
4282    return S_OK;
4283}
4284
4285HRESULT STDMETHODCALLTYPE WebView::copyURL(
4286        /* [in] */ BSTR url)
4287{
4288    m_page->focusController()->focusedOrMainFrame()->editor()->copyURL(MarshallingHelpers::BSTRToKURL(url), "");
4289    return S_OK;
4290}
4291
4292
4293HRESULT STDMETHODCALLTYPE WebView::copyFont(
4294        /* [in] */ IUnknown* /*sender*/)
4295{
4296    ASSERT_NOT_REACHED();
4297    return E_NOTIMPL;
4298}
4299
4300HRESULT STDMETHODCALLTYPE WebView::pasteFont(
4301        /* [in] */ IUnknown* /*sender*/)
4302{
4303    ASSERT_NOT_REACHED();
4304    return E_NOTIMPL;
4305}
4306
4307HRESULT STDMETHODCALLTYPE WebView::delete_(
4308        /* [in] */ IUnknown* /*sender*/)
4309{
4310    m_page->focusController()->focusedOrMainFrame()->editor()->command("Delete").execute();
4311    return S_OK;
4312}
4313
4314HRESULT STDMETHODCALLTYPE WebView::pasteAsPlainText(
4315        /* [in] */ IUnknown* /*sender*/)
4316{
4317    ASSERT_NOT_REACHED();
4318    return E_NOTIMPL;
4319}
4320
4321HRESULT STDMETHODCALLTYPE WebView::pasteAsRichText(
4322        /* [in] */ IUnknown* /*sender*/)
4323{
4324    ASSERT_NOT_REACHED();
4325    return E_NOTIMPL;
4326}
4327
4328HRESULT STDMETHODCALLTYPE WebView::changeFont(
4329        /* [in] */ IUnknown* /*sender*/)
4330{
4331    ASSERT_NOT_REACHED();
4332    return E_NOTIMPL;
4333}
4334
4335HRESULT STDMETHODCALLTYPE WebView::changeAttributes(
4336        /* [in] */ IUnknown* /*sender*/)
4337{
4338    ASSERT_NOT_REACHED();
4339    return E_NOTIMPL;
4340}
4341
4342HRESULT STDMETHODCALLTYPE WebView::changeDocumentBackgroundColor(
4343        /* [in] */ IUnknown* /*sender*/)
4344{
4345    ASSERT_NOT_REACHED();
4346    return E_NOTIMPL;
4347}
4348
4349HRESULT STDMETHODCALLTYPE WebView::changeColor(
4350        /* [in] */ IUnknown* /*sender*/)
4351{
4352    ASSERT_NOT_REACHED();
4353    return E_NOTIMPL;
4354}
4355
4356HRESULT STDMETHODCALLTYPE WebView::alignCenter(
4357        /* [in] */ IUnknown* /*sender*/)
4358{
4359    ASSERT_NOT_REACHED();
4360    return E_NOTIMPL;
4361}
4362
4363HRESULT STDMETHODCALLTYPE WebView::alignJustified(
4364        /* [in] */ IUnknown* /*sender*/)
4365{
4366    ASSERT_NOT_REACHED();
4367    return E_NOTIMPL;
4368}
4369
4370HRESULT STDMETHODCALLTYPE WebView::alignLeft(
4371        /* [in] */ IUnknown* /*sender*/)
4372{
4373    ASSERT_NOT_REACHED();
4374    return E_NOTIMPL;
4375}
4376
4377HRESULT STDMETHODCALLTYPE WebView::alignRight(
4378        /* [in] */ IUnknown* /*sender*/)
4379{
4380    ASSERT_NOT_REACHED();
4381    return E_NOTIMPL;
4382}
4383
4384HRESULT STDMETHODCALLTYPE WebView::checkSpelling(
4385        /* [in] */ IUnknown* /*sender*/)
4386{
4387    if (!m_editingDelegate) {
4388        LOG_ERROR("No NSSpellChecker");
4389        return E_FAIL;
4390    }
4391
4392    core(m_mainFrame)->editor()->advanceToNextMisspelling();
4393    return S_OK;
4394}
4395
4396HRESULT STDMETHODCALLTYPE WebView::showGuessPanel(
4397        /* [in] */ IUnknown* /*sender*/)
4398{
4399    if (!m_editingDelegate) {
4400        LOG_ERROR("No NSSpellChecker");
4401        return E_FAIL;
4402    }
4403
4404    // Post-Tiger, this menu item is a show/hide toggle, to match AppKit. Leave Tiger behavior alone
4405    // to match rest of OS X.
4406    BOOL showing;
4407    if (SUCCEEDED(m_editingDelegate->spellingUIIsShowing(&showing)) && showing) {
4408        m_editingDelegate->showSpellingUI(FALSE);
4409    }
4410
4411    core(m_mainFrame)->editor()->advanceToNextMisspelling(true);
4412    m_editingDelegate->showSpellingUI(TRUE);
4413    return S_OK;
4414}
4415
4416HRESULT STDMETHODCALLTYPE WebView::performFindPanelAction(
4417        /* [in] */ IUnknown* /*sender*/)
4418{
4419    ASSERT_NOT_REACHED();
4420    return E_NOTIMPL;
4421}
4422
4423HRESULT STDMETHODCALLTYPE WebView::startSpeaking(
4424        /* [in] */ IUnknown* /*sender*/)
4425{
4426    ASSERT_NOT_REACHED();
4427    return E_NOTIMPL;
4428}
4429
4430HRESULT STDMETHODCALLTYPE WebView::stopSpeaking(
4431        /* [in] */ IUnknown* /*sender*/)
4432{
4433    ASSERT_NOT_REACHED();
4434    return E_NOTIMPL;
4435}
4436
4437// IWebNotificationObserver -----------------------------------------------------------------
4438
4439HRESULT STDMETHODCALLTYPE WebView::onNotify(
4440    /* [in] */ IWebNotification* notification)
4441{
4442    BSTR nameBSTR;
4443    HRESULT hr = notification->name(&nameBSTR);
4444    if (FAILED(hr))
4445        return hr;
4446
4447    BString name;
4448    name.adoptBSTR(nameBSTR);
4449
4450    if (!wcscmp(name, WebIconDatabase::iconDatabaseDidAddIconNotification()))
4451        return notifyDidAddIcon(notification);
4452
4453    if (!wcscmp(name, WebPreferences::webPreferencesChangedNotification()))
4454        return notifyPreferencesChanged(notification);
4455
4456    return hr;
4457}
4458
4459HRESULT WebView::notifyPreferencesChanged(IWebNotification* notification)
4460{
4461    HRESULT hr;
4462
4463    COMPtr<IUnknown> unkPrefs;
4464    hr = notification->getObject(&unkPrefs);
4465    if (FAILED(hr))
4466        return hr;
4467
4468    COMPtr<IWebPreferences> preferences(Query, unkPrefs);
4469    if (!preferences)
4470        return E_NOINTERFACE;
4471
4472    ASSERT(preferences == m_preferences);
4473
4474    BSTR str;
4475    int size;
4476    BOOL enabled;
4477
4478    Settings* settings = m_page->settings();
4479
4480    hr = preferences->cursiveFontFamily(&str);
4481    if (FAILED(hr))
4482        return hr;
4483    settings->setCursiveFontFamily(AtomicString(str, SysStringLen(str)));
4484    SysFreeString(str);
4485
4486    hr = preferences->defaultFixedFontSize(&size);
4487    if (FAILED(hr))
4488        return hr;
4489    settings->setDefaultFixedFontSize(size);
4490
4491    hr = preferences->defaultFontSize(&size);
4492    if (FAILED(hr))
4493        return hr;
4494    settings->setDefaultFontSize(size);
4495
4496    hr = preferences->defaultTextEncodingName(&str);
4497    if (FAILED(hr))
4498        return hr;
4499    settings->setDefaultTextEncodingName(String(str, SysStringLen(str)));
4500    SysFreeString(str);
4501
4502    hr = preferences->fantasyFontFamily(&str);
4503    if (FAILED(hr))
4504        return hr;
4505    settings->setFantasyFontFamily(AtomicString(str, SysStringLen(str)));
4506    SysFreeString(str);
4507
4508    hr = preferences->fixedFontFamily(&str);
4509    if (FAILED(hr))
4510        return hr;
4511    settings->setFixedFontFamily(AtomicString(str, SysStringLen(str)));
4512    SysFreeString(str);
4513
4514    hr = preferences->isJavaEnabled(&enabled);
4515    if (FAILED(hr))
4516        return hr;
4517    settings->setJavaEnabled(!!enabled);
4518
4519    hr = preferences->isJavaScriptEnabled(&enabled);
4520    if (FAILED(hr))
4521        return hr;
4522    settings->setJavaScriptEnabled(!!enabled);
4523
4524    hr = preferences->javaScriptCanOpenWindowsAutomatically(&enabled);
4525    if (FAILED(hr))
4526        return hr;
4527    settings->setJavaScriptCanOpenWindowsAutomatically(!!enabled);
4528
4529    hr = preferences->minimumFontSize(&size);
4530    if (FAILED(hr))
4531        return hr;
4532    settings->setMinimumFontSize(size);
4533
4534    hr = preferences->minimumLogicalFontSize(&size);
4535    if (FAILED(hr))
4536        return hr;
4537    settings->setMinimumLogicalFontSize(size);
4538
4539    hr = preferences->arePlugInsEnabled(&enabled);
4540    if (FAILED(hr))
4541        return hr;
4542    settings->setPluginsEnabled(!!enabled);
4543
4544    hr = preferences->privateBrowsingEnabled(&enabled);
4545    if (FAILED(hr))
4546        return hr;
4547    settings->setPrivateBrowsingEnabled(!!enabled);
4548
4549    hr = preferences->sansSerifFontFamily(&str);
4550    if (FAILED(hr))
4551        return hr;
4552    settings->setSansSerifFontFamily(AtomicString(str, SysStringLen(str)));
4553    SysFreeString(str);
4554
4555    hr = preferences->serifFontFamily(&str);
4556    if (FAILED(hr))
4557        return hr;
4558    settings->setSerifFontFamily(AtomicString(str, SysStringLen(str)));
4559    SysFreeString(str);
4560
4561    hr = preferences->standardFontFamily(&str);
4562    if (FAILED(hr))
4563        return hr;
4564    settings->setStandardFontFamily(AtomicString(str, SysStringLen(str)));
4565    SysFreeString(str);
4566
4567    hr = preferences->loadsImagesAutomatically(&enabled);
4568    if (FAILED(hr))
4569        return hr;
4570    settings->setLoadsImagesAutomatically(!!enabled);
4571
4572    hr = preferences->userStyleSheetEnabled(&enabled);
4573    if (FAILED(hr))
4574        return hr;
4575    if (enabled) {
4576        hr = preferences->userStyleSheetLocation(&str);
4577        if (FAILED(hr))
4578            return hr;
4579
4580        RetainPtr<CFStringRef> urlString(AdoptCF, String(str, SysStringLen(str)).createCFString());
4581        RetainPtr<CFURLRef> url(AdoptCF, CFURLCreateWithString(kCFAllocatorDefault, urlString.get(), 0));
4582
4583        // Check if the passed in string is a path and convert it to a URL.
4584        // FIXME: This is a workaround for nightly builds until we can get Safari to pass
4585        // in an URL here. See <rdar://problem/5478378>
4586        if (!url) {
4587            DWORD len = SysStringLen(str) + 1;
4588
4589            int result = WideCharToMultiByte(CP_UTF8, 0, str, len, 0, 0, 0, 0);
4590            Vector<UInt8> utf8Path(result);
4591            if (!WideCharToMultiByte(CP_UTF8, 0, str, len, (LPSTR)utf8Path.data(), result, 0, 0))
4592                return E_FAIL;
4593
4594            url.adoptCF(CFURLCreateFromFileSystemRepresentation(0, utf8Path.data(), result - 1, false));
4595        }
4596
4597        settings->setUserStyleSheetLocation(url.get());
4598        SysFreeString(str);
4599    } else {
4600        settings->setUserStyleSheetLocation(KURL());
4601    }
4602
4603    hr = preferences->shouldPrintBackgrounds(&enabled);
4604    if (FAILED(hr))
4605        return hr;
4606    settings->setShouldPrintBackgrounds(!!enabled);
4607
4608    hr = preferences->textAreasAreResizable(&enabled);
4609    if (FAILED(hr))
4610        return hr;
4611    settings->setTextAreasAreResizable(!!enabled);
4612
4613    WebKitEditableLinkBehavior behavior;
4614    hr = preferences->editableLinkBehavior(&behavior);
4615    if (FAILED(hr))
4616        return hr;
4617    settings->setEditableLinkBehavior((EditableLinkBehavior)behavior);
4618
4619    WebKitEditingBehavior editingBehavior;
4620    hr = preferences->editingBehavior(&editingBehavior);
4621    if (FAILED(hr))
4622        return hr;
4623    settings->setEditingBehaviorType((EditingBehaviorType)editingBehavior);
4624
4625    hr = preferences->usesPageCache(&enabled);
4626    if (FAILED(hr))
4627        return hr;
4628    settings->setUsesPageCache(!!enabled);
4629
4630    hr = preferences->isDOMPasteAllowed(&enabled);
4631    if (FAILED(hr))
4632        return hr;
4633    settings->setDOMPasteAllowed(!!enabled);
4634
4635    hr = preferences->shouldPaintCustomScrollbars(&enabled);
4636    if (FAILED(hr))
4637        return hr;
4638    settings->setShouldPaintCustomScrollbars(!!enabled);
4639
4640    hr = preferences->zoomsTextOnly(&enabled);
4641    if (FAILED(hr))
4642        return hr;
4643
4644    if (m_zoomsTextOnly != !!enabled)
4645        setZoomMultiplier(m_zoomMultiplier, enabled);
4646
4647    settings->setShowsURLsInToolTips(false);
4648    settings->setForceFTPDirectoryListings(true);
4649    settings->setDeveloperExtrasEnabled(developerExtrasEnabled());
4650    settings->setNeedsSiteSpecificQuirks(s_allowSiteSpecificHacks);
4651
4652    FontSmoothingType smoothingType;
4653    hr = preferences->fontSmoothing(&smoothingType);
4654    if (FAILED(hr))
4655        return hr;
4656    settings->setFontRenderingMode(smoothingType != FontSmoothingTypeWindows ? NormalRenderingMode : AlternateRenderingMode);
4657
4658    COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
4659    if (prefsPrivate) {
4660        hr = prefsPrivate->authorAndUserStylesEnabled(&enabled);
4661        if (FAILED(hr))
4662            return hr;
4663        settings->setAuthorAndUserStylesEnabled(enabled);
4664    }
4665
4666    hr = prefsPrivate->inApplicationChromeMode(&enabled);
4667    if (FAILED(hr))
4668        return hr;
4669    settings->setApplicationChromeMode(enabled);
4670
4671    hr = prefsPrivate->offlineWebApplicationCacheEnabled(&enabled);
4672    if (FAILED(hr))
4673        return hr;
4674    settings->setOfflineWebApplicationCacheEnabled(enabled);
4675
4676#if ENABLE(DATABASE)
4677    hr = prefsPrivate->databasesEnabled(&enabled);
4678    if (FAILED(hr))
4679        return hr;
4680    AbstractDatabase::setIsAvailable(enabled);
4681#endif
4682
4683    hr = prefsPrivate->localStorageEnabled(&enabled);
4684    if (FAILED(hr))
4685        return hr;
4686    settings->setLocalStorageEnabled(enabled);
4687
4688    hr = prefsPrivate->experimentalNotificationsEnabled(&enabled);
4689    if (FAILED(hr))
4690        return hr;
4691    settings->setExperimentalNotificationsEnabled(enabled);
4692
4693    hr = prefsPrivate->isWebSecurityEnabled(&enabled);
4694    if (FAILED(hr))
4695        return hr;
4696    settings->setWebSecurityEnabled(!!enabled);
4697
4698    hr = prefsPrivate->allowUniversalAccessFromFileURLs(&enabled);
4699    if (FAILED(hr))
4700        return hr;
4701    settings->setAllowUniversalAccessFromFileURLs(!!enabled);
4702
4703    hr = prefsPrivate->allowFileAccessFromFileURLs(&enabled);
4704    if (FAILED(hr))
4705        return hr;
4706    settings->setAllowFileAccessFromFileURLs(!!enabled);
4707
4708    hr = prefsPrivate->javaScriptCanAccessClipboard(&enabled);
4709    if (FAILED(hr))
4710        return hr;
4711    settings->setJavaScriptCanAccessClipboard(!!enabled);
4712
4713    hr = prefsPrivate->isXSSAuditorEnabled(&enabled);
4714    if (FAILED(hr))
4715        return hr;
4716    settings->setXSSAuditorEnabled(!!enabled);
4717
4718#if USE(SAFARI_THEME)
4719    hr = prefsPrivate->shouldPaintNativeControls(&enabled);
4720    if (FAILED(hr))
4721        return hr;
4722    settings->setShouldPaintNativeControls(!!enabled);
4723#endif
4724
4725    hr = prefsPrivate->shouldUseHighResolutionTimers(&enabled);
4726    if (FAILED(hr))
4727        return hr;
4728    settings->setShouldUseHighResolutionTimers(enabled);
4729
4730    UINT runTime;
4731    hr = prefsPrivate->pluginAllowedRunTime(&runTime);
4732    if (FAILED(hr))
4733        return hr;
4734    settings->setPluginAllowedRunTime(runTime);
4735
4736    hr = prefsPrivate->isFrameFlatteningEnabled(&enabled);
4737    if (FAILED(hr))
4738        return hr;
4739    settings->setFrameFlatteningEnabled(enabled);
4740
4741#if USE(ACCELERATED_COMPOSITING)
4742    hr = prefsPrivate->acceleratedCompositingEnabled(&enabled);
4743    if (FAILED(hr))
4744        return hr;
4745    settings->setAcceleratedCompositingEnabled(enabled);
4746#endif
4747
4748    hr = prefsPrivate->showDebugBorders(&enabled);
4749    if (FAILED(hr))
4750        return hr;
4751    settings->setShowDebugBorders(enabled);
4752
4753    hr = prefsPrivate->showRepaintCounter(&enabled);
4754    if (FAILED(hr))
4755        return hr;
4756    settings->setShowRepaintCounter(enabled);
4757
4758#if ENABLE(WEB_AUDIO)
4759    settings->setWebAudioEnabled(true);
4760#endif // ENABLE(WEB_AUDIO)
4761
4762#if ENABLE(WEBGL)
4763    settings->setWebGLEnabled(true);
4764#endif // ENABLE(WEBGL)
4765
4766    hr = prefsPrivate->isDNSPrefetchingEnabled(&enabled);
4767    if (FAILED(hr))
4768        return hr;
4769    settings->setDNSPrefetchingEnabled(enabled);
4770
4771    hr = prefsPrivate->memoryInfoEnabled(&enabled);
4772    if (FAILED(hr))
4773        return hr;
4774    settings->setMemoryInfoEnabled(enabled);
4775
4776    hr = prefsPrivate->hyperlinkAuditingEnabled(&enabled);
4777    if (FAILED(hr))
4778        return hr;
4779    settings->setHyperlinkAuditingEnabled(enabled);
4780
4781    if (!m_closeWindowTimer)
4782        m_mainFrame->invalidate(); // FIXME
4783
4784    hr = updateSharedSettingsFromPreferencesIfNeeded(preferences.get());
4785    if (FAILED(hr))
4786        return hr;
4787
4788    return S_OK;
4789}
4790
4791HRESULT updateSharedSettingsFromPreferencesIfNeeded(IWebPreferences* preferences)
4792{
4793    if (preferences != WebPreferences::sharedStandardPreferences())
4794        return S_OK;
4795
4796    WebKitCookieStorageAcceptPolicy acceptPolicy;
4797    HRESULT hr = preferences->cookieStorageAcceptPolicy(&acceptPolicy);
4798    if (FAILED(hr))
4799        return hr;
4800
4801#if USE(CFNETWORK)
4802    // Set cookie storage accept policy
4803    if (CFHTTPCookieStorageRef cookieStorage = currentCookieStorage())
4804        CFHTTPCookieStorageSetCookieAcceptPolicy(cookieStorage, acceptPolicy);
4805#endif
4806
4807    return S_OK;
4808}
4809
4810// IWebViewPrivate ------------------------------------------------------------
4811
4812HRESULT STDMETHODCALLTYPE WebView::MIMETypeForExtension(
4813    /* [in] */ BSTR extension,
4814    /* [retval][out] */ BSTR* mimeType)
4815{
4816    if (!mimeType)
4817        return E_POINTER;
4818
4819    String extensionStr(extension, SysStringLen(extension));
4820
4821    *mimeType = BString(MIMETypeRegistry::getMIMETypeForExtension(extensionStr)).release();
4822
4823    return S_OK;
4824}
4825
4826HRESULT STDMETHODCALLTYPE WebView::setCustomDropTarget(
4827    /* [in] */ IDropTarget* dt)
4828{
4829    ASSERT(::IsWindow(m_viewWindow));
4830    if (!dt)
4831        return E_POINTER;
4832    m_hasCustomDropTarget = true;
4833    revokeDragDrop();
4834    return ::RegisterDragDrop(m_viewWindow,dt);
4835}
4836
4837HRESULT STDMETHODCALLTYPE WebView::removeCustomDropTarget()
4838{
4839    if (!m_hasCustomDropTarget)
4840        return S_OK;
4841    m_hasCustomDropTarget = false;
4842    revokeDragDrop();
4843    return registerDragDrop();
4844}
4845
4846HRESULT STDMETHODCALLTYPE WebView::setInViewSourceMode(
4847        /* [in] */ BOOL flag)
4848{
4849    if (!m_mainFrame)
4850        return E_FAIL;
4851
4852    return m_mainFrame->setInViewSourceMode(flag);
4853}
4854
4855HRESULT STDMETHODCALLTYPE WebView::inViewSourceMode(
4856        /* [retval][out] */ BOOL* flag)
4857{
4858    if (!m_mainFrame)
4859        return E_FAIL;
4860
4861    return m_mainFrame->inViewSourceMode(flag);
4862}
4863
4864HRESULT STDMETHODCALLTYPE WebView::viewWindow(
4865        /* [retval][out] */ OLE_HANDLE *window)
4866{
4867    *window = (OLE_HANDLE)(ULONG64)m_viewWindow;
4868    return S_OK;
4869}
4870
4871HRESULT STDMETHODCALLTYPE WebView::setFormDelegate(
4872    /* [in] */ IWebFormDelegate *formDelegate)
4873{
4874    m_formDelegate = formDelegate;
4875    return S_OK;
4876}
4877
4878HRESULT STDMETHODCALLTYPE WebView::formDelegate(
4879    /* [retval][out] */ IWebFormDelegate **formDelegate)
4880{
4881    if (!m_formDelegate)
4882        return E_FAIL;
4883
4884    return m_formDelegate.copyRefTo(formDelegate);
4885}
4886
4887HRESULT STDMETHODCALLTYPE WebView::setFrameLoadDelegatePrivate(
4888    /* [in] */ IWebFrameLoadDelegatePrivate* d)
4889{
4890    m_frameLoadDelegatePrivate = d;
4891    return S_OK;
4892}
4893
4894HRESULT STDMETHODCALLTYPE WebView::frameLoadDelegatePrivate(
4895    /* [out][retval] */ IWebFrameLoadDelegatePrivate** d)
4896{
4897    if (!m_frameLoadDelegatePrivate)
4898        return E_FAIL;
4899
4900    return m_frameLoadDelegatePrivate.copyRefTo(d);
4901}
4902
4903HRESULT STDMETHODCALLTYPE WebView::scrollOffset(
4904    /* [retval][out] */ LPPOINT offset)
4905{
4906    if (!offset)
4907        return E_POINTER;
4908    IntSize offsetIntSize = m_page->mainFrame()->view()->scrollOffset();
4909    offset->x = offsetIntSize.width();
4910    offset->y = offsetIntSize.height();
4911    return S_OK;
4912}
4913
4914HRESULT STDMETHODCALLTYPE WebView::scrollBy(
4915    /* [in] */ LPPOINT offset)
4916{
4917    if (!offset)
4918        return E_POINTER;
4919    m_page->mainFrame()->view()->scrollBy(IntSize(offset->x, offset->y));
4920    return S_OK;
4921}
4922
4923HRESULT STDMETHODCALLTYPE WebView::visibleContentRect(
4924    /* [retval][out] */ LPRECT rect)
4925{
4926    if (!rect)
4927        return E_POINTER;
4928    FloatRect visibleContent = m_page->mainFrame()->view()->visibleContentRect();
4929    rect->left = (LONG) visibleContent.x();
4930    rect->top = (LONG) visibleContent.y();
4931    rect->right = (LONG) visibleContent.maxX();
4932    rect->bottom = (LONG) visibleContent.maxY();
4933    return S_OK;
4934}
4935
4936static DWORD dragOperationToDragCursor(DragOperation op) {
4937    DWORD res = DROPEFFECT_NONE;
4938    if (op & DragOperationCopy)
4939        res = DROPEFFECT_COPY;
4940    else if (op & DragOperationLink)
4941        res = DROPEFFECT_LINK;
4942    else if (op & DragOperationMove)
4943        res = DROPEFFECT_MOVE;
4944    else if (op & DragOperationGeneric)
4945        res = DROPEFFECT_MOVE; //This appears to be the Firefox behaviour
4946    return res;
4947}
4948
4949DragOperation WebView::keyStateToDragOperation(DWORD grfKeyState) const
4950{
4951    if (!m_page)
4952        return DragOperationNone;
4953
4954    // Conforms to Microsoft's key combinations as documented for
4955    // IDropTarget::DragOver. Note, grfKeyState is the current
4956    // state of the keyboard modifier keys on the keyboard. See:
4957    // <http://msdn.microsoft.com/en-us/library/ms680129(VS.85).aspx>.
4958    DragOperation operation = m_page->dragController()->sourceDragOperation();
4959
4960    if ((grfKeyState & (MK_CONTROL | MK_SHIFT)) == (MK_CONTROL | MK_SHIFT))
4961        operation = DragOperationLink;
4962    else if ((grfKeyState & MK_CONTROL) == MK_CONTROL)
4963        operation = DragOperationCopy;
4964    else if ((grfKeyState & MK_SHIFT) == MK_SHIFT)
4965        operation = DragOperationGeneric;
4966
4967    return operation;
4968}
4969
4970HRESULT STDMETHODCALLTYPE WebView::DragEnter(
4971        IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
4972{
4973    m_dragData = 0;
4974
4975    if (m_dropTargetHelper)
4976        m_dropTargetHelper->DragEnter(m_viewWindow, pDataObject, (POINT*)&pt, *pdwEffect);
4977
4978    POINTL localpt = pt;
4979    ::ScreenToClient(m_viewWindow, (LPPOINT)&localpt);
4980    DragData data(pDataObject, IntPoint(localpt.x, localpt.y),
4981        IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState));
4982    *pdwEffect = dragOperationToDragCursor(m_page->dragController()->dragEntered(&data));
4983
4984    m_lastDropEffect = *pdwEffect;
4985    m_dragData = pDataObject;
4986
4987    return S_OK;
4988}
4989
4990HRESULT STDMETHODCALLTYPE WebView::DragOver(
4991        DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
4992{
4993    if (m_dropTargetHelper)
4994        m_dropTargetHelper->DragOver((POINT*)&pt, *pdwEffect);
4995
4996    if (m_dragData) {
4997        POINTL localpt = pt;
4998        ::ScreenToClient(m_viewWindow, (LPPOINT)&localpt);
4999        DragData data(m_dragData.get(), IntPoint(localpt.x, localpt.y),
5000            IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState));
5001        *pdwEffect = dragOperationToDragCursor(m_page->dragController()->dragUpdated(&data));
5002    } else
5003        *pdwEffect = DROPEFFECT_NONE;
5004
5005    m_lastDropEffect = *pdwEffect;
5006    return S_OK;
5007}
5008
5009HRESULT STDMETHODCALLTYPE WebView::DragLeave()
5010{
5011    if (m_dropTargetHelper)
5012        m_dropTargetHelper->DragLeave();
5013
5014    if (m_dragData) {
5015        DragData data(m_dragData.get(), IntPoint(), IntPoint(),
5016            DragOperationNone);
5017        m_page->dragController()->dragExited(&data);
5018        m_dragData = 0;
5019    }
5020    return S_OK;
5021}
5022
5023HRESULT STDMETHODCALLTYPE WebView::Drop(
5024        IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
5025{
5026    if (m_dropTargetHelper)
5027        m_dropTargetHelper->Drop(pDataObject, (POINT*)&pt, *pdwEffect);
5028
5029    m_dragData = 0;
5030    *pdwEffect = m_lastDropEffect;
5031    POINTL localpt = pt;
5032    ::ScreenToClient(m_viewWindow, (LPPOINT)&localpt);
5033    DragData data(pDataObject, IntPoint(localpt.x, localpt.y),
5034        IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState));
5035    m_page->dragController()->performDrag(&data);
5036    return S_OK;
5037}
5038
5039HRESULT STDMETHODCALLTYPE WebView::canHandleRequest(
5040    IWebURLRequest *request,
5041    BOOL *result)
5042{
5043    COMPtr<WebMutableURLRequest> requestImpl;
5044
5045    HRESULT hr = request->QueryInterface(&requestImpl);
5046    if (FAILED(hr))
5047        return hr;
5048
5049    *result = !!canHandleRequest(requestImpl->resourceRequest());
5050    return S_OK;
5051}
5052
5053HRESULT STDMETHODCALLTYPE WebView::standardUserAgentWithApplicationName(
5054    BSTR applicationName,
5055    BSTR* groupName)
5056{
5057    if (!groupName) {
5058        ASSERT_NOT_REACHED();
5059        return E_POINTER;
5060    }
5061
5062    *groupName;
5063
5064    if (!applicationName) {
5065        ASSERT_NOT_REACHED();
5066        return E_POINTER;
5067    }
5068
5069    BString applicationNameBString(applicationName);
5070    *groupName = BString(standardUserAgentWithApplicationName(String(applicationNameBString, SysStringLen(applicationNameBString)))).release();
5071    return S_OK;
5072}
5073
5074HRESULT STDMETHODCALLTYPE WebView::clearFocusNode()
5075{
5076    if (m_page && m_page->focusController())
5077        m_page->focusController()->setFocusedNode(0, 0);
5078    return S_OK;
5079}
5080
5081HRESULT STDMETHODCALLTYPE WebView::setInitialFocus(
5082    /* [in] */ BOOL forward)
5083{
5084    if (m_page && m_page->focusController()) {
5085        Frame* frame = m_page->focusController()->focusedOrMainFrame();
5086        frame->document()->setFocusedNode(0);
5087        m_page->focusController()->setInitialFocus(forward ? FocusDirectionForward : FocusDirectionBackward, 0);
5088    }
5089    return S_OK;
5090}
5091
5092HRESULT STDMETHODCALLTYPE WebView::setTabKeyCyclesThroughElements(
5093    /* [in] */ BOOL cycles)
5094{
5095    if (m_page)
5096        m_page->setTabKeyCyclesThroughElements(!!cycles);
5097
5098    return S_OK;
5099}
5100
5101HRESULT STDMETHODCALLTYPE WebView::tabKeyCyclesThroughElements(
5102    /* [retval][out] */ BOOL* result)
5103{
5104    if (!result) {
5105        ASSERT_NOT_REACHED();
5106        return E_POINTER;
5107    }
5108
5109    *result = m_page && m_page->tabKeyCyclesThroughElements() ? TRUE : FALSE;
5110    return S_OK;
5111}
5112
5113HRESULT STDMETHODCALLTYPE WebView::setAllowSiteSpecificHacks(
5114    /* [in] */ BOOL allow)
5115{
5116    s_allowSiteSpecificHacks = !!allow;
5117    // FIXME: This sets a global so it needs to call notifyPreferencesChanged
5118    // on all WebView objects (not just itself).
5119    return S_OK;
5120}
5121
5122HRESULT STDMETHODCALLTYPE WebView::addAdditionalPluginDirectory(
5123        /* [in] */ BSTR directory)
5124{
5125    PluginDatabase::installedPlugins()->addExtraPluginDirectory(String(directory, SysStringLen(directory)));
5126    return S_OK;
5127}
5128
5129HRESULT STDMETHODCALLTYPE WebView::loadBackForwardListFromOtherView(
5130    /* [in] */ IWebView* otherView)
5131{
5132    if (!m_page)
5133        return E_FAIL;
5134
5135    // It turns out the right combination of behavior is done with the back/forward load
5136    // type.  (See behavior matrix at the top of WebFramePrivate.)  So we copy all the items
5137    // in the back forward list, and go to the current one.
5138    BackForwardList* backForwardList = m_page->backForwardList();
5139    ASSERT(!backForwardList->currentItem()); // destination list should be empty
5140
5141    COMPtr<WebView> otherWebView;
5142    if (FAILED(otherView->QueryInterface(&otherWebView)))
5143        return E_FAIL;
5144    BackForwardList* otherBackForwardList = otherWebView->m_page->backForwardList();
5145    if (!otherBackForwardList->currentItem())
5146        return S_OK; // empty back forward list, bail
5147
5148    HistoryItem* newItemToGoTo = 0;
5149
5150    int lastItemIndex = otherBackForwardList->forwardListCount();
5151    for (int i = -otherBackForwardList->backListCount(); i <= lastItemIndex; ++i) {
5152        if (!i) {
5153            // If this item is showing , save away its current scroll and form state,
5154            // since that might have changed since loading and it is normally not saved
5155            // until we leave that page.
5156            otherWebView->m_page->mainFrame()->loader()->history()->saveDocumentAndScrollState();
5157        }
5158        RefPtr<HistoryItem> newItem = otherBackForwardList->itemAtIndex(i)->copy();
5159        if (!i)
5160            newItemToGoTo = newItem.get();
5161        backForwardList->addItem(newItem.release());
5162    }
5163
5164    ASSERT(newItemToGoTo);
5165    m_page->goToItem(newItemToGoTo, FrameLoadTypeIndexedBackForward);
5166    return S_OK;
5167}
5168
5169HRESULT STDMETHODCALLTYPE WebView::clearUndoRedoOperations()
5170{
5171    if (Frame* frame = m_page->focusController()->focusedOrMainFrame())
5172        frame->editor()->clearUndoRedoOperations();
5173    return S_OK;
5174}
5175
5176HRESULT STDMETHODCALLTYPE WebView::shouldClose(
5177    /* [retval][out] */ BOOL* result)
5178{
5179    if (!result) {
5180        ASSERT_NOT_REACHED();
5181        return E_POINTER;
5182    }
5183
5184    *result = TRUE;
5185    if (Frame* frame = m_page->mainFrame())
5186        *result = frame->loader()->shouldClose();
5187    return S_OK;
5188}
5189
5190HRESULT WebView::registerDragDrop()
5191{
5192    ASSERT(::IsWindow(m_viewWindow));
5193    return ::RegisterDragDrop(m_viewWindow, this);
5194}
5195
5196HRESULT WebView::revokeDragDrop()
5197{
5198    if (!m_viewWindow)
5199        return S_OK;
5200
5201    return ::RevokeDragDrop(m_viewWindow);
5202}
5203
5204HRESULT WebView::setProhibitsMainFrameScrolling(BOOL b)
5205{
5206    if (!m_page)
5207        return E_FAIL;
5208
5209    m_page->mainFrame()->view()->setProhibitsScrolling(b);
5210    return S_OK;
5211}
5212
5213HRESULT WebView::setShouldApplyMacFontAscentHack(BOOL b)
5214{
5215    SimpleFontData::setShouldApplyMacAscentHack(b);
5216    return S_OK;
5217}
5218
5219class IMMDict {
5220    typedef HIMC (CALLBACK *getContextPtr)(HWND);
5221    typedef BOOL (CALLBACK *releaseContextPtr)(HWND, HIMC);
5222    typedef LONG (CALLBACK *getCompositionStringPtr)(HIMC, DWORD, LPVOID, DWORD);
5223    typedef BOOL (CALLBACK *setCandidateWindowPtr)(HIMC, LPCANDIDATEFORM);
5224    typedef BOOL (CALLBACK *setOpenStatusPtr)(HIMC, BOOL);
5225    typedef BOOL (CALLBACK *notifyIMEPtr)(HIMC, DWORD, DWORD, DWORD);
5226    typedef BOOL (CALLBACK *associateContextExPtr)(HWND, HIMC, DWORD);
5227
5228public:
5229    getContextPtr getContext;
5230    releaseContextPtr releaseContext;
5231    getCompositionStringPtr getCompositionString;
5232    setCandidateWindowPtr setCandidateWindow;
5233    setOpenStatusPtr setOpenStatus;
5234    notifyIMEPtr notifyIME;
5235    associateContextExPtr associateContextEx;
5236
5237    static const IMMDict& dict();
5238private:
5239    IMMDict();
5240    HMODULE m_instance;
5241};
5242
5243const IMMDict& IMMDict::dict()
5244{
5245    static IMMDict instance;
5246    return instance;
5247}
5248
5249IMMDict::IMMDict()
5250{
5251    m_instance = ::LoadLibraryW(L"IMM32.DLL");
5252    getContext = reinterpret_cast<getContextPtr>(::GetProcAddress(m_instance, "ImmGetContext"));
5253    ASSERT(getContext);
5254    releaseContext = reinterpret_cast<releaseContextPtr>(::GetProcAddress(m_instance, "ImmReleaseContext"));
5255    ASSERT(releaseContext);
5256    getCompositionString = reinterpret_cast<getCompositionStringPtr>(::GetProcAddress(m_instance, "ImmGetCompositionStringW"));
5257    ASSERT(getCompositionString);
5258    setCandidateWindow = reinterpret_cast<setCandidateWindowPtr>(::GetProcAddress(m_instance, "ImmSetCandidateWindow"));
5259    ASSERT(setCandidateWindow);
5260    setOpenStatus = reinterpret_cast<setOpenStatusPtr>(::GetProcAddress(m_instance, "ImmSetOpenStatus"));
5261    ASSERT(setOpenStatus);
5262    notifyIME = reinterpret_cast<notifyIMEPtr>(::GetProcAddress(m_instance, "ImmNotifyIME"));
5263    ASSERT(notifyIME);
5264    associateContextEx = reinterpret_cast<associateContextExPtr>(::GetProcAddress(m_instance, "ImmAssociateContextEx"));
5265    ASSERT(associateContextEx);
5266}
5267
5268HIMC WebView::getIMMContext()
5269{
5270    HIMC context = IMMDict::dict().getContext(m_viewWindow);
5271    return context;
5272}
5273
5274void WebView::releaseIMMContext(HIMC hIMC)
5275{
5276    if (!hIMC)
5277        return;
5278    IMMDict::dict().releaseContext(m_viewWindow, hIMC);
5279}
5280
5281void WebView::prepareCandidateWindow(Frame* targetFrame, HIMC hInputContext)
5282{
5283    IntRect caret;
5284    if (RefPtr<Range> range = targetFrame->selection()->selection().toNormalizedRange()) {
5285        ExceptionCode ec = 0;
5286        RefPtr<Range> tempRange = range->cloneRange(ec);
5287        caret = targetFrame->editor()->firstRectForRange(tempRange.get());
5288    }
5289    caret = targetFrame->view()->contentsToWindow(caret);
5290    CANDIDATEFORM form;
5291    form.dwIndex = 0;
5292    form.dwStyle = CFS_EXCLUDE;
5293    form.ptCurrentPos.x = caret.x();
5294    form.ptCurrentPos.y = caret.y() + caret.height();
5295    form.rcArea.top = caret.y();
5296    form.rcArea.bottom = caret.maxY();
5297    form.rcArea.left = caret.x();
5298    form.rcArea.right = caret.maxX();
5299    IMMDict::dict().setCandidateWindow(hInputContext, &form);
5300}
5301
5302void WebView::resetIME(Frame* targetFrame)
5303{
5304    if (targetFrame)
5305        targetFrame->editor()->confirmCompositionWithoutDisturbingSelection();
5306
5307    if (HIMC hInputContext = getIMMContext()) {
5308        IMMDict::dict().notifyIME(hInputContext, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
5309        releaseIMMContext(hInputContext);
5310    }
5311}
5312
5313void WebView::updateSelectionForIME()
5314{
5315    Frame* targetFrame = m_page->focusController()->focusedOrMainFrame();
5316    if (!targetFrame || !targetFrame->editor()->hasComposition())
5317        return;
5318
5319    if (targetFrame->editor()->ignoreCompositionSelectionChange())
5320        return;
5321
5322    unsigned start;
5323    unsigned end;
5324    if (!targetFrame->editor()->getCompositionSelection(start, end))
5325        resetIME(targetFrame);
5326}
5327
5328void WebView::setInputMethodState(bool enabled)
5329{
5330    IMMDict::dict().associateContextEx(m_viewWindow, 0, enabled ? IACE_DEFAULT : 0);
5331}
5332
5333void WebView::selectionChanged()
5334{
5335    updateSelectionForIME();
5336}
5337
5338bool WebView::onIMEStartComposition()
5339{
5340    LOG(TextInput, "onIMEStartComposition");
5341    m_inIMEComposition++;
5342    Frame* targetFrame = m_page->focusController()->focusedOrMainFrame();
5343    if (!targetFrame)
5344        return true;
5345
5346    HIMC hInputContext = getIMMContext();
5347    prepareCandidateWindow(targetFrame, hInputContext);
5348    releaseIMMContext(hInputContext);
5349    return true;
5350}
5351
5352static bool getCompositionString(HIMC hInputContext, DWORD type, String& result)
5353{
5354    int compositionLength = IMMDict::dict().getCompositionString(hInputContext, type, 0, 0);
5355    if (compositionLength <= 0)
5356        return false;
5357    Vector<UChar> compositionBuffer(compositionLength / 2);
5358    compositionLength = IMMDict::dict().getCompositionString(hInputContext, type, (LPVOID)compositionBuffer.data(), compositionLength);
5359    result = String(compositionBuffer.data(), compositionLength / 2);
5360    ASSERT(!compositionLength || compositionBuffer[0]);
5361    ASSERT(!compositionLength || compositionBuffer[compositionLength / 2 - 1]);
5362    return true;
5363}
5364
5365static void compositionToUnderlines(const Vector<DWORD>& clauses, const Vector<BYTE>& attributes, Vector<CompositionUnderline>& underlines)
5366{
5367    if (clauses.isEmpty()) {
5368        underlines.clear();
5369        return;
5370    }
5371
5372    const size_t numBoundaries = clauses.size() - 1;
5373    underlines.resize(numBoundaries);
5374    for (unsigned i = 0; i < numBoundaries; i++) {
5375        underlines[i].startOffset = clauses[i];
5376        underlines[i].endOffset = clauses[i + 1];
5377        BYTE attribute = attributes[clauses[i]];
5378        underlines[i].thick = attribute == ATTR_TARGET_CONVERTED || attribute == ATTR_TARGET_NOTCONVERTED;
5379        underlines[i].color = Color(0,0,0);
5380    }
5381}
5382
5383#if !LOG_DISABLED
5384#define APPEND_ARGUMENT_NAME(name) \
5385    if (lparam & name) { \
5386        if (needsComma) \
5387            result += ", "; \
5388            result += #name; \
5389        needsComma = true; \
5390    }
5391
5392static String imeCompositionArgumentNames(LPARAM lparam)
5393{
5394    String result;
5395    bool needsComma = false;
5396    if (lparam & GCS_COMPATTR) {
5397        result = "GCS_COMPATTR";
5398        needsComma = true;
5399    }
5400    APPEND_ARGUMENT_NAME(GCS_COMPCLAUSE);
5401    APPEND_ARGUMENT_NAME(GCS_COMPREADSTR);
5402    APPEND_ARGUMENT_NAME(GCS_COMPREADATTR);
5403    APPEND_ARGUMENT_NAME(GCS_COMPREADCLAUSE);
5404    APPEND_ARGUMENT_NAME(GCS_COMPSTR);
5405    APPEND_ARGUMENT_NAME(GCS_CURSORPOS);
5406    APPEND_ARGUMENT_NAME(GCS_DELTASTART);
5407    APPEND_ARGUMENT_NAME(GCS_RESULTCLAUSE);
5408    APPEND_ARGUMENT_NAME(GCS_RESULTREADCLAUSE);
5409    APPEND_ARGUMENT_NAME(GCS_RESULTREADSTR);
5410    APPEND_ARGUMENT_NAME(GCS_RESULTSTR);
5411    APPEND_ARGUMENT_NAME(CS_INSERTCHAR);
5412    APPEND_ARGUMENT_NAME(CS_NOMOVECARET);
5413
5414    return result;
5415}
5416
5417static String imeNotificationName(WPARAM wparam)
5418{
5419    switch (wparam) {
5420    case IMN_CHANGECANDIDATE:
5421        return "IMN_CHANGECANDIDATE";
5422    case IMN_CLOSECANDIDATE:
5423        return "IMN_CLOSECANDIDATE";
5424    case IMN_CLOSESTATUSWINDOW:
5425        return "IMN_CLOSESTATUSWINDOW";
5426    case IMN_GUIDELINE:
5427        return "IMN_GUIDELINE";
5428    case IMN_OPENCANDIDATE:
5429        return "IMN_OPENCANDIDATE";
5430    case IMN_OPENSTATUSWINDOW:
5431        return "IMN_OPENSTATUSWINDOW";
5432    case IMN_SETCANDIDATEPOS:
5433        return "IMN_SETCANDIDATEPOS";
5434    case IMN_SETCOMPOSITIONFONT:
5435        return "IMN_SETCOMPOSITIONFONT";
5436    case IMN_SETCOMPOSITIONWINDOW:
5437        return "IMN_SETCOMPOSITIONWINDOW";
5438    case IMN_SETCONVERSIONMODE:
5439        return "IMN_SETCONVERSIONMODE";
5440    case IMN_SETOPENSTATUS:
5441        return "IMN_SETOPENSTATUS";
5442    case IMN_SETSENTENCEMODE:
5443        return "IMN_SETSENTENCEMODE";
5444    case IMN_SETSTATUSWINDOWPOS:
5445        return "IMN_SETSTATUSWINDOWPOS";
5446    default:
5447        return "Unknown (" + String::number(wparam) + ")";
5448    }
5449}
5450
5451static String imeRequestName(WPARAM wparam)
5452{
5453    switch (wparam) {
5454    case IMR_CANDIDATEWINDOW:
5455        return "IMR_CANDIDATEWINDOW";
5456    case IMR_COMPOSITIONFONT:
5457        return "IMR_COMPOSITIONFONT";
5458    case IMR_COMPOSITIONWINDOW:
5459        return "IMR_COMPOSITIONWINDOW";
5460    case IMR_CONFIRMRECONVERTSTRING:
5461        return "IMR_CONFIRMRECONVERTSTRING";
5462    case IMR_DOCUMENTFEED:
5463        return "IMR_DOCUMENTFEED";
5464    case IMR_QUERYCHARPOSITION:
5465        return "IMR_QUERYCHARPOSITION";
5466    case IMR_RECONVERTSTRING:
5467        return "IMR_RECONVERTSTRING";
5468    default:
5469        return "Unknown (" + String::number(wparam) + ")";
5470    }
5471}
5472#endif
5473
5474bool WebView::onIMEComposition(LPARAM lparam)
5475{
5476    LOG(TextInput, "onIMEComposition %s", imeCompositionArgumentNames(lparam).latin1().data());
5477    HIMC hInputContext = getIMMContext();
5478    if (!hInputContext)
5479        return true;
5480
5481    Frame* targetFrame = m_page->focusController()->focusedOrMainFrame();
5482    if (!targetFrame || !targetFrame->editor()->canEdit())
5483        return true;
5484
5485    prepareCandidateWindow(targetFrame, hInputContext);
5486
5487    if (lparam & GCS_RESULTSTR || !lparam) {
5488        String compositionString;
5489        if (!getCompositionString(hInputContext, GCS_RESULTSTR, compositionString) && lparam)
5490            return true;
5491
5492        targetFrame->editor()->confirmComposition(compositionString);
5493    } else {
5494        String compositionString;
5495        if (!getCompositionString(hInputContext, GCS_COMPSTR, compositionString))
5496            return true;
5497
5498        // Composition string attributes
5499        int numAttributes = IMMDict::dict().getCompositionString(hInputContext, GCS_COMPATTR, 0, 0);
5500        Vector<BYTE> attributes(numAttributes);
5501        IMMDict::dict().getCompositionString(hInputContext, GCS_COMPATTR, attributes.data(), numAttributes);
5502
5503        // Get clauses
5504        int numClauses = IMMDict::dict().getCompositionString(hInputContext, GCS_COMPCLAUSE, 0, 0);
5505        Vector<DWORD> clauses(numClauses / sizeof(DWORD));
5506        IMMDict::dict().getCompositionString(hInputContext, GCS_COMPCLAUSE, clauses.data(), numClauses);
5507
5508        Vector<CompositionUnderline> underlines;
5509        compositionToUnderlines(clauses, attributes, underlines);
5510
5511        int cursorPosition = LOWORD(IMMDict::dict().getCompositionString(hInputContext, GCS_CURSORPOS, 0, 0));
5512
5513        targetFrame->editor()->setComposition(compositionString, underlines, cursorPosition, 0);
5514    }
5515
5516    return true;
5517}
5518
5519bool WebView::onIMEEndComposition()
5520{
5521    LOG(TextInput, "onIMEEndComposition");
5522    // If the composition hasn't been confirmed yet, it needs to be cancelled.
5523    // This happens after deleting the last character from inline input hole.
5524    Frame* targetFrame = m_page->focusController()->focusedOrMainFrame();
5525    if (targetFrame && targetFrame->editor()->hasComposition())
5526        targetFrame->editor()->confirmComposition(String());
5527
5528    if (m_inIMEComposition)
5529        m_inIMEComposition--;
5530
5531    return true;
5532}
5533
5534bool WebView::onIMEChar(WPARAM wparam, LPARAM lparam)
5535{
5536    UNUSED_PARAM(wparam);
5537    UNUSED_PARAM(lparam);
5538    LOG(TextInput, "onIMEChar U+%04X %08X", wparam, lparam);
5539    return true;
5540}
5541
5542bool WebView::onIMENotify(WPARAM wparam, LPARAM, LRESULT*)
5543{
5544    UNUSED_PARAM(wparam);
5545    LOG(TextInput, "onIMENotify %s", imeNotificationName(wparam).latin1().data());
5546    return false;
5547}
5548
5549LRESULT WebView::onIMERequestCharPosition(Frame* targetFrame, IMECHARPOSITION* charPos)
5550{
5551    if (charPos->dwCharPos && !targetFrame->editor()->hasComposition())
5552        return 0;
5553    IntRect caret;
5554    if (RefPtr<Range> range = targetFrame->editor()->hasComposition() ? targetFrame->editor()->compositionRange() : targetFrame->selection()->selection().toNormalizedRange()) {
5555        ExceptionCode ec = 0;
5556        RefPtr<Range> tempRange = range->cloneRange(ec);
5557        tempRange->setStart(tempRange->startContainer(ec), tempRange->startOffset(ec) + charPos->dwCharPos, ec);
5558        caret = targetFrame->editor()->firstRectForRange(tempRange.get());
5559    }
5560    caret = targetFrame->view()->contentsToWindow(caret);
5561    charPos->pt.x = caret.x();
5562    charPos->pt.y = caret.y();
5563    ::ClientToScreen(m_viewWindow, &charPos->pt);
5564    charPos->cLineHeight = caret.height();
5565    ::GetWindowRect(m_viewWindow, &charPos->rcDocument);
5566    return true;
5567}
5568
5569LRESULT WebView::onIMERequestReconvertString(Frame* targetFrame, RECONVERTSTRING* reconvertString)
5570{
5571    RefPtr<Range> selectedRange = targetFrame->selection()->toNormalizedRange();
5572    String text = selectedRange->text();
5573    if (!reconvertString)
5574        return sizeof(RECONVERTSTRING) + text.length() * sizeof(UChar);
5575
5576    unsigned totalSize = sizeof(RECONVERTSTRING) + text.length() * sizeof(UChar);
5577    if (totalSize > reconvertString->dwSize)
5578        return 0;
5579    reconvertString->dwCompStrLen = text.length();
5580    reconvertString->dwStrLen = text.length();
5581    reconvertString->dwTargetStrLen = text.length();
5582    reconvertString->dwStrOffset = sizeof(RECONVERTSTRING);
5583    memcpy(reconvertString + 1, text.characters(), text.length() * sizeof(UChar));
5584    return totalSize;
5585}
5586
5587LRESULT WebView::onIMERequest(WPARAM request, LPARAM data)
5588{
5589    LOG(TextInput, "onIMERequest %s", imeRequestName(request).latin1().data());
5590    Frame* targetFrame = m_page->focusController()->focusedOrMainFrame();
5591    if (!targetFrame || !targetFrame->editor()->canEdit())
5592        return 0;
5593
5594    switch (request) {
5595        case IMR_RECONVERTSTRING:
5596            return onIMERequestReconvertString(targetFrame, (RECONVERTSTRING*)data);
5597
5598        case IMR_QUERYCHARPOSITION:
5599            return onIMERequestCharPosition(targetFrame, (IMECHARPOSITION*)data);
5600    }
5601    return 0;
5602}
5603
5604bool WebView::onIMESelect(WPARAM wparam, LPARAM lparam)
5605{
5606    UNUSED_PARAM(wparam);
5607    UNUSED_PARAM(lparam);
5608    LOG(TextInput, "onIMESelect locale %ld %s", lparam, wparam ? "select" : "deselect");
5609    return false;
5610}
5611
5612bool WebView::onIMESetContext(WPARAM wparam, LPARAM)
5613{
5614    LOG(TextInput, "onIMESetContext %s", wparam ? "active" : "inactive");
5615    return false;
5616}
5617
5618HRESULT STDMETHODCALLTYPE WebView::inspector(IWebInspector** inspector)
5619{
5620    if (!m_webInspector)
5621        m_webInspector.adoptRef(WebInspector::createInstance(this));
5622
5623    return m_webInspector.copyRefTo(inspector);
5624}
5625
5626HRESULT STDMETHODCALLTYPE WebView::windowAncestryDidChange()
5627{
5628    HWND newParent;
5629    if (m_viewWindow)
5630        newParent = findTopLevelParent(m_hostWindow);
5631    else {
5632        // There's no point in tracking active state changes of our parent window if we don't have
5633        // a window ourselves.
5634        newParent = 0;
5635    }
5636
5637    if (newParent == m_topLevelParent)
5638        return S_OK;
5639
5640    if (m_topLevelParent)
5641        WindowMessageBroadcaster::removeListener(m_topLevelParent, this);
5642
5643    m_topLevelParent = newParent;
5644
5645    if (m_topLevelParent)
5646        WindowMessageBroadcaster::addListener(m_topLevelParent, this);
5647
5648    updateActiveState();
5649
5650    return S_OK;
5651}
5652
5653HRESULT STDMETHODCALLTYPE WebView::paintDocumentRectToContext(
5654    /* [in] */ RECT rect,
5655    /* [in] */ OLE_HANDLE deviceContext)
5656{
5657    if (!deviceContext)
5658        return E_POINTER;
5659
5660    if (!m_mainFrame)
5661        return E_FAIL;
5662
5663    return m_mainFrame->paintDocumentRectToContext(rect, deviceContext);
5664}
5665
5666HRESULT STDMETHODCALLTYPE WebView::paintScrollViewRectToContextAtPoint(
5667    /* [in] */ RECT rect,
5668    /* [in] */ POINT pt,
5669    /* [in] */ OLE_HANDLE deviceContext)
5670{
5671    if (!deviceContext)
5672        return E_POINTER;
5673
5674    if (!m_mainFrame)
5675        return E_FAIL;
5676
5677    return m_mainFrame->paintScrollViewRectToContextAtPoint(rect, pt, deviceContext);
5678}
5679
5680HRESULT STDMETHODCALLTYPE WebView::reportException(
5681    /* [in] */ JSContextRef context,
5682    /* [in] */ JSValueRef exception)
5683{
5684    if (!context || !exception)
5685        return E_FAIL;
5686
5687    JSLock lock(JSC::SilenceAssertionsOnly);
5688    JSC::ExecState* execState = toJS(context);
5689
5690    // Make sure the context has a DOMWindow global object, otherwise this context didn't originate from a WebView.
5691    if (!toJSDOMWindow(execState->lexicalGlobalObject()))
5692        return E_FAIL;
5693
5694    WebCore::reportException(execState, toJS(execState, exception));
5695    return S_OK;
5696}
5697
5698HRESULT STDMETHODCALLTYPE WebView::elementFromJS(
5699    /* [in] */ JSContextRef context,
5700    /* [in] */ JSValueRef nodeObject,
5701    /* [retval][out] */ IDOMElement **element)
5702{
5703    if (!element)
5704        return E_POINTER;
5705
5706    *element = 0;
5707
5708    if (!context)
5709        return E_FAIL;
5710
5711    if (!nodeObject)
5712        return E_FAIL;
5713
5714    JSLock lock(JSC::SilenceAssertionsOnly);
5715    Element* elt = toElement(toJS(toJS(context), nodeObject));
5716    if (!elt)
5717        return E_FAIL;
5718
5719    *element = DOMElement::createInstance(elt);
5720    return S_OK;
5721}
5722
5723HRESULT STDMETHODCALLTYPE WebView::setCustomHTMLTokenizerTimeDelay(
5724    /* [in] */ double timeDelay)
5725{
5726    if (!m_page)
5727        return E_FAIL;
5728
5729    m_page->setCustomHTMLTokenizerTimeDelay(timeDelay);
5730    return S_OK;
5731}
5732
5733HRESULT STDMETHODCALLTYPE WebView::setCustomHTMLTokenizerChunkSize(
5734    /* [in] */ int chunkSize)
5735{
5736    if (!m_page)
5737        return E_FAIL;
5738
5739    m_page->setCustomHTMLTokenizerChunkSize(chunkSize);
5740    return S_OK;
5741}
5742
5743HRESULT STDMETHODCALLTYPE WebView::backingStore(
5744    /* [out, retval] */ OLE_HANDLE* hBitmap)
5745{
5746    if (!hBitmap)
5747        return E_POINTER;
5748    if (!m_backingStoreBitmap)
5749        return E_FAIL;
5750    *hBitmap = reinterpret_cast<OLE_HANDLE>(m_backingStoreBitmap->handle());
5751    return S_OK;
5752}
5753
5754HRESULT STDMETHODCALLTYPE WebView::setTransparent(BOOL transparent)
5755{
5756    if (m_transparent == !!transparent)
5757        return S_OK;
5758
5759    m_transparent = transparent;
5760    m_mainFrame->updateBackground();
5761    return S_OK;
5762}
5763
5764HRESULT STDMETHODCALLTYPE WebView::transparent(BOOL* transparent)
5765{
5766    if (!transparent)
5767        return E_POINTER;
5768
5769    *transparent = this->transparent() ? TRUE : FALSE;
5770    return S_OK;
5771}
5772
5773HRESULT STDMETHODCALLTYPE WebView::setCookieEnabled(BOOL enable)
5774{
5775    if (!m_page)
5776        return E_FAIL;
5777
5778    m_page->setCookieEnabled(enable);
5779    return S_OK;
5780}
5781
5782HRESULT STDMETHODCALLTYPE WebView::cookieEnabled(BOOL* enabled)
5783{
5784    if (!enabled)
5785        return E_POINTER;
5786
5787    if (!m_page)
5788        return E_FAIL;
5789
5790    *enabled = m_page->cookieEnabled();
5791    return S_OK;
5792}
5793
5794HRESULT STDMETHODCALLTYPE WebView::setMediaVolume(float volume)
5795{
5796    if (!m_page)
5797        return E_FAIL;
5798
5799    m_page->setMediaVolume(volume);
5800    return S_OK;
5801}
5802
5803HRESULT STDMETHODCALLTYPE WebView::mediaVolume(float* volume)
5804{
5805    if (!volume)
5806        return E_POINTER;
5807
5808    if (!m_page)
5809        return E_FAIL;
5810
5811    *volume = m_page->mediaVolume();
5812    return S_OK;
5813}
5814
5815HRESULT STDMETHODCALLTYPE WebView::setDefersCallbacks(BOOL defersCallbacks)
5816{
5817    if (!m_page)
5818        return E_FAIL;
5819
5820    m_page->setDefersLoading(defersCallbacks);
5821    return S_OK;
5822}
5823
5824HRESULT STDMETHODCALLTYPE WebView::defersCallbacks(BOOL* defersCallbacks)
5825{
5826    if (!defersCallbacks)
5827        return E_POINTER;
5828
5829    if (!m_page)
5830        return E_FAIL;
5831
5832    *defersCallbacks = m_page->defersLoading();
5833    return S_OK;
5834}
5835
5836HRESULT STDMETHODCALLTYPE WebView::globalHistoryItem(IWebHistoryItem** item)
5837{
5838    if (!item)
5839        return E_POINTER;
5840
5841    if (!m_page)
5842        return E_FAIL;
5843
5844    if (!m_globalHistoryItem) {
5845        *item = 0;
5846        return S_OK;
5847    }
5848
5849    *item = WebHistoryItem::createInstance(m_globalHistoryItem);
5850    return S_OK;
5851}
5852
5853HRESULT STDMETHODCALLTYPE WebView::setAlwaysUsesComplexTextCodePath(BOOL complex)
5854{
5855    WebCoreSetAlwaysUsesComplexTextCodePath(complex);
5856
5857    return S_OK;
5858}
5859
5860HRESULT STDMETHODCALLTYPE WebView::alwaysUsesComplexTextCodePath(BOOL* complex)
5861{
5862    if (!complex)
5863        return E_POINTER;
5864
5865    *complex = WebCoreAlwaysUsesComplexTextCodePath();
5866    return S_OK;
5867}
5868
5869HRESULT STDMETHODCALLTYPE WebView::registerEmbeddedViewMIMEType(BSTR mimeType)
5870{
5871    if (!mimeType)
5872        return E_POINTER;
5873
5874    if (!m_embeddedViewMIMETypes)
5875        m_embeddedViewMIMETypes.set(new HashSet<String>);
5876
5877    m_embeddedViewMIMETypes->add(String(mimeType, ::SysStringLen(mimeType)));
5878    return S_OK;
5879}
5880
5881bool WebView::shouldUseEmbeddedView(const WTF::String& mimeType) const
5882{
5883    if (!m_embeddedViewMIMETypes)
5884        return false;
5885
5886    return m_embeddedViewMIMETypes->contains(mimeType);
5887}
5888
5889bool WebView::onGetObject(WPARAM wParam, LPARAM lParam, LRESULT& lResult) const
5890{
5891    lResult = 0;
5892
5893    if (lParam != OBJID_CLIENT)
5894        return false;
5895
5896    AXObjectCache::enableAccessibility();
5897
5898    // Get the accessible object for the top-level frame.
5899    WebFrame* mainFrameImpl = topLevelFrame();
5900    if (!mainFrameImpl)
5901        return false;
5902
5903    COMPtr<IAccessible> accessible = mainFrameImpl->accessible();
5904    if (!accessible)
5905        return false;
5906
5907    if (!accessibilityLib) {
5908        if (!(accessibilityLib = ::LoadLibraryW(L"oleacc.dll")))
5909            return false;
5910    }
5911
5912    static LPFNLRESULTFROMOBJECT procPtr = reinterpret_cast<LPFNLRESULTFROMOBJECT>(::GetProcAddress(accessibilityLib, "LresultFromObject"));
5913    if (!procPtr)
5914        return false;
5915
5916    // LresultFromObject returns a reference to the accessible object, stored
5917    // in an LRESULT. If this call is not successful, Windows will handle the
5918    // request through DefWindowProc.
5919    return SUCCEEDED(lResult = procPtr(__uuidof(IAccessible), wParam, accessible.get()));
5920}
5921
5922STDMETHODIMP WebView::AccessibleObjectFromWindow(HWND hwnd, DWORD objectID, REFIID riid, void** ppObject)
5923{
5924    ASSERT(accessibilityLib);
5925    static LPFNACCESSIBLEOBJECTFROMWINDOW procPtr = reinterpret_cast<LPFNACCESSIBLEOBJECTFROMWINDOW>(::GetProcAddress(accessibilityLib, "AccessibleObjectFromWindow"));
5926    if (!procPtr)
5927        return E_FAIL;
5928    return procPtr(hwnd, objectID, riid, ppObject);
5929}
5930
5931HRESULT WebView::setMemoryCacheDelegateCallsEnabled(BOOL enabled)
5932{
5933    m_page->setMemoryCacheClientCallsEnabled(enabled);
5934    return S_OK;
5935}
5936
5937HRESULT WebView::setJavaScriptURLsAreAllowed(BOOL areAllowed)
5938{
5939    m_page->setJavaScriptURLsAreAllowed(areAllowed);
5940    return S_OK;
5941}
5942
5943HRESULT WebView::setCanStartPlugins(BOOL canStartPlugins)
5944{
5945    m_page->setCanStartMedia(canStartPlugins);
5946    return S_OK;
5947}
5948
5949static String toString(BSTR bstr)
5950{
5951    return String(bstr, SysStringLen(bstr));
5952}
5953
5954static KURL toKURL(BSTR bstr)
5955{
5956    return KURL(KURL(), toString(bstr));
5957}
5958
5959void WebView::enterFullscreenForNode(Node* node)
5960{
5961    if (!node->hasTagName(HTMLNames::videoTag))
5962        return;
5963
5964#if ENABLE(VIDEO)
5965    HTMLMediaElement* videoElement = static_cast<HTMLMediaElement*>(node);
5966
5967    if (m_fullscreenController) {
5968        if (m_fullscreenController->mediaElement() == videoElement) {
5969            // The backend may just warn us that the underlaying plaftormMovie()
5970            // has changed. Just force an update.
5971            m_fullscreenController->setMediaElement(videoElement);
5972            return; // No more to do.
5973        }
5974
5975        // First exit Fullscreen for the old mediaElement.
5976        m_fullscreenController->mediaElement()->exitFullscreen();
5977        // This previous call has to trigger exitFullscreen,
5978        // which has to clear m_fullscreenController.
5979        ASSERT(!m_fullscreenController);
5980    }
5981
5982    m_fullscreenController = new FullscreenVideoController;
5983    m_fullscreenController->setMediaElement(videoElement);
5984    m_fullscreenController->enterFullscreen();
5985#endif
5986}
5987
5988void WebView::exitFullscreen()
5989{
5990#if ENABLE(VIDEO)
5991    if (m_fullscreenController)
5992        m_fullscreenController->exitFullscreen();
5993    m_fullscreenController = 0;
5994#endif
5995}
5996
5997static PassOwnPtr<Vector<String> > toStringVector(unsigned patternsCount, BSTR* patterns)
5998{
5999    // Convert the patterns into a Vector.
6000    if (patternsCount == 0)
6001        return 0;
6002    Vector<String>* patternsVector = new Vector<String>;
6003    for (unsigned i = 0; i < patternsCount; ++i)
6004        patternsVector->append(toString(patterns[i]));
6005    return patternsVector;
6006}
6007
6008HRESULT WebView::addUserScriptToGroup(BSTR groupName, IWebScriptWorld* iWorld, BSTR source, BSTR url,
6009                                      unsigned whitelistCount, BSTR* whitelist,
6010                                      unsigned blacklistCount, BSTR* blacklist,
6011                                      WebUserScriptInjectionTime injectionTime)
6012{
6013    COMPtr<WebScriptWorld> world(Query, iWorld);
6014    if (!world)
6015        return E_POINTER;
6016
6017    String group = toString(groupName);
6018    if (group.isEmpty())
6019        return E_INVALIDARG;
6020
6021    PageGroup* pageGroup = PageGroup::pageGroup(group);
6022    ASSERT(pageGroup);
6023    if (!pageGroup)
6024        return E_FAIL;
6025
6026    pageGroup->addUserScriptToWorld(world->world(), toString(source), toKURL(url),
6027                                    toStringVector(whitelistCount, whitelist), toStringVector(blacklistCount, blacklist),
6028                                    injectionTime == WebInjectAtDocumentStart ? InjectAtDocumentStart : InjectAtDocumentEnd,
6029                                    InjectInAllFrames);
6030
6031    return S_OK;
6032}
6033
6034HRESULT WebView::addUserStyleSheetToGroup(BSTR groupName, IWebScriptWorld* iWorld, BSTR source, BSTR url,
6035                                          unsigned whitelistCount, BSTR* whitelist,
6036                                          unsigned blacklistCount, BSTR* blacklist)
6037{
6038    COMPtr<WebScriptWorld> world(Query, iWorld);
6039    if (!world)
6040        return E_POINTER;
6041
6042    String group = toString(groupName);
6043    if (group.isEmpty())
6044        return E_INVALIDARG;
6045
6046    PageGroup* pageGroup = PageGroup::pageGroup(group);
6047    ASSERT(pageGroup);
6048    if (!pageGroup)
6049        return E_FAIL;
6050
6051    pageGroup->addUserStyleSheetToWorld(world->world(), toString(source), toKURL(url),
6052                                        toStringVector(whitelistCount, whitelist), toStringVector(blacklistCount, blacklist),
6053                                        InjectInAllFrames);
6054
6055    return S_OK;
6056}
6057
6058HRESULT WebView::removeUserScriptFromGroup(BSTR groupName, IWebScriptWorld* iWorld, BSTR url)
6059{
6060    COMPtr<WebScriptWorld> world(Query, iWorld);
6061    if (!world)
6062        return E_POINTER;
6063
6064    String group = toString(groupName);
6065    if (group.isEmpty())
6066        return E_INVALIDARG;
6067
6068    PageGroup* pageGroup = PageGroup::pageGroup(group);
6069    ASSERT(pageGroup);
6070    if (!pageGroup)
6071        return E_FAIL;
6072
6073    pageGroup->removeUserScriptFromWorld(world->world(), toKURL(url));
6074
6075    return S_OK;
6076}
6077
6078HRESULT WebView::removeUserStyleSheetFromGroup(BSTR groupName, IWebScriptWorld* iWorld, BSTR url)
6079{
6080    COMPtr<WebScriptWorld> world(Query, iWorld);
6081    if (!world)
6082        return E_POINTER;
6083
6084    String group = toString(groupName);
6085    if (group.isEmpty())
6086        return E_INVALIDARG;
6087
6088    PageGroup* pageGroup = PageGroup::pageGroup(group);
6089    ASSERT(pageGroup);
6090    if (!pageGroup)
6091        return E_FAIL;
6092
6093    pageGroup->removeUserStyleSheetFromWorld(world->world(), toKURL(url));
6094
6095    return S_OK;
6096}
6097
6098HRESULT WebView::removeUserScriptsFromGroup(BSTR groupName, IWebScriptWorld* iWorld)
6099{
6100    COMPtr<WebScriptWorld> world(Query, iWorld);
6101    if (!world)
6102        return E_POINTER;
6103
6104    String group = toString(groupName);
6105    if (group.isEmpty())
6106        return E_INVALIDARG;
6107
6108    PageGroup* pageGroup = PageGroup::pageGroup(group);
6109    ASSERT(pageGroup);
6110    if (!pageGroup)
6111        return E_FAIL;
6112
6113    pageGroup->removeUserScriptsFromWorld(world->world());
6114    return S_OK;
6115}
6116
6117HRESULT WebView::removeUserStyleSheetsFromGroup(BSTR groupName, IWebScriptWorld* iWorld)
6118{
6119    COMPtr<WebScriptWorld> world(Query, iWorld);
6120    if (!world)
6121        return E_POINTER;
6122
6123    String group = toString(groupName);
6124    if (group.isEmpty())
6125        return E_INVALIDARG;
6126
6127    PageGroup* pageGroup = PageGroup::pageGroup(group);
6128    ASSERT(pageGroup);
6129    if (!pageGroup)
6130        return E_FAIL;
6131
6132    pageGroup->removeUserStyleSheetsFromWorld(world->world());
6133    return S_OK;
6134}
6135
6136HRESULT WebView::removeAllUserContentFromGroup(BSTR groupName)
6137{
6138    String group = toString(groupName);
6139    if (group.isEmpty())
6140        return E_INVALIDARG;
6141
6142    PageGroup* pageGroup = PageGroup::pageGroup(group);
6143    ASSERT(pageGroup);
6144    if (!pageGroup)
6145        return E_FAIL;
6146
6147    pageGroup->removeAllUserContent();
6148    return S_OK;
6149}
6150
6151HRESULT WebView::invalidateBackingStore(const RECT* rect)
6152{
6153    if (!IsWindow(m_viewWindow))
6154        return S_OK;
6155
6156    RECT clientRect;
6157    if (!GetClientRect(m_viewWindow, &clientRect))
6158        return E_FAIL;
6159
6160    RECT rectToInvalidate;
6161    if (!rect)
6162        rectToInvalidate = clientRect;
6163    else if (!IntersectRect(&rectToInvalidate, &clientRect, rect))
6164        return S_OK;
6165
6166    repaint(rectToInvalidate, true);
6167    return S_OK;
6168}
6169
6170HRESULT WebView::addOriginAccessWhitelistEntry(BSTR sourceOrigin, BSTR destinationProtocol, BSTR destinationHost, BOOL allowDestinationSubdomains)
6171{
6172    SecurityOrigin::addOriginAccessWhitelistEntry(*SecurityOrigin::createFromString(String(sourceOrigin, SysStringLen(sourceOrigin))), String(destinationProtocol, SysStringLen(destinationProtocol)), String(destinationHost, SysStringLen(destinationHost)), allowDestinationSubdomains);
6173    return S_OK;
6174}
6175
6176HRESULT WebView::removeOriginAccessWhitelistEntry(BSTR sourceOrigin, BSTR destinationProtocol, BSTR destinationHost, BOOL allowDestinationSubdomains)
6177{
6178    SecurityOrigin::removeOriginAccessWhitelistEntry(*SecurityOrigin::createFromString(String(sourceOrigin, SysStringLen(sourceOrigin))), String(destinationProtocol, SysStringLen(destinationProtocol)), String(destinationHost, SysStringLen(destinationHost)), allowDestinationSubdomains);
6179    return S_OK;
6180}
6181
6182HRESULT WebView::resetOriginAccessWhitelists()
6183{
6184    SecurityOrigin::resetOriginAccessWhitelists();
6185    return S_OK;
6186}
6187
6188HRESULT WebView::setHistoryDelegate(IWebHistoryDelegate* historyDelegate)
6189{
6190    m_historyDelegate = historyDelegate;
6191    return S_OK;
6192}
6193
6194HRESULT WebView::historyDelegate(IWebHistoryDelegate** historyDelegate)
6195{
6196    if (!historyDelegate)
6197        return E_POINTER;
6198
6199    return m_historyDelegate.copyRefTo(historyDelegate);
6200}
6201
6202HRESULT WebView::addVisitedLinks(BSTR* visitedURLs, unsigned visitedURLCount)
6203{
6204    PageGroup& group = core(this)->group();
6205
6206    for (unsigned i = 0; i < visitedURLCount; ++i) {
6207        BSTR url = visitedURLs[i];
6208        unsigned length = SysStringLen(url);
6209        group.addVisitedLink(url, length);
6210    }
6211
6212    return S_OK;
6213}
6214
6215void WebView::downloadURL(const KURL& url)
6216{
6217    // It's the delegate's job to ref the WebDownload to keep it alive - otherwise it will be
6218    // destroyed when this function returns.
6219    COMPtr<WebDownload> download(AdoptCOM, WebDownload::createInstance(url, m_downloadDelegate.get()));
6220    download->start();
6221}
6222
6223#if USE(ACCELERATED_COMPOSITING)
6224void WebView::setRootChildLayer(GraphicsLayer* layer)
6225{
6226    setAcceleratedCompositing(layer ? true : false);
6227    if (!m_backingLayer)
6228        return;
6229    m_backingLayer->addChild(layer);
6230}
6231
6232void WebView::flushPendingGraphicsLayerChangesSoon()
6233{
6234    if (!m_layerTreeHost)
6235        return;
6236    m_layerTreeHost->flushPendingGraphicsLayerChangesSoon();
6237}
6238
6239void WebView::setAcceleratedCompositing(bool accelerated)
6240{
6241    if (m_isAcceleratedCompositing == accelerated || !CACFLayerTreeHost::acceleratedCompositingAvailable())
6242        return;
6243
6244    if (accelerated) {
6245        m_layerTreeHost = CACFLayerTreeHost::create();
6246        if (m_layerTreeHost) {
6247            m_isAcceleratedCompositing = true;
6248
6249            m_layerTreeHost->setClient(this);
6250            ASSERT(m_viewWindow);
6251            m_layerTreeHost->setWindow(m_viewWindow);
6252
6253            // FIXME: We could perhaps get better performance by never allowing this layer to
6254            // become tiled (or choosing a higher-than-normal tiling threshold).
6255            // <http://webkit.org/b/52603>
6256            m_backingLayer = GraphicsLayer::create(this);
6257            m_backingLayer->setDrawsContent(true);
6258            m_backingLayer->setContentsOpaque(true);
6259            RECT clientRect;
6260            ::GetClientRect(m_viewWindow, &clientRect);
6261            m_backingLayer->setSize(IntRect(clientRect).size());
6262            m_backingLayer->setNeedsDisplay();
6263
6264            m_layerTreeHost->setRootChildLayer(PlatformCALayer::platformCALayer(m_backingLayer->platformLayer()));
6265
6266            // We aren't going to be using our backing store while we're in accelerated compositing
6267            // mode. But don't delete it immediately, in case we switch out of accelerated
6268            // compositing mode soon (e.g., if we're only compositing for a :hover animation).
6269            deleteBackingStoreSoon();
6270        }
6271    } else {
6272        ASSERT(m_layerTreeHost);
6273        m_layerTreeHost->setClient(0);
6274        m_layerTreeHost->setWindow(0);
6275        m_layerTreeHost = 0;
6276        m_backingLayer = 0;
6277        m_isAcceleratedCompositing = false;
6278    }
6279}
6280#endif
6281
6282HRESULT STDMETHODCALLTYPE WebView::setPluginHalterDelegate(IWebPluginHalterDelegate* d)
6283{
6284    m_pluginHalterDelegate = d;
6285    return S_OK;
6286}
6287
6288HRESULT STDMETHODCALLTYPE WebView::pluginHalterDelegate(IWebPluginHalterDelegate** d)
6289{
6290    if (!d)
6291        return E_POINTER;
6292
6293    if (!m_pluginHalterDelegate)
6294        return E_FAIL;
6295
6296    return m_pluginHalterDelegate.copyRefTo(d);
6297}
6298
6299static PluginView* pluginViewForNode(IDOMNode* domNode)
6300{
6301    COMPtr<DOMNode> webKitDOMNode(Query, domNode);
6302    if (!webKitDOMNode)
6303        return 0;
6304
6305    Node* node = webKitDOMNode->node();
6306    if (!node)
6307        return 0;
6308
6309    RenderObject* renderer = node->renderer();
6310    if (!renderer || !renderer->isWidget())
6311        return 0;
6312
6313    Widget* widget = toRenderWidget(renderer)->widget();
6314    if (!widget || !widget->isPluginView())
6315        return 0;
6316
6317    return static_cast<PluginView*>(widget);
6318}
6319
6320HRESULT WebView::isNodeHaltedPlugin(IDOMNode* domNode, BOOL* result)
6321{
6322    if (!domNode || !result)
6323        return E_POINTER;
6324
6325    *result = FALSE;
6326
6327    PluginView* view = pluginViewForNode(domNode);
6328    if (!view)
6329        return E_FAIL;
6330
6331    *result = view->isHalted();
6332    return S_OK;
6333}
6334
6335HRESULT WebView::restartHaltedPluginForNode(IDOMNode* domNode)
6336{
6337    if (!domNode)
6338        return E_POINTER;
6339
6340    PluginView* view = pluginViewForNode(domNode);
6341    if (!view)
6342        return E_FAIL;
6343
6344    view->restart();
6345    return S_OK;
6346}
6347
6348HRESULT WebView::hasPluginForNodeBeenHalted(IDOMNode* domNode, BOOL* result)
6349{
6350    if (!domNode || !result)
6351        return E_POINTER;
6352
6353    *result = FALSE;
6354
6355    PluginView* view = pluginViewForNode(domNode);
6356    if (!view)
6357        return E_FAIL;
6358
6359    *result = view->hasBeenHalted();
6360    return S_OK;
6361}
6362
6363HRESULT WebView::setGeolocationProvider(IWebGeolocationProvider* locationProvider)
6364{
6365    m_geolocationProvider = locationProvider;
6366    return S_OK;
6367}
6368
6369HRESULT WebView::geolocationProvider(IWebGeolocationProvider** locationProvider)
6370{
6371    if (!locationProvider)
6372        return E_POINTER;
6373
6374    if (!m_geolocationProvider)
6375        return E_FAIL;
6376
6377    return m_geolocationProvider.copyRefTo(locationProvider);
6378}
6379
6380HRESULT WebView::geolocationDidChangePosition(IWebGeolocationPosition* position)
6381{
6382#if ENABLE(CLIENT_BASED_GEOLOCATION)
6383    if (!m_page)
6384        return E_FAIL;
6385    m_page->geolocationController()->positionChanged(core(position));
6386    return S_OK;
6387#else
6388    return E_NOTIMPL;
6389#endif
6390}
6391
6392HRESULT WebView::geolocationDidFailWithError(IWebError* error)
6393{
6394#if ENABLE(CLIENT_BASED_GEOLOCATION)
6395    if (!m_page)
6396        return E_FAIL;
6397    if (!error)
6398        return E_POINTER;
6399
6400    BSTR descriptionBSTR;
6401    if (FAILED(error->localizedDescription(&descriptionBSTR)))
6402        return E_FAIL;
6403    String descriptionString(descriptionBSTR, SysStringLen(descriptionBSTR));
6404    SysFreeString(descriptionBSTR);
6405
6406    RefPtr<GeolocationError> geolocationError = GeolocationError::create(GeolocationError::PositionUnavailable, descriptionString);
6407    m_page->geolocationController()->errorOccurred(geolocationError.get());
6408    return S_OK;
6409#else
6410    return E_NOTIMPL;
6411#endif
6412}
6413
6414HRESULT WebView::setDomainRelaxationForbiddenForURLScheme(BOOL forbidden, BSTR scheme)
6415{
6416    SecurityOrigin::setDomainRelaxationForbiddenForURLScheme(forbidden, String(scheme, SysStringLen(scheme)));
6417    return S_OK;
6418}
6419
6420HRESULT WebView::registerURLSchemeAsSecure(BSTR scheme)
6421{
6422    SchemeRegistry::registerURLSchemeAsSecure(toString(scheme));
6423    return S_OK;
6424}
6425
6426HRESULT WebView::nextDisplayIsSynchronous()
6427{
6428    m_nextDisplayIsSynchronous = true;
6429    return S_OK;
6430}
6431
6432#if USE(ACCELERATED_COMPOSITING)
6433void WebView::notifyAnimationStarted(const GraphicsLayer*, double)
6434{
6435    // We never set any animations on our backing layer.
6436    ASSERT_NOT_REACHED();
6437}
6438
6439void WebView::notifySyncRequired(const GraphicsLayer*)
6440{
6441    flushPendingGraphicsLayerChangesSoon();
6442}
6443
6444void WebView::paintContents(const GraphicsLayer*, GraphicsContext& context, GraphicsLayerPaintingPhase, const IntRect& inClip)
6445{
6446    Frame* frame = core(m_mainFrame);
6447    if (!frame)
6448        return;
6449
6450    context.save();
6451    context.clip(inClip);
6452    frame->view()->paint(&context, inClip);
6453    context.restore();
6454}
6455
6456bool WebView::showDebugBorders() const
6457{
6458    return m_page->settings()->showDebugBorders();
6459}
6460
6461bool WebView::showRepaintCounter() const
6462{
6463    return m_page->settings()->showRepaintCounter();
6464}
6465
6466void WebView::flushPendingGraphicsLayerChanges()
6467{
6468    Frame* coreFrame = core(m_mainFrame);
6469    if (!coreFrame)
6470        return;
6471    FrameView* view = coreFrame->view();
6472    if (!view)
6473        return;
6474    if (!m_backingLayer)
6475        return;
6476
6477    view->updateLayoutAndStyleIfNeededRecursive();
6478
6479    // Updating layout might have taken us out of compositing mode.
6480    if (m_backingLayer)
6481        m_backingLayer->syncCompositingStateForThisLayerOnly();
6482
6483    view->syncCompositingStateIncludingSubframes();
6484}
6485
6486#endif
6487
6488class EnumTextMatches : public IEnumTextMatches
6489{
6490    long m_ref;
6491    UINT m_index;
6492    Vector<IntRect> m_rects;
6493public:
6494    EnumTextMatches(Vector<IntRect>* rects) : m_index(0), m_ref(1)
6495    {
6496        m_rects = *rects;
6497    }
6498
6499    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv)
6500    {
6501        if (IsEqualGUID(riid, IID_IUnknown) || IsEqualGUID(riid, IID_IEnumTextMatches)) {
6502            *ppv = this;
6503            AddRef();
6504        }
6505
6506        return *ppv?S_OK:E_NOINTERFACE;
6507    }
6508
6509    virtual ULONG STDMETHODCALLTYPE AddRef()
6510    {
6511        return m_ref++;
6512    }
6513
6514    virtual ULONG STDMETHODCALLTYPE Release()
6515    {
6516        if (m_ref == 1) {
6517            delete this;
6518            return 0;
6519        }
6520        else
6521            return m_ref--;
6522    }
6523
6524    virtual HRESULT STDMETHODCALLTYPE Next(ULONG, RECT* rect, ULONG* pceltFetched)
6525    {
6526        if (m_index < m_rects.size()) {
6527            if (pceltFetched)
6528                *pceltFetched = 1;
6529            *rect = m_rects[m_index];
6530            m_index++;
6531            return S_OK;
6532        }
6533
6534        if (pceltFetched)
6535            *pceltFetched = 0;
6536
6537        return S_FALSE;
6538    }
6539    virtual HRESULT STDMETHODCALLTYPE Skip(ULONG celt)
6540    {
6541        m_index += celt;
6542        return S_OK;
6543    }
6544    virtual HRESULT STDMETHODCALLTYPE Reset(void)
6545    {
6546        m_index = 0;
6547        return S_OK;
6548    }
6549    virtual HRESULT STDMETHODCALLTYPE Clone(IEnumTextMatches**)
6550    {
6551        return E_NOTIMPL;
6552    }
6553};
6554
6555HRESULT createMatchEnumerator(Vector<IntRect>* rects, IEnumTextMatches** matches)
6556{
6557    *matches = new EnumTextMatches(rects);
6558    return (*matches)?S_OK:E_OUTOFMEMORY;
6559}
6560
6561Page* core(IWebView* iWebView)
6562{
6563    Page* page = 0;
6564
6565    COMPtr<WebView> webView;
6566    if (SUCCEEDED(iWebView->QueryInterface(&webView)) && webView)
6567        page = webView->page();
6568
6569    return page;
6570}
6571
6572HRESULT WebView::defaultMinimumTimerInterval(double* interval)
6573{
6574    if (!interval)
6575        return E_POINTER;
6576    *interval = Settings::defaultMinDOMTimerInterval();
6577    return S_OK;
6578}
6579
6580HRESULT WebView::setMinimumTimerInterval(double interval)
6581{
6582    page()->settings()->setMinDOMTimerInterval(interval);
6583    return S_OK;
6584}
6585
6586void WebView::setGlobalHistoryItem(HistoryItem* historyItem)
6587{
6588    m_globalHistoryItem = historyItem;
6589}
6590