| // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ppapi/proxy/raw_var_data.h" |
| |
| #include "base/containers/hash_tables.h" |
| #include "base/containers/stack.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/stl_util.h" |
| #include "ipc/ipc_message.h" |
| #include "ppapi/proxy/ppapi_param_traits.h" |
| #include "ppapi/shared_impl/array_var.h" |
| #include "ppapi/shared_impl/dictionary_var.h" |
| #include "ppapi/shared_impl/ppapi_globals.h" |
| #include "ppapi/shared_impl/resource_var.h" |
| #include "ppapi/shared_impl/scoped_pp_var.h" |
| #include "ppapi/shared_impl/var.h" |
| #include "ppapi/shared_impl/var_tracker.h" |
| |
| using std::make_pair; |
| |
| namespace ppapi { |
| namespace proxy { |
| |
| namespace { |
| |
| // When sending array buffers, if the size is over 256K, we use shared |
| // memory instead of sending the data over IPC. Light testing suggests |
| // shared memory is much faster for 256K and larger messages. |
| static const uint32_t kMinimumArrayBufferSizeForShmem = 256 * 1024; |
| static uint32_t g_minimum_array_buffer_size_for_shmem = |
| kMinimumArrayBufferSizeForShmem; |
| |
| struct StackEntry { |
| StackEntry(PP_Var v, size_t i) : var(v), data_index(i) {} |
| PP_Var var; |
| size_t data_index; |
| }; |
| |
| // For a given PP_Var, returns the RawVarData associated with it, or creates a |
| // new one if there is no existing one. The data is appended to |data| if it |
| // is newly created. The index into |data| pointing to the result is returned. |
| // |visited_map| keeps track of RawVarDatas that have already been created. |
| size_t GetOrCreateRawVarData(const PP_Var& var, |
| base::hash_map<int64_t, size_t>* visited_map, |
| std::vector<std::unique_ptr<RawVarData>>* data) { |
| if (VarTracker::IsVarTypeRefcounted(var.type)) { |
| base::hash_map<int64_t, size_t>::iterator it = visited_map->find( |
| var.value.as_id); |
| if (it != visited_map->end()) { |
| return it->second; |
| } else { |
| data->push_back(base::WrapUnique(RawVarData::Create(var.type))); |
| (*visited_map)[var.value.as_id] = data->size() - 1; |
| } |
| } else { |
| data->push_back(base::WrapUnique(RawVarData::Create(var.type))); |
| } |
| return data->size() - 1; |
| } |
| |
| bool CanHaveChildren(PP_Var var) { |
| return var.type == PP_VARTYPE_ARRAY || var.type == PP_VARTYPE_DICTIONARY; |
| } |
| |
| } // namespace |
| |
| // RawVarDataGraph ------------------------------------------------------------ |
| RawVarDataGraph::RawVarDataGraph() { |
| } |
| |
| RawVarDataGraph::~RawVarDataGraph() { |
| } |
| |
| // This function uses a stack-based DFS search to traverse the var graph. Each |
| // iteration, the top node on the stack examined. If the node has not been |
| // visited yet (i.e. !initialized()) then it is added to the list of |
| // |parent_ids| which contains all of the nodes on the path from the start node |
| // to the current node. Each of that nodes children are examined. If they appear |
| // in the list of |parent_ids| it means we have a cycle and we return NULL. |
| // Otherwise, if they haven't been visited yet we add them to the stack, If the |
| // node at the top of the stack has already been visited, then we pop it off the |
| // stack and erase it from |parent_ids|. |
| // static |
| std::unique_ptr<RawVarDataGraph> RawVarDataGraph::Create(const PP_Var& var, |
| PP_Instance instance) { |
| std::unique_ptr<RawVarDataGraph> graph(new RawVarDataGraph); |
| // Map of |var.value.as_id| to a RawVarData index in RawVarDataGraph. |
| base::hash_map<int64_t, size_t> visited_map; |
| base::hash_set<int64_t> parent_ids; |
| |
| base::stack<StackEntry> stack; |
| stack.push(StackEntry(var, GetOrCreateRawVarData(var, &visited_map, |
| &graph->data_))); |
| |
| while (!stack.empty()) { |
| PP_Var current_var = stack.top().var; |
| RawVarData* current_var_data = graph->data_[stack.top().data_index].get(); |
| |
| if (current_var_data->initialized()) { |
| stack.pop(); |
| if (CanHaveChildren(current_var)) |
| parent_ids.erase(current_var.value.as_id); |
| continue; |
| } |
| |
| if (CanHaveChildren(current_var)) |
| parent_ids.insert(current_var.value.as_id); |
| if (!current_var_data->Init(current_var, instance)) { |
| NOTREACHED(); |
| return nullptr; |
| } |
| |
| // Add child nodes to the stack. |
| if (current_var.type == PP_VARTYPE_ARRAY) { |
| ArrayVar* array_var = ArrayVar::FromPPVar(current_var); |
| if (!array_var) { |
| NOTREACHED(); |
| return nullptr; |
| } |
| for (ArrayVar::ElementVector::const_iterator iter = |
| array_var->elements().begin(); |
| iter != array_var->elements().end(); |
| ++iter) { |
| const PP_Var& child = iter->get(); |
| // If a child of this node is already in parent_ids, we have a cycle so |
| // we just return null. |
| if (CanHaveChildren(child) && parent_ids.count(child.value.as_id) != 0) |
| return nullptr; |
| size_t child_id = GetOrCreateRawVarData(child, &visited_map, |
| &graph->data_); |
| static_cast<ArrayRawVarData*>(current_var_data)->AddChild(child_id); |
| if (!graph->data_[child_id]->initialized()) |
| stack.push(StackEntry(child, child_id)); |
| } |
| } else if (current_var.type == PP_VARTYPE_DICTIONARY) { |
| DictionaryVar* dict_var = DictionaryVar::FromPPVar(current_var); |
| if (!dict_var) { |
| NOTREACHED(); |
| return nullptr; |
| } |
| for (DictionaryVar::KeyValueMap::const_iterator iter = |
| dict_var->key_value_map().begin(); |
| iter != dict_var->key_value_map().end(); |
| ++iter) { |
| const PP_Var& child = iter->second.get(); |
| if (CanHaveChildren(child) && parent_ids.count(child.value.as_id) != 0) |
| return nullptr; |
| size_t child_id = GetOrCreateRawVarData(child, &visited_map, |
| &graph->data_); |
| static_cast<DictionaryRawVarData*>( |
| current_var_data)->AddChild(iter->first, child_id); |
| if (!graph->data_[child_id]->initialized()) |
| stack.push(StackEntry(child, child_id)); |
| } |
| } |
| } |
| return graph; |
| } |
| |
| PP_Var RawVarDataGraph::CreatePPVar(PP_Instance instance) { |
| // Create and initialize each node in the graph. |
| std::vector<PP_Var> graph; |
| for (size_t i = 0; i < data_.size(); ++i) |
| graph.push_back(data_[i]->CreatePPVar(instance)); |
| for (size_t i = 0; i < data_.size(); ++i) |
| data_[i]->PopulatePPVar(graph[i], graph); |
| // Everything except the root will have one extra ref. Remove that ref. |
| for (size_t i = 1; i < data_.size(); ++i) |
| ScopedPPVar(ScopedPPVar::PassRef(), graph[i]); |
| // The first element is the root. |
| return graph[0]; |
| } |
| |
| void RawVarDataGraph::Write(base::Pickle* m, |
| const HandleWriter& handle_writer) { |
| // Write the size, followed by each node in the graph. |
| m->WriteUInt32(static_cast<uint32_t>(data_.size())); |
| for (size_t i = 0; i < data_.size(); ++i) { |
| m->WriteInt(data_[i]->Type()); |
| data_[i]->Write(m, handle_writer); |
| } |
| } |
| |
| // static |
| std::unique_ptr<RawVarDataGraph> RawVarDataGraph::Read( |
| const base::Pickle* m, |
| base::PickleIterator* iter) { |
| std::unique_ptr<RawVarDataGraph> result(new RawVarDataGraph); |
| uint32_t size = 0; |
| if (!iter->ReadUInt32(&size)) |
| return nullptr; |
| for (uint32_t i = 0; i < size; ++i) { |
| int32_t type; |
| if (!iter->ReadInt(&type)) |
| return nullptr; |
| PP_VarType var_type = static_cast<PP_VarType>(type); |
| result->data_.push_back(base::WrapUnique(RawVarData::Create(var_type))); |
| if (!result->data_.back()) |
| return nullptr; |
| if (!result->data_.back()->Read(var_type, m, iter)) |
| return nullptr; |
| } |
| return result; |
| } |
| |
| std::vector<SerializedHandle*> RawVarDataGraph::GetHandles() { |
| std::vector<SerializedHandle*> result; |
| for (size_t i = 0; i < data_.size(); ++i) { |
| SerializedHandle* handle = data_[i]->GetHandle(); |
| if (handle) |
| result.push_back(handle); |
| } |
| return result; |
| } |
| |
| // static |
| void RawVarDataGraph::SetMinimumArrayBufferSizeForShmemForTest( |
| uint32_t threshold) { |
| if (threshold == 0) |
| g_minimum_array_buffer_size_for_shmem = kMinimumArrayBufferSizeForShmem; |
| else |
| g_minimum_array_buffer_size_for_shmem = threshold; |
| } |
| |
| // RawVarData ------------------------------------------------------------------ |
| |
| // static |
| RawVarData* RawVarData::Create(PP_VarType type) { |
| switch (type) { |
| case PP_VARTYPE_UNDEFINED: |
| case PP_VARTYPE_NULL: |
| case PP_VARTYPE_BOOL: |
| case PP_VARTYPE_INT32: |
| case PP_VARTYPE_DOUBLE: |
| case PP_VARTYPE_OBJECT: |
| return new BasicRawVarData(); |
| case PP_VARTYPE_STRING: |
| return new StringRawVarData(); |
| case PP_VARTYPE_ARRAY_BUFFER: |
| return new ArrayBufferRawVarData(); |
| case PP_VARTYPE_ARRAY: |
| return new ArrayRawVarData(); |
| case PP_VARTYPE_DICTIONARY: |
| return new DictionaryRawVarData(); |
| case PP_VARTYPE_RESOURCE: |
| return new ResourceRawVarData(); |
| } |
| NOTREACHED(); |
| return NULL; |
| } |
| |
| RawVarData::RawVarData() : initialized_(false) { |
| } |
| |
| RawVarData::~RawVarData() { |
| } |
| |
| SerializedHandle* RawVarData::GetHandle() { |
| return NULL; |
| } |
| |
| // BasicRawVarData ------------------------------------------------------------- |
| BasicRawVarData::BasicRawVarData() { |
| } |
| |
| BasicRawVarData::~BasicRawVarData() { |
| } |
| |
| PP_VarType BasicRawVarData::Type() { |
| return var_.type; |
| } |
| |
| bool BasicRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) { |
| var_ = var; |
| initialized_ = true; |
| return true; |
| } |
| |
| PP_Var BasicRawVarData::CreatePPVar(PP_Instance instance) { |
| return var_; |
| } |
| |
| void BasicRawVarData::PopulatePPVar(const PP_Var& var, |
| const std::vector<PP_Var>& graph) { |
| } |
| |
| void BasicRawVarData::Write(base::Pickle* m, |
| const HandleWriter& handle_writer) { |
| switch (var_.type) { |
| case PP_VARTYPE_UNDEFINED: |
| case PP_VARTYPE_NULL: |
| // These don't need any data associated with them other than the type we |
| // just serialized. |
| break; |
| case PP_VARTYPE_BOOL: |
| m->WriteBool(PP_ToBool(var_.value.as_bool)); |
| break; |
| case PP_VARTYPE_INT32: |
| m->WriteInt(var_.value.as_int); |
| break; |
| case PP_VARTYPE_DOUBLE: |
| IPC::WriteParam(m, var_.value.as_double); |
| break; |
| case PP_VARTYPE_OBJECT: |
| m->WriteInt64(var_.value.as_id); |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| } |
| |
| bool BasicRawVarData::Read(PP_VarType type, |
| const base::Pickle* m, |
| base::PickleIterator* iter) { |
| PP_Var result; |
| result.type = type; |
| switch (type) { |
| case PP_VARTYPE_UNDEFINED: |
| case PP_VARTYPE_NULL: |
| // These don't have any data associated with them other than the type we |
| // just deserialized. |
| break; |
| case PP_VARTYPE_BOOL: { |
| bool bool_value; |
| if (!iter->ReadBool(&bool_value)) |
| return false; |
| result.value.as_bool = PP_FromBool(bool_value); |
| break; |
| } |
| case PP_VARTYPE_INT32: |
| if (!iter->ReadInt(&result.value.as_int)) |
| return false; |
| break; |
| case PP_VARTYPE_DOUBLE: |
| if (!IPC::ReadParam(m, iter, &result.value.as_double)) |
| return false; |
| break; |
| case PP_VARTYPE_OBJECT: |
| if (!iter->ReadInt64(&result.value.as_id)) |
| return false; |
| break; |
| default: |
| NOTREACHED(); |
| return false; |
| } |
| var_ = result; |
| return true; |
| } |
| |
| // StringRawVarData ------------------------------------------------------------ |
| StringRawVarData::StringRawVarData() { |
| } |
| |
| StringRawVarData::~StringRawVarData() { |
| } |
| |
| PP_VarType StringRawVarData::Type() { |
| return PP_VARTYPE_STRING; |
| } |
| |
| bool StringRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) { |
| DCHECK(var.type == PP_VARTYPE_STRING); |
| StringVar* string_var = StringVar::FromPPVar(var); |
| if (!string_var) |
| return false; |
| data_ = string_var->value(); |
| initialized_ = true; |
| return true; |
| } |
| |
| PP_Var StringRawVarData::CreatePPVar(PP_Instance instance) { |
| return StringVar::SwapValidatedUTF8StringIntoPPVar(&data_); |
| } |
| |
| void StringRawVarData::PopulatePPVar(const PP_Var& var, |
| const std::vector<PP_Var>& graph) { |
| } |
| |
| void StringRawVarData::Write(base::Pickle* m, |
| const HandleWriter& handle_writer) { |
| m->WriteString(data_); |
| } |
| |
| bool StringRawVarData::Read(PP_VarType type, |
| const base::Pickle* m, |
| base::PickleIterator* iter) { |
| if (!iter->ReadString(&data_)) |
| return false; |
| return true; |
| } |
| |
| // ArrayBufferRawVarData ------------------------------------------------------- |
| ArrayBufferRawVarData::ArrayBufferRawVarData() { |
| } |
| |
| ArrayBufferRawVarData::~ArrayBufferRawVarData() { |
| } |
| |
| PP_VarType ArrayBufferRawVarData::Type() { |
| return PP_VARTYPE_ARRAY_BUFFER; |
| } |
| |
| bool ArrayBufferRawVarData::Init(const PP_Var& var, |
| PP_Instance instance) { |
| DCHECK(var.type == PP_VARTYPE_ARRAY_BUFFER); |
| ArrayBufferVar* buffer_var = ArrayBufferVar::FromPPVar(var); |
| if (!buffer_var) |
| return false; |
| bool using_shmem = false; |
| if (buffer_var->ByteLength() >= g_minimum_array_buffer_size_for_shmem && |
| instance != 0) { |
| int host_handle_id; |
| base::SharedMemoryHandle plugin_handle; |
| using_shmem = buffer_var->CopyToNewShmem(instance, |
| &host_handle_id, |
| &plugin_handle); |
| if (using_shmem) { |
| if (host_handle_id != -1) { |
| DCHECK(!base::SharedMemory::IsHandleValid(plugin_handle)); |
| DCHECK(PpapiGlobals::Get()->IsPluginGlobals()); |
| type_ = ARRAY_BUFFER_SHMEM_HOST; |
| host_shm_handle_id_ = host_handle_id; |
| } else { |
| DCHECK(base::SharedMemory::IsHandleValid(plugin_handle)); |
| DCHECK(PpapiGlobals::Get()->IsHostGlobals()); |
| type_ = ARRAY_BUFFER_SHMEM_PLUGIN; |
| plugin_shm_handle_ = SerializedHandle(plugin_handle, |
| buffer_var->ByteLength()); |
| } |
| } |
| } |
| if (!using_shmem) { |
| type_ = ARRAY_BUFFER_NO_SHMEM; |
| data_ = std::string(static_cast<const char*>(buffer_var->Map()), |
| buffer_var->ByteLength()); |
| } |
| initialized_ = true; |
| return true; |
| } |
| |
| PP_Var ArrayBufferRawVarData::CreatePPVar(PP_Instance instance) { |
| PP_Var result = PP_MakeUndefined(); |
| switch (type_) { |
| case ARRAY_BUFFER_SHMEM_HOST: { |
| base::SharedMemoryHandle host_handle; |
| uint32_t size_in_bytes; |
| bool ok = PpapiGlobals::Get()->GetVarTracker()-> |
| StopTrackingSharedMemoryHandle(host_shm_handle_id_, |
| instance, |
| &host_handle, |
| &size_in_bytes); |
| if (ok) { |
| result = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( |
| size_in_bytes, host_handle); |
| } else { |
| LOG(ERROR) << "Couldn't find array buffer id: " << host_shm_handle_id_; |
| return PP_MakeUndefined(); |
| } |
| break; |
| } |
| case ARRAY_BUFFER_SHMEM_PLUGIN: { |
| result = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( |
| plugin_shm_handle_.size(), |
| plugin_shm_handle_.shmem()); |
| break; |
| } |
| case ARRAY_BUFFER_NO_SHMEM: { |
| result = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( |
| static_cast<uint32_t>(data_.size()), data_.data()); |
| break; |
| } |
| default: |
| NOTREACHED(); |
| return PP_MakeUndefined(); |
| } |
| DCHECK(result.type == PP_VARTYPE_ARRAY_BUFFER); |
| return result; |
| } |
| |
| void ArrayBufferRawVarData::PopulatePPVar(const PP_Var& var, |
| const std::vector<PP_Var>& graph) { |
| } |
| |
| void ArrayBufferRawVarData::Write(base::Pickle* m, |
| const HandleWriter& handle_writer) { |
| m->WriteInt(type_); |
| switch (type_) { |
| case ARRAY_BUFFER_SHMEM_HOST: |
| m->WriteInt(host_shm_handle_id_); |
| break; |
| case ARRAY_BUFFER_SHMEM_PLUGIN: |
| handle_writer.Run(m, plugin_shm_handle_); |
| break; |
| case ARRAY_BUFFER_NO_SHMEM: |
| m->WriteString(data_); |
| break; |
| } |
| } |
| |
| bool ArrayBufferRawVarData::Read(PP_VarType type, |
| const base::Pickle* m, |
| base::PickleIterator* iter) { |
| int shmem_type; |
| if (!iter->ReadInt(&shmem_type)) |
| return false; |
| type_ = static_cast<ShmemType>(shmem_type); |
| switch (type_) { |
| case ARRAY_BUFFER_SHMEM_HOST: |
| if (!iter->ReadInt(&host_shm_handle_id_)) |
| return false; |
| break; |
| case ARRAY_BUFFER_SHMEM_PLUGIN: |
| if (!IPC::ReadParam(m, iter, &plugin_shm_handle_)) { |
| return false; |
| } |
| break; |
| case ARRAY_BUFFER_NO_SHMEM: |
| if (!iter->ReadString(&data_)) |
| return false; |
| break; |
| default: |
| // We read an invalid ID. |
| NOTREACHED(); |
| return false; |
| } |
| return true; |
| } |
| |
| SerializedHandle* ArrayBufferRawVarData::GetHandle() { |
| if (type_ == ARRAY_BUFFER_SHMEM_PLUGIN && plugin_shm_handle_.size() != 0) |
| return &plugin_shm_handle_; |
| return NULL; |
| } |
| |
| // ArrayRawVarData ------------------------------------------------------------- |
| ArrayRawVarData::ArrayRawVarData() { |
| } |
| |
| ArrayRawVarData::~ArrayRawVarData() { |
| } |
| |
| void ArrayRawVarData::AddChild(size_t element) { |
| children_.push_back(element); |
| } |
| |
| PP_VarType ArrayRawVarData::Type() { |
| return PP_VARTYPE_ARRAY; |
| } |
| |
| bool ArrayRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) { |
| initialized_ = true; |
| DCHECK(var.type == PP_VARTYPE_ARRAY); |
| initialized_ = true; |
| return true; |
| } |
| |
| PP_Var ArrayRawVarData::CreatePPVar(PP_Instance instance) { |
| return (new ArrayVar())->GetPPVar(); |
| } |
| |
| void ArrayRawVarData::PopulatePPVar(const PP_Var& var, |
| const std::vector<PP_Var>& graph) { |
| if (var.type != PP_VARTYPE_ARRAY) { |
| NOTREACHED(); |
| return; |
| } |
| ArrayVar* array_var = ArrayVar::FromPPVar(var); |
| DCHECK(array_var->elements().empty()); |
| for (size_t i = 0; i < children_.size(); ++i) |
| array_var->elements().push_back(ScopedPPVar(graph[children_[i]])); |
| } |
| |
| void ArrayRawVarData::Write(base::Pickle* m, |
| const HandleWriter& handle_writer) { |
| m->WriteUInt32(static_cast<uint32_t>(children_.size())); |
| for (size_t i = 0; i < children_.size(); ++i) |
| m->WriteUInt32(static_cast<uint32_t>(children_[i])); |
| } |
| |
| bool ArrayRawVarData::Read(PP_VarType type, |
| const base::Pickle* m, |
| base::PickleIterator* iter) { |
| uint32_t size; |
| if (!iter->ReadUInt32(&size)) |
| return false; |
| for (uint32_t i = 0; i < size; ++i) { |
| uint32_t index; |
| if (!iter->ReadUInt32(&index)) |
| return false; |
| children_.push_back(index); |
| } |
| return true; |
| } |
| |
| // DictionaryRawVarData -------------------------------------------------------- |
| DictionaryRawVarData::DictionaryRawVarData() { |
| } |
| |
| DictionaryRawVarData::~DictionaryRawVarData() { |
| } |
| |
| void DictionaryRawVarData::AddChild(const std::string& key, |
| size_t value) { |
| children_.push_back(make_pair(key, value)); |
| } |
| |
| PP_VarType DictionaryRawVarData::Type() { |
| return PP_VARTYPE_DICTIONARY; |
| } |
| |
| bool DictionaryRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) { |
| DCHECK(var.type == PP_VARTYPE_DICTIONARY); |
| initialized_ = true; |
| return true; |
| } |
| |
| PP_Var DictionaryRawVarData::CreatePPVar(PP_Instance instance) { |
| return (new DictionaryVar())->GetPPVar(); |
| } |
| |
| void DictionaryRawVarData::PopulatePPVar(const PP_Var& var, |
| const std::vector<PP_Var>& graph) { |
| if (var.type != PP_VARTYPE_DICTIONARY) { |
| NOTREACHED(); |
| return; |
| } |
| DictionaryVar* dictionary_var = DictionaryVar::FromPPVar(var); |
| DCHECK(dictionary_var->key_value_map().empty()); |
| for (size_t i = 0; i < children_.size(); ++i) { |
| bool success = dictionary_var->SetWithStringKey(children_[i].first, |
| graph[children_[i].second]); |
| DCHECK(success); |
| } |
| } |
| |
| void DictionaryRawVarData::Write(base::Pickle* m, |
| const HandleWriter& handle_writer) { |
| m->WriteUInt32(static_cast<uint32_t>(children_.size())); |
| for (size_t i = 0; i < children_.size(); ++i) { |
| m->WriteString(children_[i].first); |
| m->WriteUInt32(static_cast<uint32_t>(children_[i].second)); |
| } |
| } |
| |
| bool DictionaryRawVarData::Read(PP_VarType type, |
| const base::Pickle* m, |
| base::PickleIterator* iter) { |
| uint32_t size; |
| if (!iter->ReadUInt32(&size)) |
| return false; |
| for (uint32_t i = 0; i < size; ++i) { |
| std::string key; |
| uint32_t value; |
| if (!iter->ReadString(&key)) |
| return false; |
| if (!iter->ReadUInt32(&value)) |
| return false; |
| children_.push_back(make_pair(key, value)); |
| } |
| return true; |
| } |
| |
| // ResourceRawVarData ---------------------------------------------------------- |
| ResourceRawVarData::ResourceRawVarData() |
| : pp_resource_(0), |
| pending_renderer_host_id_(0), |
| pending_browser_host_id_(0) {} |
| |
| ResourceRawVarData::~ResourceRawVarData() { |
| } |
| |
| PP_VarType ResourceRawVarData::Type() { |
| return PP_VARTYPE_RESOURCE; |
| } |
| |
| bool ResourceRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) { |
| DCHECK(var.type == PP_VARTYPE_RESOURCE); |
| ResourceVar* resource_var = ResourceVar::FromPPVar(var); |
| if (!resource_var) |
| return false; |
| pp_resource_ = resource_var->GetPPResource(); |
| const IPC::Message* message = resource_var->GetCreationMessage(); |
| if (message) |
| creation_message_.reset(new IPC::Message(*message)); |
| else |
| creation_message_.reset(); |
| pending_renderer_host_id_ = resource_var->GetPendingRendererHostId(); |
| pending_browser_host_id_ = resource_var->GetPendingBrowserHostId(); |
| initialized_ = true; |
| return true; |
| } |
| |
| PP_Var ResourceRawVarData::CreatePPVar(PP_Instance instance) { |
| // If this is not a pending resource host, just create the var. |
| if (pp_resource_ || !creation_message_) { |
| return PpapiGlobals::Get()->GetVarTracker()->MakeResourcePPVar( |
| pp_resource_); |
| } |
| |
| // This is a pending resource host, so create the resource and var. |
| return PpapiGlobals::Get()->GetVarTracker()->MakeResourcePPVarFromMessage( |
| instance, |
| *creation_message_, |
| pending_renderer_host_id_, |
| pending_browser_host_id_); |
| } |
| |
| void ResourceRawVarData::PopulatePPVar(const PP_Var& var, |
| const std::vector<PP_Var>& graph) { |
| } |
| |
| void ResourceRawVarData::Write(base::Pickle* m, |
| const HandleWriter& handle_writer) { |
| m->WriteInt(static_cast<int>(pp_resource_)); |
| m->WriteInt(pending_renderer_host_id_); |
| m->WriteInt(pending_browser_host_id_); |
| m->WriteBool(!!creation_message_); |
| if (creation_message_) |
| IPC::WriteParam(m, *creation_message_); |
| } |
| |
| bool ResourceRawVarData::Read(PP_VarType type, |
| const base::Pickle* m, |
| base::PickleIterator* iter) { |
| int value; |
| if (!iter->ReadInt(&value)) |
| return false; |
| pp_resource_ = static_cast<PP_Resource>(value); |
| if (!iter->ReadInt(&pending_renderer_host_id_)) |
| return false; |
| if (!iter->ReadInt(&pending_browser_host_id_)) |
| return false; |
| bool has_creation_message; |
| if (!iter->ReadBool(&has_creation_message)) |
| return false; |
| if (has_creation_message) { |
| creation_message_.reset(new IPC::Message()); |
| if (!IPC::ReadParam(m, iter, creation_message_.get())) |
| return false; |
| } else { |
| creation_message_.reset(); |
| } |
| return true; |
| } |
| |
| } // namespace proxy |
| } // namespace ppapi |