4b1866ad88f0ab3efad1fa7a3a9e620f6102e845
[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 "COMEnumVariant.h"
34 #include "Function.h"
35
36 #include <JavaScriptCore/JSGlobalObject.h>
37 #include <JavaScriptCore/JSStringRefBSTR.h>
38 #include <JavaScriptCore/JSValueRef.h>
39 #include <JavaScriptCore/PropertyNameArray.h>
40
41 #pragma warning(push, 0)
42 #include <WebCore/BString.h>
43 #include <WebCore/PlatformString.h>
44 #pragma warning(pop)
45
46 #include <wtf/Assertions.h>
47
48 using namespace KJS;
49
50 UString WebScriptCallFrame::jsValueToString(KJS::ExecState* state, JSValue* jsvalue)
51 {
52     if (!jsvalue)
53         return "undefined";
54
55     switch (jsvalue->type()) {
56         case NullType:
57         case UndefinedType:
58         case UnspecifiedType:
59         case GetterSetterType:
60             break;
61         case StringType:
62             return jsvalue->getString();
63             break;
64         case NumberType:
65             return UString::from(jsvalue->getNumber());
66             break;
67         case BooleanType:
68             return jsvalue->getBoolean() ? "True" : "False";
69             break;
70         case ObjectType:
71             jsvalue = jsvalue->getObject()->defaultValue(state, StringType);
72             return jsvalue->getString();
73             break;
74     }
75
76     return "undefined";
77 }
78
79 // WebScriptCallFrame -----------------------------------------------------------
80
81 WebScriptCallFrame::WebScriptCallFrame(ExecState* state, IWebScriptCallFrame* caller)
82     : m_refCount(0)
83 {
84     m_state = state;
85     m_caller = caller;
86
87     gClassCount++;
88 }
89
90 WebScriptCallFrame::~WebScriptCallFrame()
91 {
92     gClassCount--;
93 }
94
95 WebScriptCallFrame* WebScriptCallFrame::createInstance(ExecState* state, IWebScriptCallFrame* caller)
96 {
97     WebScriptCallFrame* instance = new WebScriptCallFrame(state, caller);
98     instance->AddRef();
99     return instance;
100 }
101
102 // IUnknown ------------------------------------------------------------------
103
104 HRESULT STDMETHODCALLTYPE WebScriptCallFrame::QueryInterface(REFIID riid, void** ppvObject)
105 {
106     *ppvObject = 0;
107     if (IsEqualGUID(riid, IID_IUnknown))
108         *ppvObject = static_cast<IWebScriptCallFrame*>(this);
109     else if (IsEqualGUID(riid, IID_IWebScriptCallFrame))
110         *ppvObject = static_cast<IWebScriptCallFrame*>(this);
111     else
112         return E_NOINTERFACE;
113
114     AddRef();
115     return S_OK;
116 }
117
118 ULONG STDMETHODCALLTYPE WebScriptCallFrame::AddRef()
119 {
120     return ++m_refCount;
121 }
122
123 ULONG STDMETHODCALLTYPE WebScriptCallFrame::Release()
124 {
125     ULONG newRef = --m_refCount;
126     if (!newRef)
127         delete(this);
128
129     return newRef;
130 }
131
132 // IWebScriptCallFrame -----------------------------------------------------------
133
134 HRESULT STDMETHODCALLTYPE WebScriptCallFrame::caller(
135     /* [out, retval] */ IWebScriptCallFrame** callFrame)
136 {
137     return m_caller.copyRefTo(callFrame);
138 }
139
140 HRESULT STDMETHODCALLTYPE WebScriptCallFrame::functionName(
141     /* [out, retval] */ BSTR* funcName)
142 {
143     if (!funcName)
144         return E_POINTER;
145
146     *funcName = 0;
147
148     if (!m_state->currentBody())
149         return S_OK;
150
151     FunctionImp* func = m_state->function();
152     if (!func)
153         return E_FAIL;
154
155     const Identifier& funcIdent = func->functionName();
156     if (!funcIdent.isEmpty())
157         *funcName = WebCore::BString(funcIdent).release();
158
159     return S_OK;
160 }
161
162 HRESULT STDMETHODCALLTYPE WebScriptCallFrame::stringByEvaluatingJavaScriptFromString(
163     /* [in] */ BSTR script,
164     /* [out, retval] */ BSTR* result)
165 {
166     if (!script)
167         return E_FAIL;
168
169     if (!result)
170         return E_POINTER;
171
172     *result = 0;
173
174     JSLock lock;
175
176     JSValue* scriptExecutionResult = valueByEvaluatingJavaScriptFromString(script);
177     *result = WebCore::BString(jsValueToString(m_state, scriptExecutionResult)).release();
178
179     return S_OK;
180 }
181
182 HRESULT STDMETHODCALLTYPE WebScriptCallFrame::variableNames(
183     /* [out, retval] */ IEnumVARIANT** variableNames)
184 {
185     if (!variableNames)
186         return E_POINTER;
187
188     *variableNames = 0;
189
190     PropertyNameArray propertyNames;
191
192     m_state->scopeChain().top()->getPropertyNames(m_state, propertyNames);
193     *variableNames = COMEnumVariant<PropertyNameArray>::adopt(propertyNames);
194
195     return S_OK;
196 }
197
198 HRESULT STDMETHODCALLTYPE WebScriptCallFrame::valueForVariable(
199     /* [in] */ BSTR key,
200     /* [out, retval] */ BSTR* value)
201 {
202     if (!key)
203         return E_FAIL;
204
205     if (!value)
206         return E_POINTER;
207
208     *value = 0;
209
210     Identifier identKey(reinterpret_cast<KJS::UChar*>(key), SysStringLen(key));
211
212     JSValue* jsvalue = 0;
213     ScopeChain scopeChain = m_state->scopeChain();
214     for (ScopeChainIterator it = scopeChain.begin(); it != scopeChain.end() && !jsvalue; ++it)
215         jsvalue = (*it)->get(m_state, identKey);
216
217     *value = WebCore::BString(jsValueToString(m_state, jsvalue)).release();
218
219     return S_OK;
220 }
221
222 JSValue* WebScriptCallFrame::valueByEvaluatingJavaScriptFromString(BSTR script)
223 {
224     ExecState* state = m_state;
225     Interpreter* interp  = state->dynamicInterpreter();
226     JSGlobalObject* globObj = interp->globalObject();
227
228     // find "eval"
229     JSObject* eval = 0;
230     if (state->currentBody()) {  // "eval" won't work without context (i.e. at global scope)
231         JSValue* v = globObj->get(state, "eval");
232         if (v->isObject() && static_cast<JSObject*>(v)->implementsCall())
233             eval = static_cast<JSObject*>(v);
234         else
235             // no "eval" - fallback operates on global exec state
236             state = globObj->globalExec();
237     }
238
239     JSValue* savedException = state->exception();
240     state->clearException();
241
242     UString code(reinterpret_cast<KJS::UChar*>(script), SysStringLen(script));
243
244     // evaluate
245     JSValue* scriptExecutionResult;
246     if (eval) {
247         List args;
248         args.append(jsString(code));
249         scriptExecutionResult = eval->call(state, 0, args);
250     } else
251         // no "eval", or no context (i.e. global scope) - use global fallback
252         scriptExecutionResult = interp->evaluate(UString(), 0, code.data(), code.size(), globObj).value();
253
254     if (state->hadException())
255         scriptExecutionResult = state->exception();    // (may be redundant depending on which eval path was used)
256     state->setException(savedException);
257
258     return scriptExecutionResult;
259 }
260
261 template<> struct COMVariantSetter<Identifier>
262 {
263     static void setVariant(VARIANT* variant, const Identifier& value)
264     {
265         ASSERT(V_VT(variant) == VT_EMPTY);
266
267         V_VT(variant) = VT_BSTR;
268         V_BSTR(variant) = WebCore::BString(reinterpret_cast<const wchar_t*>(value.data()), value.size()).release();
269     }
270 };