Home | History | Annotate | Download | only in proxy
      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
      3 // found in the LICENSE file.
      4 
      5 #include "ppapi/proxy/raw_var_data.h"
      6 
      7 #include <stack>
      8 
      9 #include "base/containers/hash_tables.h"
     10 #include "base/stl_util.h"
     11 #include "ipc/ipc_message.h"
     12 #include "ppapi/proxy/ppapi_param_traits.h"
     13 #include "ppapi/shared_impl/array_var.h"
     14 #include "ppapi/shared_impl/dictionary_var.h"
     15 #include "ppapi/shared_impl/ppapi_globals.h"
     16 #include "ppapi/shared_impl/resource_var.h"
     17 #include "ppapi/shared_impl/scoped_pp_var.h"
     18 #include "ppapi/shared_impl/var.h"
     19 #include "ppapi/shared_impl/var_tracker.h"
     20 
     21 using std::make_pair;
     22 
     23 namespace ppapi {
     24 namespace proxy {
     25 
     26 namespace {
     27 
     28 // When sending array buffers, if the size is over 256K, we use shared
     29 // memory instead of sending the data over IPC. Light testing suggests
     30 // shared memory is much faster for 256K and larger messages.
     31 static const uint32 kMinimumArrayBufferSizeForShmem = 256 * 1024;
     32 static uint32 g_minimum_array_buffer_size_for_shmem =
     33     kMinimumArrayBufferSizeForShmem;
     34 
     35 struct StackEntry {
     36   StackEntry(PP_Var v, size_t i) : var(v), data_index(i) {}
     37   PP_Var var;
     38   size_t data_index;
     39 };
     40 
     41 // For a given PP_Var, returns the RawVarData associated with it, or creates a
     42 // new one if there is no existing one. The data is appended to |data| if it
     43 // is newly created. The index into |data| pointing to the result is returned.
     44 // |visited_map| keeps track of RawVarDatas that have already been created.
     45 size_t GetOrCreateRawVarData(const PP_Var& var,
     46                              base::hash_map<int64_t, size_t>* visited_map,
     47                              ScopedVector<RawVarData>* data) {
     48   if (VarTracker::IsVarTypeRefcounted(var.type)) {
     49     base::hash_map<int64_t, size_t>::iterator it = visited_map->find(
     50         var.value.as_id);
     51     if (it != visited_map->end()) {
     52       return it->second;
     53     } else {
     54       data->push_back(RawVarData::Create(var.type));
     55       (*visited_map)[var.value.as_id] = data->size() - 1;
     56     }
     57   } else {
     58     data->push_back(RawVarData::Create(var.type));
     59   }
     60   return data->size() - 1;
     61 }
     62 
     63 bool CanHaveChildren(PP_Var var) {
     64   return var.type == PP_VARTYPE_ARRAY || var.type == PP_VARTYPE_DICTIONARY;
     65 }
     66 
     67 }  // namespace
     68 
     69 // RawVarDataGraph ------------------------------------------------------------
     70 RawVarDataGraph::RawVarDataGraph() {
     71 }
     72 
     73 RawVarDataGraph::~RawVarDataGraph() {
     74 }
     75 
     76 // This function uses a stack-based DFS search to traverse the var graph. Each
     77 // iteration, the top node on the stack examined. If the node has not been
     78 // visited yet (i.e. !initialized()) then it is added to the list of
     79 // |parent_ids| which contains all of the nodes on the path from the start node
     80 // to the current node. Each of that nodes children are examined. If they appear
     81 // in the list of |parent_ids| it means we have a cycle and we return NULL.
     82 // Otherwise, if they haven't been visited yet we add them to the stack, If the
     83 // node at the top of the stack has already been visited, then we pop it off the
     84 // stack and erase it from |parent_ids|.
     85 // static
     86 scoped_ptr<RawVarDataGraph> RawVarDataGraph::Create(const PP_Var& var,
     87                                                     PP_Instance instance) {
     88   scoped_ptr<RawVarDataGraph> graph(new RawVarDataGraph);
     89   // Map of |var.value.as_id| to a RawVarData index in RawVarDataGraph.
     90   base::hash_map<int64_t, size_t> visited_map;
     91   base::hash_set<int64_t> parent_ids;
     92 
     93   std::stack<StackEntry> stack;
     94   stack.push(StackEntry(var, GetOrCreateRawVarData(var, &visited_map,
     95                                                    &graph->data_)));
     96 
     97   while (!stack.empty()) {
     98     PP_Var current_var = stack.top().var;
     99     RawVarData* current_var_data = graph->data_[stack.top().data_index];
    100 
    101     if (current_var_data->initialized()) {
    102       stack.pop();
    103       if (CanHaveChildren(current_var))
    104         parent_ids.erase(current_var.value.as_id);
    105       continue;
    106     }
    107 
    108     if (CanHaveChildren(current_var))
    109       parent_ids.insert(current_var.value.as_id);
    110     if (!current_var_data->Init(current_var, instance)) {
    111       NOTREACHED();
    112       return scoped_ptr<RawVarDataGraph>();
    113     }
    114 
    115     // Add child nodes to the stack.
    116     if (current_var.type == PP_VARTYPE_ARRAY) {
    117       ArrayVar* array_var = ArrayVar::FromPPVar(current_var);
    118       if (!array_var) {
    119         NOTREACHED();
    120         return scoped_ptr<RawVarDataGraph>();
    121       }
    122       for (ArrayVar::ElementVector::const_iterator iter =
    123                array_var->elements().begin();
    124            iter != array_var->elements().end();
    125            ++iter) {
    126         const PP_Var& child = iter->get();
    127         // If a child of this node is already in parent_ids, we have a cycle so
    128         // we just return null.
    129         if (CanHaveChildren(child) && parent_ids.count(child.value.as_id) != 0)
    130           return scoped_ptr<RawVarDataGraph>();
    131         size_t child_id = GetOrCreateRawVarData(child, &visited_map,
    132                                                 &graph->data_);
    133         static_cast<ArrayRawVarData*>(current_var_data)->AddChild(child_id);
    134         if (!graph->data_[child_id]->initialized())
    135           stack.push(StackEntry(child, child_id));
    136       }
    137     } else if (current_var.type == PP_VARTYPE_DICTIONARY) {
    138       DictionaryVar* dict_var = DictionaryVar::FromPPVar(current_var);
    139       if (!dict_var) {
    140         NOTREACHED();
    141         return scoped_ptr<RawVarDataGraph>();
    142       }
    143       for (DictionaryVar::KeyValueMap::const_iterator iter =
    144                dict_var->key_value_map().begin();
    145            iter != dict_var->key_value_map().end();
    146            ++iter) {
    147         const PP_Var& child = iter->second.get();
    148         if (CanHaveChildren(child) && parent_ids.count(child.value.as_id) != 0)
    149           return scoped_ptr<RawVarDataGraph>();
    150         size_t child_id = GetOrCreateRawVarData(child, &visited_map,
    151                                                 &graph->data_);
    152         static_cast<DictionaryRawVarData*>(
    153             current_var_data)->AddChild(iter->first, child_id);
    154         if (!graph->data_[child_id]->initialized())
    155           stack.push(StackEntry(child, child_id));
    156       }
    157     }
    158   }
    159   return graph.Pass();
    160 }
    161 
    162 PP_Var RawVarDataGraph::CreatePPVar(PP_Instance instance) {
    163   // Create and initialize each node in the graph.
    164   std::vector<PP_Var> graph;
    165   for (size_t i = 0; i < data_.size(); ++i)
    166     graph.push_back(data_[i]->CreatePPVar(instance));
    167   for (size_t i = 0; i < data_.size(); ++i)
    168     data_[i]->PopulatePPVar(graph[i], graph);
    169   // Everything except the root will have one extra ref. Remove that ref.
    170   for (size_t i = 1; i < data_.size(); ++i)
    171     ScopedPPVar(ScopedPPVar::PassRef(), graph[i]);
    172   // The first element is the root.
    173   return graph[0];
    174 }
    175 
    176 void RawVarDataGraph::Write(IPC::Message* m,
    177                             const HandleWriter& handle_writer) {
    178   // Write the size, followed by each node in the graph.
    179   m->WriteUInt32(static_cast<uint32_t>(data_.size()));
    180   for (size_t i = 0; i < data_.size(); ++i) {
    181     m->WriteInt(data_[i]->Type());
    182     data_[i]->Write(m, handle_writer);
    183   }
    184 }
    185 
    186 // static
    187 scoped_ptr<RawVarDataGraph> RawVarDataGraph::Read(const IPC::Message* m,
    188                                                   PickleIterator* iter) {
    189   scoped_ptr<RawVarDataGraph> result(new RawVarDataGraph);
    190   uint32_t size = 0;
    191   if (!m->ReadUInt32(iter, &size))
    192     return scoped_ptr<RawVarDataGraph>();
    193   for (uint32_t i = 0; i < size; ++i) {
    194     int32_t type;
    195     if (!m->ReadInt(iter, &type))
    196       return scoped_ptr<RawVarDataGraph>();
    197     PP_VarType var_type = static_cast<PP_VarType>(type);
    198     result->data_.push_back(RawVarData::Create(var_type));
    199     if (!result->data_.back()->Read(var_type, m, iter))
    200       return scoped_ptr<RawVarDataGraph>();
    201   }
    202   return result.Pass();
    203 }
    204 
    205 std::vector<SerializedHandle*> RawVarDataGraph::GetHandles() {
    206   std::vector<SerializedHandle*> result;
    207   for (size_t i = 0; i < data_.size(); ++i) {
    208     SerializedHandle* handle = data_[i]->GetHandle();
    209     if (handle)
    210       result.push_back(handle);
    211   }
    212   return result;
    213 }
    214 
    215 // static
    216 void RawVarDataGraph::SetMinimumArrayBufferSizeForShmemForTest(
    217     uint32 threshold) {
    218   if (threshold == 0)
    219     g_minimum_array_buffer_size_for_shmem = kMinimumArrayBufferSizeForShmem;
    220   else
    221     g_minimum_array_buffer_size_for_shmem = threshold;
    222 }
    223 
    224 // RawVarData ------------------------------------------------------------------
    225 
    226 // static
    227 RawVarData* RawVarData::Create(PP_VarType type) {
    228   switch (type) {
    229     case PP_VARTYPE_UNDEFINED:
    230     case PP_VARTYPE_NULL:
    231     case PP_VARTYPE_BOOL:
    232     case PP_VARTYPE_INT32:
    233     case PP_VARTYPE_DOUBLE:
    234     case PP_VARTYPE_OBJECT:
    235       return new BasicRawVarData();
    236     case PP_VARTYPE_STRING:
    237       return new StringRawVarData();
    238     case PP_VARTYPE_ARRAY_BUFFER:
    239       return new ArrayBufferRawVarData();
    240     case PP_VARTYPE_ARRAY:
    241       return new ArrayRawVarData();
    242     case PP_VARTYPE_DICTIONARY:
    243       return new DictionaryRawVarData();
    244     case PP_VARTYPE_RESOURCE:
    245       return new ResourceRawVarData();
    246   }
    247   NOTREACHED();
    248   return NULL;
    249 }
    250 
    251 RawVarData::RawVarData() : initialized_(false) {
    252 }
    253 
    254 RawVarData::~RawVarData() {
    255 }
    256 
    257 SerializedHandle* RawVarData::GetHandle() {
    258   return NULL;
    259 }
    260 
    261 // BasicRawVarData -------------------------------------------------------------
    262 BasicRawVarData::BasicRawVarData() {
    263 }
    264 
    265 BasicRawVarData::~BasicRawVarData() {
    266 }
    267 
    268 PP_VarType BasicRawVarData::Type() {
    269   return var_.type;
    270 }
    271 
    272 bool BasicRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) {
    273   var_ = var;
    274   initialized_ = true;
    275   return true;
    276 }
    277 
    278 PP_Var BasicRawVarData::CreatePPVar(PP_Instance instance) {
    279   return var_;
    280 }
    281 
    282 void BasicRawVarData::PopulatePPVar(const PP_Var& var,
    283                                     const std::vector<PP_Var>& graph) {
    284 }
    285 
    286 void BasicRawVarData::Write(
    287     IPC::Message* m,
    288     const HandleWriter& handle_writer) {
    289   switch (var_.type) {
    290     case PP_VARTYPE_UNDEFINED:
    291     case PP_VARTYPE_NULL:
    292       // These don't need any data associated with them other than the type we
    293       // just serialized.
    294       break;
    295     case PP_VARTYPE_BOOL:
    296       m->WriteBool(PP_ToBool(var_.value.as_bool));
    297       break;
    298     case PP_VARTYPE_INT32:
    299       m->WriteInt(var_.value.as_int);
    300       break;
    301     case PP_VARTYPE_DOUBLE:
    302       IPC::ParamTraits<double>::Write(m, var_.value.as_double);
    303       break;
    304     case PP_VARTYPE_OBJECT:
    305       m->WriteInt64(var_.value.as_id);
    306       break;
    307     default:
    308       NOTREACHED();
    309       break;
    310   }
    311 }
    312 
    313 bool BasicRawVarData::Read(PP_VarType type,
    314                            const IPC::Message* m,
    315                            PickleIterator* iter) {
    316   PP_Var result;
    317   result.type = type;
    318   switch (type) {
    319     case PP_VARTYPE_UNDEFINED:
    320     case PP_VARTYPE_NULL:
    321       // These don't have any data associated with them other than the type we
    322       // just deserialized.
    323       break;
    324     case PP_VARTYPE_BOOL: {
    325       bool bool_value;
    326       if (!m->ReadBool(iter, &bool_value))
    327         return false;
    328       result.value.as_bool = PP_FromBool(bool_value);
    329       break;
    330     }
    331     case PP_VARTYPE_INT32:
    332       if (!m->ReadInt(iter, &result.value.as_int))
    333         return false;
    334       break;
    335     case PP_VARTYPE_DOUBLE:
    336       if (!IPC::ParamTraits<double>::Read(m, iter, &result.value.as_double))
    337         return false;
    338       break;
    339     case PP_VARTYPE_OBJECT:
    340       if (!m->ReadInt64(iter, &result.value.as_id))
    341         return false;
    342       break;
    343     default:
    344       NOTREACHED();
    345       return false;
    346   }
    347   var_ = result;
    348   return true;
    349 }
    350 
    351 // StringRawVarData ------------------------------------------------------------
    352 StringRawVarData::StringRawVarData() {
    353 }
    354 
    355 StringRawVarData::~StringRawVarData() {
    356 }
    357 
    358 PP_VarType StringRawVarData::Type() {
    359   return PP_VARTYPE_STRING;
    360 }
    361 
    362 bool StringRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) {
    363   DCHECK(var.type == PP_VARTYPE_STRING);
    364   StringVar* string_var = StringVar::FromPPVar(var);
    365   if (!string_var)
    366     return false;
    367   data_ = string_var->value();
    368   initialized_ = true;
    369   return true;
    370 }
    371 
    372 PP_Var StringRawVarData::CreatePPVar(PP_Instance instance) {
    373   return StringVar::SwapValidatedUTF8StringIntoPPVar(&data_);
    374 }
    375 
    376 void StringRawVarData::PopulatePPVar(const PP_Var& var,
    377                                      const std::vector<PP_Var>& graph) {
    378 }
    379 
    380 void StringRawVarData::Write(IPC::Message* m,
    381                              const HandleWriter& handle_writer) {
    382   m->WriteString(data_);
    383 }
    384 
    385 bool StringRawVarData::Read(PP_VarType type,
    386                             const IPC::Message* m,
    387                             PickleIterator* iter) {
    388   if (!m->ReadString(iter, &data_))
    389     return false;
    390   return true;
    391 }
    392 
    393 // ArrayBufferRawVarData -------------------------------------------------------
    394 ArrayBufferRawVarData::ArrayBufferRawVarData() {
    395 }
    396 
    397 ArrayBufferRawVarData::~ArrayBufferRawVarData() {
    398 }
    399 
    400 PP_VarType ArrayBufferRawVarData::Type() {
    401   return PP_VARTYPE_ARRAY_BUFFER;
    402 }
    403 
    404 bool ArrayBufferRawVarData::Init(const PP_Var& var,
    405                                  PP_Instance instance) {
    406   DCHECK(var.type == PP_VARTYPE_ARRAY_BUFFER);
    407   ArrayBufferVar* buffer_var = ArrayBufferVar::FromPPVar(var);
    408   if (!buffer_var)
    409     return false;
    410   bool using_shmem = false;
    411   if (buffer_var->ByteLength() >= g_minimum_array_buffer_size_for_shmem &&
    412       instance != 0) {
    413     int host_handle_id;
    414     base::SharedMemoryHandle plugin_handle;
    415     using_shmem = buffer_var->CopyToNewShmem(instance,
    416                                              &host_handle_id,
    417                                              &plugin_handle);
    418     if (using_shmem) {
    419       if (host_handle_id != -1) {
    420         DCHECK(!base::SharedMemory::IsHandleValid(plugin_handle));
    421         DCHECK(PpapiGlobals::Get()->IsPluginGlobals());
    422         type_ = ARRAY_BUFFER_SHMEM_HOST;
    423         host_shm_handle_id_ = host_handle_id;
    424       } else {
    425         DCHECK(base::SharedMemory::IsHandleValid(plugin_handle));
    426         DCHECK(PpapiGlobals::Get()->IsHostGlobals());
    427         type_ = ARRAY_BUFFER_SHMEM_PLUGIN;
    428         plugin_shm_handle_ = SerializedHandle(plugin_handle,
    429                                               buffer_var->ByteLength());
    430       }
    431     }
    432   }
    433   if (!using_shmem) {
    434     type_ = ARRAY_BUFFER_NO_SHMEM;
    435     data_ = std::string(static_cast<const char*>(buffer_var->Map()),
    436                         buffer_var->ByteLength());
    437   }
    438   initialized_ = true;
    439   return true;
    440 }
    441 
    442 PP_Var ArrayBufferRawVarData::CreatePPVar(PP_Instance instance) {
    443   PP_Var result = PP_MakeUndefined();
    444   switch (type_) {
    445     case ARRAY_BUFFER_SHMEM_HOST: {
    446       base::SharedMemoryHandle host_handle;
    447       uint32 size_in_bytes;
    448       bool ok = PpapiGlobals::Get()->GetVarTracker()->
    449           StopTrackingSharedMemoryHandle(host_shm_handle_id_,
    450                                          instance,
    451                                          &host_handle,
    452                                          &size_in_bytes);
    453       if (ok) {
    454         result = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
    455             size_in_bytes, host_handle);
    456       } else {
    457         LOG(ERROR) << "Couldn't find array buffer id: " << host_shm_handle_id_;
    458         return PP_MakeUndefined();
    459       }
    460       break;
    461     }
    462     case ARRAY_BUFFER_SHMEM_PLUGIN: {
    463       result = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
    464           plugin_shm_handle_.size(),
    465           plugin_shm_handle_.shmem());
    466       break;
    467     }
    468     case ARRAY_BUFFER_NO_SHMEM: {
    469       result = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
    470           static_cast<uint32>(data_.size()), data_.data());
    471       break;
    472     }
    473     default:
    474       NOTREACHED();
    475       return PP_MakeUndefined();
    476   }
    477   DCHECK(result.type == PP_VARTYPE_ARRAY_BUFFER);
    478   return result;
    479 }
    480 
    481 void ArrayBufferRawVarData::PopulatePPVar(const PP_Var& var,
    482                                           const std::vector<PP_Var>& graph) {
    483 }
    484 
    485 void ArrayBufferRawVarData::Write(
    486     IPC::Message* m,
    487     const HandleWriter& handle_writer) {
    488   m->WriteInt(type_);
    489   switch (type_) {
    490     case ARRAY_BUFFER_SHMEM_HOST:
    491       m->WriteInt(host_shm_handle_id_);
    492       break;
    493     case ARRAY_BUFFER_SHMEM_PLUGIN:
    494       handle_writer.Run(m, plugin_shm_handle_);
    495       break;
    496     case ARRAY_BUFFER_NO_SHMEM:
    497       m->WriteString(data_);
    498       break;
    499   }
    500 }
    501 
    502 bool ArrayBufferRawVarData::Read(PP_VarType type,
    503                                  const IPC::Message* m,
    504                                  PickleIterator* iter) {
    505   int shmem_type;
    506   if (!m->ReadInt(iter, &shmem_type))
    507     return false;
    508   type_ = static_cast<ShmemType>(shmem_type);
    509   switch (type_) {
    510     case ARRAY_BUFFER_SHMEM_HOST:
    511       if (!m->ReadInt(iter, &host_shm_handle_id_))
    512         return false;
    513       break;
    514     case ARRAY_BUFFER_SHMEM_PLUGIN:
    515       if (!IPC::ParamTraits<SerializedHandle>::Read(
    516               m, iter, &plugin_shm_handle_)) {
    517         return false;
    518       }
    519       break;
    520     case ARRAY_BUFFER_NO_SHMEM:
    521       if (!m->ReadString(iter, &data_))
    522         return false;
    523       break;
    524     default:
    525       // We read an invalid ID.
    526       NOTREACHED();
    527       return false;
    528   }
    529   return true;
    530 }
    531 
    532 SerializedHandle* ArrayBufferRawVarData::GetHandle() {
    533   if (type_ == ARRAY_BUFFER_SHMEM_PLUGIN && plugin_shm_handle_.size() != 0)
    534     return &plugin_shm_handle_;
    535   return NULL;
    536 }
    537 
    538 // ArrayRawVarData -------------------------------------------------------------
    539 ArrayRawVarData::ArrayRawVarData() {
    540 }
    541 
    542 ArrayRawVarData::~ArrayRawVarData() {
    543 }
    544 
    545 void ArrayRawVarData::AddChild(size_t element) {
    546   children_.push_back(element);
    547 }
    548 
    549 PP_VarType ArrayRawVarData::Type() {
    550   return PP_VARTYPE_ARRAY;
    551 }
    552 
    553 bool ArrayRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) {
    554   initialized_ = true;
    555   DCHECK(var.type == PP_VARTYPE_ARRAY);
    556   initialized_ = true;
    557   return true;
    558 }
    559 
    560 PP_Var ArrayRawVarData::CreatePPVar(PP_Instance instance) {
    561   return (new ArrayVar())->GetPPVar();
    562 }
    563 
    564 void ArrayRawVarData::PopulatePPVar(const PP_Var& var,
    565                                     const std::vector<PP_Var>& graph) {
    566   if (var.type != PP_VARTYPE_ARRAY) {
    567     NOTREACHED();
    568     return;
    569   }
    570   ArrayVar* array_var = ArrayVar::FromPPVar(var);
    571   DCHECK(array_var->elements().empty());
    572   for (size_t i = 0; i < children_.size(); ++i)
    573     array_var->elements().push_back(ScopedPPVar(graph[children_[i]]));
    574 }
    575 
    576 void ArrayRawVarData::Write(IPC::Message* m,
    577                             const HandleWriter& handle_writer) {
    578   m->WriteUInt32(static_cast<uint32_t>(children_.size()));
    579   for (size_t i = 0; i < children_.size(); ++i)
    580     m->WriteUInt32(static_cast<uint32_t>(children_[i]));
    581 }
    582 
    583 bool ArrayRawVarData::Read(PP_VarType type,
    584                            const IPC::Message* m,
    585                            PickleIterator* iter) {
    586   uint32_t size;
    587   if (!m->ReadUInt32(iter, &size))
    588     return false;
    589   for (uint32_t i = 0; i < size; ++i) {
    590     uint32_t index;
    591     if (!m->ReadUInt32(iter, &index))
    592       return false;
    593     children_.push_back(index);
    594   }
    595   return true;
    596 }
    597 
    598 // DictionaryRawVarData --------------------------------------------------------
    599 DictionaryRawVarData::DictionaryRawVarData() {
    600 }
    601 
    602 DictionaryRawVarData::~DictionaryRawVarData() {
    603 }
    604 
    605 void DictionaryRawVarData::AddChild(const std::string& key,
    606                                     size_t value) {
    607   children_.push_back(make_pair(key, value));
    608 }
    609 
    610 PP_VarType DictionaryRawVarData::Type() {
    611   return PP_VARTYPE_DICTIONARY;
    612 }
    613 
    614 bool DictionaryRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) {
    615   DCHECK(var.type == PP_VARTYPE_DICTIONARY);
    616   initialized_ = true;
    617   return true;
    618 }
    619 
    620 PP_Var DictionaryRawVarData::CreatePPVar(PP_Instance instance) {
    621   return (new DictionaryVar())->GetPPVar();
    622 }
    623 
    624 void DictionaryRawVarData::PopulatePPVar(const PP_Var& var,
    625                                          const std::vector<PP_Var>& graph) {
    626   if (var.type != PP_VARTYPE_DICTIONARY) {
    627     NOTREACHED();
    628     return;
    629   }
    630   DictionaryVar* dictionary_var = DictionaryVar::FromPPVar(var);
    631   DCHECK(dictionary_var->key_value_map().empty());
    632   for (size_t i = 0; i < children_.size(); ++i) {
    633     bool success = dictionary_var->SetWithStringKey(children_[i].first,
    634                                                     graph[children_[i].second]);
    635     DCHECK(success);
    636   }
    637 }
    638 
    639 void DictionaryRawVarData::Write(
    640     IPC::Message* m,
    641     const HandleWriter& handle_writer) {
    642   m->WriteUInt32(static_cast<uint32_t>(children_.size()));
    643   for (size_t i = 0; i < children_.size(); ++i) {
    644     m->WriteString(children_[i].first);
    645     m->WriteUInt32(static_cast<uint32_t>(children_[i].second));
    646   }
    647 }
    648 
    649 bool DictionaryRawVarData::Read(PP_VarType type,
    650                                 const IPC::Message* m,
    651                                 PickleIterator* iter) {
    652   uint32_t size;
    653   if (!m->ReadUInt32(iter, &size))
    654     return false;
    655   for (uint32_t i = 0; i < size; ++i) {
    656     std::string key;
    657     uint32_t value;
    658     if (!m->ReadString(iter, &key))
    659       return false;
    660     if (!m->ReadUInt32(iter, &value))
    661       return false;
    662     children_.push_back(make_pair(key, value));
    663   }
    664   return true;
    665 }
    666 
    667 // ResourceRawVarData ----------------------------------------------------------
    668 ResourceRawVarData::ResourceRawVarData()
    669     : pp_resource_(0),
    670       pending_renderer_host_id_(0),
    671       pending_browser_host_id_(0) {}
    672 
    673 ResourceRawVarData::~ResourceRawVarData() {
    674 }
    675 
    676 PP_VarType ResourceRawVarData::Type() {
    677   return PP_VARTYPE_RESOURCE;
    678 }
    679 
    680 bool ResourceRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) {
    681   DCHECK(var.type == PP_VARTYPE_RESOURCE);
    682   ResourceVar* resource_var = ResourceVar::FromPPVar(var);
    683   if (!resource_var)
    684     return false;
    685   pp_resource_ = resource_var->GetPPResource();
    686   const IPC::Message* message = resource_var->GetCreationMessage();
    687   if (message)
    688     creation_message_.reset(new IPC::Message(*message));
    689   else
    690     creation_message_.reset();
    691   pending_renderer_host_id_ = resource_var->GetPendingRendererHostId();
    692   pending_browser_host_id_ = resource_var->GetPendingBrowserHostId();
    693   initialized_ = true;
    694   return true;
    695 }
    696 
    697 PP_Var ResourceRawVarData::CreatePPVar(PP_Instance instance) {
    698   // If this is not a pending resource host, just create the var.
    699   if (pp_resource_ || !creation_message_) {
    700     return PpapiGlobals::Get()->GetVarTracker()->MakeResourcePPVar(
    701         pp_resource_);
    702   }
    703 
    704   // This is a pending resource host, so create the resource and var.
    705   return PpapiGlobals::Get()->GetVarTracker()->MakeResourcePPVarFromMessage(
    706       instance,
    707       *creation_message_,
    708       pending_renderer_host_id_,
    709       pending_browser_host_id_);
    710 }
    711 
    712 void ResourceRawVarData::PopulatePPVar(const PP_Var& var,
    713                                        const std::vector<PP_Var>& graph) {
    714 }
    715 
    716 void ResourceRawVarData::Write(IPC::Message* m,
    717                                const HandleWriter& handle_writer) {
    718   m->WriteInt(static_cast<int>(pp_resource_));
    719   m->WriteInt(pending_renderer_host_id_);
    720   m->WriteInt(pending_browser_host_id_);
    721   m->WriteBool(creation_message_);
    722   if (creation_message_)
    723     IPC::ParamTraits<IPC::Message>::Write(m, *creation_message_);
    724 }
    725 
    726 bool ResourceRawVarData::Read(PP_VarType type,
    727                               const IPC::Message* m,
    728                               PickleIterator* iter) {
    729   int value;
    730   if (!m->ReadInt(iter, &value))
    731     return false;
    732   pp_resource_ = static_cast<PP_Resource>(value);
    733   if (!m->ReadInt(iter, &pending_renderer_host_id_))
    734     return false;
    735   if (!m->ReadInt(iter, &pending_browser_host_id_))
    736     return false;
    737   bool has_creation_message;
    738   if (!m->ReadBool(iter, &has_creation_message))
    739     return false;
    740   if (has_creation_message) {
    741     creation_message_.reset(new IPC::Message());
    742     if (!IPC::ParamTraits<IPC::Message>::Read(m, iter, creation_message_.get()))
    743       return false;
    744   } else {
    745     creation_message_.reset();
    746   }
    747   return true;
    748 }
    749 
    750 }  // namespace proxy
    751 }  // namespace ppapi
    752