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