| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 <map> | 7 #include <map> |
| 8 #include <stack> | 8 #include <stack> |
| 9 #include <string> | 9 #include <string> |
| 10 | 10 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 47 bool operator<(const HashedHandle& h) const { return hash() < h.hash(); } | 47 bool operator<(const HashedHandle& h) const { return hash() < h.hash(); } |
| 48 v8::Handle<v8::Object> handle; | 48 v8::Handle<v8::Object> handle; |
| 49 }; | 49 }; |
| 50 | 50 |
| 51 } // namespace | 51 } // namespace |
| 52 | 52 |
| 53 namespace BASE_HASH_NAMESPACE { | 53 namespace BASE_HASH_NAMESPACE { |
| 54 #if defined(COMPILER_GCC) | 54 #if defined(COMPILER_GCC) |
| 55 template <> | 55 template <> |
| 56 struct hash<HashedHandle> { | 56 struct hash<HashedHandle> { |
| 57 size_t operator()(const HashedHandle& handle) const { | 57 size_t operator()(const HashedHandle& handle) const { return handle.hash(); } |
| 58 return handle.hash(); | |
| 59 } | |
| 60 }; | 58 }; |
| 61 #elif defined(COMPILER_MSVC) | 59 #elif defined(COMPILER_MSVC) |
| 62 inline size_t hash_value(const HashedHandle& handle) { | 60 inline size_t hash_value(const HashedHandle& handle) { return handle.hash(); } |
| 63 return handle.hash(); | |
| 64 } | |
| 65 #endif | 61 #endif |
| 66 } // namespace BASE_HASH_NAMESPACE | 62 } // namespace BASE_HASH_NAMESPACE |
| 67 | 63 |
| 68 namespace content { | 64 namespace content { |
| 69 | 65 |
| 70 namespace { | 66 namespace { |
| 71 | 67 |
| 72 // Maps PP_Var IDs to the V8 value handle they correspond to. | 68 // Maps PP_Var IDs to the V8 value handle they correspond to. |
| 73 typedef base::hash_map<int64_t, v8::Handle<v8::Value> > VarHandleMap; | 69 typedef base::hash_map<int64_t, v8::Handle<v8::Value> > VarHandleMap; |
| 74 typedef base::hash_set<int64_t> ParentVarSet; | 70 typedef base::hash_set<int64_t> ParentVarSet; |
| (...skipping 28 matching lines...) Expand all Loading... |
| 103 } | 99 } |
| 104 | 100 |
| 105 switch (var.type) { | 101 switch (var.type) { |
| 106 case PP_VARTYPE_UNDEFINED: | 102 case PP_VARTYPE_UNDEFINED: |
| 107 *result = v8::Undefined(isolate); | 103 *result = v8::Undefined(isolate); |
| 108 break; | 104 break; |
| 109 case PP_VARTYPE_NULL: | 105 case PP_VARTYPE_NULL: |
| 110 *result = v8::Null(isolate); | 106 *result = v8::Null(isolate); |
| 111 break; | 107 break; |
| 112 case PP_VARTYPE_BOOL: | 108 case PP_VARTYPE_BOOL: |
| 113 *result = (var.value.as_bool == PP_TRUE) | 109 *result = (var.value.as_bool == PP_TRUE) ? v8::True(isolate) |
| 114 ? v8::True(isolate) | 110 : v8::False(isolate); |
| 115 : v8::False(isolate); | |
| 116 break; | 111 break; |
| 117 case PP_VARTYPE_INT32: | 112 case PP_VARTYPE_INT32: |
| 118 *result = v8::Integer::New(isolate, var.value.as_int); | 113 *result = v8::Integer::New(isolate, var.value.as_int); |
| 119 break; | 114 break; |
| 120 case PP_VARTYPE_DOUBLE: | 115 case PP_VARTYPE_DOUBLE: |
| 121 *result = v8::Number::New(isolate, var.value.as_double); | 116 *result = v8::Number::New(isolate, var.value.as_double); |
| 122 break; | 117 break; |
| 123 case PP_VARTYPE_STRING: { | 118 case PP_VARTYPE_STRING: { |
| 124 StringVar* string = StringVar::FromPPVar(var); | 119 StringVar* string = StringVar::FromPPVar(var); |
| 125 if (!string) { | 120 if (!string) { |
| 126 NOTREACHED(); | 121 NOTREACHED(); |
| 127 result->Clear(); | 122 result->Clear(); |
| 128 return false; | 123 return false; |
| 129 } | 124 } |
| 130 const std::string& value = string->value(); | 125 const std::string& value = string->value(); |
| 131 // Create a string primitive rather than a string object. This is lossy | 126 // Create a string primitive rather than a string object. This is lossy |
| 132 // in the sense that string primitives in JavaScript can't be referenced | 127 // in the sense that string primitives in JavaScript can't be referenced |
| 133 // in the same way that string vars can in pepper. But that information | 128 // in the same way that string vars can in pepper. But that information |
| 134 // isn't very useful and primitive strings are a more expected form in JS. | 129 // isn't very useful and primitive strings are a more expected form in JS. |
| 135 *result = v8::String::NewFromUtf8(isolate, | 130 *result = v8::String::NewFromUtf8( |
| 136 value.c_str(), | 131 isolate, value.c_str(), v8::String::kNormalString, value.size()); |
| 137 v8::String::kNormalString, | |
| 138 value.size()); | |
| 139 break; | 132 break; |
| 140 } | 133 } |
| 141 case PP_VARTYPE_ARRAY_BUFFER: { | 134 case PP_VARTYPE_ARRAY_BUFFER: { |
| 142 ArrayBufferVar* buffer = ArrayBufferVar::FromPPVar(var); | 135 ArrayBufferVar* buffer = ArrayBufferVar::FromPPVar(var); |
| 143 if (!buffer) { | 136 if (!buffer) { |
| 144 NOTREACHED(); | 137 NOTREACHED(); |
| 145 result->Clear(); | 138 result->Clear(); |
| 146 return false; | 139 return false; |
| 147 } | 140 } |
| 148 HostArrayBufferVar* host_buffer = | 141 HostArrayBufferVar* host_buffer = |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 189 CHECK(!val.IsEmpty()); | 182 CHECK(!val.IsEmpty()); |
| 190 *did_create = false; | 183 *did_create = false; |
| 191 | 184 |
| 192 // Even though every v8 string primitive encountered will be a unique object, | 185 // Even though every v8 string primitive encountered will be a unique object, |
| 193 // we still add them to |visited_handles| so that the corresponding string | 186 // we still add them to |visited_handles| so that the corresponding string |
| 194 // PP_Var created will be properly refcounted. | 187 // PP_Var created will be properly refcounted. |
| 195 if (val->IsObject() || val->IsString()) { | 188 if (val->IsObject() || val->IsString()) { |
| 196 if (parent_handles->count(HashedHandle(val->ToObject())) != 0) | 189 if (parent_handles->count(HashedHandle(val->ToObject())) != 0) |
| 197 return false; | 190 return false; |
| 198 | 191 |
| 199 HandleVarMap::const_iterator it = visited_handles->find( | 192 HandleVarMap::const_iterator it = |
| 200 HashedHandle(val->ToObject())); | 193 visited_handles->find(HashedHandle(val->ToObject())); |
| 201 if (it != visited_handles->end()) { | 194 if (it != visited_handles->end()) { |
| 202 *result = it->second.get(); | 195 *result = it->second.get(); |
| 203 return true; | 196 return true; |
| 204 } | 197 } |
| 205 } | 198 } |
| 206 | 199 |
| 207 if (val->IsUndefined()) { | 200 if (val->IsUndefined()) { |
| 208 *result = PP_MakeUndefined(); | 201 *result = PP_MakeUndefined(); |
| 209 } else if (val->IsNull()) { | 202 } else if (val->IsNull()) { |
| 210 *result = PP_MakeNull(); | 203 *result = PP_MakeNull(); |
| 211 } else if (val->IsBoolean() || val->IsBooleanObject()) { | 204 } else if (val->IsBoolean() || val->IsBooleanObject()) { |
| 212 *result = PP_MakeBool(PP_FromBool(val->ToBoolean()->Value())); | 205 *result = PP_MakeBool(PP_FromBool(val->ToBoolean()->Value())); |
| 213 } else if (val->IsInt32()) { | 206 } else if (val->IsInt32()) { |
| 214 *result = PP_MakeInt32(val->ToInt32()->Value()); | 207 *result = PP_MakeInt32(val->ToInt32()->Value()); |
| 215 } else if (val->IsNumber() || val->IsNumberObject()) { | 208 } else if (val->IsNumber() || val->IsNumberObject()) { |
| 216 *result = PP_MakeDouble(val->ToNumber()->Value()); | 209 *result = PP_MakeDouble(val->ToNumber()->Value()); |
| 217 } else if (val->IsString() || val->IsStringObject()) { | 210 } else if (val->IsString() || val->IsStringObject()) { |
| 218 v8::String::Utf8Value utf8(val->ToString()); | 211 v8::String::Utf8Value utf8(val->ToString()); |
| 219 *result = StringVar::StringToPPVar(std::string(*utf8, utf8.length())); | 212 *result = StringVar::StringToPPVar(std::string(*utf8, utf8.length())); |
| 220 } else if (val->IsArray()) { | 213 } else if (val->IsArray()) { |
| 221 *result = (new ArrayVar())->GetPPVar(); | 214 *result = (new ArrayVar())->GetPPVar(); |
| 222 } else if (val->IsObject()) { | 215 } else if (val->IsObject()) { |
| 223 scoped_ptr<blink::WebArrayBuffer> web_array_buffer( | 216 scoped_ptr<blink::WebArrayBuffer> web_array_buffer( |
| 224 blink::WebArrayBufferConverter::createFromV8Value(val)); | 217 blink::WebArrayBufferConverter::createFromV8Value(val)); |
| 225 if (web_array_buffer.get()) { | 218 if (web_array_buffer.get()) { |
| 226 scoped_refptr<HostArrayBufferVar> buffer_var(new HostArrayBufferVar( | 219 scoped_refptr<HostArrayBufferVar> buffer_var( |
| 227 *web_array_buffer)); | 220 new HostArrayBufferVar(*web_array_buffer)); |
| 228 *result = buffer_var->GetPPVar(); | 221 *result = buffer_var->GetPPVar(); |
| 229 } else { | 222 } else { |
| 230 bool was_resource; | 223 bool was_resource; |
| 231 if (!resource_converter->FromV8Value(val->ToObject(), context, result, | 224 if (!resource_converter->FromV8Value( |
| 232 &was_resource)) | 225 val->ToObject(), context, result, &was_resource)) |
| 233 return false; | 226 return false; |
| 234 if (!was_resource) { | 227 if (!was_resource) { |
| 235 *result = (new DictionaryVar())->GetPPVar(); | 228 *result = (new DictionaryVar())->GetPPVar(); |
| 236 } | 229 } |
| 237 } | 230 } |
| 238 } else { | 231 } else { |
| 239 // Silently ignore the case where we can't convert to a Var as we may | 232 // Silently ignore the case where we can't convert to a Var as we may |
| 240 // be trying to convert a type that doesn't have a corresponding | 233 // be trying to convert a type that doesn't have a corresponding |
| 241 // PP_Var type. | 234 // PP_Var type. |
| 242 return true; | 235 return true; |
| 243 } | 236 } |
| 244 | 237 |
| 245 *did_create = true; | 238 *did_create = true; |
| 246 if (val->IsObject() || val->IsString()) { | 239 if (val->IsObject() || val->IsString()) { |
| 247 visited_handles->insert(make_pair( | 240 visited_handles->insert( |
| 248 HashedHandle(val->ToObject()), | 241 make_pair(HashedHandle(val->ToObject()), |
| 249 ScopedPPVar(ScopedPPVar::PassRef(), *result))); | 242 ScopedPPVar(ScopedPPVar::PassRef(), *result))); |
| 250 } | 243 } |
| 251 return true; | 244 return true; |
| 252 } | 245 } |
| 253 | 246 |
| 254 bool CanHaveChildren(PP_Var var) { | 247 bool CanHaveChildren(PP_Var var) { |
| 255 return var.type == PP_VARTYPE_ARRAY || var.type == PP_VARTYPE_DICTIONARY; | 248 return var.type == PP_VARTYPE_ARRAY || var.type == PP_VARTYPE_DICTIONARY; |
| 256 } | 249 } |
| 257 | 250 |
| 258 } // namespace | 251 } // namespace |
| 259 | 252 |
| 260 V8VarConverter::V8VarConverter(PP_Instance instance) | 253 V8VarConverter::V8VarConverter(PP_Instance instance) |
| 261 : message_loop_proxy_(base::MessageLoopProxy::current()) { | 254 : message_loop_proxy_(base::MessageLoopProxy::current()) { |
| 262 resource_converter_.reset(new ResourceConverterImpl( | 255 resource_converter_.reset(new ResourceConverterImpl( |
| 263 instance, RendererPpapiHost::GetForPPInstance(instance))); | 256 instance, RendererPpapiHost::GetForPPInstance(instance))); |
| 264 } | 257 } |
| 265 | 258 |
| 266 V8VarConverter::V8VarConverter( | 259 V8VarConverter::V8VarConverter(PP_Instance instance, |
| 267 PP_Instance instance, | 260 scoped_ptr<ResourceConverter> resource_converter) |
| 268 scoped_ptr<ResourceConverter> resource_converter) | |
| 269 : message_loop_proxy_(base::MessageLoopProxy::current()), | 261 : message_loop_proxy_(base::MessageLoopProxy::current()), |
| 270 resource_converter_(resource_converter.release()) { | 262 resource_converter_(resource_converter.release()) {} |
| 271 } | |
| 272 | 263 |
| 273 V8VarConverter::~V8VarConverter() { | 264 V8VarConverter::~V8VarConverter() {} |
| 274 } | |
| 275 | 265 |
| 276 // To/FromV8Value use a stack-based DFS search to traverse V8/Var graph. Each | 266 // To/FromV8Value use a stack-based DFS search to traverse V8/Var graph. Each |
| 277 // iteration, the top node on the stack examined. If the node has not been | 267 // iteration, the top node on the stack examined. If the node has not been |
| 278 // visited yet (i.e. sentinel == false) then it is added to the list of parents | 268 // visited yet (i.e. sentinel == false) then it is added to the list of parents |
| 279 // which contains all of the nodes on the path from the start node to the | 269 // which contains all of the nodes on the path from the start node to the |
| 280 // current node. Each of the current nodes children are examined. If they appear | 270 // current node. Each of the current nodes children are examined. If they appear |
| 281 // in the list of parents it means we have a cycle and we return NULL. | 271 // in the list of parents it means we have a cycle and we return NULL. |
| 282 // Otherwise, if they can have children, we add them to the stack. If the | 272 // Otherwise, if they can have children, we add them to the stack. If the |
| 283 // node at the top of the stack has already been visited, then we pop it off the | 273 // node at the top of the stack has already been visited, then we pop it off the |
| 284 // stack and erase it from the list of parents. | 274 // stack and erase it from the list of parents. |
| (...skipping 20 matching lines...) Expand all Loading... |
| 305 if (stack.top().sentinel) { | 295 if (stack.top().sentinel) { |
| 306 stack.pop(); | 296 stack.pop(); |
| 307 if (CanHaveChildren(current_var)) | 297 if (CanHaveChildren(current_var)) |
| 308 parent_ids.erase(current_var.value.as_id); | 298 parent_ids.erase(current_var.value.as_id); |
| 309 continue; | 299 continue; |
| 310 } else { | 300 } else { |
| 311 stack.top().sentinel = true; | 301 stack.top().sentinel = true; |
| 312 } | 302 } |
| 313 | 303 |
| 314 bool did_create = false; | 304 bool did_create = false; |
| 315 if (!GetOrCreateV8Value(context, current_var, ¤t_v8, &did_create, | 305 if (!GetOrCreateV8Value(context, |
| 316 &visited_ids, &parent_ids, | 306 current_var, |
| 307 ¤t_v8, |
| 308 &did_create, |
| 309 &visited_ids, |
| 310 &parent_ids, |
| 317 resource_converter_.get())) { | 311 resource_converter_.get())) { |
| 318 return false; | 312 return false; |
| 319 } | 313 } |
| 320 | 314 |
| 321 if (is_root) { | 315 if (is_root) { |
| 322 is_root = false; | 316 is_root = false; |
| 323 root = current_v8; | 317 root = current_v8; |
| 324 } | 318 } |
| 325 | 319 |
| 326 // Add child nodes to the stack. | 320 // Add child nodes to the stack. |
| 327 if (current_var.type == PP_VARTYPE_ARRAY) { | 321 if (current_var.type == PP_VARTYPE_ARRAY) { |
| 328 parent_ids.insert(current_var.value.as_id); | 322 parent_ids.insert(current_var.value.as_id); |
| 329 ArrayVar* array_var = ArrayVar::FromPPVar(current_var); | 323 ArrayVar* array_var = ArrayVar::FromPPVar(current_var); |
| 330 if (!array_var) { | 324 if (!array_var) { |
| 331 NOTREACHED(); | 325 NOTREACHED(); |
| 332 return false; | 326 return false; |
| 333 } | 327 } |
| 334 DCHECK(current_v8->IsArray()); | 328 DCHECK(current_v8->IsArray()); |
| 335 v8::Handle<v8::Array> v8_array = current_v8.As<v8::Array>(); | 329 v8::Handle<v8::Array> v8_array = current_v8.As<v8::Array>(); |
| 336 | 330 |
| 337 for (size_t i = 0; i < array_var->elements().size(); ++i) { | 331 for (size_t i = 0; i < array_var->elements().size(); ++i) { |
| 338 const PP_Var& child_var = array_var->elements()[i].get(); | 332 const PP_Var& child_var = array_var->elements()[i].get(); |
| 339 v8::Handle<v8::Value> child_v8; | 333 v8::Handle<v8::Value> child_v8; |
| 340 if (!GetOrCreateV8Value(context, child_var, &child_v8, &did_create, | 334 if (!GetOrCreateV8Value(context, |
| 341 &visited_ids, &parent_ids, | 335 child_var, |
| 336 &child_v8, |
| 337 &did_create, |
| 338 &visited_ids, |
| 339 &parent_ids, |
| 342 resource_converter_.get())) { | 340 resource_converter_.get())) { |
| 343 return false; | 341 return false; |
| 344 } | 342 } |
| 345 if (did_create && CanHaveChildren(child_var)) | 343 if (did_create && CanHaveChildren(child_var)) |
| 346 stack.push(child_var); | 344 stack.push(child_var); |
| 347 v8::TryCatch try_catch; | 345 v8::TryCatch try_catch; |
| 348 v8_array->Set(static_cast<uint32>(i), child_v8); | 346 v8_array->Set(static_cast<uint32>(i), child_v8); |
| 349 if (try_catch.HasCaught()) { | 347 if (try_catch.HasCaught()) { |
| 350 LOG(ERROR) << "Setter for index " << i << " threw an exception."; | 348 LOG(ERROR) << "Setter for index " << i << " threw an exception."; |
| 351 return false; | 349 return false; |
| 352 } | 350 } |
| 353 } | 351 } |
| 354 } else if (current_var.type == PP_VARTYPE_DICTIONARY) { | 352 } else if (current_var.type == PP_VARTYPE_DICTIONARY) { |
| 355 parent_ids.insert(current_var.value.as_id); | 353 parent_ids.insert(current_var.value.as_id); |
| 356 DictionaryVar* dict_var = DictionaryVar::FromPPVar(current_var); | 354 DictionaryVar* dict_var = DictionaryVar::FromPPVar(current_var); |
| 357 if (!dict_var) { | 355 if (!dict_var) { |
| 358 NOTREACHED(); | 356 NOTREACHED(); |
| 359 return false; | 357 return false; |
| 360 } | 358 } |
| 361 DCHECK(current_v8->IsObject()); | 359 DCHECK(current_v8->IsObject()); |
| 362 v8::Handle<v8::Object> v8_object = current_v8->ToObject(); | 360 v8::Handle<v8::Object> v8_object = current_v8->ToObject(); |
| 363 | 361 |
| 364 for (DictionaryVar::KeyValueMap::const_iterator iter = | 362 for (DictionaryVar::KeyValueMap::const_iterator iter = |
| 365 dict_var->key_value_map().begin(); | 363 dict_var->key_value_map().begin(); |
| 366 iter != dict_var->key_value_map().end(); | 364 iter != dict_var->key_value_map().end(); |
| 367 ++iter) { | 365 ++iter) { |
| 368 const std::string& key = iter->first; | 366 const std::string& key = iter->first; |
| 369 const PP_Var& child_var = iter->second.get(); | 367 const PP_Var& child_var = iter->second.get(); |
| 370 v8::Handle<v8::Value> child_v8; | 368 v8::Handle<v8::Value> child_v8; |
| 371 if (!GetOrCreateV8Value(context, child_var, &child_v8, &did_create, | 369 if (!GetOrCreateV8Value(context, |
| 372 &visited_ids, &parent_ids, | 370 child_var, |
| 371 &child_v8, |
| 372 &did_create, |
| 373 &visited_ids, |
| 374 &parent_ids, |
| 373 resource_converter_.get())) { | 375 resource_converter_.get())) { |
| 374 return false; | 376 return false; |
| 375 } | 377 } |
| 376 if (did_create && CanHaveChildren(child_var)) | 378 if (did_create && CanHaveChildren(child_var)) |
| 377 stack.push(child_var); | 379 stack.push(child_var); |
| 378 v8::TryCatch try_catch; | 380 v8::TryCatch try_catch; |
| 379 v8_object->Set(v8::String::NewFromUtf8(isolate, | 381 v8_object->Set( |
| 380 key.c_str(), | 382 v8::String::NewFromUtf8( |
| 381 v8::String::kNormalString, | 383 isolate, key.c_str(), v8::String::kNormalString, key.length()), |
| 382 key.length()), | 384 child_v8); |
| 383 child_v8); | |
| 384 if (try_catch.HasCaught()) { | 385 if (try_catch.HasCaught()) { |
| 385 LOG(ERROR) << "Setter for property " << key.c_str() << " threw an " | 386 LOG(ERROR) << "Setter for property " << key.c_str() << " threw an " |
| 386 << "exception."; | 387 << "exception."; |
| 387 return false; | 388 return false; |
| 388 } | 389 } |
| 389 } | 390 } |
| 390 } | 391 } |
| 391 } | 392 } |
| 392 | 393 |
| 393 *result = handle_scope.Escape(root); | 394 *result = handle_scope.Escape(root); |
| 394 return true; | 395 return true; |
| 395 } | 396 } |
| 396 | 397 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 416 if (stack.top().sentinel) { | 417 if (stack.top().sentinel) { |
| 417 stack.pop(); | 418 stack.pop(); |
| 418 if (current_v8->IsObject()) | 419 if (current_v8->IsObject()) |
| 419 parent_handles.erase(HashedHandle(current_v8->ToObject())); | 420 parent_handles.erase(HashedHandle(current_v8->ToObject())); |
| 420 continue; | 421 continue; |
| 421 } else { | 422 } else { |
| 422 stack.top().sentinel = true; | 423 stack.top().sentinel = true; |
| 423 } | 424 } |
| 424 | 425 |
| 425 bool did_create = false; | 426 bool did_create = false; |
| 426 if (!GetOrCreateVar(current_v8, context, ¤t_var, &did_create, | 427 if (!GetOrCreateVar(current_v8, |
| 427 &visited_handles, &parent_handles, | 428 context, |
| 429 ¤t_var, |
| 430 &did_create, |
| 431 &visited_handles, |
| 432 &parent_handles, |
| 428 resource_converter_.get())) { | 433 resource_converter_.get())) { |
| 429 message_loop_proxy_->PostTask(FROM_HERE, | 434 message_loop_proxy_->PostTask( |
| 435 FROM_HERE, |
| 430 base::Bind(callback, ScopedPPVar(PP_MakeUndefined()), false)); | 436 base::Bind(callback, ScopedPPVar(PP_MakeUndefined()), false)); |
| 431 return; | 437 return; |
| 432 } | 438 } |
| 433 | 439 |
| 434 if (is_root) { | 440 if (is_root) { |
| 435 is_root = false; | 441 is_root = false; |
| 436 root = current_var; | 442 root = current_var; |
| 437 } | 443 } |
| 438 | 444 |
| 439 // Add child nodes to the stack. | 445 // Add child nodes to the stack. |
| 440 if (current_var.type == PP_VARTYPE_ARRAY) { | 446 if (current_var.type == PP_VARTYPE_ARRAY) { |
| 441 DCHECK(current_v8->IsArray()); | 447 DCHECK(current_v8->IsArray()); |
| 442 v8::Handle<v8::Array> v8_array = current_v8.As<v8::Array>(); | 448 v8::Handle<v8::Array> v8_array = current_v8.As<v8::Array>(); |
| 443 parent_handles.insert(HashedHandle(v8_array)); | 449 parent_handles.insert(HashedHandle(v8_array)); |
| 444 | 450 |
| 445 ArrayVar* array_var = ArrayVar::FromPPVar(current_var); | 451 ArrayVar* array_var = ArrayVar::FromPPVar(current_var); |
| 446 if (!array_var) { | 452 if (!array_var) { |
| 447 NOTREACHED(); | 453 NOTREACHED(); |
| 448 message_loop_proxy_->PostTask(FROM_HERE, | 454 message_loop_proxy_->PostTask( |
| 455 FROM_HERE, |
| 449 base::Bind(callback, ScopedPPVar(PP_MakeUndefined()), false)); | 456 base::Bind(callback, ScopedPPVar(PP_MakeUndefined()), false)); |
| 450 return; | 457 return; |
| 451 } | 458 } |
| 452 | 459 |
| 453 for (uint32 i = 0; i < v8_array->Length(); ++i) { | 460 for (uint32 i = 0; i < v8_array->Length(); ++i) { |
| 454 v8::TryCatch try_catch; | 461 v8::TryCatch try_catch; |
| 455 v8::Handle<v8::Value> child_v8 = v8_array->Get(i); | 462 v8::Handle<v8::Value> child_v8 = v8_array->Get(i); |
| 456 if (try_catch.HasCaught()) { | 463 if (try_catch.HasCaught()) { |
| 457 message_loop_proxy_->PostTask(FROM_HERE, | 464 message_loop_proxy_->PostTask( |
| 465 FROM_HERE, |
| 458 base::Bind(callback, ScopedPPVar(PP_MakeUndefined()), false)); | 466 base::Bind(callback, ScopedPPVar(PP_MakeUndefined()), false)); |
| 459 return; | 467 return; |
| 460 } | 468 } |
| 461 | 469 |
| 462 if (!v8_array->HasRealIndexedProperty(i)) | 470 if (!v8_array->HasRealIndexedProperty(i)) |
| 463 continue; | 471 continue; |
| 464 | 472 |
| 465 PP_Var child_var; | 473 PP_Var child_var; |
| 466 if (!GetOrCreateVar(child_v8, context, &child_var, &did_create, | 474 if (!GetOrCreateVar(child_v8, |
| 467 &visited_handles, &parent_handles, | 475 context, |
| 476 &child_var, |
| 477 &did_create, |
| 478 &visited_handles, |
| 479 &parent_handles, |
| 468 resource_converter_.get())) { | 480 resource_converter_.get())) { |
| 469 message_loop_proxy_->PostTask(FROM_HERE, | 481 message_loop_proxy_->PostTask( |
| 482 FROM_HERE, |
| 470 base::Bind(callback, ScopedPPVar(PP_MakeUndefined()), false)); | 483 base::Bind(callback, ScopedPPVar(PP_MakeUndefined()), false)); |
| 471 return; | 484 return; |
| 472 } | 485 } |
| 473 if (did_create && child_v8->IsObject()) | 486 if (did_create && child_v8->IsObject()) |
| 474 stack.push(child_v8); | 487 stack.push(child_v8); |
| 475 | 488 |
| 476 array_var->Set(i, child_var); | 489 array_var->Set(i, child_var); |
| 477 } | 490 } |
| 478 } else if (current_var.type == PP_VARTYPE_DICTIONARY) { | 491 } else if (current_var.type == PP_VARTYPE_DICTIONARY) { |
| 479 DCHECK(current_v8->IsObject()); | 492 DCHECK(current_v8->IsObject()); |
| 480 v8::Handle<v8::Object> v8_object = current_v8->ToObject(); | 493 v8::Handle<v8::Object> v8_object = current_v8->ToObject(); |
| 481 parent_handles.insert(HashedHandle(v8_object)); | 494 parent_handles.insert(HashedHandle(v8_object)); |
| 482 | 495 |
| 483 DictionaryVar* dict_var = DictionaryVar::FromPPVar(current_var); | 496 DictionaryVar* dict_var = DictionaryVar::FromPPVar(current_var); |
| 484 if (!dict_var) { | 497 if (!dict_var) { |
| 485 NOTREACHED(); | 498 NOTREACHED(); |
| 486 message_loop_proxy_->PostTask(FROM_HERE, | 499 message_loop_proxy_->PostTask( |
| 500 FROM_HERE, |
| 487 base::Bind(callback, ScopedPPVar(PP_MakeUndefined()), false)); | 501 base::Bind(callback, ScopedPPVar(PP_MakeUndefined()), false)); |
| 488 return; | 502 return; |
| 489 } | 503 } |
| 490 | 504 |
| 491 v8::Handle<v8::Array> property_names(v8_object->GetOwnPropertyNames()); | 505 v8::Handle<v8::Array> property_names(v8_object->GetOwnPropertyNames()); |
| 492 for (uint32 i = 0; i < property_names->Length(); ++i) { | 506 for (uint32 i = 0; i < property_names->Length(); ++i) { |
| 493 v8::Handle<v8::Value> key(property_names->Get(i)); | 507 v8::Handle<v8::Value> key(property_names->Get(i)); |
| 494 | 508 |
| 495 // Extend this test to cover more types as necessary and if sensible. | 509 // Extend this test to cover more types as necessary and if sensible. |
| 496 if (!key->IsString() && !key->IsNumber()) { | 510 if (!key->IsString() && !key->IsNumber()) { |
| 497 NOTREACHED() << "Key \"" << *v8::String::Utf8Value(key) << "\" " | 511 NOTREACHED() << "Key \"" << *v8::String::Utf8Value(key) |
| 512 << "\" " |
| 498 "is neither a string nor a number"; | 513 "is neither a string nor a number"; |
| 499 message_loop_proxy_->PostTask(FROM_HERE, | 514 message_loop_proxy_->PostTask( |
| 515 FROM_HERE, |
| 500 base::Bind(callback, ScopedPPVar(PP_MakeUndefined()), false)); | 516 base::Bind(callback, ScopedPPVar(PP_MakeUndefined()), false)); |
| 501 return; | 517 return; |
| 502 } | 518 } |
| 503 | 519 |
| 504 // Skip all callbacks: crbug.com/139933 | 520 // Skip all callbacks: crbug.com/139933 |
| 505 if (v8_object->HasRealNamedCallbackProperty(key->ToString())) | 521 if (v8_object->HasRealNamedCallbackProperty(key->ToString())) |
| 506 continue; | 522 continue; |
| 507 | 523 |
| 508 v8::String::Utf8Value name_utf8(key->ToString()); | 524 v8::String::Utf8Value name_utf8(key->ToString()); |
| 509 | 525 |
| 510 v8::TryCatch try_catch; | 526 v8::TryCatch try_catch; |
| 511 v8::Handle<v8::Value> child_v8 = v8_object->Get(key); | 527 v8::Handle<v8::Value> child_v8 = v8_object->Get(key); |
| 512 if (try_catch.HasCaught()) { | 528 if (try_catch.HasCaught()) { |
| 513 message_loop_proxy_->PostTask(FROM_HERE, | 529 message_loop_proxy_->PostTask( |
| 530 FROM_HERE, |
| 514 base::Bind(callback, ScopedPPVar(PP_MakeUndefined()), false)); | 531 base::Bind(callback, ScopedPPVar(PP_MakeUndefined()), false)); |
| 515 return; | 532 return; |
| 516 } | 533 } |
| 517 | 534 |
| 518 PP_Var child_var; | 535 PP_Var child_var; |
| 519 if (!GetOrCreateVar(child_v8, context, &child_var, &did_create, | 536 if (!GetOrCreateVar(child_v8, |
| 520 &visited_handles, &parent_handles, | 537 context, |
| 538 &child_var, |
| 539 &did_create, |
| 540 &visited_handles, |
| 541 &parent_handles, |
| 521 resource_converter_.get())) { | 542 resource_converter_.get())) { |
| 522 message_loop_proxy_->PostTask(FROM_HERE, | 543 message_loop_proxy_->PostTask( |
| 544 FROM_HERE, |
| 523 base::Bind(callback, ScopedPPVar(PP_MakeUndefined()), false)); | 545 base::Bind(callback, ScopedPPVar(PP_MakeUndefined()), false)); |
| 524 return; | 546 return; |
| 525 } | 547 } |
| 526 if (did_create && child_v8->IsObject()) | 548 if (did_create && child_v8->IsObject()) |
| 527 stack.push(child_v8); | 549 stack.push(child_v8); |
| 528 | 550 |
| 529 bool success = dict_var->SetWithStringKey( | 551 bool success = dict_var->SetWithStringKey( |
| 530 std::string(*name_utf8, name_utf8.length()), child_var); | 552 std::string(*name_utf8, name_utf8.length()), child_var); |
| 531 DCHECK(success); | 553 DCHECK(success); |
| 532 } | 554 } |
| 533 } | 555 } |
| 534 } | 556 } |
| 535 resource_converter_->Flush(base::Bind(callback, root)); | 557 resource_converter_->Flush(base::Bind(callback, root)); |
| 536 } | 558 } |
| 537 | 559 |
| 538 } // namespace content | 560 } // namespace content |
| OLD | NEW |