| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/renderer/pepper/v8_var_converter.h" | 5 #include "content/renderer/pepper/v8_var_converter.h" |
| 6 | 6 |
| 7 #include <cmath> | 7 #include <cmath> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/memory/ref_counted.h" | 10 #include "base/memory/ref_counted.h" |
| 11 #include "base/memory/scoped_ptr.h" | 11 #include "base/memory/scoped_ptr.h" |
| 12 #include "base/synchronization/waitable_event.h" | 12 #include "base/synchronization/waitable_event.h" |
| 13 #include "base/threading/thread.h" | 13 #include "base/threading/thread.h" |
| 14 #include "base/values.h" | 14 #include "base/values.h" |
| 15 #include "content/renderer/pepper/resource_converter.h" |
| 15 #include "ppapi/c/pp_bool.h" | 16 #include "ppapi/c/pp_bool.h" |
| 16 #include "ppapi/c/pp_var.h" | 17 #include "ppapi/c/pp_var.h" |
| 17 #include "ppapi/shared_impl/array_var.h" | 18 #include "ppapi/shared_impl/array_var.h" |
| 18 #include "ppapi/shared_impl/dictionary_var.h" | 19 #include "ppapi/shared_impl/dictionary_var.h" |
| 19 #include "ppapi/shared_impl/ppapi_globals.h" | 20 #include "ppapi/shared_impl/ppapi_globals.h" |
| 20 #include "ppapi/shared_impl/proxy_lock.h" | 21 #include "ppapi/shared_impl/proxy_lock.h" |
| 21 #include "ppapi/shared_impl/scoped_pp_var.h" | 22 #include "ppapi/shared_impl/scoped_pp_var.h" |
| 22 #include "ppapi/shared_impl/test_globals.h" | 23 #include "ppapi/shared_impl/test_globals.h" |
| 23 #include "ppapi/shared_impl/unittest_utils.h" | 24 #include "ppapi/shared_impl/unittest_utils.h" |
| 24 #include "ppapi/shared_impl/var.h" | 25 #include "ppapi/shared_impl/var.h" |
| 25 #include "ppapi/shared_impl/var_tracker.h" | 26 #include "ppapi/shared_impl/var_tracker.h" |
| 26 #include "testing/gtest/include/gtest/gtest.h" | 27 #include "testing/gtest/include/gtest/gtest.h" |
| 27 #include "v8/include/v8.h" | 28 #include "v8/include/v8.h" |
| 28 | 29 |
| 29 using ppapi::ArrayBufferVar; | 30 using ppapi::ArrayBufferVar; |
| 30 using ppapi::ArrayVar; | 31 using ppapi::ArrayVar; |
| 31 using ppapi::DictionaryVar; | 32 using ppapi::DictionaryVar; |
| 32 using ppapi::PpapiGlobals; | 33 using ppapi::PpapiGlobals; |
| 33 using ppapi::ProxyLock; | 34 using ppapi::ProxyLock; |
| 34 using ppapi::ScopedPPVar; | 35 using ppapi::ScopedPPVar; |
| 35 using ppapi::StringVar; | 36 using ppapi::StringVar; |
| 36 using ppapi::TestGlobals; | 37 using ppapi::TestGlobals; |
| 37 using ppapi::TestEqual; | 38 using ppapi::TestEqual; |
| 38 using ppapi::VarTracker; | 39 using ppapi::VarTracker; |
| 39 | 40 |
| 40 namespace content { | 41 namespace content { |
| 41 | 42 |
| 42 namespace { | 43 namespace { |
| 43 | 44 |
| 45 class MockResourceConverter : public content::ResourceConverter { |
| 46 public: |
| 47 virtual ~MockResourceConverter() {} |
| 48 virtual void ShutDown(const base::Callback<void(bool)>& callback) OVERRIDE { |
| 49 callback.Run(true); |
| 50 } |
| 51 }; |
| 52 |
| 44 // Maps PP_Var IDs to the V8 value handle they correspond to. | 53 // Maps PP_Var IDs to the V8 value handle they correspond to. |
| 45 typedef base::hash_map<int64_t, v8::Handle<v8::Value> > VarHandleMap; | 54 typedef base::hash_map<int64_t, v8::Handle<v8::Value> > VarHandleMap; |
| 46 | 55 |
| 47 bool Equals(const PP_Var& var, | 56 bool Equals(const PP_Var& var, |
| 48 v8::Handle<v8::Value> val, | 57 v8::Handle<v8::Value> val, |
| 49 VarHandleMap* visited_ids) { | 58 VarHandleMap* visited_ids) { |
| 50 if (ppapi::VarTracker::IsVarTypeRefcounted(var.type)) { | 59 if (ppapi::VarTracker::IsVarTypeRefcounted(var.type)) { |
| 51 VarHandleMap::iterator it = visited_ids->find(var.value.as_id); | 60 VarHandleMap::iterator it = visited_ids->find(var.value.as_id); |
| 52 if (it != visited_ids->end()) | 61 if (it != visited_ids->end()) |
| 53 return it->second == val; | 62 return it->second == val; |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 133 } | 142 } |
| 134 | 143 |
| 135 class V8VarConverterTest : public testing::Test { | 144 class V8VarConverterTest : public testing::Test { |
| 136 public: | 145 public: |
| 137 V8VarConverterTest() | 146 V8VarConverterTest() |
| 138 : isolate_(v8::Isolate::GetCurrent()), | 147 : isolate_(v8::Isolate::GetCurrent()), |
| 139 conversion_success_(false), | 148 conversion_success_(false), |
| 140 conversion_event_(true, false), | 149 conversion_event_(true, false), |
| 141 callback_thread_("callback_thread") { | 150 callback_thread_("callback_thread") { |
| 142 callback_thread_.Start(); | 151 callback_thread_.Start(); |
| 152 converter_.reset(new V8VarConverter( |
| 153 callback_thread_.message_loop_proxy(), |
| 154 scoped_ptr<ResourceConverter>(new MockResourceConverter).Pass())); |
| 143 } | 155 } |
| 144 virtual ~V8VarConverterTest() {} | 156 virtual ~V8VarConverterTest() {} |
| 145 | 157 |
| 146 // testing::Test implementation. | 158 // testing::Test implementation. |
| 147 virtual void SetUp() { | 159 virtual void SetUp() { |
| 148 ProxyLock::Acquire(); | 160 ProxyLock::Acquire(); |
| 149 v8::HandleScope handle_scope(isolate_); | 161 v8::HandleScope handle_scope(isolate_); |
| 150 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(); | 162 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(); |
| 151 context_.Reset(isolate_, v8::Context::New(isolate_, NULL, global)); | 163 context_.Reset(isolate_, v8::Context::New(isolate_, NULL, global)); |
| 152 } | 164 } |
| 153 virtual void TearDown() { | 165 virtual void TearDown() { |
| 154 context_.Dispose(); | 166 context_.Dispose(); |
| 155 ASSERT_TRUE(PpapiGlobals::Get()->GetVarTracker()->GetLiveVars().empty()); | 167 ASSERT_TRUE(PpapiGlobals::Get()->GetVarTracker()->GetLiveVars().empty()); |
| 156 ProxyLock::Release(); | 168 ProxyLock::Release(); |
| 157 } | 169 } |
| 158 | 170 |
| 159 protected: | 171 protected: |
| 160 bool FromV8ValueSync(v8::Handle<v8::Value> val, | 172 bool FromV8ValueSync(v8::Handle<v8::Value> val, |
| 161 v8::Handle<v8::Context> context, | 173 v8::Handle<v8::Context> context, |
| 162 PP_Var* result) { | 174 PP_Var* result) { |
| 163 V8VarConverter::FromV8Value(val, context, base::Bind( | 175 converter_->FromV8Value(val, context, base::Bind( |
| 164 &V8VarConverterTest::FromV8ValueComplete, base::Unretained(this)), | 176 &V8VarConverterTest::FromV8ValueComplete, base::Unretained(this))); |
| 165 callback_thread_.message_loop_proxy()); | |
| 166 conversion_event_.Wait(); | 177 conversion_event_.Wait(); |
| 167 conversion_event_.Reset(); | 178 conversion_event_.Reset(); |
| 168 if (conversion_success_) | 179 if (conversion_success_) |
| 169 *result = conversion_result_; | 180 *result = conversion_result_; |
| 170 return conversion_success_; | 181 return conversion_success_; |
| 171 } | 182 } |
| 172 | 183 |
| 173 void FromV8ValueComplete(const ScopedPPVar& scoped_var, bool success) { | 184 void FromV8ValueComplete(const ScopedPPVar& scoped_var, bool success) { |
| 174 conversion_success_ = success; | 185 conversion_success_ = success; |
| 175 if (success) { | 186 if (success) { |
| 176 ScopedPPVar var = scoped_var; | 187 ScopedPPVar var = scoped_var; |
| 177 conversion_result_ = var.Release(); | 188 conversion_result_ = var.Release(); |
| 178 } | 189 } |
| 179 conversion_event_.Signal(); | 190 conversion_event_.Signal(); |
| 180 } | 191 } |
| 181 | 192 |
| 182 bool RoundTrip(const PP_Var& var, PP_Var* result) { | 193 bool RoundTrip(const PP_Var& var, PP_Var* result) { |
| 183 v8::HandleScope handle_scope(isolate_); | 194 v8::HandleScope handle_scope(isolate_); |
| 184 v8::Context::Scope context_scope(isolate_, context_); | 195 v8::Context::Scope context_scope(isolate_, context_); |
| 185 v8::Local<v8::Context> context = | 196 v8::Local<v8::Context> context = |
| 186 v8::Local<v8::Context>::New(isolate_, context_); | 197 v8::Local<v8::Context>::New(isolate_, context_); |
| 187 v8::Handle<v8::Value> v8_result; | 198 v8::Handle<v8::Value> v8_result; |
| 188 if (!V8VarConverter::ToV8Value(var, context, &v8_result)) | 199 if (!converter_->ToV8Value(var, context, &v8_result)) |
| 189 return false; | 200 return false; |
| 190 if (!Equals(var, v8_result)) | 201 if (!Equals(var, v8_result)) |
| 191 return false; | 202 return false; |
| 192 if (!FromV8ValueSync(v8_result, context, result)) | 203 if (!FromV8ValueSync(v8_result, context, result)) |
| 193 return false; | 204 return false; |
| 194 return true; | 205 return true; |
| 195 } | 206 } |
| 196 | 207 |
| 197 // Assumes a ref for var. | 208 // Assumes a ref for var. |
| 198 bool RoundTripAndCompare(const PP_Var& var) { | 209 bool RoundTripAndCompare(const PP_Var& var) { |
| 199 ScopedPPVar expected(ScopedPPVar::PassRef(), var); | 210 ScopedPPVar expected(ScopedPPVar::PassRef(), var); |
| 200 PP_Var actual_var; | 211 PP_Var actual_var; |
| 201 if (!RoundTrip(expected.get(), &actual_var)) | 212 if (!RoundTrip(expected.get(), &actual_var)) |
| 202 return false; | 213 return false; |
| 203 ScopedPPVar actual(ScopedPPVar::PassRef(), actual_var); | 214 ScopedPPVar actual(ScopedPPVar::PassRef(), actual_var); |
| 204 return TestEqual(expected.get(), actual.get()); | 215 return TestEqual(expected.get(), actual.get()); |
| 205 } | 216 } |
| 206 | 217 |
| 207 v8::Isolate* isolate_; | 218 v8::Isolate* isolate_; |
| 208 | 219 |
| 209 // Context for the JavaScript in the test. | 220 // Context for the JavaScript in the test. |
| 210 v8::Persistent<v8::Context> context_; | 221 v8::Persistent<v8::Context> context_; |
| 211 | 222 |
| 223 scoped_ptr<V8VarConverter> converter_; |
| 224 |
| 212 private: | 225 private: |
| 213 TestGlobals globals_; | 226 TestGlobals globals_; |
| 214 | 227 |
| 215 PP_Var conversion_result_; | 228 PP_Var conversion_result_; |
| 216 bool conversion_success_; | 229 bool conversion_success_; |
| 217 base::WaitableEvent conversion_event_; | 230 base::WaitableEvent conversion_event_; |
| 218 base::Thread callback_thread_; | 231 base::Thread callback_thread_; |
| 219 }; | 232 }; |
| 220 | 233 |
| 221 } // namespace | 234 } // namespace |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 320 scoped_refptr<ArrayVar> array(new ArrayVar); | 333 scoped_refptr<ArrayVar> array(new ArrayVar); |
| 321 ScopedPPVar release_array(ScopedPPVar::PassRef(), array->GetPPVar()); | 334 ScopedPPVar release_array(ScopedPPVar::PassRef(), array->GetPPVar()); |
| 322 | 335 |
| 323 dictionary->SetWithStringKey("1", release_array.get()); | 336 dictionary->SetWithStringKey("1", release_array.get()); |
| 324 array->Set(0, release_dictionary.get()); | 337 array->Set(0, release_dictionary.get()); |
| 325 | 338 |
| 326 v8::Handle<v8::Value> v8_result; | 339 v8::Handle<v8::Value> v8_result; |
| 327 | 340 |
| 328 // Array <-> dictionary cycle. | 341 // Array <-> dictionary cycle. |
| 329 dictionary->SetWithStringKey("1", release_array.get()); | 342 dictionary->SetWithStringKey("1", release_array.get()); |
| 330 ASSERT_FALSE(V8VarConverter::ToV8Value(release_dictionary.get(), | 343 ASSERT_FALSE(converter_->ToV8Value(release_dictionary.get(), |
| 331 context, &v8_result)); | 344 context, &v8_result)); |
| 332 // Break the cycle. | 345 // Break the cycle. |
| 333 // TODO(raymes): We need some better machinery for releasing vars with | 346 // TODO(raymes): We need some better machinery for releasing vars with |
| 334 // cycles. Remove the code below once we have that. | 347 // cycles. Remove the code below once we have that. |
| 335 dictionary->DeleteWithStringKey("1"); | 348 dictionary->DeleteWithStringKey("1"); |
| 336 | 349 |
| 337 // Array with self reference. | 350 // Array with self reference. |
| 338 array->Set(0, release_array.get()); | 351 array->Set(0, release_array.get()); |
| 339 ASSERT_FALSE(V8VarConverter::ToV8Value(release_array.get(), | 352 ASSERT_FALSE(converter_->ToV8Value(release_array.get(), |
| 340 context, &v8_result)); | 353 context, &v8_result)); |
| 341 // Break the self reference. | 354 // Break the self reference. |
| 342 array->Set(0, PP_MakeUndefined()); | 355 array->Set(0, PP_MakeUndefined()); |
| 343 } | 356 } |
| 344 | 357 |
| 345 // V8->Var conversion. | 358 // V8->Var conversion. |
| 346 { | 359 { |
| 347 v8::Handle<v8::Object> object = v8::Object::New(); | 360 v8::Handle<v8::Object> object = v8::Object::New(); |
| 348 v8::Handle<v8::Array> array = v8::Array::New(); | 361 v8::Handle<v8::Array> array = v8::Array::New(); |
| 349 | 362 |
| 350 PP_Var var_result; | 363 PP_Var var_result; |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 410 ScopedPPVar oops(ScopedPPVar::PassRef(), StringVar::StringToPPVar("oops")); | 423 ScopedPPVar oops(ScopedPPVar::PassRef(), StringVar::StringToPPVar("oops")); |
| 411 expected->SetWithStringKey("undefined", oops.get()); | 424 expected->SetWithStringKey("undefined", oops.get()); |
| 412 ScopedPPVar release_expected( | 425 ScopedPPVar release_expected( |
| 413 ScopedPPVar::PassRef(), expected->GetPPVar()); | 426 ScopedPPVar::PassRef(), expected->GetPPVar()); |
| 414 | 427 |
| 415 ASSERT_TRUE(TestEqual(release_expected.get(), release_actual.get())); | 428 ASSERT_TRUE(TestEqual(release_expected.get(), release_actual.get())); |
| 416 } | 429 } |
| 417 } | 430 } |
| 418 | 431 |
| 419 } // namespace content | 432 } // namespace content |
| OLD | NEW |