/* * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "WebScriptCallFrame.h" #include "COMEnumVariant.h" #include "WebKitDLL.h" #include #include #include #include #include #include #include #pragma warning(push, 0) #include #include #pragma warning(pop) #include using namespace JSC; UString WebScriptCallFrame::jsValueToString(JSC::ExecState* state, JSValuePtr jsvalue) { if (!jsvalue) return "undefined"; if (jsvalue.isString()) return jsvalue.getString(); else if (jsvalue.isNumber()) return UString::from(jsvalue.uncheckedGetNumber()); else if (jsvalue.isBoolean()) return jsvalue.getBoolean() ? "True" : "False"; else if (jsvalue.isObject()) { jsvalue = jsvalue.getObject()->defaultValue(state, PreferString); return jsvalue.getString(); } return "undefined"; } // WebScriptCallFrame ----------------------------------------------------------- static ExecState* callingFunctionOrGlobalExecState(ExecState* exec) { #if 0 for (ExecState* current = exec; current; current = current->callingExecState()) if (current->codeType() == FunctionCode || current->codeType() == GlobalCode) return current; #endif return 0; } WebScriptCallFrame::WebScriptCallFrame(ExecState* state) : m_refCount(0) , m_state(callingFunctionOrGlobalExecState(state)) { ASSERT_ARG(state, state); ASSERT(m_state); gClassCount++; gClassNameCount.add("WebScriptCallFrame"); } WebScriptCallFrame::~WebScriptCallFrame() { gClassCount--; gClassNameCount.remove("WebScriptCallFrame"); } WebScriptCallFrame* WebScriptCallFrame::createInstance(ExecState* state) { WebScriptCallFrame* instance = new WebScriptCallFrame(state); instance->AddRef(); return instance; } // IUnknown ------------------------------------------------------------------ HRESULT STDMETHODCALLTYPE WebScriptCallFrame::QueryInterface(REFIID riid, void** ppvObject) { *ppvObject = 0; if (IsEqualGUID(riid, IID_IUnknown)) *ppvObject = static_cast(this); else if (IsEqualGUID(riid, IID_IWebScriptCallFrame)) *ppvObject = static_cast(this); else return E_NOINTERFACE; AddRef(); return S_OK; } ULONG STDMETHODCALLTYPE WebScriptCallFrame::AddRef() { return ++m_refCount; } ULONG STDMETHODCALLTYPE WebScriptCallFrame::Release() { ULONG newRef = --m_refCount; if (!newRef) delete(this); return newRef; } // IWebScriptCallFrame ----------------------------------------------------------- HRESULT STDMETHODCALLTYPE WebScriptCallFrame::caller( /* [out, retval] */ IWebScriptCallFrame** callFrame) { if (!callFrame) return E_POINTER; #if 0 *callFrame = m_state->callingExecState() ? WebScriptCallFrame::createInstance(m_state->callingExecState()) : 0; #endif return S_OK; } HRESULT STDMETHODCALLTYPE WebScriptCallFrame::functionName( /* [out, retval] */ BSTR* funcName) { if (!funcName) return E_POINTER; *funcName = 0; #if 0 if (!m_state->scopeNode()) return S_OK; JSFunction* func = m_state->function(); if (!func) return E_FAIL; const Identifier& funcIdent = func->functionName(); if (!funcIdent.isEmpty()) *funcName = WebCore::BString(funcIdent).release(); #endif return S_OK; } HRESULT STDMETHODCALLTYPE WebScriptCallFrame::stringByEvaluatingJavaScriptFromString( /* [in] */ BSTR script, /* [out, retval] */ BSTR* result) { if (!script) return E_FAIL; if (!result) return E_POINTER; *result = 0; JSLock lock(false); JSValuePtr scriptExecutionResult = valueByEvaluatingJavaScriptFromString(script); *result = WebCore::BString(jsValueToString(m_state, scriptExecutionResult)).release(); return S_OK; } HRESULT STDMETHODCALLTYPE WebScriptCallFrame::variableNames( /* [out, retval] */ IEnumVARIANT** variableNames) { if (!variableNames) return E_POINTER; *variableNames = 0; PropertyNameArray propertyNames(m_state); #if 0 m_state->scopeChain().top()->getPropertyNames(m_state, propertyNames); // FIXME: It would be more efficient to use ::adopt here, but PropertyNameArray doesn't have a swap function. *variableNames = COMEnumVariant::createInstance(propertyNames); #endif return S_OK; } HRESULT STDMETHODCALLTYPE WebScriptCallFrame::valueForVariable( /* [in] */ BSTR key, /* [out, retval] */ BSTR* value) { if (!key) return E_FAIL; if (!value) return E_POINTER; *value = 0; Identifier identKey(m_state, reinterpret_cast(key), SysStringLen(key)); #if 0 JSValuePtr jsvalue = noValue(); ScopeChain scopeChain = m_state->scopeChain(); for (ScopeChainIterator it = scopeChain.begin(); it != scopeChain.end() && !jsvalue; ++it) jsvalue = (*it)->get(m_state, identKey); *value = WebCore::BString(jsValueToString(m_state, jsvalue)).release(); #endif return S_OK; } JSValuePtr WebScriptCallFrame::valueByEvaluatingJavaScriptFromString(BSTR script) { #if 0 ExecState* state = m_state; JSGlobalObject* globObj = state->dynamicGlobalObject(); // find "eval" JSObject* eval = 0; if (state->scopeNode()) { // "eval" won't work without context (i.e. at global scope) JSValuePtr v = globObj->get(state, "eval"); if (v->isObject() && asObject(v)->implementsCall()) eval = asObject(v); else // no "eval" - fallback operates on global exec state state = globObj->globalExec(); } JSValuePtr savedException = state->exception(); state->clearException(); UString code(reinterpret_cast(script), SysStringLen(script)); // evaluate JSValuePtr scriptExecutionResult; if (eval) { ArgList args; args.append(jsString(state, code)); scriptExecutionResult = eval->call(state, 0, args); } else // no "eval", or no context (i.e. global scope) - use global fallback scriptExecutionResult = JSC::evaluate(state, UString(), 0, code.data(), code.size(), globObj).value(); if (state->hadException()) scriptExecutionResult = state->exception(); // (may be redundant depending on which eval path was used) state->setException(savedException); return scriptExecutionResult; #else return jsNull(); #endif } template<> struct COMVariantSetter { static void setVariant(VARIANT* variant, const Identifier& value) { ASSERT(V_VT(variant) == VT_EMPTY); V_VT(variant) = VT_BSTR; V_BSTR(variant) = WebCore::BString(reinterpret_cast(value.data()), value.size()).release(); } };