1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/editor/composer/src/nsEditingSession.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1421 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 sw=2 et tw=78: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include <string.h> // for nullptr, strcmp 1.11 + 1.12 +#include "imgIContainer.h" // for imgIContainer, etc 1.13 +#include "mozFlushType.h" // for mozFlushType::Flush_Frames 1.14 +#include "mozilla/mozalloc.h" // for operator new 1.15 +#include "nsAString.h" 1.16 +#include "nsComponentManagerUtils.h" // for do_CreateInstance 1.17 +#include "nsComposerCommandsUpdater.h" // for nsComposerCommandsUpdater 1.18 +#include "nsDebug.h" // for NS_ENSURE_SUCCESS, etc 1.19 +#include "nsEditingSession.h" 1.20 +#include "nsError.h" // for NS_ERROR_FAILURE, NS_OK, etc 1.21 +#include "nsIChannel.h" // for nsIChannel 1.22 +#include "nsICommandManager.h" // for nsICommandManager 1.23 +#include "nsIContentViewer.h" // for nsIContentViewer 1.24 +#include "nsIController.h" // for nsIController 1.25 +#include "nsIControllerContext.h" // for nsIControllerContext 1.26 +#include "nsIControllers.h" // for nsIControllers 1.27 +#include "nsID.h" // for NS_GET_IID, etc 1.28 +#include "nsIDOMDocument.h" // for nsIDOMDocument 1.29 +#include "nsIDOMHTMLDocument.h" // for nsIDOMHTMLDocument 1.30 +#include "nsIDOMWindow.h" // for nsIDOMWindow 1.31 +#include "nsIDOMWindowUtils.h" // for nsIDOMWindowUtils 1.32 +#include "nsIDocShell.h" // for nsIDocShell 1.33 +#include "nsIDocument.h" // for nsIDocument 1.34 +#include "nsIDocumentStateListener.h" 1.35 +#include "nsIEditor.h" // for nsIEditor 1.36 +#include "nsIHTMLDocument.h" // for nsIHTMLDocument, etc 1.37 +#include "nsIInterfaceRequestorUtils.h" // for do_GetInterface 1.38 +#include "nsIPlaintextEditor.h" // for nsIPlaintextEditor, etc 1.39 +#include "nsIRefreshURI.h" // for nsIRefreshURI 1.40 +#include "nsIRequest.h" // for nsIRequest 1.41 +#include "nsISelection.h" // for nsISelection 1.42 +#include "nsISelectionPrivate.h" // for nsISelectionPrivate 1.43 +#include "nsITimer.h" // for nsITimer, etc 1.44 +#include "nsITransactionManager.h" // for nsITransactionManager 1.45 +#include "nsIWeakReference.h" // for nsISupportsWeakReference, etc 1.46 +#include "nsIWebNavigation.h" // for nsIWebNavigation 1.47 +#include "nsIWebProgress.h" // for nsIWebProgress, etc 1.48 +#include "nsLiteralString.h" // for NS_LITERAL_STRING 1.49 +#include "nsPICommandUpdater.h" // for nsPICommandUpdater 1.50 +#include "nsPIDOMWindow.h" // for nsPIDOMWindow 1.51 +#include "nsReadableUtils.h" // for AppendUTF16toUTF8 1.52 +#include "nsStringFwd.h" // for nsAFlatString 1.53 + 1.54 +class nsISupports; 1.55 +class nsIURI; 1.56 + 1.57 +/*--------------------------------------------------------------------------- 1.58 + 1.59 + nsEditingSession 1.60 + 1.61 +----------------------------------------------------------------------------*/ 1.62 +nsEditingSession::nsEditingSession() 1.63 +: mDoneSetup(false) 1.64 +, mCanCreateEditor(false) 1.65 +, mInteractive(false) 1.66 +, mMakeWholeDocumentEditable(true) 1.67 +, mDisabledJSAndPlugins(false) 1.68 +, mScriptsEnabled(true) 1.69 +, mPluginsEnabled(true) 1.70 +, mProgressListenerRegistered(false) 1.71 +, mImageAnimationMode(0) 1.72 +, mEditorFlags(0) 1.73 +, mEditorStatus(eEditorOK) 1.74 +, mBaseCommandControllerId(0) 1.75 +, mDocStateControllerId(0) 1.76 +, mHTMLCommandControllerId(0) 1.77 +{ 1.78 +} 1.79 + 1.80 +/*--------------------------------------------------------------------------- 1.81 + 1.82 + ~nsEditingSession 1.83 + 1.84 +----------------------------------------------------------------------------*/ 1.85 +nsEditingSession::~nsEditingSession() 1.86 +{ 1.87 + // Must cancel previous timer? 1.88 + if (mLoadBlankDocTimer) 1.89 + mLoadBlankDocTimer->Cancel(); 1.90 +} 1.91 + 1.92 +NS_IMPL_ISUPPORTS(nsEditingSession, nsIEditingSession, nsIWebProgressListener, 1.93 + nsISupportsWeakReference) 1.94 + 1.95 +/*--------------------------------------------------------------------------- 1.96 + 1.97 + MakeWindowEditable 1.98 + 1.99 + aEditorType string, "html" "htmlsimple" "text" "textsimple" 1.100 + void makeWindowEditable(in nsIDOMWindow aWindow, in string aEditorType, 1.101 + in boolean aDoAfterUriLoad, 1.102 + in boolean aMakeWholeDocumentEditable, 1.103 + in boolean aInteractive); 1.104 +----------------------------------------------------------------------------*/ 1.105 +#define DEFAULT_EDITOR_TYPE "html" 1.106 + 1.107 +NS_IMETHODIMP 1.108 +nsEditingSession::MakeWindowEditable(nsIDOMWindow *aWindow, 1.109 + const char *aEditorType, 1.110 + bool aDoAfterUriLoad, 1.111 + bool aMakeWholeDocumentEditable, 1.112 + bool aInteractive) 1.113 +{ 1.114 + mEditorType.Truncate(); 1.115 + mEditorFlags = 0; 1.116 + 1.117 + // disable plugins 1.118 + nsCOMPtr<nsIDocShell> docShell = GetDocShellFromWindow(aWindow); 1.119 + NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); 1.120 + 1.121 + mDocShell = do_GetWeakReference(docShell); 1.122 + mInteractive = aInteractive; 1.123 + mMakeWholeDocumentEditable = aMakeWholeDocumentEditable; 1.124 + 1.125 + nsresult rv; 1.126 + if (!mInteractive) { 1.127 + rv = DisableJSAndPlugins(aWindow); 1.128 + NS_ENSURE_SUCCESS(rv, rv); 1.129 + } 1.130 + 1.131 + // Always remove existing editor 1.132 + TearDownEditorOnWindow(aWindow); 1.133 + 1.134 + // Tells embedder that startup is in progress 1.135 + mEditorStatus = eEditorCreationInProgress; 1.136 + 1.137 + //temporary to set editor type here. we will need different classes soon. 1.138 + if (!aEditorType) 1.139 + aEditorType = DEFAULT_EDITOR_TYPE; 1.140 + mEditorType = aEditorType; 1.141 + 1.142 + // if all this does is setup listeners and I don't need listeners, 1.143 + // can't this step be ignored?? (based on aDoAfterURILoad) 1.144 + rv = PrepareForEditing(aWindow); 1.145 + NS_ENSURE_SUCCESS(rv, rv); 1.146 + 1.147 + // set the flag on the docShell to say that it's editable 1.148 + rv = docShell->MakeEditable(aDoAfterUriLoad); 1.149 + NS_ENSURE_SUCCESS(rv, rv); 1.150 + 1.151 + // Setup commands common to plaintext and html editors, 1.152 + // including the document creation observers 1.153 + // the first is an editing controller 1.154 + rv = SetupEditorCommandController("@mozilla.org/editor/editingcontroller;1", 1.155 + aWindow, 1.156 + static_cast<nsIEditingSession*>(this), 1.157 + &mBaseCommandControllerId); 1.158 + NS_ENSURE_SUCCESS(rv, rv); 1.159 + 1.160 + // The second is a controller to monitor doc state, 1.161 + // such as creation and "dirty flag" 1.162 + rv = SetupEditorCommandController("@mozilla.org/editor/editordocstatecontroller;1", 1.163 + aWindow, 1.164 + static_cast<nsIEditingSession*>(this), 1.165 + &mDocStateControllerId); 1.166 + NS_ENSURE_SUCCESS(rv, rv); 1.167 + 1.168 + // aDoAfterUriLoad can be false only when making an existing window editable 1.169 + if (!aDoAfterUriLoad) 1.170 + { 1.171 + rv = SetupEditorOnWindow(aWindow); 1.172 + 1.173 + // mEditorStatus is set to the error reason 1.174 + // Since this is used only when editing an existing page, 1.175 + // it IS ok to destroy current editor 1.176 + if (NS_FAILED(rv)) 1.177 + TearDownEditorOnWindow(aWindow); 1.178 + } 1.179 + return rv; 1.180 +} 1.181 + 1.182 +NS_IMETHODIMP 1.183 +nsEditingSession::DisableJSAndPlugins(nsIDOMWindow *aWindow) 1.184 +{ 1.185 + nsIDocShell *docShell = GetDocShellFromWindow(aWindow); 1.186 + NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); 1.187 + 1.188 + bool tmp; 1.189 + nsresult rv = docShell->GetAllowJavascript(&tmp); 1.190 + NS_ENSURE_SUCCESS(rv, rv); 1.191 + 1.192 + mScriptsEnabled = tmp; 1.193 + 1.194 + rv = docShell->SetAllowJavascript(false); 1.195 + NS_ENSURE_SUCCESS(rv, rv); 1.196 + 1.197 + // Disable plugins in this document: 1.198 + mPluginsEnabled = docShell->PluginsAllowedInCurrentDoc(); 1.199 + 1.200 + rv = docShell->SetAllowPlugins(false); 1.201 + NS_ENSURE_SUCCESS(rv, rv); 1.202 + 1.203 + mDisabledJSAndPlugins = true; 1.204 + 1.205 + return NS_OK; 1.206 +} 1.207 + 1.208 +NS_IMETHODIMP 1.209 +nsEditingSession::RestoreJSAndPlugins(nsIDOMWindow *aWindow) 1.210 +{ 1.211 + NS_ENSURE_TRUE(mDisabledJSAndPlugins, NS_OK); 1.212 + 1.213 + mDisabledJSAndPlugins = false; 1.214 + 1.215 + nsIDocShell *docShell = GetDocShellFromWindow(aWindow); 1.216 + NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); 1.217 + 1.218 + nsresult rv = docShell->SetAllowJavascript(mScriptsEnabled); 1.219 + NS_ENSURE_SUCCESS(rv, rv); 1.220 + 1.221 + // Disable plugins in this document: 1.222 + return docShell->SetAllowPlugins(mPluginsEnabled); 1.223 +} 1.224 + 1.225 +NS_IMETHODIMP 1.226 +nsEditingSession::GetJsAndPluginsDisabled(bool *aResult) 1.227 +{ 1.228 + NS_ENSURE_ARG_POINTER(aResult); 1.229 + *aResult = mDisabledJSAndPlugins; 1.230 + return NS_OK; 1.231 +} 1.232 + 1.233 +/*--------------------------------------------------------------------------- 1.234 + 1.235 + WindowIsEditable 1.236 + 1.237 + boolean windowIsEditable (in nsIDOMWindow aWindow); 1.238 +----------------------------------------------------------------------------*/ 1.239 +NS_IMETHODIMP 1.240 +nsEditingSession::WindowIsEditable(nsIDOMWindow *aWindow, bool *outIsEditable) 1.241 +{ 1.242 + nsCOMPtr<nsIDocShell> docShell = GetDocShellFromWindow(aWindow); 1.243 + NS_ENSURE_STATE(docShell); 1.244 + 1.245 + return docShell->GetEditable(outIsEditable); 1.246 +} 1.247 + 1.248 + 1.249 +// These are MIME types that are automatically parsed as "text/plain" 1.250 +// and thus we can edit them as plaintext 1.251 +// Note: in older versions, we attempted to convert the mimetype of 1.252 +// the network channel for these and "text/xml" to "text/plain", 1.253 +// but further investigation reveals that strategy doesn't work 1.254 +const char* const gSupportedTextTypes[] = { 1.255 + "text/plain", 1.256 + "text/css", 1.257 + "text/rdf", 1.258 + "text/xsl", 1.259 + "text/javascript", // obsolete type 1.260 + "text/ecmascript", // obsolete type 1.261 + "application/javascript", 1.262 + "application/ecmascript", 1.263 + "application/x-javascript", // obsolete type 1.264 + "text/xul", // obsolete type 1.265 + "application/vnd.mozilla.xul+xml", 1.266 + nullptr // IMPORTANT! Null must be at end 1.267 +}; 1.268 + 1.269 +bool 1.270 +IsSupportedTextType(const char* aMIMEType) 1.271 +{ 1.272 + NS_ENSURE_TRUE(aMIMEType, false); 1.273 + 1.274 + int32_t i = 0; 1.275 + while (gSupportedTextTypes[i]) 1.276 + { 1.277 + if (strcmp(gSupportedTextTypes[i], aMIMEType) == 0) 1.278 + { 1.279 + return true; 1.280 + } 1.281 + 1.282 + i ++; 1.283 + } 1.284 + 1.285 + return false; 1.286 +} 1.287 + 1.288 +/*--------------------------------------------------------------------------- 1.289 + 1.290 + SetupEditorOnWindow 1.291 + 1.292 + nsIEditor setupEditorOnWindow (in nsIDOMWindow aWindow); 1.293 +----------------------------------------------------------------------------*/ 1.294 +NS_IMETHODIMP 1.295 +nsEditingSession::SetupEditorOnWindow(nsIDOMWindow *aWindow) 1.296 +{ 1.297 + mDoneSetup = true; 1.298 + 1.299 + nsresult rv; 1.300 + 1.301 + //MIME CHECKING 1.302 + //must get the content type 1.303 + // Note: the doc gets this from the network channel during StartPageLoad, 1.304 + // so we don't have to get it from there ourselves 1.305 + nsCOMPtr<nsIDOMDocument> doc; 1.306 + nsAutoCString mimeCType; 1.307 + 1.308 + //then lets check the mime type 1.309 + if (NS_SUCCEEDED(aWindow->GetDocument(getter_AddRefs(doc))) && doc) 1.310 + { 1.311 + nsAutoString mimeType; 1.312 + if (NS_SUCCEEDED(doc->GetContentType(mimeType))) 1.313 + AppendUTF16toUTF8(mimeType, mimeCType); 1.314 + 1.315 + if (IsSupportedTextType(mimeCType.get())) 1.316 + { 1.317 + mEditorType.AssignLiteral("text"); 1.318 + mimeCType = "text/plain"; 1.319 + } 1.320 + else if (!mimeCType.EqualsLiteral("text/html") && 1.321 + !mimeCType.EqualsLiteral("application/xhtml+xml")) 1.322 + { 1.323 + // Neither an acceptable text or html type. 1.324 + mEditorStatus = eEditorErrorCantEditMimeType; 1.325 + 1.326 + // Turn editor into HTML -- we will load blank page later 1.327 + mEditorType.AssignLiteral("html"); 1.328 + mimeCType.AssignLiteral("text/html"); 1.329 + } 1.330 + 1.331 + // Flush out frame construction to make sure that the subframe's 1.332 + // presshell is set up if it needs to be. 1.333 + nsCOMPtr<nsIDocument> document = do_QueryInterface(doc); 1.334 + if (document) { 1.335 + document->FlushPendingNotifications(Flush_Frames); 1.336 + if (mMakeWholeDocumentEditable) { 1.337 + document->SetEditableFlag(true); 1.338 + nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(document); 1.339 + if (htmlDocument) { 1.340 + // Enable usage of the execCommand API 1.341 + htmlDocument->SetEditingState(nsIHTMLDocument::eDesignMode); 1.342 + } 1.343 + } 1.344 + } 1.345 + } 1.346 + bool needHTMLController = false; 1.347 + 1.348 + const char *classString = "@mozilla.org/editor/htmleditor;1"; 1.349 + if (mEditorType.EqualsLiteral("textmail")) 1.350 + { 1.351 + mEditorFlags = nsIPlaintextEditor::eEditorPlaintextMask | 1.352 + nsIPlaintextEditor::eEditorEnableWrapHackMask | 1.353 + nsIPlaintextEditor::eEditorMailMask; 1.354 + } 1.355 + else if (mEditorType.EqualsLiteral("text")) 1.356 + { 1.357 + mEditorFlags = nsIPlaintextEditor::eEditorPlaintextMask | 1.358 + nsIPlaintextEditor::eEditorEnableWrapHackMask; 1.359 + } 1.360 + else if (mEditorType.EqualsLiteral("htmlmail")) 1.361 + { 1.362 + if (mimeCType.EqualsLiteral("text/html")) 1.363 + { 1.364 + needHTMLController = true; 1.365 + mEditorFlags = nsIPlaintextEditor::eEditorMailMask; 1.366 + } 1.367 + else //set the flags back to textplain. 1.368 + mEditorFlags = nsIPlaintextEditor::eEditorPlaintextMask | 1.369 + nsIPlaintextEditor::eEditorEnableWrapHackMask; 1.370 + } 1.371 + else // Defaulted to html 1.372 + { 1.373 + needHTMLController = true; 1.374 + } 1.375 + 1.376 + if (mInteractive) { 1.377 + mEditorFlags |= nsIPlaintextEditor::eEditorAllowInteraction; 1.378 + } 1.379 + 1.380 + // make the UI state maintainer 1.381 + mStateMaintainer = new nsComposerCommandsUpdater(); 1.382 + 1.383 + // now init the state maintainer 1.384 + // This allows notification of error state 1.385 + // even if we don't create an editor 1.386 + rv = mStateMaintainer->Init(aWindow); 1.387 + NS_ENSURE_SUCCESS(rv, rv); 1.388 + 1.389 + if (mEditorStatus != eEditorCreationInProgress) 1.390 + { 1.391 + mStateMaintainer->NotifyDocumentCreated(); 1.392 + return NS_ERROR_FAILURE; 1.393 + } 1.394 + 1.395 + // Create editor and do other things 1.396 + // only if we haven't found some error above, 1.397 + nsCOMPtr<nsIDocShell> docShell = GetDocShellFromWindow(aWindow); 1.398 + NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); 1.399 + 1.400 + if (!mInteractive) { 1.401 + // Disable animation of images in this document: 1.402 + nsCOMPtr<nsIDOMWindowUtils> utils(do_GetInterface(aWindow)); 1.403 + NS_ENSURE_TRUE(utils, NS_ERROR_FAILURE); 1.404 + 1.405 + rv = utils->GetImageAnimationMode(&mImageAnimationMode); 1.406 + NS_ENSURE_SUCCESS(rv, rv); 1.407 + utils->SetImageAnimationMode(imgIContainer::kDontAnimMode); 1.408 + } 1.409 + 1.410 + // create and set editor 1.411 + // Try to reuse an existing editor 1.412 + nsCOMPtr<nsIEditor> editor = do_QueryReferent(mExistingEditor); 1.413 + if (editor) { 1.414 + editor->PreDestroy(false); 1.415 + } else { 1.416 + editor = do_CreateInstance(classString, &rv); 1.417 + NS_ENSURE_SUCCESS(rv, rv); 1.418 + mExistingEditor = do_GetWeakReference(editor); 1.419 + } 1.420 + // set the editor on the docShell. The docShell now owns it. 1.421 + rv = docShell->SetEditor(editor); 1.422 + NS_ENSURE_SUCCESS(rv, rv); 1.423 + 1.424 + // setup the HTML editor command controller 1.425 + if (needHTMLController) 1.426 + { 1.427 + // The third controller takes an nsIEditor as the context 1.428 + rv = SetupEditorCommandController("@mozilla.org/editor/htmleditorcontroller;1", 1.429 + aWindow, editor, 1.430 + &mHTMLCommandControllerId); 1.431 + NS_ENSURE_SUCCESS(rv, rv); 1.432 + } 1.433 + 1.434 + // Set mimetype on editor 1.435 + rv = editor->SetContentsMIMEType(mimeCType.get()); 1.436 + NS_ENSURE_SUCCESS(rv, rv); 1.437 + 1.438 + nsCOMPtr<nsIContentViewer> contentViewer; 1.439 + rv = docShell->GetContentViewer(getter_AddRefs(contentViewer)); 1.440 + NS_ENSURE_SUCCESS(rv, rv); 1.441 + NS_ENSURE_TRUE(contentViewer, NS_ERROR_FAILURE); 1.442 + 1.443 + nsCOMPtr<nsIDOMDocument> domDoc; 1.444 + rv = contentViewer->GetDOMDocument(getter_AddRefs(domDoc)); 1.445 + NS_ENSURE_SUCCESS(rv, rv); 1.446 + NS_ENSURE_TRUE(domDoc, NS_ERROR_FAILURE); 1.447 + 1.448 + // Set up as a doc state listener 1.449 + // Important! We must have this to broadcast the "obs_documentCreated" message 1.450 + rv = editor->AddDocumentStateListener(mStateMaintainer); 1.451 + NS_ENSURE_SUCCESS(rv, rv); 1.452 + 1.453 + rv = editor->Init(domDoc, nullptr /* root content */, 1.454 + nullptr, mEditorFlags, EmptyString()); 1.455 + NS_ENSURE_SUCCESS(rv, rv); 1.456 + 1.457 + nsCOMPtr<nsISelection> selection; 1.458 + editor->GetSelection(getter_AddRefs(selection)); 1.459 + nsCOMPtr<nsISelectionPrivate> selPriv = do_QueryInterface(selection); 1.460 + NS_ENSURE_TRUE(selPriv, NS_ERROR_FAILURE); 1.461 + 1.462 + rv = selPriv->AddSelectionListener(mStateMaintainer); 1.463 + NS_ENSURE_SUCCESS(rv, rv); 1.464 + 1.465 + // and as a transaction listener 1.466 + nsCOMPtr<nsITransactionManager> txnMgr; 1.467 + editor->GetTransactionManager(getter_AddRefs(txnMgr)); 1.468 + if (txnMgr) 1.469 + txnMgr->AddListener(mStateMaintainer); 1.470 + 1.471 + // Set context on all controllers to be the editor 1.472 + rv = SetEditorOnControllers(aWindow, editor); 1.473 + NS_ENSURE_SUCCESS(rv, rv); 1.474 + 1.475 + // Everything went fine! 1.476 + mEditorStatus = eEditorOK; 1.477 + 1.478 + // This will trigger documentCreation notification 1.479 + return editor->PostCreate(); 1.480 +} 1.481 + 1.482 +// Removes all listeners and controllers from aWindow and aEditor. 1.483 +void 1.484 +nsEditingSession::RemoveListenersAndControllers(nsIDOMWindow *aWindow, 1.485 + nsIEditor *aEditor) 1.486 +{ 1.487 + if (!mStateMaintainer || !aEditor) 1.488 + return; 1.489 + 1.490 + // Remove all the listeners 1.491 + nsCOMPtr<nsISelection> selection; 1.492 + aEditor->GetSelection(getter_AddRefs(selection)); 1.493 + nsCOMPtr<nsISelectionPrivate> selPriv = do_QueryInterface(selection); 1.494 + if (selPriv) 1.495 + selPriv->RemoveSelectionListener(mStateMaintainer); 1.496 + 1.497 + aEditor->RemoveDocumentStateListener(mStateMaintainer); 1.498 + 1.499 + nsCOMPtr<nsITransactionManager> txnMgr; 1.500 + aEditor->GetTransactionManager(getter_AddRefs(txnMgr)); 1.501 + if (txnMgr) 1.502 + txnMgr->RemoveListener(mStateMaintainer); 1.503 + 1.504 + // Remove editor controllers from the window now that we're not 1.505 + // editing in that window any more. 1.506 + RemoveEditorControllers(aWindow); 1.507 +} 1.508 + 1.509 +/*--------------------------------------------------------------------------- 1.510 + 1.511 + TearDownEditorOnWindow 1.512 + 1.513 + void tearDownEditorOnWindow (in nsIDOMWindow aWindow); 1.514 +----------------------------------------------------------------------------*/ 1.515 +NS_IMETHODIMP 1.516 +nsEditingSession::TearDownEditorOnWindow(nsIDOMWindow *aWindow) 1.517 +{ 1.518 + if (!mDoneSetup) { 1.519 + return NS_OK; 1.520 + } 1.521 + 1.522 + NS_ENSURE_TRUE(aWindow, NS_ERROR_NULL_POINTER); 1.523 + 1.524 + nsresult rv; 1.525 + 1.526 + // Kill any existing reload timer 1.527 + if (mLoadBlankDocTimer) 1.528 + { 1.529 + mLoadBlankDocTimer->Cancel(); 1.530 + mLoadBlankDocTimer = nullptr; 1.531 + } 1.532 + 1.533 + mDoneSetup = false; 1.534 + 1.535 + // Check if we're turning off editing (from contentEditable or designMode). 1.536 + nsCOMPtr<nsIDOMDocument> domDoc; 1.537 + aWindow->GetDocument(getter_AddRefs(domDoc)); 1.538 + nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(domDoc); 1.539 + bool stopEditing = htmlDoc && htmlDoc->IsEditingOn(); 1.540 + if (stopEditing) 1.541 + RemoveWebProgressListener(aWindow); 1.542 + 1.543 + nsCOMPtr<nsIDocShell> docShell = GetDocShellFromWindow(aWindow); 1.544 + NS_ENSURE_STATE(docShell); 1.545 + 1.546 + nsCOMPtr<nsIEditor> editor; 1.547 + rv = docShell->GetEditor(getter_AddRefs(editor)); 1.548 + NS_ENSURE_SUCCESS(rv, rv); 1.549 + 1.550 + if (stopEditing) 1.551 + htmlDoc->TearingDownEditor(editor); 1.552 + 1.553 + if (mStateMaintainer && editor) 1.554 + { 1.555 + // Null out the editor on the controllers first to prevent their weak 1.556 + // references from pointing to a destroyed editor. 1.557 + SetEditorOnControllers(aWindow, nullptr); 1.558 + } 1.559 + 1.560 + // Null out the editor on the docShell to trigger PreDestroy which 1.561 + // needs to happen before document state listeners are removed below. 1.562 + docShell->SetEditor(nullptr); 1.563 + 1.564 + RemoveListenersAndControllers(aWindow, editor); 1.565 + 1.566 + if (stopEditing) 1.567 + { 1.568 + // Make things the way they were before we started editing. 1.569 + RestoreJSAndPlugins(aWindow); 1.570 + RestoreAnimationMode(aWindow); 1.571 + 1.572 + if (mMakeWholeDocumentEditable) 1.573 + { 1.574 + nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc, &rv); 1.575 + NS_ENSURE_SUCCESS(rv, rv); 1.576 + 1.577 + doc->SetEditableFlag(false); 1.578 + nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(doc); 1.579 + if (htmlDocument) { 1.580 + htmlDocument->SetEditingState(nsIHTMLDocument::eOff); 1.581 + } 1.582 + } 1.583 + } 1.584 + 1.585 + return rv; 1.586 +} 1.587 + 1.588 +/*--------------------------------------------------------------------------- 1.589 + 1.590 + GetEditorForFrame 1.591 + 1.592 + nsIEditor getEditorForFrame (in nsIDOMWindow aWindow); 1.593 +----------------------------------------------------------------------------*/ 1.594 +NS_IMETHODIMP 1.595 +nsEditingSession::GetEditorForWindow(nsIDOMWindow *aWindow, 1.596 + nsIEditor **outEditor) 1.597 +{ 1.598 + nsCOMPtr<nsIDocShell> docShell = GetDocShellFromWindow(aWindow); 1.599 + NS_ENSURE_STATE(aWindow); 1.600 + 1.601 + return docShell->GetEditor(outEditor); 1.602 +} 1.603 + 1.604 +/*--------------------------------------------------------------------------- 1.605 + 1.606 + OnStateChange 1.607 + 1.608 +----------------------------------------------------------------------------*/ 1.609 +NS_IMETHODIMP 1.610 +nsEditingSession::OnStateChange(nsIWebProgress *aWebProgress, 1.611 + nsIRequest *aRequest, 1.612 + uint32_t aStateFlags, nsresult aStatus) 1.613 +{ 1.614 + 1.615 +#ifdef NOISY_DOC_LOADING 1.616 + nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest)); 1.617 + if (channel) 1.618 + { 1.619 + nsAutoCString contentType; 1.620 + channel->GetContentType(contentType); 1.621 + if (!contentType.IsEmpty()) 1.622 + printf(" ++++++ MIMETYPE = %s\n", contentType.get()); 1.623 + } 1.624 +#endif 1.625 + 1.626 + // 1.627 + // A Request has started... 1.628 + // 1.629 + if (aStateFlags & nsIWebProgressListener::STATE_START) 1.630 + { 1.631 +#ifdef NOISY_DOC_LOADING 1.632 + { 1.633 + nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest)); 1.634 + if (channel) 1.635 + { 1.636 + nsCOMPtr<nsIURI> uri; 1.637 + channel->GetURI(getter_AddRefs(uri)); 1.638 + if (uri) 1.639 + { 1.640 + nsXPIDLCString spec; 1.641 + uri->GetSpec(spec); 1.642 + printf(" **** STATE_START: CHANNEL URI=%s, flags=%x\n", 1.643 + spec.get(), aStateFlags); 1.644 + } 1.645 + } 1.646 + else 1.647 + printf(" STATE_START: NO CHANNEL flags=%x\n", aStateFlags); 1.648 + } 1.649 +#endif 1.650 + // Page level notification... 1.651 + if (aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK) 1.652 + { 1.653 + nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest)); 1.654 + StartPageLoad(channel); 1.655 +#ifdef NOISY_DOC_LOADING 1.656 + printf("STATE_START & STATE_IS_NETWORK flags=%x\n", aStateFlags); 1.657 +#endif 1.658 + } 1.659 + 1.660 + // Document level notification... 1.661 + if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT && 1.662 + !(aStateFlags & nsIWebProgressListener::STATE_RESTORING)) { 1.663 +#ifdef NOISY_DOC_LOADING 1.664 + printf("STATE_START & STATE_IS_DOCUMENT flags=%x\n", aStateFlags); 1.665 +#endif 1.666 + 1.667 + bool progressIsForTargetDocument = 1.668 + IsProgressForTargetDocument(aWebProgress); 1.669 + 1.670 + if (progressIsForTargetDocument) 1.671 + { 1.672 + nsCOMPtr<nsIDOMWindow> window; 1.673 + aWebProgress->GetDOMWindow(getter_AddRefs(window)); 1.674 + 1.675 + nsCOMPtr<nsIDOMDocument> doc; 1.676 + window->GetDocument(getter_AddRefs(doc)); 1.677 + 1.678 + nsCOMPtr<nsIHTMLDocument> htmlDoc(do_QueryInterface(doc)); 1.679 + 1.680 + if (htmlDoc && htmlDoc->IsWriting()) 1.681 + { 1.682 + nsCOMPtr<nsIDOMHTMLDocument> htmlDomDoc = do_QueryInterface(doc); 1.683 + nsAutoString designMode; 1.684 + htmlDomDoc->GetDesignMode(designMode); 1.685 + 1.686 + if (designMode.EqualsLiteral("on")) 1.687 + { 1.688 + // This notification is for data coming in through 1.689 + // document.open/write/close(), ignore it. 1.690 + 1.691 + return NS_OK; 1.692 + } 1.693 + } 1.694 + 1.695 + mCanCreateEditor = true; 1.696 + StartDocumentLoad(aWebProgress, progressIsForTargetDocument); 1.697 + } 1.698 + } 1.699 + } 1.700 + // 1.701 + // A Request is being processed 1.702 + // 1.703 + else if (aStateFlags & nsIWebProgressListener::STATE_TRANSFERRING) 1.704 + { 1.705 + if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT) 1.706 + { 1.707 + // document transfer started 1.708 + } 1.709 + } 1.710 + // 1.711 + // Got a redirection 1.712 + // 1.713 + else if (aStateFlags & nsIWebProgressListener::STATE_REDIRECTING) 1.714 + { 1.715 + if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT) 1.716 + { 1.717 + // got a redirect 1.718 + } 1.719 + } 1.720 + // 1.721 + // A network or document Request has finished... 1.722 + // 1.723 + else if (aStateFlags & nsIWebProgressListener::STATE_STOP) 1.724 + { 1.725 + 1.726 +#ifdef NOISY_DOC_LOADING 1.727 + { 1.728 + nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest)); 1.729 + if (channel) 1.730 + { 1.731 + nsCOMPtr<nsIURI> uri; 1.732 + channel->GetURI(getter_AddRefs(uri)); 1.733 + if (uri) 1.734 + { 1.735 + nsXPIDLCString spec; 1.736 + uri->GetSpec(spec); 1.737 + printf(" **** STATE_STOP: CHANNEL URI=%s, flags=%x\n", 1.738 + spec.get(), aStateFlags); 1.739 + } 1.740 + } 1.741 + else 1.742 + printf(" STATE_STOP: NO CHANNEL flags=%x\n", aStateFlags); 1.743 + } 1.744 +#endif 1.745 + 1.746 + // Document level notification... 1.747 + if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT) 1.748 + { 1.749 + nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest); 1.750 + EndDocumentLoad(aWebProgress, channel, aStatus, 1.751 + IsProgressForTargetDocument(aWebProgress)); 1.752 +#ifdef NOISY_DOC_LOADING 1.753 + printf("STATE_STOP & STATE_IS_DOCUMENT flags=%x\n", aStateFlags); 1.754 +#endif 1.755 + } 1.756 + 1.757 + // Page level notification... 1.758 + if (aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK) 1.759 + { 1.760 + nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest); 1.761 + (void)EndPageLoad(aWebProgress, channel, aStatus); 1.762 +#ifdef NOISY_DOC_LOADING 1.763 + printf("STATE_STOP & STATE_IS_NETWORK flags=%x\n", aStateFlags); 1.764 +#endif 1.765 + } 1.766 + } 1.767 + 1.768 + return NS_OK; 1.769 +} 1.770 + 1.771 +/*--------------------------------------------------------------------------- 1.772 + 1.773 + OnProgressChange 1.774 + 1.775 +----------------------------------------------------------------------------*/ 1.776 +NS_IMETHODIMP 1.777 +nsEditingSession::OnProgressChange(nsIWebProgress *aWebProgress, 1.778 + nsIRequest *aRequest, 1.779 + int32_t aCurSelfProgress, 1.780 + int32_t aMaxSelfProgress, 1.781 + int32_t aCurTotalProgress, 1.782 + int32_t aMaxTotalProgress) 1.783 +{ 1.784 + NS_NOTREACHED("notification excluded in AddProgressListener(...)"); 1.785 + return NS_OK; 1.786 +} 1.787 + 1.788 +/*--------------------------------------------------------------------------- 1.789 + 1.790 + OnLocationChange 1.791 + 1.792 +----------------------------------------------------------------------------*/ 1.793 +NS_IMETHODIMP 1.794 +nsEditingSession::OnLocationChange(nsIWebProgress *aWebProgress, 1.795 + nsIRequest *aRequest, nsIURI *aURI, 1.796 + uint32_t aFlags) 1.797 +{ 1.798 + nsCOMPtr<nsIDOMWindow> domWindow; 1.799 + nsresult rv = aWebProgress->GetDOMWindow(getter_AddRefs(domWindow)); 1.800 + NS_ENSURE_SUCCESS(rv, rv); 1.801 + 1.802 + nsCOMPtr<nsIDOMDocument> domDoc; 1.803 + rv = domWindow->GetDocument(getter_AddRefs(domDoc)); 1.804 + NS_ENSURE_SUCCESS(rv, rv); 1.805 + 1.806 + nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc); 1.807 + NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); 1.808 + 1.809 + doc->SetDocumentURI(aURI); 1.810 + 1.811 + // Notify the location-changed observer that 1.812 + // the document URL has changed 1.813 + nsIDocShell *docShell = GetDocShellFromWindow(domWindow); 1.814 + NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); 1.815 + 1.816 + nsCOMPtr<nsICommandManager> commandManager = do_GetInterface(docShell); 1.817 + nsCOMPtr<nsPICommandUpdater> commandUpdater = 1.818 + do_QueryInterface(commandManager); 1.819 + NS_ENSURE_TRUE(commandUpdater, NS_ERROR_FAILURE); 1.820 + 1.821 + return commandUpdater->CommandStatusChanged("obs_documentLocationChanged"); 1.822 +} 1.823 + 1.824 +/*--------------------------------------------------------------------------- 1.825 + 1.826 + OnStatusChange 1.827 + 1.828 +----------------------------------------------------------------------------*/ 1.829 +NS_IMETHODIMP 1.830 +nsEditingSession::OnStatusChange(nsIWebProgress *aWebProgress, 1.831 + nsIRequest *aRequest, 1.832 + nsresult aStatus, 1.833 + const char16_t *aMessage) 1.834 +{ 1.835 + NS_NOTREACHED("notification excluded in AddProgressListener(...)"); 1.836 + return NS_OK; 1.837 +} 1.838 + 1.839 +/*--------------------------------------------------------------------------- 1.840 + 1.841 + OnSecurityChange 1.842 + 1.843 +----------------------------------------------------------------------------*/ 1.844 +NS_IMETHODIMP 1.845 +nsEditingSession::OnSecurityChange(nsIWebProgress *aWebProgress, 1.846 + nsIRequest *aRequest, uint32_t state) 1.847 +{ 1.848 + NS_NOTREACHED("notification excluded in AddProgressListener(...)"); 1.849 + return NS_OK; 1.850 +} 1.851 + 1.852 + 1.853 +/*--------------------------------------------------------------------------- 1.854 + 1.855 + IsProgressForTargetDocument 1.856 + 1.857 + Check that this notification is for our document. 1.858 +----------------------------------------------------------------------------*/ 1.859 + 1.860 +bool 1.861 +nsEditingSession::IsProgressForTargetDocument(nsIWebProgress *aWebProgress) 1.862 +{ 1.863 + nsCOMPtr<nsIWebProgress> editedWebProgress = do_QueryReferent(mDocShell); 1.864 + return editedWebProgress == aWebProgress; 1.865 +} 1.866 + 1.867 + 1.868 +/*--------------------------------------------------------------------------- 1.869 + 1.870 + GetEditorStatus 1.871 + 1.872 + Called during GetCommandStateParams("obs_documentCreated"...) 1.873 + to determine if editor was created and document 1.874 + was loaded successfully 1.875 +----------------------------------------------------------------------------*/ 1.876 +NS_IMETHODIMP 1.877 +nsEditingSession::GetEditorStatus(uint32_t *aStatus) 1.878 +{ 1.879 + NS_ENSURE_ARG_POINTER(aStatus); 1.880 + *aStatus = mEditorStatus; 1.881 + return NS_OK; 1.882 +} 1.883 + 1.884 +/*--------------------------------------------------------------------------- 1.885 + 1.886 + StartDocumentLoad 1.887 + 1.888 + Called on start of load in a single frame 1.889 +----------------------------------------------------------------------------*/ 1.890 +nsresult 1.891 +nsEditingSession::StartDocumentLoad(nsIWebProgress *aWebProgress, 1.892 + bool aIsToBeMadeEditable) 1.893 +{ 1.894 +#ifdef NOISY_DOC_LOADING 1.895 + printf("======= StartDocumentLoad ========\n"); 1.896 +#endif 1.897 + 1.898 + NS_ENSURE_ARG_POINTER(aWebProgress); 1.899 + 1.900 + // If we have an editor here, then we got a reload after making the editor. 1.901 + // We need to blow it away and make a new one at the end of the load. 1.902 + nsCOMPtr<nsIDOMWindow> domWindow; 1.903 + aWebProgress->GetDOMWindow(getter_AddRefs(domWindow)); 1.904 + if (domWindow) 1.905 + { 1.906 + nsIDocShell *docShell = GetDocShellFromWindow(domWindow); 1.907 + NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); 1.908 + docShell->DetachEditorFromWindow(); 1.909 + } 1.910 + 1.911 + if (aIsToBeMadeEditable) 1.912 + mEditorStatus = eEditorCreationInProgress; 1.913 + 1.914 + return NS_OK; 1.915 +} 1.916 + 1.917 +/*--------------------------------------------------------------------------- 1.918 + 1.919 + EndDocumentLoad 1.920 + 1.921 + Called on end of load in a single frame 1.922 +----------------------------------------------------------------------------*/ 1.923 +nsresult 1.924 +nsEditingSession::EndDocumentLoad(nsIWebProgress *aWebProgress, 1.925 + nsIChannel* aChannel, nsresult aStatus, 1.926 + bool aIsToBeMadeEditable) 1.927 +{ 1.928 + NS_ENSURE_ARG_POINTER(aWebProgress); 1.929 + 1.930 +#ifdef NOISY_DOC_LOADING 1.931 + printf("======= EndDocumentLoad ========\n"); 1.932 + printf("with status %d, ", aStatus); 1.933 + nsCOMPtr<nsIURI> uri; 1.934 + nsXPIDLCString spec; 1.935 + if (NS_SUCCEEDED(aChannel->GetURI(getter_AddRefs(uri)))) { 1.936 + uri->GetSpec(spec); 1.937 + printf(" uri %s\n", spec.get()); 1.938 + } 1.939 +#endif 1.940 + 1.941 + // We want to call the base class EndDocumentLoad, 1.942 + // but avoid some of the stuff 1.943 + // that nsDocShell does (need to refactor). 1.944 + 1.945 + // OK, time to make an editor on this document 1.946 + nsCOMPtr<nsIDOMWindow> domWindow; 1.947 + aWebProgress->GetDOMWindow(getter_AddRefs(domWindow)); 1.948 + 1.949 + // Set the error state -- we will create an editor 1.950 + // anyway and load empty doc later 1.951 + if (aIsToBeMadeEditable) { 1.952 + if (aStatus == NS_ERROR_FILE_NOT_FOUND) 1.953 + mEditorStatus = eEditorErrorFileNotFound; 1.954 + } 1.955 + 1.956 + nsIDocShell *docShell = GetDocShellFromWindow(domWindow); 1.957 + NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); // better error handling? 1.958 + 1.959 + // cancel refresh from meta tags 1.960 + // we need to make sure that all pages in editor (whether editable or not) 1.961 + // can't refresh contents being edited 1.962 + nsCOMPtr<nsIRefreshURI> refreshURI = do_QueryInterface(docShell); 1.963 + if (refreshURI) 1.964 + refreshURI->CancelRefreshURITimers(); 1.965 + 1.966 + nsresult rv = NS_OK; 1.967 + 1.968 + // did someone set the flag to make this shell editable? 1.969 + if (aIsToBeMadeEditable && mCanCreateEditor) 1.970 + { 1.971 + bool makeEditable; 1.972 + docShell->GetEditable(&makeEditable); 1.973 + 1.974 + if (makeEditable) 1.975 + { 1.976 + // To keep pre Gecko 1.9 behavior, setup editor always when 1.977 + // mMakeWholeDocumentEditable. 1.978 + bool needsSetup = false; 1.979 + if (mMakeWholeDocumentEditable) { 1.980 + needsSetup = true; 1.981 + } else { 1.982 + // do we already have an editor here? 1.983 + nsCOMPtr<nsIEditor> editor; 1.984 + rv = docShell->GetEditor(getter_AddRefs(editor)); 1.985 + NS_ENSURE_SUCCESS(rv, rv); 1.986 + 1.987 + needsSetup = !editor; 1.988 + } 1.989 + 1.990 + if (needsSetup) 1.991 + { 1.992 + mCanCreateEditor = false; 1.993 + rv = SetupEditorOnWindow(domWindow); 1.994 + if (NS_FAILED(rv)) 1.995 + { 1.996 + // If we had an error, setup timer to load a blank page later 1.997 + if (mLoadBlankDocTimer) 1.998 + { 1.999 + // Must cancel previous timer? 1.1000 + mLoadBlankDocTimer->Cancel(); 1.1001 + mLoadBlankDocTimer = nullptr; 1.1002 + } 1.1003 + 1.1004 + mLoadBlankDocTimer = do_CreateInstance("@mozilla.org/timer;1", &rv); 1.1005 + NS_ENSURE_SUCCESS(rv, rv); 1.1006 + 1.1007 + mEditorStatus = eEditorCreationInProgress; 1.1008 + mLoadBlankDocTimer->InitWithFuncCallback( 1.1009 + nsEditingSession::TimerCallback, 1.1010 + static_cast<void*> (mDocShell.get()), 1.1011 + 10, nsITimer::TYPE_ONE_SHOT); 1.1012 + } 1.1013 + } 1.1014 + } 1.1015 + } 1.1016 + return rv; 1.1017 +} 1.1018 + 1.1019 + 1.1020 +void 1.1021 +nsEditingSession::TimerCallback(nsITimer* aTimer, void* aClosure) 1.1022 +{ 1.1023 + nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(static_cast<nsIWeakReference*> (aClosure)); 1.1024 + if (docShell) 1.1025 + { 1.1026 + nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell)); 1.1027 + if (webNav) 1.1028 + webNav->LoadURI(MOZ_UTF16("about:blank"), 1.1029 + 0, nullptr, nullptr, nullptr); 1.1030 + } 1.1031 +} 1.1032 + 1.1033 +/*--------------------------------------------------------------------------- 1.1034 + 1.1035 + StartPageLoad 1.1036 + 1.1037 + Called on start load of the entire page (incl. subframes) 1.1038 +----------------------------------------------------------------------------*/ 1.1039 +nsresult 1.1040 +nsEditingSession::StartPageLoad(nsIChannel *aChannel) 1.1041 +{ 1.1042 +#ifdef NOISY_DOC_LOADING 1.1043 + printf("======= StartPageLoad ========\n"); 1.1044 +#endif 1.1045 + return NS_OK; 1.1046 +} 1.1047 + 1.1048 +/*--------------------------------------------------------------------------- 1.1049 + 1.1050 + EndPageLoad 1.1051 + 1.1052 + Called on end load of the entire page (incl. subframes) 1.1053 +----------------------------------------------------------------------------*/ 1.1054 +nsresult 1.1055 +nsEditingSession::EndPageLoad(nsIWebProgress *aWebProgress, 1.1056 + nsIChannel* aChannel, nsresult aStatus) 1.1057 +{ 1.1058 +#ifdef NOISY_DOC_LOADING 1.1059 + printf("======= EndPageLoad ========\n"); 1.1060 + printf(" with status %d, ", aStatus); 1.1061 + nsCOMPtr<nsIURI> uri; 1.1062 + nsXPIDLCString spec; 1.1063 + if (NS_SUCCEEDED(aChannel->GetURI(getter_AddRefs(uri)))) { 1.1064 + uri->GetSpec(spec); 1.1065 + printf("uri %s\n", spec.get()); 1.1066 + } 1.1067 + 1.1068 + nsAutoCString contentType; 1.1069 + aChannel->GetContentType(contentType); 1.1070 + if (!contentType.IsEmpty()) 1.1071 + printf(" flags = %d, status = %d, MIMETYPE = %s\n", 1.1072 + mEditorFlags, mEditorStatus, contentType.get()); 1.1073 +#endif 1.1074 + 1.1075 + // Set the error state -- we will create an editor anyway 1.1076 + // and load empty doc later 1.1077 + if (aStatus == NS_ERROR_FILE_NOT_FOUND) 1.1078 + mEditorStatus = eEditorErrorFileNotFound; 1.1079 + 1.1080 + nsCOMPtr<nsIDOMWindow> domWindow; 1.1081 + aWebProgress->GetDOMWindow(getter_AddRefs(domWindow)); 1.1082 + 1.1083 + nsIDocShell *docShell = GetDocShellFromWindow(domWindow); 1.1084 + NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); 1.1085 + 1.1086 + // cancel refresh from meta tags 1.1087 + // we need to make sure that all pages in editor (whether editable or not) 1.1088 + // can't refresh contents being edited 1.1089 + nsCOMPtr<nsIRefreshURI> refreshURI = do_QueryInterface(docShell); 1.1090 + if (refreshURI) 1.1091 + refreshURI->CancelRefreshURITimers(); 1.1092 + 1.1093 +#if 0 1.1094 + // Shouldn't we do this when we want to edit sub-frames? 1.1095 + return MakeWindowEditable(domWindow, "html", false, mInteractive); 1.1096 +#else 1.1097 + return NS_OK; 1.1098 +#endif 1.1099 +} 1.1100 + 1.1101 +/*--------------------------------------------------------------------------- 1.1102 + 1.1103 + GetDocShellFromWindow 1.1104 + 1.1105 + Utility method. This will always return nullptr if no docShell is found. 1.1106 +----------------------------------------------------------------------------*/ 1.1107 +nsIDocShell * 1.1108 +nsEditingSession::GetDocShellFromWindow(nsIDOMWindow *aWindow) 1.1109 +{ 1.1110 + nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow); 1.1111 + NS_ENSURE_TRUE(window, nullptr); 1.1112 + 1.1113 + return window->GetDocShell(); 1.1114 +} 1.1115 + 1.1116 +/*--------------------------------------------------------------------------- 1.1117 + 1.1118 + PrepareForEditing 1.1119 + 1.1120 + Set up this editing session for one or more editors 1.1121 +----------------------------------------------------------------------------*/ 1.1122 +nsresult 1.1123 +nsEditingSession::PrepareForEditing(nsIDOMWindow *aWindow) 1.1124 +{ 1.1125 + if (mProgressListenerRegistered) 1.1126 + return NS_OK; 1.1127 + 1.1128 + nsIDocShell *docShell = GetDocShellFromWindow(aWindow); 1.1129 + 1.1130 + // register callback 1.1131 + nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell); 1.1132 + NS_ENSURE_TRUE(webProgress, NS_ERROR_FAILURE); 1.1133 + 1.1134 + nsresult rv = 1.1135 + webProgress->AddProgressListener(this, 1.1136 + (nsIWebProgress::NOTIFY_STATE_NETWORK | 1.1137 + nsIWebProgress::NOTIFY_STATE_DOCUMENT | 1.1138 + nsIWebProgress::NOTIFY_LOCATION)); 1.1139 + 1.1140 + mProgressListenerRegistered = NS_SUCCEEDED(rv); 1.1141 + 1.1142 + return rv; 1.1143 +} 1.1144 + 1.1145 +/*--------------------------------------------------------------------------- 1.1146 + 1.1147 + SetupEditorCommandController 1.1148 + 1.1149 + Create a command controller, append to controllers, 1.1150 + get and return the controller ID, and set the context 1.1151 +----------------------------------------------------------------------------*/ 1.1152 +nsresult 1.1153 +nsEditingSession::SetupEditorCommandController( 1.1154 + const char *aControllerClassName, 1.1155 + nsIDOMWindow *aWindow, 1.1156 + nsISupports *aContext, 1.1157 + uint32_t *aControllerId) 1.1158 +{ 1.1159 + NS_ENSURE_ARG_POINTER(aControllerClassName); 1.1160 + NS_ENSURE_ARG_POINTER(aWindow); 1.1161 + NS_ENSURE_ARG_POINTER(aContext); 1.1162 + NS_ENSURE_ARG_POINTER(aControllerId); 1.1163 + 1.1164 + nsCOMPtr<nsIControllers> controllers; 1.1165 + nsresult rv = aWindow->GetControllers(getter_AddRefs(controllers)); 1.1166 + NS_ENSURE_SUCCESS(rv, rv); 1.1167 + 1.1168 + // We only have to create each singleton controller once 1.1169 + // We know this has happened once we have a controllerId value 1.1170 + if (!*aControllerId) 1.1171 + { 1.1172 + nsCOMPtr<nsIController> controller; 1.1173 + controller = do_CreateInstance(aControllerClassName, &rv); 1.1174 + NS_ENSURE_SUCCESS(rv, rv); 1.1175 + 1.1176 + // We must insert at head of the list to be sure our 1.1177 + // controller is found before other implementations 1.1178 + // (e.g., not-implemented versions by browser) 1.1179 + rv = controllers->InsertControllerAt(0, controller); 1.1180 + NS_ENSURE_SUCCESS(rv, rv); 1.1181 + 1.1182 + // Remember the ID for the controller 1.1183 + rv = controllers->GetControllerId(controller, aControllerId); 1.1184 + NS_ENSURE_SUCCESS(rv, rv); 1.1185 + } 1.1186 + 1.1187 + // Set the context 1.1188 + return SetContextOnControllerById(controllers, aContext, *aControllerId); 1.1189 +} 1.1190 + 1.1191 +/*--------------------------------------------------------------------------- 1.1192 + 1.1193 + SetEditorOnControllers 1.1194 + 1.1195 + Set the editor on the controller(s) for this window 1.1196 +----------------------------------------------------------------------------*/ 1.1197 +NS_IMETHODIMP 1.1198 +nsEditingSession::SetEditorOnControllers(nsIDOMWindow *aWindow, 1.1199 + nsIEditor* aEditor) 1.1200 +{ 1.1201 + NS_ENSURE_TRUE(aWindow, NS_ERROR_NULL_POINTER); 1.1202 + 1.1203 + nsCOMPtr<nsIControllers> controllers; 1.1204 + nsresult rv = aWindow->GetControllers(getter_AddRefs(controllers)); 1.1205 + NS_ENSURE_SUCCESS(rv, rv); 1.1206 + 1.1207 + nsCOMPtr<nsISupports> editorAsISupports = do_QueryInterface(aEditor); 1.1208 + if (mBaseCommandControllerId) 1.1209 + { 1.1210 + rv = SetContextOnControllerById(controllers, editorAsISupports, 1.1211 + mBaseCommandControllerId); 1.1212 + NS_ENSURE_SUCCESS(rv, rv); 1.1213 + } 1.1214 + 1.1215 + if (mDocStateControllerId) 1.1216 + { 1.1217 + rv = SetContextOnControllerById(controllers, editorAsISupports, 1.1218 + mDocStateControllerId); 1.1219 + NS_ENSURE_SUCCESS(rv, rv); 1.1220 + } 1.1221 + 1.1222 + if (mHTMLCommandControllerId) 1.1223 + rv = SetContextOnControllerById(controllers, editorAsISupports, 1.1224 + mHTMLCommandControllerId); 1.1225 + 1.1226 + return rv; 1.1227 +} 1.1228 + 1.1229 +nsresult 1.1230 +nsEditingSession::SetContextOnControllerById(nsIControllers* aControllers, 1.1231 + nsISupports* aContext, 1.1232 + uint32_t aID) 1.1233 +{ 1.1234 + NS_ENSURE_ARG_POINTER(aControllers); 1.1235 + 1.1236 + // aContext can be null (when destroying editor) 1.1237 + nsCOMPtr<nsIController> controller; 1.1238 + aControllers->GetControllerById(aID, getter_AddRefs(controller)); 1.1239 + 1.1240 + // ok with nil controller 1.1241 + nsCOMPtr<nsIControllerContext> editorController = 1.1242 + do_QueryInterface(controller); 1.1243 + NS_ENSURE_TRUE(editorController, NS_ERROR_FAILURE); 1.1244 + 1.1245 + return editorController->SetCommandContext(aContext); 1.1246 +} 1.1247 + 1.1248 +void 1.1249 +nsEditingSession::RemoveEditorControllers(nsIDOMWindow *aWindow) 1.1250 +{ 1.1251 + // Remove editor controllers from the aWindow, call when we're 1.1252 + // tearing down/detaching editor. 1.1253 + 1.1254 + nsCOMPtr<nsIControllers> controllers; 1.1255 + if (aWindow) 1.1256 + aWindow->GetControllers(getter_AddRefs(controllers)); 1.1257 + 1.1258 + if (controllers) 1.1259 + { 1.1260 + nsCOMPtr<nsIController> controller; 1.1261 + if (mBaseCommandControllerId) 1.1262 + { 1.1263 + controllers->GetControllerById(mBaseCommandControllerId, 1.1264 + getter_AddRefs(controller)); 1.1265 + if (controller) 1.1266 + controllers->RemoveController(controller); 1.1267 + } 1.1268 + 1.1269 + if (mDocStateControllerId) 1.1270 + { 1.1271 + controllers->GetControllerById(mDocStateControllerId, 1.1272 + getter_AddRefs(controller)); 1.1273 + if (controller) 1.1274 + controllers->RemoveController(controller); 1.1275 + } 1.1276 + 1.1277 + if (mHTMLCommandControllerId) 1.1278 + { 1.1279 + controllers->GetControllerById(mHTMLCommandControllerId, 1.1280 + getter_AddRefs(controller)); 1.1281 + if (controller) 1.1282 + controllers->RemoveController(controller); 1.1283 + } 1.1284 + } 1.1285 + 1.1286 + // Clear IDs to trigger creation of new controllers. 1.1287 + mBaseCommandControllerId = 0; 1.1288 + mDocStateControllerId = 0; 1.1289 + mHTMLCommandControllerId = 0; 1.1290 +} 1.1291 + 1.1292 +void 1.1293 +nsEditingSession::RemoveWebProgressListener(nsIDOMWindow *aWindow) 1.1294 +{ 1.1295 + nsIDocShell *docShell = GetDocShellFromWindow(aWindow); 1.1296 + nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell); 1.1297 + if (webProgress) 1.1298 + { 1.1299 + webProgress->RemoveProgressListener(this); 1.1300 + mProgressListenerRegistered = false; 1.1301 + } 1.1302 +} 1.1303 + 1.1304 +void 1.1305 +nsEditingSession::RestoreAnimationMode(nsIDOMWindow *aWindow) 1.1306 +{ 1.1307 + if (!mInteractive) 1.1308 + { 1.1309 + nsCOMPtr<nsIDOMWindowUtils> utils(do_GetInterface(aWindow)); 1.1310 + if (utils) 1.1311 + utils->SetImageAnimationMode(mImageAnimationMode); 1.1312 + } 1.1313 +} 1.1314 + 1.1315 +nsresult 1.1316 +nsEditingSession::DetachFromWindow(nsIDOMWindow* aWindow) 1.1317 +{ 1.1318 + NS_ENSURE_TRUE(mDoneSetup, NS_OK); 1.1319 + 1.1320 + NS_ASSERTION(mStateMaintainer, "mStateMaintainer should exist."); 1.1321 + 1.1322 + // Kill any existing reload timer 1.1323 + if (mLoadBlankDocTimer) 1.1324 + { 1.1325 + mLoadBlankDocTimer->Cancel(); 1.1326 + mLoadBlankDocTimer = nullptr; 1.1327 + } 1.1328 + 1.1329 + // Remove controllers, webprogress listener, and otherwise 1.1330 + // make things the way they were before we started editing. 1.1331 + RemoveEditorControllers(aWindow); 1.1332 + RemoveWebProgressListener(aWindow); 1.1333 + RestoreJSAndPlugins(aWindow); 1.1334 + RestoreAnimationMode(aWindow); 1.1335 + 1.1336 + // Kill our weak reference to our original window, in case 1.1337 + // it changes on restore, or otherwise dies. 1.1338 + mDocShell = nullptr; 1.1339 + 1.1340 + return NS_OK; 1.1341 +} 1.1342 + 1.1343 +nsresult 1.1344 +nsEditingSession::ReattachToWindow(nsIDOMWindow* aWindow) 1.1345 +{ 1.1346 + NS_ENSURE_TRUE(mDoneSetup, NS_OK); 1.1347 + 1.1348 + NS_ASSERTION(mStateMaintainer, "mStateMaintainer should exist."); 1.1349 + 1.1350 + // Imitate nsEditorDocShell::MakeEditable() to reattach the 1.1351 + // old editor ot the window. 1.1352 + nsresult rv; 1.1353 + 1.1354 + nsIDocShell *docShell = GetDocShellFromWindow(aWindow); 1.1355 + NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); 1.1356 + mDocShell = do_GetWeakReference(docShell); 1.1357 + 1.1358 + // Disable plugins. 1.1359 + if (!mInteractive) 1.1360 + { 1.1361 + rv = DisableJSAndPlugins(aWindow); 1.1362 + NS_ENSURE_SUCCESS(rv, rv); 1.1363 + } 1.1364 + 1.1365 + // Tells embedder that startup is in progress. 1.1366 + mEditorStatus = eEditorCreationInProgress; 1.1367 + 1.1368 + // Adds back web progress listener. 1.1369 + rv = PrepareForEditing(aWindow); 1.1370 + NS_ENSURE_SUCCESS(rv, rv); 1.1371 + 1.1372 + // Setup the command controllers again. 1.1373 + rv = SetupEditorCommandController("@mozilla.org/editor/editingcontroller;1", 1.1374 + aWindow, 1.1375 + static_cast<nsIEditingSession*>(this), 1.1376 + &mBaseCommandControllerId); 1.1377 + NS_ENSURE_SUCCESS(rv, rv); 1.1378 + 1.1379 + rv = SetupEditorCommandController("@mozilla.org/editor/editordocstatecontroller;1", 1.1380 + aWindow, 1.1381 + static_cast<nsIEditingSession*>(this), 1.1382 + &mDocStateControllerId); 1.1383 + NS_ENSURE_SUCCESS(rv, rv); 1.1384 + 1.1385 + if (mStateMaintainer) 1.1386 + mStateMaintainer->Init(aWindow); 1.1387 + 1.1388 + // Get editor 1.1389 + nsCOMPtr<nsIEditor> editor; 1.1390 + rv = GetEditorForWindow(aWindow, getter_AddRefs(editor)); 1.1391 + NS_ENSURE_TRUE(editor, NS_ERROR_FAILURE); 1.1392 + 1.1393 + if (!mInteractive) 1.1394 + { 1.1395 + // Disable animation of images in this document: 1.1396 + nsCOMPtr<nsIDOMWindowUtils> utils(do_GetInterface(aWindow)); 1.1397 + NS_ENSURE_TRUE(utils, NS_ERROR_FAILURE); 1.1398 + 1.1399 + rv = utils->GetImageAnimationMode(&mImageAnimationMode); 1.1400 + NS_ENSURE_SUCCESS(rv, rv); 1.1401 + utils->SetImageAnimationMode(imgIContainer::kDontAnimMode); 1.1402 + } 1.1403 + 1.1404 + // The third controller takes an nsIEditor as the context 1.1405 + rv = SetupEditorCommandController("@mozilla.org/editor/htmleditorcontroller;1", 1.1406 + aWindow, editor, 1.1407 + &mHTMLCommandControllerId); 1.1408 + NS_ENSURE_SUCCESS(rv, rv); 1.1409 + 1.1410 + // Set context on all controllers to be the editor 1.1411 + rv = SetEditorOnControllers(aWindow, editor); 1.1412 + NS_ENSURE_SUCCESS(rv, rv); 1.1413 + 1.1414 +#ifdef DEBUG 1.1415 + { 1.1416 + bool isEditable; 1.1417 + rv = WindowIsEditable(aWindow, &isEditable); 1.1418 + NS_ENSURE_SUCCESS(rv, rv); 1.1419 + NS_ASSERTION(isEditable, "Window is not editable after reattaching editor."); 1.1420 + } 1.1421 +#endif // DEBUG 1.1422 + 1.1423 + return NS_OK; 1.1424 +}