bb11460b522ae2694ad7b087b6921bc6bd686862
[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_windowShell->setWindow(new JSDOMWindow(m_frame->domWindow(), m_windowShell));
116     if (Page* page = m_frame->page()) {
117         attachDebugger(page->debugger());
118         m_windowShell->window()->setPageGroupIdentifier(page->group().identifier());
119     }
120
121     // There is likely to be a lot of garbage now.
122     gcController().garbageCollectSoon();
123 }
124
125 EventListener* KJSProxy::createHTMLEventHandler(const String& functionName, const String& code, Node* node)
126 {
127     initScriptIfNeeded();
128     JSLock lock;
129     return new JSLazyEventListener(functionName, code, m_windowShell->window(), node, m_handlerLineno);
130 }
131
132 #if ENABLE(SVG)
133 EventListener* KJSProxy::createSVGEventHandler(const String& functionName, const String& code, Node* node)
134 {
135     initScriptIfNeeded();
136     JSLock lock;
137     return new JSSVGLazyEventListener(functionName, code, m_windowShell->window(), node, m_handlerLineno);
138 }
139 #endif
140
141 void KJSProxy::finishedWithEvent(Event* event)
142 {
143   // This is called when the DOM implementation has finished with a particular event. This
144   // is the case in sitations where an event has been created just for temporary usage,
145   // e.g. an image load or mouse move. Once the event has been dispatched, it is forgotten
146   // by the DOM implementation and so does not need to be cached still by the interpreter
147   ScriptInterpreter::forgetDOMObject(event);
148 }
149
150 void KJSProxy::initScript()
151 {
152     if (m_windowShell)
153         return;
154
155     JSLock lock;
156
157     m_windowShell = new JSDOMWindowShell(m_frame->domWindow());
158     m_windowShell->updateDocument();
159
160     if (Page* page = m_frame->page()) {
161         attachDebugger(page->debugger());
162         m_windowShell->window()->setPageGroupIdentifier(page->group().identifier());
163     }
164
165     m_frame->loader()->dispatchWindowObjectAvailable();
166 }
167
168 bool KJSProxy::processingUserGesture() const
169 {
170     if (!m_windowShell)
171         return false;
172
173     if (Event* event = m_windowShell->window()->currentEvent()) {
174         const AtomicString& type = event->type();
175         if ( // mouse events
176             type == clickEvent || type == mousedownEvent ||
177             type == mouseupEvent || type == dblclickEvent ||
178             // keyboard events
179             type == keydownEvent || type == keypressEvent ||
180             type == keyupEvent ||
181             // other accepted events
182             type == selectEvent || type == changeEvent ||
183             type == focusEvent || type == blurEvent ||
184             type == submitEvent)
185             return true;
186     } else { // no event
187         if (m_processingInlineCode && !m_processingTimerCallback) {
188             // This is the <a href="javascript:window.open('...')> case -> we let it through
189             return true;
190         }
191         // This is the <script>window.open(...)</script> case or a timer callback -> block it
192     }
193     return false;
194 }
195
196 bool KJSProxy::isEnabled()
197 {
198     Settings* settings = m_frame->settings();
199     return (settings && settings->isJavaScriptEnabled());
200 }
201
202 void KJSProxy::attachDebugger(KJS::Debugger* debugger)
203 {
204     if (!m_windowShell)
205         return;
206
207     if (debugger)
208         debugger->attach(m_windowShell->window());
209     else if (KJS::Debugger* currentDebugger = m_windowShell->window()->debugger())
210         currentDebugger->detach(m_windowShell->window());
211 }
212
213 } // namespace WebCore