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