WebCore:
[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 riid, 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 // WebScriptCallFrame -----------------------------------------------------------
157
158
159
160 WebScriptCallFrame::WebScriptCallFrame()
161     : m_refCount(0)
162 {
163     gClassCount++;
164 }
165
166 WebScriptCallFrame::~WebScriptCallFrame()
167 {
168     gClassCount--;
169 }
170
171 WebScriptCallFrame* WebScriptCallFrame::createInstance()
172 {
173     WebScriptCallFrame* instance = new WebScriptCallFrame();
174     instance->AddRef();
175     return instance;
176 }
177
178 // IUnknown ------------------------------------------------------------------
179
180 HRESULT STDMETHODCALLTYPE WebScriptCallFrame::QueryInterface(REFIID riid, void** ppvObject)
181 {
182     *ppvObject = 0;
183     if (IsEqualGUID(riid, IID_IUnknown))
184         *ppvObject = static_cast<IWebScriptCallFrame*>(this);
185     else if (IsEqualGUID(riid, IID_IWebScriptCallFrame))
186         *ppvObject = static_cast<IWebScriptCallFrame*>(this);
187     else
188         return E_NOINTERFACE;
189
190     AddRef();
191     return S_OK;
192 }
193
194 ULONG STDMETHODCALLTYPE WebScriptCallFrame::AddRef()
195 {
196     return ++m_refCount;
197 }
198
199 ULONG STDMETHODCALLTYPE WebScriptCallFrame::Release()
200 {
201     ULONG newRef = --m_refCount;
202     if (!newRef)
203         delete(this);
204
205     return newRef;
206 }
207
208 // IWebScriptCallFrame -----------------------------------------------------------
209
210 HRESULT STDMETHODCALLTYPE WebScriptCallFrame::caller(
211     /* [out, retval] */ IWebScriptCallFrame** callFrame)
212 {
213     if (!callFrame)
214         return E_POINTER;
215
216     *callFrame = m_caller.get();
217     return S_OK;
218 }
219
220 HRESULT STDMETHODCALLTYPE WebScriptCallFrame::scopeChain(
221     /* [out, retval] */ IEnumVARIANT** result)
222 {
223     if (!result)
224         return E_POINTER;
225
226     // FIXME: If there is no current body do we need to make scope chain from the global object?
227
228     *result = EnumScopes::createInstance(m_state->scopeChain());
229
230     return S_OK;
231 }
232
233 HRESULT STDMETHODCALLTYPE WebScriptCallFrame::functionName(
234     /* [out, retval] */ BSTR* funcName)
235 {
236     if (!funcName)
237         return E_POINTER;
238
239     if (m_state->currentBody()) {
240         FunctionImp* func = m_state->function();
241         if (!func)
242             return E_FAIL;
243
244         *funcName = WebCore::BString(func->functionName()).release();
245     }
246
247     return S_OK;
248 }
249
250 HRESULT STDMETHODCALLTYPE WebScriptCallFrame::stringByEvaluatingJavaScriptFromString(
251     /* [in] */ BSTR script,
252     /* [out, retval] */ BSTR* result)
253 {
254     if (!script)
255         return E_FAIL;
256
257     if (!result)
258         return E_POINTER;
259
260     *result = 0;
261
262     JSLock lock;
263
264     ExecState* state = m_state;
265     Interpreter* interp  = state->dynamicInterpreter();
266     JSObject* globObj = interp->globalObject();
267
268     // find "eval"
269     JSObject* eval = 0;
270     if (state->currentBody()) {  // "eval" won't work without context (i.e. at global scope)
271         JSValue* v = globObj->get(state, "eval");
272         if (v->isObject() && static_cast<JSObject*>(v)->implementsCall())
273             eval = static_cast<JSObject*>(v);
274         else
275             // no "eval" - fallback operates on global exec state
276             state = interp->globalExec();
277     }
278
279     JSValue* savedException = state->exception();
280     state->clearException();
281
282     UString code(reinterpret_cast<KJS::UChar*>(script), SysStringLen(script));
283
284     // evaluate
285     JSValue* scriptExecutionResult;
286     if (eval) {
287         List args;
288         args.append(jsString(code));
289         scriptExecutionResult = eval->call(state, 0, args);
290     } else
291         // no "eval", or no context (i.e. global scope) - use global fallback
292         scriptExecutionResult = interp->evaluate(UString(), 0, code.data(), code.size(), globObj).value();
293
294     if (state->hadException())
295         scriptExecutionResult = state->exception();    // (may be redundant depending on which eval path was used)
296     state->setException(savedException);
297
298     if (!scriptExecutionResult)
299         return E_FAIL;
300
301     scriptExecutionResult->isString();
302     *result = WebCore::BString(WebCore::String(scriptExecutionResult->getString())).release();
303
304     return S_OK;
305 }