Bumping manifests a=b2g-bump
[gecko.git] / widget / xpwidgets / GfxInfoBase.cpp
blob1ce88da2cbf5e16d29763d602b7fd5e81d111806
1 /* vim: se cin sw=2 ts=2 et : */
2 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "mozilla/ArrayUtils.h"
10 #include "GfxInfoBase.h"
12 #include "GfxInfoWebGL.h"
13 #include "GfxDriverInfo.h"
14 #include "nsCOMPtr.h"
15 #include "nsCOMArray.h"
16 #include "nsAutoPtr.h"
17 #include "nsString.h"
18 #include "nsUnicharUtils.h"
19 #include "mozilla/Services.h"
20 #include "mozilla/Observer.h"
21 #include "nsIObserver.h"
22 #include "nsIObserverService.h"
23 #include "nsIDOMElement.h"
24 #include "nsIDOMHTMLCollection.h"
25 #include "nsIDOMNode.h"
26 #include "nsIDOMNodeList.h"
27 #include "nsTArray.h"
28 #include "nsXULAppAPI.h"
29 #include "mozilla/Preferences.h"
30 #include "mozilla/dom/ContentChild.h"
32 #if defined(MOZ_CRASHREPORTER)
33 #include "nsExceptionHandler.h"
34 #endif
36 using namespace mozilla::widget;
37 using namespace mozilla;
38 using mozilla::MutexAutoLock;
40 nsTArray<GfxDriverInfo>* GfxInfoBase::mDriverInfo;
41 bool GfxInfoBase::mDriverInfoObserverInitialized;
43 // Observes for shutdown so that the child GfxDriverInfo list is freed.
44 class ShutdownObserver : public nsIObserver
46 virtual ~ShutdownObserver() {}
48 public:
49 ShutdownObserver() {}
51 NS_DECL_ISUPPORTS
53 NS_IMETHOD Observe(nsISupports *subject, const char *aTopic,
54 const char16_t *aData)
56 MOZ_ASSERT(strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0);
58 delete GfxInfoBase::mDriverInfo;
59 GfxInfoBase::mDriverInfo = nullptr;
61 for (uint32_t i = 0; i < DeviceFamilyMax; i++)
62 delete GfxDriverInfo::mDeviceFamilies[i];
64 for (uint32_t i = 0; i < DeviceVendorMax; i++)
65 delete GfxDriverInfo::mDeviceVendors[i];
67 return NS_OK;
71 NS_IMPL_ISUPPORTS(ShutdownObserver, nsIObserver)
73 void InitGfxDriverInfoShutdownObserver()
75 if (GfxInfoBase::mDriverInfoObserverInitialized)
76 return;
78 GfxInfoBase::mDriverInfoObserverInitialized = true;
80 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
81 if (!observerService) {
82 NS_WARNING("Could not get observer service!");
83 return;
86 ShutdownObserver *obs = new ShutdownObserver();
87 observerService->AddObserver(obs, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
90 using namespace mozilla::widget;
91 using namespace mozilla;
93 NS_IMPL_ISUPPORTS(GfxInfoBase, nsIGfxInfo, nsIObserver, nsISupportsWeakReference)
95 #define BLACKLIST_PREF_BRANCH "gfx.blacklist."
96 #define SUGGESTED_VERSION_PREF BLACKLIST_PREF_BRANCH "suggested-driver-version"
97 #define BLACKLIST_ENTRY_TAG_NAME "gfxBlacklistEntry"
99 static const char*
100 GetPrefNameForFeature(int32_t aFeature)
102 const char* name = nullptr;
103 switch(aFeature) {
104 case nsIGfxInfo::FEATURE_DIRECT2D:
105 name = BLACKLIST_PREF_BRANCH "direct2d";
106 break;
107 case nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS:
108 name = BLACKLIST_PREF_BRANCH "layers.direct3d9";
109 break;
110 case nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS:
111 name = BLACKLIST_PREF_BRANCH "layers.direct3d10";
112 break;
113 case nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS:
114 name = BLACKLIST_PREF_BRANCH "layers.direct3d10-1";
115 break;
116 case nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS:
117 name = BLACKLIST_PREF_BRANCH "layers.direct3d11";
118 break;
119 case nsIGfxInfo::FEATURE_OPENGL_LAYERS:
120 name = BLACKLIST_PREF_BRANCH "layers.opengl";
121 break;
122 case nsIGfxInfo::FEATURE_WEBGL_OPENGL:
123 name = BLACKLIST_PREF_BRANCH "webgl.opengl";
124 break;
125 case nsIGfxInfo::FEATURE_WEBGL_ANGLE:
126 name = BLACKLIST_PREF_BRANCH "webgl.angle";
127 break;
128 case nsIGfxInfo::FEATURE_WEBGL_MSAA:
129 name = BLACKLIST_PREF_BRANCH "webgl.msaa";
130 break;
131 case nsIGfxInfo::FEATURE_STAGEFRIGHT:
132 name = BLACKLIST_PREF_BRANCH "stagefright";
133 break;
134 default:
135 break;
138 return name;
141 // Returns the value of the pref for the relevant feature in aValue.
142 // If the pref doesn't exist, aValue is not touched, and returns false.
143 static bool
144 GetPrefValueForFeature(int32_t aFeature, int32_t& aValue)
146 const char *prefname = GetPrefNameForFeature(aFeature);
147 if (!prefname)
148 return false;
150 aValue = false;
151 return NS_SUCCEEDED(Preferences::GetInt(prefname, &aValue));
154 static void
155 SetPrefValueForFeature(int32_t aFeature, int32_t aValue)
157 const char *prefname = GetPrefNameForFeature(aFeature);
158 if (!prefname)
159 return;
161 Preferences::SetInt(prefname, aValue);
164 static void
165 RemovePrefForFeature(int32_t aFeature)
167 const char *prefname = GetPrefNameForFeature(aFeature);
168 if (!prefname)
169 return;
171 Preferences::ClearUser(prefname);
174 static bool
175 GetPrefValueForDriverVersion(nsCString& aVersion)
177 return NS_SUCCEEDED(Preferences::GetCString(SUGGESTED_VERSION_PREF,
178 &aVersion));
181 static void
182 SetPrefValueForDriverVersion(const nsAString& aVersion)
184 Preferences::SetString(SUGGESTED_VERSION_PREF, aVersion);
187 static void
188 RemovePrefForDriverVersion()
190 Preferences::ClearUser(SUGGESTED_VERSION_PREF);
193 // <foo>Hello</foo> - "Hello" is stored as a child text node of the foo node.
194 static bool
195 BlacklistNodeToTextValue(nsIDOMNode *aBlacklistNode, nsAString& aValue)
197 nsAutoString value;
198 if (NS_FAILED(aBlacklistNode->GetTextContent(value)))
199 return false;
201 value.Trim(" \t\r\n");
202 aValue = value;
204 return true;
207 static OperatingSystem
208 BlacklistOSToOperatingSystem(const nsAString& os)
210 if (os.EqualsLiteral("WINNT 5.1"))
211 return DRIVER_OS_WINDOWS_XP;
212 else if (os.EqualsLiteral("WINNT 5.2"))
213 return DRIVER_OS_WINDOWS_SERVER_2003;
214 else if (os.EqualsLiteral("WINNT 6.0"))
215 return DRIVER_OS_WINDOWS_VISTA;
216 else if (os.EqualsLiteral("WINNT 6.1"))
217 return DRIVER_OS_WINDOWS_7;
218 else if (os.EqualsLiteral("WINNT 6.2"))
219 return DRIVER_OS_WINDOWS_8;
220 else if (os.EqualsLiteral("WINNT 6.3"))
221 return DRIVER_OS_WINDOWS_8_1;
222 else if (os.EqualsLiteral("Linux"))
223 return DRIVER_OS_LINUX;
224 else if (os.EqualsLiteral("Darwin 9"))
225 return DRIVER_OS_OS_X_10_5;
226 else if (os.EqualsLiteral("Darwin 10"))
227 return DRIVER_OS_OS_X_10_6;
228 else if (os.EqualsLiteral("Darwin 11"))
229 return DRIVER_OS_OS_X_10_7;
230 else if (os.EqualsLiteral("Darwin 12"))
231 return DRIVER_OS_OS_X_10_8;
232 else if (os.EqualsLiteral("Android"))
233 return DRIVER_OS_ANDROID;
234 else if (os.EqualsLiteral("All"))
235 return DRIVER_OS_ALL;
237 return DRIVER_OS_UNKNOWN;
240 static GfxDeviceFamily*
241 BlacklistDevicesToDeviceFamily(nsIDOMHTMLCollection* aDevices)
243 uint32_t length;
244 if (NS_FAILED(aDevices->GetLength(&length)))
245 return nullptr;
247 // For each <device>, get its device ID, and return a freshly-allocated
248 // GfxDeviceFamily with the contents of that array.
249 GfxDeviceFamily* deviceIds = new GfxDeviceFamily;
251 for (uint32_t i = 0; i < length; ++i) {
252 nsCOMPtr<nsIDOMNode> node;
253 if (NS_FAILED(aDevices->Item(i, getter_AddRefs(node))) || !node)
254 continue;
256 nsAutoString deviceValue;
257 if (!BlacklistNodeToTextValue(node, deviceValue))
258 continue;
260 deviceIds->AppendElement(deviceValue);
263 return deviceIds;
266 static int32_t
267 BlacklistFeatureToGfxFeature(const nsAString& aFeature)
269 if (aFeature.EqualsLiteral("DIRECT2D"))
270 return nsIGfxInfo::FEATURE_DIRECT2D;
271 else if (aFeature.EqualsLiteral("DIRECT3D_9_LAYERS"))
272 return nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS;
273 else if (aFeature.EqualsLiteral("DIRECT3D_10_LAYERS"))
274 return nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS;
275 else if (aFeature.EqualsLiteral("DIRECT3D_10_1_LAYERS"))
276 return nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS;
277 else if (aFeature.EqualsLiteral("DIRECT3D_11_LAYERS"))
278 return nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS;
279 else if (aFeature.EqualsLiteral("OPENGL_LAYERS"))
280 return nsIGfxInfo::FEATURE_OPENGL_LAYERS;
281 else if (aFeature.EqualsLiteral("WEBGL_OPENGL"))
282 return nsIGfxInfo::FEATURE_WEBGL_OPENGL;
283 else if (aFeature.EqualsLiteral("WEBGL_ANGLE"))
284 return nsIGfxInfo::FEATURE_WEBGL_ANGLE;
285 else if (aFeature.EqualsLiteral("WEBGL_MSAA"))
286 return nsIGfxInfo::FEATURE_WEBGL_MSAA;
287 else if (aFeature.EqualsLiteral("STAGEFRIGHT"))
288 return nsIGfxInfo::FEATURE_STAGEFRIGHT;
289 return 0;
292 static int32_t
293 BlacklistFeatureStatusToGfxFeatureStatus(const nsAString& aStatus)
295 if (aStatus.EqualsLiteral("STATUS_OK"))
296 return nsIGfxInfo::FEATURE_STATUS_OK;
297 else if (aStatus.EqualsLiteral("BLOCKED_DRIVER_VERSION"))
298 return nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION;
299 else if (aStatus.EqualsLiteral("BLOCKED_DEVICE"))
300 return nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
301 else if (aStatus.EqualsLiteral("DISCOURAGED"))
302 return nsIGfxInfo::FEATURE_DISCOURAGED;
303 else if (aStatus.EqualsLiteral("BLOCKED_OS_VERSION"))
304 return nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION;
306 // Do not allow it to set STATUS_UNKNOWN.
308 return nsIGfxInfo::FEATURE_STATUS_OK;
311 static VersionComparisonOp
312 BlacklistComparatorToComparisonOp(const nsAString& op)
314 if (op.EqualsLiteral("LESS_THAN"))
315 return DRIVER_LESS_THAN;
316 else if (op.EqualsLiteral("LESS_THAN_OR_EQUAL"))
317 return DRIVER_LESS_THAN_OR_EQUAL;
318 else if (op.EqualsLiteral("GREATER_THAN"))
319 return DRIVER_GREATER_THAN;
320 else if (op.EqualsLiteral("GREATER_THAN_OR_EQUAL"))
321 return DRIVER_GREATER_THAN_OR_EQUAL;
322 else if (op.EqualsLiteral("EQUAL"))
323 return DRIVER_EQUAL;
324 else if (op.EqualsLiteral("NOT_EQUAL"))
325 return DRIVER_NOT_EQUAL;
326 else if (op.EqualsLiteral("BETWEEN_EXCLUSIVE"))
327 return DRIVER_BETWEEN_EXCLUSIVE;
328 else if (op.EqualsLiteral("BETWEEN_INCLUSIVE"))
329 return DRIVER_BETWEEN_INCLUSIVE;
330 else if (op.EqualsLiteral("BETWEEN_INCLUSIVE_START"))
331 return DRIVER_BETWEEN_INCLUSIVE_START;
333 return DRIVER_COMPARISON_IGNORED;
336 // Arbitrarily returns the first |tagname| child of |element|.
337 static bool
338 BlacklistNodeGetChildByName(nsIDOMElement *element,
339 const nsAString& tagname,
340 nsIDOMNode** firstchild)
342 nsCOMPtr<nsIDOMHTMLCollection> nodelist;
343 if (NS_FAILED(element->GetElementsByTagName(tagname,
344 getter_AddRefs(nodelist))) ||
345 !nodelist) {
346 return false;
349 nsCOMPtr<nsIDOMNode> node;
350 if (NS_FAILED(nodelist->Item(0, getter_AddRefs(node))) || !node)
351 return false;
353 node.forget(firstchild);
354 return true;
359 <gfxBlacklistEntry>
360 <os>WINNT 6.0</os>
361 <vendor>0x8086</vendor>
362 <devices>
363 <device>0x2582</device>
364 <device>0x2782</device>
365 </devices>
366 <feature> DIRECT3D_10_LAYERS </feature>
367 <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
368 <driverVersion> 8.52.322.2202 </driverVersion>
369 <driverVersionComparator> LESS_THAN_OR_EQUAL </driverVersionComparator>
370 </gfxBlacklistEntry>
373 static bool
374 BlacklistEntryToDriverInfo(nsIDOMNode* aBlacklistEntry,
375 GfxDriverInfo& aDriverInfo)
377 nsAutoString nodename;
378 if (NS_FAILED(aBlacklistEntry->GetNodeName(nodename)) ||
379 nodename != NS_LITERAL_STRING(BLACKLIST_ENTRY_TAG_NAME)) {
380 return false;
383 nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aBlacklistEntry);
384 if (!element)
385 return false;
387 nsCOMPtr<nsIDOMNode> dataNode;
388 nsAutoString dataValue;
390 // <os>WINNT 6.0</os>
391 if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("os"),
392 getter_AddRefs(dataNode))) {
393 BlacklistNodeToTextValue(dataNode, dataValue);
394 aDriverInfo.mOperatingSystem = BlacklistOSToOperatingSystem(dataValue);
397 // <osversion>14</osversion> currently only used for Android
398 if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("osversion"),
399 getter_AddRefs(dataNode))) {
400 BlacklistNodeToTextValue(dataNode, dataValue);
401 aDriverInfo.mOperatingSystemVersion = strtoul(NS_LossyConvertUTF16toASCII(dataValue).get(),
402 nullptr, 10);
405 // <vendor>0x8086</vendor>
406 if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("vendor"),
407 getter_AddRefs(dataNode))) {
408 BlacklistNodeToTextValue(dataNode, dataValue);
409 aDriverInfo.mAdapterVendor = dataValue;
412 // <devices>
413 // <device>0x2582</device>
414 // <device>0x2782</device>
415 // </devices>
416 if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("devices"),
417 getter_AddRefs(dataNode))) {
418 nsCOMPtr<nsIDOMElement> devicesElement = do_QueryInterface(dataNode);
419 if (devicesElement) {
421 // Get only the <device> nodes, because BlacklistDevicesToDeviceFamily
422 // assumes it is passed no other nodes.
423 nsCOMPtr<nsIDOMHTMLCollection> devices;
424 if (NS_SUCCEEDED(devicesElement->GetElementsByTagName(NS_LITERAL_STRING("device"),
425 getter_AddRefs(devices)))) {
426 GfxDeviceFamily* deviceIds = BlacklistDevicesToDeviceFamily(devices);
427 if (deviceIds) {
428 // Get GfxDriverInfo to adopt the devices array we created.
429 aDriverInfo.mDeleteDevices = true;
430 aDriverInfo.mDevices = deviceIds;
436 // <feature> DIRECT3D_10_LAYERS </feature>
437 if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("feature"),
438 getter_AddRefs(dataNode))) {
439 BlacklistNodeToTextValue(dataNode, dataValue);
440 aDriverInfo.mFeature = BlacklistFeatureToGfxFeature(dataValue);
443 // <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
444 if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("featureStatus"),
445 getter_AddRefs(dataNode))) {
446 BlacklistNodeToTextValue(dataNode, dataValue);
447 aDriverInfo.mFeatureStatus = BlacklistFeatureStatusToGfxFeatureStatus(dataValue);
450 // <driverVersion> 8.52.322.2202 </driverVersion>
451 if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("driverVersion"),
452 getter_AddRefs(dataNode))) {
453 BlacklistNodeToTextValue(dataNode, dataValue);
454 uint64_t version;
455 if (ParseDriverVersion(dataValue, &version))
456 aDriverInfo.mDriverVersion = version;
459 // <driverVersionComparator> LESS_THAN_OR_EQUAL </driverVersionComparator>
460 if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("driverVersionComparator"),
461 getter_AddRefs(dataNode))) {
462 BlacklistNodeToTextValue(dataNode, dataValue);
463 aDriverInfo.mComparisonOp = BlacklistComparatorToComparisonOp(dataValue);
466 // <model>foo</model>
467 if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("model"),
468 getter_AddRefs(dataNode))) {
469 BlacklistNodeToTextValue(dataNode, dataValue);
470 aDriverInfo.mModel = dataValue;
472 // <product>foo</product>
473 if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("product"),
474 getter_AddRefs(dataNode))) {
475 BlacklistNodeToTextValue(dataNode, dataValue);
476 aDriverInfo.mProduct = dataValue;
478 // <manufacturer>foo</manufacturer>
479 if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("manufacturer"),
480 getter_AddRefs(dataNode))) {
481 BlacklistNodeToTextValue(dataNode, dataValue);
482 aDriverInfo.mManufacturer = dataValue;
484 // <hardware>foo</hardware>
485 if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("hardware"),
486 getter_AddRefs(dataNode))) {
487 BlacklistNodeToTextValue(dataNode, dataValue);
488 aDriverInfo.mHardware = dataValue;
491 // We explicitly ignore unknown elements.
493 return true;
496 static void
497 BlacklistEntriesToDriverInfo(nsIDOMHTMLCollection* aBlacklistEntries,
498 nsTArray<GfxDriverInfo>& aDriverInfo)
500 uint32_t length;
501 if (NS_FAILED(aBlacklistEntries->GetLength(&length)))
502 return;
504 aDriverInfo.Clear();
505 aDriverInfo.SetLength(length);
506 for (uint32_t i = 0; i < length; ++i) {
507 nsCOMPtr<nsIDOMNode> blacklistEntry;
508 if (NS_SUCCEEDED(aBlacklistEntries->Item(i,
509 getter_AddRefs(blacklistEntry))) &&
510 blacklistEntry) {
511 GfxDriverInfo di;
512 if (BlacklistEntryToDriverInfo(blacklistEntry, di)) {
513 aDriverInfo[i] = di;
515 // Prevent di falling out of scope from destroying the devices.
516 di.mDeleteDevices = false;
521 NS_IMETHODIMP
522 GfxInfoBase::Observe(nsISupports* aSubject, const char* aTopic,
523 const char16_t* aData)
525 if (strcmp(aTopic, "blocklist-data-gfxItems") == 0) {
526 nsCOMPtr<nsIDOMElement> gfxItems = do_QueryInterface(aSubject);
527 if (gfxItems) {
528 nsCOMPtr<nsIDOMHTMLCollection> blacklistEntries;
529 if (NS_SUCCEEDED(gfxItems->
530 GetElementsByTagName(NS_LITERAL_STRING(BLACKLIST_ENTRY_TAG_NAME),
531 getter_AddRefs(blacklistEntries))) &&
532 blacklistEntries)
534 nsTArray<GfxDriverInfo> driverInfo;
535 BlacklistEntriesToDriverInfo(blacklistEntries, driverInfo);
536 EvaluateDownloadedBlacklist(driverInfo);
541 return NS_OK;
544 GfxInfoBase::GfxInfoBase()
545 : mFailureCount(0)
546 , mMutex("GfxInfoBase")
550 GfxInfoBase::~GfxInfoBase()
554 nsresult
555 GfxInfoBase::Init()
557 InitGfxDriverInfoShutdownObserver();
559 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
560 if (os) {
561 os->AddObserver(this, "blocklist-data-gfxItems", true);
564 return NS_OK;
567 NS_IMETHODIMP
568 GfxInfoBase::GetFeatureStatus(int32_t aFeature, int32_t* aStatus)
570 if (GetPrefValueForFeature(aFeature, *aStatus))
571 return NS_OK;
573 if (XRE_GetProcessType() == GeckoProcessType_Content) {
574 // Delegate to the parent process.
575 mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton();
576 bool success;
577 cc->SendGetGraphicsFeatureStatus(aFeature, aStatus, &success);
578 return success ? NS_OK : NS_ERROR_FAILURE;
581 nsString version;
582 nsTArray<GfxDriverInfo> driverInfo;
583 return GetFeatureStatusImpl(aFeature, aStatus, version, driverInfo);
586 int32_t
587 GfxInfoBase::FindBlocklistedDeviceInList(const nsTArray<GfxDriverInfo>& info,
588 nsAString& aSuggestedVersion,
589 int32_t aFeature,
590 OperatingSystem os)
592 int32_t status = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
594 nsAutoString adapterVendorID;
595 nsAutoString adapterDeviceID;
596 nsAutoString adapterDriverVersionString;
597 if (NS_FAILED(GetAdapterVendorID(adapterVendorID)) ||
598 NS_FAILED(GetAdapterDeviceID(adapterDeviceID)) ||
599 NS_FAILED(GetAdapterDriverVersion(adapterDriverVersionString)))
601 return 0;
604 #if defined(XP_WIN) || defined(ANDROID)
605 uint64_t driverVersion;
606 ParseDriverVersion(adapterDriverVersionString, &driverVersion);
607 #endif
609 uint32_t i = 0;
610 for (; i < info.Length(); i++) {
611 if (info[i].mOperatingSystem != DRIVER_OS_ALL &&
612 info[i].mOperatingSystem != os)
614 continue;
617 if (info[i].mOperatingSystemVersion && info[i].mOperatingSystemVersion != OperatingSystemVersion()) {
618 continue;
621 if (!info[i].mAdapterVendor.Equals(GfxDriverInfo::GetDeviceVendor(VendorAll), nsCaseInsensitiveStringComparator()) &&
622 !info[i].mAdapterVendor.Equals(adapterVendorID, nsCaseInsensitiveStringComparator())) {
623 continue;
626 if (info[i].mDevices != GfxDriverInfo::allDevices && info[i].mDevices->Length()) {
627 bool deviceMatches = false;
628 for (uint32_t j = 0; j < info[i].mDevices->Length(); j++) {
629 if ((*info[i].mDevices)[j].Equals(adapterDeviceID, nsCaseInsensitiveStringComparator())) {
630 deviceMatches = true;
631 break;
635 if (!deviceMatches) {
636 continue;
640 bool match = false;
642 if (!info[i].mHardware.IsEmpty() && !info[i].mHardware.Equals(Hardware())) {
643 continue;
645 if (!info[i].mModel.IsEmpty() && !info[i].mModel.Equals(Model())) {
646 continue;
648 if (!info[i].mProduct.IsEmpty() && !info[i].mProduct.Equals(Product())) {
649 continue;
651 if (!info[i].mManufacturer.IsEmpty() && !info[i].mManufacturer.Equals(Manufacturer())) {
652 continue;
655 #if defined(XP_WIN) || defined(ANDROID)
656 switch (info[i].mComparisonOp) {
657 case DRIVER_LESS_THAN:
658 match = driverVersion < info[i].mDriverVersion;
659 break;
660 case DRIVER_LESS_THAN_OR_EQUAL:
661 match = driverVersion <= info[i].mDriverVersion;
662 break;
663 case DRIVER_GREATER_THAN:
664 match = driverVersion > info[i].mDriverVersion;
665 break;
666 case DRIVER_GREATER_THAN_OR_EQUAL:
667 match = driverVersion >= info[i].mDriverVersion;
668 break;
669 case DRIVER_EQUAL:
670 match = driverVersion == info[i].mDriverVersion;
671 break;
672 case DRIVER_NOT_EQUAL:
673 match = driverVersion != info[i].mDriverVersion;
674 break;
675 case DRIVER_BETWEEN_EXCLUSIVE:
676 match = driverVersion > info[i].mDriverVersion && driverVersion < info[i].mDriverVersionMax;
677 break;
678 case DRIVER_BETWEEN_INCLUSIVE:
679 match = driverVersion >= info[i].mDriverVersion && driverVersion <= info[i].mDriverVersionMax;
680 break;
681 case DRIVER_BETWEEN_INCLUSIVE_START:
682 match = driverVersion >= info[i].mDriverVersion && driverVersion < info[i].mDriverVersionMax;
683 break;
684 case DRIVER_COMPARISON_IGNORED:
685 // We don't have a comparison op, so we match everything.
686 match = true;
687 break;
688 default:
689 NS_WARNING("Bogus op in GfxDriverInfo");
690 break;
692 #else
693 // We don't care what driver version it was. We only check OS version and if
694 // the device matches.
695 match = true;
696 #endif
698 if (match || info[i].mDriverVersion == GfxDriverInfo::allDriverVersions) {
699 if (info[i].mFeature == GfxDriverInfo::allFeatures ||
700 info[i].mFeature == aFeature)
702 status = info[i].mFeatureStatus;
703 break;
708 #if defined(XP_WIN)
709 // As a very special case, we block D2D on machines with an NVidia 310M GPU
710 // as either the primary or secondary adapter. D2D is also blocked when the
711 // NV 310M is the primary adapter (using the standard blocklisting mechanism).
712 // If the primary GPU already matched something in the blocklist then we
713 // ignore this special rule. See bug 1008759.
714 if (status == nsIGfxInfo::FEATURE_STATUS_UNKNOWN &&
715 (aFeature == nsIGfxInfo::FEATURE_DIRECT2D)) {
716 nsAutoString adapterVendorID2;
717 nsAutoString adapterDeviceID2;
718 if ((!NS_FAILED(GetAdapterVendorID2(adapterVendorID2))) &&
719 (!NS_FAILED(GetAdapterDeviceID2(adapterDeviceID2))))
721 nsAString &nvVendorID = (nsAString &)GfxDriverInfo::GetDeviceVendor(VendorNVIDIA);
722 const nsString nv310mDeviceId = NS_LITERAL_STRING("0x0A70");
723 if (nvVendorID.Equals(adapterVendorID2, nsCaseInsensitiveStringComparator()) &&
724 nv310mDeviceId.Equals(adapterDeviceID2, nsCaseInsensitiveStringComparator())) {
725 status = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
730 // Depends on Windows driver versioning. We don't pass a GfxDriverInfo object
731 // back to the Windows handler, so we must handle this here.
732 if (status == FEATURE_BLOCKED_DRIVER_VERSION) {
733 if (info[i].mSuggestedVersion) {
734 aSuggestedVersion.AppendPrintf("%s", info[i].mSuggestedVersion);
735 } else if (info[i].mComparisonOp == DRIVER_LESS_THAN &&
736 info[i].mDriverVersion != GfxDriverInfo::allDriverVersions)
738 aSuggestedVersion.AppendPrintf("%lld.%lld.%lld.%lld",
739 (info[i].mDriverVersion & 0xffff000000000000) >> 48,
740 (info[i].mDriverVersion & 0x0000ffff00000000) >> 32,
741 (info[i].mDriverVersion & 0x00000000ffff0000) >> 16,
742 (info[i].mDriverVersion & 0x000000000000ffff));
745 #endif
747 return status;
750 nsresult
751 GfxInfoBase::GetFeatureStatusImpl(int32_t aFeature,
752 int32_t* aStatus,
753 nsAString& aSuggestedVersion,
754 const nsTArray<GfxDriverInfo>& aDriverInfo,
755 OperatingSystem* aOS /* = nullptr */)
757 if (*aStatus != nsIGfxInfo::FEATURE_STATUS_UNKNOWN) {
758 // Terminate now with the status determined by the derived type (OS-specific
759 // code).
760 return NS_OK;
763 // If an operating system was provided by the derived GetFeatureStatusImpl,
764 // grab it here. Otherwise, the OS is unknown.
765 OperatingSystem os = DRIVER_OS_UNKNOWN;
766 if (aOS)
767 os = *aOS;
769 nsAutoString adapterVendorID;
770 nsAutoString adapterDeviceID;
771 nsAutoString adapterDriverVersionString;
772 if (NS_FAILED(GetAdapterVendorID(adapterVendorID)) ||
773 NS_FAILED(GetAdapterDeviceID(adapterDeviceID)) ||
774 NS_FAILED(GetAdapterDriverVersion(adapterDriverVersionString)))
776 return NS_OK;
779 // Check if the device is blocked from the downloaded blocklist. If not, check
780 // the static list after that. This order is used so that we can later escape
781 // out of static blocks (i.e. if we were wrong or something was patched, we
782 // can back out our static block without doing a release).
783 int32_t status;
784 if (aDriverInfo.Length()) {
785 status = FindBlocklistedDeviceInList(aDriverInfo, aSuggestedVersion, aFeature, os);
786 } else {
787 if (!mDriverInfo) {
788 mDriverInfo = new nsTArray<GfxDriverInfo>();
790 status = FindBlocklistedDeviceInList(GetGfxDriverInfo(), aSuggestedVersion, aFeature, os);
793 // It's now done being processed. It's safe to set the status to STATUS_OK.
794 if (status == nsIGfxInfo::FEATURE_STATUS_UNKNOWN) {
795 *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
796 } else {
797 *aStatus = status;
800 return NS_OK;
803 NS_IMETHODIMP
804 GfxInfoBase::GetFeatureSuggestedDriverVersion(int32_t aFeature,
805 nsAString& aVersion)
807 nsCString version;
808 if (GetPrefValueForDriverVersion(version)) {
809 aVersion = NS_ConvertASCIItoUTF16(version);
810 return NS_OK;
813 int32_t status;
814 nsTArray<GfxDriverInfo> driverInfo;
815 return GetFeatureStatusImpl(aFeature, &status, aVersion, driverInfo);
819 NS_IMETHODIMP
820 GfxInfoBase::GetWebGLParameter(const nsAString& aParam,
821 nsAString& aResult)
823 return GfxInfoWebGL::GetWebGLParameter(aParam, aResult);
826 void
827 GfxInfoBase::EvaluateDownloadedBlacklist(nsTArray<GfxDriverInfo>& aDriverInfo)
829 int32_t features[] = {
830 nsIGfxInfo::FEATURE_DIRECT2D,
831 nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS,
832 nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS,
833 nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS,
834 nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS,
835 nsIGfxInfo::FEATURE_OPENGL_LAYERS,
836 nsIGfxInfo::FEATURE_WEBGL_OPENGL,
837 nsIGfxInfo::FEATURE_WEBGL_ANGLE,
838 nsIGfxInfo::FEATURE_WEBGL_MSAA,
839 nsIGfxInfo::FEATURE_STAGEFRIGHT,
843 // For every feature we know about, we evaluate whether this blacklist has a
844 // non-STATUS_OK status. If it does, we set the pref we evaluate in
845 // GetFeatureStatus above, so we don't need to hold on to this blacklist
846 // anywhere permanent.
847 int i = 0;
848 while (features[i]) {
849 int32_t status;
850 nsAutoString suggestedVersion;
851 if (NS_SUCCEEDED(GetFeatureStatusImpl(features[i], &status,
852 suggestedVersion,
853 aDriverInfo))) {
854 switch (status) {
855 default:
856 case nsIGfxInfo::FEATURE_STATUS_OK:
857 RemovePrefForFeature(features[i]);
858 break;
860 case nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION:
861 if (!suggestedVersion.IsEmpty()) {
862 SetPrefValueForDriverVersion(suggestedVersion);
863 } else {
864 RemovePrefForDriverVersion();
866 // FALLTHROUGH
868 case nsIGfxInfo::FEATURE_BLOCKED_DEVICE:
869 case nsIGfxInfo::FEATURE_DISCOURAGED:
870 case nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION:
871 SetPrefValueForFeature(features[i], status);
872 break;
876 ++i;
880 NS_IMETHODIMP_(void)
881 GfxInfoBase::LogFailure(const nsACString &failure)
883 MutexAutoLock lock(mMutex);
884 /* We only keep the first 9 failures */
885 if (mFailureCount < ArrayLength(mFailures)) {
886 mFailures[mFailureCount++] = failure;
888 /* record it in the crash notes too */
889 #if defined(MOZ_CRASHREPORTER)
890 CrashReporter::AppendAppNotesToCrashReport(failure);
891 #endif
896 /* void getFailures ([optional] out unsigned long failureCount, [array, size_is (failureCount), retval] out string failures); */
897 /* XPConnect method of returning arrays is very ugly. Would not recommend. Fallable nsMemory::Alloc makes things worse */
898 NS_IMETHODIMP GfxInfoBase::GetFailures(uint32_t *failureCount, char ***failures)
901 NS_ENSURE_ARG_POINTER(failureCount);
902 NS_ENSURE_ARG_POINTER(failures);
904 *failures = nullptr;
905 *failureCount = mFailureCount;
907 if (*failureCount != 0) {
908 *failures = (char**)nsMemory::Alloc(*failureCount * sizeof(char*));
909 if (!failures)
910 return NS_ERROR_OUT_OF_MEMORY;
912 /* copy over the failure messages into the array we just allocated */
913 for (uint32_t i = 0; i < *failureCount; i++) {
914 nsCString& flattenedFailureMessage(mFailures[i]);
915 (*failures)[i] = (char*)nsMemory::Clone(flattenedFailureMessage.get(), flattenedFailureMessage.Length() + 1);
917 if (!(*failures)[i]) {
918 /* <sarcasm> I'm too afraid to use an inline function... </sarcasm> */
919 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, (*failures));
920 return NS_ERROR_OUT_OF_MEMORY;
925 return NS_OK;
928 nsTArray<GfxInfoCollectorBase*> *sCollectors;
930 static void
931 InitCollectors()
933 if (!sCollectors)
934 sCollectors = new nsTArray<GfxInfoCollectorBase*>;
937 nsresult GfxInfoBase::GetInfo(JSContext* aCx, JS::MutableHandle<JS::Value> aResult)
939 InitCollectors();
940 InfoObject obj(aCx);
942 for (uint32_t i = 0; i < sCollectors->Length(); i++) {
943 (*sCollectors)[i]->GetInfo(obj);
946 // Some example property definitions
947 // obj.DefineProperty("wordCacheSize", gfxTextRunWordCache::Count());
948 // obj.DefineProperty("renderer", mRendererIDsString);
949 // obj.DefineProperty("five", 5);
951 if (!obj.mOk) {
952 return NS_ERROR_FAILURE;
955 aResult.setObject(*obj.mObj);
956 return NS_OK;
959 void
960 GfxInfoBase::AddCollector(GfxInfoCollectorBase* collector)
962 InitCollectors();
963 sCollectors->AppendElement(collector);
966 void
967 GfxInfoBase::RemoveCollector(GfxInfoCollectorBase* collector)
969 InitCollectors();
970 for (uint32_t i = 0; i < sCollectors->Length(); i++) {
971 if ((*sCollectors)[i] == collector) {
972 sCollectors->RemoveElementAt(i);
973 break;
976 if (sCollectors->IsEmpty()) {
977 delete sCollectors;
978 sCollectors = nullptr;
982 GfxInfoCollectorBase::GfxInfoCollectorBase()
984 GfxInfoBase::AddCollector(this);
987 GfxInfoCollectorBase::~GfxInfoCollectorBase()
989 GfxInfoBase::RemoveCollector(this);