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"
17 const char kConversionException
[] =
18 "Error: Failed conversion between PP_Var and V8 value";
19 const char kInvalidException
[] = "Error: An invalid exception was thrown.";
23 PepperTryCatch::PepperTryCatch(PepperPluginInstanceImpl
* instance
,
24 V8VarConverter
* var_converter
)
25 : instance_(instance
), var_converter_(var_converter
) {}
27 PepperTryCatch::~PepperTryCatch() {}
29 v8::Local
<v8::Value
> PepperTryCatch::ToV8(PP_Var var
) {
31 SetException(kConversionException
);
32 return v8::Local
<v8::Value
>();
35 v8::Local
<v8::Value
> result
;
36 bool success
= var_converter_
->ToV8Value(var
, GetContext(), &result
);
38 SetException(kConversionException
);
39 return v8::Local
<v8::Value
>();
44 ppapi::ScopedPPVar
PepperTryCatch::FromV8(v8::Local
<v8::Value
> v8_value
) {
45 if (HasException() || v8_value
.IsEmpty()) {
46 SetException(kConversionException
);
47 return ppapi::ScopedPPVar();
49 ppapi::ScopedPPVar result
;
51 var_converter_
->FromV8ValueSync(v8_value
, GetContext(), &result
);
53 SetException(kConversionException
);
54 return ppapi::ScopedPPVar();
59 PepperTryCatchV8::PepperTryCatchV8(PepperPluginInstanceImpl
* instance
,
60 V8VarConverter
* var_converter
,
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
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::Local
<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() {
91 // If there is no context then we have an exception but we don't try to throw
93 if (GetContext().IsEmpty())
96 std::string
message(kInvalidException
);
97 ppapi::StringVar
* message_var
= ppapi::StringVar::FromPPVar(exception_
);
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();
108 void PepperTryCatchV8::ThrowException(const char* message
) {
109 SetException(message
);
113 void PepperTryCatchV8::SetException(const char* message
) {
117 exception_
= ppapi::StringVar::StringToPPVar(message
);
120 PepperTryCatchVar::PepperTryCatchVar(PepperPluginInstanceImpl
* instance
,
121 V8VarConverter
* var_converter
,
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())
141 PepperTryCatchVar::~PepperTryCatchVar() {
142 if (!context_
.IsEmpty())
146 bool PepperTryCatchVar::HasException() {
147 if (exception_is_set_
)
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::Local
<v8::Message
> message(try_catch_
.Message());
155 if (!message
.IsEmpty()) {
156 v8::String::Utf8Value
utf8(try_catch_
.Message()->Get());
157 exception_message
= std::string(*utf8
, utf8
.length());
159 exception_message
= "There was a v8 exception.";
163 if (!exception_message
.empty()) {
164 exception_is_set_
= true;
166 *exception_
= ppapi::StringVar::StringToPPVar(exception_message
);
169 return exception_is_set_
;
172 v8::Local
<v8::Context
> PepperTryCatchVar::GetContext() {
176 void PepperTryCatchVar::SetException(const char* message
) {
177 if (exception_is_set_
)
181 *exception_
= ppapi::StringVar::StringToPPVar(message
, strlen(message
));
182 exception_is_set_
= true;
185 } // namespace content