/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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 "mozilla/dom/Element.h" #include "nsContainerFrame.h" #include "nsIAnonymousContentCreator.h" #include "nsIContent.h" #include "nsITextControlFrame.h" #include "nsITextControlElement.h" #include "nsIStatefulFrame.h" class nsISelectionController; class EditorInitializerEntryTracker; class nsTextEditorState; namespace mozilla { class TextEditor; enum class CSSPseudoElementType : uint8_t; namespace dom { class Element; } // namespace dom } // namespace mozilla class nsTextControlFrame final : public nsContainerFrame, public nsIAnonymousContentCreator, public nsITextControlFrame, public nsIStatefulFrame { public: NS_DECL_FRAMEARENA_HELPERS(nsTextControlFrame) NS_DECLARE_FRAME_PROPERTY_DELETABLE(ContentScrollPos, nsPoint) explicit nsTextControlFrame(ComputedStyle* aStyle); virtual ~nsTextControlFrame(); virtual void DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData) override; virtual nsIScrollableFrame* GetScrollTargetFrame() override { return do_QueryFrame(PrincipalChildList().FirstChild()); } virtual nscoord GetMinISize(gfxContext* aRenderingContext) override; virtual nscoord GetPrefISize(gfxContext* aRenderingContext) override; virtual mozilla::LogicalSize ComputeAutoSize( gfxContext* aRenderingContext, mozilla::WritingMode aWM, const mozilla::LogicalSize& aCBSize, nscoord aAvailableISize, const mozilla::LogicalSize& aMargin, const mozilla::LogicalSize& aBorder, const mozilla::LogicalSize& aPadding, ComputeSizeFlags aFlags) override; virtual void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, nsReflowStatus& aStatus) override; bool GetVerticalAlignBaseline(mozilla::WritingMode aWM, nscoord* aBaseline) const override { return GetNaturalBaselineBOffset(aWM, BaselineSharingGroup::eFirst, aBaseline); } bool GetNaturalBaselineBOffset(mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup, nscoord* aBaseline) const override { if (!IsSingleLineTextControl()) { return false; } NS_ASSERTION(mFirstBaseline != NS_INTRINSIC_WIDTH_UNKNOWN, "please call Reflow before asking for the baseline"); if (aBaselineGroup == BaselineSharingGroup::eFirst) { *aBaseline = mFirstBaseline; } else { *aBaseline = BSize(aWM) - mFirstBaseline; } return true; } virtual nsSize GetXULMinSize(nsBoxLayoutState& aBoxLayoutState) override; virtual bool IsXULCollapsed() override; #ifdef ACCESSIBILITY virtual mozilla::a11y::AccType AccessibleType() override; #endif #ifdef DEBUG_FRAME_DUMP virtual nsresult GetFrameName(nsAString& aResult) const override { aResult.AssignLiteral("nsTextControlFrame"); return NS_OK; } #endif virtual bool IsFrameOfType(uint32_t aFlags) const 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)); } #ifdef DEBUG void MarkIntrinsicISizesDirty() override { // Need another Reflow to have a correct baseline value again. mFirstBaseline = NS_INTRINSIC_WIDTH_UNKNOWN; } #endif // nsIAnonymousContentCreator virtual nsresult CreateAnonymousContent( nsTArray& aElements) override; virtual void AppendAnonymousContentTo(nsTArray& aElements, uint32_t aFilter) override; virtual void SetInitialChildList(ChildListID aListID, nsFrameList& aChildList) override; virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists) override; //==== BEGIN NSIFORMCONTROLFRAME virtual void SetFocus(bool aOn, bool aRepaint) override; virtual nsresult SetFormProperty(nsAtom* aName, const nsAString& aValue) override; //==== END NSIFORMCONTROLFRAME //==== NSITEXTCONTROLFRAME NS_IMETHOD_(already_AddRefed) GetTextEditor() override; NS_IMETHOD SetSelectionRange(uint32_t aSelectionStart, uint32_t aSelectionEnd, SelectionDirection aDirection = eNone) override; NS_IMETHOD GetOwnedSelectionController( nsISelectionController** aSelCon) override; virtual nsFrameSelection* GetOwnedFrameSelection() 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() override; //==== END NSITEXTCONTROLFRAME //==== NSISTATEFULFRAME mozilla::UniquePtr SaveState() override; NS_IMETHOD RestoreState(mozilla::PresState* aState) override; //=== END NSISTATEFULFRAME //==== OVERLOAD of nsIFrame /** handler for attribute changes to mContent */ virtual nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute, int32_t aModType) override; void GetText(nsString& aText); virtual nsresult PeekOffset(nsPeekOffsetStruct* aPos) override; NS_DECL_QUERYFRAME protected: /** * Launch the reflow on the child frames - see nsTextControlFrame::Reflow() */ void ReflowTextControlChild(nsIFrame* aFrame, nsPresContext* aPresContext, const ReflowInput& aReflowInput, nsReflowStatus& aStatus, ReflowOutput& aParentDesiredSize); public: // for methods who access nsTextControlFrame directly void SetValueChanged(bool aValueChanged); mozilla::dom::Element* GetRootNode() const { return mRootNode; } mozilla::dom::Element* GetPreviewNode() const { return mPreviewDiv; } // called by the focus listener nsresult MaybeBeginSecureKeyboardInput(); void MaybeEndSecureKeyboardInput(); #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, IsPasswordTextControl) DEFINE_TEXTCTRL_CONST_FORWARDER(int32_t, GetCols) DEFINE_TEXTCTRL_CONST_FORWARDER(int32_t, GetRows) #undef DEFINE_TEXTCTRL_CONST_FORWARDER protected: class EditorInitializer; friend class EditorInitializer; friend class nsTextEditorState; // needs access to UpdateValueDisplay // Temp reference to scriptrunner NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(TextControlInitializer, EditorInitializer, nsTextControlFrame::RevokeInitializer) static void RevokeInitializer(EditorInitializer* aInitializer) { aInitializer->Revoke(); }; class EditorInitializer : public mozilla::Runnable { public: explicit EditorInitializer(nsTextControlFrame* aFrame) : mozilla::Runnable("nsTextControlFrame::EditorInitializer"), mFrame(aFrame) {} NS_IMETHOD Run() override; // avoids use of AutoWeakFrame void Revoke() { mFrame = nullptr; } private: nsTextControlFrame* mFrame; }; class ScrollOnFocusEvent; friend class ScrollOnFocusEvent; class ScrollOnFocusEvent : public mozilla::Runnable { public: explicit ScrollOnFocusEvent(nsTextControlFrame* aFrame) : mozilla::Runnable("nsTextControlFrame::ScrollOnFocusEvent"), mFrame(aFrame) {} NS_DECL_NSIRUNNABLE void Revoke() { mFrame = nullptr; } private: nsTextControlFrame* mFrame; }; nsresult OffsetToDOMPoint(uint32_t aOffset, nsINode** aResult, uint32_t* aPosition); /** * 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(nsAtom* aAtt) const { return mContent && mContent->AsElement()->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