1/*
2 * Copyright (C) 2009 Google 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 are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "config.h"
32#include "ScriptFunctionCall.h"
33
34#include "ScriptScope.h"
35#include "ScriptState.h"
36#include "ScriptValue.h"
37
38#include "V8Binding.h"
39#include "V8Proxy.h"
40#include "V8Utilities.h"
41
42#include <v8.h>
43#include <wtf/OwnArrayPtr.h>
44
45namespace WebCore {
46
47void ScriptCallArgumentHandler::appendArgument(const ScriptObject& argument)
48{
49    if (argument.scriptState() != m_scriptState) {
50        ASSERT_NOT_REACHED();
51        return;
52    }
53    m_arguments.append(argument);
54}
55
56void ScriptCallArgumentHandler::appendArgument(const ScriptValue& argument)
57{
58    m_arguments.append(argument);
59}
60
61void ScriptCallArgumentHandler::appendArgument(const String& argument)
62{
63    ScriptScope scope(m_scriptState);
64    m_arguments.append(v8String(argument));
65}
66
67void ScriptCallArgumentHandler::appendArgument(const char* argument)
68{
69    ScriptScope scope(m_scriptState);
70    m_arguments.append(v8String(argument));
71}
72
73void ScriptCallArgumentHandler::appendArgument(long argument)
74{
75    ScriptScope scope(m_scriptState);
76    m_arguments.append(v8::Number::New(argument));
77}
78
79void ScriptCallArgumentHandler::appendArgument(long long argument)
80{
81    ScriptScope scope(m_scriptState);
82    m_arguments.append(v8::Number::New(argument));
83}
84
85void ScriptCallArgumentHandler::appendArgument(unsigned int argument)
86{
87    ScriptScope scope(m_scriptState);
88    m_arguments.append(v8::Number::New(argument));
89}
90
91void ScriptCallArgumentHandler::appendArgument(unsigned long argument)
92{
93    ScriptScope scope(m_scriptState);
94    m_arguments.append(v8::Number::New(argument));
95}
96
97void ScriptCallArgumentHandler::appendArgument(int argument)
98{
99    ScriptScope scope(m_scriptState);
100    m_arguments.append(v8::Number::New(argument));
101}
102
103void ScriptCallArgumentHandler::appendArgument(bool argument)
104{
105    m_arguments.append(v8Boolean(argument));
106}
107
108ScriptFunctionCall::ScriptFunctionCall(const ScriptObject& thisObject, const String& name)
109    : ScriptCallArgumentHandler(thisObject.scriptState())
110    , m_thisObject(thisObject)
111    , m_name(name)
112{
113}
114
115ScriptValue ScriptFunctionCall::call(bool& hadException, bool reportExceptions)
116{
117    ScriptScope scope(m_scriptState, reportExceptions);
118
119    v8::Local<v8::Object> thisObject = m_thisObject.v8Object();
120    v8::Local<v8::Value> value = thisObject->Get(v8String(m_name));
121    if (!scope.success()) {
122        hadException = true;
123        return ScriptValue();
124    }
125
126    ASSERT(value->IsFunction());
127
128    v8::Local<v8::Function> function(v8::Function::Cast(*value));
129    OwnArrayPtr<v8::Handle<v8::Value> > args = adoptArrayPtr(new v8::Handle<v8::Value>[m_arguments.size()]);
130    for (size_t i = 0; i < m_arguments.size(); ++i)
131        args[i] = m_arguments[i].v8Value();
132
133    v8::Local<v8::Value> result = function->Call(thisObject, m_arguments.size(), args.get());
134    if (!scope.success()) {
135        hadException = true;
136        return ScriptValue();
137    }
138
139    return ScriptValue(result);
140}
141
142ScriptValue ScriptFunctionCall::call()
143{
144    bool hadException = false;
145    return call(hadException);
146}
147
148ScriptObject ScriptFunctionCall::construct(bool& hadException, bool reportExceptions)
149{
150    ScriptScope scope(m_scriptState, reportExceptions);
151
152    v8::Local<v8::Object> thisObject = m_thisObject.v8Object();
153    v8::Local<v8::Value> value = thisObject->Get(v8String(m_name));
154    if (!scope.success()) {
155        hadException = true;
156        return ScriptObject();
157    }
158
159    ASSERT(value->IsFunction());
160
161    v8::Local<v8::Function> constructor(v8::Function::Cast(*value));
162    OwnArrayPtr<v8::Handle<v8::Value> > args = adoptArrayPtr(new v8::Handle<v8::Value>[m_arguments.size()]);
163    for (size_t i = 0; i < m_arguments.size(); ++i)
164        args[i] = m_arguments[i].v8Value();
165
166    v8::Local<v8::Object> result = SafeAllocation::newInstance(constructor, m_arguments.size(), args.get());
167    if (!scope.success()) {
168        hadException = true;
169        return ScriptObject();
170    }
171
172    return ScriptObject(m_scriptState, result);
173}
174
175ScriptCallback::ScriptCallback(ScriptState* state, ScriptValue function)
176    : ScriptCallArgumentHandler(state)
177    , m_function(function)
178{
179}
180
181ScriptValue ScriptCallback::call()
182{
183    bool hadException = false;
184    return call(hadException);
185}
186
187ScriptValue ScriptCallback::call(bool& hadException)
188{
189    ASSERT(v8::Context::InContext());
190    ASSERT(m_function.v8Value()->IsFunction());
191
192    v8::TryCatch exceptionCatcher;
193    v8::Handle<v8::Object> object = v8::Context::GetCurrent()->Global();
194    v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(m_function.v8Value());
195
196    OwnArrayPtr<v8::Handle<v8::Value> > args = adoptArrayPtr(new v8::Handle<v8::Value>[m_arguments.size()]);
197    for (size_t i = 0; i < m_arguments.size(); ++i)
198        args[i] = m_arguments[i].v8Value();
199
200    v8::Handle<v8::Value> result = V8Proxy::callFunctionWithoutFrame(function, object, m_arguments.size(), args.get());
201
202    if (exceptionCatcher.HasCaught()) {
203        hadException = true;
204        m_scriptState->setException(exceptionCatcher.Exception());
205        return ScriptValue();
206    }
207
208    return ScriptValue(result);
209}
210
211} // namespace WebCore
212