1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #ifndef nsTextControlFrame_h___
39 : #define nsTextControlFrame_h___
40 :
41 : #include "nsStackFrame.h"
42 : #include "nsBlockFrame.h"
43 : #include "nsIFormControlFrame.h"
44 : #include "nsIAnonymousContentCreator.h"
45 : #include "nsITextControlFrame.h"
46 : #include "nsDisplayList.h"
47 : #include "nsIScrollableFrame.h"
48 : #include "nsStubMutationObserver.h"
49 : #include "nsITextControlElement.h"
50 : #include "nsIStatefulFrame.h"
51 : #include "nsContentUtils.h" // nsAutoScriptBlocker
52 :
53 : class nsIEditor;
54 : class nsISelectionController;
55 : class nsIDOMCharacterData;
56 : #ifdef ACCESSIBILITY
57 : class nsIAccessible;
58 : #endif
59 : class EditorInitializerEntryTracker;
60 : class nsTextEditorState;
61 :
62 : class nsTextControlFrame : public nsStackFrame,
63 : public nsIAnonymousContentCreator,
64 : public nsITextControlFrame,
65 : public nsIStatefulFrame
66 : {
67 : public:
68 : NS_DECL_FRAMEARENA_HELPERS
69 :
70 0 : NS_DECLARE_FRAME_PROPERTY(ContentScrollPos, DestroyPoint)
71 :
72 : nsTextControlFrame(nsIPresShell* aShell, nsStyleContext* aContext);
73 : virtual ~nsTextControlFrame();
74 :
75 : virtual void DestroyFrom(nsIFrame* aDestructRoot);
76 :
77 0 : virtual nsIScrollableFrame* GetScrollTargetFrame() {
78 0 : if (!IsScrollable())
79 0 : return nsnull;
80 0 : return do_QueryFrame(GetFirstPrincipalChild());
81 : }
82 :
83 : virtual nscoord GetMinWidth(nsRenderingContext* aRenderingContext);
84 : virtual nsSize ComputeAutoSize(nsRenderingContext *aRenderingContext,
85 : nsSize aCBSize, nscoord aAvailableWidth,
86 : nsSize aMargin, nsSize aBorder,
87 : nsSize aPadding, bool aShrinkWrap);
88 :
89 : NS_IMETHOD Reflow(nsPresContext* aPresContext,
90 : nsHTMLReflowMetrics& aDesiredSize,
91 : const nsHTMLReflowState& aReflowState,
92 : nsReflowStatus& aStatus);
93 :
94 : virtual nsSize GetPrefSize(nsBoxLayoutState& aBoxLayoutState);
95 : virtual nsSize GetMinSize(nsBoxLayoutState& aBoxLayoutState);
96 : virtual nsSize GetMaxSize(nsBoxLayoutState& aBoxLayoutState);
97 : virtual nscoord GetBoxAscent(nsBoxLayoutState& aBoxLayoutState);
98 : virtual bool IsCollapsed();
99 :
100 0 : DECL_DO_GLOBAL_REFLOW_COUNT_DSP(nsTextControlFrame, nsStackFrame)
101 :
102 : virtual bool IsLeaf() const;
103 :
104 : #ifdef ACCESSIBILITY
105 : virtual already_AddRefed<nsAccessible> CreateAccessible();
106 : #endif
107 :
108 : #ifdef NS_DEBUG
109 0 : NS_IMETHOD GetFrameName(nsAString& aResult) const
110 : {
111 0 : aResult.AssignLiteral("nsTextControlFrame");
112 0 : return NS_OK;
113 : }
114 : #endif
115 :
116 0 : virtual bool IsFrameOfType(PRUint32 aFlags) const
117 : {
118 : // nsStackFrame is already both of these, but that's somewhat bogus,
119 : // and we really mean it.
120 : return nsStackFrame::IsFrameOfType(aFlags &
121 0 : ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
122 : }
123 :
124 : // nsIAnonymousContentCreator
125 : virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements);
126 : virtual void AppendAnonymousContentTo(nsBaseContentList& aElements,
127 : PRUint32 aFilter);
128 :
129 : // Utility methods to set current widget state
130 :
131 : NS_IMETHOD SetInitialChildList(ChildListID aListID,
132 : nsFrameList& aChildList);
133 :
134 : //==== BEGIN NSIFORMCONTROLFRAME
135 : virtual void SetFocus(bool aOn , bool aRepaint);
136 : virtual nsresult SetFormProperty(nsIAtom* aName, const nsAString& aValue);
137 : virtual nsresult GetFormProperty(nsIAtom* aName, nsAString& aValue) const;
138 :
139 :
140 : //==== END NSIFORMCONTROLFRAME
141 :
142 : //==== NSITEXTCONTROLFRAME
143 :
144 : NS_IMETHOD GetEditor(nsIEditor **aEditor);
145 : NS_IMETHOD GetTextLength(PRInt32* aTextLength);
146 : NS_IMETHOD CheckFireOnChange();
147 : NS_IMETHOD SetSelectionStart(PRInt32 aSelectionStart);
148 : NS_IMETHOD SetSelectionEnd(PRInt32 aSelectionEnd);
149 : NS_IMETHOD SetSelectionRange(PRInt32 aSelectionStart,
150 : PRInt32 aSelectionEnd,
151 : SelectionDirection aDirection = eNone);
152 : NS_IMETHOD GetSelectionRange(PRInt32* aSelectionStart,
153 : PRInt32* aSelectionEnd,
154 : SelectionDirection* aDirection = nsnull);
155 : NS_IMETHOD GetOwnedSelectionController(nsISelectionController** aSelCon);
156 : virtual nsFrameSelection* GetOwnedFrameSelection();
157 :
158 : nsresult GetPhonetic(nsAString& aPhonetic);
159 :
160 : /**
161 : * Ensure mEditor is initialized with the proper flags and the default value.
162 : * @throws NS_ERROR_NOT_INITIALIZED if mEditor has not been created
163 : * @throws various and sundry other things
164 : */
165 : virtual nsresult EnsureEditorInitialized();
166 :
167 : //==== END NSITEXTCONTROLFRAME
168 :
169 : //==== NSISTATEFULFRAME
170 :
171 : NS_IMETHOD SaveState(SpecialStateID aStateID, nsPresState** aState);
172 : NS_IMETHOD RestoreState(nsPresState* aState);
173 :
174 : //=== END NSISTATEFULFRAME
175 :
176 : //==== OVERLOAD of nsIFrame
177 : virtual nsIAtom* GetType() const;
178 :
179 : /** handler for attribute changes to mContent */
180 : NS_IMETHOD AttributeChanged(PRInt32 aNameSpaceID,
181 : nsIAtom* aAttribute,
182 : PRInt32 aModType);
183 :
184 : nsresult GetText(nsString& aText);
185 :
186 : NS_DECL_QUERYFRAME
187 :
188 : // Temp reference to scriptrunner
189 : // We could make these auto-Revoking via the "delete" entry for safety
190 0 : NS_DECLARE_FRAME_PROPERTY(TextControlInitializer, nsnull)
191 :
192 :
193 : public: //for methods who access nsTextControlFrame directly
194 : void FireOnInput(bool aTrusted);
195 : void SetValueChanged(bool aValueChanged);
196 : /** Called when the frame is focused, to remember the value for onChange. */
197 : nsresult InitFocusedValue();
198 :
199 0 : void SetFireChangeEventState(bool aNewState)
200 : {
201 0 : mFireChangeEventState = aNewState;
202 0 : }
203 :
204 0 : bool GetFireChangeEventState() const
205 : {
206 0 : return mFireChangeEventState;
207 : }
208 :
209 : // called by the focus listener
210 : nsresult MaybeBeginSecureKeyboardInput();
211 : void MaybeEndSecureKeyboardInput();
212 :
213 : class ValueSetter {
214 : public:
215 0 : ValueSetter(nsTextControlFrame* aFrame,
216 : bool aHasFocusValue)
217 : : mFrame(aFrame)
218 : // This method isn't used for user-generated changes, except for calls
219 : // from nsFileControlFrame which sets mFireChangeEventState==true and
220 : // restores it afterwards (ie. we want 'change' events for those changes).
221 : // Focused value must be updated to prevent incorrect 'change' events,
222 : // but only if user hasn't changed the value.
223 0 : , mFocusValueInit(!mFrame->mFireChangeEventState && aHasFocusValue)
224 : , mOuterTransaction(false)
225 0 : , mInited(false)
226 : {
227 0 : NS_ASSERTION(aFrame, "Should pass a valid frame");
228 0 : }
229 0 : void Cancel() {
230 0 : mInited = false;
231 0 : }
232 0 : void Init() {
233 : // Since this code does not handle user-generated changes to the text,
234 : // make sure we don't fire oninput when the editor notifies us.
235 : // (mNotifyOnInput must be reset before we return).
236 :
237 : // To protect against a reentrant call to SetValue, we check whether
238 : // another SetValue is already happening for this frame. If it is,
239 : // we must wait until we unwind to re-enable oninput events.
240 0 : mOuterTransaction = mFrame->mNotifyOnInput;
241 0 : if (mOuterTransaction)
242 0 : mFrame->mNotifyOnInput = false;
243 :
244 0 : mInited = true;
245 0 : }
246 0 : ~ValueSetter() {
247 0 : if (!mInited)
248 0 : return;
249 :
250 0 : if (mOuterTransaction)
251 0 : mFrame->mNotifyOnInput = true;
252 :
253 0 : if (mFocusValueInit) {
254 : // Reset mFocusedValue so the onchange event doesn't fire incorrectly.
255 0 : mFrame->InitFocusedValue();
256 : }
257 0 : }
258 :
259 : private:
260 : nsTextControlFrame* mFrame;
261 : bool mFocusValueInit;
262 : bool mOuterTransaction;
263 : bool mInited;
264 : };
265 : friend class ValueSetter;
266 :
267 : #define DEFINE_TEXTCTRL_FORWARDER(type, name) \
268 : type name() { \
269 : nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent()); \
270 : NS_ASSERTION(txtCtrl, "Content not a text control element"); \
271 : return txtCtrl->name(); \
272 : }
273 : #define DEFINE_TEXTCTRL_CONST_FORWARDER(type, name) \
274 : type name() const { \
275 : nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent()); \
276 : NS_ASSERTION(txtCtrl, "Content not a text control element"); \
277 : return txtCtrl->name(); \
278 : }
279 :
280 0 : DEFINE_TEXTCTRL_CONST_FORWARDER(bool, IsSingleLineTextControl)
281 0 : DEFINE_TEXTCTRL_CONST_FORWARDER(bool, IsTextArea)
282 : DEFINE_TEXTCTRL_CONST_FORWARDER(bool, IsPlainTextControl)
283 0 : DEFINE_TEXTCTRL_CONST_FORWARDER(bool, IsPasswordTextControl)
284 0 : DEFINE_TEXTCTRL_FORWARDER(PRInt32, GetCols)
285 : DEFINE_TEXTCTRL_FORWARDER(PRInt32, GetWrapCols)
286 0 : DEFINE_TEXTCTRL_FORWARDER(PRInt32, GetRows)
287 :
288 : #undef DEFINE_TEXTCTRL_CONST_FORWARDER
289 : #undef DEFINE_TEXTCTRL_FORWARDER
290 :
291 : protected:
292 : class EditorInitializer;
293 : friend class EditorInitializer;
294 : friend class nsTextEditorState; // needs access to UpdateValueDisplay
295 :
296 0 : class EditorInitializer : public nsRunnable {
297 : public:
298 0 : EditorInitializer(nsTextControlFrame* aFrame) :
299 0 : mFrame(aFrame) {}
300 :
301 0 : NS_IMETHOD Run() {
302 0 : if (mFrame) {
303 : // need to block script to avoid bug 669767
304 0 : nsAutoScriptBlocker scriptBlocker;
305 :
306 : nsCOMPtr<nsIPresShell> shell =
307 0 : mFrame->PresContext()->GetPresShell();
308 0 : bool observes = shell->ObservesNativeAnonMutationsForPrint();
309 0 : shell->ObserveNativeAnonMutationsForPrint(true);
310 : // This can cause the frame to be destroyed (and call Revoke())
311 0 : mFrame->EnsureEditorInitialized();
312 0 : shell->ObserveNativeAnonMutationsForPrint(observes);
313 :
314 : // The frame can *still* be destroyed even though we have a scriptblocker
315 : // Bug 682684
316 0 : if (!mFrame)
317 0 : return NS_ERROR_FAILURE;
318 :
319 0 : mFrame->FinishedInitializer();
320 : }
321 0 : return NS_OK;
322 : }
323 :
324 : // avoids use of nsWeakFrame
325 0 : void Revoke() {
326 0 : mFrame = nsnull;
327 0 : }
328 :
329 : private:
330 : nsTextControlFrame* mFrame;
331 : };
332 :
333 : class ScrollOnFocusEvent;
334 : friend class ScrollOnFocusEvent;
335 :
336 0 : class ScrollOnFocusEvent : public nsRunnable {
337 : public:
338 0 : ScrollOnFocusEvent(nsTextControlFrame* aFrame) :
339 0 : mFrame(aFrame) {}
340 :
341 : NS_DECL_NSIRUNNABLE
342 :
343 0 : void Revoke() {
344 0 : mFrame = nsnull;
345 0 : }
346 :
347 : private:
348 : nsTextControlFrame* mFrame;
349 : };
350 :
351 : nsresult DOMPointToOffset(nsIDOMNode* aNode, PRInt32 aNodeOffset, PRInt32 *aResult);
352 : nsresult OffsetToDOMPoint(PRInt32 aOffset, nsIDOMNode** aResult, PRInt32* aPosition);
353 :
354 : /**
355 : * Find out whether this control is scrollable (i.e. if it is not a single
356 : * line text control)
357 : * @return whether this control is scrollable
358 : */
359 : bool IsScrollable() const;
360 :
361 : /**
362 : * Update the textnode under our anonymous div to show the new
363 : * value. This should only be called when we have no editor yet.
364 : * @throws NS_ERROR_UNEXPECTED if the div has no text content
365 : */
366 : nsresult UpdateValueDisplay(bool aNotify,
367 : bool aBeforeEditorInit = false,
368 : const nsAString *aValue = nsnull);
369 :
370 : /**
371 : * Get the maxlength attribute
372 : * @param aMaxLength the value of the max length attr
373 : * @returns false if attr not defined
374 : */
375 : bool GetMaxLength(PRInt32* aMaxLength);
376 :
377 : /**
378 : * Find out whether an attribute exists on the content or not.
379 : * @param aAtt the attribute to determine the existence of
380 : * @returns false if it does not exist
381 : */
382 0 : bool AttributeExists(nsIAtom *aAtt) const
383 0 : { return mContent && mContent->HasAttr(kNameSpaceID_None, aAtt); }
384 :
385 : /**
386 : * We call this when we are being destroyed or removed from the PFM.
387 : * @param aPresContext the current pres context
388 : */
389 : void PreDestroy();
390 :
391 : // Compute our intrinsic size. This does not include any borders, paddings,
392 : // etc. Just the size of our actual area for the text (and the scrollbars,
393 : // for <textarea>).
394 : nsresult CalcIntrinsicSize(nsRenderingContext* aRenderingContext,
395 : nsSize& aIntrinsicSize,
396 : float aFontSizeInflation);
397 :
398 : nsresult ScrollSelectionIntoView();
399 :
400 : private:
401 : //helper methods
402 : nsresult SetSelectionInternal(nsIDOMNode *aStartNode, PRInt32 aStartOffset,
403 : nsIDOMNode *aEndNode, PRInt32 aEndOffset,
404 : SelectionDirection aDirection = eNone);
405 : nsresult SelectAllOrCollapseToEndOfText(bool aSelect);
406 : nsresult SetSelectionEndPoints(PRInt32 aSelStart, PRInt32 aSelEnd,
407 : SelectionDirection aDirection = eNone);
408 :
409 : // accessors for the notify on input flag
410 : bool GetNotifyOnInput() const { return mNotifyOnInput; }
411 : void SetNotifyOnInput(bool val) { mNotifyOnInput = val; }
412 :
413 : /**
414 : * Return the root DOM element, and implicitly initialize the editor if needed.
415 : */
416 : nsresult GetRootNodeAndInitializeEditor(nsIDOMElement **aRootElement);
417 :
418 0 : void FinishedInitializer() {
419 0 : Properties().Delete(TextControlInitializer());
420 0 : }
421 :
422 : private:
423 : // these packed bools could instead use the high order bits on mState, saving 4 bytes
424 : bool mUseEditor;
425 : bool mIsProcessing;
426 : bool mNotifyOnInput;//default this to off to stop any notifications until setup is complete
427 : // Calls to SetValue will be treated as user values (i.e. trigger onChange
428 : // eventually) when mFireChangeEventState==true, this is used by nsFileControlFrame.
429 : bool mFireChangeEventState;
430 : // Keep track if we have asked a placeholder node creation.
431 : bool mUsePlaceholder;
432 :
433 : #ifdef DEBUG
434 : bool mInEditorInitialization;
435 : friend class EditorInitializerEntryTracker;
436 : #endif
437 :
438 : nsString mFocusedValue;
439 : nsRevocableEventPtr<ScrollOnFocusEvent> mScrollEvent;
440 : };
441 :
442 : #endif
443 :
444 :
|