Global Metrics

path: .metrics.nom.total
old: 3.0
new: 29.0

path: .metrics.nom.functions
old: 3.0
new: 29.0

path: .metrics.cognitive.sum
old: 14.0
new: 16.0

path: .metrics.cognitive.average
old: 4.666666666666667
new: 0.5517241379310345

path: .metrics.loc.ploc
old: 159.0
new: 308.0

path: .metrics.loc.cloc
old: 15.0
new: 294.0

path: .metrics.loc.sloc
old: 233.0
new: 685.0

path: .metrics.loc.lloc
old: 90.0
new: 75.0

path: .metrics.loc.blank
old: 59.0
new: 83.0

path: .metrics.nexits.average
old: 1.0
new: 1.206896551724138

path: .metrics.nexits.sum
old: 3.0
new: 35.0

path: .metrics.cyclomatic.sum
old: 13.0
new: 61.0

path: .metrics.cyclomatic.average
old: 3.25
new: 1.648648648648649

path: .metrics.halstead.bugs
old: 1.068337314420316
new: 1.8003971043661116

path: .metrics.halstead.volume
old: 5528.975085778734
new: 11100.136635150266

path: .metrics.halstead.n2
old: 123.0
new: 257.0

path: .metrics.halstead.length
old: 769.0
new: 1357.0

path: .metrics.halstead.time
old: 10080.265552730742
new: 22052.70336042986

path: .metrics.halstead.purity_ratio
old: 1.2457362927776825
new: 1.6388434156828708

path: .metrics.halstead.level
old: 0.030471943515421773
new: 0.027963658125238017

path: .metrics.halstead.N2
old: 351.0
new: 557.0

path: .metrics.halstead.effort
old: 181444.77994915337
new: 396948.66048773745

path: .metrics.halstead.N1
old: 418.0
new: 800.0

path: .metrics.halstead.difficulty
old: 32.81707317073171
new: 35.76070038910506

path: .metrics.halstead.estimated_program_length
old: 957.9712091460376
new: 2223.910515081656

path: .metrics.halstead.n1
old: 23.0
new: 33.0

path: .metrics.halstead.vocabulary
old: 146.0
new: 290.0

path: .metrics.mi.mi_original
old: 34.8908368030459
new: 2.756908797324101

path: .metrics.mi.mi_sei
old: -4.888910339677995
new: -23.040409942502116

path: .metrics.mi.mi_visual_studio
old: 20.4039981304362
new: 1.6122273668561995

path: .metrics.nargs.sum
old: 3.0
new: 8.0

path: .metrics.nargs.average
old: 1.0
new: 0.27586206896551724

Spaces Data

Minimal test - lines (25, 683)

path: .spaces[1].metrics.halstead.volume
old: 993.3186894003514
new: 10940.803400697148

path: .spaces[1].metrics.halstead.N1
old: 104.0
new: 799.0

path: .spaces[1].metrics.halstead.difficulty
old: 15.428571428571429
new: 36.32661290322581

path: .spaces[1].metrics.halstead.length
old: 176.0
new: 1345.0

path: .spaces[1].metrics.halstead.bugs
old: 0.20566242870448112
new: 1.8018895173657337

path: .spaces[1].metrics.halstead.n2
old: 35.0
new: 248.0

path: .spaces[1].metrics.halstead.effort
old: 15325.48835074828
new: 397442.32998742175

path: .spaces[1].metrics.halstead.level
old: 0.06481481481481481
new: 0.027528027528027528

path: .spaces[1].metrics.halstead.N2
old: 72.0
new: 546.0

path: .spaces[1].metrics.halstead.purity_ratio
old: 1.3530015029954636
new: 1.5904131530964865

path: .spaces[1].metrics.halstead.estimated_program_length
old: 238.1282645272016
new: 2139.105690914774

path: .spaces[1].metrics.halstead.n1
old: 15.0
new: 33.0

path: .spaces[1].metrics.halstead.vocabulary
old: 50.0
new: 281.0

path: .spaces[1].metrics.halstead.time
old: 851.4160194860156
new: 22080.129443745653

path: .spaces[1].metrics.nexits.average
old: 1.0
new: 1.206896551724138

path: .spaces[1].metrics.nexits.sum
old: 1.0
new: 35.0

path: .spaces[1].metrics.nargs.average
old: 0.0
new: 0.27586206896551724

path: .spaces[1].metrics.nargs.sum
old: 0.0
new: 8.0

path: .spaces[1].metrics.cyclomatic.sum
old: 5.0
new: 59.0

path: .spaces[1].metrics.cyclomatic.average
old: 5.0
new: 1.6857142857142855

path: .spaces[1].metrics.loc.cloc
old: 1.0
new: 286.0

path: .spaces[1].metrics.loc.blank
old: 13.0
new: 79.0

path: .spaces[1].metrics.loc.ploc
old: 40.0
new: 294.0

path: .spaces[1].metrics.loc.sloc
old: 54.0
new: 659.0

path: .spaces[1].metrics.loc.lloc
old: 26.0
new: 75.0

path: .spaces[1].metrics.nom.total
old: 1.0
new: 29.0

path: .spaces[1].metrics.nom.functions
old: 1.0
new: 29.0

path: .spaces[1].metrics.cognitive.sum
old: 9.0
new: 16.0

path: .spaces[1].metrics.cognitive.average
old: 9.0
new: 0.5517241379310345

path: .spaces[1].metrics.mi.mi_original
old: 69.34299039341577
new: 3.918955287644792

path: .spaces[1].metrics.mi.mi_visual_studio
old: 40.551456370418585
new: 2.291786717920931

path: .spaces[1].metrics.mi.mi_sei
old: 35.312053599694444
new: -21.41912039206099

Code

namespace mozilla {
namespace widget {

/**
 * KeyHandlingState is result of IMContextWrapper::OnKeyEvent().
 */
enum class KeyHandlingState {
  // The native key event has not been handled by IMContextWrapper.
  eNotHandled,
  // The native key event was handled by IMContextWrapper.
  eHandled,
  // The native key event has not been handled by IMContextWrapper,
  // but eKeyDown or eKeyUp event has been dispatched.
  eNotHandledButEventDispatched,
  // The native key event has not been handled by IMContextWrapper,
  // but eKeyDown or eKeyUp event has been dispatched and consumed.
  eNotHandledButEventConsumed,
};

class IMContextWrapper final : public TextEventDispatcherListener {
 public:
  // TextEventDispatcherListener implementation
  NS_DECL_ISUPPORTS

  NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher,
                       const IMENotification& aNotification) override;
  NS_IMETHOD_(IMENotificationRequests) GetIMENotificationRequests() override;
  NS_IMETHOD_(void)
  OnRemovedFrom(TextEventDispatcher* aTextEventDispatcher) override;
  NS_IMETHOD_(void)
  WillDispatchKeyboardEvent(TextEventDispatcher* aTextEventDispatcher,
                            WidgetKeyboardEvent& aKeyboardEvent,
                            uint32_t aIndexOfKeypress, void* aData) override;

 public:
  // aOwnerWindow is a pointer of the owner window.  When aOwnerWindow is
  // destroyed, the related IME contexts are released (i.e., IME cannot be
  // used with the instance after that).
  explicit IMContextWrapper(nsWindow* aOwnerWindow);

  // Called when the process is being shut down.
  static void Shutdown();

  // "Enabled" means the users can use all IMEs.
  // I.e., the focus is in the normal editors.
  bool IsEnabled() const;

  // OnFocusWindow is a notification that aWindow is going to be focused.
  void OnFocusWindow(nsWindow* aWindow);
  // OnBlurWindow is a notification that aWindow is going to be unfocused.
  void OnBlurWindow(nsWindow* aWindow);
  // OnDestroyWindow is a notification that aWindow is going to be destroyed.
  void OnDestroyWindow(nsWindow* aWindow);
  // OnFocusChangeInGecko is a notification that an editor gets focus.
  void OnFocusChangeInGecko(bool aFocus);
  // OnSelectionChange is a notification that selection (caret) is changed
  // in the focused editor.
  void OnSelectionChange(nsWindow* aCaller,
                         const IMENotification& aIMENotification);
  // OnThemeChanged is called when desktop theme is changed.
  static void OnThemeChanged();

  /**
   * OnKeyEvent() is called when aWindow gets a native key press event or a
   * native key release event.  If this returns true, the key event was
   * filtered by IME.  Otherwise, this returns false.
   * NOTE: When the native key press event starts composition, this returns
   *       true but dispatches an eKeyDown event or eKeyUp event before
   *       dispatching composition events or content command event.
   *
   * @param aWindow                       A window on which user operate the
   *                                      key.
   * @param aEvent                        A native key press or release
   *                                      event.
   * @param aKeyboardEventWasDispatched   true if eKeyDown or eKeyUp event
   *                                      for aEvent has already been
   *                                      dispatched.  In this case,
   *                                      this class doesn't dispatch
   *                                      keyboard event anymore.
   */
  KeyHandlingState OnKeyEvent(nsWindow* aWindow, GdkEventKey* aEvent,
                              bool aKeyboardEventWasDispatched = false);

  // IME related nsIWidget methods.
  nsresult EndIMEComposition(nsWindow* aCaller);
  void SetInputContext(nsWindow* aCaller, const InputContext* aContext,
                       const InputContextAction* aAction);
  InputContext GetInputContext();
  void OnUpdateComposition();
  void OnLayoutChange();

  TextEventDispatcher* GetTextEventDispatcher();

  // TODO: Typically, new IM comes every several years.  And now, our code
  //       becomes really IM behavior dependent.  So, perhaps, we need prefs
  //       to control related flags for IM developers.
  enum class IMContextID : uint8_t {
    Fcitx,  // 4.x or earlier
    Fcitx5,
    IBus,
    IIIMF,
    Scim,
    Uim,
    Wayland,
    Unknown,
  };

  friend std::ostream& operator<<(std::ostream& aStream,
                                  const IMContextID& aIMContextID) {
    switch (aIMContextID) {
      case IMContextID::Fcitx:
        return aStream << "Fcitx";
      case IMContextID::Fcitx5:
        return aStream << "Fcitx5";
      case IMContextID::IBus:
        return aStream << "IBus";
      case IMContextID::IIIMF:
        return aStream << "IIIMF";
      case IMContextID::Scim:
        return aStream << "Scim";
      case IMContextID::Uim:
        return aStream << "Uim";
      case IMContextID::Wayland:
        return aStream << "Wayland";
      case IMContextID::Unknown:
        return aStream << "Unknown";
    }
    MOZ_ASSERT_UNREACHABLE("Add new case for the new IM support");
    return aStream << "Unknown";
  }

  /**
   * GetIMName() returns IM name associated with mContext.  If the context is
   * xim, this look for actual engine from XMODIFIERS environment variable.
   */
  nsDependentCSubstring GetIMName() const;

  /**
   * GetWaitingSynthesizedKeyPressHardwareKeyCode() returns hardware_keycode
   * value of last handled GDK_KEY_PRESS event which is probable handled by
   * IME asynchronously and we have not received synthesized GDK_KEY_PRESS
   * event yet.
   */
  static guint16 GetWaitingSynthesizedKeyPressHardwareKeyCode() {
    return sWaitingSynthesizedKeyPressHardwareKeyCode;
  }

 protected:
  ~IMContextWrapper();

  // Owner of an instance of this class. This should be top level window.
  // The owner window must release the contexts when it's destroyed because
  // the IME contexts need the native window.  If OnDestroyWindow() is called
  // with the owner window, it'll release IME contexts.  Otherwise, it'll
  // just clean up any existing composition if it's related to the destroying
  // child window.
  nsWindow* mOwnerWindow;

  // A last focused window in this class's context.
  nsWindow* mLastFocusedWindow;

  // Actual context. This is used for handling the user's input.
  GtkIMContext* mContext;

  // mSimpleContext is used for the password field and
  // the |ime-mode: disabled;| editors if sUseSimpleContext is true.
  // These editors disable IME.  But dead keys should work.  Fortunately,
  // the simple IM context of GTK2 support only them.
  GtkIMContext* mSimpleContext;

  // mDummyContext is a dummy context and will be used in Focus()
  // when the state of mEnabled means disabled.  This context's IME state is
  // always "closed", so it closes IME forcedly.
  GtkIMContext* mDummyContext;

  // mComposingContext is not nullptr while one of mContext, mSimpleContext
  // and mDummyContext has composition.
  // XXX: We don't assume that two or more context have composition same time.
  GtkIMContext* mComposingContext;

  // IME enabled state and other things defined in InputContext.
  // Use following helper methods if you don't need the detail of the status.
  InputContext mInputContext;

  // mCompositionStart is the start offset of the composition string in the
  // current content.  When