Global Metrics
path: .metrics.nom.closures
old: 0.0
new: 2.0
path: .metrics.nom.functions
old: 20.0
new: 17.0
path: .metrics.nom.total
old: 20.0
new: 19.0
path: .metrics.cognitive.average
old: 0.0
new: 0.5789473684210527
path: .metrics.cognitive.sum
old: 0.0
new: 11.0
path: .metrics.mi.mi_sei
old: -14.269474730390726
new: -8.526717464579328
path: .metrics.mi.mi_visual_studio
old: 5.930942612387386
new: 14.106869054552885
path: .metrics.mi.mi_original
old: 10.14191186718243
new: 24.122746083285435
path: .metrics.nargs.average
old: 1.15
new: 0.42105263157894735
path: .metrics.nargs.sum
old: 23.0
new: 8.0
path: .metrics.cyclomatic.sum
old: 34.0
new: 38.0
path: .metrics.cyclomatic.average
old: 1.0303030303030305
new: 1.4074074074074074
path: .metrics.nexits.average
old: 0.3
new: 0.5789473684210527
path: .metrics.nexits.sum
old: 6.0
new: 11.0
path: .metrics.halstead.purity_ratio
old: 1.8127404273924628
new: 1.6786057373752006
path: .metrics.halstead.n2
old: 280.0
new: 197.0
path: .metrics.halstead.N2
old: 579.0
new: 390.0
path: .metrics.halstead.time
old: 10379.413172541495
new: 11255.96663236292
path: .metrics.halstead.volume
old: 10629.328942316191
new: 7580.941629317933
path: .metrics.halstead.vocabulary
old: 297.0
new: 224.0
path: .metrics.halstead.length
old: 1294.0
new: 971.0
path: .metrics.halstead.N1
old: 715.0
new: 581.0
path: .metrics.halstead.n1
old: 17.0
new: 27.0
path: .metrics.halstead.estimated_program_length
old: 2345.686113045847
new: 1629.92617099132
path: .metrics.halstead.difficulty
old: 17.576785714285716
new: 26.725888324873097
path: .metrics.halstead.effort
old: 186829.43710574697
new: 202607.39938253257
path: .metrics.halstead.level
old: 0.05689322361068779
new: 0.03741690408357075
path: .metrics.halstead.bugs
old: 1.0893705126318372
new: 1.1498705381538254
path: .metrics.loc.ploc
old: 249.0
new: 199.0
path: .metrics.loc.blank
old: 101.0
new: 44.0
path: .metrics.loc.sloc
old: 646.0
new: 287.0
path: .metrics.loc.lloc
old: 20.0
new: 33.0
path: .metrics.loc.cloc
old: 296.0
new: 44.0
Spaces Data
Minimal test - lines (21, 285)
path: .spaces[1].metrics.nom.functions
old: 0.0
new: 17.0
path: .spaces[1].metrics.nom.closures
old: 0.0
new: 2.0
path: .spaces[1].metrics.nom.total
old: 0.0
new: 19.0
path: .spaces[1].metrics.halstead.N1
old: 0.0
new: 580.0
path: .spaces[1].metrics.halstead.purity_ratio
old: null
new: 1.6148536670216989
path: .spaces[1].metrics.halstead.n1
old: 0.0
new: 27.0
path: .spaces[1].metrics.halstead.N2
old: 1.0
new: 379.0
path: .spaces[1].metrics.halstead.effort
old: 0.0
new: 202224.6805192158
path: .spaces[1].metrics.halstead.estimated_program_length
old: null
new: 1548.6446666738093
path: .spaces[1].metrics.halstead.n2
old: 1.0
new: 188.0
path: .spaces[1].metrics.halstead.bugs
old: 0.0
new: 1.1484220362343256
path: .spaces[1].metrics.halstead.difficulty
old: 0.0
new: 27.215425531914892
path: .spaces[1].metrics.halstead.volume
old: 0.0
new: 7430.516942756292
path: .spaces[1].metrics.halstead.time
old: 0.0
new: 11234.704473289768
path: .spaces[1].metrics.halstead.length
old: 1.0
new: 959.0
path: .spaces[1].metrics.halstead.vocabulary
old: 1.0
new: 215.0
path: .spaces[1].metrics.halstead.level
old: null
new: 0.03674386787843252
path: .spaces[1].metrics.nexits.average
old: null
new: 0.5789473684210527
path: .spaces[1].metrics.nexits.sum
old: 0.0
new: 11.0
path: .spaces[1].metrics.cyclomatic.average
old: 1.0
new: 1.44
path: .spaces[1].metrics.cyclomatic.sum
old: 1.0
new: 36.0
path: .spaces[1].metrics.loc.lloc
old: 0.0
new: 33.0
path: .spaces[1].metrics.loc.sloc
old: 1.0
new: 265.0
path: .spaces[1].metrics.loc.ploc
old: 1.0
new: 187.0
path: .spaces[1].metrics.loc.blank
old: 0.0
new: 40.0
path: .spaces[1].metrics.loc.cloc
old: 0.0
new: 38.0
path: .spaces[1].metrics.nargs.sum
old: 0.0
new: 8.0
path: .spaces[1].metrics.nargs.average
old: null
new: 0.42105263157894735
path: .spaces[1].metrics.cognitive.average
old: null
new: 0.5789473684210527
path: .spaces[1].metrics.cognitive.sum
old: 0.0
new: 11.0
path: .spaces[1].metrics.mi.mi_sei
old: null
new: -6.877175798631306
path: .spaces[1].metrics.mi.mi_original
old: null
new: 25.9789531251527
path: .spaces[1].metrics.mi.mi_visual_studio
old: null
new: 15.19237024862731
Code
namespace mozilla {
class TextComposition;
namespace dom {
class BrowserChild;
}
namespace widget {
class GeckoEditableSupport final
: public TextEventDispatcherListener,
public java::GeckoEditableChild::Natives {
/*
Rules for managing IME between Gecko and Java:
* Gecko controls the text content, and Java shadows the Gecko text
through text updates
* Gecko and Java maintain separate selections, and synchronize when
needed through selection updates and set-selection events
* Java controls the composition, and Gecko shadows the Java
composition through update composition events
*/
using EditableBase = java::GeckoEditableChild::Natives;
using EditableClient = java::SessionTextInput::EditableClient;
using EditableListener = java::SessionTextInput::EditableListener;
struct IMETextChange final {
int32_t mStart, mOldEnd, mNewEnd;
IMETextChange() : mStart(-1), mOldEnd(-1), mNewEnd(-1) {}
explicit IMETextChange(const IMENotification& aIMENotification)
: mStart(aIMENotification.mTextChangeData.mStartOffset),
mOldEnd(aIMENotification.mTextChangeData.mRemovedEndOffset),
mNewEnd(aIMENotification.mTextChangeData.mAddedEndOffset) {
MOZ_ASSERT(aIMENotification.mMessage == NOTIFY_IME_OF_TEXT_CHANGE,
"IMETextChange initialized with wrong notification");
MOZ_ASSERT(aIMENotification.mTextChangeData.IsValid(),
"The text change notification isn't initialized");
MOZ_ASSERT(aIMENotification.mTextChangeData.IsInInt32Range(),
"The text change notification is out of range");
}
bool IsEmpty() const { return mStart < 0; }
};
enum FlushChangesFlag {
// Not retrying.
FLUSH_FLAG_NONE,
// Retrying due to IME text changes during flush.
FLUSH_FLAG_RETRY,
// Retrying due to IME sync exceptions during flush.
FLUSH_FLAG_RECOVER
};
enum RemoveCompositionFlag { CANCEL_IME_COMPOSITION, COMMIT_IME_COMPOSITION };
const bool mIsRemote;
jni::NativeWeakPtr mWindow; // Parent only
RefPtr mDispatcher;
java::GeckoEditableChild::GlobalRef mEditable;
bool mEditableAttached;
InputContext mInputContext;
AutoTArray, 4> mIMEKeyEvents;
AutoTArray mIMETextChanges;
RefPtr mIMERanges;
RefPtr mDisposeRunnable;
int32_t mIMEMaskEventsCount; // Mask events when > 0.
int32_t mIMEFocusCount; // We are focused when > 0.
bool mIMEDelaySynchronizeReply; // We reply asynchronously when true.
int32_t mIMEActiveSynchronizeCount; // The number of replies being delayed.
int32_t mIMEActiveCompositionCount; // The number of compositions expected.
uint32_t mDisposeBlockCount;
bool mIMESelectionChanged;
bool mIMETextChangedDuringFlush;
bool mIMEMonitorCursor;
nsIWidget* GetWidget() const;
nsWindow* GetNsWindow() const;
nsresult BeginInputTransaction(TextEventDispatcher* aDispatcher) {
if (mIsRemote) {
return aDispatcher->BeginInputTransaction(this);
} else {
return aDispatcher->BeginNativeInputTransaction();
}
}
virtual ~GeckoEditableSupport() {}
RefPtr GetComposition() const;
bool RemoveComposition(RemoveCompositionFlag aFlag = COMMIT_IME_COMPOSITION);
void SendIMEDummyKeyEvent(nsIWidget* aWidget, EventMessage msg);
void AddIMETextChange(const IMETextChange& aChange);
void PostFlushIMEChanges();
void FlushIMEChanges(FlushChangesFlag aFlags = FLUSH_FLAG_NONE);
void FlushIMEText(FlushChangesFlag aFlags = FLUSH_FLAG_NONE);
void AsyncNotifyIME(int32_t aNotification);
void UpdateCompositionRects();
bool DoReplaceText(int32_t aStart, int32_t aEnd, jni::String::Param aText);
bool DoUpdateComposition(int32_t aStart, int32_t aEnd, int32_t aFlags);
void OnNotifyIMEOfCompositionEventHandled();
void NotifyIMEContext(const InputContext& aContext,
const InputContextAction& aAction);
public:
template
static void OnNativeCall(Functor&& aCall) {
struct IMEEvent : nsAppShell::LambdaEvent {
explicit IMEEvent(Functor&& l)
: nsAppShell::LambdaEvent(std::move(l)) {}
bool IsUIEvent() const override {
using GES = GeckoEditableSupport;
if (this->lambda.IsTarget(&GES::OnKeyEvent) ||
this->lambda.IsTarget(&GES::OnImeReplaceText) ||
this->lambda.IsTarget(&GES::OnImeUpdateComposition)) {
return true;
}
return false;
}
void Run() override {
if (NS_WARN_IF(!this->lambda.GetNativeObject())) {
// Ignore stale calls after disposal.
jni::GetGeckoThreadEnv()->ExceptionClear();
return;
}
nsAppShell::LambdaEvent::Run();
}
};
nsAppShell::PostEvent(mozilla::MakeUnique(std::move(aCall)));
}
static void SetOnBrowserChild(dom::BrowserChild* aBrowserChild);
// Constructor for main process GeckoEditableChild.
GeckoEditableSupport(jni::NativeWeakPtr aWindow,
java::GeckoEditableChild::Param aEditableChild)
: mIsRemote(!aWindow.IsAttached()),
mWindow(aWindow),
mEditable(aEditableChild),
mEditableAttached(!mIsRemote),
mIMERanges(new TextRangeArray()),
mIMEMaskEventsCount(1), // Mask IME events since there's no focus yet
mIMEFocusCount(0),
mIMEDelaySynchronizeReply(false),
mIMEActiveSynchronizeCount(0),
mDisposeBlockCount(0),
mIMESelectionChanged(false),
mIMETextChangedDuringFlush(false),
mIMEMonitorCursor(false) {}
// Constructor for content process GeckoEditableChild.
explicit GeckoEditableSupport(java::GeckoEditableChild::Param aEditableChild)
: GeckoEditableSupport(nullptr, aEditableChild) {}
NS_DECL_ISUPPORTS
// TextEventDispatcherListener methods
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;
void SetInputContext(const InputContext& aContext,
const InputContextAction& aAction);
InputContext GetInputContext();
bool HasIMEFocus() const { return mIMEFocusCount != 0; }
void AddBlocker() { mDisposeBlockCount++; }
void ReleaseBlocker() {
mDisposeBlockCount--;
if (!mDisposeBlockCount && mDisposeRunnable) {
if (HasIMEFocus()) {
// If we have IME focus, GeckoEditableChild is already attached again.
// So disposer is unnecessary.
mDisposeRunnable = nullptr;
return;
}
RefPtr self(this);
RefPtr disposer = std::move(mDisposeRunnable);
nsAppShell::PostEvent(
[self = std::move(self), disposer = std::move(disposer)] {
self->mEditableAttached = false;
disposer->Run();
});
}
}
bool IsGeckoEditableUsed() const { return mDisposeBlockCount != 0; }
// GeckoEditableChild methods
using EditableBase::AttachNative;
using EditableBase::DisposeNative;
const java::GeckoEditableChild::Ref& GetJavaEditable() { return mEditable; }
void OnWeakNonIntrusiveDetach(already_AddRefed aDisposer) {
RefPtr self(this);
nsAppShell::PostEvent(
[self = std::move(self), disposer = RefPtr(aDisposer)] {
if (self->IsGeckoEditableUsed()) {
// Current calling stack uses GeckoEditableChild, so we should
// not dispose it now.
self->mDisposeRunnable = disposer;
return;
}
self->mEditableAttached = false;
disposer->Run();
});
}
// Transfer to a new parent.
void TransferParent(jni::Object::Param aEditableParent);
// Handle an Android KeyEvent.
void OnKeyEvent(int32_t aAction, int32_t aKeyCode, int32_t aScanCode,
int32_t aMetaState, int32_t aKeyPressMetaState, int64_t aTime,
int32_t aDomPrintableKeyValue, int32_t aRepeatCount,
int32_t aFlags, bool aIsSynthesizedImeKey,
jni::Object::Param originalEvent);
// Synchronize Gecko thread with the InputConnection thread.
void OnImeSynchronize();
// Replace a range of text with new text.
void OnImeReplaceText(int32_t aStart, int32_t aEnd, jni::String::Param aText);
// Add styling for a range within the active composition.
void OnImeAddCompositionRange(int32_t aStart, int32_t aEnd,
int32_t aRangeType, int32_t aRangeStyle,
int32_t aRangeLineStyle, bool aRangeBoldLine,
int32_t aRangeForeColor,
int32_t aRangeBackColor,
int32_t aRangeLineColor);
// Update styling for the active composition using previous-added ranges.
void OnImeUpdateComposition(int32_t aStart, int32_t aEnd, int32_t aFlags);
// Set cursor mode whether IME requests
void OnImeRequestCursorUpdates(int aRequestMode);
// Commit current composition to sync Gecko text state with Java.
void OnImeRequestCommit();
};
} // namespace widget
} // namespace mozilla