Home | History | Annotate | Download | only in page
      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 "core/page/DOMWindow.h"
     29 
     30 #include "wtf/MainThread.h"
     31 #include "wtf/MathExtras.h"
     32 #include "wtf/text/WTFString.h"
     33 #include <algorithm>
     34 #include "RuntimeEnabledFeatures.h"
     35 #include "bindings/v8/ExceptionState.h"
     36 #include "bindings/v8/ExceptionStatePlaceholder.h"
     37 #include "bindings/v8/ScriptCallStackFactory.h"
     38 #include "bindings/v8/ScriptController.h"
     39 #include "bindings/v8/SerializedScriptValue.h"
     40 #include "core/css/CSSComputedStyleDeclaration.h"
     41 #include "core/css/CSSRuleList.h"
     42 #include "core/css/DOMWindowCSS.h"
     43 #include "core/css/MediaQueryList.h"
     44 #include "core/css/MediaQueryMatcher.h"
     45 #include "core/css/StyleMedia.h"
     46 #include "core/css/resolver/StyleResolver.h"
     47 #include "core/dom/DeviceOrientationController.h"
     48 #include "core/dom/Document.h"
     49 #include "core/dom/Element.h"
     50 #include "core/dom/EventListener.h"
     51 #include "core/dom/EventNames.h"
     52 #include "core/dom/ExceptionCode.h"
     53 #include "core/dom/MessageEvent.h"
     54 #include "core/dom/PageTransitionEvent.h"
     55 #include "core/dom/RequestAnimationFrameCallback.h"
     56 #include "core/dom/ScriptExecutionContext.h"
     57 #include "core/editing/Editor.h"
     58 #include "core/history/BackForwardController.h"
     59 #include "core/html/HTMLFrameOwnerElement.h"
     60 #include "core/inspector/InspectorInstrumentation.h"
     61 #include "core/inspector/ScriptCallStack.h"
     62 #include "core/loader/DocumentLoader.h"
     63 #include "core/loader/FrameLoadRequest.h"
     64 #include "core/loader/FrameLoader.h"
     65 #include "core/loader/FrameLoaderClient.h"
     66 #include "core/loader/appcache/DOMApplicationCache.h"
     67 #include "core/page/BarProp.h"
     68 #include "core/page/Chrome.h"
     69 #include "core/page/ChromeClient.h"
     70 #include "core/page/Console.h"
     71 #include "core/page/CreateWindow.h"
     72 #include "core/page/DOMPoint.h"
     73 #include "core/page/EventHandler.h"
     74 #include "core/page/Frame.h"
     75 #include "core/page/FrameTree.h"
     76 #include "core/page/FrameView.h"
     77 #include "core/page/History.h"
     78 #include "core/page/Location.h"
     79 #include "core/page/Navigator.h"
     80 #include "core/page/Page.h"
     81 #include "core/page/PageConsole.h"
     82 #include "core/page/PageGroup.h"
     83 #include "core/page/Performance.h"
     84 #include "core/page/Screen.h"
     85 #include "core/page/Settings.h"
     86 #include "core/page/WindowFeatures.h"
     87 #include "core/page/WindowFocusAllowedIndicator.h"
     88 #include "core/page/scrolling/ScrollingCoordinator.h"
     89 #include "core/platform/PlatformScreen.h"
     90 #include "core/platform/SuddenTermination.h"
     91 #include "core/platform/graphics/FloatRect.h"
     92 #include "core/platform/graphics/MediaPlayer.h"
     93 #include "core/storage/Storage.h"
     94 #include "core/storage/StorageArea.h"
     95 #include "core/storage/StorageNamespace.h"
     96 #include "modules/device_orientation/DeviceMotionController.h"
     97 #include "weborigin/KURL.h"
     98 #include "weborigin/SecurityOrigin.h"
     99 #include "weborigin/SecurityPolicy.h"
    100 
    101 using std::min;
    102 using std::max;
    103 
    104 namespace WebCore {
    105 
    106 class PostMessageTimer : public TimerBase {
    107 public:
    108     PostMessageTimer(DOMWindow* window, PassRefPtr<SerializedScriptValue> message, const String& sourceOrigin, PassRefPtr<DOMWindow> source, PassOwnPtr<MessagePortChannelArray> channels, SecurityOrigin* targetOrigin, PassRefPtr<ScriptCallStack> stackTrace)
    109         : m_window(window)
    110         , m_message(message)
    111         , m_origin(sourceOrigin)
    112         , m_source(source)
    113         , m_channels(channels)
    114         , m_targetOrigin(targetOrigin)
    115         , m_stackTrace(stackTrace)
    116     {
    117     }
    118 
    119     PassRefPtr<MessageEvent> event(ScriptExecutionContext* context)
    120     {
    121         OwnPtr<MessagePortArray> messagePorts = MessagePort::entanglePorts(*context, m_channels.release());
    122         return MessageEvent::create(messagePorts.release(), m_message, m_origin, "", m_source);
    123     }
    124     SecurityOrigin* targetOrigin() const { return m_targetOrigin.get(); }
    125     ScriptCallStack* stackTrace() const { return m_stackTrace.get(); }
    126 
    127 private:
    128     virtual void fired()
    129     {
    130         m_window->postMessageTimerFired(adoptPtr(this));
    131         // This object is deleted now.
    132     }
    133 
    134     RefPtr<DOMWindow> m_window;
    135     RefPtr<SerializedScriptValue> m_message;
    136     String m_origin;
    137     RefPtr<DOMWindow> m_source;
    138     OwnPtr<MessagePortChannelArray> m_channels;
    139     RefPtr<SecurityOrigin> m_targetOrigin;
    140     RefPtr<ScriptCallStack> m_stackTrace;
    141 };
    142 
    143 typedef HashCountedSet<DOMWindow*> DOMWindowSet;
    144 
    145 static DOMWindowSet& windowsWithUnloadEventListeners()
    146 {
    147     DEFINE_STATIC_LOCAL(DOMWindowSet, windowsWithUnloadEventListeners, ());
    148     return windowsWithUnloadEventListeners;
    149 }
    150 
    151 static DOMWindowSet& windowsWithBeforeUnloadEventListeners()
    152 {
    153     DEFINE_STATIC_LOCAL(DOMWindowSet, windowsWithBeforeUnloadEventListeners, ());
    154     return windowsWithBeforeUnloadEventListeners;
    155 }
    156 
    157 static void addUnloadEventListener(DOMWindow* domWindow)
    158 {
    159     DOMWindowSet& set = windowsWithUnloadEventListeners();
    160     if (set.isEmpty())
    161         disableSuddenTermination();
    162     set.add(domWindow);
    163 }
    164 
    165 static void removeUnloadEventListener(DOMWindow* domWindow)
    166 {
    167     DOMWindowSet& set = windowsWithUnloadEventListeners();
    168     DOMWindowSet::iterator it = set.find(domWindow);
    169     if (it == set.end())
    170         return;
    171     set.remove(it);
    172     if (set.isEmpty())
    173         enableSuddenTermination();
    174 }
    175 
    176 static void removeAllUnloadEventListeners(DOMWindow* domWindow)
    177 {
    178     DOMWindowSet& set = windowsWithUnloadEventListeners();
    179     DOMWindowSet::iterator it = set.find(domWindow);
    180     if (it == set.end())
    181         return;
    182     set.removeAll(it);
    183     if (set.isEmpty())
    184         enableSuddenTermination();
    185 }
    186 
    187 static void addBeforeUnloadEventListener(DOMWindow* domWindow)
    188 {
    189     DOMWindowSet& set = windowsWithBeforeUnloadEventListeners();
    190     if (set.isEmpty())
    191         disableSuddenTermination();
    192     set.add(domWindow);
    193 }
    194 
    195 static void removeBeforeUnloadEventListener(DOMWindow* domWindow)
    196 {
    197     DOMWindowSet& set = windowsWithBeforeUnloadEventListeners();
    198     DOMWindowSet::iterator it = set.find(domWindow);
    199     if (it == set.end())
    200         return;
    201     set.remove(it);
    202     if (set.isEmpty())
    203         enableSuddenTermination();
    204 }
    205 
    206 static void removeAllBeforeUnloadEventListeners(DOMWindow* domWindow)
    207 {
    208     DOMWindowSet& set = windowsWithBeforeUnloadEventListeners();
    209     DOMWindowSet::iterator it = set.find(domWindow);
    210     if (it == set.end())
    211         return;
    212     set.removeAll(it);
    213     if (set.isEmpty())
    214         enableSuddenTermination();
    215 }
    216 
    217 static bool allowsBeforeUnloadListeners(DOMWindow* window)
    218 {
    219     ASSERT_ARG(window, window);
    220     Frame* frame = window->frame();
    221     if (!frame)
    222         return false;
    223     Page* page = frame->page();
    224     if (!page)
    225         return false;
    226     return frame == page->mainFrame();
    227 }
    228 
    229 unsigned DOMWindow::pendingUnloadEventListeners() const
    230 {
    231     return windowsWithUnloadEventListeners().count(const_cast<DOMWindow*>(this));
    232 }
    233 
    234 // This function:
    235 // 1) Validates the pending changes are not changing any value to NaN; in that case keep original value.
    236 // 2) Constrains the window rect to the minimum window size and no bigger than the float rect's dimensions.
    237 // 3) Constrains the window rect to within the top and left boundaries of the available screen rect.
    238 // 4) Constrains the window rect to within the bottom and right boundaries of the available screen rect.
    239 // 5) Translate the window rect coordinates to be within the coordinate space of the screen.
    240 FloatRect DOMWindow::adjustWindowRect(Page* page, const FloatRect& pendingChanges)
    241 {
    242     ASSERT(page);
    243 
    244     FloatRect screen = screenAvailableRect(page->mainFrame()->view());
    245     FloatRect window = page->chrome().windowRect();
    246 
    247     // Make sure we're in a valid state before adjusting dimensions.
    248     ASSERT(std::isfinite(screen.x()));
    249     ASSERT(std::isfinite(screen.y()));
    250     ASSERT(std::isfinite(screen.width()));
    251     ASSERT(std::isfinite(screen.height()));
    252     ASSERT(std::isfinite(window.x()));
    253     ASSERT(std::isfinite(window.y()));
    254     ASSERT(std::isfinite(window.width()));
    255     ASSERT(std::isfinite(window.height()));
    256 
    257     // Update window values if new requested values are not NaN.
    258     if (!std::isnan(pendingChanges.x()))
    259         window.setX(pendingChanges.x());
    260     if (!std::isnan(pendingChanges.y()))
    261         window.setY(pendingChanges.y());
    262     if (!std::isnan(pendingChanges.width()))
    263         window.setWidth(pendingChanges.width());
    264     if (!std::isnan(pendingChanges.height()))
    265         window.setHeight(pendingChanges.height());
    266 
    267     FloatSize minimumSize = page->chrome().client()->minimumWindowSize();
    268     // Let size 0 pass through, since that indicates default size, not minimum size.
    269     if (window.width())
    270         window.setWidth(min(max(minimumSize.width(), window.width()), screen.width()));
    271     if (window.height())
    272         window.setHeight(min(max(minimumSize.height(), window.height()), screen.height()));
    273 
    274     // Constrain the window position within the valid screen area.
    275     window.setX(max(screen.x(), min(window.x(), screen.maxX() - window.width())));
    276     window.setY(max(screen.y(), min(window.y(), screen.maxY() - window.height())));
    277 
    278     return window;
    279 }
    280 
    281 bool DOMWindow::allowPopUp(Frame* firstFrame)
    282 {
    283     ASSERT(firstFrame);
    284 
    285     if (ScriptController::processingUserGesture())
    286         return true;
    287 
    288     Settings* settings = firstFrame->settings();
    289     return settings && settings->javaScriptCanOpenWindowsAutomatically();
    290 }
    291 
    292 bool DOMWindow::allowPopUp()
    293 {
    294     return m_frame && allowPopUp(m_frame);
    295 }
    296 
    297 bool DOMWindow::canShowModalDialog(const Frame* frame)
    298 {
    299     if (!frame)
    300         return false;
    301     Page* page = frame->page();
    302     if (!page)
    303         return false;
    304     return page->chrome().canRunModal();
    305 }
    306 
    307 bool DOMWindow::canShowModalDialogNow(const Frame* frame)
    308 {
    309     if (!frame)
    310         return false;
    311     Page* page = frame->page();
    312     if (!page)
    313         return false;
    314     return page->chrome().canRunModalNow();
    315 }
    316 
    317 DOMWindow::DOMWindow(Frame* frame)
    318     : FrameDestructionObserver(frame)
    319     , m_shouldPrintWhenFinishedLoading(false)
    320 {
    321     ASSERT(frame);
    322     ScriptWrappable::init(this);
    323 }
    324 
    325 void DOMWindow::setDocument(PassRefPtr<Document> document)
    326 {
    327     ASSERT(!document || document->frame() == m_frame);
    328     if (m_document) {
    329         if (m_document->attached()) {
    330             // FIXME: We don't call willRemove here. Why is that OK?
    331             // This detach() call is also mostly redundant. Most of the calls to
    332             // this function come via DocumentLoader::createWriterFor, which
    333             // always detaches the previous Document first. Only XSLTProcessor
    334             // depends on this detach() call, so it seems like there's some room
    335             // for cleanup.
    336             m_document->detach();
    337         }
    338         m_document->setDOMWindow(0);
    339     }
    340 
    341     m_document = document;
    342 
    343     if (!m_document)
    344         return;
    345 
    346     m_document->setDOMWindow(this);
    347     if (!m_document->attached())
    348         m_document->attach();
    349 
    350     if (!m_frame)
    351         return;
    352 
    353     m_frame->script()->updateDocument();
    354     m_document->updateViewportArguments();
    355 
    356     if (m_frame->page() && m_frame->view()) {
    357         if (ScrollingCoordinator* scrollingCoordinator = m_frame->page()->scrollingCoordinator()) {
    358             scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_frame->view(), HorizontalScrollbar);
    359             scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_frame->view(), VerticalScrollbar);
    360             scrollingCoordinator->scrollableAreaScrollLayerDidChange(m_frame->view());
    361         }
    362     }
    363 
    364     m_frame->selection()->updateSecureKeyboardEntryIfActive();
    365 
    366     if (m_frame->page() && m_frame->page()->mainFrame() == m_frame) {
    367         m_frame->page()->mainFrame()->notifyChromeClientWheelEventHandlerCountChanged();
    368         if (m_document->hasTouchEventHandlers())
    369             m_frame->page()->chrome().client()->needTouchEvents(true);
    370     }
    371 }
    372 
    373 DOMWindow::~DOMWindow()
    374 {
    375     ASSERT(!m_screen);
    376     ASSERT(!m_history);
    377     ASSERT(!m_locationbar);
    378     ASSERT(!m_menubar);
    379     ASSERT(!m_personalbar);
    380     ASSERT(!m_scrollbars);
    381     ASSERT(!m_statusbar);
    382     ASSERT(!m_toolbar);
    383     ASSERT(!m_console);
    384     ASSERT(!m_navigator);
    385     ASSERT(!m_performance);
    386     ASSERT(!m_location);
    387     ASSERT(!m_media);
    388     ASSERT(!m_sessionStorage);
    389     ASSERT(!m_localStorage);
    390     ASSERT(!m_applicationCache);
    391 
    392     reset();
    393 
    394     removeAllEventListeners();
    395 
    396     ASSERT(!m_document->attached());
    397     setDocument(0);
    398 }
    399 
    400 const AtomicString& DOMWindow::interfaceName() const
    401 {
    402     return eventNames().interfaceForDOMWindow;
    403 }
    404 
    405 ScriptExecutionContext* DOMWindow::scriptExecutionContext() const
    406 {
    407     return m_document.get();
    408 }
    409 
    410 DOMWindow* DOMWindow::toDOMWindow()
    411 {
    412     return this;
    413 }
    414 
    415 PassRefPtr<MediaQueryList> DOMWindow::matchMedia(const String& media)
    416 {
    417     return document() ? document()->mediaQueryMatcher()->matchMedia(media) : 0;
    418 }
    419 
    420 Page* DOMWindow::page()
    421 {
    422     return frame() ? frame()->page() : 0;
    423 }
    424 
    425 void DOMWindow::frameDestroyed()
    426 {
    427     FrameDestructionObserver::frameDestroyed();
    428     reset();
    429 }
    430 
    431 void DOMWindow::willDetachPage()
    432 {
    433     InspectorInstrumentation::frameWindowDiscarded(m_frame, this);
    434     // FIXME: Once DeviceOrientationController is a ScriptExecutionContext
    435     // Supplement, this will no longer be needed.
    436     if (DeviceOrientationController* controller = DeviceOrientationController::from(page()))
    437         controller->removeAllDeviceEventListeners(this);
    438 }
    439 
    440 void DOMWindow::willDestroyDocumentInFrame()
    441 {
    442     // It is necessary to copy m_properties to a separate vector because the DOMWindowProperties may
    443     // unregister themselves from the DOMWindow as a result of the call to willDestroyGlobalObjectInFrame.
    444     Vector<DOMWindowProperty*> properties;
    445     copyToVector(m_properties, properties);
    446     for (size_t i = 0; i < properties.size(); ++i)
    447         properties[i]->willDestroyGlobalObjectInFrame();
    448 }
    449 
    450 void DOMWindow::willDetachDocumentFromFrame()
    451 {
    452     // It is necessary to copy m_properties to a separate vector because the DOMWindowProperties may
    453     // unregister themselves from the DOMWindow as a result of the call to willDetachGlobalObjectFromFrame.
    454     Vector<DOMWindowProperty*> properties;
    455     copyToVector(m_properties, properties);
    456     for (size_t i = 0; i < properties.size(); ++i)
    457         properties[i]->willDetachGlobalObjectFromFrame();
    458 }
    459 
    460 void DOMWindow::registerProperty(DOMWindowProperty* property)
    461 {
    462     m_properties.add(property);
    463 }
    464 
    465 void DOMWindow::unregisterProperty(DOMWindowProperty* property)
    466 {
    467     m_properties.remove(property);
    468 }
    469 
    470 void DOMWindow::reset()
    471 {
    472     willDestroyDocumentInFrame();
    473     resetDOMWindowProperties();
    474 }
    475 
    476 void DOMWindow::resetDOMWindowProperties()
    477 {
    478     m_properties.clear();
    479 
    480     m_screen = 0;
    481     m_history = 0;
    482     m_locationbar = 0;
    483     m_menubar = 0;
    484     m_personalbar = 0;
    485     m_scrollbars = 0;
    486     m_statusbar = 0;
    487     m_toolbar = 0;
    488     m_console = 0;
    489     m_navigator = 0;
    490     m_performance = 0;
    491     m_location = 0;
    492     m_media = 0;
    493     m_sessionStorage = 0;
    494     m_localStorage = 0;
    495     m_applicationCache = 0;
    496 }
    497 
    498 bool DOMWindow::isCurrentlyDisplayedInFrame() const
    499 {
    500     return m_frame && m_frame->domWindow() == this;
    501 }
    502 
    503 #if ENABLE(ORIENTATION_EVENTS)
    504 int DOMWindow::orientation() const
    505 {
    506     if (!m_frame)
    507         return 0;
    508 
    509     return m_frame->orientation();
    510 }
    511 #endif
    512 
    513 Screen* DOMWindow::screen() const
    514 {
    515     if (!isCurrentlyDisplayedInFrame())
    516         return 0;
    517     if (!m_screen)
    518         m_screen = Screen::create(m_frame);
    519     return m_screen.get();
    520 }
    521 
    522 History* DOMWindow::history() const
    523 {
    524     if (!isCurrentlyDisplayedInFrame())
    525         return 0;
    526     if (!m_history)
    527         m_history = History::create(m_frame);
    528     return m_history.get();
    529 }
    530 
    531 BarProp* DOMWindow::locationbar() const
    532 {
    533     if (!isCurrentlyDisplayedInFrame())
    534         return 0;
    535     if (!m_locationbar)
    536         m_locationbar = BarProp::create(m_frame, BarProp::Locationbar);
    537     return m_locationbar.get();
    538 }
    539 
    540 BarProp* DOMWindow::menubar() const
    541 {
    542     if (!isCurrentlyDisplayedInFrame())
    543         return 0;
    544     if (!m_menubar)
    545         m_menubar = BarProp::create(m_frame, BarProp::Menubar);
    546     return m_menubar.get();
    547 }
    548 
    549 BarProp* DOMWindow::personalbar() const
    550 {
    551     if (!isCurrentlyDisplayedInFrame())
    552         return 0;
    553     if (!m_personalbar)
    554         m_personalbar = BarProp::create(m_frame, BarProp::Personalbar);
    555     return m_personalbar.get();
    556 }
    557 
    558 BarProp* DOMWindow::scrollbars() const
    559 {
    560     if (!isCurrentlyDisplayedInFrame())
    561         return 0;
    562     if (!m_scrollbars)
    563         m_scrollbars = BarProp::create(m_frame, BarProp::Scrollbars);
    564     return m_scrollbars.get();
    565 }
    566 
    567 BarProp* DOMWindow::statusbar() const
    568 {
    569     if (!isCurrentlyDisplayedInFrame())
    570         return 0;
    571     if (!m_statusbar)
    572         m_statusbar = BarProp::create(m_frame, BarProp::Statusbar);
    573     return m_statusbar.get();
    574 }
    575 
    576 BarProp* DOMWindow::toolbar() const
    577 {
    578     if (!isCurrentlyDisplayedInFrame())
    579         return 0;
    580     if (!m_toolbar)
    581         m_toolbar = BarProp::create(m_frame, BarProp::Toolbar);
    582     return m_toolbar.get();
    583 }
    584 
    585 Console* DOMWindow::console() const
    586 {
    587     if (!isCurrentlyDisplayedInFrame())
    588         return 0;
    589     if (!m_console)
    590         m_console = Console::create(m_frame);
    591     return m_console.get();
    592 }
    593 
    594 PageConsole* DOMWindow::pageConsole() const
    595 {
    596     if (!isCurrentlyDisplayedInFrame())
    597         return 0;
    598     return m_frame->page() ? m_frame->page()->console() : 0;
    599 }
    600 
    601 DOMApplicationCache* DOMWindow::applicationCache() const
    602 {
    603     if (!isCurrentlyDisplayedInFrame())
    604         return 0;
    605     if (!m_applicationCache)
    606         m_applicationCache = DOMApplicationCache::create(m_frame);
    607     return m_applicationCache.get();
    608 }
    609 
    610 Navigator* DOMWindow::navigator() const
    611 {
    612     if (!isCurrentlyDisplayedInFrame())
    613         return 0;
    614     if (!m_navigator)
    615         m_navigator = Navigator::create(m_frame);
    616     return m_navigator.get();
    617 }
    618 
    619 Performance* DOMWindow::performance() const
    620 {
    621     if (!isCurrentlyDisplayedInFrame())
    622         return 0;
    623     if (!m_performance)
    624         m_performance = Performance::create(m_frame);
    625     return m_performance.get();
    626 }
    627 
    628 Location* DOMWindow::location() const
    629 {
    630     if (!isCurrentlyDisplayedInFrame())
    631         return 0;
    632     if (!m_location)
    633         m_location = Location::create(m_frame);
    634     return m_location.get();
    635 }
    636 
    637 Storage* DOMWindow::sessionStorage(ExceptionState& es) const
    638 {
    639     if (!isCurrentlyDisplayedInFrame())
    640         return 0;
    641 
    642     Document* document = this->document();
    643     if (!document)
    644         return 0;
    645 
    646     if (!document->securityOrigin()->canAccessLocalStorage()) {
    647         es.throwDOMException(SecurityError);
    648         return 0;
    649     }
    650 
    651     if (m_sessionStorage) {
    652         if (!m_sessionStorage->area()->canAccessStorage(m_frame)) {
    653             es.throwDOMException(SecurityError);
    654             return 0;
    655         }
    656         return m_sessionStorage.get();
    657     }
    658 
    659     Page* page = document->page();
    660     if (!page)
    661         return 0;
    662 
    663     OwnPtr<StorageArea> storageArea = page->sessionStorage()->storageArea(document->securityOrigin());
    664     if (!storageArea->canAccessStorage(m_frame)) {
    665         es.throwDOMException(SecurityError);
    666         return 0;
    667     }
    668 
    669     m_sessionStorage = Storage::create(m_frame, storageArea.release());
    670     return m_sessionStorage.get();
    671 }
    672 
    673 Storage* DOMWindow::localStorage(ExceptionState& es) const
    674 {
    675     if (!isCurrentlyDisplayedInFrame())
    676         return 0;
    677 
    678     Document* document = this->document();
    679     if (!document)
    680         return 0;
    681 
    682     if (!document->securityOrigin()->canAccessLocalStorage()) {
    683         es.throwDOMException(SecurityError);
    684         return 0;
    685     }
    686 
    687     if (m_localStorage) {
    688         if (!m_localStorage->area()->canAccessStorage(m_frame)) {
    689             es.throwDOMException(SecurityError);
    690             return 0;
    691         }
    692         return m_localStorage.get();
    693     }
    694 
    695     Page* page = document->page();
    696     if (!page)
    697         return 0;
    698 
    699     if (!page->settings()->localStorageEnabled())
    700         return 0;
    701 
    702     OwnPtr<StorageArea> storageArea = StorageNamespace::localStorageArea(document->securityOrigin());
    703     if (!storageArea->canAccessStorage(m_frame)) {
    704         es.throwDOMException(SecurityError);
    705         return 0;
    706     }
    707 
    708     m_localStorage = Storage::create(m_frame, storageArea.release());
    709     return m_localStorage.get();
    710 }
    711 
    712 void DOMWindow::postMessage(PassRefPtr<SerializedScriptValue> message, const MessagePortArray* ports, const String& targetOrigin, DOMWindow* source, ExceptionState& es)
    713 {
    714     if (!isCurrentlyDisplayedInFrame())
    715         return;
    716 
    717     Document* sourceDocument = source->document();
    718 
    719     // Compute the target origin.  We need to do this synchronously in order
    720     // to generate the SyntaxError exception correctly.
    721     RefPtr<SecurityOrigin> target;
    722     if (targetOrigin == "/") {
    723         if (!sourceDocument)
    724             return;
    725         target = sourceDocument->securityOrigin();
    726     } else if (targetOrigin != "*") {
    727         target = SecurityOrigin::createFromString(targetOrigin);
    728         // It doesn't make sense target a postMessage at a unique origin
    729         // because there's no way to represent a unique origin in a string.
    730         if (target->isUnique()) {
    731             es.throwDOMException(SyntaxError);
    732             return;
    733         }
    734     }
    735 
    736     OwnPtr<MessagePortChannelArray> channels = MessagePort::disentanglePorts(ports, es);
    737     if (es.hadException())
    738         return;
    739 
    740     // Capture the source of the message.  We need to do this synchronously
    741     // in order to capture the source of the message correctly.
    742     if (!sourceDocument)
    743         return;
    744     String sourceOrigin = sourceDocument->securityOrigin()->toString();
    745 
    746     // Capture stack trace only when inspector front-end is loaded as it may be time consuming.
    747     RefPtr<ScriptCallStack> stackTrace;
    748     if (InspectorInstrumentation::consoleAgentEnabled(sourceDocument))
    749         stackTrace = createScriptCallStack(ScriptCallStack::maxCallStackSizeToCapture, true);
    750 
    751     // Schedule the message.
    752     PostMessageTimer* timer = new PostMessageTimer(this, message, sourceOrigin, source, channels.release(), target.get(), stackTrace.release());
    753     timer->startOneShot(0);
    754 }
    755 
    756 void DOMWindow::postMessageTimerFired(PassOwnPtr<PostMessageTimer> t)
    757 {
    758     OwnPtr<PostMessageTimer> timer(t);
    759 
    760     if (!document() || !isCurrentlyDisplayedInFrame())
    761         return;
    762 
    763     RefPtr<MessageEvent> event = timer->event(document());
    764 
    765     // Give the embedder a chance to intercept this postMessage because this
    766     // DOMWindow might be a proxy for another in browsers that support
    767     // postMessage calls across WebKit instances.
    768     if (m_frame->loader()->client()->willCheckAndDispatchMessageEvent(timer->targetOrigin(), event.get()))
    769         return;
    770 
    771     dispatchMessageEventWithOriginCheck(timer->targetOrigin(), event, timer->stackTrace());
    772 }
    773 
    774 void DOMWindow::dispatchMessageEventWithOriginCheck(SecurityOrigin* intendedTargetOrigin, PassRefPtr<Event> event, PassRefPtr<ScriptCallStack> stackTrace)
    775 {
    776     if (intendedTargetOrigin) {
    777         // Check target origin now since the target document may have changed since the timer was scheduled.
    778         if (!intendedTargetOrigin->isSameSchemeHostPort(document()->securityOrigin())) {
    779             String message = "Unable to post message to " + intendedTargetOrigin->toString() +
    780                              ". Recipient has origin " + document()->securityOrigin()->toString() + ".\n";
    781             pageConsole()->addMessage(SecurityMessageSource, ErrorMessageLevel, message, stackTrace);
    782             return;
    783         }
    784     }
    785 
    786     dispatchEvent(event);
    787 }
    788 
    789 DOMSelection* DOMWindow::getSelection()
    790 {
    791     if (!isCurrentlyDisplayedInFrame() || !m_frame)
    792         return 0;
    793 
    794     return m_frame->document()->getSelection();
    795 }
    796 
    797 Element* DOMWindow::frameElement() const
    798 {
    799     if (!m_frame)
    800         return 0;
    801 
    802     return m_frame->ownerElement();
    803 }
    804 
    805 void DOMWindow::focus(ScriptExecutionContext* context)
    806 {
    807     if (!m_frame)
    808         return;
    809 
    810     Page* page = m_frame->page();
    811     if (!page)
    812         return;
    813 
    814     bool allowFocus = WindowFocusAllowedIndicator::windowFocusAllowed();
    815     if (context) {
    816         ASSERT(isMainThread());
    817         Document* activeDocument = toDocument(context);
    818         if (opener() && opener() != this && activeDocument->domWindow() == opener())
    819             allowFocus = true;
    820     }
    821 
    822     // If we're a top level window, bring the window to the front.
    823     if (m_frame == page->mainFrame() && allowFocus)
    824         page->chrome().focus();
    825 
    826     if (!m_frame)
    827         return;
    828 
    829     m_frame->eventHandler()->focusDocumentView();
    830 }
    831 
    832 void DOMWindow::blur()
    833 {
    834 }
    835 
    836 void DOMWindow::close(ScriptExecutionContext* context)
    837 {
    838     if (!m_frame)
    839         return;
    840 
    841     Page* page = m_frame->page();
    842     if (!page)
    843         return;
    844 
    845     if (m_frame != page->mainFrame())
    846         return;
    847 
    848     if (context) {
    849         ASSERT(isMainThread());
    850         Document* activeDocument = toDocument(context);
    851         if (!activeDocument)
    852             return;
    853 
    854         if (!activeDocument->canNavigate(m_frame))
    855             return;
    856     }
    857 
    858     Settings* settings = m_frame->settings();
    859     bool allowScriptsToCloseWindows = settings && settings->allowScriptsToCloseWindows();
    860 
    861     if (!(page->openedByDOM() || page->backForward()->count() <= 1 || allowScriptsToCloseWindows))
    862         return;
    863 
    864     if (!m_frame->loader()->shouldClose())
    865         return;
    866 
    867     page->chrome().closeWindowSoon();
    868 }
    869 
    870 void DOMWindow::print()
    871 {
    872     if (!m_frame)
    873         return;
    874 
    875     Page* page = m_frame->page();
    876     if (!page)
    877         return;
    878 
    879     if (m_frame->loader()->activeDocumentLoader()->isLoading()) {
    880         m_shouldPrintWhenFinishedLoading = true;
    881         return;
    882     }
    883     m_shouldPrintWhenFinishedLoading = false;
    884     page->chrome().print(m_frame);
    885 }
    886 
    887 void DOMWindow::stop()
    888 {
    889     if (!m_frame)
    890         return;
    891 
    892     // We must check whether the load is complete asynchronously, because we might still be parsing
    893     // the document until the callstack unwinds.
    894     m_frame->loader()->stopForUserCancel(true);
    895 }
    896 
    897 void DOMWindow::alert(const String& message)
    898 {
    899     if (!m_frame)
    900         return;
    901 
    902     m_frame->document()->updateStyleIfNeeded();
    903 
    904     Page* page = m_frame->page();
    905     if (!page)
    906         return;
    907 
    908     page->chrome().runJavaScriptAlert(m_frame, message);
    909 }
    910 
    911 bool DOMWindow::confirm(const String& message)
    912 {
    913     if (!m_frame)
    914         return false;
    915 
    916     m_frame->document()->updateStyleIfNeeded();
    917 
    918     Page* page = m_frame->page();
    919     if (!page)
    920         return false;
    921 
    922     return page->chrome().runJavaScriptConfirm(m_frame, message);
    923 }
    924 
    925 String DOMWindow::prompt(const String& message, const String& defaultValue)
    926 {
    927     if (!m_frame)
    928         return String();
    929 
    930     m_frame->document()->updateStyleIfNeeded();
    931 
    932     Page* page = m_frame->page();
    933     if (!page)
    934         return String();
    935 
    936     String returnValue;
    937     if (page->chrome().runJavaScriptPrompt(m_frame, message, defaultValue, returnValue))
    938         return returnValue;
    939 
    940     return String();
    941 }
    942 
    943 bool DOMWindow::find(const String& string, bool caseSensitive, bool backwards, bool wrap, bool /*wholeWord*/, bool /*searchInFrames*/, bool /*showDialog*/) const
    944 {
    945     if (!isCurrentlyDisplayedInFrame())
    946         return false;
    947 
    948     // FIXME (13016): Support wholeWord, searchInFrames and showDialog
    949     return m_frame->editor()->findString(string, !backwards, caseSensitive, wrap, false);
    950 }
    951 
    952 bool DOMWindow::offscreenBuffering() const
    953 {
    954     return true;
    955 }
    956 
    957 int DOMWindow::outerHeight() const
    958 {
    959     if (!m_frame)
    960         return 0;
    961 
    962     Page* page = m_frame->page();
    963     if (!page)
    964         return 0;
    965 
    966     if (page->settings()->reportScreenSizeInPhysicalPixelsQuirk())
    967         return lroundf(page->chrome().windowRect().height() * page->deviceScaleFactor());
    968     return static_cast<int>(page->chrome().windowRect().height());
    969 }
    970 
    971 int DOMWindow::outerWidth() const
    972 {
    973     if (!m_frame)
    974         return 0;
    975 
    976     Page* page = m_frame->page();
    977     if (!page)
    978         return 0;
    979 
    980     if (page->settings()->reportScreenSizeInPhysicalPixelsQuirk())
    981         return lroundf(page->chrome().windowRect().width() * page->deviceScaleFactor());
    982     return static_cast<int>(page->chrome().windowRect().width());
    983 }
    984 
    985 int DOMWindow::innerHeight() const
    986 {
    987     if (!m_frame)
    988         return 0;
    989 
    990     FrameView* view = m_frame->view();
    991     if (!view)
    992         return 0;
    993 
    994     // FIXME: This is potentially too much work. We really only need to know the dimensions of the parent frame's renderer.
    995     if (Frame* parent = m_frame->tree()->parent())
    996         parent->document()->updateLayoutIgnorePendingStylesheets();
    997 
    998     // If the device height is overridden, do not include the horizontal scrollbar into the innerHeight (since it is absent on the real device).
    999     bool includeScrollbars = !InspectorInstrumentation::shouldApplyScreenHeightOverride(m_frame);
   1000     return view->mapFromLayoutToCSSUnits(static_cast<int>(view->visibleContentRect(includeScrollbars ? ScrollableArea::IncludeScrollbars : ScrollableArea::ExcludeScrollbars).height()));
   1001 }
   1002 
   1003 int DOMWindow::innerWidth() const
   1004 {
   1005     if (!m_frame)
   1006         return 0;
   1007 
   1008     FrameView* view = m_frame->view();
   1009     if (!view)
   1010         return 0;
   1011 
   1012     // FIXME: This is potentially too much work. We really only need to know the dimensions of the parent frame's renderer.
   1013     if (Frame* parent = m_frame->tree()->parent())
   1014         parent->document()->updateLayoutIgnorePendingStylesheets();
   1015 
   1016     // If the device width is overridden, do not include the vertical scrollbar into the innerWidth (since it is absent on the real device).
   1017     bool includeScrollbars = !InspectorInstrumentation::shouldApplyScreenWidthOverride(m_frame);
   1018     return view->mapFromLayoutToCSSUnits(static_cast<int>(view->visibleContentRect(includeScrollbars ? ScrollableArea::IncludeScrollbars : ScrollableArea::ExcludeScrollbars).width()));
   1019 }
   1020 
   1021 int DOMWindow::screenX() const
   1022 {
   1023     if (!m_frame)
   1024         return 0;
   1025 
   1026     Page* page = m_frame->page();
   1027     if (!page)
   1028         return 0;
   1029 
   1030     if (page->settings()->reportScreenSizeInPhysicalPixelsQuirk())
   1031         return lroundf(page->chrome().windowRect().x() * page->deviceScaleFactor());
   1032     return static_cast<int>(page->chrome().windowRect().x());
   1033 }
   1034 
   1035 int DOMWindow::screenY() const
   1036 {
   1037     if (!m_frame)
   1038         return 0;
   1039 
   1040     Page* page = m_frame->page();
   1041     if (!page)
   1042         return 0;
   1043 
   1044     if (page->settings()->reportScreenSizeInPhysicalPixelsQuirk())
   1045         return lroundf(page->chrome().windowRect().y() * page->deviceScaleFactor());
   1046     return static_cast<int>(page->chrome().windowRect().y());
   1047 }
   1048 
   1049 int DOMWindow::scrollX() const
   1050 {
   1051     if (!m_frame)
   1052         return 0;
   1053 
   1054     FrameView* view = m_frame->view();
   1055     if (!view)
   1056         return 0;
   1057 
   1058     m_frame->document()->updateLayoutIgnorePendingStylesheets();
   1059 
   1060     return view->mapFromLayoutToCSSUnits(view->scrollX());
   1061 }
   1062 
   1063 int DOMWindow::scrollY() const
   1064 {
   1065     if (!m_frame)
   1066         return 0;
   1067 
   1068     FrameView* view = m_frame->view();
   1069     if (!view)
   1070         return 0;
   1071 
   1072     m_frame->document()->updateLayoutIgnorePendingStylesheets();
   1073 
   1074     return view->mapFromLayoutToCSSUnits(view->scrollY());
   1075 }
   1076 
   1077 bool DOMWindow::closed() const
   1078 {
   1079     return !m_frame;
   1080 }
   1081 
   1082 unsigned DOMWindow::length() const
   1083 {
   1084     if (!isCurrentlyDisplayedInFrame())
   1085         return 0;
   1086 
   1087     return m_frame->tree()->scopedChildCount();
   1088 }
   1089 
   1090 String DOMWindow::name() const
   1091 {
   1092     if (!m_frame)
   1093         return String();
   1094 
   1095     return m_frame->tree()->name();
   1096 }
   1097 
   1098 void DOMWindow::setName(const String& string)
   1099 {
   1100     if (!m_frame)
   1101         return;
   1102 
   1103     m_frame->tree()->setName(string);
   1104     m_frame->loader()->client()->didChangeName(string);
   1105 }
   1106 
   1107 void DOMWindow::setStatus(const String& string)
   1108 {
   1109     m_status = string;
   1110 
   1111     if (!m_frame)
   1112         return;
   1113 
   1114     Page* page = m_frame->page();
   1115     if (!page)
   1116         return;
   1117 
   1118     ASSERT(m_frame->document()); // Client calls shouldn't be made when the frame is in inconsistent state.
   1119     page->chrome().setStatusbarText(m_frame, m_status);
   1120 }
   1121 
   1122 void DOMWindow::setDefaultStatus(const String& string)
   1123 {
   1124     m_defaultStatus = string;
   1125 
   1126     if (!m_frame)
   1127         return;
   1128 
   1129     Page* page = m_frame->page();
   1130     if (!page)
   1131         return;
   1132 
   1133     ASSERT(m_frame->document()); // Client calls shouldn't be made when the frame is in inconsistent state.
   1134     page->chrome().setStatusbarText(m_frame, m_defaultStatus);
   1135 }
   1136 
   1137 DOMWindow* DOMWindow::self() const
   1138 {
   1139     if (!m_frame)
   1140         return 0;
   1141 
   1142     return m_frame->domWindow();
   1143 }
   1144 
   1145 DOMWindow* DOMWindow::opener() const
   1146 {
   1147     if (!m_frame)
   1148         return 0;
   1149 
   1150     Frame* opener = m_frame->loader()->opener();
   1151     if (!opener)
   1152         return 0;
   1153 
   1154     return opener->domWindow();
   1155 }
   1156 
   1157 DOMWindow* DOMWindow::parent() const
   1158 {
   1159     if (!m_frame)
   1160         return 0;
   1161 
   1162     Frame* parent = m_frame->tree()->parent();
   1163     if (parent)
   1164         return parent->domWindow();
   1165 
   1166     return m_frame->domWindow();
   1167 }
   1168 
   1169 DOMWindow* DOMWindow::top() const
   1170 {
   1171     if (!m_frame)
   1172         return 0;
   1173 
   1174     Page* page = m_frame->page();
   1175     if (!page)
   1176         return 0;
   1177 
   1178     return m_frame->tree()->top()->domWindow();
   1179 }
   1180 
   1181 Document* DOMWindow::document() const
   1182 {
   1183     return m_document.get();
   1184 }
   1185 
   1186 PassRefPtr<StyleMedia> DOMWindow::styleMedia() const
   1187 {
   1188     if (!isCurrentlyDisplayedInFrame())
   1189         return 0;
   1190     if (!m_media)
   1191         m_media = StyleMedia::create(m_frame);
   1192     return m_media.get();
   1193 }
   1194 
   1195 PassRefPtr<CSSStyleDeclaration> DOMWindow::getComputedStyle(Element* elt, const String& pseudoElt) const
   1196 {
   1197     if (!elt)
   1198         return 0;
   1199 
   1200     return CSSComputedStyleDeclaration::create(elt, false, pseudoElt);
   1201 }
   1202 
   1203 PassRefPtr<CSSRuleList> DOMWindow::getMatchedCSSRules(Element* element, const String& pseudoElement, bool authorOnly) const
   1204 {
   1205     if (!isCurrentlyDisplayedInFrame())
   1206         return 0;
   1207 
   1208     unsigned colonStart = pseudoElement[0] == ':' ? (pseudoElement[1] == ':' ? 2 : 1) : 0;
   1209     CSSSelector::PseudoType pseudoType = CSSSelector::parsePseudoType(AtomicString(pseudoElement.substring(colonStart)));
   1210     if (pseudoType == CSSSelector::PseudoUnknown && !pseudoElement.isEmpty())
   1211         return 0;
   1212 
   1213     unsigned rulesToInclude = StyleResolver::AuthorCSSRules;
   1214     if (!authorOnly)
   1215         rulesToInclude |= StyleResolver::UAAndUserCSSRules;
   1216 
   1217     PseudoId pseudoId = CSSSelector::pseudoId(pseudoType);
   1218 
   1219     return m_frame->document()->styleResolver()->pseudoStyleRulesForElement(element, pseudoId, rulesToInclude);
   1220 }
   1221 
   1222 PassRefPtr<DOMPoint> DOMWindow::webkitConvertPointFromNodeToPage(Node* node, const DOMPoint* p) const
   1223 {
   1224     if (!node || !p)
   1225         return 0;
   1226 
   1227     if (!document())
   1228         return 0;
   1229 
   1230     document()->updateLayoutIgnorePendingStylesheets();
   1231 
   1232     FloatPoint pagePoint(p->x(), p->y());
   1233     pagePoint = node->convertToPage(pagePoint);
   1234     return DOMPoint::create(pagePoint.x(), pagePoint.y());
   1235 }
   1236 
   1237 PassRefPtr<DOMPoint> DOMWindow::webkitConvertPointFromPageToNode(Node* node, const DOMPoint* p) const
   1238 {
   1239     if (!node || !p)
   1240         return 0;
   1241 
   1242     if (!document())
   1243         return 0;
   1244 
   1245     document()->updateLayoutIgnorePendingStylesheets();
   1246 
   1247     FloatPoint nodePoint(p->x(), p->y());
   1248     nodePoint = node->convertFromPage(nodePoint);
   1249     return DOMPoint::create(nodePoint.x(), nodePoint.y());
   1250 }
   1251 
   1252 double DOMWindow::devicePixelRatio() const
   1253 {
   1254     if (!m_frame)
   1255         return 0.0;
   1256 
   1257     Page* page = m_frame->page();
   1258     if (!page)
   1259         return 0.0;
   1260 
   1261     return page->deviceScaleFactor();
   1262 }
   1263 
   1264 void DOMWindow::scrollBy(int x, int y) const
   1265 {
   1266     if (!isCurrentlyDisplayedInFrame())
   1267         return;
   1268 
   1269     document()->updateLayoutIgnorePendingStylesheets();
   1270 
   1271     FrameView* view = m_frame->view();
   1272     if (!view)
   1273         return;
   1274 
   1275     IntSize scaledOffset(view->mapFromCSSToLayoutUnits(x), view->mapFromCSSToLayoutUnits(y));
   1276     view->scrollBy(scaledOffset);
   1277 }
   1278 
   1279 void DOMWindow::scrollTo(int x, int y) const
   1280 {
   1281     if (!isCurrentlyDisplayedInFrame())
   1282         return;
   1283 
   1284     document()->updateLayoutIgnorePendingStylesheets();
   1285 
   1286     RefPtr<FrameView> view = m_frame->view();
   1287     if (!view)
   1288         return;
   1289 
   1290     IntPoint layoutPos(view->mapFromCSSToLayoutUnits(x), view->mapFromCSSToLayoutUnits(y));
   1291     view->setScrollPosition(layoutPos);
   1292 }
   1293 
   1294 void DOMWindow::moveBy(float x, float y) const
   1295 {
   1296     if (!m_frame)
   1297         return;
   1298 
   1299     Page* page = m_frame->page();
   1300     if (!page)
   1301         return;
   1302 
   1303     if (m_frame != page->mainFrame())
   1304         return;
   1305 
   1306     FloatRect fr = page->chrome().windowRect();
   1307     FloatRect update = fr;
   1308     update.move(x, y);
   1309     // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
   1310     page->chrome().setWindowRect(adjustWindowRect(page, update));
   1311 }
   1312 
   1313 void DOMWindow::moveTo(float x, float y) const
   1314 {
   1315     if (!m_frame)
   1316         return;
   1317 
   1318     Page* page = m_frame->page();
   1319     if (!page)
   1320         return;
   1321 
   1322     if (m_frame != page->mainFrame())
   1323         return;
   1324 
   1325     FloatRect fr = page->chrome().windowRect();
   1326     FloatRect sr = screenAvailableRect(page->mainFrame()->view());
   1327     fr.setLocation(sr.location());
   1328     FloatRect update = fr;
   1329     update.move(x, y);
   1330     // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
   1331     page->chrome().setWindowRect(adjustWindowRect(page, update));
   1332 }
   1333 
   1334 void DOMWindow::resizeBy(float x, float y) const
   1335 {
   1336     if (!m_frame)
   1337         return;
   1338 
   1339     Page* page = m_frame->page();
   1340     if (!page)
   1341         return;
   1342 
   1343     if (m_frame != page->mainFrame())
   1344         return;
   1345 
   1346     FloatRect fr = page->chrome().windowRect();
   1347     FloatSize dest = fr.size() + FloatSize(x, y);
   1348     FloatRect update(fr.location(), dest);
   1349     page->chrome().setWindowRect(adjustWindowRect(page, update));
   1350 }
   1351 
   1352 void DOMWindow::resizeTo(float width, float height) const
   1353 {
   1354     if (!m_frame)
   1355         return;
   1356 
   1357     Page* page = m_frame->page();
   1358     if (!page)
   1359         return;
   1360 
   1361     if (m_frame != page->mainFrame())
   1362         return;
   1363 
   1364     FloatRect fr = page->chrome().windowRect();
   1365     FloatSize dest = FloatSize(width, height);
   1366     FloatRect update(fr.location(), dest);
   1367     page->chrome().setWindowRect(adjustWindowRect(page, update));
   1368 }
   1369 
   1370 int DOMWindow::requestAnimationFrame(PassRefPtr<RequestAnimationFrameCallback> callback)
   1371 {
   1372     callback->m_useLegacyTimeBase = false;
   1373     if (Document* d = document())
   1374         return d->requestAnimationFrame(callback);
   1375     return 0;
   1376 }
   1377 
   1378 int DOMWindow::webkitRequestAnimationFrame(PassRefPtr<RequestAnimationFrameCallback> callback)
   1379 {
   1380     callback->m_useLegacyTimeBase = true;
   1381     if (Document* d = document())
   1382         return d->requestAnimationFrame(callback);
   1383     return 0;
   1384 }
   1385 
   1386 void DOMWindow::cancelAnimationFrame(int id)
   1387 {
   1388     if (Document* d = document())
   1389         d->cancelAnimationFrame(id);
   1390 }
   1391 
   1392 DOMWindowCSS* DOMWindow::css()
   1393 {
   1394     if (!m_css)
   1395         m_css = DOMWindowCSS::create();
   1396     return m_css.get();
   1397 }
   1398 
   1399 static void didAddStorageEventListener(DOMWindow* window)
   1400 {
   1401     // Creating these WebCore::Storage objects informs the system that we'd like to receive
   1402     // notifications about storage events that might be triggered in other processes. Rather
   1403     // than subscribe to these notifications explicitly, we subscribe to them implicitly to
   1404     // simplify the work done by the system.
   1405     window->localStorage(IGNORE_EXCEPTION);
   1406     window->sessionStorage(IGNORE_EXCEPTION);
   1407 }
   1408 
   1409 bool DOMWindow::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
   1410 {
   1411     if (!EventTarget::addEventListener(eventType, listener, useCapture))
   1412         return false;
   1413 
   1414     if (Document* document = this->document()) {
   1415         document->addListenerTypeIfNeeded(eventType);
   1416         if (eventType == eventNames().mousewheelEvent)
   1417             document->didAddWheelEventHandler();
   1418         else if (eventNames().isTouchEventType(eventType))
   1419             document->didAddTouchEventHandler(document);
   1420         else if (eventType == eventNames().storageEvent)
   1421             didAddStorageEventListener(this);
   1422     }
   1423 
   1424     if (eventType == eventNames().unloadEvent) {
   1425         addUnloadEventListener(this);
   1426     } else if (eventType == eventNames().beforeunloadEvent) {
   1427         if (allowsBeforeUnloadListeners(this)) {
   1428             // This is confusingly named. It doesn't actually add the listener. It just increments a count
   1429             // so that we know we have listeners registered for the purposes of determining if we can
   1430             // fast terminate the renderer process.
   1431             addBeforeUnloadEventListener(this);
   1432         } else {
   1433             // Subframes return false from allowsBeforeUnloadListeners.
   1434             UseCounter::count(this, UseCounter::SubFrameBeforeUnloadRegistered);
   1435         }
   1436     } else if (eventType == eventNames().devicemotionEvent && RuntimeEnabledFeatures::deviceMotionEnabled()) {
   1437         if (DeviceMotionController* controller = DeviceMotionController::from(document()))
   1438             controller->startUpdating();
   1439     } else if (eventType == eventNames().deviceorientationEvent && RuntimeEnabledFeatures::deviceOrientationEnabled()) {
   1440         if (DeviceOrientationController* controller = DeviceOrientationController::from(page()))
   1441             controller->addDeviceEventListener(this);
   1442     }
   1443 
   1444     return true;
   1445 }
   1446 
   1447 bool DOMWindow::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
   1448 {
   1449     if (!EventTarget::removeEventListener(eventType, listener, useCapture))
   1450         return false;
   1451 
   1452     if (Document* document = this->document()) {
   1453         if (eventType == eventNames().mousewheelEvent)
   1454             document->didRemoveWheelEventHandler();
   1455         else if (eventNames().isTouchEventType(eventType))
   1456             document->didRemoveTouchEventHandler(document);
   1457     }
   1458 
   1459     if (eventType == eventNames().unloadEvent)
   1460         removeUnloadEventListener(this);
   1461     else if (eventType == eventNames().beforeunloadEvent && allowsBeforeUnloadListeners(this))
   1462         removeBeforeUnloadEventListener(this);
   1463     else if (eventType == eventNames().devicemotionEvent) {
   1464         if (DeviceMotionController* controller = DeviceMotionController::from(document()))
   1465             controller->stopUpdating();
   1466     } else if (eventType == eventNames().deviceorientationEvent) {
   1467         if (DeviceOrientationController* controller = DeviceOrientationController::from(page()))
   1468             controller->removeDeviceEventListener(this);
   1469     }
   1470 
   1471     return true;
   1472 }
   1473 
   1474 void DOMWindow::dispatchLoadEvent()
   1475 {
   1476     RefPtr<Event> loadEvent(Event::create(eventNames().loadEvent, false, false));
   1477     if (m_frame && m_frame->loader()->documentLoader() && !m_frame->loader()->documentLoader()->timing()->loadEventStart()) {
   1478         // The DocumentLoader (and thus its DocumentLoadTiming) might get destroyed while dispatching
   1479         // the event, so protect it to prevent writing the end time into freed memory.
   1480         RefPtr<DocumentLoader> documentLoader = m_frame->loader()->documentLoader();
   1481         DocumentLoadTiming* timing = documentLoader->timing();
   1482         timing->markLoadEventStart();
   1483         dispatchEvent(loadEvent, document());
   1484         timing->markLoadEventEnd();
   1485     } else
   1486         dispatchEvent(loadEvent, document());
   1487 
   1488     // For load events, send a separate load event to the enclosing frame only.
   1489     // This is a DOM extension and is independent of bubbling/capturing rules of
   1490     // the DOM.
   1491     Element* ownerElement = m_frame ? m_frame->ownerElement() : 0;
   1492     if (ownerElement)
   1493         ownerElement->dispatchEvent(Event::create(eventNames().loadEvent, false, false));
   1494 
   1495     InspectorInstrumentation::loadEventFired(frame());
   1496 }
   1497 
   1498 bool DOMWindow::dispatchEvent(PassRefPtr<Event> prpEvent, PassRefPtr<EventTarget> prpTarget)
   1499 {
   1500     RefPtr<EventTarget> protect = this;
   1501     RefPtr<Event> event = prpEvent;
   1502 
   1503     event->setTarget(prpTarget ? prpTarget : this);
   1504     event->setCurrentTarget(this);
   1505     event->setEventPhase(Event::AT_TARGET);
   1506 
   1507     InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispatchEventOnWindow(frame(), *event, this);
   1508 
   1509     bool result = fireEventListeners(event.get());
   1510 
   1511     InspectorInstrumentation::didDispatchEventOnWindow(cookie);
   1512 
   1513     return result;
   1514 }
   1515 
   1516 void DOMWindow::removeAllEventListeners()
   1517 {
   1518     EventTarget::removeAllEventListeners();
   1519 
   1520     if (DeviceMotionController* controller = DeviceMotionController::from(document()))
   1521         controller->stopUpdating();
   1522     if (DeviceOrientationController* controller = DeviceOrientationController::from(page()))
   1523         controller->removeAllDeviceEventListeners(this);
   1524     if (Document* document = this->document())
   1525         document->didRemoveEventTargetNode(document);
   1526 
   1527     removeAllUnloadEventListeners(this);
   1528     removeAllBeforeUnloadEventListeners(this);
   1529 }
   1530 
   1531 void DOMWindow::finishedLoading()
   1532 {
   1533     if (m_shouldPrintWhenFinishedLoading) {
   1534         m_shouldPrintWhenFinishedLoading = false;
   1535         print();
   1536     }
   1537 }
   1538 
   1539 EventTargetData* DOMWindow::eventTargetData()
   1540 {
   1541     return &m_eventTargetData;
   1542 }
   1543 
   1544 EventTargetData* DOMWindow::ensureEventTargetData()
   1545 {
   1546     return &m_eventTargetData;
   1547 }
   1548 
   1549 void DOMWindow::setLocation(const String& urlString, DOMWindow* activeWindow, DOMWindow* firstWindow, SetLocationLocking locking)
   1550 {
   1551     if (!isCurrentlyDisplayedInFrame())
   1552         return;
   1553 
   1554     Document* activeDocument = activeWindow->document();
   1555     if (!activeDocument)
   1556         return;
   1557 
   1558     if (!activeDocument->canNavigate(m_frame))
   1559         return;
   1560 
   1561     Frame* firstFrame = firstWindow->frame();
   1562     if (!firstFrame)
   1563         return;
   1564 
   1565     KURL completedURL = firstFrame->document()->completeURL(urlString);
   1566     if (firstFrame->loader()->client()->shouldAbortNavigationAfterUrlResolve(firstFrame->document()->baseURI(), urlString, completedURL))
   1567       return;
   1568 
   1569     if (completedURL.isNull())
   1570         return;
   1571 
   1572     if (isInsecureScriptAccess(activeWindow, completedURL))
   1573         return;
   1574 
   1575     // We want a new history item if we are processing a user gesture.
   1576     m_frame->navigationScheduler()->scheduleLocationChange(activeDocument->securityOrigin(),
   1577         // FIXME: What if activeDocument()->frame() is 0?
   1578         completedURL, activeDocument->frame()->loader()->outgoingReferrer(),
   1579         locking != LockHistoryBasedOnGestureState);
   1580 }
   1581 
   1582 void DOMWindow::printErrorMessage(const String& message)
   1583 {
   1584     if (message.isEmpty())
   1585         return;
   1586 
   1587     pageConsole()->addMessage(JSMessageSource, ErrorMessageLevel, message);
   1588 }
   1589 
   1590 String DOMWindow::crossDomainAccessErrorMessage(DOMWindow* activeWindow)
   1591 {
   1592     const KURL& activeWindowURL = activeWindow->document()->url();
   1593     if (activeWindowURL.isNull())
   1594         return String();
   1595 
   1596     ASSERT(!activeWindow->document()->securityOrigin()->canAccess(document()->securityOrigin()));
   1597 
   1598     // FIXME: This message, and other console messages, have extra newlines. Should remove them.
   1599     SecurityOrigin* activeOrigin = activeWindow->document()->securityOrigin();
   1600     SecurityOrigin* targetOrigin = document()->securityOrigin();
   1601     String message = "Blocked a frame with origin \"" + activeOrigin->toString() + "\" from accessing a frame with origin \"" + targetOrigin->toString() + "\". ";
   1602 
   1603     // Sandbox errors: Use the origin of the frames' location, rather than their actual origin (since we know that at least one will be "null").
   1604     KURL activeURL = activeWindow->document()->url();
   1605     KURL targetURL = document()->url();
   1606     if (document()->isSandboxed(SandboxOrigin) || activeWindow->document()->isSandboxed(SandboxOrigin)) {
   1607         message = "Blocked a frame at \"" + SecurityOrigin::create(activeURL)->toString() + "\" from accessing a frame at \"" + SecurityOrigin::create(targetURL)->toString() + "\". ";
   1608         if (document()->isSandboxed(SandboxOrigin) && activeWindow->document()->isSandboxed(SandboxOrigin))
   1609             return "Sandbox access violation: " + message + " Both frames are sandboxed and lack the \"allow-same-origin\" flag.";
   1610         if (document()->isSandboxed(SandboxOrigin))
   1611             return "Sandbox access violation: " + message + " The frame being accessed is sandboxed and lacks the \"allow-same-origin\" flag.";
   1612         return "Sandbox access violation: " + message + " The frame requesting access is sandboxed and lacks the \"allow-same-origin\" flag.";
   1613     }
   1614 
   1615     // Protocol errors: Use the URL's protocol rather than the origin's protocol so that we get a useful message for non-heirarchal URLs like 'data:'.
   1616     if (targetOrigin->protocol() != activeOrigin->protocol())
   1617         return message + " The frame requesting access has a protocol of \"" + activeURL.protocol() + "\", the frame being accessed has a protocol of \"" + targetURL.protocol() + "\". Protocols must match.\n";
   1618 
   1619     // 'document.domain' errors.
   1620     if (targetOrigin->domainWasSetInDOM() && activeOrigin->domainWasSetInDOM())
   1621         return message + "The frame requesting access set \"document.domain\" to \"" + activeOrigin->domain() + "\", the frame being accessed set it to \"" + targetOrigin->domain() + "\". Both must set \"document.domain\" to the same value to allow access.";
   1622     if (activeOrigin->domainWasSetInDOM())
   1623         return message + "The frame requesting access set \"document.domain\" to \"" + activeOrigin->domain() + "\", but the frame being accessed did not. Both must set \"document.domain\" to the same value to allow access.";
   1624     if (targetOrigin->domainWasSetInDOM())
   1625         return message + "The frame being accessed set \"document.domain\" to \"" + targetOrigin->domain() + "\", but the frame requesting access did not. Both must set \"document.domain\" to the same value to allow access.";
   1626 
   1627     // Default.
   1628     return message + "Protocols, domains, and ports must match.";
   1629 }
   1630 
   1631 bool DOMWindow::isInsecureScriptAccess(DOMWindow* activeWindow, const String& urlString)
   1632 {
   1633     if (!protocolIsJavaScript(urlString))
   1634         return false;
   1635 
   1636     // If this DOMWindow isn't currently active in the Frame, then there's no
   1637     // way we should allow the access.
   1638     // FIXME: Remove this check if we're able to disconnect DOMWindow from
   1639     // Frame on navigation: https://bugs.webkit.org/show_bug.cgi?id=62054
   1640     if (isCurrentlyDisplayedInFrame()) {
   1641         // FIXME: Is there some way to eliminate the need for a separate "activeWindow == this" check?
   1642         if (activeWindow == this)
   1643             return false;
   1644 
   1645         // FIXME: The name canAccess seems to be a roundabout way to ask "can execute script".
   1646         // Can we name the SecurityOrigin function better to make this more clear?
   1647         if (activeWindow->document()->securityOrigin()->canAccess(document()->securityOrigin()))
   1648             return false;
   1649     }
   1650 
   1651     printErrorMessage(crossDomainAccessErrorMessage(activeWindow));
   1652     return true;
   1653 }
   1654 
   1655 PassRefPtr<DOMWindow> DOMWindow::open(const String& urlString, const AtomicString& frameName, const String& windowFeaturesString,
   1656     DOMWindow* activeWindow, DOMWindow* firstWindow)
   1657 {
   1658     if (!isCurrentlyDisplayedInFrame())
   1659         return 0;
   1660     Document* activeDocument = activeWindow->document();
   1661     if (!activeDocument)
   1662         return 0;
   1663     Frame* firstFrame = firstWindow->frame();
   1664     if (!firstFrame)
   1665         return 0;
   1666 
   1667     if (!firstWindow->allowPopUp()) {
   1668         // Because FrameTree::find() returns true for empty strings, we must check for empty frame names.
   1669         // Otherwise, illegitimate window.open() calls with no name will pass right through the popup blocker.
   1670         if (frameName.isEmpty() || !m_frame->tree()->find(frameName))
   1671             return 0;
   1672     }
   1673 
   1674     // Get the target frame for the special cases of _top and _parent.
   1675     // In those cases, we schedule a location change right now and return early.
   1676     Frame* targetFrame = 0;
   1677     if (frameName == "_top")
   1678         targetFrame = m_frame->tree()->top();
   1679     else if (frameName == "_parent") {
   1680         if (Frame* parent = m_frame->tree()->parent())
   1681             targetFrame = parent;
   1682         else
   1683             targetFrame = m_frame;
   1684     }
   1685     if (targetFrame) {
   1686         if (!activeDocument->canNavigate(targetFrame))
   1687             return 0;
   1688 
   1689         KURL completedURL = firstFrame->document()->completeURL(urlString);
   1690 
   1691         if (targetFrame->domWindow()->isInsecureScriptAccess(activeWindow, completedURL))
   1692             return targetFrame->domWindow();
   1693 
   1694         if (urlString.isEmpty())
   1695             return targetFrame->domWindow();
   1696 
   1697         // For whatever reason, Firefox uses the first window rather than the active window to
   1698         // determine the outgoing referrer. We replicate that behavior here.
   1699         targetFrame->navigationScheduler()->scheduleLocationChange(
   1700             activeDocument->securityOrigin(),
   1701             completedURL,
   1702             firstFrame->loader()->outgoingReferrer(),
   1703             false);
   1704         return targetFrame->domWindow();
   1705     }
   1706 
   1707     WindowFeatures windowFeatures(windowFeaturesString);
   1708     Frame* result = createWindow(urlString, frameName, windowFeatures, activeWindow, firstFrame, m_frame);
   1709     return result ? result->domWindow() : 0;
   1710 }
   1711 
   1712 void DOMWindow::showModalDialog(const String& urlString, const String& dialogFeaturesString,
   1713     DOMWindow* activeWindow, DOMWindow* firstWindow, PrepareDialogFunction function, void* functionContext)
   1714 {
   1715     if (!isCurrentlyDisplayedInFrame())
   1716         return;
   1717     Frame* activeFrame = activeWindow->frame();
   1718     if (!activeFrame)
   1719         return;
   1720     Frame* firstFrame = firstWindow->frame();
   1721     if (!firstFrame)
   1722         return;
   1723 
   1724     if (!canShowModalDialogNow(m_frame) || !firstWindow->allowPopUp())
   1725         return;
   1726 
   1727     WindowFeatures windowFeatures(dialogFeaturesString, screenAvailableRect(m_frame->view()));
   1728     Frame* dialogFrame = createWindow(urlString, emptyAtom, windowFeatures,
   1729         activeWindow, firstFrame, m_frame, function, functionContext);
   1730     if (!dialogFrame)
   1731         return;
   1732     UserGestureIndicatorDisabler disabler;
   1733     dialogFrame->page()->chrome().runModal();
   1734 }
   1735 
   1736 DOMWindow* DOMWindow::anonymousIndexedGetter(uint32_t index)
   1737 {
   1738     Frame* frame = this->frame();
   1739     if (!frame)
   1740         return 0;
   1741 
   1742     Frame* child = frame->tree()->scopedChild(index);
   1743     if (child)
   1744         return child->domWindow();
   1745 
   1746     return 0;
   1747 }
   1748 
   1749 
   1750 } // namespace WebCore
   1751