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