mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1038089 IMEStateManager should log its behavior r=smaug
This commit is contained in:
parent
e3618bd35b
commit
93d7daf9c6
@ -4,6 +4,8 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "prlog.h"
|
||||
|
||||
#include "mozilla/IMEStateManager.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
@ -36,6 +38,155 @@ namespace mozilla {
|
||||
using namespace dom;
|
||||
using namespace widget;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
/**
|
||||
* When a method is called, log its arguments and/or related static variables
|
||||
* with PR_LOG_ALWAYS. However, if it puts too many logs like
|
||||
* OnDestroyPresContext(), should long only when the method actually does
|
||||
* something. In this case, the log should start with "ISM: <method name>".
|
||||
*
|
||||
* When a method quits due to unexpected situation, log the reason with
|
||||
* PR_LOG_ERROR. In this case, the log should start with
|
||||
* "ISM: <method name>(), FAILED". The indent makes the log look easier.
|
||||
*
|
||||
* When a method does something only in some situations and it may be important
|
||||
* for debug, log the information with PR_LOG_DEBUG. In this case, the log
|
||||
* should start with "ISM: <method name>(),".
|
||||
*/
|
||||
PRLogModuleInfo* sISMLog = nullptr;
|
||||
|
||||
static const char*
|
||||
GetBoolName(bool aBool)
|
||||
{
|
||||
return aBool ? "true" : "false";
|
||||
}
|
||||
|
||||
static const char*
|
||||
GetActionCauseName(InputContextAction::Cause aCause)
|
||||
{
|
||||
switch (aCause) {
|
||||
case InputContextAction::CAUSE_UNKNOWN:
|
||||
return "CAUSE_UNKNOWN";
|
||||
case InputContextAction::CAUSE_UNKNOWN_CHROME:
|
||||
return "CAUSE_UNKNOWN_CHROME";
|
||||
case InputContextAction::CAUSE_KEY:
|
||||
return "CAUSE_KEY";
|
||||
case InputContextAction::CAUSE_MOUSE:
|
||||
return "CAUSE_MOUSE";
|
||||
default:
|
||||
return "illegal value";
|
||||
}
|
||||
}
|
||||
|
||||
static const char*
|
||||
GetActionFocusChangeName(InputContextAction::FocusChange aFocusChange)
|
||||
{
|
||||
switch (aFocusChange) {
|
||||
case InputContextAction::FOCUS_NOT_CHANGED:
|
||||
return "FOCUS_NOT_CHANGED";
|
||||
case InputContextAction::GOT_FOCUS:
|
||||
return "GOT_FOCUS";
|
||||
case InputContextAction::LOST_FOCUS:
|
||||
return "LOST_FOCUS";
|
||||
case InputContextAction::MENU_GOT_PSEUDO_FOCUS:
|
||||
return "MENU_GOT_PSEUDO_FOCUS";
|
||||
case InputContextAction::MENU_LOST_PSEUDO_FOCUS:
|
||||
return "MENU_LOST_PSEUDO_FOCUS";
|
||||
default:
|
||||
return "illegal value";
|
||||
}
|
||||
}
|
||||
|
||||
static const char*
|
||||
GetIMEStateEnabledName(IMEState::Enabled aEnabled)
|
||||
{
|
||||
switch (aEnabled) {
|
||||
case IMEState::DISABLED:
|
||||
return "DISABLED";
|
||||
case IMEState::ENABLED:
|
||||
return "ENABLED";
|
||||
case IMEState::PASSWORD:
|
||||
return "PASSWORD";
|
||||
case IMEState::PLUGIN:
|
||||
return "PLUGIN";
|
||||
default:
|
||||
return "illegal value";
|
||||
}
|
||||
}
|
||||
|
||||
static const char*
|
||||
GetIMEStateSetOpenName(IMEState::Open aOpen)
|
||||
{
|
||||
switch (aOpen) {
|
||||
case IMEState::DONT_CHANGE_OPEN_STATE:
|
||||
return "DONT_CHANGE_OPEN_STATE";
|
||||
case IMEState::OPEN:
|
||||
return "OPEN";
|
||||
case IMEState::CLOSED:
|
||||
return "CLOSED";
|
||||
default:
|
||||
return "illegal value";
|
||||
}
|
||||
}
|
||||
|
||||
static const char*
|
||||
GetEventStructName(nsEventStructType aEventStructType)
|
||||
{
|
||||
switch (aEventStructType) {
|
||||
case NS_COMPOSITION_EVENT:
|
||||
return "NS_COMPOSITION_EVENT";
|
||||
case NS_TEXT_EVENT:
|
||||
return "NS_TEXT_EVENT";
|
||||
default:
|
||||
return "unacceptable event struct type";
|
||||
}
|
||||
}
|
||||
|
||||
static const char*
|
||||
GetEventMessageName(uint32_t aMessage)
|
||||
{
|
||||
switch (aMessage) {
|
||||
case NS_COMPOSITION_START:
|
||||
return "NS_COMPOSITION_START";
|
||||
case NS_COMPOSITION_END:
|
||||
return "NS_COMPOSITION_END";
|
||||
case NS_COMPOSITION_UPDATE:
|
||||
return "NS_COMPOSITION_UPDATE";
|
||||
case NS_TEXT_TEXT:
|
||||
return "NS_TEXT_TEXT";
|
||||
default:
|
||||
return "unacceptable event message";
|
||||
}
|
||||
}
|
||||
|
||||
static const char*
|
||||
GetNotifyIMEMessageName(IMEMessage aMessage)
|
||||
{
|
||||
switch (aMessage) {
|
||||
case NOTIFY_IME_OF_CURSOR_POS_CHANGED:
|
||||
return "NOTIFY_IME_OF_CURSOR_POS_CHANGED";
|
||||
case NOTIFY_IME_OF_FOCUS:
|
||||
return "NOTIFY_IME_OF_FOCUS";
|
||||
case NOTIFY_IME_OF_BLUR:
|
||||
return "NOTIFY_IME_OF_BLUR";
|
||||
case NOTIFY_IME_OF_SELECTION_CHANGE:
|
||||
return "NOTIFY_IME_OF_SELECTION_CHANGE";
|
||||
case NOTIFY_IME_OF_TEXT_CHANGE:
|
||||
return "NOTIFY_IME_OF_TEXT_CHANGE";
|
||||
case NOTIFY_IME_OF_COMPOSITION_UPDATE:
|
||||
return "NOTIFY_IME_OF_COMPOSITION_UPDATE";
|
||||
case NOTIFY_IME_OF_POSITION_CHANGE:
|
||||
return "NOTIFY_IME_OF_POSITION_CHANGE";
|
||||
case REQUEST_TO_COMMIT_COMPOSITION:
|
||||
return "REQUEST_TO_COMMIT_COMPOSITION";
|
||||
case REQUEST_TO_CANCEL_COMPOSITION:
|
||||
return "REQUEST_TO_CANCEL_COMPOSITION";
|
||||
default:
|
||||
return "unacceptable IME notification message";
|
||||
}
|
||||
}
|
||||
#endif // #ifdef PR_LOGGING
|
||||
|
||||
nsIContent* IMEStateManager::sContent = nullptr;
|
||||
nsPresContext* IMEStateManager::sPresContext = nullptr;
|
||||
bool IMEStateManager::sInstalledMenuKeyboardListener = false;
|
||||
@ -46,14 +197,32 @@ bool IMEStateManager::sIsTestingIME = false;
|
||||
IMEContentObserver* IMEStateManager::sActiveIMEContentObserver = nullptr;
|
||||
TextCompositionArray* IMEStateManager::sTextCompositions = nullptr;
|
||||
|
||||
// static
|
||||
void
|
||||
IMEStateManager::Init()
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
if (!sISMLog) {
|
||||
sISMLog = PR_NewLogModule("IMEStateManager");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
IMEStateManager::Shutdown()
|
||||
{
|
||||
PR_LOG(sISMLog, PR_LOG_ALWAYS,
|
||||
("ISM: IMEStateManager::Shutdown(), "
|
||||
"sTextCompositions=0x%p, sTextCompositions->Length()=%u",
|
||||
sTextCompositions, sTextCompositions ? sTextCompositions->Length() : 0));
|
||||
|
||||
MOZ_ASSERT(!sTextCompositions || !sTextCompositions->Length());
|
||||
delete sTextCompositions;
|
||||
sTextCompositions = nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
IMEStateManager::OnDestroyPresContext(nsPresContext* aPresContext)
|
||||
{
|
||||
@ -64,11 +233,21 @@ IMEStateManager::OnDestroyPresContext(nsPresContext* aPresContext)
|
||||
TextCompositionArray::index_type i =
|
||||
sTextCompositions->IndexOf(aPresContext);
|
||||
if (i != TextCompositionArray::NoIndex) {
|
||||
PR_LOG(sISMLog, PR_LOG_DEBUG,
|
||||
("ISM: IMEStateManager::OnDestroyPresContext(), "
|
||||
"removing TextComposition instance from the array (index=%u)", i));
|
||||
// there should be only one composition per presContext object.
|
||||
sTextCompositions->ElementAt(i)->Destroy();
|
||||
sTextCompositions->RemoveElementAt(i);
|
||||
MOZ_ASSERT(sTextCompositions->IndexOf(aPresContext) ==
|
||||
TextCompositionArray::NoIndex);
|
||||
#if defined DEBUG || PR_LOGGING
|
||||
if (sTextCompositions->IndexOf(aPresContext) !=
|
||||
TextCompositionArray::NoIndex) {
|
||||
PR_LOG(sISMLog, PR_LOG_ERROR,
|
||||
("ISM: IMEStateManager::OnDestroyPresContext(), FAILED to remove "
|
||||
"TextComposition instance from the array"));
|
||||
MOZ_CRASH("Failed to remove TextComposition instance from the array");
|
||||
}
|
||||
#endif // #if defined DEBUG || PR_LOGGING
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,7 +255,12 @@ IMEStateManager::OnDestroyPresContext(nsPresContext* aPresContext)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
DestroyTextStateManager();
|
||||
PR_LOG(sISMLog, PR_LOG_ALWAYS,
|
||||
("ISM: IMEStateManager::OnDestroyPresContext(aPresContext=0x%p), "
|
||||
"sPresContext=0x%p, sContent=0x%p, sTextCompositions=0x%p",
|
||||
aPresContext, sPresContext, sContent, sTextCompositions));
|
||||
|
||||
DestroyIMEContentObserver();
|
||||
|
||||
nsCOMPtr<nsIWidget> widget = sPresContext->GetRootWidget();
|
||||
if (widget) {
|
||||
@ -90,6 +274,7 @@ IMEStateManager::OnDestroyPresContext(nsPresContext* aPresContext)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
IMEStateManager::OnRemoveContent(nsPresContext* aPresContext,
|
||||
nsIContent* aContent)
|
||||
@ -102,6 +287,10 @@ IMEStateManager::OnRemoveContent(nsPresContext* aPresContext,
|
||||
sTextCompositions->GetCompositionInContent(aPresContext, aContent);
|
||||
|
||||
if (compositionInContent) {
|
||||
PR_LOG(sISMLog, PR_LOG_DEBUG,
|
||||
("ISM: IMEStateManager::OnRemoveContent(), "
|
||||
"composition is in the content"));
|
||||
|
||||
// Try resetting the native IME state. Be aware, typically, this method
|
||||
// is called during the content being removed. Then, the native
|
||||
// composition events which are caused by following APIs are ignored due
|
||||
@ -124,6 +313,9 @@ IMEStateManager::OnRemoveContent(nsPresContext* aPresContext,
|
||||
// If the compositionInContent is still available, we should finish the
|
||||
// composition just on the content forcibly.
|
||||
if (compositionInContent) {
|
||||
PR_LOG(sISMLog, PR_LOG_DEBUG,
|
||||
("ISM: IMEStateManager::OnRemoveContent(), "
|
||||
"composition in the content still alive, committing it forcibly..."));
|
||||
compositionInContent->SynthesizeCommit(true);
|
||||
}
|
||||
}
|
||||
@ -133,7 +325,12 @@ IMEStateManager::OnRemoveContent(nsPresContext* aPresContext,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
DestroyTextStateManager();
|
||||
PR_LOG(sISMLog, PR_LOG_ALWAYS,
|
||||
("ISM: IMEStateManager::OnRemoveContent(aPresContext=0x%p, "
|
||||
"aContent=0x%p), sPresContext=0x%p, sContent=0x%p, sTextCompositions=0x%p",
|
||||
aPresContext, aContent, sPresContext, sContent, sTextCompositions));
|
||||
|
||||
DestroyIMEContentObserver();
|
||||
|
||||
// Current IME transaction should commit
|
||||
nsCOMPtr<nsIWidget> widget = sPresContext->GetRootWidget();
|
||||
@ -150,20 +347,35 @@ IMEStateManager::OnRemoveContent(nsPresContext* aPresContext,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
IMEStateManager::OnChangeFocus(nsPresContext* aPresContext,
|
||||
nsIContent* aContent,
|
||||
InputContextAction::Cause aCause)
|
||||
{
|
||||
PR_LOG(sISMLog, PR_LOG_ALWAYS,
|
||||
("ISM: IMEStateManager::OnChangeFocus(aPresContext=0x%p, "
|
||||
"aContent=0x%p, aCause=%s)",
|
||||
aPresContext, aContent, GetActionCauseName(aCause)));
|
||||
|
||||
InputContextAction action(aCause);
|
||||
return OnChangeFocusInternal(aPresContext, aContent, action);
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
IMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
|
||||
nsIContent* aContent,
|
||||
InputContextAction aAction)
|
||||
{
|
||||
PR_LOG(sISMLog, PR_LOG_ALWAYS,
|
||||
("ISM: IMEStateManager::OnChangeFocusInternal(aPresContext=0x%p, "
|
||||
"aContent=0x%p, aAction={ mCause=%s, mFocusChange=%s }), "
|
||||
"sPresContext=0x%p, sContent=0x%p, sActiveIMEContentObserver=0x%p",
|
||||
aPresContext, aContent, GetActionCauseName(aAction.mCause),
|
||||
GetActionFocusChangeName(aAction.mFocusChange),
|
||||
sPresContext, sContent, sActiveIMEContentObserver));
|
||||
|
||||
bool focusActuallyChanging =
|
||||
(sContent != aContent || sPresContext != aPresContext);
|
||||
|
||||
@ -180,17 +392,23 @@ IMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
|
||||
if (sActiveIMEContentObserver &&
|
||||
(aPresContext || !sActiveIMEContentObserver->KeepAliveDuringDeactive()) &&
|
||||
!sActiveIMEContentObserver->IsManaging(aPresContext, aContent)) {
|
||||
DestroyTextStateManager();
|
||||
DestroyIMEContentObserver();
|
||||
}
|
||||
|
||||
if (!aPresContext) {
|
||||
PR_LOG(sISMLog, PR_LOG_DEBUG,
|
||||
("ISM: IMEStateManager::OnChangeFocusInternal(), "
|
||||
"no nsPresContext is being activated"));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWidget> widget =
|
||||
(sPresContext == aPresContext) ? oldWidget.get() :
|
||||
aPresContext->GetRootWidget();
|
||||
if (!widget) {
|
||||
if (NS_WARN_IF(!widget)) {
|
||||
PR_LOG(sISMLog, PR_LOG_ERROR,
|
||||
("ISM: IMEStateManager::OnChangeFocusInternal(), FAILED due to "
|
||||
"no widget to manage its IME state"));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -200,7 +418,9 @@ IMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
|
||||
// we should do it.
|
||||
InputContext context = widget->GetInputContext();
|
||||
if (context.mIMEState.mEnabled == newState.mEnabled) {
|
||||
// the enabled state isn't changing.
|
||||
PR_LOG(sISMLog, PR_LOG_DEBUG,
|
||||
("ISM: IMEStateManager::OnChangeFocusInternal(), "
|
||||
"neither focus nor IME state is changing"));
|
||||
return NS_OK;
|
||||
}
|
||||
aAction.mFocusChange = InputContextAction::FOCUS_NOT_CHANGED;
|
||||
@ -233,9 +453,15 @@ IMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
IMEStateManager::OnInstalledMenuKeyboardListener(bool aInstalling)
|
||||
{
|
||||
PR_LOG(sISMLog, PR_LOG_ALWAYS,
|
||||
("ISM: IMEStateManager::OnInstalledMenuKeyboardListener(aInstalling=%s), "
|
||||
"sInstalledMenuKeyboardListener=%s",
|
||||
GetBoolName(aInstalling), GetBoolName(sInstalledMenuKeyboardListener)));
|
||||
|
||||
sInstalledMenuKeyboardListener = aInstalling;
|
||||
|
||||
InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
|
||||
@ -244,12 +470,21 @@ IMEStateManager::OnInstalledMenuKeyboardListener(bool aInstalling)
|
||||
OnChangeFocusInternal(sPresContext, sContent, action);
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
IMEStateManager::OnClickInEditor(nsPresContext* aPresContext,
|
||||
nsIContent* aContent,
|
||||
nsIDOMMouseEvent* aMouseEvent)
|
||||
{
|
||||
PR_LOG(sISMLog, PR_LOG_ALWAYS,
|
||||
("ISM: IMEStateManager::OnClickInEditor(aPresContext=0x%p, aContent=0x%p, "
|
||||
"aMouseEvent=0x%p), sPresContext=0x%p, sContent=0x%p",
|
||||
aPresContext, aContent, aMouseEvent, sPresContext, sContent));
|
||||
|
||||
if (sPresContext != aPresContext || sContent != aContent) {
|
||||
PR_LOG(sISMLog, PR_LOG_DEBUG,
|
||||
("ISM: IMEStateManager::OnClickInEditor(), "
|
||||
"the mouse event isn't fired on the editor managed by ISM"));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -260,6 +495,9 @@ IMEStateManager::OnClickInEditor(nsPresContext* aPresContext,
|
||||
nsresult rv = aMouseEvent->GetIsTrusted(&isTrusted);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
if (!isTrusted) {
|
||||
PR_LOG(sISMLog, PR_LOG_DEBUG,
|
||||
("ISM: IMEStateManager::OnClickInEditor(), "
|
||||
"the mouse event isn't a trusted event"));
|
||||
return; // ignore untrusted event.
|
||||
}
|
||||
|
||||
@ -267,6 +505,9 @@ IMEStateManager::OnClickInEditor(nsPresContext* aPresContext,
|
||||
rv = aMouseEvent->GetButton(&button);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
if (button != 0) {
|
||||
PR_LOG(sISMLog, PR_LOG_DEBUG,
|
||||
("ISM: IMEStateManager::OnClickInEditor(), "
|
||||
"the mouse event isn't a left mouse button event"));
|
||||
return; // not a left click event.
|
||||
}
|
||||
|
||||
@ -274,6 +515,9 @@ IMEStateManager::OnClickInEditor(nsPresContext* aPresContext,
|
||||
rv = aMouseEvent->GetDetail(&clickCount);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
if (clickCount != 1) {
|
||||
PR_LOG(sISMLog, PR_LOG_DEBUG,
|
||||
("ISM: IMEStateManager::OnClickInEditor(), "
|
||||
"the mouse event isn't a single click event"));
|
||||
return; // should notify only first click event.
|
||||
}
|
||||
|
||||
@ -283,11 +527,21 @@ IMEStateManager::OnClickInEditor(nsPresContext* aPresContext,
|
||||
SetIMEState(newState, aContent, widget, action);
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
IMEStateManager::OnFocusInEditor(nsPresContext* aPresContext,
|
||||
nsIContent* aContent)
|
||||
{
|
||||
PR_LOG(sISMLog, PR_LOG_ALWAYS,
|
||||
("ISM: IMEStateManager::OnFocusInEditor(aPresContext=0x%p, aContent=0x%p), "
|
||||
"sPresContext=0x%p, sContent=0x%p, sActiveIMEContentObserver=0x%p",
|
||||
aPresContext, aContent, sPresContext, sContent,
|
||||
sActiveIMEContentObserver));
|
||||
|
||||
if (sPresContext != aPresContext || sContent != aContent) {
|
||||
PR_LOG(sISMLog, PR_LOG_DEBUG,
|
||||
("ISM: IMEStateManager::OnFocusInEditor(), "
|
||||
"an editor not managed by ISM gets focus"));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -295,25 +549,41 @@ IMEStateManager::OnFocusInEditor(nsPresContext* aPresContext,
|
||||
// we need to recreate the instance.
|
||||
if (sActiveIMEContentObserver) {
|
||||
if (sActiveIMEContentObserver->IsManaging(aPresContext, aContent)) {
|
||||
PR_LOG(sISMLog, PR_LOG_DEBUG,
|
||||
("ISM: IMEStateManager::OnFocusInEditor(), "
|
||||
"the editor is already being managed by sActiveIMEContentObserver"));
|
||||
return;
|
||||
}
|
||||
DestroyTextStateManager();
|
||||
DestroyIMEContentObserver();
|
||||
}
|
||||
|
||||
CreateIMEContentObserver();
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
IMEStateManager::UpdateIMEState(const IMEState& aNewIMEState,
|
||||
nsIContent* aContent)
|
||||
{
|
||||
if (!sPresContext) {
|
||||
NS_WARNING("ISM doesn't know which editor has focus");
|
||||
PR_LOG(sISMLog, PR_LOG_ALWAYS,
|
||||
("ISM: IMEStateManager::UpdateIMEState(aNewIMEState={ mEnabled=%s, "
|
||||
"mOpen=%s }, aContent=0x%p), "
|
||||
"sPresContext=0x%p, sContent=0x%p, sActiveIMEContentObserver=0x%p",
|
||||
GetIMEStateEnabledName(aNewIMEState.mEnabled),
|
||||
GetIMEStateSetOpenName(aNewIMEState.mOpen), aContent,
|
||||
sPresContext, sContent, sActiveIMEContentObserver));
|
||||
|
||||
if (NS_WARN_IF(!sPresContext)) {
|
||||
PR_LOG(sISMLog, PR_LOG_ERROR,
|
||||
("ISM: IMEStateManager::UpdateIMEState(), FAILED due to "
|
||||
"no managing nsPresContext"));
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIWidget> widget = sPresContext->GetRootWidget();
|
||||
if (!widget) {
|
||||
NS_WARNING("focused widget is not found");
|
||||
if (NS_WARN_IF(!widget)) {
|
||||
PR_LOG(sISMLog, PR_LOG_ERROR,
|
||||
("ISM: IMEStateManager::UpdateIMEState(), FAILED due to "
|
||||
"no widget for the managing nsPresContext"));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -333,7 +603,7 @@ IMEStateManager::UpdateIMEState(const IMEState& aNewIMEState,
|
||||
}
|
||||
|
||||
if (createTextStateManager) {
|
||||
DestroyTextStateManager();
|
||||
DestroyIMEContentObserver();
|
||||
}
|
||||
|
||||
if (updateIMEState) {
|
||||
@ -347,17 +617,29 @@ IMEStateManager::UpdateIMEState(const IMEState& aNewIMEState,
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
IMEState
|
||||
IMEStateManager::GetNewIMEState(nsPresContext* aPresContext,
|
||||
nsIContent* aContent)
|
||||
{
|
||||
PR_LOG(sISMLog, PR_LOG_ALWAYS,
|
||||
("ISM: IMEStateManager::GetNewIMEState(aPresContext=0x%p, aContent=0x%p), "
|
||||
"sInstalledMenuKeyboardListener=%s",
|
||||
aPresContext, aContent, GetBoolName(sInstalledMenuKeyboardListener)));
|
||||
|
||||
// On Printing or Print Preview, we don't need IME.
|
||||
if (aPresContext->Type() == nsPresContext::eContext_PrintPreview ||
|
||||
aPresContext->Type() == nsPresContext::eContext_Print) {
|
||||
PR_LOG(sISMLog, PR_LOG_DEBUG,
|
||||
("ISM: IMEStateManager::GetNewIMEState() returns DISABLED because "
|
||||
"the nsPresContext is for print or print preview"));
|
||||
return IMEState(IMEState::DISABLED);
|
||||
}
|
||||
|
||||
if (sInstalledMenuKeyboardListener) {
|
||||
PR_LOG(sISMLog, PR_LOG_DEBUG,
|
||||
("ISM: IMEStateManager::GetNewIMEState() returns DISABLED because "
|
||||
"menu keyboard listener was installed"));
|
||||
return IMEState(IMEState::DISABLED);
|
||||
}
|
||||
|
||||
@ -366,12 +648,24 @@ IMEStateManager::GetNewIMEState(nsPresContext* aPresContext,
|
||||
// editable, such case is design mode.
|
||||
nsIDocument* doc = aPresContext->Document();
|
||||
if (doc && doc->HasFlag(NODE_IS_EDITABLE)) {
|
||||
PR_LOG(sISMLog, PR_LOG_DEBUG,
|
||||
("ISM: IMEStateManager::GetNewIMEState() returns ENABLED because "
|
||||
"design mode editor has focus"));
|
||||
return IMEState(IMEState::ENABLED);
|
||||
}
|
||||
PR_LOG(sISMLog, PR_LOG_DEBUG,
|
||||
("ISM: IMEStateManager::GetNewIMEState() returns DISABLED because "
|
||||
"no content has focus"));
|
||||
return IMEState(IMEState::DISABLED);
|
||||
}
|
||||
|
||||
return aContent->GetDesiredIMEState();
|
||||
IMEState newIMEState = aContent->GetDesiredIMEState();
|
||||
PR_LOG(sISMLog, PR_LOG_DEBUG,
|
||||
("ISM: IMEStateManager::GetNewIMEState() returns { mEnabled=%s, "
|
||||
"mOpen=%s }",
|
||||
GetIMEStateEnabledName(newIMEState.mEnabled),
|
||||
GetIMEStateSetOpenName(newIMEState.mOpen)));
|
||||
return newIMEState;
|
||||
}
|
||||
|
||||
// Helper class, used for IME enabled state change notification
|
||||
@ -387,6 +681,9 @@ public:
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
services::GetObserverService();
|
||||
if (observerService) {
|
||||
PR_LOG(sISMLog, PR_LOG_ALWAYS,
|
||||
("ISM: IMEEnabledStateChangedEvent::Run(), notifies observers of "
|
||||
"\"ime-enabled-state-changed\""));
|
||||
nsAutoString state;
|
||||
state.AppendInt(mState);
|
||||
observerService->NotifyObservers(nullptr, "ime-enabled-state-changed",
|
||||
@ -399,12 +696,21 @@ private:
|
||||
uint32_t mState;
|
||||
};
|
||||
|
||||
// static
|
||||
void
|
||||
IMEStateManager::SetIMEState(const IMEState& aState,
|
||||
nsIContent* aContent,
|
||||
nsIWidget* aWidget,
|
||||
InputContextAction aAction)
|
||||
{
|
||||
PR_LOG(sISMLog, PR_LOG_ALWAYS,
|
||||
("ISM: IMEStateManager::SetIMEState(aState={ mEnabled=%s, mOpen=%s }, "
|
||||
"aContent=0x%p, aWidget=0x%p, aAction={ mCause=%s, mFocusChange=%s })",
|
||||
GetIMEStateEnabledName(aState.mEnabled),
|
||||
GetIMEStateSetOpenName(aState.mOpen), aContent, aWidget,
|
||||
GetActionCauseName(aAction.mCause),
|
||||
GetActionFocusChangeName(aAction.mFocusChange)));
|
||||
|
||||
NS_ENSURE_TRUE_VOID(aWidget);
|
||||
|
||||
InputContext oldContext = aWidget->GetInputContext();
|
||||
@ -478,6 +784,20 @@ IMEStateManager::SetIMEState(const IMEState& aState,
|
||||
aAction.mCause = InputContextAction::CAUSE_UNKNOWN_CHROME;
|
||||
}
|
||||
|
||||
|
||||
PR_LOG(sISMLog, PR_LOG_DEBUG,
|
||||
("ISM: IMEStateManager::SetIMEState(), "
|
||||
"calling nsIWidget::SetInputContext(context={ mIMEState={ mEnabled=%s, "
|
||||
"mOpen=%s }, mHTMLInputType=\"%s\", mHTMLInputInputmode=\"%s\", "
|
||||
"mActionHint=\"%s\" }, aAction={ mCause=%s, mAction=%s })",
|
||||
GetIMEStateEnabledName(context.mIMEState.mEnabled),
|
||||
GetIMEStateSetOpenName(context.mIMEState.mOpen),
|
||||
NS_ConvertUTF16toUTF8(context.mHTMLInputType).get(),
|
||||
NS_ConvertUTF16toUTF8(context.mHTMLInputInputmode).get(),
|
||||
NS_ConvertUTF16toUTF8(context.mActionHint).get(),
|
||||
GetActionCauseName(aAction.mCause),
|
||||
GetActionFocusChangeName(aAction.mFocusChange)));
|
||||
|
||||
aWidget->SetInputContext(context, aAction);
|
||||
if (oldContext.mIMEState.mEnabled == context.mIMEState.mEnabled) {
|
||||
return;
|
||||
@ -487,6 +807,7 @@ IMEStateManager::SetIMEState(const IMEState& aState,
|
||||
new IMEEnabledStateChangedEvent(context.mIMEState.mEnabled));
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
IMEStateManager::EnsureTextCompositionArray()
|
||||
{
|
||||
@ -496,6 +817,7 @@ IMEStateManager::EnsureTextCompositionArray()
|
||||
sTextCompositions = new TextCompositionArray();
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
IMEStateManager::DispatchCompositionEvent(nsINode* aEventTargetNode,
|
||||
nsPresContext* aPresContext,
|
||||
@ -503,6 +825,16 @@ IMEStateManager::DispatchCompositionEvent(nsINode* aEventTargetNode,
|
||||
nsEventStatus* aStatus,
|
||||
EventDispatchingCallback* aCallBack)
|
||||
{
|
||||
PR_LOG(sISMLog, PR_LOG_ALWAYS,
|
||||
("ISM: IMEStateManager::DispatchCompositionEvent(aNode=0x%p, "
|
||||
"aPresContext=0x%p, aEvent={ eventStructType=%s, message=%s, "
|
||||
" mFlags={ mIsTrusted=%s, mPropagationStopped=%s } })",
|
||||
aEventTargetNode, aPresContext,
|
||||
GetEventStructName(aEvent->eventStructType),
|
||||
GetEventMessageName(aEvent->message),
|
||||
GetBoolName(aEvent->mFlags.mIsTrusted),
|
||||
GetBoolName(aEvent->mFlags.mPropagationStopped)));
|
||||
|
||||
MOZ_ASSERT(aEvent->eventStructType == NS_COMPOSITION_EVENT ||
|
||||
aEvent->eventStructType == NS_TEXT_EVENT);
|
||||
if (!aEvent->mFlags.mIsTrusted || aEvent->mFlags.mPropagationStopped) {
|
||||
@ -516,6 +848,9 @@ IMEStateManager::DispatchCompositionEvent(nsINode* aEventTargetNode,
|
||||
nsRefPtr<TextComposition> composition =
|
||||
sTextCompositions->GetCompositionFor(GUIEvent->widget);
|
||||
if (!composition) {
|
||||
PR_LOG(sISMLog, PR_LOG_DEBUG,
|
||||
("ISM: IMEStateManager::DispatchCompositionEvent(), "
|
||||
"adding new TextComposition to the array"));
|
||||
MOZ_ASSERT(GUIEvent->message == NS_COMPOSITION_START);
|
||||
composition = new TextComposition(aPresContext, aEventTargetNode, GUIEvent);
|
||||
sTextCompositions->AppendElement(composition);
|
||||
@ -536,6 +871,10 @@ IMEStateManager::DispatchCompositionEvent(nsINode* aEventTargetNode,
|
||||
TextCompositionArray::index_type i =
|
||||
sTextCompositions->IndexOf(GUIEvent->widget);
|
||||
if (i != TextCompositionArray::NoIndex) {
|
||||
PR_LOG(sISMLog, PR_LOG_DEBUG,
|
||||
("ISM: IMEStateManager::DispatchCompositionEvent(), "
|
||||
"removing TextComposition from the array since NS_COMPOSTION_END "
|
||||
"was dispatched"));
|
||||
sTextCompositions->ElementAt(i)->Destroy();
|
||||
sTextCompositions->RemoveElementAt(i);
|
||||
}
|
||||
@ -547,12 +886,23 @@ nsresult
|
||||
IMEStateManager::NotifyIME(IMEMessage aMessage,
|
||||
nsIWidget* aWidget)
|
||||
{
|
||||
NS_ENSURE_TRUE(aWidget, NS_ERROR_INVALID_ARG);
|
||||
|
||||
nsRefPtr<TextComposition> composition;
|
||||
if (sTextCompositions) {
|
||||
if (aWidget && sTextCompositions) {
|
||||
composition = sTextCompositions->GetCompositionFor(aWidget);
|
||||
}
|
||||
|
||||
PR_LOG(sISMLog, PR_LOG_ALWAYS,
|
||||
("ISM: IMEStateManager::NotifyIME(aMessage=%s, aWidget=0x%p), "
|
||||
"composition=0x%p, composition->IsSynthesizedForTests()=%s",
|
||||
GetNotifyIMEMessageName(aMessage), aWidget, composition.get(),
|
||||
GetBoolName(composition ? composition->IsSynthesizedForTests() : false)));
|
||||
|
||||
if (NS_WARN_IF(!aWidget)) {
|
||||
PR_LOG(sISMLog, PR_LOG_ERROR,
|
||||
("ISM: IMEStateManager::NotifyIME(), FAILED due to no widget"));
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!composition || !composition->IsSynthesizedForTests()) {
|
||||
switch (aMessage) {
|
||||
case NOTIFY_IME_OF_CURSOR_POS_CHANGED:
|
||||
@ -634,15 +984,23 @@ nsresult
|
||||
IMEStateManager::NotifyIME(IMEMessage aMessage,
|
||||
nsPresContext* aPresContext)
|
||||
{
|
||||
PR_LOG(sISMLog, PR_LOG_ALWAYS,
|
||||
("ISM: IMEStateManager::NotifyIME(aMessage=%s, aPresContext=0x%p)",
|
||||
GetNotifyIMEMessageName(aMessage), aPresContext));
|
||||
|
||||
NS_ENSURE_TRUE(aPresContext, NS_ERROR_INVALID_ARG);
|
||||
|
||||
nsIWidget* widget = aPresContext->GetRootWidget();
|
||||
if (!widget) {
|
||||
if (NS_WARN_IF(!widget)) {
|
||||
PR_LOG(sISMLog, PR_LOG_ERROR,
|
||||
("ISM: IMEStateManager::NotifyIME(), FAILED due to no widget for the "
|
||||
"nsPresContext"));
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
return NotifyIME(aMessage, widget);
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
IMEStateManager::IsEditable(nsINode* node)
|
||||
{
|
||||
@ -657,6 +1015,7 @@ IMEStateManager::IsEditable(nsINode* node)
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
nsINode*
|
||||
IMEStateManager::GetRootEditableNode(nsPresContext* aPresContext,
|
||||
nsIContent* aContent)
|
||||
@ -679,6 +1038,7 @@ IMEStateManager::GetRootEditableNode(nsPresContext* aPresContext,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
IMEStateManager::IsEditableIMEState(nsIWidget* aWidget)
|
||||
{
|
||||
@ -694,34 +1054,62 @@ IMEStateManager::IsEditableIMEState(nsIWidget* aWidget)
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
IMEStateManager::DestroyTextStateManager()
|
||||
IMEStateManager::DestroyIMEContentObserver()
|
||||
{
|
||||
PR_LOG(sISMLog, PR_LOG_ALWAYS,
|
||||
("ISM: IMEStateManager::DestroyIMEContentObserver(), "
|
||||
"sActiveIMEContentObserver=0x%p",
|
||||
sActiveIMEContentObserver));
|
||||
|
||||
if (!sActiveIMEContentObserver) {
|
||||
PR_LOG(sISMLog, PR_LOG_DEBUG,
|
||||
("ISM: IMEStateManager::DestroyIMEContentObserver() does nothing"));
|
||||
return;
|
||||
}
|
||||
|
||||
PR_LOG(sISMLog, PR_LOG_DEBUG,
|
||||
("ISM: IMEStateManager::DestroyIMEContentObserver(), destroying "
|
||||
"the active IMEContentObserver..."));
|
||||
nsRefPtr<IMEContentObserver> tsm;
|
||||
tsm.swap(sActiveIMEContentObserver);
|
||||
tsm->Destroy();
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
IMEStateManager::CreateIMEContentObserver()
|
||||
{
|
||||
if (sActiveIMEContentObserver) {
|
||||
NS_WARNING("text state observer has been there already");
|
||||
PR_LOG(sISMLog, PR_LOG_ALWAYS,
|
||||
("ISM: IMEStateManager::CreateIMEContentObserver(), "
|
||||
"sPresContext=0x%p, sContent=0x%p, sActiveIMEContentObserver=0x%p, "
|
||||
"sActiveIMEContentObserver->IsManaging(sPresContext, sContent)=%s",
|
||||
sPresContext, sContent, sActiveIMEContentObserver,
|
||||
GetBoolName(sActiveIMEContentObserver ?
|
||||
sActiveIMEContentObserver->IsManaging(sPresContext, sContent) : false)));
|
||||
|
||||
if (NS_WARN_IF(sActiveIMEContentObserver)) {
|
||||
PR_LOG(sISMLog, PR_LOG_ERROR,
|
||||
("ISM: IMEStateManager::CreateIMEContentObserver(), FAILED due to "
|
||||
"there is already an active IMEContentObserver"));
|
||||
MOZ_ASSERT(sActiveIMEContentObserver->IsManaging(sPresContext, sContent));
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWidget> widget = sPresContext->GetRootWidget();
|
||||
if (!widget) {
|
||||
PR_LOG(sISMLog, PR_LOG_ERROR,
|
||||
("ISM: IMEStateManager::CreateIMEContentObserver(), FAILED due to "
|
||||
"there is a root widget for the nsPresContext"));
|
||||
return; // Sometimes, there are no widgets.
|
||||
}
|
||||
|
||||
// If it's not text ediable, we don't need to create IMEContentObserver.
|
||||
if (!IsEditableIMEState(widget)) {
|
||||
PR_LOG(sISMLog, PR_LOG_DEBUG,
|
||||
("ISM: IMEStateManager::CreateIMEContentObserver() doesn't create "
|
||||
"IMEContentObserver because of non-editable IME state"));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -731,6 +1119,9 @@ IMEStateManager::CreateIMEContentObserver()
|
||||
sInitializeIsTestingIME = false;
|
||||
}
|
||||
|
||||
PR_LOG(sISMLog, PR_LOG_DEBUG,
|
||||
("ISM: IMEStateManager::CreateIMEContentObserver() is creating an "
|
||||
"IMEContentObserver instance..."));
|
||||
sActiveIMEContentObserver = new IMEContentObserver();
|
||||
NS_ADDREF(sActiveIMEContentObserver);
|
||||
|
||||
@ -741,6 +1132,7 @@ IMEStateManager::CreateIMEContentObserver()
|
||||
sActiveIMEContentObserver->Init(widget, sPresContext, sContent);
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
IMEStateManager::GetFocusSelectionAndRoot(nsISelection** aSelection,
|
||||
nsIContent** aRootContent)
|
||||
|
@ -37,6 +37,7 @@ class IMEStateManager
|
||||
typedef widget::InputContextAction InputContextAction;
|
||||
|
||||
public:
|
||||
static void Init();
|
||||
static void Shutdown();
|
||||
|
||||
static nsresult OnDestroyPresContext(nsPresContext* aPresContext);
|
||||
@ -135,7 +136,7 @@ protected:
|
||||
|
||||
static void EnsureTextCompositionArray();
|
||||
static void CreateIMEContentObserver();
|
||||
static void DestroyTextStateManager();
|
||||
static void DestroyIMEContentObserver();
|
||||
|
||||
static bool IsEditable(nsINode* node);
|
||||
|
||||
|
@ -298,6 +298,8 @@ nsLayoutStatics::Initialize()
|
||||
|
||||
CameraPreferences::Initialize();
|
||||
|
||||
IMEStateManager::Init();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user