1 // -*- c-basic-offset: 2 -*-
3 * This file is part of the KDE libraries
4 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
5 * Copyright (C) 2001,2003 Peter Kelly (pmk@post.com)
6 * Copyright (C) 2001-2003 David Faure (faure@kde.org)
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #include "kjs_proxy.h"
27 #include "kjs_window.h"
28 #include "kjs_events.h"
29 //#include "kjs_debugwin.h"
30 #include "debugger/debugwindow.h"
31 #include <xml/dom_nodeimpl.h>
32 #include <khtmlpart_p.h>
33 #include <khtml_part.h>
34 #include <kprotocolmanager.h>
39 #include <kjs/function.h>
40 #include <kjs/JSLock.h>
43 using namespace KJSDebugger
;
46 KJSProxy
*kjs_html_init(khtml::ChildFrame
*childframe
);
51 class KJSProxyImpl
: public KJSProxy
{
53 KJSProxyImpl(khtml::ChildFrame
*frame
);
54 virtual ~KJSProxyImpl();
55 virtual QVariant
evaluate(QString filename
, int baseLine
, const QString
&, const DOM::Node
&n
,
56 Completion
*completion
= 0);
58 virtual DOM::EventListener
*createHTMLEventHandler(QString sourceUrl
, QString name
, QString code
, DOM::NodeImpl
*node
, bool svg
= false);
59 virtual void finishedWithEvent(const DOM::Event
&event
);
60 virtual KJS::Interpreter
*interpreter();
62 virtual void setDebugEnabled(bool enabled
);
63 virtual bool debugEnabled() const;
64 virtual void showDebugWindow(bool show
=true);
65 virtual bool paused() const;
66 virtual void dataReceived();
69 void applyUserAgent();
71 KJS::ScriptInterpreter
* m_script
;
72 WTF::RefPtr
<DebugWindow
> m_debugWindow
;
82 int KJSProxyImpl::s_count
= 0;
85 KJSProxyImpl::KJSProxyImpl(khtml::ChildFrame
*frame
)
89 m_debugEnabled
= false;
95 KJSProxyImpl::~KJSProxyImpl()
98 //kDebug() << "KJSProxyImpl::~KJSProxyImpl clearing global object " << m_script->globalObject().imp();
99 // This allows to delete the global-object properties, like all the protos
100 m_script
->globalObject()->clearProperties();
101 //kDebug() << "KJSProxyImpl::~KJSProxyImpl garbage collecting";
104 while (Interpreter::collect())
107 //kDebug() << "KJSProxyImpl::~KJSProxyImpl deleting interpreter " << m_script;
109 //kDebug() << "KJSProxyImpl::~KJSProxyImpl garbage collecting again";
110 // Garbage collect - as many times as necessary
111 // (we could delete an object which was holding another object, so
112 // the deref() will happen too late for deleting the impl of the 2nd object).
114 while (Interpreter::collect())
121 // If it was the last interpreter, we should have nothing left
124 Interpreter::finalCheck();
129 QVariant
KJSProxyImpl::evaluate(QString filename
, int baseLine
,
130 const QString
&str
, const DOM::Node
&n
, Completion
*completion
) {
131 // evaluate code. Returns the JS return value or an invalid QVariant
132 // if there was none, an error occurred or the type couldn't be converted.
135 // inlineCode is true for <a href="javascript:doSomething()">
136 // and false for <script>doSomething()</script>. Check if it has the
137 // expected value in all cases.
138 // See smart window.open policy for where this is used.
139 bool inlineCode
= filename
.isNull();
140 //kDebug(6070) << "KJSProxyImpl::evaluate inlineCode=" << inlineCode;
144 filename
= "(unknown file)";
146 m_debugWindow
->attach(m_script
);
151 m_script
->setInlineCode(inlineCode
);
152 Window
* window
= Window::retrieveWindow( m_frame
->m_part
);
153 KJS::JSValue
*thisNode
= n
.isNull() ? Window::retrieve( m_frame
->m_part
) : getDOMNode(m_script
->globalExec(),n
.handle());
157 m_script
->startCPUGuard();
158 Completion comp
= m_script
->evaluate(filename
, baseLine
, code
, thisNode
);
159 m_script
->stopCPUGuard();
161 bool success
= ( comp
.complType() == Normal
) || ( comp
.complType() == ReturnValue
);
167 // KJSDebugWin::debugWindow()->setCode(QString());
170 window
->afterScriptExecution();
172 // let's try to convert the return value
173 if (success
&& comp
.value())
174 return ValueToVariant( m_script
->globalExec(), comp
.value());
177 if ( comp
.complType() == Throw
)
179 UString msg
= comp
.value()->toString(m_script
->globalExec());
180 kDebug(6070) << "WARNING: Script threw exception: " << msg
.qstring();
186 // Implementation of the debug() function
187 class TestFunctionImp
: public JSObject
{
189 TestFunctionImp() : JSObject() {}
190 virtual bool implementsCall() const { return true; }
191 virtual JSValue
*callAsFunction(ExecState
*exec
, JSObject
*thisObj
, const List
&args
);
194 JSValue
*TestFunctionImp::callAsFunction(ExecState
*exec
, JSObject
* /*thisObj*/, const List
&args
)
196 fprintf(stderr
,"--> %s\n",args
[0]->toString(exec
).ascii());
197 return jsUndefined();
200 void KJSProxyImpl::clear() {
201 // clear resources allocated by the interpreter, and make it ready to be used by another page
202 // We have to keep it, so that the Window object for the part remains the same.
203 // (we used to delete and re-create it, previously)
207 m_debugWindow
->clearInterpreter(m_script
);
211 Window
*win
= static_cast<Window
*>(m_script
->globalObject());
213 win
->clear( m_script
->globalExec() );
214 // re-add "debug", clear() removed it
215 m_script
->globalObject()->put(m_script
->globalExec(),
216 "debug", new TestFunctionImp(), Internal
);
221 // Really delete everything that can be, so that the DOM nodes get deref'ed
222 //kDebug() << "all done -> collecting";
224 while (Interpreter::collect())
230 // Detach from debugging entirely if it's been turned off.
231 if (m_debugWindow
&& !m_debugEnabled
) {
232 m_debugWindow
->detach(m_script
);
238 DOM::EventListener
*KJSProxyImpl::createHTMLEventHandler(QString sourceUrl
, QString name
, QString code
, DOM::NodeImpl
*node
, bool svg
)
244 m_debugWindow
->attach(m_script
);
249 return KJS::Window::retrieveWindow(m_frame
->m_part
)->getJSLazyEventListener(
250 code
, sourceUrl
, m_handlerLineno
, name
, node
, svg
);
253 void KJSProxyImpl::finishedWithEvent(const DOM::Event
&event
)
255 // This is called when the DOM implementation has finished with a particular event. This
256 // is the case in sitations where an event has been created just for temporary usage,
257 // e.g. an image load or mouse move. Once the event has been dispatched, it is forgotten
258 // by the DOM implementation and so does not need to be cached still by the interpreter
259 ScriptInterpreter::forgetDOMObject(event
.handle());
262 KJS::Interpreter
*KJSProxyImpl::interpreter()
269 void KJSProxyImpl::setDebugEnabled(bool enabled
)
272 m_debugEnabled
= enabled
;
274 // Note that we attach to the debugger only before
275 // running a script. Detaches/disabling are done between
276 // documents, at clear. Both are done so the debugger
277 // see the entire session
279 m_debugWindow
= DebugWindow::window();
283 bool KJSProxyImpl::debugEnabled() const
286 return m_debugEnabled
;
292 void KJSProxyImpl::showDebugWindow(bool /*show*/)
296 m_debugWindow
->show();
302 bool KJSProxyImpl::paused() const
305 // if (DebugWindow::window())
306 // return DebugWindow::window()->inSession();
311 void KJSProxyImpl::dataReceived()
314 // if (DebugWindow::window() && m_frame->m_part)
315 // DebugWindow::window()->sourceChanged(m_script, m_frame->m_part->url().url());
321 void KJSProxyImpl::initScript()
326 // Build the global object - which is a Window instance
327 JSGlobalObject
*globalObject( new Window(m_frame
) );
329 // Create a KJS interpreter for this part
330 m_script
= new KJS::ScriptInterpreter(globalObject
, m_frame
);
332 globalObject
->setPrototype(m_script
->builtinObjectPrototype());
335 //m_script->setDebuggingEnabled(m_debugEnabled);
337 //m_script->enableDebug();
338 globalObject
->put(m_script
->globalExec(),
339 "debug", new TestFunctionImp(), Internal
);
343 void KJSProxyImpl::applyUserAgent()
346 QString host
= m_frame
->m_part
->url().isLocalFile() ? "localhost" : m_frame
->m_part
->url().host();
347 QString userAgent
= KProtocolManager::userAgentForHost(host
);
348 if (userAgent
.indexOf(QLatin1String("Microsoft"), 0, Qt::CaseSensitive
) >= 0 ||
349 userAgent
.indexOf(QLatin1String("MSIE"), 0, Qt::CaseSensitive
) >= 0)
351 m_script
->setCompatMode(Interpreter::IECompat
);
353 kDebug() << "Setting IE compat mode";
357 // If we find "Mozilla" but not "(compatible, ...)" we are a real Netscape
358 if (userAgent
.indexOf(QLatin1String("Mozilla"), 0, Qt::CaseSensitive
) >= 0 &&
359 userAgent
.indexOf(QLatin1String("compatible"), 0, Qt::CaseSensitive
) == -1 &&
360 userAgent
.indexOf(QLatin1String("KHTML"), 0, Qt::CaseSensitive
) == -1)
362 m_script
->setCompatMode(Interpreter::NetscapeCompat
);
364 kDebug() << "Setting NS compat mode";
369 // Helper method, so that all classes which need jScript() don't need to be added
370 // as friend to KHTMLPart
371 KJSProxy
* KJSProxy::proxy( KHTMLPart
*part
)
373 return part
->jScript();
376 // initialize HTML module
377 KJSProxy
*kjs_html_init(khtml::ChildFrame
*childframe
)
379 return new KJSProxyImpl(childframe
);