# Global Metrics

path: .metrics.nargs.average
old: 0.0
new: 1.3846153846153846
path: .metrics.nargs.sum
old: 0.0
new: 18.0
path: .metrics.cognitive.sum
old: 0.0
new: 15.0
path: .metrics.cognitive.average
old: 0.0
new: 1.1538461538461535
path: .metrics.nom.functions
old: 1.0
new: 12.0
path: .metrics.nom.total
old: 1.0
new: 13.0
path: .metrics.nom.closures
old: 0.0
new: 1.0
path: .metrics.cyclomatic.average
old: 1.0
new: 2.6
path: .metrics.cyclomatic.sum
old: 6.0
new: 39.0
path: .metrics.mi.mi_original
old: 52.98595694031312
new: 24.64473238896632
path: .metrics.mi.mi_sei
old: 30.006555294746203
new: -11.65779193782504
path: .metrics.mi.mi_visual_studio
old: 30.98593973117726
new: 14.41212420407387
path: .metrics.loc.blank
old: 18.0
new: 39.0
path: .metrics.loc.cloc
old: 18.0
new: 29.0
path: .metrics.loc.sloc
old: 116.0
new: 265.0
path: .metrics.loc.ploc
old: 80.0
new: 197.0
path: .metrics.loc.lloc
old: 0.0
new: 85.0
path: .metrics.halstead.time
old: 1541.613729648784
new: 23094.6382402426
path: .metrics.halstead.n1
old: 12.0
new: 31.0
path: .metrics.halstead.n2
old: 56.0
new: 143.0
path: .metrics.halstead.N1
old: 208.0
new: 674.0
path: .metrics.halstead.estimated_program_length
old: 368.2314256438797
new: 1177.441686781303
path: .metrics.halstead.level
old: 0.07349081364829396
new: 0.02023203169213356
path: .metrics.halstead.purity_ratio
old: 1.0991982855041185
new: 1.0419837936117724
path: .metrics.halstead.N2
old: 127.0
new: 456.0
path: .metrics.halstead.bugs
old: 0.3055231537325993
new: 1.856669163600524
path: .metrics.halstead.difficulty
old: 13.607142857142858
new: 49.42657342657343
path: .metrics.halstead.length
old: 335.0
new: 1130.0
path: .metrics.halstead.vocabulary
old: 68.0
new: 174.0
path: .metrics.halstead.volume
old: 2039.3000518188635
new: 8410.526150309062
path: .metrics.halstead.effort
old: 27749.04713367811
new: 415703.4883243668
path: .metrics.nexits.average
old: 0.0
new: 1.0
path: .metrics.nexits.sum
old: 0.0
new: 13.0

# Spaces Data

## Minimal test - lines (25, 37)

path: .spaces[0].spaces[0].metrics.cyclomatic.average
old: 1.0
new: 3.0
path: .spaces[0].spaces[0].metrics.cyclomatic.sum
old: 4.0
new: 3.0
path: .spaces[0].spaces[0].metrics.nargs.average
old: 0.0
new: 1.0
path: .spaces[0].spaces[0].metrics.nargs.sum
old: 0.0
new: 1.0
path: .spaces[0].spaces[0].metrics.mi.mi_sei
old: 9.463929589217742
new: 99.9127859439038
path: .spaces[0].spaces[0].metrics.mi.mi_visual_studio
old: 34.35638809482378
new: 59.48964249589074
path: .spaces[0].spaces[0].metrics.mi.mi_original
old: 58.749423642148656
new: 101.72728866797316
path: .spaces[0].spaces[0].metrics.loc.blank
old: 15.0
new: 1.0
path: .spaces[0].spaces[0].metrics.loc.lloc
old: 0.0
new: 3.0
path: .spaces[0].spaces[0].metrics.loc.ploc
old: 71.0
new: 10.0
path: .spaces[0].spaces[0].metrics.loc.sloc
old: 86.0
new: 13.0
path: .spaces[0].spaces[0].metrics.loc.cloc
old: 0.0
new: 2.0
path: .spaces[0].spaces[0].metrics.cognitive.sum
old: 0.0
new: 1.0
path: .spaces[0].spaces[0].metrics.cognitive.average
old: 0.0
new: 1.0
path: .spaces[0].spaces[0].metrics.halstead.N1
old: 199.0
new: 25.0
path: .spaces[0].spaces[0].metrics.halstead.length
old: 315.0
new: 40.0
path: .spaces[0].spaces[0].metrics.halstead.n2
old: 49.0
new: 13.0
path: .spaces[0].spaces[0].metrics.halstead.bugs
old: 0.29655165201150546
new: 0.034301863062073376
path: .spaces[0].spaces[0].metrics.halstead.N2
old: 116.0
new: 15.0
path: .spaces[0].spaces[0].metrics.halstead.effort
old: 26535.813344638515
new: 1043.8989129362335
path: .spaces[0].spaces[0].metrics.halstead.purity_ratio
old: 1.0099693091120605
new: 2.0331249321176954
path: .spaces[0].spaces[0].metrics.halstead.level
old: 0.07040229885057471
new: 0.17333333333333334
path: .spaces[0].spaces[0].metrics.halstead.time
old: 1474.2118524799175
new: 57.99438405201298
path: .spaces[0].spaces[0].metrics.halstead.volume
old: 1868.1822613323093
new: 180.94247824228052
path: .spaces[0].spaces[0].metrics.halstead.vocabulary
old: 61.0
new: 23.0
path: .spaces[0].spaces[0].metrics.halstead.difficulty
old: 14.20408163265306
new: 5.769230769230769
path: .spaces[0].spaces[0].metrics.halstead.estimated_program_length
old: 318.14033237029906
new: 81.32499728470782
path: .spaces[0].spaces[0].metrics.halstead.n1
old: 12.0
new: 10.0

### Code

    RemoteLookAndFeel::RemoteLookAndFeel(FullLookAndFeel&& aData)
        : mTables(std::move(aData.tables())) {
      MOZ_ASSERT(XRE_IsContentProcess(),
                 "Only content processes should be using a RemoteLookAndFeel");

    #ifdef MOZ_WIDGET_GTK
      if (!StaticPrefs::widget_non_native_theme_enabled()) {
        // Configure the theme in this content process with the Gtk theme that was
        // chosen by WithThemeConfiguredForContent in the parent process.
        nsLookAndFeel::ConfigureTheme(aData.theme());
      }
    #endif
    }

## Minimal test - lines (23, 265)

path: .spaces[0].metrics.nargs.sum
old: 0.0
new: 18.0
path: .spaces[0].metrics.nargs.average
old: 0.0
new: 1.3846153846153846
path: .spaces[0].metrics.cognitive.average
old: 0.0
new: 1.1538461538461535
path: .spaces[0].metrics.cognitive.sum
old: 0.0
new: 15.0
path: .spaces[0].metrics.loc.cloc
old: 1.0
new: 22.0
path: .spaces[0].metrics.loc.ploc
old: 75.0
new: 185.0
path: .spaces[0].metrics.loc.lloc
old: 0.0
new: 85.0
path: .spaces[0].metrics.loc.sloc
old: 92.0
new: 243.0
path: .spaces[0].metrics.loc.blank
old: 16.0
new: 36.0
path: .spaces[0].metrics.cyclomatic.average
old: 1.0
new: 2.7142857142857144
path: .spaces[0].metrics.cyclomatic.sum
old: 5.0
new: 38.0
path: .spaces[0].metrics.nom.total
old: 1.0
new: 13.0
path: .spaces[0].metrics.nom.functions
old: 1.0
new: 12.0
path: .spaces[0].metrics.nom.closures
old: 0.0
new: 1.0
path: .spaces[0].metrics.halstead.N2
old: 123.0
new: 447.0
path: .spaces[0].metrics.halstead.estimated_program_length
old: 346.5993341005034
new: 1100.4360371433345
path: .spaces[0].metrics.halstead.n1
old: 12.0
new: 31.0
path: .spaces[0].metrics.halstead.volume
old: 1993.4037461124185
new: 8257.647202169559
path: .spaces[0].metrics.halstead.bugs
old: 0.3055830445389962
new: 1.8900468815180436
path: .spaces[0].metrics.halstead.purity_ratio
old: 1.0471278975846026
new: 0.9816556977192992
path: .spaces[0].metrics.halstead.length
old: 331.0
new: 1121.0
path: .spaces[0].metrics.halstead.level
old: 0.07181571815718157
new: 0.019340405571191453
path: .spaces[0].metrics.halstead.N1
old: 208.0
new: 674.0
path: .spaces[0].metrics.halstead.n2
old: 53.0
new: 134.0
path: .spaces[0].metrics.halstead.difficulty
old: 13.924528301886792
new: 51.70522388059702
path: .spaces[0].metrics.halstead.time
old: 1542.0670488794178
new: 23720.194295286812
path: .spaces[0].metrics.halstead.effort
old: 27757.20687982952
new: 426963.4973151626
path: .spaces[0].metrics.halstead.vocabulary
old: 65.0
new: 165.0
path: .spaces[0].metrics.mi.mi_original
old: 57.08951086650093
new: 26.374150703228736
path: .spaces[0].metrics.mi.mi_sei
old: 15.21166395622851
new: -11.309889708285429
path: .spaces[0].metrics.mi.mi_visual_studio
old: 33.38567886929879
new: 15.423479943408616
path: .spaces[0].metrics.nexits.average
old: 0.0
new: 1.0
path: .spaces[0].metrics.nexits.sum
old: 0.0
new: 13.0

### Code

    namespace mozilla::widget {

    RemoteLookAndFeel::RemoteLookAndFeel(FullLookAndFeel&& aData)
        : mTables(std::move(aData.tables())) {
      MOZ_ASSERT(XRE_IsContentProcess(),
                 "Only content processes should be using a RemoteLookAndFeel");

    #ifdef MOZ_WIDGET_GTK
      if (!StaticPrefs::widget_non_native_theme_enabled()) {
        // Configure the theme in this content process with the Gtk theme that was
        // chosen by WithThemeConfiguredForContent in the parent process.
        nsLookAndFeel::ConfigureTheme(aData.theme());
      }
    #endif
    }

    RemoteLookAndFeel::~RemoteLookAndFeel() = default;

    void RemoteLookAndFeel::SetDataImpl(FullLookAndFeel&& aData) {
      MOZ_ASSERT(XRE_IsContentProcess(),
                 "Only content processes should be using a RemoteLookAndFeel");
      MOZ_ASSERT(NS_IsMainThread());
      mTables = std::move(aData.tables());

    #ifdef MOZ_WIDGET_GTK
      if (!StaticPrefs::widget_non_native_theme_enabled()) {
        // Configure the theme in this content process with the Gtk theme that was
        // chosen by WithThemeConfiguredForContent in the parent process.
        nsLookAndFeel::ConfigureTheme(aData.theme());
      }
    #endif
    }

    namespace {

    template
    Result MapLookup(const nsTArray& aItems,
                                            const nsTArray& aMap, ID aID,
                                            ID aMinimum = ID(0)) {
      UInt mapped = aMap[static_cast(aID) - static_cast(aMinimum)];

      if (mapped == std::numeric_limits::max()) {
        return Err(NS_ERROR_NOT_IMPLEMENTED);
      }

      return &aItems[static_cast(mapped)];
    }

    template
    void AddToMap(nsTArray* aItems, nsTArray* aMap,
                  Maybe&& aNewItem) {
      if (aNewItem.isNothing()) {
        aMap->AppendElement(std::numeric_limits::max());
        return;
      }

      size_t newIndex = aItems->Length();
      MOZ_ASSERT(newIndex < std::numeric_limits::max());

      // Check if there is an existing value in aItems that we can point to.
      //
      // The arrays should be small enough and contain few enough unique
      // values that sequential search here is reasonable.
      for (size_t i = 0; i < newIndex; ++i) {
        if ((*aItems)[i] == aNewItem.ref()) {
          aMap->AppendElement(static_cast(i));
          return;
        }
      }

      aItems->AppendElement(aNewItem.extract());
      aMap->AppendElement(static_cast(newIndex));
    }

    }  // namespace

    nsresult RemoteLookAndFeel::NativeGetColor(ColorID aID, nscolor& aResult) {
      const nscolor* result;
      MOZ_TRY_VAR(result, MapLookup(mTables.colors(), mTables.colorMap(), aID));
      aResult = *result;
      return NS_OK;
    }

    nsresult RemoteLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
      const int32_t* result;
      MOZ_TRY_VAR(result, MapLookup(mTables.ints(), mTables.intMap(), aID));
      aResult = *result;
      return NS_OK;
    }

    nsresult RemoteLookAndFeel::NativeGetFloat(FloatID aID, float& aResult) {
      const float* result;
      MOZ_TRY_VAR(result, MapLookup(mTables.floats(), mTables.floatMap(), aID));
      aResult = *result;
      return NS_OK;
    }

    bool RemoteLookAndFeel::NativeGetFont(FontID aID, nsString& aFontName,
                                          gfxFontStyle& aFontStyle) {
      auto result =
          MapLookup(mTables.fonts(), mTables.fontMap(), aID, FontID::MINIMUM);
      if (result.isErr()) {
        return false;
      }

      const LookAndFeelFont& font = *result.unwrap();
      MOZ_ASSERT(font.haveFont());
      aFontName = font.name();
      aFontStyle = gfxFontStyle();
      aFontStyle.size = font.size();
      aFontStyle.weight = FontWeight(font.weight());
      aFontStyle.style =
          font.italic() ? FontSlantStyle::Italic() : FontSlantStyle::Normal();

      return true;
    }

    char16_t RemoteLookAndFeel::GetPasswordCharacterImpl() {
      return static_cast(mTables.passwordChar());
    }

    bool RemoteLookAndFeel::GetEchoPasswordImpl() { return mTables.passwordEcho(); }

    // static
    const FullLookAndFeel* RemoteLookAndFeel::ExtractData() {
      MOZ_ASSERT(XRE_IsParentProcess(),
                 "Only parent processes should be extracting LookAndFeel data");

      if (sCachedLookAndFeelData) {
        return sCachedLookAndFeelData;
      }

      static bool sInitialized = false;
      if (!sInitialized) {
        sInitialized = true;
        ClearOnShutdown(&sCachedLookAndFeelData);
      }

      FullLookAndFeel* lf = new FullLookAndFeel{};
      nsXPLookAndFeel* impl = nsXPLookAndFeel::GetInstance();

      int32_t darkTheme = 0;
      int32_t accessibilityTheme = 0;
      impl->NativeGetInt(IntID::SystemUsesDarkTheme, darkTheme);
      impl->NativeGetInt(IntID::UseAccessibilityTheme, accessibilityTheme);

      impl->WithThemeConfiguredForContent([&](const LookAndFeelTheme& aTheme) {
        for (auto id : MakeEnumeratedRange(IntID::End)) {
          int32_t theInt;
          nsresult rv;
          // We want to take SystemUsesDarkTheme and UseAccessibilityTheme from
          // the parent process theme rather than the content configured theme.
          // This ensures that media queries like (prefers-color-scheme: dark) will
          // match correctly in content processes.
          //
          // (When the RemoteLookAndFeel is not in use, the LookAndFeelCache
          // ensures we get these values from the parent process theme.)
          switch (id) {
            case IntID::SystemUsesDarkTheme:
              theInt = darkTheme;
              rv = NS_OK;
              break;
            case IntID::UseAccessibilityTheme:
              theInt = accessibilityTheme;
              rv = NS_OK;
              break;
            default:
              rv = impl->NativeGetInt(id, theInt);
              break;
          }
          AddToMap(&lf->tables().ints(), &lf->tables().intMap(),
                   NS_SUCCEEDED(rv) ? Some(theInt) : Nothing{});
        }

        for (auto id : MakeEnumeratedRange(FloatID::End)) {
          float theFloat;
          nsresult rv = impl->NativeGetFloat(id, theFloat);
          AddToMap(&lf->tables().floats(), &lf->tables().floatMap(),
                   NS_SUCCEEDED(rv) ? Some(theFloat) : Nothing{});
        }

        for (auto id : MakeEnumeratedRange(ColorID::End)) {
          nscolor theColor;
          nsresult rv = impl->NativeGetColor(id, theColor);
          AddToMap(&lf->tables().colors(), &lf->tables().colorMap(),
                   NS_SUCCEEDED(rv) ? Some(theColor) : Nothing{});
        }

        for (auto id :
             MakeInclusiveEnumeratedRange(FontID::MINIMUM, FontID::MAXIMUM)) {
          LookAndFeelFont font{};
          gfxFontStyle fontStyle{};

          bool rv = impl->NativeGetFont(id, font.name(), fontStyle);
          Maybe maybeFont;
          if (rv) {
            font.haveFont() = true;
            font.size() = fontStyle.size;
            font.weight() = fontStyle.weight.ToFloat();
            font.italic() = fontStyle.style.IsItalic();
            MOZ_ASSERT(fontStyle.style.IsNormal() || fontStyle.style.IsItalic(),
                       "Cannot handle oblique font style");
    #ifdef DEBUG
            {
              // Assert that all the remaining font style properties have their
              // default values.
              gfxFontStyle candidate = fontStyle;
              gfxFontStyle defaults{};
              candidate.size = defaults.size;
              candidate.weight = defaults.weight;
              candidate.style = defaults.style;
              MOZ_ASSERT(candidate.Equals(defaults),
                         "Some font style properties not supported");
            }
    #endif
            maybeFont = Some(std::move(font));
          }
          AddToMap(&lf->tables().fonts(), &lf->tables().fontMap(),
                   std::move(maybeFont));
        }

        lf->tables().passwordChar() = impl->GetPasswordCharacterImpl();
        lf->tables().passwordEcho() = impl->GetEchoPasswordImpl();
    #ifdef MOZ_WIDGET_GTK
        lf->theme() = aTheme;
    #endif
      });

      // This assignment to sCachedLookAndFeelData must be done after the
      // WithThemeConfiguredForContent call, since it can end up calling RefreshImpl
      // on the LookAndFeel, which will clear out sCachedTables.
      sCachedLookAndFeelData = lf;
      return sCachedLookAndFeelData;
    }

    void RemoteLookAndFeel::ClearCachedData() {
      MOZ_ASSERT(XRE_IsParentProcess());
      sCachedLookAndFeelData = nullptr;
    }

    StaticAutoPtr RemoteLookAndFeel::sCachedLookAndFeelData;

    }  // namespace mozilla::widget