# Global Metrics

path: .metrics.nom.functions
old: 2.0
new: 6.0
path: .metrics.nom.total
old: 2.0
new: 6.0
path: .metrics.cognitive.sum
old: 2.0
new: 35.0
path: .metrics.cognitive.average
old: 1.0
new: 5.833333333333333
path: .metrics.cyclomatic.average
old: 1.25
new: 3.4166666666666665
path: .metrics.cyclomatic.sum
old: 5.0
new: 41.0
path: .metrics.nargs.sum
old: 4.0
new: 12.0
path: .metrics.nexits.sum
old: 2.0
new: 14.0
path: .metrics.nexits.average
old: 1.0
new: 2.3333333333333335
path: .metrics.loc.lloc
old: 8.0
new: 58.0
path: .metrics.loc.cloc
old: 6.0
new: 70.0
path: .metrics.loc.sloc
old: 38.0
new: 521.0
path: .metrics.loc.ploc
old: 26.0
new: 346.0
path: .metrics.loc.blank
old: 6.0
new: 105.0
path: .metrics.halstead.difficulty
old: 9.0
new: 34.61666666666667
path: .metrics.halstead.n1
old: 12.0
new: 31.0
path: .metrics.halstead.purity_ratio
old: 1.911445014258101
new: 1.751178017123569
path: .metrics.halstead.bugs
old: 0.1053348789179992
new: 1.748569413319447
path: .metrics.halstead.level
old: 0.1111111111111111
new: 0.02888781896966779
path: .metrics.halstead.time
old: 312.08125051722124
new: 21107.349088410796
path: .metrics.halstead.length
old: 113.0
new: 1333.0
path: .metrics.halstead.volume
old: 624.1625010344425
new: 10975.415029120682
path: .metrics.halstead.N1
old: 62.0
new: 730.0
path: .metrics.halstead.N2
old: 51.0
new: 603.0
path: .metrics.halstead.n2
old: 34.0
new: 270.0
path: .metrics.halstead.effort
old: 5617.462509309982
new: 379932.2835913943
path: .metrics.halstead.vocabulary
old: 46.0
new: 301.0
path: .metrics.halstead.estimated_program_length
old: 215.99328661116544
new: 2334.3202968257174
path: .metrics.mi.mi_visual_studio
old: 45.29343175316955
new: 6.929299092110443
path: .metrics.mi.mi_sei
old: 65.41942323929804
new: -27.54044361920933
path: .metrics.mi.mi_original
old: 77.45176829791993
new: 11.849101447508858

# Spaces Data

## Minimal test - lines (118, 519)

path: .spaces[0].metrics.cognitive.sum
old: 2.0
new: 35.0
path: .spaces[0].metrics.cognitive.average
old: 1.0
new: 5.833333333333333
path: .spaces[0].metrics.cyclomatic.average
old: 1.3333333333333333
new: 3.636363636363636
path: .spaces[0].metrics.cyclomatic.sum
old: 4.0
new: 40.0
path: .spaces[0].metrics.loc.cloc
old: 0.0
new: 60.0
path: .spaces[0].metrics.loc.lloc
old: 8.0
new: 58.0
path: .spaces[0].metrics.loc.ploc
old: 22.0
new: 307.0
path: .spaces[0].metrics.loc.sloc
old: 26.0
new: 402.0
path: .spaces[0].metrics.loc.blank
old: 4.0
new: 35.0
path: .spaces[0].metrics.halstead.bugs
old: 0.10417542459227112
new: 1.453013230916801
path: .spaces[0].metrics.halstead.estimated_program_length
old: 190.22626787690945
new: 2192.140212021002
path: .spaces[0].metrics.halstead.purity_ratio
old: 1.745195118136784
new: 1.907867895579636
path: .spaces[0].metrics.halstead.difficulty
old: 9.4
new: 30.69607843137255
path: .spaces[0].metrics.halstead.N1
old: 62.0
new: 644.0
path: .spaces[0].metrics.halstead.length
old: 109.0
new: 1149.0
path: .spaces[0].metrics.halstead.n1
old: 12.0
new: 31.0
path: .spaces[0].metrics.halstead.N2
old: 47.0
new: 505.0
path: .spaces[0].metrics.halstead.vocabulary
old: 42.0
new: 286.0
path: .spaces[0].metrics.halstead.time
old: 306.94269063217325
new: 15988.721226370182
path: .spaces[0].metrics.halstead.n2
old: 30.0
new: 255.0
path: .spaces[0].metrics.halstead.volume
old: 587.7625990828849
new: 9375.69216595837
path: .spaces[0].metrics.halstead.effort
old: 5524.968431379119
new: 287796.9820746633
path: .spaces[0].metrics.halstead.level
old: 0.10638297872340426
new: 0.03257745129351645
path: .spaces[0].metrics.nexits.average
old: 1.0
new: 2.3333333333333335
path: .spaces[0].metrics.nexits.sum
old: 2.0
new: 14.0
path: .spaces[0].metrics.nom.total
old: 2.0
new: 6.0
path: .spaces[0].metrics.nom.functions
old: 2.0
new: 6.0
path: .spaces[0].metrics.mi.mi_visual_studio
old: 49.20582213029712
new: 9.999369960700664
path: .spaces[0].metrics.mi.mi_original
old: 84.14195584280807
new: 17.098922632798136
path: .spaces[0].metrics.mi.mi_sei
old: 46.097609870722465
new: -18.789103569057204
path: .spaces[0].metrics.nargs.sum
old: 4.0
new: 12.0

### Code

    namespace mozilla {
    namespace widget {

    enum class OperatingSystem : uint8_t {
      Unknown,
      Windows,
      WindowsXP,
      WindowsServer2003,
      WindowsVista,
      Windows7,
      Windows8,
      Windows8_1,
      Windows10,
      RecentWindows10,
      NotRecentWindows10,
      Linux,
      OSX,
      OSX10_5,
      OSX10_6,
      OSX10_7,
      OSX10_8,
      OSX10_9,
      OSX10_10,
      OSX10_11,
      OSX10_12,
      OSX10_13,
      OSX10_14,
      OSX10_15,
      OSX11_0,
      Android,
      Ios
    };

    enum VersionComparisonOp {
      DRIVER_LESS_THAN,                    // driver <  version
      DRIVER_BUILD_ID_LESS_THAN,           // driver build id <  version
      DRIVER_LESS_THAN_OR_EQUAL,           // driver <= version
      DRIVER_BUILD_ID_LESS_THAN_OR_EQUAL,  // driver build id <= version
      DRIVER_GREATER_THAN,                 // driver >  version
      DRIVER_GREATER_THAN_OR_EQUAL,        // driver >= version
      DRIVER_EQUAL,                        // driver == version
      DRIVER_NOT_EQUAL,                    // driver != version
      DRIVER_BETWEEN_EXCLUSIVE,        // driver > version && driver < versionMax
      DRIVER_BETWEEN_INCLUSIVE,        // driver >= version && driver <= versionMax
      DRIVER_BETWEEN_INCLUSIVE_START,  // driver >= version && driver < versionMax
      DRIVER_COMPARISON_IGNORED
    };

    enum class DeviceFamily : uint8_t {
      All,
      IntelAll,
      NvidiaAll,
      AtiAll,
      MicrosoftAll,
      ParallelsAll,
      QualcommAll,
      AppleAll,
      AmazonAll,
      IntelGMA500,
      IntelGMA900,
      IntelGMA950,
      IntelGMA3150,
      IntelGMAX3000,
      IntelGMAX4500HD,
      IntelHDGraphicsToIvyBridge,
      IntelHDGraphicsToSandyBridge,
      IntelHaswell,
      IntelSandyBridge,
      IntelHD520,
      IntelMobileHDGraphics,
      NvidiaBlockD3D9Layers,
      RadeonX1000,
      RadeonCaicos,
      Geforce7300GT,
      Nvidia310M,
      Nvidia8800GTS,
      Bug1137716,
      Bug1116812,
      Bug1155608,
      Bug1207665,
      Bug1447141,
      AmdR600,
      NvidiaBlockWebRender,
      NvidiaRolloutWebRender,
      IntelRolloutWebRender,
      IntelModernRolloutWebRender,
      AtiRolloutWebRender,

      Max
    };

    enum class DeviceVendor : uint8_t {
      All,  // There is an assumption that this is the first enum
      Intel,
      NVIDIA,
      ATI,
      Microsoft,
      Parallels,
      VMWare,
      VirtualBox,
      Qualcomm,
      MicrosoftBasic,
      MicrosoftHyperV,
      Apple,
      Amazon,

      Max
    };

    enum DriverVendor : uint8_t {
      All,  // There is an assumption that this is the first enum
      // Wildcard for all Mesa drivers.
      MesaAll,
      // Note that the following list of Mesa drivers is not comprehensive; we pull
      // the DRI driver at runtime. These drivers are provided for convenience when
      // populating the local blocklist.
      MesaLLVMPipe,
      MesaSoftPipe,
      MesaSWRast,
      // AMD
      MesaR600,
      // Nouveau: Open-source nvidia
      MesaNouveau,
      // A generic ID to be provided when we can't determine the DRI driver on Mesa.
      MesaUnknown,
      // Wildcard for all non-Mesa drivers.
      NonMesaAll,
      // Wildcard for all hardware Mesa drivers.
      HardwareMesaAll,
      // Wildcard for all software Mesa drivers.
      SoftwareMesaAll,

      Max
    };

    enum class DesktopEnvironment : uint8_t {
      All,  // There is an assumption that this is the first enum
      GNOME,
      KDE,
      XFCE,
      Cinnamon,
      Enlightenment,
      LXDE,
      Openbox,
      i3,
      Mate,
      Unity,
      Pantheon,
      LXQT,
      Deepin,
      Dwm,
      Budgie,
      Unknown,
      Max
    };

    enum class WindowProtocol : uint8_t {
      All,  // There is an assumption that this is the first enum
      X11,
      XWayland,
      Wayland,
      WaylandDRM,
      // Wildcard for all Wayland variants, excluding XWayland.
      WaylandAll,
      // Wildcard for all X11 variants, including XWayland.
      X11All,
      Max
    };

    enum class BatteryStatus : uint8_t { All, Present, None };

    enum class ScreenSizeStatus : uint8_t {
      All,
      Small,           // <= 1900x1200
      SmallAndMedium,  // <= 3440x1440
      Medium,          // <= 3440x1440 && > 1900x1200
      MediumAndLarge,  // >1900x1200
      Large            // > 3440x1440
    };

    /* Array of devices to match, or an empty array for all devices */
    class GfxDeviceFamily final {
     public:
      GfxDeviceFamily() = default;

      void Append(const nsAString& aDeviceId);
      void AppendRange(int32_t aBeginDeviceId, int32_t aEndDeviceId);

      bool IsEmpty() const { return mIds.IsEmpty() && mRanges.IsEmpty(); }

      nsresult Contains(nsAString& aDeviceId) const;

     private:
      struct DeviceRange {
        int32_t mBegin;
        int32_t mEnd;
      };

      CopyableTArray mIds;
      CopyableTArray mRanges;
    };

    struct GfxDriverInfo {
      // If |ownDevices| is true, you are transferring ownership of the devices
      // array, and it will be deleted when this GfxDriverInfo is destroyed.
      GfxDriverInfo(OperatingSystem os, ScreenSizeStatus aScreen,
                    BatteryStatus aBattery, const nsAString& desktopEnv,
                    const nsAString& windowProtocol, const nsAString& vendor,
                    const nsAString& driverVendor, GfxDeviceFamily* devices,
                    int32_t feature, int32_t featureStatus, VersionComparisonOp op,
                    uint64_t driverVersion, const char* ruleId,
                    const char* suggestedVersion = nullptr, bool ownDevices = false,
                    bool gpu2 = false);

      GfxDriverInfo();
      GfxDriverInfo(const GfxDriverInfo&);
      ~GfxDriverInfo();

      OperatingSystem mOperatingSystem;
      uint32_t mOperatingSystemVersion;
      ScreenSizeStatus mScreen;
      BatteryStatus mBattery;
      nsString mDesktopEnvironment;
      nsString mWindowProtocol;

      nsString mAdapterVendor;
      nsString mDriverVendor;

      const GfxDeviceFamily* mDevices;

      // Whether the mDevices array should be deleted when this structure is
      // deallocated. False by default.
      bool mDeleteDevices;

      /* A feature from nsIGfxInfo, or all features */
      int32_t mFeature;
      static int32_t allFeatures;

      /* A feature status from nsIGfxInfo */
      int32_t mFeatureStatus;

      VersionComparisonOp mComparisonOp;

      /* versions are assumed to be A.B.C.D packed as 0xAAAABBBBCCCCDDDD */
      uint64_t mDriverVersion;
      uint64_t mDriverVersionMax;
      static uint64_t allDriverVersions;

      const char* mSuggestedVersion;
      nsCString mRuleId;

      static const GfxDeviceFamily* GetDeviceFamily(DeviceFamily id);
      static GfxDeviceFamily*
          sDeviceFamilies[static_cast(DeviceFamily::Max)];

      static const nsAString& GetDesktopEnvironment(DesktopEnvironment id);
      static nsAString*
          sDesktopEnvironment[static_cast(DesktopEnvironment::Max)];

      static const nsAString& GetWindowProtocol(WindowProtocol id);
      static nsAString* sWindowProtocol[static_cast(WindowProtocol::Max)];

      static const nsAString& GetDeviceVendor(DeviceVendor id);
      static const nsAString& GetDeviceVendor(DeviceFamily id);
      static nsAString* sDeviceVendors[static_cast(DeviceVendor::Max)];

      static const nsAString& GetDriverVendor(DriverVendor id);
      static nsAString* sDriverVendors[static_cast(DriverVendor::Max)];

      nsString mModel, mHardware, mProduct, mManufacturer;

      bool mGpu2;
    };

    #define GFX_DRIVER_VERSION(a, b, c, d)                               \
      ((uint64_t(a) << 48) | (uint64_t(b) << 32) | (uint64_t(c) << 16) | \
       uint64_t(d))

    inline 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.
    inline 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);

      // This "4" is hardcoded in a few places, including once as a 3.
      char* dest[4] = {aAStr, aBStr, aCStr, aDStr};
      unsigned destIdx = 0;
      unsigned destPos = 0;

      for (int i = 0; i < len; i++) {
        if (destIdx >= 4) {
          // Invalid format found. Ensure we don't access dest beyond bounds.
          return false;
        }

        if (aSource[i] == '.') {
          MOZ_ASSERT(destIdx < 4 && destPos <= 4);
          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;
        }

        MOZ_ASSERT(destIdx < 4 && destPos < 4);
        dest[destIdx][destPos++] = aSource[i];
      }

      // Take care of the trailing period
      if (destIdx >= 4) {
        return false;
      }

      // Add last terminator.
      MOZ_ASSERT(destIdx < 4 && destPos <= 4);
      dest[destIdx][destPos] = 0;

      if (destIdx != 3) {
        return false;
      }
      return true;
    }

    // This allows us to pad driver version '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.
    inline 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(const nsAString& aVersion,
                                   uint64_t* aNumericVersion) {
      *aNumericVersion = 0;

    #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
      int a, b, c, d;
      char aStr[8], bStr[8], cStr[8], dStr[8];
      /* honestly, why do I even bother */
      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);
      MOZ_ASSERT(*aNumericVersion != GfxDriverInfo::allDriverVersions);
      return true;
    #elif defined(ANDROID)
      // Can't use aVersion.ToInteger() because that's not compiled into our code
      // unless we have XPCOM_GLUE_AVOID_NSPR disabled.
      *aNumericVersion = atoi(NS_LossyConvertUTF16toASCII(aVersion).get());
      MOZ_ASSERT(*aNumericVersion != GfxDriverInfo::allDriverVersions);
      return true;
    #else
      return false;
    #endif
    }

    }  // namespace widget
    }  // namespace mozilla

## Minimal test - lines (119, 518)

path: .spaces[0].spaces[0].metrics.halstead.length
old: 16.0
new: 1147.0
path: .spaces[0].spaces[0].metrics.halstead.difficulty
old: 4.9
new: 30.755905511811022
path: .spaces[0].spaces[0].metrics.halstead.time
old: 15.614503336474373
new: 15982.095059251653
path: .spaces[0].spaces[0].metrics.halstead.purity_ratio
old: 1.9538203080525025
new: 1.90296948218145
path: .spaces[0].spaces[0].metrics.halstead.level
old: 0.2040816326530612
new: 0.032514080901177675
path: .spaces[0].spaces[0].metrics.halstead.estimated_program_length
old: 31.26112492884004
new: 2182.705996062123
path: .spaces[0].spaces[0].metrics.halstead.N2
old: 7.0
new: 504.0
path: .spaces[0].spaces[0].metrics.halstead.bugs
old: 0.01430251895140066
new: 1.452611757340876
path: .spaces[0].spaces[0].metrics.halstead.N1
old: 9.0
new: 643.0
path: .spaces[0].spaces[0].metrics.halstead.n1
old: 7.0
new: 31.0
path: .spaces[0].spaces[0].metrics.halstead.vocabulary
old: 12.0
new: 285.0
path: .spaces[0].spaces[0].metrics.halstead.volume
old: 57.3594000115385
new: 9353.576371082763
path: .spaces[0].spaces[0].metrics.halstead.effort
old: 281.0610600565387
new: 287677.71106652974
path: .spaces[0].spaces[0].metrics.halstead.n2
old: 5.0
new: 254.0
path: .spaces[0].spaces[0].metrics.mi.mi_original
old: 127.25548032168658
new: 17.42200128345749
path: .spaces[0].spaces[0].metrics.mi.mi_sei
old: 107.991818253432
new: -18.57067482172422
path: .spaces[0].spaces[0].metrics.mi.mi_visual_studio
old: 74.41840954484594
new: 10.188304844127186
path: .spaces[0].spaces[0].metrics.loc.lloc
old: 2.0
new: 58.0
path: .spaces[0].spaces[0].metrics.loc.sloc
old: 4.0
new: 400.0
path: .spaces[0].spaces[0].metrics.loc.blank
old: 0.0
new: 36.0
path: .spaces[0].spaces[0].metrics.loc.ploc
old: 4.0
new: 305.0
path: .spaces[0].spaces[0].metrics.loc.cloc
old: 0.0
new: 59.0
path: .spaces[0].spaces[0].metrics.cognitive.average
old: 0.0
new: 5.833333333333333
path: .spaces[0].spaces[0].metrics.cognitive.sum
old: 0.0
new: 35.0
path: .spaces[0].spaces[0].metrics.nargs.sum
old: 1.0
new: 12.0
path: .spaces[0].spaces[0].metrics.nargs.average
old: 1.0
new: 2.0
path: .spaces[0].spaces[0].metrics.cyclomatic.sum
old: 1.0
new: 39.0
path: .spaces[0].spaces[0].metrics.cyclomatic.average
old: 1.0
new: 3.9
path: .spaces[0].spaces[0].metrics.nom.total
old: 1.0
new: 6.0
path: .spaces[0].spaces[0].metrics.nom.functions
old: 1.0
new: 6.0
path: .spaces[0].spaces[0].metrics.nexits.average
old: 1.0
new: 2.3333333333333335
path: .spaces[0].spaces[0].metrics.nexits.sum
old: 1.0
new: 14.0

### Code

    namespace widget {

    enum class OperatingSystem : uint8_t {
      Unknown,
      Windows,
      WindowsXP,
      WindowsServer2003,
      WindowsVista,
      Windows7,
      Windows8,
      Windows8_1,
      Windows10,
      RecentWindows10,
      NotRecentWindows10,
      Linux,
      OSX,
      OSX10_5,
      OSX10_6,
      OSX10_7,
      OSX10_8,
      OSX10_9,
      OSX10_10,
      OSX10_11,
      OSX10_12,
      OSX10_13,
      OSX10_14,
      OSX10_15,
      OSX11_0,
      Android,
      Ios
    };

    enum VersionComparisonOp {
      DRIVER_LESS_THAN,                    // driver <  version
      DRIVER_BUILD_ID_LESS_THAN,           // driver build id <  version
      DRIVER_LESS_THAN_OR_EQUAL,           // driver <= version
      DRIVER_BUILD_ID_LESS_THAN_OR_EQUAL,  // driver build id <= version
      DRIVER_GREATER_THAN,                 // driver >  version
      DRIVER_GREATER_THAN_OR_EQUAL,        // driver >= version
      DRIVER_EQUAL,                        // driver == version
      DRIVER_NOT_EQUAL,                    // driver != version
      DRIVER_BETWEEN_EXCLUSIVE,        // driver > version && driver < versionMax
      DRIVER_BETWEEN_INCLUSIVE,        // driver >= version && driver <= versionMax
      DRIVER_BETWEEN_INCLUSIVE_START,  // driver >= version && driver < versionMax
      DRIVER_COMPARISON_IGNORED
    };

    enum class DeviceFamily : uint8_t {
      All,
      IntelAll,
      NvidiaAll,
      AtiAll,
      MicrosoftAll,
      ParallelsAll,
      QualcommAll,
      AppleAll,
      AmazonAll,
      IntelGMA500,
      IntelGMA900,
      IntelGMA950,
      IntelGMA3150,
      IntelGMAX3000,
      IntelGMAX4500HD,
      IntelHDGraphicsToIvyBridge,
      IntelHDGraphicsToSandyBridge,
      IntelHaswell,
      IntelSandyBridge,
      IntelHD520,
      IntelMobileHDGraphics,
      NvidiaBlockD3D9Layers,
      RadeonX1000,
      RadeonCaicos,
      Geforce7300GT,
      Nvidia310M,
      Nvidia8800GTS,
      Bug1137716,
      Bug1116812,
      Bug1155608,
      Bug1207665,
      Bug1447141,
      AmdR600,
      NvidiaBlockWebRender,
      NvidiaRolloutWebRender,
      IntelRolloutWebRender,
      IntelModernRolloutWebRender,
      AtiRolloutWebRender,

      Max
    };

    enum class DeviceVendor : uint8_t {
      All,  // There is an assumption that this is the first enum
      Intel,
      NVIDIA,
      ATI,
      Microsoft,
      Parallels,
      VMWare,
      VirtualBox,
      Qualcomm,
      MicrosoftBasic,
      MicrosoftHyperV,
      Apple,
      Amazon,

      Max
    };

    enum DriverVendor : uint8_t {
      All,  // There is an assumption that this is the first enum
      // Wildcard for all Mesa drivers.
      MesaAll,
      // Note that the following list of Mesa drivers is not comprehensive; we pull
      // the DRI driver at runtime. These drivers are provided for convenience when
      // populating the local blocklist.
      MesaLLVMPipe,
      MesaSoftPipe,
      MesaSWRast,
      // AMD
      MesaR600,
      // Nouveau: Open-source nvidia
      MesaNouveau,
      // A generic ID to be provided when we can't determine the DRI driver on Mesa.
      MesaUnknown,
      // Wildcard for all non-Mesa drivers.
      NonMesaAll,
      // Wildcard for all hardware Mesa drivers.
      HardwareMesaAll,
      // Wildcard for all software Mesa drivers.
      SoftwareMesaAll,

      Max
    };

    enum class DesktopEnvironment : uint8_t {
      All,  // There is an assumption that this is the first enum
      GNOME,
      KDE,
      XFCE,
      Cinnamon,
      Enlightenment,
      LXDE,
      Openbox,
      i3,
      Mate,
      Unity,
      Pantheon,
      LXQT,
      Deepin,
      Dwm,
      Budgie,
      Unknown,
      Max
    };

    enum class WindowProtocol : uint8_t {
      All,  // There is an assumption that this is the first enum
      X11,
      XWayland,
      Wayland,
      WaylandDRM,
      // Wildcard for all Wayland variants, excluding XWayland.
      WaylandAll,
      // Wildcard for all X11 variants, including XWayland.
      X11All,
      Max
    };

    enum class BatteryStatus : uint8_t { All, Present, None };

    enum class ScreenSizeStatus : uint8_t {
      All,
      Small,           // <= 1900x1200
      SmallAndMedium,  // <= 3440x1440
      Medium,          // <= 3440x1440 && > 1900x1200
      MediumAndLarge,  // >1900x1200
      Large            // > 3440x1440
    };

    /* Array of devices to match, or an empty array for all devices */
    class GfxDeviceFamily final {
     public:
      GfxDeviceFamily() = default;

      void Append(const nsAString& aDeviceId);
      void AppendRange(int32_t aBeginDeviceId, int32_t aEndDeviceId);

      bool IsEmpty() const { return mIds.IsEmpty() && mRanges.IsEmpty(); }

      nsresult Contains(nsAString& aDeviceId) const;

     private:
      struct DeviceRange {
        int32_t mBegin;
        int32_t mEnd;
      };

      CopyableTArray mIds;
      CopyableTArray mRanges;
    };

    struct GfxDriverInfo {
      // If |ownDevices| is true, you are transferring ownership of the devices
      // array, and it will be deleted when this GfxDriverInfo is destroyed.
      GfxDriverInfo(OperatingSystem os, ScreenSizeStatus aScreen,
                    BatteryStatus aBattery, const nsAString& desktopEnv,
                    const nsAString& windowProtocol, const nsAString& vendor,
                    const nsAString& driverVendor, GfxDeviceFamily* devices,
                    int32_t feature, int32_t featureStatus, VersionComparisonOp op,
                    uint64_t driverVersion, const char* ruleId,
                    const char* suggestedVersion = nullptr, bool ownDevices = false,
                    bool gpu2 = false);

      GfxDriverInfo();
      GfxDriverInfo(const GfxDriverInfo&);
      ~GfxDriverInfo();

      OperatingSystem mOperatingSystem;
      uint32_t mOperatingSystemVersion;
      ScreenSizeStatus mScreen;
      BatteryStatus mBattery;
      nsString mDesktopEnvironment;
      nsString mWindowProtocol;

      nsString mAdapterVendor;
      nsString mDriverVendor;

      const GfxDeviceFamily* mDevices;

      // Whether the mDevices array should be deleted when this structure is
      // deallocated. False by default.
      bool mDeleteDevices;

      /* A feature from nsIGfxInfo, or all features */
      int32_t mFeature;
      static int32_t allFeatures;

      /* A feature status from nsIGfxInfo */
      int32_t mFeatureStatus;

      VersionComparisonOp mComparisonOp;

      /* versions are assumed to be A.B.C.D packed as 0xAAAABBBBCCCCDDDD */
      uint64_t mDriverVersion;
      uint64_t mDriverVersionMax;
      static uint64_t allDriverVersions;

      const char* mSuggestedVersion;
      nsCString mRuleId;

      static const GfxDeviceFamily* GetDeviceFamily(DeviceFamily id);
      static GfxDeviceFamily*
          sDeviceFamilies[static_cast(DeviceFamily::Max)];

      static const nsAString& GetDesktopEnvironment(DesktopEnvironment id);
      static nsAString*
          sDesktopEnvironment[static_cast(DesktopEnvironment::Max)];

      static const nsAString& GetWindowProtocol(WindowProtocol id);
      static nsAString* sWindowProtocol[static_cast(WindowProtocol::Max)];

      static const nsAString& GetDeviceVendor(DeviceVendor id);
      static const nsAString& GetDeviceVendor(DeviceFamily id);
      static nsAString* sDeviceVendors[static_cast(DeviceVendor::Max)];

      static const nsAString& GetDriverVendor(DriverVendor id);
      static nsAString* sDriverVendors[static_cast(DriverVendor::Max)];

      nsString mModel, mHardware, mProduct, mManufacturer;

      bool mGpu2;
    };

    #define GFX_DRIVER_VERSION(a, b, c, d)                               \
      ((uint64_t(a) << 48) | (uint64_t(b) << 32) | (uint64_t(c) << 16) | \
       uint64_t(d))

    inline 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.
    inline 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);

      // This "4" is hardcoded in a few places, including once as a 3.
      char* dest[4] = {aAStr, aBStr, aCStr, aDStr};
      unsigned destIdx = 0;
      unsigned destPos = 0;

      for (int i = 0; i < len; i++) {
        if (destIdx >= 4) {
          // Invalid format found. Ensure we don't access dest beyond bounds.
          return false;
        }

        if (aSource[i] == '.') {
          MOZ_ASSERT(destIdx < 4 && destPos <= 4);
          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;
        }

        MOZ_ASSERT(destIdx < 4 && destPos < 4);
        dest[destIdx][destPos++] = aSource[i];
      }

      // Take care of the trailing period
      if (destIdx >= 4) {
        return false;
      }

      // Add last terminator.
      MOZ_ASSERT(destIdx < 4 && destPos <= 4);
      dest[destIdx][destPos] = 0;

      if (destIdx != 3) {
        return false;
      }
      return true;
    }

    // This allows us to pad driver version '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.
    inline 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(const nsAString& aVersion,
                                   uint64_t* aNumericVersion) {
      *aNumericVersion = 0;

    #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
      int a, b, c, d;
      char aStr[8], bStr[8], cStr[8], dStr[8];
      /* honestly, why do I even bother */
      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);
      MOZ_ASSERT(*aNumericVersion != GfxDriverInfo::allDriverVersions);
      return true;
    #elif defined(ANDROID)
      // Can't use aVersion.ToInteger() because that's not compiled into our code
      // unless we have XPCOM_GLUE_AVOID_NSPR disabled.
      *aNumericVersion = atoi(NS_LossyConvertUTF16toASCII(aVersion).get());
      MOZ_ASSERT(*aNumericVersion != GfxDriverInfo::allDriverVersions);
      return true;
    #else
      return false;
    #endif
    }

    }  // namespace widget