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