1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set sw=2 ts=2 et tw=80: */
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Mozilla.org client code.
17 : *
18 : * The Initial Developer of the Original Code is Mozilla Foundation.
19 : * Portions created by the Initial Developer are Copyright (C) 2009
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Ehsan Akhgari <ehsan@mozilla.com> (Original Author)
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #ifndef nsTextEditorState_h__
40 : #define nsTextEditorState_h__
41 :
42 : #include "nsAutoPtr.h"
43 : #include "nsString.h"
44 : #include "nsITextControlElement.h"
45 : #include "nsITextControlFrame.h"
46 : #include "nsCycleCollectionParticipant.h"
47 :
48 : class nsTextInputListener;
49 : class nsTextControlFrame;
50 : class nsTextInputSelectionImpl;
51 : class nsAnonDivObserver;
52 : class nsISelectionController;
53 : class nsFrameSelection;
54 : class nsIEditor;
55 : class nsITextControlElement;
56 :
57 : /**
58 : * nsTextEditorState is a class which is responsible for managing the state of
59 : * plaintext controls. This currently includes the following HTML elements:
60 : * <input type=text>
61 : * <input type=password>
62 : * <textarea>
63 : * and also XUL controls such as <textbox> which use one of these elements behind
64 : * the scenes.
65 : *
66 : * This class is held as a member of nsHTMLInputElement and nsHTMLTextAreaElement.
67 : * The public functions in this class include the public APIs which content/ uses.
68 : * Layout code uses the nsITextControlElement interface to invoke functions on this
69 : * class.
70 : *
71 : * The design motivation behind this class is maintaining all of the things which
72 : * collectively are considered the "state" of the text control in a single location.
73 : * This state includes several things:
74 : *
75 : * * The control's value. This value is stored in the mValue member, and is only
76 : * used when there is no frame for the control, or when the editor object has
77 : * not been initialized yet.
78 : *
79 : * * The control's associated frame. This value is stored in the mBoundFrame member.
80 : * A text control might never have an associated frame during its life cycle,
81 : * or might have several different ones, but at any given moment in time there is
82 : * a maximum of 1 bound frame to each text control.
83 : *
84 : * * The control's associated editor. This value is stored in the mEditor member.
85 : * An editor is initilized for the control only when necessary (that is, when either
86 : * the user is about to interact with the text control, or when some other code
87 : * needs to access the editor object. Without a frame bound to the control, an
88 : * editor is never initialzied. Once initialized, the editor might outlive the frame,
89 : * in which case the same editor will be used if a new frame gets bound to the
90 : * text control.
91 : *
92 : * * The anonymous content associated with the text control's frame, including the
93 : * value div (the DIV element responsible for holding the value of the text control)
94 : * and the placeholder div (the DIV element responsible for holding the placeholder
95 : * value of the text control.) These values are stored in the mRootNode and
96 : * mPlaceholderDiv members, respectively. They will be created when a
97 : * frame is bound to the text control. They will be destroyed when the frame is
98 : * unbound from the object. We could try and hold on to the anonymous content
99 : * between different frames, but unfortunately that is not currently possible
100 : * because they are not unbound from the document in time.
101 : *
102 : * * The frame selection controller. This value is stored in the mSelCon member.
103 : * The frame selection controller is responsible for maintaining the selection state
104 : * on a frame. It is created when a frame is bound to the text control element,
105 : * and will be destroy when the frame is being unbound from the text control element.
106 : * It is created alongside with the frame selection object which is stored in the
107 : * mFrameSel member.
108 : *
109 : * * The editor text listener. This value is stored in the mTextListener member.
110 : * Its job is to listen to selection and keyboard events, and act accordingly.
111 : * It is created when an a frame is first bound to the control, and will be destroyed
112 : * when the frame is unbound from the text control element.
113 : *
114 : * * The editor's cached value. This value is stored in the mCachedValue member.
115 : * It is used to improve the performance of append operations to the text
116 : * control. A mutation observer stored in the mMutationObserver has the job of
117 : * invalidating this cache when the anonymous contect containing the value is
118 : * changed.
119 : *
120 : * * The editor's cached selection properties. These vales are stored in the
121 : * mSelectionProperties member, and include the selection's start, end and
122 : * direction. They are only used when there is no frame available for the
123 : * text field.
124 : *
125 : *
126 : * As a general rule, nsTextEditorState objects own the value of the text control, and any
127 : * attempt to retrieve or set the value must be made through those objects. Internally,
128 : * the value can be represented in several different ways, based on the state the control is
129 : * in.
130 : *
131 : * * When the control is first initialized, its value is equal to the default value of
132 : * the DOM node. For <input> text controls, this default value is the value of the
133 : * value attribute. For <textarea> elements, this default value is the value of the
134 : * text node children of the element.
135 : *
136 : * * If the value has been changed through the DOM node (before the editor for the object
137 : * is initialized), the value is stored as a simple string inside the mValue member of
138 : * the nsTextEditorState object.
139 : *
140 : * * If an editor has been initialized for the control, the value is set and retrievd via
141 : * the nsIPlaintextEditor interface, and is internally managed by the editor as the
142 : * native anonymous content tree attached to the control's frame.
143 : *
144 : * * If the text editor state object is unbound from the control's frame, the value is
145 : * transferred to the mValue member variable, and will be managed there until a new
146 : * frame is bound to the text editor state object.
147 : */
148 :
149 : class RestoreSelectionState;
150 :
151 : class nsTextEditorState {
152 : public:
153 : explicit nsTextEditorState(nsITextControlElement* aOwningElement);
154 : ~nsTextEditorState();
155 :
156 1464 : NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsTextEditorState)
157 5 : NS_INLINE_DECL_REFCOUNTING(nsTextEditorState)
158 :
159 : nsIEditor* GetEditor();
160 : nsISelectionController* GetSelectionController() const;
161 : nsFrameSelection* GetConstFrameSelection();
162 : nsresult BindToFrame(nsTextControlFrame* aFrame);
163 : void UnbindFromFrame(nsTextControlFrame* aFrame);
164 : nsresult PrepareEditor(const nsAString *aValue = nsnull);
165 : void InitializeKeyboardEventListeners();
166 :
167 : void SetValue(const nsAString& aValue, bool aUserInput);
168 : void GetValue(nsAString& aValue, bool aIgnoreWrap) const;
169 0 : void EmptyValue() { if (mValue) mValue->Truncate(); }
170 0 : bool IsEmpty() const { return mValue ? mValue->IsEmpty() : true; }
171 :
172 : nsresult CreatePlaceholderNode();
173 :
174 0 : nsIContent* GetRootNode() {
175 0 : if (!mRootNode)
176 0 : CreateRootNode();
177 0 : return mRootNode;
178 : }
179 0 : nsIContent* GetPlaceholderNode() {
180 0 : return mPlaceholderDiv;
181 : }
182 :
183 0 : bool IsSingleLineTextControl() const {
184 0 : return mTextCtrlElement->IsSingleLineTextControl();
185 : }
186 : bool IsTextArea() const {
187 : return mTextCtrlElement->IsTextArea();
188 : }
189 0 : bool IsPlainTextControl() const {
190 0 : return mTextCtrlElement->IsPlainTextControl();
191 : }
192 0 : bool IsPasswordTextControl() const {
193 0 : return mTextCtrlElement->IsPasswordTextControl();
194 : }
195 : PRInt32 GetCols() {
196 : return mTextCtrlElement->GetCols();
197 : }
198 0 : PRInt32 GetWrapCols() {
199 0 : return mTextCtrlElement->GetWrapCols();
200 : }
201 : PRInt32 GetRows() {
202 : return mTextCtrlElement->GetRows();
203 : }
204 :
205 : // placeholder methods
206 : void SetPlaceholderClass(bool aVisible, bool aNotify);
207 : void UpdatePlaceholderText(bool aNotify);
208 :
209 : /**
210 : * Get the maxlength attribute
211 : * @param aMaxLength the value of the max length attr
212 : * @returns false if attr not defined
213 : */
214 : bool GetMaxLength(PRInt32* aMaxLength);
215 :
216 : /* called to free up native keybinding services */
217 : static NS_HIDDEN_(void) ShutDown();
218 :
219 0 : void ClearValueCache() { mCachedValue.Truncate(); }
220 :
221 : void HideSelectionIfBlurred();
222 :
223 : struct SelectionProperties {
224 1 : SelectionProperties() : mStart(0), mEnd(0),
225 1 : mDirection(nsITextControlFrame::eForward) {}
226 0 : bool IsDefault() const {
227 : return mStart == 0 && mEnd == 0 &&
228 0 : mDirection == nsITextControlFrame::eForward;
229 : }
230 : PRInt32 mStart, mEnd;
231 : nsITextControlFrame::SelectionDirection mDirection;
232 : };
233 :
234 0 : bool IsSelectionCached() const { return mSelectionCached; }
235 0 : SelectionProperties& GetSelectionProperties() {
236 0 : return mSelectionProperties;
237 : }
238 0 : void WillInitEagerly() { mSelectionRestoreEagerInit = true; }
239 0 : bool HasNeverInitializedBefore() const { return !mEverInited; }
240 :
241 : private:
242 : friend class RestoreSelectionState;
243 :
244 : // not copy constructible
245 : nsTextEditorState(const nsTextEditorState&);
246 : // not assignable
247 : void operator= (const nsTextEditorState&);
248 :
249 : nsresult CreateRootNode();
250 :
251 : void ValueWasChanged(bool aNotify);
252 :
253 : void DestroyEditor();
254 : void Clear();
255 :
256 : nsresult InitializeRootNode();
257 :
258 0 : void FinishedRestoringSelection() { mRestoringSelection = nsnull; }
259 :
260 : class InitializationGuard {
261 : public:
262 0 : explicit InitializationGuard(nsTextEditorState& aState) :
263 : mState(aState),
264 0 : mGuardSet(false)
265 : {
266 0 : if (!mState.mInitializing) {
267 0 : mGuardSet = true;
268 0 : mState.mInitializing = true;
269 : }
270 0 : }
271 0 : ~InitializationGuard() {
272 0 : if (mGuardSet) {
273 0 : mState.mInitializing = false;
274 : }
275 0 : }
276 0 : bool IsInitializingRecursively() const {
277 0 : return !mGuardSet;
278 : }
279 : private:
280 : nsTextEditorState& mState;
281 : bool mGuardSet;
282 : };
283 : friend class InitializationGuard;
284 : friend class PrepareEditorEvent;
285 :
286 : nsITextControlElement* const mTextCtrlElement;
287 : nsRefPtr<nsTextInputSelectionImpl> mSelCon;
288 : RestoreSelectionState* mRestoringSelection;
289 : nsCOMPtr<nsIEditor> mEditor;
290 : nsCOMPtr<nsIContent> mRootNode;
291 : nsCOMPtr<nsIContent> mPlaceholderDiv;
292 : nsTextControlFrame* mBoundFrame;
293 : nsTextInputListener* mTextListener;
294 : nsAutoPtr<nsCString> mValue;
295 : nsRefPtr<nsAnonDivObserver> mMutationObserver;
296 : mutable nsString mCachedValue; // Caches non-hard-wrapped value on a multiline control.
297 : bool mEverInited; // Have we ever been initialized?
298 : bool mEditorInitialized;
299 : bool mInitializing; // Whether we're in the process of initialization
300 : bool mValueTransferInProgress; // Whether a value is being transferred to the frame
301 : bool mSelectionCached; // Whether mSelectionProperties is valid
302 : mutable bool mSelectionRestoreEagerInit; // Whether we're eager initing because of selection restore
303 : SelectionProperties mSelectionProperties;
304 : };
305 :
306 : #endif
|