[Android] Add tests for toolbar of Chrome Custom Tabs
[chromium-blink-merge.git] / base / trace_event / trace_event_argument.cc
blob37df6ef8f1a5a7989e3a5162b4d60ad33379aa1c
1 // Copyright (c) 2014 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.
5 #include "base/trace_event/trace_event_argument.h"
7 #include "base/json/json_writer.h"
8 #include "base/trace_event/trace_event_memory_overhead.h"
9 #include "base/values.h"
11 namespace base {
12 namespace trace_event {
14 namespace {
15 const char kTypeStartDict = '{';
16 const char kTypeEndDict = '}';
17 const char kTypeStartArray = '[';
18 const char kTypeEndArray = ']';
19 const char kTypeBool = 'b';
20 const char kTypeInt = 'i';
21 const char kTypeDouble = 'd';
22 const char kTypeString = 's';
23 const char kTypeCStr = '*';
25 #ifndef NDEBUG
26 const bool kStackTypeDict = false;
27 const bool kStackTypeArray = true;
28 #define DCHECK_CURRENT_CONTAINER_IS(x) DCHECK_EQ(x, nesting_stack_.back())
29 #define DCHECK_CONTAINER_STACK_DEPTH_EQ(x) DCHECK_EQ(x, nesting_stack_.size())
30 #define DEBUG_PUSH_CONTAINER(x) nesting_stack_.push_back(x)
31 #define DEBUG_POP_CONTAINER() nesting_stack_.pop_back()
32 #else
33 #define DCHECK_CURRENT_CONTAINER_IS(x) do {} while (0)
34 #define DCHECK_CONTAINER_STACK_DEPTH_EQ(x) do {} while (0)
35 #define DEBUG_PUSH_CONTAINER(x) do {} while (0)
36 #define DEBUG_POP_CONTAINER() do {} while (0)
37 #endif
39 inline void WriteKeyNameAsRawPtr(Pickle& pickle, const char* ptr) {
40 pickle.WriteBytes(&kTypeCStr, 1);
41 pickle.WriteUInt64(static_cast<uint64>(reinterpret_cast<uintptr_t>(ptr)));
44 inline void WriteKeyNameAsStdString(Pickle& pickle, const std::string& str) {
45 pickle.WriteBytes(&kTypeString, 1);
46 pickle.WriteString(str);
49 std::string ReadKeyName(PickleIterator& pickle_iterator) {
50 const char* type = nullptr;
51 bool res = pickle_iterator.ReadBytes(&type, 1);
52 std::string key_name;
53 if (res && *type == kTypeCStr) {
54 uint64 ptr_value = 0;
55 res = pickle_iterator.ReadUInt64(&ptr_value);
56 key_name = reinterpret_cast<const char*>(static_cast<uintptr_t>(ptr_value));
57 } else if (res && *type == kTypeString) {
58 res = pickle_iterator.ReadString(&key_name);
60 DCHECK(res);
61 return key_name;
63 } // namespace
65 TracedValue::TracedValue() : TracedValue(0) {
68 TracedValue::TracedValue(size_t capacity) {
69 DEBUG_PUSH_CONTAINER(kStackTypeDict);
70 if (capacity)
71 pickle_.Reserve(capacity);
74 TracedValue::~TracedValue() {
75 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
76 DEBUG_POP_CONTAINER();
77 DCHECK_CONTAINER_STACK_DEPTH_EQ(0u);
80 void TracedValue::SetInteger(const char* name, int value) {
81 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
82 pickle_.WriteBytes(&kTypeInt, 1);
83 pickle_.WriteInt(value);
84 WriteKeyNameAsRawPtr(pickle_, name);
87 void TracedValue::SetIntegerWithCopiedName(const std::string& name, int value) {
88 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
89 pickle_.WriteBytes(&kTypeInt, 1);
90 pickle_.WriteInt(value);
91 WriteKeyNameAsStdString(pickle_, name);
94 void TracedValue::SetDouble(const char* name, double value) {
95 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
96 pickle_.WriteBytes(&kTypeDouble, 1);
97 pickle_.WriteDouble(value);
98 WriteKeyNameAsRawPtr(pickle_, name);
101 void TracedValue::SetDoubleWithCopiedName(const std::string& name,
102 double value) {
103 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
104 pickle_.WriteBytes(&kTypeDouble, 1);
105 pickle_.WriteDouble(value);
106 WriteKeyNameAsStdString(pickle_, name);
109 void TracedValue::SetBoolean(const char* name, bool value) {
110 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
111 pickle_.WriteBytes(&kTypeBool, 1);
112 pickle_.WriteBool(value);
113 WriteKeyNameAsRawPtr(pickle_, name);
116 void TracedValue::SetBooleanWithCopiedName(const std::string& name,
117 bool value) {
118 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
119 pickle_.WriteBytes(&kTypeBool, 1);
120 pickle_.WriteBool(value);
121 WriteKeyNameAsStdString(pickle_, name);
124 void TracedValue::SetString(const char* name, const std::string& value) {
125 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
126 pickle_.WriteBytes(&kTypeString, 1);
127 pickle_.WriteString(value);
128 WriteKeyNameAsRawPtr(pickle_, name);
131 void TracedValue::SetStringWithCopiedName(const std::string& name,
132 const std::string& value) {
133 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
134 pickle_.WriteBytes(&kTypeString, 1);
135 pickle_.WriteString(value);
136 WriteKeyNameAsStdString(pickle_, name);
139 void TracedValue::SetValue(const char* name, const TracedValue& value) {
140 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
141 BeginDictionary(name);
142 pickle_.WriteBytes(value.pickle_.payload(),
143 static_cast<int>(value.pickle_.payload_size()));
144 EndDictionary();
147 void TracedValue::SetValueWithCopiedName(const std::string& name,
148 const TracedValue& value) {
149 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
150 BeginDictionaryWithCopiedName(name);
151 pickle_.WriteBytes(value.pickle_.payload(),
152 static_cast<int>(value.pickle_.payload_size()));
153 EndDictionary();
156 void TracedValue::BeginDictionary(const char* name) {
157 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
158 DEBUG_PUSH_CONTAINER(kStackTypeDict);
159 pickle_.WriteBytes(&kTypeStartDict, 1);
160 WriteKeyNameAsRawPtr(pickle_, name);
163 void TracedValue::BeginDictionaryWithCopiedName(const std::string& name) {
164 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
165 DEBUG_PUSH_CONTAINER(kStackTypeDict);
166 pickle_.WriteBytes(&kTypeStartDict, 1);
167 WriteKeyNameAsStdString(pickle_, name);
170 void TracedValue::BeginArray(const char* name) {
171 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
172 DEBUG_PUSH_CONTAINER(kStackTypeArray);
173 pickle_.WriteBytes(&kTypeStartArray, 1);
174 WriteKeyNameAsRawPtr(pickle_, name);
177 void TracedValue::BeginArrayWithCopiedName(const std::string& name) {
178 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
179 DEBUG_PUSH_CONTAINER(kStackTypeArray);
180 pickle_.WriteBytes(&kTypeStartArray, 1);
181 WriteKeyNameAsStdString(pickle_, name);
184 void TracedValue::EndDictionary() {
185 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
186 DEBUG_POP_CONTAINER();
187 pickle_.WriteBytes(&kTypeEndDict, 1);
190 void TracedValue::AppendInteger(int value) {
191 DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
192 pickle_.WriteBytes(&kTypeInt, 1);
193 pickle_.WriteInt(value);
196 void TracedValue::AppendDouble(double value) {
197 DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
198 pickle_.WriteBytes(&kTypeDouble, 1);
199 pickle_.WriteDouble(value);
202 void TracedValue::AppendBoolean(bool value) {
203 DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
204 pickle_.WriteBytes(&kTypeBool, 1);
205 pickle_.WriteBool(value);
208 void TracedValue::AppendString(const std::string& value) {
209 DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
210 pickle_.WriteBytes(&kTypeString, 1);
211 pickle_.WriteString(value);
214 void TracedValue::BeginArray() {
215 DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
216 DEBUG_PUSH_CONTAINER(kStackTypeArray);
217 pickle_.WriteBytes(&kTypeStartArray, 1);
220 void TracedValue::BeginDictionary() {
221 DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
222 DEBUG_PUSH_CONTAINER(kStackTypeDict);
223 pickle_.WriteBytes(&kTypeStartDict, 1);
226 void TracedValue::EndArray() {
227 DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
228 DEBUG_POP_CONTAINER();
229 pickle_.WriteBytes(&kTypeEndArray, 1);
232 void TracedValue::SetValue(const char* name, scoped_ptr<base::Value> value) {
233 SetBaseValueWithCopiedName(name, *value);
236 void TracedValue::SetBaseValueWithCopiedName(const std::string& name,
237 const base::Value& value) {
238 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
239 switch (value.GetType()) {
240 case base::Value::TYPE_NULL:
241 case base::Value::TYPE_BINARY:
242 NOTREACHED();
243 break;
245 case base::Value::TYPE_BOOLEAN: {
246 bool bool_value;
247 value.GetAsBoolean(&bool_value);
248 SetBooleanWithCopiedName(name, bool_value);
249 } break;
251 case base::Value::TYPE_INTEGER: {
252 int int_value;
253 value.GetAsInteger(&int_value);
254 SetIntegerWithCopiedName(name, int_value);
255 } break;
257 case base::Value::TYPE_DOUBLE: {
258 double double_value;
259 value.GetAsDouble(&double_value);
260 SetDoubleWithCopiedName(name, double_value);
261 } break;
263 case base::Value::TYPE_STRING: {
264 const StringValue* string_value;
265 value.GetAsString(&string_value);
266 SetStringWithCopiedName(name, string_value->GetString());
267 } break;
269 case base::Value::TYPE_DICTIONARY: {
270 const DictionaryValue* dict_value;
271 value.GetAsDictionary(&dict_value);
272 BeginDictionaryWithCopiedName(name);
273 for (DictionaryValue::Iterator it(*dict_value); !it.IsAtEnd();
274 it.Advance()) {
275 SetBaseValueWithCopiedName(it.key(), it.value());
277 EndDictionary();
278 } break;
280 case base::Value::TYPE_LIST: {
281 const ListValue* list_value;
282 value.GetAsList(&list_value);
283 BeginArrayWithCopiedName(name);
284 for (base::Value* base_value : *list_value)
285 AppendBaseValue(*base_value);
286 EndArray();
287 } break;
291 void TracedValue::AppendBaseValue(const base::Value& value) {
292 DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
293 switch (value.GetType()) {
294 case base::Value::TYPE_NULL:
295 case base::Value::TYPE_BINARY:
296 NOTREACHED();
297 break;
299 case base::Value::TYPE_BOOLEAN: {
300 bool bool_value;
301 value.GetAsBoolean(&bool_value);
302 AppendBoolean(bool_value);
303 } break;
305 case base::Value::TYPE_INTEGER: {
306 int int_value;
307 value.GetAsInteger(&int_value);
308 AppendInteger(int_value);
309 } break;
311 case base::Value::TYPE_DOUBLE: {
312 double double_value;
313 value.GetAsDouble(&double_value);
314 AppendDouble(double_value);
315 } break;
317 case base::Value::TYPE_STRING: {
318 const StringValue* string_value;
319 value.GetAsString(&string_value);
320 AppendString(string_value->GetString());
321 } break;
323 case base::Value::TYPE_DICTIONARY: {
324 const DictionaryValue* dict_value;
325 value.GetAsDictionary(&dict_value);
326 BeginDictionary();
327 for (DictionaryValue::Iterator it(*dict_value); !it.IsAtEnd();
328 it.Advance()) {
329 SetBaseValueWithCopiedName(it.key(), it.value());
331 EndDictionary();
332 } break;
334 case base::Value::TYPE_LIST: {
335 const ListValue* list_value;
336 value.GetAsList(&list_value);
337 BeginArray();
338 for (base::Value* base_value : *list_value)
339 AppendBaseValue(*base_value);
340 EndArray();
341 } break;
345 scoped_ptr<base::Value> TracedValue::ToBaseValue() const {
346 scoped_ptr<DictionaryValue> root(new DictionaryValue);
347 DictionaryValue* cur_dict = root.get();
348 ListValue* cur_list = nullptr;
349 std::vector<Value*> stack;
350 PickleIterator it(pickle_);
351 const char* type;
353 while (it.ReadBytes(&type, 1)) {
354 DCHECK((cur_dict && !cur_list) || (cur_list && !cur_dict));
355 switch (*type) {
356 case kTypeStartDict: {
357 auto new_dict = new DictionaryValue();
358 if (cur_dict) {
359 cur_dict->Set(ReadKeyName(it), make_scoped_ptr(new_dict));
360 stack.push_back(cur_dict);
361 cur_dict = new_dict;
362 } else {
363 cur_list->Append(make_scoped_ptr(new_dict));
364 stack.push_back(cur_list);
365 cur_list = nullptr;
366 cur_dict = new_dict;
368 } break;
370 case kTypeEndArray:
371 case kTypeEndDict: {
372 if (stack.back()->GetAsDictionary(&cur_dict)) {
373 cur_list = nullptr;
374 } else if (stack.back()->GetAsList(&cur_list)) {
375 cur_dict = nullptr;
377 stack.pop_back();
378 } break;
380 case kTypeStartArray: {
381 auto new_list = new ListValue();
382 if (cur_dict) {
383 cur_dict->Set(ReadKeyName(it), make_scoped_ptr(new_list));
384 stack.push_back(cur_dict);
385 cur_dict = nullptr;
386 cur_list = new_list;
387 } else {
388 cur_list->Append(make_scoped_ptr(new_list));
389 stack.push_back(cur_list);
390 cur_list = new_list;
392 } break;
394 case kTypeBool: {
395 bool value;
396 CHECK(it.ReadBool(&value));
397 if (cur_dict) {
398 cur_dict->SetBoolean(ReadKeyName(it), value);
399 } else {
400 cur_list->AppendBoolean(value);
402 } break;
404 case kTypeInt: {
405 int value;
406 CHECK(it.ReadInt(&value));
407 if (cur_dict) {
408 cur_dict->SetInteger(ReadKeyName(it), value);
409 } else {
410 cur_list->AppendInteger(value);
412 } break;
414 case kTypeDouble: {
415 double value;
416 CHECK(it.ReadDouble(&value));
417 if (cur_dict) {
418 cur_dict->SetDouble(ReadKeyName(it), value);
419 } else {
420 cur_list->AppendDouble(value);
422 } break;
424 case kTypeString: {
425 std::string value;
426 CHECK(it.ReadString(&value));
427 if (cur_dict) {
428 cur_dict->SetString(ReadKeyName(it), value);
429 } else {
430 cur_list->AppendString(value);
432 } break;
434 default:
435 NOTREACHED();
438 DCHECK(stack.empty());
439 return root.Pass();
442 void TracedValue::AppendAsTraceFormat(std::string* out) const {
443 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
444 DCHECK_CONTAINER_STACK_DEPTH_EQ(1u);
446 // TODO(primiano): this could be smarter, skip the ToBaseValue encoding and
447 // produce the JSON on its own. This will require refactoring JSONWriter
448 // to decouple the base::Value traversal from the JSON writing bits
449 std::string tmp;
450 JSONWriter::Write(*ToBaseValue(), &tmp);
451 *out += tmp;
454 void TracedValue::EstimateTraceMemoryOverhead(
455 TraceEventMemoryOverhead* overhead) {
456 overhead->Add("TracedValue", pickle_.size());
459 } // namespace trace_event
460 } // namespace base