bug 514212 - Typed letters in password fields become asterisks immediately r=neil
--- a/editor/libeditor/text/nsTextEditRules.cpp
+++ b/editor/libeditor/text/nsTextEditRules.cpp
@@ -58,16 +58,18 @@
#include "nsEditorUtils.h"
#include "EditTxn.h"
#include "nsIPrefBranch.h"
#include "nsIPrefService.h"
#include "nsUnicharUtils.h"
#include "nsILookAndFeel.h"
#include "nsWidgetsCID.h"
#include "DeleteTextTxn.h"
+#include "nsNodeIterator.h"
+#include "nsIDOMNodeFilter.h"
// for IBMBIDI
#include "nsIPresShell.h"
#include "nsFrameSelection.h"
static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
#define CANCEL_OPERATION_IF_READONLY_OR_DISABLED \
@@ -654,18 +656,42 @@ nsTextEditRules::WillInsertText(PRInt32
break;
}
outString->Assign(tString);
}
if (mFlags & nsIPlaintextEditor::eEditorPasswordMask)
{
- res = EchoInsertionToPWBuff(start, end, outString);
- if (NS_FAILED(res)) return res;
+ // manage the password buffer
+ mPasswordText.Insert(*outString, start);
+
+ nsCOMPtr<nsILookAndFeel> lookAndFeel = do_GetService(kLookAndFeelCID);
+ if (lookAndFeel->GetEchoPassword()) {
+ if (mPasswordText.Length() > outString->Length()) {
+ HideLastPWInput();
+ }
+ mLastStart = start;
+ mLastLength = outString->Length();
+ if (mTimer)
+ {
+ mTimer->Cancel();
+ }
+ else
+ {
+ mTimer = do_CreateInstance("@mozilla.org/timer;1", &res);
+ if (NS_FAILED(res)) return res;
+ }
+ mTimer->InitWithCallback(this, 600, nsITimer::TYPE_ONE_SHOT);
+ }
+ else
+ {
+ res = FillBufWithPWChars(outString, outString->Length());
+ if (NS_FAILED(res)) return res;
+ }
}
// get the (collapsed) selection location
nsCOMPtr<nsIDOMNode> selNode;
PRInt32 selOffset;
res = mEditor->GetStartNodeAndOffset(aSelection, address_of(selNode), &selOffset);
if (NS_FAILED(res)) return res;
@@ -1362,39 +1388,73 @@ nsTextEditRules::RemoveIMETextFromPWBuf(
mPasswordText.Cut(mPasswordIMEIndex, mPasswordIMEText.Length());
aStart = mPasswordIMEIndex;
}
mPasswordIMEText.Assign(*aIMEString);
return NS_OK;
}
+NS_IMETHODIMP nsTextEditRules::Notify(class nsITimer *) {
+ return HideLastPWInput();
+}
+
+nsresult nsTextEditRules::HideLastPWInput() {
+ nsCOMPtr<nsIDOMNode> selNode;
+ nsCOMPtr<nsISelection> selection;
+ PRInt32 selOffset;
+ PRUint32 start, end;
+ nsresult res = mEditor->GetSelection(getter_AddRefs(selection));
+ if (NS_FAILED(res)) return res;
+ res = mEditor->GetTextSelectionOffsets(selection, start, end);
+ if (NS_FAILED(res)) return res;
+ res = mEditor->GetStartNodeAndOffset(selection, address_of(selNode), &selOffset);
+ if (NS_FAILED(res)) return res;
+ if (!mEditor->IsTextNode(selNode)) {
+ // Get an nsINode from the nsIDOMNode
+ nsCOMPtr<nsINode> node = do_QueryInterface(selNode);
+ // if node is null, return NS_OK because there's no text to hide
+ if (!node) return NS_OK;
+ // This should be the root node, walk the tree looking for text nodes
+ nsNodeIterator iter(node, nsIDOMNodeFilter::SHOW_TEXT, nsnull, PR_TRUE);
+ while (!mEditor->IsTextNode(selNode)) {
+ if (NS_FAILED(res = iter.NextNode(getter_AddRefs(selNode))) ||
+ selNode == nsnull) {
+ return NS_SUCCEEDED(res) ? NS_ERROR_NULL_POINTER : res;
+ }
+ }
+ }
+ nsCOMPtr<nsIDOMCharacterData> nodeAsText(do_QueryInterface(selNode));
+ if (!nodeAsText) return NS_ERROR_FAILURE;
+ nsAutoString hiddenText;
+ FillBufWithPWChars(&hiddenText, mLastLength);
+ nodeAsText->ReplaceData(mLastStart, mLastLength, hiddenText);
+ selection->Collapse(selNode, start);
+ if (start != end)
+ selection->Extend(selNode, end);
+ return NS_OK;
+}
+
nsresult
-nsTextEditRules::EchoInsertionToPWBuff(PRInt32 aStart, PRInt32 aEnd, nsAString *aOutString)
+nsTextEditRules::FillBufWithPWChars(nsAString *aOutString, PRInt32 aLength)
{
if (!aOutString) {return NS_ERROR_NULL_POINTER;}
- // manage the password buffer
- mPasswordText.Insert(*aOutString, aStart);
-
// change the output to the platform password character
PRUnichar passwordChar = PRUnichar('*');
nsCOMPtr<nsILookAndFeel> lookAndFeel = do_GetService(kLookAndFeelCID);
if (lookAndFeel)
{
passwordChar = lookAndFeel->GetPasswordCharacter();
}
- PRInt32 length = aOutString->Length();
PRInt32 i;
aOutString->Truncate();
- for (i=0; i<length; i++)
- {
+ for (i=0; i < aLength; i++)
aOutString->Append(passwordChar);
- }
return NS_OK;
}
///////////////////////////////////////////////////////////////////////////
// CreateMozBR: put a BR node with moz attribute at {aNode, aOffset}
//
--- a/editor/libeditor/text/nsTextEditRules.h
+++ b/editor/libeditor/text/nsTextEditRules.h
@@ -39,33 +39,35 @@
#define nsTextEditRules_h__
#include "nsCOMPtr.h"
#include "nsPlaintextEditor.h"
#include "nsIDOMNode.h"
#include "nsEditRules.h"
+#include "nsITimer.h"
/** Object that encapsulates HTML text-specific editing rules.
*
* To be a good citizen, edit rules must live by these restrictions:
* 1. All data manipulation is through the editor.
* Content nodes in the document tree must <B>not</B> be manipulated directly.
* Content nodes in document fragments that are not part of the document itself
* may be manipulated at will. Operations on document fragments must <B>not</B>
* go through the editor.
* 2. Selection must not be explicitly set by the rule method.
* Any manipulation of Selection must be done by the editor.
*/
-class nsTextEditRules : public nsIEditRules
+class nsTextEditRules : public nsIEditRules, public nsITimerCallback
{
public:
+ NS_DECL_NSITIMERCALLBACK
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
- NS_DECL_CYCLE_COLLECTION_CLASS(nsTextEditRules)
+ NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsTextEditRules, nsIEditRules)
nsTextEditRules();
virtual ~nsTextEditRules();
// nsIEditRules methods
NS_IMETHOD Init(nsPlaintextEditor *aEditor, PRUint32 aFlags);
NS_IMETHOD DetachEditor();
NS_IMETHOD BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection);
@@ -181,29 +183,31 @@ protected:
over aMaxLength */
nsresult TruncateInsertionIfNeeded(nsISelection *aSelection,
const nsAString *aInString,
nsAString *aOutString,
PRInt32 aMaxLength);
/** Echo's the insertion text into the password buffer, and converts
insertion text to '*'s */
- nsresult EchoInsertionToPWBuff(PRInt32 aStart, PRInt32 aEnd, nsAString *aOutString);
+ nsresult FillBufWithPWChars(nsAString *aOutString, PRInt32 aLength);
/** Remove IME composition text from password buffer */
nsresult RemoveIMETextFromPWBuf(PRUint32 &aStart, nsAString *aIMEString);
nsresult CreateMozBR(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outBRNode);
nsresult CheckBidiLevelForDeletion(nsISelection *aSelection,
nsIDOMNode *aSelNode,
PRInt32 aSelOffset,
nsIEditor::EDirection aAction,
PRBool *aCancel);
+ nsresult HideLastPWInput();
+
// data members
nsPlaintextEditor *mEditor; // note that we do not refcount the editor
nsString mPasswordText; // a buffer we use to store the real value of password editors
nsString mPasswordIMEText; // a buffer we use to track the IME composition string
PRUint32 mPasswordIMEIndex;
nsCOMPtr<nsIDOMNode> mBogusNode; // magic node acts as placeholder in empty doc
nsCOMPtr<nsIDOMNode> mCachedSelectionNode; // cached selected node
PRInt32 mCachedSelectionOffset; // cached selected offset
@@ -211,16 +215,19 @@ protected:
PRUint32 mActionNesting;
PRPackedBool mLockRulesSniffing;
PRPackedBool mDidExplicitlySetInterline;
PRPackedBool mDeleteBidiImmediately; // in bidirectional text, delete
// characters not visually
// adjacent to the caret without
// moving the caret first.
PRInt32 mTheAction; // the top level editor action
+ nsCOMPtr<nsITimer> mTimer;
+ PRUint32 mLastStart, mLastLength;
+
// friends
friend class nsAutoLockRulesSniffing;
};
class nsTextRulesInfo : public nsRulesInfo
--- a/widget/public/nsILookAndFeel.h
+++ b/widget/public/nsILookAndFeel.h
@@ -366,16 +366,25 @@ public:
NS_IMETHOD GetColor(const nsColorID aID, nscolor &aColor) = 0;
NS_IMETHOD GetMetric(const nsMetricID aID, PRInt32 & aMetric) = 0;
NS_IMETHOD GetMetric(const nsMetricFloatID aID, float & aMetric) = 0;
virtual PRUnichar GetPasswordCharacter()
{
return PRUnichar('*');
}
+ virtual PRBool GetEchoPassword()
+ {
+#ifdef MOZ_GFX_OPTIMIZE_MOBILE
+ return PR_TRUE;
+#else
+ return PR_FALSE;
+#endif
+ }
+
NS_IMETHOD LookAndFeelChanged() = 0;
#ifdef NS_DEBUG
typedef enum {
eMetricSize_TextField = 0,
eMetricSize_TextArea = 1,
eMetricSize_ListBox = 2,