editor/composer/src/nsEditingSession.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 sw=2 et tw=78: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include <string.h>                     // for nullptr, strcmp
     9 #include "imgIContainer.h"              // for imgIContainer, etc
    10 #include "mozFlushType.h"               // for mozFlushType::Flush_Frames
    11 #include "mozilla/mozalloc.h"           // for operator new
    12 #include "nsAString.h"
    13 #include "nsComponentManagerUtils.h"    // for do_CreateInstance
    14 #include "nsComposerCommandsUpdater.h"  // for nsComposerCommandsUpdater
    15 #include "nsDebug.h"                    // for NS_ENSURE_SUCCESS, etc
    16 #include "nsEditingSession.h"
    17 #include "nsError.h"                    // for NS_ERROR_FAILURE, NS_OK, etc
    18 #include "nsIChannel.h"                 // for nsIChannel
    19 #include "nsICommandManager.h"          // for nsICommandManager
    20 #include "nsIContentViewer.h"           // for nsIContentViewer
    21 #include "nsIController.h"              // for nsIController
    22 #include "nsIControllerContext.h"       // for nsIControllerContext
    23 #include "nsIControllers.h"             // for nsIControllers
    24 #include "nsID.h"                       // for NS_GET_IID, etc
    25 #include "nsIDOMDocument.h"             // for nsIDOMDocument
    26 #include "nsIDOMHTMLDocument.h"         // for nsIDOMHTMLDocument
    27 #include "nsIDOMWindow.h"               // for nsIDOMWindow
    28 #include "nsIDOMWindowUtils.h"          // for nsIDOMWindowUtils
    29 #include "nsIDocShell.h"                // for nsIDocShell
    30 #include "nsIDocument.h"                // for nsIDocument
    31 #include "nsIDocumentStateListener.h"
    32 #include "nsIEditor.h"                  // for nsIEditor
    33 #include "nsIHTMLDocument.h"            // for nsIHTMLDocument, etc
    34 #include "nsIInterfaceRequestorUtils.h"  // for do_GetInterface
    35 #include "nsIPlaintextEditor.h"         // for nsIPlaintextEditor, etc
    36 #include "nsIRefreshURI.h"              // for nsIRefreshURI
    37 #include "nsIRequest.h"                 // for nsIRequest
    38 #include "nsISelection.h"               // for nsISelection
    39 #include "nsISelectionPrivate.h"        // for nsISelectionPrivate
    40 #include "nsITimer.h"                   // for nsITimer, etc
    41 #include "nsITransactionManager.h"      // for nsITransactionManager
    42 #include "nsIWeakReference.h"           // for nsISupportsWeakReference, etc
    43 #include "nsIWebNavigation.h"           // for nsIWebNavigation
    44 #include "nsIWebProgress.h"             // for nsIWebProgress, etc
    45 #include "nsLiteralString.h"            // for NS_LITERAL_STRING
    46 #include "nsPICommandUpdater.h"         // for nsPICommandUpdater
    47 #include "nsPIDOMWindow.h"              // for nsPIDOMWindow
    48 #include "nsReadableUtils.h"            // for AppendUTF16toUTF8
    49 #include "nsStringFwd.h"                // for nsAFlatString
    51 class nsISupports;
    52 class nsIURI;
    54 /*---------------------------------------------------------------------------
    56   nsEditingSession
    58 ----------------------------------------------------------------------------*/
    59 nsEditingSession::nsEditingSession()
    60 : mDoneSetup(false)
    61 , mCanCreateEditor(false)
    62 , mInteractive(false)
    63 , mMakeWholeDocumentEditable(true)
    64 , mDisabledJSAndPlugins(false)
    65 , mScriptsEnabled(true)
    66 , mPluginsEnabled(true)
    67 , mProgressListenerRegistered(false)
    68 , mImageAnimationMode(0)
    69 , mEditorFlags(0)
    70 , mEditorStatus(eEditorOK)
    71 , mBaseCommandControllerId(0)
    72 , mDocStateControllerId(0)
    73 , mHTMLCommandControllerId(0)
    74 {
    75 }
    77 /*---------------------------------------------------------------------------
    79   ~nsEditingSession
    81 ----------------------------------------------------------------------------*/
    82 nsEditingSession::~nsEditingSession()
    83 {
    84   // Must cancel previous timer?
    85   if (mLoadBlankDocTimer)
    86     mLoadBlankDocTimer->Cancel();
    87 }
    89 NS_IMPL_ISUPPORTS(nsEditingSession, nsIEditingSession, nsIWebProgressListener, 
    90                   nsISupportsWeakReference)
    92 /*---------------------------------------------------------------------------
    94   MakeWindowEditable
    96   aEditorType string, "html" "htmlsimple" "text" "textsimple"
    97   void makeWindowEditable(in nsIDOMWindow aWindow, in string aEditorType, 
    98                           in boolean aDoAfterUriLoad,
    99                           in boolean aMakeWholeDocumentEditable,
   100                           in boolean aInteractive);
   101 ----------------------------------------------------------------------------*/
   102 #define DEFAULT_EDITOR_TYPE "html"
   104 NS_IMETHODIMP
   105 nsEditingSession::MakeWindowEditable(nsIDOMWindow *aWindow,
   106                                      const char *aEditorType, 
   107                                      bool aDoAfterUriLoad,
   108                                      bool aMakeWholeDocumentEditable,
   109                                      bool aInteractive)
   110 {
   111   mEditorType.Truncate();
   112   mEditorFlags = 0;
   114   // disable plugins
   115   nsCOMPtr<nsIDocShell> docShell = GetDocShellFromWindow(aWindow);
   116   NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
   118   mDocShell = do_GetWeakReference(docShell);
   119   mInteractive = aInteractive;
   120   mMakeWholeDocumentEditable = aMakeWholeDocumentEditable;
   122   nsresult rv;
   123   if (!mInteractive) {
   124     rv = DisableJSAndPlugins(aWindow);
   125     NS_ENSURE_SUCCESS(rv, rv);
   126   }
   128   // Always remove existing editor
   129   TearDownEditorOnWindow(aWindow);
   131   // Tells embedder that startup is in progress
   132   mEditorStatus = eEditorCreationInProgress;
   134   //temporary to set editor type here. we will need different classes soon.
   135   if (!aEditorType)
   136     aEditorType = DEFAULT_EDITOR_TYPE;
   137   mEditorType = aEditorType;
   139   // if all this does is setup listeners and I don't need listeners, 
   140   // can't this step be ignored?? (based on aDoAfterURILoad)
   141   rv = PrepareForEditing(aWindow);
   142   NS_ENSURE_SUCCESS(rv, rv);  
   144   // set the flag on the docShell to say that it's editable
   145   rv = docShell->MakeEditable(aDoAfterUriLoad);
   146   NS_ENSURE_SUCCESS(rv, rv);  
   148   // Setup commands common to plaintext and html editors,
   149   //  including the document creation observers
   150   // the first is an editing controller
   151   rv = SetupEditorCommandController("@mozilla.org/editor/editingcontroller;1",
   152                                     aWindow,
   153                                     static_cast<nsIEditingSession*>(this),
   154                                     &mBaseCommandControllerId);
   155   NS_ENSURE_SUCCESS(rv, rv);
   157   // The second is a controller to monitor doc state,
   158   // such as creation and "dirty flag"
   159   rv = SetupEditorCommandController("@mozilla.org/editor/editordocstatecontroller;1",
   160                                     aWindow,
   161                                     static_cast<nsIEditingSession*>(this),
   162                                     &mDocStateControllerId);
   163   NS_ENSURE_SUCCESS(rv, rv);
   165   // aDoAfterUriLoad can be false only when making an existing window editable
   166   if (!aDoAfterUriLoad)
   167   {
   168     rv = SetupEditorOnWindow(aWindow);
   170     // mEditorStatus is set to the error reason
   171     // Since this is used only when editing an existing page,
   172     //  it IS ok to destroy current editor
   173     if (NS_FAILED(rv))
   174       TearDownEditorOnWindow(aWindow);
   175   }
   176   return rv;
   177 }
   179 NS_IMETHODIMP
   180 nsEditingSession::DisableJSAndPlugins(nsIDOMWindow *aWindow)
   181 {
   182   nsIDocShell *docShell = GetDocShellFromWindow(aWindow);
   183   NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
   185   bool tmp;
   186   nsresult rv = docShell->GetAllowJavascript(&tmp);
   187   NS_ENSURE_SUCCESS(rv, rv);
   189   mScriptsEnabled = tmp;
   191   rv = docShell->SetAllowJavascript(false);
   192   NS_ENSURE_SUCCESS(rv, rv);
   194   // Disable plugins in this document:
   195   mPluginsEnabled = docShell->PluginsAllowedInCurrentDoc();
   197   rv = docShell->SetAllowPlugins(false);
   198   NS_ENSURE_SUCCESS(rv, rv);
   200   mDisabledJSAndPlugins = true;
   202   return NS_OK;
   203 }
   205 NS_IMETHODIMP
   206 nsEditingSession::RestoreJSAndPlugins(nsIDOMWindow *aWindow)
   207 {
   208   NS_ENSURE_TRUE(mDisabledJSAndPlugins, NS_OK);
   210   mDisabledJSAndPlugins = false;
   212   nsIDocShell *docShell = GetDocShellFromWindow(aWindow);
   213   NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
   215   nsresult rv = docShell->SetAllowJavascript(mScriptsEnabled);
   216   NS_ENSURE_SUCCESS(rv, rv);
   218   // Disable plugins in this document:
   219   return docShell->SetAllowPlugins(mPluginsEnabled);
   220 }
   222 NS_IMETHODIMP
   223 nsEditingSession::GetJsAndPluginsDisabled(bool *aResult)
   224 {
   225   NS_ENSURE_ARG_POINTER(aResult);
   226   *aResult = mDisabledJSAndPlugins;
   227   return NS_OK;
   228 }
   230 /*---------------------------------------------------------------------------
   232   WindowIsEditable
   234   boolean windowIsEditable (in nsIDOMWindow aWindow);
   235 ----------------------------------------------------------------------------*/
   236 NS_IMETHODIMP
   237 nsEditingSession::WindowIsEditable(nsIDOMWindow *aWindow, bool *outIsEditable)
   238 {
   239   nsCOMPtr<nsIDocShell> docShell = GetDocShellFromWindow(aWindow);
   240   NS_ENSURE_STATE(docShell);
   242   return docShell->GetEditable(outIsEditable);
   243 }
   246 // These are MIME types that are automatically parsed as "text/plain"
   247 //   and thus we can edit them as plaintext
   248 // Note: in older versions, we attempted to convert the mimetype of
   249 //   the network channel for these and "text/xml" to "text/plain", 
   250 //   but further investigation reveals that strategy doesn't work
   251 const char* const gSupportedTextTypes[] = {
   252   "text/plain",
   253   "text/css",
   254   "text/rdf",
   255   "text/xsl",
   256   "text/javascript",           // obsolete type
   257   "text/ecmascript",           // obsolete type
   258   "application/javascript",
   259   "application/ecmascript",
   260   "application/x-javascript",  // obsolete type
   261   "text/xul",                  // obsolete type
   262   "application/vnd.mozilla.xul+xml",
   263   nullptr   // IMPORTANT! Null must be at end
   264 };
   266 bool
   267 IsSupportedTextType(const char* aMIMEType)
   268 {
   269   NS_ENSURE_TRUE(aMIMEType, false);
   271   int32_t i = 0;
   272   while (gSupportedTextTypes[i])
   273   {
   274     if (strcmp(gSupportedTextTypes[i], aMIMEType) == 0)
   275     {
   276       return true;
   277     }
   279     i ++;
   280   }
   282   return false;
   283 }
   285 /*---------------------------------------------------------------------------
   287   SetupEditorOnWindow
   289   nsIEditor setupEditorOnWindow (in nsIDOMWindow aWindow);
   290 ----------------------------------------------------------------------------*/
   291 NS_IMETHODIMP
   292 nsEditingSession::SetupEditorOnWindow(nsIDOMWindow *aWindow)
   293 {
   294   mDoneSetup = true;
   296   nsresult rv;
   298   //MIME CHECKING
   299   //must get the content type
   300   // Note: the doc gets this from the network channel during StartPageLoad,
   301   //    so we don't have to get it from there ourselves
   302   nsCOMPtr<nsIDOMDocument> doc;
   303   nsAutoCString mimeCType;
   305   //then lets check the mime type
   306   if (NS_SUCCEEDED(aWindow->GetDocument(getter_AddRefs(doc))) && doc)
   307   {
   308     nsAutoString mimeType;
   309     if (NS_SUCCEEDED(doc->GetContentType(mimeType)))
   310       AppendUTF16toUTF8(mimeType, mimeCType);
   312     if (IsSupportedTextType(mimeCType.get()))
   313     {
   314       mEditorType.AssignLiteral("text");
   315       mimeCType = "text/plain";
   316     }
   317     else if (!mimeCType.EqualsLiteral("text/html") &&
   318              !mimeCType.EqualsLiteral("application/xhtml+xml"))
   319     {
   320       // Neither an acceptable text or html type.
   321       mEditorStatus = eEditorErrorCantEditMimeType;
   323       // Turn editor into HTML -- we will load blank page later
   324       mEditorType.AssignLiteral("html");
   325       mimeCType.AssignLiteral("text/html");
   326     }
   328     // Flush out frame construction to make sure that the subframe's
   329     // presshell is set up if it needs to be.
   330     nsCOMPtr<nsIDocument> document = do_QueryInterface(doc);
   331     if (document) {
   332       document->FlushPendingNotifications(Flush_Frames);
   333       if (mMakeWholeDocumentEditable) {
   334         document->SetEditableFlag(true);
   335         nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(document);
   336         if (htmlDocument) {
   337           // Enable usage of the execCommand API
   338           htmlDocument->SetEditingState(nsIHTMLDocument::eDesignMode);
   339         }
   340       }
   341     }
   342   }
   343   bool needHTMLController = false;
   345   const char *classString = "@mozilla.org/editor/htmleditor;1";
   346   if (mEditorType.EqualsLiteral("textmail"))
   347   {
   348     mEditorFlags = nsIPlaintextEditor::eEditorPlaintextMask | 
   349                    nsIPlaintextEditor::eEditorEnableWrapHackMask | 
   350                    nsIPlaintextEditor::eEditorMailMask;
   351   }
   352   else if (mEditorType.EqualsLiteral("text"))
   353   {
   354     mEditorFlags = nsIPlaintextEditor::eEditorPlaintextMask | 
   355                    nsIPlaintextEditor::eEditorEnableWrapHackMask;
   356   }
   357   else if (mEditorType.EqualsLiteral("htmlmail"))
   358   {
   359     if (mimeCType.EqualsLiteral("text/html"))
   360     {
   361       needHTMLController = true;
   362       mEditorFlags = nsIPlaintextEditor::eEditorMailMask;
   363     }
   364     else //set the flags back to textplain.
   365       mEditorFlags = nsIPlaintextEditor::eEditorPlaintextMask | 
   366                      nsIPlaintextEditor::eEditorEnableWrapHackMask;
   367   }
   368   else // Defaulted to html
   369   {
   370     needHTMLController = true;
   371   }
   373   if (mInteractive) {
   374     mEditorFlags |= nsIPlaintextEditor::eEditorAllowInteraction;
   375   }
   377   // make the UI state maintainer
   378   mStateMaintainer = new nsComposerCommandsUpdater();
   380   // now init the state maintainer
   381   // This allows notification of error state
   382   //  even if we don't create an editor
   383   rv = mStateMaintainer->Init(aWindow);
   384   NS_ENSURE_SUCCESS(rv, rv);
   386   if (mEditorStatus != eEditorCreationInProgress)
   387   {
   388     mStateMaintainer->NotifyDocumentCreated();
   389     return NS_ERROR_FAILURE;
   390   }
   392   // Create editor and do other things 
   393   //  only if we haven't found some error above,
   394   nsCOMPtr<nsIDocShell> docShell = GetDocShellFromWindow(aWindow);
   395   NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);  
   397   if (!mInteractive) {
   398     // Disable animation of images in this document:
   399     nsCOMPtr<nsIDOMWindowUtils> utils(do_GetInterface(aWindow));
   400     NS_ENSURE_TRUE(utils, NS_ERROR_FAILURE);
   402     rv = utils->GetImageAnimationMode(&mImageAnimationMode);
   403     NS_ENSURE_SUCCESS(rv, rv);
   404     utils->SetImageAnimationMode(imgIContainer::kDontAnimMode);
   405   }
   407   // create and set editor
   408   // Try to reuse an existing editor
   409   nsCOMPtr<nsIEditor> editor = do_QueryReferent(mExistingEditor);
   410   if (editor) {
   411     editor->PreDestroy(false);
   412   } else {
   413     editor = do_CreateInstance(classString, &rv);
   414     NS_ENSURE_SUCCESS(rv, rv);
   415     mExistingEditor = do_GetWeakReference(editor);
   416   }
   417   // set the editor on the docShell. The docShell now owns it.
   418   rv = docShell->SetEditor(editor);
   419   NS_ENSURE_SUCCESS(rv, rv);
   421   // setup the HTML editor command controller
   422   if (needHTMLController)
   423   {
   424     // The third controller takes an nsIEditor as the context
   425     rv = SetupEditorCommandController("@mozilla.org/editor/htmleditorcontroller;1",
   426                                       aWindow, editor,
   427                                       &mHTMLCommandControllerId);
   428     NS_ENSURE_SUCCESS(rv, rv);
   429   }
   431   // Set mimetype on editor
   432   rv = editor->SetContentsMIMEType(mimeCType.get());
   433   NS_ENSURE_SUCCESS(rv, rv);
   435   nsCOMPtr<nsIContentViewer> contentViewer;
   436   rv = docShell->GetContentViewer(getter_AddRefs(contentViewer));
   437   NS_ENSURE_SUCCESS(rv, rv);
   438   NS_ENSURE_TRUE(contentViewer, NS_ERROR_FAILURE);
   440   nsCOMPtr<nsIDOMDocument> domDoc;  
   441   rv = contentViewer->GetDOMDocument(getter_AddRefs(domDoc));
   442   NS_ENSURE_SUCCESS(rv, rv);
   443   NS_ENSURE_TRUE(domDoc, NS_ERROR_FAILURE);
   445   // Set up as a doc state listener
   446   // Important! We must have this to broadcast the "obs_documentCreated" message
   447   rv = editor->AddDocumentStateListener(mStateMaintainer);
   448   NS_ENSURE_SUCCESS(rv, rv);
   450   rv = editor->Init(domDoc, nullptr /* root content */,
   451                     nullptr, mEditorFlags, EmptyString());
   452   NS_ENSURE_SUCCESS(rv, rv);
   454   nsCOMPtr<nsISelection> selection;
   455   editor->GetSelection(getter_AddRefs(selection));
   456   nsCOMPtr<nsISelectionPrivate> selPriv = do_QueryInterface(selection);
   457   NS_ENSURE_TRUE(selPriv, NS_ERROR_FAILURE);
   459   rv = selPriv->AddSelectionListener(mStateMaintainer);
   460   NS_ENSURE_SUCCESS(rv, rv);
   462   // and as a transaction listener
   463   nsCOMPtr<nsITransactionManager> txnMgr;
   464   editor->GetTransactionManager(getter_AddRefs(txnMgr));
   465   if (txnMgr)
   466     txnMgr->AddListener(mStateMaintainer);
   468   // Set context on all controllers to be the editor
   469   rv = SetEditorOnControllers(aWindow, editor);
   470   NS_ENSURE_SUCCESS(rv, rv);
   472   // Everything went fine!
   473   mEditorStatus = eEditorOK;
   475   // This will trigger documentCreation notification
   476   return editor->PostCreate();
   477 }
   479 // Removes all listeners and controllers from aWindow and aEditor.
   480 void
   481 nsEditingSession::RemoveListenersAndControllers(nsIDOMWindow *aWindow,
   482                                                 nsIEditor *aEditor)
   483 {
   484   if (!mStateMaintainer || !aEditor)
   485     return;
   487   // Remove all the listeners
   488   nsCOMPtr<nsISelection> selection;
   489   aEditor->GetSelection(getter_AddRefs(selection));
   490   nsCOMPtr<nsISelectionPrivate> selPriv = do_QueryInterface(selection);
   491   if (selPriv)
   492     selPriv->RemoveSelectionListener(mStateMaintainer);
   494   aEditor->RemoveDocumentStateListener(mStateMaintainer);
   496   nsCOMPtr<nsITransactionManager> txnMgr;
   497   aEditor->GetTransactionManager(getter_AddRefs(txnMgr));
   498   if (txnMgr)
   499     txnMgr->RemoveListener(mStateMaintainer);
   501   // Remove editor controllers from the window now that we're not
   502   // editing in that window any more.
   503   RemoveEditorControllers(aWindow);
   504 }
   506 /*---------------------------------------------------------------------------
   508   TearDownEditorOnWindow
   510   void tearDownEditorOnWindow (in nsIDOMWindow aWindow);
   511 ----------------------------------------------------------------------------*/
   512 NS_IMETHODIMP
   513 nsEditingSession::TearDownEditorOnWindow(nsIDOMWindow *aWindow)
   514 {
   515   if (!mDoneSetup) {
   516     return NS_OK;
   517   }
   519   NS_ENSURE_TRUE(aWindow, NS_ERROR_NULL_POINTER);
   521   nsresult rv;
   523   // Kill any existing reload timer
   524   if (mLoadBlankDocTimer)
   525   {
   526     mLoadBlankDocTimer->Cancel();
   527     mLoadBlankDocTimer = nullptr;
   528   }
   530   mDoneSetup = false;
   532   // Check if we're turning off editing (from contentEditable or designMode).
   533   nsCOMPtr<nsIDOMDocument> domDoc;
   534   aWindow->GetDocument(getter_AddRefs(domDoc));
   535   nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(domDoc);
   536   bool stopEditing = htmlDoc && htmlDoc->IsEditingOn();
   537   if (stopEditing)
   538     RemoveWebProgressListener(aWindow);
   540   nsCOMPtr<nsIDocShell> docShell = GetDocShellFromWindow(aWindow);
   541   NS_ENSURE_STATE(docShell);
   543   nsCOMPtr<nsIEditor> editor;
   544   rv = docShell->GetEditor(getter_AddRefs(editor));
   545   NS_ENSURE_SUCCESS(rv, rv);
   547   if (stopEditing)
   548     htmlDoc->TearingDownEditor(editor);
   550   if (mStateMaintainer && editor)
   551   {
   552     // Null out the editor on the controllers first to prevent their weak 
   553     // references from pointing to a destroyed editor.
   554     SetEditorOnControllers(aWindow, nullptr);
   555   }
   557   // Null out the editor on the docShell to trigger PreDestroy which
   558   // needs to happen before document state listeners are removed below.
   559   docShell->SetEditor(nullptr);
   561   RemoveListenersAndControllers(aWindow, editor);
   563   if (stopEditing)
   564   {
   565     // Make things the way they were before we started editing.
   566     RestoreJSAndPlugins(aWindow);
   567     RestoreAnimationMode(aWindow);
   569     if (mMakeWholeDocumentEditable)
   570     {
   571       nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc, &rv);
   572       NS_ENSURE_SUCCESS(rv, rv);
   574       doc->SetEditableFlag(false);
   575       nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(doc);
   576       if (htmlDocument) {
   577         htmlDocument->SetEditingState(nsIHTMLDocument::eOff);
   578       }
   579     }
   580   }
   582   return rv;
   583 }
   585 /*---------------------------------------------------------------------------
   587   GetEditorForFrame
   589   nsIEditor getEditorForFrame (in nsIDOMWindow aWindow);
   590 ----------------------------------------------------------------------------*/
   591 NS_IMETHODIMP 
   592 nsEditingSession::GetEditorForWindow(nsIDOMWindow *aWindow,
   593                                      nsIEditor **outEditor)
   594 {
   595   nsCOMPtr<nsIDocShell> docShell = GetDocShellFromWindow(aWindow);
   596   NS_ENSURE_STATE(aWindow);
   598   return docShell->GetEditor(outEditor);
   599 }
   601 /*---------------------------------------------------------------------------
   603   OnStateChange
   605 ----------------------------------------------------------------------------*/
   606 NS_IMETHODIMP
   607 nsEditingSession::OnStateChange(nsIWebProgress *aWebProgress,
   608                                 nsIRequest *aRequest,
   609                                 uint32_t aStateFlags, nsresult aStatus)
   610 {
   612 #ifdef NOISY_DOC_LOADING
   613   nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
   614   if (channel)
   615   {
   616     nsAutoCString contentType;
   617     channel->GetContentType(contentType);
   618     if (!contentType.IsEmpty())
   619       printf(" ++++++ MIMETYPE = %s\n", contentType.get());
   620   }
   621 #endif
   623   //
   624   // A Request has started...
   625   //
   626   if (aStateFlags & nsIWebProgressListener::STATE_START)
   627   {
   628 #ifdef NOISY_DOC_LOADING
   629   {
   630     nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
   631     if (channel)
   632     {
   633       nsCOMPtr<nsIURI> uri;
   634       channel->GetURI(getter_AddRefs(uri));
   635       if (uri)
   636       {
   637         nsXPIDLCString spec;
   638         uri->GetSpec(spec);
   639         printf(" **** STATE_START: CHANNEL URI=%s, flags=%x\n",
   640                spec.get(), aStateFlags);
   641       }
   642     }
   643     else
   644       printf("    STATE_START: NO CHANNEL flags=%x\n", aStateFlags);
   645   }
   646 #endif
   647     // Page level notification...
   648     if (aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK)
   649     {
   650       nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
   651       StartPageLoad(channel);
   652 #ifdef NOISY_DOC_LOADING
   653       printf("STATE_START & STATE_IS_NETWORK flags=%x\n", aStateFlags);
   654 #endif
   655     }
   657     // Document level notification...
   658     if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT &&
   659         !(aStateFlags & nsIWebProgressListener::STATE_RESTORING)) {
   660 #ifdef NOISY_DOC_LOADING
   661       printf("STATE_START & STATE_IS_DOCUMENT flags=%x\n", aStateFlags);
   662 #endif
   664       bool progressIsForTargetDocument =
   665         IsProgressForTargetDocument(aWebProgress);
   667       if (progressIsForTargetDocument)
   668       {
   669         nsCOMPtr<nsIDOMWindow> window;
   670         aWebProgress->GetDOMWindow(getter_AddRefs(window));
   672         nsCOMPtr<nsIDOMDocument> doc;
   673         window->GetDocument(getter_AddRefs(doc));
   675         nsCOMPtr<nsIHTMLDocument> htmlDoc(do_QueryInterface(doc));
   677         if (htmlDoc && htmlDoc->IsWriting())
   678         {
   679           nsCOMPtr<nsIDOMHTMLDocument> htmlDomDoc = do_QueryInterface(doc);
   680           nsAutoString designMode;
   681           htmlDomDoc->GetDesignMode(designMode);
   683           if (designMode.EqualsLiteral("on"))
   684           {
   685             // This notification is for data coming in through
   686             // document.open/write/close(), ignore it.
   688             return NS_OK;
   689           }
   690         }
   692         mCanCreateEditor = true;
   693         StartDocumentLoad(aWebProgress, progressIsForTargetDocument);
   694       }
   695     }
   696   }
   697   //
   698   // A Request is being processed
   699   //
   700   else if (aStateFlags & nsIWebProgressListener::STATE_TRANSFERRING)
   701   {
   702     if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT)
   703     {
   704       // document transfer started
   705     }
   706   }
   707   //
   708   // Got a redirection
   709   //
   710   else if (aStateFlags & nsIWebProgressListener::STATE_REDIRECTING)
   711   {
   712     if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT)
   713     {
   714       // got a redirect
   715     }
   716   }
   717   //
   718   // A network or document Request has finished...
   719   //
   720   else if (aStateFlags & nsIWebProgressListener::STATE_STOP)
   721   {
   723 #ifdef NOISY_DOC_LOADING
   724   {
   725     nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
   726     if (channel)
   727     {
   728       nsCOMPtr<nsIURI> uri;
   729       channel->GetURI(getter_AddRefs(uri));
   730       if (uri)
   731       {
   732         nsXPIDLCString spec;
   733         uri->GetSpec(spec);
   734         printf(" **** STATE_STOP: CHANNEL URI=%s, flags=%x\n",
   735                spec.get(), aStateFlags);
   736       }
   737     }
   738     else
   739       printf("     STATE_STOP: NO CHANNEL  flags=%x\n", aStateFlags);
   740   }
   741 #endif
   743     // Document level notification...
   744     if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT)
   745     {
   746       nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
   747       EndDocumentLoad(aWebProgress, channel, aStatus,
   748                       IsProgressForTargetDocument(aWebProgress));
   749 #ifdef NOISY_DOC_LOADING
   750       printf("STATE_STOP & STATE_IS_DOCUMENT flags=%x\n", aStateFlags);
   751 #endif
   752     }
   754     // Page level notification...
   755     if (aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK)
   756     {
   757       nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
   758       (void)EndPageLoad(aWebProgress, channel, aStatus);
   759 #ifdef NOISY_DOC_LOADING
   760       printf("STATE_STOP & STATE_IS_NETWORK flags=%x\n", aStateFlags);
   761 #endif
   762     }
   763   }
   765   return NS_OK;
   766 }
   768 /*---------------------------------------------------------------------------
   770   OnProgressChange
   772 ----------------------------------------------------------------------------*/
   773 NS_IMETHODIMP
   774 nsEditingSession::OnProgressChange(nsIWebProgress *aWebProgress,
   775                                    nsIRequest *aRequest,
   776                                    int32_t aCurSelfProgress,
   777                                    int32_t aMaxSelfProgress,
   778                                    int32_t aCurTotalProgress,
   779                                    int32_t aMaxTotalProgress)
   780 {
   781     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
   782     return NS_OK;
   783 }
   785 /*---------------------------------------------------------------------------
   787   OnLocationChange
   789 ----------------------------------------------------------------------------*/
   790 NS_IMETHODIMP
   791 nsEditingSession::OnLocationChange(nsIWebProgress *aWebProgress, 
   792                                    nsIRequest *aRequest, nsIURI *aURI,
   793                                    uint32_t aFlags)
   794 {
   795   nsCOMPtr<nsIDOMWindow> domWindow;
   796   nsresult rv = aWebProgress->GetDOMWindow(getter_AddRefs(domWindow));
   797   NS_ENSURE_SUCCESS(rv, rv);
   799   nsCOMPtr<nsIDOMDocument> domDoc;
   800   rv = domWindow->GetDocument(getter_AddRefs(domDoc));
   801   NS_ENSURE_SUCCESS(rv, rv);
   803   nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
   804   NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
   806   doc->SetDocumentURI(aURI);
   808   // Notify the location-changed observer that
   809   //  the document URL has changed
   810   nsIDocShell *docShell = GetDocShellFromWindow(domWindow);
   811   NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
   813   nsCOMPtr<nsICommandManager> commandManager = do_GetInterface(docShell);
   814   nsCOMPtr<nsPICommandUpdater> commandUpdater =
   815                                   do_QueryInterface(commandManager);
   816   NS_ENSURE_TRUE(commandUpdater, NS_ERROR_FAILURE);
   818   return commandUpdater->CommandStatusChanged("obs_documentLocationChanged");
   819 }
   821 /*---------------------------------------------------------------------------
   823   OnStatusChange
   825 ----------------------------------------------------------------------------*/
   826 NS_IMETHODIMP
   827 nsEditingSession::OnStatusChange(nsIWebProgress *aWebProgress,
   828                                  nsIRequest *aRequest,
   829                                  nsresult aStatus,
   830                                  const char16_t *aMessage)
   831 {
   832     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
   833     return NS_OK;
   834 }
   836 /*---------------------------------------------------------------------------
   838   OnSecurityChange
   840 ----------------------------------------------------------------------------*/
   841 NS_IMETHODIMP
   842 nsEditingSession::OnSecurityChange(nsIWebProgress *aWebProgress,
   843                                    nsIRequest *aRequest, uint32_t state)
   844 {
   845     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
   846     return NS_OK;
   847 }
   850 /*---------------------------------------------------------------------------
   852   IsProgressForTargetDocument
   854   Check that this notification is for our document.
   855 ----------------------------------------------------------------------------*/
   857 bool
   858 nsEditingSession::IsProgressForTargetDocument(nsIWebProgress *aWebProgress)
   859 {
   860   nsCOMPtr<nsIWebProgress> editedWebProgress = do_QueryReferent(mDocShell);
   861   return editedWebProgress == aWebProgress;
   862 }
   865 /*---------------------------------------------------------------------------
   867   GetEditorStatus
   869   Called during GetCommandStateParams("obs_documentCreated"...) 
   870   to determine if editor was created and document 
   871   was loaded successfully
   872 ----------------------------------------------------------------------------*/
   873 NS_IMETHODIMP
   874 nsEditingSession::GetEditorStatus(uint32_t *aStatus)
   875 {
   876   NS_ENSURE_ARG_POINTER(aStatus);
   877   *aStatus = mEditorStatus;
   878   return NS_OK;
   879 }
   881 /*---------------------------------------------------------------------------
   883   StartDocumentLoad
   885   Called on start of load in a single frame
   886 ----------------------------------------------------------------------------*/
   887 nsresult
   888 nsEditingSession::StartDocumentLoad(nsIWebProgress *aWebProgress, 
   889                                     bool aIsToBeMadeEditable)
   890 {
   891 #ifdef NOISY_DOC_LOADING
   892   printf("======= StartDocumentLoad ========\n");
   893 #endif
   895   NS_ENSURE_ARG_POINTER(aWebProgress);
   897   // If we have an editor here, then we got a reload after making the editor.
   898   // We need to blow it away and make a new one at the end of the load.
   899   nsCOMPtr<nsIDOMWindow> domWindow;
   900   aWebProgress->GetDOMWindow(getter_AddRefs(domWindow));
   901   if (domWindow)
   902   {
   903     nsIDocShell *docShell = GetDocShellFromWindow(domWindow);
   904     NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
   905     docShell->DetachEditorFromWindow();
   906   }
   908   if (aIsToBeMadeEditable)
   909     mEditorStatus = eEditorCreationInProgress;
   911   return NS_OK;
   912 }
   914 /*---------------------------------------------------------------------------
   916   EndDocumentLoad
   918   Called on end of load in a single frame
   919 ----------------------------------------------------------------------------*/
   920 nsresult
   921 nsEditingSession::EndDocumentLoad(nsIWebProgress *aWebProgress,
   922                                   nsIChannel* aChannel, nsresult aStatus,
   923                                   bool aIsToBeMadeEditable)
   924 {
   925   NS_ENSURE_ARG_POINTER(aWebProgress);
   927 #ifdef NOISY_DOC_LOADING
   928   printf("======= EndDocumentLoad ========\n");
   929   printf("with status %d, ", aStatus);
   930   nsCOMPtr<nsIURI> uri;
   931   nsXPIDLCString spec;
   932   if (NS_SUCCEEDED(aChannel->GetURI(getter_AddRefs(uri)))) {
   933     uri->GetSpec(spec);
   934     printf(" uri %s\n", spec.get());
   935   }
   936 #endif
   938   // We want to call the base class EndDocumentLoad,
   939   // but avoid some of the stuff
   940   // that nsDocShell does (need to refactor).
   942   // OK, time to make an editor on this document
   943   nsCOMPtr<nsIDOMWindow> domWindow;
   944   aWebProgress->GetDOMWindow(getter_AddRefs(domWindow));
   946   // Set the error state -- we will create an editor 
   947   // anyway and load empty doc later
   948   if (aIsToBeMadeEditable) {
   949     if (aStatus == NS_ERROR_FILE_NOT_FOUND)
   950       mEditorStatus = eEditorErrorFileNotFound;
   951   }
   953   nsIDocShell *docShell = GetDocShellFromWindow(domWindow);
   954   NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);       // better error handling?
   956   // cancel refresh from meta tags
   957   // we need to make sure that all pages in editor (whether editable or not)
   958   // can't refresh contents being edited
   959   nsCOMPtr<nsIRefreshURI> refreshURI = do_QueryInterface(docShell);
   960   if (refreshURI)
   961     refreshURI->CancelRefreshURITimers();
   963   nsresult rv = NS_OK;
   965   // did someone set the flag to make this shell editable?
   966   if (aIsToBeMadeEditable && mCanCreateEditor)
   967   {
   968     bool    makeEditable;
   969     docShell->GetEditable(&makeEditable);
   971     if (makeEditable)
   972     {
   973       // To keep pre Gecko 1.9 behavior, setup editor always when
   974       // mMakeWholeDocumentEditable.
   975       bool needsSetup = false;
   976       if (mMakeWholeDocumentEditable) {
   977         needsSetup = true;
   978       } else {
   979         // do we already have an editor here?
   980         nsCOMPtr<nsIEditor> editor;
   981         rv = docShell->GetEditor(getter_AddRefs(editor));
   982         NS_ENSURE_SUCCESS(rv, rv);
   984         needsSetup = !editor;
   985       }
   987       if (needsSetup)
   988       {
   989         mCanCreateEditor = false;
   990         rv = SetupEditorOnWindow(domWindow);
   991         if (NS_FAILED(rv))
   992         {
   993           // If we had an error, setup timer to load a blank page later
   994           if (mLoadBlankDocTimer)
   995           {
   996             // Must cancel previous timer?
   997             mLoadBlankDocTimer->Cancel();
   998             mLoadBlankDocTimer = nullptr;
   999           }
  1001           mLoadBlankDocTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
  1002           NS_ENSURE_SUCCESS(rv, rv);
  1004           mEditorStatus = eEditorCreationInProgress;
  1005           mLoadBlankDocTimer->InitWithFuncCallback(
  1006                                           nsEditingSession::TimerCallback,
  1007                                           static_cast<void*> (mDocShell.get()),
  1008                                           10, nsITimer::TYPE_ONE_SHOT);
  1013   return rv;
  1017 void
  1018 nsEditingSession::TimerCallback(nsITimer* aTimer, void* aClosure)
  1020   nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(static_cast<nsIWeakReference*> (aClosure));
  1021   if (docShell)
  1023     nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell));
  1024     if (webNav)
  1025       webNav->LoadURI(MOZ_UTF16("about:blank"),
  1026                       0, nullptr, nullptr, nullptr);
  1030 /*---------------------------------------------------------------------------
  1032   StartPageLoad
  1034   Called on start load of the entire page (incl. subframes)
  1035 ----------------------------------------------------------------------------*/
  1036 nsresult
  1037 nsEditingSession::StartPageLoad(nsIChannel *aChannel)
  1039 #ifdef NOISY_DOC_LOADING
  1040   printf("======= StartPageLoad ========\n");
  1041 #endif
  1042   return NS_OK;
  1045 /*---------------------------------------------------------------------------
  1047   EndPageLoad
  1049   Called on end load of the entire page (incl. subframes)
  1050 ----------------------------------------------------------------------------*/
  1051 nsresult
  1052 nsEditingSession::EndPageLoad(nsIWebProgress *aWebProgress,
  1053                               nsIChannel* aChannel, nsresult aStatus)
  1055 #ifdef NOISY_DOC_LOADING
  1056   printf("======= EndPageLoad ========\n");
  1057   printf("  with status %d, ", aStatus);
  1058   nsCOMPtr<nsIURI> uri;
  1059   nsXPIDLCString spec;
  1060   if (NS_SUCCEEDED(aChannel->GetURI(getter_AddRefs(uri)))) {
  1061     uri->GetSpec(spec);
  1062     printf("uri %s\n", spec.get());
  1065   nsAutoCString contentType;
  1066   aChannel->GetContentType(contentType);
  1067   if (!contentType.IsEmpty())
  1068     printf("   flags = %d, status = %d, MIMETYPE = %s\n", 
  1069                mEditorFlags, mEditorStatus, contentType.get());
  1070 #endif
  1072   // Set the error state -- we will create an editor anyway 
  1073   // and load empty doc later
  1074   if (aStatus == NS_ERROR_FILE_NOT_FOUND)
  1075     mEditorStatus = eEditorErrorFileNotFound;
  1077   nsCOMPtr<nsIDOMWindow> domWindow;
  1078   aWebProgress->GetDOMWindow(getter_AddRefs(domWindow));
  1080   nsIDocShell *docShell = GetDocShellFromWindow(domWindow);
  1081   NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
  1083   // cancel refresh from meta tags
  1084   // we need to make sure that all pages in editor (whether editable or not)
  1085   // can't refresh contents being edited
  1086   nsCOMPtr<nsIRefreshURI> refreshURI = do_QueryInterface(docShell);
  1087   if (refreshURI)
  1088     refreshURI->CancelRefreshURITimers();
  1090 #if 0
  1091   // Shouldn't we do this when we want to edit sub-frames?
  1092   return MakeWindowEditable(domWindow, "html", false, mInteractive);
  1093 #else
  1094   return NS_OK;
  1095 #endif
  1098 /*---------------------------------------------------------------------------
  1100   GetDocShellFromWindow
  1102   Utility method. This will always return nullptr if no docShell is found.
  1103 ----------------------------------------------------------------------------*/
  1104 nsIDocShell *
  1105 nsEditingSession::GetDocShellFromWindow(nsIDOMWindow *aWindow)
  1107   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
  1108   NS_ENSURE_TRUE(window, nullptr);
  1110   return window->GetDocShell();
  1113 /*---------------------------------------------------------------------------
  1115   PrepareForEditing
  1117   Set up this editing session for one or more editors
  1118 ----------------------------------------------------------------------------*/
  1119 nsresult
  1120 nsEditingSession::PrepareForEditing(nsIDOMWindow *aWindow)
  1122   if (mProgressListenerRegistered)
  1123     return NS_OK;
  1125   nsIDocShell *docShell = GetDocShellFromWindow(aWindow);
  1127   // register callback
  1128   nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
  1129   NS_ENSURE_TRUE(webProgress, NS_ERROR_FAILURE);
  1131   nsresult rv =
  1132     webProgress->AddProgressListener(this,
  1133                                      (nsIWebProgress::NOTIFY_STATE_NETWORK  | 
  1134                                       nsIWebProgress::NOTIFY_STATE_DOCUMENT |
  1135                                       nsIWebProgress::NOTIFY_LOCATION));
  1137   mProgressListenerRegistered = NS_SUCCEEDED(rv);
  1139   return rv;
  1142 /*---------------------------------------------------------------------------
  1144   SetupEditorCommandController
  1146   Create a command controller, append to controllers,
  1147   get and return the controller ID, and set the context
  1148 ----------------------------------------------------------------------------*/
  1149 nsresult
  1150 nsEditingSession::SetupEditorCommandController(
  1151                                   const char *aControllerClassName,
  1152                                   nsIDOMWindow *aWindow,
  1153                                   nsISupports *aContext,
  1154                                   uint32_t *aControllerId)
  1156   NS_ENSURE_ARG_POINTER(aControllerClassName);
  1157   NS_ENSURE_ARG_POINTER(aWindow);
  1158   NS_ENSURE_ARG_POINTER(aContext);
  1159   NS_ENSURE_ARG_POINTER(aControllerId);
  1161   nsCOMPtr<nsIControllers> controllers;      
  1162   nsresult rv = aWindow->GetControllers(getter_AddRefs(controllers));
  1163   NS_ENSURE_SUCCESS(rv, rv);
  1165   // We only have to create each singleton controller once
  1166   // We know this has happened once we have a controllerId value
  1167   if (!*aControllerId)
  1169     nsCOMPtr<nsIController> controller;
  1170     controller = do_CreateInstance(aControllerClassName, &rv);
  1171     NS_ENSURE_SUCCESS(rv, rv);  
  1173     // We must insert at head of the list to be sure our
  1174     //   controller is found before other implementations
  1175     //   (e.g., not-implemented versions by browser)
  1176     rv = controllers->InsertControllerAt(0, controller);
  1177     NS_ENSURE_SUCCESS(rv, rv);  
  1179     // Remember the ID for the controller
  1180     rv = controllers->GetControllerId(controller, aControllerId);
  1181     NS_ENSURE_SUCCESS(rv, rv);  
  1184   // Set the context
  1185   return SetContextOnControllerById(controllers, aContext, *aControllerId);
  1188 /*---------------------------------------------------------------------------
  1190   SetEditorOnControllers
  1192   Set the editor on the controller(s) for this window
  1193 ----------------------------------------------------------------------------*/
  1194 NS_IMETHODIMP
  1195 nsEditingSession::SetEditorOnControllers(nsIDOMWindow *aWindow,
  1196                                          nsIEditor* aEditor)
  1198   NS_ENSURE_TRUE(aWindow, NS_ERROR_NULL_POINTER);
  1200   nsCOMPtr<nsIControllers> controllers;      
  1201   nsresult rv = aWindow->GetControllers(getter_AddRefs(controllers));
  1202   NS_ENSURE_SUCCESS(rv, rv);
  1204   nsCOMPtr<nsISupports> editorAsISupports = do_QueryInterface(aEditor);
  1205   if (mBaseCommandControllerId)
  1207     rv = SetContextOnControllerById(controllers, editorAsISupports,
  1208                                     mBaseCommandControllerId);
  1209     NS_ENSURE_SUCCESS(rv, rv);
  1212   if (mDocStateControllerId)
  1214     rv = SetContextOnControllerById(controllers, editorAsISupports,
  1215                                     mDocStateControllerId);
  1216     NS_ENSURE_SUCCESS(rv, rv);
  1219   if (mHTMLCommandControllerId)
  1220     rv = SetContextOnControllerById(controllers, editorAsISupports,
  1221                                     mHTMLCommandControllerId);
  1223   return rv;
  1226 nsresult
  1227 nsEditingSession::SetContextOnControllerById(nsIControllers* aControllers,
  1228                                              nsISupports* aContext,
  1229                                              uint32_t aID)
  1231   NS_ENSURE_ARG_POINTER(aControllers);
  1233   // aContext can be null (when destroying editor)
  1234   nsCOMPtr<nsIController> controller;    
  1235   aControllers->GetControllerById(aID, getter_AddRefs(controller));
  1237   // ok with nil controller
  1238   nsCOMPtr<nsIControllerContext> editorController =
  1239                                        do_QueryInterface(controller);
  1240   NS_ENSURE_TRUE(editorController, NS_ERROR_FAILURE);
  1242   return editorController->SetCommandContext(aContext);
  1245 void
  1246 nsEditingSession::RemoveEditorControllers(nsIDOMWindow *aWindow)
  1248   // Remove editor controllers from the aWindow, call when we're 
  1249   // tearing down/detaching editor.
  1251   nsCOMPtr<nsIControllers> controllers;
  1252   if (aWindow)
  1253     aWindow->GetControllers(getter_AddRefs(controllers));
  1255   if (controllers)
  1257     nsCOMPtr<nsIController> controller;
  1258     if (mBaseCommandControllerId)
  1260       controllers->GetControllerById(mBaseCommandControllerId,
  1261                                      getter_AddRefs(controller));
  1262       if (controller)
  1263         controllers->RemoveController(controller);
  1266     if (mDocStateControllerId)
  1268       controllers->GetControllerById(mDocStateControllerId,
  1269                                      getter_AddRefs(controller));
  1270       if (controller)
  1271         controllers->RemoveController(controller);
  1274     if (mHTMLCommandControllerId)
  1276       controllers->GetControllerById(mHTMLCommandControllerId,
  1277                                      getter_AddRefs(controller));
  1278       if (controller)
  1279         controllers->RemoveController(controller);
  1283   // Clear IDs to trigger creation of new controllers.
  1284   mBaseCommandControllerId = 0;
  1285   mDocStateControllerId = 0;
  1286   mHTMLCommandControllerId = 0;
  1289 void
  1290 nsEditingSession::RemoveWebProgressListener(nsIDOMWindow *aWindow)
  1292   nsIDocShell *docShell = GetDocShellFromWindow(aWindow);
  1293   nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
  1294   if (webProgress)
  1296     webProgress->RemoveProgressListener(this);
  1297     mProgressListenerRegistered = false;
  1301 void
  1302 nsEditingSession::RestoreAnimationMode(nsIDOMWindow *aWindow)
  1304   if (!mInteractive)
  1306     nsCOMPtr<nsIDOMWindowUtils> utils(do_GetInterface(aWindow));
  1307     if (utils)
  1308       utils->SetImageAnimationMode(mImageAnimationMode);
  1312 nsresult
  1313 nsEditingSession::DetachFromWindow(nsIDOMWindow* aWindow)
  1315   NS_ENSURE_TRUE(mDoneSetup, NS_OK);
  1317   NS_ASSERTION(mStateMaintainer, "mStateMaintainer should exist.");
  1319   // Kill any existing reload timer
  1320   if (mLoadBlankDocTimer)
  1322     mLoadBlankDocTimer->Cancel();
  1323     mLoadBlankDocTimer = nullptr;
  1326   // Remove controllers, webprogress listener, and otherwise
  1327   // make things the way they were before we started editing.
  1328   RemoveEditorControllers(aWindow);
  1329   RemoveWebProgressListener(aWindow);
  1330   RestoreJSAndPlugins(aWindow);
  1331   RestoreAnimationMode(aWindow);
  1333   // Kill our weak reference to our original window, in case
  1334   // it changes on restore, or otherwise dies.
  1335   mDocShell = nullptr;
  1337   return NS_OK;
  1340 nsresult
  1341 nsEditingSession::ReattachToWindow(nsIDOMWindow* aWindow)
  1343   NS_ENSURE_TRUE(mDoneSetup, NS_OK);
  1345   NS_ASSERTION(mStateMaintainer, "mStateMaintainer should exist.");
  1347   // Imitate nsEditorDocShell::MakeEditable() to reattach the
  1348   // old editor ot the window.
  1349   nsresult rv;
  1351   nsIDocShell *docShell = GetDocShellFromWindow(aWindow);
  1352   NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
  1353   mDocShell = do_GetWeakReference(docShell);
  1355   // Disable plugins.
  1356   if (!mInteractive)
  1358     rv = DisableJSAndPlugins(aWindow);
  1359     NS_ENSURE_SUCCESS(rv, rv);
  1362   // Tells embedder that startup is in progress.
  1363   mEditorStatus = eEditorCreationInProgress;
  1365   // Adds back web progress listener.
  1366   rv = PrepareForEditing(aWindow);
  1367   NS_ENSURE_SUCCESS(rv, rv);
  1369   // Setup the command controllers again.
  1370   rv = SetupEditorCommandController("@mozilla.org/editor/editingcontroller;1",
  1371                                     aWindow,
  1372                                     static_cast<nsIEditingSession*>(this),
  1373                                     &mBaseCommandControllerId);
  1374   NS_ENSURE_SUCCESS(rv, rv);
  1376   rv = SetupEditorCommandController("@mozilla.org/editor/editordocstatecontroller;1",
  1377                                     aWindow,
  1378                                     static_cast<nsIEditingSession*>(this),
  1379                                     &mDocStateControllerId);
  1380   NS_ENSURE_SUCCESS(rv, rv);
  1382   if (mStateMaintainer)
  1383     mStateMaintainer->Init(aWindow);
  1385   // Get editor
  1386   nsCOMPtr<nsIEditor> editor;
  1387   rv = GetEditorForWindow(aWindow, getter_AddRefs(editor));
  1388   NS_ENSURE_TRUE(editor, NS_ERROR_FAILURE);
  1390   if (!mInteractive)
  1392     // Disable animation of images in this document:
  1393     nsCOMPtr<nsIDOMWindowUtils> utils(do_GetInterface(aWindow));
  1394     NS_ENSURE_TRUE(utils, NS_ERROR_FAILURE);
  1396     rv = utils->GetImageAnimationMode(&mImageAnimationMode);
  1397     NS_ENSURE_SUCCESS(rv, rv);
  1398     utils->SetImageAnimationMode(imgIContainer::kDontAnimMode);
  1401   // The third controller takes an nsIEditor as the context
  1402   rv = SetupEditorCommandController("@mozilla.org/editor/htmleditorcontroller;1",
  1403                                     aWindow, editor,
  1404                                     &mHTMLCommandControllerId);
  1405   NS_ENSURE_SUCCESS(rv, rv);
  1407   // Set context on all controllers to be the editor
  1408   rv = SetEditorOnControllers(aWindow, editor);
  1409   NS_ENSURE_SUCCESS(rv, rv);
  1411 #ifdef DEBUG
  1413     bool isEditable;
  1414     rv = WindowIsEditable(aWindow, &isEditable);
  1415     NS_ENSURE_SUCCESS(rv, rv);
  1416     NS_ASSERTION(isEditable, "Window is not editable after reattaching editor.");
  1418 #endif // DEBUG
  1420   return NS_OK;

mercurial