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.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Jul 22 10:18:35 2005 by doxygen 1.3.6 written by Dimitri van Heesch, © 1997-2003