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
00242 KJS::Object constr = m_script->builtinFunction();
00243 KJS::List args;
00244 args.append(KJS::String(
"event"));
00245 args.append(KJS::String(code));
00246
00247 Object handlerFunc = constr.construct(m_script->globalExec(), args);
00248
if (m_script->globalExec()->hadException())
00249 m_script->globalExec()->clearException();
00250
00251
if (!handlerFunc.inherits(&DeclaredFunctionImp::info))
00252
return 0;
00253
00254 DeclaredFunctionImp *declFunc = static_cast<DeclaredFunctionImp*>(handlerFunc.imp());
00255 declFunc->setName(Identifier(name));
00256
return KJS::Window::retrieveWindow(m_part)->getJSEventListener(handlerFunc,
true);
00257 }
00258
00259
void KJSProxyImpl::finishedWithEvent(
const DOM::Event &event)
00260 {
00261
00262
00263
00264
00265
ScriptInterpreter::forgetDOMObject(
event.handle());
00266 }
00267
00268 KJS::Interpreter *KJSProxyImpl::interpreter()
00269 {
00270
if (!m_script)
00271 initScript();
00272
return m_script;
00273 }
00274
00275
void KJSProxyImpl::setDebugEnabled(
bool enabled)
00276 {
00277
#ifdef KJS_DEBUGGER
00278
m_debugEnabled = enabled;
00279
00280
00281
00282
00283
if (!enabled && KJSDebugWin::debugWindow()) {
00284 KJSDebugWin::destroyInstance();
00285 }
00286
else if (enabled && !KJSDebugWin::debugWindow()) {
00287 KJSDebugWin::createInstance();
00288 initScript();
00289 KJSDebugWin::debugWindow()->attach(m_script);
00290 }
00291
#else
00292
Q_UNUSED(enabled);
00293
#endif
00294
}
00295
00296
void KJSProxyImpl::showDebugWindow(
bool )
00297 {
00298
#ifdef KJS_DEBUGGER
00299
if (KJSDebugWin::debugWindow())
00300 KJSDebugWin::debugWindow()->show();
00301
#else
00302
00303
#endif
00304
}
00305
00306
bool KJSProxyImpl::paused()
const
00307
{
00308
#ifdef KJS_DEBUGGER
00309
if (KJSDebugWin::debugWindow())
00310
return KJSDebugWin::debugWindow()->inSession();
00311
#endif
00312
return false;
00313 }
00314
00315
void KJSProxyImpl::dataReceived()
00316 {
00317
#ifdef KJS_DEBUGGER
00318
if (KJSDebugWin::debugWindow())
00319 KJSDebugWin::debugWindow()->sourceChanged(m_script,m_part->
url().
url());
00320
#endif
00321
}
00322
00323
void KJSProxyImpl::initScript()
00324 {
00325
if (m_script)
00326
return;
00327
00328
00329 Object globalObject(
new Window(m_part) );
00330
00331
00332 m_script =
new KJS::ScriptInterpreter(globalObject, m_part);
00333 static_cast<ObjectImp*>(globalObject.imp())->setPrototype(m_script->builtinObjectPrototype());
00334
00335
#ifdef KJS_DEBUGGER
00336
00337
#endif
00338
00339 globalObject.put(m_script->globalExec(),
00340
"debug", Value(
new TestFunctionImp()), Internal);
00341 applyUserAgent();
00342 }
00343
00344
void KJSProxyImpl::applyUserAgent()
00345 {
00346 assert( m_script );
00347
QString host = m_part->
url().
isLocalFile() ?
"localhost" : m_part->
url().
host();
00348
QString userAgent =
KProtocolManager::userAgentForHost(host);
00349
if (userAgent.
find(QString::fromLatin1(
"Microsoft")) >= 0 ||
00350 userAgent.
find(QString::fromLatin1(
"MSIE")) >= 0)
00351 {
00352 m_script->setCompatMode(Interpreter::IECompat);
00353
#ifdef KJS_VERBOSE
00354
kdDebug() <<
"Setting IE compat mode" <<
endl;
00355
#endif
00356
}
00357
else
00358
00359
if (userAgent.
find(QString::fromLatin1(
"Mozilla")) >= 0 &&
00360 userAgent.
find(QString::fromLatin1(
"compatible")) == -1)
00361 {
00362 m_script->setCompatMode(Interpreter::NetscapeCompat);
00363
#ifdef KJS_VERBOSE
00364
kdDebug() <<
"Setting NS compat mode" <<
endl;
00365
#endif
00366
}
00367 }
00368
00369
00370 KJSProxy *kjs_html_init(
KHTMLPart *khtmlpart)
00371 {
00372
return new KJSProxyImpl(khtmlpart);
00373 }
00374
00375
void KJSCPUGuard::start(
unsigned int ms,
unsigned int i_ms)
00376 {
00377 oldAlarmHandler = signal(SIGVTALRM, alarmHandler);
00378 itimerval tv = {
00379 { i_ms / 1000, (i_ms % 1000) * 1000 },
00380 { ms / 1000, (ms % 1000) * 1000 }
00381 };
00382 setitimer(ITIMER_VIRTUAL, &tv, &oldtv);
00383 }
00384
00385
void KJSCPUGuard::stop()
00386 {
00387 setitimer(ITIMER_VIRTUAL, &oldtv, 0L);
00388 signal(SIGVTALRM, oldAlarmHandler);
00389 }
00390
00391
bool KJSCPUGuard::confirmTerminate() {
00392
kdDebug(6070) <<
"alarmhandler" <<
endl;
00393
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;
00394 }
00395
00396
void KJSCPUGuard::alarmHandler(
int) {
00397 ExecState::requestTerminate();
00398 ExecState::confirmTerminate = KJSCPUGuard::confirmTerminate;
00399 }