RenderTheme does not need to be per-page
[WebKit-https.git] / Source / WebKit / win / WebView.cpp
1 /*
2  * Copyright (C) 2006-2016 Apple, Inc.  All rights reserved.
3  * Copyright (C) 2009, 2010, 2011 Appcelerator, Inc. All rights reserved.
4  * Copyright (C) 2011 Brent Fulgham. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
26  */
27
28 #include "WebView.h"
29
30 #include "BackForwardList.h"
31 #include "COMVariantSetter.h"
32 #include "DOMCoreClasses.h"
33 #include "FullscreenVideoController.h"
34 #include "MarshallingHelpers.h"
35 #include "PluginDatabase.h"
36 #include "PluginView.h"
37 #include "SocketProvider.h"
38 #include "SoftLinking.h"
39 #include "SubframeLoader.h"
40 #include "TextIterator.h"
41 #include "WebApplicationCache.h"
42 #include "WebBackForwardList.h"
43 #include "WebChromeClient.h"
44 #include "WebContextMenuClient.h"
45 #include "WebCoreTextRenderer.h"
46 #include "WebDatabaseManager.h"
47 #include "WebDatabaseProvider.h"
48 #include "WebDocumentLoader.h"
49 #include "WebDownload.h"
50 #include "WebDragClient.h"
51 #include "WebEditorClient.h"
52 #include "WebElementPropertyBag.h"
53 #include "WebFrame.h"
54 #include "WebFrameLoaderClient.h"
55 #include "WebFrameNetworkingContext.h"
56 #include "WebGeolocationClient.h"
57 #include "WebGeolocationPosition.h"
58 #include "WebIconDatabase.h"
59 #include "WebInspector.h"
60 #include "WebInspectorClient.h"
61 #include "WebKit.h"
62 #include "WebKitDLL.h"
63 #include "WebKitLogging.h"
64 #include "WebKitStatisticsPrivate.h"
65 #include "WebKitSystemBits.h"
66 #include "WebKitVersion.h"
67 #include "WebMutableURLRequest.h"
68 #include "WebNotificationCenter.h"
69 #include "WebPlatformStrategies.h"
70 #include "WebPluginInfoProvider.h"
71 #include "WebPreferences.h"
72 #include "WebResourceLoadScheduler.h"
73 #include "WebScriptWorld.h"
74 #include "WebStorageNamespaceProvider.h"
75 #include "WebViewGroup.h"
76 #include "WebVisitedLinkStore.h"
77 #include "resource.h"
78 #include <JavaScriptCore/APICast.h>
79 #include <JavaScriptCore/Exception.h>
80 #include <JavaScriptCore/HeapInlines.h>
81 #include <JavaScriptCore/InitializeThreading.h>
82 #include <JavaScriptCore/JSCJSValue.h>
83 #include <JavaScriptCore/JSLock.h>
84 #include <WebCore/AXObjectCache.h>
85 #include <WebCore/ApplicationCacheStorage.h>
86 #include <WebCore/BString.h>
87 #include <WebCore/BackForwardController.h>
88 #include <WebCore/BitmapInfo.h>
89 #include <WebCore/Chrome.h>
90 #include <WebCore/ContextMenu.h>
91 #include <WebCore/ContextMenuController.h>
92 #include <WebCore/Cursor.h>
93 #include <WebCore/DatabaseManager.h>
94 #include <WebCore/Document.h>
95 #include <WebCore/DocumentMarkerController.h>
96 #include <WebCore/DragController.h>
97 #include <WebCore/DragData.h>
98 #include <WebCore/Editor.h>
99 #include <WebCore/EventHandler.h>
100 #include <WebCore/EventNames.h>
101 #include <WebCore/FileSystem.h>
102 #include <WebCore/FloatQuad.h>
103 #include <WebCore/FocusController.h>
104 #include <WebCore/Font.h>
105 #include <WebCore/FrameLoader.h>
106 #include <WebCore/FrameSelection.h>
107 #include <WebCore/FrameTree.h>
108 #include <WebCore/FrameView.h>
109 #include <WebCore/FrameWin.h>
110 #include <WebCore/FullScreenController.h>
111 #include <WebCore/GDIObjectCounter.h>
112 #include <WebCore/GDIUtilities.h>
113 #include <WebCore/GeolocationController.h>
114 #include <WebCore/GeolocationError.h>
115 #include <WebCore/GraphicsContext.h>
116 #include <WebCore/HTMLNames.h>
117 #include <WebCore/HTMLVideoElement.h>
118 #include <WebCore/HWndDC.h>
119 #include <WebCore/HistoryController.h>
120 #include <WebCore/HistoryItem.h>
121 #include <WebCore/HitTestRequest.h>
122 #include <WebCore/HitTestResult.h>
123 #include <WebCore/IntRect.h>
124 #include <WebCore/JSElement.h>
125 #include <WebCore/KeyboardEvent.h>
126 #include <WebCore/LibWebRTCProvider.h>
127 #include <WebCore/LogInitialization.h>
128 #include <WebCore/Logging.h>
129 #include <WebCore/MIMETypeRegistry.h>
130 #include <WebCore/MainFrame.h>
131 #include <WebCore/MemoryCache.h>
132 #include <WebCore/MemoryRelease.h>
133 #include <WebCore/NotImplemented.h>
134 #include <WebCore/Page.h>
135 #include <WebCore/PageCache.h>
136 #include <WebCore/PageConfiguration.h>
137 #include <WebCore/PageGroup.h>
138 #include <WebCore/PathUtilities.h>
139 #include <WebCore/PlatformKeyboardEvent.h>
140 #include <WebCore/PlatformMouseEvent.h>
141 #include <WebCore/PlatformWheelEvent.h>
142 #include <WebCore/PluginData.h>
143 #include <WebCore/PopupMenu.h>
144 #include <WebCore/PopupMenuWin.h>
145 #include <WebCore/ProgressTracker.h>
146 #include <WebCore/RenderLayer.h>
147 #include <WebCore/RenderTheme.h>
148 #include <WebCore/RenderTreeAsText.h>
149 #include <WebCore/RenderView.h>
150 #include <WebCore/RenderWidget.h>
151 #include <WebCore/ResourceHandle.h>
152 #include <WebCore/ResourceHandleClient.h>
153 #include <WebCore/ResourceRequest.h>
154 #include <WebCore/RuntimeEnabledFeatures.h>
155 #include <WebCore/SchemeRegistry.h>
156 #include <WebCore/ScriptController.h>
157 #include <WebCore/Scrollbar.h>
158 #include <WebCore/ScrollbarTheme.h>
159 #include <WebCore/SecurityOrigin.h>
160 #include <WebCore/SecurityPolicy.h>
161 #include <WebCore/Settings.h>
162 #include <WebCore/SystemInfo.h>
163 #include <WebCore/UserContentController.h>
164 #include <WebCore/UserScript.h>
165 #include <WebCore/UserStyleSheet.h>
166 #include <WebCore/WindowMessageBroadcaster.h>
167 #include <WebCore/WindowsTouch.h>
168 #include <bindings/ScriptValue.h>
169 #include <comdef.h>
170 #include <d2d1.h>
171 #include <wtf/MainThread.h>
172 #include <wtf/RAMSize.h>
173 #include <wtf/UniqueRef.h>
174
175 #if USE(CG)
176 #include <CoreGraphics/CGContext.h>
177 #endif
178
179 #if USE(CF)
180 #include <CoreFoundation/CoreFoundation.h>
181 #endif
182
183 #if USE(CFURLCONNECTION)
184 #include <CFNetwork/CFURLCachePriv.h>
185 #include <CFNetwork/CFURLProtocolPriv.h>
186 #include <WebKitSystemInterface/WebKitSystemInterface.h>
187 #elif USE(CURL)
188 #include <WebCore/CurlCacheManager.h>
189 #endif
190
191 #if USE(CA)
192 #include <WebCore/CACFLayerTreeHost.h>
193 #include <WebCore/PlatformCALayer.h>
194 #elif USE(TEXTURE_MAPPER_GL)
195 #include "AcceleratedCompositingContext.h"
196 #endif
197
198 #if ENABLE(FULLSCREEN_API)
199 #include <WebCore/FullScreenController.h>
200 #endif
201
202 #include <ShlObj.h>
203 #include <comutil.h>
204 #include <dimm.h>
205 #include <oleacc.h>
206 #include <wchar.h>
207 #include <windowsx.h>
208 #include <winuser.h>
209 #include <wtf/HashSet.h>
210 #include <wtf/text/CString.h>
211 #include <wtf/text/StringConcatenate.h>
212 #include <wtf/win/GDIObject.h>
213
214 #define WEBKIT_DRAWING 4
215
216 // Soft link functions for gestures and panning feedback
217 SOFT_LINK_LIBRARY(USER32);
218 SOFT_LINK_OPTIONAL(USER32, GetGestureInfo, BOOL, WINAPI, (HGESTUREINFO, PGESTUREINFO));
219 SOFT_LINK_OPTIONAL(USER32, SetGestureConfig, BOOL, WINAPI, (HWND, DWORD, UINT, PGESTURECONFIG, UINT));
220 SOFT_LINK_OPTIONAL(USER32, CloseGestureInfoHandle, BOOL, WINAPI, (HGESTUREINFO));
221 SOFT_LINK_LIBRARY(Uxtheme);
222 SOFT_LINK_OPTIONAL(Uxtheme, BeginPanningFeedback, BOOL, WINAPI, (HWND));
223 SOFT_LINK_OPTIONAL(Uxtheme, EndPanningFeedback, BOOL, WINAPI, (HWND, BOOL));
224 SOFT_LINK_OPTIONAL(Uxtheme, UpdatePanningFeedback, BOOL, WINAPI, (HWND, LONG, LONG, BOOL));
225
226 using namespace WebCore;
227 using namespace std;
228 using JSC::JSLock;
229
230 static HMODULE accessibilityLib;
231 static HashSet<WebView*>& pendingDeleteBackingStoreSet()
232 {
233     static NeverDestroyed<HashSet<WebView*>> pendingDeleteBackingStoreSet;
234     return pendingDeleteBackingStoreSet;
235 }
236
237 static CFStringRef WebKitLocalCacheDefaultsKey = CFSTR("WebKitLocalCache");
238
239 static String webKitVersionString();
240
241 WebView* kit(Page* page)
242 {
243     if (!page)
244         return 0;
245     
246     if (page->chrome().client().isEmptyChromeClient())
247         return 0;
248     
249     return static_cast<WebChromeClient&>(page->chrome().client()).webView();
250 }
251
252 static inline AtomicString toAtomicString(BSTR bstr)
253 {
254     return AtomicString(bstr, SysStringLen(bstr));
255 }
256
257 static inline String toString(BSTR bstr)
258 {
259     return String(bstr, SysStringLen(bstr));
260 }
261
262 static inline String toString(BString &bstr)
263 {
264     return String(bstr, SysStringLen(bstr));
265 }
266
267 static inline URL toURL(BSTR bstr)
268 {
269     return URL(URL(), toString(bstr));
270 }
271
272 static String localStorageDatabasePath(WebPreferences* preferences)
273 {
274     BString localStorageDatabasePath;
275     if (FAILED(preferences->localStorageDatabasePath(&localStorageDatabasePath)))
276         return String();
277
278     return toString(localStorageDatabasePath);
279 }
280
281 class PreferencesChangedOrRemovedObserver : public IWebNotificationObserver {
282 public:
283     static PreferencesChangedOrRemovedObserver* sharedInstance();
284
285 private:
286     PreferencesChangedOrRemovedObserver() {}
287     ~PreferencesChangedOrRemovedObserver() {}
288
289     virtual HRESULT STDMETHODCALLTYPE QueryInterface(_In_ REFIID, _Outptr_ void**) { return E_FAIL; }
290     virtual ULONG STDMETHODCALLTYPE AddRef() { return 0; }
291     virtual ULONG STDMETHODCALLTYPE Release() { return 0; }
292
293 public:
294     // IWebNotificationObserver
295     virtual HRESULT STDMETHODCALLTYPE onNotify( 
296         /* [in] */ IWebNotification* notification);
297
298 private:
299     HRESULT notifyPreferencesChanged(WebCacheModel);
300     HRESULT notifyPreferencesRemoved(WebCacheModel);
301 };
302
303 PreferencesChangedOrRemovedObserver* PreferencesChangedOrRemovedObserver::sharedInstance()
304 {
305     static PreferencesChangedOrRemovedObserver* shared = new PreferencesChangedOrRemovedObserver;
306     return shared;
307 }
308
309 HRESULT PreferencesChangedOrRemovedObserver::onNotify(IWebNotification* notification)
310 {
311     HRESULT hr = S_OK;
312
313     COMPtr<IUnknown> unkPrefs;
314     hr = notification->getObject(&unkPrefs);
315     if (FAILED(hr))
316         return hr;
317
318     COMPtr<IWebPreferences> preferences(Query, unkPrefs);
319     if (!preferences)
320         return E_NOINTERFACE;
321
322     WebCacheModel cacheModel;
323     hr = preferences->cacheModel(&cacheModel);
324     if (FAILED(hr))
325         return hr;
326
327     BString name;
328     hr = notification->name(&name);
329     if (FAILED(hr))
330         return hr;
331
332     if (wcscmp(name, WebPreferences::webPreferencesChangedNotification()) == 0)
333         return notifyPreferencesChanged(cacheModel);
334
335     if (wcscmp(name, WebPreferences::webPreferencesRemovedNotification()) == 0)
336         return notifyPreferencesRemoved(cacheModel);
337
338     ASSERT_NOT_REACHED();
339     return E_FAIL;
340 }
341
342 HRESULT PreferencesChangedOrRemovedObserver::notifyPreferencesChanged(WebCacheModel cacheModel)
343 {
344     HRESULT hr = S_OK;
345
346     if (!WebView::didSetCacheModel() || cacheModel > WebView::cacheModel())
347         WebView::setCacheModel(cacheModel);
348     else if (cacheModel < WebView::cacheModel()) {
349         WebCacheModel sharedPreferencesCacheModel;
350         hr = WebPreferences::sharedStandardPreferences()->cacheModel(&sharedPreferencesCacheModel);
351         if (FAILED(hr))
352             return hr;
353         WebView::setCacheModel(max(sharedPreferencesCacheModel, WebView::maxCacheModelInAnyInstance()));
354     }
355
356     return hr;
357 }
358
359 HRESULT PreferencesChangedOrRemovedObserver::notifyPreferencesRemoved(WebCacheModel cacheModel)
360 {
361     HRESULT hr = S_OK;
362
363     if (cacheModel == WebView::cacheModel()) {
364         WebCacheModel sharedPreferencesCacheModel;
365         hr = WebPreferences::sharedStandardPreferences()->cacheModel(&sharedPreferencesCacheModel);
366         if (FAILED(hr))
367             return hr;
368         WebView::setCacheModel(max(sharedPreferencesCacheModel, WebView::maxCacheModelInAnyInstance()));
369     }
370
371     return hr;
372 }
373
374
375 const LPCWSTR kWebViewWindowClassName = L"WebViewWindowClass";
376
377 const int WM_XP_THEMECHANGED = 0x031A;
378 const int WM_VISTA_MOUSEHWHEEL = 0x020E;
379 #ifndef WM_DPICHANGED
380 const int WM_DPICHANGED = 0x02E0;
381 #endif
382
383 static const int maxToolTipWidth = 250;
384
385 static const int delayBeforeDeletingBackingStoreMsec = 5000;
386
387 static ATOM registerWebView();
388
389 static void initializeStaticObservers();
390
391 static HRESULT updateSharedSettingsFromPreferencesIfNeeded(IWebPreferences*);
392
393 HRESULT createMatchEnumerator(Vector<IntRect>* rects, IEnumTextMatches** matches);
394
395 static bool continuousSpellCheckingEnabled;
396 static bool grammarCheckingEnabled;
397
398 static bool s_didSetCacheModel;
399 static WebCacheModel s_cacheModel = WebCacheModelDocumentViewer;
400
401 enum {
402     UpdateActiveStateTimer = 1,
403     DeleteBackingStoreTimer = 2,
404 };
405
406 // WebView ----------------------------------------------------------------
407
408 bool WebView::s_allowSiteSpecificHacks = false;
409
410 WebView::WebView()
411 {
412     JSC::initializeThreading();
413     RunLoop::initializeMainRunLoop();
414
415     m_backingStoreSize.cx = m_backingStoreSize.cy = 0;
416
417     CoCreateInstance(CLSID_DragDropHelper, 0, CLSCTX_INPROC_SERVER, IID_IDropTargetHelper,(void**)&m_dropTargetHelper);
418
419     initializeStaticObservers();
420
421     WebPreferences* sharedPreferences = WebPreferences::sharedStandardPreferences();
422     BOOL enabled = FALSE;
423     if (SUCCEEDED(sharedPreferences->continuousSpellCheckingEnabled(&enabled)))
424         continuousSpellCheckingEnabled = !!enabled;
425     if (SUCCEEDED(sharedPreferences->grammarCheckingEnabled(&enabled)))
426         grammarCheckingEnabled = !!enabled;
427
428     m_webViewGroup = WebViewGroup::getOrCreate(String(), localStorageDatabasePath(sharedPreferences));
429     m_webViewGroup->addWebView(this);
430
431     WebViewCount++;
432     gClassCount++;
433     gClassNameCount().add("WebView");
434 }
435
436 WebView::~WebView()
437 {
438     deleteBackingStore();
439
440     // the tooltip window needs to be explicitly destroyed since it isn't a WS_CHILD
441     if (::IsWindow(m_toolTipHwnd))
442         ::DestroyWindow(m_toolTipHwnd);
443
444     ASSERT(!m_page);
445     ASSERT(!m_preferences);
446     ASSERT(!m_viewWindow);
447
448 #if USE(CA)
449     ASSERT(!m_layerTreeHost);
450 #endif
451
452     m_webViewGroup->removeWebView(this);
453
454     WebViewCount--;
455     gClassCount--;
456     gClassNameCount().remove("WebView");
457 }
458
459 WebView* WebView::createInstance()
460 {
461     WebView* instance = new WebView();
462     instance->AddRef();
463     return instance;
464 }
465
466 void initializeStaticObservers()
467 {
468     static bool initialized = false;
469     if (initialized)
470         return;
471     initialized = true;
472
473     IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal();
474     notifyCenter->addObserver(PreferencesChangedOrRemovedObserver::sharedInstance(), WebPreferences::webPreferencesChangedNotification(), 0);
475     notifyCenter->addObserver(PreferencesChangedOrRemovedObserver::sharedInstance(), WebPreferences::webPreferencesRemovedNotification(), 0);
476 }
477
478 static HashSet<WebView*>& allWebViewsSet()
479 {
480     static HashSet<WebView*> allWebViewsSet;
481     return allWebViewsSet;
482 }
483
484 void WebView::addToAllWebViewsSet()
485 {
486     allWebViewsSet().add(this);
487 }
488
489 void WebView::removeFromAllWebViewsSet()
490 {
491     allWebViewsSet().remove(this);
492 }
493
494 void WebView::setCacheModel(WebCacheModel cacheModel)
495 {
496     if (s_didSetCacheModel && cacheModel == s_cacheModel)
497         return;
498
499     String cacheDirectory;
500
501 #if USE(CFURLCONNECTION)
502     RetainPtr<CFURLCacheRef> cfurlCache = adoptCF(CFURLCacheCopySharedURLCache());
503     RetainPtr<CFStringRef> cfurlCacheDirectory = adoptCF(wkCopyFoundationCacheDirectory(0));
504     if (!cfurlCacheDirectory) {
505         RetainPtr<CFPropertyListRef> preference = adoptCF(CFPreferencesCopyAppValue(WebKitLocalCacheDefaultsKey, WebPreferences::applicationId()));
506         if (preference && (CFStringGetTypeID() == CFGetTypeID(preference.get())))
507             cfurlCacheDirectory = adoptCF(static_cast<CFStringRef>(preference.leakRef()));
508         else
509             cfurlCacheDirectory = WebCore::localUserSpecificStorageDirectory().createCFString();
510     }
511     cacheDirectory = String(cfurlCacheDirectory.get());
512     CFIndex cacheMemoryCapacity = 0;
513     CFIndex cacheDiskCapacity = 0;
514 #elif USE(CURL)
515     cacheDirectory = CurlCacheManager::getInstance().cacheDirectory();
516     long cacheMemoryCapacity = 0;
517     long cacheDiskCapacity = 0;
518 #endif
519
520     unsigned long long memSize = ramSize() / 1024 / 1024;
521
522     // As a fudge factor, use 1000 instead of 1024, in case the reported byte 
523     // count doesn't align exactly to a megabyte boundary.
524     unsigned long long diskFreeSize = WebVolumeFreeSize(cacheDirectory) / 1024 / 1000;
525
526     unsigned cacheTotalCapacity = 0;
527     unsigned cacheMinDeadCapacity = 0;
528     unsigned cacheMaxDeadCapacity = 0;
529     Seconds deadDecodedDataDeletionInterval;
530
531     unsigned pageCacheSize = 0;
532
533
534     switch (cacheModel) {
535     case WebCacheModelDocumentViewer: {
536         // Page cache capacity (in pages)
537         pageCacheSize = 0;
538
539         // Object cache capacities (in bytes)
540         if (memSize >= 2048)
541             cacheTotalCapacity = 96 * 1024 * 1024;
542         else if (memSize >= 1536)
543             cacheTotalCapacity = 64 * 1024 * 1024;
544         else if (memSize >= 1024)
545             cacheTotalCapacity = 32 * 1024 * 1024;
546         else if (memSize >= 512)
547             cacheTotalCapacity = 16 * 1024 * 1024; 
548
549         cacheMinDeadCapacity = 0;
550         cacheMaxDeadCapacity = 0;
551
552         // Memory cache capacity (in bytes)
553         cacheMemoryCapacity = 0;
554
555 #if USE(CFURLCONNECTION)
556         // Foundation disk cache capacity (in bytes)
557         cacheDiskCapacity = CFURLCacheDiskCapacity(cfurlCache.get());
558 #endif
559         break;
560     }
561     case WebCacheModelDocumentBrowser: {
562         // Page cache capacity (in pages)
563         if (memSize >= 1024)
564             pageCacheSize = 3;
565         else if (memSize >= 512)
566             pageCacheSize = 2;
567         else if (memSize >= 256)
568             pageCacheSize = 1;
569         else
570             pageCacheSize = 0;
571
572         // Object cache capacities (in bytes)
573         if (memSize >= 2048)
574             cacheTotalCapacity = 96 * 1024 * 1024;
575         else if (memSize >= 1536)
576             cacheTotalCapacity = 64 * 1024 * 1024;
577         else if (memSize >= 1024)
578             cacheTotalCapacity = 32 * 1024 * 1024;
579         else if (memSize >= 512)
580             cacheTotalCapacity = 16 * 1024 * 1024; 
581
582         cacheMinDeadCapacity = cacheTotalCapacity / 8;
583         cacheMaxDeadCapacity = cacheTotalCapacity / 4;
584
585         // Memory cache capacity (in bytes)
586         if (memSize >= 2048)
587             cacheMemoryCapacity = 4 * 1024 * 1024;
588         else if (memSize >= 1024)
589             cacheMemoryCapacity = 2 * 1024 * 1024;
590         else if (memSize >= 512)
591             cacheMemoryCapacity = 1 * 1024 * 1024;
592         else
593             cacheMemoryCapacity =      512 * 1024; 
594
595         // Disk cache capacity (in bytes)
596         if (diskFreeSize >= 16384)
597             cacheDiskCapacity = 50 * 1024 * 1024;
598         else if (diskFreeSize >= 8192)
599             cacheDiskCapacity = 40 * 1024 * 1024;
600         else if (diskFreeSize >= 4096)
601             cacheDiskCapacity = 30 * 1024 * 1024;
602         else
603             cacheDiskCapacity = 20 * 1024 * 1024;
604
605         break;
606     }
607     case WebCacheModelPrimaryWebBrowser: {
608         // Page cache capacity (in pages)
609         // (Research indicates that value / page drops substantially after 3 pages.)
610         if (memSize >= 2048)
611             pageCacheSize = 5;
612         else if (memSize >= 1024)
613             pageCacheSize = 4;
614         else if (memSize >= 512)
615             pageCacheSize = 3;
616         else if (memSize >= 256)
617             pageCacheSize = 2;
618         else
619             pageCacheSize = 1;
620
621         // Object cache capacities (in bytes)
622         // (Testing indicates that value / MB depends heavily on content and
623         // browsing pattern. Even growth above 128MB can have substantial 
624         // value / MB for some content / browsing patterns.)
625         if (memSize >= 2048)
626             cacheTotalCapacity = 128 * 1024 * 1024;
627         else if (memSize >= 1536)
628             cacheTotalCapacity = 96 * 1024 * 1024;
629         else if (memSize >= 1024)
630             cacheTotalCapacity = 64 * 1024 * 1024;
631         else if (memSize >= 512)
632             cacheTotalCapacity = 32 * 1024 * 1024; 
633
634         cacheMinDeadCapacity = cacheTotalCapacity / 4;
635         cacheMaxDeadCapacity = cacheTotalCapacity / 2;
636
637         // This code is here to avoid a PLT regression. We can remove it if we
638         // can prove that the overall system gain would justify the regression.
639         cacheMaxDeadCapacity = max(24u, cacheMaxDeadCapacity);
640
641         deadDecodedDataDeletionInterval = 60_s;
642
643         // Memory cache capacity (in bytes)
644         // (These values are small because WebCore does most caching itself.)
645         if (memSize >= 1024)
646             cacheMemoryCapacity = 4 * 1024 * 1024;
647         else if (memSize >= 512)
648             cacheMemoryCapacity = 2 * 1024 * 1024;
649         else if (memSize >= 256)
650             cacheMemoryCapacity = 1 * 1024 * 1024;
651         else
652             cacheMemoryCapacity =      512 * 1024; 
653
654         // Disk cache capacity (in bytes)
655         if (diskFreeSize >= 16384)
656             cacheDiskCapacity = 175 * 1024 * 1024;
657         else if (diskFreeSize >= 8192)
658             cacheDiskCapacity = 150 * 1024 * 1024;
659         else if (diskFreeSize >= 4096)
660             cacheDiskCapacity = 125 * 1024 * 1024;
661         else if (diskFreeSize >= 2048)
662             cacheDiskCapacity = 100 * 1024 * 1024;
663         else if (diskFreeSize >= 1024)
664             cacheDiskCapacity = 75 * 1024 * 1024;
665         else
666             cacheDiskCapacity = 50 * 1024 * 1024;
667
668         break;
669     }
670     default:
671         ASSERT_NOT_REACHED();
672     }
673
674     auto& memoryCache = MemoryCache::singleton();
675     memoryCache.setCapacities(cacheMinDeadCapacity, cacheMaxDeadCapacity, cacheTotalCapacity);
676     memoryCache.setDeadDecodedDataDeletionInterval(deadDecodedDataDeletionInterval);
677     PageCache::singleton().setMaxSize(pageCacheSize);
678
679 #if USE(CFURLCONNECTION)
680     // Don't shrink a big disk cache, since that would cause churn.
681     cacheDiskCapacity = max(cacheDiskCapacity, CFURLCacheDiskCapacity(cfurlCache.get()));
682
683     CFURLCacheSetMemoryCapacity(cfurlCache.get(), cacheMemoryCapacity);
684     CFURLCacheSetDiskCapacity(cfurlCache.get(), cacheDiskCapacity);
685 #elif USE(CURL)
686     CurlCacheManager::getInstance().setStorageSizeLimit(cacheDiskCapacity);
687 #endif
688
689     s_didSetCacheModel = true;
690     s_cacheModel = cacheModel;
691     return;
692 }
693
694 WebCacheModel WebView::cacheModel()
695 {
696     return s_cacheModel;
697 }
698
699 bool WebView::didSetCacheModel()
700 {
701     return s_didSetCacheModel;
702 }
703
704 WebCacheModel WebView::maxCacheModelInAnyInstance()
705 {
706     WebCacheModel cacheModel = WebCacheModelDocumentViewer;
707
708     HashSet<WebView*>::iterator end = allWebViewsSet().end();
709     for (HashSet<WebView*>::iterator it = allWebViewsSet().begin(); it != end; ++it) {
710         COMPtr<IWebPreferences> pref;
711         if (FAILED((*it)->preferences(&pref)))
712             continue;
713         WebCacheModel prefCacheModel = WebCacheModelDocumentViewer;
714         if (FAILED(pref->cacheModel(&prefCacheModel)))
715             continue;
716
717         cacheModel = max(cacheModel, prefCacheModel);
718     }
719
720     return cacheModel;
721 }
722
723 HRESULT WebView::close()
724 {
725     if (m_didClose)
726         return S_OK;
727
728     m_didClose = true;
729
730     setAcceleratedCompositing(false);
731
732     WebNotificationCenter::defaultCenterInternal()->postNotificationName(_bstr_t(WebViewWillCloseNotification).GetBSTR(), static_cast<IWebView*>(this), 0);
733
734     if (m_uiDelegatePrivate)
735         m_uiDelegatePrivate->webViewClosing(this);
736
737     removeFromAllWebViewsSet();
738
739     if (m_page)
740         m_page->mainFrame().loader().detachFromParent();
741
742     if (m_mouseOutTracker) {
743         m_mouseOutTracker->dwFlags = TME_CANCEL;
744         ::TrackMouseEvent(m_mouseOutTracker.get());
745         m_mouseOutTracker.reset();
746     }
747     
748     revokeDragDrop();
749
750     if (m_viewWindow) {
751         // We can't check IsWindow(m_viewWindow) here, because that will return true even while
752         // we're already handling WM_DESTROY. So we check !isBeingDestroyed() instead.
753         if (!isBeingDestroyed())
754             DestroyWindow(m_viewWindow);
755         // Either we just destroyed m_viewWindow, or it's in the process of being destroyed. Either
756         // way, we clear it out to make sure we don't try to use it later.
757         m_viewWindow = 0;
758     }
759
760     setHostWindow(0);
761
762     setAccessibilityDelegate(0);
763     setDownloadDelegate(0);
764     setEditingDelegate(0);
765     setFrameLoadDelegate(0);
766     setFrameLoadDelegatePrivate(0);
767     setHistoryDelegate(0);
768     setPolicyDelegate(0);
769     setResourceLoadDelegate(0);
770     setUIDelegate(0);
771     setFormDelegate(0);
772
773     m_inspectorClient = nullptr;
774     if (m_webInspector)
775         m_webInspector->inspectedWebViewClosed();
776
777     delete m_page;
778     m_page = nullptr;
779
780     m_mainFrame = nullptr;
781
782     registerForIconNotification(false);
783     IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal();
784     notifyCenter->removeObserver(this, WebPreferences::webPreferencesChangedNotification(), static_cast<IWebPreferences*>(m_preferences.get()));
785
786     if (COMPtr<WebPreferences> preferences = m_preferences) {
787         BString identifier;
788         preferences->identifier(&identifier);
789
790         m_preferences = 0;
791         preferences->didRemoveFromWebView();
792         // Make sure we release the reference, since WebPreferences::removeReferenceForIdentifier will check for last reference to WebPreferences
793         preferences = 0;
794         if (identifier)
795             WebPreferences::removeReferenceForIdentifier(identifier);
796     }
797
798     deleteBackingStore();
799     return S_OK;
800 }
801
802 void WebView::repaint(const WebCore::IntRect& logicalWindowRect, bool contentChanged, bool immediate, bool repaintContentOnly)
803 {
804     FloatRect windowRectFloat(logicalWindowRect);
805     windowRectFloat.scale(deviceScaleFactor());
806     IntRect windowRect(enclosingIntRect(windowRectFloat));
807
808     if (isAcceleratedCompositing()) {
809         // The contentChanged, immediate, and repaintContentOnly parameters are all based on a non-
810         // compositing painting/scrolling model.
811         addToDirtyRegion(logicalWindowRect);
812         return;
813     }
814
815     if (!repaintContentOnly) {
816         RECT rect = windowRect;
817         ::InvalidateRect(m_viewWindow, &rect, false);
818     }
819     if (contentChanged)
820         addToDirtyRegion(windowRect);
821     if (immediate) {
822         if (repaintContentOnly)
823             updateBackingStore(core(topLevelFrame())->view());
824         else
825             ::UpdateWindow(m_viewWindow);
826     }
827     m_needsDisplay = true;
828 }
829
830 void WebView::deleteBackingStore()
831 {
832     pendingDeleteBackingStoreSet().remove(this);
833
834     if (m_deleteBackingStoreTimerActive) {
835         KillTimer(m_viewWindow, DeleteBackingStoreTimer);
836         m_deleteBackingStoreTimerActive = false;
837     }
838     m_backingStoreBitmap = nullptr;
839 #if USE(DIRECT2D)
840     m_backingStoreD2DBitmap = nullptr;
841     m_backingStoreGdiInterop = nullptr;
842     m_backingStoreRenderTarget = nullptr;
843 #endif
844     m_backingStoreDirtyRegion = nullptr;
845     m_backingStoreSize.cx = m_backingStoreSize.cy = 0;
846 }
847
848 bool WebView::ensureBackingStore()
849 {
850     RECT windowRect;
851     ::GetClientRect(m_viewWindow, &windowRect);
852     LONG width = windowRect.right - windowRect.left;
853     LONG height = windowRect.bottom - windowRect.top;
854     if (width > 0 && height > 0 && (width != m_backingStoreSize.cx || height != m_backingStoreSize.cy)) {
855         deleteBackingStore();
856
857 #if USE(DIRECT2D)
858         auto bitmapSize = D2D1::SizeF(width, height);
859         auto pixelSize = D2D1::SizeU(width, height);
860
861         if (!m_renderTarget) {
862             // Create a Direct2D render target.
863             auto renderTargetProperties = D2D1::RenderTargetProperties();
864             renderTargetProperties.usage = D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE;
865             auto hwndRenderTargetProperties = D2D1::HwndRenderTargetProperties(m_viewWindow, pixelSize);
866             HRESULT hr = GraphicsContext::systemFactory()->CreateHwndRenderTarget(&renderTargetProperties, &hwndRenderTargetProperties, &m_renderTarget);
867             if (!SUCCEEDED(hr))
868                 return false;
869         }
870
871         COMPtr<ID2D1SolidColorBrush> brush;
872         m_renderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::BlueViolet), &brush);
873
874         m_renderTarget->BeginDraw();
875         m_renderTarget->FillRoundedRectangle(D2D1::RoundedRect(D2D1::RectF(100.0f, 100.0f, 300.0f, 200.0f), 20.0f, 20.0f), brush.get());
876         m_renderTarget->EndDraw();
877 #endif
878         m_backingStoreSize.cx = width;
879         m_backingStoreSize.cy = height;
880         BitmapInfo bitmapInfo = BitmapInfo::createBottomUp(IntSize(m_backingStoreSize));
881
882         void* pixels = NULL;
883         m_backingStoreBitmap = SharedGDIObject<HBITMAP>::create(adoptGDIObject(::CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0)));
884
885 #if USE(DIRECT2D)
886         HRESULT hr = m_renderTarget->CreateCompatibleRenderTarget(&bitmapSize, &pixelSize, nullptr, D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_GDI_COMPATIBLE, &m_backingStoreRenderTarget);
887         RELEASE_ASSERT(SUCCEEDED(hr));
888
889         hr = m_backingStoreRenderTarget->GetBitmap(&m_backingStoreD2DBitmap);
890         RELEASE_ASSERT(SUCCEEDED(hr));
891
892         hr = m_backingStoreRenderTarget->QueryInterface(__uuidof(ID2D1GdiInteropRenderTarget), (void**)&m_backingStoreGdiInterop);
893         RELEASE_ASSERT(SUCCEEDED(hr));
894
895         COMPtr<ID2D1SolidColorBrush> brush2;
896         m_backingStoreRenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::SeaGreen), &brush2);
897         m_backingStoreRenderTarget->BeginDraw();
898         m_renderTarget->FillRoundedRectangle(D2D1::RoundedRect(D2D1::RectF(100.0f, 100.0f, 300.0f, 200.0f), 20.0f, 20.0f), brush2.get());
899         m_renderTarget->EndDraw();
900 #endif
901         return true;
902     }
903
904     return false;
905 }
906
907 void WebView::addToDirtyRegion(const IntRect& dirtyRect)
908 {
909     m_needsDisplay = true;
910
911     // FIXME: We want an assert here saying that the dirtyRect is inside the clienRect,
912     // but it was being hit during our layout tests, and is being investigated in
913     // http://webkit.org/b/29350.
914
915     if (isAcceleratedCompositing()) {
916 #if USE(CA)
917         m_backingLayer->setNeedsDisplayInRect(dirtyRect);
918 #elif USE(TEXTURE_MAPPER_GL)
919         m_acceleratedCompositingContext->setNonCompositedContentsNeedDisplay(dirtyRect);
920 #endif
921         return;
922     }
923
924     auto newRegion = adoptGDIObject(::CreateRectRgn(dirtyRect.x(), dirtyRect.y(),
925         dirtyRect.maxX(), dirtyRect.maxY()));
926     addToDirtyRegion(WTFMove(newRegion));
927 }
928
929 void WebView::addToDirtyRegion(GDIObject<HRGN> newRegion)
930 {
931     m_needsDisplay = true;
932
933     ASSERT(!isAcceleratedCompositing());
934
935     LOCAL_GDI_COUNTER(0, __FUNCTION__);
936
937     if (m_backingStoreDirtyRegion) {
938         auto combinedRegion = adoptGDIObject(::CreateRectRgn(0, 0, 0, 0));
939         ::CombineRgn(combinedRegion.get(), m_backingStoreDirtyRegion->get(), newRegion.get(), RGN_OR);
940         m_backingStoreDirtyRegion = SharedGDIObject<HRGN>::create(WTFMove(combinedRegion));
941     } else
942         m_backingStoreDirtyRegion = SharedGDIObject<HRGN>::create(WTFMove(newRegion));
943
944     if (m_uiDelegatePrivate)
945         m_uiDelegatePrivate->webViewDidInvalidate(this);
946 }
947
948 void WebView::scrollBackingStore(FrameView* frameView, int logicalDx, int logicalDy, const IntRect& logicalScrollViewRect, const IntRect& logicalClipRect)
949 {
950     m_needsDisplay = true;
951
952     // Dimensions passed to us from WebCore are in logical units. We must convert to pixels:
953     float scaleFactor = deviceScaleFactor();
954     int dx = clampTo<int>(scaleFactor * logicalDx);
955     int dy = clampTo<int>(scaleFactor * logicalDy);
956     FloatRect scrollViewRectFloat(logicalScrollViewRect);
957     scrollViewRectFloat.scale(scaleFactor);
958     IntRect scrollViewRect(enclosingIntRect(scrollViewRectFloat));
959     FloatRect clipRect(logicalClipRect);
960     clipRect.scale(scaleFactor);
961
962 #if USE(DIRECT2D)
963     RECT scrollRectWin(scrollViewRect);
964     RECT clipRectWin(enclosingIntRect(clipRect));
965     RECT updateRect;
966     ::ScrollWindowEx(m_viewWindow, dx, dy, &scrollRectWin, &clipRectWin, nullptr, &updateRect, 0);
967     ::InvalidateRect(m_viewWindow, &updateRect, FALSE);
968
969     if (m_uiDelegatePrivate)
970         m_uiDelegatePrivate->webViewScrolled(this);
971 #else
972     if (isAcceleratedCompositing()) {
973         // FIXME: We should be doing something smarter here, like moving tiles around and painting
974         // any newly-exposed tiles. <http://webkit.org/b/52714>
975 #if USE(CA)
976         m_backingLayer->setNeedsDisplayInRect(scrollViewRect);
977 #elif USE(TEXTURE_MAPPER_GL)
978         m_acceleratedCompositingContext->scrollNonCompositedContents(scrollViewRect, IntSize(dx, dy));
979 #endif
980         return;
981     }
982
983     LOCAL_GDI_COUNTER(0, __FUNCTION__);
984
985     // If there's no backing store we don't need to update it
986     if (!m_backingStoreBitmap) {
987         if (m_uiDelegatePrivate)
988             m_uiDelegatePrivate->webViewScrolled(this);
989
990         return;
991     }
992
993     // Make a region to hold the invalidated scroll area.
994     auto updateRegion = adoptGDIObject(::CreateRectRgn(0, 0, 0, 0));
995
996     // Collect our device context info and select the bitmap to scroll.
997     HWndDC windowDC(m_viewWindow);
998     auto bitmapDC = adoptGDIObject(::CreateCompatibleDC(windowDC));
999     HGDIOBJ oldBitmap = ::SelectObject(bitmapDC.get(), m_backingStoreBitmap->get());
1000     if (!oldBitmap) {
1001         // The ::SelectObject call will fail if m_backingStoreBitmap is already selected into a device context.
1002         // This happens when this method is called indirectly from WebView::updateBackingStore during normal WM_PAINT handling.
1003         // There is no point continuing, since we would just be scrolling a 1x1 bitmap which is selected into the device context by default.
1004         // We can just scroll by repainting the scroll rectangle.
1005         RECT scrollRect(scrollViewRect);
1006         ::InvalidateRect(m_viewWindow, &scrollRect, FALSE);
1007         return;
1008     }
1009
1010     // Scroll the bitmap.
1011     RECT scrollRectWin(scrollViewRect);
1012     RECT clipRectWin(enclosingIntRect(clipRect));
1013     ::ScrollDC(bitmapDC.get(), dx, dy, &scrollRectWin, &clipRectWin, updateRegion.get(), 0);
1014     RECT regionBox;
1015     ::GetRgnBox(updateRegion.get(), &regionBox);
1016
1017     // Flush.
1018     GdiFlush();
1019
1020     // Add the dirty region to the backing store's dirty region.
1021     addToDirtyRegion(WTFMove(updateRegion));
1022
1023     if (m_uiDelegatePrivate)
1024         m_uiDelegatePrivate->webViewScrolled(this);
1025
1026     // Update the backing store.
1027     updateBackingStore(frameView, bitmapDC.get(), false);
1028
1029     // Clean up.
1030     ::SelectObject(bitmapDC.get(), oldBitmap);
1031 #endif // USE(DIRECT2D)
1032 }
1033
1034 void WebView::sizeChanged(const IntSize& newSize)
1035 {
1036     m_needsDisplay = true;
1037
1038     deleteBackingStore();
1039
1040     if (Frame* coreFrame = core(topLevelFrame())) {
1041         IntSize logicalSize = newSize;
1042         logicalSize.scale(1.0f / deviceScaleFactor());
1043         coreFrame->view()->resize(logicalSize);
1044     }
1045
1046 #if USE(CA)
1047     if (m_layerTreeHost)
1048         m_layerTreeHost->resize();
1049
1050     if (m_backingLayer) {
1051         m_backingLayer->setSize(newSize);
1052         m_backingLayer->setNeedsDisplay();
1053     }
1054 #elif USE(TEXTURE_MAPPER_GL)
1055     if (m_acceleratedCompositingContext)
1056         m_acceleratedCompositingContext->resizeRootLayer(newSize);
1057 #endif
1058
1059 #if USE(DIRECT2D)
1060     if (m_renderTarget) {
1061         m_renderTarget->Resize(newSize);
1062         return;
1063     }
1064
1065     // Create a Direct2D render target.
1066     auto renderTargetProperties = D2D1::RenderTargetProperties();
1067     renderTargetProperties.usage = D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE;
1068     auto hwndRenderTargetProperties = D2D1::HwndRenderTargetProperties(m_viewWindow, newSize, D2D1_PRESENT_OPTIONS_IMMEDIATELY);
1069     HRESULT hr = GraphicsContext::systemFactory()->CreateHwndRenderTarget(&renderTargetProperties, &hwndRenderTargetProperties, &m_renderTarget);
1070     ASSERT(SUCCEEDED(hr));
1071 #endif
1072 }
1073
1074 bool WebView::dpiChanged(float, const WebCore::IntSize& newSize)
1075 {
1076     if (!IsProcessDPIAware())
1077         return false;
1078
1079     sizeChanged(newSize);
1080
1081     return true;
1082 }
1083
1084 // This emulates the Mac smarts for painting rects intelligently.  This is very
1085 // important for us, since we double buffer based off dirty rects.
1086 static void getUpdateRects(HRGN region, const IntRect& dirtyRect, Vector<IntRect>& rects)
1087 {
1088     ASSERT_ARG(region, region);
1089
1090     const int cRectThreshold = 10;
1091     const float cWastedSpaceThreshold = 0.75f;
1092
1093     rects.clear();
1094
1095     DWORD regionDataSize = GetRegionData(region, sizeof(RGNDATA), NULL);
1096     if (!regionDataSize) {
1097         rects.append(dirtyRect);
1098         return;
1099     }
1100
1101     Vector<unsigned char> buffer(regionDataSize);
1102     RGNDATA* regionData = reinterpret_cast<RGNDATA*>(buffer.data());
1103     GetRegionData(region, regionDataSize, regionData);
1104     if (regionData->rdh.nCount > cRectThreshold) {
1105         rects.append(dirtyRect);
1106         return;
1107     }
1108
1109     double singlePixels = 0.0;
1110     unsigned i;
1111     RECT* rect;
1112     for (i = 0, rect = reinterpret_cast<RECT*>(regionData->Buffer); i < regionData->rdh.nCount; i++, rect++)
1113         singlePixels += (rect->right - rect->left) * (rect->bottom - rect->top);
1114
1115     double unionPixels = dirtyRect.width() * dirtyRect.height();
1116     double wastedSpace = 1.0 - (singlePixels / unionPixels);
1117     if (wastedSpace <= cWastedSpaceThreshold) {
1118         rects.append(dirtyRect);
1119         return;
1120     }
1121
1122     for (i = 0, rect = reinterpret_cast<RECT*>(regionData->Buffer); i < regionData->rdh.nCount; i++, rect++)
1123         rects.append(*rect);
1124 }
1125
1126 void WebView::updateBackingStore(FrameView* frameView, HDC dc, bool backingStoreCompletelyDirty, WindowsToPaint windowsToPaint)
1127 {
1128     ASSERT(!isAcceleratedCompositing());
1129
1130     LOCAL_GDI_COUNTER(0, __FUNCTION__);
1131
1132 #if USE(DIRECT2D)
1133     if (!m_backingStoreGdiInterop) {
1134         HRESULT hr = m_backingStoreRenderTarget->QueryInterface(__uuidof(ID2D1GdiInteropRenderTarget), (void**)&m_backingStoreGdiInterop);
1135         RELEASE_ASSERT(SUCCEEDED(hr));
1136     }
1137 #endif
1138
1139     GDIObject<HDC> bitmapDCObject;
1140
1141     HDC bitmapDC = dc;
1142     HGDIOBJ oldBitmap = 0;
1143     if (!dc) {
1144         HWndDC windowDC(m_viewWindow);
1145         bitmapDCObject = adoptGDIObject(::CreateCompatibleDC(windowDC));
1146         bitmapDC = bitmapDCObject.get();
1147         oldBitmap = ::SelectObject(bitmapDC, m_backingStoreBitmap->get());
1148 #if USE(DIRECT2D)
1149         HRESULT hr = m_backingStoreGdiInterop->GetDC(D2D1_DC_INITIALIZE_MODE_COPY, &bitmapDC);
1150         RELEASE_ASSERT(SUCCEEDED(hr));
1151 #endif
1152     }
1153
1154     if (m_backingStoreBitmap && (m_backingStoreDirtyRegion || backingStoreCompletelyDirty)) {
1155         // Do a layout first so that everything we render to the backing store is always current.
1156         if (Frame* coreFrame = core(m_mainFrame))
1157             if (FrameView* view = coreFrame->view())
1158                 view->updateLayoutAndStyleIfNeededRecursive();
1159
1160         Vector<IntRect> paintRects;
1161         if (!backingStoreCompletelyDirty && m_backingStoreDirtyRegion) {
1162             RECT regionBox;
1163             ::GetRgnBox(m_backingStoreDirtyRegion->get(), &regionBox);
1164             getUpdateRects(m_backingStoreDirtyRegion->get(), regionBox, paintRects);
1165         } else {
1166             RECT clientRect;
1167             ::GetClientRect(m_viewWindow, &clientRect);
1168             paintRects.append(clientRect);
1169         }
1170
1171         for (unsigned i = 0; i < paintRects.size(); ++i)
1172             paintIntoBackingStore(frameView, bitmapDC, paintRects[i], windowsToPaint);
1173
1174         if (m_uiDelegatePrivate)
1175             m_uiDelegatePrivate->webViewPainted(this);
1176
1177         m_backingStoreDirtyRegion = nullptr;
1178     }
1179
1180     if (!dc) {
1181         ::SelectObject(bitmapDC, oldBitmap);
1182 #if USE(DIRECT2D)
1183         m_backingStoreGdiInterop->ReleaseDC(nullptr);
1184 #endif
1185     }
1186
1187     GdiFlush();
1188
1189     m_needsDisplay = true;
1190 }
1191
1192 void WebView::performLayeredWindowUpdate()
1193 {
1194     // The backing store may have been destroyed if the window rect was set to zero height or zero width.
1195     if (!m_backingStoreBitmap)
1196         return;
1197
1198     HWndDC hdcScreen(m_viewWindow);
1199     auto hdcMem = adoptGDIObject(::CreateCompatibleDC(hdcScreen));
1200     HBITMAP hbmOld = static_cast<HBITMAP>(::SelectObject(hdcMem.get(), m_backingStoreBitmap->get()));
1201
1202     BITMAP bmpInfo;
1203     ::GetObject(m_backingStoreBitmap->get(), sizeof(bmpInfo), &bmpInfo);
1204     SIZE windowSize = { bmpInfo.bmWidth, bmpInfo.bmHeight };
1205
1206     BLENDFUNCTION blendFunction;
1207     blendFunction.BlendOp = AC_SRC_OVER;
1208     blendFunction.BlendFlags = 0;
1209     blendFunction.SourceConstantAlpha = 0xFF;
1210     blendFunction.AlphaFormat = AC_SRC_ALPHA;
1211
1212     POINT layerPos = { 0, 0 };
1213     ::UpdateLayeredWindow(m_viewWindow, hdcScreen, 0, &windowSize, hdcMem.get(), &layerPos, 0, &blendFunction, ULW_ALPHA);
1214
1215     ::SelectObject(hdcMem.get(), hbmOld);
1216
1217     m_needsDisplay = false;
1218 }
1219
1220 void WebView::paintWithDirect2D()
1221 {
1222 #if USE(DIRECT2D)
1223     Frame* coreFrame = core(m_mainFrame);
1224     if (!coreFrame)
1225         return;
1226     FrameView* frameView = coreFrame->view();
1227     frameView->updateLayoutAndStyleIfNeededRecursive();
1228
1229     if (!m_renderTarget) {
1230         // Create a Direct2D render target.
1231         auto renderTargetProperties = D2D1::RenderTargetProperties();
1232         renderTargetProperties.usage = D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE;
1233
1234         RECT rect;
1235         ::GetClientRect(m_viewWindow, &rect);
1236
1237         IntRect clientRect(rect);
1238
1239         auto pixelSize = D2D1::SizeU(clientRect.width(), clientRect.height());
1240
1241         auto hwndRenderTargetProperties = D2D1::HwndRenderTargetProperties(m_viewWindow, pixelSize, D2D1_PRESENT_OPTIONS_IMMEDIATELY);
1242         HRESULT hr = GraphicsContext::systemFactory()->CreateHwndRenderTarget(&renderTargetProperties, &hwndRenderTargetProperties, &m_renderTarget);
1243         if (!SUCCEEDED(hr))
1244             return;
1245     }
1246
1247     RECT clientRect = {};
1248     GraphicsContext gc(m_renderTarget.get());
1249
1250     {
1251         m_renderTarget->SetTags(WEBKIT_DRAWING, __LINE__);
1252         m_renderTarget->Clear();
1253
1254         // Direct2D honors the scale factor natively.
1255         float scaleFactor = 1.0f;
1256         float inverseScaleFactor = 1.0f / scaleFactor;
1257
1258         GetClientRect(m_viewWindow, &clientRect);
1259
1260         IntRect dirtyRectPixels(0, 0, clientRect.right, clientRect.bottom);
1261         FloatRect logicalDirtyRectFloat = dirtyRectPixels;
1262         logicalDirtyRectFloat.scale(inverseScaleFactor);
1263         IntRect logicalDirtyRect(enclosingIntRect(logicalDirtyRectFloat));
1264
1265         if (frameView && frameView->frame().contentRenderer()) {
1266             gc.save();
1267             gc.scale(FloatSize(scaleFactor, scaleFactor));
1268             gc.clip(logicalDirtyRect);
1269             frameView->paint(gc, logicalDirtyRect);
1270             gc.restore();
1271             if (m_shouldInvertColors)
1272                 gc.fillRect(logicalDirtyRect, Color::white, CompositeDifference);
1273         }
1274     }
1275
1276     ::ValidateRect(m_viewWindow, &clientRect);
1277 #else
1278     ASSERT_NOT_REACHED();
1279 #endif
1280 }
1281
1282 void WebView::paint(HDC dc, LPARAM options)
1283 {
1284     LOCAL_GDI_COUNTER(0, __FUNCTION__);
1285
1286     if (paintCompositedContentToHDC(dc)) {
1287         ::ValidateRect(m_viewWindow, nullptr);
1288         return;
1289     }
1290
1291     Frame* coreFrame = core(m_mainFrame);
1292     if (!coreFrame)
1293         return;
1294     FrameView* frameView = coreFrame->view();
1295
1296     RECT rcPaint;
1297     HDC hdc;
1298     GDIObject<HRGN> region;
1299     int regionType = NULLREGION;
1300     PAINTSTRUCT ps;
1301     WindowsToPaint windowsToPaint;
1302     if (!dc) {
1303         region = adoptGDIObject(::CreateRectRgn(0, 0, 0, 0));
1304         regionType = GetUpdateRgn(m_viewWindow, region.get(), false);
1305         hdc = BeginPaint(m_viewWindow, &ps);
1306         rcPaint = ps.rcPaint;
1307         // We're painting to the screen, and our child windows can handle
1308         // painting themselves to the screen.
1309         windowsToPaint = PaintWebViewOnly;
1310     } else {
1311         hdc = dc;
1312         ::GetClientRect(m_viewWindow, &rcPaint);
1313         if (options & PRF_ERASEBKGND)
1314             ::FillRect(hdc, &rcPaint, (HBRUSH)GetStockObject(WHITE_BRUSH));
1315         // Since we aren't painting to the screen, we want to paint all our
1316         // children into the HDC.
1317         windowsToPaint = PaintWebViewAndChildren;
1318     }
1319
1320     bool backingStoreCompletelyDirty = ensureBackingStore();
1321     if (!m_backingStoreBitmap) {
1322         if (!dc)
1323             EndPaint(m_viewWindow, &ps);
1324         return;
1325     }
1326
1327     m_paintCount++;
1328
1329     auto bitmapDC = adoptGDIObject(::CreateCompatibleDC(hdc));
1330     HGDIOBJ oldBitmap = ::SelectObject(bitmapDC.get(), m_backingStoreBitmap->get());
1331
1332     // Update our backing store if needed.
1333     updateBackingStore(frameView, bitmapDC.get(), backingStoreCompletelyDirty, windowsToPaint);
1334
1335     // Now we blit the updated backing store
1336     IntRect windowDirtyRect = rcPaint;
1337     
1338     // Apply the same heuristic for this update region too.
1339     Vector<IntRect> blitRects;
1340     if (region && regionType == COMPLEXREGION)
1341         getUpdateRects(region.get(), windowDirtyRect, blitRects);
1342     else
1343         blitRects.append(windowDirtyRect);
1344
1345     for (unsigned i = 0; i < blitRects.size(); ++i)
1346         paintIntoWindow(bitmapDC.get(), hdc, blitRects[i]);
1347
1348     ::SelectObject(bitmapDC.get(), oldBitmap);
1349
1350     if (!dc) {
1351         EndPaint(m_viewWindow, &ps);
1352 #if USE(DIRECT2D)
1353         HRESULT hr = m_backingStoreRenderTarget->EndDraw();
1354         // FIXME: Recognize and recover from error state:
1355         RELEASE_ASSERT(SUCCEEDED(hr));
1356 #endif
1357     }
1358
1359 #if USE(DIRECT2D)
1360     m_backingStoreGdiInterop->ReleaseDC(nullptr);
1361 #endif
1362
1363     m_paintCount--;
1364
1365     if (active())
1366         cancelDeleteBackingStoreSoon();
1367     else
1368         deleteBackingStoreSoon();
1369 }
1370
1371 void WebView::paintIntoBackingStore(FrameView* frameView, HDC bitmapDC, const IntRect& dirtyRectPixels, WindowsToPaint windowsToPaint)
1372 {
1373     // FIXME: This function should never be called in accelerated compositing mode, and we should
1374     // assert as such. But currently it *is* sometimes called, so we can't assert yet. See
1375     // <http://webkit.org/b/58539>.
1376
1377     LOCAL_GDI_COUNTER(0, __FUNCTION__);
1378
1379     // FIXME: We want an assert here saying that the dirtyRect is inside the clienRect,
1380     // but it was being hit during our layout tests, and is being investigated in
1381     // http://webkit.org/b/29350.
1382
1383     RECT rect = dirtyRectPixels;
1384
1385 #if FLASH_BACKING_STORE_REDRAW
1386     {
1387         HWndDC dc(m_viewWindow);
1388         auto yellowBrush = adoptGDIObject(::CreateSolidBrush(RGB(255, 255, 0)));
1389         FillRect(dc, &rect, yellowBrush.get());
1390         GdiFlush();
1391         Sleep(50);
1392         paintIntoWindow(bitmapDC, dc, dirtyRectPixels);
1393     }
1394 #endif
1395
1396     float scaleFactor = deviceScaleFactor();
1397     float inverseScaleFactor = 1.0f / scaleFactor;
1398
1399     FloatRect logicalDirtyRectFloat = dirtyRectPixels;
1400     logicalDirtyRectFloat.scale(inverseScaleFactor);    
1401     IntRect logicalDirtyRect(enclosingIntRect(logicalDirtyRectFloat));
1402
1403 #if USE(DIRECT2D)
1404     m_backingStoreRenderTarget = nullptr;
1405 #endif
1406
1407     GraphicsContext gc(bitmapDC, m_transparent);
1408     gc.setShouldIncludeChildWindows(windowsToPaint == PaintWebViewAndChildren);
1409     gc.save();
1410     if (m_transparent)
1411         gc.clearRect(logicalDirtyRect);
1412     else
1413         FillRect(bitmapDC, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
1414
1415     COMPtr<IWebUIDelegatePrivate2> uiPrivate(Query, m_uiDelegate);
1416     if (uiPrivate)
1417         uiPrivate->drawBackground(this, bitmapDC, &rect);
1418
1419     if (frameView && frameView->frame().contentRenderer()) {
1420         gc.save();
1421         gc.scale(FloatSize(scaleFactor, scaleFactor));
1422         gc.clip(logicalDirtyRect);
1423         frameView->paint(gc, logicalDirtyRect);
1424         gc.restore();
1425         if (m_shouldInvertColors)
1426             gc.fillRect(logicalDirtyRect, Color::white, CompositeDifference);
1427     }
1428     gc.restore();
1429 }
1430
1431 void WebView::paintIntoWindow(HDC bitmapDC, HDC windowDC, const IntRect& dirtyRectPixels)
1432 {
1433     // FIXME: This function should never be called in accelerated compositing mode, and we should
1434     // assert as such. But currently it *is* sometimes called, so we can't assert yet. See
1435     // <http://webkit.org/b/58539>.
1436
1437     LOCAL_GDI_COUNTER(0, __FUNCTION__);
1438 #if FLASH_WINDOW_REDRAW
1439     auto greenBrush = adoptGDIObject(::CreateSolidBrush(RGB(0, 255, 0)));
1440     RECT rect = dirtyRectPixels;
1441     FillRect(windowDC, &rect, greenBrush.get());
1442     GdiFlush();
1443     Sleep(50);
1444 #endif
1445
1446     // Blit the dirty rect from the backing store into the same position
1447     // in the destination DC.
1448     BitBlt(windowDC, dirtyRectPixels.x(), dirtyRectPixels.y(), dirtyRectPixels.width(), dirtyRectPixels.height(), bitmapDC,
1449         dirtyRectPixels.x(), dirtyRectPixels.y(), SRCCOPY);
1450
1451     m_needsDisplay = false;
1452 }
1453
1454 void WebView::frameRect(RECT* rect)
1455 {
1456     ::GetWindowRect(m_viewWindow, rect);
1457 }
1458
1459 class WindowCloseTimer final : public WebCore::SuspendableTimer {
1460 public:
1461     static WindowCloseTimer* create(WebView*);
1462
1463 private:
1464     WindowCloseTimer(ScriptExecutionContext&, WebView*);
1465
1466     // ActiveDOMObject API.
1467     void contextDestroyed() override;
1468     const char* activeDOMObjectName() const override { return "WindowCloseTimer"; }
1469
1470     // SuspendableTimer API.
1471     void fired() override;
1472
1473     WebView* m_webView;
1474 };
1475
1476 WindowCloseTimer* WindowCloseTimer::create(WebView* webView)
1477 {
1478     ASSERT_ARG(webView, webView);
1479     Frame* frame = core(webView->topLevelFrame());
1480     ASSERT(frame);
1481     if (!frame)
1482         return nullptr;
1483
1484     Document* document = frame->document();
1485     ASSERT(document);
1486     if (!document)
1487         return nullptr;
1488
1489     auto closeTimer = new WindowCloseTimer(*document, webView);
1490     closeTimer->suspendIfNeeded();
1491     return closeTimer;
1492 }
1493
1494 WindowCloseTimer::WindowCloseTimer(ScriptExecutionContext& context, WebView* webView)
1495     : SuspendableTimer(context)
1496     , m_webView(webView)
1497 {
1498     ASSERT_ARG(webView, webView);
1499 }
1500
1501 void WindowCloseTimer::contextDestroyed()
1502 {
1503     SuspendableTimer::contextDestroyed();
1504     delete this;
1505 }
1506
1507 void WindowCloseTimer::fired()
1508 {
1509     m_webView->closeWindowTimerFired();
1510 }
1511
1512 void WebView::closeWindowSoon()
1513 {
1514     if (m_closeWindowTimer)
1515         return;
1516
1517     m_closeWindowTimer = WindowCloseTimer::create(this);
1518     if (!m_closeWindowTimer)
1519         return;
1520     m_closeWindowTimer->startOneShot(0_s);
1521
1522     AddRef();
1523 }
1524
1525 void WebView::closeWindowTimerFired()
1526 {
1527     closeWindow();
1528     Release();
1529 }
1530
1531 void WebView::closeWindow()
1532 {
1533     if (m_hasSpellCheckerDocumentTag) {
1534         if (m_editingDelegate)
1535             m_editingDelegate->closeSpellDocument(this);
1536         m_hasSpellCheckerDocumentTag = false;
1537     }
1538
1539     COMPtr<IWebUIDelegate> ui;
1540     if (SUCCEEDED(uiDelegate(&ui)))
1541         ui->webViewClose(this);
1542 }
1543
1544 bool WebView::canHandleRequest(const WebCore::ResourceRequest& request)
1545 {
1546 #if USE(CFURLCONNECTION)
1547     // On the Mac there's an about URL protocol implementation but Windows CFNetwork doesn't have that.
1548     if (request.url().protocolIs("about"))
1549         return true;
1550
1551     return CFURLProtocolCanHandleRequest(request.cfURLRequest(UpdateHTTPBody));
1552 #else
1553     return true;
1554 #endif
1555 }
1556
1557 String WebView::standardUserAgentWithApplicationName(const String& applicationName)
1558 {
1559     DEPRECATED_DEFINE_STATIC_LOCAL(String, osVersion, (windowsVersionForUAString()));
1560     DEPRECATED_DEFINE_STATIC_LOCAL(String, webKitVersion, (webKitVersionString()));
1561
1562     return makeString("Mozilla/5.0 (", osVersion, ") AppleWebKit/", webKitVersion, " (KHTML, like Gecko)", applicationName.isEmpty() ? "" : " ", applicationName);
1563 }
1564
1565 Page* WebView::page()
1566 {
1567     return m_page;
1568 }
1569
1570 static HMENU createContextMenuFromItems(const Vector<ContextMenuItem>& items)
1571 {
1572     HMENU menu = ::CreatePopupMenu();
1573
1574     for (auto& item : items) {
1575         UINT flags = 0;
1576
1577         flags |= item.enabled() ? MF_ENABLED : MF_DISABLED;
1578         flags |= item.checked() ? MF_CHECKED : MF_UNCHECKED;
1579
1580         switch (item.type()) {
1581         case ActionType:
1582         case CheckableActionType:
1583             ::AppendMenu(menu, flags | MF_STRING, item.action(), item.title().charactersWithNullTermination().data());
1584             break;
1585         case SeparatorType:
1586             ::AppendMenu(menu, flags | MF_SEPARATOR, item.action(), nullptr);
1587             break;
1588         case SubmenuType:
1589             ::AppendMenu(menu, flags | MF_POPUP, (UINT_PTR)createContextMenuFromItems(item.subMenuItems()), item.title().charactersWithNullTermination().data());
1590             break;
1591         }
1592     }
1593
1594     return menu;
1595 }
1596
1597 HMENU WebView::createContextMenu()
1598 {
1599     auto& contextMenuController = m_page->contextMenuController();
1600
1601     ContextMenu* coreMenu = contextMenuController.contextMenu();
1602     if (!coreMenu)
1603         return nullptr;
1604
1605     HMENU contextMenu = createContextMenuFromItems(coreMenu->items());
1606
1607     COMPtr<IWebUIDelegate> uiDelegate;
1608     if (SUCCEEDED(this->uiDelegate(&uiDelegate))) {
1609         ASSERT(uiDelegate);
1610
1611         COMPtr<WebElementPropertyBag> propertyBag;
1612         propertyBag.adoptRef(WebElementPropertyBag::createInstance(contextMenuController.hitTestResult()));
1613
1614         HMENU newMenu = nullptr;
1615         if (SUCCEEDED(uiDelegate->contextMenuItemsForElement(this, propertyBag.get(), contextMenu, &newMenu))) {
1616             // Make sure to delete the old menu if the delegate returned a new menu.
1617             if (newMenu != contextMenu) {
1618                 ::DestroyMenu(contextMenu);
1619                 contextMenu = newMenu;
1620             }
1621         }
1622     }
1623
1624     return contextMenu;
1625 }
1626
1627 bool WebView::handleContextMenuEvent(WPARAM wParam, LPARAM lParam)
1628 {
1629     // Translate the screen coordinates into window coordinates
1630     POINT coords = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
1631     if (coords.x == -1 || coords.y == -1) {
1632         // The contextMenuController() holds onto the last context menu that was popped up on the
1633         // page until a new one is created. We need to clear this menu before propagating the event
1634         // through the DOM so that we can detect if we create a new menu for this event, since we
1635         // won't create a new menu if the DOM swallows the event and the defaultEventHandler does
1636         // not run.
1637         m_page->contextMenuController().clearContextMenu();
1638
1639         Frame& focusedFrame = m_page->focusController().focusedOrMainFrame();
1640         return focusedFrame.eventHandler().sendContextMenuEventForKey();
1641
1642     } else {
1643         if (!::ScreenToClient(m_viewWindow, &coords))
1644             return false;
1645     }
1646
1647     lParam = MAKELPARAM(coords.x, coords.y);
1648
1649     // Convert coordinates to logical pixels
1650     float scaleFactor = deviceScaleFactor();
1651     float inverseScaleFactor = 1.0f / scaleFactor;
1652     IntPoint logicalCoords(coords);
1653     logicalCoords.scale(inverseScaleFactor, inverseScaleFactor);
1654
1655     m_page->contextMenuController().clearContextMenu();
1656
1657     IntPoint documentPoint(m_page->mainFrame().view()->windowToContents(logicalCoords));
1658     HitTestResult result = m_page->mainFrame().eventHandler().hitTestResultAtPoint(documentPoint);
1659     Frame* targetFrame = result.innerNonSharedNode() ? result.innerNonSharedNode()->document().frame() : &m_page->focusController().focusedOrMainFrame();
1660
1661     targetFrame->view()->setCursor(pointerCursor());
1662     PlatformMouseEvent mouseEvent(m_viewWindow, WM_RBUTTONUP, wParam, makeScaledPoint(IntPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)), deviceScaleFactor()));
1663     bool handledEvent = targetFrame->eventHandler().sendContextMenuEvent(mouseEvent);
1664     if (!handledEvent)
1665         return false;
1666
1667     ContextMenuController& contextMenuController = m_page->contextMenuController();
1668
1669     // Show the menu
1670     ContextMenu* coreMenu = contextMenuController.contextMenu();
1671     if (!coreMenu)
1672         return false;
1673
1674     Frame* frame = contextMenuController.hitTestResult().innerNodeFrame();
1675     if (!frame)
1676         return false;
1677
1678     FrameView* view = frame->view();
1679     if (!view)
1680         return false;
1681
1682     IntPoint logicalPoint = view->contentsToWindow(contextMenuController.hitTestResult().roundedPointInInnerNodeFrame());
1683     logicalPoint.scale(scaleFactor, scaleFactor);
1684
1685     // Translate the point to screen coordinates
1686     POINT point = logicalPoint;
1687     if (!::ClientToScreen(m_viewWindow, &point))
1688         return false;
1689
1690     if (m_currentContextMenu)
1691         ::DestroyMenu(m_currentContextMenu);
1692     m_currentContextMenu = createContextMenu();
1693
1694     MENUINFO menuInfo;
1695     menuInfo.cbSize = sizeof(menuInfo);
1696     menuInfo.fMask = MIM_STYLE;
1697     menuInfo.dwStyle = MNS_NOTIFYBYPOS;
1698     ::SetMenuInfo(m_currentContextMenu, &menuInfo);
1699
1700     BOOL hasCustomMenus = false;
1701     if (m_uiDelegate)
1702         m_uiDelegate->hasCustomMenuImplementation(&hasCustomMenus);
1703
1704     if (hasCustomMenus)
1705         m_uiDelegate->trackCustomPopupMenu((IWebView*)this, m_currentContextMenu, &point);
1706     else {
1707         // Surprisingly, TPM_RIGHTBUTTON means that items are selectable with either the right OR left mouse button
1708         UINT flags = TPM_RIGHTBUTTON | TPM_TOPALIGN | TPM_VERPOSANIMATION | TPM_HORIZONTAL | TPM_LEFTALIGN | TPM_HORPOSANIMATION;
1709         ::TrackPopupMenuEx(m_currentContextMenu, flags, point.x, point.y, m_viewWindow, 0);
1710     }
1711
1712     return true;
1713 }
1714
1715 bool WebView::onMeasureItem(WPARAM /*wParam*/, LPARAM lParam)
1716 {
1717     if (!m_uiDelegate)
1718         return false;
1719
1720     BOOL hasCustomMenus = false;
1721     m_uiDelegate->hasCustomMenuImplementation(&hasCustomMenus);
1722     if (!hasCustomMenus)
1723         return false;
1724
1725     m_uiDelegate->measureCustomMenuItem((IWebView*)this, (void*)lParam);
1726     return true;
1727 }
1728
1729 bool WebView::onDrawItem(WPARAM /*wParam*/, LPARAM lParam)
1730 {
1731     if (!m_uiDelegate)
1732         return false;
1733
1734     BOOL hasCustomMenus = false;
1735     m_uiDelegate->hasCustomMenuImplementation(&hasCustomMenus);
1736     if (!hasCustomMenus)
1737         return false;
1738
1739     m_uiDelegate->drawCustomMenuItem((IWebView*)this, (void*)lParam);
1740     return true;
1741 }
1742
1743 bool WebView::onInitMenuPopup(WPARAM wParam, LPARAM /*lParam*/)
1744 {
1745     if (!m_uiDelegate)
1746         return false;
1747
1748     HMENU menu = (HMENU)wParam;
1749     if (!menu)
1750         return false;
1751
1752     BOOL hasCustomMenus = false;
1753     m_uiDelegate->hasCustomMenuImplementation(&hasCustomMenus);
1754     if (!hasCustomMenus)
1755         return false;
1756
1757     m_uiDelegate->addCustomMenuDrawingData((IWebView*)this, menu);
1758     return true;
1759 }
1760
1761 bool WebView::onUninitMenuPopup(WPARAM wParam, LPARAM /*lParam*/)
1762 {
1763     if (!m_uiDelegate)
1764         return false;
1765
1766     HMENU menu = (HMENU)wParam;
1767     if (!menu)
1768         return false;
1769
1770     BOOL hasCustomMenus = false;
1771     m_uiDelegate->hasCustomMenuImplementation(&hasCustomMenus);
1772     if (!hasCustomMenus)
1773         return false;
1774
1775     m_uiDelegate->cleanUpCustomMenuDrawingData((IWebView*)this, menu);
1776     return true;
1777 }
1778
1779 void WebView::onMenuCommand(WPARAM wParam, LPARAM lParam)
1780 {
1781     HMENU hMenu = reinterpret_cast<HMENU>(lParam);
1782     unsigned index = static_cast<unsigned>(wParam);
1783
1784     MENUITEMINFO menuItemInfo = { 0 };
1785     menuItemInfo.cbSize = sizeof(menuItemInfo);
1786     menuItemInfo.fMask = MIIM_STRING;
1787     ::GetMenuItemInfo(hMenu, index, true, &menuItemInfo);
1788
1789     auto buffer = std::make_unique<WCHAR[]>(menuItemInfo.cch + 1);
1790     menuItemInfo.dwTypeData = buffer.get();
1791     menuItemInfo.cch++;
1792     menuItemInfo.fMask |= MIIM_ID;
1793
1794     ::GetMenuItemInfo(hMenu, index, true, &menuItemInfo);
1795
1796     ::DestroyMenu(m_currentContextMenu);
1797     m_currentContextMenu = nullptr;
1798
1799     String title(buffer.get(), menuItemInfo.cch);
1800     ContextMenuAction action = static_cast<ContextMenuAction>(menuItemInfo.wID);
1801
1802     if (action >= ContextMenuItemBaseApplicationTag) {
1803         if (m_uiDelegate) {
1804             COMPtr<WebElementPropertyBag> propertyBag;
1805             propertyBag.adoptRef(WebElementPropertyBag::createInstance(m_page->contextMenuController().hitTestResult()));
1806
1807             m_uiDelegate->contextMenuItemSelected(this, &menuItemInfo, propertyBag.get());
1808         }
1809         return;
1810     }
1811
1812     m_page->contextMenuController().contextMenuItemSelected(action, title);
1813 }
1814
1815 bool WebView::handleMouseEvent(UINT message, WPARAM wParam, LPARAM lParam)
1816 {
1817     static LONG globalClickCount;
1818     static IntPoint globalPrevPoint;
1819     static MouseButton globalPrevButton;
1820     static LONG globalPrevMouseDownTime;
1821
1822     if (message == WM_CANCELMODE) {
1823         m_page->mainFrame().eventHandler().lostMouseCapture();
1824         return true;
1825     }
1826
1827     // Create our event.
1828     // On WM_MOUSELEAVE we need to create a mouseout event, so we force the position
1829     // of the event to be at (MINSHORT, MINSHORT).
1830     LPARAM position = (message == WM_MOUSELEAVE) ? ((MINSHORT << 16) | MINSHORT) : makeScaledPoint(IntPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)), deviceScaleFactor());
1831     PlatformMouseEvent mouseEvent(m_viewWindow, message, wParam, position, m_mouseActivated);
1832
1833     setMouseActivated(false);
1834
1835     bool insideThreshold = abs(globalPrevPoint.x() - mouseEvent.position().x()) < ::GetSystemMetrics(SM_CXDOUBLECLK) &&
1836                            abs(globalPrevPoint.y() - mouseEvent.position().y()) < ::GetSystemMetrics(SM_CYDOUBLECLK);
1837     LONG messageTime = ::GetMessageTime();
1838
1839     bool handled = false;
1840
1841     if (message == WM_LBUTTONDOWN || message == WM_MBUTTONDOWN || message == WM_RBUTTONDOWN) {
1842         // FIXME: I'm not sure if this is the "right" way to do this
1843         // but without this call, we never become focused since we don't allow
1844         // the default handling of mouse events.
1845         SetFocus(m_viewWindow);
1846
1847         // Always start capturing events when the mouse goes down in our HWND.
1848         ::SetCapture(m_viewWindow);
1849
1850         if (((messageTime - globalPrevMouseDownTime) < (LONG)::GetDoubleClickTime()) && 
1851             insideThreshold &&
1852             mouseEvent.button() == globalPrevButton)
1853             globalClickCount++;
1854         else
1855             // Reset the click count.
1856             globalClickCount = 1;
1857         globalPrevMouseDownTime = messageTime;
1858         globalPrevButton = mouseEvent.button();
1859         globalPrevPoint = mouseEvent.position();
1860         
1861         mouseEvent.setClickCount(globalClickCount);
1862         handled = m_page->mainFrame().eventHandler().handleMousePressEvent(mouseEvent);
1863     } else if (message == WM_LBUTTONDBLCLK || message == WM_MBUTTONDBLCLK || message == WM_RBUTTONDBLCLK) {
1864         globalClickCount++;
1865         mouseEvent.setClickCount(globalClickCount);
1866         handled = m_page->mainFrame().eventHandler().handleMousePressEvent(mouseEvent);
1867     } else if (message == WM_LBUTTONUP || message == WM_MBUTTONUP || message == WM_RBUTTONUP) {
1868         // Record the global position and the button of the up.
1869         globalPrevButton = mouseEvent.button();
1870         globalPrevPoint = mouseEvent.position();
1871         mouseEvent.setClickCount(globalClickCount);
1872         m_page->mainFrame().eventHandler().handleMouseReleaseEvent(mouseEvent);
1873         ::ReleaseCapture();
1874     } else if (message == WM_MOUSELEAVE && m_mouseOutTracker) {
1875         // Once WM_MOUSELEAVE is fired windows clears this tracker
1876         // so there is no need to disable it ourselves.
1877         m_mouseOutTracker.reset();
1878         m_page->mainFrame().eventHandler().mouseMoved(mouseEvent);
1879         handled = true;
1880     } else if (message == WM_MOUSEMOVE) {
1881         if (!insideThreshold)
1882             globalClickCount = 0;
1883         mouseEvent.setClickCount(globalClickCount);
1884         handled = m_page->mainFrame().eventHandler().mouseMoved(mouseEvent);
1885         if (!m_mouseOutTracker) {
1886             m_mouseOutTracker = std::make_unique<TRACKMOUSEEVENT>();
1887             m_mouseOutTracker->cbSize = sizeof(TRACKMOUSEEVENT);
1888             m_mouseOutTracker->dwFlags = TME_LEAVE;
1889             m_mouseOutTracker->hwndTrack = m_viewWindow;
1890             ::TrackMouseEvent(m_mouseOutTracker.get());
1891         }
1892     }
1893     return handled;
1894 }
1895
1896 bool WebView::gestureNotify(WPARAM wParam, LPARAM lParam)
1897 {
1898     GESTURENOTIFYSTRUCT* gn = reinterpret_cast<GESTURENOTIFYSTRUCT*>(lParam);
1899
1900     Frame* coreFrame = core(m_mainFrame);
1901     if (!coreFrame)
1902         return false;
1903
1904     ScrollView* view = coreFrame->view();
1905     if (!view)
1906         return false;
1907
1908     // If we don't have this function, we shouldn't be receiving this message
1909     ASSERT(SetGestureConfigPtr());
1910
1911     bool hitScrollbar = false;
1912     POINT gestureBeginPoint = {gn->ptsLocation.x, gn->ptsLocation.y};
1913
1914     float scaleFactor = deviceScaleFactor();
1915     float inverseScaleFactor = 1.0f / scaleFactor;
1916     IntPoint logicalGestureBeginPoint(gestureBeginPoint);
1917     logicalGestureBeginPoint.scale(inverseScaleFactor, inverseScaleFactor);
1918
1919     HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowUserAgentShadowContent);
1920     for (Frame* childFrame = &m_page->mainFrame(); childFrame; childFrame = EventHandler::subframeForTargetNode(m_gestureTargetNode.get())) {
1921         FrameView* frameView = childFrame->view();
1922         if (!frameView)
1923             break;
1924         RenderView* renderView = childFrame->document()->renderView();
1925         if (!renderView)
1926             break;
1927         RenderLayer* layer = renderView->layer();
1928         if (!layer)
1929             break;
1930
1931         HitTestResult result(frameView->screenToContents(logicalGestureBeginPoint));
1932         layer->hitTest(request, result);
1933         m_gestureTargetNode = result.innerNode();
1934
1935         if (!hitScrollbar)
1936             hitScrollbar = result.scrollbar();
1937     }
1938
1939     if (!hitScrollbar) {
1940         // The hit testing above won't detect if we've hit the main frame's vertical scrollbar. Check that manually now.
1941         RECT webViewRect;
1942         GetWindowRect(m_viewWindow, &webViewRect);
1943         hitScrollbar = (view->verticalScrollbar() && (gestureBeginPoint.x > (webViewRect.right - view->verticalScrollbar()->theme().scrollbarThickness()))) 
1944             || (view->horizontalScrollbar() && (gestureBeginPoint.y > (webViewRect.bottom - view->horizontalScrollbar()->theme().scrollbarThickness())));  
1945     }
1946
1947     bool canBeScrolled = false;
1948     if (m_gestureTargetNode) {
1949         for (RenderObject* renderer = m_gestureTargetNode->renderer(); renderer; renderer = renderer->parent()) {
1950             if (is<RenderBox>(*renderer) && downcast<RenderBox>(*renderer).canBeScrolledAndHasScrollableArea()) {
1951                 canBeScrolled = true;
1952                 break;
1953             }
1954         }
1955     } else {
1956         // We've hit the main document but not any of the document's content
1957         if (core(m_mainFrame)->view()->isScrollable())
1958             canBeScrolled = true;
1959     }
1960
1961     // We always allow two-fingered panning with inertia and a gutter (which limits movement to one
1962     // direction in most cases).
1963     DWORD dwPanWant = GC_PAN | GC_PAN_WITH_INERTIA | GC_PAN_WITH_GUTTER;
1964     DWORD dwPanBlock = 0;
1965
1966     if (hitScrollbar || !canBeScrolled) {
1967         // The part of the page under the gesture can't be scrolled, or the gesture is on a scrollbar.
1968         // Disallow single-fingered panning in this case so we'll fall back to the default
1969         // behavior (which allows the scrollbar thumb to be dragged, text selections to be made, etc.).
1970         dwPanBlock = GC_PAN_WITH_SINGLE_FINGER_VERTICALLY | GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY;
1971     } else {
1972         // The part of the page the gesture is under can be scrolled, and we're not under a scrollbar.
1973         // Allow single-fingered vertical panning in this case, so the user will be able to pan the page
1974         // with one or two fingers.
1975         dwPanWant |= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY;
1976
1977         // Disable single-fingered horizontal panning only if the target node is text.
1978         if (m_gestureTargetNode && m_gestureTargetNode->isTextNode())
1979             dwPanBlock = GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY;
1980         else
1981             dwPanWant |= GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY;
1982     }
1983
1984     GESTURECONFIG gc = { GID_PAN, dwPanWant, dwPanBlock };
1985     return SetGestureConfigPtr()(m_viewWindow, 0, 1, &gc, sizeof(GESTURECONFIG));
1986 }
1987
1988 bool WebView::gesture(WPARAM wParam, LPARAM lParam) 
1989 {
1990     // We want to bail out if we don't have either of these functions
1991     if (!GetGestureInfoPtr() || !CloseGestureInfoHandlePtr())
1992         return false;
1993
1994     HGESTUREINFO gestureHandle = reinterpret_cast<HGESTUREINFO>(lParam);
1995     
1996     GESTUREINFO gi = {0};
1997     gi.cbSize = sizeof(GESTUREINFO);
1998
1999     if (!GetGestureInfoPtr()(gestureHandle, reinterpret_cast<PGESTUREINFO>(&gi)))
2000         return false;
2001
2002     switch (gi.dwID) {
2003     case GID_BEGIN:
2004         m_lastPanX = gi.ptsLocation.x;
2005         m_lastPanY = gi.ptsLocation.y;
2006
2007         break;
2008     case GID_END:
2009         m_gestureTargetNode = nullptr;
2010         break;
2011     case GID_PAN: {
2012         if (gi.dwFlags & GF_BEGIN) {
2013             m_lastPanX = gi.ptsLocation.x;
2014             m_lastPanY = gi.ptsLocation.y;
2015         }
2016         // Where are the fingers currently?
2017         long currentX = gi.ptsLocation.x;
2018         long currentY = gi.ptsLocation.y;
2019         // How far did we pan in each direction?
2020         long deltaX = currentX - m_lastPanX;
2021         long deltaY = currentY - m_lastPanY;
2022         // Calculate the overpan for window bounce
2023         m_yOverpan -= m_lastPanY - currentY;
2024         m_xOverpan -= m_lastPanX - currentX;
2025         // Update our class variables with updated values
2026         m_lastPanX = currentX;
2027         m_lastPanY = currentY;
2028
2029         Frame* coreFrame = core(m_mainFrame);
2030         if (!coreFrame) {
2031             CloseGestureInfoHandlePtr()(gestureHandle);
2032             return false;
2033         }
2034
2035         ScrollableArea* scrolledArea = 0;
2036         float scaleFactor = deviceScaleFactor();
2037         IntSize logicalScrollDelta(-deltaX * scaleFactor, -deltaY * scaleFactor);
2038
2039         RenderLayer* scrollableLayer = nullptr;
2040         if (m_gestureTargetNode && m_gestureTargetNode->renderer() && m_gestureTargetNode->renderer()->enclosingLayer())
2041             scrollableLayer = m_gestureTargetNode->renderer()->enclosingLayer()->enclosingScrollableLayer();
2042
2043         if (!scrollableLayer) {
2044             // We might directly hit the document without hitting any nodes
2045             coreFrame->view()->scrollBy(logicalScrollDelta);
2046             scrolledArea = coreFrame->view();
2047         } else
2048             scrollableLayer->scrollByRecursively(logicalScrollDelta, WebCore::RenderLayer::ScrollOffsetClamped, &scrolledArea);
2049
2050         if (!(UpdatePanningFeedbackPtr() && BeginPanningFeedbackPtr() && EndPanningFeedbackPtr())) {
2051             CloseGestureInfoHandlePtr()(gestureHandle);
2052             return true;
2053         }
2054
2055         // Handle overpanning
2056         if (gi.dwFlags & GF_BEGIN) {
2057             BeginPanningFeedbackPtr()(m_viewWindow);
2058             m_yOverpan = 0;
2059             m_xOverpan = 0;
2060         } else if (gi.dwFlags & GF_END) {
2061             EndPanningFeedbackPtr()(m_viewWindow, true);
2062             m_yOverpan = 0;
2063             m_xOverpan = 0;
2064         }
2065
2066         if (!scrolledArea) {
2067             CloseGestureInfoHandlePtr()(gestureHandle);
2068             return true;
2069         }
2070
2071         Scrollbar* vertScrollbar = scrolledArea->verticalScrollbar();
2072
2073         int ypan = 0;
2074         int xpan = 0;
2075
2076         if (vertScrollbar && (!vertScrollbar->currentPos() || vertScrollbar->currentPos() >= vertScrollbar->maximum()))
2077             ypan = m_yOverpan;
2078
2079         Scrollbar* horiScrollbar = scrolledArea->horizontalScrollbar();
2080
2081         if (horiScrollbar && (!horiScrollbar->currentPos() || horiScrollbar->currentPos() >= horiScrollbar->maximum()))
2082             xpan = m_xOverpan;
2083
2084         UpdatePanningFeedbackPtr()(m_viewWindow, xpan, ypan, gi.dwFlags & GF_INERTIA);
2085
2086         CloseGestureInfoHandlePtr()(gestureHandle);
2087         return true;
2088     }
2089     default:
2090         break;
2091     }
2092
2093     // If we get to this point, the gesture has not been handled. We forward
2094     // the call to DefWindowProc by returning false, and we don't need to 
2095     // to call CloseGestureInfoHandle. 
2096     // http://msdn.microsoft.com/en-us/library/dd353228(VS.85).aspx
2097     return false;
2098 }
2099
2100 bool WebView::mouseWheel(WPARAM wParam, LPARAM lParam, bool isMouseHWheel)
2101 {
2102     // Ctrl+Mouse wheel doesn't ever go into WebCore.  It is used to
2103     // zoom instead (Mac zooms the whole Desktop, but Windows browsers trigger their
2104     // own local zoom modes for Ctrl+wheel).
2105     if (wParam & MK_CONTROL) {
2106         short delta = short(HIWORD(wParam));
2107         if (delta < 0)
2108             makeTextSmaller(0);
2109         else
2110             makeTextLarger(0);
2111         return true;
2112     }
2113     
2114     // 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.
2115     HWND focusedWindow = GetFocus();
2116     if (focusedWindow && focusedWindow != m_viewWindow) {
2117         // 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).
2118         WCHAR className[256];
2119
2120         // Make sure truncation won't affect the comparison.
2121         ASSERT(WTF_ARRAY_LENGTH(className) > wcslen(PopupMenuWin::popupClassName()));
2122
2123         if (GetClassNameW(focusedWindow, className, WTF_ARRAY_LENGTH(className)) && !wcscmp(className, PopupMenuWin::popupClassName())) {
2124             // We don't let the WebView scroll here for two reasons - 1) To match Firefox behavior, 2) If we do scroll, we lose the
2125             // focus ring around the select menu.
2126             SetFocus(m_viewWindow);
2127             return true;
2128         }
2129     }
2130
2131     PlatformWheelEvent wheelEvent(m_viewWindow, wParam, lParam, isMouseHWheel);
2132     Frame* coreFrame = core(m_mainFrame);
2133     if (!coreFrame)
2134         return false;
2135
2136     return coreFrame->eventHandler().handleWheelEvent(wheelEvent);
2137 }
2138
2139 bool WebView::verticalScroll(WPARAM wParam, LPARAM /*lParam*/)
2140 {
2141     ScrollDirection direction;
2142     ScrollGranularity granularity;
2143     switch (LOWORD(wParam)) {
2144     case SB_LINEDOWN:
2145         granularity = ScrollByLine;
2146         direction = ScrollDown;
2147         break;
2148     case SB_LINEUP:
2149         granularity = ScrollByLine;
2150         direction = ScrollUp;
2151         break;
2152     case SB_PAGEDOWN:
2153         granularity = ScrollByDocument;
2154         direction = ScrollDown;
2155         break;
2156     case SB_PAGEUP:
2157         granularity = ScrollByDocument;
2158         direction = ScrollUp;
2159         break;
2160     default:
2161         return false;
2162         break;
2163     }
2164     
2165     Frame& frame = m_page->focusController().focusedOrMainFrame();
2166     return frame.eventHandler().scrollRecursively(direction, granularity);
2167 }
2168
2169 bool WebView::horizontalScroll(WPARAM wParam, LPARAM /*lParam*/)
2170 {
2171     ScrollDirection direction;
2172     ScrollGranularity granularity;
2173     switch (LOWORD(wParam)) {
2174     case SB_LINELEFT:
2175         granularity = ScrollByLine;
2176         direction = ScrollLeft;
2177         break;
2178     case SB_LINERIGHT:
2179         granularity = ScrollByLine;
2180         direction = ScrollRight;
2181         break;
2182     case SB_PAGELEFT:
2183         granularity = ScrollByDocument;
2184         direction = ScrollLeft;
2185         break;
2186     case SB_PAGERIGHT:
2187         granularity = ScrollByDocument;
2188         direction = ScrollRight;
2189         break;
2190     default:
2191         return false;
2192     }
2193
2194     Frame& frame = m_page->focusController().focusedOrMainFrame();
2195     return frame.eventHandler().scrollRecursively(direction, granularity);
2196 }
2197
2198
2199 bool WebView::execCommand(WPARAM wParam, LPARAM /*lParam*/)
2200 {
2201     Frame& frame = m_page->focusController().focusedOrMainFrame();
2202     switch (LOWORD(wParam)) {
2203         case SelectAll:
2204             return frame.editor().command("SelectAll").execute();
2205         case Undo:
2206             return frame.editor().command("Undo").execute();
2207         case Redo:
2208             return frame.editor().command("Redo").execute();
2209     }
2210     return false;
2211 }
2212
2213 bool WebView::keyUp(WPARAM virtualKeyCode, LPARAM keyData, bool systemKeyDown)
2214 {
2215     PlatformKeyboardEvent keyEvent(m_viewWindow, virtualKeyCode, keyData, PlatformEvent::KeyUp, systemKeyDown);
2216
2217     Frame& frame = m_page->focusController().focusedOrMainFrame();
2218     m_currentCharacterCode = 0;
2219
2220     return frame.eventHandler().keyEvent(keyEvent);
2221 }
2222
2223 static const unsigned CtrlKey = 1 << 0;
2224 static const unsigned AltKey = 1 << 1;
2225 static const unsigned ShiftKey = 1 << 2;
2226
2227
2228 struct KeyDownEntry {
2229     unsigned virtualKey;
2230     unsigned modifiers;
2231     const char* name;
2232 };
2233
2234 struct KeyPressEntry {
2235     unsigned charCode;
2236     unsigned modifiers;
2237     const char* name;
2238 };
2239
2240 static const KeyDownEntry keyDownEntries[] = {
2241     { VK_LEFT,   0,                  "MoveLeft"                                    },
2242     { VK_LEFT,   ShiftKey,           "MoveLeftAndModifySelection"                  },
2243     { VK_LEFT,   CtrlKey,            "MoveWordLeft"                                },
2244     { VK_LEFT,   CtrlKey | ShiftKey, "MoveWordLeftAndModifySelection"              },
2245     { VK_RIGHT,  0,                  "MoveRight"                                   },
2246     { VK_RIGHT,  ShiftKey,           "MoveRightAndModifySelection"                 },
2247     { VK_RIGHT,  CtrlKey,            "MoveWordRight"                               },
2248     { VK_RIGHT,  CtrlKey | ShiftKey, "MoveWordRightAndModifySelection"             },
2249     { VK_UP,     0,                  "MoveUp"                                      },
2250     { VK_UP,     ShiftKey,           "MoveUpAndModifySelection"                    },
2251     { VK_PRIOR,  ShiftKey,           "MovePageUpAndModifySelection"                },
2252     { VK_DOWN,   0,                  "MoveDown"                                    },
2253     { VK_DOWN,   ShiftKey,           "MoveDownAndModifySelection"                  },
2254     { VK_NEXT,   ShiftKey,           "MovePageDownAndModifySelection"              },
2255     { VK_PRIOR,  0,                  "MovePageUp"                                  },
2256     { VK_NEXT,   0,                  "MovePageDown"                                },
2257     { VK_HOME,   0,                  "MoveToBeginningOfLine"                       },
2258     { VK_HOME,   ShiftKey,           "MoveToBeginningOfLineAndModifySelection"     },
2259     { VK_HOME,   CtrlKey,            "MoveToBeginningOfDocument"                   },
2260     { VK_HOME,   CtrlKey | ShiftKey, "MoveToBeginningOfDocumentAndModifySelection" },
2261
2262     { VK_END,    0,                  "MoveToEndOfLine"                             },
2263     { VK_END,    ShiftKey,           "MoveToEndOfLineAndModifySelection"           },
2264     { VK_END,    CtrlKey,            "MoveToEndOfDocument"                         },
2265     { VK_END,    CtrlKey | ShiftKey, "MoveToEndOfDocumentAndModifySelection"       },
2266
2267     { VK_BACK,   0,                  "DeleteBackward"                              },
2268     { VK_BACK,   ShiftKey,           "DeleteBackward"                              },
2269     { VK_DELETE, 0,                  "DeleteForward"                               },
2270     { VK_BACK,   CtrlKey,            "DeleteWordBackward"                          },
2271     { VK_DELETE, CtrlKey,            "DeleteWordForward"                           },
2272     
2273     { 'B',       CtrlKey,            "ToggleBold"                                  },
2274     { 'I',       CtrlKey,            "ToggleItalic"                                },
2275
2276     { VK_ESCAPE, 0,                  "Cancel"                                      },
2277     { VK_OEM_PERIOD, CtrlKey,        "Cancel"                                      },
2278     { VK_TAB,    0,                  "InsertTab"                                   },
2279     { VK_TAB,    ShiftKey,           "InsertBacktab"                               },
2280     { VK_RETURN, 0,                  "InsertNewline"                               },
2281     { VK_RETURN, CtrlKey,            "InsertNewline"                               },
2282     { VK_RETURN, AltKey,             "InsertNewline"                               },
2283     { VK_RETURN, ShiftKey,           "InsertNewline"                               },
2284     { VK_RETURN, AltKey | ShiftKey,  "InsertNewline"                               },
2285
2286     // It's not quite clear whether clipboard shortcuts and Undo/Redo should be handled
2287     // in the application or in WebKit. We chose WebKit.
2288     { 'C',       CtrlKey,            "Copy"                                        },
2289     { 'V',       CtrlKey,            "Paste"                                       },
2290     { 'X',       CtrlKey,            "Cut"                                         },
2291     { 'A',       CtrlKey,            "SelectAll"                                   },
2292     { VK_INSERT, CtrlKey,            "Copy"                                        },
2293     { VK_DELETE, ShiftKey,           "Cut"                                         },
2294     { VK_INSERT, ShiftKey,           "Paste"                                       },
2295     { 'Z',       CtrlKey,            "Undo"                                        },
2296     { 'Z',       CtrlKey | ShiftKey, "Redo"                                        },
2297 };
2298
2299 static const KeyPressEntry keyPressEntries[] = {
2300     { '\t',   0,                  "InsertTab"                                   },
2301     { '\t',   ShiftKey,           "InsertBacktab"                               },
2302     { '\r',   0,                  "InsertNewline"                               },
2303     { '\r',   CtrlKey,            "InsertNewline"                               },
2304     { '\r',   AltKey,             "InsertNewline"                               },
2305     { '\r',   ShiftKey,           "InsertNewline"                               },
2306     { '\r',   AltKey | ShiftKey,  "InsertNewline"                               },
2307 };
2308
2309 const char* WebView::interpretKeyEvent(const KeyboardEvent* evt)
2310 {
2311     ASSERT(evt->type() == eventNames().keydownEvent || evt->type() == eventNames().keypressEvent);
2312
2313     static HashMap<int, const char*>* keyDownCommandsMap = 0;
2314     static HashMap<int, const char*>* keyPressCommandsMap = 0;
2315
2316     if (!keyDownCommandsMap) {
2317         keyDownCommandsMap = new HashMap<int, const char*>;
2318         keyPressCommandsMap = new HashMap<int, const char*>;
2319
2320         for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyDownEntries); ++i)
2321             keyDownCommandsMap->set(keyDownEntries[i].modifiers << 16 | keyDownEntries[i].virtualKey, keyDownEntries[i].name);
2322
2323         for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyPressEntries); ++i)
2324             keyPressCommandsMap->set(keyPressEntries[i].modifiers << 16 | keyPressEntries[i].charCode, keyPressEntries[i].name);
2325     }
2326
2327     unsigned modifiers = 0;
2328     if (evt->shiftKey())
2329         modifiers |= ShiftKey;
2330     if (evt->altKey())
2331         modifiers |= AltKey;
2332     if (evt->ctrlKey())
2333         modifiers |= CtrlKey;
2334
2335     if (evt->type() == eventNames().keydownEvent) {
2336         int mapKey = modifiers << 16 | evt->keyCode();
2337         return mapKey ? keyDownCommandsMap->get(mapKey) : 0;
2338     }
2339
2340     int mapKey = modifiers << 16 | evt->charCode();
2341     return mapKey ? keyPressCommandsMap->get(mapKey) : 0;
2342 }
2343
2344 bool WebView::handleEditingKeyboardEvent(KeyboardEvent* evt)
2345 {
2346     Node* node = evt->target()->toNode();
2347     ASSERT(node);
2348     Frame* frame = node->document().frame();
2349     ASSERT(frame);
2350
2351     const PlatformKeyboardEvent* keyEvent = evt->keyEvent();
2352     if (!keyEvent || keyEvent->isSystemKey())  // do not treat this as text input if it's a system key event
2353         return false;
2354
2355     Editor::Command command = frame->editor().command(interpretKeyEvent(evt));
2356
2357     if (keyEvent->type() == PlatformEvent::RawKeyDown) {
2358         // WebKit doesn't have enough information about mode to decide how commands that just insert text if executed via Editor should be treated,
2359         // so we leave it upon WebCore to either handle them immediately (e.g. Tab that changes focus) or let a keypress event be generated
2360         // (e.g. Tab that inserts a Tab character, or Enter).
2361         return !command.isTextInsertion() && command.execute(evt);
2362     }
2363
2364      if (command.execute(evt))
2365         return true;
2366
2367     // Don't insert null or control characters as they can result in unexpected behaviour
2368     if (evt->charCode() < ' ')
2369         return false;
2370
2371     return frame->editor().insertText(evt->keyEvent()->text(), evt);
2372 }
2373
2374 bool WebView::keyDown(WPARAM virtualKeyCode, LPARAM keyData, bool systemKeyDown)
2375 {
2376 #if ENABLE(FULLSCREEN_API)
2377     // Trap the ESC key when in full screen mode.
2378     if (virtualKeyCode == VK_ESCAPE && isFullScreen()) {
2379         m_fullscreenController->exitFullScreen();
2380         return false;
2381     }
2382 #endif
2383     Frame& frame = m_page->focusController().focusedOrMainFrame();
2384
2385     PlatformKeyboardEvent keyEvent(m_viewWindow, virtualKeyCode, keyData, PlatformEvent::RawKeyDown, systemKeyDown);
2386     bool handled = frame.eventHandler().keyEvent(keyEvent);
2387
2388     // These events cannot be canceled, and we have no default handling for them.
2389     // FIXME: match IE list more closely, see <http://msdn2.microsoft.com/en-us/library/ms536938.aspx>.
2390     if (systemKeyDown && virtualKeyCode != VK_RETURN)
2391         return false;
2392
2393     if (handled) {
2394         // FIXME: remove WM_UNICHAR, too
2395         MSG msg;
2396         // WM_SYSCHAR events should not be removed, because access keys are implemented in WebCore in WM_SYSCHAR handler.
2397         if (!systemKeyDown)
2398             ::PeekMessage(&msg, m_viewWindow, WM_CHAR, WM_CHAR, PM_REMOVE);
2399         return true;
2400     }
2401
2402     // We need to handle back/forward using either Ctrl+Left/Right Arrow keys.
2403     // FIXME: This logic should probably be in EventHandler::defaultArrowEventHandler().
2404     // FIXME: Should check that other modifiers aren't pressed.
2405     if (virtualKeyCode == VK_RIGHT && keyEvent.ctrlKey())
2406         return m_page->backForward().goForward();
2407     if (virtualKeyCode == VK_LEFT && keyEvent.ctrlKey())
2408         return m_page->backForward().goBack();
2409
2410     // Need to scroll the page if the arrow keys, pgup/dn, or home/end are hit.
2411     ScrollDirection direction;
2412     ScrollGranularity granularity;
2413     switch (virtualKeyCode) {
2414         case VK_LEFT:
2415             granularity = ScrollByLine;
2416             direction = ScrollLeft;
2417             break;
2418         case VK_RIGHT:
2419             granularity = ScrollByLine;
2420             direction = ScrollRight;
2421             break;
2422         case VK_UP:
2423             granularity = ScrollByLine;
2424             direction = ScrollUp;
2425             break;
2426         case VK_DOWN:
2427             granularity = ScrollByLine;
2428             direction = ScrollDown;
2429             break;
2430         case VK_HOME:
2431             granularity = ScrollByDocument;
2432             direction = ScrollUp;
2433             break;
2434         case VK_END:
2435             granularity = ScrollByDocument;
2436             direction = ScrollDown;
2437             break;
2438         case VK_PRIOR:
2439             granularity = ScrollByPage;
2440             direction = ScrollUp;
2441             break;
2442         case VK_NEXT:
2443             granularity = ScrollByPage;
2444             direction = ScrollDown;
2445             break;
2446         default:
2447             return false;
2448     }
2449
2450     return frame.eventHandler().scrollRecursively(direction, granularity);
2451 }
2452
2453 bool WebView::keyPress(WPARAM charCode, LPARAM keyData, bool systemKeyDown)
2454 {
2455     Frame& frame = m_page->focusController().focusedOrMainFrame();
2456
2457     PlatformKeyboardEvent keyEvent(m_viewWindow, charCode, keyData, PlatformEvent::Char, systemKeyDown);
2458     // IE does not dispatch keypress event for WM_SYSCHAR.
2459     if (systemKeyDown)
2460         return frame.eventHandler().handleAccessKey(keyEvent);
2461     return frame.eventHandler().keyEvent(keyEvent);
2462 }
2463
2464 void WebView::setIsBeingDestroyed()
2465 {
2466     m_isBeingDestroyed = true;
2467
2468     // Remove our this pointer from the window so we won't try to handle any more window messages.
2469     // See <http://webkit.org/b/55054>.
2470     ::SetWindowLongPtrW(m_viewWindow, 0, 0);
2471 }
2472
2473 void WebView::setShouldInvertColors(bool shouldInvertColors)
2474 {
2475     if (m_shouldInvertColors == shouldInvertColors)
2476         return;
2477
2478     m_shouldInvertColors = shouldInvertColors;
2479
2480 #if USE(CA)
2481     if (m_layerTreeHost)
2482         m_layerTreeHost->setShouldInvertColors(shouldInvertColors);
2483 #endif
2484
2485     RECT windowRect = {0};
2486     frameRect(&windowRect);
2487
2488     // repaint expects logical pixels, so rescale here.
2489     IntRect logicalRect(windowRect);
2490     logicalRect.scale(1.0f / deviceScaleFactor());
2491     repaint(logicalRect, true, true);
2492 }
2493
2494 bool WebView::registerWebViewWindowClass()
2495 {
2496     static bool haveRegisteredWindowClass = false;
2497     if (haveRegisteredWindowClass)
2498         return true;
2499
2500     haveRegisteredWindowClass = true;
2501
2502     WNDCLASSEX wcex;
2503
2504     wcex.cbSize = sizeof(WNDCLASSEX);
2505
2506     wcex.style          = CS_DBLCLKS;
2507     wcex.lpfnWndProc    = WebViewWndProc;
2508     wcex.cbClsExtra     = 0;
2509     wcex.cbWndExtra     = sizeof(WebView*);
2510     wcex.hInstance      = gInstance;
2511     wcex.hIcon          = 0;
2512     wcex.hCursor        = ::LoadCursor(0, IDC_ARROW);
2513     wcex.hbrBackground  = 0;
2514     wcex.lpszMenuName   = 0;
2515     wcex.lpszClassName  = kWebViewWindowClassName;
2516     wcex.hIconSm        = 0;
2517
2518     return !!RegisterClassEx(&wcex);
2519 }
2520
2521 static HWND findTopLevelParent(HWND window)
2522 {
2523     if (!window)
2524         return 0;
2525
2526     HWND current = window;
2527     for (HWND parent = GetParent(current); current; current = parent, parent = GetParent(parent))
2528         if (!parent || !(GetWindowLongPtr(current, GWL_STYLE) & (WS_POPUP | WS_CHILD)))
2529             return current;
2530     ASSERT_NOT_REACHED();
2531     return 0;
2532 }
2533
2534 LRESULT CALLBACK WebView::WebViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
2535 {
2536     LRESULT lResult = 0;
2537     LONG_PTR longPtr = GetWindowLongPtr(hWnd, 0);
2538     WebView* webView = reinterpret_cast<WebView*>(longPtr);
2539     WebFrame* mainFrameImpl = webView ? webView->topLevelFrame() : 0;
2540     if (!mainFrameImpl)
2541         return DefWindowProc(hWnd, message, wParam, lParam);
2542
2543     // We shouldn't be trying to handle any window messages after WM_DESTROY.
2544     // See <http://webkit.org/b/55054>.
2545     ASSERT(!webView->isBeingDestroyed());
2546
2547     // hold a ref, since the WebView could go away in an event handler.
2548     COMPtr<WebView> protector(webView);
2549     ASSERT(webView);
2550
2551     // Windows Media Player has a modal message loop that will deliver messages
2552     // to us at inappropriate times and we will crash if we handle them when:
2553     // they are delivered. We repost paint messages so that we eventually get
2554     // a chance to paint once the modal loop has exited, but other messages
2555     // aren't safe to repost, so we just drop them.
2556     if (PluginView::isCallingPlugin()) {
2557         if (message == WM_PAINT)
2558             PostMessage(hWnd, message, wParam, lParam);
2559         return 0;
2560     }
2561
2562     bool handled = true;
2563
2564     switch (message) {
2565         case WM_PAINT: {
2566 #if USE(DIRECT2D)
2567             webView->paintWithDirect2D();
2568 #else
2569             webView->paint(0, 0);
2570 #endif
2571             if (webView->usesLayeredWindow())
2572                 webView->performLayeredWindowUpdate();
2573             break;
2574         }
2575         case WM_ERASEBKGND:
2576             // Don't perform a background erase.
2577             handled = true;
2578             lResult = 1;
2579             break;
2580         case WM_PRINTCLIENT:
2581             webView->paint((HDC)wParam, lParam);
2582             break;
2583         case WM_DESTROY:
2584             webView->setIsBeingDestroyed();
2585             webView->close();
2586             break;
2587         case WM_GESTURENOTIFY:
2588             handled = webView->gestureNotify(wParam, lParam);
2589             break;
2590         case WM_GESTURE:
2591             handled = webView->gesture(wParam, lParam);
2592             break;
2593         case WM_MOUSEMOVE:
2594         case WM_LBUTTONDOWN:
2595         case WM_MBUTTONDOWN:
2596         case WM_RBUTTONDOWN:
2597         case WM_LBUTTONDBLCLK:
2598         case WM_MBUTTONDBLCLK:
2599         case WM_RBUTTONDBLCLK:
2600         case WM_LBUTTONUP:
2601         case WM_MBUTTONUP:
2602         case WM_RBUTTONUP:
2603         case WM_MOUSELEAVE:
2604         case WM_CANCELMODE:
2605             if (Frame* coreFrame = core(mainFrameImpl))
2606                 if (coreFrame->view()->didFirstLayout())
2607                     handled = webView->handleMouseEvent(message, wParam, lParam);
2608             break;
2609         case WM_MOUSEWHEEL:
2610         case WM_VISTA_MOUSEHWHEEL:
2611             if (Frame* coreFrame = core(mainFrameImpl))
2612                 if (coreFrame->view()->didFirstLayout())
2613                     handled = webView->mouseWheel(wParam, lParam, message == WM_VISTA_MOUSEHWHEEL);
2614             break;
2615         case WM_SYSKEYDOWN:
2616             handled = webView->keyDown(wParam, lParam, true);
2617             break;
2618         case WM_KEYDOWN:
2619             handled = webView->keyDown(wParam, lParam);
2620             break;
2621         case WM_SYSKEYUP:
2622             handled = webView->keyUp(wParam, lParam, true);
2623             break;
2624         case WM_KEYUP:
2625             handled = webView->keyUp(wParam, lParam);
2626             break;
2627         case WM_SYSCHAR:
2628             handled = webView->keyPress(wParam, lParam, true);
2629             break;
2630         case WM_CHAR:
2631             handled = webView->keyPress(wParam, lParam);
2632             break;
2633         // FIXME: We need to check WM_UNICHAR to support supplementary characters (that don't fit in 16 bits).
2634         case WM_SIZE:
2635             if (lParam != 0)
2636                 webView->sizeChanged(IntSize(LOWORD(lParam), HIWORD(lParam)));
2637             break;
2638         case WM_DPICHANGED:
2639             webView->dpiChanged(LOWORD(wParam), IntSize(LOWORD(lParam), HIWORD(lParam)));
2640             break;
2641         case WM_SHOWWINDOW:
2642             lResult = DefWindowProc(hWnd, message, wParam, lParam);
2643             if (wParam == 0) {
2644                 // The window is being hidden (e.g., because we switched tabs).
2645                 // Null out our backing store.
2646                 webView->deleteBackingStore();
2647             }
2648             break;
2649         case WM_SETFOCUS: {
2650             COMPtr<IWebUIDelegate> uiDelegate;
2651             COMPtr<IWebUIDelegatePrivate> uiDelegatePrivate;
2652             if (SUCCEEDED(webView->uiDelegate(&uiDelegate)) && uiDelegate
2653                 && SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**) &uiDelegatePrivate)) && uiDelegatePrivate)
2654                 uiDelegatePrivate->webViewReceivedFocus(webView);
2655
2656             FocusController& focusController = webView->page()->focusController();
2657             if (Frame* frame = focusController.focusedFrame()) {
2658                 // Send focus events unless the previously focused window is a
2659                 // child of ours (for example a plugin).
2660                 if (!IsChild(hWnd, reinterpret_cast<HWND>(wParam)))
2661                     focusController.setFocused(true);
2662             } else
2663                 focusController.setFocused(true);
2664             break;
2665         }
2666         case WM_KILLFOCUS: {
2667             COMPtr<IWebUIDelegate> uiDelegate;
2668             COMPtr<IWebUIDelegatePrivate> uiDelegatePrivate;
2669             HWND newFocusWnd = reinterpret_cast<HWND>(wParam);
2670             if (SUCCEEDED(webView->uiDelegate(&uiDelegate)) && uiDelegate
2671                 && SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**) &uiDelegatePrivate)) && uiDelegatePrivate)
2672                 uiDelegatePrivate->webViewLostFocus(webView, newFocusWnd);
2673
2674             FocusController& focusController = webView->page()->focusController();
2675             Frame& frame = focusController.focusedOrMainFrame();
2676             webView->resetIME(&frame);
2677             // Send blur events unless we're losing focus to a child of ours.
2678             if (!IsChild(hWnd, newFocusWnd))
2679                 focusController.setFocused(false);
2680
2681             // If we are pan-scrolling when we lose focus, stop the pan scrolling.
2682             frame.eventHandler().stopAutoscrollTimer();
2683
2684             break;
2685         }
2686         case WM_WINDOWPOSCHANGED:
2687             if (reinterpret_cast<WINDOWPOS*>(lParam)->flags & SWP_SHOWWINDOW)
2688                 webView->updateActiveStateSoon();
2689             handled = false;
2690             break;
2691         case WM_CUT:
2692             webView->cut(0);
2693             break;
2694         case WM_COPY:
2695             webView->copy(0);
2696             break;
2697         case WM_PASTE:
2698             webView->paste(0);
2699             break;
2700         case WM_CLEAR:
2701             webView->delete_(0);
2702             break;
2703         case WM_COMMAND:
2704             if (HIWORD(wParam))
2705                 handled = webView->execCommand(wParam, lParam);
2706             break;
2707         case WM_MENUCOMMAND:
2708             webView->onMenuCommand(wParam, lParam);
2709             break;
2710         case WM_CONTEXTMENU:
2711             handled = webView->handleContextMenuEvent(wParam, lParam);
2712             break;
2713         case WM_INITMENUPOPUP:
2714             handled = webView->onInitMenuPopup(wParam, lParam);
2715             break;
2716         case WM_MEASUREITEM:
2717             handled = webView->onMeasureItem(wParam, lParam);
2718             break;
2719         case WM_DRAWITEM:
2720             handled = webView->onDrawItem(wParam, lParam);
2721             break;
2722         case WM_UNINITMENUPOPUP:
2723             handled = webView->onUninitMenuPopup(wParam, lParam);
2724             break;
2725         case WM_XP_THEMECHANGED:
2726             if (Frame* coreFrame = core(mainFrameImpl)) {
2727                 webView->deleteBackingStore();
2728                 RenderTheme::singleton().themeChanged();
2729                 ScrollbarTheme::theme().themeChanged();
2730                 RECT windowRect;
2731                 ::GetClientRect(hWnd, &windowRect);
2732                 ::InvalidateRect(hWnd, &windowRect, false);
2733 #if USE(CA)
2734                 if (webView->isAcceleratedCompositing())
2735                     webView->m_backingLayer->setNeedsDisplay();
2736 #endif
2737            }
2738             break;
2739         case WM_MOUSEACTIVATE:
2740             webView->setMouseActivated(true);
2741             handled = false;
2742             break;
2743         case WM_GETDLGCODE: {
2744             COMPtr<IWebUIDelegate> uiDelegate;
2745             COMPtr<IWebUIDelegatePrivate> uiDelegatePrivate;
2746             LONG_PTR dlgCode = 0;
2747             UINT keyCode = 0;
2748             if (lParam) {
2749                 LPMSG lpMsg = (LPMSG)lParam;
2750                 if (lpMsg->message == WM_KEYDOWN)
2751                     keyCode = (UINT) lpMsg->wParam;
2752             }
2753             if (SUCCEEDED(webView->uiDelegate(&uiDelegate)) && uiDelegate
2754                 && SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**) &uiDelegatePrivate)) && uiDelegatePrivate
2755                 && SUCCEEDED(uiDelegatePrivate->webViewGetDlgCode(webView, keyCode, &dlgCode)))
2756                 return dlgCode;
2757             handled = false;
2758             break;
2759         }
2760         case WM_GETOBJECT:
2761             handled = webView->onGetObject(wParam, lParam, lResult);
2762             break;
2763         case WM_IME_STARTCOMPOSITION:
2764             handled = webView->onIMEStartComposition();
2765             break;
2766         case WM_IME_REQUEST:
2767             lResult = webView->onIMERequest(wParam, lParam);
2768             break;
2769         case WM_IME_COMPOSITION:
2770             handled = webView->onIMEComposition(lParam);
2771             break;
2772         case WM_IME_ENDCOMPOSITION:
2773             handled = webView->onIMEEndComposition();
2774             break;
2775         case WM_IME_CHAR:
2776             handled = webView->onIMEChar(wParam, lParam);
2777             break;
2778         case WM_IME_NOTIFY:
2779             handled = webView->onIMENotify(wParam, lParam, &lResult);
2780             break;
2781         case WM_IME_SELECT:
2782             handled = webView->onIMESelect(wParam, lParam);
2783             break;
2784         case WM_IME_SETCONTEXT:
2785             handled = webView->onIMESetContext(wParam, lParam);
2786             break;
2787         case WM_TIMER:
2788             switch (wParam) {
2789                 case UpdateActiveStateTimer:
2790                     KillTimer(hWnd, UpdateActiveStateTimer);
2791                     webView->updateActiveState();
2792                     break;
2793                 case DeleteBackingStoreTimer:
2794                     webView->deleteBackingStore();
2795                     break;
2796             }
2797             break;
2798         case WM_SETCURSOR:
2799             handled = ::SetCursor(webView->m_lastSetCursor);
2800             break;
2801         case WM_VSCROLL:
2802             handled = webView->verticalScroll(wParam, lParam);
2803             break;
2804         case WM_HSCROLL:
2805             handled = webView->horizontalScroll(wParam, lParam);
2806             break;
2807         default:
2808             handled = false;
2809             break;
2810     }
2811
2812     webView->updateWindowIfNeeded(hWnd, message);
2813
2814     if (!handled)
2815         lResult = DefWindowProc(hWnd, message, wParam, lParam);
2816     
2817     // Let the client know whether we consider this message handled.
2818     return (message == WM_KEYDOWN || message == WM_SYSKEYDOWN || message == WM_KEYUP || message == WM_SYSKEYUP) ? !handled : lResult;
2819 }
2820
2821 void WebView::updateWindowIfNeeded(HWND hWnd, UINT message)
2822 {
2823     if (!needsDisplay())
2824         return;
2825
2826     // Care should be taken when updating the window from the window procedure.
2827     // Updating the window in response to e.g. WM_PARENTNOTIFY may cause reentrancy problems,
2828     // because WM_PARENTNOTIFY is sent synchronously to the parent window when e.g. DestroyWindow() is called.
2829
2830     switch (message) {
2831     case WM_PAINT:
2832     case WM_PARENTNOTIFY:
2833         return;
2834     }
2835
2836     ::UpdateWindow(hWnd);
2837 }
2838
2839 bool WebView::developerExtrasEnabled() const
2840 {
2841     if (m_preferences->developerExtrasDisabledByOverride())
2842         return false;
2843
2844 #ifdef NDEBUG
2845     BOOL enabled;
2846     return SUCCEEDED(m_preferences->developerExtrasEnabled(&enabled)) && enabled;
2847 #else
2848     return true;
2849 #endif
2850 }
2851
2852 static String webKitVersionString()
2853 {
2854 #if !USE(CAIRO)
2855     LPWSTR buildNumberStringPtr;
2856     if (::LoadStringW(gInstance, BUILD_NUMBER, reinterpret_cast<LPWSTR>(&buildNumberStringPtr), 0) && buildNumberStringPtr)
2857         return buildNumberStringPtr;
2858 #endif
2859     return String::format("%d.%d", WEBKIT_MAJOR_VERSION, WEBKIT_MINOR_VERSION);
2860 }
2861
2862 const String& WebView::userAgentForKURL(const URL&)
2863 {
2864     if (m_userAgentOverridden)
2865         return m_userAgentCustom;
2866
2867     if (!m_userAgentStandard.length())
2868         m_userAgentStandard = WebView::standardUserAgentWithApplicationName(m_applicationName);
2869     return m_userAgentStandard;
2870 }
2871
2872 // IUnknown -------------------------------------------------------------------
2873
2874 HRESULT WebView::QueryInterface(_In_ REFIID riid, _COM_Outptr_ void** ppvObject)
2875 {
2876     if (!ppvObject)
2877         return E_POINTER;
2878     *ppvObject = nullptr;
2879     if (IsEqualGUID(riid, CLSID_WebView))
2880         *ppvObject = this;
2881     else if (IsEqualGUID(riid, IID_IUnknown))
2882         *ppvObject = static_cast<IWebView*>(this);
2883     else if (IsEqualGUID(riid, IID_IWebView))
2884         *ppvObject = static_cast<IWebView*>(this);
2885     else if (IsEqualGUID(riid, IID_IWebViewPrivate))
2886         *ppvObject = static_cast<IWebViewPrivate*>(this);
2887     else if (IsEqualGUID(riid, IID_IWebViewPrivate2))
2888         *ppvObject = static_cast<IWebViewPrivate2*>(this);
2889     else if (IsEqualGUID(riid, IID_IWebViewPrivate3))
2890         *ppvObject = static_cast<IWebViewPrivate3*>(this);
2891     else if (IsEqualGUID(riid, IID_IWebViewPrivate4))
2892         *ppvObject = static_cast<IWebViewPrivate4*>(this);
2893     else if (IsEqualGUID(riid, IID_IWebIBActions))
2894         *ppvObject = static_cast<IWebIBActions*>(this);
2895     else if (IsEqualGUID(riid, IID_IWebViewCSS))
2896         *ppvObject = static_cast<IWebViewCSS*>(this);
2897     else if (IsEqualGUID(riid, IID_IWebViewEditing))
2898         *ppvObject = static_cast<IWebViewEditing*>(this);
2899     else if (IsEqualGUID(riid, IID_IWebViewUndoableEditing))
2900         *ppvObject = static_cast<IWebViewUndoableEditing*>(this);
2901     else if (IsEqualGUID(riid, IID_IWebViewEditingActions))
2902         *ppvObject = static_cast<IWebViewEditingActions*>(this);
2903     else if (IsEqualGUID(riid, IID_IWebNotificationObserver))
2904         *ppvObject = static_cast<IWebNotificationObserver*>(this);
2905     else if (IsEqualGUID(riid, IID_IDropTarget))
2906         *ppvObject = static_cast<IDropTarget*>(this);
2907     else
2908         return E_NOINTERFACE;
2909
2910     AddRef();
2911     return S_OK;
2912 }
2913
2914 ULONG WebView::AddRef()
2915 {
2916     ASSERT(!m_deletionHasBegun);
2917     return ++m_refCount;
2918 }
2919
2920 ULONG WebView::Release()
2921 {
2922     ASSERT(!m_deletionHasBegun);
2923
2924     if (m_refCount == 1) {
2925         // Call close() now so that clients don't have to. (It's harmless to call close() multiple
2926         // times.) We do this here instead of in our destructor because close() can cause AddRef()
2927         // and Release() to be called, and if that happened in our destructor we would be destroyed
2928         // more than once.
2929         close();
2930     }
2931
2932     ULONG newRef = --m_refCount;
2933     if (!newRef) {
2934 #if !ASSERT_DISABLED
2935         m_deletionHasBegun = true;
2936 #endif
2937         delete(this);
2938     }
2939
2940     return newRef;
2941 }
2942
2943 // IWebView --------------------------------------------------------------------
2944
2945 HRESULT WebView::canShowMIMEType(_In_ BSTR mimeType, _Out_ BOOL* canShow)
2946 {
2947     if (!canShow)
2948         return E_POINTER;
2949
2950     *canShow = canShowMIMEType(toString(mimeType));
2951
2952     return S_OK;
2953 }
2954
2955 bool WebView::canShowMIMEType(const String& mimeType)
2956 {
2957     Frame* coreFrame = core(m_mainFrame);
2958     bool allowPlugins = coreFrame && coreFrame->loader().subframeLoader().allowPlugins();
2959
2960     bool canShow = MIMETypeRegistry::isSupportedImageMIMEType(mimeType)
2961         || MIMETypeRegistry::isSupportedNonImageMIMEType(mimeType)
2962         || MIMETypeRegistry::isSupportedMediaMIMEType(mimeType);
2963
2964     if (!canShow && m_page) {
2965         canShow = (m_page->pluginData().supportsWebVisibleMimeType(mimeType, PluginData::AllPlugins) && allowPlugins)
2966             || m_page->pluginData().supportsWebVisibleMimeType(mimeType, PluginData::OnlyApplicationPlugins);
2967     }
2968
2969     if (!canShow)
2970         canShow = shouldUseEmbeddedView(mimeType);
2971
2972     return canShow;
2973 }
2974
2975 HRESULT WebView::canShowMIMETypeAsHTML(_In_ BSTR mimeType, _Out_ BOOL* canShow)
2976 {
2977     if (!canShow)
2978         return E_POINTER;
2979
2980     *canShow = canShowMIMETypeAsHTML(toString(mimeType));
2981
2982     return S_OK;
2983 }
2984
2985 bool WebView::canShowMIMETypeAsHTML(const String& /*mimeType*/)
2986 {
2987     // FIXME
2988     notImplemented();
2989     return true;
2990 }
2991
2992 HRESULT WebView::MIMETypesShownAsHTML(_COM_Outptr_opt_ IEnumVARIANT** enumVariant)
2993 {
2994     ASSERT_NOT_REACHED();
2995     if (!enumVariant)
2996         return E_POINTER;
2997     *enumVariant = nullptr;
2998     return E_NOTIMPL;
2999 }
3000
3001 HRESULT WebView::setMIMETypesShownAsHTML(__inout_ecount_full(cMimeTypes) BSTR* mimeTypes, int cMimeTypes)
3002 {
3003     ASSERT_NOT_REACHED();
3004     return E_NOTIMPL;
3005 }
3006
3007 HRESULT WebView::URLFromPasteboard(_In_opt_ IDataObject* /*pasteboard*/, _Deref_opt_out_ BSTR* /*url*/)
3008 {
3009     ASSERT_NOT_REACHED();
3010     return E_NOTIMPL;
3011 }
3012
3013 HRESULT WebView::URLTitleFromPasteboard(_In_opt_ IDataObject* /*pasteboard*/, _Deref_opt_out_ BSTR* /*urlTitle*/)
3014 {
3015     ASSERT_NOT_REACHED();
3016     return E_NOTIMPL;
3017 }
3018
3019 bool WebView::shouldInitializeTrackPointHack()
3020 {
3021     static bool shouldCreateScrollbars;
3022     static bool hasRunTrackPointCheck;
3023
3024     if (hasRunTrackPointCheck)
3025         return shouldCreateScrollbars;
3026
3027     hasRunTrackPointCheck = true;
3028     const WCHAR trackPointKeys[][50] = { L"Software\\Lenovo\\TrackPoint",
3029         L"Software\\Lenovo\\UltraNav",
3030         L"Software\\Alps\\Apoint\\TrackPoint",
3031         L"Software\\Synaptics\\SynTPEnh\\UltraNavUSB",
3032         L"Software\\Synaptics\\SynTPEnh\\UltraNavPS2" };
3033
3034     for (int i = 0; i < 5; ++i) {
3035         HKEY trackPointKey = nullptr;
3036         LSTATUS readKeyResult = ::RegOpenKeyExW(HKEY_CURRENT_USER, trackPointKeys[i], 0, KEY_READ, &trackPointKey);
3037         ::RegCloseKey(trackPointKey);
3038         if (readKeyResult == ERROR_SUCCESS) {
3039             shouldCreateScrollbars = true;
3040             return shouldCreateScrollbars;
3041         }
3042     }
3043
3044     return shouldCreateScrollbars;
3045 }
3046
3047 HRESULT WebView::initWithFrame(RECT frame, _In_ BSTR frameName, _In_ BSTR groupName)
3048 {
3049     HRESULT hr = S_OK;
3050
3051     if (m_viewWindow)
3052         return E_UNEXPECTED;
3053
3054     registerWebViewWindowClass();
3055
3056     m_viewWindow = CreateWindowEx(0, kWebViewWindowClassName, 0, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
3057         frame.left, frame.top, frame.right - frame.left, frame.bottom - frame.top, m_hostWindow ? m_hostWindow : HWND_MESSAGE, 0, gInstance, 0);
3058     ASSERT(::IsWindow(m_viewWindow));
3059
3060     if (shouldInitializeTrackPointHack()) {
3061         // If we detected a registry key belonging to a TrackPoint driver, then create fake trackpoint
3062         // scrollbars, so the WebView will receive WM_VSCROLL and WM_HSCROLL messages. We create one
3063         // vertical scrollbar and one horizontal to allow for receiving both types of messages.
3064         ::CreateWindowW(L"SCROLLBAR", L"FAKETRACKPOINTHSCROLLBAR", WS_CHILD | WS_VISIBLE | SBS_HORZ, 0, 0, 0, 0, m_viewWindow, 0, gInstance, 0);
3065         ::CreateWindowW(L"SCROLLBAR", L"FAKETRACKPOINTVSCROLLBAR", WS_CHILD | WS_VISIBLE | SBS_VERT, 0, 0, 0, 0, m_viewWindow, 0, gInstance, 0);
3066     }
3067
3068     hr = registerDragDrop();
3069     if (FAILED(hr))
3070         return hr;
3071
3072     WebPreferences* sharedPreferences = WebPreferences::sharedStandardPreferences();
3073     sharedPreferences->willAddToWebView();
3074     m_preferences = sharedPreferences;
3075
3076     static bool didOneTimeInitialization;
3077     if (!didOneTimeInitialization) {
3078 #if !LOG_DISABLED || !RELEASE_LOG_DISABLED
3079         initializeLogChannelsIfNecessary();
3080 #endif // !LOG_DISABLED || !RELEASE_LOG_DISABLED
3081
3082         // Initialize our platform strategies first before invoking the rest
3083         // of the initialization code which may depend on the strategies.
3084         WebPlatformStrategies::initialize();
3085
3086         WebKitInitializeWebDatabasesIfNecessary();
3087
3088         auto& memoryPressureHandler = MemoryPressureHandler::singleton();
3089         memoryPressureHandler.setLowMemoryHandler([] (Critical critical, Synchronous synchronous) {
3090             WebCore::releaseMemory(critical, synchronous);
3091         });
3092         memoryPressureHandler.install();
3093
3094         didOneTimeInitialization = true;
3095      }
3096
3097     BOOL useHighResolutionTimer;
3098     if (SUCCEEDED(m_preferences->shouldUseHighResolutionTimers(&useHighResolutionTimer)))
3099         Settings::setShouldUseHighResolutionTimers(useHighResolutionTimer);
3100
3101     m_inspectorClient = new WebInspectorClient(this);
3102
3103     PageConfiguration configuration(
3104         makeUniqueRef<WebEditorClient>(this),
3105         SocketProvider::create(),
3106         makeUniqueRef<LibWebRTCProvider>()
3107     );
3108     configuration.backForwardClient = BackForwardList::create();
3109     configuration.chromeClient = new WebChromeClient(this);
3110     configuration.contextMenuClient = new WebContextMenuClient(this);
3111     configuration.dragClient = new WebDragClient(this);
3112     configuration.inspectorClient = m_inspectorClient;
3113     configuration.loaderClientForMainFrame = new WebFrameLoaderClient;
3114     configuration.applicationCacheStorage = &WebApplicationCache::storage();
3115     configuration.databaseProvider = &WebDatabaseProvider::singleton();
3116     configuration.storageNamespaceProvider = &m_webViewGroup->storageNamespaceProvider();
3117     configuration.progressTrackerClient = static_cast<WebFrameLoaderClient*>(configuration.loaderClientForMainFrame);
3118     configuration.userContentProvider = &m_webViewGroup->userContentController();
3119     configuration.visitedLinkStore = &m_webViewGroup->visitedLinkStore();
3120     configuration.pluginInfoProvider = &WebPluginInfoProvider::singleton();
3121
3122     m_page = new Page(WTFMove(configuration));
3123     provideGeolocationTo(m_page, new WebGeolocationClient(this));
3124
3125     unsigned layoutMilestones = DidFirstLayout | DidFirstVisuallyNonEmptyLayout;
3126     m_page->addLayoutMilestones(static_cast<LayoutMilestones>(layoutMilestones));
3127
3128
3129     if (m_uiDelegate) {
3130         BString path;
3131         if (SUCCEEDED(m_uiDelegate->ftpDirectoryTemplatePath(this, &path)))
3132             m_page->settings().setFTPDirectoryTemplatePath(toString(path));
3133     }
3134
3135     WebFrame* webFrame = WebFrame::createInstance();
3136     webFrame->initWithWebView(this, m_page);
3137     static_cast<WebFrameLoaderClient&>(m_page->mainFrame().loader().client()).setWebFrame(webFrame);
3138     m_mainFrame = webFrame;
3139     webFrame->Release(); // The WebFrame is owned by the Frame, so release our reference to it.
3140
3141     m_page->mainFrame().tree().setName(toString(frameName));
3142     m_page->mainFrame().init();
3143     setGroupName(groupName);
3144
3145     addToAllWebViewsSet();
3146
3147     #pragma warning(suppress: 4244)
3148     SetWindowLongPtr(m_viewWindow, 0, (LONG_PTR)this);
3149     ShowWindow(m_viewWindow, SW_SHOW);
3150
3151     initializeToolTipWindow();
3152     windowAncestryDidChange();
3153
3154     IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal();
3155     notifyCenter->addObserver(this, WebPreferences::webPreferencesChangedNotification(), static_cast<IWebPreferences*>(m_preferences.get()));
3156     m_preferences->postPreferencesChangesNotification();
3157
3158     m_page->setDeviceScaleFactor(deviceScaleFactor());
3159
3160     setSmartInsertDeleteEnabled(TRUE);
3161
3162     return hr;
3163 }
3164
3165 static bool initCommonControls()
3166 {
3167     static bool haveInitialized = false;
3168     if (haveInitialized)
3169         return true;
3170
3171     INITCOMMONCONTROLSEX init;
3172     init.dwSize = sizeof(init);
3173     init.dwICC = ICC_TREEVIEW_CLASSES;
3174     haveInitialized = !!::InitCommonControlsEx(&init);
3175     return haveInitialized;
3176 }
3177
3178 void WebView::initializeToolTipWindow()
3179 {
3180     if (!initCommonControls())
3181         return;
3182
3183     m_toolTipHwnd = CreateWindowEx(WS_EX_TRANSPARENT, TOOLTIPS_CLASS, 0, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
3184                                    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
3185                                    m_viewWindow, 0, 0, 0);
3186     if (!m_toolTipHwnd)
3187         return;
3188
3189     TOOLINFO info = {0};
3190     info.cbSize = sizeof(info);
3191     info.uFlags = TTF_IDISHWND | TTF_SUBCLASS ;
3192     info.uId = reinterpret_cast<UINT_PTR>(m_viewWindow);
3193
3194     ::SendMessage(m_toolTipHwnd, TTM_ADDTOOL, 0, reinterpret_cast<LPARAM>(&info));
3195     ::SendMessage(m_toolTipHwnd, TTM_SETMAXTIPWIDTH, 0, clampTo<int>(maxToolTipWidth * deviceScaleFactor()));
3196
3197     ::SetWindowPos(m_toolTipHwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
3198 }
3199
3200 void WebView::setToolTip(const String& toolTip)
3201 {
3202     if (!m_toolTipHwnd)
3203         return;
3204
3205     if (toolTip == m_toolTip)
3206         return;
3207
3208     m_toolTip = toolTip;
3209
3210     if (!m_toolTip.isEmpty()) {
3211         TOOLINFO info = {0};
3212         info.cbSize = sizeof(info);
3213         info.uFlags = TTF_IDISHWND;
3214         info.uId = reinterpret_cast<UINT_PTR>(m_viewWindow);
3215         Vector<UChar> toolTipCharacters = m_toolTip.charactersWithNullTermination(); // Retain buffer long enough to make the SendMessage call
3216         info.lpszText = const_cast<UChar*>(toolTipCharacters.data());
3217         ::SendMessage(m_toolTipHwnd, TTM_UPDATETIPTEXT, 0, reinterpret_cast<LPARAM>(&info));
3218     }
3219
3220     ::SendMessage(m_toolTipHwnd, TTM_ACTIVATE, !m_toolTip.isEmpty(), 0);
3221 }
3222
3223 HRESULT WebView::notifyDidAddIcon(IWebNotification* notification)
3224 {
3225     COMPtr<IPropertyBag> propertyBag;
3226     HRESULT hr = notification->userInfo(&propertyBag);
3227     if (FAILED(hr))
3228         return hr;
3229     if (!propertyBag)
3230         return E_FAIL;
3231
3232     COMVariant iconUserInfoURL;
3233     hr = propertyBag->Read(WebIconDatabase::iconDatabaseNotificationUserInfoURLKey(), &iconUserInfoURL, nullptr);
3234     if (FAILED(hr))
3235         return hr;
3236
3237     if (iconUserInfoURL.variantType() != VT_BSTR)
3238         return E_FAIL;
3239
3240     String mainFrameURL;
3241     if (m_mainFrame)
3242         mainFrameURL = m_mainFrame->url().string();
3243
3244     if (!mainFrameURL.isEmpty() && mainFrameURL == toString(V_BSTR(&iconUserInfoURL)))
3245         dispatchDidReceiveIconFromWebFrame(m_mainFrame);
3246
3247     return hr;
3248 }
3249
3250 void WebView::registerForIconNotification(bool listen)
3251 {
3252     IWebNotificationCenter* nc = WebNotificationCenter::defaultCenterInternal();
3253     if (listen)
3254         nc->addObserver(this, WebIconDatabase::iconDatabaseDidAddIconNotification(), 0);
3255     else
3256         nc->removeObserver(this, WebIconDatabase::iconDatabaseDidAddIconNotification(), 0);
3257 }
3258
3259 void WebView::dispatchDidReceiveIconFromWebFrame(WebFrame* frame)
3260 {
3261     registerForIconNotification(false);
3262
3263     if (m_frameLoadDelegate) {
3264         String str = frame->url().string();
3265
3266         IntSize sz(16, 16);
3267
3268         BitmapInfo bmInfo = BitmapInfo::create(sz);
3269
3270         HBITMAP hBitmap = nullptr;
3271
3272         Image* icon = iconDatabase().synchronousIconForPageURL(str, sz);
3273
3274         if (icon && icon->width()) {
3275             HWndDC dc(0);
3276             hBitmap = CreateDIBSection(dc, &bmInfo, DIB_RGB_COLORS, 0, 0, 0);
3277             icon->getHBITMAPOfSize(hBitmap, &sz);
3278         }
3279
3280         HRESULT hr = m_frameLoadDelegate->didReceiveIcon(this, hBitmap, frame);
3281         if ((hr == E_NOTIMPL) && hBitmap)
3282             DeleteObject(hBitmap);
3283     }
3284 }
3285
3286 HRESULT WebView::setAccessibilityDelegate(_In_opt_ IAccessibilityDelegate* d)
3287 {
3288     m_accessibilityDelegate = d;
3289     return S_OK;
3290 }
3291
3292 HRESULT WebView::accessibilityDelegate(_COM_Outptr_opt_ IAccessibilityDelegate** d)
3293 {
3294     if (!d)
3295         return E_POINTER;
3296     *d = nullptr;
3297     if (!m_accessibilityDelegate)
3298         return E_POINTER;
3299
3300     return m_accessibilityDelegate.copyRefTo(d);
3301 }
3302
3303 HRESULT WebView::setUIDelegate(_In_opt_ IWebUIDelegate* d)
3304 {
3305     m_uiDelegate = d;
3306
3307     if (m_uiDelegatePrivate)
3308         m_uiDelegatePrivate = 0;
3309
3310     if (d) {
3311         if (FAILED(d->QueryInterface(IID_IWebUIDelegatePrivate, (void**)&m_uiDelegatePrivate)))
3312             m_uiDelegatePrivate = 0;
3313     }
3314
3315     return S_OK;
3316 }
3317
3318 HRESULT WebView::uiDelegate(_COM_Outptr_opt_ IWebUIDelegate** d)
3319 {
3320     if (!d)
3321         return E_POINTER;
3322     *d = nullptr;
3323     if (!m_uiDelegate)
3324         return E_FAIL;
3325
3326     return m_uiDelegate.copyRefTo(d);
3327 }
3328
3329 HRESULT WebView::setResourceLoadDelegate(_In_opt_ IWebResourceLoadDelegate* d)
3330 {
3331     m_resourceLoadDelegate = d;
3332     return S_OK;
3333 }
3334
3335 HRESULT WebView::resourceLoadDelegate(_COM_Outptr_opt_ IWebResourceLoadDelegate** d)
3336 {
3337     if (!d)
3338         return E_POINTER;
3339     *d = nullptr;
3340     if (!m_resourceLoadDelegate)
3341         return E_FAIL;
3342
3343     return m_resourceLoadDelegate.copyRefTo(d);
3344 }
3345
3346 HRESULT WebView::setDownloadDelegate(_In_opt_ IWebDownloadDelegate* d)
3347 {
3348     m_downloadDelegate = d;
3349     return S_OK;
3350 }
3351
3352 HRESULT WebView::downloadDelegate(_COM_Outptr_opt_ IWebDownloadDelegate** d)
3353 {
3354     if (!d)
3355         return E_POINTER;
3356     *d = nullptr;
3357     if (!m_downloadDelegate)
3358         return E_FAIL;
3359
3360     return m_downloadDelegate.copyRefTo(d);
3361 }
3362
3363 HRESULT WebView::setFrameLoadDelegate(_In_opt_ IWebFrameLoadDelegate* d)
3364 {
3365     m_frameLoadDelegate = d;
3366     return S_OK;
3367 }
3368
3369 HRESULT WebView::frameLoadDelegate(_COM_Outptr_opt_ IWebFrameLoadDelegate** d)
3370 {
3371     if (!d)
3372         return E_POINTER;
3373     *d = nullptr;
3374     if (!m_frameLoadDelegate)
3375         return E_FAIL;
3376
3377     return m_frameLoadDelegate.copyRefTo(d);
3378 }
3379
3380 HRESULT WebView::setPolicyDelegate(_In_opt_ IWebPolicyDelegate* d)
3381 {
3382     m_policyDelegate = d;
3383     return S_OK;
3384 }
3385
3386 HRESULT WebView::policyDelegate(_COM_Outptr_opt_ IWebPolicyDelegate** d)
3387 {
3388     if (!d)
3389         return E_POINTER;
3390     *d = nullptr;
3391     if (!m_policyDelegate)
3392         return E_FAIL;
3393
3394     return m_policyDelegate.copyRefTo(d);
3395 }
3396
3397 HRESULT WebView::mainFrame(_COM_Outptr_opt_ IWebFrame** frame)
3398 {
3399     if (!frame) {
3400         ASSERT_NOT_REACHED();
3401         return E_POINTER;
3402     }
3403
3404     *frame = m_mainFrame;
3405     if (!m_mainFrame)
3406         return E_UNEXPECTED;
3407
3408     m_mainFrame->AddRef();
3409     return S_OK;
3410 }
3411
3412 HRESULT WebView::focusedFrame(_COM_Outptr_opt_ IWebFrame** frame)
3413 {
3414     if (!frame) {
3415         ASSERT_NOT_REACHED();
3416         return E_POINTER;
3417     }
3418
3419     *frame = nullptr;
3420     Frame* f = m_page->focusController().focusedFrame();
3421     if (!f)
3422         return E_FAIL;
3423
3424     WebFrame* webFrame = kit(f);
3425     if (!webFrame)
3426         return E_UNEXPECTED;
3427
3428     return webFrame->QueryInterface(IID_IWebFrame, (void**) frame);
3429 }
3430
3431 HRESULT WebView::backForwardList(_COM_Outptr_opt_ IWebBackForwardList** list)
3432 {
3433     if (!list) {
3434         ASSERT_NOT_REACHED();
3435         return E_POINTER;
3436     }
3437     *list = nullptr;
3438     if (!m_useBackForwardList)
3439         return E_FAIL;
3440  
3441     *list = WebBackForwardList::createInstance(static_cast<BackForwardList*>(m_page->backForward().client()));
3442
3443     return S_OK;
3444 }
3445
3446 HRESULT WebView::setMaintainsBackForwardList(BOOL flag)
3447 {
3448     m_useBackForwardList = !!flag;
3449     return S_OK;
3450 }
3451
3452 HRESULT WebView::goBack(_Out_ BOOL* succeeded)
3453 {
3454     if (!succeeded)
3455         return E_POINTER;
3456
3457     *succeeded = m_page->backForward().goBack();
3458     return S_OK;
3459 }
3460
3461 HRESULT WebView::goForward(_Out_ BOOL* succeeded)
3462 {
3463     if (!succeeded)
3464         return E_POINTER;
3465
3466     *succeeded = m_page->backForward().goForward();
3467     return S_OK;
3468 }
3469
3470 HRESULT WebView::goToBackForwardItem(_In_opt_ IWebHistoryItem* item, _Out_ BOOL* succeeded)
3471 {
3472     if (!item)
3473         return E_FAIL;
3474
3475     if (!succeeded)
3476         return E_POINTER;
3477
3478     *succeeded = FALSE;
3479
3480     COMPtr<WebHistoryItem> webHistoryItem;
3481     HRESULT hr = item->QueryInterface(&webHistoryItem);
3482     if (FAILED(hr))
3483         return hr;
3484
3485     m_page->goToItem(*webHistoryItem->historyItem(), FrameLoadType::IndexedBackForward);
3486     *succeeded = TRUE;
3487
3488     return S_OK;
3489 }
3490
3491 HRESULT WebView::setTextSizeMultiplier(float multiplier)
3492 {
3493     if (!m_mainFrame)
3494         return E_UNEXPECTED;
3495     setZoomMultiplier(multiplier, true);
3496     return S_OK;
3497 }
3498
3499 HRESULT WebView::setPageSizeMultiplier(float multiplier)
3500 {
3501     if (!m_mainFrame)
3502         return E_UNEXPECTED;
3503     setZoomMultiplier(multiplier, false);
3504     return S_OK;
3505 }
3506
3507 void WebView::setZoomMultiplier(float multiplier, bool isTextOnly)
3508 {
3509     m_zoomMultiplier = multiplier;
3510     m_zoomsTextOnly = isTextOnly;
3511
3512     if (Frame* coreFrame = core(m_mainFrame)) {
3513         if (m_zoomsTextOnly)
3514             coreFrame->setPageAndTextZoomFactors(1, multiplier);
3515         else
3516             coreFrame->setPageAndTextZoomFactors(multiplier, 1);
3517     }
3518 }
3519
3520 HRESULT WebView::textSizeMultiplier(_Out_ float* multiplier)
3521 {
3522     if (!multiplier)
3523         return E_POINTER;
3524
3525     *multiplier = zoomMultiplier(true);
3526     return S_OK;
3527 }
3528
3529 HRESULT WebView::pageSizeMultiplier(_Out_ float* multiplier)
3530 {
3531     if (!multiplier)
3532         return E_POINTER;
3533
3534     *multiplier = zoomMultiplier(false);
3535     return S_OK;
3536 }
3537
3538 float WebView::zoomMultiplier(bool isTextOnly)
3539 {
3540     if (isTextOnly != m_zoomsTextOnly)
3541         return 1.0f;
3542     return m_zoomMultiplier;
3543 }
3544
3545 HRESULT WebView::setApplicationNameForUserAgent(_In_ BSTR applicationName)
3546 {
3547     m_applicationName = toString(applicationName);
3548     m_userAgentStandard = String();
3549     return S_OK;
3550 }
3551
3552 HRESULT WebView::applicationNameForUserAgent(_Deref_opt_out_ BSTR* applicationName)
3553 {
3554     if (!applicationName)
3555         return E_POINTER;
3556
3557     *applicationName = BString(m_applicationName).release();
3558     if (!*applicationName && m_applicationName.length())
3559         return E_OUTOFMEMORY;
3560     return S_OK;
3561 }
3562
3563 HRESULT WebView::setCustomUserAgent(_In_ BSTR userAgentString)
3564 {
3565     m_userAgentOverridden = userAgentString;
3566     m_userAgentCustom = toString(userAgentString);
3567     return S_OK;
3568 }
3569
3570 HRESULT WebView::customUserAgent(_Deref_opt_out_ BSTR* userAgentString)
3571 {
3572     if (!userAgentString)
3573         return E_POINTER;
3574
3575     *userAgentString = nullptr;
3576     if (!m_userAgentOverridden)
3577         return S_OK;
3578     *userAgentString = BString(m_userAgentCustom).release();
3579     if (!*userAgentString && m_userAgentCustom.length())
3580         return E_OUTOFMEMORY;
3581     return S_OK;
3582 }
3583
3584 HRESULT WebView::userAgentForURL(_In_ BSTR url, _Deref_opt_out_ BSTR* userAgent)
3585 {
3586     if (!userAgent)
3587         return E_POINTER;
3588
3589     String userAgentString = userAgentForKURL(MarshallingHelpers::BSTRToKURL(url));
3590     *userAgent = BString(userAgentString).release();
3591     if (!*userAgent && userAgentString.length())
3592         return E_OUTOFMEMORY;
3593     return S_OK;
3594 }
3595
3596 HRESULT WebView::supportsTextEncoding(_Out_ BOOL* supports)
3597 {
3598     if (!supports)
3599         return E_POINTER;
3600
3601     *supports = TRUE;