12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * 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 "mozilla/Logging.h"
- #include "mozilla/IMEStateManager.h"
- #include "mozilla/Attributes.h"
- #include "mozilla/EditorBase.h"
- #include "mozilla/EventListenerManager.h"
- #include "mozilla/EventStates.h"
- #include "mozilla/MouseEvents.h"
- #include "mozilla/Preferences.h"
- #include "mozilla/Services.h"
- #include "mozilla/TextComposition.h"
- #include "mozilla/TextEvents.h"
- #include "mozilla/Unused.h"
- #include "mozilla/dom/Event.h"
- #include "mozilla/dom/HTMLFormElement.h"
- #include "mozilla/dom/TabParent.h"
- #include "HTMLInputElement.h"
- #include "IMEContentObserver.h"
- #include "nsCOMPtr.h"
- #include "nsContentUtils.h"
- #include "nsIContent.h"
- #include "nsIDocument.h"
- #include "nsIDOMMouseEvent.h"
- #include "nsIForm.h"
- #include "nsIFormControl.h"
- #include "nsINode.h"
- #include "nsIObserverService.h"
- #include "nsIPresShell.h"
- #include "nsISelection.h"
- #include "nsISupports.h"
- #include "nsPresContext.h"
- namespace mozilla {
- using namespace dom;
- using namespace widget;
- /**
- * When a method is called, log its arguments and/or related static variables
- * with LogLevel::Info. 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 "<method name>".
- *
- * When a method quits due to unexpected situation, log the reason with
- * LogLevel::Error. In this case, the log should start with
- * "<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 LogLevel::Debug. In this case, the log
- * should start with " <method name>(),".
- */
- LazyLogModule sISMLog("IMEStateManager");
- 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";
- case InputContextAction::CAUSE_TOUCH:
- return "CAUSE_TOUCH";
- 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";
- }
- }
- StaticRefPtr<nsIContent> IMEStateManager::sContent;
- StaticRefPtr<nsPresContext> IMEStateManager::sPresContext;
- nsIWidget* IMEStateManager::sWidget = nullptr;
- nsIWidget* IMEStateManager::sFocusedIMEWidget = nullptr;
- nsIWidget* IMEStateManager::sActiveInputContextWidget = nullptr;
- StaticRefPtr<TabParent> IMEStateManager::sActiveTabParent;
- StaticRefPtr<IMEContentObserver> IMEStateManager::sActiveIMEContentObserver;
- TextCompositionArray* IMEStateManager::sTextCompositions = nullptr;
- bool IMEStateManager::sInstalledMenuKeyboardListener = false;
- bool IMEStateManager::sIsGettingNewIMEState = false;
- bool IMEStateManager::sCheckForIMEUnawareWebApps = false;
- bool IMEStateManager::sRemoteHasFocus = false;
- // static
- void
- IMEStateManager::Init()
- {
- Preferences::AddBoolVarCache(
- &sCheckForIMEUnawareWebApps,
- "intl.ime.hack.on_ime_unaware_apps.fire_key_events_for_composition",
- false);
- }
- // static
- void
- IMEStateManager::Shutdown()
- {
- MOZ_LOG(sISMLog, LogLevel::Info,
- ("Shutdown(), sTextCompositions=0x%p, sTextCompositions->Length()=%u",
- sTextCompositions, sTextCompositions ? sTextCompositions->Length() : 0));
- MOZ_ASSERT(!sTextCompositions || !sTextCompositions->Length());
- delete sTextCompositions;
- sTextCompositions = nullptr;
- }
- // static
- void
- IMEStateManager::OnTabParentDestroying(TabParent* aTabParent)
- {
- if (sActiveTabParent != aTabParent) {
- return;
- }
- MOZ_LOG(sISMLog, LogLevel::Info,
- ("OnTabParentDestroying(aTabParent=0x%p), "
- "The active TabParent is being destroyed", aTabParent));
- // The active remote process might have crashed.
- sActiveTabParent = nullptr;
- // TODO: Need to cancel composition without TextComposition and make
- // disable IME.
- }
- // static
- void
- IMEStateManager::WidgetDestroyed(nsIWidget* aWidget)
- {
- if (sWidget == aWidget) {
- sWidget = nullptr;
- }
- if (sFocusedIMEWidget == aWidget) {
- sFocusedIMEWidget = nullptr;
- }
- if (sActiveInputContextWidget == aWidget) {
- sActiveInputContextWidget = nullptr;
- }
- }
- // static
- void
- IMEStateManager::StopIMEStateManagement()
- {
- MOZ_LOG(sISMLog, LogLevel::Info,
- ("StopIMEStateManagement()"));
- // NOTE: Don't set input context from here since this has already lost
- // the rights to change input context.
- if (sTextCompositions && sPresContext) {
- NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, sPresContext);
- }
- sActiveInputContextWidget = nullptr;
- sPresContext = nullptr;
- sContent = nullptr;
- sActiveTabParent = nullptr;
- DestroyIMEContentObserver();
- }
- // static
- void
- IMEStateManager::MaybeStartOffsetUpdatedInChild(nsIWidget* aWidget,
- uint32_t aStartOffset)
- {
- if (NS_WARN_IF(!sTextCompositions)) {
- MOZ_LOG(sISMLog, LogLevel::Warning,
- ("MaybeStartOffsetUpdatedInChild(aWidget=0x%p, aStartOffset=%u), "
- "called when there is no composition", aWidget, aStartOffset));
- return;
- }
- RefPtr<TextComposition> composition = GetTextCompositionFor(aWidget);
- if (NS_WARN_IF(!composition)) {
- MOZ_LOG(sISMLog, LogLevel::Warning,
- ("MaybeStartOffsetUpdatedInChild(aWidget=0x%p, aStartOffset=%u), "
- "called when there is no composition", aWidget, aStartOffset));
- return;
- }
- if (composition->NativeOffsetOfStartComposition() == aStartOffset) {
- return;
- }
- MOZ_LOG(sISMLog, LogLevel::Info,
- ("MaybeStartOffsetUpdatedInChild(aWidget=0x%p, aStartOffset=%u), "
- "old offset=%u",
- aWidget, aStartOffset, composition->NativeOffsetOfStartComposition()));
- composition->OnStartOffsetUpdatedInChild(aStartOffset);
- }
- // static
- nsresult
- IMEStateManager::OnDestroyPresContext(nsPresContext* aPresContext)
- {
- NS_ENSURE_ARG_POINTER(aPresContext);
- // First, if there is a composition in the aPresContext, clean up it.
- if (sTextCompositions) {
- TextCompositionArray::index_type i =
- sTextCompositions->IndexOf(aPresContext);
- if (i != TextCompositionArray::NoIndex) {
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" 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);
- if (sTextCompositions->IndexOf(aPresContext) !=
- TextCompositionArray::NoIndex) {
- MOZ_LOG(sISMLog, LogLevel::Error,
- (" OnDestroyPresContext(), FAILED to remove "
- "TextComposition instance from the array"));
- MOZ_CRASH("Failed to remove TextComposition instance from the array");
- }
- }
- }
- if (aPresContext != sPresContext) {
- return NS_OK;
- }
- MOZ_LOG(sISMLog, LogLevel::Info,
- ("OnDestroyPresContext(aPresContext=0x%p), "
- "sPresContext=0x%p, sContent=0x%p, sTextCompositions=0x%p",
- aPresContext, sPresContext.get(), sContent.get(), sTextCompositions));
- DestroyIMEContentObserver();
- if (sWidget) {
- IMEState newState = GetNewIMEState(sPresContext, nullptr);
- InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
- InputContextAction::LOST_FOCUS);
- SetIMEState(newState, nullptr, nullptr, sWidget, action);
- }
- sWidget = nullptr;
- sContent = nullptr;
- sPresContext = nullptr;
- sActiveTabParent = nullptr;
- return NS_OK;
- }
- // static
- nsresult
- IMEStateManager::OnRemoveContent(nsPresContext* aPresContext,
- nsIContent* aContent)
- {
- NS_ENSURE_ARG_POINTER(aPresContext);
- // First, if there is a composition in the aContent, clean up it.
- if (sTextCompositions) {
- RefPtr<TextComposition> compositionInContent =
- sTextCompositions->GetCompositionInContent(aPresContext, aContent);
- if (compositionInContent) {
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" 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
- // to unsafe to run script (in PresShell::HandleEvent()).
- nsresult rv =
- compositionInContent->NotifyIME(REQUEST_TO_CANCEL_COMPOSITION);
- if (NS_FAILED(rv)) {
- compositionInContent->NotifyIME(REQUEST_TO_COMMIT_COMPOSITION);
- }
- }
- }
- if (!sPresContext || !sContent ||
- !nsContentUtils::ContentIsDescendantOf(sContent, aContent)) {
- return NS_OK;
- }
- MOZ_LOG(sISMLog, LogLevel::Info,
- ("OnRemoveContent(aPresContext=0x%p, aContent=0x%p), "
- "sPresContext=0x%p, sContent=0x%p, sTextCompositions=0x%p",
- aPresContext, aContent, sPresContext.get(), sContent.get(), sTextCompositions));
- DestroyIMEContentObserver();
- // Current IME transaction should commit
- if (sWidget) {
- IMEState newState = GetNewIMEState(sPresContext, nullptr);
- InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
- InputContextAction::LOST_FOCUS);
- SetIMEState(newState, aPresContext, nullptr, sWidget, action);
- }
- sWidget = nullptr;
- sContent = nullptr;
- sPresContext = nullptr;
- sActiveTabParent = nullptr;
- return NS_OK;
- }
- // static
- bool
- IMEStateManager::CanHandleWith(nsPresContext* aPresContext)
- {
- return aPresContext &&
- aPresContext->GetPresShell() &&
- !aPresContext->PresShell()->IsDestroying();
- }
- // static
- nsresult
- IMEStateManager::OnChangeFocus(nsPresContext* aPresContext,
- nsIContent* aContent,
- InputContextAction::Cause aCause)
- {
- MOZ_LOG(sISMLog, LogLevel::Info,
- ("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)
- {
- RefPtr<TabParent> newTabParent = TabParent::GetFrom(aContent);
- MOZ_LOG(sISMLog, LogLevel::Info,
- ("OnChangeFocusInternal(aPresContext=0x%p (available: %s), "
- "aContent=0x%p (TabParent=0x%p), aAction={ mCause=%s, mFocusChange=%s }), "
- "sPresContext=0x%p (available: %s), sContent=0x%p, "
- "sWidget=0x%p (available: %s), sActiveTabParent=0x%p, "
- "sActiveIMEContentObserver=0x%p, sInstalledMenuKeyboardListener=%s",
- aPresContext, GetBoolName(CanHandleWith(aPresContext)), aContent,
- newTabParent.get(), GetActionCauseName(aAction.mCause),
- GetActionFocusChangeName(aAction.mFocusChange),
- sPresContext.get(), GetBoolName(CanHandleWith(sPresContext)),
- sContent.get(), sWidget, GetBoolName(sWidget && !sWidget->Destroyed()),
- sActiveTabParent.get(), sActiveIMEContentObserver.get(),
- GetBoolName(sInstalledMenuKeyboardListener)));
- // If new aPresShell has been destroyed, this should handle the focus change
- // as nobody is getting focus.
- if (NS_WARN_IF(aPresContext && !CanHandleWith(aPresContext))) {
- MOZ_LOG(sISMLog, LogLevel::Warning,
- (" OnChangeFocusInternal(), called with destroyed PresShell, "
- "handling this call as nobody getting focus"));
- aPresContext = nullptr;
- aContent = nullptr;
- }
- nsCOMPtr<nsIWidget> oldWidget = sWidget;
- nsCOMPtr<nsIWidget> newWidget =
- aPresContext ? aPresContext->GetRootWidget() : nullptr;
- bool focusActuallyChanging =
- (sContent != aContent || sPresContext != aPresContext ||
- oldWidget != newWidget || sActiveTabParent != newTabParent);
- if (oldWidget && focusActuallyChanging) {
- // If we're deactivating, we shouldn't commit composition forcibly because
- // the user may want to continue the composition.
- if (aPresContext) {
- NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, oldWidget);
- }
- }
- if (sActiveIMEContentObserver &&
- (aPresContext || !sActiveIMEContentObserver->KeepAliveDuringDeactive()) &&
- !sActiveIMEContentObserver->IsManaging(aPresContext, aContent)) {
- DestroyIMEContentObserver();
- }
- if (!aPresContext) {
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" OnChangeFocusInternal(), "
- "no nsPresContext is being activated"));
- return NS_OK;
- }
- nsIContentParent* currentContentParent =
- sActiveTabParent ? sActiveTabParent->Manager() : nullptr;
- nsIContentParent* newContentParent =
- newTabParent ? newTabParent->Manager() : nullptr;
- if (sActiveTabParent && currentContentParent != newContentParent) {
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" OnChangeFocusInternal(), notifying previous "
- "focused child process of parent process or another child process "
- "getting focus"));
- Unused << sActiveTabParent->SendStopIMEStateManagement();
- }
- if (NS_WARN_IF(!newWidget)) {
- MOZ_LOG(sISMLog, LogLevel::Error,
- (" OnChangeFocusInternal(), FAILED due to "
- "no widget to manage its IME state"));
- return NS_OK;
- }
- // Update the cached widget since root view of the presContext may be
- // changed to different view.
- sWidget = newWidget;
- // If a child process has focus, we should disable IME state until the child
- // process actually gets focus because if user types keys before that they
- // are handled by IME.
- IMEState newState =
- newTabParent ? IMEState(IMEState::DISABLED) :
- GetNewIMEState(aPresContext, aContent);
- bool setIMEState = true;
- if (newTabParent) {
- if (aAction.mFocusChange == InputContextAction::MENU_GOT_PSEUDO_FOCUS ||
- aAction.mFocusChange == InputContextAction::MENU_LOST_PSEUDO_FOCUS) {
- // XXX When menu keyboard listener is being uninstalled, IME state needs
- // to be restored by the child process asynchronously. Therefore,
- // some key events which are fired immediately after closing menu
- // may not be handled by IME.
- Unused << newTabParent->
- SendMenuKeyboardListenerInstalled(sInstalledMenuKeyboardListener);
- setIMEState = sInstalledMenuKeyboardListener;
- } else if (focusActuallyChanging) {
- InputContext context = newWidget->GetInputContext();
- if (context.mIMEState.mEnabled == IMEState::DISABLED) {
- setIMEState = false;
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" OnChangeFocusInternal(), doesn't set IME "
- "state because focused element (or document) is in a child process "
- "and the IME state is already disabled"));
- } else {
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" OnChangeFocusInternal(), will disable IME "
- "until new focused element (or document) in the child process "
- "will get focus actually"));
- }
- } else {
- // When focus is NOT changed actually, we shouldn't set IME state since
- // that means that the window is being activated and the child process
- // may have composition. Then, we shouldn't commit the composition with
- // making IME state disabled.
- setIMEState = false;
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" OnChangeFocusInternal(), doesn't set IME "
- "state because focused element (or document) is already in the child "
- "process"));
- }
- }
- if (setIMEState) {
- if (!focusActuallyChanging) {
- // actual focus isn't changing, but if IME enabled state is changing,
- // we should do it.
- InputContext context = newWidget->GetInputContext();
- if (context.mIMEState.mEnabled == newState.mEnabled) {
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" OnChangeFocusInternal(), "
- "neither focus nor IME state is changing"));
- return NS_OK;
- }
- aAction.mFocusChange = InputContextAction::FOCUS_NOT_CHANGED;
- // Even if focus isn't changing actually, we should commit current
- // composition here since the IME state is changing.
- if (sPresContext && oldWidget && !focusActuallyChanging) {
- NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, oldWidget);
- }
- } else if (aAction.mFocusChange == InputContextAction::FOCUS_NOT_CHANGED) {
- // If aContent isn't null or aContent is null but editable, somebody gets
- // focus.
- bool gotFocus = aContent || (newState.mEnabled == IMEState::ENABLED);
- aAction.mFocusChange =
- gotFocus ? InputContextAction::GOT_FOCUS :
- InputContextAction::LOST_FOCUS;
- }
- // Update IME state for new focus widget
- SetIMEState(newState, aPresContext, aContent, newWidget, aAction);
- }
- sActiveTabParent = newTabParent;
- sPresContext = aPresContext;
- sContent = aContent;
- // Don't call CreateIMEContentObserver() here except when a plugin gets
- // focus because it will be called from the focus event handler of focused
- // editor.
- if (newState.mEnabled == IMEState::PLUGIN) {
- CreateIMEContentObserver(nullptr);
- if (sActiveIMEContentObserver) {
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" OnChangeFocusInternal(), an "
- "IMEContentObserver instance is created for plugin and trying to "
- "flush its pending notifications..."));
- sActiveIMEContentObserver->TryToFlushPendingNotifications();
- }
- }
- return NS_OK;
- }
- // static
- void
- IMEStateManager::OnInstalledMenuKeyboardListener(bool aInstalling)
- {
- MOZ_LOG(sISMLog, LogLevel::Info,
- ("OnInstalledMenuKeyboardListener(aInstalling=%s), "
- "sInstalledMenuKeyboardListener=%s",
- GetBoolName(aInstalling), GetBoolName(sInstalledMenuKeyboardListener)));
- sInstalledMenuKeyboardListener = aInstalling;
- InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
- aInstalling ? InputContextAction::MENU_GOT_PSEUDO_FOCUS :
- InputContextAction::MENU_LOST_PSEUDO_FOCUS);
- OnChangeFocusInternal(sPresContext, sContent, action);
- }
- // static
- bool
- IMEStateManager::OnMouseButtonEventInEditor(nsPresContext* aPresContext,
- nsIContent* aContent,
- nsIDOMMouseEvent* aMouseEvent)
- {
- MOZ_LOG(sISMLog, LogLevel::Info,
- ("OnMouseButtonEventInEditor(aPresContext=0x%p, "
- "aContent=0x%p, aMouseEvent=0x%p), sPresContext=0x%p, sContent=0x%p",
- aPresContext, aContent, aMouseEvent, sPresContext.get(), sContent.get()));
- if (sPresContext != aPresContext || sContent != aContent) {
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" OnMouseButtonEventInEditor(), "
- "the mouse event isn't fired on the editor managed by ISM"));
- return false;
- }
- if (!sActiveIMEContentObserver) {
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" OnMouseButtonEventInEditor(), "
- "there is no active IMEContentObserver"));
- return false;
- }
- if (!sActiveIMEContentObserver->IsManaging(aPresContext, aContent)) {
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" OnMouseButtonEventInEditor(), "
- "the active IMEContentObserver isn't managing the editor"));
- return false;
- }
- WidgetMouseEvent* internalEvent =
- aMouseEvent->AsEvent()->WidgetEventPtr()->AsMouseEvent();
- if (NS_WARN_IF(!internalEvent)) {
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" OnMouseButtonEventInEditor(), "
- "the internal event of aMouseEvent isn't WidgetMouseEvent"));
- return false;
- }
- bool consumed =
- sActiveIMEContentObserver->OnMouseButtonEvent(aPresContext, internalEvent);
- if (MOZ_LOG_TEST(sISMLog, LogLevel::Info)) {
- nsAutoString eventType;
- aMouseEvent->AsEvent()->GetType(eventType);
- MOZ_LOG(sISMLog, LogLevel::Info,
- (" OnMouseButtonEventInEditor(), "
- "mouse event (type=%s, button=%d) is %s",
- NS_ConvertUTF16toUTF8(eventType).get(), internalEvent->button,
- consumed ? "consumed" : "not consumed"));
- }
- return consumed;
- }
- // static
- void
- IMEStateManager::OnClickInEditor(nsPresContext* aPresContext,
- nsIContent* aContent,
- nsIDOMMouseEvent* aMouseEvent)
- {
- MOZ_LOG(sISMLog, LogLevel::Info,
- ("OnClickInEditor(aPresContext=0x%p, aContent=0x%p, aMouseEvent=0x%p), "
- "sPresContext=0x%p, sContent=0x%p, sWidget=0x%p (available: %s)",
- aPresContext, aContent, aMouseEvent, sPresContext.get(), sContent.get(),
- sWidget, GetBoolName(sWidget && !sWidget->Destroyed())));
- if (sPresContext != aPresContext || sContent != aContent ||
- NS_WARN_IF(!sPresContext) || NS_WARN_IF(!sWidget) ||
- NS_WARN_IF(sWidget->Destroyed())) {
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" OnClickInEditor(), "
- "the mouse event isn't fired on the editor managed by ISM"));
- return;
- }
- nsCOMPtr<nsIWidget> widget(sWidget);
- MOZ_ASSERT(!sPresContext->GetRootWidget() ||
- sPresContext->GetRootWidget() == widget);
- bool isTrusted;
- nsresult rv = aMouseEvent->AsEvent()->GetIsTrusted(&isTrusted);
- NS_ENSURE_SUCCESS_VOID(rv);
- if (!isTrusted) {
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" OnClickInEditor(), "
- "the mouse event isn't a trusted event"));
- return; // ignore untrusted event.
- }
- int16_t button;
- rv = aMouseEvent->GetButton(&button);
- NS_ENSURE_SUCCESS_VOID(rv);
- if (button != 0) {
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" OnClickInEditor(), "
- "the mouse event isn't a left mouse button event"));
- return; // not a left click event.
- }
- int32_t clickCount;
- rv = aMouseEvent->GetDetail(&clickCount);
- NS_ENSURE_SUCCESS_VOID(rv);
- if (clickCount != 1) {
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" OnClickInEditor(), "
- "the mouse event isn't a single click event"));
- return; // should notify only first click event.
- }
- uint16_t inputSource = nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
- aMouseEvent->GetMozInputSource(&inputSource);
- InputContextAction::Cause cause =
- inputSource == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH ?
- InputContextAction::CAUSE_TOUCH : InputContextAction::CAUSE_MOUSE;
- InputContextAction action(cause, InputContextAction::FOCUS_NOT_CHANGED);
- IMEState newState = GetNewIMEState(aPresContext, aContent);
- SetIMEState(newState, aPresContext, aContent, widget, action);
- }
- // static
- void
- IMEStateManager::OnFocusInEditor(nsPresContext* aPresContext,
- nsIContent* aContent,
- nsIEditor* aEditor)
- {
- MOZ_LOG(sISMLog, LogLevel::Info,
- ("OnFocusInEditor(aPresContext=0x%p, aContent=0x%p, aEditor=0x%p), "
- "sPresContext=0x%p, sContent=0x%p, sActiveIMEContentObserver=0x%p",
- aPresContext, aContent, aEditor, sPresContext.get(), sContent.get(),
- sActiveIMEContentObserver.get()));
- if (sPresContext != aPresContext || sContent != aContent) {
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" OnFocusInEditor(), "
- "an editor not managed by ISM gets focus"));
- return;
- }
- // If the IMEContentObserver instance isn't managing the editor actually,
- // we need to recreate the instance.
- if (sActiveIMEContentObserver) {
- if (sActiveIMEContentObserver->IsManaging(aPresContext, aContent)) {
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" OnFocusInEditor(), "
- "the editor is already being managed by sActiveIMEContentObserver"));
- return;
- }
- DestroyIMEContentObserver();
- }
- CreateIMEContentObserver(aEditor);
- // Let's flush the focus notification now.
- if (sActiveIMEContentObserver) {
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" OnFocusInEditor(), new IMEContentObserver is "
- "created, trying to flush pending notifications..."));
- sActiveIMEContentObserver->TryToFlushPendingNotifications();
- }
- }
- // static
- void
- IMEStateManager::OnEditorInitialized(nsIEditor* aEditor)
- {
- if (!sActiveIMEContentObserver ||
- sActiveIMEContentObserver->GetEditor() != aEditor) {
- return;
- }
- MOZ_LOG(sISMLog, LogLevel::Info,
- ("OnEditorInitialized(aEditor=0x%p)",
- aEditor));
- sActiveIMEContentObserver->UnsuppressNotifyingIME();
- }
- // static
- void
- IMEStateManager::OnEditorDestroying(nsIEditor* aEditor)
- {
- if (!sActiveIMEContentObserver ||
- sActiveIMEContentObserver->GetEditor() != aEditor) {
- return;
- }
- MOZ_LOG(sISMLog, LogLevel::Info,
- ("OnEditorDestroying(aEditor=0x%p)",
- aEditor));
- // The IMEContentObserver shouldn't notify IME of anything until reframing
- // is finished.
- sActiveIMEContentObserver->SuppressNotifyingIME();
- }
- // static
- void
- IMEStateManager::UpdateIMEState(const IMEState& aNewIMEState,
- nsIContent* aContent,
- EditorBase& aEditorBase)
- {
- MOZ_LOG(sISMLog, LogLevel::Info,
- ("UpdateIMEState(aNewIMEState={ mEnabled=%s, "
- "mOpen=%s }, aContent=0x%p, aEditorBase=0x%p), "
- "sPresContext=0x%p, sContent=0x%p, sWidget=0x%p (available: %s), "
- "sActiveIMEContentObserver=0x%p, sIsGettingNewIMEState=%s",
- GetIMEStateEnabledName(aNewIMEState.mEnabled),
- GetIMEStateSetOpenName(aNewIMEState.mOpen), aContent, &aEditorBase,
- sPresContext.get(), sContent.get(),
- sWidget, GetBoolName(sWidget && !sWidget->Destroyed()),
- sActiveIMEContentObserver.get(),
- GetBoolName(sIsGettingNewIMEState)));
- if (sIsGettingNewIMEState) {
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" UpdateIMEState(), "
- "does nothing because of called while getting new IME state"));
- return;
- }
- nsCOMPtr<nsIPresShell> presShell = aEditorBase.GetPresShell();
- if (NS_WARN_IF(!presShell)) {
- MOZ_LOG(sISMLog, LogLevel::Error,
- (" UpdateIMEState(), FAILED due to "
- "editor doesn't have PresShell"));
- return;
- }
- nsPresContext* presContext = presShell->GetPresContext();
- if (NS_WARN_IF(!presContext)) {
- MOZ_LOG(sISMLog, LogLevel::Error,
- (" UpdateIMEState(), FAILED due to "
- "editor doesn't have PresContext"));
- return;
- }
- // IMEStateManager::UpdateIMEState() should be called after
- // IMEStateManager::OnChangeFocus() is called for setting focus to aContent
- // and aEditorBase. However, when aEditorBase is an HTMLEditor, this may be
- // called by nsIEditor::PostCreate() before IMEStateManager::OnChangeFocus().
- // Similarly, when aEditorBase is a TextEditor, this may be called by
- // nsIEditor::SetFlags(). In such cases, this method should do nothing
- // because input context should be updated when
- // IMEStateManager::OnChangeFocus() is called later.
- if (sPresContext != presContext) {
- MOZ_LOG(sISMLog, LogLevel::Warning,
- (" UpdateIMEState(), does nothing due to "
- "the editor hasn't managed by IMEStateManager yet"));
- return;
- }
- // If IMEStateManager doesn't manage any document, this cannot update IME
- // state of any widget.
- if (NS_WARN_IF(!sPresContext)) {
- MOZ_LOG(sISMLog, LogLevel::Error,
- (" UpdateIMEState(), FAILED due to "
- "no managing nsPresContext"));
- return;
- }
- if (NS_WARN_IF(!sWidget) || NS_WARN_IF(sWidget->Destroyed())) {
- MOZ_LOG(sISMLog, LogLevel::Error,
- (" UpdateIMEState(), FAILED due to "
- "the widget for the managing nsPresContext has gone"));
- return;
- }
- nsCOMPtr<nsIWidget> widget(sWidget);
- MOZ_ASSERT(!sPresContext->GetRootWidget() ||
- sPresContext->GetRootWidget() == widget);
- // Even if there is active IMEContentObserver, it may not be observing the
- // editor with current editable root content due to reframed. In such case,
- // We should try to reinitialize the IMEContentObserver.
- if (sActiveIMEContentObserver && IsIMEObserverNeeded(aNewIMEState)) {
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" UpdateIMEState(), try to reinitialize the "
- "active IMEContentObserver"));
- if (!sActiveIMEContentObserver->MaybeReinitialize(widget, sPresContext,
- aContent, &aEditorBase)) {
- MOZ_LOG(sISMLog, LogLevel::Error,
- (" UpdateIMEState(), failed to reinitialize the "
- "active IMEContentObserver"));
- }
- if (NS_WARN_IF(widget->Destroyed())) {
- MOZ_LOG(sISMLog, LogLevel::Error,
- (" UpdateIMEState(), widget has gone during reinitializing the "
- "active IMEContentObserver"));
- return;
- }
- }
- // If there is no active IMEContentObserver or it isn't observing the
- // editor correctly, we should recreate it.
- bool createTextStateManager =
- (!sActiveIMEContentObserver ||
- !sActiveIMEContentObserver->IsManaging(sPresContext, aContent));
- bool updateIMEState =
- (widget->GetInputContext().mIMEState.mEnabled != aNewIMEState.mEnabled);
- if (NS_WARN_IF(widget->Destroyed())) {
- MOZ_LOG(sISMLog, LogLevel::Error,
- (" UpdateIMEState(), widget has gone during getting input context"));
- return;
- }
- if (updateIMEState) {
- // commit current composition before modifying IME state.
- NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, widget);
- if (NS_WARN_IF(widget->Destroyed())) {
- MOZ_LOG(sISMLog, LogLevel::Error,
- (" UpdateIMEState(), widget has gone during committing composition"));
- return;
- }
- }
- if (createTextStateManager) {
- DestroyIMEContentObserver();
- }
- if (updateIMEState) {
- InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
- InputContextAction::FOCUS_NOT_CHANGED);
- SetIMEState(aNewIMEState, sPresContext, aContent, widget, action);
- if (NS_WARN_IF(widget->Destroyed())) {
- MOZ_LOG(sISMLog, LogLevel::Error,
- (" UpdateIMEState(), widget has gone during setting input context"));
- return;
- }
- }
- if (createTextStateManager) {
- // XXX In this case, it might not be enough safe to notify IME of anything.
- // So, don't try to flush pending notifications of IMEContentObserver
- // here.
- CreateIMEContentObserver(&aEditorBase);
- }
- }
- // static
- IMEState
- IMEStateManager::GetNewIMEState(nsPresContext* aPresContext,
- nsIContent* aContent)
- {
- MOZ_LOG(sISMLog, LogLevel::Info,
- ("GetNewIMEState(aPresContext=0x%p, aContent=0x%p), "
- "sInstalledMenuKeyboardListener=%s",
- aPresContext, aContent, GetBoolName(sInstalledMenuKeyboardListener)));
- if (!CanHandleWith(aPresContext)) {
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" GetNewIMEState() returns DISABLED because "
- "the nsPresContext has been destroyed"));
- return IMEState(IMEState::DISABLED);
- }
- // On Printing or Print Preview, we don't need IME.
- if (aPresContext->Type() == nsPresContext::eContext_PrintPreview ||
- aPresContext->Type() == nsPresContext::eContext_Print) {
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" GetNewIMEState() returns DISABLED because "
- "the nsPresContext is for print or print preview"));
- return IMEState(IMEState::DISABLED);
- }
- if (sInstalledMenuKeyboardListener) {
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" GetNewIMEState() returns DISABLED because "
- "menu keyboard listener was installed"));
- return IMEState(IMEState::DISABLED);
- }
- if (!aContent) {
- // Even if there are no focused content, the focused document might be
- // editable, such case is design mode.
- nsIDocument* doc = aPresContext->Document();
- if (doc && doc->HasFlag(NODE_IS_EDITABLE)) {
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" GetNewIMEState() returns ENABLED because "
- "design mode editor has focus"));
- return IMEState(IMEState::ENABLED);
- }
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" GetNewIMEState() returns DISABLED because "
- "no content has focus"));
- return IMEState(IMEState::DISABLED);
- }
- // nsIContent::GetDesiredIMEState() may cause a call of UpdateIMEState()
- // from EditorBase::PostCreate() because GetDesiredIMEState() needs to
- // retrieve an editor instance for the element if it's editable element.
- // For avoiding such nested IME state updates, we should set
- // sIsGettingNewIMEState here and UpdateIMEState() should check it.
- GettingNewIMEStateBlocker blocker;
- IMEState newIMEState = aContent->GetDesiredIMEState();
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" GetNewIMEState() returns { mEnabled=%s, "
- "mOpen=%s }",
- GetIMEStateEnabledName(newIMEState.mEnabled),
- GetIMEStateSetOpenName(newIMEState.mOpen)));
- return newIMEState;
- }
- static bool
- MayBeIMEUnawareWebApp(nsINode* aNode)
- {
- bool haveKeyEventsListener = false;
- while (aNode) {
- EventListenerManager* const mgr = aNode->GetExistingListenerManager();
- if (mgr) {
- if (mgr->MayHaveInputOrCompositionEventListener()) {
- return false;
- }
- haveKeyEventsListener |= mgr->MayHaveKeyEventListener();
- }
- aNode = aNode->GetParentNode();
- }
- return haveKeyEventsListener;
- }
- // static
- void
- IMEStateManager::SetInputContextForChildProcess(
- TabParent* aTabParent,
- const InputContext& aInputContext,
- const InputContextAction& aAction)
- {
- MOZ_LOG(sISMLog, LogLevel::Info,
- ("SetInputContextForChildProcess(aTabParent=0x%p, "
- "aInputContext={ mIMEState={ mEnabled=%s, mOpen=%s }, "
- "mHTMLInputType=\"%s\", mHTMLInputInputmode=\"%s\", mActionHint=\"%s\", "
- "mInPrivateBrowsing=%s }, aAction={ mCause=%s, mAction=%s }), "
- "sPresContext=0x%p (available: %s), sWidget=0x%p (available: %s), "
- "sActiveTabParent=0x%p",
- aTabParent, GetIMEStateEnabledName(aInputContext.mIMEState.mEnabled),
- GetIMEStateSetOpenName(aInputContext.mIMEState.mOpen),
- NS_ConvertUTF16toUTF8(aInputContext.mHTMLInputType).get(),
- NS_ConvertUTF16toUTF8(aInputContext.mHTMLInputInputmode).get(),
- NS_ConvertUTF16toUTF8(aInputContext.mActionHint).get(),
- GetBoolName(aInputContext.mInPrivateBrowsing),
- GetActionCauseName(aAction.mCause),
- GetActionFocusChangeName(aAction.mFocusChange),
- sPresContext.get(), GetBoolName(CanHandleWith(sPresContext)),
- sWidget, GetBoolName(sWidget && !sWidget->Destroyed()),
- sActiveTabParent.get()));
- if (aTabParent != sActiveTabParent) {
- MOZ_LOG(sISMLog, LogLevel::Error,
- (" SetInputContextForChildProcess(), FAILED, "
- "because non-focused tab parent tries to set input context"));
- return;
- }
- if (NS_WARN_IF(!CanHandleWith(sPresContext))) {
- MOZ_LOG(sISMLog, LogLevel::Error,
- (" SetInputContextForChildProcess(), FAILED, "
- "due to no focused presContext"));
- return;
- }
- if (NS_WARN_IF(!sWidget) || NS_WARN_IF(sWidget->Destroyed())) {
- MOZ_LOG(sISMLog, LogLevel::Error,
- (" SetInputContextForChildProcess(), FAILED, "
- "due to the widget for the nsPresContext has gone"));
- return;
- }
- nsCOMPtr<nsIWidget> widget(sWidget);
- MOZ_ASSERT(!sPresContext->GetRootWidget() ||
- sPresContext->GetRootWidget() == widget);
- MOZ_ASSERT(aInputContext.mOrigin == InputContext::ORIGIN_CONTENT);
- SetInputContext(widget, aInputContext, aAction);
- }
- // static
- void
- IMEStateManager::SetIMEState(const IMEState& aState,
- nsPresContext* aPresContext,
- nsIContent* aContent,
- nsIWidget* aWidget,
- InputContextAction aAction)
- {
- MOZ_LOG(sISMLog, LogLevel::Info,
- ("SetIMEState(aState={ mEnabled=%s, mOpen=%s }, "
- "aContent=0x%p (TabParent=0x%p), aWidget=0x%p, aAction={ mCause=%s, "
- "mFocusChange=%s })",
- GetIMEStateEnabledName(aState.mEnabled),
- GetIMEStateSetOpenName(aState.mOpen), aContent,
- TabParent::GetFrom(aContent), aWidget,
- GetActionCauseName(aAction.mCause),
- GetActionFocusChangeName(aAction.mFocusChange)));
- NS_ENSURE_TRUE_VOID(aWidget);
- InputContext context;
- context.mIMEState = aState;
- context.mMayBeIMEUnaware = context.mIMEState.IsEditable() &&
- sCheckForIMEUnawareWebApps && MayBeIMEUnawareWebApp(aContent);
-
- context.mInPrivateBrowsing =
- aPresContext &&
- nsContentUtils::IsInPrivateBrowsing(aPresContext->Document());
- if (aContent &&
- aContent->IsAnyOfHTMLElements(nsGkAtoms::input, nsGkAtoms::textarea)) {
- if (!aContent->IsHTMLElement(nsGkAtoms::textarea)) {
- // <input type=number> has an anonymous <input type=text> descendant
- // that gets focus whenever anyone tries to focus the number control. We
- // need to check if aContent is one of those anonymous text controls and,
- // if so, use the number control instead:
- nsIContent* content = aContent;
- HTMLInputElement* inputElement =
- HTMLInputElement::FromContentOrNull(aContent);
- if (inputElement) {
- HTMLInputElement* ownerNumberControl =
- inputElement->GetOwnerNumberControl();
- if (ownerNumberControl) {
- content = ownerNumberControl; // an <input type=number>
- }
- }
- content->GetAttr(kNameSpaceID_None, nsGkAtoms::type,
- context.mHTMLInputType);
- } else {
- context.mHTMLInputType.Assign(nsGkAtoms::textarea->GetUTF16String());
- }
- if (Preferences::GetBool("dom.forms.inputmode", false) ||
- nsContentUtils::IsChromeDoc(aContent->OwnerDoc())) {
- aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::inputmode,
- context.mHTMLInputInputmode);
- }
- aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::moz_action_hint,
- context.mActionHint);
- // Get the input content corresponding to the focused node,
- // which may be an anonymous child of the input content.
- nsIContent* inputContent = aContent->FindFirstNonChromeOnlyAccessContent();
- // If we don't have an action hint and
- // return won't submit the form, use "next".
- if (context.mActionHint.IsEmpty() &&
- inputContent->IsHTMLElement(nsGkAtoms::input)) {
- bool willSubmit = false;
- nsCOMPtr<nsIFormControl> control(do_QueryInterface(inputContent));
- mozilla::dom::Element* formElement = nullptr;
- nsCOMPtr<nsIForm> form;
- if (control) {
- formElement = control->GetFormElement();
- // is this a form and does it have a default submit element?
- if ((form = do_QueryInterface(formElement)) &&
- form->GetDefaultSubmitElement()) {
- willSubmit = true;
- // is this an html form and does it only have a single text input element?
- } else if (formElement && formElement->IsHTMLElement(nsGkAtoms::form) &&
- !static_cast<dom::HTMLFormElement*>(formElement)->
- ImplicitSubmissionIsDisabled()) {
- willSubmit = true;
- }
- }
- context.mActionHint.Assign(
- willSubmit ? (control->GetType() == NS_FORM_INPUT_SEARCH ?
- NS_LITERAL_STRING("search") : NS_LITERAL_STRING("go")) :
- (formElement ?
- NS_LITERAL_STRING("next") : EmptyString()));
- }
- }
- // XXX I think that we should use nsContentUtils::IsCallerChrome() instead
- // of the process type.
- if (aAction.mCause == InputContextAction::CAUSE_UNKNOWN &&
- !XRE_IsContentProcess()) {
- aAction.mCause = InputContextAction::CAUSE_UNKNOWN_CHROME;
- }
- SetInputContext(aWidget, context, aAction);
- }
- // static
- void
- IMEStateManager::SetInputContext(nsIWidget* aWidget,
- const InputContext& aInputContext,
- const InputContextAction& aAction)
- {
- MOZ_LOG(sISMLog, LogLevel::Info,
- ("SetInputContext(aWidget=0x%p, aInputContext={ "
- "mIMEState={ mEnabled=%s, mOpen=%s }, mHTMLInputType=\"%s\", "
- "mHTMLInputInputmode=\"%s\", mActionHint=\"%s\", "
- "mInPrivateBrowsing=%s }, "
- "aAction={ mCause=%s, mAction=%s }), sActiveTabParent=0x%p",
- aWidget,
- GetIMEStateEnabledName(aInputContext.mIMEState.mEnabled),
- GetIMEStateSetOpenName(aInputContext.mIMEState.mOpen),
- NS_ConvertUTF16toUTF8(aInputContext.mHTMLInputType).get(),
- NS_ConvertUTF16toUTF8(aInputContext.mHTMLInputInputmode).get(),
- NS_ConvertUTF16toUTF8(aInputContext.mActionHint).get(),
- GetBoolName(aInputContext.mInPrivateBrowsing),
- GetActionCauseName(aAction.mCause),
- GetActionFocusChangeName(aAction.mFocusChange),
- sActiveTabParent.get()));
- MOZ_RELEASE_ASSERT(aWidget);
- nsCOMPtr<nsIWidget> widget(aWidget);
- widget->SetInputContext(aInputContext, aAction);
- sActiveInputContextWidget = widget;
- }
- // static
- void
- IMEStateManager::EnsureTextCompositionArray()
- {
- if (sTextCompositions) {
- return;
- }
- sTextCompositions = new TextCompositionArray();
- }
- // static
- void
- IMEStateManager::DispatchCompositionEvent(
- nsINode* aEventTargetNode,
- nsPresContext* aPresContext,
- WidgetCompositionEvent* aCompositionEvent,
- nsEventStatus* aStatus,
- EventDispatchingCallback* aCallBack,
- bool aIsSynthesized)
- {
- RefPtr<TabParent> tabParent =
- aEventTargetNode->IsContent() ?
- TabParent::GetFrom(aEventTargetNode->AsContent()) : nullptr;
- MOZ_LOG(sISMLog, LogLevel::Info,
- ("DispatchCompositionEvent(aNode=0x%p, "
- "aPresContext=0x%p, aCompositionEvent={ mMessage=%s, "
- "mNativeIMEContext={ mRawNativeIMEContext=0x%X, "
- "mOriginProcessID=0x%X }, mWidget(0x%p)={ "
- "GetNativeIMEContext()={ mRawNativeIMEContext=0x%X, "
- "mOriginProcessID=0x%X }, Destroyed()=%s }, "
- "mFlags={ mIsTrusted=%s, mPropagationStopped=%s } }, "
- "aIsSynthesized=%s), tabParent=%p",
- aEventTargetNode, aPresContext,
- ToChar(aCompositionEvent->mMessage),
- aCompositionEvent->mNativeIMEContext.mRawNativeIMEContext,
- aCompositionEvent->mNativeIMEContext.mOriginProcessID,
- aCompositionEvent->mWidget.get(),
- aCompositionEvent->mWidget->GetNativeIMEContext().mRawNativeIMEContext,
- aCompositionEvent->mWidget->GetNativeIMEContext().mOriginProcessID,
- GetBoolName(aCompositionEvent->mWidget->Destroyed()),
- GetBoolName(aCompositionEvent->mFlags.mIsTrusted),
- GetBoolName(aCompositionEvent->mFlags.mPropagationStopped),
- GetBoolName(aIsSynthesized), tabParent.get()));
- if (!aCompositionEvent->IsTrusted() ||
- aCompositionEvent->PropagationStopped()) {
- return;
- }
- MOZ_ASSERT(aCompositionEvent->mMessage != eCompositionUpdate,
- "compositionupdate event shouldn't be dispatched manually");
- EnsureTextCompositionArray();
- RefPtr<TextComposition> composition =
- sTextCompositions->GetCompositionFor(aCompositionEvent);
- if (!composition) {
- // If synthesized event comes after delayed native composition events
- // for request of commit or cancel, we should ignore it.
- if (NS_WARN_IF(aIsSynthesized)) {
- return;
- }
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" DispatchCompositionEvent(), "
- "adding new TextComposition to the array"));
- MOZ_ASSERT(aCompositionEvent->mMessage == eCompositionStart);
- composition =
- new TextComposition(aPresContext, aEventTargetNode, tabParent,
- aCompositionEvent);
- sTextCompositions->AppendElement(composition);
- }
- #ifdef DEBUG
- else {
- MOZ_ASSERT(aCompositionEvent->mMessage != eCompositionStart);
- }
- #endif // #ifdef DEBUG
- // Dispatch the event on composing target.
- composition->DispatchCompositionEvent(aCompositionEvent, aStatus, aCallBack,
- aIsSynthesized);
- // WARNING: the |composition| might have been destroyed already.
- // Remove the ended composition from the array.
- // NOTE: When TextComposition is synthesizing compositionend event for
- // emulating a commit, the instance shouldn't be removed from the array
- // because IME may perform it later. Then, we need to ignore the
- // following commit events in TextComposition::DispatchEvent().
- // However, if commit or cancel for a request is performed synchronously
- // during not safe to dispatch events, PresShell must have discarded
- // compositionend event. Then, the synthesized compositionend event is
- // the last event for the composition. In this case, we need to
- // destroy the TextComposition with synthesized compositionend event.
- if ((!aIsSynthesized ||
- composition->WasNativeCompositionEndEventDiscarded()) &&
- aCompositionEvent->CausesDOMCompositionEndEvent()) {
- TextCompositionArray::index_type i =
- sTextCompositions->IndexOf(aCompositionEvent->mWidget);
- if (i != TextCompositionArray::NoIndex) {
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" DispatchCompositionEvent(), "
- "removing TextComposition from the array since NS_COMPOSTION_END "
- "was dispatched"));
- sTextCompositions->ElementAt(i)->Destroy();
- sTextCompositions->RemoveElementAt(i);
- }
- }
- }
- // static
- IMEContentObserver*
- IMEStateManager::GetActiveContentObserver()
- {
- return sActiveIMEContentObserver;
- }
- // static
- nsIContent*
- IMEStateManager::GetRootContent(nsPresContext* aPresContext)
- {
- nsIDocument* doc = aPresContext->Document();
- if (NS_WARN_IF(!doc)) {
- return nullptr;
- }
- return doc->GetRootElement();
- }
- // static
- void
- IMEStateManager::HandleSelectionEvent(nsPresContext* aPresContext,
- nsIContent* aEventTargetContent,
- WidgetSelectionEvent* aSelectionEvent)
- {
- nsIContent* eventTargetContent =
- aEventTargetContent ? aEventTargetContent :
- GetRootContent(aPresContext);
- RefPtr<TabParent> tabParent =
- eventTargetContent ? TabParent::GetFrom(eventTargetContent) : nullptr;
- MOZ_LOG(sISMLog, LogLevel::Info,
- ("HandleSelectionEvent(aPresContext=0x%p, "
- "aEventTargetContent=0x%p, aSelectionEvent={ mMessage=%s, "
- "mFlags={ mIsTrusted=%s } }), tabParent=%p",
- aPresContext, aEventTargetContent,
- ToChar(aSelectionEvent->mMessage),
- GetBoolName(aSelectionEvent->mFlags.mIsTrusted),
- tabParent.get()));
- if (!aSelectionEvent->IsTrusted()) {
- return;
- }
- RefPtr<TextComposition> composition = sTextCompositions ?
- sTextCompositions->GetCompositionFor(aSelectionEvent->mWidget) : nullptr;
- if (composition) {
- // When there is a composition, TextComposition should guarantee that the
- // selection event will be handled in same target as composition events.
- composition->HandleSelectionEvent(aSelectionEvent);
- } else {
- // When there is no composition, the selection event should be handled
- // in the aPresContext or tabParent.
- TextComposition::HandleSelectionEvent(aPresContext, tabParent,
- aSelectionEvent);
- }
- }
- // static
- void
- IMEStateManager::OnCompositionEventDiscarded(
- WidgetCompositionEvent* aCompositionEvent)
- {
- // Note that this method is never called for synthesized events for emulating
- // commit or cancel composition.
- MOZ_LOG(sISMLog, LogLevel::Info,
- ("OnCompositionEventDiscarded(aCompositionEvent={ "
- "mMessage=%s, mNativeIMEContext={ mRawNativeIMEContext=0x%X, "
- "mOriginProcessID=0x%X }, mWidget(0x%p)={ "
- "GetNativeIMEContext()={ mRawNativeIMEContext=0x%X, "
- "mOriginProcessID=0x%X }, Destroyed()=%s }, "
- "mFlags={ mIsTrusted=%s } })",
- ToChar(aCompositionEvent->mMessage),
- aCompositionEvent->mNativeIMEContext.mRawNativeIMEContext,
- aCompositionEvent->mNativeIMEContext.mOriginProcessID,
- aCompositionEvent->mWidget.get(),
- aCompositionEvent->mWidget->GetNativeIMEContext().mRawNativeIMEContext,
- aCompositionEvent->mWidget->GetNativeIMEContext().mOriginProcessID,
- GetBoolName(aCompositionEvent->mWidget->Destroyed()),
- GetBoolName(aCompositionEvent->mFlags.mIsTrusted)));
- if (!aCompositionEvent->IsTrusted()) {
- return;
- }
- // Ignore compositionstart for now because sTextCompositions may not have
- // been created yet.
- if (aCompositionEvent->mMessage == eCompositionStart) {
- return;
- }
- RefPtr<TextComposition> composition =
- sTextCompositions->GetCompositionFor(aCompositionEvent->mWidget);
- if (!composition) {
- // If the PresShell has been being destroyed during composition,
- // a TextComposition instance for the composition was already removed from
- // the array and destroyed in OnDestroyPresContext(). Therefore, we may
- // fail to retrieve a TextComposition instance here.
- MOZ_LOG(sISMLog, LogLevel::Info,
- (" OnCompositionEventDiscarded(), "
- "TextComposition instance for the widget has already gone"));
- return;
- }
- composition->OnCompositionEventDiscarded(aCompositionEvent);
- }
- // static
- nsresult
- IMEStateManager::NotifyIME(IMEMessage aMessage,
- nsIWidget* aWidget,
- bool aOriginIsRemote)
- {
- return IMEStateManager::NotifyIME(IMENotification(aMessage), aWidget,
- aOriginIsRemote);
- }
- // static
- nsresult
- IMEStateManager::NotifyIME(const IMENotification& aNotification,
- nsIWidget* aWidget,
- bool aOriginIsRemote)
- {
- MOZ_LOG(sISMLog, LogLevel::Info,
- ("NotifyIME(aNotification={ mMessage=%s }, "
- "aWidget=0x%p, aOriginIsRemote=%s), sFocusedIMEWidget=0x%p, "
- "sRemoteHasFocus=%s",
- ToChar(aNotification.mMessage), aWidget,
- GetBoolName(aOriginIsRemote), sFocusedIMEWidget,
- GetBoolName(sRemoteHasFocus)));
- if (NS_WARN_IF(!aWidget)) {
- MOZ_LOG(sISMLog, LogLevel::Error,
- (" NotifyIME(), FAILED due to no widget"));
- return NS_ERROR_INVALID_ARG;
- }
- switch (aNotification.mMessage) {
- case NOTIFY_IME_OF_FOCUS: {
- if (sFocusedIMEWidget) {
- if (NS_WARN_IF(!sRemoteHasFocus && !aOriginIsRemote)) {
- MOZ_LOG(sISMLog, LogLevel::Error,
- (" NotifyIME(), although, this process is "
- "getting IME focus but there was focused IME widget"));
- } else {
- MOZ_LOG(sISMLog, LogLevel::Info,
- (" NotifyIME(), tries to notify IME of "
- "blur first because remote process's blur notification hasn't "
- "been received yet..."));
- }
- nsCOMPtr<nsIWidget> focusedIMEWidget(sFocusedIMEWidget);
- sFocusedIMEWidget = nullptr;
- sRemoteHasFocus = false;
- focusedIMEWidget->NotifyIME(IMENotification(NOTIFY_IME_OF_BLUR));
- }
- sRemoteHasFocus = aOriginIsRemote;
- sFocusedIMEWidget = aWidget;
- nsCOMPtr<nsIWidget> widget(aWidget);
- return widget->NotifyIME(aNotification);
- }
- case NOTIFY_IME_OF_BLUR: {
- if (!sRemoteHasFocus && aOriginIsRemote) {
- MOZ_LOG(sISMLog, LogLevel::Info,
- (" NotifyIME(), received blur notification "
- "after another one has focus, nothing to do..."));
- return NS_OK;
- }
- if (NS_WARN_IF(sRemoteHasFocus && !aOriginIsRemote)) {
- MOZ_LOG(sISMLog, LogLevel::Error,
- (" NotifyIME(), FAILED, received blur "
- "notification from this process but the remote has focus"));
- return NS_OK;
- }
- if (!sFocusedIMEWidget && aOriginIsRemote) {
- MOZ_LOG(sISMLog, LogLevel::Info,
- (" NotifyIME(), received blur notification "
- "but the remote has already lost focus"));
- return NS_OK;
- }
- if (NS_WARN_IF(!sFocusedIMEWidget)) {
- MOZ_LOG(sISMLog, LogLevel::Error,
- (" NotifyIME(), FAILED, received blur "
- "notification but there is no focused IME widget"));
- return NS_OK;
- }
- if (NS_WARN_IF(sFocusedIMEWidget != aWidget)) {
- MOZ_LOG(sISMLog, LogLevel::Error,
- (" NotifyIME(), FAILED, received blur "
- "notification but there is no focused IME widget"));
- return NS_OK;
- }
- nsCOMPtr<nsIWidget> focusedIMEWidget(sFocusedIMEWidget);
- sFocusedIMEWidget = nullptr;
- sRemoteHasFocus = false;
- return focusedIMEWidget->NotifyIME(IMENotification(NOTIFY_IME_OF_BLUR));
- }
- case NOTIFY_IME_OF_SELECTION_CHANGE:
- case NOTIFY_IME_OF_TEXT_CHANGE:
- case NOTIFY_IME_OF_POSITION_CHANGE:
- case NOTIFY_IME_OF_MOUSE_BUTTON_EVENT:
- case NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED: {
- if (!sRemoteHasFocus && aOriginIsRemote) {
- MOZ_LOG(sISMLog, LogLevel::Info,
- (" NotifyIME(), received content change "
- "notification from the remote but it's already lost focus"));
- return NS_OK;
- }
- if (NS_WARN_IF(sRemoteHasFocus && !aOriginIsRemote)) {
- MOZ_LOG(sISMLog, LogLevel::Error,
- (" NotifyIME(), FAILED, received content "
- "change notification from this process but the remote has already "
- "gotten focus"));
- return NS_OK;
- }
- if (!sFocusedIMEWidget) {
- MOZ_LOG(sISMLog, LogLevel::Info,
- (" NotifyIME(), received content change "
- "notification but there is no focused IME widget"));
- return NS_OK;
- }
- if (NS_WARN_IF(sFocusedIMEWidget != aWidget)) {
- MOZ_LOG(sISMLog, LogLevel::Error,
- (" NotifyIME(), FAILED, received content "
- "change notification for IME which has already lost focus, so, "
- "nothing to do..."));
- return NS_OK;
- }
- nsCOMPtr<nsIWidget> widget(aWidget);
- return widget->NotifyIME(aNotification);
- }
- default:
- // Other notifications should be sent only when there is composition.
- // So, we need to handle the others below.
- break;
- }
- RefPtr<TextComposition> composition;
- if (sTextCompositions) {
- composition = sTextCompositions->GetCompositionFor(aWidget);
- }
- bool isSynthesizedForTests =
- composition && composition->IsSynthesizedForTests();
- MOZ_LOG(sISMLog, LogLevel::Info,
- (" NotifyIME(), composition=0x%p, "
- "composition->IsSynthesizedForTests()=%s",
- composition.get(), GetBoolName(isSynthesizedForTests)));
- switch (aNotification.mMessage) {
- case REQUEST_TO_COMMIT_COMPOSITION:
- return composition ?
- composition->RequestToCommit(aWidget, false) : NS_OK;
- case REQUEST_TO_CANCEL_COMPOSITION:
- return composition ?
- composition->RequestToCommit(aWidget, true) : NS_OK;
- default:
- MOZ_CRASH("Unsupported notification");
- }
- MOZ_CRASH(
- "Failed to handle the notification for non-synthesized composition");
- return NS_ERROR_FAILURE;
- }
- // static
- nsresult
- IMEStateManager::NotifyIME(IMEMessage aMessage,
- nsPresContext* aPresContext,
- bool aOriginIsRemote)
- {
- MOZ_LOG(sISMLog, LogLevel::Info,
- ("NotifyIME(aMessage=%s, aPresContext=0x%p, aOriginIsRemote=%s)",
- ToChar(aMessage), aPresContext, GetBoolName(aOriginIsRemote)));
- if (NS_WARN_IF(!CanHandleWith(aPresContext))) {
- return NS_ERROR_INVALID_ARG;
- }
- nsIWidget* widget = aPresContext->GetRootWidget();
- if (NS_WARN_IF(!widget)) {
- MOZ_LOG(sISMLog, LogLevel::Error,
- (" NotifyIME(), FAILED due to no widget for the "
- "nsPresContext"));
- return NS_ERROR_NOT_AVAILABLE;
- }
- return NotifyIME(aMessage, widget, aOriginIsRemote);
- }
- // static
- bool
- IMEStateManager::IsEditable(nsINode* node)
- {
- if (node->IsEditable()) {
- return true;
- }
- // |node| might be readwrite (for example, a text control)
- if (node->IsElement() &&
- node->AsElement()->State().HasState(NS_EVENT_STATE_MOZ_READWRITE)) {
- return true;
- }
- return false;
- }
- // static
- nsINode*
- IMEStateManager::GetRootEditableNode(nsPresContext* aPresContext,
- nsIContent* aContent)
- {
- if (aContent) {
- nsINode* root = nullptr;
- nsINode* node = aContent;
- while (node && IsEditable(node)) {
- // If the node has independent selection like <input type="text"> or
- // <textarea>, the node should be the root editable node for aContent.
- // FYI: <select> element also has independent selection but IsEditable()
- // returns false.
- // XXX: If somebody adds new editable element which has independent
- // selection but doesn't own editor, we'll need more checks here.
- if (node->IsContent() &&
- node->AsContent()->HasIndependentSelection()) {
- return node;
- }
- root = node;
- node = node->GetParentNode();
- }
- return root;
- }
- if (aPresContext) {
- nsIDocument* document = aPresContext->Document();
- if (document && document->IsEditable()) {
- return document;
- }
- }
- return nullptr;
- }
- // static
- bool
- IMEStateManager::IsIMEObserverNeeded(const IMEState& aState)
- {
- return aState.MaybeEditable();
- }
- // static
- void
- IMEStateManager::DestroyIMEContentObserver()
- {
- MOZ_LOG(sISMLog, LogLevel::Info,
- ("DestroyIMEContentObserver(), sActiveIMEContentObserver=0x%p",
- sActiveIMEContentObserver.get()));
- if (!sActiveIMEContentObserver) {
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" DestroyIMEContentObserver() does nothing"));
- return;
- }
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" DestroyIMEContentObserver(), destroying "
- "the active IMEContentObserver..."));
- RefPtr<IMEContentObserver> tsm = sActiveIMEContentObserver.get();
- sActiveIMEContentObserver = nullptr;
- tsm->Destroy();
- }
- // static
- void
- IMEStateManager::CreateIMEContentObserver(nsIEditor* aEditor)
- {
- MOZ_LOG(sISMLog, LogLevel::Info,
- ("CreateIMEContentObserver(aEditor=0x%p), "
- "sPresContext=0x%p, sContent=0x%p, sWidget=0x%p (available: %s), "
- "sActiveIMEContentObserver=0x%p, "
- "sActiveIMEContentObserver->IsManaging(sPresContext, sContent)=%s",
- aEditor, sPresContext.get(), sContent.get(),
- sWidget, GetBoolName(sWidget && !sWidget->Destroyed()),
- sActiveIMEContentObserver.get(),
- GetBoolName(sActiveIMEContentObserver ?
- sActiveIMEContentObserver->IsManaging(sPresContext, sContent) : false)));
- if (NS_WARN_IF(sActiveIMEContentObserver)) {
- MOZ_LOG(sISMLog, LogLevel::Error,
- (" CreateIMEContentObserver(), FAILED due to "
- "there is already an active IMEContentObserver"));
- MOZ_ASSERT(sActiveIMEContentObserver->IsManaging(sPresContext, sContent));
- return;
- }
- if (!sWidget || NS_WARN_IF(sWidget->Destroyed())) {
- MOZ_LOG(sISMLog, LogLevel::Error,
- (" CreateIMEContentObserver(), FAILED due to "
- "the widget for the nsPresContext has gone"));
- return; // Sometimes, there are no widgets.
- }
- nsCOMPtr<nsIWidget> widget(sWidget);
- // If it's not text editable, we don't need to create IMEContentObserver.
- if (!IsIMEObserverNeeded(widget->GetInputContext().mIMEState)) {
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" CreateIMEContentObserver() doesn't create "
- "IMEContentObserver because of non-editable IME state"));
- return;
- }
- if (NS_WARN_IF(widget->Destroyed())) {
- MOZ_LOG(sISMLog, LogLevel::Error,
- (" CreateIMEContentObserver(), FAILED due to "
- "the widget for the nsPresContext has gone"));
- return;
- }
- MOZ_ASSERT(sPresContext->GetRootWidget() == widget);
- MOZ_LOG(sISMLog, LogLevel::Debug,
- (" CreateIMEContentObserver() is creating an "
- "IMEContentObserver instance..."));
- sActiveIMEContentObserver = new IMEContentObserver();
- // IMEContentObserver::Init() might create another IMEContentObserver
- // instance. So, sActiveIMEContentObserver would be replaced with new one.
- // We should hold the current instance here.
- RefPtr<IMEContentObserver> activeIMEContentObserver(sActiveIMEContentObserver);
- activeIMEContentObserver->Init(widget, sPresContext, sContent, aEditor);
- }
- // static
- nsresult
- IMEStateManager::GetFocusSelectionAndRoot(nsISelection** aSelection,
- nsIContent** aRootContent)
- {
- if (!sActiveIMEContentObserver) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- return sActiveIMEContentObserver->GetSelectionAndRoot(aSelection,
- aRootContent);
- }
- // static
- already_AddRefed<TextComposition>
- IMEStateManager::GetTextCompositionFor(nsIWidget* aWidget)
- {
- if (!sTextCompositions) {
- return nullptr;
- }
- RefPtr<TextComposition> textComposition =
- sTextCompositions->GetCompositionFor(aWidget);
- return textComposition.forget();
- }
- // static
- already_AddRefed<TextComposition>
- IMEStateManager::GetTextCompositionFor(
- const WidgetCompositionEvent* aCompositionEvent)
- {
- if (!sTextCompositions) {
- return nullptr;
- }
- RefPtr<TextComposition> textComposition =
- sTextCompositions->GetCompositionFor(aCompositionEvent);
- return textComposition.forget();
- }
- // static
- already_AddRefed<TextComposition>
- IMEStateManager::GetTextCompositionFor(nsPresContext* aPresContext)
- {
- if (!sTextCompositions) {
- return nullptr;
- }
- RefPtr<TextComposition> textComposition =
- sTextCompositions->GetCompositionFor(aPresContext);
- return textComposition.forget();
- }
- } // namespace mozilla
|