/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef nsTextControlFrame_h___ #define nsTextControlFrame_h___ #include "mozilla/Attributes.h" #include "nsContainerFrame.h" #include "nsBlockFrame.h" #include "nsIFormControlFrame.h" #include "nsIAnonymousContentCreator.h" #include "nsITextControlFrame.h" #include "nsDisplayList.h" #include "nsIScrollableFrame.h" #include "nsStubMutationObserver.h" #include "nsITextControlElement.h" #include "nsIStatefulFrame.h" #include "nsIEditor.h" class nsISelectionController; class nsIDOMCharacterData; class EditorInitializerEntryTracker; class nsTextEditorState; namespace mozilla { namespace dom { class Element; } } class nsTextControlFrame : public nsContainerFrame, public nsIAnonymousContentCreator, public nsITextControlFrame, public nsIStatefulFrame { public: NS_DECL_FRAMEARENA_HELPERS NS_DECLARE_FRAME_PROPERTY(ContentScrollPos, DestroyPoint) nsTextControlFrame(nsIPresShell* aShell, nsStyleContext* aContext); virtual ~nsTextControlFrame(); virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE; virtual nsIScrollableFrame* GetScrollTargetFrame() MOZ_OVERRIDE { if (!IsScrollable()) return nullptr; return do_QueryFrame(GetFirstPrincipalChild()); } virtual nscoord GetMinWidth(nsRenderingContext* aRenderingContext) MOZ_OVERRIDE; virtual nscoord GetPrefWidth(nsRenderingContext* aRenderingContext) MOZ_OVERRIDE; virtual nsSize ComputeAutoSize(nsRenderingContext *aRenderingContext, nsSize aCBSize, nscoord aAvailableWidth, nsSize aMargin, nsSize aBorder, nsSize aPadding, bool aShrinkWrap) MOZ_OVERRIDE; NS_IMETHOD Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) MOZ_OVERRIDE; virtual nsSize GetMinSize(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE; virtual bool IsCollapsed() MOZ_OVERRIDE; virtual bool IsLeaf() const MOZ_OVERRIDE; #ifdef ACCESSIBILITY virtual mozilla::a11y::AccType AccessibleType() MOZ_OVERRIDE; #endif #ifdef DEBUG NS_IMETHOD GetFrameName(nsAString& aResult) const MOZ_OVERRIDE { aResult.AssignLiteral("nsTextControlFrame"); return NS_OK; } #endif virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE { // nsStackFrame is already both of these, but that's somewhat bogus, // and we really mean it. return nsContainerFrame::IsFrameOfType(aFlags & ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock)); } // nsIAnonymousContentCreator virtual nsresult CreateAnonymousContent(nsTArray& aElements) MOZ_OVERRIDE; virtual void AppendAnonymousContentTo(nsBaseContentList& aElements, uint32_t aFilter) MOZ_OVERRIDE; // Utility methods to set current widget state NS_IMETHOD SetInitialChildList(ChildListID aListID, nsFrameList& aChildList) MOZ_OVERRIDE; virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) MOZ_OVERRIDE; //==== BEGIN NSIFORMCONTROLFRAME virtual void SetFocus(bool aOn , bool aRepaint) MOZ_OVERRIDE; virtual nsresult SetFormProperty(nsIAtom* aName, const nsAString& aValue) MOZ_OVERRIDE; //==== END NSIFORMCONTROLFRAME //==== NSITEXTCONTROLFRAME NS_IMETHOD GetEditor(nsIEditor **aEditor) MOZ_OVERRIDE; NS_IMETHOD SetSelectionStart(int32_t aSelectionStart) MOZ_OVERRIDE; NS_IMETHOD SetSelectionEnd(int32_t aSelectionEnd) MOZ_OVERRIDE; NS_IMETHOD SetSelectionRange(int32_t aSelectionStart, int32_t aSelectionEnd, SelectionDirection aDirection = eNone) MOZ_OVERRIDE; NS_IMETHOD GetSelectionRange(int32_t* aSelectionStart, int32_t* aSelectionEnd, SelectionDirection* aDirection = nullptr) MOZ_OVERRIDE; NS_IMETHOD GetOwnedSelectionController(nsISelectionController** aSelCon) MOZ_OVERRIDE; virtual nsFrameSelection* GetOwnedFrameSelection() MOZ_OVERRIDE; nsresult GetPhonetic(nsAString& aPhonetic) MOZ_OVERRIDE; /** * Ensure mEditor is initialized with the proper flags and the default value. * @throws NS_ERROR_NOT_INITIALIZED if mEditor has not been created * @throws various and sundry other things */ virtual nsresult EnsureEditorInitialized() MOZ_OVERRIDE; //==== END NSITEXTCONTROLFRAME //==== NSISTATEFULFRAME NS_IMETHOD SaveState(nsPresState** aState) MOZ_OVERRIDE; NS_IMETHOD RestoreState(nsPresState* aState) MOZ_OVERRIDE; //=== END NSISTATEFULFRAME //==== OVERLOAD of nsIFrame virtual nsIAtom* GetType() const MOZ_OVERRIDE; /** handler for attribute changes to mContent */ NS_IMETHOD AttributeChanged(int32_t aNameSpaceID, nsIAtom* aAttribute, int32_t aModType) MOZ_OVERRIDE; nsresult GetText(nsString& aText); NS_IMETHOD PeekOffset(nsPeekOffsetStruct *aPos) MOZ_OVERRIDE; NS_DECL_QUERYFRAME // Temp reference to scriptrunner // We could make these auto-Revoking via the "delete" entry for safety NS_DECLARE_FRAME_PROPERTY(TextControlInitializer, nullptr) protected: /** * Launch the reflow on the child frames - see nsTextControlFrame::Reflow() */ void ReflowTextControlChild(nsIFrame* aFrame, nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus, nsHTMLReflowMetrics& aParentDesiredSize); public: //for methods who access nsTextControlFrame directly void SetValueChanged(bool aValueChanged); // called by the focus listener nsresult MaybeBeginSecureKeyboardInput(); void MaybeEndSecureKeyboardInput(); class MOZ_STACK_CLASS ValueSetter { public: ValueSetter(nsIEditor* aEditor) : mEditor(aEditor) , mCanceled(false) { MOZ_ASSERT(aEditor); // To protect against a reentrant call to SetValue, we check whether // another SetValue is already happening for this frame. If it is, // we must wait until we unwind to re-enable oninput events. mEditor->GetSuppressDispatchingInputEvent(&mOuterTransaction); } void Cancel() { mCanceled = true; } void Init() { mEditor->SetSuppressDispatchingInputEvent(true); } ~ValueSetter() { mEditor->SetSuppressDispatchingInputEvent(mOuterTransaction); if (mCanceled) { return; } } private: nsCOMPtr mEditor; bool mOuterTransaction; bool mCanceled; }; friend class ValueSetter; #define DEFINE_TEXTCTRL_FORWARDER(type, name) \ type name() { \ nsCOMPtr txtCtrl = do_QueryInterface(GetContent()); \ NS_ASSERTION(txtCtrl, "Content not a text control element"); \ return txtCtrl->name(); \ } #define DEFINE_TEXTCTRL_CONST_FORWARDER(type, name) \ type name() const { \ nsCOMPtr txtCtrl = do_QueryInterface(GetContent()); \ NS_ASSERTION(txtCtrl, "Content not a text control element"); \ return txtCtrl->name(); \ } DEFINE_TEXTCTRL_CONST_FORWARDER(bool, IsSingleLineTextControl) DEFINE_TEXTCTRL_CONST_FORWARDER(bool, IsTextArea) DEFINE_TEXTCTRL_CONST_FORWARDER(bool, IsPlainTextControl) DEFINE_TEXTCTRL_CONST_FORWARDER(bool, IsPasswordTextControl) DEFINE_TEXTCTRL_FORWARDER(int32_t, GetCols) DEFINE_TEXTCTRL_FORWARDER(int32_t, GetWrapCols) DEFINE_TEXTCTRL_FORWARDER(int32_t, GetRows) #undef DEFINE_TEXTCTRL_CONST_FORWARDER #undef DEFINE_TEXTCTRL_FORWARDER protected: class EditorInitializer; friend class EditorInitializer; friend class nsTextEditorState; // needs access to UpdateValueDisplay class EditorInitializer : public nsRunnable { public: EditorInitializer(nsTextControlFrame* aFrame) : mFrame(aFrame) {} NS_IMETHOD Run() MOZ_OVERRIDE; // avoids use of nsWeakFrame void Revoke() { mFrame = nullptr; } private: nsTextControlFrame* mFrame; }; class ScrollOnFocusEvent; friend class ScrollOnFocusEvent; class ScrollOnFocusEvent : public nsRunnable { public: ScrollOnFocusEvent(nsTextControlFrame* aFrame) : mFrame(aFrame) {} NS_DECL_NSIRUNNABLE void Revoke() { mFrame = nullptr; } private: nsTextControlFrame* mFrame; }; nsresult OffsetToDOMPoint(int32_t aOffset, nsIDOMNode** aResult, int32_t* aPosition); /** * Find out whether this control is scrollable (i.e. if it is not a single * line text control) * @return whether this control is scrollable */ bool IsScrollable() const; /** * Update the textnode under our anonymous div to show the new * value. This should only be called when we have no editor yet. * @throws NS_ERROR_UNEXPECTED if the div has no text content */ nsresult UpdateValueDisplay(bool aNotify, bool aBeforeEditorInit = false, const nsAString *aValue = nullptr); /** * Get the maxlength attribute * @param aMaxLength the value of the max length attr * @returns false if attr not defined */ bool GetMaxLength(int32_t* aMaxLength); /** * Find out whether an attribute exists on the content or not. * @param aAtt the attribute to determine the existence of * @returns false if it does not exist */ bool AttributeExists(nsIAtom *aAtt) const { return mContent && mContent->HasAttr(kNameSpaceID_None, aAtt); } /** * We call this when we are being destroyed or removed from the PFM. * @param aPresContext the current pres context */ void PreDestroy(); // Compute our intrinsic size. This does not include any borders, paddings, // etc. Just the size of our actual area for the text (and the scrollbars, // for