Bug 1869043 assert that graph set access is main thread only r=padenot
[gecko.git] / editor / composer / nsEditingSession.cpp
blob92ab84ac2605bd8d9a1ba76653164aa5d693f72b
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 "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"
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);
119 mDocShell = do_GetWeakReference(docShell);
121 mInteractive = aInteractive;
122 mMakeWholeDocumentEditable = aMakeWholeDocumentEditable;
124 nsresult rv;
125 if (!mInteractive) {
126 rv = DisableJSAndPlugins(window->GetCurrentInnerWindow());
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(nsPIDOMWindowInner* aWindow) {
179 WindowContext* wc = aWindow->GetWindowContext();
180 BrowsingContext* bc = wc->GetBrowsingContext();
182 mScriptsEnabled = wc->GetAllowJavascript();
184 MOZ_TRY(wc->SetAllowJavascript(false));
186 // Disable plugins in this document:
187 mPluginsEnabled = bc->GetAllowPlugins();
189 MOZ_TRY(bc->SetAllowPlugins(false));
191 mDisabledJSAndPlugins = true;
193 return NS_OK;
196 nsresult nsEditingSession::RestoreJSAndPlugins(nsPIDOMWindowInner* aWindow) {
197 if (!mDisabledJSAndPlugins) {
198 return NS_OK;
201 mDisabledJSAndPlugins = false;
203 if (NS_WARN_IF(!aWindow)) {
204 // DetachFromWindow may call this method with nullptr.
205 return NS_ERROR_FAILURE;
208 WindowContext* wc = aWindow->GetWindowContext();
209 BrowsingContext* bc = wc->GetBrowsingContext();
211 MOZ_TRY(wc->SetAllowJavascript(mScriptsEnabled));
213 // Disable plugins in this document:
215 return bc->SetAllowPlugins(mPluginsEnabled);
218 /*---------------------------------------------------------------------------
220 WindowIsEditable
222 boolean windowIsEditable (in nsIDOMWindow aWindow);
223 ----------------------------------------------------------------------------*/
224 NS_IMETHODIMP
225 nsEditingSession::WindowIsEditable(mozIDOMWindowProxy* aWindow,
226 bool* outIsEditable) {
227 NS_ENSURE_STATE(aWindow);
228 nsCOMPtr<nsIDocShell> docShell =
229 nsPIDOMWindowOuter::From(aWindow)->GetDocShell();
230 NS_ENSURE_STATE(docShell);
232 return docShell->GetEditable(outIsEditable);
235 bool IsSupportedTextType(const nsAString& aMIMEType) {
236 // These are MIME types that are automatically parsed as "text/plain"
237 // and thus we can edit them as plaintext
238 // Note: in older versions, we attempted to convert the mimetype of
239 // the network channel for these and "text/xml" to "text/plain",
240 // but further investigation reveals that strategy doesn't work
241 static constexpr nsLiteralString sSupportedTextTypes[] = {
242 u"text/plain"_ns,
243 u"text/css"_ns,
244 u"text/rdf"_ns,
245 u"text/xsl"_ns,
246 u"text/javascript"_ns, // obsolete type
247 u"text/ecmascript"_ns, // obsolete type
248 u"application/javascript"_ns,
249 u"application/ecmascript"_ns,
250 u"application/x-javascript"_ns, // obsolete type
251 u"text/xul"_ns // obsolete type
254 for (const nsLiteralString& supportedTextType : sSupportedTextTypes) {
255 if (aMIMEType.Equals(supportedTextType)) {
256 return true;
260 return false;
263 nsresult nsEditingSession::SetupEditorOnWindow(nsPIDOMWindowOuter& aWindow) {
264 mDoneSetup = true;
266 // MIME CHECKING
267 // must get the content type
268 // Note: the doc gets this from the network channel during StartPageLoad,
269 // so we don't have to get it from there ourselves
270 nsAutoString mimeType;
272 // then lets check the mime type
273 if (RefPtr<Document> doc = aWindow.GetDoc()) {
274 doc->GetContentType(mimeType);
276 if (IsSupportedTextType(mimeType)) {
277 mEditorType.AssignLiteral("text");
278 mimeType.AssignLiteral("text/plain");
279 } else if (!doc->IsHTMLOrXHTML()) {
280 // Neither an acceptable text or html type.
281 mEditorStatus = eEditorErrorCantEditMimeType;
283 // Turn editor into HTML -- we will load blank page later
284 mEditorType.AssignLiteral("html");
285 mimeType.AssignLiteral("text/html");
288 // Flush out frame construction to make sure that the subframe's
289 // presshell is set up if it needs to be.
290 doc->FlushPendingNotifications(mozilla::FlushType::Frames);
291 if (mMakeWholeDocumentEditable) {
292 doc->SetEditableFlag(true);
293 // Enable usage of the execCommand API
294 doc->SetEditingState(Document::EditingState::eDesignMode);
297 bool needHTMLController = false;
299 if (mEditorType.EqualsLiteral("textmail")) {
300 mEditorFlags = nsIEditor::eEditorPlaintextMask |
301 nsIEditor::eEditorEnableWrapHackMask |
302 nsIEditor::eEditorMailMask;
303 } else if (mEditorType.EqualsLiteral("text")) {
304 mEditorFlags =
305 nsIEditor::eEditorPlaintextMask | nsIEditor::eEditorEnableWrapHackMask;
306 } else if (mEditorType.EqualsLiteral("htmlmail")) {
307 if (mimeType.EqualsLiteral("text/html")) {
308 needHTMLController = true;
309 mEditorFlags = nsIEditor::eEditorMailMask;
310 } else {
311 // Set the flags back to textplain.
312 mEditorFlags = nsIEditor::eEditorPlaintextMask |
313 nsIEditor::eEditorEnableWrapHackMask;
315 } else {
316 // Defaulted to html
317 needHTMLController = true;
320 if (mInteractive) {
321 mEditorFlags |= nsIEditor::eEditorAllowInteraction;
324 // make the UI state maintainer
325 RefPtr<ComposerCommandsUpdater> commandsUpdater =
326 new ComposerCommandsUpdater();
327 mComposerCommandsUpdater = commandsUpdater;
329 // now init the state maintainer
330 // This allows notification of error state
331 // even if we don't create an editor
332 commandsUpdater->Init(aWindow);
334 if (mEditorStatus != eEditorCreationInProgress) {
335 commandsUpdater->OnHTMLEditorCreated();
337 // At this point we have made a final decision that we don't support
338 // editing the current document. This is an internal failure state, but
339 // we return NS_OK to avoid throwing an exception from the designMode
340 // setter for web compatibility. The document editing APIs will tell the
341 // developer if editing has been disabled because we're in a document type
342 // that doesn't support editing.
343 return NS_OK;
346 // Create editor and do other things
347 // only if we haven't found some error above,
348 const RefPtr<nsDocShell> docShell = nsDocShell::Cast(aWindow.GetDocShell());
349 if (NS_WARN_IF(!docShell)) {
350 return NS_ERROR_FAILURE;
352 const RefPtr<PresShell> presShell = docShell->GetPresShell();
353 if (NS_WARN_IF(!presShell)) {
354 return NS_ERROR_FAILURE;
357 if (!mInteractive) {
358 // Disable animation of images in this document:
359 nsPresContext* presContext = presShell->GetPresContext();
360 NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
362 mImageAnimationMode = presContext->ImageAnimationMode();
363 presContext->SetImageAnimationMode(imgIContainer::kDontAnimMode);
366 // Hide selection changes during initialization, in order to hide this
367 // from web pages.
368 RefPtr<nsFrameSelection> fs = presShell->FrameSelection();
369 NS_ENSURE_TRUE(fs, NS_ERROR_FAILURE);
370 AutoHideSelectionChanges hideSelectionChanges(fs);
372 nsCOMPtr<nsIDocumentViewer> viewer;
373 nsresult rv = docShell->GetDocViewer(getter_AddRefs(viewer));
374 if (NS_FAILED(rv) || NS_WARN_IF(!viewer)) {
375 NS_WARNING("nsDocShell::GetDocViewer() failed");
376 return rv;
379 const RefPtr<Document> doc = viewer->GetDocument();
380 if (NS_WARN_IF(!doc)) {
381 return NS_ERROR_FAILURE;
384 // create and set editor
385 // Try to reuse an existing editor
386 nsCOMPtr<nsIEditor> editor = do_QueryReferent(mExistingEditor);
387 RefPtr<HTMLEditor> htmlEditor = HTMLEditor::GetFrom(editor);
388 MOZ_ASSERT_IF(editor, htmlEditor);
389 if (htmlEditor) {
390 htmlEditor->PreDestroy();
391 } else {
392 htmlEditor = new HTMLEditor(*doc);
393 mExistingEditor =
394 do_GetWeakReference(static_cast<nsIEditor*>(htmlEditor.get()));
396 // set the editor on the docShell. The docShell now owns it.
397 rv = docShell->SetHTMLEditor(htmlEditor);
398 NS_ENSURE_SUCCESS(rv, rv);
400 // setup the HTML editor command controller
401 if (needHTMLController) {
402 // The third controller takes an nsIEditor as the context
403 rv = SetupEditorCommandController(
404 nsBaseCommandController::CreateHTMLEditorController, &aWindow,
405 static_cast<nsIEditor*>(htmlEditor), &mHTMLCommandControllerId);
406 NS_ENSURE_SUCCESS(rv, rv);
409 // Set mimetype on editor
410 rv = htmlEditor->SetContentsMIMEType(mimeType);
411 NS_ENSURE_SUCCESS(rv, rv);
413 MOZ_ASSERT(docShell->HasDocumentViewer());
414 MOZ_ASSERT(viewer->GetDocument());
416 MOZ_DIAGNOSTIC_ASSERT(commandsUpdater == mComposerCommandsUpdater);
417 if (MOZ_UNLIKELY(commandsUpdater != mComposerCommandsUpdater)) {
418 commandsUpdater = mComposerCommandsUpdater;
420 rv = htmlEditor->Init(*doc, *commandsUpdater, mEditorFlags);
421 NS_ENSURE_SUCCESS(rv, rv);
423 RefPtr<Selection> selection = htmlEditor->GetSelection();
424 if (NS_WARN_IF(!selection)) {
425 return NS_ERROR_FAILURE;
428 // Set context on all controllers to be the editor
429 rv = SetEditorOnControllers(aWindow, htmlEditor);
430 NS_ENSURE_SUCCESS(rv, rv);
432 // Everything went fine!
433 mEditorStatus = eEditorOK;
435 // This will trigger documentCreation notification
436 return htmlEditor->PostCreate();
439 // Removes all listeners and controllers from aWindow and aEditor.
440 void nsEditingSession::RemoveListenersAndControllers(
441 nsPIDOMWindowOuter* aWindow, HTMLEditor* aHTMLEditor) {
442 if (!mComposerCommandsUpdater || !aHTMLEditor) {
443 return;
446 // Remove all the listeners
447 RefPtr<ComposerCommandsUpdater> composertCommandsUpdater =
448 std::move(mComposerCommandsUpdater);
449 MOZ_ASSERT(!mComposerCommandsUpdater);
450 aHTMLEditor->Detach(*composertCommandsUpdater);
452 // Remove editor controllers from the window now that we're not
453 // editing in that window any more.
454 RemoveEditorControllers(aWindow);
457 /*---------------------------------------------------------------------------
459 TearDownEditorOnWindow
461 void tearDownEditorOnWindow (in nsIDOMWindow aWindow);
462 ----------------------------------------------------------------------------*/
463 NS_IMETHODIMP
464 nsEditingSession::TearDownEditorOnWindow(mozIDOMWindowProxy* aWindow) {
465 if (!mDoneSetup) {
466 return NS_OK;
469 NS_ENSURE_TRUE(aWindow, NS_ERROR_NULL_POINTER);
471 // Kill any existing reload timer
472 if (mLoadBlankDocTimer) {
473 mLoadBlankDocTimer->Cancel();
474 mLoadBlankDocTimer = nullptr;
477 mDoneSetup = false;
479 // Check if we're turning off editing (from contentEditable or designMode).
480 auto* window = nsPIDOMWindowOuter::From(aWindow);
482 RefPtr<Document> doc = window->GetDoc();
483 bool stopEditing = doc && doc->IsEditingOn();
484 if (stopEditing) {
485 RemoveWebProgressListener(window);
488 nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
489 NS_ENSURE_STATE(docShell);
491 RefPtr<HTMLEditor> htmlEditor = docShell->GetHTMLEditor();
492 if (stopEditing) {
493 doc->TearingDownEditor();
496 if (mComposerCommandsUpdater && htmlEditor) {
497 // Null out the editor on the controllers first to prevent their weak
498 // references from pointing to a destroyed editor.
499 SetEditorOnControllers(*window, nullptr);
502 // Null out the editor on the docShell to trigger PreDestroy which
503 // needs to happen before document state listeners are removed below.
504 docShell->SetEditor(nullptr);
506 RemoveListenersAndControllers(window, htmlEditor);
508 if (stopEditing) {
509 // Make things the way they were before we started editing.
510 RestoreJSAndPlugins(window->GetCurrentInnerWindow());
511 RestoreAnimationMode(window);
513 if (mMakeWholeDocumentEditable) {
514 doc->SetEditableFlag(false);
515 doc->SetEditingState(Document::EditingState::eOff);
519 return NS_OK;
522 /*---------------------------------------------------------------------------
524 GetEditorForFrame
526 nsIEditor getEditorForFrame (in nsIDOMWindow aWindow);
527 ----------------------------------------------------------------------------*/
528 NS_IMETHODIMP
529 nsEditingSession::GetEditorForWindow(mozIDOMWindowProxy* aWindow,
530 nsIEditor** outEditor) {
531 if (NS_WARN_IF(!aWindow)) {
532 return NS_ERROR_INVALID_ARG;
534 nsCOMPtr<nsIEditor> editor = GetHTMLEditorForWindow(aWindow);
535 editor.forget(outEditor);
536 return NS_OK;
539 /*---------------------------------------------------------------------------
541 OnStateChange
543 ----------------------------------------------------------------------------*/
544 NS_IMETHODIMP
545 nsEditingSession::OnStateChange(nsIWebProgress* aWebProgress,
546 nsIRequest* aRequest, uint32_t aStateFlags,
547 nsresult aStatus) {
548 #ifdef NOISY_DOC_LOADING
549 nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
550 if (channel) {
551 nsAutoCString contentType;
552 channel->GetContentType(contentType);
553 if (!contentType.IsEmpty()) {
554 printf(" ++++++ MIMETYPE = %s\n", contentType.get());
557 #endif
560 // A Request has started...
562 if (aStateFlags & nsIWebProgressListener::STATE_START) {
563 #ifdef NOISY_DOC_LOADING
565 nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
566 if (channel) {
567 nsCOMPtr<nsIURI> uri;
568 channel->GetURI(getter_AddRefs(uri));
569 if (uri) {
570 nsCString spec;
571 uri->GetSpec(spec);
572 printf(" **** STATE_START: CHANNEL URI=%s, flags=%x\n", spec.get(),
573 aStateFlags);
575 } else {
576 printf(" STATE_START: NO CHANNEL flags=%x\n", aStateFlags);
579 #endif
580 // Page level notification...
581 if (aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK) {
582 nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
583 StartPageLoad(channel);
584 #ifdef NOISY_DOC_LOADING
585 printf("STATE_START & STATE_IS_NETWORK flags=%x\n", aStateFlags);
586 #endif
589 // Document level notification...
590 if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT &&
591 !(aStateFlags & nsIWebProgressListener::STATE_RESTORING)) {
592 #ifdef NOISY_DOC_LOADING
593 printf("STATE_START & STATE_IS_DOCUMENT flags=%x\n", aStateFlags);
594 #endif
596 bool progressIsForTargetDocument =
597 IsProgressForTargetDocument(aWebProgress);
599 if (progressIsForTargetDocument) {
600 nsCOMPtr<mozIDOMWindowProxy> window;
601 aWebProgress->GetDOMWindow(getter_AddRefs(window));
603 auto* piWindow = nsPIDOMWindowOuter::From(window);
604 RefPtr<Document> doc = piWindow->GetDoc();
605 nsHTMLDocument* htmlDoc =
606 doc && doc->IsHTMLOrXHTML() ? doc->AsHTMLDocument() : nullptr;
607 if (htmlDoc && doc->IsWriting()) {
608 nsAutoString designMode;
609 htmlDoc->GetDesignMode(designMode);
611 if (designMode.EqualsLiteral("on")) {
612 // This notification is for data coming in through
613 // document.open/write/close(), ignore it.
615 return NS_OK;
619 mCanCreateEditor = true;
620 StartDocumentLoad(aWebProgress, progressIsForTargetDocument);
625 // A Request is being processed
627 else if (aStateFlags & nsIWebProgressListener::STATE_TRANSFERRING) {
628 if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT) {
629 // document transfer started
633 // Got a redirection
635 else if (aStateFlags & nsIWebProgressListener::STATE_REDIRECTING) {
636 if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT) {
637 // got a redirect
641 // A network or document Request has finished...
643 else if (aStateFlags & nsIWebProgressListener::STATE_STOP) {
644 #ifdef NOISY_DOC_LOADING
646 nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
647 if (channel) {
648 nsCOMPtr<nsIURI> uri;
649 channel->GetURI(getter_AddRefs(uri));
650 if (uri) {
651 nsCString spec;
652 uri->GetSpec(spec);
653 printf(" **** STATE_STOP: CHANNEL URI=%s, flags=%x\n", spec.get(),
654 aStateFlags);
656 } else {
657 printf(" STATE_STOP: NO CHANNEL flags=%x\n", aStateFlags);
660 #endif
662 // Document level notification...
663 if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT) {
664 nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
665 EndDocumentLoad(aWebProgress, channel, aStatus,
666 IsProgressForTargetDocument(aWebProgress));
667 #ifdef NOISY_DOC_LOADING
668 printf("STATE_STOP & STATE_IS_DOCUMENT flags=%x\n", aStateFlags);
669 #endif
672 // Page level notification...
673 if (aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK) {
674 nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
675 (void)EndPageLoad(aWebProgress, channel, aStatus);
676 #ifdef NOISY_DOC_LOADING
677 printf("STATE_STOP & STATE_IS_NETWORK flags=%x\n", aStateFlags);
678 #endif
682 return NS_OK;
685 /*---------------------------------------------------------------------------
687 OnProgressChange
689 ----------------------------------------------------------------------------*/
690 NS_IMETHODIMP
691 nsEditingSession::OnProgressChange(nsIWebProgress* aWebProgress,
692 nsIRequest* aRequest,
693 int32_t aCurSelfProgress,
694 int32_t aMaxSelfProgress,
695 int32_t aCurTotalProgress,
696 int32_t aMaxTotalProgress) {
697 MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
698 return NS_OK;
701 /*---------------------------------------------------------------------------
703 OnLocationChange
705 ----------------------------------------------------------------------------*/
706 NS_IMETHODIMP
707 nsEditingSession::OnLocationChange(nsIWebProgress* aWebProgress,
708 nsIRequest* aRequest, nsIURI* aURI,
709 uint32_t aFlags) {
710 nsCOMPtr<mozIDOMWindowProxy> domWindow;
711 nsresult rv = aWebProgress->GetDOMWindow(getter_AddRefs(domWindow));
712 NS_ENSURE_SUCCESS(rv, rv);
714 auto* piWindow = nsPIDOMWindowOuter::From(domWindow);
716 RefPtr<Document> doc = piWindow->GetDoc();
717 NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
719 doc->SetDocumentURI(aURI);
721 // Notify the location-changed observer that
722 // the document URL has changed
723 nsIDocShell* docShell = piWindow->GetDocShell();
724 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
726 RefPtr<nsCommandManager> commandManager = docShell->GetCommandManager();
727 commandManager->CommandStatusChanged("obs_documentLocationChanged");
728 return NS_OK;
731 /*---------------------------------------------------------------------------
733 OnStatusChange
735 ----------------------------------------------------------------------------*/
736 NS_IMETHODIMP
737 nsEditingSession::OnStatusChange(nsIWebProgress* aWebProgress,
738 nsIRequest* aRequest, nsresult aStatus,
739 const char16_t* aMessage) {
740 MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
741 return NS_OK;
744 /*---------------------------------------------------------------------------
746 OnSecurityChange
748 ----------------------------------------------------------------------------*/
749 NS_IMETHODIMP
750 nsEditingSession::OnSecurityChange(nsIWebProgress* aWebProgress,
751 nsIRequest* aRequest, uint32_t aState) {
752 MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
753 return NS_OK;
756 /*---------------------------------------------------------------------------
758 OnContentBlockingEvent
760 ----------------------------------------------------------------------------*/
761 NS_IMETHODIMP
762 nsEditingSession::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
763 nsIRequest* aRequest,
764 uint32_t aEvent) {
765 MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
766 return NS_OK;
769 /*---------------------------------------------------------------------------
771 IsProgressForTargetDocument
773 Check that this notification is for our document.
774 ----------------------------------------------------------------------------*/
776 bool nsEditingSession::IsProgressForTargetDocument(
777 nsIWebProgress* aWebProgress) {
778 nsCOMPtr<nsIWebProgress> editedWebProgress = do_QueryReferent(mDocShell);
779 return editedWebProgress == aWebProgress;
782 /*---------------------------------------------------------------------------
784 GetEditorStatus
786 Called during GetCommandStateParams("obs_documentCreated"...)
787 to determine if editor was created and document
788 was loaded successfully
789 ----------------------------------------------------------------------------*/
790 NS_IMETHODIMP
791 nsEditingSession::GetEditorStatus(uint32_t* aStatus) {
792 NS_ENSURE_ARG_POINTER(aStatus);
793 *aStatus = mEditorStatus;
794 return NS_OK;
797 /*---------------------------------------------------------------------------
799 StartDocumentLoad
801 Called on start of load in a single frame
802 ----------------------------------------------------------------------------*/
803 nsresult nsEditingSession::StartDocumentLoad(nsIWebProgress* aWebProgress,
804 bool aIsToBeMadeEditable) {
805 #ifdef NOISY_DOC_LOADING
806 printf("======= StartDocumentLoad ========\n");
807 #endif
809 NS_ENSURE_ARG_POINTER(aWebProgress);
811 if (aIsToBeMadeEditable) {
812 mEditorStatus = eEditorCreationInProgress;
815 return NS_OK;
818 /*---------------------------------------------------------------------------
820 EndDocumentLoad
822 Called on end of load in a single frame
823 ----------------------------------------------------------------------------*/
824 nsresult nsEditingSession::EndDocumentLoad(nsIWebProgress* aWebProgress,
825 nsIChannel* aChannel,
826 nsresult aStatus,
827 bool aIsToBeMadeEditable) {
828 NS_ENSURE_ARG_POINTER(aWebProgress);
830 #ifdef NOISY_DOC_LOADING
831 printf("======= EndDocumentLoad ========\n");
832 printf("with status %d, ", aStatus);
833 nsCOMPtr<nsIURI> uri;
834 nsCString spec;
835 if (NS_SUCCEEDED(aChannel->GetURI(getter_AddRefs(uri)))) {
836 uri->GetSpec(spec);
837 printf(" uri %s\n", spec.get());
839 #endif
841 // We want to call the base class EndDocumentLoad,
842 // but avoid some of the stuff
843 // that nsDocShell does (need to refactor).
845 // OK, time to make an editor on this document
846 nsCOMPtr<mozIDOMWindowProxy> domWindow;
847 aWebProgress->GetDOMWindow(getter_AddRefs(domWindow));
848 NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
850 // Set the error state -- we will create an editor
851 // anyway and load empty doc later
852 if (aIsToBeMadeEditable && aStatus == NS_ERROR_FILE_NOT_FOUND) {
853 mEditorStatus = eEditorErrorFileNotFound;
856 auto* window = nsPIDOMWindowOuter::From(domWindow);
857 nsIDocShell* docShell = window->GetDocShell();
858 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); // better error handling?
860 // cancel refresh from meta tags
861 // we need to make sure that all pages in editor (whether editable or not)
862 // can't refresh contents being edited
863 nsCOMPtr<nsIRefreshURI> refreshURI = do_QueryInterface(docShell);
864 if (refreshURI) {
865 refreshURI->CancelRefreshURITimers();
868 nsresult rv = NS_OK;
870 // did someone set the flag to make this shell editable?
871 if (aIsToBeMadeEditable && mCanCreateEditor) {
872 bool makeEditable;
873 docShell->GetEditable(&makeEditable);
875 if (makeEditable) {
876 // To keep pre Gecko 1.9 behavior, setup editor always when
877 // mMakeWholeDocumentEditable.
878 bool needsSetup = false;
879 if (mMakeWholeDocumentEditable) {
880 needsSetup = true;
881 } else {
882 // do we already have an editor here?
883 needsSetup = !docShell->GetHTMLEditor();
886 if (needsSetup) {
887 mCanCreateEditor = false;
888 rv = SetupEditorOnWindow(MOZ_KnownLive(*window));
889 if (NS_FAILED(rv)) {
890 // If we had an error, setup timer to load a blank page later
891 if (mLoadBlankDocTimer) {
892 // Must cancel previous timer?
893 mLoadBlankDocTimer->Cancel();
894 mLoadBlankDocTimer = nullptr;
897 rv = NS_NewTimerWithFuncCallback(getter_AddRefs(mLoadBlankDocTimer),
898 nsEditingSession::TimerCallback,
899 static_cast<void*>(mDocShell.get()),
900 10, nsITimer::TYPE_ONE_SHOT,
901 "nsEditingSession::EndDocumentLoad");
902 NS_ENSURE_SUCCESS(rv, rv);
904 mEditorStatus = eEditorCreationInProgress;
909 return rv;
912 void nsEditingSession::TimerCallback(nsITimer* aTimer, void* aClosure) {
913 nsCOMPtr<nsIDocShell> docShell =
914 do_QueryReferent(static_cast<nsIWeakReference*>(aClosure));
915 if (docShell) {
916 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell));
917 if (webNav) {
918 LoadURIOptions loadURIOptions;
919 loadURIOptions.mTriggeringPrincipal =
920 nsContentUtils::GetSystemPrincipal();
921 nsCOMPtr<nsIURI> uri;
922 MOZ_ALWAYS_SUCCEEDS(NS_NewURI(getter_AddRefs(uri), "about:blank"_ns));
923 webNav->LoadURI(uri, loadURIOptions);
928 /*---------------------------------------------------------------------------
930 StartPageLoad
932 Called on start load of the entire page (incl. subframes)
933 ----------------------------------------------------------------------------*/
934 nsresult nsEditingSession::StartPageLoad(nsIChannel* aChannel) {
935 #ifdef NOISY_DOC_LOADING
936 printf("======= StartPageLoad ========\n");
937 #endif
938 return NS_OK;
941 /*---------------------------------------------------------------------------
943 EndPageLoad
945 Called on end load of the entire page (incl. subframes)
946 ----------------------------------------------------------------------------*/
947 nsresult nsEditingSession::EndPageLoad(nsIWebProgress* aWebProgress,
948 nsIChannel* aChannel, nsresult aStatus) {
949 #ifdef NOISY_DOC_LOADING
950 printf("======= EndPageLoad ========\n");
951 printf(" with status %d, ", aStatus);
952 nsCOMPtr<nsIURI> uri;
953 nsCString spec;
954 if (NS_SUCCEEDED(aChannel->GetURI(getter_AddRefs(uri)))) {
955 uri->GetSpec(spec);
956 printf("uri %s\n", spec.get());
959 nsAutoCString contentType;
960 aChannel->GetContentType(contentType);
961 if (!contentType.IsEmpty()) {
962 printf(" flags = %d, status = %d, MIMETYPE = %s\n", mEditorFlags,
963 mEditorStatus, contentType.get());
965 #endif
967 // Set the error state -- we will create an editor anyway
968 // and load empty doc later
969 if (aStatus == NS_ERROR_FILE_NOT_FOUND) {
970 mEditorStatus = eEditorErrorFileNotFound;
973 nsCOMPtr<mozIDOMWindowProxy> domWindow;
974 aWebProgress->GetDOMWindow(getter_AddRefs(domWindow));
976 nsIDocShell* docShell =
977 domWindow ? nsPIDOMWindowOuter::From(domWindow)->GetDocShell() : nullptr;
978 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
980 // cancel refresh from meta tags
981 // we need to make sure that all pages in editor (whether editable or not)
982 // can't refresh contents being edited
983 nsCOMPtr<nsIRefreshURI> refreshURI = do_QueryInterface(docShell);
984 if (refreshURI) {
985 refreshURI->CancelRefreshURITimers();
988 #if 0
989 // Shouldn't we do this when we want to edit sub-frames?
990 return MakeWindowEditable(domWindow, "html", false, mInteractive);
991 #else
992 return NS_OK;
993 #endif
996 /*---------------------------------------------------------------------------
998 PrepareForEditing
1000 Set up this editing session for one or more editors
1001 ----------------------------------------------------------------------------*/
1002 nsresult nsEditingSession::PrepareForEditing(nsPIDOMWindowOuter* aWindow) {
1003 if (mProgressListenerRegistered) {
1004 return NS_OK;
1007 nsIDocShell* docShell = aWindow ? aWindow->GetDocShell() : nullptr;
1009 // register callback
1010 nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
1011 NS_ENSURE_TRUE(webProgress, NS_ERROR_FAILURE);
1013 nsresult rv = webProgress->AddProgressListener(
1014 this, (nsIWebProgress::NOTIFY_STATE_NETWORK |
1015 nsIWebProgress::NOTIFY_STATE_DOCUMENT |
1016 nsIWebProgress::NOTIFY_LOCATION));
1018 mProgressListenerRegistered = NS_SUCCEEDED(rv);
1020 return rv;
1023 /*---------------------------------------------------------------------------
1025 SetupEditorCommandController
1027 Create a command controller, append to controllers,
1028 get and return the controller ID, and set the context
1029 ----------------------------------------------------------------------------*/
1030 nsresult nsEditingSession::SetupEditorCommandController(
1031 nsEditingSession::ControllerCreatorFn aControllerCreatorFn,
1032 mozIDOMWindowProxy* aWindow, nsISupports* aContext,
1033 uint32_t* aControllerId) {
1034 NS_ENSURE_ARG_POINTER(aControllerCreatorFn);
1035 NS_ENSURE_ARG_POINTER(aWindow);
1036 NS_ENSURE_ARG_POINTER(aContext);
1037 NS_ENSURE_ARG_POINTER(aControllerId);
1039 auto* piWindow = nsPIDOMWindowOuter::From(aWindow);
1040 MOZ_ASSERT(piWindow);
1042 nsCOMPtr<nsIControllers> controllers;
1043 nsresult rv = piWindow->GetControllers(getter_AddRefs(controllers));
1044 NS_ENSURE_SUCCESS(rv, rv);
1046 // We only have to create each singleton controller once
1047 // We know this has happened once we have a controllerId value
1048 if (!*aControllerId) {
1049 RefPtr<nsBaseCommandController> commandController = aControllerCreatorFn();
1050 NS_ENSURE_TRUE(commandController, NS_ERROR_FAILURE);
1052 // We must insert at head of the list to be sure our
1053 // controller is found before other implementations
1054 // (e.g., not-implemented versions by browser)
1055 rv = controllers->InsertControllerAt(0, commandController);
1056 NS_ENSURE_SUCCESS(rv, rv);
1058 // Remember the ID for the controller
1059 rv = controllers->GetControllerId(commandController, aControllerId);
1060 NS_ENSURE_SUCCESS(rv, rv);
1063 // Set the context
1064 return SetContextOnControllerById(controllers, aContext, *aControllerId);
1067 nsresult nsEditingSession::SetEditorOnControllers(nsPIDOMWindowOuter& aWindow,
1068 HTMLEditor* aEditor) {
1069 nsCOMPtr<nsIControllers> controllers;
1070 nsresult rv = aWindow.GetControllers(getter_AddRefs(controllers));
1071 NS_ENSURE_SUCCESS(rv, rv);
1073 nsCOMPtr<nsISupports> editorAsISupports = static_cast<nsIEditor*>(aEditor);
1074 if (mBaseCommandControllerId) {
1075 rv = SetContextOnControllerById(controllers, editorAsISupports,
1076 mBaseCommandControllerId);
1077 NS_ENSURE_SUCCESS(rv, rv);
1080 if (mDocStateControllerId) {
1081 rv = SetContextOnControllerById(controllers, editorAsISupports,
1082 mDocStateControllerId);
1083 NS_ENSURE_SUCCESS(rv, rv);
1086 if (mHTMLCommandControllerId) {
1087 rv = SetContextOnControllerById(controllers, editorAsISupports,
1088 mHTMLCommandControllerId);
1091 return rv;
1094 nsresult nsEditingSession::SetContextOnControllerById(
1095 nsIControllers* aControllers, nsISupports* aContext, uint32_t aID) {
1096 NS_ENSURE_ARG_POINTER(aControllers);
1098 // aContext can be null (when destroying editor)
1099 nsCOMPtr<nsIController> controller;
1100 aControllers->GetControllerById(aID, getter_AddRefs(controller));
1102 // ok with nil controller
1103 nsCOMPtr<nsIControllerContext> editorController =
1104 do_QueryInterface(controller);
1105 NS_ENSURE_TRUE(editorController, NS_ERROR_FAILURE);
1107 return editorController->SetCommandContext(aContext);
1110 void nsEditingSession::RemoveEditorControllers(nsPIDOMWindowOuter* aWindow) {
1111 // Remove editor controllers from the aWindow, call when we're
1112 // tearing down/detaching editor.
1114 nsCOMPtr<nsIControllers> controllers;
1115 if (aWindow) {
1116 aWindow->GetControllers(getter_AddRefs(controllers));
1119 if (controllers) {
1120 nsCOMPtr<nsIController> controller;
1121 if (mBaseCommandControllerId) {
1122 controllers->GetControllerById(mBaseCommandControllerId,
1123 getter_AddRefs(controller));
1124 if (controller) {
1125 controllers->RemoveController(controller);
1129 if (mDocStateControllerId) {
1130 controllers->GetControllerById(mDocStateControllerId,
1131 getter_AddRefs(controller));
1132 if (controller) {
1133 controllers->RemoveController(controller);
1137 if (mHTMLCommandControllerId) {
1138 controllers->GetControllerById(mHTMLCommandControllerId,
1139 getter_AddRefs(controller));
1140 if (controller) {
1141 controllers->RemoveController(controller);
1146 // Clear IDs to trigger creation of new controllers.
1147 mBaseCommandControllerId = 0;
1148 mDocStateControllerId = 0;
1149 mHTMLCommandControllerId = 0;
1152 void nsEditingSession::RemoveWebProgressListener(nsPIDOMWindowOuter* aWindow) {
1153 nsIDocShell* docShell = aWindow ? aWindow->GetDocShell() : nullptr;
1154 nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
1155 if (webProgress) {
1156 webProgress->RemoveProgressListener(this);
1157 mProgressListenerRegistered = false;
1161 void nsEditingSession::RestoreAnimationMode(nsPIDOMWindowOuter* aWindow) {
1162 if (mInteractive) {
1163 return;
1166 nsCOMPtr<nsIDocShell> docShell = aWindow ? aWindow->GetDocShell() : nullptr;
1167 NS_ENSURE_TRUE_VOID(docShell);
1168 RefPtr<PresShell> presShell = docShell->GetPresShell();
1169 if (NS_WARN_IF(!presShell)) {
1170 return;
1172 nsPresContext* presContext = presShell->GetPresContext();
1173 NS_ENSURE_TRUE_VOID(presContext);
1175 presContext->SetImageAnimationMode(mImageAnimationMode);
1178 nsresult nsEditingSession::DetachFromWindow(nsPIDOMWindowOuter* aWindow) {
1179 NS_ENSURE_TRUE(mDoneSetup, NS_OK);
1181 NS_ASSERTION(mComposerCommandsUpdater,
1182 "mComposerCommandsUpdater should exist.");
1184 // Kill any existing reload timer
1185 if (mLoadBlankDocTimer) {
1186 mLoadBlankDocTimer->Cancel();
1187 mLoadBlankDocTimer = nullptr;
1190 // Remove controllers, webprogress listener, and otherwise
1191 // make things the way they were before we started editing.
1192 RemoveEditorControllers(aWindow);
1193 RemoveWebProgressListener(aWindow);
1194 RestoreJSAndPlugins(aWindow->GetCurrentInnerWindow());
1195 RestoreAnimationMode(aWindow);
1197 // Kill our weak reference to our original window, in case
1198 // it changes on restore, or otherwise dies.
1199 mDocShell = nullptr;
1201 return NS_OK;
1204 nsresult nsEditingSession::ReattachToWindow(nsPIDOMWindowOuter* aWindow) {
1205 NS_ENSURE_TRUE(mDoneSetup, NS_OK);
1206 NS_ENSURE_TRUE(aWindow, NS_ERROR_FAILURE);
1208 NS_ASSERTION(mComposerCommandsUpdater,
1209 "mComposerCommandsUpdater should exist.");
1211 // Imitate nsEditorDocShell::MakeEditable() to reattach the
1212 // old editor to the window.
1213 nsresult rv;
1215 nsIDocShell* docShell = aWindow->GetDocShell();
1216 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
1217 mDocShell = do_GetWeakReference(docShell);
1219 // Disable plugins.
1220 if (!mInteractive) {
1221 rv = DisableJSAndPlugins(aWindow->GetCurrentInnerWindow());
1222 NS_ENSURE_SUCCESS(rv, rv);
1225 // Tells embedder that startup is in progress.
1226 mEditorStatus = eEditorCreationInProgress;
1228 // Adds back web progress listener.
1229 rv = PrepareForEditing(aWindow);
1230 NS_ENSURE_SUCCESS(rv, rv);
1232 // Setup the command controllers again.
1233 rv = SetupEditorCommandController(
1234 nsBaseCommandController::CreateEditingController, aWindow,
1235 static_cast<nsIEditingSession*>(this), &mBaseCommandControllerId);
1236 NS_ENSURE_SUCCESS(rv, rv);
1238 rv = SetupEditorCommandController(
1239 nsBaseCommandController::CreateHTMLEditorDocStateController, aWindow,
1240 static_cast<nsIEditingSession*>(this), &mDocStateControllerId);
1241 NS_ENSURE_SUCCESS(rv, rv);
1243 if (mComposerCommandsUpdater) {
1244 mComposerCommandsUpdater->Init(*aWindow);
1247 // Get editor
1248 RefPtr<HTMLEditor> htmlEditor = GetHTMLEditorForWindow(aWindow);
1249 if (NS_WARN_IF(!htmlEditor)) {
1250 return NS_ERROR_FAILURE;
1253 if (!mInteractive) {
1254 // Disable animation of images in this document:
1255 RefPtr<PresShell> presShell = docShell->GetPresShell();
1256 if (NS_WARN_IF(!presShell)) {
1257 return NS_ERROR_FAILURE;
1259 nsPresContext* presContext = presShell->GetPresContext();
1260 NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
1262 mImageAnimationMode = presContext->ImageAnimationMode();
1263 presContext->SetImageAnimationMode(imgIContainer::kDontAnimMode);
1266 // The third controller takes an nsIEditor as the context
1267 rv = SetupEditorCommandController(
1268 nsBaseCommandController::CreateHTMLEditorController, aWindow,
1269 static_cast<nsIEditor*>(htmlEditor.get()), &mHTMLCommandControllerId);
1270 NS_ENSURE_SUCCESS(rv, rv);
1272 // Set context on all controllers to be the editor
1273 rv = SetEditorOnControllers(*aWindow, htmlEditor);
1274 NS_ENSURE_SUCCESS(rv, rv);
1276 #ifdef DEBUG
1278 bool isEditable;
1279 rv = WindowIsEditable(aWindow, &isEditable);
1280 NS_ENSURE_SUCCESS(rv, rv);
1281 NS_ASSERTION(isEditable,
1282 "Window is not editable after reattaching editor.");
1284 #endif // DEBUG
1286 return NS_OK;
1289 HTMLEditor* nsIEditingSession::GetHTMLEditorForWindow(
1290 mozIDOMWindowProxy* aWindow) {
1291 if (NS_WARN_IF(!aWindow)) {
1292 return nullptr;
1295 nsCOMPtr<nsIDocShell> docShell =
1296 nsPIDOMWindowOuter::From(aWindow)->GetDocShell();
1297 if (NS_WARN_IF(!docShell)) {
1298 return nullptr;
1301 return docShell->GetHTMLEditor();