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