OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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 "chrome/browser/gpu_blacklist.h" | |
6 | |
7 #include "base/json/json_reader.h" | |
8 #include "base/logging.h" | |
9 #include "base/string_number_conversions.h" | |
10 #include "base/string_util.h" | |
11 #include "base/stringprintf.h" | |
12 #include "base/sys_info.h" | |
13 #include "base/values.h" | |
14 #include "base/version.h" | |
15 #include "chrome/common/gpu_info.h" | |
16 | |
17 GpuBlacklist::VersionInfo::VersionInfo(const std::string& version_op, | |
18 const std::string& version_string, | |
19 const std::string& version_string2) { | |
20 op_ = StringToOp(version_op); | |
21 if (op_ == kUnknown || op_ == kAny) | |
22 return; | |
23 version_.reset(Version::GetVersionFromString(version_string)); | |
24 if (version_.get() == NULL) { | |
25 op_ = kUnknown; | |
26 return; | |
27 } | |
28 if (op_ == kBetween) { | |
29 version2_.reset(Version::GetVersionFromString(version_string2)); | |
30 if (version2_.get() == NULL) | |
31 op_ = kUnknown; | |
32 } | |
33 } | |
34 | |
35 GpuBlacklist::VersionInfo::~VersionInfo() { | |
36 } | |
37 | |
38 bool GpuBlacklist::VersionInfo::Contains(const Version& version) const { | |
39 if (op_ == kUnknown) | |
40 return false; | |
41 if (op_ == kAny) | |
42 return true; | |
43 if (op_ == kEQ) { | |
44 // Handles cases where 10.6 is considered as containing 10.6.*. | |
45 const std::vector<uint16>& components_reference = version_->components(); | |
46 const std::vector<uint16>& components = version.components(); | |
47 for (size_t i = 0; i < components_reference.size(); ++i) { | |
48 if (i >= components.size() && components_reference[i] != 0) | |
49 return false; | |
50 if (components[i] != components_reference[i]) | |
51 return false; | |
52 } | |
53 return true; | |
54 } | |
55 int relation = version.CompareTo(*version_); | |
56 if (op_ == kEQ) | |
57 return (relation == 0); | |
58 else if (op_ == kLT) | |
59 return (relation < 0); | |
60 else if (op_ == kLE) | |
61 return (relation <= 0); | |
62 else if (op_ == kGT) | |
63 return (relation > 0); | |
64 else if (op_ == kGE) | |
65 return (relation >= 0); | |
66 // op_ == kBetween | |
67 if (relation < 0) | |
68 return false; | |
69 return version.CompareTo(*version2_) <= 0; | |
70 } | |
71 | |
72 bool GpuBlacklist::VersionInfo::IsValid() const { | |
73 return op_ != kUnknown; | |
74 } | |
75 | |
76 GpuBlacklist::VersionInfo::Op GpuBlacklist::VersionInfo::StringToOp( | |
77 const std::string& version_op) { | |
78 if (version_op == "=") | |
79 return kEQ; | |
80 else if (version_op == "<") | |
81 return kLT; | |
82 else if (version_op == "<=") | |
83 return kLE; | |
84 else if (version_op == ">") | |
85 return kGT; | |
86 else if (version_op == ">=") | |
87 return kGE; | |
88 else if (version_op == "any") | |
89 return kAny; | |
90 else if (version_op == "between") | |
91 return kBetween; | |
92 return kUnknown; | |
93 } | |
94 | |
95 GpuBlacklist::OsInfo::OsInfo(const std::string& os, | |
96 const std::string& version_op, | |
97 const std::string& version_string, | |
98 const std::string& version_string2) { | |
99 type_ = StringToOsType(os); | |
100 if (type_ != kOsUnknown) { | |
101 version_info_.reset( | |
102 new VersionInfo(version_op, version_string, version_string2)); | |
103 } | |
104 } | |
105 | |
106 GpuBlacklist::OsInfo::~OsInfo() {} | |
107 | |
108 bool GpuBlacklist::OsInfo::Contains(OsType type, | |
109 const Version& version) const { | |
110 if (!IsValid()) | |
111 return false; | |
112 if (type_ != type && type_ != kOsAny) | |
113 return false; | |
114 return version_info_->Contains(version); | |
115 } | |
116 | |
117 bool GpuBlacklist::OsInfo::IsValid() const { | |
118 return type_ != kOsUnknown && version_info_->IsValid(); | |
119 } | |
120 | |
121 GpuBlacklist::OsType GpuBlacklist::OsInfo::type() const { | |
122 return type_; | |
123 } | |
124 | |
125 GpuBlacklist::OsType GpuBlacklist::OsInfo::StringToOsType( | |
126 const std::string& os) { | |
127 if (os == "win") | |
128 return kOsWin; | |
129 else if (os == "macosx") | |
130 return kOsMacosx; | |
131 else if (os == "linux") | |
132 return kOsLinux; | |
133 else if (os == "any") | |
134 return kOsAny; | |
135 return kOsUnknown; | |
136 } | |
137 | |
138 GpuBlacklist::StringInfo::StringInfo(const std::string& string_op, | |
139 const std::string& string_value) { | |
140 op_ = StringToOp(string_op); | |
141 value_ = StringToLowerASCII(string_value); | |
142 } | |
143 | |
144 bool GpuBlacklist::StringInfo::Contains(const std::string& value) const { | |
145 std::string my_value = StringToLowerASCII(value); | |
146 switch (op_) { | |
147 case kContains: | |
148 return strstr(my_value.c_str(), value_.c_str()) != NULL; | |
149 case kBeginWith: | |
150 return StartsWithASCII(my_value, value_, false); | |
151 case kEndWith: | |
152 return EndsWith(my_value, value_, false); | |
153 case kEQ: | |
154 return value_ == my_value; | |
155 default: | |
156 return false; | |
157 } | |
158 } | |
159 | |
160 bool GpuBlacklist::StringInfo::IsValid() const { | |
161 return op_ != kUnknown; | |
162 } | |
163 | |
164 GpuBlacklist::StringInfo::Op GpuBlacklist::StringInfo::StringToOp( | |
165 const std::string& string_op) { | |
166 if (string_op == "=") | |
167 return kEQ; | |
168 else if (string_op == "contains") | |
169 return kContains; | |
170 else if (string_op == "beginwith") | |
171 return kBeginWith; | |
172 else if (string_op == "endwith") | |
173 return kEndWith; | |
174 return kUnknown; | |
175 } | |
176 | |
177 GpuBlacklist::GpuBlacklistEntry* | |
178 GpuBlacklist::GpuBlacklistEntry::GetGpuBlacklistEntryFromValue( | |
179 DictionaryValue* value) { | |
180 if (value == NULL) | |
181 return NULL; | |
182 | |
183 GpuBlacklistEntry* entry = new GpuBlacklistEntry(); | |
184 | |
185 std::string id; | |
186 if (!value->GetString("id", &id) || !entry->SetId(id)) { | |
187 delete entry; | |
188 return NULL; | |
189 } | |
190 | |
191 DictionaryValue* os_value = NULL; | |
192 if (value->GetDictionary("os", &os_value)) { | |
193 std::string os_type; | |
194 std::string os_version_op = "any"; | |
195 std::string os_version_string; | |
196 std::string os_version_string2; | |
197 os_value->GetString("type", &os_type); | |
198 DictionaryValue* os_version_value = NULL; | |
199 if (os_value->GetDictionary("version", &os_version_value)) { | |
200 os_version_value->GetString("op", &os_version_op); | |
201 os_version_value->GetString("number", &os_version_string); | |
202 os_version_value->GetString("number2", &os_version_string2); | |
203 } | |
204 if (!entry->SetOsInfo(os_type, os_version_op, os_version_string, | |
205 os_version_string2)) { | |
206 delete entry; | |
207 return NULL; | |
208 } | |
209 } | |
210 | |
211 std::string vendor_id; | |
212 if (value->GetString("vendor_id", &vendor_id)) { | |
213 if (!entry->SetVendorId(vendor_id)) { | |
214 delete entry; | |
215 return NULL; | |
216 } | |
217 } | |
218 | |
219 std::string device_id; | |
220 if (value->GetString("device_id", &device_id)) { | |
221 if (!entry->SetDeviceId(device_id)) { | |
222 delete entry; | |
223 return NULL; | |
224 } | |
225 } | |
226 | |
227 DictionaryValue* driver_vendor_value = NULL; | |
228 if (value->GetDictionary("driver_vendor", &driver_vendor_value)) { | |
229 std::string vendor_op; | |
230 std::string vendor_value; | |
231 driver_vendor_value->GetString("op", &vendor_op); | |
232 driver_vendor_value->GetString("value", &vendor_value); | |
233 if (!entry->SetDriverVendorInfo(vendor_op, vendor_value)) { | |
234 delete entry; | |
235 return NULL; | |
236 } | |
237 } | |
238 | |
239 DictionaryValue* driver_version_value = NULL; | |
240 if (value->GetDictionary("driver_version", &driver_version_value)) { | |
241 std::string driver_version_op = "any"; | |
242 std::string driver_version_string; | |
243 std::string driver_version_string2; | |
244 driver_version_value->GetString("op", &driver_version_op); | |
245 driver_version_value->GetString("number", &driver_version_string); | |
246 driver_version_value->GetString("number2", &driver_version_string2); | |
247 if (!entry->SetDriverVersionInfo(driver_version_op, driver_version_string, | |
248 driver_version_string2)) { | |
249 delete entry; | |
250 return NULL; | |
251 } | |
252 } | |
253 | |
254 DictionaryValue* gl_renderer_value = NULL; | |
255 if (value->GetDictionary("gl_renderer", &gl_renderer_value)) { | |
256 std::string renderer_op; | |
257 std::string renderer_value; | |
258 gl_renderer_value->GetString("op", &renderer_op); | |
259 gl_renderer_value->GetString("value", &renderer_value); | |
260 if (!entry->SetGLRendererInfo(renderer_op, renderer_value)) { | |
261 delete entry; | |
262 return NULL; | |
263 } | |
264 } | |
265 | |
266 ListValue* blacklist_value = NULL; | |
267 if (!value->GetList("blacklist", &blacklist_value)) { | |
268 delete entry; | |
269 return NULL; | |
270 } | |
271 std::vector<std::string> blacklist; | |
272 for (size_t i = 0; i < blacklist_value->GetSize(); ++i) { | |
273 std::string feature; | |
274 if (blacklist_value->GetString(i, &feature)) { | |
275 blacklist.push_back(feature); | |
276 } else { | |
277 delete entry; | |
278 return NULL; | |
279 } | |
280 } | |
281 if (!entry->SetBlacklistedFeatures(blacklist)) { | |
282 delete entry; | |
283 return NULL; | |
284 } | |
285 | |
286 return entry; | |
287 } | |
288 | |
289 GpuBlacklist::GpuBlacklistEntry::~GpuBlacklistEntry() {} | |
290 | |
291 GpuBlacklist::GpuBlacklistEntry::GpuBlacklistEntry() | |
292 : id_(0), | |
293 vendor_id_(0), | |
294 device_id_(0) { | |
295 } | |
296 | |
297 bool GpuBlacklist::GpuBlacklistEntry::SetId( | |
298 const std::string& id_string) { | |
299 int my_id; | |
300 if (base::HexStringToInt(id_string, &my_id) && my_id != 0) { | |
301 id_ = static_cast<uint32>(my_id); | |
302 return true; | |
303 } | |
304 return false; | |
305 } | |
306 | |
307 bool GpuBlacklist::GpuBlacklistEntry::SetOsInfo( | |
308 const std::string& os, | |
309 const std::string& version_op, | |
310 const std::string& version_string, | |
311 const std::string& version_string2) { | |
312 os_info_.reset(new OsInfo(os, version_op, version_string, version_string2)); | |
313 return os_info_->IsValid(); | |
314 } | |
315 | |
316 bool GpuBlacklist::GpuBlacklistEntry::SetVendorId( | |
317 const std::string& vendor_id_string) { | |
318 vendor_id_ = 0; | |
319 return base::HexStringToInt(vendor_id_string, | |
320 reinterpret_cast<int*>(&vendor_id_)); | |
321 } | |
322 | |
323 bool GpuBlacklist::GpuBlacklistEntry::SetDeviceId( | |
324 const std::string& device_id_string) { | |
325 device_id_ = 0; | |
326 return base::HexStringToInt(device_id_string, | |
327 reinterpret_cast<int*>(&device_id_)); | |
328 } | |
329 | |
330 bool GpuBlacklist::GpuBlacklistEntry::SetDriverVendorInfo( | |
331 const std::string& vendor_op, | |
332 const std::string& vendor_value) { | |
333 driver_vendor_info_.reset( | |
334 new StringInfo(vendor_op, vendor_value)); | |
335 return driver_vendor_info_->IsValid(); | |
336 } | |
337 | |
338 bool GpuBlacklist::GpuBlacklistEntry::SetDriverVersionInfo( | |
339 const std::string& version_op, | |
340 const std::string& version_string, | |
341 const std::string& version_string2) { | |
342 driver_version_info_.reset( | |
343 new VersionInfo(version_op, version_string, version_string2)); | |
344 return driver_version_info_->IsValid(); | |
345 } | |
346 | |
347 bool GpuBlacklist::GpuBlacklistEntry::SetGLRendererInfo( | |
348 const std::string& renderer_op, | |
349 const std::string& renderer_value) { | |
350 gl_renderer_info_.reset( | |
351 new StringInfo(renderer_op, renderer_value)); | |
352 return gl_renderer_info_->IsValid(); | |
353 } | |
354 | |
355 bool GpuBlacklist::GpuBlacklistEntry::SetBlacklistedFeatures( | |
356 const std::vector<std::string>& blacklisted_features) { | |
357 size_t size = blacklisted_features.size(); | |
358 if (size == 0) | |
359 return false; | |
360 uint32 flags = 0; | |
361 for (size_t i = 0; i < size; ++i) { | |
362 GpuFeatureFlags::GpuFeatureType type = | |
363 GpuFeatureFlags::StringToGpuFeatureType(blacklisted_features[i]); | |
364 switch (type) { | |
365 case GpuFeatureFlags::kGpuFeatureAccelerated2dCanvas: | |
366 case GpuFeatureFlags::kGpuFeatureAcceleratedCompositing: | |
367 case GpuFeatureFlags::kGpuFeatureWebgl: | |
368 case GpuFeatureFlags::kGpuFeatureAll: | |
369 flags |= type; | |
370 break; | |
371 case GpuFeatureFlags::kGpuFeatureUnknown: | |
372 return false; | |
373 } | |
374 } | |
375 feature_flags_.reset(new GpuFeatureFlags()); | |
376 feature_flags_->set_flags(flags); | |
377 return true; | |
378 } | |
379 | |
380 bool GpuBlacklist::GpuBlacklistEntry::Contains( | |
381 OsType os_type, const Version& os_version, const GPUInfo& gpu_info) const { | |
382 DCHECK(os_type != kOsAny); | |
383 if (os_info_.get() != NULL && !os_info_->Contains(os_type, os_version)) | |
384 return false; | |
385 if (vendor_id_ != 0 && vendor_id_ != gpu_info.vendor_id()) | |
386 return false; | |
387 if (device_id_ != 0 && device_id_ != gpu_info.device_id()) | |
388 return false; | |
389 if (driver_vendor_info_.get() != NULL && | |
390 !driver_vendor_info_->Contains(gpu_info.driver_vendor())) | |
391 return false; | |
392 if (driver_version_info_.get() != NULL) { | |
393 scoped_ptr<Version> driver_version( | |
394 Version::GetVersionFromString(gpu_info.driver_version())); | |
395 if (driver_version.get() == NULL || | |
396 !driver_version_info_->Contains(*driver_version)) | |
397 return false; | |
398 } | |
399 if (gl_renderer_info_.get() != NULL && | |
400 !gl_renderer_info_->Contains(gpu_info.gl_renderer())) | |
401 return false; | |
402 return true; | |
403 } | |
404 | |
405 GpuBlacklist::OsType GpuBlacklist::GpuBlacklistEntry::GetOsType() const { | |
406 if (os_info_.get() == NULL) | |
407 return kOsAny; | |
408 return os_info_->type(); | |
409 } | |
410 | |
411 uint32 GpuBlacklist::GpuBlacklistEntry::id() const { | |
412 return id_; | |
413 } | |
414 | |
415 GpuFeatureFlags GpuBlacklist::GpuBlacklistEntry::GetGpuFeatureFlags() const { | |
416 return *feature_flags_; | |
417 } | |
418 | |
419 GpuBlacklist::GpuBlacklist() | |
420 : max_entry_id_(0) { | |
421 } | |
422 | |
423 GpuBlacklist::~GpuBlacklist() { | |
424 Clear(); | |
425 } | |
426 | |
427 bool GpuBlacklist::LoadGpuBlacklist(const std::string& json_context, | |
428 bool current_os_only) { | |
429 std::vector<GpuBlacklistEntry*> entries; | |
430 scoped_ptr<Value> root; | |
431 root.reset(base::JSONReader::Read(json_context, false)); | |
432 if (root.get() == NULL || !root->IsType(Value::TYPE_DICTIONARY)) | |
433 return false; | |
434 | |
435 DictionaryValue* root_dictionary = static_cast<DictionaryValue*>(root.get()); | |
436 DCHECK(root_dictionary); | |
437 std::string version_string; | |
438 root_dictionary->GetString("version", &version_string); | |
439 version_.reset(Version::GetVersionFromString(version_string)); | |
440 if (version_.get() == NULL) | |
441 return false; | |
442 | |
443 ListValue* list = NULL; | |
444 root_dictionary->GetList("entries", &list); | |
445 if (list == NULL) | |
446 return false; | |
447 | |
448 uint32 max_entry_id = 0; | |
449 for (size_t i = 0; i < list->GetSize(); ++i) { | |
450 DictionaryValue* list_item = NULL; | |
451 bool valid = list->GetDictionary(i, &list_item); | |
452 if (!valid) | |
453 break; | |
454 GpuBlacklistEntry* entry = | |
455 GpuBlacklistEntry::GetGpuBlacklistEntryFromValue(list_item); | |
456 if (entry == NULL) | |
457 break; | |
458 if (entry->id() > max_entry_id) | |
459 max_entry_id = entry->id(); | |
460 entries.push_back(entry); | |
461 } | |
462 | |
463 if (entries.size() < list->GetSize()) { | |
464 for (size_t i = 0; i < entries.size(); ++i) | |
465 delete entries[i]; | |
466 return false; | |
467 } | |
468 | |
469 Clear(); | |
470 // Don't apply GPU blacklist for a non-registered OS. | |
471 OsType os_filter = GetOsType(); | |
472 if (os_filter != kOsUnknown) { | |
473 for (size_t i = 0; i < entries.size(); ++i) { | |
474 OsType entry_os = entries[i]->GetOsType(); | |
475 if (!current_os_only || | |
476 entry_os == kOsAny || entry_os == os_filter) | |
477 blacklist_.push_back(entries[i]); | |
478 else | |
479 delete entries[i]; | |
480 } | |
481 } | |
482 max_entry_id_ = max_entry_id; | |
483 return true; | |
484 } | |
485 | |
486 GpuFeatureFlags GpuBlacklist::DetermineGpuFeatureFlags( | |
487 GpuBlacklist::OsType os, | |
488 Version* os_version, | |
489 const GPUInfo& gpu_info) { | |
490 active_entries_.clear(); | |
491 GpuFeatureFlags flags; | |
492 // No need to go through blacklist entries if GPUInfo isn't available. | |
493 if (gpu_info.level() == GPUInfo::kUninitialized) | |
494 return flags; | |
495 | |
496 if (os == kOsAny) | |
497 os = GetOsType(); | |
498 scoped_ptr<Version> my_os_version; | |
499 if (os_version == NULL) { | |
500 std::string version_string; | |
501 #if defined(OS_MACOSX) | |
502 // Seems like base::SysInfo::OperatingSystemVersion() returns the wrong | |
503 // version in MacOsx. | |
504 int32 version_major, version_minor, version_bugfix; | |
505 base::SysInfo::OperatingSystemVersionNumbers( | |
506 &version_major, &version_minor, &version_bugfix); | |
507 version_string = base::StringPrintf("%d.%d.%d", | |
508 version_major, | |
509 version_minor, | |
510 version_bugfix); | |
511 #else | |
512 version_string = base::SysInfo::OperatingSystemVersion(); | |
513 size_t pos = version_string.find_first_not_of("0123456789."); | |
514 if (pos != std::string::npos) | |
515 version_string = version_string.substr(0, pos); | |
516 #endif | |
517 my_os_version.reset(Version::GetVersionFromString(version_string)); | |
518 os_version = my_os_version.get(); | |
519 } | |
520 DCHECK(os_version != NULL); | |
521 | |
522 for (size_t i = 0; i < blacklist_.size(); ++i) { | |
523 if (blacklist_[i]->Contains(os, *os_version, gpu_info)) { | |
524 flags.Combine(blacklist_[i]->GetGpuFeatureFlags()); | |
525 active_entries_.push_back(blacklist_[i]); | |
526 } | |
527 } | |
528 return flags; | |
529 } | |
530 | |
531 void GpuBlacklist::GetGpuFeatureFlagEntries( | |
532 GpuFeatureFlags::GpuFeatureType feature, | |
533 std::vector<uint32>& entry_ids) const { | |
534 entry_ids.clear(); | |
535 for (size_t i = 0; i < active_entries_.size(); ++i) { | |
536 if ((feature & active_entries_[i]->GetGpuFeatureFlags().flags()) != 0) | |
537 entry_ids.push_back(active_entries_[i]->id()); | |
538 } | |
539 } | |
540 | |
541 uint32 GpuBlacklist::max_entry_id() const { | |
542 return max_entry_id_; | |
543 } | |
544 | |
545 bool GpuBlacklist::GetVersion(uint16* major, uint16* minor) const { | |
546 DCHECK(major && minor); | |
547 *major = 0; | |
548 *minor = 0; | |
549 if (version_.get() == NULL) | |
550 return false; | |
551 const std::vector<uint16>& components_reference = version_->components(); | |
552 if (components_reference.size() != 2) | |
553 return false; | |
554 *major = components_reference[0]; | |
555 *minor = components_reference[1]; | |
556 return true; | |
557 } | |
558 | |
559 GpuBlacklist::OsType GpuBlacklist::GetOsType() { | |
560 #if defined(OS_WIN) | |
561 return kOsWin; | |
562 #elif defined(OS_LINUX) | |
563 return kOsLinux; | |
564 #elif defined(OS_MACOSX) | |
565 return kOsMacosx; | |
566 #else | |
567 return kOsUnknown; | |
568 #endif | |
569 } | |
570 | |
571 void GpuBlacklist::Clear() { | |
572 for (size_t i = 0; i < blacklist_.size(); ++i) | |
573 delete blacklist_[i]; | |
574 blacklist_.clear(); | |
575 active_entries_.clear(); | |
576 } | |
577 | |
OLD | NEW |