LCOV - code coverage report
Current view: top level - widget - GfxInfoBase.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 186 724 25.7 %
Date: 2017-07-14 16:53:18 Functions: 23 66 34.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* vim: se cin sw=2 ts=2 et : */
       2             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       3             :  *
       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/. */
       7             : 
       8             : #include "mozilla/ArrayUtils.h"
       9             : 
      10             : #include "GfxInfoBase.h"
      11             : 
      12             : #include "GfxInfoWebGL.h"
      13             : #include "GfxDriverInfo.h"
      14             : #include "nsCOMPtr.h"
      15             : #include "nsCOMArray.h"
      16             : #include "nsString.h"
      17             : #include "nsUnicharUtils.h"
      18             : #include "nsVersionComparator.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 "nsIXULAppInfo.h"
      30             : #include "mozilla/Preferences.h"
      31             : #include "mozilla/dom/ContentChild.h"
      32             : #include "mozilla/gfx/2D.h"
      33             : #include "mozilla/gfx/GPUProcessManager.h"
      34             : #include "mozilla/gfx/Logging.h"
      35             : #include "mozilla/gfx/gfxVars.h"
      36             : #include "MediaPrefs.h"
      37             : #include "gfxPrefs.h"
      38             : #include "gfxPlatform.h"
      39             : #include "gfxConfig.h"
      40             : #include "DriverCrashGuard.h"
      41             : 
      42             : #if defined(MOZ_CRASHREPORTER)
      43             : #include "nsExceptionHandler.h"
      44             : #endif
      45             : 
      46             : using namespace mozilla::widget;
      47             : using namespace mozilla;
      48             : using mozilla::MutexAutoLock;
      49             : 
      50             : nsTArray<GfxDriverInfo>* GfxInfoBase::mDriverInfo;
      51             : nsTArray<dom::GfxInfoFeatureStatus>* GfxInfoBase::mFeatureStatus;
      52             : bool GfxInfoBase::mDriverInfoObserverInitialized;
      53             : bool GfxInfoBase::mShutdownOccurred;
      54             : 
      55             : // Observes for shutdown so that the child GfxDriverInfo list is freed.
      56             : class ShutdownObserver : public nsIObserver
      57             : {
      58           0 :   virtual ~ShutdownObserver() {}
      59             : 
      60             : public:
      61           3 :   ShutdownObserver() {}
      62             : 
      63             :   NS_DECL_ISUPPORTS
      64             : 
      65           0 :   NS_IMETHOD Observe(nsISupports *subject, const char *aTopic,
      66             :                      const char16_t *aData) override
      67             :   {
      68           0 :     MOZ_ASSERT(strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0);
      69             : 
      70           0 :     delete GfxInfoBase::mDriverInfo;
      71           0 :     GfxInfoBase::mDriverInfo = nullptr;
      72             : 
      73           0 :     delete GfxInfoBase::mFeatureStatus;
      74           0 :     GfxInfoBase::mFeatureStatus = nullptr;
      75             : 
      76           0 :     for (uint32_t i = 0; i < DeviceFamilyMax; i++)
      77           0 :       delete GfxDriverInfo::mDeviceFamilies[i];
      78             : 
      79           0 :     for (uint32_t i = 0; i < DeviceVendorMax; i++)
      80           0 :       delete GfxDriverInfo::mDeviceVendors[i];
      81             : 
      82           0 :     GfxInfoBase::mShutdownOccurred = true;
      83             : 
      84           0 :     return NS_OK;
      85             :   }
      86             : };
      87             : 
      88           3 : NS_IMPL_ISUPPORTS(ShutdownObserver, nsIObserver)
      89             : 
      90           3 : void InitGfxDriverInfoShutdownObserver()
      91             : {
      92           3 :   if (GfxInfoBase::mDriverInfoObserverInitialized)
      93           0 :     return;
      94             : 
      95           3 :   GfxInfoBase::mDriverInfoObserverInitialized = true;
      96             : 
      97           6 :   nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
      98           3 :   if (!observerService) {
      99           0 :     NS_WARNING("Could not get observer service!");
     100           0 :     return;
     101             :   }
     102             : 
     103           3 :   ShutdownObserver *obs = new ShutdownObserver();
     104           3 :   observerService->AddObserver(obs, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
     105             : }
     106             : 
     107             : using namespace mozilla::widget;
     108             : using namespace mozilla::gfx;
     109             : using namespace mozilla;
     110             : 
     111         221 : NS_IMPL_ISUPPORTS(GfxInfoBase, nsIGfxInfo, nsIObserver, nsISupportsWeakReference)
     112             : 
     113             : #define BLACKLIST_PREF_BRANCH "gfx.blacklist."
     114             : #define SUGGESTED_VERSION_PREF BLACKLIST_PREF_BRANCH "suggested-driver-version"
     115             : #define BLACKLIST_ENTRY_TAG_NAME "gfxBlacklistEntry"
     116             : 
     117             : static const char*
     118          50 : GetPrefNameForFeature(int32_t aFeature)
     119             : {
     120          50 :   const char* name = nullptr;
     121          50 :   switch(aFeature) {
     122             :     case nsIGfxInfo::FEATURE_DIRECT2D:
     123           2 :       name = BLACKLIST_PREF_BRANCH "direct2d";
     124           2 :       break;
     125             :     case nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS:
     126           2 :       name = BLACKLIST_PREF_BRANCH "layers.direct3d9";
     127           2 :       break;
     128             :     case nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS:
     129           2 :       name = BLACKLIST_PREF_BRANCH "layers.direct3d10";
     130           2 :       break;
     131             :     case nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS:
     132           2 :       name = BLACKLIST_PREF_BRANCH "layers.direct3d10-1";
     133           2 :       break;
     134             :     case nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS:
     135           2 :       name = BLACKLIST_PREF_BRANCH "layers.direct3d11";
     136           2 :       break;
     137             :     case nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE:
     138           2 :       name = BLACKLIST_PREF_BRANCH "direct3d11angle";
     139           2 :       break;
     140             :     case nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING:
     141           5 :       name = BLACKLIST_PREF_BRANCH "hardwarevideodecoding";
     142           5 :       break;
     143             :     case nsIGfxInfo::FEATURE_OPENGL_LAYERS:
     144           2 :       name = BLACKLIST_PREF_BRANCH "layers.opengl";
     145           2 :       break;
     146             :     case nsIGfxInfo::FEATURE_WEBGL_OPENGL:
     147           2 :       name = BLACKLIST_PREF_BRANCH "webgl.opengl";
     148           2 :       break;
     149             :     case nsIGfxInfo::FEATURE_WEBGL_ANGLE:
     150           2 :       name = BLACKLIST_PREF_BRANCH "webgl.angle";
     151           2 :       break;
     152             :     case nsIGfxInfo::FEATURE_WEBGL_MSAA:
     153           2 :       name = BLACKLIST_PREF_BRANCH "webgl.msaa";
     154           2 :       break;
     155             :     case nsIGfxInfo::FEATURE_STAGEFRIGHT:
     156           2 :       name = BLACKLIST_PREF_BRANCH "stagefright";
     157           2 :       break;
     158             :     case nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION:
     159           2 :       name = BLACKLIST_PREF_BRANCH "webrtc.hw.acceleration";
     160           2 :       break;
     161             :     case nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_ENCODE:
     162           2 :       name = BLACKLIST_PREF_BRANCH "webrtc.hw.acceleration.encode";
     163           2 :       break;
     164             :     case nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_DECODE:
     165           2 :       name = BLACKLIST_PREF_BRANCH "webrtc.hw.acceleration.decode";
     166           2 :       break;
     167             :     case nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION:
     168           2 :       name = BLACKLIST_PREF_BRANCH "canvas2d.acceleration";
     169           2 :       break;
     170             :     case nsIGfxInfo::FEATURE_WEBGL2:
     171           2 :       name = BLACKLIST_PREF_BRANCH "webgl2";
     172           2 :       break;
     173             :     case nsIGfxInfo::FEATURE_ADVANCED_LAYERS:
     174           2 :       name = BLACKLIST_PREF_BRANCH "layers.advanced";
     175           2 :       break;
     176             :     case nsIGfxInfo::FEATURE_VP8_HW_DECODE:
     177             :     case nsIGfxInfo::FEATURE_VP9_HW_DECODE:
     178             :     case nsIGfxInfo::FEATURE_DX_INTEROP2:
     179             :     case nsIGfxInfo::FEATURE_GPU_PROCESS:
     180             :       // We don't provide prefs for these features.
     181          11 :       break;
     182             :     default:
     183           0 :       MOZ_ASSERT_UNREACHABLE("Unexpected nsIGfxInfo feature?!");
     184             :       break;
     185             :   }
     186             : 
     187          50 :   return name;
     188             : }
     189             : 
     190             : // Returns the value of the pref for the relevant feature in aValue.
     191             : // If the pref doesn't exist, aValue is not touched, and returns false.
     192             : static bool
     193          50 : GetPrefValueForFeature(int32_t aFeature, int32_t& aValue, nsACString& aFailureId)
     194             : {
     195          50 :   const char *prefname = GetPrefNameForFeature(aFeature);
     196          50 :   if (!prefname)
     197          11 :     return false;
     198             : 
     199          39 :   aValue = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
     200          39 :   if (!NS_SUCCEEDED(Preferences::GetInt(prefname, &aValue))) {
     201          39 :     return false;
     202             :   }
     203             : 
     204           0 :   nsCString failureprefname(prefname);
     205           0 :   failureprefname += ".failureid";
     206           0 :   nsAdoptingCString failureValue = Preferences::GetCString(failureprefname.get());
     207           0 :   if (failureValue) {
     208           0 :     aFailureId = failureValue.get();
     209             :   } else {
     210           0 :     aFailureId = "FEATURE_FAILURE_BLACKLIST_PREF";
     211             :   }
     212             : 
     213           0 :   return true;
     214             : }
     215             : 
     216             : static void
     217           0 : SetPrefValueForFeature(int32_t aFeature, int32_t aValue, const nsACString& aFailureId)
     218             : {
     219           0 :   const char *prefname = GetPrefNameForFeature(aFeature);
     220           0 :   if (!prefname)
     221           0 :     return;
     222             : 
     223           0 :   Preferences::SetInt(prefname, aValue);
     224           0 :   if (!aFailureId.IsEmpty()) {
     225           0 :     nsCString failureprefname(prefname);
     226           0 :     failureprefname += ".failureid";
     227           0 :     Preferences::SetCString(failureprefname.get(), aFailureId);
     228             :   }
     229             : }
     230             : 
     231             : static void
     232           0 : RemovePrefForFeature(int32_t aFeature)
     233             : {
     234           0 :   const char *prefname = GetPrefNameForFeature(aFeature);
     235           0 :   if (!prefname)
     236           0 :     return;
     237             : 
     238           0 :   Preferences::ClearUser(prefname);
     239             : }
     240             : 
     241             : static bool
     242           0 : GetPrefValueForDriverVersion(nsCString& aVersion)
     243             : {
     244           0 :   return NS_SUCCEEDED(Preferences::GetCString(SUGGESTED_VERSION_PREF,
     245             :                                               &aVersion));
     246             : }
     247             : 
     248             : static void
     249           0 : SetPrefValueForDriverVersion(const nsAString& aVersion)
     250             : {
     251           0 :   Preferences::SetString(SUGGESTED_VERSION_PREF, aVersion);
     252           0 : }
     253             : 
     254             : static void
     255           0 : RemovePrefForDriverVersion()
     256             : {
     257           0 :   Preferences::ClearUser(SUGGESTED_VERSION_PREF);
     258           0 : }
     259             : 
     260             : 
     261             : static OperatingSystem
     262           0 : BlacklistOSToOperatingSystem(const nsAString& os)
     263             : {
     264           0 :   if (os.EqualsLiteral("WINNT 6.1"))
     265           0 :     return OperatingSystem::Windows7;
     266           0 :   else if (os.EqualsLiteral("WINNT 6.2"))
     267           0 :     return OperatingSystem::Windows8;
     268           0 :   else if (os.EqualsLiteral("WINNT 6.3"))
     269           0 :     return OperatingSystem::Windows8_1;
     270           0 :   else if (os.EqualsLiteral("WINNT 10.0"))
     271           0 :     return OperatingSystem::Windows10;
     272           0 :   else if (os.EqualsLiteral("Linux"))
     273           0 :     return OperatingSystem::Linux;
     274           0 :   else if (os.EqualsLiteral("Darwin 9"))
     275           0 :     return OperatingSystem::OSX10_5;
     276           0 :   else if (os.EqualsLiteral("Darwin 10"))
     277           0 :     return OperatingSystem::OSX10_6;
     278           0 :   else if (os.EqualsLiteral("Darwin 11"))
     279           0 :     return OperatingSystem::OSX10_7;
     280           0 :   else if (os.EqualsLiteral("Darwin 12"))
     281           0 :     return OperatingSystem::OSX10_8;
     282           0 :   else if (os.EqualsLiteral("Darwin 13"))
     283           0 :     return OperatingSystem::OSX10_9;
     284           0 :   else if (os.EqualsLiteral("Darwin 14"))
     285           0 :     return OperatingSystem::OSX10_10;
     286           0 :   else if (os.EqualsLiteral("Darwin 15"))
     287           0 :     return OperatingSystem::OSX10_11;
     288           0 :   else if (os.EqualsLiteral("Darwin 16"))
     289           0 :     return OperatingSystem::OSX10_12;
     290           0 :   else if (os.EqualsLiteral("Android"))
     291           0 :     return OperatingSystem::Android;
     292             :   // For historical reasons, "All" in blocklist means "All Windows"
     293           0 :   else if (os.EqualsLiteral("All"))
     294           0 :     return OperatingSystem::Windows;
     295             : 
     296           0 :   return OperatingSystem::Unknown;
     297             : }
     298             : 
     299             : static GfxDeviceFamily*
     300           0 : BlacklistDevicesToDeviceFamily(nsTArray<nsCString>& devices)
     301             : {
     302           0 :   if (devices.Length() == 0)
     303           0 :     return nullptr;
     304             : 
     305             :   // For each device, get its device ID, and return a freshly-allocated
     306             :   // GfxDeviceFamily with the contents of that array.
     307           0 :   GfxDeviceFamily* deviceIds = new GfxDeviceFamily;
     308             : 
     309           0 :   for (uint32_t i = 0; i < devices.Length(); ++i) {
     310             :     // We make sure we don't add any "empty" device entries to the array, so
     311             :     // we don't need to check if devices[i] is empty.
     312           0 :     deviceIds->AppendElement(NS_ConvertUTF8toUTF16(devices[i]));
     313             :   }
     314             : 
     315           0 :   return deviceIds;
     316             : }
     317             : 
     318             : static int32_t
     319           0 : BlacklistFeatureToGfxFeature(const nsAString& aFeature)
     320             : {
     321           0 :   MOZ_ASSERT(!aFeature.IsEmpty());
     322           0 :   if (aFeature.EqualsLiteral("DIRECT2D"))
     323           0 :     return nsIGfxInfo::FEATURE_DIRECT2D;
     324           0 :   else if (aFeature.EqualsLiteral("DIRECT3D_9_LAYERS"))
     325           0 :     return nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS;
     326           0 :   else if (aFeature.EqualsLiteral("DIRECT3D_10_LAYERS"))
     327           0 :     return nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS;
     328           0 :   else if (aFeature.EqualsLiteral("DIRECT3D_10_1_LAYERS"))
     329           0 :     return nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS;
     330           0 :   else if (aFeature.EqualsLiteral("DIRECT3D_11_LAYERS"))
     331           0 :     return nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS;
     332           0 :   else if (aFeature.EqualsLiteral("DIRECT3D_11_ANGLE"))
     333           0 :     return nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE;
     334           0 :   else if (aFeature.EqualsLiteral("HARDWARE_VIDEO_DECODING"))
     335           0 :     return nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING;
     336           0 :   else if (aFeature.EqualsLiteral("OPENGL_LAYERS"))
     337           0 :     return nsIGfxInfo::FEATURE_OPENGL_LAYERS;
     338           0 :   else if (aFeature.EqualsLiteral("WEBGL_OPENGL"))
     339           0 :     return nsIGfxInfo::FEATURE_WEBGL_OPENGL;
     340           0 :   else if (aFeature.EqualsLiteral("WEBGL_ANGLE"))
     341           0 :     return nsIGfxInfo::FEATURE_WEBGL_ANGLE;
     342           0 :   else if (aFeature.EqualsLiteral("WEBGL_MSAA"))
     343           0 :     return nsIGfxInfo::FEATURE_WEBGL_MSAA;
     344           0 :   else if (aFeature.EqualsLiteral("STAGEFRIGHT"))
     345           0 :     return nsIGfxInfo::FEATURE_STAGEFRIGHT;
     346           0 :   else if (aFeature.EqualsLiteral("WEBRTC_HW_ACCELERATION_ENCODE"))
     347           0 :     return nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_ENCODE;
     348           0 :   else if (aFeature.EqualsLiteral("WEBRTC_HW_ACCELERATION_DECODE"))
     349           0 :     return nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_DECODE;
     350           0 :   else if (aFeature.EqualsLiteral("WEBRTC_HW_ACCELERATION"))
     351           0 :     return nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION;
     352           0 :   else if (aFeature.EqualsLiteral("CANVAS2D_ACCELERATION"))
     353           0 :       return nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION;
     354           0 :   else if (aFeature.EqualsLiteral("WEBGL2"))
     355           0 :     return nsIGfxInfo::FEATURE_WEBGL2;
     356             : 
     357             :   // If we don't recognize the feature, it may be new, and something
     358             :   // this version doesn't understand.  So, nothing to do.  This is
     359             :   // different from feature not being specified at all, in which case
     360             :   // this method should not get called and we should continue with the
     361             :   // "all features" blocklisting.
     362           0 :   return -1;
     363             : }
     364             : 
     365             : static int32_t
     366           0 : BlacklistFeatureStatusToGfxFeatureStatus(const nsAString& aStatus)
     367             : {
     368           0 :   if (aStatus.EqualsLiteral("STATUS_OK"))
     369           0 :     return nsIGfxInfo::FEATURE_STATUS_OK;
     370           0 :   else if (aStatus.EqualsLiteral("BLOCKED_DRIVER_VERSION"))
     371           0 :     return nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION;
     372           0 :   else if (aStatus.EqualsLiteral("BLOCKED_DEVICE"))
     373           0 :     return nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
     374           0 :   else if (aStatus.EqualsLiteral("DISCOURAGED"))
     375           0 :     return nsIGfxInfo::FEATURE_DISCOURAGED;
     376           0 :   else if (aStatus.EqualsLiteral("BLOCKED_OS_VERSION"))
     377           0 :     return nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION;
     378             : 
     379             :   // Do not allow it to set STATUS_UNKNOWN.  Also, we are not
     380             :   // expecting the "mismatch" status showing up here.
     381             : 
     382           0 :   return nsIGfxInfo::FEATURE_STATUS_OK;
     383             : }
     384             : 
     385             : static VersionComparisonOp
     386           0 : BlacklistComparatorToComparisonOp(const nsAString& op)
     387             : {
     388           0 :   if (op.EqualsLiteral("LESS_THAN"))
     389           0 :     return DRIVER_LESS_THAN;
     390           0 :   else if (op.EqualsLiteral("BUILD_ID_LESS_THAN"))
     391           0 :     return DRIVER_BUILD_ID_LESS_THAN;
     392           0 :   else if (op.EqualsLiteral("LESS_THAN_OR_EQUAL"))
     393           0 :     return DRIVER_LESS_THAN_OR_EQUAL;
     394           0 :   else if (op.EqualsLiteral("BUILD_ID_LESS_THAN_OR_EQUAL"))
     395           0 :     return DRIVER_BUILD_ID_LESS_THAN_OR_EQUAL;
     396           0 :   else if (op.EqualsLiteral("GREATER_THAN"))
     397           0 :     return DRIVER_GREATER_THAN;
     398           0 :   else if (op.EqualsLiteral("GREATER_THAN_OR_EQUAL"))
     399           0 :     return DRIVER_GREATER_THAN_OR_EQUAL;
     400           0 :   else if (op.EqualsLiteral("EQUAL"))
     401           0 :     return DRIVER_EQUAL;
     402           0 :   else if (op.EqualsLiteral("NOT_EQUAL"))
     403           0 :     return DRIVER_NOT_EQUAL;
     404           0 :   else if (op.EqualsLiteral("BETWEEN_EXCLUSIVE"))
     405           0 :     return DRIVER_BETWEEN_EXCLUSIVE;
     406           0 :   else if (op.EqualsLiteral("BETWEEN_INCLUSIVE"))
     407           0 :     return DRIVER_BETWEEN_INCLUSIVE;
     408           0 :   else if (op.EqualsLiteral("BETWEEN_INCLUSIVE_START"))
     409           0 :     return DRIVER_BETWEEN_INCLUSIVE_START;
     410             : 
     411           0 :   return DRIVER_COMPARISON_IGNORED;
     412             : }
     413             : 
     414             : 
     415             : /*
     416             :   Deserialize Blacklist entries from string.
     417             :   e.g:
     418             :   os:WINNT 6.0\tvendor:0x8086\tdevices:0x2582,0x2782\tfeature:DIRECT3D_10_LAYERS\tfeatureStatus:BLOCKED_DRIVER_VERSION\tdriverVersion:8.52.322.2202\tdriverVersionComparator:LESS_THAN_OR_EQUAL
     419             : */
     420             : static bool
     421           0 : BlacklistEntryToDriverInfo(nsCString& aBlacklistEntry,
     422             :                            GfxDriverInfo& aDriverInfo)
     423             : {
     424             :   // If we get an application version to be zero, something is not working
     425             :   // and we are not going to bother checking the blocklist versions.
     426             :   // See TestGfxWidgets.cpp for how version comparison works.
     427             :   // <versionRange minVersion="42.0a1" maxVersion="45.0"></versionRange>
     428           0 :   static mozilla::Version zeroV("0");
     429           0 :   static mozilla::Version appV(GfxInfoBase::GetApplicationVersion().get());
     430           0 :   if (appV <= zeroV) {
     431           0 :       gfxCriticalErrorOnce(gfxCriticalError::DefaultOptions(false)) << "Invalid application version " << GfxInfoBase::GetApplicationVersion().get();
     432             :   }
     433             : 
     434           0 :   nsTArray<nsCString> keyValues;
     435           0 :   ParseString(aBlacklistEntry, '\t', keyValues);
     436             : 
     437           0 :   aDriverInfo.mRuleId = NS_LITERAL_CSTRING("FEATURE_FAILURE_DL_BLACKLIST_NO_ID");
     438             : 
     439           0 :   for (uint32_t i = 0; i < keyValues.Length(); ++i) {
     440           0 :     nsCString keyValue = keyValues[i];
     441           0 :     nsTArray<nsCString> splitted;
     442           0 :     ParseString(keyValue, ':', splitted);
     443           0 :     if (splitted.Length() != 2) {
     444             :       // If we don't recognize the input data, we do not want to proceed.
     445           0 :       gfxCriticalErrorOnce(CriticalLog::DefaultOptions(false)) << "Unrecognized data " << keyValue.get();
     446           0 :       return false;
     447             :     }
     448           0 :     nsCString key = splitted[0];
     449           0 :     nsCString value = splitted[1];
     450           0 :     NS_ConvertUTF8toUTF16 dataValue(value);
     451             : 
     452           0 :     if (value.Length() == 0) {
     453             :       // Safety check for empty values.
     454           0 :       gfxCriticalErrorOnce(CriticalLog::DefaultOptions(false)) << "Empty value for " << key.get();
     455           0 :       return false;
     456             :     }
     457             : 
     458           0 :     if (key.EqualsLiteral("blockID")) {
     459           0 :        nsCString blockIdStr = NS_LITERAL_CSTRING("FEATURE_FAILURE_DL_BLACKLIST_") + value;
     460           0 :        aDriverInfo.mRuleId = blockIdStr.get();
     461           0 :     } else if (key.EqualsLiteral("os")) {
     462           0 :       aDriverInfo.mOperatingSystem = BlacklistOSToOperatingSystem(dataValue);
     463           0 :     } else if (key.EqualsLiteral("osversion")) {
     464           0 :       aDriverInfo.mOperatingSystemVersion = strtoul(value.get(), nullptr, 10);
     465           0 :     } else if (key.EqualsLiteral("vendor")) {
     466           0 :       aDriverInfo.mAdapterVendor = dataValue;
     467           0 :     } else if (key.EqualsLiteral("feature")) {
     468           0 :       aDriverInfo.mFeature = BlacklistFeatureToGfxFeature(dataValue);
     469           0 :       if (aDriverInfo.mFeature < 0) {
     470             :         // If we don't recognize the feature, we do not want to proceed.
     471           0 :         gfxCriticalErrorOnce(CriticalLog::DefaultOptions(false)) << "Unrecognized feature " << value.get();
     472           0 :         return false;
     473             :       }
     474           0 :     } else if (key.EqualsLiteral("featureStatus")) {
     475           0 :       aDriverInfo.mFeatureStatus = BlacklistFeatureStatusToGfxFeatureStatus(dataValue);
     476           0 :     } else if (key.EqualsLiteral("driverVersion")) {
     477             :       uint64_t version;
     478           0 :       if (ParseDriverVersion(dataValue, &version))
     479           0 :         aDriverInfo.mDriverVersion = version;
     480           0 :     } else if (key.EqualsLiteral("driverVersionMax")) {
     481             :       uint64_t version;
     482           0 :       if (ParseDriverVersion(dataValue, &version))
     483           0 :         aDriverInfo.mDriverVersionMax = version;
     484           0 :     } else if (key.EqualsLiteral("driverVersionComparator")) {
     485           0 :       aDriverInfo.mComparisonOp = BlacklistComparatorToComparisonOp(dataValue);
     486           0 :     } else if (key.EqualsLiteral("model")) {
     487           0 :       aDriverInfo.mModel = dataValue;
     488           0 :     } else if (key.EqualsLiteral("product")) {
     489           0 :       aDriverInfo.mProduct = dataValue;
     490           0 :     } else if (key.EqualsLiteral("manufacturer")) {
     491           0 :       aDriverInfo.mManufacturer = dataValue;
     492           0 :     } else if (key.EqualsLiteral("hardware")) {
     493           0 :       aDriverInfo.mHardware = dataValue;
     494           0 :     } else if (key.EqualsLiteral("versionRange")) {
     495           0 :       nsTArray<nsCString> versionRange;
     496           0 :       ParseString(value, ',', versionRange);
     497           0 :       if (versionRange.Length() != 2) {
     498           0 :         gfxCriticalErrorOnce(CriticalLog::DefaultOptions(false)) << "Unrecognized versionRange " << value.get();
     499           0 :         return false;
     500             :       }
     501           0 :       nsCString minValue = versionRange[0];
     502           0 :       nsCString maxValue = versionRange[1];
     503             : 
     504           0 :       mozilla::Version minV(minValue.get());
     505           0 :       mozilla::Version maxV(maxValue.get());
     506             : 
     507           0 :       if (minV > zeroV && !(appV >= minV)) {
     508             :         // The version of the application is less than the minimal version
     509             :         // this blocklist entry applies to, so we can just ignore it by
     510             :         // returning false and letting the caller deal with it.
     511           0 :         return false;
     512             :       }
     513           0 :       if (maxV > zeroV && !(appV <= maxV)) {
     514             :         // The version of the application is more than the maximal version
     515             :         // this blocklist entry applies to, so we can just ignore it by
     516             :         // returning false and letting the caller deal with it.
     517           0 :         return false;
     518             :       }
     519           0 :     } else if (key.EqualsLiteral("devices")) {
     520           0 :       nsTArray<nsCString> devices;
     521           0 :       ParseString(value, ',', devices);
     522           0 :       GfxDeviceFamily* deviceIds = BlacklistDevicesToDeviceFamily(devices);
     523           0 :       if (deviceIds) {
     524             :         // Get GfxDriverInfo to adopt the devices array we created.
     525           0 :         aDriverInfo.mDeleteDevices = true;
     526           0 :         aDriverInfo.mDevices = deviceIds;
     527             :       }
     528             :     }
     529             :     // We explicitly ignore unknown elements.
     530             :   }
     531             : 
     532           0 :   return true;
     533             : }
     534             : 
     535             : static void
     536           0 : BlacklistEntriesToDriverInfo(nsTArray<nsCString>& aBlacklistEntries,
     537             :                              nsTArray<GfxDriverInfo>& aDriverInfo)
     538             : {
     539           0 :   aDriverInfo.Clear();
     540           0 :   aDriverInfo.SetLength(aBlacklistEntries.Length());
     541             : 
     542           0 :   for (uint32_t i = 0; i < aBlacklistEntries.Length(); ++i) {
     543           0 :     nsCString blacklistEntry = aBlacklistEntries[i];
     544           0 :     GfxDriverInfo di;
     545           0 :     if (BlacklistEntryToDriverInfo(blacklistEntry, di)) {
     546           0 :       aDriverInfo[i] = di;
     547             :       // Prevent di falling out of scope from destroying the devices.
     548           0 :       di.mDeleteDevices = false;
     549             :     }
     550             :   }
     551           0 : }
     552             : 
     553             : NS_IMETHODIMP
     554           0 : GfxInfoBase::Observe(nsISupports* aSubject, const char* aTopic,
     555             :                      const char16_t* aData)
     556             : {
     557           0 :   if (strcmp(aTopic, "blocklist-data-gfxItems") == 0) {
     558           0 :     nsTArray<GfxDriverInfo> driverInfo;
     559           0 :     nsTArray<nsCString> blacklistEntries;
     560           0 :     nsCString utf8Data = NS_ConvertUTF16toUTF8(aData);
     561           0 :     if (utf8Data.Length() > 0) {
     562           0 :       ParseString(utf8Data, '\n', blacklistEntries);
     563             :     }
     564           0 :     BlacklistEntriesToDriverInfo(blacklistEntries, driverInfo);
     565           0 :     EvaluateDownloadedBlacklist(driverInfo);
     566             :   }
     567             : 
     568           0 :   return NS_OK;
     569             : }
     570             : 
     571           3 : GfxInfoBase::GfxInfoBase()
     572           3 :     : mMutex("GfxInfoBase")
     573             : {
     574           3 : }
     575             : 
     576           0 : GfxInfoBase::~GfxInfoBase()
     577             : {
     578           0 : }
     579             : 
     580             : nsresult
     581           3 : GfxInfoBase::Init()
     582             : {
     583           3 :   InitGfxDriverInfoShutdownObserver();
     584           3 :   gfxPrefs::GetSingleton();
     585           3 :   MediaPrefs::GetSingleton();
     586             : 
     587           6 :   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
     588           3 :   if (os) {
     589           3 :     os->AddObserver(this, "blocklist-data-gfxItems", true);
     590             :   }
     591             : 
     592           6 :   return NS_OK;
     593             : }
     594             : 
     595             : NS_IMETHODIMP
     596          50 : GfxInfoBase::GetFeatureStatus(int32_t aFeature, nsACString& aFailureId, int32_t* aStatus)
     597             : {
     598          50 :   int32_t blocklistAll = gfxPrefs::BlocklistAll();
     599          50 :   if (blocklistAll > 0) {
     600           0 :     gfxCriticalErrorOnce(gfxCriticalError::DefaultOptions(false)) << "Forcing blocklisting all features";
     601           0 :     *aStatus = FEATURE_BLOCKED_DEVICE;
     602           0 :     aFailureId = "FEATURE_FAILURE_BLOCK_ALL";
     603           0 :     return NS_OK;
     604          50 :   } else if (blocklistAll < 0) {
     605           0 :     gfxCriticalErrorOnce(gfxCriticalError::DefaultOptions(false)) << "Ignoring any feature blocklisting.";
     606           0 :     *aStatus = FEATURE_STATUS_OK;
     607           0 :     return NS_OK;
     608             :   }
     609             : 
     610          50 :   if (GetPrefValueForFeature(aFeature, *aStatus, aFailureId)) {
     611           0 :     return NS_OK;
     612             :   }
     613             : 
     614          50 :   if (XRE_IsContentProcess()) {
     615             :     // Use the cached data received from the parent process.
     616           2 :     MOZ_ASSERT(mFeatureStatus);
     617           2 :     bool success = false;
     618          24 :     for (const auto& fs : *mFeatureStatus) {
     619          24 :       if (fs.feature() == aFeature) {
     620           2 :         aFailureId = fs.failureId();
     621           2 :         *aStatus = fs.status();
     622           2 :         success = true;
     623           2 :         break;
     624             :       }
     625             :     }
     626           2 :     return success ? NS_OK : NS_ERROR_FAILURE;
     627             :   }
     628             : 
     629          96 :   nsString version;
     630          96 :   nsTArray<GfxDriverInfo> driverInfo;
     631          48 :   nsresult rv = GetFeatureStatusImpl(aFeature, aStatus, version, driverInfo, aFailureId);
     632          48 :   return rv;
     633             : }
     634             : 
     635             : // Matching OS go somewhat beyond the simple equality check because of the
     636             : // "All Windows" and "All OS X" variations.
     637             : //
     638             : // aBlockedOS is describing the system(s) we are trying to block.
     639             : // aSystemOS is describing the system we are running on.
     640             : //
     641             : // aSystemOS should not be "Windows" or "OSX" - it should be set to
     642             : // a particular version instead.
     643             : // However, it is valid for aBlockedOS to be one of those generic values,
     644             : // as we could be blocking all of the versions.
     645             : inline bool
     646           0 : MatchingOperatingSystems(OperatingSystem aBlockedOS, OperatingSystem aSystemOS)
     647             : {
     648           0 :   MOZ_ASSERT(aSystemOS != OperatingSystem::Windows &&
     649             :              aSystemOS != OperatingSystem::OSX);
     650             : 
     651             :   // If the block entry OS is unknown, it doesn't match
     652           0 :   if (aBlockedOS == OperatingSystem::Unknown) {
     653           0 :     return false;
     654             :   }
     655             : 
     656             : #if defined (XP_WIN)
     657             :   if (aBlockedOS == OperatingSystem::Windows) {
     658             :     // We do want even "unknown" aSystemOS to fall under "all windows"
     659             :     return true;
     660             :   }
     661             : #endif
     662             : 
     663             : #if defined (XP_MACOSX)
     664             :   if (aBlockedOS == OperatingSystem::OSX) {
     665             :     // We do want even "unknown" aSystemOS to fall under "all OS X"
     666             :     return true;
     667             :   }
     668             : #endif
     669             : 
     670           0 :   return aSystemOS == aBlockedOS;
     671             : }
     672             : 
     673             : int32_t
     674          48 : GfxInfoBase::FindBlocklistedDeviceInList(const nsTArray<GfxDriverInfo>& info,
     675             :                                          nsAString& aSuggestedVersion,
     676             :                                          int32_t aFeature,
     677             :                                          nsACString& aFailureId,
     678             :                                          OperatingSystem os)
     679             : {
     680          48 :   int32_t status = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
     681             : 
     682             :   // Get the adapters once then reuse below
     683          96 :   nsAutoString adapterVendorID[2];
     684          96 :   nsAutoString adapterDeviceID[2];
     685          96 :   nsAutoString adapterDriverVersionString[2];
     686             :   bool adapterInfoFailed[2];
     687             : 
     688         144 :   adapterInfoFailed[0] = (NS_FAILED(GetAdapterVendorID(adapterVendorID[0])) ||
     689          96 :                           NS_FAILED(GetAdapterDeviceID(adapterDeviceID[0])) ||
     690          48 :                           NS_FAILED(GetAdapterDriverVersion(adapterDriverVersionString[0])));
     691          96 :   adapterInfoFailed[1] = (NS_FAILED(GetAdapterVendorID2(adapterVendorID[1])) ||
     692          48 :                           NS_FAILED(GetAdapterDeviceID2(adapterDeviceID[1])) ||
     693           0 :                           NS_FAILED(GetAdapterDriverVersion2(adapterDriverVersionString[1])));
     694             :   // No point in going on if we don't have adapter info
     695          48 :   if (adapterInfoFailed[0] && adapterInfoFailed[1]) {
     696           0 :     return 0;
     697             :   }
     698             : 
     699             : #if defined(XP_WIN) || defined(ANDROID)
     700             :   uint64_t driverVersion[2] = {0, 0};
     701             :   if (!adapterInfoFailed[0]) {
     702             :     ParseDriverVersion(adapterDriverVersionString[0], &driverVersion[0]);
     703             :   }
     704             :   if (!adapterInfoFailed[1]) {
     705             :     ParseDriverVersion(adapterDriverVersionString[1], &driverVersion[1]);
     706             :   }
     707             : #endif
     708             : 
     709          48 :   uint32_t i = 0;
     710          48 :   for (; i < info.Length(); i++) {
     711             :     // If we don't have the info for this GPU, no need to check further.
     712             :     // It is unclear that we would ever have a mixture of 1st and 2nd
     713             :     // GPU, but leaving the code in for that possibility for now.
     714             :     // (Actually, currently mGpu2 will never be true, so this can
     715             :     // be optimized out.)
     716           0 :     uint32_t infoIndex = info[i].mGpu2 ? 1 : 0;
     717           0 :     if (adapterInfoFailed[infoIndex]) {
     718           0 :       continue;
     719             :     }
     720             : 
     721             :     // Do the operating system check first, no point in getting the driver
     722             :     // info if we won't need to use it.
     723           0 :     if (!MatchingOperatingSystems(info[i].mOperatingSystem, os)) {
     724           0 :       continue;
     725             :     }
     726             : 
     727           0 :     if (info[i].mOperatingSystemVersion && info[i].mOperatingSystemVersion != OperatingSystemVersion()) {
     728           0 :         continue;
     729             :     }
     730             : 
     731           0 :     if (!info[i].mAdapterVendor.Equals(GfxDriverInfo::GetDeviceVendor(VendorAll), nsCaseInsensitiveStringComparator()) &&
     732           0 :         !info[i].mAdapterVendor.Equals(adapterVendorID[infoIndex], nsCaseInsensitiveStringComparator())) {
     733           0 :       continue;
     734             :     }
     735             : 
     736           0 :     if (info[i].mDevices != GfxDriverInfo::allDevices && info[i].mDevices->Length()) {
     737           0 :         bool deviceMatches = false;
     738           0 :         for (uint32_t j = 0; j < info[i].mDevices->Length(); j++) {
     739           0 :             if ((*info[i].mDevices)[j].Equals(adapterDeviceID[infoIndex], nsCaseInsensitiveStringComparator())) {
     740           0 :                 deviceMatches = true;
     741           0 :                 break;
     742             :             }
     743             :         }
     744             : 
     745           0 :         if (!deviceMatches) {
     746           0 :             continue;
     747             :         }
     748             :     }
     749             : 
     750           0 :     bool match = false;
     751             : 
     752           0 :     if (!info[i].mHardware.IsEmpty() && !info[i].mHardware.Equals(Hardware())) {
     753           0 :         continue;
     754             :     }
     755           0 :     if (!info[i].mModel.IsEmpty() && !info[i].mModel.Equals(Model())) {
     756           0 :         continue;
     757             :     }
     758           0 :     if (!info[i].mProduct.IsEmpty() && !info[i].mProduct.Equals(Product())) {
     759           0 :         continue;
     760             :     }
     761           0 :     if (!info[i].mManufacturer.IsEmpty() && !info[i].mManufacturer.Equals(Manufacturer())) {
     762           0 :         continue;
     763             :     }
     764             : 
     765             : #if defined(XP_WIN) || defined(ANDROID)
     766             :     switch (info[i].mComparisonOp) {
     767             :     case DRIVER_LESS_THAN:
     768             :       match = driverVersion[infoIndex] < info[i].mDriverVersion;
     769             :       break;
     770             :     case DRIVER_BUILD_ID_LESS_THAN:
     771             :       match = (driverVersion[infoIndex] & 0xFFFF) < info[i].mDriverVersion;
     772             :       break;
     773             :     case DRIVER_LESS_THAN_OR_EQUAL:
     774             :       match = driverVersion[infoIndex] <= info[i].mDriverVersion;
     775             :       break;
     776             :     case DRIVER_BUILD_ID_LESS_THAN_OR_EQUAL:
     777             :       match = (driverVersion[infoIndex] & 0xFFFF) <= info[i].mDriverVersion;
     778             :       break;
     779             :     case DRIVER_GREATER_THAN:
     780             :       match = driverVersion[infoIndex] > info[i].mDriverVersion;
     781             :       break;
     782             :     case DRIVER_GREATER_THAN_OR_EQUAL:
     783             :       match = driverVersion[infoIndex] >= info[i].mDriverVersion;
     784             :       break;
     785             :     case DRIVER_EQUAL:
     786             :       match = driverVersion[infoIndex] == info[i].mDriverVersion;
     787             :       break;
     788             :     case DRIVER_NOT_EQUAL:
     789             :       match = driverVersion[infoIndex] != info[i].mDriverVersion;
     790             :       break;
     791             :     case DRIVER_BETWEEN_EXCLUSIVE:
     792             :       match = driverVersion[infoIndex] > info[i].mDriverVersion && driverVersion[infoIndex] < info[i].mDriverVersionMax;
     793             :       break;
     794             :     case DRIVER_BETWEEN_INCLUSIVE:
     795             :       match = driverVersion[infoIndex] >= info[i].mDriverVersion && driverVersion[infoIndex] <= info[i].mDriverVersionMax;
     796             :       break;
     797             :     case DRIVER_BETWEEN_INCLUSIVE_START:
     798             :       match = driverVersion[infoIndex] >= info[i].mDriverVersion && driverVersion[infoIndex] < info[i].mDriverVersionMax;
     799             :       break;
     800             :     case DRIVER_COMPARISON_IGNORED:
     801             :       // We don't have a comparison op, so we match everything.
     802             :       match = true;
     803             :       break;
     804             :     default:
     805             :       NS_WARNING("Bogus op in GfxDriverInfo");
     806             :       break;
     807             :     }
     808             : #else
     809             :     // We don't care what driver version it was. We only check OS version and if
     810             :     // the device matches.
     811           0 :     match = true;
     812             : #endif
     813             : 
     814           0 :     if (match || info[i].mDriverVersion == GfxDriverInfo::allDriverVersions) {
     815           0 :       if (info[i].mFeature == GfxDriverInfo::allFeatures ||
     816           0 :           info[i].mFeature == aFeature)
     817             :       {
     818           0 :         status = info[i].mFeatureStatus;
     819           0 :         if (!info[i].mRuleId.IsEmpty()) {
     820           0 :           aFailureId = info[i].mRuleId.get();
     821             :         } else {
     822           0 :           aFailureId = "FEATURE_FAILURE_DL_BLACKLIST_NO_ID";
     823             :         }
     824           0 :         break;
     825             :       }
     826             :     }
     827             :   }
     828             : 
     829             : #if defined(XP_WIN)
     830             :   // As a very special case, we block D2D on machines with an NVidia 310M GPU
     831             :   // as either the primary or secondary adapter.  D2D is also blocked when the
     832             :   // NV 310M is the primary adapter (using the standard blocklisting mechanism).
     833             :   // If the primary GPU already matched something in the blocklist then we
     834             :   // ignore this special rule.  See bug 1008759.
     835             :   if (status == nsIGfxInfo::FEATURE_STATUS_UNKNOWN &&
     836             :     (aFeature == nsIGfxInfo::FEATURE_DIRECT2D)) {
     837             :     if (!adapterInfoFailed[1]) {
     838             :       nsAString &nvVendorID = (nsAString &)GfxDriverInfo::GetDeviceVendor(VendorNVIDIA);
     839             :       const nsString nv310mDeviceId = NS_LITERAL_STRING("0x0A70");
     840             :       if (nvVendorID.Equals(adapterVendorID[1], nsCaseInsensitiveStringComparator()) &&
     841             :         nv310mDeviceId.Equals(adapterDeviceID[1], nsCaseInsensitiveStringComparator())) {
     842             :         status = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
     843             :         aFailureId = "FEATURE_FAILURE_D2D_NV310M_BLOCK";
     844             :       }
     845             :     }
     846             :   }
     847             : 
     848             :   // Depends on Windows driver versioning. We don't pass a GfxDriverInfo object
     849             :   // back to the Windows handler, so we must handle this here.
     850             :   if (status == FEATURE_BLOCKED_DRIVER_VERSION) {
     851             :     if (info[i].mSuggestedVersion) {
     852             :         aSuggestedVersion.AppendPrintf("%s", info[i].mSuggestedVersion);
     853             :     } else if (info[i].mComparisonOp == DRIVER_LESS_THAN &&
     854             :                info[i].mDriverVersion != GfxDriverInfo::allDriverVersions)
     855             :     {
     856             :         aSuggestedVersion.AppendPrintf("%lld.%lld.%lld.%lld",
     857             :                                       (info[i].mDriverVersion & 0xffff000000000000) >> 48,
     858             :                                       (info[i].mDriverVersion & 0x0000ffff00000000) >> 32,
     859             :                                       (info[i].mDriverVersion & 0x00000000ffff0000) >> 16,
     860             :                                       (info[i].mDriverVersion & 0x000000000000ffff));
     861             :     }
     862             :   }
     863             : #endif
     864             : 
     865          48 :   return status;
     866             : }
     867             : 
     868             : void
     869           2 : GfxInfoBase::SetFeatureStatus(const nsTArray<dom::GfxInfoFeatureStatus>& aFS)
     870             : {
     871           2 :   MOZ_ASSERT(!mFeatureStatus);
     872           2 :   mFeatureStatus = new nsTArray<dom::GfxInfoFeatureStatus>(aFS);
     873           2 : }
     874             : 
     875             : nsresult
     876          48 : GfxInfoBase::GetFeatureStatusImpl(int32_t aFeature,
     877             :                                   int32_t* aStatus,
     878             :                                   nsAString& aSuggestedVersion,
     879             :                                   const nsTArray<GfxDriverInfo>& aDriverInfo,
     880             :                                   nsACString& aFailureId,
     881             :                                   OperatingSystem* aOS /* = nullptr */)
     882             : {
     883          48 :   if (aFeature <= 0) {
     884           0 :     gfxWarning() << "Invalid feature <= 0";
     885           0 :     return NS_OK;
     886             :   }
     887             : 
     888          48 :   if (*aStatus != nsIGfxInfo::FEATURE_STATUS_UNKNOWN) {
     889             :     // Terminate now with the status determined by the derived type (OS-specific
     890             :     // code).
     891           0 :     return NS_OK;
     892             :   }
     893             : 
     894          48 :   if (mShutdownOccurred) {
     895             :     // This is futile; we've already commenced shutdown and our blocklists have
     896             :     // been deleted. We may want to look into resurrecting the blocklist instead
     897             :     // but for now, just don't even go there.
     898           0 :     return NS_OK;
     899             :   }
     900             : 
     901             :   // If an operating system was provided by the derived GetFeatureStatusImpl,
     902             :   // grab it here. Otherwise, the OS is unknown.
     903          48 :   OperatingSystem os = (aOS ? *aOS : OperatingSystem::Unknown);
     904             : 
     905          96 :   nsAutoString adapterVendorID;
     906          96 :   nsAutoString adapterDeviceID;
     907          96 :   nsAutoString adapterDriverVersionString;
     908         144 :   if (NS_FAILED(GetAdapterVendorID(adapterVendorID)) ||
     909          96 :       NS_FAILED(GetAdapterDeviceID(adapterDeviceID)) ||
     910          48 :       NS_FAILED(GetAdapterDriverVersion(adapterDriverVersionString)))
     911             :   {
     912           0 :     aFailureId = "FEATURE_FAILURE_CANT_RESOLVE_ADAPTER";
     913           0 :     *aStatus = FEATURE_BLOCKED_DEVICE;
     914           0 :     return NS_OK;
     915             :   }
     916             : 
     917             :   // Check if the device is blocked from the downloaded blocklist. If not, check
     918             :   // the static list after that. This order is used so that we can later escape
     919             :   // out of static blocks (i.e. if we were wrong or something was patched, we
     920             :   // can back out our static block without doing a release).
     921             :   int32_t status;
     922          48 :   if (aDriverInfo.Length()) {
     923           0 :     status = FindBlocklistedDeviceInList(aDriverInfo, aSuggestedVersion, aFeature, aFailureId, os);
     924             :   } else {
     925          48 :     if (!mDriverInfo) {
     926           1 :       mDriverInfo = new nsTArray<GfxDriverInfo>();
     927             :     }
     928          48 :     status = FindBlocklistedDeviceInList(GetGfxDriverInfo(), aSuggestedVersion, aFeature, aFailureId, os);
     929             :   }
     930             : 
     931             :   // It's now done being processed. It's safe to set the status to STATUS_OK.
     932          48 :   if (status == nsIGfxInfo::FEATURE_STATUS_UNKNOWN) {
     933          48 :     *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
     934             :   } else {
     935           0 :     *aStatus = status;
     936             :   }
     937             : 
     938          48 :   return NS_OK;
     939             : }
     940             : 
     941             : NS_IMETHODIMP
     942           0 : GfxInfoBase::GetFeatureSuggestedDriverVersion(int32_t aFeature,
     943             :                                               nsAString& aVersion)
     944             : {
     945           0 :   nsCString version;
     946           0 :   if (GetPrefValueForDriverVersion(version)) {
     947           0 :     aVersion = NS_ConvertASCIItoUTF16(version);
     948           0 :     return NS_OK;
     949             :   }
     950             : 
     951             :   int32_t status;
     952           0 :   nsCString discardFailureId;
     953           0 :   nsTArray<GfxDriverInfo> driverInfo;
     954           0 :   return GetFeatureStatusImpl(aFeature, &status, aVersion, driverInfo, discardFailureId);
     955             : }
     956             : 
     957             : 
     958             : NS_IMETHODIMP
     959           0 : GfxInfoBase::GetWebGLParameter(const nsAString& aParam,
     960             :                                nsAString& aResult)
     961             : {
     962           0 :   return GfxInfoWebGL::GetWebGLParameter(aParam, aResult);
     963             : }
     964             : 
     965             : void
     966           0 : GfxInfoBase::EvaluateDownloadedBlacklist(nsTArray<GfxDriverInfo>& aDriverInfo)
     967             : {
     968             :   int32_t features[] = {
     969             :     nsIGfxInfo::FEATURE_DIRECT2D,
     970             :     nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS,
     971             :     nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS,
     972             :     nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS,
     973             :     nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS,
     974             :     nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE,
     975             :     nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING,
     976             :     nsIGfxInfo::FEATURE_OPENGL_LAYERS,
     977             :     nsIGfxInfo::FEATURE_WEBGL_OPENGL,
     978             :     nsIGfxInfo::FEATURE_WEBGL_ANGLE,
     979             :     nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_ENCODE,
     980             :     nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_DECODE,
     981             :     nsIGfxInfo::FEATURE_WEBGL_MSAA,
     982             :     nsIGfxInfo::FEATURE_STAGEFRIGHT,
     983             :     nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION,
     984             :     nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION,
     985             :     nsIGfxInfo::FEATURE_WEBGL2,
     986             :     0
     987           0 :   };
     988             : 
     989             :   // For every feature we know about, we evaluate whether this blacklist has a
     990             :   // non-STATUS_OK status. If it does, we set the pref we evaluate in
     991             :   // GetFeatureStatus above, so we don't need to hold on to this blacklist
     992             :   // anywhere permanent.
     993           0 :   int i = 0;
     994           0 :   while (features[i]) {
     995             :     int32_t status;
     996           0 :     nsCString failureId;
     997           0 :     nsAutoString suggestedVersion;
     998           0 :     if (NS_SUCCEEDED(GetFeatureStatusImpl(features[i], &status,
     999             :                                           suggestedVersion,
    1000             :                                           aDriverInfo,
    1001             :                                           failureId))) {
    1002           0 :       switch (status) {
    1003             :         default:
    1004             :         case nsIGfxInfo::FEATURE_STATUS_OK:
    1005           0 :           RemovePrefForFeature(features[i]);
    1006           0 :           break;
    1007             : 
    1008             :         case nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION:
    1009           0 :           if (!suggestedVersion.IsEmpty()) {
    1010           0 :             SetPrefValueForDriverVersion(suggestedVersion);
    1011             :           } else {
    1012           0 :             RemovePrefForDriverVersion();
    1013             :           }
    1014             :           MOZ_FALLTHROUGH;
    1015             : 
    1016             :         case nsIGfxInfo::FEATURE_BLOCKED_MISMATCHED_VERSION:
    1017             :         case nsIGfxInfo::FEATURE_BLOCKED_DEVICE:
    1018             :         case nsIGfxInfo::FEATURE_DISCOURAGED:
    1019             :         case nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION:
    1020           0 :           SetPrefValueForFeature(features[i], status, failureId);
    1021           0 :           break;
    1022             :       }
    1023             :     }
    1024             : 
    1025           0 :     ++i;
    1026             :   }
    1027           0 : }
    1028             : 
    1029             : NS_IMETHODIMP_(void)
    1030           0 : GfxInfoBase::LogFailure(const nsACString &failure)
    1031             : {
    1032             :   // gfxCriticalError has a mutex lock of its own, so we may not actually
    1033             :   // need this lock. ::GetFailures() accesses the data but the LogForwarder
    1034             :   // will not return the copy of the logs unless it can get the same lock
    1035             :   // that gfxCriticalError uses.  Still, that is so much of an implementation
    1036             :   // detail that it's nicer to just add an extra lock here and in ::GetFailures()
    1037           0 :   MutexAutoLock lock(mMutex);
    1038             : 
    1039             :   // By default, gfxCriticalError asserts; make it not assert in this case.
    1040           0 :   gfxCriticalError(CriticalLog::DefaultOptions(false)) << "(LF) " << failure.BeginReading();
    1041           0 : }
    1042             : 
    1043             : /* XPConnect method of returning arrays is very ugly. Would not recommend. */
    1044           0 : NS_IMETHODIMP GfxInfoBase::GetFailures(uint32_t* failureCount,
    1045             :                                        int32_t** indices,
    1046             :                                        char ***failures)
    1047             : {
    1048           0 :   MutexAutoLock lock(mMutex);
    1049             : 
    1050           0 :   NS_ENSURE_ARG_POINTER(failureCount);
    1051           0 :   NS_ENSURE_ARG_POINTER(failures);
    1052             : 
    1053           0 :   *failures = nullptr;
    1054           0 :   *failureCount = 0;
    1055             : 
    1056             :   // indices is "allowed" to be null, the caller may not care about them,
    1057             :   // although calling from JS doesn't seem to get us there.
    1058           0 :   if (indices) *indices = nullptr;
    1059             : 
    1060           0 :   LogForwarder* logForwarder = Factory::GetLogForwarder();
    1061           0 :   if (!logForwarder) {
    1062           0 :     return NS_ERROR_UNEXPECTED;
    1063             :   }
    1064             : 
    1065             :   // There are two stirng copies in this method, starting with this one. We are
    1066             :   // assuming this is not a big deal, as the size of the array should be small
    1067             :   // and the strings in it should be small as well (the error messages in the
    1068             :   // code.)  The second copy happens with the Clone() calls.  Technically,
    1069             :   // we don't need the mutex lock after the StringVectorCopy() call.
    1070           0 :   LoggingRecord loggedStrings = logForwarder->LoggingRecordCopy();
    1071           0 :   *failureCount = loggedStrings.size();
    1072             : 
    1073           0 :   if (*failureCount != 0) {
    1074           0 :     *failures = (char**)moz_xmalloc(*failureCount * sizeof(char*));
    1075           0 :     if (!(*failures)) {
    1076           0 :       return NS_ERROR_OUT_OF_MEMORY;
    1077             :     }
    1078           0 :     if (indices) {
    1079           0 :       *indices = (int32_t*)moz_xmalloc(*failureCount * sizeof(int32_t));
    1080           0 :       if (!(*indices)) {
    1081           0 :         free(*failures);
    1082           0 :         *failures = nullptr;
    1083           0 :         return NS_ERROR_OUT_OF_MEMORY;
    1084             :       }
    1085             :     }
    1086             : 
    1087             :     /* copy over the failure messages into the array we just allocated */
    1088           0 :     LoggingRecord::const_iterator it;
    1089           0 :     uint32_t i=0;
    1090           0 :     for(it = loggedStrings.begin() ; it != loggedStrings.end(); ++it, i++) {
    1091           0 :       (*failures)[i] = (char*)nsMemory::Clone(Get<1>(*it).c_str(), Get<1>(*it).size() + 1);
    1092           0 :       if (indices) (*indices)[i] = Get<0>(*it);
    1093             : 
    1094           0 :       if (!(*failures)[i]) {
    1095             :         /* <sarcasm> I'm too afraid to use an inline function... </sarcasm> */
    1096           0 :         NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, (*failures));
    1097           0 :         *failureCount = i;
    1098           0 :         return NS_ERROR_OUT_OF_MEMORY;
    1099             :       }
    1100             :     }
    1101             :   }
    1102             : 
    1103           0 :   return NS_OK;
    1104             : }
    1105             : 
    1106             : nsTArray<GfxInfoCollectorBase*> *sCollectors;
    1107             : 
    1108             : static void
    1109           9 : InitCollectors()
    1110             : {
    1111           9 :   if (!sCollectors)
    1112           3 :     sCollectors = new nsTArray<GfxInfoCollectorBase*>;
    1113           9 : }
    1114             : 
    1115           0 : nsresult GfxInfoBase::GetInfo(JSContext* aCx, JS::MutableHandle<JS::Value> aResult)
    1116             : {
    1117           0 :   InitCollectors();
    1118           0 :   InfoObject obj(aCx);
    1119             : 
    1120           0 :   for (uint32_t i = 0; i < sCollectors->Length(); i++) {
    1121           0 :     (*sCollectors)[i]->GetInfo(obj);
    1122             :   }
    1123             : 
    1124             :   // Some example property definitions
    1125             :   // obj.DefineProperty("wordCacheSize", gfxTextRunWordCache::Count());
    1126             :   // obj.DefineProperty("renderer", mRendererIDsString);
    1127             :   // obj.DefineProperty("five", 5);
    1128             : 
    1129           0 :   if (!obj.mOk) {
    1130           0 :     return NS_ERROR_FAILURE;
    1131             :   }
    1132             : 
    1133           0 :   aResult.setObject(*obj.mObj);
    1134           0 :   return NS_OK;
    1135             : }
    1136             : 
    1137           3 : nsAutoCString gBaseAppVersion;
    1138             : 
    1139             : const nsCString&
    1140           0 : GfxInfoBase::GetApplicationVersion()
    1141             : {
    1142             :   static bool versionInitialized = false;
    1143           0 :   if (!versionInitialized) {
    1144             :     // If we fail to get the version, we will not try again.
    1145           0 :     versionInitialized = true;
    1146             : 
    1147             :     // Get the version from xpcom/system/nsIXULAppInfo.idl
    1148           0 :     nsCOMPtr<nsIXULAppInfo> app = do_GetService("@mozilla.org/xre/app-info;1");
    1149           0 :     if (app) {
    1150           0 :       app->GetVersion(gBaseAppVersion);
    1151             :     }
    1152             :   }
    1153           0 :   return gBaseAppVersion;
    1154             : }
    1155             : 
    1156             : void
    1157           9 : GfxInfoBase::AddCollector(GfxInfoCollectorBase* collector)
    1158             : {
    1159           9 :   InitCollectors();
    1160           9 :   sCollectors->AppendElement(collector);
    1161           9 : }
    1162             : 
    1163             : void
    1164           0 : GfxInfoBase::RemoveCollector(GfxInfoCollectorBase* collector)
    1165             : {
    1166           0 :   InitCollectors();
    1167           0 :   for (uint32_t i = 0; i < sCollectors->Length(); i++) {
    1168           0 :     if ((*sCollectors)[i] == collector) {
    1169           0 :       sCollectors->RemoveElementAt(i);
    1170           0 :       break;
    1171             :     }
    1172             :   }
    1173           0 :   if (sCollectors->IsEmpty()) {
    1174           0 :     delete sCollectors;
    1175           0 :     sCollectors = nullptr;
    1176             :   }
    1177           0 : }
    1178             : 
    1179             : NS_IMETHODIMP
    1180           0 : GfxInfoBase::GetMonitors(JSContext* aCx, JS::MutableHandleValue aResult)
    1181             : {
    1182           0 :   JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, 0));
    1183             : 
    1184           0 :   nsresult rv = FindMonitors(aCx, array);
    1185           0 :   if (NS_FAILED(rv)) {
    1186           0 :     return rv;
    1187             :   }
    1188             : 
    1189           0 :   aResult.setObject(*array);
    1190           0 :   return NS_OK;
    1191             : }
    1192             : 
    1193             : static const char*
    1194           2 : GetLayersBackendName(layers::LayersBackend aBackend)
    1195             : {
    1196           2 :   switch (aBackend) {
    1197             :     case layers::LayersBackend::LAYERS_NONE:
    1198           1 :       return "none";
    1199             :     case layers::LayersBackend::LAYERS_OPENGL:
    1200           0 :       return "opengl";
    1201             :     case layers::LayersBackend::LAYERS_D3D11:
    1202           0 :       return "d3d11";
    1203             :     case layers::LayersBackend::LAYERS_CLIENT:
    1204           0 :       return "client";
    1205             :     case layers::LayersBackend::LAYERS_WR:
    1206           0 :       return "webrender";
    1207             :     case layers::LayersBackend::LAYERS_BASIC:
    1208           1 :       return "basic";
    1209             :     default:
    1210           0 :       MOZ_ASSERT_UNREACHABLE("unknown layers backend");
    1211             :       return "unknown";
    1212             :   }
    1213             : }
    1214             : 
    1215             : static inline bool
    1216           2 : SetJSPropertyString(JSContext* aCx, JS::Handle<JSObject*> aObj,
    1217             :                     const char* aProp, const char* aString)
    1218             : {
    1219           4 :   JS::Rooted<JSString*> str(aCx, JS_NewStringCopyZ(aCx, aString));
    1220           2 :   if (!str) {
    1221           0 :     return false;
    1222             :   }
    1223             : 
    1224           4 :   JS::Rooted<JS::Value> val(aCx, JS::StringValue(str));
    1225           2 :   return JS_SetProperty(aCx, aObj, aProp, val);
    1226             : }
    1227             : 
    1228             : template <typename T>
    1229             : static inline bool
    1230           0 : AppendJSElement(JSContext* aCx, JS::Handle<JSObject*> aObj, const T& aValue)
    1231             : {
    1232             :   uint32_t index;
    1233           0 :   if (!JS_GetArrayLength(aCx, aObj, &index)) {
    1234           0 :     return false;
    1235             :   }
    1236           0 :   return JS_SetElement(aCx, aObj, index, aValue);
    1237             : }
    1238             : 
    1239             : nsresult
    1240           2 : GfxInfoBase::GetFeatures(JSContext* aCx, JS::MutableHandle<JS::Value> aOut)
    1241             : {
    1242           4 :   JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
    1243           2 :   if (!obj) {
    1244           0 :     return NS_ERROR_OUT_OF_MEMORY;
    1245             :   }
    1246           2 :   aOut.setObject(*obj);
    1247             : 
    1248           2 :   layers::LayersBackend backend = gfxPlatform::Initialized()
    1249           2 :                                   ? gfxPlatform::GetPlatform()->GetCompositorBackend()
    1250           2 :                                   : layers::LayersBackend::LAYERS_NONE;
    1251           2 :   const char* backendName = GetLayersBackendName(backend);
    1252           2 :   SetJSPropertyString(aCx, obj, "compositor", backendName);
    1253             : 
    1254             :   // If graphics isn't initialized yet, just stop now.
    1255           2 :   if (!gfxPlatform::Initialized()) {
    1256           0 :     return NS_OK;
    1257             :   }
    1258             : 
    1259           2 :   DescribeFeatures(aCx, obj);
    1260           2 :   return NS_OK;
    1261             : }
    1262             : 
    1263           0 : nsresult GfxInfoBase::GetFeatureLog(JSContext* aCx, JS::MutableHandle<JS::Value> aOut)
    1264             : {
    1265           0 :   JS::Rooted<JSObject*> containerObj(aCx, JS_NewPlainObject(aCx));
    1266           0 :   if (!containerObj) {
    1267           0 :     return NS_ERROR_OUT_OF_MEMORY;
    1268             :   }
    1269           0 :   aOut.setObject(*containerObj);
    1270             : 
    1271           0 :   JS::Rooted<JSObject*> featureArray(aCx, JS_NewArrayObject(aCx, 0));
    1272           0 :   if (!featureArray) {
    1273           0 :     return NS_ERROR_OUT_OF_MEMORY;
    1274             :   }
    1275             : 
    1276             :   // Collect features.
    1277           0 :   gfxConfig::ForEachFeature([&](const char* aName,
    1278             :                                 const char* aDescription,
    1279           0 :                                 FeatureState& aFeature) -> void {
    1280           0 :     JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
    1281           0 :     if (!obj) {
    1282           0 :       return;
    1283             :     }
    1284           0 :     if (!SetJSPropertyString(aCx, obj, "name", aName) ||
    1285           0 :         !SetJSPropertyString(aCx, obj, "description", aDescription) ||
    1286           0 :         !SetJSPropertyString(aCx, obj, "status", FeatureStatusToString(aFeature.GetValue())))
    1287             :     {
    1288           0 :       return;
    1289             :     }
    1290             : 
    1291           0 :     JS::Rooted<JS::Value> log(aCx);
    1292           0 :     if (!BuildFeatureStateLog(aCx, aFeature, &log)) {
    1293           0 :       return;
    1294             :     }
    1295           0 :     if (!JS_SetProperty(aCx, obj, "log", log)) {
    1296           0 :       return;
    1297             :     }
    1298             : 
    1299           0 :     if (!AppendJSElement(aCx, featureArray, obj)) {
    1300           0 :       return;
    1301             :     }
    1302           0 :   });
    1303             : 
    1304           0 :   JS::Rooted<JSObject*> fallbackArray(aCx, JS_NewArrayObject(aCx, 0));
    1305           0 :   if (!fallbackArray) {
    1306           0 :     return NS_ERROR_OUT_OF_MEMORY;
    1307             :   }
    1308             : 
    1309             :   // Collect fallbacks.
    1310           0 :   gfxConfig::ForEachFallback([&](const char* aName, const char* aMessage) -> void {
    1311           0 :     JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
    1312           0 :     if (!obj) {
    1313           0 :       return;
    1314             :     }
    1315             : 
    1316           0 :     if (!SetJSPropertyString(aCx, obj, "name", aName) ||
    1317           0 :         !SetJSPropertyString(aCx, obj, "message", aMessage))
    1318             :     {
    1319           0 :       return;
    1320             :     }
    1321             : 
    1322           0 :     if (!AppendJSElement(aCx, fallbackArray, obj)) {
    1323           0 :       return;
    1324             :     }
    1325           0 :   });
    1326             : 
    1327           0 :   JS::Rooted<JS::Value> val(aCx);
    1328             : 
    1329           0 :   val = JS::ObjectValue(*featureArray);
    1330           0 :   JS_SetProperty(aCx, containerObj, "features", val);
    1331             : 
    1332           0 :   val = JS::ObjectValue(*fallbackArray);
    1333           0 :   JS_SetProperty(aCx, containerObj, "fallbacks", val);
    1334             : 
    1335           0 :   return NS_OK;
    1336             : }
    1337             : 
    1338             : bool
    1339           0 : GfxInfoBase::BuildFeatureStateLog(JSContext* aCx, const FeatureState& aFeature,
    1340             :                                   JS::MutableHandle<JS::Value> aOut)
    1341             : {
    1342           0 :   JS::Rooted<JSObject*> log(aCx, JS_NewArrayObject(aCx, 0));
    1343           0 :   if (!log) {
    1344           0 :     return false;
    1345             :   }
    1346           0 :   aOut.setObject(*log);
    1347             : 
    1348           0 :   aFeature.ForEachStatusChange([&](const char* aType,
    1349             :                                    FeatureStatus aStatus,
    1350           0 :                                    const char* aMessage) -> void {
    1351           0 :     JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
    1352           0 :     if (!obj) {
    1353           0 :       return;
    1354             :     }
    1355             : 
    1356           0 :     if (!SetJSPropertyString(aCx, obj, "type", aType) ||
    1357           0 :         !SetJSPropertyString(aCx, obj, "status", FeatureStatusToString(aStatus)) ||
    1358           0 :         (aMessage && !SetJSPropertyString(aCx, obj, "message", aMessage)))
    1359             :     {
    1360           0 :       return;
    1361             :     }
    1362             : 
    1363           0 :     if (!AppendJSElement(aCx, log, obj)) {
    1364           0 :       return;
    1365             :     }
    1366           0 :   });
    1367             : 
    1368           0 :   return true;
    1369             : }
    1370             : 
    1371             : void
    1372           2 : GfxInfoBase::DescribeFeatures(JSContext* aCx, JS::Handle<JSObject*> aObj)
    1373             : {
    1374           4 :   JS::Rooted<JSObject*> obj(aCx);
    1375             : 
    1376           2 :   gfx::FeatureStatus gpuProcess = gfxConfig::GetValue(Feature::GPU_PROCESS);
    1377           2 :   InitFeatureObject(aCx, aObj, "gpuProcess", FEATURE_GPU_PROCESS, Some(gpuProcess), &obj);
    1378             : 
    1379             :   // Only include AL if the platform attempted to use it.
    1380           2 :   gfx::FeatureStatus advancedLayers = gfxConfig::GetValue(Feature::ADVANCED_LAYERS);
    1381           2 :   if (advancedLayers != FeatureStatus::Unused) {
    1382           0 :     InitFeatureObject(aCx, aObj, "advancedLayers", FEATURE_ADVANCED_LAYERS,
    1383           0 :                       Some(advancedLayers), &obj);
    1384             : 
    1385           0 :     if (gfxConfig::UseFallback(Fallback::NO_CONSTANT_BUFFER_OFFSETTING)) {
    1386           0 :       JS::Rooted<JS::Value> trueVal(aCx, JS::BooleanValue(true));
    1387           0 :       JS_SetProperty(aCx, obj, "noConstantBufferOffsetting", trueVal);
    1388             :     }
    1389             :   }
    1390           2 : }
    1391             : 
    1392             : bool
    1393           2 : GfxInfoBase::InitFeatureObject(JSContext* aCx,
    1394             :                                JS::Handle<JSObject*> aContainer,
    1395             :                                const char* aName,
    1396             :                                int32_t aFeature,
    1397             :                                const Maybe<mozilla::gfx::FeatureStatus>& aFeatureStatus,
    1398             :                                JS::MutableHandle<JSObject*> aOutObj)
    1399             : {
    1400           4 :   JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
    1401           2 :   if (!obj) {
    1402           0 :     return false;
    1403             :   }
    1404             : 
    1405           4 :   nsCString failureId = NS_LITERAL_CSTRING("OK");
    1406             :   int32_t unused;
    1407           2 :   if (!NS_SUCCEEDED(GetFeatureStatus(aFeature, failureId, &unused))) {
    1408           0 :     return false;
    1409             :   }
    1410             : 
    1411             :   // Set "status".
    1412           2 :   if (aFeatureStatus) {
    1413           2 :     const char* status = FeatureStatusToString(aFeatureStatus.value());
    1414             : 
    1415           4 :     JS::Rooted<JSString*> str(aCx, JS_NewStringCopyZ(aCx, status));
    1416           4 :     JS::Rooted<JS::Value> val(aCx, JS::StringValue(str));
    1417           2 :     JS_SetProperty(aCx, obj, "status", val);
    1418             :   }
    1419             : 
    1420             :   // Add the feature object to the container.
    1421             :   {
    1422           4 :     JS::Rooted<JS::Value> val(aCx, JS::ObjectValue(*obj));
    1423           2 :     JS_SetProperty(aCx, aContainer, aName, val);
    1424             :   }
    1425             : 
    1426           2 :   aOutObj.set(obj);
    1427           2 :   return true;
    1428             : }
    1429             : 
    1430             : nsresult
    1431           0 : GfxInfoBase::GetActiveCrashGuards(JSContext* aCx, JS::MutableHandle<JS::Value> aOut)
    1432             : {
    1433           0 :   JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, 0));
    1434           0 :   if (!array) {
    1435           0 :     return NS_ERROR_OUT_OF_MEMORY;
    1436             :   }
    1437           0 :   aOut.setObject(*array);
    1438             : 
    1439           0 :   DriverCrashGuard::ForEachActiveCrashGuard([&](const char* aName,
    1440           0 :                                                 const char* aPrefName) -> void {
    1441           0 :     JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
    1442           0 :     if (!obj) {
    1443           0 :       return;
    1444             :     }
    1445           0 :     if (!SetJSPropertyString(aCx, obj, "type", aName)) {
    1446           0 :       return;
    1447             :     }
    1448           0 :     if (!SetJSPropertyString(aCx, obj, "prefName", aPrefName)) {
    1449           0 :       return;
    1450             :     }
    1451           0 :     if (!AppendJSElement(aCx, array, obj)) {
    1452           0 :       return;
    1453             :     }
    1454           0 :   });
    1455             : 
    1456           0 :   return NS_OK;
    1457             : }
    1458             : 
    1459             : NS_IMETHODIMP
    1460           0 : GfxInfoBase::GetWebRenderEnabled(bool* aWebRenderEnabled)
    1461             : {
    1462           0 :   *aWebRenderEnabled = gfxVars::UseWebRender();
    1463           0 :   return NS_OK;
    1464             : }
    1465             : 
    1466             : NS_IMETHODIMP
    1467           1 : GfxInfoBase::GetContentBackend(nsAString & aContentBackend)
    1468             : {
    1469           1 :   BackendType backend = gfxPlatform::GetPlatform()->GetDefaultContentBackend();
    1470           2 :   nsString outStr;
    1471             : 
    1472           1 :   switch (backend) {
    1473             :   case BackendType::DIRECT2D1_1: {
    1474           0 :     outStr.AppendPrintf("Direct2D 1.1");
    1475           0 :     break;
    1476             :   }
    1477             :   case BackendType::SKIA: {
    1478           1 :     outStr.AppendPrintf("Skia");
    1479           1 :     break;
    1480             :   }
    1481             :   case BackendType::CAIRO: {
    1482           0 :     outStr.AppendPrintf("Cairo");
    1483           0 :     break;
    1484             :   }
    1485             :   default:
    1486           0 :     return NS_ERROR_FAILURE;
    1487             :   }
    1488             : 
    1489           1 :   aContentBackend.Assign(outStr);
    1490           1 :   return NS_OK;
    1491             : }
    1492             : 
    1493             : NS_IMETHODIMP
    1494           0 : GfxInfoBase::GetUsingGPUProcess(bool *aOutValue)
    1495             : {
    1496           0 :   GPUProcessManager* gpu = GPUProcessManager::Get();
    1497           0 :   if (!gpu) {
    1498             :     // Not supported in content processes.
    1499           0 :     return NS_ERROR_FAILURE;
    1500             :   }
    1501             : 
    1502           0 :   *aOutValue = !!gpu->GetGPUChild();
    1503           0 :   return NS_OK;
    1504             : }
    1505             : 
    1506             : NS_IMETHODIMP
    1507           0 : GfxInfoBase::ControlGPUProcessForXPCShell(bool aEnable, bool *_retval)
    1508             : {
    1509           0 :   gfxPlatform::GetPlatform();
    1510             : 
    1511           0 :   GPUProcessManager* gpm = GPUProcessManager::Get();
    1512           0 :   if (aEnable) {
    1513           0 :     if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
    1514           0 :       gfxConfig::UserForceEnable(Feature::GPU_PROCESS, "xpcshell-test");
    1515             :     }
    1516           0 :     gpm->LaunchGPUProcess();
    1517           0 :     gpm->EnsureGPUReady();
    1518             :   } else {
    1519           0 :     gpm->KillProcess();
    1520             :   }
    1521             : 
    1522           0 :   *_retval = true;
    1523           0 :   return NS_OK;
    1524             : }
    1525             : 
    1526           9 : GfxInfoCollectorBase::GfxInfoCollectorBase()
    1527             : {
    1528           9 :   GfxInfoBase::AddCollector(this);
    1529           9 : }
    1530             : 
    1531           0 : GfxInfoCollectorBase::~GfxInfoCollectorBase()
    1532             : {
    1533           0 :   GfxInfoBase::RemoveCollector(this);
    1534           0 : }

Generated by: LCOV version 1.13