KHtml

kjs_window.cpp
1 /*
2  * This file is part of the KDE libraries
3  * Copyright (C) 2000-2003 Harri Porten ([email protected])
4  * Copyright (C) 2001-2003 David Faure ([email protected])
5  * Copyright (C) 2003 Apple Computer, Inc.
6  * Copyright (C) 2006, 2008-2010 Maksim Orlovich ([email protected])
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:
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;
92  const ClassInfo *classInfo() const override
93  {
94  return &info;
95  }
96  static const ClassInfo info;
97  enum { Back, Forward, Go, Length };
98 private:
100 };
101 
102 class External : public JSObject
103 {
104  friend class ExternalFunc;
105 public:
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;
110  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
145 Screen::Screen(ExecState *exec)
146  : JSObject(exec->lexicalInterpreter()->builtinObjectPrototype()) {}
147 
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 
156 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
227 Console::Console(ExecState *exec)
228  : JSObject(exec->lexicalInterpreter()->builtinObjectPrototype()) {}
229 
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 
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 
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 
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 
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 */
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 
612 Window::~Window()
613 {
614  qDeleteAll(m_delayed);
615  delete winq;
616 }
617 
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 
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 
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 
669 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
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 
705 UString Window::toString(ExecState *) const
706 {
707  return "[object Window]";
708 }
709 
710 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 
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 
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 
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 
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 
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 
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  }
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  }
1237  return jsNumber(part->view()->mapToGlobal(QPoint(0, 0)).y() + sg.y());
1238  }
1239  case ScrollX: {
1240  if (!part->view()) {
1241  return jsUndefined();
1242  }
1243  return jsNumber(part->view()->contentsX());
1244  }
1245  case ScrollY: {
1246  if (!part->view()) {
1247  return jsUndefined();
1248  }
1249  return jsNumber(part->view()->contentsY());
1250  }
1251  case Scrollbars:
1252  return new JSObject(); // ###
1253  case _Screen:
1254  return screen ? screen :
1255  (const_cast<Window *>(this)->screen = new Screen(exec));
1256  case _Console:
1257  return console ? console :
1258  (const_cast<Window *>(this)->console = new Console(exec));
1259  case Audio:
1260  return new AudioConstructorImp(exec, part->xmlDocImpl());
1261  case Image:
1262  return new ImageConstructorImp(exec, part->xmlDocImpl());
1263  case Option:
1264  return new OptionConstructorImp(exec, part->xmlDocImpl());
1265  case XMLHttpRequest:
1266  return new XMLHttpRequestConstructorImp(exec, part->xmlDocImpl());
1267  case XMLSerializer:
1268  return new XMLSerializerConstructorImp(exec);
1269  case DOMParser:
1270  return new DOMParserConstructorImp(exec, part->xmlDocImpl());
1271  case ArrayBuffer:
1272  return new ArrayBufferConstructorImp(exec, part->xmlDocImpl());
1273  case Int8Array:
1274  return new ArrayBufferConstructorImpInt8(exec, part->xmlDocImpl());
1275  case Uint8Array:
1276  return new ArrayBufferConstructorImpUint8(exec, part->xmlDocImpl());
1277  case Int16Array:
1278  return new ArrayBufferConstructorImpInt16(exec, part->xmlDocImpl());
1279  case Uint16Array:
1280  return new ArrayBufferConstructorImpUint16(exec, part->xmlDocImpl());
1281  case Int32Array:
1282  return new ArrayBufferConstructorImpInt32(exec, part->xmlDocImpl());
1283  case Uint32Array:
1284  return new ArrayBufferConstructorImpUint32(exec, part->xmlDocImpl());
1285  case Float32Array:
1286  return new ArrayBufferConstructorImpFloat32(exec, part->xmlDocImpl());
1287  case Float64Array:
1288  return new ArrayBufferConstructorImpFloat64(exec, part->xmlDocImpl());
1289  case Onabort:
1290  return getListener(exec, DOM::EventImpl::ABORT_EVENT);
1291  case Onblur:
1292  return getListener(exec, DOM::EventImpl::BLUR_EVENT);
1293  case Onchange:
1294  return getListener(exec, DOM::EventImpl::CHANGE_EVENT);
1295  case Onclick:
1296  return getListener(exec, DOM::EventImpl::KHTML_ECMA_CLICK_EVENT);
1297  case Ondblclick:
1298  return getListener(exec, DOM::EventImpl::KHTML_ECMA_DBLCLICK_EVENT);
1299  case Ondragdrop:
1300  return getListener(exec, DOM::EventImpl::KHTML_DRAGDROP_EVENT);
1301  case Onerror:
1302  return getListener(exec, DOM::EventImpl::ERROR_EVENT);
1303  case Onfocus:
1304  return getListener(exec, DOM::EventImpl::FOCUS_EVENT);
1305  case Onkeydown:
1306  return getListener(exec, DOM::EventImpl::KEYDOWN_EVENT);
1307  case Onkeypress:
1308  return getListener(exec, DOM::EventImpl::KEYPRESS_EVENT);
1309  case Onkeyup:
1310  return getListener(exec, DOM::EventImpl::KEYUP_EVENT);
1311  case Onload:
1312  return getListener(exec, DOM::EventImpl::LOAD_EVENT);
1313  case Onmessage:
1314  return getListener(exec, DOM::EventImpl::MESSAGE_EVENT);
1315  case Onmousedown:
1316  return getListener(exec, DOM::EventImpl::MOUSEDOWN_EVENT);
1317  case Onmousemove:
1318  return getListener(exec, DOM::EventImpl::MOUSEMOVE_EVENT);
1319  case Onmouseout:
1320  return getListener(exec, DOM::EventImpl::MOUSEOUT_EVENT);
1321  case Onmouseover:
1322  return getListener(exec, DOM::EventImpl::MOUSEOVER_EVENT);
1323  case Onmouseup:
1324  return getListener(exec, DOM::EventImpl::MOUSEUP_EVENT);
1325  case Onmove:
1326  return getListener(exec, DOM::EventImpl::KHTML_MOVE_EVENT);
1327  case Onreset:
1328  return getListener(exec, DOM::EventImpl::RESET_EVENT);
1329  case Onresize:
1330  return getListener(exec, DOM::EventImpl::RESIZE_EVENT);
1331  case Onscroll:
1332  return getListener(exec, DOM::EventImpl::SCROLL_EVENT);
1333  case Onselect:
1334  return getListener(exec, DOM::EventImpl::SELECT_EVENT);
1335  case Onsubmit:
1336  return getListener(exec, DOM::EventImpl::SUBMIT_EVENT);
1337  case Onunload:
1338  return getListener(exec, DOM::EventImpl::UNLOAD_EVENT);
1339  case Onhashchange:
1340  return getListener(exec, DOM::EventImpl::HASHCHANGE_EVENT);
1341  }
1342 
1343  return jsUndefined();
1344 }
1345 
1346 void Window::put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr)
1347 {
1348  // we don't want any operations on a closed window
1349  if (m_frame.isNull() || m_frame->m_part.isNull()) {
1350  // ### throw exception? allow setting of some props like location?
1351  return;
1352  }
1353 
1354  // Called by an internal KJS call (e.g. InterpreterImp's constructor) ?
1355  // If yes, save time and jump directly to JSObject. We also have
1356  // to do this now since calling isSafeScript() may not work yet.
1357  if (attr != None && attr != DontDelete) {
1358  JSObject::put(exec, propertyName, value, attr);
1359  return;
1360  }
1361 
1362  // If we already have a variable, that's writeable w/o a getter/setter mess, just write to it.
1363  bool safe = isSafeScript(exec);
1364  if (safe) {
1365  if (JSValue **slot = getDirectWriteLocation(propertyName)) {
1366  *slot = value;
1367  return;
1368  }
1369  }
1370 
1371  const HashEntry *entry = Lookup::findEntry(&WindowTable, propertyName);
1372  if (entry) {
1373 #ifdef KJS_VERBOSE
1374  qCDebug(KHTML_LOG) << "Window(" << this << ")::put " << propertyName.qstring();
1375 #endif
1376  if (entry->value == _Location) {
1377  goURL(exec, value->toString(exec).qstring());
1378  return;
1379  }
1380 
1381  KHTMLPart *part = qobject_cast<KHTMLPart *>(m_frame->m_part);
1382  if (part) {
1383  switch (entry->value) {
1384  case Status: {
1385  if (isSafeScript(exec) && part->settings()->windowStatusPolicy(part->url().host())
1386  == KHTMLSettings::KJSWindowStatusAllow) {
1387  UString s = value->toString(exec);
1388  part->setJSStatusBarText(s.qstring());
1389  }
1390  return;
1391  }
1392  case DefaultStatus: {
1393  if (isSafeScript(exec) && part->settings()->windowStatusPolicy(part->url().host())
1394  == KHTMLSettings::KJSWindowStatusAllow) {
1395  UString s = value->toString(exec);
1397  }
1398  return;
1399  }
1400  case Onabort:
1401  if (isSafeScript(exec)) {
1402  setListener(exec, DOM::EventImpl::ABORT_EVENT, value);
1403  }
1404  return;
1405  case Onblur:
1406  if (isSafeScript(exec)) {
1407  setListener(exec, DOM::EventImpl::BLUR_EVENT, value);
1408  }
1409  return;
1410  case Onchange:
1411  if (isSafeScript(exec)) {
1412  setListener(exec, DOM::EventImpl::CHANGE_EVENT, value);
1413  }
1414  return;
1415  case Onclick:
1416  if (isSafeScript(exec)) {
1417  setListener(exec, DOM::EventImpl::KHTML_ECMA_CLICK_EVENT, value);
1418  }
1419  return;
1420  case Ondblclick:
1421  if (isSafeScript(exec)) {
1422  setListener(exec, DOM::EventImpl::KHTML_ECMA_DBLCLICK_EVENT, value);
1423  }
1424  return;
1425  case Ondragdrop:
1426  if (isSafeScript(exec)) {
1427  setListener(exec, DOM::EventImpl::KHTML_DRAGDROP_EVENT, value);
1428  }
1429  return;
1430  case Onerror:
1431  if (isSafeScript(exec)) {
1432  setListener(exec, DOM::EventImpl::ERROR_EVENT, value);
1433  }
1434  return;
1435  case Onfocus:
1436  if (isSafeScript(exec)) {
1437  setListener(exec, DOM::EventImpl::FOCUS_EVENT, value);
1438  }
1439  return;
1440  case Onkeydown:
1441  if (isSafeScript(exec)) {
1442  setListener(exec, DOM::EventImpl::KEYDOWN_EVENT, value);
1443  }
1444  return;
1445  case Onkeypress:
1446  if (isSafeScript(exec)) {
1447  setListener(exec, DOM::EventImpl::KEYPRESS_EVENT, value);
1448  }
1449  return;
1450  case Onkeyup:
1451  if (isSafeScript(exec)) {
1452  setListener(exec, DOM::EventImpl::KEYUP_EVENT, value);
1453  }
1454  return;
1455  case Onload:
1456  if (isSafeScript(exec)) {
1457  setListener(exec, DOM::EventImpl::LOAD_EVENT, value);
1458  }
1459  return;
1460  case Onmessage:
1461  if (isSafeScript(exec)) {
1462  setListener(exec, DOM::EventImpl::MESSAGE_EVENT, value);
1463  }
1464  return;
1465  case Onmousedown:
1466  if (isSafeScript(exec)) {
1467  setListener(exec, DOM::EventImpl::MOUSEDOWN_EVENT, value);
1468  }
1469  return;
1470  case Onmousemove:
1471  if (isSafeScript(exec)) {
1472  setListener(exec, DOM::EventImpl::MOUSEMOVE_EVENT, value);
1473  }
1474  return;
1475  case Onmouseout:
1476  if (isSafeScript(exec)) {
1477  setListener(exec, DOM::EventImpl::MOUSEOUT_EVENT, value);
1478  }
1479  return;
1480  case Onmouseover:
1481  if (isSafeScript(exec)) {
1482  setListener(exec, DOM::EventImpl::MOUSEOVER_EVENT, value);
1483  }
1484  return;
1485  case Onmouseup:
1486  if (isSafeScript(exec)) {
1487  setListener(exec, DOM::EventImpl::MOUSEUP_EVENT, value);
1488  }
1489  return;
1490  case Onmove:
1491  if (isSafeScript(exec)) {
1492  setListener(exec, DOM::EventImpl::KHTML_MOVE_EVENT, value);
1493  }
1494  return;
1495  case Onreset:
1496  if (isSafeScript(exec)) {
1497  setListener(exec, DOM::EventImpl::RESET_EVENT, value);
1498  }
1499  return;
1500  case Onresize:
1501  if (isSafeScript(exec)) {
1502  setListener(exec, DOM::EventImpl::RESIZE_EVENT, value);
1503  }
1504  return;
1505  case Onscroll:
1506  if (isSafeScript(exec)) {
1507  setListener(exec, DOM::EventImpl::SCROLL_EVENT, value);
1508  }
1509  return;
1510  case Onselect:
1511  if (isSafeScript(exec)) {
1512  setListener(exec, DOM::EventImpl::SELECT_EVENT, value);
1513  }
1514  return;
1515  case Onsubmit:
1516  if (isSafeScript(exec)) {
1517  setListener(exec, DOM::EventImpl::SUBMIT_EVENT, value);
1518  }
1519  return;
1520  case Onunload:
1521  if (isSafeScript(exec)) {
1522  setListener(exec, DOM::EventImpl::UNLOAD_EVENT, value);
1523  }
1524  return;
1525  case Onhashchange:
1526  if (isSafeScript(exec)) {
1527  setListener(exec, DOM::EventImpl::HASHCHANGE_EVENT, value);
1528  }
1529  return;
1530  case Name:
1531  if (isSafeScript(exec)) {
1532  part->setObjectName(value->toString(exec).qstring().toLocal8Bit().data());
1533  }
1534  return;
1535  default:
1536  break;
1537  }
1538  }
1539  }
1540  if (isSafeScript(exec) &&
1541  pluginRootPut(exec, m_frame->m_scriptable.data(), propertyName, value)) {
1542  return;
1543  }
1544  if (safe) {
1545  //qCDebug(KHTML_LOG) << "Window("<<this<<")::put storing " << propertyName.qstring();
1546  JSObject::put(exec, propertyName, value, attr);
1547  }
1548 }
1549 
1550 bool Window::toBoolean(ExecState *) const
1551 {
1552  return !m_frame.isNull() && !m_frame->m_part.isNull();
1553 }
1554 
1555 DOM::AbstractViewImpl *Window::toAbstractView() const
1556 {
1557  KHTMLPart *part = ::qobject_cast<KHTMLPart *>(m_frame->m_part);
1558  if (!part || !part->xmlDocImpl()) {
1559  return nullptr;
1560  }
1561  return part->xmlDocImpl()->defaultView();
1562 }
1563 
1564 void Window::scheduleClose()
1565 {
1566  // qCDebug(KHTML_LOG) << "Window::scheduleClose window.close() " << m_frame;
1567  Q_ASSERT(winq);
1568  QTimer::singleShot(0, winq, SLOT(timeoutClose()));
1569 }
1570 
1571 void Window::closeNow()
1572 {
1573  if (m_frame.isNull() || m_frame->m_part.isNull()) {
1574  // qCDebug(KHTML_LOG) << "part is deleted already";
1575  } else {
1576  KHTMLPart *part = qobject_cast<KHTMLPart *>(m_frame->m_part);
1577  if (!part) {
1578  // qCDebug(KHTML_LOG) << "closeNow on non KHTML part";
1579  } else {
1580  //qCDebug(KHTML_LOG) << " -> closing window";
1581  // We want to make sure that window.open won't find this part by name.
1582  part->setObjectName(QString());
1583  part->deleteLater();
1584  part = nullptr;
1585  }
1586  }
1587 }
1588 
1589 void Window::afterScriptExecution()
1590 {
1591  DOM::DocumentImpl::updateDocumentsRendering();
1592  const QList<DelayedAction *> delayedActions = m_delayed;
1593  m_delayed.clear();
1594  foreach (DelayedAction *act, delayedActions) {
1595  if (!act->execute(this)) {
1596  break; // done with them
1597  }
1598  }
1599  qDeleteAll(delayedActions);
1600 }
1601 
1602 bool Window::checkIsSafeScript(KParts::ReadOnlyPart *activePart) const
1603 {
1604  if (m_frame.isNull() || m_frame->m_part.isNull()) { // part deleted ? can't grant access
1605  // qCDebug(KHTML_LOG) << "Window::isSafeScript: accessing deleted part !";
1606  return false;
1607  }
1608  if (!activePart) {
1609  // qCDebug(KHTML_LOG) << "Window::isSafeScript: current interpreter's part is 0L!";
1610  return false;
1611  }
1612  if (activePart == m_frame->m_part) { // Not calling from another frame, no problem.
1613  return true;
1614  }
1615 
1616  KHTMLPart *part = qobject_cast<KHTMLPart *>(m_frame->m_part);
1617  if (!part) {
1618  return true; // not a KHTMLPart
1619  }
1620 
1621  if (!part->xmlDocImpl()) {
1622  return true; // allow to access a window that was just created (e.g. with window.open("about:blank"))
1623  }
1624 
1625  DOM::DocumentImpl *thisDocument = part->xmlDocImpl();
1626 
1627  KHTMLPart *activeKHTMLPart = qobject_cast<KHTMLPart *>(activePart);
1628  if (!activeKHTMLPart) {
1629  return true; // not a KHTMLPart
1630  }
1631 
1632  DOM::DocumentImpl *actDocument = activeKHTMLPart->xmlDocImpl();
1633  if (!actDocument) {
1634  // qCDebug(KHTML_LOG) << "Window::isSafeScript: active part has no document!";
1635  return false;
1636  }
1637  khtml::SecurityOrigin *actDomain = actDocument->origin();
1638  khtml::SecurityOrigin *thisDomain = thisDocument->origin();
1639 
1640  if (actDomain->canAccess(thisDomain)) {
1641 #ifdef KJS_VERBOSE
1642  qCDebug(KHTML_LOG) << "JavaScript: access granted, domain is '" << actDomain.string() << "'";
1643 #endif
1644  return true;
1645  }
1646 
1647  // qCDebug(KHTML_LOG) << "WARNING: JavaScript: access denied for current frame '" << actDomain->toString() << "' to frame '" << thisDomain->toString() << "'";
1648  // TODO after 3.1: throw security exception (exec->setException())
1649  return false;
1650 }
1651 
1652 void Window::setListener(ExecState *exec, int eventId, JSValue *func)
1653 {
1654  KHTMLPart *part = qobject_cast<KHTMLPart *>(m_frame->m_part);
1655  if (!part || !isSafeScript(exec)) {
1656  return;
1657  }
1658  DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(part->htmlDocument().handle());
1659  if (!doc) {
1660  return;
1661  }
1662 
1663  doc->setHTMLWindowEventListener(eventId, getJSEventListener(func, true));
1664 }
1665 
1666 JSValue *Window::getListener(ExecState *exec, int eventId) const
1667 {
1668  KHTMLPart *part = qobject_cast<KHTMLPart *>(m_frame->m_part);
1669  if (!part || !isSafeScript(exec)) {
1670  return jsUndefined();
1671  }
1672  DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(part->htmlDocument().handle());
1673  if (!doc) {
1674  return jsUndefined();
1675  }
1676 
1677  DOM::EventListener *listener = doc->getHTMLWindowEventListener(eventId);
1678  if (listener && static_cast<JSEventListener *>(listener)->listenerObj()) {
1679  return static_cast<JSEventListener *>(listener)->listenerObj();
1680  } else {
1681  return jsNull();
1682  }
1683 }
1684 
1685 JSEventListener *Window::getJSEventListener(JSValue *val, bool html)
1686 {
1687  // This function is so hot that it's worth coding it directly with imps.
1688  KHTMLPart *part = qobject_cast<KHTMLPart *>(m_frame->m_part);
1689  if (!part || val->type() != ObjectType) {
1690  return nullptr;
1691  }
1692 
1693  // It's ObjectType, so it must be valid.
1694  JSObject *listenerObject = val->getObject();
1695  JSObject *thisObject = listenerObject;
1696 
1697  // 'listener' is not a simple ecma function. (Always use sanity checks: Better safe than sorry!)
1698  if (!listenerObject->implementsCall() && part && part->jScript() && part->jScript()->interpreter()) {
1699  Interpreter *interpreter = part->jScript()->interpreter();
1700 
1701  // 'listener' probably is an EventListener object containing a 'handleEvent' function.
1702  JSValue *handleEventValue = listenerObject->get(interpreter->globalExec(), Identifier("handleEvent"));
1703  JSObject *handleEventObject = handleEventValue->getObject();
1704 
1705  if (handleEventObject && handleEventObject->implementsCall()) {
1706  thisObject = listenerObject;
1707  listenerObject = handleEventObject;
1708  }
1709  }
1710 
1711  JSEventListener *existingListener = jsEventListeners.value(QPair<void *, bool>(thisObject, html));
1712  if (existingListener) {
1713  assert(existingListener->isHTMLEventListener() == html);
1714  return existingListener;
1715  }
1716 
1717  // Note that the JSEventListener constructor adds it to our jsEventListeners list
1718  return new JSEventListener(listenerObject, thisObject, this, html);
1719 }
1720 
1721 JSLazyEventListener *Window::getJSLazyEventListener(const QString &code, const QString &srcUrl, int line,
1722  const QString &name, DOM::NodeImpl *node, bool svg)
1723 {
1724  return new JSLazyEventListener(code, srcUrl, line, name, this, node, svg);
1725 }
1726 
1727 void Window::clear(ExecState *exec)
1728 {
1729  Q_UNUSED(exec);
1730  delete winq;
1731  qDeleteAll(m_delayed);
1732  m_delayed.clear();
1733 
1734  winq = nullptr;
1735  // Get rid of everything, those user vars could hold references to DOM nodes
1736  clearProperties();
1737 
1738  // Ditto for the special subobjects.
1739  screen = nullptr;
1740  console = nullptr;
1741  history = nullptr;
1742  external = nullptr;
1743  loc = nullptr;
1744  setPrototype(jsNull());
1745 
1746  // Break the dependency between the listeners and their object
1747  QHashIterator<const QPair<void *, bool>, JSEventListener *> it(jsEventListeners);
1748  while (it.hasNext()) {
1749  it.next();
1750  it.value()->clear();
1751  }
1752 
1753  // Forget about the listeners (the DOM::NodeImpls will delete them)
1754  jsEventListeners.clear();
1755 
1756  if (m_frame) {
1757  KJSProxy *proxy = m_frame->m_jscript;
1758  if (proxy) { // i.e. JS not disabled
1759  winq = new WindowQObject(this);
1760  // Now recreate a working global object for the next URL that will use us
1761  KJS::Interpreter *interpreter = proxy->interpreter();
1762  interpreter->initGlobalObject();
1763  }
1764  }
1765 }
1766 
1767 void Window::setCurrentEvent(DOM::EventImpl *evt)
1768 {
1769  m_evt = evt;
1770  //qCDebug(KHTML_LOG) << "Window " << this << " (part=" << m_part << ")::setCurrentEvent m_evt=" << evt;
1771 }
1772 
1773 void Window::goURL(ExecState *exec, const QString &url, bool lockHistory)
1774 {
1775  Window *active = Window::retrieveActive(exec);
1776  KHTMLPart *part = qobject_cast<KHTMLPart *>(m_frame->m_part);
1777  KHTMLPart *active_part = qobject_cast<KHTMLPart *>(active->part());
1778  // Complete the URL using the "active part" (running interpreter)
1779  if (active_part && part) {
1780  QString dstUrl = active_part->htmlDocument().completeURL(url).string();
1781  // qCDebug(KHTML_LOG) << "Window::goURL dstUrl=" << dstUrl;
1782 
1783  // check if we're allowed to inject javascript
1784  if (!KHTMLPartPrivate::isJavaScriptURL(dstUrl) || isSafeScript(exec)) {
1785  part->scheduleRedirection(-1, dstUrl, lockHistory);
1786  }
1787  } else if (!part && m_frame->m_partContainerElement) {
1789  if (b) {
1790  emit b->openUrlRequest(QUrl(m_frame->m_partContainerElement.data()->document()->completeURL(url)));
1791  }
1792  // qCDebug(KHTML_LOG) << "goURL for ROPart";
1793  }
1794 }
1795 
1796 class DelayedGoHistory: public Window::DelayedAction
1797 {
1798 public:
1799  DelayedGoHistory(int _steps): steps(_steps)
1800  {}
1801 
1802  bool execute(Window *win) override
1803  {
1804  win->goHistory(steps);
1805  return true;
1806  }
1807 private:
1808  int steps;
1809 };
1810 
1811 void Window::delayedGoHistory(int steps)
1812 {
1813  m_delayed.append(new DelayedGoHistory(steps));
1814 }
1815 
1816 void Window::goHistory(int steps)
1817 {
1818  KHTMLPart *part = qobject_cast<KHTMLPart *>(m_frame->m_part);
1819  if (!part)
1820  // TODO history readonlypart
1821  {
1822  return;
1823  }
1825  if (!ext) {
1826  return;
1827  }
1828  KParts::BrowserInterface *iface = ext->browserInterface();
1829 
1830  if (!iface) {
1831  return;
1832  }
1833 
1834  iface->callMethod("goHistory", steps);
1835  //emit ext->goHistory(steps);
1836 }
1837 
1838 void KJS::Window::resizeTo(QWidget *tl, int width, int height)
1839 {
1840  KHTMLPart *part = qobject_cast<KHTMLPart *>(m_frame->m_part);
1841  if (!part)
1842  // TODO resizeTo readonlypart
1843  {
1844  return;
1845  }
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 
1859 
1860  if (width > sg.width() || height > sg.height()) {
1861  // qCDebug(KHTML_LOG) << "Window::resizeTo refused, window would be too big ("<<width<<","<<height<<")";
1862  return;
1863  }
1864 
1865  // qCDebug(KHTML_LOG) << "resizing to " << width << "x" << height;
1866 
1867  emit ext->resizeTopLevelWidget(width, height);
1868 
1869  // If the window is out of the desktop, move it up/left
1870  // (maybe we should use workarea instead of sg, otherwise the window ends up below kicker)
1871  int right = tl->x() + tl->frameGeometry().width();
1872  int bottom = tl->y() + tl->frameGeometry().height();
1873  int moveByX = 0;
1874  int moveByY = 0;
1875  if (right > sg.right()) {
1876  moveByX = - right + sg.right(); // always <0
1877  }
1878  if (bottom > sg.bottom()) {
1879  moveByY = - bottom + sg.bottom(); // always <0
1880  }
1881  if (moveByX || moveByY) {
1882  emit ext->moveTopLevelWidget(tl->x() + moveByX, tl->y() + moveByY);
1883  }
1884 }
1885 
1886 bool Window::targetIsExistingWindow(KHTMLPart *ourPart, const QString &frameName)
1887 {
1888  QString normalized = frameName.toLower();
1889  if (normalized == "_top" || normalized == "_self" || normalized == "_parent") {
1890  return true;
1891  }
1892 
1893  // Find the highest parent part we can access.
1894  KHTMLPart *p = ourPart;
1895  while (p->parentPart() && p->parentPart()->checkFrameAccess(ourPart)) {
1896  p = p->parentPart();
1897  }
1898 
1899  return p->findFrame(frameName);
1900 }
1901 
1902 JSValue *Window::openWindow(ExecState *exec, const List &args)
1903 {
1904  KHTMLPart *part = qobject_cast<KHTMLPart *>(m_frame->m_part);
1905  if (!part) {
1906  return jsUndefined();
1907  }
1908  KHTMLView *widget = part->view();
1909  JSValue *v = args[0];
1910  QString str;
1911  if (!v->isUndefinedOrNull()) {
1912  str = v->toString(exec).qstring();
1913  }
1914 
1915  // prepare arguments
1916  QUrl url;
1917  if (!str.isEmpty()) {
1918  KHTMLPart *p = qobject_cast<KHTMLPart *>(Window::retrieveActive(exec)->m_frame->m_part);
1919  if (p) {
1920  url = QUrl(p->htmlDocument().completeURL(str).string());
1921  }
1922  if (!p ||
1923  !static_cast<DOM::DocumentImpl *>(p->htmlDocument().handle())->isURLAllowed(url.url())) {
1924  return jsUndefined();
1925  }
1926  }
1927 
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");
1946  str.isEmpty() ?
1947  i18n("This site is requesting to open up a new browser "
1948  "window via JavaScript.\n"
1949  "Do you want to allow this?") :
1950  i18n("<qt>This site is requesting to open<p>%1</p>in a new browser window via JavaScript.<br />"
1951  "Do you want to allow this?</qt>", KStringHandler::csqueeze(url.toDisplayString().toHtmlEscaped(), 100)),
1952  caption, KGuiItem(i18n("Allow")), KGuiItem(i18n("Do Not Allow"))) == KMessageBox::PrimaryAction) {
1953  policy = KHTMLSettings::KJSWindowOpenAllow;
1954  }
1955  } else if (policy == KHTMLSettings::KJSWindowOpenSmart) {
1956  // window.open disabled unless from a key/mouse event
1957  if (static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->isWindowOpenAllowed()) {
1958  policy = KHTMLSettings::KJSWindowOpenAllow;
1959  }
1960  }
1961 
1962  v = args[2];
1963  QString features;
1964  if (v && v->type() != UndefinedType && v->toString(exec).size() > 0) {
1965  features = v->toString(exec).qstring();
1966  // Buggy scripts have ' at beginning and end, cut those
1967  if (features.startsWith(QLatin1Char('\'')) &&
1968  features.endsWith(QLatin1Char('\''))) {
1969  features = features.mid(1, features.length() - 2);
1970  }
1971  }
1972 
1973  if (policy != KHTMLSettings::KJSWindowOpenAllow) {
1974  if (url.isEmpty()) {
1975  part->setSuppressedPopupIndicator(true, nullptr);
1976  } else {
1977  part->setSuppressedPopupIndicator(true, part);
1978  m_suppressedWindowInfo.append(SuppressedWindowInfo(url, frameName, features));
1979  }
1980  return jsUndefined();
1981  } else {
1982  return executeOpenWindow(exec, url, frameName, features);
1983  }
1984 }
1985 
1986 JSValue *Window::executeOpenWindow(ExecState *exec, const QUrl &url, const QString &frameName, const QString &features)
1987 {
1988  KHTMLPart *p = qobject_cast<KHTMLPart *>(m_frame->m_part);
1989  KHTMLView *widget = p->view();
1990  KParts::WindowArgs winargs;
1991 
1992  // Split on commas and syntactic whitespace
1993  // Testcase: 'height=600, width=950 left = 30,top = 50,statusbar=0'
1994  static const QRegExp m(",|\\b\\s+(?!=)");
1995 
1996  // scan feature argument
1997  if (!features.isEmpty()) {
1998  // specifying window params means false defaults
1999  winargs.setMenuBarVisible(false);
2000  winargs.setToolBarsVisible(false);
2001  winargs.setStatusBarVisible(false);
2002  winargs.setScrollBarsVisible(false);
2003  const QStringList flist = features.trimmed().split(m);
2004  QStringList::ConstIterator it = flist.begin();
2005  while (it != flist.end()) {
2006  QString s = *it++;
2007  QString key, val;
2008  int pos = s.indexOf('=');
2009  if (pos >= 0) {
2010  key = s.left(pos).trimmed().toLower();
2011  val = s.mid(pos + 1).trimmed().toLower();
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 
2069  KParts::BrowserArguments browserArgs;
2070  browserArgs.frameName = frameName;
2071 
2072  if (browserArgs.frameName.toLower() == "_top") {
2073  while (p->parentPart()) {
2074  p = p->parentPart();
2075  }
2076  Window::retrieveWindow(p)->goURL(exec, url.url());
2077  return Window::retrieve(p);
2078  }
2079  if (browserArgs.frameName.toLower() == "_parent") {
2080  if (p->parentPart()) {
2081  p = p->parentPart();
2082  }
2083  Window::retrieveWindow(p)->goURL(exec, url.url());
2084  return Window::retrieve(p);
2085  }
2086  if (browserArgs.frameName.toLower() == "_self") {
2087  Window::retrieveWindow(p)->goURL(exec, url.url());
2088  return Window::retrieve(p);
2089  }
2090  if (browserArgs.frameName.toLower() == "replace") {
2091  Window::retrieveWindow(p)->goURL(exec, url.url(), true/*lock history*/);
2092  return Window::retrieve(p);
2093  }
2094  args.setMimeType("text/html");
2095  args.setActionRequestedByUser(false);
2096 
2097  // request window (new or existing if framename is set)
2098  KParts::ReadOnlyPart *newPart = nullptr;
2099  emit p->browserExtension()->createNewWindow(QUrl(), args, browserArgs, winargs, &newPart);
2100  if (newPart && qobject_cast<KHTMLPart *>(newPart)) {
2101  KHTMLPart *khtmlpart = static_cast<KHTMLPart *>(newPart);
2102  //qDebug("opener set to %p (this Window's part) in new Window %p (this Window=%p)",part,win,window);
2103  khtmlpart->setOpener(p);
2104  khtmlpart->setOpenedByJS(true);
2105  if (khtmlpart->document().isNull()) {
2106  khtmlpart->begin();
2107  khtmlpart->write("<HTML><BODY>");
2108  khtmlpart->end();
2109  if (p->docImpl()) {
2110  //qCDebug(KHTML_LOG) << "Setting domain to " << p->docImpl()->domain().string();
2111  khtmlpart->docImpl()->setOrigin(p->docImpl()->origin());
2112  khtmlpart->docImpl()->setBaseURL(p->docImpl()->baseURL());
2113  }
2114  }
2115  args.setMimeType(QString());
2116  if (browserArgs.frameName.toLower() == "_blank") {
2117  browserArgs.frameName.clear();
2118  }
2119  if (!url.isEmpty()) {
2120  emit khtmlpart->browserExtension()->openUrlRequest(url, args, browserArgs);
2121  }
2122  return Window::retrieve(khtmlpart); // global object
2123  } else {
2124  return jsUndefined();
2125  }
2126 }
2127 
2128 void Window::forgetSuppressedWindows()
2129 {
2130  m_suppressedWindowInfo.clear();
2131 }
2132 
2133 void Window::showSuppressedWindows()
2134 {
2135  KHTMLPart *part = qobject_cast<KHTMLPart *>(m_frame->m_part);
2136  KJS::Interpreter *interpreter = part->jScript()->interpreter();
2137  ExecState *exec = interpreter->globalExec();
2138 
2139  QList<SuppressedWindowInfo> suppressedWindowInfo = m_suppressedWindowInfo;
2140  m_suppressedWindowInfo.clear();
2141  foreach (const SuppressedWindowInfo &info, suppressedWindowInfo) {
2142  executeOpenWindow(exec, info.url, info.frameName, info.features);
2143  }
2144 }
2145 
2146 class DelayedClose: public Window::DelayedAction
2147 {
2148 public:
2149  bool execute(Window *win) override
2150  {
2151  win->scheduleClose();
2152  return false;
2153  }
2154 private:
2155  int steps;
2156 };
2157 
2158 JSValue *WindowFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
2159 {
2160  KJS_CHECK_THIS(Window, thisObj);
2161 
2162  // these should work no matter whether the window is already
2163  // closed or not
2164  if (id == Window::ValueOf || id == Window::ToString) {
2165  return jsString("[object Window]");
2166  }
2167 
2168  Window *window = static_cast<Window *>(thisObj);
2169  QString str, str2;
2170 
2171  KHTMLPart *part = qobject_cast<KHTMLPart *>(window->m_frame->m_part);
2172  if (!part) {
2173  return jsUndefined();
2174  }
2175 
2176  KHTMLView *widget = part->view();
2177  JSValue *v = args[0];
2178  UString s;
2179  s = v->toString(exec);
2180  str = s.qstring();
2181 
2182  QString caption;
2183  if (part && !part->url().host().isEmpty()) {
2184  caption = part->url().host() + " - ";
2185  }
2186  caption += "JavaScript"; // TODO: i18n
2187  // functions that work everywhere
2188  switch (id) {
2189  case Window::Alert: {
2190  TimerPauser pause(exec);
2191  if (!widget->dialogsAllowed()) {
2192  return jsUndefined();
2193  }
2194  if (part && part->xmlDocImpl()) {
2195  part->xmlDocImpl()->updateRendering();
2196  }
2197  if (part) {
2198  emit part->browserExtension()->requestFocus(part);
2199  }
2200  KMessageBox::error(widget, Qt::convertFromPlainText(str), caption);
2201  return jsUndefined();
2202  }
2203  case Window::Confirm: {
2204  TimerPauser pause(exec);
2205  if (!widget->dialogsAllowed()) {
2206  return jsUndefined();
2207  }
2208  if (part && part->xmlDocImpl()) {
2209  part->xmlDocImpl()->updateRendering();
2210  }
2211  if (part) {
2212  emit part->browserExtension()->requestFocus(part);
2213  }
2214  return jsBoolean((KMessageBox::warningTwoActions(widget, Qt::convertFromPlainText(str), caption,
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,
2233  args[1]->toString(exec).qstring(), &ok);
2234  else
2235  str2 = QInputDialog::getText(widget, caption,
2237  QLineEdit::Normal, QString(), &ok);
2238  if (ok) {
2239  return jsString(UString(str2));
2240  } else {
2241  return jsNull();
2242  }
2243 #else
2244  return jsUndefined();
2245 #endif
2246  }
2247  case Window::GetComputedStyle: {
2248  if (!part || !part->xmlDocImpl()) {
2249  return jsUndefined();
2250  }
2251  DOM::NodeImpl *arg0 = toNode(args[0]);
2252  if (!arg0 || arg0->nodeType() != DOM::Node::ELEMENT_NODE) {
2253  return jsUndefined(); // throw exception?
2254  } else
2255  return getDOMCSSStyleDeclaration(exec, part->xmlDocImpl()->defaultView()->getComputedStyle(
2256  static_cast<DOM::ElementImpl *>(arg0), args[1]->toString(exec).domString().implementation()));
2257  }
2258  case Window::Open:
2259  return window->openWindow(exec, args);
2260  case Window::Close: {
2261  /* From http://developer.netscape.com/docs/manuals/js/client/jsref/window.htm :
2262  The close method closes only windows opened by JavaScript using the open method.
2263  If you attempt to close any other window, a confirm is generated, which
2264  lets the user choose whether the window closes.
2265  This is a security feature to prevent "mail bombs" containing self.close().
2266  However, if the window has only one document (the current one) in its
2267  session history, the close is allowed without any confirm. This is a
2268  special case for one-off windows that need to open other windows and
2269  then dispose of themselves.
2270  */
2271  bool doClose = false;
2272  if (!part->openedByJS()) {
2273  // To conform to the SPEC, we only ask if the window
2274  // has more than one entry in the history (NS does that too).
2275  History history(exec, part);
2276 
2277  if (history.get(exec, "length")->toInt32(exec) <= 1) {
2278  doClose = true;
2279  } else {
2280  // Can we get this dialog with tabs??? Does it close the window or the tab in that case?
2281  emit part->browserExtension()->requestFocus(part);
2282  if (KMessageBox::questionTwoActions(window->part()->widget(),
2283  i18n("Close window?"), i18n("Confirmation Required"),
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: {
2322  part->settings()->windowFocusPolicy(part->url().host());
2323  if (policy == KHTMLSettings::KJSWindowFocusAllow && widget) {
2324  widget->topLevelWidget()->raise();
2325 #if HAVE_X11
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: {
2407  part->settings()->windowMovePolicy(part->url().host());
2408  if (policy == KHTMLSettings::KJSWindowMoveAllow && args.size() == 2 && widget) {
2410  if (ext) {
2411  QWidget *tl = widget->topLevelWidget();
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: {
2427  part->settings()->windowMovePolicy(part->url().host());
2428  if (policy == KHTMLSettings::KJSWindowMoveAllow && args.size() == 2 && widget) {
2430  if (ext) {
2431  QWidget *tl = widget->topLevelWidget();
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: {
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: {
2460  part->settings()->windowResizePolicy(part->url().host());
2461  if (policy == KHTMLSettings::KJSWindowResizeAllow
2462  && args.size() == 2 && widget) {
2463  QWidget *tl = widget->topLevelWidget();
2464  window->resizeTo(tl, args[0]->toInt32(exec), args[1]->toInt32(exec));
2465  }
2466  return jsUndefined();
2467  }
2468  case Window::SetTimeout:
2469  case Window::SetInterval: {
2470  bool singleShot;
2471  int i; // timeout interval
2472  if (args.size() == 0) {
2473  return jsUndefined();
2474  }
2475  if (args.size() > 1) {
2476  singleShot = (id == Window::SetTimeout);
2477  i = args[1]->toInt32(exec);
2478  } else {
2479  // second parameter is missing. Emulate Mozilla behavior.
2480  singleShot = true;
2481  i = 4;
2482  }
2483  if (v->type() == StringType) {
2484  int r = (const_cast<Window *>(window))->winq->installTimeout(Identifier(s), i, singleShot);
2485  return jsNumber(r);
2486  } else if (v->type() == ObjectType && v->getObject()->implementsCall()) {
2487  JSObject *func = v->getObject();
2488  List funcArgs;
2489  ListIterator it = args.begin();
2490  int argno = 0;
2491  while (it != args.end()) {
2492  JSValue *arg = it++;
2493  if (argno++ >= 2) {
2494  funcArgs.append(arg);
2495  }
2496  }
2497  if (args.size() < 2) {
2498  funcArgs.append(jsNumber(i));
2499  }
2500  int r = (const_cast<Window *>(window))->winq->installTimeout(func, funcArgs, i, singleShot);
2501  return jsNumber(r);
2502  } else {
2503  return jsUndefined();
2504  }
2505  }
2506  case Window::ClearTimeout:
2507  case Window::ClearInterval:
2508  (const_cast<Window *>(window))->winq->clearTimeout(v->toInt32(exec));
2509  return jsUndefined();
2510  case Window::Print:
2511  if (widget) {
2512  // ### TODO emit onbeforeprint event
2513  widget->print();
2514  // ### TODO emit onafterprint event
2515  }
2516  case Window::CaptureEvents:
2517  case Window::ReleaseEvents:
2518  // Do nothing for now. These are NS-specific legacy calls.
2519  break;
2520  case Window::AddEventListener: {
2521  JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]);
2522  if (listener) {
2523  DOM::DocumentImpl *docimpl = static_cast<DOM::DocumentImpl *>(part->document().handle());
2524  if (docimpl) {
2525  docimpl->addWindowEventListener(EventName::fromString(args[0]->toString(exec).domString()), listener, args[2]->toBoolean(exec));
2526  } else {
2527  qCWarning(KHTML_LOG) << "document missing on Window::AddEventListener. why?";
2528  }
2529  }
2530  return jsUndefined();
2531  }
2532  case Window::RemoveEventListener: {
2533  JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]);
2534  if (listener) {
2535  DOM::DocumentImpl *docimpl = static_cast<DOM::DocumentImpl *>(part->document().handle());
2536  if (docimpl) {
2537  docimpl->removeWindowEventListener(EventName::fromString(args[0]->toString(exec).domString()), listener, args[2]->toBoolean(exec));
2538  } else {
2539  qCWarning(KHTML_LOG) << "document missing on Window::RemoveEventListener. why?";
2540  }
2541  }
2542  return jsUndefined();
2543  }
2544 
2545  }
2546  return jsUndefined();
2547 }
2548 
2549 ////////////////////// ScheduledAction ////////////////////////
2550 
2551 ScheduledAction::ScheduledAction(JSObject *_func, const List &_args, const DateTimeMS &_nextTime, int _interval, bool _singleShot,
2552  int _timerId)
2553 {
2554  //qCDebug(KHTML_LOG) << "ScheduledAction::ScheduledAction(isFunction) " << this;
2555  func = static_cast<JSObject *>(_func);
2556  args = _args;
2557  isFunction = true;
2558  singleShot = _singleShot;
2559  nextTime = _nextTime;
2560  interval = _interval;
2561  executing = false;
2562  timerId = _timerId;
2563 }
2564 
2565 ScheduledAction::ScheduledAction(const QString &_code, const DateTimeMS &_nextTime, int _interval, bool _singleShot, int _timerId)
2566 {
2567  //qCDebug(KHTML_LOG) << "ScheduledAction::ScheduledAction(!isFunction) " << this;
2568  //func = 0;
2569  //args = 0;
2570  func = nullptr;
2571  code = _code;
2572  isFunction = false;
2573  singleShot = _singleShot;
2574  nextTime = _nextTime;
2575  interval = _interval;
2576  executing = false;
2577  timerId = _timerId;
2578 }
2579 
2580 bool ScheduledAction::execute(Window *window)
2581 {
2582  KHTMLPart *part = qobject_cast<KHTMLPart *>(window->m_frame->m_part);
2583  if (!part || !part->jScriptEnabled()) {
2584  return false;
2585  }
2586  ScriptInterpreter *interpreter = static_cast<ScriptInterpreter *>(part->jScript()->interpreter());
2587 
2588  interpreter->setProcessingTimerCallback(true);
2589 
2590  //qCDebug(KHTML_LOG) << "ScheduledAction::execute " << this;
2591  if (isFunction) {
2592  if (func->implementsCall()) {
2593  // #### check this
2594  Q_ASSERT(part);
2595  if (part) {
2596  KJS::Interpreter *interpreter = part->jScript()->interpreter();
2597  ExecState *exec = interpreter->globalExec();
2598  Q_ASSERT(window == interpreter->globalObject());
2599  JSObject *obj(window);
2600  func->call(exec, obj, args); // note that call() creates its own execution state for the func call
2601  if (exec->hadException()) {
2602  exec->clearException();
2603  }
2604 
2605  // Update our document's rendering following the execution of the timeout callback.
2606  part->document().updateRendering();
2607  }
2608  }
2609  } else {
2610  part->executeScript(DOM::Node(), code);
2611  }
2612 
2613  interpreter->setProcessingTimerCallback(false);
2614  return true;
2615 }
2616 
2617 void ScheduledAction::mark()
2618 {
2619  if (func && !func->marked()) {
2620  func->mark();
2621  }
2622 }
2623 
2624 ScheduledAction::~ScheduledAction()
2625 {
2626  args.reset();
2627  //qCDebug(KHTML_LOG) << "ScheduledAction::~ScheduledAction " << this;
2628 }
2629 
2630 ////////////////////// WindowQObject ////////////////////////
2631 
2632 WindowQObject::WindowQObject(Window *w)
2633  : parent(w)
2634 {
2635  //qCDebug(KHTML_LOG) << "WindowQObject::WindowQObject " << this;
2636  if (!parent->m_frame) {
2637  // qCDebug(KHTML_LOG) << "WARNING: null part in " ;
2638  } else
2639  connect(parent->m_frame, SIGNAL(destroyed()),
2640  this, SLOT(parentDestroyed()));
2641  pauseLevel = 0;
2642  lastTimerId = 0;
2643  currentlyDispatching = false;
2644 }
2645 
2646 WindowQObject::~WindowQObject()
2647 {
2648  //qCDebug(KHTML_LOG) << "WindowQObject::~WindowQObject " << this;
2649  parentDestroyed(); // reuse same code
2650 }
2651 
2652 void WindowQObject::parentDestroyed()
2653 {
2654  killTimers();
2655 
2656  while (!scheduledActions.isEmpty()) {
2657  delete scheduledActions.takeFirst();
2658  }
2659  scheduledActions.clear();
2660 }
2661 
2662 void WindowQObject::pauseTimers()
2663 {
2664  ++pauseLevel;
2665  if (pauseLevel == 1) {
2666  pauseStart = DateTimeMS::now();
2667  }
2668 }
2669 
2670 void WindowQObject::resumeTimers()
2671 {
2672  if (pauseLevel == 1) {
2673  // Adjust all timers by the delay length, making sure there is a minimum
2674  // margin from current time, however, so we don't go stampeding off if
2675  // there is some unwanted recursion, etc.
2676  DateTimeMS curTime = DateTimeMS::now();
2677  DateTimeMS earliestDispatch = curTime.addMSecs(5);
2678  int delay = pauseStart.msecsTo(curTime);
2679  foreach (ScheduledAction *action, scheduledActions) {
2680  action->nextTime = action->nextTime.addMSecs(delay);
2681  if (earliestDispatch > action->nextTime) {
2682  action->nextTime = earliestDispatch;
2683  }
2684  }
2685 
2686  // Dispatch any timers that may have been ignored if ::timerEvent fell in the middle
2687  // of a pause..
2688  timerEvent(nullptr);
2689  }
2690 
2691  --pauseLevel; // We do it afterwards so that timerEvent can know about us.
2692 }
2693 
2694 int WindowQObject::installTimeout(const Identifier &handler, int t, bool singleShot)
2695 {
2696  int id = ++lastTimerId;
2697  if (t < 10) {
2698  t = 10;
2699  }
2700  DateTimeMS nextTime = DateTimeMS::now().addMSecs(t);
2701 
2702  ScheduledAction *action = new ScheduledAction(handler.qstring(), nextTime, t, singleShot, id);
2703  scheduledActions.append(action);
2704  setNextTimer();
2705  return id;
2706 }
2707 
2708 int WindowQObject::installTimeout(JSValue *func, List args, int t, bool singleShot)
2709 {
2710  JSObject *objFunc = func->getObject();
2711  if (!objFunc) {
2712  return 0;
2713  }
2714  int id = ++lastTimerId;
2715  if (t < 10) {
2716  t = 10;
2717  }
2718 
2719  DateTimeMS nextTime = DateTimeMS::now().addMSecs(t);
2720  ScheduledAction *action = new ScheduledAction(objFunc, args, nextTime, t, singleShot, id);
2721  scheduledActions.append(action);
2722  setNextTimer();
2723  return id;
2724 }
2725 
2726 void WindowQObject::clearTimeout(int timerId)
2727 {
2728  foreach (ScheduledAction *action, scheduledActions) {
2729  if (action->timerId == timerId) {
2730  scheduledActions.removeAll(action);
2731  if (!action->executing) {
2732  delete action;
2733  }
2734  return;
2735  }
2736  }
2737 }
2738 
2739 bool WindowQObject::hasTimers() const
2740 {
2741  return scheduledActions.count();
2742 }
2743 
2744 void WindowQObject::mark()
2745 {
2746  foreach (ScheduledAction *action, scheduledActions) {
2747  action->mark();
2748  }
2749 }
2750 
2751 void WindowQObject::timerEvent(QTimerEvent *)
2752 {
2753  killTimers();
2754 
2755  if (scheduledActions.isEmpty()) {
2756  return;
2757  }
2758 
2759  if (pauseLevel) {
2760  return;
2761  }
2762 
2763  currentlyDispatching = true;
2764 
2765  DateTimeMS current = DateTimeMS::now();
2766 
2767  // Work out which actions are to be executed. We take a separate copy of
2768  // this list since the main one may be modified during action execution
2769  QList<ScheduledAction *> toExecute;
2770  foreach (ScheduledAction *action, scheduledActions) {
2771  if (current >= action->nextTime) {
2772  toExecute.append(action);
2773  }
2774  }
2775 
2776  // ### verify that the window can't be closed (and action deleted) during execution
2777  foreach (ScheduledAction *action, toExecute) {
2778  if (!scheduledActions.count(action)) { // removed by clearTimeout()
2779  continue;
2780  }
2781 
2782  action->executing = true; // prevent deletion in clearTimeout()
2783 
2784  if (parent->part()) {
2785  bool ok = action->execute(parent);
2786  if (!ok) { // e.g. JS disabled
2787  scheduledActions.removeAll(action);
2788  }
2789  }
2790 
2791  if (action->singleShot) {
2792  scheduledActions.removeAll(action);
2793  }
2794 
2795  action->executing = false;
2796 
2797  if (!scheduledActions.count(action)) {
2798  delete action;
2799  } else {
2800  action->nextTime = action->nextTime.addMSecs(action->interval);
2801  }
2802  }
2803 
2804  currentlyDispatching = false;
2805 
2806  // Work out when next event is to occur
2807  setNextTimer();
2808 
2809  // unless we're inside a nested context, do post-script processing
2810  if (!pauseLevel) {
2811  parent->afterScriptExecution();
2812  }
2813 }
2814 
2815 DateTimeMS DateTimeMS::addMSecs(int s) const
2816 {
2817  DateTimeMS c = *this;
2818  c.mTime = mTime.addMSecs(s);
2819  if (s > 0) {
2820  if (c.mTime < mTime) {
2821  c.mDate = mDate.addDays(1);
2822  }
2823  } else {
2824  if (c.mTime > mTime) {
2825  c.mDate = mDate.addDays(-1);
2826  }
2827  }
2828  return c;
2829 }
2830 
2831 bool DateTimeMS::operator >(const DateTimeMS &other) const
2832 {
2833  if (mDate > other.mDate) {
2834  return true;
2835  }
2836 
2837  if (mDate < other.mDate) {
2838  return false;
2839  }
2840 
2841  return mTime > other.mTime;
2842 }
2843 
2844 bool DateTimeMS::operator >=(const DateTimeMS &other) const
2845 {
2846  if (mDate > other.mDate) {
2847  return true;
2848  }
2849 
2850  if (mDate < other.mDate) {
2851  return false;
2852  }
2853 
2854  return mTime >= other.mTime;
2855 }
2856 
2857 int DateTimeMS::msecsTo(const DateTimeMS &other) const
2858 {
2859  int d = mDate.daysTo(other.mDate);
2860  int ms = mTime.msecsTo(other.mTime);
2861  return d * 24 * 60 * 60 * 1000 + ms;
2862 }
2863 
2864 DateTimeMS DateTimeMS::now()
2865 {
2866  DateTimeMS t;
2867  QTime before = QTime::currentTime();
2868  t.mDate = QDate::currentDate();
2869  t.mTime = QTime::currentTime();
2870  if (t.mTime < before) {
2871  t.mDate = QDate::currentDate(); // prevent race condition in hacky way :)
2872  }
2873  return t;
2874 }
2875 
2876 void WindowQObject::setNextTimer()
2877 {
2878  if (currentlyDispatching) {
2879  return; // Will schedule at the end
2880  }
2881 
2882  if (scheduledActions.isEmpty()) {
2883  return;
2884  }
2885 
2886  QListIterator<ScheduledAction *> it(scheduledActions);
2887  DateTimeMS nextTime = it.next()->nextTime;
2888  while (it.hasNext()) {
2889  const DateTimeMS &currTime = it.next()->nextTime;
2890  if (nextTime > currTime) {
2891  nextTime = currTime;
2892  }
2893  }
2894 
2895  int nextInterval = DateTimeMS::now().msecsTo(nextTime);
2896  if (nextInterval < 0) {
2897  nextInterval = 0;
2898  }
2899  timerIds.append(startTimer(nextInterval));
2900 }
2901 
2902 void WindowQObject::killTimers()
2903 {
2904  for (int i = 0; i < timerIds.size(); ++i) {
2905  killTimer(timerIds.at(i));
2906  }
2907  timerIds.clear();
2908 }
2909 
2910 void WindowQObject::timeoutClose()
2911 {
2912  parent->closeNow();
2913 }
2914 
2915 ////////////////////// Location Object ////////////////////////
2916 
2917 const ClassInfo Location::info = { "Location", nullptr, &LocationTable, nullptr };
2918 /*
2919 @begin LocationTable 11
2920  hash Location::Hash DontDelete
2921  host Location::Host DontDelete
2922  hostname Location::Hostname DontDelete
2923  href Location::Href DontDelete
2924  pathname Location::Pathname DontDelete
2925  port Location::Port DontDelete
2926  protocol Location::Protocol DontDelete
2927  search Location::Search DontDelete
2928  [[==]] Location::EqualEqual DontDelete|ReadOnly
2929  assign Location::Assign DontDelete|Function 1
2930  toString Location::ToString DontDelete|Function 0
2931  replace Location::Replace DontDelete|Function 1
2932  reload Location::Reload DontDelete|Function 0
2933 @end
2934 */
2935 KJS_IMPLEMENT_PROTOFUNC(LocationFunc)
2936 Location::Location(khtml::ChildFrame *f) : m_frame(f)
2937 {
2938  //qCDebug(KHTML_LOG) << "Location::Location " << this << " m_part=" << (void*)m_part;
2939 }
2940 
2941 Location::~Location()
2942 {
2943  //qCDebug(KHTML_LOG) << "Location::~Location " << this << " m_part=" << (void*)m_part;
2944 }
2945 
2946 KParts::ReadOnlyPart *Location::part() const
2947 {
2948  return m_frame ? static_cast<KParts::ReadOnlyPart *>(m_frame->m_part) : nullptr;
2949 }
2950 
2951 bool Location::getOwnPropertySlot(ExecState *exec, const Identifier &p, PropertySlot &slot)
2952 {
2953 #ifdef KJS_VERBOSE
2954  qCDebug(KHTML_LOG) << "Location::getOwnPropertySlot " << p.qstring() << " m_part=" << (void *)m_frame->m_part;
2955 #endif
2956 
2957  if (m_frame.isNull() || m_frame->m_part.isNull()) {
2958  return jsUndefined();
2959  }
2960 
2961  const HashEntry *entry = Lookup::findEntry(&LocationTable, p);
2962 
2963  if (entry) {
2964  // properties that work on all Location objects
2965  if (entry->value == Replace) {
2966  getSlotFromEntry<LocationFunc, Location>(entry, this, slot);
2967  return true;
2968  }
2969 
2970  // XSS check
2971  const Window *window = Window::retrieveWindow(m_frame->m_part);
2972  if (!window || !window->isSafeScript(exec)) {
2973  slot.setUndefined(this);
2974  return true;
2975  }
2976 
2977  // XSS check passed - can now dispatch normally.
2978  getSlotFromEntry<LocationFunc, Location>(entry, this, slot);
2979  return true;
2980  }
2981 
2982  return JSObject::getOwnPropertySlot(exec, p, slot);
2983 }
2984 
2985 JSValue *Location::getValueProperty(ExecState *exec, int token) const
2986 {
2987  QUrl url = m_frame->m_part->url();
2988  switch (token) {
2989  case Hash: {
2990  const QString encodedHash = url.fragment(QUrl::FullyEncoded);
2991  if (encodedHash.isEmpty()) {
2992  return jsString("");
2993  }
2994  return jsString(QLatin1Char('#') + encodedHash);
2995  }
2996  case Host: {
2997  UString str = url.host();
2998  if (url.port() > 0) {
2999  str += QString(QLatin1Char(':') + QString::number(url.port()));
3000  }
3001  return jsString(str);
3002  // Note: this is the IE spec. The NS spec swaps the two, it says
3003  // "The hostname property is the concatenation of the host and port properties, separated by a colon."
3004  // Bleh.
3005  }
3006  case Hostname:
3007  return jsString(UString(url.host()));
3008  case Href:
3009  if (url.isEmpty()) {
3010  return jsString("about:blank");
3011  } else if (url.path().isEmpty()) {
3012  return jsString(UString(url.toDisplayString() + '/'));
3013  } else {
3014  return jsString(UString(url.toDisplayString()));
3015  }
3016  case Pathname:
3017  if (url.isEmpty()) {
3018  return jsString("");
3019  }
3020  return jsString(UString(url.path().isEmpty() ? QString("/") : url.path()));
3021  case Port:
3022  return jsString(UString(url.port() > 0 ? QString::number(url.port()) : QLatin1String("")));
3023  case Protocol:
3024  return jsString(UString(url.scheme() + ':'));
3025  case Search:
3026  return jsString(UString(url.query()));
3027  case EqualEqual: // [[==]]
3028  return jsString(toString(exec));
3029  }
3030  return jsUndefined();
3031 }
3032 
3033 void Location::put(ExecState *exec, const Identifier &p, JSValue *v, int attr)
3034 {
3035 #ifdef KJS_VERBOSE
3036  qCDebug(KHTML_LOG) << "Location::put " << p.qstring() << " m_part=" << (void *)m_frame->m_part;
3037 #endif
3038  if (m_frame.isNull() || m_frame->m_part.isNull()) {
3039  return;
3040  }
3041 
3042  Window *window = Window::retrieveWindow(m_frame->m_part);
3043  if (!window) {
3044  return;
3045  }
3046 
3047  QUrl url = m_frame->m_part->url();
3048 
3049  const HashEntry *entry = Lookup::findEntry(&LocationTable, p);
3050 
3051  if (entry) {
3052 
3053  // XSS check. Only new hrefs can be set from other sites
3054  if (entry->value != Href && !window->isSafeScript(exec)) {
3055  return;
3056  }
3057 
3058  QString str = v->toString(exec).qstring();
3059  switch (entry->value) {
3060  case Href: {
3061  KHTMLPart *p = qobject_cast<KHTMLPart *>(Window::retrieveActive(exec)->part());
3062  if (p) {
3063  url = QUrl(p->htmlDocument().completeURL(str).string());
3064  } else {
3065  url = QUrl(str);
3066  }
3067  break;
3068  }
3069  case Hash:
3070  // Strip any leading # --- setting hash to #foo is the same as setting it to foo.
3071  if (str.startsWith(QLatin1Char('#'))) {
3072  str = str.mid(1);
3073  }
3074 
3075  // Note that we want to do gotoAnchor even when the hash is already set, so we
3076  // scroll the destination into view.
3077 
3078  // Setting this must always provide a ref, even if just # see
3079  // HTML5 2.6.
3080  if (str.isEmpty()) {
3081  url.setFragment("");
3082  } else {
3084  }
3085  break;
3086  case Host: {
3087  QString host = str.left(str.indexOf(":"));
3088  QString port = str.mid(str.indexOf(":") + 1);
3089  url.setHost(host);
3090  url.setPort(port.toUInt());
3091  break;
3092  }
3093  case Hostname:
3094  url.setHost(str);
3095  break;
3096  case Pathname:
3097  url.setPath(str);
3098  break;
3099  case Port:
3100  url.setPort(str.toUInt());
3101  break;
3102  case Protocol:
3103  url.setScheme(str);
3104  break;
3105  case Search:
3106  url.setQuery(str);
3107  break;
3108  }
3109  } else {
3110  JSObject::put(exec, p, v, attr);
3111  return;
3112  }
3113 
3114  window->goURL(exec, url.url());
3115 }
3116 
3117 JSValue *Location::toPrimitive(ExecState *exec, JSType) const
3118 {
3119  if (m_frame) {
3120  Window *window = Window::retrieveWindow(m_frame->m_part);
3121  if (window && window->isSafeScript(exec)) {
3122  return jsString(toString(exec));
3123  }
3124  }
3125  return jsUndefined();
3126 }
3127 
3128 UString Location::toString(ExecState *exec) const
3129 {
3130  if (m_frame) {
3131  Window *window = Window::retrieveWindow(m_frame->m_part);
3132  if (window && window->isSafeScript(exec)) {
3133  QUrl url = m_frame->m_part->url();
3134  if (url.isEmpty()) {
3135  return "about:blank";
3136  } else if (url.path().isEmpty()) {
3137  return QString(url.toDisplayString() + '/');
3138  } else {
3139  return url.toDisplayString();
3140  }
3141  }
3142  }
3143  return "";
3144 }
3145 
3146 JSValue *LocationFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
3147 {
3148  KJS_CHECK_THIS(Location, thisObj);
3149  Location *location = static_cast<Location *>(thisObj);
3150  KParts::ReadOnlyPart *part = location->part();
3151 
3152  if (!part) {
3153  return jsUndefined();
3154  }
3155 
3156  Window *window = Window::retrieveWindow(part);
3157 
3158  if (!window->isSafeScript(exec) && id != Location::Replace) {
3159  return jsUndefined();
3160  }
3161 
3162  switch (id) {
3163  case Location::Assign:
3164  window->goURL(exec, args[0]->toString(exec).qstring());
3165  break;
3166  case Location::Replace:
3167  window->goURL(exec, args[0]->toString(exec).qstring(), true/*lock history*/);
3168  break;
3169  case Location::Reload: {
3170  KHTMLPart *khtmlpart = qobject_cast<KHTMLPart *>(part);
3171  if (khtmlpart) {
3172  khtmlpart->scheduleRedirection(-1, part->url().toString(), true/*lock history*/);
3173  } else {
3174  part->openUrl(part->url());
3175  }
3176  break;
3177  }
3178  case Location::ToString:
3179  return jsString(location->toString(exec));
3180  }
3181  return jsUndefined();
3182 }
3183 
3184 ////////////////////// External Object ////////////////////////
3185 
3186 const ClassInfo External::info = { "External", nullptr, nullptr, nullptr };
3187 /*
3188 @begin ExternalTable 4
3189  addFavorite External::AddFavorite DontDelete|Function 1
3190 @end
3191 */
3192 KJS_IMPLEMENT_PROTOFUNC(ExternalFunc)
3193 
3194 bool External::getOwnPropertySlot(ExecState *exec, const Identifier &p, PropertySlot &propertySlot)
3195 {
3196  return getStaticFunctionSlot<ExternalFunc, JSObject>(exec, &ExternalTable, this, p, propertySlot);
3197 }
3198 
3199 JSValue *ExternalFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
3200 {
3201  KJS_CHECK_THIS(External, thisObj);
3202  External *external = static_cast<External *>(thisObj);
3203 
3204  KHTMLPart *part = external->part;
3205  if (!part) {
3206  return jsUndefined();
3207  }
3208 
3209  switch (id) {
3210  case External::AddFavorite: {
3211 #ifndef KONQ_EMBEDDED
3212  KHTMLView *widget = part->view();
3213  if (!widget->dialogsAllowed()) {
3214  return jsUndefined();
3215  }
3216  part->xmlDocImpl()->updateRendering();
3217  if (args.size() != 1 && args.size() != 2) {
3218  return jsUndefined();
3219  }
3220 
3221  QString url = args[0]->toString(exec).qstring();
3222  QString title;
3223  if (args.size() == 2) {
3224  title = args[1]->toString(exec).qstring();
3225  }
3226 
3227  // AK - don't do anything yet, for the moment i
3228  // just wanted the base js handling code in cvs
3229  return jsUndefined();
3230 
3231  QString question;
3232  if (title.isEmpty())
3233  question = i18n("Do you want a bookmark pointing to the location \"%1\" to be added to your collection?",
3234  url);
3235  else
3236  question = i18n("Do you want a bookmark pointing to the location \"%1\" titled \"%2\" to be added to your collection?",
3237  url, title);
3238 
3239  emit part->browserExtension()->requestFocus(part);
3240 
3241  QString caption;
3242  if (!part->url().host().isEmpty()) {
3243  caption = part->url().host() + " - ";
3244  }
3245  caption += i18n("JavaScript Attempted Bookmark Insert");
3246 
3248  widget, question, caption,
3249  KGuiItem(i18n("Insert")), KGuiItem(i18n("Disallow"))) == KMessageBox::PrimaryAction) {
3251  KBookmarkDialog dlg(mgr, nullptr);
3252  dlg.addBookmark(title, QUrl(url), KIO::iconNameForUrl(QUrl(url)));
3253  }
3254 #else
3255  return jsUndefined();
3256 #endif
3257  break;
3258  }
3259  default:
3260  return jsUndefined();
3261  }
3262 
3263  return jsUndefined();
3264 }
3265 
3266 ////////////////////// History Object ////////////////////////
3267 
3268 const ClassInfo History::info = { "History", nullptr, nullptr, nullptr };
3269 /*
3270 @begin HistoryTable 4
3271  length History::Length DontDelete|ReadOnly
3272  back History::Back DontDelete|Function 0
3273  forward History::Forward DontDelete|Function 0
3274  go History::Go DontDelete|Function 1
3275 @end
3276 */
3277 KJS_IMPLEMENT_PROTOFUNC(HistoryFunc)
3278 
3279 bool History::getOwnPropertySlot(ExecState *exec, const Identifier &p, PropertySlot &slot)
3280 {
3281  return getStaticPropertySlot<HistoryFunc, History, JSObject>(exec, &HistoryTable, this, p, slot);
3282 }
3283 
3284 JSValue *History::getValueProperty(ExecState *, int token) const
3285 {
3286  // if previous or next is implemented, make sure it is not a major
3287  // privacy leak (see i.e. http://security.greymagic.com/adv/gm005-op/)
3288  switch (token) {
3289  case Length: {
3290  if (!part) {
3291  return jsNumber(0);
3292  }
3293 
3295  if (!ext) {
3296  return jsNumber(0);
3297  }
3298 
3299  KParts::BrowserInterface *iface = ext->browserInterface();
3300  if (!iface) {
3301  return jsNumber(0);
3302  }
3303 
3304  QVariant length = iface->property("historyLength");
3305 
3306  if (length.type() != QVariant::UInt) {
3307  return jsNumber(0);
3308  }
3309 
3310  return jsNumber(length.toUInt());
3311  }
3312  default:
3313  // qCDebug(KHTML_LOG) << "WARNING: Unhandled token in History::getValueProperty : " << token;
3314  return jsUndefined();
3315  }
3316 }
3317 
3318 JSValue *HistoryFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
3319 {
3320  KJS_CHECK_THIS(History, thisObj);
3321  History *history = static_cast<History *>(thisObj);
3322 
3323  JSValue *v = args[0];
3324  double n = 0.0;
3325  if (v) {
3326  n = v->toInteger(exec);
3327  }
3328 
3329  int steps;
3330  switch (id) {
3331  case History::Back:
3332  steps = -1;
3333  break;
3334  case History::Forward:
3335  steps = 1;
3336  break;
3337  case History::Go:
3338  steps = (int)n;
3339  break;
3340  default:
3341  return jsUndefined();
3342  }
3343 
3344  // Special case for go(0) from a frame -> reload only the frame
3345  // go(i!=0) from a frame navigates into the history of the frame only,
3346  // in both IE and NS (but not in Mozilla).... we can't easily do that
3347  // in Konqueror...
3348  if (!steps) { // add && history->part->parentPart() to get only frames, but doesn't matter
3349  history->part->openUrl(history->part->url()); /// ## need args.reload=true?
3350  } else {
3351  // Delay it.
3352  // Testcase: history.back(); alert("hello");
3353  Window *window = Window::retrieveWindow(history->part);
3354  window->delayedGoHistory(steps);
3355  }
3356  return jsUndefined();
3357 }
3358 
3359 } // namespace KJS
3360 
3361 #include "moc_kjs_window.cpp"
void append(const T &value)
void append(JSValue *val)
virtual void mark(bool currentThreadIsMainThread)
QScrollBar * verticalScrollBar() const const
int depth() const const
QTextStream & right(QTextStream &stream)
void setJSDefaultStatusBarText(const QString &text)
Called by KJS.
QWidget * topLevelWidget() const const
KJSWindowFocusPolicy
This enum specifies the policy for window.focus.
char * ascii() const
QDesktopWidget * desktop()
virtual void end()
Call this after your last call to write().
void createNewWindow(const QUrl &url, const KParts::OpenUrlArguments &arguments=KParts::OpenUrlArguments(), const KParts::BrowserArguments &browserArguments=KParts::BrowserArguments(), const KParts::WindowArgs &windowArgs=KParts::WindowArgs(), KParts::ReadOnlyPart **part=nullptr)
void updateRendering()
not part of the DOM
Definition: dom_doc.cpp:703
const KHTMLSettings * settings() const
QString number(int n, int base)
QVariant location(const QVariant &res)
VehicleSection::Features features(QStringView coachNumber, QStringView coachClassification)
JSGlobalObject * globalObject() const
QString toHtmlEscaped() const const
int right() const const
Introduced in DOM Level 2.
Definition: dom2_events.h:69
Type type(const QSqlDatabase &db)
QString scheme() const const
int size() const
int count(const T &value) const const
void callMethod(const char *name, const QVariant &argument)
QString trimmed() const const
void clear()
QString url(QUrl::FormattingOptions options) const const
int contentsX() const
Returns the x coordinate of the contents area point that is currently located at the top left in the ...
Definition: khtmlview.cpp:710
The CSSRule interface is the abstract base interface for any type of CSS statement .
Definition: css_rule.h:53
QTime addMSecs(int ms) const const
int width() const const
int contentsY() const
Returns the y coordinate of the contents area point that is currently located at the top left in the ...
Definition: khtmlview.cpp:715
QString fromPercentEncoding(const QByteArray &input)
static KBookmarkManager * userBookmarksManager()
virtual ExecState * globalExec()
int x() const const
int y() const const
QString query(QUrl::ComponentFormattingOptions options) const const
void setHost(const QString &host, QUrl::ParsingMode mode)
virtual void write(const char *str, int len=-1)
Writes another part of the HTML code to the widget.
We inherit from Interpreter, to save a pointer to the HTML part that the interpreter runs for.
Definition: kjs_binding.h:96
bool implementsCall() const
This library provides a full-featured HTML parser and widget.
int x() const const
int y() const const
int size() const
This class is khtml's main class.
Definition: khtml_part.h:208
QString jsDefaultStatusBarText() const
Called by KJS.
QByteArray toBase64(QByteArray::Base64Options options) const const
int width() const const
void setJSStatusBarText(const QString &text)
Called by KJS.
QRect intersected(const QRect &rectangle) const const
QString caption()
ListIterator end() const
UString substr(int pos=0, int len=-1) const
virtual QSize sizeHint() const const override
const QRect screenGeometry(const QWidget *widget) const const
like QDateTime, but properly handles milliseconds
Definition: kjs_window.h:273
bool is8Bit() const
void setScheme(const QString &scheme)
KGuiItem close()
For each name, we hold a reference count, and a pointer.
Definition: dom_docimpl.h:160
KGuiItem cancel()
void setSuppressedPopupIndicator(bool enable, KHTMLPart *originPart=nullptr)
Shows or hides the suppressed popup indicator.
bool hadException() const
An action (either function or string) to be executed after a specified time interval,...
Definition: kjs_window.h:292
bool isVisible() const const
QTime currentTime()
Window
Definition: kjs_window.h:393
void deleteLater()
KJS_EXTERNAL_EXPORT QString qstring() const
Renders and displays HTML in a QScrollArea.
Definition: khtmlview.h:97
int bottom() const const
QString toString(QUrl::FormattingOptions options) const const
KHTMLPart * findFrame(const QString &f)
Finds a frame by name.
void clearException()
QString i18n(const char *text, const TYPE &arg...)
KCOREADDONS_EXPORT QString csqueeze(const QString &str, int maxlen=40)
bool isEmpty() const const
int height() const const
QVariant::Type type() const const
DOM operations only raise exceptions in "exceptional" circumstances, i.e., when an operation is impos...
Definition: dom_exception.h:58
FullyEncoded
static void unminimizeWindow(WId win)
QVariant executeScript(const DOM::Node &n, const QString &script)
Same as executeScript( const QString & ) except with the Node parameter specifying the 'this' value.
The Document interface represents the entire HTML or XML document.
Definition: dom_doc.h:246
KHTMLView * view() const
Returns a pointer to the HTML document's view.
void requestFocus(KParts::ReadOnlyPart *part)
bool isEmpty() const const
QByteArray toUtf8() const const
QString toDisplayString(QUrl::FormattingOptions options) const const
void moveTopLevelWidget(int x, int y)
static BrowserExtension * childObject(QObject *obj)
const T & at(int i) const const
void setPort(int port)
uint toUInt(bool *ok) const const
void activateWindow()
ObjectType
QAction * replace(const QObject *recvr, const char *slot, QObject *parent)
QByteArray fromBase64(const QByteArray &base64, QByteArray::Base64Options options)
QString getText(QWidget *parent, const QString &title, const QString &label, QLineEdit::EchoMode mode, const QString &text, bool *ok, Qt::WindowFlags flags, Qt::InputMethodHints inputMethodHints)
void resizeTopLevelWidget(int w, int h)
float toFloat(bool *ok) const const
Q_SCRIPTABLE Q_NOREPLY void pause()
KJSWindowMovePolicy
This enum specifies the policy for window.moveBy and .moveTo.
virtual void begin(const QUrl &url=QUrl(), int xOffset=0, int yOffset=0)
Clears the widget and prepares it for new content.
ButtonCode warningTwoActions(QWidget *parent, const QString &text, const QString &title, const KGuiItem &primaryAction, const KGuiItem &secondaryAction, const QString &dontAskAgainName=QString(), Options options=Options(Notify|Dangerous))
QDate currentDate()
DOMString completeURL(const DOMString &url) const
not part of the DOM
QPoint mapToGlobal(const QPoint &pos) const const
QDate addDays(qint64 ndays) const const
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
ButtonCode questionTwoActions(QWidget *parent, const QString &text, const QString &title, const KGuiItem &primaryAction, const KGuiItem &secondaryAction, const QString &dontAskAgainName=QString(), Options options=Notify)
QString convertFromPlainText(const QString &plain, Qt::WhiteSpaceMode mode)
virtual bool openUrl(const QUrl &url)
QScrollBar * horizontalScrollBar() const const
uint toUInt(bool *ok, int base) const const
PM_DefaultFrameWidth
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
void setContentsPos(int x, int y)
Place the contents area point x/y at the top left of the viewport.
Definition: khtmlview.cpp:752
void setQuery(const QString &query, QUrl::ParsingMode mode)
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
typedef ConstIterator
Width
ScriptableExtension * host() const
QString toLower() const const
QString jsStatusBarText() const
Called by KJS.
QString host(QUrl::ComponentFormattingOptions options) const const
void openUrlRequest(const QUrl &url, const KParts::OpenUrlArguments &arguments=KParts::OpenUrlArguments(), const KParts::BrowserArguments &browserArguments=KParts::BrowserArguments())
KJSWindowResizePolicy
This enum specifies the policy for window.resizeBy and .resizeTo.
void scheduleRedirection(int delay, const QString &url, bool lockHistory=true)
Schedules a redirection after delay seconds.
int visibleHeight() const
Returns the height of the viewport.
Definition: khtmlview.cpp:736
int height() const const
QString fragment(QUrl::ComponentFormattingOptions options) const const
QString path(QUrl::ComponentFormattingOptions options) const const
KJSProxy * framejScript(KParts::ReadOnlyPart *framePart)
Returns child frame framePart its script interpreter.
KJSWindowOpenPolicy
This enum specifies the policy for window.open.
void raise()
QString left(int n) const const
Proxy class serving as interface when being dlopen'ed.
Definition: kjs_proxy.h:61
void setPath(const QString &path, QUrl::ParsingMode mode)
int port(int defaultPort) const const
int visibleWidth() const
Returns the width of the viewport.
Definition: khtmlview.cpp:720
Helper for pausing/resuming timers.
Definition: kjs_window.h:354
void setFragment(const QString &fragment, QUrl::ParsingMode mode)
void clear()
QList::iterator begin()
WId winId() const const
virtual QVariant callAsFunction(ScriptableExtension *callerPrincipal, quint64 objId, const ArgList &args)
static QRect workArea(const QList< WId > &excludes, int desktop=-1)
int size() const const
The NodeList interface provides the abstraction of an ordered collection of nodes,...
Definition: dom_node.h:976
DOM::Document document() const
Returns a reference to the DOM document.
DOM::HTMLDocument htmlDocument() const
Returns a reference to the DOM HTML document (for non-HTML documents, returns null)
KHTMLPart * parentPart()
Returns a pointer to the parent KHTMLPart if the part is a frame in an HTML frameset.
Interpreter * dynamicInterpreter() const
ListIterator begin() const
The Node interface is the primary datatype for the entire Document Object Model.
Definition: dom_node.h:278
int msecsTo(const QTime &t) const const
KJOBWIDGETS_EXPORT QWidget * window(KJob *job)
NodeImpl * handle() const
Definition: dom_node.h:936
KParts::ReadOnlyPart * findFramePart(const QString &f)
Finds a frame by name.
virtual QWidget * widget()
Height
QList::iterator end()
bool isNull() const
tests if this Node is 0.
Definition: dom_node.h:928
Filters are objects that know how to "filter out" nodes.
virtual bool put(ScriptableExtension *callerPrincipal, quint64 objId, const QString &propName, const QVariant &value)
void scrollBy(int x, int y)
Scrolls the content area by a given amount.
Definition: khtmlview.cpp:759
QString mid(int position, int n) const const
bool isWindowOpenAllowed() const
"Smart" window.open policy
bool jScriptEnabled() const
Returns true if Javascript support is enabled or false otherwise.
KJS_EXTERNAL_EXPORT QString qstring() const
QObject * parent() const const
QString message
qint64 daysTo(const QDate &d) const const
ItemInfo * get(const DOMString &id)
Returns the information for the given ID.
void print(bool quick=false)
Prints the HTML document.
Definition: khtmlview.cpp:3099
KParts::BrowserExtension * browserExtension() const
Returns a pointer to the KParts::BrowserExtension.
char * toString(const EngineQuery &query)
QString toString() const const
QVariant property(const char *name) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Wed Sep 27 2023 04:05:43 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.