1 /* 2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "DOMWindow.h" 28 29 #include "BarInfo.h" 30 #include "BeforeUnloadEvent.h" 31 #include "CSSComputedStyleDeclaration.h" 32 #include "CSSRuleList.h" 33 #include "CSSStyleSelector.h" 34 #include "CString.h" 35 #include "Chrome.h" 36 #include "Console.h" 37 #include "Database.h" 38 #include "DOMApplicationCache.h" 39 #include "DOMSelection.h" 40 #include "DOMTimer.h" 41 #include "PageTransitionEvent.h" 42 #include "Document.h" 43 #include "Element.h" 44 #include "EventException.h" 45 #include "EventListener.h" 46 #include "EventNames.h" 47 #include "ExceptionCode.h" 48 #include "FloatRect.h" 49 #include "Frame.h" 50 #include "FrameLoader.h" 51 #include "FrameTree.h" 52 #include "FrameView.h" 53 #include "HTMLFrameOwnerElement.h" 54 #include "History.h" 55 #include "InspectorController.h" 56 #include "InspectorTimelineAgent.h" 57 #include "Location.h" 58 #include "Media.h" 59 #include "MessageEvent.h" 60 #include "Navigator.h" 61 #include "NotificationCenter.h" 62 #include "Page.h" 63 #include "PageGroup.h" 64 #include "PlatformScreen.h" 65 #include "PlatformString.h" 66 #include "Screen.h" 67 #include "SecurityOrigin.h" 68 #include "SerializedScriptValue.h" 69 #include "Settings.h" 70 #include "Storage.h" 71 #include "StorageArea.h" 72 #include "StorageNamespace.h" 73 #include "SuddenTermination.h" 74 #include "WebKitPoint.h" 75 #include <algorithm> 76 #include <wtf/MathExtras.h> 77 78 using std::min; 79 using std::max; 80 81 namespace WebCore { 82 83 class PostMessageTimer : public TimerBase { 84 public: 85 PostMessageTimer(DOMWindow* window, PassRefPtr<SerializedScriptValue> message, const String& sourceOrigin, PassRefPtr<DOMWindow> source, PassOwnPtr<MessagePortChannelArray> channels, SecurityOrigin* targetOrigin) 86 : m_window(window) 87 , m_message(message) 88 , m_origin(sourceOrigin) 89 , m_source(source) 90 , m_channels(channels) 91 , m_targetOrigin(targetOrigin) 92 { 93 } 94 95 PassRefPtr<MessageEvent> event(ScriptExecutionContext* context) 96 { 97 OwnPtr<MessagePortArray> messagePorts = MessagePort::entanglePorts(*context, m_channels.release()); 98 return MessageEvent::create(messagePorts.release(), m_message, m_origin, "", m_source); 99 } 100 SecurityOrigin* targetOrigin() const { return m_targetOrigin.get(); } 101 102 private: 103 virtual void fired() 104 { 105 m_window->postMessageTimerFired(this); 106 } 107 108 RefPtr<DOMWindow> m_window; 109 RefPtr<SerializedScriptValue> m_message; 110 String m_origin; 111 RefPtr<DOMWindow> m_source; 112 OwnPtr<MessagePortChannelArray> m_channels; 113 RefPtr<SecurityOrigin> m_targetOrigin; 114 }; 115 116 typedef HashCountedSet<DOMWindow*> DOMWindowSet; 117 118 static DOMWindowSet& windowsWithUnloadEventListeners() 119 { 120 DEFINE_STATIC_LOCAL(DOMWindowSet, windowsWithUnloadEventListeners, ()); 121 return windowsWithUnloadEventListeners; 122 } 123 124 static DOMWindowSet& windowsWithBeforeUnloadEventListeners() 125 { 126 DEFINE_STATIC_LOCAL(DOMWindowSet, windowsWithBeforeUnloadEventListeners, ()); 127 return windowsWithBeforeUnloadEventListeners; 128 } 129 130 static void addUnloadEventListener(DOMWindow* domWindow) 131 { 132 DOMWindowSet& set = windowsWithUnloadEventListeners(); 133 if (set.isEmpty()) 134 disableSuddenTermination(); 135 set.add(domWindow); 136 } 137 138 static void removeUnloadEventListener(DOMWindow* domWindow) 139 { 140 DOMWindowSet& set = windowsWithUnloadEventListeners(); 141 DOMWindowSet::iterator it = set.find(domWindow); 142 if (it == set.end()) 143 return; 144 set.remove(it); 145 if (set.isEmpty()) 146 enableSuddenTermination(); 147 } 148 149 static void removeAllUnloadEventListeners(DOMWindow* domWindow) 150 { 151 DOMWindowSet& set = windowsWithUnloadEventListeners(); 152 DOMWindowSet::iterator it = set.find(domWindow); 153 if (it == set.end()) 154 return; 155 set.removeAll(it); 156 if (set.isEmpty()) 157 enableSuddenTermination(); 158 } 159 160 static void addBeforeUnloadEventListener(DOMWindow* domWindow) 161 { 162 DOMWindowSet& set = windowsWithBeforeUnloadEventListeners(); 163 if (set.isEmpty()) 164 disableSuddenTermination(); 165 set.add(domWindow); 166 } 167 168 static void removeBeforeUnloadEventListener(DOMWindow* domWindow) 169 { 170 DOMWindowSet& set = windowsWithBeforeUnloadEventListeners(); 171 DOMWindowSet::iterator it = set.find(domWindow); 172 if (it == set.end()) 173 return; 174 set.remove(it); 175 if (set.isEmpty()) 176 enableSuddenTermination(); 177 } 178 179 static void removeAllBeforeUnloadEventListeners(DOMWindow* domWindow) 180 { 181 DOMWindowSet& set = windowsWithBeforeUnloadEventListeners(); 182 DOMWindowSet::iterator it = set.find(domWindow); 183 if (it == set.end()) 184 return; 185 set.removeAll(it); 186 if (set.isEmpty()) 187 enableSuddenTermination(); 188 } 189 190 static bool allowsBeforeUnloadListeners(DOMWindow* window) 191 { 192 ASSERT_ARG(window, window); 193 Frame* frame = window->frame(); 194 if (!frame) 195 return false; 196 Page* page = frame->page(); 197 if (!page) 198 return false; 199 return frame == page->mainFrame(); 200 } 201 202 bool DOMWindow::dispatchAllPendingBeforeUnloadEvents() 203 { 204 DOMWindowSet& set = windowsWithBeforeUnloadEventListeners(); 205 if (set.isEmpty()) 206 return true; 207 208 static bool alreadyDispatched = false; 209 ASSERT(!alreadyDispatched); 210 if (alreadyDispatched) 211 return true; 212 213 Vector<RefPtr<DOMWindow> > windows; 214 DOMWindowSet::iterator end = set.end(); 215 for (DOMWindowSet::iterator it = set.begin(); it != end; ++it) 216 windows.append(it->first); 217 218 size_t size = windows.size(); 219 for (size_t i = 0; i < size; ++i) { 220 DOMWindow* window = windows[i].get(); 221 if (!set.contains(window)) 222 continue; 223 224 Frame* frame = window->frame(); 225 if (!frame) 226 continue; 227 228 if (!frame->shouldClose()) 229 return false; 230 } 231 232 enableSuddenTermination(); 233 234 alreadyDispatched = true; 235 236 return true; 237 } 238 239 unsigned DOMWindow::pendingUnloadEventListeners() const 240 { 241 return windowsWithUnloadEventListeners().count(const_cast<DOMWindow*>(this)); 242 } 243 244 void DOMWindow::dispatchAllPendingUnloadEvents() 245 { 246 DOMWindowSet& set = windowsWithUnloadEventListeners(); 247 if (set.isEmpty()) 248 return; 249 250 static bool alreadyDispatched = false; 251 ASSERT(!alreadyDispatched); 252 if (alreadyDispatched) 253 return; 254 255 Vector<RefPtr<DOMWindow> > windows; 256 DOMWindowSet::iterator end = set.end(); 257 for (DOMWindowSet::iterator it = set.begin(); it != end; ++it) 258 windows.append(it->first); 259 260 size_t size = windows.size(); 261 for (size_t i = 0; i < size; ++i) { 262 DOMWindow* window = windows[i].get(); 263 if (!set.contains(window)) 264 continue; 265 266 window->dispatchEvent(PageTransitionEvent::create(eventNames().pagehideEvent, false), window->document()); 267 window->dispatchEvent(Event::create(eventNames().unloadEvent, false, false), window->document()); 268 } 269 270 enableSuddenTermination(); 271 272 alreadyDispatched = true; 273 } 274 275 // This function: 276 // 1) Validates the pending changes are not changing to NaN 277 // 2) Constrains the window rect to no smaller than 100 in each dimension and no 278 // bigger than the the float rect's dimensions. 279 // 3) Constrain window rect to within the top and left boundaries of the screen rect 280 // 4) Constraint the window rect to within the bottom and right boundaries of the 281 // screen rect. 282 // 5) Translate the window rect coordinates to be within the coordinate space of 283 // the screen rect. 284 void DOMWindow::adjustWindowRect(const FloatRect& screen, FloatRect& window, const FloatRect& pendingChanges) 285 { 286 // Make sure we're in a valid state before adjusting dimensions. 287 ASSERT(isfinite(screen.x())); 288 ASSERT(isfinite(screen.y())); 289 ASSERT(isfinite(screen.width())); 290 ASSERT(isfinite(screen.height())); 291 ASSERT(isfinite(window.x())); 292 ASSERT(isfinite(window.y())); 293 ASSERT(isfinite(window.width())); 294 ASSERT(isfinite(window.height())); 295 296 // Update window values if new requested values are not NaN. 297 if (!isnan(pendingChanges.x())) 298 window.setX(pendingChanges.x()); 299 if (!isnan(pendingChanges.y())) 300 window.setY(pendingChanges.y()); 301 if (!isnan(pendingChanges.width())) 302 window.setWidth(pendingChanges.width()); 303 if (!isnan(pendingChanges.height())) 304 window.setHeight(pendingChanges.height()); 305 306 // Resize the window to between 100 and the screen width and height. 307 window.setWidth(min(max(100.0f, window.width()), screen.width())); 308 window.setHeight(min(max(100.0f, window.height()), screen.height())); 309 310 // Constrain the window position to the screen. 311 window.setX(max(screen.x(), min(window.x(), screen.right() - window.width()))); 312 window.setY(max(screen.y(), min(window.y(), screen.bottom() - window.height()))); 313 } 314 315 void DOMWindow::parseModalDialogFeatures(const String& featuresArg, HashMap<String, String>& map) 316 { 317 Vector<String> features; 318 featuresArg.split(';', features); 319 Vector<String>::const_iterator end = features.end(); 320 for (Vector<String>::const_iterator it = features.begin(); it != end; ++it) { 321 String s = *it; 322 int pos = s.find('='); 323 int colonPos = s.find(':'); 324 if (pos >= 0 && colonPos >= 0) 325 continue; // ignore any strings that have both = and : 326 if (pos < 0) 327 pos = colonPos; 328 if (pos < 0) { 329 // null string for value means key without value 330 map.set(s.stripWhiteSpace().lower(), String()); 331 } else { 332 String key = s.left(pos).stripWhiteSpace().lower(); 333 String val = s.substring(pos + 1).stripWhiteSpace().lower(); 334 int spacePos = val.find(' '); 335 if (spacePos != -1) 336 val = val.left(spacePos); 337 map.set(key, val); 338 } 339 } 340 } 341 342 bool DOMWindow::allowPopUp(Frame* activeFrame) 343 { 344 ASSERT(activeFrame); 345 Settings* settings = activeFrame->settings(); 346 return settings && settings->javaScriptCanOpenWindowsAutomatically(); 347 } 348 349 bool DOMWindow::canShowModalDialog(const Frame* frame) 350 { 351 if (!frame) 352 return false; 353 Page* page = frame->page(); 354 if (!page) 355 return false; 356 return page->chrome()->canRunModal(); 357 } 358 359 bool DOMWindow::canShowModalDialogNow(const Frame* frame) 360 { 361 if (!frame) 362 return false; 363 Page* page = frame->page(); 364 if (!page) 365 return false; 366 return page->chrome()->canRunModalNow(); 367 } 368 369 DOMWindow::DOMWindow(Frame* frame) 370 : m_frame(frame) 371 { 372 } 373 374 DOMWindow::~DOMWindow() 375 { 376 if (m_frame) 377 m_frame->clearFormerDOMWindow(this); 378 379 removeAllUnloadEventListeners(this); 380 removeAllBeforeUnloadEventListeners(this); 381 } 382 383 ScriptExecutionContext* DOMWindow::scriptExecutionContext() const 384 { 385 return document(); 386 } 387 388 void DOMWindow::disconnectFrame() 389 { 390 m_frame = 0; 391 clear(); 392 } 393 394 void DOMWindow::clear() 395 { 396 if (m_screen) 397 m_screen->disconnectFrame(); 398 m_screen = 0; 399 400 if (m_selection) 401 m_selection->disconnectFrame(); 402 m_selection = 0; 403 404 if (m_history) 405 m_history->disconnectFrame(); 406 m_history = 0; 407 408 if (m_locationbar) 409 m_locationbar->disconnectFrame(); 410 m_locationbar = 0; 411 412 if (m_menubar) 413 m_menubar->disconnectFrame(); 414 m_menubar = 0; 415 416 if (m_personalbar) 417 m_personalbar->disconnectFrame(); 418 m_personalbar = 0; 419 420 if (m_scrollbars) 421 m_scrollbars->disconnectFrame(); 422 m_scrollbars = 0; 423 424 if (m_statusbar) 425 m_statusbar->disconnectFrame(); 426 m_statusbar = 0; 427 428 if (m_toolbar) 429 m_toolbar->disconnectFrame(); 430 m_toolbar = 0; 431 432 if (m_console) 433 m_console->disconnectFrame(); 434 m_console = 0; 435 436 if (m_navigator) 437 m_navigator->disconnectFrame(); 438 m_navigator = 0; 439 440 if (m_location) 441 m_location->disconnectFrame(); 442 m_location = 0; 443 444 if (m_media) 445 m_media->disconnectFrame(); 446 m_media = 0; 447 448 #if ENABLE(DOM_STORAGE) 449 if (m_sessionStorage) 450 m_sessionStorage->disconnectFrame(); 451 m_sessionStorage = 0; 452 453 if (m_localStorage) 454 m_localStorage->disconnectFrame(); 455 m_localStorage = 0; 456 #endif 457 458 #if ENABLE(OFFLINE_WEB_APPLICATIONS) 459 if (m_applicationCache) 460 m_applicationCache->disconnectFrame(); 461 m_applicationCache = 0; 462 #endif 463 464 #if ENABLE(NOTIFICATIONS) 465 if (m_notifications) 466 m_notifications->disconnectFrame(); 467 m_notifications = 0; 468 #endif 469 } 470 471 #if ENABLE(ORIENTATION_EVENTS) 472 int DOMWindow::orientation() const 473 { 474 if (!m_frame) 475 return 0; 476 477 return m_frame->orientation(); 478 } 479 #endif 480 481 Screen* DOMWindow::screen() const 482 { 483 if (!m_screen) 484 m_screen = Screen::create(m_frame); 485 return m_screen.get(); 486 } 487 488 History* DOMWindow::history() const 489 { 490 if (!m_history) 491 m_history = History::create(m_frame); 492 return m_history.get(); 493 } 494 495 BarInfo* DOMWindow::locationbar() const 496 { 497 if (!m_locationbar) 498 m_locationbar = BarInfo::create(m_frame, BarInfo::Locationbar); 499 return m_locationbar.get(); 500 } 501 502 BarInfo* DOMWindow::menubar() const 503 { 504 if (!m_menubar) 505 m_menubar = BarInfo::create(m_frame, BarInfo::Menubar); 506 return m_menubar.get(); 507 } 508 509 BarInfo* DOMWindow::personalbar() const 510 { 511 if (!m_personalbar) 512 m_personalbar = BarInfo::create(m_frame, BarInfo::Personalbar); 513 return m_personalbar.get(); 514 } 515 516 BarInfo* DOMWindow::scrollbars() const 517 { 518 if (!m_scrollbars) 519 m_scrollbars = BarInfo::create(m_frame, BarInfo::Scrollbars); 520 return m_scrollbars.get(); 521 } 522 523 BarInfo* DOMWindow::statusbar() const 524 { 525 if (!m_statusbar) 526 m_statusbar = BarInfo::create(m_frame, BarInfo::Statusbar); 527 return m_statusbar.get(); 528 } 529 530 BarInfo* DOMWindow::toolbar() const 531 { 532 if (!m_toolbar) 533 m_toolbar = BarInfo::create(m_frame, BarInfo::Toolbar); 534 return m_toolbar.get(); 535 } 536 537 Console* DOMWindow::console() const 538 { 539 if (!m_console) 540 m_console = Console::create(m_frame); 541 return m_console.get(); 542 } 543 544 #if ENABLE(OFFLINE_WEB_APPLICATIONS) 545 DOMApplicationCache* DOMWindow::applicationCache() const 546 { 547 if (!m_applicationCache) 548 m_applicationCache = DOMApplicationCache::create(m_frame); 549 return m_applicationCache.get(); 550 } 551 #endif 552 553 Navigator* DOMWindow::navigator() const 554 { 555 if (!m_navigator) 556 m_navigator = Navigator::create(m_frame); 557 return m_navigator.get(); 558 } 559 560 Location* DOMWindow::location() const 561 { 562 if (!m_location) 563 m_location = Location::create(m_frame); 564 return m_location.get(); 565 } 566 567 #if ENABLE(DOM_STORAGE) 568 Storage* DOMWindow::sessionStorage() const 569 { 570 if (m_sessionStorage) 571 return m_sessionStorage.get(); 572 573 Document* document = this->document(); 574 if (!document) 575 return 0; 576 577 if (!document->securityOrigin()->canAccessStorage()) 578 return 0; 579 580 Page* page = document->page(); 581 if (!page) 582 return 0; 583 584 RefPtr<StorageArea> storageArea = page->sessionStorage()->storageArea(document->securityOrigin()); 585 #if ENABLE(INSPECTOR) 586 page->inspectorController()->didUseDOMStorage(storageArea.get(), false, m_frame); 587 #endif 588 589 m_sessionStorage = Storage::create(m_frame, storageArea.release()); 590 return m_sessionStorage.get(); 591 } 592 593 Storage* DOMWindow::localStorage() const 594 { 595 if (m_localStorage) 596 return m_localStorage.get(); 597 598 Document* document = this->document(); 599 if (!document) 600 return 0; 601 602 if (!document->securityOrigin()->canAccessStorage()) 603 return 0; 604 605 Page* page = document->page(); 606 if (!page) 607 return 0; 608 609 if (!page->settings()->localStorageEnabled()) 610 return 0; 611 612 RefPtr<StorageArea> storageArea = page->group().localStorage()->storageArea(document->securityOrigin()); 613 #if ENABLE(INSPECTOR) 614 page->inspectorController()->didUseDOMStorage(storageArea.get(), true, m_frame); 615 #endif 616 617 m_localStorage = Storage::create(m_frame, storageArea.release()); 618 return m_localStorage.get(); 619 } 620 #endif 621 622 #if ENABLE(NOTIFICATIONS) 623 NotificationCenter* DOMWindow::webkitNotifications() const 624 { 625 if (m_notifications) 626 return m_notifications.get(); 627 628 Document* document = this->document(); 629 if (!document) 630 return 0; 631 632 Page* page = document->page(); 633 if (!page) 634 return 0; 635 636 NotificationPresenter* provider = page->chrome()->notificationPresenter(); 637 if (provider) 638 m_notifications = NotificationCenter::create(document, provider); 639 640 return m_notifications.get(); 641 } 642 #endif 643 644 #if ENABLE(INDEXED_DATABASE) 645 IndexedDatabaseRequest* DOMWindow::indexedDB() const 646 { 647 return 0; 648 } 649 #endif 650 651 void DOMWindow::postMessage(PassRefPtr<SerializedScriptValue> message, MessagePort* port, const String& targetOrigin, DOMWindow* source, ExceptionCode& ec) 652 { 653 MessagePortArray ports; 654 if (port) 655 ports.append(port); 656 postMessage(message, &ports, targetOrigin, source, ec); 657 } 658 659 void DOMWindow::postMessage(PassRefPtr<SerializedScriptValue> message, const MessagePortArray* ports, const String& targetOrigin, DOMWindow* source, ExceptionCode& ec) 660 { 661 if (!m_frame) 662 return; 663 664 // Compute the target origin. We need to do this synchronously in order 665 // to generate the SYNTAX_ERR exception correctly. 666 RefPtr<SecurityOrigin> target; 667 if (targetOrigin != "*") { 668 target = SecurityOrigin::createFromString(targetOrigin); 669 if (target->isEmpty()) { 670 ec = SYNTAX_ERR; 671 return; 672 } 673 } 674 675 OwnPtr<MessagePortChannelArray> channels = MessagePort::disentanglePorts(ports, ec); 676 if (ec) 677 return; 678 679 // Capture the source of the message. We need to do this synchronously 680 // in order to capture the source of the message correctly. 681 Document* sourceDocument = source->document(); 682 if (!sourceDocument) 683 return; 684 String sourceOrigin = sourceDocument->securityOrigin()->toString(); 685 686 // Schedule the message. 687 PostMessageTimer* timer = new PostMessageTimer(this, message, sourceOrigin, source, channels.release(), target.get()); 688 timer->startOneShot(0); 689 } 690 691 void DOMWindow::postMessageTimerFired(PostMessageTimer* t) 692 { 693 OwnPtr<PostMessageTimer> timer(t); 694 695 if (!document()) 696 return; 697 698 if (timer->targetOrigin()) { 699 // Check target origin now since the target document may have changed since the simer was scheduled. 700 if (!timer->targetOrigin()->isSameSchemeHostPort(document()->securityOrigin())) { 701 String message = String::format("Unable to post message to %s. Recipient has origin %s.\n", 702 timer->targetOrigin()->toString().utf8().data(), document()->securityOrigin()->toString().utf8().data()); 703 console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, 0, String()); 704 return; 705 } 706 } 707 708 dispatchEvent(timer->event(document())); 709 } 710 711 DOMSelection* DOMWindow::getSelection() 712 { 713 if (!m_selection) 714 m_selection = DOMSelection::create(m_frame); 715 return m_selection.get(); 716 } 717 718 Element* DOMWindow::frameElement() const 719 { 720 if (!m_frame) 721 return 0; 722 723 return m_frame->ownerElement(); 724 } 725 726 void DOMWindow::focus() 727 { 728 if (!m_frame) 729 return; 730 731 m_frame->focusWindow(); 732 } 733 734 void DOMWindow::blur() 735 { 736 if (!m_frame) 737 return; 738 739 m_frame->unfocusWindow(); 740 } 741 742 void DOMWindow::close() 743 { 744 if (!m_frame) 745 return; 746 747 Page* page = m_frame->page(); 748 if (!page) 749 return; 750 751 if (m_frame != page->mainFrame()) 752 return; 753 754 Settings* settings = m_frame->settings(); 755 bool allowScriptsToCloseWindows = settings && settings->allowScriptsToCloseWindows(); 756 757 if (page->openedByDOM() || page->getHistoryLength() <= 1 || allowScriptsToCloseWindows) 758 m_frame->scheduleClose(); 759 } 760 761 void DOMWindow::print() 762 { 763 if (!m_frame) 764 return; 765 766 Page* page = m_frame->page(); 767 if (!page) 768 return; 769 770 page->chrome()->print(m_frame); 771 } 772 773 void DOMWindow::stop() 774 { 775 if (!m_frame) 776 return; 777 778 // We must check whether the load is complete asynchronously, because we might still be parsing 779 // the document until the callstack unwinds. 780 m_frame->loader()->stopForUserCancel(true); 781 } 782 783 void DOMWindow::alert(const String& message) 784 { 785 if (!m_frame) 786 return; 787 788 m_frame->document()->updateStyleIfNeeded(); 789 790 Page* page = m_frame->page(); 791 if (!page) 792 return; 793 794 page->chrome()->runJavaScriptAlert(m_frame, message); 795 } 796 797 bool DOMWindow::confirm(const String& message) 798 { 799 if (!m_frame) 800 return false; 801 802 m_frame->document()->updateStyleIfNeeded(); 803 804 Page* page = m_frame->page(); 805 if (!page) 806 return false; 807 808 return page->chrome()->runJavaScriptConfirm(m_frame, message); 809 } 810 811 String DOMWindow::prompt(const String& message, const String& defaultValue) 812 { 813 if (!m_frame) 814 return String(); 815 816 m_frame->document()->updateStyleIfNeeded(); 817 818 Page* page = m_frame->page(); 819 if (!page) 820 return String(); 821 822 String returnValue; 823 if (page->chrome()->runJavaScriptPrompt(m_frame, message, defaultValue, returnValue)) 824 return returnValue; 825 826 return String(); 827 } 828 829 bool DOMWindow::find(const String& string, bool caseSensitive, bool backwards, bool wrap, bool /*wholeWord*/, bool /*searchInFrames*/, bool /*showDialog*/) const 830 { 831 if (!m_frame) 832 return false; 833 834 // FIXME (13016): Support wholeWord, searchInFrames and showDialog 835 return m_frame->findString(string, !backwards, caseSensitive, wrap, false); 836 } 837 838 bool DOMWindow::offscreenBuffering() const 839 { 840 return true; 841 } 842 843 int DOMWindow::outerHeight() const 844 { 845 if (!m_frame) 846 return 0; 847 848 Page* page = m_frame->page(); 849 if (!page) 850 return 0; 851 852 return static_cast<int>(page->chrome()->windowRect().height()); 853 } 854 855 int DOMWindow::outerWidth() const 856 { 857 if (!m_frame) 858 return 0; 859 860 Page* page = m_frame->page(); 861 if (!page) 862 return 0; 863 864 return static_cast<int>(page->chrome()->windowRect().width()); 865 } 866 867 int DOMWindow::innerHeight() const 868 { 869 if (!m_frame) 870 return 0; 871 872 FrameView* view = m_frame->view(); 873 if (!view) 874 return 0; 875 876 return static_cast<int>(view->height() / m_frame->pageZoomFactor()); 877 } 878 879 int DOMWindow::innerWidth() const 880 { 881 if (!m_frame) 882 return 0; 883 884 FrameView* view = m_frame->view(); 885 if (!view) 886 return 0; 887 888 return static_cast<int>(view->width() / m_frame->pageZoomFactor()); 889 } 890 891 int DOMWindow::screenX() const 892 { 893 if (!m_frame) 894 return 0; 895 896 Page* page = m_frame->page(); 897 if (!page) 898 return 0; 899 900 return static_cast<int>(page->chrome()->windowRect().x()); 901 } 902 903 int DOMWindow::screenY() const 904 { 905 if (!m_frame) 906 return 0; 907 908 Page* page = m_frame->page(); 909 if (!page) 910 return 0; 911 912 return static_cast<int>(page->chrome()->windowRect().y()); 913 } 914 915 int DOMWindow::scrollX() const 916 { 917 if (!m_frame) 918 return 0; 919 920 FrameView* view = m_frame->view(); 921 if (!view) 922 return 0; 923 924 m_frame->document()->updateLayoutIgnorePendingStylesheets(); 925 926 return static_cast<int>(view->scrollX() / m_frame->pageZoomFactor()); 927 } 928 929 int DOMWindow::scrollY() const 930 { 931 if (!m_frame) 932 return 0; 933 934 FrameView* view = m_frame->view(); 935 if (!view) 936 return 0; 937 938 m_frame->document()->updateLayoutIgnorePendingStylesheets(); 939 940 return static_cast<int>(view->scrollY() / m_frame->pageZoomFactor()); 941 } 942 943 bool DOMWindow::closed() const 944 { 945 return !m_frame; 946 } 947 948 unsigned DOMWindow::length() const 949 { 950 if (!m_frame) 951 return 0; 952 953 return m_frame->tree()->childCount(); 954 } 955 956 String DOMWindow::name() const 957 { 958 if (!m_frame) 959 return String(); 960 961 return m_frame->tree()->name(); 962 } 963 964 void DOMWindow::setName(const String& string) 965 { 966 if (!m_frame) 967 return; 968 969 m_frame->tree()->setName(string); 970 } 971 972 String DOMWindow::status() const 973 { 974 if (!m_frame) 975 return String(); 976 977 return m_frame->jsStatusBarText(); 978 } 979 980 void DOMWindow::setStatus(const String& string) 981 { 982 if (!m_frame) 983 return; 984 985 m_frame->setJSStatusBarText(string); 986 } 987 988 String DOMWindow::defaultStatus() const 989 { 990 if (!m_frame) 991 return String(); 992 993 return m_frame->jsDefaultStatusBarText(); 994 } 995 996 void DOMWindow::setDefaultStatus(const String& string) 997 { 998 if (!m_frame) 999 return; 1000 1001 m_frame->setJSDefaultStatusBarText(string); 1002 } 1003 1004 DOMWindow* DOMWindow::self() const 1005 { 1006 if (!m_frame) 1007 return 0; 1008 1009 return m_frame->domWindow(); 1010 } 1011 1012 DOMWindow* DOMWindow::opener() const 1013 { 1014 if (!m_frame) 1015 return 0; 1016 1017 Frame* opener = m_frame->loader()->opener(); 1018 if (!opener) 1019 return 0; 1020 1021 return opener->domWindow(); 1022 } 1023 1024 DOMWindow* DOMWindow::parent() const 1025 { 1026 if (!m_frame) 1027 return 0; 1028 1029 Frame* parent = m_frame->tree()->parent(true); 1030 if (parent) 1031 return parent->domWindow(); 1032 1033 return m_frame->domWindow(); 1034 } 1035 1036 DOMWindow* DOMWindow::top() const 1037 { 1038 if (!m_frame) 1039 return 0; 1040 1041 Page* page = m_frame->page(); 1042 if (!page) 1043 return 0; 1044 1045 return m_frame->tree()->top(true)->domWindow(); 1046 } 1047 1048 Document* DOMWindow::document() const 1049 { 1050 // FIXME: This function shouldn't need a frame to work. 1051 if (!m_frame) 1052 return 0; 1053 1054 // 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. 1055 // FIXME: We should always zero out the frame pointer on navigation to avoid accidentally accessing the new frame content. 1056 if (m_frame->domWindow() != this) 1057 return 0; 1058 1059 ASSERT(m_frame->document()); 1060 return m_frame->document(); 1061 } 1062 1063 PassRefPtr<Media> DOMWindow::media() const 1064 { 1065 if (!m_media) 1066 m_media = Media::create(m_frame); 1067 return m_media.get(); 1068 } 1069 1070 PassRefPtr<CSSStyleDeclaration> DOMWindow::getComputedStyle(Element* elt, const String&) const 1071 { 1072 if (!elt) 1073 return 0; 1074 1075 // FIXME: This needs take pseudo elements into account. 1076 return computedStyle(elt); 1077 } 1078 1079 PassRefPtr<CSSRuleList> DOMWindow::getMatchedCSSRules(Element* elt, const String& pseudoElt, bool authorOnly) const 1080 { 1081 if (!m_frame) 1082 return 0; 1083 1084 Document* doc = m_frame->document(); 1085 1086 if (!pseudoElt.isEmpty()) 1087 return doc->styleSelector()->pseudoStyleRulesForElement(elt, pseudoElt, authorOnly); 1088 return doc->styleSelector()->styleRulesForElement(elt, authorOnly); 1089 } 1090 1091 PassRefPtr<WebKitPoint> DOMWindow::webkitConvertPointFromNodeToPage(Node* node, const WebKitPoint* p) const 1092 { 1093 if (!node || !p) 1094 return 0; 1095 1096 m_frame->document()->updateLayoutIgnorePendingStylesheets(); 1097 1098 FloatPoint pagePoint(p->x(), p->y()); 1099 pagePoint = node->convertToPage(pagePoint); 1100 return WebKitPoint::create(pagePoint.x(), pagePoint.y()); 1101 } 1102 1103 PassRefPtr<WebKitPoint> DOMWindow::webkitConvertPointFromPageToNode(Node* node, const WebKitPoint* p) const 1104 { 1105 if (!node || !p) 1106 return 0; 1107 1108 m_frame->document()->updateLayoutIgnorePendingStylesheets(); 1109 1110 FloatPoint nodePoint(p->x(), p->y()); 1111 nodePoint = node->convertFromPage(nodePoint); 1112 return WebKitPoint::create(nodePoint.x(), nodePoint.y()); 1113 } 1114 1115 double DOMWindow::devicePixelRatio() const 1116 { 1117 if (!m_frame) 1118 return 0.0; 1119 1120 Page* page = m_frame->page(); 1121 if (!page) 1122 return 0.0; 1123 1124 return page->chrome()->scaleFactor(); 1125 } 1126 1127 #if ENABLE(DATABASE) 1128 PassRefPtr<Database> DOMWindow::openDatabase(const String& name, const String& version, const String& displayName, unsigned long estimatedSize, ExceptionCode& ec) 1129 { 1130 if (!m_frame) 1131 return 0; 1132 1133 Document* document = m_frame->document(); 1134 if (!document->securityOrigin()->canAccessDatabase()) 1135 return 0; 1136 1137 Settings* settings = m_frame->settings(); 1138 if (!settings || !settings->databasesEnabled()) 1139 return 0; 1140 1141 return Database::openDatabase(document, name, version, displayName, estimatedSize, ec); 1142 } 1143 #endif 1144 1145 void DOMWindow::scrollBy(int x, int y) const 1146 { 1147 if (!m_frame) 1148 return; 1149 1150 m_frame->document()->updateLayoutIgnorePendingStylesheets(); 1151 1152 FrameView* view = m_frame->view(); 1153 if (!view) 1154 return; 1155 1156 view->scrollBy(IntSize(x, y)); 1157 } 1158 1159 void DOMWindow::scrollTo(int x, int y) const 1160 { 1161 if (!m_frame) 1162 return; 1163 1164 m_frame->document()->updateLayoutIgnorePendingStylesheets(); 1165 1166 FrameView* view = m_frame->view(); 1167 if (!view) 1168 return; 1169 1170 int zoomedX = static_cast<int>(x * m_frame->pageZoomFactor()); 1171 int zoomedY = static_cast<int>(y * m_frame->pageZoomFactor()); 1172 view->setScrollPosition(IntPoint(zoomedX, zoomedY)); 1173 } 1174 1175 void DOMWindow::moveBy(float x, float y) const 1176 { 1177 if (!m_frame) 1178 return; 1179 1180 Page* page = m_frame->page(); 1181 if (!page) 1182 return; 1183 1184 if (m_frame != page->mainFrame()) 1185 return; 1186 1187 FloatRect fr = page->chrome()->windowRect(); 1188 FloatRect update = fr; 1189 update.move(x, y); 1190 // Security check (the spec talks about UniversalBrowserWrite to disable this check...) 1191 adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update); 1192 page->chrome()->setWindowRect(fr); 1193 } 1194 1195 void DOMWindow::moveTo(float x, float y) const 1196 { 1197 if (!m_frame) 1198 return; 1199 1200 Page* page = m_frame->page(); 1201 if (!page) 1202 return; 1203 1204 if (m_frame != page->mainFrame()) 1205 return; 1206 1207 FloatRect fr = page->chrome()->windowRect(); 1208 FloatRect sr = screenAvailableRect(page->mainFrame()->view()); 1209 fr.setLocation(sr.location()); 1210 FloatRect update = fr; 1211 update.move(x, y); 1212 // Security check (the spec talks about UniversalBrowserWrite to disable this check...) 1213 adjustWindowRect(sr, fr, update); 1214 page->chrome()->setWindowRect(fr); 1215 } 1216 1217 void DOMWindow::resizeBy(float x, float y) const 1218 { 1219 if (!m_frame) 1220 return; 1221 1222 Page* page = m_frame->page(); 1223 if (!page) 1224 return; 1225 1226 if (m_frame != page->mainFrame()) 1227 return; 1228 1229 FloatRect fr = page->chrome()->windowRect(); 1230 FloatSize dest = fr.size() + FloatSize(x, y); 1231 FloatRect update(fr.location(), dest); 1232 adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update); 1233 page->chrome()->setWindowRect(fr); 1234 } 1235 1236 void DOMWindow::resizeTo(float width, float height) const 1237 { 1238 if (!m_frame) 1239 return; 1240 1241 Page* page = m_frame->page(); 1242 if (!page) 1243 return; 1244 1245 if (m_frame != page->mainFrame()) 1246 return; 1247 1248 FloatRect fr = page->chrome()->windowRect(); 1249 FloatSize dest = FloatSize(width, height); 1250 FloatRect update(fr.location(), dest); 1251 adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update); 1252 page->chrome()->setWindowRect(fr); 1253 } 1254 1255 int DOMWindow::setTimeout(ScheduledAction* action, int timeout, ExceptionCode& ec) 1256 { 1257 ScriptExecutionContext* context = scriptExecutionContext(); 1258 if (!context) { 1259 ec = INVALID_ACCESS_ERR; 1260 return -1; 1261 } 1262 return DOMTimer::install(context, action, timeout, true); 1263 } 1264 1265 void DOMWindow::clearTimeout(int timeoutId) 1266 { 1267 ScriptExecutionContext* context = scriptExecutionContext(); 1268 if (!context) 1269 return; 1270 DOMTimer::removeById(context, timeoutId); 1271 } 1272 1273 int DOMWindow::setInterval(ScheduledAction* action, int timeout, ExceptionCode& ec) 1274 { 1275 ScriptExecutionContext* context = scriptExecutionContext(); 1276 if (!context) { 1277 ec = INVALID_ACCESS_ERR; 1278 return -1; 1279 } 1280 return DOMTimer::install(context, action, timeout, false); 1281 } 1282 1283 void DOMWindow::clearInterval(int timeoutId) 1284 { 1285 ScriptExecutionContext* context = scriptExecutionContext(); 1286 if (!context) 1287 return; 1288 DOMTimer::removeById(context, timeoutId); 1289 } 1290 1291 bool DOMWindow::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture) 1292 { 1293 if (!EventTarget::addEventListener(eventType, listener, useCapture)) 1294 return false; 1295 1296 if (Document* document = this->document()) 1297 document->addListenerTypeIfNeeded(eventType); 1298 1299 if (eventType == eventNames().unloadEvent) 1300 addUnloadEventListener(this); 1301 else if (eventType == eventNames().beforeunloadEvent && allowsBeforeUnloadListeners(this)) 1302 addBeforeUnloadEventListener(this); 1303 1304 return true; 1305 } 1306 1307 bool DOMWindow::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture) 1308 { 1309 if (!EventTarget::removeEventListener(eventType, listener, useCapture)) 1310 return false; 1311 1312 if (eventType == eventNames().unloadEvent) 1313 removeUnloadEventListener(this); 1314 else if (eventType == eventNames().beforeunloadEvent && allowsBeforeUnloadListeners(this)) 1315 removeBeforeUnloadEventListener(this); 1316 1317 return true; 1318 } 1319 1320 void DOMWindow::dispatchLoadEvent() 1321 { 1322 dispatchEvent(Event::create(eventNames().loadEvent, false, false), document()); 1323 1324 // For load events, send a separate load event to the enclosing frame only. 1325 // This is a DOM extension and is independent of bubbling/capturing rules of 1326 // the DOM. 1327 Element* ownerElement = document()->ownerElement(); 1328 if (ownerElement) { 1329 RefPtr<Event> ownerEvent = Event::create(eventNames().loadEvent, false, false); 1330 ownerEvent->setTarget(ownerElement); 1331 ownerElement->dispatchGenericEvent(ownerEvent.release()); 1332 } 1333 1334 #if ENABLE(INSPECTOR) 1335 if (!frame() || !frame()->page()) 1336 return; 1337 1338 if (InspectorController* controller = frame()->page()->inspectorController()) 1339 controller->mainResourceFiredLoadEvent(frame()->loader()->documentLoader(), url()); 1340 #endif 1341 } 1342 1343 #if ENABLE(INSPECTOR) 1344 InspectorTimelineAgent* DOMWindow::inspectorTimelineAgent() 1345 { 1346 if (frame() && frame()->page()) 1347 return frame()->page()->inspectorTimelineAgent(); 1348 return 0; 1349 } 1350 #endif 1351 1352 bool DOMWindow::dispatchEvent(PassRefPtr<Event> prpEvent, PassRefPtr<EventTarget> prpTarget) 1353 { 1354 RefPtr<EventTarget> protect = this; 1355 RefPtr<Event> event = prpEvent; 1356 1357 event->setTarget(prpTarget ? prpTarget : this); 1358 event->setCurrentTarget(this); 1359 event->setEventPhase(Event::AT_TARGET); 1360 1361 #if ENABLE(INSPECTOR) 1362 InspectorTimelineAgent* timelineAgent = inspectorTimelineAgent(); 1363 bool timelineAgentIsActive = timelineAgent && hasEventListeners(event->type()); 1364 if (timelineAgentIsActive) 1365 timelineAgent->willDispatchEvent(*event); 1366 #endif 1367 1368 bool result = fireEventListeners(event.get()); 1369 1370 #if ENABLE(INSPECTOR) 1371 if (timelineAgentIsActive) { 1372 timelineAgent = inspectorTimelineAgent(); 1373 if (timelineAgent) 1374 timelineAgent->didDispatchEvent(); 1375 } 1376 #endif 1377 1378 return result; 1379 } 1380 1381 void DOMWindow::removeAllEventListeners() 1382 { 1383 EventTarget::removeAllEventListeners(); 1384 1385 removeAllUnloadEventListeners(this); 1386 removeAllBeforeUnloadEventListeners(this); 1387 } 1388 1389 void DOMWindow::captureEvents() 1390 { 1391 // Not implemented. 1392 } 1393 1394 void DOMWindow::releaseEvents() 1395 { 1396 // Not implemented. 1397 } 1398 1399 EventTargetData* DOMWindow::eventTargetData() 1400 { 1401 return &m_eventTargetData; 1402 } 1403 1404 EventTargetData* DOMWindow::ensureEventTargetData() 1405 { 1406 return &m_eventTargetData; 1407 } 1408 1409 } // namespace WebCore 1410