Back to index

lightning-sunbird  0.9+nobinonly
nsTextControlFrame.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Blake Ross <blakeross@telocity.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 
00040 #include "nsCOMPtr.h"
00041 #include "nsTextControlFrame.h"
00042 #include "nsIDocument.h"
00043 #include "nsIDOMNSHTMLTextAreaElement.h"
00044 #include "nsIDOMNSHTMLInputElement.h"
00045 #include "nsIFormControl.h"
00046 #include "nsIServiceManager.h"
00047 #include "nsIFrameSelection.h"
00048 #include "nsIPlaintextEditor.h"
00049 #include "nsEditorCID.h"
00050 #include "nsLayoutCID.h"
00051 #include "nsFormControlHelper.h"
00052 #include "nsIDocumentEncoder.h"
00053 #include "nsICaret.h"
00054 #include "nsISelectionListener.h"
00055 #include "nsISelectionPrivate.h"
00056 #include "nsIController.h"
00057 #include "nsIControllers.h"
00058 #include "nsIControllerContext.h"
00059 #include "nsGenericHTMLElement.h"
00060 #include "nsIEditorIMESupport.h"
00061 #include "nsIPhonetic.h"
00062 #include "nsIEditorObserver.h"
00063 #include "nsIDOMHTMLTextAreaElement.h"
00064 #include "nsINameSpaceManager.h"
00065 #include "nsINodeInfo.h"
00066 #include "nsIScrollableView.h"
00067 #include "nsIScrollableFrame.h" //to turn off scroll bars
00068 #include "nsFormControlFrame.h" //for registering accesskeys
00069 #include "nsIDeviceContext.h" // to measure fonts
00070 
00071 #include "nsIContent.h"
00072 #include "nsIAtom.h"
00073 #include "nsPresContext.h"
00074 #ifdef USE_QI_IN_SUPPRESS_EVENT_HANDLERS
00075 #include "nsIPrintContext.h"
00076 #include "nsIPrintPreviewContext.h"
00077 #endif // USE_QI_IN_SUPPRESS_EVENT_HANDLERS
00078 #include "nsHTMLAtoms.h"
00079 #include "nsIComponentManager.h"
00080 #include "nsIView.h"
00081 #include "nsIDOMHTMLInputElement.h"
00082 #include "nsISupportsArray.h"
00083 #include "nsIDOMElement.h"
00084 #include "nsIDOMDocument.h"
00085 #include "nsIPresShell.h"
00086 #include "nsIComponentManager.h"
00087 
00088 #include "nsBoxLayoutState.h"
00089 #include "nsLayoutAtoms.h" //getframetype
00090 //for keylistener for "return" check
00091 #include "nsIPrivateDOMEvent.h"
00092 #include "nsIDOMEventReceiver.h"
00093 #include "nsIDocument.h" //observe documents to send onchangenotifications
00094 #include "nsIStyleSheet.h"//observe documents to send onchangenotifications
00095 #include "nsIStyleRule.h"//observe documents to send onchangenotifications
00096 #include "nsIDOMEventListener.h"//observe documents to send onchangenotifications
00097 #include "nsGUIEvent.h"
00098 #include "nsIDOMEventGroup.h"
00099 #include "nsIDOM3EventTarget.h"
00100 #include "nsIDOMNSEvent.h"
00101 #include "nsIDOMNSUIEvent.h"
00102 #include "nsIEventStateManager.h"
00103 
00104 #include "nsIDOMFocusListener.h" //onchange events
00105 #include "nsIDOMCharacterData.h" //for selection setting helper func
00106 #include "nsIDOMNodeList.h" //for selection setting helper func
00107 #include "nsIDOMRange.h" //for selection setting helper func
00108 #include "nsIScriptGlobalObject.h" //needed for notify selection changed to update the menus ect.
00109 #include "nsIDOMWindowInternal.h" //needed for notify selection changed to update the menus ect.
00110 #include "nsITextContent.h" //needed to create initial text control content
00111 #ifdef ACCESSIBILITY
00112 #include "nsIAccessibilityService.h"
00113 #endif
00114 #include "nsIServiceManager.h"
00115 #include "nsIDOMNode.h"
00116 #include "nsITextControlElement.h"
00117 
00118 #include "nsIEditorObserver.h"
00119 #include "nsITransactionManager.h"
00120 #include "nsIDOMText.h" //for multiline getselection
00121 #include "nsNodeInfoManager.h"
00122 #include "nsContentCreatorFunctions.h"
00123 #include "nsIDOMKeyListener.h"
00124 #include "nsIDOMEventGroup.h"
00125 #include "nsIDOM3EventTarget.h"
00126 #include "nsINativeKeyBindings.h"
00127 #include "nsIJSContextStack.h"
00128 
00129 #ifdef IBMBIDI
00130 #include "nsIBidiKeyboard.h"
00131 #include "nsWidgetsCID.h"
00132 #endif // IBMBIDI
00133 
00134 #define DEFAULT_COLUMN_WIDTH 20
00135 
00136 #include "nsContentCID.h"
00137 static NS_DEFINE_IID(kRangeCID,     NS_RANGE_CID);
00138 
00139 static NS_DEFINE_CID(kTextEditorCID, NS_TEXTEDITOR_CID);
00140 static NS_DEFINE_CID(kFrameSelectionCID, NS_FRAMESELECTION_CID);
00141 
00142 static const PRInt32 DEFAULT_COLS = 20;
00143 static const PRInt32 DEFAULT_ROWS = 1;
00144 static const PRInt32 DEFAULT_ROWS_TEXTAREA = 2;
00145 static const PRInt32 DEFAULT_UNDO_CAP = 1000;
00146 
00147 static nsINativeKeyBindings *sNativeInputBindings = nsnull;
00148 static nsINativeKeyBindings *sNativeTextAreaBindings = nsnull;
00149 
00150 class nsTextInputListener : public nsISelectionListener,
00151                             public nsIDOMFocusListener,
00152                             public nsIDOMKeyListener,
00153                             public nsIEditorObserver,
00154                             public nsSupportsWeakReference
00155 {
00156 public:
00159   nsTextInputListener();
00162   virtual ~nsTextInputListener();
00163 
00167   void SetFrame(nsTextControlFrame *aFrame){mFrame = aFrame;}
00168 
00169   NS_DECL_ISUPPORTS
00170 
00171   NS_DECL_NSISELECTIONLISTENER
00172 
00177   NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
00178   NS_IMETHOD Focus(nsIDOMEvent* aEvent);
00179   NS_IMETHOD Blur (nsIDOMEvent* aEvent);
00180   /* END interfaces from nsIDOMFocusListener*/
00181 
00182   // nsIDOMKeyListener
00183   NS_IMETHOD KeyDown(nsIDOMEvent *aKeyEvent);
00184   NS_IMETHOD KeyPress(nsIDOMEvent *aKeyEvent);
00185   NS_IMETHOD KeyUp(nsIDOMEvent *aKeyEvent);
00186 
00187   NS_DECL_NSIEDITOROBSERVER
00188 
00189 protected:
00190 
00191   nsresult  UpdateTextInputCommands(const nsAString& commandsToUpdate);
00192 
00193   NS_HIDDEN_(nsINativeKeyBindings*) GetKeyBindings();
00194 
00195 protected:
00196 
00197   nsTextControlFrame* mFrame;  // weak reference
00198   
00199   PRPackedBool    mSelectionWasCollapsed;
00200   PRPackedBool    mKnowSelectionCollapsed;
00205   PRPackedBool    mHadUndoItems;
00210   PRPackedBool    mHadRedoItems;
00211 };
00212 
00213 
00214 /*
00215  * nsTextEditorListener implementation
00216  */
00217 
00218 nsTextInputListener::nsTextInputListener()
00219 : mFrame(nsnull)
00220 , mSelectionWasCollapsed(PR_TRUE)
00221 , mKnowSelectionCollapsed(PR_FALSE)
00222 , mHadUndoItems(PR_FALSE)
00223 , mHadRedoItems(PR_FALSE)
00224 {
00225 }
00226 
00227 nsTextInputListener::~nsTextInputListener() 
00228 {
00229 }
00230 
00231 NS_IMPL_ADDREF(nsTextInputListener)
00232 NS_IMPL_RELEASE(nsTextInputListener)
00233 
00234 NS_INTERFACE_MAP_BEGIN(nsTextInputListener)
00235   NS_INTERFACE_MAP_ENTRY(nsISelectionListener)
00236   NS_INTERFACE_MAP_ENTRY(nsIEditorObserver)
00237   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00238   NS_INTERFACE_MAP_ENTRY(nsIDOMKeyListener)
00239   NS_INTERFACE_MAP_ENTRY(nsIDOMFocusListener)
00240   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEventListener, nsIDOMFocusListener)
00241   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFocusListener)
00242 NS_INTERFACE_MAP_END
00243 
00244 // BEGIN nsIDOMSelectionListener
00245 
00246 NS_IMETHODIMP
00247 nsTextInputListener::NotifySelectionChanged(nsIDOMDocument* aDoc, nsISelection* aSel, PRInt16 aReason)
00248 {
00249   PRBool collapsed;
00250   if (!mFrame || !aDoc || !aSel || NS_FAILED(aSel->GetIsCollapsed(&collapsed)))
00251     return NS_OK;
00252 
00253   // Fire the select event
00254   // The specs don't exactly say when we should fire the select event.
00255   // IE: Whenever you add/remove a character to/from the selection. Also
00256   //     each time for select all. Also if you get to the end of the text 
00257   //     field you will get new event for each keypress or a continuous 
00258   //     stream of events if you use the mouse. IE will fire select event 
00259   //     when the selection collapses to nothing if you are holding down
00260   //     the shift or mouse button.
00261   // Mozilla: If we have non-empty selection we will fire a new event for each
00262   //          keypress (or mouseup) if the selection changed. Mozilla will also
00263   //          create the event each time select all is called, even if everything
00264   //          was previously selected, becase technically select all will first collapse
00265   //          and then extend. Mozilla will never create an event if the selection 
00266   //          collapses to nothing.
00267   if (!collapsed && (aReason & (nsISelectionListener::MOUSEUP_REASON | 
00268                                 nsISelectionListener::KEYPRESS_REASON |
00269                                 nsISelectionListener::SELECTALL_REASON)))
00270   {
00271     nsCOMPtr<nsIContent> content;
00272     mFrame->GetFormContent(*getter_AddRefs(content));
00273     if (content) 
00274     {
00275       nsCOMPtr<nsIDocument> doc = content->GetDocument();
00276       if (doc) 
00277       {
00278         nsCOMPtr<nsIPresShell> presShell = doc->GetShellAt(0);
00279         if (presShell) 
00280         {
00281           nsEventStatus status = nsEventStatus_eIgnore;
00282           nsEvent event(PR_TRUE, NS_FORM_SELECTED);
00283 
00284           presShell->HandleEventWithTarget(&event,mFrame,content,NS_EVENT_FLAG_INIT,&status);
00285         }
00286       }
00287     }
00288   }
00289 
00290   // if the collapsed state did not change, don't fire notifications
00291   if (mKnowSelectionCollapsed && collapsed == mSelectionWasCollapsed)
00292     return NS_OK;
00293   
00294   mSelectionWasCollapsed = collapsed;
00295   mKnowSelectionCollapsed = PR_TRUE;
00296 
00297   return UpdateTextInputCommands(NS_LITERAL_STRING("select"));
00298 }
00299 
00300 // END nsIDOMSelectionListener
00301 
00302 // BEGIN nsIFocusListener
00303 
00304 NS_IMETHODIMP
00305 nsTextInputListener::HandleEvent(nsIDOMEvent* aEvent)
00306 {
00307   return NS_OK;
00308 }
00309 
00310 NS_IMETHODIMP
00311 nsTextInputListener::Focus(nsIDOMEvent* aEvent)
00312 {
00313   if (!mFrame)
00314     return NS_OK;
00315 
00316   nsCOMPtr<nsIEditor> editor;
00317   mFrame->GetEditor(getter_AddRefs(editor));
00318   if (editor) {
00319     editor->AddEditorObserver(this);
00320   }
00321 
00322   mFrame->SetHasFocus(PR_TRUE);
00323 
00324   return mFrame->InitFocusedValue();
00325 }
00326 
00327 NS_IMETHODIMP
00328 nsTextInputListener::Blur(nsIDOMEvent* aEvent)
00329 {
00330   if (!mFrame)
00331     return NS_OK;
00332 
00333   nsCOMPtr<nsIEditor> editor;
00334   mFrame->GetEditor(getter_AddRefs(editor));
00335   if (editor) {
00336     editor->RemoveEditorObserver(this);
00337   }
00338 
00339   mFrame->SetHasFocus(PR_FALSE);
00340 
00341   return mFrame->CheckFireOnChange();
00342 }
00343 
00344 // END nsIFocusListener
00345 
00346 // BEGIN nsIDOMKeyListener
00347 
00348 static void
00349 DoCommandCallback(const char *aCommand, void *aData)
00350 {
00351   nsTextControlFrame *frame = NS_STATIC_CAST(nsTextControlFrame*, aData);
00352   nsIContent *content = frame->GetContent();
00353 
00354   nsCOMPtr<nsIControllers> controllers;
00355   nsCOMPtr<nsIDOMNSHTMLInputElement> input = do_QueryInterface(content);
00356   if (input) {
00357     input->GetControllers(getter_AddRefs(controllers));
00358   } else {
00359     nsCOMPtr<nsIDOMNSHTMLTextAreaElement> textArea =
00360       do_QueryInterface(content);
00361 
00362     if (textArea) {
00363       textArea->GetControllers(getter_AddRefs(controllers));
00364     }
00365   }
00366 
00367   if (!controllers) {
00368     NS_WARNING("Could not get controllers");
00369     return;
00370   }
00371 
00372   nsCOMPtr<nsIController> controller;
00373   controllers->GetControllerForCommand(aCommand, getter_AddRefs(controller));
00374   if (controller) {
00375     controller->DoCommand(aCommand);
00376   }
00377 }
00378 
00379 static PRBool
00380 DOMEventToNativeKeyEvent(nsIDOMEvent      *aDOMEvent,
00381                          nsNativeKeyEvent *aNativeEvent)
00382 {
00383   nsCOMPtr<nsIDOMNSUIEvent> uievent = do_QueryInterface(aDOMEvent);
00384   PRBool defaultPrevented;
00385   uievent->GetPreventDefault(&defaultPrevented);
00386   if (defaultPrevented)
00387     return PR_FALSE;
00388 
00389   nsCOMPtr<nsIDOMNSEvent> nsevent = do_QueryInterface(aDOMEvent);
00390   PRBool trusted = PR_FALSE;
00391   nsevent->GetIsTrusted(&trusted);
00392   if (!trusted)
00393     return PR_FALSE;
00394 
00395   nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aDOMEvent);
00396 
00397   keyEvent->GetCharCode(&aNativeEvent->charCode);
00398   keyEvent->GetKeyCode(&aNativeEvent->keyCode);
00399   keyEvent->GetAltKey(&aNativeEvent->altKey);
00400   keyEvent->GetCtrlKey(&aNativeEvent->ctrlKey);
00401   keyEvent->GetShiftKey(&aNativeEvent->shiftKey);
00402   keyEvent->GetMetaKey(&aNativeEvent->metaKey);
00403 
00404   return PR_TRUE;
00405 }
00406 
00407 NS_IMETHODIMP
00408 nsTextInputListener::KeyDown(nsIDOMEvent *aKeyEvent)
00409 {
00410   nsNativeKeyEvent nativeEvent;
00411   nsINativeKeyBindings *bindings = GetKeyBindings();
00412   if (bindings && DOMEventToNativeKeyEvent(aKeyEvent, &nativeEvent)) {
00413     if (bindings->KeyDown(nativeEvent, DoCommandCallback, mFrame)) {
00414       aKeyEvent->PreventDefault();
00415     }
00416   }
00417 
00418   return NS_OK;
00419 }
00420 
00421 NS_IMETHODIMP
00422 nsTextInputListener::KeyPress(nsIDOMEvent *aKeyEvent)
00423 {
00424   nsNativeKeyEvent nativeEvent;
00425   nsINativeKeyBindings *bindings = GetKeyBindings();
00426   if (bindings && DOMEventToNativeKeyEvent(aKeyEvent, &nativeEvent)) {
00427     if (bindings->KeyPress(nativeEvent, DoCommandCallback, mFrame)) {
00428       aKeyEvent->PreventDefault();
00429     }
00430   }
00431 
00432   return NS_OK;
00433 }
00434 
00435 NS_IMETHODIMP
00436 nsTextInputListener::KeyUp(nsIDOMEvent *aKeyEvent)
00437 {
00438   nsNativeKeyEvent nativeEvent;
00439   nsINativeKeyBindings *bindings = GetKeyBindings();
00440   if (bindings && DOMEventToNativeKeyEvent(aKeyEvent, &nativeEvent)) {
00441     if (bindings->KeyUp(nativeEvent, DoCommandCallback, mFrame)) {
00442       aKeyEvent->PreventDefault();
00443     }
00444   }
00445 
00446   return NS_OK;
00447 }
00448 // END nsIDOMKeyListener
00449 
00450 // BEGIN nsIEditorObserver
00451 
00452 NS_IMETHODIMP
00453 nsTextInputListener::EditAction()
00454 {
00455   //
00456   // Update the undo / redo menus
00457   //
00458   nsCOMPtr<nsIEditor> editor;
00459   mFrame->GetEditor(getter_AddRefs(editor));
00460 
00461   nsCOMPtr<nsITransactionManager> manager;
00462   editor->GetTransactionManager(getter_AddRefs(manager));
00463   NS_ENSURE_TRUE(manager, NS_ERROR_FAILURE);
00464 
00465   // Get the number of undo / redo items
00466   PRInt32 numUndoItems = 0;
00467   PRInt32 numRedoItems = 0;
00468   manager->GetNumberOfUndoItems(&numUndoItems);
00469   manager->GetNumberOfRedoItems(&numRedoItems);
00470   if (numUndoItems && !mHadUndoItems || !numUndoItems && mHadUndoItems ||
00471       numRedoItems && !mHadRedoItems || !numRedoItems && mHadRedoItems) {
00472     // Modify the menu if undo or redo items are different
00473     UpdateTextInputCommands(NS_LITERAL_STRING("undo"));
00474 
00475     mHadUndoItems = numUndoItems != 0;
00476     mHadRedoItems = numRedoItems != 0;
00477   }
00478 
00479   // Make sure we know we were changed (do NOT set this to false if there are
00480   // no undo items; JS could change the value and we'd still need to save it)
00481   mFrame->SetValueChanged(PR_TRUE);
00482 
00483   // Fire input event
00484   mFrame->FireOnInput();
00485 
00486   return NS_OK;
00487 }
00488 
00489 // END nsIEditorObserver
00490 
00491 
00492 nsresult
00493 nsTextInputListener::UpdateTextInputCommands(const nsAString& commandsToUpdate)
00494 {
00495   NS_ENSURE_STATE(mFrame);
00496 
00497   nsIContent* content = mFrame->GetContent();
00498   NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
00499   
00500   nsCOMPtr<nsIDocument> doc = content->GetDocument();
00501   NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
00502 
00503   nsCOMPtr<nsIDOMWindowInternal> domWindow = do_QueryInterface(doc->GetScriptGlobalObject());
00504   NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
00505 
00506   return domWindow->UpdateCommands(commandsToUpdate);
00507 }
00508 
00509 nsINativeKeyBindings*
00510 nsTextInputListener::GetKeyBindings()
00511 {
00512   if (mFrame->IsTextArea()) {
00513     static PRBool sNoTextAreaBindings = PR_FALSE;
00514 
00515     if (!sNativeTextAreaBindings && !sNoTextAreaBindings) {
00516       CallGetService(NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "textarea",
00517                      &sNativeTextAreaBindings);
00518 
00519       if (!sNativeTextAreaBindings) {
00520         sNoTextAreaBindings = PR_TRUE;
00521       }
00522     }
00523 
00524     return sNativeTextAreaBindings;
00525   }
00526 
00527   static PRBool sNoInputBindings = PR_FALSE;
00528   if (!sNativeInputBindings && !sNoInputBindings) {
00529     CallGetService(NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "input",
00530                    &sNativeInputBindings);
00531 
00532     if (!sNativeInputBindings) {
00533       sNoInputBindings = PR_TRUE;
00534     }
00535   }
00536 
00537   return sNativeInputBindings;
00538 }
00539 
00540 // END nsTextInputListener
00541 
00542 #ifdef XP_MAC
00543 #pragma mark -
00544 #endif
00545   
00546 class nsTextInputSelectionImpl : public nsSupportsWeakReference, public nsISelectionController, public nsIFrameSelection
00547 {
00548 public:
00549   NS_DECL_ISUPPORTS
00550 
00551   nsTextInputSelectionImpl(nsIFrameSelection *aSel, nsIPresShell *aShell, nsIContent *aLimiter);
00552   ~nsTextInputSelectionImpl(){}
00553 
00554   
00555   //NSISELECTIONCONTROLLER INTERFACES
00556   NS_IMETHOD SetDisplaySelection(PRInt16 toggle);
00557   NS_IMETHOD GetDisplaySelection(PRInt16 *_retval);
00558   NS_IMETHOD SetSelectionFlags(PRInt16 aInEnable);
00559   NS_IMETHOD GetSelectionFlags(PRInt16 *aOutEnable);
00560   NS_IMETHOD GetSelection(PRInt16 type, nsISelection **_retval);
00561   NS_IMETHOD ScrollSelectionIntoView(PRInt16 aType, PRInt16 aRegion, PRBool aIsSynchronous);
00562   NS_IMETHOD RepaintSelection(PRInt16 type);
00563   NS_IMETHOD RepaintSelection(nsPresContext* aPresContext, SelectionType aSelectionType);
00564   NS_IMETHOD SetCaretEnabled(PRBool enabled);
00565   NS_IMETHOD SetCaretReadOnly(PRBool aReadOnly);
00566   NS_IMETHOD GetCaretEnabled(PRBool *_retval);
00567   NS_IMETHOD SetCaretVisibilityDuringSelection(PRBool aVisibility);
00568   NS_IMETHOD CharacterMove(PRBool aForward, PRBool aExtend);
00569   NS_IMETHOD WordMove(PRBool aForward, PRBool aExtend);
00570   NS_IMETHOD LineMove(PRBool aForward, PRBool aExtend);
00571   NS_IMETHOD IntraLineMove(PRBool aForward, PRBool aExtend);
00572   NS_IMETHOD PageMove(PRBool aForward, PRBool aExtend);
00573   NS_IMETHOD CompleteScroll(PRBool aForward);
00574   NS_IMETHOD CompleteMove(PRBool aForward, PRBool aExtend);
00575   NS_IMETHOD ScrollPage(PRBool aForward);
00576   NS_IMETHOD ScrollLine(PRBool aForward);
00577   NS_IMETHOD ScrollHorizontal(PRBool aLeft);
00578   NS_IMETHOD SelectAll(void);
00579   NS_IMETHOD CheckVisibility(nsIDOMNode *node, PRInt16 startOffset, PRInt16 EndOffset, PRBool *_retval);
00580 
00581   // NSIFRAMESELECTION INTERFACES
00582   NS_IMETHOD Init(nsIPresShell *aShell, nsIContent *aLimiter) ;
00583   NS_IMETHOD ShutDown() ;
00584   NS_IMETHOD HandleTextEvent(nsGUIEvent *aGuiEvent) ;
00585   NS_IMETHOD HandleKeyEvent(nsPresContext* aPresContext, nsGUIEvent *aGuiEvent);
00586   NS_IMETHOD HandleClick(nsIContent *aNewFocus, PRUint32 aContentOffset, PRUint32 aContentEndOffset , 
00587                        PRBool aContinueSelection, PRBool aMultipleSelection, PRBool aHint); 
00588   NS_IMETHOD HandleDrag(nsPresContext *aPresContext, nsIFrame *aFrame, nsPoint& aPoint);
00589   NS_IMETHOD HandleTableSelection(nsIContent *aParentContent, PRInt32 aContentOffset, PRInt32 aTarget, nsMouseEvent *aMouseEvent);
00590   NS_IMETHOD StartAutoScrollTimer(nsPresContext *aPresContext, nsIView* aView, nsPoint& aPoint, PRUint32 aDelay);
00591   NS_IMETHOD StopAutoScrollTimer();
00592   NS_IMETHOD EnableFrameNotification(PRBool aEnable);
00593   NS_IMETHOD LookUpSelection(nsIContent *aContent, PRInt32 aContentOffset, PRInt32 aContentLength,
00594                              SelectionDetails **aReturnDetails, PRBool aSlowCheck);
00595   NS_IMETHOD SetMouseDownState(PRBool aState);
00596   NS_IMETHOD GetMouseDownState(PRBool *aState);
00597   NS_IMETHOD SetDelayCaretOverExistingSelection(PRBool aDelay);
00598   NS_IMETHOD GetDelayCaretOverExistingSelection(PRBool *aDelay);
00599   NS_IMETHOD SetDelayedCaretData(nsMouseEvent *aMouseEvent);
00600   NS_IMETHOD GetDelayedCaretData(nsMouseEvent **aMouseEvent);
00601   NS_IMETHOD GetLimiter(nsIContent **aLimiterContent);
00602   NS_IMETHOD GetTableCellSelection(PRBool *aState);
00603   NS_IMETHOD GetFrameForNodeOffset(nsIContent *aNode, PRInt32 aOffset, HINT aHint, nsIFrame **aReturnFrame, PRInt32 *aReturnOffset);
00604   NS_IMETHOD AdjustOffsetsFromStyle(nsIFrame *aFrame, PRBool *changeSelection,
00605       nsIContent** outContent, PRInt32* outStartOffset, PRInt32* outEndOffset);
00606   NS_IMETHOD GetHint(nsIFrameSelection::HINT *aHint);
00607   NS_IMETHOD SetHint(nsIFrameSelection::HINT aHint);
00608   NS_IMETHOD SetScrollableView(nsIScrollableView *aScrollableView);
00609   NS_IMETHOD GetScrollableView(nsIScrollableView **aScrollableView);
00610   NS_IMETHOD CommonPageMove(PRBool aForward, PRBool aExtend, nsIScrollableView *aScrollableView, nsIFrameSelection *aFrameSel);
00611   NS_IMETHOD SetMouseDoubleDown(PRBool aDoubleDown);
00612   NS_IMETHOD GetMouseDoubleDown(PRBool *aDoubleDown);
00613   NS_IMETHOD MaintainSelection();
00614 #ifdef IBMBIDI
00615   NS_IMETHOD GetPrevNextBidiLevels(nsPresContext *aPresContext,
00616                                    nsIContent *aNode,
00617                                    PRUint32 aContentOffset,
00618                                    nsIFrame **aPrevFrame,
00619                                    nsIFrame **aNextFrame,
00620                                    PRUint8 *aPrevLevel,
00621                                    PRUint8 *aNextLevel);
00622   NS_IMETHOD GetFrameFromLevel(nsPresContext *aPresContext,
00623                                nsIFrame *aFrameIn,
00624                                nsDirection aDirection,
00625                                PRUint8 aBidiLevel,
00626                                nsIFrame **aFrameOut);
00627 #endif
00628   //END INTERFACES
00629 
00630 
00631   nsWeakPtr &GetPresShell(){return mPresShellWeak;}
00632 private:
00633   nsCOMPtr<nsIFrameSelection> mFrameSelection;
00634   nsCOMPtr<nsIContent>        mLimiter;
00635   nsWeakPtr mPresShellWeak;
00636 #ifdef IBMBIDI
00637   nsCOMPtr<nsIBidiKeyboard> mBidiKeyboard;
00638 #endif
00639 };
00640 
00641 // Implement our nsISupports methods
00642 NS_IMPL_ISUPPORTS3(nsTextInputSelectionImpl, nsISelectionController, nsISupportsWeakReference, nsIFrameSelection)
00643 
00644 
00645 // BEGIN nsTextInputSelectionImpl
00646 
00647 nsTextInputSelectionImpl::nsTextInputSelectionImpl(nsIFrameSelection *aSel, nsIPresShell *aShell, nsIContent *aLimiter)
00648 {
00649   if (aSel && aShell)
00650   {
00651     mFrameSelection = aSel;//we are the owner now!
00652     mLimiter = aLimiter;
00653     mFrameSelection->Init(aShell, mLimiter);
00654     mPresShellWeak = do_GetWeakReference(aShell);
00655 #ifdef IBMBIDI
00656     mBidiKeyboard = do_GetService("@mozilla.org/widget/bidikeyboard;1");
00657 #endif
00658   }
00659 }
00660 
00661 NS_IMETHODIMP
00662 nsTextInputSelectionImpl::SetDisplaySelection(PRInt16 aToggle)
00663 {
00664   if (mFrameSelection)
00665     return mFrameSelection->SetDisplaySelection(aToggle);
00666   return NS_ERROR_NULL_POINTER;
00667 }
00668 
00669 NS_IMETHODIMP
00670 nsTextInputSelectionImpl::GetDisplaySelection(PRInt16 *aToggle)
00671 {
00672   if (mFrameSelection)
00673     return mFrameSelection->GetDisplaySelection(aToggle);
00674   return NS_ERROR_NULL_POINTER;
00675 }
00676 
00677 NS_IMETHODIMP
00678 nsTextInputSelectionImpl::SetSelectionFlags(PRInt16 aToggle)
00679 {
00680   return NS_OK;//stub this out. not used in input
00681 }
00682 
00683 NS_IMETHODIMP
00684 nsTextInputSelectionImpl::GetSelectionFlags(PRInt16 *aOutEnable)
00685 {
00686   *aOutEnable = nsISelectionDisplay::DISPLAY_TEXT;
00687   return NS_OK; 
00688 }
00689 
00690 NS_IMETHODIMP
00691 nsTextInputSelectionImpl::GetSelection(PRInt16 type, nsISelection **_retval)
00692 {
00693   if (mFrameSelection)
00694     return mFrameSelection->GetSelection(type, _retval);
00695   return NS_ERROR_NULL_POINTER;
00696 }
00697 
00698 NS_IMETHODIMP
00699 nsTextInputSelectionImpl::ScrollSelectionIntoView(PRInt16 aType, PRInt16 aRegion, PRBool aIsSynchronous)
00700 {
00701   if (mFrameSelection) {
00702     nsresult rv = mFrameSelection->ScrollSelectionIntoView(aType, aRegion, aIsSynchronous);
00703 
00704     nsIScrollableView* scrollableView = nsnull;
00705     GetScrollableView(&scrollableView);
00706     if (!scrollableView) {
00707       return rv;
00708     }
00709     nsIView* view = nsnull;
00710     scrollableView->GetScrolledView(view);
00711     if (!view) {
00712       return rv;
00713     }
00714     const nsRect portRect = scrollableView->View()->GetBounds();
00715     const nsRect viewRect = view->GetBounds();
00716     if (viewRect.XMost() < portRect.width) {
00717       return scrollableView->ScrollTo(PR_MAX(viewRect.width - portRect.width, 0), viewRect.y, 0);
00718     }
00719 
00720     return rv;
00721   }
00722   return NS_ERROR_NULL_POINTER;
00723 }
00724 
00725 NS_IMETHODIMP
00726 nsTextInputSelectionImpl::RepaintSelection(PRInt16 type)
00727 {
00728   if (!mPresShellWeak) return NS_ERROR_NOT_INITIALIZED;
00729   nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShellWeak);
00730   if (presShell)
00731   {
00732     nsPresContext *context = presShell->GetPresContext();
00733     if (context)
00734     {
00735       return mFrameSelection->RepaintSelection(context, type);
00736     }
00737   }
00738   return NS_ERROR_FAILURE;
00739 }
00740 
00741 NS_IMETHODIMP
00742 nsTextInputSelectionImpl::RepaintSelection(nsPresContext* aPresContext, SelectionType aSelectionType)
00743 {
00744   return RepaintSelection(aSelectionType);
00745 }
00746 
00747 NS_IMETHODIMP
00748 nsTextInputSelectionImpl::SetCaretEnabled(PRBool enabled)
00749 {
00750   if (!mPresShellWeak) return NS_ERROR_NOT_INITIALIZED;
00751 
00752   nsCOMPtr<nsIPresShell> shell = do_QueryReferent(mPresShellWeak);
00753   if (!shell) return NS_ERROR_FAILURE;
00754 
00755   // tell the pres shell to enable the caret, rather than settings its visibility directly.
00756   // this way the presShell's idea of caret visibility is maintained.
00757   nsCOMPtr<nsISelectionController> selCon = do_QueryInterface(shell);
00758   if (!selCon) return NS_ERROR_NO_INTERFACE;
00759   selCon->SetCaretEnabled(enabled);
00760 
00761   return NS_OK;
00762 }
00763 
00764 NS_IMETHODIMP
00765 nsTextInputSelectionImpl::SetCaretReadOnly(PRBool aReadOnly)
00766 {
00767   if (!mPresShellWeak) return NS_ERROR_NOT_INITIALIZED;
00768   nsresult result;
00769   nsCOMPtr<nsIPresShell> shell = do_QueryReferent(mPresShellWeak, &result);
00770   if (shell)
00771   {
00772     nsCOMPtr<nsICaret> caret;
00773     if (NS_SUCCEEDED(result = shell->GetCaret(getter_AddRefs(caret))))
00774     {
00775       nsCOMPtr<nsISelection> domSel;
00776       if (NS_SUCCEEDED(result = mFrameSelection->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSel))))
00777       {
00778         return caret->SetCaretReadOnly(aReadOnly);
00779       }
00780     }
00781 
00782   }
00783   return NS_ERROR_FAILURE;
00784 }
00785 
00786 NS_IMETHODIMP
00787 nsTextInputSelectionImpl::GetCaretEnabled(PRBool *_retval)
00788 {
00789   if (!mPresShellWeak) return NS_ERROR_NOT_INITIALIZED;
00790   nsresult result;
00791   nsCOMPtr<nsIPresShell> shell = do_QueryReferent(mPresShellWeak, &result);
00792   if (shell)
00793   {
00794     nsCOMPtr<nsICaret> caret;
00795     if (NS_SUCCEEDED(result = shell->GetCaret(getter_AddRefs(caret))))
00796     {
00797       nsCOMPtr<nsISelection> domSel;
00798       if (NS_SUCCEEDED(result = mFrameSelection->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSel))))
00799       {
00800         return caret->GetCaretVisible(_retval);
00801       }
00802     }
00803 
00804   }
00805   return NS_ERROR_FAILURE;
00806 }
00807 
00808 NS_IMETHODIMP
00809 nsTextInputSelectionImpl::SetCaretVisibilityDuringSelection(PRBool aVisibility)
00810 {
00811   if (!mPresShellWeak) return NS_ERROR_NOT_INITIALIZED;
00812   nsresult result;
00813   nsCOMPtr<nsIPresShell> shell = do_QueryReferent(mPresShellWeak, &result);
00814   if (shell)
00815   {
00816     nsCOMPtr<nsICaret> caret;
00817     if (NS_SUCCEEDED(result = shell->GetCaret(getter_AddRefs(caret))))
00818     {
00819       nsCOMPtr<nsISelection> domSel;
00820       if (NS_SUCCEEDED(result = mFrameSelection->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSel))))
00821       {
00822         return caret->SetVisibilityDuringSelection(aVisibility);
00823       }
00824     }
00825 
00826   }
00827   return NS_ERROR_FAILURE;
00828 }
00829 
00830 NS_IMETHODIMP
00831 nsTextInputSelectionImpl::CharacterMove(PRBool aForward, PRBool aExtend)
00832 {
00833   if (mFrameSelection)
00834     return mFrameSelection->CharacterMove(aForward, aExtend);
00835   return NS_ERROR_NULL_POINTER;
00836 }
00837 
00838 
00839 NS_IMETHODIMP
00840 nsTextInputSelectionImpl::WordMove(PRBool aForward, PRBool aExtend)
00841 {
00842   if (mFrameSelection)
00843     return mFrameSelection->WordMove(aForward, aExtend);
00844   return NS_ERROR_NULL_POINTER;
00845 }
00846 
00847 
00848 NS_IMETHODIMP
00849 nsTextInputSelectionImpl::LineMove(PRBool aForward, PRBool aExtend)
00850 {
00851   if (mFrameSelection)
00852   {
00853     nsresult result = mFrameSelection->LineMove(aForward, aExtend);
00854     if (NS_FAILED(result))
00855       result = CompleteMove(aForward,aExtend);
00856     return result;
00857   }
00858   return NS_ERROR_NULL_POINTER;
00859 }
00860 
00861 
00862 NS_IMETHODIMP
00863 nsTextInputSelectionImpl::IntraLineMove(PRBool aForward, PRBool aExtend)
00864 {
00865   if (mFrameSelection)
00866     return mFrameSelection->IntraLineMove(aForward, aExtend);
00867   return NS_ERROR_NULL_POINTER;
00868 }
00869 
00870 
00871 NS_IMETHODIMP
00872 nsTextInputSelectionImpl::PageMove(PRBool aForward, PRBool aExtend)
00873 {
00874   // expected behavior for PageMove is to scroll AND move the caret
00875   // and to remain relative position of the caret in view. see Bug 4302.
00876 
00877   if (mPresShellWeak)
00878   {
00879     nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShellWeak);
00880     if (!presShell)
00881       return NS_ERROR_NULL_POINTER;
00882 
00883     //get the scroll view
00884     nsIScrollableView *scrollableView;
00885     nsresult result = GetScrollableView(&scrollableView);
00886     if (NS_FAILED(result))
00887       return result;
00888 
00889     CommonPageMove(aForward, aExtend, scrollableView, this);
00890   }
00891   return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL, nsISelectionController::SELECTION_FOCUS_REGION, PR_TRUE);
00892 }
00893 
00894 NS_IMETHODIMP
00895 nsTextInputSelectionImpl::CompleteScroll(PRBool aForward)
00896 {
00897   nsIScrollableView *scrollableView;
00898   nsresult result;
00899   result = GetScrollableView(&scrollableView);
00900   if (NS_FAILED(result))
00901     return result;
00902   if (!scrollableView)
00903     return NS_ERROR_NOT_INITIALIZED;
00904 
00905   return scrollableView->ScrollByWhole(!aForward); //TRUE = top, aForward TRUE=bottom
00906 }
00907 
00908 NS_IMETHODIMP
00909 nsTextInputSelectionImpl::CompleteMove(PRBool aForward, PRBool aExtend)
00910 {
00911   // grab the parent / root DIV for this text widget
00912   nsresult result;
00913   nsCOMPtr<nsIContent> parentDIV;
00914   result = GetLimiter(getter_AddRefs(parentDIV));
00915   if (NS_FAILED(result))
00916     return result;
00917   if (!parentDIV)
00918     return NS_ERROR_UNEXPECTED;
00919 
00920   // make the caret be either at the very beginning (0) or the very end
00921   PRInt32 offset = 0;
00922   HINT hint = HINTLEFT;
00923   if (aForward)
00924   {
00925     offset = parentDIV->GetChildCount();
00926 
00927     // Prevent the caret from being placed after the last
00928     // BR node in the content tree!
00929 
00930     if (offset > 0)
00931     {
00932       nsIContent *child = parentDIV->GetChildAt(offset - 1);
00933 
00934       if (child->Tag() == nsHTMLAtoms::br)
00935       {
00936         --offset;
00937         hint = HINTRIGHT; // for Bug 106855
00938       }
00939     }
00940   }
00941 
00942   result = mFrameSelection->HandleClick(parentDIV, offset, offset, aExtend, PR_FALSE, hint);
00943 
00944   // if we got this far, attempt to scroll no matter what the above result is
00945   return CompleteScroll(aForward);
00946 }
00947 
00948 NS_IMETHODIMP
00949 nsTextInputSelectionImpl::ScrollPage(PRBool aForward)
00950 {
00951   nsIScrollableView *scrollableView;
00952   nsresult result;
00953   result = GetScrollableView(&scrollableView);
00954   if (NS_FAILED(result))
00955     return result;
00956   if (!scrollableView)
00957     return NS_ERROR_NOT_INITIALIZED;
00958 
00959   return scrollableView->ScrollByPages(0, aForward ? 1 : -1);
00960 }
00961 
00962 NS_IMETHODIMP
00963 nsTextInputSelectionImpl::ScrollLine(PRBool aForward)
00964 {
00965   nsIScrollableView *scrollableView;
00966   nsresult result;
00967   result = GetScrollableView(&scrollableView);
00968   if (NS_FAILED(result))
00969     return result;
00970   if (!scrollableView)
00971     return NS_ERROR_NOT_INITIALIZED;
00972 
00973   // will we have bug #7354 because we aren't forcing an update here?
00974   return scrollableView->ScrollByLines(0, aForward ? 1 : -1);
00975 }
00976 
00977 NS_IMETHODIMP
00978 nsTextInputSelectionImpl::ScrollHorizontal(PRBool aLeft)
00979 {
00980   nsIScrollableView *scrollableView;
00981   nsresult result;
00982   result = GetScrollableView(&scrollableView);
00983   if (NS_FAILED(result))
00984     return result;
00985   if (!scrollableView)
00986     return NS_ERROR_NOT_INITIALIZED;
00987 
00988   // will we have bug #7354 because we aren't forcing an update here?
00989   return scrollableView->ScrollByLines(aLeft ? -1 : 1, 0);
00990 }
00991 
00992 NS_IMETHODIMP
00993 nsTextInputSelectionImpl::SelectAll()
00994 {
00995   if (mFrameSelection)
00996     return mFrameSelection->SelectAll();
00997   return NS_ERROR_NULL_POINTER;
00998 }
00999 
01000 NS_IMETHODIMP
01001 nsTextInputSelectionImpl::CheckVisibility(nsIDOMNode *node, PRInt16 startOffset, PRInt16 EndOffset, PRBool *_retval)
01002 {
01003   if (!mPresShellWeak) return NS_ERROR_NOT_INITIALIZED;
01004   nsresult result;
01005   nsCOMPtr<nsISelectionController> shell = do_QueryReferent(mPresShellWeak, &result);
01006   if (shell)
01007   {
01008     return shell->CheckVisibility(node,startOffset,EndOffset, _retval);
01009   }
01010   return NS_ERROR_FAILURE;
01011 
01012 }
01013 
01014 
01015 //nsTextInputSelectionImpl::FRAMESELECTIONAPIS
01016 
01017 NS_IMETHODIMP
01018 nsTextInputSelectionImpl::Init(nsIPresShell *aShell, nsIContent *aLimiter)
01019 {
01020   return mFrameSelection->Init(aShell, aLimiter);
01021 }
01022 
01023 
01024 NS_IMETHODIMP
01025 nsTextInputSelectionImpl::ShutDown()
01026 {
01027   return mFrameSelection->ShutDown();
01028 }
01029 
01030 
01031 NS_IMETHODIMP
01032 nsTextInputSelectionImpl::HandleTextEvent(nsGUIEvent *aGuiEvent)
01033 {
01034   return mFrameSelection->HandleTextEvent(aGuiEvent);
01035 }
01036 
01037 
01038 NS_IMETHODIMP
01039 nsTextInputSelectionImpl::HandleKeyEvent(nsPresContext* aPresContext, nsGUIEvent *aGuiEvent)
01040 {
01041   return mFrameSelection->HandleKeyEvent(aPresContext, aGuiEvent);
01042 }
01043 
01044 
01045 NS_IMETHODIMP
01046 nsTextInputSelectionImpl::HandleClick(nsIContent *aNewFocus, PRUint32 aContentOffset, PRUint32 aContentEndOffset , 
01047                      PRBool aContinueSelection, PRBool aMultipleSelection, PRBool aHint)
01048 {
01049   return mFrameSelection->HandleClick(aNewFocus, aContentOffset, aContentEndOffset , 
01050                      aContinueSelection, aMultipleSelection, aHint);
01051 }
01052 
01053 
01054 NS_IMETHODIMP
01055 nsTextInputSelectionImpl::HandleDrag(nsPresContext *aPresContext, nsIFrame *aFrame, nsPoint& aPoint)
01056 {
01057   return mFrameSelection->HandleDrag(aPresContext, aFrame, aPoint);
01058 }
01059 
01060 
01061 NS_IMETHODIMP
01062 nsTextInputSelectionImpl::HandleTableSelection(nsIContent *aParentContent, PRInt32 aContentOffset, PRInt32 aTarget, nsMouseEvent *aMouseEvent)
01063 {
01064   // We should never have a table inside a text control frame!
01065   NS_ASSERTION(PR_TRUE, "Calling HandleTableSelection inside nsTextControlFrame!");
01066   return NS_OK;
01067 }
01068 
01069 
01070 NS_IMETHODIMP
01071 nsTextInputSelectionImpl::StartAutoScrollTimer(nsPresContext *aPresContext, nsIView *aView, nsPoint& aPoint, PRUint32 aDelay)
01072 {
01073   return mFrameSelection->StartAutoScrollTimer(aPresContext, aView, aPoint, aDelay);
01074 }
01075 
01076 
01077 NS_IMETHODIMP
01078 nsTextInputSelectionImpl::StopAutoScrollTimer()
01079 {
01080   return mFrameSelection->StopAutoScrollTimer();
01081 }
01082 
01083 
01084 NS_IMETHODIMP
01085 nsTextInputSelectionImpl::EnableFrameNotification(PRBool aEnable)
01086 {
01087   return mFrameSelection->EnableFrameNotification(aEnable);
01088 }
01089 
01090 
01091 NS_IMETHODIMP
01092 nsTextInputSelectionImpl::LookUpSelection(nsIContent *aContent, PRInt32 aContentOffset, PRInt32 aContentLength,
01093                            SelectionDetails **aReturnDetails, PRBool aSlowCheck)
01094 {
01095   return mFrameSelection->LookUpSelection(aContent, aContentOffset, aContentLength, aReturnDetails, aSlowCheck);
01096 }
01097 
01098 
01099 NS_IMETHODIMP
01100 nsTextInputSelectionImpl::SetMouseDownState(PRBool aState)
01101 {
01102   return mFrameSelection->SetMouseDownState(aState);
01103 }
01104 
01105 
01106 NS_IMETHODIMP
01107 nsTextInputSelectionImpl::GetMouseDownState(PRBool *aState)
01108 {
01109   return mFrameSelection->GetMouseDownState(aState);
01110 }
01111 
01112 NS_IMETHODIMP
01113 nsTextInputSelectionImpl::SetDelayCaretOverExistingSelection(PRBool aDelay)
01114 {
01115   return mFrameSelection->SetDelayCaretOverExistingSelection(aDelay);
01116 }
01117 
01118 NS_IMETHODIMP
01119 nsTextInputSelectionImpl::GetDelayCaretOverExistingSelection(PRBool *aDelay)
01120 {
01121   return mFrameSelection->GetDelayCaretOverExistingSelection(aDelay);
01122 }
01123 
01124 NS_IMETHODIMP
01125 nsTextInputSelectionImpl::SetDelayedCaretData(nsMouseEvent *aMouseEvent)
01126 {
01127   return mFrameSelection->SetDelayedCaretData(aMouseEvent);
01128 }
01129 
01130 NS_IMETHODIMP
01131 nsTextInputSelectionImpl::GetDelayedCaretData(nsMouseEvent **aMouseEvent)
01132 {
01133   return mFrameSelection->GetDelayedCaretData(aMouseEvent);
01134 }
01135 
01136 NS_IMETHODIMP
01137 nsTextInputSelectionImpl::GetLimiter(nsIContent **aLimiterContent)
01138 {
01139   return mFrameSelection->GetLimiter(aLimiterContent);
01140 }
01141 
01142 NS_IMETHODIMP
01143 nsTextInputSelectionImpl::GetTableCellSelection(PRBool *aState)
01144 {
01145   return mFrameSelection->GetTableCellSelection(aState);
01146 }
01147 
01148 
01149 NS_IMETHODIMP
01150 nsTextInputSelectionImpl::GetFrameForNodeOffset(nsIContent *aNode, PRInt32 aOffset, HINT aHint, nsIFrame **aReturnFrame, PRInt32 *aReturnOffset)
01151 {
01152   return mFrameSelection->GetFrameForNodeOffset(aNode, aOffset, aHint,aReturnFrame,aReturnOffset);
01153 }
01154 
01155 NS_IMETHODIMP
01156 nsTextInputSelectionImpl::AdjustOffsetsFromStyle(nsIFrame *aFrame, PRBool *changeSelection,
01157       nsIContent** outContent, PRInt32* outStartOffset, PRInt32* outEndOffset)
01158 {
01159   return mFrameSelection->AdjustOffsetsFromStyle(aFrame, changeSelection, outContent, outStartOffset, outEndOffset);
01160 }
01161 
01162 NS_IMETHODIMP nsTextInputSelectionImpl::GetHint(nsIFrameSelection::HINT *aHint)
01163 {
01164   return mFrameSelection->GetHint(aHint);
01165 }
01166 
01167 NS_IMETHODIMP nsTextInputSelectionImpl::SetHint(nsIFrameSelection::HINT aHint)
01168 {
01169   return mFrameSelection->SetHint(aHint);
01170 }
01171 
01172 NS_IMETHODIMP nsTextInputSelectionImpl::SetScrollableView(nsIScrollableView *aScrollableView)
01173 {
01174   return mFrameSelection->SetScrollableView(aScrollableView);
01175 }
01176 
01177 NS_IMETHODIMP nsTextInputSelectionImpl::GetScrollableView(nsIScrollableView **aScrollableView)
01178 {
01179   return mFrameSelection->GetScrollableView(aScrollableView);
01180 }
01181 
01182 NS_IMETHODIMP nsTextInputSelectionImpl::SetMouseDoubleDown(PRBool aDoubleDown)
01183 {
01184   return mFrameSelection->SetMouseDoubleDown(aDoubleDown);
01185 }
01186 
01187 NS_IMETHODIMP nsTextInputSelectionImpl::GetMouseDoubleDown(PRBool *aDoubleDown)
01188 {
01189   return mFrameSelection->GetMouseDoubleDown(aDoubleDown);
01190 }
01191 
01192 NS_IMETHODIMP nsTextInputSelectionImpl::MaintainSelection()
01193 {
01194   return mFrameSelection->MaintainSelection();
01195 }
01196 
01197 NS_IMETHODIMP nsTextInputSelectionImpl::CommonPageMove(PRBool aForward, PRBool aExtend, nsIScrollableView *aScrollableView, nsIFrameSelection *aFrameSel)
01198 {
01199   return mFrameSelection->CommonPageMove(aForward, aExtend, aScrollableView, this);
01200 }
01201 
01202 #ifdef IBMBIDI
01203 NS_IMETHODIMP nsTextInputSelectionImpl::GetPrevNextBidiLevels(nsPresContext *aPresContext,
01204                                                               nsIContent *aNode,
01205                                                               PRUint32 aContentOffset,
01206                                                               nsIFrame **aPrevFrame,
01207                                                               nsIFrame **aNextFrame,
01208                                                               PRUint8 *aPrevLevel,
01209                                                               PRUint8 *aNextLevel)
01210 {
01211   if (mFrameSelection)
01212     return mFrameSelection->GetPrevNextBidiLevels(aPresContext, aNode, aContentOffset, aPrevFrame, aNextFrame, aPrevLevel, aNextLevel);
01213   return NS_ERROR_FAILURE;
01214 }
01215 
01216 NS_IMETHODIMP nsTextInputSelectionImpl::GetFrameFromLevel(nsPresContext *aPresContext,
01217                                                           nsIFrame *aFrameIn,
01218                                                           nsDirection aDirection,
01219                                                           PRUint8 aBidiLevel,
01220                                                           nsIFrame **aFrameOut)
01221 {
01222   if (mFrameSelection)
01223     return mFrameSelection->GetFrameFromLevel(aPresContext, aFrameIn, aDirection, aBidiLevel, aFrameOut);
01224   return NS_ERROR_FAILURE;
01225 }
01226 #endif // IBMBIDI
01227 
01228 // END   nsTextInputSelectionImpl
01229 
01230 
01231 
01232 nsresult
01233 NS_NewTextControlFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
01234 {
01235   NS_PRECONDITION(aNewFrame, "null OUT ptr");
01236   if (nsnull == aNewFrame) {
01237     return NS_ERROR_NULL_POINTER;
01238   }
01239   nsTextControlFrame* it = new (aPresShell) nsTextControlFrame(aPresShell);
01240   if (!it) {
01241     return NS_ERROR_OUT_OF_MEMORY;
01242   }
01243   *aNewFrame = it;
01244   return NS_OK;
01245 }
01246 
01247 NS_IMPL_ADDREF_INHERITED(nsTextControlFrame, nsBoxFrame)
01248 NS_IMPL_RELEASE_INHERITED(nsTextControlFrame, nsBoxFrame)
01249  
01250 
01251 NS_IMETHODIMP
01252 nsTextControlFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
01253 {
01254   if (NULL == aInstancePtr) {
01255     return NS_ERROR_NULL_POINTER;
01256   }
01257   if (aIID.Equals(NS_GET_IID(nsIFormControlFrame))) {
01258     *aInstancePtr = (void*) ((nsIFormControlFrame*) this);
01259     return NS_OK;
01260   }
01261   if (aIID.Equals(NS_GET_IID(nsIAnonymousContentCreator))) {
01262     *aInstancePtr = (void*)(nsIAnonymousContentCreator*) this;
01263     return NS_OK;
01264   }
01265   if (aIID.Equals(NS_GET_IID(nsITextControlFrame))) {
01266     *aInstancePtr = (void*)(nsITextControlFrame*) this;
01267     return NS_OK;
01268   }
01269   if (aIID.Equals(NS_GET_IID(nsIScrollableViewProvider)) && IsScrollable()) {
01270     *aInstancePtr = (void*)(nsIScrollableViewProvider*) this;
01271     return NS_OK;
01272   }
01273   if (aIID.Equals(NS_GET_IID(nsIPhonetic))) {
01274     *aInstancePtr = (void*)(nsIPhonetic*) this;
01275     return NS_OK;
01276   }
01277 
01278   return nsBoxFrame::QueryInterface(aIID, aInstancePtr);
01279 }
01280 
01281 #ifdef ACCESSIBILITY
01282 NS_IMETHODIMP nsTextControlFrame::GetAccessible(nsIAccessible** aAccessible)
01283 {
01284   nsCOMPtr<nsIAccessibilityService> accService = do_GetService("@mozilla.org/accessibilityService;1");
01285 
01286   if (accService) {
01287     return accService->CreateHTMLTextFieldAccessible(NS_STATIC_CAST(nsIFrame*, this), aAccessible);
01288   }
01289 
01290   return NS_ERROR_FAILURE;
01291 }
01292 #endif
01293 
01294 nsTextControlFrame::nsTextControlFrame(nsIPresShell* aShell)
01295   : nsStackFrame(aShell)
01296 {
01297   mUseEditor = PR_FALSE;
01298   mIsProcessing = PR_FALSE;
01299   mNotifyOnInput = PR_TRUE;
01300   mSuggestedWidth = NS_FORMSIZE_NOTSET;
01301   mSuggestedHeight = NS_FORMSIZE_NOTSET;
01302   mScrollableView = nsnull;
01303   mDidPreDestroy = PR_FALSE;
01304   mHasFocus = PR_FALSE;
01305 }
01306 
01307 nsTextControlFrame::~nsTextControlFrame()
01308 {
01309   //delete mTextListener;
01310   //delete mTextSelImpl; dont delete this since mSelCon will release it.
01311 }
01312 
01313 static PRBool
01314 SuppressEventHandlers(nsPresContext* aPresContext)
01315 {
01316   PRBool suppressHandlers = PR_FALSE;
01317 
01318   if (aPresContext)
01319   {
01320     // Right now we only suppress event handlers and controller manipulation
01321     // when in a print preview or print context!
01322 
01323 #ifdef USE_QI_IN_SUPPRESS_EVENT_HANDLERS
01324 
01325     // Using QI to see if we're printing or print previewing is more
01326     // accurate, but a bit more heavy weight then just checking
01327     // the pagination bool, which will return the right answer to us
01328     // with the current implementation.
01329 
01330     nsCOMPtr<nsIPrintContext> printContext = do_QueryInterface(aPresContext);
01331     if (printContext)
01332       suppressHandlers = PR_TRUE;
01333     else
01334     {
01335       nsCOMPtr<nsIPrintPreviewContext> printPreviewContext = do_QueryInterface(aPresContext);
01336       if (printPreviewContext)
01337         suppressHandlers = PR_TRUE;
01338     }
01339 
01340 #else
01341 
01342     // In the current implementation, we only paginate when
01343     // printing or in print preview.
01344 
01345     suppressHandlers = aPresContext->IsPaginated();
01346 
01347 #endif
01348   }
01349 
01350   return suppressHandlers;
01351 }
01352 
01353 void
01354 nsTextControlFrame::PreDestroy(nsPresContext* aPresContext)
01355 {
01356   // notify the editor that we are going away
01357   if (mEditor)
01358   {
01359     // If we were in charge of state before, relinquish it back
01360     // to the control.
01361     if (mUseEditor)
01362     {
01363       // First get the frame state from the editor
01364       nsAutoString value;
01365       GetValue(value, PR_TRUE);
01366 
01367       mUseEditor = PR_FALSE;
01368 
01369       // Next store the frame state in the control
01370       // (now that mUseEditor is false values get stored
01371       // in content).
01372       SetValue(value);
01373     }
01374     mEditor->PreDestroy();
01375   }
01376   
01377   // Clean up the controller
01378 
01379   if (!SuppressEventHandlers(aPresContext))
01380   {
01381     nsCOMPtr<nsIControllers> controllers;
01382     nsCOMPtr<nsIDOMNSHTMLInputElement> inputElement = do_QueryInterface(mContent);
01383     if (inputElement)
01384       inputElement->GetControllers(getter_AddRefs(controllers));
01385     else
01386     {
01387       nsCOMPtr<nsIDOMNSHTMLTextAreaElement> textAreaElement = do_QueryInterface(mContent);
01388       if (textAreaElement) {
01389         textAreaElement->GetControllers(getter_AddRefs(controllers));
01390       }
01391     }
01392 
01393     if (controllers)
01394     {
01395       PRUint32 numControllers;
01396       nsresult rv = controllers->GetControllerCount(&numControllers);
01397       NS_ASSERTION((NS_SUCCEEDED(rv)), "bad result in gfx text control destructor");
01398       for (PRUint32 i = 0; i < numControllers; i ++)
01399       {
01400         nsCOMPtr<nsIController> controller;
01401         rv = controllers->GetControllerAt(i, getter_AddRefs(controller));
01402         if (NS_SUCCEEDED(rv) && controller)
01403         {
01404           nsCOMPtr<nsIControllerContext> editController = do_QueryInterface(controller);
01405           if (editController)
01406           {
01407             editController->SetCommandContext(nsnull);
01408           }
01409         }
01410       }
01411     }
01412   }
01413 
01414   mSelCon = 0;
01415   mEditor = 0;
01416   
01417 //unregister self from content
01418   mTextListener->SetFrame(nsnull);
01419   nsFormControlFrame::RegUnRegAccessKey(aPresContext, NS_STATIC_CAST(nsIFrame*, this), PR_FALSE);
01420   if (mTextListener)
01421   {
01422     nsCOMPtr<nsIDOMEventReceiver> erP = do_QueryInterface(mContent);
01423     if (erP)
01424     {
01425       erP->RemoveEventListenerByIID(NS_STATIC_CAST(nsIDOMFocusListener  *,mTextListener), NS_GET_IID(nsIDOMFocusListener));
01426     }
01427 
01428     nsCOMPtr<nsIDOMEventGroup> systemGroup;
01429     erP->GetSystemEventGroup(getter_AddRefs(systemGroup));
01430     nsCOMPtr<nsIDOM3EventTarget> dom3Targ = do_QueryInterface(mContent);
01431     if (dom3Targ) {
01432       // cast because of ambiguous base
01433       nsIDOMEventListener *listener = NS_STATIC_CAST(nsIDOMKeyListener*,
01434                                                      mTextListener);
01435 
01436       dom3Targ->RemoveGroupedEventListener(NS_LITERAL_STRING("keydown"),
01437                                            listener, PR_FALSE, systemGroup);
01438       dom3Targ->RemoveGroupedEventListener(NS_LITERAL_STRING("keypress"),
01439                                            listener, PR_FALSE, systemGroup);
01440       dom3Targ->RemoveGroupedEventListener(NS_LITERAL_STRING("keyup"),
01441                                            listener, PR_FALSE, systemGroup);
01442     }
01443   }
01444 
01445   mDidPreDestroy = PR_TRUE; 
01446 }
01447 
01448 NS_IMETHODIMP 
01449 nsTextControlFrame::Destroy(nsPresContext* aPresContext)
01450 {
01451   if (!mDidPreDestroy) {
01452     PreDestroy(aPresContext);
01453   }
01454   return nsBoxFrame::Destroy(aPresContext);
01455 }
01456 
01457 void 
01458 nsTextControlFrame::RemovedAsPrimaryFrame(nsPresContext* aPresContext)
01459 {
01460   if (!mDidPreDestroy) {
01461     PreDestroy(aPresContext);
01462   }
01463   else NS_ASSERTION(PR_FALSE, "RemovedAsPrimaryFrame called after PreDestroy");
01464 }
01465 
01466 nsIAtom*
01467 nsTextControlFrame::GetType() const 
01468 { 
01469   return nsLayoutAtoms::textInputFrame;
01470 } 
01471 
01472 // XXX: wouldn't it be nice to get this from the style context!
01473 PRBool nsTextControlFrame::IsSingleLineTextControl() const
01474 {
01475   PRInt32 type = GetFormControlType();
01476   return (type == NS_FORM_INPUT_TEXT) || (type == NS_FORM_INPUT_PASSWORD);
01477 }
01478 
01479 PRBool nsTextControlFrame::IsTextArea() const
01480 {
01481   return mContent && mContent->Tag() == nsHTMLAtoms::textarea;
01482 }
01483 
01484 // XXX: wouldn't it be nice to get this from the style context!
01485 PRBool nsTextControlFrame::IsPlainTextControl() const
01486 {
01487   // need to check HTML attribute of mContent and/or CSS.
01488   return PR_TRUE;
01489 }
01490 
01491 PRBool nsTextControlFrame::IsPasswordTextControl() const
01492 {
01493   return GetFormControlType() == NS_FORM_INPUT_PASSWORD;
01494 }
01495 
01496 
01497 PRInt32
01498 nsTextControlFrame::GetCols()
01499 {
01500   nsGenericHTMLElement *content = nsGenericHTMLElement::FromContent(mContent);
01501   NS_ASSERTION(content, "Content is not HTML content!");
01502 
01503   if (IsTextArea()) {
01504     const nsAttrValue* attr = content->GetParsedAttr(nsHTMLAtoms::cols);
01505     if (attr) {
01506       PRInt32 cols = attr->Type() == nsAttrValue::eInteger ?
01507                      attr->GetIntegerValue() : 0;
01508       // XXX why a default of 1 char, why hide it
01509       return (cols <= 0) ? 1 : cols;
01510     }
01511   } else {
01512     // Else we know (assume) it is an input with size attr
01513     const nsAttrValue* attr = content->GetParsedAttr(nsHTMLAtoms::size);
01514     if (attr && attr->Type() == nsAttrValue::eInteger) {
01515       PRInt32 cols = attr->GetIntegerValue();
01516       if (cols > 0) {
01517         return cols;
01518       }
01519     }
01520   }
01521 
01522   return DEFAULT_COLS;
01523 }
01524 
01525 
01526 PRInt32
01527 nsTextControlFrame::GetRows()
01528 {
01529   if (IsTextArea()) {
01530     nsGenericHTMLElement *content =
01531       nsGenericHTMLElement::FromContent(mContent);
01532     NS_ASSERTION(content, "Content is not HTML content!");
01533 
01534     const nsAttrValue* attr = content->GetParsedAttr(nsHTMLAtoms::rows);
01535     if (attr && attr->Type() == nsAttrValue::eInteger) {
01536       PRInt32 rows = attr->GetIntegerValue();
01537       return (rows <= 0) ? DEFAULT_ROWS_TEXTAREA : rows;
01538     }
01539     return DEFAULT_ROWS_TEXTAREA;
01540   }
01541 
01542   return DEFAULT_ROWS;
01543 }
01544 
01545 
01546 nsresult
01547 nsTextControlFrame::ReflowStandard(nsPresContext*          aPresContext,
01548                                    nsSize&                  aDesiredSize,
01549                                    const nsHTMLReflowState& aReflowState,
01550                                    nsReflowStatus&          aStatus)
01551 {
01552   // get the css size and let the frame use or override it
01553   nsSize minSize;
01554   nsresult rv = CalculateSizeStandard(aPresContext, aReflowState,
01555                                       aDesiredSize, minSize);
01556   NS_ENSURE_SUCCESS(rv, rv);
01557 
01558   // Add in the size of the scrollbars for textarea
01559   if (IsTextArea()) {
01560     float p2t;
01561     p2t = aPresContext->PixelsToTwips();
01562 
01563     nsIDeviceContext *dx = aPresContext->DeviceContext();
01564 
01565     float   scale;
01566     dx->GetCanonicalPixelScale(scale);
01567 
01568     float sbWidth;
01569     float sbHeight;
01570     dx->GetScrollBarDimensions(sbWidth, sbHeight);
01571 
01572     nscoord scrollbarWidth  = PRInt32(sbWidth * scale);
01573     nscoord scrollbarHeight = PRInt32(sbHeight * scale);
01574 
01575     aDesiredSize.height += scrollbarHeight;
01576     minSize.height      += scrollbarHeight;
01577 
01578     aDesiredSize.width  += scrollbarWidth;
01579     minSize.width       += scrollbarWidth;
01580   }
01581   aDesiredSize.width  += aReflowState.mComputedBorderPadding.left + aReflowState.mComputedBorderPadding.right;
01582   aDesiredSize.height += aReflowState.mComputedBorderPadding.top + aReflowState.mComputedBorderPadding.bottom;
01583 
01584   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
01585 
01586   return NS_OK;
01587 }
01588 
01589 
01590 
01591 nsresult
01592 nsTextControlFrame::CalculateSizeStandard(nsPresContext*       aPresContext,
01593                                           const nsHTMLReflowState& aReflowState,
01594                                           nsSize&               aDesiredSize,
01595                                           nsSize&               aMinSize)
01596 {
01597   aDesiredSize.width  = CSS_NOTSET;
01598   aDesiredSize.height = CSS_NOTSET;
01599 
01600   // Get leading and the Average/MaxAdvance char width 
01601   nscoord lineHeight  = 0;
01602   nscoord charWidth   = 0;
01603   nscoord charMaxAdvance  = 0;
01604 
01605   nsCOMPtr<nsIFontMetrics> fontMet;
01606   nsresult rv = nsFormControlHelper::GetFrameFontFM(this, getter_AddRefs(fontMet));
01607   NS_ENSURE_SUCCESS(rv, rv);
01608   nsIRenderingContext* rendContext = aReflowState.rendContext;
01609   rendContext->SetFont(fontMet);
01610   lineHeight = aReflowState.CalcLineHeight(aPresContext, rendContext, this);
01611   fontMet->GetAveCharWidth(charWidth);
01612   fontMet->GetMaxAdvance(charMaxAdvance);
01613 
01614   // Set the width equal to the width in characters
01615   PRInt32 cols = GetCols();
01616   aDesiredSize.width = cols * charWidth;
01617 
01618   // To better match IE, take the maximum character width(in twips) and remove
01619   // 4 pixels add this on as additional padding(internalPadding). But only do
01620   // this if charMaxAdvance != charWidth; if they are equal, this is almost
01621   // certainly a fixed-width font.
01622   if (charWidth != charMaxAdvance) {
01623     float p2t;
01624     p2t = aPresContext->PixelsToTwips();
01625     nscoord internalPadding = PR_MAX(charMaxAdvance - NSToCoordRound(4 * p2t), 0);
01626     // round to a multiple of p2t
01627     nscoord t = NSToCoordRound(p2t); 
01628     nscoord rest = internalPadding % t; 
01629     if (rest < t - rest) {
01630       internalPadding -= rest;
01631     } else {
01632       internalPadding += t - rest;
01633     }
01634     // Now add the extra padding on (so that small input sizes work well)
01635     aDesiredSize.width += internalPadding;
01636   } else {
01637     // This is to account for the anonymous <br> having a 1 twip width
01638     // in Full Standards mode, see BRFrame::Reflow and bug 228752.
01639     if (aPresContext->CompatibilityMode() == eCompatibility_FullStandards) {
01640       aDesiredSize.width += 1;
01641     }
01642   }
01643 
01644   // Increment width with cols * letter-spacing.
01645   {
01646     const nsStyleCoord& lsCoord = GetStyleText()->mLetterSpacing;
01647     if (eStyleUnit_Coord == lsCoord.GetUnit()) {
01648       nscoord letterSpacing = lsCoord.GetCoordValue();
01649       if (letterSpacing != 0) {
01650         aDesiredSize.width += cols * letterSpacing;
01651       }
01652     }
01653   }
01654 
01655   // Set the height equal to total number of rows (times the height of each
01656   // line, of course)
01657   aDesiredSize.height = lineHeight * GetRows();
01658 
01659   // Set minimum size equal to desired size.  We are form controls.  We are Gods
01660   // among elements.  We do not yield for anybody, not even a table cell.  None
01661   // shall pass.
01662   aMinSize.width  = aDesiredSize.width;
01663   aMinSize.height = aDesiredSize.height;
01664 
01665   return NS_OK;
01666 }
01667 
01668 void nsTextControlFrame::PostCreateFrames() {
01669   InitEditor();
01670 }
01671 
01672 NS_IMETHODIMP
01673 nsTextControlFrame::CreateFrameFor(nsPresContext*   aPresContext,
01674                                        nsIContent *      aContent,
01675                                        nsIFrame**        aFrame)
01676 {
01677   *aFrame = nsnull;
01678   return NS_ERROR_FAILURE;
01679 }
01680 
01681 nsresult
01682 nsTextControlFrame::InitEditor()
01683 {
01684   // This method must be called during/after the text
01685   // control frame's initial reflow to avoid any unintened
01686   // forced reflows that might result when the editor
01687   // calls into DOM/layout code while trying to set the
01688   // initial string.
01689   //
01690   // This code used to be called from CreateAnonymousContent(),
01691   // but when the editor set the initial string, it would trigger
01692   // a PresShell listener which called FlushPendingNotifications()
01693   // during frame construction. This was causing other form controls
01694   // to display wrong values.
01695 
01696   // Check if this method has been called already.
01697   // If so, just return early.
01698 
01699   if (mUseEditor)
01700     return NS_OK;
01701 
01702   // If the editor is not here, then we can't use it, now can we?
01703   if (!mEditor)
01704     return NS_ERROR_NOT_INITIALIZED;
01705 
01706   // Get the current value of the textfield from the content.
01707   nsAutoString defaultValue;
01708   GetValue(defaultValue, PR_TRUE);
01709 
01710   // Turn on mUseEditor so that subsequent calls will use the
01711   // editor.
01712   mUseEditor = PR_TRUE;
01713 
01714   // If we have a default value, insert it under the div we created
01715   // above, but be sure to use the editor so that '*' characters get
01716   // displayed for password fields, etc. SetValue() will call the
01717   // editor for us.
01718 
01719   if (!defaultValue.IsEmpty()) {
01720     PRUint32 editorFlags = 0;
01721 
01722     nsresult rv = mEditor->GetFlags(&editorFlags);
01723 
01724     if (NS_FAILED(rv))
01725       return rv;
01726 
01727     // Avoid causing reentrant painting and reflowing by telling the editor
01728     // that we don't want it to force immediate view refreshes or force
01729     // immediate reflows during any editor calls.
01730 
01731     rv = mEditor->SetFlags(editorFlags |
01732                            nsIPlaintextEditor::eEditorUseAsyncUpdatesMask);
01733 
01734     if (NS_FAILED(rv))
01735       return rv;
01736 
01737     // Now call SetValue() which will make the necessary editor calls to set
01738     // the default value.  Make sure to turn off undo before setting the default
01739     // value, and turn it back on afterwards. This will make sure we can't undo
01740     // past the default value.
01741 
01742     rv = mEditor->EnableUndo(PR_FALSE);
01743 
01744     if (NS_FAILED(rv))
01745       return rv;
01746 
01747     SetValue(defaultValue);
01748 
01749     rv = mEditor->EnableUndo(PR_TRUE);
01750     NS_ASSERTION(NS_SUCCEEDED(rv),"Transaction Manager must have failed");
01751     // Now restore the original editor flags.
01752 
01753     rv = mEditor->SetFlags(editorFlags);
01754 
01755     if (NS_FAILED(rv))
01756       return rv;
01757   }
01758 
01759   nsCOMPtr<nsITransactionManager> transMgr;
01760   mEditor->GetTransactionManager(getter_AddRefs(transMgr));
01761   NS_ENSURE_TRUE(transMgr, NS_ERROR_FAILURE);
01762 
01763   transMgr->SetMaxTransactionCount(DEFAULT_UNDO_CAP);
01764 
01765   if (IsPasswordTextControl()) {
01766     // Disable undo for password textfields.  Note that we want to do this at
01767     // the very end of InitEditor, so the calls to EnableUndo when setting the
01768     // default value don't screw us up.
01769     // Since changing the control type does a reframe, we don't have to worry
01770     // about dynamic type changes here.
01771     mEditor->EnableUndo(PR_FALSE);
01772   }
01773 
01774   return NS_OK;
01775 }
01776 
01777 NS_IMETHODIMP
01778 nsTextControlFrame::CreateAnonymousContent(nsPresContext* aPresContext,
01779                                            nsISupportsArray& aChildList)
01780 {
01781   // Get the PresShell
01782 
01783   mState |= NS_FRAME_INDEPENDENT_SELECTION;
01784 
01785   nsIPresShell *shell = aPresContext->GetPresShell();
01786 
01787   if (!shell)
01788     return NS_ERROR_FAILURE;
01789 
01790   // Get the DOM document
01791 
01792   nsIDocument *doc = shell->GetDocument();
01793   if (!doc)
01794     return NS_ERROR_FAILURE;
01795 
01796   nsresult rv;
01797   nsCOMPtr<nsIDOMDocument> domdoc = do_QueryInterface(doc, &rv);
01798   if (NS_FAILED(rv))
01799     return rv;
01800   if (!domdoc)
01801     return NS_ERROR_FAILURE;
01802   
01803   // Now create a DIV and add it to the anonymous content child list.
01804   nsCOMPtr<nsINodeInfo> nodeInfo;
01805   rv = doc->NodeInfoManager()->GetNodeInfo(nsHTMLAtoms::div, nsnull,
01806                                            kNameSpaceID_XHTML,
01807                                            getter_AddRefs(nodeInfo));
01808 
01809   if (NS_FAILED(rv))
01810     return rv;
01811 
01812   if (!nodeInfo)
01813     return NS_ERROR_FAILURE;
01814 
01815   nsCOMPtr<nsIContent> divContent;
01816   rv = NS_NewHTMLElement(getter_AddRefs(divContent), nodeInfo);
01817 
01818   if (NS_FAILED(rv))
01819     return rv;
01820 
01821   if (!divContent)
01822     return NS_ERROR_FAILURE;
01823 
01824   // Set the div native anonymous, so CSS will be its style language
01825   // no matter what.
01826   divContent->SetNativeAnonymous(PR_TRUE);
01827 
01828   // Set the necessary style attributes on the text control.
01829 
01830   rv = divContent->SetAttr(kNameSpaceID_None, nsHTMLAtoms::kClass,
01831                            NS_LITERAL_STRING("anonymous-div"), PR_FALSE);
01832 
01833   if (!IsSingleLineTextControl()) {
01834     // We can't just inherit the overflow because setting visible overflow will
01835     // crash when the number of lines exceeds the height of the textarea and
01836     // setting -moz-hidden-unscrollable overflow (NS_STYLE_OVERFLOW_CLIP)
01837     // doesn't paint the caret for some reason.
01838     const nsStyleDisplay* disp = GetStyleDisplay();
01839     if (disp->mOverflowX != NS_STYLE_OVERFLOW_VISIBLE &&
01840         disp->mOverflowX != NS_STYLE_OVERFLOW_CLIP) {
01841       rv = divContent->SetAttr(kNameSpaceID_None, nsHTMLAtoms::style,
01842                                NS_LITERAL_STRING("overflow: inherit;"),
01843                                PR_FALSE);
01844     }
01845   }
01846 
01847   if (NS_FAILED(rv))
01848     return rv;
01849 
01850   // rv = divContent->SetAttr(kNameSpaceID_None,nsXULAtoms::debug, NS_LITERAL_STRING("true"), PR_FALSE);
01851   rv = aChildList.AppendElement(divContent);
01852 
01853   if (NS_FAILED(rv))
01854     return rv;
01855 
01856   // Create an editor
01857 
01858   mEditor = do_CreateInstance(kTextEditorCID, &rv);
01859   if (NS_FAILED(rv))
01860     return rv;
01861   if (!mEditor) 
01862     return NS_ERROR_OUT_OF_MEMORY;
01863 
01864   // Create selection
01865 
01866   nsCOMPtr<nsIFrameSelection> frameSel = do_CreateInstance(kFrameSelectionCID, &rv);
01867 
01868   // Create a SelectionController
01869 
01870   mTextSelImpl = new nsTextInputSelectionImpl(frameSel,shell,divContent);
01871   if (!mTextSelImpl)
01872     return NS_ERROR_OUT_OF_MEMORY;
01873   mTextListener = new nsTextInputListener();
01874   if (!mTextListener)
01875     return NS_ERROR_OUT_OF_MEMORY;
01876   mTextListener->SetFrame(this);
01877   mSelCon =  do_QueryInterface((nsISupports *)(nsISelectionController *)mTextSelImpl);//this will addref it once
01878   if (!mSelCon)
01879     return NS_ERROR_NO_INTERFACE;
01880   mSelCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
01881 
01882   // Setup the editor flags
01883 
01884   PRUint32 editorFlags = 0;
01885   if (IsPlainTextControl())
01886     editorFlags |= nsIPlaintextEditor::eEditorPlaintextMask;
01887   if (IsSingleLineTextControl())
01888     editorFlags |= nsIPlaintextEditor::eEditorSingleLineMask;
01889   if (IsPasswordTextControl())
01890     editorFlags |= nsIPlaintextEditor::eEditorPasswordMask;
01891 
01892   // All gfxtextcontrolframe2's are widgets
01893   editorFlags |= nsIPlaintextEditor::eEditorWidgetMask;
01894 
01895   // Use async reflow and painting for text widgets to improve
01896   // performance.
01897 
01898   // XXX: Using editor async updates exposes bugs 158782, 151882,
01899   //      and 165130, so we're disabling it for now, until they
01900   //      can be addressed.
01901   // editorFlags |= nsIPlaintextEditor::eEditorUseAsyncUpdatesMask;
01902 
01903   // Now initialize the editor.
01904   //
01905   // NOTE: Conversion of '\n' to <BR> happens inside the
01906   //       editor's Init() call.
01907 
01908   rv = mEditor->Init(domdoc, shell, divContent, mSelCon, editorFlags);
01909 
01910   if (NS_FAILED(rv))
01911     return rv;
01912 
01913   // Initialize the controller for the editor
01914 
01915   if (!SuppressEventHandlers(aPresContext))
01916   {
01917     nsCOMPtr<nsIControllers> controllers;
01918     nsCOMPtr<nsIDOMNSHTMLInputElement> inputElement = do_QueryInterface(mContent);
01919     if (inputElement)
01920       rv = inputElement->GetControllers(getter_AddRefs(controllers));
01921     else
01922     {
01923       nsCOMPtr<nsIDOMNSHTMLTextAreaElement> textAreaElement = do_QueryInterface(mContent);
01924 
01925       if (!textAreaElement)
01926         return NS_ERROR_FAILURE;
01927 
01928       rv = textAreaElement->GetControllers(getter_AddRefs(controllers));
01929     }
01930 
01931     if (NS_FAILED(rv))
01932       return rv;
01933 
01934     if (controllers)
01935     {
01936       PRUint32 numControllers;
01937       PRBool found = PR_FALSE;
01938       rv = controllers->GetControllerCount(&numControllers);
01939       for (PRUint32 i = 0; i < numControllers; i ++)
01940       {
01941         nsCOMPtr<nsIController> controller;
01942         rv = controllers->GetControllerAt(i, getter_AddRefs(controller));
01943         if (NS_SUCCEEDED(rv) && controller)
01944         {
01945           nsCOMPtr<nsIControllerContext> editController = do_QueryInterface(controller);
01946           if (editController)
01947           {
01948             editController->SetCommandContext(mEditor);
01949             found = PR_TRUE;
01950           }
01951         }
01952       }
01953       if (!found)
01954         rv = NS_ERROR_FAILURE;
01955     }
01956   }
01957 
01958   // Initialize the plaintext editor
01959   nsCOMPtr<nsIPlaintextEditor> textEditor(do_QueryInterface(mEditor));
01960   if (textEditor) {
01961     // Set up wrapping
01962     if (IsTextArea()) {
01963       // wrap=off means -1 for wrap width no matter what cols is
01964       nsFormControlHelper::nsHTMLTextWrap wrapProp;
01965       nsFormControlHelper::GetWrapPropertyEnum(mContent, wrapProp);
01966       if (wrapProp == nsFormControlHelper::eHTMLTextWrap_Off) {
01967         // do not wrap when wrap=off
01968         textEditor->SetWrapWidth(-1);
01969       } else {
01970         // Set wrapping normally otherwise
01971         textEditor->SetWrapWidth(GetCols());
01972       }
01973     } else {
01974       // Never wrap non-textareas
01975       textEditor->SetWrapWidth(-1);
01976     }
01977 
01978 
01979     // Set max text field length
01980     PRInt32 maxLength;
01981     rv = GetMaxLength(&maxLength);
01982     if (NS_CONTENT_ATTR_NOT_THERE != rv)
01983     { 
01984       textEditor->SetMaxTextLength(maxLength);
01985     }
01986   }
01987     
01988   // Get the caret and make it a selection listener.
01989 
01990   nsCOMPtr<nsISelection> domSelection;
01991   if (NS_SUCCEEDED(mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSelection))) && domSelection)
01992   {
01993     nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(domSelection));
01994     nsCOMPtr<nsICaret> caret;
01995     nsCOMPtr<nsISelectionListener> listener;
01996     if (NS_SUCCEEDED(shell->GetCaret(getter_AddRefs(caret))) && caret)
01997     {
01998       listener = do_QueryInterface(caret);
01999       if (listener)
02000       {
02001         selPriv->AddSelectionListener(listener);
02002       }
02003     }
02004 
02005     selPriv->AddSelectionListener(NS_STATIC_CAST(nsISelectionListener *, mTextListener));
02006   }
02007   
02008   if (mContent)
02009   {
02010     rv = mEditor->GetFlags(&editorFlags);
02011 
02012     if (NS_FAILED(rv))
02013       return rv;
02014 
02015     nsAutoString resultValue;
02016 
02017     // Check if the readonly attribute is set.
02018 
02019     rv = mContent->GetAttr(kNameSpaceID_None, nsHTMLAtoms::readonly, resultValue);
02020 
02021     if (NS_FAILED(rv))
02022       return rv;
02023 
02024     if (NS_CONTENT_ATTR_NOT_THERE != rv)
02025       editorFlags |= nsIPlaintextEditor::eEditorReadonlyMask;
02026 
02027     // Check if the disabled attribute is set.
02028 
02029     rv = mContent->GetAttr(kNameSpaceID_None, nsHTMLAtoms::disabled, resultValue);
02030 
02031     if (NS_FAILED(rv))
02032       return rv;
02033 
02034     if (NS_CONTENT_ATTR_NOT_THERE != rv) 
02035       editorFlags |= nsIPlaintextEditor::eEditorDisabledMask;
02036 
02037     // Disable the caret and selection if necessary.
02038 
02039     if (editorFlags & nsIPlaintextEditor::eEditorReadonlyMask ||
02040         editorFlags & nsIPlaintextEditor::eEditorDisabledMask)
02041     {
02042       if (mSelCon)
02043       {
02044          //do not turn caret enabled off at this time.  the caret will behave 
02045          //dependant on the focused frame it is in.  disabling it here has
02046          //an adverse affect on the browser in caret display mode or the editor
02047          //when a readonly/disabled text form is in the page. bug 141888
02048          //mSelCon->SetCaretEnabled(PR_FALSE);
02049 
02050         if (editorFlags & nsIPlaintextEditor::eEditorDisabledMask)
02051           mSelCon->SetDisplaySelection(nsISelectionController::SELECTION_OFF);
02052       }
02053 
02054       mEditor->SetFlags(editorFlags);
02055     }
02056   }
02057 
02058   return NS_OK;
02059 }
02060 
02061 NS_IMETHODIMP
02062 nsTextControlFrame::Reflow(nsPresContext*   aPresContext,
02063                                nsHTMLReflowMetrics&     aDesiredSize,
02064                                const nsHTMLReflowState& aReflowState,
02065                                nsReflowStatus&          aStatus)
02066 {
02067   DO_GLOBAL_REFLOW_COUNT("nsTextControlFrame", aReflowState.reason);
02068   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
02069 
02070   // make sure the the form registers itself on the initial/first reflow
02071   if (mState & NS_FRAME_FIRST_REFLOW) {
02072     nsFormControlFrame::RegUnRegAccessKey(aPresContext, this, PR_TRUE);
02073   }
02074 
02075   nsresult rv = nsStackFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus);
02076   if (NS_SUCCEEDED(rv))
02077   { // fix for bug 40596, width:auto means the control sets it's mMaxElementWidth to it's default width
02078     if (aDesiredSize.mComputeMEW)
02079     {
02080       const nsStylePosition* stylePosition = GetStylePosition();
02081       nsStyleUnit widthUnit = stylePosition->mWidth.GetUnit();
02082       if (eStyleUnit_Auto == widthUnit) {
02083         aDesiredSize.mMaxElementWidth = aDesiredSize.width;
02084       }
02085     }
02086   }
02087   return rv;
02088 }
02089 
02090 NS_IMETHODIMP
02091 nsTextControlFrame::Paint(nsPresContext*      aPresContext,
02092                               nsIRenderingContext& aRenderingContext,
02093                               const nsRect&        aDirtyRect,
02094                               nsFramePaintLayer    aWhichLayer,
02095                               PRUint32             aFlags)
02096 {
02097   PRBool isVisible;
02098   if (NS_SUCCEEDED(IsVisibleForPainting(aPresContext, aRenderingContext, PR_TRUE, &isVisible)) && !isVisible) {
02099     return NS_OK;
02100   }
02101   nsresult rv = NS_OK;
02102   if (aWhichLayer == NS_FRAME_PAINT_LAYER_FOREGROUND) {
02103     rv = nsStackFrame::Paint(aPresContext, aRenderingContext, aDirtyRect, NS_FRAME_PAINT_LAYER_BACKGROUND);
02104     if (NS_FAILED(rv)) return rv;
02105     rv = nsStackFrame::Paint(aPresContext, aRenderingContext, aDirtyRect, NS_FRAME_PAINT_LAYER_FLOATS);
02106     if (NS_FAILED(rv)) return rv;
02107     rv = nsStackFrame::Paint(aPresContext, aRenderingContext, aDirtyRect, NS_FRAME_PAINT_LAYER_FOREGROUND);
02108   }
02109   DO_GLOBAL_REFLOW_COUNT_DSP("nsTextControlFrame", &aRenderingContext);
02110   return rv;
02111 }
02112 
02113 NS_IMETHODIMP
02114 nsTextControlFrame::GetFrameForPoint(const nsPoint& aPoint,
02115                                          nsFramePaintLayer aWhichLayer,
02116                                          nsIFrame** aFrame)
02117 {
02118   nsresult rv = NS_ERROR_FAILURE;
02119   if (aWhichLayer == NS_FRAME_PAINT_LAYER_FOREGROUND) {
02120     rv = nsStackFrame::GetFrameForPoint(aPoint,
02121                                       NS_FRAME_PAINT_LAYER_FOREGROUND, aFrame);
02122     if (NS_SUCCEEDED(rv))
02123       return NS_OK;
02124     rv = nsStackFrame::GetFrameForPoint(aPoint,
02125                                         NS_FRAME_PAINT_LAYER_FLOATS, aFrame);
02126     if (NS_SUCCEEDED(rv))
02127       return NS_OK;
02128     rv = nsStackFrame::GetFrameForPoint(aPoint,
02129                                       NS_FRAME_PAINT_LAYER_BACKGROUND, aFrame);
02130   }
02131   return rv;
02132 }
02133 
02134 NS_IMETHODIMP
02135 nsTextControlFrame::GetPrefSize(nsBoxLayoutState& aState, nsSize& aSize)
02136 {
02137   if (!DoesNeedRecalc(mPrefSize)) {
02138      aSize = mPrefSize;
02139      return NS_OK;
02140   }
02141 
02142 #ifdef DEBUG_LAYOUT
02143   PropagateDebug(aState);
02144 #endif
02145 
02146   aSize.width = 0;
02147   aSize.height = 0;
02148 
02149   PRBool collapsed = PR_FALSE;
02150   IsCollapsed(aState, collapsed);
02151   if (collapsed)
02152     return NS_OK;
02153 
02154   nsPresContext* presContext = aState.PresContext();
02155   const nsHTMLReflowState* reflowState = aState.GetReflowState();
02156   // XXXldb Is there a good reason to think this is both non-null and the
02157   // correct reflow state?
02158   if (!reflowState)
02159     return NS_OK;
02160 
02161   nsSize styleSize(CSS_NOTSET,CSS_NOTSET);
02162   nsFormControlFrame::GetStyleSize(presContext, *reflowState, styleSize);
02163 
02164   nsReflowStatus status;
02165   nsresult rv = ReflowStandard(presContext, aSize, *reflowState, status);
02166   NS_ENSURE_SUCCESS(rv, rv);
02167   AddInset(aSize);
02168 
02169   mPrefSize = aSize;
02170 
02171 #ifdef DEBUG_rods
02172   {
02173     nsMargin borderPadding(0,0,0,0);
02174     GetBorderAndPadding(borderPadding);
02175     nsSize size(169, 24);
02176     nsSize actual(aSize.width/15, 
02177                   aSize.height/15);
02178     printf("nsGfxText(field) %d,%d  %d,%d  %d,%d\n", 
02179            size.width, size.height, actual.width, actual.height, actual.width-size.width, actual.height-size.height);  // text field
02180   }
02181 #endif
02182 
02183   return NS_OK;
02184 }
02185 
02186 
02187 
02188 NS_IMETHODIMP
02189 nsTextControlFrame::GetMinSize(nsBoxLayoutState& aState, nsSize& aSize)
02190 {
02191 #define FIX_FOR_BUG_40596
02192 #ifdef FIX_FOR_BUG_40596
02193   aSize = mMinSize;
02194   return NS_OK;
02195 #else
02196   return nsBox::GetMinSize(aState, aSize);
02197 #endif
02198 }
02199 
02200 NS_IMETHODIMP
02201 nsTextControlFrame::GetMaxSize(nsBoxLayoutState& aState, nsSize& aSize)
02202 {
02203   return nsBox::GetMaxSize(aState, aSize);
02204 }
02205 
02206 NS_IMETHODIMP
02207 nsTextControlFrame::GetAscent(nsBoxLayoutState& aState, nscoord& aAscent)
02208 {
02209   // First calculate the ascent of the text inside
02210   nsresult rv = nsStackFrame::GetAscent(aState, aAscent);
02211   NS_ENSURE_SUCCESS(rv, rv);
02212     
02213   // Now adjust the ascent for our borders and padding
02214   aAscent += aState.GetReflowState()->mComputedBorderPadding.top;
02215   
02216   return NS_OK;
02217 }
02218 
02219 PRBool
02220 nsTextControlFrame::IsLeaf() const
02221 {
02222   return PR_TRUE;
02223 }
02224 
02225 //IMPLEMENTING NS_IFORMCONTROLFRAME
02226 NS_IMETHODIMP
02227 nsTextControlFrame::GetName(nsAString* aResult)
02228 {
02229   return nsFormControlHelper::GetName(mContent, aResult);
02230 }
02231 
02232 NS_IMETHODIMP_(PRInt32)
02233 nsTextControlFrame::GetFormControlType() const
02234 {
02235   return nsFormControlHelper::GetType(mContent);
02236 }
02237 
02238 static PRBool
02239 IsFocusedContent(nsPresContext* aPresContext, nsIContent* aContent)
02240 {
02241   nsCOMPtr<nsIContent> focusedContent;
02242   aPresContext->EventStateManager()->
02243     GetFocusedContent(getter_AddRefs(focusedContent));
02244   return focusedContent == aContent;
02245 }
02246 
02247 void    nsTextControlFrame::SetFocus(PRBool aOn, PRBool aRepaint)
02248 {
02249   if (!aOn || !mSelCon)
02250     return;
02251 
02252   // onfocus="some_where_else.focus()" can trigger several focus
02253   // in succession. Here, we only care if we are the winner.
02254   // @see also nsTextEditorFocusListener::Focus()
02255   if (!IsFocusedContent(GetPresContext(), mContent))
02256     return;
02257 
02258   // tell the caret to use our selection
02259 
02260   nsCOMPtr<nsISelection> ourSel;
02261   mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL, 
02262     getter_AddRefs(ourSel));
02263   if (!ourSel) return;
02264 
02265   nsIPresShell* presShell = GetPresContext()->GetPresShell();
02266   nsCOMPtr<nsICaret> caret;
02267   presShell->GetCaret(getter_AddRefs(caret));
02268   if (!caret) return;
02269   caret->SetCaretDOMSelection(ourSel);
02270 
02271   // mutual-exclusion: the selection is either controlled by the
02272   // document or by the text input/area. Clear any selection in the
02273   // document since the focus is now on our independent selection.
02274 
02275   nsCOMPtr<nsISelectionController> selCon(do_QueryInterface(presShell));
02276   nsCOMPtr<nsISelection> docSel;
02277   selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
02278     getter_AddRefs(docSel));
02279   if (!docSel) return;
02280 
02281   PRBool isCollapsed = PR_FALSE;
02282   docSel->GetIsCollapsed(&isCollapsed);
02283   if (!isCollapsed)
02284     docSel->RemoveAllRanges();
02285 }
02286 
02287 void    nsTextControlFrame::ScrollIntoView(nsPresContext* aPresContext)
02288 {
02289   if (aPresContext) {
02290     nsIPresShell *presShell = aPresContext->GetPresShell();
02291     if (presShell) {
02292       presShell->ScrollFrameIntoView(this,
02293                    NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE,NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE);
02294     }
02295   }
02296 }
02297 
02298 nscoord 
02299 nsTextControlFrame::GetVerticalInsidePadding(nsPresContext* aPresContext,
02300                                              float aPixToTwip, 
02301                                              nscoord aInnerHeight) const
02302 {
02303    return NSIntPixelsToTwips(0, aPixToTwip); 
02304 }
02305 
02306 
02307 //---------------------------------------------------------
02308 nscoord 
02309 nsTextControlFrame::GetHorizontalInsidePadding(nsPresContext* aPresContext,
02310                                                float aPixToTwip, 
02311                                                nscoord aInnerWidth,
02312                                                nscoord aCharWidth) const
02313 {
02314   return GetVerticalInsidePadding(aPresContext, aPixToTwip, aInnerWidth);
02315 }
02316 
02317 
02318 NS_IMETHODIMP 
02319 nsTextControlFrame::SetSuggestedSize(nscoord aWidth, nscoord aHeight)
02320 {
02321   mSuggestedWidth = aWidth;
02322   mSuggestedHeight = aHeight;
02323   return NS_OK;
02324 }
02325 
02326 NS_IMETHODIMP
02327 nsTextControlFrame::GetFormContent(nsIContent*& aContent) const
02328 {
02329   aContent = GetContent();
02330   NS_IF_ADDREF(aContent);
02331   return NS_OK;
02332 }
02333 
02334 NS_IMETHODIMP nsTextControlFrame::SetProperty(nsPresContext* aPresContext, nsIAtom* aName, const nsAString& aValue)
02335 {
02336   if (!mIsProcessing)//some kind of lock.
02337   {
02338     mIsProcessing = PR_TRUE;
02339     
02340     if (nsHTMLAtoms::value == aName) 
02341     {
02342       if (mEditor && mUseEditor) {
02343         // If the editor exists, the control needs to be informed that the value
02344         // has changed.
02345         SetValueChanged(PR_TRUE);
02346       }
02347       nsresult rv = SetValue(aValue);   // set new text value
02348       NS_ENSURE_SUCCESS(rv, rv);
02349     }
02350     else if (nsHTMLAtoms::select == aName && mSelCon)
02351     {
02352       // Select all the text.
02353       //
02354       // XXX: This is lame, we can't call mEditor->SelectAll()
02355       //      because that triggers AutoCopies in unix builds.
02356       //      Instead, we have to call our own homegrown version
02357       //      of select all which merely builds a range that selects
02358       //      all of the content and adds that to the selection.
02359 
02360       SelectAllContents();
02361     }
02362     mIsProcessing = PR_FALSE;
02363   }
02364   return NS_OK;
02365 }      
02366 
02367 NS_IMETHODIMP
02368 nsTextControlFrame::GetProperty(nsIAtom* aName, nsAString& aValue)
02369 {
02370   // Return the value of the property from the widget it is not null.
02371   // If widget is null, assume the widget is GFX-rendered and return a member variable instead.
02372 
02373   if (nsHTMLAtoms::value == aName) {
02374     GetValue(aValue, PR_FALSE);
02375   }
02376   return NS_OK;
02377 }  
02378 
02379 
02380 
02381 NS_IMETHODIMP
02382 nsTextControlFrame::GetEditor(nsIEditor **aEditor)
02383 {
02384   NS_ENSURE_ARG_POINTER(aEditor);
02385   *aEditor = mEditor;
02386   NS_IF_ADDREF(*aEditor);
02387   return NS_OK;
02388 }
02389 
02390 NS_IMETHODIMP
02391 nsTextControlFrame::OwnsValue(PRBool* aOwnsValue)
02392 {
02393   NS_PRECONDITION(aOwnsValue, "aOwnsValue must be non-null");
02394   *aOwnsValue = mUseEditor;
02395   return NS_OK;
02396 }
02397 
02398 NS_IMETHODIMP
02399 nsTextControlFrame::GetTextLength(PRInt32* aTextLength)
02400 {
02401   NS_ENSURE_ARG_POINTER(aTextLength);
02402 
02403   nsAutoString   textContents;
02404   GetValue(textContents, PR_FALSE);   // this is expensive!
02405   *aTextLength = textContents.Length();
02406   return NS_OK;
02407 }
02408 
02409 nsresult
02410 nsTextControlFrame::SetSelectionInternal(nsIDOMNode *aStartNode,
02411                                          PRInt32 aStartOffset,
02412                                          nsIDOMNode *aEndNode,
02413                                          PRInt32 aEndOffset)
02414 {
02415   // Create a new range to represent the new selection.
02416   // Note that we use a new range to avoid having to do
02417   // isIncreasing checks to avoid possible errors.
02418 
02419   nsCOMPtr<nsIDOMRange> range = do_CreateInstance(kRangeCID);
02420   NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
02421 
02422   nsresult rv = range->SetStart(aStartNode, aStartOffset);
02423   NS_ENSURE_SUCCESS(rv, rv);
02424 
02425   rv = range->SetEnd(aEndNode, aEndOffset);
02426   NS_ENSURE_SUCCESS(rv, rv);
02427 
02428   // Get the selection, clear it and add the new range to it!
02429 
02430   nsCOMPtr<nsISelection> selection;
02431   mTextSelImpl->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));  
02432   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
02433 
02434   rv = selection->RemoveAllRanges();  
02435 
02436   NS_ENSURE_SUCCESS(rv, rv);
02437 
02438   return selection->AddRange(range);
02439 }
02440 
02441 nsresult
02442 nsTextControlFrame::SelectAllContents()
02443 {
02444   if (!mEditor)
02445     return NS_OK;
02446 
02447   nsCOMPtr<nsIDOMElement> rootElement;
02448   nsresult rv = mEditor->GetRootElement(getter_AddRefs(rootElement));
02449   NS_ENSURE_SUCCESS(rv, rv);
02450 
02451   nsCOMPtr<nsIContent> rootContent = do_QueryInterface(rootElement);
02452   PRInt32 numChildren = rootContent->GetChildCount();
02453 
02454   if (numChildren > 0) {
02455     // We never want to place the selection after the last
02456     // br under the root node!
02457     nsIContent *child = rootContent->GetChildAt(numChildren - 1);
02458     if (child) {
02459       if (child->Tag() == nsHTMLAtoms::br)
02460         --numChildren;
02461     }
02462   }
02463 
02464   nsCOMPtr<nsIDOMNode> rootNode(do_QueryInterface(rootElement));
02465 
02466   return SetSelectionInternal(rootNode, 0, rootNode, numChildren);
02467 }
02468 
02469 nsresult
02470 nsTextControlFrame::SetSelectionEndPoints(PRInt32 aSelStart, PRInt32 aSelEnd)
02471 {
02472   NS_ASSERTION(aSelStart <= aSelEnd, "Invalid selection offsets!");
02473 
02474   if (aSelStart > aSelEnd)
02475     return NS_ERROR_FAILURE;
02476 
02477   nsCOMPtr<nsIDOMNode> startNode, endNode;
02478   PRInt32 startOffset, endOffset;
02479 
02480   // Calculate the selection start point.
02481 
02482   nsresult rv = OffsetToDOMPoint(aSelStart, getter_AddRefs(startNode), &startOffset);
02483 
02484   NS_ENSURE_SUCCESS(rv, rv);
02485 
02486   if (aSelStart == aSelEnd) {
02487     // Collapsed selection, so start and end are the same!
02488     endNode   = startNode;
02489     endOffset = startOffset;
02490   }
02491   else {
02492     // Selection isn't collapsed so we have to calculate
02493     // the end point too.
02494 
02495     rv = OffsetToDOMPoint(aSelEnd, getter_AddRefs(endNode), &endOffset);
02496 
02497     NS_ENSURE_SUCCESS(rv, rv);
02498   }
02499 
02500   return SetSelectionInternal(startNode, startOffset, endNode, endOffset);
02501 }
02502 
02503 NS_IMETHODIMP
02504 nsTextControlFrame::SetSelectionRange(PRInt32 aSelStart, PRInt32 aSelEnd)
02505 {
02506   NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_INITIALIZED);
02507   
02508   if (aSelStart > aSelEnd) {
02509     // Simulate what we'd see SetSelectionStart() was called, followed
02510     // by a SetSelectionEnd().
02511 
02512     aSelStart   = aSelEnd;
02513   }
02514 
02515   return SetSelectionEndPoints(aSelStart, aSelEnd);
02516 }
02517 
02518 
02519 NS_IMETHODIMP
02520 nsTextControlFrame::SetSelectionStart(PRInt32 aSelectionStart)
02521 {
02522   NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_INITIALIZED);
02523 
02524   PRInt32 selStart = 0, selEnd = 0; 
02525 
02526   nsresult rv = GetSelectionRange(&selStart, &selEnd);
02527   NS_ENSURE_SUCCESS(rv, rv);
02528 
02529   if (aSelectionStart > selEnd) {
02530     // Collapse to the new start point.
02531     selEnd = aSelectionStart; 
02532   }
02533 
02534   selStart = aSelectionStart;
02535   
02536   return SetSelectionEndPoints(selStart, selEnd);
02537 }
02538 
02539 NS_IMETHODIMP
02540 nsTextControlFrame::SetSelectionEnd(PRInt32 aSelectionEnd)
02541 {
02542   NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_INITIALIZED);
02543   
02544   PRInt32 selStart = 0, selEnd = 0; 
02545 
02546   nsresult rv = GetSelectionRange(&selStart, &selEnd);
02547   NS_ENSURE_SUCCESS(rv, rv);
02548 
02549   if (aSelectionEnd < selStart) {
02550     // Collapse to the new end point.
02551     selStart = aSelectionEnd; 
02552   }
02553 
02554   selEnd = aSelectionEnd;
02555   
02556   return SetSelectionEndPoints(selStart, selEnd);
02557 }
02558 
02559 nsresult
02560 nsTextControlFrame::DOMPointToOffset(nsIDOMNode* aNode,
02561                                      PRInt32 aNodeOffset,
02562                                      PRInt32* aResult)
02563 {
02564   NS_ENSURE_ARG_POINTER(aNode && aResult);
02565 
02566   *aResult = 0;
02567 
02568   nsCOMPtr<nsIDOMElement> rootElement;
02569   mEditor->GetRootElement(getter_AddRefs(rootElement));
02570   nsCOMPtr<nsIDOMNode> rootNode(do_QueryInterface(rootElement));
02571 
02572   NS_ENSURE_TRUE(rootNode, NS_ERROR_FAILURE);
02573 
02574   nsCOMPtr<nsIDOMNodeList> nodeList;
02575 
02576   nsresult rv = rootNode->GetChildNodes(getter_AddRefs(nodeList));
02577   NS_ENSURE_SUCCESS(rv, rv);
02578   NS_ENSURE_TRUE(nodeList, NS_ERROR_FAILURE);
02579 
02580   PRUint32 length = 0;
02581   rv = nodeList->GetLength(&length);
02582   NS_ENSURE_SUCCESS(rv, rv);
02583 
02584   if (!length || aNodeOffset < 0)
02585     return NS_OK;
02586 
02587   PRInt32 i, textOffset = 0;
02588   PRInt32 lastIndex = (PRInt32)length - 1;
02589 
02590   for (i = 0; i < (PRInt32)length; i++) {
02591     if (rootNode == aNode && i == aNodeOffset) {
02592       *aResult = textOffset;
02593       return NS_OK;
02594     }
02595 
02596     nsCOMPtr<nsIDOMNode> item;
02597     rv = nodeList->Item(i, getter_AddRefs(item));
02598     NS_ENSURE_SUCCESS(rv, rv);
02599     NS_ENSURE_TRUE(item, NS_ERROR_FAILURE);
02600 
02601     nsCOMPtr<nsIDOMText> domText(do_QueryInterface(item));
02602 
02603     if (domText) {
02604       PRUint32 textLength = 0;
02605 
02606       rv = domText->GetLength(&textLength);
02607       NS_ENSURE_SUCCESS(rv, rv);
02608 
02609       if (item == aNode) {
02610         NS_ASSERTION((aNodeOffset >= 0 && aNodeOffset <= (PRInt32)textLength),
02611                      "Invalid aNodeOffset!");
02612         *aResult = textOffset + aNodeOffset;
02613         return NS_OK;
02614       }
02615 
02616       textOffset += textLength;
02617     }
02618     else {
02619       // Must be a BR node. If it's not the last BR node
02620       // under the root, count it as a newline.
02621 
02622       if (i != lastIndex)
02623         ++textOffset;
02624     }
02625   }
02626 
02627   NS_ASSERTION((aNode == rootNode && aNodeOffset == (PRInt32)length),
02628                "Invalide node offset!");
02629 
02630   *aResult = textOffset;
02631   
02632   return NS_OK;
02633 }
02634 
02635 nsresult
02636 nsTextControlFrame::OffsetToDOMPoint(PRInt32 aOffset,
02637                                      nsIDOMNode** aResult,
02638                                      PRInt32* aPosition)
02639 {
02640   NS_ENSURE_ARG_POINTER(aResult && aPosition);
02641 
02642   *aResult = nsnull;
02643   *aPosition = 0;
02644 
02645   nsCOMPtr<nsIDOMElement> rootElement;
02646   mEditor->GetRootElement(getter_AddRefs(rootElement));
02647   nsCOMPtr<nsIDOMNode> rootNode(do_QueryInterface(rootElement));
02648 
02649   NS_ENSURE_TRUE(rootNode, NS_ERROR_FAILURE);
02650 
02651   nsCOMPtr<nsIDOMNodeList> nodeList;
02652 
02653   nsresult rv = rootNode->GetChildNodes(getter_AddRefs(nodeList));
02654   NS_ENSURE_SUCCESS(rv, rv);
02655   NS_ENSURE_TRUE(nodeList, NS_ERROR_FAILURE);
02656 
02657   PRUint32 length = 0;
02658 
02659   rv = nodeList->GetLength(&length);
02660   NS_ENSURE_SUCCESS(rv, rv);
02661 
02662   if (!length || aOffset < 0) {
02663     *aPosition = 0;
02664     *aResult = rootNode;
02665     NS_ADDREF(*aResult);
02666     return NS_OK;
02667   }
02668 
02669   PRInt32 textOffset = 0;
02670   PRUint32 lastIndex = length - 1;
02671 
02672   for (PRUint32 i=0; i<length; i++) {
02673     nsCOMPtr<nsIDOMNode> item;
02674     rv = nodeList->Item(i, getter_AddRefs(item));
02675     NS_ENSURE_SUCCESS(rv, rv);
02676     NS_ENSURE_TRUE(item, NS_ERROR_FAILURE);
02677 
02678     nsCOMPtr<nsIDOMText> domText(do_QueryInterface(item));
02679 
02680     if (domText) {
02681       PRUint32 textLength = 0;
02682 
02683       rv = domText->GetLength(&textLength);
02684       NS_ENSURE_SUCCESS(rv, rv);
02685 
02686       // Check if aOffset falls within this range.
02687       if (aOffset >= textOffset && aOffset <= textOffset+(PRInt32)textLength) {
02688         *aPosition = aOffset - textOffset;
02689         *aResult = item;
02690         NS_ADDREF(*aResult);
02691         return NS_OK;
02692       }
02693 
02694       textOffset += textLength;
02695 
02696       // If there aren't any more siblings after this text node,
02697       // return the point at the end of this text node!
02698 
02699       if (i == lastIndex) {
02700         *aPosition = textLength;
02701         *aResult = item;
02702         NS_ADDREF(*aResult);
02703         return NS_OK;
02704       }
02705     }
02706     else {
02707       // Must be a BR node, count it as a newline.
02708 
02709       if (aOffset == textOffset || i == lastIndex) {
02710         // We've found the correct position, or aOffset takes us
02711         // beyond the last child under rootNode, just return the point
02712         // under rootNode that is in front of this br.
02713 
02714         *aPosition = i;
02715         *aResult = rootNode;
02716         NS_ADDREF(*aResult);
02717         return NS_OK;
02718       }
02719 
02720       ++textOffset;
02721     }
02722   }
02723 
02724   NS_ASSERTION(0, "We should never get here!");
02725 
02726   return NS_ERROR_FAILURE;
02727 }
02728 
02729 NS_IMETHODIMP
02730 nsTextControlFrame::GetSelectionRange(PRInt32* aSelectionStart, PRInt32* aSelectionEnd)
02731 {
02732   // make sure we have an editor
02733   NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_INITIALIZED);
02734 
02735   *aSelectionStart = 0;
02736   *aSelectionEnd = 0;
02737 
02738   nsCOMPtr<nsISelection> selection;
02739   nsresult rv = mTextSelImpl->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));  
02740   NS_ENSURE_SUCCESS(rv, rv);
02741   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
02742 
02743   PRInt32 numRanges = 0;
02744   selection->GetRangeCount(&numRanges);
02745 
02746   if (numRanges < 1)
02747     return NS_OK;
02748 
02749   // We only operate on the first range in the selection!
02750 
02751   nsCOMPtr<nsIDOMRange> firstRange;
02752   rv = selection->GetRangeAt(0, getter_AddRefs(firstRange));
02753   NS_ENSURE_SUCCESS(rv, rv);
02754   NS_ENSURE_TRUE(firstRange, NS_ERROR_FAILURE);
02755 
02756   nsCOMPtr<nsIDOMNode> startNode, endNode;
02757   PRInt32 startOffset = 0, endOffset = 0;
02758 
02759   // Get the start point of the range.
02760 
02761   rv = firstRange->GetStartContainer(getter_AddRefs(startNode));
02762   NS_ENSURE_SUCCESS(rv, rv);
02763   NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
02764 
02765   rv = firstRange->GetStartOffset(&startOffset);
02766   NS_ENSURE_SUCCESS(rv, rv);
02767 
02768   // Get the end point of the range.
02769 
02770   rv = firstRange->GetEndContainer(getter_AddRefs(endNode));
02771   NS_ENSURE_SUCCESS(rv, rv);
02772   NS_ENSURE_TRUE(endNode, NS_ERROR_FAILURE);
02773 
02774   rv = firstRange->GetEndOffset(&endOffset);
02775   NS_ENSURE_SUCCESS(rv, rv);
02776 
02777   // Convert the start point to a selection offset.
02778 
02779   rv = DOMPointToOffset(startNode, startOffset, aSelectionStart);
02780   NS_ENSURE_SUCCESS(rv, rv);
02781 
02782   // Convert the end point to a selection offset.
02783 
02784   return DOMPointToOffset(endNode, endOffset, aSelectionEnd);
02785 }
02786 
02787 
02788 NS_IMETHODIMP
02789 nsTextControlFrame::GetSelectionContr(nsISelectionController **aSelCon)
02790 {
02791   NS_ENSURE_ARG_POINTER(aSelCon);
02792   NS_IF_ADDREF(*aSelCon = mSelCon);
02793   return NS_OK;
02794 }
02795 
02796 
02798 
02800 NS_IMETHODIMP
02801 nsTextControlFrame::AttributeChanged(nsIContent*     aChild,
02802                                      PRInt32         aNameSpaceID,
02803                                      nsIAtom*        aAttribute,
02804                                      PRInt32         aModType)
02805 {
02806   if (!mEditor || !mSelCon) {return NS_ERROR_NOT_INITIALIZED;}
02807   nsresult rv = NS_OK;
02808 
02809   if (nsHTMLAtoms::maxlength == aAttribute) 
02810   {
02811     PRInt32 maxLength;
02812     rv = GetMaxLength(&maxLength);
02813     
02814     nsCOMPtr<nsIPlaintextEditor> textEditor = do_QueryInterface(mEditor);
02815     if (textEditor)
02816     {
02817       if (NS_CONTENT_ATTR_NOT_THERE != rv) 
02818       {  // set the maxLength attribute
02819           textEditor->SetMaxTextLength(maxLength);
02820         // if maxLength>docLength, we need to truncate the doc content
02821       }
02822       else { // unset the maxLength attribute
02823           textEditor->SetMaxTextLength(-1);
02824       }
02825     }
02826     rv = NS_OK; // don't propagate the error
02827   } 
02828   else if (mEditor && nsHTMLAtoms::readonly == aAttribute) 
02829   {
02830     PRUint32 flags;
02831     mEditor->GetFlags(&flags);
02832     if (AttributeExists(nsHTMLAtoms::readonly))
02833     { // set readonly
02834       flags |= nsIPlaintextEditor::eEditorReadonlyMask;
02835       if (mSelCon && IsFocusedContent(GetPresContext(), mContent))
02836         mSelCon->SetCaretEnabled(PR_FALSE);
02837     }
02838     else 
02839     { // unset readonly
02840       flags &= ~(nsIPlaintextEditor::eEditorReadonlyMask);
02841       if (mSelCon && !(flags & nsIPlaintextEditor::eEditorDisabledMask) &&
02842           IsFocusedContent(GetPresContext(), mContent))
02843         mSelCon->SetCaretEnabled(PR_TRUE);
02844     }    
02845     mEditor->SetFlags(flags);
02846   }
02847   else if (mEditor && nsHTMLAtoms::disabled == aAttribute) 
02848   {
02849     // XXXbryner do we need to check for a null presshell here?
02850     //           we don't do anything with it.
02851     nsIPresShell *shell = GetPresContext()->GetPresShell();
02852     if (!shell)
02853       return NS_ERROR_FAILURE;
02854 
02855     PRUint32 flags;
02856     mEditor->GetFlags(&flags);
02857     if (AttributeExists(nsHTMLAtoms::disabled))
02858     { // set disabled
02859       flags |= nsIPlaintextEditor::eEditorDisabledMask;
02860       if (mSelCon)
02861       {
02862         mSelCon->SetDisplaySelection(nsISelectionController::SELECTION_OFF);
02863         if (IsFocusedContent(GetPresContext(), mContent))
02864           mSelCon->SetCaretEnabled(PR_FALSE);
02865       }
02866     }
02867     else 
02868     { // unset disabled
02869       flags &= ~(nsIPlaintextEditor::eEditorDisabledMask);
02870       if (mSelCon)
02871       {
02872         mSelCon->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN);
02873       }
02874     }    
02875     mEditor->SetFlags(flags);
02876   }
02877   // Allow the base class to handle common attributes supported
02878   // by all form elements... 
02879   else {
02880     rv = nsBoxFrame::AttributeChanged(aChild, aNameSpaceID, aAttribute, aModType);
02881   }
02882 
02883   return rv;
02884 }
02885 
02886 
02887 NS_IMETHODIMP
02888 nsTextControlFrame::GetText(nsString* aText)
02889 {
02890   nsresult rv = NS_CONTENT_ATTR_NOT_THERE;
02891   if (IsSingleLineTextControl()) {
02892     // If we're going to remove newlines anyway, ignore the wrap property
02893     GetValue(*aText, PR_TRUE);
02894     RemoveNewlines(*aText);
02895   } else {
02896     nsCOMPtr<nsIDOMHTMLTextAreaElement> textArea = do_QueryInterface(mContent);
02897     if (textArea) {
02898       if (mEditor) {
02899         nsCOMPtr<nsIEditorIMESupport> imeSupport = do_QueryInterface(mEditor);
02900         if (imeSupport)
02901           imeSupport->ForceCompositionEnd();
02902       }
02903       rv = textArea->GetValue(*aText);
02904     }
02905   }
02906   return rv;
02907 }
02908 
02909 
02910 NS_IMETHODIMP
02911 nsTextControlFrame::GetPhonetic(nsAString& aPhonetic)
02912 {
02913   aPhonetic.Truncate(0); 
02914   if (!mEditor)
02915     return NS_ERROR_NOT_INITIALIZED;
02916   nsCOMPtr<nsIEditorIMESupport> imeSupport = do_QueryInterface(mEditor);
02917   if (imeSupport) {
02918     nsCOMPtr<nsIPhonetic> phonetic = do_QueryInterface(imeSupport);
02919     if (phonetic)
02920       phonetic->GetPhonetic(aPhonetic);
02921   }
02922   return NS_OK;
02923 }
02924 
02927 
02928 void nsTextControlFrame::RemoveNewlines(nsString &aString)
02929 {
02930   // strip CR/LF and null
02931   static const char badChars[] = {10, 13, 0};
02932   aString.StripChars(badChars);
02933 }
02934 
02935 
02936 nsresult
02937 nsTextControlFrame::GetMaxLength(PRInt32* aSize)
02938 {
02939   *aSize = -1;
02940 
02941   nsGenericHTMLElement *content = nsGenericHTMLElement::FromContent(mContent);
02942   if (content) {
02943     const nsAttrValue* attr = content->GetParsedAttr(nsHTMLAtoms::maxlength);
02944     if (attr && attr->Type() == nsAttrValue::eInteger) {
02945       *aSize = attr->GetIntegerValue();
02946 
02947       return NS_CONTENT_ATTR_HAS_VALUE;
02948     }
02949   }
02950   return NS_CONTENT_ATTR_NOT_THERE;
02951 }
02952 
02953 // this is where we propagate a content changed event
02954 void
02955 nsTextControlFrame::FireOnInput()
02956 {
02957   NS_ASSERTION(mContent, "illegal to call unless we map to a content node");
02958 
02959   if (!mNotifyOnInput) { 
02960     return; // if notification is turned off, do nothing
02961   } 
02962   
02963   // Dispatch the "input" event
02964   nsEventStatus status = nsEventStatus_eIgnore;
02965   nsUIEvent event(PR_TRUE, NS_FORM_INPUT, 0);
02966 
02967   // Have the content handle the event, propagating it according to normal
02968   // DOM rules.
02969   nsWeakPtr &shell = mTextSelImpl->GetPresShell();
02970   nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(shell);
02971   NS_ASSERTION(presShell, "No pres shell");
02972   if (!presShell) {
02973     return;
02974   }
02975 
02976   presShell->HandleEventWithTarget(&event, nsnull, mContent,
02977                                    NS_EVENT_FLAG_INIT, &status); 
02978 }
02979 
02980 nsresult
02981 nsTextControlFrame::InitFocusedValue()
02982 {
02983   return GetText(&mFocusedValue);
02984 }
02985 
02986 NS_IMETHODIMP
02987 nsTextControlFrame::CheckFireOnChange()
02988 {
02989   nsString value;
02990   GetText(&value);
02991   if (!mFocusedValue.Equals(value))//different fire onchange
02992   {
02993     mFocusedValue = value;
02994     FireOnChange();
02995   }
02996   return NS_OK;
02997 }
02998 
02999 nsresult
03000 nsTextControlFrame::FireOnChange()
03001 {
03002   // Dispatch th1e change event
03003   nsCOMPtr<nsIContent> content;
03004   if (NS_SUCCEEDED(GetFormContent(*getter_AddRefs(content))))
03005   {
03006     nsEventStatus status = nsEventStatus_eIgnore;
03007     nsInputEvent event(PR_TRUE, NS_FORM_CHANGE, nsnull);
03008 
03009     // Have the content handle the event.
03010     nsWeakPtr &shell = mTextSelImpl->GetPresShell();
03011     nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(shell);
03012     NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
03013     return presShell->HandleEventWithTarget(&event, nsnull, mContent, NS_EVENT_FLAG_INIT, &status); 
03014   }
03015   return NS_OK;
03016 }
03017 
03018 
03019 //======
03020 //privates
03021 
03022 NS_IMETHODIMP
03023 nsTextControlFrame::GetValue(nsAString& aValue, PRBool aIgnoreWrap)
03024 {
03025   aValue.Truncate();  // initialize out param
03026   nsresult rv = NS_OK;
03027   
03028   if (mEditor && mUseEditor) 
03029   {
03030     PRUint32 flags = nsIDocumentEncoder::OutputLFLineBreak;;
03031 
03032     if (PR_TRUE==IsPlainTextControl())
03033     {
03034       flags |= nsIDocumentEncoder::OutputBodyOnly;
03035     }
03036 
03037     flags |= nsIDocumentEncoder::OutputPreformatted;
03038 
03039     if (!aIgnoreWrap) {
03040       nsFormControlHelper::nsHTMLTextWrap wrapProp;
03041       rv = nsFormControlHelper::GetWrapPropertyEnum(mContent, wrapProp);
03042       if (rv != NS_CONTENT_ATTR_NOT_THERE) {
03043         if (wrapProp == nsFormControlHelper::eHTMLTextWrap_Hard)
03044         {
03045           flags |= nsIDocumentEncoder::OutputWrap;
03046         }
03047       }
03048     }
03049 
03050     // What follows is a bit of a hack.  The problem is that we could be in
03051     // this method because we're being destroyed for whatever reason while
03052     // script is executing.  If that happens, editor will run with the
03053     // privileges of the executing script, which means it may not be able to
03054     // access its own DOM nodes!  Let's try to deal with that by pushing a null
03055     // JSContext on the JSContext stack to make it clear that we're native
03056     // code.  Note that any script that's directly trying to access our value
03057     // has to be going through some scriptable object to do that and that
03058     // already does the relevant security checks.
03059     // XXXbz if we could just get the textContent of our anonymous content (eg
03060     // if plaintext editor didn't create <br> nodes all over), we wouldn't need
03061     // this.
03062     nsCOMPtr<nsIJSContextStack> stack =
03063       do_GetService("@mozilla.org/js/xpc/ContextStack;1");
03064     PRBool pushed = stack && NS_SUCCEEDED(stack->Push(nsnull));
03065       
03066     rv = mEditor->OutputToString(NS_LITERAL_STRING("text/plain"), flags,
03067                                  aValue);
03068 
03069     if (pushed) {
03070       JSContext* cx;
03071       stack->Pop(&cx);
03072       NS_ASSERTION(!cx, "Unexpected JSContext popped!");
03073     }
03074   }
03075   else
03076   {
03077     // Otherwise get the value from content.
03078     nsCOMPtr<nsIDOMHTMLInputElement> inputControl = do_QueryInterface(mContent);
03079     if (inputControl)
03080     {
03081       rv = inputControl->GetValue(aValue);
03082     }
03083     else
03084     {
03085       nsCOMPtr<nsIDOMHTMLTextAreaElement> textareaControl
03086           = do_QueryInterface(mContent);
03087       if (textareaControl)
03088       {
03089         rv = textareaControl->GetValue(aValue);
03090       }
03091     }
03092   }
03093 
03094   return rv;
03095 }
03096 
03097 
03098 // END IMPLEMENTING NS_IFORMCONTROLFRAME
03099 
03100 nsresult
03101 nsTextControlFrame::SetValue(const nsAString& aValue)
03102 {
03103   // XXX this method should actually propagate errors!  It'd make debugging it
03104   // so much easier...
03105   if (mEditor && mUseEditor) 
03106   {
03107     nsCOMPtr<nsIEditor> editor = mEditor;
03108     nsWeakFrame weakFrame(this);
03109     nsAutoString currentValue;
03110     GetValue(currentValue, PR_FALSE);
03111     if (IsSingleLineTextControl())
03112     {
03113       RemoveNewlines(currentValue); 
03114     }
03115     // this is necessary to avoid infinite recursion
03116     if (!currentValue.Equals(aValue))
03117     {
03118       // \r is an illegal character in the dom, but people use them,
03119       // so convert windows and mac platform linebreaks to \n:
03120       // Unfortunately aValue is declared const, so we have to copy
03121       // in order to do this substitution.
03122       currentValue.Assign(aValue);
03123       nsFormControlHelper::PlatformToDOMLineBreaks(currentValue);
03124 
03125       nsCOMPtr<nsIDOMDocument>domDoc;
03126       nsresult rv = editor->GetDocument(getter_AddRefs(domDoc));
03127       NS_ENSURE_SUCCESS(rv, rv);
03128       NS_ENSURE_STATE(domDoc);
03129 
03130       // Time to mess with our security context... See comments in GetValue()
03131       // for why this is needed.  Note that we have to do this up here, because
03132       // otherwise SelectAll() will fail.
03133       nsCOMPtr<nsIJSContextStack> stack =
03134         do_GetService("@mozilla.org/js/xpc/ContextStack;1");
03135       PRBool pushed = stack && NS_SUCCEEDED(stack->Push(nsnull));
03136 
03137       nsCOMPtr<nsISelection> domSel;
03138       nsCOMPtr<nsISelectionPrivate> selPriv;
03139       mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSel));
03140       if (domSel)
03141       {
03142         selPriv = do_QueryInterface(domSel);
03143         if (selPriv)
03144           selPriv->StartBatchChanges();
03145       }
03146 
03147       mSelCon->SelectAll();
03148       nsCOMPtr<nsIPlaintextEditor> htmlEditor = do_QueryInterface(mEditor);
03149       if (!htmlEditor) {
03150         NS_WARNING("Somehow not a plaintext editor?");
03151         if (pushed) {
03152           JSContext* cx;
03153           stack->Pop(&cx);
03154           NS_ASSERTION(!cx, "Unexpected JSContext popped!");
03155         }
03156         return NS_ERROR_FAILURE;
03157       }
03158 
03159       // Since this code does not handle user-generated changes to the text,
03160       // make sure we don't fire oninput when the editor notifies us.
03161       // (mNotifyOnInput must be reset before we return).
03162 
03163       // To protect against a reentrant call to SetValue, we check whether
03164       // another SetValue is already happening for this frame.  If it is,
03165       // we must wait until we unwind to re-enable oninput events.
03166       PRBool outerTransaction = mNotifyOnInput;
03167       if (outerTransaction)
03168         mNotifyOnInput = PR_FALSE;
03169 
03170       // get the flags, remove readonly and disabled, set the value,
03171       // restore flags
03172       PRUint32 flags, savedFlags;
03173       editor->GetFlags(&savedFlags);
03174       flags = savedFlags;
03175       flags &= ~(nsIPlaintextEditor::eEditorDisabledMask);
03176       flags &= ~(nsIPlaintextEditor::eEditorReadonlyMask);
03177       editor->SetFlags(flags);
03178       if (currentValue.Length() < 1)
03179         editor->DeleteSelection(nsIEditor::eNone);
03180       else {
03181         nsCOMPtr<nsIPlaintextEditor> textEditor = do_QueryInterface(editor);
03182         if (textEditor)
03183           textEditor->InsertText(currentValue);
03184       }
03185       editor->SetFlags(savedFlags);
03186       if (selPriv)
03187         selPriv->EndBatchChanges();
03188 
03189       if (pushed) {
03190         JSContext* cx;
03191         stack->Pop(&cx);
03192         NS_ASSERTION(!cx, "Unexpected JSContext popped!");
03193       }
03194 
03195       NS_ENSURE_STATE(weakFrame.IsAlive());
03196       if (outerTransaction)
03197         mNotifyOnInput = PR_TRUE;
03198 
03199       if (mHasFocus) {
03200         // Since this code doesn't handle user-generated changes, reset
03201         // mFocusedValue so the onchange event doesn't fire incorrectly.
03202         InitFocusedValue();
03203       }
03204     }
03205 
03206     if (mScrollableView)
03207     {
03208       // Scroll the upper left corner of the text control's
03209       // content area back into view.
03210 
03211       mScrollableView->ScrollTo(0, 0, NS_VMREFRESH_NO_SYNC);
03212     }
03213   }
03214   else
03215   {
03216     // Otherwise set the value in content.
03217     nsCOMPtr<nsITextControlElement> textControl = do_QueryInterface(mContent);
03218     if (textControl)
03219     {
03220       textControl->TakeTextFrameValue(aValue);
03221     }
03222   }
03223   return NS_OK;
03224 }
03225 
03226 
03227 NS_IMETHODIMP
03228 nsTextControlFrame::SetInitialChildList(nsPresContext* aPresContext,
03229                                   nsIAtom*        aListName,
03230                                   nsIFrame*       aChildList)
03231 {
03232   nsresult rv = nsBoxFrame::SetInitialChildList(aPresContext, aListName, aChildList);
03233   if (mEditor)
03234     mEditor->PostCreate();
03235   //look for scroll view below this frame go along first child list
03236   nsIFrame* first = GetFirstChild(nsnull);
03237 
03238   // Mark the scroll frame as being a reflow root. This will allow
03239   // incremental reflows to be initiated at the scroll frame, rather
03240   // than descending from the root frame of the frame hierarchy.
03241   first->AddStateBits(NS_FRAME_REFLOW_ROOT);
03242 
03243   nsIScrollableFrame *scrollableFrame = nsnull;
03244   CallQueryInterface(first, &scrollableFrame);
03245   NS_ASSERTION(scrollableFrame, "Child must be scrollable");
03246 
03247   // we must turn off scrollbars for singleline text controls
03248   // XXX FIXME this should be removed,
03249   // nsGfxScrollFrameInner::CreateAnonymousContent handles this
03250   if (IsSingleLineTextControl()) 
03251   {
03252     if (scrollableFrame)
03253       scrollableFrame->SetScrollbarVisibility(PR_FALSE, PR_FALSE);
03254   }
03255 
03256   //register focus and key listeners
03257   nsCOMPtr<nsIDOMEventReceiver> erP = do_QueryInterface(mContent);
03258   if (erP) {
03259     // register the event listeners with the DOM event receiver
03260     rv = erP->AddEventListenerByIID(NS_STATIC_CAST(nsIDOMFocusListener *,mTextListener), NS_GET_IID(nsIDOMFocusListener));
03261     NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register focus listener");
03262     // XXXbryner do we need to check for a null presshell here?
03263     if (!aPresContext->GetPresShell())
03264       return NS_ERROR_FAILURE;
03265   }
03266 
03267   nsCOMPtr<nsIDOMEventGroup> systemGroup;
03268   erP->GetSystemEventGroup(getter_AddRefs(systemGroup));
03269   nsCOMPtr<nsIDOM3EventTarget> dom3Targ = do_QueryInterface(mContent);
03270   if (dom3Targ) {
03271     // cast because of ambiguous base
03272     nsIDOMEventListener *listener = NS_STATIC_CAST(nsIDOMKeyListener*,
03273                                                    mTextListener);
03274 
03275     dom3Targ->AddGroupedEventListener(NS_LITERAL_STRING("keydown"),
03276                                       listener, PR_FALSE, systemGroup);
03277     dom3Targ->AddGroupedEventListener(NS_LITERAL_STRING("keypress"),
03278                                       listener, PR_FALSE, systemGroup);
03279     dom3Targ->AddGroupedEventListener(NS_LITERAL_STRING("keyup"),
03280                                       listener, PR_FALSE, systemGroup);
03281   }
03282 
03283   if (scrollableFrame) {
03284     mScrollableView = scrollableFrame->GetScrollableView();
03285     mTextSelImpl->SetScrollableView(mScrollableView);
03286   }
03287 
03288   return rv;
03289 }
03290 
03291 
03292 PRInt32 
03293 nsTextControlFrame::GetWidthInCharacters() const
03294 {
03295   // see if there's a COL attribute, if so it wins
03296   nsGenericHTMLElement *content = nsGenericHTMLElement::FromContent(mContent);
03297   if (content)
03298   {
03299     const nsAttrValue* attr = content->GetParsedAttr(nsHTMLAtoms::cols);
03300     if (attr && attr->Type() == nsAttrValue::eInteger) {
03301       return attr->GetIntegerValue();
03302     }
03303   }
03304 
03305   // otherwise, see if CSS has a width specified.  If so, work backwards to get the 
03306   // number of characters this width represents.
03307  
03308   
03309   // otherwise, the default is just returned.
03310   return DEFAULT_COLUMN_WIDTH;
03311 }
03312 
03313 nsIScrollableView* nsTextControlFrame::GetScrollableView()
03314 {
03315   return mScrollableView;
03316 }
03317 
03318 PRBool
03319 nsTextControlFrame::IsScrollable() const
03320 {
03321   return !IsSingleLineTextControl();
03322 }
03323 
03324 NS_IMETHODIMP
03325 nsTextControlFrame::OnContentReset()
03326 {
03327   return NS_OK;
03328 }
03329 
03330 void
03331 nsTextControlFrame::SetValueChanged(PRBool aValueChanged)
03332 {
03333   nsCOMPtr<nsITextControlElement> elem = do_QueryInterface(mContent);
03334   if (elem) {
03335     elem->SetValueChanged(aValueChanged);
03336   }
03337 }
03338 
03339 NS_IMETHODIMP 
03340 nsTextControlFrame::HandleEvent(nsPresContext* aPresContext, 
03341                                        nsGUIEvent*     aEvent,
03342                                        nsEventStatus*  aEventStatus)
03343 {
03344   NS_ENSURE_ARG_POINTER(aEventStatus);
03345 
03346   // temp fix until Bug 124990 gets fixed
03347   if (aPresContext->IsPaginated() && NS_IS_MOUSE_EVENT(aEvent)) {
03348     return NS_OK;
03349   }
03350 
03351   return nsStackFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
03352     
03353 }
03354 
03355 /* static */ void
03356 nsTextControlFrame::ShutDown()
03357 {
03358   NS_IF_RELEASE(sNativeTextAreaBindings);
03359   NS_IF_RELEASE(sNativeInputBindings);
03360 }