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 Value DOMFunction::get(ExecState *exec, const Identifier &propertyName) const
00096 {
00097 try {
00098 return tryGet(exec, propertyName);
00099 }
00100 catch (DOM::DOMException e) {
00101 Object err = Error::create(exec, GeneralError, QString("DOM exception %1").arg(e.code).local8Bit());
00102 exec->setException(err);
00103 return Undefined();
00104 }
00105 catch (...) {
00106 kdError(6070) << "Unknown exception in DOMFunction::get()" << endl;
00107 return String("Unknown exception");
00108 }
00109 }
00110
00111 Value DOMFunction::call(ExecState *exec, Object &thisObj, const List &args)
00112 {
00113 try {
00114 return tryCall(exec, thisObj, args);
00115 }
00116
00117
00118
00119 catch (DOM::DOMException e) {
00120 Object err = Error::create(exec, GeneralError, QString("DOM Exception %1").arg(e.code).local8Bit());
00121 err.put(exec, "code", Number(e.code));
00122 exec->setException(err);
00123 return Undefined();
00124 }
00125 catch (DOM::RangeException e) {
00126 Object err = Error::create(exec, GeneralError, QString("DOM Range Exception %1").arg(e.code).local8Bit());
00127 err.put(exec, "code", Number(e.code));
00128 exec->setException(err);
00129 return Undefined();
00130 }
00131 catch (DOM::CSSException e) {
00132 Object err = Error::create(exec, GeneralError, QString("CSS Exception %1").arg(e.code).local8Bit());
00133 err.put(exec, "code", Number(e.code));
00134 exec->setException(err);
00135 return Undefined();
00136 }
00137 catch (DOM::EventException e) {
00138 Object err = Error::create(exec, GeneralError, QString("DOM Event Exception %1").arg(e.code).local8Bit());
00139 err.put(exec, "code", Number(e.code));
00140 exec->setException(err);
00141 return Undefined();
00142 }
00143 catch (...) {
00144 kdError(6070) << "Unknown exception in DOMFunction::call()" << endl;
00145 Object err = Error::create(exec, GeneralError, "Unknown exception");
00146 exec->setException(err);
00147 return Undefined();
00148 }
00149 }
00150
00151 typedef QPtrList<ScriptInterpreter> InterpreterList;
00152 static InterpreterList *interpreterList;
00153
00154 ScriptInterpreter::ScriptInterpreter( const Object &global, khtml::ChildFrame* frame )
00155 : Interpreter( global ), m_frame( frame ), m_domObjects(1021),
00156 m_evt( 0L ), m_inlineCode(false), m_timerCallback(false)
00157 {
00158 #ifdef KJS_VERBOSE
00159 kdDebug(6070) << "ScriptInterpreter::ScriptInterpreter " << this << " for part=" << m_frame << endl;
00160 #endif
00161 if ( !interpreterList )
00162 interpreterList = new InterpreterList;
00163 interpreterList->append( this );
00164 }
00165
00166 ScriptInterpreter::~ScriptInterpreter()
00167 {
00168 #ifdef KJS_VERBOSE
00169 kdDebug(6070) << "ScriptInterpreter::~ScriptInterpreter " << this << " for part=" << m_frame << endl;
00170 #endif
00171 assert( interpreterList && interpreterList->contains( this ) );
00172 interpreterList->remove( this );
00173 if ( interpreterList->isEmpty() ) {
00174 delete interpreterList;
00175 interpreterList = 0;
00176 }
00177 }
00178
00179 void ScriptInterpreter::forgetDOMObject( void* objectHandle )
00180 {
00181 if( !interpreterList ) return;
00182
00183 QPtrListIterator<ScriptInterpreter> it( *interpreterList );
00184 while ( it.current() ) {
00185 (*it)->deleteDOMObject( objectHandle );
00186 ++it;
00187 }
00188 }
00189
00190 void ScriptInterpreter::mark()
00191 {
00192 Interpreter::mark();
00193 #ifdef KJS_VERBOSE
00194 kdDebug(6070) << "ScriptInterpreter::mark " << this << " marking " << m_customizedDomObjects.count() << " DOM objects" << endl;
00195 #endif
00196 QPtrDictIterator<void> it( m_customizedDomObjects );
00197 for( ; it.current(); ++it )
00198 static_cast<DOMObject*>(it.currentKey())->mark();
00199 }
00200
00201 KParts::ReadOnlyPart* ScriptInterpreter::part() const {
00202 return m_frame->m_part;
00203 }
00204
00205 bool ScriptInterpreter::isWindowOpenAllowed() const
00206 {
00207 if ( m_evt )
00208 {
00209 int id = m_evt->handle()->id();
00210 bool eventOk = (
00211 id == DOM::EventImpl::CLICK_EVENT ||
00212 id == DOM::EventImpl::MOUSEUP_EVENT || id == DOM::EventImpl::MOUSEDOWN_EVENT ||
00213 id == DOM::EventImpl::KHTML_ECMA_CLICK_EVENT || id == DOM::EventImpl::KHTML_ECMA_DBLCLICK_EVENT ||
00214
00215 id == DOM::EventImpl::KEYDOWN_EVENT || id == DOM::EventImpl::KEYPRESS_EVENT ||
00216 id == DOM::EventImpl::KEYUP_EVENT ||
00217
00218 id == DOM::EventImpl::SELECT_EVENT || id == DOM::EventImpl::CHANGE_EVENT ||
00219 id == DOM::EventImpl::SUBMIT_EVENT );
00220 kdDebug(6070) << "Window.open, smart policy: id=" << id << " eventOk=" << eventOk << endl;
00221 if (eventOk)
00222 return true;
00223 } else
00224 {
00225 if ( m_inlineCode && !m_timerCallback )
00226 {
00227
00228 return true;
00229 kdDebug(6070) << "Window.open, smart policy, no event, inline code -> ok" << endl;
00230 }
00231 else
00232 kdDebug(6070) << "Window.open, smart policy, no event, <script> tag -> refused" << endl;
00233 }
00234 return false;
00235 }
00236
00237
00238 UString::UString(const QString &d)
00239 {
00240 unsigned int len = d.length();
00241 UChar *dat = new UChar[len];
00242 memcpy(dat, d.unicode(), len * sizeof(UChar));
00243 rep = UString::Rep::create(dat, len);
00244 }
00245
00246 UString::UString(const DOM::DOMString &d)
00247 {
00248 if (d.isNull()) {
00249
00250
00251
00252 attach(&Rep::empty);
00253 return;
00254 }
00255
00256 unsigned int len = d.length();
00257 UChar *dat = new UChar[len];
00258 memcpy(dat, d.unicode(), len * sizeof(UChar));
00259 rep = UString::Rep::create(dat, len);
00260 }
00261
00262 DOM::DOMString UString::string() const
00263 {
00264 return DOM::DOMString((QChar*) data(), size());
00265 }
00266
00267 QString UString::qstring() const
00268 {
00269 return QString((QChar*) data(), size());
00270 }
00271
00272 QConstString UString::qconststring() const
00273 {
00274 return QConstString((QChar*) data(), size());
00275 }
00276
00277 DOM::DOMString Identifier::string() const
00278 {
00279 return DOM::DOMString((QChar*) data(), size());
00280 }
00281
00282 QString Identifier::qstring() const
00283 {
00284 return QString((QChar*) data(), size());
00285 }
00286
00287 DOM::Node KJS::toNode(const Value& val)
00288 {
00289 Object obj = Object::dynamicCast(val);
00290 if (!obj.isValid() || !obj.inherits(&DOMNode::info))
00291 return DOM::Node();
00292
00293 const DOMNode *dobj = static_cast<const DOMNode*>(obj.imp());
00294 return dobj->toNode();
00295 }
00296
00297 Value KJS::getString(DOM::DOMString s)
00298 {
00299 if (s.isNull())
00300 return Null();
00301 else
00302 return String(s);
00303 }
00304
00305 QVariant KJS::ValueToVariant(ExecState* exec, const Value &val) {
00306 QVariant res;
00307 switch (val.type()) {
00308 case BooleanType:
00309 res = QVariant(val.toBoolean(exec), 0);
00310 break;
00311 case NumberType:
00312 res = QVariant(val.toNumber(exec));
00313 break;
00314 case StringType:
00315 res = QVariant(val.toString(exec).qstring());
00316 break;
00317 default:
00318
00319 break;
00320 }
00321 return res;
00322 }
00323
00324 class EmbedLiveConnect : public ObjectImp
00325 {
00326 friend Value KJS::getLiveConnectValue(KParts::LiveConnectExtension *lc, const QString & name, const int type, const QString & value, int id);
00327 EmbedLiveConnect(KParts::LiveConnectExtension *lc, UString n, KParts::LiveConnectExtension::Type t, int id);
00328 public:
00329 ~EmbedLiveConnect();
00330
00331 virtual Value get(ExecState *, const Identifier & prop) const;
00332 virtual void put(ExecState * exec, const Identifier &prop, const Value & value, int=None);
00333 virtual Value call(ExecState * exec, Object &, const List &args);
00334 virtual bool implementsCall() const;
00335 virtual bool toBoolean(ExecState *) const;
00336 virtual Value toPrimitive(ExecState *exec, Type) const;
00337 virtual UString toString(ExecState *) const;
00338
00339 private:
00340 EmbedLiveConnect(const EmbedLiveConnect &);
00341 QGuardedPtr<KParts::LiveConnectExtension> m_liveconnect;
00342 UString name;
00343 KParts::LiveConnectExtension::Type objtype;
00344 unsigned long objid;
00345 };
00346
00347 Value KJS::getLiveConnectValue(KParts::LiveConnectExtension *lc, const QString & name, const int type, const QString & value, int id)
00348 {
00349 KParts::LiveConnectExtension::Type t=(KParts::LiveConnectExtension::Type)type;
00350 switch(t) {
00351 case KParts::LiveConnectExtension::TypeBool: {
00352 bool ok;
00353 int i = value.toInt(&ok);
00354 if (ok)
00355 return Boolean(i);
00356 return Boolean(!strcasecmp(value.latin1(), "true"));
00357 }
00358 case KParts::LiveConnectExtension::TypeObject:
00359 case KParts::LiveConnectExtension::TypeFunction:
00360 return Value(new EmbedLiveConnect(lc, name, t, id));
00361 case KParts::LiveConnectExtension::TypeNumber: {
00362 bool ok;
00363 int i = value.toInt(&ok);
00364 if (ok)
00365 return Number(i);
00366 else
00367 return Number(value.toDouble(&ok));
00368 }
00369 case KParts::LiveConnectExtension::TypeString:
00370 return String(value);
00371 case KParts::LiveConnectExtension::TypeVoid:
00372 default:
00373 return Undefined();
00374 }
00375 }
00376
00377
00378 EmbedLiveConnect::EmbedLiveConnect(KParts::LiveConnectExtension *lc, UString n, KParts::LiveConnectExtension::Type t, int id)
00379 : m_liveconnect (lc), name(n), objtype(t), objid(id)
00380 {}
00381
00382
00383 EmbedLiveConnect::~EmbedLiveConnect() {
00384 if (m_liveconnect)
00385 m_liveconnect->unregister(objid);
00386 }
00387
00388 KDE_NO_EXPORT
00389 Value EmbedLiveConnect::get(ExecState *, const Identifier & prop) const
00390 {
00391 if (m_liveconnect) {
00392 KParts::LiveConnectExtension::Type rettype;
00393 QString retval;
00394 unsigned long retobjid;
00395 if (m_liveconnect->get(objid, prop.qstring(), rettype, retobjid, retval))
00396 return getLiveConnectValue(m_liveconnect, prop.qstring(), rettype, retval, retobjid);
00397 }
00398 return Undefined();
00399 }
00400
00401 KDE_NO_EXPORT
00402 void EmbedLiveConnect::put(ExecState * exec, const Identifier &prop, const Value & value, int)
00403 {
00404 if (m_liveconnect)
00405 m_liveconnect->put(objid, prop.qstring(), value.toString(exec).qstring());
00406 }
00407
00408 KDE_NO_EXPORT
00409 bool EmbedLiveConnect::implementsCall() const {
00410 return objtype == KParts::LiveConnectExtension::TypeFunction;
00411 }
00412
00413 KDE_NO_EXPORT
00414 Value EmbedLiveConnect::call(ExecState *exec, Object&, const List &args)
00415 {
00416 if (m_liveconnect) {
00417 QStringList qargs;
00418 for (ListIterator i = args.begin(); i != args.end(); ++i)
00419 qargs.append((*i).toString(exec).qstring());
00420 KParts::LiveConnectExtension::Type rtype;
00421 QString rval;
00422 unsigned long robjid;
00423 if (m_liveconnect->call(objid, name.qstring(), qargs, rtype, robjid, rval))
00424 return getLiveConnectValue(m_liveconnect, name.qstring(), rtype, rval, robjid);
00425 }
00426 return Undefined();
00427 }
00428
00429 KDE_NO_EXPORT
00430 bool EmbedLiveConnect::toBoolean(ExecState *) const {
00431 return true;
00432 }
00433
00434 KDE_NO_EXPORT
00435 Value EmbedLiveConnect::toPrimitive(ExecState *exec, Type) const {
00436 return String(toString(exec));
00437 }
00438
00439 KDE_NO_EXPORT
00440 UString EmbedLiveConnect::toString(ExecState *) const {
00441 QString str;
00442 const char *type = objtype == KParts::LiveConnectExtension::TypeFunction ? "Function" : "Object";
00443 str.sprintf("[object %s ref=%d]", type, (int) objid);
00444 return UString(str);
00445 }