File indexing completed on 2024-04-28 15:23:16

0001 /* This file is part of the KDE project
0002    Copyright (C) 2010 Maksim Orlovich <maksim@kde.org>
0003 
0004    This library is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Library General Public
0006    License as published by the Free Software Foundation; either
0007    version 2 of the License, or (at your option) any later version.
0008 
0009    This library is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012    Library General Public License for more details.
0013 
0014    You should have received a copy of the GNU Library General Public License
0015    along with this library; see the file COPYING.LIB.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017    Boston, MA 02110-1301, USA.
0018 */
0019 
0020 #ifndef KJS_SCRIPTABLE_H
0021 #define KJS_SCRIPTABLE_H
0022 
0023 #include <khtml_part.h>
0024 #include <kparts/scriptableextension.h>
0025 #include <kjs/object.h>
0026 #include <kjs/list.h>
0027 #include <QHash>
0028 
0029 using namespace KParts;
0030 
0031 namespace KJS
0032 {
0033 
0034 // First, a couple of helpers: these let clients perform basic getOwnPropertySlot or
0035 // put (with a bool effect return) on the root of given extension.
0036 bool pluginRootGet(ExecState *exec, ScriptableExtension *ext, const KJS::Identifier &i, PropertySlot &slot);
0037 bool pluginRootPut(ExecState *exec, ScriptableExtension *ext, const KJS::Identifier &i, JSValue *v);
0038 
0039 class WrapScriptableObject;
0040 
0041 // We have two ScriptableExtension subclasses.
0042 // ScriptableOperations is a singleton used to perform operations on objects.
0043 // This is because objects in child  parts (and other windows) can survive their
0044 // parent, and we still need to perform operations on them.
0045 class ScriptableOperations: public ScriptableExtension
0046 {
0047     Q_OBJECT
0048 public:
0049     // ScriptableExtension API
0050     QVariant callAsFunction(ScriptableExtension *callerPrincipal, quint64 objId, const ArgList &args) override;
0051     virtual QVariant callFunctionReference(ScriptableExtension *callerPrincipal, quint64 objId,
0052                                            const QString &f, const ArgList &args) override;
0053     QVariant callAsConstructor(ScriptableExtension *callerPrincipal, quint64 objId, const ArgList &args) override;
0054     bool hasProperty(ScriptableExtension *callerPrincipal, quint64 objId, const QString &propName) override;
0055     QVariant get(ScriptableExtension *callerPrincipal, quint64 objId, const QString &propName) override;
0056     bool put(ScriptableExtension *callerPrincipal, quint64 objId, const QString &propName, const QVariant &value) override;
0057     bool removeProperty(ScriptableExtension *callerPrincipal, quint64 objId, const QString &propName) override;
0058     bool enumerateProperties(ScriptableExtension *callerPrincipal, quint64 objId, QStringList *result) override;
0059 
0060     void acquire(quint64 objid) override;
0061     void release(quint64 objid) override;
0062 
0063     // May return null.
0064     static JSObject *objectForId(quint64 objId);
0065 
0066     static ScriptableOperations *self();
0067 
0068     void mark();
0069 public:
0070     // We keep a weak table of our wrappers for external objects, so that
0071     // the same object gets the same wrapper all the time.
0072     static QHash<Object,      WrapScriptableObject *> *importedObjects();
0073     static QHash<FunctionRef, WrapScriptableObject *> *importedFunctions();
0074 
0075     // For exported objects, we keep refcounts, and mark them
0076     static QHash<JSObject *, int> *exportedObjects();
0077 
0078     static JSValue *importValue(ExecState *exec, const QVariant &v, bool alreadyRefd);
0079     static JSValue *importFunctionRef(ExecState *exec, const QVariant &v, bool alreadyRefd);
0080     static JSObject *importObject(ExecState *exec, const QVariant &v, bool alreadyRefd);
0081     static List importArgs(ExecState *exec, const ArgList &args);
0082 
0083     static QVariant exportValue(JSValue *v, bool preRef);
0084     static QVariant exportObject(JSObject *o, bool preRef);
0085     static QVariant exportFuncRef(JSObject *base, const QString &field, bool preRef);
0086 
0087     // Both methods may return 0. Used for security checks!
0088     static KHTMLPart *partForPrincipal(ScriptableExtension *callerPrincipal);
0089     static ExecState *execStateForPrincipal(ScriptableExtension *callerPrincipal);
0090 private:
0091     // input should not be a WrapScriptableObject.
0092     static ScriptableExtension::Object exportNativeObject(JSObject *o, bool preRef);
0093 
0094     // Checks exception state before handling conversion
0095     QVariant handleReturn(ExecState *exec, JSValue *v);
0096 
0097     // If the given object is owned by a KHTMLScriptable, return the
0098     // JS object for it. If not, return 0.
0099     static JSObject *tryGetNativeObject(const Object &sObj);
0100 
0101     static QHash<JSObject *, int> *s_exportedObjects;
0102     static QHash<Object,      WrapScriptableObject *> *s_importedObjects;
0103     static QHash<FunctionRef, WrapScriptableObject *> *s_importedFunctions;
0104 
0105     ScriptableOperations();
0106     ~ScriptableOperations();
0107 
0108     // copy ctor, etc., disabled already, being a QObject
0109     static ScriptableOperations *s_instance;
0110 };
0111 
0112 // KHTMLPartScriptable, on other hands, is tied to a part, and
0113 // is used for part-specific operations such as looking up
0114 // root objects and script execution.
0115 class KHTMLPartScriptable: public ScriptableExtension
0116 {
0117     Q_OBJECT
0118     friend class ScriptableOperations;
0119 public:
0120     KHTMLPartScriptable(KHTMLPart *part);
0121 
0122     QVariant rootObject() override;
0123     QVariant encloserForKid(KParts::ScriptableExtension *kid) override;
0124 
0125     bool setException(ScriptableExtension *callerPrincipal, const QString &message) override;
0126 
0127     virtual QVariant evaluateScript(ScriptableExtension *callerPrincipal,
0128                                     quint64 contextObjectId,
0129                                     const QString &code,
0130                                     ScriptLanguage language = ECMAScript) override;
0131     bool isScriptLanguageSupported(ScriptLanguage lang) const override;
0132 
0133     // For paranoia: forward to ScriptOperations
0134     void acquire(quint64 objid) override;
0135     void release(quint64 objid) override;
0136 private:
0137     KJS::Interpreter *interpreter();
0138     KHTMLPart *m_part;
0139 };
0140 
0141 // This represents an object we imported from a foreign ScriptableExtension
0142 class WrapScriptableObject: public JSObject
0143 {
0144 public:
0145     friend class ScriptableOperations;
0146 
0147     enum Type {
0148         Object,
0149         FunctionRef
0150     };
0151 
0152     WrapScriptableObject(ExecState *exec, Type t,
0153                          ScriptableExtension *owner, quint64 objId,
0154                          const QString &field = QString());
0155 
0156     ~WrapScriptableObject();
0157 
0158     const ClassInfo *classInfo() const override
0159     {
0160         return &info;
0161     }
0162     static const ClassInfo info;
0163 
0164     bool getOwnPropertySlot(ExecState *, const Identifier &, PropertySlot &) override;
0165     using JSObject::getOwnPropertySlot;
0166     void put(ExecState *exec, const Identifier &propertyName, JSValue *value, int) override;
0167     using JSObject::put;
0168     bool deleteProperty(ExecState *exec, const Identifier &i) override;
0169     using JSObject::deleteProperty;
0170 
0171     bool isFunctionType() const override
0172     {
0173         return false;
0174     }
0175     bool implementsCall() const override
0176     {
0177         return true;
0178     }
0179     JSValue *callAsFunction(ExecState *exec, JSObject *thisObj, const List &args) override;
0180 
0181     // We claim true, since may be calleable
0182     bool implementsConstruct() const override
0183     {
0184         return true;
0185     }
0186     JSObject *construct(ExecState *exec, const List &args) override;
0187     using JSObject::construct;
0188 
0189     void getOwnPropertyNames(ExecState *, PropertyNameArray &, PropertyMap::PropertyMode mode) override;
0190 
0191     UString toString(ExecState *exec) const override;
0192 
0193     // This method is used to note that the object has been ref'd on our
0194     // behalf by an external producer.
0195     void reportRef();
0196 private:
0197     // If we're a function reference type, before we perform non-call operations we need
0198     // to actually lookup the field. This takes care of that.
0199     ScriptableExtension::Object resolveAnyReferences(ExecState *exec, bool *ok);
0200 
0201     // resolves all function references to get an ref, if any.
0202     ScriptableExtension::Object resolveReferences(ExecState *exec,
0203             const ScriptableExtension::FunctionRef &f,
0204             bool *ok);
0205 
0206     // gets a field of the given object id, base
0207     QVariant doGet(ExecState *exec, const ScriptableExtension::Object &o,
0208                    const QString &field, bool *ok);
0209 
0210     ScriptableExtension::ArgList exportArgs(const List &l);
0211     void releaseArgs(ScriptableExtension::ArgList &a);
0212 
0213     // Looks up the principal we're running as
0214     ScriptableExtension *principal(ExecState *exec);
0215 
0216     // what we wrap
0217     QWeakPointer<ScriptableExtension> objExtension;
0218     quint64 objId;
0219     QString field;
0220     Type    type;
0221     int     refsByUs; // how many references we hold
0222 
0223     // this is an unguarded copy of objExtension. We need it in order to
0224     // clean ourselves up from the imports tables properly even if the peer
0225     // was destroyed.
0226     ScriptableExtension *tableKey;
0227 };
0228 
0229 }
0230 
0231 #endif