Fix build.
[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/Interpreter.h>
37 #include <JavaScriptCore/JSGlobalObject.h>
38 #include <JavaScriptCore/JSStringRefBSTR.h>
39 #include <JavaScriptCore/JSValueRef.h>
40 #include <JavaScriptCore/PropertyNameArray.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 UString WebScriptCallFrame::jsValueToString(KJS::ExecState* state, JSValue* jsvalue)
52 {
53     if (!jsvalue)
54         return "undefined";
55
56     switch (jsvalue->type()) {
57         case NullType:
58         case UndefinedType:
59         case UnspecifiedType:
60         case GetterSetterType:
61             break;
62         case StringType:
63             return jsvalue->getString();
64             break;
65         case NumberType:
66             return UString::from(jsvalue->getNumber());
67             break;
68         case BooleanType:
69             return jsvalue->getBoolean() ? "True" : "False";
70             break;
71         case ObjectType:
72             jsvalue = jsvalue->getObject()->defaultValue(state, StringType);
73             return jsvalue->getString();
74             break;
75     }
76
77     return "undefined";
78 }
79
80 // WebScriptCallFrame -----------------------------------------------------------
81
82 WebScriptCallFrame::WebScriptCallFrame(ExecState* state, IWebScriptCallFrame* caller)
83     : m_refCount(0)
84 {
85     m_state = state;
86     m_caller = caller;
87
88     gClassCount++;
89 }
90
91 WebScriptCallFrame::~WebScriptCallFrame()
92 {
93     gClassCount--;
94 }
95
96 WebScriptCallFrame* WebScriptCallFrame::createInstance(ExecState* state, IWebScriptCallFrame* caller)
97 {
98     WebScriptCallFrame* instance = new WebScriptCallFrame(state, caller);
99     instance->AddRef();
100     return instance;
101 }
102
103 // IUnknown ------------------------------------------------------------------
104
105 HRESULT STDMETHODCALLTYPE WebScriptCallFrame::QueryInterface(REFIID riid, void** ppvObject)
106 {
107     *ppvObject = 0;
108     if (IsEqualGUID(riid, IID_IUnknown))
109         *ppvObject = static_cast<IWebScriptCallFrame*>(this);
110     else if (IsEqualGUID(riid, IID_IWebScriptCallFrame))
111         *ppvObject = static_cast<IWebScriptCallFrame*>(this);
112     else
113         return E_NOINTERFACE;
114
115     AddRef();
116     return S_OK;
117 }
118
119 ULONG STDMETHODCALLTYPE WebScriptCallFrame::AddRef()
120 {
121     return ++m_refCount;
122 }
123
124 ULONG STDMETHODCALLTYPE WebScriptCallFrame::Release()
125 {
126     ULONG newRef = --m_refCount;
127     if (!newRef)
128         delete(this);
129
130     return newRef;
131 }
132
133 // IWebScriptCallFrame -----------------------------------------------------------
134
135 HRESULT STDMETHODCALLTYPE WebScriptCallFrame::caller(
136     /* [out, retval] */ IWebScriptCallFrame** callFrame)
137 {
138     return m_caller.copyRefTo(callFrame);
139 }
140
141 HRESULT STDMETHODCALLTYPE WebScriptCallFrame::functionName(
142     /* [out, retval] */ BSTR* funcName)
143 {
144     if (!funcName)
145         return E_POINTER;
146
147     *funcName = 0;
148
149     if (!m_state->currentBody())
150         return S_OK;
151
152     FunctionImp* func = m_state->function();
153     if (!func)
154         return E_FAIL;
155
156     const Identifier& funcIdent = func->functionName();
157     if (!funcIdent.isEmpty())
158         *funcName = WebCore::BString(funcIdent).release();
159
160     return S_OK;
161 }
162
163 HRESULT STDMETHODCALLTYPE WebScriptCallFrame::stringByEvaluatingJavaScriptFromString(
164     /* [in] */ BSTR script,
165     /* [out, retval] */ BSTR* result)
166 {
167     if (!script)
168         return E_FAIL;
169
170     if (!result)
171         return E_POINTER;
172
173     *result = 0;
174
175     JSLock lock;
176
177     JSValue* scriptExecutionResult = valueByEvaluatingJavaScriptFromString(script);
178     *result = WebCore::BString(jsValueToString(m_state, scriptExecutionResult)).release();
179
180     return S_OK;
181 }
182
183 HRESULT STDMETHODCALLTYPE WebScriptCallFrame::variableNames(
184     /* [out, retval] */ IEnumVARIANT** variableNames)
185 {
186     if (!variableNames)
187         return E_POINTER;
188
189     *variableNames = 0;
190
191     PropertyNameArray propertyNames;
192
193     m_state->scopeChain().top()->getPropertyNames(m_state, propertyNames);
194     *variableNames = COMEnumVariant<PropertyNameArray>::adopt(propertyNames);
195
196     return S_OK;
197 }
198
199 HRESULT STDMETHODCALLTYPE WebScriptCallFrame::valueForVariable(
200     /* [in] */ BSTR key,
201     /* [out, retval] */ BSTR* value)
202 {
203     if (!key)
204         return E_FAIL;
205
206     if (!value)
207         return E_POINTER;
208
209     *value = 0;
210
211     Identifier identKey(reinterpret_cast<KJS::UChar*>(key), SysStringLen(key));
212
213     JSValue* jsvalue = 0;
214     ScopeChain scopeChain = m_state->scopeChain();
215     for (ScopeChainIterator it = scopeChain.begin(); it != scopeChain.end() && !jsvalue; ++it)
216         jsvalue = (*it)->get(m_state, identKey);
217
218     *value = WebCore::BString(jsValueToString(m_state, jsvalue)).release();
219
220     return S_OK;
221 }
222
223 JSValue* WebScriptCallFrame::valueByEvaluatingJavaScriptFromString(BSTR script)
224 {
225     ExecState* state = m_state;
226     JSGlobalObject* globObj = state->dynamicGlobalObject();
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 = Interpreter::evaluate(state, 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 };