Reviewed by Adam.
[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 "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 // WebScriptCallFrame -----------------------------------------------------------
52
53 WebScriptCallFrame::WebScriptCallFrame(ExecState* state, IWebScriptCallFrame* caller)
54     : m_refCount(0)
55 {
56     m_state = state;
57     m_caller = caller;
58
59     gClassCount++;
60 }
61
62 WebScriptCallFrame::~WebScriptCallFrame()
63 {
64     gClassCount--;
65 }
66
67 WebScriptCallFrame* WebScriptCallFrame::createInstance(ExecState* state, IWebScriptCallFrame* caller)
68 {
69     WebScriptCallFrame* instance = new WebScriptCallFrame(state, caller);
70     instance->AddRef();
71     return instance;
72 }
73
74 // IUnknown ------------------------------------------------------------------
75
76 HRESULT STDMETHODCALLTYPE WebScriptCallFrame::QueryInterface(REFIID riid, void** ppvObject)
77 {
78     *ppvObject = 0;
79     if (IsEqualGUID(riid, IID_IUnknown))
80         *ppvObject = static_cast<IWebScriptCallFrame*>(this);
81     else if (IsEqualGUID(riid, IID_IWebScriptCallFrame))
82         *ppvObject = static_cast<IWebScriptCallFrame*>(this);
83     else
84         return E_NOINTERFACE;
85
86     AddRef();
87     return S_OK;
88 }
89
90 ULONG STDMETHODCALLTYPE WebScriptCallFrame::AddRef()
91 {
92     return ++m_refCount;
93 }
94
95 ULONG STDMETHODCALLTYPE WebScriptCallFrame::Release()
96 {
97     ULONG newRef = --m_refCount;
98     if (!newRef)
99         delete(this);
100
101     return newRef;
102 }
103
104 // IWebScriptCallFrame -----------------------------------------------------------
105
106 HRESULT STDMETHODCALLTYPE WebScriptCallFrame::caller(
107     /* [out, retval] */ IWebScriptCallFrame** callFrame)
108 {
109     return m_caller.copyRefTo(callFrame);
110 }
111
112 template<> struct COMVariantSetter<JSObject*> : COMIUnknownVariantSetter<WebScriptScope, JSObject*> {};
113
114 HRESULT STDMETHODCALLTYPE WebScriptCallFrame::scopeChain(
115     /* [out, retval] */ IEnumVARIANT** result)
116 {
117     if (!result)
118         return E_POINTER;
119
120     // FIXME: If there is no current body do we need to make scope chain from the global object?
121     *result = COMEnumVariant<ScopeChain>::createInstance(m_state->scopeChain());
122
123     return S_OK;
124 }
125
126 HRESULT STDMETHODCALLTYPE WebScriptCallFrame::functionName(
127     /* [out, retval] */ BSTR* funcName)
128 {
129     if (!funcName)
130         return E_POINTER;
131
132     *funcName = 0;
133
134     if (!m_state->currentBody())
135         return S_OK;
136
137     FunctionImp* func = m_state->function();
138     if (!func)
139         return E_FAIL;
140
141     const Identifier& funcIdent = func->functionName();
142     if (!funcIdent.isEmpty())
143         *funcName = WebCore::BString(funcIdent).release();
144
145     return S_OK;
146 }
147
148 HRESULT STDMETHODCALLTYPE WebScriptCallFrame::stringByEvaluatingJavaScriptFromString(
149     /* [in] */ BSTR script,
150     /* [out, retval] */ BSTR* result)
151 {
152     if (!script)
153         return E_FAIL;
154
155     if (!result)
156         return E_POINTER;
157
158     *result = 0;
159
160     JSLock lock;
161
162     JSValue* scriptExecutionResult = valueByEvaluatingJavaScriptFromString(script);
163
164     if (scriptExecutionResult && scriptExecutionResult->isString())
165         *result = WebCore::BString(WebCore::String(scriptExecutionResult->getString())).release();
166     else
167         return E_FAIL;
168
169     return S_OK;
170 }
171
172 JSValue* WebScriptCallFrame::valueByEvaluatingJavaScriptFromString(BSTR script)
173 {
174     ExecState* state = m_state;
175     Interpreter* interp  = state->dynamicInterpreter();
176     JSObject* globObj = interp->globalObject();
177
178     // find "eval"
179     JSObject* eval = 0;
180     if (state->currentBody()) {  // "eval" won't work without context (i.e. at global scope)
181         JSValue* v = globObj->get(state, "eval");
182         if (v->isObject() && static_cast<JSObject*>(v)->implementsCall())
183             eval = static_cast<JSObject*>(v);
184         else
185             // no "eval" - fallback operates on global exec state
186             state = interp->globalExec();
187     }
188
189     JSValue* savedException = state->exception();
190     state->clearException();
191
192     UString code(reinterpret_cast<KJS::UChar*>(script), SysStringLen(script));
193
194     // evaluate
195     JSValue* scriptExecutionResult;
196     if (eval) {
197         List args;
198         args.append(jsString(code));
199         scriptExecutionResult = eval->call(state, 0, args);
200     } else
201         // no "eval", or no context (i.e. global scope) - use global fallback
202         scriptExecutionResult = interp->evaluate(UString(), 0, code.data(), code.size(), globObj).value();
203
204     if (state->hadException())
205         scriptExecutionResult = state->exception();    // (may be redundant depending on which eval path was used)
206     state->setException(savedException);
207
208     return scriptExecutionResult;
209 }
210