WebCore:
[WebKit-https.git] / WebCore / page / DOMWindow.cpp
1 /*
2  * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "DOMWindow.h"
28
29 #include "BarInfo.h"
30 #include "CSSComputedStyleDeclaration.h"
31 #include "CSSRuleList.h"
32 #include "CSSStyleSelector.h"
33 #include "Chrome.h"
34 #include "Console.h"
35 #include "DOMSelection.h"
36 #include "Document.h"
37 #include "Element.h"
38 #include "FloatRect.h"
39 #include "Frame.h"
40 #include "FrameLoader.h"
41 #include "FrameTree.h"
42 #include "FrameView.h"
43 #include "History.h"
44 #include "MessageEvent.h"
45 #include "Page.h"
46 #include "PlatformScreen.h"
47 #include "PlatformString.h"
48 #include "Screen.h"
49 #include <algorithm>
50 #include <wtf/MathExtras.h>
51
52 #if ENABLE(DATABASE)
53 #include "Database.h"
54 #endif
55
56 using std::min;
57 using std::max;
58
59 namespace WebCore {
60
61 // This function:
62 // 1) Validates the pending changes are not changing to NaN
63 // 2) Constrains the window rect to no smaller than 100 in each dimension and no
64 //    bigger than the the float rect's dimensions.
65 // 3) Constrain window rect to within the top and left boundaries of the screen rect
66 // 4) Constraint the window rect to within the bottom and right boundaries of the
67 //    screen rect.
68 // 5) Translate the window rect coordinates to be within the coordinate space of
69 //    the screen rect.
70 void DOMWindow::adjustWindowRect(const FloatRect& screen, FloatRect& window, const FloatRect& pendingChanges)
71 {
72     // Make sure we're in a valid state before adjusting dimensions
73     ASSERT(!isnan(screen.x()) && !isnan(screen.y()) && !isnan(screen.width()) && !isnan(screen.height()) &&
74            !isnan(window.x()) && !isnan(window.y()) && !isnan(window.width()) && !isnan(window.height()));
75     
76     // Update window values if they are not NaN
77     if (!isnan(pendingChanges.x()))
78         window.setX(pendingChanges.x());
79     if (!isnan(pendingChanges.y()))
80         window.setY(pendingChanges.y());
81     if (!isnan(pendingChanges.width()))
82         window.setWidth(pendingChanges.width());
83     if (!isnan(pendingChanges.height()))
84         window.setHeight(pendingChanges.height());
85     
86     // Resize the window to between 100 and the screen width and height if it's
87     // outside of those ranges.
88     window.setWidth(min(max(100.0f, window.width()), screen.width()));
89     window.setHeight(min(max(100.0f, window.height()), screen.height()));
90     
91     // Constrain the window to the top and left of the screen if it's left or
92     // above it.
93     window.setX(max(window.x(), screen.x()));
94     window.setY(max(window.y(), screen.y()));
95
96     // Constrain the window to the bottom and right of the screen if it's past
97     // the right or below it.
98     window.setX(window.x() - max(0.0f, window.right() - screen.width() - screen.x()));
99     window.setY(window.y() - max(0.0f, window.bottom() - screen.height() - screen.y()));
100 }
101
102 DOMWindow::DOMWindow(Frame* frame)
103     : m_frame(frame)
104 {
105 }
106
107 DOMWindow::~DOMWindow()
108 {
109 }
110
111 void DOMWindow::disconnectFrame()
112 {
113     m_frame = 0;
114     clear();
115 }
116
117 void DOMWindow::clear()
118 {
119     if (m_screen)
120         m_screen->disconnectFrame();
121     m_screen = 0;
122
123     if (m_selection)
124         m_selection->disconnectFrame();
125     m_selection = 0;
126
127     if (m_history)
128         m_history->disconnectFrame();
129     m_history = 0;
130
131     if (m_locationbar)
132         m_locationbar->disconnectFrame();
133     m_locationbar = 0;
134
135     if (m_menubar)
136         m_menubar->disconnectFrame();
137     m_menubar = 0;
138
139     if (m_personalbar)
140         m_personalbar->disconnectFrame();
141     m_personalbar = 0;
142
143     if (m_scrollbars)
144         m_scrollbars->disconnectFrame();
145     m_scrollbars = 0;
146
147     if (m_statusbar)
148         m_statusbar->disconnectFrame();
149     m_statusbar = 0;
150
151     if (m_toolbar)
152         m_toolbar->disconnectFrame();
153     m_toolbar = 0;
154
155     if (m_console)
156         m_console->disconnectFrame();
157     m_console = 0;
158 }
159
160 Screen* DOMWindow::screen() const
161 {
162     if (!m_screen)
163         m_screen = new Screen(m_frame);
164     return m_screen.get();
165 }
166
167 History* DOMWindow::history() const
168 {
169     if (!m_history)
170         m_history = new History(m_frame);
171     return m_history.get();
172 }
173
174 BarInfo* DOMWindow::locationbar() const
175 {
176     if (!m_locationbar)
177         m_locationbar = new BarInfo(m_frame, BarInfo::Locationbar);
178     return m_locationbar.get();
179 }
180
181 BarInfo* DOMWindow::menubar() const
182 {
183     if (!m_menubar)
184         m_menubar = new BarInfo(m_frame, BarInfo::Menubar);
185     return m_menubar.get();
186 }
187
188 BarInfo* DOMWindow::personalbar() const
189 {
190     if (!m_personalbar)
191         m_personalbar = new BarInfo(m_frame, BarInfo::Personalbar);
192     return m_personalbar.get();
193 }
194
195 BarInfo* DOMWindow::scrollbars() const
196 {
197     if (!m_scrollbars)
198         m_scrollbars = new BarInfo(m_frame, BarInfo::Scrollbars);
199     return m_scrollbars.get();
200 }
201
202 BarInfo* DOMWindow::statusbar() const
203 {
204     if (!m_statusbar)
205         m_statusbar = new BarInfo(m_frame, BarInfo::Statusbar);
206     return m_statusbar.get();
207 }
208
209 BarInfo* DOMWindow::toolbar() const
210 {
211     if (!m_toolbar)
212         m_toolbar = new BarInfo(m_frame, BarInfo::Toolbar);
213     return m_toolbar.get();
214 }
215
216 Console* DOMWindow::console() const
217 {
218     if (!m_console)
219         m_console = new Console(m_frame);
220     return m_console.get();
221 }
222
223 void DOMWindow::postMessage(const String& message, const String& domain, const String& uri, DOMWindow* source) const
224 {
225    ExceptionCode ec;
226    document()->dispatchEvent(new MessageEvent(message, domain, uri, source), ec, true);
227 }
228
229 DOMSelection* DOMWindow::getSelection()
230 {
231     if (!m_selection)
232         m_selection = new DOMSelection(m_frame);
233     return m_selection.get();
234 }
235
236 Element* DOMWindow::frameElement() const
237 {
238     if (!m_frame)
239         return 0;
240
241     Document* doc = m_frame->document();
242     ASSERT(doc);
243     if (!doc)
244         return 0;
245
246     // FIXME: could this use m_frame->ownerElement() instead of going through the Document.
247     return doc->ownerElement();
248 }
249
250 void DOMWindow::focus()
251 {
252     if (!m_frame)
253         return;
254
255     m_frame->focusWindow();
256 }
257
258 void DOMWindow::blur()
259 {
260     if (!m_frame)
261         return;
262
263     m_frame->unfocusWindow();
264 }
265
266 void DOMWindow::close()
267 {
268     if (!m_frame)
269         return;
270
271     if (m_frame->loader()->openedByDOM() || m_frame->loader()->getHistoryLength() <= 1)
272         m_frame->scheduleClose();
273 }
274
275 void DOMWindow::print()
276 {
277     if (!m_frame)
278         return;
279
280     Page* page = m_frame->page();
281     if (!page)
282         return;
283
284     page->chrome()->print(m_frame);
285 }
286
287 void DOMWindow::stop()
288 {
289     if (!m_frame)
290         return;
291
292     // We must check whether the load is complete asynchronously, because we might still be parsing
293     // the document until the callstack unwinds.
294     m_frame->loader()->stopForUserCancel(true);
295 }
296
297 void DOMWindow::alert(const String& message)
298 {
299     if (!m_frame)
300         return;
301
302     Document* doc = m_frame->document();
303     ASSERT(doc);
304     if (doc)
305         doc->updateRendering();
306
307     Page* page = m_frame->page();
308     if (!page)
309         return;
310
311     page->chrome()->runJavaScriptAlert(m_frame, message);
312 }
313
314 bool DOMWindow::confirm(const String& message)
315 {
316     if (!m_frame)
317         return false;
318
319     Document* doc = m_frame->document();
320     ASSERT(doc);
321     if (doc)
322         doc->updateRendering();
323
324     Page* page = m_frame->page();
325     if (!page)
326         return false;
327
328     return page->chrome()->runJavaScriptConfirm(m_frame, message);
329 }
330
331 String DOMWindow::prompt(const String& message, const String& defaultValue)
332 {
333     if (!m_frame)
334         return String();
335
336     Document* doc = m_frame->document();
337     ASSERT(doc);
338     if (doc)
339         doc->updateRendering();
340
341     Page* page = m_frame->page();
342     if (!page)
343         return String();
344
345     String returnValue;
346     if (page->chrome()->runJavaScriptPrompt(m_frame, message, defaultValue, returnValue))
347         return returnValue;
348
349     return String();
350 }
351
352 bool DOMWindow::find(const String& string, bool caseSensitive, bool backwards, bool wrap, bool wholeWord, bool searchInFrames, bool showDialog) const
353 {
354     if (!m_frame)
355         return false;
356
357     // FIXME (13016): Support wholeWord, searchInFrames and showDialog
358     return m_frame->findString(string, !backwards, caseSensitive, wrap, false);
359 }
360
361 bool DOMWindow::offscreenBuffering() const
362 {
363     return true;
364 }
365
366 int DOMWindow::outerHeight() const
367 {
368     if (!m_frame)
369         return 0;
370
371     Page* page = m_frame->page();
372     if (!page)
373         return 0;
374
375     return static_cast<int>(page->chrome()->windowRect().height());
376 }
377
378 int DOMWindow::outerWidth() const
379 {
380     if (!m_frame)
381         return 0;
382
383     Page* page = m_frame->page();
384     if (!page)
385         return 0;
386
387     return static_cast<int>(page->chrome()->windowRect().width());
388 }
389
390 int DOMWindow::innerHeight() const
391 {
392     if (!m_frame)
393         return 0;
394
395     FrameView* view = m_frame->view();
396     if (!view)
397         return 0;
398
399     return view->height();
400 }
401
402 int DOMWindow::innerWidth() const
403 {
404     if (!m_frame)
405         return 0;
406
407     FrameView* view = m_frame->view();
408     if (!view)
409         return 0;
410
411     return view->width();
412 }
413
414 int DOMWindow::screenX() const
415 {
416     if (!m_frame)
417         return 0;
418
419     Page* page = m_frame->page();
420     if (!page)
421         return 0;
422
423     return static_cast<int>(page->chrome()->windowRect().x());
424 }
425
426 int DOMWindow::screenY() const
427 {
428     if (!m_frame)
429         return 0;
430
431     Page* page = m_frame->page();
432     if (!page)
433         return 0;
434
435     return static_cast<int>(page->chrome()->windowRect().y());
436 }
437
438 int DOMWindow::scrollX() const
439 {
440     if (!m_frame)
441         return 0;
442
443     FrameView* view = m_frame->view();
444     if (!view)
445         return 0;
446
447     Document* doc = m_frame->document();
448     ASSERT(doc);
449     if (doc)
450         doc->updateLayoutIgnorePendingStylesheets();
451
452     return view->contentsX();
453 }
454
455 int DOMWindow::scrollY() const
456 {
457     if (!m_frame)
458         return 0;
459
460     FrameView* view = m_frame->view();
461     if (!view)
462         return 0;
463
464     Document* doc = m_frame->document();
465     ASSERT(doc);
466     if (doc)
467         doc->updateLayoutIgnorePendingStylesheets();
468
469     return view->contentsY();
470 }
471
472 bool DOMWindow::closed() const
473 {
474     return !m_frame;
475 }
476
477 unsigned DOMWindow::length() const
478 {
479     if (!m_frame)
480         return 0;
481
482     return m_frame->tree()->childCount();
483 }
484
485 String DOMWindow::name() const
486 {
487     if (!m_frame)
488         return String();
489
490     return m_frame->tree()->name();
491 }
492
493 void DOMWindow::setName(const String& string)
494 {
495     if (!m_frame)
496         return;
497
498     m_frame->tree()->setName(string);
499 }
500
501 String DOMWindow::status() const
502 {
503     if (!m_frame)
504         return String();
505
506     return m_frame->jsStatusBarText();
507 }
508
509 void DOMWindow::setStatus(const String& string)
510 {
511     if (!m_frame)
512         return;
513
514     m_frame->setJSStatusBarText(string);
515 }
516
517 String DOMWindow::defaultStatus() const
518 {
519     if (!m_frame)
520         return String();
521
522     return m_frame->jsDefaultStatusBarText();
523 }
524
525 void DOMWindow::setDefaultStatus(const String& string)
526 {
527     if (!m_frame)
528         return;
529
530     m_frame->setJSDefaultStatusBarText(string);
531 }
532
533 DOMWindow* DOMWindow::self() const
534 {
535     if (!m_frame)
536         return 0;
537
538     return m_frame->domWindow();
539 }
540
541 DOMWindow* DOMWindow::opener() const
542 {
543     if (!m_frame)
544         return 0;
545
546     Frame* opener = m_frame->loader()->opener();
547     if (!opener)
548         return 0;
549
550     return opener->domWindow();
551 }
552
553 DOMWindow* DOMWindow::parent() const
554 {
555     if (!m_frame)
556         return 0;
557
558     Frame* parent = m_frame->tree()->parent();
559     if (parent)
560         return parent->domWindow();
561
562     return m_frame->domWindow();
563 }
564
565 DOMWindow* DOMWindow::top() const
566 {
567     if (!m_frame)
568         return 0;
569
570     Page* page = m_frame->page();
571     if (!page)
572         return 0;
573
574     return page->mainFrame()->domWindow();
575 }
576
577 Document* DOMWindow::document() const
578 {
579     if (!m_frame)
580         return 0;
581
582     ASSERT(m_frame->document());
583     return m_frame->document();
584 }
585
586 PassRefPtr<CSSStyleDeclaration> DOMWindow::getComputedStyle(Element* elt, const String&) const
587 {
588     if (!elt)
589         return 0;
590
591     // FIXME: This needs to work with pseudo elements.
592     return new CSSComputedStyleDeclaration(elt);
593 }
594
595 PassRefPtr<CSSRuleList> DOMWindow::getMatchedCSSRules(Element* elt, const String& pseudoElt, bool authorOnly) const
596 {
597     if (!m_frame)
598         return 0;
599
600     Document* doc = m_frame->document();
601     ASSERT(doc);
602     if (!doc)
603         return 0;
604
605     if (!pseudoElt.isEmpty())
606         return doc->styleSelector()->pseudoStyleRulesForElement(elt, pseudoElt.impl(), authorOnly);
607     return doc->styleSelector()->styleRulesForElement(elt, authorOnly);
608 }
609
610 double DOMWindow::devicePixelRatio() const
611 {
612     if (!m_frame)
613         return 0.0;
614
615     Page* page = m_frame->page();
616     if (!page)
617         return 0.0;
618
619     return page->chrome()->scaleFactor();
620 }
621
622 #if ENABLE(DATABASE)
623 PassRefPtr<Database> DOMWindow::openDatabase(const String& name, const String& version, const String& displayName, unsigned long estimatedSize, ExceptionCode& ec)
624 {
625     if (!m_frame)
626         return 0;
627
628     Document* doc = m_frame->document();
629     ASSERT(doc);
630     if (!doc)
631         return 0;
632
633     return Database::openDatabase(doc, name, version, displayName, estimatedSize, ec);
634 }
635 #endif
636
637 void DOMWindow::scrollBy(int x, int y) const
638 {
639     if (!m_frame)
640         return;
641
642     Document* doc = m_frame->document();
643     ASSERT(doc);
644     if (doc)
645         doc->updateLayoutIgnorePendingStylesheets();
646
647     FrameView* view = m_frame->view();
648     if (!view)
649         return;
650
651     view->scrollBy(x, y);
652 }
653
654 void DOMWindow::scrollTo(int x, int y) const
655 {
656     if (!m_frame)
657         return;
658
659     Document* doc = m_frame->document();
660     ASSERT(doc);
661     if (doc)
662         doc->updateLayoutIgnorePendingStylesheets();
663
664     FrameView* view = m_frame->view();
665     if (!view)
666         return;
667
668     view->setContentsPos(x, y);
669 }
670
671 void DOMWindow::moveBy(float x, float y) const
672 {
673     if (!m_frame)
674         return;
675
676     Page* page = m_frame->page();
677     if (!page)
678         return;
679
680     FloatRect fr = page->chrome()->windowRect();
681     FloatRect update = fr;
682     update.move(x, y);
683     // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
684     adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update);
685     page->chrome()->setWindowRect(fr);
686 }
687
688 void DOMWindow::moveTo(float x, float y) const
689 {
690     if (!m_frame)
691         return;
692
693     Page* page = m_frame->page();
694     if (!page)
695         return;
696
697     FloatRect fr = page->chrome()->windowRect();
698     FloatRect sr = screenAvailableRect(page->mainFrame()->view());
699     fr.setLocation(sr.location());
700     FloatRect update = fr;
701     update.move(x, y);     
702     // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
703     adjustWindowRect(sr, fr, update);
704     page->chrome()->setWindowRect(fr);
705 }
706
707 void DOMWindow::resizeBy(float x, float y) const
708 {
709     if (!m_frame)
710         return;
711
712     Page* page = m_frame->page();
713     if (!page)
714         return;
715
716     FloatRect fr = page->chrome()->windowRect();
717     FloatSize dest = fr.size() + FloatSize(x, y);
718     FloatRect update(fr.location(), dest);
719     adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update);
720     page->chrome()->setWindowRect(fr);
721 }
722
723 void DOMWindow::resizeTo(float width, float height) const
724 {
725     if (!m_frame)
726         return;
727
728     Page* page = m_frame->page();
729     if (!page)
730         return;
731
732     FloatRect fr = page->chrome()->windowRect();
733     FloatSize dest = FloatSize(width, height);
734     FloatRect update(fr.location(), dest);
735     adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update);
736     page->chrome()->setWindowRect(fr);
737 }
738
739 } // namespace WebCore