00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "kjs_proxy.h"
00023
00024 #include "kjs_window.h"
00025 #include "kjs_events.h"
00026 #include "kjs_debugwin.h"
00027 #include <khtml_part.h>
00028 #include <kprotocolmanager.h>
00029 #include <kdebug.h>
00030 #include <kmessagebox.h>
00031 #include <klocale.h>
00032 #include <unistd.h>
00033 #include <signal.h>
00034 #include <sys/time.h>
00035 #include <kjs/collector.h>
00036 #include <assert.h>
00037
00038 using namespace KJS;
00039
00040 extern "C" {
00041 KJSProxy *kjs_html_init(KHTMLPart *khtmlpart);
00042 }
00043
00044 class KJSProxyImpl : public KJSProxy {
00045 public:
00046 KJSProxyImpl(KHTMLPart *part);
00047 virtual ~KJSProxyImpl();
00048 virtual QVariant evaluate(QString filename, int baseLine, const QString&str, const DOM::Node &n);
00049 virtual void clear();
00050 virtual DOM::EventListener *createHTMLEventHandler(QString sourceUrl, QString code);
00051 virtual void finishedWithEvent(const DOM::Event &event);
00052 virtual KJS::ScriptInterpreter *interpreter();
00053
00054 virtual void setDebugEnabled(bool enabled);
00055 virtual bool paused() const;
00056 virtual void setSourceFile(QString url, QString code);
00057 virtual void appendSourceFile(QString url, QString code);
00058
00059 void initScript();
00060 void applyUserAgent();
00061
00062 private:
00063 KJS::ScriptInterpreter* m_script;
00064 bool m_debugEnabled;
00065 #ifndef NDEBUG
00066 static int s_count;
00067 #endif
00068 };
00069
00070 #ifndef NDEBUG
00071 int KJSProxyImpl::s_count = 0;
00072 #endif
00073
00074 KJSProxyImpl::KJSProxyImpl(KHTMLPart *part)
00075 {
00076 m_script = 0;
00077 m_part = part;
00078 m_debugEnabled = false;
00079 #ifndef NDEBUG
00080 s_count++;
00081 #endif
00082 }
00083
00084 KJSProxyImpl::~KJSProxyImpl()
00085 {
00086 if ( m_script ) {
00087
00088
00089 static_cast<ObjectImp*>(m_script->globalObject().imp())->deleteAllProperties( m_script->globalExec() );
00090
00091 while (KJS::Collector::collect())
00092 ;
00093
00094 delete m_script;
00095
00096
00097
00098
00099 while (KJS::Collector::collect())
00100 ;
00101 }
00102
00103 #ifndef NDEBUG
00104 s_count--;
00105
00106 #ifdef KJS_DEBUG_MEM
00107 if ( s_count == 0 )
00108 Interpreter::finalCheck();
00109 #endif
00110 #endif
00111 }
00112
00113 QVariant KJSProxyImpl::evaluate(QString filename, int baseLine,
00114 const QString&str, const DOM::Node &n) {
00115
00116
00117
00118 initScript();
00119
00120
00121
00122
00123 bool inlineCode = filename.isNull();
00124
00125
00126 #ifdef KJS_DEBUGGER
00127 if (inlineCode)
00128 filename = "(unknown file)";
00129 if (KJSDebugWin::instance()) {
00130 KJSDebugWin::instance()->attach(m_script);
00131 KJSDebugWin::instance()->setNextSourceInfo(filename,baseLine);
00132
00133 }
00134 #else
00135 Q_UNUSED(baseLine);
00136 #endif
00137
00138 m_script->setInlineCode(inlineCode);
00139 Window* window = Window::retrieveWindow( m_part );
00140 KJS::Value thisNode = n.isNull() ? Window::retrieve( m_part ) : getDOMNode(m_script->globalExec(),n);
00141
00142 UString code( str );
00143
00144 KJSCPUGuard guard;
00145 guard.start();
00146 Completion comp = m_script->evaluate(code, thisNode);
00147 guard.stop();
00148
00149 bool success = ( comp.complType() == Normal ) || ( comp.complType() == ReturnValue );
00150
00151 #ifdef KJS_DEBUGGER
00152
00153 #endif
00154
00155 window->afterScriptExecution();
00156
00157
00158 if (success && !comp.value().isNull())
00159 return ValueToVariant( m_script->globalExec(), comp.value());
00160 else
00161 {
00162 if ( comp.complType() == Throw )
00163 {
00164 UString msg = comp.value().toString(m_script->globalExec());
00165 kdWarning(6070) << "Script threw exception: " << msg.qstring() << endl;
00166 }
00167 return QVariant();
00168 }
00169 }
00170
00171
00172 class TestFunctionImp : public ObjectImp {
00173 public:
00174 TestFunctionImp() : ObjectImp() {}
00175 virtual bool implementsCall() const { return true; }
00176 virtual Value call(ExecState *exec, Object &thisObj, const List &args);
00177 };
00178
00179 Value TestFunctionImp::call(ExecState *exec, Object &, const List &args)
00180 {
00181 fprintf(stderr,"--> %s\n",args[0].toString(exec).ascii());
00182 return Undefined();
00183 }
00184
00185 void KJSProxyImpl::clear() {
00186
00187
00188
00189 if (m_script) {
00190 #ifdef KJS_DEBUGGER
00191
00192
00193
00194
00195
00196 #endif
00197 m_script->clear();
00198
00199 Window *win = static_cast<Window *>(m_script->globalObject().imp());
00200 if (win) {
00201 win->clear( m_script->globalExec() );
00202
00203 m_script->globalObject().put(m_script->globalExec(),
00204 "debug", Value(new TestFunctionImp()), Internal);
00205 if ( !win->part().isNull() )
00206 applyUserAgent();
00207 }
00208 }
00209 }
00210
00211 DOM::EventListener *KJSProxyImpl::createHTMLEventHandler(QString sourceUrl, QString code)
00212 {
00213 #ifdef KJS_DEBUGGER
00214 if (KJSDebugWin::instance())
00215 KJSDebugWin::instance()->setNextSourceInfo(sourceUrl,m_handlerLineno);
00216 #else
00217 Q_UNUSED(sourceUrl);
00218 #endif
00219
00220 initScript();
00221
00222 KJS::Object constr = m_script->builtinFunction();
00223 KJS::List args;
00224 args.append(KJS::String("event"));
00225 args.append(KJS::String(code));
00226 Object handlerFunc = constr.construct(m_script->globalExec(), args);
00227
00228 return KJS::Window::retrieveWindow(m_part)->getJSEventListener(handlerFunc,true);
00229 }
00230
00231 void KJSProxyImpl::finishedWithEvent(const DOM::Event &event)
00232 {
00233
00234
00235
00236
00237 m_script->forgetDOMObject(event.handle());
00238 }
00239
00240 KJS::ScriptInterpreter *KJSProxyImpl::interpreter()
00241 {
00242 if (!m_script)
00243 initScript();
00244 return m_script;
00245 }
00246
00247 void KJSProxyImpl::setDebugEnabled(bool enabled)
00248 {
00249 #ifdef KJS_DEBUGGER
00250 m_debugEnabled = enabled;
00251
00252
00253
00254
00255 if (!enabled && KJSDebugWin::instance()) {
00256 KJSDebugWin::destroyInstance();
00257 }
00258 else if (enabled && !KJSDebugWin::instance()) {
00259 KJSDebugWin::createInstance();
00260 initScript();
00261 KJSDebugWin::instance()->attach(m_script);
00262 }
00263 #else
00264 Q_UNUSED(enabled);
00265 #endif
00266 }
00267
00268 bool KJSProxyImpl::paused() const
00269 {
00270 #ifdef KJS_DEBUGGER
00271 if (KJSDebugWin::instance())
00272 return KJSDebugWin::instance()->inSession();
00273 #endif
00274 return false;
00275 }
00276
00277 void KJSProxyImpl::setSourceFile(QString url, QString code)
00278 {
00279 #ifdef KJS_DEBUGGER
00280 if (KJSDebugWin::instance())
00281 KJSDebugWin::instance()->setSourceFile(url,code);
00282 #else
00283 Q_UNUSED(url);
00284 Q_UNUSED(code);
00285 #endif
00286
00287 }
00288
00289 void KJSProxyImpl::appendSourceFile(QString url, QString code)
00290 {
00291 #ifdef KJS_DEBUGGER
00292 if (KJSDebugWin::instance())
00293 KJSDebugWin::instance()->appendSourceFile(url,code);
00294 #else
00295 Q_UNUSED(url);
00296 Q_UNUSED(code);
00297 #endif
00298 }
00299
00300 void KJSProxyImpl::initScript()
00301 {
00302 if (m_script)
00303 return;
00304
00305
00306 Object globalObject( new Window(m_part) );
00307
00308
00309 m_script = new KJS::ScriptInterpreter(globalObject, m_part);
00310 static_cast<ObjectImp*>(globalObject.imp())->setPrototype(m_script->builtinObjectPrototype());
00311
00312 #ifdef KJS_DEBUGGER
00313
00314 #endif
00315
00316 globalObject.put(m_script->globalExec(),
00317 "debug", Value(new TestFunctionImp()), Internal);
00318 applyUserAgent();
00319 }
00320
00321 void KJSProxyImpl::applyUserAgent()
00322 {
00323 assert( m_script );
00324 QString userAgent = KProtocolManager::userAgentForHost(m_part->url().host());
00325 if (userAgent.find(QString::fromLatin1("Microsoft")) >= 0 ||
00326 userAgent.find(QString::fromLatin1("MSIE")) >= 0)
00327 {
00328 m_script->setCompatMode(Interpreter::IECompat);
00329 #ifdef KJS_VERBOSE
00330 kdDebug() << "Setting IE compat mode" << endl;
00331 #endif
00332 }
00333 else
00334
00335 if (userAgent.find(QString::fromLatin1("Mozilla")) >= 0 &&
00336 userAgent.find(QString::fromLatin1("compatible")) == -1)
00337 {
00338 m_script->setCompatMode(Interpreter::NetscapeCompat);
00339 #ifdef KJS_VERBOSE
00340 kdDebug() << "Setting NS compat mode" << endl;
00341 #endif
00342 }
00343 }
00344
00345
00346
00347 KJSProxy * KJSProxy::proxy( KHTMLPart *part )
00348 {
00349 return part->jScript();
00350 }
00351
00352
00353 KJSProxy *kjs_html_init(KHTMLPart *khtmlpart)
00354 {
00355 return new KJSProxyImpl(khtmlpart);
00356 }
00357
00358 void KJSCPUGuard::start(unsigned int ms, unsigned int i_ms)
00359 {
00360 oldAlarmHandler = signal(SIGVTALRM, alarmHandler);
00361 itimerval tv = {
00362 { i_ms / 1000, (i_ms % 1000) * 1000 },
00363 { ms / 1000, (ms % 1000) * 1000 }
00364 };
00365 setitimer(ITIMER_VIRTUAL, &tv, &oldtv);
00366 }
00367
00368 void KJSCPUGuard::stop()
00369 {
00370 setitimer(ITIMER_VIRTUAL, &oldtv, 0L);
00371 signal(SIGVTALRM, oldAlarmHandler);
00372 }
00373
00374 void KJSCPUGuard::alarmHandler(int) {
00375 kdDebug(6070) << "alarmhandler" << endl;
00376 if (KMessageBox::warningYesNo(0L, i18n("A script on this page is causing KHTML to freeze. If it continues to run, other applications may become less responsive.\nDo you want to abort the script?"), i18n("JavaScript"), i18n("Abort"), KStdGuiItem::cont(), "kjscupguard_alarmhandler") == KMessageBox::Yes)
00377 ExecState::requestTerminate();
00378 }