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