Bug 1162530 - Part 1: Add versioning to graphics blocklist. r=jmuizelaar
authorMilan Sreckovic <milan@mozilla.com>
Fri, 15 May 2015 10:42:10 -0400
changeset 244759 93fe551e8a557bc81c6798a8e4f494cfbb2d7fd6
parent 244758 23611294fcd654307bd98d8776bb40d6c9a71fa6
child 244760 edb5b81dd9e76fb76c0a8d38e214c9593a0f9c0a
push id28788
push userkwierso@gmail.com
push dateThu, 21 May 2015 01:16:49 +0000
treeherdermozilla-central@bc3500c5afa0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjmuizelaar
bugs1162530
milestone41.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1162530 - Part 1: Add versioning to graphics blocklist. r=jmuizelaar
gfx/tests/gtest/TestGfxWidgets.cpp
gfx/tests/gtest/moz.build
widget/GfxInfoBase.cpp
widget/GfxInfoBase.h
new file mode 100644
--- /dev/null
+++ b/gfx/tests/gtest/TestGfxWidgets.cpp
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+#include "GfxDriverInfo.h"
+#include "nsVersionComparator.h"
+
+using namespace mozilla::widget;
+
+TEST(GfxWidgets, Split) {
+  char aStr[8], bStr[8], cStr[8], dStr[8];
+
+  ASSERT_TRUE(SplitDriverVersion("33.4.3.22", aStr, bStr, cStr, dStr));
+  ASSERT_TRUE(atoi(aStr) == 33 && atoi(bStr) == 4 && atoi(cStr) == 3 && atoi(dStr) == 22);
+
+  ASSERT_TRUE(SplitDriverVersion("28.74.0.0", aStr, bStr, cStr, dStr));
+  ASSERT_TRUE(atoi(aStr) == 28 && atoi(bStr) == 74 && atoi(cStr) == 0 && atoi(dStr) == 0);
+
+  ASSERT_TRUE(SplitDriverVersion("132.0.0.0", aStr, bStr, cStr, dStr));
+  ASSERT_TRUE(atoi(aStr) == 132 && atoi(bStr) == 0 && atoi(cStr) == 0 && atoi(dStr) == 0);
+
+  ASSERT_TRUE(SplitDriverVersion("2.3.0.0", aStr, bStr, cStr, dStr));
+  ASSERT_TRUE(atoi(aStr) == 2 && atoi(bStr) == 3 && atoi(cStr) == 0 && atoi(dStr) == 0);
+
+  ASSERT_TRUE(SplitDriverVersion("25.4.0.8", aStr, bStr, cStr, dStr));
+  ASSERT_TRUE(atoi(aStr) == 25 && atoi(bStr) == 4 && atoi(cStr) == 0 && atoi(dStr) == 8);
+
+}
+
+TEST(GfxWidgets, Versioning) {
+  ASSERT_TRUE(mozilla::Version("0") < mozilla::Version("41.0a1"));
+  ASSERT_TRUE(mozilla::Version("39.0.5b7") < mozilla::Version("41.0a1"));
+  ASSERT_TRUE(mozilla::Version("18.0.5b7") < mozilla::Version("18.2"));
+  ASSERT_TRUE(mozilla::Version("30.0.5b7") < mozilla::Version("41.0b9"));
+  ASSERT_TRUE(mozilla::Version("100") > mozilla::Version("43.0a1"));
+  ASSERT_FALSE(mozilla::Version("42.0") < mozilla::Version("42.0"));
+  ASSERT_TRUE(mozilla::Version("42.0b2") < mozilla::Version("42.0"));
+  ASSERT_TRUE(mozilla::Version("42.0b2") < mozilla::Version("42"));
+  ASSERT_TRUE(mozilla::Version("42.0b2") < mozilla::Version("43.0a1"));
+  ASSERT_TRUE(mozilla::Version("42") < mozilla::Version("43.0a1"));
+  ASSERT_TRUE(mozilla::Version("42.0") < mozilla::Version("43.0a1"));
+  ASSERT_TRUE(mozilla::Version("42.0.5") < mozilla::Version("43.0a1"));
+  ASSERT_TRUE(mozilla::Version("42.1") < mozilla::Version("43.0a1"));
+  ASSERT_TRUE(mozilla::Version("42.0a1") < mozilla::Version("42"));
+  ASSERT_TRUE(mozilla::Version("42.0a1") < mozilla::Version("42.0.5"));
+  ASSERT_TRUE(mozilla::Version("42.0b7") < mozilla::Version("42.0.5"));
+  ASSERT_TRUE(mozilla::Version("") == mozilla::Version("0"));
+
+  // Note these two; one would expect for 42.0b1 and 42b1 to compare the
+  // same, but they do not.  If this ever changes, we want to know, so
+  // leave the test here to fail.
+  ASSERT_TRUE(mozilla::Version("42.0a1") < mozilla::Version("42.0b2"));
+  ASSERT_FALSE(mozilla::Version("42.0a1") < mozilla::Version("42b2"));
+}
+
--- a/gfx/tests/gtest/moz.build
+++ b/gfx/tests/gtest/moz.build
@@ -8,16 +8,17 @@ UNIFIED_SOURCES += [
     'gfxSurfaceRefCountTest.cpp',
     # Disabled on suspicion of causing bug 904227
     #'gfxWordCacheTest.cpp',
     'TestAsyncPanZoomController.cpp',
     'TestBufferRotation.cpp',
     'TestColorNames.cpp',
     'TestCompositor.cpp',
     'TestGfxPrefs.cpp',
+    'TestGfxWidgets.cpp',
     'TestLayers.cpp',
     'TestRegion.cpp',
     'TestSkipChars.cpp',
     # Hangs on linux in ApplyGdkScreenFontOptions
     #'gfxFontSelectionTest.cpp',
     'TestTextures.cpp',
     # Test works but it doesn't assert anything
     #'gfxTextRunPerfTest.cpp',
--- a/widget/GfxInfoBase.cpp
+++ b/widget/GfxInfoBase.cpp
@@ -11,26 +11,28 @@
 
 #include "GfxInfoWebGL.h"
 #include "GfxDriverInfo.h"
 #include "nsCOMPtr.h"
 #include "nsCOMArray.h"
 #include "nsAutoPtr.h"
 #include "nsString.h"
 #include "nsUnicharUtils.h"
+#include "nsVersionComparator.h"
 #include "mozilla/Services.h"
 #include "mozilla/Observer.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMHTMLCollection.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMNodeList.h"
 #include "nsTArray.h"
 #include "nsXULAppAPI.h"
+#include "nsIXULAppInfo.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Logging.h"
 
 #if defined(MOZ_CRASHREPORTER)
 #include "nsExceptionHandler.h"
 #endif
@@ -212,16 +214,39 @@ BlacklistNodeToTextValue(nsIDOMNode *aBl
     return false;
 
   value.Trim(" \t\r\n");
   aValue = value;
 
   return true;
 }
 
+// <foo attr=Hello/> finds "Hello" if the aAttrName is "attr".
+static bool
+BlacklistAttrToTextValue(nsIDOMNode *aBlacklistNode,
+                         const nsAString& aAttrName,
+                         nsAString& aValue)
+{
+  nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aBlacklistNode);
+  if (!element) {
+    return false;
+  }
+
+  nsAutoString value;
+  if (NS_FAILED(element->GetAttribute(aAttrName, value))) {
+    return false;
+  }
+
+  value.Trim(" \t\r\n");
+  aValue = value;
+
+  return true;
+}
+
+
 static OperatingSystem
 BlacklistOSToOperatingSystem(const nsAString& os)
 {
   if (os.EqualsLiteral("WINNT 5.1"))
     return DRIVER_OS_WINDOWS_XP;
   else if (os.EqualsLiteral("WINNT 5.2"))
     return DRIVER_OS_WINDOWS_SERVER_2003;
   else if (os.EqualsLiteral("WINNT 6.0"))
@@ -403,16 +428,52 @@ BlacklistEntryToDriverInfo(nsIDOMNode* a
 
   nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aBlacklistEntry);
   if (!element)
     return false;
 
   nsCOMPtr<nsIDOMNode> dataNode;
   nsAutoString dataValue;
 
+  // If we get an application version to be zero, something is not working
+  // and we are not going to bother checking the blocklist versions.
+  // See TestGfxWidgets.cpp for how version comparison works.
+  // <versionRange minVersion="42.0a1" maxVersion="45.0"></versionRange>
+  static mozilla::Version zeroV("0");
+  static mozilla::Version appV(GfxInfoBase::GetApplicationVersion().get());
+  if (appV <= zeroV) {
+      gfxCriticalErrorOnce(gfxCriticalError::DefaultOptions(false)) << "Invalid application version " << GfxInfoBase::GetApplicationVersion().get();
+  } else if (BlacklistNodeGetChildByName(element,
+                                         NS_LITERAL_STRING("versionRange"),
+                                         getter_AddRefs(dataNode))) {
+    if (BlacklistAttrToTextValue(dataNode,
+                                 NS_LITERAL_STRING("minVersion"),
+                                 dataValue)) {
+      mozilla::Version minV(NS_ConvertUTF16toUTF8(dataValue).get());
+      if (minV > zeroV && appV < minV) {
+        // The version of the application is less than the minimal version
+        // this blocklist entry applies to, so we can just ignore it by
+        // returning false and letting the caller deal with it.
+        return false;
+      }
+    }
+
+    if (BlacklistAttrToTextValue(dataNode,
+                                 NS_LITERAL_STRING("maxVersion"),
+                                 dataValue)) {
+      mozilla::Version maxV(NS_ConvertUTF16toUTF8(dataValue).get());
+      if (maxV > zeroV && appV > maxV) {
+        // The version of the application is more than the maximal version
+        // this blocklist entry applies to, so we can just ignore it by
+        // returning false and letting the caller deal with it.
+        return false;
+      }
+    }
+  }
+
   // <os>WINNT 6.0</os>
   if (BlacklistNodeGetChildByName(element, NS_LITERAL_STRING("os"),
                                   getter_AddRefs(dataNode))) {
     BlacklistNodeToTextValue(dataNode, dataValue);
     aDriverInfo.mOperatingSystem = BlacklistOSToOperatingSystem(dataValue);
   }
 
   // <osversion>14</osversion> currently only used for Android
@@ -527,19 +588,19 @@ BlacklistEntriesToDriverInfo(nsIDOMHTMLC
   for (uint32_t i = 0; i < length; ++i) {
     nsCOMPtr<nsIDOMNode> blacklistEntry;
     if (NS_SUCCEEDED(aBlacklistEntries->Item(i,
                                              getter_AddRefs(blacklistEntry))) &&
         blacklistEntry) {
       GfxDriverInfo di;
       if (BlacklistEntryToDriverInfo(blacklistEntry, di)) {
         aDriverInfo[i] = di;
+        // Prevent di falling out of scope from destroying the devices.
+        di.mDeleteDevices = false;
       }
-      // Prevent di falling out of scope from destroying the devices.
-      di.mDeleteDevices = false;
     }
   }
 }
 
 NS_IMETHODIMP
 GfxInfoBase::Observe(nsISupports* aSubject, const char* aTopic,
                      const char16_t* aData)
 {
@@ -608,16 +669,30 @@ GfxInfoBase::FindBlocklistedDeviceInList
                                          nsAString& aSuggestedVersion,
                                          int32_t aFeature,
                                          OperatingSystem os)
 {
   int32_t status = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
 
   uint32_t i = 0;
   for (; i < info.Length(); i++) {
+    // Do the operating system check first, no point in getting the driver
+    // info if we won't need to use it. Note that this also catches the
+    // application version mismatches that would leave operating system
+    // set to unknown.
+    if (info[i].mOperatingSystem != DRIVER_OS_ALL &&
+        info[i].mOperatingSystem != os)
+    {
+      continue;
+    }
+
+    if (info[i].mOperatingSystemVersion && info[i].mOperatingSystemVersion != OperatingSystemVersion()) {
+        continue;
+    }
+
     // XXX: it would be better not to do this everytime round the loop
     nsAutoString adapterVendorID;
     nsAutoString adapterDeviceID;
     nsAutoString adapterDriverVersionString;
     if (info[i].mGpu2) {
       if (NS_FAILED(GetAdapterVendorID2(adapterVendorID)) ||
           NS_FAILED(GetAdapterDeviceID2(adapterDeviceID)) ||
           NS_FAILED(GetAdapterDriverVersion2(adapterDriverVersionString)))
@@ -633,27 +708,16 @@ GfxInfoBase::FindBlocklistedDeviceInList
       }
     }
 
 #if defined(XP_WIN) || defined(ANDROID)
     uint64_t driverVersion;
     ParseDriverVersion(adapterDriverVersionString, &driverVersion);
 #endif
 
-
-    if (info[i].mOperatingSystem != DRIVER_OS_ALL &&
-        info[i].mOperatingSystem != os)
-    {
-      continue;
-    }
-
-    if (info[i].mOperatingSystemVersion && info[i].mOperatingSystemVersion != OperatingSystemVersion()) {
-        continue;
-    }
-
     if (!info[i].mAdapterVendor.Equals(GfxDriverInfo::GetDeviceVendor(VendorAll), nsCaseInsensitiveStringComparator()) &&
         !info[i].mAdapterVendor.Equals(adapterVendorID, nsCaseInsensitiveStringComparator())) {
       continue;
     }
 
     if (info[i].mDevices != GfxDriverInfo::allDevices && info[i].mDevices->Length()) {
         bool deviceMatches = false;
         for (uint32_t j = 0; j < info[i].mDevices->Length(); j++) {
@@ -1014,16 +1078,34 @@ nsresult GfxInfoBase::GetInfo(JSContext*
   if (!obj.mOk) {
     return NS_ERROR_FAILURE;
   }
 
   aResult.setObject(*obj.mObj);
   return NS_OK;
 }
 
+const nsCString&
+GfxInfoBase::GetApplicationVersion()
+{
+  static nsAutoCString version;
+  static bool versionInitialized = false;
+  if (!versionInitialized) {
+    // If we fail to get the version, we will not try again.
+    versionInitialized = true;
+
+    // Get the version from xpcom/system/nsIXULAppInfo.idl
+    nsCOMPtr<nsIXULAppInfo> app = do_GetService("@mozilla.org/xre/app-info;1");
+    if (app) {
+      app->GetVersion(version);
+    }
+  }
+  return version;
+}
+
 void
 GfxInfoBase::AddCollector(GfxInfoCollectorBase* collector)
 {
   InitCollectors();
   sCollectors->AppendElement(collector);
 }
 
 void
--- a/widget/GfxInfoBase.h
+++ b/widget/GfxInfoBase.h
@@ -77,16 +77,19 @@ public:
   static bool mDriverInfoObserverInitialized;
 
   virtual nsString Model() { return EmptyString(); }
   virtual nsString Hardware() { return EmptyString(); }
   virtual nsString Product() { return EmptyString(); }
   virtual nsString Manufacturer() { return EmptyString(); }
   virtual uint32_t OperatingSystemVersion() { return 0; }
 
+  // Convenience to get the application version
+  static const nsCString& GetApplicationVersion();
+
 protected:
 
   virtual ~GfxInfoBase();
 
   virtual nsresult GetFeatureStatusImpl(int32_t aFeature, int32_t* aStatus,
                                         nsAString& aSuggestedDriverVersion,
                                         const nsTArray<GfxDriverInfo>& aDriverInfo,
                                         OperatingSystem* aOS = nullptr);