Reviewed by Darin.
[WebKit-https.git] / WebCore / bindings / js / kjs_proxy.cpp
1 /*
2  *  This file is part of the KDE libraries
3  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
4  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation; either
9  *  version 2 of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "kjs_proxy.h"
23
24 #include "kjs_events.h"
25 #include "kjs_window.h"
26 #include "Frame.h"
27 #include "JSDOMWindow.h"
28
29 #if SVG_SUPPORT
30 #include "JSSVGLazyEventListener.h"
31 #endif
32
33 using namespace KJS;
34
35 namespace WebCore {
36
37 KJSProxy::KJSProxy(Frame* frame)
38 {
39     m_script = 0;
40     m_frame = frame;
41     m_handlerLineno = 0;
42 }
43
44 KJSProxy::~KJSProxy()
45 {
46     JSLock lock;
47     delete m_script;
48     Collector::collect();
49 }
50
51 JSValue* KJSProxy::evaluate(const String& filename, int baseLine, const String& str, Node* n) 
52 {
53   // evaluate code. Returns the JS return value or 0
54   // if there was none, an error occured or the type couldn't be converted.
55
56   initScriptIfNeeded();
57   // inlineCode is true for <a href="javascript:doSomething()">
58   // and false for <script>doSomething()</script>. Check if it has the
59   // expected value in all cases.
60   // See smart window.open policy for where this is used.
61   bool inlineCode = filename.isNull();
62
63   m_script->setInlineCode(inlineCode);
64
65   JSLock lock;
66
67   JSValue* thisNode = n ? Window::retrieve(m_frame) : toJS(m_script->globalExec(), n);
68   
69   m_script->startTimeoutCheck();
70   Completion comp = m_script->evaluate(filename, baseLine, reinterpret_cast<const KJS::UChar*>(str.characters()), str.length(), thisNode);
71   m_script->stopTimeoutCheck();
72   
73   if (comp.complType() == Normal || comp.complType() == ReturnValue)
74     return comp.value();
75
76   if (comp.complType() == Throw) {
77     UString errorMessage = comp.value()->toString(m_script->globalExec());
78     int lineNumber = comp.value()->toObject(m_script->globalExec())->get(m_script->globalExec(), "line")->toInt32(m_script->globalExec());
79     UString sourceURL = comp.value()->toObject(m_script->globalExec())->get(m_script->globalExec(), "sourceURL")->toString(m_script->globalExec());
80     m_frame->addMessageToConsole(errorMessage, lineNumber, sourceURL);
81   }
82
83   return 0;
84 }
85
86 void KJSProxy::clear() {
87   // clear resources allocated by the interpreter, and make it ready to be used by another page
88   // We have to keep it, so that the Window object for the frame remains the same.
89   // (we used to delete and re-create it, previously)
90   if (m_script) {
91     Window *win = Window::retrieveWindow(m_frame);
92     if (win)
93         win->clear();
94   }
95 }
96
97 EventListener* KJSProxy::createHTMLEventHandler(const String& functionName, const String& code, Node* node)
98 {
99     initScriptIfNeeded();
100     JSLock lock;
101     return new JSLazyEventListener(functionName, code, Window::retrieveWindow(m_frame), node, m_handlerLineno);
102 }
103
104 #if SVG_SUPPORT
105 EventListener* KJSProxy::createSVGEventHandler(const String& functionName, const String& code, Node* node)
106 {
107     initScriptIfNeeded();
108     JSLock lock;
109     return new JSSVGLazyEventListener(functionName, code, Window::retrieveWindow(m_frame), node, m_handlerLineno);
110 }
111 #endif
112
113 void KJSProxy::finishedWithEvent(Event* event)
114 {
115   // This is called when the DOM implementation has finished with a particular event. This
116   // is the case in sitations where an event has been created just for temporary usage,
117   // e.g. an image load or mouse move. Once the event has been dispatched, it is forgotten
118   // by the DOM implementation and so does not need to be cached still by the interpreter
119   m_script->forgetDOMObject(event);
120 }
121
122 ScriptInterpreter* KJSProxy::interpreter()
123 {
124   initScriptIfNeeded();
125   assert(m_script);
126   return m_script;
127 }
128
129 void KJSProxy::initScriptIfNeeded()
130 {
131   if (m_script)
132     return;
133
134   // Build the global object - which is a Window instance
135   JSLock lock;
136   JSObject* globalObject = new JSDOMWindow(m_frame->domWindow());
137
138   // Create a KJS interpreter for this frame
139   m_script = new ScriptInterpreter(globalObject, m_frame);
140
141   String userAgent = m_frame->userAgent();
142   if (userAgent.find("Microsoft") >= 0 || userAgent.find("MSIE") >= 0)
143     m_script->setCompatMode(Interpreter::IECompat);
144   else
145     // If we find "Mozilla" but not "(compatible, ...)" we are a real Netscape
146     if (userAgent.find("Mozilla") >= 0 && userAgent.find("compatible") == -1)
147       m_script->setCompatMode(Interpreter::NetscapeCompat);
148 }
149
150 }