0bdf3419d63c71386e221f4f373f819c9e5284e0
[WebKit-https.git] / WebKit / win / WebScriptCallFrame.cpp
1 /*
2  * Copyright (C) 2007 Apple Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "WebKitDLL.h"
31 #include "WebScriptCallFrame.h"
32
33 #include "Identifier.h"
34 #include "IWebScriptScope.h"
35 #include "Function.h"
36 #include "WebScriptScope.h"
37
38 #include <JavaScriptCore/JSGlobalObject.h>
39 #include <JavaScriptCore/JSStringRefBSTR.h>
40 #include <JavaScriptCore/JSValueRef.h>
41
42 #pragma warning(push, 0)
43 #include <WebCore/BString.h>
44 #include <WebCore/PlatformString.h>
45 #pragma warning(pop)
46
47 #include <wtf/Assertions.h>
48
49 using namespace KJS;
50
51 // EnumScopes -----------------------------------------------------------------
52
53 class EnumScopes : public IEnumVARIANT {
54 public:
55     static EnumScopes* createInstance(ScopeChain chain);
56
57 private:
58     EnumScopes(ScopeChain chain)
59         : m_refCount(0)
60         , m_chain(chain)
61         , m_current(chain.begin())
62     {
63     }
64
65 public:
66     virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, void** ppvObject);
67     virtual ULONG STDMETHODCALLTYPE AddRef();
68     virtual ULONG STDMETHODCALLTYPE Release();
69     virtual HRESULT STDMETHODCALLTYPE Next(ULONG celt, VARIANT* rgVar, ULONG* pCeltFetched);
70     virtual HRESULT STDMETHODCALLTYPE Skip(ULONG celt);
71     virtual HRESULT STDMETHODCALLTYPE Reset(void);
72     virtual HRESULT STDMETHODCALLTYPE Clone(IEnumVARIANT**);
73
74 private:
75     ULONG m_refCount;
76     ScopeChain m_chain;
77     ScopeChainIterator m_current;
78 };
79
80 EnumScopes* EnumScopes::createInstance(ScopeChain chain)
81 {
82     EnumScopes* instance = new EnumScopes(chain);
83     instance->AddRef();
84     return instance;
85 }
86
87 HRESULT STDMETHODCALLTYPE EnumScopes::QueryInterface(REFIID riid, void** ppvObject)
88 {
89     *ppvObject = 0;
90     if (IsEqualGUID(riid, IID_IUnknown) || IsEqualGUID(riid, IID_IEnumVARIANT))
91         *ppvObject = this;
92     else
93         return E_NOINTERFACE;
94
95     AddRef();
96     return S_OK;
97 }
98
99 ULONG STDMETHODCALLTYPE EnumScopes::AddRef()
100 {
101     return ++m_refCount;
102 }
103
104 ULONG STDMETHODCALLTYPE EnumScopes::Release()
105 {
106     ULONG newRef = --m_refCount;
107     if (!newRef)
108         delete(this);
109     return newRef;
110 }
111
112 HRESULT STDMETHODCALLTYPE EnumScopes::Next(ULONG celt, VARIANT* rgVar, ULONG* pCeltFetched)
113 {
114     if (pCeltFetched)
115         *pCeltFetched = 0;
116     if (!rgVar)
117         return E_POINTER;
118     VariantInit(rgVar);
119     if (!celt || celt > 1)
120         return S_FALSE;
121     if (m_current == m_chain.end())
122         return S_FALSE;
123
124     // Create a WebScriptScope from the m_current then put it in an IUnknown.
125     COMPtr<IWebScriptScope> scope = WebScriptScope::createInstance(*m_current);
126     COMPtr<IUnknown> unknown = static_cast<IUnknown*>(scope.get());
127     ++m_current;
128     if (!unknown)
129         return E_FAIL;
130
131     V_VT(rgVar) = VT_UNKNOWN;
132     V_UNKNOWN(rgVar) = unknown.get();
133
134     if (pCeltFetched)
135         *pCeltFetched = 1;
136     return S_OK;
137 }
138
139 HRESULT STDMETHODCALLTYPE EnumScopes::Skip(ULONG celt)
140 {
141     for (ULONG i = 0; i < celt; ++i)
142         ++m_current;
143     return (m_current != m_chain.end()) ? S_OK : S_FALSE;
144 }
145
146 HRESULT STDMETHODCALLTYPE EnumScopes::Reset(void)
147 {
148     m_current = m_chain.begin();
149     return S_OK;
150 }
151
152 HRESULT STDMETHODCALLTYPE EnumScopes::Clone(IEnumVARIANT**)
153 {
154     return E_NOTIMPL;
155 }
156
157 // WebScriptCallFrame -----------------------------------------------------------
158
159 WebScriptCallFrame::WebScriptCallFrame(ExecState* state, IWebScriptCallFrame* caller)
160     : m_refCount(0)
161 {
162     m_state = state;
163     m_caller = caller;
164
165     gClassCount++;
166 }
167
168 WebScriptCallFrame::~WebScriptCallFrame()
169 {
170     gClassCount--;
171 }
172
173 WebScriptCallFrame* WebScriptCallFrame::createInstance(ExecState* state, IWebScriptCallFrame* caller)
174 {
175     WebScriptCallFrame* instance = new WebScriptCallFrame(state, caller);
176     instance->AddRef();
177     return instance;
178 }
179
180 // IUnknown ------------------------------------------------------------------
181
182 HRESULT STDMETHODCALLTYPE WebScriptCallFrame::QueryInterface(REFIID riid, void** ppvObject)
183 {
184     *ppvObject = 0;
185     if (IsEqualGUID(riid, IID_IUnknown))
186         *ppvObject = static_cast<IWebScriptCallFrame*>(this);
187     else if (IsEqualGUID(riid, IID_IWebScriptCallFrame))
188         *ppvObject = static_cast<IWebScriptCallFrame*>(this);
189     else
190         return E_NOINTERFACE;
191
192     AddRef();
193     return S_OK;
194 }
195
196 ULONG STDMETHODCALLTYPE WebScriptCallFrame::AddRef()
197 {
198     return ++m_refCount;
199 }
200
201 ULONG STDMETHODCALLTYPE WebScriptCallFrame::Release()
202 {
203     ULONG newRef = --m_refCount;
204     if (!newRef)
205         delete(this);
206
207     return newRef;
208 }
209
210 // IWebScriptCallFrame -----------------------------------------------------------
211
212 HRESULT STDMETHODCALLTYPE WebScriptCallFrame::caller(
213     /* [out, retval] */ IWebScriptCallFrame** callFrame)
214 {
215     return m_caller.copyRefTo(callFrame);
216 }
217
218 HRESULT STDMETHODCALLTYPE WebScriptCallFrame::scopeChain(
219     /* [out, retval] */ IEnumVARIANT** result)
220 {
221     if (!result)
222         return E_POINTER;
223
224     // FIXME: If there is no current body do we need to make scope chain from the global object?
225
226     *result = EnumScopes::createInstance(m_state->scopeChain());
227
228     return S_OK;
229 }
230
231 HRESULT STDMETHODCALLTYPE WebScriptCallFrame::functionName(
232     /* [out, retval] */ BSTR* funcName)
233 {
234     if (!funcName)
235         return E_POINTER;
236
237     *funcName = 0;
238
239     if (!m_state->currentBody())
240         return S_OK;
241
242     FunctionImp* func = m_state->function();
243     if (!func)
244         return E_FAIL;
245
246     const Identifier& funcIdent = func->functionName();
247     if (!funcIdent.isEmpty())
248         *funcName = WebCore::BString(funcIdent).release();
249
250     return S_OK;
251 }
252
253
254 HRESULT STDMETHODCALLTYPE WebScriptCallFrame::stringByEvaluatingJavaScriptFromString(
255     /* [in] */ BSTR script,
256     /* [out, retval] */ BSTR* result)
257 {
258     if (!script)
259         return E_FAIL;
260
261     if (!result)
262         return E_POINTER;
263
264     *result = 0;
265
266     JSLock lock;
267
268     ExecState* state = m_state;
269     Interpreter* interp  = state->dynamicInterpreter();
270     JSObject* globObj = interp->globalObject();
271
272     // find "eval"
273     JSObject* eval = 0;
274     if (state->currentBody()) {  // "eval" won't work without context (i.e. at global scope)
275         JSValue* v = globObj->get(state, "eval");
276         if (v->isObject() && static_cast<JSObject*>(v)->implementsCall())
277             eval = static_cast<JSObject*>(v);
278         else
279             // no "eval" - fallback operates on global exec state
280             state = interp->globalExec();
281     }
282
283     JSValue* savedException = state->exception();
284     state->clearException();
285
286     UString code(reinterpret_cast<KJS::UChar*>(script), SysStringLen(script));
287
288     // evaluate
289     JSValue* scriptExecutionResult;
290     if (eval) {
291         List args;
292         args.append(jsString(code));
293         scriptExecutionResult = eval->call(state, 0, args);
294     } else
295         // no "eval", or no context (i.e. global scope) - use global fallback
296         scriptExecutionResult = interp->evaluate(UString(), 0, code.data(), code.size(), globObj).value();
297
298     if (state->hadException())
299         scriptExecutionResult = state->exception();    // (may be redundant depending on which eval path was used)
300     state->setException(savedException);
301
302     if (!scriptExecutionResult)
303         return E_FAIL;
304
305     scriptExecutionResult->isString();
306     *result = WebCore::BString(WebCore::String(scriptExecutionResult->getString())).release();
307
308     return S_OK;
309 }
310