00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "kjs_binding.h"
00024 #include "kjs_dom.h"
00025
00026 #include "dom/dom_exception.h"
00027 #include "dom/dom2_range.h"
00028 #include "xml/dom2_eventsimpl.h"
00029 #include "khtmlpart_p.h"
00030
00031 #include <kdebug.h>
00032 #include <kparts/browserextension.h>
00033
00034 #include <assert.h>
00035
00036 using namespace KJS;
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 Value DOMObject::get(ExecState *exec, const Identifier &p) const
00047 {
00048 Value result;
00049 try {
00050 result = tryGet(exec,p);
00051 }
00052 catch (DOM::DOMException e) {
00053
00054
00055
00056 Object err = Error::create(exec, GeneralError, QString("DOM exception %1").arg(e.code).local8Bit());
00057 exec->setException( err );
00058 result = Undefined();
00059 }
00060 catch (...) {
00061 kdError(6070) << "Unknown exception in DOMObject::get()" << endl;
00062 result = String("Unknown exception");
00063 }
00064
00065 return result;
00066 }
00067
00068 void DOMObject::put(ExecState *exec, const Identifier &propertyName,
00069 const Value &value, int attr)
00070 {
00071 try {
00072 tryPut(exec, propertyName, value, attr);
00073 }
00074 catch (DOM::DOMException e) {
00075 Object err = Error::create(exec, GeneralError, QString("DOM exception %1").arg(e.code).local8Bit());
00076 exec->setException(err);
00077 }
00078 catch (...) {
00079 kdError(6070) << "Unknown exception in DOMObject::put()" << endl;
00080 }
00081 }
00082
00083 void DOMObject::tryPut(ExecState *exec, const Identifier &propertyName,
00084 const Value& value, int attr)
00085 {
00086 static_cast<ScriptInterpreter*>(exec->dynamicInterpreter())->customizedDOMObject(this);
00087 ObjectImp::put(exec,propertyName,value,attr);
00088 }
00089
00090 UString DOMObject::toString(ExecState *) const
00091 {
00092 return "[object " + className() + "]";
00093 }
00094
00095 Boolean DOMObject::hasInstance(ExecState *exec, const Value &value)
00096 {
00097 if (value.type() != ObjectType)
00098 return Boolean(false);
00099
00100 Value prot = get(exec,prototypePropertyName);
00101 if (prot.type() != ObjectType && prot.type() != NullType) {
00102 Object err = Error::create(exec, TypeError, "Invalid prototype encountered "
00103 "in instanceof operation.");
00104 exec->setException(err);
00105 return Boolean(false);
00106 }
00107
00108 Object v = Object(static_cast<ObjectImp*>(value.imp()));
00109 while ((v = Object::dynamicCast(v.prototype())).imp()) {
00110 if (v.imp() == prot.imp())
00111 return Boolean(true);
00112 }
00113 return Boolean(false);
00114 }
00115
00116
00117 Value DOMFunction::get(ExecState *exec, const Identifier &propertyName) const
00118 {
00119 try {
00120 return tryGet(exec, propertyName);
00121 }
00122 catch (DOM::DOMException e) {
00123 Object err = Error::create(exec, GeneralError, QString("DOM exception %1").arg(e.code).local8Bit());
00124 exec->setException(err);
00125 return Undefined();
00126 }
00127 catch (...) {
00128 kdError(6070) << "Unknown exception in DOMFunction::get()" << endl;
00129 return String("Unknown exception");
00130 }
00131 }
00132
00133 Value DOMFunction::call(ExecState *exec, Object &thisObj, const List &args)
00134 {
00135 try {
00136 return tryCall(exec, thisObj, args);
00137 }
00138
00139
00140
00141 catch (DOM::DOMException e) {
00142 Object err = Error::create(exec, GeneralError, QString("DOM Exception %1").arg(e.code).local8Bit());
00143 err.put(exec, "code", Number(e.code));
00144 exec->setException(err);
00145 return Undefined();
00146 }
00147 catch (DOM::RangeException e) {
00148 Object err = Error::create(exec, GeneralError, QString("DOM Range Exception %1").arg(e.code).local8Bit());
00149 err.put(exec, "code", Number(e.code));
00150 exec->setException(err);
00151 return Undefined();
00152 }
00153 catch (DOM::CSSException e) {
00154 Object err = Error::create(exec, GeneralError, QString("CSS Exception %1").arg(e.code).local8Bit());
00155 err.put(exec, "code", Number(e.code));
00156 exec->setException(err);
00157 return Undefined();
00158 }
00159 catch (DOM::EventException e) {
00160 Object err = Error::create(exec, GeneralError, QString("DOM Event Exception %1").arg(e.code).local8Bit());
00161 err.put(exec, "code", Number(e.code));
00162 exec->setException(err);
00163 return Undefined();
00164 }
00165 catch (...) {
00166 kdError(6070) << "Unknown exception in DOMFunction::call()" << endl;
00167 Object err = Error::create(exec, GeneralError, "Unknown exception");
00168 exec->setException(err);
00169 return Undefined();
00170 }
00171 }
00172
00173 typedef QPtrList<ScriptInterpreter> InterpreterList;
00174 static InterpreterList *interpreterList;
00175
00176 ScriptInterpreter::ScriptInterpreter( const Object &global, khtml::ChildFrame* frame )
00177 : Interpreter( global ), m_frame( frame ), m_domObjects(1021),
00178 m_evt( 0L ), m_inlineCode(false), m_timerCallback(false)
00179 {
00180 #ifdef KJS_VERBOSE
00181 kdDebug(6070) << "ScriptInterpreter::ScriptInterpreter " << this << " for part=" << m_frame << endl;
00182 #endif
00183 if ( !interpreterList )
00184 interpreterList = new InterpreterList;
00185 interpreterList->append( this );
00186 }
00187
00188 ScriptInterpreter::~ScriptInterpreter()
00189 {
00190 #ifdef KJS_VERBOSE
00191 kdDebug(6070) << "ScriptInterpreter::~ScriptInterpreter " << this << " for part=" << m_frame << endl;
00192 #endif
00193 assert( interpreterList && interpreterList->contains( this ) );
00194 interpreterList->remove( this );
00195 if ( interpreterList->isEmpty() ) {
00196 delete interpreterList;
00197 interpreterList = 0;
00198 }
00199 }
00200
00201 void ScriptInterpreter::forgetDOMObject( void* objectHandle )
00202 {
00203 if( !interpreterList ) return;
00204
00205 QPtrListIterator<ScriptInterpreter> it( *interpreterList );
00206 while ( it.current() ) {
00207 (*it)->deleteDOMObject( objectHandle );
00208 ++it;
00209 }
00210 }
00211
00212 void ScriptInterpreter::mark()
00213 {
00214 Interpreter::mark();
00215 #ifdef KJS_VERBOSE
00216 kdDebug(6070) << "ScriptInterpreter::mark " << this << " marking " << m_customizedDomObjects.count() << " DOM objects" << endl;
00217 #endif
00218 QPtrDictIterator<void> it( m_customizedDomObjects );
00219 for( ; it.current(); ++it )
00220 static_cast<DOMObject*>(it.currentKey())->mark();
00221 }
00222
00223 KParts::ReadOnlyPart* ScriptInterpreter::part() const {
00224 return m_frame->m_part;
00225 }
00226
00227 bool ScriptInterpreter::isWindowOpenAllowed() const
00228 {
00229 if ( m_evt )
00230 {
00231 int id = m_evt->handle()->id();
00232 bool eventOk = (
00233 id == DOM::EventImpl::CLICK_EVENT ||
00234 id == DOM::EventImpl::MOUSEUP_EVENT || id == DOM::EventImpl::MOUSEDOWN_EVENT ||
00235 id == DOM::EventImpl::KHTML_ECMA_CLICK_EVENT || id == DOM::EventImpl::KHTML_ECMA_DBLCLICK_EVENT ||
00236
00237 id == DOM::EventImpl::KEYDOWN_EVENT || id == DOM::EventImpl::KEYPRESS_EVENT ||
00238 id == DOM::EventImpl::KEYUP_EVENT ||
00239
00240 id == DOM::EventImpl::SELECT_EVENT || id == DOM::EventImpl::CHANGE_EVENT ||
00241 id == DOM::EventImpl::SUBMIT_EVENT );
00242 kdDebug(6070) << "Window.open, smart policy: id=" << id << " eventOk=" << eventOk << endl;
00243 if (eventOk)
00244 return true;
00245 } else
00246 {
00247 if ( m_inlineCode && !m_timerCallback )
00248 {
00249
00250 return true;
00251 kdDebug(6070) << "Window.open, smart policy, no event, inline code -> ok" << endl;
00252 }
00253 else
00254 kdDebug(6070) << "Window.open, smart policy, no event, <script> tag -> refused" << endl;
00255 }
00256 return false;
00257 }
00258
00259
00260 UString::UString(const QString &d)
00261 {
00262 unsigned int len = d.length();
00263 UChar *dat = new UChar[len];
00264 memcpy(dat, d.unicode(), len * sizeof(UChar));
00265 rep = UString::Rep::create(dat, len);
00266 }
00267
00268 UString::UString(const DOM::DOMString &d)
00269 {
00270 if (d.isNull()) {
00271
00272
00273
00274 attach(&Rep::empty);
00275 return;
00276 }
00277
00278 unsigned int len = d.length();
00279 UChar *dat = new UChar[len];
00280 memcpy(dat, d.unicode(), len * sizeof(UChar));
00281 rep = UString::Rep::create(dat, len);
00282 }
00283
00284 DOM::DOMString UString::string() const
00285 {
00286 return DOM::DOMString((QChar*) data(), size());
00287 }
00288
00289 QString UString::qstring() const
00290 {
00291 return QString((QChar*) data(), size());
00292 }
00293
00294 QConstString UString::qconststring() const
00295 {
00296 return QConstString((QChar*) data(), size());
00297 }
00298
00299 DOM::DOMString Identifier::string() const
00300 {
00301 return DOM::DOMString((QChar*) data(), size());
00302 }
00303
00304 QString Identifier::qstring() const
00305 {
00306 return QString((QChar*) data(), size());
00307 }
00308
00309 DOM::Node KJS::toNode(const Value& val)
00310 {
00311 Object obj = Object::dynamicCast(val);
00312 if (!obj.isValid() || !obj.inherits(&DOMNode::info))
00313 return DOM::Node();
00314
00315 const DOMNode *dobj = static_cast<const DOMNode*>(obj.imp());
00316 return dobj->toNode();
00317 }
00318
00319 Value KJS::getString(DOM::DOMString s)
00320 {
00321 if (s.isNull())
00322 return Null();
00323 else
00324 return String(s);
00325 }
00326
00327 QVariant KJS::ValueToVariant(ExecState* exec, const Value &val) {
00328 QVariant res;
00329 switch (val.type()) {
00330 case BooleanType:
00331 res = QVariant(val.toBoolean(exec), 0);
00332 break;
00333 case NumberType:
00334 res = QVariant(val.toNumber(exec));
00335 break;
00336 case StringType:
00337 res = QVariant(val.toString(exec).qstring());
00338 break;
00339 default:
00340
00341 break;
00342 }
00343 return res;
00344 }
00345
00346 class EmbedLiveConnect : public ObjectImp
00347 {
00348 friend Value KJS::getLiveConnectValue(KParts::LiveConnectExtension *lc, const QString & name, const int type, const QString & value, int id);
00349 EmbedLiveConnect(KParts::LiveConnectExtension *lc, UString n, KParts::LiveConnectExtension::Type t, int id);
00350 public:
00351 ~EmbedLiveConnect();
00352
00353 virtual Value get(ExecState *, const Identifier & prop) const;
00354 virtual void put(ExecState * exec, const Identifier &prop, const Value & value, int=None);
00355 virtual Value call(ExecState * exec, Object &, const List &args);
00356 virtual bool implementsCall() const;
00357 virtual bool toBoolean(ExecState *) const;
00358 virtual Value toPrimitive(ExecState *exec, Type) const;
00359 virtual UString toString(ExecState *) const;
00360
00361 private:
00362 EmbedLiveConnect(const EmbedLiveConnect &);
00363 QGuardedPtr<KParts::LiveConnectExtension> m_liveconnect;
00364 UString name;
00365 KParts::LiveConnectExtension::Type objtype;
00366 unsigned long objid;
00367 };
00368
00369 Value KJS::getLiveConnectValue(KParts::LiveConnectExtension *lc, const QString & name, const int type, const QString & value, int id)
00370 {
00371 KParts::LiveConnectExtension::Type t=(KParts::LiveConnectExtension::Type)type;
00372 switch(t) {
00373 case KParts::LiveConnectExtension::TypeBool: {
00374 bool ok;
00375 int i = value.toInt(&ok);
00376 if (ok)
00377 return Boolean(i);
00378 return Boolean(!strcasecmp(value.latin1(), "true"));
00379 }
00380 case KParts::LiveConnectExtension::TypeObject:
00381 case KParts::LiveConnectExtension::TypeFunction:
00382 return Value(new EmbedLiveConnect(lc, name, t, id));
00383 case KParts::LiveConnectExtension::TypeNumber: {
00384 bool ok;
00385 int i = value.toInt(&ok);
00386 if (ok)
00387 return Number(i);
00388 else
00389 return Number(value.toDouble(&ok));
00390 }
00391 case KParts::LiveConnectExtension::TypeString:
00392 return String(value);
00393 case KParts::LiveConnectExtension::TypeVoid:
00394 default:
00395 return Undefined();
00396 }
00397 }
00398
00399
00400 EmbedLiveConnect::EmbedLiveConnect(KParts::LiveConnectExtension *lc, UString n, KParts::LiveConnectExtension::Type t, int id)
00401 : m_liveconnect (lc), name(n), objtype(t), objid(id)
00402 {}
00403
00404
00405 EmbedLiveConnect::~EmbedLiveConnect() {
00406 if (m_liveconnect)
00407 m_liveconnect->unregister(objid);
00408 }
00409
00410 KDE_NO_EXPORT
00411 Value EmbedLiveConnect::get(ExecState *, const Identifier & prop) const
00412 {
00413 if (m_liveconnect) {
00414 KParts::LiveConnectExtension::Type rettype;
00415 QString retval;
00416 unsigned long retobjid;
00417 if (m_liveconnect->get(objid, prop.qstring(), rettype, retobjid, retval))
00418 return getLiveConnectValue(m_liveconnect, prop.qstring(), rettype, retval, retobjid);
00419 }
00420 return Undefined();
00421 }
00422
00423 KDE_NO_EXPORT
00424 void EmbedLiveConnect::put(ExecState * exec, const Identifier &prop, const Value & value, int)
00425 {
00426 if (m_liveconnect)
00427 m_liveconnect->put(objid, prop.qstring(), value.toString(exec).qstring());
00428 }
00429
00430 KDE_NO_EXPORT
00431 bool EmbedLiveConnect::implementsCall() const {
00432 return objtype == KParts::LiveConnectExtension::TypeFunction;
00433 }
00434
00435 KDE_NO_EXPORT
00436 Value EmbedLiveConnect::call(ExecState *exec, Object&, const List &args)
00437 {
00438 if (m_liveconnect) {
00439 QStringList qargs;
00440 for (ListIterator i = args.begin(); i != args.end(); ++i)
00441 qargs.append((*i).toString(exec).qstring());
00442 KParts::LiveConnectExtension::Type rtype;
00443 QString rval;
00444 unsigned long robjid;
00445 if (m_liveconnect->call(objid, name.qstring(), qargs, rtype, robjid, rval))
00446 return getLiveConnectValue(m_liveconnect, name.qstring(), rtype, rval, robjid);
00447 }
00448 return Undefined();
00449 }
00450
00451 KDE_NO_EXPORT
00452 bool EmbedLiveConnect::toBoolean(ExecState *) const {
00453 return true;
00454 }
00455
00456 KDE_NO_EXPORT
00457 Value EmbedLiveConnect::toPrimitive(ExecState *exec, Type) const {
00458 return String(toString(exec));
00459 }
00460
00461 KDE_NO_EXPORT
00462 UString EmbedLiveConnect::toString(ExecState *) const {
00463 QString str;
00464 const char *type = objtype == KParts::LiveConnectExtension::TypeFunction ? "Function" : "Object";
00465 str.sprintf("[object %s ref=%d]", type, (int) objid);
00466 return UString(str);
00467 }