LCOV - code coverage report
Current view: top level - editor/libeditor - TextEditor.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 111 755 14.7 %
Date: 2017-07-14 16:53:18 Functions: 20 68 29.4 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13