File indexing completed on 2024-04-28 15:23:19

0001 /*
0002  *  This file is part of the KDE libraries
0003  *  Copyright (C) 2000-2003 Harri Porten (porten@kde.org)
0004  *  Copyright (C) 2001-2003 David Faure (faure@kde.org)
0005  *  Copyright (C) 2003 Apple Computer, Inc.
0006  *  Copyright (C) 2006, 2008-2010  Maksim Orlovich (maksim@kde.org)
0007  *
0008  *  This library is free software; you can redistribute it and/or
0009  *  modify it under the terms of the GNU Library General Public
0010  *  License as published by the Free Software Foundation; either
0011  *  version 2 of the License, or (at your option) any later version.
0012  *
0013  *  This library is distributed in the hope that it will be useful,
0014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0016  *  Library General Public License for more details.
0017  *
0018  *  You should have received a copy of the GNU Library General Public
0019  *  License along with this library; if not, write to the Free Software
0020  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
0021  */
0022 
0023 #include "kjs_window.h"
0024 #include "kjs_data.h"
0025 
0026 #include <khtmlview.h>
0027 #include <khtml_part.h>
0028 #include <khtmlpart_p.h>
0029 #include <khtml_settings.h>
0030 #include <xml/dom2_eventsimpl.h>
0031 #include <xml/dom_docimpl.h>
0032 #include <dom/html_document.h>
0033 #include <html/html_documentimpl.h>
0034 #include <rendering/render_frames.h>
0035 
0036 #include <config-khtml.h>
0037 
0038 #include <QTimer>
0039 #include <QApplication>
0040 #include <QDesktopWidget>
0041 #include <qinputdialog.h>
0042 #include "khtml_debug.h"
0043 #include <kmessagebox.h>
0044 #include <klocalizedstring.h>
0045 #include <kparts/browserinterface.h>
0046 #include <kwindowsystem.h>
0047 
0048 #ifndef KONQ_EMBEDDED
0049 #include <kbookmarkmanager.h>
0050 #include <kbookmarkdialog.h>
0051 #endif
0052 #include <assert.h>
0053 #include <QStyle>
0054 #include <QTextDocument>
0055 #include <kstringhandler.h>
0056 
0057 #include "kjs_proxy.h"
0058 #include "kjs_navigator.h"
0059 #include "kjs_mozilla.h"
0060 #include "kjs_html.h"
0061 #include "kjs_range.h"
0062 #include "kjs_traversal.h"
0063 #include "kjs_css.h"
0064 #include "kjs_events.h"
0065 #include "kjs_audio.h"
0066 #include "kjs_context2d.h"
0067 #include "kjs_xpath.h"
0068 #include "kjs_scriptable.h"
0069 #include "xmlhttprequest.h"
0070 #include "xmlserializer.h"
0071 #include "domparser.h"
0072 #include "kjs_arraybuffer.h"
0073 #include "kjs_arraytyped.h"
0074 
0075 #include <rendering/render_replaced.h>
0076 
0077 using namespace KJS;
0078 using namespace DOM;
0079 
0080 namespace KJS
0081 {
0082 
0083 class History : public JSObject
0084 {
0085     friend class HistoryFunc;
0086 public:
0087     History(ExecState *exec, KHTMLPart *p)
0088         : JSObject(exec->lexicalInterpreter()->builtinObjectPrototype()), part(p) { }
0089     using KJS::JSObject::getOwnPropertySlot;
0090     bool getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot) override;
0091     JSValue *getValueProperty(ExecState *exec, int token) const;
0092     const ClassInfo *classInfo() const override
0093     {
0094         return &info;
0095     }
0096     static const ClassInfo info;
0097     enum { Back, Forward, Go, Length };
0098 private:
0099     QPointer<KHTMLPart> part;
0100 };
0101 
0102 class External : public JSObject
0103 {
0104     friend class ExternalFunc;
0105 public:
0106     External(ExecState *exec, KHTMLPart *p)
0107         : JSObject(exec->lexicalInterpreter()->builtinObjectPrototype()), part(p) { }
0108     using KJS::JSObject::getOwnPropertySlot;
0109     bool getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot) override;
0110     const ClassInfo *classInfo() const override
0111     {
0112         return &info;
0113     }
0114     static const ClassInfo info;
0115     enum { AddFavorite };
0116 private:
0117     QPointer<KHTMLPart> part;
0118 };
0119 } //namespace KJS
0120 
0121 #include "kjs_window.lut.h"
0122 
0123 namespace KJS
0124 {
0125 
0126 ////////////////////// Screen Object ////////////////////////
0127 
0128 // table for screen object
0129 /*
0130 @begin ScreenTable 7
0131   height        Screen::Height      DontEnum|ReadOnly
0132   width         Screen::Width       DontEnum|ReadOnly
0133   colorDepth    Screen::ColorDepth  DontEnum|ReadOnly
0134   pixelDepth    Screen::PixelDepth  DontEnum|ReadOnly
0135   availLeft     Screen::AvailLeft   DontEnum|ReadOnly
0136   availTop      Screen::AvailTop    DontEnum|ReadOnly
0137   availHeight   Screen::AvailHeight DontEnum|ReadOnly
0138   availWidth    Screen::AvailWidth  DontEnum|ReadOnly
0139 @end
0140 */
0141 
0142 const ClassInfo Screen::info = { "Screen", nullptr, &ScreenTable, nullptr };
0143 
0144 // We set the object prototype so that toString is implemented
0145 Screen::Screen(ExecState *exec)
0146     : JSObject(exec->lexicalInterpreter()->builtinObjectPrototype()) {}
0147 
0148 bool Screen::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot)
0149 {
0150 #ifdef KJS_VERBOSE
0151     qCDebug(KHTML_LOG) << "Screen::getPropertyName " << propertyName.qstring();
0152 #endif
0153     return getStaticValueSlot<Screen, JSObject>(exec, &ScreenTable, this, propertyName, slot);
0154 }
0155 
0156 JSValue *Screen::getValueProperty(ExecState *exec, int token) const
0157 {
0158     QWidget *thisWidget = Window::retrieveActive(exec)->part()->widget();
0159     QRect sg = QApplication::desktop()->screenGeometry(thisWidget);
0160 
0161     switch (token) {
0162     case Height:
0163         return jsNumber(sg.height());
0164     case Width:
0165         return jsNumber(sg.width());
0166     case ColorDepth:
0167     case PixelDepth:
0168         return jsNumber(thisWidget->depth());
0169     case AvailLeft: {
0170 #if HAVE_X11 && ! defined K_WS_QTONLY
0171         QRect clipped = KWindowSystem::workArea().intersected(sg);
0172         return jsNumber(clipped.x() - sg.x());
0173 #else
0174         return jsNumber(10);
0175 #endif
0176     }
0177     case AvailTop: {
0178 #if HAVE_X11 && ! defined K_WS_QTONLY
0179         QRect clipped = KWindowSystem::workArea().intersected(sg);
0180         return jsNumber(clipped.y() - sg.y());
0181 #else
0182         return jsNumber(10);
0183 #endif
0184     }
0185     case AvailHeight: {
0186 #if HAVE_X11 && ! defined K_WS_QTONLY
0187         QRect clipped = KWindowSystem::workArea().intersected(sg);
0188         return jsNumber(clipped.height());
0189 #else
0190         return jsNumber(100);
0191 #endif
0192     }
0193     case AvailWidth: {
0194 #if HAVE_X11 && ! defined K_WS_QTONLY
0195         QRect clipped = KWindowSystem::workArea().intersected(sg);
0196         return jsNumber(clipped.width());
0197 #else
0198         return jsNumber(100);
0199 #endif
0200     }
0201     default:
0202         // qCDebug(KHTML_LOG) << "WARNING: Screen::getValueProperty unhandled token " << token;
0203         return jsUndefined();
0204     }
0205 }
0206 
0207 ////////////////////// Console Object ////////////////////////
0208 
0209 // table for console object
0210 /*
0211 @begin ConsoleTable 7
0212   assert        Console::Assert     DontEnum|Function 1
0213   log           Console::Log        DontEnum|Function 1
0214   debug         Console::Debug      DontEnum|Function 1
0215   warn          Console::Warn       DontEnum|Function 1
0216   error         Console::Error      DontEnum|Function 1
0217   info          Console::Info       DontEnum|Function 1
0218   clear         Console::Clear      DontEnum|Function 0
0219 @end
0220 */
0221 
0222 KJS_IMPLEMENT_PROTOFUNC(ConsoleFunc)
0223 
0224 const ClassInfo Console::info = { "Console", nullptr, &ConsoleTable, nullptr };
0225 
0226 // We set the object prototype so that toString is implemented
0227 Console::Console(ExecState *exec)
0228     : JSObject(exec->lexicalInterpreter()->builtinObjectPrototype()) {}
0229 
0230 bool Console::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot)
0231 {
0232 #ifdef KJS_VERBOSE
0233     qCDebug(KHTML_LOG) << "Console::getPropertyName " << propertyName.qstring();
0234 #endif
0235     return getStaticFunctionSlot<ConsoleFunc, JSObject>(exec, &ConsoleTable, this, propertyName, slot);
0236 }
0237 
0238 void printMessage(Console::MessageType msgType, const UString &message)
0239 {
0240     const char *type;
0241     switch (msgType) {
0242     case Console::DebugType:
0243         type = "DEBUG";
0244         break;
0245     case Console::ErrorType:
0246         type = "ERROR";
0247         break;
0248     case Console::InfoType:
0249         type = "INFO";
0250         break;
0251     case Console::LogType:
0252         type = "LOG";
0253         break;
0254     case Console::WarnType:
0255         type = "WARN";
0256         break;
0257 
0258     default:
0259         type = "UNKNOWN";
0260         ASSERT_NOT_REACHED();
0261     }
0262     // qCDebug(KHTML_LOG) << "[" << type << "]\t" << message.ascii();
0263 }
0264 
0265 JSValue *consolePrintf(ExecState *exec, Console::MessageType msgType, const List &args)
0266 {
0267     if (!args[0]->isString()) {
0268         return jsUndefined();
0269     }
0270     UString output = args[0]->toString(exec);
0271     if (exec->hadException()) {
0272         return jsUndefined();
0273     }
0274     int size = output.size();
0275     int arg = 1;
0276     int last = 0;
0277     UString composedOutput;
0278     for (int i = 0; i < size; ++i) {
0279         if (!(output[i] == '%')) {
0280             continue;
0281         }
0282         if (i + 1 >= size) {
0283             break;
0284         }
0285 
0286         UString replace;
0287         switch (output[i + 1].uc) {
0288         case 's': {
0289             if (args[arg]->isString()) {
0290                 replace = args[arg]->toString(exec);
0291                 ++arg;
0292             }
0293             break;
0294         }
0295         case 'f':
0296         case 'i':
0297         case 'd': {
0298             if (args[arg]->isNumber()) {
0299                 double val = args[arg]->toNumber(exec);
0300                 replace = UString::from(val);
0301                 ++arg;
0302             }
0303             break;
0304         }
0305         case 'o':
0306         case 'c':
0307             //not yet implemented skip me
0308             i += 1;
0309             ++arg;
0310 
0311         default:
0312             continue;
0313         }
0314         if (exec->hadException()) {
0315             return jsUndefined();
0316         }
0317         composedOutput += output.substr(last, i - last);
0318         composedOutput += replace;
0319         i += 1;
0320         last = i + 1;
0321     }
0322 
0323     if (last == 0) { // no % magic used, just copy the original
0324         composedOutput = output;
0325     } else {
0326         composedOutput += output.substr(last);
0327     }
0328 
0329     printMessage(msgType, composedOutput);
0330     return jsUndefined();
0331 }
0332 
0333 JSValue *ConsoleFunc::callAsFunction(ExecState *exec, JSObject * /*thisObj*/, const List &args)
0334 {
0335     switch (id) {
0336     case Console::Assert: {
0337         JSType type = args[0]->type();
0338         bool assertFailed = false;
0339         switch (type) {
0340         case UnspecifiedType:
0341         case NullType:
0342         case UndefinedType:
0343             assertFailed = true;
0344             break;
0345         case BooleanType:
0346             assertFailed = !args[0]->getBoolean();
0347             break;
0348         case NumberType:
0349         case StringType:
0350         case ObjectType:
0351         case GetterSetterType:
0352             assertFailed = false;
0353             break;
0354         default:
0355             assertFailed = true;
0356             ASSERT_NOT_REACHED();
0357             break;
0358         }
0359 
0360         if (assertFailed) {
0361             // ignore further parameter for now..
0362             if (args.size() > 1 && args[1]->isString()) {
0363                 printMessage(Console::ErrorType, args[1]->getString());
0364             } else {
0365                 printMessage(Console::ErrorType, "Assert failed!");
0366             }
0367         }
0368         return jsUndefined();
0369     }
0370     case Console::Log:
0371         return consolePrintf(exec, Console::LogType, args);
0372     case Console::Debug:
0373         return consolePrintf(exec, Console::DebugType, args);
0374     case Console::Warn:
0375         return consolePrintf(exec, Console::WarnType, args);
0376     case Console::Error:
0377         return consolePrintf(exec, Console::ErrorType, args);
0378     case Console::Info:
0379         return consolePrintf(exec, Console::InfoType, args);
0380     case Console::Clear:
0381         // TODO: clear the console
0382         return jsUndefined();
0383     }
0384     return jsUndefined();
0385 }
0386 
0387 ////////////////////// Window Object ////////////////////////
0388 
0389 const ClassInfo Window::info = { "Window", &DOMAbstractView::info, &WindowTable, nullptr };
0390 
0391 /*
0392 @begin WindowTable 233
0393   atob      Window::AToB        DontDelete|Function 1
0394   btoa      Window::BToA        DontDelete|Function 1
0395   closed    Window::Closed      DontDelete|ReadOnly
0396   crypto    Window::Crypto      DontDelete|ReadOnly
0397   defaultStatus Window::DefaultStatus   DontDelete
0398   defaultstatus Window::DefaultStatus   DontDelete
0399   status    Window::Status      DontDelete
0400   document  Window::Document    DontDelete|ReadOnly
0401   frameElement      Window::FrameElement        DontDelete|ReadOnly
0402   frames    Window::Frames      DontDelete
0403   history   Window::_History    DontDelete|ReadOnly
0404   external  Window::_External   DontDelete|ReadOnly
0405   event     Window::Event       DontDelete|ReadOnly
0406   innerHeight   Window::InnerHeight DontDelete|ReadOnly
0407   innerWidth    Window::InnerWidth  DontDelete|ReadOnly
0408   length    Window::Length      DontDelete
0409   location  Window::_Location   DontDelete
0410   name      Window::Name        DontDelete
0411   navigator Window::_Navigator  DontDelete|ReadOnly
0412   clientInformation Window::ClientInformation   DontDelete|ReadOnly
0413   konqueror Window::_Konqueror  DontDelete
0414   offscreenBuffering    Window::OffscreenBuffering  DontDelete|ReadOnly
0415   opener    Window::Opener      DontDelete|ReadOnly
0416   outerHeight   Window::OuterHeight DontDelete|ReadOnly
0417   outerWidth    Window::OuterWidth  DontDelete|ReadOnly
0418   pageXOffset   Window::PageXOffset DontDelete|ReadOnly
0419   pageYOffset   Window::PageYOffset DontDelete|ReadOnly
0420   parent    Window::Parent      DontDelete
0421   personalbar   Window::Personalbar DontDelete
0422   screenX   Window::ScreenX     DontDelete|ReadOnly
0423   screenY   Window::ScreenY     DontDelete|ReadOnly
0424   scrollbars    Window::Scrollbars  DontDelete|ReadOnly
0425   scroll    Window::Scroll      DontDelete|Function 2
0426   scrollBy  Window::ScrollBy    DontDelete|Function 2
0427   scrollTo  Window::ScrollTo    DontDelete|Function 2
0428   scrollX       Window::ScrollX         DontDelete|ReadOnly
0429   scrollY       Window::ScrollY         DontDelete|ReadOnly
0430   moveBy    Window::MoveBy      DontDelete|Function 2
0431   moveTo    Window::MoveTo      DontDelete|Function 2
0432   postMessage Window::PostMessage DontDelete|Function 2
0433   resizeBy  Window::ResizeBy    DontDelete|Function 2
0434   resizeTo  Window::ResizeTo    DontDelete|Function 2
0435   self      Window::Self        DontDelete|ReadOnly
0436   window    Window::_Window     DontDelete|ReadOnly
0437   top       Window::Top     DontDelete
0438   screen    Window::_Screen     DontDelete|ReadOnly
0439   console   Window::_Console        DontDelete|ReadOnly
0440   alert     Window::Alert       DontDelete|Function 1
0441   confirm   Window::Confirm     DontDelete|Function 1
0442   prompt    Window::Prompt      DontDelete|Function 2
0443   open      Window::Open        DontDelete|Function 3
0444   setTimeout    Window::SetTimeout  DontDelete|Function 2
0445   clearTimeout  Window::ClearTimeout    DontDelete|Function 1
0446   focus     Window::Focus       DontDelete|Function 0
0447   blur      Window::Blur        DontDelete|Function 0
0448   close     Window::Close       DontDelete|Function 0
0449   setInterval   Window::SetInterval DontDelete|Function 2
0450   clearInterval Window::ClearInterval   DontDelete|Function 1
0451   captureEvents Window::CaptureEvents   DontDelete|Function 0
0452   releaseEvents Window::ReleaseEvents   DontDelete|Function 0
0453   print     Window::Print       DontDelete|Function 0
0454   addEventListener  Window::AddEventListener    DontDelete|Function 3
0455   removeEventListener   Window::RemoveEventListener DontDelete|Function 3
0456   getSelection  Window::GetSelection            DontDelete|Function 0
0457 # Normally found in prototype. Add to window object itself to make them
0458 # accessible in closed and cross-site windows
0459   valueOf       Window::ValueOf     DontEnum|DontDelete|Function 0
0460   toString      Window::ToString    DontEnum|DontDelete|Function 0
0461 # IE extension
0462   navigate  Window::Navigate    DontDelete|Function 1
0463 # Mozilla extension
0464   sidebar   Window::SideBar     DontDelete|DontEnum
0465   getComputedStyle  Window::GetComputedStyle    DontDelete|Function 2
0466 
0467 # Warning, when adding a function to this object you need to add a case in Window::get
0468 
0469 # Event handlers
0470 # IE also has: onactivate, onbefore/afterprint, onbeforedeactivate/unload, oncontrolselect,
0471 # ondeactivate, onhelp, onmovestart/end, onresizestart/end.
0472 # It doesn't have onabort, onchange, ondragdrop (but NS has that last one).
0473   onabort   Window::Onabort     DontDelete
0474   onblur    Window::Onblur      DontDelete
0475   onchange  Window::Onchange    DontDelete
0476   onclick   Window::Onclick     DontDelete
0477   ondblclick    Window::Ondblclick  DontDelete
0478   ondragdrop    Window::Ondragdrop  DontDelete
0479   onerror   Window::Onerror     DontDelete
0480   onfocus   Window::Onfocus     DontDelete
0481   onkeydown Window::Onkeydown   DontDelete
0482   onkeypress    Window::Onkeypress  DontDelete
0483   onkeyup   Window::Onkeyup     DontDelete
0484   onload    Window::Onload      DontDelete
0485   onmessage   Window::Onmessage DontDelete
0486   onmousedown   Window::Onmousedown DontDelete
0487   onmousemove   Window::Onmousemove DontDelete
0488   onmouseout    Window::Onmouseout  DontDelete
0489   onmouseover   Window::Onmouseover DontDelete
0490   onmouseup Window::Onmouseup   DontDelete
0491   onmove    Window::Onmove      DontDelete
0492   onreset   Window::Onreset     DontDelete
0493   onresize  Window::Onresize    DontDelete
0494   onscroll      Window::Onscroll        DontDelete
0495   onselect  Window::Onselect    DontDelete
0496   onsubmit  Window::Onsubmit    DontDelete
0497   onunload  Window::Onunload    DontDelete
0498   onhashchange  Window::Onhashchange    DontDelete
0499 
0500 # Constructors/constant tables
0501   Node      Window::Node        DontEnum|DontDelete
0502   Event     Window::EventCtor   DontEnum|DontDelete
0503   Range     Window::Range       DontEnum|DontDelete
0504   NodeFilter    Window::NodeFilter  DontEnum|DontDelete
0505   NodeList  Window::NodeList    DontEnum|DontDelete
0506   DOMException  Window::DOMException    DontEnum|DontDelete
0507   RangeException Window::RangeException DontEnum|DontDelete
0508   CSSRule   Window::CSSRule     DontEnum|DontDelete
0509   MutationEvent Window::MutationEventCtor   DontEnum|DontDelete
0510   MessageEvent Window::MessageEventCtor   DontEnum|DontDelete
0511   KeyboardEvent Window::KeyboardEventCtor   DontEnum|DontDelete
0512   EventException Window::EventExceptionCtor DontEnum|DontDelete
0513   HashChangeEvent Window::HashChangeEventCtor DontEnum|DontDelete
0514   Audio     Window::Audio       DontEnum|DontDelete
0515   Image     Window::Image       DontEnum|DontDelete
0516   Option    Window::Option      DontEnum|DontDelete
0517   XMLHttpRequest Window::XMLHttpRequest DontEnum|DontDelete
0518   XMLSerializer Window::XMLSerializer   DontEnum|DontDelete
0519   DOMParser Window::DOMParser   DontEnum|DontDelete
0520   ArrayBuffer   Window::ArrayBuffer   DontEnum|DontDelete
0521   Int8Array     Window::Int8Array     DontEnum|DontDelete
0522   Uint8Array    Window::Uint8Array    DontEnum|DontDelete
0523   Int16Array    Window::Int16Array    DontEnum|DontDelete
0524   Uint16Array   Window::Uint16Array   DontEnum|DontDelete
0525   Int32Array    Window::Int32Array    DontEnum|DontDelete
0526   Uint32Array   Window::Uint32Array   DontEnum|DontDelete
0527   Float32Array  Window::Float32Array  DontEnum|DontDelete
0528   Float64Array  Window::Float64Array  DontEnum|DontDelete
0529 
0530 # Mozilla dom emulation ones.
0531   Element   Window::ElementCtor DontEnum|DontDelete
0532   Document  Window::DocumentCtor DontEnum|DontDelete
0533   DocumentFragment Window::DocumentFragmentCtor DontEnum|DontDelete
0534   #this one is an alias since we don't have a separate XMLDocument
0535   XMLDocument Window::DocumentCtor DontEnum|DontDelete
0536   HTMLElement  Window::HTMLElementCtor DontEnum|DontDelete
0537   HTMLDocument  Window::HTMLDocumentCtor DontEnum|DontDelete
0538   HTMLHtmlElement Window::HTMLHtmlElementCtor DontEnum|DontDelete
0539   HTMLHeadElement Window::HTMLHeadElementCtor DontEnum|DontDelete
0540   HTMLLinkElement Window::HTMLLinkElementCtor DontEnum|DontDelete
0541   HTMLTitleElement Window::HTMLTitleElementCtor DontEnum|DontDelete
0542   HTMLMetaElement Window::HTMLMetaElementCtor DontEnum|DontDelete
0543   HTMLBaseElement Window::HTMLBaseElementCtor DontEnum|DontDelete
0544   HTMLIsIndexElement Window::HTMLIsIndexElementCtor DontEnum|DontDelete
0545   HTMLStyleElement Window::HTMLStyleElementCtor DontEnum|DontDelete
0546   HTMLBodyElement Window::HTMLBodyElementCtor DontEnum|DontDelete
0547   HTMLFormElement Window::HTMLFormElementCtor DontEnum|DontDelete
0548   HTMLSelectElement Window::HTMLSelectElementCtor DontEnum|DontDelete
0549   HTMLOptGroupElement Window::HTMLOptGroupElementCtor DontEnum|DontDelete
0550   HTMLOptionElement Window::HTMLOptionElementCtor DontEnum|DontDelete
0551   HTMLInputElement Window::HTMLInputElementCtor DontEnum|DontDelete
0552   HTMLTextAreaElement Window::HTMLTextAreaElementCtor DontEnum|DontDelete
0553   HTMLButtonElement Window::HTMLButtonElementCtor DontEnum|DontDelete
0554   HTMLLabelElement Window::HTMLLabelElementCtor DontEnum|DontDelete
0555   HTMLFieldSetElement Window::HTMLFieldSetElementCtor DontEnum|DontDelete
0556   HTMLLegendElement Window::HTMLLegendElementCtor DontEnum|DontDelete
0557   HTMLUListElement Window::HTMLUListElementCtor DontEnum|DontDelete
0558   HTMLOListElement Window::HTMLOListElementCtor DontEnum|DontDelete
0559   HTMLDListElement Window::HTMLDListElementCtor DontEnum|DontDelete
0560   HTMLDirectoryElement Window::HTMLDirectoryElementCtor DontEnum|DontDelete
0561   HTMLMenuElement Window::HTMLMenuElementCtor DontEnum|DontDelete
0562   HTMLLIElement Window::HTMLLIElementCtor DontEnum|DontDelete
0563   HTMLDivElement Window::HTMLDivElementCtor DontEnum|DontDelete
0564   HTMLParagraphElement Window::HTMLParagraphElementCtor DontEnum|DontDelete
0565   HTMLHeadingElement Window::HTMLHeadingElementCtor DontEnum|DontDelete
0566   HTMLBlockQuoteElement Window::HTMLBlockQuoteElementCtor DontEnum|DontDelete
0567   HTMLQuoteElement Window::HTMLQuoteElementCtor DontEnum|DontDelete
0568   HTMLPreElement Window::HTMLPreElementCtor DontEnum|DontDelete
0569   HTMLBRElement Window::HTMLBRElementCtor DontEnum|DontDelete
0570   HTMLBaseFontElement Window::HTMLBaseFontElementCtor DontEnum|DontDelete
0571   HTMLFontElement Window::HTMLFontElementCtor DontEnum|DontDelete
0572   HTMLHRElement Window::HTMLHRElementCtor DontEnum|DontDelete
0573   HTMLModElement Window::HTMLModElementCtor DontEnum|DontDelete
0574   HTMLAnchorElement Window::HTMLAnchorElementCtor DontEnum|DontDelete
0575   HTMLImageElement Window::HTMLImageElementCtor DontEnum|DontDelete
0576   HTMLObjectElement Window::HTMLObjectElementCtor DontEnum|DontDelete
0577   HTMLParamElement Window::HTMLParamElementCtor DontEnum|DontDelete
0578   HTMLAppletElement Window::HTMLAppletElementCtor DontEnum|DontDelete
0579   HTMLMapElement Window::HTMLMapElementCtor DontEnum|DontDelete
0580   HTMLAreaElement Window::HTMLAreaElementCtor DontEnum|DontDelete
0581   HTMLScriptElement Window::HTMLScriptElementCtor DontEnum|DontDelete
0582   HTMLTableElement Window::HTMLTableElementCtor DontEnum|DontDelete
0583   HTMLTableCaptionElement Window::HTMLTableCaptionElementCtor DontEnum|DontDelete
0584   HTMLTableColElement Window::HTMLTableColElementCtor DontEnum|DontDelete
0585   HTMLTableSectionElement Window::HTMLTableSectionElementCtor DontEnum|DontDelete
0586   HTMLTableRowElement Window::HTMLTableRowElementCtor DontEnum|DontDelete
0587   HTMLTableCellElement Window::HTMLTableCellElementCtor DontEnum|DontDelete
0588   HTMLFrameSetElement Window::HTMLFrameSetElementCtor DontEnum|DontDelete
0589   HTMLLayerElement Window::HTMLLayerElementCtor DontEnum|DontDelete
0590   HTMLFrameElement Window::HTMLFrameElementCtor DontEnum|DontDelete
0591   HTMLIFrameElement Window::HTMLIFrameElementCtor DontEnum|DontDelete
0592   HTMLCollection Window::HTMLCollectionCtor DontEnum|DontDelete
0593   HTMLCanvasElement Window::HTMLCanvasElementCtor DontEnum|DontDelete
0594   CSSStyleDeclaration Window::CSSStyleDeclarationCtor DontEnum|DontDelete
0595   StyleSheet   Window::StyleSheetCtor DontEnum|DontDelete
0596   CanvasRenderingContext2D Window::Context2DCtor DontEnum|DontDelete
0597   SVGAngle Window::SVGAngleCtor DontEnum|DontDelete
0598   XPathResult Window::XPathResultCtor DontEnum|DontDelete
0599   XPathExpression Window::XPathExpressionCtor DontEnum|DontDelete
0600   XPathNSResolver Window::XPathNSResolverCtor DontEnum|DontDelete
0601 @end
0602 */
0603 KJS_IMPLEMENT_PROTOFUNC(WindowFunc)
0604 
0605 Window::Window(khtml::ChildFrame *p)
0606     : JSGlobalObject(/*no proto*/), m_frame(p), screen(nullptr), console(nullptr), history(nullptr), external(nullptr), loc(nullptr), m_evt(nullptr)
0607 {
0608     winq = new WindowQObject(this);
0609     //qCDebug(KHTML_LOG) << "Window::Window this=" << this << " part=" << m_part << " " << m_part->name();
0610 }
0611 
0612 Window::~Window()
0613 {
0614     qDeleteAll(m_delayed);
0615     delete winq;
0616 }
0617 
0618 Window *Window::retrieveWindow(KParts::ReadOnlyPart *p)
0619 {
0620     JSObject *obj = retrieve(p)->getObject();
0621 #ifndef NDEBUG
0622     // obj should never be null, except when javascript has been disabled in that part.
0623     KHTMLPart *part = qobject_cast<KHTMLPart *>(p);
0624     if (part && part->jScriptEnabled()) {
0625         assert(obj);
0626         assert(dynamic_cast<KJS::Window *>(obj));  // type checking
0627     }
0628 #endif
0629     if (!obj) { // JS disabled
0630         return nullptr;
0631     }
0632     return static_cast<KJS::Window *>(obj);
0633 }
0634 
0635 Window *Window::retrieveActive(ExecState *exec)
0636 {
0637     JSValue *imp = exec->dynamicInterpreter()->globalObject();
0638     assert(imp);
0639     assert(dynamic_cast<KJS::Window *>(imp));
0640     return static_cast<KJS::Window *>(imp);
0641 }
0642 
0643 JSValue *Window::retrieve(KParts::ReadOnlyPart *p)
0644 {
0645     assert(p);
0646     KHTMLPart *part = qobject_cast<KHTMLPart *>(p);
0647     KJSProxy *proxy = nullptr;
0648     if (!part) {
0649         part = qobject_cast<KHTMLPart *>(p->parent());
0650         if (part) {
0651             proxy = part->framejScript(p);
0652         }
0653     } else {
0654         proxy = part->jScript();
0655     }
0656     if (proxy) {
0657 #ifdef KJS_VERBOSE
0658         qCDebug(KHTML_LOG) << "Window::retrieve part=" << part << " '" << part->objectName() << "' interpreter=" << proxy->interpreter() << " window=" << proxy->interpreter()->globalObject();
0659 #endif
0660         return proxy->interpreter()->globalObject(); // the Global object is the "window"
0661     } else {
0662 #ifdef KJS_VERBOSE
0663         qCDebug(KHTML_LOG) << "Window::retrieve part=" << p << " '" << p->objectName() << "' no jsproxy.";
0664 #endif
0665         return jsUndefined(); // This can happen with JS disabled on the domain of that window
0666     }
0667 }
0668 
0669 Location *Window::location() const
0670 {
0671     if (!loc) {
0672         const_cast<Window *>(this)->loc = new Location(m_frame);
0673     }
0674     return loc;
0675 }
0676 
0677 // reference our special objects during garbage collection
0678 void Window::mark()
0679 {
0680     JSObject::mark();
0681     if (screen && !screen->marked()) {
0682         screen->mark();
0683     }
0684     if (console && !console->marked()) {
0685         console->mark();
0686     }
0687     if (history && !history->marked()) {
0688         history->mark();
0689     }
0690     if (external && !external->marked()) {
0691         external->mark();
0692     }
0693     //qCDebug(KHTML_LOG) << "Window::mark " << this << " marking loc=" << loc;
0694     if (loc && !loc->marked()) {
0695         loc->mark();
0696     }
0697     if (winq) {
0698         winq->mark();
0699     }
0700     foreach (DelayedAction *action, m_delayed) {
0701         action->mark();
0702     }
0703 }
0704 
0705 UString Window::toString(ExecState *) const
0706 {
0707     return "[object Window]";
0708 }
0709 
0710 bool Window::isCrossFrameAccessible(int token) const
0711 {
0712     switch (token) {
0713     case Closed:
0714     case _Location: // No isSafeScript test here, we must be able to _set_ location.href (#49819)
0715     case _Window:
0716     case Self:
0717     case Frames:
0718     case Opener:
0719     case Parent:
0720     case Top:
0721     case Alert:
0722     case Confirm:
0723     case Prompt:
0724     case Open:
0725     case Close:
0726     case Focus:
0727     case Blur:
0728     case AToB:
0729     case BToA:
0730     case ValueOf:
0731     case ToString:
0732     case PostMessage:
0733         return true;
0734     default:
0735         return false;
0736     }
0737 }
0738 
0739 bool Window::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot)
0740 {
0741 #ifdef KJS_VERBOSE
0742     qCDebug(KHTML_LOG) << "Window(" << this << ")::getOwnPropertySlot " << propertyName.qstring();
0743 #endif
0744 
0745     // we want only limited operations on a closed window
0746     if (m_frame.isNull() || m_frame->m_part.isNull()) {
0747         const HashEntry *entry = Lookup::findEntry(&WindowTable, propertyName);
0748         if (entry) {
0749             switch (entry->value) {
0750             case Closed:
0751             case _Location:
0752             case ValueOf:
0753             case ToString:
0754                 getSlotFromEntry<WindowFunc, Window>(entry, this, slot);
0755                 return true;
0756             default:
0757                 break;
0758             }
0759         }
0760         slot.setUndefined(this);
0761         return true;
0762     }
0763 
0764     bool safe = isSafeScript(exec);
0765 
0766     // Look for overrides first.
0767     JSValue **val = getDirectLocation(propertyName);
0768     if (val) {
0769         if (safe) {
0770             fillDirectLocationSlot(slot, val);
0771         } else {
0772             // We may need to permit access to the property map cross-frame in
0773             // order to pick up cross-frame accessible functions that got
0774             // cached as direct properties.
0775             const HashEntry *entry = Lookup::findEntry(&WindowTable, propertyName);
0776             if (entry && isCrossFrameAccessible(entry->value)) {
0777                 fillDirectLocationSlot(slot, val);
0778             } else {
0779                 slot.setUndefined(this);
0780             }
0781         }
0782         return true;
0783     }
0784 
0785     // The only stuff we permit XSS (besides cached things above) are
0786     // a few of hashtable properties.
0787     const HashEntry *entry = Lookup::findEntry(&WindowTable, propertyName);
0788     if (!safe && (!entry || !isCrossFrameAccessible(entry->value))) {
0789         slot.setUndefined(this);
0790         return true;
0791     }
0792 
0793     // invariant: accesses below this point are permitted by the XSS policy
0794 
0795     KHTMLPart *part = qobject_cast<KHTMLPart *>(m_frame->m_part.data());
0796 
0797     if (entry) {
0798         // Things that work on any ReadOnlyPart first
0799         switch (entry->value) {
0800         case Closed:
0801         case _Location:
0802         case _Window:
0803         case Self:
0804             getSlotFromEntry<WindowFunc, Window>(entry, this, slot);
0805             return true;
0806         default:
0807             break;
0808         }
0809 
0810         if (!part) {
0811             slot.setUndefined(this);
0812             return true;
0813         }
0814 
0815         // KHTMLPart-specific next.
0816 
0817         // Disabled in NS-compat mode. Supported by default - can't hurt, unless someone uses
0818         // if (navigate) to test for IE (unlikely).
0819         if (entry->value == Navigate && exec->dynamicInterpreter()->compatMode() == Interpreter::NetscapeCompat) {
0820             slot.setUndefined(this);
0821             return true;
0822         }
0823 
0824         getSlotFromEntry<WindowFunc, Window>(entry, this, slot);
0825         return true;
0826     }
0827 
0828     if (!part) {
0829         // not a  KHTMLPart, so try to get plugin scripting stuff
0830         if (pluginRootGet(exec, m_frame->m_scriptable.data(), propertyName, slot)) {
0831             return true;
0832         }
0833 
0834         slot.setUndefined(this);
0835         return true;
0836     }
0837 
0838     // Now do frame indexing.
0839     KParts::ReadOnlyPart *rop = part->findFramePart(propertyName.qstring());
0840     if (rop) {
0841         slot.setCustom(this, framePartGetter);
0842         return true;
0843     }
0844 
0845     // allow window[1] or parent[1] etc. (#56983)
0846     bool ok;
0847     unsigned int i = propertyName.toArrayIndex(&ok);
0848     if (ok && frameByIndex(i)) {
0849         slot.setCustomIndex(this, i, indexGetterAdapter<Window>);
0850         return true;
0851     }
0852 
0853     // allow shortcuts like 'Image1' instead of document.images.Image1
0854     DOM::DocumentImpl *doc = part->xmlDocImpl();
0855     if (doc && doc->isHTMLDocument()) {
0856         DOM::ElementMappingCache::ItemInfo *info = doc->underDocNamedCache().get(propertyName.domString());
0857         if (info || doc->getElementById(propertyName.domString())) {
0858             slot.setCustom(this, namedItemGetter);
0859             return true;
0860         }
0861     }
0862 
0863     // This isn't necessarily a bug. Some code uses if(!window.blah) window.blah=1
0864     // But it can also mean something isn't loaded or implemented, hence the WARNING to help grepping.
0865 #ifdef KJS_VERBOSE
0866     qCDebug(KHTML_LOG) << "WARNING: Window::get property not found: " << propertyName.qstring();
0867 #endif
0868 
0869     return JSObject::getOwnPropertySlot(exec, propertyName, slot);
0870 }
0871 
0872 KParts::ReadOnlyPart *Window::frameByIndex(unsigned i)
0873 {
0874     KHTMLPart *part = qobject_cast<KHTMLPart *>(m_frame->m_part);
0875     QList<KParts::ReadOnlyPart *> frames = part->frames();
0876     unsigned int len = frames.count();
0877     if (i < len) {
0878         KParts::ReadOnlyPart *frame = frames.at(i);
0879         return frame;
0880     }
0881     return nullptr;
0882 }
0883 
0884 JSValue *Window::indexGetter(ExecState *exec, unsigned index)
0885 {
0886     Q_UNUSED(exec);
0887     KParts::ReadOnlyPart *frame = frameByIndex(index);
0888     if (frame) {
0889         return Window::retrieve(frame);
0890     }
0891     return jsUndefined(); //### ?
0892 }
0893 
0894 JSValue *Window::framePartGetter(ExecState *exec, JSObject *, const Identifier &propertyName, const PropertySlot &slot)
0895 {
0896     Q_UNUSED(exec);
0897     Window *thisObj = static_cast<Window *>(slot.slotBase());
0898     KHTMLPart *part = qobject_cast<KHTMLPart *>(thisObj->m_frame->m_part);
0899     KParts::ReadOnlyPart *rop = part->findFramePart(propertyName.qstring());
0900     return thisObj->retrieve(rop);
0901 }
0902 
0903 JSValue *Window::namedItemGetter(ExecState *exec, JSObject *, const Identifier &p, const PropertySlot &slot)
0904 {
0905     Window *thisObj = static_cast<Window *>(slot.slotBase());
0906     KHTMLPart *part = qobject_cast<KHTMLPart *>(thisObj->m_frame->m_part);
0907     DOM::DocumentImpl *doc = part->xmlDocImpl();
0908 
0909     DOM::ElementMappingCache::ItemInfo *info = doc->underDocNamedCache().get(p.domString());
0910     if (info) {
0911         if (info->nd) {
0912             return getDOMNode(exec, info->nd);
0913         } else {
0914             //No cached mapping, do it by hand...
0915             DOM::HTMLMappedNameCollectionImpl *coll = new DOM::HTMLMappedNameCollectionImpl(doc,
0916                     DOM::HTMLCollectionImpl::DOCUMENT_NAMED_ITEMS, p.domString());
0917 
0918             if (coll->length() == 1) {
0919                 info->nd = static_cast<DOM::ElementImpl *>(coll->firstItem());
0920                 delete coll;
0921                 return getDOMNode(exec, info->nd);
0922             }
0923             return getHTMLCollection(exec, coll);
0924         }
0925     }
0926 
0927     DOM::ElementImpl *element = doc->getElementById(p.domString());
0928     return getDOMNode(exec, element);
0929 }
0930 
0931 JSValue *Window::getValueProperty(ExecState *exec, int token)
0932 {
0933     KHTMLPart *part = m_frame.isNull() ? nullptr : qobject_cast<KHTMLPart *>(m_frame->m_part);
0934     if (!part) {
0935         switch (token) {
0936         case Closed:
0937             return jsBoolean(true);
0938         case _Location:
0939             return jsNull();
0940         default:
0941             return jsUndefined();
0942         }
0943     }
0944 
0945     switch (token) {
0946     case Closed:
0947         return jsBoolean(!part);
0948     case _Location:
0949         // No isSafeScript test here, we must be able to _set_ location.href (#49819)
0950         return location();
0951     case _Window:
0952     case Self:
0953         return retrieve(part);
0954     case Frames:
0955         return this;
0956     case Opener:
0957         if (!part->opener()) {
0958             return jsNull();    // ### a null Window might be better, but == null
0959         } else {            // doesn't work yet
0960             return retrieve(part->opener());
0961         }
0962     case Parent:
0963         return retrieve(part && part->parentPart() ? part->parentPart() : (KHTMLPart *)part);
0964     case Top: {
0965         KHTMLPart *p = part;
0966         while (p->parentPart()) {
0967             p = p->parentPart();
0968         }
0969         return retrieve(p);
0970     }
0971     case Crypto:
0972         return jsUndefined(); // ###
0973     case DefaultStatus:
0974         return jsString(UString(part->jsDefaultStatusBarText()));
0975     case Status:
0976         return jsString(UString(part->jsStatusBarText()));
0977     case Document:
0978         return getDOMNode(exec, part->xmlDocImpl());
0979     case FrameElement:
0980         if (m_frame->m_partContainerElement) {
0981             return getDOMNode(exec, m_frame->m_partContainerElement.data());
0982         } else {
0983             return jsUndefined();
0984         }
0985     case Node:
0986         return NodeConstructor::self(exec);
0987     case Range:
0988         return getRangeConstructor(exec);
0989     case NodeFilter:
0990         return getNodeFilterConstructor(exec);
0991     case NodeList:
0992         return NodeListPseudoCtor::self(exec);
0993     case DOMException:
0994         return getDOMExceptionConstructor(exec);
0995     case RangeException:
0996         return RangeExceptionPseudoCtor::self(exec);
0997     case CSSRule:
0998         return getCSSRuleConstructor(exec);
0999     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 
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 
1550 bool Window::toBoolean(ExecState *) const
1551 {
1552     return !m_frame.isNull() && !m_frame->m_part.isNull();
1553 }
1554 
1555 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 
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 
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 
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 
1602 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 
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 
1666 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 
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 
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 
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 
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 
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:
1799     DelayedGoHistory(int _steps): steps(_steps)
1800     {}
1801 
1802     bool execute(Window *win) override
1803     {
1804         win->goHistory(steps);
1805         return true;
1806     }
1807 private:
1808     int steps;
1809 };
1810 
1811 void Window::delayedGoHistory(int steps)
1812 {
1813     m_delayed.append(new DelayedGoHistory(steps));
1814 }
1815 
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 
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 
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 
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::questionTwoActions(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::PrimaryAction) {
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 
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 
2128 void Window::forgetSuppressedWindows()
2129 {
2130     m_suppressedWindowInfo.clear();
2131 }
2132 
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:
2149     bool execute(Window *win) override
2150     {
2151         win->scheduleClose();
2152         return false;
2153     }
2154 private:
2155     int steps;
2156 };
2157 
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::warningTwoActions(widget, Qt::convertFromPlainText(str), caption,
2215                           KStandardGuiItem::ok(), KStandardGuiItem::cancel()) == KMessageBox::PrimaryAction));
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::questionTwoActions(window->part()->widget(),
2283                                                     i18n("Close window?"), i18n("Confirmation Required"),
2284                                                     KStandardGuiItem::close(), KStandardGuiItem::cancel())
2285                         == KMessageBox::PrimaryAction) {
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 
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 
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 
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 
2617 void ScheduledAction::mark()
2618 {
2619     if (func && !func->marked()) {
2620         func->mark();
2621     }
2622 }
2623 
2624 ScheduledAction::~ScheduledAction()
2625 {
2626     args.reset();
2627     //qCDebug(KHTML_LOG) << "ScheduledAction::~ScheduledAction " << this;
2628 }
2629 
2630 ////////////////////// WindowQObject ////////////////////////
2631 
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 
2646 WindowQObject::~WindowQObject()
2647 {
2648     //qCDebug(KHTML_LOG) << "WindowQObject::~WindowQObject " << this;
2649     parentDestroyed(); // reuse same code
2650 }
2651 
2652 void WindowQObject::parentDestroyed()
2653 {
2654     killTimers();
2655 
2656     while (!scheduledActions.isEmpty()) {
2657         delete scheduledActions.takeFirst();
2658     }
2659     scheduledActions.clear();
2660 }
2661 
2662 void WindowQObject::pauseTimers()
2663 {
2664     ++pauseLevel;
2665     if (pauseLevel == 1) {
2666         pauseStart = DateTimeMS::now();
2667     }
2668 }
2669 
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 
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 
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 
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 
2739 bool WindowQObject::hasTimers() const
2740 {
2741     return scheduledActions.count();
2742 }
2743 
2744 void WindowQObject::mark()
2745 {
2746     foreach (ScheduledAction *action, scheduledActions) {
2747         action->mark();
2748     }
2749 }
2750 
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 
2815 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 
2831 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 
2844 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 
2857 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 
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 
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 
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 
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 */
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 
2941 Location::~Location()
2942 {
2943     //qCDebug(KHTML_LOG) << "Location::~Location " << this << " m_part=" << (void*)m_part;
2944 }
2945 
2946 KParts::ReadOnlyPart *Location::part() const
2947 {
2948     return m_frame ? static_cast<KParts::ReadOnlyPart *>(m_frame->m_part) : nullptr;
2949 }
2950 
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 
2985 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 
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 
3117 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 
3128 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 
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 */
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 
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::warningTwoActions(
3248                     widget, question, caption,
3249                     KGuiItem(i18n("Insert")), KGuiItem(i18n("Disallow"))) == KMessageBox::PrimaryAction) {
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 */
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 
3284 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 
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 #include "moc_kjs_window.cpp"