File indexing completed on 2024-04-28 15:29:24
0001 /* 0002 This file is part of the KDE project 0003 SPDX-FileCopyrightText: 2010 Maksim Orlovich <maksim@kde.org> 0004 SPDX-FileCopyrightText: 2002 Koos Vriezen <koos.vriezen@gmail.com> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #ifndef kparts_scriptableextension_h 0010 #define kparts_scriptableextension_h 0011 0012 #include <kparts/part.h> 0013 0014 #include <QObject> 0015 #include <QVariant> 0016 #include <memory> 0017 0018 namespace KParts 0019 { 0020 class ScriptableExtension; 0021 struct ScriptableExtensionPrivate; 0022 class LiveConnectExtension; 0023 0024 /** 0025 * @class ScriptableExtension scriptableextension.h <KParts/ScriptableExtension> 0026 * 0027 * @short An extension class that permits KParts to be scripted (such as when embedded 0028 * inside a KHTMLPart) and to access the host's scriptable objects as well. 0029 * 0030 * See @ref ScriptValueTypes for how values are passed to/from various methods here. 0031 * 0032 * @since 4.5 0033 * \nosubgrouping 0034 */ 0035 class KPARTS_EXPORT ScriptableExtension : public QObject 0036 { 0037 Q_OBJECT 0038 public: 0039 /** @defgroup ScriptValueTypes Script Value Types 0040 * @{ 0041 * Values are passed to and from scriptable methods or properties as QVariants. 0042 * Valid values may be bools, strings, and numbers (doubles), as well as the 0043 * following custom types: 0044 * \li @ref Null 0045 * \li @ref Undefined 0046 * \li @ref Exception 0047 * \li @ref Object 0048 * \li @ref FunctionRef 0049 */ 0050 0051 /// Corresponds to 'null' in JavaScript 0052 struct Null { 0053 }; 0054 0055 /// Corresponds to 'undefined' in JavaScript 0056 struct Undefined { 0057 }; 0058 0059 /// Returned from operations to denote a failure. May not be passed in as 0060 /// a parameter, only returned 0061 struct Exception { 0062 /// Error message returned from the callee. This should be assumed to be 0063 /// low-level (in particular, it might not be translated) and should 0064 /// only be displayed in low-level debugging tools and the like. 0065 QString message; 0066 0067 Exception() 0068 { 0069 } 0070 Exception(const QString &msg) 0071 : message(msg) 0072 { 0073 } 0074 }; 0075 0076 /// Objects are abstracted away as a pair of the ScriptableExtension 0077 /// the performs operations on it, and an implementation-specific Id, 0078 /// which gets passed to the extension's methods. 0079 /// 0080 /// Objects are reference-counted, with the following protocol: 0081 /// 1) Return values from methods, rootObject(), enclosingObject(), 0082 /// and get() are already acquired by the producer, so the consumer 0083 /// should release them when done. 0084 /// 2) During a call, the caller guarantees that all the arguments 0085 /// will be live for the calls duration, but the callee must 0086 /// acquire them if it stores it for longer than that. 0087 /// 0088 /// @see acquire, acquireValue, release, releaseValue 0089 struct Object { 0090 ScriptableExtension *owner; 0091 quint64 objId; 0092 0093 Object() 0094 : owner(nullptr) 0095 , objId(0) 0096 { 0097 } 0098 Object(ScriptableExtension *o, quint64 id) 0099 : owner(o) 0100 , objId(id) 0101 { 0102 } 0103 bool operator==(const Object &other) const 0104 { 0105 return owner == other.owner && objId == other.objId; 0106 } 0107 }; 0108 0109 /// Function references are a pair of an object and a field in it. 0110 /// Essentially, if you have a base.field(something) call, the 0111 /// 'base' needs to be passed as the 'this' to the function, and 0112 /// these references can be used to resolve that. 0113 struct FunctionRef { 0114 Object base; 0115 QString field; 0116 0117 FunctionRef() 0118 { 0119 } 0120 FunctionRef(const Object &b, const QString &f) 0121 : base(b) 0122 , field(f) 0123 { 0124 } 0125 bool operator==(const FunctionRef &other) const 0126 { 0127 return base == other.base && field == other.field; 0128 } 0129 }; 0130 0131 //@} 0132 0133 ///@name lifetime 0134 //@{ 0135 protected: 0136 ScriptableExtension(QObject *parent); 0137 0138 public: 0139 ~ScriptableExtension() override; 0140 0141 /** 0142 * Queries @p obj for a child object which inherits from this 0143 * ScriptableExtension class. Convenience method. 0144 */ 0145 static ScriptableExtension *childObject(QObject *obj); 0146 0147 /** 0148 * This returns a bridge object that permits KParts implementing the older 0149 * LiveConnectExtension to be used via the ScriptableExtension API. 0150 * The bridge's parent will be the @p parentObj. 0151 */ 0152 static ScriptableExtension *adapterFromLiveConnect(QObject *parentObj, LiveConnectExtension *oldApi); 0153 0154 //@} 0155 0156 ///@name Object Hierarchy 0157 //@{ 0158 0159 /** 0160 * Reports the hosting ScriptableExtension to a child. It's the responsibility 0161 * of a parent part to call this method on all of its kids' ScriptableExtensions 0162 * as soon as possible. 0163 */ 0164 void setHost(ScriptableExtension *host); 0165 0166 /** 0167 * Returns any registered parent scripting context. May be 0 if setHost 0168 * was not called (or not call yet). 0169 */ 0170 ScriptableExtension *host() const; 0171 0172 /** 0173 * Return the root scriptable object of this KPart. 0174 * For example for an HTML part, it would represent a Window object. 0175 * May be undefined or null 0176 */ 0177 virtual QVariant rootObject(); 0178 0179 /** 0180 * Returns an object that represents the host()'s view of us. 0181 * For example, if the host is an HTML part, it would return 0182 * a DOM node of an <object> handled by this part. 0183 * May be undefined or null 0184 * 0185 * Implemented in terms of objectForKid 0186 * 0187 */ 0188 QVariant enclosingObject(); 0189 //@} 0190 0191 ///@name Object Operations 0192 /// All these methods share the following conventions: 0193 /// \li Values are passed and returned encoded as defined in 0194 /// @ref ScriptValueTypes 0195 /// \li All methods may return an exception if unsupported 0196 /// \li All callers \b must provide an accurate callerPrincipal 0197 /// argument describing which ScriptableExtension (and hence which KPart) 0198 /// they're acting as. This is used to implement <b>security checks</b>. This 0199 /// is \b not the same as the owner of an object. For example, if a plugin is 0200 /// calling an operation on a KHTMLPart object, 0201 /// then the 'this' parameter would be the object owner, a ScriptableExtension 0202 /// provided by the KHTMLPart, while the callerPrincipal would be the 0203 /// ScriptableExtension of the \em plugin. The extension is expected 0204 /// to do appropriate cross-site scripting checks on this argument 0205 /// if it is acting as a host. 0206 //@{ 0207 0208 typedef QList<QVariant> ArgList; 0209 0210 /** 0211 Try to use the object @p objId associated with 'this' as a function. 0212 */ 0213 virtual QVariant callAsFunction(ScriptableExtension *callerPrincipal, quint64 objId, const ArgList &args); 0214 0215 /** 0216 Try to use a function reference to field @p f of object @objId as a function 0217 */ 0218 virtual QVariant callFunctionReference(ScriptableExtension *callerPrincipal, quint64 objId, const QString &f, const ArgList &args); 0219 0220 /** 0221 Try to use the object @p objId associated with 'this' as a constructor 0222 (corresponding to ECMAScript's new foo(bar, baz, glarch) expression). 0223 */ 0224 virtual QVariant callAsConstructor(ScriptableExtension *callerPrincipal, quint64 objId, const ArgList &args); 0225 0226 /** 0227 Returns true if the object @p objId associated with 'this' has the property 0228 @p propName. 0229 */ 0230 virtual bool hasProperty(ScriptableExtension *callerPrincipal, quint64 objId, const QString &propName); 0231 0232 /** 0233 Tries to get field @p propName from object @p objId associated with 'this'. 0234 */ 0235 virtual QVariant get(ScriptableExtension *callerPrincipal, quint64 objId, const QString &propName); 0236 0237 /** 0238 Tries to set the field @p propName from object @p objId associated with 'this' 0239 to @p value. Returns true on success 0240 */ 0241 virtual bool put(ScriptableExtension *callerPrincipal, quint64 objId, const QString &propName, const QVariant &value); 0242 0243 /** 0244 Tries to remove the field d @p propName from object @p objId associated with 'this'. 0245 Returns true on success 0246 */ 0247 virtual bool removeProperty(ScriptableExtension *callerPrincipal, quint64 objId, const QString &propName); 0248 0249 /** 0250 Tries to enumerate all fields of object @p objId associated with this to 0251 @p result. Returns true on success 0252 */ 0253 virtual bool enumerateProperties(ScriptableExtension *callerPrincipal, quint64 objId, QStringList *result); 0254 0255 /** 0256 Tries to raise an exception with given message in this extension's scripting 0257 context. Returns true on success 0258 */ 0259 virtual bool setException(ScriptableExtension *callerPrincipal, const QString &message); 0260 0261 enum ScriptLanguage { 0262 ECMAScript, /// < also known as JavaScript 0263 EnumLimit = 0xFFFF, 0264 }; 0265 0266 /** 0267 Tries to evaluate a script @p code with the given object as its context. 0268 The parameter @p language specifies the language to execute it as. 0269 Use isScriptLanguageSupported to check for support. 0270 */ 0271 virtual QVariant evaluateScript(ScriptableExtension *callerPrincipal, quint64 contextObjectId, const QString &code, ScriptLanguage language = ECMAScript); 0272 0273 /** returns true if this extension can execute scripts in the given 0274 language */ 0275 virtual bool isScriptLanguageSupported(ScriptLanguage lang) const; 0276 0277 /** 0278 increases reference count of object @p objId 0279 */ 0280 virtual void acquire(quint64 objid); 0281 0282 /** 0283 Helper that calls @ref acquire on any object or function reference base 0284 stored in @p v. 0285 0286 @return a copy of the passed in value 0287 */ 0288 static QVariant acquireValue(const QVariant &v); 0289 0290 /** 0291 decreases reference count of object @p objId 0292 */ 0293 virtual void release(quint64 objid); 0294 0295 /** 0296 Helper that calls @ref release on any object or function reference base 0297 stored in @p v. 0298 0299 @return a copy of the passed in value 0300 */ 0301 static QVariant releaseValue(const QVariant &v); 0302 0303 //@} 0304 private: 0305 /** 0306 * If this extension is a host that provides an object corresponding 0307 * to each kid, override this method to provide it. 0308 * @see enclosingObject 0309 */ 0310 virtual QVariant encloserForKid(KParts::ScriptableExtension *kid); 0311 0312 private: 0313 std::unique_ptr<ScriptableExtensionPrivate> const d; 0314 }; 0315 0316 KPARTS_EXPORT unsigned int qHash(const KParts::ScriptableExtension::Object &o, uint seed = 0); 0317 0318 KPARTS_EXPORT unsigned int qHash(const KParts::ScriptableExtension::FunctionRef &f); 0319 0320 } // namespace KParts 0321 0322 Q_DECLARE_METATYPE(KParts::ScriptableExtension::Null) 0323 Q_DECLARE_METATYPE(KParts::ScriptableExtension::Undefined) 0324 Q_DECLARE_METATYPE(KParts::ScriptableExtension::Exception) 0325 Q_DECLARE_METATYPE(KParts::ScriptableExtension::Object) 0326 Q_DECLARE_METATYPE(KParts::ScriptableExtension::FunctionRef) 0327 0328 #endif