Bug 1567650 [wpt PR 17950] - [ElementTiming] Replace responseEnd with loadTime, a...
[gecko.git] / editor / composer / nsEditingSession.cpp
blob43897c8f31e8cea7ab0b5cd77c6a18e02a770486
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 "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 "nsAString.h"
16 #include "nsBaseCommandController.h" // for nsBaseCommandController
17 #include "nsCommandManager.h" // for nsCommandManager
18 #include "nsComponentManagerUtils.h" // for do_CreateInstance
19 #include "nsContentUtils.h"
20 #include "nsDebug.h" // for NS_ENSURE_SUCCESS, etc
21 #include "nsEditingSession.h"
22 #include "nsError.h" // for NS_ERROR_FAILURE, NS_OK, etc
23 #include "nsIChannel.h" // for nsIChannel
24 #include "nsIContentViewer.h" // for nsIContentViewer
25 #include "nsIControllers.h" // for nsIControllers
26 #include "nsID.h" // for NS_GET_IID, etc
27 #include "nsHTMLDocument.h" // for nsHTMLDocument
28 #include "nsIDOMWindow.h" // for nsIDOMWindow
29 #include "nsIDocShell.h" // for nsIDocShell
30 #include "mozilla/dom/Document.h" // for Document
31 #include "nsIDocumentStateListener.h"
32 #include "nsIEditor.h" // for nsIEditor
33 #include "nsIInterfaceRequestorUtils.h" // for do_GetInterface
34 #include "nsIPlaintextEditor.h" // for nsIPlaintextEditor, etc
35 #include "nsIRefreshURI.h" // for nsIRefreshURI
36 #include "nsIRequest.h" // for nsIRequest
37 #include "nsITimer.h" // for nsITimer, etc
38 #include "nsITransactionManager.h" // for nsITransactionManager
39 #include "nsIWeakReference.h" // for nsISupportsWeakReference, etc
40 #include "nsIWebNavigation.h" // for nsIWebNavigation
41 #include "nsIWebProgress.h" // for nsIWebProgress, etc
42 #include "nsLiteralString.h" // for NS_LITERAL_STRING
43 #include "nsPIDOMWindow.h" // for nsPIDOMWindow
44 #include "nsPresContext.h" // for nsPresContext
45 #include "nsReadableUtils.h" // for AppendUTF16toUTF8
46 #include "nsStringFwd.h" // for nsString
47 #include "mozilla/dom/Selection.h" // for AutoHideSelectionChanges, etc
48 #include "nsFrameSelection.h" // for nsFrameSelection
49 #include "nsBaseCommandController.h" // for nsBaseCommandController
50 #include "mozilla/dom/LoadURIOptionsBinding.h"
52 class nsISupports;
53 class nsIURI;
55 using namespace mozilla;
56 using namespace mozilla::dom;
58 /*---------------------------------------------------------------------------
60 nsEditingSession
62 ----------------------------------------------------------------------------*/
63 nsEditingSession::nsEditingSession()
64 : mDoneSetup(false),
65 mCanCreateEditor(false),
66 mInteractive(false),
67 mMakeWholeDocumentEditable(true),
68 mDisabledJSAndPlugins(false),
69 mScriptsEnabled(true),
70 mPluginsEnabled(true),
71 mProgressListenerRegistered(false),
72 mImageAnimationMode(0),
73 mEditorFlags(0),
74 mEditorStatus(eEditorOK),
75 mBaseCommandControllerId(0),
76 mDocStateControllerId(0),
77 mHTMLCommandControllerId(0) {}
79 /*---------------------------------------------------------------------------
81 ~nsEditingSession
83 ----------------------------------------------------------------------------*/
84 nsEditingSession::~nsEditingSession() {
85 // Must cancel previous timer?
86 if (mLoadBlankDocTimer) mLoadBlankDocTimer->Cancel();
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(mozIDOMWindowProxy* aWindow,
106 const char* aEditorType,
107 bool aDoAfterUriLoad,
108 bool aMakeWholeDocumentEditable,
109 bool aInteractive) {
110 mEditorType.Truncate();
111 mEditorFlags = 0;
113 NS_ENSURE_TRUE(aWindow, NS_ERROR_FAILURE);
114 auto* window = nsPIDOMWindowOuter::From(aWindow);
116 // disable plugins
117 nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
118 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
120 mDocShell = do_GetWeakReference(docShell);
121 mInteractive = aInteractive;
122 mMakeWholeDocumentEditable = aMakeWholeDocumentEditable;
124 nsresult rv;
125 if (!mInteractive) {
126 rv = DisableJSAndPlugins(*docShell);
127 NS_ENSURE_SUCCESS(rv, rv);
130 // Always remove existing editor
131 TearDownEditorOnWindow(aWindow);
133 // Tells embedder that startup is in progress
134 mEditorStatus = eEditorCreationInProgress;
136 // temporary to set editor type here. we will need different classes soon.
137 if (!aEditorType) aEditorType = DEFAULT_EDITOR_TYPE;
138 mEditorType = aEditorType;
140 // if all this does is setup listeners and I don't need listeners,
141 // can't this step be ignored?? (based on aDoAfterURILoad)
142 rv = PrepareForEditing(window);
143 NS_ENSURE_SUCCESS(rv, rv);
145 // set the flag on the docShell to say that it's editable
146 rv = docShell->MakeEditable(aDoAfterUriLoad);
147 NS_ENSURE_SUCCESS(rv, rv);
149 // Setup commands common to plaintext and html editors,
150 // including the document creation observers
151 // the first is an editing controller
152 rv = SetupEditorCommandController(
153 nsBaseCommandController::CreateEditingController, aWindow,
154 static_cast<nsIEditingSession*>(this), &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(
160 nsBaseCommandController::CreateHTMLEditorDocStateController, aWindow,
161 static_cast<nsIEditingSession*>(this), &mDocStateControllerId);
162 NS_ENSURE_SUCCESS(rv, rv);
164 // aDoAfterUriLoad can be false only when making an existing window editable
165 if (!aDoAfterUriLoad) {
166 rv = SetupEditorOnWindow(MOZ_KnownLive(*window));
168 // mEditorStatus is set to the error reason
169 // Since this is used only when editing an existing page,
170 // it IS ok to destroy current editor
171 if (NS_FAILED(rv)) {
172 TearDownEditorOnWindow(aWindow);
175 return rv;
178 nsresult nsEditingSession::DisableJSAndPlugins(nsIDocShell& aDocShell) {
179 bool tmp;
180 nsresult rv = aDocShell.GetAllowJavascript(&tmp);
181 NS_ENSURE_SUCCESS(rv, rv);
183 mScriptsEnabled = tmp;
185 rv = aDocShell.SetAllowJavascript(false);
186 NS_ENSURE_SUCCESS(rv, rv);
188 // Disable plugins in this document:
189 mPluginsEnabled = aDocShell.PluginsAllowedInCurrentDoc();
191 rv = aDocShell.SetAllowPlugins(false);
192 NS_ENSURE_SUCCESS(rv, rv);
194 mDisabledJSAndPlugins = true;
196 return NS_OK;
199 nsresult nsEditingSession::RestoreJSAndPlugins(nsPIDOMWindowOuter* aWindow) {
200 if (!mDisabledJSAndPlugins) {
201 return NS_OK;
204 mDisabledJSAndPlugins = false;
206 if (NS_WARN_IF(!aWindow)) {
207 // DetachFromWindow may call this method with nullptr.
208 return NS_ERROR_FAILURE;
210 nsIDocShell* docShell = aWindow->GetDocShell();
211 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
213 nsresult rv = docShell->SetAllowJavascript(mScriptsEnabled);
214 NS_ENSURE_SUCCESS(rv, rv);
216 // Disable plugins in this document:
217 return docShell->SetAllowPlugins(mPluginsEnabled);
220 /*---------------------------------------------------------------------------
222 WindowIsEditable
224 boolean windowIsEditable (in nsIDOMWindow aWindow);
225 ----------------------------------------------------------------------------*/
226 NS_IMETHODIMP
227 nsEditingSession::WindowIsEditable(mozIDOMWindowProxy* aWindow,
228 bool* outIsEditable) {
229 NS_ENSURE_STATE(aWindow);
230 nsCOMPtr<nsIDocShell> docShell =
231 nsPIDOMWindowOuter::From(aWindow)->GetDocShell();
232 NS_ENSURE_STATE(docShell);
234 return docShell->GetEditable(outIsEditable);
237 // These are MIME types that are automatically parsed as "text/plain"
238 // and thus we can edit them as plaintext
239 // Note: in older versions, we attempted to convert the mimetype of
240 // the network channel for these and "text/xml" to "text/plain",
241 // but further investigation reveals that strategy doesn't work
242 const char* const gSupportedTextTypes[] = {
243 "text/plain",
244 "text/css",
245 "text/rdf",
246 "text/xsl",
247 "text/javascript", // obsolete type
248 "text/ecmascript", // obsolete type
249 "application/javascript",
250 "application/ecmascript",
251 "application/x-javascript", // obsolete type
252 "text/xul", // obsolete type
253 "application/vnd.mozilla.xul+xml",
254 nullptr // IMPORTANT! Null must be at end
257 bool IsSupportedTextType(const char* aMIMEType) {
258 NS_ENSURE_TRUE(aMIMEType, false);
260 for (size_t i = 0; gSupportedTextTypes[i]; ++i) {
261 if (!strcmp(gSupportedTextTypes[i], aMIMEType)) {
262 return true;
266 return false;
269 nsresult nsEditingSession::SetupEditorOnWindow(nsPIDOMWindowOuter& aWindow) {
270 mDoneSetup = true;
272 // MIME CHECKING
273 // must get the content type
274 // Note: the doc gets this from the network channel during StartPageLoad,
275 // so we don't have to get it from there ourselves
276 nsAutoCString mimeCType;
278 // then lets check the mime type
279 if (RefPtr<Document> doc = aWindow.GetDoc()) {
280 nsAutoString mimeType;
281 doc->GetContentType(mimeType);
282 AppendUTF16toUTF8(mimeType, mimeCType);
284 if (IsSupportedTextType(mimeCType.get())) {
285 mEditorType.AssignLiteral("text");
286 mimeCType = "text/plain";
287 } else if (!mimeCType.EqualsLiteral("text/html") &&
288 !mimeCType.EqualsLiteral("application/xhtml+xml")) {
289 // Neither an acceptable text or html type.
290 mEditorStatus = eEditorErrorCantEditMimeType;
292 // Turn editor into HTML -- we will load blank page later
293 mEditorType.AssignLiteral("html");
294 mimeCType.AssignLiteral("text/html");
297 // Flush out frame construction to make sure that the subframe's
298 // presshell is set up if it needs to be.
299 doc->FlushPendingNotifications(mozilla::FlushType::Frames);
300 if (mMakeWholeDocumentEditable) {
301 doc->SetEditableFlag(true);
302 // Enable usage of the execCommand API
303 doc->SetEditingState(Document::EditingState::eDesignMode);
306 bool needHTMLController = false;
308 if (mEditorType.EqualsLiteral("textmail")) {
309 mEditorFlags = nsIPlaintextEditor::eEditorPlaintextMask |
310 nsIPlaintextEditor::eEditorEnableWrapHackMask |
311 nsIPlaintextEditor::eEditorMailMask;
312 } else if (mEditorType.EqualsLiteral("text")) {
313 mEditorFlags = nsIPlaintextEditor::eEditorPlaintextMask |
314 nsIPlaintextEditor::eEditorEnableWrapHackMask;
315 } else if (mEditorType.EqualsLiteral("htmlmail")) {
316 if (mimeCType.EqualsLiteral("text/html")) {
317 needHTMLController = true;
318 mEditorFlags = nsIPlaintextEditor::eEditorMailMask;
319 } else {
320 // Set the flags back to textplain.
321 mEditorFlags = nsIPlaintextEditor::eEditorPlaintextMask |
322 nsIPlaintextEditor::eEditorEnableWrapHackMask;
324 } else {
325 // Defaulted to html
326 needHTMLController = true;
329 if (mInteractive) {
330 mEditorFlags |= nsIPlaintextEditor::eEditorAllowInteraction;
333 // make the UI state maintainer
334 mComposerCommandsUpdater = new ComposerCommandsUpdater();
336 // now init the state maintainer
337 // This allows notification of error state
338 // even if we don't create an editor
339 mComposerCommandsUpdater->Init(aWindow);
341 if (mEditorStatus != eEditorCreationInProgress) {
342 RefPtr<ComposerCommandsUpdater> updater = mComposerCommandsUpdater;
343 updater->NotifyDocumentCreated();
345 // At this point we have made a final decision that we don't support
346 // editing the current document. This is an internal failure state, but
347 // we return NS_OK to avoid throwing an exception from the designMode
348 // setter for web compatibility. The document editing APIs will tell the
349 // developer if editing has been disabled because we're in a document type
350 // that doesn't support editing.
351 return NS_OK;
354 // Create editor and do other things
355 // only if we haven't found some error above,
356 nsCOMPtr<nsIDocShell> docShell = aWindow.GetDocShell();
357 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
358 RefPtr<PresShell> presShell = docShell->GetPresShell();
359 if (NS_WARN_IF(!presShell)) {
360 return NS_ERROR_FAILURE;
363 if (!mInteractive) {
364 // Disable animation of images in this document:
365 nsPresContext* presContext = presShell->GetPresContext();
366 NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
368 mImageAnimationMode = presContext->ImageAnimationMode();
369 presContext->SetImageAnimationMode(imgIContainer::kDontAnimMode);
372 // Hide selection changes during initialization, in order to hide this
373 // from web pages.
374 RefPtr<nsFrameSelection> fs = presShell->FrameSelection();
375 NS_ENSURE_TRUE(fs, NS_ERROR_FAILURE);
376 AutoHideSelectionChanges hideSelectionChanges(fs);
378 // create and set editor
379 // Try to reuse an existing editor
380 nsCOMPtr<nsIEditor> editor = do_QueryReferent(mExistingEditor);
381 RefPtr<HTMLEditor> htmlEditor = editor ? editor->AsHTMLEditor() : nullptr;
382 MOZ_ASSERT(!editor || htmlEditor);
383 if (htmlEditor) {
384 htmlEditor->PreDestroy(false);
385 } else {
386 htmlEditor = new HTMLEditor();
387 mExistingEditor =
388 do_GetWeakReference(static_cast<nsIEditor*>(htmlEditor.get()));
390 // set the editor on the docShell. The docShell now owns it.
391 nsresult rv = docShell->SetHTMLEditor(htmlEditor);
392 NS_ENSURE_SUCCESS(rv, rv);
394 // setup the HTML editor command controller
395 if (needHTMLController) {
396 // The third controller takes an nsIEditor as the context
397 rv = SetupEditorCommandController(
398 nsBaseCommandController::CreateHTMLEditorController, &aWindow,
399 static_cast<nsIEditor*>(htmlEditor), &mHTMLCommandControllerId);
400 NS_ENSURE_SUCCESS(rv, rv);
403 // Set mimetype on editor
404 rv = htmlEditor->SetContentsMIMEType(mimeCType.get());
405 NS_ENSURE_SUCCESS(rv, rv);
407 nsCOMPtr<nsIContentViewer> contentViewer;
408 rv = docShell->GetContentViewer(getter_AddRefs(contentViewer));
409 NS_ENSURE_SUCCESS(rv, rv);
410 NS_ENSURE_TRUE(contentViewer, NS_ERROR_FAILURE);
412 RefPtr<Document> doc = contentViewer->GetDocument();
413 if (NS_WARN_IF(!doc)) {
414 return NS_ERROR_FAILURE;
417 // Set up as a doc state listener
418 // Important! We must have this to broadcast the "obs_documentCreated" message
419 rv = htmlEditor->AddDocumentStateListener(mComposerCommandsUpdater);
420 NS_ENSURE_SUCCESS(rv, rv);
422 rv = htmlEditor->Init(*doc, nullptr /* root content */, nullptr, mEditorFlags,
423 EmptyString());
424 NS_ENSURE_SUCCESS(rv, rv);
426 RefPtr<Selection> selection = htmlEditor->GetSelection();
427 if (NS_WARN_IF(!selection)) {
428 return NS_ERROR_FAILURE;
431 htmlEditor->SetComposerCommandsUpdater(mComposerCommandsUpdater);
433 // and as a transaction listener
434 MOZ_ASSERT(mComposerCommandsUpdater);
435 DebugOnly<bool> addedTransactionListener =
436 htmlEditor->AddTransactionListener(*mComposerCommandsUpdater);
437 NS_WARNING_ASSERTION(addedTransactionListener,
438 "Failed to add transaction listener to the editor");
440 // Set context on all controllers to be the editor
441 rv = SetEditorOnControllers(aWindow, htmlEditor);
442 NS_ENSURE_SUCCESS(rv, rv);
444 // Everything went fine!
445 mEditorStatus = eEditorOK;
447 // This will trigger documentCreation notification
448 return htmlEditor->PostCreate();
451 // Removes all listeners and controllers from aWindow and aEditor.
452 void nsEditingSession::RemoveListenersAndControllers(
453 nsPIDOMWindowOuter* aWindow, HTMLEditor* aHTMLEditor) {
454 if (!mComposerCommandsUpdater || !aHTMLEditor) {
455 return;
458 // Remove all the listeners
459 aHTMLEditor->SetComposerCommandsUpdater(nullptr);
460 aHTMLEditor->RemoveDocumentStateListener(mComposerCommandsUpdater);
461 DebugOnly<bool> removedTransactionListener =
462 aHTMLEditor->RemoveTransactionListener(*mComposerCommandsUpdater);
463 NS_WARNING_ASSERTION(removedTransactionListener,
464 "Failed to remove transaction listener from the editor");
466 // Remove editor controllers from the window now that we're not
467 // editing in that window any more.
468 RemoveEditorControllers(aWindow);
471 /*---------------------------------------------------------------------------
473 TearDownEditorOnWindow
475 void tearDownEditorOnWindow (in nsIDOMWindow aWindow);
476 ----------------------------------------------------------------------------*/
477 NS_IMETHODIMP
478 nsEditingSession::TearDownEditorOnWindow(mozIDOMWindowProxy* aWindow) {
479 if (!mDoneSetup) {
480 return NS_OK;
483 NS_ENSURE_TRUE(aWindow, NS_ERROR_NULL_POINTER);
485 // Kill any existing reload timer
486 if (mLoadBlankDocTimer) {
487 mLoadBlankDocTimer->Cancel();
488 mLoadBlankDocTimer = nullptr;
491 mDoneSetup = false;
493 // Check if we're turning off editing (from contentEditable or designMode).
494 auto* window = nsPIDOMWindowOuter::From(aWindow);
496 RefPtr<Document> doc = window->GetDoc();
497 bool stopEditing = doc && doc->IsEditingOn();
498 if (stopEditing) {
499 RemoveWebProgressListener(window);
502 nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
503 NS_ENSURE_STATE(docShell);
505 RefPtr<HTMLEditor> htmlEditor = docShell->GetHTMLEditor();
506 if (stopEditing) {
507 doc->TearingDownEditor();
510 if (mComposerCommandsUpdater && htmlEditor) {
511 // Null out the editor on the controllers first to prevent their weak
512 // references from pointing to a destroyed editor.
513 SetEditorOnControllers(*window, nullptr);
516 // Null out the editor on the docShell to trigger PreDestroy which
517 // needs to happen before document state listeners are removed below.
518 docShell->SetEditor(nullptr);
520 RemoveListenersAndControllers(window, htmlEditor);
522 if (stopEditing) {
523 // Make things the way they were before we started editing.
524 RestoreJSAndPlugins(window);
525 RestoreAnimationMode(window);
527 if (mMakeWholeDocumentEditable) {
528 doc->SetEditableFlag(false);
529 doc->SetEditingState(Document::EditingState::eOff);
533 return NS_OK;
536 /*---------------------------------------------------------------------------
538 GetEditorForFrame
540 nsIEditor getEditorForFrame (in nsIDOMWindow aWindow);
541 ----------------------------------------------------------------------------*/
542 NS_IMETHODIMP
543 nsEditingSession::GetEditorForWindow(mozIDOMWindowProxy* aWindow,
544 nsIEditor** outEditor) {
545 if (NS_WARN_IF(!aWindow)) {
546 return NS_ERROR_INVALID_ARG;
548 nsCOMPtr<nsIEditor> editor = GetHTMLEditorForWindow(aWindow);
549 editor.forget(outEditor);
550 return NS_OK;
553 /*---------------------------------------------------------------------------
555 OnStateChange
557 ----------------------------------------------------------------------------*/
558 NS_IMETHODIMP
559 nsEditingSession::OnStateChange(nsIWebProgress* aWebProgress,
560 nsIRequest* aRequest, uint32_t aStateFlags,
561 nsresult aStatus) {
562 #ifdef NOISY_DOC_LOADING
563 nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
564 if (channel) {
565 nsAutoCString contentType;
566 channel->GetContentType(contentType);
567 if (!contentType.IsEmpty()) {
568 printf(" ++++++ MIMETYPE = %s\n", contentType.get());
571 #endif
574 // A Request has started...
576 if (aStateFlags & nsIWebProgressListener::STATE_START) {
577 #ifdef NOISY_DOC_LOADING
579 nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
580 if (channel) {
581 nsCOMPtr<nsIURI> uri;
582 channel->GetURI(getter_AddRefs(uri));
583 if (uri) {
584 nsCString spec;
585 uri->GetSpec(spec);
586 printf(" **** STATE_START: CHANNEL URI=%s, flags=%x\n", spec.get(),
587 aStateFlags);
589 } else {
590 printf(" STATE_START: NO CHANNEL flags=%x\n", aStateFlags);
593 #endif
594 // Page level notification...
595 if (aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK) {
596 nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
597 StartPageLoad(channel);
598 #ifdef NOISY_DOC_LOADING
599 printf("STATE_START & STATE_IS_NETWORK flags=%x\n", aStateFlags);
600 #endif
603 // Document level notification...
604 if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT &&
605 !(aStateFlags & nsIWebProgressListener::STATE_RESTORING)) {
606 #ifdef NOISY_DOC_LOADING
607 printf("STATE_START & STATE_IS_DOCUMENT flags=%x\n", aStateFlags);
608 #endif
610 bool progressIsForTargetDocument =
611 IsProgressForTargetDocument(aWebProgress);
613 if (progressIsForTargetDocument) {
614 nsCOMPtr<mozIDOMWindowProxy> window;
615 aWebProgress->GetDOMWindow(getter_AddRefs(window));
617 auto* piWindow = nsPIDOMWindowOuter::From(window);
618 RefPtr<Document> doc = piWindow->GetDoc();
619 nsHTMLDocument* htmlDoc =
620 doc && doc->IsHTMLOrXHTML() ? doc->AsHTMLDocument() : nullptr;
621 if (htmlDoc && doc->IsWriting()) {
622 nsAutoString designMode;
623 htmlDoc->GetDesignMode(designMode);
625 if (designMode.EqualsLiteral("on")) {
626 // This notification is for data coming in through
627 // document.open/write/close(), ignore it.
629 return NS_OK;
633 mCanCreateEditor = true;
634 StartDocumentLoad(aWebProgress, progressIsForTargetDocument);
639 // A Request is being processed
641 else if (aStateFlags & nsIWebProgressListener::STATE_TRANSFERRING) {
642 if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT) {
643 // document transfer started
647 // Got a redirection
649 else if (aStateFlags & nsIWebProgressListener::STATE_REDIRECTING) {
650 if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT) {
651 // got a redirect
655 // A network or document Request has finished...
657 else if (aStateFlags & nsIWebProgressListener::STATE_STOP) {
658 #ifdef NOISY_DOC_LOADING
660 nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
661 if (channel) {
662 nsCOMPtr<nsIURI> uri;
663 channel->GetURI(getter_AddRefs(uri));
664 if (uri) {
665 nsCString spec;
666 uri->GetSpec(spec);
667 printf(" **** STATE_STOP: CHANNEL URI=%s, flags=%x\n", spec.get(),
668 aStateFlags);
670 } else {
671 printf(" STATE_STOP: NO CHANNEL flags=%x\n", aStateFlags);
674 #endif
676 // Document level notification...
677 if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT) {
678 nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
679 EndDocumentLoad(aWebProgress, channel, aStatus,
680 IsProgressForTargetDocument(aWebProgress));
681 #ifdef NOISY_DOC_LOADING
682 printf("STATE_STOP & STATE_IS_DOCUMENT flags=%x\n", aStateFlags);
683 #endif
686 // Page level notification...
687 if (aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK) {
688 nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
689 (void)EndPageLoad(aWebProgress, channel, aStatus);
690 #ifdef NOISY_DOC_LOADING
691 printf("STATE_STOP & STATE_IS_NETWORK flags=%x\n", aStateFlags);
692 #endif
696 return NS_OK;
699 /*---------------------------------------------------------------------------
701 OnProgressChange
703 ----------------------------------------------------------------------------*/
704 NS_IMETHODIMP
705 nsEditingSession::OnProgressChange(nsIWebProgress* aWebProgress,
706 nsIRequest* aRequest,
707 int32_t aCurSelfProgress,
708 int32_t aMaxSelfProgress,
709 int32_t aCurTotalProgress,
710 int32_t aMaxTotalProgress) {
711 MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
712 return NS_OK;
715 /*---------------------------------------------------------------------------
717 OnLocationChange
719 ----------------------------------------------------------------------------*/
720 NS_IMETHODIMP
721 nsEditingSession::OnLocationChange(nsIWebProgress* aWebProgress,
722 nsIRequest* aRequest, nsIURI* aURI,
723 uint32_t aFlags) {
724 nsCOMPtr<mozIDOMWindowProxy> domWindow;
725 nsresult rv = aWebProgress->GetDOMWindow(getter_AddRefs(domWindow));
726 NS_ENSURE_SUCCESS(rv, rv);
728 auto* piWindow = nsPIDOMWindowOuter::From(domWindow);
730 RefPtr<Document> doc = piWindow->GetDoc();
731 NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
733 doc->SetDocumentURI(aURI);
735 // Notify the location-changed observer that
736 // the document URL has changed
737 nsIDocShell* docShell = piWindow->GetDocShell();
738 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
740 RefPtr<nsCommandManager> commandManager = docShell->GetCommandManager();
741 return commandManager->CommandStatusChanged("obs_documentLocationChanged");
744 /*---------------------------------------------------------------------------
746 OnStatusChange
748 ----------------------------------------------------------------------------*/
749 NS_IMETHODIMP
750 nsEditingSession::OnStatusChange(nsIWebProgress* aWebProgress,
751 nsIRequest* aRequest, nsresult aStatus,
752 const char16_t* aMessage) {
753 MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
754 return NS_OK;
757 /*---------------------------------------------------------------------------
759 OnSecurityChange
761 ----------------------------------------------------------------------------*/
762 NS_IMETHODIMP
763 nsEditingSession::OnSecurityChange(nsIWebProgress* aWebProgress,
764 nsIRequest* aRequest, uint32_t aState) {
765 MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
766 return NS_OK;
769 /*---------------------------------------------------------------------------
771 OnContentBlockingEvent
773 ----------------------------------------------------------------------------*/
774 NS_IMETHODIMP
775 nsEditingSession::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
776 nsIRequest* aRequest,
777 uint32_t aEvent) {
778 MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
779 return NS_OK;
782 /*---------------------------------------------------------------------------
784 IsProgressForTargetDocument
786 Check that this notification is for our document.
787 ----------------------------------------------------------------------------*/
789 bool nsEditingSession::IsProgressForTargetDocument(
790 nsIWebProgress* aWebProgress) {
791 nsCOMPtr<nsIWebProgress> editedWebProgress = do_QueryReferent(mDocShell);
792 return editedWebProgress == aWebProgress;
795 /*---------------------------------------------------------------------------
797 GetEditorStatus
799 Called during GetCommandStateParams("obs_documentCreated"...)
800 to determine if editor was created and document
801 was loaded successfully
802 ----------------------------------------------------------------------------*/
803 NS_IMETHODIMP
804 nsEditingSession::GetEditorStatus(uint32_t* aStatus) {
805 NS_ENSURE_ARG_POINTER(aStatus);
806 *aStatus = mEditorStatus;
807 return NS_OK;
810 /*---------------------------------------------------------------------------
812 StartDocumentLoad
814 Called on start of load in a single frame
815 ----------------------------------------------------------------------------*/
816 nsresult nsEditingSession::StartDocumentLoad(nsIWebProgress* aWebProgress,
817 bool aIsToBeMadeEditable) {
818 #ifdef NOISY_DOC_LOADING
819 printf("======= StartDocumentLoad ========\n");
820 #endif
822 NS_ENSURE_ARG_POINTER(aWebProgress);
824 if (aIsToBeMadeEditable) {
825 mEditorStatus = eEditorCreationInProgress;
828 return NS_OK;
831 /*---------------------------------------------------------------------------
833 EndDocumentLoad
835 Called on end of load in a single frame
836 ----------------------------------------------------------------------------*/
837 nsresult nsEditingSession::EndDocumentLoad(nsIWebProgress* aWebProgress,
838 nsIChannel* aChannel,
839 nsresult aStatus,
840 bool aIsToBeMadeEditable) {
841 NS_ENSURE_ARG_POINTER(aWebProgress);
843 #ifdef NOISY_DOC_LOADING
844 printf("======= EndDocumentLoad ========\n");
845 printf("with status %d, ", aStatus);
846 nsCOMPtr<nsIURI> uri;
847 nsCString spec;
848 if (NS_SUCCEEDED(aChannel->GetURI(getter_AddRefs(uri)))) {
849 uri->GetSpec(spec);
850 printf(" uri %s\n", spec.get());
852 #endif
854 // We want to call the base class EndDocumentLoad,
855 // but avoid some of the stuff
856 // that nsDocShell does (need to refactor).
858 // OK, time to make an editor on this document
859 nsCOMPtr<mozIDOMWindowProxy> domWindow;
860 aWebProgress->GetDOMWindow(getter_AddRefs(domWindow));
861 NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
863 // Set the error state -- we will create an editor
864 // anyway and load empty doc later
865 if (aIsToBeMadeEditable && aStatus == NS_ERROR_FILE_NOT_FOUND) {
866 mEditorStatus = eEditorErrorFileNotFound;
869 auto* window = nsPIDOMWindowOuter::From(domWindow);
870 nsIDocShell* docShell = window->GetDocShell();
871 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); // better error handling?
873 // cancel refresh from meta tags
874 // we need to make sure that all pages in editor (whether editable or not)
875 // can't refresh contents being edited
876 nsCOMPtr<nsIRefreshURI> refreshURI = do_QueryInterface(docShell);
877 if (refreshURI) {
878 refreshURI->CancelRefreshURITimers();
881 nsresult rv = NS_OK;
883 // did someone set the flag to make this shell editable?
884 if (aIsToBeMadeEditable && mCanCreateEditor) {
885 bool makeEditable;
886 docShell->GetEditable(&makeEditable);
888 if (makeEditable) {
889 // To keep pre Gecko 1.9 behavior, setup editor always when
890 // mMakeWholeDocumentEditable.
891 bool needsSetup = false;
892 if (mMakeWholeDocumentEditable) {
893 needsSetup = true;
894 } else {
895 // do we already have an editor here?
896 needsSetup = !docShell->GetHTMLEditor();
899 if (needsSetup) {
900 mCanCreateEditor = false;
901 rv = SetupEditorOnWindow(MOZ_KnownLive(*window));
902 if (NS_FAILED(rv)) {
903 // If we had an error, setup timer to load a blank page later
904 if (mLoadBlankDocTimer) {
905 // Must cancel previous timer?
906 mLoadBlankDocTimer->Cancel();
907 mLoadBlankDocTimer = nullptr;
910 rv = NS_NewTimerWithFuncCallback(getter_AddRefs(mLoadBlankDocTimer),
911 nsEditingSession::TimerCallback,
912 static_cast<void*>(mDocShell.get()),
913 10, nsITimer::TYPE_ONE_SHOT,
914 "nsEditingSession::EndDocumentLoad");
915 NS_ENSURE_SUCCESS(rv, rv);
917 mEditorStatus = eEditorCreationInProgress;
922 return rv;
925 void nsEditingSession::TimerCallback(nsITimer* aTimer, void* aClosure) {
926 nsCOMPtr<nsIDocShell> docShell =
927 do_QueryReferent(static_cast<nsIWeakReference*>(aClosure));
928 if (docShell) {
929 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell));
930 if (webNav) {
931 LoadURIOptions loadURIOptions;
932 loadURIOptions.mTriggeringPrincipal =
933 nsContentUtils::GetSystemPrincipal();
934 webNav->LoadURI(NS_LITERAL_STRING("about:blank"), loadURIOptions);
939 /*---------------------------------------------------------------------------
941 StartPageLoad
943 Called on start load of the entire page (incl. subframes)
944 ----------------------------------------------------------------------------*/
945 nsresult nsEditingSession::StartPageLoad(nsIChannel* aChannel) {
946 #ifdef NOISY_DOC_LOADING
947 printf("======= StartPageLoad ========\n");
948 #endif
949 return NS_OK;
952 /*---------------------------------------------------------------------------
954 EndPageLoad
956 Called on end load of the entire page (incl. subframes)
957 ----------------------------------------------------------------------------*/
958 nsresult nsEditingSession::EndPageLoad(nsIWebProgress* aWebProgress,
959 nsIChannel* aChannel, nsresult aStatus) {
960 #ifdef NOISY_DOC_LOADING
961 printf("======= EndPageLoad ========\n");
962 printf(" with status %d, ", aStatus);
963 nsCOMPtr<nsIURI> uri;
964 nsCString spec;
965 if (NS_SUCCEEDED(aChannel->GetURI(getter_AddRefs(uri)))) {
966 uri->GetSpec(spec);
967 printf("uri %s\n", spec.get());
970 nsAutoCString contentType;
971 aChannel->GetContentType(contentType);
972 if (!contentType.IsEmpty()) {
973 printf(" flags = %d, status = %d, MIMETYPE = %s\n", mEditorFlags,
974 mEditorStatus, contentType.get());
976 #endif
978 // Set the error state -- we will create an editor anyway
979 // and load empty doc later
980 if (aStatus == NS_ERROR_FILE_NOT_FOUND) {
981 mEditorStatus = eEditorErrorFileNotFound;
984 nsCOMPtr<mozIDOMWindowProxy> domWindow;
985 aWebProgress->GetDOMWindow(getter_AddRefs(domWindow));
987 nsIDocShell* docShell =
988 domWindow ? nsPIDOMWindowOuter::From(domWindow)->GetDocShell() : nullptr;
989 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
991 // cancel refresh from meta tags
992 // we need to make sure that all pages in editor (whether editable or not)
993 // can't refresh contents being edited
994 nsCOMPtr<nsIRefreshURI> refreshURI = do_QueryInterface(docShell);
995 if (refreshURI) {
996 refreshURI->CancelRefreshURITimers();
999 #if 0
1000 // Shouldn't we do this when we want to edit sub-frames?
1001 return MakeWindowEditable(domWindow, "html", false, mInteractive);
1002 #else
1003 return NS_OK;
1004 #endif
1007 /*---------------------------------------------------------------------------
1009 PrepareForEditing
1011 Set up this editing session for one or more editors
1012 ----------------------------------------------------------------------------*/
1013 nsresult nsEditingSession::PrepareForEditing(nsPIDOMWindowOuter* aWindow) {
1014 if (mProgressListenerRegistered) {
1015 return NS_OK;
1018 nsIDocShell* docShell = aWindow ? aWindow->GetDocShell() : nullptr;
1020 // register callback
1021 nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
1022 NS_ENSURE_TRUE(webProgress, NS_ERROR_FAILURE);
1024 nsresult rv = webProgress->AddProgressListener(
1025 this, (nsIWebProgress::NOTIFY_STATE_NETWORK |
1026 nsIWebProgress::NOTIFY_STATE_DOCUMENT |
1027 nsIWebProgress::NOTIFY_LOCATION));
1029 mProgressListenerRegistered = NS_SUCCEEDED(rv);
1031 return rv;
1034 /*---------------------------------------------------------------------------
1036 SetupEditorCommandController
1038 Create a command controller, append to controllers,
1039 get and return the controller ID, and set the context
1040 ----------------------------------------------------------------------------*/
1041 nsresult nsEditingSession::SetupEditorCommandController(
1042 nsEditingSession::ControllerCreatorFn aControllerCreatorFn,
1043 mozIDOMWindowProxy* aWindow, nsISupports* aContext,
1044 uint32_t* aControllerId) {
1045 NS_ENSURE_ARG_POINTER(aControllerCreatorFn);
1046 NS_ENSURE_ARG_POINTER(aWindow);
1047 NS_ENSURE_ARG_POINTER(aContext);
1048 NS_ENSURE_ARG_POINTER(aControllerId);
1050 auto* piWindow = nsPIDOMWindowOuter::From(aWindow);
1051 MOZ_ASSERT(piWindow);
1053 nsCOMPtr<nsIControllers> controllers;
1054 nsresult rv = piWindow->GetControllers(getter_AddRefs(controllers));
1055 NS_ENSURE_SUCCESS(rv, rv);
1057 // We only have to create each singleton controller once
1058 // We know this has happened once we have a controllerId value
1059 if (!*aControllerId) {
1060 RefPtr<nsBaseCommandController> commandController = aControllerCreatorFn();
1061 NS_ENSURE_TRUE(commandController, NS_ERROR_FAILURE);
1063 // We must insert at head of the list to be sure our
1064 // controller is found before other implementations
1065 // (e.g., not-implemented versions by browser)
1066 rv = controllers->InsertControllerAt(0, commandController);
1067 NS_ENSURE_SUCCESS(rv, rv);
1069 // Remember the ID for the controller
1070 rv = controllers->GetControllerId(commandController, aControllerId);
1071 NS_ENSURE_SUCCESS(rv, rv);
1074 // Set the context
1075 return SetContextOnControllerById(controllers, aContext, *aControllerId);
1078 nsresult nsEditingSession::SetEditorOnControllers(nsPIDOMWindowOuter& aWindow,
1079 HTMLEditor* aEditor) {
1080 nsCOMPtr<nsIControllers> controllers;
1081 nsresult rv = aWindow.GetControllers(getter_AddRefs(controllers));
1082 NS_ENSURE_SUCCESS(rv, rv);
1084 nsCOMPtr<nsISupports> editorAsISupports = static_cast<nsIEditor*>(aEditor);
1085 if (mBaseCommandControllerId) {
1086 rv = SetContextOnControllerById(controllers, editorAsISupports,
1087 mBaseCommandControllerId);
1088 NS_ENSURE_SUCCESS(rv, rv);
1091 if (mDocStateControllerId) {
1092 rv = SetContextOnControllerById(controllers, editorAsISupports,
1093 mDocStateControllerId);
1094 NS_ENSURE_SUCCESS(rv, rv);
1097 if (mHTMLCommandControllerId) {
1098 rv = SetContextOnControllerById(controllers, editorAsISupports,
1099 mHTMLCommandControllerId);
1102 return rv;
1105 nsresult nsEditingSession::SetContextOnControllerById(
1106 nsIControllers* aControllers, nsISupports* aContext, uint32_t aID) {
1107 NS_ENSURE_ARG_POINTER(aControllers);
1109 // aContext can be null (when destroying editor)
1110 nsCOMPtr<nsIController> controller;
1111 aControllers->GetControllerById(aID, getter_AddRefs(controller));
1113 // ok with nil controller
1114 nsCOMPtr<nsIControllerContext> editorController =
1115 do_QueryInterface(controller);
1116 NS_ENSURE_TRUE(editorController, NS_ERROR_FAILURE);
1118 return editorController->SetCommandContext(aContext);
1121 void nsEditingSession::RemoveEditorControllers(nsPIDOMWindowOuter* aWindow) {
1122 // Remove editor controllers from the aWindow, call when we're
1123 // tearing down/detaching editor.
1125 nsCOMPtr<nsIControllers> controllers;
1126 if (aWindow) {
1127 aWindow->GetControllers(getter_AddRefs(controllers));
1130 if (controllers) {
1131 nsCOMPtr<nsIController> controller;
1132 if (mBaseCommandControllerId) {
1133 controllers->GetControllerById(mBaseCommandControllerId,
1134 getter_AddRefs(controller));
1135 if (controller) {
1136 controllers->RemoveController(controller);
1140 if (mDocStateControllerId) {
1141 controllers->GetControllerById(mDocStateControllerId,
1142 getter_AddRefs(controller));
1143 if (controller) {
1144 controllers->RemoveController(controller);
1148 if (mHTMLCommandControllerId) {
1149 controllers->GetControllerById(mHTMLCommandControllerId,
1150 getter_AddRefs(controller));
1151 if (controller) {
1152 controllers->RemoveController(controller);
1157 // Clear IDs to trigger creation of new controllers.
1158 mBaseCommandControllerId = 0;
1159 mDocStateControllerId = 0;
1160 mHTMLCommandControllerId = 0;
1163 void nsEditingSession::RemoveWebProgressListener(nsPIDOMWindowOuter* aWindow) {
1164 nsIDocShell* docShell = aWindow ? aWindow->GetDocShell() : nullptr;
1165 nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
1166 if (webProgress) {
1167 webProgress->RemoveProgressListener(this);
1168 mProgressListenerRegistered = false;
1172 void nsEditingSession::RestoreAnimationMode(nsPIDOMWindowOuter* aWindow) {
1173 if (mInteractive) {
1174 return;
1177 nsCOMPtr<nsIDocShell> docShell = aWindow ? aWindow->GetDocShell() : nullptr;
1178 NS_ENSURE_TRUE_VOID(docShell);
1179 RefPtr<PresShell> presShell = docShell->GetPresShell();
1180 if (NS_WARN_IF(!presShell)) {
1181 return;
1183 nsPresContext* presContext = presShell->GetPresContext();
1184 NS_ENSURE_TRUE_VOID(presContext);
1186 presContext->SetImageAnimationMode(mImageAnimationMode);
1189 nsresult nsEditingSession::DetachFromWindow(nsPIDOMWindowOuter* aWindow) {
1190 NS_ENSURE_TRUE(mDoneSetup, NS_OK);
1192 NS_ASSERTION(mComposerCommandsUpdater,
1193 "mComposerCommandsUpdater should exist.");
1195 // Kill any existing reload timer
1196 if (mLoadBlankDocTimer) {
1197 mLoadBlankDocTimer->Cancel();
1198 mLoadBlankDocTimer = nullptr;
1201 // Remove controllers, webprogress listener, and otherwise
1202 // make things the way they were before we started editing.
1203 RemoveEditorControllers(aWindow);
1204 RemoveWebProgressListener(aWindow);
1205 RestoreJSAndPlugins(aWindow);
1206 RestoreAnimationMode(aWindow);
1208 // Kill our weak reference to our original window, in case
1209 // it changes on restore, or otherwise dies.
1210 mDocShell = nullptr;
1212 return NS_OK;
1215 nsresult nsEditingSession::ReattachToWindow(nsPIDOMWindowOuter* aWindow) {
1216 NS_ENSURE_TRUE(mDoneSetup, NS_OK);
1217 NS_ENSURE_TRUE(aWindow, NS_ERROR_FAILURE);
1219 NS_ASSERTION(mComposerCommandsUpdater,
1220 "mComposerCommandsUpdater should exist.");
1222 // Imitate nsEditorDocShell::MakeEditable() to reattach the
1223 // old editor ot the window.
1224 nsresult rv;
1226 nsIDocShell* docShell = aWindow->GetDocShell();
1227 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
1228 mDocShell = do_GetWeakReference(docShell);
1230 // Disable plugins.
1231 if (!mInteractive) {
1232 rv = DisableJSAndPlugins(*docShell);
1233 NS_ENSURE_SUCCESS(rv, rv);
1236 // Tells embedder that startup is in progress.
1237 mEditorStatus = eEditorCreationInProgress;
1239 // Adds back web progress listener.
1240 rv = PrepareForEditing(aWindow);
1241 NS_ENSURE_SUCCESS(rv, rv);
1243 // Setup the command controllers again.
1244 rv = SetupEditorCommandController(
1245 nsBaseCommandController::CreateEditingController, aWindow,
1246 static_cast<nsIEditingSession*>(this), &mBaseCommandControllerId);
1247 NS_ENSURE_SUCCESS(rv, rv);
1249 rv = SetupEditorCommandController(
1250 nsBaseCommandController::CreateHTMLEditorDocStateController, aWindow,
1251 static_cast<nsIEditingSession*>(this), &mDocStateControllerId);
1252 NS_ENSURE_SUCCESS(rv, rv);
1254 if (mComposerCommandsUpdater) {
1255 mComposerCommandsUpdater->Init(*aWindow);
1258 // Get editor
1259 RefPtr<HTMLEditor> htmlEditor = GetHTMLEditorForWindow(aWindow);
1260 if (NS_WARN_IF(!htmlEditor)) {
1261 return NS_ERROR_FAILURE;
1264 if (!mInteractive) {
1265 // Disable animation of images in this document:
1266 RefPtr<PresShell> presShell = docShell->GetPresShell();
1267 if (NS_WARN_IF(!presShell)) {
1268 return NS_ERROR_FAILURE;
1270 nsPresContext* presContext = presShell->GetPresContext();
1271 NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
1273 mImageAnimationMode = presContext->ImageAnimationMode();
1274 presContext->SetImageAnimationMode(imgIContainer::kDontAnimMode);
1277 // The third controller takes an nsIEditor as the context
1278 rv = SetupEditorCommandController(
1279 nsBaseCommandController::CreateHTMLEditorController, aWindow,
1280 static_cast<nsIEditor*>(htmlEditor.get()), &mHTMLCommandControllerId);
1281 NS_ENSURE_SUCCESS(rv, rv);
1283 // Set context on all controllers to be the editor
1284 rv = SetEditorOnControllers(*aWindow, htmlEditor);
1285 NS_ENSURE_SUCCESS(rv, rv);
1287 #ifdef DEBUG
1289 bool isEditable;
1290 rv = WindowIsEditable(aWindow, &isEditable);
1291 NS_ENSURE_SUCCESS(rv, rv);
1292 NS_ASSERTION(isEditable,
1293 "Window is not editable after reattaching editor.");
1295 #endif // DEBUG
1297 return NS_OK;
1300 HTMLEditor* nsIEditingSession::GetHTMLEditorForWindow(
1301 mozIDOMWindowProxy* aWindow) {
1302 if (NS_WARN_IF(!aWindow)) {
1303 return nullptr;
1306 nsCOMPtr<nsIDocShell> docShell =
1307 nsPIDOMWindowOuter::From(aWindow)->GetDocShell();
1308 if (NS_WARN_IF(!docShell)) {
1309 return nullptr;
1312 return docShell->GetHTMLEditor();