Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / renderer / pepper / pepper_try_catch.cc
blob7f1b48d3c06e39ad338c796ec8c4860d2d130b0c
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/pepper/pepper_try_catch.h"
7 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
8 #include "content/renderer/pepper/v8_var_converter.h"
9 #include "gin/converter.h"
10 #include "ppapi/shared_impl/ppapi_globals.h"
11 #include "ppapi/shared_impl/var_tracker.h"
13 namespace content {
15 namespace {
17 const char kConversionException[] =
18 "Error: Failed conversion between PP_Var and V8 value";
19 const char kInvalidException[] = "Error: An invalid exception was thrown.";
21 } // namespace
23 PepperTryCatch::PepperTryCatch(PepperPluginInstanceImpl* instance,
24 V8VarConverter* var_converter)
25 : instance_(instance), var_converter_(var_converter) {}
27 PepperTryCatch::~PepperTryCatch() {}
29 v8::Handle<v8::Value> PepperTryCatch::ToV8(PP_Var var) {
30 if (HasException()) {
31 SetException(kConversionException);
32 return v8::Handle<v8::Value>();
35 v8::Handle<v8::Value> result;
36 bool success = var_converter_->ToV8Value(var, GetContext(), &result);
37 if (!success) {
38 SetException(kConversionException);
39 return v8::Handle<v8::Value>();
41 return result;
44 ppapi::ScopedPPVar PepperTryCatch::FromV8(v8::Handle<v8::Value> v8_value) {
45 if (HasException() || v8_value.IsEmpty()) {
46 SetException(kConversionException);
47 return ppapi::ScopedPPVar();
49 ppapi::ScopedPPVar result;
50 bool success =
51 var_converter_->FromV8ValueSync(v8_value, GetContext(), &result);
52 if (!success) {
53 SetException(kConversionException);
54 return ppapi::ScopedPPVar();
56 return result;
59 PepperTryCatchV8::PepperTryCatchV8(PepperPluginInstanceImpl* instance,
60 V8VarConverter* var_converter,
61 v8::Isolate* isolate)
62 : PepperTryCatch(instance, var_converter),
63 exception_(PP_MakeUndefined()) {
64 // Typically when using PepperTryCatchV8 we are passed an isolate. We verify
65 // that this isolate is the same as the plugin isolate.
66 DCHECK(isolate == instance_->GetIsolate());
68 // We assume that a handle scope and context has been setup by the user of
69 // this class. This is typically true because this class is used when calling
70 // into the plugin from JavaScript. We want to use whatever v8 context the
71 // caller is in.
74 PepperTryCatchV8::~PepperTryCatchV8() {
75 ppapi::PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(exception_);
78 bool PepperTryCatchV8::HasException() {
79 return GetContext().IsEmpty() || exception_.type != PP_VARTYPE_UNDEFINED;
82 v8::Handle<v8::Context> PepperTryCatchV8::GetContext() {
83 // When calling from JS into the plugin always use the current context.
84 return instance_->GetIsolate()->GetCurrentContext();
87 bool PepperTryCatchV8::ThrowException() {
88 if (!HasException())
89 return false;
91 // If there is no context then we have an exception but we don't try to throw
92 // it into v8.
93 if (GetContext().IsEmpty())
94 return true;
96 std::string message(kInvalidException);
97 ppapi::StringVar* message_var = ppapi::StringVar::FromPPVar(exception_);
98 if (message_var)
99 message = message_var->value();
100 instance_->GetIsolate()->ThrowException(v8::Exception::Error(
101 gin::StringToV8(instance_->GetIsolate(), message)));
103 ppapi::PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(exception_);
104 exception_ = PP_MakeUndefined();
105 return true;
108 void PepperTryCatchV8::ThrowException(const char* message) {
109 SetException(message);
110 ThrowException();
113 void PepperTryCatchV8::SetException(const char* message) {
114 if (HasException())
115 return;
117 exception_ = ppapi::StringVar::StringToPPVar(message);
120 PepperTryCatchVar::PepperTryCatchVar(PepperPluginInstanceImpl* instance,
121 V8VarConverter* var_converter,
122 PP_Var* exception)
123 : PepperTryCatch(instance, var_converter),
124 handle_scope_(instance_->GetIsolate()),
125 exception_(exception),
126 exception_is_set_(false) {
127 // Store a handle to the context here for 2 reasons:
128 // 1) To hold a handle to it in case all other handles are destroyed.
129 // 2) Because calling PepperPluginInstanceImpl::GetMainWorldContext() later
130 // can result in trying to access the plugin element. However the plugin
131 // element may have been destroyed during the PepperTryCatchVar (for
132 // example if a script is executed which destroys the plugin element). So
133 // we want to avoid accessing the plugin element again beyond this point.
134 context_ = instance_->GetMainWorldContext();
136 // We switch to the plugin context if it's not empty.
137 if (!context_.IsEmpty())
138 context_->Enter();
141 PepperTryCatchVar::~PepperTryCatchVar() {
142 if (!context_.IsEmpty())
143 context_->Exit();
146 bool PepperTryCatchVar::HasException() {
147 if (exception_is_set_)
148 return true;
150 std::string exception_message;
151 if (context_.IsEmpty()) {
152 exception_message = "The v8 context has been destroyed.";
153 } else if (try_catch_.HasCaught()) {
154 v8::String::Utf8Value utf8(try_catch_.Message()->Get());
155 exception_message = std::string(*utf8, utf8.length());
158 if (!exception_message.empty()) {
159 exception_is_set_ = true;
160 if (exception_)
161 *exception_ = ppapi::StringVar::StringToPPVar(exception_message);
164 return exception_is_set_;
167 v8::Handle<v8::Context> PepperTryCatchVar::GetContext() {
168 return context_;
171 void PepperTryCatchVar::SetException(const char* message) {
172 if (exception_is_set_)
173 return;
175 if (exception_)
176 *exception_ = ppapi::StringVar::StringToPPVar(message, strlen(message));
177 exception_is_set_ = true;
180 } // namespace content