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