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

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: changes in response to David's suggestions 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/values.h"
15 #include "ppapi/c/pp_bool.h"
16 #include "ppapi/c/pp_stdint.h"
17 #include "ppapi/shared_impl/dictionary_var.h"
18 #include "ppapi/shared_impl/ppapi_globals.h"
19 #include "ppapi/shared_impl/scoped_pp_var.h"
20 #include "ppapi/shared_impl/var.h"
21 #include "ppapi/shared_impl/var_tracker.h"
22
23 namespace ppapi {
24
25 namespace {
26
27 // In CreateValueFromVar(), a stack is used to keep track of conversion progress
28 // of array and dictionary vars. VarNodeBase is the base class of stack
29 // elements.
30 class VarNodeBase : public base::RefCounted<VarNodeBase> {
31 public:
32 virtual bool IsArrayVar() const { return false; }
33 virtual bool IsDictionaryVar() const { return false; }
34
35 protected:
36 friend class base::RefCounted<VarNodeBase>;
37
38 VarNodeBase() {}
39 virtual ~VarNodeBase() {}
40 };
41
42 class DictionaryVarNode : public VarNodeBase {
43 public:
44 DictionaryVarNode(int64_t in_var_id, const DictionaryVar* dict_var)
45 : var_id(in_var_id),
46 next(dict_var->key_value_map().begin()),
47 end(dict_var->key_value_map().end()),
48 dict_value(new base::DictionaryValue()) {
49 }
50
51 virtual bool IsDictionaryVar() const OVERRIDE {
52 return true;
53 }
54
55 int64_t var_id;
56 DictionaryVar::KeyValueMap::const_iterator next;
57 DictionaryVar::KeyValueMap::const_iterator end;
58 std::string current_key;
59 scoped_ptr<base::DictionaryValue> dict_value;
60
61 private:
62 virtual ~DictionaryVarNode() {}
63 };
64
65 // In CreateVarFromValue(), a stack is used to keep track of conversion progress
66 // of list and dictionary values. ValueNodeBase is the base class of stack
67 // elements.
68 class ValueNodeBase : public base::RefCounted<ValueNodeBase> {
69 public:
70 virtual bool IsListValue() const { return false; }
71 virtual bool IsDictionaryValue() const { return false; }
72
73 protected:
74 friend class base::RefCounted<ValueNodeBase>;
75
76 ValueNodeBase() {}
77 virtual ~ValueNodeBase() {}
78 };
79
80 class DictionaryValueNode : public ValueNodeBase {
81 public:
82 explicit DictionaryValueNode(const base::DictionaryValue& dict_value)
83 : iter(dict_value),
84 dict_var(new DictionaryVar()) {
85 }
86
87 virtual bool IsDictionaryValue() const OVERRIDE {
88 return true;
89 }
90
91 base::DictionaryValue::Iterator iter;
92 std::string current_key;
93 scoped_refptr<DictionaryVar> dict_var;
94
95 private:
96 virtual ~DictionaryValueNode() {}
97 };
98
99 // Helper function for CreateValueFromVar(). If |var| is neither array nor
100 // dictionary, the conversion result is stored in |value|; otherwise,
101 // |parent_ids| and |state| are updated.
102 //
103 // Returns false on failure.
104 bool CreateValueFromVarHelper(const PP_Var& var,
105 scoped_ptr<base::Value>* value,
106 std::set<int64_t>* parent_ids,
dmichael (off chromium) 2013/03/15 17:35:48 As I mentioned on IM, I think we probably should d
yzshen1 2013/03/15 22:56:49 Done. (Discussed offline.) On 2013/03/15 17:35:48,
107 std::stack<scoped_refptr<VarNodeBase> >* state) {
108 switch (var.type) {
109 case PP_VARTYPE_UNDEFINED:
110 case PP_VARTYPE_NULL: {
111 value->reset(base::Value::CreateNullValue());
112 return true;
113 }
114 case PP_VARTYPE_BOOL: {
115 value->reset(new base::FundamentalValue(PP_ToBool(var.value.as_bool)));
116 return true;
117 }
118 case PP_VARTYPE_INT32: {
119 value->reset(new base::FundamentalValue(var.value.as_int));
120 return true;
121 }
122 case PP_VARTYPE_DOUBLE: {
123 value->reset(new base::FundamentalValue(var.value.as_double));
124 return true;
125 }
126 case PP_VARTYPE_STRING: {
127 StringVar* string_var = StringVar::FromPPVar(var);
128 if (!string_var)
129 return false;
130
131 value->reset(new base::StringValue(string_var->value()));
132 return true;
133 }
134 case PP_VARTYPE_OBJECT: {
135 return false;
136 }
137 case PP_VARTYPE_ARRAY: {
138 // TODO(yzshen): Implement it once array var is supported.
139 return false;
140 }
141 case PP_VARTYPE_DICTIONARY: {
142 if (parent_ids->find(var.value.as_id) != parent_ids->end()) {
dmichael (off chromium) 2013/03/15 17:35:48 optional suggestion: you can also ContainsKey from
yzshen1 2013/03/15 22:56:49 Done.
143 // A circular reference is found.
144 return false;
145 }
146
147 DictionaryVar* dict_var = DictionaryVar::FromPPVar(var);
148 if (!dict_var)
149 return false;
150
151 parent_ids->insert(var.value.as_id);
152 state->push(new DictionaryVarNode(var.value.as_id, dict_var));
153 return true;
154 }
155 case PP_VARTYPE_ARRAY_BUFFER: {
156 ArrayBufferVar* array_buffer = ArrayBufferVar::FromPPVar(var);
157 if (!array_buffer)
158 return false;
159
160 base::BinaryValue* binary_value =
161 base::BinaryValue::CreateWithCopiedBuffer(
162 static_cast<const char*>(array_buffer->Map()),
163 array_buffer->ByteLength());
164 array_buffer->Unmap();
165 value->reset(binary_value);
166 return true;
167 }
168 }
169 NOTREACHED();
170 return false;
171 }
172
173 // Helper function for CreateVarFromValue(). If |value| is neither list nor
174 // dictionary, the conversion result is stored in |var|; otherwise, |state| is
175 // updated.
176 //
177 // Returns false on failure.
178 bool CreateVarFromValueHelper(
179 const base::Value& value,
180 ScopedPPVar* var,
181 std::stack<scoped_refptr<ValueNodeBase> >* state) {
182 switch (value.GetType()) {
183 case base::Value::TYPE_NULL: {
184 *var = PP_MakeNull();
185 return true;
186 }
187 case base::Value::TYPE_BOOLEAN: {
188 bool result = false;
189 if (value.GetAsBoolean(&result)) {
190 *var = PP_MakeBool(PP_FromBool(result));
191 return true;
192 }
193 return false;
194 }
195 case base::Value::TYPE_INTEGER: {
196 int result = 0;
197 if (value.GetAsInteger(&result)) {
198 *var = PP_MakeInt32(result);
199 return true;
200 }
201 return false;
202 }
203 case base::Value::TYPE_DOUBLE: {
204 double result = 0;
205 if (value.GetAsDouble(&result)) {
206 *var = PP_MakeDouble(result);
207 return true;
208 }
209 return false;
210 }
211 case base::Value::TYPE_STRING: {
212 std::string result;
213 if (value.GetAsString(&result)) {
214 *var = ScopedPPVar(ScopedPPVar::PassRef(),
215 StringVar::StringToPPVar(result));
216 return true;
217 }
218 return false;
219 }
220 case base::Value::TYPE_BINARY: {
221 const base::BinaryValue& binary_value =
222 static_cast<const base::BinaryValue&>(value);
223
224 size_t size = binary_value.GetSize();
225 if (size > std::numeric_limits<uint32>::max())
226 return false;
227
228 ScopedPPVar temp(
229 ScopedPPVar::PassRef(),
230 PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
231 static_cast<uint32>(size), binary_value.GetBuffer()));
232 if (temp.get().type == PP_VARTYPE_ARRAY_BUFFER) {
233 *var = temp;
234 return true;
235 }
236 return false;
237 }
238 case base::Value::TYPE_DICTIONARY: {
239 state->push(new DictionaryValueNode(
240 static_cast<const base::DictionaryValue&>(value)));
241 return true;
242 }
243 case base::Value::TYPE_LIST: {
244 // TODO(yzshen): Add support once array var is supported.
245 return false;
246 }
247 }
248 NOTREACHED();
249 return false;
250 }
251
252 } // namespace
253
254 base::Value* CreateValueFromVar(const PP_Var& var) {
255 // Used to detect circular references.
256 std::set<int64_t> parent_ids;
257 std::stack<scoped_refptr<VarNodeBase> > state;
258 scoped_ptr<base::Value> current_value;
259
260 if (!CreateValueFromVarHelper(var, &current_value, &parent_ids, &state))
261 return NULL;
262
263 while (!state.empty()) {
264 PP_Var current_var = PP_MakeUndefined();
265 if (state.top()->IsDictionaryVar()) {
266 scoped_refptr<DictionaryVarNode> top(
267 static_cast<DictionaryVarNode*>(state.top().get()));
268
269 DCHECK(current_value.get() || top->current_key.empty());
270 if (current_value.get()) {
271 top->dict_value->SetWithoutPathExpansion(top->current_key,
272 current_value.release());
dmichael (off chromium) 2013/03/15 17:35:48 As we discussed offline, I had a little bit of tro
yzshen1 2013/03/15 22:56:49 Done. Thanks! On 2013/03/15 17:35:48, dmichael wr
273 }
274 if (top->next == top->end) {
275 current_value.reset(top->dict_value.release());
276 parent_ids.erase(top->var_id);
277 state.pop();
278 continue;
279 } else {
280 top->current_key = top->next->first;
281 current_var = top->next->second.get();
282 ++top->next;
283
284 // Ignore the key-value pair if the value is undefined.
285 if (current_var.type == PP_VARTYPE_UNDEFINED) {
286 top->current_key.clear();
287 continue;
288 }
289 }
290 } else {
291 NOTREACHED();
292 return NULL;
293 }
294
295 DCHECK(!current_value.get());
296 if (!CreateValueFromVarHelper(current_var, &current_value, &parent_ids,
297 &state)) {
298 return NULL;
299 }
300 }
301 DCHECK(parent_ids.empty());
302 return current_value.release();
303 }
304
305 PP_Var CreateVarFromValue(const base::Value& value) {
306 std::stack<scoped_refptr<ValueNodeBase> > state;
307 ScopedPPVar current_var;
308
309 if (!CreateVarFromValueHelper(value, &current_var, &state))
310 return PP_MakeUndefined();
311
312 while (!state.empty()) {
313 const base::Value* current_value = NULL;
314 if (state.top()->IsDictionaryValue()) {
315 scoped_refptr<DictionaryValueNode> top(
316 static_cast<DictionaryValueNode*>(state.top().get()));
317
318 DCHECK(current_var.get().type != PP_VARTYPE_UNDEFINED ||
319 top->current_key.empty());
320 if (current_var.get().type != PP_VARTYPE_UNDEFINED &&
321 !top->dict_var->SetWithStringKey(
322 top->current_key, current_var.get())) {
323 return PP_MakeUndefined();
324 }
325 current_var = PP_MakeUndefined();
326 if (top->iter.IsAtEnd()) {
327 current_var = ScopedPPVar(ScopedPPVar::PassRef(),
328 top->dict_var->GetPPVar());
329 state.pop();
330 continue;
331 } else {
332 top->current_key = top->iter.key();
333 current_value = &top->iter.value();
334 top->iter.Advance();
335 }
336 } else {
337 NOTREACHED();
338 return PP_MakeUndefined();
339 }
340
341 DCHECK(current_var.get().type == PP_VARTYPE_UNDEFINED);
342 if (!CreateVarFromValueHelper(*current_value, &current_var, &state))
343 return PP_MakeUndefined();
344 };
345
346 return current_var.Release();
347 }
348 } // namespace ppapi
349
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