# Global Metrics

path: .metrics.cognitive.average
old: null
new: 3.909090909090909
path: .metrics.cognitive.sum
old: 0.0
new: 43.0
path: .metrics.loc.blank
old: 5.0
new: 33.0
path: .metrics.loc.ploc
old: 24.0
new: 278.0
path: .metrics.loc.sloc
old: 37.0
new: 354.0
path: .metrics.loc.lloc
old: 0.0
new: 98.0
path: .metrics.loc.cloc
old: 8.0
new: 43.0
path: .metrics.cyclomatic.average
old: 1.0
new: 4.375
path: .metrics.cyclomatic.sum
old: 2.0
new: 70.0
path: .metrics.halstead.volume
old: 330.3427076686749
new: 12101.92343184597
path: .metrics.halstead.difficulty
old: 4.173913043478261
new: 66.53954802259886
path: .metrics.halstead.vocabulary
old: 29.0
new: 212.0
path: .metrics.halstead.length
old: 68.0
new: 1566.0
path: .metrics.halstead.time
old: 76.6012075753449
new: 44736.47307550718
path: .metrics.halstead.n2
old: 23.0
new: 177.0
path: .metrics.halstead.purity_ratio
old: 1.7581132352005624
new: 0.9586788556562992
path: .metrics.halstead.bugs
old: 0.04129373433627555
new: 2.885148979180852
path: .metrics.halstead.N2
old: 32.0
new: 673.0
path: .metrics.halstead.level
old: 0.23958333333333337
new: 0.015028656336234346
path: .metrics.halstead.N1
old: 36.0
new: 893.0
path: .metrics.halstead.estimated_program_length
old: 119.55169999363824
new: 1501.2910879577644
path: .metrics.halstead.effort
old: 1378.8217363562082
new: 805256.5153591293
path: .metrics.halstead.n1
old: 6.0
new: 35.0
path: .metrics.nexits.average
old: null
new: 2.0
path: .metrics.nexits.sum
old: 0.0
new: 22.0
path: .metrics.nargs.average
old: null
new: 2.1818181818181817
path: .metrics.nargs.sum
old: 0.0
new: 24.0
path: .metrics.mi.mi_sei
old: 75.61696722259691
new: -27.098705364640544
path: .metrics.mi.mi_visual_studio
old: 47.88447401875708
new: 6.392729631505006
path: .metrics.mi.mi_original
old: 81.88245057207462
new: 10.93156766987356
path: .metrics.nom.functions
old: 0.0
new: 10.0
path: .metrics.nom.closures
old: 0.0
new: 1.0
path: .metrics.nom.total
old: 0.0
new: 11.0

# Spaces Data

## Minimal test - lines (16, 354)

path: .spaces[0].metrics.mi.mi_original
old: null
new: 11.92708504330217
path: .spaces[0].metrics.mi.mi_visual_studio
old: null
new: 6.974903534094836
path: .spaces[0].metrics.mi.mi_sei
old: null
new: -26.98043914866469
path: .spaces[0].metrics.cyclomatic.sum
old: 1.0
new: 69.0
path: .spaces[0].metrics.cyclomatic.average
old: 1.0
new: 4.6
path: .spaces[0].metrics.halstead.purity_ratio
old: null
new: 0.9180189539953548
path: .spaces[0].metrics.halstead.estimated_program_length
old: null
new: 1430.273530324763
path: .spaces[0].metrics.halstead.difficulty
old: 0.0
new: 68.86094674556213
path: .spaces[0].metrics.halstead.n2
old: 1.0
new: 169.0
path: .spaces[0].metrics.halstead.effort
old: 0.0
new: 823138.8767514032
path: .spaces[0].metrics.halstead.volume
old: 0.0
new: 11953.63868279159
path: .spaces[0].metrics.halstead.length
old: 1.0
new: 1558.0
path: .spaces[0].metrics.halstead.level
old: null
new: 0.014522019334049409
path: .spaces[0].metrics.halstead.N2
old: 1.0
new: 665.0
path: .spaces[0].metrics.halstead.N1
old: 0.0
new: 893.0
path: .spaces[0].metrics.halstead.bugs
old: 0.0
new: 2.9277061691230233
path: .spaces[0].metrics.halstead.vocabulary
old: 1.0
new: 204.0
path: .spaces[0].metrics.halstead.n1
old: 0.0
new: 35.0
path: .spaces[0].metrics.halstead.time
old: 0.0
new: 45729.93759730018
path: .spaces[0].metrics.nexits.average
old: null
new: 2.0
path: .spaces[0].metrics.nexits.sum
old: 0.0
new: 22.0
path: .spaces[0].metrics.nargs.sum
old: 0.0
new: 24.0
path: .spaces[0].metrics.nargs.average
old: null
new: 2.1818181818181817
path: .spaces[0].metrics.cognitive.sum
old: 0.0
new: 43.0
path: .spaces[0].metrics.cognitive.average
old: null
new: 3.909090909090909
path: .spaces[0].metrics.loc.blank
old: 0.0
new: 32.0
path: .spaces[0].metrics.loc.lloc
old: 0.0
new: 98.0
path: .spaces[0].metrics.loc.sloc
old: 1.0
new: 339.0
path: .spaces[0].metrics.loc.cloc
old: 0.0
new: 37.0
path: .spaces[0].metrics.loc.ploc
old: 1.0
new: 270.0
path: .spaces[0].metrics.nom.closures
old: 0.0
new: 1.0
path: .spaces[0].metrics.nom.functions
old: 0.0
new: 10.0
path: .spaces[0].metrics.nom.total
old: 0.0
new: 11.0

### Code

    namespace mozilla {

    using namespace gfx;

    namespace widget {

    static nsIFrame* GetParentScrollbarFrame(nsIFrame* aFrame) {
      // Walk our parents to find a scrollbar frame
      nsIFrame* scrollbarFrame = aFrame;
      do {
        if (scrollbarFrame->IsScrollbarFrame()) {
          break;
        }
      } while ((scrollbarFrame = scrollbarFrame->GetParent()));

      // We return null if we can't find a parent scrollbar frame
      return scrollbarFrame;
    }

    static bool IsParentScrollbarRolledOver(nsIFrame* aFrame) {
      nsIFrame* scrollbarFrame = GetParentScrollbarFrame(aFrame);
      return nsLookAndFeel::GetInt(LookAndFeel::IntID::UseOverlayScrollbars) != 0
                 ? nsNativeTheme::CheckBooleanAttr(scrollbarFrame, nsGkAtoms::hover)
                 : nsNativeTheme::GetContentState(scrollbarFrame,
                                                  StyleAppearance::None)
                       .HasState(NS_EVENT_STATE_HOVER);
    }

    CSSIntCoord ScrollbarDrawingMac::GetScrollbarSize(StyleScrollbarWidth aWidth,
                                                      bool aOverlay) {
      bool isSmall = aWidth == StyleScrollbarWidth::Thin;
      if (aOverlay) {
        return isSmall ? 14 : 16;
      }
      return isSmall ? 11 : 15;
    }

    LayoutDeviceIntCoord ScrollbarDrawingMac::GetScrollbarSize(
        StyleScrollbarWidth aWidth, bool aOverlay, float aDpiRatio) {
      CSSIntCoord size = GetScrollbarSize(aWidth, aOverlay);
      if (aDpiRatio >= 2.0f) {
        return int32_t(size) * 2;
      }
      return int32_t(size);
    }

    LayoutDeviceIntSize ScrollbarDrawingMac::GetMinimumWidgetSize(
        StyleAppearance aAppearance, nsIFrame* aFrame, float aDpiRatio) {
      auto minSize = [&] {
        switch (aAppearance) {
          case StyleAppearance::ScrollbarthumbHorizontal:
            return IntSize{26, 0};
          case StyleAppearance::ScrollbarthumbVertical:
            return IntSize{0, 26};
          case StyleAppearance::ScrollbarVertical:
          case StyleAppearance::ScrollbarHorizontal:
          case StyleAppearance::ScrollbartrackVertical:
          case StyleAppearance::ScrollbartrackHorizontal: {
            ComputedStyle* style = nsLayoutUtils::StyleForScrollbar(aFrame);
            auto scrollbarWidth = style->StyleUIReset()->mScrollbarWidth;
            auto size = GetScrollbarSize(
                scrollbarWidth,
                LookAndFeel::GetInt(LookAndFeel::IntID::UseOverlayScrollbars));
            return IntSize{size, size};
          }
          case StyleAppearance::MozMenulistArrowButton: {
            auto size =
                GetScrollbarSize(StyleScrollbarWidth::Auto, /* aOverlay = */ false);
            return IntSize{size, size};
          }
          case StyleAppearance::ScrollbarbuttonUp:
          case StyleAppearance::ScrollbarbuttonDown:
            return IntSize{15, 16};
          case StyleAppearance::ScrollbarbuttonLeft:
          case StyleAppearance::ScrollbarbuttonRight:
            return IntSize{16, 15};
          default:
            return IntSize{};
        }
      }();

      if (aDpiRatio >= 2.0f) {
        return LayoutDeviceIntSize{minSize.width * 2, minSize.height * 2};
      }
      return LayoutDeviceIntSize{minSize.width, minSize.height};
    }

    ScrollbarParams ScrollbarDrawingMac::ComputeScrollbarParams(
        nsIFrame* aFrame, const ComputedStyle& aStyle, bool aIsHorizontal) {
      ScrollbarParams params;
      params.overlay =
          nsLookAndFeel::GetInt(LookAndFeel::IntID::UseOverlayScrollbars) != 0;
      params.rolledOver = IsParentScrollbarRolledOver(aFrame);
      params.small =
          aStyle.StyleUIReset()->mScrollbarWidth == StyleScrollbarWidth::Thin;
      params.rtl = nsNativeTheme::IsFrameRTL(aFrame);
      params.horizontal = aIsHorizontal;
      params.onDarkBackground = nsNativeTheme::IsDarkBackground(aFrame);
      // Don't use custom scrollbars for overlay scrollbars since they are
      // generally good enough for use cases of custom scrollbars.
      if (!params.overlay) {
        const nsStyleUI* ui = aStyle.StyleUI();
        if (ui->HasCustomScrollbars()) {
          const auto& colors = ui->mScrollbarColor.AsColors();
          params.custom = true;
          params.trackColor = colors.track.CalcColor(aStyle);
          params.faceColor = colors.thumb.CalcColor(aStyle);
        }
      }

      return params;
    }

    auto ScrollbarDrawingMac::GetThumbRect(const Rect& aRect,
                                           const ScrollbarParams& aParams,
                                           float aScale) -> ThumbRect {
      // This matches the sizing checks in GetMinimumWidgetSize etc.
      aScale = aScale >= 2.0f ? 2.0f : 1.0f;

      // Compute the thumb thickness. This varies based on aParams.small,
      // aParams.overlay and aParams.rolledOver. non-overlay: 6 / 8, overlay
      // non-hovered: 5 / 7, overlay hovered: 9 / 11
      float thickness = aParams.small ? 6.0f : 8.0f;
      if (aParams.overlay) {
        thickness -= 1.0f;
        if (aParams.rolledOver) {
          thickness += 4.0f;
        }
      }
      thickness *= aScale;

      // Compute the thumb rect.
      const float outerSpacing =
          ((aParams.overlay || aParams.small) ? 1.0f : 2.0f) * aScale;
      Rect thumbRect = aRect;
      thumbRect.Deflate(1.0f * aScale);
      if (aParams.horizontal) {
        float bottomEdge = thumbRect.YMost() - outerSpacing;
        thumbRect.SetBoxY(bottomEdge - thickness, bottomEdge);
      } else {
        if (aParams.rtl) {
          float leftEdge = thumbRect.X() + outerSpacing;
          thumbRect.SetBoxX(leftEdge, leftEdge + thickness);
        } else {
          float rightEdge = thumbRect.XMost() - outerSpacing;
          thumbRect.SetBoxX(rightEdge - thickness, rightEdge);
        }
      }

      // Compute the thumb fill color.
      nscolor faceColor;
      if (aParams.custom) {
        faceColor = aParams.faceColor;
      } else {
        if (aParams.overlay) {
          faceColor = aParams.onDarkBackground ? NS_RGBA(255, 255, 255, 128)
                                               : NS_RGBA(0, 0, 0, 128);
        } else {
          faceColor = aParams.rolledOver ? NS_RGBA(125, 125, 125, 255)
                                         : NS_RGBA(194, 194, 194, 255);
        }
      }

      nscolor strokeColor = 0;
      float strokeOutset = 0.0f;
      float strokeWidth = 0.0f;

      // Overlay scrollbars have an additional stroke around the fill.
      if (aParams.overlay) {
        strokeOutset = (aParams.onDarkBackground ? 0.3f : 0.5f) * aScale;
        strokeWidth = (aParams.onDarkBackground ? 0.6f : 0.8f) * aScale;

        strokeColor = aParams.onDarkBackground ? NS_RGBA(0, 0, 0, 48)
                                               : NS_RGBA(255, 255, 255, 48);
      }

      return {thumbRect, faceColor, strokeColor, strokeWidth, strokeOutset};
    }

    struct ScrollbarTrackDecorationColors {
      nscolor mInnerColor = 0;
      nscolor mShadowColor = 0;
      nscolor mOuterColor = 0;
    };

    static ScrollbarTrackDecorationColors ComputeScrollbarTrackDecorationColors(
        nscolor aTrackColor) {
      ScrollbarTrackDecorationColors result;
      float luminance = RelativeLuminanceUtils::Compute(aTrackColor);
      if (luminance >= 0.5f) {
        result.mInnerColor =
            RelativeLuminanceUtils::Adjust(aTrackColor, luminance * 0.836f);
        result.mShadowColor =
            RelativeLuminanceUtils::Adjust(aTrackColor, luminance * 0.982f);
        result.mOuterColor =
            RelativeLuminanceUtils::Adjust(aTrackColor, luminance * 0.886f);
      } else {
        result.mInnerColor =
            RelativeLuminanceUtils::Adjust(aTrackColor, luminance * 1.196f);
        result.mShadowColor =
            RelativeLuminanceUtils::Adjust(aTrackColor, luminance * 1.018f);
        result.mOuterColor =
            RelativeLuminanceUtils::Adjust(aTrackColor, luminance * 1.129f);
      }
      return result;
    }

    bool ScrollbarDrawingMac::GetScrollbarTrackRects(const Rect& aRect,
                                                     const ScrollbarParams& aParams,
                                                     float aScale,
                                                     ScrollbarTrackRects& aRects) {
      if (aParams.overlay && !aParams.rolledOver) {
        // Non-hovered overlay scrollbars don't have a track. Draw nothing.
        return false;
      }

      // This matches the sizing checks in GetMinimumWidgetSize etc.
      aScale = aScale >= 2.0f ? 2.0f : 1.0f;

      nscolor trackColor;
      if (aParams.custom) {
        trackColor = aParams.trackColor;
      } else {
        if (aParams.overlay) {
          trackColor = aParams.onDarkBackground ? NS_RGBA(201, 201, 201, 38)
                                                : NS_RGBA(250, 250, 250, 191);
        } else {
          trackColor = NS_RGBA(250, 250, 250, 255);
        }
      }

      float thickness = aParams.horizontal ? aRect.height : aRect.width;

      // The scrollbar track is drawn as multiple non-overlapping segments, which
      // make up lines of different widths and with slightly different shading.
      ScrollbarTrackDecorationColors colors =
          ComputeScrollbarTrackDecorationColors(trackColor);
      struct {
        nscolor color;
        float thickness;
      } segments[] = {
          {colors.mInnerColor, 1.0f * aScale},
          {colors.mShadowColor, 1.0f * aScale},
          {trackColor, thickness - 3.0f * aScale},
          {colors.mOuterColor, 1.0f * aScale},
      };

      // Iterate over the segments "from inside to outside" and fill each segment.
      // For horizontal scrollbars, iterate top to bottom.
      // For vertical scrollbars, iterate left to right or right to left based on
      // aParams.rtl.
      auto current = aRects.begin();
      float accumulatedThickness = 0.0f;
      for (const auto& segment : segments) {
        Rect segmentRect = aRect;
        float startThickness = accumulatedThickness;
        float endThickness = startThickness + segment.thickness;
        if (aParams.horizontal) {
          segmentRect.SetBoxY(aRect.Y() + startThickness, aRect.Y() + endThickness);
        } else {
          if (aParams.rtl) {
            segmentRect.SetBoxX(aRect.XMost() - endThickness,
                                aRect.XMost() - startThickness);
          } else {
            segmentRect.SetBoxX(aRect.X() + startThickness,
                                aRect.X() + endThickness);
          }
        }
        accumulatedThickness = endThickness;
        *current++ = {segmentRect, segment.color};
      }

      return true;
    }

    bool ScrollbarDrawingMac::GetScrollCornerRects(const Rect& aRect,
                                                   const ScrollbarParams& aParams,
                                                   float aScale,
                                                   ScrollCornerRects& aRects) {
      if (aParams.overlay && !aParams.rolledOver) {
        // Non-hovered overlay scrollbars don't have a corner. Draw nothing.
        return false;
      }

      // This matches the sizing checks in GetMinimumWidgetSize etc.
      aScale = aScale >= 2.0f ? 2.0f : 1.0f;

      // Draw the following scroll corner.
      //
      //        Output:                      Rectangles:
      // +---+---+----------+---+     +---+---+----------+---+
      // | I | S | T ...  T | O |     | I | S | T ...  T | O |
      // +---+   |          |   |     +---+---+          |   |
      // | S   S | T ...  T |   |     | S   S | T ...  T | . |
      // +-------+          | . |     +-------+----------+ . |
      // | T      ...     T | . |     | T      ...     T | . |
      // | .              . | . |     | .              . |   |
      // | T      ...     T |   |     | T      ...     T | O |
      // +------------------+   |     +------------------+---+
      // | O       ...        O |     | O       ...        O |
      // +----------------------+     +----------------------+

      float width = aRect.width;
      float height = aRect.height;
      nscolor trackColor =
          aParams.custom ? aParams.trackColor : NS_RGBA(250, 250, 250, 255);
      ScrollbarTrackDecorationColors colors =
          ComputeScrollbarTrackDecorationColors(trackColor);
      struct {
        nscolor color;
        Rect relativeRect;
      } pieces[] = {
          {colors.mInnerColor, {0.0f, 0.0f, 1.0f * aScale, 1.0f * aScale}},
          {colors.mShadowColor,
           {1.0f * aScale, 0.0f, 1.0f * aScale, 1.0f * aScale}},
          {colors.mShadowColor,
           {0.0f, 1.0f * aScale, 2.0f * aScale, 1.0f * aScale}},
          {trackColor, {2.0f * aScale, 0.0f, width - 3.0f * aScale, 2.0f * aScale}},
          {trackColor,
           {0.0f, 2.0f * aScale, width - 1.0f * aScale, height - 3.0f * aScale}},
          {colors.mOuterColor,
           {width - 1.0f * aScale, 0.0f, 1.0f * aScale, height - 1.0f * aScale}},
          {colors.mOuterColor,
           {0.0f, height - 1.0f * aScale, width, 1.0f * aScale}},
      };

      auto current = aRects.begin();
      for (const auto& piece : pieces) {
        Rect pieceRect = piece.relativeRect + aRect.TopLeft();
        if (aParams.rtl) {
          pieceRect.x = aRect.XMost() - piece.relativeRect.XMost();
        }
        *current++ = {pieceRect, piece.color};
      }
      return true;
    }

    }  // namespace widget
    }  // namespace mozilla