1 /* This file is part of the KDE project 2 Copyright (C) 2010 Maksim Orlovich <maksim@kde.org> 3 4 This library is free software; you can redistribute it and/or 5 modify it under the terms of the GNU Library General Public 6 License as published by the Free Software Foundation; either 7 version 2 of the License, or (at your option) any later version. 8 9 This library is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 Library General Public License for more details. 13 14 You should have received a copy of the GNU Library General Public License 15 along with this library; see the file COPYING.LIB. If not, write to 16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 Boston, MA 02110-1301, USA. 18 */ 19 20 #ifndef KJS_SCRIPTABLE_H 21 #define KJS_SCRIPTABLE_H 22 23 #include <khtml_part.h> 24 #include <kparts/scriptableextension.h> 25 #include <kjs/object.h> 26 #include <kjs/list.h> 27 #include <QHash> 28 29 using namespace KParts; 30 31 namespace KJS 32 { 33 34 // First, a couple of helpers: these let clients perform basic getOwnPropertySlot or 35 // put (with a bool effect return) on the root of given extension. 36 bool pluginRootGet(ExecState *exec, ScriptableExtension *ext, const KJS::Identifier &i, PropertySlot &slot); 37 bool pluginRootPut(ExecState *exec, ScriptableExtension *ext, const KJS::Identifier &i, JSValue *v); 38 39 class WrapScriptableObject; 40 41 // We have two ScriptableExtension subclasses. 42 // ScriptableOperations is a singleton used to perform operations on objects. 43 // This is because objects in child parts (and other windows) can survive their 44 // parent, and we still need to perform operations on them. 45 class ScriptableOperations: public ScriptableExtension 46 { 47 Q_OBJECT 48 public: 49 // ScriptableExtension API 50 QVariant callAsFunction(ScriptableExtension *callerPrincipal, quint64 objId, const ArgList &args) override; 51 virtual QVariant callFunctionReference(ScriptableExtension *callerPrincipal, quint64 objId, 52 const QString &f, const ArgList &args) override; 53 QVariant callAsConstructor(ScriptableExtension *callerPrincipal, quint64 objId, const ArgList &args) override; 54 bool hasProperty(ScriptableExtension *callerPrincipal, quint64 objId, const QString &propName) override; 55 QVariant get(ScriptableExtension *callerPrincipal, quint64 objId, const QString &propName) override; 56 bool put(ScriptableExtension *callerPrincipal, quint64 objId, const QString &propName, const QVariant &value) override; 57 bool removeProperty(ScriptableExtension *callerPrincipal, quint64 objId, const QString &propName) override; 58 bool enumerateProperties(ScriptableExtension *callerPrincipal, quint64 objId, QStringList *result) override; 59 60 void acquire(quint64 objid) override; 61 void release(quint64 objid) override; 62 63 // May return null. 64 static JSObject *objectForId(quint64 objId); 65 66 static ScriptableOperations *self(); 67 68 void mark(); 69 public: 70 // We keep a weak table of our wrappers for external objects, so that 71 // the same object gets the same wrapper all the time. 72 static QHash<Object, WrapScriptableObject *> *importedObjects(); 73 static QHash<FunctionRef, WrapScriptableObject *> *importedFunctions(); 74 75 // For exported objects, we keep refcounts, and mark them 76 static QHash<JSObject *, int> *exportedObjects(); 77 78 static JSValue *importValue(ExecState *exec, const QVariant &v, bool alreadyRefd); 79 static JSValue *importFunctionRef(ExecState *exec, const QVariant &v, bool alreadyRefd); 80 static JSObject *importObject(ExecState *exec, const QVariant &v, bool alreadyRefd); 81 static List importArgs(ExecState *exec, const ArgList &args); 82 83 static QVariant exportValue(JSValue *v, bool preRef); 84 static QVariant exportObject(JSObject *o, bool preRef); 85 static QVariant exportFuncRef(JSObject *base, const QString &field, bool preRef); 86 87 // Both methods may return 0. Used for security checks! 88 static KHTMLPart *partForPrincipal(ScriptableExtension *callerPrincipal); 89 static ExecState *execStateForPrincipal(ScriptableExtension *callerPrincipal); 90 private: 91 // input should not be a WrapScriptableObject. 92 static ScriptableExtension::Object exportNativeObject(JSObject *o, bool preRef); 93 94 // Checks exception state before handling conversion 95 QVariant handleReturn(ExecState *exec, JSValue *v); 96 97 // If the given object is owned by a KHTMLScriptable, return the 98 // JS object for it. If not, return 0. 99 static JSObject *tryGetNativeObject(const Object &sObj); 100 101 static QHash<JSObject *, int> *s_exportedObjects; 102 static QHash<Object, WrapScriptableObject *> *s_importedObjects; 103 static QHash<FunctionRef, WrapScriptableObject *> *s_importedFunctions; 104 105 ScriptableOperations(); 106 ~ScriptableOperations(); 107 108 // copy ctor, etc., disabled already, being a QObject 109 static ScriptableOperations *s_instance; 110 }; 111 112 // KHTMLPartScriptable, on other hands, is tied to a part, and 113 // is used for part-specific operations such as looking up 114 // root objects and script execution. 115 class KHTMLPartScriptable: public ScriptableExtension 116 { 117 Q_OBJECT 118 friend class ScriptableOperations; 119 public: 120 KHTMLPartScriptable(KHTMLPart *part); 121 122 QVariant rootObject() override; 123 QVariant encloserForKid(KParts::ScriptableExtension *kid) override; 124 125 bool setException(ScriptableExtension *callerPrincipal, const QString &message) override; 126 127 virtual QVariant evaluateScript(ScriptableExtension *callerPrincipal, 128 quint64 contextObjectId, 129 const QString &code, 130 ScriptLanguage language = ECMAScript) override; 131 bool isScriptLanguageSupported(ScriptLanguage lang) const override; 132 133 // For paranoia: forward to ScriptOperations 134 void acquire(quint64 objid) override; 135 void release(quint64 objid) override; 136 private: 137 KJS::Interpreter *interpreter(); 138 KHTMLPart *m_part; 139 }; 140 141 // This represents an object we imported from a foreign ScriptableExtension 142 class WrapScriptableObject: public JSObject 143 { 144 public: 145 friend class ScriptableOperations; 146 147 enum Type { 148 Object, 149 FunctionRef 150 }; 151 152 WrapScriptableObject(ExecState *exec, Type t, 153 ScriptableExtension *owner, quint64 objId, 154 const QString &field = QString()); 155 156 ~WrapScriptableObject(); 157 classInfo()158 const ClassInfo *classInfo() const override 159 { 160 return &info; 161 } 162 static const ClassInfo info; 163 164 bool getOwnPropertySlot(ExecState *, const Identifier &, PropertySlot &) override; 165 using JSObject::getOwnPropertySlot; 166 void put(ExecState *exec, const Identifier &propertyName, JSValue *value, int) override; 167 using JSObject::put; 168 bool deleteProperty(ExecState *exec, const Identifier &i) override; 169 using JSObject::deleteProperty; 170 isFunctionType()171 bool isFunctionType() const override 172 { 173 return false; 174 } implementsCall()175 bool implementsCall() const override 176 { 177 return true; 178 } 179 JSValue *callAsFunction(ExecState *exec, JSObject *thisObj, const List &args) override; 180 181 // We claim true, since may be calleable implementsConstruct()182 bool implementsConstruct() const override 183 { 184 return true; 185 } 186 JSObject *construct(ExecState *exec, const List &args) override; 187 using JSObject::construct; 188 189 void getOwnPropertyNames(ExecState *, PropertyNameArray &, PropertyMap::PropertyMode mode) override; 190 191 UString toString(ExecState *exec) const override; 192 193 // This method is used to note that the object has been ref'd on our 194 // behalf by an external producer. 195 void reportRef(); 196 private: 197 // If we're a function reference type, before we perform non-call operations we need 198 // to actually lookup the field. This takes care of that. 199 ScriptableExtension::Object resolveAnyReferences(ExecState *exec, bool *ok); 200 201 // resolves all function references to get an ref, if any. 202 ScriptableExtension::Object resolveReferences(ExecState *exec, 203 const ScriptableExtension::FunctionRef &f, 204 bool *ok); 205 206 // gets a field of the given object id, base 207 QVariant doGet(ExecState *exec, const ScriptableExtension::Object &o, 208 const QString &field, bool *ok); 209 210 ScriptableExtension::ArgList exportArgs(const List &l); 211 void releaseArgs(ScriptableExtension::ArgList &a); 212 213 // Looks up the principal we're running as 214 ScriptableExtension *principal(ExecState *exec); 215 216 // what we wrap 217 QWeakPointer<ScriptableExtension> objExtension; 218 quint64 objId; 219 QString field; 220 Type type; 221 int refsByUs; // how many references we hold 222 223 // this is an unguarded copy of objExtension. We need it in order to 224 // clean ourselves up from the imports tables properly even if the peer 225 // was destroyed. 226 ScriptableExtension *tableKey; 227 }; 228 229 } 230 231 #endif 232