author | Ehsan Akhgari <ehsan@mozilla.com> |
Tue, 07 Dec 2010 01:30:05 -0500 | |
changeset 59460 | 83f76e76d7803b8f2a6ca1a72bbd1263875c4fab |
parent 59459 | acb2f28f8e128d20858f68cb8b850e599fda7029 |
child 59461 | 839bb8d210a9b62a1728386cdcd579fa429eb8e8 |
push id | unknown |
push user | unknown |
push date | unknown |
reviewers | roc, blocking-final |
bugs | 527935 |
milestone | 2.0b9pre |
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/src/nsTextEditorState.cpp +++ b/content/html/content/src/nsTextEditorState.cpp @@ -879,17 +879,21 @@ nsTextInputListener::EditAction() // no undo items; JS could change the value and we'd still need to save it) mFrame->SetValueChanged(PR_TRUE); if (!mSettingValue) { mTxtCtrlElement->OnValueChanged(PR_TRUE); } // Fire input event - mFrame->FireOnInput(); + nsCOMPtr<nsIEditor_MOZILLA_2_0_BRANCH> editor20 = do_QueryInterface(editor); + NS_ASSERTION(editor20, "Something is very wrong!"); + PRBool trusted = PR_FALSE; + editor20->GetLastKeypressEventTrusted(&trusted); + mFrame->FireOnInput(trusted); return NS_OK; } // END nsIEditorObserver nsresult
--- a/editor/idl/nsIEditor.idl +++ b/editor/idl/nsIEditor.idl @@ -578,8 +578,19 @@ interface nsIEditor : nsISupports void debugDumpContent() ; /* Run unit tests. Noop in optimized builds */ void debugUnitTests(out long outNumTests, out long outNumTestsFailed); /* checks if a node is read-only or not */ [notxpcom] boolean isModifiableNode(in nsIDOMNode aNode); }; + +[uuid(54c0bc08-6c0e-4967-bb0d-ec991d78a8b3)] +interface nsIEditor_MOZILLA_2_0_BRANCH : nsISupports +{ + /** + * Will be set to true if the last keypress event that the editor has handled + * has been trusted. The value will only be valid when the edit action listeners + * are being called, and will throw upon access at all other times. + */ + readonly attribute boolean lastKeypressEventTrusted; +};
--- a/editor/libeditor/base/nsEditor.cpp +++ b/editor/libeditor/base/nsEditor.cpp @@ -157,16 +157,17 @@ nsEditor::nsEditor() , mIMEBufferLength(0) , mInIMEMode(PR_FALSE) , mIsIMEComposing(PR_FALSE) , mShouldTxnSetSelection(PR_TRUE) , mDidPreDestroy(PR_FALSE) , mDocDirtyState(-1) , mDocWeak(nsnull) , mPhonetic(nsnull) +, mLastKeypressEventWasTrusted(eTriUnset) { //initialize member variables here } nsEditor::~nsEditor() { NS_ASSERTION(!mDocWeak || mDidPreDestroy, "Why PreDestroy hasn't been called?"); @@ -199,16 +200,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN( NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mActionListeners) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mEditorObservers) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mDocStateListeners) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mEventTarget) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mEventListener) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsEditor) + NS_INTERFACE_MAP_ENTRY(nsIEditor_MOZILLA_2_0_BRANCH) NS_INTERFACE_MAP_ENTRY(nsIPhonetic) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_ENTRY(nsIEditorIMESupport) NS_INTERFACE_MAP_ENTRY(nsIEditor) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIEditor) NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsEditor, nsIEditor) @@ -5302,8 +5304,33 @@ nsEditor::IsAcceptableInputEvent(nsIDOME NS_ENSURE_SUCCESS(rv, PR_FALSE); if (isTrusted) { return PR_TRUE; } // Otherwise, we shouldn't handle any input events when we're not an active // element of the DOM window. return IsActiveInDOMWindow(); } + +NS_IMETHODIMP +nsEditor::GetLastKeypressEventTrusted(PRBool *aWasTrusted) +{ + NS_ENSURE_ARG_POINTER(aWasTrusted); + + if (mLastKeypressEventWasTrusted == eTriUnset) { + return NS_ERROR_UNEXPECTED; + } + + *aWasTrusted = (mLastKeypressEventWasTrusted == eTriTrue); + return NS_OK; +} + +void +nsEditor::BeginKeypressHandling(nsIDOMNSEvent* aEvent) +{ + NS_ASSERTION(mLastKeypressEventWasTrusted == eTriUnset, "How come our status is not clear?"); + + if (aEvent) { + PRBool isTrusted = PR_FALSE; + aEvent->GetIsTrusted(&isTrusted); + mLastKeypressEventWasTrusted = isTrusted ? eTriTrue : eTriFalse; + } +}
--- a/editor/libeditor/base/nsEditor.h +++ b/editor/libeditor/base/nsEditor.h @@ -82,29 +82,31 @@ class EditAggregateTxn; class IMETextTxn; class AddStyleSheetTxn; class RemoveStyleSheetTxn; class nsIFile; class nsISelectionController; class nsIDOMEventTarget; class nsCSSStyleSheet; class nsKeyEvent; +class nsIDOMNSEvent; #define kMOZEditorBogusNodeAttrAtom nsEditProperty::mozEditorBogusNode #define kMOZEditorBogusNodeValue NS_LITERAL_STRING("TRUE") /** implementation of an editor object. it will be the controller/focal point * for the main editor services. i.e. the GUIManager, publishing, transaction * manager, event interfaces. the idea for the event interfaces is to have them * delegate the actual commands to the editor independent of the XPFE implementation. */ class nsEditor : public nsIEditor, public nsIEditorIMESupport, public nsSupportsWeakReference, - public nsIPhonetic + public nsIPhonetic, + public nsIEditor_MOZILLA_2_0_BRANCH { public: enum IterDirection { kIterForward, kIterBackward }; @@ -150,16 +152,19 @@ public: /* ------------ nsIEditor methods -------------- */ NS_DECL_NSIEDITOR /* ------------ nsIEditorIMESupport methods -------------- */ NS_DECL_NSIEDITORIMESUPPORT // nsIPhonetic NS_DECL_NSIPHONETIC + // nsIEditor_MOZILLA_2_0_BRANCH + NS_DECL_NSIEDITOR_MOZILLA_2_0_BRANCH + public: NS_IMETHOD InsertTextImpl(const nsAString& aStringToInsert, nsCOMPtr<nsIDOMNode> *aInOutNode, PRInt32 *aInOutOffset, nsIDOMDocument *aDoc); nsresult InsertTextIntoTextNodeImpl(const nsAString& aStringToInsert, @@ -194,16 +199,19 @@ public: nsresult CreateHTMLContent(const nsAString& aTag, nsIContent** aContent); // IME event handlers virtual nsresult BeginIMEComposition(); virtual nsresult UpdateIMEComposition(const nsAString &aCompositionString, nsIPrivateTextRangeList *aTextRange)=0; nsresult EndIMEComposition(); + void BeginKeypressHandling(nsIDOMNSEvent* aEvent); + void EndKeypressHandling() { mLastKeypressEventWasTrusted = eTriUnset; } + protected: nsCString mContentMIMEType; // MIME type of the doc we are editing. /** create a transaction for setting aAttribute to aValue on aElement */ NS_IMETHOD CreateTxnForSetAttribute(nsIDOMElement *aElement, const nsAString & aAttribute, const nsAString & aValue, @@ -741,16 +749,18 @@ protected: nsWeakPtr mDocWeak; // weak reference to the nsIDOMDocument // The form field as an event receiver nsCOMPtr<nsPIDOMEventTarget> mEventTarget; nsString* mPhonetic; nsCOMPtr<nsIDOMEventListener> mEventListener; + Tristate mLastKeypressEventWasTrusted; + friend PRBool NSCanUnload(nsISupports* serviceMgr); friend class nsAutoTxnsConserveSelection; friend class nsAutoSelectionReset; friend class nsAutoRules; friend class nsRangeUpdater; };
--- a/editor/libeditor/base/nsEditorEventListener.cpp +++ b/editor/libeditor/base/nsEditorEventListener.cpp @@ -73,16 +73,30 @@ #include "nsIDOMEventTarget.h" #include "nsIEventStateManager.h" #include "nsISelectionPrivate.h" #include "nsIDOMDragEvent.h" #include "nsIFocusManager.h" #include "nsIDOMWindow.h" #include "nsContentUtils.h" +class nsAutoEditorKeypressOperation { +public: + nsAutoEditorKeypressOperation(nsEditor *aEditor, nsIDOMNSEvent *aEvent) + : mEditor(aEditor) { + mEditor->BeginKeypressHandling(aEvent); + } + ~nsAutoEditorKeypressOperation() { + mEditor->EndKeypressHandling(); + } + +private: + nsEditor *mEditor; +}; + nsEditorEventListener::nsEditorEventListener() : mEditor(nsnull), mCaretDrawn(PR_FALSE), mCommitText(PR_FALSE), mInTransaction(PR_FALSE) { } nsEditorEventListener::~nsEditorEventListener() { @@ -315,16 +329,20 @@ NS_IMETHODIMP nsEditorEventListener::KeyPress(nsIDOMEvent* aKeyEvent) { NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE); if (!mEditor->IsAcceptableInputEvent(aKeyEvent)) { return NS_OK; } + // Transfer the event's trusted-ness to our editor + nsCOMPtr<nsIDOMNSEvent> NSEvent = do_QueryInterface(aKeyEvent); + nsAutoEditorKeypressOperation operation(mEditor, NSEvent); + // DOM event handling happens in two passes, the client pass and the system // pass. We do all of our processing in the system pass, to allow client // handlers the opportunity to cancel events and prevent typing in the editor. // If the client pass cancelled the event, defaultPrevented will be true // below. nsCOMPtr<nsIDOMNSUIEvent> UIEvent = do_QueryInterface(aKeyEvent); if(UIEvent) {
--- a/editor/libeditor/text/tests/Makefile.in +++ b/editor/libeditor/text/tests/Makefile.in @@ -41,16 +41,17 @@ srcdir = @srcdir@ VPATH = @srcdir@ relativesrcdir = editor/libeditor/text/tests include $(DEPTH)/config/autoconf.mk include $(topsrcdir)/config/rules.mk _TEST_FILES = \ test_bug471722.html \ + test_bug527935.html \ test_bug569988.html \ test_bug590554.html \ test_bug596001.html \ test_bug596333.html \ test_bug596506.html \ test_bug597331.html \ test_bug600570.html \ test_bug602130.html \
new file mode 100644 --- /dev/null +++ b/editor/libeditor/text/tests/test_bug527935.html @@ -0,0 +1,84 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=527935 +--> +<head> + <title>Test for Bug 527935</title> + <script type="application/javascript" src="/MochiKit/packed.js"></script> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=527935">Mozilla Bug 527935</a> +<p id="display"></p> +<div id="content"> + <iframe id="formTarget" name="formTarget"></iframe> + <form action="data:text/html," target="formTarget"> + <input name="test" id="initValue"><input type="submit"> + </form> +</div> +<pre id="test"> +<script type="application/javascript"> + +function getAutocompletePopup() { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + var Ci = Components.interfaces; + chromeWin = window.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShellTreeItem) + .rootTreeItem + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindow) + .QueryInterface(Ci.nsIDOMChromeWindow); + autocompleteMenu = chromeWin.document.getElementById("PopupAutoComplete"); + ok(autocompleteMenu, "Got autocomplete popup"); + + return autocompleteMenu; +} + +/** Test for Bug 527935 **/ +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + var formTarget = document.getElementById("formTarget"); + var initValue = document.getElementById("initValue"); + + formTarget.addEventListener("load", function() { + var newInput = document.createElement("input"); + newInput.setAttribute("name", "test"); + document.body.appendChild(newInput); + + setTimeout(function() { + var popupShown = false; + var popup = getAutocompletePopup(); + function listener() { + popupShown = true; + } + popup.addEventListener("popupshowing", listener, false); + + var event = document.createEvent("KeyboardEvent"); + + event.initKeyEvent("keypress", true, true, null, false, false, + false, false, 0, "f".charCodeAt(0)); + newInput.value = ""; + newInput.focus(); + newInput.dispatchEvent(event); + + setTimeout(function() { + ok(!popupShown, "Popup must not be opened"); + popup.removeEventListener("popupshowing", listener, false); + SimpleTest.finish(); + }, 1000); + }, 0); + }, false); + + initValue.focus(); + initValue.value = "foo"; + synthesizeKey("VK_ENTER", {}); +}); + +</script> +</pre> +</body> +</html>
--- a/layout/forms/nsTextControlFrame.cpp +++ b/layout/forms/nsTextControlFrame.cpp @@ -1325,24 +1325,24 @@ nsTextControlFrame::GetMaxLength(PRInt32 return PR_TRUE; } } return PR_FALSE; } // this is where we propagate a content changed event void -nsTextControlFrame::FireOnInput() +nsTextControlFrame::FireOnInput(PRBool aTrusted) { if (!mNotifyOnInput) return; // if notification is turned off, do nothing // Dispatch the "input" event nsEventStatus status = nsEventStatus_eIgnore; - nsUIEvent event(PR_TRUE, NS_FORM_INPUT, 0); + nsUIEvent event(aTrusted, NS_FORM_INPUT, 0); // Have the content handle the event, propagating it according to normal // DOM rules. nsCOMPtr<nsIPresShell> shell = PresContext()->PresShell(); shell->HandleEventWithTarget(&event, nsnull, mContent, &status); } nsresult
--- a/layout/forms/nsTextControlFrame.h +++ b/layout/forms/nsTextControlFrame.h @@ -164,17 +164,17 @@ public: nsIAtom* aAttribute, PRInt32 aModType); nsresult GetText(nsString& aText); NS_DECL_QUERYFRAME public: //for methods who access nsTextControlFrame directly - void FireOnInput(); + void FireOnInput(PRBool aTrusted); void SetValueChanged(PRBool aValueChanged); /** Called when the frame is focused, to remember the value for onChange. */ nsresult InitFocusedValue(); void SetFireChangeEventState(PRBool aNewState) { mFireChangeEventState = aNewState; }