1/* 2 * Copyright (C) 2006, 2007, 2008, 2010 Apple Inc. All rights reserved. 3 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include "config.h" 28#include "DOMWindow.h" 29 30#include "AbstractDatabase.h" 31#include "BackForwardController.h" 32#include "BarInfo.h" 33#include "Base64.h" 34#include "BeforeUnloadEvent.h" 35#include "CSSComputedStyleDeclaration.h" 36#include "CSSRuleList.h" 37#include "CSSStyleSelector.h" 38#include "Chrome.h" 39#include "Console.h" 40#include "Crypto.h" 41#include "DOMApplicationCache.h" 42#include "DOMSelection.h" 43#include "DOMSettableTokenList.h" 44#include "DOMStringList.h" 45#include "DOMTimer.h" 46#include "DOMTokenList.h" 47#include "DOMURL.h" 48#include "Database.h" 49#include "DatabaseCallback.h" 50#include "DeviceMotionController.h" 51#include "DeviceOrientationController.h" 52#include "Document.h" 53#include "DocumentLoader.h" 54#include "Element.h" 55#include "EventException.h" 56#include "EventListener.h" 57#include "EventNames.h" 58#include "ExceptionCode.h" 59#include "FloatRect.h" 60#include "Frame.h" 61#include "FrameLoadRequest.h" 62#include "FrameLoader.h" 63#include "FrameTree.h" 64#include "FrameView.h" 65#include "HTMLFrameOwnerElement.h" 66#include "History.h" 67#include "IDBFactory.h" 68#include "IDBFactoryBackendInterface.h" 69#include "InspectorInstrumentation.h" 70#include "KURL.h" 71#include "Location.h" 72#include "MediaQueryList.h" 73#include "MediaQueryMatcher.h" 74#include "MessageEvent.h" 75#include "Navigator.h" 76#include "NotificationCenter.h" 77#include "Page.h" 78#include "PageGroup.h" 79#include "PageTransitionEvent.h" 80#include "Performance.h" 81#include "PlatformScreen.h" 82#include "PlatformString.h" 83#include "Screen.h" 84#include "SecurityOrigin.h" 85#include "SerializedScriptValue.h" 86#include "Settings.h" 87#include "Storage.h" 88#include "StorageArea.h" 89#include "StorageInfo.h" 90#include "StorageNamespace.h" 91#include "StyleMedia.h" 92#include "SuddenTermination.h" 93#include "WebKitPoint.h" 94#include "WindowFeatures.h" 95#include <algorithm> 96#include <wtf/CurrentTime.h> 97#include <wtf/MathExtras.h> 98#include <wtf/text/StringConcatenate.h> 99 100#if ENABLE(FILE_SYSTEM) 101#include "AsyncFileSystem.h" 102#include "DOMFileSystem.h" 103#include "DOMFileSystemBase.h" 104#include "EntryCallback.h" 105#include "ErrorCallback.h" 106#include "FileError.h" 107#include "FileSystemCallback.h" 108#include "FileSystemCallbacks.h" 109#include "LocalFileSystem.h" 110#endif 111 112#if ENABLE(REQUEST_ANIMATION_FRAME) 113#include "RequestAnimationFrameCallback.h" 114#endif 115 116using std::min; 117using std::max; 118 119namespace WebCore { 120 121class PostMessageTimer : public TimerBase { 122public: 123 PostMessageTimer(DOMWindow* window, PassRefPtr<SerializedScriptValue> message, const String& sourceOrigin, PassRefPtr<DOMWindow> source, PassOwnPtr<MessagePortChannelArray> channels, SecurityOrigin* targetOrigin) 124 : m_window(window) 125 , m_message(message) 126 , m_origin(sourceOrigin) 127 , m_source(source) 128 , m_channels(channels) 129 , m_targetOrigin(targetOrigin) 130 { 131 } 132 133 PassRefPtr<MessageEvent> event(ScriptExecutionContext* context) 134 { 135 OwnPtr<MessagePortArray> messagePorts = MessagePort::entanglePorts(*context, m_channels.release()); 136 return MessageEvent::create(messagePorts.release(), m_message, m_origin, "", m_source); 137 } 138 SecurityOrigin* targetOrigin() const { return m_targetOrigin.get(); } 139 140private: 141 virtual void fired() 142 { 143 m_window->postMessageTimerFired(this); 144 } 145 146 RefPtr<DOMWindow> m_window; 147 RefPtr<SerializedScriptValue> m_message; 148 String m_origin; 149 RefPtr<DOMWindow> m_source; 150 OwnPtr<MessagePortChannelArray> m_channels; 151 RefPtr<SecurityOrigin> m_targetOrigin; 152}; 153 154typedef HashCountedSet<DOMWindow*> DOMWindowSet; 155 156static DOMWindowSet& windowsWithUnloadEventListeners() 157{ 158 DEFINE_STATIC_LOCAL(DOMWindowSet, windowsWithUnloadEventListeners, ()); 159 return windowsWithUnloadEventListeners; 160} 161 162static DOMWindowSet& windowsWithBeforeUnloadEventListeners() 163{ 164 DEFINE_STATIC_LOCAL(DOMWindowSet, windowsWithBeforeUnloadEventListeners, ()); 165 return windowsWithBeforeUnloadEventListeners; 166} 167 168static void addUnloadEventListener(DOMWindow* domWindow) 169{ 170 DOMWindowSet& set = windowsWithUnloadEventListeners(); 171 if (set.isEmpty()) 172 disableSuddenTermination(); 173 set.add(domWindow); 174} 175 176static void removeUnloadEventListener(DOMWindow* domWindow) 177{ 178 DOMWindowSet& set = windowsWithUnloadEventListeners(); 179 DOMWindowSet::iterator it = set.find(domWindow); 180 if (it == set.end()) 181 return; 182 set.remove(it); 183 if (set.isEmpty()) 184 enableSuddenTermination(); 185} 186 187static void removeAllUnloadEventListeners(DOMWindow* domWindow) 188{ 189 DOMWindowSet& set = windowsWithUnloadEventListeners(); 190 DOMWindowSet::iterator it = set.find(domWindow); 191 if (it == set.end()) 192 return; 193 set.removeAll(it); 194 if (set.isEmpty()) 195 enableSuddenTermination(); 196} 197 198static void addBeforeUnloadEventListener(DOMWindow* domWindow) 199{ 200 DOMWindowSet& set = windowsWithBeforeUnloadEventListeners(); 201 if (set.isEmpty()) 202 disableSuddenTermination(); 203 set.add(domWindow); 204} 205 206static void removeBeforeUnloadEventListener(DOMWindow* domWindow) 207{ 208 DOMWindowSet& set = windowsWithBeforeUnloadEventListeners(); 209 DOMWindowSet::iterator it = set.find(domWindow); 210 if (it == set.end()) 211 return; 212 set.remove(it); 213 if (set.isEmpty()) 214 enableSuddenTermination(); 215} 216 217static void removeAllBeforeUnloadEventListeners(DOMWindow* domWindow) 218{ 219 DOMWindowSet& set = windowsWithBeforeUnloadEventListeners(); 220 DOMWindowSet::iterator it = set.find(domWindow); 221 if (it == set.end()) 222 return; 223 set.removeAll(it); 224 if (set.isEmpty()) 225 enableSuddenTermination(); 226} 227 228static bool allowsBeforeUnloadListeners(DOMWindow* window) 229{ 230 ASSERT_ARG(window, window); 231 Frame* frame = window->frame(); 232 if (!frame) 233 return false; 234 Page* page = frame->page(); 235 if (!page) 236 return false; 237 return frame == page->mainFrame(); 238} 239 240bool DOMWindow::dispatchAllPendingBeforeUnloadEvents() 241{ 242 DOMWindowSet& set = windowsWithBeforeUnloadEventListeners(); 243 if (set.isEmpty()) 244 return true; 245 246 static bool alreadyDispatched = false; 247 ASSERT(!alreadyDispatched); 248 if (alreadyDispatched) 249 return true; 250 251 Vector<RefPtr<DOMWindow> > windows; 252 DOMWindowSet::iterator end = set.end(); 253 for (DOMWindowSet::iterator it = set.begin(); it != end; ++it) 254 windows.append(it->first); 255 256 size_t size = windows.size(); 257 for (size_t i = 0; i < size; ++i) { 258 DOMWindow* window = windows[i].get(); 259 if (!set.contains(window)) 260 continue; 261 262 Frame* frame = window->frame(); 263 if (!frame) 264 continue; 265 266 if (!frame->loader()->shouldClose()) 267 return false; 268 } 269 270 enableSuddenTermination(); 271 272 alreadyDispatched = true; 273 274 return true; 275} 276 277unsigned DOMWindow::pendingUnloadEventListeners() const 278{ 279 return windowsWithUnloadEventListeners().count(const_cast<DOMWindow*>(this)); 280} 281 282void DOMWindow::dispatchAllPendingUnloadEvents() 283{ 284 DOMWindowSet& set = windowsWithUnloadEventListeners(); 285 if (set.isEmpty()) 286 return; 287 288 static bool alreadyDispatched = false; 289 ASSERT(!alreadyDispatched); 290 if (alreadyDispatched) 291 return; 292 293 Vector<RefPtr<DOMWindow> > windows; 294 DOMWindowSet::iterator end = set.end(); 295 for (DOMWindowSet::iterator it = set.begin(); it != end; ++it) 296 windows.append(it->first); 297 298 size_t size = windows.size(); 299 for (size_t i = 0; i < size; ++i) { 300 DOMWindow* window = windows[i].get(); 301 if (!set.contains(window)) 302 continue; 303 304 window->dispatchEvent(PageTransitionEvent::create(eventNames().pagehideEvent, false), window->document()); 305 window->dispatchEvent(Event::create(eventNames().unloadEvent, false, false), window->document()); 306 } 307 308 enableSuddenTermination(); 309 310 alreadyDispatched = true; 311} 312 313// This function: 314// 1) Validates the pending changes are not changing to NaN 315// 2) Constrains the window rect to no smaller than 100 in each dimension and no 316// bigger than the the float rect's dimensions. 317// 3) Constrain window rect to within the top and left boundaries of the screen rect 318// 4) Constraint the window rect to within the bottom and right boundaries of the 319// screen rect. 320// 5) Translate the window rect coordinates to be within the coordinate space of 321// the screen rect. 322void DOMWindow::adjustWindowRect(const FloatRect& screen, FloatRect& window, const FloatRect& pendingChanges) 323{ 324 // Make sure we're in a valid state before adjusting dimensions. 325 ASSERT(isfinite(screen.x())); 326 ASSERT(isfinite(screen.y())); 327 ASSERT(isfinite(screen.width())); 328 ASSERT(isfinite(screen.height())); 329 ASSERT(isfinite(window.x())); 330 ASSERT(isfinite(window.y())); 331 ASSERT(isfinite(window.width())); 332 ASSERT(isfinite(window.height())); 333 334 // Update window values if new requested values are not NaN. 335 if (!isnan(pendingChanges.x())) 336 window.setX(pendingChanges.x()); 337 if (!isnan(pendingChanges.y())) 338 window.setY(pendingChanges.y()); 339 if (!isnan(pendingChanges.width())) 340 window.setWidth(pendingChanges.width()); 341 if (!isnan(pendingChanges.height())) 342 window.setHeight(pendingChanges.height()); 343 344 // Resize the window to between 100 and the screen width and height. 345 window.setWidth(min(max(100.0f, window.width()), screen.width())); 346 window.setHeight(min(max(100.0f, window.height()), screen.height())); 347 348 // Constrain the window position to the screen. 349 window.setX(max(screen.x(), min(window.x(), screen.maxX() - window.width()))); 350 window.setY(max(screen.y(), min(window.y(), screen.maxY() - window.height()))); 351} 352 353// FIXME: We can remove this function once V8 showModalDialog is changed to use DOMWindow. 354void DOMWindow::parseModalDialogFeatures(const String& string, HashMap<String, String>& map) 355{ 356 WindowFeatures::parseDialogFeatures(string, map); 357} 358 359bool DOMWindow::allowPopUp(Frame* firstFrame) 360{ 361 ASSERT(firstFrame); 362 363 if (ScriptController::processingUserGesture()) 364 return true; 365 366 Settings* settings = firstFrame->settings(); 367 return settings && settings->javaScriptCanOpenWindowsAutomatically(); 368} 369 370bool DOMWindow::allowPopUp() 371{ 372 return m_frame && allowPopUp(m_frame); 373} 374 375bool DOMWindow::canShowModalDialog(const Frame* frame) 376{ 377 if (!frame) 378 return false; 379 Page* page = frame->page(); 380 if (!page) 381 return false; 382 return page->chrome()->canRunModal(); 383} 384 385bool DOMWindow::canShowModalDialogNow(const Frame* frame) 386{ 387 if (!frame) 388 return false; 389 Page* page = frame->page(); 390 if (!page) 391 return false; 392 return page->chrome()->canRunModalNow(); 393} 394 395DOMWindow::DOMWindow(Frame* frame) 396 : m_shouldPrintWhenFinishedLoading(false) 397 , m_frame(frame) 398 , m_printTimer(this, &DOMWindow::printTimerFired) 399{ 400} 401 402DOMWindow::~DOMWindow() 403{ 404 if (m_frame) 405 m_frame->clearFormerDOMWindow(this); 406 407 removeAllUnloadEventListeners(this); 408 removeAllBeforeUnloadEventListeners(this); 409} 410 411ScriptExecutionContext* DOMWindow::scriptExecutionContext() const 412{ 413 return document(); 414} 415 416PassRefPtr<MediaQueryList> DOMWindow::matchMedia(const String& media) 417{ 418 return document() ? document()->mediaQueryMatcher()->matchMedia(media) : 0; 419} 420 421void DOMWindow::disconnectFrame() 422{ 423 m_frame = 0; 424 clear(); 425} 426 427void DOMWindow::clear() 428{ 429 if (m_screen) 430 m_screen->disconnectFrame(); 431 m_screen = 0; 432 433 if (m_selection) 434 m_selection->disconnectFrame(); 435 m_selection = 0; 436 437 if (m_history) 438 m_history->disconnectFrame(); 439 m_history = 0; 440 441 m_crypto = 0; 442 443 if (m_locationbar) 444 m_locationbar->disconnectFrame(); 445 m_locationbar = 0; 446 447 if (m_menubar) 448 m_menubar->disconnectFrame(); 449 m_menubar = 0; 450 451 if (m_personalbar) 452 m_personalbar->disconnectFrame(); 453 m_personalbar = 0; 454 455 if (m_scrollbars) 456 m_scrollbars->disconnectFrame(); 457 m_scrollbars = 0; 458 459 if (m_statusbar) 460 m_statusbar->disconnectFrame(); 461 m_statusbar = 0; 462 463 if (m_toolbar) 464 m_toolbar->disconnectFrame(); 465 m_toolbar = 0; 466 467 if (m_console) 468 m_console->disconnectFrame(); 469 m_console = 0; 470 471 if (m_navigator) 472 m_navigator->disconnectFrame(); 473 m_navigator = 0; 474 475#if ENABLE(WEB_TIMING) 476 if (m_performance) 477 m_performance->disconnectFrame(); 478 m_performance = 0; 479#endif 480 481 if (m_location) 482 m_location->disconnectFrame(); 483 m_location = 0; 484 485 if (m_media) 486 m_media->disconnectFrame(); 487 m_media = 0; 488 489#if ENABLE(DOM_STORAGE) 490 if (m_sessionStorage) 491 m_sessionStorage->disconnectFrame(); 492 m_sessionStorage = 0; 493 494 if (m_localStorage) 495 m_localStorage->disconnectFrame(); 496 m_localStorage = 0; 497#endif 498 499#if ENABLE(OFFLINE_WEB_APPLICATIONS) 500 if (m_applicationCache) 501 m_applicationCache->disconnectFrame(); 502 m_applicationCache = 0; 503#endif 504 505#if ENABLE(NOTIFICATIONS) 506 if (m_notifications) 507 m_notifications->disconnectFrame(); 508 m_notifications = 0; 509#endif 510 511#if ENABLE(INDEXED_DATABASE) 512 m_idbFactory = 0; 513#endif 514} 515 516#if ENABLE(ORIENTATION_EVENTS) 517int DOMWindow::orientation() const 518{ 519 if (!m_frame) 520 return 0; 521 522 return m_frame->orientation(); 523} 524#endif 525 526Screen* DOMWindow::screen() const 527{ 528 if (!m_screen) 529 m_screen = Screen::create(m_frame); 530 return m_screen.get(); 531} 532 533History* DOMWindow::history() const 534{ 535 if (!m_history) 536 m_history = History::create(m_frame); 537 return m_history.get(); 538} 539 540Crypto* DOMWindow::crypto() const 541{ 542 if (!m_crypto) 543 m_crypto = Crypto::create(); 544 return m_crypto.get(); 545} 546 547BarInfo* DOMWindow::locationbar() const 548{ 549 if (!m_locationbar) 550 m_locationbar = BarInfo::create(m_frame, BarInfo::Locationbar); 551 return m_locationbar.get(); 552} 553 554BarInfo* DOMWindow::menubar() const 555{ 556 if (!m_menubar) 557 m_menubar = BarInfo::create(m_frame, BarInfo::Menubar); 558 return m_menubar.get(); 559} 560 561BarInfo* DOMWindow::personalbar() const 562{ 563 if (!m_personalbar) 564 m_personalbar = BarInfo::create(m_frame, BarInfo::Personalbar); 565 return m_personalbar.get(); 566} 567 568BarInfo* DOMWindow::scrollbars() const 569{ 570 if (!m_scrollbars) 571 m_scrollbars = BarInfo::create(m_frame, BarInfo::Scrollbars); 572 return m_scrollbars.get(); 573} 574 575BarInfo* DOMWindow::statusbar() const 576{ 577 if (!m_statusbar) 578 m_statusbar = BarInfo::create(m_frame, BarInfo::Statusbar); 579 return m_statusbar.get(); 580} 581 582BarInfo* DOMWindow::toolbar() const 583{ 584 if (!m_toolbar) 585 m_toolbar = BarInfo::create(m_frame, BarInfo::Toolbar); 586 return m_toolbar.get(); 587} 588 589Console* DOMWindow::console() const 590{ 591 if (!m_console) 592 m_console = Console::create(m_frame); 593 return m_console.get(); 594} 595 596#if ENABLE(OFFLINE_WEB_APPLICATIONS) 597DOMApplicationCache* DOMWindow::applicationCache() const 598{ 599 if (!m_applicationCache) 600 m_applicationCache = DOMApplicationCache::create(m_frame); 601 return m_applicationCache.get(); 602} 603#endif 604 605Navigator* DOMWindow::navigator() const 606{ 607 if (!m_navigator) 608 m_navigator = Navigator::create(m_frame); 609 return m_navigator.get(); 610} 611 612#if ENABLE(WEB_TIMING) 613Performance* DOMWindow::performance() const 614{ 615 if (!m_performance) 616 m_performance = Performance::create(m_frame); 617 return m_performance.get(); 618} 619#endif 620 621Location* DOMWindow::location() const 622{ 623 if (!m_location) 624 m_location = Location::create(m_frame); 625 return m_location.get(); 626} 627 628#if ENABLE(DOM_STORAGE) 629Storage* DOMWindow::sessionStorage(ExceptionCode& ec) const 630{ 631 if (m_sessionStorage) 632 return m_sessionStorage.get(); 633 634 Document* document = this->document(); 635 if (!document) 636 return 0; 637 638 if (!document->securityOrigin()->canAccessLocalStorage()) { 639 ec = SECURITY_ERR; 640 return 0; 641 } 642 643 Page* page = document->page(); 644 if (!page) 645 return 0; 646 647 RefPtr<StorageArea> storageArea = page->sessionStorage()->storageArea(document->securityOrigin()); 648 InspectorInstrumentation::didUseDOMStorage(page, storageArea.get(), false, m_frame); 649 650 m_sessionStorage = Storage::create(m_frame, storageArea.release()); 651 return m_sessionStorage.get(); 652} 653 654Storage* DOMWindow::localStorage(ExceptionCode& ec) const 655{ 656 if (m_localStorage) 657 return m_localStorage.get(); 658 659 Document* document = this->document(); 660 if (!document) 661 return 0; 662 663 if (!document->securityOrigin()->canAccessLocalStorage()) { 664 ec = SECURITY_ERR; 665 return 0; 666 } 667 668 Page* page = document->page(); 669 if (!page) 670 return 0; 671 672 if (!page->settings()->localStorageEnabled()) 673 return 0; 674 675 RefPtr<StorageArea> storageArea = page->group().localStorage()->storageArea(document->securityOrigin()); 676 InspectorInstrumentation::didUseDOMStorage(page, storageArea.get(), true, m_frame); 677 678 m_localStorage = Storage::create(m_frame, storageArea.release()); 679 return m_localStorage.get(); 680} 681#endif 682 683#if ENABLE(NOTIFICATIONS) 684NotificationCenter* DOMWindow::webkitNotifications() const 685{ 686 if (m_notifications) 687 return m_notifications.get(); 688 689 Document* document = this->document(); 690 if (!document) 691 return 0; 692 693 Page* page = document->page(); 694 if (!page) 695 return 0; 696 697 NotificationPresenter* provider = page->chrome()->notificationPresenter(); 698 if (provider) 699 m_notifications = NotificationCenter::create(document, provider); 700 701 return m_notifications.get(); 702} 703#endif 704 705void DOMWindow::pageDestroyed() 706{ 707#if ENABLE(NOTIFICATIONS) 708 // Clearing Notifications requests involves accessing the client so it must be done 709 // before the frame is detached. 710 if (m_notifications) 711 m_notifications->disconnectFrame(); 712 m_notifications = 0; 713#endif 714} 715 716void DOMWindow::resetGeolocation() 717{ 718 // Geolocation should cancel activities and permission requests when the page is detached. 719 if (m_navigator) 720 m_navigator->resetGeolocation(); 721} 722 723#if ENABLE(INDEXED_DATABASE) 724IDBFactory* DOMWindow::webkitIndexedDB() const 725{ 726 if (m_idbFactory) 727 return m_idbFactory.get(); 728 729 Document* document = this->document(); 730 if (!document) 731 return 0; 732 733 // FIXME: See if access is allowed. 734 735 Page* page = document->page(); 736 if (!page) 737 return 0; 738 739 // FIXME: See if indexedDatabase access is allowed. 740 741 m_idbFactory = IDBFactory::create(page->group().idbFactory()); 742 return m_idbFactory.get(); 743} 744#endif 745 746#if ENABLE(FILE_SYSTEM) 747void DOMWindow::webkitRequestFileSystem(int type, long long size, PassRefPtr<FileSystemCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback) 748{ 749 Document* document = this->document(); 750 if (!document) 751 return; 752 753 if (!AsyncFileSystem::isAvailable() || !document->securityOrigin()->canAccessFileSystem()) { 754 DOMFileSystem::scheduleCallback(document, errorCallback, FileError::create(FileError::SECURITY_ERR)); 755 return; 756 } 757 758 AsyncFileSystem::Type fileSystemType = static_cast<AsyncFileSystem::Type>(type); 759 if (fileSystemType != AsyncFileSystem::Temporary && fileSystemType != AsyncFileSystem::Persistent && fileSystemType != AsyncFileSystem::External) { 760 DOMFileSystem::scheduleCallback(document, errorCallback, FileError::create(FileError::INVALID_MODIFICATION_ERR)); 761 return; 762 } 763 764 LocalFileSystem::localFileSystem().requestFileSystem(document, fileSystemType, size, FileSystemCallbacks::create(successCallback, errorCallback, document), false); 765} 766 767void DOMWindow::webkitResolveLocalFileSystemURL(const String& url, PassRefPtr<EntryCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback) 768{ 769 Document* document = this->document(); 770 if (!document) 771 return; 772 773 SecurityOrigin* securityOrigin = document->securityOrigin(); 774 KURL completedURL = document->completeURL(url); 775 if (!AsyncFileSystem::isAvailable() || !securityOrigin->canAccessFileSystem() || !securityOrigin->canRequest(completedURL)) { 776 DOMFileSystem::scheduleCallback(document, errorCallback, FileError::create(FileError::SECURITY_ERR)); 777 return; 778 } 779 780 AsyncFileSystem::Type type; 781 String filePath; 782 if (!completedURL.isValid() || !DOMFileSystemBase::crackFileSystemURL(completedURL, type, filePath)) { 783 DOMFileSystem::scheduleCallback(document, errorCallback, FileError::create(FileError::ENCODING_ERR)); 784 return; 785 } 786 787 LocalFileSystem::localFileSystem().readFileSystem(document, type, ResolveURICallbacks::create(successCallback, errorCallback, document, filePath)); 788} 789 790COMPILE_ASSERT(static_cast<int>(DOMWindow::EXTERNAL) == static_cast<int>(AsyncFileSystem::External), enum_mismatch); 791 792COMPILE_ASSERT(static_cast<int>(DOMWindow::TEMPORARY) == static_cast<int>(AsyncFileSystem::Temporary), enum_mismatch); 793COMPILE_ASSERT(static_cast<int>(DOMWindow::PERSISTENT) == static_cast<int>(AsyncFileSystem::Persistent), enum_mismatch); 794 795#endif 796 797void DOMWindow::postMessage(PassRefPtr<SerializedScriptValue> message, MessagePort* port, const String& targetOrigin, DOMWindow* source, ExceptionCode& ec) 798{ 799 MessagePortArray ports; 800 if (port) 801 ports.append(port); 802 postMessage(message, &ports, targetOrigin, source, ec); 803} 804 805void DOMWindow::postMessage(PassRefPtr<SerializedScriptValue> message, const MessagePortArray* ports, const String& targetOrigin, DOMWindow* source, ExceptionCode& ec) 806{ 807 if (!m_frame) 808 return; 809 810 // Compute the target origin. We need to do this synchronously in order 811 // to generate the SYNTAX_ERR exception correctly. 812 RefPtr<SecurityOrigin> target; 813 if (targetOrigin != "*") { 814 target = SecurityOrigin::createFromString(targetOrigin); 815 if (target->isEmpty()) { 816 ec = SYNTAX_ERR; 817 return; 818 } 819 } 820 821 OwnPtr<MessagePortChannelArray> channels = MessagePort::disentanglePorts(ports, ec); 822 if (ec) 823 return; 824 825 // Capture the source of the message. We need to do this synchronously 826 // in order to capture the source of the message correctly. 827 Document* sourceDocument = source->document(); 828 if (!sourceDocument) 829 return; 830 String sourceOrigin = sourceDocument->securityOrigin()->toString(); 831 832 // Schedule the message. 833 PostMessageTimer* timer = new PostMessageTimer(this, message, sourceOrigin, source, channels.release(), target.get()); 834 timer->startOneShot(0); 835} 836 837void DOMWindow::postMessageTimerFired(PostMessageTimer* t) 838{ 839 OwnPtr<PostMessageTimer> timer(t); 840 841 if (!document()) 842 return; 843 844 if (timer->targetOrigin()) { 845 // Check target origin now since the target document may have changed since the simer was scheduled. 846 if (!timer->targetOrigin()->isSameSchemeHostPort(document()->securityOrigin())) { 847 String message = makeString("Unable to post message to ", timer->targetOrigin()->toString(), 848 ". Recipient has origin ", document()->securityOrigin()->toString(), ".\n"); 849 console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, 0, String()); 850 return; 851 } 852 } 853 854 dispatchEvent(timer->event(document())); 855} 856 857DOMSelection* DOMWindow::getSelection() 858{ 859 if (!m_selection) 860 m_selection = DOMSelection::create(m_frame); 861 return m_selection.get(); 862} 863 864Element* DOMWindow::frameElement() const 865{ 866 if (!m_frame) 867 return 0; 868 869 return m_frame->ownerElement(); 870} 871 872void DOMWindow::focus() 873{ 874 if (!m_frame) 875 return; 876 877 Page* page = m_frame->page(); 878 if (!page) 879 return; 880 881 // If we're a top level window, bring the window to the front. 882 if (m_frame == page->mainFrame()) 883 page->chrome()->focus(); 884 885 if (!m_frame) 886 return; 887 888 m_frame->eventHandler()->focusDocumentView(); 889} 890 891void DOMWindow::blur() 892{ 893 if (!m_frame) 894 return; 895 896 Page* page = m_frame->page(); 897 if (!page) 898 return; 899 900 if (m_frame != page->mainFrame()) 901 return; 902 903 page->chrome()->unfocus(); 904} 905 906void DOMWindow::close(ScriptExecutionContext* context) 907{ 908 if (!m_frame) 909 return; 910 911 Page* page = m_frame->page(); 912 if (!page) 913 return; 914 915 if (m_frame != page->mainFrame()) 916 return; 917 918 if (context) { 919 ASSERT(WTF::isMainThread()); 920 Frame* activeFrame = static_cast<Document*>(context)->frame(); 921 if (!activeFrame) 922 return; 923 924 if (!activeFrame->loader()->shouldAllowNavigation(m_frame)) 925 return; 926 } 927 928 Settings* settings = m_frame->settings(); 929 bool allowScriptsToCloseWindows = settings && settings->allowScriptsToCloseWindows(); 930 931 if (!(page->openedByDOM() || page->backForward()->count() <= 1 || allowScriptsToCloseWindows)) 932 return; 933 934 if (!m_frame->loader()->shouldClose()) 935 return; 936 937 page->chrome()->closeWindowSoon(); 938} 939 940void DOMWindow::print() 941{ 942 if (!m_frame) 943 return; 944 945 Page* page = m_frame->page(); 946 if (!page) 947 return; 948 949 if (m_frame->loader()->activeDocumentLoader()->isLoading()) { 950 m_shouldPrintWhenFinishedLoading = true; 951 return; 952 } 953 m_shouldPrintWhenFinishedLoading = false; 954 page->chrome()->print(m_frame); 955} 956 957void DOMWindow::printTimerFired(Timer<DOMWindow>* timer) 958{ 959 ASSERT_UNUSED(timer, timer == &m_printTimer); 960 print(); 961} 962 963void DOMWindow::stop() 964{ 965 if (!m_frame) 966 return; 967 968 // We must check whether the load is complete asynchronously, because we might still be parsing 969 // the document until the callstack unwinds. 970 m_frame->loader()->stopForUserCancel(true); 971} 972 973void DOMWindow::alert(const String& message) 974{ 975 if (!m_frame) 976 return; 977 978 m_frame->document()->updateStyleIfNeeded(); 979 980 Page* page = m_frame->page(); 981 if (!page) 982 return; 983 984 page->chrome()->runJavaScriptAlert(m_frame, message); 985} 986 987bool DOMWindow::confirm(const String& message) 988{ 989 if (!m_frame) 990 return false; 991 992 m_frame->document()->updateStyleIfNeeded(); 993 994 Page* page = m_frame->page(); 995 if (!page) 996 return false; 997 998 return page->chrome()->runJavaScriptConfirm(m_frame, message); 999} 1000 1001String DOMWindow::prompt(const String& message, const String& defaultValue) 1002{ 1003 if (!m_frame) 1004 return String(); 1005 1006 m_frame->document()->updateStyleIfNeeded(); 1007 1008 Page* page = m_frame->page(); 1009 if (!page) 1010 return String(); 1011 1012 String returnValue; 1013 if (page->chrome()->runJavaScriptPrompt(m_frame, message, defaultValue, returnValue)) 1014 return returnValue; 1015 1016 return String(); 1017} 1018 1019String DOMWindow::btoa(const String& stringToEncode, ExceptionCode& ec) 1020{ 1021 if (stringToEncode.isNull()) 1022 return String(); 1023 1024 if (!stringToEncode.containsOnlyLatin1()) { 1025 ec = INVALID_CHARACTER_ERR; 1026 return String(); 1027 } 1028 1029 return base64Encode(stringToEncode.latin1()); 1030} 1031 1032String DOMWindow::atob(const String& encodedString, ExceptionCode& ec) 1033{ 1034 if (encodedString.isNull()) 1035 return String(); 1036 1037 if (!encodedString.containsOnlyLatin1()) { 1038 ec = INVALID_CHARACTER_ERR; 1039 return String(); 1040 } 1041 1042 Vector<char> out; 1043 if (!base64Decode(encodedString, out, FailOnInvalidCharacter)) { 1044 ec = INVALID_CHARACTER_ERR; 1045 return String(); 1046 } 1047 1048 return String(out.data(), out.size()); 1049} 1050 1051bool DOMWindow::find(const String& string, bool caseSensitive, bool backwards, bool wrap, bool /*wholeWord*/, bool /*searchInFrames*/, bool /*showDialog*/) const 1052{ 1053 if (!m_frame) 1054 return false; 1055 1056 // FIXME (13016): Support wholeWord, searchInFrames and showDialog 1057 return m_frame->editor()->findString(string, !backwards, caseSensitive, wrap, false); 1058} 1059 1060bool DOMWindow::offscreenBuffering() const 1061{ 1062 return true; 1063} 1064 1065int DOMWindow::outerHeight() const 1066{ 1067 if (!m_frame) 1068 return 0; 1069 1070 Page* page = m_frame->page(); 1071 if (!page) 1072 return 0; 1073 1074 return static_cast<int>(page->chrome()->windowRect().height()); 1075} 1076 1077int DOMWindow::outerWidth() const 1078{ 1079 if (!m_frame) 1080 return 0; 1081 1082 Page* page = m_frame->page(); 1083 if (!page) 1084 return 0; 1085 1086 return static_cast<int>(page->chrome()->windowRect().width()); 1087} 1088 1089int DOMWindow::innerHeight() const 1090{ 1091 if (!m_frame) 1092 return 0; 1093 1094 FrameView* view = m_frame->view(); 1095 if (!view) 1096 return 0; 1097 1098#if PLATFORM(ANDROID) 1099 return static_cast<int>(view->actualHeight() / m_frame->pageZoomFactor()); 1100#else 1101 return static_cast<int>(view->height() / m_frame->pageZoomFactor()); 1102#endif 1103} 1104 1105int DOMWindow::innerWidth() const 1106{ 1107 if (!m_frame) 1108 return 0; 1109 1110 FrameView* view = m_frame->view(); 1111 if (!view) 1112 return 0; 1113 1114#if PLATFORM(ANDROID) 1115 return static_cast<int>(view->actualWidth() / m_frame->pageZoomFactor()); 1116#else 1117 return static_cast<int>(view->width() / m_frame->pageZoomFactor()); 1118#endif 1119} 1120 1121int DOMWindow::screenX() const 1122{ 1123 if (!m_frame) 1124 return 0; 1125 1126 Page* page = m_frame->page(); 1127 if (!page) 1128 return 0; 1129 1130 return static_cast<int>(page->chrome()->windowRect().x()); 1131} 1132 1133int DOMWindow::screenY() const 1134{ 1135 if (!m_frame) 1136 return 0; 1137 1138 Page* page = m_frame->page(); 1139 if (!page) 1140 return 0; 1141 1142 return static_cast<int>(page->chrome()->windowRect().y()); 1143} 1144 1145int DOMWindow::scrollX() const 1146{ 1147 if (!m_frame) 1148 return 0; 1149 1150 FrameView* view = m_frame->view(); 1151 if (!view) 1152 return 0; 1153 1154 m_frame->document()->updateLayoutIgnorePendingStylesheets(); 1155 1156#if PLATFORM(ANDROID) 1157 return static_cast<int>(view->actualScrollX() / m_frame->pageZoomFactor()); 1158#else 1159 return static_cast<int>(view->scrollX() / m_frame->pageZoomFactor()); 1160#endif 1161} 1162 1163int DOMWindow::scrollY() const 1164{ 1165 if (!m_frame) 1166 return 0; 1167 1168 FrameView* view = m_frame->view(); 1169 if (!view) 1170 return 0; 1171 1172 m_frame->document()->updateLayoutIgnorePendingStylesheets(); 1173 1174#if PLATFORM(ANDROID) 1175 return static_cast<int>(view->actualScrollY() / m_frame->pageZoomFactor()); 1176#else 1177 return static_cast<int>(view->scrollY() / m_frame->pageZoomFactor()); 1178#endif 1179} 1180 1181bool DOMWindow::closed() const 1182{ 1183 return !m_frame; 1184} 1185 1186unsigned DOMWindow::length() const 1187{ 1188 if (!m_frame) 1189 return 0; 1190 1191 return m_frame->tree()->childCount(); 1192} 1193 1194String DOMWindow::name() const 1195{ 1196 if (!m_frame) 1197 return String(); 1198 1199 return m_frame->tree()->name(); 1200} 1201 1202void DOMWindow::setName(const String& string) 1203{ 1204 if (!m_frame) 1205 return; 1206 1207 m_frame->tree()->setName(string); 1208} 1209 1210void DOMWindow::setStatus(const String& string) 1211{ 1212 m_status = string; 1213 1214 if (!m_frame) 1215 return; 1216 1217 Page* page = m_frame->page(); 1218 if (!page) 1219 return; 1220 1221 ASSERT(m_frame->document()); // Client calls shouldn't be made when the frame is in inconsistent state. 1222 page->chrome()->setStatusbarText(m_frame, m_status); 1223} 1224 1225void DOMWindow::setDefaultStatus(const String& string) 1226{ 1227 m_defaultStatus = string; 1228 1229 if (!m_frame) 1230 return; 1231 1232 Page* page = m_frame->page(); 1233 if (!page) 1234 return; 1235 1236 ASSERT(m_frame->document()); // Client calls shouldn't be made when the frame is in inconsistent state. 1237 page->chrome()->setStatusbarText(m_frame, m_defaultStatus); 1238} 1239 1240DOMWindow* DOMWindow::self() const 1241{ 1242 if (!m_frame) 1243 return 0; 1244 1245 return m_frame->domWindow(); 1246} 1247 1248DOMWindow* DOMWindow::opener() const 1249{ 1250 if (!m_frame) 1251 return 0; 1252 1253 Frame* opener = m_frame->loader()->opener(); 1254 if (!opener) 1255 return 0; 1256 1257 return opener->domWindow(); 1258} 1259 1260DOMWindow* DOMWindow::parent() const 1261{ 1262 if (!m_frame) 1263 return 0; 1264 1265 Frame* parent = m_frame->tree()->parent(true); 1266 if (parent) 1267 return parent->domWindow(); 1268 1269 return m_frame->domWindow(); 1270} 1271 1272DOMWindow* DOMWindow::top() const 1273{ 1274 if (!m_frame) 1275 return 0; 1276 1277 Page* page = m_frame->page(); 1278 if (!page) 1279 return 0; 1280 1281 return m_frame->tree()->top(true)->domWindow(); 1282} 1283 1284Document* DOMWindow::document() const 1285{ 1286 // FIXME: This function shouldn't need a frame to work. 1287 if (!m_frame) 1288 return 0; 1289 1290 // The m_frame pointer is not zeroed out when the window is put into b/f cache, so it can hold an unrelated document/window pair. 1291 // FIXME: We should always zero out the frame pointer on navigation to avoid accidentally accessing the new frame content. 1292 if (m_frame->domWindow() != this) 1293 return 0; 1294 1295 ASSERT(m_frame->document()); 1296 return m_frame->document(); 1297} 1298 1299PassRefPtr<StyleMedia> DOMWindow::styleMedia() const 1300{ 1301 if (!m_media) 1302 m_media = StyleMedia::create(m_frame); 1303 return m_media.get(); 1304} 1305 1306PassRefPtr<CSSStyleDeclaration> DOMWindow::getComputedStyle(Element* elt, const String& pseudoElt) const 1307{ 1308 if (!elt) 1309 return 0; 1310 1311 return computedStyle(elt, false, pseudoElt); 1312} 1313 1314PassRefPtr<CSSRuleList> DOMWindow::getMatchedCSSRules(Element* elt, const String&, bool authorOnly) const 1315{ 1316 if (!m_frame) 1317 return 0; 1318 1319 Settings* settings = m_frame->settings(); 1320 return m_frame->document()->styleSelector()->styleRulesForElement(elt, authorOnly, false, settings && settings->crossOriginCheckInGetMatchedCSSRulesDisabled() ? AllCSSRules : SameOriginCSSRulesOnly); 1321} 1322 1323PassRefPtr<WebKitPoint> DOMWindow::webkitConvertPointFromNodeToPage(Node* node, const WebKitPoint* p) const 1324{ 1325 if (!node || !p) 1326 return 0; 1327 1328 m_frame->document()->updateLayoutIgnorePendingStylesheets(); 1329 1330 FloatPoint pagePoint(p->x(), p->y()); 1331 pagePoint = node->convertToPage(pagePoint); 1332 return WebKitPoint::create(pagePoint.x(), pagePoint.y()); 1333} 1334 1335PassRefPtr<WebKitPoint> DOMWindow::webkitConvertPointFromPageToNode(Node* node, const WebKitPoint* p) const 1336{ 1337 if (!node || !p) 1338 return 0; 1339 1340 m_frame->document()->updateLayoutIgnorePendingStylesheets(); 1341 1342 FloatPoint nodePoint(p->x(), p->y()); 1343 nodePoint = node->convertFromPage(nodePoint); 1344 return WebKitPoint::create(nodePoint.x(), nodePoint.y()); 1345} 1346 1347double DOMWindow::devicePixelRatio() const 1348{ 1349 if (!m_frame) 1350 return 0.0; 1351 1352 Page* page = m_frame->page(); 1353 if (!page) 1354 return 0.0; 1355 1356 return page->chrome()->scaleFactor(); 1357} 1358 1359#if ENABLE(DATABASE) 1360PassRefPtr<Database> DOMWindow::openDatabase(const String& name, const String& version, const String& displayName, unsigned long estimatedSize, PassRefPtr<DatabaseCallback> creationCallback, ExceptionCode& ec) 1361{ 1362 RefPtr<Database> database = 0; 1363 if (m_frame && AbstractDatabase::isAvailable() && m_frame->document()->securityOrigin()->canAccessDatabase()) 1364 database = Database::openDatabase(m_frame->document(), name, version, displayName, estimatedSize, creationCallback, ec); 1365 1366 if (!database && !ec) 1367 ec = SECURITY_ERR; 1368 1369 return database; 1370} 1371#endif 1372 1373void DOMWindow::scrollBy(int x, int y) const 1374{ 1375 if (!m_frame) 1376 return; 1377 1378 m_frame->document()->updateLayoutIgnorePendingStylesheets(); 1379 1380 RefPtr<FrameView> view = m_frame->view(); 1381 if (!view) 1382 return; 1383 1384 view->scrollBy(IntSize(x, y)); 1385} 1386 1387void DOMWindow::scrollTo(int x, int y) const 1388{ 1389 if (!m_frame) 1390 return; 1391 1392 m_frame->document()->updateLayoutIgnorePendingStylesheets(); 1393 1394 RefPtr<FrameView> view = m_frame->view(); 1395 if (!view) 1396 return; 1397 1398 int zoomedX = static_cast<int>(x * m_frame->pageZoomFactor()); 1399 int zoomedY = static_cast<int>(y * m_frame->pageZoomFactor()); 1400 view->setScrollPosition(IntPoint(zoomedX, zoomedY)); 1401} 1402 1403void DOMWindow::moveBy(float x, float y) const 1404{ 1405 if (!m_frame) 1406 return; 1407 1408 Page* page = m_frame->page(); 1409 if (!page) 1410 return; 1411 1412 if (m_frame != page->mainFrame()) 1413 return; 1414 1415 FloatRect fr = page->chrome()->windowRect(); 1416 FloatRect update = fr; 1417 update.move(x, y); 1418 // Security check (the spec talks about UniversalBrowserWrite to disable this check...) 1419 adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update); 1420 page->chrome()->setWindowRect(fr); 1421} 1422 1423void DOMWindow::moveTo(float x, float y) const 1424{ 1425 if (!m_frame) 1426 return; 1427 1428 Page* page = m_frame->page(); 1429 if (!page) 1430 return; 1431 1432 if (m_frame != page->mainFrame()) 1433 return; 1434 1435 FloatRect fr = page->chrome()->windowRect(); 1436 FloatRect sr = screenAvailableRect(page->mainFrame()->view()); 1437 fr.setLocation(sr.location()); 1438 FloatRect update = fr; 1439 update.move(x, y); 1440 // Security check (the spec talks about UniversalBrowserWrite to disable this check...) 1441 adjustWindowRect(sr, fr, update); 1442 page->chrome()->setWindowRect(fr); 1443} 1444 1445void DOMWindow::resizeBy(float x, float y) const 1446{ 1447 if (!m_frame) 1448 return; 1449 1450 Page* page = m_frame->page(); 1451 if (!page) 1452 return; 1453 1454 if (m_frame != page->mainFrame()) 1455 return; 1456 1457 FloatRect fr = page->chrome()->windowRect(); 1458 FloatSize dest = fr.size() + FloatSize(x, y); 1459 FloatRect update(fr.location(), dest); 1460 adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update); 1461 page->chrome()->setWindowRect(fr); 1462} 1463 1464void DOMWindow::resizeTo(float width, float height) const 1465{ 1466 if (!m_frame) 1467 return; 1468 1469 Page* page = m_frame->page(); 1470 if (!page) 1471 return; 1472 1473 if (m_frame != page->mainFrame()) 1474 return; 1475 1476 FloatRect fr = page->chrome()->windowRect(); 1477 FloatSize dest = FloatSize(width, height); 1478 FloatRect update(fr.location(), dest); 1479 adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update); 1480 page->chrome()->setWindowRect(fr); 1481} 1482 1483int DOMWindow::setTimeout(PassOwnPtr<ScheduledAction> action, int timeout, ExceptionCode& ec) 1484{ 1485 ScriptExecutionContext* context = scriptExecutionContext(); 1486 if (!context) { 1487 ec = INVALID_ACCESS_ERR; 1488 return -1; 1489 } 1490 return DOMTimer::install(context, action, timeout, true); 1491} 1492 1493void DOMWindow::clearTimeout(int timeoutId) 1494{ 1495 ScriptExecutionContext* context = scriptExecutionContext(); 1496 if (!context) 1497 return; 1498 DOMTimer::removeById(context, timeoutId); 1499} 1500 1501int DOMWindow::setInterval(PassOwnPtr<ScheduledAction> action, int timeout, ExceptionCode& ec) 1502{ 1503 ScriptExecutionContext* context = scriptExecutionContext(); 1504 if (!context) { 1505 ec = INVALID_ACCESS_ERR; 1506 return -1; 1507 } 1508 return DOMTimer::install(context, action, timeout, false); 1509} 1510 1511void DOMWindow::clearInterval(int timeoutId) 1512{ 1513 ScriptExecutionContext* context = scriptExecutionContext(); 1514 if (!context) 1515 return; 1516 DOMTimer::removeById(context, timeoutId); 1517} 1518 1519#if ENABLE(REQUEST_ANIMATION_FRAME) 1520int DOMWindow::webkitRequestAnimationFrame(PassRefPtr<RequestAnimationFrameCallback> callback, Element* e) 1521{ 1522 if (Document* d = document()) 1523 return d->webkitRequestAnimationFrame(callback, e); 1524 return 0; 1525} 1526 1527void DOMWindow::webkitCancelRequestAnimationFrame(int id) 1528{ 1529 if (Document* d = document()) 1530 d->webkitCancelRequestAnimationFrame(id); 1531} 1532#endif 1533 1534bool DOMWindow::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture) 1535{ 1536 if (!EventTarget::addEventListener(eventType, listener, useCapture)) 1537 return false; 1538 1539 if (Document* document = this->document()) 1540 document->addListenerTypeIfNeeded(eventType); 1541 1542 if (eventType == eventNames().unloadEvent) 1543 addUnloadEventListener(this); 1544 else if (eventType == eventNames().beforeunloadEvent && allowsBeforeUnloadListeners(this)) 1545 addBeforeUnloadEventListener(this); 1546#if ENABLE(DEVICE_ORIENTATION) 1547 else if (eventType == eventNames().devicemotionEvent && frame() && frame()->page() && frame()->page()->deviceMotionController()) 1548 frame()->page()->deviceMotionController()->addListener(this); 1549 else if (eventType == eventNames().deviceorientationEvent && frame() && frame()->page() && frame()->page()->deviceOrientationController()) 1550 frame()->page()->deviceOrientationController()->addListener(this); 1551#endif 1552 1553 return true; 1554} 1555 1556bool DOMWindow::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture) 1557{ 1558 if (!EventTarget::removeEventListener(eventType, listener, useCapture)) 1559 return false; 1560 1561 if (eventType == eventNames().unloadEvent) 1562 removeUnloadEventListener(this); 1563 else if (eventType == eventNames().beforeunloadEvent && allowsBeforeUnloadListeners(this)) 1564 removeBeforeUnloadEventListener(this); 1565#if ENABLE(DEVICE_ORIENTATION) 1566 else if (eventType == eventNames().devicemotionEvent && frame() && frame()->page() && frame()->page()->deviceMotionController()) 1567 frame()->page()->deviceMotionController()->removeListener(this); 1568 else if (eventType == eventNames().deviceorientationEvent && frame() && frame()->page() && frame()->page()->deviceOrientationController()) 1569 frame()->page()->deviceOrientationController()->removeListener(this); 1570#endif 1571 1572 return true; 1573} 1574 1575void DOMWindow::dispatchLoadEvent() 1576{ 1577 RefPtr<Event> loadEvent(Event::create(eventNames().loadEvent, false, false)); 1578 if (m_frame && m_frame->loader()->documentLoader() && !m_frame->loader()->documentLoader()->timing()->loadEventStart) { 1579 // The DocumentLoader (and thus its DocumentLoadTiming) might get destroyed while dispatching 1580 // the event, so protect it to prevent writing the end time into freed memory. 1581 RefPtr<DocumentLoader> documentLoader = m_frame->loader()->documentLoader(); 1582 DocumentLoadTiming* timing = documentLoader->timing(); 1583 dispatchTimedEvent(loadEvent, document(), &timing->loadEventStart, &timing->loadEventEnd); 1584 } else 1585 dispatchEvent(loadEvent, document()); 1586 1587 // For load events, send a separate load event to the enclosing frame only. 1588 // This is a DOM extension and is independent of bubbling/capturing rules of 1589 // the DOM. 1590 Element* ownerElement = m_frame ? m_frame->ownerElement() : 0; 1591 if (ownerElement) 1592 ownerElement->dispatchEvent(Event::create(eventNames().loadEvent, false, false)); 1593 1594 InspectorInstrumentation::loadEventFired(frame(), url()); 1595} 1596 1597bool DOMWindow::dispatchEvent(PassRefPtr<Event> prpEvent, PassRefPtr<EventTarget> prpTarget) 1598{ 1599 RefPtr<EventTarget> protect = this; 1600 RefPtr<Event> event = prpEvent; 1601 1602 event->setTarget(prpTarget ? prpTarget : this); 1603 event->setCurrentTarget(this); 1604 event->setEventPhase(Event::AT_TARGET); 1605 1606 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispatchEventOnWindow(frame(), *event, this); 1607 1608 bool result = fireEventListeners(event.get()); 1609 1610 InspectorInstrumentation::didDispatchEventOnWindow(cookie); 1611 1612 return result; 1613} 1614 1615void DOMWindow::dispatchTimedEvent(PassRefPtr<Event> event, Document* target, double* startTime, double* endTime) 1616{ 1617 ASSERT(startTime); 1618 ASSERT(endTime); 1619 *startTime = currentTime(); 1620 dispatchEvent(event, target); 1621 *endTime = currentTime(); 1622} 1623 1624void DOMWindow::removeAllEventListeners() 1625{ 1626 EventTarget::removeAllEventListeners(); 1627 1628#if ENABLE(DEVICE_ORIENTATION) 1629 if (frame() && frame()->page() && frame()->page()->deviceMotionController()) 1630 frame()->page()->deviceMotionController()->removeAllListeners(this); 1631 if (frame() && frame()->page() && frame()->page()->deviceOrientationController()) 1632 frame()->page()->deviceOrientationController()->removeAllListeners(this); 1633#endif 1634 1635 removeAllUnloadEventListeners(this); 1636 removeAllBeforeUnloadEventListeners(this); 1637} 1638 1639void DOMWindow::captureEvents() 1640{ 1641 // Not implemented. 1642} 1643 1644void DOMWindow::releaseEvents() 1645{ 1646 // Not implemented. 1647} 1648 1649void DOMWindow::finishedLoading() 1650{ 1651 if (m_shouldPrintWhenFinishedLoading) { 1652 m_shouldPrintWhenFinishedLoading = false; 1653 1654 m_printTimer.stop(); 1655 m_printTimer.startOneShot(0); 1656 } 1657} 1658 1659EventTargetData* DOMWindow::eventTargetData() 1660{ 1661 return &m_eventTargetData; 1662} 1663 1664EventTargetData* DOMWindow::ensureEventTargetData() 1665{ 1666 return &m_eventTargetData; 1667} 1668 1669#if ENABLE(DOM_STORAGE) && defined(ANDROID) 1670void DOMWindow::clearDOMStorage() 1671{ 1672 if (m_sessionStorage) 1673 m_sessionStorage->disconnectFrame(); 1674 m_sessionStorage = 0; 1675 1676 if (m_localStorage) 1677 m_localStorage->disconnectFrame(); 1678 m_localStorage = 0; 1679} 1680#endif 1681 1682void DOMWindow::setLocation(const String& urlString, DOMWindow* activeWindow, DOMWindow* firstWindow, SetLocationLocking locking) 1683{ 1684 if (!m_frame) 1685 return; 1686 1687 Frame* activeFrame = activeWindow->frame(); 1688 if (!activeFrame) 1689 return; 1690 1691 if (!activeFrame->loader()->shouldAllowNavigation(m_frame)) 1692 return; 1693 1694 Frame* firstFrame = firstWindow->frame(); 1695 if (!firstFrame) 1696 return; 1697 1698 KURL completedURL = firstFrame->document()->completeURL(urlString); 1699 if (completedURL.isNull()) 1700 return; 1701 1702 if (isInsecureScriptAccess(activeWindow, urlString)) 1703 return; 1704 1705 // We want a new history item if we are processing a user gesture. 1706 m_frame->navigationScheduler()->scheduleLocationChange(activeFrame->document()->securityOrigin(), 1707 completedURL, activeFrame->loader()->outgoingReferrer(), 1708 locking != LockHistoryBasedOnGestureState || !activeFrame->script()->anyPageIsProcessingUserGesture(), 1709 locking != LockHistoryBasedOnGestureState); 1710} 1711 1712void DOMWindow::printErrorMessage(const String& message) 1713{ 1714 if (message.isEmpty()) 1715 return; 1716 1717 Settings* settings = m_frame->settings(); 1718 if (!settings) 1719 return; 1720 if (settings->privateBrowsingEnabled()) 1721 return; 1722 1723 // FIXME: Add arguments so that we can provide a correct source URL and line number. 1724 console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, 1, String()); 1725} 1726 1727String DOMWindow::crossDomainAccessErrorMessage(DOMWindow* activeWindow) 1728{ 1729 const KURL& activeWindowURL = activeWindow->url(); 1730 if (activeWindowURL.isNull()) 1731 return String(); 1732 1733 // FIXME: This error message should contain more specifics of why the same origin check has failed. 1734 // Perhaps we should involve the security origin object in composing it. 1735 // FIXME: This message, and other console messages, have extra newlines. Should remove them. 1736 return makeString("Unsafe JavaScript attempt to access frame with URL ", m_url.string(), 1737 " from frame with URL ", activeWindowURL.string(), ". Domains, protocols and ports must match.\n"); 1738} 1739 1740bool DOMWindow::isInsecureScriptAccess(DOMWindow* activeWindow, const String& urlString) 1741{ 1742 if (!protocolIsJavaScript(urlString)) 1743 return false; 1744 1745 // If m_frame->domWindow() != this, then |this| isn't the DOMWindow that's 1746 // currently active in the frame and there's no way we should allow the 1747 // access. 1748 // FIXME: Remove this check if we're able to disconnect DOMWindow from 1749 // Frame on navigation: https://bugs.webkit.org/show_bug.cgi?id=62054 1750 if (m_frame->domWindow() == this) { 1751 // FIXME: Is there some way to eliminate the need for a separate "activeWindow == this" check? 1752 if (activeWindow == this) 1753 return false; 1754 1755 // FIXME: The name canAccess seems to be a roundabout way to ask "can execute script". 1756 // Can we name the SecurityOrigin function better to make this more clear? 1757 if (activeWindow->securityOrigin()->canAccess(securityOrigin())) 1758 return false; 1759 } 1760 1761 printErrorMessage(crossDomainAccessErrorMessage(activeWindow)); 1762 return true; 1763} 1764 1765Frame* DOMWindow::createWindow(const String& urlString, const AtomicString& frameName, const WindowFeatures& windowFeatures, 1766 DOMWindow* activeWindow, Frame* firstFrame, Frame* openerFrame, PrepareDialogFunction function, void* functionContext) 1767{ 1768 Frame* activeFrame = activeWindow->frame(); 1769 1770 // For whatever reason, Firefox uses the first frame to determine the outgoingReferrer. We replicate that behavior here. 1771 String referrer = firstFrame->loader()->outgoingReferrer(); 1772 1773 KURL completedURL = urlString.isEmpty() ? KURL(ParsedURLString, "") : firstFrame->document()->completeURL(urlString); 1774 ResourceRequest request(completedURL, referrer); 1775 FrameLoader::addHTTPOriginIfNeeded(request, firstFrame->loader()->outgoingOrigin()); 1776 FrameLoadRequest frameRequest(activeWindow->securityOrigin(), request, frameName); 1777 1778 // We pass the opener frame for the lookupFrame in case the active frame is different from 1779 // the opener frame, and the name references a frame relative to the opener frame. 1780 bool created; 1781 Frame* newFrame = WebCore::createWindow(activeFrame, openerFrame, frameRequest, windowFeatures, created); 1782 if (!newFrame) 1783 return 0; 1784 1785 newFrame->loader()->setOpener(openerFrame); 1786 newFrame->page()->setOpenedByDOM(); 1787 1788 if (newFrame->domWindow()->isInsecureScriptAccess(activeWindow, urlString)) 1789 return newFrame; 1790 1791 if (function) 1792 function(newFrame->domWindow(), functionContext); 1793 1794 if (created) 1795 newFrame->loader()->changeLocation(activeWindow->securityOrigin(), completedURL, referrer, false, false); 1796 else if (!urlString.isEmpty()) { 1797 newFrame->navigationScheduler()->scheduleLocationChange(activeWindow->securityOrigin(), completedURL.string(), referrer, 1798 !activeFrame->script()->anyPageIsProcessingUserGesture(), false); 1799 } 1800 1801 return newFrame; 1802} 1803 1804PassRefPtr<DOMWindow> DOMWindow::open(const String& urlString, const AtomicString& frameName, const String& windowFeaturesString, 1805 DOMWindow* activeWindow, DOMWindow* firstWindow) 1806{ 1807 if (!m_frame) 1808 return 0; 1809 Frame* activeFrame = activeWindow->frame(); 1810 if (!activeFrame) 1811 return 0; 1812 Frame* firstFrame = firstWindow->frame(); 1813 if (!firstFrame) 1814 return 0; 1815 1816 if (!firstWindow->allowPopUp()) { 1817 // Because FrameTree::find() returns true for empty strings, we must check for empty frame names. 1818 // Otherwise, illegitimate window.open() calls with no name will pass right through the popup blocker. 1819 if (frameName.isEmpty() || !m_frame->tree()->find(frameName)) 1820 return 0; 1821 } 1822 1823 // Get the target frame for the special cases of _top and _parent. 1824 // In those cases, we schedule a location change right now and return early. 1825 Frame* targetFrame = 0; 1826 if (frameName == "_top") 1827 targetFrame = m_frame->tree()->top(); 1828 else if (frameName == "_parent") { 1829 if (Frame* parent = m_frame->tree()->parent()) 1830 targetFrame = parent; 1831 else 1832 targetFrame = m_frame; 1833 } 1834 if (targetFrame) { 1835 if (!activeFrame->loader()->shouldAllowNavigation(targetFrame)) 1836 return 0; 1837 1838 if (isInsecureScriptAccess(activeWindow, urlString)) 1839 return targetFrame->domWindow(); 1840 1841 if (urlString.isEmpty()) 1842 return targetFrame->domWindow(); 1843 1844 // For whatever reason, Firefox uses the first window rather than the active window to 1845 // determine the outgoing referrer. We replicate that behavior here. 1846 targetFrame->navigationScheduler()->scheduleLocationChange(activeFrame->document()->securityOrigin(), 1847 firstFrame->document()->completeURL(urlString).string(), 1848 firstFrame->loader()->outgoingReferrer(), 1849 !activeFrame->script()->anyPageIsProcessingUserGesture(), false); 1850 1851 return targetFrame->domWindow(); 1852 } 1853 1854 WindowFeatures windowFeatures(windowFeaturesString); 1855 FloatRect windowRect(windowFeatures.xSet ? windowFeatures.x : 0, windowFeatures.ySet ? windowFeatures.y : 0, 1856 windowFeatures.widthSet ? windowFeatures.width : 0, windowFeatures.heightSet ? windowFeatures.height : 0); 1857 Page* page = m_frame->page(); 1858 DOMWindow::adjustWindowRect(screenAvailableRect(page ? page->mainFrame()->view() : 0), windowRect, windowRect); 1859 windowFeatures.x = windowRect.x(); 1860 windowFeatures.y = windowRect.y(); 1861 windowFeatures.height = windowRect.height(); 1862 windowFeatures.width = windowRect.width(); 1863 1864 Frame* result = createWindow(urlString, frameName, windowFeatures, activeWindow, firstFrame, m_frame); 1865 return result ? result->domWindow() : 0; 1866} 1867 1868void DOMWindow::showModalDialog(const String& urlString, const String& dialogFeaturesString, 1869 DOMWindow* activeWindow, DOMWindow* firstWindow, PrepareDialogFunction function, void* functionContext) 1870{ 1871 if (!m_frame) 1872 return; 1873 Frame* activeFrame = activeWindow->frame(); 1874 if (!activeFrame) 1875 return; 1876 Frame* firstFrame = firstWindow->frame(); 1877 if (!firstFrame) 1878 return; 1879 1880 if (m_frame->page()) 1881 m_frame->page()->chrome()->willRunModalHTMLDialog(m_frame); 1882 1883 if (!canShowModalDialogNow(m_frame) || !firstWindow->allowPopUp()) 1884 return; 1885 1886 Frame* dialogFrame = createWindow(urlString, emptyAtom, WindowFeatures(dialogFeaturesString, screenAvailableRect(m_frame->view())), 1887 activeWindow, firstFrame, m_frame, function, functionContext); 1888 if (!dialogFrame) 1889 return; 1890 1891 dialogFrame->page()->chrome()->runModal(); 1892} 1893 1894#if ENABLE(BLOB) 1895DOMURL* DOMWindow::webkitURL() const 1896{ 1897 if (!m_domURL) 1898 m_domURL = DOMURL::create(this->scriptExecutionContext()); 1899 return m_domURL.get(); 1900} 1901#endif 1902 1903#if ENABLE(QUOTA) 1904StorageInfo* DOMWindow::webkitStorageInfo() const 1905{ 1906 if (!m_storageInfo) 1907 m_storageInfo = StorageInfo::create(); 1908 return m_storageInfo.get(); 1909} 1910#endif 1911 1912} // namespace WebCore 1913