# Global Metrics

path: .metrics.nexits.average
old: 0.0
new: 0.5714285714285714
path: .metrics.nexits.sum
old: 0.0
new: 4.0
path: .metrics.nargs.sum
old: 0.0
new: 3.0
path: .metrics.nargs.average
old: 0.0
new: 0.42857142857142855
path: .metrics.cyclomatic.average
old: 1.0
new: 1.2666666666666666
path: .metrics.cyclomatic.sum
old: 6.0
new: 19.0
path: .metrics.loc.cloc
old: 18.0
new: 85.0
path: .metrics.loc.blank
old: 8.0
new: 30.0
path: .metrics.loc.sloc
old: 49.0
new: 191.0
path: .metrics.loc.ploc
old: 23.0
new: 76.0
path: .metrics.loc.lloc
old: 0.0
new: 10.0
path: .metrics.mi.mi_original
old: 77.60984893600903
new: 41.67134000188257
path: .metrics.mi.mi_sei
old: 77.22441753244352
new: 29.30680521115906
path: .metrics.mi.mi_visual_studio
old: 45.38587657076551
new: 24.369204679463493
path: .metrics.nom.total
old: 2.0
new: 7.0
path: .metrics.nom.functions
old: 2.0
new: 7.0
path: .metrics.halstead.estimated_program_length
old: 81.83229392178727
new: 506.11891378608817
path: .metrics.halstead.N1
old: 38.0
new: 190.0
path: .metrics.halstead.volume
old: 262.36659345130676
new: 2138.071865768946
path: .metrics.halstead.length
old: 58.0
new: 331.0
path: .metrics.halstead.vocabulary
old: 23.0
new: 88.0
path: .metrics.halstead.purity_ratio
old: 1.41090161934116
new: 1.5290601624957347
path: .metrics.halstead.level
old: 0.15555555555555556
new: 0.0592407175636212
path: .metrics.halstead.effort
old: 1686.6423864726864
new: 36091.2553679448
path: .metrics.halstead.N2
old: 20.0
new: 141.0
path: .metrics.halstead.n1
old: 9.0
new: 17.0
path: .metrics.halstead.n2
old: 14.0
new: 71.0
path: .metrics.halstead.bugs
old: 0.04723103023209937
new: 0.3640380149770425
path: .metrics.halstead.time
old: 93.70235480403814
new: 2005.0697426636
path: .metrics.halstead.difficulty
old: 6.428571428571429
new: 16.880281690140844

# Spaces Data

## Minimal test - lines (18, 188)

path: .spaces[0].spaces[0].metrics.nom.functions
old: 2.0
new: 7.0
path: .spaces[0].spaces[0].metrics.nom.total
old: 2.0
new: 7.0
path: .spaces[0].spaces[0].metrics.nexits.sum
old: 0.0
new: 4.0
path: .spaces[0].spaces[0].metrics.nexits.average
old: 0.0
new: 0.5714285714285714
path: .spaces[0].spaces[0].metrics.halstead.volume
old: 232.7928234072743
new: 2065.5127757564037
path: .spaces[0].spaces[0].metrics.halstead.difficulty
old: 6.375
new: 17.386363636363637
path: .spaces[0].spaces[0].metrics.halstead.N2
old: 17.0
new: 135.0
path: .spaces[0].spaces[0].metrics.halstead.purity_ratio
old: 1.3499787739931073
new: 1.4457311116633138
path: .spaces[0].spaces[0].metrics.halstead.level
old: 0.1568627450980392
new: 0.05751633986928104
path: .spaces[0].spaces[0].metrics.halstead.n1
old: 9.0
new: 17.0
path: .spaces[0].spaces[0].metrics.halstead.vocabulary
old: 21.0
new: 83.0
path: .spaces[0].spaces[0].metrics.halstead.N1
old: 36.0
new: 189.0
path: .spaces[0].spaces[0].metrics.halstead.n2
old: 12.0
new: 66.0
path: .spaces[0].spaces[0].metrics.halstead.estimated_program_length
old: 71.54887502163469
new: 468.4168801789137
path: .spaces[0].spaces[0].metrics.halstead.effort
old: 1484.0542492213738
new: 35911.75621485565
path: .spaces[0].spaces[0].metrics.halstead.time
old: 82.44745829007633
new: 1995.0975674919807
path: .spaces[0].spaces[0].metrics.halstead.length
old: 53.0
new: 324.0
path: .spaces[0].spaces[0].metrics.halstead.bugs
old: 0.04336891892558609
new: 0.3628299882729645
path: .spaces[0].spaces[0].metrics.cyclomatic.sum
old: 4.0
new: 17.0
path: .spaces[0].spaces[0].metrics.cyclomatic.average
old: 1.0
new: 1.3076923076923077
path: .spaces[0].spaces[0].metrics.loc.blank
old: 4.0
new: 28.0
path: .spaces[0].spaces[0].metrics.loc.sloc
old: 25.0
new: 171.0
path: .spaces[0].spaces[0].metrics.loc.lloc
old: 0.0
new: 10.0
path: .spaces[0].spaces[0].metrics.loc.ploc
old: 17.0
new: 66.0
path: .spaces[0].spaces[0].metrics.loc.cloc
old: 4.0
new: 77.0
path: .spaces[0].spaces[0].metrics.nargs.average
old: 0.0
new: 0.42857142857142855
path: .spaces[0].spaces[0].metrics.nargs.sum
old: 0.0
new: 3.0
path: .spaces[0].spaces[0].metrics.mi.mi_sei
old: 83.00106133241832
new: 32.76618560127405
path: .spaces[0].spaces[0].metrics.mi.mi_visual_studio
old: 52.3938230520746
new: 25.791084599764005
path: .spaces[0].spaces[0].metrics.mi.mi_original
old: 89.59343741904756
new: 44.10275466559645

### Code

    namespace widget {

    /**
     * De-jitters touch motions by resampling (interpolating or extrapolating) touch
     * positions for the vsync timestamp.
     *
     * Touch resampling improves the touch panning experience on devices where touch
     * positions are sampled at a rate that's not an integer multiple of the display
     * refresh rate, for example 100Hz touch sampling on a 60Hz display: Without
     * resampling, we would alternate between taking one touch sample or two touch
     * samples into account each frame, creating a jittery motion ("small step, big
     * step, small step, big step").
     * Intended for use on Android, where both touch events and vsync notifications
     * arrive on the same thread, the Java UI thread.
     * This class is not thread safe.
     *
     * TouchResampler operates in the following way:
     *
     * Original events are fed into ProcessEvent().
     * Outgoing events (potentially resampled for resampling) are added to a queue
     * and can be consumed by calling ConsumeOutgoingEvents(). Touch events which
     * are not touch move events are forwarded instantly and not resampled. Only
     * touch move events are resampled. Whenever a touch move event is received, it
     * gets delayed until NotifyFrame() is called, at which point it is resampled
     * into a resampled version for the given frame timestamp, and added to the
     * outgoing queue. If no touch move event is received between two consecutive
     * frames, this is treated as a stop in the touch motion. If the last outgoing
     * event was an resampled touch move event, we return back to the non-resampled
     * state by emitting a copy of the last original touch move event, which has
     * unmodified position data. Touch events which are not touch move events also
     * force a return to the non-resampled state before they are moved to the
     * outgoing queue.
     */
    class TouchResampler final {
     public:
      // Feed a touch event into the interpolater. Returns an ID that can be used to
      // match outgoing events to this incoming event, to track data associated with
      // this event.
      uint64_t ProcessEvent(MultiTouchInput&& aInput);

      // Emit events, potentially resampled, for this timestamp. The events are put
      // into the outgoing queue. May not emit any events if there's no update.
      void NotifyFrame(const TimeStamp& aTimeStamp);

      // Returns true between the start and the end of a touch gesture. During this
      // time, the caller should keep itself registered with the system frame
      // callback mechanism, so that NotifyFrame() can be called on every frame.
      // (Otherwise, if we only registered the callback after receiving a touch move
      // event, the frame callback might be delayed by a full frame.)
      bool InTouchingState() const { return mCurrentTouches.HasTouch(); }

      struct OutgoingEvent {
        // The event, potentially modified from the original for resampling.
        MultiTouchInput mEvent;

        // Some(eventId) if this event is a modified version of an original event,
        // Nothing() if this is an extra event.
        Maybe mEventId;
      };

      // Returns the outgoing events that were produced since the last call.
      // No event IDs will be skipped. Returns at least one outgoing event for each
      // incoming event (possibly after a delay), and potential extra events with
      // no originating event ID.
      // Outgoing events should be consumed after every call to ProcessEvent() and
      // after every call to NotifyFrame().
      std::queue ConsumeOutgoingEvents() {
        return std::move(mOutgoingEvents);
      }

     private:
      // Add the event to the outgoing queue.
      void EmitEvent(MultiTouchInput&& aInput, uint64_t aEventId) {
        mLastEmittedEventTime = aInput.mTimeStamp;
        mOutgoingEvents.push(OutgoingEvent{std::move(aInput), Some(aEventId)});
      }

      // Emit an event that does not correspond to an incoming event.
      void EmitExtraEvent(MultiTouchInput&& aInput) {
        mLastEmittedEventTime = aInput.mTimeStamp;
        mOutgoingEvents.push(OutgoingEvent{std::move(aInput), Nothing()});
      }

      // Move any touch move events that we deferred for resampling to the outgoing
      // queue unmodified, leaving mDeferredTouchMoveEvents empty.
      void FlushDeferredTouchMoveEventsUnresampled();

      // Must only be called if mInResampledState is true and
      // mDeferredTouchMoveEvents is empty. Emits mOriginalOfResampledTouchMove,
      // with a potentially adjusted timestamp for correct ordering.
      void ReturnToNonResampledState();

      // Takes historical touch data from mRemainingTouchData and prepends it to the
      // data in aInput.
      void PrependLeftoverHistoricalData(MultiTouchInput* aInput);

      struct DataPoint {
        TimeStamp mTimeStamp;
        ScreenIntPoint mPosition;
      };

      struct TouchInfo {
        void Update(const SingleTouchData& aTouch, const TimeStamp& aEventTime);
        ScreenIntPoint ResampleAtTime(const ScreenIntPoint& aLastObservedPosition,
                                      const TimeStamp& aTimeStamp);

        int32_t mIdentifier = 0;
        Maybe mBaseDataPoint;
        Maybe mLatestDataPoint;
      };

      struct CurrentTouches {
        void UpdateFromEvent(const MultiTouchInput& aInput);
        bool HasTouch() const { return !mTouches.IsEmpty(); }
        TimeStamp LatestDataPointTime() { return mLatestDataPointTime; }

        ScreenIntPoint ResampleTouchPositionAtTime(
            int32_t aIdentifier, const ScreenIntPoint& aLastObservedPosition,
            const TimeStamp& aTimeStamp);

        void ClearDataPoints() {
          for (auto& touch : mTouches) {
            touch.mBaseDataPoint = Nothing();
            touch.mLatestDataPoint = Nothing();
          }
        }

       private:
        nsTArray::iterator TouchByIdentifier(int32_t aIdentifier);

        nsTArray mTouches;
        TimeStamp mLatestDataPointTime;
      };

      // The current touch positions with historical data points. This data only
      // contains original non-resampled positions from the incoming touch events.
      CurrentTouches mCurrentTouches;

      // Incoming touch move events are stored here until NotifyFrame is called.
      std::queue> mDeferredTouchMoveEvents;

      // Stores any touch samples that were not included in the last emitted touch
      // move event because they were in the future compared to the emitted event's
      // timestamp. These data points should be prepended to the historical data of
      // the next emitted touch move evnt.
      // Can only be non-empty if mInResampledState is true.
      std::unordered_map>
          mRemainingTouchData;

      // If we're in an resampled state, because the last outgoing event was a
      // resampled touch move event, then this contains a copy of the unresampled,
      // original touch move event.
      // Some() iff mInResampledState is true.
      Maybe mOriginalOfResampledTouchMove;

      // The stream of outgoing events that can be consumed by our caller.
      std::queue mOutgoingEvents;

      // The timestamp of the event that was emitted most recently, or the null
      // timestamp if no event has been emitted yet.
      TimeStamp mLastEmittedEventTime;

      uint64_t mNextEventId = 0;

      // True if the last outgoing event was a touch move event with an resampled
      // position. We only want to stay in this state as long as a continuous stream
      // of touch move events is coming in.
      bool mInResampledState = false;
    };

    }  // namespace widget

## Minimal test - lines (51, 186)

path: .spaces[0].spaces[0].spaces[0].metrics.nargs.sum
old: 0.0
new: 3.0
path: .spaces[0].spaces[0].spaces[0].metrics.nargs.average
old: 0.0
new: 0.42857142857142855
path: .spaces[0].spaces[0].spaces[0].metrics.cyclomatic.average
old: 1.0
new: 1.3333333333333333
path: .spaces[0].spaces[0].spaces[0].metrics.cyclomatic.sum
old: 2.0
new: 16.0
path: .spaces[0].spaces[0].spaces[0].metrics.loc.ploc
old: 11.0
new: 64.0
path: .spaces[0].spaces[0].spaces[0].metrics.loc.lloc
old: 0.0
new: 10.0
path: .spaces[0].spaces[0].spaces[0].metrics.loc.cloc
old: 2.0
new: 46.0
path: .spaces[0].spaces[0].spaces[0].metrics.loc.blank
old: 2.0
new: 26.0
path: .spaces[0].spaces[0].spaces[0].metrics.loc.sloc
old: 15.0
new: 136.0
path: .spaces[0].spaces[0].spaces[0].metrics.nexits.average
old: 0.0
new: 0.5714285714285714
path: .spaces[0].spaces[0].spaces[0].metrics.nexits.sum
old: 0.0
new: 4.0
path: .spaces[0].spaces[0].spaces[0].metrics.nom.total
old: 1.0
new: 7.0
path: .spaces[0].spaces[0].spaces[0].metrics.nom.functions
old: 1.0
new: 7.0
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.length
old: 35.0
new: 321.0
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.estimated_program_length
old: 57.05865002596162
new: 460.9407761481053
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.level
old: 0.18181818181818185
new: 0.057067603160667245
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.volume
old: 145.94737505048093
new: 2040.7741934824048
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.n2
old: 9.0
new: 65.0
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.vocabulary
old: 18.0
new: 82.0
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.effort
old: 802.7105627776451
new: 35760.64317502245
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.N2
old: 11.0
new: 134.0
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.purity_ratio
old: 1.6302471435989034
new: 1.43595257367011
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.difficulty
old: 5.5
new: 17.523076923076925
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.bugs
old: 0.028790645175253947
new: 0.36181143850239467
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.n1
old: 9.0
new: 17.0
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.N1
old: 24.0
new: 187.0
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.time
old: 44.59503126542473
new: 1986.7023986123584
path: .spaces[0].spaces[0].spaces[0].metrics.mi.mi_sei
old: 96.66371880954054
new: 34.526398748934426
path: .spaces[0].spaces[0].spaces[0].metrics.mi.mi_visual_studio
old: 58.92205085403852
new: 28.131784409076637
path: .spaces[0].spaces[0].spaces[0].metrics.mi.mi_original
old: 100.75670696040586
new: 48.10535133952105

### Code

    class TouchResampler final {
     public:
      // Feed a touch event into the interpolater. Returns an ID that can be used to
      // match outgoing events to this incoming event, to track data associated with
      // this event.
      uint64_t ProcessEvent(MultiTouchInput&& aInput);

      // Emit events, potentially resampled, for this timestamp. The events are put
      // into the outgoing queue. May not emit any events if there's no update.
      void NotifyFrame(const TimeStamp& aTimeStamp);

      // Returns true between the start and the end of a touch gesture. During this
      // time, the caller should keep itself registered with the system frame
      // callback mechanism, so that NotifyFrame() can be called on every frame.
      // (Otherwise, if we only registered the callback after receiving a touch move
      // event, the frame callback might be delayed by a full frame.)
      bool InTouchingState() const { return mCurrentTouches.HasTouch(); }

      struct OutgoingEvent {
        // The event, potentially modified from the original for resampling.
        MultiTouchInput mEvent;

        // Some(eventId) if this event is a modified version of an original event,
        // Nothing() if this is an extra event.
        Maybe mEventId;
      };

      // Returns the outgoing events that were produced since the last call.
      // No event IDs will be skipped. Returns at least one outgoing event for each
      // incoming event (possibly after a delay), and potential extra events with
      // no originating event ID.
      // Outgoing events should be consumed after every call to ProcessEvent() and
      // after every call to NotifyFrame().
      std::queue ConsumeOutgoingEvents() {
        return std::move(mOutgoingEvents);
      }

     private:
      // Add the event to the outgoing queue.
      void EmitEvent(MultiTouchInput&& aInput, uint64_t aEventId) {
        mLastEmittedEventTime = aInput.mTimeStamp;
        mOutgoingEvents.push(OutgoingEvent{std::move(aInput), Some(aEventId)});
      }

      // Emit an event that does not correspond to an incoming event.
      void EmitExtraEvent(MultiTouchInput&& aInput) {
        mLastEmittedEventTime = aInput.mTimeStamp;
        mOutgoingEvents.push(OutgoingEvent{std::move(aInput), Nothing()});
      }

      // Move any touch move events that we deferred for resampling to the outgoing
      // queue unmodified, leaving mDeferredTouchMoveEvents empty.
      void FlushDeferredTouchMoveEventsUnresampled();

      // Must only be called if mInResampledState is true and
      // mDeferredTouchMoveEvents is empty. Emits mOriginalOfResampledTouchMove,
      // with a potentially adjusted timestamp for correct ordering.
      void ReturnToNonResampledState();

      // Takes historical touch data from mRemainingTouchData and prepends it to the
      // data in aInput.
      void PrependLeftoverHistoricalData(MultiTouchInput* aInput);

      struct DataPoint {
        TimeStamp mTimeStamp;
        ScreenIntPoint mPosition;
      };

      struct TouchInfo {
        void Update(const SingleTouchData& aTouch, const TimeStamp& aEventTime);
        ScreenIntPoint ResampleAtTime(const ScreenIntPoint& aLastObservedPosition,
                                      const TimeStamp& aTimeStamp);

        int32_t mIdentifier = 0;
        Maybe mBaseDataPoint;
        Maybe mLatestDataPoint;
      };

      struct CurrentTouches {
        void UpdateFromEvent(const MultiTouchInput& aInput);
        bool HasTouch() const { return !mTouches.IsEmpty(); }
        TimeStamp LatestDataPointTime() { return mLatestDataPointTime; }

        ScreenIntPoint ResampleTouchPositionAtTime(
            int32_t aIdentifier, const ScreenIntPoint& aLastObservedPosition,
            const TimeStamp& aTimeStamp);

        void ClearDataPoints() {
          for (auto& touch : mTouches) {
            touch.mBaseDataPoint = Nothing();
            touch.mLatestDataPoint = Nothing();
          }
        }

       private:
        nsTArray::iterator TouchByIdentifier(int32_t aIdentifier);

        nsTArray mTouches;
        TimeStamp mLatestDataPointTime;
      };

      // The current touch positions with historical data points. This data only
      // contains original non-resampled positions from the incoming touch events.
      CurrentTouches mCurrentTouches;

      // Incoming touch move events are stored here until NotifyFrame is called.
      std::queue> mDeferredTouchMoveEvents;

      // Stores any touch samples that were not included in the last emitted touch
      // move event because they were in the future compared to the emitted event's
      // timestamp. These data points should be prepended to the historical data of
      // the next emitted touch move evnt.
      // Can only be non-empty if mInResampledState is true.
      std::unordered_map>
          mRemainingTouchData;

      // If we're in an resampled state, because the last outgoing event was a
      // resampled touch move event, then this contains a copy of the unresampled,
      // original touch move event.
      // Some() iff mInResampledState is true.
      Maybe mOriginalOfResampledTouchMove;

      // The stream of outgoing events that can be consumed by our caller.
      std::queue mOutgoingEvents;

      // The timestamp of the event that was emitted most recently, or the null
      // timestamp if no event has been emitted yet.
      TimeStamp mLastEmittedEventTime;

      uint64_t mNextEventId = 0;

      // True if the last outgoing event was a touch move event with an resampled
      // position. We only want to stay in this state as long as a continuous stream
      // of touch move events is coming in.
      bool mInResampledState = false;
    };

## Minimal test - lines (67, 67)

path: .spaces[0].spaces[0].spaces[0].spaces[0].metrics.loc.lloc
old: 0.0
new: 1.0
path: .spaces[0].spaces[0].spaces[0].spaces[0].metrics.mi.mi_sei
old: 155.17000000000002
new: 144.8408406278255
path: .spaces[0].spaces[0].spaces[0].spaces[0].metrics.mi.mi_visual_studio
old: 93.54204911302038
new: 89.35513233151332
path: .spaces[0].spaces[0].spaces[0].spaces[0].metrics.mi.mi_original
old: 159.95690398326485
new: 152.79727628688778
path: .spaces[0].spaces[0].spaces[0].spaces[0].metrics.halstead.estimated_program_length
old: 4.754887502163468
new: 20.264662506490403
path: .spaces[0].spaces[0].spaces[0].spaces[0].metrics.halstead.level
old: 0.6666666666666666
new: 0.3333333333333333
path: .spaces[0].spaces[0].spaces[0].spaces[0].metrics.halstead.time
old: 0.6666666666666666
new: 5.2832083357371875
path: .spaces[0].spaces[0].spaces[0].spaces[0].metrics.halstead.volume
old: 8.0
new: 31.69925001442312
path: .spaces[0].spaces[0].spaces[0].spaces[0].metrics.halstead.length
old: 4.0
new: 10.0
path: .spaces[0].spaces[0].spaces[0].spaces[0].metrics.halstead.vocabulary
old: 4.0
new: 9.0
path: .spaces[0].spaces[0].spaces[0].spaces[0].metrics.halstead.N1
old: 3.0
new: 7.0
path: .spaces[0].spaces[0].spaces[0].spaces[0].metrics.halstead.n2
old: 1.0
new: 3.0
path: .spaces[0].spaces[0].spaces[0].spaces[0].metrics.halstead.difficulty
old: 1.5
new: 3.0
path: .spaces[0].spaces[0].spaces[0].spaces[0].metrics.halstead.bugs
old: 0.0017471609294725976
new: 0.006944786620971931
path: .spaces[0].spaces[0].spaces[0].spaces[0].metrics.halstead.n1
old: 3.0
new: 6.0
path: .spaces[0].spaces[0].spaces[0].spaces[0].metrics.halstead.purity_ratio
old: 1.188721875540867
new: 2.0264662506490403
path: .spaces[0].spaces[0].spaces[0].spaces[0].metrics.halstead.N2
old: 1.0
new: 3.0
path: .spaces[0].spaces[0].spaces[0].spaces[0].metrics.halstead.effort
old: 12.0
new: 95.09775004326936
path: .spaces[0].spaces[0].spaces[0].spaces[0].metrics.nexits.sum
old: 0.0
new: 1.0
path: .spaces[0].spaces[0].spaces[0].spaces[0].metrics.nexits.average
old: 0.0
new: 1.0

### Code

      bool InTouchingState() const { return mCurrentTouches.HasTouch(); }

## Minimal test - lines (17, 189)

path: .spaces[0].metrics.nexits.sum
old: 0.0
new: 4.0
path: .spaces[0].metrics.nexits.average
old: 0.0
new: 0.5714285714285714
path: .spaces[0].metrics.mi.mi_sei
old: 80.57671602890764
new: 32.21473506783513
path: .spaces[0].metrics.mi.mi_original
old: 84.9991387284759
new: 43.63830607963422
path: .spaces[0].metrics.mi.mi_visual_studio
old: 49.707098671623335
new: 25.519477239552177
path: .spaces[0].metrics.cyclomatic.average
old: 1.0
new: 1.2857142857142858
path: .spaces[0].metrics.cyclomatic.sum
old: 5.0
new: 18.0
path: .spaces[0].metrics.loc.lloc
old: 0.0
new: 10.0
path: .spaces[0].metrics.loc.sloc
old: 32.0
new: 173.0
path: .spaces[0].metrics.loc.blank
old: 6.0
new: 27.0
path: .spaces[0].metrics.loc.ploc
old: 19.0
new: 68.0
path: .spaces[0].metrics.loc.cloc
old: 7.0
new: 78.0
path: .spaces[0].metrics.halstead.time
old: 86.44436676127685
new: 1997.4984864665944
path: .spaces[0].metrics.halstead.vocabulary
old: 22.0
new: 84.0
path: .spaces[0].metrics.halstead.bugs
old: 0.044759464313189494
new: 0.363121018576748
path: .spaces[0].metrics.halstead.estimated_program_length
old: 76.63504134881501
new: 475.9148440619265
path: .spaces[0].metrics.halstead.length
old: 56.0
new: 326.0
path: .spaces[0].metrics.halstead.level
old: 0.16049382716049382
new: 0.05795847750865052
path: .spaces[0].metrics.halstead.purity_ratio
old: 1.3684828812288394
new: 1.4598614848525353
path: .spaces[0].metrics.halstead.N1
old: 38.0
new: 190.0
path: .spaces[0].metrics.halstead.volume
old: 249.72817064368863
new: 2083.895479825876
path: .spaces[0].metrics.halstead.N2
old: 18.0
new: 136.0
path: .spaces[0].metrics.halstead.n2
old: 13.0
new: 67.0
path: .spaces[0].metrics.halstead.effort
old: 1555.9986017029833
new: 35954.972756398696
path: .spaces[0].metrics.halstead.n1
old: 9.0
new: 17.0
path: .spaces[0].metrics.halstead.difficulty
old: 6.230769230769231
new: 17.253731343283583
path: .spaces[0].metrics.nargs.sum
old: 0.0
new: 3.0
path: .spaces[0].metrics.nargs.average
old: 0.0
new: 0.42857142857142855
path: .spaces[0].metrics.nom.functions
old: 2.0
new: 7.0
path: .spaces[0].metrics.nom.total
old: 2.0
new: 7.0

### Code

    namespace mozilla {
    namespace widget {

    /**
     * De-jitters touch motions by resampling (interpolating or extrapolating) touch
     * positions for the vsync timestamp.
     *
     * Touch resampling improves the touch panning experience on devices where touch
     * positions are sampled at a rate that's not an integer multiple of the display
     * refresh rate, for example 100Hz touch sampling on a 60Hz display: Without
     * resampling, we would alternate between taking one touch sample or two touch
     * samples into account each frame, creating a jittery motion ("small step, big
     * step, small step, big step").
     * Intended for use on Android, where both touch events and vsync notifications
     * arrive on the same thread, the Java UI thread.
     * This class is not thread safe.
     *
     * TouchResampler operates in the following way:
     *
     * Original events are fed into ProcessEvent().
     * Outgoing events (potentially resampled for resampling) are added to a queue
     * and can be consumed by calling ConsumeOutgoingEvents(). Touch events which
     * are not touch move events are forwarded instantly and not resampled. Only
     * touch move events are resampled. Whenever a touch move event is received, it
     * gets delayed until NotifyFrame() is called, at which point it is resampled
     * into a resampled version for the given frame timestamp, and added to the
     * outgoing queue. If no touch move event is received between two consecutive
     * frames, this is treated as a stop in the touch motion. If the last outgoing
     * event was an resampled touch move event, we return back to the non-resampled
     * state by emitting a copy of the last original touch move event, which has
     * unmodified position data. Touch events which are not touch move events also
     * force a return to the non-resampled state before they are moved to the
     * outgoing queue.
     */
    class TouchResampler final {
     public:
      // Feed a touch event into the interpolater. Returns an ID that can be used to
      // match outgoing events to this incoming event, to track data associated with
      // this event.
      uint64_t ProcessEvent(MultiTouchInput&& aInput);

      // Emit events, potentially resampled, for this timestamp. The events are put
      // into the outgoing queue. May not emit any events if there's no update.
      void NotifyFrame(const TimeStamp& aTimeStamp);

      // Returns true between the start and the end of a touch gesture. During this
      // time, the caller should keep itself registered with the system frame
      // callback mechanism, so that NotifyFrame() can be called on every frame.
      // (Otherwise, if we only registered the callback after receiving a touch move
      // event, the frame callback might be delayed by a full frame.)
      bool InTouchingState() const { return mCurrentTouches.HasTouch(); }

      struct OutgoingEvent {
        // The event, potentially modified from the original for resampling.
        MultiTouchInput mEvent;

        // Some(eventId) if this event is a modified version of an original event,
        // Nothing() if this is an extra event.
        Maybe mEventId;
      };

      // Returns the outgoing events that were produced since the last call.
      // No event IDs will be skipped. Returns at least one outgoing event for each
      // incoming event (possibly after a delay), and potential extra events with
      // no originating event ID.
      // Outgoing events should be consumed after every call to ProcessEvent() and
      // after every call to NotifyFrame().
      std::queue ConsumeOutgoingEvents() {
        return std::move(mOutgoingEvents);
      }

     private:
      // Add the event to the outgoing queue.
      void EmitEvent(MultiTouchInput&& aInput, uint64_t aEventId) {
        mLastEmittedEventTime = aInput.mTimeStamp;
        mOutgoingEvents.push(OutgoingEvent{std::move(aInput), Some(aEventId)});
      }

      // Emit an event that does not correspond to an incoming event.
      void EmitExtraEvent(MultiTouchInput&& aInput) {
        mLastEmittedEventTime = aInput.mTimeStamp;
        mOutgoingEvents.push(OutgoingEvent{std::move(aInput), Nothing()});
      }

      // Move any touch move events that we deferred for resampling to the outgoing
      // queue unmodified, leaving mDeferredTouchMoveEvents empty.
      void FlushDeferredTouchMoveEventsUnresampled();

      // Must only be called if mInResampledState is true and
      // mDeferredTouchMoveEvents is empty. Emits mOriginalOfResampledTouchMove,
      // with a potentially adjusted timestamp for correct ordering.
      void ReturnToNonResampledState();

      // Takes historical touch data from mRemainingTouchData and prepends it to the
      // data in aInput.
      void PrependLeftoverHistoricalData(MultiTouchInput* aInput);

      struct DataPoint {
        TimeStamp mTimeStamp;
        ScreenIntPoint mPosition;
      };

      struct TouchInfo {
        void Update(const SingleTouchData& aTouch, const TimeStamp& aEventTime);
        ScreenIntPoint ResampleAtTime(const ScreenIntPoint& aLastObservedPosition,
                                      const TimeStamp& aTimeStamp);

        int32_t mIdentifier = 0;
        Maybe mBaseDataPoint;
        Maybe mLatestDataPoint;
      };

      struct CurrentTouches {
        void UpdateFromEvent(const MultiTouchInput& aInput);
        bool HasTouch() const { return !mTouches.IsEmpty(); }
        TimeStamp LatestDataPointTime() { return mLatestDataPointTime; }

        ScreenIntPoint ResampleTouchPositionAtTime(
            int32_t aIdentifier, const ScreenIntPoint& aLastObservedPosition,
            const TimeStamp& aTimeStamp);

        void ClearDataPoints() {
          for (auto& touch : mTouches) {
            touch.mBaseDataPoint = Nothing();
            touch.mLatestDataPoint = Nothing();
          }
        }

       private:
        nsTArray::iterator TouchByIdentifier(int32_t aIdentifier);

        nsTArray mTouches;
        TimeStamp mLatestDataPointTime;
      };

      // The current touch positions with historical data points. This data only
      // contains original non-resampled positions from the incoming touch events.
      CurrentTouches mCurrentTouches;

      // Incoming touch move events are stored here until NotifyFrame is called.
      std::queue> mDeferredTouchMoveEvents;

      // Stores any touch samples that were not included in the last emitted touch
      // move event because they were in the future compared to the emitted event's
      // timestamp. These data points should be prepended to the historical data of
      // the next emitted touch move evnt.
      // Can only be non-empty if mInResampledState is true.
      std::unordered_map>
          mRemainingTouchData;

      // If we're in an resampled state, because the last outgoing event was a
      // resampled touch move event, then this contains a copy of the unresampled,
      // original touch move event.
      // Some() iff mInResampledState is true.
      Maybe mOriginalOfResampledTouchMove;

      // The stream of outgoing events that can be consumed by our caller.
      std::queue mOutgoingEvents;

      // The timestamp of the event that was emitted most recently, or the null
      // timestamp if no event has been emitted yet.
      TimeStamp mLastEmittedEventTime;

      uint64_t mNextEventId = 0;

      // True if the last outgoing event was a touch move event with an resampled
      // position. We only want to stay in this state as long as a continuous stream
      // of touch move events is coming in.
      bool mInResampledState = false;
    };

    }  // namespace widget
    }  // namespace mozilla