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 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
49 } | 49 } |
50 | 50 |
51 class MockResourceConverter : public content::ResourceConverter { | 51 class MockResourceConverter : public content::ResourceConverter { |
52 public: | 52 public: |
53 ~MockResourceConverter() override {} | 53 ~MockResourceConverter() override {} |
54 void Reset() override {} | 54 void Reset() override {} |
55 bool NeedsFlush() override { return false; } | 55 bool NeedsFlush() override { return false; } |
56 void Flush(const base::Callback<void(bool)>& callback) override { | 56 void Flush(const base::Callback<void(bool)>& callback) override { |
57 NOTREACHED(); | 57 NOTREACHED(); |
58 } | 58 } |
59 bool FromV8Value(v8::Handle<v8::Object> val, | 59 bool FromV8Value(v8::Local<v8::Object> val, |
60 v8::Handle<v8::Context> context, | 60 v8::Local<v8::Context> context, |
61 PP_Var* result, | 61 PP_Var* result, |
62 bool* was_resource) override { | 62 bool* was_resource) override { |
63 *was_resource = false; | 63 *was_resource = false; |
64 return true; | 64 return true; |
65 } | 65 } |
66 bool ToV8Value(const PP_Var& var, | 66 bool ToV8Value(const PP_Var& var, |
67 v8::Handle<v8::Context> context, | 67 v8::Local<v8::Context> context, |
68 v8::Handle<v8::Value>* result) override { | 68 v8::Local<v8::Value>* result) override { |
69 return false; | 69 return false; |
70 } | 70 } |
71 }; | 71 }; |
72 | 72 |
73 // Maps PP_Var IDs to the V8 value handle they correspond to. | 73 // Maps PP_Var IDs to the V8 value handle they correspond to. |
74 typedef base::hash_map<int64_t, v8::Handle<v8::Value> > VarHandleMap; | 74 typedef base::hash_map<int64_t, v8::Local<v8::Value> > VarHandleMap; |
75 | 75 |
76 bool Equals(const PP_Var& var, | 76 bool Equals(const PP_Var& var, |
77 v8::Handle<v8::Value> val, | 77 v8::Local<v8::Value> val, |
78 VarHandleMap* visited_ids) { | 78 VarHandleMap* visited_ids) { |
79 if (ppapi::VarTracker::IsVarTypeRefcounted(var.type)) { | 79 if (ppapi::VarTracker::IsVarTypeRefcounted(var.type)) { |
80 VarHandleMap::iterator it = visited_ids->find(var.value.as_id); | 80 VarHandleMap::iterator it = visited_ids->find(var.value.as_id); |
81 if (it != visited_ids->end()) | 81 if (it != visited_ids->end()) |
82 return it->second == val; | 82 return it->second == val; |
83 (*visited_ids)[var.value.as_id] = val; | 83 (*visited_ids)[var.value.as_id] = val; |
84 } | 84 } |
85 | 85 |
86 v8::Isolate* isolate = v8::Isolate::GetCurrent(); | 86 v8::Isolate* isolate = v8::Isolate::GetCurrent(); |
87 if (val->IsUndefined()) { | 87 if (val->IsUndefined()) { |
(...skipping 15 matching lines...) Expand all Loading... |
103 return false; | 103 return false; |
104 StringVar* string_var = StringVar::FromPPVar(var); | 104 StringVar* string_var = StringVar::FromPPVar(var); |
105 DCHECK(string_var); | 105 DCHECK(string_var); |
106 v8::String::Utf8Value utf8(val); | 106 v8::String::Utf8Value utf8(val); |
107 return std::string(*utf8, utf8.length()) == string_var->value(); | 107 return std::string(*utf8, utf8.length()) == string_var->value(); |
108 } else if (val->IsArray()) { | 108 } else if (val->IsArray()) { |
109 if (var.type != PP_VARTYPE_ARRAY) | 109 if (var.type != PP_VARTYPE_ARRAY) |
110 return false; | 110 return false; |
111 ArrayVar* array_var = ArrayVar::FromPPVar(var); | 111 ArrayVar* array_var = ArrayVar::FromPPVar(var); |
112 DCHECK(array_var); | 112 DCHECK(array_var); |
113 v8::Handle<v8::Array> v8_array = val.As<v8::Array>(); | 113 v8::Local<v8::Array> v8_array = val.As<v8::Array>(); |
114 if (v8_array->Length() != array_var->elements().size()) | 114 if (v8_array->Length() != array_var->elements().size()) |
115 return false; | 115 return false; |
116 for (uint32 i = 0; i < v8_array->Length(); ++i) { | 116 for (uint32 i = 0; i < v8_array->Length(); ++i) { |
117 v8::Handle<v8::Value> child_v8 = v8_array->Get(i); | 117 v8::Local<v8::Value> child_v8 = v8_array->Get(i); |
118 if (!Equals(array_var->elements()[i].get(), child_v8, visited_ids)) | 118 if (!Equals(array_var->elements()[i].get(), child_v8, visited_ids)) |
119 return false; | 119 return false; |
120 } | 120 } |
121 return true; | 121 return true; |
122 } else if (val->IsObject()) { | 122 } else if (val->IsObject()) { |
123 if (var.type == PP_VARTYPE_ARRAY_BUFFER) { | 123 if (var.type == PP_VARTYPE_ARRAY_BUFFER) { |
124 // TODO(raymes): Implement this when we have tests for array buffers. | 124 // TODO(raymes): Implement this when we have tests for array buffers. |
125 NOTIMPLEMENTED(); | 125 NOTIMPLEMENTED(); |
126 return false; | 126 return false; |
127 } else { | 127 } else { |
128 v8::Handle<v8::Object> v8_object = val.As<v8::Object>(); | 128 v8::Local<v8::Object> v8_object = val.As<v8::Object>(); |
129 if (var.type != PP_VARTYPE_DICTIONARY) | 129 if (var.type != PP_VARTYPE_DICTIONARY) |
130 return false; | 130 return false; |
131 DictionaryVar* dict_var = DictionaryVar::FromPPVar(var); | 131 DictionaryVar* dict_var = DictionaryVar::FromPPVar(var); |
132 DCHECK(dict_var); | 132 DCHECK(dict_var); |
133 v8::Handle<v8::Array> property_names(v8_object->GetOwnPropertyNames()); | 133 v8::Local<v8::Array> property_names(v8_object->GetOwnPropertyNames()); |
134 if (property_names->Length() != dict_var->key_value_map().size()) | 134 if (property_names->Length() != dict_var->key_value_map().size()) |
135 return false; | 135 return false; |
136 for (uint32 i = 0; i < property_names->Length(); ++i) { | 136 for (uint32 i = 0; i < property_names->Length(); ++i) { |
137 v8::Handle<v8::Value> key(property_names->Get(i)); | 137 v8::Local<v8::Value> key(property_names->Get(i)); |
138 | 138 |
139 if (!key->IsString() && !key->IsNumber()) | 139 if (!key->IsString() && !key->IsNumber()) |
140 return false; | 140 return false; |
141 v8::Handle<v8::Value> child_v8 = v8_object->Get(key); | 141 v8::Local<v8::Value> child_v8 = v8_object->Get(key); |
142 | 142 |
143 v8::String::Utf8Value name_utf8(key); | 143 v8::String::Utf8Value name_utf8(key); |
144 ScopedPPVar release_key(ScopedPPVar::PassRef(), | 144 ScopedPPVar release_key(ScopedPPVar::PassRef(), |
145 StringVar::StringToPPVar(std::string( | 145 StringVar::StringToPPVar(std::string( |
146 *name_utf8, name_utf8.length()))); | 146 *name_utf8, name_utf8.length()))); |
147 if (!dict_var->HasKey(release_key.get())) | 147 if (!dict_var->HasKey(release_key.get())) |
148 return false; | 148 return false; |
149 ScopedPPVar release_value(ScopedPPVar::PassRef(), | 149 ScopedPPVar release_value(ScopedPPVar::PassRef(), |
150 dict_var->Get(release_key.get())); | 150 dict_var->Get(release_key.get())); |
151 if (!Equals(release_value.get(), child_v8, visited_ids)) | 151 if (!Equals(release_value.get(), child_v8, visited_ids)) |
152 return false; | 152 return false; |
153 } | 153 } |
154 return true; | 154 return true; |
155 } | 155 } |
156 } | 156 } |
157 return false; | 157 return false; |
158 } | 158 } |
159 | 159 |
160 bool Equals(const PP_Var& var, v8::Handle<v8::Value> val) { | 160 bool Equals(const PP_Var& var, v8::Local<v8::Value> val) { |
161 VarHandleMap var_handle_map; | 161 VarHandleMap var_handle_map; |
162 return Equals(var, val, &var_handle_map); | 162 return Equals(var, val, &var_handle_map); |
163 } | 163 } |
164 | 164 |
165 class V8VarConverterTest : public testing::Test { | 165 class V8VarConverterTest : public testing::Test { |
166 public: | 166 public: |
167 V8VarConverterTest() | 167 V8VarConverterTest() |
168 : isolate_(v8::Isolate::GetCurrent()) { | 168 : isolate_(v8::Isolate::GetCurrent()) { |
169 PP_Instance dummy = 1234; | 169 PP_Instance dummy = 1234; |
170 converter_.reset(new V8VarConverter( | 170 converter_.reset(new V8VarConverter( |
171 dummy, | 171 dummy, |
172 scoped_ptr<ResourceConverter>(new MockResourceConverter).Pass())); | 172 scoped_ptr<ResourceConverter>(new MockResourceConverter).Pass())); |
173 } | 173 } |
174 ~V8VarConverterTest() override {} | 174 ~V8VarConverterTest() override {} |
175 | 175 |
176 // testing::Test implementation. | 176 // testing::Test implementation. |
177 void SetUp() override { | 177 void SetUp() override { |
178 ProxyLock::Acquire(); | 178 ProxyLock::Acquire(); |
179 v8::HandleScope handle_scope(isolate_); | 179 v8::HandleScope handle_scope(isolate_); |
180 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate_); | 180 v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate_); |
181 context_.Reset(isolate_, v8::Context::New(isolate_, NULL, global)); | 181 context_.Reset(isolate_, v8::Context::New(isolate_, NULL, global)); |
182 } | 182 } |
183 void TearDown() override { | 183 void TearDown() override { |
184 context_.Reset(); | 184 context_.Reset(); |
185 ASSERT_TRUE(PpapiGlobals::Get()->GetVarTracker()->GetLiveVars().empty()); | 185 ASSERT_TRUE(PpapiGlobals::Get()->GetVarTracker()->GetLiveVars().empty()); |
186 ProxyLock::Release(); | 186 ProxyLock::Release(); |
187 } | 187 } |
188 | 188 |
189 protected: | 189 protected: |
190 bool FromV8ValueSync(v8::Handle<v8::Value> val, | 190 bool FromV8ValueSync(v8::Local<v8::Value> val, |
191 v8::Handle<v8::Context> context, | 191 v8::Local<v8::Context> context, |
192 PP_Var* result) { | 192 PP_Var* result) { |
193 V8VarConverter::VarResult conversion_result = | 193 V8VarConverter::VarResult conversion_result = |
194 converter_->FromV8Value(val, | 194 converter_->FromV8Value(val, |
195 context, | 195 context, |
196 base::Bind(&FromV8ValueComplete)); | 196 base::Bind(&FromV8ValueComplete)); |
197 DCHECK(conversion_result.completed_synchronously); | 197 DCHECK(conversion_result.completed_synchronously); |
198 if (conversion_result.success) | 198 if (conversion_result.success) |
199 *result = conversion_result.var.Release(); | 199 *result = conversion_result.var.Release(); |
200 | 200 |
201 return conversion_result.success; | 201 return conversion_result.success; |
202 } | 202 } |
203 | 203 |
204 bool RoundTrip(const PP_Var& var, PP_Var* result) { | 204 bool RoundTrip(const PP_Var& var, PP_Var* result) { |
205 v8::HandleScope handle_scope(isolate_); | 205 v8::HandleScope handle_scope(isolate_); |
206 v8::Local<v8::Context> context = | 206 v8::Local<v8::Context> context = |
207 v8::Local<v8::Context>::New(isolate_, context_); | 207 v8::Local<v8::Context>::New(isolate_, context_); |
208 v8::Context::Scope context_scope(context); | 208 v8::Context::Scope context_scope(context); |
209 v8::Handle<v8::Value> v8_result; | 209 v8::Local<v8::Value> v8_result; |
210 if (!converter_->ToV8Value(var, context, &v8_result)) | 210 if (!converter_->ToV8Value(var, context, &v8_result)) |
211 return false; | 211 return false; |
212 if (!Equals(var, v8_result)) | 212 if (!Equals(var, v8_result)) |
213 return false; | 213 return false; |
214 if (!FromV8ValueSync(v8_result, context, result)) | 214 if (!FromV8ValueSync(v8_result, context, result)) |
215 return false; | 215 return false; |
216 return true; | 216 return true; |
217 } | 217 } |
218 | 218 |
219 // Assumes a ref for var. | 219 // Assumes a ref for var. |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
337 { | 337 { |
338 scoped_refptr<DictionaryVar> dictionary(new DictionaryVar); | 338 scoped_refptr<DictionaryVar> dictionary(new DictionaryVar); |
339 ScopedPPVar release_dictionary(ScopedPPVar::PassRef(), | 339 ScopedPPVar release_dictionary(ScopedPPVar::PassRef(), |
340 dictionary->GetPPVar()); | 340 dictionary->GetPPVar()); |
341 scoped_refptr<ArrayVar> array(new ArrayVar); | 341 scoped_refptr<ArrayVar> array(new ArrayVar); |
342 ScopedPPVar release_array(ScopedPPVar::PassRef(), array->GetPPVar()); | 342 ScopedPPVar release_array(ScopedPPVar::PassRef(), array->GetPPVar()); |
343 | 343 |
344 dictionary->SetWithStringKey("1", release_array.get()); | 344 dictionary->SetWithStringKey("1", release_array.get()); |
345 array->Set(0, release_dictionary.get()); | 345 array->Set(0, release_dictionary.get()); |
346 | 346 |
347 v8::Handle<v8::Value> v8_result; | 347 v8::Local<v8::Value> v8_result; |
348 | 348 |
349 // Array <-> dictionary cycle. | 349 // Array <-> dictionary cycle. |
350 dictionary->SetWithStringKey("1", release_array.get()); | 350 dictionary->SetWithStringKey("1", release_array.get()); |
351 ASSERT_FALSE( | 351 ASSERT_FALSE( |
352 converter_->ToV8Value(release_dictionary.get(), context, &v8_result)); | 352 converter_->ToV8Value(release_dictionary.get(), context, &v8_result)); |
353 // Break the cycle. | 353 // Break the cycle. |
354 // TODO(raymes): We need some better machinery for releasing vars with | 354 // TODO(raymes): We need some better machinery for releasing vars with |
355 // cycles. Remove the code below once we have that. | 355 // cycles. Remove the code below once we have that. |
356 dictionary->DeleteWithStringKey("1"); | 356 dictionary->DeleteWithStringKey("1"); |
357 | 357 |
358 // Array with self reference. | 358 // Array with self reference. |
359 array->Set(0, release_array.get()); | 359 array->Set(0, release_array.get()); |
360 ASSERT_FALSE( | 360 ASSERT_FALSE( |
361 converter_->ToV8Value(release_array.get(), context, &v8_result)); | 361 converter_->ToV8Value(release_array.get(), context, &v8_result)); |
362 // Break the self reference. | 362 // Break the self reference. |
363 array->Set(0, PP_MakeUndefined()); | 363 array->Set(0, PP_MakeUndefined()); |
364 } | 364 } |
365 | 365 |
366 // V8->Var conversion. | 366 // V8->Var conversion. |
367 { | 367 { |
368 v8::Handle<v8::Object> object = v8::Object::New(isolate_); | 368 v8::Local<v8::Object> object = v8::Object::New(isolate_); |
369 v8::Handle<v8::Array> array = v8::Array::New(isolate_); | 369 v8::Local<v8::Array> array = v8::Array::New(isolate_); |
370 | 370 |
371 PP_Var var_result; | 371 PP_Var var_result; |
372 | 372 |
373 // Array <-> dictionary cycle. | 373 // Array <-> dictionary cycle. |
374 std::string key = "1"; | 374 std::string key = "1"; |
375 object->Set( | 375 object->Set( |
376 v8::String::NewFromUtf8( | 376 v8::String::NewFromUtf8( |
377 isolate_, key.c_str(), v8::String::kNormalString, key.length()), | 377 isolate_, key.c_str(), v8::String::kNormalString, key.length()), |
378 array); | 378 array); |
379 array->Set(0, object); | 379 array->Set(0, object); |
(...skipping 27 matching lines...) Expand all Loading... |
407 "return {" | 407 "return {" |
408 "1: 'foo'," | 408 "1: 'foo'," |
409 "'2': 'bar'," | 409 "'2': 'bar'," |
410 "true: 'baz'," | 410 "true: 'baz'," |
411 "false: 'qux'," | 411 "false: 'qux'," |
412 "null: 'quux'," | 412 "null: 'quux'," |
413 "undefined: 'oops'" | 413 "undefined: 'oops'" |
414 "};" | 414 "};" |
415 "})();"; | 415 "})();"; |
416 | 416 |
417 v8::Handle<v8::Script> script( | 417 v8::Local<v8::Script> script( |
418 v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source))); | 418 v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source))); |
419 v8::Handle<v8::Object> object = script->Run().As<v8::Object>(); | 419 v8::Local<v8::Object> object = script->Run().As<v8::Object>(); |
420 ASSERT_FALSE(object.IsEmpty()); | 420 ASSERT_FALSE(object.IsEmpty()); |
421 | 421 |
422 PP_Var actual; | 422 PP_Var actual; |
423 ASSERT_TRUE(FromV8ValueSync( | 423 ASSERT_TRUE(FromV8ValueSync( |
424 object, v8::Local<v8::Context>::New(isolate_, context_), &actual)); | 424 object, v8::Local<v8::Context>::New(isolate_, context_), &actual)); |
425 ScopedPPVar release_actual(ScopedPPVar::PassRef(), actual); | 425 ScopedPPVar release_actual(ScopedPPVar::PassRef(), actual); |
426 | 426 |
427 scoped_refptr<DictionaryVar> expected(new DictionaryVar); | 427 scoped_refptr<DictionaryVar> expected(new DictionaryVar); |
428 ScopedPPVar foo(ScopedPPVar::PassRef(), StringVar::StringToPPVar("foo")); | 428 ScopedPPVar foo(ScopedPPVar::PassRef(), StringVar::StringToPPVar("foo")); |
429 expected->SetWithStringKey("1", foo.get()); | 429 expected->SetWithStringKey("1", foo.get()); |
430 ScopedPPVar bar(ScopedPPVar::PassRef(), StringVar::StringToPPVar("bar")); | 430 ScopedPPVar bar(ScopedPPVar::PassRef(), StringVar::StringToPPVar("bar")); |
431 expected->SetWithStringKey("2", bar.get()); | 431 expected->SetWithStringKey("2", bar.get()); |
432 ScopedPPVar baz(ScopedPPVar::PassRef(), StringVar::StringToPPVar("baz")); | 432 ScopedPPVar baz(ScopedPPVar::PassRef(), StringVar::StringToPPVar("baz")); |
433 expected->SetWithStringKey("true", baz.get()); | 433 expected->SetWithStringKey("true", baz.get()); |
434 ScopedPPVar qux(ScopedPPVar::PassRef(), StringVar::StringToPPVar("qux")); | 434 ScopedPPVar qux(ScopedPPVar::PassRef(), StringVar::StringToPPVar("qux")); |
435 expected->SetWithStringKey("false", qux.get()); | 435 expected->SetWithStringKey("false", qux.get()); |
436 ScopedPPVar quux(ScopedPPVar::PassRef(), StringVar::StringToPPVar("quux")); | 436 ScopedPPVar quux(ScopedPPVar::PassRef(), StringVar::StringToPPVar("quux")); |
437 expected->SetWithStringKey("null", quux.get()); | 437 expected->SetWithStringKey("null", quux.get()); |
438 ScopedPPVar oops(ScopedPPVar::PassRef(), StringVar::StringToPPVar("oops")); | 438 ScopedPPVar oops(ScopedPPVar::PassRef(), StringVar::StringToPPVar("oops")); |
439 expected->SetWithStringKey("undefined", oops.get()); | 439 expected->SetWithStringKey("undefined", oops.get()); |
440 ScopedPPVar release_expected(ScopedPPVar::PassRef(), expected->GetPPVar()); | 440 ScopedPPVar release_expected(ScopedPPVar::PassRef(), expected->GetPPVar()); |
441 | 441 |
442 ASSERT_TRUE(TestEqual(release_expected.get(), release_actual.get(), true)); | 442 ASSERT_TRUE(TestEqual(release_expected.get(), release_actual.get(), true)); |
443 } | 443 } |
444 } | 444 } |
445 | 445 |
446 } // namespace content | 446 } // namespace content |
OLD | NEW |