Bug 1540043 - part 2: Make comm-central stop using `nsIPlaintextEditor` interface r=jorgk
authorMasayuki Nakano <masayuki@d-toybox.com>
Mon, 27 Jan 2020 15:51:12 +0900
changeset 38049 857a1d5c45074840d913440bf8151d79198b98cf
parent 38048 779c55ffd47b1ced2db5ba5397c4c42b9300ad47
child 38050 a2cc7c9b4a0635baabcb037cc89c1c5a59f1d4fa
push id398
push userclokep@gmail.com
push dateMon, 09 Mar 2020 19:10:28 +0000
reviewersjorgk
bugs1540043
Bug 1540043 - part 2: Make comm-central stop using `nsIPlaintextEditor` interface r=jorgk
editor/ui/composer/content/ComposerCommands.js
editor/ui/composer/content/editingOverlay.js
editor/ui/composer/content/editor.js
editor/ui/composer/content/editorUtilities.js
editor/ui/dialogs/content/EdDialogCommon.js
editor/ui/dialogs/content/EdImageLinkLoader.js
editor/ui/dialogs/content/EdInsertMath.js
editor/ui/dialogs/content/EdInsertTable.js
mail/components/compose/content/ComposerCommands.js
mail/components/compose/content/MsgComposeCommands.js
mail/components/compose/content/dialogs/EdDialogCommon.js
mail/components/compose/content/dialogs/EdImageLinkLoader.js
mail/components/compose/content/dialogs/EdInsertMath.js
mail/components/compose/content/dialogs/EdInsertTable.js
mail/components/compose/content/editor.js
mail/components/compose/content/editorUtilities.js
mail/components/im/content/chat-messenger.js
mail/extensions/openpgp/content/ui/enigmailMsgComposeOverlay.js
mailnews/compose/src/nsMsgCompose.cpp
suite/components/bindings/textbox.xml
suite/mailnews/components/compose/content/MsgComposeCommands.js
--- a/editor/ui/composer/content/ComposerCommands.js
+++ b/editor/ui/composer/content/ComposerCommands.js
@@ -2229,18 +2229,18 @@ function SetSaveAndPublishUI(urlstring) 
 }
 
 function SetDocumentEditable(isDocEditable) {
   var editor = GetCurrentEditor();
   if (editor && editor.document) {
     try {
       var flags = editor.flags;
       editor.flags = isDocEditable
-        ? (flags &= ~nsIPlaintextEditor.eEditorReadonlyMask)
-        : flags | nsIPlaintextEditor.eEditorReadonlyMask;
+        ? (flags &= ~Ci.nsIEditor.eEditorReadonlyMask)
+        : flags | Ci.nsIEditor.eEditorReadonlyMask;
     } catch (e) {}
 
     // update all commands
     window.updateCommands("create");
   }
 }
 
 // ****** end of save / publish **********//
--- a/editor/ui/composer/content/editingOverlay.js
+++ b/editor/ui/composer/content/editingOverlay.js
@@ -59,17 +59,16 @@ function EditorOnLoad()
       cmd.collapsed = true;
   }
 
   // Initialize our source text <editor>
   try {
     gSourceContentWindow = document.getElementById("content-source");
     gSourceContentWindow.makeEditable("text", false);
     gSourceTextEditor = gSourceContentWindow.getEditor(gSourceContentWindow.contentWindow);
-    gSourceTextEditor.QueryInterface(Ci.nsIPlaintextEditor);
     gSourceTextEditor.enableUndo(false);
     gSourceTextEditor.rootElement.style.fontFamily = "-moz-fixed";
     gSourceTextEditor.rootElement.style.whiteSpace = "pre";
     gSourceTextEditor.rootElement.style.margin = 0;
     var controller = Cc["@mozilla.org/embedcomp/base-command-controller;1"]
                        .createInstance(Ci.nsIControllerContext);
     controller.setCommandContext(gSourceContentWindow);
     gSourceContentWindow.contentWindow.controllers.insertControllerAt(0, controller);
--- a/editor/ui/composer/content/editor.js
+++ b/editor/ui/composer/content/editor.js
@@ -2805,20 +2805,17 @@ function goUpdateTableMenuItems(commands
     dump("goUpdateTableMenuItems: too early, not initialized\n");
     return;
   }
 
   var enabled = false;
   var enabledIfTable = false;
 
   var flags = editor.flags;
-  if (
-    !(flags & nsIPlaintextEditor.eEditorReadonlyMask) &&
-    IsEditingRenderedHTML()
-  ) {
+  if (!(flags & Ci.nsIEditor.eEditorReadonlyMask) && IsEditingRenderedHTML()) {
     var tagNameObj = { value: "" };
     var element;
     try {
       element = editor.getSelectedOrParentTableElement(tagNameObj, {
         value: 0,
       });
     } catch (e) {}
 
@@ -2863,31 +2860,31 @@ function goUpdateTableMenuItems(commands
 // Helpers for inserting and editing tables:
 
 function IsInTable() {
   var editor = GetCurrentEditor();
   try {
     var flags = editor.flags;
     return (
       IsHTMLEditor() &&
-      !(flags & nsIPlaintextEditor.eEditorReadonlyMask) &&
+      !(flags & Ci.nsIEditor.eEditorReadonlyMask) &&
       IsEditingRenderedHTML() &&
       null != editor.getElementOrParentByTagName("table", null)
     );
   } catch (e) {}
   return false;
 }
 
 function IsInTableCell() {
   try {
     var editor = GetCurrentEditor();
     var flags = editor.flags;
     return (
       IsHTMLEditor() &&
-      !(flags & nsIPlaintextEditor.eEditorReadonlyMask) &&
+      !(flags & Ci.nsIEditor.eEditorReadonlyMask) &&
       IsEditingRenderedHTML() &&
       null != editor.getElementOrParentByTagName("td", null)
     );
   } catch (e) {}
   return false;
 }
 
 function IsSelectionInOneCell() {
--- a/editor/ui/composer/content/editorUtilities.js
+++ b/editor/ui/composer/content/editorUtilities.js
@@ -163,17 +163,16 @@ function GetSelectionAsText() {
       kOutputSelectionOnly
     );
   } catch (e) {}
 
   return "";
 }
 
 /** *********** Get Current Editor and associated interfaces or info ***************/
-const nsIPlaintextEditor = Ci.nsIPlaintextEditor;
 const nsIHTMLEditor = Ci.nsIHTMLEditor;
 const nsITableEditor = Ci.nsITableEditor;
 const nsIEditorStyleSheets = Ci.nsIEditorStyleSheets;
 const nsIEditingSession = Ci.nsIEditingSession;
 
 function GetCurrentEditor() {
   // Get the active editor from the <editor> tag
   // XXX This will probably change if we support > 1 editor in main Composer window
@@ -182,17 +181,16 @@ function GetCurrentEditor() {
   // For dialogs: Search up parent chain to find top window with editor
   var editor;
   try {
     var editorElement = GetCurrentEditorElement();
     editor = editorElement.getEditor(editorElement.contentWindow);
 
     // Do QIs now so editor users won't have to figure out which interface to use
     // Using "instanceof" does the QI for us.
-    editor instanceof Ci.nsIPlaintextEditor;
     editor instanceof Ci.nsIHTMLEditor;
   } catch (e) {
     dump(e) + "\n";
   }
 
   return editor;
 }
 
--- a/editor/ui/dialogs/content/EdDialogCommon.js
+++ b/editor/ui/dialogs/content/EdDialogCommon.js
@@ -579,17 +579,17 @@ function SetRelativeCheckbox(checkbox) {
     checkbox = document.getElementById("MakeRelativeCheckbox");
     if (!checkbox) {
       return;
     }
   }
 
   var editor = GetCurrentEditor();
   // Mail never allows relative URLs, so hide the checkbox
-  if (editor && editor.flags & Ci.nsIPlaintextEditor.eEditorMailMask) {
+  if (editor && editor.flags & Ci.nsIEditor.eEditorMailMask) {
     checkbox.collapsed = true;
     return;
   }
 
   var input = document.getElementById(checkbox.getAttribute("for"));
   if (!input) {
     return;
   }
@@ -991,17 +991,17 @@ function FillLinkMenulist(linkMenulist, 
         return 0;
       });
 
       for (i = 0; i < anchorList.length; i++) {
         createMenuItem(menupopup, anchorList[i].anchor);
       }
     } else {
       // Don't bother with named anchors in Mail.
-      if (editor && editor.flags & Ci.nsIPlaintextEditor.eEditorMailMask) {
+      if (editor && editor.flags & Ci.nsIEditor.eEditorMailMask) {
         menupopup.remove();
         linkMenulist.removeAttribute("enablehistory");
         return;
       }
       var item = createMenuItem(
         menupopup,
         GetString("NoNamedAnchorsOrHeadings")
       );
--- a/editor/ui/dialogs/content/EdImageLinkLoader.js
+++ b/editor/ui/dialogs/content/EdImageLinkLoader.js
@@ -14,17 +14,17 @@ var gMsgCompPrevMozDoNotSendAttribute;
 var gMsgCompAttachSourceElement = null;
 
 function OnLoadDialog() {
   gMsgCompAttachSourceElement = document.getElementById("AttachSourceToMail");
   var editor = GetCurrentEditor();
   if (
     gMsgCompAttachSourceElement &&
     editor &&
-    editor.flags & Ci.nsIPlaintextEditor.eEditorMailMask
+    editor.flags & Ci.nsIEditor.eEditorMailMask
   ) {
     SetRelativeCheckbox = function() {
       SetAttachCheckbox();
     };
     // initialize the AttachSourceToMail checkbox
     gMsgCompAttachSourceElement.hidden = false;
 
     switch (document.documentElement.id) {
--- a/editor/ui/dialogs/content/EdInsertMath.js
+++ b/editor/ui/dialogs/content/EdInsertMath.js
@@ -114,19 +114,17 @@ function Startup() {
   SetWindowLocation();
 }
 
 function insertLaTeXCommand(aButton) {
   gDialog.input.focus();
 
   // For a single math symbol, just use the insertText command.
   if (aButton.label) {
-    gDialog.input.editor
-      .QueryInterface(Ci.nsIPlaintextEditor)
-      .insertText(aButton.label);
+    gDialog.input.editor.insertText(aButton.label);
     return;
   }
 
   // Otherwise, it's a LaTeX command with at least one argument...
   var latex = TeXZilla.getTeXSource(aButton.firstChild);
   var selectionStart = gDialog.input.selectionStart;
   var selectionEnd = gDialog.input.selectionEnd;
 
@@ -147,17 +145,17 @@ function insertLaTeXCommand(aButton) {
     latexNewStart = 0;
     latexNewEnd = latex.length;
   } else {
     // Otherwise, select the dots representing the next argument.
     latexNewEnd = latexNewStart + 1;
   }
 
   // Update the input text and selection.
-  gDialog.input.editor.QueryInterface(Ci.nsIPlaintextEditor).insertText(latex);
+  gDialog.input.editor.insertText(latex);
   gDialog.input.setSelectionRange(
     selectionStart + latexNewStart,
     selectionStart + latexNewEnd
   );
 
   updateMath();
 }
 
--- a/editor/ui/dialogs/content/EdInsertTable.js
+++ b/editor/ui/dialogs/content/EdInsertTable.js
@@ -44,17 +44,17 @@ function Startup() {
   gDialog.OkButton = document.documentElement.getButton("accept");
 
   // Make a copy to use for AdvancedEdit
   globalElement = gTableElement.cloneNode(false);
   try {
     if (
       Services.prefs.getBoolPref("editor.use_css") &&
       IsHTMLEditor() &&
-      !(gActiveEditor.flags & Ci.nsIPlaintextEditor.eEditorMailMask)
+      !(gActiveEditor.flags & Ci.nsIEditor.eEditorMailMask)
     ) {
       // only for Composer and not for htmlmail
       globalElement.setAttribute("style", "text-align: left;");
     }
   } catch (e) {}
 
   // Initialize all widgets with image attributes
   InitDialog();
--- a/mail/components/compose/content/ComposerCommands.js
+++ b/mail/components/compose/content/ComposerCommands.js
@@ -2023,18 +2023,18 @@ function GetDocUrlFromPublishData(publis
 }
 
 function SetDocumentEditable(isDocEditable) {
   var editor = GetCurrentEditor();
   if (editor && editor.document) {
     try {
       var flags = editor.flags;
       editor.flags = isDocEditable
-        ? (flags &= ~nsIPlaintextEditor.eEditorReadonlyMask)
-        : flags | nsIPlaintextEditor.eEditorReadonlyMask;
+        ? (flags &= ~Ci.nsIEditor.eEditorReadonlyMask)
+        : flags | Ci.nsIEditor.eEditorReadonlyMask;
     } catch (e) {}
 
     // update all commands
     window.updateCommands("create");
   }
 }
 
 var nsCloseCommand = {
--- a/mail/components/compose/content/MsgComposeCommands.js
+++ b/mail/components/compose/content/MsgComposeCommands.js
@@ -235,19 +235,19 @@ function getPrettyKey(aKeyId) {
  * @param aDisable  true = disable items. false = enable items.
  */
 function updateEditableFields(aDisable) {
   if (!gMsgCompose) {
     return;
   }
 
   if (aDisable) {
-    gMsgCompose.editor.flags |= Ci.nsIPlaintextEditor.eEditorReadonlyMask;
+    gMsgCompose.editor.flags |= Ci.nsIEditor.eEditorReadonlyMask;
   } else {
-    gMsgCompose.editor.flags &= ~Ci.nsIPlaintextEditor.eEditorReadonlyMask;
+    gMsgCompose.editor.flags &= ~Ci.nsIEditor.eEditorReadonlyMask;
   }
 
   let elements = document.querySelectorAll('[disableonsend="true"]');
   for (let i = 0; i < elements.length; i++) {
     elements[i].disabled = aDisable;
   }
 }
 
@@ -2337,18 +2337,17 @@ function ComposeFieldsReady() {
   } catch (e) {
     charset = gMsgCompose.compFields.defaultCharacterSet;
   }
   SetDocumentCharacterSet(charset);
 
   // If we are in plain text, we need to set the wrap column
   if (!gMsgCompose.composeHTML) {
     try {
-      gMsgCompose.editor.QueryInterface(Ci.nsIPlaintextEditor).wrapWidth =
-        gMsgCompose.wrapLength;
+      gMsgCompose.editor.wrapWidth = gMsgCompose.wrapLength;
     } catch (e) {
       dump("### textEditor.wrapWidth exception text: " + e + " - failed\n");
     }
   }
 
   CompFields2Recipients(gMsgCompose.compFields);
   SetComposeWindowTitle();
   updateEditableFields(false);
@@ -7688,17 +7687,17 @@ function removeQueryPart(aURL, aQuery) {
 }
 
 function InitEditor() {
   var editor = GetCurrentEditor();
 
   // Set eEditorMailMask flag to avoid using content prefs for spell checker,
   // otherwise dictionary setting in preferences is ignored and dictionary is
   // inconsistent in subject and message body.
-  let eEditorMailMask = Ci.nsIPlaintextEditor.eEditorMailMask;
+  let eEditorMailMask = Ci.nsIEditor.eEditorMailMask;
   editor.flags |= eEditorMailMask;
   document.getElementById("msgSubject").editor.flags |= eEditorMailMask;
 
   // Control insertion of line breaks.
   editor.returnInParagraphCreatesNewParagraph = Services.prefs.getBoolPref(
     "editor.CR_creates_new_p"
   );
   editor.document.execCommand(
--- a/mail/components/compose/content/dialogs/EdDialogCommon.js
+++ b/mail/components/compose/content/dialogs/EdDialogCommon.js
@@ -463,17 +463,17 @@ function SetRelativeCheckbox(checkbox) {
     checkbox = document.getElementById("MakeRelativeCheckbox");
     if (!checkbox) {
       return;
     }
   }
 
   var editor = GetCurrentEditor();
   // Mail never allows relative URLs, so hide the checkbox
-  if (editor && editor.flags & Ci.nsIPlaintextEditor.eEditorMailMask) {
+  if (editor && editor.flags & Ci.nsIEditor.eEditorMailMask) {
     checkbox.collapsed = true;
     return;
   }
 
   var input = document.getElementById(checkbox.getAttribute("for"));
   if (!input) {
     return;
   }
@@ -657,17 +657,17 @@ function FillLinkMenulist(linkMenulist, 
         }
         return 0;
       });
       for (i = 0; i < anchorList.length; i++) {
         menuItems.push(createMenuItem(anchorList[i].anchor));
       }
     } else {
       // Don't bother with named anchors in Mail.
-      if (editor && editor.flags & Ci.nsIPlaintextEditor.eEditorMailMask) {
+      if (editor && editor.flags & Ci.nsIEditor.eEditorMailMask) {
         linkMenulist.removeAttribute("enablehistory");
         return;
       }
       let item = createMenuItem(GetString("NoNamedAnchorsOrHeadings"));
       item.setAttribute("disabled", "true");
       menuItems.push(item);
     }
     window.addEventListener("contextmenu", event => {
--- a/mail/components/compose/content/dialogs/EdImageLinkLoader.js
+++ b/mail/components/compose/content/dialogs/EdImageLinkLoader.js
@@ -14,17 +14,17 @@ var gMsgCompPrevMozDoNotSendAttribute;
 var gMsgCompAttachSourceElement = null;
 
 function OnLoadDialog() {
   gMsgCompAttachSourceElement = document.getElementById("AttachSourceToMail");
   var editor = GetCurrentEditor();
   if (
     gMsgCompAttachSourceElement &&
     editor &&
-    editor.flags & Ci.nsIPlaintextEditor.eEditorMailMask
+    editor.flags & Ci.nsIEditor.eEditorMailMask
   ) {
     SetRelativeCheckbox = function() {
       SetAttachCheckbox();
     };
     // initialize the AttachSourceToMail checkbox
     gMsgCompAttachSourceElement.hidden = false;
 
     switch (document.querySelector("dialog").id) {
--- a/mail/components/compose/content/dialogs/EdInsertMath.js
+++ b/mail/components/compose/content/dialogs/EdInsertMath.js
@@ -114,19 +114,17 @@ function Startup() {
   SetWindowLocation();
 }
 
 function insertLaTeXCommand(aButton) {
   gDialog.input.focus();
 
   // For a single math symbol, just use the insertText command.
   if (aButton.label) {
-    gDialog.input.editor
-      .QueryInterface(Ci.nsIPlaintextEditor)
-      .insertText(aButton.label);
+    gDialog.input.editor.insertText(aButton.label);
     return;
   }
 
   // Otherwise, it's a LaTeX command with at least one argument...
   var latex = TeXZilla.getTeXSource(aButton.firstElementChild);
   var selectionStart = gDialog.input.selectionStart;
   var selectionEnd = gDialog.input.selectionEnd;
 
@@ -147,17 +145,17 @@ function insertLaTeXCommand(aButton) {
     latexNewStart = 0;
     latexNewEnd = latex.length;
   } else {
     // Otherwise, select the dots representing the next argument.
     latexNewEnd = latexNewStart + 1;
   }
 
   // Update the input text and selection.
-  gDialog.input.editor.QueryInterface(Ci.nsIPlaintextEditor).insertText(latex);
+  gDialog.input.editor.insertText(latex);
   gDialog.input.setSelectionRange(
     selectionStart + latexNewStart,
     selectionStart + latexNewEnd
   );
 
   updateMath();
 }
 
--- a/mail/components/compose/content/dialogs/EdInsertTable.js
+++ b/mail/components/compose/content/dialogs/EdInsertTable.js
@@ -44,17 +44,17 @@ function Startup() {
   gDialog.OkButton = document.querySelector("dialog").getButton("accept");
 
   // Make a copy to use for AdvancedEdit
   globalElement = gTableElement.cloneNode(false);
   try {
     if (
       Services.prefs.getBoolPref("editor.use_css") &&
       IsHTMLEditor() &&
-      !(gActiveEditor.flags & Ci.nsIPlaintextEditor.eEditorMailMask)
+      !(gActiveEditor.flags & Ci.nsIEditor.eEditorMailMask)
     ) {
       // only for Composer and not for htmlmail
       globalElement.setAttribute("style", "text-align: left;");
     }
   } catch (e) {}
 
   // Initialize all widgets with image attributes
   InitDialog();
--- a/mail/components/compose/content/editor.js
+++ b/mail/components/compose/content/editor.js
@@ -2111,20 +2111,17 @@ function goUpdateTableMenuItems(commands
     dump("goUpdateTableMenuItems: too early, not initialized\n");
     return;
   }
 
   var enabled = false;
   var enabledIfTable = false;
 
   var flags = editor.flags;
-  if (
-    !(flags & nsIPlaintextEditor.eEditorReadonlyMask) &&
-    IsEditingRenderedHTML()
-  ) {
+  if (!(flags & Ci.nsIEditor.eEditorReadonlyMask) && IsEditingRenderedHTML()) {
     var tagNameObj = { value: "" };
     var element;
     try {
       element = editor.getSelectedOrParentTableElement(tagNameObj, {
         value: 0,
       });
     } catch (e) {}
 
@@ -2168,31 +2165,31 @@ function goUpdateTableMenuItems(commands
 // Helpers for inserting and editing tables:
 
 function IsInTable() {
   var editor = GetCurrentEditor();
   try {
     var flags = editor.flags;
     return (
       IsHTMLEditor() &&
-      !(flags & nsIPlaintextEditor.eEditorReadonlyMask) &&
+      !(flags & Ci.nsIEditor.eEditorReadonlyMask) &&
       IsEditingRenderedHTML() &&
       null != editor.getElementOrParentByTagName("table", null)
     );
   } catch (e) {}
   return false;
 }
 
 function IsInTableCell() {
   try {
     var editor = GetCurrentEditor();
     var flags = editor.flags;
     return (
       IsHTMLEditor() &&
-      !(flags & nsIPlaintextEditor.eEditorReadonlyMask) &&
+      !(flags & Ci.nsIEditor.eEditorReadonlyMask) &&
       IsEditingRenderedHTML() &&
       null != editor.getElementOrParentByTagName("td", null)
     );
   } catch (e) {}
   return false;
 }
 
 function IsSelectionInOneCell() {
--- a/mail/components/compose/content/editorUtilities.js
+++ b/mail/components/compose/content/editorUtilities.js
@@ -163,17 +163,16 @@ function GetSelectionAsText() {
       kOutputSelectionOnly
     );
   } catch (e) {}
 
   return "";
 }
 
 /** *********** Get Current Editor and associated interfaces or info ***************/
-const nsIPlaintextEditor = Ci.nsIPlaintextEditor;
 const nsIHTMLEditor = Ci.nsIHTMLEditor;
 const nsITableEditor = Ci.nsITableEditor;
 const nsIEditorStyleSheets = Ci.nsIEditorStyleSheets;
 const nsIEditingSession = Ci.nsIEditingSession;
 
 function GetCurrentEditor() {
   // Get the active editor from the <editor> tag
   // XXX This will probably change if we support > 1 editor in main Composer window
@@ -182,17 +181,16 @@ function GetCurrentEditor() {
   // For dialogs: Search up parent chain to find top window with editor
   var editor;
   try {
     var editorElement = GetCurrentEditorElement();
     editor = editorElement.getEditor(editorElement.contentWindow);
 
     // Do QIs now so editor users won't have to figure out which interface to use
     // Using "instanceof" does the QI for us.
-    editor instanceof Ci.nsIPlaintextEditor;
     editor instanceof Ci.nsIHTMLEditor;
   } catch (e) {
     dump(e) + "\n";
   }
 
   return editor;
 }
 
--- a/mail/components/im/content/chat-messenger.js
+++ b/mail/components/im/content/chat-messenger.js
@@ -890,17 +890,17 @@ var chatHandler = {
           let popup = document.getElementById("chatContextMenu");
           popup.openPopupAtScreen(e.screenX, e.screenY, true);
           e.preventDefault();
         });
 
         // Set "mail editor mask" so changing the language doesn't
         // affect the global preference and multiple chats can have
         // individual languages.
-        conv.editor.editor.flags |= Ci.nsIPlaintextEditor.eEditorMailMask;
+        conv.editor.editor.flags |= Ci.nsIEditor.eEditorMailMask;
 
         // Initialise language to the default.
         conv.editor.setAttribute(
           "lang",
           Services.prefs.getStringPref("spellchecker.dictionary")
         );
 
         // Attach listener so we hear about language changes.
--- a/mail/extensions/openpgp/content/ui/enigmailMsgComposeOverlay.js
+++ b/mail/extensions/openpgp/content/ui/enigmailMsgComposeOverlay.js
@@ -3089,32 +3089,31 @@ Enigmail.msg = {
    */
 
   wrapInLine: function(wrapresultObj) {
     EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: WrapInLine\n");
     wrapresultObj.cancelled = false;
     wrapresultObj.usePpgMime = false;
     try {
       const dce = Components.interfaces.nsIDocumentEncoder;
-      var wrapper = gMsgCompose.editor.QueryInterface(Components.interfaces.nsIEditorMailSupport);
-      var editor = gMsgCompose.editor.QueryInterface(Components.interfaces.nsIPlaintextEditor);
+      var editor = gMsgCompose.editor.QueryInterface(Components.interfaces.nsIEditorMailSupport);
       var encoderFlags = dce.OutputFormatted | dce.OutputLFLineBreak;
 
       var wrapWidth = this.getMailPref("mailnews.wraplength");
       if (wrapWidth > 0 && wrapWidth < 68 && editor.wrapWidth > 0) {
         if (EnigmailDialog.confirmDlg(window, EnigmailLocale.getString("minimalLineWrapping", [wrapWidth]))) {
           wrapWidth = 68;
           EnigmailPrefs.getPrefRoot().setIntPref("mailnews.wraplength", wrapWidth);
         }
       }
 
       if (wrapWidth && editor.wrapWidth > 0) {
         // First use standard editor wrap mechanism:
         editor.wrapWidth = wrapWidth - 2;
-        wrapper.rewrap(true);
+        editor.rewrap(true);
         editor.wrapWidth = wrapWidth;
 
         // Now get plaintext from editor
         var wrapText = this.editorGetContentAs("text/plain", encoderFlags);
 
         // split the lines into an array
         wrapText = wrapText.split(/\r\n|\r|\n/g);
 
@@ -4099,18 +4098,17 @@ Enigmail.msg = {
     try {
       sendFlowed = this.getMailPref("mailnews.send_plaintext_flowed");
     }
     catch (ex) {
       sendFlowed = true;
     }
     var encoderFlags = dce.OutputFormatted | dce.OutputLFLineBreak;
 
-    var wrapper = gMsgCompose.editor.QueryInterface(Components.interfaces.nsIEditorMailSupport);
-    var editor = gMsgCompose.editor.QueryInterface(Components.interfaces.nsIPlaintextEditor);
+    var editor = gMsgCompose.editor.QueryInterface(Components.interfaces.nsIEditorMailSupport);
     var wrapWidth = 72;
 
     if (!(sendInfo.sendFlags & ENCRYPT)) {
       // signed messages only
       if (gMsgCompose.composeHTML) {
         // enforce line wrapping here
         // otherwise the message isn't signed correctly
         try {
@@ -4119,17 +4117,17 @@ Enigmail.msg = {
           if (wrapWidth > 0 && wrapWidth < 68 && gMsgCompose.wrapLength > 0) {
             if (EnigmailDialog.confirmDlg(window, EnigmailLocale.getString("minimalLineWrapping", [wrapWidth]))) {
               EnigmailPrefs.getPrefRoot().setIntPref("editor.htmlWrapColumn", 68);
             }
           }
           if (EnigmailPrefs.getPref("wrapHtmlBeforeSend")) {
             if (wrapWidth) {
               editor.wrapWidth = wrapWidth - 2; // prepare for the worst case: a 72 char's long line starting with '-'
-              wrapper.rewrap(false);
+              editor.rewrap(false);
             }
           }
         }
         catch (ex) {}
       }
       else {
         // plaintext: Wrapping code has been moved to superordinate function encryptMsg to enable interactive format switch
       }
--- a/mailnews/compose/src/nsMsgCompose.cpp
+++ b/mailnews/compose/src/nsMsgCompose.cpp
@@ -17,17 +17,16 @@
 #include "nsMsgCompUtils.h"
 #include "nsComposeStrings.h"
 #include "nsIMsgSend.h"
 #include "nsMailHeaders.h"
 #include "nsMsgPrompts.h"
 #include "nsMimeTypes.h"
 #include "nsICharsetConverterManager.h"
 #include "nsTextFormatter.h"
-#include "nsIPlaintextEditor.h"
 #include "nsIHTMLEditor.h"
 #include "nsIEditor.h"
 #include "plstr.h"
 #include "prmem.h"
 #include "nsIDocShell.h"
 #include "nsAbBaseCID.h"
 #include "nsCExternalHandlerService.h"
 #include "nsIMIMEService.h"
@@ -613,17 +612,16 @@ nsMsgCompose::ConvertAndLoadComposeWindo
   // Ok - now we need to figure out the charset of the aBuf we are going to send
   // into the editor shell. There are I18N calls to sniff the data and then we
   // need to call the new routine in the editor that will allow us to send in
   // the charset
   //
 
   // Now, insert it into the editor...
   RefPtr<HTMLEditor> htmlEditor = m_editor->AsHTMLEditor();
-  nsCOMPtr<nsIPlaintextEditor> textEditor(do_QueryInterface(m_editor));
   int32_t reply_on_top = 0;
   bool sig_bottom = true;
   m_identity->GetReplyOnTop(&reply_on_top);
   m_identity->GetSigBottom(&sig_bottom);
   bool sigOnTop = (reply_on_top == 1 && !sig_bottom);
   bool isForwarded = (mType == nsIMsgCompType::ForwardInline);
 
   // When in paragraph mode, don't call InsertLineBreak() since that inserts
@@ -636,35 +634,35 @@ nsMsgCompose::ConvertAndLoadComposeWindo
     mInsertingQuotedContent = true;
     if (!aPrefix.IsEmpty()) {
       if (!aHTMLEditor) aPrefix.AppendLiteral("\n");
 
       int32_t reply_on_top = 0;
       m_identity->GetReplyOnTop(&reply_on_top);
       if (reply_on_top == 1) {
         // HTML editor eats one line break but not a whole paragraph.
-        if (aHTMLEditor && !paragraphMode) textEditor->InsertLineBreak();
+        if (aHTMLEditor && !paragraphMode) htmlEditor->InsertLineBreak();
 
         // add one newline if a signature comes before the quote, two otherwise
         bool includeSignature = true;
         bool sig_bottom = true;
         bool attachFile = false;
         nsString prefSigText;
 
         m_identity->GetSigOnReply(&includeSignature);
         m_identity->GetSigBottom(&sig_bottom);
         m_identity->GetHtmlSigText(prefSigText);
         nsresult rv = m_identity->GetAttachSignature(&attachFile);
         if (!paragraphMode || !aHTMLEditor) {
           if (includeSignature && !sig_bottom &&
               ((NS_SUCCEEDED(rv) && attachFile) || !prefSigText.IsEmpty()))
-            textEditor->InsertLineBreak();
+            htmlEditor->InsertLineBreak();
           else {
-            textEditor->InsertLineBreak();
-            textEditor->InsertLineBreak();
+            htmlEditor->InsertLineBreak();
+            htmlEditor->InsertLineBreak();
           }
         }
       }
 
       InsertDivWrappedTextAtSelection(aPrefix,
                                       NS_LITERAL_STRING("moz-cite-prefix"));
     }
 
@@ -677,32 +675,32 @@ nsMsgCompose::ConvertAndLoadComposeWindo
                                            getter_AddRefs(nodeInserted));
       } else {
         htmlEditor->InsertAsQuotation(aBuf, getter_AddRefs(nodeInserted));
       }
     }
 
     mInsertingQuotedContent = false;
 
-    (void)TagEmbeddedObjects(m_editor);
+    (void)TagEmbeddedObjects(htmlEditor);
 
     if (!aSignature.IsEmpty()) {
       // we cannot add it on top earlier, because TagEmbeddedObjects will mark
       // all images in the signature as "moz-do-not-send"
       if (sigOnTop) MoveToBeginningOfDocument();
 
       if (aHTMLEditor)
         htmlEditor->InsertHTML(aSignature);
       else {
-        textEditor->InsertLineBreak();
+        htmlEditor->InsertLineBreak();
         InsertDivWrappedTextAtSelection(aSignature,
                                         NS_LITERAL_STRING("moz-signature"));
       }
 
-      if (sigOnTop) m_editor->EndOfDocument();
+      if (sigOnTop) htmlEditor->EndOfDocument();
     }
   } else {
     if (aHTMLEditor) {
       mInsertingQuotedContent = true;
       if (isForwarded &&
           Substring(aBuf, 0, sizeof(MIME_FORWARD_HTML_PREFIX) - 1)
               .EqualsLiteral(MIME_FORWARD_HTML_PREFIX)) {
         // We assign the opening tag inside "<HTML><BODY><BR><BR>" before the
@@ -730,40 +728,40 @@ nsMsgCompose::ConvertAndLoadComposeWindo
       }
 
       mInsertingQuotedContent = false;
 
       // When forwarding a message as inline, or editing as new (which could
       // contain unsanitized remote content), tag any embedded objects
       // with moz-do-not-send=true so they don't get attached upon send.
       if (isForwarded || mType == nsIMsgCompType::EditAsNew)
-        (void)TagEmbeddedObjects(m_editor);
+        (void)TagEmbeddedObjects(htmlEditor);
 
       if (!aSignature.IsEmpty()) {
         if (isForwarded && sigOnTop) {
           // Use our own function, nsEditor::BeginningOfDocument() would
           // position into the <div class="moz-forward-container"> we've just
           // created.
           MoveToBeginningOfDocument();
         } else {
           // Use our own function, nsEditor::EndOfDocument() would position
           // into the <div class="moz-forward-container"> we've just created.
           MoveToEndOfDocument();
         }
         htmlEditor->InsertHTML(aSignature);
-        if (isForwarded && sigOnTop) m_editor->EndOfDocument();
+        if (isForwarded && sigOnTop) htmlEditor->EndOfDocument();
       } else
-        m_editor->EndOfDocument();
+        htmlEditor->EndOfDocument();
     } else {
       bool sigOnTopInserted = false;
       if (isForwarded && sigOnTop && !aSignature.IsEmpty()) {
-        textEditor->InsertLineBreak();
+        htmlEditor->InsertLineBreak();
         InsertDivWrappedTextAtSelection(aSignature,
                                         NS_LITERAL_STRING("moz-signature"));
-        m_editor->EndOfDocument();
+        htmlEditor->EndOfDocument();
         sigOnTopInserted = true;
       }
 
       if (!aBuf.IsEmpty()) {
         nsresult rv;
         RefPtr<Element> divElem;
         RefPtr<Element> extraBr;
 
@@ -793,129 +791,128 @@ nsMsgCompose::ConvertAndLoadComposeWindo
           }
 
           // Insert the non-empty <div> into the DOM.
           rv = htmlEditor->InsertElementAtSelection(divElem, false);
           NS_ENSURE_SUCCESS(rv, rv);
 
           // Position into the div, so out content goes there.
           RefPtr<Selection> selection;
-          m_editor->GetSelection(getter_AddRefs(selection));
+          htmlEditor->GetSelection(getter_AddRefs(selection));
           rv = selection->Collapse(divElem, 0);
           NS_ENSURE_SUCCESS(rv, rv);
         }
 
         rv = htmlEditor->InsertTextWithQuotations(aBuf);
         NS_ENSURE_SUCCESS(rv, rv);
 
         if (isForwarded) {
-          nsCOMPtr<nsIEditor> editor(m_editor);  // Strong reference.
           // Special treatment for forwarded messages: Part 2.
           if (sigOnTopInserted) {
             // Sadly the M-C editor inserts a <br> between the <div> for the
             // signature and this <div>, so remove the <br> we don't want.
             nsCOMPtr<nsINode> brBeforeDiv;
             nsAutoString tagLocalName;
             brBeforeDiv = divElem->GetPreviousSibling();
             if (brBeforeDiv) {
               tagLocalName = brBeforeDiv->LocalName();
               if (tagLocalName.EqualsLiteral("br")) {
-                rv = editor->DeleteNode(brBeforeDiv);
+                rv = htmlEditor->DeleteNode(brBeforeDiv);
                 NS_ENSURE_SUCCESS(rv, rv);
               }
             }
           }
 
           // Clean up the <br> we inserted.
-          rv = editor->DeleteNode(extraBr);
+          rv = htmlEditor->DeleteNode(extraBr);
           NS_ENSURE_SUCCESS(rv, rv);
         }
 
         // Use our own function instead of nsEditor::EndOfDocument() because
         // we don't want to position at the end of the div we've just created.
         // It's OK to use, even if we're not forwarding and didn't create a
         // <div>.
         rv = MoveToEndOfDocument();
         NS_ENSURE_SUCCESS(rv, rv);
       }
 
       if ((!isForwarded || !sigOnTop) && !aSignature.IsEmpty()) {
-        textEditor->InsertLineBreak();
+        htmlEditor->InsertLineBreak();
         InsertDivWrappedTextAtSelection(aSignature,
                                         NS_LITERAL_STRING("moz-signature"));
       }
     }
   }
 
   if (aBuf.IsEmpty())
-    m_editor->BeginningOfDocument();
+    htmlEditor->BeginningOfDocument();
   else {
     switch (reply_on_top) {
       // This should set the cursor after the body but before the sig
       case 0: {
-        if (!textEditor) {
-          m_editor->BeginningOfDocument();
+        if (!htmlEditor) {
+          htmlEditor->BeginningOfDocument();
           break;
         }
 
         RefPtr<Selection> selection;
         nsCOMPtr<nsINode> parent;
         int32_t offset;
         nsresult rv;
 
         // get parent and offset of mailcite
         rv = GetNodeLocation(nodeInserted, address_of(parent), &offset);
         if (NS_FAILED(rv) || (!parent)) {
-          m_editor->BeginningOfDocument();
+          htmlEditor->BeginningOfDocument();
           break;
         }
 
         // get selection
-        m_editor->GetSelection(getter_AddRefs(selection));
+        htmlEditor->GetSelection(getter_AddRefs(selection));
         if (!selection) {
-          m_editor->BeginningOfDocument();
+          htmlEditor->BeginningOfDocument();
           break;
         }
 
         // place selection after mailcite
         selection->Collapse(parent, offset + 1);
 
         // insert a break at current selection
-        if (!paragraphMode || !aHTMLEditor) textEditor->InsertLineBreak();
+        if (!paragraphMode || !aHTMLEditor) htmlEditor->InsertLineBreak();
 
         // i'm not sure if you need to move the selection back to before the
         // break. expirement.
         selection->Collapse(parent, offset + 1);
 
         break;
       }
 
       case 2: {
-        nsCOMPtr<nsIEditor> editor(m_editor);  // Strong reference.
+        nsCOMPtr<nsIEditor> editor(htmlEditor);  // Strong reference.
         editor->SelectAll();
         break;
       }
 
       // This should set the cursor to the top!
       default: {
         MoveToBeginningOfDocument();
         break;
       }
     }
   }
 
   nsCOMPtr<nsISelectionController> selCon;
-  m_editor->GetSelectionController(getter_AddRefs(selCon));
+  htmlEditor->GetSelectionController(getter_AddRefs(selCon));
 
   if (selCon)
     selCon->ScrollSelectionIntoView(
         nsISelectionController::SELECTION_NORMAL,
         nsISelectionController::SELECTION_ANCHOR_REGION, true);
 
-  m_editor->EnableUndo(true);
+  htmlEditor->EnableUndo(true);
   SetBodyModified(false);
 
 #ifdef MSGCOMP_TRACE_PERFORMANCE
   nsCOMPtr<nsIMsgComposeService> composeService(
       do_GetService(NS_MSGCOMPOSESERVICE_CONTRACTID));
   composeService->TimeStamp(
       "Finished inserting data into the editor. The window is finally ready!",
       false);
@@ -2848,51 +2845,49 @@ MOZ_CAN_RUN_SCRIPT nsresult QuotingOutpu
   // Now, insert it into the editor...
   if (aEditor) aEditor->EnableUndo(true);
 
   nsCOMPtr<nsIMsgCompose> compose = do_QueryReferent(mWeakComposeObj);
   if (!mMsgBody.IsEmpty() && compose) {
     compose->SetInsertingQuotedContent(true);
     if (!mCitePrefix.IsEmpty()) {
       if (!aHTMLEditor) mCitePrefix.AppendLiteral("\n");
-      nsCOMPtr<nsIPlaintextEditor> textEditor(do_QueryInterface(aEditor));
-      if (textEditor) textEditor->InsertText(mCitePrefix);
+      if (aEditor) aEditor->InsertText(mCitePrefix);
     }
 
     RefPtr<mozilla::HTMLEditor> htmlEditor = aEditor->AsHTMLEditor();
     if (aHTMLEditor) {
       nsAutoString body(mMsgBody);
       remove_plaintext_tag(body);
       htmlEditor->InsertAsCitedQuotation(body, EmptyString(), true,
                                          getter_AddRefs(nodeInserted));
     } else {
       htmlEditor->InsertAsQuotation(mMsgBody, getter_AddRefs(nodeInserted));
     }
     compose->SetInsertingQuotedContent(false);
   }
 
   if (aEditor) {
-    nsCOMPtr<nsIPlaintextEditor> textEditor = do_QueryInterface(aEditor);
-    if (textEditor) {
+    if (aEditor) {
       RefPtr<Selection> selection;
       nsCOMPtr<nsINode> parent;
       int32_t offset;
       nsresult rv;
 
       // get parent and offset of mailcite
       rv = GetNodeLocation(nodeInserted, address_of(parent), &offset);
       NS_ENSURE_SUCCESS(rv, rv);
 
       // get selection
       aEditor->GetSelection(getter_AddRefs(selection));
       if (selection) {
         // place selection after mailcite
         selection->Collapse(parent, offset + 1);
         // insert a break at current selection
-        textEditor->InsertLineBreak();
+        aEditor->InsertLineBreak();
         selection->Collapse(parent, offset + 1);
       }
       nsCOMPtr<nsISelectionController> selCon;
       aEditor->GetSelectionController(getter_AddRefs(selCon));
 
       if (selCon)
         // After ScrollSelectionIntoView(), the pending notifications might be
         // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
@@ -5395,21 +5390,19 @@ nsMsgCompose::SetIdentity(nsIMsgIdentity
       rv = MoveToAboveQuote();
     } else {
       // Note: New messages aren't quoted so we always move to the end.
       rv = MoveToEndOfDocument();
     }
 
     if (NS_SUCCEEDED(rv)) {
       if (m_composeHTML) {
-        nsCOMPtr<nsIHTMLEditor> htmlEditor(do_QueryInterface(editor));
-        rv = htmlEditor->InsertHTML(aSignature);
+        rv = MOZ_KnownLive(editor->AsHTMLEditor())->InsertHTML(aSignature);
       } else {
-        nsCOMPtr<nsIPlaintextEditor> textEditor(do_QueryInterface(editor));
-        rv = textEditor->InsertLineBreak();
+        rv = editor->InsertLineBreak();
         InsertDivWrappedTextAtSelection(aSignature,
                                         NS_LITERAL_STRING("moz-signature"));
       }
     }
     editor->EndTransaction();
   }
 
   return rv;
--- a/suite/components/bindings/textbox.xml
+++ b/suite/components/bindings/textbox.xml
@@ -125,21 +125,20 @@
           this.inputField.setSelectionRange(aSelectionStart, aSelectionEnd);
         </body>
       </method>
 
       <method name="_setNewlineHandling">
         <body><![CDATA[
           var str = this.getAttribute("newlines");
           if (str && this.editor) {
-            for (let x in Ci.nsIPlaintextEditor) {
+            for (let x in Ci.nsIEditor) {
               if (/^eNewlines/.test(x)) {
                 if (str == RegExp.rightContext.toLowerCase()) {
-                  this.editor.QueryInterface(Ci.nsIPlaintextEditor)
-                      .newlineHandling = Ci.nsIPlaintextEditor[x];
+                  this.editor.newlineHandling = Ci.nsIEditor[x];
                   break;
                 }
               }
             }
           }
         ]]></body>
       </method>
 
--- a/suite/mailnews/components/compose/content/MsgComposeCommands.js
+++ b/suite/mailnews/components/compose/content/MsgComposeCommands.js
@@ -15,17 +15,16 @@ const {MailServices} = ChromeUtils.impor
  * interfaces
  */
 var nsIMsgCompDeliverMode = Ci.nsIMsgCompDeliverMode;
 var nsIMsgCompSendFormat = Ci.nsIMsgCompSendFormat;
 var nsIMsgCompConvertible = Ci.nsIMsgCompConvertible;
 var nsIMsgCompType = Ci.nsIMsgCompType;
 var nsIMsgCompFormat = Ci.nsIMsgCompFormat;
 var nsIAbPreferMailFormat = Ci.nsIAbPreferMailFormat;
-var nsIPlaintextEditorMail = Ci.nsIPlaintextEditor;
 var mozISpellCheckingEngine = Ci.mozISpellCheckingEngine;
 
 /**
  * In order to distinguish clearly globals that are initialized once when js load (static globals) and those that need to be
  * initialize every time a compose window open (globals), I (ducarroz) have decided to prefix by s... the static one and
  * by g... the other one. Please try to continue and repect this rule in the future. Thanks.
  */
 /**
@@ -129,26 +128,26 @@ function ReleaseGlobalVariables()
   gCharsetConvertManager = null;
   gMsgCompose = null;
   gOriginalMsgURI = null;
   gMailSession = null;
 }
 
 function disableEditableFields()
 {
-  gMsgCompose.editor.flags |= nsIPlaintextEditorMail.eEditorReadonlyMask;
+  gMsgCompose.editor.flags |= Ci.nsIEditor.eEditorReadonlyMask;
   var disableElements = document.getElementsByAttribute("disableonsend", "true");
   for (let i = 0; i < disableElements.length; i++)
     disableElements[i].setAttribute('disabled', 'true');
 
 }
 
 function enableEditableFields()
 {
-  gMsgCompose.editor.flags &= ~nsIPlaintextEditorMail.eEditorReadonlyMask;
+  gMsgCompose.editor.flags &= ~Ci.nsIEditor.eEditorReadonlyMask;
   var enableElements = document.getElementsByAttribute("disableonsend", "true");
   for (let i = 0; i < enableElements.length; i++)
     enableElements[i].removeAttribute('disabled');
 
 }
 
 /**
  * Small helper function to check whether the node passed in is a signature.
@@ -977,18 +976,17 @@ function GetArgs(originalData)
   return args;
 }
 
 function ComposeFieldsReady()
 {
   //If we are in plain text, we need to set the wrap column
   if (! gMsgCompose.composeHTML) {
     try {
-      gMsgCompose.editor.QueryInterface(nsIPlaintextEditorMail).wrapWidth
-          = gMsgCompose.wrapLength;
+      gMsgCompose.editor.wrapWidth = gMsgCompose.wrapLength;
     }
     catch (e) {
       dump("### textEditor.wrapWidth exception text: " + e + " - failed\n");
     }
   }
   CompFields2Recipients(gMsgCompose.compFields);
   SetComposeWindowTitle();
   enableEditableFields();
@@ -3323,17 +3321,17 @@ function removeQueryPart(aURL, aQuery)
   return aURL.substr(0, indexQM + 1) + queryParts.join("&");
 }
 
 function InitEditor(editor)
 {
   // Set the eEditorMailMask flag to avoid using content prefs for the spell
   // checker, otherwise the dictionary setting in preferences is ignored and
   // the dictionary is inconsistent between the subject and message body.
-  var eEditorMailMask = Ci.nsIPlaintextEditor.eEditorMailMask;
+  var eEditorMailMask = Ci.nsIEditor.eEditorMailMask;
   editor.flags |= eEditorMailMask;
   GetMsgSubjectElement().editor.flags |= eEditorMailMask;
 
   // Control insertion of line breaks.
   editor.returnInParagraphCreatesNewParagraph =
     Services.prefs.getBoolPref("mail.compose.default_to_paragraph") ||
     Services.prefs.getBoolPref("editor.CR_creates_new_p");
   editor.document.execCommand("defaultparagraphseparator", false,