2007-10-20 Rodney Dawes <dobey@wayofthemonkey.com>
[WebKit-https.git] / WebCore / bindings / js / kjs_proxy.cpp
1 /*
2  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
4  *  Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21 #include "config.h"
22 #include "kjs_proxy.h"
23
24 #include "Chrome.h"
25 #include "Document.h"
26 #include "Frame.h"
27 #include "FrameLoader.h"
28 #include "GCController.h"
29 #include "JSDocument.h"
30 #include "JSDOMWindow.h"
31 #include "Page.h"
32 #include "Settings.h"
33 #include "kjs_events.h"
34 #include "kjs_window.h"
35
36 #if ENABLE(SVG)
37 #include "JSSVGLazyEventListener.h"
38 #endif
39
40 using namespace KJS;
41
42 namespace WebCore {
43
44 KJSProxy::KJSProxy(Frame* frame)
45 {
46     m_frame = frame;
47     m_handlerLineno = 0;
48 }
49
50 KJSProxy::~KJSProxy()
51 {
52     // Check for <rdar://problem/4876466>. In theory, no JS should be executing
53     // in our interpreter. 
54     ASSERT(!m_script || !m_script->context());
55     
56     if (m_script) {
57         m_script = 0;
58     
59         // It's likely that destroying the interpreter has created a lot of garbage.
60         gcController().garbageCollectSoon();
61     }
62 }
63
64 JSValue* KJSProxy::evaluate(const String& filename, int baseLine, const String& str) 
65 {
66     // evaluate code. Returns the JS return value or 0
67     // if there was none, an error occured or the type couldn't be converted.
68
69     initScriptIfNeeded();
70     // inlineCode is true for <a href="javascript:doSomething()">
71     // and false for <script>doSomething()</script>. Check if it has the
72     // expected value in all cases.
73     // See smart window.open policy for where this is used.
74     bool inlineCode = filename.isNull();
75
76     m_script->setInlineCode(inlineCode);
77
78     JSLock lock;
79
80     // Evaluating the JavaScript could cause the frame to be deallocated
81     // so we start the keep alive timer here.
82     m_frame->keepAlive();
83     
84     JSValue* thisNode = KJS::Window::retrieve(m_frame);
85   
86     m_script->startTimeoutCheck();
87     Completion comp = m_script->evaluate(filename, baseLine, reinterpret_cast<const KJS::UChar*>(str.characters()), str.length(), thisNode);
88     m_script->stopTimeoutCheck();
89   
90     if (comp.complType() == Normal || comp.complType() == ReturnValue)
91         return comp.value();
92
93     if (comp.complType() == Throw) {
94         UString errorMessage = comp.value()->toString(m_script->globalExec());
95         int lineNumber = comp.value()->toObject(m_script->globalExec())->get(m_script->globalExec(), "line")->toInt32(m_script->globalExec());
96         UString sourceURL = comp.value()->toObject(m_script->globalExec())->get(m_script->globalExec(), "sourceURL")->toString(m_script->globalExec());
97         if (Page* page = m_frame->page())
98             page->chrome()->addMessageToConsole(JSMessageSource, ErrorMessageLevel, errorMessage, lineNumber, sourceURL);
99     }
100
101     return 0;
102 }
103
104 void KJSProxy::clear() {
105   // clear resources allocated by the interpreter, and make it ready to be used by another page
106   // We have to keep it, so that the KJS::Window object for the frame remains the same.
107   // (we used to delete and re-create it, previously)
108   if (m_script) {
109     KJS::Window *win = KJS::Window::retrieveWindow(m_frame);
110     if (win)
111         win->clear();
112   }
113 }
114
115 EventListener* KJSProxy::createHTMLEventHandler(const String& functionName, const String& code, Node* node)
116 {
117     initScriptIfNeeded();
118     JSLock lock;
119     return new JSLazyEventListener(functionName, code, KJS::Window::retrieveWindow(m_frame), node, m_handlerLineno);
120 }
121
122 #if ENABLE(SVG)
123 EventListener* KJSProxy::createSVGEventHandler(const String& functionName, const String& code, Node* node)
124 {
125     initScriptIfNeeded();
126     JSLock lock;
127     return new JSSVGLazyEventListener(functionName, code, KJS::Window::retrieveWindow(m_frame), node, m_handlerLineno);
128 }
129 #endif
130
131 void KJSProxy::finishedWithEvent(Event* event)
132 {
133   // This is called when the DOM implementation has finished with a particular event. This
134   // is the case in sitations where an event has been created just for temporary usage,
135   // e.g. an image load or mouse move. Once the event has been dispatched, it is forgotten
136   // by the DOM implementation and so does not need to be cached still by the interpreter
137   m_script->forgetDOMObject(event);
138 }
139
140 ScriptInterpreter* KJSProxy::interpreter()
141 {
142   initScriptIfNeeded();
143   ASSERT(m_script);
144   return m_script.get();
145 }
146
147 void KJSProxy::initScriptIfNeeded()
148 {
149   if (m_script)
150     return;
151
152   // Build the global object - which is a Window instance
153   JSLock lock;
154   JSObject* globalObject = new JSDOMWindow(m_frame->domWindow());
155
156   // Create a KJS interpreter for this frame
157   m_script = new ScriptInterpreter(globalObject, m_frame);
158
159   String userAgent = m_frame->loader()->userAgent(m_frame->document() ? m_frame->document()->URL() : KURL());
160   if (userAgent.find("Microsoft") >= 0 || userAgent.find("MSIE") >= 0)
161     m_script->setCompatMode(Interpreter::IECompat);
162   else
163     // If we find "Mozilla" but not "(compatible, ...)" we are a real Netscape
164     if (userAgent.find("Mozilla") >= 0 && userAgent.find("compatible") == -1)
165       m_script->setCompatMode(Interpreter::NetscapeCompat);
166
167   m_frame->loader()->dispatchWindowObjectAvailable();
168 }
169     
170 void KJSProxy::clearDocumentWrapper() 
171 {
172     if (!m_script)
173         return;
174
175     JSLock lock;
176     m_script->globalObject()->removeDirect("document");
177 }
178
179 }