ba098b133dc23d4919f8c16c6586cc0cf05ee3a4
[WebKit.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, 2008 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 "Console.h"
25 #include "DOMWindow.h"
26 #include "Document.h"
27 #include "Event.h"
28 #include "EventNames.h"
29 #include "Frame.h"
30 #include "FrameLoader.h"
31 #include "GCController.h"
32 #include "JSDocument.h"
33 #include "JSDOMWindow.h"
34 #include "Page.h"
35 #include "PageGroup.h"
36 #include "Settings.h"
37 #include "StringSourceProvider.h"
38 #include "kjs_events.h"
39 #include <kjs/debugger.h>
40
41 #if ENABLE(SVG)
42 #include "JSSVGLazyEventListener.h"
43 #endif
44
45 using namespace KJS;
46 using namespace WebCore::EventNames;
47
48 namespace WebCore {
49
50 KJSProxy::KJSProxy(Frame* frame)
51     : m_frame(frame)
52     , m_handlerLineno(0)
53     , m_processingTimerCallback(0)
54     , m_processingInlineCode(0)
55     , m_paused(false)
56 {
57 }
58
59 KJSProxy::~KJSProxy()
60 {
61     if (m_windowShell) {
62         m_windowShell = 0;
63     
64         // It's likely that releasing the global object has created a lot of garbage.
65         gcController().garbageCollectSoon();
66     }
67 }
68
69 JSValue* KJSProxy::evaluate(const String& filename, int baseLine, const String& str) 
70 {
71     // evaluate code. Returns the JS return value or 0
72     // if there was none, an error occured or the type couldn't be converted.
73
74     initScriptIfNeeded();
75     // inlineCode is true for <a href="javascript:doSomething()">
76     // and false for <script>doSomething()</script>. Check if it has the
77     // expected value in all cases.
78     // See smart window.open policy for where this is used.
79     ExecState* exec = m_windowShell->window()->globalExec();
80     m_processingInlineCode = filename.isNull();
81
82     JSLock lock;
83
84     // Evaluating the JavaScript could cause the frame to be deallocated
85     // so we start the keep alive timer here.
86     m_frame->keepAlive();
87
88     m_windowShell->window()->startTimeoutCheck();
89     Completion comp = Interpreter::evaluate(exec, exec->dynamicGlobalObject()->globalScopeChain(), filename, baseLine, StringSourceProvider::create(str), m_windowShell);
90     m_windowShell->window()->stopTimeoutCheck();
91
92     if (comp.complType() == Normal || comp.complType() == ReturnValue) {
93         m_processingInlineCode = false;
94         return comp.value();
95     }
96
97     if (comp.complType() == Throw) {
98         UString errorMessage = comp.value()->toString(exec);
99         int lineNumber = comp.value()->toObject(exec)->get(exec, "line")->toInt32(exec);
100         UString sourceURL = comp.value()->toObject(exec)->get(exec, "sourceURL")->toString(exec);
101         m_frame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, errorMessage, lineNumber, sourceURL);
102     }
103
104     m_processingInlineCode = false;
105     return 0;
106 }
107
108 void KJSProxy::clear()
109 {
110     if (!m_windowShell)
111         return;
112
113     JSLock lock;
114     m_windowShell->window()->clear();
115     m_liveFormerWindows.add(m_windowShell->window());
116     m_windowShell->setWindow(new JSDOMWindow(m_frame->domWindow(), m_windowShell));
117     if (Page* page = m_frame->page()) {
118         attachDebugger(page->debugger());
119         m_windowShell->window()->setPageGroupIdentifier(page->group().identifier());
120     }
121
122     // There is likely to be a lot of garbage now.
123     gcController().garbageCollectSoon();
124 }
125
126 EventListener* KJSProxy::createHTMLEventHandler(const String& functionName, const String& code, Node* node)
127 {
128     initScriptIfNeeded();
129     JSLock lock;
130     return new JSLazyEventListener(functionName, code, m_windowShell->window(), node, m_handlerLineno);
131 }
132
133 #if ENABLE(SVG)
134 EventListener* KJSProxy::createSVGEventHandler(const String& functionName, const String& code, Node* node)
135 {
136     initScriptIfNeeded();
137     JSLock lock;
138     return new JSSVGLazyEventListener(functionName, code, m_windowShell->window(), node, m_handlerLineno);
139 }
140 #endif
141
142 void KJSProxy::finishedWithEvent(Event* event)
143 {
144   // This is called when the DOM implementation has finished with a particular event. This
145   // is the case in sitations where an event has been created just for temporary usage,
146   // e.g. an image load or mouse move. Once the event has been dispatched, it is forgotten
147   // by the DOM implementation and so does not need to be cached still by the interpreter
148   ScriptInterpreter::forgetDOMObject(event);
149 }
150
151 void KJSProxy::initScript()
152 {
153     if (m_windowShell)
154         return;
155
156     JSLock lock;
157
158     m_windowShell = new JSDOMWindowShell(m_frame->domWindow());
159     updateDocument();
160
161     if (Page* page = m_frame->page()) {
162         attachDebugger(page->debugger());
163         m_windowShell->window()->setPageGroupIdentifier(page->group().identifier());
164     }
165
166     m_frame->loader()->dispatchWindowObjectAvailable();
167 }
168
169 bool KJSProxy::processingUserGesture() const
170 {
171     if (!m_windowShell)
172         return false;
173
174     if (Event* event = m_windowShell->window()->currentEvent()) {
175         const AtomicString& type = event->type();
176         if ( // mouse events
177             type == clickEvent || type == mousedownEvent ||
178             type == mouseupEvent || type == dblclickEvent ||
179             // keyboard events
180             type == keydownEvent || type == keypressEvent ||
181             type == keyupEvent ||
182             // other accepted events
183             type == selectEvent || type == changeEvent ||
184             type == focusEvent || type == blurEvent ||
185             type == submitEvent)
186             return true;
187     } else { // no event
188         if (m_processingInlineCode && !m_processingTimerCallback) {
189             // This is the <a href="javascript:window.open('...')> case -> we let it through
190             return true;
191         }
192         // This is the <script>window.open(...)</script> case or a timer callback -> block it
193     }
194     return false;
195 }
196
197 bool KJSProxy::isEnabled()
198 {
199     Settings* settings = m_frame->settings();
200     return (settings && settings->isJavaScriptEnabled());
201 }
202
203 void KJSProxy::attachDebugger(KJS::Debugger* debugger)
204 {
205     if (!m_windowShell)
206         return;
207
208     if (debugger)
209         debugger->attach(m_windowShell->window());
210     else if (KJS::Debugger* currentDebugger = m_windowShell->window()->debugger())
211         currentDebugger->detach(m_windowShell->window());
212 }
213
214 void KJSProxy::updateDocument()
215 {
216     JSLock lock;
217     if (m_windowShell)
218         m_windowShell->window()->updateDocument();
219     HashSet<JSDOMWindow*>::iterator end = m_liveFormerWindows.end();
220     for (HashSet<JSDOMWindow*>::iterator it = m_liveFormerWindows.begin(); it != end; ++it)
221         (*it)->updateDocument();
222 }
223
224
225 } // namespace WebCore