Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(28)

Side by Side Diff: ppapi/shared_impl/var_value_conversions.cc

Issue 12387073: Add PPB_VarDictionary_Dev support - part 1. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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/shared_impl/var_value_conversions.h"
6
7 #include <limits>
8 #include <set>
9 #include <stack>
10
11 #include "base/logging.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/stl_util.h"
15 #include "base/values.h"
16 #include "ppapi/c/pp_bool.h"
17 #include "ppapi/c/pp_stdint.h"
18 #include "ppapi/shared_impl/dictionary_var.h"
19 #include "ppapi/shared_impl/ppapi_globals.h"
20 #include "ppapi/shared_impl/scoped_pp_var.h"
21 #include "ppapi/shared_impl/var.h"
22 #include "ppapi/shared_impl/var_tracker.h"
23
24 namespace ppapi {
25
26 namespace {
27
28 // In CreateValueFromVar(), a stack is used to keep track of conversion progress
29 // of array and dictionary vars. VarNode represents elements of that stack.
30 struct VarNode {
31 VarNode(const PP_Var& in_var, base::Value* in_value)
32 : var(in_var),
33 value(in_value),
34 sentinel(false) {
35 }
36
37 // This object doesn't hold a reference to it.
38 PP_Var var;
39 // It is not owned by this object.
40 base::Value* value;
41 // When this is set to true for a node in the stack, it means that we have
42 // finished processing the node itself. However, we keep it in the stack as
43 // a sentinel. When it becomes the top element of the stack again, we know
44 // that we have processed all the descendants of this node.
45 bool sentinel;
46 };
47
48 // In CreateVarFromValue(), a stack is used to keep track of conversion progress
49 // of list and dictionary values. ValueNode represents elements of that stack.
50 struct ValueNode {
51 ValueNode(const PP_Var& in_var, const base::Value* in_value)
52 : var(in_var),
53 value(in_value) {
54 }
55
56 // This object doesn't hold a reference to it.
57 PP_Var var;
58 // It is not owned by this object.
59 const base::Value* value;
60 };
61
62 // Helper function for CreateValueFromVar(). It only looks at |var| but not its
63 // descendants. The conversion result is stored in |value|. If |var| is array or
64 // dictionary, a new node is pushed onto |state|.
65 //
66 // Returns false on failure.
67 bool CreateValueFromVarHelper(const std::set<int64_t>& parent_ids,
68 const PP_Var& var,
69 scoped_ptr<base::Value>* value,
70 std::stack<VarNode>* state) {
71 switch (var.type) {
72 case PP_VARTYPE_UNDEFINED:
73 case PP_VARTYPE_NULL: {
74 value->reset(base::Value::CreateNullValue());
75 return true;
76 }
77 case PP_VARTYPE_BOOL: {
78 value->reset(new base::FundamentalValue(PP_ToBool(var.value.as_bool)));
79 return true;
80 }
81 case PP_VARTYPE_INT32: {
82 value->reset(new base::FundamentalValue(var.value.as_int));
83 return true;
84 }
85 case PP_VARTYPE_DOUBLE: {
86 value->reset(new base::FundamentalValue(var.value.as_double));
87 return true;
88 }
89 case PP_VARTYPE_STRING: {
90 StringVar* string_var = StringVar::FromPPVar(var);
91 if (!string_var)
92 return false;
93
94 value->reset(new base::StringValue(string_var->value()));
95 return true;
96 }
97 case PP_VARTYPE_OBJECT: {
98 return false;
99 }
100 case PP_VARTYPE_ARRAY: {
101 // TODO(yzshen): Implement it once array var is supported.
102 return false;
103 }
104 case PP_VARTYPE_DICTIONARY: {
105 if (ContainsKey(parent_ids, var.value.as_id)) {
106 // A circular reference is found.
107 return false;
108 }
109
110 value->reset(new base::DictionaryValue());
dmichael (off chromium) 2013/03/18 16:21:05 I think it's worth noting somewhere (probably the
yzshen1 2013/03/18 17:24:09 Done.
111 state->push(VarNode(var, value->get()));
112 return true;
113 }
114 case PP_VARTYPE_ARRAY_BUFFER: {
115 ArrayBufferVar* array_buffer = ArrayBufferVar::FromPPVar(var);
116 if (!array_buffer)
117 return false;
118
119 base::BinaryValue* binary_value =
120 base::BinaryValue::CreateWithCopiedBuffer(
121 static_cast<const char*>(array_buffer->Map()),
122 array_buffer->ByteLength());
123 array_buffer->Unmap();
124 value->reset(binary_value);
125 return true;
126 }
127 }
128 NOTREACHED();
129 return false;
130 }
131
132 // Helper function for CreateVarFromValue(). It only looks at |value| but not
133 // its descendants. The conversion result is stored in |var|. If |value| is list
134 // or dictionary, a new node is pushed onto |state|.
135 //
136 // Returns false on failure.
137 bool CreateVarFromValueHelper(const base::Value& value,
138 ScopedPPVar* var,
139 std::stack<ValueNode>* state) {
140 switch (value.GetType()) {
141 case base::Value::TYPE_NULL: {
142 *var = PP_MakeNull();
143 return true;
144 }
145 case base::Value::TYPE_BOOLEAN: {
146 bool result = false;
147 if (value.GetAsBoolean(&result)) {
148 *var = PP_MakeBool(PP_FromBool(result));
149 return true;
150 }
151 return false;
152 }
153 case base::Value::TYPE_INTEGER: {
154 int result = 0;
155 if (value.GetAsInteger(&result)) {
156 *var = PP_MakeInt32(result);
157 return true;
158 }
159 return false;
160 }
161 case base::Value::TYPE_DOUBLE: {
162 double result = 0;
163 if (value.GetAsDouble(&result)) {
164 *var = PP_MakeDouble(result);
165 return true;
166 }
167 return false;
168 }
169 case base::Value::TYPE_STRING: {
170 std::string result;
171 if (value.GetAsString(&result)) {
172 *var = ScopedPPVar(ScopedPPVar::PassRef(),
173 StringVar::StringToPPVar(result));
174 return true;
175 }
176 return false;
177 }
178 case base::Value::TYPE_BINARY: {
179 const base::BinaryValue& binary_value =
180 static_cast<const base::BinaryValue&>(value);
181
182 size_t size = binary_value.GetSize();
183 if (size > std::numeric_limits<uint32>::max())
184 return false;
185
186 ScopedPPVar temp(
187 ScopedPPVar::PassRef(),
188 PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
189 static_cast<uint32>(size), binary_value.GetBuffer()));
190 if (temp.get().type == PP_VARTYPE_ARRAY_BUFFER) {
191 *var = temp;
192 return true;
193 }
194 return false;
195 }
196 case base::Value::TYPE_DICTIONARY: {
197 scoped_refptr<DictionaryVar> dict_var(new DictionaryVar());
198 *var = ScopedPPVar(ScopedPPVar::PassRef(), dict_var->GetPPVar());
199 state->push(ValueNode(var->get(), &value));
200 return true;
201 }
202 case base::Value::TYPE_LIST: {
203 // TODO(yzshen): Add support once array var is supported.
204 return false;
205 }
206 }
207 NOTREACHED();
208 return false;
209 }
210
211 } // namespace
212
213 base::Value* CreateValueFromVar(const PP_Var& var) {
214 // Used to detect circular references.
215 std::set<int64_t> parent_ids;
216 std::stack<VarNode> state;
217 scoped_ptr<base::Value> root_value;
218
219 if (!CreateValueFromVarHelper(parent_ids, var, &root_value, &state))
220 return NULL;
221
222 while (!state.empty()) {
223 VarNode& top = state.top();
224 if (top.sentinel) {
225 parent_ids.erase(top.var.value.as_id);
226 state.pop();
227 } else if (top.var.type == PP_VARTYPE_DICTIONARY) {
228 parent_ids.insert(top.var.value.as_id);
229 top.sentinel = true;
230
231 DictionaryVar* dict_var = DictionaryVar::FromPPVar(top.var);
232 if (!dict_var)
233 return NULL;
234
235 DCHECK(top.value->GetType() == base::Value::TYPE_DICTIONARY);
236 base::DictionaryValue* dict_value =
237 static_cast<base::DictionaryValue*>(top.value);
238
239 for (DictionaryVar::KeyValueMap::const_iterator iter =
240 dict_var->key_value_map().begin();
241 iter != dict_var->key_value_map().end();
242 ++iter) {
243 // Skip the key-value pair if the value is undefined.
244 if (iter->second.get().type == PP_VARTYPE_UNDEFINED)
245 continue;
246
247 scoped_ptr<base::Value> child_value;
248 if (!CreateValueFromVarHelper(parent_ids, iter->second.get(),
249 &child_value, &state)) {
250 return NULL;
251 }
252
253 dict_value->SetWithoutPathExpansion(iter->first, child_value.release());
254 }
255 } else {
256 NOTREACHED();
257 return NULL;
258 }
259 }
260 DCHECK(parent_ids.empty());
261 return root_value.release();
262 }
263
264 PP_Var CreateVarFromValue(const base::Value& value) {
265 std::stack<ValueNode> state;
266 ScopedPPVar root_var;
267
268 if (!CreateVarFromValueHelper(value, &root_var, &state))
269 return PP_MakeUndefined();
270
271 while (!state.empty()) {
272 ValueNode top = state.top();
273 state.pop();
274
275 if (top.value->GetType() == base::Value::TYPE_DICTIONARY) {
276 const base::DictionaryValue* dict_value =
277 static_cast<const base::DictionaryValue*>(top.value);
278 DictionaryVar* dict_var = DictionaryVar::FromPPVar(top.var);
279 DCHECK(dict_var);
280 for (base::DictionaryValue::Iterator iter(*dict_value);
281 !iter.IsAtEnd();
282 iter.Advance()) {
283 ScopedPPVar child_var;
284 if (!CreateVarFromValueHelper(iter.value(), &child_var, &state) ||
285 !dict_var->SetWithStringKey(iter.key(), child_var.get())) {
286 return PP_MakeUndefined();
287 }
288 }
289 } else {
290 NOTREACHED();
291 return PP_MakeUndefined();
292 }
293 }
294
295 return root_var.Release();
296 }
297 } // namespace ppapi
298
OLDNEW
« no previous file with comments | « ppapi/shared_impl/var_value_conversions.h ('k') | ppapi/shared_impl/var_value_conversions_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698