00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "kjsprototype.h"
00023 #include "kjsinterpreter.h"
00024 #include "kjsarguments.h"
00025 #include "kjsprivate.h"
00026
00027 #include "kjs/object.h"
00028 #include "kjs/context.h"
00029 #include "kjs/interpreter.h"
00030
00031 #include <QMap>
00032
00033 using namespace KJS;
00034
00035 class KJSCustomProperty
00036 {
00037 public:
00038 KJSCustomProperty(KJSPrototype::PropertyGetter g,
00039 KJSPrototype::PropertySetter s)
00040 : getter(g), setter(s)
00041 {
00042 }
00043
00044 JSValue* read(ExecState* exec, void* object);
00045 void write(ExecState* exec, void* object, JSValue* value);
00046
00047 private:
00048 KJSPrototype::PropertyGetter getter;
00049 KJSPrototype::PropertySetter setter;
00050 };
00051
00052 class CustomObject : public JSObject {
00053 public:
00054 CustomObject(JSValue* proto, void* v)
00055 : JSObject(proto),
00056 iv(v)
00057 {
00058 }
00059
00060 void put(ExecState* exec, const Identifier& id,
00061 JSValue *value, int attr = None);
00062
00063 void* internalValue() { return iv; }
00064
00065
00066 static const ClassInfo info;
00067 const ClassInfo* classInfo() const { return &info; }
00068
00069 private:
00070 void* iv;
00071 };
00072
00073 const ClassInfo CustomObject::info = { "CustomObject", 0, 0, 0 };
00074
00075 class KJSCustomFunction : public JSObject {
00076 public:
00077 KJSCustomFunction(ExecState* exec, KJSPrototype::FunctionCall f)
00078 : callback(f)
00079 {
00080 setPrototype(exec->lexicalInterpreter()->builtinObjectPrototype());
00081 }
00082
00083 JSValue* callAsFunction(ExecState* exec, JSObject* thisObj,
00084 const List &args);
00085 bool implementsCall() const { return true; }
00086
00087 private:
00088 KJSPrototype::FunctionCall callback;
00089 };
00090
00091 JSValue* KJSCustomFunction::callAsFunction(ExecState* exec, JSObject* thisObj,
00092 const List &args)
00093 {
00094
00095 KJS_CHECK_THIS(CustomObject, thisObj);
00096
00097 CustomObject* co = static_cast<CustomObject*>(thisObj);
00098 void* thisValue = co->internalValue();
00099
00100 KJSContext ctx(EXECSTATE_HANDLE(exec));
00101 KJSArguments a(LIST_HANDLE(&args));
00102 KJSObject res = (*callback)(&ctx, thisValue, a);
00103 return JSVALUE(&res);
00104 }
00105
00106 JSValue* KJSCustomProperty::read(ExecState* exec, void* object)
00107 {
00108 assert(getter);
00109
00110 KJSContext ctx(EXECSTATE_HANDLE(exec));
00111 KJSObject res = (*getter)(&ctx, object);
00112 return JSVALUE(&res);
00113 }
00114
00115 void KJSCustomProperty::write(ExecState* exec, void* object, JSValue* value)
00116 {
00117 KJSContext ctx(EXECSTATE_HANDLE(exec));
00118
00119 if (setter) {
00120 KJSObject vo(JSVALUE_HANDLE(value));
00121 (*setter)(&ctx, object, vo);
00122 } else {
00123 JSObject *e = Error::create(exec, GeneralError,
00124 "Property is read-only");
00125 exec->setException(e);
00126 }
00127 }
00128
00129 static JSValue* getPropertyValue(ExecState* exec, JSObject *originalObject,
00130 const Identifier&, const PropertySlot& sl)
00131 {
00132 CustomObject* o = static_cast<CustomObject*>(originalObject);
00133 KJSCustomProperty* p =
00134 reinterpret_cast<KJSCustomProperty*>(sl.customValue());
00135
00136 return p->read(exec, o->internalValue());
00137 }
00138
00139
00140
00141 typedef QMap<UString, KJSCustomProperty*> CustomPropertyMap;
00142
00143 class CustomPrototype : public JSObject {
00144 public:
00145 CustomPrototype()
00146 {
00147 }
00148 ~CustomPrototype()
00149 {
00150 qDeleteAll(properties);
00151 }
00152
00153 bool getOwnPropertySlot(ExecState *exec, const Identifier& id,
00154 PropertySlot& sl)
00155 {
00156 CustomPropertyMap::iterator it = properties.find(id.ustring());
00157 if (it == properties.end())
00158 return JSObject::getOwnPropertySlot(exec, id, sl);
00159
00160 sl.setCustomValue(0, *it, getPropertyValue);
00161
00162 return true;
00163 }
00164
00165 void registerProperty(const QString& name,
00166 KJSPrototype::PropertyGetter g,
00167 KJSPrototype::PropertySetter s)
00168 {
00169 properties.insert(toUString(name), new KJSCustomProperty(g, s));
00170 }
00171
00172 void registerFunction(ExecState* exec,
00173 const QString& name, KJSPrototype::FunctionCall f)
00174 {
00175 putDirect(toIdentifier(name), new KJSCustomFunction(exec, f));
00176 }
00177
00178 bool setProperty(ExecState* exec, CustomObject* obj,
00179 const Identifier& id, JSValue* value)
00180 {
00181 CustomPropertyMap::iterator it = properties.find(id.ustring());
00182 if (it == properties.end())
00183 return false;
00184
00185 (*it)->write(exec, obj->internalValue(), value);
00186
00187 return true;
00188 }
00189
00190 private:
00191 CustomPropertyMap properties;
00192 };
00193
00194 void CustomObject::put(ExecState* exec, const Identifier& id,
00195 JSValue* value, int attr)
00196 {
00197 CustomPrototype* p = static_cast<CustomPrototype*>(prototype());
00198
00199 if (!p->setProperty(exec, this, id, value))
00200 JSObject::put(exec, id, value, attr);
00201 }
00202
00203 KJSPrototype::KJSPrototype()
00204 {
00205 CustomPrototype* p = new CustomPrototype;
00206 gcProtect(p);
00207
00208 hnd = PROTOTYPE_HANDLE(p);
00209 }
00210
00211 KJSPrototype::~KJSPrototype()
00212 {
00213 gcUnprotect(PROTOTYPE(this));
00214 }
00215
00216 void KJSPrototype::defineConstant(const QString& name, double value)
00217 {
00218 CustomPrototype* p = PROTOTYPE(this);
00219
00220 p->putDirect(toIdentifier(name), jsNumber(value),
00221 DontEnum|DontDelete|ReadOnly);
00222 }
00223
00224 void KJSPrototype::defineConstant(const QString& name, const QString& value)
00225 {
00226 CustomPrototype* p = PROTOTYPE(this);
00227
00228 p->putDirect(toIdentifier(name), jsString(toUString(value)),
00229 DontEnum|DontDelete|ReadOnly);
00230 }
00231
00232 void KJSPrototype::defineConstant(const QString& name, const KJSObject& value)
00233 {
00234 CustomPrototype* p = PROTOTYPE(this);
00235
00236 p->putDirect(toIdentifier(name), JSVALUE(&value),
00237 DontEnum|DontDelete|ReadOnly);
00238 }
00239
00240 KJSObject KJSPrototype::constructObject(KJSContext* ctx, void *internalValue)
00241 {
00242 CustomPrototype* p = PROTOTYPE(this);
00243
00244 if (ctx && !p->prototype()) {
00245 ExecState* exec = EXECSTATE(ctx);
00246 KJS::Interpreter* i = exec->lexicalInterpreter();
00247 JSObject* objectProto = i->builtinObjectPrototype();
00248 p->setPrototype(objectProto);
00249 }
00250
00251 CustomObject* newObj = new CustomObject(p, internalValue);
00252 return KJSObject(JSVALUE_HANDLE(newObj));
00253 }
00254
00255 KJSGlobalObject KJSPrototype::constructGlobalObject(void *internalValue)
00256 {
00257 CustomPrototype* p = PROTOTYPE(this);
00258
00259 CustomObject* newObj = new CustomObject(p, internalValue);
00260 return KJSGlobalObject(JSVALUE_HANDLE(newObj));
00261 }
00262
00263 void KJSPrototype::defineProperty(KJSContext* ctx,
00264 const QString& name,
00265 PropertyGetter getter,
00266 PropertySetter setter)
00267 {
00268 assert(getter);
00269
00270 CustomPrototype* p = PROTOTYPE(this);
00271
00272 p->registerProperty(name, getter, setter);
00273 }
00274
00275 void KJSPrototype::defineFunction(KJSContext* ctx,
00276 const QString& name, FunctionCall callback)
00277 {
00278 assert(callback);
00279
00280 CustomPrototype* p = PROTOTYPE(this);
00281 ExecState* exec = EXECSTATE(ctx);
00282
00283 p->registerFunction(exec, name, callback);
00284 }
00285
00286