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 }