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