1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef nsTextControlFrame_h___
8 #define nsTextControlFrame_h___
10 #include "mozilla/Attributes.h"
11 #include "mozilla/TextControlElement.h"
12 #include "nsContainerFrame.h"
13 #include "nsIAnonymousContentCreator.h"
14 #include "nsIContent.h"
15 #include "nsITextControlFrame.h"
16 #include "nsIStatefulFrame.h"
18 class nsISelectionController
;
19 class EditorInitializerEntryTracker
;
21 class AutoTextControlHandlingState
;
23 class TextControlState
;
24 enum class PseudoStyleType
: uint8_t;
28 } // namespace mozilla
30 class nsTextControlFrame
: public nsContainerFrame
,
31 public nsIAnonymousContentCreator
,
32 public nsITextControlFrame
,
33 public nsIStatefulFrame
{
34 using Element
= mozilla::dom::Element
;
37 NS_DECL_FRAMEARENA_HELPERS(nsTextControlFrame
)
39 NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(ContentScrollPos
, nsPoint
)
42 nsTextControlFrame(ComputedStyle
*, nsPresContext
*, nsIFrame::ClassID
);
45 explicit nsTextControlFrame(ComputedStyle
* aStyle
,
46 nsPresContext
* aPresContext
)
47 : nsTextControlFrame(aStyle
, aPresContext
, kClassID
) {}
49 virtual ~nsTextControlFrame();
52 * Destroy() causes preparing to destroy editor and that may cause running
53 * selection listeners of spellchecker selection and document state listeners.
54 * Not sure whether the former does something or not, but nobody should run
55 * content script. The latter is currently only FinderHighlighter to clean up
56 * its fields at destruction. Thus, the latter won't run content script too.
57 * Therefore, this won't run unsafe script.
59 MOZ_CAN_RUN_SCRIPT_BOUNDARY
void Destroy(DestroyContext
&) override
;
61 nsIScrollableFrame
* GetScrollTargetFrame() const override
;
63 nscoord
GetMinISize(gfxContext
* aRenderingContext
) override
;
64 nscoord
GetPrefISize(gfxContext
* aRenderingContext
) override
;
66 mozilla::LogicalSize
ComputeAutoSize(
67 gfxContext
* aRenderingContext
, mozilla::WritingMode aWM
,
68 const mozilla::LogicalSize
& aCBSize
, nscoord aAvailableISize
,
69 const mozilla::LogicalSize
& aMargin
,
70 const mozilla::LogicalSize
& aBorderPadding
,
71 const mozilla::StyleSizeOverrides
& aSizeOverrides
,
72 mozilla::ComputeSizeFlags aFlags
) override
;
74 void Reflow(nsPresContext
* aPresContext
, ReflowOutput
& aDesiredSize
,
75 const ReflowInput
& aReflowInput
,
76 nsReflowStatus
& aStatus
) override
;
78 Maybe
<nscoord
> GetNaturalBaselineBOffset(
79 mozilla::WritingMode aWM
, BaselineSharingGroup aBaselineGroup
,
80 BaselineExportContext aExportContext
) const override
;
82 BaselineSharingGroup
GetDefaultBaselineSharingGroup() const override
{
83 return BaselineSharingGroup::Last
;
86 static Maybe
<nscoord
> GetSingleLineTextControlBaseline(
87 const nsIFrame
* aFrame
, nscoord aFirstBaseline
, mozilla::WritingMode aWM
,
88 BaselineSharingGroup aBaselineGroup
) {
89 if (aFrame
->StyleDisplay()->IsContainLayout()) {
92 NS_ASSERTION(aFirstBaseline
!= NS_INTRINSIC_ISIZE_UNKNOWN
,
93 "please call Reflow before asking for the baseline");
94 return mozilla::Some(aBaselineGroup
== BaselineSharingGroup::First
96 : aFrame
->BSize(aWM
) - aFirstBaseline
);
100 mozilla::a11y::AccType
AccessibleType() override
;
103 #ifdef DEBUG_FRAME_DUMP
104 nsresult
GetFrameName(nsAString
& aResult
) const override
{
105 aResult
.AssignLiteral("nsTextControlFrame");
110 // nsIAnonymousContentCreator
111 nsresult
CreateAnonymousContent(nsTArray
<ContentInfo
>& aElements
) override
;
112 void AppendAnonymousContentTo(nsTArray
<nsIContent
*>& aElements
,
113 uint32_t aFilter
) override
;
115 void SetInitialChildList(ChildListID
, nsFrameList
&&) override
;
117 void BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
118 const nsDisplayListSet
& aLists
) override
;
120 //==== BEGIN NSIFORMCONTROLFRAME
121 MOZ_CAN_RUN_SCRIPT_BOUNDARY
void SetFocus(bool aOn
, bool aRepaint
) override
;
122 MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult
123 SetFormProperty(nsAtom
* aName
, const nsAString
& aValue
) override
;
125 //==== END NSIFORMCONTROLFRAME
127 //==== NSITEXTCONTROLFRAME
129 MOZ_CAN_RUN_SCRIPT_BOUNDARY already_AddRefed
<mozilla::TextEditor
>
130 GetTextEditor() override
;
131 MOZ_CAN_RUN_SCRIPT NS_IMETHOD
132 SetSelectionRange(uint32_t aSelectionStart
, uint32_t aSelectionEnd
,
133 SelectionDirection
= SelectionDirection::None
) override
;
134 NS_IMETHOD
GetOwnedSelectionController(
135 nsISelectionController
** aSelCon
) override
;
136 nsFrameSelection
* GetOwnedFrameSelection() override
{
137 return ControlElement()->GetConstFrameSelection();
139 nsISelectionController
* GetSelectionController() {
140 return ControlElement()->GetSelectionController();
143 void PlaceholderChanged(const nsAttrValue
* aOld
, const nsAttrValue
* aNew
);
146 * Ensure mEditor is initialized with the proper flags and the default value.
147 * @throws NS_ERROR_NOT_INITIALIZED if mEditor has not been created
148 * @throws various and sundry other things
150 MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult
EnsureEditorInitialized() override
;
152 //==== END NSITEXTCONTROLFRAME
154 //==== NSISTATEFULFRAME
156 mozilla::UniquePtr
<mozilla::PresState
> SaveState() override
;
157 NS_IMETHOD
RestoreState(mozilla::PresState
* aState
) override
;
159 //=== END NSISTATEFULFRAME
161 //==== OVERLOAD of nsIFrame
163 /** handler for attribute changes to mContent */
164 MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult
AttributeChanged(
165 int32_t aNameSpaceID
, nsAtom
* aAttribute
, int32_t aModType
) override
;
166 void ElementStateChanged(mozilla::dom::ElementState aStates
) override
;
168 nsresult
PeekOffset(mozilla::PeekOffsetStruct
* aPos
) override
;
172 // Whether we should scroll only the current selection into view in the inner
173 // scroller, or also ancestors as needed.
174 enum class ScrollAncestors
{ No
, Yes
};
175 void ScrollSelectionIntoViewAsync(ScrollAncestors
= ScrollAncestors::No
);
178 MOZ_CAN_RUN_SCRIPT_BOUNDARY
void HandleReadonlyOrDisabledChange();
181 * Launch the reflow on the child frames - see nsTextControlFrame::Reflow()
183 void ReflowTextControlChild(nsIFrame
* aFrame
, nsPresContext
* aPresContext
,
184 const ReflowInput
& aReflowInput
,
185 nsReflowStatus
& aStatus
,
186 ReflowOutput
& aParentDesiredSize
,
187 nscoord
& aButtonBoxISize
);
190 static Maybe
<nscoord
> ComputeBaseline(const nsIFrame
*, const ReflowInput
&,
191 bool aForSingleLineControl
);
193 Element
* GetRootNode() const { return mRootNode
; }
195 Element
* GetPreviewNode() const { return mPreviewDiv
; }
197 Element
* GetPlaceholderNode() const { return mPlaceholderDiv
; }
199 Element
* GetRevealButton() const { return mRevealButton
; }
201 // called by the focus listener
202 nsresult
MaybeBeginSecureKeyboardInput();
203 void MaybeEndSecureKeyboardInput();
205 mozilla::TextControlElement
* ControlElement() const {
206 MOZ_ASSERT(mozilla::TextControlElement::FromNode(GetContent()));
207 return static_cast<mozilla::TextControlElement
*>(GetContent());
210 #define DEFINE_TEXTCTRL_CONST_FORWARDER(type, name) \
211 type name() const { return ControlElement()->name(); }
213 DEFINE_TEXTCTRL_CONST_FORWARDER(bool, IsSingleLineTextControl
)
214 DEFINE_TEXTCTRL_CONST_FORWARDER(bool, IsTextArea
)
215 DEFINE_TEXTCTRL_CONST_FORWARDER(bool, IsPasswordTextControl
)
216 DEFINE_TEXTCTRL_CONST_FORWARDER(int32_t, GetCols
)
217 DEFINE_TEXTCTRL_CONST_FORWARDER(int32_t, GetRows
)
219 #undef DEFINE_TEXTCTRL_CONST_FORWARDER
222 class EditorInitializer
;
223 friend class EditorInitializer
;
224 friend class mozilla::AutoTextControlHandlingState
; // needs access to
226 friend class mozilla::TextControlState
; // needs access to UpdateValueDisplay
228 // Temp reference to scriptrunner
229 NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(TextControlInitializer
, EditorInitializer
,
230 nsTextControlFrame::RevokeInitializer
)
232 static void RevokeInitializer(EditorInitializer
* aInitializer
) {
233 aInitializer
->Revoke();
236 class EditorInitializer
: public mozilla::Runnable
{
238 explicit EditorInitializer(nsTextControlFrame
* aFrame
)
239 : mozilla::Runnable("nsTextControlFrame::EditorInitializer"),
242 NS_IMETHOD
Run() override
;
244 // avoids use of AutoWeakFrame
245 void Revoke() { mFrame
= nullptr; }
248 nsTextControlFrame
* mFrame
;
251 nsresult
OffsetToDOMPoint(uint32_t aOffset
, nsINode
** aResult
,
252 uint32_t* aPosition
);
255 * Update the textnode under our anonymous div to show the new
256 * value. This should only be called when we have no editor yet.
257 * @throws NS_ERROR_UNEXPECTED if the div has no text content
259 nsresult
UpdateValueDisplay(bool aNotify
, bool aBeforeEditorInit
= false,
260 const nsAString
* aValue
= nullptr);
263 * Find out whether an attribute exists on the content or not.
264 * @param aAtt the attribute to determine the existence of
265 * @returns false if it does not exist
267 bool AttributeExists(nsAtom
* aAtt
) const {
268 return mContent
&& mContent
->AsElement()->HasAttr(aAtt
);
272 * We call this when we are being destroyed or removed from the PFM.
273 * @param aPresContext the current pres context
277 // Compute our intrinsic size. This does not include any borders, paddings,
278 // etc. Just the size of our actual area for the text (and the scrollbars,
280 mozilla::LogicalSize
CalcIntrinsicSize(gfxContext
* aRenderingContext
,
281 mozilla::WritingMode aWM
,
282 float aFontSizeInflation
) const;
286 MOZ_CAN_RUN_SCRIPT nsresult
SetSelectionInternal(
287 nsINode
* aStartNode
, uint32_t aStartOffset
, nsINode
* aEndNode
,
288 uint32_t aEndOffset
, SelectionDirection
= SelectionDirection::None
);
289 MOZ_CAN_RUN_SCRIPT nsresult
SelectAllOrCollapseToEndOfText(bool aSelect
);
290 MOZ_CAN_RUN_SCRIPT nsresult
291 SetSelectionEndPoints(uint32_t aSelStart
, uint32_t aSelEnd
,
292 SelectionDirection
= SelectionDirection::None
);
294 void FinishedInitializer() { RemoveProperty(TextControlInitializer()); }
296 const nsAString
& CachedValue() const { return mCachedValue
; }
298 void ClearCachedValue() { mCachedValue
.SetIsVoid(true); }
300 void CacheValue(const nsAString
& aValue
) { mCachedValue
.Assign(aValue
); }
302 [[nodiscard
]] bool CacheValue(const nsAString
& aValue
,
303 const mozilla::fallible_t
& aFallible
) {
304 if (!mCachedValue
.Assign(aValue
, aFallible
)) {
312 class nsAnonDivObserver
;
314 nsresult
CreateRootNode();
315 void CreatePlaceholderIfNeeded();
316 void UpdatePlaceholderText(nsString
&, bool aNotify
);
317 void CreatePreviewIfNeeded();
318 already_AddRefed
<Element
> MakeAnonElement(
319 mozilla::PseudoStyleType
, Element
* aParent
= nullptr,
320 nsAtom
* aTag
= nsGkAtoms::div
) const;
321 already_AddRefed
<Element
> MakeAnonDivWithTextNode(
322 mozilla::PseudoStyleType
) const;
324 bool ShouldInitializeEagerly() const;
325 void InitializeEagerlyIfNeeded();
327 RefPtr
<Element
> mRootNode
;
328 RefPtr
<Element
> mPlaceholderDiv
;
329 RefPtr
<Element
> mPreviewDiv
;
330 // The Reveal Password button. Only used for type=password, nullptr
332 RefPtr
<Element
> mRevealButton
;
333 RefPtr
<nsAnonDivObserver
> mMutationObserver
;
334 // Cache of the |.value| of <input> or <textarea> element without hard-wrap.
335 // If its IsVoid() returns true, it doesn't cache |.value|.
336 // Otherwise, it's cached when setting specific value or getting value from
337 // TextEditor. Additionally, when contents in the anonymous <div> element
338 // is modified, this is cleared.
340 // FIXME(bug 1402545): Consider using an nsAutoString here.
341 nsString mCachedValue
{VoidString()};
343 // Our first baseline, or NS_INTRINSIC_ISIZE_UNKNOWN if we have a pending
344 // Reflow (or if we're contain:layout, which means we have no baseline).
345 nscoord mFirstBaseline
= NS_INTRINSIC_ISIZE_UNKNOWN
;
347 // these packed bools could instead use the high order bits on mState, saving
349 bool mEditorHasBeenInitialized
= false;
350 bool mIsProcessing
= false;
353 bool mInEditorInitialization
= false;
354 friend class EditorInitializerEntryTracker
;