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