michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef __mozilla_widget_GfxDriverInfo_h__ michael@0: #define __mozilla_widget_GfxDriverInfo_h__ michael@0: michael@0: #include "mozilla/ArrayUtils.h" // ArrayLength michael@0: #include "nsString.h" michael@0: michael@0: // Macros for adding a blocklist item to the static list. michael@0: #define APPEND_TO_DRIVER_BLOCKLIST(os, vendor, devices, feature, featureStatus, driverComparator, driverVersion, suggestedVersion) \ michael@0: mDriverInfo->AppendElement(GfxDriverInfo(os, vendor, devices, feature, featureStatus, driverComparator, driverVersion, suggestedVersion)) michael@0: #define APPEND_TO_DRIVER_BLOCKLIST2(os, vendor, devices, feature, featureStatus, driverComparator, driverVersion) \ michael@0: mDriverInfo->AppendElement(GfxDriverInfo(os, vendor, devices, feature, featureStatus, driverComparator, driverVersion)) michael@0: michael@0: #define APPEND_TO_DRIVER_BLOCKLIST_RANGE(os, vendor, devices, feature, featureStatus, driverComparator, driverVersion, driverVersionMax, suggestedVersion) \ michael@0: do { \ michael@0: MOZ_ASSERT(driverComparator == DRIVER_BETWEEN_EXCLUSIVE || \ michael@0: driverComparator == DRIVER_BETWEEN_INCLUSIVE || \ michael@0: driverComparator == DRIVER_BETWEEN_INCLUSIVE_START); \ michael@0: GfxDriverInfo info(os, vendor, devices, feature, featureStatus, driverComparator, driverVersion, suggestedVersion); \ michael@0: info.mDriverVersionMax = driverVersionMax; \ michael@0: mDriverInfo->AppendElement(info); \ michael@0: } while (false) michael@0: michael@0: namespace mozilla { michael@0: namespace widget { michael@0: michael@0: enum OperatingSystem { michael@0: DRIVER_OS_UNKNOWN = 0, michael@0: DRIVER_OS_WINDOWS_XP, michael@0: DRIVER_OS_WINDOWS_SERVER_2003, michael@0: DRIVER_OS_WINDOWS_VISTA, michael@0: DRIVER_OS_WINDOWS_7, michael@0: DRIVER_OS_WINDOWS_8, michael@0: DRIVER_OS_WINDOWS_8_1, michael@0: DRIVER_OS_LINUX, michael@0: DRIVER_OS_OS_X_10_5, michael@0: DRIVER_OS_OS_X_10_6, michael@0: DRIVER_OS_OS_X_10_7, michael@0: DRIVER_OS_OS_X_10_8, michael@0: DRIVER_OS_ANDROID, michael@0: DRIVER_OS_ALL michael@0: }; michael@0: michael@0: enum VersionComparisonOp { michael@0: DRIVER_LESS_THAN, // driver < version michael@0: DRIVER_LESS_THAN_OR_EQUAL, // driver <= version michael@0: DRIVER_GREATER_THAN, // driver > version michael@0: DRIVER_GREATER_THAN_OR_EQUAL, // driver >= version michael@0: DRIVER_EQUAL, // driver == version michael@0: DRIVER_NOT_EQUAL, // driver != version michael@0: DRIVER_BETWEEN_EXCLUSIVE, // driver > version && driver < versionMax michael@0: DRIVER_BETWEEN_INCLUSIVE, // driver >= version && driver <= versionMax michael@0: DRIVER_BETWEEN_INCLUSIVE_START, // driver >= version && driver < versionMax michael@0: DRIVER_COMPARISON_IGNORED michael@0: }; michael@0: michael@0: enum DeviceFamily { michael@0: IntelGMA500, michael@0: IntelGMA900, michael@0: IntelGMA950, michael@0: IntelGMA3150, michael@0: IntelGMAX3000, michael@0: IntelGMAX4500HD, michael@0: IntelMobileHDGraphics, michael@0: NvidiaBlockD3D9Layers, michael@0: RadeonX1000, michael@0: Geforce7300GT, michael@0: DeviceFamilyMax michael@0: }; michael@0: michael@0: enum DeviceVendor { michael@0: VendorAll, michael@0: VendorIntel, michael@0: VendorNVIDIA, michael@0: VendorAMD, michael@0: VendorATI, michael@0: VendorMicrosoft, michael@0: DeviceVendorMax michael@0: }; michael@0: michael@0: /* Array of devices to match, or an empty array for all devices */ michael@0: typedef nsTArray GfxDeviceFamily; michael@0: michael@0: struct GfxDriverInfo michael@0: { michael@0: // If |ownDevices| is true, you are transferring ownership of the devices michael@0: // array, and it will be deleted when this GfxDriverInfo is destroyed. michael@0: GfxDriverInfo(OperatingSystem os, nsAString& vendor, GfxDeviceFamily* devices, michael@0: int32_t feature, int32_t featureStatus, VersionComparisonOp op, michael@0: uint64_t driverVersion, const char *suggestedVersion = nullptr, michael@0: bool ownDevices = false); michael@0: michael@0: GfxDriverInfo(); michael@0: GfxDriverInfo(const GfxDriverInfo&); michael@0: ~GfxDriverInfo(); michael@0: michael@0: OperatingSystem mOperatingSystem; michael@0: uint32_t mOperatingSystemVersion; michael@0: michael@0: nsString mAdapterVendor; michael@0: michael@0: static GfxDeviceFamily* const allDevices; michael@0: GfxDeviceFamily* mDevices; michael@0: michael@0: // Whether the mDevices array should be deleted when this structure is michael@0: // deallocated. False by default. michael@0: bool mDeleteDevices; michael@0: michael@0: /* A feature from nsIGfxInfo, or all features */ michael@0: int32_t mFeature; michael@0: static int32_t allFeatures; michael@0: michael@0: /* A feature status from nsIGfxInfo */ michael@0: int32_t mFeatureStatus; michael@0: michael@0: VersionComparisonOp mComparisonOp; michael@0: michael@0: /* versions are assumed to be A.B.C.D packed as 0xAAAABBBBCCCCDDDD */ michael@0: uint64_t mDriverVersion; michael@0: uint64_t mDriverVersionMax; michael@0: static uint64_t allDriverVersions; michael@0: michael@0: const char *mSuggestedVersion; michael@0: michael@0: static const GfxDeviceFamily* GetDeviceFamily(DeviceFamily id); michael@0: static GfxDeviceFamily* mDeviceFamilies[DeviceFamilyMax]; michael@0: michael@0: static const nsAString& GetDeviceVendor(DeviceVendor id); michael@0: static nsAString* mDeviceVendors[DeviceVendorMax]; michael@0: michael@0: nsString mModel, mHardware, mProduct, mManufacturer; michael@0: }; michael@0: michael@0: #define GFX_DRIVER_VERSION(a,b,c,d) \ michael@0: ((uint64_t(a)<<48) | (uint64_t(b)<<32) | (uint64_t(c)<<16) | uint64_t(d)) michael@0: michael@0: inline uint64_t michael@0: V(uint32_t a, uint32_t b, uint32_t c, uint32_t d) michael@0: { michael@0: // We make sure every driver number is padded by 0s, this will allow us the michael@0: // easiest 'compare as if decimals' approach. See ParseDriverVersion for a michael@0: // more extensive explanation of this approach. michael@0: while (b > 0 && b < 1000) { michael@0: b *= 10; michael@0: } michael@0: while (c > 0 && c < 1000) { michael@0: c *= 10; michael@0: } michael@0: while (d > 0 && d < 1000) { michael@0: d *= 10; michael@0: } michael@0: return GFX_DRIVER_VERSION(a, b, c, d); michael@0: } michael@0: michael@0: // All destination string storage needs to have at least 5 bytes available. michael@0: inline bool SplitDriverVersion(const char *aSource, char *aAStr, char *aBStr, char *aCStr, char *aDStr) michael@0: { michael@0: // sscanf doesn't do what we want here to we parse this manually. michael@0: int len = strlen(aSource); michael@0: char *dest[4] = { aAStr, aBStr, aCStr, aDStr }; michael@0: unsigned destIdx = 0; michael@0: unsigned destPos = 0; michael@0: michael@0: for (int i = 0; i < len; i++) { michael@0: if (destIdx > ArrayLength(dest)) { michael@0: // Invalid format found. Ensure we don't access dest beyond bounds. michael@0: return false; michael@0: } michael@0: michael@0: if (aSource[i] == '.') { michael@0: dest[destIdx++][destPos] = 0; michael@0: destPos = 0; michael@0: continue; michael@0: } michael@0: michael@0: if (destPos > 3) { michael@0: // Ignore more than 4 chars. Ensure we never access dest[destIdx] michael@0: // beyond its bounds. michael@0: continue; michael@0: } michael@0: michael@0: dest[destIdx][destPos++] = aSource[i]; michael@0: } michael@0: michael@0: // Add last terminator. michael@0: dest[destIdx][destPos] = 0; michael@0: michael@0: if (destIdx != ArrayLength(dest) - 1) { michael@0: return false; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: // This allows us to pad driver version 'substrings' with 0s, this michael@0: // effectively allows us to treat the version numbers as 'decimals'. This is michael@0: // a little strange but this method seems to do the right thing for all michael@0: // different vendor's driver strings. i.e. .98 will become 9800, which is michael@0: // larger than .978 which would become 9780. michael@0: inline void PadDriverDecimal(char *aString) michael@0: { michael@0: for (int i = 0; i < 4; i++) { michael@0: if (!aString[i]) { michael@0: for (int c = i; c < 4; c++) { michael@0: aString[c] = '0'; michael@0: } michael@0: break; michael@0: } michael@0: } michael@0: aString[4] = 0; michael@0: } michael@0: michael@0: inline bool michael@0: ParseDriverVersion(const nsAString& aVersion, uint64_t *aNumericVersion) michael@0: { michael@0: *aNumericVersion = 0; michael@0: michael@0: #if defined(XP_WIN) michael@0: int a, b, c, d; michael@0: char aStr[8], bStr[8], cStr[8], dStr[8]; michael@0: /* honestly, why do I even bother */ michael@0: if (!SplitDriverVersion(NS_LossyConvertUTF16toASCII(aVersion).get(), aStr, bStr, cStr, dStr)) michael@0: return false; michael@0: michael@0: PadDriverDecimal(bStr); michael@0: PadDriverDecimal(cStr); michael@0: PadDriverDecimal(dStr); michael@0: michael@0: a = atoi(aStr); michael@0: b = atoi(bStr); michael@0: c = atoi(cStr); michael@0: d = atoi(dStr); michael@0: michael@0: if (a < 0 || a > 0xffff) return false; michael@0: if (b < 0 || b > 0xffff) return false; michael@0: if (c < 0 || c > 0xffff) return false; michael@0: if (d < 0 || d > 0xffff) return false; michael@0: michael@0: *aNumericVersion = GFX_DRIVER_VERSION(a, b, c, d); michael@0: return true; michael@0: #elif defined(ANDROID) michael@0: // Can't use aVersion.ToInteger() because that's not compiled into our code michael@0: // unless we have XPCOM_GLUE_AVOID_NSPR disabled. michael@0: *aNumericVersion = atoi(NS_LossyConvertUTF16toASCII(aVersion).get()); michael@0: return true; michael@0: #else michael@0: return false; michael@0: #endif michael@0: } michael@0: michael@0: } michael@0: } michael@0: michael@0: #endif /*__mozilla_widget_GfxDriverInfo_h__ */