KHtml

kjs_binding.h
1 /*
2  * This file is part of the KDE libraries
3  * Copyright (C) 1999-2001 Harri Porten ([email protected])
4  * Copyright (C) 2003 Apple Computer, Inc.
5  * Copyright (C) 2007, 2008 Maksim Orlovich ([email protected])
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #ifndef _KJS_BINDING_H_
23 #define _KJS_BINDING_H_
24 
25 #include <khtml_export.h>
26 #include <kjs/interpreter.h>
27 #include <kjs/global.h>
28 #include <wtf/HashMap.h>
29 
30 #include <dom/dom_node.h>
31 #include <QVariant>
32 #include <QHash>
33 #include <QString>
34 #include <kjs/lookup.h>
35 #include <kjs/function.h>
36 #include <kjs/JSVariableObject.h>
37 #include <kjs/object_object.h>
38 #include <misc/shared.h>
39 
40 #include <stdlib.h> // for abort
41 
42 #define KJS_CHECK_THIS( ClassName, theObj ) \
43  if (!theObj || !theObj->inherits(&ClassName::info)) { \
44  KJS::UString errMsg = "Attempt at calling a function that expects a "; \
45  errMsg += ClassName::info.className; \
46  errMsg += " on a "; \
47  errMsg += theObj->className(); \
48  KJS::JSObject *err = KJS::Error::create(exec, KJS::TypeError, errMsg.ascii()); \
49  exec->setException(err); \
50  return err; \
51  }
52 
53 namespace KParts
54 {
55 class ReadOnlyPart;
56 class LiveConnectExtension;
57 }
58 
59 namespace khtml
60 {
61 class ChildFrame;
62 }
63 
64 namespace KJS
65 {
66 
67 // For the ecma debugger we provide our own conversion rather than the
68 // use the native one, since using the toString
69 // method on object can invoke code
70 QString valueToString(KJS::JSValue *value);
71 
72 // Serializes an exception for human consumption.
73 QString exceptionToString(ExecState *exec, JSValue *exception);
74 
78 class DOMObject : public JSObject
79 {
80 protected:
81  DOMObject() : JSObject() {}
82  DOMObject(JSObject *proto) : JSObject(proto) {}
83 public:
84  bool shouldMark() const
85  {
86  return !_prop.isEmpty();
87  }
88  UString toString(ExecState *exec) const override;
89 };
90 
97 {
98 public:
99  ScriptInterpreter(JSGlobalObject *global, khtml::ChildFrame *frame);
100  virtual ~ScriptInterpreter();
101 
102  // We need to keep track of wrappers in 2 ways:
103  // - we want the same wrapper for the same node (see #145775)
104  // - we want to drop all the references from this interpreter on clear, so
105  // wrappers don't stick around. Hence we have a global set and a per-interpreter one.
106 
107  // Reuses an existing wrapper, perhaps also updating the current map
108  // to refer to it as well.
109  DOMObject *getDOMObject(void *objectHandle)
110  {
111  DOMObject *existing = allDomObjects()->get(objectHandle);
112  if (existing) {
113  m_domObjects.set(objectHandle, existing);
114  }
115  return existing;
116  }
117 
118  void putDOMObject(void *objectHandle, DOMObject *obj)
119  {
120  allDomObjects()->set(objectHandle, obj);
121  m_domObjects.set(objectHandle, obj);
122  }
123 
124  static void forgetDOMObject(void *objectHandle);
125 
126  void clear()
127  {
128  m_domObjects.clear(); // Global set will be cleared at GC time.
129  }
130 
134  void mark(bool isMain) override;
135  KParts::ReadOnlyPart *part() const;
136 
137  int rtti() override
138  {
139  return 1;
140  }
141 
146  {
147  m_evt = evt;
148  }
149  void setInlineCode(bool inlineCode)
150  {
151  m_inlineCode = inlineCode;
152  }
153  void setProcessingTimerCallback(bool timerCallback)
154  {
155  m_timerCallback = timerCallback;
156  }
160  bool isWindowOpenAllowed() const;
161 
166  bool shouldInterruptScript() const override;
167  void startCPUGuard();
168  void stopCPUGuard();
169 
170  static void turnOffCPUGuard()
171  {
172  s_disableCPUGuard = true;
173  }
174 private:
175  khtml::ChildFrame *m_frame;
176  HashMap<void *, DOMObject *> m_domObjects;
177  static HashMap<void *, DOMObject *> *s_allDomObjects;
178  static HashMap<void *, DOMObject *> *allDomObjects()
179  {
180  if (!s_allDomObjects) {
181  s_allDomObjects = new HashMap<void *, DOMObject *>();
182  }
183  return s_allDomObjects;
184  }
185 
186  DOM::Event *m_evt;
187  bool m_inlineCode;
188  bool m_timerCallback;
189  static bool s_disableCPUGuard;
190 };
191 
200 template<typename Wrapper>
201 JSValue *getWrapper(ExecState *exec, typename Wrapper::wrappedType *g)
202 {
203  DOMObject *ret = nullptr;
204  if (!g) {
205  return jsNull();
206  }
207 
208  ScriptInterpreter *interp = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter());
209  if ((ret = interp->getDOMObject(g))) {
210  return ret;
211  }
212 
213  ret = new Wrapper(exec, g);
214  interp->putDOMObject(g, ret);
215  return ret;
216 }
217 
218 template<typename Wrapped>
219 class DOMWrapperObject : public DOMObject
220 {
221 public:
222  typedef Wrapped wrappedType;
223  typedef DOMWrapperObject<Wrapped> WrapperBase;
224 
225  DOMWrapperObject(JSObject *proto, Wrapped *wrapee):
226  DOMObject(proto), m_impl(wrapee)
227  {}
228 
229  virtual ~DOMWrapperObject()
230  {
231  ScriptInterpreter::forgetDOMObject(m_impl.get());
232  }
233 
234  bool toBoolean(ExecState *) const override
235  {
236  return true;
237  }
238 
239  Wrapped *impl()
240  {
241  return m_impl.get();
242  }
243  const Wrapped *impl() const
244  {
245  return m_impl.get();
246  }
247 private:
248  SharedPtr<Wrapped> m_impl;
249 };
250 
254 template<class FuncImp, class ThisImp>
255 inline void getSlotFromEntry(const HashEntry *entry, ThisImp *thisObj, PropertySlot &slot)
256 {
257  if (entry->attr & Function) {
258  slot.setStaticEntry(thisObj, entry, staticFunctionGetter<FuncImp>);
259  } else {
260  slot.setStaticEntry(thisObj, entry, staticValueGetter<ThisImp>);
261  }
262 }
263 
268 template <class FuncImp, class ThisImp>
269 inline bool getStaticOwnPropertySlot(const HashTable *table,
270  ThisImp *thisObj, const Identifier &propertyName, PropertySlot &slot)
271 {
272  const HashEntry *entry = Lookup::findEntry(table, propertyName);
273 
274  if (!entry) { // not found, forward to parent
275  return false;
276  }
277 
278  if (entry->attr & Function) {
279  slot.setStaticEntry(thisObj, entry, staticFunctionGetter<FuncImp>);
280  } else {
281  slot.setStaticEntry(thisObj, entry, staticValueGetter<ThisImp>);
282  }
283 
284  return true;
285 }
286 
290 template<class ThisImp>
291 inline bool getStaticOwnValueSlot(const HashTable *table,
292  ThisImp *thisObj, const Identifier &propertyName, PropertySlot &slot)
293 {
294  const HashEntry *entry = Lookup::findEntry(table, propertyName);
295  if (!entry) {
296  return false;
297  }
298 
299  assert(!(entry->attr & Function));
300  slot.setStaticEntry(thisObj, entry, staticValueGetter<ThisImp>);
301  return true;
302 }
303 
304 /* Helper for the below*/
305 template<class JSTypeImp>
306 JSValue *indexGetterAdapter(ExecState *exec, JSObject *, unsigned, const PropertySlot &slot)
307 {
308  JSTypeImp *thisObj = static_cast<JSTypeImp *>(slot.slotBase());
309  return thisObj->indexGetter(exec, slot.index());
310 }
311 
316 template<class ThisImp, class BaseObj>
317 inline bool getIndexSlot(ThisImp *thisObj, const BaseObj &listObj,
318  const Identifier &propertyName, PropertySlot &slot)
319 {
320  bool ok;
321  unsigned u = propertyName.toArrayIndex(&ok);
322  if (ok && u < listObj.length()) {
323  slot.setCustomIndex(thisObj, u, indexGetterAdapter<ThisImp>);
324  return true;
325  }
326  return false;
327 }
328 
332 template<class ThisImp>
333 inline bool getIndexSlot(ThisImp *thisObj, unsigned lengthLimit,
334  const Identifier &propertyName, PropertySlot &slot)
335 {
336  bool ok;
337  unsigned u = propertyName.toArrayIndex(&ok);
338  if (ok && u < lengthLimit) {
339  slot.setCustomIndex(thisObj, u, indexGetterAdapter<ThisImp>);
340  return true;
341  }
342  return false;
343 }
344 
345 template<class ThisImp>
346 inline bool getIndexSlot(ThisImp *thisObj, int lengthLimit,
347  const Identifier &propertyName, PropertySlot &slot)
348 {
349  return getIndexSlot(thisObj, (unsigned)lengthLimit, propertyName, slot);
350 }
351 
355 template<class ThisImp>
356 inline bool getIndexSlot(ThisImp *thisObj, const Identifier &propertyName, PropertySlot &slot)
357 {
358  bool ok;
359  unsigned u = propertyName.toArrayIndex(&ok);
360  if (ok) {
361  slot.setCustomIndex(thisObj, u, indexGetterAdapter<ThisImp>);
362  return true;
363  }
364  return false;
365 }
366 
367 /* Helper for below */
368 JSValue *valueGetterAdapter(ExecState *exec, JSObject *, const Identifier &, const PropertySlot &slot);
369 
374 inline bool getImmediateValueSlot(JSObject *thisObj, JSValue *value, PropertySlot &slot)
375 {
376  slot.setCustomValue(thisObj, value, valueGetterAdapter);
377  return true;
378 }
379 
383 template<class DOMObj, class KJSDOMObj>
384 inline JSValue *cacheDOMObject(ExecState *exec, DOMObj *domObj)
385 {
386  DOMObject *ret;
387  if (!domObj) {
388  return jsNull();
389  }
390  ScriptInterpreter *interp = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter());
391  if ((ret = interp->getDOMObject(domObj))) {
392  return ret;
393  } else {
394  ret = new KJSDOMObj(exec, domObj);
395  interp->putDOMObject(domObj, ret);
396  return ret;
397  }
398 }
399 
403 DOM::NodeImpl *toNode(JSValue *);
407 JSValue *getStringOrNull(DOM::DOMString s);
408 
412 DOM::DOMString valueToStringWithNullCheck(ExecState *exec, JSValue *v);
413 
417 QVariant ValueToVariant(ExecState *exec, JSValue *val);
418 
419 // Convert a DOM implementation exception code into a JavaScript exception in the execution state.
420 void setDOMException(ExecState *exec, int DOMExceptionCode);
421 
422 // Helper class to call setDOMException on exit without adding lots of separate calls to that function.
423 class DOMExceptionTranslator
424 {
425 public:
426  explicit DOMExceptionTranslator(ExecState *exec) : m_exec(exec), m_code(0) { }
427  ~DOMExceptionTranslator()
428  {
429  setDOMException(m_exec, m_code);
430  }
431  operator int &()
432  {
433  return m_code;
434  }
435  operator int *()
436  {
437  return &m_code;
438  }
439 
440  bool triggered()
441  {
442  return m_code;
443  }
444 private:
445  ExecState *m_exec;
446  int m_code;
447 };
448 
449 // convenience function
450 inline JSCell *jsString(const QString &s)
451 {
452  return jsString(UString(s));
453 }
454 
455 // This is used to create pseudo-constructor objects, like Mozillaish
456 // Element, HTMLDocument, etc., which do not act like real constructors,
457 // but do have the prototype property pointing to prototype of "instances"
458 #define DEFINE_PSEUDO_CONSTRUCTOR(ClassName) \
459  class ClassName : public DOMObject { \
460  public: \
461  ClassName(ExecState *); \
462  virtual const ClassInfo* classInfo() const { return &info; } \
463  static const ClassInfo info; \
464  static JSObject* self(ExecState *exec); \
465  virtual bool implementsHasInstance() const; \
466  };
467 
468 #define IMPLEMENT_PSEUDO_CONSTRUCTOR_IMP(Class,ClassName,ProtoClass,ParentProto) \
469  const ClassInfo Class::info = { ClassName, nullptr, nullptr, nullptr }; \
470  Class::Class(ExecState* exec): DOMObject(ParentProto) {\
471  /* Since ProtoClass ctor might need us, make sure we're registered */ \
472  exec->lexicalInterpreter()->globalObject()->put(exec, "[[" ClassName ".constructor]]", this, KJS::Internal | KJS::DontEnum); \
473  JSObject* proto = ProtoClass::self(exec); \
474  putDirect(exec->propertyNames().prototype, proto, DontDelete|ReadOnly); \
475  }\
476  JSObject* Class::self(ExecState *exec) { \
477  return cacheGlobalObject<Class>(exec, "[[" ClassName ".constructor]]"); \
478  } \
479  bool Class::implementsHasInstance() const { \
480  return true; \
481  }
482 
483 #define IMPLEMENT_PSEUDO_CONSTRUCTOR(Class,ClassName,ProtoClass) \
484  IMPLEMENT_PSEUDO_CONSTRUCTOR_IMP(Class,ClassName,ProtoClass,exec->lexicalInterpreter()->builtinObjectPrototype())
485 
486 #define IMPLEMENT_PSEUDO_CONSTRUCTOR_WITH_PARENT(Class,ClassName,ProtoClass,ParentProtoClass) \
487  IMPLEMENT_PSEUDO_CONSTRUCTOR_IMP(Class,ClassName,ProtoClass,ParentProtoClass::self(exec))
488 
489 // This declares a constant table, which merely maps everything in its
490 // table to its token value. Can be used as a prototype
491 #define DEFINE_CONSTANT_TABLE(Class) \
492  class Class : public DOMObject { \
493  public: \
494  Class(ExecState *exec): DOMObject(exec->lexicalInterpreter()->builtinObjectPrototype()) {} \
495  \
496  using KJS::JSObject::getOwnPropertySlot;\
497  virtual bool getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot);\
498  JSValue* getValueProperty(ExecState *exec, int token) const; \
499  virtual const ClassInfo* classInfo() const { return &info; } \
500  static const ClassInfo info; \
501  static JSObject* self(ExecState *exec);\
502  static Identifier* s_name; \
503  static Identifier* name(); \
504  };
505 
506 // Emits an implementation of a constant table
507 #define IMPLEMENT_CONSTANT_TABLE(Class,ClassName) \
508  bool Class::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot) \
509  { \
510  return getStaticValueSlot<Class, DOMObject>(exec, &Class##Table, this, propertyName, slot);\
511  }\
512  JSValue* Class::getValueProperty(ExecState * /*exec*/, int token) const { \
513  /* We use the token as the value to return directly*/ \
514  return jsNumber((unsigned int)token); \
515  } \
516  JSObject* Class::self(ExecState *exec) { \
517  return cacheGlobalObject<Class>(exec, *name()); \
518  } \
519  Identifier* Class::s_name = nullptr; \
520  Identifier* Class::name() { \
521  if (!s_name) s_name = new Identifier("[[" ClassName ".constant_table]]"); \
522  return s_name; \
523  } \
524  const ClassInfo Class::info = { ClassName, nullptr, &Class##Table, nullptr };
525 
526 // cacheGlobalObject<> is not in namespace KJS - need to use ::cacheGlobalObject<>
527 #define KJS_EMPTY_PROTOTYPE_IMP(ClassName, ClassProto, ProtoCode) \
528  class ClassProto : public JSObject { \
529  friend JSObject* KJS_CACHEGLOBALOBJECT_NS cacheGlobalObject<ClassProto>(ExecState *exec, const Identifier &propertyName); \
530  public: \
531  static JSObject* self(ExecState *exec) { \
532  return KJS_CACHEGLOBALOBJECT_NS cacheGlobalObject<ClassProto>(exec, *name()); \
533  } \
534  virtual const ClassInfo *classInfo() const { return &info; } \
535  static const ClassInfo info; \
536  protected: \
537  ClassProto( ExecState *exec ) \
538  : JSObject( ProtoCode ) {} \
539  \
540  static Identifier* s_name; \
541  static Identifier* name() { \
542  if (!s_name) s_name = new Identifier("[[" ClassName ".prototype]]"); \
543  return s_name; \
544  }\
545  }; \
546  Identifier* ClassProto::s_name = nullptr; \
547  const ClassInfo ClassProto::info = { ClassName, nullptr, nullptr, nullptr };
548 
549 #define KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE(ClassName, ClassProto, ClassProtoProto) \
550  KJS_EMPTY_PROTOTYPE_IMP(ClassName, ClassProto, ClassProtoProto::self(exec))
551 
552 } // namespace
553 
554 #endif
Base class for all objects in this binding.
Definition: kjs_binding.h:78
Interpreter * dynamicInterpreter() const
short int attr
This file is part of the HTML rendering engine for KDE.
We inherit from Interpreter, to save a pointer to the HTML part that the interpreter runs for...
Definition: kjs_binding.h:96
This class implements the basic string we use in the DOM.
Definition: dom_string.h:44
void setCurrentEvent(DOM::Event *evt)
Set the event that is triggering the execution of a script, if any.
Definition: kjs_binding.h:145
Introduced in DOM Level 2.
Definition: dom2_events.h:116
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Sat Jul 4 2020 22:46:22 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.