From 8edfbaf7e49ddd156c0fd4f718ab355cf628652d Mon Sep 17 00:00:00 2001 From: Mounir Lamouri Date: Fri, 9 Nov 2012 10:22:29 +0000 Subject: [PATCH] Bug 737786 - 1/5 - Show/hide placeholder based on display lists instead of CSS class. r=bz --- .../content/public/nsITextControlElement.h | 11 ++++-- .../html/content/src/nsHTMLInputElement.cpp | 15 ++++++- content/html/content/src/nsHTMLInputElement.h | 3 +- .../content/src/nsHTMLTextAreaElement.cpp | 13 +++++-- .../html/content/src/nsTextEditorState.cpp | 32 +++++++-------- content/html/content/src/nsTextEditorState.h | 6 ++- layout/forms/nsTextControlFrame.cpp | 39 ++++++++++++++++++- layout/forms/nsTextControlFrame.h | 6 ++- layout/style/forms.css | 5 --- 9 files changed, 92 insertions(+), 38 deletions(-) diff --git a/content/html/content/public/nsITextControlElement.h b/content/html/content/public/nsITextControlElement.h index 37a2058d9294..baf2ef50fff5 100644 --- a/content/html/content/public/nsITextControlElement.h +++ b/content/html/content/public/nsITextControlElement.h @@ -18,8 +18,8 @@ class nsTextControlFrame; // IID for the nsITextControl interface #define NS_ITEXTCONTROLELEMENT_IID \ -{ 0xe0a05008, 0xef02, 0x4fa2, \ - { 0x93, 0xf2, 0x78, 0xe1, 0xec, 0xf7, 0x5b, 0x79 } } +{ 0x669bd7ca, 0x42af, 0x4f1e, \ + { 0xa6, 0xe2, 0x86, 0xc4, 0x0a, 0x14, 0x73, 0x4e } } /** * This interface is used for the text control frame to get the editor and @@ -153,7 +153,12 @@ public: /** * Show/hide the placeholder for the control. */ - NS_IMETHOD_(void) SetPlaceholderClass(bool aVisible, bool aNotify) = 0; + NS_IMETHOD_(void) SetPlaceholderVisibility(bool aVisible, bool aNotify) = 0; + + /** + * Returns the current expected placeholder visibility state. + */ + NS_IMETHOD_(bool) GetPlaceholderVisibility() = 0; /** * Callback called whenever the value is changed. diff --git a/content/html/content/src/nsHTMLInputElement.cpp b/content/html/content/src/nsHTMLInputElement.cpp index d3cc79ebc0b7..94c047dab4b3 100644 --- a/content/html/content/src/nsHTMLInputElement.cpp +++ b/content/html/content/src/nsHTMLInputElement.cpp @@ -1474,14 +1474,25 @@ nsHTMLInputElement::GetPlaceholderNode() } NS_IMETHODIMP_(void) -nsHTMLInputElement::SetPlaceholderClass(bool aVisible, bool aNotify) +nsHTMLInputElement::SetPlaceholderVisibility(bool aVisible, bool aNotify) { nsTextEditorState *state = GetEditorState(); if (state) { - state->SetPlaceholderClass(aVisible, aNotify); + state->SetPlaceholderVisibility(aVisible, aNotify); } } +NS_IMETHODIMP_(bool) +nsHTMLInputElement::GetPlaceholderVisibility() +{ + nsTextEditorState* state = GetEditorState(); + if (!state) { + return false; + } + + return state->GetPlaceholderVisibility(); +} + void nsHTMLInputElement::GetDisplayFileName(nsAString& aValue) const { diff --git a/content/html/content/src/nsHTMLInputElement.h b/content/html/content/src/nsHTMLInputElement.h index 8237b494d623..fd329d14fd99 100644 --- a/content/html/content/src/nsHTMLInputElement.h +++ b/content/html/content/src/nsHTMLInputElement.h @@ -150,7 +150,8 @@ public: NS_IMETHOD_(nsIContent*) GetRootEditorNode(); NS_IMETHOD_(nsIContent*) CreatePlaceholderNode(); NS_IMETHOD_(nsIContent*) GetPlaceholderNode(); - NS_IMETHOD_(void) SetPlaceholderClass(bool aVisible, bool aNotify); + NS_IMETHOD_(void) SetPlaceholderVisibility(bool aVisible, bool aNotify); + NS_IMETHOD_(bool) GetPlaceholderVisibility(); NS_IMETHOD_(void) InitializeKeyboardEventListeners(); NS_IMETHOD_(void) OnValueChanged(bool aNotify); NS_IMETHOD_(bool) HasCachedSelection(); diff --git a/content/html/content/src/nsHTMLTextAreaElement.cpp b/content/html/content/src/nsHTMLTextAreaElement.cpp index 7ab5abd2d5aa..25b1376df105 100644 --- a/content/html/content/src/nsHTMLTextAreaElement.cpp +++ b/content/html/content/src/nsHTMLTextAreaElement.cpp @@ -122,7 +122,8 @@ public: NS_IMETHOD_(nsIContent*) GetRootEditorNode(); NS_IMETHOD_(nsIContent*) CreatePlaceholderNode(); NS_IMETHOD_(nsIContent*) GetPlaceholderNode(); - NS_IMETHOD_(void) SetPlaceholderClass(bool aVisible, bool aNotify); + NS_IMETHOD_(void) SetPlaceholderVisibility(bool aVisible, bool aNotify); + NS_IMETHOD_(bool) GetPlaceholderVisibility(); NS_IMETHOD_(void) InitializeKeyboardEventListeners(); NS_IMETHOD_(void) OnValueChanged(bool aNotify); NS_IMETHOD_(bool) HasCachedSelection(); @@ -513,9 +514,15 @@ nsHTMLTextAreaElement::GetPlaceholderNode() } NS_IMETHODIMP_(void) -nsHTMLTextAreaElement::SetPlaceholderClass(bool aVisible, bool aNotify) +nsHTMLTextAreaElement::SetPlaceholderVisibility(bool aVisible, bool aNotify) { - mState.SetPlaceholderClass(aVisible, aNotify); + mState.SetPlaceholderVisibility(aVisible, aNotify); +} + +NS_IMETHODIMP_(bool) +nsHTMLTextAreaElement::GetPlaceholderVisibility() +{ + return mState.GetPlaceholderVisibility(); } nsresult diff --git a/content/html/content/src/nsTextEditorState.cpp b/content/html/content/src/nsTextEditorState.cpp index e42dc54f005a..bb6733450964 100644 --- a/content/html/content/src/nsTextEditorState.cpp +++ b/content/html/content/src/nsTextEditorState.cpp @@ -933,7 +933,8 @@ nsTextEditorState::nsTextEditorState(nsITextControlElement* aOwningElement) mInitializing(false), mValueTransferInProgress(false), mSelectionCached(true), - mSelectionRestoreEagerInit(false) + mSelectionRestoreEagerInit(false), + mPlaceholderVisibility(false) { MOZ_COUNT_CTOR(nsTextEditorState); } @@ -1660,6 +1661,10 @@ be called if @placeholder is the empty string when trimmed from line breaks"); rv = mPlaceholderDiv->AppendChildTo(placeholderText, false); NS_ENSURE_SUCCESS(rv, rv); + mPlaceholderDiv->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, + NS_LITERAL_STRING("anonymous-div placeholder"), + false); + // initialize the text UpdatePlaceholderText(false); @@ -1969,7 +1974,7 @@ nsTextEditorState::ValueWasChanged(bool aNotify) nsAutoString valueString; GetValue(valueString, true); - SetPlaceholderClass(valueString.IsEmpty(), aNotify); + SetPlaceholderVisibility(valueString.IsEmpty(), aNotify); } void @@ -1993,28 +1998,17 @@ nsTextEditorState::UpdatePlaceholderText(bool aNotify) } void -nsTextEditorState::SetPlaceholderClass(bool aVisible, - bool aNotify) +nsTextEditorState::SetPlaceholderVisibility(bool aVisible, + bool aNotify) { NS_ASSERTION(mPlaceholderDiv, "This function should not be called if " "mPlaceholderDiv isn't set"); - // No need to do anything if we don't have a frame yet - if (!mBoundFrame) - return; + mPlaceholderVisibility = aVisible; - nsAutoString classValue; - - classValue.Assign(NS_LITERAL_STRING("anonymous-div placeholder")); - - if (!aVisible) - classValue.AppendLiteral(" hidden"); - - nsIContent* placeholderDiv = GetPlaceholderNode(); - NS_ENSURE_TRUE_VOID(placeholderDiv); - - placeholderDiv->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, - classValue, aNotify); + if (mBoundFrame && aNotify) { + mBoundFrame->InvalidateFrame(); + } } void diff --git a/content/html/content/src/nsTextEditorState.h b/content/html/content/src/nsTextEditorState.h index 9f00a8a82367..2cf74a56e4d5 100644 --- a/content/html/content/src/nsTextEditorState.h +++ b/content/html/content/src/nsTextEditorState.h @@ -174,7 +174,10 @@ public: } // placeholder methods - void SetPlaceholderClass(bool aVisible, bool aNotify); + void SetPlaceholderVisibility(bool aVisible, bool aNotify); + bool GetPlaceholderVisibility() { + return mPlaceholderVisibility; + } void UpdatePlaceholderText(bool aNotify); /** @@ -278,6 +281,7 @@ private: bool mSelectionCached; // Whether mSelectionProperties is valid mutable bool mSelectionRestoreEagerInit; // Whether we're eager initing because of selection restore SelectionProperties mSelectionProperties; + bool mPlaceholderVisibility; }; #endif diff --git a/layout/forms/nsTextControlFrame.cpp b/layout/forms/nsTextControlFrame.cpp index bdc3747402e3..c6d9985f6a50 100644 --- a/layout/forms/nsTextControlFrame.cpp +++ b/layout/forms/nsTextControlFrame.cpp @@ -1307,7 +1307,7 @@ nsTextControlFrame::SetValueChanged(bool aValueChanged) GetTextLength(&textLength); nsWeakFrame weakFrame(this); - txtCtrl->SetPlaceholderClass(!textLength, true); + txtCtrl->SetPlaceholderVisibility(!textLength, true); if (!weakFrame.IsAlive()) { return; } @@ -1365,7 +1365,7 @@ nsTextControlFrame::UpdateValueDisplay(bool aNotify, if (mUsePlaceholder && !aBeforeEditorInit) { nsWeakFrame weakFrame(this); - txtCtrl->SetPlaceholderClass(value.IsEmpty(), aNotify); + txtCtrl->SetPlaceholderVisibility(value.IsEmpty(), aNotify); NS_ENSURE_STATE(weakFrame.IsAlive()); } @@ -1455,3 +1455,38 @@ nsTextControlFrame::PeekOffset(nsPeekOffsetStruct *aPos) return NS_ERROR_FAILURE; } +NS_IMETHODIMP +nsTextControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, + const nsDisplayListSet& aLists) +{ + /* + * The implementation of this method is equivalent as: + * nsContainerFrame::BuildDisplayList() + * with the difference that we filter-out the placeholder frame when it + * should not be visible. + */ + DO_GLOBAL_REFLOW_COUNT_DSP("nsTextControlFrame"); + + nsCOMPtr txtCtrl = do_QueryInterface(GetContent()); + NS_ASSERTION(txtCtrl, "Content not a text control element!"); + + nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists); + NS_ENSURE_SUCCESS(rv, rv); + + nsIFrame* kid = mFrames.FirstChild(); + nsDisplayListSet set(aLists, aLists.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()) { + nsresult rv = BuildDisplayListForChild(aBuilder, kid, aDirtyRect, set, 0); + NS_ENSURE_SUCCESS(rv, rv); + } + kid = kid->GetNextSibling(); + } + + return NS_OK; +} diff --git a/layout/forms/nsTextControlFrame.h b/layout/forms/nsTextControlFrame.h index 8ce6674762d5..c16193b0c8db 100644 --- a/layout/forms/nsTextControlFrame.h +++ b/layout/forms/nsTextControlFrame.h @@ -67,8 +67,6 @@ public: virtual nsSize GetMinSize(nsBoxLayoutState& aBoxLayoutState); virtual bool IsCollapsed(); - DECL_DO_GLOBAL_REFLOW_COUNT_DSP(nsTextControlFrame, nsContainerFrame) - virtual bool IsLeaf() const; #ifdef ACCESSIBILITY @@ -101,6 +99,10 @@ public: NS_IMETHOD SetInitialChildList(ChildListID aListID, nsFrameList& aChildList) MOZ_OVERRIDE; + NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, + const nsDisplayListSet& aLists); + //==== BEGIN NSIFORMCONTROLFRAME virtual void SetFocus(bool aOn , bool aRepaint); virtual nsresult SetFormProperty(nsIAtom* aName, const nsAString& aValue); diff --git a/layout/style/forms.css b/layout/style/forms.css index ae2071196f8c..b12abb0f2992 100644 --- a/layout/style/forms.css +++ b/layout/style/forms.css @@ -161,11 +161,6 @@ textarea > .placeholder { white-space: pre-wrap; } -input > .placeholder.hidden, -textarea > .placeholder.hidden { - visibility: hidden; -} - input:-moz-read-write, textarea:-moz-read-write { -moz-user-modify: read-write !important;