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