1 /*
2  *  This file is part of the KDE libraries
3  *  Copyright (C) 2000-2003 Harri Porten (porten@kde.org)
4  *  Copyright (C) 2001-2003 David Faure (faure@kde.org)
5  *  Copyright (C) 2003 Apple Computer, Inc.
6  *  Copyright (C) 2006, 2008-2010  Maksim Orlovich (maksim@kde.org)
7  *
8  *  This library is free software; you can redistribute it and/or
9  *  modify it under the terms of the GNU Library General Public
10  *  License as published by the Free Software Foundation; either
11  *  version 2 of the License, or (at your option) any later version.
12  *
13  *  This library is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  *  Library General Public License for more details.
17  *
18  *  You should have received a copy of the GNU Library General Public
19  *  License along with this library; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22 
23 #include "kjs_window.h"
24 #include "kjs_data.h"
25 
26 #include <khtmlview.h>
27 #include <khtml_part.h>
28 #include <khtmlpart_p.h>
29 #include <khtml_settings.h>
30 #include <xml/dom2_eventsimpl.h>
31 #include <xml/dom_docimpl.h>
32 #include <dom/html_document.h>
33 #include <html/html_documentimpl.h>
34 #include <rendering/render_frames.h>
35 
36 #include <config-khtml.h>
37 
38 #include <QTimer>
39 #include <QApplication>
40 #include <QDesktopWidget>
41 #include <qinputdialog.h>
42 #include "khtml_debug.h"
43 #include <kmessagebox.h>
44 #include <klocalizedstring.h>
45 #include <kparts/browserinterface.h>
46 #include <kwindowsystem.h>
47 
48 #ifndef KONQ_EMBEDDED
49 #include <kbookmarkmanager.h>
50 #include <kbookmarkdialog.h>
51 #endif
52 #include <assert.h>
53 #include <QStyle>
54 #include <QTextDocument>
55 #include <kstringhandler.h>
56 
57 #include "kjs_proxy.h"
58 #include "kjs_navigator.h"
59 #include "kjs_mozilla.h"
60 #include "kjs_html.h"
61 #include "kjs_range.h"
62 #include "kjs_traversal.h"
63 #include "kjs_css.h"
64 #include "kjs_events.h"
65 #include "kjs_audio.h"
66 #include "kjs_context2d.h"
67 #include "kjs_xpath.h"
68 #include "kjs_scriptable.h"
69 #include "xmlhttprequest.h"
70 #include "xmlserializer.h"
71 #include "domparser.h"
72 #include "kjs_arraybuffer.h"
73 #include "kjs_arraytyped.h"
74 
75 #include <rendering/render_replaced.h>
76 
77 using namespace KJS;
78 using namespace DOM;
79 
80 namespace KJS
81 {
82 
83 class History : public JSObject
84 {
85     friend class HistoryFunc;
86 public:
History(ExecState * exec,KHTMLPart * p)87     History(ExecState *exec, KHTMLPart *p)
88         : JSObject(exec->lexicalInterpreter()->builtinObjectPrototype()), part(p) { }
89     using KJS::JSObject::getOwnPropertySlot;
90     bool getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot) override;
91     JSValue *getValueProperty(ExecState *exec, int token) const;
classInfo() const92     const ClassInfo *classInfo() const override
93     {
94         return &info;
95     }
96     static const ClassInfo info;
97     enum { Back, Forward, Go, Length };
98 private:
99     QPointer<KHTMLPart> part;
100 };
101 
102 class External : public JSObject
103 {
104     friend class ExternalFunc;
105 public:
External(ExecState * exec,KHTMLPart * p)106     External(ExecState *exec, KHTMLPart *p)
107         : JSObject(exec->lexicalInterpreter()->builtinObjectPrototype()), part(p) { }
108     using KJS::JSObject::getOwnPropertySlot;
109     bool getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot) override;
classInfo() const110     const ClassInfo *classInfo() const override
111     {
112         return &info;
113     }
114     static const ClassInfo info;
115     enum { AddFavorite };
116 private:
117     QPointer<KHTMLPart> part;
118 };
119 } //namespace KJS
120 
121 #include "kjs_window.lut.h"
122 
123 namespace KJS
124 {
125 
126 ////////////////////// Screen Object ////////////////////////
127 
128 // table for screen object
129 /*
130 @begin ScreenTable 7
131   height        Screen::Height      DontEnum|ReadOnly
132   width         Screen::Width       DontEnum|ReadOnly
133   colorDepth    Screen::ColorDepth  DontEnum|ReadOnly
134   pixelDepth    Screen::PixelDepth  DontEnum|ReadOnly
135   availLeft     Screen::AvailLeft   DontEnum|ReadOnly
136   availTop      Screen::AvailTop    DontEnum|ReadOnly
137   availHeight   Screen::AvailHeight DontEnum|ReadOnly
138   availWidth    Screen::AvailWidth  DontEnum|ReadOnly
139 @end
140 */
141 
142 const ClassInfo Screen::info = { "Screen", nullptr, &ScreenTable, nullptr };
143 
144 // We set the object prototype so that toString is implemented
Screen(ExecState * exec)145 Screen::Screen(ExecState *exec)
146     : JSObject(exec->lexicalInterpreter()->builtinObjectPrototype()) {}
147 
getOwnPropertySlot(ExecState * exec,const Identifier & propertyName,PropertySlot & slot)148 bool Screen::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot)
149 {
150 #ifdef KJS_VERBOSE
151     qCDebug(KHTML_LOG) << "Screen::getPropertyName " << propertyName.qstring();
152 #endif
153     return getStaticValueSlot<Screen, JSObject>(exec, &ScreenTable, this, propertyName, slot);
154 }
155 
getValueProperty(ExecState * exec,int token) const156 JSValue *Screen::getValueProperty(ExecState *exec, int token) const
157 {
158     QWidget *thisWidget = Window::retrieveActive(exec)->part()->widget();
159     QRect sg = QApplication::desktop()->screenGeometry(thisWidget);
160 
161     switch (token) {
162     case Height:
163         return jsNumber(sg.height());
164     case Width:
165         return jsNumber(sg.width());
166     case ColorDepth:
167     case PixelDepth:
168         return jsNumber(thisWidget->depth());
169     case AvailLeft: {
170 #if HAVE_X11 && ! defined K_WS_QTONLY
171         QRect clipped = KWindowSystem::workArea().intersected(sg);
172         return jsNumber(clipped.x() - sg.x());
173 #else
174         return jsNumber(10);
175 #endif
176     }
177     case AvailTop: {
178 #if HAVE_X11 && ! defined K_WS_QTONLY
179         QRect clipped = KWindowSystem::workArea().intersected(sg);
180         return jsNumber(clipped.y() - sg.y());
181 #else
182         return jsNumber(10);
183 #endif
184     }
185     case AvailHeight: {
186 #if HAVE_X11 && ! defined K_WS_QTONLY
187         QRect clipped = KWindowSystem::workArea().intersected(sg);
188         return jsNumber(clipped.height());
189 #else
190         return jsNumber(100);
191 #endif
192     }
193     case AvailWidth: {
194 #if HAVE_X11 && ! defined K_WS_QTONLY
195         QRect clipped = KWindowSystem::workArea().intersected(sg);
196         return jsNumber(clipped.width());
197 #else
198         return jsNumber(100);
199 #endif
200     }
201     default:
202         // qCDebug(KHTML_LOG) << "WARNING: Screen::getValueProperty unhandled token " << token;
203         return jsUndefined();
204     }
205 }
206 
207 ////////////////////// Console Object ////////////////////////
208 
209 // table for console object
210 /*
211 @begin ConsoleTable 7
212   assert        Console::Assert     DontEnum|Function 1
213   log           Console::Log        DontEnum|Function 1
214   debug         Console::Debug      DontEnum|Function 1
215   warn          Console::Warn       DontEnum|Function 1
216   error         Console::Error      DontEnum|Function 1
217   info          Console::Info       DontEnum|Function 1
218   clear         Console::Clear      DontEnum|Function 0
219 @end
220 */
221 
222 KJS_IMPLEMENT_PROTOFUNC(ConsoleFunc)
223 
224 const ClassInfo Console::info = { "Console", nullptr, &ConsoleTable, nullptr };
225 
226 // We set the object prototype so that toString is implemented
Console(ExecState * exec)227 Console::Console(ExecState *exec)
228     : JSObject(exec->lexicalInterpreter()->builtinObjectPrototype()) {}
229 
getOwnPropertySlot(ExecState * exec,const Identifier & propertyName,PropertySlot & slot)230 bool Console::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot)
231 {
232 #ifdef KJS_VERBOSE
233     qCDebug(KHTML_LOG) << "Console::getPropertyName " << propertyName.qstring();
234 #endif
235     return getStaticFunctionSlot<ConsoleFunc, JSObject>(exec, &ConsoleTable, this, propertyName, slot);
236 }
237 
printMessage(Console::MessageType msgType,const UString & message)238 void printMessage(Console::MessageType msgType, const UString &message)
239 {
240     const char *type;
241     switch (msgType) {
242     case Console::DebugType:
243         type = "DEBUG";
244         break;
245     case Console::ErrorType:
246         type = "ERROR";
247         break;
248     case Console::InfoType:
249         type = "INFO";
250         break;
251     case Console::LogType:
252         type = "LOG";
253         break;
254     case Console::WarnType:
255         type = "WARN";
256         break;
257 
258     default:
259         type = "UNKNOWN";
260         ASSERT_NOT_REACHED();
261     }
262     // qCDebug(KHTML_LOG) << "[" << type << "]\t" << message.ascii();
263 }
264 
consolePrintf(ExecState * exec,Console::MessageType msgType,const List & args)265 JSValue *consolePrintf(ExecState *exec, Console::MessageType msgType, const List &args)
266 {
267     if (!args[0]->isString()) {
268         return jsUndefined();
269     }
270     UString output = args[0]->toString(exec);
271     if (exec->hadException()) {
272         return jsUndefined();
273     }
274     int size = output.size();
275     int arg = 1;
276     int last = 0;
277     UString composedOutput;
278     for (int i = 0; i < size; ++i) {
279         if (!(output[i] == '%')) {
280             continue;
281         }
282         if (i + 1 >= size) {
283             break;
284         }
285 
286         UString replace;
287         switch (output[i + 1].uc) {
288         case 's': {
289             if (args[arg]->isString()) {
290                 replace = args[arg]->toString(exec);
291                 ++arg;
292             }
293             break;
294         }
295         case 'f':
296         case 'i':
297         case 'd': {
298             if (args[arg]->isNumber()) {
299                 double val = args[arg]->toNumber(exec);
300                 replace = UString::from(val);
301                 ++arg;
302             }
303             break;
304         }
305         case 'o':
306         case 'c':
307             //not yet implemented skip me
308             i += 1;
309             ++arg;
310 
311         default:
312             continue;
313         }
314         if (exec->hadException()) {
315             return jsUndefined();
316         }
317         composedOutput += output.substr(last, i - last);
318         composedOutput += replace;
319         i += 1;
320         last = i + 1;
321     }
322 
323     if (last == 0) { // no % magic used, just copy the original
324         composedOutput = output;
325     } else {
326         composedOutput += output.substr(last);
327     }
328 
329     printMessage(msgType, composedOutput);
330     return jsUndefined();
331 }
332 
callAsFunction(ExecState * exec,JSObject *,const List & args)333 JSValue *ConsoleFunc::callAsFunction(ExecState *exec, JSObject * /*thisObj*/, const List &args)
334 {
335     switch (id) {
336     case Console::Assert: {
337         JSType type = args[0]->type();
338         bool assertFailed = false;
339         switch (type) {
340         case UnspecifiedType:
341         case NullType:
342         case UndefinedType:
343             assertFailed = true;
344             break;
345         case BooleanType:
346             assertFailed = !args[0]->getBoolean();
347             break;
348         case NumberType:
349         case StringType:
350         case ObjectType:
351         case GetterSetterType:
352             assertFailed = false;
353             break;
354         default:
355             assertFailed = true;
356             ASSERT_NOT_REACHED();
357             break;
358         }
359 
360         if (assertFailed) {
361             // ignore further parameter for now..
362             if (args.size() > 1 && args[1]->isString()) {
363                 printMessage(Console::ErrorType, args[1]->getString());
364             } else {
365                 printMessage(Console::ErrorType, "Assert failed!");
366             }
367         }
368         return jsUndefined();
369     }
370     case Console::Log:
371         return consolePrintf(exec, Console::LogType, args);
372     case Console::Debug:
373         return consolePrintf(exec, Console::DebugType, args);
374     case Console::Warn:
375         return consolePrintf(exec, Console::WarnType, args);
376     case Console::Error:
377         return consolePrintf(exec, Console::ErrorType, args);
378     case Console::Info:
379         return consolePrintf(exec, Console::InfoType, args);
380     case Console::Clear:
381         // TODO: clear the console
382         return jsUndefined();
383     }
384     return jsUndefined();
385 }
386 
387 ////////////////////// Window Object ////////////////////////
388 
389 const ClassInfo Window::info = { "Window", &DOMAbstractView::info, &WindowTable, nullptr };
390 
391 /*
392 @begin WindowTable 233
393   atob      Window::AToB        DontDelete|Function 1
394   btoa      Window::BToA        DontDelete|Function 1
395   closed    Window::Closed      DontDelete|ReadOnly
396   crypto    Window::Crypto      DontDelete|ReadOnly
397   defaultStatus Window::DefaultStatus   DontDelete
398   defaultstatus Window::DefaultStatus   DontDelete
399   status    Window::Status      DontDelete
400   document  Window::Document    DontDelete|ReadOnly
401   frameElement      Window::FrameElement        DontDelete|ReadOnly
402   frames    Window::Frames      DontDelete
403   history   Window::_History    DontDelete|ReadOnly
404   external  Window::_External   DontDelete|ReadOnly
405   event     Window::Event       DontDelete|ReadOnly
406   innerHeight   Window::InnerHeight DontDelete|ReadOnly
407   innerWidth    Window::InnerWidth  DontDelete|ReadOnly
408   length    Window::Length      DontDelete
409   location  Window::_Location   DontDelete
410   name      Window::Name        DontDelete
411   navigator Window::_Navigator  DontDelete|ReadOnly
412   clientInformation Window::ClientInformation   DontDelete|ReadOnly
413   konqueror Window::_Konqueror  DontDelete
414   offscreenBuffering    Window::OffscreenBuffering  DontDelete|ReadOnly
415   opener    Window::Opener      DontDelete|ReadOnly
416   outerHeight   Window::OuterHeight DontDelete|ReadOnly
417   outerWidth    Window::OuterWidth  DontDelete|ReadOnly
418   pageXOffset   Window::PageXOffset DontDelete|ReadOnly
419   pageYOffset   Window::PageYOffset DontDelete|ReadOnly
420   parent    Window::Parent      DontDelete
421   personalbar   Window::Personalbar DontDelete
422   screenX   Window::ScreenX     DontDelete|ReadOnly
423   screenY   Window::ScreenY     DontDelete|ReadOnly
424   scrollbars    Window::Scrollbars  DontDelete|ReadOnly
425   scroll    Window::Scroll      DontDelete|Function 2
426   scrollBy  Window::ScrollBy    DontDelete|Function 2
427   scrollTo  Window::ScrollTo    DontDelete|Function 2
428   scrollX       Window::ScrollX         DontDelete|ReadOnly
429   scrollY       Window::ScrollY         DontDelete|ReadOnly
430   moveBy    Window::MoveBy      DontDelete|Function 2
431   moveTo    Window::MoveTo      DontDelete|Function 2
432   postMessage Window::PostMessage DontDelete|Function 2
433   resizeBy  Window::ResizeBy    DontDelete|Function 2
434   resizeTo  Window::ResizeTo    DontDelete|Function 2
435   self      Window::Self        DontDelete|ReadOnly
436   window    Window::_Window     DontDelete|ReadOnly
437   top       Window::Top     DontDelete
438   screen    Window::_Screen     DontDelete|ReadOnly
439   console   Window::_Console        DontDelete|ReadOnly
440   alert     Window::Alert       DontDelete|Function 1
441   confirm   Window::Confirm     DontDelete|Function 1
442   prompt    Window::Prompt      DontDelete|Function 2
443   open      Window::Open        DontDelete|Function 3
444   setTimeout    Window::SetTimeout  DontDelete|Function 2
445   clearTimeout  Window::ClearTimeout    DontDelete|Function 1
446   focus     Window::Focus       DontDelete|Function 0
447   blur      Window::Blur        DontDelete|Function 0
448   close     Window::Close       DontDelete|Function 0
449   setInterval   Window::SetInterval DontDelete|Function 2
450   clearInterval Window::ClearInterval   DontDelete|Function 1
451   captureEvents Window::CaptureEvents   DontDelete|Function 0
452   releaseEvents Window::ReleaseEvents   DontDelete|Function 0
453   print     Window::Print       DontDelete|Function 0
454   addEventListener  Window::AddEventListener    DontDelete|Function 3
455   removeEventListener   Window::RemoveEventListener DontDelete|Function 3
456   getSelection  Window::GetSelection            DontDelete|Function 0
457 # Normally found in prototype. Add to window object itself to make them
458 # accessible in closed and cross-site windows
459   valueOf       Window::ValueOf     DontEnum|DontDelete|Function 0
460   toString      Window::ToString    DontEnum|DontDelete|Function 0
461 # IE extension
462   navigate  Window::Navigate    DontDelete|Function 1
463 # Mozilla extension
464   sidebar   Window::SideBar     DontDelete|DontEnum
465   getComputedStyle  Window::GetComputedStyle    DontDelete|Function 2
466 
467 # Warning, when adding a function to this object you need to add a case in Window::get
468 
469 # Event handlers
470 # IE also has: onactivate, onbefore/afterprint, onbeforedeactivate/unload, oncontrolselect,
471 # ondeactivate, onhelp, onmovestart/end, onresizestart/end.
472 # It doesn't have onabort, onchange, ondragdrop (but NS has that last one).
473   onabort   Window::Onabort     DontDelete
474   onblur    Window::Onblur      DontDelete
475   onchange  Window::Onchange    DontDelete
476   onclick   Window::Onclick     DontDelete
477   ondblclick    Window::Ondblclick  DontDelete
478   ondragdrop    Window::Ondragdrop  DontDelete
479   onerror   Window::Onerror     DontDelete
480   onfocus   Window::Onfocus     DontDelete
481   onkeydown Window::Onkeydown   DontDelete
482   onkeypress    Window::Onkeypress  DontDelete
483   onkeyup   Window::Onkeyup     DontDelete
484   onload    Window::Onload      DontDelete
485   onmessage   Window::Onmessage DontDelete
486   onmousedown   Window::Onmousedown DontDelete
487   onmousemove   Window::Onmousemove DontDelete
488   onmouseout    Window::Onmouseout  DontDelete
489   onmouseover   Window::Onmouseover DontDelete
490   onmouseup Window::Onmouseup   DontDelete
491   onmove    Window::Onmove      DontDelete
492   onreset   Window::Onreset     DontDelete
493   onresize  Window::Onresize    DontDelete
494   onscroll      Window::Onscroll        DontDelete
495   onselect  Window::Onselect    DontDelete
496   onsubmit  Window::Onsubmit    DontDelete
497   onunload  Window::Onunload    DontDelete
498   onhashchange  Window::Onhashchange    DontDelete
499 
500 # Constructors/constant tables
501   Node      Window::Node        DontEnum|DontDelete
502   Event     Window::EventCtor   DontEnum|DontDelete
503   Range     Window::Range       DontEnum|DontDelete
504   NodeFilter    Window::NodeFilter  DontEnum|DontDelete
505   NodeList  Window::NodeList    DontEnum|DontDelete
506   DOMException  Window::DOMException    DontEnum|DontDelete
507   RangeException Window::RangeException DontEnum|DontDelete
508   CSSRule   Window::CSSRule     DontEnum|DontDelete
509   MutationEvent Window::MutationEventCtor   DontEnum|DontDelete
510   MessageEvent Window::MessageEventCtor   DontEnum|DontDelete
511   KeyboardEvent Window::KeyboardEventCtor   DontEnum|DontDelete
512   EventException Window::EventExceptionCtor DontEnum|DontDelete
513   HashChangeEvent Window::HashChangeEventCtor DontEnum|DontDelete
514   Audio     Window::Audio       DontEnum|DontDelete
515   Image     Window::Image       DontEnum|DontDelete
516   Option    Window::Option      DontEnum|DontDelete
517   XMLHttpRequest Window::XMLHttpRequest DontEnum|DontDelete
518   XMLSerializer Window::XMLSerializer   DontEnum|DontDelete
519   DOMParser Window::DOMParser   DontEnum|DontDelete
520   ArrayBuffer   Window::ArrayBuffer   DontEnum|DontDelete
521   Int8Array     Window::Int8Array     DontEnum|DontDelete
522   Uint8Array    Window::Uint8Array    DontEnum|DontDelete
523   Int16Array    Window::Int16Array    DontEnum|DontDelete
524   Uint16Array   Window::Uint16Array   DontEnum|DontDelete
525   Int32Array    Window::Int32Array    DontEnum|DontDelete
526   Uint32Array   Window::Uint32Array   DontEnum|DontDelete
527   Float32Array  Window::Float32Array  DontEnum|DontDelete
528   Float64Array  Window::Float64Array  DontEnum|DontDelete
529 
530 # Mozilla dom emulation ones.
531   Element   Window::ElementCtor DontEnum|DontDelete
532   Document  Window::DocumentCtor DontEnum|DontDelete
533   DocumentFragment Window::DocumentFragmentCtor DontEnum|DontDelete
534   #this one is an alias since we don't have a separate XMLDocument
535   XMLDocument Window::DocumentCtor DontEnum|DontDelete
536   HTMLElement  Window::HTMLElementCtor DontEnum|DontDelete
537   HTMLDocument  Window::HTMLDocumentCtor DontEnum|DontDelete
538   HTMLHtmlElement Window::HTMLHtmlElementCtor DontEnum|DontDelete
539   HTMLHeadElement Window::HTMLHeadElementCtor DontEnum|DontDelete
540   HTMLLinkElement Window::HTMLLinkElementCtor DontEnum|DontDelete
541   HTMLTitleElement Window::HTMLTitleElementCtor DontEnum|DontDelete
542   HTMLMetaElement Window::HTMLMetaElementCtor DontEnum|DontDelete
543   HTMLBaseElement Window::HTMLBaseElementCtor DontEnum|DontDelete
544   HTMLIsIndexElement Window::HTMLIsIndexElementCtor DontEnum|DontDelete
545   HTMLStyleElement Window::HTMLStyleElementCtor DontEnum|DontDelete
546   HTMLBodyElement Window::HTMLBodyElementCtor DontEnum|DontDelete
547   HTMLFormElement Window::HTMLFormElementCtor DontEnum|DontDelete
548   HTMLSelectElement Window::HTMLSelectElementCtor DontEnum|DontDelete
549   HTMLOptGroupElement Window::HTMLOptGroupElementCtor DontEnum|DontDelete
550   HTMLOptionElement Window::HTMLOptionElementCtor DontEnum|DontDelete
551   HTMLInputElement Window::HTMLInputElementCtor DontEnum|DontDelete
552   HTMLTextAreaElement Window::HTMLTextAreaElementCtor DontEnum|DontDelete
553   HTMLButtonElement Window::HTMLButtonElementCtor DontEnum|DontDelete
554   HTMLLabelElement Window::HTMLLabelElementCtor DontEnum|DontDelete
555   HTMLFieldSetElement Window::HTMLFieldSetElementCtor DontEnum|DontDelete
556   HTMLLegendElement Window::HTMLLegendElementCtor DontEnum|DontDelete
557   HTMLUListElement Window::HTMLUListElementCtor DontEnum|DontDelete
558   HTMLOListElement Window::HTMLOListElementCtor DontEnum|DontDelete
559   HTMLDListElement Window::HTMLDListElementCtor DontEnum|DontDelete
560   HTMLDirectoryElement Window::HTMLDirectoryElementCtor DontEnum|DontDelete
561   HTMLMenuElement Window::HTMLMenuElementCtor DontEnum|DontDelete
562   HTMLLIElement Window::HTMLLIElementCtor DontEnum|DontDelete
563   HTMLDivElement Window::HTMLDivElementCtor DontEnum|DontDelete
564   HTMLParagraphElement Window::HTMLParagraphElementCtor DontEnum|DontDelete
565   HTMLHeadingElement Window::HTMLHeadingElementCtor DontEnum|DontDelete
566   HTMLBlockQuoteElement Window::HTMLBlockQuoteElementCtor DontEnum|DontDelete
567   HTMLQuoteElement Window::HTMLQuoteElementCtor DontEnum|DontDelete
568   HTMLPreElement Window::HTMLPreElementCtor DontEnum|DontDelete
569   HTMLBRElement Window::HTMLBRElementCtor DontEnum|DontDelete
570   HTMLBaseFontElement Window::HTMLBaseFontElementCtor DontEnum|DontDelete
571   HTMLFontElement Window::HTMLFontElementCtor DontEnum|DontDelete
572   HTMLHRElement Window::HTMLHRElementCtor DontEnum|DontDelete
573   HTMLModElement Window::HTMLModElementCtor DontEnum|DontDelete
574   HTMLAnchorElement Window::HTMLAnchorElementCtor DontEnum|DontDelete
575   HTMLImageElement Window::HTMLImageElementCtor DontEnum|DontDelete
576   HTMLObjectElement Window::HTMLObjectElementCtor DontEnum|DontDelete
577   HTMLParamElement Window::HTMLParamElementCtor DontEnum|DontDelete
578   HTMLAppletElement Window::HTMLAppletElementCtor DontEnum|DontDelete
579   HTMLMapElement Window::HTMLMapElementCtor DontEnum|DontDelete
580   HTMLAreaElement Window::HTMLAreaElementCtor DontEnum|DontDelete
581   HTMLScriptElement Window::HTMLScriptElementCtor DontEnum|DontDelete
582   HTMLTableElement Window::HTMLTableElementCtor DontEnum|DontDelete
583   HTMLTableCaptionElement Window::HTMLTableCaptionElementCtor DontEnum|DontDelete
584   HTMLTableColElement Window::HTMLTableColElementCtor DontEnum|DontDelete
585   HTMLTableSectionElement Window::HTMLTableSectionElementCtor DontEnum|DontDelete
586   HTMLTableRowElement Window::HTMLTableRowElementCtor DontEnum|DontDelete
587   HTMLTableCellElement Window::HTMLTableCellElementCtor DontEnum|DontDelete
588   HTMLFrameSetElement Window::HTMLFrameSetElementCtor DontEnum|DontDelete
589   HTMLLayerElement Window::HTMLLayerElementCtor DontEnum|DontDelete
590   HTMLFrameElement Window::HTMLFrameElementCtor DontEnum|DontDelete
591   HTMLIFrameElement Window::HTMLIFrameElementCtor DontEnum|DontDelete
592   HTMLCollection Window::HTMLCollectionCtor DontEnum|DontDelete
593   HTMLCanvasElement Window::HTMLCanvasElementCtor DontEnum|DontDelete
594   CSSStyleDeclaration Window::CSSStyleDeclarationCtor DontEnum|DontDelete
595   StyleSheet   Window::StyleSheetCtor DontEnum|DontDelete
596   CanvasRenderingContext2D Window::Context2DCtor DontEnum|DontDelete
597   SVGAngle Window::SVGAngleCtor DontEnum|DontDelete
598   XPathResult Window::XPathResultCtor DontEnum|DontDelete
599   XPathExpression Window::XPathExpressionCtor DontEnum|DontDelete
600   XPathNSResolver Window::XPathNSResolverCtor DontEnum|DontDelete
601 @end
602 */
KJS_IMPLEMENT_PROTOFUNC(WindowFunc)603 KJS_IMPLEMENT_PROTOFUNC(WindowFunc)
604 
605 Window::Window(khtml::ChildFrame *p)
606     : JSGlobalObject(/*no proto*/), m_frame(p), screen(nullptr), console(nullptr), history(nullptr), external(nullptr), loc(nullptr), m_evt(nullptr)
607 {
608     winq = new WindowQObject(this);
609     //qCDebug(KHTML_LOG) << "Window::Window this=" << this << " part=" << m_part << " " << m_part->name();
610 }
611 
~Window()612 Window::~Window()
613 {
614     qDeleteAll(m_delayed);
615     delete winq;
616 }
617 
retrieveWindow(KParts::ReadOnlyPart * p)618 Window *Window::retrieveWindow(KParts::ReadOnlyPart *p)
619 {
620     JSObject *obj = retrieve(p)->getObject();
621 #ifndef NDEBUG
622     // obj should never be null, except when javascript has been disabled in that part.
623     KHTMLPart *part = qobject_cast<KHTMLPart *>(p);
624     if (part && part->jScriptEnabled()) {
625         assert(obj);
626         assert(dynamic_cast<KJS::Window *>(obj));  // type checking
627     }
628 #endif
629     if (!obj) { // JS disabled
630         return nullptr;
631     }
632     return static_cast<KJS::Window *>(obj);
633 }
634 
retrieveActive(ExecState * exec)635 Window *Window::retrieveActive(ExecState *exec)
636 {
637     JSValue *imp = exec->dynamicInterpreter()->globalObject();
638     assert(imp);
639     assert(dynamic_cast<KJS::Window *>(imp));
640     return static_cast<KJS::Window *>(imp);
641 }
642 
retrieve(KParts::ReadOnlyPart * p)643 JSValue *Window::retrieve(KParts::ReadOnlyPart *p)
644 {
645     assert(p);
646     KHTMLPart *part = qobject_cast<KHTMLPart *>(p);
647     KJSProxy *proxy = nullptr;
648     if (!part) {
649         part = qobject_cast<KHTMLPart *>(p->parent());
650         if (part) {
651             proxy = part->framejScript(p);
652         }
653     } else {
654         proxy = part->jScript();
655     }
656     if (proxy) {
657 #ifdef KJS_VERBOSE
658         qCDebug(KHTML_LOG) << "Window::retrieve part=" << part << " '" << part->objectName() << "' interpreter=" << proxy->interpreter() << " window=" << proxy->interpreter()->globalObject();
659 #endif
660         return proxy->interpreter()->globalObject(); // the Global object is the "window"
661     } else {
662 #ifdef KJS_VERBOSE
663         qCDebug(KHTML_LOG) << "Window::retrieve part=" << p << " '" << p->objectName() << "' no jsproxy.";
664 #endif
665         return jsUndefined(); // This can happen with JS disabled on the domain of that window
666     }
667 }
668 
location() const669 Location *Window::location() const
670 {
671     if (!loc) {
672         const_cast<Window *>(this)->loc = new Location(m_frame);
673     }
674     return loc;
675 }
676 
677 // reference our special objects during garbage collection
mark()678 void Window::mark()
679 {
680     JSObject::mark();
681     if (screen && !screen->marked()) {
682         screen->mark();
683     }
684     if (console && !console->marked()) {
685         console->mark();
686     }
687     if (history && !history->marked()) {
688         history->mark();
689     }
690     if (external && !external->marked()) {
691         external->mark();
692     }
693     //qCDebug(KHTML_LOG) << "Window::mark " << this << " marking loc=" << loc;
694     if (loc && !loc->marked()) {
695         loc->mark();
696     }
697     if (winq) {
698         winq->mark();
699     }
700     foreach (DelayedAction *action, m_delayed) {
701         action->mark();
702     }
703 }
704 
toString(ExecState *) const705 UString Window::toString(ExecState *) const
706 {
707     return "[object Window]";
708 }
709 
isCrossFrameAccessible(int token) const710 bool Window::isCrossFrameAccessible(int token) const
711 {
712     switch (token) {
713     case Closed:
714     case _Location: // No isSafeScript test here, we must be able to _set_ location.href (#49819)
715     case _Window:
716     case Self:
717     case Frames:
718     case Opener:
719     case Parent:
720     case Top:
721     case Alert:
722     case Confirm:
723     case Prompt:
724     case Open:
725     case Close:
726     case Focus:
727     case Blur:
728     case AToB:
729     case BToA:
730     case ValueOf:
731     case ToString:
732     case PostMessage:
733         return true;
734     default:
735         return false;
736     }
737 }
738 
getOwnPropertySlot(ExecState * exec,const Identifier & propertyName,PropertySlot & slot)739 bool Window::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot)
740 {
741 #ifdef KJS_VERBOSE
742     qCDebug(KHTML_LOG) << "Window(" << this << ")::getOwnPropertySlot " << propertyName.qstring();
743 #endif
744 
745     // we want only limited operations on a closed window
746     if (m_frame.isNull() || m_frame->m_part.isNull()) {
747         const HashEntry *entry = Lookup::findEntry(&WindowTable, propertyName);
748         if (entry) {
749             switch (entry->value) {
750             case Closed:
751             case _Location:
752             case ValueOf:
753             case ToString:
754                 getSlotFromEntry<WindowFunc, Window>(entry, this, slot);
755                 return true;
756             default:
757                 break;
758             }
759         }
760         slot.setUndefined(this);
761         return true;
762     }
763 
764     bool safe = isSafeScript(exec);
765 
766     // Look for overrides first.
767     JSValue **val = getDirectLocation(propertyName);
768     if (val) {
769         if (safe) {
770             fillDirectLocationSlot(slot, val);
771         } else {
772             // We may need to permit access to the property map cross-frame in
773             // order to pick up cross-frame accessible functions that got
774             // cached as direct properties.
775             const HashEntry *entry = Lookup::findEntry(&WindowTable, propertyName);
776             if (entry && isCrossFrameAccessible(entry->value)) {
777                 fillDirectLocationSlot(slot, val);
778             } else {
779                 slot.setUndefined(this);
780             }
781         }
782         return true;
783     }
784 
785     // The only stuff we permit XSS (besides cached things above) are
786     // a few of hashtable properties.
787     const HashEntry *entry = Lookup::findEntry(&WindowTable, propertyName);
788     if (!safe && (!entry || !isCrossFrameAccessible(entry->value))) {
789         slot.setUndefined(this);
790         return true;
791     }
792 
793     // invariant: accesses below this point are permitted by the XSS policy
794 
795     KHTMLPart *part = qobject_cast<KHTMLPart *>(m_frame->m_part.data());
796 
797     if (entry) {
798         // Things that work on any ReadOnlyPart first
799         switch (entry->value) {
800         case Closed:
801         case _Location:
802         case _Window:
803         case Self:
804             getSlotFromEntry<WindowFunc, Window>(entry, this, slot);
805             return true;
806         default:
807             break;
808         }
809 
810         if (!part) {
811             slot.setUndefined(this);
812             return true;
813         }
814 
815         // KHTMLPart-specific next.
816 
817         // Disabled in NS-compat mode. Supported by default - can't hurt, unless someone uses
818         // if (navigate) to test for IE (unlikely).
819         if (entry->value == Navigate && exec->dynamicInterpreter()->compatMode() == Interpreter::NetscapeCompat) {
820             slot.setUndefined(this);
821             return true;
822         }
823 
824         getSlotFromEntry<WindowFunc, Window>(entry, this, slot);
825         return true;
826     }
827 
828     if (!part) {
829         // not a  KHTMLPart, so try to get plugin scripting stuff
830         if (pluginRootGet(exec, m_frame->m_scriptable.data(), propertyName, slot)) {
831             return true;
832         }
833 
834         slot.setUndefined(this);
835         return true;
836     }
837 
838     // Now do frame indexing.
839     KParts::ReadOnlyPart *rop = part->findFramePart(propertyName.qstring());
840     if (rop) {
841         slot.setCustom(this, framePartGetter);
842         return true;
843     }
844 
845     // allow window[1] or parent[1] etc. (#56983)
846     bool ok;
847     unsigned int i = propertyName.toArrayIndex(&ok);
848     if (ok && frameByIndex(i)) {
849         slot.setCustomIndex(this, i, indexGetterAdapter<Window>);
850         return true;
851     }
852 
853     // allow shortcuts like 'Image1' instead of document.images.Image1
854     DOM::DocumentImpl *doc = part->xmlDocImpl();
855     if (doc && doc->isHTMLDocument()) {
856         DOM::ElementMappingCache::ItemInfo *info = doc->underDocNamedCache().get(propertyName.domString());
857         if (info || doc->getElementById(propertyName.domString())) {
858             slot.setCustom(this, namedItemGetter);
859             return true;
860         }
861     }
862 
863     // This isn't necessarily a bug. Some code uses if(!window.blah) window.blah=1
864     // But it can also mean something isn't loaded or implemented, hence the WARNING to help grepping.
865 #ifdef KJS_VERBOSE
866     qCDebug(KHTML_LOG) << "WARNING: Window::get property not found: " << propertyName.qstring();
867 #endif
868 
869     return JSObject::getOwnPropertySlot(exec, propertyName, slot);
870 }
871 
frameByIndex(unsigned i)872 KParts::ReadOnlyPart *Window::frameByIndex(unsigned i)
873 {
874     KHTMLPart *part = qobject_cast<KHTMLPart *>(m_frame->m_part);
875     QList<KParts::ReadOnlyPart *> frames = part->frames();
876     unsigned int len = frames.count();
877     if (i < len) {
878         KParts::ReadOnlyPart *frame = frames.at(i);
879         return frame;
880     }
881     return nullptr;
882 }
883 
indexGetter(ExecState * exec,unsigned index)884 JSValue *Window::indexGetter(ExecState *exec, unsigned index)
885 {
886     Q_UNUSED(exec);
887     KParts::ReadOnlyPart *frame = frameByIndex(index);
888     if (frame) {
889         return Window::retrieve(frame);
890     }
891     return jsUndefined(); //### ?
892 }
893 
framePartGetter(ExecState * exec,JSObject *,const Identifier & propertyName,const PropertySlot & slot)894 JSValue *Window::framePartGetter(ExecState *exec, JSObject *, const Identifier &propertyName, const PropertySlot &slot)
895 {
896     Q_UNUSED(exec);
897     Window *thisObj = static_cast<Window *>(slot.slotBase());
898     KHTMLPart *part = qobject_cast<KHTMLPart *>(thisObj->m_frame->m_part);
899     KParts::ReadOnlyPart *rop = part->findFramePart(propertyName.qstring());
900     return thisObj->retrieve(rop);
901 }
902 
namedItemGetter(ExecState * exec,JSObject *,const Identifier & p,const PropertySlot & slot)903 JSValue *Window::namedItemGetter(ExecState *exec, JSObject *, const Identifier &p, const PropertySlot &slot)
904 {
905     Window *thisObj = static_cast<Window *>(slot.slotBase());
906     KHTMLPart *part = qobject_cast<KHTMLPart *>(thisObj->m_frame->m_part);
907     DOM::DocumentImpl *doc = part->xmlDocImpl();
908 
909     DOM::ElementMappingCache::ItemInfo *info = doc->underDocNamedCache().get(p.domString());
910     if (info) {
911         if (info->nd) {
912             return getDOMNode(exec, info->nd);
913         } else {
914             //No cached mapping, do it by hand...
915             DOM::HTMLMappedNameCollectionImpl *coll = new DOM::HTMLMappedNameCollectionImpl(doc,
916                     DOM::HTMLCollectionImpl::DOCUMENT_NAMED_ITEMS, p.domString());
917 
918             if (coll->length() == 1) {
919                 info->nd = static_cast<DOM::ElementImpl *>(coll->firstItem());
920                 delete coll;
921                 return getDOMNode(exec, info->nd);
922             }
923             return getHTMLCollection(exec, coll);
924         }
925     }
926 
927     DOM::ElementImpl *element = doc->getElementById(p.domString());
928     return getDOMNode(exec, element);
929 }
930 
getValueProperty(ExecState * exec,int token)931 JSValue *Window::getValueProperty(ExecState *exec, int token)
932 {
933     KHTMLPart *part = m_frame.isNull() ? nullptr : qobject_cast<KHTMLPart *>(m_frame->m_part);
934     if (!part) {
935         switch (token) {
936         case Closed:
937             return jsBoolean(true);
938         case _Location:
939             return jsNull();
940         default:
941             return jsUndefined();
942         }
943     }
944 
945     switch (token) {
946     case Closed:
947         return jsBoolean(!part);
948     case _Location:
949         // No isSafeScript test here, we must be able to _set_ location.href (#49819)
950         return location();
951     case _Window:
952     case Self:
953         return retrieve(part);
954     case Frames:
955         return this;
956     case Opener:
957         if (!part->opener()) {
958             return jsNull();    // ### a null Window might be better, but == null
959         } else {            // doesn't work yet
960             return retrieve(part->opener());
961         }
962     case Parent:
963         return retrieve(part && part->parentPart() ? part->parentPart() : (KHTMLPart *)part);
964     case Top: {
965         KHTMLPart *p = part;
966         while (p->parentPart()) {
967             p = p->parentPart();
968         }
969         return retrieve(p);
970     }
971     case Crypto:
972         return jsUndefined(); // ###
973     case DefaultStatus:
974         return jsString(UString(part->jsDefaultStatusBarText()));
975     case Status:
976         return jsString(UString(part->jsStatusBarText()));
977     case Document:
978         return getDOMNode(exec, part->xmlDocImpl());
979     case FrameElement:
980         if (m_frame->m_partContainerElement) {
981             return getDOMNode(exec, m_frame->m_partContainerElement.data());
982         } else {
983             return jsUndefined();
984         }
985     case Node:
986         return NodeConstructor::self(exec);
987     case Range:
988         return getRangeConstructor(exec);
989     case NodeFilter:
990         return getNodeFilterConstructor(exec);
991     case NodeList:
992         return NodeListPseudoCtor::self(exec);
993     case DOMException:
994         return getDOMExceptionConstructor(exec);
995     case RangeException:
996         return RangeExceptionPseudoCtor::self(exec);
997     case CSSRule:
998         return getCSSRuleConstructor(exec);
999     case ElementCtor:
1000         return ElementPseudoCtor::self(exec);
1001     case DocumentFragmentCtor:
1002         return DocumentFragmentPseudoCtor::self(exec);
1003     case HTMLElementCtor:
1004         return HTMLElementPseudoCtor::self(exec);
1005     case HTMLHtmlElementCtor:
1006         return HTMLHtmlElementPseudoCtor::self(exec);
1007     case HTMLHeadElementCtor:
1008         return HTMLHeadElementPseudoCtor::self(exec);
1009     case HTMLLinkElementCtor:
1010         return HTMLLinkElementPseudoCtor::self(exec);
1011     case HTMLTitleElementCtor:
1012         return HTMLTitleElementPseudoCtor::self(exec);
1013     case HTMLMetaElementCtor:
1014         return HTMLMetaElementPseudoCtor::self(exec);
1015     case HTMLBaseElementCtor:
1016         return HTMLBaseElementPseudoCtor::self(exec);
1017     case HTMLIsIndexElementCtor:
1018         return HTMLIsIndexElementPseudoCtor::self(exec);
1019     case HTMLStyleElementCtor:
1020         return HTMLStyleElementPseudoCtor::self(exec);
1021     case HTMLBodyElementCtor:
1022         return HTMLBodyElementPseudoCtor::self(exec);
1023     case HTMLFormElementCtor:
1024         return HTMLFormElementPseudoCtor::self(exec);
1025     case HTMLSelectElementCtor:
1026         return HTMLSelectElementPseudoCtor::self(exec);
1027     case HTMLOptGroupElementCtor:
1028         return HTMLOptGroupElementPseudoCtor::self(exec);
1029     case HTMLOptionElementCtor:
1030         return HTMLOptionElementPseudoCtor::self(exec);
1031     case HTMLInputElementCtor:
1032         return HTMLInputElementPseudoCtor::self(exec);
1033     case HTMLTextAreaElementCtor:
1034         return HTMLTextAreaElementPseudoCtor::self(exec);
1035     case HTMLButtonElementCtor:
1036         return HTMLButtonElementPseudoCtor::self(exec);
1037     case HTMLLabelElementCtor:
1038         return HTMLLabelElementPseudoCtor::self(exec);
1039     case HTMLFieldSetElementCtor:
1040         return HTMLFieldSetElementPseudoCtor::self(exec);
1041     case HTMLLegendElementCtor:
1042         return HTMLLegendElementPseudoCtor::self(exec);
1043     case HTMLUListElementCtor:
1044         return HTMLUListElementPseudoCtor::self(exec);
1045     case HTMLOListElementCtor:
1046         return HTMLOListElementPseudoCtor::self(exec);
1047     case HTMLDListElementCtor:
1048         return HTMLDListElementPseudoCtor::self(exec);
1049     case HTMLDirectoryElementCtor:
1050         return HTMLDirectoryElementPseudoCtor::self(exec);
1051     case HTMLMenuElementCtor:
1052         return HTMLMenuElementPseudoCtor::self(exec);
1053     case HTMLLIElementCtor:
1054         return HTMLLIElementPseudoCtor::self(exec);
1055     case HTMLDivElementCtor:
1056         return HTMLDivElementPseudoCtor::self(exec);
1057     case HTMLParagraphElementCtor:
1058         return HTMLParagraphElementPseudoCtor::self(exec);
1059     case HTMLHeadingElementCtor:
1060         return HTMLHeadingElementPseudoCtor::self(exec);
1061     case HTMLBlockQuoteElementCtor:
1062         return HTMLBlockQuoteElementPseudoCtor::self(exec);
1063     case HTMLQuoteElementCtor:
1064         return HTMLQuoteElementPseudoCtor::self(exec);
1065     case HTMLPreElementCtor:
1066         return HTMLPreElementPseudoCtor::self(exec);
1067     case HTMLBRElementCtor:
1068         return HTMLBRElementPseudoCtor::self(exec);
1069     case HTMLBaseFontElementCtor:
1070         return HTMLBaseFontElementPseudoCtor::self(exec);
1071     case HTMLFontElementCtor:
1072         return HTMLFontElementPseudoCtor::self(exec);
1073     case HTMLHRElementCtor:
1074         return HTMLHRElementPseudoCtor::self(exec);
1075     case HTMLModElementCtor:
1076         return HTMLModElementPseudoCtor::self(exec);
1077     case HTMLAnchorElementCtor:
1078         return HTMLAnchorElementPseudoCtor::self(exec);
1079     case HTMLImageElementCtor:
1080         return HTMLImageElementPseudoCtor::self(exec);
1081     case HTMLObjectElementCtor:
1082         return HTMLObjectElementPseudoCtor::self(exec);
1083     case HTMLParamElementCtor:
1084         return HTMLParamElementPseudoCtor::self(exec);
1085     case HTMLAppletElementCtor:
1086         return HTMLAppletElementPseudoCtor::self(exec);
1087     case HTMLMapElementCtor:
1088         return HTMLMapElementPseudoCtor::self(exec);
1089     case HTMLAreaElementCtor:
1090         return HTMLAreaElementPseudoCtor::self(exec);
1091     case HTMLScriptElementCtor:
1092         return HTMLScriptElementPseudoCtor::self(exec);
1093     case HTMLTableElementCtor:
1094         return HTMLTableElementPseudoCtor::self(exec);
1095     case HTMLTableCaptionElementCtor:
1096         return HTMLTableCaptionElementPseudoCtor::self(exec);
1097     case HTMLTableColElementCtor:
1098         return HTMLTableColElementPseudoCtor::self(exec);
1099     case HTMLTableSectionElementCtor:
1100         return HTMLTableSectionElementPseudoCtor::self(exec);
1101     case HTMLTableRowElementCtor:
1102         return HTMLTableRowElementPseudoCtor::self(exec);
1103     case HTMLTableCellElementCtor:
1104         return HTMLTableCellElementPseudoCtor::self(exec);
1105     case HTMLFrameSetElementCtor:
1106         return HTMLFrameSetElementPseudoCtor::self(exec);
1107     case HTMLLayerElementCtor:
1108         return HTMLLayerElementPseudoCtor::self(exec);
1109     case HTMLFrameElementCtor:
1110         return HTMLFrameElementPseudoCtor::self(exec);
1111     case HTMLIFrameElementCtor:
1112         return HTMLIFrameElementPseudoCtor::self(exec);
1113     case HTMLCollectionCtor:
1114         return HTMLCollectionPseudoCtor::self(exec);
1115     case HTMLCanvasElementCtor:
1116         return HTMLCanvasElementPseudoCtor::self(exec);
1117     case Context2DCtor:
1118         return Context2DPseudoCtor::self(exec);
1119     case SVGAngleCtor:
1120         return SVGAnglePseudoCtor::self(exec);
1121     case XPathResultCtor:
1122         return XPathResultPseudoCtor::self(exec);
1123     case XPathExpressionCtor:
1124         return XPathExpressionPseudoCtor::self(exec);
1125     case XPathNSResolverCtor:
1126         return XPathNSResolverPseudoCtor::self(exec);
1127     case DocumentCtor:
1128         return DocumentPseudoCtor::self(exec);
1129     case HTMLDocumentCtor:
1130         return HTMLDocumentPseudoCtor::self(exec);
1131     case CSSStyleDeclarationCtor:
1132         return CSSStyleDeclarationPseudoCtor::self(exec);
1133     case StyleSheetCtor:
1134         return DOMStyleSheetPseudoCtor::self(exec);
1135     case EventCtor:
1136         return EventConstructor::self(exec);
1137     case MessageEventCtor:
1138         return MessageEventPseudoCtor::self(exec);
1139     case HashChangeEventCtor:
1140         return HashChangeEventPseudoCtor::self(exec);
1141     case MutationEventCtor:
1142         return getMutationEventConstructor(exec);
1143     case KeyboardEventCtor:
1144         return getKeyboardEventConstructor(exec);
1145     case EventExceptionCtor:
1146         return getEventExceptionConstructor(exec);
1147     case _History:
1148         return history ? history :
1149                (const_cast<Window *>(this)->history = new History(exec, part));
1150 
1151     case _External:
1152         return external ? external :
1153                (const_cast<Window *>(this)->external = new External(exec, part));
1154 
1155     case Event:
1156         if (m_evt) {
1157             return getDOMEvent(exec, m_evt);
1158         } else {
1159 #ifdef KJS_VERBOSE
1160             qCDebug(KHTML_LOG) << "WARNING: window(" << this << "," << part->objectName() << ").event, no event!";
1161 #endif
1162             return jsUndefined();
1163         }
1164     case InnerHeight: {
1165         if (!part->view()) {
1166             return jsUndefined();
1167         }
1168         int ret = part->view()->visibleHeight();
1169         // match Gecko which does not subtract the scrollbars
1170         if (part->view()->horizontalScrollBar()->isVisible()) {
1171             ret += part->view()->horizontalScrollBar()->sizeHint().height();
1172         }
1173         return jsNumber(ret);
1174     }
1175     case InnerWidth: {
1176         if (!part->view()) {
1177             return jsUndefined();
1178         }
1179         int ret = part->view()->visibleWidth();
1180         // match Gecko which does not subtract the scrollbars
1181         if (part->view()->verticalScrollBar()->isVisible()) {
1182             ret += part->view()->verticalScrollBar()->sizeHint().width();
1183         }
1184         return jsNumber(ret);
1185     }
1186     case Length:
1187         return jsNumber(part->frames().count());
1188     case Name:
1189         return jsString(part->objectName());
1190     case SideBar:
1191         return new MozillaSidebarExtension(exec, part);
1192     case _Navigator:
1193     case ClientInformation: {
1194         // Store the navigator in the object so we get the same one each time.
1195         JSValue *nav(new Navigator(exec, part));
1196         const_cast<Window *>(this)->put(exec, "navigator", nav, DontDelete | ReadOnly | Internal);
1197         const_cast<Window *>(this)->put(exec, "clientInformation", nav, DontDelete | ReadOnly | Internal);
1198         return nav;
1199     }
1200 
1201     case OffscreenBuffering:
1202         return jsBoolean(true);
1203     case OuterHeight:
1204     case OuterWidth: {
1205 #if HAVE_X11 && ! defined K_WS_QTONLY
1206         if (!part->widget()) {
1207             return jsNumber(0);
1208         }
1209         const KWindowInfo inf(part->widget()->topLevelWidget()->winId(), NET::WMGeometry);
1210         return jsNumber(token == OuterHeight ?
1211                         inf.geometry().height() : inf.geometry().width());
1212 #else
1213         return jsNumber(token == OuterHeight ?
1214                         part->view()->height() : part->view()->width());
1215 #endif
1216     }
1217     case PageXOffset:
1218         return jsNumber(part->view()->contentsX());
1219     case PageYOffset:
1220         return jsNumber(part->view()->contentsY());
1221     case Personalbar:
1222         return jsUndefined(); // ###
1223     case ScreenLeft:
1224     case ScreenX: {
1225         if (!part->view()) {
1226             return jsUndefined();
1227         }
1228         QRect sg = QApplication::desktop()->screenGeometry(part->view());
1229         return jsNumber(part->view()->mapToGlobal(QPoint(0, 0)).x() + sg.x());
1230     }
1231     case ScreenTop:
1232     case ScreenY: {
1233         if (!part->view()) {
1234             return jsUndefined();
1235         }
1236         QRect sg = QApplication::desktop()->screenGeometry(part->view());
1237         return jsNumber(part->view()->mapToGlobal(QPoint(0, 0)).y() + sg.y());
1238     }
1239     case ScrollX: {
1240         if (!part->view()) {
1241             return jsUndefined();
1242         }
1243         return jsNumber(part->view()->contentsX());
1244     }
1245     case ScrollY: {
1246         if (!part->view()) {
1247             return jsUndefined();
1248         }
1249         return jsNumber(part->view()->contentsY());
1250     }
1251     case Scrollbars:
1252         return new JSObject(); // ###
1253     case _Screen:
1254         return screen ? screen :
1255                (const_cast<Window *>(this)->screen = new Screen(exec));
1256     case _Console:
1257         return console ? console :
1258                (const_cast<Window *>(this)->console = new Console(exec));
1259     case Audio:
1260         return new AudioConstructorImp(exec, part->xmlDocImpl());
1261     case Image:
1262         return new ImageConstructorImp(exec, part->xmlDocImpl());
1263     case Option:
1264         return new OptionConstructorImp(exec, part->xmlDocImpl());
1265     case XMLHttpRequest:
1266         return new XMLHttpRequestConstructorImp(exec, part->xmlDocImpl());
1267     case XMLSerializer:
1268         return new XMLSerializerConstructorImp(exec);
1269     case DOMParser:
1270         return new DOMParserConstructorImp(exec, part->xmlDocImpl());
1271     case ArrayBuffer:
1272         return new ArrayBufferConstructorImp(exec, part->xmlDocImpl());
1273     case Int8Array:
1274         return new ArrayBufferConstructorImpInt8(exec, part->xmlDocImpl());
1275     case Uint8Array:
1276         return new ArrayBufferConstructorImpUint8(exec, part->xmlDocImpl());
1277     case Int16Array:
1278         return new ArrayBufferConstructorImpInt16(exec, part->xmlDocImpl());
1279     case Uint16Array:
1280         return new ArrayBufferConstructorImpUint16(exec, part->xmlDocImpl());
1281     case Int32Array:
1282         return new ArrayBufferConstructorImpInt32(exec, part->xmlDocImpl());
1283     case Uint32Array:
1284         return new ArrayBufferConstructorImpUint32(exec, part->xmlDocImpl());
1285     case Float32Array:
1286         return new ArrayBufferConstructorImpFloat32(exec, part->xmlDocImpl());
1287     case Float64Array:
1288         return new ArrayBufferConstructorImpFloat64(exec, part->xmlDocImpl());
1289     case Onabort:
1290         return getListener(exec, DOM::EventImpl::ABORT_EVENT);
1291     case Onblur:
1292         return getListener(exec, DOM::EventImpl::BLUR_EVENT);
1293     case Onchange:
1294         return getListener(exec, DOM::EventImpl::CHANGE_EVENT);
1295     case Onclick:
1296         return getListener(exec, DOM::EventImpl::KHTML_ECMA_CLICK_EVENT);
1297     case Ondblclick:
1298         return getListener(exec, DOM::EventImpl::KHTML_ECMA_DBLCLICK_EVENT);
1299     case Ondragdrop:
1300         return getListener(exec, DOM::EventImpl::KHTML_DRAGDROP_EVENT);
1301     case Onerror:
1302         return getListener(exec, DOM::EventImpl::ERROR_EVENT);
1303     case Onfocus:
1304         return getListener(exec, DOM::EventImpl::FOCUS_EVENT);
1305     case Onkeydown:
1306         return getListener(exec, DOM::EventImpl::KEYDOWN_EVENT);
1307     case Onkeypress:
1308         return getListener(exec, DOM::EventImpl::KEYPRESS_EVENT);
1309     case Onkeyup:
1310         return getListener(exec, DOM::EventImpl::KEYUP_EVENT);
1311     case Onload:
1312         return getListener(exec, DOM::EventImpl::LOAD_EVENT);
1313     case Onmessage:
1314         return getListener(exec, DOM::EventImpl::MESSAGE_EVENT);
1315     case Onmousedown:
1316         return getListener(exec, DOM::EventImpl::MOUSEDOWN_EVENT);
1317     case Onmousemove:
1318         return getListener(exec, DOM::EventImpl::MOUSEMOVE_EVENT);
1319     case Onmouseout:
1320         return getListener(exec, DOM::EventImpl::MOUSEOUT_EVENT);
1321     case Onmouseover:
1322         return getListener(exec, DOM::EventImpl::MOUSEOVER_EVENT);
1323     case Onmouseup:
1324         return getListener(exec, DOM::EventImpl::MOUSEUP_EVENT);
1325     case Onmove:
1326         return getListener(exec, DOM::EventImpl::KHTML_MOVE_EVENT);
1327     case Onreset:
1328         return getListener(exec, DOM::EventImpl::RESET_EVENT);
1329     case Onresize:
1330         return getListener(exec, DOM::EventImpl::RESIZE_EVENT);
1331     case Onscroll:
1332         return getListener(exec, DOM::EventImpl::SCROLL_EVENT);
1333     case Onselect:
1334         return getListener(exec, DOM::EventImpl::SELECT_EVENT);
1335     case Onsubmit:
1336         return getListener(exec, DOM::EventImpl::SUBMIT_EVENT);
1337     case Onunload:
1338         return getListener(exec, DOM::EventImpl::UNLOAD_EVENT);
1339     case Onhashchange:
1340         return getListener(exec, DOM::EventImpl::HASHCHANGE_EVENT);
1341     }
1342 
1343     return jsUndefined();
1344 }
1345 
put(ExecState * exec,const Identifier & propertyName,JSValue * value,int attr)1346 void Window::put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr)
1347 {
1348     // we don't want any operations on a closed window
1349     if (m_frame.isNull() || m_frame->m_part.isNull()) {
1350         // ### throw exception? allow setting of some props like location?
1351         return;
1352     }
1353 
1354     // Called by an internal KJS call (e.g. InterpreterImp's constructor) ?
1355     // If yes, save time and jump directly to JSObject. We also have
1356     // to do this now since calling isSafeScript() may not work yet.
1357     if (attr != None && attr != DontDelete) {
1358         JSObject::put(exec, propertyName, value, attr);
1359         return;
1360     }
1361 
1362     // If we already have a variable, that's writeable w/o a getter/setter mess, just write to it.
1363     bool safe = isSafeScript(exec);
1364     if (safe) {
1365         if (JSValue **slot = getDirectWriteLocation(propertyName)) {
1366             *slot = value;
1367             return;
1368         }
1369     }
1370 
1371     const HashEntry *entry = Lookup::findEntry(&WindowTable, propertyName);
1372     if (entry) {
1373 #ifdef KJS_VERBOSE
1374         qCDebug(KHTML_LOG) << "Window(" << this << ")::put " << propertyName.qstring();
1375 #endif
1376         if (entry->value == _Location) {
1377             goURL(exec, value->toString(exec).qstring());
1378             return;
1379         }
1380 
1381         KHTMLPart *part = qobject_cast<KHTMLPart *>(m_frame->m_part);
1382         if (part) {
1383             switch (entry->value) {
1384             case Status: {
1385                 if (isSafeScript(exec) && part->settings()->windowStatusPolicy(part->url().host())
1386                         == KHTMLSettings::KJSWindowStatusAllow) {
1387                     UString s = value->toString(exec);
1388                     part->setJSStatusBarText(s.qstring());
1389                 }
1390                 return;
1391             }
1392             case DefaultStatus: {
1393                 if (isSafeScript(exec) && part->settings()->windowStatusPolicy(part->url().host())
1394                         == KHTMLSettings::KJSWindowStatusAllow) {
1395                     UString s = value->toString(exec);
1396                     part->setJSDefaultStatusBarText(s.qstring());
1397                 }
1398                 return;
1399             }
1400             case Onabort:
1401                 if (isSafeScript(exec)) {
1402                     setListener(exec, DOM::EventImpl::ABORT_EVENT, value);
1403                 }
1404                 return;
1405             case Onblur:
1406                 if (isSafeScript(exec)) {
1407                     setListener(exec, DOM::EventImpl::BLUR_EVENT, value);
1408                 }
1409                 return;
1410             case Onchange:
1411                 if (isSafeScript(exec)) {
1412                     setListener(exec, DOM::EventImpl::CHANGE_EVENT, value);
1413                 }
1414                 return;
1415             case Onclick:
1416                 if (isSafeScript(exec)) {
1417                     setListener(exec, DOM::EventImpl::KHTML_ECMA_CLICK_EVENT, value);
1418                 }
1419                 return;
1420             case Ondblclick:
1421                 if (isSafeScript(exec)) {
1422                     setListener(exec, DOM::EventImpl::KHTML_ECMA_DBLCLICK_EVENT, value);
1423                 }
1424                 return;
1425             case Ondragdrop:
1426                 if (isSafeScript(exec)) {
1427                     setListener(exec, DOM::EventImpl::KHTML_DRAGDROP_EVENT, value);
1428                 }
1429                 return;
1430             case Onerror:
1431                 if (isSafeScript(exec)) {
1432                     setListener(exec, DOM::EventImpl::ERROR_EVENT, value);
1433                 }
1434                 return;
1435             case Onfocus:
1436                 if (isSafeScript(exec)) {
1437                     setListener(exec, DOM::EventImpl::FOCUS_EVENT, value);
1438                 }
1439                 return;
1440             case Onkeydown:
1441                 if (isSafeScript(exec)) {
1442                     setListener(exec, DOM::EventImpl::KEYDOWN_EVENT, value);
1443                 }
1444                 return;
1445             case Onkeypress:
1446                 if (isSafeScript(exec)) {
1447                     setListener(exec, DOM::EventImpl::KEYPRESS_EVENT, value);
1448                 }
1449                 return;
1450             case Onkeyup:
1451                 if (isSafeScript(exec)) {
1452                     setListener(exec, DOM::EventImpl::KEYUP_EVENT, value);
1453                 }
1454                 return;
1455             case Onload:
1456                 if (isSafeScript(exec)) {
1457                     setListener(exec, DOM::EventImpl::LOAD_EVENT, value);
1458                 }
1459                 return;
1460             case Onmessage:
1461                 if (isSafeScript(exec)) {
1462                     setListener(exec, DOM::EventImpl::MESSAGE_EVENT, value);
1463                 }
1464                 return;
1465             case Onmousedown:
1466                 if (isSafeScript(exec)) {
1467                     setListener(exec, DOM::EventImpl::MOUSEDOWN_EVENT, value);
1468                 }
1469                 return;
1470             case Onmousemove:
1471                 if (isSafeScript(exec)) {
1472                     setListener(exec, DOM::EventImpl::MOUSEMOVE_EVENT, value);
1473                 }
1474                 return;
1475             case Onmouseout:
1476                 if (isSafeScript(exec)) {
1477                     setListener(exec, DOM::EventImpl::MOUSEOUT_EVENT, value);
1478                 }
1479                 return;
1480             case Onmouseover:
1481                 if (isSafeScript(exec)) {
1482                     setListener(exec, DOM::EventImpl::MOUSEOVER_EVENT, value);
1483                 }
1484                 return;
1485             case Onmouseup:
1486                 if (isSafeScript(exec)) {
1487                     setListener(exec, DOM::EventImpl::MOUSEUP_EVENT, value);
1488                 }
1489                 return;
1490             case Onmove:
1491                 if (isSafeScript(exec)) {
1492                     setListener(exec, DOM::EventImpl::KHTML_MOVE_EVENT, value);
1493                 }
1494                 return;
1495             case Onreset:
1496                 if (isSafeScript(exec)) {
1497                     setListener(exec, DOM::EventImpl::RESET_EVENT, value);
1498                 }
1499                 return;
1500             case Onresize:
1501                 if (isSafeScript(exec)) {
1502                     setListener(exec, DOM::EventImpl::RESIZE_EVENT, value);
1503                 }
1504                 return;
1505             case Onscroll:
1506                 if (isSafeScript(exec)) {
1507                     setListener(exec, DOM::EventImpl::SCROLL_EVENT, value);
1508                 }
1509                 return;
1510             case Onselect:
1511                 if (isSafeScript(exec)) {
1512                     setListener(exec, DOM::EventImpl::SELECT_EVENT, value);
1513                 }
1514                 return;
1515             case Onsubmit:
1516                 if (isSafeScript(exec)) {
1517                     setListener(exec, DOM::EventImpl::SUBMIT_EVENT, value);
1518                 }
1519                 return;
1520             case Onunload:
1521                 if (isSafeScript(exec)) {
1522                     setListener(exec, DOM::EventImpl::UNLOAD_EVENT, value);
1523                 }
1524                 return;
1525             case Onhashchange:
1526                 if (isSafeScript(exec)) {
1527                     setListener(exec, DOM::EventImpl::HASHCHANGE_EVENT, value);
1528                 }
1529                 return;
1530             case Name:
1531                 if (isSafeScript(exec)) {
1532                     part->setObjectName(value->toString(exec).qstring().toLocal8Bit().data());
1533                 }
1534                 return;
1535             default:
1536                 break;
1537             }
1538         }
1539     }
1540     if (isSafeScript(exec) &&
1541             pluginRootPut(exec, m_frame->m_scriptable.data(), propertyName, value)) {
1542         return;
1543     }
1544     if (safe) {
1545         //qCDebug(KHTML_LOG) << "Window("<<this<<")::put storing " << propertyName.qstring();
1546         JSObject::put(exec, propertyName, value, attr);
1547     }
1548 }
1549 
toBoolean(ExecState *) const1550 bool Window::toBoolean(ExecState *) const
1551 {
1552     return !m_frame.isNull() && !m_frame->m_part.isNull();
1553 }
1554 
toAbstractView() const1555 DOM::AbstractViewImpl *Window::toAbstractView() const
1556 {
1557     KHTMLPart *part = ::qobject_cast<KHTMLPart *>(m_frame->m_part);
1558     if (!part || !part->xmlDocImpl()) {
1559         return nullptr;
1560     }
1561     return part->xmlDocImpl()->defaultView();
1562 }
1563 
scheduleClose()1564 void Window::scheduleClose()
1565 {
1566     // qCDebug(KHTML_LOG) << "Window::scheduleClose window.close() " << m_frame;
1567     Q_ASSERT(winq);
1568     QTimer::singleShot(0, winq, SLOT(timeoutClose()));
1569 }
1570 
closeNow()1571 void Window::closeNow()
1572 {
1573     if (m_frame.isNull() || m_frame->m_part.isNull()) {
1574         // qCDebug(KHTML_LOG) << "part is deleted already";
1575     } else {
1576         KHTMLPart *part = qobject_cast<KHTMLPart *>(m_frame->m_part);
1577         if (!part) {
1578             // qCDebug(KHTML_LOG) << "closeNow on non KHTML part";
1579         } else {
1580             //qCDebug(KHTML_LOG) << " -> closing window";
1581             // We want to make sure that window.open won't find this part by name.
1582             part->setObjectName(QString());
1583             part->deleteLater();
1584             part = nullptr;
1585         }
1586     }
1587 }
1588 
afterScriptExecution()1589 void Window::afterScriptExecution()
1590 {
1591     DOM::DocumentImpl::updateDocumentsRendering();
1592     const QList<DelayedAction *> delayedActions = m_delayed;
1593     m_delayed.clear();
1594     foreach (DelayedAction *act, delayedActions) {
1595         if (!act->execute(this)) {
1596             break;    // done with them
1597         }
1598     }
1599     qDeleteAll(delayedActions);
1600 }
1601 
checkIsSafeScript(KParts::ReadOnlyPart * activePart) const1602 bool Window::checkIsSafeScript(KParts::ReadOnlyPart *activePart) const
1603 {
1604     if (m_frame.isNull() || m_frame->m_part.isNull()) { // part deleted ? can't grant access
1605         // qCDebug(KHTML_LOG) << "Window::isSafeScript: accessing deleted part !";
1606         return false;
1607     }
1608     if (!activePart) {
1609         // qCDebug(KHTML_LOG) << "Window::isSafeScript: current interpreter's part is 0L!";
1610         return false;
1611     }
1612     if (activePart == m_frame->m_part) { // Not calling from another frame, no problem.
1613         return true;
1614     }
1615 
1616     KHTMLPart *part = qobject_cast<KHTMLPart *>(m_frame->m_part);
1617     if (!part) {
1618         return true;    // not a KHTMLPart
1619     }
1620 
1621     if (!part->xmlDocImpl()) {
1622         return true;    // allow to access a window that was just created (e.g. with window.open("about:blank"))
1623     }
1624 
1625     DOM::DocumentImpl *thisDocument = part->xmlDocImpl();
1626 
1627     KHTMLPart *activeKHTMLPart = qobject_cast<KHTMLPart *>(activePart);
1628     if (!activeKHTMLPart) {
1629         return true;    // not a KHTMLPart
1630     }
1631 
1632     DOM::DocumentImpl *actDocument = activeKHTMLPart->xmlDocImpl();
1633     if (!actDocument) {
1634         // qCDebug(KHTML_LOG) << "Window::isSafeScript: active part has no document!";
1635         return false;
1636     }
1637     khtml::SecurityOrigin *actDomain  = actDocument->origin();
1638     khtml::SecurityOrigin *thisDomain = thisDocument->origin();
1639 
1640     if (actDomain->canAccess(thisDomain)) {
1641 #ifdef KJS_VERBOSE
1642         qCDebug(KHTML_LOG) << "JavaScript: access granted, domain is '" << actDomain.string() << "'";
1643 #endif
1644         return true;
1645     }
1646 
1647     // qCDebug(KHTML_LOG) << "WARNING: JavaScript: access denied for current frame '" << actDomain->toString() << "' to frame '" << thisDomain->toString() << "'";
1648     // TODO after 3.1: throw security exception (exec->setException())
1649     return false;
1650 }
1651 
setListener(ExecState * exec,int eventId,JSValue * func)1652 void Window::setListener(ExecState *exec, int eventId, JSValue *func)
1653 {
1654     KHTMLPart *part = qobject_cast<KHTMLPart *>(m_frame->m_part);
1655     if (!part || !isSafeScript(exec)) {
1656         return;
1657     }
1658     DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(part->htmlDocument().handle());
1659     if (!doc) {
1660         return;
1661     }
1662 
1663     doc->setHTMLWindowEventListener(eventId, getJSEventListener(func, true));
1664 }
1665 
getListener(ExecState * exec,int eventId) const1666 JSValue *Window::getListener(ExecState *exec, int eventId) const
1667 {
1668     KHTMLPart *part = qobject_cast<KHTMLPart *>(m_frame->m_part);
1669     if (!part || !isSafeScript(exec)) {
1670         return jsUndefined();
1671     }
1672     DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(part->htmlDocument().handle());
1673     if (!doc) {
1674         return jsUndefined();
1675     }
1676 
1677     DOM::EventListener *listener = doc->getHTMLWindowEventListener(eventId);
1678     if (listener && static_cast<JSEventListener *>(listener)->listenerObj()) {
1679         return static_cast<JSEventListener *>(listener)->listenerObj();
1680     } else {
1681         return jsNull();
1682     }
1683 }
1684 
getJSEventListener(JSValue * val,bool html)1685 JSEventListener *Window::getJSEventListener(JSValue *val, bool html)
1686 {
1687     // This function is so hot that it's worth coding it directly with imps.
1688     KHTMLPart *part = qobject_cast<KHTMLPart *>(m_frame->m_part);
1689     if (!part || val->type() != ObjectType) {
1690         return nullptr;
1691     }
1692 
1693     // It's ObjectType, so it must be valid.
1694     JSObject *listenerObject = val->getObject();
1695     JSObject *thisObject = listenerObject;
1696 
1697     // 'listener' is not a simple ecma function. (Always use sanity checks: Better safe than sorry!)
1698     if (!listenerObject->implementsCall() && part && part->jScript() && part->jScript()->interpreter()) {
1699         Interpreter *interpreter = part->jScript()->interpreter();
1700 
1701         // 'listener' probably is an EventListener object containing a 'handleEvent' function.
1702         JSValue *handleEventValue = listenerObject->get(interpreter->globalExec(), Identifier("handleEvent"));
1703         JSObject *handleEventObject = handleEventValue->getObject();
1704 
1705         if (handleEventObject && handleEventObject->implementsCall()) {
1706             thisObject = listenerObject;
1707             listenerObject = handleEventObject;
1708         }
1709     }
1710 
1711     JSEventListener *existingListener = jsEventListeners.value(QPair<void *, bool>(thisObject, html));
1712     if (existingListener) {
1713         assert(existingListener->isHTMLEventListener() == html);
1714         return existingListener;
1715     }
1716 
1717     // Note that the JSEventListener constructor adds it to our jsEventListeners list
1718     return new JSEventListener(listenerObject, thisObject, this, html);
1719 }
1720 
getJSLazyEventListener(const QString & code,const QString & srcUrl,int line,const QString & name,DOM::NodeImpl * node,bool svg)1721 JSLazyEventListener *Window::getJSLazyEventListener(const QString &code, const QString &srcUrl, int line,
1722         const QString &name, DOM::NodeImpl *node, bool svg)
1723 {
1724     return new JSLazyEventListener(code, srcUrl, line, name, this, node, svg);
1725 }
1726 
clear(ExecState * exec)1727 void Window::clear(ExecState *exec)
1728 {
1729     Q_UNUSED(exec);
1730     delete winq;
1731     qDeleteAll(m_delayed);
1732     m_delayed.clear();
1733 
1734     winq = nullptr;
1735     // Get rid of everything, those user vars could hold references to DOM nodes
1736     clearProperties();
1737 
1738     // Ditto for the special subobjects.
1739     screen   = nullptr;
1740     console  = nullptr;
1741     history  = nullptr;
1742     external = nullptr;
1743     loc      = nullptr;
1744     setPrototype(jsNull());
1745 
1746     // Break the dependency between the listeners and their object
1747     QHashIterator<const QPair<void *, bool>, JSEventListener *> it(jsEventListeners);
1748     while (it.hasNext()) {
1749         it.next();
1750         it.value()->clear();
1751     }
1752 
1753     // Forget about the listeners (the DOM::NodeImpls will delete them)
1754     jsEventListeners.clear();
1755 
1756     if (m_frame) {
1757         KJSProxy *proxy = m_frame->m_jscript;
1758         if (proxy) { // i.e. JS not disabled
1759             winq = new WindowQObject(this);
1760             // Now recreate a working global object for the next URL that will use us
1761             KJS::Interpreter *interpreter = proxy->interpreter();
1762             interpreter->initGlobalObject();
1763         }
1764     }
1765 }
1766 
setCurrentEvent(DOM::EventImpl * evt)1767 void Window::setCurrentEvent(DOM::EventImpl *evt)
1768 {
1769     m_evt = evt;
1770     //qCDebug(KHTML_LOG) << "Window " << this << " (part=" << m_part << ")::setCurrentEvent m_evt=" << evt;
1771 }
1772 
goURL(ExecState * exec,const QString & url,bool lockHistory)1773 void Window::goURL(ExecState *exec, const QString &url, bool lockHistory)
1774 {
1775     Window *active = Window::retrieveActive(exec);
1776     KHTMLPart *part = qobject_cast<KHTMLPart *>(m_frame->m_part);
1777     KHTMLPart *active_part = qobject_cast<KHTMLPart *>(active->part());
1778     // Complete the URL using the "active part" (running interpreter)
1779     if (active_part && part) {
1780         QString dstUrl = active_part->htmlDocument().completeURL(url).string();
1781         // qCDebug(KHTML_LOG) << "Window::goURL dstUrl=" << dstUrl;
1782 
1783         // check if we're allowed to inject javascript
1784         if (!KHTMLPartPrivate::isJavaScriptURL(dstUrl) || isSafeScript(exec)) {
1785             part->scheduleRedirection(-1, dstUrl, lockHistory);
1786         }
1787     } else if (!part && m_frame->m_partContainerElement) {
1788         KParts::BrowserExtension *b = KParts::BrowserExtension::childObject(m_frame->m_part);
1789         if (b) {
1790             emit b->openUrlRequest(QUrl(m_frame->m_partContainerElement.data()->document()->completeURL(url)));
1791         }
1792         // qCDebug(KHTML_LOG) << "goURL for ROPart";
1793     }
1794 }
1795 
1796 class DelayedGoHistory: public Window::DelayedAction
1797 {
1798 public:
DelayedGoHistory(int _steps)1799     DelayedGoHistory(int _steps): steps(_steps)
1800     {}
1801 
execute(Window * win)1802     bool execute(Window *win) override
1803     {
1804         win->goHistory(steps);
1805         return true;
1806     }
1807 private:
1808     int steps;
1809 };
1810 
delayedGoHistory(int steps)1811 void Window::delayedGoHistory(int steps)
1812 {
1813     m_delayed.append(new DelayedGoHistory(steps));
1814 }
1815 
goHistory(int steps)1816 void Window::goHistory(int steps)
1817 {
1818     KHTMLPart *part = qobject_cast<KHTMLPart *>(m_frame->m_part);
1819     if (!part)
1820         // TODO history readonlypart
1821     {
1822         return;
1823     }
1824     KParts::BrowserExtension *ext = part->browserExtension();
1825     if (!ext) {
1826         return;
1827     }
1828     KParts::BrowserInterface *iface = ext->browserInterface();
1829 
1830     if (!iface) {
1831         return;
1832     }
1833 
1834     iface->callMethod("goHistory", steps);
1835     //emit ext->goHistory(steps);
1836 }
1837 
resizeTo(QWidget * tl,int width,int height)1838 void KJS::Window::resizeTo(QWidget *tl, int width, int height)
1839 {
1840     KHTMLPart *part = qobject_cast<KHTMLPart *>(m_frame->m_part);
1841     if (!part)
1842         // TODO resizeTo readonlypart
1843     {
1844         return;
1845     }
1846     KParts::BrowserExtension *ext = part->browserExtension();
1847     if (!ext) {
1848         // qCDebug(KHTML_LOG) << "Window::resizeTo found no browserExtension";
1849         return;
1850     }
1851 
1852     // Security check: within desktop limits and bigger than 100x100 (per spec)
1853     if (width < 100 || height < 100) {
1854         // qCDebug(KHTML_LOG) << "Window::resizeTo refused, window would be too small ("<<width<<","<<height<<")";
1855         return;
1856     }
1857 
1858     QRect sg = QApplication::desktop()->screenGeometry(tl);
1859 
1860     if (width > sg.width() || height > sg.height()) {
1861         // qCDebug(KHTML_LOG) << "Window::resizeTo refused, window would be too big ("<<width<<","<<height<<")";
1862         return;
1863     }
1864 
1865     // qCDebug(KHTML_LOG) << "resizing to " << width << "x" << height;
1866 
1867     emit ext->resizeTopLevelWidget(width, height);
1868 
1869     // If the window is out of the desktop, move it up/left
1870     // (maybe we should use workarea instead of sg, otherwise the window ends up below kicker)
1871     int right = tl->x() + tl->frameGeometry().width();
1872     int bottom = tl->y() + tl->frameGeometry().height();
1873     int moveByX = 0;
1874     int moveByY = 0;
1875     if (right > sg.right()) {
1876         moveByX = - right + sg.right();    // always <0
1877     }
1878     if (bottom > sg.bottom()) {
1879         moveByY = - bottom + sg.bottom();    // always <0
1880     }
1881     if (moveByX || moveByY) {
1882         emit ext->moveTopLevelWidget(tl->x() + moveByX, tl->y() + moveByY);
1883     }
1884 }
1885 
targetIsExistingWindow(KHTMLPart * ourPart,const QString & frameName)1886 bool Window::targetIsExistingWindow(KHTMLPart *ourPart, const QString &frameName)
1887 {
1888     QString normalized = frameName.toLower();
1889     if (normalized == "_top" || normalized == "_self" || normalized == "_parent") {
1890         return true;
1891     }
1892 
1893     // Find the highest parent part we can access.
1894     KHTMLPart *p = ourPart;
1895     while (p->parentPart() && p->parentPart()->checkFrameAccess(ourPart)) {
1896         p = p->parentPart();
1897     }
1898 
1899     return p->findFrame(frameName);
1900 }
1901 
openWindow(ExecState * exec,const List & args)1902 JSValue *Window::openWindow(ExecState *exec, const List &args)
1903 {
1904     KHTMLPart *part = qobject_cast<KHTMLPart *>(m_frame->m_part);
1905     if (!part) {
1906         return jsUndefined();
1907     }
1908     KHTMLView *widget = part->view();
1909     JSValue *v = args[0];
1910     QString str;
1911     if (!v->isUndefinedOrNull()) {
1912         str = v->toString(exec).qstring();
1913     }
1914 
1915     // prepare arguments
1916     QUrl url;
1917     if (!str.isEmpty()) {
1918         KHTMLPart *p = qobject_cast<KHTMLPart *>(Window::retrieveActive(exec)->m_frame->m_part);
1919         if (p) {
1920             url = QUrl(p->htmlDocument().completeURL(str).string());
1921         }
1922         if (!p ||
1923                 !static_cast<DOM::DocumentImpl *>(p->htmlDocument().handle())->isURLAllowed(url.url())) {
1924             return jsUndefined();
1925         }
1926     }
1927 
1928     KHTMLSettings::KJSWindowOpenPolicy policy =
1929         part->settings()->windowOpenPolicy(part->url().host());
1930 
1931     QString frameName = args.size() > 1 ? args[1]->toString(exec).qstring() : QString("_blank");
1932 
1933     // Always permit opening in an exist frame (including _self, etc.)
1934     if (targetIsExistingWindow(part, frameName)) {
1935         policy = KHTMLSettings::KJSWindowOpenAllow;
1936     }
1937 
1938     if (policy == KHTMLSettings::KJSWindowOpenAsk) {
1939         emit part->browserExtension()->requestFocus(part);
1940         QString caption;
1941         if (!part->url().host().isEmpty()) {
1942             caption = part->url().host() + " - ";
1943         }
1944         caption += i18n("Confirmation: JavaScript Popup");
1945         if (KMessageBox::questionYesNo(widget,
1946                                        str.isEmpty() ?
1947                                        i18n("This site is requesting to open up a new browser "
1948                                             "window via JavaScript.\n"
1949                                             "Do you want to allow this?") :
1950                                        i18n("<qt>This site is requesting to open<p>%1</p>in a new browser window via JavaScript.<br />"
1951                                             "Do you want to allow this?</qt>", KStringHandler::csqueeze(url.toDisplayString().toHtmlEscaped(),  100)),
1952                                        caption, KGuiItem(i18n("Allow")), KGuiItem(i18n("Do Not Allow"))) == KMessageBox::Yes) {
1953             policy = KHTMLSettings::KJSWindowOpenAllow;
1954         }
1955     } else if (policy == KHTMLSettings::KJSWindowOpenSmart) {
1956         // window.open disabled unless from a key/mouse event
1957         if (static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->isWindowOpenAllowed()) {
1958             policy = KHTMLSettings::KJSWindowOpenAllow;
1959         }
1960     }
1961 
1962     v = args[2];
1963     QString features;
1964     if (v && v->type() != UndefinedType && v->toString(exec).size() > 0) {
1965         features = v->toString(exec).qstring();
1966         // Buggy scripts have ' at beginning and end, cut those
1967         if (features.startsWith(QLatin1Char('\'')) &&
1968                 features.endsWith(QLatin1Char('\''))) {
1969             features = features.mid(1, features.length() - 2);
1970         }
1971     }
1972 
1973     if (policy != KHTMLSettings::KJSWindowOpenAllow) {
1974         if (url.isEmpty()) {
1975             part->setSuppressedPopupIndicator(true, nullptr);
1976         } else {
1977             part->setSuppressedPopupIndicator(true, part);
1978             m_suppressedWindowInfo.append(SuppressedWindowInfo(url, frameName, features));
1979         }
1980         return jsUndefined();
1981     } else {
1982         return executeOpenWindow(exec, url, frameName, features);
1983     }
1984 }
1985 
executeOpenWindow(ExecState * exec,const QUrl & url,const QString & frameName,const QString & features)1986 JSValue *Window::executeOpenWindow(ExecState *exec, const QUrl &url, const QString &frameName, const QString &features)
1987 {
1988     KHTMLPart *p = qobject_cast<KHTMLPart *>(m_frame->m_part);
1989     KHTMLView *widget = p->view();
1990     KParts::WindowArgs winargs;
1991 
1992     // Split on commas and syntactic whitespace
1993     // Testcase: 'height=600, width=950 left = 30,top = 50,statusbar=0'
1994     static const QRegExp m(",|\\b\\s+(?!=)");
1995 
1996     // scan feature argument
1997     if (!features.isEmpty()) {
1998         // specifying window params means false defaults
1999         winargs.setMenuBarVisible(false);
2000         winargs.setToolBarsVisible(false);
2001         winargs.setStatusBarVisible(false);
2002         winargs.setScrollBarsVisible(false);
2003         const QStringList flist = features.trimmed().split(m);
2004         QStringList::ConstIterator it = flist.begin();
2005         while (it != flist.end()) {
2006             QString s = *it++;
2007             QString key, val;
2008             int pos = s.indexOf('=');
2009             if (pos >= 0) {
2010                 key = s.left(pos).trimmed().toLower();
2011                 val = s.mid(pos + 1).trimmed().toLower();
2012                 QRect screen = QApplication::desktop()->screenGeometry(widget->topLevelWidget());
2013 
2014                 if (key == "left" || key == "screenx") {
2015                     winargs.setX((int)val.toFloat() + screen.x());
2016                     if (winargs.x() < screen.x() || winargs.x() > screen.right()) {
2017                         winargs.setX(screen.x());    // only safe choice until size is determined
2018                     }
2019                 } else if (key == "top" || key == "screeny") {
2020                     winargs.setY((int)val.toFloat() + screen.y());
2021                     if (winargs.y() < screen.y() || winargs.y() > screen.bottom()) {
2022                         winargs.setY(screen.y());    // only safe choice until size is determined
2023                     }
2024                 } else if (key == "height") {
2025                     winargs.setHeight((int)val.toFloat() + 2 * qApp->style()->pixelMetric(QStyle::PM_DefaultFrameWidth) + 2);
2026                     if (winargs.height() > screen.height()) { // should actually check workspace
2027                         winargs.setHeight(screen.height());
2028                     }
2029                     if (winargs.height() < 100) {
2030                         winargs.setHeight(100);
2031                     }
2032                 } else if (key == "width") {
2033                     winargs.setWidth((int)val.toFloat() + 2 * qApp->style()->pixelMetric(QStyle::PM_DefaultFrameWidth) + 2);
2034                     if (winargs.width() > screen.width()) {  // should actually check workspace
2035                         winargs.setWidth(screen.width());
2036                     }
2037                     if (winargs.width() < 100) {
2038                         winargs.setWidth(100);
2039                     }
2040                 } else {
2041                     goto boolargs;
2042                 }
2043                 continue;
2044             } else {
2045                 // leaving away the value gives true
2046                 key = s.trimmed().toLower();
2047                 val = "1";
2048             }
2049         boolargs:
2050             if (key == "menubar") {
2051                 winargs.setMenuBarVisible(val == "1" || val == "yes");
2052             } else if (key == "toolbar") {
2053                 winargs.setToolBarsVisible(val == "1" || val == "yes");
2054             } else if (key == "location") { // ### missing in WindowArgs
2055                 winargs.setToolBarsVisible(val == "1" || val == "yes");
2056             } else if (key == "status" || key == "statusbar") {
2057                 winargs.setStatusBarVisible(val == "1" || val == "yes");
2058             } else if (key == "scrollbars") {
2059                 winargs.setScrollBarsVisible(val == "1" || val == "yes");
2060             } else if (key == "resizable") {
2061                 winargs.setResizable(val == "1" || val == "yes");
2062             } else if (key == "fullscreen") {
2063                 winargs.setFullScreen(val == "1" || val == "yes");
2064             }
2065         }
2066     }
2067 
2068     KParts::OpenUrlArguments args;
2069     KParts::BrowserArguments browserArgs;
2070     browserArgs.frameName = frameName;
2071 
2072     if (browserArgs.frameName.toLower() == "_top") {
2073         while (p->parentPart()) {
2074             p = p->parentPart();
2075         }
2076         Window::retrieveWindow(p)->goURL(exec, url.url());
2077         return Window::retrieve(p);
2078     }
2079     if (browserArgs.frameName.toLower() == "_parent") {
2080         if (p->parentPart()) {
2081             p = p->parentPart();
2082         }
2083         Window::retrieveWindow(p)->goURL(exec, url.url());
2084         return Window::retrieve(p);
2085     }
2086     if (browserArgs.frameName.toLower() == "_self") {
2087         Window::retrieveWindow(p)->goURL(exec, url.url());
2088         return Window::retrieve(p);
2089     }
2090     if (browserArgs.frameName.toLower() == "replace") {
2091         Window::retrieveWindow(p)->goURL(exec, url.url(), true/*lock history*/);
2092         return Window::retrieve(p);
2093     }
2094     args.setMimeType("text/html");
2095     args.setActionRequestedByUser(false);
2096 
2097     // request window (new or existing if framename is set)
2098     KParts::ReadOnlyPart *newPart = nullptr;
2099     emit p->browserExtension()->createNewWindow(QUrl(), args, browserArgs, winargs, &newPart);
2100     if (newPart && qobject_cast<KHTMLPart *>(newPart)) {
2101         KHTMLPart *khtmlpart = static_cast<KHTMLPart *>(newPart);
2102         //qDebug("opener set to %p (this Window's part) in new Window %p  (this Window=%p)",part,win,window);
2103         khtmlpart->setOpener(p);
2104         khtmlpart->setOpenedByJS(true);
2105         if (khtmlpart->document().isNull()) {
2106             khtmlpart->begin();
2107             khtmlpart->write("<HTML><BODY>");
2108             khtmlpart->end();
2109             if (p->docImpl()) {
2110                 //qCDebug(KHTML_LOG) << "Setting domain to " << p->docImpl()->domain().string();
2111                 khtmlpart->docImpl()->setOrigin(p->docImpl()->origin());
2112                 khtmlpart->docImpl()->setBaseURL(p->docImpl()->baseURL());
2113             }
2114         }
2115         args.setMimeType(QString());
2116         if (browserArgs.frameName.toLower() == "_blank") {
2117             browserArgs.frameName.clear();
2118         }
2119         if (!url.isEmpty()) {
2120             emit khtmlpart->browserExtension()->openUrlRequest(url, args, browserArgs);
2121         }
2122         return Window::retrieve(khtmlpart); // global object
2123     } else {
2124         return jsUndefined();
2125     }
2126 }
2127 
forgetSuppressedWindows()2128 void Window::forgetSuppressedWindows()
2129 {
2130     m_suppressedWindowInfo.clear();
2131 }
2132 
showSuppressedWindows()2133 void Window::showSuppressedWindows()
2134 {
2135     KHTMLPart *part = qobject_cast<KHTMLPart *>(m_frame->m_part);
2136     KJS::Interpreter *interpreter = part->jScript()->interpreter();
2137     ExecState *exec = interpreter->globalExec();
2138 
2139     QList<SuppressedWindowInfo> suppressedWindowInfo = m_suppressedWindowInfo;
2140     m_suppressedWindowInfo.clear();
2141     foreach (const SuppressedWindowInfo &info, suppressedWindowInfo) {
2142         executeOpenWindow(exec, info.url, info.frameName, info.features);
2143     }
2144 }
2145 
2146 class DelayedClose: public Window::DelayedAction
2147 {
2148 public:
execute(Window * win)2149     bool execute(Window *win) override
2150     {
2151         win->scheduleClose();
2152         return false;
2153     }
2154 private:
2155     int steps;
2156 };
2157 
callAsFunction(ExecState * exec,JSObject * thisObj,const List & args)2158 JSValue *WindowFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
2159 {
2160     KJS_CHECK_THIS(Window, thisObj);
2161 
2162     // these should work no matter whether the window is already
2163     // closed or not
2164     if (id == Window::ValueOf || id == Window::ToString) {
2165         return jsString("[object Window]");
2166     }
2167 
2168     Window *window = static_cast<Window *>(thisObj);
2169     QString str, str2;
2170 
2171     KHTMLPart *part = qobject_cast<KHTMLPart *>(window->m_frame->m_part);
2172     if (!part) {
2173         return jsUndefined();
2174     }
2175 
2176     KHTMLView *widget = part->view();
2177     JSValue *v = args[0];
2178     UString s;
2179     s = v->toString(exec);
2180     str = s.qstring();
2181 
2182     QString caption;
2183     if (part && !part->url().host().isEmpty()) {
2184         caption = part->url().host() + " - ";
2185     }
2186     caption += "JavaScript"; // TODO: i18n
2187     // functions that work everywhere
2188     switch (id) {
2189     case Window::Alert: {
2190         TimerPauser pause(exec);
2191         if (!widget->dialogsAllowed()) {
2192             return jsUndefined();
2193         }
2194         if (part && part->xmlDocImpl()) {
2195             part->xmlDocImpl()->updateRendering();
2196         }
2197         if (part) {
2198             emit part->browserExtension()->requestFocus(part);
2199         }
2200         KMessageBox::error(widget, Qt::convertFromPlainText(str), caption);
2201         return jsUndefined();
2202     }
2203     case Window::Confirm: {
2204         TimerPauser pause(exec);
2205         if (!widget->dialogsAllowed()) {
2206             return jsUndefined();
2207         }
2208         if (part && part->xmlDocImpl()) {
2209             part->xmlDocImpl()->updateRendering();
2210         }
2211         if (part) {
2212             emit part->browserExtension()->requestFocus(part);
2213         }
2214         return jsBoolean((KMessageBox::warningYesNo(widget, Qt::convertFromPlainText(str), caption,
2215                           KStandardGuiItem::ok(), KStandardGuiItem::cancel()) == KMessageBox::Yes));
2216     }
2217     case Window::Prompt: {
2218         TimerPauser pause(exec);
2219 #ifndef KONQ_EMBEDDED
2220         if (!widget->dialogsAllowed()) {
2221             return jsUndefined();
2222         }
2223         if (part && part->xmlDocImpl()) {
2224             part->xmlDocImpl()->updateRendering();
2225         }
2226         if (part) {
2227             emit part->browserExtension()->requestFocus(part);
2228         }
2229         bool ok;
2230         if (args.size() >= 2)
2231             str2 = QInputDialog::getText(widget, caption,
2232                                          Qt::convertFromPlainText(str), QLineEdit::Normal,
2233                                          args[1]->toString(exec).qstring(), &ok);
2234         else
2235             str2 = QInputDialog::getText(widget, caption,
2236                                          Qt::convertFromPlainText(str),
2237                                          QLineEdit::Normal, QString(), &ok);
2238         if (ok) {
2239             return jsString(UString(str2));
2240         } else {
2241             return jsNull();
2242         }
2243 #else
2244         return jsUndefined();
2245 #endif
2246     }
2247     case Window::GetComputedStyle:  {
2248         if (!part || !part->xmlDocImpl()) {
2249             return jsUndefined();
2250         }
2251         DOM::NodeImpl *arg0 = toNode(args[0]);
2252         if (!arg0 || arg0->nodeType() != DOM::Node::ELEMENT_NODE) {
2253             return jsUndefined();    // throw exception?
2254         } else
2255             return getDOMCSSStyleDeclaration(exec, part->xmlDocImpl()->defaultView()->getComputedStyle(
2256                                                  static_cast<DOM::ElementImpl *>(arg0), args[1]->toString(exec).domString().implementation()));
2257     }
2258     case Window::Open:
2259         return window->openWindow(exec, args);
2260     case Window::Close: {
2261         /* From http://developer.netscape.com/docs/manuals/js/client/jsref/window.htm :
2262            The close method closes only windows opened by JavaScript using the open method.
2263            If you attempt to close any other window, a confirm is generated, which
2264            lets the user choose whether the window closes.
2265            This is a security feature to prevent "mail bombs" containing self.close().
2266            However, if the window has only one document (the current one) in its
2267            session history, the close is allowed without any confirm. This is a
2268            special case for one-off windows that need to open other windows and
2269            then dispose of themselves.
2270         */
2271         bool doClose = false;
2272         if (!part->openedByJS()) {
2273             // To conform to the SPEC, we only ask if the window
2274             // has more than one entry in the history (NS does that too).
2275             History history(exec, part);
2276 
2277             if (history.get(exec, "length")->toInt32(exec) <= 1) {
2278                 doClose = true;
2279             } else {
2280                 // Can we get this dialog with tabs??? Does it close the window or the tab in that case?
2281                 emit part->browserExtension()->requestFocus(part);
2282                 if (KMessageBox::questionYesNo(window->part()->widget(),
2283                                                i18n("Close window?"), i18n("Confirmation Required"),
2284                                                KStandardGuiItem::close(), KStandardGuiItem::cancel())
2285                         == KMessageBox::Yes) {
2286                     doClose = true;
2287                 }
2288             }
2289         } else {
2290             doClose = true;
2291         }
2292 
2293         if (doClose) {
2294             // If this is the current window (the one the interpreter runs in),
2295             // then schedule a delayed close (so that the script terminates first).
2296             // But otherwise, close immediately. This fixes w=window.open("","name");w.close();window.open("name");
2297             if (Window::retrieveActive(exec) == window) {
2298                 if (widget) {
2299                     // quit all dialogs of this view
2300                     // this fixes 'setTimeout('self.close()',1000); alert("Hi");' crash
2301                     widget->closeChildDialogs();
2302                 }
2303                 //qCDebug(KHTML_LOG) << "scheduling delayed close";
2304                 // We'll close the window at the end of the script execution
2305                 Window *w = const_cast<Window *>(window);
2306                 w->m_delayed.append(new DelayedClose);
2307             } else {
2308                 //qCDebug(KHTML_LOG) << "closing NOW";
2309                 (const_cast<Window *>(window))->closeNow();
2310             }
2311         }
2312         return jsUndefined();
2313     }
2314     case Window::GetSelection:
2315         return new KJS::DOMSelection(exec, part->xmlDocImpl());
2316 
2317     case Window::Navigate:
2318         window->goURL(exec, args[0]->toString(exec).qstring());
2319         return jsUndefined();
2320     case Window::Focus: {
2321         KHTMLSettings::KJSWindowFocusPolicy policy =
2322             part->settings()->windowFocusPolicy(part->url().host());
2323         if (policy == KHTMLSettings::KJSWindowFocusAllow && widget) {
2324             widget->topLevelWidget()->raise();
2325 #if HAVE_X11
2326             KWindowSystem::unminimizeWindow(widget->topLevelWidget()->winId());
2327 #else
2328             //TODO
2329 #endif
2330             widget->activateWindow();
2331             emit part->browserExtension()->requestFocus(part);
2332         }
2333         return jsUndefined();
2334     }
2335     case Window::Blur:
2336         // TODO
2337         return jsUndefined();
2338     case Window::BToA:
2339     case Window::AToB: {
2340         if (!s.is8Bit()) {
2341             return jsUndefined();
2342         }
2343         QByteArray  in, out;
2344         char *binData = s.ascii();
2345         in = QByteArray(binData, s.size());
2346         if (id == Window::AToB) {
2347             out = QByteArray::fromBase64(in);
2348         } else {
2349             out = in.toBase64();
2350         }
2351         UChar *d = new UChar[out.size()];
2352         for (int i = 0; i < out.size(); i++) {
2353             d[i].uc = (uchar) out[i];
2354         }
2355         UString ret(d, out.size(), false /*no copy*/);
2356         return jsString(ret);
2357     }
2358     case Window::PostMessage: {
2359         // Get our own origin.
2360         if (!part->xmlDocImpl()) {
2361             setDOMException(exec, DOM::DOMException::SECURITY_ERR);
2362             return jsUndefined();
2363         }
2364 
2365         QString sourceOrigin = part->xmlDocImpl()->origin()->toString();
2366         QString targetOrigin = args[1]->toString(exec).qstring();
2367         QUrl    targetURL(targetOrigin);
2368         // qCDebug(KHTML_LOG) << "postMessage targetting:" << targetOrigin;
2369 
2370         // Make sure we get * or an absolute URL for target origin
2371         if (targetOrigin != QLatin1String("*") &&
2372                 !(targetURL.isValid() && !targetURL.isRelative() && !targetURL.isEmpty())) {
2373             setDOMException(exec, DOM::DOMException::SYNTAX_ERR);
2374             return jsUndefined();
2375         }
2376 
2377         // Grab a snapshot of the data. Unfortunately it means we copy it
2378         // twice, but it's simpler than having separate code for swizzling
2379         // prototype pointers.
2380         JSValue *payload = cloneData(exec, args[0]);
2381 
2382         // Queue the actual action, for after script execution.
2383         window->m_delayed.append(new DelayedPostMessage(part, sourceOrigin, targetOrigin, payload));
2384     }
2385 
2386     };
2387 
2388     // now unsafe functions..
2389     if (!window->isSafeScript(exec)) {
2390         return jsUndefined();
2391     }
2392 
2393     switch (id) {
2394     case Window::ScrollBy:
2395         if (args.size() == 2 && widget) {
2396             widget->scrollBy(args[0]->toInt32(exec), args[1]->toInt32(exec));
2397         }
2398         return jsUndefined();
2399     case Window::Scroll:
2400     case Window::ScrollTo:
2401         if (args.size() == 2 && widget) {
2402             widget->setContentsPos(args[0]->toInt32(exec), args[1]->toInt32(exec));
2403         }
2404         return jsUndefined();
2405     case Window::MoveBy: {
2406         KHTMLSettings::KJSWindowMovePolicy policy =
2407             part->settings()->windowMovePolicy(part->url().host());
2408         if (policy == KHTMLSettings::KJSWindowMoveAllow && args.size() == 2 && widget) {
2409             KParts::BrowserExtension *ext = part->browserExtension();
2410             if (ext) {
2411                 QWidget *tl = widget->topLevelWidget();
2412                 QRect sg = QApplication::desktop()->screenGeometry(tl);
2413 
2414                 QPoint dest = tl->pos() + QPoint(args[0]->toInt32(exec), args[1]->toInt32(exec));
2415                 // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
2416                 if (dest.x() >= sg.x() && dest.y() >= sg.x() &&
2417                         dest.x() + tl->width() <= sg.width() + sg.x() &&
2418                         dest.y() + tl->height() <= sg.height() + sg.y()) {
2419                     emit ext->moveTopLevelWidget(dest.x(), dest.y());
2420                 }
2421             }
2422         }
2423         return jsUndefined();
2424     }
2425     case Window::MoveTo: {
2426         KHTMLSettings::KJSWindowMovePolicy policy =
2427             part->settings()->windowMovePolicy(part->url().host());
2428         if (policy == KHTMLSettings::KJSWindowMoveAllow && args.size() == 2 && widget) {
2429             KParts::BrowserExtension *ext = part->browserExtension();
2430             if (ext) {
2431                 QWidget *tl = widget->topLevelWidget();
2432                 QRect sg = QApplication::desktop()->screenGeometry(tl);
2433 
2434                 QPoint dest(args[0]->toInt32(exec) + sg.x(), args[1]->toInt32(exec) + sg.y());
2435                 // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
2436                 if (dest.x() >= sg.x() && dest.y() >= sg.y() &&
2437                         dest.x() + tl->width() <= sg.width() + sg.x() &&
2438                         dest.y() + tl->height() <= sg.height() + sg.y()) {
2439                     emit ext->moveTopLevelWidget(dest.x(), dest.y());
2440                 }
2441             }
2442         }
2443         return jsUndefined();
2444     }
2445     case Window::ResizeBy: {
2446         KHTMLSettings::KJSWindowResizePolicy policy =
2447             part->settings()->windowResizePolicy(part->url().host());
2448         if (policy == KHTMLSettings::KJSWindowResizeAllow
2449                 && args.size() == 2 && widget) {
2450             QWidget *tl = widget->topLevelWidget();
2451             QRect geom = tl->frameGeometry();
2452             window->resizeTo(tl,
2453                              geom.width() + args[0]->toInt32(exec),
2454                              geom.height() + args[1]->toInt32(exec));
2455         }
2456         return jsUndefined();
2457     }
2458     case Window::ResizeTo: {
2459         KHTMLSettings::KJSWindowResizePolicy policy =
2460             part->settings()->windowResizePolicy(part->url().host());
2461         if (policy == KHTMLSettings::KJSWindowResizeAllow
2462                 && args.size() == 2 && widget) {
2463             QWidget *tl = widget->topLevelWidget();
2464             window->resizeTo(tl, args[0]->toInt32(exec), args[1]->toInt32(exec));
2465         }
2466         return jsUndefined();
2467     }
2468     case Window::SetTimeout:
2469     case Window::SetInterval: {
2470         bool singleShot;
2471         int i; // timeout interval
2472         if (args.size() == 0) {
2473             return jsUndefined();
2474         }
2475         if (args.size() > 1) {
2476             singleShot = (id == Window::SetTimeout);
2477             i = args[1]->toInt32(exec);
2478         } else {
2479             // second parameter is missing. Emulate Mozilla behavior.
2480             singleShot = true;
2481             i = 4;
2482         }
2483         if (v->type() == StringType) {
2484             int r = (const_cast<Window *>(window))->winq->installTimeout(Identifier(s), i, singleShot);
2485             return jsNumber(r);
2486         } else if (v->type() == ObjectType && v->getObject()->implementsCall()) {
2487             JSObject *func = v->getObject();
2488             List funcArgs;
2489             ListIterator it = args.begin();
2490             int argno = 0;
2491             while (it != args.end()) {
2492                 JSValue *arg = it++;
2493                 if (argno++ >= 2) {
2494                     funcArgs.append(arg);
2495                 }
2496             }
2497             if (args.size() < 2) {
2498                 funcArgs.append(jsNumber(i));
2499             }
2500             int r = (const_cast<Window *>(window))->winq->installTimeout(func, funcArgs, i, singleShot);
2501             return jsNumber(r);
2502         } else {
2503             return jsUndefined();
2504         }
2505     }
2506     case Window::ClearTimeout:
2507     case Window::ClearInterval:
2508         (const_cast<Window *>(window))->winq->clearTimeout(v->toInt32(exec));
2509         return jsUndefined();
2510     case Window::Print:
2511         if (widget) {
2512             // ### TODO emit onbeforeprint event
2513             widget->print();
2514             // ### TODO emit onafterprint event
2515         }
2516     case Window::CaptureEvents:
2517     case Window::ReleaseEvents:
2518         // Do nothing for now. These are NS-specific legacy calls.
2519         break;
2520     case Window::AddEventListener: {
2521         JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]);
2522         if (listener) {
2523             DOM::DocumentImpl *docimpl = static_cast<DOM::DocumentImpl *>(part->document().handle());
2524             if (docimpl) {
2525                 docimpl->addWindowEventListener(EventName::fromString(args[0]->toString(exec).domString()), listener, args[2]->toBoolean(exec));
2526             } else {
2527                 qCWarning(KHTML_LOG) << "document missing on Window::AddEventListener. why?";
2528             }
2529         }
2530         return jsUndefined();
2531     }
2532     case Window::RemoveEventListener: {
2533         JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]);
2534         if (listener) {
2535             DOM::DocumentImpl *docimpl = static_cast<DOM::DocumentImpl *>(part->document().handle());
2536             if (docimpl) {
2537                 docimpl->removeWindowEventListener(EventName::fromString(args[0]->toString(exec).domString()), listener, args[2]->toBoolean(exec));
2538             } else {
2539                 qCWarning(KHTML_LOG) << "document missing on Window::RemoveEventListener. why?";
2540             }
2541         }
2542         return jsUndefined();
2543     }
2544 
2545     }
2546     return jsUndefined();
2547 }
2548 
2549 ////////////////////// ScheduledAction ////////////////////////
2550 
ScheduledAction(JSObject * _func,const List & _args,const DateTimeMS & _nextTime,int _interval,bool _singleShot,int _timerId)2551 ScheduledAction::ScheduledAction(JSObject *_func, const List &_args, const DateTimeMS &_nextTime, int _interval, bool _singleShot,
2552                                  int _timerId)
2553 {
2554     //qCDebug(KHTML_LOG) << "ScheduledAction::ScheduledAction(isFunction) " << this;
2555     func = static_cast<JSObject *>(_func);
2556     args = _args;
2557     isFunction = true;
2558     singleShot = _singleShot;
2559     nextTime = _nextTime;
2560     interval = _interval;
2561     executing = false;
2562     timerId = _timerId;
2563 }
2564 
ScheduledAction(const QString & _code,const DateTimeMS & _nextTime,int _interval,bool _singleShot,int _timerId)2565 ScheduledAction::ScheduledAction(const QString &_code, const DateTimeMS &_nextTime, int _interval, bool _singleShot, int _timerId)
2566 {
2567     //qCDebug(KHTML_LOG) << "ScheduledAction::ScheduledAction(!isFunction) " << this;
2568     //func = 0;
2569     //args = 0;
2570     func = nullptr;
2571     code = _code;
2572     isFunction = false;
2573     singleShot = _singleShot;
2574     nextTime = _nextTime;
2575     interval = _interval;
2576     executing = false;
2577     timerId = _timerId;
2578 }
2579 
execute(Window * window)2580 bool ScheduledAction::execute(Window *window)
2581 {
2582     KHTMLPart *part = qobject_cast<KHTMLPart *>(window->m_frame->m_part);
2583     if (!part || !part->jScriptEnabled()) {
2584         return false;
2585     }
2586     ScriptInterpreter *interpreter = static_cast<ScriptInterpreter *>(part->jScript()->interpreter());
2587 
2588     interpreter->setProcessingTimerCallback(true);
2589 
2590     //qCDebug(KHTML_LOG) << "ScheduledAction::execute " << this;
2591     if (isFunction) {
2592         if (func->implementsCall()) {
2593             // #### check this
2594             Q_ASSERT(part);
2595             if (part) {
2596                 KJS::Interpreter *interpreter = part->jScript()->interpreter();
2597                 ExecState *exec = interpreter->globalExec();
2598                 Q_ASSERT(window == interpreter->globalObject());
2599                 JSObject *obj(window);
2600                 func->call(exec, obj, args); // note that call() creates its own execution state for the func call
2601                 if (exec->hadException()) {
2602                     exec->clearException();
2603                 }
2604 
2605                 // Update our document's rendering following the execution of the timeout callback.
2606                 part->document().updateRendering();
2607             }
2608         }
2609     } else {
2610         part->executeScript(DOM::Node(), code);
2611     }
2612 
2613     interpreter->setProcessingTimerCallback(false);
2614     return true;
2615 }
2616 
mark()2617 void ScheduledAction::mark()
2618 {
2619     if (func && !func->marked()) {
2620         func->mark();
2621     }
2622 }
2623 
~ScheduledAction()2624 ScheduledAction::~ScheduledAction()
2625 {
2626     args.reset();
2627     //qCDebug(KHTML_LOG) << "ScheduledAction::~ScheduledAction " << this;
2628 }
2629 
2630 ////////////////////// WindowQObject ////////////////////////
2631 
WindowQObject(Window * w)2632 WindowQObject::WindowQObject(Window *w)
2633     : parent(w)
2634 {
2635     //qCDebug(KHTML_LOG) << "WindowQObject::WindowQObject " << this;
2636     if (!parent->m_frame) {
2637         // qCDebug(KHTML_LOG) << "WARNING: null part in " ;
2638     } else
2639         connect(parent->m_frame, SIGNAL(destroyed()),
2640                 this, SLOT(parentDestroyed()));
2641     pauseLevel  = 0;
2642     lastTimerId = 0;
2643     currentlyDispatching = false;
2644 }
2645 
~WindowQObject()2646 WindowQObject::~WindowQObject()
2647 {
2648     //qCDebug(KHTML_LOG) << "WindowQObject::~WindowQObject " << this;
2649     parentDestroyed(); // reuse same code
2650 }
2651 
parentDestroyed()2652 void WindowQObject::parentDestroyed()
2653 {
2654     killTimers();
2655 
2656     while (!scheduledActions.isEmpty()) {
2657         delete scheduledActions.takeFirst();
2658     }
2659     scheduledActions.clear();
2660 }
2661 
pauseTimers()2662 void WindowQObject::pauseTimers()
2663 {
2664     ++pauseLevel;
2665     if (pauseLevel == 1) {
2666         pauseStart = DateTimeMS::now();
2667     }
2668 }
2669 
resumeTimers()2670 void WindowQObject::resumeTimers()
2671 {
2672     if (pauseLevel == 1) {
2673         // Adjust all timers by the delay length, making sure there is a minimum
2674         // margin from current time, however, so we don't go stampeding off if
2675         // there is some unwanted recursion, etc.
2676         DateTimeMS curTime          = DateTimeMS::now();
2677         DateTimeMS earliestDispatch = curTime.addMSecs(5);
2678         int delay = pauseStart.msecsTo(curTime);
2679         foreach (ScheduledAction *action, scheduledActions) {
2680             action->nextTime = action->nextTime.addMSecs(delay);
2681             if (earliestDispatch > action->nextTime) {
2682                 action->nextTime = earliestDispatch;
2683             }
2684         }
2685 
2686         // Dispatch any timers that may have been ignored if ::timerEvent fell in the middle
2687         // of a pause..
2688         timerEvent(nullptr);
2689     }
2690 
2691     --pauseLevel; // We do it afterwards so that timerEvent can know about us.
2692 }
2693 
installTimeout(const Identifier & handler,int t,bool singleShot)2694 int WindowQObject::installTimeout(const Identifier &handler, int t, bool singleShot)
2695 {
2696     int id = ++lastTimerId;
2697     if (t < 10) {
2698         t = 10;
2699     }
2700     DateTimeMS nextTime = DateTimeMS::now().addMSecs(t);
2701 
2702     ScheduledAction *action = new ScheduledAction(handler.qstring(), nextTime, t, singleShot, id);
2703     scheduledActions.append(action);
2704     setNextTimer();
2705     return id;
2706 }
2707 
installTimeout(JSValue * func,List args,int t,bool singleShot)2708 int WindowQObject::installTimeout(JSValue *func, List args, int t, bool singleShot)
2709 {
2710     JSObject *objFunc = func->getObject();
2711     if (!objFunc) {
2712         return 0;
2713     }
2714     int id = ++lastTimerId;
2715     if (t < 10) {
2716         t = 10;
2717     }
2718 
2719     DateTimeMS nextTime = DateTimeMS::now().addMSecs(t);
2720     ScheduledAction *action = new ScheduledAction(objFunc, args, nextTime, t, singleShot, id);
2721     scheduledActions.append(action);
2722     setNextTimer();
2723     return id;
2724 }
2725 
clearTimeout(int timerId)2726 void WindowQObject::clearTimeout(int timerId)
2727 {
2728     foreach (ScheduledAction *action, scheduledActions) {
2729         if (action->timerId == timerId) {
2730             scheduledActions.removeAll(action);
2731             if (!action->executing) {
2732                 delete action;
2733             }
2734             return;
2735         }
2736     }
2737 }
2738 
hasTimers() const2739 bool WindowQObject::hasTimers() const
2740 {
2741     return scheduledActions.count();
2742 }
2743 
mark()2744 void WindowQObject::mark()
2745 {
2746     foreach (ScheduledAction *action, scheduledActions) {
2747         action->mark();
2748     }
2749 }
2750 
timerEvent(QTimerEvent *)2751 void WindowQObject::timerEvent(QTimerEvent *)
2752 {
2753     killTimers();
2754 
2755     if (scheduledActions.isEmpty()) {
2756         return;
2757     }
2758 
2759     if (pauseLevel) {
2760         return;
2761     }
2762 
2763     currentlyDispatching = true;
2764 
2765     DateTimeMS current = DateTimeMS::now();
2766 
2767     // Work out which actions are to be executed. We take a separate copy of
2768     // this list since the main one may be modified during action execution
2769     QList<ScheduledAction *> toExecute;
2770     foreach (ScheduledAction *action, scheduledActions) {
2771         if (current >= action->nextTime) {
2772             toExecute.append(action);
2773         }
2774     }
2775 
2776     // ### verify that the window can't be closed (and action deleted) during execution
2777     foreach (ScheduledAction *action, toExecute) {
2778         if (!scheduledActions.count(action)) { // removed by clearTimeout()
2779             continue;
2780         }
2781 
2782         action->executing = true; // prevent deletion in clearTimeout()
2783 
2784         if (parent->part()) {
2785             bool ok = action->execute(parent);
2786             if (!ok) { // e.g. JS disabled
2787                 scheduledActions.removeAll(action);
2788             }
2789         }
2790 
2791         if (action->singleShot) {
2792             scheduledActions.removeAll(action);
2793         }
2794 
2795         action->executing = false;
2796 
2797         if (!scheduledActions.count(action)) {
2798             delete action;
2799         } else {
2800             action->nextTime = action->nextTime.addMSecs(action->interval);
2801         }
2802     }
2803 
2804     currentlyDispatching = false;
2805 
2806     // Work out when next event is to occur
2807     setNextTimer();
2808 
2809     // unless we're inside a nested context, do post-script processing
2810     if (!pauseLevel) {
2811         parent->afterScriptExecution();
2812     }
2813 }
2814 
addMSecs(int s) const2815 DateTimeMS DateTimeMS::addMSecs(int s) const
2816 {
2817     DateTimeMS c = *this;
2818     c.mTime = mTime.addMSecs(s);
2819     if (s > 0) {
2820         if (c.mTime < mTime) {
2821             c.mDate = mDate.addDays(1);
2822         }
2823     } else {
2824         if (c.mTime > mTime) {
2825             c.mDate = mDate.addDays(-1);
2826         }
2827     }
2828     return c;
2829 }
2830 
operator >(const DateTimeMS & other) const2831 bool DateTimeMS::operator >(const DateTimeMS &other) const
2832 {
2833     if (mDate > other.mDate) {
2834         return true;
2835     }
2836 
2837     if (mDate < other.mDate) {
2838         return false;
2839     }
2840 
2841     return mTime > other.mTime;
2842 }
2843 
operator >=(const DateTimeMS & other) const2844 bool DateTimeMS::operator >=(const DateTimeMS &other) const
2845 {
2846     if (mDate > other.mDate) {
2847         return true;
2848     }
2849 
2850     if (mDate < other.mDate) {
2851         return false;
2852     }
2853 
2854     return mTime >= other.mTime;
2855 }
2856 
msecsTo(const DateTimeMS & other) const2857 int DateTimeMS::msecsTo(const DateTimeMS &other) const
2858 {
2859     int d = mDate.daysTo(other.mDate);
2860     int ms = mTime.msecsTo(other.mTime);
2861     return d * 24 * 60 * 60 * 1000 + ms;
2862 }
2863 
now()2864 DateTimeMS DateTimeMS::now()
2865 {
2866     DateTimeMS t;
2867     QTime before = QTime::currentTime();
2868     t.mDate = QDate::currentDate();
2869     t.mTime = QTime::currentTime();
2870     if (t.mTime < before) {
2871         t.mDate = QDate::currentDate();    // prevent race condition in hacky way :)
2872     }
2873     return t;
2874 }
2875 
setNextTimer()2876 void WindowQObject::setNextTimer()
2877 {
2878     if (currentlyDispatching) {
2879         return;    // Will schedule at the end
2880     }
2881 
2882     if (scheduledActions.isEmpty()) {
2883         return;
2884     }
2885 
2886     QListIterator<ScheduledAction *> it(scheduledActions);
2887     DateTimeMS nextTime = it.next()->nextTime;
2888     while (it.hasNext()) {
2889         const DateTimeMS &currTime = it.next()->nextTime;
2890         if (nextTime > currTime) {
2891             nextTime = currTime;
2892         }
2893     }
2894 
2895     int nextInterval = DateTimeMS::now().msecsTo(nextTime);
2896     if (nextInterval < 0) {
2897         nextInterval = 0;
2898     }
2899     timerIds.append(startTimer(nextInterval));
2900 }
2901 
killTimers()2902 void WindowQObject::killTimers()
2903 {
2904     for (int i = 0; i < timerIds.size(); ++i) {
2905         killTimer(timerIds.at(i));
2906     }
2907     timerIds.clear();
2908 }
2909 
timeoutClose()2910 void WindowQObject::timeoutClose()
2911 {
2912     parent->closeNow();
2913 }
2914 
2915 ////////////////////// Location Object ////////////////////////
2916 
2917 const ClassInfo Location::info = { "Location", nullptr, &LocationTable, nullptr };
2918 /*
2919 @begin LocationTable 11
2920   hash      Location::Hash      DontDelete
2921   host      Location::Host      DontDelete
2922   hostname  Location::Hostname  DontDelete
2923   href      Location::Href      DontDelete
2924   pathname  Location::Pathname  DontDelete
2925   port      Location::Port      DontDelete
2926   protocol  Location::Protocol  DontDelete
2927   search    Location::Search    DontDelete
2928   [[==]]    Location::EqualEqual    DontDelete|ReadOnly
2929   assign    Location::Assign    DontDelete|Function 1
2930   toString  Location::ToString  DontDelete|Function 0
2931   replace   Location::Replace   DontDelete|Function 1
2932   reload    Location::Reload    DontDelete|Function 0
2933 @end
2934 */
KJS_IMPLEMENT_PROTOFUNC(LocationFunc)2935 KJS_IMPLEMENT_PROTOFUNC(LocationFunc)
2936 Location::Location(khtml::ChildFrame *f) : m_frame(f)
2937 {
2938     //qCDebug(KHTML_LOG) << "Location::Location " << this << " m_part=" << (void*)m_part;
2939 }
2940 
~Location()2941 Location::~Location()
2942 {
2943     //qCDebug(KHTML_LOG) << "Location::~Location " << this << " m_part=" << (void*)m_part;
2944 }
2945 
part() const2946 KParts::ReadOnlyPart *Location::part() const
2947 {
2948     return m_frame ? static_cast<KParts::ReadOnlyPart *>(m_frame->m_part) : nullptr;
2949 }
2950 
getOwnPropertySlot(ExecState * exec,const Identifier & p,PropertySlot & slot)2951 bool Location::getOwnPropertySlot(ExecState *exec, const Identifier &p, PropertySlot &slot)
2952 {
2953 #ifdef KJS_VERBOSE
2954     qCDebug(KHTML_LOG) << "Location::getOwnPropertySlot " << p.qstring() << " m_part=" << (void *)m_frame->m_part;
2955 #endif
2956 
2957     if (m_frame.isNull() || m_frame->m_part.isNull()) {
2958         return jsUndefined();
2959     }
2960 
2961     const HashEntry *entry = Lookup::findEntry(&LocationTable, p);
2962 
2963     if (entry) {
2964         // properties that work on all Location objects
2965         if (entry->value == Replace) {
2966             getSlotFromEntry<LocationFunc, Location>(entry, this, slot);
2967             return true;
2968         }
2969 
2970         // XSS check
2971         const Window *window = Window::retrieveWindow(m_frame->m_part);
2972         if (!window || !window->isSafeScript(exec)) {
2973             slot.setUndefined(this);
2974             return true;
2975         }
2976 
2977         // XSS check passed - can now dispatch normally.
2978         getSlotFromEntry<LocationFunc, Location>(entry, this, slot);
2979         return true;
2980     }
2981 
2982     return JSObject::getOwnPropertySlot(exec, p, slot);
2983 }
2984 
getValueProperty(ExecState * exec,int token) const2985 JSValue *Location::getValueProperty(ExecState *exec, int token) const
2986 {
2987     QUrl url = m_frame->m_part->url();
2988     switch (token) {
2989     case Hash: {
2990         const QString encodedHash = url.fragment(QUrl::FullyEncoded);
2991         if (encodedHash.isEmpty()) {
2992             return jsString("");
2993         }
2994         return jsString(QLatin1Char('#') + encodedHash);
2995     }
2996     case Host: {
2997         UString str = url.host();
2998         if (url.port() > 0) {
2999             str += QString(QLatin1Char(':') + QString::number(url.port()));
3000         }
3001         return jsString(str);
3002         // Note: this is the IE spec. The NS spec swaps the two, it says
3003         // "The hostname property is the concatenation of the host and port properties, separated by a colon."
3004         // Bleh.
3005     }
3006     case Hostname:
3007         return jsString(UString(url.host()));
3008     case Href:
3009         if (url.isEmpty()) {
3010             return jsString("about:blank");
3011         } else if (url.path().isEmpty()) {
3012             return jsString(UString(url.toDisplayString() + '/'));
3013         } else {
3014             return jsString(UString(url.toDisplayString()));
3015         }
3016     case Pathname:
3017         if (url.isEmpty()) {
3018             return jsString("");
3019         }
3020         return jsString(UString(url.path().isEmpty() ? QString("/") : url.path()));
3021     case Port:
3022         return jsString(UString(url.port() > 0 ? QString::number(url.port()) : QLatin1String("")));
3023     case Protocol:
3024         return jsString(UString(url.scheme() + ':'));
3025     case Search:
3026         return jsString(UString(url.query()));
3027     case EqualEqual: // [[==]]
3028         return jsString(toString(exec));
3029     }
3030     return jsUndefined();
3031 }
3032 
put(ExecState * exec,const Identifier & p,JSValue * v,int attr)3033 void Location::put(ExecState *exec, const Identifier &p, JSValue *v, int attr)
3034 {
3035 #ifdef KJS_VERBOSE
3036     qCDebug(KHTML_LOG) << "Location::put " << p.qstring() << " m_part=" << (void *)m_frame->m_part;
3037 #endif
3038     if (m_frame.isNull() || m_frame->m_part.isNull()) {
3039         return;
3040     }
3041 
3042     Window *window = Window::retrieveWindow(m_frame->m_part);
3043     if (!window) {
3044         return;
3045     }
3046 
3047     QUrl url = m_frame->m_part->url();
3048 
3049     const HashEntry *entry = Lookup::findEntry(&LocationTable, p);
3050 
3051     if (entry) {
3052 
3053         // XSS check. Only new hrefs can be set from other sites
3054         if (entry->value != Href && !window->isSafeScript(exec)) {
3055             return;
3056         }
3057 
3058         QString str = v->toString(exec).qstring();
3059         switch (entry->value) {
3060         case Href: {
3061             KHTMLPart *p = qobject_cast<KHTMLPart *>(Window::retrieveActive(exec)->part());
3062             if (p) {
3063                 url = QUrl(p->htmlDocument().completeURL(str).string());
3064             } else {
3065                 url = QUrl(str);
3066             }
3067             break;
3068         }
3069         case Hash:
3070             // Strip any leading # --- setting hash to #foo is the same as setting it to foo.
3071             if (str.startsWith(QLatin1Char('#'))) {
3072                 str = str.mid(1);
3073             }
3074 
3075             // Note that we want to do gotoAnchor even when the hash is already set, so we
3076             // scroll the destination into view.
3077 
3078             // Setting this must always provide a ref, even if just # see
3079             // HTML5 2.6.
3080             if (str.isEmpty()) {
3081                 url.setFragment("");
3082             } else {
3083                 url.setFragment(QUrl::fromPercentEncoding(str.toUtf8()), QUrl::DecodedMode);
3084             }
3085             break;
3086         case Host: {
3087             QString host = str.left(str.indexOf(":"));
3088             QString port = str.mid(str.indexOf(":") + 1);
3089             url.setHost(host);
3090             url.setPort(port.toUInt());
3091             break;
3092         }
3093         case Hostname:
3094             url.setHost(str);
3095             break;
3096         case Pathname:
3097             url.setPath(str);
3098             break;
3099         case Port:
3100             url.setPort(str.toUInt());
3101             break;
3102         case Protocol:
3103             url.setScheme(str);
3104             break;
3105         case Search:
3106             url.setQuery(str);
3107             break;
3108         }
3109     } else {
3110         JSObject::put(exec, p, v, attr);
3111         return;
3112     }
3113 
3114     window->goURL(exec, url.url());
3115 }
3116 
toPrimitive(ExecState * exec,JSType) const3117 JSValue *Location::toPrimitive(ExecState *exec, JSType) const
3118 {
3119     if (m_frame) {
3120         Window *window = Window::retrieveWindow(m_frame->m_part);
3121         if (window && window->isSafeScript(exec)) {
3122             return jsString(toString(exec));
3123         }
3124     }
3125     return jsUndefined();
3126 }
3127 
toString(ExecState * exec) const3128 UString Location::toString(ExecState *exec) const
3129 {
3130     if (m_frame) {
3131         Window *window = Window::retrieveWindow(m_frame->m_part);
3132         if (window && window->isSafeScript(exec)) {
3133             QUrl url = m_frame->m_part->url();
3134             if (url.isEmpty()) {
3135                 return "about:blank";
3136             } else if (url.path().isEmpty()) {
3137                 return QString(url.toDisplayString() + '/');
3138             } else {
3139                 return url.toDisplayString();
3140             }
3141         }
3142     }
3143     return "";
3144 }
3145 
callAsFunction(ExecState * exec,JSObject * thisObj,const List & args)3146 JSValue *LocationFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
3147 {
3148     KJS_CHECK_THIS(Location, thisObj);
3149     Location *location = static_cast<Location *>(thisObj);
3150     KParts::ReadOnlyPart *part = location->part();
3151 
3152     if (!part) {
3153         return jsUndefined();
3154     }
3155 
3156     Window *window = Window::retrieveWindow(part);
3157 
3158     if (!window->isSafeScript(exec) && id != Location::Replace) {
3159         return jsUndefined();
3160     }
3161 
3162     switch (id) {
3163     case Location::Assign:
3164         window->goURL(exec, args[0]->toString(exec).qstring());
3165         break;
3166     case Location::Replace:
3167         window->goURL(exec, args[0]->toString(exec).qstring(), true/*lock history*/);
3168         break;
3169     case Location::Reload: {
3170         KHTMLPart *khtmlpart = qobject_cast<KHTMLPart *>(part);
3171         if (khtmlpart) {
3172             khtmlpart->scheduleRedirection(-1, part->url().toString(), true/*lock history*/);
3173         } else {
3174             part->openUrl(part->url());
3175         }
3176         break;
3177     }
3178     case Location::ToString:
3179         return jsString(location->toString(exec));
3180     }
3181     return jsUndefined();
3182 }
3183 
3184 ////////////////////// External Object ////////////////////////
3185 
3186 const ClassInfo External::info = { "External", nullptr, nullptr, nullptr };
3187 /*
3188 @begin ExternalTable 4
3189   addFavorite   External::AddFavorite   DontDelete|Function 1
3190 @end
3191 */
KJS_IMPLEMENT_PROTOFUNC(ExternalFunc)3192 KJS_IMPLEMENT_PROTOFUNC(ExternalFunc)
3193 
3194 bool External::getOwnPropertySlot(ExecState *exec, const Identifier &p, PropertySlot &propertySlot)
3195 {
3196     return getStaticFunctionSlot<ExternalFunc, JSObject>(exec, &ExternalTable, this, p, propertySlot);
3197 }
3198 
callAsFunction(ExecState * exec,JSObject * thisObj,const List & args)3199 JSValue *ExternalFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
3200 {
3201     KJS_CHECK_THIS(External, thisObj);
3202     External *external = static_cast<External *>(thisObj);
3203 
3204     KHTMLPart *part = external->part;
3205     if (!part) {
3206         return jsUndefined();
3207     }
3208 
3209     switch (id) {
3210     case External::AddFavorite: {
3211 #ifndef KONQ_EMBEDDED
3212         KHTMLView *widget = part->view();
3213         if (!widget->dialogsAllowed()) {
3214             return jsUndefined();
3215         }
3216         part->xmlDocImpl()->updateRendering();
3217         if (args.size() != 1 && args.size() != 2) {
3218             return jsUndefined();
3219         }
3220 
3221         QString url = args[0]->toString(exec).qstring();
3222         QString title;
3223         if (args.size() == 2) {
3224             title = args[1]->toString(exec).qstring();
3225         }
3226 
3227         // AK - don't do anything yet, for the moment i
3228         // just wanted the base js handling code in cvs
3229         return jsUndefined();
3230 
3231         QString question;
3232         if (title.isEmpty())
3233             question = i18n("Do you want a bookmark pointing to the location \"%1\" to be added to your collection?",
3234                             url);
3235         else
3236             question = i18n("Do you want a bookmark pointing to the location \"%1\" titled \"%2\" to be added to your collection?",
3237                             url, title);
3238 
3239         emit part->browserExtension()->requestFocus(part);
3240 
3241         QString caption;
3242         if (!part->url().host().isEmpty()) {
3243             caption = part->url().host() + " - ";
3244         }
3245         caption += i18n("JavaScript Attempted Bookmark Insert");
3246 
3247         if (KMessageBox::warningYesNo(
3248                     widget, question, caption,
3249                     KGuiItem(i18n("Insert")), KGuiItem(i18n("Disallow"))) == KMessageBox::Yes) {
3250             KBookmarkManager *mgr = KBookmarkManager::userBookmarksManager();
3251             KBookmarkDialog dlg(mgr, nullptr);
3252             dlg.addBookmark(title, QUrl(url), KIO::iconNameForUrl(QUrl(url)));
3253         }
3254 #else
3255         return jsUndefined();
3256 #endif
3257         break;
3258     }
3259     default:
3260         return jsUndefined();
3261     }
3262 
3263     return jsUndefined();
3264 }
3265 
3266 ////////////////////// History Object ////////////////////////
3267 
3268 const ClassInfo History::info = { "History", nullptr, nullptr, nullptr };
3269 /*
3270 @begin HistoryTable 4
3271   length    History::Length     DontDelete|ReadOnly
3272   back      History::Back       DontDelete|Function 0
3273   forward   History::Forward    DontDelete|Function 0
3274   go        History::Go     DontDelete|Function 1
3275 @end
3276 */
KJS_IMPLEMENT_PROTOFUNC(HistoryFunc)3277 KJS_IMPLEMENT_PROTOFUNC(HistoryFunc)
3278 
3279 bool History::getOwnPropertySlot(ExecState *exec, const Identifier &p, PropertySlot &slot)
3280 {
3281     return getStaticPropertySlot<HistoryFunc, History, JSObject>(exec, &HistoryTable, this, p, slot);
3282 }
3283 
getValueProperty(ExecState *,int token) const3284 JSValue *History::getValueProperty(ExecState *, int token) const
3285 {
3286     // if previous or next is implemented, make sure it is not a major
3287     // privacy leak (see i.e. http://security.greymagic.com/adv/gm005-op/)
3288     switch (token) {
3289     case Length: {
3290         if (!part) {
3291             return jsNumber(0);
3292         }
3293 
3294         KParts::BrowserExtension *ext = part->browserExtension();
3295         if (!ext) {
3296             return jsNumber(0);
3297         }
3298 
3299         KParts::BrowserInterface *iface = ext->browserInterface();
3300         if (!iface) {
3301             return jsNumber(0);
3302         }
3303 
3304         QVariant length = iface->property("historyLength");
3305 
3306         if (length.type() != QVariant::UInt) {
3307             return jsNumber(0);
3308         }
3309 
3310         return jsNumber(length.toUInt());
3311     }
3312     default:
3313         // qCDebug(KHTML_LOG) << "WARNING: Unhandled token in History::getValueProperty : " << token;
3314         return jsUndefined();
3315     }
3316 }
3317 
callAsFunction(ExecState * exec,JSObject * thisObj,const List & args)3318 JSValue *HistoryFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
3319 {
3320     KJS_CHECK_THIS(History, thisObj);
3321     History *history = static_cast<History *>(thisObj);
3322 
3323     JSValue *v = args[0];
3324     double n = 0.0;
3325     if (v) {
3326         n = v->toInteger(exec);
3327     }
3328 
3329     int steps;
3330     switch (id) {
3331     case History::Back:
3332         steps = -1;
3333         break;
3334     case History::Forward:
3335         steps = 1;
3336         break;
3337     case History::Go:
3338         steps = (int)n;
3339         break;
3340     default:
3341         return jsUndefined();
3342     }
3343 
3344     // Special case for go(0) from a frame -> reload only the frame
3345     // go(i!=0) from a frame navigates into the history of the frame only,
3346     // in both IE and NS (but not in Mozilla).... we can't easily do that
3347     // in Konqueror...
3348     if (!steps) { // add && history->part->parentPart() to get only frames, but doesn't matter
3349         history->part->openUrl(history->part->url());   /// ## need args.reload=true?
3350     } else {
3351         // Delay it.
3352         // Testcase: history.back(); alert("hello");
3353         Window *window = Window::retrieveWindow(history->part);
3354         window->delayedGoHistory(steps);
3355     }
3356     return jsUndefined();
3357 }
3358 
3359 } // namespace KJS
3360 
3361