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
)
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
;
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"
100 GetPrefNameForFeature(int32_t aFeature
)
102 const char* name
= nullptr;
104 case nsIGfxInfo::FEATURE_DIRECT2D
:
105 name
= BLACKLIST_PREF_BRANCH
"direct2d";
107 case nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS
:
108 name
= BLACKLIST_PREF_BRANCH
"layers.direct3d9";
110 case nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS
:
111 name
= BLACKLIST_PREF_BRANCH
"layers.direct3d10";
113 case nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS
:
114 name
= BLACKLIST_PREF_BRANCH
"layers.direct3d10-1";
116 case nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS
:
117 name
= BLACKLIST_PREF_BRANCH
"layers.direct3d11";
119 case nsIGfxInfo::FEATURE_OPENGL_LAYERS
:
120 name
= BLACKLIST_PREF_BRANCH
"layers.opengl";
122 case nsIGfxInfo::FEATURE_WEBGL_OPENGL
:
123 name
= BLACKLIST_PREF_BRANCH
"webgl.opengl";
125 case nsIGfxInfo::FEATURE_WEBGL_ANGLE
:
126 name
= BLACKLIST_PREF_BRANCH
"webgl.angle";
128 case nsIGfxInfo::FEATURE_WEBGL_MSAA
:
129 name
= BLACKLIST_PREF_BRANCH
"webgl.msaa";
131 case nsIGfxInfo::FEATURE_STAGEFRIGHT
:
132 name
= BLACKLIST_PREF_BRANCH
"stagefright";
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.
144 GetPrefValueForFeature(int32_t aFeature
, int32_t& aValue
)
146 const char *prefname
= GetPrefNameForFeature(aFeature
);
151 return NS_SUCCEEDED(Preferences::GetInt(prefname
, &aValue
));
155 SetPrefValueForFeature(int32_t aFeature
, int32_t aValue
)
157 const char *prefname
= GetPrefNameForFeature(aFeature
);
161 Preferences::SetInt(prefname
, aValue
);
165 RemovePrefForFeature(int32_t aFeature
)
167 const char *prefname
= GetPrefNameForFeature(aFeature
);
171 Preferences::ClearUser(prefname
);
175 GetPrefValueForDriverVersion(nsCString
& aVersion
)
177 return NS_SUCCEEDED(Preferences::GetCString(SUGGESTED_VERSION_PREF
,
182 SetPrefValueForDriverVersion(const nsAString
& aVersion
)
184 Preferences::SetString(SUGGESTED_VERSION_PREF
, aVersion
);
188 RemovePrefForDriverVersion()
190 Preferences::ClearUser(SUGGESTED_VERSION_PREF
);
193 // <foo>Hello</foo> - "Hello" is stored as a child text node of the foo node.
195 BlacklistNodeToTextValue(nsIDOMNode
*aBlacklistNode
, nsAString
& aValue
)
198 if (NS_FAILED(aBlacklistNode
->GetTextContent(value
)))
201 value
.Trim(" \t\r\n");
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
)
244 if (NS_FAILED(aDevices
->GetLength(&length
)))
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
)
256 nsAutoString deviceValue
;
257 if (!BlacklistNodeToTextValue(node
, deviceValue
))
260 deviceIds
->AppendElement(deviceValue
);
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
;
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"))
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|.
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
))) ||
349 nsCOMPtr
<nsIDOMNode
> node
;
350 if (NS_FAILED(nodelist
->Item(0, getter_AddRefs(node
))) || !node
)
353 node
.forget(firstchild
);
361 <vendor>0x8086</vendor>
363 <device>0x2582</device>
364 <device>0x2782</device>
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>
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
)) {
383 nsCOMPtr
<nsIDOMElement
> element
= do_QueryInterface(aBlacklistEntry
);
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(),
405 // <vendor>0x8086</vendor>
406 if (BlacklistNodeGetChildByName(element
, NS_LITERAL_STRING("vendor"),
407 getter_AddRefs(dataNode
))) {
408 BlacklistNodeToTextValue(dataNode
, dataValue
);
409 aDriverInfo
.mAdapterVendor
= dataValue
;
413 // <device>0x2582</device>
414 // <device>0x2782</device>
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
);
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
);
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.
497 BlacklistEntriesToDriverInfo(nsIDOMHTMLCollection
* aBlacklistEntries
,
498 nsTArray
<GfxDriverInfo
>& aDriverInfo
)
501 if (NS_FAILED(aBlacklistEntries
->GetLength(&length
)))
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
))) &&
512 if (BlacklistEntryToDriverInfo(blacklistEntry
, di
)) {
515 // Prevent di falling out of scope from destroying the devices.
516 di
.mDeleteDevices
= false;
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
);
528 nsCOMPtr
<nsIDOMHTMLCollection
> blacklistEntries
;
529 if (NS_SUCCEEDED(gfxItems
->
530 GetElementsByTagName(NS_LITERAL_STRING(BLACKLIST_ENTRY_TAG_NAME
),
531 getter_AddRefs(blacklistEntries
))) &&
534 nsTArray
<GfxDriverInfo
> driverInfo
;
535 BlacklistEntriesToDriverInfo(blacklistEntries
, driverInfo
);
536 EvaluateDownloadedBlacklist(driverInfo
);
544 GfxInfoBase::GfxInfoBase()
546 , mMutex("GfxInfoBase")
550 GfxInfoBase::~GfxInfoBase()
557 InitGfxDriverInfoShutdownObserver();
559 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
561 os
->AddObserver(this, "blocklist-data-gfxItems", true);
568 GfxInfoBase::GetFeatureStatus(int32_t aFeature
, int32_t* aStatus
)
570 if (GetPrefValueForFeature(aFeature
, *aStatus
))
573 if (XRE_GetProcessType() == GeckoProcessType_Content
) {
574 // Delegate to the parent process.
575 mozilla::dom::ContentChild
* cc
= mozilla::dom::ContentChild::GetSingleton();
577 cc
->SendGetGraphicsFeatureStatus(aFeature
, aStatus
, &success
);
578 return success
? NS_OK
: NS_ERROR_FAILURE
;
582 nsTArray
<GfxDriverInfo
> driverInfo
;
583 return GetFeatureStatusImpl(aFeature
, aStatus
, version
, driverInfo
);
587 GfxInfoBase::FindBlocklistedDeviceInList(const nsTArray
<GfxDriverInfo
>& info
,
588 nsAString
& aSuggestedVersion
,
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
)))
604 #if defined(XP_WIN) || defined(ANDROID)
605 uint64_t driverVersion
;
606 ParseDriverVersion(adapterDriverVersionString
, &driverVersion
);
610 for (; i
< info
.Length(); i
++) {
611 if (info
[i
].mOperatingSystem
!= DRIVER_OS_ALL
&&
612 info
[i
].mOperatingSystem
!= os
)
617 if (info
[i
].mOperatingSystemVersion
&& info
[i
].mOperatingSystemVersion
!= OperatingSystemVersion()) {
621 if (!info
[i
].mAdapterVendor
.Equals(GfxDriverInfo::GetDeviceVendor(VendorAll
), nsCaseInsensitiveStringComparator()) &&
622 !info
[i
].mAdapterVendor
.Equals(adapterVendorID
, nsCaseInsensitiveStringComparator())) {
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;
635 if (!deviceMatches
) {
642 if (!info
[i
].mHardware
.IsEmpty() && !info
[i
].mHardware
.Equals(Hardware())) {
645 if (!info
[i
].mModel
.IsEmpty() && !info
[i
].mModel
.Equals(Model())) {
648 if (!info
[i
].mProduct
.IsEmpty() && !info
[i
].mProduct
.Equals(Product())) {
651 if (!info
[i
].mManufacturer
.IsEmpty() && !info
[i
].mManufacturer
.Equals(Manufacturer())) {
655 #if defined(XP_WIN) || defined(ANDROID)
656 switch (info
[i
].mComparisonOp
) {
657 case DRIVER_LESS_THAN
:
658 match
= driverVersion
< info
[i
].mDriverVersion
;
660 case DRIVER_LESS_THAN_OR_EQUAL
:
661 match
= driverVersion
<= info
[i
].mDriverVersion
;
663 case DRIVER_GREATER_THAN
:
664 match
= driverVersion
> info
[i
].mDriverVersion
;
666 case DRIVER_GREATER_THAN_OR_EQUAL
:
667 match
= driverVersion
>= info
[i
].mDriverVersion
;
670 match
= driverVersion
== info
[i
].mDriverVersion
;
672 case DRIVER_NOT_EQUAL
:
673 match
= driverVersion
!= info
[i
].mDriverVersion
;
675 case DRIVER_BETWEEN_EXCLUSIVE
:
676 match
= driverVersion
> info
[i
].mDriverVersion
&& driverVersion
< info
[i
].mDriverVersionMax
;
678 case DRIVER_BETWEEN_INCLUSIVE
:
679 match
= driverVersion
>= info
[i
].mDriverVersion
&& driverVersion
<= info
[i
].mDriverVersionMax
;
681 case DRIVER_BETWEEN_INCLUSIVE_START
:
682 match
= driverVersion
>= info
[i
].mDriverVersion
&& driverVersion
< info
[i
].mDriverVersionMax
;
684 case DRIVER_COMPARISON_IGNORED
:
685 // We don't have a comparison op, so we match everything.
689 NS_WARNING("Bogus op in GfxDriverInfo");
693 // We don't care what driver version it was. We only check OS version and if
694 // the device matches.
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
;
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));
751 GfxInfoBase::GetFeatureStatusImpl(int32_t aFeature
,
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
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
;
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
)))
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).
784 if (aDriverInfo
.Length()) {
785 status
= FindBlocklistedDeviceInList(aDriverInfo
, aSuggestedVersion
, aFeature
, os
);
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
;
804 GfxInfoBase::GetFeatureSuggestedDriverVersion(int32_t aFeature
,
808 if (GetPrefValueForDriverVersion(version
)) {
809 aVersion
= NS_ConvertASCIItoUTF16(version
);
814 nsTArray
<GfxDriverInfo
> driverInfo
;
815 return GetFeatureStatusImpl(aFeature
, &status
, aVersion
, driverInfo
);
820 GfxInfoBase::GetWebGLParameter(const nsAString
& aParam
,
823 return GfxInfoWebGL::GetWebGLParameter(aParam
, aResult
);
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.
848 while (features
[i
]) {
850 nsAutoString suggestedVersion
;
851 if (NS_SUCCEEDED(GetFeatureStatusImpl(features
[i
], &status
,
856 case nsIGfxInfo::FEATURE_STATUS_OK
:
857 RemovePrefForFeature(features
[i
]);
860 case nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION
:
861 if (!suggestedVersion
.IsEmpty()) {
862 SetPrefValueForDriverVersion(suggestedVersion
);
864 RemovePrefForDriverVersion();
868 case nsIGfxInfo::FEATURE_BLOCKED_DEVICE
:
869 case nsIGfxInfo::FEATURE_DISCOURAGED
:
870 case nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION
:
871 SetPrefValueForFeature(features
[i
], status
);
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
);
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
);
905 *failureCount
= mFailureCount
;
907 if (*failureCount
!= 0) {
908 *failures
= (char**)nsMemory::Alloc(*failureCount
* sizeof(char*));
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
;
928 nsTArray
<GfxInfoCollectorBase
*> *sCollectors
;
934 sCollectors
= new nsTArray
<GfxInfoCollectorBase
*>;
937 nsresult
GfxInfoBase::GetInfo(JSContext
* aCx
, JS::MutableHandle
<JS::Value
> aResult
)
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);
952 return NS_ERROR_FAILURE
;
955 aResult
.setObject(*obj
.mObj
);
960 GfxInfoBase::AddCollector(GfxInfoCollectorBase
* collector
)
963 sCollectors
->AppendElement(collector
);
967 GfxInfoBase::RemoveCollector(GfxInfoCollectorBase
* collector
)
970 for (uint32_t i
= 0; i
< sCollectors
->Length(); i
++) {
971 if ((*sCollectors
)[i
] == collector
) {
972 sCollectors
->RemoveElementAt(i
);
976 if (sCollectors
->IsEmpty()) {
978 sCollectors
= nullptr;
982 GfxInfoCollectorBase::GfxInfoCollectorBase()
984 GfxInfoBase::AddCollector(this);
987 GfxInfoCollectorBase::~GfxInfoCollectorBase()
989 GfxInfoBase::RemoveCollector(this);