Bug 791742: Consider driver version substrings in decimals. r=joedrew
authorBas Schouten <bschouten@mozilla.com>
Mon, 17 Sep 2012 20:50:38 +0000
changeset 107406 dbd4f12bebc071ed9451f27b78912706e7e41640
parent 107405 efd7b5216aa5ad8477126e68ac66a0dc3c9c8f2f
child 107407 eacd4f900b5632dccb50c91d76e13ca9d7960742
push id23486
push usergraememcc_firefox@graeme-online.co.uk
push dateWed, 19 Sep 2012 14:18:40 +0000
treeherdermozilla-central@0c8ac138706e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjoedrew
bugs791742
milestone18.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 791742: Consider driver version substrings in decimals. r=joedrew
widget/windows/GfxInfo.cpp
widget/xpwidgets/GfxDriverInfo.h
--- a/widget/windows/GfxInfo.cpp
+++ b/widget/windows/GfxInfo.cpp
@@ -28,19 +28,16 @@ using namespace mozilla;
 using namespace mozilla::widget;
 
 #ifdef DEBUG
 NS_IMPL_ISUPPORTS_INHERITED1(GfxInfo, GfxInfoBase, nsIGfxInfoDebug)
 #endif
 
 static const uint32_t allWindowsVersions = 0xffffffff;
 
-#define V(a,b,c,d) GFX_DRIVER_VERSION(a,b,c,d)
-
-
 GfxInfo::GfxInfo()
  :  mWindowsVersion(0),
     mHasDualGPU(false),
     mIsGPU2Active(false)
 {
 }
 
 /* GetD2DEnabled and GetDwriteEnabled shouldn't be called until after gfxPlatform initialization
--- a/widget/xpwidgets/GfxDriverInfo.h
+++ b/widget/xpwidgets/GfxDriverInfo.h
@@ -4,18 +4,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "prtypes.h"
 #include "nsString.h"
 
 #ifndef __mozilla_widget_GfxDriverInfo_h__
 #define __mozilla_widget_GfxDriverInfo_h__
 
-#define V(a,b,c,d) GFX_DRIVER_VERSION(a,b,c,d)
-
 // Macros for adding a blocklist item to the static list.
 #define APPEND_TO_DRIVER_BLOCKLIST(os, vendor, devices, feature, featureStatus, driverComparator, driverVersion, suggestedVersion) \
     mDriverInfo->AppendElement(GfxDriverInfo(os, vendor, devices, feature, featureStatus, driverComparator, driverVersion, suggestedVersion))
 #define APPEND_TO_DRIVER_BLOCKLIST2(os, vendor, devices, feature, featureStatus, driverComparator, driverVersion) \
     mDriverInfo->AppendElement(GfxDriverInfo(os, vendor, devices, feature, featureStatus, driverComparator, driverVersion))
 
 namespace mozilla {
 namespace widget {
@@ -119,25 +117,110 @@ struct GfxDriverInfo
 
   static const nsAString& GetDeviceVendor(DeviceVendor id);
   static nsAString* mDeviceVendors[DeviceVendorMax];
 };
 
 #define GFX_DRIVER_VERSION(a,b,c,d) \
   ((uint64_t(a)<<48) | (uint64_t(b)<<32) | (uint64_t(c)<<16) | uint64_t(d))
 
+static uint64_t
+V(uint32_t a, uint32_t b, uint32_t c, uint32_t d)
+{
+  // We make sure every driver number is padded by 0s, this will allow us the
+  // easiest 'compare as if decimals' approach. See ParseDriverVersion for a
+  // more extensive explanation of this approach.
+  while (b > 0 && b < 1000) {
+    b *= 10;
+  }
+  while (c > 0 && c < 1000) {
+    c *= 10;
+  }
+  while (d > 0 && d < 1000) {
+    d *= 10;
+  }
+  return GFX_DRIVER_VERSION(a, b, c, d);
+}
+
+// All destination string storage needs to have at least 5 bytes available.
+static bool SplitDriverVersion(const char *aSource, char *aAStr, char *aBStr, char *aCStr, char *aDStr)
+{
+  // sscanf doesn't do what we want here to we parse this manually.
+  int len = strlen(aSource);
+  char *dest[4] = { aAStr, aBStr, aCStr, aDStr };
+  int destIdx = 0;
+  int destPos = 0;
+
+  for (int i = 0; i < len; i++) {
+    if (destIdx > ArrayLength(dest)) {
+      // Invalid format found. Ensure we don't access dest beyond bounds.
+      return false;
+    }
+
+    if (aSource[i] == '.') {
+      dest[destIdx++][destPos] = 0;
+      destPos = 0;
+      continue;
+    }
+
+    if (destPos > 3) {
+      // Ignore more than 4 chars. Ensure we never access dest[destIdx]
+      // beyond its bounds.
+      continue;
+    }
+
+    dest[destIdx][destPos++] = aSource[i];
+  }
+
+  // Add last terminator.
+  dest[destIdx][destPos] = 0;
+
+  if (destIdx != ArrayLength(dest) - 1) {
+    return false;
+  }
+  return true;
+}
+
+// This allows us to pad driver versiopn 'substrings' with 0s, this
+// effectively allows us to treat the version numbers as 'decimals'. This is
+// a little strange but this method seems to do the right thing for all
+// different vendor's driver strings. i.e. .98 will become 9800, which is
+// larger than .978 which would become 9780.
+static void PadDriverDecimal(char *aString)
+{
+  for (int i = 0; i < 4; i++) {
+    if (!aString[i]) {
+      for (int c = i; c < 4; c++) {
+        aString[c] = '0';
+      }
+      break;
+    }
+  }
+  aString[4] = 0;
+}
+
 inline bool
 ParseDriverVersion(nsAString& aVersion, uint64_t *aNumericVersion)
 {
 #if defined(XP_WIN)
   int a, b, c, d;
+  char aStr[8], bStr[8], cStr[8], dStr[8];
   /* honestly, why do I even bother */
-  if (sscanf(NS_LossyConvertUTF16toASCII(aVersion).get(),
-             "%d.%d.%d.%d", &a, &b, &c, &d) != 4)
+  if (!SplitDriverVersion(NS_LossyConvertUTF16toASCII(aVersion).get(), aStr, bStr, cStr, dStr))
     return false;
+
+  PadDriverDecimal(bStr);
+  PadDriverDecimal(cStr);
+  PadDriverDecimal(dStr);
+
+  a = atoi(aStr);
+  b = atoi(bStr);
+  c = atoi(cStr);
+  d = atoi(dStr);
+
   if (a < 0 || a > 0xffff) return false;
   if (b < 0 || b > 0xffff) return false;
   if (c < 0 || c > 0xffff) return false;
   if (d < 0 || d > 0xffff) return false;
 
   *aNumericVersion = GFX_DRIVER_VERSION(a, b, c, d);
 #elif defined(ANDROID)
   // Can't use aVersion.ToInteger() because that's not compiled into our code