Bug 791742: Consider driver version substrings in decimals. r=joedrew
authorBas Schouten <bschouten@mozilla.com>
Mon, 17 Sep 2012 20:50:38 +0000
changeset 111002 dbd4f12bebc071ed9451f27b78912706e7e41640
parent 111001 efd7b5216aa5ad8477126e68ac66a0dc3c9c8f2f
child 111003 eacd4f900b5632dccb50c91d76e13ca9d7960742
push idunknown
push userunknown
push dateunknown
reviewersjoedrew
bugs791742
milestone18.0a1
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