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
21using std::make_pair;
22
23namespace ppapi {
24namespace proxy {
25
26namespace {
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.
31static const uint32 kMinimumArrayBufferSizeForShmem = 256 * 1024;
32static uint32 g_minimum_array_buffer_size_for_shmem =
33    kMinimumArrayBufferSizeForShmem;
34
35struct 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.
45size_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
63bool CanHaveChildren(PP_Var var) {
64  return var.type == PP_VARTYPE_ARRAY || var.type == PP_VARTYPE_DICTIONARY;
65}
66
67}  // namespace
68
69// RawVarDataGraph ------------------------------------------------------------
70RawVarDataGraph::RawVarDataGraph() {
71}
72
73RawVarDataGraph::~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
86scoped_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
162PP_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
176void 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
187scoped_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
205std::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
216void 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
227RawVarData* 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
251RawVarData::RawVarData() : initialized_(false) {
252}
253
254RawVarData::~RawVarData() {
255}
256
257SerializedHandle* RawVarData::GetHandle() {
258  return NULL;
259}
260
261// BasicRawVarData -------------------------------------------------------------
262BasicRawVarData::BasicRawVarData() {
263}
264
265BasicRawVarData::~BasicRawVarData() {
266}
267
268PP_VarType BasicRawVarData::Type() {
269  return var_.type;
270}
271
272bool BasicRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) {
273  var_ = var;
274  initialized_ = true;
275  return true;
276}
277
278PP_Var BasicRawVarData::CreatePPVar(PP_Instance instance) {
279  return var_;
280}
281
282void BasicRawVarData::PopulatePPVar(const PP_Var& var,
283                                    const std::vector<PP_Var>& graph) {
284}
285
286void 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
313bool 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 ------------------------------------------------------------
352StringRawVarData::StringRawVarData() {
353}
354
355StringRawVarData::~StringRawVarData() {
356}
357
358PP_VarType StringRawVarData::Type() {
359  return PP_VARTYPE_STRING;
360}
361
362bool 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
372PP_Var StringRawVarData::CreatePPVar(PP_Instance instance) {
373  return StringVar::SwapValidatedUTF8StringIntoPPVar(&data_);
374}
375
376void StringRawVarData::PopulatePPVar(const PP_Var& var,
377                                     const std::vector<PP_Var>& graph) {
378}
379
380void StringRawVarData::Write(IPC::Message* m,
381                             const HandleWriter& handle_writer) {
382  m->WriteString(data_);
383}
384
385bool 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 -------------------------------------------------------
394ArrayBufferRawVarData::ArrayBufferRawVarData() {
395}
396
397ArrayBufferRawVarData::~ArrayBufferRawVarData() {
398}
399
400PP_VarType ArrayBufferRawVarData::Type() {
401  return PP_VARTYPE_ARRAY_BUFFER;
402}
403
404bool 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
442PP_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
481void ArrayBufferRawVarData::PopulatePPVar(const PP_Var& var,
482                                          const std::vector<PP_Var>& graph) {
483}
484
485void 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
502bool 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
532SerializedHandle* 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 -------------------------------------------------------------
539ArrayRawVarData::ArrayRawVarData() {
540}
541
542ArrayRawVarData::~ArrayRawVarData() {
543}
544
545void ArrayRawVarData::AddChild(size_t element) {
546  children_.push_back(element);
547}
548
549PP_VarType ArrayRawVarData::Type() {
550  return PP_VARTYPE_ARRAY;
551}
552
553bool 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
560PP_Var ArrayRawVarData::CreatePPVar(PP_Instance instance) {
561  return (new ArrayVar())->GetPPVar();
562}
563
564void 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
576void 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
583bool 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 --------------------------------------------------------
599DictionaryRawVarData::DictionaryRawVarData() {
600}
601
602DictionaryRawVarData::~DictionaryRawVarData() {
603}
604
605void DictionaryRawVarData::AddChild(const std::string& key,
606                                    size_t value) {
607  children_.push_back(make_pair(key, value));
608}
609
610PP_VarType DictionaryRawVarData::Type() {
611  return PP_VARTYPE_DICTIONARY;
612}
613
614bool DictionaryRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) {
615  DCHECK(var.type == PP_VARTYPE_DICTIONARY);
616  initialized_ = true;
617  return true;
618}
619
620PP_Var DictionaryRawVarData::CreatePPVar(PP_Instance instance) {
621  return (new DictionaryVar())->GetPPVar();
622}
623
624void 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
639void 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
649bool 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 ----------------------------------------------------------
668ResourceRawVarData::ResourceRawVarData()
669    : pp_resource_(0),
670      pending_renderer_host_id_(0),
671      pending_browser_host_id_(0) {}
672
673ResourceRawVarData::~ResourceRawVarData() {
674}
675
676PP_VarType ResourceRawVarData::Type() {
677  return PP_VARTYPE_RESOURCE;
678}
679
680bool 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
697PP_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
712void ResourceRawVarData::PopulatePPVar(const PP_Var& var,
713                                       const std::vector<PP_Var>& graph) {
714}
715
716void 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
726bool 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