tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsEditingSession.cpp (43232B)


      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/. */
      6 
      7 #include <string.h>  // for nullptr, strcmp
      8 
      9 #include "imgIContainer.h"                    // for imgIContainer, etc
     10 #include "mozilla/ComposerCommandsUpdater.h"  // for ComposerCommandsUpdater
     11 #include "mozilla/FlushType.h"                // for FlushType::Frames
     12 #include "mozilla/HTMLEditor.h"               // for HTMLEditor
     13 #include "mozilla/mozalloc.h"                 // for operator new
     14 #include "mozilla/PresShell.h"                // for PresShell
     15 #include "mozilla/Try.h"                      // for MOZ_TRY
     16 #include "nsAString.h"
     17 #include "nsBaseCommandController.h"  // for nsBaseCommandController
     18 #include "nsCommandManager.h"         // for nsCommandManager
     19 #include "nsComponentManagerUtils.h"  // for do_CreateInstance
     20 #include "nsContentUtils.h"
     21 #include "nsDebug.h"     // for NS_ENSURE_SUCCESS, etc
     22 #include "nsDocShell.h"  // for nsDocShell
     23 #include "nsEditingSession.h"
     24 #include "nsError.h"                      // for NS_ERROR_FAILURE, NS_OK, etc
     25 #include "nsIChannel.h"                   // for nsIChannel
     26 #include "nsIDocumentViewer.h"            // for nsIDocumentViewer
     27 #include "nsIControllers.h"               // for nsIControllers
     28 #include "nsID.h"                         // for NS_GET_IID, etc
     29 #include "nsHTMLDocument.h"               // for nsHTMLDocument
     30 #include "nsIDocShell.h"                  // for nsIDocShell
     31 #include "mozilla/dom/Document.h"         // for Document
     32 #include "nsIEditor.h"                    // for nsIEditor
     33 #include "nsIInterfaceRequestorUtils.h"   // for do_GetInterface
     34 #include "nsIRefreshURI.h"                // for nsIRefreshURI
     35 #include "nsIRequest.h"                   // for nsIRequest
     36 #include "nsITimer.h"                     // for nsITimer, etc
     37 #include "nsIWeakReference.h"             // for nsISupportsWeakReference, etc
     38 #include "nsIWebNavigation.h"             // for nsIWebNavigation
     39 #include "nsIWebProgress.h"               // for nsIWebProgress, etc
     40 #include "nsLiteralString.h"              // for NS_LITERAL_STRING
     41 #include "nsPIDOMWindow.h"                // for nsPIDOMWindow
     42 #include "nsPresContext.h"                // for nsPresContext
     43 #include "nsReadableUtils.h"              // for AppendUTF16toUTF8
     44 #include "nsStringFwd.h"                  // for nsString
     45 #include "mozilla/dom/BrowsingContext.h"  // for BrowsingContext
     46 #include "mozilla/dom/Selection.h"        // for AutoHideSelectionChanges, etc
     47 #include "mozilla/dom/WindowContext.h"    // for WindowContext
     48 #include "nsFrameSelection.h"             // for nsFrameSelection
     49 #include "nsBaseCommandController.h"      // for nsBaseCommandController
     50 #include "mozilla/dom/LoadURIOptionsBinding.h"
     51 
     52 class nsISupports;
     53 class nsIURI;
     54 
     55 using namespace mozilla;
     56 using namespace mozilla::dom;
     57 
     58 /*---------------------------------------------------------------------------
     59 
     60  nsEditingSession
     61 
     62 ----------------------------------------------------------------------------*/
     63 nsEditingSession::nsEditingSession()
     64    : mDoneSetup(false),
     65      mCanCreateEditor(false),
     66      mInteractive(false),
     67      mMakeWholeDocumentEditable(true),
     68      mDisabledJS(false),
     69      mScriptsEnabled(true),
     70      mProgressListenerRegistered(false),
     71      mImageAnimationMode(0),
     72      mEditorFlags(0),
     73      mEditorStatus(eEditorOK),
     74      mBaseCommandControllerId(0),
     75      mDocStateControllerId(0),
     76      mHTMLCommandControllerId(0) {}
     77 
     78 /*---------------------------------------------------------------------------
     79 
     80  ~nsEditingSession
     81 
     82 ----------------------------------------------------------------------------*/
     83 nsEditingSession::~nsEditingSession() {
     84  // Must cancel previous timer?
     85  if (mLoadBlankDocTimer) mLoadBlankDocTimer->Cancel();
     86 }
     87 
     88 NS_IMPL_ISUPPORTS(nsEditingSession, nsIEditingSession, nsIWebProgressListener,
     89                  nsISupportsWeakReference)
     90 
     91 /*---------------------------------------------------------------------------
     92 
     93  MakeWindowEditable
     94 
     95  aEditorType string, "html" "htmlsimple" "text" "textsimple"
     96  void makeWindowEditable(in nsIDOMWindow aWindow, in string aEditorType,
     97                          in boolean aDoAfterUriLoad,
     98                          in boolean aMakeWholeDocumentEditable,
     99                          in boolean aInteractive);
    100 ----------------------------------------------------------------------------*/
    101 #define DEFAULT_EDITOR_TYPE "html"
    102 
    103 NS_IMETHODIMP
    104 nsEditingSession::MakeWindowEditable(mozIDOMWindowProxy* aWindow,
    105                                     const char* aEditorType,
    106                                     bool aDoAfterUriLoad,
    107                                     bool aMakeWholeDocumentEditable,
    108                                     bool aInteractive) {
    109  mEditorType.Truncate();
    110  mEditorFlags = 0;
    111 
    112  NS_ENSURE_TRUE(aWindow, NS_ERROR_FAILURE);
    113  auto* window = nsPIDOMWindowOuter::From(aWindow);
    114 
    115  // disable plugins
    116  nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
    117  NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
    118  mDocShell = do_GetWeakReference(docShell);
    119 
    120  mInteractive = aInteractive;
    121  mMakeWholeDocumentEditable = aMakeWholeDocumentEditable;
    122 
    123  nsresult rv;
    124  if (!mInteractive) {
    125    rv = DisableJS(window->GetCurrentInnerWindow());
    126    NS_ENSURE_SUCCESS(rv, rv);
    127  }
    128 
    129  // Always remove existing editor
    130  TearDownEditorOnWindow(aWindow);
    131 
    132  // Tells embedder that startup is in progress
    133  mEditorStatus = eEditorCreationInProgress;
    134 
    135  // temporary to set editor type here. we will need different classes soon.
    136  if (!aEditorType) aEditorType = DEFAULT_EDITOR_TYPE;
    137  mEditorType = aEditorType;
    138 
    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(window);
    142  NS_ENSURE_SUCCESS(rv, rv);
    143 
    144  // set the flag on the docShell to say that it's editable
    145  rv = docShell->MakeEditable(aDoAfterUriLoad);
    146  NS_ENSURE_SUCCESS(rv, rv);
    147 
    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(
    152      nsBaseCommandController::CreateEditingController, aWindow, this,
    153      &mBaseCommandControllerId);
    154  NS_ENSURE_SUCCESS(rv, rv);
    155 
    156  // The second is a controller to monitor doc state,
    157  // such as creation and "dirty flag"
    158  rv = SetupEditorCommandController(
    159      nsBaseCommandController::CreateHTMLEditorDocStateController, aWindow,
    160      this, &mDocStateControllerId);
    161  NS_ENSURE_SUCCESS(rv, rv);
    162 
    163  // aDoAfterUriLoad can be false only when making an existing window editable
    164  if (!aDoAfterUriLoad) {
    165    rv = SetupEditorOnWindow(MOZ_KnownLive(*window));
    166 
    167    // mEditorStatus is set to the error reason
    168    // Since this is used only when editing an existing page,
    169    //  it IS ok to destroy current editor
    170    if (NS_FAILED(rv)) {
    171      TearDownEditorOnWindow(aWindow);
    172    }
    173  }
    174  return rv;
    175 }
    176 
    177 nsresult nsEditingSession::DisableJS(nsPIDOMWindowInner* aWindow) {
    178  WindowContext* wc = aWindow->GetWindowContext();
    179 
    180  mScriptsEnabled = wc->GetAllowJavascript();
    181  MOZ_TRY(wc->SetAllowJavascript(false));
    182  mDisabledJS = true;
    183  return NS_OK;
    184 }
    185 
    186 nsresult nsEditingSession::RestoreJS(nsPIDOMWindowInner* aWindow) {
    187  if (!mDisabledJS) {
    188    return NS_OK;
    189  }
    190 
    191  mDisabledJS = false;
    192 
    193  if (NS_WARN_IF(!aWindow)) {
    194    // DetachFromWindow may call this method with nullptr.
    195    return NS_ERROR_FAILURE;
    196  }
    197 
    198  WindowContext* wc = aWindow->GetWindowContext();
    199  return wc->SetAllowJavascript(mScriptsEnabled);
    200 }
    201 
    202 /*---------------------------------------------------------------------------
    203 
    204  WindowIsEditable
    205 
    206  boolean windowIsEditable (in nsIDOMWindow aWindow);
    207 ----------------------------------------------------------------------------*/
    208 NS_IMETHODIMP
    209 nsEditingSession::WindowIsEditable(mozIDOMWindowProxy* aWindow,
    210                                   bool* outIsEditable) {
    211  NS_ENSURE_STATE(aWindow);
    212  nsCOMPtr<nsIDocShell> docShell =
    213      nsPIDOMWindowOuter::From(aWindow)->GetDocShell();
    214  NS_ENSURE_STATE(docShell);
    215 
    216  return docShell->GetEditable(outIsEditable);
    217 }
    218 
    219 bool IsSupportedTextType(const nsAString& aMIMEType) {
    220  // These are MIME types that are automatically parsed as "text/plain"
    221  //   and thus we can edit them as plaintext
    222  // Note: in older versions, we attempted to convert the mimetype of
    223  //   the network channel for these and "text/xml" to "text/plain",
    224  //   but further investigation reveals that strategy doesn't work
    225  static constexpr nsLiteralString sSupportedTextTypes[] = {
    226      u"text/plain"_ns,
    227      u"text/css"_ns,
    228      u"text/rdf"_ns,
    229      u"text/xsl"_ns,
    230      u"text/javascript"_ns,  // obsolete type
    231      u"text/ecmascript"_ns,  // obsolete type
    232      u"application/javascript"_ns,
    233      u"application/ecmascript"_ns,
    234      u"application/x-javascript"_ns,  // obsolete type
    235      u"text/xul"_ns                   // obsolete type
    236  };
    237 
    238  for (const nsLiteralString& supportedTextType : sSupportedTextTypes) {
    239    if (aMIMEType.Equals(supportedTextType)) {
    240      return true;
    241    }
    242  }
    243 
    244  return false;
    245 }
    246 
    247 nsresult nsEditingSession::SetupEditorOnWindow(nsPIDOMWindowOuter& aWindow) {
    248  mDoneSetup = true;
    249 
    250  // MIME CHECKING
    251  // must get the content type
    252  // Note: the doc gets this from the network channel during StartPageLoad,
    253  //    so we don't have to get it from there ourselves
    254  nsAutoString mimeType;
    255 
    256  // then lets check the mime type
    257  if (RefPtr<Document> doc = aWindow.GetDoc()) {
    258    doc->GetContentType(mimeType);
    259 
    260    if (IsSupportedTextType(mimeType)) {
    261      mEditorType.AssignLiteral("text");
    262      mimeType.AssignLiteral("text/plain");
    263    } else if (!doc->IsHTMLOrXHTML()) {
    264      // Neither an acceptable text or html type.
    265      mEditorStatus = eEditorErrorCantEditMimeType;
    266 
    267      // Turn editor into HTML -- we will load blank page later
    268      mEditorType.AssignLiteral("html");
    269      mimeType.AssignLiteral("text/html");
    270    }
    271 
    272    // Flush out frame construction to make sure that the subframe's
    273    // presshell is set up if it needs to be.
    274    doc->FlushPendingNotifications(mozilla::FlushType::Frames);
    275    if (mMakeWholeDocumentEditable) {
    276      doc->SetDocumentEditableFlag(true);
    277      // Enable usage of the execCommand API
    278      doc->SetEditingState(Document::EditingState::eDesignMode);
    279    }
    280  }
    281  bool needHTMLController = false;
    282 
    283  if (mEditorType.EqualsLiteral("textmail")) {
    284    mEditorFlags = nsIEditor::eEditorPlaintextMask |
    285                   nsIEditor::eEditorEnableWrapHackMask |
    286                   nsIEditor::eEditorMailMask;
    287  } else if (mEditorType.EqualsLiteral("text")) {
    288    mEditorFlags =
    289        nsIEditor::eEditorPlaintextMask | nsIEditor::eEditorEnableWrapHackMask;
    290  } else if (mEditorType.EqualsLiteral("htmlmail")) {
    291    if (mimeType.EqualsLiteral("text/html")) {
    292      needHTMLController = true;
    293      mEditorFlags = nsIEditor::eEditorMailMask;
    294    } else {
    295      // Set the flags back to textplain.
    296      mEditorFlags = nsIEditor::eEditorPlaintextMask |
    297                     nsIEditor::eEditorEnableWrapHackMask;
    298    }
    299  } else {
    300    // Defaulted to html
    301    needHTMLController = true;
    302  }
    303 
    304  if (mInteractive) {
    305    mEditorFlags |= nsIEditor::eEditorAllowInteraction;
    306  }
    307 
    308  // make the UI state maintainer
    309  RefPtr<ComposerCommandsUpdater> commandsUpdater =
    310      new ComposerCommandsUpdater();
    311  mComposerCommandsUpdater = commandsUpdater;
    312 
    313  // now init the state maintainer
    314  // This allows notification of error state
    315  //  even if we don't create an editor
    316  commandsUpdater->Init(aWindow);
    317 
    318  if (mEditorStatus != eEditorCreationInProgress) {
    319    commandsUpdater->OnHTMLEditorCreated();
    320 
    321    // At this point we have made a final decision that we don't support
    322    // editing the current document.  This is an internal failure state, but
    323    // we return NS_OK to avoid throwing an exception from the designMode
    324    // setter for web compatibility.  The document editing APIs will tell the
    325    // developer if editing has been disabled because we're in a document type
    326    // that doesn't support editing.
    327    return NS_OK;
    328  }
    329 
    330  // Create editor and do other things
    331  //  only if we haven't found some error above,
    332  const RefPtr<nsDocShell> docShell = nsDocShell::Cast(aWindow.GetDocShell());
    333  if (NS_WARN_IF(!docShell)) {
    334    return NS_ERROR_FAILURE;
    335  }
    336  const RefPtr<PresShell> presShell = docShell->GetPresShell();
    337  if (NS_WARN_IF(!presShell)) {
    338    return NS_ERROR_FAILURE;
    339  }
    340 
    341  if (!mInteractive) {
    342    // Disable animation of images in this document:
    343    nsPresContext* presContext = presShell->GetPresContext();
    344    NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
    345 
    346    mImageAnimationMode = presContext->ImageAnimationMode();
    347    presContext->SetImageAnimationMode(imgIContainer::kDontAnimMode);
    348  }
    349 
    350  // Hide selection changes during initialization, in order to hide this
    351  // from web pages.
    352  RefPtr<nsFrameSelection> fs = presShell->FrameSelection();
    353  NS_ENSURE_TRUE(fs, NS_ERROR_FAILURE);
    354  AutoHideSelectionChanges hideSelectionChanges(fs);
    355 
    356  nsCOMPtr<nsIDocumentViewer> viewer;
    357  nsresult rv = docShell->GetDocViewer(getter_AddRefs(viewer));
    358  if (NS_FAILED(rv) || NS_WARN_IF(!viewer)) {
    359    NS_WARNING("nsDocShell::GetDocViewer() failed");
    360    return rv;
    361  }
    362 
    363  const RefPtr<Document> doc = viewer->GetDocument();
    364  if (NS_WARN_IF(!doc)) {
    365    return NS_ERROR_FAILURE;
    366  }
    367 
    368  // create and set editor
    369  // Try to reuse an existing editor
    370  nsCOMPtr<nsIEditor> editor = do_QueryReferent(mExistingEditor);
    371  RefPtr<HTMLEditor> htmlEditor = HTMLEditor::GetFrom(editor);
    372  MOZ_ASSERT_IF(editor, htmlEditor);
    373  if (htmlEditor) {
    374    htmlEditor->PreDestroy();
    375  } else {
    376    htmlEditor = new HTMLEditor(*doc);
    377    mExistingEditor =
    378        do_GetWeakReference(static_cast<nsIEditor*>(htmlEditor.get()));
    379  }
    380  // set the editor on the docShell. The docShell now owns it.
    381  rv = docShell->SetHTMLEditor(htmlEditor);
    382  NS_ENSURE_SUCCESS(rv, rv);
    383 
    384  // setup the HTML editor command controller
    385  if (needHTMLController) {
    386    // The third controller takes an nsIEditor as the context
    387    rv = SetupEditorCommandController(
    388        nsBaseCommandController::CreateHTMLEditorController, &aWindow,
    389        htmlEditor, &mHTMLCommandControllerId);
    390    NS_ENSURE_SUCCESS(rv, rv);
    391  }
    392 
    393  // Set mimetype on editor
    394  rv = htmlEditor->SetContentsMIMEType(mimeType);
    395  NS_ENSURE_SUCCESS(rv, rv);
    396 
    397  MOZ_ASSERT(docShell->HasDocumentViewer());
    398  MOZ_ASSERT(viewer->GetDocument());
    399 
    400  MOZ_DIAGNOSTIC_ASSERT(commandsUpdater == mComposerCommandsUpdater);
    401  if (MOZ_UNLIKELY(commandsUpdater != mComposerCommandsUpdater)) {
    402    commandsUpdater = mComposerCommandsUpdater;
    403  }
    404  rv = htmlEditor->Init(*doc, *commandsUpdater, mEditorFlags);
    405  NS_ENSURE_SUCCESS(rv, rv);
    406 
    407  RefPtr<Selection> selection = htmlEditor->GetSelection();
    408  if (NS_WARN_IF(!selection)) {
    409    return NS_ERROR_FAILURE;
    410  }
    411 
    412  // Set context on all controllers to be the editor
    413  rv = SetEditorOnControllers(aWindow, htmlEditor);
    414  NS_ENSURE_SUCCESS(rv, rv);
    415 
    416  // Everything went fine!
    417  mEditorStatus = eEditorOK;
    418 
    419  // This will trigger documentCreation notification
    420  return htmlEditor->PostCreate();
    421 }
    422 
    423 // Removes all listeners and controllers from aWindow and aEditor.
    424 void nsEditingSession::RemoveListenersAndControllers(
    425    nsPIDOMWindowOuter* aWindow, HTMLEditor* aHTMLEditor) {
    426  if (!mComposerCommandsUpdater || !aHTMLEditor) {
    427    return;
    428  }
    429 
    430  // Remove all the listeners
    431  RefPtr<ComposerCommandsUpdater> composertCommandsUpdater =
    432      std::move(mComposerCommandsUpdater);
    433  MOZ_ASSERT(!mComposerCommandsUpdater);
    434  aHTMLEditor->Detach(*composertCommandsUpdater);
    435 
    436  // Remove editor controllers from the window now that we're not
    437  // editing in that window any more.
    438  RemoveEditorControllers(aWindow);
    439 }
    440 
    441 /*---------------------------------------------------------------------------
    442 
    443  TearDownEditorOnWindow
    444 
    445  void tearDownEditorOnWindow (in nsIDOMWindow aWindow);
    446 ----------------------------------------------------------------------------*/
    447 NS_IMETHODIMP
    448 nsEditingSession::TearDownEditorOnWindow(mozIDOMWindowProxy* aWindow) {
    449  if (!mDoneSetup) {
    450    return NS_OK;
    451  }
    452 
    453  NS_ENSURE_TRUE(aWindow, NS_ERROR_NULL_POINTER);
    454 
    455  // Kill any existing reload timer
    456  if (mLoadBlankDocTimer) {
    457    mLoadBlankDocTimer->Cancel();
    458    mLoadBlankDocTimer = nullptr;
    459  }
    460 
    461  mDoneSetup = false;
    462 
    463  // Check if we're turning off editing (from contentEditable or designMode).
    464  auto* window = nsPIDOMWindowOuter::From(aWindow);
    465 
    466  RefPtr<Document> doc = window->GetDoc();
    467  bool stopEditing = doc && doc->IsEditingOn();
    468  if (stopEditing) {
    469    RemoveWebProgressListener(window);
    470  }
    471 
    472  nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
    473  NS_ENSURE_STATE(docShell);
    474 
    475  RefPtr<HTMLEditor> htmlEditor = docShell->GetHTMLEditor();
    476  if (stopEditing) {
    477    doc->TearingDownEditor();
    478  }
    479 
    480  if (mComposerCommandsUpdater && htmlEditor) {
    481    // Null out the editor on the controllers first to prevent their weak
    482    // references from pointing to a destroyed editor.
    483    SetEditorOnControllers(*window, nullptr);
    484  }
    485 
    486  // Null out the editor on the docShell to trigger PreDestroy which
    487  // needs to happen before document state listeners are removed below.
    488  docShell->SetEditor(nullptr);
    489 
    490  RemoveListenersAndControllers(window, htmlEditor);
    491 
    492  if (stopEditing) {
    493    // Make things the way they were before we started editing.
    494    RestoreJS(window->GetCurrentInnerWindow());
    495    RestoreAnimationMode(window);
    496 
    497    if (mMakeWholeDocumentEditable) {
    498      doc->SetDocumentEditableFlag(false);
    499      doc->SetEditingState(Document::EditingState::eOff);
    500    }
    501  }
    502 
    503  return NS_OK;
    504 }
    505 
    506 /*---------------------------------------------------------------------------
    507 
    508  GetEditorForFrame
    509 
    510  nsIEditor getEditorForFrame (in nsIDOMWindow aWindow);
    511 ----------------------------------------------------------------------------*/
    512 NS_IMETHODIMP
    513 nsEditingSession::GetEditorForWindow(mozIDOMWindowProxy* aWindow,
    514                                     nsIEditor** outEditor) {
    515  if (NS_WARN_IF(!aWindow)) {
    516    return NS_ERROR_INVALID_ARG;
    517  }
    518  nsCOMPtr<nsIEditor> editor = GetHTMLEditorForWindow(aWindow);
    519  editor.forget(outEditor);
    520  return NS_OK;
    521 }
    522 
    523 /*---------------------------------------------------------------------------
    524 
    525  OnStateChange
    526 
    527 ----------------------------------------------------------------------------*/
    528 NS_IMETHODIMP
    529 nsEditingSession::OnStateChange(nsIWebProgress* aWebProgress,
    530                                nsIRequest* aRequest, uint32_t aStateFlags,
    531                                nsresult aStatus) {
    532 #ifdef NOISY_DOC_LOADING
    533  nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
    534  if (channel) {
    535    nsAutoCString contentType;
    536    channel->GetContentType(contentType);
    537    if (!contentType.IsEmpty()) {
    538      printf(" ++++++ MIMETYPE = %s\n", contentType.get());
    539    }
    540  }
    541 #endif
    542 
    543  //
    544  // A Request has started...
    545  //
    546  if (aStateFlags & nsIWebProgressListener::STATE_START) {
    547 #ifdef NOISY_DOC_LOADING
    548    {
    549      nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
    550      if (channel) {
    551        nsCOMPtr<nsIURI> uri;
    552        channel->GetURI(getter_AddRefs(uri));
    553        if (uri) {
    554          nsCString spec;
    555          uri->GetSpec(spec);
    556          printf(" **** STATE_START: CHANNEL URI=%s, flags=%x\n", spec.get(),
    557                 aStateFlags);
    558        }
    559      } else {
    560        printf("    STATE_START: NO CHANNEL flags=%x\n", aStateFlags);
    561      }
    562    }
    563 #endif
    564    // Page level notification...
    565    if (aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK) {
    566      nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
    567      StartPageLoad(channel);
    568 #ifdef NOISY_DOC_LOADING
    569      printf("STATE_START & STATE_IS_NETWORK flags=%x\n", aStateFlags);
    570 #endif
    571    }
    572 
    573    // Document level notification...
    574    if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT &&
    575        !(aStateFlags & nsIWebProgressListener::STATE_RESTORING)) {
    576 #ifdef NOISY_DOC_LOADING
    577      printf("STATE_START & STATE_IS_DOCUMENT flags=%x\n", aStateFlags);
    578 #endif
    579 
    580      bool progressIsForTargetDocument =
    581          IsProgressForTargetDocument(aWebProgress);
    582 
    583      if (progressIsForTargetDocument) {
    584        nsCOMPtr<mozIDOMWindowProxy> window;
    585        aWebProgress->GetDOMWindow(getter_AddRefs(window));
    586 
    587        auto* piWindow = nsPIDOMWindowOuter::From(window);
    588        RefPtr<Document> doc = piWindow->GetDoc();
    589        nsHTMLDocument* htmlDoc =
    590            doc && doc->IsHTMLOrXHTML() ? doc->AsHTMLDocument() : nullptr;
    591        if (htmlDoc && doc->IsWriting()) {
    592          nsAutoString designMode;
    593          htmlDoc->GetDesignMode(designMode);
    594 
    595          if (designMode.EqualsLiteral("on")) {
    596            // This notification is for data coming in through
    597            // document.open/write/close(), ignore it.
    598 
    599            return NS_OK;
    600          }
    601        }
    602 
    603        mCanCreateEditor = true;
    604        StartDocumentLoad(aWebProgress, progressIsForTargetDocument);
    605      }
    606    }
    607  }
    608  //
    609  // A Request is being processed
    610  //
    611  else if (aStateFlags & nsIWebProgressListener::STATE_TRANSFERRING) {
    612    if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT) {
    613      // document transfer started
    614    }
    615  }
    616  //
    617  // Got a redirection
    618  //
    619  else if (aStateFlags & nsIWebProgressListener::STATE_REDIRECTING) {
    620    if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT) {
    621      // got a redirect
    622    }
    623  }
    624  //
    625  // A network or document Request has finished...
    626  //
    627  else if (aStateFlags & nsIWebProgressListener::STATE_STOP) {
    628 #ifdef NOISY_DOC_LOADING
    629    {
    630      nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
    631      if (channel) {
    632        nsCOMPtr<nsIURI> uri;
    633        channel->GetURI(getter_AddRefs(uri));
    634        if (uri) {
    635          nsCString spec;
    636          uri->GetSpec(spec);
    637          printf(" **** STATE_STOP: CHANNEL URI=%s, flags=%x\n", spec.get(),
    638                 aStateFlags);
    639        }
    640      } else {
    641        printf("     STATE_STOP: NO CHANNEL  flags=%x\n", aStateFlags);
    642      }
    643    }
    644 #endif
    645 
    646    // Document level notification...
    647    if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT) {
    648      nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
    649      EndDocumentLoad(aWebProgress, channel, aStatus,
    650                      IsProgressForTargetDocument(aWebProgress));
    651 #ifdef NOISY_DOC_LOADING
    652      printf("STATE_STOP & STATE_IS_DOCUMENT flags=%x\n", aStateFlags);
    653 #endif
    654    }
    655 
    656    // Page level notification...
    657    if (aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK) {
    658      nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
    659      (void)EndPageLoad(aWebProgress, channel, aStatus);
    660 #ifdef NOISY_DOC_LOADING
    661      printf("STATE_STOP & STATE_IS_NETWORK flags=%x\n", aStateFlags);
    662 #endif
    663    }
    664  }
    665 
    666  return NS_OK;
    667 }
    668 
    669 /*---------------------------------------------------------------------------
    670 
    671  OnProgressChange
    672 
    673 ----------------------------------------------------------------------------*/
    674 NS_IMETHODIMP
    675 nsEditingSession::OnProgressChange(nsIWebProgress* aWebProgress,
    676                                   nsIRequest* aRequest,
    677                                   int32_t aCurSelfProgress,
    678                                   int32_t aMaxSelfProgress,
    679                                   int32_t aCurTotalProgress,
    680                                   int32_t aMaxTotalProgress) {
    681  MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
    682  return NS_OK;
    683 }
    684 
    685 /*---------------------------------------------------------------------------
    686 
    687  OnLocationChange
    688 
    689 ----------------------------------------------------------------------------*/
    690 NS_IMETHODIMP
    691 nsEditingSession::OnLocationChange(nsIWebProgress* aWebProgress,
    692                                   nsIRequest* aRequest, nsIURI* aURI,
    693                                   uint32_t aFlags) {
    694  nsCOMPtr<mozIDOMWindowProxy> domWindow;
    695  nsresult rv = aWebProgress->GetDOMWindow(getter_AddRefs(domWindow));
    696  NS_ENSURE_SUCCESS(rv, rv);
    697 
    698  auto* piWindow = nsPIDOMWindowOuter::From(domWindow);
    699 
    700  RefPtr<Document> doc = piWindow->GetDoc();
    701  NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
    702 
    703  doc->SetDocumentURI(aURI);
    704 
    705  // Notify the location-changed observer that
    706  //  the document URL has changed
    707  nsIDocShell* docShell = piWindow->GetDocShell();
    708  NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
    709 
    710  RefPtr<nsCommandManager> commandManager = docShell->GetCommandManager();
    711  commandManager->CommandStatusChanged("obs_documentLocationChanged");
    712  return NS_OK;
    713 }
    714 
    715 /*---------------------------------------------------------------------------
    716 
    717  OnStatusChange
    718 
    719 ----------------------------------------------------------------------------*/
    720 NS_IMETHODIMP
    721 nsEditingSession::OnStatusChange(nsIWebProgress* aWebProgress,
    722                                 nsIRequest* aRequest, nsresult aStatus,
    723                                 const char16_t* aMessage) {
    724  MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
    725  return NS_OK;
    726 }
    727 
    728 /*---------------------------------------------------------------------------
    729 
    730  OnSecurityChange
    731 
    732 ----------------------------------------------------------------------------*/
    733 NS_IMETHODIMP
    734 nsEditingSession::OnSecurityChange(nsIWebProgress* aWebProgress,
    735                                   nsIRequest* aRequest, uint32_t aState) {
    736  MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
    737  return NS_OK;
    738 }
    739 
    740 /*---------------------------------------------------------------------------
    741 
    742  OnContentBlockingEvent
    743 
    744 ----------------------------------------------------------------------------*/
    745 NS_IMETHODIMP
    746 nsEditingSession::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
    747                                         nsIRequest* aRequest,
    748                                         uint32_t aEvent) {
    749  MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
    750  return NS_OK;
    751 }
    752 
    753 /*---------------------------------------------------------------------------
    754 
    755  IsProgressForTargetDocument
    756 
    757  Check that this notification is for our document.
    758 ----------------------------------------------------------------------------*/
    759 
    760 bool nsEditingSession::IsProgressForTargetDocument(
    761    nsIWebProgress* aWebProgress) {
    762  nsCOMPtr<nsIWebProgress> editedWebProgress = do_QueryReferent(mDocShell);
    763  return editedWebProgress == aWebProgress;
    764 }
    765 
    766 /*---------------------------------------------------------------------------
    767 
    768  GetEditorStatus
    769 
    770  Called during GetCommandStateParams("obs_documentCreated"...)
    771  to determine if editor was created and document
    772  was loaded successfully
    773 ----------------------------------------------------------------------------*/
    774 NS_IMETHODIMP
    775 nsEditingSession::GetEditorStatus(uint32_t* aStatus) {
    776  NS_ENSURE_ARG_POINTER(aStatus);
    777  *aStatus = mEditorStatus;
    778  return NS_OK;
    779 }
    780 
    781 /*---------------------------------------------------------------------------
    782 
    783  StartDocumentLoad
    784 
    785  Called on start of load in a single frame
    786 ----------------------------------------------------------------------------*/
    787 nsresult nsEditingSession::StartDocumentLoad(nsIWebProgress* aWebProgress,
    788                                             bool aIsToBeMadeEditable) {
    789 #ifdef NOISY_DOC_LOADING
    790  printf("======= StartDocumentLoad ========\n");
    791 #endif
    792 
    793  NS_ENSURE_ARG_POINTER(aWebProgress);
    794 
    795  if (aIsToBeMadeEditable) {
    796    mEditorStatus = eEditorCreationInProgress;
    797  }
    798 
    799  return NS_OK;
    800 }
    801 
    802 /*---------------------------------------------------------------------------
    803 
    804  EndDocumentLoad
    805 
    806  Called on end of load in a single frame
    807 ----------------------------------------------------------------------------*/
    808 nsresult nsEditingSession::EndDocumentLoad(nsIWebProgress* aWebProgress,
    809                                           nsIChannel* aChannel,
    810                                           nsresult aStatus,
    811                                           bool aIsToBeMadeEditable) {
    812  NS_ENSURE_ARG_POINTER(aWebProgress);
    813 
    814 #ifdef NOISY_DOC_LOADING
    815  printf("======= EndDocumentLoad ========\n");
    816  printf("with status %d, ", aStatus);
    817  nsCOMPtr<nsIURI> uri;
    818  nsCString spec;
    819  if (NS_SUCCEEDED(aChannel->GetURI(getter_AddRefs(uri)))) {
    820    uri->GetSpec(spec);
    821    printf(" uri %s\n", spec.get());
    822  }
    823 #endif
    824 
    825  // We want to call the base class EndDocumentLoad,
    826  // but avoid some of the stuff
    827  // that nsDocShell does (need to refactor).
    828 
    829  // OK, time to make an editor on this document
    830  nsCOMPtr<mozIDOMWindowProxy> domWindow;
    831  aWebProgress->GetDOMWindow(getter_AddRefs(domWindow));
    832  NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
    833 
    834  // Set the error state -- we will create an editor
    835  // anyway and load empty doc later
    836  if (aIsToBeMadeEditable && aStatus == NS_ERROR_FILE_NOT_FOUND) {
    837    mEditorStatus = eEditorErrorFileNotFound;
    838  }
    839 
    840  auto* window = nsPIDOMWindowOuter::From(domWindow);
    841  nsIDocShell* docShell = window->GetDocShell();
    842  NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);  // better error handling?
    843 
    844  // cancel refresh from meta tags
    845  // we need to make sure that all pages in editor (whether editable or not)
    846  // can't refresh contents being edited
    847  nsCOMPtr<nsIRefreshURI> refreshURI = do_QueryInterface(docShell);
    848  if (refreshURI) {
    849    refreshURI->CancelRefreshURITimers();
    850  }
    851 
    852  nsresult rv = NS_OK;
    853 
    854  // did someone set the flag to make this shell editable?
    855  if (aIsToBeMadeEditable && mCanCreateEditor) {
    856    bool makeEditable;
    857    docShell->GetEditable(&makeEditable);
    858 
    859    if (makeEditable) {
    860      // To keep pre Gecko 1.9 behavior, setup editor always when
    861      // mMakeWholeDocumentEditable.
    862      bool needsSetup = false;
    863      if (mMakeWholeDocumentEditable) {
    864        needsSetup = true;
    865      } else {
    866        // do we already have an editor here?
    867        needsSetup = !docShell->GetHTMLEditor();
    868      }
    869 
    870      if (needsSetup) {
    871        mCanCreateEditor = false;
    872        rv = SetupEditorOnWindow(MOZ_KnownLive(*window));
    873        if (NS_FAILED(rv)) {
    874          // If we had an error, setup timer to load a blank page later
    875          if (mLoadBlankDocTimer) {
    876            // Must cancel previous timer?
    877            mLoadBlankDocTimer->Cancel();
    878            mLoadBlankDocTimer = nullptr;
    879          }
    880 
    881          rv = NS_NewTimerWithFuncCallback(
    882              getter_AddRefs(mLoadBlankDocTimer),
    883              nsEditingSession::TimerCallback,
    884              static_cast<void*>(mDocShell.get()), 10, nsITimer::TYPE_ONE_SHOT,
    885              "nsEditingSession::EndDocumentLoad"_ns);
    886          NS_ENSURE_SUCCESS(rv, rv);
    887 
    888          mEditorStatus = eEditorCreationInProgress;
    889        }
    890      }
    891    }
    892  }
    893  return rv;
    894 }
    895 
    896 void nsEditingSession::TimerCallback(nsITimer* aTimer, void* aClosure) {
    897  nsCOMPtr<nsIDocShell> docShell =
    898      do_QueryReferent(static_cast<nsIWeakReference*>(aClosure));
    899  if (docShell) {
    900    nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell));
    901    if (webNav) {
    902      LoadURIOptions loadURIOptions;
    903      loadURIOptions.mTriggeringPrincipal =
    904          nsContentUtils::GetSystemPrincipal();
    905      nsCOMPtr<nsIURI> uri;
    906      MOZ_ALWAYS_SUCCEEDS(NS_NewURI(getter_AddRefs(uri), "about:blank"_ns));
    907      webNav->LoadURI(uri, loadURIOptions);
    908    }
    909  }
    910 }
    911 
    912 /*---------------------------------------------------------------------------
    913 
    914  StartPageLoad
    915 
    916  Called on start load of the entire page (incl. subframes)
    917 ----------------------------------------------------------------------------*/
    918 nsresult nsEditingSession::StartPageLoad(nsIChannel* aChannel) {
    919 #ifdef NOISY_DOC_LOADING
    920  printf("======= StartPageLoad ========\n");
    921 #endif
    922  return NS_OK;
    923 }
    924 
    925 /*---------------------------------------------------------------------------
    926 
    927  EndPageLoad
    928 
    929  Called on end load of the entire page (incl. subframes)
    930 ----------------------------------------------------------------------------*/
    931 nsresult nsEditingSession::EndPageLoad(nsIWebProgress* aWebProgress,
    932                                       nsIChannel* aChannel, nsresult aStatus) {
    933 #ifdef NOISY_DOC_LOADING
    934  printf("======= EndPageLoad ========\n");
    935  printf("  with status %d, ", aStatus);
    936  nsCOMPtr<nsIURI> uri;
    937  nsCString spec;
    938  if (NS_SUCCEEDED(aChannel->GetURI(getter_AddRefs(uri)))) {
    939    uri->GetSpec(spec);
    940    printf("uri %s\n", spec.get());
    941  }
    942 
    943  nsAutoCString contentType;
    944  aChannel->GetContentType(contentType);
    945  if (!contentType.IsEmpty()) {
    946    printf("   flags = %d, status = %d, MIMETYPE = %s\n", mEditorFlags,
    947           mEditorStatus, contentType.get());
    948  }
    949 #endif
    950 
    951  // Set the error state -- we will create an editor anyway
    952  // and load empty doc later
    953  if (aStatus == NS_ERROR_FILE_NOT_FOUND) {
    954    mEditorStatus = eEditorErrorFileNotFound;
    955  }
    956 
    957  nsCOMPtr<mozIDOMWindowProxy> domWindow;
    958  aWebProgress->GetDOMWindow(getter_AddRefs(domWindow));
    959 
    960  nsIDocShell* docShell =
    961      domWindow ? nsPIDOMWindowOuter::From(domWindow)->GetDocShell() : nullptr;
    962  NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
    963 
    964  // cancel refresh from meta tags
    965  // we need to make sure that all pages in editor (whether editable or not)
    966  // can't refresh contents being edited
    967  nsCOMPtr<nsIRefreshURI> refreshURI = do_QueryInterface(docShell);
    968  if (refreshURI) {
    969    refreshURI->CancelRefreshURITimers();
    970  }
    971 
    972 #if 0
    973  // Shouldn't we do this when we want to edit sub-frames?
    974  return MakeWindowEditable(domWindow, "html", false, mInteractive);
    975 #else
    976  return NS_OK;
    977 #endif
    978 }
    979 
    980 /*---------------------------------------------------------------------------
    981 
    982  PrepareForEditing
    983 
    984  Set up this editing session for one or more editors
    985 ----------------------------------------------------------------------------*/
    986 nsresult nsEditingSession::PrepareForEditing(nsPIDOMWindowOuter* aWindow) {
    987  if (mProgressListenerRegistered) {
    988    return NS_OK;
    989  }
    990 
    991  nsIDocShell* docShell = aWindow ? aWindow->GetDocShell() : nullptr;
    992 
    993  // register callback
    994  nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
    995  NS_ENSURE_TRUE(webProgress, NS_ERROR_FAILURE);
    996 
    997  nsresult rv = webProgress->AddProgressListener(
    998      this, (nsIWebProgress::NOTIFY_STATE_NETWORK |
    999             nsIWebProgress::NOTIFY_STATE_DOCUMENT |
   1000             nsIWebProgress::NOTIFY_LOCATION));
   1001 
   1002  mProgressListenerRegistered = NS_SUCCEEDED(rv);
   1003 
   1004  return rv;
   1005 }
   1006 
   1007 /*---------------------------------------------------------------------------
   1008 
   1009  SetupEditorCommandController
   1010 
   1011  Create a command controller, append to controllers,
   1012  get and return the controller ID, and set the context
   1013 ----------------------------------------------------------------------------*/
   1014 nsresult nsEditingSession::SetupEditorCommandController(
   1015    nsEditingSession::ControllerCreatorFn aControllerCreatorFn,
   1016    mozIDOMWindowProxy* aWindow, nsISupportsWeakReference* aContext,
   1017    uint32_t* aControllerId) {
   1018  NS_ENSURE_ARG_POINTER(aControllerCreatorFn);
   1019  NS_ENSURE_ARG_POINTER(aWindow);
   1020  NS_ENSURE_ARG_POINTER(aContext);
   1021  NS_ENSURE_ARG_POINTER(aControllerId);
   1022 
   1023  auto* piWindow = nsPIDOMWindowOuter::From(aWindow);
   1024  MOZ_ASSERT(piWindow);
   1025 
   1026  nsCOMPtr<nsIControllers> controllers;
   1027  nsresult rv = piWindow->GetControllers(getter_AddRefs(controllers));
   1028  NS_ENSURE_SUCCESS(rv, rv);
   1029 
   1030  // We only have to create each singleton controller once
   1031  // We know this has happened once we have a controllerId value
   1032  if (!*aControllerId) {
   1033    RefPtr<nsBaseCommandController> commandController = aControllerCreatorFn();
   1034    NS_ENSURE_TRUE(commandController, NS_ERROR_FAILURE);
   1035 
   1036    // We must insert at head of the list to be sure our
   1037    //   controller is found before other implementations
   1038    //   (e.g., not-implemented versions by browser)
   1039    rv = controllers->InsertControllerAt(0, commandController);
   1040    NS_ENSURE_SUCCESS(rv, rv);
   1041 
   1042    // Remember the ID for the controller
   1043    rv = controllers->GetControllerId(commandController, aControllerId);
   1044    NS_ENSURE_SUCCESS(rv, rv);
   1045  }
   1046 
   1047  // Set the context
   1048  return SetContextOnControllerById(controllers, aContext, *aControllerId);
   1049 }
   1050 
   1051 nsresult nsEditingSession::SetEditorOnControllers(nsPIDOMWindowOuter& aWindow,
   1052                                                  HTMLEditor* aEditor) {
   1053  nsCOMPtr<nsIControllers> controllers;
   1054  nsresult rv = aWindow.GetControllers(getter_AddRefs(controllers));
   1055  NS_ENSURE_SUCCESS(rv, rv);
   1056 
   1057  if (mBaseCommandControllerId) {
   1058    rv = SetContextOnControllerById(controllers, aEditor,
   1059                                    mBaseCommandControllerId);
   1060    NS_ENSURE_SUCCESS(rv, rv);
   1061  }
   1062 
   1063  if (mDocStateControllerId) {
   1064    rv =
   1065        SetContextOnControllerById(controllers, aEditor, mDocStateControllerId);
   1066    NS_ENSURE_SUCCESS(rv, rv);
   1067  }
   1068 
   1069  if (mHTMLCommandControllerId) {
   1070    rv = SetContextOnControllerById(controllers, aEditor,
   1071                                    mHTMLCommandControllerId);
   1072  }
   1073 
   1074  return rv;
   1075 }
   1076 
   1077 nsresult nsEditingSession::SetContextOnControllerById(
   1078    nsIControllers* aControllers, nsISupportsWeakReference* aContext,
   1079    uint32_t aID) {
   1080  NS_ENSURE_ARG_POINTER(aControllers);
   1081 
   1082  // aContext can be null (when destroying editor)
   1083  nsCOMPtr<nsIController> controller;
   1084  aControllers->GetControllerById(aID, getter_AddRefs(controller));
   1085 
   1086  // ok with nil controller
   1087  nsCOMPtr<nsBaseCommandController> editorController =
   1088      do_QueryInterface(controller);
   1089  NS_ENSURE_TRUE(editorController, NS_ERROR_FAILURE);
   1090 
   1091  editorController->SetContext(aContext);
   1092  return NS_OK;
   1093 }
   1094 
   1095 void nsEditingSession::RemoveEditorControllers(nsPIDOMWindowOuter* aWindow) {
   1096  // Remove editor controllers from the aWindow, call when we're
   1097  // tearing down/detaching editor.
   1098 
   1099  nsCOMPtr<nsIControllers> controllers;
   1100  if (aWindow) {
   1101    aWindow->GetControllers(getter_AddRefs(controllers));
   1102  }
   1103 
   1104  if (controllers) {
   1105    nsCOMPtr<nsIController> controller;
   1106    if (mBaseCommandControllerId) {
   1107      controllers->GetControllerById(mBaseCommandControllerId,
   1108                                     getter_AddRefs(controller));
   1109      if (controller) {
   1110        controllers->RemoveController(controller);
   1111      }
   1112    }
   1113 
   1114    if (mDocStateControllerId) {
   1115      controllers->GetControllerById(mDocStateControllerId,
   1116                                     getter_AddRefs(controller));
   1117      if (controller) {
   1118        controllers->RemoveController(controller);
   1119      }
   1120    }
   1121 
   1122    if (mHTMLCommandControllerId) {
   1123      controllers->GetControllerById(mHTMLCommandControllerId,
   1124                                     getter_AddRefs(controller));
   1125      if (controller) {
   1126        controllers->RemoveController(controller);
   1127      }
   1128    }
   1129  }
   1130 
   1131  // Clear IDs to trigger creation of new controllers.
   1132  mBaseCommandControllerId = 0;
   1133  mDocStateControllerId = 0;
   1134  mHTMLCommandControllerId = 0;
   1135 }
   1136 
   1137 void nsEditingSession::RemoveWebProgressListener(nsPIDOMWindowOuter* aWindow) {
   1138  nsIDocShell* docShell = aWindow ? aWindow->GetDocShell() : nullptr;
   1139  nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
   1140  if (webProgress) {
   1141    webProgress->RemoveProgressListener(this);
   1142    mProgressListenerRegistered = false;
   1143  }
   1144 }
   1145 
   1146 void nsEditingSession::RestoreAnimationMode(nsPIDOMWindowOuter* aWindow) {
   1147  if (mInteractive) {
   1148    return;
   1149  }
   1150 
   1151  nsCOMPtr<nsIDocShell> docShell = aWindow ? aWindow->GetDocShell() : nullptr;
   1152  NS_ENSURE_TRUE_VOID(docShell);
   1153  RefPtr<PresShell> presShell = docShell->GetPresShell();
   1154  if (NS_WARN_IF(!presShell)) {
   1155    return;
   1156  }
   1157  nsPresContext* presContext = presShell->GetPresContext();
   1158  NS_ENSURE_TRUE_VOID(presContext);
   1159 
   1160  presContext->SetImageAnimationMode(mImageAnimationMode);
   1161 }
   1162 
   1163 nsresult nsEditingSession::DetachFromWindow(nsPIDOMWindowOuter* aWindow) {
   1164  NS_ENSURE_TRUE(mDoneSetup, NS_OK);
   1165 
   1166  NS_ASSERTION(mComposerCommandsUpdater,
   1167               "mComposerCommandsUpdater should exist.");
   1168 
   1169  // Kill any existing reload timer
   1170  if (mLoadBlankDocTimer) {
   1171    mLoadBlankDocTimer->Cancel();
   1172    mLoadBlankDocTimer = nullptr;
   1173  }
   1174 
   1175  // Remove controllers, webprogress listener, and otherwise
   1176  // make things the way they were before we started editing.
   1177  RemoveEditorControllers(aWindow);
   1178  RemoveWebProgressListener(aWindow);
   1179  RestoreJS(aWindow->GetCurrentInnerWindow());
   1180  RestoreAnimationMode(aWindow);
   1181 
   1182  // Kill our weak reference to our original window, in case
   1183  // it changes on restore, or otherwise dies.
   1184  mDocShell = nullptr;
   1185 
   1186  return NS_OK;
   1187 }
   1188 
   1189 nsresult nsEditingSession::ReattachToWindow(nsPIDOMWindowOuter* aWindow) {
   1190  NS_ENSURE_TRUE(mDoneSetup, NS_OK);
   1191  NS_ENSURE_TRUE(aWindow, NS_ERROR_FAILURE);
   1192 
   1193  NS_ASSERTION(mComposerCommandsUpdater,
   1194               "mComposerCommandsUpdater should exist.");
   1195 
   1196  // Imitate nsEditorDocShell::MakeEditable() to reattach the
   1197  // old editor to the window.
   1198  nsresult rv;
   1199 
   1200  nsIDocShell* docShell = aWindow->GetDocShell();
   1201  NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
   1202  mDocShell = do_GetWeakReference(docShell);
   1203 
   1204  // Disable JS.
   1205  if (!mInteractive) {
   1206    rv = DisableJS(aWindow->GetCurrentInnerWindow());
   1207    NS_ENSURE_SUCCESS(rv, rv);
   1208  }
   1209 
   1210  // Tells embedder that startup is in progress.
   1211  mEditorStatus = eEditorCreationInProgress;
   1212 
   1213  // Adds back web progress listener.
   1214  rv = PrepareForEditing(aWindow);
   1215  NS_ENSURE_SUCCESS(rv, rv);
   1216 
   1217  // Setup the command controllers again.
   1218  rv = SetupEditorCommandController(
   1219      nsBaseCommandController::CreateEditingController, aWindow, this,
   1220      &mBaseCommandControllerId);
   1221  NS_ENSURE_SUCCESS(rv, rv);
   1222 
   1223  rv = SetupEditorCommandController(
   1224      nsBaseCommandController::CreateHTMLEditorDocStateController, aWindow,
   1225      this, &mDocStateControllerId);
   1226  NS_ENSURE_SUCCESS(rv, rv);
   1227 
   1228  if (mComposerCommandsUpdater) {
   1229    mComposerCommandsUpdater->Init(*aWindow);
   1230  }
   1231 
   1232  // Get editor
   1233  RefPtr<HTMLEditor> htmlEditor = GetHTMLEditorForWindow(aWindow);
   1234  if (NS_WARN_IF(!htmlEditor)) {
   1235    return NS_ERROR_FAILURE;
   1236  }
   1237 
   1238  if (!mInteractive) {
   1239    // Disable animation of images in this document:
   1240    RefPtr<PresShell> presShell = docShell->GetPresShell();
   1241    if (NS_WARN_IF(!presShell)) {
   1242      return NS_ERROR_FAILURE;
   1243    }
   1244    nsPresContext* presContext = presShell->GetPresContext();
   1245    NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
   1246 
   1247    mImageAnimationMode = presContext->ImageAnimationMode();
   1248    presContext->SetImageAnimationMode(imgIContainer::kDontAnimMode);
   1249  }
   1250 
   1251  // The third controller takes an nsIEditor as the context
   1252  rv = SetupEditorCommandController(
   1253      nsBaseCommandController::CreateHTMLEditorController, aWindow, htmlEditor,
   1254      &mHTMLCommandControllerId);
   1255  NS_ENSURE_SUCCESS(rv, rv);
   1256 
   1257  // Set context on all controllers to be the editor
   1258  rv = SetEditorOnControllers(*aWindow, htmlEditor);
   1259  NS_ENSURE_SUCCESS(rv, rv);
   1260 
   1261 #ifdef DEBUG
   1262  {
   1263    bool isEditable;
   1264    rv = WindowIsEditable(aWindow, &isEditable);
   1265    NS_ENSURE_SUCCESS(rv, rv);
   1266    NS_ASSERTION(isEditable,
   1267                 "Window is not editable after reattaching editor.");
   1268  }
   1269 #endif  // DEBUG
   1270 
   1271  return NS_OK;
   1272 }
   1273 
   1274 HTMLEditor* nsIEditingSession::GetHTMLEditorForWindow(
   1275    mozIDOMWindowProxy* aWindow) {
   1276  if (NS_WARN_IF(!aWindow)) {
   1277    return nullptr;
   1278  }
   1279 
   1280  nsCOMPtr<nsIDocShell> docShell =
   1281      nsPIDOMWindowOuter::From(aWindow)->GetDocShell();
   1282  if (NS_WARN_IF(!docShell)) {
   1283    return nullptr;
   1284  }
   1285 
   1286  return docShell->GetHTMLEditor();
   1287 }