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 &lt;object&gt; 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