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 116 using std::min; 117 using std::max; 118 119 namespace WebCore { 120 121 class PostMessageTimer : public TimerBase { 122 public: 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 140 private: 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 154 typedef HashCountedSet<DOMWindow*> DOMWindowSet; 155 156 static DOMWindowSet& windowsWithUnloadEventListeners() 157 { 158 DEFINE_STATIC_LOCAL(DOMWindowSet, windowsWithUnloadEventListeners, ()); 159 return windowsWithUnloadEventListeners; 160 } 161 162 static DOMWindowSet& windowsWithBeforeUnloadEventListeners() 163 { 164 DEFINE_STATIC_LOCAL(DOMWindowSet, windowsWithBeforeUnloadEventListeners, ()); 165 return windowsWithBeforeUnloadEventListeners; 166 } 167 168 static void addUnloadEventListener(DOMWindow* domWindow) 169 { 170 DOMWindowSet& set = windowsWithUnloadEventListeners(); 171 if (set.isEmpty()) 172 disableSuddenTermination(); 173 set.add(domWindow); 174 } 175 176 static 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 187 static 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 198 static void addBeforeUnloadEventListener(DOMWindow* domWindow) 199 { 200 DOMWindowSet& set = windowsWithBeforeUnloadEventListeners(); 201 if (set.isEmpty()) 202 disableSuddenTermination(); 203 set.add(domWindow); 204 } 205 206 static 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 217 static 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 228 static 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 240 bool 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 277 unsigned DOMWindow::pendingUnloadEventListeners() const 278 { 279 return windowsWithUnloadEventListeners().count(const_cast<DOMWindow*>(this)); 280 } 281 282 void 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. 322 void 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. 354 void DOMWindow::parseModalDialogFeatures(const String& string, HashMap<String, String>& map) 355 { 356 WindowFeatures::parseDialogFeatures(string, map); 357 } 358 359 bool 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 370 bool DOMWindow::allowPopUp() 371 { 372 return m_frame && allowPopUp(m_frame); 373 } 374 375 bool 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 385 bool 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 395 DOMWindow::DOMWindow(Frame* frame) 396 : m_shouldPrintWhenFinishedLoading(false) 397 , m_frame(frame) 398 , m_printTimer(this, &DOMWindow::printTimerFired) 399 { 400 } 401 402 DOMWindow::~DOMWindow() 403 { 404 if (m_frame) 405 m_frame->clearFormerDOMWindow(this); 406 407 removeAllUnloadEventListeners(this); 408 removeAllBeforeUnloadEventListeners(this); 409 } 410 411 ScriptExecutionContext* DOMWindow::scriptExecutionContext() const 412 { 413 return document(); 414 } 415 416 PassRefPtr<MediaQueryList> DOMWindow::matchMedia(const String& media) 417 { 418 return document() ? document()->mediaQueryMatcher()->matchMedia(media) : 0; 419 } 420 421 void DOMWindow::disconnectFrame() 422 { 423 m_frame = 0; 424 clear(); 425 } 426 427 void 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) 517 int DOMWindow::orientation() const 518 { 519 if (!m_frame) 520 return 0; 521 522 return m_frame->orientation(); 523 } 524 #endif 525 526 Screen* DOMWindow::screen() const 527 { 528 if (!m_screen) 529 m_screen = Screen::create(m_frame); 530 return m_screen.get(); 531 } 532 533 History* DOMWindow::history() const 534 { 535 if (!m_history) 536 m_history = History::create(m_frame); 537 return m_history.get(); 538 } 539 540 Crypto* DOMWindow::crypto() const 541 { 542 if (!m_crypto) 543 m_crypto = Crypto::create(); 544 return m_crypto.get(); 545 } 546 547 BarInfo* DOMWindow::locationbar() const 548 { 549 if (!m_locationbar) 550 m_locationbar = BarInfo::create(m_frame, BarInfo::Locationbar); 551 return m_locationbar.get(); 552 } 553 554 BarInfo* DOMWindow::menubar() const 555 { 556 if (!m_menubar) 557 m_menubar = BarInfo::create(m_frame, BarInfo::Menubar); 558 return m_menubar.get(); 559 } 560 561 BarInfo* DOMWindow::personalbar() const 562 { 563 if (!m_personalbar) 564 m_personalbar = BarInfo::create(m_frame, BarInfo::Personalbar); 565 return m_personalbar.get(); 566 } 567 568 BarInfo* DOMWindow::scrollbars() const 569 { 570 if (!m_scrollbars) 571 m_scrollbars = BarInfo::create(m_frame, BarInfo::Scrollbars); 572 return m_scrollbars.get(); 573 } 574 575 BarInfo* DOMWindow::statusbar() const 576 { 577 if (!m_statusbar) 578 m_statusbar = BarInfo::create(m_frame, BarInfo::Statusbar); 579 return m_statusbar.get(); 580 } 581 582 BarInfo* DOMWindow::toolbar() const 583 { 584 if (!m_toolbar) 585 m_toolbar = BarInfo::create(m_frame, BarInfo::Toolbar); 586 return m_toolbar.get(); 587 } 588 589 Console* 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) 597 DOMApplicationCache* DOMWindow::applicationCache() const 598 { 599 if (!m_applicationCache) 600 m_applicationCache = DOMApplicationCache::create(m_frame); 601 return m_applicationCache.get(); 602 } 603 #endif 604 605 Navigator* 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) 613 Performance* DOMWindow::performance() const 614 { 615 if (!m_performance) 616 m_performance = Performance::create(m_frame); 617 return m_performance.get(); 618 } 619 #endif 620 621 Location* 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) 629 Storage* 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 654 Storage* 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) 684 NotificationCenter* 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 705 void 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 716 void 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) 724 IDBFactory* 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) 747 void 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 767 void 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 790 COMPILE_ASSERT(static_cast<int>(DOMWindow::EXTERNAL) == static_cast<int>(AsyncFileSystem::External), enum_mismatch); 791 792 COMPILE_ASSERT(static_cast<int>(DOMWindow::TEMPORARY) == static_cast<int>(AsyncFileSystem::Temporary), enum_mismatch); 793 COMPILE_ASSERT(static_cast<int>(DOMWindow::PERSISTENT) == static_cast<int>(AsyncFileSystem::Persistent), enum_mismatch); 794 795 #endif 796 797 void 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 805 void 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 837 void 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 857 DOMSelection* DOMWindow::getSelection() 858 { 859 if (!m_selection) 860 m_selection = DOMSelection::create(m_frame); 861 return m_selection.get(); 862 } 863 864 Element* DOMWindow::frameElement() const 865 { 866 if (!m_frame) 867 return 0; 868 869 return m_frame->ownerElement(); 870 } 871 872 void 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 891 void 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 906 void 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 940 void 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 957 void DOMWindow::printTimerFired(Timer<DOMWindow>* timer) 958 { 959 ASSERT_UNUSED(timer, timer == &m_printTimer); 960 print(); 961 } 962 963 void 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 973 void 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 987 bool 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 1001 String 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 1019 String 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 1032 String 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 1051 bool 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 1060 bool DOMWindow::offscreenBuffering() const 1061 { 1062 return true; 1063 } 1064 1065 int 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 1077 int 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 1089 int 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 1105 int 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 1121 int 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 1133 int 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 1145 int 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 1163 int 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 1181 bool DOMWindow::closed() const 1182 { 1183 return !m_frame; 1184 } 1185 1186 unsigned DOMWindow::length() const 1187 { 1188 if (!m_frame) 1189 return 0; 1190 1191 return m_frame->tree()->childCount(); 1192 } 1193 1194 String DOMWindow::name() const 1195 { 1196 if (!m_frame) 1197 return String(); 1198 1199 return m_frame->tree()->name(); 1200 } 1201 1202 void DOMWindow::setName(const String& string) 1203 { 1204 if (!m_frame) 1205 return; 1206 1207 m_frame->tree()->setName(string); 1208 } 1209 1210 void 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 1225 void 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 1240 DOMWindow* DOMWindow::self() const 1241 { 1242 if (!m_frame) 1243 return 0; 1244 1245 return m_frame->domWindow(); 1246 } 1247 1248 DOMWindow* 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 1260 DOMWindow* 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 1272 DOMWindow* 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 1284 Document* 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 1299 PassRefPtr<StyleMedia> DOMWindow::styleMedia() const 1300 { 1301 if (!m_media) 1302 m_media = StyleMedia::create(m_frame); 1303 return m_media.get(); 1304 } 1305 1306 PassRefPtr<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 1314 PassRefPtr<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 1323 PassRefPtr<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 1335 PassRefPtr<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 1347 double 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) 1360 PassRefPtr<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 1373 void 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 1387 void 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 1403 void 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 1423 void 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 1445 void 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 1464 void 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 1483 int 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 1493 void DOMWindow::clearTimeout(int timeoutId) 1494 { 1495 ScriptExecutionContext* context = scriptExecutionContext(); 1496 if (!context) 1497 return; 1498 DOMTimer::removeById(context, timeoutId); 1499 } 1500 1501 int 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 1511 void 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) 1520 int DOMWindow::webkitRequestAnimationFrame(PassRefPtr<RequestAnimationFrameCallback> callback, Element* e) 1521 { 1522 if (Document* d = document()) 1523 return d->webkitRequestAnimationFrame(callback, e); 1524 return 0; 1525 } 1526 1527 void DOMWindow::webkitCancelRequestAnimationFrame(int id) 1528 { 1529 if (Document* d = document()) 1530 d->webkitCancelRequestAnimationFrame(id); 1531 } 1532 #endif 1533 1534 bool 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 1556 bool 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 1575 void 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 1597 bool 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 1615 void 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 1624 void 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 1639 void DOMWindow::captureEvents() 1640 { 1641 // Not implemented. 1642 } 1643 1644 void DOMWindow::releaseEvents() 1645 { 1646 // Not implemented. 1647 } 1648 1649 void DOMWindow::finishedLoading() 1650 { 1651 if (m_shouldPrintWhenFinishedLoading) { 1652 m_shouldPrintWhenFinishedLoading = false; 1653 1654 m_printTimer.stop(); 1655 m_printTimer.startOneShot(0); 1656 } 1657 } 1658 1659 EventTargetData* DOMWindow::eventTargetData() 1660 { 1661 return &m_eventTargetData; 1662 } 1663 1664 EventTargetData* DOMWindow::ensureEventTargetData() 1665 { 1666 return &m_eventTargetData; 1667 } 1668 1669 #if ENABLE(DOM_STORAGE) && defined(ANDROID) 1670 void 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 1682 void 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 1712 void 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 1727 String 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 1740 bool 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 1765 Frame* 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 1804 PassRefPtr<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 1868 void 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) 1895 DOMURL* 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) 1904 StorageInfo* 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