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
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/
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
15 * The Original Code is mozilla.org code.
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.
23 * Blake Ross <blakeross@telocity.com>
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.
37 * ***** END LICENSE BLOCK ***** */
41 #include "nsTextControlFrame.h"
42 #include "nsIDocument.h"
43 #include "nsIDOMNSHTMLTextAreaElement.h"
44 #include "nsIDOMNSHTMLInputElement.h"
45 #include "nsIFormControl.h"
46 #include "nsIServiceManager.h"
47 #include "nsFrameSelection.h"
48 #include "nsIPlaintextEditor.h"
49 #include "nsEditorCID.h"
50 #include "nsLayoutCID.h"
51 #include "nsIDocumentEncoder.h"
53 #include "nsISelectionListener.h"
54 #include "nsISelectionPrivate.h"
55 #include "nsIController.h"
56 #include "nsIControllers.h"
57 #include "nsIControllerContext.h"
58 #include "nsGenericHTMLElement.h"
59 #include "nsIEditorIMESupport.h"
60 #include "nsIPhonetic.h"
61 #include "nsIEditorObserver.h"
62 #include "nsIDOMHTMLTextAreaElement.h"
63 #include "nsINameSpaceManager.h"
64 #include "nsINodeInfo.h"
65 #include "nsIScrollableView.h"
66 #include "nsIScrollableFrame.h" //to turn off scroll bars
67 #include "nsFormControlFrame.h" //for registering accesskeys
68 #include "nsIDeviceContext.h" // to measure fonts
70 #include "nsIContent.h"
72 #include "nsPresContext.h"
73 #include "nsGkAtoms.h"
74 #include "nsLayoutUtils.h"
75 #include "nsIComponentManager.h"
77 #include "nsIViewManager.h"
78 #include "nsIDOMHTMLInputElement.h"
79 #include "nsIDOMElement.h"
80 #include "nsIDOMDocument.h"
81 #include "nsIPresShell.h"
82 #include "nsIComponentManager.h"
84 #include "nsBoxLayoutState.h"
85 //for keylistener for "return" check
86 #include "nsIPrivateDOMEvent.h"
87 #include "nsIDOMEventTarget.h"
88 #include "nsIDocument.h" //observe documents to send onchangenotifications
89 #include "nsIStyleSheet.h"//observe documents to send onchangenotifications
90 #include "nsIStyleRule.h"//observe documents to send onchangenotifications
91 #include "nsIDOMEventListener.h"//observe documents to send onchangenotifications
92 #include "nsGUIEvent.h"
93 #include "nsIDOMEventGroup.h"
94 #include "nsIDOM3EventTarget.h"
95 #include "nsIDOMNSEvent.h"
96 #include "nsIDOMNSUIEvent.h"
97 #include "nsIEventStateManager.h"
99 #include "nsIDOMFocusListener.h" //onchange events
100 #include "nsIDOMCharacterData.h" //for selection setting helper func
101 #include "nsIDOMNodeList.h" //for selection setting helper func
102 #include "nsIDOMRange.h" //for selection setting helper func
103 #include "nsPIDOMWindow.h" //needed for notify selection changed to update the menus ect.
105 #include "nsIAccessibilityService.h"
107 #include "nsIServiceManager.h"
108 #include "nsIDOMNode.h"
109 #include "nsITextControlElement.h"
111 #include "nsIEditorObserver.h"
112 #include "nsITransactionManager.h"
113 #include "nsIDOMText.h" //for multiline getselection
114 #include "nsNodeInfoManager.h"
115 #include "nsContentCreatorFunctions.h"
116 #include "nsIDOMKeyListener.h"
117 #include "nsIDOMEventGroup.h"
118 #include "nsIDOM3EventTarget.h"
119 #include "nsINativeKeyBindings.h"
120 #include "nsIJSContextStack.h"
121 #include "nsFocusManager.h"
123 #define DEFAULT_COLUMN_WIDTH 20
125 #include "nsContentCID.h"
126 static NS_DEFINE_IID(kRangeCID
, NS_RANGE_CID
);
128 static NS_DEFINE_CID(kTextEditorCID
, NS_TEXTEDITOR_CID
);
129 static NS_DEFINE_CID(kFrameSelectionCID
, NS_FRAMESELECTION_CID
);
131 static const PRInt32 DEFAULT_COLS
= 20;
132 static const PRInt32 DEFAULT_ROWS
= 1;
133 static const PRInt32 DEFAULT_ROWS_TEXTAREA
= 2;
134 static const PRInt32 DEFAULT_UNDO_CAP
= 1000;
136 static nsINativeKeyBindings
*sNativeInputBindings
= nsnull
;
137 static nsINativeKeyBindings
*sNativeTextAreaBindings
= nsnull
;
140 PlatformToDOMLineBreaks(nsString
&aString
)
142 // Windows linebreaks: Map CRLF to LF:
143 aString
.ReplaceSubstring(NS_LITERAL_STRING("\r\n").get(),
144 NS_LITERAL_STRING("\n").get());
146 // Mac linebreaks: Map any remaining CR to LF:
147 aString
.ReplaceSubstring(NS_LITERAL_STRING("\r").get(),
148 NS_LITERAL_STRING("\n").get());
151 // wrap can be one of these three values.
153 eHTMLTextWrap_Off
= 1, // "off"
154 eHTMLTextWrap_Hard
= 2, // "hard"
155 eHTMLTextWrap_Soft
= 3 // the default
159 GetWrapPropertyEnum(nsIContent
* aContent
, nsHTMLTextWrap
& aWrapProp
)
161 // soft is the default; "physical" defaults to soft as well because all other
162 // browsers treat it that way and there is no real reason to maintain physical
163 // and virtual as separate entities if no one else does. Only hard and off
164 // do anything different.
165 aWrapProp
= eHTMLTextWrap_Soft
; // the default
168 if (aContent
->IsNodeOfType(nsINode::eHTML
)) {
169 static nsIContent::AttrValuesArray strings
[] =
170 {&nsGkAtoms::HARD
, &nsGkAtoms::OFF
, nsnull
};
172 switch (aContent
->FindAttrValueIn(kNameSpaceID_None
, nsGkAtoms::wrap
,
173 strings
, eIgnoreCase
)) {
174 case 0: aWrapProp
= eHTMLTextWrap_Hard
; break;
175 case 1: aWrapProp
= eHTMLTextWrap_Off
; break;
184 class nsTextInputListener
: public nsISelectionListener
,
185 public nsIDOMKeyListener
,
186 public nsIEditorObserver
,
187 public nsSupportsWeakReference
190 /** the default constructor
192 nsTextInputListener();
193 /** the default destructor. virtual due to the possibility of derivation.
195 virtual ~nsTextInputListener();
197 /** SetEditor gives an address to the editor that will be accessed
198 * @param aEditor the editor this listener calls for editing operations
200 void SetFrame(nsTextControlFrame
*aFrame
){mFrame
= aFrame
;}
204 NS_DECL_NSISELECTIONLISTENER
206 NS_IMETHOD
HandleEvent(nsIDOMEvent
* aEvent
);
209 NS_IMETHOD
KeyDown(nsIDOMEvent
*aKeyEvent
);
210 NS_IMETHOD
KeyPress(nsIDOMEvent
*aKeyEvent
);
211 NS_IMETHOD
KeyUp(nsIDOMEvent
*aKeyEvent
);
213 NS_DECL_NSIEDITOROBSERVER
217 nsresult
UpdateTextInputCommands(const nsAString
& commandsToUpdate
);
219 NS_HIDDEN_(nsINativeKeyBindings
*) GetKeyBindings();
223 nsTextControlFrame
* mFrame
; // weak reference
225 PRPackedBool mSelectionWasCollapsed
;
227 * Whether we had undo items or not the last time we got EditAction()
228 * notification (when this state changes we update undo and redo menus)
230 PRPackedBool mHadUndoItems
;
232 * Whether we had redo items or not the last time we got EditAction()
233 * notification (when this state changes we update undo and redo menus)
235 PRPackedBool mHadRedoItems
;
240 * nsTextEditorListener implementation
243 nsTextInputListener::nsTextInputListener()
245 , mSelectionWasCollapsed(PR_TRUE
)
246 , mHadUndoItems(PR_FALSE
)
247 , mHadRedoItems(PR_FALSE
)
251 nsTextInputListener::~nsTextInputListener()
255 NS_IMPL_ADDREF(nsTextInputListener
)
256 NS_IMPL_RELEASE(nsTextInputListener
)
258 NS_INTERFACE_MAP_BEGIN(nsTextInputListener
)
259 NS_INTERFACE_MAP_ENTRY(nsISelectionListener
)
260 NS_INTERFACE_MAP_ENTRY(nsIEditorObserver
)
261 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
262 NS_INTERFACE_MAP_ENTRY(nsIDOMKeyListener
)
263 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEventListener
, nsIDOMKeyListener
)
264 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIDOMKeyListener
)
267 // BEGIN nsIDOMSelectionListener
270 IsFocusedContent(nsIContent
* aContent
)
272 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
276 nsCOMPtr
<nsIDOMElement
> focusedElement
;
277 fm
->GetFocusedElement(getter_AddRefs(focusedElement
));
278 nsCOMPtr
<nsIContent
> focusedContent
= do_QueryInterface(focusedElement
);
279 return (focusedContent
== aContent
);
283 nsTextInputListener::NotifySelectionChanged(nsIDOMDocument
* aDoc
, nsISelection
* aSel
, PRInt16 aReason
)
286 if (!mFrame
|| !aDoc
|| !aSel
|| NS_FAILED(aSel
->GetIsCollapsed(&collapsed
)))
289 // Fire the select event
290 // The specs don't exactly say when we should fire the select event.
291 // IE: Whenever you add/remove a character to/from the selection. Also
292 // each time for select all. Also if you get to the end of the text
293 // field you will get new event for each keypress or a continuous
294 // stream of events if you use the mouse. IE will fire select event
295 // when the selection collapses to nothing if you are holding down
296 // the shift or mouse button.
297 // Mozilla: If we have non-empty selection we will fire a new event for each
298 // keypress (or mouseup) if the selection changed. Mozilla will also
299 // create the event each time select all is called, even if everything
300 // was previously selected, becase technically select all will first collapse
301 // and then extend. Mozilla will never create an event if the selection
302 // collapses to nothing.
303 if (!collapsed
&& (aReason
& (nsISelectionListener::MOUSEUP_REASON
|
304 nsISelectionListener::KEYPRESS_REASON
|
305 nsISelectionListener::SELECTALL_REASON
)))
307 nsIContent
* content
= mFrame
->GetContent();
310 nsCOMPtr
<nsIDocument
> doc
= content
->GetDocument();
313 nsCOMPtr
<nsIPresShell
> presShell
= doc
->GetPrimaryShell();
316 nsEventStatus status
= nsEventStatus_eIgnore
;
317 nsEvent
event(PR_TRUE
, NS_FORM_SELECTED
);
319 presShell
->HandleEventWithTarget(&event
, mFrame
, content
, &status
);
325 // if the collapsed state did not change, don't fire notifications
326 if (collapsed
== mSelectionWasCollapsed
)
329 mSelectionWasCollapsed
= collapsed
;
331 if (!mFrame
|| !IsFocusedContent(mFrame
->GetContent()))
334 return UpdateTextInputCommands(NS_LITERAL_STRING("select"));
337 // END nsIDOMSelectionListener
339 // BEGIN nsIDOMKeyListener
342 nsTextInputListener::HandleEvent(nsIDOMEvent
* aEvent
)
348 DoCommandCallback(const char *aCommand
, void *aData
)
350 nsTextControlFrame
*frame
= static_cast<nsTextControlFrame
*>(aData
);
351 nsIContent
*content
= frame
->GetContent();
353 nsCOMPtr
<nsIControllers
> controllers
;
354 nsCOMPtr
<nsIDOMNSHTMLInputElement
> input
= do_QueryInterface(content
);
356 input
->GetControllers(getter_AddRefs(controllers
));
358 nsCOMPtr
<nsIDOMNSHTMLTextAreaElement
> textArea
=
359 do_QueryInterface(content
);
362 textArea
->GetControllers(getter_AddRefs(controllers
));
367 NS_WARNING("Could not get controllers");
371 nsCOMPtr
<nsIController
> controller
;
372 controllers
->GetControllerForCommand(aCommand
, getter_AddRefs(controller
));
374 controller
->DoCommand(aCommand
);
380 nsTextInputListener::KeyDown(nsIDOMEvent
*aDOMEvent
)
382 nsCOMPtr
<nsIDOMKeyEvent
> keyEvent(do_QueryInterface(aDOMEvent
));
383 NS_ENSURE_TRUE(keyEvent
, NS_ERROR_INVALID_ARG
);
385 nsNativeKeyEvent nativeEvent
;
386 nsINativeKeyBindings
*bindings
= GetKeyBindings();
388 nsContentUtils::DOMEventToNativeKeyEvent(keyEvent
, &nativeEvent
, PR_FALSE
)) {
389 if (bindings
->KeyDown(nativeEvent
, DoCommandCallback
, mFrame
)) {
390 aDOMEvent
->PreventDefault();
398 nsTextInputListener::KeyPress(nsIDOMEvent
*aDOMEvent
)
400 nsCOMPtr
<nsIDOMKeyEvent
> keyEvent(do_QueryInterface(aDOMEvent
));
401 NS_ENSURE_TRUE(keyEvent
, NS_ERROR_INVALID_ARG
);
403 nsNativeKeyEvent nativeEvent
;
404 nsINativeKeyBindings
*bindings
= GetKeyBindings();
406 nsContentUtils::DOMEventToNativeKeyEvent(keyEvent
, &nativeEvent
, PR_TRUE
)) {
407 if (bindings
->KeyPress(nativeEvent
, DoCommandCallback
, mFrame
)) {
408 aDOMEvent
->PreventDefault();
416 nsTextInputListener::KeyUp(nsIDOMEvent
*aDOMEvent
)
418 nsCOMPtr
<nsIDOMKeyEvent
> keyEvent(do_QueryInterface(aDOMEvent
));
419 NS_ENSURE_TRUE(keyEvent
, NS_ERROR_INVALID_ARG
);
421 nsNativeKeyEvent nativeEvent
;
422 nsINativeKeyBindings
*bindings
= GetKeyBindings();
424 nsContentUtils::DOMEventToNativeKeyEvent(keyEvent
, &nativeEvent
, PR_FALSE
)) {
425 if (bindings
->KeyUp(nativeEvent
, DoCommandCallback
, mFrame
)) {
426 aDOMEvent
->PreventDefault();
432 // END nsIDOMKeyListener
434 // BEGIN nsIEditorObserver
437 nsTextInputListener::EditAction()
440 // Update the undo / redo menus
442 nsCOMPtr
<nsIEditor
> editor
;
443 mFrame
->GetEditor(getter_AddRefs(editor
));
445 nsCOMPtr
<nsITransactionManager
> manager
;
446 editor
->GetTransactionManager(getter_AddRefs(manager
));
447 NS_ENSURE_TRUE(manager
, NS_ERROR_FAILURE
);
449 // Get the number of undo / redo items
450 PRInt32 numUndoItems
= 0;
451 PRInt32 numRedoItems
= 0;
452 manager
->GetNumberOfUndoItems(&numUndoItems
);
453 manager
->GetNumberOfRedoItems(&numRedoItems
);
454 if ((numUndoItems
&& !mHadUndoItems
) || (!numUndoItems
&& mHadUndoItems
) ||
455 (numRedoItems
&& !mHadRedoItems
) || (!numRedoItems
&& mHadRedoItems
)) {
456 // Modify the menu if undo or redo items are different
457 UpdateTextInputCommands(NS_LITERAL_STRING("undo"));
459 mHadUndoItems
= numUndoItems
!= 0;
460 mHadRedoItems
= numRedoItems
!= 0;
463 // Make sure we know we were changed (do NOT set this to false if there are
464 // no undo items; JS could change the value and we'd still need to save it)
465 mFrame
->SetValueChanged(PR_TRUE
);
468 mFrame
->FireOnInput();
473 // END nsIEditorObserver
477 nsTextInputListener::UpdateTextInputCommands(const nsAString
& commandsToUpdate
)
479 NS_ENSURE_STATE(mFrame
);
481 nsIContent
* content
= mFrame
->GetContent();
482 NS_ENSURE_TRUE(content
, NS_ERROR_FAILURE
);
484 nsCOMPtr
<nsIDocument
> doc
= content
->GetDocument();
485 NS_ENSURE_TRUE(doc
, NS_ERROR_FAILURE
);
487 nsPIDOMWindow
*domWindow
= doc
->GetWindow();
488 NS_ENSURE_TRUE(domWindow
, NS_ERROR_FAILURE
);
490 return domWindow
->UpdateCommands(commandsToUpdate
);
493 nsINativeKeyBindings
*
494 nsTextInputListener::GetKeyBindings()
496 if (mFrame
->IsTextArea()) {
497 static PRBool sNoTextAreaBindings
= PR_FALSE
;
499 if (!sNativeTextAreaBindings
&& !sNoTextAreaBindings
) {
500 CallGetService(NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX
"textarea",
501 &sNativeTextAreaBindings
);
503 if (!sNativeTextAreaBindings
) {
504 sNoTextAreaBindings
= PR_TRUE
;
508 return sNativeTextAreaBindings
;
511 static PRBool sNoInputBindings
= PR_FALSE
;
512 if (!sNativeInputBindings
&& !sNoInputBindings
) {
513 CallGetService(NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX
"input",
514 &sNativeInputBindings
);
516 if (!sNativeInputBindings
) {
517 sNoInputBindings
= PR_TRUE
;
521 return sNativeInputBindings
;
524 // END nsTextInputListener
526 class nsTextInputSelectionImpl
: public nsSupportsWeakReference
527 , public nsISelectionController
532 nsTextInputSelectionImpl(nsFrameSelection
*aSel
, nsIPresShell
*aShell
, nsIContent
*aLimiter
);
533 ~nsTextInputSelectionImpl(){}
535 //NSISELECTIONCONTROLLER INTERFACES
536 NS_IMETHOD
SetDisplaySelection(PRInt16 toggle
);
537 NS_IMETHOD
GetDisplaySelection(PRInt16
*_retval
);
538 NS_IMETHOD
SetSelectionFlags(PRInt16 aInEnable
);
539 NS_IMETHOD
GetSelectionFlags(PRInt16
*aOutEnable
);
540 NS_IMETHOD
GetSelection(PRInt16 type
, nsISelection
**_retval
);
541 NS_IMETHOD
ScrollSelectionIntoView(PRInt16 aType
, PRInt16 aRegion
, PRBool aIsSynchronous
);
542 NS_IMETHOD
RepaintSelection(PRInt16 type
);
543 NS_IMETHOD
RepaintSelection(nsPresContext
* aPresContext
, SelectionType aSelectionType
);
544 NS_IMETHOD
SetCaretEnabled(PRBool enabled
);
545 NS_IMETHOD
SetCaretReadOnly(PRBool aReadOnly
);
546 NS_IMETHOD
GetCaretEnabled(PRBool
*_retval
);
547 NS_IMETHOD
GetCaretVisible(PRBool
*_retval
);
548 NS_IMETHOD
SetCaretVisibilityDuringSelection(PRBool aVisibility
);
549 NS_IMETHOD
CharacterMove(PRBool aForward
, PRBool aExtend
);
550 NS_IMETHOD
CharacterExtendForDelete();
551 NS_IMETHOD
WordMove(PRBool aForward
, PRBool aExtend
);
552 NS_IMETHOD
WordExtendForDelete(PRBool aForward
);
553 NS_IMETHOD
LineMove(PRBool aForward
, PRBool aExtend
);
554 NS_IMETHOD
IntraLineMove(PRBool aForward
, PRBool aExtend
);
555 NS_IMETHOD
PageMove(PRBool aForward
, PRBool aExtend
);
556 NS_IMETHOD
CompleteScroll(PRBool aForward
);
557 NS_IMETHOD
CompleteMove(PRBool aForward
, PRBool aExtend
);
558 NS_IMETHOD
ScrollPage(PRBool aForward
);
559 NS_IMETHOD
ScrollLine(PRBool aForward
);
560 NS_IMETHOD
ScrollHorizontal(PRBool aLeft
);
561 NS_IMETHOD
SelectAll(void);
562 NS_IMETHOD
CheckVisibility(nsIDOMNode
*node
, PRInt16 startOffset
, PRInt16 EndOffset
, PRBool
*_retval
);
565 nsCOMPtr
<nsFrameSelection
> mFrameSelection
;
566 nsCOMPtr
<nsIContent
> mLimiter
;
567 nsWeakPtr mPresShellWeak
;
570 // Implement our nsISupports methods
571 NS_IMPL_ISUPPORTS3(nsTextInputSelectionImpl
,
572 nsISelectionController
,
574 nsISupportsWeakReference
)
577 // BEGIN nsTextInputSelectionImpl
579 nsTextInputSelectionImpl::nsTextInputSelectionImpl(nsFrameSelection
*aSel
, nsIPresShell
*aShell
, nsIContent
*aLimiter
)
583 mFrameSelection
= aSel
;//we are the owner now!
585 mFrameSelection
->Init(aShell
, mLimiter
);
586 mPresShellWeak
= do_GetWeakReference(aShell
);
591 nsTextInputSelectionImpl::SetDisplaySelection(PRInt16 aToggle
)
593 if (!mFrameSelection
)
594 return NS_ERROR_NULL_POINTER
;
596 mFrameSelection
->SetDisplaySelection(aToggle
);
601 nsTextInputSelectionImpl::GetDisplaySelection(PRInt16
*aToggle
)
603 if (!mFrameSelection
)
604 return NS_ERROR_NULL_POINTER
;
606 *aToggle
= mFrameSelection
->GetDisplaySelection();
611 nsTextInputSelectionImpl::SetSelectionFlags(PRInt16 aToggle
)
613 return NS_OK
;//stub this out. not used in input
617 nsTextInputSelectionImpl::GetSelectionFlags(PRInt16
*aOutEnable
)
619 *aOutEnable
= nsISelectionDisplay::DISPLAY_TEXT
;
624 nsTextInputSelectionImpl::GetSelection(PRInt16 type
, nsISelection
**_retval
)
626 if (!mFrameSelection
)
627 return NS_ERROR_NULL_POINTER
;
629 *_retval
= mFrameSelection
->GetSelection(type
);
632 return NS_ERROR_FAILURE
;
639 nsTextInputSelectionImpl::ScrollSelectionIntoView(PRInt16 aType
, PRInt16 aRegion
, PRBool aIsSynchronous
)
641 if (mFrameSelection
) {
642 // After ScrollSelectionIntoView(), the pending notifications might be
643 // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
644 nsresult rv
= mFrameSelection
->ScrollSelectionIntoView(aType
, aRegion
, aIsSynchronous
);
646 nsIScrollableView
* scrollableView
= mFrameSelection
->GetScrollableView();
647 if (!scrollableView
) {
650 nsIView
* view
= nsnull
;
651 scrollableView
->GetScrolledView(view
);
655 const nsRect portRect
= scrollableView
->View()->GetBounds();
656 const nsRect viewRect
= view
->GetBounds();
657 if (viewRect
.XMost() < portRect
.width
) {
658 return scrollableView
->ScrollTo(PR_MAX(viewRect
.width
- portRect
.width
, 0), -viewRect
.y
, 0);
663 return NS_ERROR_NULL_POINTER
;
667 nsTextInputSelectionImpl::RepaintSelection(PRInt16 type
)
669 if (!mFrameSelection
)
670 return NS_ERROR_FAILURE
;
672 return mFrameSelection
->RepaintSelection(type
);
676 nsTextInputSelectionImpl::RepaintSelection(nsPresContext
* aPresContext
, SelectionType aSelectionType
)
678 if (!mFrameSelection
)
679 return NS_ERROR_FAILURE
;
681 return mFrameSelection
->RepaintSelection(aSelectionType
);
685 nsTextInputSelectionImpl::SetCaretEnabled(PRBool enabled
)
687 if (!mPresShellWeak
) return NS_ERROR_NOT_INITIALIZED
;
689 nsCOMPtr
<nsIPresShell
> shell
= do_QueryReferent(mPresShellWeak
);
690 if (!shell
) return NS_ERROR_FAILURE
;
692 // tell the pres shell to enable the caret, rather than settings its visibility directly.
693 // this way the presShell's idea of caret visibility is maintained.
694 nsCOMPtr
<nsISelectionController
> selCon
= do_QueryInterface(shell
);
695 if (!selCon
) return NS_ERROR_NO_INTERFACE
;
696 selCon
->SetCaretEnabled(enabled
);
702 nsTextInputSelectionImpl::SetCaretReadOnly(PRBool aReadOnly
)
704 if (!mPresShellWeak
) return NS_ERROR_NOT_INITIALIZED
;
706 nsCOMPtr
<nsIPresShell
> shell
= do_QueryReferent(mPresShellWeak
, &result
);
709 nsRefPtr
<nsCaret
> caret
;
710 if (NS_SUCCEEDED(shell
->GetCaret(getter_AddRefs(caret
))))
712 nsISelection
* domSel
= mFrameSelection
->
713 GetSelection(nsISelectionController::SELECTION_NORMAL
);
715 caret
->SetCaretReadOnly(aReadOnly
);
719 return NS_ERROR_FAILURE
;
723 nsTextInputSelectionImpl::GetCaretEnabled(PRBool
*_retval
)
725 return GetCaretVisible(_retval
);
729 nsTextInputSelectionImpl::GetCaretVisible(PRBool
*_retval
)
731 if (!mPresShellWeak
) return NS_ERROR_NOT_INITIALIZED
;
733 nsCOMPtr
<nsIPresShell
> shell
= do_QueryReferent(mPresShellWeak
, &result
);
736 nsRefPtr
<nsCaret
> caret
;
737 if (NS_SUCCEEDED(shell
->GetCaret(getter_AddRefs(caret
))))
739 nsISelection
* domSel
= mFrameSelection
->
740 GetSelection(nsISelectionController::SELECTION_NORMAL
);
742 return caret
->GetCaretVisible(_retval
);
745 return NS_ERROR_FAILURE
;
749 nsTextInputSelectionImpl::SetCaretVisibilityDuringSelection(PRBool aVisibility
)
751 if (!mPresShellWeak
) return NS_ERROR_NOT_INITIALIZED
;
753 nsCOMPtr
<nsIPresShell
> shell
= do_QueryReferent(mPresShellWeak
, &result
);
756 nsRefPtr
<nsCaret
> caret
;
757 if (NS_SUCCEEDED(shell
->GetCaret(getter_AddRefs(caret
))))
759 nsISelection
* domSel
= mFrameSelection
->
760 GetSelection(nsISelectionController::SELECTION_NORMAL
);
762 caret
->SetVisibilityDuringSelection(aVisibility
);
766 return NS_ERROR_FAILURE
;
770 nsTextInputSelectionImpl::CharacterMove(PRBool aForward
, PRBool aExtend
)
773 return mFrameSelection
->CharacterMove(aForward
, aExtend
);
774 return NS_ERROR_NULL_POINTER
;
778 nsTextInputSelectionImpl::CharacterExtendForDelete()
781 return mFrameSelection
->CharacterExtendForDelete();
782 return NS_ERROR_NULL_POINTER
;
786 nsTextInputSelectionImpl::WordMove(PRBool aForward
, PRBool aExtend
)
789 return mFrameSelection
->WordMove(aForward
, aExtend
);
790 return NS_ERROR_NULL_POINTER
;
794 nsTextInputSelectionImpl::WordExtendForDelete(PRBool aForward
)
797 return mFrameSelection
->WordExtendForDelete(aForward
);
798 return NS_ERROR_NULL_POINTER
;
802 nsTextInputSelectionImpl::LineMove(PRBool aForward
, PRBool aExtend
)
806 nsresult result
= mFrameSelection
->LineMove(aForward
, aExtend
);
807 if (NS_FAILED(result
))
808 result
= CompleteMove(aForward
,aExtend
);
811 return NS_ERROR_NULL_POINTER
;
816 nsTextInputSelectionImpl::IntraLineMove(PRBool aForward
, PRBool aExtend
)
819 return mFrameSelection
->IntraLineMove(aForward
, aExtend
);
820 return NS_ERROR_NULL_POINTER
;
825 nsTextInputSelectionImpl::PageMove(PRBool aForward
, PRBool aExtend
)
827 // expected behavior for PageMove is to scroll AND move the caret
828 // and to remain relative position of the caret in view. see Bug 4302.
832 nsCOMPtr
<nsIPresShell
> presShell
= do_QueryReferent(mPresShellWeak
);
834 return NS_ERROR_NULL_POINTER
;
836 //get the scroll view
837 nsIScrollableView
*scrollableView
= mFrameSelection
->GetScrollableView();
839 mFrameSelection
->CommonPageMove(aForward
, aExtend
, scrollableView
);
841 // After ScrollSelectionIntoView(), the pending notifications might be
842 // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
843 return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL
, nsISelectionController::SELECTION_FOCUS_REGION
, PR_TRUE
);
847 nsTextInputSelectionImpl::CompleteScroll(PRBool aForward
)
849 nsIScrollableView
*scrollableView
= mFrameSelection
->GetScrollableView();
852 return NS_ERROR_NOT_INITIALIZED
;
854 return scrollableView
->ScrollByWhole(!aForward
); //TRUE = top, aForward TRUE=bottom
858 nsTextInputSelectionImpl::CompleteMove(PRBool aForward
, PRBool aExtend
)
860 // grab the parent / root DIV for this text widget
861 nsIContent
* parentDIV
= mFrameSelection
->GetLimiter();
863 return NS_ERROR_UNEXPECTED
;
865 // make the caret be either at the very beginning (0) or the very end
867 nsFrameSelection::HINT hint
= nsFrameSelection::HINTLEFT
;
870 offset
= parentDIV
->GetChildCount();
872 // Prevent the caret from being placed after the last
873 // BR node in the content tree!
877 nsIContent
*child
= parentDIV
->GetChildAt(offset
- 1);
879 if (child
->Tag() == nsGkAtoms::br
)
882 hint
= nsFrameSelection::HINTRIGHT
; // for Bug 106855
887 mFrameSelection
->HandleClick(parentDIV
, offset
, offset
, aExtend
,
890 // if we got this far, attempt to scroll no matter what the above result is
891 return CompleteScroll(aForward
);
895 nsTextInputSelectionImpl::ScrollPage(PRBool aForward
)
897 nsIScrollableView
*scrollableView
= mFrameSelection
->GetScrollableView();
899 return NS_ERROR_NOT_INITIALIZED
;
901 return scrollableView
->ScrollByPages(0, aForward
? 1 : -1);
905 nsTextInputSelectionImpl::ScrollLine(PRBool aForward
)
907 nsIScrollableView
*scrollableView
= mFrameSelection
->GetScrollableView();
909 return NS_ERROR_NOT_INITIALIZED
;
911 // will we have bug #7354 because we aren't forcing an update here?
912 return scrollableView
->ScrollByLines(0, aForward
? 1 : -1);
916 nsTextInputSelectionImpl::ScrollHorizontal(PRBool aLeft
)
918 nsIScrollableView
*scrollableView
= mFrameSelection
->GetScrollableView();
920 return NS_ERROR_NOT_INITIALIZED
;
922 // will we have bug #7354 because we aren't forcing an update here?
923 return scrollableView
->ScrollByLines(aLeft
? -1 : 1, 0);
927 nsTextInputSelectionImpl::SelectAll()
930 return mFrameSelection
->SelectAll();
931 return NS_ERROR_NULL_POINTER
;
935 nsTextInputSelectionImpl::CheckVisibility(nsIDOMNode
*node
, PRInt16 startOffset
, PRInt16 EndOffset
, PRBool
*_retval
)
937 if (!mPresShellWeak
) return NS_ERROR_NOT_INITIALIZED
;
939 nsCOMPtr
<nsISelectionController
> shell
= do_QueryReferent(mPresShellWeak
, &result
);
942 return shell
->CheckVisibility(node
,startOffset
,EndOffset
, _retval
);
944 return NS_ERROR_FAILURE
;
949 NS_NewTextControlFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
951 return new (aPresShell
) nsTextControlFrame(aPresShell
, aContext
);
954 NS_QUERYFRAME_HEAD(nsTextControlFrame
)
955 NS_QUERYFRAME_ENTRY(nsIFormControlFrame
)
956 NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator
)
957 NS_QUERYFRAME_ENTRY(nsITextControlFrame
)
958 if (nsIScrollableViewProvider::kFrameIID
== id
&& IsScrollable())
959 return static_cast<nsIScrollableViewProvider
*>(this);
960 NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame
)
963 NS_IMETHODIMP
nsTextControlFrame::GetAccessible(nsIAccessible
** aAccessible
)
965 nsCOMPtr
<nsIAccessibilityService
> accService
= do_GetService("@mozilla.org/accessibilityService;1");
968 return accService
->CreateHTMLTextFieldAccessible(static_cast<nsIFrame
*>(this), aAccessible
);
971 return NS_ERROR_FAILURE
;
975 nsTextControlFrame::nsTextControlFrame(nsIPresShell
* aShell
, nsStyleContext
* aContext
)
976 : nsStackFrame(aShell
, aContext
)
977 , mUseEditor(PR_FALSE
)
978 , mIsProcessing(PR_FALSE
)
979 , mNotifyOnInput(PR_TRUE
)
980 , mDidPreDestroy(PR_FALSE
)
981 , mFireChangeEventState(PR_FALSE
)
982 , mInSecureKeyboardInputMode(PR_FALSE
)
983 , mTextListener(nsnull
)
987 nsTextControlFrame::~nsTextControlFrame()
989 NS_IF_RELEASE(mTextListener
);
993 SuppressEventHandlers(nsPresContext
* aPresContext
)
995 PRBool suppressHandlers
= PR_FALSE
;
999 // Right now we only suppress event handlers and controller manipulation
1000 // when in a print preview or print context!
1002 // In the current implementation, we only paginate when
1003 // printing or in print preview.
1005 suppressHandlers
= aPresContext
->IsPaginated();
1008 return suppressHandlers
;
1012 nsTextControlFrame::PreDestroy()
1014 // notify the editor that we are going away
1017 // If we were in charge of state before, relinquish it back
1021 // First get the frame state from the editor
1023 GetValue(value
, PR_TRUE
);
1025 mUseEditor
= PR_FALSE
;
1027 // Next store the frame state in the control
1028 // (now that mUseEditor is false values get stored
1032 mEditor
->PreDestroy(PR_TRUE
);
1035 // Clean up the controller
1037 if (!SuppressEventHandlers(PresContext()))
1039 nsCOMPtr
<nsIControllers
> controllers
;
1040 nsCOMPtr
<nsIDOMNSHTMLInputElement
> inputElement
= do_QueryInterface(mContent
);
1042 inputElement
->GetControllers(getter_AddRefs(controllers
));
1045 nsCOMPtr
<nsIDOMNSHTMLTextAreaElement
> textAreaElement
= do_QueryInterface(mContent
);
1046 if (textAreaElement
) {
1047 textAreaElement
->GetControllers(getter_AddRefs(controllers
));
1053 PRUint32 numControllers
;
1054 nsresult rv
= controllers
->GetControllerCount(&numControllers
);
1055 NS_ASSERTION((NS_SUCCEEDED(rv
)), "bad result in gfx text control destructor");
1056 for (PRUint32 i
= 0; i
< numControllers
; i
++)
1058 nsCOMPtr
<nsIController
> controller
;
1059 rv
= controllers
->GetControllerAt(i
, getter_AddRefs(controller
));
1060 if (NS_SUCCEEDED(rv
) && controller
)
1062 nsCOMPtr
<nsIControllerContext
> editController
= do_QueryInterface(controller
);
1065 editController
->SetCommandContext(nsnull
);
1075 mFrameSel
->SetScrollableViewProvider(nsnull
);
1076 mFrameSel
->DisconnectFromPresShell();
1080 nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame
*>(this), PR_FALSE
);
1083 mTextListener
->SetFrame(nsnull
);
1085 nsCOMPtr
<nsIDOMEventGroup
> systemGroup
;
1086 mContent
->GetSystemEventGroup(getter_AddRefs(systemGroup
));
1087 nsCOMPtr
<nsIDOM3EventTarget
> dom3Targ
= do_QueryInterface(mContent
);
1089 // cast because of ambiguous base
1090 nsIDOMEventListener
*listener
= static_cast<nsIDOMKeyListener
*>
1093 dom3Targ
->RemoveGroupedEventListener(NS_LITERAL_STRING("keydown"),
1094 listener
, PR_FALSE
, systemGroup
);
1095 dom3Targ
->RemoveGroupedEventListener(NS_LITERAL_STRING("keypress"),
1096 listener
, PR_FALSE
, systemGroup
);
1097 dom3Targ
->RemoveGroupedEventListener(NS_LITERAL_STRING("keyup"),
1098 listener
, PR_FALSE
, systemGroup
);
1102 mDidPreDestroy
= PR_TRUE
;
1106 nsTextControlFrame::Destroy()
1108 if (mInSecureKeyboardInputMode
) {
1109 MaybeEndSecureKeyboardInput();
1111 if (!mDidPreDestroy
) {
1115 mFrameSel
->SetScrollableViewProvider(nsnull
);
1117 nsContentUtils::DestroyAnonymousContent(&mAnonymousDiv
);
1118 nsBoxFrame::Destroy();
1122 nsTextControlFrame::RemovedAsPrimaryFrame()
1124 if (!mDidPreDestroy
) {
1127 else NS_ASSERTION(PR_FALSE
, "RemovedAsPrimaryFrame called after PreDestroy");
1131 nsTextControlFrame::GetType() const
1133 return nsGkAtoms::textInputFrame
;
1136 // XXX: wouldn't it be nice to get this from the style context!
1137 PRBool
nsTextControlFrame::IsSingleLineTextControl() const
1139 nsCOMPtr
<nsIFormControl
> formControl
= do_QueryInterface(mContent
);
1141 PRInt32 type
= formControl
->GetType();
1142 return (type
== NS_FORM_INPUT_TEXT
) || (type
== NS_FORM_INPUT_PASSWORD
);
1147 PRBool
nsTextControlFrame::IsTextArea() const
1149 return mContent
&& mContent
->Tag() == nsGkAtoms::textarea
;
1152 // XXX: wouldn't it be nice to get this from the style context!
1153 PRBool
nsTextControlFrame::IsPlainTextControl() const
1155 // need to check HTML attribute of mContent and/or CSS.
1159 nsresult
nsTextControlFrame::MaybeBeginSecureKeyboardInput()
1161 nsresult rv
= NS_OK
;
1162 if (IsPasswordTextControl() && !mInSecureKeyboardInputMode
) {
1163 nsIWidget
* window
= GetWindow();
1164 NS_ENSURE_TRUE(window
, NS_ERROR_FAILURE
);
1165 rv
= window
->BeginSecureKeyboardInput();
1166 mInSecureKeyboardInputMode
= NS_SUCCEEDED(rv
);
1171 void nsTextControlFrame::MaybeEndSecureKeyboardInput()
1173 if (mInSecureKeyboardInputMode
) {
1174 nsIWidget
* window
= GetWindow();
1177 window
->EndSecureKeyboardInput();
1178 mInSecureKeyboardInputMode
= PR_FALSE
;
1182 PRBool
nsTextControlFrame::IsPasswordTextControl() const
1184 nsCOMPtr
<nsIFormControl
> formControl
= do_QueryInterface(mContent
);
1185 return formControl
&& formControl
->GetType() == NS_FORM_INPUT_PASSWORD
;
1190 nsTextControlFrame::GetCols()
1192 nsGenericHTMLElement
*content
= nsGenericHTMLElement::FromContent(mContent
);
1193 NS_ASSERTION(content
, "Content is not HTML content!");
1196 const nsAttrValue
* attr
= content
->GetParsedAttr(nsGkAtoms::cols
);
1198 PRInt32 cols
= attr
->Type() == nsAttrValue::eInteger
?
1199 attr
->GetIntegerValue() : 0;
1200 // XXX why a default of 1 char, why hide it
1201 return (cols
<= 0) ? 1 : cols
;
1204 // Else we know (assume) it is an input with size attr
1205 const nsAttrValue
* attr
= content
->GetParsedAttr(nsGkAtoms::size
);
1206 if (attr
&& attr
->Type() == nsAttrValue::eInteger
) {
1207 PRInt32 cols
= attr
->GetIntegerValue();
1214 return DEFAULT_COLS
;
1219 nsTextControlFrame::GetRows()
1222 nsGenericHTMLElement
*content
=
1223 nsGenericHTMLElement::FromContent(mContent
);
1224 NS_ASSERTION(content
, "Content is not HTML content!");
1226 const nsAttrValue
* attr
= content
->GetParsedAttr(nsGkAtoms::rows
);
1227 if (attr
&& attr
->Type() == nsAttrValue::eInteger
) {
1228 PRInt32 rows
= attr
->GetIntegerValue();
1229 return (rows
<= 0) ? DEFAULT_ROWS_TEXTAREA
: rows
;
1231 return DEFAULT_ROWS_TEXTAREA
;
1234 return DEFAULT_ROWS
;
1239 nsTextControlFrame::CalcIntrinsicSize(nsIRenderingContext
* aRenderingContext
,
1240 nsSize
& aIntrinsicSize
)
1242 // Get leading and the Average/MaxAdvance char width
1243 nscoord lineHeight
= 0;
1244 nscoord charWidth
= 0;
1245 nscoord charMaxAdvance
= 0;
1247 nsCOMPtr
<nsIFontMetrics
> fontMet
;
1249 nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fontMet
));
1250 NS_ENSURE_SUCCESS(rv
, rv
);
1251 aRenderingContext
->SetFont(fontMet
);
1254 nsHTMLReflowState::CalcLineHeight(GetStyleContext(), NS_AUTOHEIGHT
);
1255 fontMet
->GetAveCharWidth(charWidth
);
1256 fontMet
->GetMaxAdvance(charMaxAdvance
);
1258 // Set the width equal to the width in characters
1259 PRInt32 cols
= GetCols();
1260 aIntrinsicSize
.width
= cols
* charWidth
;
1262 // To better match IE, take the maximum character width(in twips) and remove
1263 // 4 pixels add this on as additional padding(internalPadding). But only do
1264 // this if charMaxAdvance != charWidth; if they are equal, this is almost
1265 // certainly a fixed-width font.
1266 if (charWidth
!= charMaxAdvance
) {
1267 nscoord internalPadding
= PR_MAX(0, charMaxAdvance
-
1268 nsPresContext::CSSPixelsToAppUnits(4));
1269 nscoord t
= nsPresContext::CSSPixelsToAppUnits(1);
1270 // Round to a multiple of t
1271 nscoord rest
= internalPadding
% t
;
1272 if (rest
< t
- rest
) {
1273 internalPadding
-= rest
;
1275 internalPadding
+= t
- rest
;
1277 // Now add the extra padding on (so that small input sizes work well)
1278 aIntrinsicSize
.width
+= internalPadding
;
1280 // This is to account for the anonymous <br> having a 1 twip width
1281 // in Full Standards mode, see BRFrame::Reflow and bug 228752.
1282 if (PresContext()->CompatibilityMode() == eCompatibility_FullStandards
) {
1283 aIntrinsicSize
.width
+= 1;
1286 // Also add in the padding of our anonymous div child. Note that it hasn't
1287 // been reflowed yet, so we can't get its used padding, but it shouldn't be
1288 // using percentage padding anyway.
1289 nsMargin childPadding
;
1290 if (GetFirstChild(nsnull
)->GetStylePadding()->GetPadding(childPadding
)) {
1291 aIntrinsicSize
.width
+= childPadding
.LeftRight();
1293 NS_ERROR("Percentage padding on anonymous div?");
1297 // Increment width with cols * letter-spacing.
1299 const nsStyleCoord
& lsCoord
= GetStyleText()->mLetterSpacing
;
1300 if (eStyleUnit_Coord
== lsCoord
.GetUnit()) {
1301 nscoord letterSpacing
= lsCoord
.GetCoordValue();
1302 if (letterSpacing
!= 0) {
1303 aIntrinsicSize
.width
+= cols
* letterSpacing
;
1308 // Set the height equal to total number of rows (times the height of each
1310 aIntrinsicSize
.height
= lineHeight
* GetRows();
1312 // Add in the size of the scrollbars for textarea
1314 nsIFrame
* first
= GetFirstChild(nsnull
);
1316 nsIScrollableFrame
*scrollableFrame
= do_QueryFrame(first
);
1317 NS_ASSERTION(scrollableFrame
, "Child must be scrollable");
1319 nsMargin scrollbarSizes
=
1320 scrollableFrame
->GetDesiredScrollbarSizes(PresContext(), aRenderingContext
);
1322 aIntrinsicSize
.width
+= scrollbarSizes
.LeftRight();
1324 aIntrinsicSize
.height
+= scrollbarSizes
.TopBottom();;
1331 nsTextControlFrame::DelayedEditorInit()
1333 nsIDocument
* doc
= mContent
->GetCurrentDoc();
1338 nsWeakFrame
weakFrame(this);
1340 // Flush out content on our document. Have to do this, because script
1341 // blockers don't prevent the sink flushing out content and notifying in the
1342 // process, which can destroy frames.
1343 doc
->FlushPendingNotifications(Flush_ContentAndNotify
);
1344 if (!weakFrame
.IsAlive()) {
1348 // Make sure that editor init doesn't do things that would kill us off
1349 // (especially off the script blockers it'll create for its DOM mutations).
1350 nsAutoScriptBlocker scriptBlocker
;
1352 // Time to mess with our security context... See comments in GetValue()
1353 // for why this is needed.
1358 if (IsFocusedContent(GetContent()))
1359 SetFocus(PR_TRUE
, PR_FALSE
);
1363 nsTextControlFrame::GetWrapCols()
1366 // wrap=off means -1 for wrap width no matter what cols is
1367 nsHTMLTextWrap wrapProp
;
1368 ::GetWrapPropertyEnum(mContent
, wrapProp
);
1369 if (wrapProp
== eHTMLTextWrap_Off
) {
1370 // do not wrap when wrap=off
1374 // Otherwise we just wrap at the given number of columns
1378 // Never wrap non-textareas
1383 nsTextControlFrame::InitEditor()
1385 // This method initializes our editor, if needed.
1387 // This code used to be called from CreateAnonymousContent(), but
1388 // when the editor set the initial string, it would trigger a
1389 // PresShell listener which called FlushPendingNotifications()
1390 // during frame construction. This was causing other form controls
1391 // to display wrong values. So we call this from a script runner
1394 // Check if this method has been called already.
1395 // If so, just return early.
1403 mEditor
= do_CreateInstance(kTextEditorCID
, &rv
);
1404 NS_ENSURE_SUCCESS(rv
, rv
);
1406 // Setup the editor flags
1408 PRUint32 editorFlags
= 0;
1409 if (IsPlainTextControl())
1410 editorFlags
|= nsIPlaintextEditor::eEditorPlaintextMask
;
1411 if (IsSingleLineTextControl())
1412 editorFlags
|= nsIPlaintextEditor::eEditorSingleLineMask
;
1413 if (IsPasswordTextControl())
1414 editorFlags
|= nsIPlaintextEditor::eEditorPasswordMask
;
1416 // All nsTextControlFrames are widgets
1417 editorFlags
|= nsIPlaintextEditor::eEditorWidgetMask
;
1419 // Use async reflow and painting for text widgets to improve
1422 // XXX: Using editor async updates exposes bugs 158782, 151882,
1423 // and 165130, so we're disabling it for now, until they
1424 // can be addressed.
1425 // editorFlags |= nsIPlaintextEditor::eEditorUseAsyncUpdatesMask;
1427 // Now initialize the editor.
1429 // NOTE: Conversion of '\n' to <BR> happens inside the
1430 // editor's Init() call.
1432 nsPresContext
*presContext
= PresContext();
1433 nsIPresShell
*shell
= presContext
->GetPresShell();
1435 // Get the DOM document
1436 nsCOMPtr
<nsIDOMDocument
> domdoc
= do_QueryInterface(shell
->GetDocument());
1438 return NS_ERROR_FAILURE
;
1440 rv
= mEditor
->Init(domdoc
, shell
, mAnonymousDiv
, mSelCon
, editorFlags
);
1441 NS_ENSURE_SUCCESS(rv
, rv
);
1443 // Initialize the controller for the editor
1445 if (!SuppressEventHandlers(presContext
)) {
1446 nsCOMPtr
<nsIControllers
> controllers
;
1447 nsCOMPtr
<nsIDOMNSHTMLInputElement
> inputElement
=
1448 do_QueryInterface(mContent
);
1450 rv
= inputElement
->GetControllers(getter_AddRefs(controllers
));
1452 nsCOMPtr
<nsIDOMNSHTMLTextAreaElement
> textAreaElement
=
1453 do_QueryInterface(mContent
);
1455 if (!textAreaElement
)
1456 return NS_ERROR_FAILURE
;
1458 rv
= textAreaElement
->GetControllers(getter_AddRefs(controllers
));
1465 PRUint32 numControllers
;
1466 PRBool found
= PR_FALSE
;
1467 rv
= controllers
->GetControllerCount(&numControllers
);
1468 for (PRUint32 i
= 0; i
< numControllers
; i
++) {
1469 nsCOMPtr
<nsIController
> controller
;
1470 rv
= controllers
->GetControllerAt(i
, getter_AddRefs(controller
));
1471 if (NS_SUCCEEDED(rv
) && controller
) {
1472 nsCOMPtr
<nsIControllerContext
> editController
=
1473 do_QueryInterface(controller
);
1474 if (editController
) {
1475 editController
->SetCommandContext(mEditor
);
1481 rv
= NS_ERROR_FAILURE
;
1485 // Initialize the plaintext editor
1486 nsCOMPtr
<nsIPlaintextEditor
> textEditor(do_QueryInterface(mEditor
));
1489 textEditor
->SetWrapColumn(GetWrapCols());
1491 // Set max text field length
1493 if (GetMaxLength(&maxLength
)) {
1494 textEditor
->SetMaxTextLength(maxLength
);
1499 rv
= mEditor
->GetFlags(&editorFlags
);
1504 // Check if the readonly attribute is set.
1506 if (mContent
->HasAttr(kNameSpaceID_None
, nsGkAtoms::readonly
))
1507 editorFlags
|= nsIPlaintextEditor::eEditorReadonlyMask
;
1509 // Check if the disabled attribute is set.
1511 if (mContent
->HasAttr(kNameSpaceID_None
, nsGkAtoms::disabled
))
1512 editorFlags
|= nsIPlaintextEditor::eEditorDisabledMask
;
1514 // Disable the selection if necessary.
1516 if (editorFlags
& nsIPlaintextEditor::eEditorDisabledMask
)
1517 mSelCon
->SetDisplaySelection(nsISelectionController::SELECTION_OFF
);
1519 mEditor
->SetFlags(editorFlags
);
1522 // Get the current value of the textfield from the content.
1523 nsAutoString defaultValue
;
1524 GetValue(defaultValue
, PR_TRUE
);
1526 // Turn on mUseEditor so that subsequent calls will use the
1528 mUseEditor
= PR_TRUE
;
1530 // If we have a default value, insert it under the div we created
1531 // above, but be sure to use the editor so that '*' characters get
1532 // displayed for password fields, etc. SetValue() will call the
1535 if (!defaultValue
.IsEmpty()) {
1536 // Avoid causing reentrant painting and reflowing by telling the editor
1537 // that we don't want it to force immediate view refreshes or force
1538 // immediate reflows during any editor calls.
1540 rv
= mEditor
->SetFlags(editorFlags
|
1541 nsIPlaintextEditor::eEditorUseAsyncUpdatesMask
);
1546 // Now call SetValue() which will make the necessary editor calls to set
1547 // the default value. Make sure to turn off undo before setting the default
1548 // value, and turn it back on afterwards. This will make sure we can't undo
1549 // past the default value.
1551 rv
= mEditor
->EnableUndo(PR_FALSE
);
1556 SetValue(defaultValue
);
1558 rv
= mEditor
->EnableUndo(PR_TRUE
);
1559 NS_ASSERTION(NS_SUCCEEDED(rv
),"Transaction Manager must have failed");
1561 // Now restore the original editor flags.
1562 rv
= mEditor
->SetFlags(editorFlags
);
1568 nsCOMPtr
<nsITransactionManager
> transMgr
;
1569 mEditor
->GetTransactionManager(getter_AddRefs(transMgr
));
1570 NS_ENSURE_TRUE(transMgr
, NS_ERROR_FAILURE
);
1572 transMgr
->SetMaxTransactionCount(DEFAULT_UNDO_CAP
);
1574 if (IsPasswordTextControl()) {
1575 // Disable undo for password textfields. Note that we want to do this at
1576 // the very end of InitEditor, so the calls to EnableUndo when setting the
1577 // default value don't screw us up.
1578 // Since changing the control type does a reframe, we don't have to worry
1579 // about dynamic type changes here.
1580 mEditor
->EnableUndo(PR_FALSE
);
1583 mEditor
->PostCreate();
1589 nsTextControlFrame::CreateAnonymousContent(nsTArray
<nsIContent
*>& aElements
)
1591 mState
|= NS_FRAME_INDEPENDENT_SELECTION
;
1593 nsIPresShell
* shell
= PresContext()->GetPresShell();
1595 return NS_ERROR_FAILURE
;
1597 nsIDocument
*doc
= shell
->GetDocument();
1599 return NS_ERROR_FAILURE
;
1601 // Now create a DIV and add it to the anonymous content child list.
1602 nsCOMPtr
<nsINodeInfo
> nodeInfo
;
1603 nodeInfo
= doc
->NodeInfoManager()->GetNodeInfo(nsGkAtoms::div
, nsnull
,
1604 kNameSpaceID_XHTML
);
1605 NS_ENSURE_TRUE(nodeInfo
, NS_ERROR_OUT_OF_MEMORY
);
1607 nsresult rv
= NS_NewHTMLElement(getter_AddRefs(mAnonymousDiv
), nodeInfo
, PR_FALSE
);
1608 NS_ENSURE_SUCCESS(rv
, rv
);
1610 // Set the div native anonymous, so CSS will be its style language
1611 // no matter what. We need to do this before we set the 'style' attribute.
1612 mAnonymousDiv
->SetNativeAnonymous();
1614 // Set the necessary style attributes on the text control.
1616 rv
= mAnonymousDiv
->SetAttr(kNameSpaceID_None
, nsGkAtoms::_class
,
1617 NS_LITERAL_STRING("anonymous-div"), PR_FALSE
);
1618 NS_ENSURE_SUCCESS(rv
, rv
);
1620 nsAutoString styleValue
;
1621 PRInt32 wrapCols
= GetWrapCols();
1622 if (wrapCols
>= 0) {
1623 styleValue
.AppendLiteral("white-space:pre-wrap");
1625 styleValue
.AppendLiteral("white-space:pre");
1627 if (!IsSingleLineTextControl()) {
1628 // We can't just inherit the overflow because setting visible overflow will
1629 // crash when the number of lines exceeds the height of the textarea and
1630 // setting -moz-hidden-unscrollable overflow (NS_STYLE_OVERFLOW_CLIP)
1631 // doesn't paint the caret for some reason.
1632 const nsStyleDisplay
* disp
= GetStyleDisplay();
1633 if (disp
->mOverflowX
!= NS_STYLE_OVERFLOW_VISIBLE
&&
1634 disp
->mOverflowX
!= NS_STYLE_OVERFLOW_CLIP
) {
1635 styleValue
.AppendLiteral(";overflow:inherit");
1638 rv
= mAnonymousDiv
->SetAttr(kNameSpaceID_None
, nsGkAtoms::style
,
1639 styleValue
, PR_FALSE
);
1640 NS_ENSURE_SUCCESS(rv
, rv
);
1642 if (!aElements
.AppendElement(mAnonymousDiv
))
1643 return NS_ERROR_OUT_OF_MEMORY
;
1647 mFrameSel
= do_CreateInstance(kFrameSelectionCID
, &rv
);
1650 mFrameSel
->SetScrollableViewProvider(this);
1652 // Create a SelectionController
1654 mSelCon
= static_cast<nsISelectionController
*>
1655 (new nsTextInputSelectionImpl(mFrameSel
, shell
,
1658 return NS_ERROR_OUT_OF_MEMORY
;
1659 mTextListener
= new nsTextInputListener();
1661 return NS_ERROR_OUT_OF_MEMORY
;
1662 NS_ADDREF(mTextListener
);
1664 mTextListener
->SetFrame(this);
1665 mSelCon
->SetDisplaySelection(nsISelectionController::SELECTION_ON
);
1667 // Get the caret and make it a selection listener.
1669 nsRefPtr
<nsISelection
> domSelection
;
1670 if (NS_SUCCEEDED(mSelCon
->GetSelection(nsISelectionController::SELECTION_NORMAL
,
1671 getter_AddRefs(domSelection
))) &&
1673 nsCOMPtr
<nsISelectionPrivate
> selPriv(do_QueryInterface(domSelection
));
1674 nsRefPtr
<nsCaret
> caret
;
1675 nsCOMPtr
<nsISelectionListener
> listener
;
1676 if (NS_SUCCEEDED(shell
->GetCaret(getter_AddRefs(caret
))) && caret
) {
1677 listener
= do_QueryInterface(caret
);
1679 selPriv
->AddSelectionListener(listener
);
1683 selPriv
->AddSelectionListener(static_cast<nsISelectionListener
*>
1687 NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
1688 "Someone forgot a script blocker?");
1690 if (!nsContentUtils::AddScriptRunner(new EditorInitializer(this))) {
1691 return NS_ERROR_OUT_OF_MEMORY
;
1698 nsTextControlFrame::GetMinWidth(nsIRenderingContext
* aRenderingContext
)
1700 // Our min width is just our preferred width if we have auto width.
1702 DISPLAY_MIN_WIDTH(this, result
);
1704 result
= GetPrefWidth(aRenderingContext
);
1710 nsTextControlFrame::ComputeAutoSize(nsIRenderingContext
*aRenderingContext
,
1711 nsSize aCBSize
, nscoord aAvailableWidth
,
1712 nsSize aMargin
, nsSize aBorder
,
1713 nsSize aPadding
, PRBool aShrinkWrap
)
1716 nsresult rv
= CalcIntrinsicSize(aRenderingContext
, autoSize
);
1717 if (NS_FAILED(rv
)) {
1719 autoSize
.SizeTo(0, 0);
1722 // Note: Ancestor ComputeAutoSize only computes a width if we're auto-width
1723 else if (GetStylePosition()->mWidth
.GetUnit() == eStyleUnit_Auto
) {
1724 nsSize ancestorAutoSize
=
1725 nsStackFrame::ComputeAutoSize(aRenderingContext
,
1726 aCBSize
, aAvailableWidth
,
1728 aPadding
, aShrinkWrap
);
1729 NS_ASSERTION(ancestorAutoSize
.width
== autoSize
.width
,
1730 "Incorrect size computed by ComputeAutoSize?");
1738 // We inherit our GetPrefWidth from nsBoxFrame
1741 nsTextControlFrame::Reflow(nsPresContext
* aPresContext
,
1742 nsHTMLReflowMetrics
& aDesiredSize
,
1743 const nsHTMLReflowState
& aReflowState
,
1744 nsReflowStatus
& aStatus
)
1746 DO_GLOBAL_REFLOW_COUNT("nsTextControlFrame");
1747 DISPLAY_REFLOW(aPresContext
, this, aReflowState
, aDesiredSize
, aStatus
);
1749 // make sure the the form registers itself on the initial/first reflow
1750 if (mState
& NS_FRAME_FIRST_REFLOW
) {
1751 nsFormControlFrame::RegUnRegAccessKey(this, PR_TRUE
);
1754 return nsStackFrame::Reflow(aPresContext
, aDesiredSize
, aReflowState
,
1759 nsTextControlFrame::GetPrefSize(nsBoxLayoutState
& aState
)
1761 if (!DoesNeedRecalc(mPrefSize
))
1765 PropagateDebug(aState
);
1770 nsresult rv
= CalcIntrinsicSize(aState
.GetRenderingContext(), pref
);
1771 NS_ENSURE_SUCCESS(rv
, pref
);
1772 AddBorderAndPadding(pref
);
1778 nsMargin
borderPadding(0,0,0,0);
1779 GetBorderAndPadding(borderPadding
);
1780 nsSize
size(169, 24);
1781 nsSize
actual(pref
.width
/15,
1783 printf("nsGfxText(field) %d,%d %d,%d %d,%d\n",
1784 size
.width
, size
.height
, actual
.width
, actual
.height
, actual
.width
-size
.width
, actual
.height
-size
.height
); // text field
1792 nsTextControlFrame::GetMinSize(nsBoxLayoutState
& aState
)
1794 // XXXbz why? Why not the nsBoxFrame sizes?
1795 return nsBox::GetMinSize(aState
);
1799 nsTextControlFrame::GetMaxSize(nsBoxLayoutState
& aState
)
1801 // XXXbz why? Why not the nsBoxFrame sizes?
1802 return nsBox::GetMaxSize(aState
);
1806 nsTextControlFrame::GetBoxAscent(nsBoxLayoutState
& aState
)
1808 // Return the baseline of the first (nominal) row, with centering for
1809 // single-line controls.
1811 // First calculate the ascent wrt the client rect
1813 GetClientRect(clientRect
);
1814 nscoord lineHeight
=
1815 IsSingleLineTextControl() ? clientRect
.height
:
1816 nsHTMLReflowState::CalcLineHeight(GetStyleContext(), NS_AUTOHEIGHT
);
1818 nsCOMPtr
<nsIFontMetrics
> fontMet
;
1820 nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fontMet
));
1821 NS_ENSURE_SUCCESS(rv
, 0);
1823 nscoord ascent
= nsLayoutUtils::GetCenteredFontBaseline(fontMet
, lineHeight
);
1825 // Now adjust for our borders and padding
1826 ascent
+= clientRect
.y
;
1832 nsTextControlFrame::IsCollapsed(nsBoxLayoutState
& aBoxLayoutState
)
1834 // We're never collapsed in the box sense.
1839 nsTextControlFrame::IsLeaf() const
1844 //IMPLEMENTING NS_IFORMCONTROLFRAME
1845 void nsTextControlFrame::SetFocus(PRBool aOn
, PRBool aRepaint
)
1847 nsCOMPtr
<nsIEditor
> editor
;
1848 GetEditor(getter_AddRefs(editor
));
1852 editor
->RemoveEditorObserver(mTextListener
);
1854 MaybeEndSecureKeyboardInput();
1862 editor
->AddEditorObserver(mTextListener
);
1864 if (NS_SUCCEEDED(InitFocusedValue()))
1865 MaybeBeginSecureKeyboardInput();
1867 // tell the caret to use our selection
1869 nsCOMPtr
<nsISelection
> ourSel
;
1870 mSelCon
->GetSelection(nsISelectionController::SELECTION_NORMAL
,
1871 getter_AddRefs(ourSel
));
1872 if (!ourSel
) return;
1874 nsIPresShell
* presShell
= PresContext()->GetPresShell();
1875 nsRefPtr
<nsCaret
> caret
;
1876 presShell
->GetCaret(getter_AddRefs(caret
));
1878 caret
->SetCaretDOMSelection(ourSel
);
1880 // mutual-exclusion: the selection is either controlled by the
1881 // document or by the text input/area. Clear any selection in the
1882 // document since the focus is now on our independent selection.
1884 nsCOMPtr
<nsISelectionController
> selCon(do_QueryInterface(presShell
));
1885 nsCOMPtr
<nsISelection
> docSel
;
1886 selCon
->GetSelection(nsISelectionController::SELECTION_NORMAL
,
1887 getter_AddRefs(docSel
));
1888 if (!docSel
) return;
1890 PRBool isCollapsed
= PR_FALSE
;
1891 docSel
->GetIsCollapsed(&isCollapsed
);
1893 docSel
->RemoveAllRanges();
1896 nsresult
nsTextControlFrame::SetFormProperty(nsIAtom
* aName
, const nsAString
& aValue
)
1898 if (!mIsProcessing
)//some kind of lock.
1900 mIsProcessing
= PR_TRUE
;
1901 PRBool isUserInput
= (nsGkAtoms::userInput
== aName
);
1902 if (nsGkAtoms::value
== aName
|| isUserInput
)
1904 PRBool fireChangeEvent
= GetFireChangeEventState();
1906 SetFireChangeEventState(PR_TRUE
);
1908 SetValueChanged(PR_TRUE
);
1909 nsresult rv
= SetValue(aValue
); // set new text value
1911 SetFireChangeEventState(fireChangeEvent
);
1913 NS_ENSURE_SUCCESS(rv
, rv
);
1915 else if (nsGkAtoms::select
== aName
)
1917 // Select all the text.
1919 // XXX: This is lame, we can't call mEditor->SelectAll()
1920 // because that triggers AutoCopies in unix builds.
1921 // Instead, we have to call our own homegrown version
1922 // of select all which merely builds a range that selects
1923 // all of the content and adds that to the selection.
1925 SelectAllContents();
1927 mIsProcessing
= PR_FALSE
;
1933 nsTextControlFrame::GetFormProperty(nsIAtom
* aName
, nsAString
& aValue
) const
1935 // Return the value of the property from the widget it is not null.
1936 // If widget is null, assume the widget is GFX-rendered and return a member variable instead.
1938 if (nsGkAtoms::value
== aName
) {
1939 GetValue(aValue
, PR_FALSE
);
1947 nsTextControlFrame::GetEditor(nsIEditor
**aEditor
)
1949 NS_ENSURE_ARG_POINTER(aEditor
);
1951 NS_IF_ADDREF(*aEditor
);
1956 nsTextControlFrame::OwnsValue(PRBool
* aOwnsValue
)
1958 NS_PRECONDITION(aOwnsValue
, "aOwnsValue must be non-null");
1959 *aOwnsValue
= mUseEditor
;
1964 nsTextControlFrame::GetTextLength(PRInt32
* aTextLength
)
1966 NS_ENSURE_ARG_POINTER(aTextLength
);
1968 nsAutoString textContents
;
1969 GetValue(textContents
, PR_FALSE
); // this is expensive!
1970 *aTextLength
= textContents
.Length();
1975 nsTextControlFrame::SetSelectionInternal(nsIDOMNode
*aStartNode
,
1976 PRInt32 aStartOffset
,
1977 nsIDOMNode
*aEndNode
,
1980 // Create a new range to represent the new selection.
1981 // Note that we use a new range to avoid having to do
1982 // isIncreasing checks to avoid possible errors.
1984 nsCOMPtr
<nsIDOMRange
> range
= do_CreateInstance(kRangeCID
);
1985 NS_ENSURE_TRUE(range
, NS_ERROR_FAILURE
);
1987 nsresult rv
= range
->SetStart(aStartNode
, aStartOffset
);
1988 NS_ENSURE_SUCCESS(rv
, rv
);
1990 rv
= range
->SetEnd(aEndNode
, aEndOffset
);
1991 NS_ENSURE_SUCCESS(rv
, rv
);
1993 // Get the selection, clear it and add the new range to it!
1995 nsCOMPtr
<nsISelection
> selection
;
1996 mSelCon
->GetSelection(nsISelectionController::SELECTION_NORMAL
, getter_AddRefs(selection
));
1997 NS_ENSURE_TRUE(selection
, NS_ERROR_FAILURE
);
1999 rv
= selection
->RemoveAllRanges();
2001 NS_ENSURE_SUCCESS(rv
, rv
);
2003 return selection
->AddRange(range
);
2007 nsTextControlFrame::SelectAllContents()
2012 nsCOMPtr
<nsIDOMElement
> rootElement
;
2013 nsresult rv
= mEditor
->GetRootElement(getter_AddRefs(rootElement
));
2014 NS_ENSURE_SUCCESS(rv
, rv
);
2016 nsCOMPtr
<nsIContent
> rootContent
= do_QueryInterface(rootElement
);
2017 PRInt32 numChildren
= rootContent
->GetChildCount();
2019 if (numChildren
> 0) {
2020 // We never want to place the selection after the last
2021 // br under the root node!
2022 nsIContent
*child
= rootContent
->GetChildAt(numChildren
- 1);
2024 if (child
->Tag() == nsGkAtoms::br
)
2029 nsCOMPtr
<nsIDOMNode
> rootNode(do_QueryInterface(rootElement
));
2031 return SetSelectionInternal(rootNode
, 0, rootNode
, numChildren
);
2035 nsTextControlFrame::SetSelectionEndPoints(PRInt32 aSelStart
, PRInt32 aSelEnd
)
2037 NS_ASSERTION(aSelStart
<= aSelEnd
, "Invalid selection offsets!");
2039 if (aSelStart
> aSelEnd
)
2040 return NS_ERROR_FAILURE
;
2042 nsCOMPtr
<nsIDOMNode
> startNode
, endNode
;
2043 PRInt32 startOffset
, endOffset
;
2045 // Calculate the selection start point.
2047 nsresult rv
= OffsetToDOMPoint(aSelStart
, getter_AddRefs(startNode
), &startOffset
);
2049 NS_ENSURE_SUCCESS(rv
, rv
);
2051 if (aSelStart
== aSelEnd
) {
2052 // Collapsed selection, so start and end are the same!
2053 endNode
= startNode
;
2054 endOffset
= startOffset
;
2057 // Selection isn't collapsed so we have to calculate
2058 // the end point too.
2060 rv
= OffsetToDOMPoint(aSelEnd
, getter_AddRefs(endNode
), &endOffset
);
2062 NS_ENSURE_SUCCESS(rv
, rv
);
2065 return SetSelectionInternal(startNode
, startOffset
, endNode
, endOffset
);
2069 nsTextControlFrame::SetSelectionRange(PRInt32 aSelStart
, PRInt32 aSelEnd
)
2071 NS_ENSURE_TRUE(mEditor
, NS_ERROR_NOT_INITIALIZED
);
2073 if (aSelStart
> aSelEnd
) {
2074 // Simulate what we'd see SetSelectionStart() was called, followed
2075 // by a SetSelectionEnd().
2077 aSelStart
= aSelEnd
;
2080 return SetSelectionEndPoints(aSelStart
, aSelEnd
);
2085 nsTextControlFrame::SetSelectionStart(PRInt32 aSelectionStart
)
2087 NS_ENSURE_TRUE(mEditor
, NS_ERROR_NOT_INITIALIZED
);
2089 PRInt32 selStart
= 0, selEnd
= 0;
2091 nsresult rv
= GetSelectionRange(&selStart
, &selEnd
);
2092 NS_ENSURE_SUCCESS(rv
, rv
);
2094 if (aSelectionStart
> selEnd
) {
2095 // Collapse to the new start point.
2096 selEnd
= aSelectionStart
;
2099 selStart
= aSelectionStart
;
2101 return SetSelectionEndPoints(selStart
, selEnd
);
2105 nsTextControlFrame::SetSelectionEnd(PRInt32 aSelectionEnd
)
2107 NS_ENSURE_TRUE(mEditor
, NS_ERROR_NOT_INITIALIZED
);
2109 PRInt32 selStart
= 0, selEnd
= 0;
2111 nsresult rv
= GetSelectionRange(&selStart
, &selEnd
);
2112 NS_ENSURE_SUCCESS(rv
, rv
);
2114 if (aSelectionEnd
< selStart
) {
2115 // Collapse to the new end point.
2116 selStart
= aSelectionEnd
;
2119 selEnd
= aSelectionEnd
;
2121 return SetSelectionEndPoints(selStart
, selEnd
);
2125 nsTextControlFrame::DOMPointToOffset(nsIDOMNode
* aNode
,
2126 PRInt32 aNodeOffset
,
2129 NS_ENSURE_ARG_POINTER(aNode
&& aResult
);
2133 nsCOMPtr
<nsIDOMElement
> rootElement
;
2134 mEditor
->GetRootElement(getter_AddRefs(rootElement
));
2135 nsCOMPtr
<nsIDOMNode
> rootNode(do_QueryInterface(rootElement
));
2137 NS_ENSURE_TRUE(rootNode
, NS_ERROR_FAILURE
);
2139 nsCOMPtr
<nsIDOMNodeList
> nodeList
;
2141 nsresult rv
= rootNode
->GetChildNodes(getter_AddRefs(nodeList
));
2142 NS_ENSURE_SUCCESS(rv
, rv
);
2143 NS_ENSURE_TRUE(nodeList
, NS_ERROR_FAILURE
);
2145 PRUint32 length
= 0;
2146 rv
= nodeList
->GetLength(&length
);
2147 NS_ENSURE_SUCCESS(rv
, rv
);
2149 if (!length
|| aNodeOffset
< 0)
2152 PRInt32 i
, textOffset
= 0;
2153 PRInt32 lastIndex
= (PRInt32
)length
- 1;
2155 for (i
= 0; i
< (PRInt32
)length
; i
++) {
2156 if (rootNode
== aNode
&& i
== aNodeOffset
) {
2157 *aResult
= textOffset
;
2161 nsCOMPtr
<nsIDOMNode
> item
;
2162 rv
= nodeList
->Item(i
, getter_AddRefs(item
));
2163 NS_ENSURE_SUCCESS(rv
, rv
);
2164 NS_ENSURE_TRUE(item
, NS_ERROR_FAILURE
);
2166 nsCOMPtr
<nsIDOMText
> domText(do_QueryInterface(item
));
2169 PRUint32 textLength
= 0;
2171 rv
= domText
->GetLength(&textLength
);
2172 NS_ENSURE_SUCCESS(rv
, rv
);
2174 if (item
== aNode
) {
2175 NS_ASSERTION((aNodeOffset
>= 0 && aNodeOffset
<= (PRInt32
)textLength
),
2176 "Invalid aNodeOffset!");
2177 *aResult
= textOffset
+ aNodeOffset
;
2181 textOffset
+= textLength
;
2184 // Must be a BR node. If it's not the last BR node
2185 // under the root, count it as a newline.
2192 NS_ASSERTION((aNode
== rootNode
&& aNodeOffset
== (PRInt32
)length
),
2193 "Invalid node offset!");
2195 *aResult
= textOffset
;
2201 nsTextControlFrame::OffsetToDOMPoint(PRInt32 aOffset
,
2202 nsIDOMNode
** aResult
,
2205 NS_ENSURE_ARG_POINTER(aResult
&& aPosition
);
2210 nsCOMPtr
<nsIDOMElement
> rootElement
;
2211 mEditor
->GetRootElement(getter_AddRefs(rootElement
));
2212 nsCOMPtr
<nsIDOMNode
> rootNode(do_QueryInterface(rootElement
));
2214 NS_ENSURE_TRUE(rootNode
, NS_ERROR_FAILURE
);
2216 nsCOMPtr
<nsIDOMNodeList
> nodeList
;
2218 nsresult rv
= rootNode
->GetChildNodes(getter_AddRefs(nodeList
));
2219 NS_ENSURE_SUCCESS(rv
, rv
);
2220 NS_ENSURE_TRUE(nodeList
, NS_ERROR_FAILURE
);
2222 PRUint32 length
= 0;
2224 rv
= nodeList
->GetLength(&length
);
2225 NS_ENSURE_SUCCESS(rv
, rv
);
2227 if (!length
|| aOffset
< 0) {
2229 *aResult
= rootNode
;
2230 NS_ADDREF(*aResult
);
2234 PRInt32 textOffset
= 0;
2235 PRUint32 lastIndex
= length
- 1;
2237 for (PRUint32 i
=0; i
<length
; i
++) {
2238 nsCOMPtr
<nsIDOMNode
> item
;
2239 rv
= nodeList
->Item(i
, getter_AddRefs(item
));
2240 NS_ENSURE_SUCCESS(rv
, rv
);
2241 NS_ENSURE_TRUE(item
, NS_ERROR_FAILURE
);
2243 nsCOMPtr
<nsIDOMText
> domText(do_QueryInterface(item
));
2246 PRUint32 textLength
= 0;
2248 rv
= domText
->GetLength(&textLength
);
2249 NS_ENSURE_SUCCESS(rv
, rv
);
2251 // Check if aOffset falls within this range.
2252 if (aOffset
>= textOffset
&& aOffset
<= textOffset
+(PRInt32
)textLength
) {
2253 *aPosition
= aOffset
- textOffset
;
2255 NS_ADDREF(*aResult
);
2259 textOffset
+= textLength
;
2261 // If there aren't any more siblings after this text node,
2262 // return the point at the end of this text node!
2264 if (i
== lastIndex
) {
2265 *aPosition
= textLength
;
2267 NS_ADDREF(*aResult
);
2272 // Must be a BR node, count it as a newline.
2274 if (aOffset
== textOffset
|| i
== lastIndex
) {
2275 // We've found the correct position, or aOffset takes us
2276 // beyond the last child under rootNode, just return the point
2277 // under rootNode that is in front of this br.
2280 *aResult
= rootNode
;
2281 NS_ADDREF(*aResult
);
2289 NS_ASSERTION(0, "We should never get here!");
2291 return NS_ERROR_FAILURE
;
2295 nsTextControlFrame::GetSelectionRange(PRInt32
* aSelectionStart
, PRInt32
* aSelectionEnd
)
2297 // make sure we have an editor
2298 NS_ENSURE_TRUE(mEditor
, NS_ERROR_NOT_INITIALIZED
);
2300 *aSelectionStart
= 0;
2303 nsCOMPtr
<nsISelection
> selection
;
2304 nsresult rv
= mSelCon
->GetSelection(nsISelectionController::SELECTION_NORMAL
, getter_AddRefs(selection
));
2305 NS_ENSURE_SUCCESS(rv
, rv
);
2306 NS_ENSURE_TRUE(selection
, NS_ERROR_FAILURE
);
2308 PRInt32 numRanges
= 0;
2309 selection
->GetRangeCount(&numRanges
);
2314 // We only operate on the first range in the selection!
2316 nsCOMPtr
<nsIDOMRange
> firstRange
;
2317 rv
= selection
->GetRangeAt(0, getter_AddRefs(firstRange
));
2318 NS_ENSURE_SUCCESS(rv
, rv
);
2319 NS_ENSURE_TRUE(firstRange
, NS_ERROR_FAILURE
);
2321 nsCOMPtr
<nsIDOMNode
> startNode
, endNode
;
2322 PRInt32 startOffset
= 0, endOffset
= 0;
2324 // Get the start point of the range.
2326 rv
= firstRange
->GetStartContainer(getter_AddRefs(startNode
));
2327 NS_ENSURE_SUCCESS(rv
, rv
);
2328 NS_ENSURE_TRUE(startNode
, NS_ERROR_FAILURE
);
2330 rv
= firstRange
->GetStartOffset(&startOffset
);
2331 NS_ENSURE_SUCCESS(rv
, rv
);
2333 // Get the end point of the range.
2335 rv
= firstRange
->GetEndContainer(getter_AddRefs(endNode
));
2336 NS_ENSURE_SUCCESS(rv
, rv
);
2337 NS_ENSURE_TRUE(endNode
, NS_ERROR_FAILURE
);
2339 rv
= firstRange
->GetEndOffset(&endOffset
);
2340 NS_ENSURE_SUCCESS(rv
, rv
);
2342 // Convert the start point to a selection offset.
2344 rv
= DOMPointToOffset(startNode
, startOffset
, aSelectionStart
);
2345 NS_ENSURE_SUCCESS(rv
, rv
);
2347 // Convert the end point to a selection offset.
2349 return DOMPointToOffset(endNode
, endOffset
, aSelectionEnd
);
2352 /////END INTERFACE IMPLEMENTATIONS
2356 nsTextControlFrame::AttributeChanged(PRInt32 aNameSpaceID
,
2357 nsIAtom
* aAttribute
,
2360 if (!mEditor
|| !mSelCon
)
2361 return nsBoxFrame::AttributeChanged(aNameSpaceID
, aAttribute
, aModType
);;
2363 nsresult rv
= NS_OK
;
2365 if (nsGkAtoms::maxlength
== aAttribute
)
2368 PRBool maxDefined
= GetMaxLength(&maxLength
);
2370 nsCOMPtr
<nsIPlaintextEditor
> textEditor
= do_QueryInterface(mEditor
);
2374 { // set the maxLength attribute
2375 textEditor
->SetMaxTextLength(maxLength
);
2376 // if maxLength>docLength, we need to truncate the doc content
2378 else { // unset the maxLength attribute
2379 textEditor
->SetMaxTextLength(-1);
2382 rv
= NS_OK
; // don't propagate the error
2384 else if (nsGkAtoms::readonly
== aAttribute
)
2387 mEditor
->GetFlags(&flags
);
2388 if (AttributeExists(nsGkAtoms::readonly
))
2390 flags
|= nsIPlaintextEditor::eEditorReadonlyMask
;
2391 if (IsFocusedContent(mContent
))
2392 mSelCon
->SetCaretEnabled(PR_FALSE
);
2396 flags
&= ~(nsIPlaintextEditor::eEditorReadonlyMask
);
2397 if (!(flags
& nsIPlaintextEditor::eEditorDisabledMask
) &&
2398 IsFocusedContent(mContent
))
2399 mSelCon
->SetCaretEnabled(PR_TRUE
);
2401 mEditor
->SetFlags(flags
);
2403 else if (nsGkAtoms::disabled
== aAttribute
)
2406 mEditor
->GetFlags(&flags
);
2407 if (AttributeExists(nsGkAtoms::disabled
))
2409 flags
|= nsIPlaintextEditor::eEditorDisabledMask
;
2410 mSelCon
->SetDisplaySelection(nsISelectionController::SELECTION_OFF
);
2411 if (IsFocusedContent(mContent
))
2412 mSelCon
->SetCaretEnabled(PR_FALSE
);
2416 flags
&= ~(nsIPlaintextEditor::eEditorDisabledMask
);
2417 mSelCon
->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN
);
2419 mEditor
->SetFlags(flags
);
2421 // Allow the base class to handle common attributes supported
2422 // by all form elements...
2424 rv
= nsBoxFrame::AttributeChanged(aNameSpaceID
, aAttribute
, aModType
);
2432 nsTextControlFrame::GetText(nsString
* aText
)
2434 nsresult rv
= NS_OK
;
2435 if (IsSingleLineTextControl()) {
2436 // If we're going to remove newlines anyway, ignore the wrap property
2437 GetValue(*aText
, PR_TRUE
);
2438 RemoveNewlines(*aText
);
2440 nsCOMPtr
<nsIDOMHTMLTextAreaElement
> textArea
= do_QueryInterface(mContent
);
2442 rv
= textArea
->GetValue(*aText
);
2450 nsTextControlFrame::GetPhonetic(nsAString
& aPhonetic
)
2452 aPhonetic
.Truncate(0);
2454 return NS_ERROR_NOT_INITIALIZED
;
2455 nsCOMPtr
<nsIEditorIMESupport
> imeSupport
= do_QueryInterface(mEditor
);
2457 nsCOMPtr
<nsIPhonetic
> phonetic
= do_QueryInterface(imeSupport
);
2459 phonetic
->GetPhonetic(aPhonetic
);
2464 ///END NSIFRAME OVERLOADS
2465 /////BEGIN PROTECTED METHODS
2467 void nsTextControlFrame::RemoveNewlines(nsString
&aString
)
2469 // strip CR/LF and null
2470 static const char badChars
[] = {10, 13, 0};
2471 aString
.StripChars(badChars
);
2476 nsTextControlFrame::GetMaxLength(PRInt32
* aSize
)
2480 nsGenericHTMLElement
*content
= nsGenericHTMLElement::FromContent(mContent
);
2482 const nsAttrValue
* attr
= content
->GetParsedAttr(nsGkAtoms::maxlength
);
2483 if (attr
&& attr
->Type() == nsAttrValue::eInteger
) {
2484 *aSize
= attr
->GetIntegerValue();
2492 // this is where we propagate a content changed event
2494 nsTextControlFrame::FireOnInput()
2496 if (!mNotifyOnInput
)
2497 return; // if notification is turned off, do nothing
2499 // Dispatch the "input" event
2500 nsEventStatus status
= nsEventStatus_eIgnore
;
2501 nsUIEvent
event(PR_TRUE
, NS_FORM_INPUT
, 0);
2503 // Have the content handle the event, propagating it according to normal
2505 nsCOMPtr
<nsIPresShell
> shell
= PresContext()->PresShell();
2506 shell
->HandleEventWithTarget(&event
, nsnull
, mContent
, &status
);
2510 nsTextControlFrame::InitFocusedValue()
2512 return GetText(&mFocusedValue
);
2516 nsTextControlFrame::CheckFireOnChange()
2520 if (!mFocusedValue
.Equals(value
))
2522 mFocusedValue
= value
;
2523 // Dispatch the change event
2524 nsEventStatus status
= nsEventStatus_eIgnore
;
2525 nsInputEvent
event(PR_TRUE
, NS_FORM_CHANGE
, nsnull
);
2526 nsCOMPtr
<nsIPresShell
> shell
= PresContext()->PresShell();
2527 shell
->HandleEventWithTarget(&event
, nsnull
, mContent
, &status
);
2536 nsTextControlFrame::GetValue(nsAString
& aValue
, PRBool aIgnoreWrap
) const
2538 aValue
.Truncate(); // initialize out param
2539 nsresult rv
= NS_OK
;
2541 if (mEditor
&& mUseEditor
)
2543 PRUint32 flags
= (nsIDocumentEncoder::OutputLFLineBreak
|
2544 nsIDocumentEncoder::OutputPreformatted
|
2545 nsIDocumentEncoder::OutputPersistNBSP
);
2547 if (PR_TRUE
==IsPlainTextControl())
2549 flags
|= nsIDocumentEncoder::OutputBodyOnly
;
2553 nsHTMLTextWrap wrapProp
;
2554 if (::GetWrapPropertyEnum(mContent
, wrapProp
) &&
2555 wrapProp
== eHTMLTextWrap_Hard
) {
2556 flags
|= nsIDocumentEncoder::OutputWrap
;
2560 // What follows is a bit of a hack. The problem is that we could be in
2561 // this method because we're being destroyed for whatever reason while
2562 // script is executing. If that happens, editor will run with the
2563 // privileges of the executing script, which means it may not be able to
2564 // access its own DOM nodes! Let's try to deal with that by pushing a null
2565 // JSContext on the JSContext stack to make it clear that we're native
2566 // code. Note that any script that's directly trying to access our value
2567 // has to be going through some scriptable object to do that and that
2568 // already does the relevant security checks.
2569 // XXXbz if we could just get the textContent of our anonymous content (eg
2570 // if plaintext editor didn't create <br> nodes all over), we wouldn't need
2572 { /* Scope for context pusher */
2576 rv
= mEditor
->OutputToString(NS_LITERAL_STRING("text/plain"), flags
,
2582 // Otherwise get the value from content.
2583 nsCOMPtr
<nsIDOMHTMLInputElement
> inputControl
= do_QueryInterface(mContent
);
2586 rv
= inputControl
->GetValue(aValue
);
2590 nsCOMPtr
<nsIDOMHTMLTextAreaElement
> textareaControl
2591 = do_QueryInterface(mContent
);
2592 if (textareaControl
)
2594 rv
= textareaControl
->GetValue(aValue
);
2603 // END IMPLEMENTING NS_IFORMCONTROLFRAME
2606 nsTextControlFrame::SetValue(const nsAString
& aValue
)
2608 // XXX this method should actually propagate errors! It'd make debugging it
2609 // so much easier...
2610 if (mEditor
&& mUseEditor
)
2612 // This method isn't used for user-generated changes, except for calls
2613 // from nsFileControlFrame which sets mFireChangeEventState==true and
2614 // restores it afterwards (ie. we want 'change' events for those changes).
2615 // Focused value must be updated to prevent incorrect 'change' events,
2616 // but only if user hasn't changed the value.
2619 PRBool focusValueInit
= !mFireChangeEventState
&&
2620 mFocusedValue
.Equals(val
);
2622 nsCOMPtr
<nsIEditor
> editor
= mEditor
;
2623 nsWeakFrame
weakFrame(this);
2624 nsAutoString currentValue
;
2625 GetValue(currentValue
, PR_FALSE
);
2626 if (IsSingleLineTextControl())
2628 RemoveNewlines(currentValue
);
2630 // this is necessary to avoid infinite recursion
2631 if (!currentValue
.Equals(aValue
))
2633 // \r is an illegal character in the dom, but people use them,
2634 // so convert windows and mac platform linebreaks to \n:
2635 // Unfortunately aValue is declared const, so we have to copy
2636 // in order to do this substitution.
2637 currentValue
.Assign(aValue
);
2638 ::PlatformToDOMLineBreaks(currentValue
);
2640 nsCOMPtr
<nsIDOMDocument
>domDoc
;
2641 nsresult rv
= editor
->GetDocument(getter_AddRefs(domDoc
));
2642 NS_ENSURE_SUCCESS(rv
, rv
);
2643 NS_ENSURE_STATE(domDoc
);
2645 PRBool outerTransaction
;
2646 // Time to mess with our security context... See comments in GetValue()
2647 // for why this is needed. Note that we have to do this up here, because
2648 // otherwise SelectAll() will fail.
2649 { /* Scope for context pusher */
2653 nsCOMPtr
<nsISelection
> domSel
;
2654 nsCOMPtr
<nsISelectionPrivate
> selPriv
;
2655 mSelCon
->GetSelection(nsISelectionController::SELECTION_NORMAL
,
2656 getter_AddRefs(domSel
));
2659 selPriv
= do_QueryInterface(domSel
);
2661 selPriv
->StartBatchChanges();
2664 nsCOMPtr
<nsISelectionController
> kungFuDeathGrip
= mSelCon
;
2665 mSelCon
->SelectAll();
2666 nsCOMPtr
<nsIPlaintextEditor
> plaintextEditor
= do_QueryInterface(editor
);
2667 if (!plaintextEditor
|| !weakFrame
.IsAlive()) {
2668 NS_WARNING("Somehow not a plaintext editor?");
2669 return NS_ERROR_FAILURE
;
2672 // Since this code does not handle user-generated changes to the text,
2673 // make sure we don't fire oninput when the editor notifies us.
2674 // (mNotifyOnInput must be reset before we return).
2676 // To protect against a reentrant call to SetValue, we check whether
2677 // another SetValue is already happening for this frame. If it is,
2678 // we must wait until we unwind to re-enable oninput events.
2679 outerTransaction
= mNotifyOnInput
;
2680 if (outerTransaction
)
2681 mNotifyOnInput
= PR_FALSE
;
2683 // get the flags, remove readonly and disabled, set the value,
2685 PRUint32 flags
, savedFlags
;
2686 editor
->GetFlags(&savedFlags
);
2688 flags
&= ~(nsIPlaintextEditor::eEditorDisabledMask
);
2689 flags
&= ~(nsIPlaintextEditor::eEditorReadonlyMask
);
2690 editor
->SetFlags(flags
);
2692 // Also don't enforce max-length here
2693 PRInt32 savedMaxLength
;
2694 plaintextEditor
->GetMaxTextLength(&savedMaxLength
);
2695 plaintextEditor
->SetMaxTextLength(-1);
2697 if (currentValue
.Length() < 1)
2698 editor
->DeleteSelection(nsIEditor::eNone
);
2700 if (plaintextEditor
)
2701 plaintextEditor
->InsertText(currentValue
);
2704 plaintextEditor
->SetMaxTextLength(savedMaxLength
);
2705 editor
->SetFlags(savedFlags
);
2707 selPriv
->EndBatchChanges();
2710 NS_ENSURE_STATE(weakFrame
.IsAlive());
2711 if (outerTransaction
)
2712 mNotifyOnInput
= PR_TRUE
;
2714 if (focusValueInit
) {
2715 // Reset mFocusedValue so the onchange event doesn't fire incorrectly.
2720 NS_ENSURE_STATE(weakFrame
.IsAlive());
2721 nsIScrollableView
* scrollableView
= GetScrollableView();
2724 // Scroll the upper left corner of the text control's
2725 // content area back into view.
2727 scrollableView
->ScrollTo(0, 0, 0);
2732 // Otherwise set the value in content.
2733 nsCOMPtr
<nsITextControlElement
> textControl
= do_QueryInterface(mContent
);
2736 textControl
->TakeTextFrameValue(aValue
);
2744 nsTextControlFrame::SetInitialChildList(nsIAtom
* aListName
,
2745 nsFrameList
& aChildList
)
2747 nsresult rv
= nsBoxFrame::SetInitialChildList(aListName
, aChildList
);
2749 //look for scroll view below this frame go along first child list
2750 nsIFrame
* first
= GetFirstChild(nsnull
);
2752 // Mark the scroll frame as being a reflow root. This will allow
2753 // incremental reflows to be initiated at the scroll frame, rather
2754 // than descending from the root frame of the frame hierarchy.
2755 first
->AddStateBits(NS_FRAME_REFLOW_ROOT
);
2757 nsIScrollableFrame
*scrollableFrame
= do_QueryFrame(first
);
2758 NS_ASSERTION(scrollableFrame
, "Child must be scrollable");
2760 // we must turn off scrollbars for singleline text controls
2761 // XXX FIXME this should be removed,
2762 // nsGfxScrollFrameInner::CreateAnonymousContent handles this
2763 if (IsSingleLineTextControl())
2765 if (scrollableFrame
)
2766 scrollableFrame
->SetScrollbarVisibility(PR_FALSE
, PR_FALSE
);
2769 //register key listeners
2770 nsCOMPtr
<nsIDOMEventGroup
> systemGroup
;
2771 mContent
->GetSystemEventGroup(getter_AddRefs(systemGroup
));
2772 nsCOMPtr
<nsIDOM3EventTarget
> dom3Targ
= do_QueryInterface(mContent
);
2774 // cast because of ambiguous base
2775 nsIDOMEventListener
*listener
= static_cast<nsIDOMKeyListener
*>
2778 dom3Targ
->AddGroupedEventListener(NS_LITERAL_STRING("keydown"),
2779 listener
, PR_FALSE
, systemGroup
);
2780 dom3Targ
->AddGroupedEventListener(NS_LITERAL_STRING("keypress"),
2781 listener
, PR_FALSE
, systemGroup
);
2782 dom3Targ
->AddGroupedEventListener(NS_LITERAL_STRING("keyup"),
2783 listener
, PR_FALSE
, systemGroup
);
2789 nsIScrollableView
* nsTextControlFrame::GetScrollableView()
2791 nsIFrame
* first
= GetFirstChild(nsnull
);
2792 nsIScrollableFrame
* scrollableFrame
= do_QueryFrame(first
);
2793 return scrollableFrame
? scrollableFrame
->GetScrollableView() : nsnull
;
2797 nsTextControlFrame::IsScrollable() const
2799 return !IsSingleLineTextControl();
2803 nsTextControlFrame::SetValueChanged(PRBool aValueChanged
)
2805 nsCOMPtr
<nsITextControlElement
> elem
= do_QueryInterface(mContent
);
2807 elem
->SetValueChanged(aValueChanged
);
2812 nsTextControlFrame::ShutDown()
2814 NS_IF_RELEASE(sNativeTextAreaBindings
);
2815 NS_IF_RELEASE(sNativeInputBindings
);