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