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