khtml Library API Documentation

kjs_binding.cpp

00001 // -*- c-basic-offset: 2 -*- 00002 /* 00003 * This file is part of the KDE libraries 00004 * Copyright (C) 1999-2003 Harri Porten (porten@kde.org) 00005 * Copyright (C) 2001-2003 David Faure (faure@kde.org) 00006 * Copyright (C) 2003 Apple Computer, Inc. 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Library General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2 of the License, or (at your option) any later version. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Library General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Library General Public 00019 * License along with this library; if not, write to the Free Software 00020 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 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 /* TODO: 00039 * The catch all (...) clauses below shouldn't be necessary. 00040 * But they helped to view for example www.faz.net in an stable manner. 00041 * Those unknown exceptions should be treated as severe bugs and be fixed. 00042 * 00043 * these may be CSS exceptions - need to check - pmk 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 // ### translate code into readable string ? 00054 // ### oh, and s/QString/i18n or I18N_NOOP (the code in kjs uses I18N_NOOP... but where is it translated ?) 00055 // and where does it appear to the user ? 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 UString DOMObject::toString(ExecState *) const 00084 { 00085 return "[object " + className() + "]"; 00086 } 00087 00088 Value DOMFunction::get(ExecState *exec, const Identifier &propertyName) const 00089 { 00090 try { 00091 return tryGet(exec, propertyName); 00092 } 00093 catch (DOM::DOMException e) { 00094 Object err = Error::create(exec, GeneralError, QString("DOM exception %1").arg(e.code).local8Bit()); 00095 exec->setException(err); 00096 return Undefined(); 00097 } 00098 catch (...) { 00099 kdError(6070) << "Unknown exception in DOMFunction::get()" << endl; 00100 return String("Unknown exception"); 00101 } 00102 } 00103 00104 Value DOMFunction::call(ExecState *exec, Object &thisObj, const List &args) 00105 { 00106 try { 00107 return tryCall(exec, thisObj, args); 00108 } 00109 // pity there's no way to distinguish between these in JS code 00110 // ### Look into setting prototypes of these & the use of instanceof so the exception 00111 // type can be determined. See what other browsers do. 00112 catch (DOM::DOMException e) { 00113 Object err = Error::create(exec, GeneralError, QString("DOM Exception %1").arg(e.code).local8Bit()); 00114 err.put(exec, "code", Number(e.code)); 00115 exec->setException(err); 00116 return Undefined(); 00117 } 00118 catch (DOM::RangeException e) { 00119 Object err = Error::create(exec, GeneralError, QString("DOM Range Exception %1").arg(e.code).local8Bit()); 00120 err.put(exec, "code", Number(e.code)); 00121 exec->setException(err); 00122 return Undefined(); 00123 } 00124 catch (DOM::CSSException e) { 00125 Object err = Error::create(exec, GeneralError, QString("CSS Exception %1").arg(e.code).local8Bit()); 00126 err.put(exec, "code", Number(e.code)); 00127 exec->setException(err); 00128 return Undefined(); 00129 } 00130 catch (DOM::EventException e) { 00131 Object err = Error::create(exec, GeneralError, QString("DOM Event Exception %1").arg(e.code).local8Bit()); 00132 err.put(exec, "code", Number(e.code)); 00133 exec->setException(err); 00134 return Undefined(); 00135 } 00136 catch (...) { 00137 kdError(6070) << "Unknown exception in DOMFunction::call()" << endl; 00138 Object err = Error::create(exec, GeneralError, "Unknown exception"); 00139 exec->setException(err); 00140 return Undefined(); 00141 } 00142 } 00143 00144 typedef QPtrList<ScriptInterpreter> InterpreterList; 00145 static InterpreterList *interpreterList; 00146 00147 ScriptInterpreter::ScriptInterpreter( const Object &global, khtml::ChildFrame* frame ) 00148 : Interpreter( global ), m_frame( frame ), m_domObjects(1021), 00149 m_evt( 0L ), m_inlineCode(false), m_timerCallback(false) 00150 { 00151 #ifdef KJS_VERBOSE 00152 kdDebug(6070) << "ScriptInterpreter::ScriptInterpreter " << this << " for part=" << m_frame << endl; 00153 #endif 00154 if ( !interpreterList ) 00155 interpreterList = new InterpreterList; 00156 interpreterList->append( this ); 00157 } 00158 00159 ScriptInterpreter::~ScriptInterpreter() 00160 { 00161 #ifdef KJS_VERBOSE 00162 kdDebug(6070) << "ScriptInterpreter::~ScriptInterpreter " << this << " for part=" << m_frame << endl; 00163 #endif 00164 assert( interpreterList && interpreterList->contains( this ) ); 00165 interpreterList->remove( this ); 00166 if ( interpreterList->isEmpty() ) { 00167 delete interpreterList; 00168 interpreterList = 0; 00169 } 00170 } 00171 00172 void ScriptInterpreter::forgetDOMObject( void* objectHandle ) 00173 { 00174 if( !interpreterList ) return; 00175 00176 QPtrListIterator<ScriptInterpreter> it( *interpreterList ); 00177 while ( it.current() ) { 00178 (*it)->deleteDOMObject( objectHandle ); 00179 ++it; 00180 } 00181 } 00182 00183 void ScriptInterpreter::mark() 00184 { 00185 Interpreter::mark(); 00186 #ifdef KJS_VERBOSE 00187 kdDebug(6070) << "ScriptInterpreter::mark " << this << " marking " << m_domObjects.count() << " DOM objects" << endl; 00188 #endif 00189 QPtrDictIterator<DOMObject> it( m_domObjects ); 00190 for( ; it.current(); ++it ) 00191 it.current()->mark(); 00192 } 00193 00194 KParts::ReadOnlyPart* ScriptInterpreter::part() const { 00195 return m_frame->m_part; 00196 } 00197 00198 bool ScriptInterpreter::isWindowOpenAllowed() const 00199 { 00200 if ( m_evt ) 00201 { 00202 int id = m_evt->handle()->id(); 00203 bool eventOk = ( // mouse events 00204 id == DOM::EventImpl::CLICK_EVENT || 00205 id == DOM::EventImpl::MOUSEUP_EVENT || id == DOM::EventImpl::MOUSEDOWN_EVENT || 00206 id == DOM::EventImpl::KHTML_ECMA_CLICK_EVENT || id == DOM::EventImpl::KHTML_ECMA_DBLCLICK_EVENT || 00207 // keyboard events 00208 id == DOM::EventImpl::KEYDOWN_EVENT || id == DOM::EventImpl::KHTML_KEYPRESS_EVENT || 00209 id == DOM::EventImpl::KEYUP_EVENT || 00210 // other accepted events 00211 id == DOM::EventImpl::SELECT_EVENT || id == DOM::EventImpl::CHANGE_EVENT || 00212 id == DOM::EventImpl::SUBMIT_EVENT ); 00213 kdDebug(6070) << "Window.open, smart policy: id=" << id << " eventOk=" << eventOk << endl; 00214 if (eventOk) 00215 return true; 00216 } else // no event 00217 { 00218 if ( m_inlineCode && !m_timerCallback ) 00219 { 00220 // This is the <a href="javascript:window.open('...')> case -> we let it through 00221 return true; 00222 kdDebug(6070) << "Window.open, smart policy, no event, inline code -> ok" << endl; 00223 } 00224 else // This is the <script>window.open(...)</script> case or a timer callback -> block it 00225 kdDebug(6070) << "Window.open, smart policy, no event, <script> tag -> refused" << endl; 00226 } 00227 return false; 00228 } 00229 00230 00231 UString::UString(const QString &d) 00232 { 00233 unsigned int len = d.length(); 00234 UChar *dat = new UChar[len]; 00235 memcpy(dat, d.unicode(), len * sizeof(UChar)); 00236 rep = UString::Rep::create(dat, len); 00237 } 00238 00239 UString::UString(const DOM::DOMString &d) 00240 { 00241 if (d.isNull()) { 00242 attach(&Rep::null); 00243 return; 00244 } 00245 00246 unsigned int len = d.length(); 00247 UChar *dat = new UChar[len]; 00248 memcpy(dat, d.unicode(), len * sizeof(UChar)); 00249 rep = UString::Rep::create(dat, len); 00250 } 00251 00252 DOM::DOMString UString::string() const 00253 { 00254 return DOM::DOMString((QChar*) data(), size()); 00255 } 00256 00257 QString UString::qstring() const 00258 { 00259 return QString((QChar*) data(), size()); 00260 } 00261 00262 QConstString UString::qconststring() const 00263 { 00264 return QConstString((QChar*) data(), size()); 00265 } 00266 00267 DOM::DOMString Identifier::string() const 00268 { 00269 return DOM::DOMString((QChar*) data(), size()); 00270 } 00271 00272 QString Identifier::qstring() const 00273 { 00274 return QString((QChar*) data(), size()); 00275 } 00276 00277 DOM::Node KJS::toNode(const Value& val) 00278 { 00279 Object obj = Object::dynamicCast(val); 00280 if (obj.isNull() || !obj.inherits(&DOMNode::info)) 00281 return DOM::Node(); 00282 00283 const DOMNode *dobj = static_cast<const DOMNode*>(obj.imp()); 00284 return dobj->toNode(); 00285 } 00286 00287 Value KJS::getString(DOM::DOMString s) 00288 { 00289 if (s.isNull()) 00290 return Null(); 00291 else 00292 return String(s); 00293 } 00294 00295 QVariant KJS::ValueToVariant(ExecState* exec, const Value &val) { 00296 QVariant res; 00297 switch (val.type()) { 00298 case BooleanType: 00299 res = QVariant(val.toBoolean(exec), 0); 00300 break; 00301 case NumberType: 00302 res = QVariant(val.toNumber(exec)); 00303 break; 00304 case StringType: 00305 res = QVariant(val.toString(exec).qstring()); 00306 break; 00307 default: 00308 // everything else will be 'invalid' 00309 break; 00310 } 00311 return res; 00312 } 00313 00314 class EmbedLiveConnect : public ObjectImp 00315 { 00316 friend Value KJS::getLiveConnectValue(KParts::LiveConnectExtension *lc, const QString & name, const int type, const QString & value, int id); 00317 EmbedLiveConnect(KParts::LiveConnectExtension *lc, UString n, KParts::LiveConnectExtension::Type t, int id); 00318 public: 00319 ~EmbedLiveConnect(); 00320 00321 virtual Value get(ExecState *, const Identifier & prop) const; 00322 virtual void put(ExecState * exec, const Identifier &prop, const Value & value, int=None); 00323 virtual Value call(ExecState * exec, Object &, const List &args); 00324 virtual bool implementsCall() const; 00325 virtual bool toBoolean(ExecState *) const; 00326 virtual Value toPrimitive(ExecState *exec, Type) const; 00327 virtual UString toString(ExecState *) const; 00328 00329 private: 00330 EmbedLiveConnect(const EmbedLiveConnect &); 00331 QGuardedPtr<KParts::LiveConnectExtension> m_liveconnect; 00332 UString name; 00333 KParts::LiveConnectExtension::Type objtype; 00334 unsigned long objid; 00335 }; 00336 00337 Value KJS::getLiveConnectValue(KParts::LiveConnectExtension *lc, const QString & name, const int type, const QString & value, int id) 00338 { 00339 KParts::LiveConnectExtension::Type t=(KParts::LiveConnectExtension::Type)type; 00340 switch(t) { 00341 case KParts::LiveConnectExtension::TypeBool: { 00342 bool ok; 00343 int i = value.toInt(&ok); 00344 if (ok) 00345 return Boolean(i); 00346 return Boolean(!strcasecmp(value.latin1(), "true")); 00347 } 00348 case KParts::LiveConnectExtension::TypeObject: 00349 case KParts::LiveConnectExtension::TypeFunction: 00350 return Value(new EmbedLiveConnect(lc, name, t, id)); 00351 case KParts::LiveConnectExtension::TypeNumber: { 00352 bool ok; 00353 int i = value.toInt(&ok); 00354 if (ok) 00355 return Number(i); 00356 else 00357 return Number(value.toDouble(&ok)); 00358 } 00359 case KParts::LiveConnectExtension::TypeString: 00360 return String(value); 00361 case KParts::LiveConnectExtension::TypeVoid: 00362 default: 00363 return Undefined(); 00364 } 00365 } 00366 00367 /* only with gcc > 3.4 KDE_NO_EXPORT */ 00368 EmbedLiveConnect::EmbedLiveConnect(KParts::LiveConnectExtension *lc, UString n, KParts::LiveConnectExtension::Type t, int id) 00369 : m_liveconnect (lc), name(n), objtype(t), objid(id) 00370 {} 00371 00372 /* only with gcc > 3.4 KDE_NO_EXPORT */ 00373 EmbedLiveConnect::~EmbedLiveConnect() { 00374 if (m_liveconnect) 00375 m_liveconnect->unregister(objid); 00376 } 00377 00378 KDE_NO_EXPORT 00379 Value EmbedLiveConnect::get(ExecState *, const Identifier & prop) const 00380 { 00381 if (m_liveconnect) { 00382 KParts::LiveConnectExtension::Type rettype; 00383 QString retval; 00384 unsigned long retobjid; 00385 if (m_liveconnect->get(objid, prop.qstring(), rettype, retobjid, retval)) 00386 return getLiveConnectValue(m_liveconnect, prop.qstring(), rettype, retval, retobjid); 00387 } 00388 return Undefined(); 00389 } 00390 00391 KDE_NO_EXPORT 00392 void EmbedLiveConnect::put(ExecState * exec, const Identifier &prop, const Value & value, int) 00393 { 00394 if (m_liveconnect) 00395 m_liveconnect->put(objid, prop.qstring(), value.toString(exec).qstring()); 00396 } 00397 00398 KDE_NO_EXPORT 00399 bool EmbedLiveConnect::implementsCall() const { 00400 return objtype == KParts::LiveConnectExtension::TypeFunction; 00401 } 00402 00403 KDE_NO_EXPORT 00404 Value EmbedLiveConnect::call(ExecState *exec, Object&, const List &args) 00405 { 00406 if (m_liveconnect) { 00407 QStringList qargs; 00408 for (ListIterator i = args.begin(); i != args.end(); ++i) 00409 qargs.append((*i).toString(exec).qstring()); 00410 KParts::LiveConnectExtension::Type rtype; 00411 QString rval; 00412 unsigned long robjid; 00413 if (m_liveconnect->call(objid, name.qstring(), qargs, rtype, robjid, rval)) 00414 return getLiveConnectValue(m_liveconnect, name.qstring(), rtype, rval, robjid); 00415 } 00416 return Undefined(); 00417 } 00418 00419 KDE_NO_EXPORT 00420 bool EmbedLiveConnect::toBoolean(ExecState *) const { 00421 return true; 00422 } 00423 00424 KDE_NO_EXPORT 00425 Value EmbedLiveConnect::toPrimitive(ExecState *exec, Type) const { 00426 return String(toString(exec)); 00427 } 00428 00429 KDE_NO_EXPORT 00430 UString EmbedLiveConnect::toString(ExecState *) const { 00431 QString str; 00432 const char *type = objtype == KParts::LiveConnectExtension::TypeFunction ? "Function" : "Object"; 00433 str.sprintf("[object %s ref=%d]", type, (int) objid); 00434 return UString(str); 00435 }
KDE Logo
This file is part of the documentation for khtml Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Apr 14 00:38:34 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003