Bug 1340483 - Part 4. Update input visibility accordingly. r=heycam draft
authorRay Lin <ralin@mozilla.com>
Thu, 30 Mar 2017 17:38:59 +0800
changeset 564427 75e7f7cbd512dee072b2e7fc6f384e989956e9a3
parent 564426 253f102b30031e2ad86fd2578297ff3ce2b4f5c0
child 564428 13fc7c962278662af4760a60c8f7fb237c2b85dd
push id54590
push userbmo:ralin@mozilla.com
push dateTue, 18 Apr 2017 14:37:59 +0000
reviewersheycam
bugs1340483
milestone55.0a1
Bug 1340483 - Part 4. Update input visibility accordingly. r=heycam MozReview-Commit-ID: 7eBhj7w4qhP
dom/html/HTMLInputElement.cpp
dom/html/HTMLInputElement.h
dom/html/HTMLTextAreaElement.cpp
dom/html/HTMLTextAreaElement.h
dom/html/nsITextControlElement.h
dom/html/nsTextEditorState.cpp
dom/html/nsTextEditorState.h
layout/forms/nsTextControlFrame.cpp
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -2868,21 +2868,21 @@ HTMLInputElement::GetPlaceholderNode()
   nsTextEditorState* state = GetEditorState();
   if (state) {
     return state->GetPlaceholderNode();
   }
   return nullptr;
 }
 
 NS_IMETHODIMP_(void)
-HTMLInputElement::UpdatePlaceholderVisibility(bool aNotify)
+HTMLInputElement::UpdateOverlayTextVisibility(bool aNotify)
 {
   nsTextEditorState* state = GetEditorState();
   if (state) {
-    state->UpdatePlaceholderVisibility(aNotify);
+    state->UpdateOverlayTextVisibility(aNotify);
   }
 }
 
 NS_IMETHODIMP_(bool)
 HTMLInputElement::GetPlaceholderVisibility()
 {
   nsTextEditorState* state = GetEditorState();
   if (!state) {
@@ -2944,16 +2944,27 @@ HTMLInputElement::EnablePreview()
 }
 
 NS_IMETHODIMP_(bool)
 HTMLInputElement::IsPreviewEnabled()
 {
   return mIsPreviewEnabled;
 }
 
+NS_IMETHODIMP_(bool)
+HTMLInputElement::GetPreviewVisibility()
+{
+  nsTextEditorState* state = GetEditorState();
+  if (!state) {
+    return false;
+  }
+
+  return state->GetPreviewVisibility();
+}
+
 void
 HTMLInputElement::GetDisplayFileName(nsAString& aValue) const
 {
   if (OwnerDoc()->IsStaticDocument()) {
     aValue = mStaticDocFileList;
     return;
   }
 
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -231,22 +231,23 @@ public:
   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_(void) UpdateOverlayTextVisibility(bool aNotify) override;
   NS_IMETHOD_(void) SetPreviewValue(const nsAString& aValue) override;
   NS_IMETHOD_(void) GetPreviewValue(nsAString& aValue) override;
   NS_IMETHOD_(void) EnablePreview() override;
   NS_IMETHOD_(bool) IsPreviewEnabled() override;
   NS_IMETHOD_(bool) GetPlaceholderVisibility() override;
+  NS_IMETHOD_(bool) GetPreviewVisibility() 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;
 
   // Methods for nsFormFillController so it can do selection operations on input
   // types the HTML spec doesn't support them on, like "email".
--- a/dom/html/HTMLTextAreaElement.cpp
+++ b/dom/html/HTMLTextAreaElement.cpp
@@ -305,19 +305,19 @@ HTMLTextAreaElement::CreatePlaceholderNo
 
 NS_IMETHODIMP_(Element*)
 HTMLTextAreaElement::GetPlaceholderNode()
 {
   return mState.GetPlaceholderNode();
 }
 
 NS_IMETHODIMP_(void)
-HTMLTextAreaElement::UpdatePlaceholderVisibility(bool aNotify)
+HTMLTextAreaElement::UpdateOverlayTextVisibility(bool aNotify)
 {
-  mState.UpdatePlaceholderVisibility(aNotify);
+  mState.UpdateOverlayTextVisibility(aNotify);
 }
 
 NS_IMETHODIMP_(bool)
 HTMLTextAreaElement::GetPlaceholderVisibility()
 {
   return mState.GetPlaceholderVisibility();
 }
 
@@ -359,16 +359,22 @@ HTMLTextAreaElement::EnablePreview()
 }
 
 NS_IMETHODIMP_(bool)
 HTMLTextAreaElement::IsPreviewEnabled()
 {
   return mIsPreviewEnabled;
 }
 
+NS_IMETHODIMP_(bool)
+HTMLTextAreaElement::GetPreviewVisibility()
+{
+  return mState.GetPreviewVisibility();
+}
+
 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
@@ -100,18 +100,19 @@ public:
   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_(void) UpdateOverlayTextVisibility(bool aNotify) override;
   NS_IMETHOD_(bool) GetPlaceholderVisibility() override;
+  NS_IMETHOD_(bool) GetPreviewVisibility() override;
   NS_IMETHOD_(void) SetPreviewValue(const nsAString& aValue) override;
   NS_IMETHOD_(void) GetPreviewValue(nsAString& aValue) override;
   NS_IMETHOD_(void) EnablePreview() override;
   NS_IMETHOD_(bool) IsPreviewEnabled() 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;
--- a/dom/html/nsITextControlElement.h
+++ b/dom/html/nsITextControlElement.h
@@ -185,26 +185,31 @@ public:
   NS_IMETHOD_(bool) IsPreviewEnabled() = 0;
 
   /**
    * Initialize the keyboard event listeners.
    */
   NS_IMETHOD_(void) InitializeKeyboardEventListeners() = 0;
 
   /**
-   * Update the placeholder visibility based on the element's state.
+   * Update the visibility of both the placholder and preview text based on the element's state.
    */
-  NS_IMETHOD_(void) UpdatePlaceholderVisibility(bool aNotify) = 0;
+  NS_IMETHOD_(void) UpdateOverlayTextVisibility(bool aNotify) = 0;
 
   /**
    * Returns the current expected placeholder visibility state.
    */
   NS_IMETHOD_(bool) GetPlaceholderVisibility() = 0;
 
   /**
+   * Returns the current expected preview visibility state.
+   */
+  NS_IMETHOD_(bool) GetPreviewVisibility() = 0;
+
+  /**
    * Callback called whenever the value is changed.
    */
   NS_IMETHOD_(void) OnValueChanged(bool aNotify, bool aWasInteractiveUserChange) = 0;
 
   /**
    * Helpers for value manipulation from SetRangeText.
    */
   virtual void GetValueFromSetRangeText(nsAString& aValue) = 0;
--- a/dom/html/nsTextEditorState.cpp
+++ b/dom/html/nsTextEditorState.cpp
@@ -1062,16 +1062,17 @@ nsTextEditorState::nsTextEditorState(nsI
   , mBoundFrame(nullptr)
   , mEverInited(false)
   , mEditorInitialized(false)
   , mInitializing(false)
   , mValueTransferInProgress(false)
   , mSelectionCached(true)
   , mSelectionRestoreEagerInit(false)
   , mPlaceholderVisibility(false)
+  , mPreviewVisibility(false)
   , mIsCommittingComposition(false)
   // When adding more member variable initializations here, add the same
   // also to ::Construct.
 {
   MOZ_COUNT_CTOR(nsTextEditorState);
 }
 
 nsTextEditorState*
@@ -1086,16 +1087,17 @@ nsTextEditorState::Construct(nsITextCont
     state->mSelectionProperties = SelectionProperties();
     state->mEverInited = false;
     state->mEditorInitialized = false;
     state->mInitializing = false;
     state->mValueTransferInProgress = false;
     state->mSelectionCached = true;
     state->mSelectionRestoreEagerInit = false;
     state->mPlaceholderVisibility = false;
+    state->mPreviewVisibility = false;
     state->mIsCommittingComposition = false;
     // When adding more member variable initializations here, add the same
     // also to the constructor.
     return state;
   }
 
   return new nsTextEditorState(aOwningElement);
 }
@@ -2695,17 +2697,17 @@ nsTextEditorState::InitializeKeyboardEve
   }
 
   mSelCon->SetScrollableFrame(do_QueryFrame(mBoundFrame->PrincipalChildList().FirstChild()));
 }
 
 void
 nsTextEditorState::ValueWasChanged(bool aNotify)
 {
-  UpdatePlaceholderVisibility(aNotify);
+  UpdateOverlayTextVisibility(aNotify);
 }
 
 void
 nsTextEditorState::UpdatePlaceholderText(bool aNotify)
 {
   NS_ASSERTION(mPlaceholderDiv, "This function should not be called if "
                                 "mPlaceholderDiv isn't set");
 
@@ -2732,16 +2734,18 @@ nsTextEditorState::SetPreviewText(const 
   if (!mPreviewDiv)
     return;
 
   nsAutoString previewValue(aValue);
 
   nsContentUtils::RemoveNewlines(previewValue);
   MOZ_ASSERT(mPreviewDiv->GetFirstChild(), "preview div has no child");
   mPreviewDiv->GetFirstChild()->SetText(previewValue, aNotify);
+
+  UpdateOverlayTextVisibility(aNotify);
 }
 
 void
 nsTextEditorState::GetPreviewText(nsAString& aValue)
 {
   // If we don't have a preview div, there's nothing to do.
   if (!mPreviewDiv)
     return;
@@ -2749,22 +2753,24 @@ nsTextEditorState::GetPreviewText(nsAStr
   MOZ_ASSERT(mPreviewDiv->GetFirstChild(), "preview div has no child");
   const nsTextFragment *text = mPreviewDiv->GetFirstChild()->GetText();
 
   aValue.Truncate();
   text->AppendTo(aValue);
 }
 
 void
-nsTextEditorState::UpdatePlaceholderVisibility(bool aNotify)
+nsTextEditorState::UpdateOverlayTextVisibility(bool aNotify)
 {
-  nsAutoString value;
+  nsAutoString value, previewValue;
   GetValue(value, true);
-
-  mPlaceholderVisibility = value.IsEmpty();
+  GetPreviewText(previewValue);
+
+  mPreviewVisibility = value.IsEmpty() && !previewValue.IsEmpty();
+  mPlaceholderVisibility = value.IsEmpty() && previewValue.IsEmpty();
 
   if (mPlaceholderVisibility &&
       !Preferences::GetBool("dom.placeholder.show_on_focus", true)) {
     nsCOMPtr<nsIContent> content = do_QueryInterface(mTextCtrlElement);
     mPlaceholderVisibility = !nsContentUtils::IsFocusedContent(content);
   }
 
   if (mBoundFrame && aNotify) {
--- a/dom/html/nsTextEditorState.h
+++ b/dom/html/nsTextEditorState.h
@@ -213,27 +213,30 @@ public:
   }
   int32_t GetWrapCols() {
     return mTextCtrlElement->GetWrapCols();
   }
   int32_t GetRows() {
     return mTextCtrlElement->GetRows();
   }
 
+  void UpdateOverlayTextVisibility(bool aNotify);
+
   // placeholder methods
-  void UpdatePlaceholderVisibility(bool aNotify);
   bool GetPlaceholderVisibility() {
     return mPlaceholderVisibility;
   }
-
   void UpdatePlaceholderText(bool aNotify);
 
   // preview methods
   void SetPreviewText(const nsAString& aValue, bool aNotify);
   void GetPreviewText(nsAString& aValue);
+  bool GetPreviewVisibility() {
+    return mPreviewVisibility;
+  }
 
   /**
    * Get the maxlength attribute
    * @param aMaxLength the value of the max length attr
    * @returns false if attr not defined
    */
   bool GetMaxLength(int32_t* aMaxLength);
 
@@ -445,16 +448,17 @@ private:
   SelectionProperties mSelectionProperties;
   bool mEverInited; // Have we ever been initialized?
   bool mEditorInitialized;
   bool mInitializing; // Whether we're in the process of initialization
   bool mValueTransferInProgress; // Whether a value is being transferred to the frame
   bool mSelectionCached; // Whether mSelectionProperties is valid
   mutable bool mSelectionRestoreEagerInit; // Whether we're eager initing because of selection restore
   bool mPlaceholderVisibility;
+  bool mPreviewVisibility;
   bool mIsCommittingComposition;
 };
 
 inline void
 ImplCycleCollectionUnlink(nsTextEditorState& aField)
 {
   aField.Unlink();
 }
--- a/layout/forms/nsTextControlFrame.cpp
+++ b/layout/forms/nsTextControlFrame.cpp
@@ -359,17 +359,17 @@ nsTextControlFrame::CreateAnonymousConte
     // Associate ::placeholder pseudo-element with the placeholder node.
     placeholderNode->SetPseudoElementType(CSSPseudoElementType::placeholder);
     aElements.AppendElement(placeholderNode);
 
     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);
+      txtCtrl->UpdateOverlayTextVisibility(true);
     }
   }
 
   mUsePreview = txtCtrl->IsPreviewEnabled();
 
   if (mUsePreview) {
     // Create the preview anonymous content if needed.
     Element* previewNode = txtCtrl->CreatePreviewNode();
@@ -651,17 +651,17 @@ void nsTextControlFrame::SetFocus(bool a
   NS_ASSERTION(txtCtrl, "Content not a text control element");
 
   // Revoke the previous scroll event if one exists
   mScrollEvent.Revoke();
 
   // If 'dom.placeholeder.show_on_focus' preference is 'false', focusing or
   // blurring the frame can have an impact on the placeholder visibility.
   if (mUsePlaceholder) {
-    txtCtrl->UpdatePlaceholderVisibility(true);
+    txtCtrl->UpdateOverlayTextVisibility(true);
   }
 
   if (!aOn) {
     return;
   }
 
   nsISelectionController* selCon = txtCtrl->GetSelectionController();
   if (!selCon)
@@ -1178,17 +1178,17 @@ nsTextControlFrame::SetInitialChildList(
 void
 nsTextControlFrame::SetValueChanged(bool aValueChanged)
 {
   nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
   NS_ASSERTION(txtCtrl, "Content not a text control element");
 
   if (mUsePlaceholder) {
     AutoWeakFrame weakFrame(this);
-    txtCtrl->UpdatePlaceholderVisibility(true);
+    txtCtrl->UpdateOverlayTextVisibility(true);
     if (!weakFrame.IsAlive()) {
       return;
     }
   }
 
   txtCtrl->SetValueChanged(aValueChanged);
 }
 
@@ -1228,23 +1228,23 @@ nsTextControlFrame::UpdateValueDisplay(b
   // Get the current value of the textfield from the content.
   nsAutoString value;
   if (aValue) {
     value = *aValue;
   } else {
     txtCtrl->GetTextEditorValue(value, true);
   }
 
-  // Update the display of the placeholder value if needed.
-  // We don't need to do this if we're about to initialize the
-  // editor, since EnsureEditorInitialized takes care of this.
-  if (mUsePlaceholder && !aBeforeEditorInit)
+  // Update the display of the placeholder value and preview text if needed.
+  // We don't need to do this if we're about to initialize the editor, since
+  // EnsureEditorInitialized takes care of this.
+  if ((mUsePlaceholder || mUsePreview) && !aBeforeEditorInit)
   {
     AutoWeakFrame weakFrame(this);
-    txtCtrl->UpdatePlaceholderVisibility(aNotify);
+    txtCtrl->UpdateOverlayTextVisibility(aNotify);
     NS_ENSURE_STATE(weakFrame.IsAlive());
   }
 
   if (aBeforeEditorInit && value.IsEmpty()) {
     rootNode->RemoveChildAt(0, true);
     return NS_OK;
   }
 
@@ -1350,20 +1350,22 @@ nsTextControlFrame::BuildDisplayList(nsD
   nsIFrame* kid = mFrames.FirstChild();
   // Redirect all lists to the Content list so that nothing can escape, ie
   // opacity creating stacking contexts that then get sorted with stacking
   // contexts external to us.
   nsDisplayList* content = aLists.Content();
   nsDisplayListSet set(content, content, content, content, content, content);
 
   while (kid) {
-    // If the frame is the placeholder frame, we should only show it if the
-    // placeholder has to be visible.
-    if (kid->GetContent() != txtCtrl->GetPlaceholderNode() ||
-        txtCtrl->GetPlaceholderVisibility()) {
+    // If the frame is the placeholder or preview frame, we should only show
+    // it if it has to be visible.
+    if (!((kid->GetContent() == txtCtrl->GetPlaceholderNode() &&
+           !txtCtrl->GetPlaceholderVisibility()) ||
+          (kid->GetContent() == txtCtrl->GetPreviewNode() &&
+           !txtCtrl->GetPreviewVisibility()))) {
       BuildDisplayListForChild(aBuilder, kid, aDirtyRect, set, 0);
     }
     kid = kid->GetNextSibling();
   }
 }
 
 mozilla::dom::Element*
 nsTextControlFrame::GetPseudoElement(CSSPseudoElementType aType)