LCOV - code coverage report
Current view: directory - editor/libeditor/text - nsPlaintextEditor.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 770 2 0.3 %
Date: 2012-06-02 Functions: 69 2 2.9 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Daniel Glazman <glazman@netscape.com>
      24                 :  *   Mats Palmgren <matspal@gmail.com>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : 
      41                 : #include "nsPlaintextEditor.h"
      42                 : #include "nsCaret.h"
      43                 : #include "nsTextEditUtils.h"
      44                 : #include "nsTextEditRules.h"
      45                 : #include "nsIEditActionListener.h"
      46                 : #include "nsIDOMNodeList.h"
      47                 : #include "nsIDOMDocument.h"
      48                 : #include "nsIDocument.h"
      49                 : #include "nsIDOMEventTarget.h" 
      50                 : #include "nsIDOMKeyEvent.h"
      51                 : #include "nsISelection.h"
      52                 : #include "nsISelectionPrivate.h"
      53                 : #include "nsISelectionController.h"
      54                 : #include "nsGUIEvent.h"
      55                 : #include "nsCRT.h"
      56                 : 
      57                 : #include "nsIEnumerator.h"
      58                 : #include "nsIContent.h"
      59                 : #include "nsIContentIterator.h"
      60                 : #include "nsIDOMRange.h"
      61                 : #include "nsISupportsArray.h"
      62                 : #include "nsIComponentManager.h"
      63                 : #include "nsIServiceManager.h"
      64                 : #include "nsIDocumentEncoder.h"
      65                 : #include "nsIPresShell.h"
      66                 : #include "nsISupportsPrimitives.h"
      67                 : #include "nsReadableUtils.h"
      68                 : 
      69                 : // Misc
      70                 : #include "nsEditorUtils.h"  // nsAutoEditBatch, nsAutoRules
      71                 : #include "nsUnicharUtils.h"
      72                 : #include "nsContentCID.h"
      73                 : #include "nsInternetCiter.h"
      74                 : #include "nsEventDispatcher.h"
      75                 : #include "nsGkAtoms.h"
      76                 : #include "nsDebug.h"
      77                 : #include "mozilla/Preferences.h"
      78                 : #include "mozilla/dom/Element.h"
      79                 : 
      80                 : // Drag & Drop, Clipboard
      81                 : #include "nsIClipboard.h"
      82                 : #include "nsITransferable.h"
      83                 : #include "nsCopySupport.h"
      84                 : 
      85                 : #include "mozilla/FunctionTimer.h"
      86                 : 
      87                 : using namespace mozilla;
      88                 : 
      89               0 : nsPlaintextEditor::nsPlaintextEditor()
      90                 : : nsEditor()
      91                 : , mRules(nsnull)
      92                 : , mWrapToWindow(false)
      93                 : , mWrapColumn(0)
      94                 : , mMaxTextLength(-1)
      95                 : , mInitTriggerCounter(0)
      96                 : , mNewlineHandling(nsIPlaintextEditor::eNewlinesPasteToFirst)
      97                 : #ifdef XP_WIN
      98                 : , mCaretStyle(1)
      99                 : #else
     100               0 : , mCaretStyle(0)
     101                 : #endif
     102                 : {
     103               0 : } 
     104                 : 
     105               0 : nsPlaintextEditor::~nsPlaintextEditor()
     106                 : {
     107                 :   // Remove event listeners. Note that if we had an HTML editor,
     108                 :   //  it installed its own instead of these
     109               0 :   RemoveEventListeners();
     110                 : 
     111               0 :   if (mRules)
     112               0 :     mRules->DetachEditor();
     113               0 : }
     114                 : 
     115            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsPlaintextEditor)
     116                 : 
     117               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsPlaintextEditor, nsEditor)
     118               0 :   if (tmp->mRules)
     119               0 :     tmp->mRules->DetachEditor();
     120               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRules)
     121               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     122                 : 
     123               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsPlaintextEditor, nsEditor)
     124               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mRules)
     125               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     126                 : 
     127               0 : NS_IMPL_ADDREF_INHERITED(nsPlaintextEditor, nsEditor)
     128               0 : NS_IMPL_RELEASE_INHERITED(nsPlaintextEditor, nsEditor)
     129                 : 
     130               0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsPlaintextEditor)
     131               0 :   NS_INTERFACE_MAP_ENTRY(nsIPlaintextEditor)
     132               0 :   NS_INTERFACE_MAP_ENTRY(nsIEditorMailSupport)
     133               0 : NS_INTERFACE_MAP_END_INHERITING(nsEditor)
     134                 : 
     135                 : 
     136               0 : NS_IMETHODIMP nsPlaintextEditor::Init(nsIDOMDocument *aDoc, 
     137                 :                                       nsIContent *aRoot,
     138                 :                                       nsISelectionController *aSelCon,
     139                 :                                       PRUint32 aFlags)
     140                 : {
     141                 :   NS_TIME_FUNCTION;
     142                 : 
     143               0 :   NS_PRECONDITION(aDoc, "bad arg");
     144               0 :   NS_ENSURE_TRUE(aDoc, NS_ERROR_NULL_POINTER);
     145                 :   
     146               0 :   nsresult res = NS_OK, rulesRes = NS_OK;
     147                 :   
     148                 :   if (1)
     149                 :   {
     150                 :     // block to scope nsAutoEditInitRulesTrigger
     151               0 :     nsAutoEditInitRulesTrigger rulesTrigger(this, rulesRes);
     152                 :   
     153                 :     // Init the base editor
     154               0 :     res = nsEditor::Init(aDoc, aRoot, aSelCon, aFlags);
     155                 :   }
     156                 : 
     157                 :   // check the "single line editor newline handling"
     158                 :   // and "caret behaviour in selection" prefs
     159               0 :   GetDefaultEditorPrefs(mNewlineHandling, mCaretStyle);
     160                 : 
     161               0 :   NS_ENSURE_SUCCESS(rulesRes, rulesRes);
     162               0 :   return res;
     163                 : }
     164                 : 
     165                 : static PRInt32 sNewlineHandlingPref = -1,
     166                 :                sCaretStylePref = -1;
     167                 : 
     168                 : static int
     169               0 : EditorPrefsChangedCallback(const char *aPrefName, void *)
     170                 : {
     171               0 :   if (nsCRT::strcmp(aPrefName, "editor.singleLine.pasteNewlines") == 0) {
     172                 :     sNewlineHandlingPref =
     173                 :       Preferences::GetInt("editor.singleLine.pasteNewlines",
     174               0 :                           nsIPlaintextEditor::eNewlinesPasteToFirst);
     175               0 :   } else if (nsCRT::strcmp(aPrefName, "layout.selection.caret_style") == 0) {
     176                 :     sCaretStylePref = Preferences::GetInt("layout.selection.caret_style",
     177                 : #ifdef XP_WIN
     178                 :                                                  1);
     179                 :     if (sCaretStylePref == 0)
     180                 :       sCaretStylePref = 1;
     181                 : #else
     182               0 :                                                  0);
     183                 : #endif
     184                 :   }
     185               0 :   return 0;
     186                 : }
     187                 : 
     188                 : // static
     189                 : void
     190               0 : nsPlaintextEditor::GetDefaultEditorPrefs(PRInt32 &aNewlineHandling,
     191                 :                                          PRInt32 &aCaretStyle)
     192                 : {
     193               0 :   if (sNewlineHandlingPref == -1) {
     194                 :     Preferences::RegisterCallback(EditorPrefsChangedCallback,
     195               0 :                                   "editor.singleLine.pasteNewlines");
     196               0 :     EditorPrefsChangedCallback("editor.singleLine.pasteNewlines", nsnull);
     197                 :     Preferences::RegisterCallback(EditorPrefsChangedCallback,
     198               0 :                                   "layout.selection.caret_style");
     199               0 :     EditorPrefsChangedCallback("layout.selection.caret_style", nsnull);
     200                 :   }
     201                 : 
     202               0 :   aNewlineHandling = sNewlineHandlingPref;
     203               0 :   aCaretStyle = sCaretStylePref;
     204               0 : }
     205                 : 
     206                 : void 
     207               0 : nsPlaintextEditor::BeginEditorInit()
     208                 : {
     209               0 :   mInitTriggerCounter++;
     210               0 : }
     211                 : 
     212                 : nsresult 
     213               0 : nsPlaintextEditor::EndEditorInit()
     214                 : {
     215               0 :   nsresult res = NS_OK;
     216               0 :   NS_PRECONDITION(mInitTriggerCounter > 0, "ended editor init before we began?");
     217               0 :   mInitTriggerCounter--;
     218               0 :   if (mInitTriggerCounter == 0)
     219                 :   {
     220               0 :     res = InitRules();
     221               0 :     if (NS_SUCCEEDED(res)) {
     222                 :       // Throw away the old transaction manager if this is not the first time that
     223                 :       // we're initializing the editor.
     224               0 :       EnableUndo(false);
     225               0 :       EnableUndo(true);
     226                 :     }
     227                 :   }
     228               0 :   return res;
     229                 : }
     230                 : 
     231                 : NS_IMETHODIMP
     232               0 : nsPlaintextEditor::SetDocumentCharacterSet(const nsACString& characterSet)
     233                 : {
     234               0 :   nsresult rv = nsEditor::SetDocumentCharacterSet(characterSet);
     235               0 :   NS_ENSURE_SUCCESS(rv, rv);
     236                 : 
     237                 :   // Update META charset element.
     238               0 :   nsCOMPtr<nsIDOMDocument> domdoc;
     239               0 :   rv = GetDocument(getter_AddRefs(domdoc));
     240               0 :   NS_ENSURE_SUCCESS(rv, rv);
     241               0 :   NS_ENSURE_TRUE(domdoc, NS_ERROR_FAILURE);
     242                 : 
     243               0 :   if (UpdateMetaCharset(domdoc, characterSet)) {
     244               0 :     return NS_OK;
     245                 :   }
     246                 : 
     247               0 :   nsCOMPtr<nsIDOMNodeList> headList;
     248               0 :   rv = domdoc->GetElementsByTagName(NS_LITERAL_STRING("head"), getter_AddRefs(headList));
     249               0 :   NS_ENSURE_SUCCESS(rv, rv);
     250               0 :   NS_ENSURE_TRUE(headList, NS_OK);
     251                 : 
     252               0 :   nsCOMPtr<nsIDOMNode> headNode;
     253               0 :   headList->Item(0, getter_AddRefs(headNode));
     254               0 :   NS_ENSURE_TRUE(headNode, NS_OK);
     255                 : 
     256                 :   // Create a new meta charset tag
     257               0 :   nsCOMPtr<nsIDOMNode> resultNode;
     258               0 :   rv = CreateNode(NS_LITERAL_STRING("meta"), headNode, 0, getter_AddRefs(resultNode));
     259               0 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
     260               0 :   NS_ENSURE_TRUE(resultNode, NS_OK);
     261                 : 
     262                 :   // Set attributes to the created element
     263               0 :   if (characterSet.IsEmpty()) {
     264               0 :     return NS_OK;
     265                 :   }
     266                 : 
     267               0 :   nsCOMPtr<dom::Element> metaElement = do_QueryInterface(resultNode);
     268               0 :   if (!metaElement) {
     269               0 :     return NS_OK;
     270                 :   }
     271                 : 
     272                 :   // not undoable, undo should undo CreateNode
     273               0 :   metaElement->SetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv,
     274               0 :                        NS_LITERAL_STRING("Content-Type"), true);
     275               0 :   metaElement->SetAttr(kNameSpaceID_None, nsGkAtoms::content,
     276               0 :                        NS_LITERAL_STRING("text/html;charset=") +
     277               0 :                          NS_ConvertASCIItoUTF16(characterSet),
     278               0 :                        true);
     279               0 :   return NS_OK;
     280                 : }
     281                 : 
     282                 : bool
     283               0 : nsPlaintextEditor::UpdateMetaCharset(nsIDOMDocument* aDocument,
     284                 :                                      const nsACString& aCharacterSet)
     285                 : {
     286                 :   // get a list of META tags
     287               0 :   nsCOMPtr<nsIDOMNodeList> metaList;
     288               0 :   nsresult rv = aDocument->GetElementsByTagName(NS_LITERAL_STRING("meta"),
     289               0 :                                                 getter_AddRefs(metaList));
     290               0 :   NS_ENSURE_SUCCESS(rv, false);
     291               0 :   NS_ENSURE_TRUE(metaList, false);
     292                 : 
     293               0 :   PRUint32 listLength = 0;
     294               0 :   metaList->GetLength(&listLength);
     295                 : 
     296               0 :   for (PRUint32 i = 0; i < listLength; ++i) {
     297               0 :     nsCOMPtr<nsIContent> metaNode = metaList->GetNodeAt(i);
     298               0 :     MOZ_ASSERT(metaNode);
     299                 : 
     300               0 :     if (!metaNode->IsElement()) {
     301               0 :       continue;
     302                 :     }
     303                 : 
     304               0 :     nsAutoString currentValue;
     305               0 :     metaNode->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, currentValue);
     306                 : 
     307               0 :     if (!FindInReadable(NS_LITERAL_STRING("content-type"),
     308                 :                         currentValue,
     309               0 :                         nsCaseInsensitiveStringComparator())) {
     310               0 :       continue;
     311                 :     }
     312                 : 
     313               0 :     metaNode->GetAttr(kNameSpaceID_None, nsGkAtoms::content, currentValue);
     314                 : 
     315               0 :     NS_NAMED_LITERAL_STRING(charsetEquals, "charset=");
     316               0 :     nsAString::const_iterator originalStart, start, end;
     317               0 :     originalStart = currentValue.BeginReading(start);
     318               0 :     currentValue.EndReading(end);
     319               0 :     if (!FindInReadable(charsetEquals, start, end,
     320               0 :                         nsCaseInsensitiveStringComparator())) {
     321               0 :       continue;
     322                 :     }
     323                 : 
     324                 :     // set attribute to <original prefix> charset=text/html
     325               0 :     nsCOMPtr<nsIDOMElement> metaElement = do_QueryInterface(metaNode);
     326               0 :     MOZ_ASSERT(metaElement);
     327               0 :     rv = nsEditor::SetAttribute(metaElement, NS_LITERAL_STRING("content"),
     328               0 :                                 Substring(originalStart, start) +
     329               0 :                                   charsetEquals +
     330               0 :                                   NS_ConvertASCIItoUTF16(aCharacterSet));
     331               0 :     return NS_SUCCEEDED(rv);
     332                 :   }
     333               0 :   return false;
     334                 : }
     335                 : 
     336               0 : NS_IMETHODIMP nsPlaintextEditor::InitRules()
     337                 : {
     338                 :   // instantiate the rules for this text editor
     339               0 :   mRules = new nsTextEditRules();
     340               0 :   return mRules->Init(this);
     341                 : }
     342                 : 
     343                 : 
     344                 : NS_IMETHODIMP
     345               0 : nsPlaintextEditor::GetIsDocumentEditable(bool *aIsDocumentEditable)
     346                 : {
     347               0 :   NS_ENSURE_ARG_POINTER(aIsDocumentEditable);
     348                 : 
     349               0 :   nsCOMPtr<nsIDOMDocument> doc;
     350               0 :   GetDocument(getter_AddRefs(doc));
     351               0 :   *aIsDocumentEditable = doc ? IsModifiable() : false;
     352                 : 
     353               0 :   return NS_OK;
     354                 : }
     355                 : 
     356               0 : bool nsPlaintextEditor::IsModifiable()
     357                 : {
     358               0 :   return !IsReadonly();
     359                 : }
     360                 : 
     361                 : nsresult
     362               0 : nsPlaintextEditor::HandleKeyPressEvent(nsIDOMKeyEvent* aKeyEvent)
     363                 : {
     364                 :   // NOTE: When you change this method, you should also change:
     365                 :   //   * editor/libeditor/text/tests/test_texteditor_keyevent_handling.html
     366                 :   //   * editor/libeditor/html/tests/test_htmleditor_keyevent_handling.html
     367                 :   //
     368                 :   // And also when you add new key handling, you need to change the subclass's
     369                 :   // HandleKeyPressEvent()'s switch statement.
     370                 : 
     371               0 :   if (IsReadonly() || IsDisabled()) {
     372                 :     // When we're not editable, the events handled on nsEditor.
     373               0 :     return nsEditor::HandleKeyPressEvent(aKeyEvent);
     374                 :   }
     375                 : 
     376               0 :   nsKeyEvent* nativeKeyEvent = GetNativeKeyEvent(aKeyEvent);
     377               0 :   NS_ENSURE_TRUE(nativeKeyEvent, NS_ERROR_UNEXPECTED);
     378               0 :   NS_ASSERTION(nativeKeyEvent->message == NS_KEY_PRESS,
     379                 :                "HandleKeyPressEvent gets non-keypress event");
     380                 : 
     381               0 :   switch (nativeKeyEvent->keyCode) {
     382                 :     case nsIDOMKeyEvent::DOM_VK_META:
     383                 :     case nsIDOMKeyEvent::DOM_VK_SHIFT:
     384                 :     case nsIDOMKeyEvent::DOM_VK_CONTROL:
     385                 :     case nsIDOMKeyEvent::DOM_VK_ALT:
     386                 :     case nsIDOMKeyEvent::DOM_VK_BACK_SPACE:
     387                 :     case nsIDOMKeyEvent::DOM_VK_DELETE:
     388                 :       // These keys are handled on nsEditor
     389               0 :       return nsEditor::HandleKeyPressEvent(aKeyEvent);
     390                 :     case nsIDOMKeyEvent::DOM_VK_TAB: {
     391               0 :       if (IsTabbable()) {
     392               0 :         return NS_OK; // let it be used for focus switching
     393                 :       }
     394                 : 
     395               0 :       if (nativeKeyEvent->isShift || nativeKeyEvent->isControl ||
     396                 :           nativeKeyEvent->isAlt || nativeKeyEvent->isMeta) {
     397               0 :         return NS_OK;
     398                 :       }
     399                 : 
     400                 :       // else we insert the tab straight through
     401               0 :       aKeyEvent->PreventDefault();
     402               0 :       return TypedText(NS_LITERAL_STRING("\t"), eTypedText);
     403                 :     }
     404                 :     case nsIDOMKeyEvent::DOM_VK_RETURN:
     405                 :     case nsIDOMKeyEvent::DOM_VK_ENTER:
     406               0 :       if (IsSingleLineEditor() || nativeKeyEvent->isControl ||
     407                 :           nativeKeyEvent->isAlt || nativeKeyEvent->isMeta) {
     408               0 :         return NS_OK;
     409                 :       }
     410               0 :       aKeyEvent->PreventDefault();
     411               0 :       return TypedText(EmptyString(), eTypedBreak);
     412                 :   }
     413                 : 
     414                 :   // NOTE: On some keyboard layout, some characters are inputted with Control
     415                 :   // key or Alt key, but at that time, widget sets FALSE to these keys.
     416               0 :   if (nativeKeyEvent->charCode == 0 || nativeKeyEvent->isControl ||
     417                 :       nativeKeyEvent->isAlt || nativeKeyEvent->isMeta) {
     418                 :     // we don't PreventDefault() here or keybindings like control-x won't work
     419               0 :     return NS_OK;
     420                 :   }
     421               0 :   aKeyEvent->PreventDefault();
     422               0 :   nsAutoString str(nativeKeyEvent->charCode);
     423               0 :   return TypedText(str, eTypedText);
     424                 : }
     425                 : 
     426                 : /* This routine is needed to provide a bottleneck for typing for logging
     427                 :    purposes.  Can't use HandleKeyPress() (above) for that since it takes
     428                 :    a nsIDOMKeyEvent* parameter.  So instead we pass enough info through
     429                 :    to TypedText() to determine what action to take, but without passing
     430                 :    an event.
     431                 :    */
     432               0 : NS_IMETHODIMP nsPlaintextEditor::TypedText(const nsAString& aString,
     433                 :                                       PRInt32 aAction)
     434                 : {
     435               0 :   nsAutoPlaceHolderBatch batch(this, nsGkAtoms::TypingTxnName);
     436                 : 
     437               0 :   switch (aAction)
     438                 :   {
     439                 :     case eTypedText:
     440                 :       {
     441               0 :         return InsertText(aString);
     442                 :       }
     443                 :     case eTypedBreak:
     444                 :       {
     445               0 :         return InsertLineBreak();
     446                 :       } 
     447                 :   } 
     448               0 :   return NS_ERROR_FAILURE; 
     449                 : }
     450                 : 
     451                 : nsresult
     452               0 : nsPlaintextEditor::CreateBRImpl(nsCOMPtr<nsIDOMNode>* aInOutParent,
     453                 :                                 PRInt32* aInOutOffset,
     454                 :                                 nsCOMPtr<nsIDOMNode>* outBRNode,
     455                 :                                 EDirection aSelect)
     456                 : {
     457               0 :   NS_ENSURE_TRUE(aInOutParent && *aInOutParent && aInOutOffset && outBRNode, NS_ERROR_NULL_POINTER);
     458               0 :   *outBRNode = nsnull;
     459                 :   nsresult res;
     460                 :   
     461                 :   // we need to insert a br.  unfortunately, we may have to split a text node to do it.
     462               0 :   nsCOMPtr<nsIDOMNode> node = *aInOutParent;
     463               0 :   PRInt32 theOffset = *aInOutOffset;
     464               0 :   nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(node);
     465               0 :   NS_NAMED_LITERAL_STRING(brType, "br");
     466               0 :   nsCOMPtr<nsIDOMNode> brNode;
     467               0 :   if (nodeAsText)  
     468                 :   {
     469               0 :     nsCOMPtr<nsIDOMNode> tmp;
     470                 :     PRInt32 offset;
     471                 :     PRUint32 len;
     472               0 :     nodeAsText->GetLength(&len);
     473               0 :     GetNodeLocation(node, address_of(tmp), &offset);
     474               0 :     NS_ENSURE_TRUE(tmp, NS_ERROR_FAILURE);
     475               0 :     if (!theOffset)
     476                 :     {
     477                 :       // we are already set to go
     478                 :     }
     479               0 :     else if (theOffset == (PRInt32)len)
     480                 :     {
     481                 :       // update offset to point AFTER the text node
     482               0 :       offset++;
     483                 :     }
     484                 :     else
     485                 :     {
     486                 :       // split the text node
     487               0 :       res = SplitNode(node, theOffset, getter_AddRefs(tmp));
     488               0 :       NS_ENSURE_SUCCESS(res, res);
     489               0 :       res = GetNodeLocation(node, address_of(tmp), &offset);
     490               0 :       NS_ENSURE_SUCCESS(res, res);
     491                 :     }
     492                 :     // create br
     493               0 :     res = CreateNode(brType, tmp, offset, getter_AddRefs(brNode));
     494               0 :     NS_ENSURE_SUCCESS(res, res);
     495               0 :     *aInOutParent = tmp;
     496               0 :     *aInOutOffset = offset+1;
     497                 :   }
     498                 :   else
     499                 :   {
     500               0 :     res = CreateNode(brType, node, theOffset, getter_AddRefs(brNode));
     501               0 :     NS_ENSURE_SUCCESS(res, res);
     502               0 :     (*aInOutOffset)++;
     503                 :   }
     504                 : 
     505               0 :   *outBRNode = brNode;
     506               0 :   if (*outBRNode && (aSelect != eNone))
     507                 :   {
     508               0 :     nsCOMPtr<nsIDOMNode> parent;
     509                 :     PRInt32 offset;
     510               0 :     res = GetNodeLocation(*outBRNode, address_of(parent), &offset);
     511               0 :     NS_ENSURE_SUCCESS(res, res);
     512                 : 
     513               0 :     nsCOMPtr<nsISelection> selection;
     514               0 :     res = GetSelection(getter_AddRefs(selection));
     515               0 :     NS_ENSURE_SUCCESS(res, res);
     516               0 :     nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
     517               0 :     if (aSelect == eNext)
     518                 :     {
     519                 :       // position selection after br
     520               0 :       selPriv->SetInterlinePosition(true);
     521               0 :       res = selection->Collapse(parent, offset+1);
     522                 :     }
     523               0 :     else if (aSelect == ePrevious)
     524                 :     {
     525                 :       // position selection before br
     526               0 :       selPriv->SetInterlinePosition(true);
     527               0 :       res = selection->Collapse(parent, offset);
     528                 :     }
     529                 :   }
     530               0 :   return NS_OK;
     531                 : }
     532                 : 
     533                 : 
     534               0 : NS_IMETHODIMP nsPlaintextEditor::CreateBR(nsIDOMNode *aNode, PRInt32 aOffset, nsCOMPtr<nsIDOMNode> *outBRNode, EDirection aSelect)
     535                 : {
     536               0 :   nsCOMPtr<nsIDOMNode> parent = aNode;
     537               0 :   PRInt32 offset = aOffset;
     538               0 :   return CreateBRImpl(address_of(parent), &offset, outBRNode, aSelect);
     539                 : }
     540                 : 
     541                 : nsresult
     542               0 : nsPlaintextEditor::InsertBR(nsCOMPtr<nsIDOMNode>* outBRNode)
     543                 : {
     544               0 :   NS_ENSURE_TRUE(outBRNode, NS_ERROR_NULL_POINTER);
     545               0 :   *outBRNode = nsnull;
     546                 : 
     547                 :   // calling it text insertion to trigger moz br treatment by rules
     548               0 :   nsAutoRules beginRulesSniffing(this, kOpInsertText, nsIEditor::eNext);
     549                 : 
     550               0 :   nsCOMPtr<nsISelection> selection;
     551               0 :   nsresult res = GetSelection(getter_AddRefs(selection));
     552               0 :   NS_ENSURE_SUCCESS(res, res);
     553                 :   bool bCollapsed;
     554               0 :   res = selection->GetIsCollapsed(&bCollapsed);
     555               0 :   NS_ENSURE_SUCCESS(res, res);
     556               0 :   if (!bCollapsed)
     557                 :   {
     558               0 :     res = DeleteSelection(nsIEditor::eNone);
     559               0 :     NS_ENSURE_SUCCESS(res, res);
     560                 :   }
     561               0 :   nsCOMPtr<nsIDOMNode> selNode;
     562                 :   PRInt32 selOffset;
     563               0 :   res = GetStartNodeAndOffset(selection, getter_AddRefs(selNode), &selOffset);
     564               0 :   NS_ENSURE_SUCCESS(res, res);
     565                 :   
     566               0 :   res = CreateBR(selNode, selOffset, outBRNode);
     567               0 :   NS_ENSURE_SUCCESS(res, res);
     568                 :     
     569                 :   // position selection after br
     570               0 :   res = GetNodeLocation(*outBRNode, address_of(selNode), &selOffset);
     571               0 :   NS_ENSURE_SUCCESS(res, res);
     572               0 :   nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
     573               0 :   selPriv->SetInterlinePosition(true);
     574               0 :   return selection->Collapse(selNode, selOffset+1);
     575                 : }
     576                 : 
     577                 : nsresult
     578               0 : nsPlaintextEditor::GetTextSelectionOffsets(nsISelection *aSelection,
     579                 :                                            PRUint32 &aOutStartOffset, 
     580                 :                                            PRUint32 &aOutEndOffset)
     581                 : {
     582               0 :   NS_ASSERTION(aSelection, "null selection");
     583                 : 
     584                 :   nsresult rv;
     585               0 :   nsCOMPtr<nsIDOMNode> startNode, endNode;
     586                 :   PRInt32 startNodeOffset, endNodeOffset;
     587               0 :   aSelection->GetAnchorNode(getter_AddRefs(startNode));
     588               0 :   aSelection->GetAnchorOffset(&startNodeOffset);
     589               0 :   aSelection->GetFocusNode(getter_AddRefs(endNode));
     590               0 :   aSelection->GetFocusOffset(&endNodeOffset);
     591                 : 
     592               0 :   dom::Element *rootElement = GetRoot();
     593               0 :   nsCOMPtr<nsIDOMNode> rootNode = do_QueryInterface(rootElement);
     594               0 :   NS_ENSURE_TRUE(rootNode, NS_ERROR_NULL_POINTER);
     595                 : 
     596               0 :   PRInt32 startOffset = -1;
     597               0 :   PRInt32 endOffset = -1;
     598                 : 
     599                 :   nsCOMPtr<nsIContentIterator> iter =
     600               0 :     do_CreateInstance("@mozilla.org/content/post-content-iterator;1", &rv);
     601               0 :   NS_ENSURE_SUCCESS(rv, rv);
     602                 :     
     603                 : #ifdef NS_DEBUG
     604               0 :   PRInt32 nodeCount = 0; // only needed for the assertions below
     605                 : #endif
     606               0 :   PRUint32 totalLength = 0;
     607               0 :   iter->Init(rootElement);
     608               0 :   for (; !iter->IsDone() && (startOffset == -1 || endOffset == -1); iter->Next()) {
     609               0 :     nsCOMPtr<nsIDOMNode> currentNode = do_QueryInterface(iter->GetCurrentNode());
     610               0 :     nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(currentNode);
     611               0 :     if (textNode) {
     612                 :       // Note that sometimes we have an empty #text-node as start/endNode,
     613                 :       // which we regard as not editable because the frame width == 0,
     614                 :       // see nsEditor::IsEditable().
     615               0 :       bool editable = IsEditable(currentNode);
     616               0 :       if (currentNode == startNode) {
     617               0 :         startOffset = totalLength + (editable ? startNodeOffset : 0);
     618                 :       }
     619               0 :       if (currentNode == endNode) {
     620               0 :         endOffset = totalLength + (editable ? endNodeOffset : 0);
     621                 :       }
     622               0 :       if (editable) {
     623                 :         PRUint32 length;
     624               0 :         textNode->GetLength(&length);
     625               0 :         totalLength += length;
     626                 :       }
     627                 :     }
     628                 : #ifdef NS_DEBUG
     629                 :     // The post content iterator might return the parent node (which is the
     630                 :     // editor's root node) as the last item.  Don't count the root node itself
     631                 :     // as one of its children!
     632               0 :     if (!SameCOMIdentity(currentNode, rootNode)) {
     633               0 :       ++nodeCount;
     634                 :     }
     635                 : #endif
     636                 :   }
     637                 : 
     638               0 :   if (endOffset == -1) {
     639               0 :     NS_ASSERTION(endNode == rootNode, "failed to find the end node");
     640               0 :     NS_ASSERTION(IsPasswordEditor() ||
     641                 :                  (endNodeOffset == nodeCount-1 || endNodeOffset == 0),
     642                 :                  "invalid end node offset");
     643               0 :     endOffset = endNodeOffset == 0 ? 0 : totalLength;
     644                 :   }
     645               0 :   if (startOffset == -1) {
     646               0 :     NS_ASSERTION(startNode == rootNode, "failed to find the start node");
     647               0 :     NS_ASSERTION(startNodeOffset == nodeCount-1 || startNodeOffset == 0,
     648                 :                  "invalid start node offset");
     649               0 :     startOffset = startNodeOffset == 0 ? 0 : totalLength;
     650                 :   }
     651                 : 
     652                 :   // Make sure aOutStartOffset <= aOutEndOffset.
     653               0 :   if (startOffset <= endOffset) {
     654               0 :     aOutStartOffset = startOffset;
     655               0 :     aOutEndOffset = endOffset;
     656                 :   }
     657                 :   else {
     658               0 :     aOutStartOffset = endOffset;
     659               0 :     aOutEndOffset = startOffset;
     660                 :   }
     661                 : 
     662               0 :   return NS_OK;
     663                 : }
     664                 : 
     665                 : nsresult
     666               0 : nsPlaintextEditor::ExtendSelectionForDelete(nsISelection *aSelection,
     667                 :                                             nsIEditor::EDirection *aAction)
     668                 : {
     669                 :   nsresult result;
     670                 : 
     671                 :   bool bCollapsed;
     672               0 :   result = aSelection->GetIsCollapsed(&bCollapsed);
     673               0 :   NS_ENSURE_SUCCESS(result, result);
     674                 : 
     675               0 :   if (*aAction == eNextWord || *aAction == ePreviousWord
     676                 :       || (*aAction == eNext && bCollapsed)
     677                 :       || (*aAction == ePrevious && bCollapsed)
     678                 :       || *aAction == eToBeginningOfLine || *aAction == eToEndOfLine)
     679                 :   {
     680               0 :     nsCOMPtr<nsISelectionController> selCont;
     681               0 :     GetSelectionController(getter_AddRefs(selCont));
     682               0 :     NS_ENSURE_TRUE(selCont, NS_ERROR_NO_INTERFACE);
     683                 : 
     684               0 :     switch (*aAction)
     685                 :     {
     686                 :       case eNextWord:
     687               0 :         result = selCont->WordExtendForDelete(true);
     688                 :         // DeleteSelectionImpl doesn't handle these actions
     689                 :         // because it's inside batching, so don't confuse it:
     690               0 :         *aAction = eNone;
     691               0 :         break;
     692                 :       case ePreviousWord:
     693               0 :         result = selCont->WordExtendForDelete(false);
     694               0 :         *aAction = eNone;
     695               0 :         break;
     696                 :       case eNext:
     697               0 :         result = selCont->CharacterExtendForDelete();
     698                 :         // Don't set aAction to eNone (see Bug 502259)
     699               0 :         break;
     700                 :       case ePrevious: {
     701                 :         // Only extend the selection where the selection is after a UTF-16
     702                 :         // surrogate pair.  For other cases we don't want to do that, in order
     703                 :         // to make sure that pressing backspace will only delete the last
     704                 :         // typed character.
     705               0 :         nsCOMPtr<nsIDOMNode> node;
     706                 :         PRInt32 offset;
     707               0 :         result = GetStartNodeAndOffset(aSelection, getter_AddRefs(node), &offset);
     708               0 :         NS_ENSURE_SUCCESS(result, result);
     709               0 :         NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
     710                 : 
     711               0 :         if (IsTextNode(node)) {
     712               0 :           nsCOMPtr<nsIDOMCharacterData> charData = do_QueryInterface(node);
     713               0 :           if (charData) {
     714               0 :             nsAutoString data;
     715               0 :             result = charData->GetData(data);
     716               0 :             NS_ENSURE_SUCCESS(result, result);
     717                 : 
     718               0 :             if (offset > 1 &&
     719               0 :                 NS_IS_LOW_SURROGATE(data[offset - 1]) &&
     720               0 :                 NS_IS_HIGH_SURROGATE(data[offset - 2])) {
     721               0 :               result = selCont->CharacterExtendForBackspace();
     722                 :             }
     723                 :           }
     724                 :         }
     725               0 :         break;
     726                 :       }
     727                 :       case eToBeginningOfLine:
     728               0 :         selCont->IntraLineMove(true, false);          // try to move to end
     729               0 :         result = selCont->IntraLineMove(false, true); // select to beginning
     730               0 :         *aAction = eNone;
     731               0 :         break;
     732                 :       case eToEndOfLine:
     733               0 :         result = selCont->IntraLineMove(true, true);
     734               0 :         *aAction = eNext;
     735               0 :         break;
     736                 :       default:       // avoid several compiler warnings
     737               0 :         result = NS_OK;
     738               0 :         break;
     739                 :     }
     740                 :   }
     741               0 :   return result;
     742                 : }
     743                 : 
     744               0 : NS_IMETHODIMP nsPlaintextEditor::DeleteSelection(nsIEditor::EDirection aAction)
     745                 : {
     746               0 :   if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
     747                 : 
     748                 :   // Protect the edit rules object from dying
     749               0 :   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
     750                 : 
     751                 :   nsresult result;
     752                 : 
     753               0 :   FireTrustedInputEvent trusted(this, aAction != eNone);
     754                 : 
     755                 :   // delete placeholder txns merge.
     756               0 :   nsAutoPlaceHolderBatch batch(this, nsGkAtoms::DeleteTxnName);
     757               0 :   nsAutoRules beginRulesSniffing(this, kOpDeleteSelection, aAction);
     758                 : 
     759                 :   // pre-process
     760               0 :   nsCOMPtr<nsISelection> selection;
     761               0 :   result = GetSelection(getter_AddRefs(selection));
     762               0 :   NS_ENSURE_SUCCESS(result, result);
     763               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
     764                 : 
     765                 :   // If there is an existing selection when an extended delete is requested,
     766                 :   //  platforms that use "caret-style" caret positioning collapse the
     767                 :   //  selection to the  start and then create a new selection.
     768                 :   //  Platforms that use "selection-style" caret positioning just delete the
     769                 :   //  existing selection without extending it.
     770                 :   bool bCollapsed;
     771               0 :   result  = selection->GetIsCollapsed(&bCollapsed);
     772               0 :   NS_ENSURE_SUCCESS(result, result);
     773               0 :   if (!bCollapsed &&
     774                 :       (aAction == eNextWord || aAction == ePreviousWord ||
     775                 :        aAction == eToBeginningOfLine || aAction == eToEndOfLine))
     776                 :   {
     777               0 :     if (mCaretStyle == 1)
     778                 :     {
     779               0 :       result = selection->CollapseToStart();
     780               0 :       NS_ENSURE_SUCCESS(result, result);
     781                 :     }
     782                 :     else
     783                 :     { 
     784               0 :       aAction = eNone;
     785                 :     }
     786                 :   }
     787                 : 
     788               0 :   nsTextRulesInfo ruleInfo(nsTextEditRules::kDeleteSelection);
     789               0 :   ruleInfo.collapsedAction = aAction;
     790                 :   bool cancel, handled;
     791               0 :   result = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
     792               0 :   NS_ENSURE_SUCCESS(result, result);
     793               0 :   if (!cancel && !handled)
     794                 :   {
     795               0 :     result = DeleteSelectionImpl(aAction);
     796                 :   }
     797               0 :   if (!cancel)
     798                 :   {
     799                 :     // post-process 
     800               0 :     result = mRules->DidDoAction(selection, &ruleInfo, result);
     801                 :   }
     802                 : 
     803               0 :   return result;
     804                 : }
     805                 : 
     806               0 : NS_IMETHODIMP nsPlaintextEditor::InsertText(const nsAString &aStringToInsert)
     807                 : {
     808               0 :   if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
     809                 : 
     810                 :   // Protect the edit rules object from dying
     811               0 :   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
     812                 : 
     813               0 :   PRInt32 theAction = nsTextEditRules::kInsertText;
     814               0 :   PRInt32 opID = kOpInsertText;
     815               0 :   if (mInIMEMode) 
     816                 :   {
     817               0 :     theAction = nsTextEditRules::kInsertTextIME;
     818               0 :     opID = kOpInsertIMEText;
     819                 :   }
     820               0 :   nsAutoPlaceHolderBatch batch(this, nsnull); 
     821               0 :   nsAutoRules beginRulesSniffing(this, opID, nsIEditor::eNext);
     822                 : 
     823                 :   // pre-process
     824               0 :   nsCOMPtr<nsISelection> selection;
     825               0 :   nsresult result = GetSelection(getter_AddRefs(selection));
     826               0 :   NS_ENSURE_SUCCESS(result, result);
     827               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
     828               0 :   nsAutoString resultString;
     829                 :   // XXX can we trust instring to outlive ruleInfo,
     830                 :   // XXX and ruleInfo not to refer to instring in its dtor?
     831                 :   //nsAutoString instring(aStringToInsert);
     832               0 :   nsTextRulesInfo ruleInfo(theAction);
     833               0 :   ruleInfo.inString = &aStringToInsert;
     834               0 :   ruleInfo.outString = &resultString;
     835               0 :   ruleInfo.maxLength = mMaxTextLength;
     836                 : 
     837                 :   bool cancel, handled;
     838               0 :   result = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
     839               0 :   NS_ENSURE_SUCCESS(result, result);
     840               0 :   if (!cancel && !handled)
     841                 :   {
     842                 :     // we rely on rules code for now - no default implementation
     843                 :   }
     844               0 :   if (!cancel)
     845                 :   {
     846                 :     // post-process 
     847               0 :     result = mRules->DidDoAction(selection, &ruleInfo, result);
     848                 :   }
     849               0 :   return result;
     850                 : }
     851                 : 
     852               0 : NS_IMETHODIMP nsPlaintextEditor::InsertLineBreak()
     853                 : {
     854               0 :   if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
     855                 : 
     856                 :   // Protect the edit rules object from dying
     857               0 :   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
     858                 : 
     859               0 :   nsAutoEditBatch beginBatching(this);
     860               0 :   nsAutoRules beginRulesSniffing(this, kOpInsertBreak, nsIEditor::eNext);
     861                 : 
     862                 :   // pre-process
     863               0 :   nsCOMPtr<nsISelection> selection;
     864                 :   nsresult res;
     865               0 :   res = GetSelection(getter_AddRefs(selection));
     866               0 :   NS_ENSURE_SUCCESS(res, res);
     867               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
     868                 : 
     869                 :   // Batching the selection and moving nodes out from under the caret causes
     870                 :   // caret turds. Ask the shell to invalidate the caret now to avoid the turds.
     871               0 :   nsCOMPtr<nsIPresShell> shell = GetPresShell();
     872               0 :   NS_ENSURE_TRUE(shell, NS_ERROR_NOT_INITIALIZED);
     873               0 :   shell->MaybeInvalidateCaretPosition();
     874                 : 
     875               0 :   nsTextRulesInfo ruleInfo(nsTextEditRules::kInsertBreak);
     876               0 :   ruleInfo.maxLength = mMaxTextLength;
     877                 :   bool cancel, handled;
     878               0 :   res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
     879               0 :   NS_ENSURE_SUCCESS(res, res);
     880               0 :   if (!cancel && !handled)
     881                 :   {
     882                 :     // get the (collapsed) selection location
     883               0 :     nsCOMPtr<nsIDOMNode> selNode;
     884                 :     PRInt32 selOffset;
     885               0 :     res = GetStartNodeAndOffset(selection, getter_AddRefs(selNode), &selOffset);
     886               0 :     NS_ENSURE_SUCCESS(res, res);
     887                 : 
     888                 :     // don't put text in places that can't have it
     889               0 :     if (!IsTextNode(selNode) && !CanContainTag(selNode, NS_LITERAL_STRING("#text")))
     890               0 :       return NS_ERROR_FAILURE;
     891                 : 
     892                 :     // we need to get the doc
     893               0 :     nsCOMPtr<nsIDOMDocument> doc;
     894               0 :     res = GetDocument(getter_AddRefs(doc));
     895               0 :     NS_ENSURE_SUCCESS(res, res);
     896               0 :     NS_ENSURE_TRUE(doc, NS_ERROR_NULL_POINTER);
     897                 : 
     898                 :     // don't spaz my selection in subtransactions
     899               0 :     nsAutoTxnsConserveSelection dontSpazMySelection(this);
     900                 : 
     901                 :     // insert a linefeed character
     902               0 :     res = InsertTextImpl(NS_LITERAL_STRING("\n"), address_of(selNode),
     903               0 :                          &selOffset, doc);
     904               0 :     if (!selNode) res = NS_ERROR_NULL_POINTER; // don't return here, so DidDoAction is called
     905               0 :     if (NS_SUCCEEDED(res))
     906                 :     {
     907                 :       // set the selection to the correct location
     908               0 :       res = selection->Collapse(selNode, selOffset);
     909                 : 
     910               0 :       if (NS_SUCCEEDED(res))
     911                 :       {
     912                 :         // see if we're at the end of the editor range
     913               0 :         nsCOMPtr<nsIDOMNode> endNode;
     914                 :         PRInt32 endOffset;
     915               0 :         res = GetEndNodeAndOffset(selection, getter_AddRefs(endNode), &endOffset);
     916                 : 
     917               0 :         if (NS_SUCCEEDED(res) && endNode == selNode && endOffset == selOffset)
     918                 :         {
     919                 :           // SetInterlinePosition(true) means we want the caret to stick to the content on the "right".
     920                 :           // We want the caret to stick to whatever is past the break.  This is
     921                 :           // because the break is on the same line we were on, but the next content
     922                 :           // will be on the following line.
     923               0 :           nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
     924               0 :           selPriv->SetInterlinePosition(true);
     925                 :         }
     926                 :       }
     927                 :     }
     928                 :   }
     929               0 :   if (!cancel)
     930                 :   {
     931                 :     // post-process, always called if WillInsertBreak didn't return cancel==true
     932               0 :     res = mRules->DidDoAction(selection, &ruleInfo, res);
     933                 :   }
     934                 : 
     935               0 :   return res;
     936                 : }
     937                 : 
     938                 : nsresult
     939               0 : nsPlaintextEditor::BeginIMEComposition()
     940                 : {
     941               0 :   NS_ENSURE_TRUE(!mInIMEMode, NS_OK);
     942                 : 
     943               0 :   if (IsPasswordEditor()) {
     944               0 :     NS_ENSURE_TRUE(mRules, NS_ERROR_NULL_POINTER);
     945                 :     // Protect the edit rules object from dying
     946               0 :     nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
     947                 : 
     948                 :     nsTextEditRules *textEditRules =
     949               0 :       static_cast<nsTextEditRules*>(mRules.get());
     950               0 :     textEditRules->ResetIMETextPWBuf();
     951                 :   }
     952                 : 
     953               0 :   return nsEditor::BeginIMEComposition();
     954                 : }
     955                 : 
     956                 : nsresult
     957               0 : nsPlaintextEditor::UpdateIMEComposition(const nsAString& aCompositionString,
     958                 :                                         nsIPrivateTextRangeList* aTextRangeList)
     959                 : {
     960               0 :   NS_ABORT_IF_FALSE(aTextRangeList, "aTextRangeList must not be NULL");
     961                 : 
     962               0 :   nsCOMPtr<nsIPresShell> ps = GetPresShell();
     963               0 :   NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
     964                 : 
     965               0 :   nsCOMPtr<nsISelection> selection;
     966               0 :   nsresult rv = GetSelection(getter_AddRefs(selection));
     967               0 :   NS_ENSURE_SUCCESS(rv, rv);
     968                 : 
     969               0 :   nsRefPtr<nsCaret> caretP = ps->GetCaret();
     970                 : 
     971                 :   // Update information of clauses in the new composition string.
     972                 :   // This will be refered by followed methods.
     973               0 :   mIMETextRangeList = aTextRangeList;
     974                 : 
     975                 :   // We set mIsIMEComposing properly.
     976               0 :   SetIsIMEComposing();
     977                 : 
     978                 :   {
     979               0 :     nsAutoPlaceHolderBatch batch(this, nsGkAtoms::IMETxnName);
     980                 : 
     981               0 :     rv = InsertText(aCompositionString);
     982                 : 
     983               0 :     mIMEBufferLength = aCompositionString.Length();
     984                 : 
     985               0 :     if (caretP) {
     986               0 :       caretP->SetCaretDOMSelection(selection);
     987                 :     }
     988                 :   }
     989                 : 
     990                 :   // If still composing, we should fire input event via observer.
     991                 :   // Note that if committed, we don't need to notify it since it will be
     992                 :   // notified at followed compositionend event.
     993                 :   // NOTE: We must notify after the auto batch will be gone.
     994               0 :   if (mIsIMEComposing) {
     995               0 :     NotifyEditorObservers();
     996                 :   }
     997                 : 
     998               0 :   return rv;
     999                 : }
    1000                 : 
    1001                 : NS_IMETHODIMP
    1002               0 : nsPlaintextEditor::GetDocumentIsEmpty(bool *aDocumentIsEmpty)
    1003                 : {
    1004               0 :   NS_ENSURE_TRUE(aDocumentIsEmpty, NS_ERROR_NULL_POINTER);
    1005                 :   
    1006               0 :   NS_ENSURE_TRUE(mRules, NS_ERROR_NOT_INITIALIZED);
    1007                 : 
    1008                 :   // Protect the edit rules object from dying
    1009               0 :   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
    1010                 :   
    1011               0 :   return mRules->DocumentIsEmpty(aDocumentIsEmpty);
    1012                 : }
    1013                 : 
    1014                 : NS_IMETHODIMP
    1015               0 : nsPlaintextEditor::GetTextLength(PRInt32 *aCount)
    1016                 : {
    1017               0 :   NS_ASSERTION(aCount, "null pointer");
    1018                 : 
    1019                 :   // initialize out params
    1020               0 :   *aCount = 0;
    1021                 :   
    1022                 :   // special-case for empty document, to account for the bogus node
    1023                 :   bool docEmpty;
    1024               0 :   nsresult rv = GetDocumentIsEmpty(&docEmpty);
    1025               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1026               0 :   if (docEmpty)
    1027               0 :     return NS_OK;
    1028                 : 
    1029               0 :   dom::Element *rootElement = GetRoot();
    1030               0 :   NS_ENSURE_TRUE(rootElement, NS_ERROR_NULL_POINTER);
    1031                 : 
    1032                 :   nsCOMPtr<nsIContentIterator> iter =
    1033               0 :     do_CreateInstance("@mozilla.org/content/post-content-iterator;1", &rv);
    1034               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1035                 : 
    1036               0 :   PRUint32 totalLength = 0;
    1037               0 :   iter->Init(rootElement);
    1038               0 :   for (; !iter->IsDone(); iter->Next()) {
    1039               0 :     nsCOMPtr<nsIDOMNode> currentNode = do_QueryInterface(iter->GetCurrentNode());
    1040               0 :     nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(currentNode);
    1041               0 :     if (textNode && IsEditable(currentNode)) {
    1042                 :       PRUint32 length;
    1043               0 :       textNode->GetLength(&length);
    1044               0 :       totalLength += length;
    1045                 :     }
    1046                 :   }
    1047                 : 
    1048               0 :   *aCount = totalLength;
    1049               0 :   return NS_OK;
    1050                 : }
    1051                 : 
    1052                 : NS_IMETHODIMP
    1053               0 : nsPlaintextEditor::SetMaxTextLength(PRInt32 aMaxTextLength)
    1054                 : {
    1055               0 :   mMaxTextLength = aMaxTextLength;
    1056               0 :   return NS_OK;
    1057                 : }
    1058                 : 
    1059                 : NS_IMETHODIMP
    1060               0 : nsPlaintextEditor::GetMaxTextLength(PRInt32* aMaxTextLength)
    1061                 : {
    1062               0 :   NS_ENSURE_TRUE(aMaxTextLength, NS_ERROR_INVALID_POINTER);
    1063               0 :   *aMaxTextLength = mMaxTextLength;
    1064               0 :   return NS_OK;
    1065                 : }
    1066                 : 
    1067                 : //
    1068                 : // Get the wrap width
    1069                 : //
    1070                 : NS_IMETHODIMP 
    1071               0 : nsPlaintextEditor::GetWrapWidth(PRInt32 *aWrapColumn)
    1072                 : {
    1073               0 :   NS_ENSURE_TRUE( aWrapColumn, NS_ERROR_NULL_POINTER);
    1074                 : 
    1075               0 :   *aWrapColumn = mWrapColumn;
    1076               0 :   return NS_OK;
    1077                 : }
    1078                 : 
    1079                 : //
    1080                 : // See if the style value includes this attribute, and if it does,
    1081                 : // cut out everything from the attribute to the next semicolon.
    1082                 : //
    1083               0 : static void CutStyle(const char* stylename, nsString& styleValue)
    1084                 : {
    1085                 :   // Find the current wrapping type:
    1086               0 :   PRInt32 styleStart = styleValue.Find(stylename, true);
    1087               0 :   if (styleStart >= 0)
    1088                 :   {
    1089               0 :     PRInt32 styleEnd = styleValue.Find(";", false, styleStart);
    1090               0 :     if (styleEnd > styleStart)
    1091               0 :       styleValue.Cut(styleStart, styleEnd - styleStart + 1);
    1092                 :     else
    1093               0 :       styleValue.Cut(styleStart, styleValue.Length() - styleStart);
    1094                 :   }
    1095               0 : }
    1096                 : 
    1097                 : //
    1098                 : // Change the wrap width on the root of this document.
    1099                 : // 
    1100                 : NS_IMETHODIMP 
    1101               0 : nsPlaintextEditor::SetWrapWidth(PRInt32 aWrapColumn)
    1102                 : {
    1103               0 :   SetWrapColumn(aWrapColumn);
    1104                 : 
    1105                 :   // Make sure we're a plaintext editor, otherwise we shouldn't
    1106                 :   // do the rest of this.
    1107               0 :   if (!IsPlaintextEditor())
    1108               0 :     return NS_OK;
    1109                 : 
    1110                 :   // Ought to set a style sheet here ...
    1111                 :   // Probably should keep around an mPlaintextStyleSheet for this purpose.
    1112               0 :   dom::Element *rootElement = GetRoot();
    1113               0 :   NS_ENSURE_TRUE(rootElement, NS_ERROR_NULL_POINTER);
    1114                 : 
    1115                 :   // Get the current style for this root element:
    1116               0 :   nsAutoString styleValue;
    1117               0 :   nsresult res = rootElement->GetAttr(kNameSpaceID_None, nsGkAtoms::style, styleValue);
    1118               0 :   NS_ENSURE_SUCCESS(res, res);
    1119                 : 
    1120                 :   // We'll replace styles for these values:
    1121               0 :   CutStyle("white-space", styleValue);
    1122               0 :   CutStyle("width", styleValue);
    1123               0 :   CutStyle("font-family", styleValue);
    1124                 : 
    1125                 :   // If we have other style left, trim off any existing semicolons
    1126                 :   // or whitespace, then add a known semicolon-space:
    1127               0 :   if (!styleValue.IsEmpty())
    1128                 :   {
    1129               0 :     styleValue.Trim("; \t", false, true);
    1130               0 :     styleValue.AppendLiteral("; ");
    1131                 :   }
    1132                 : 
    1133                 :   // Make sure we have fixed-width font.  This should be done for us,
    1134                 :   // but it isn't, see bug 22502, so we have to add "font: -moz-fixed;".
    1135                 :   // Only do this if we're wrapping.
    1136               0 :   if (IsWrapHackEnabled() && aWrapColumn >= 0)
    1137               0 :     styleValue.AppendLiteral("font-family: -moz-fixed; ");
    1138                 : 
    1139                 :   // If "mail.compose.wrap_to_window_width" is set, and we're a mail editor,
    1140                 :   // then remember our wrap width (for output purposes) but set the visual
    1141                 :   // wrapping to window width.
    1142                 :   // We may reset mWrapToWindow here, based on the pref's current value.
    1143               0 :   if (IsMailEditor())
    1144                 :   {
    1145                 :     mWrapToWindow =
    1146               0 :       Preferences::GetBool("mail.compose.wrap_to_window_width", mWrapToWindow);
    1147                 :   }
    1148                 : 
    1149                 :   // and now we're ready to set the new whitespace/wrapping style.
    1150               0 :   if (aWrapColumn > 0 && !mWrapToWindow)        // Wrap to a fixed column
    1151                 :   {
    1152               0 :     styleValue.AppendLiteral("white-space: pre-wrap; width: ");
    1153               0 :     styleValue.AppendInt(aWrapColumn);
    1154               0 :     styleValue.AppendLiteral("ch;");
    1155                 :   }
    1156               0 :   else if (mWrapToWindow || aWrapColumn == 0)
    1157               0 :     styleValue.AppendLiteral("white-space: pre-wrap;");
    1158                 :   else
    1159               0 :     styleValue.AppendLiteral("white-space: pre;");
    1160                 : 
    1161               0 :   return rootElement->SetAttr(kNameSpaceID_None, nsGkAtoms::style, styleValue, true);
    1162                 : }
    1163                 : 
    1164                 : NS_IMETHODIMP 
    1165               0 : nsPlaintextEditor::SetWrapColumn(PRInt32 aWrapColumn)
    1166                 : {
    1167               0 :   mWrapColumn = aWrapColumn;
    1168               0 :   return NS_OK;
    1169                 : }
    1170                 : 
    1171                 : //
    1172                 : // Get the newline handling for this editor
    1173                 : //
    1174                 : NS_IMETHODIMP 
    1175               0 : nsPlaintextEditor::GetNewlineHandling(PRInt32 *aNewlineHandling)
    1176                 : {
    1177               0 :   NS_ENSURE_ARG_POINTER(aNewlineHandling);
    1178                 : 
    1179               0 :   *aNewlineHandling = mNewlineHandling;
    1180               0 :   return NS_OK;
    1181                 : }
    1182                 : 
    1183                 : //
    1184                 : // Change the newline handling for this editor
    1185                 : // 
    1186                 : NS_IMETHODIMP 
    1187               0 : nsPlaintextEditor::SetNewlineHandling(PRInt32 aNewlineHandling)
    1188                 : {
    1189               0 :   mNewlineHandling = aNewlineHandling;
    1190                 :   
    1191               0 :   return NS_OK;
    1192                 : }
    1193                 : 
    1194                 : NS_IMETHODIMP 
    1195               0 : nsPlaintextEditor::Undo(PRUint32 aCount)
    1196                 : {
    1197                 :   // Protect the edit rules object from dying
    1198               0 :   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
    1199                 : 
    1200               0 :   FireTrustedInputEvent trusted(this);
    1201                 : 
    1202               0 :   nsAutoUpdateViewBatch beginViewBatching(this);
    1203                 : 
    1204               0 :   ForceCompositionEnd();
    1205                 : 
    1206               0 :   nsAutoRules beginRulesSniffing(this, kOpUndo, nsIEditor::eNone);
    1207                 : 
    1208               0 :   nsTextRulesInfo ruleInfo(nsTextEditRules::kUndo);
    1209               0 :   nsCOMPtr<nsISelection> selection;
    1210               0 :   GetSelection(getter_AddRefs(selection));
    1211                 :   bool cancel, handled;
    1212               0 :   nsresult result = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
    1213                 :   
    1214               0 :   if (!cancel && NS_SUCCEEDED(result))
    1215                 :   {
    1216               0 :     result = nsEditor::Undo(aCount);
    1217               0 :     result = mRules->DidDoAction(selection, &ruleInfo, result);
    1218                 :   } 
    1219                 :    
    1220               0 :   NotifyEditorObservers();
    1221               0 :   return result;
    1222                 : }
    1223                 : 
    1224                 : NS_IMETHODIMP 
    1225               0 : nsPlaintextEditor::Redo(PRUint32 aCount)
    1226                 : {
    1227                 :   // Protect the edit rules object from dying
    1228               0 :   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
    1229                 : 
    1230               0 :   FireTrustedInputEvent trusted(this);
    1231                 : 
    1232               0 :   nsAutoUpdateViewBatch beginViewBatching(this);
    1233                 : 
    1234               0 :   ForceCompositionEnd();
    1235                 : 
    1236               0 :   nsAutoRules beginRulesSniffing(this, kOpRedo, nsIEditor::eNone);
    1237                 : 
    1238               0 :   nsTextRulesInfo ruleInfo(nsTextEditRules::kRedo);
    1239               0 :   nsCOMPtr<nsISelection> selection;
    1240               0 :   GetSelection(getter_AddRefs(selection));
    1241                 :   bool cancel, handled;
    1242               0 :   nsresult result = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
    1243                 :   
    1244               0 :   if (!cancel && NS_SUCCEEDED(result))
    1245                 :   {
    1246               0 :     result = nsEditor::Redo(aCount);
    1247               0 :     result = mRules->DidDoAction(selection, &ruleInfo, result);
    1248                 :   } 
    1249                 :    
    1250               0 :   NotifyEditorObservers();
    1251               0 :   return result;
    1252                 : }
    1253                 : 
    1254                 : bool
    1255               0 : nsPlaintextEditor::CanCutOrCopy()
    1256                 : {
    1257               0 :   nsCOMPtr<nsISelection> selection;
    1258               0 :   if (NS_FAILED(GetSelection(getter_AddRefs(selection))))
    1259               0 :     return false;
    1260                 : 
    1261                 :   bool isCollapsed;
    1262               0 :   selection->GetIsCollapsed(&isCollapsed);
    1263               0 :   return !isCollapsed;
    1264                 : }
    1265                 : 
    1266                 : bool
    1267               0 : nsPlaintextEditor::FireClipboardEvent(PRInt32 aType)
    1268                 : {
    1269               0 :   if (aType == NS_PASTE)
    1270               0 :     ForceCompositionEnd();
    1271                 : 
    1272               0 :   nsCOMPtr<nsIPresShell> presShell = GetPresShell();
    1273               0 :   NS_ENSURE_TRUE(presShell, false);
    1274                 : 
    1275               0 :   nsCOMPtr<nsISelection> selection;
    1276               0 :   if (NS_FAILED(GetSelection(getter_AddRefs(selection))))
    1277               0 :     return false;
    1278                 : 
    1279               0 :   if (!nsCopySupport::FireClipboardEvent(aType, presShell, selection))
    1280               0 :     return false;
    1281                 : 
    1282                 :   // If the event handler caused the editor to be destroyed, return false.
    1283                 :   // Otherwise return true to indicate that the event was not cancelled.
    1284               0 :   return !mDidPreDestroy;
    1285                 : }
    1286                 : 
    1287               0 : NS_IMETHODIMP nsPlaintextEditor::Cut()
    1288                 : {
    1289               0 :   FireTrustedInputEvent trusted(this);
    1290                 : 
    1291               0 :   if (FireClipboardEvent(NS_CUT))
    1292               0 :     return DeleteSelection(eNone);
    1293               0 :   return NS_OK;
    1294                 : }
    1295                 : 
    1296               0 : NS_IMETHODIMP nsPlaintextEditor::CanCut(bool *aCanCut)
    1297                 : {
    1298               0 :   NS_ENSURE_ARG_POINTER(aCanCut);
    1299               0 :   *aCanCut = IsModifiable() && CanCutOrCopy();
    1300               0 :   return NS_OK;
    1301                 : }
    1302                 : 
    1303               0 : NS_IMETHODIMP nsPlaintextEditor::Copy()
    1304                 : {
    1305               0 :   FireClipboardEvent(NS_COPY);
    1306               0 :   return NS_OK;
    1307                 : }
    1308                 : 
    1309               0 : NS_IMETHODIMP nsPlaintextEditor::CanCopy(bool *aCanCopy)
    1310                 : {
    1311               0 :   NS_ENSURE_ARG_POINTER(aCanCopy);
    1312               0 :   *aCanCopy = CanCutOrCopy();
    1313               0 :   return NS_OK;
    1314                 : }
    1315                 : 
    1316                 : // Shared between OutputToString and OutputToStream
    1317                 : NS_IMETHODIMP
    1318               0 : nsPlaintextEditor::GetAndInitDocEncoder(const nsAString& aFormatType,
    1319                 :                                         PRUint32 aFlags,
    1320                 :                                         const nsACString& aCharset,
    1321                 :                                         nsIDocumentEncoder** encoder)
    1322                 : {
    1323               0 :   nsresult rv = NS_OK;
    1324                 : 
    1325               0 :   nsCAutoString formatType(NS_DOC_ENCODER_CONTRACTID_BASE);
    1326               0 :   formatType.AppendWithConversion(aFormatType);
    1327               0 :   nsCOMPtr<nsIDocumentEncoder> docEncoder (do_CreateInstance(formatType.get(), &rv));
    1328               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1329                 : 
    1330               0 :   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryReferent(mDocWeak);
    1331               0 :   NS_ASSERTION(domDoc, "Need a document");
    1332                 : 
    1333               0 :   rv = docEncoder->Init(domDoc, aFormatType, aFlags);
    1334               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1335                 : 
    1336               0 :   if (!aCharset.IsEmpty() && !aCharset.EqualsLiteral("null")) {
    1337               0 :     docEncoder->SetCharset(aCharset);
    1338                 :   }
    1339                 : 
    1340                 :   PRInt32 wc;
    1341               0 :   (void) GetWrapWidth(&wc);
    1342               0 :   if (wc >= 0)
    1343               0 :     (void) docEncoder->SetWrapColumn(wc);
    1344                 : 
    1345                 :   // Set the selection, if appropriate.
    1346                 :   // We do this either if the OutputSelectionOnly flag is set,
    1347                 :   // in which case we use our existing selection ...
    1348               0 :   if (aFlags & nsIDocumentEncoder::OutputSelectionOnly)
    1349                 :   {
    1350               0 :     nsCOMPtr<nsISelection> selection;
    1351               0 :     rv = GetSelection(getter_AddRefs(selection));
    1352               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1353               0 :     if (selection) {
    1354               0 :       rv = docEncoder->SetSelection(selection);
    1355               0 :       NS_ENSURE_SUCCESS(rv, rv);
    1356                 :     }
    1357                 :   }
    1358                 :   // ... or if the root element is not a body,
    1359                 :   // in which case we set the selection to encompass the root.
    1360                 :   else
    1361                 :   {
    1362               0 :     dom::Element* rootElement = GetRoot();
    1363               0 :     NS_ENSURE_TRUE(rootElement, NS_ERROR_FAILURE);
    1364               0 :     if (!rootElement->IsHTML(nsGkAtoms::body)) {
    1365               0 :       rv = docEncoder->SetNativeContainerNode(rootElement);
    1366               0 :       NS_ENSURE_SUCCESS(rv, rv);
    1367                 :     }
    1368                 :   }
    1369                 : 
    1370               0 :   docEncoder.forget(encoder);
    1371               0 :   return NS_OK;
    1372                 : }
    1373                 : 
    1374                 : 
    1375                 : NS_IMETHODIMP 
    1376               0 : nsPlaintextEditor::OutputToString(const nsAString& aFormatType,
    1377                 :                                   PRUint32 aFlags,
    1378                 :                                   nsAString& aOutputString)
    1379                 : {
    1380                 :   // Protect the edit rules object from dying
    1381               0 :   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
    1382                 : 
    1383               0 :   nsString resultString;
    1384               0 :   nsTextRulesInfo ruleInfo(nsTextEditRules::kOutputText);
    1385               0 :   ruleInfo.outString = &resultString;
    1386                 :   // XXX Struct should store a nsAReadable*
    1387               0 :   nsAutoString str(aFormatType);
    1388               0 :   ruleInfo.outputFormat = &str;
    1389                 :   bool cancel, handled;
    1390               0 :   nsresult rv = mRules->WillDoAction(nsnull, &ruleInfo, &cancel, &handled);
    1391               0 :   if (cancel || NS_FAILED(rv)) { return rv; }
    1392               0 :   if (handled)
    1393                 :   { // this case will get triggered by password fields
    1394               0 :     aOutputString.Assign(*(ruleInfo.outString));
    1395               0 :     return rv;
    1396                 :   }
    1397                 : 
    1398               0 :   nsCAutoString charsetStr;
    1399               0 :   rv = GetDocumentCharacterSet(charsetStr);
    1400               0 :   if(NS_FAILED(rv) || charsetStr.IsEmpty())
    1401               0 :     charsetStr.AssignLiteral("ISO-8859-1");
    1402                 : 
    1403               0 :   nsCOMPtr<nsIDocumentEncoder> encoder;
    1404               0 :   rv = GetAndInitDocEncoder(aFormatType, aFlags, charsetStr, getter_AddRefs(encoder));
    1405               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1406               0 :   return encoder->EncodeToString(aOutputString);
    1407                 : }
    1408                 : 
    1409                 : NS_IMETHODIMP
    1410               0 : nsPlaintextEditor::OutputToStream(nsIOutputStream* aOutputStream,
    1411                 :                              const nsAString& aFormatType,
    1412                 :                              const nsACString& aCharset,
    1413                 :                              PRUint32 aFlags)
    1414                 : {
    1415                 :   nsresult rv;
    1416                 : 
    1417                 :   // special-case for empty document when requesting plain text,
    1418                 :   // to account for the bogus text node.
    1419                 :   // XXX Should there be a similar test in OutputToString?
    1420               0 :   if (aFormatType.EqualsLiteral("text/plain"))
    1421                 :   {
    1422                 :     bool docEmpty;
    1423               0 :     rv = GetDocumentIsEmpty(&docEmpty);
    1424               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1425                 :     
    1426               0 :     if (docEmpty)
    1427               0 :        return NS_OK;    // output nothing
    1428                 :   }
    1429                 : 
    1430               0 :   nsCOMPtr<nsIDocumentEncoder> encoder;
    1431                 :   rv = GetAndInitDocEncoder(aFormatType, aFlags, aCharset,
    1432               0 :                             getter_AddRefs(encoder));
    1433                 : 
    1434               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1435                 : 
    1436               0 :   return encoder->EncodeToStream(aOutputStream);
    1437                 : }
    1438                 : 
    1439                 : NS_IMETHODIMP
    1440               0 : nsPlaintextEditor::InsertTextWithQuotations(const nsAString &aStringToInsert)
    1441                 : {
    1442               0 :   return InsertText(aStringToInsert);
    1443                 : }
    1444                 : 
    1445                 : NS_IMETHODIMP
    1446               0 : nsPlaintextEditor::PasteAsQuotation(PRInt32 aSelectionType)
    1447                 : {
    1448                 :   // Get Clipboard Service
    1449                 :   nsresult rv;
    1450               0 :   nsCOMPtr<nsIClipboard> clipboard(do_GetService("@mozilla.org/widget/clipboard;1", &rv));
    1451               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1452                 : 
    1453                 :   // Create generic Transferable for getting the data
    1454               0 :   nsCOMPtr<nsITransferable> trans = do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
    1455               0 :   if (NS_SUCCEEDED(rv) && trans)
    1456                 :   {
    1457                 :     // We only handle plaintext pastes here
    1458               0 :     trans->AddDataFlavor(kUnicodeMime);
    1459                 : 
    1460                 :     // Get the Data from the clipboard
    1461               0 :     clipboard->GetData(trans, aSelectionType);
    1462                 : 
    1463                 :     // Now we ask the transferable for the data
    1464                 :     // it still owns the data, we just have a pointer to it.
    1465                 :     // If it can't support a "text" output of the data the call will fail
    1466               0 :     nsCOMPtr<nsISupports> genericDataObj;
    1467                 :     PRUint32 len;
    1468               0 :     char* flav = nsnull;
    1469               0 :     rv = trans->GetAnyTransferData(&flav, getter_AddRefs(genericDataObj),
    1470               0 :                                    &len);
    1471               0 :     if (NS_FAILED(rv) || !flav)
    1472                 :     {
    1473                 : #ifdef DEBUG_akkana
    1474                 :       printf("PasteAsPlaintextQuotation: GetAnyTransferData failed, %d\n", rv);
    1475                 : #endif
    1476               0 :       return rv;
    1477                 :     }
    1478                 : #ifdef DEBUG_clipboard
    1479                 :     printf("Got flavor [%s]\n", flav);
    1480                 : #endif
    1481               0 :     if (0 == nsCRT::strcmp(flav, kUnicodeMime))
    1482                 :     {
    1483               0 :       nsCOMPtr<nsISupportsString> textDataObj ( do_QueryInterface(genericDataObj) );
    1484               0 :       if (textDataObj && len > 0)
    1485                 :       {
    1486               0 :         nsAutoString stuffToPaste;
    1487               0 :         textDataObj->GetData ( stuffToPaste );
    1488               0 :         nsAutoEditBatch beginBatching(this);
    1489               0 :         rv = InsertAsQuotation(stuffToPaste, 0);
    1490                 :       }
    1491                 :     }
    1492               0 :     NS_Free(flav);
    1493                 :   }
    1494                 : 
    1495               0 :   return rv;
    1496                 : }
    1497                 : 
    1498                 : NS_IMETHODIMP
    1499               0 : nsPlaintextEditor::InsertAsQuotation(const nsAString& aQuotedText,
    1500                 :                                      nsIDOMNode **aNodeInserted)
    1501                 : {
    1502                 :   // Protect the edit rules object from dying
    1503               0 :   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
    1504                 : 
    1505                 :   // Let the citer quote it for us:
    1506               0 :   nsString quotedStuff;
    1507               0 :   nsresult rv = nsInternetCiter::GetCiteString(aQuotedText, quotedStuff);
    1508               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1509                 : 
    1510                 :   // It's best to put a blank line after the quoted text so that mails
    1511                 :   // written without thinking won't be so ugly.
    1512               0 :   if (!aQuotedText.IsEmpty() && (aQuotedText.Last() != PRUnichar('\n')))
    1513               0 :     quotedStuff.Append(PRUnichar('\n'));
    1514                 : 
    1515                 :   // get selection
    1516               0 :   nsCOMPtr<nsISelection> selection;
    1517               0 :   rv = GetSelection(getter_AddRefs(selection));
    1518               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1519               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
    1520                 : 
    1521               0 :   nsAutoEditBatch beginBatching(this);
    1522               0 :   nsAutoRules beginRulesSniffing(this, kOpInsertText, nsIEditor::eNext);
    1523                 : 
    1524                 :   // give rules a chance to handle or cancel
    1525               0 :   nsTextRulesInfo ruleInfo(nsTextEditRules::kInsertElement);
    1526                 :   bool cancel, handled;
    1527               0 :   rv = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
    1528               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1529               0 :   if (cancel) return NS_OK; // rules canceled the operation
    1530               0 :   if (!handled)
    1531                 :   {
    1532               0 :     rv = InsertText(quotedStuff);
    1533                 : 
    1534                 :     // XXX Should set *aNodeInserted to the first node inserted
    1535               0 :     if (aNodeInserted && NS_SUCCEEDED(rv))
    1536                 :     {
    1537               0 :       *aNodeInserted = 0;
    1538                 :       //NS_IF_ADDREF(*aNodeInserted);
    1539                 :     }
    1540                 :   }
    1541               0 :   return rv;
    1542                 : }
    1543                 : 
    1544                 : NS_IMETHODIMP
    1545               0 : nsPlaintextEditor::PasteAsCitedQuotation(const nsAString& aCitation,
    1546                 :                                          PRInt32 aSelectionType)
    1547                 : {
    1548               0 :   return NS_ERROR_NOT_IMPLEMENTED;
    1549                 : }
    1550                 : 
    1551                 : NS_IMETHODIMP
    1552               0 : nsPlaintextEditor::InsertAsCitedQuotation(const nsAString& aQuotedText,
    1553                 :                                           const nsAString& aCitation,
    1554                 :                                           bool aInsertHTML,
    1555                 :                                           nsIDOMNode **aNodeInserted)
    1556                 : {
    1557               0 :   return InsertAsQuotation(aQuotedText, aNodeInserted);
    1558                 : }
    1559                 : 
    1560                 : nsresult
    1561               0 : nsPlaintextEditor::SharedOutputString(PRUint32 aFlags,
    1562                 :                                       bool* aIsCollapsed,
    1563                 :                                       nsAString& aResult)
    1564                 : {
    1565               0 :   nsCOMPtr<nsISelection> selection;
    1566               0 :   nsresult rv = GetSelection(getter_AddRefs(selection));
    1567               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1568               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NOT_INITIALIZED);
    1569                 : 
    1570               0 :   rv = selection->GetIsCollapsed(aIsCollapsed);
    1571               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1572                 : 
    1573               0 :   if (!*aIsCollapsed)
    1574               0 :     aFlags |= nsIDocumentEncoder::OutputSelectionOnly;
    1575                 :   // If the selection isn't collapsed, we'll use the whole document.
    1576                 : 
    1577               0 :   return OutputToString(NS_LITERAL_STRING("text/plain"), aFlags, aResult);
    1578                 : }
    1579                 : 
    1580                 : NS_IMETHODIMP
    1581               0 : nsPlaintextEditor::Rewrap(bool aRespectNewlines)
    1582                 : {
    1583                 :   PRInt32 wrapCol;
    1584               0 :   nsresult rv = GetWrapWidth(&wrapCol);
    1585               0 :   NS_ENSURE_SUCCESS(rv, NS_OK);
    1586                 : 
    1587                 :   // Rewrap makes no sense if there's no wrap column; default to 72.
    1588               0 :   if (wrapCol <= 0)
    1589               0 :     wrapCol = 72;
    1590                 : 
    1591                 : #ifdef DEBUG_akkana
    1592                 :   printf("nsPlaintextEditor::Rewrap to %ld columns\n", (long)wrapCol);
    1593                 : #endif
    1594                 : 
    1595               0 :   nsAutoString current;
    1596                 :   bool isCollapsed;
    1597                 :   rv = SharedOutputString(nsIDocumentEncoder::OutputFormatted
    1598                 :                           | nsIDocumentEncoder::OutputLFLineBreak,
    1599               0 :                           &isCollapsed, current);
    1600               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1601                 : 
    1602               0 :   nsString wrapped;
    1603               0 :   PRUint32 firstLineOffset = 0;   // XXX need to reset this if there is a selection
    1604                 :   rv = nsInternetCiter::Rewrap(current, wrapCol, firstLineOffset, aRespectNewlines,
    1605               0 :                      wrapped);
    1606               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1607                 : 
    1608               0 :   if (isCollapsed)    // rewrap the whole document
    1609               0 :     SelectAll();
    1610                 : 
    1611               0 :   return InsertTextWithQuotations(wrapped);
    1612                 : }
    1613                 : 
    1614                 : NS_IMETHODIMP    
    1615               0 : nsPlaintextEditor::StripCites()
    1616                 : {
    1617                 : #ifdef DEBUG_akkana
    1618                 :   printf("nsPlaintextEditor::StripCites()\n");
    1619                 : #endif
    1620                 : 
    1621               0 :   nsAutoString current;
    1622                 :   bool isCollapsed;
    1623                 :   nsresult rv = SharedOutputString(nsIDocumentEncoder::OutputFormatted,
    1624               0 :                                    &isCollapsed, current);
    1625               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1626                 : 
    1627               0 :   nsString stripped;
    1628               0 :   rv = nsInternetCiter::StripCites(current, stripped);
    1629               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1630                 : 
    1631               0 :   if (isCollapsed)    // rewrap the whole document
    1632                 :   {
    1633               0 :     rv = SelectAll();
    1634               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1635                 :   }
    1636                 : 
    1637               0 :   return InsertText(stripped);
    1638                 : }
    1639                 : 
    1640                 : NS_IMETHODIMP
    1641               0 : nsPlaintextEditor::GetEmbeddedObjects(nsISupportsArray** aNodeList)
    1642                 : {
    1643               0 :   *aNodeList = 0;
    1644               0 :   return NS_OK;
    1645                 : }
    1646                 : 
    1647                 : 
    1648                 : /** All editor operations which alter the doc should be prefaced
    1649                 :  *  with a call to StartOperation, naming the action and direction */
    1650                 : NS_IMETHODIMP
    1651               0 : nsPlaintextEditor::StartOperation(PRInt32 opID, nsIEditor::EDirection aDirection)
    1652                 : {
    1653                 :   // Protect the edit rules object from dying
    1654               0 :   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
    1655                 : 
    1656               0 :   nsEditor::StartOperation(opID, aDirection);  // will set mAction, mDirection
    1657               0 :   if (mRules) return mRules->BeforeEdit(mAction, mDirection);
    1658               0 :   return NS_OK;
    1659                 : }
    1660                 : 
    1661                 : 
    1662                 : /** All editor operations which alter the doc should be followed
    1663                 :  *  with a call to EndOperation */
    1664                 : NS_IMETHODIMP
    1665               0 : nsPlaintextEditor::EndOperation()
    1666                 : {
    1667                 :   // Protect the edit rules object from dying
    1668               0 :   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
    1669                 : 
    1670                 :   // post processing
    1671               0 :   nsresult res = NS_OK;
    1672               0 :   if (mRules) res = mRules->AfterEdit(mAction, mDirection);
    1673               0 :   nsEditor::EndOperation();  // will clear mAction, mDirection
    1674               0 :   return res;
    1675                 : }  
    1676                 : 
    1677                 : 
    1678                 : NS_IMETHODIMP 
    1679               0 : nsPlaintextEditor::SelectEntireDocument(nsISelection *aSelection)
    1680                 : {
    1681               0 :   if (!aSelection || !mRules) { return NS_ERROR_NULL_POINTER; }
    1682                 : 
    1683                 :   // Protect the edit rules object from dying
    1684               0 :   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
    1685                 : 
    1686                 :   // is doc empty?
    1687                 :   bool bDocIsEmpty;
    1688               0 :   if (NS_SUCCEEDED(mRules->DocumentIsEmpty(&bDocIsEmpty)) && bDocIsEmpty)
    1689                 :   {
    1690                 :     // get root node
    1691               0 :     nsCOMPtr<nsIDOMElement> rootElement = do_QueryInterface(GetRoot());
    1692               0 :     NS_ENSURE_TRUE(rootElement, NS_ERROR_FAILURE);
    1693                 : 
    1694                 :     // if it's empty don't select entire doc - that would select the bogus node
    1695               0 :     return aSelection->Collapse(rootElement, 0);
    1696                 :   }
    1697                 : 
    1698               0 :   nsresult rv = nsEditor::SelectEntireDocument(aSelection);
    1699               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1700                 : 
    1701                 :   // Don't select the trailing BR node if we have one
    1702                 :   PRInt32 selOffset;
    1703               0 :   nsCOMPtr<nsIDOMNode> selNode;
    1704               0 :   rv = GetEndNodeAndOffset(aSelection, getter_AddRefs(selNode), &selOffset);
    1705               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1706                 : 
    1707               0 :   nsCOMPtr<nsIDOMNode> childNode = GetChildAt(selNode, selOffset - 1);
    1708                 : 
    1709               0 :   if (childNode && nsTextEditUtils::IsMozBR(childNode)) {
    1710               0 :     nsCOMPtr<nsIDOMNode> parentNode;
    1711                 :     PRInt32 parentOffset;
    1712               0 :     rv = GetNodeLocation(childNode, address_of(parentNode), &parentOffset);
    1713               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1714                 : 
    1715               0 :     return aSelection->Extend(parentNode, parentOffset);
    1716                 :   }
    1717                 : 
    1718               0 :   return NS_OK;
    1719                 : }
    1720                 : 
    1721                 : already_AddRefed<nsIDOMEventTarget>
    1722               0 : nsPlaintextEditor::GetDOMEventTarget()
    1723                 : {
    1724               0 :   nsCOMPtr<nsIDOMEventTarget> copy = mEventTarget;
    1725               0 :   return copy.forget();
    1726                 : }
    1727                 : 
    1728                 : 
    1729                 : nsresult
    1730               0 : nsPlaintextEditor::SetAttributeOrEquivalent(nsIDOMElement * aElement,
    1731                 :                                             const nsAString & aAttribute,
    1732                 :                                             const nsAString & aValue,
    1733                 :                                             bool aSuppressTransaction)
    1734                 : {
    1735               0 :   return nsEditor::SetAttribute(aElement, aAttribute, aValue);
    1736                 : }
    1737                 : 
    1738                 : nsresult
    1739               0 : nsPlaintextEditor::RemoveAttributeOrEquivalent(nsIDOMElement * aElement,
    1740                 :                                                const nsAString & aAttribute,
    1741                 :                                                bool aSuppressTransaction)
    1742                 : {
    1743               0 :   return nsEditor::RemoveAttribute(aElement, aAttribute);
    1744            4392 : }

Generated by: LCOV version 1.7