/* -*- Mode: C++; tab-width: 40; 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/. */
// Helper class to logging string which may contain various Unicode characters // and/or may be too long string for logging. class MOZ_STACK_CLASS PrintStringDetail : public nsAutoCString { public: static constexpr uint32_t kMaxLengthForCompositionString = 8; static constexpr uint32_t kMaxLengthForSelectedString = 12; static constexpr uint32_t kMaxLengthForEditor = 20;
// OffsetAndData class is designed for storing composition string and its // start offset. Length() and EndOffset() return only valid length or // offset. I.e., if the string is too long for inserting at the offset, // the length is shrunken. However, the string itself is not shrunken. // Therefore, moving it to where all of the string can be contained, // they will return longer/bigger value. enumclass OffsetAndDataFor {
CompositionString,
SelectedString,
EditorString,
}; template <typename IntType> class OffsetAndData { protected: static IntType MaxOffset() { return std::numeric_limits<IntType>::max(); }
bool IsValid() const {
CheckedInt<IntType> offset(mOffset);
offset += mData.Length(); return offset.isValid();
}
IntType StartOffset() const { return mOffset; }
IntType Length() const {
CheckedInt<IntType> endOffset(CheckedInt<IntType>(mOffset) +
mData.Length()); return endOffset.isValid() ? mData.Length() : MaxOffset() - mOffset;
}
IntType EndOffset() const { return mOffset + Length(); }
StartAndEndOffsets<IntType> CreateStartAndEndOffsets() const { return StartAndEndOffsets<IntType>(StartOffset(), EndOffset());
} const nsString& DataRef() const { // In strictly speaking, we should return substring which may be shrunken // for rounding to the max offset. However, it's unrealistic edge case, // and creating new string is not so cheap job in a hot path. Therefore, // this just returns the data as-is. return mData;
} bool IsDataEmpty() const { return mData.IsEmpty(); }
/** * Preference for receiving IME updates * * If mWantUpdates is not NOTIFY_NOTHING, nsTextStateManager will observe text * change and/or selection change and call nsIWidget::NotifyIME() with * NOTIFY_IME_OF_SELECTION_CHANGE and/or NOTIFY_IME_OF_TEXT_CHANGE. * Please note that the text change observing cost is very expensive especially * on an HTML editor has focus. * If the IME implementation on a particular platform doesn't care about * NOTIFY_IME_OF_SELECTION_CHANGE and/or NOTIFY_IME_OF_TEXT_CHANGE, * they should set mWantUpdates to NOTIFY_NOTHING to avoid the cost. * If the IME implementation needs notifications even while our process is * deactive, it should also set NOTIFY_DURING_DEACTIVE.
*/ struct IMENotificationRequests final { typedef uint8_t Notifications;
enum : Notifications {
NOTIFY_NOTHING = 0,
NOTIFY_TEXT_CHANGE = 1 << 1,
NOTIFY_POSITION_CHANGE = 1 << 2, // NOTIFY_MOUSE_BUTTON_EVENT_ON_CHAR is used when mouse button is pressed // or released on a character in the focused editor. The notification is // notified to IME as a mouse event. If it's consumed by IME, NotifyIME() // returns NS_SUCCESS_EVENT_CONSUMED. Otherwise, it returns NS_OK if it's // handled without any error.
NOTIFY_MOUSE_BUTTON_EVENT_ON_CHAR = 1 << 3, // NOTE: NOTIFY_DURING_DEACTIVE isn't supported in environments where two // or more compositions are possible. E.g., Mac and Linux (GTK).
NOTIFY_DURING_DEACTIVE = 1 << 7,
/** * IME enabled states. * * WARNING: If you change these values, you also need to edit: * nsIDOMWindowUtils.idl
*/ enumclass IMEEnabled { /** * 'Disabled' means the user cannot use IME. So, the IME open state should * be 'closed' during 'disabled'.
*/
Disabled, /** * 'Enabled' means the user can use IME.
*/
Enabled, /** * 'Password' state is a special case for the password editors. * E.g., on mac, the password editors should disable the non-Roman * keyboard layouts at getting focus. Thus, the password editor may have * special rules on some platforms.
*/
Password, /** * 'Unknown' is useful when you cache this enum. So, this shouldn't be * used with nsIWidget::SetInputContext().
*/
Unknown,
};
/** * Contains IMEStatus plus information about the current * input context that the IME can use as hints if desired.
*/
struct IMEState final {
IMEEnabled mEnabled;
/** * IME open states the mOpen value of SetInputContext() should be one value of * OPEN, CLOSE or DONT_CHANGE_OPEN_STATE. GetInputContext() should return * OPEN, CLOSE or OPEN_STATE_NOT_SUPPORTED.
*/ enum Open { /** * 'Unsupported' means the platform cannot return actual IME open state. * This value is used only by GetInputContext().
*/
OPEN_STATE_NOT_SUPPORTED, /** * 'Don't change' means the widget shouldn't change IME open state when * SetInputContext() is called.
*/
DONT_CHANGE_OPEN_STATE = OPEN_STATE_NOT_SUPPORTED, /** * 'Open' means that IME should compose in its primary language (or latest * input mode except direct ASCII character input mode). Even if IME is * opened by this value, users should be able to close IME by theirselves. * Web contents can specify this value by |ime-mode: active;|.
*/
OPEN, /** * 'Closed' means that IME shouldn't handle key events (or should handle * as ASCII character inputs on mobile device). Even if IME is closed by * this value, users should be able to open IME by theirselves. * Web contents can specify this value by |ime-mode: inactive;|.
*/
CLOSED
};
Open mOpen;
// Returns true if the user can input characters. // This means that a plain text editor, an HTML editor, a password editor or // a plain text editor whose ime-mode is "disabled". bool IsEditable() const { return mEnabled == IMEEnabled::Enabled || mEnabled == IMEEnabled::Password;
}
};
// NS_ONLY_ONE_NATIVE_IME_CONTEXT is a special value of native IME context. // If there can be only one IME composition in a process, this can be used. #define NS_ONLY_ONE_NATIVE_IME_CONTEXT \
(reinterpret_cast<void*>(static_cast<intptr_t>(-1)))
struct NativeIMEContext final { // Pointer to native IME context. Typically this is the result of // nsIWidget::GetNativeData(NS_RAW_NATIVE_IME_CONTEXT) in the parent process. // See also NS_ONLY_ONE_NATIVE_IME_CONTEXT.
uintptr_t mRawNativeIMEContext; // Process ID of the origin of mNativeIMEContext. // static_cast<uint64_t>(-1) if the instance is not initialized properly. // 0 if the instance is originated in the parent process. // 1 or greater if the instance is originated in a content process.
uint64_t mOriginProcessID;
// If InputContext instance is a static variable, any heap allocated stuff // of its members need to be deleted at XPCOM shutdown. Otherwise, it's // detected as memory leak. void ShutDown() {
mURI = nullptr;
mHTMLInputType.Truncate();
mHTMLInputMode.Truncate();
mActionHint.Truncate();
mAutocapitalize.Truncate();
mAutocorrect = true;
}
bool IsInputAttributeChanged(const InputContext& aOldContext) const { return mIMEState.mEnabled != aOldContext.mIMEState.mEnabled || #ifdefined(ANDROID) || defined(MOZ_WIDGET_GTK) || defined(XP_WIN) || \ defined(XP_IOS) // input type and inputmode are supported by Windows IME API, GTK // IME API, Android IME API and iOS API.
mHTMLInputType != aOldContext.mHTMLInputType ||
mHTMLInputMode != aOldContext.mHTMLInputMode || #endif #ifdefined(ANDROID) || defined(MOZ_WIDGET_GTK) || defined(XP_IOS) // autocapitalize is supported by Android IME API, GTK IME API, and // iOS API
mAutocapitalize != aOldContext.mAutocapitalize || #endif #ifdefined(ANDROID) || defined(XP_IOS) // enterkeyhint is only supported by Android IME API and iOS API.
mActionHint != aOldContext.mActionHint || #endif #ifdefined(ANDROID) || defined(XP_DARWIN) // autocorrect is only supported by Android IME API, macOS text // substitution and iOS API.
mAutocorrect != aOldContext.mAutocorrect || #endif false;
}
IMEState mIMEState;
// The URI of the document which has the editable element.
nsCOMPtr<nsIURI> mURI;
/* The type of the input if the input is a html input field */
nsString mHTMLInputType;
// The value of the inputmode
nsString mHTMLInputMode;
/* A hint for the action that is performed when the input is submitted */
nsString mActionHint;
/* A hint for autocapitalize */
nsString mAutocapitalize;
/* A hint for autocorrect */ bool mAutocorrect = true; // on-by-default
/** * mOrigin indicates whether this focus event refers to main or remote * content.
*/ enum Origin { // Adjusting focus of content on the main process
ORIGIN_MAIN, // Adjusting focus of content in a remote process
ORIGIN_CONTENT
};
Origin mOrigin;
/** * True if the document has ever received user input
*/ bool mHasHandledUserInput;
/* Whether the owning document of the input element has been loaded
* in private browsing mode. */ bool mInPrivateBrowsing;
// FYI: Implemented in nsBaseWidget.cpp constchar* ToChar(InputContext::Origin aOrigin);
struct InputContextAction final { /** * mCause indicates what action causes calling nsIWidget::SetInputContext(). * It must be one of following values.
*/ enum Cause { // The cause is unknown but originated from content. Focus might have been // changed by content script.
CAUSE_UNKNOWN, // The cause is unknown but originated from chrome. Focus might have been // changed by chrome script.
CAUSE_UNKNOWN_CHROME, // The cause is user's keyboard operation.
CAUSE_KEY, // The cause is user's mouse operation.
CAUSE_MOUSE, // The cause is user's touch operation (implies mouse)
CAUSE_TOUCH, // The cause is users' long press operation.
CAUSE_LONGPRESS, // The cause is unknown but it occurs during user input except keyboard // input. E.g., an event handler of a user input event moves focus.
CAUSE_UNKNOWN_DURING_NON_KEYBOARD_INPUT, // The cause is unknown but it occurs during keyboard input.
CAUSE_UNKNOWN_DURING_KEYBOARD_INPUT,
};
Cause mCause;
/** * mFocusChange indicates what happened for focus.
*/ enum FocusChange {
FOCUS_NOT_CHANGED, // A content got focus.
GOT_FOCUS, // Focused content lost focus.
LOST_FOCUS, // Menu got pseudo focus that means focused content isn't changed but // keyboard events will be handled by menu.
MENU_GOT_PSEUDO_FOCUS, // Menu lost pseudo focus that means focused content will handle keyboard // events.
MENU_LOST_PSEUDO_FOCUS, // The widget is created. When a widget is crated, it may need to notify // IME module to initialize its native IME context. In such case, this is // used. I.e., this isn't used by IMEStateManager.
WIDGET_CREATED
};
FocusChange mFocusChange;
bool UserMightRequestOpenVKB() const { // If focus is changed, user must not request to open VKB. if (mFocusChange != FOCUS_NOT_CHANGED) { returnfalse;
} switch (mCause) { // If user clicks or touches focused editor, user must request to open // VKB. case CAUSE_MOUSE: case CAUSE_TOUCH: // If script does something during a user input and that causes changing // input context, user might request to open VKB. E.g., user clicks // dummy editor and JS moves focus to an actual editable node. However, // this should return false if the user input is a keyboard event since // physical keyboard operation shouldn't cause opening VKB. case CAUSE_UNKNOWN_DURING_NON_KEYBOARD_INPUT: returntrue; default: returnfalse;
}
}
/** * IsHandlingUserInput() returns true if it's caused by a user action directly * or it's caused by script or something but it occurred while we're handling * a user action. E.g., when it's caused by Element.focus() in an event * handler of a user input, this returns true.
*/ staticbool IsHandlingUserInput(Cause aCause) { switch (aCause) { case CAUSE_KEY: case CAUSE_MOUSE: case CAUSE_TOUCH: case CAUSE_LONGPRESS: case CAUSE_UNKNOWN_DURING_NON_KEYBOARD_INPUT: case CAUSE_UNKNOWN_DURING_KEYBOARD_INPUT: returntrue; default: returnfalse;
}
}
// IMEMessage is shared by IMEStateManager and TextComposition. // Update values in GeckoEditable.java if you make changes here. // XXX Negative values are used in Android... typedef int8_t IMEMessageType; enum IMEMessage : IMEMessageType { // This is used by IMENotification internally. This means that the instance // hasn't been initialized yet.
NOTIFY_IME_OF_NOTHING, // An editable content is getting focus
NOTIFY_IME_OF_FOCUS, // An editable content is losing focus
NOTIFY_IME_OF_BLUR, // Selection in the focused editable content is changed
NOTIFY_IME_OF_SELECTION_CHANGE, // Text in the focused editable content is changed
NOTIFY_IME_OF_TEXT_CHANGE, // Notified when a dispatched composition event is handled by the // contents. This must be notified after the other notifications. // Note that if a remote process has focus, this is notified only once when // all dispatched events are handled completely. So, the receiver shouldn't // count number of received this notification for comparing with the number // of dispatched events. // NOTE: If a composition event causes moving focus from the focused editor, // this notification may not be notified as usual. Even in such case, // NOTIFY_IME_OF_BLUR is always sent. So, notification listeners // should tread the blur notification as including this if there is // pending composition events.
NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED, // Position or size of focused element may be changed.
NOTIFY_IME_OF_POSITION_CHANGE, // Mouse button event is fired on a character in focused editor
NOTIFY_IME_OF_MOUSE_BUTTON_EVENT, // Request to commit current composition to IME // (some platforms may not support)
REQUEST_TO_COMMIT_COMPOSITION, // Request to cancel current composition to IME // (some platforms may not support)
REQUEST_TO_CANCEL_COMPOSITION
};
// FYI: Implemented in nsBaseWidget.cpp constchar* ToChar(IMEMessage aIMEMessage);
struct IMENotification final {
IMENotification() : mMessage(NOTIFY_IME_OF_NOTHING), mSelectionChangeData() {}
// SelectionChangeDataBase cannot have constructors because it's used in // the union. Therefore, SelectionChangeData should only implement // constructors. In other words, add other members to // SelectionChangeDataBase. struct SelectionChangeData final : public SelectionChangeDataBase {
SelectionChangeData() {
mString = &mStringInstance;
Clear();
} explicit SelectionChangeData(const SelectionChangeDataBase& aOther) {
mString = &mStringInstance;
Assign(aOther);
}
SelectionChangeData(const SelectionChangeData& aOther) {
mString = &mStringInstance;
Assign(aOther);
}
SelectionChangeData& operator=(const SelectionChangeDataBase& aOther) {
mString = &mStringInstance;
Assign(aOther); return *this;
}
SelectionChangeData& operator=(const SelectionChangeData& aOther) {
mString = &mStringInstance;
Assign(aOther); return *this;
}
private: // When SelectionChangeData is used outside of union, it shouldn't create // nsString instance in the heap as far as possible.
nsString mStringInstance;
};
struct TextChangeDataBase { // mStartOffset is the start offset of modified or removed text in // original content and inserted text in new content.
uint32_t mStartOffset; // mRemovalEndOffset is the end offset of modified or removed text in // original content. If the value is same as mStartOffset, no text hasn't // been removed yet.
uint32_t mRemovedEndOffset; // mAddedEndOffset is the end offset of inserted text or same as // mStartOffset if just removed. The vlaue is offset in the new content.
uint32_t mAddedEndOffset;
// Note that TextChangeDataBase may be the result of merging two or more // changes especially in e10s mode.
// mCausedOnlyByComposition is true only when *all* merged changes are // caused by composition. bool mCausedOnlyByComposition; // mIncludingChangesDuringComposition is true if at least one change which // is not caused by composition occurred during the last composition. // Note that if after the last composition is finished and there are some // changes not caused by composition, this is set to false. bool mIncludingChangesDuringComposition; // mIncludingChangesWithoutComposition is true if there is at least one // change which did occur when there wasn't a composition ongoing. bool mIncludingChangesWithoutComposition;
// TextChangeDataBase cannot have constructors because they are used in union. // Therefore, TextChangeData should only implement constructor. In other // words, add other members to TextChangeDataBase. struct TextChangeData : public TextChangeDataBase {
TextChangeData() { Clear(); }
TextChangeData(uint32_t aStartOffset, uint32_t aRemovedEndOffset,
uint32_t aAddedEndOffset, bool aCausedByComposition, bool aOccurredDuringComposition) {
MOZ_ASSERT(aRemovedEndOffset >= aStartOffset, "removed end offset must not be smaller than start offset");
MOZ_ASSERT(aAddedEndOffset >= aStartOffset, "added end offset must not be smaller than start offset");
mStartOffset = aStartOffset;
mRemovedEndOffset = aRemovedEndOffset;
mAddedEndOffset = aAddedEndOffset;
mCausedOnlyByComposition = aCausedByComposition;
mIncludingChangesDuringComposition =
!aCausedByComposition && aOccurredDuringComposition;
mIncludingChangesWithoutComposition =
!aCausedByComposition && !aOccurredDuringComposition;
}
};
struct MouseButtonEventData { // The value of WidgetEvent::mMessage
EventMessage mEventMessage; // Character offset from the start of the focused editor under the cursor
uint32_t mOffset; // Cursor position in pixels relative to the widget
LayoutDeviceIntPoint mCursorPos; // Character rect in pixels under the cursor relative to the widget
LayoutDeviceIntRect mCharRect; // The value of WidgetMouseEventBase::button and buttons
int16_t mButton;
int16_t mButtons; // The value of WidgetInputEvent::modifiers
Modifiers mModifiers;
};
union { // NOTIFY_IME_OF_SELECTION_CHANGE specific data
SelectionChangeDataBase mSelectionChangeData;
// NOTIFY_IME_OF_TEXT_CHANGE specific data
TextChangeDataBase mTextChangeData;
// NOTIFY_IME_OF_MOUSE_BUTTON_EVENT specific data
MouseButtonEventData mMouseButtonEventData;
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.