Upstream version 8.37.180.0
[platform/framework/web/crosswalk.git] / src / gpu / config / gpu_control_list.cc
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 "gpu/config/gpu_control_list.h"
6
7 #include "base/cpu.h"
8 #include "base/json/json_reader.h"
9 #include "base/logging.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_split.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/sys_info.h"
15 #include "gpu/config/gpu_info.h"
16 #include "gpu/config/gpu_util.h"
17
18 namespace gpu {
19 namespace {
20
21 // Break a version string into segments.  Return true if each segment is
22 // a valid number, and not all segment is 0.
23 bool ProcessVersionString(const std::string& version_string,
24                           char splitter,
25                           std::vector<std::string>* version) {
26   DCHECK(version);
27   base::SplitString(version_string, splitter, version);
28   if (version->size() == 0)
29     return false;
30   // If the splitter is '-', we assume it's a date with format "mm-dd-yyyy";
31   // we split it into the order of "yyyy", "mm", "dd".
32   if (splitter == '-') {
33     std::string year = (*version)[version->size() - 1];
34     for (int i = version->size() - 1; i > 0; --i) {
35       (*version)[i] = (*version)[i - 1];
36     }
37     (*version)[0] = year;
38   }
39   bool all_zero = true;
40   for (size_t i = 0; i < version->size(); ++i) {
41     unsigned num = 0;
42     if (!base::StringToUint((*version)[i], &num))
43       return false;
44     if (num)
45       all_zero = false;
46   }
47   return !all_zero;
48 }
49
50 // Compare two number strings using numerical ordering.
51 // Return  0 if number = number_ref,
52 //         1 if number > number_ref,
53 //        -1 if number < number_ref.
54 int CompareNumericalNumberStrings(
55     const std::string& number, const std::string& number_ref) {
56   unsigned value1 = 0;
57   unsigned value2 = 0;
58   bool valid = base::StringToUint(number, &value1);
59   DCHECK(valid);
60   valid = base::StringToUint(number_ref, &value2);
61   DCHECK(valid);
62   if (value1 == value2)
63     return 0;
64   if (value1 > value2)
65     return 1;
66   return -1;
67 }
68
69 // Compare two number strings using lexical ordering.
70 // Return  0 if number = number_ref,
71 //         1 if number > number_ref,
72 //        -1 if number < number_ref.
73 // We only compare as many digits as number_ref contains.
74 // If number_ref is xxx, it's considered as xxx*
75 // For example: CompareLexicalNumberStrings("121", "12") returns 0,
76 //              CompareLexicalNumberStrings("12", "121") returns -1.
77 int CompareLexicalNumberStrings(
78     const std::string& number, const std::string& number_ref) {
79   for (size_t i = 0; i < number_ref.length(); ++i) {
80     unsigned value1 = 0;
81     if (i < number.length())
82       value1 = number[i] - '0';
83     unsigned value2 = number_ref[i] - '0';
84     if (value1 > value2)
85       return 1;
86     if (value1 < value2)
87       return -1;
88   }
89   return 0;
90 }
91
92 const char kMultiGpuStyleStringAMDSwitchable[] = "amd_switchable";
93 const char kMultiGpuStyleStringAMDSwitchableDiscrete[] =
94     "amd_switchable_discrete";
95 const char kMultiGpuStyleStringAMDSwitchableIntegrated[] =
96     "amd_switchable_integrated";
97 const char kMultiGpuStyleStringOptimus[] = "optimus";
98
99 const char kMultiGpuCategoryStringPrimary[] = "primary";
100 const char kMultiGpuCategoryStringSecondary[] = "secondary";
101 const char kMultiGpuCategoryStringActive[] = "active";
102 const char kMultiGpuCategoryStringAny[] = "any";
103
104 const char kGLTypeStringGL[] = "gl";
105 const char kGLTypeStringGLES[] = "gles";
106 const char kGLTypeStringANGLE[] = "angle";
107
108 const char kVersionStyleStringNumerical[] = "numerical";
109 const char kVersionStyleStringLexical[] = "lexical";
110
111 const char kOp[] = "op";
112
113 }  // namespace anonymous
114
115 GpuControlList::VersionInfo::VersionInfo(
116     const std::string& version_op,
117     const std::string& version_style,
118     const std::string& version_string,
119     const std::string& version_string2)
120     : version_style_(kVersionStyleNumerical) {
121   op_ = StringToNumericOp(version_op);
122   if (op_ == kUnknown || op_ == kAny)
123     return;
124   version_style_ = StringToVersionStyle(version_style);
125   if (!ProcessVersionString(version_string, '.', &version_)) {
126     op_ = kUnknown;
127     return;
128   }
129   if (op_ == kBetween) {
130     if (!ProcessVersionString(version_string2, '.', &version2_))
131       op_ = kUnknown;
132   }
133 }
134
135 GpuControlList::VersionInfo::~VersionInfo() {
136 }
137
138 bool GpuControlList::VersionInfo::Contains(
139     const std::string& version_string) const {
140   return Contains(version_string, '.');
141 }
142
143 bool GpuControlList::VersionInfo::Contains(
144     const std::string& version_string, char splitter) const {
145   if (op_ == kUnknown)
146     return false;
147   if (op_ == kAny)
148     return true;
149   std::vector<std::string> version;
150   if (!ProcessVersionString(version_string, splitter, &version))
151     return false;
152   int relation = Compare(version, version_, version_style_);
153   if (op_ == kEQ)
154     return (relation == 0);
155   else if (op_ == kLT)
156     return (relation < 0);
157   else if (op_ == kLE)
158     return (relation <= 0);
159   else if (op_ == kGT)
160     return (relation > 0);
161   else if (op_ == kGE)
162     return (relation >= 0);
163   // op_ == kBetween
164   if (relation < 0)
165     return false;
166   return Compare(version, version2_, version_style_) <= 0;
167 }
168
169 bool GpuControlList::VersionInfo::IsValid() const {
170   return (op_ != kUnknown && version_style_ != kVersionStyleUnknown);
171 }
172
173 bool GpuControlList::VersionInfo::IsLexical() const {
174   return version_style_ == kVersionStyleLexical;
175 }
176
177 // static
178 int GpuControlList::VersionInfo::Compare(
179     const std::vector<std::string>& version,
180     const std::vector<std::string>& version_ref,
181     VersionStyle version_style) {
182   DCHECK(version.size() > 0 && version_ref.size() > 0);
183   DCHECK(version_style != kVersionStyleUnknown);
184   for (size_t i = 0; i < version_ref.size(); ++i) {
185     if (i >= version.size())
186       return 0;
187     int ret = 0;
188     // We assume both versions are checked by ProcessVersionString().
189     if (i > 0 && version_style == kVersionStyleLexical)
190       ret = CompareLexicalNumberStrings(version[i], version_ref[i]);
191     else
192       ret = CompareNumericalNumberStrings(version[i], version_ref[i]);
193     if (ret != 0)
194       return ret;
195   }
196   return 0;
197 }
198
199 // static
200 GpuControlList::VersionInfo::VersionStyle
201 GpuControlList::VersionInfo::StringToVersionStyle(
202     const std::string& version_style) {
203   if (version_style.empty() || version_style == kVersionStyleStringNumerical)
204     return kVersionStyleNumerical;
205   if (version_style == kVersionStyleStringLexical)
206     return kVersionStyleLexical;
207   return kVersionStyleUnknown;
208 }
209
210 GpuControlList::OsInfo::OsInfo(const std::string& os,
211                              const std::string& version_op,
212                              const std::string& version_string,
213                              const std::string& version_string2) {
214   type_ = StringToOsType(os);
215   if (type_ != kOsUnknown) {
216     version_info_.reset(new VersionInfo(
217         version_op, std::string(), version_string, version_string2));
218   }
219 }
220
221 GpuControlList::OsInfo::~OsInfo() {}
222
223 bool GpuControlList::OsInfo::Contains(
224     OsType type, const std::string& version) const {
225   if (!IsValid())
226     return false;
227   if (type_ != type && type_ != kOsAny)
228     return false;
229   std::string processed_version;
230   size_t pos = version.find_first_not_of("0123456789.");
231   if (pos != std::string::npos)
232     processed_version = version.substr(0, pos);
233   else
234     processed_version = version;
235
236   return version_info_->Contains(processed_version);
237 }
238
239 bool GpuControlList::OsInfo::IsValid() const {
240   return type_ != kOsUnknown && version_info_->IsValid();
241 }
242
243 GpuControlList::OsType GpuControlList::OsInfo::type() const {
244   return type_;
245 }
246
247 GpuControlList::OsType GpuControlList::OsInfo::StringToOsType(
248     const std::string& os) {
249   if (os == "win")
250     return kOsWin;
251   else if (os == "macosx")
252     return kOsMacosx;
253   else if (os == "android")
254     return kOsAndroid;
255   else if (os == "linux")
256     return kOsLinux;
257   else if (os == "chromeos")
258     return kOsChromeOS;
259   else if (os == "any")
260     return kOsAny;
261   return kOsUnknown;
262 }
263
264 GpuControlList::StringInfo::StringInfo(const std::string& string_op,
265                                      const std::string& string_value) {
266   op_ = StringToOp(string_op);
267   value_ = StringToLowerASCII(string_value);
268 }
269
270 bool GpuControlList::StringInfo::Contains(const std::string& value) const {
271   std::string my_value = StringToLowerASCII(value);
272   switch (op_) {
273     case kContains:
274       return strstr(my_value.c_str(), value_.c_str()) != NULL;
275     case kBeginWith:
276       return StartsWithASCII(my_value, value_, false);
277     case kEndWith:
278       return EndsWith(my_value, value_, false);
279     case kEQ:
280       return value_ == my_value;
281     default:
282       return false;
283   }
284 }
285
286 bool GpuControlList::StringInfo::IsValid() const {
287   return op_ != kUnknown;
288 }
289
290 GpuControlList::StringInfo::Op GpuControlList::StringInfo::StringToOp(
291     const std::string& string_op) {
292   if (string_op == "=")
293     return kEQ;
294   else if (string_op == "contains")
295     return kContains;
296   else if (string_op == "beginwith")
297     return kBeginWith;
298   else if (string_op == "endwith")
299     return kEndWith;
300   return kUnknown;
301 }
302
303 GpuControlList::FloatInfo::FloatInfo(const std::string& float_op,
304                                      const std::string& float_value,
305                                      const std::string& float_value2)
306     : op_(kUnknown),
307       value_(0.f),
308       value2_(0.f) {
309   op_ = StringToNumericOp(float_op);
310   if (op_ == kAny)
311     return;
312   double dvalue = 0;
313   if (!base::StringToDouble(float_value, &dvalue)) {
314     op_ = kUnknown;
315     return;
316   }
317   value_ = static_cast<float>(dvalue);
318   if (op_ == kBetween) {
319     if (!base::StringToDouble(float_value2, &dvalue)) {
320       op_ = kUnknown;
321       return;
322     }
323     value2_ = static_cast<float>(dvalue);
324   }
325 }
326
327 bool GpuControlList::FloatInfo::Contains(float value) const {
328   if (op_ == kUnknown)
329     return false;
330   if (op_ == kAny)
331     return true;
332   if (op_ == kEQ)
333     return (value == value_);
334   if (op_ == kLT)
335     return (value < value_);
336   if (op_ == kLE)
337     return (value <= value_);
338   if (op_ == kGT)
339     return (value > value_);
340   if (op_ == kGE)
341     return (value >= value_);
342   DCHECK(op_ == kBetween);
343   return ((value_ <= value && value <= value2_) ||
344           (value2_ <= value && value <= value_));
345 }
346
347 bool GpuControlList::FloatInfo::IsValid() const {
348   return op_ != kUnknown;
349 }
350
351 GpuControlList::IntInfo::IntInfo(const std::string& int_op,
352                                  const std::string& int_value,
353                                  const std::string& int_value2)
354     : op_(kUnknown),
355       value_(0),
356       value2_(0) {
357   op_ = StringToNumericOp(int_op);
358   if (op_ == kAny)
359     return;
360   if (!base::StringToInt(int_value, &value_)) {
361     op_ = kUnknown;
362     return;
363   }
364   if (op_ == kBetween &&
365       !base::StringToInt(int_value2, &value2_))
366     op_ = kUnknown;
367 }
368
369 bool GpuControlList::IntInfo::Contains(int value) const {
370   if (op_ == kUnknown)
371     return false;
372   if (op_ == kAny)
373     return true;
374   if (op_ == kEQ)
375     return (value == value_);
376   if (op_ == kLT)
377     return (value < value_);
378   if (op_ == kLE)
379     return (value <= value_);
380   if (op_ == kGT)
381     return (value > value_);
382   if (op_ == kGE)
383     return (value >= value_);
384   DCHECK(op_ == kBetween);
385   return ((value_ <= value && value <= value2_) ||
386           (value2_ <= value && value <= value_));
387 }
388
389 bool GpuControlList::IntInfo::IsValid() const {
390   return op_ != kUnknown;
391 }
392
393 GpuControlList::BoolInfo::BoolInfo(bool value) : value_(value) {}
394
395 bool GpuControlList::BoolInfo::Contains(bool value) const {
396   return value_ == value;
397 }
398
399 // static
400 GpuControlList::ScopedGpuControlListEntry
401 GpuControlList::GpuControlListEntry::GetEntryFromValue(
402     const base::DictionaryValue* value, bool top_level,
403     const FeatureMap& feature_map,
404     bool supports_feature_type_all) {
405   DCHECK(value);
406   ScopedGpuControlListEntry entry(new GpuControlListEntry());
407
408   size_t dictionary_entry_count = 0;
409
410   if (top_level) {
411     uint32 id;
412     if (!value->GetInteger("id", reinterpret_cast<int*>(&id)) ||
413         !entry->SetId(id)) {
414       LOG(WARNING) << "Malformed id entry " << entry->id();
415       return NULL;
416     }
417     dictionary_entry_count++;
418
419     bool disabled;
420     if (value->GetBoolean("disabled", &disabled)) {
421       entry->SetDisabled(disabled);
422       dictionary_entry_count++;
423     }
424   }
425
426   std::string description;
427   if (value->GetString("description", &description)) {
428     entry->description_ = description;
429     dictionary_entry_count++;
430   } else {
431     entry->description_ = "The GPU is unavailable for an unexplained reason.";
432   }
433
434   const base::ListValue* cr_bugs;
435   if (value->GetList("cr_bugs", &cr_bugs)) {
436     for (size_t i = 0; i < cr_bugs->GetSize(); ++i) {
437       int bug_id;
438       if (cr_bugs->GetInteger(i, &bug_id)) {
439         entry->cr_bugs_.push_back(bug_id);
440       } else {
441         LOG(WARNING) << "Malformed cr_bugs entry " << entry->id();
442         return NULL;
443       }
444     }
445     dictionary_entry_count++;
446   }
447
448   const base::ListValue* webkit_bugs;
449   if (value->GetList("webkit_bugs", &webkit_bugs)) {
450     for (size_t i = 0; i < webkit_bugs->GetSize(); ++i) {
451       int bug_id;
452       if (webkit_bugs->GetInteger(i, &bug_id)) {
453         entry->webkit_bugs_.push_back(bug_id);
454       } else {
455         LOG(WARNING) << "Malformed webkit_bugs entry " << entry->id();
456         return NULL;
457       }
458     }
459     dictionary_entry_count++;
460   }
461
462   const base::DictionaryValue* os_value = NULL;
463   if (value->GetDictionary("os", &os_value)) {
464     std::string os_type;
465     std::string os_version_op = "any";
466     std::string os_version_string;
467     std::string os_version_string2;
468     os_value->GetString("type", &os_type);
469     const base::DictionaryValue* os_version_value = NULL;
470     if (os_value->GetDictionary("version", &os_version_value)) {
471       os_version_value->GetString(kOp, &os_version_op);
472       os_version_value->GetString("value", &os_version_string);
473       os_version_value->GetString("value2", &os_version_string2);
474     }
475     if (!entry->SetOsInfo(os_type, os_version_op, os_version_string,
476                           os_version_string2)) {
477       LOG(WARNING) << "Malformed os entry " << entry->id();
478       return NULL;
479     }
480     dictionary_entry_count++;
481   }
482
483   std::string vendor_id;
484   if (value->GetString("vendor_id", &vendor_id)) {
485     if (!entry->SetVendorId(vendor_id)) {
486       LOG(WARNING) << "Malformed vendor_id entry " << entry->id();
487       return NULL;
488     }
489     dictionary_entry_count++;
490   }
491
492   const base::ListValue* device_id_list;
493   if (value->GetList("device_id", &device_id_list)) {
494     for (size_t i = 0; i < device_id_list->GetSize(); ++i) {
495       std::string device_id;
496       if (!device_id_list->GetString(i, &device_id) ||
497           !entry->AddDeviceId(device_id)) {
498         LOG(WARNING) << "Malformed device_id entry " << entry->id();
499         return NULL;
500       }
501     }
502     dictionary_entry_count++;
503   }
504
505   std::string multi_gpu_style;
506   if (value->GetString("multi_gpu_style", &multi_gpu_style)) {
507     if (!entry->SetMultiGpuStyle(multi_gpu_style)) {
508       LOG(WARNING) << "Malformed multi_gpu_style entry " << entry->id();
509       return NULL;
510     }
511     dictionary_entry_count++;
512   }
513
514   std::string multi_gpu_category;
515   if (value->GetString("multi_gpu_category", &multi_gpu_category)) {
516     if (!entry->SetMultiGpuCategory(multi_gpu_category)) {
517       LOG(WARNING) << "Malformed multi_gpu_category entry " << entry->id();
518       return NULL;
519     }
520     dictionary_entry_count++;
521   }
522
523   const base::DictionaryValue* driver_vendor_value = NULL;
524   if (value->GetDictionary("driver_vendor", &driver_vendor_value)) {
525     std::string vendor_op;
526     std::string vendor_value;
527     driver_vendor_value->GetString(kOp, &vendor_op);
528     driver_vendor_value->GetString("value", &vendor_value);
529     if (!entry->SetDriverVendorInfo(vendor_op, vendor_value)) {
530       LOG(WARNING) << "Malformed driver_vendor entry " << entry->id();
531       return NULL;
532     }
533     dictionary_entry_count++;
534   }
535
536   const base::DictionaryValue* driver_version_value = NULL;
537   if (value->GetDictionary("driver_version", &driver_version_value)) {
538     std::string driver_version_op = "any";
539     std::string driver_version_style;
540     std::string driver_version_string;
541     std::string driver_version_string2;
542     driver_version_value->GetString(kOp, &driver_version_op);
543     driver_version_value->GetString("style", &driver_version_style);
544     driver_version_value->GetString("value", &driver_version_string);
545     driver_version_value->GetString("value2", &driver_version_string2);
546     if (!entry->SetDriverVersionInfo(driver_version_op,
547                                      driver_version_style,
548                                      driver_version_string,
549                                      driver_version_string2)) {
550       LOG(WARNING) << "Malformed driver_version entry " << entry->id();
551       return NULL;
552     }
553     dictionary_entry_count++;
554   }
555
556   const base::DictionaryValue* driver_date_value = NULL;
557   if (value->GetDictionary("driver_date", &driver_date_value)) {
558     std::string driver_date_op = "any";
559     std::string driver_date_string;
560     std::string driver_date_string2;
561     driver_date_value->GetString(kOp, &driver_date_op);
562     driver_date_value->GetString("value", &driver_date_string);
563     driver_date_value->GetString("value2", &driver_date_string2);
564     if (!entry->SetDriverDateInfo(driver_date_op, driver_date_string,
565                                   driver_date_string2)) {
566       LOG(WARNING) << "Malformed driver_date entry " << entry->id();
567       return NULL;
568     }
569     dictionary_entry_count++;
570   }
571
572   std::string gl_type;
573   if (value->GetString("gl_type", &gl_type)) {
574     if (!entry->SetGLType(gl_type)) {
575       LOG(WARNING) << "Malformed gl_type entry " << entry->id();
576       return NULL;
577     }
578     dictionary_entry_count++;
579   }
580
581   const base::DictionaryValue* gl_version_value = NULL;
582   if (value->GetDictionary("gl_version", &gl_version_value)) {
583     std::string version_op = "any";
584     std::string version_string;
585     std::string version_string2;
586     gl_version_value->GetString(kOp, &version_op);
587     gl_version_value->GetString("value", &version_string);
588     gl_version_value->GetString("value2", &version_string2);
589     if (!entry->SetGLVersionInfo(
590             version_op, version_string, version_string2)) {
591       LOG(WARNING) << "Malformed gl_version entry " << entry->id();
592       return NULL;
593     }
594     dictionary_entry_count++;
595   }
596
597   const base::DictionaryValue* gl_vendor_value = NULL;
598   if (value->GetDictionary("gl_vendor", &gl_vendor_value)) {
599     std::string vendor_op;
600     std::string vendor_value;
601     gl_vendor_value->GetString(kOp, &vendor_op);
602     gl_vendor_value->GetString("value", &vendor_value);
603     if (!entry->SetGLVendorInfo(vendor_op, vendor_value)) {
604       LOG(WARNING) << "Malformed gl_vendor entry " << entry->id();
605       return NULL;
606     }
607     dictionary_entry_count++;
608   }
609
610   const base::DictionaryValue* gl_renderer_value = NULL;
611   if (value->GetDictionary("gl_renderer", &gl_renderer_value)) {
612     std::string renderer_op;
613     std::string renderer_value;
614     gl_renderer_value->GetString(kOp, &renderer_op);
615     gl_renderer_value->GetString("value", &renderer_value);
616     if (!entry->SetGLRendererInfo(renderer_op, renderer_value)) {
617       LOG(WARNING) << "Malformed gl_renderer entry " << entry->id();
618       return NULL;
619     }
620     dictionary_entry_count++;
621   }
622
623   const base::DictionaryValue* gl_extensions_value = NULL;
624   if (value->GetDictionary("gl_extensions", &gl_extensions_value)) {
625     std::string extensions_op;
626     std::string extensions_value;
627     gl_extensions_value->GetString(kOp, &extensions_op);
628     gl_extensions_value->GetString("value", &extensions_value);
629     if (!entry->SetGLExtensionsInfo(extensions_op, extensions_value)) {
630       LOG(WARNING) << "Malformed gl_extensions entry " << entry->id();
631       return NULL;
632     }
633     dictionary_entry_count++;
634   }
635
636   const base::DictionaryValue* gl_reset_notification_strategy_value = NULL;
637   if (value->GetDictionary("gl_reset_notification_strategy",
638                            &gl_reset_notification_strategy_value)) {
639     std::string op;
640     std::string int_value;
641     std::string int_value2;
642     gl_reset_notification_strategy_value->GetString(kOp, &op);
643     gl_reset_notification_strategy_value->GetString("value", &int_value);
644     gl_reset_notification_strategy_value->GetString("value2", &int_value2);
645     if (!entry->SetGLResetNotificationStrategyInfo(
646             op, int_value, int_value2)) {
647       LOG(WARNING) << "Malformed gl_reset_notification_strategy entry "
648                    << entry->id();
649       return NULL;
650     }
651     dictionary_entry_count++;
652   }
653
654   const base::DictionaryValue* cpu_brand_value = NULL;
655   if (value->GetDictionary("cpu_info", &cpu_brand_value)) {
656     std::string cpu_op;
657     std::string cpu_value;
658     cpu_brand_value->GetString(kOp, &cpu_op);
659     cpu_brand_value->GetString("value", &cpu_value);
660     if (!entry->SetCpuBrand(cpu_op, cpu_value)) {
661       LOG(WARNING) << "Malformed cpu_brand entry " << entry->id();
662       return NULL;
663     }
664     dictionary_entry_count++;
665   }
666
667   const base::DictionaryValue* perf_graphics_value = NULL;
668   if (value->GetDictionary("perf_graphics", &perf_graphics_value)) {
669     std::string op;
670     std::string float_value;
671     std::string float_value2;
672     perf_graphics_value->GetString(kOp, &op);
673     perf_graphics_value->GetString("value", &float_value);
674     perf_graphics_value->GetString("value2", &float_value2);
675     if (!entry->SetPerfGraphicsInfo(op, float_value, float_value2)) {
676       LOG(WARNING) << "Malformed perf_graphics entry " << entry->id();
677       return NULL;
678     }
679     dictionary_entry_count++;
680   }
681
682   const base::DictionaryValue* perf_gaming_value = NULL;
683   if (value->GetDictionary("perf_gaming", &perf_gaming_value)) {
684     std::string op;
685     std::string float_value;
686     std::string float_value2;
687     perf_gaming_value->GetString(kOp, &op);
688     perf_gaming_value->GetString("value", &float_value);
689     perf_gaming_value->GetString("value2", &float_value2);
690     if (!entry->SetPerfGamingInfo(op, float_value, float_value2)) {
691       LOG(WARNING) << "Malformed perf_gaming entry " << entry->id();
692       return NULL;
693     }
694     dictionary_entry_count++;
695   }
696
697   const base::DictionaryValue* perf_overall_value = NULL;
698   if (value->GetDictionary("perf_overall", &perf_overall_value)) {
699     std::string op;
700     std::string float_value;
701     std::string float_value2;
702     perf_overall_value->GetString(kOp, &op);
703     perf_overall_value->GetString("value", &float_value);
704     perf_overall_value->GetString("value2", &float_value2);
705     if (!entry->SetPerfOverallInfo(op, float_value, float_value2)) {
706       LOG(WARNING) << "Malformed perf_overall entry " << entry->id();
707       return NULL;
708     }
709     dictionary_entry_count++;
710   }
711
712   const base::ListValue* machine_model_name_list;
713   if (value->GetList("machine_model_name", &machine_model_name_list)) {
714     for (size_t i = 0; i < machine_model_name_list->GetSize(); ++i) {
715       std::string model_name;
716       if (!machine_model_name_list->GetString(i, &model_name) ||
717           !entry->AddMachineModelName(model_name)) {
718         LOG(WARNING) << "Malformed machine_model_name entry " << entry->id();
719         return NULL;
720       }
721     }
722     dictionary_entry_count++;
723   }
724
725   const base::DictionaryValue* machine_model_version_value = NULL;
726   if (value->GetDictionary(
727           "machine_model_version", &machine_model_version_value)) {
728     std::string version_op = "any";
729     std::string version_string;
730     std::string version_string2;
731     machine_model_version_value->GetString(kOp, &version_op);
732     machine_model_version_value->GetString("value", &version_string);
733     machine_model_version_value->GetString("value2", &version_string2);
734     if (!entry->SetMachineModelVersionInfo(
735             version_op, version_string, version_string2)) {
736       LOG(WARNING) << "Malformed machine_model_version entry " << entry->id();
737       return NULL;
738     }
739     dictionary_entry_count++;
740   }
741
742   const base::DictionaryValue* gpu_count_value = NULL;
743   if (value->GetDictionary("gpu_count", &gpu_count_value)) {
744     std::string op;
745     std::string int_value;
746     std::string int_value2;
747     gpu_count_value->GetString(kOp, &op);
748     gpu_count_value->GetString("value", &int_value);
749     gpu_count_value->GetString("value2", &int_value2);
750     if (!entry->SetGpuCountInfo(op, int_value, int_value2)) {
751       LOG(WARNING) << "Malformed gpu_count entry " << entry->id();
752       return NULL;
753     }
754     dictionary_entry_count++;
755   }
756
757   bool direct_rendering;
758   if (value->GetBoolean("direct_rendering", &direct_rendering)) {
759     entry->SetDirectRenderingInfo(direct_rendering);
760     dictionary_entry_count++;
761   }
762
763   if (top_level) {
764     const base::ListValue* feature_value = NULL;
765     if (value->GetList("features", &feature_value)) {
766       std::vector<std::string> feature_list;
767       for (size_t i = 0; i < feature_value->GetSize(); ++i) {
768         std::string feature;
769         if (feature_value->GetString(i, &feature)) {
770           feature_list.push_back(feature);
771         } else {
772           LOG(WARNING) << "Malformed feature entry " << entry->id();
773           return NULL;
774         }
775       }
776       if (!entry->SetFeatures(
777               feature_list, feature_map, supports_feature_type_all)) {
778         LOG(WARNING) << "Malformed feature entry " << entry->id();
779         return NULL;
780       }
781       dictionary_entry_count++;
782     }
783   }
784
785   if (top_level) {
786     const base::ListValue* exception_list_value = NULL;
787     if (value->GetList("exceptions", &exception_list_value)) {
788       for (size_t i = 0; i < exception_list_value->GetSize(); ++i) {
789         const base::DictionaryValue* exception_value = NULL;
790         if (!exception_list_value->GetDictionary(i, &exception_value)) {
791           LOG(WARNING) << "Malformed exceptions entry " << entry->id();
792           return NULL;
793         }
794         ScopedGpuControlListEntry exception(GetEntryFromValue(
795             exception_value, false, feature_map, supports_feature_type_all));
796         if (exception.get() == NULL) {
797           LOG(WARNING) << "Malformed exceptions entry " << entry->id();
798           return NULL;
799         }
800         // Exception should inherit vendor_id from parent, otherwise if only
801         // device_ids are specified in Exception, the info will be incomplete.
802         if (exception->vendor_id_ == 0 && entry->vendor_id_ != 0)
803           exception->vendor_id_ = entry->vendor_id_;
804         entry->AddException(exception);
805       }
806       dictionary_entry_count++;
807     }
808   }
809
810   if (value->size() != dictionary_entry_count) {
811     LOG(WARNING) << "Entry with unknown fields " << entry->id();
812     return NULL;
813   }
814
815   // If GL_VERSION is specified, but no info about whether it's GL or GLES,
816   // we use the default for the platform.  See GLType enum declaration.
817   if (entry->gl_version_info_.get() != NULL && entry->gl_type_ == kGLTypeNone)
818     entry->gl_type_ = GetDefaultGLType();
819
820   return entry;
821 }
822
823 GpuControlList::GpuControlListEntry::GpuControlListEntry()
824     : id_(0),
825       disabled_(false),
826       vendor_id_(0),
827       multi_gpu_style_(kMultiGpuStyleNone),
828       multi_gpu_category_(kMultiGpuCategoryPrimary),
829       gl_type_(kGLTypeNone) {
830 }
831
832 GpuControlList::GpuControlListEntry::~GpuControlListEntry() { }
833
834 bool GpuControlList::GpuControlListEntry::SetId(uint32 id) {
835   if (id != 0) {
836     id_ = id;
837     return true;
838   }
839   return false;
840 }
841
842 void GpuControlList::GpuControlListEntry::SetDisabled(bool disabled) {
843   disabled_ = disabled;
844 }
845
846 bool GpuControlList::GpuControlListEntry::SetOsInfo(
847     const std::string& os,
848     const std::string& version_op,
849     const std::string& version_string,
850     const std::string& version_string2) {
851   os_info_.reset(new OsInfo(os, version_op, version_string, version_string2));
852   return os_info_->IsValid();
853 }
854
855 bool GpuControlList::GpuControlListEntry::SetVendorId(
856     const std::string& vendor_id_string) {
857   vendor_id_ = 0;
858   return base::HexStringToUInt(vendor_id_string, &vendor_id_) &&
859       vendor_id_ != 0;
860 }
861
862 bool GpuControlList::GpuControlListEntry::AddDeviceId(
863     const std::string& device_id_string) {
864   uint32 device_id = 0;
865   if (base::HexStringToUInt(device_id_string, &device_id) && device_id != 0) {
866     device_id_list_.push_back(device_id);
867     return true;
868   }
869   return false;
870 }
871
872 bool GpuControlList::GpuControlListEntry::SetMultiGpuStyle(
873     const std::string& multi_gpu_style_string) {
874   MultiGpuStyle style = StringToMultiGpuStyle(multi_gpu_style_string);
875   if (style == kMultiGpuStyleNone)
876     return false;
877   multi_gpu_style_ = style;
878   return true;
879 }
880
881 bool GpuControlList::GpuControlListEntry::SetMultiGpuCategory(
882     const std::string& multi_gpu_category_string) {
883   MultiGpuCategory category =
884       StringToMultiGpuCategory(multi_gpu_category_string);
885   if (category == kMultiGpuCategoryNone)
886     return false;
887   multi_gpu_category_ = category;
888   return true;
889 }
890
891 bool GpuControlList::GpuControlListEntry::SetGLType(
892     const std::string& gl_type_string) {
893   GLType gl_type = StringToGLType(gl_type_string);
894   if (gl_type == kGLTypeNone)
895     return false;
896   gl_type_ = gl_type;
897   return true;
898 }
899
900 bool GpuControlList::GpuControlListEntry::SetDriverVendorInfo(
901     const std::string& vendor_op,
902     const std::string& vendor_value) {
903   driver_vendor_info_.reset(new StringInfo(vendor_op, vendor_value));
904   return driver_vendor_info_->IsValid();
905 }
906
907 bool GpuControlList::GpuControlListEntry::SetDriverVersionInfo(
908     const std::string& version_op,
909     const std::string& version_style,
910     const std::string& version_string,
911     const std::string& version_string2) {
912   driver_version_info_.reset(new VersionInfo(
913       version_op, version_style, version_string, version_string2));
914   return driver_version_info_->IsValid();
915 }
916
917 bool GpuControlList::GpuControlListEntry::SetDriverDateInfo(
918     const std::string& date_op,
919     const std::string& date_string,
920     const std::string& date_string2) {
921   driver_date_info_.reset(
922       new VersionInfo(date_op, std::string(), date_string, date_string2));
923   return driver_date_info_->IsValid();
924 }
925
926 bool GpuControlList::GpuControlListEntry::SetGLVersionInfo(
927     const std::string& version_op,
928     const std::string& version_string,
929     const std::string& version_string2) {
930   gl_version_info_.reset(new VersionInfo(
931       version_op, std::string(), version_string, version_string2));
932   return gl_version_info_->IsValid();
933 }
934
935 bool GpuControlList::GpuControlListEntry::SetGLVendorInfo(
936     const std::string& vendor_op,
937     const std::string& vendor_value) {
938   gl_vendor_info_.reset(new StringInfo(vendor_op, vendor_value));
939   return gl_vendor_info_->IsValid();
940 }
941
942 bool GpuControlList::GpuControlListEntry::SetGLRendererInfo(
943     const std::string& renderer_op,
944     const std::string& renderer_value) {
945   gl_renderer_info_.reset(new StringInfo(renderer_op, renderer_value));
946   return gl_renderer_info_->IsValid();
947 }
948
949 bool GpuControlList::GpuControlListEntry::SetGLExtensionsInfo(
950     const std::string& extensions_op,
951     const std::string& extensions_value) {
952   gl_extensions_info_.reset(new StringInfo(extensions_op, extensions_value));
953   return gl_extensions_info_->IsValid();
954 }
955
956 bool GpuControlList::GpuControlListEntry::SetGLResetNotificationStrategyInfo(
957     const std::string& op,
958     const std::string& int_string,
959     const std::string& int_string2) {
960   gl_reset_notification_strategy_info_.reset(
961       new IntInfo(op, int_string, int_string2));
962   return gl_reset_notification_strategy_info_->IsValid();
963 }
964
965 bool GpuControlList::GpuControlListEntry::SetCpuBrand(
966     const std::string& cpu_op,
967     const std::string& cpu_value) {
968   cpu_brand_.reset(new StringInfo(cpu_op, cpu_value));
969   return cpu_brand_->IsValid();
970 }
971
972 bool GpuControlList::GpuControlListEntry::SetPerfGraphicsInfo(
973     const std::string& op,
974     const std::string& float_string,
975     const std::string& float_string2) {
976   perf_graphics_info_.reset(new FloatInfo(op, float_string, float_string2));
977   return perf_graphics_info_->IsValid();
978 }
979
980 bool GpuControlList::GpuControlListEntry::SetPerfGamingInfo(
981     const std::string& op,
982     const std::string& float_string,
983     const std::string& float_string2) {
984   perf_gaming_info_.reset(new FloatInfo(op, float_string, float_string2));
985   return perf_gaming_info_->IsValid();
986 }
987
988 bool GpuControlList::GpuControlListEntry::SetPerfOverallInfo(
989     const std::string& op,
990     const std::string& float_string,
991     const std::string& float_string2) {
992   perf_overall_info_.reset(new FloatInfo(op, float_string, float_string2));
993   return perf_overall_info_->IsValid();
994 }
995
996 bool GpuControlList::GpuControlListEntry::AddMachineModelName(
997     const std::string& model_name) {
998   if (model_name.empty())
999     return false;
1000   machine_model_name_list_.push_back(model_name);
1001   return true;
1002 }
1003
1004 bool GpuControlList::GpuControlListEntry::SetMachineModelVersionInfo(
1005     const std::string& version_op,
1006     const std::string& version_string,
1007     const std::string& version_string2) {
1008   machine_model_version_info_.reset(new VersionInfo(
1009       version_op, std::string(), version_string, version_string2));
1010   return machine_model_version_info_->IsValid();
1011 }
1012
1013 bool GpuControlList::GpuControlListEntry::SetGpuCountInfo(
1014     const std::string& op,
1015     const std::string& int_string,
1016     const std::string& int_string2) {
1017   gpu_count_info_.reset(new IntInfo(op, int_string, int_string2));
1018   return gpu_count_info_->IsValid();
1019 }
1020
1021 void GpuControlList::GpuControlListEntry::SetDirectRenderingInfo(bool value) {
1022   direct_rendering_info_.reset(new BoolInfo(value));
1023 }
1024
1025 bool GpuControlList::GpuControlListEntry::SetFeatures(
1026     const std::vector<std::string>& feature_strings,
1027     const FeatureMap& feature_map,
1028     bool supports_feature_type_all) {
1029   size_t size = feature_strings.size();
1030   if (size == 0)
1031     return false;
1032   features_.clear();
1033   for (size_t i = 0; i < size; ++i) {
1034     int feature = 0;
1035     if (supports_feature_type_all && feature_strings[i] == "all") {
1036       for (FeatureMap::const_iterator iter = feature_map.begin();
1037            iter != feature_map.end(); ++iter)
1038         features_.insert(iter->second);
1039       continue;
1040     }
1041     if (!StringToFeature(feature_strings[i], &feature, feature_map)) {
1042       features_.clear();
1043       return false;
1044     }
1045     features_.insert(feature);
1046   }
1047   return true;
1048 }
1049
1050 void GpuControlList::GpuControlListEntry::AddException(
1051     ScopedGpuControlListEntry exception) {
1052   exceptions_.push_back(exception);
1053 }
1054
1055 bool GpuControlList::GpuControlListEntry::GLVersionInfoMismatch(
1056     const std::string& gl_version) const {
1057   if (gl_version.empty())
1058     return false;
1059
1060   if (gl_version_info_.get() == NULL && gl_type_ == kGLTypeNone)
1061     return false;
1062
1063   std::vector<std::string> segments;
1064   base::SplitString(gl_version, ' ', &segments);
1065   std::string number;
1066   GLType gl_type = kGLTypeNone;
1067   if (segments.size() > 2 &&
1068       segments[0] == "OpenGL" && segments[1] == "ES") {
1069     number = segments[2];
1070     gl_type = kGLTypeGLES;
1071     if (segments.size() > 3 &&
1072         StartsWithASCII(segments[3], "(ANGLE", false)) {
1073       gl_type = kGLTypeANGLE;
1074     }
1075   } else {
1076     number = segments[0];
1077     gl_type = kGLTypeGL;
1078   }
1079
1080   if (gl_type_ != kGLTypeNone && gl_type_ != gl_type)
1081     return true;
1082   if (gl_version_info_.get() != NULL && !gl_version_info_->Contains(number))
1083     return true;
1084   return false;
1085 }
1086
1087 // static
1088 GpuControlList::GpuControlListEntry::MultiGpuStyle
1089 GpuControlList::GpuControlListEntry::StringToMultiGpuStyle(
1090     const std::string& style) {
1091   if (style == kMultiGpuStyleStringOptimus)
1092     return kMultiGpuStyleOptimus;
1093   if (style == kMultiGpuStyleStringAMDSwitchable)
1094     return kMultiGpuStyleAMDSwitchable;
1095   if (style == kMultiGpuStyleStringAMDSwitchableIntegrated)
1096     return kMultiGpuStyleAMDSwitchableIntegrated;
1097   if (style == kMultiGpuStyleStringAMDSwitchableDiscrete)
1098     return kMultiGpuStyleAMDSwitchableDiscrete;
1099   return kMultiGpuStyleNone;
1100 }
1101
1102 // static
1103 GpuControlList::GpuControlListEntry::MultiGpuCategory
1104 GpuControlList::GpuControlListEntry::StringToMultiGpuCategory(
1105     const std::string& category) {
1106   if (category == kMultiGpuCategoryStringPrimary)
1107     return kMultiGpuCategoryPrimary;
1108   if (category == kMultiGpuCategoryStringSecondary)
1109     return kMultiGpuCategorySecondary;
1110   if (category == kMultiGpuCategoryStringActive)
1111     return kMultiGpuCategoryActive;
1112   if (category == kMultiGpuCategoryStringAny)
1113     return kMultiGpuCategoryAny;
1114   return kMultiGpuCategoryNone;
1115 }
1116
1117 // static
1118 GpuControlList::GpuControlListEntry::GLType
1119 GpuControlList::GpuControlListEntry::StringToGLType(
1120     const std::string& gl_type) {
1121   if (gl_type == kGLTypeStringGL)
1122     return kGLTypeGL;
1123   if (gl_type == kGLTypeStringGLES)
1124     return kGLTypeGLES;
1125   if (gl_type == kGLTypeStringANGLE)
1126     return kGLTypeANGLE;
1127   return kGLTypeNone;
1128 }
1129
1130 // static
1131 GpuControlList::GpuControlListEntry::GLType
1132 GpuControlList::GpuControlListEntry::GetDefaultGLType() {
1133 #if defined(OS_CHROMEOS)
1134   return kGLTypeGL;
1135 #elif defined(OS_LINUX) || defined(OS_OPENBSD)
1136   return kGLTypeGL;
1137 #elif defined(OS_MACOSX)
1138   return kGLTypeGL;
1139 #elif defined(OS_WIN)
1140   return kGLTypeANGLE;
1141 #elif defined(OS_ANDROID)
1142   return kGLTypeGLES;
1143 #else
1144   return kGLTypeNone;
1145 #endif
1146 }
1147
1148 void GpuControlList::GpuControlListEntry::LogControlListMatch(
1149     const std::string& control_list_logging_name) const {
1150   static const char kControlListMatchMessage[] =
1151       "Control list match for rule #%u in %s.";
1152   VLOG(1) << base::StringPrintf(kControlListMatchMessage, id_,
1153                                 control_list_logging_name.c_str());
1154 }
1155
1156 bool GpuControlList::GpuControlListEntry::Contains(
1157     OsType os_type, const std::string& os_version,
1158     const GPUInfo& gpu_info) const {
1159   DCHECK(os_type != kOsAny);
1160   if (os_info_.get() != NULL && !os_info_->Contains(os_type, os_version))
1161     return false;
1162   if (vendor_id_ != 0) {
1163     std::vector<GPUInfo::GPUDevice> candidates;
1164     switch (multi_gpu_category_) {
1165       case kMultiGpuCategoryPrimary:
1166         candidates.push_back(gpu_info.gpu);
1167         break;
1168       case kMultiGpuCategorySecondary:
1169         candidates = gpu_info.secondary_gpus;
1170         break;
1171       case kMultiGpuCategoryAny:
1172         candidates = gpu_info.secondary_gpus;
1173         candidates.push_back(gpu_info.gpu);
1174         break;
1175       case kMultiGpuCategoryActive:
1176         if (gpu_info.gpu.active)
1177           candidates.push_back(gpu_info.gpu);
1178         for (size_t ii = 0; ii < gpu_info.secondary_gpus.size(); ++ii) {
1179           if (gpu_info.secondary_gpus[ii].active)
1180             candidates.push_back(gpu_info.secondary_gpus[ii]);
1181         }
1182       default:
1183         break;
1184     }
1185
1186     GPUInfo::GPUDevice gpu;
1187     gpu.vendor_id = vendor_id_;
1188     bool found = false;
1189     if (device_id_list_.empty()) {
1190       for (size_t ii = 0; ii < candidates.size(); ++ii) {
1191         if (gpu.vendor_id == candidates[ii].vendor_id) {
1192           found = true;
1193           break;
1194         }
1195       }
1196     } else {
1197       for (size_t ii = 0; ii < device_id_list_.size(); ++ii) {
1198         gpu.device_id = device_id_list_[ii];
1199         for (size_t jj = 0; jj < candidates.size(); ++jj) {
1200           if (gpu.vendor_id == candidates[jj].vendor_id &&
1201               gpu.device_id == candidates[jj].device_id) {
1202             found = true;
1203             break;
1204           }
1205         }
1206       }
1207     }
1208     if (!found)
1209       return false;
1210   }
1211   switch (multi_gpu_style_) {
1212     case kMultiGpuStyleOptimus:
1213       if (!gpu_info.optimus)
1214         return false;
1215       break;
1216     case kMultiGpuStyleAMDSwitchable:
1217       if (!gpu_info.amd_switchable)
1218         return false;
1219       break;
1220     case kMultiGpuStyleAMDSwitchableDiscrete:
1221       if (!gpu_info.amd_switchable)
1222         return false;
1223       // The discrete GPU is always the primary GPU.
1224       // This is guaranteed by GpuInfoCollector.
1225       if (!gpu_info.gpu.active)
1226         return false;
1227       break;
1228     case kMultiGpuStyleAMDSwitchableIntegrated:
1229       if (!gpu_info.amd_switchable)
1230         return false;
1231       // Assume the integrated GPU is the first in the secondary GPU list.
1232       if (gpu_info.secondary_gpus.size() == 0 ||
1233           !gpu_info.secondary_gpus[0].active)
1234         return false;
1235       break;
1236     case kMultiGpuStyleNone:
1237       break;
1238   }
1239   if (driver_vendor_info_.get() != NULL && !gpu_info.driver_vendor.empty() &&
1240       !driver_vendor_info_->Contains(gpu_info.driver_vendor))
1241     return false;
1242   if (driver_version_info_.get() != NULL && !gpu_info.driver_version.empty()) {
1243     if (!driver_version_info_->Contains(gpu_info.driver_version))
1244       return false;
1245   }
1246   if (driver_date_info_.get() != NULL && !gpu_info.driver_date.empty()) {
1247     if (!driver_date_info_->Contains(gpu_info.driver_date, '-'))
1248       return false;
1249   }
1250   if (GLVersionInfoMismatch(gpu_info.gl_version))
1251     return false;
1252   if (gl_vendor_info_.get() != NULL && !gpu_info.gl_vendor.empty() &&
1253       !gl_vendor_info_->Contains(gpu_info.gl_vendor))
1254     return false;
1255   if (gl_renderer_info_.get() != NULL && !gpu_info.gl_renderer.empty() &&
1256       !gl_renderer_info_->Contains(gpu_info.gl_renderer))
1257     return false;
1258   if (gl_extensions_info_.get() != NULL && !gpu_info.gl_extensions.empty() &&
1259       !gl_extensions_info_->Contains(gpu_info.gl_extensions))
1260     return false;
1261   if (gl_reset_notification_strategy_info_.get() != NULL &&
1262       !gl_reset_notification_strategy_info_->Contains(
1263           gpu_info.gl_reset_notification_strategy))
1264     return false;
1265   if (perf_graphics_info_.get() != NULL &&
1266       (gpu_info.performance_stats.graphics == 0.0 ||
1267        !perf_graphics_info_->Contains(gpu_info.performance_stats.graphics)))
1268     return false;
1269   if (perf_gaming_info_.get() != NULL &&
1270       (gpu_info.performance_stats.gaming == 0.0 ||
1271        !perf_gaming_info_->Contains(gpu_info.performance_stats.gaming)))
1272     return false;
1273   if (perf_overall_info_.get() != NULL &&
1274       (gpu_info.performance_stats.overall == 0.0 ||
1275        !perf_overall_info_->Contains(gpu_info.performance_stats.overall)))
1276     return false;
1277   if (!machine_model_name_list_.empty()) {
1278     if (gpu_info.machine_model_name.empty())
1279       return false;
1280     bool found_match = false;
1281     for (size_t ii = 0; ii < machine_model_name_list_.size(); ++ii) {
1282       if (machine_model_name_list_[ii] == gpu_info.machine_model_name) {
1283         found_match = true;
1284         break;
1285       }
1286     }
1287     if (!found_match)
1288       return false;
1289   }
1290   if (machine_model_version_info_.get() != NULL &&
1291       (gpu_info.machine_model_version.empty() ||
1292        !machine_model_version_info_->Contains(gpu_info.machine_model_version)))
1293     return false;
1294   if (gpu_count_info_.get() != NULL &&
1295       !gpu_count_info_->Contains(gpu_info.secondary_gpus.size() + 1))
1296     return false;
1297   if (direct_rendering_info_.get() != NULL &&
1298       !direct_rendering_info_->Contains(gpu_info.direct_rendering))
1299     return false;
1300   if (cpu_brand_.get() != NULL) {
1301     base::CPU cpu_info;
1302     if (!cpu_brand_->Contains(cpu_info.cpu_brand()))
1303       return false;
1304   }
1305
1306   for (size_t i = 0; i < exceptions_.size(); ++i) {
1307     if (exceptions_[i]->Contains(os_type, os_version, gpu_info) &&
1308         !exceptions_[i]->NeedsMoreInfo(gpu_info))
1309       return false;
1310   }
1311   return true;
1312 }
1313
1314 bool GpuControlList::GpuControlListEntry::NeedsMoreInfo(
1315     const GPUInfo& gpu_info) const {
1316   // We only check for missing info that might be collected with a gl context.
1317   // If certain info is missing due to some error, say, we fail to collect
1318   // vendor_id/device_id, then even if we launch GPU process and create a gl
1319   // context, we won't gather such missing info, so we still return false.
1320   if (driver_vendor_info_.get() && gpu_info.driver_vendor.empty())
1321     return true;
1322   if (driver_version_info_.get() && gpu_info.driver_version.empty())
1323     return true;
1324   if (gl_vendor_info_.get() && gpu_info.gl_vendor.empty())
1325     return true;
1326   if (gl_renderer_info_.get() && gpu_info.gl_renderer.empty())
1327     return true;
1328   for (size_t i = 0; i < exceptions_.size(); ++i) {
1329     if (exceptions_[i]->NeedsMoreInfo(gpu_info))
1330       return true;
1331   }
1332   return false;
1333 }
1334
1335 GpuControlList::OsType GpuControlList::GpuControlListEntry::GetOsType() const {
1336   if (os_info_.get() == NULL)
1337     return kOsAny;
1338   return os_info_->type();
1339 }
1340
1341 uint32 GpuControlList::GpuControlListEntry::id() const {
1342   return id_;
1343 }
1344
1345 bool GpuControlList::GpuControlListEntry::disabled() const {
1346   return disabled_;
1347 }
1348
1349 const std::set<int>& GpuControlList::GpuControlListEntry::features() const {
1350   return features_;
1351 }
1352
1353 void GpuControlList::GpuControlListEntry::GetFeatureNames(
1354     base::ListValue* feature_names,
1355     const FeatureMap& feature_map,
1356     bool supports_feature_type_all) const {
1357   DCHECK(feature_names);
1358   if (supports_feature_type_all && features_.size() == feature_map.size()) {
1359     feature_names->AppendString("all");
1360     return;
1361   }
1362   for (FeatureMap::const_iterator iter = feature_map.begin();
1363        iter != feature_map.end(); ++iter) {
1364     if (features_.count(iter->second) > 0)
1365       feature_names->AppendString(iter->first);
1366   }
1367 }
1368
1369 // static
1370 bool GpuControlList::GpuControlListEntry::StringToFeature(
1371     const std::string& feature_name, int* feature_id,
1372     const FeatureMap& feature_map) {
1373   FeatureMap::const_iterator iter = feature_map.find(feature_name);
1374   if (iter != feature_map.end()) {
1375     *feature_id = iter->second;
1376     return true;
1377   }
1378   return false;
1379 }
1380
1381 GpuControlList::GpuControlList()
1382     : max_entry_id_(0),
1383       needs_more_info_(false),
1384       supports_feature_type_all_(false),
1385       control_list_logging_enabled_(false) {
1386 }
1387
1388 GpuControlList::~GpuControlList() {
1389   Clear();
1390 }
1391
1392 bool GpuControlList::LoadList(
1393     const std::string& json_context,
1394     GpuControlList::OsFilter os_filter) {
1395   scoped_ptr<base::Value> root;
1396   root.reset(base::JSONReader::Read(json_context));
1397   if (root.get() == NULL || !root->IsType(base::Value::TYPE_DICTIONARY))
1398     return false;
1399
1400   base::DictionaryValue* root_dictionary =
1401       static_cast<base::DictionaryValue*>(root.get());
1402   DCHECK(root_dictionary);
1403   return LoadList(*root_dictionary, os_filter);
1404 }
1405
1406 bool GpuControlList::LoadList(const base::DictionaryValue& parsed_json,
1407                               GpuControlList::OsFilter os_filter) {
1408   std::vector<ScopedGpuControlListEntry> entries;
1409
1410   parsed_json.GetString("version", &version_);
1411   std::vector<std::string> pieces;
1412   if (!ProcessVersionString(version_, '.', &pieces))
1413     return false;
1414
1415   const base::ListValue* list = NULL;
1416   if (!parsed_json.GetList("entries", &list))
1417     return false;
1418
1419   uint32 max_entry_id = 0;
1420   for (size_t i = 0; i < list->GetSize(); ++i) {
1421     const base::DictionaryValue* list_item = NULL;
1422     bool valid = list->GetDictionary(i, &list_item);
1423     if (!valid || list_item == NULL)
1424       return false;
1425     ScopedGpuControlListEntry entry(GpuControlListEntry::GetEntryFromValue(
1426         list_item, true, feature_map_, supports_feature_type_all_));
1427     if (entry.get() == NULL)
1428       return false;
1429     if (entry->id() > max_entry_id)
1430       max_entry_id = entry->id();
1431     entries.push_back(entry);
1432   }
1433
1434   Clear();
1435   OsType my_os = GetOsType();
1436   for (size_t i = 0; i < entries.size(); ++i) {
1437     OsType entry_os = entries[i]->GetOsType();
1438     if (os_filter == GpuControlList::kAllOs ||
1439         entry_os == kOsAny || entry_os == my_os)
1440       entries_.push_back(entries[i]);
1441   }
1442   max_entry_id_ = max_entry_id;
1443   return true;
1444 }
1445
1446 std::set<int> GpuControlList::MakeDecision(
1447     GpuControlList::OsType os,
1448     std::string os_version,
1449     const GPUInfo& gpu_info) {
1450   active_entries_.clear();
1451   std::set<int> features;
1452
1453   needs_more_info_ = false;
1454   std::set<int> possible_features;
1455
1456   if (os == kOsAny)
1457     os = GetOsType();
1458   if (os_version.empty())
1459     os_version = base::SysInfo::OperatingSystemVersion();
1460
1461   for (size_t i = 0; i < entries_.size(); ++i) {
1462     if (entries_[i]->Contains(os, os_version, gpu_info)) {
1463       if (!entries_[i]->disabled()) {
1464         if (control_list_logging_enabled_)
1465           entries_[i]->LogControlListMatch(control_list_logging_name_);
1466         MergeFeatureSets(&possible_features, entries_[i]->features());
1467         if (!entries_[i]->NeedsMoreInfo(gpu_info))
1468           MergeFeatureSets(&features, entries_[i]->features());
1469       }
1470       active_entries_.push_back(entries_[i]);
1471     }
1472   }
1473
1474   if (possible_features.size() > features.size())
1475     needs_more_info_ = true;
1476
1477   return features;
1478 }
1479
1480 void GpuControlList::GetDecisionEntries(
1481     std::vector<uint32>* entry_ids, bool disabled) const {
1482   DCHECK(entry_ids);
1483   entry_ids->clear();
1484   for (size_t i = 0; i < active_entries_.size(); ++i) {
1485     if (disabled == active_entries_[i]->disabled())
1486       entry_ids->push_back(active_entries_[i]->id());
1487   }
1488 }
1489
1490 void GpuControlList::GetReasons(base::ListValue* problem_list,
1491                                 const std::string& tag) const {
1492   DCHECK(problem_list);
1493   for (size_t i = 0; i < active_entries_.size(); ++i) {
1494     GpuControlListEntry* entry = active_entries_[i].get();
1495     if (entry->disabled())
1496       continue;
1497     base::DictionaryValue* problem = new base::DictionaryValue();
1498
1499     problem->SetString("description", entry->description());
1500
1501     base::ListValue* cr_bugs = new base::ListValue();
1502     for (size_t j = 0; j < entry->cr_bugs().size(); ++j)
1503       cr_bugs->Append(new base::FundamentalValue(entry->cr_bugs()[j]));
1504     problem->Set("crBugs", cr_bugs);
1505
1506     base::ListValue* webkit_bugs = new base::ListValue();
1507     for (size_t j = 0; j < entry->webkit_bugs().size(); ++j) {
1508       webkit_bugs->Append(new base::FundamentalValue(entry->webkit_bugs()[j]));
1509     }
1510     problem->Set("webkitBugs", webkit_bugs);
1511
1512     base::ListValue* features = new base::ListValue();
1513     entry->GetFeatureNames(features, feature_map_, supports_feature_type_all_);
1514     problem->Set("affectedGpuSettings", features);
1515
1516     DCHECK(tag == "workarounds" || tag == "disabledFeatures");
1517     problem->SetString("tag", tag);
1518
1519     problem_list->Append(problem);
1520   }
1521 }
1522
1523 size_t GpuControlList::num_entries() const {
1524   return entries_.size();
1525 }
1526
1527 uint32 GpuControlList::max_entry_id() const {
1528   return max_entry_id_;
1529 }
1530
1531 std::string GpuControlList::version() const {
1532   return version_;
1533 }
1534
1535 GpuControlList::OsType GpuControlList::GetOsType() {
1536 #if defined(OS_CHROMEOS)
1537   return kOsChromeOS;
1538 #elif defined(OS_WIN)
1539   return kOsWin;
1540 #elif defined(OS_ANDROID)
1541   return kOsAndroid;
1542 #elif defined(OS_LINUX) || defined(OS_OPENBSD)
1543   return kOsLinux;
1544 #elif defined(OS_MACOSX)
1545   return kOsMacosx;
1546 #else
1547   return kOsUnknown;
1548 #endif
1549 }
1550
1551 void GpuControlList::Clear() {
1552   entries_.clear();
1553   active_entries_.clear();
1554   max_entry_id_ = 0;
1555 }
1556
1557 // static
1558 GpuControlList::NumericOp GpuControlList::StringToNumericOp(
1559     const std::string& op) {
1560   if (op == "=")
1561     return kEQ;
1562   if (op == "<")
1563     return kLT;
1564   if (op == "<=")
1565     return kLE;
1566   if (op == ">")
1567     return kGT;
1568   if (op == ">=")
1569     return kGE;
1570   if (op == "any")
1571     return kAny;
1572   if (op == "between")
1573     return kBetween;
1574   return kUnknown;
1575 }
1576
1577 void GpuControlList::AddSupportedFeature(
1578     const std::string& feature_name, int feature_id) {
1579   feature_map_[feature_name] = feature_id;
1580 }
1581
1582 void GpuControlList::set_supports_feature_type_all(bool supported) {
1583   supports_feature_type_all_ = supported;
1584 }
1585
1586 }  // namespace gpu
1587