Bug 1340483 - Part 1. Create empty anonymous node for autofill preview. r=heycam
MozReview-Commit-ID: GTVgIPoogp9
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -2886,16 +2886,37 @@ HTMLInputElement::GetPlaceholderVisibili
nsTextEditorState* state = GetEditorState();
if (!state) {
return false;
}
return state->GetPlaceholderVisibility();
}
+NS_IMETHODIMP_(Element*)
+HTMLInputElement::CreatePreviewNode()
+{
+ nsTextEditorState* state = GetEditorState();
+ if (state) {
+ NS_ENSURE_SUCCESS(state->CreatePreviewNode(), nullptr);
+ return state->GetPreviewNode();
+ }
+ return nullptr;
+}
+
+NS_IMETHODIMP_(Element*)
+HTMLInputElement::GetPreviewNode()
+{
+ nsTextEditorState* state = GetEditorState();
+ if (state) {
+ return state->GetPreviewNode();
+ }
+ return nullptr;
+}
+
void
HTMLInputElement::GetDisplayFileName(nsAString& aValue) const
{
if (OwnerDoc()->IsStaticDocument()) {
aValue = mStaticDocFileList;
return;
}
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -229,16 +229,18 @@ public:
NS_IMETHOD_(nsISelectionController*) GetSelectionController() override;
NS_IMETHOD_(nsFrameSelection*) GetConstFrameSelection() override;
NS_IMETHOD BindToFrame(nsTextControlFrame* aFrame) override;
NS_IMETHOD_(void) UnbindFromFrame(nsTextControlFrame* aFrame) override;
NS_IMETHOD CreateEditor() override;
NS_IMETHOD_(Element*) GetRootEditorNode() override;
NS_IMETHOD_(Element*) CreatePlaceholderNode() override;
NS_IMETHOD_(Element*) GetPlaceholderNode() override;
+ NS_IMETHOD_(Element*) CreatePreviewNode() override;
+ NS_IMETHOD_(Element*) GetPreviewNode() override;
NS_IMETHOD_(void) UpdatePlaceholderVisibility(bool aNotify) override;
NS_IMETHOD_(bool) GetPlaceholderVisibility() override;
NS_IMETHOD_(void) InitializeKeyboardEventListeners() override;
NS_IMETHOD_(void) OnValueChanged(bool aNotify, bool aWasInteractiveUserChange) override;
virtual void GetValueFromSetRangeText(nsAString& aValue) override;
virtual nsresult SetValueFromSetRangeText(const nsAString& aValue) override;
NS_IMETHOD_(bool) HasCachedSelection() override;
--- a/dom/html/HTMLTextAreaElement.cpp
+++ b/dom/html/HTMLTextAreaElement.cpp
@@ -315,16 +315,30 @@ HTMLTextAreaElement::UpdatePlaceholderVi
}
NS_IMETHODIMP_(bool)
HTMLTextAreaElement::GetPlaceholderVisibility()
{
return mState.GetPlaceholderVisibility();
}
+NS_IMETHODIMP_(Element*)
+HTMLTextAreaElement::CreatePreviewNode()
+{
+ NS_ENSURE_SUCCESS(mState.CreatePreviewNode(), nullptr);
+ return mState.GetPreviewNode();
+}
+
+NS_IMETHODIMP_(Element*)
+HTMLTextAreaElement::GetPreviewNode()
+{
+ return mState.GetPreviewNode();
+}
+
+
nsresult
HTMLTextAreaElement::SetValueInternal(const nsAString& aValue,
uint32_t aFlags)
{
// Need to set the value changed flag here if our value has in fact changed
// (i.e. if eSetValue_Notify is in aFlags), so that
// nsTextControlFrame::UpdateValueDisplay retrieves the correct value if
// needed.
--- a/dom/html/HTMLTextAreaElement.h
+++ b/dom/html/HTMLTextAreaElement.h
@@ -98,16 +98,18 @@ public:
NS_IMETHOD_(nsISelectionController*) GetSelectionController() override;
NS_IMETHOD_(nsFrameSelection*) GetConstFrameSelection() override;
NS_IMETHOD BindToFrame(nsTextControlFrame* aFrame) override;
NS_IMETHOD_(void) UnbindFromFrame(nsTextControlFrame* aFrame) override;
NS_IMETHOD CreateEditor() override;
NS_IMETHOD_(Element*) GetRootEditorNode() override;
NS_IMETHOD_(Element*) CreatePlaceholderNode() override;
NS_IMETHOD_(Element*) GetPlaceholderNode() override;
+ NS_IMETHOD_(Element*) CreatePreviewNode() override;
+ NS_IMETHOD_(Element*) GetPreviewNode() override;
NS_IMETHOD_(void) UpdatePlaceholderVisibility(bool aNotify) override;
NS_IMETHOD_(bool) GetPlaceholderVisibility() override;
NS_IMETHOD_(void) InitializeKeyboardEventListeners() override;
NS_IMETHOD_(void) OnValueChanged(bool aNotify, bool aWasInteractiveUserChange) override;
virtual void GetValueFromSetRangeText(nsAString& aValue) override;
virtual nsresult SetValueFromSetRangeText(const nsAString& aValue) override;
NS_IMETHOD_(bool) HasCachedSelection() override;
--- a/dom/html/nsITextControlElement.h
+++ b/dom/html/nsITextControlElement.h
@@ -150,16 +150,26 @@ public:
NS_IMETHOD_(mozilla::dom::Element*) CreatePlaceholderNode() = 0;
/**
* Get the placeholder anonymous node for the text control.
*/
NS_IMETHOD_(mozilla::dom::Element*) GetPlaceholderNode() = 0;
/**
+ * Create the preview anonymous node for the text control and returns it.
+ */
+ NS_IMETHOD_(mozilla::dom::Element*) CreatePreviewNode() = 0;
+
+ /**
+ * Get the preview anonymous node for the text control.
+ */
+ NS_IMETHOD_(mozilla::dom::Element*) GetPreviewNode() = 0;
+
+ /**
* Initialize the keyboard event listeners.
*/
NS_IMETHOD_(void) InitializeKeyboardEventListeners() = 0;
/**
* Update the placeholder visibility based on the element's state.
*/
NS_IMETHOD_(void) UpdatePlaceholderVisibility(bool aNotify) = 0;
--- a/dom/html/nsTextEditorState.cpp
+++ b/dom/html/nsTextEditorState.cpp
@@ -1127,25 +1127,27 @@ nsTextEditorState::Clear()
void nsTextEditorState::Unlink()
{
nsTextEditorState* tmp = this;
tmp->Clear();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSelCon)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mEditor)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRootNode)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPlaceholderDiv)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mPreviewDiv)
}
void nsTextEditorState::Traverse(nsCycleCollectionTraversalCallback& cb)
{
nsTextEditorState* tmp = this;
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelCon)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEditor)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRootNode)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlaceholderDiv)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPreviewDiv)
}
nsFrameSelection*
nsTextEditorState::GetConstFrameSelection() {
if (mSelCon)
return mSelCon->GetConstFrameSelection();
return nullptr;
}
@@ -2181,16 +2183,17 @@ nsTextEditorState::UnbindFromFrame(nsTex
mMutationObserver = nullptr;
}
// Unbind the anonymous content from the tree.
// We actually hold a reference to the content nodes so that
// they're not actually destroyed.
nsContentUtils::DestroyAnonymousContent(&mRootNode);
nsContentUtils::DestroyAnonymousContent(&mPlaceholderDiv);
+ nsContentUtils::DestroyAnonymousContent(&mPreviewDiv);
}
nsresult
nsTextEditorState::CreateRootNode()
{
MOZ_ASSERT(!mRootNode);
MOZ_ASSERT(mBoundFrame);
@@ -2247,16 +2250,48 @@ nsTextEditorState::InitializeRootNode()
}
nsresult rv = mRootNode->SetAttr(kNameSpaceID_None, nsGkAtoms::_class,
classValue, false);
NS_ENSURE_SUCCESS(rv, rv);
return mBoundFrame->UpdateValueDisplay(false);
}
+Element*
+nsTextEditorState::CreateEmptyDivNode()
+{
+ MOZ_ASSERT(mBoundFrame);
+
+ nsIPresShell *shell = mBoundFrame->PresContext()->GetPresShell();
+ MOZ_ASSERT(shell);
+
+ nsIDocument *doc = shell->GetDocument();
+ MOZ_ASSERT(doc);
+
+ nsNodeInfoManager* pNodeInfoManager = doc->NodeInfoManager();
+ MOZ_ASSERT(pNodeInfoManager);
+
+ Element *element;
+
+ // Create a DIV
+ RefPtr<mozilla::dom::NodeInfo> nodeInfo;
+ nodeInfo = pNodeInfoManager->GetNodeInfo(nsGkAtoms::div, nullptr,
+ kNameSpaceID_XHTML,
+ nsIDOMNode::ELEMENT_NODE);
+
+ element = NS_NewHTMLDivElement(nodeInfo.forget());
+
+ // Create the text node for DIV
+ RefPtr<nsTextNode> textNode = new nsTextNode(pNodeInfoManager);
+
+ element->AppendChildTo(textNode, false);
+
+ return element;
+}
+
nsresult
nsTextEditorState::CreatePlaceholderNode()
{
#ifdef DEBUG
{
nsCOMPtr<nsIContent> content = do_QueryInterface(mTextCtrlElement);
if (content) {
nsAutoString placeholderTxt;
@@ -2265,52 +2300,42 @@ nsTextEditorState::CreatePlaceholderNode
nsContentUtils::RemoveNewlines(placeholderTxt);
NS_ASSERTION(!placeholderTxt.IsEmpty(), "CreatePlaceholderNode() shouldn't \
be called if @placeholder is the empty string when trimmed from line breaks");
}
}
#endif // DEBUG
NS_ENSURE_TRUE(!mPlaceholderDiv, NS_ERROR_UNEXPECTED);
- NS_ENSURE_ARG_POINTER(mBoundFrame);
-
- nsIPresShell *shell = mBoundFrame->PresContext()->GetPresShell();
- NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
-
- nsIDocument *doc = shell->GetDocument();
- NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
-
- nsNodeInfoManager* pNodeInfoManager = doc->NodeInfoManager();
- NS_ENSURE_TRUE(pNodeInfoManager, NS_ERROR_OUT_OF_MEMORY);
-
- nsresult rv;
// Create a DIV for the placeholder
// and add it to the anonymous content child list
- RefPtr<mozilla::dom::NodeInfo> nodeInfo;
- nodeInfo = pNodeInfoManager->GetNodeInfo(nsGkAtoms::div, nullptr,
- kNameSpaceID_XHTML,
- nsIDOMNode::ELEMENT_NODE);
-
- rv = NS_NewHTMLElement(getter_AddRefs(mPlaceholderDiv), nodeInfo.forget(),
- NOT_FROM_PARSER);
- NS_ENSURE_SUCCESS(rv, rv);
-
- // Create the text node for the placeholder text before doing anything else
- RefPtr<nsTextNode> placeholderText = new nsTextNode(pNodeInfoManager);
-
- rv = mPlaceholderDiv->AppendChildTo(placeholderText, false);
- NS_ENSURE_SUCCESS(rv, rv);
+ mPlaceholderDiv = CreateEmptyDivNode();
// initialize the text
UpdatePlaceholderText(false);
return NS_OK;
}
+nsresult
+nsTextEditorState::CreatePreviewNode()
+{
+ NS_ENSURE_TRUE(!mPreviewDiv, NS_ERROR_UNEXPECTED);
+
+ // Create a DIV for the preview
+ // and add it to the anonymous content child list
+ mPreviewDiv = CreateEmptyDivNode();
+
+ mPreviewDiv->SetAttr(kNameSpaceID_None, nsGkAtoms::_class,
+ NS_LITERAL_STRING("preview-div"), false);
+
+ return NS_OK;
+}
+
bool
nsTextEditorState::GetMaxLength(int32_t* aMaxLength)
{
nsCOMPtr<nsIContent> content = do_QueryInterface(mTextCtrlElement);
nsGenericHTMLElement* element =
nsGenericHTMLElement::FromContentOrNull(content);
NS_ENSURE_TRUE(element, false);
--- a/dom/html/nsTextEditorState.h
+++ b/dom/html/nsTextEditorState.h
@@ -178,23 +178,28 @@ public:
eSetValue_MoveCursorToEnd = 1 << 3,
};
MOZ_MUST_USE bool SetValue(const nsAString& aValue, uint32_t aFlags);
void GetValue(nsAString& aValue, bool aIgnoreWrap) const;
void EmptyValue() { if (mValue) mValue->Truncate(); }
bool IsEmpty() const { return mValue ? mValue->IsEmpty() : true; }
nsresult CreatePlaceholderNode();
+ nsresult CreatePreviewNode();
+ mozilla::dom::Element* CreateEmptyDivNode();
mozilla::dom::Element* GetRootNode() {
return mRootNode;
}
mozilla::dom::Element* GetPlaceholderNode() {
return mPlaceholderDiv;
}
+ mozilla::dom::Element* GetPreviewNode() {
+ return mPreviewDiv;
+ }
bool IsSingleLineTextControl() const {
return mTextCtrlElement->IsSingleLineTextControl();
}
bool IsTextArea() const {
return mTextCtrlElement->IsTextArea();
}
bool IsPlainTextControl() const {
@@ -416,16 +421,17 @@ private:
// has a smaller lifetime.
nsITextControlElement* MOZ_NON_OWNING_REF mTextCtrlElement;
// mSelCon is non-null while we have an mBoundFrame.
RefPtr<nsTextInputSelectionImpl> mSelCon;
RefPtr<RestoreSelectionState> mRestoringSelection;
nsCOMPtr<nsIEditor> mEditor;
nsCOMPtr<mozilla::dom::Element> mRootNode;
nsCOMPtr<mozilla::dom::Element> mPlaceholderDiv;
+ nsCOMPtr<mozilla::dom::Element> mPreviewDiv;
nsTextControlFrame* mBoundFrame;
RefPtr<nsTextInputListener> mTextListener;
mozilla::Maybe<nsString> mValue;
RefPtr<nsAnonDivObserver> mMutationObserver;
mutable nsString mCachedValue; // Caches non-hard-wrapped value on a multiline control.
// mValueBeingSet is available only while SetValue() is requesting to commit
// composition. I.e., this is valid only while mIsCommittingComposition is
// true. While active composition is being committed, GetValue() needs
--- a/layout/forms/nsTextControlFrame.cpp
+++ b/layout/forms/nsTextControlFrame.cpp
@@ -362,16 +362,22 @@ nsTextControlFrame::CreateAnonymousConte
if (!IsSingleLineTextControl()) {
// For textareas, UpdateValueDisplay doesn't initialize the visibility
// status of the placeholder because it returns early, so we have to
// do that manually here.
txtCtrl->UpdatePlaceholderVisibility(true);
}
}
+ // Create the preview anonymous content if needed.
+ Element* previewNode = txtCtrl->CreatePreviewNode();
+ NS_ENSURE_TRUE(previewNode, NS_ERROR_OUT_OF_MEMORY);
+
+ aElements.AppendElement(previewNode);
+
rv = UpdateValueDisplay(false);
NS_ENSURE_SUCCESS(rv, rv);
// textareas are eagerly initialized
bool initEagerly = !IsSingleLineTextControl();
if (!initEagerly) {
// Also, input elements which have a cached selection should get eager
// editor initialization.
@@ -419,19 +425,24 @@ nsTextControlFrame::AppendAnonymousConte
}
nsIContent* root = txtCtrl->GetRootEditorNode();
if (root) {
aElements.AppendElement(root);
}
nsIContent* placeholder = txtCtrl->GetPlaceholderNode();
- if (placeholder && !(aFilter & nsIContent::eSkipPlaceholderContent))
+ if (placeholder && !(aFilter & nsIContent::eSkipPlaceholderContent)) {
aElements.AppendElement(placeholder);
+ }
+ nsIContent* preview = txtCtrl->GetPreviewNode();
+ if (preview) {
+ aElements.AppendElement(preview);
+ }
}
nscoord
nsTextControlFrame::GetPrefISize(nsRenderingContext* aRenderingContext)
{
nscoord result = 0;
DISPLAY_PREF_WIDTH(this, result);
float inflation = nsLayoutUtils::FontSizeInflationFor(this);