author | Masayuki Nakano <masayuki@d-toybox.com> |
Thu, 10 Apr 2014 16:11:37 +0900 | |
changeset 197486 | 8a2a1efffcd579563b2e6914722f3299657432e5 |
parent 197485 | d40a8916b7e70824d066488d309fed4662f3d8e1 |
child 197487 | 86cbe44bf63e331d341f4c13a88d5c89c6120bba |
push id | 486 |
push user | asasaki@mozilla.com |
push date | Mon, 14 Jul 2014 18:39:42 +0000 |
treeherder | mozilla-release@d33428174ff1 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | smaug |
bugs | 993253 |
milestone | 31.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/content/html/content/public/nsIFormControl.h +++ b/content/html/content/public/nsIFormControl.h @@ -27,17 +27,16 @@ enum FormControlsTypes { NS_FORM_TEXTAREA, NS_FORM_OBJECT, eFormControlsWithoutSubTypesMax, // After this, all types will have sub-types which introduce new enum lists. // eFormControlsWithoutSubTypesMax let us know if the previous types values // are not overlapping with sub-types/masks. // Elements with different types, the value is used as a mask. - // Adding '_ELEMENT' because NS_FORM_INPUT is used for 'oninput' event. // When changing the order, adding or removing elements, be sure to update // the static_assert checks accordingly. NS_FORM_BUTTON_ELEMENT = 0x40, // 0b01000000 NS_FORM_INPUT_ELEMENT = 0x80 // 0b10000000 }; enum ButtonElementTypes { NS_FORM_BUTTON_BUTTON = NS_FORM_BUTTON_ELEMENT + 1,
--- a/content/html/content/src/HTMLInputElement.cpp +++ b/content/html/content/src/HTMLInputElement.cpp @@ -3488,17 +3488,17 @@ HTMLInputElement::PreHandleEvent(EventCh // to do some special handling here. HTMLInputElement* textControl = nullptr; nsNumberControlFrame* numberControlFrame = do_QueryFrame(GetPrimaryFrame()); if (numberControlFrame) { textControl = numberControlFrame->GetAnonTextControl(); } if (textControl && aVisitor.mEvent->originalTarget == textControl) { - if (aVisitor.mEvent->message == NS_FORM_INPUT) { + if (aVisitor.mEvent->message == NS_EDITOR_INPUT) { // Propogate the anon text control's new value to our HTMLInputElement: nsAutoString value; numberControlFrame->GetValueOfAnonTextControl(value); numberControlFrame->HandlingInputEvent(true); nsWeakFrame weakNumberControlFrame(numberControlFrame); SetValueInternal(value, true, true); if (weakNumberControlFrame.IsAlive()) { numberControlFrame->HandlingInputEvent(false);
--- a/dom/events/Event.cpp +++ b/dom/events/Event.cpp @@ -663,23 +663,23 @@ Event::GetEventPopupControlState(WidgetE case NS_FORM_CHANGE : if (PopupAllowedForEvent("change")) { abuse = openControlled; } break; } } break; - case NS_GUI_EVENT : + case NS_EDITOR_INPUT_EVENT : // For this following event only allow popups if it's triggered // while handling user input. See // nsPresShell::HandleEventInternal() for details. if (EventStateManager::IsHandlingUserInput()) { switch(aEvent->message) { - case NS_FORM_INPUT : + case NS_EDITOR_INPUT: if (PopupAllowedForEvent("input")) { abuse = openControlled; } break; } } break; case NS_INPUT_EVENT :
--- a/dom/events/EventDispatcher.cpp +++ b/dom/events/EventDispatcher.cpp @@ -702,16 +702,19 @@ EventDispatcher::CreateEvent(EventTarget return NS_NewDOMFocusEvent(aDOMEvent, aOwner, aPresContext, aEvent->AsFocusEvent()); case NS_MOUSE_SCROLL_EVENT: return NS_NewDOMMouseScrollEvent(aDOMEvent, aOwner, aPresContext, aEvent->AsMouseScrollEvent()); case NS_WHEEL_EVENT: return NS_NewDOMWheelEvent(aDOMEvent, aOwner, aPresContext, aEvent->AsWheelEvent()); + case NS_EDITOR_INPUT_EVENT: + return NS_NewDOMInputEvent(aDOMEvent, aOwner, aPresContext, + aEvent->AsEditorInputEvent()); case NS_DRAG_EVENT: return NS_NewDOMDragEvent(aDOMEvent, aOwner, aPresContext, aEvent->AsDragEvent()); case NS_TEXT_EVENT: return NS_NewDOMUIEvent(aDOMEvent, aOwner, aPresContext, aEvent->AsTextEvent()); case NS_CLIPBOARD_EVENT: return NS_NewDOMClipboardEvent(aDOMEvent, aOwner, aPresContext,
--- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -213,19 +213,19 @@ EVENT(emptied, NS_EMPTIED, EventNameType_HTML, NS_EVENT) EVENT(ended, NS_ENDED, EventNameType_HTML, NS_EVENT) EVENT(input, - NS_FORM_INPUT, + NS_EDITOR_INPUT, EventNameType_HTMLXUL, - NS_UI_EVENT) + NS_EDITOR_INPUT_EVENT) EVENT(invalid, NS_FORM_INVALID, EventNameType_HTMLXUL, NS_EVENT) EVENT(keydown, NS_KEY_DOWN, EventNameType_HTMLXUL, NS_KEY_EVENT)
new file mode 100644 --- /dev/null +++ b/dom/events/InputEvent.cpp @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 2; 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/dom/InputEvent.h" +#include "mozilla/TextEvents.h" +#include "prtime.h" + +namespace mozilla { +namespace dom { + +InputEvent::InputEvent(EventTarget* aOwner, + nsPresContext* aPresContext, + InternalEditorInputEvent* aEvent) + : UIEvent(aOwner, aPresContext, + aEvent ? aEvent : new InternalEditorInputEvent(false, 0, nullptr)) +{ + NS_ASSERTION(mEvent->eventStructType == NS_EDITOR_INPUT_EVENT, + "event type mismatch"); + + if (aEvent) { + mEventIsInternal = false; + } else { + mEventIsInternal = true; + mEvent->time = PR_Now(); + } +} + +NS_IMPL_ADDREF_INHERITED(InputEvent, UIEvent) +NS_IMPL_RELEASE_INHERITED(InputEvent, UIEvent) + +NS_INTERFACE_MAP_BEGIN(InputEvent) +NS_INTERFACE_MAP_END_INHERITING(UIEvent) + +bool +InputEvent::IsComposing() +{ + return mEvent->AsEditorInputEvent()->mIsComposing; +} + +already_AddRefed<InputEvent> +InputEvent::Constructor(const GlobalObject& aGlobal, + const nsAString& aType, + const InputEventInit& aParam, + ErrorResult& aRv) +{ + nsCOMPtr<EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports()); + nsRefPtr<InputEvent> e = new InputEvent(t, nullptr, nullptr); + bool trusted = e->Init(t); + aRv = e->InitUIEvent(aType, aParam.mBubbles, aParam.mCancelable, + aParam.mView, aParam.mDetail); + InternalEditorInputEvent* internalEvent = e->mEvent->AsEditorInputEvent(); + internalEvent->mIsComposing = aParam.mIsComposing; + e->SetTrusted(trusted); + return e.forget(); +} + +} // namespace dom +} // namespace mozilla + +using namespace mozilla; +using namespace mozilla::dom; + +nsresult +NS_NewDOMInputEvent(nsIDOMEvent** aInstancePtrResult, + EventTarget* aOwner, + nsPresContext* aPresContext, + InternalEditorInputEvent* aEvent) +{ + InputEvent* it = new InputEvent(aOwner, aPresContext, aEvent); + NS_ADDREF(it); + *aInstancePtrResult = static_cast<Event*>(it); + return NS_OK; +}
new file mode 100644 --- /dev/null +++ b/dom/events/InputEvent.h @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 2; 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/. */ + +#ifndef mozilla_dom_InputEvent_h_ +#define mozilla_dom_InputEvent_h_ + +#include "mozilla/dom/UIEvent.h" +#include "mozilla/dom/InputEventBinding.h" +#include "mozilla/EventForwards.h" + +namespace mozilla { +namespace dom { + +class InputEvent : public UIEvent +{ +public: + InputEvent(EventTarget* aOwner, + nsPresContext* aPresContext, + InternalEditorInputEvent* aEvent); + + NS_DECL_ISUPPORTS_INHERITED + + // Forward to base class + NS_FORWARD_TO_UIEVENT + + + static already_AddRefed<InputEvent> Constructor(const GlobalObject& aGlobal, + const nsAString& aType, + const InputEventInit& aParam, + ErrorResult& aRv); + + virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE + { + return InputEventBinding::Wrap(aCx, this); + } + + bool IsComposing(); +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_InputEvent_h_
--- a/dom/events/moz.build +++ b/dom/events/moz.build @@ -37,16 +37,17 @@ EXPORTS.mozilla.dom += [ 'CompositionEvent.h', 'DataContainerEvent.h', 'DataTransfer.h', 'DeviceMotionEvent.h', 'DragEvent.h', 'Event.h', 'EventTarget.h', 'FocusEvent.h', + 'InputEvent.h', 'KeyboardEvent.h', 'MessageEvent.h', 'MouseEvent.h', 'MouseScrollEvent.h', 'MutationEvent.h', 'NotifyPaintEvent.h', 'PaintRequest.h', 'PointerEvent.h', @@ -79,16 +80,17 @@ UNIFIED_SOURCES += [ 'Event.cpp', 'EventDispatcher.cpp', 'EventListenerManager.cpp', 'EventListenerService.cpp', 'EventTarget.cpp', 'FocusEvent.cpp', 'IMEContentObserver.cpp', 'IMEStateManager.cpp', + 'InputEvent.cpp', 'JSEventHandler.cpp', 'KeyboardEvent.cpp', 'MessageEvent.cpp', 'MouseEvent.cpp', 'MouseScrollEvent.cpp', 'MutationEvent.cpp', 'NotifyPaintEvent.cpp', 'PaintRequest.cpp',
--- a/dom/events/test/test_all_synthetic_events.html +++ b/dom/events/test/test_all_synthetic_events.html @@ -178,16 +178,20 @@ const kEventConstructors = { IccChangeEvent: { create: function (aName, aProps) { return new IccChangeEvent(aName, aProps); }, }, IDBVersionChangeEvent: { create: function (aName, aProps) { return new IDBVersionChangeEvent(aName, aProps); }, }, + InputEvent: { create: function (aName, aProps) { + return new InputEvent(aName, aProps); + }, + }, KeyEvent: { create: function (aName, aProps) { var e = document.createEvent("keyboardevent"); e.initKeyEvent(aName, aProps.bubbles, aProps.cancelable, aProps.view, aProps.ctrlKey, aProps.altKey, aProps.shiftKey, aProps.metaKey, aProps.keyCode, aProps.charCode); return e; },
--- a/dom/events/test/test_eventctors.html +++ b/dom/events/test/test_eventctors.html @@ -309,16 +309,42 @@ is(e.type, "hello", "Wrong event type!") ok(!e.isTrusted, "Event shouldn't be trusted!"); ok(e.bubbles, "Event should bubble!"); ok(e.cancelable, "Event should be cancelable!"); is(e.oldURL, "", "oldURL should be ''"); is(e.newURL, "new", "newURL should be 'new'"); document.dispatchEvent(e); is(receivedEvent, e, "Wrong event!"); +// InputEvent + +e = new InputEvent("hello"); +is(e.type, "hello", "Wrong event type!"); +ok(!e.isTrusted, "Event shouldn't be trusted!"); +ok(!e.bubbles, "Event shouldn't bubble!"); +ok(!e.cancelable, "Event shouldn't be cancelable!"); +is(e.detail, 0, "detail should be 0"); +ok(!e.isComposing, "isComposing should be false"); + +e = new InputEvent("hi!", { bubbles: true, detail: 5, isComposing: false }); +is(e.type, "hi!", "Wrong event type!"); +ok(!e.isTrusted, "Event shouldn't be trusted!"); +ok(e.bubbles, "Event should bubble!"); +ok(!e.cancelable, "Event shouldn't be cancelable!"); +is(e.detail, 5, "detail should be 5"); +ok(!e.isComposing, "isComposing should be false"); + +e = new InputEvent("hi!", { cancelable: true, detail: 0, isComposing: true }); +is(e.type, "hi!", "Wrong event type!"); +ok(!e.isTrusted, "Event shouldn't be trusted!"); +ok(!e.bubbles, "Event shouldn't bubble!"); +ok(e.cancelable, "Event should be cancelable!"); +is(e.detail, 0, "detail should be 0"); +ok(e.isComposing, "isComposing should be true"); + // PageTransitionEvent try { e = new PageTransitionEvent(); } catch(exp) { ex = true; } ok(ex, "First parameter is required!");
--- a/dom/interfaces/events/nsIDOMEvent.idl +++ b/dom/interfaces/events/nsIDOMEvent.idl @@ -257,17 +257,21 @@ NS_NewDOMDragEvent(nsIDOMEvent** aInstan mozilla::dom::EventTarget* aOwner, nsPresContext* aPresContext, mozilla::WidgetDragEvent* aEvent); nsresult NS_NewDOMClipboardEvent(nsIDOMEvent** aInstancePtrResult, mozilla::dom::EventTarget* aOwner, nsPresContext* aPresContext, mozilla::InternalClipboardEvent* aEvent); - +nsresult +NS_NewDOMInputEvent(nsIDOMEvent** aInstancePtrResult, + mozilla::dom::EventTarget* aOwner, + nsPresContext* aPresContext, + mozilla::InternalEditorInputEvent* aEvent); nsresult NS_NewDOMKeyboardEvent(nsIDOMEvent** aInstancePtrResult, mozilla::dom::EventTarget* aOwner, nsPresContext* aPresContext, mozilla::WidgetKeyboardEvent* aEvent); nsresult NS_NewDOMCompositionEvent(nsIDOMEvent** aInstancePtrResult, mozilla::dom::EventTarget* aOwner,
--- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -555,16 +555,18 @@ var interfaceNamesInGlobalScope = "IDBTransaction", // IMPORTANT: Do not change this list without review from a DOM peer! "IDBVersionChangeEvent", // IMPORTANT: Do not change this list without review from a DOM peer! "Image", // IMPORTANT: Do not change this list without review from a DOM peer! "ImageData", // IMPORTANT: Do not change this list without review from a DOM peer! + "InputEvent", +// IMPORTANT: Do not change this list without review from a DOM peer! {name: "InstallTrigger", b2g: false, xbl: false}, // IMPORTANT: Do not change this list without review from a DOM peer! "KeyEvent", // IMPORTANT: Do not change this list without review from a DOM peer! "KeyboardEvent", // IMPORTANT: Do not change this list without review from a DOM peer! "LocalMediaStream", // IMPORTANT: Do not change this list without review from a DOM peer!
new file mode 100644 --- /dev/null +++ b/dom/webidl/InputEvent.webidl @@ -0,0 +1,16 @@ +/* -*- Mode: IDL; tab-width: 2; 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/. + */ + +[Constructor(DOMString type, optional InputEventInit eventInitDict)] +interface InputEvent : UIEvent +{ + readonly attribute boolean isComposing; +}; + +dictionary InputEventInit : UIEventInit +{ + boolean isComposing = false; +};
--- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -202,16 +202,17 @@ WEBIDL_FILES = [ 'IDBKeyRange.webidl', 'IDBObjectStore.webidl', 'IDBOpenDBRequest.webidl', 'IDBRequest.webidl', 'IDBTransaction.webidl', 'IDBVersionChangeEvent.webidl', 'ImageData.webidl', 'ImageDocument.webidl', + 'InputEvent.webidl', 'InputMethod.webidl', 'InspectorUtils.webidl', 'InterAppConnection.webidl', 'InterAppConnectionRequest.webidl', 'InterAppMessagePort.webidl', 'KeyboardEvent.webidl', 'KeyEvent.webidl', 'LegacyQueryInterface.webidl',
--- a/editor/libeditor/base/nsEditor.cpp +++ b/editor/libeditor/base/nsEditor.cpp @@ -562,16 +562,27 @@ nsEditor::GetPresShell() { NS_PRECONDITION(mDocWeak, "bad state, null mDocWeak"); nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak); NS_ENSURE_TRUE(doc, nullptr); nsCOMPtr<nsIPresShell> ps = doc->GetShell(); return ps.forget(); } +already_AddRefed<nsIWidget> +nsEditor::GetWidget() +{ + nsCOMPtr<nsIPresShell> ps = GetPresShell(); + NS_ENSURE_TRUE(ps, nullptr); + nsPresContext* pc = ps->GetPresContext(); + NS_ENSURE_TRUE(pc, nullptr); + nsCOMPtr<nsIWidget> widget = pc->GetRootWidget(); + NS_ENSURE_TRUE(widget.get(), nullptr); + return widget.forget(); +} /* attribute string contentsMIMEType; */ NS_IMETHODIMP nsEditor::GetContentsMIMEType(char * *aContentsMIMEType) { NS_ENSURE_ARG_POINTER(aContentsMIMEType); *aContentsMIMEType = ToNewCString(mContentMIMEType); return NS_OK; @@ -1799,18 +1810,21 @@ nsEditor::RemoveEditorObserver(nsIEditor return NS_OK; } class EditorInputEventDispatcher : public nsRunnable { public: EditorInputEventDispatcher(nsEditor* aEditor, - nsIContent* aTarget) : - mEditor(aEditor), mTarget(aTarget) + nsIContent* aTarget, + bool aIsComposing) + : mEditor(aEditor) + , mTarget(aTarget) + , mIsComposing(aIsComposing) { } NS_IMETHOD Run() { // Note that we don't need to check mDispatchInputEvent here. We need // to check it only when the editor requests to dispatch the input event. @@ -1818,31 +1832,37 @@ public: return NS_OK; } nsCOMPtr<nsIPresShell> ps = mEditor->GetPresShell(); if (!ps) { return NS_OK; } + nsCOMPtr<nsIWidget> widget = mEditor->GetWidget(); + if (!widget) { + return NS_OK; + } + // Even if the change is caused by untrusted event, we need to dispatch // trusted input event since it's a fact. - WidgetEvent inputEvent(true, NS_FORM_INPUT); - inputEvent.mFlags.mCancelable = false; + InternalEditorInputEvent inputEvent(true, NS_EDITOR_INPUT, widget); inputEvent.time = static_cast<uint64_t>(PR_Now() / 1000); + inputEvent.mIsComposing = mIsComposing; nsEventStatus status = nsEventStatus_eIgnore; nsresult rv = ps->HandleEventWithTarget(&inputEvent, nullptr, mTarget, &status); NS_ENSURE_SUCCESS(rv, NS_OK); // print the warning if error return NS_OK; } private: nsRefPtr<nsEditor> mEditor; nsCOMPtr<nsIContent> mTarget; + bool mIsComposing; }; void nsEditor::NotifyEditorObservers(void) { for (int32_t i = 0; i < mEditorObservers.Count(); i++) { mEditorObservers[i]->EditAction(); } @@ -1859,18 +1879,21 @@ nsEditor::FireInputEvent() // We don't need to dispatch multiple input events if there is a pending // input event. However, it may have different event target. If we resolved // this issue, we need to manage the pending events in an array. But it's // overwork. We don't need to do it for the very rare case. nsCOMPtr<nsIContent> target = GetInputEventTargetContent(); NS_ENSURE_TRUE_VOID(target); + // NOTE: Don't refer IsIMEComposing() because it returns false even before + // compositionend. However, DOM Level 3 Events defines it should be + // true after compositionstart and before compositionend. nsContentUtils::AddScriptRunner( - new EditorInputEventDispatcher(this, target)); + new EditorInputEventDispatcher(this, target, !!GetComposition())); } NS_IMETHODIMP nsEditor::AddEditActionListener(nsIEditActionListener *aListener) { NS_ENSURE_TRUE(aListener, NS_ERROR_NULL_POINTER); // Make sure the listener isn't already on the list
--- a/editor/libeditor/base/nsEditor.h +++ b/editor/libeditor/base/nsEditor.h @@ -166,16 +166,17 @@ public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsEditor, nsIEditor) /* ------------ utility methods -------------- */ already_AddRefed<nsIDOMDocument> GetDOMDocument(); already_AddRefed<nsIDocument> GetDocument(); already_AddRefed<nsIPresShell> GetPresShell(); + already_AddRefed<nsIWidget> GetWidget(); void NotifyEditorObservers(); /* ------------ nsIEditor methods -------------- */ NS_DECL_NSIEDITOR /* ------------ nsIEditorIMESupport methods -------------- */ NS_DECL_NSIEDITORIMESUPPORT
--- a/widget/BasicEvents.h +++ b/widget/BasicEvents.h @@ -30,16 +30,17 @@ enum nsEventStructType NS_UI_EVENT, // InternalUIEvent // TextEvents.h NS_KEY_EVENT, // WidgetKeyboardEvent NS_COMPOSITION_EVENT, // WidgetCompositionEvent NS_TEXT_EVENT, // WidgetTextEvent NS_QUERY_CONTENT_EVENT, // WidgetQueryContentEvent NS_SELECTION_EVENT, // WidgetSelectionEvent + NS_EDITOR_INPUT_EVENT, // InternalEditorInputEvent // MouseEvents.h NS_MOUSE_EVENT, // WidgetMouseEvent NS_DRAG_EVENT, // WidgetDragEvent NS_MOUSE_SCROLL_EVENT, // WidgetMouseScrollEvent NS_WHEEL_EVENT, // WidgetWheelEvent NS_POINTER_EVENT, // PointerEvent @@ -161,18 +162,17 @@ enum nsEventStructType #define NS_PAGE_RESTORE (NS_STREAM_EVENT_START + 7) #define NS_READYSTATECHANGE (NS_STREAM_EVENT_START + 8) #define NS_FORM_EVENT_START 1200 #define NS_FORM_SUBMIT (NS_FORM_EVENT_START) #define NS_FORM_RESET (NS_FORM_EVENT_START + 1) #define NS_FORM_CHANGE (NS_FORM_EVENT_START + 2) #define NS_FORM_SELECTED (NS_FORM_EVENT_START + 3) -#define NS_FORM_INPUT (NS_FORM_EVENT_START + 4) -#define NS_FORM_INVALID (NS_FORM_EVENT_START + 5) +#define NS_FORM_INVALID (NS_FORM_EVENT_START + 4) //Need separate focus/blur notifications for non-native widgets #define NS_FOCUS_EVENT_START 1300 #define NS_FOCUS_CONTENT (NS_FOCUS_EVENT_START) #define NS_BLUR_CONTENT (NS_FOCUS_EVENT_START + 1) #define NS_DRAGDROP_EVENT_START 1400 #define NS_DRAGDROP_ENTER (NS_DRAGDROP_EVENT_START) @@ -468,16 +468,20 @@ enum nsEventStructType #define NS_GAMEPAD_BUTTONUP (NS_GAMEPAD_START+1) #define NS_GAMEPAD_AXISMOVE (NS_GAMEPAD_START+2) #define NS_GAMEPAD_CONNECTED (NS_GAMEPAD_START+3) #define NS_GAMEPAD_DISCONNECTED (NS_GAMEPAD_START+4) // Keep this defined to the same value as the event above #define NS_GAMEPAD_END (NS_GAMEPAD_START+4) #endif +// input and beforeinput events. +#define NS_EDITOR_EVENT_START 6100 +#define NS_EDITOR_INPUT (NS_EDITOR_EVENT_START) + namespace mozilla { /****************************************************************************** * mozilla::BaseEventFlags * * BaseEventFlags must be a POD struct for safe to use memcpy (including * in ParamTraits<BaseEventFlags>). So don't make virtual methods, constructor, * destructor and operators. @@ -1052,16 +1056,28 @@ public: * mozilla::InternalUIEvent * * XXX Why this inherits WidgetGUIEvent rather than WidgetEvent? ******************************************************************************/ class InternalUIEvent : public WidgetGUIEvent { protected: + InternalUIEvent() + : detail(0) + { + } + + InternalUIEvent(bool aIsTrusted, uint32_t aMessage, nsIWidget* aWidget, + nsEventStructType aStructType) + : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, aStructType) + , detail(0) + { + } + InternalUIEvent(bool aIsTrusted, uint32_t aMessage, nsEventStructType aStructType) : WidgetGUIEvent(aIsTrusted, aMessage, nullptr, aStructType) , detail(0) { } public:
--- a/widget/EventClassList.h +++ b/widget/EventClassList.h @@ -21,16 +21,17 @@ NS_EVENT_CLASS(Widget, InputEvent) NS_EVENT_CLASS(Internal, UIEvent) // TextEvents.h NS_EVENT_CLASS(Widget, KeyboardEvent) NS_EVENT_CLASS(Widget, TextEvent) NS_EVENT_CLASS(Widget, CompositionEvent) NS_EVENT_CLASS(Widget, QueryContentEvent) NS_EVENT_CLASS(Widget, SelectionEvent) +NS_EVENT_CLASS(Internal, EditorInputEvent) // MouseEvents.h NS_EVENT_CLASS(Widget, MouseEventBase) NS_EVENT_CLASS(Widget, MouseEvent) NS_EVENT_CLASS(Widget, DragEvent) NS_EVENT_CLASS(Widget, MouseScrollEvent) NS_EVENT_CLASS(Widget, WheelEvent) NS_EVENT_CLASS(Widget, PointerEvent)
--- a/widget/TextEvents.h +++ b/widget/TextEvents.h @@ -492,11 +492,67 @@ public: // Selection "anchor" should be in front bool mReversed; // Cluster-based or character-based bool mExpandToClusterBoundary; // true if setting selection succeeded. bool mSucceeded; }; +/****************************************************************************** + * mozilla::InternalEditorInputEvent + ******************************************************************************/ + +class InternalEditorInputEvent : public InternalUIEvent +{ +private: + InternalEditorInputEvent() + : mIsComposing(false) + { + } + +public: + virtual InternalEditorInputEvent* AsEditorInputEvent() MOZ_OVERRIDE + { + return this; + } + + InternalEditorInputEvent(bool aIsTrusted, uint32_t aMessage, + nsIWidget* aWidget) + : InternalUIEvent(aIsTrusted, aMessage, aWidget, NS_EDITOR_INPUT_EVENT) + , mIsComposing(false) + { + if (!aIsTrusted) { + mFlags.mBubbles = false; + mFlags.mCancelable = false; + return; + } + + mFlags.mBubbles = true; + mFlags.mCancelable = false; + } + + virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE + { + MOZ_ASSERT(eventStructType == NS_EDITOR_INPUT_EVENT, + "Duplicate() must be overridden by sub class"); + // Not copying widget, it is a weak reference. + InternalEditorInputEvent* result = + new InternalEditorInputEvent(false, message, nullptr); + result->AssignEditorInputEventData(*this, true); + result->mFlags = mFlags; + return result; + } + + bool mIsComposing; + + void AssignEditorInputEventData(const InternalEditorInputEvent& aEvent, + bool aCopyTargets) + { + AssignUIEventData(aEvent, aCopyTargets); + + mIsComposing = aEvent.mIsComposing; + } +}; + } // namespace mozilla #endif // mozilla_TextEvents_h__
--- a/widget/tests/test_assign_event_data.html +++ b/widget/tests/test_assign_event_data.html @@ -43,17 +43,17 @@ <div id="content" style="display: none"> </div> <pre id="test"> </pre> <script class="testbody" type="application/javascript"> SimpleTest.waitForExplicitFinish(); -SimpleTest.expectAssertions(0, 16); +SimpleTest.expectAssertions(0, 32); const kIsMac = (navigator.platform.indexOf("Mac") == 0); const kIsWin = (navigator.platform.indexOf("Win") == 0); var gEvent = null; var gCopiedEvent = []; var gCallback = null; var gCallPreventDefault = false; @@ -327,16 +327,70 @@ const kTests = [ }); synthesizeComposition({ type: "compositionend", data: "\u30E9\u30FC\u30E1\u30F3" }); }, canRun: function () { return true; }, todoMismatch: [ ], }, + { description: "InternalEditorInputEvent (input at key input)", + targetID: "input-text", eventType: "input", + dispatchEvent: function () { + document.getElementById(this.targetID).value = ""; + document.getElementById(this.targetID).focus(); + synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, kIsWin ? WIN_VK_B : MAC_VK_ANSI_B, + { shiftKey: true }, "B", "B"); + }, + canRun: function () { + return (kIsMac || kIsWin); + }, + todoMismatch: [], + }, + { description: "InternalEditorInputEvent (input at composing)", + targetID: "input-text", eventType: "input", + dispatchEvent: function () { + document.getElementById(this.targetID).value = ""; + document.getElementById(this.targetID).focus(); + synthesizeComposition({ type: "compositionstart" }); + synthesizeComposition({ type: "compositionupdate", data: "\u30E9\u30FC\u30E1\u30F3" }); + synthesizeText({ "composition": + { "string": "\u30E9\u30FC\u30E1\u30F3", + "clauses": + [ + { "length": 4, "attr": COMPOSITION_ATTR_RAWINPUT } + ] + }, + "caret": { "start": 4, "length": 0 } + }); + }, + canRun: function () { + return true; + }, + todoMismatch: [ ], + }, + { description: "InternalEditorInputEvent (input at committing)", + targetID: "input-text", eventType: "input", + dispatchEvent: function () { + synthesizeText({ "composition": + { "string": "\u30E9\u30FC\u30E1\u30F3", + "clauses": + [ + { "length": 0, "attr": 0 } + ] + }, + "caret": { "start": 4, "length": 0 } + }); + synthesizeComposition({ type: "compositionend", data: "\u30E9\u30FC\u30E1\u30F3" }); + }, + canRun: function () { + return true; + }, + todoMismatch: [ ], + }, { description: "WidgetMouseScrollEvent (DOMMouseScroll, vertical)", targetID: "input-text", eventType: "DOMMouseScroll", dispatchEvent: function () { document.getElementById(this.targetID).value = ""; synthesizeWheel(document.getElementById(this.targetID), 3, 4, { deltaY: 30, lineOrPageDeltaY: 2 }); }, canRun: function () {
--- a/widget/tests/window_composition_text_querycontent.xul +++ b/widget/tests/window_composition_text_querycontent.xul @@ -2794,23 +2794,29 @@ function runBug811755Test() function runIsComposingTest() { var expectedIsComposing = false; var descriptionBase = "runIsComposingTest: "; var description = ""; function eventHandler(aEvent) { - is(aEvent.isComposing, expectedIsComposing, - "runIsComposingTest: " + description + " (type=" + aEvent.type + ", key=" + aEvent.key + ")"); + if (aEvent.type == "keydown" || aEvent.type == "keyup") { + is(aEvent.isComposing, expectedIsComposing, + "runIsComposingTest: " + description + " (type=" + aEvent.type + ", key=" + aEvent.key + ")"); + } else { + is(aEvent.isComposing, expectedIsComposing, + "runIsComposingTest: " + description + " (type=" + aEvent.type + ")"); + } } textarea.addEventListener("keydown", eventHandler, true); textarea.addEventListener("keypress", eventHandler, true); textarea.addEventListener("keyup", eventHandler, true); + textarea.addEventListener("input", eventHandler, true); textarea.focus(); textarea.value = ""; // XXX These cases shouldn't occur in actual native key events because we // don't dispatch key events while composition (bug 354358). expectedIsComposing = false; description = "events before dispatching compositionstart"; @@ -2843,25 +2849,28 @@ function runIsComposingTest() { "string": "\u3042", "clauses": [ { "length": 0, "attr": 0 } ] }, "caret": { "start": 1, "length": 0 } }); - synthesizeComposition({ type: "compositionend" }); - + + // input event will be fired by synthesizing compositionend event. + // Then, its isComposing should be false. expectedIsComposing = false; description = "events after dispatching compositionend"; + synthesizeComposition({ type: "compositionend" }); synthesizeKey("VK_RETURN", { type: "keyup" }); textarea.removeEventListener("keydown", eventHandler, true); textarea.removeEventListener("keypress", eventHandler, true); textarea.removeEventListener("keyup", eventHandler, true); + textarea.removeEventListener("input", eventHandler, true); textarea.value = ""; } function runRemoveContentTest(aCallback) { var events = []; function eventHandler(aEvent)
--- a/widget/xpwidgets/nsBaseWidget.cpp +++ b/widget/xpwidgets/nsBaseWidget.cpp @@ -1608,20 +1608,20 @@ case _value: eventName.AssignLiteral(_na switch(aGuiEvent->message) { _ASSIGN_eventName(NS_BLUR_CONTENT,"NS_BLUR_CONTENT"); _ASSIGN_eventName(NS_DRAGDROP_GESTURE,"NS_DND_GESTURE"); _ASSIGN_eventName(NS_DRAGDROP_DROP,"NS_DND_DROP"); _ASSIGN_eventName(NS_DRAGDROP_ENTER,"NS_DND_ENTER"); _ASSIGN_eventName(NS_DRAGDROP_EXIT,"NS_DND_EXIT"); _ASSIGN_eventName(NS_DRAGDROP_OVER,"NS_DND_OVER"); + _ASSIGN_eventName(NS_EDITOR_INPUT,"NS_EDITOR_INPUT"); _ASSIGN_eventName(NS_FOCUS_CONTENT,"NS_FOCUS_CONTENT"); _ASSIGN_eventName(NS_FORM_SELECTED,"NS_FORM_SELECTED"); _ASSIGN_eventName(NS_FORM_CHANGE,"NS_FORM_CHANGE"); - _ASSIGN_eventName(NS_FORM_INPUT,"NS_FORM_INPUT"); _ASSIGN_eventName(NS_FORM_RESET,"NS_FORM_RESET"); _ASSIGN_eventName(NS_FORM_SUBMIT,"NS_FORM_SUBMIT"); _ASSIGN_eventName(NS_IMAGE_ABORT,"NS_IMAGE_ABORT"); _ASSIGN_eventName(NS_LOAD_ERROR,"NS_LOAD_ERROR"); _ASSIGN_eventName(NS_KEY_DOWN,"NS_KEY_DOWN"); _ASSIGN_eventName(NS_KEY_PRESS,"NS_KEY_PRESS"); _ASSIGN_eventName(NS_KEY_UP,"NS_KEY_UP"); _ASSIGN_eventName(NS_MOUSE_ENTER,"NS_MOUSE_ENTER");