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"
15 #include "nsCOMArray.h"
16 #include "nsAutoPtr.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"
28 #include "nsXULAppAPI.h"
29 #include "mozilla/Preferences.h"
30 #include "mozilla/dom/ContentChild.h"
32 #if defined(MOZ_CRASHREPORTER)
33 #include "nsExceptionHandler.h"
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() {}
53 NS_IMETHOD
Observe(nsISupports
*subject
, const char *aTopic
,
54 const char16_t
*aData
) MOZ_OVERRIDE
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
];
71 NS_IMPL_ISUPPORTS(ShutdownObserver
, nsIObserver
)
73 void InitGfxDriverInfoShutdownObserver()
75 if (GfxInfoBase::mDriverInfoObserverInitialized
)
78 GfxInfoBase::mDriverInfoObserverInitialized
= true;
80 nsCOMPtr
<nsIObserverService
> observerService
= services::GetObserverService();
81 if (!observerService
) {
82 NS_WARNING("Could not get observer service!");
86 ShutdownObserver
*obs
= new ShutdownObserver();
87 observerService
->AddObserver(obs
, NS_XPCOM_SHUTDOWN_OBSERVER_ID
, false);
90 using namespace mozilla::widget
;
91 using namespace mozilla
;
94 NS_IMPL_ISUPPORTS(GfxInfoBase
, nsIGfxInfo
, nsIGfxInfo2
, nsIObserver
, nsISupportsWeakReference
)
96 NS_IMPL_ISUPPORTS(GfxInfoBase
, nsIGfxInfo
, nsIObserver
, nsISupportsWeakReference
)
99 #define BLACKLIST_PREF_BRANCH "gfx.blacklist."
100 #define SUGGESTED_VERSION_PREF BLACKLIST_PREF_BRANCH "suggested-driver-version"
101 #define BLACKLIST_ENTRY_TAG_NAME "gfxBlacklistEntry"
104 GetPrefNameForFeature(int32_t aFeature
)
106 const char* name
= nullptr;
108 case nsIGfxInfo::FEATURE_DIRECT2D
:
109 name
= BLACKLIST_PREF_BRANCH
"direct2d";
111 case nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS
:
112 name
= BLACKLIST_PREF_BRANCH
"layers.direct3d9";
114 case nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS
:
115 name
= BLACKLIST_PREF_BRANCH
"layers.direct3d10";
117 case nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS
:
118 name
= BLACKLIST_PREF_BRANCH
"layers.direct3d10-1";
120 case nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS
:
121 name
= BLACKLIST_PREF_BRANCH
"layers.direct3d11";
123 case nsIGfxInfo::FEATURE_DXVA
:
124 name
= BLACKLIST_PREF_BRANCH
"dxva";
126 case nsIGfxInfo::FEATURE_OPENGL_LAYERS
:
127 name
= BLACKLIST_PREF_BRANCH
"layers.opengl";
129 case nsIGfxInfo::FEATURE_WEBGL_OPENGL
:
130 name
= BLACKLIST_PREF_BRANCH
"webgl.opengl";
132 case nsIGfxInfo::FEATURE_WEBGL_ANGLE
:
133 name
= BLACKLIST_PREF_BRANCH
"webgl.angle";
135 case nsIGfxInfo::FEATURE_WEBGL_MSAA
:
136 name
= BLACKLIST_PREF_BRANCH
"webgl.msaa";
138 case nsIGfxInfo::FEATURE_STAGEFRIGHT
:
139 name
= BLACKLIST_PREF_BRANCH
"stagefright";
148 // Returns the value of the pref for the relevant feature in aValue.
149 // If the pref doesn't exist, aValue is not touched, and returns false.
151 GetPrefValueForFeature(int32_t aFeature
, int32_t& aValue
)
153 const char *prefname
= GetPrefNameForFeature(aFeature
);
158 return NS_SUCCEEDED(Preferences::GetInt(prefname
, &aValue
));
162 SetPrefValueForFeature(int32_t aFeature
, int32_t aValue
)
164 const char *prefname
= GetPrefNameForFeature(aFeature
);
168 Preferences::SetInt(prefname
, aValue
);
172 RemovePrefForFeature(int32_t aFeature
)
174 const char *prefname
= GetPrefNameForFeature(aFeature
);
178 Preferences::ClearUser(prefname
);
182 GetPrefValueForDriverVersion(nsCString
& aVersion
)
184 return NS_SUCCEEDED(Preferences::GetCString(SUGGESTED_VERSION_PREF
,
189 SetPrefValueForDriverVersion(const nsAString
& aVersion
)
191 Preferences::SetString(SUGGESTED_VERSION_PREF
, aVersion
);
195 RemovePrefForDriverVersion()
197 Preferences::ClearUser(SUGGESTED_VERSION_PREF
);
200 // <foo>Hello</foo> - "Hello" is stored as a child text node of the foo node.
202 BlacklistNodeToTextValue(nsIDOMNode
*aBlacklistNode
, nsAString
& aValue
)
205 if (NS_FAILED(aBlacklistNode
->GetTextContent(value
)))
208 value
.Trim(" \t\r\n");
214 static OperatingSystem
215 BlacklistOSToOperatingSystem(const nsAString
& os
)
217 if (os
.EqualsLiteral("WINNT 5.1"))
218 return DRIVER_OS_WINDOWS_XP
;
219 else if (os
.EqualsLiteral("WINNT 5.2"))
220 return DRIVER_OS_WINDOWS_SERVER_2003
;
221 else if (os
.EqualsLiteral("WINNT 6.0"))
222 return DRIVER_OS_WINDOWS_VISTA
;
223 else if (os
.EqualsLiteral("WINNT 6.1"))
224 return DRIVER_OS_WINDOWS_7
;
225 else if (os
.EqualsLiteral("WINNT 6.2"))
226 return DRIVER_OS_WINDOWS_8
;
227 else if (os
.EqualsLiteral("WINNT 6.3"))
228 return DRIVER_OS_WINDOWS_8_1
;
229 else if (os
.EqualsLiteral("Linux"))
230 return DRIVER_OS_LINUX
;
231 else if (os
.EqualsLiteral("Darwin 9"))
232 return DRIVER_OS_OS_X_10_5
;
233 else if (os
.EqualsLiteral("Darwin 10"))
234 return DRIVER_OS_OS_X_10_6
;
235 else if (os
.EqualsLiteral("Darwin 11"))
236 return DRIVER_OS_OS_X_10_7
;
237 else if (os
.EqualsLiteral("Darwin 12"))
238 return DRIVER_OS_OS_X_10_8
;
239 else if (os
.EqualsLiteral("Darwin 13"))
240 return DRIVER_OS_OS_X_10_9
;
241 else if (os
.EqualsLiteral("Darwin 14"))
242 return DRIVER_OS_OS_X_10_10
;
243 else if (os
.EqualsLiteral("Android"))
244 return DRIVER_OS_ANDROID
;
245 else if (os
.EqualsLiteral("All"))
246 return DRIVER_OS_ALL
;
248 return DRIVER_OS_UNKNOWN
;
251 static GfxDeviceFamily
*
252 BlacklistDevicesToDeviceFamily(nsIDOMHTMLCollection
* aDevices
)
255 if (NS_FAILED(aDevices
->GetLength(&length
)))
258 // For each <device>, get its device ID, and return a freshly-allocated
259 // GfxDeviceFamily with the contents of that array.
260 GfxDeviceFamily
* deviceIds
= new GfxDeviceFamily
;
262 for (uint32_t i
= 0; i
< length
; ++i
) {
263 nsCOMPtr
<nsIDOMNode
> node
;
264 if (NS_FAILED(aDevices
->Item(i
, getter_AddRefs(node
))) || !node
)
267 nsAutoString deviceValue
;
268 if (!BlacklistNodeToTextValue(node
, deviceValue
))
271 deviceIds
->AppendElement(deviceValue
);
278 BlacklistFeatureToGfxFeature(const nsAString
& aFeature
)
280 if (aFeature
.EqualsLiteral("DIRECT2D"))
281 return nsIGfxInfo::FEATURE_DIRECT2D
;
282 else if (aFeature
.EqualsLiteral("DIRECT3D_9_LAYERS"))
283 return nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS
;
284 else if (aFeature
.EqualsLiteral("DIRECT3D_10_LAYERS"))
285 return nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS
;
286 else if (aFeature
.EqualsLiteral("DIRECT3D_10_1_LAYERS"))
287 return nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS
;
288 else if (aFeature
.EqualsLiteral("DIRECT3D_11_LAYERS"))
289 return nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS
;
290 else if (aFeature
.EqualsLiteral("DXVA"))
291 return nsIGfxInfo::FEATURE_DXVA
;
292 else if (aFeature
.EqualsLiteral("OPENGL_LAYERS"))
293 return nsIGfxInfo::FEATURE_OPENGL_LAYERS
;
294 else if (aFeature
.EqualsLiteral("WEBGL_OPENGL"))
295 return nsIGfxInfo::FEATURE_WEBGL_OPENGL
;
296 else if (aFeature
.EqualsLiteral("WEBGL_ANGLE"))
297 return nsIGfxInfo::FEATURE_WEBGL_ANGLE
;
298 else if (aFeature
.EqualsLiteral("WEBGL_MSAA"))
299 return nsIGfxInfo::FEATURE_WEBGL_MSAA
;
300 else if (aFeature
.EqualsLiteral("STAGEFRIGHT"))
301 return nsIGfxInfo::FEATURE_STAGEFRIGHT
;
306 BlacklistFeatureStatusToGfxFeatureStatus(const nsAString
& aStatus
)
308 if (aStatus
.EqualsLiteral("STATUS_OK"))
309 return nsIGfxInfo::FEATURE_STATUS_OK
;
310 else if (aStatus
.EqualsLiteral("BLOCKED_DRIVER_VERSION"))
311 return nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION
;
312 else if (aStatus
.EqualsLiteral("BLOCKED_DEVICE"))
313 return nsIGfxInfo::FEATURE_BLOCKED_DEVICE
;
314 else if (aStatus
.EqualsLiteral("DISCOURAGED"))
315 return nsIGfxInfo::FEATURE_DISCOURAGED
;
316 else if (aStatus
.EqualsLiteral("BLOCKED_OS_VERSION"))
317 return nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION
;
319 // Do not allow it to set STATUS_UNKNOWN.
321 return nsIGfxInfo::FEATURE_STATUS_OK
;
324 static VersionComparisonOp
325 BlacklistComparatorToComparisonOp(const nsAString
& op
)
327 if (op
.EqualsLiteral("LESS_THAN"))
328 return DRIVER_LESS_THAN
;
329 else if (op
.EqualsLiteral("LESS_THAN_OR_EQUAL"))
330 return DRIVER_LESS_THAN_OR_EQUAL
;
331 else if (op
.EqualsLiteral("GREATER_THAN"))
332 return DRIVER_GREATER_THAN
;
333 else if (op
.EqualsLiteral("GREATER_THAN_OR_EQUAL"))
334 return DRIVER_GREATER_THAN_OR_EQUAL
;
335 else if (op
.EqualsLiteral("EQUAL"))
337 else if (op
.EqualsLiteral("NOT_EQUAL"))
338 return DRIVER_NOT_EQUAL
;
339 else if (op
.EqualsLiteral("BETWEEN_EXCLUSIVE"))
340 return DRIVER_BETWEEN_EXCLUSIVE
;
341 else if (op
.EqualsLiteral("BETWEEN_INCLUSIVE"))
342 return DRIVER_BETWEEN_INCLUSIVE
;
343 else if (op
.EqualsLiteral("BETWEEN_INCLUSIVE_START"))
344 return DRIVER_BETWEEN_INCLUSIVE_START
;
346 return DRIVER_COMPARISON_IGNORED
;
349 // Arbitrarily returns the first |tagname| child of |element|.
351 BlacklistNodeGetChildByName(nsIDOMElement
*element
,
352 const nsAString
& tagname
,
353 nsIDOMNode
** firstchild
)
355 nsCOMPtr
<nsIDOMHTMLCollection
> nodelist
;
356 if (NS_FAILED(element
->GetElementsByTagName(tagname
,
357 getter_AddRefs(nodelist
))) ||
362 nsCOMPtr
<nsIDOMNode
> node
;
363 if (NS_FAILED(nodelist
->Item(0, getter_AddRefs(node
))) || !node
)
366 node
.forget(firstchild
);
374 <vendor>0x8086</vendor>
376 <device>0x2582</device>
377 <device>0x2782</device>
379 <feature> DIRECT3D_10_LAYERS </feature>
380 <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
381 <driverVersion> 8.52.322.2202 </driverVersion>
382 <driverVersionComparator> LESS_THAN_OR_EQUAL </driverVersionComparator>
387 BlacklistEntryToDriverInfo(nsIDOMNode
* aBlacklistEntry
,
388 GfxDriverInfo
& aDriverInfo
)
390 nsAutoString nodename
;
391 if (NS_FAILED(aBlacklistEntry
->GetNodeName(nodename
)) ||
392 nodename
!= NS_LITERAL_STRING(BLACKLIST_ENTRY_TAG_NAME
)) {
396 nsCOMPtr
<nsIDOMElement
> element
= do_QueryInterface(aBlacklistEntry
);
400 nsCOMPtr
<nsIDOMNode
> dataNode
;
401 nsAutoString dataValue
;
403 // <os>WINNT 6.0</os>
404 if (BlacklistNodeGetChildByName(element
, NS_LITERAL_STRING("os"),
405 getter_AddRefs(dataNode
))) {
406 BlacklistNodeToTextValue(dataNode
, dataValue
);
407 aDriverInfo
.mOperatingSystem
= BlacklistOSToOperatingSystem(dataValue
);
410 // <osversion>14</osversion> currently only used for Android
411 if (BlacklistNodeGetChildByName(element
, NS_LITERAL_STRING("osversion"),
412 getter_AddRefs(dataNode
))) {
413 BlacklistNodeToTextValue(dataNode
, dataValue
);
414 aDriverInfo
.mOperatingSystemVersion
= strtoul(NS_LossyConvertUTF16toASCII(dataValue
).get(),
418 // <vendor>0x8086</vendor>
419 if (BlacklistNodeGetChildByName(element
, NS_LITERAL_STRING("vendor"),
420 getter_AddRefs(dataNode
))) {
421 BlacklistNodeToTextValue(dataNode
, dataValue
);
422 aDriverInfo
.mAdapterVendor
= dataValue
;
426 // <device>0x2582</device>
427 // <device>0x2782</device>
429 if (BlacklistNodeGetChildByName(element
, NS_LITERAL_STRING("devices"),
430 getter_AddRefs(dataNode
))) {
431 nsCOMPtr
<nsIDOMElement
> devicesElement
= do_QueryInterface(dataNode
);
432 if (devicesElement
) {
434 // Get only the <device> nodes, because BlacklistDevicesToDeviceFamily
435 // assumes it is passed no other nodes.
436 nsCOMPtr
<nsIDOMHTMLCollection
> devices
;
437 if (NS_SUCCEEDED(devicesElement
->GetElementsByTagName(NS_LITERAL_STRING("device"),
438 getter_AddRefs(devices
)))) {
439 GfxDeviceFamily
* deviceIds
= BlacklistDevicesToDeviceFamily(devices
);
441 // Get GfxDriverInfo to adopt the devices array we created.
442 aDriverInfo
.mDeleteDevices
= true;
443 aDriverInfo
.mDevices
= deviceIds
;
449 // <feature> DIRECT3D_10_LAYERS </feature>
450 if (BlacklistNodeGetChildByName(element
, NS_LITERAL_STRING("feature"),
451 getter_AddRefs(dataNode
))) {
452 BlacklistNodeToTextValue(dataNode
, dataValue
);
453 aDriverInfo
.mFeature
= BlacklistFeatureToGfxFeature(dataValue
);
456 // <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
457 if (BlacklistNodeGetChildByName(element
, NS_LITERAL_STRING("featureStatus"),
458 getter_AddRefs(dataNode
))) {
459 BlacklistNodeToTextValue(dataNode
, dataValue
);
460 aDriverInfo
.mFeatureStatus
= BlacklistFeatureStatusToGfxFeatureStatus(dataValue
);
463 // <driverVersion> 8.52.322.2202 </driverVersion>
464 if (BlacklistNodeGetChildByName(element
, NS_LITERAL_STRING("driverVersion"),
465 getter_AddRefs(dataNode
))) {
466 BlacklistNodeToTextValue(dataNode
, dataValue
);
468 if (ParseDriverVersion(dataValue
, &version
))
469 aDriverInfo
.mDriverVersion
= version
;
472 // <driverVersionComparator> LESS_THAN_OR_EQUAL </driverVersionComparator>
473 if (BlacklistNodeGetChildByName(element
, NS_LITERAL_STRING("driverVersionComparator"),
474 getter_AddRefs(dataNode
))) {
475 BlacklistNodeToTextValue(dataNode
, dataValue
);
476 aDriverInfo
.mComparisonOp
= BlacklistComparatorToComparisonOp(dataValue
);
479 // <model>foo</model>
480 if (BlacklistNodeGetChildByName(element
, NS_LITERAL_STRING("model"),
481 getter_AddRefs(dataNode
))) {
482 BlacklistNodeToTextValue(dataNode
, dataValue
);
483 aDriverInfo
.mModel
= dataValue
;
485 // <product>foo</product>
486 if (BlacklistNodeGetChildByName(element
, NS_LITERAL_STRING("product"),
487 getter_AddRefs(dataNode
))) {
488 BlacklistNodeToTextValue(dataNode
, dataValue
);
489 aDriverInfo
.mProduct
= dataValue
;
491 // <manufacturer>foo</manufacturer>
492 if (BlacklistNodeGetChildByName(element
, NS_LITERAL_STRING("manufacturer"),
493 getter_AddRefs(dataNode
))) {
494 BlacklistNodeToTextValue(dataNode
, dataValue
);
495 aDriverInfo
.mManufacturer
= dataValue
;
497 // <hardware>foo</hardware>
498 if (BlacklistNodeGetChildByName(element
, NS_LITERAL_STRING("hardware"),
499 getter_AddRefs(dataNode
))) {
500 BlacklistNodeToTextValue(dataNode
, dataValue
);
501 aDriverInfo
.mHardware
= dataValue
;
504 // We explicitly ignore unknown elements.
510 BlacklistEntriesToDriverInfo(nsIDOMHTMLCollection
* aBlacklistEntries
,
511 nsTArray
<GfxDriverInfo
>& aDriverInfo
)
514 if (NS_FAILED(aBlacklistEntries
->GetLength(&length
)))
518 aDriverInfo
.SetLength(length
);
519 for (uint32_t i
= 0; i
< length
; ++i
) {
520 nsCOMPtr
<nsIDOMNode
> blacklistEntry
;
521 if (NS_SUCCEEDED(aBlacklistEntries
->Item(i
,
522 getter_AddRefs(blacklistEntry
))) &&
525 if (BlacklistEntryToDriverInfo(blacklistEntry
, di
)) {
528 // Prevent di falling out of scope from destroying the devices.
529 di
.mDeleteDevices
= false;
535 GfxInfoBase::Observe(nsISupports
* aSubject
, const char* aTopic
,
536 const char16_t
* aData
)
538 if (strcmp(aTopic
, "blocklist-data-gfxItems") == 0) {
539 nsCOMPtr
<nsIDOMElement
> gfxItems
= do_QueryInterface(aSubject
);
541 nsCOMPtr
<nsIDOMHTMLCollection
> blacklistEntries
;
542 if (NS_SUCCEEDED(gfxItems
->
543 GetElementsByTagName(NS_LITERAL_STRING(BLACKLIST_ENTRY_TAG_NAME
),
544 getter_AddRefs(blacklistEntries
))) &&
547 nsTArray
<GfxDriverInfo
> driverInfo
;
548 BlacklistEntriesToDriverInfo(blacklistEntries
, driverInfo
);
549 EvaluateDownloadedBlacklist(driverInfo
);
557 GfxInfoBase::GfxInfoBase()
559 , mMutex("GfxInfoBase")
563 GfxInfoBase::~GfxInfoBase()
570 InitGfxDriverInfoShutdownObserver();
572 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
574 os
->AddObserver(this, "blocklist-data-gfxItems", true);
581 GfxInfoBase::GetFeatureStatus(int32_t aFeature
, int32_t* aStatus
)
583 if (GetPrefValueForFeature(aFeature
, *aStatus
))
586 if (XRE_GetProcessType() == GeckoProcessType_Content
) {
587 // Delegate to the parent process.
588 mozilla::dom::ContentChild
* cc
= mozilla::dom::ContentChild::GetSingleton();
590 cc
->SendGetGraphicsFeatureStatus(aFeature
, aStatus
, &success
);
591 return success
? NS_OK
: NS_ERROR_FAILURE
;
595 nsTArray
<GfxDriverInfo
> driverInfo
;
596 return GetFeatureStatusImpl(aFeature
, aStatus
, version
, driverInfo
);
600 GfxInfoBase::FindBlocklistedDeviceInList(const nsTArray
<GfxDriverInfo
>& info
,
601 nsAString
& aSuggestedVersion
,
605 int32_t status
= nsIGfxInfo::FEATURE_STATUS_UNKNOWN
;
608 for (; i
< info
.Length(); i
++) {
609 // XXX: it would be better not to do this everytime round the loop
610 nsAutoString adapterVendorID
;
611 nsAutoString adapterDeviceID
;
612 nsAutoString adapterDriverVersionString
;
614 if (NS_FAILED(GetAdapterVendorID2(adapterVendorID
)) ||
615 NS_FAILED(GetAdapterDeviceID2(adapterDeviceID
)) ||
616 NS_FAILED(GetAdapterDriverVersion2(adapterDriverVersionString
)))
621 if (NS_FAILED(GetAdapterVendorID(adapterVendorID
)) ||
622 NS_FAILED(GetAdapterDeviceID(adapterDeviceID
)) ||
623 NS_FAILED(GetAdapterDriverVersion(adapterDriverVersionString
)))
629 #if defined(XP_WIN) || defined(ANDROID)
630 uint64_t driverVersion
;
631 ParseDriverVersion(adapterDriverVersionString
, &driverVersion
);
635 if (info
[i
].mOperatingSystem
!= DRIVER_OS_ALL
&&
636 info
[i
].mOperatingSystem
!= os
)
641 if (info
[i
].mOperatingSystemVersion
&& info
[i
].mOperatingSystemVersion
!= OperatingSystemVersion()) {
645 if (!info
[i
].mAdapterVendor
.Equals(GfxDriverInfo::GetDeviceVendor(VendorAll
), nsCaseInsensitiveStringComparator()) &&
646 !info
[i
].mAdapterVendor
.Equals(adapterVendorID
, nsCaseInsensitiveStringComparator())) {
650 if (info
[i
].mDevices
!= GfxDriverInfo::allDevices
&& info
[i
].mDevices
->Length()) {
651 bool deviceMatches
= false;
652 for (uint32_t j
= 0; j
< info
[i
].mDevices
->Length(); j
++) {
653 if ((*info
[i
].mDevices
)[j
].Equals(adapterDeviceID
, nsCaseInsensitiveStringComparator())) {
654 deviceMatches
= true;
659 if (!deviceMatches
) {
666 if (!info
[i
].mHardware
.IsEmpty() && !info
[i
].mHardware
.Equals(Hardware())) {
669 if (!info
[i
].mModel
.IsEmpty() && !info
[i
].mModel
.Equals(Model())) {
672 if (!info
[i
].mProduct
.IsEmpty() && !info
[i
].mProduct
.Equals(Product())) {
675 if (!info
[i
].mManufacturer
.IsEmpty() && !info
[i
].mManufacturer
.Equals(Manufacturer())) {
679 #if defined(XP_WIN) || defined(ANDROID)
680 switch (info
[i
].mComparisonOp
) {
681 case DRIVER_LESS_THAN
:
682 match
= driverVersion
< info
[i
].mDriverVersion
;
684 case DRIVER_LESS_THAN_OR_EQUAL
:
685 match
= driverVersion
<= info
[i
].mDriverVersion
;
687 case DRIVER_GREATER_THAN
:
688 match
= driverVersion
> info
[i
].mDriverVersion
;
690 case DRIVER_GREATER_THAN_OR_EQUAL
:
691 match
= driverVersion
>= info
[i
].mDriverVersion
;
694 match
= driverVersion
== info
[i
].mDriverVersion
;
696 case DRIVER_NOT_EQUAL
:
697 match
= driverVersion
!= info
[i
].mDriverVersion
;
699 case DRIVER_BETWEEN_EXCLUSIVE
:
700 match
= driverVersion
> info
[i
].mDriverVersion
&& driverVersion
< info
[i
].mDriverVersionMax
;
702 case DRIVER_BETWEEN_INCLUSIVE
:
703 match
= driverVersion
>= info
[i
].mDriverVersion
&& driverVersion
<= info
[i
].mDriverVersionMax
;
705 case DRIVER_BETWEEN_INCLUSIVE_START
:
706 match
= driverVersion
>= info
[i
].mDriverVersion
&& driverVersion
< info
[i
].mDriverVersionMax
;
708 case DRIVER_COMPARISON_IGNORED
:
709 // We don't have a comparison op, so we match everything.
713 NS_WARNING("Bogus op in GfxDriverInfo");
717 // We don't care what driver version it was. We only check OS version and if
718 // the device matches.
722 if (match
|| info
[i
].mDriverVersion
== GfxDriverInfo::allDriverVersions
) {
723 if (info
[i
].mFeature
== GfxDriverInfo::allFeatures
||
724 info
[i
].mFeature
== aFeature
)
726 status
= info
[i
].mFeatureStatus
;
733 // As a very special case, we block D2D on machines with an NVidia 310M GPU
734 // as either the primary or secondary adapter. D2D is also blocked when the
735 // NV 310M is the primary adapter (using the standard blocklisting mechanism).
736 // If the primary GPU already matched something in the blocklist then we
737 // ignore this special rule. See bug 1008759.
738 if (status
== nsIGfxInfo::FEATURE_STATUS_UNKNOWN
&&
739 (aFeature
== nsIGfxInfo::FEATURE_DIRECT2D
)) {
740 nsAutoString adapterVendorID2
;
741 nsAutoString adapterDeviceID2
;
742 if ((!NS_FAILED(GetAdapterVendorID2(adapterVendorID2
))) &&
743 (!NS_FAILED(GetAdapterDeviceID2(adapterDeviceID2
))))
745 nsAString
&nvVendorID
= (nsAString
&)GfxDriverInfo::GetDeviceVendor(VendorNVIDIA
);
746 const nsString nv310mDeviceId
= NS_LITERAL_STRING("0x0A70");
747 if (nvVendorID
.Equals(adapterVendorID2
, nsCaseInsensitiveStringComparator()) &&
748 nv310mDeviceId
.Equals(adapterDeviceID2
, nsCaseInsensitiveStringComparator())) {
749 status
= nsIGfxInfo::FEATURE_BLOCKED_DEVICE
;
754 // Depends on Windows driver versioning. We don't pass a GfxDriverInfo object
755 // back to the Windows handler, so we must handle this here.
756 if (status
== FEATURE_BLOCKED_DRIVER_VERSION
) {
757 if (info
[i
].mSuggestedVersion
) {
758 aSuggestedVersion
.AppendPrintf("%s", info
[i
].mSuggestedVersion
);
759 } else if (info
[i
].mComparisonOp
== DRIVER_LESS_THAN
&&
760 info
[i
].mDriverVersion
!= GfxDriverInfo::allDriverVersions
)
762 aSuggestedVersion
.AppendPrintf("%lld.%lld.%lld.%lld",
763 (info
[i
].mDriverVersion
& 0xffff000000000000) >> 48,
764 (info
[i
].mDriverVersion
& 0x0000ffff00000000) >> 32,
765 (info
[i
].mDriverVersion
& 0x00000000ffff0000) >> 16,
766 (info
[i
].mDriverVersion
& 0x000000000000ffff));
775 GfxInfoBase::GetFeatureStatusImpl(int32_t aFeature
,
777 nsAString
& aSuggestedVersion
,
778 const nsTArray
<GfxDriverInfo
>& aDriverInfo
,
779 OperatingSystem
* aOS
/* = nullptr */)
781 if (*aStatus
!= nsIGfxInfo::FEATURE_STATUS_UNKNOWN
) {
782 // Terminate now with the status determined by the derived type (OS-specific
787 // If an operating system was provided by the derived GetFeatureStatusImpl,
788 // grab it here. Otherwise, the OS is unknown.
789 OperatingSystem os
= DRIVER_OS_UNKNOWN
;
793 nsAutoString adapterVendorID
;
794 nsAutoString adapterDeviceID
;
795 nsAutoString adapterDriverVersionString
;
796 if (NS_FAILED(GetAdapterVendorID(adapterVendorID
)) ||
797 NS_FAILED(GetAdapterDeviceID(adapterDeviceID
)) ||
798 NS_FAILED(GetAdapterDriverVersion(adapterDriverVersionString
)))
803 // Check if the device is blocked from the downloaded blocklist. If not, check
804 // the static list after that. This order is used so that we can later escape
805 // out of static blocks (i.e. if we were wrong or something was patched, we
806 // can back out our static block without doing a release).
808 if (aDriverInfo
.Length()) {
809 status
= FindBlocklistedDeviceInList(aDriverInfo
, aSuggestedVersion
, aFeature
, os
);
812 mDriverInfo
= new nsTArray
<GfxDriverInfo
>();
814 status
= FindBlocklistedDeviceInList(GetGfxDriverInfo(), aSuggestedVersion
, aFeature
, os
);
817 // It's now done being processed. It's safe to set the status to STATUS_OK.
818 if (status
== nsIGfxInfo::FEATURE_STATUS_UNKNOWN
) {
819 *aStatus
= nsIGfxInfo::FEATURE_STATUS_OK
;
828 GfxInfoBase::GetFeatureSuggestedDriverVersion(int32_t aFeature
,
832 if (GetPrefValueForDriverVersion(version
)) {
833 aVersion
= NS_ConvertASCIItoUTF16(version
);
838 nsTArray
<GfxDriverInfo
> driverInfo
;
839 return GetFeatureStatusImpl(aFeature
, &status
, aVersion
, driverInfo
);
844 GfxInfoBase::GetWebGLParameter(const nsAString
& aParam
,
847 return GfxInfoWebGL::GetWebGLParameter(aParam
, aResult
);
851 GfxInfoBase::EvaluateDownloadedBlacklist(nsTArray
<GfxDriverInfo
>& aDriverInfo
)
853 int32_t features
[] = {
854 nsIGfxInfo::FEATURE_DIRECT2D
,
855 nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS
,
856 nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS
,
857 nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS
,
858 nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS
,
859 nsIGfxInfo::FEATURE_DXVA
,
860 nsIGfxInfo::FEATURE_OPENGL_LAYERS
,
861 nsIGfxInfo::FEATURE_WEBGL_OPENGL
,
862 nsIGfxInfo::FEATURE_WEBGL_ANGLE
,
863 nsIGfxInfo::FEATURE_WEBGL_MSAA
,
864 nsIGfxInfo::FEATURE_STAGEFRIGHT
,
868 // For every feature we know about, we evaluate whether this blacklist has a
869 // non-STATUS_OK status. If it does, we set the pref we evaluate in
870 // GetFeatureStatus above, so we don't need to hold on to this blacklist
871 // anywhere permanent.
873 while (features
[i
]) {
875 nsAutoString suggestedVersion
;
876 if (NS_SUCCEEDED(GetFeatureStatusImpl(features
[i
], &status
,
881 case nsIGfxInfo::FEATURE_STATUS_OK
:
882 RemovePrefForFeature(features
[i
]);
885 case nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION
:
886 if (!suggestedVersion
.IsEmpty()) {
887 SetPrefValueForDriverVersion(suggestedVersion
);
889 RemovePrefForDriverVersion();
893 case nsIGfxInfo::FEATURE_BLOCKED_DEVICE
:
894 case nsIGfxInfo::FEATURE_DISCOURAGED
:
895 case nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION
:
896 SetPrefValueForFeature(features
[i
], status
);
906 GfxInfoBase::LogFailure(const nsACString
&failure
)
908 MutexAutoLock
lock(mMutex
);
909 /* We only keep the first 9 failures */
910 if (mFailureCount
< ArrayLength(mFailures
)) {
911 mFailures
[mFailureCount
++] = failure
;
913 /* record it in the crash notes too */
914 #if defined(MOZ_CRASHREPORTER)
915 CrashReporter::AppendAppNotesToCrashReport(failure
);
921 /* void getFailures ([optional] out unsigned long failureCount, [array, size_is (failureCount), retval] out string failures); */
922 /* XPConnect method of returning arrays is very ugly. Would not recommend. Fallable nsMemory::Alloc makes things worse */
923 NS_IMETHODIMP
GfxInfoBase::GetFailures(uint32_t *failureCount
, char ***failures
)
926 NS_ENSURE_ARG_POINTER(failureCount
);
927 NS_ENSURE_ARG_POINTER(failures
);
930 *failureCount
= mFailureCount
;
932 if (*failureCount
!= 0) {
933 *failures
= (char**)nsMemory::Alloc(*failureCount
* sizeof(char*));
935 return NS_ERROR_OUT_OF_MEMORY
;
937 /* copy over the failure messages into the array we just allocated */
938 for (uint32_t i
= 0; i
< *failureCount
; i
++) {
939 nsCString
& flattenedFailureMessage(mFailures
[i
]);
940 (*failures
)[i
] = (char*)nsMemory::Clone(flattenedFailureMessage
.get(), flattenedFailureMessage
.Length() + 1);
942 if (!(*failures
)[i
]) {
943 /* <sarcasm> I'm too afraid to use an inline function... </sarcasm> */
944 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i
, (*failures
));
945 return NS_ERROR_OUT_OF_MEMORY
;
953 nsTArray
<GfxInfoCollectorBase
*> *sCollectors
;
959 sCollectors
= new nsTArray
<GfxInfoCollectorBase
*>;
962 nsresult
GfxInfoBase::GetInfo(JSContext
* aCx
, JS::MutableHandle
<JS::Value
> aResult
)
967 for (uint32_t i
= 0; i
< sCollectors
->Length(); i
++) {
968 (*sCollectors
)[i
]->GetInfo(obj
);
971 // Some example property definitions
972 // obj.DefineProperty("wordCacheSize", gfxTextRunWordCache::Count());
973 // obj.DefineProperty("renderer", mRendererIDsString);
974 // obj.DefineProperty("five", 5);
977 return NS_ERROR_FAILURE
;
980 aResult
.setObject(*obj
.mObj
);
985 GfxInfoBase::AddCollector(GfxInfoCollectorBase
* collector
)
988 sCollectors
->AppendElement(collector
);
992 GfxInfoBase::RemoveCollector(GfxInfoCollectorBase
* collector
)
995 for (uint32_t i
= 0; i
< sCollectors
->Length(); i
++) {
996 if ((*sCollectors
)[i
] == collector
) {
997 sCollectors
->RemoveElementAt(i
);
1001 if (sCollectors
->IsEmpty()) {
1003 sCollectors
= nullptr;
1007 GfxInfoCollectorBase::GfxInfoCollectorBase()
1009 GfxInfoBase::AddCollector(this);
1012 GfxInfoCollectorBase::~GfxInfoCollectorBase()
1014 GfxInfoBase::RemoveCollector(this);