widget/xpwidgets/GfxInfoBase.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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/. */
     8 #include "mozilla/ArrayUtils.h"
    10 #include "GfxInfoBase.h"
    12 #include "GfxInfoWebGL.h"
    13 #include "GfxDriverInfo.h"
    14 #include "nsCOMPtr.h"
    15 #include "nsCOMArray.h"
    16 #include "nsAutoPtr.h"
    17 #include "nsString.h"
    18 #include "nsUnicharUtils.h"
    19 #include "mozilla/Services.h"
    20 #include "mozilla/Observer.h"
    21 #include "nsIObserver.h"
    22 #include "nsIObserverService.h"
    23 #include "nsIDOMElement.h"
    24 #include "nsIDOMHTMLCollection.h"
    25 #include "nsIDOMNode.h"
    26 #include "nsIDOMNodeList.h"
    27 #include "nsTArray.h"
    28 #include "nsXULAppAPI.h"
    29 #include "mozilla/Preferences.h"
    30 #include "mozilla/dom/ContentChild.h"
    32 #if defined(MOZ_CRASHREPORTER)
    33 #include "nsExceptionHandler.h"
    34 #endif
    36 using namespace mozilla::widget;
    37 using namespace mozilla;
    38 using mozilla::MutexAutoLock;
    40 nsTArray<GfxDriverInfo>* GfxInfoBase::mDriverInfo;
    41 bool GfxInfoBase::mDriverInfoObserverInitialized;
    43 // Observes for shutdown so that the child GfxDriverInfo list is freed.
    44 class ShutdownObserver : public nsIObserver
    45 {
    46 public:
    47   ShutdownObserver() {}
    48   virtual ~ShutdownObserver() {}
    50   NS_DECL_ISUPPORTS
    52   NS_IMETHOD Observe(nsISupports *subject, const char *aTopic,
    53                      const char16_t *aData)
    54   {
    55     MOZ_ASSERT(strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0);
    57     delete GfxInfoBase::mDriverInfo;
    58     GfxInfoBase::mDriverInfo = nullptr;
    60     for (uint32_t i = 0; i < DeviceFamilyMax; i++)
    61       delete GfxDriverInfo::mDeviceFamilies[i];
    63     for (uint32_t i = 0; i < DeviceVendorMax; i++)
    64       delete GfxDriverInfo::mDeviceVendors[i];
    66     return NS_OK;
    67   }
    68 };
    70 NS_IMPL_ISUPPORTS(ShutdownObserver, nsIObserver)
    72 void InitGfxDriverInfoShutdownObserver()
    73 {
    74   if (GfxInfoBase::mDriverInfoObserverInitialized)
    75     return;
    77   GfxInfoBase::mDriverInfoObserverInitialized = true;
    79   nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
    80   if (!observerService) {
    81     NS_WARNING("Could not get observer service!");
    82     return;
    83   }
    85   ShutdownObserver *obs = new ShutdownObserver();
    86   observerService->AddObserver(obs, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
    87 }
    89 using namespace mozilla::widget;
    90 using namespace mozilla;
    92 NS_IMPL_ISUPPORTS(GfxInfoBase, nsIGfxInfo, nsIObserver, nsISupportsWeakReference)
    94 #define BLACKLIST_PREF_BRANCH "gfx.blacklist."
    95 #define SUGGESTED_VERSION_PREF BLACKLIST_PREF_BRANCH "suggested-driver-version"
    96 #define BLACKLIST_ENTRY_TAG_NAME "gfxBlacklistEntry"
    98 static const char*
    99 GetPrefNameForFeature(int32_t aFeature)
   100 {
   101   const char* name = nullptr;
   102   switch(aFeature) {
   103     case nsIGfxInfo::FEATURE_DIRECT2D:
   104       name = BLACKLIST_PREF_BRANCH "direct2d";
   105       break;
   106     case nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS:
   107       name = BLACKLIST_PREF_BRANCH "layers.direct3d9";
   108       break;
   109     case nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS:
   110       name = BLACKLIST_PREF_BRANCH "layers.direct3d10";
   111       break;
   112     case nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS:
   113       name = BLACKLIST_PREF_BRANCH "layers.direct3d10-1";
   114       break;
   115     case nsIGfxInfo::FEATURE_OPENGL_LAYERS:
   116       name = BLACKLIST_PREF_BRANCH "layers.opengl";
   117       break;
   118     case nsIGfxInfo::FEATURE_WEBGL_OPENGL:
   119       name = BLACKLIST_PREF_BRANCH "webgl.opengl";
   120       break;
   121     case nsIGfxInfo::FEATURE_WEBGL_ANGLE:
   122       name = BLACKLIST_PREF_BRANCH "webgl.angle";
   123       break;
   124     case nsIGfxInfo::FEATURE_WEBGL_MSAA:
   125       name = BLACKLIST_PREF_BRANCH "webgl.msaa";
   126       break;
   127     case nsIGfxInfo::FEATURE_STAGEFRIGHT:
   128       name = BLACKLIST_PREF_BRANCH "stagefright";
   129       break;
   130     default:
   131       break;
   132   };
   134   return name;
   135 }
   137 // Returns the value of the pref for the relevant feature in aValue.
   138 // If the pref doesn't exist, aValue is not touched, and returns false.
   139 static bool
   140 GetPrefValueForFeature(int32_t aFeature, int32_t& aValue)
   141 {
   142   const char *prefname = GetPrefNameForFeature(aFeature);
   143   if (!prefname)
   144     return false;
   146   aValue = false;
   147   return NS_SUCCEEDED(Preferences::GetInt(prefname, &aValue));
   148 }
   150 static void
   151 SetPrefValueForFeature(int32_t aFeature, int32_t aValue)
   152 {
   153   const char *prefname = GetPrefNameForFeature(aFeature);
   154   if (!prefname)
   155     return;
   157   Preferences::SetInt(prefname, aValue);
   158 }
   160 static void
   161 RemovePrefForFeature(int32_t aFeature)
   162 {
   163   const char *prefname = GetPrefNameForFeature(aFeature);
   164   if (!prefname)
   165     return;
   167   Preferences::ClearUser(prefname);
   168 }
   170 static bool
   171 GetPrefValueForDriverVersion(nsCString& aVersion)
   172 {
   173   return NS_SUCCEEDED(Preferences::GetCString(SUGGESTED_VERSION_PREF,
   174                                               &aVersion));
   175 }
   177 static void
   178 SetPrefValueForDriverVersion(const nsAString& aVersion)
   179 {
   180   Preferences::SetString(SUGGESTED_VERSION_PREF, aVersion);
   181 }
   183 static void
   184 RemovePrefForDriverVersion()
   185 {
   186   Preferences::ClearUser(SUGGESTED_VERSION_PREF);
   187 }
   189 // <foo>Hello</foo> - "Hello" is stored as a child text node of the foo node.
   190 static bool
   191 BlacklistNodeToTextValue(nsIDOMNode *aBlacklistNode, nsAString& aValue)
   192 {
   193   nsAutoString value;
   194   if (NS_FAILED(aBlacklistNode->GetTextContent(value)))
   195     return false;
   197   value.Trim(" \t\r\n");
   198   aValue = value;
   200   return true;
   201 }
   203 static OperatingSystem
   204 BlacklistOSToOperatingSystem(const nsAString& os)
   205 {
   206   if (os == NS_LITERAL_STRING("WINNT 5.1"))
   207     return DRIVER_OS_WINDOWS_XP;
   208   else if (os == NS_LITERAL_STRING("WINNT 5.2"))
   209     return DRIVER_OS_WINDOWS_SERVER_2003;
   210   else if (os == NS_LITERAL_STRING("WINNT 6.0"))
   211     return DRIVER_OS_WINDOWS_VISTA;
   212   else if (os == NS_LITERAL_STRING("WINNT 6.1"))
   213     return DRIVER_OS_WINDOWS_7;
   214   else if (os == NS_LITERAL_STRING("WINNT 6.2"))
   215     return DRIVER_OS_WINDOWS_8;
   216   else if (os == NS_LITERAL_STRING("WINNT 6.3"))
   217     return DRIVER_OS_WINDOWS_8_1;
   218   else if (os == NS_LITERAL_STRING("Linux"))
   219     return DRIVER_OS_LINUX;
   220   else if (os == NS_LITERAL_STRING("Darwin 9"))
   221     return DRIVER_OS_OS_X_10_5;
   222   else if (os == NS_LITERAL_STRING("Darwin 10"))
   223     return DRIVER_OS_OS_X_10_6;
   224   else if (os == NS_LITERAL_STRING("Darwin 11"))
   225     return DRIVER_OS_OS_X_10_7;
   226   else if (os == NS_LITERAL_STRING("Darwin 12"))
   227     return DRIVER_OS_OS_X_10_8;
   228   else if (os == NS_LITERAL_STRING("Android"))
   229     return DRIVER_OS_ANDROID;
   230   else if (os == NS_LITERAL_STRING("All"))
   231     return DRIVER_OS_ALL;
   233   return DRIVER_OS_UNKNOWN;
   234 }
   236 static GfxDeviceFamily*
   237 BlacklistDevicesToDeviceFamily(nsIDOMHTMLCollection* aDevices)
   238 {
   239   uint32_t length;
   240   if (NS_FAILED(aDevices->GetLength(&length)))
   241     return nullptr;
   243   // For each <device>, get its device ID, and return a freshly-allocated
   244   // GfxDeviceFamily with the contents of that array.
   245   GfxDeviceFamily* deviceIds = new GfxDeviceFamily;
   247   for (uint32_t i = 0; i < length; ++i) {
   248     nsCOMPtr<nsIDOMNode> node;
   249     if (NS_FAILED(aDevices->Item(i, getter_AddRefs(node))) || !node)
   250       continue;
   252     nsAutoString deviceValue;
   253     if (!BlacklistNodeToTextValue(node, deviceValue))
   254       continue;
   256     deviceIds->AppendElement(deviceValue);
   257   }
   259   return deviceIds;
   260 }
   262 static int32_t
   263 BlacklistFeatureToGfxFeature(const nsAString& aFeature)
   264 {
   265   if (aFeature == NS_LITERAL_STRING("DIRECT2D"))
   266     return nsIGfxInfo::FEATURE_DIRECT2D;
   267   else if (aFeature == NS_LITERAL_STRING("DIRECT3D_9_LAYERS"))
   268     return nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS;
   269   else if (aFeature == NS_LITERAL_STRING("DIRECT3D_10_LAYERS"))
   270     return nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS;
   271   else if (aFeature == NS_LITERAL_STRING("DIRECT3D_10_1_LAYERS"))
   272     return nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS;
   273   else if (aFeature == NS_LITERAL_STRING("OPENGL_LAYERS"))
   274     return nsIGfxInfo::FEATURE_OPENGL_LAYERS;
   275   else if (aFeature == NS_LITERAL_STRING("WEBGL_OPENGL"))
   276     return nsIGfxInfo::FEATURE_WEBGL_OPENGL;
   277   else if (aFeature == NS_LITERAL_STRING("WEBGL_ANGLE"))
   278     return nsIGfxInfo::FEATURE_WEBGL_ANGLE;
   279   else if (aFeature == NS_LITERAL_STRING("WEBGL_MSAA"))
   280     return nsIGfxInfo::FEATURE_WEBGL_MSAA;
   281   else if (aFeature == NS_LITERAL_STRING("STAGEFRIGHT"))
   282     return nsIGfxInfo::FEATURE_STAGEFRIGHT;
   283   return 0;
   284 }
   286 static int32_t
   287 BlacklistFeatureStatusToGfxFeatureStatus(const nsAString& aStatus)
   288 {
   289   if (aStatus == NS_LITERAL_STRING("NO_INFO"))
   290     return nsIGfxInfo::FEATURE_NO_INFO;
   291   else if (aStatus == NS_LITERAL_STRING("BLOCKED_DRIVER_VERSION"))
   292     return nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION;
   293   else if (aStatus == NS_LITERAL_STRING("BLOCKED_DEVICE"))
   294     return nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
   295   else if (aStatus == NS_LITERAL_STRING("DISCOURAGED"))
   296     return nsIGfxInfo::FEATURE_DISCOURAGED;
   297   else if (aStatus == NS_LITERAL_STRING("BLOCKED_OS_VERSION"))
   298     return nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION;
   300   // Do not allow it to set STATUS_UNKNOWN.
   302   return nsIGfxInfo::FEATURE_NO_INFO;
   303 }
   305 static VersionComparisonOp
   306 BlacklistComparatorToComparisonOp(const nsAString& op)
   307 {
   308   if (op == NS_LITERAL_STRING("LESS_THAN"))
   309     return DRIVER_LESS_THAN;
   310   else if (op == NS_LITERAL_STRING("LESS_THAN_OR_EQUAL"))
   311     return DRIVER_LESS_THAN_OR_EQUAL;
   312   else if (op == NS_LITERAL_STRING("GREATER_THAN"))
   313     return DRIVER_GREATER_THAN;
   314   else if (op == NS_LITERAL_STRING("GREATER_THAN_OR_EQUAL"))
   315     return DRIVER_GREATER_THAN_OR_EQUAL;
   316   else if (op == NS_LITERAL_STRING("EQUAL"))
   317     return DRIVER_EQUAL;
   318   else if (op == NS_LITERAL_STRING("NOT_EQUAL"))
   319     return DRIVER_NOT_EQUAL;
   320   else if (op == NS_LITERAL_STRING("BETWEEN_EXCLUSIVE"))
   321     return DRIVER_BETWEEN_EXCLUSIVE;
   322   else if (op == NS_LITERAL_STRING("BETWEEN_INCLUSIVE"))
   323     return DRIVER_BETWEEN_INCLUSIVE;
   324   else if (op == NS_LITERAL_STRING("BETWEEN_INCLUSIVE_START"))
   325     return DRIVER_BETWEEN_INCLUSIVE_START;
   327   return DRIVER_COMPARISON_IGNORED;
   328 }
   330 // Arbitrarily returns the first |tagname| child of |element|.
   331 static bool
   332 BlacklistNodeGetChildByName(nsIDOMElement *element,
   333                             const nsAString& tagname,
   334                             nsIDOMNode** firstchild)
   335 {
   336   nsCOMPtr<nsIDOMHTMLCollection> nodelist;
   337   if (NS_FAILED(element->GetElementsByTagName(tagname,
   338                                               getter_AddRefs(nodelist))) ||
   339       !nodelist) {
   340     return false;
   341   }
   343   nsCOMPtr<nsIDOMNode> node;
   344   if (NS_FAILED(nodelist->Item(0, getter_AddRefs(node))) || !node)
   345     return false;
   347   node.forget(firstchild);
   348   return true;
   349 }
   351 /*
   353 <gfxBlacklistEntry>
   354   <os>WINNT 6.0</os>
   355   <vendor>0x8086</vendor>
   356   <devices>
   357     <device>0x2582</device>
   358     <device>0x2782</device>
   359   </devices>
   360   <feature> DIRECT3D_10_LAYERS </feature>
   361   <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
   362   <driverVersion> 8.52.322.2202 </driverVersion>
   363   <driverVersionComparator> LESS_THAN_OR_EQUAL </driverVersionComparator>
   364 </gfxBlacklistEntry>
   366 */
   367 static bool
   368 BlacklistEntryToDriverInfo(nsIDOMNode* aBlacklistEntry,
   369                            GfxDriverInfo& aDriverInfo)
   370 {
   371   nsAutoString nodename;
   372   if (NS_FAILED(aBlacklistEntry->GetNodeName(nodename)) ||
   373       nodename != NS_LITERAL_STRING(BLACKLIST_ENTRY_TAG_NAME)) {
   374     return false;
   375   }
   377   nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aBlacklistEntry);
   378   if (!element)
   379     return false;
   381   nsCOMPtr<nsIDOMNode> dataNode;
   382   nsAutoString dataValue;
   384   // <os>WINNT 6.0</os>
   385   if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("os"),
   386                                   getter_AddRefs(dataNode))) {
   387     BlacklistNodeToTextValue(dataNode, dataValue);
   388     aDriverInfo.mOperatingSystem = BlacklistOSToOperatingSystem(dataValue);
   389   }
   391   // <osversion>14</osversion> currently only used for Android
   392   if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("osversion"),
   393                                   getter_AddRefs(dataNode))) {
   394     BlacklistNodeToTextValue(dataNode, dataValue);
   395     aDriverInfo.mOperatingSystemVersion = strtoul(NS_LossyConvertUTF16toASCII(dataValue).get(),
   396                                                   nullptr, 10);
   397   }
   399   // <vendor>0x8086</vendor>
   400   if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("vendor"),
   401                                   getter_AddRefs(dataNode))) {
   402     BlacklistNodeToTextValue(dataNode, dataValue);
   403     aDriverInfo.mAdapterVendor = dataValue;
   404   }
   406   // <devices>
   407   //   <device>0x2582</device>
   408   //   <device>0x2782</device>
   409   // </devices>
   410   if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("devices"),
   411                                   getter_AddRefs(dataNode))) {
   412     nsCOMPtr<nsIDOMElement> devicesElement = do_QueryInterface(dataNode);
   413     if (devicesElement) {
   415       // Get only the <device> nodes, because BlacklistDevicesToDeviceFamily
   416       // assumes it is passed no other nodes.
   417       nsCOMPtr<nsIDOMHTMLCollection> devices;
   418       if (NS_SUCCEEDED(devicesElement->GetElementsByTagName(NS_LITERAL_STRING("device"),
   419                                                             getter_AddRefs(devices)))) {
   420         GfxDeviceFamily* deviceIds = BlacklistDevicesToDeviceFamily(devices);
   421         if (deviceIds) {
   422           // Get GfxDriverInfo to adopt the devices array we created.
   423           aDriverInfo.mDeleteDevices = true;
   424           aDriverInfo.mDevices = deviceIds;
   425         }
   426       }
   427     }
   428   }
   430   // <feature> DIRECT3D_10_LAYERS </feature>
   431   if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("feature"),
   432                                   getter_AddRefs(dataNode))) {
   433     BlacklistNodeToTextValue(dataNode, dataValue);
   434     aDriverInfo.mFeature = BlacklistFeatureToGfxFeature(dataValue);
   435   }
   437   // <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
   438   if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("featureStatus"),
   439                                   getter_AddRefs(dataNode))) {
   440     BlacklistNodeToTextValue(dataNode, dataValue);
   441     aDriverInfo.mFeatureStatus = BlacklistFeatureStatusToGfxFeatureStatus(dataValue);
   442   }
   444   // <driverVersion> 8.52.322.2202 </driverVersion>
   445   if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("driverVersion"),
   446                                   getter_AddRefs(dataNode))) {
   447     BlacklistNodeToTextValue(dataNode, dataValue);
   448     uint64_t version;
   449     if (ParseDriverVersion(dataValue, &version))
   450       aDriverInfo.mDriverVersion = version;
   451   }
   453   // <driverVersionComparator> LESS_THAN_OR_EQUAL </driverVersionComparator>
   454   if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("driverVersionComparator"),
   455                                   getter_AddRefs(dataNode))) {
   456     BlacklistNodeToTextValue(dataNode, dataValue);
   457     aDriverInfo.mComparisonOp = BlacklistComparatorToComparisonOp(dataValue);
   458   }
   460   // <model>foo</model>
   461   if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("model"),
   462                                   getter_AddRefs(dataNode))) {
   463     BlacklistNodeToTextValue(dataNode, dataValue);
   464     aDriverInfo.mModel = dataValue;
   465   }
   466   // <product>foo</product>
   467   if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("product"),
   468                                   getter_AddRefs(dataNode))) {
   469     BlacklistNodeToTextValue(dataNode, dataValue);
   470     aDriverInfo.mProduct = dataValue;
   471   }
   472   // <manufacturer>foo</manufacturer>
   473   if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("manufacturer"),
   474                                   getter_AddRefs(dataNode))) {
   475     BlacklistNodeToTextValue(dataNode, dataValue);
   476     aDriverInfo.mManufacturer = dataValue;
   477   }
   478   // <hardware>foo</hardware>
   479   if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("hardware"),
   480                                   getter_AddRefs(dataNode))) {
   481     BlacklistNodeToTextValue(dataNode, dataValue);
   482     aDriverInfo.mHardware = dataValue;
   483   }
   485   // We explicitly ignore unknown elements.
   487   return true;
   488 }
   490 static void
   491 BlacklistEntriesToDriverInfo(nsIDOMHTMLCollection* aBlacklistEntries,
   492                              nsTArray<GfxDriverInfo>& aDriverInfo)
   493 {
   494   uint32_t length;
   495   if (NS_FAILED(aBlacklistEntries->GetLength(&length)))
   496     return;
   498   aDriverInfo.Clear();
   499   aDriverInfo.SetLength(length);
   500   for (uint32_t i = 0; i < length; ++i) {
   501     nsCOMPtr<nsIDOMNode> blacklistEntry;
   502     if (NS_SUCCEEDED(aBlacklistEntries->Item(i,
   503                                              getter_AddRefs(blacklistEntry))) &&
   504         blacklistEntry) {
   505       GfxDriverInfo di;
   506       if (BlacklistEntryToDriverInfo(blacklistEntry, di)) {
   507         aDriverInfo[i] = di;
   508       }
   509       // Prevent di falling out of scope from destroying the devices.
   510       di.mDeleteDevices = false;
   511     }
   512   }
   513 }
   515 NS_IMETHODIMP
   516 GfxInfoBase::Observe(nsISupports* aSubject, const char* aTopic,
   517                      const char16_t* aData)
   518 {
   519   if (strcmp(aTopic, "blocklist-data-gfxItems") == 0) {
   520     nsCOMPtr<nsIDOMElement> gfxItems = do_QueryInterface(aSubject);
   521     if (gfxItems) {
   522       nsCOMPtr<nsIDOMHTMLCollection> blacklistEntries;
   523       if (NS_SUCCEEDED(gfxItems->
   524             GetElementsByTagName(NS_LITERAL_STRING(BLACKLIST_ENTRY_TAG_NAME),
   525                                  getter_AddRefs(blacklistEntries))) &&
   526           blacklistEntries)
   527       {
   528         nsTArray<GfxDriverInfo> driverInfo;
   529         BlacklistEntriesToDriverInfo(blacklistEntries, driverInfo);
   530         EvaluateDownloadedBlacklist(driverInfo);
   531       }
   532     }
   533   }
   535   return NS_OK;
   536 }
   538 GfxInfoBase::GfxInfoBase()
   539     : mFailureCount(0)
   540     , mMutex("GfxInfoBase")
   541 {
   542 }
   544 GfxInfoBase::~GfxInfoBase()
   545 {
   546 }
   548 nsresult
   549 GfxInfoBase::Init()
   550 {
   551   InitGfxDriverInfoShutdownObserver();
   553   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
   554   if (os) {
   555     os->AddObserver(this, "blocklist-data-gfxItems", true);
   556   }
   558   return NS_OK;
   559 }
   561 NS_IMETHODIMP
   562 GfxInfoBase::GetFeatureStatus(int32_t aFeature, int32_t* aStatus)
   563 {
   564   if (GetPrefValueForFeature(aFeature, *aStatus))
   565     return NS_OK;
   567   if (XRE_GetProcessType() == GeckoProcessType_Content) {
   568       // Delegate to the parent process.
   569       mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton();
   570       bool success;
   571       cc->SendGetGraphicsFeatureStatus(aFeature, aStatus, &success);
   572       return success ? NS_OK : NS_ERROR_FAILURE;
   573   }
   575   nsString version;
   576   nsTArray<GfxDriverInfo> driverInfo;
   577   return GetFeatureStatusImpl(aFeature, aStatus, version, driverInfo);
   578 }
   580 int32_t
   581 GfxInfoBase::FindBlocklistedDeviceInList(const nsTArray<GfxDriverInfo>& info,
   582                                          nsAString& aSuggestedVersion,
   583                                          int32_t aFeature,
   584                                          OperatingSystem os)
   585 {
   586   int32_t status = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
   588   nsAutoString adapterVendorID;
   589   nsAutoString adapterDeviceID;
   590   nsAutoString adapterDriverVersionString;
   591   if (NS_FAILED(GetAdapterVendorID(adapterVendorID)) ||
   592       NS_FAILED(GetAdapterDeviceID(adapterDeviceID)) ||
   593       NS_FAILED(GetAdapterDriverVersion(adapterDriverVersionString)))
   594   {
   595     return 0;
   596   }
   598 #if defined(XP_WIN) || defined(ANDROID)
   599   uint64_t driverVersion;
   600   ParseDriverVersion(adapterDriverVersionString, &driverVersion);
   601 #endif
   603   uint32_t i = 0;
   604   for (; i < info.Length(); i++) {
   605     if (info[i].mOperatingSystem != DRIVER_OS_ALL &&
   606         info[i].mOperatingSystem != os)
   607     {
   608       continue;
   609     }
   611     if (info[i].mOperatingSystemVersion && info[i].mOperatingSystemVersion != OperatingSystemVersion()) {
   612         continue;
   613     }
   615     if (!info[i].mAdapterVendor.Equals(GfxDriverInfo::GetDeviceVendor(VendorAll), nsCaseInsensitiveStringComparator()) &&
   616         !info[i].mAdapterVendor.Equals(adapterVendorID, nsCaseInsensitiveStringComparator())) {
   617       continue;
   618     }
   620     if (info[i].mDevices != GfxDriverInfo::allDevices && info[i].mDevices->Length()) {
   621         bool deviceMatches = false;
   622         for (uint32_t j = 0; j < info[i].mDevices->Length(); j++) {
   623             if ((*info[i].mDevices)[j].Equals(adapterDeviceID, nsCaseInsensitiveStringComparator())) {
   624                 deviceMatches = true;
   625                 break;
   626             }
   627         }
   629         if (!deviceMatches) {
   630             continue;
   631         }
   632     }
   634     bool match = false;
   636     if (!info[i].mHardware.IsEmpty() && !info[i].mHardware.Equals(Hardware())) {
   637         continue;
   638     }
   639     if (!info[i].mModel.IsEmpty() && !info[i].mModel.Equals(Model())) {
   640         continue;
   641     }
   642     if (!info[i].mProduct.IsEmpty() && !info[i].mProduct.Equals(Product())) {
   643         continue;
   644     }
   645     if (!info[i].mManufacturer.IsEmpty() && !info[i].mManufacturer.Equals(Manufacturer())) {
   646         continue;
   647     }
   649 #if defined(XP_WIN) || defined(ANDROID)
   650     switch (info[i].mComparisonOp) {
   651     case DRIVER_LESS_THAN:
   652       match = driverVersion < info[i].mDriverVersion;
   653       break;
   654     case DRIVER_LESS_THAN_OR_EQUAL:
   655       match = driverVersion <= info[i].mDriverVersion;
   656       break;
   657     case DRIVER_GREATER_THAN:
   658       match = driverVersion > info[i].mDriverVersion;
   659       break;
   660     case DRIVER_GREATER_THAN_OR_EQUAL:
   661       match = driverVersion >= info[i].mDriverVersion;
   662       break;
   663     case DRIVER_EQUAL:
   664       match = driverVersion == info[i].mDriverVersion;
   665       break;
   666     case DRIVER_NOT_EQUAL:
   667       match = driverVersion != info[i].mDriverVersion;
   668       break;
   669     case DRIVER_BETWEEN_EXCLUSIVE:
   670       match = driverVersion > info[i].mDriverVersion && driverVersion < info[i].mDriverVersionMax;
   671       break;
   672     case DRIVER_BETWEEN_INCLUSIVE:
   673       match = driverVersion >= info[i].mDriverVersion && driverVersion <= info[i].mDriverVersionMax;
   674       break;
   675     case DRIVER_BETWEEN_INCLUSIVE_START:
   676       match = driverVersion >= info[i].mDriverVersion && driverVersion < info[i].mDriverVersionMax;
   677       break;
   678     case DRIVER_COMPARISON_IGNORED:
   679       // We don't have a comparison op, so we match everything.
   680       match = true;
   681       break;
   682     default:
   683       NS_WARNING("Bogus op in GfxDriverInfo");
   684       break;
   685     }
   686 #else
   687     // We don't care what driver version it was. We only check OS version and if
   688     // the device matches.
   689     match = true;
   690 #endif
   692     if (match || info[i].mDriverVersion == GfxDriverInfo::allDriverVersions) {
   693       if (info[i].mFeature == GfxDriverInfo::allFeatures ||
   694           info[i].mFeature == aFeature)
   695       {
   696         status = info[i].mFeatureStatus;
   697         break;
   698       }
   699     }
   700   }
   702   // Depends on Windows driver versioning. We don't pass a GfxDriverInfo object
   703   // back to the Windows handler, so we must handle this here.
   704 #if defined(XP_WIN)
   705   if (status == FEATURE_BLOCKED_DRIVER_VERSION) {
   706     if (info[i].mSuggestedVersion) {
   707         aSuggestedVersion.AppendPrintf("%s", info[i].mSuggestedVersion);
   708     } else if (info[i].mComparisonOp == DRIVER_LESS_THAN &&
   709                info[i].mDriverVersion != GfxDriverInfo::allDriverVersions)
   710     {
   711         aSuggestedVersion.AppendPrintf("%lld.%lld.%lld.%lld",
   712                                       (info[i].mDriverVersion & 0xffff000000000000) >> 48,
   713                                       (info[i].mDriverVersion & 0x0000ffff00000000) >> 32,
   714                                       (info[i].mDriverVersion & 0x00000000ffff0000) >> 16,
   715                                       (info[i].mDriverVersion & 0x000000000000ffff));
   716     }
   717   }
   718 #endif
   720   return status;
   721 }
   723 nsresult
   724 GfxInfoBase::GetFeatureStatusImpl(int32_t aFeature,
   725                                   int32_t* aStatus,
   726                                   nsAString& aSuggestedVersion,
   727                                   const nsTArray<GfxDriverInfo>& aDriverInfo,
   728                                   OperatingSystem* aOS /* = nullptr */)
   729 {
   730   if (*aStatus != nsIGfxInfo::FEATURE_STATUS_UNKNOWN) {
   731     // Terminate now with the status determined by the derived type (OS-specific
   732     // code).
   733     return NS_OK;
   734   }
   736   // If an operating system was provided by the derived GetFeatureStatusImpl,
   737   // grab it here. Otherwise, the OS is unknown.
   738   OperatingSystem os = DRIVER_OS_UNKNOWN;
   739   if (aOS)
   740     os = *aOS;
   742   nsAutoString adapterVendorID;
   743   nsAutoString adapterDeviceID;
   744   nsAutoString adapterDriverVersionString;
   745   if (NS_FAILED(GetAdapterVendorID(adapterVendorID)) ||
   746       NS_FAILED(GetAdapterDeviceID(adapterDeviceID)) ||
   747       NS_FAILED(GetAdapterDriverVersion(adapterDriverVersionString)))
   748   {
   749     return NS_OK;
   750   }
   752   // Check if the device is blocked from the downloaded blocklist. If not, check
   753   // the static list after that. This order is used so that we can later escape
   754   // out of static blocks (i.e. if we were wrong or something was patched, we
   755   // can back out our static block without doing a release).
   756   int32_t status;
   757   if (aDriverInfo.Length()) {
   758     status = FindBlocklistedDeviceInList(aDriverInfo, aSuggestedVersion, aFeature, os);
   759   } else {
   760     if (!mDriverInfo) {
   761       mDriverInfo = new nsTArray<GfxDriverInfo>();
   762     }
   763     status = FindBlocklistedDeviceInList(GetGfxDriverInfo(), aSuggestedVersion, aFeature, os);
   764   }
   766   // It's now done being processed. It's safe to set the status to NO_INFO.
   767   if (status == nsIGfxInfo::FEATURE_STATUS_UNKNOWN) {
   768     *aStatus = nsIGfxInfo::FEATURE_NO_INFO;
   769   } else {
   770     *aStatus = status;
   771   }
   773   return NS_OK;
   774 }
   776 NS_IMETHODIMP
   777 GfxInfoBase::GetFeatureSuggestedDriverVersion(int32_t aFeature,
   778                                               nsAString& aVersion)
   779 {
   780   nsCString version;
   781   if (GetPrefValueForDriverVersion(version)) {
   782     aVersion = NS_ConvertASCIItoUTF16(version);
   783     return NS_OK;
   784   }
   786   int32_t status;
   787   nsTArray<GfxDriverInfo> driverInfo;
   788   return GetFeatureStatusImpl(aFeature, &status, aVersion, driverInfo);
   789 }
   792 NS_IMETHODIMP
   793 GfxInfoBase::GetWebGLParameter(const nsAString& aParam,
   794                                nsAString& aResult)
   795 {
   796   return GfxInfoWebGL::GetWebGLParameter(aParam, aResult);
   797 }
   799 void
   800 GfxInfoBase::EvaluateDownloadedBlacklist(nsTArray<GfxDriverInfo>& aDriverInfo)
   801 {
   802   int32_t features[] = {
   803     nsIGfxInfo::FEATURE_DIRECT2D,
   804     nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS,
   805     nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS,
   806     nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS,
   807     nsIGfxInfo::FEATURE_OPENGL_LAYERS,
   808     nsIGfxInfo::FEATURE_WEBGL_OPENGL,
   809     nsIGfxInfo::FEATURE_WEBGL_ANGLE,
   810     nsIGfxInfo::FEATURE_WEBGL_MSAA,
   811     nsIGfxInfo::FEATURE_STAGEFRIGHT,
   812     0
   813   };
   815   // For every feature we know about, we evaluate whether this blacklist has a
   816   // non-NO_INFO status. If it does, we set the pref we evaluate in
   817   // GetFeatureStatus above, so we don't need to hold on to this blacklist
   818   // anywhere permanent.
   819   int i = 0;
   820   while (features[i]) {
   821     int32_t status;
   822     nsAutoString suggestedVersion;
   823     if (NS_SUCCEEDED(GetFeatureStatusImpl(features[i], &status,
   824                                           suggestedVersion,
   825                                           aDriverInfo))) {
   826       switch (status) {
   827         default:
   828         case nsIGfxInfo::FEATURE_NO_INFO:
   829           RemovePrefForFeature(features[i]);
   830           break;
   832         case nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION:
   833           if (!suggestedVersion.IsEmpty()) {
   834             SetPrefValueForDriverVersion(suggestedVersion);
   835           } else {
   836             RemovePrefForDriverVersion();
   837           }
   838           // FALLTHROUGH
   840         case nsIGfxInfo::FEATURE_BLOCKED_DEVICE:
   841         case nsIGfxInfo::FEATURE_DISCOURAGED:
   842         case nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION:
   843           SetPrefValueForFeature(features[i], status);
   844           break;
   845       }
   846     }
   848     ++i;
   849   }
   850 }
   852 NS_IMETHODIMP_(void)
   853 GfxInfoBase::LogFailure(const nsACString &failure)
   854 {
   855   MutexAutoLock lock(mMutex);
   856   /* We only keep the first 9 failures */
   857   if (mFailureCount < ArrayLength(mFailures)) {
   858     mFailures[mFailureCount++] = failure;
   860     /* record it in the crash notes too */
   861     #if defined(MOZ_CRASHREPORTER)
   862       CrashReporter::AppendAppNotesToCrashReport(failure);
   863     #endif
   864   }
   866 }
   868 /* void getFailures ([optional] out unsigned long failureCount, [array, size_is (failureCount), retval] out string failures); */
   869 /* XPConnect method of returning arrays is very ugly. Would not recommend. Fallable nsMemory::Alloc makes things worse */
   870 NS_IMETHODIMP GfxInfoBase::GetFailures(uint32_t *failureCount, char ***failures)
   871 {
   873   NS_ENSURE_ARG_POINTER(failureCount);
   874   NS_ENSURE_ARG_POINTER(failures);
   876   *failures = nullptr;
   877   *failureCount = mFailureCount;
   879   if (*failureCount != 0) {
   880     *failures = (char**)nsMemory::Alloc(*failureCount * sizeof(char*));
   881     if (!failures)
   882       return NS_ERROR_OUT_OF_MEMORY;
   884     /* copy over the failure messages into the array we just allocated */
   885     for (uint32_t i = 0; i < *failureCount; i++) {
   886       nsCString& flattenedFailureMessage(mFailures[i]);
   887       (*failures)[i] = (char*)nsMemory::Clone(flattenedFailureMessage.get(), flattenedFailureMessage.Length() + 1);
   889       if (!(*failures)[i]) {
   890         /* <sarcasm> I'm too afraid to use an inline function... </sarcasm> */
   891         NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, (*failures));
   892         return NS_ERROR_OUT_OF_MEMORY;
   893       }
   894     }
   895   }
   897   return NS_OK;
   898 }
   900 nsTArray<GfxInfoCollectorBase*> *sCollectors;
   902 static void
   903 InitCollectors()
   904 {
   905   if (!sCollectors)
   906     sCollectors = new nsTArray<GfxInfoCollectorBase*>;
   907 }
   909 nsresult GfxInfoBase::GetInfo(JSContext* aCx, JS::MutableHandle<JS::Value> aResult)
   910 {
   911   InitCollectors();
   912   InfoObject obj(aCx);
   914   for (uint32_t i = 0; i < sCollectors->Length(); i++) {
   915     (*sCollectors)[i]->GetInfo(obj);
   916   }
   918   // Some example property definitions
   919   // obj.DefineProperty("wordCacheSize", gfxTextRunWordCache::Count());
   920   // obj.DefineProperty("renderer", mRendererIDsString);
   921   // obj.DefineProperty("five", 5);
   923   if (!obj.mOk) {
   924     return NS_ERROR_FAILURE;
   925   }
   927   aResult.setObject(*obj.mObj);
   928   return NS_OK;
   929 }
   931 void
   932 GfxInfoBase::AddCollector(GfxInfoCollectorBase* collector)
   933 {
   934   InitCollectors();
   935   sCollectors->AppendElement(collector);
   936 }
   938 void
   939 GfxInfoBase::RemoveCollector(GfxInfoCollectorBase* collector)
   940 {
   941   InitCollectors();
   942   for (uint32_t i = 0; i < sCollectors->Length(); i++) {
   943     if ((*sCollectors)[i] == collector) {
   944       sCollectors->RemoveElementAt(i);
   945       break;
   946     }
   947   }
   948   if (sCollectors->IsEmpty()) {
   949     delete sCollectors;
   950     sCollectors = nullptr;
   951   }
   952 }
   954 GfxInfoCollectorBase::GfxInfoCollectorBase()
   955 {
   956   GfxInfoBase::AddCollector(this);
   957 }
   959 GfxInfoCollectorBase::~GfxInfoCollectorBase()
   960 {
   961   GfxInfoBase::RemoveCollector(this);
   962 }

mercurial