/src/mozilla-central/layout/forms/nsTextControlFrame.h
Line | Count | Source (jump to first uncovered line) |
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/. */ |
6 | | |
7 | | #ifndef nsTextControlFrame_h___ |
8 | | #define nsTextControlFrame_h___ |
9 | | |
10 | | #include "mozilla/Attributes.h" |
11 | | #include "mozilla/dom/Element.h" |
12 | | #include "nsContainerFrame.h" |
13 | | #include "nsIAnonymousContentCreator.h" |
14 | | #include "nsIContent.h" |
15 | | #include "nsITextControlFrame.h" |
16 | | #include "nsITextControlElement.h" |
17 | | #include "nsIStatefulFrame.h" |
18 | | |
19 | | class nsISelectionController; |
20 | | class EditorInitializerEntryTracker; |
21 | | class nsTextEditorState; |
22 | | namespace mozilla { |
23 | | class TextEditor; |
24 | | enum class CSSPseudoElementType : uint8_t; |
25 | | namespace dom { |
26 | | class Element; |
27 | | } // namespace dom |
28 | | } // namespace mozilla |
29 | | |
30 | | class nsTextControlFrame final : public nsContainerFrame, |
31 | | public nsIAnonymousContentCreator, |
32 | | public nsITextControlFrame, |
33 | | public nsIStatefulFrame |
34 | | { |
35 | | public: |
36 | | NS_DECL_FRAMEARENA_HELPERS(nsTextControlFrame) |
37 | | |
38 | | NS_DECLARE_FRAME_PROPERTY_DELETABLE(ContentScrollPos, nsPoint) |
39 | | |
40 | | explicit nsTextControlFrame(ComputedStyle* aStyle); |
41 | | virtual ~nsTextControlFrame(); |
42 | | |
43 | | virtual void DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData) override; |
44 | | |
45 | 0 | virtual nsIScrollableFrame* GetScrollTargetFrame() override { |
46 | 0 | return do_QueryFrame(PrincipalChildList().FirstChild()); |
47 | 0 | } |
48 | | |
49 | | virtual nscoord GetMinISize(gfxContext* aRenderingContext) override; |
50 | | virtual nscoord GetPrefISize(gfxContext* aRenderingContext) override; |
51 | | |
52 | | virtual mozilla::LogicalSize |
53 | | ComputeAutoSize(gfxContext* aRenderingContext, |
54 | | mozilla::WritingMode aWM, |
55 | | const mozilla::LogicalSize& aCBSize, |
56 | | nscoord aAvailableISize, |
57 | | const mozilla::LogicalSize& aMargin, |
58 | | const mozilla::LogicalSize& aBorder, |
59 | | const mozilla::LogicalSize& aPadding, |
60 | | ComputeSizeFlags aFlags) override; |
61 | | |
62 | | virtual void Reflow(nsPresContext* aPresContext, |
63 | | ReflowOutput& aDesiredSize, |
64 | | const ReflowInput& aReflowInput, |
65 | | nsReflowStatus& aStatus) override; |
66 | | |
67 | | bool GetVerticalAlignBaseline(mozilla::WritingMode aWM, |
68 | | nscoord* aBaseline) const override |
69 | 0 | { |
70 | 0 | return GetNaturalBaselineBOffset(aWM, BaselineSharingGroup::eFirst, aBaseline); |
71 | 0 | } |
72 | | |
73 | | bool GetNaturalBaselineBOffset(mozilla::WritingMode aWM, |
74 | | BaselineSharingGroup aBaselineGroup, |
75 | | nscoord* aBaseline) const override |
76 | 0 | { |
77 | 0 | if (!IsSingleLineTextControl()) { |
78 | 0 | return false; |
79 | 0 | } |
80 | 0 | NS_ASSERTION(mFirstBaseline != NS_INTRINSIC_WIDTH_UNKNOWN, |
81 | 0 | "please call Reflow before asking for the baseline"); |
82 | 0 | if (aBaselineGroup == BaselineSharingGroup::eFirst) { |
83 | 0 | *aBaseline = mFirstBaseline; |
84 | 0 | } else { |
85 | 0 | *aBaseline = BSize(aWM) - mFirstBaseline; |
86 | 0 | } |
87 | 0 | return true; |
88 | 0 | } |
89 | | |
90 | | virtual nsSize GetXULMinSize(nsBoxLayoutState& aBoxLayoutState) override; |
91 | | virtual bool IsXULCollapsed() override; |
92 | | |
93 | | #ifdef ACCESSIBILITY |
94 | | virtual mozilla::a11y::AccType AccessibleType() override; |
95 | | #endif |
96 | | |
97 | | #ifdef DEBUG_FRAME_DUMP |
98 | | virtual nsresult GetFrameName(nsAString& aResult) const override |
99 | | { |
100 | | aResult.AssignLiteral("nsTextControlFrame"); |
101 | | return NS_OK; |
102 | | } |
103 | | #endif |
104 | | |
105 | | virtual bool IsFrameOfType(uint32_t aFlags) const override |
106 | 0 | { |
107 | 0 | // nsStackFrame is already both of these, but that's somewhat bogus, |
108 | 0 | // and we really mean it. |
109 | 0 | return nsContainerFrame::IsFrameOfType(aFlags & |
110 | 0 | ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock)); |
111 | 0 | } |
112 | | |
113 | | #ifdef DEBUG |
114 | | void MarkIntrinsicISizesDirty() override |
115 | | { |
116 | | // Need another Reflow to have a correct baseline value again. |
117 | | mFirstBaseline = NS_INTRINSIC_WIDTH_UNKNOWN; |
118 | | } |
119 | | #endif |
120 | | |
121 | | // nsIAnonymousContentCreator |
122 | | virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override; |
123 | | virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements, |
124 | | uint32_t aFilter) override; |
125 | | |
126 | | virtual void SetInitialChildList(ChildListID aListID, |
127 | | nsFrameList& aChildList) override; |
128 | | |
129 | | virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, |
130 | | const nsDisplayListSet& aLists) override; |
131 | | |
132 | | //==== BEGIN NSIFORMCONTROLFRAME |
133 | | virtual void SetFocus(bool aOn , bool aRepaint) override; |
134 | | virtual nsresult SetFormProperty(nsAtom* aName, const nsAString& aValue) override; |
135 | | |
136 | | //==== END NSIFORMCONTROLFRAME |
137 | | |
138 | | //==== NSITEXTCONTROLFRAME |
139 | | |
140 | | NS_IMETHOD_(already_AddRefed<mozilla::TextEditor>) GetTextEditor() override; |
141 | | NS_IMETHOD SetSelectionRange(uint32_t aSelectionStart, |
142 | | uint32_t aSelectionEnd, |
143 | | SelectionDirection aDirection = eNone) override; |
144 | | NS_IMETHOD GetOwnedSelectionController(nsISelectionController** aSelCon) override; |
145 | | virtual nsFrameSelection* GetOwnedFrameSelection() override; |
146 | | |
147 | | /** |
148 | | * Ensure mEditor is initialized with the proper flags and the default value. |
149 | | * @throws NS_ERROR_NOT_INITIALIZED if mEditor has not been created |
150 | | * @throws various and sundry other things |
151 | | */ |
152 | | virtual nsresult EnsureEditorInitialized() override; |
153 | | |
154 | | //==== END NSITEXTCONTROLFRAME |
155 | | |
156 | | //==== NSISTATEFULFRAME |
157 | | |
158 | | mozilla::UniquePtr<mozilla::PresState> SaveState() override; |
159 | | NS_IMETHOD RestoreState(mozilla::PresState* aState) override; |
160 | | |
161 | | //=== END NSISTATEFULFRAME |
162 | | |
163 | | //==== OVERLOAD of nsIFrame |
164 | | |
165 | | /** handler for attribute changes to mContent */ |
166 | | virtual nsresult AttributeChanged(int32_t aNameSpaceID, |
167 | | nsAtom* aAttribute, |
168 | | int32_t aModType) override; |
169 | | |
170 | | void GetText(nsString& aText); |
171 | | |
172 | | virtual nsresult PeekOffset(nsPeekOffsetStruct *aPos) override; |
173 | | |
174 | | NS_DECL_QUERYFRAME |
175 | | |
176 | | protected: |
177 | | /** |
178 | | * Launch the reflow on the child frames - see nsTextControlFrame::Reflow() |
179 | | */ |
180 | | void ReflowTextControlChild(nsIFrame* aFrame, |
181 | | nsPresContext* aPresContext, |
182 | | const ReflowInput& aReflowInput, |
183 | | nsReflowStatus& aStatus, |
184 | | ReflowOutput& aParentDesiredSize); |
185 | | |
186 | | public: //for methods who access nsTextControlFrame directly |
187 | | void SetValueChanged(bool aValueChanged); |
188 | | |
189 | 0 | mozilla::dom::Element* GetRootNode() const { |
190 | 0 | return mRootNode; |
191 | 0 | } |
192 | | |
193 | 0 | mozilla::dom::Element* GetPreviewNode() const { |
194 | 0 | return mPreviewDiv; |
195 | 0 | } |
196 | | |
197 | | // called by the focus listener |
198 | | nsresult MaybeBeginSecureKeyboardInput(); |
199 | | void MaybeEndSecureKeyboardInput(); |
200 | | |
201 | | #define DEFINE_TEXTCTRL_CONST_FORWARDER(type, name) \ |
202 | 0 | type name() const { \ |
203 | 0 | nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent()); \ |
204 | 0 | NS_ASSERTION(txtCtrl, "Content not a text control element"); \ |
205 | 0 | return txtCtrl->name(); \ |
206 | 0 | } Unexecuted instantiation: nsTextControlFrame::IsSingleLineTextControl() const Unexecuted instantiation: nsTextControlFrame::IsTextArea() const Unexecuted instantiation: nsTextControlFrame::IsPasswordTextControl() const Unexecuted instantiation: nsTextControlFrame::GetCols() const Unexecuted instantiation: nsTextControlFrame::GetRows() const |
207 | | |
208 | | DEFINE_TEXTCTRL_CONST_FORWARDER(bool, IsSingleLineTextControl) |
209 | | DEFINE_TEXTCTRL_CONST_FORWARDER(bool, IsTextArea) |
210 | | DEFINE_TEXTCTRL_CONST_FORWARDER(bool, IsPasswordTextControl) |
211 | | DEFINE_TEXTCTRL_CONST_FORWARDER(int32_t, GetCols) |
212 | | DEFINE_TEXTCTRL_CONST_FORWARDER(int32_t, GetRows) |
213 | | |
214 | | #undef DEFINE_TEXTCTRL_CONST_FORWARDER |
215 | | |
216 | | protected: |
217 | | class EditorInitializer; |
218 | | friend class EditorInitializer; |
219 | | friend class nsTextEditorState; // needs access to UpdateValueDisplay |
220 | | |
221 | | // Temp reference to scriptrunner |
222 | | NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(TextControlInitializer, |
223 | | EditorInitializer, |
224 | | nsTextControlFrame::RevokeInitializer) |
225 | | |
226 | | static void |
227 | 0 | RevokeInitializer(EditorInitializer* aInitializer) { |
228 | 0 | aInitializer->Revoke(); |
229 | 0 | }; |
230 | | |
231 | | class EditorInitializer : public mozilla::Runnable { |
232 | | public: |
233 | | explicit EditorInitializer(nsTextControlFrame* aFrame) |
234 | | : mozilla::Runnable("nsTextControlFrame::EditorInitializer") |
235 | | , mFrame(aFrame) |
236 | 0 | { |
237 | 0 | } |
238 | | |
239 | | NS_IMETHOD Run() override; |
240 | | |
241 | | // avoids use of AutoWeakFrame |
242 | 0 | void Revoke() { |
243 | 0 | mFrame = nullptr; |
244 | 0 | } |
245 | | |
246 | | private: |
247 | | nsTextControlFrame* mFrame; |
248 | | }; |
249 | | |
250 | | class ScrollOnFocusEvent; |
251 | | friend class ScrollOnFocusEvent; |
252 | | |
253 | | class ScrollOnFocusEvent : public mozilla::Runnable { |
254 | | public: |
255 | | explicit ScrollOnFocusEvent(nsTextControlFrame* aFrame) |
256 | | : mozilla::Runnable("nsTextControlFrame::ScrollOnFocusEvent") |
257 | | , mFrame(aFrame) |
258 | 0 | { |
259 | 0 | } |
260 | | |
261 | | NS_DECL_NSIRUNNABLE |
262 | | |
263 | 0 | void Revoke() { |
264 | 0 | mFrame = nullptr; |
265 | 0 | } |
266 | | |
267 | | private: |
268 | | nsTextControlFrame* mFrame; |
269 | | }; |
270 | | |
271 | | nsresult OffsetToDOMPoint(uint32_t aOffset, nsINode** aResult, |
272 | | uint32_t* aPosition); |
273 | | |
274 | | /** |
275 | | * Update the textnode under our anonymous div to show the new |
276 | | * value. This should only be called when we have no editor yet. |
277 | | * @throws NS_ERROR_UNEXPECTED if the div has no text content |
278 | | */ |
279 | | nsresult UpdateValueDisplay(bool aNotify, |
280 | | bool aBeforeEditorInit = false, |
281 | | const nsAString *aValue = nullptr); |
282 | | |
283 | | /** |
284 | | * Get the maxlength attribute |
285 | | * @param aMaxLength the value of the max length attr |
286 | | * @returns false if attr not defined |
287 | | */ |
288 | | bool GetMaxLength(int32_t* aMaxLength); |
289 | | |
290 | | /** |
291 | | * Find out whether an attribute exists on the content or not. |
292 | | * @param aAtt the attribute to determine the existence of |
293 | | * @returns false if it does not exist |
294 | | */ |
295 | | bool AttributeExists(nsAtom *aAtt) const |
296 | 0 | { return mContent && mContent->AsElement()->HasAttr(kNameSpaceID_None, aAtt); } |
297 | | |
298 | | /** |
299 | | * We call this when we are being destroyed or removed from the PFM. |
300 | | * @param aPresContext the current pres context |
301 | | */ |
302 | | void PreDestroy(); |
303 | | |
304 | | // Compute our intrinsic size. This does not include any borders, paddings, |
305 | | // etc. Just the size of our actual area for the text (and the scrollbars, |
306 | | // for <textarea>). |
307 | | mozilla::LogicalSize CalcIntrinsicSize(gfxContext* aRenderingContext, |
308 | | mozilla::WritingMode aWM, |
309 | | float aFontSizeInflation) const; |
310 | | |
311 | | nsresult ScrollSelectionIntoView() override; |
312 | | |
313 | | private: |
314 | | //helper methods |
315 | | nsresult SetSelectionInternal(nsINode* aStartNode, uint32_t aStartOffset, |
316 | | nsINode* aEndNode, uint32_t aEndOffset, |
317 | | SelectionDirection aDirection = eNone); |
318 | | nsresult SelectAllOrCollapseToEndOfText(bool aSelect); |
319 | | nsresult SetSelectionEndPoints(uint32_t aSelStart, uint32_t aSelEnd, |
320 | | SelectionDirection aDirection = eNone); |
321 | | |
322 | 0 | void FinishedInitializer() { |
323 | 0 | DeleteProperty(TextControlInitializer()); |
324 | 0 | } |
325 | | |
326 | | const nsAString& CachedValue() const |
327 | 0 | { |
328 | 0 | return mCachedValue; |
329 | 0 | } |
330 | | |
331 | | void ClearCachedValue() |
332 | 0 | { |
333 | 0 | mCachedValue.SetIsVoid(true); |
334 | 0 | } |
335 | | |
336 | | void CacheValue(const nsAString& aValue) |
337 | 0 | { |
338 | 0 | mCachedValue.Assign(aValue); |
339 | 0 | } |
340 | | |
341 | | MOZ_MUST_USE bool |
342 | | CacheValue(const nsAString& aValue, const mozilla::fallible_t& aFallible) |
343 | 0 | { |
344 | 0 | if (!mCachedValue.Assign(aValue, aFallible)) { |
345 | 0 | ClearCachedValue(); |
346 | 0 | return false; |
347 | 0 | } |
348 | 0 | return true; |
349 | 0 | } |
350 | | |
351 | | private: |
352 | | class nsAnonDivObserver; |
353 | | |
354 | | nsresult CreateRootNode(); |
355 | | void CreatePlaceholderIfNeeded(); |
356 | | void CreatePreviewIfNeeded(); |
357 | | bool ShouldInitializeEagerly() const; |
358 | | void InitializeEagerlyIfNeeded(); |
359 | | |
360 | | RefPtr<mozilla::dom::Element> mRootNode; |
361 | | RefPtr<mozilla::dom::Element> mPlaceholderDiv; |
362 | | RefPtr<mozilla::dom::Element> mPreviewDiv; |
363 | | RefPtr<nsAnonDivObserver> mMutationObserver; |
364 | | // Cache of the |.value| of <input> or <textarea> element without hard-wrap. |
365 | | // If its IsVoid() returns true, it doesn't cache |.value|. |
366 | | // Otherwise, it's cached when setting specific value or getting value from |
367 | | // TextEditor. Additionally, when contents in the anonymous <div> element |
368 | | // is modified, this is cleared. |
369 | | // |
370 | | // FIXME(bug 1402545): Consider using an nsAutoString here. |
371 | | nsString mCachedValue; |
372 | | |
373 | | // Our first baseline, or NS_INTRINSIC_WIDTH_UNKNOWN if we have a pending |
374 | | // Reflow. |
375 | | nscoord mFirstBaseline; |
376 | | |
377 | | // these packed bools could instead use the high order bits on mState, saving 4 bytes |
378 | | bool mEditorHasBeenInitialized; |
379 | | bool mIsProcessing; |
380 | | |
381 | | #ifdef DEBUG |
382 | | bool mInEditorInitialization; |
383 | | friend class EditorInitializerEntryTracker; |
384 | | #endif |
385 | | |
386 | | nsRevocableEventPtr<ScrollOnFocusEvent> mScrollEvent; |
387 | | }; |
388 | | |
389 | | #endif |
390 | | |
391 | | |