Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / Source / core / inspector / InjectedScript.cpp
blob076bb237009d7fed429cac889f72ca8f55ce3cac
1 /*
2 * Copyright (C) 2012 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
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.
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.
31 #include "config.h"
34 #include "core/inspector/InjectedScript.h"
36 #include "bindings/core/v8/ScriptFunctionCall.h"
37 #include "bindings/core/v8/V8Binding.h"
38 #include "core/inspector/InjectedScriptHost.h"
39 #include "core/inspector/InspectorTraceEvents.h"
40 #include "core/inspector/JSONParser.h"
41 #include "core/inspector/RemoteObjectId.h"
42 #include "platform/JSONValues.h"
43 #include "wtf/text/WTFString.h"
45 using blink::TypeBuilder::Array;
46 using blink::TypeBuilder::Debugger::CallFrame;
47 using blink::TypeBuilder::Debugger::CollectionEntry;
48 using blink::TypeBuilder::Debugger::FunctionDetails;
49 using blink::TypeBuilder::Debugger::GeneratorObjectDetails;
50 using blink::TypeBuilder::Runtime::PropertyDescriptor;
51 using blink::TypeBuilder::Runtime::InternalPropertyDescriptor;
52 using blink::TypeBuilder::Runtime::RemoteObject;
54 namespace blink {
56 PassRefPtr<JSONValue> toJSONValue(const ScriptValue& value)
58 ScriptState* scriptState = value.scriptState();
59 ASSERT(scriptState->contextIsValid());
60 ScriptState::Scope scope(scriptState);
61 NonThrowableExceptionState exceptionState;
62 return ScriptValue::to<JSONValuePtr>(scriptState->isolate(), value, exceptionState);
65 static PassRefPtr<TypeBuilder::Debugger::ExceptionDetails> toExceptionDetails(PassRefPtr<JSONObject> object)
67 String text;
68 if (!object->getString("text", &text))
69 return nullptr;
71 RefPtr<TypeBuilder::Debugger::ExceptionDetails> exceptionDetails = TypeBuilder::Debugger::ExceptionDetails::create().setText(text);
72 String url;
73 if (object->getString("url", &url))
74 exceptionDetails->setUrl(url);
75 int line = 0;
76 if (object->getNumber("line", &line))
77 exceptionDetails->setLine(line);
78 int column = 0;
79 if (object->getNumber("column", &column))
80 exceptionDetails->setColumn(column);
81 int originScriptId = 0;
82 object->getNumber("scriptId", &originScriptId);
84 RefPtr<JSONArray> stackTrace = object->getArray("stackTrace");
85 if (stackTrace && stackTrace->length() > 0) {
86 RefPtr<TypeBuilder::Array<TypeBuilder::Console::CallFrame>> frames = TypeBuilder::Array<TypeBuilder::Console::CallFrame>::create();
87 for (unsigned i = 0; i < stackTrace->length(); ++i) {
88 RefPtr<JSONObject> stackFrame = stackTrace->get(i)->asObject();
89 int lineNumber = 0;
90 stackFrame->getNumber("lineNumber", &lineNumber);
91 int column = 0;
92 stackFrame->getNumber("column", &column);
93 int scriptId = 0;
94 stackFrame->getNumber("scriptId", &scriptId);
95 if (i == 0 && scriptId == originScriptId)
96 originScriptId = 0;
98 String sourceURL;
99 stackFrame->getString("scriptNameOrSourceURL", &sourceURL);
100 String functionName;
101 stackFrame->getString("functionName", &functionName);
103 RefPtr<TypeBuilder::Console::CallFrame> callFrame = TypeBuilder::Console::CallFrame::create()
104 .setFunctionName(functionName)
105 .setScriptId(String::number(scriptId))
106 .setUrl(sourceURL)
107 .setLineNumber(lineNumber)
108 .setColumnNumber(column);
110 frames->addItem(callFrame.release());
112 exceptionDetails->setStackTrace(frames.release());
114 if (originScriptId)
115 exceptionDetails->setScriptId(String::number(originScriptId));
116 return exceptionDetails.release();
119 InjectedScript::InjectedScript()
120 : m_inspectedStateAccessCheck(nullptr)
124 InjectedScript::InjectedScript(ScriptValue injectedScriptObject, InspectedStateAccessCheck accessCheck, PassRefPtr<InjectedScriptNative> injectedScriptNative)
125 : m_injectedScriptObject(injectedScriptObject)
126 , m_inspectedStateAccessCheck(accessCheck)
127 , m_native(injectedScriptNative)
131 InjectedScript::~InjectedScript()
135 void InjectedScript::evaluate(ErrorString* errorString, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, RefPtr<TypeBuilder::Runtime::RemoteObject>* result, TypeBuilder::OptOutput<bool>* wasThrown, RefPtr<TypeBuilder::Debugger::ExceptionDetails>* exceptionDetails)
137 ScriptFunctionCall function(injectedScriptObject(), "evaluate");
138 function.appendArgument(expression);
139 function.appendArgument(objectGroup);
140 function.appendArgument(includeCommandLineAPI);
141 function.appendArgument(returnByValue);
142 function.appendArgument(generatePreview);
143 makeEvalCall(errorString, function, result, wasThrown, exceptionDetails);
146 void InjectedScript::callFunctionOn(ErrorString* errorString, const String& objectId, const String& expression, const String& arguments, bool returnByValue, bool generatePreview, RefPtr<TypeBuilder::Runtime::RemoteObject>* result, TypeBuilder::OptOutput<bool>* wasThrown)
148 ScriptFunctionCall function(injectedScriptObject(), "callFunctionOn");
149 function.appendArgument(objectId);
150 function.appendArgument(expression);
151 function.appendArgument(arguments);
152 function.appendArgument(returnByValue);
153 function.appendArgument(generatePreview);
154 makeEvalCall(errorString, function, result, wasThrown);
157 void InjectedScript::evaluateOnCallFrame(ErrorString* errorString, v8::Local<v8::Object> callFrames, bool isAsyncCallStack, const String& callFrameId, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, RefPtr<RemoteObject>* result, TypeBuilder::OptOutput<bool>* wasThrown, RefPtr<TypeBuilder::Debugger::ExceptionDetails>* exceptionDetails)
159 ScriptFunctionCall function(injectedScriptObject(), "evaluateOnCallFrame");
160 function.appendArgument(callFrames);
161 function.appendArgument(isAsyncCallStack);
162 function.appendArgument(callFrameId);
163 function.appendArgument(expression);
164 function.appendArgument(objectGroup);
165 function.appendArgument(includeCommandLineAPI);
166 function.appendArgument(returnByValue);
167 function.appendArgument(generatePreview);
168 makeEvalCall(errorString, function, result, wasThrown, exceptionDetails);
171 void InjectedScript::restartFrame(ErrorString* errorString, v8::Local<v8::Object> callFrames, const String& callFrameId)
173 ScriptFunctionCall function(injectedScriptObject(), "restartFrame");
174 function.appendArgument(callFrames);
175 function.appendArgument(callFrameId);
176 RefPtr<JSONValue> resultValue;
177 makeCall(function, &resultValue);
178 if (resultValue) {
179 if (resultValue->type() == JSONValue::TypeString) {
180 resultValue->asString(errorString);
181 } else {
182 bool value;
183 ASSERT_UNUSED(value, resultValue->asBoolean(&value) && value);
185 return;
187 *errorString = "Internal error";
190 void InjectedScript::getStepInPositions(ErrorString* errorString, v8::Local<v8::Object> callFrames, const String& callFrameId, RefPtr<Array<TypeBuilder::Debugger::Location>>& positions)
192 ScriptFunctionCall function(injectedScriptObject(), "getStepInPositions");
193 function.appendArgument(callFrames);
194 function.appendArgument(callFrameId);
195 RefPtr<JSONValue> resultValue;
196 makeCall(function, &resultValue);
197 if (resultValue) {
198 if (resultValue->type() == JSONValue::TypeString) {
199 resultValue->asString(errorString);
200 return;
202 if (resultValue->type() == JSONValue::TypeArray) {
203 positions = Array<TypeBuilder::Debugger::Location>::runtimeCast(resultValue);
204 return;
207 *errorString = "Internal error";
210 void InjectedScript::setVariableValue(ErrorString* errorString, v8::Local<v8::Object> callFrames, const String* callFrameIdOpt, const String* functionObjectIdOpt, int scopeNumber, const String& variableName, const String& newValueStr)
212 ScriptFunctionCall function(injectedScriptObject(), "setVariableValue");
213 if (callFrameIdOpt) {
214 function.appendArgument(callFrames);
215 function.appendArgument(*callFrameIdOpt);
216 } else {
217 function.appendArgument(false);
218 function.appendArgument(false);
220 if (functionObjectIdOpt)
221 function.appendArgument(*functionObjectIdOpt);
222 else
223 function.appendArgument(false);
224 function.appendArgument(scopeNumber);
225 function.appendArgument(variableName);
226 function.appendArgument(newValueStr);
227 RefPtr<JSONValue> resultValue;
228 makeCall(function, &resultValue);
229 if (!resultValue) {
230 *errorString = "Internal error";
231 return;
233 if (resultValue->type() == JSONValue::TypeString) {
234 resultValue->asString(errorString);
235 return;
237 // Normal return.
240 void InjectedScript::getFunctionDetails(ErrorString* errorString, const String& functionId, RefPtr<FunctionDetails>* result)
242 ScriptFunctionCall function(injectedScriptObject(), "getFunctionDetails");
243 function.appendArgument(functionId);
244 RefPtr<JSONValue> resultValue;
245 makeCall(function, &resultValue);
246 if (!resultValue || resultValue->type() != JSONValue::TypeObject) {
247 if (!resultValue->asString(errorString))
248 *errorString = "Internal error";
249 return;
251 *result = FunctionDetails::runtimeCast(resultValue);
254 void InjectedScript::getGeneratorObjectDetails(ErrorString* errorString, const String& objectId, RefPtr<GeneratorObjectDetails>* result)
256 ScriptFunctionCall function(injectedScriptObject(), "getGeneratorObjectDetails");
257 function.appendArgument(objectId);
258 RefPtr<JSONValue> resultValue;
259 makeCall(function, &resultValue);
260 if (!resultValue || resultValue->type() != JSONValue::TypeObject) {
261 if (!resultValue->asString(errorString))
262 *errorString = "Internal error";
263 return;
265 *result = GeneratorObjectDetails::runtimeCast(resultValue);
268 void InjectedScript::getCollectionEntries(ErrorString* errorString, const String& objectId, RefPtr<Array<CollectionEntry> >* result)
270 ScriptFunctionCall function(injectedScriptObject(), "getCollectionEntries");
271 function.appendArgument(objectId);
272 RefPtr<JSONValue> resultValue;
273 makeCall(function, &resultValue);
274 if (!resultValue || resultValue->type() != JSONValue::TypeArray) {
275 if (!resultValue->asString(errorString))
276 *errorString = "Internal error";
277 return;
279 *result = Array<CollectionEntry>::runtimeCast(resultValue);
282 void InjectedScript::getProperties(ErrorString* errorString, const String& objectId, bool ownProperties, bool accessorPropertiesOnly, bool generatePreview, RefPtr<Array<PropertyDescriptor>>* properties, RefPtr<TypeBuilder::Debugger::ExceptionDetails>* exceptionDetails)
284 ScriptFunctionCall function(injectedScriptObject(), "getProperties");
285 function.appendArgument(objectId);
286 function.appendArgument(ownProperties);
287 function.appendArgument(accessorPropertiesOnly);
288 function.appendArgument(generatePreview);
290 RefPtr<JSONValue> result;
291 makeCallWithExceptionDetails(function, &result, exceptionDetails);
292 if (*exceptionDetails) {
293 // FIXME: make properties optional
294 *properties = Array<PropertyDescriptor>::create();
295 return;
297 if (!result || result->type() != JSONValue::TypeArray) {
298 *errorString = "Internal error";
299 return;
301 *properties = Array<PropertyDescriptor>::runtimeCast(result);
304 void InjectedScript::getInternalProperties(ErrorString* errorString, const String& objectId, RefPtr<Array<InternalPropertyDescriptor>>* properties, RefPtr<TypeBuilder::Debugger::ExceptionDetails>* exceptionDetails)
306 ScriptFunctionCall function(injectedScriptObject(), "getInternalProperties");
307 function.appendArgument(objectId);
309 RefPtr<JSONValue> result;
310 makeCallWithExceptionDetails(function, &result, exceptionDetails);
311 if (*exceptionDetails)
312 return;
313 if (!result || result->type() != JSONValue::TypeArray) {
314 *errorString = "Internal error";
315 return;
317 RefPtr<Array<InternalPropertyDescriptor> > array = Array<InternalPropertyDescriptor>::runtimeCast(result);
318 if (array->length() > 0)
319 *properties = array;
322 void InjectedScript::releaseObject(const String& objectId)
324 RefPtr<JSONValue> parsedObjectId = parseJSON(objectId);
325 if (!parsedObjectId)
326 return;
327 RefPtr<JSONObject> object;
328 if (!parsedObjectId->asObject(&object))
329 return;
330 int boundId = 0;
331 if (!object->getNumber("id", &boundId))
332 return;
333 m_native->unbind(boundId);
336 PassRefPtr<Array<CallFrame>> InjectedScript::wrapCallFrames(v8::Local<v8::Object> callFrames, int asyncOrdinal)
338 ASSERT(!isEmpty());
339 ScriptFunctionCall function(injectedScriptObject(), "wrapCallFrames");
340 function.appendArgument(callFrames);
341 function.appendArgument(asyncOrdinal);
342 bool hadException = false;
343 ScriptValue callFramesValue = callFunctionWithEvalEnabled(function, hadException);
344 ASSERT(!hadException);
345 RefPtr<JSONValue> result = toJSONValue(callFramesValue);
346 if (result && result->type() == JSONValue::TypeArray)
347 return Array<CallFrame>::runtimeCast(result);
348 return Array<CallFrame>::create();
351 PassRefPtr<TypeBuilder::Runtime::RemoteObject> InjectedScript::wrapObject(const ScriptValue& value, const String& groupName, bool generatePreview) const
353 ASSERT(!isEmpty());
354 ScriptFunctionCall wrapFunction(injectedScriptObject(), "wrapObject");
355 wrapFunction.appendArgument(value);
356 wrapFunction.appendArgument(groupName);
357 wrapFunction.appendArgument(canAccessInspectedWindow());
358 wrapFunction.appendArgument(generatePreview);
359 bool hadException = false;
360 ScriptValue r = callFunctionWithEvalEnabled(wrapFunction, hadException);
361 if (hadException)
362 return nullptr;
363 RefPtr<JSONObject> rawResult = toJSONValue(r)->asObject();
364 return TypeBuilder::Runtime::RemoteObject::runtimeCast(rawResult);
367 PassRefPtr<TypeBuilder::Runtime::RemoteObject> InjectedScript::wrapTable(const ScriptValue& table, const ScriptValue& columns) const
369 ASSERT(!isEmpty());
370 ScriptFunctionCall wrapFunction(injectedScriptObject(), "wrapTable");
371 wrapFunction.appendArgument(canAccessInspectedWindow());
372 wrapFunction.appendArgument(table);
373 if (columns.isEmpty())
374 wrapFunction.appendArgument(false);
375 else
376 wrapFunction.appendArgument(columns);
377 bool hadException = false;
378 ScriptValue r = callFunctionWithEvalEnabled(wrapFunction, hadException);
379 if (hadException)
380 return nullptr;
381 RefPtr<JSONObject> rawResult = toJSONValue(r)->asObject();
382 return TypeBuilder::Runtime::RemoteObject::runtimeCast(rawResult);
385 v8::Local<v8::Value> InjectedScript::findObject(const RemoteObjectId& objectId) const
387 ASSERT(!isEmpty());
388 return m_native->objectForId(objectId.id());
391 String InjectedScript::objectIdToObjectGroupName(const String& objectId) const
393 RefPtr<JSONValue> parsedObjectId = parseJSON(objectId);
394 if (!parsedObjectId)
395 return String();
396 RefPtr<JSONObject> object;
397 if (!parsedObjectId->asObject(&object))
398 return String();
399 int boundId = 0;
400 if (!object->getNumber("id", &boundId))
401 return String();
402 return m_native->groupName(boundId);
405 void InjectedScript::releaseObjectGroup(const String& objectGroup)
407 ASSERT(!isEmpty());
408 m_native->releaseObjectGroup(objectGroup);
409 if (objectGroup == "console") {
410 ScriptFunctionCall releaseFunction(injectedScriptObject(), "clearLastEvaluationResult");
411 bool hadException = false;
412 callFunctionWithEvalEnabled(releaseFunction, hadException);
413 ASSERT(!hadException);
417 void InjectedScript::setCustomObjectFormatterEnabled(bool enabled)
419 ASSERT(!isEmpty());
420 ScriptFunctionCall function(injectedScriptObject(), "setCustomObjectFormatterEnabled");
421 function.appendArgument(enabled);
422 RefPtr<JSONValue> result;
423 makeCall(function, &result);
426 void InjectedScript::initialize(ScriptValue injectedScriptObject, InspectedStateAccessCheck accessCheck)
428 m_injectedScriptObject = injectedScriptObject;
429 m_inspectedStateAccessCheck = accessCheck;
432 bool InjectedScript::canAccessInspectedWindow() const
434 ASSERT(!isEmpty());
435 return m_inspectedStateAccessCheck(m_injectedScriptObject.scriptState());
438 const ScriptValue& InjectedScript::injectedScriptObject() const
440 return m_injectedScriptObject;
443 ScriptValue InjectedScript::callFunctionWithEvalEnabled(ScriptFunctionCall& function, bool& hadException) const
445 ASSERT(!isEmpty());
447 ScriptState* scriptState = m_injectedScriptObject.scriptState();
448 ScriptState::Scope scope(scriptState);
449 bool evalIsDisabled = !scriptState->evalEnabled();
450 // Temporarily enable allow evals for inspector.
451 if (evalIsDisabled)
452 scriptState->setEvalEnabled(true);
454 ScriptValue resultValue = function.call(hadException);
456 if (evalIsDisabled)
457 scriptState->setEvalEnabled(false);
459 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "UpdateCounters", TRACE_EVENT_SCOPE_THREAD, "data", InspectorUpdateCountersEvent::data());
460 return resultValue;
463 void InjectedScript::makeCall(ScriptFunctionCall& function, RefPtr<JSONValue>* result)
465 if (isEmpty() || !canAccessInspectedWindow()) {
466 *result = JSONValue::null();
467 return;
470 bool hadException = false;
471 ScriptValue resultValue = callFunctionWithEvalEnabled(function, hadException);
473 ASSERT(!hadException);
474 if (!hadException) {
475 *result = toJSONValue(resultValue);
476 if (!*result)
477 *result = JSONString::create(String::format("Object has too long reference chain(must not be longer than %d)", JSONValue::maxDepth));
478 } else {
479 *result = JSONString::create("Exception while making a call.");
483 void InjectedScript::makeEvalCall(ErrorString* errorString, ScriptFunctionCall& function, RefPtr<TypeBuilder::Runtime::RemoteObject>* objectResult, TypeBuilder::OptOutput<bool>* wasThrown, RefPtr<TypeBuilder::Debugger::ExceptionDetails>* exceptionDetails)
485 RefPtr<JSONValue> result;
486 makeCall(function, &result);
487 if (!result) {
488 *errorString = "Internal error: result value is empty";
489 return;
491 if (result->type() == JSONValue::TypeString) {
492 result->asString(errorString);
493 ASSERT(errorString->length());
494 return;
496 RefPtr<JSONObject> resultPair = result->asObject();
497 if (!resultPair) {
498 *errorString = "Internal error: result is not an Object";
499 return;
501 RefPtr<JSONObject> resultObj = resultPair->getObject("result");
502 bool wasThrownVal = false;
503 if (!resultObj || !resultPair->getBoolean("wasThrown", &wasThrownVal)) {
504 *errorString = "Internal error: result is not a pair of value and wasThrown flag";
505 return;
507 if (wasThrownVal) {
508 RefPtr<JSONObject> objectExceptionDetails = resultPair->getObject("exceptionDetails");
509 if (objectExceptionDetails)
510 *exceptionDetails = toExceptionDetails(objectExceptionDetails.release());
512 *objectResult = TypeBuilder::Runtime::RemoteObject::runtimeCast(resultObj);
513 *wasThrown = wasThrownVal;
516 void InjectedScript::makeCallWithExceptionDetails(ScriptFunctionCall& function, RefPtr<JSONValue>* result, RefPtr<TypeBuilder::Debugger::ExceptionDetails>* exceptionDetails)
518 ScriptState::Scope scope(injectedScriptObject().scriptState());
519 v8::TryCatch tryCatch;
520 ScriptValue resultValue = function.callWithoutExceptionHandling();
521 if (tryCatch.HasCaught()) {
522 v8::Local<v8::Message> message = tryCatch.Message();
523 String text = !message.IsEmpty() ? toCoreStringWithUndefinedOrNullCheck(message->Get()) : "Internal error";
524 *exceptionDetails = TypeBuilder::Debugger::ExceptionDetails::create().setText(text);
525 } else {
526 *result = toJSONValue(resultValue);
527 if (!*result)
528 *result = JSONString::create(String::format("Object has too long reference chain(must not be longer than %d)", JSONValue::maxDepth));
532 } // namespace blink