| 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" |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 75 return it->second == val; | 75 return it->second == val; |
| 76 (*visited_ids)[var.value.as_id] = val; | 76 (*visited_ids)[var.value.as_id] = val; |
| 77 } | 77 } |
| 78 | 78 |
| 79 if (val->IsUndefined()) { | 79 if (val->IsUndefined()) { |
| 80 return var.type == PP_VARTYPE_UNDEFINED; | 80 return var.type == PP_VARTYPE_UNDEFINED; |
| 81 } else if (val->IsNull()) { | 81 } else if (val->IsNull()) { |
| 82 return var.type == PP_VARTYPE_NULL; | 82 return var.type == PP_VARTYPE_NULL; |
| 83 } else if (val->IsBoolean() || val->IsBooleanObject()) { | 83 } else if (val->IsBoolean() || val->IsBooleanObject()) { |
| 84 return var.type == PP_VARTYPE_BOOL && | 84 return var.type == PP_VARTYPE_BOOL && |
| 85 PP_FromBool(val->ToBoolean()->Value()) == var.value.as_bool; | 85 PP_FromBool(val->ToBoolean()->Value()) == var.value.as_bool; |
| 86 } else if (val->IsInt32()) { | 86 } else if (val->IsInt32()) { |
| 87 return var.type == PP_VARTYPE_INT32 && | 87 return var.type == PP_VARTYPE_INT32 && |
| 88 val->ToInt32()->Value() == var.value.as_int; | 88 val->ToInt32()->Value() == var.value.as_int; |
| 89 } else if (val->IsNumber() || val->IsNumberObject()) { | 89 } else if (val->IsNumber() || val->IsNumberObject()) { |
| 90 return var.type == PP_VARTYPE_DOUBLE && | 90 return var.type == PP_VARTYPE_DOUBLE && |
| 91 fabs(val->ToNumber()->Value() - var.value.as_double) <= 1.0e-4; | 91 fabs(val->ToNumber()->Value() - var.value.as_double) <= 1.0e-4; |
| 92 } else if (val->IsString() || val->IsStringObject()) { | 92 } else if (val->IsString() || val->IsStringObject()) { |
| 93 if (var.type != PP_VARTYPE_STRING) | 93 if (var.type != PP_VARTYPE_STRING) |
| 94 return false; | 94 return false; |
| 95 StringVar* string_var = StringVar::FromPPVar(var); | 95 StringVar* string_var = StringVar::FromPPVar(var); |
| 96 DCHECK(string_var); | 96 DCHECK(string_var); |
| 97 v8::String::Utf8Value utf8(val->ToString()); | 97 v8::String::Utf8Value utf8(val->ToString()); |
| 98 return std::string(*utf8, utf8.length()) == string_var->value(); | 98 return std::string(*utf8, utf8.length()) == string_var->value(); |
| 99 } else if (val->IsArray()) { | 99 } else if (val->IsArray()) { |
| 100 if (var.type != PP_VARTYPE_ARRAY) | 100 if (var.type != PP_VARTYPE_ARRAY) |
| 101 return false; | 101 return false; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 126 return false; | 126 return false; |
| 127 for (uint32 i = 0; i < property_names->Length(); ++i) { | 127 for (uint32 i = 0; i < property_names->Length(); ++i) { |
| 128 v8::Handle<v8::Value> key(property_names->Get(i)); | 128 v8::Handle<v8::Value> key(property_names->Get(i)); |
| 129 | 129 |
| 130 if (!key->IsString() && !key->IsNumber()) | 130 if (!key->IsString() && !key->IsNumber()) |
| 131 return false; | 131 return false; |
| 132 v8::Handle<v8::Value> child_v8 = v8_object->Get(key); | 132 v8::Handle<v8::Value> child_v8 = v8_object->Get(key); |
| 133 | 133 |
| 134 v8::String::Utf8Value name_utf8(key->ToString()); | 134 v8::String::Utf8Value name_utf8(key->ToString()); |
| 135 ScopedPPVar release_key(ScopedPPVar::PassRef(), | 135 ScopedPPVar release_key(ScopedPPVar::PassRef(), |
| 136 StringVar::StringToPPVar( | 136 StringVar::StringToPPVar(std::string( |
| 137 std::string(*name_utf8, name_utf8.length()))); | 137 *name_utf8, name_utf8.length()))); |
| 138 if (!dict_var->HasKey(release_key.get())) | 138 if (!dict_var->HasKey(release_key.get())) |
| 139 return false; | 139 return false; |
| 140 ScopedPPVar release_value(ScopedPPVar::PassRef(), | 140 ScopedPPVar release_value(ScopedPPVar::PassRef(), |
| 141 dict_var->Get(release_key.get())); | 141 dict_var->Get(release_key.get())); |
| 142 if (!Equals(release_value.get(), child_v8, visited_ids)) | 142 if (!Equals(release_value.get(), child_v8, visited_ids)) |
| 143 return false; | 143 return false; |
| 144 } | 144 } |
| 145 return true; | 145 return true; |
| 146 } | 146 } |
| 147 } | 147 } |
| 148 return false; | 148 return false; |
| 149 } | 149 } |
| 150 | 150 |
| 151 bool Equals(const PP_Var& var, | 151 bool Equals(const PP_Var& var, v8::Handle<v8::Value> val) { |
| 152 v8::Handle<v8::Value> val) { | |
| 153 VarHandleMap var_handle_map; | 152 VarHandleMap var_handle_map; |
| 154 return Equals(var, val, &var_handle_map); | 153 return Equals(var, val, &var_handle_map); |
| 155 } | 154 } |
| 156 | 155 |
| 157 class V8VarConverterTest : public testing::Test { | 156 class V8VarConverterTest : public testing::Test { |
| 158 public: | 157 public: |
| 159 V8VarConverterTest() | 158 V8VarConverterTest() |
| 160 : isolate_(v8::Isolate::GetCurrent()), | 159 : isolate_(v8::Isolate::GetCurrent()), conversion_success_(false) { |
| 161 conversion_success_(false) { | |
| 162 PP_Instance dummy = 1234; | 160 PP_Instance dummy = 1234; |
| 163 converter_.reset(new V8VarConverter( | 161 converter_.reset(new V8VarConverter( |
| 164 dummy, | 162 dummy, |
| 165 scoped_ptr<ResourceConverter>(new MockResourceConverter).Pass())); | 163 scoped_ptr<ResourceConverter>(new MockResourceConverter).Pass())); |
| 166 } | 164 } |
| 167 virtual ~V8VarConverterTest() {} | 165 virtual ~V8VarConverterTest() {} |
| 168 | 166 |
| 169 // testing::Test implementation. | 167 // testing::Test implementation. |
| 170 virtual void SetUp() { | 168 virtual void SetUp() { |
| 171 ProxyLock::Acquire(); | 169 ProxyLock::Acquire(); |
| 172 v8::HandleScope handle_scope(isolate_); | 170 v8::HandleScope handle_scope(isolate_); |
| 173 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate_); | 171 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate_); |
| 174 context_.Reset(isolate_, v8::Context::New(isolate_, NULL, global)); | 172 context_.Reset(isolate_, v8::Context::New(isolate_, NULL, global)); |
| 175 } | 173 } |
| 176 virtual void TearDown() { | 174 virtual void TearDown() { |
| 177 context_.Reset(); | 175 context_.Reset(); |
| 178 ASSERT_TRUE(PpapiGlobals::Get()->GetVarTracker()->GetLiveVars().empty()); | 176 ASSERT_TRUE(PpapiGlobals::Get()->GetVarTracker()->GetLiveVars().empty()); |
| 179 ProxyLock::Release(); | 177 ProxyLock::Release(); |
| 180 } | 178 } |
| 181 | 179 |
| 182 protected: | 180 protected: |
| 183 bool FromV8ValueSync(v8::Handle<v8::Value> val, | 181 bool FromV8ValueSync(v8::Handle<v8::Value> val, |
| 184 v8::Handle<v8::Context> context, | 182 v8::Handle<v8::Context> context, |
| 185 PP_Var* result) { | 183 PP_Var* result) { |
| 186 base::RunLoop loop; | 184 base::RunLoop loop; |
| 187 converter_->FromV8Value(val, context, base::Bind( | 185 converter_->FromV8Value(val, |
| 188 &V8VarConverterTest::FromV8ValueComplete, base::Unretained(this), | 186 context, |
| 189 loop.QuitClosure())); | 187 base::Bind(&V8VarConverterTest::FromV8ValueComplete, |
| 188 base::Unretained(this), |
| 189 loop.QuitClosure())); |
| 190 loop.Run(); | 190 loop.Run(); |
| 191 if (conversion_success_) | 191 if (conversion_success_) |
| 192 *result = conversion_result_; | 192 *result = conversion_result_; |
| 193 return conversion_success_; | 193 return conversion_success_; |
| 194 } | 194 } |
| 195 | 195 |
| 196 void FromV8ValueComplete(base::Closure quit_closure, | 196 void FromV8ValueComplete(base::Closure quit_closure, |
| 197 const ScopedPPVar& scoped_var, | 197 const ScopedPPVar& scoped_var, |
| 198 bool success) { | 198 bool success) { |
| 199 conversion_success_ = success; | 199 conversion_success_ = success; |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 274 | 274 |
| 275 // Array with primitives. | 275 // Array with primitives. |
| 276 array->Set(index++, PP_MakeUndefined()); | 276 array->Set(index++, PP_MakeUndefined()); |
| 277 array->Set(index++, PP_MakeNull()); | 277 array->Set(index++, PP_MakeNull()); |
| 278 array->Set(index++, PP_MakeInt32(100)); | 278 array->Set(index++, PP_MakeInt32(100)); |
| 279 array->Set(index++, PP_MakeBool(PP_FALSE)); | 279 array->Set(index++, PP_MakeBool(PP_FALSE)); |
| 280 array->Set(index++, PP_MakeDouble(0.123)); | 280 array->Set(index++, PP_MakeDouble(0.123)); |
| 281 EXPECT_TRUE(RoundTripAndCompare(array->GetPPVar())); | 281 EXPECT_TRUE(RoundTripAndCompare(array->GetPPVar())); |
| 282 | 282 |
| 283 // Array with 2 references to the same string. | 283 // Array with 2 references to the same string. |
| 284 ScopedPPVar release_string( | 284 ScopedPPVar release_string(ScopedPPVar::PassRef(), |
| 285 ScopedPPVar::PassRef(), StringVar::StringToPPVar("abc")); | 285 StringVar::StringToPPVar("abc")); |
| 286 array->Set(index++, release_string.get()); | 286 array->Set(index++, release_string.get()); |
| 287 array->Set(index++, release_string.get()); | 287 array->Set(index++, release_string.get()); |
| 288 EXPECT_TRUE(RoundTripAndCompare(array->GetPPVar())); | 288 EXPECT_TRUE(RoundTripAndCompare(array->GetPPVar())); |
| 289 | 289 |
| 290 // Array with nested array that references the same string. | 290 // Array with nested array that references the same string. |
| 291 scoped_refptr<ArrayVar> array2(new ArrayVar); | 291 scoped_refptr<ArrayVar> array2(new ArrayVar); |
| 292 ScopedPPVar release_array2(ScopedPPVar::PassRef(), array2->GetPPVar()); | 292 ScopedPPVar release_array2(ScopedPPVar::PassRef(), array2->GetPPVar()); |
| 293 array2->Set(0, release_string.get()); | 293 array2->Set(0, release_string.get()); |
| 294 array->Set(index++, release_array2.get()); | 294 array->Set(index++, release_array2.get()); |
| 295 EXPECT_TRUE(RoundTripAndCompare(array->GetPPVar())); | 295 EXPECT_TRUE(RoundTripAndCompare(array->GetPPVar())); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 346 scoped_refptr<ArrayVar> array(new ArrayVar); | 346 scoped_refptr<ArrayVar> array(new ArrayVar); |
| 347 ScopedPPVar release_array(ScopedPPVar::PassRef(), array->GetPPVar()); | 347 ScopedPPVar release_array(ScopedPPVar::PassRef(), array->GetPPVar()); |
| 348 | 348 |
| 349 dictionary->SetWithStringKey("1", release_array.get()); | 349 dictionary->SetWithStringKey("1", release_array.get()); |
| 350 array->Set(0, release_dictionary.get()); | 350 array->Set(0, release_dictionary.get()); |
| 351 | 351 |
| 352 v8::Handle<v8::Value> v8_result; | 352 v8::Handle<v8::Value> v8_result; |
| 353 | 353 |
| 354 // Array <-> dictionary cycle. | 354 // Array <-> dictionary cycle. |
| 355 dictionary->SetWithStringKey("1", release_array.get()); | 355 dictionary->SetWithStringKey("1", release_array.get()); |
| 356 ASSERT_FALSE(converter_->ToV8Value(release_dictionary.get(), | 356 ASSERT_FALSE( |
| 357 context, &v8_result)); | 357 converter_->ToV8Value(release_dictionary.get(), context, &v8_result)); |
| 358 // Break the cycle. | 358 // Break the cycle. |
| 359 // TODO(raymes): We need some better machinery for releasing vars with | 359 // TODO(raymes): We need some better machinery for releasing vars with |
| 360 // cycles. Remove the code below once we have that. | 360 // cycles. Remove the code below once we have that. |
| 361 dictionary->DeleteWithStringKey("1"); | 361 dictionary->DeleteWithStringKey("1"); |
| 362 | 362 |
| 363 // Array with self reference. | 363 // Array with self reference. |
| 364 array->Set(0, release_array.get()); | 364 array->Set(0, release_array.get()); |
| 365 ASSERT_FALSE(converter_->ToV8Value(release_array.get(), | 365 ASSERT_FALSE( |
| 366 context, &v8_result)); | 366 converter_->ToV8Value(release_array.get(), context, &v8_result)); |
| 367 // Break the self reference. | 367 // Break the self reference. |
| 368 array->Set(0, PP_MakeUndefined()); | 368 array->Set(0, PP_MakeUndefined()); |
| 369 } | 369 } |
| 370 | 370 |
| 371 // V8->Var conversion. | 371 // V8->Var conversion. |
| 372 { | 372 { |
| 373 v8::Handle<v8::Object> object = v8::Object::New(isolate_); | 373 v8::Handle<v8::Object> object = v8::Object::New(isolate_); |
| 374 v8::Handle<v8::Array> array = v8::Array::New(isolate_); | 374 v8::Handle<v8::Array> array = v8::Array::New(isolate_); |
| 375 | 375 |
| 376 PP_Var var_result; | 376 PP_Var var_result; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 400 EXPECT_TRUE(RoundTripAndCompare(dictionary->GetPPVar())); | 400 EXPECT_TRUE(RoundTripAndCompare(dictionary->GetPPVar())); |
| 401 } | 401 } |
| 402 | 402 |
| 403 { | 403 { |
| 404 // Test non-string key types. They should be cast to strings. | 404 // Test non-string key types. They should be cast to strings. |
| 405 v8::HandleScope handle_scope(isolate_); | 405 v8::HandleScope handle_scope(isolate_); |
| 406 v8::Local<v8::Context> context = | 406 v8::Local<v8::Context> context = |
| 407 v8::Local<v8::Context>::New(isolate_, context_); | 407 v8::Local<v8::Context>::New(isolate_, context_); |
| 408 v8::Context::Scope context_scope(context); | 408 v8::Context::Scope context_scope(context); |
| 409 | 409 |
| 410 const char* source = "(function() {" | 410 const char* source = |
| 411 "(function() {" |
| 411 "return {" | 412 "return {" |
| 412 "1: 'foo'," | 413 "1: 'foo'," |
| 413 "'2': 'bar'," | 414 "'2': 'bar'," |
| 414 "true: 'baz'," | 415 "true: 'baz'," |
| 415 "false: 'qux'," | 416 "false: 'qux'," |
| 416 "null: 'quux'," | 417 "null: 'quux'," |
| 417 "undefined: 'oops'" | 418 "undefined: 'oops'" |
| 418 "};" | 419 "};" |
| 419 "})();"; | 420 "})();"; |
| 420 | 421 |
| 421 v8::Handle<v8::Script> script( | 422 v8::Handle<v8::Script> script( |
| 422 v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source))); | 423 v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source))); |
| 423 v8::Handle<v8::Object> object = script->Run().As<v8::Object>(); | 424 v8::Handle<v8::Object> object = script->Run().As<v8::Object>(); |
| 424 ASSERT_FALSE(object.IsEmpty()); | 425 ASSERT_FALSE(object.IsEmpty()); |
| 425 | 426 |
| 426 PP_Var actual; | 427 PP_Var actual; |
| 427 ASSERT_TRUE(FromV8ValueSync(object, | 428 ASSERT_TRUE(FromV8ValueSync( |
| 428 v8::Local<v8::Context>::New(isolate_, context_), &actual)); | 429 object, v8::Local<v8::Context>::New(isolate_, context_), &actual)); |
| 429 ScopedPPVar release_actual(ScopedPPVar::PassRef(), actual); | 430 ScopedPPVar release_actual(ScopedPPVar::PassRef(), actual); |
| 430 | 431 |
| 431 scoped_refptr<DictionaryVar> expected(new DictionaryVar); | 432 scoped_refptr<DictionaryVar> expected(new DictionaryVar); |
| 432 ScopedPPVar foo(ScopedPPVar::PassRef(), StringVar::StringToPPVar("foo")); | 433 ScopedPPVar foo(ScopedPPVar::PassRef(), StringVar::StringToPPVar("foo")); |
| 433 expected->SetWithStringKey("1", foo.get()); | 434 expected->SetWithStringKey("1", foo.get()); |
| 434 ScopedPPVar bar(ScopedPPVar::PassRef(), StringVar::StringToPPVar("bar")); | 435 ScopedPPVar bar(ScopedPPVar::PassRef(), StringVar::StringToPPVar("bar")); |
| 435 expected->SetWithStringKey("2", bar.get()); | 436 expected->SetWithStringKey("2", bar.get()); |
| 436 ScopedPPVar baz(ScopedPPVar::PassRef(), StringVar::StringToPPVar("baz")); | 437 ScopedPPVar baz(ScopedPPVar::PassRef(), StringVar::StringToPPVar("baz")); |
| 437 expected->SetWithStringKey("true", baz.get()); | 438 expected->SetWithStringKey("true", baz.get()); |
| 438 ScopedPPVar qux(ScopedPPVar::PassRef(), StringVar::StringToPPVar("qux")); | 439 ScopedPPVar qux(ScopedPPVar::PassRef(), StringVar::StringToPPVar("qux")); |
| 439 expected->SetWithStringKey("false", qux.get()); | 440 expected->SetWithStringKey("false", qux.get()); |
| 440 ScopedPPVar quux(ScopedPPVar::PassRef(), StringVar::StringToPPVar("quux")); | 441 ScopedPPVar quux(ScopedPPVar::PassRef(), StringVar::StringToPPVar("quux")); |
| 441 expected->SetWithStringKey("null", quux.get()); | 442 expected->SetWithStringKey("null", quux.get()); |
| 442 ScopedPPVar oops(ScopedPPVar::PassRef(), StringVar::StringToPPVar("oops")); | 443 ScopedPPVar oops(ScopedPPVar::PassRef(), StringVar::StringToPPVar("oops")); |
| 443 expected->SetWithStringKey("undefined", oops.get()); | 444 expected->SetWithStringKey("undefined", oops.get()); |
| 444 ScopedPPVar release_expected( | 445 ScopedPPVar release_expected(ScopedPPVar::PassRef(), expected->GetPPVar()); |
| 445 ScopedPPVar::PassRef(), expected->GetPPVar()); | |
| 446 | 446 |
| 447 ASSERT_TRUE(TestEqual(release_expected.get(), release_actual.get(), true)); | 447 ASSERT_TRUE(TestEqual(release_expected.get(), release_actual.get(), true)); |
| 448 } | 448 } |
| 449 } | 449 } |
| 450 | 450 |
| 451 } // namespace content | 451 } // namespace content |
| OLD | NEW |