diff --git a/b2g/app/b2g.js b/b2g/app/b2g.js index c2a211b58e..484a91a0a7 100644 --- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -1088,9 +1088,6 @@ pref("dom.mozSettings.SettingsService.verbose.enabled", false); // readwrite. pref("dom.mozSettings.allowForceReadOnly", false); -// RequestSync API is enabled by default on B2G. -pref("dom.requestSync.enabled", true); - // Comma separated list of activity names that can only be provided by // the system app in dev mode. pref("dom.activities.developer_mode_only", "import-app"); diff --git a/b2g/chrome/content/shell.js b/b2g/chrome/content/shell.js index 141a050665..db17fca465 100644 --- a/b2g/chrome/content/shell.js +++ b/b2g/chrome/content/shell.js @@ -17,7 +17,6 @@ Cu.import('resource://gre/modules/UserAgentOverrides.jsm'); Cu.import('resource://gre/modules/Keyboard.jsm'); Cu.import('resource://gre/modules/ErrorPage.jsm'); Cu.import('resource://gre/modules/AlertsHelper.jsm'); -Cu.import('resource://gre/modules/RequestSyncService.jsm'); Cu.import('resource://gre/modules/SystemUpdateService.jsm'); if (isGonk) { diff --git a/b2g/installer/package-manifest.in b/b2g/installer/package-manifest.in index 82b0f380dd..b08382fb8c 100644 --- a/b2g/installer/package-manifest.in +++ b/b2g/installer/package-manifest.in @@ -373,9 +373,6 @@ @RESPATH@/components/zipwriter.xpt ; JavaScript components -@RESPATH@/components/RequestSync.manifest -@RESPATH@/components/RequestSyncManager.js -@RESPATH@/components/RequestSyncScheduler.js @RESPATH@/components/ChromeNotifications.js @RESPATH@/components/ChromeNotifications.manifest @RESPATH@/components/ConsoleAPI.manifest diff --git a/browser/installer/allowed-dupes.mn b/browser/installer/allowed-dupes.mn index a4be4d4899..b808acf2ae 100644 --- a/browser/installer/allowed-dupes.mn +++ b/browser/installer/allowed-dupes.mn @@ -623,6 +623,9 @@ browser/chrome/devtools/skin/images/security-state-weak.svg browser/chrome/browser/skin/classic/browser/identity-secure.svg browser/chrome/browser/skin/classic/browser/identity-not-secure.svg +browser/chrome/browser/defaults/permissions +browser/defaults/permissions + #Windows ArcticFox exceptions chrome/toolkit/skin/classic/mozapps/extensions/category-plugins.png diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index dd53b971c2..6ca595f1e9 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -554,10 +554,6 @@ @RESPATH@/components/htmlMenuBuilder.js @RESPATH@/components/htmlMenuBuilder.manifest -@RESPATH@/components/RequestSync.manifest -@RESPATH@/components/RequestSyncManager.js -@RESPATH@/components/RequestSyncScheduler.js - @RESPATH@/components/PermissionSettings.js @RESPATH@/components/PermissionSettings.manifest @RESPATH@/components/ContactManager.js diff --git a/dom/apps/PermissionsTable.jsm b/dom/apps/PermissionsTable.jsm index 71ddad5983..ef9719a88f 100644 --- a/dom/apps/PermissionsTable.jsm +++ b/dom/apps/PermissionsTable.jsm @@ -472,11 +472,6 @@ this.PermissionsTable = { geolocation: { privileged: DENY_ACTION, certified: ALLOW_ACTION }, - "requestsync-manager": { - app: DENY_ACTION, - privileged: DENY_ACTION, - certified: ALLOW_ACTION - }, "secureelement-manage": { app: DENY_ACTION, privileged: DENY_ACTION, diff --git a/dom/base/AnonymousContent.cpp b/dom/base/AnonymousContent.cpp index 9d4e42b97b..753ea54dfb 100644 --- a/dom/base/AnonymousContent.cpp +++ b/dom/base/AnonymousContent.cpp @@ -29,7 +29,7 @@ AnonymousContent::~AnonymousContent() { } -nsCOMPtr +Element* AnonymousContent::GetContentNode() { return mContentNode; diff --git a/dom/base/AnonymousContent.h b/dom/base/AnonymousContent.h index 6d6b1e2571..aabafca4df 100644 --- a/dom/base/AnonymousContent.h +++ b/dom/base/AnonymousContent.h @@ -25,7 +25,7 @@ public: NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(AnonymousContent) explicit AnonymousContent(Element* aContentNode); - nsCOMPtr GetContentNode(); + Element* GetContentNode(); void SetContentNode(Element* aContentNode); bool WrapObject(JSContext* aCx, JS::Handle aGivenProto, JS::MutableHandle aReflector); diff --git a/dom/base/ImportManager.h b/dom/base/ImportManager.h index 9003726403..258d4691cf 100644 --- a/dom/base/ImportManager.h +++ b/dom/base/ImportManager.h @@ -159,7 +159,10 @@ public: // nullptr if the import is not yet ready. nsIDocument* GetImport() { - return mReady ? mDocument : nullptr; + if (!mReady) { + return nullptr; + } + return mDocument; } // There is only one referring link that is marked as primary link per @@ -170,7 +173,10 @@ public: // a new import link is added to the manager. nsINode* GetMainReferrer() { - return mLinks.IsEmpty() ? nullptr : mLinks[mMainReferrer]; + if (mLinks.IsEmpty()) { + return nullptr; + } + return mLinks[mMainReferrer]; } // An import is not only blocked by its import children, but also diff --git a/dom/base/ScriptSettings.cpp b/dom/base/ScriptSettings.cpp index 99bb1059d8..7ece97586f 100644 --- a/dom/base/ScriptSettings.cpp +++ b/dom/base/ScriptSettings.cpp @@ -52,7 +52,10 @@ public: static nsIGlobalObject* IncumbentGlobal() { ScriptSettingsStackEntry *entry = Top(); - return entry ? entry->mGlobalObject : nullptr; + if (!entry) { + return nullptr; + } + return entry->mGlobalObject; } static ScriptSettingsStackEntry* EntryPoint() { @@ -70,7 +73,10 @@ public: static nsIGlobalObject* EntryGlobal() { ScriptSettingsStackEntry *entry = EntryPoint(); - return entry ? entry->mGlobalObject : nullptr; + if (!entry) { + return nullptr; + } + return entry->mGlobalObject; } }; diff --git a/dom/base/nsFrameLoader.cpp b/dom/base/nsFrameLoader.cpp index 5faaa5336d..ef2e97f7f6 100644 --- a/dom/base/nsFrameLoader.cpp +++ b/dom/base/nsFrameLoader.cpp @@ -1314,9 +1314,9 @@ nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther, // Restore the correct treeowners // (and also chrome event handlers for content frames only). SetTreeOwnerAndChromeEventHandlerOnDocshellTree(ourDocshell, otherOwner, - ourType == nsIDocShellTreeItem::typeContent ? otherChromeEventHandler : nullptr); + ourType == nsIDocShellTreeItem::typeContent ? otherChromeEventHandler.get() : nullptr); SetTreeOwnerAndChromeEventHandlerOnDocshellTree(otherDocshell, ourOwner, - ourType == nsIDocShellTreeItem::typeContent ? ourChromeEventHandler : nullptr); + ourType == nsIDocShellTreeItem::typeContent ? ourChromeEventHandler.get() : nullptr); // Switch the owner content before we start calling AddTreeItemToTreeOwner. // Note that we rely on this to deal with setting mObservingOwnerContent to diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 2158214fbb..e7ce3d6f36 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -2092,7 +2092,10 @@ nsIScriptContext * nsGlobalWindow::GetScriptContext() { nsGlobalWindow* outer = GetOuterWindowInternal(); - return outer ? outer->mContext : nullptr; + if (!outer) { + return nullptr; + } + return outer->mContext; } JSObject * @@ -7248,7 +7251,7 @@ nsGlobalWindow::PrintOuter(ErrorResult& aError) if (NS_SUCCEEDED(GetInterface(NS_GET_IID(nsIWebBrowserPrint), getter_AddRefs(webBrowserPrint)))) { nsAutoSyncOperation sync(GetCurrentInnerWindowInternal() ? - GetCurrentInnerWindowInternal()->mDoc : + GetCurrentInnerWindowInternal()->mDoc.get() : nullptr); nsCOMPtr printSettingsService = diff --git a/dom/base/nsXMLHttpRequest.cpp b/dom/base/nsXMLHttpRequest.cpp index 01c606987e..0c70c4ba69 100644 --- a/dom/base/nsXMLHttpRequest.cpp +++ b/dom/base/nsXMLHttpRequest.cpp @@ -550,7 +550,10 @@ nsXMLHttpRequest::GetResponseXML(ErrorResult& aRv) mWarnAboutSyncHtml = false; LogMessage("HTMLSyncXHRWarning", GetOwner()); } - return (XML_HTTP_REQUEST_DONE & mState) ? mResponseXML : nullptr; + if (!(XML_HTTP_REQUEST_DONE & mState)) { + return nullptr; + } + return mResponseXML; } /* diff --git a/dom/canvas/OffscreenCanvas.cpp b/dom/canvas/OffscreenCanvas.cpp index 857da02aea..73c4fa10b5 100644 --- a/dom/canvas/OffscreenCanvas.cpp +++ b/dom/canvas/OffscreenCanvas.cpp @@ -222,7 +222,8 @@ already_AddRefed OffscreenCanvas::TransferToImageBitmap() { ErrorResult rv; - RefPtr result = ImageBitmap::CreateFromOffscreenCanvas(GetGlobalObject(), *this, rv); + nsCOMPtr globalObject = GetGlobalObject(); + RefPtr result = ImageBitmap::CreateFromOffscreenCanvas(globalObject, *this, rv); // Clear the content. if ((mCurrentContextType == CanvasContextType::WebGL1 || diff --git a/dom/downloads/tests/shim_app_as_test.js b/dom/downloads/tests/shim_app_as_test.js index 0b83746bf1..1dd73df8e8 100644 --- a/dom/downloads/tests/shim_app_as_test.js +++ b/dom/downloads/tests/shim_app_as_test.js @@ -1,11 +1,5 @@ /** - * Support logic to run a test file as an installed app. This file is derived - * from dom/requestsync/tests/test_basic_app.html but uses - * DOMApplicationRegistry in a chrome script (shim_app_as_test_chrome.js) to - * directly install the apps instead of mozApps.install because mozApps.install - * can't install privileged/certified apps. (This is the same mechanism used by - * the Firefox OS Gaia email app's backend test runner.) - * + * Support logic to run a test file as an installed app. * You really only want to do this if your test cares about the app's origin * or you REALLY want to double-check AvailableIn and other WebIDL-provided * security mechanisms. diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index 1148ab632d..d6748786ea 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -1899,7 +1899,7 @@ public: MediaStreamTrackSource) explicit CaptureStreamTrackSource(HTMLMediaElement* aElement) - : MediaStreamTrackSource(nsCOMPtr(aElement->GetCurrentPrincipal()), + : MediaStreamTrackSource(nsCOMPtr(aElement->GetCurrentPrincipal()).get(), true, nsString()) , mElement(aElement) diff --git a/dom/ipc/ContentBridgeChild.cpp b/dom/ipc/ContentBridgeChild.cpp index 0908319576..30dbfc720f 100644 --- a/dom/ipc/ContentBridgeChild.cpp +++ b/dom/ipc/ContentBridgeChild.cpp @@ -27,14 +27,14 @@ ContentBridgeChild::ContentBridgeChild(Transport* aTransport) ContentBridgeChild::~ContentBridgeChild() { - XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new DeleteTask(mTransport)); + RefPtr> task = new DeleteTask(mTransport); + XRE_GetIOMessageLoop()->PostTask(task.forget()); } void ContentBridgeChild::ActorDestroy(ActorDestroyReason aWhy) { MessageLoop::current()->PostTask( - FROM_HERE, NewRunnableMethod(this, &ContentBridgeChild::DeferredDestroy)); } diff --git a/dom/ipc/ContentBridgeParent.cpp b/dom/ipc/ContentBridgeParent.cpp index 918455c3d9..608f7f2abc 100644 --- a/dom/ipc/ContentBridgeParent.cpp +++ b/dom/ipc/ContentBridgeParent.cpp @@ -26,7 +26,8 @@ ContentBridgeParent::ContentBridgeParent(Transport* aTransport) ContentBridgeParent::~ContentBridgeParent() { - XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new DeleteTask(mTransport)); + RefPtr> task = new DeleteTask(mTransport); + XRE_GetIOMessageLoop()->PostTask(task.forget()); } void @@ -37,7 +38,6 @@ ContentBridgeParent::ActorDestroy(ActorDestroyReason aWhy) os->RemoveObserver(this, "content-child-shutdown"); } MessageLoop::current()->PostTask( - FROM_HERE, NewRunnableMethod(this, &ContentBridgeParent::DeferredDestroy)); } @@ -169,7 +169,6 @@ ContentBridgeParent::NotifyTabDestroyed() int32_t numLiveTabs = ManagedPBrowserParent().Count(); if (numLiveTabs == 1) { MessageLoop::current()->PostTask( - FROM_HERE, NewRunnableMethod(this, &ContentBridgeParent::Close)); } } diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 52a72b08ea..cf08ad5623 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -1513,7 +1513,7 @@ ContentChild::RecvBidiKeyboardNotify(const bool& aIsLangRTL) return true; } -static CancelableTask* sFirstIdleTask; +static CancelableRunnable* sFirstIdleTask; static void FirstIdle(void) { @@ -1594,8 +1594,9 @@ ContentChild::RecvPBrowserConstructor(PBrowserChild* aActor, hasRunOnce = true; MOZ_ASSERT(!sFirstIdleTask); - sFirstIdleTask = NewRunnableFunction(FirstIdle); - MessageLoop::current()->PostIdleTask(FROM_HERE, sFirstIdleTask); + RefPtr firstIdleTask = NewRunnableFunction(FirstIdle); + sFirstIdleTask = firstIdleTask; + MessageLoop::current()->PostIdleTask(firstIdleTask.forget()); // Redo InitProcessAttributes() when the app or browser is really // launching so the attributes will be correct. @@ -2617,8 +2618,7 @@ ContentChild::RecvAppInit() #ifdef MOZ_NUWA_PROCESS if (IsNuwaProcess()) { ContentChild::GetSingleton()->RecvGarbageCollect(); - MessageLoop::current()->PostTask( - FROM_HERE, NewRunnableFunction(OnFinishNuwaPreparation)); + MessageLoop::current()->PostTask(NewRunnableFunction(OnFinishNuwaPreparation)); } #endif diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index a02b964b0a..36b925958f 100755 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -793,8 +793,7 @@ ContentParent::JoinAllSubprocesses() bool done = false; Monitor monitor("mozilla.dom.ContentParent.JoinAllSubprocesses"); - XRE_GetIOMessageLoop()->PostTask(FROM_HERE, - NewRunnableFunction( + XRE_GetIOMessageLoop()->PostTask(NewRunnableFunction( &ContentParent::JoinProcessesIOThread, &processes, &monitor, &done)); { @@ -2173,7 +2172,6 @@ ContentParent::ActorDestroy(ActorDestroyReason why) for(uint32_t i = 0; i < childIDArray.Length(); i++) { ContentParent* cp = cpm->GetContentProcessById(childIDArray[i]); MessageLoop::current()->PostTask( - FROM_HERE, NewRunnableMethod(cp, &ContentParent::ShutDownProcess, SEND_SHUTDOWN_MESSAGE)); } @@ -2257,7 +2255,6 @@ ContentParent::NotifyTabDestroyed(const TabId& aTabId, // In the case of normal shutdown, send a shutdown message to child to // allow it to perform shutdown tasks. MessageLoop::current()->PostTask( - FROM_HERE, NewRunnableMethod(this, &ContentParent::ShutDownProcess, SEND_SHUTDOWN_MESSAGE)); } @@ -3622,7 +3619,6 @@ ContentParent::KillHard(const char* aReason) // EnsureProcessTerminated has responsibilty for closing otherProcessHandle. XRE_GetIOMessageLoop()->PostTask( - FROM_HERE, NewRunnableFunction(&ProcessWatcher::EnsureProcessTerminated, otherProcessHandle, /*force=*/true)); } diff --git a/dom/ipc/PreallocatedProcessManager.cpp b/dom/ipc/PreallocatedProcessManager.cpp index 46c12f6578..697e619947 100644 --- a/dom/ipc/PreallocatedProcessManager.cpp +++ b/dom/ipc/PreallocatedProcessManager.cpp @@ -205,7 +205,6 @@ PreallocatedProcessManagerImpl::AllocateAfterDelay() } MessageLoop::current()->PostDelayedTask( - FROM_HERE, NewRunnableMethod(this, &PreallocatedProcessManagerImpl::AllocateOnIdle), Preferences::GetUint("dom.ipc.processPrelaunch.delayMs", DEFAULT_ALLOCATE_DELAY)); @@ -219,7 +218,6 @@ PreallocatedProcessManagerImpl::AllocateOnIdle() } MessageLoop::current()->PostIdleTask( - FROM_HERE, NewRunnableMethod(this, &PreallocatedProcessManagerImpl::AllocateNow)); } @@ -245,10 +243,10 @@ PreallocatedProcessManagerImpl::ScheduleDelayedNuwaFork() return; } - mPreallocateAppProcessTask = NewRunnableMethod( + RefPtr task = NewRunnableMethod( this, &PreallocatedProcessManagerImpl::DelayedNuwaFork); - MessageLoop::current()->PostDelayedTask( - FROM_HERE, mPreallocateAppProcessTask, + mPreallocateAppProcessTask = task; + MessageLoop::current()->PostDelayedTask(task.forget(), Preferences::GetUint("dom.ipc.processPrelaunch.delayMs", DEFAULT_ALLOCATE_DELAY)); } diff --git a/dom/ipc/ProcessHangMonitor.cpp b/dom/ipc/ProcessHangMonitor.cpp index 221a434dd1..39d832e768 100644 --- a/dom/ipc/ProcessHangMonitor.cpp +++ b/dom/ipc/ProcessHangMonitor.cpp @@ -265,7 +265,8 @@ HangMonitorChild::~HangMonitorChild() { // For some reason IPDL doesn't automatically delete the channel for a // bridged protocol (bug 1090570). So we have to do it ourselves. - XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new DeleteTask(GetTransport())); + RefPtr> task = new DeleteTask(GetTransport()); + XRE_GetIOMessageLoop()->PostTask(task.forget()); MOZ_RELEASE_ASSERT(NS_IsMainThread()); MOZ_ASSERT(sInstance == this); @@ -303,7 +304,6 @@ HangMonitorChild::ActorDestroy(ActorDestroyReason aWhy) // We use a task here to ensure that IPDL is finished with this // HangMonitorChild before it gets deleted on the main thread. MonitorLoop()->PostTask( - FROM_HERE, NewRunnableMethod(this, &HangMonitorChild::ShutdownOnThread)); } @@ -391,7 +391,6 @@ HangMonitorChild::NotifySlowScript(nsITabChild* aTabChild, nsAutoCString filename(aFileName); MonitorLoop()->PostTask( - FROM_HERE, NewRunnableMethod(this, &HangMonitorChild::NotifySlowScriptAsync, id, filename, aLineNo)); return SlowScriptAction::Continue; @@ -422,7 +421,6 @@ HangMonitorChild::NotifyPluginHang(uint32_t aPluginId) // bounce to background thread MonitorLoop()->PostTask( - FROM_HERE, NewRunnableMethod(this, &HangMonitorChild::NotifyPluginHangAsync, aPluginId)); @@ -448,7 +446,6 @@ HangMonitorChild::ClearHang() if (mSentReport) { // bounce to background thread MonitorLoop()->PostTask( - FROM_HERE, NewRunnableMethod(this, &HangMonitorChild::ClearHangAsync)); MonitorAutoLock lock(mMonitor); @@ -487,7 +484,8 @@ HangMonitorParent::~HangMonitorParent() { // For some reason IPDL doesn't automatically delete the channel for a // bridged protocol (bug 1090570). So we have to do it ourselves. - XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new DeleteTask(GetTransport())); + RefPtr> task = new DeleteTask(GetTransport()); + XRE_GetIOMessageLoop()->PostTask(task.forget()); #ifdef MOZ_CRASHREPORTER MutexAutoLock lock(mBrowserCrashDumpHashLock); @@ -514,7 +512,6 @@ HangMonitorParent::Shutdown() } MonitorLoop()->PostTask( - FROM_HERE, NewRunnableMethod(this, &HangMonitorParent::ShutdownOnThread)); while (!mShutdownDone) { @@ -836,7 +833,6 @@ HangMonitoredProcess::TerminateScript() } ProcessHangMonitor::Get()->MonitorLoop()->PostTask( - FROM_HERE, NewRunnableMethod(mActor, &HangMonitorParent::TerminateScript)); return NS_OK; } @@ -854,7 +850,6 @@ HangMonitoredProcess::BeginStartingDebugger() } ProcessHangMonitor::Get()->MonitorLoop()->PostTask( - FROM_HERE, NewRunnableMethod(mActor, &HangMonitorParent::BeginStartingDebugger)); return NS_OK; } @@ -872,7 +867,6 @@ HangMonitoredProcess::EndStartingDebugger() } ProcessHangMonitor::Get()->MonitorLoop()->PostTask( - FROM_HERE, NewRunnableMethod(mActor, &HangMonitorParent::EndStartingDebugger)); return NS_OK; } @@ -1052,7 +1046,6 @@ mozilla::CreateHangMonitorParent(ContentParent* aContentParent, parent->SetProcess(process); monitor->MonitorLoop()->PostTask( - FROM_HERE, NewRunnableMethod(parent, &HangMonitorParent::Open, aTransport, aOtherPid, XRE_GetIOMessageLoop())); @@ -1069,7 +1062,6 @@ mozilla::CreateHangMonitorChild(mozilla::ipc::Transport* aTransport, HangMonitorChild* child = new HangMonitorChild(monitor); monitor->MonitorLoop()->PostTask( - FROM_HERE, NewRunnableMethod(child, &HangMonitorChild::Open, aTransport, aOtherPid, XRE_GetIOMessageLoop())); diff --git a/dom/media/MediaCallbackID.cpp b/dom/media/MediaCallbackID.cpp new file mode 100644 index 0000000000..d1d40f7b29 --- /dev/null +++ b/dom/media/MediaCallbackID.cpp @@ -0,0 +1,50 @@ +#include "MediaCallbackID.h" + +namespace mozilla { + +char const* CallbackID::INVALID_TAG = "INVALID_TAG"; +int32_t const CallbackID::INVALID_ID = -1; + +CallbackID::CallbackID() + : mTag(INVALID_TAG), mID(INVALID_ID) +{ +} + +CallbackID::CallbackID(char const* aTag, int32_t aID /* = 0*/) + : mTag(aTag), mID(aID) +{ +} + +CallbackID& +CallbackID::operator++() +{ + ++mID; + return *this; +} + +CallbackID +CallbackID::operator++(int) +{ + CallbackID ret = *this; + ++(*this); // call prefix++ + return ret; +} + +bool +CallbackID::operator==(const CallbackID& rhs) const +{ + return (strcmp(mTag, rhs.mTag) == 0) && (mID == rhs.mID); +} + +bool +CallbackID::operator!=(const CallbackID& rhs) const +{ + return !(*this == rhs); +} + +CallbackID::operator int() const +{ + return mID; +} + +} // namespace mozilla diff --git a/dom/media/MediaCallbackID.h b/dom/media/MediaCallbackID.h new file mode 100644 index 0000000000..62cdd2fcc1 --- /dev/null +++ b/dom/media/MediaCallbackID.h @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MediaCallbackID_h_ +#define MediaCallbackID_h_ + +namespace mozilla { + +struct CallbackID +{ + static char const* INVALID_TAG; + static int32_t const INVALID_ID; + + CallbackID(); + + explicit CallbackID(char const* aTag, int32_t aID = 0); + + CallbackID& operator++(); // prefix++ + + CallbackID operator++(int); // postfix++ + + bool operator==(const CallbackID& rhs) const; + + bool operator!=(const CallbackID& rhs) const; + + operator int() const; + +private: + char const* mTag; + int32_t mID; +}; + +} // namespace mozilla + +#endif // MediaCallbackID_h_ diff --git a/dom/media/MediaDecoderReaderWrapper.cpp b/dom/media/MediaDecoderReaderWrapper.cpp index 5866158bcc..4bed533f1c 100644 --- a/dom/media/MediaDecoderReaderWrapper.cpp +++ b/dom/media/MediaDecoderReaderWrapper.cpp @@ -144,6 +144,8 @@ MediaDecoderReaderWrapper::MediaDecoderReaderWrapper(bool aIsRealTime, : mForceZeroStartTime(aIsRealTime || aReader->ForceZeroStartTime()) , mOwnerThread(aOwnerThread) , mReader(aReader) + , mAudioCallbackID("AudioCallbackID") + , mVideoCallbackID("VideoCallbackID") {} MediaDecoderReaderWrapper::~MediaDecoderReaderWrapper() @@ -178,11 +180,30 @@ MediaDecoderReaderWrapper::AwaitStartTime() return mStartTimeRendezvous->AwaitStartTime(); } -RefPtr +void +MediaDecoderReaderWrapper::CancelAudioCallback(CallbackID aID) +{ + MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn()); + MOZ_ASSERT(aID == mAudioCallbackID); + ++mAudioCallbackID; + mRequestAudioDataCB = nullptr; +} + +void +MediaDecoderReaderWrapper::CancelVideoCallback(CallbackID aID) +{ + MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn()); + MOZ_ASSERT(aID == mVideoCallbackID); + ++mVideoCallbackID; + mRequestVideoDataCB = nullptr; +} + +void MediaDecoderReaderWrapper::RequestAudioData() { MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn()); MOZ_ASSERT(!mShutdown); + MOZ_ASSERT(mRequestAudioDataCB, "Request audio data without callback!"); auto p = InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__, &MediaDecoderReader::RequestAudioData); @@ -194,18 +215,31 @@ MediaDecoderReaderWrapper::RequestAudioData() ->CompletionPromise(); } - return p->Then(mOwnerThread, __func__, this, - &MediaDecoderReaderWrapper::OnSampleDecoded, - &MediaDecoderReaderWrapper::OnNotDecoded) - ->CompletionPromise(); + RefPtr self = this; + mAudioDataRequest.Begin(p->Then(mOwnerThread, __func__, + [self] (MediaData* aAudioSample) { + MOZ_ASSERT(self->mRequestAudioDataCB); + self->mAudioDataRequest.Complete(); + self->OnSampleDecoded(self->mRequestAudioDataCB.get(), aAudioSample, TimeStamp()); + }, + [self] (MediaDecoderReader::NotDecodedReason aReason) { + MOZ_ASSERT(self->mRequestAudioDataCB); + self->mAudioDataRequest.Complete(); + self->OnNotDecoded(self->mRequestAudioDataCB.get(), aReason); + })); } -RefPtr +void MediaDecoderReaderWrapper::RequestVideoData(bool aSkipToNextKeyframe, media::TimeUnit aTimeThreshold) { MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn()); MOZ_ASSERT(!mShutdown); + MOZ_ASSERT(mRequestVideoDataCB, "Request video data without callback!"); + + // Time the video decode and send this value back to callbacks who accept + // a TimeStamp as its second parameter. + TimeStamp videoDecodeStartTime = TimeStamp::Now(); if (aTimeThreshold.ToMicroseconds() > 0 && mStartTimeRendezvous->HaveStartTime()) { @@ -223,10 +257,32 @@ MediaDecoderReaderWrapper::RequestVideoData(bool aSkipToNextKeyframe, ->CompletionPromise(); } - return p->Then(mOwnerThread, __func__, this, - &MediaDecoderReaderWrapper::OnSampleDecoded, - &MediaDecoderReaderWrapper::OnNotDecoded) - ->CompletionPromise(); + RefPtr self = this; + mVideoDataRequest.Begin(p->Then(mOwnerThread, __func__, + [self, videoDecodeStartTime] (MediaData* aVideoSample) { + MOZ_ASSERT(self->mRequestVideoDataCB); + self->mVideoDataRequest.Complete(); + self->OnSampleDecoded(self->mRequestVideoDataCB.get(), aVideoSample, videoDecodeStartTime); + }, + [self] (MediaDecoderReader::NotDecodedReason aReason) { + MOZ_ASSERT(self->mRequestVideoDataCB); + self->mVideoDataRequest.Complete(); + self->OnNotDecoded(self->mRequestVideoDataCB.get(), aReason); + })); +} + +bool +MediaDecoderReaderWrapper::IsRequestingAudioData() const +{ + MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn()); + return mAudioDataRequest.Exists(); +} + +bool +MediaDecoderReaderWrapper::IsRequestingVidoeData() const +{ + MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn()); + return mVideoDataRequest.Exists(); } RefPtr @@ -277,6 +333,10 @@ void MediaDecoderReaderWrapper::ResetDecode() { MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn()); + + mAudioDataRequest.DisconnectIfExists(); + mVideoDataRequest.DisconnectIfExists(); + nsCOMPtr r = NS_NewRunnableMethod(mReader, &MediaDecoderReader::ResetDecode); mReader->OwnerThread()->Dispatch(r.forget()); @@ -286,6 +346,11 @@ RefPtr MediaDecoderReaderWrapper::Shutdown() { MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn()); + MOZ_ASSERT(!mRequestAudioDataCB); + MOZ_ASSERT(!mRequestVideoDataCB); + MOZ_ASSERT(!mAudioDataRequest.Exists()); + MOZ_ASSERT(!mVideoDataRequest.Exists()); + mShutdown = true; if (mStartTimeRendezvous) { mStartTimeRendezvous->Destroy(); @@ -323,12 +388,25 @@ MediaDecoderReaderWrapper::OnMetadataRead(MetadataHolder* aMetadata) } void -MediaDecoderReaderWrapper::OnSampleDecoded(MediaData* aSample) +MediaDecoderReaderWrapper::OnSampleDecoded(CallbackBase* aCallback, + MediaData* aSample, + TimeStamp aDecodeStartTime) { MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn()); - if (!mShutdown) { - aSample->AdjustForStartTime(StartTime().ToMicroseconds()); - } + MOZ_ASSERT(!mShutdown); + + aSample->AdjustForStartTime(StartTime().ToMicroseconds()); + aCallback->OnResolved(aSample, aDecodeStartTime); +} + +void +MediaDecoderReaderWrapper::OnNotDecoded(CallbackBase* aCallback, + MediaDecoderReader::NotDecodedReason aReason) +{ + MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn()); + MOZ_ASSERT(!mShutdown); + + aCallback->OnRejected(aReason); } } // namespace mozilla diff --git a/dom/media/MediaDecoderReaderWrapper.h b/dom/media/MediaDecoderReaderWrapper.h index 02c47d22ff..231591ebee 100644 --- a/dom/media/MediaDecoderReaderWrapper.h +++ b/dom/media/MediaDecoderReaderWrapper.h @@ -12,6 +12,7 @@ #include "nsISupportsImpl.h" #include "MediaDecoderReader.h" +#include "MediaCallbackID.h" namespace mozilla { @@ -33,6 +34,135 @@ class MediaDecoderReaderWrapper { typedef MediaDecoderReader::BufferedUpdatePromise BufferedUpdatePromise; NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderReaderWrapper); + /* + * Type 1: void(MediaData*) + * void(RefPtr) + */ + template + class ArgType1CheckHelper { + template + static TrueType + test(void(C::*aMethod)(Ts...), + decltype((DeclVal().*aMethod)(DeclVal()), 0)); + + template + static TrueType + test(F&&, decltype(DeclVal()(DeclVal()), 0)); + + static FalseType test(...); + public: + typedef decltype(test(DeclVal(), 0)) Type; + }; + + template + struct ArgType1Check : public ArgType1CheckHelper::Type {}; + + /* + * Type 2: void(MediaData*, TimeStamp) + * void(RefPtr, TimeStamp) + * void(MediaData*, TimeStamp&) + * void(RefPtr, const TimeStamp&&) + */ + template + class ArgType2CheckHelper { + + template + static TrueType + test(void(C::*aMethod)(Ts...), + decltype((DeclVal().*aMethod)(DeclVal(), DeclVal()), 0)); + + template + static TrueType + test(F&&, decltype(DeclVal()(DeclVal(), DeclVal()), 0)); + + static FalseType test(...); + public: + typedef decltype(test(DeclVal(), 0)) Type; + }; + + template + struct ArgType2Check : public ArgType2CheckHelper::Type {}; + + struct CallbackBase + { + virtual ~CallbackBase() {} + virtual void OnResolved(MediaData*, TimeStamp) = 0; + virtual void OnRejected(MediaDecoderReader::NotDecodedReason) = 0; + }; + + template + struct MethodCallback : public CallbackBase + { + MethodCallback(ThisType* aThis, ResolveMethodType aResolveMethod, RejectMethodType aRejectMethod) + : mThis(aThis), mResolveMethod(aResolveMethod), mRejectMethod(aRejectMethod) + { + } + + template + typename EnableIf::value, void>::Type + CallHelper(MediaData* aSample, TimeStamp) + { + (mThis->*mResolveMethod)(aSample); + } + + template + typename EnableIf::value, void>::Type + CallHelper(MediaData* aSample, TimeStamp aDecodeStartTime) + { + (mThis->*mResolveMethod)(aSample, aDecodeStartTime); + } + + void OnResolved(MediaData* aSample, TimeStamp aDecodeStartTime) override + { + CallHelper(aSample, aDecodeStartTime); + } + + void OnRejected(MediaDecoderReader::NotDecodedReason aReason) override + { + (mThis->*mRejectMethod)(aReason); + } + + RefPtr mThis; + ResolveMethodType mResolveMethod; + RejectMethodType mRejectMethod; + }; + + template + struct FunctionCallback : public CallbackBase + { + FunctionCallback(ResolveFunctionType&& aResolveFuntion, RejectFunctionType&& aRejectFunction) + : mResolveFuntion(Move(aResolveFuntion)), mRejectFunction(Move(aRejectFunction)) + { + } + + template + typename EnableIf::value, void>::Type + CallHelper(MediaData* aSample, TimeStamp) + { + mResolveFuntion(aSample); + } + + template + typename EnableIf::value, void>::Type + CallHelper(MediaData* aSample, TimeStamp aDecodeStartTime) + { + mResolveFuntion(aSample, aDecodeStartTime); + } + + void OnResolved(MediaData* aSample, TimeStamp aDecodeStartTime) override + { + CallHelper(aSample, aDecodeStartTime); + } + + void OnRejected(MediaDecoderReader::NotDecodedReason aReason) override + { + mRejectFunction(aReason); + } + + ResolveFunctionType mResolveFuntion; + RejectFunctionType mRejectFunction; + }; + public: MediaDecoderReaderWrapper(bool aIsRealTime, AbstractThread* aOwnerThread, @@ -41,9 +171,83 @@ public: media::TimeUnit StartTime() const; RefPtr ReadMetadata(); RefPtr AwaitStartTime(); - RefPtr RequestAudioData(); - RefPtr RequestVideoData(bool aSkipToNextKeyframe, - media::TimeUnit aTimeThreshold); + + template + CallbackID + SetAudioCallback(ThisType* aThisVal, + ResolveMethodType aResolveMethod, + RejectMethodType aRejectMethod) + { + MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn()); + MOZ_ASSERT(!mRequestAudioDataCB, + "Please cancel the original callback before setting a new one."); + + mRequestAudioDataCB.reset( + new MethodCallback( + aThisVal, aResolveMethod, aRejectMethod)); + + return mAudioCallbackID; + } + + template + CallbackID + SetAudioCallback(ResolveFunction&& aResolveFunction, + RejectFunction&& aRejectFunction) + { + MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn()); + MOZ_ASSERT(!mRequestAudioDataCB, + "Please cancel the original callback before setting a new one."); + + mRequestAudioDataCB.reset( + new FunctionCallback( + Move(aResolveFunction), Move(aRejectFunction))); + + return mAudioCallbackID; + } + + template + CallbackID + SetVideoCallback(ThisType* aThisVal, + ResolveMethodType aResolveMethod, + RejectMethodType aRejectMethod) + { + MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn()); + MOZ_ASSERT(!mRequestVideoDataCB, + "Please cancel the original callback before setting a new one."); + + mRequestVideoDataCB.reset( + new MethodCallback( + aThisVal, aResolveMethod, aRejectMethod)); + + return mVideoCallbackID; + } + + template + CallbackID + SetVideoCallback(ResolveFunction&& aResolveFunction, + RejectFunction&& aRejectFunction) + { + MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn()); + MOZ_ASSERT(!mRequestVideoDataCB, + "Please cancel the original callback before setting a new one."); + + mRequestVideoDataCB.reset( + new FunctionCallback( + Move(aResolveFunction), Move(aRejectFunction))); + + return mVideoCallbackID; + } + + void CancelAudioCallback(CallbackID aID); + void CancelVideoCallback(CallbackID aID); + + // NOTE: please set callbacks before requesting audio/video data! + void RequestAudioData(); + void RequestVideoData(bool aSkipToNextKeyframe, media::TimeUnit aTimeThreshold); + + bool IsRequestingAudioData() const; + bool IsRequestingVidoeData() const; + RefPtr Seek(SeekTarget aTarget, media::TimeUnit aEndTime); RefPtr WaitForData(MediaData::Type aType); RefPtr UpdateBufferedWithPromise(); @@ -96,8 +300,10 @@ private: void OnMetadataRead(MetadataHolder* aMetadata); void OnMetadataNotRead() {} - void OnSampleDecoded(MediaData* aSample); - void OnNotDecoded() {} + void OnSampleDecoded(CallbackBase* aCallback, MediaData* aSample, + TimeStamp aVideoDecodeStartTime); + void OnNotDecoded(CallbackBase* aCallback, + MediaDecoderReader::NotDecodedReason aReason); const bool mForceZeroStartTime; const RefPtr mOwnerThread; @@ -105,6 +311,17 @@ private: bool mShutdown = false; RefPtr mStartTimeRendezvous; + + UniquePtr mRequestAudioDataCB; + UniquePtr mRequestVideoDataCB; + MozPromiseRequestHolder mAudioDataRequest; + MozPromiseRequestHolder mVideoDataRequest; + + /* + * These callback ids are used to prevent mis-canceling callback. + */ + CallbackID mAudioCallbackID; + CallbackID mVideoCallbackID; }; } // namespace mozilla diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index c0e620682b..82c764d426 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -258,8 +258,6 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder, "MediaDecoderStateMachine::mPlayState (Mirror)"), mNextPlayState(mTaskQueue, MediaDecoder::PLAY_STATE_PAUSED, "MediaDecoderStateMachine::mNextPlayState (Mirror)"), - mLogicallySeeking(mTaskQueue, false, - "MediaDecoderStateMachine::mLogicallySeeking (Mirror)"), mVolume(mTaskQueue, 1.0, "MediaDecoderStateMachine::mVolume (Mirror)"), mLogicalPlaybackRate(mTaskQueue, 1.0, "MediaDecoderStateMachine::mLogicalPlaybackRate (Mirror)"), @@ -331,7 +329,6 @@ MediaDecoderStateMachine::InitializationTask(MediaDecoder* aDecoder) mExplicitDuration.Connect(aDecoder->CanonicalExplicitDuration()); mPlayState.Connect(aDecoder->CanonicalPlayState()); mNextPlayState.Connect(aDecoder->CanonicalNextPlayState()); - mLogicallySeeking.Connect(aDecoder->CanonicalLogicallySeeking()); mVolume.Connect(aDecoder->CanonicalVolume()); mLogicalPlaybackRate.Connect(aDecoder->CanonicalPlaybackRate()); mPreservesPitch.Connect(aDecoder->CanonicalPreservesPitch()); @@ -355,7 +352,9 @@ MediaDecoderStateMachine::InitializationTask(MediaDecoder* aDecoder) mWatchManager.Watch(mExplicitDuration, &MediaDecoderStateMachine::RecomputeDuration); mWatchManager.Watch(mObservedDuration, &MediaDecoderStateMachine::RecomputeDuration); mWatchManager.Watch(mPlayState, &MediaDecoderStateMachine::PlayStateChanged); - mWatchManager.Watch(mLogicallySeeking, &MediaDecoderStateMachine::LogicallySeekingChanged); + + // Configure MediaDecoderReaderWrapper. + SetMediaDecoderReaderWrapperCallback(); } media::MediaSink* @@ -564,7 +563,6 @@ MediaDecoderStateMachine::OnAudioDecoded(MediaData* aAudioSample) RefPtr audio(aAudioSample); MOZ_ASSERT(audio); - mAudioDataRequest.Complete(); // audio->GetEndTime() is not always mono-increasing in chained ogg. mDecodedAudioEndTime = std::max(audio->GetEndTime(), mDecodedAudioEndTime); @@ -678,11 +676,6 @@ MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType, bool isAudio = aType == MediaData::AUDIO_DATA; MOZ_ASSERT_IF(!isAudio, aType == MediaData::VIDEO_DATA); - if (isAudio) { - mAudioDataRequest.Complete(); - } else { - mVideoDataRequest.Complete(); - } if (IsShutdown()) { // Already shutdown; return; @@ -797,7 +790,6 @@ MediaDecoderStateMachine::OnVideoDecoded(MediaData* aVideoSample, RefPtr video(aVideoSample); MOZ_ASSERT(video); - mVideoDataRequest.Complete(); // Handle abnormal or negative timestamps. mDecodedVideoEndTime = std::max(mDecodedVideoEndTime, video->GetEndTime()); @@ -931,6 +923,33 @@ nsresult MediaDecoderStateMachine::Init(MediaDecoder* aDecoder) return NS_OK; } +void +MediaDecoderStateMachine::SetMediaDecoderReaderWrapperCallback() +{ + mAudioCallbackID = + mReader->SetAudioCallback(this, + &MediaDecoderStateMachine::OnAudioDecoded, + &MediaDecoderStateMachine::OnAudioNotDecoded); + + mVideoCallbackID = + mReader->SetVideoCallback(this, + &MediaDecoderStateMachine::OnVideoDecoded, + &MediaDecoderStateMachine::OnVideoNotDecoded); + + DECODER_LOG("MDSM set audio callbacks: mAudioCallbackID = %d\n", (int)mAudioCallbackID); + DECODER_LOG("MDSM set video callbacks: mVideoCallbackID = %d\n", (int)mVideoCallbackID); +} + +void +MediaDecoderStateMachine::CancelMediaDecoderReaderWrapperCallback() +{ + DECODER_LOG("MDSM cancel audio callbacks: mVideoCallbackID = %d\n", (int)mAudioCallbackID); + mReader->CancelAudioCallback(mAudioCallbackID); + + DECODER_LOG("MDSM cancel video callbacks: mVideoCallbackID = %d\n", (int)mVideoCallbackID); + mReader->CancelVideoCallback(mVideoCallbackID); +} + void MediaDecoderStateMachine::StopPlayback() { MOZ_ASSERT(OnTaskQueue()); @@ -1153,10 +1172,7 @@ MediaDecoderStateMachine::SetDormant(bool aDormant) } // Discard the current seek task. - if (mSeekTask) { - mSeekTask->Discard(); - mSeekTask = nullptr; - } + DiscardSeekTaskIfExist(); SetState(DECODER_STATE_DORMANT); if (IsPlaying()) { @@ -1193,10 +1209,8 @@ MediaDecoderStateMachine::Shutdown() mBufferedUpdateRequest.DisconnectIfExists(); mQueuedSeek.RejectIfExists(__func__); - if (mSeekTask) { - mSeekTask->Discard(); - mSeekTask = nullptr; - } + + DiscardSeekTaskIfExist(); #ifdef MOZ_EME mCDMProxyPromise.DisconnectIfExists(); @@ -1206,6 +1220,9 @@ MediaDecoderStateMachine::Shutdown() StopPlayback(); } + // To break the cycle-reference between MediaDecoderReaderWrapper and MDSM. + CancelMediaDecoderReaderWrapperCallback(); + Reset(); mMediaSink->Shutdown(); @@ -1309,12 +1326,6 @@ void MediaDecoderStateMachine::PlayStateChanged() ScheduleStateMachine(); } -void MediaDecoderStateMachine::LogicallySeekingChanged() -{ - MOZ_ASSERT(OnTaskQueue()); - ScheduleStateMachine(); -} - void MediaDecoderStateMachine::BufferedRangeUpdated() { MOZ_ASSERT(OnTaskQueue()); @@ -1467,12 +1478,13 @@ MediaDecoderStateMachine::InitiateSeek(SeekJob aSeekJob) MOZ_ASSERT(OnTaskQueue()); // Discard the existing seek task. - if (mSeekTask) { - mSeekTask->Discard(); - } + DiscardSeekTaskIfExist(); mSeekTaskRequest.DisconnectIfExists(); + // SeekTask will register its callbacks to MediaDecoderReaderWrapper. + CancelMediaDecoderReaderWrapperCallback(); + // Create a new SeekTask instance for the incoming seek task. mSeekTask = SeekTask::CreateSeekTask(mDecoderID, OwnerThread(), mReader.get(), Move(aSeekJob), @@ -1535,9 +1547,6 @@ MediaDecoderStateMachine::OnSeekTaskResolved(SeekTaskResolveValue aValue) } SeekCompleted(); - - mSeekTask->Discard(); - mSeekTask = nullptr; } void @@ -1568,8 +1577,19 @@ MediaDecoderStateMachine::OnSeekTaskRejected(SeekTaskRejectValue aValue) DecodeError(); - mSeekTask->Discard(); - mSeekTask = nullptr; + DiscardSeekTaskIfExist(); +} + +void +MediaDecoderStateMachine::DiscardSeekTaskIfExist() +{ + if (mSeekTask) { + mSeekTask->Discard(); + mSeekTask = nullptr; + + // Reset the MediaDecoderReaderWrapper's callbask. + SetMediaDecoderReaderWrapperCallback(); + } } nsresult @@ -1602,7 +1622,7 @@ MediaDecoderStateMachine::EnsureAudioDecodeTaskQueued() return NS_OK; } - if (!IsAudioDecoding() || mAudioDataRequest.Exists() || + if (!IsAudioDecoding() || mReader->IsRequestingAudioData() || mAudioWaitRequest.Exists()) { return NS_OK; } @@ -1620,11 +1640,7 @@ MediaDecoderStateMachine::RequestAudioData() SAMPLE_LOG("Queueing audio task - queued=%i, decoder-queued=%o", AudioQueue().GetSize(), mReader->SizeOfAudioQueueInFrames()); - mAudioDataRequest.Begin( - mReader->RequestAudioData() - ->Then(OwnerThread(), __func__, this, - &MediaDecoderStateMachine::OnAudioDecoded, - &MediaDecoderStateMachine::OnAudioNotDecoded)); + mReader->RequestAudioData(); } nsresult @@ -1657,7 +1673,7 @@ MediaDecoderStateMachine::EnsureVideoDecodeTaskQueued() return NS_OK; } - if (!IsVideoDecoding() || mVideoDataRequest.Exists() || + if (!IsVideoDecoding() || mReader->IsRequestingVidoeData() || mVideoWaitRequest.Exists()) { return NS_OK; } @@ -1672,11 +1688,6 @@ MediaDecoderStateMachine::RequestVideoData() MOZ_ASSERT(OnTaskQueue()); MOZ_ASSERT(mState != DECODER_STATE_SEEKING); - // Time the video decode, so that if it's slow, we can increase our low - // audio threshold to reduce the chance of an audio underrun while we're - // waiting for a video decode to complete. - TimeStamp videoDecodeStartTime = TimeStamp::Now(); - bool skipToNextKeyFrame = mSentFirstFrameLoadedEvent && NeedToSkipToNextKeyframe(); @@ -1686,16 +1697,11 @@ MediaDecoderStateMachine::RequestVideoData() VideoQueue().GetSize(), mReader->SizeOfVideoQueueInFrames(), skipToNextKeyFrame, currentTime.ToMicroseconds()); - RefPtr self = this; - mVideoDataRequest.Begin( - mReader->RequestVideoData(skipToNextKeyFrame, currentTime) - ->Then(OwnerThread(), __func__, - [self, videoDecodeStartTime] (MediaData* aVideoSample) { - self->OnVideoDecoded(aVideoSample, videoDecodeStartTime); - }, - [self] (MediaDecoderReader::NotDecodedReason aReason) { - self->OnVideoNotDecoded(aReason); - })); + // MediaDecoderReaderWrapper::RequestVideoData() records the decoding start + // time and sent it back to MDSM::OnVideoDecoded() so that if the decoding is + // slow, we can increase our low audio threshold to reduce the chance of an + // audio underrun while we're waiting for a video decode to complete. + mReader->RequestVideoData(skipToNextKeyFrame, currentTime); } void @@ -2016,6 +2022,15 @@ MediaDecoderStateMachine::SeekCompleted() // to ensure that the seeked event is fired prior loadeded. mSeekTask->GetSeekJob().Resolve(nextState == DECODER_STATE_COMPLETED, __func__); + // Discard and nullify the seek task. + // Reset the MediaDecoderReaderWrapper's callbask. + DiscardSeekTaskIfExist(); + + // NOTE: Discarding the mSeekTask must be done before here. The following code + // might ask the MediaDecoderReaderWrapper to request media data, however, the + // SeekTask::Discard() will ask MediaDecoderReaderWrapper to discard media + // data requests. + if (mDecodingFirstFrame) { // We were resuming from dormant, or initiated a seek early. // We can fire loadeddata now. @@ -2074,7 +2089,6 @@ MediaDecoderStateMachine::FinishShutdown() mExplicitDuration.DisconnectIfConnected(); mPlayState.DisconnectIfConnected(); mNextPlayState.DisconnectIfConnected(); - mLogicallySeeking.DisconnectIfConnected(); mVolume.DisconnectIfConnected(); mLogicalPlaybackRate.DisconnectIfConnected(); mPreservesPitch.DisconnectIfConnected(); @@ -2138,7 +2152,6 @@ nsresult MediaDecoderStateMachine::RunStateMachine() UpdatePlaybackPositionPeriodically(); NS_ASSERTION(!IsPlaying() || - mLogicallySeeking || IsStateMachineScheduled(), "Must have timer scheduled"); return NS_OK; @@ -2170,8 +2183,8 @@ nsresult MediaDecoderStateMachine::RunStateMachine() MOZ_ASSERT(mReader->IsWaitForDataSupported(), "Don't yet have a strategy for non-heuristic + non-WaitForData"); DispatchDecodeTasksIfNeeded(); - MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedAudio(), mAudioDataRequest.Exists() || mAudioWaitRequest.Exists()); - MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedVideo(), mVideoDataRequest.Exists() || mVideoWaitRequest.Exists()); + MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedAudio(), mReader->IsRequestingAudioData() || mAudioWaitRequest.Exists()); + MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedVideo(), mReader->IsRequestingVidoeData() || mVideoWaitRequest.Exists()); DECODER_LOG("In buffering mode, waiting to be notified: outOfAudio: %d, " "mAudioStatus: %s, outOfVideo: %d, mVideoStatus: %s", OutOfDecodedAudio(), AudioRequestStatus(), @@ -2204,7 +2217,6 @@ nsresult MediaDecoderStateMachine::RunStateMachine() MaybeStartPlayback(); UpdatePlaybackPositionPeriodically(); NS_ASSERTION(!IsPlaying() || - mLogicallySeeking || IsStateMachineScheduled(), "Must have timer scheduled"); return NS_OK; @@ -2266,9 +2278,7 @@ MediaDecoderStateMachine::Reset() VideoQueue().Reset(); mMetadataRequest.DisconnectIfExists(); - mAudioDataRequest.DisconnectIfExists(); mAudioWaitRequest.DisconnectIfExists(); - mVideoDataRequest.DisconnectIfExists(); mVideoWaitRequest.DisconnectIfExists(); mSeekTaskRequest.DisconnectIfExists(); @@ -2291,7 +2301,7 @@ MediaDecoderStateMachine::UpdatePlaybackPositionPeriodically() { MOZ_ASSERT(OnTaskQueue()); - if (!IsPlaying() || mLogicallySeeking) { + if (!IsPlaying()) { return; } @@ -2737,6 +2747,32 @@ MediaDecoderStateMachine::OnMediaNotSeekable() const return mReader->OnMediaNotSeekable(); } +const char* +MediaDecoderStateMachine::AudioRequestStatus() const +{ + MOZ_ASSERT(OnTaskQueue()); + if (mReader->IsRequestingAudioData()) { + MOZ_DIAGNOSTIC_ASSERT(!mAudioWaitRequest.Exists()); + return "pending"; + } else if (mAudioWaitRequest.Exists()) { + return "waiting"; + } + return "idle"; +} + +const char* +MediaDecoderStateMachine::VideoRequestStatus() const +{ + MOZ_ASSERT(OnTaskQueue()); + if (mReader->IsRequestingVidoeData()) { + MOZ_DIAGNOSTIC_ASSERT(!mVideoWaitRequest.Exists()); + return "pending"; + } else if (mVideoWaitRequest.Exists()) { + return "waiting"; + } + return "idle"; +} + } // namespace mozilla // avoid redefined macro in unified build diff --git a/dom/media/MediaDecoderStateMachine.h b/dom/media/MediaDecoderStateMachine.h index ab5de566e0..f65273c522 100644 --- a/dom/media/MediaDecoderStateMachine.h +++ b/dom/media/MediaDecoderStateMachine.h @@ -87,6 +87,7 @@ hardware (via AudioStream). #include "mozilla/StateMirroring.h" #include "nsThreadUtils.h" +#include "MediaCallbackID.h" #include "MediaDecoder.h" #include "MediaDecoderReader.h" #include "MediaDecoderOwner.h" @@ -143,6 +144,9 @@ public: nsresult Init(MediaDecoder* aDecoder); + void SetMediaDecoderReaderWrapperCallback(); + void CancelMediaDecoderReaderWrapperCallback(); + // Enumeration for the valid decoding states enum State { DECODER_STATE_DECODING_METADATA, @@ -467,9 +471,6 @@ protected: // Notification method invoked when mPlayState changes. void PlayStateChanged(); - // Notification method invoked when mLogicallySeeking changes. - void LogicallySeekingChanged(); - // Sets internal state which causes playback of media to pause. // The decoder monitor must be held. void StopPlayback(); @@ -682,6 +683,10 @@ private: void OnSeekTaskResolved(SeekTaskResolveValue aValue); void OnSeekTaskRejected(SeekTaskRejectValue aValue); + // This method discards the seek task and then get the ownership of + // MedaiDecoderReaderWarpper back via registering MDSM's callback into it. + void DiscardSeekTaskIfExist(); + // Media Fragment end time in microseconds. Access controlled by decoder monitor. int64_t mFragmentEndTime; @@ -810,33 +815,13 @@ private: // Only one of a given pair of ({Audio,Video}DataPromise, WaitForDataPromise) // should exist at any given moment. - MozPromiseRequestHolder mAudioDataRequest; + CallbackID mAudioCallbackID; MozPromiseRequestHolder mAudioWaitRequest; - const char* AudioRequestStatus() - { - MOZ_ASSERT(OnTaskQueue()); - if (mAudioDataRequest.Exists()) { - MOZ_DIAGNOSTIC_ASSERT(!mAudioWaitRequest.Exists()); - return "pending"; - } else if (mAudioWaitRequest.Exists()) { - return "waiting"; - } - return "idle"; - } + const char* AudioRequestStatus() const; + CallbackID mVideoCallbackID; MozPromiseRequestHolder mVideoWaitRequest; - MozPromiseRequestHolder mVideoDataRequest; - const char* VideoRequestStatus() - { - MOZ_ASSERT(OnTaskQueue()); - if (mVideoDataRequest.Exists()) { - MOZ_DIAGNOSTIC_ASSERT(!mVideoWaitRequest.Exists()); - return "pending"; - } else if (mVideoWaitRequest.Exists()) { - return "waiting"; - } - return "idle"; - } + const char* VideoRequestStatus() const; MozPromiseRequestHolder& WaitRequestRef(MediaData::Type aType) { @@ -980,7 +965,6 @@ private: // The current play state and next play state, mirrored from the main thread. Mirror mPlayState; Mirror mNextPlayState; - Mirror mLogicallySeeking; // Volume of playback. 0.0 = muted. 1.0 = full volume. Mirror mVolume; diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index 42b6cb7b75..4fc8859e5e 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -246,7 +246,7 @@ HostHasPermission(nsIURI &docURI) // Generic class for running long media operations like Start off the main // thread, and then (because nsDOMMediaStreams aren't threadsafe), // ProxyReleases mStream since it's cycle collected. -class MediaOperationTask : public Task +class MediaOperationTask : public Runnable { public: // so we can send Stop without AddRef()ing from the MSG thread @@ -280,14 +280,14 @@ public: void ReturnCallbackError(nsresult rv, const char* errorLog); - void - Run() + NS_IMETHOD + Run() override { SourceMediaStream *source = mListener->GetSourceStream(); // No locking between these is required as all the callbacks for the // same MediaStream will occur on the same thread. if (!source) // means the stream was never Activated() - return; + return NS_OK; switch (mType) { case MEDIA_START: @@ -300,7 +300,7 @@ public: mListener->GetPrincipalHandle()); if (NS_FAILED(rv)) { ReturnCallbackError(rv, "Starting audio failed"); - return; + return NS_OK; } } if (mVideoDevice) { @@ -308,7 +308,7 @@ public: mListener->GetPrincipalHandle()); if (NS_FAILED(rv)) { ReturnCallbackError(rv, "Starting video failed"); - return; + return NS_OK; } } // Start() queued the tracks to be added synchronously to avoid races @@ -377,6 +377,8 @@ public: MOZ_ASSERT(false,"invalid MediaManager operation"); break; } + + return NS_OK; } private: @@ -974,11 +976,12 @@ public: // because that can take a while. // Pass ownership of domStream to the MediaOperationTask // to ensure it's kept alive until the MediaOperationTask runs (at least). - MediaManager::PostTask(FROM_HERE, + RefPtr mediaOperation = new MediaOperationTask(MEDIA_START, mListener, domStream, tracksAvailableCallback, mAudioDevice, mVideoDevice, - false, mWindowID, mOnFailure.forget())); + false, mWindowID, mOnFailure.forget()); + MediaManager::PostTask(mediaOperation.forget()); // We won't need mOnFailure now. mOnFailure = nullptr; @@ -1068,8 +1071,7 @@ MediaManager::SelectSettings( // Algorithm accesses device capabilities code and must run on media thread. // Modifies passed-in aSources. - MediaManager::PostTask(FROM_HERE, NewTaskFrom([id, aConstraints, - aSources]() mutable { + MediaManager::PostTask(NewTaskFrom([id, aConstraints, aSources]() mutable { auto& sources = **aSources; // Since the advanced part of the constraints algorithm needs to know when @@ -1105,14 +1107,14 @@ MediaManager::SelectSettings( sources.AppendElement(audio); } } - NS_DispatchToMainThread(do_AddRef(NewRunnableFrom([id, badConstraint]() mutable { + NS_DispatchToMainThread(NewRunnableFrom([id, badConstraint]() mutable { RefPtr mgr = MediaManager_GetInstance(); RefPtr p = mgr->mOutstandingCharPledges.Remove(id); if (p) { p->Resolve(badConstraint); } return NS_OK; - }))); + })); })); return p.forget(); } @@ -1125,7 +1127,7 @@ MediaManager::SelectSettings( * Do not run this on the main thread. The success and error callbacks *MUST* * be dispatched on the main thread! */ -class GetUserMediaTask : public Task +class GetUserMediaTask : public Runnable { public: GetUserMediaTask( @@ -1168,8 +1170,8 @@ public: NS_DispatchToMainThread(do_AddRef(new GetUserMediaListenerRemove(mWindowID, mListener))); } - void - Run() + NS_IMETHOD + Run() override { MOZ_ASSERT(!NS_IsMainThread()); MOZ_ASSERT(mOnSuccess); @@ -1188,7 +1190,7 @@ public: LOG(("Failed to allocate audiosource %d",rv)); Fail(NS_LITERAL_STRING("SourceUnavailableError"), NS_LITERAL_STRING("Failed to allocate audiosource")); - return; + return NS_OK; } } if (mVideoDevice) { @@ -1201,7 +1203,7 @@ public: } Fail(NS_LITERAL_STRING("SourceUnavailableError"), NS_LITERAL_STRING("Failed to allocate videosource")); - return; + return NS_OK; } } PeerIdentity* peerIdentity = nullptr; @@ -1215,6 +1217,7 @@ public: mVideoDevice, peerIdentity))); MOZ_ASSERT(!mOnSuccess); MOZ_ASSERT(!mOnFailure); + return NS_OK; } nsresult @@ -1306,7 +1309,7 @@ public: ~GetUserMediaRunnableWrapper() { } - NS_IMETHOD Run() { + NS_IMETHOD Run() override { mTask->Run(); return NS_OK; } @@ -1351,10 +1354,10 @@ MediaManager::EnumerateRawDevices(uint64_t aWindowId, aFakeTracks = false; } - MediaManager::PostTask(FROM_HERE, NewTaskFrom([id, aWindowId, audioLoopDev, - videoLoopDev, aVideoType, - aAudioType, aFake, - aFakeTracks]() mutable { + MediaManager::PostTask(NewTaskFrom([id, aWindowId, audioLoopDev, + videoLoopDev, aVideoType, + aAudioType, aFake, + aFakeTracks]() mutable { // Only enumerate what's asked for, and only fake cams and mics. bool hasVideo = aVideoType != MediaSourceEnum::Other; bool hasAudio = aAudioType != MediaSourceEnum::Other; @@ -1389,7 +1392,7 @@ MediaManager::EnumerateRawDevices(uint64_t aWindowId, } } SourceSet* handoff = result.release(); - NS_DispatchToMainThread(do_AddRef(NewRunnableFrom([id, handoff]() mutable { + NS_DispatchToMainThread(NewRunnableFrom([id, handoff]() mutable { UniquePtr result(handoff); // grab result RefPtr mgr = MediaManager_GetInstance(); if (!mgr) { @@ -1400,7 +1403,7 @@ MediaManager::EnumerateRawDevices(uint64_t aWindowId, p->Resolve(result.release()); } return NS_OK; - }))); + })); })); return p.forget(); } @@ -1599,16 +1602,19 @@ MediaManager::StartupInit() /* static */ void -MediaManager::PostTask(const tracked_objects::Location& from_here, Task* task) +MediaManager::PostTask(already_AddRefed task) { if (sInShutdown) { // Can't safely delete task here since it may have items with specific // thread-release requirements. + // XXXkhuey well then who is supposed to delete it?! We don't signal + // that we failed ... + MOZ_CRASH(); return; } NS_ASSERTION(Get(), "MediaManager singleton?"); NS_ASSERTION(Get()->mMediaThread, "No thread yet"); - Get()->mMediaThread->message_loop()->PostTask(from_here, task); + Get()->mMediaThread->message_loop()->PostTask(Move(task)); } /* static */ nsresult @@ -2124,11 +2130,11 @@ MediaManager::GetUserMedia(nsPIDOMWindowInner* aWindow, } // Pass callbacks and MediaStreamListener along to GetUserMediaTask. - nsAutoPtr task (new GetUserMediaTask(c, onSuccess.forget(), - onFailure.forget(), - windowID, listener, - prefs, origin, - devices->release())); + RefPtr task (new GetUserMediaTask(c, onSuccess.forget(), + onFailure.forget(), + windowID, listener, + prefs, origin, + devices->release())); // Store the task w/callbacks. mActiveCallbacks.Put(callID, task.forget()); @@ -2376,9 +2382,9 @@ MediaManager::GetUserMediaDevices(nsPIDOMWindowInner* aWindow, } for (auto& callID : *callIDs) { - GetUserMediaTask* task; + RefPtr task; if (!aCallID.Length() || aCallID == callID) { - if (mActiveCallbacks.Get(callID, &task)) { + if (mActiveCallbacks.Get(callID, getter_AddRefs(task))) { nsCOMPtr array = MediaManager_ToJSArray(*task->mSourceSet); onSuccess->OnSuccess(array); return NS_OK; @@ -2618,15 +2624,15 @@ MediaManager::Shutdown() // Because mMediaThread is not an nsThread, we must dispatch to it so it can // clean up BackgroundChild. Continue stopping thread once this is done. - class ShutdownTask : public Task + class ShutdownTask : public Runnable { public: ShutdownTask(MediaManager* aManager, - Runnable* aReply) + already_AddRefed aReply) : mManager(aManager) , mReply(aReply) {} private: - void + NS_IMETHOD Run() override { LOG(("MediaManager Thread Shutdown")); @@ -2644,6 +2650,8 @@ MediaManager::Shutdown() if (NS_FAILED(NS_DispatchToMainThread(mReply.forget()))) { LOG(("Will leak thread: DispatchToMainthread of reply runnable failed in MediaManager shutdown")); } + + return NS_OK; } RefPtr mManager; RefPtr mReply; @@ -2660,7 +2668,7 @@ MediaManager::Shutdown() RefPtr that(sSingleton); // Release the backend (and call Shutdown()) from within the MediaManager thread // Don't use MediaManager::PostTask() because we're sInShutdown=true here! - mMediaThread->message_loop()->PostTask(FROM_HERE, new ShutdownTask(this, + RefPtr shutdown = new ShutdownTask(this, media::NewRunnableFrom([this, that]() mutable { LOG(("MediaManager shutdown lambda running, releasing MediaManager singleton and thread")); if (mMediaThread) { @@ -2676,7 +2684,8 @@ MediaManager::Shutdown() sSingleton = nullptr; return NS_OK; - }))); + })); + mMediaThread->message_loop()->PostTask(shutdown.forget()); } nsresult @@ -2702,8 +2711,8 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic, } else if (!strcmp(aTopic, "getUserMedia:privileged:allow") || !strcmp(aTopic, "getUserMedia:response:allow")) { nsString key(aData); - nsAutoPtr task; - mActiveCallbacks.RemoveAndForget(key, task); + RefPtr task; + mActiveCallbacks.Remove(key, getter_AddRefs(task)); if (!task) { return NS_OK; } @@ -2750,7 +2759,7 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic, return task->Denied(NS_LITERAL_STRING("In shutdown")); } // Reuse the same thread to save memory. - MediaManager::PostTask(FROM_HERE, task.forget()); + MediaManager::PostTask(task.forget()); return NS_OK; } else if (!strcmp(aTopic, "getUserMedia:response:deny")) { @@ -2765,8 +2774,8 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic, } nsString key(aData); - nsAutoPtr task; - mActiveCallbacks.RemoveAndForget(key, task); + RefPtr task; + mActiveCallbacks.Remove(key, getter_AddRefs(task)); if (task) { task->Denied(errorMessage); } @@ -3086,12 +3095,13 @@ GetUserMediaCallbackMediaStreamListener::Stop() // thread. // Pass a ref to us (which is threadsafe) so it can query us for the // source stream info. - MediaManager::PostTask(FROM_HERE, + RefPtr mediaOperation = new MediaOperationTask(MEDIA_STOP, this, nullptr, nullptr, !mAudioStopped ? mAudioDevice.get() : nullptr, !mVideoStopped ? mVideoDevice.get() : nullptr, - false, mWindowID, nullptr)); + false, mWindowID, nullptr); + MediaManager::PostTask(mediaOperation.forget()); mStopped = mAudioStopped = mVideoStopped = true; } @@ -3151,9 +3161,9 @@ GetUserMediaCallbackMediaStreamListener::ApplyConstraintsToTrack( uint32_t id = mgr->mOutstandingVoidPledges.Append(*p); uint64_t windowId = aWindow->WindowID(); - MediaManager::PostTask(FROM_HERE, NewTaskFrom([id, windowId, - audioDevice, videoDevice, - aConstraints]() mutable { + MediaManager::PostTask(NewTaskFrom([id, windowId, + audioDevice, videoDevice, + aConstraints]() mutable { MOZ_ASSERT(MediaManager::IsInMediaThread()); RefPtr mgr = MediaManager::GetInstance(); const char* badConstraint = nullptr; @@ -3176,8 +3186,8 @@ GetUserMediaCallbackMediaStreamListener::ApplyConstraintsToTrack( videos); } } - NS_DispatchToMainThread(do_AddRef(NewRunnableFrom([id, windowId, rv, - badConstraint]() mutable { + NS_DispatchToMainThread(NewRunnableFrom([id, windowId, rv, + badConstraint]() mutable { MOZ_ASSERT(NS_IsMainThread()); RefPtr mgr = MediaManager_GetInstance(); if (!mgr) { @@ -3209,7 +3219,7 @@ GetUserMediaCallbackMediaStreamListener::ApplyConstraintsToTrack( } } return NS_OK; - }))); + })); })); return p.forget(); } @@ -3246,12 +3256,13 @@ GetUserMediaCallbackMediaStreamListener::StopTrack(TrackID aTrackID) return; } - MediaManager::PostTask(FROM_HERE, + RefPtr mediaOperation = new MediaOperationTask(MEDIA_STOP_TRACK, this, nullptr, nullptr, stopAudio ? mAudioDevice.get() : nullptr, stopVideo ? mVideoDevice.get() : nullptr, - false , mWindowID, nullptr)); + false , mWindowID, nullptr); + MediaManager::PostTask(mediaOperation.forget()); mAudioStopped |= stopAudio; mVideoStopped |= stopVideo; } @@ -3276,11 +3287,12 @@ void GetUserMediaCallbackMediaStreamListener::NotifyDirectListeners(MediaStreamGraph* aGraph, bool aHasListeners) { - MediaManager::PostTask(FROM_HERE, + RefPtr mediaOperation = new MediaOperationTask(MEDIA_DIRECT_LISTENERS, this, nullptr, nullptr, mAudioDevice, mVideoDevice, - aHasListeners, mWindowID, nullptr)); + aHasListeners, mWindowID, nullptr); + MediaManager::PostTask(mediaOperation.forget()); } // this can be in response to our own RemoveListener() (via ::Remove()), or diff --git a/dom/media/MediaManager.h b/dom/media/MediaManager.h index a04ac13c6c..e8d5db8553 100644 --- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -424,7 +424,7 @@ public: static MediaManager* Get(); static MediaManager* GetIfExists(); static void StartupInit(); - static void PostTask(const tracked_objects::Location& from_here, Task* task); + static void PostTask(already_AddRefed task); #ifdef DEBUG static bool IsInMediaThread(); #endif @@ -536,7 +536,7 @@ private: // ONLY access from MainThread so we don't need to lock WindowTable mActiveWindows; - nsClassHashtable mActiveCallbacks; + nsRefPtrHashtable mActiveCallbacks; nsClassHashtable> mCallIds; // Always exists diff --git a/dom/media/SeekTask.cpp b/dom/media/SeekTask.cpp index 0f554189dd..9761f58973 100644 --- a/dom/media/SeekTask.cpp +++ b/dom/media/SeekTask.cpp @@ -86,6 +86,9 @@ SeekTask::SeekTask(const void* aDecoderID, mDropAudioUntilNextDiscontinuity = HasAudio(); mDropVideoUntilNextDiscontinuity = HasVideo(); + + // Configure MediaDecoderReaderWrapper. + SetMediaDecoderReaderWrapperCallback(); } SeekTask::~SeekTask() @@ -152,12 +155,11 @@ SeekTask::Discard() // Disconnect MDSM. RejectIfExist(__func__); - // Disconnect MediaDecoderReader. + // Disconnect MediaDecoderReaderWrapper. mSeekRequest.DisconnectIfExists(); - mAudioDataRequest.DisconnectIfExists(); - mVideoDataRequest.DisconnectIfExists(); mAudioWaitRequest.DisconnectIfExists(); mVideoWaitRequest.DisconnectIfExists(); + CancelMediaDecoderReaderWrapperCallback(); mIsDiscarded = true; } @@ -216,7 +218,7 @@ SeekTask::EnsureAudioDecodeTaskQueued() IsAudioDecoding(), AudioRequestStatus()); if (!IsAudioDecoding() || - mAudioDataRequest.Exists() || + mReader->IsRequestingAudioData() || mAudioWaitRequest.Exists() || mSeekRequest.Exists()) { return NS_OK; @@ -235,7 +237,7 @@ SeekTask::EnsureVideoDecodeTaskQueued() IsVideoDecoding(), VideoRequestStatus()); if (!IsVideoDecoding() || - mVideoDataRequest.Exists() || + mReader->IsRequestingVidoeData() || mVideoWaitRequest.Exists() || mSeekRequest.Exists()) { return NS_OK; @@ -249,7 +251,7 @@ const char* SeekTask::AudioRequestStatus() { AssertOwnerThread(); - if (mAudioDataRequest.Exists()) { + if (mReader->IsRequestingAudioData()) { MOZ_DIAGNOSTIC_ASSERT(!mAudioWaitRequest.Exists()); return "pending"; } else if (mAudioWaitRequest.Exists()) { @@ -262,7 +264,7 @@ const char* SeekTask::VideoRequestStatus() { AssertOwnerThread(); - if (mVideoDataRequest.Exists()) { + if (mReader->IsRequestingVidoeData()) { MOZ_DIAGNOSTIC_ASSERT(!mVideoWaitRequest.Exists()); return "pending"; } else if (mVideoWaitRequest.Exists()) { @@ -279,9 +281,7 @@ SeekTask::RequestAudioData() SAMPLE_LOG("Queueing audio task - queued=%i, decoder-queued=%o", !!mSeekedAudioData, mReader->SizeOfAudioQueueInFrames()); - mAudioDataRequest.Begin(mReader->RequestAudioData() - ->Then(OwnerThread(), __func__, this, - &SeekTask::OnAudioDecoded, &SeekTask::OnAudioNotDecoded)); + mReader->RequestAudioData(); } void @@ -296,10 +296,7 @@ SeekTask::RequestVideoData() !!mSeekedVideoData, mReader->SizeOfVideoQueueInFrames(), skipToNextKeyFrame, currentTime.ToMicroseconds()); - mVideoDataRequest.Begin( - mReader->RequestVideoData(skipToNextKeyFrame, currentTime) - ->Then(OwnerThread(), __func__, this, - &SeekTask::OnVideoDecoded, &SeekTask::OnVideoNotDecoded)); + mReader->RequestVideoData(skipToNextKeyFrame, currentTime); } nsresult @@ -500,7 +497,6 @@ SeekTask::OnAudioDecoded(MediaData* aAudioSample) AssertOwnerThread(); RefPtr audio(aAudioSample); MOZ_ASSERT(audio); - mAudioDataRequest.Complete(); // The MDSM::mDecodedAudioEndTime will be updated once the whole SeekTask is // resolved. @@ -553,7 +549,6 @@ SeekTask::OnAudioNotDecoded(MediaDecoderReader::NotDecodedReason aReason) { AssertOwnerThread(); SAMPLE_LOG("OnAduioNotDecoded (aReason=%u)", aReason); - mAudioDataRequest.Complete(); if (aReason == MediaDecoderReader::DECODE_ERROR) { // If this is a decode error, delegate to the generic error path. @@ -602,7 +597,6 @@ SeekTask::OnVideoDecoded(MediaData* aVideoSample) AssertOwnerThread(); RefPtr video(aVideoSample); MOZ_ASSERT(video); - mVideoDataRequest.Complete(); // The MDSM::mDecodedVideoEndTime will be updated once the whole SeekTask is // resolved. @@ -657,7 +651,6 @@ SeekTask::OnVideoNotDecoded(MediaDecoderReader::NotDecodedReason aReason) { AssertOwnerThread(); SAMPLE_LOG("OnVideoNotDecoded (aReason=%u)", aReason); - mVideoDataRequest.Complete(); if (aReason == MediaDecoderReader::DECODE_ERROR) { // If this is a decode error, delegate to the generic error path. @@ -710,4 +703,28 @@ SeekTask::OnVideoNotDecoded(MediaDecoderReader::NotDecodedReason aReason) } } +void +SeekTask::SetMediaDecoderReaderWrapperCallback() +{ + mAudioCallbackID = + mReader->SetAudioCallback(this, &SeekTask::OnAudioDecoded, + &SeekTask::OnAudioNotDecoded); + + mVideoCallbackID = + mReader->SetVideoCallback(this, &SeekTask::OnVideoDecoded, + &SeekTask::OnVideoNotDecoded); + + DECODER_LOG("SeekTask set audio callbacks: mAudioCallbackID = %d\n", (int)mAudioCallbackID); + DECODER_LOG("SeekTask set video callbacks: mVideoCallbackID = %d\n", (int)mAudioCallbackID); +} + +void +SeekTask::CancelMediaDecoderReaderWrapperCallback() +{ + DECODER_LOG("SeekTask cancel audio callbacks: mVideoCallbackID = %d\n", (int)mAudioCallbackID); + mReader->CancelAudioCallback(mAudioCallbackID); + + DECODER_LOG("SeekTask cancel video callbacks: mVideoCallbackID = %d\n", (int)mVideoCallbackID); + mReader->CancelVideoCallback(mVideoCallbackID); +} } // namespace mozilla diff --git a/dom/media/SeekTask.h b/dom/media/SeekTask.h index 62199a8e17..9929b27b5e 100644 --- a/dom/media/SeekTask.h +++ b/dom/media/SeekTask.h @@ -8,6 +8,7 @@ #define SEEK_TASK_H #include "mozilla/MozPromise.h" +#include "MediaCallbackID.h" #include "MediaDecoderReader.h" #include "SeekJob.h" @@ -127,6 +128,10 @@ protected: virtual void OnVideoNotDecoded(MediaDecoderReader::NotDecodedReason aReason); + void SetMediaDecoderReaderWrapperCallback(); + + void CancelMediaDecoderReaderWrapperCallback(); + /* * Data shared with MDSM. */ @@ -157,8 +162,8 @@ protected: * Track the current seek promise made by the reader. */ MozPromiseRequestHolder mSeekRequest; - MozPromiseRequestHolder mAudioDataRequest; - MozPromiseRequestHolder mVideoDataRequest; + CallbackID mAudioCallbackID; + CallbackID mVideoCallbackID; MozPromiseRequestHolder mAudioWaitRequest; MozPromiseRequestHolder mVideoWaitRequest; diff --git a/dom/media/gmp/GMPChild.cpp b/dom/media/gmp/GMPChild.cpp index b1da035e74..331b13d81f 100644 --- a/dom/media/gmp/GMPChild.cpp +++ b/dom/media/gmp/GMPChild.cpp @@ -617,8 +617,9 @@ GMPChild::GMPContentChildActorDestroy(GMPContentChild* aGMPContentChild) UniquePtr& toDestroy = mGMPContentChildren[i - 1]; if (toDestroy.get() == aGMPContentChild) { SendPGMPContentChildDestroyed(); - MessageLoop::current()->PostTask(FROM_HERE, - new DeleteTask(toDestroy.release())); + RefPtr> task = + new DeleteTask(toDestroy.release()); + MessageLoop::current()->PostTask(task.forget()); mGMPContentChildren.RemoveElementAt(i - 1); break; } diff --git a/dom/media/gmp/GMPContentChild.cpp b/dom/media/gmp/GMPContentChild.cpp index 9c35b03874..523d279fc4 100644 --- a/dom/media/gmp/GMPContentChild.cpp +++ b/dom/media/gmp/GMPContentChild.cpp @@ -22,8 +22,8 @@ GMPContentChild::GMPContentChild(GMPChild* aChild) GMPContentChild::~GMPContentChild() { MOZ_COUNT_DTOR(GMPContentChild); - XRE_GetIOMessageLoop()->PostTask(FROM_HERE, - new DeleteTask(GetTransport())); + RefPtr> task = new DeleteTask(GetTransport()); + XRE_GetIOMessageLoop()->PostTask(task.forget()); } MessageLoop* diff --git a/dom/media/gmp/GMPContentParent.cpp b/dom/media/gmp/GMPContentParent.cpp index e672f74955..83d523c91a 100644 --- a/dom/media/gmp/GMPContentParent.cpp +++ b/dom/media/gmp/GMPContentParent.cpp @@ -43,8 +43,8 @@ GMPContentParent::GMPContentParent(GMPParent* aParent) GMPContentParent::~GMPContentParent() { - XRE_GetIOMessageLoop()->PostTask(FROM_HERE, - new DeleteTask(GetTransport())); + RefPtr> task = new DeleteTask(GetTransport()); + XRE_GetIOMessageLoop()->PostTask(task.forget()); } class ReleaseGMPContentParent : public Runnable diff --git a/dom/media/gmp/GMPDecryptorChild.cpp b/dom/media/gmp/GMPDecryptorChild.cpp index aec5078e45..0627aad15e 100644 --- a/dom/media/gmp/GMPDecryptorChild.cpp +++ b/dom/media/gmp/GMPDecryptorChild.cpp @@ -61,8 +61,8 @@ GMPDecryptorChild::CallOnGMPThread(MethodType aMethod, ParamType&&... aParams) // Use const reference when we have to. auto m = &GMPDecryptorChild::CallMethod< decltype(aMethod), typename AddConstReference::Type...>; - auto t = NewRunnableMethod(this, m, aMethod, Forward(aParams)...); - mPlugin->GMPMessageLoop()->PostTask(FROM_HERE, t); + RefPtr t = NewRunnableMethod(this, m, aMethod, Forward(aParams)...); + mPlugin->GMPMessageLoop()->PostTask(t.forget()); } } @@ -170,8 +170,8 @@ GMPDecryptorChild::Decrypted(GMPBuffer* aBuffer, GMPErr aResult) if (!ON_GMP_THREAD()) { // We should run this whole method on the GMP thread since the buffer needs // to be deleted after the SendDecrypted call. - auto t = NewRunnableMethod(this, &GMPDecryptorChild::Decrypted, aBuffer, aResult); - mPlugin->GMPMessageLoop()->PostTask(FROM_HERE, t); + RefPtr t = NewRunnableMethod(this, &GMPDecryptorChild::Decrypted, aBuffer, aResult); + mPlugin->GMPMessageLoop()->PostTask(t.forget()); return; } diff --git a/dom/media/gmp/GMPPlatform.cpp b/dom/media/gmp/GMPPlatform.cpp index e06673070c..05c513209b 100644 --- a/dom/media/gmp/GMPPlatform.cpp +++ b/dom/media/gmp/GMPPlatform.cpp @@ -73,7 +73,7 @@ public: // main thread tries to do a sync call back to the calling thread. MOZ_ASSERT(!IsOnChildMainThread()); - mMessageLoop->PostTask(FROM_HERE, NewRunnableMethod(this, &SyncRunnable::Run)); + mMessageLoop->PostTask(NewRunnableMethod(this, &SyncRunnable::Run)); MonitorAutoLock lock(mMonitor); while (!mDone) { lock.Wait(); @@ -121,7 +121,7 @@ RunOnMainThread(GMPTask* aTask) } RefPtr r = new Runnable(aTask); - sMainLoop->PostTask(FROM_HERE, NewRunnableMethod(r.get(), &Runnable::Run)); + sMainLoop->PostTask(NewRunnableMethod(r.get(), &Runnable::Run)); return GMPNoErr; } @@ -254,7 +254,7 @@ GMPThreadImpl::Post(GMPTask* aTask) RefPtr r = new Runnable(aTask); - mThread.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(r.get(), &Runnable::Run)); + mThread.message_loop()->PostTask(NewRunnableMethod(r.get(), &Runnable::Run)); } void diff --git a/dom/media/gmp/GMPProcessParent.cpp b/dom/media/gmp/GMPProcessParent.cpp index 5782e7b202..94116c56e4 100644 --- a/dom/media/gmp/GMPProcessParent.cpp +++ b/dom/media/gmp/GMPProcessParent.cpp @@ -85,7 +85,7 @@ void GMPProcessParent::Delete(nsCOMPtr aCallback) { mDeletedCallback = aCallback; - XRE_GetIOMessageLoop()->PostTask(FROM_HERE, NewRunnableMethod(this, &GMPProcessParent::DoDelete)); + XRE_GetIOMessageLoop()->PostTask(NewRunnableMethod(this, &GMPProcessParent::DoDelete)); } void diff --git a/dom/media/gmp/GMPServiceChild.cpp b/dom/media/gmp/GMPServiceChild.cpp index ef69535515..9c1f941ad2 100644 --- a/dom/media/gmp/GMPServiceChild.cpp +++ b/dom/media/gmp/GMPServiceChild.cpp @@ -251,8 +251,8 @@ GMPServiceChild::GMPServiceChild() GMPServiceChild::~GMPServiceChild() { - XRE_GetIOMessageLoop()->PostTask(FROM_HERE, - new DeleteTask(GetTransport())); + RefPtr> task = new DeleteTask(GetTransport()); + XRE_GetIOMessageLoop()->PostTask(task.forget()); } PGMPContentParent* diff --git a/dom/media/gmp/GMPServiceParent.cpp b/dom/media/gmp/GMPServiceParent.cpp index 97bff89421..ac8b60ce8f 100644 --- a/dom/media/gmp/GMPServiceParent.cpp +++ b/dom/media/gmp/GMPServiceParent.cpp @@ -1774,8 +1774,8 @@ GeckoMediaPluginServiceParent::ClearStorage() GMPServiceParent::~GMPServiceParent() { - XRE_GetIOMessageLoop()->PostTask(FROM_HERE, - new DeleteTask(GetTransport())); + RefPtr> task = new DeleteTask(GetTransport()); + XRE_GetIOMessageLoop()->PostTask(task.forget()); } bool diff --git a/dom/media/gmp/GMPStorageChild.cpp b/dom/media/gmp/GMPStorageChild.cpp index b10858ea43..62056cd8ff 100644 --- a/dom/media/gmp/GMPStorageChild.cpp +++ b/dom/media/gmp/GMPStorageChild.cpp @@ -15,7 +15,7 @@ _func(__VA_ARGS__); \ } else { \ mPlugin->GMPMessageLoop()->PostTask( \ - FROM_HERE, NewRunnableMethod(this, &GMPStorageChild::_func, ##__VA_ARGS__) \ + NewRunnableMethod(this, &GMPStorageChild::_func, ##__VA_ARGS__) \ ); \ } \ } while(false) diff --git a/dom/media/gmp/GMPVideoDecoderChild.cpp b/dom/media/gmp/GMPVideoDecoderChild.cpp index e97cb3f1d8..4d0074a272 100644 --- a/dom/media/gmp/GMPVideoDecoderChild.cpp +++ b/dom/media/gmp/GMPVideoDecoderChild.cpp @@ -226,8 +226,7 @@ GMPVideoDecoderChild::Alloc(size_t aSize, rv = CallNeedShmem(aSize, aMem); --mNeedShmemIntrCount; if (mPendingDecodeComplete) { - auto t = NewRunnableMethod(this, &GMPVideoDecoderChild::RecvDecodingComplete); - mPlugin->GMPMessageLoop()->PostTask(FROM_HERE, t); + mPlugin->GMPMessageLoop()->PostTask(NewRunnableMethod(this, &GMPVideoDecoderChild::RecvDecodingComplete)); } #else #ifdef GMP_SAFE_SHMEM diff --git a/dom/media/gmp/GMPVideoEncoderChild.cpp b/dom/media/gmp/GMPVideoEncoderChild.cpp index 54e715f776..319450cb0d 100644 --- a/dom/media/gmp/GMPVideoEncoderChild.cpp +++ b/dom/media/gmp/GMPVideoEncoderChild.cpp @@ -207,8 +207,7 @@ GMPVideoEncoderChild::Alloc(size_t aSize, rv = CallNeedShmem(aSize, aMem); --mNeedShmemIntrCount; if (mPendingEncodeComplete) { - auto t = NewRunnableMethod(this, &GMPVideoEncoderChild::RecvEncodingComplete); - mPlugin->GMPMessageLoop()->PostTask(FROM_HERE, t); + mPlugin->GMPMessageLoop()->PostTask(NewRunnableMethod(this, &GMPVideoEncoderChild::RecvEncodingComplete)); } #else #ifdef GMP_SAFE_SHMEM diff --git a/dom/media/moz.build b/dom/media/moz.build index 2ff6fdc963..e4a64fe34d 100644 --- a/dom/media/moz.build +++ b/dom/media/moz.build @@ -105,6 +105,7 @@ EXPORTS += [ 'Intervals.h', 'Latency.h', 'MediaCache.h', + 'MediaCallbackID.h', 'MediaData.h', 'MediaDataDemuxer.h', 'MediaDecoder.h', @@ -215,6 +216,7 @@ UNIFIED_SOURCES += [ 'GraphDriver.cpp', 'Latency.cpp', 'MediaCache.cpp', + 'MediaCallbackID.cpp', 'MediaData.cpp', 'MediaDecoder.cpp', 'MediaDecoderReader.cpp', diff --git a/dom/media/omx/MediaOmxReader.cpp b/dom/media/omx/MediaOmxReader.cpp index d8a8c38719..441e32e390 100644 --- a/dom/media/omx/MediaOmxReader.cpp +++ b/dom/media/omx/MediaOmxReader.cpp @@ -31,7 +31,7 @@ namespace mozilla { extern LazyLogModule gMediaDecoderLog; #define DECODER_LOG(type, msg) MOZ_LOG(gMediaDecoderLog, type, msg) -class MediaOmxReader::ProcessCachedDataTask : public Task +class MediaOmxReader::ProcessCachedDataTask : public Runnable { public: ProcessCachedDataTask(MediaOmxReader* aOmxReader, int64_t aOffset) @@ -39,11 +39,12 @@ public: mOffset(aOffset) { } - void Run() + NS_IMETHOD Run() override { MOZ_ASSERT(!NS_IsMainThread()); MOZ_ASSERT(mOmxReader.get()); mOmxReader->ProcessCachedData(mOffset); + return NS_OK; } private: @@ -105,8 +106,8 @@ private: // We cannot read data in the main thread because it // might block for too long. Instead we post an IO task // to the IO thread if there is more data available. - XRE_GetIOMessageLoop()->PostTask(FROM_HERE, - new ProcessCachedDataTask(mOmxReader.get(), mOffset)); + RefPtr task = new ProcessCachedDataTask(mOmxReader.get(), mOffset); + XRE_GetIOMessageLoop()->PostTask(task.forget()); } } diff --git a/dom/media/platforms/wmf/WMFDecoderModule.cpp b/dom/media/platforms/wmf/WMFDecoderModule.cpp index d45be3d4a5..29b4d6c7a4 100644 --- a/dom/media/platforms/wmf/WMFDecoderModule.cpp +++ b/dom/media/platforms/wmf/WMFDecoderModule.cpp @@ -17,6 +17,7 @@ #include "nsComponentManagerUtils.h" #include "nsServiceManagerUtils.h" #include "nsIGfxInfo.h" +#include "nsWindowsHelpers.h" #include "GfxDriverInfo.h" #include "gfxWindowsPlatform.h" #include "MediaInfo.h" @@ -165,9 +166,45 @@ CanCreateWMFDecoder() return result.value(); } +static bool +IsH264DecoderBlacklisted() +{ +#ifdef BLACKLIST_CRASHY_H264_DECODERS + WCHAR systemPath[MAX_PATH + 1]; + if (!ConstructSystem32Path(L"msmpeg2vdec.dll", systemPath, MAX_PATH + 1)) { + // Cannot build path -> Assume it's not the blacklisted DLL. + return false; + } + + DWORD zero; + DWORD infoSize = GetFileVersionInfoSizeW(systemPath, &zero); + if (infoSize == 0) { + // Can't get file info -> Assume we don't have the blacklisted DLL. + return false; + } + auto infoData = MakeUnique(infoSize); + VS_FIXEDFILEINFO *vInfo; + UINT vInfoLen; + if (GetFileVersionInfoW(systemPath, 0, infoSize, infoData.get()) && + VerQueryValueW(infoData.get(), L"\\", (LPVOID*)&vInfo, &vInfoLen)) + { + if ((vInfo->dwFileVersionMS == ((12u << 16) | 0u)) + && ((vInfo->dwFileVersionLS == ((9200u << 16) | 16426u)) + || (vInfo->dwFileVersionLS == ((9200u << 16) | 17037u)))) { + // 12.0.9200.16426 & .17037 are blacklisted on Win64, see bug 1242343. + return true; + } + } +#endif // BLACKLIST_CRASHY_H264_DECODERS + return false; +} + /* static */ bool WMFDecoderModule::HasH264() { + if (IsH264DecoderBlacklisted()) { + return false; + } return CanCreateWMFDecoder(); } diff --git a/dom/media/systemservices/CamerasParent.cpp b/dom/media/systemservices/CamerasParent.cpp index a5ff05dfde..ebd73d8c89 100644 --- a/dom/media/systemservices/CamerasParent.cpp +++ b/dom/media/systemservices/CamerasParent.cpp @@ -165,7 +165,7 @@ CamerasParent::Observe(nsISupports *aSubject, } nsresult -CamerasParent::DispatchToVideoCaptureThread(Runnable *event) +CamerasParent::DispatchToVideoCaptureThread(Runnable* event) { // Don't try to dispatch if we're already on the right thread. // There's a potential deadlock because the mThreadMonitor is likely @@ -182,8 +182,8 @@ CamerasParent::DispatchToVideoCaptureThread(Runnable *event) if (!mVideoCaptureThread || !mVideoCaptureThread->IsRunning()) { return NS_ERROR_FAILURE; } - mVideoCaptureThread->message_loop()->PostTask(FROM_HERE, - new RunnableTask(event)); + RefPtr addrefedEvent = event; + mVideoCaptureThread->message_loop()->PostTask(addrefedEvent.forget()); return NS_OK; } diff --git a/dom/media/systemservices/CamerasParent.h b/dom/media/systemservices/CamerasParent.h index becdd435e6..5ba3541308 100644 --- a/dom/media/systemservices/CamerasParent.h +++ b/dom/media/systemservices/CamerasParent.h @@ -129,7 +129,8 @@ protected: void CloseEngines(); void StopIPC(); void StopVideoCapture(); - nsresult DispatchToVideoCaptureThread(Runnable *event); + // Can't take already_AddRefed because it can fail in stupid ways. + nsresult DispatchToVideoCaptureThread(Runnable* event); EngineHelper mEngines[CaptureEngine::MaxEngine]; nsTArray mCallbacks; diff --git a/dom/media/systemservices/CamerasUtils.h b/dom/media/systemservices/CamerasUtils.h index dc4947ac85..b52a121ea7 100644 --- a/dom/media/systemservices/CamerasUtils.h +++ b/dom/media/systemservices/CamerasUtils.h @@ -39,21 +39,6 @@ private: nsCOMPtr mThread; }; -class RunnableTask : public Task -{ -public: - explicit RunnableTask(Runnable* aRunnable) - : mRunnable(aRunnable) {} - - void Run() override { - mRunnable->Run(); - } - -private: - ~RunnableTask() {} - RefPtr mRunnable; -}; - } } diff --git a/dom/media/systemservices/MediaSystemResourceManager.cpp b/dom/media/systemservices/MediaSystemResourceManager.cpp index bb49010109..75fd5f54a8 100644 --- a/dom/media/systemservices/MediaSystemResourceManager.cpp +++ b/dom/media/systemservices/MediaSystemResourceManager.cpp @@ -39,20 +39,6 @@ MediaSystemResourceManager::Shutdown() } } -class RunnableCallTask : public Task -{ -public: - explicit RunnableCallTask(nsIRunnable* aRunnable) - : mRunnable(aRunnable) {} - - void Run() override - { - mRunnable->Run(); - } -protected: - nsCOMPtr mRunnable; -}; - /* static */ void MediaSystemResourceManager::Init() { @@ -77,7 +63,7 @@ MediaSystemResourceManager::Init() ReentrantMonitorAutoEnter autoMon(barrier); bool done = false; - nsCOMPtr runnable = + RefPtr runnable = NS_NewRunnableFunction([&]() { if (!sSingleton) { sSingleton = new MediaSystemResourceManager(); @@ -87,8 +73,7 @@ MediaSystemResourceManager::Init() barrier.NotifyAll(); }); - ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask( - FROM_HERE, new RunnableCallTask(runnable)); + ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(runnable.forget()); // should stop the thread until done. while (!done) { @@ -214,7 +199,6 @@ MediaSystemResourceManager::Acquire(MediaSystemResourceClient* aClient) } aClient->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_WAITING; ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask( - FROM_HERE, NewRunnableMethod( this, &MediaSystemResourceManager::DoAcquire, @@ -260,7 +244,6 @@ MediaSystemResourceManager::AcquireSyncNoWait(MediaSystemResourceClient* aClient } ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask( - FROM_HERE, NewRunnableMethod( this, &MediaSystemResourceManager::DoAcquire, @@ -328,7 +311,6 @@ MediaSystemResourceManager::ReleaseResource(MediaSystemResourceClient* aClient) aClient->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_END; ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask( - FROM_HERE, NewRunnableMethod( this, &MediaSystemResourceManager::DoRelease, @@ -357,7 +339,6 @@ MediaSystemResourceManager::HandleAcquireResult(uint32_t aId, bool aSuccess) { if (!InImageBridgeChildThread()) { ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask( - FROM_HERE, NewRunnableMethod( this, &MediaSystemResourceManager::HandleAcquireResult, diff --git a/dom/media/systemservices/MediaUtils.h b/dom/media/systemservices/MediaUtils.h index b76ee30a61..cc73204af3 100644 --- a/dom/media/systemservices/MediaUtils.h +++ b/dom/media/systemservices/MediaUtils.h @@ -200,31 +200,36 @@ private: }; template -LambdaRunnable* +already_AddRefed> NewRunnableFrom(OnRunType&& aOnRun) { - return new LambdaRunnable(Forward(aOnRun)); + typedef LambdaRunnable LambdaType; + RefPtr lambda = new LambdaType(Forward(aOnRun)); + return lambda.forget(); } template -class LambdaTask : public Task +class LambdaTask : public Runnable { public: explicit LambdaTask(OnRunType&& aOnRun) : mOnRun(Move(aOnRun)) {} private: - void - Run() + NS_IMETHOD + Run() override { - return mOnRun(); + mOnRun(); + return NS_OK; } OnRunType mOnRun; }; template -LambdaTask* +already_AddRefed> NewTaskFrom(OnRunType&& aOnRun) { - return new LambdaTask(Forward(aOnRun)); + typedef LambdaTask LambdaType; + RefPtr lambda = new LambdaType(Forward(aOnRun)); + return lambda.forget(); } /* media::CoatCheck - There and back again. Park an object in exchange for an id. diff --git a/dom/media/webaudio/blink/ReverbConvolver.cpp b/dom/media/webaudio/blink/ReverbConvolver.cpp index de707fe33a..712ba6420d 100644 --- a/dom/media/webaudio/blink/ReverbConvolver.cpp +++ b/dom/media/webaudio/blink/ReverbConvolver.cpp @@ -158,8 +158,8 @@ ReverbConvolver::ReverbConvolver(const float* impulseResponseData, NS_WARNING("Cannot start convolver thread."); return; } - CancelableTask* task = NewRunnableMethod(this, &ReverbConvolver::backgroundThreadEntry); - m_backgroundThread.message_loop()->PostTask(FROM_HERE, task); + m_backgroundThread.message_loop()->PostTask( + NewRunnableMethod(this, &ReverbConvolver::backgroundThreadEntry)); } } diff --git a/dom/moz.build b/dom/moz.build index 20e444c85f..be4027a107 100644 --- a/dom/moz.build +++ b/dom/moz.build @@ -46,7 +46,6 @@ DIRS += [ 'bluetooth', 'activities', 'archivereader', - 'requestsync', 'bindings', 'battery', 'browser-element', diff --git a/dom/plugins/base/nsPluginHost.cpp b/dom/plugins/base/nsPluginHost.cpp index 25a04e37fa..c35c39c607 100644 --- a/dom/plugins/base/nsPluginHost.cpp +++ b/dom/plugins/base/nsPluginHost.cpp @@ -3378,7 +3378,8 @@ nsresult nsPluginHost::NewPluginURLStream(const nsString& aURL, // in case aURL is relative RefPtr owner = aInstance->GetOwner(); if (owner) { - rv = NS_MakeAbsoluteURI(absUrl, aURL, nsCOMPtr(owner->GetBaseURI())); + nsCOMPtr baseURI = owner->GetBaseURI(); + rv = NS_MakeAbsoluteURI(absUrl, aURL, baseURI); } if (absUrl.IsEmpty()) diff --git a/dom/plugins/base/nsPluginStreamListenerPeer.cpp b/dom/plugins/base/nsPluginStreamListenerPeer.cpp index 23e30e124d..a7d771f43f 100644 --- a/dom/plugins/base/nsPluginStreamListenerPeer.cpp +++ b/dom/plugins/base/nsPluginStreamListenerPeer.cpp @@ -103,7 +103,10 @@ nsPluginByteRangeStreamListener::OnStartRequest(nsIRequest *request, nsISupports nsPluginStreamListenerPeer *pslp = static_cast(finalStreamListener.get()); - NS_ASSERTION(pslp->mRequests.IndexOfObject(GetBaseRequest(request)) != -1, +#ifdef DEBUG + nsCOMPtr baseRequest = GetBaseRequest(request); +#endif + NS_ASSERTION(pslp->mRequests.IndexOfObject(baseRequest) != -1, "Untracked byte-range request?"); nsCOMPtr serv = do_GetService(NS_STREAMCONVERTERSERVICE_CONTRACTID, &rv); @@ -430,7 +433,8 @@ nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request, PROFILER_LABEL("nsPluginStreamListenerPeer", "OnStartRequest", js::ProfileEntry::Category::OTHER); - if (mRequests.IndexOfObject(GetBaseRequest(request)) == -1) { + nsCOMPtr baseRequest = GetBaseRequest(request); + if (mRequests.IndexOfObject(baseRequest) == -1) { NS_ASSERTION(mRequests.Count() == 0, "Only our initial stream should be unknown!"); TrackRequest(request); @@ -833,7 +837,8 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request, uint64_t sourceOffset, uint32_t aLength) { - if (mRequests.IndexOfObject(GetBaseRequest(request)) == -1) { + nsCOMPtr baseRequest = GetBaseRequest(request); + if (mRequests.IndexOfObject(baseRequest) == -1) { MOZ_ASSERT(false, "Received OnDataAvailable for untracked request."); return NS_ERROR_UNEXPECTED; } diff --git a/dom/plugins/ipc/BrowserStreamChild.cpp b/dom/plugins/ipc/BrowserStreamChild.cpp index d7cb626974..4fdfc1d471 100644 --- a/dom/plugins/ipc/BrowserStreamChild.cpp +++ b/dom/plugins/ipc/BrowserStreamChild.cpp @@ -190,7 +190,7 @@ BrowserStreamChild::NPN_DestroyStream(NPReason reason) void BrowserStreamChild::EnsureDeliveryPending() { - MessageLoop::current()->PostTask(FROM_HERE, + MessageLoop::current()->PostTask( mDeliveryTracker.NewRunnableMethod(&BrowserStreamChild::Deliver)); } diff --git a/dom/plugins/ipc/ChildAsyncCall.cpp b/dom/plugins/ipc/ChildAsyncCall.cpp index d2346012dd..6adc05d559 100644 --- a/dom/plugins/ipc/ChildAsyncCall.cpp +++ b/dom/plugins/ipc/ChildAsyncCall.cpp @@ -19,12 +19,13 @@ ChildAsyncCall::ChildAsyncCall(PluginInstanceChild* instance, { } -void +nsresult ChildAsyncCall::Cancel() { mInstance = nullptr; mFunc = nullptr; mData = nullptr; + return NS_OK; } void @@ -36,13 +37,15 @@ ChildAsyncCall::RemoveFromAsyncList() } } -void +NS_IMETHODIMP ChildAsyncCall::Run() { RemoveFromAsyncList(); if (mFunc) mFunc(mData); + + return NS_OK; } } // namespace plugins diff --git a/dom/plugins/ipc/ChildAsyncCall.h b/dom/plugins/ipc/ChildAsyncCall.h index feaf84a9d4..ae5c45a932 100644 --- a/dom/plugins/ipc/ChildAsyncCall.h +++ b/dom/plugins/ipc/ChildAsyncCall.h @@ -9,7 +9,7 @@ #define mozilla_plugins_ChildAsyncCall_h #include "PluginMessageUtils.h" -#include "base/task.h" +#include "nsThreadUtils.h" namespace mozilla { namespace plugins { @@ -18,14 +18,14 @@ typedef void (*PluginThreadCallback)(void*); class PluginInstanceChild; -class ChildAsyncCall : public CancelableTask +class ChildAsyncCall : public CancelableRunnable { public: ChildAsyncCall(PluginInstanceChild* instance, PluginThreadCallback aFunc, void* aUserData); - void Run() override; - void Cancel() override; + NS_IMETHOD Run() override; + nsresult Cancel() override; protected: PluginInstanceChild* mInstance; diff --git a/dom/plugins/ipc/PluginInstanceChild.cpp b/dom/plugins/ipc/PluginInstanceChild.cpp index 536256eca4..5de8453a08 100644 --- a/dom/plugins/ipc/PluginInstanceChild.cpp +++ b/dom/plugins/ipc/PluginInstanceChild.cpp @@ -195,8 +195,6 @@ PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface, , mAccumulatedInvalidRect(0,0,0,0) , mIsTransparent(false) , mSurfaceType(gfxSurfaceType::Max) - , mCurrentInvalidateTask(nullptr) - , mCurrentAsyncSetWindowTask(nullptr) , mPendingPluginCall(false) , mDoAlphaExtraction(false) , mHasPainted(false) @@ -2624,7 +2622,7 @@ PluginInstanceChild::FlashThrottleAsyncMsg::GetProc() return nullptr; } -void +NS_IMETHODIMP PluginInstanceChild::FlashThrottleAsyncMsg::Run() { RemoveFromAsyncList(); @@ -2633,10 +2631,11 @@ PluginInstanceChild::FlashThrottleAsyncMsg::Run() // PluginInstanceChild. We don't transport sub-class procedure // ptrs around in FlashThrottleAsyncMsg msgs. if (!GetProc()) - return; + return NS_OK; // deliver the event to flash CallWindowProc(GetProc(), GetWnd(), GetMsg(), GetWParam(), GetLParam()); + return NS_OK; } void @@ -2648,14 +2647,15 @@ PluginInstanceChild::FlashThrottleMessage(HWND aWnd, { // We reuse ChildAsyncCall so we get the cancelation work // that's done in Destroy. - FlashThrottleAsyncMsg* task = new FlashThrottleAsyncMsg(this, - aWnd, aMsg, aWParam, aLParam, isWindowed); + RefPtr task = + new FlashThrottleAsyncMsg(this, aWnd, aMsg, aWParam, + aLParam, isWindowed); { MutexAutoLock lock(mAsyncCallMutex); mPendingAsyncCalls.AppendElement(task); } - MessageLoop::current()->PostDelayedTask(FROM_HERE, - task, kFlashWMUSERMessageThrottleDelayMs); + MessageLoop::current()->PostDelayedTask(task.forget(), + kFlashWMUSERMessageThrottleDelayMs); } #endif // OS_WIN @@ -2797,7 +2797,7 @@ public: { } - void Run() override + NS_IMETHOD Run() override { RemoveFromAsyncList(); @@ -2807,6 +2807,7 @@ public: DebugOnly sendOk = mBrowserStreamChild->SendAsyncNPP_NewStreamResult(rv, stype); MOZ_ASSERT(sendOk); + return NS_OK; } private: @@ -2822,9 +2823,9 @@ PluginInstanceChild::RecvAsyncNPP_NewStream(PBrowserStreamChild* actor, { // Reusing ChildAsyncCall so that the task is cancelled properly on Destroy BrowserStreamChild* child = static_cast(actor); - NewStreamAsyncCall* task = new NewStreamAsyncCall(this, child, mimeType, - seekable); - PostChildAsyncCall(task); + RefPtr task = + new NewStreamAsyncCall(this, child, mimeType, seekable); + PostChildAsyncCall(task.forget()); return true; } @@ -3303,7 +3304,8 @@ PluginInstanceChild::RecvAsyncSetWindow(const gfxSurfaceType& aSurfaceType, const gfxSurfaceType&, const NPRemoteWindow&, bool> (this, &PluginInstanceChild::DoAsyncSetWindow, aSurfaceType, aWindow, true); - MessageLoop::current()->PostTask(FROM_HERE, mCurrentAsyncSetWindowTask); + RefPtr addrefedTask = mCurrentAsyncSetWindowTask; + MessageLoop::current()->PostTask(addrefedTask.forget()); return true; } @@ -4222,7 +4224,8 @@ PluginInstanceChild::AsyncShowPluginFrame(void) mCurrentInvalidateTask = NewRunnableMethod(this, &PluginInstanceChild::InvalidateRectDelayed); - MessageLoop::current()->PostTask(FROM_HERE, mCurrentInvalidateTask); + RefPtr addrefedTask = mCurrentInvalidateTask; + MessageLoop::current()->PostTask(addrefedTask.forget()); } void @@ -4378,18 +4381,20 @@ PluginInstanceChild::UnscheduleTimer(uint32_t id) void PluginInstanceChild::AsyncCall(PluginThreadCallback aFunc, void* aUserData) { - ChildAsyncCall* task = new ChildAsyncCall(this, aFunc, aUserData); - PostChildAsyncCall(task); + RefPtr task = new ChildAsyncCall(this, aFunc, aUserData); + PostChildAsyncCall(task.forget()); } void -PluginInstanceChild::PostChildAsyncCall(ChildAsyncCall* aTask) +PluginInstanceChild::PostChildAsyncCall(already_AddRefed aTask) { + RefPtr task = aTask; + { MutexAutoLock lock(mAsyncCallMutex); - mPendingAsyncCalls.AppendElement(aTask); + mPendingAsyncCalls.AppendElement(task); } - ProcessChild::message_loop()->PostTask(FROM_HERE, aTask); + ProcessChild::message_loop()->PostTask(task.forget()); } void diff --git a/dom/plugins/ipc/PluginInstanceChild.h b/dom/plugins/ipc/PluginInstanceChild.h index c468c02448..cdeffc09cb 100644 --- a/dom/plugins/ipc/PluginInstanceChild.h +++ b/dom/plugins/ipc/PluginInstanceChild.h @@ -259,7 +259,7 @@ public: void AsyncCall(PluginThreadCallback aFunc, void* aUserData); // This function is a more general version of AsyncCall - void PostChildAsyncCall(ChildAsyncCall* aTask); + void PostChildAsyncCall(already_AddRefed aTask); int GetQuirks(); @@ -384,7 +384,7 @@ private: mWindowed(isWindowed) {} - void Run() override; + NS_IMETHOD Run() override; WNDPROC GetProc(); HWND GetWnd() { return mWnd; } @@ -446,7 +446,7 @@ private: #endif mozilla::Mutex mAsyncInvalidateMutex; - CancelableTask *mAsyncInvalidateTask; + CancelableRunnable *mAsyncInvalidateTask; // Cached scriptable actors to avoid IPC churn PluginScriptableObjectChild* mCachedWindowActor; @@ -637,10 +637,10 @@ private: gfxSurfaceType mSurfaceType; // Keep InvalidateRect task pointer to be able Cancel it on Destroy - CancelableTask *mCurrentInvalidateTask; + RefPtr mCurrentInvalidateTask; // Keep AsyncSetWindow task pointer to be able to Cancel it on Destroy - CancelableTask *mCurrentAsyncSetWindowTask; + RefPtr mCurrentAsyncSetWindowTask; // True while plugin-child in plugin call // Use to prevent plugin paint re-enter diff --git a/dom/plugins/ipc/PluginInstanceParent.cpp b/dom/plugins/ipc/PluginInstanceParent.cpp index 5f74246884..1aa5abdc54 100644 --- a/dom/plugins/ipc/PluginInstanceParent.cpp +++ b/dom/plugins/ipc/PluginInstanceParent.cpp @@ -151,7 +151,6 @@ PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent, , mShColorSpace(nullptr) #endif #if defined(XP_WIN) - , mCaptureRefreshTask(nullptr) , mValidFirstCapture(false) , mIsScrolling(false) #endif @@ -1225,7 +1224,8 @@ PluginInstanceParent::ScheduleScrollCapture(int aTimeout) CAPTURE_LOG("delayed scroll capture requested."); mCaptureRefreshTask = NewRunnableMethod(this, &PluginInstanceParent::ScheduledUpdateScrollCaptureCallback); - MessageLoop::current()->PostDelayedTask(FROM_HERE, mCaptureRefreshTask, + RefPtr addrefedTask = mCaptureRefreshTask; + MessageLoop::current()->PostDelayedTask(addrefedTask.forget(), kScrollCaptureDelayMs); } diff --git a/dom/plugins/ipc/PluginInstanceParent.h b/dom/plugins/ipc/PluginInstanceParent.h index d58c92f1ea..80f5c8ab32 100644 --- a/dom/plugins/ipc/PluginInstanceParent.h +++ b/dom/plugins/ipc/PluginInstanceParent.h @@ -474,7 +474,7 @@ private: void CancelScheduledScrollCapture(); RefPtr mScrollCapture; - CancelableTask* mCaptureRefreshTask; + RefPtr mCaptureRefreshTask; bool mValidFirstCapture; bool mIsScrolling; #endif diff --git a/dom/plugins/ipc/PluginModuleChild.cpp b/dom/plugins/ipc/PluginModuleChild.cpp index c2e50b93c3..0070b825d0 100644 --- a/dom/plugins/ipc/PluginModuleChild.cpp +++ b/dom/plugins/ipc/PluginModuleChild.cpp @@ -166,7 +166,8 @@ PluginModuleChild::~PluginModuleChild() // bridged protocol (bug 1090570). So we have to do it ourselves. This // code is only invoked for PluginModuleChild instances created via // bridging; otherwise mTransport is null. - XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new DeleteTask(mTransport)); + RefPtr> task = new DeleteTask(mTransport); + XRE_GetIOMessageLoop()->PostTask(task.forget()); } if (mIsChrome) { @@ -831,7 +832,9 @@ PluginModuleChild::ActorDestroy(ActorDestroyReason why) } // Destroy ourselves once we finish other teardown activities. - MessageLoop::current()->PostTask(FROM_HERE, new DeleteTask(this)); + RefPtr> task = + new DeleteTask(this); + MessageLoop::current()->PostTask(task.forget()); return; } @@ -2207,11 +2210,12 @@ public: { } - void Run() override + NS_IMETHOD Run() override { RemoveFromAsyncList(); DebugOnly sendOk = mInstance->SendAsyncNPP_NewResult(mResult); MOZ_ASSERT(sendOk); + return NS_OK; } private: @@ -2225,8 +2229,9 @@ RunAsyncNPP_New(void* aChildInstance) PluginInstanceChild* childInstance = static_cast(aChildInstance); NPError rv = childInstance->DoNPP_New(); - AsyncNewResultSender* task = new AsyncNewResultSender(childInstance, rv); - childInstance->PostChildAsyncCall(task); + RefPtr task = + new AsyncNewResultSender(childInstance, rv); + childInstance->PostChildAsyncCall(task.forget()); } bool diff --git a/dom/plugins/ipc/PluginModuleParent.cpp b/dom/plugins/ipc/PluginModuleParent.cpp index 006a564c36..2fdfddbc46 100755 --- a/dom/plugins/ipc/PluginModuleParent.cpp +++ b/dom/plugins/ipc/PluginModuleParent.cpp @@ -150,7 +150,7 @@ mozilla::plugins::SetupBridge(uint32_t aPluginId, /** * Use for executing CreateToolhelp32Snapshot off main thread */ -class mozilla::plugins::FinishInjectorInitTask : public CancelableTask +class mozilla::plugins::FinishInjectorInitTask : public mozilla::CancelableRunnable { public: FinishInjectorInitTask() @@ -169,34 +169,31 @@ public: void PostToMainThread() { + RefPtr self = this; mSnapshot.own(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)); - bool deleteThis = false; { // Scope for lock mozilla::MutexAutoLock lock(mMutex); if (mMainThreadMsgLoop) { - mMainThreadMsgLoop->PostTask(FROM_HERE, this); - } else { - deleteThis = true; + mMainThreadMsgLoop->PostTask(self.forget()); } } - if (deleteThis) { - delete this; - } } - void Run() override + NS_IMETHOD Run() override { mParent->DoInjection(mSnapshot); // We don't need to hold this lock during DoInjection, but we do need // to obtain it before returning from Run() to ensure that // PostToMainThread has completed before we return. mozilla::MutexAutoLock lock(mMutex); + return NS_OK; } - void Cancel() override + nsresult Cancel() override { mozilla::MutexAutoLock lock(mMutex); mMainThreadMsgLoop = nullptr; + return NS_OK; } private: @@ -710,8 +707,9 @@ PluginModuleContentParent::PluginModuleContentParent(bool aAllowAsyncInit) PluginModuleContentParent::~PluginModuleContentParent() { - XRE_GetIOMessageLoop()->PostTask(FROM_HERE, - new DeleteTask(GetTransport())); + RefPtr> task = new DeleteTask(GetTransport()); + XRE_GetIOMessageLoop()->PostTask(task.forget()); + Preferences::UnregisterCallback(TimeoutChanged, kContentTimeoutPref, this); } @@ -906,7 +904,6 @@ PluginModuleChromeParent::CleanupFromTimeout(const bool aFromHangUI) if (!OkToCleanup()) { // there's still plugin code on the C++ stack, try again MessageLoop::current()->PostDelayedTask( - FROM_HERE, mChromeTaskFactory.NewRunnableMethod( &PluginModuleChromeParent::CleanupFromTimeout, aFromHangUI), 10); return; @@ -1171,7 +1168,6 @@ PluginModuleChromeParent::ShouldContinueFromReplyTimeout() { if (mIsFlashPlugin) { MessageLoop::current()->PostTask( - FROM_HERE, mTaskFactory.NewRunnableMethod( &PluginModuleChromeParent::NotifyFlashHang)); } @@ -1349,7 +1345,6 @@ PluginModuleChromeParent::TerminateChildProcess(MessageLoop* aMsgLoop, // or not at all bool isFromHangUI = aMsgLoop != MessageLoop::current(); aMsgLoop->PostTask( - FROM_HERE, mChromeTaskFactory.NewRunnableMethod( &PluginModuleChromeParent::CleanupFromTimeout, isFromHangUI)); @@ -1599,7 +1594,6 @@ PluginModuleParent::ActorDestroy(ActorDestroyReason why) // and potentially modify the actor child list while enumerating it. if (mPlugin) MessageLoop::current()->PostTask( - FROM_HERE, mTaskFactory.NewRunnableMethod( &PluginModuleParent::NotifyPluginCrashed)); break; @@ -1655,7 +1649,6 @@ PluginModuleParent::NotifyPluginCrashed() if (!OkToCleanup()) { // there's still plugin code on the C++ stack. try again MessageLoop::current()->PostDelayedTask( - FROM_HERE, mTaskFactory.NewRunnableMethod( &PluginModuleParent::NotifyPluginCrashed), 10); return; @@ -3156,7 +3149,6 @@ PluginModuleChromeParent::InitializeInjector() mFinishInitTask->Init(this); if (!::QueueUserWorkItem(&PluginModuleChromeParent::GetToolhelpSnapshot, mFinishInitTask, WT_EXECUTEDEFAULT)) { - delete mFinishInitTask; mFinishInitTask = nullptr; return; } diff --git a/dom/plugins/ipc/PluginModuleParent.h b/dom/plugins/ipc/PluginModuleParent.h index a24f651d52..54c41bf7fa 100644 --- a/dom/plugins/ipc/PluginModuleParent.h +++ b/dom/plugins/ipc/PluginModuleParent.h @@ -610,7 +610,7 @@ private: DWORD mFlashProcess1; DWORD mFlashProcess2; - mozilla::plugins::FinishInjectorInitTask* mFinishInitTask; + RefPtr mFinishInitTask; #endif void OnProcessLaunched(const bool aSucceeded); @@ -624,9 +624,10 @@ private: MOZ_ASSERT(aModule); } - void Run() override + NS_IMETHOD Run() override { mModule->OnProcessLaunched(mLaunchSucceeded); + return NS_OK; } private: diff --git a/dom/plugins/ipc/PluginProcessParent.cpp b/dom/plugins/ipc/PluginProcessParent.cpp index d6106c205a..955b030e40 100644 --- a/dom/plugins/ipc/PluginProcessParent.cpp +++ b/dom/plugins/ipc/PluginProcessParent.cpp @@ -194,8 +194,7 @@ PluginProcessParent::Delete() return; } - ioLoop->PostTask(FROM_HERE, - NewRunnableMethod(this, &PluginProcessParent::Delete)); + ioLoop->PostTask(NewRunnableMethod(this, &PluginProcessParent::Delete)); } void @@ -239,7 +238,7 @@ PluginProcessParent::OnChannelConnected(int32_t peer_pid) GeckoChildProcessHost::OnChannelConnected(peer_pid); if (mLaunchCompleteTask && !mRunCompleteTaskImmediately) { mLaunchCompleteTask->SetLaunchSucceeded(); - mMainMsgLoop->PostTask(FROM_HERE, mTaskFactory.NewRunnableMethod( + mMainMsgLoop->PostTask(mTaskFactory.NewRunnableMethod( &PluginProcessParent::RunLaunchCompleteTask)); } } @@ -249,7 +248,7 @@ PluginProcessParent::OnChannelError() { GeckoChildProcessHost::OnChannelError(); if (mLaunchCompleteTask && !mRunCompleteTaskImmediately) { - mMainMsgLoop->PostTask(FROM_HERE, mTaskFactory.NewRunnableMethod( + mMainMsgLoop->PostTask(mTaskFactory.NewRunnableMethod( &PluginProcessParent::RunLaunchCompleteTask)); } } diff --git a/dom/plugins/ipc/PluginProcessParent.h b/dom/plugins/ipc/PluginProcessParent.h index 692160d38c..f2fd15361a 100644 --- a/dom/plugins/ipc/PluginProcessParent.h +++ b/dom/plugins/ipc/PluginProcessParent.h @@ -25,7 +25,7 @@ namespace mozilla { namespace plugins { -class LaunchCompleteTask : public Task +class LaunchCompleteTask : public Runnable { public: LaunchCompleteTask() diff --git a/dom/plugins/ipc/TaskFactory.h b/dom/plugins/ipc/TaskFactory.h index 4a49fc0571..599a708c9f 100644 --- a/dom/plugins/ipc/TaskFactory.h +++ b/dom/plugins/ipc/TaskFactory.h @@ -36,9 +36,10 @@ private: { } - virtual void Run() { + NS_IMETHOD Run() override { if (!revocable_.revoked()) TaskType::Run(); + return NS_OK; } private: @@ -49,34 +50,35 @@ public: explicit TaskFactory(T* object) : object_(object) { } template - inline TaskParamType* NewTask(Args&&... args) + inline already_AddRefed NewTask(Args&&... args) { typedef TaskWrapper TaskWrapper; - TaskWrapper* task = new TaskWrapper(this, mozilla::Forward(args)...); - return task; + RefPtr task = + new TaskWrapper(this, mozilla::Forward(args)...); + return task.forget(); } template - inline Task* NewRunnableMethod(Method method) { + inline already_AddRefed NewRunnableMethod(Method method) { typedef TaskWrapper > TaskWrapper; - TaskWrapper* task = new TaskWrapper(this); + RefPtr task = new TaskWrapper(this); task->Init(object_, method, base::MakeTuple()); - return task; + return task.forget(); } template - inline Task* NewRunnableMethod(Method method, const A& a) { + inline already_AddRefed NewRunnableMethod(Method method, const A& a) { typedef TaskWrapper > > TaskWrapper; - TaskWrapper* task = new TaskWrapper(this); + RefPtr task = new TaskWrapper(this); task->Init(object_, method, base::MakeTuple(a)); - return task; + return task.forget(); } protected: template - class RunnableMethod : public Task { + class RunnableMethod : public Runnable { public: RunnableMethod() { } @@ -86,7 +88,10 @@ protected: params_ = params; } - virtual void Run() { DispatchToMethod(obj_, meth_, params_); } + NS_IMETHOD Run() override { + DispatchToMethod(obj_, meth_, params_); + return NS_OK; + } private: T* obj_; diff --git a/dom/requestsync/RequestSync.manifest b/dom/requestsync/RequestSync.manifest deleted file mode 100644 index 0f09724b66..0000000000 --- a/dom/requestsync/RequestSync.manifest +++ /dev/null @@ -1,5 +0,0 @@ -component {8ee5ab74-15c4-478f-9d32-67627b9f0f1a} RequestSyncScheduler.js -contract @mozilla.org/dom/request-sync-scheduler;1 {8ee5ab74-15c4-478f-9d32-67627b9f0f1a} - -component {e6f55080-e549-4e30-9d00-15f240fb763c} RequestSyncManager.js -contract @mozilla.org/dom/request-sync-manager;1 {e6f55080-e549-4e30-9d00-15f240fb763c} diff --git a/dom/requestsync/RequestSyncApp.jsm b/dom/requestsync/RequestSyncApp.jsm deleted file mode 100644 index 69ad349d5e..0000000000 --- a/dom/requestsync/RequestSyncApp.jsm +++ /dev/null @@ -1,48 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -'use strict'; - -this.EXPORTED_SYMBOLS = ['RequestSyncApp']; - -function debug(s) { - //dump('DEBUG RequestSyncApp: ' + s + '\n'); -} - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import('resource://gre/modules/XPCOMUtils.jsm'); - -this.RequestSyncApp = function(aData) { - debug('created'); - - let keys = [ 'origin', 'manifestURL', 'isInBrowserElement' ]; - for (let i = 0; i < keys.length; ++i) { - if (!(keys[i] in aData)) { - dump("ERROR - RequestSyncApp must receive a full app object: " + keys[i] + " missing."); - throw "ERROR!"; - } - - this["_" + keys[i]] = aData[keys[i]]; - } -} - -this.RequestSyncApp.prototype = { - classDescription: 'RequestSyncApp XPCOM Component', - classID: Components.ID('{5a0b64db-a2be-4f08-a6c5-8bf2e3ae0c57}'), - contractID: '@mozilla.org/dom/request-sync-manager;1', - QueryInterface: XPCOMUtils.generateQI([]), - - get origin() { - return this._origin; - }, - - get manifestURL() { - return this._manifestURL; - }, - - get isInBrowserElement() { - return this._isInBrowserElement; - } -}; diff --git a/dom/requestsync/RequestSyncManager.js b/dom/requestsync/RequestSyncManager.js deleted file mode 100644 index d94121a629..0000000000 --- a/dom/requestsync/RequestSyncManager.js +++ /dev/null @@ -1,134 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -'use strict'; - -function debug(s) { - //dump('DEBUG RequestSyncManager: ' + s + '\n'); -} - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/DOMRequestHelper.jsm"); -Cu.import('resource://gre/modules/XPCOMUtils.jsm'); -Cu.import('resource://gre/modules/RequestSyncApp.jsm'); -Cu.import('resource://gre/modules/RequestSyncTask.jsm'); - -XPCOMUtils.defineLazyServiceGetter(this, "cpmm", - "@mozilla.org/childprocessmessagemanager;1", - "nsIMessageSender"); - -function RequestSyncManager() { - debug('created'); -} - -RequestSyncManager.prototype = { - __proto__: DOMRequestIpcHelper.prototype, - - classDescription: 'RequestSyncManager XPCOM Component', - classID: Components.ID('{e6f55080-e549-4e30-9d00-15f240fb763c}'), - contractID: '@mozilla.org/dom/request-sync-manager;1', - QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference, - Ci.nsIObserver, - Ci.nsIDOMGlobalPropertyInitializer]), - - _messages: [ "RequestSyncManager:Registrations:Return", - "RequestSyncManager:SetPolicy:Return", - "RequestSyncManager:RunTask:Return" ], - - init: function(aWindow) { - debug("init"); - - // DOMRequestIpcHelper.initHelper sets this._window - this.initDOMRequestHelper(aWindow, this._messages); - }, - - sendMessage: function(aMsg, aObj) { - let self = this; - return this.createPromiseWithId(function(aResolverId) { - aObj.requestID = aResolverId; - cpmm.sendAsyncMessage(aMsg, aObj, null, - self._window.document.nodePrincipal); - }); - }, - - registrations: function() { - debug('registrations'); - return this.sendMessage("RequestSyncManager:Registrations", {}); - }, - - setPolicy: function(aTask, aOrigin, aManifestURL, aIsInIsolatedMozBrowserElement, - aState, aOverwrittenMinInterval) { - debug('setPolicy'); - - return this.sendMessage("RequestSyncManager:SetPolicy", - { task: aTask, - origin: aOrigin, - manifestURL: aManifestURL, - isInBrowserElement: aIsInIsolatedMozBrowserElement, - state: aState, - overwrittenMinInterval: aOverwrittenMinInterval }); - }, - - runTask: function(aTask, aOrigin, aManifestURL, aIsInIsolatedMozBrowserElement) { - debug('runTask'); - - return this.sendMessage("RequestSyncManager:RunTask", - { task: aTask, - origin: aOrigin, - manifestURL: aManifestURL, - isInBrowserElement: aIsInIsolatedMozBrowserElement }); - }, - - registrationsResult: function(aData) { - debug("registrationsResult"); - - let results = new this._window.Array(); - for (let i = 0; i < aData.length; ++i) { - if (!("app" in aData[i])) { - dump("ERROR - Serialization error in RequestSyncManager.\n"); - continue; - } - - let app = new RequestSyncApp(aData[i].app); - let exposedApp = - this._window.RequestSyncApp._create(this._window, app); - - let task = new RequestSyncTask(this, this._window, exposedApp, aData[i]); - let exposedTask = - this._window.RequestSyncTask._create(this._window, task); - - results.push(exposedTask); - } - return results; - }, - - receiveMessage: function(aMessage) { - debug('receiveMessage'); - - let req = this.getPromiseResolver(aMessage.data.requestID); - if (!req) { - return; - } - - if ('error' in aMessage.data) { - req.reject(Cu.cloneInto(aMessage.data.error, this._window)); - return; - } - - if (aMessage.name == 'RequestSyncManager:Registrations:Return') { - req.resolve(this.registrationsResult(aMessage.data.results)); - return; - } - - if ('results' in aMessage.data) { - req.resolve(Cu.cloneInto(aMessage.data.results, this._window)); - return; - } - - req.resolve(); - } -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RequestSyncManager]); diff --git a/dom/requestsync/RequestSyncScheduler.js b/dom/requestsync/RequestSyncScheduler.js deleted file mode 100644 index 13ca8be2ad..0000000000 --- a/dom/requestsync/RequestSyncScheduler.js +++ /dev/null @@ -1,100 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -'use strict'; - -function debug(s) { - //dump('DEBUG RequestSyncScheduler: ' + s + '\n'); -} - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import('resource://gre/modules/DOMRequestHelper.jsm'); -Cu.import('resource://gre/modules/XPCOMUtils.jsm'); - -XPCOMUtils.defineLazyServiceGetter(this, 'cpmm', - '@mozilla.org/childprocessmessagemanager;1', - 'nsIMessageSender'); - -function RequestSyncScheduler() { - debug('created'); -} - -RequestSyncScheduler.prototype = { - __proto__: DOMRequestIpcHelper.prototype, - - classDescription: 'RequestSyncScheduler XPCOM Component', - classID: Components.ID('{8ee5ab74-15c4-478f-9d32-67627b9f0f1a}'), - contractID: '@mozilla.org/dom/request-sync-scheduler;1', - QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference, - Ci.nsIObserver, - Ci.nsIDOMGlobalPropertyInitializer]), - - _messages: [ 'RequestSync:Register:Return', - 'RequestSync:Unregister:Return', - 'RequestSync:Registrations:Return', - 'RequestSync:Registration:Return' ], - - init: function(aWindow) { - debug('init'); - - // DOMRequestIpcHelper.initHelper sets this._window - this.initDOMRequestHelper(aWindow, this._messages); - }, - - register: function(aTask, aParams) { - debug('register'); - return this.sendMessage('RequestSync:Register', - { task: aTask, params: aParams }); - }, - - unregister: function(aTask) { - debug('unregister'); - return this.sendMessage('RequestSync:Unregister', - { task: aTask }); - }, - - registrations: function() { - debug('registrations'); - return this.sendMessage('RequestSync:Registrations', {}); - }, - - registration: function(aTask) { - debug('registration'); - return this.sendMessage('RequestSync:Registration', - { task: aTask }); - }, - - sendMessage: function(aMsg, aObj) { - let self = this; - return this.createPromiseWithId(function(aResolverId) { - aObj.requestID = aResolverId; - cpmm.sendAsyncMessage(aMsg, aObj, null, - self._window.document.nodePrincipal); - }); - }, - - receiveMessage: function(aMessage) { - debug('receiveMessage'); - - let req = this.getPromiseResolver(aMessage.data.requestID); - if (!req) { - return; - } - - if ('error' in aMessage.data) { - req.reject(Cu.cloneInto(aMessage.data.error, this._window)); - return; - } - - if ('results' in aMessage.data) { - req.resolve(Cu.cloneInto(aMessage.data.results, this._window)); - return; - } - - req.resolve(); - } -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RequestSyncScheduler]); diff --git a/dom/requestsync/RequestSyncService.jsm b/dom/requestsync/RequestSyncService.jsm deleted file mode 100644 index 5768987ac2..0000000000 --- a/dom/requestsync/RequestSyncService.jsm +++ /dev/null @@ -1,1004 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -'use strict' - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -function debug(s) { - //dump('DEBUG RequestSyncService: ' + s + '\n'); -} - -const RSYNCDB_VERSION = 1; -const RSYNCDB_NAME = "requestSync"; -const RSYNC_MIN_INTERVAL = 100; - -const RSYNC_OPERATION_TIMEOUT = 120000 // 2 minutes - -const RSYNC_STATE_ENABLED = "enabled"; -const RSYNC_STATE_DISABLED = "disabled"; -const RSYNC_STATE_WIFIONLY = "wifiOnly"; - -Cu.import('resource://gre/modules/IndexedDBHelper.jsm'); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.importGlobalProperties(["indexedDB"]); - - -XPCOMUtils.defineLazyServiceGetter(this, "appsService", - "@mozilla.org/AppsService;1", - "nsIAppsService"); - -XPCOMUtils.defineLazyServiceGetter(this, "cpmm", - "@mozilla.org/childprocessmessagemanager;1", - "nsISyncMessageSender"); - -XPCOMUtils.defineLazyServiceGetter(this, "ppmm", - "@mozilla.org/parentprocessmessagemanager;1", - "nsIMessageBroadcaster"); - -XPCOMUtils.defineLazyServiceGetter(this, "systemMessenger", - "@mozilla.org/system-message-internal;1", - "nsISystemMessagesInternal"); - -XPCOMUtils.defineLazyServiceGetter(this, "secMan", - "@mozilla.org/scriptsecuritymanager;1", - "nsIScriptSecurityManager"); - -XPCOMUtils.defineLazyServiceGetter(this, "powerManagerService", - "@mozilla.org/power/powermanagerservice;1", - "nsIPowerManagerService"); - -XPCOMUtils.defineLazyModuleGetter(this, "AlarmService", - "resource://gre/modules/AlarmService.jsm"); - -this.RequestSyncService = { - __proto__: IndexedDBHelper.prototype, - - children: [], - - _messages: [ "RequestSync:Register", - "RequestSync:Unregister", - "RequestSync:Registrations", - "RequestSync:Registration", - "RequestSyncManager:Registrations", - "RequestSyncManager:SetPolicy", - "RequestSyncManager:RunTask" ], - - _pendingOperation: false, - _pendingMessages: [], - - _registrations: {}, - - _wifi: false, - - _activeTask: null, - _queuedTasks: [], - - _timers: {}, - _pendingRequests: {}, - - // This array contains functions to be executed after the scheduling of the - // current task or immediately if there are not scheduling in progress. - _afterSchedulingTasks: [], - - // Initialization of the RequestSyncService. - init: function() { - debug("init"); - - this._messages.forEach((function(msgName) { - ppmm.addMessageListener(msgName, this); - }).bind(this)); - - Services.obs.addObserver(this, 'xpcom-shutdown', false); - Services.obs.addObserver(this, 'clear-origin-data', false); - Services.obs.addObserver(this, 'wifi-state-changed', false); - - this.initDBHelper("requestSync", RSYNCDB_VERSION, [RSYNCDB_NAME]); - - // Loading all the data from the database into the _registrations map. - // Any incoming message will be stored and processed when the async - // operation is completed. - - this.dbTxn("readonly", function(aStore) { - aStore.openCursor().onsuccess = event => { - let cursor = event.target.result; - if (cursor) { - this.addRegistration(cursor.value, function() { - cursor.continue(); - }); - } - } - }.bind(this), - function() { - debug("initialization done"); - }, - function() { - dump("ERROR!! RequestSyncService - Failed to retrieve data from the database.\n"); - }); - }, - - // Shutdown the RequestSyncService. - shutdown: function() { - debug("shutdown"); - - this._messages.forEach((function(msgName) { - ppmm.removeMessageListener(msgName, this); - }).bind(this)); - - Services.obs.removeObserver(this, 'xpcom-shutdown'); - Services.obs.removeObserver(this, 'clear-origin-data'); - Services.obs.removeObserver(this, 'wifi-state-changed'); - - this.close(); - - // Removing all the registrations will delete the pending timers. - this.forEachRegistration(function(aObj) { - let key = this.principalToKey(aObj.principal); - this.removeRegistrationInternal(aObj.data.task, key); - }.bind(this)); - }, - - observe: function(aSubject, aTopic, aData) { - debug("observe"); - - switch (aTopic) { - case 'xpcom-shutdown': - this.executeAfterScheduling(function() { - this.shutdown(); - }.bind(this)); - break; - - case 'clear-origin-data': - this.executeAfterScheduling(function() { - this.clearData(aData); - }.bind(this)); - break; - - case 'wifi-state-changed': - this.executeAfterScheduling(function() { - this.wifiStateChanged(aSubject == 'enabled'); - }.bind(this)); - break; - - default: - debug("Wrong observer topic: " + aTopic); - break; - } - }, - - // When an app is uninstalled, we have to clean all its tasks. - clearData: function(aData) { - debug('clearData'); - - if (!aData) { - return; - } - - let pattern = JSON.parse(aData); - let dbKeys = []; - - for (let key in this._registrations) { - let prin = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(key); - if (!ChromeUtils.originAttributesMatchPattern(prin.originAttributes, pattern)) { - continue; - } - - for (let task in this._registrations[key]) { - dbKeys = this._registrations[key][task].dbKey; - this.removeRegistrationInternal(task, key); - } - } - - if (dbKeys.length == 0) { - return; - } - - // Remove the tasks from the database. - this.dbTxn('readwrite', function(aStore) { - for (let i = 0; i < dbKeys.length; ++i) { - aStore.delete(dbKeys[i]); - } - }, - function() { - debug("ClearData completed"); - }, function() { - debug("ClearData failed"); - }); - }, - - // Creation of the schema for the database. - upgradeSchema: function(aTransaction, aDb, aOldVersion, aNewVersion) { - debug('updateSchema'); - aDb.createObjectStore(RSYNCDB_NAME, { autoIncrement: true }); - }, - - // This method generates the key for the indexedDB object storage. - principalToKey: function(aPrincipal) { - return aPrincipal.origin; - }, - - // Add a task to the _registrations map and create the timer if it's needed. - addRegistration: function(aObj, aCb) { - debug('addRegistration'); - - let key = this.principalToKey(aObj.principal); - if (!(key in this._registrations)) { - this._registrations[key] = {}; - } - - this.scheduleTimer(aObj, function() { - this._registrations[key][aObj.data.task] = aObj; - if (aCb) { - aCb(); - } - }.bind(this)); - }, - - // Remove a task from the _registrations map and delete the timer if it's - // needed. It also checks if the principal is correct before doing the real - // operation. - removeRegistration: function(aTaskName, aKey, aPrincipal) { - debug('removeRegistration'); - - if (!(aKey in this._registrations) || - !(aTaskName in this._registrations[aKey])) { - return false; - } - - // Additional security check. - if (!aPrincipal.equals(this._registrations[aKey][aTaskName].principal)) { - return false; - } - - this.removeRegistrationInternal(aTaskName, aKey); - return true; - }, - - removeRegistrationInternal: function(aTaskName, aKey) { - debug('removeRegistrationInternal'); - - let obj = this._registrations[aKey][aTaskName]; - - this.removeTimer(obj); - - // It can be that this task has been already schedulated. - this.removeTaskFromQueue(obj); - - // It can be that this object is already in scheduled, or in the queue of a - // iDB transacation. In order to avoid rescheduling it, we must disable it. - obj.active = false; - - delete this._registrations[aKey][aTaskName]; - - // Lets remove the key in case there are not tasks registered. - for (let key in this._registrations[aKey]) { - return; - } - delete this._registrations[aKey]; - }, - - removeTaskFromQueue: function(aObj) { - let pos = this._queuedTasks.indexOf(aObj); - if (pos != -1) { - this._queuedTasks.splice(pos, 1); - } - }, - - // The communication from the exposed objects and the service is done using - // messages. This function receives and processes them. - receiveMessage: function(aMessage) { - debug("receiveMessage"); - - // We cannot process this request now. - if (this._pendingOperation) { - this._pendingMessages.push(aMessage); - return; - } - - // The principal is used to validate the message. - let principal = aMessage.principal; - if (!principal) { - return; - } - - switch (aMessage.name) { - case "RequestSync:Register": - this.executeAfterScheduling(function() { - this.register(aMessage.target, aMessage.data, principal); - }.bind(this)); - break; - - case "RequestSync:Unregister": - this.executeAfterScheduling(function() { - this.unregister(aMessage.target, aMessage.data, principal); - }.bind(this)); - break; - - case "RequestSync:Registrations": - this.executeAfterScheduling(function() { - this.registrations(aMessage.target, aMessage.data, principal); - }.bind(this)); - break; - - case "RequestSync:Registration": - this.executeAfterScheduling(function() { - this.registration(aMessage.target, aMessage.data, principal); - }.bind(this)); - break; - - case "RequestSyncManager:Registrations": - this.executeAfterScheduling(function() { - this.managerRegistrations(aMessage.target, aMessage.data, principal); - }.bind(this)); - break; - - case "RequestSyncManager:SetPolicy": - this.executeAfterScheduling(function() { - this.managerSetPolicy(aMessage.target, aMessage.data, principal); - }.bind(this)); - break; - - case "RequestSyncManager:RunTask": - this.executeAfterScheduling(function() { - this.managerRunTask(aMessage.target, aMessage.data, principal); - }.bind(this)); - break; - - default: - debug("Wrong message: " + aMessage.name); - break; - } - }, - - // Basic validation. - validateRegistrationParams: function(aParams) { - if (aParams === null) { - return false; - } - - // We must have a page. - if (!("wakeUpPage" in aParams) || - aParams.wakeUpPage.length == 0) { - return false; - } - - let minInterval = RSYNC_MIN_INTERVAL; - try { - minInterval = Services.prefs.getIntPref("dom.requestSync.minInterval"); - } catch(e) {} - - if (!("minInterval" in aParams) || - aParams.minInterval < minInterval) { - return false; - } - - return true; - }, - - // Registration of a new task. - register: function(aTarget, aData, aPrincipal) { - debug("register"); - - if (!this.validateRegistrationParams(aData.params)) { - aTarget.sendAsyncMessage("RequestSync:Register:Return", - { requestID: aData.requestID, - error: "ParamsError" } ); - return; - } - - let key = this.principalToKey(aPrincipal); - if (key in this._registrations && - aData.task in this._registrations[key]) { - // if this task already exists we overwrite it. - this.removeRegistrationInternal(aData.task, key); - } - - // This creates a RequestTaskFull object. - aData.params.task = aData.task; - aData.params.lastSync = 0; - aData.params.principal = aPrincipal; - - aData.params.state = RSYNC_STATE_ENABLED; - if (aData.params.wifiOnly) { - aData.params.state = RSYNC_STATE_WIFIONLY; - } - - aData.params.overwrittenMinInterval = 0; - - let dbKey = aData.task + "|" + key; - - let data = { principal: aPrincipal, - dbKey: dbKey, - data: aData.params, - active: true }; - - let self = this; - this.dbTxn('readwrite', function(aStore) { - aStore.put(data, data.dbKey); - }, - function() { - self.addRegistration(data, function() { - aTarget.sendAsyncMessage("RequestSync:Register:Return", - { requestID: aData.requestID }); - }); - }, - function() { - aTarget.sendAsyncMessage("RequestSync:Register:Return", - { requestID: aData.requestID, - error: "IndexDBError" } ); - }); - }, - - // Unregister a task. - unregister: function(aTarget, aData, aPrincipal) { - debug("unregister"); - - let key = this.principalToKey(aPrincipal); - if (!(key in this._registrations) || - !(aData.task in this._registrations[key])) { - aTarget.sendAsyncMessage("RequestSync:Unregister:Return", - { requestID: aData.requestID, - error: "UnknownTaskError" }); - return; - } - - let dbKey = this._registrations[key][aData.task].dbKey; - this.removeRegistration(aData.task, key, aPrincipal); - - let self = this; - this.dbTxn('readwrite', function(aStore) { - aStore.delete(dbKey); - }, - function() { - aTarget.sendAsyncMessage("RequestSync:Unregister:Return", - { requestID: aData.requestID }); - }, - function() { - aTarget.sendAsyncMessage("RequestSync:Unregister:Return", - { requestID: aData.requestID, - error: "IndexDBError" } ); - }); - }, - - // Get the list of registered tasks for this principal. - registrations: function(aTarget, aData, aPrincipal) { - debug("registrations"); - - let results = []; - let key = this.principalToKey(aPrincipal); - if (key in this._registrations) { - for (let i in this._registrations[key]) { - results.push(this.createPartialTaskObject( - this._registrations[key][i].data)); - } - } - - aTarget.sendAsyncMessage("RequestSync:Registrations:Return", - { requestID: aData.requestID, - results: results }); - }, - - // Get a particular registered task for this principal. - registration: function(aTarget, aData, aPrincipal) { - debug("registration"); - - let results = null; - let key = this.principalToKey(aPrincipal); - if (key in this._registrations && - aData.task in this._registrations[key]) { - results = this.createPartialTaskObject( - this._registrations[key][aData.task].data); - } - - aTarget.sendAsyncMessage("RequestSync:Registration:Return", - { requestID: aData.requestID, - results: results }); - }, - - // Get the list of the registered tasks. - managerRegistrations: function(aTarget, aData, aPrincipal) { - debug("managerRegistrations"); - - let results = []; - let self = this; - this.forEachRegistration(function(aObj) { - results.push(self.createFullTaskObject(aObj.data)); - }); - - aTarget.sendAsyncMessage("RequestSyncManager:Registrations:Return", - { requestID: aData.requestID, - results: results }); - }, - - // Set a policy to a task. - managerSetPolicy: function(aTarget, aData, aPrincipal) { - debug("managerSetPolicy"); - - let toSave = null; - let self = this; - this.forEachRegistration(function(aObj) { - if (aObj.data.task != aData.task) { - return; - } - - if (aObj.principal.isInIsolatedMozBrowserElement != aData.isInBrowserElement || - aObj.principal.originNoSuffix != aData.origin) { - return; - } - - let app = appsService.getAppByLocalId(aObj.principal.appId); - if (app && app.manifestURL != aData.manifestURL || - (!app && aData.manifestURL != "")) { - return; - } - - if ("overwrittenMinInterval" in aData) { - aObj.data.overwrittenMinInterval = aData.overwrittenMinInterval; - } - - aObj.data.state = aData.state; - - if (toSave) { - dump("ERROR!! RequestSyncService - SetPolicy matches more than 1 task.\n"); - return; - } - - toSave = aObj; - }); - - if (!toSave) { - aTarget.sendAsyncMessage("RequestSyncManager:SetPolicy:Return", - { requestID: aData.requestID, error: "UnknownTaskError" }); - return; - } - - this.updateObjectInDB(toSave, function() { - self.scheduleTimer(toSave, function() { - aTarget.sendAsyncMessage("RequestSyncManager:SetPolicy:Return", - { requestID: aData.requestID }); - }); - }); - }, - - // Run a task now. - managerRunTask: function(aTarget, aData, aPrincipal) { - debug("runTask"); - - let task = null; - this.forEachRegistration(function(aObj) { - if (aObj.data.task != aData.task) { - return; - } - - if (aObj.principal.isInIsolatedMozBrowserElement != aData.isInBrowserElement || - aObj.principal.originNoSuffix != aData.origin) { - return; - } - - let app = appsService.getAppByLocalId(aObj.principal.appId); - if (app && app.manifestURL != aData.manifestURL || - (!app && aData.manifestURL != "")) { - return; - } - - if (task) { - dump("ERROR!! RequestSyncService - RunTask matches more than 1 task.\n"); - return; - } - - task = aObj; - }); - - if (!task) { - aTarget.sendAsyncMessage("RequestSyncManager:RunTask:Return", - { requestID: aData.requestID, error: "UnknownTaskError" }); - return; - } - - // Storing the requestID into the task for the callback. - this.storePendingRequest(task, aTarget, aData.requestID); - this.timeout(task, null); - }, - - // We cannot expose the full internal object to content but just a subset. - // This method creates this subset. - createPartialTaskObject: function(aObj) { - return { task: aObj.task, - lastSync: aObj.lastSync, - oneShot: aObj.oneShot, - minInterval: aObj.minInterval, - wakeUpPage: aObj.wakeUpPage, - wifiOnly: aObj.wifiOnly, - data: aObj.data }; - }, - - createFullTaskObject: function(aObj) { - let obj = this.createPartialTaskObject(aObj); - - obj.app = { manifestURL: '', - origin: aObj.principal.originNoSuffix, - isInBrowserElement: aObj.principal.isInIsolatedMozBrowserElement }; - - let app = appsService.getAppByLocalId(aObj.principal.appId); - if (app) { - obj.app.manifestURL = app.manifestURL; - } - - obj.state = aObj.state; - obj.overwrittenMinInterval = aObj.overwrittenMinInterval; - return obj; - }, - - // Creation of the timer for a particular task object. - scheduleTimer: function(aObj, aCb) { - debug("scheduleTimer"); - - aCb = aCb || function() {}; - - this.removeTimer(aObj); - - // A registration can be already inactive if it was 1 shot. - if (!aObj.active) { - aCb(); - return; - } - - if (aObj.data.state == RSYNC_STATE_DISABLED) { - aCb(); - return; - } - - // WifiOnly check. - if (aObj.data.state == RSYNC_STATE_WIFIONLY && !this._wifi) { - aCb(); - return; - } - - if (this.scheduling) { - dump("ERROR!! RequestSyncService - ScheduleTimer called into ScheduleTimer.\n"); - aCb(); - return; - } - - this.scheduling = true; - - this.createTimer(aObj, function() { - this.scheduling = false; - - while (this._afterSchedulingTasks.length) { - var cb = this._afterSchedulingTasks.shift(); - cb(); - } - - aCb(); - }.bind(this)); - }, - - executeAfterScheduling: function(aCb) { - if (!this.scheduling) { - aCb(); - return; - } - - this._afterSchedulingTasks.push(aCb); - }, - - timeout: function(aObj, aWakeLock) { - debug("timeout"); - - if (this._activeTask) { - debug("queueing tasks"); - // We have an active task, let's queue this as next task. - if (this._queuedTasks.indexOf(aObj) == -1) { - this._queuedTasks.push(aObj); - } - this.maybeReleaseWakeLock(aWakeLock); - return; - } - - let app = appsService.getAppByLocalId(aObj.principal.appId); - if (!app) { - dump("ERROR!! RequestSyncService - Failed to retrieve app data from a principal.\n"); - aObj.active = false; - this.updateObjectInDB(aObj, () => { - this.maybeReleaseWakeLock(aWakeLock); - }); - return; - } - - let manifestURL = Services.io.newURI(app.manifestURL, null, null); - let pageURL = Services.io.newURI(aObj.data.wakeUpPage, null, aObj.principal.URI); - - // Maybe need to be rescheduled? - if (this.hasPendingMessages('request-sync', manifestURL, pageURL)) { - this.scheduleTimer(aObj, () => { - this.maybeReleaseWakeLock(aWakeLock); - }); - return; - } - - this.removeTimer(aObj); - - if (!manifestURL || !pageURL) { - dump("ERROR!! RequestSyncService - Failed to create URI for the page or the manifest\n"); - aObj.active = false; - this.updateObjectInDB(aObj, () => { - this.maybeReleaseWakeLock(aWakeLock); - }); - return; - } - - this._activeTask = aObj; - - // We don't want to run more than 1 task at the same time. We do this using - // the promise created by sendMessage(). But if the task takes more than - // RSYNC_OPERATION_TIMEOUT millisecs, we have to ignore the promise and - // continue processing other tasks. - - let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - - // We need a wakelock to keep the device alive and we want to release it - // only when all the steps are fully completely. This can involve calling - // timeout() again if we have something in _queuedTasks. In this scenario - // we want to reuse the same wakelock and we receive it as param. - // The Wakelock is passed to operationCompleted() because we want to wait - // until the data is written into IDB and maybe until all the pending next - // tasks are executed too. - let wakeLock = aWakeLock ? aWakeLock : powerManagerService.newWakeLock("cpu"); - let done = false; - let self = this; - function taskCompleted() { - debug("promise or timeout for task calls taskCompleted"); - - if (!done) { - done = true; - self.operationCompleted(wakeLock); - } - - timer.cancel(); - timer = null; - } - - let timeout = RSYNC_OPERATION_TIMEOUT; - try { - let tmp = Services.prefs.getIntPref("dom.requestSync.maxTaskTimeout"); - timeout = tmp; - } catch(e) {} - - timer.initWithCallback(function() { - debug("Task is taking too much, let's ignore the promise."); - taskCompleted(); - }, timeout, Ci.nsITimer.TYPE_ONE_SHOT); - - // Sending the message. - debug("Sending message."); - let promise = - systemMessenger.sendMessage('request-sync', - this.createPartialTaskObject(aObj.data), - pageURL, manifestURL); - - promise.then(function() { - debug("promise resolved"); - taskCompleted(); - }, function() { - debug("promise rejected"); - taskCompleted(); - }); - }, - - operationCompleted: function(aWakeLock) { - debug("operationCompleted"); - - if (!this._activeTask) { - dump("ERROR!! RequestSyncService - OperationCompleted called without an active task\n"); - aWakeLock.unlock(); - return; - } - - // One shot? Then this is not active. - this._activeTask.active = !this._activeTask.data.oneShot; - this._activeTask.data.lastSync = new Date(); - - let pendingRequests = this.stealPendingRequests(this._activeTask); - for (let i = 0; i < pendingRequests.length; ++i) { - pendingRequests[i] - .target.sendAsyncMessage("RequestSyncManager:RunTask:Return", - { requestID: pendingRequests[i].requestID }); - } - - this.updateObjectInDB(this._activeTask, function() { - if (!this._activeTask.data.oneShot) { - this.scheduleTimer(this._activeTask, function() { - this.processNextTask(aWakeLock); - }.bind(this)); - } else { - this.processNextTask(aWakeLock); - } - }.bind(this)); - }, - - processNextTask: function(aWakeLock) { - debug("processNextTask"); - - this._activeTask = null; - - if (this._queuedTasks.length == 0) { - aWakeLock.unlock(); - return; - } - - let task = this._queuedTasks.shift(); - this.timeout(task, aWakeLock); - }, - - hasPendingMessages: function(aMessageName, aManifestURL, aPageURL) { - let hasPendingMessages = - cpmm.sendSyncMessage("SystemMessageManager:HasPendingMessages", - { type: aMessageName, - pageURL: aPageURL.spec, - manifestURL: aManifestURL.spec })[0]; - - debug("Pending messages: " + hasPendingMessages); - return hasPendingMessages; - }, - - // Update the object into the database. - updateObjectInDB: function(aObj, aCb) { - debug("updateObjectInDB"); - - this.dbTxn('readwrite', function(aStore) { - aStore.put(aObj, aObj.dbKey); - }, - function() { - if (aCb) { - aCb(); - } - debug("UpdateObjectInDB completed"); - }, function() { - debug("UpdateObjectInDB failed"); - }); - }, - - pendingOperationStarted: function() { - debug('pendingOperationStarted'); - this._pendingOperation = true; - }, - - pendingOperationDone: function() { - debug('pendingOperationDone'); - - this._pendingOperation = false; - - // managing the pending messages now that the initialization is completed. - while (this._pendingMessages.length && !this._pendingOperation) { - this.receiveMessage(this._pendingMessages.shift()); - } - }, - - // This method creates a transaction and runs callbacks. Plus it manages the - // pending operations system. - dbTxn: function(aType, aCb, aSuccessCb, aErrorCb) { - debug('dbTxn'); - - this.pendingOperationStarted(); - - let self = this; - this.newTxn(aType, RSYNCDB_NAME, function(aTxn, aStore) { - aCb(aStore); - }, - function() { - self.pendingOperationDone(); - aSuccessCb(); - }, - function() { - self.pendingOperationDone(); - aErrorCb(); - }); - }, - - forEachRegistration: function(aCb) { - // This method is used also to remove registations from the map, so we have - // to make a new list and let _registations free to be used. - let list = []; - for (let key in this._registrations) { - for (let task in this._registrations[key]) { - list.push(this._registrations[key][task]); - } - } - - for (let i = 0; i < list.length; ++i) { - aCb(list[i]); - } - }, - - wifiStateChanged: function(aEnabled) { - debug("onWifiStateChanged"); - - this._wifi = aEnabled; - - if (!this._wifi) { - // Disable all the wifiOnly tasks. - this.forEachRegistration(function(aObj) { - if (aObj.data.state == RSYNC_STATE_WIFIONLY && this.hasTimer(aObj)) { - this.removeTimer(aObj); - - // It can be that this task has been already schedulated. - this.removeTaskFromQueue(aObj); - } - }.bind(this)); - return; - } - - // Enable all the tasks. - this.forEachRegistration(function(aObj) { - if (aObj.active && !this.hasTimer(aObj)) { - if (!aObj.data.wifiOnly) { - dump("ERROR - Found a disabled task that is not wifiOnly."); - } - - this.scheduleTimer(aObj); - } - }.bind(this)); - }, - - createTimer: function(aObj, aCb) { - aCb = aCb || function() {}; - - let interval = aObj.data.minInterval; - if (aObj.data.overwrittenMinInterval > 0) { - interval = aObj.data.overwrittenMinInterval; - } - - AlarmService.add( - { date: new Date(Date.now() + interval * 1000), - ignoreTimezone: false }, - () => this.timeout(aObj, null), - function(aTimerId) { - this._timers[aObj.dbKey] = aTimerId; - aCb(); - }.bind(this), - () => aCb()); - }, - - hasTimer: function(aObj) { - return (aObj.dbKey in this._timers); - }, - - removeTimer: function(aObj) { - if (aObj.dbKey in this._timers) { - AlarmService.remove(this._timers[aObj.dbKey]); - delete this._timers[aObj.dbKey]; - } - }, - - storePendingRequest: function(aObj, aTarget, aRequestID) { - if (!(aObj.dbKey in this._pendingRequests)) { - this._pendingRequests[aObj.dbKey] = []; - } - - this._pendingRequests[aObj.dbKey].push({ target: aTarget, - requestID: aRequestID }); - }, - - stealPendingRequests: function(aObj) { - if (!(aObj.dbKey in this._pendingRequests)) { - return []; - } - - let requests = this._pendingRequests[aObj.dbKey]; - delete this._pendingRequests[aObj.dbKey]; - return requests; - }, - - maybeReleaseWakeLock: function(aWakeLock) { - if (aWakeLock) { - aWakeLock.unlock(); - } - } -} - -RequestSyncService.init(); - -this.EXPORTED_SYMBOLS = [""]; diff --git a/dom/requestsync/RequestSyncTask.jsm b/dom/requestsync/RequestSyncTask.jsm deleted file mode 100644 index 0cb8d6d85f..0000000000 --- a/dom/requestsync/RequestSyncTask.jsm +++ /dev/null @@ -1,108 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -'use strict'; - -this.EXPORTED_SYMBOLS = ['RequestSyncTask']; - -function debug(s) { - //dump('DEBUG RequestSyncTask: ' + s + '\n'); -} - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import('resource://gre/modules/XPCOMUtils.jsm'); - -this.RequestSyncTask = function(aManager, aWindow, aApp, aData) { - debug('created'); - - this._manager = aManager; - this._window = aWindow; - this._app = aApp; - - let keys = [ 'task', 'lastSync', 'oneShot', 'minInterval', 'wakeUpPage', - 'wifiOnly', 'data', 'state', 'overwrittenMinInterval' ]; - for (let i = 0; i < keys.length; ++i) { - if (!(keys[i] in aData)) { - dump("ERROR - RequestSyncTask must receive a fully app object: " + keys[i] + " missing."); - throw "ERROR!"; - } - - this["_" + keys[i]] = aData[keys[i]]; - } -} - -this.RequestSyncTask.prototype = { - classDescription: 'RequestSyncTask XPCOM Component', - classID: Components.ID('{a1e1c9c6-ce42-49d4-b8b4-fbd686d8fdd9}'), - contractID: '@mozilla.org/dom/request-sync-manager;1', - QueryInterface: XPCOMUtils.generateQI([]), - - get app() { - return this._app; - }, - - get state() { - return this._state; - }, - - get overwrittenMinInterval() { - return this._overwrittenMinInterval; - }, - - get task() { - return this._task; - }, - - get lastSync() { - return this._lastSync; - }, - - get wakeUpPage() { - return this._wakeUpPage; - }, - - get oneShot() { - return this._oneShot; - }, - - get minInterval() { - return this._minInterval; - }, - - get wifiOnly() { - return this._wifiOnly; - }, - - get data() { - return this._data; - }, - - setPolicy: function(aState, aOverwrittenMinInterval) { - debug("setPolicy"); - let self = this; - - return new this._window.Promise(function(aResolve, aReject) { - let p = self._manager.setPolicy(self._task, self._app.origin, - self._app.manifestURL, - self._app.isInBrowserElement, - aState, - aOverwrittenMinInterval); - - // Set the new value only when the promise is resolved. - p.then(function() { - self._state = aState; - self._overwrittenMinInterval = aOverwrittenMinInterval; - aResolve(); - }, aReject); - }); - }, - - runNow: function() { - debug("runNow"); - return this._manager.runTask(this._task, this._app.origin, - this._app.manifestURL, - this._app.isInBrowserElement); - } -}; diff --git a/dom/requestsync/RequestSyncWifiService.cpp b/dom/requestsync/RequestSyncWifiService.cpp deleted file mode 100644 index 2fe6375d67..0000000000 --- a/dom/requestsync/RequestSyncWifiService.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "RequestSyncWifiService.h" -#include "mozilla/ClearOnShutdown.h" -#include "mozilla/Services.h" -#include "mozilla/StaticPtr.h" -#include "nsIObserverService.h" - -namespace mozilla { -namespace dom { - -using namespace hal; - -NS_IMPL_ISUPPORTS0(RequestSyncWifiService) - -namespace { - -StaticRefPtr sService; - -} // namespace - -/* static */ void -RequestSyncWifiService::Init() -{ - RefPtr service = GetInstance(); - if (!service) { - NS_WARNING("Failed to initialize RequestSyncWifiService."); - } -} - -/* static */ already_AddRefed -RequestSyncWifiService::GetInstance() -{ - if (!sService) { - sService = new RequestSyncWifiService(); - hal::RegisterNetworkObserver(sService); - ClearOnShutdown(&sService); - } - - RefPtr service = sService.get(); - return service.forget(); -} - -void -RequestSyncWifiService::Notify(const hal::NetworkInformation& aNetworkInfo) -{ - bool isWifi = aNetworkInfo.isWifi(); - if (isWifi == mIsWifi) { - return; - } - - mIsWifi = isWifi; - - nsCOMPtr obs = mozilla::services::GetObserverService(); - if (obs) { - obs->NotifyObservers(nullptr, "wifi-state-changed", - mIsWifi ? MOZ_UTF16("enabled") : - MOZ_UTF16("disabled")); - } -} - -} // namespace dom -} // namespace mozilla diff --git a/dom/requestsync/RequestSyncWifiService.h b/dom/requestsync/RequestSyncWifiService.h deleted file mode 100644 index baa40c955f..0000000000 --- a/dom/requestsync/RequestSyncWifiService.h +++ /dev/null @@ -1,43 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_dom_RequestSyncWifiService_h -#define mozilla_dom_RequestSyncWifiService_h - -#include "mozilla/dom/network/Types.h" -#include "mozilla/Hal.h" -#include "nsIObserver.h" - -namespace mozilla { -namespace dom { - -class RequestSyncWifiService final : public nsISupports - , public NetworkObserver -{ -public: - NS_DECL_ISUPPORTS - - static void Init(); - - static already_AddRefed GetInstance(); - - void Notify(const hal::NetworkInformation& aNetworkInfo) override; - -private: - RequestSyncWifiService() - : mIsWifi(false) - {} - - ~RequestSyncWifiService() - {} - - bool mIsWifi; -}; - -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_RequestSyncWifiService_h diff --git a/dom/requestsync/moz.build b/dom/requestsync/moz.build deleted file mode 100644 index b595401654..0000000000 --- a/dom/requestsync/moz.build +++ /dev/null @@ -1,34 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -MOCHITEST_MANIFESTS += ['tests/mochitest.ini'] - -EXPORTS.mozilla.dom += [ - 'RequestSyncWifiService.h', -] - -EXTRA_COMPONENTS += [ - 'RequestSync.manifest', - 'RequestSyncManager.js', - 'RequestSyncScheduler.js', -] - -EXTRA_JS_MODULES += [ - 'RequestSyncApp.jsm', - 'RequestSyncService.jsm', - 'RequestSyncTask.jsm', -] - -SOURCES += [ - 'RequestSyncWifiService.cpp', -] - -include('/ipc/chromium/chromium-config.mozbuild') - -FINAL_LIBRARY = 'xul' - -if CONFIG['GNU_CXX']: - CXXFLAGS += ['-Wshadow'] diff --git a/dom/requestsync/tests/common_app.js b/dom/requestsync/tests/common_app.js deleted file mode 100644 index e2371ed0dc..0000000000 --- a/dom/requestsync/tests/common_app.js +++ /dev/null @@ -1,15 +0,0 @@ -function is(a, b, msg) { - alert((a === b ? 'OK' : 'KO') + ' ' + msg) -} - -function ok(a, msg) { - alert((a ? 'OK' : 'KO')+ ' ' + msg) -} - -function cbError() { - alert('KO error'); -} - -function finish() { - alert('DONE'); -} diff --git a/dom/requestsync/tests/common_basic.js b/dom/requestsync/tests/common_basic.js deleted file mode 100644 index 8900201a33..0000000000 --- a/dom/requestsync/tests/common_basic.js +++ /dev/null @@ -1,188 +0,0 @@ -function test_registerFailure() { - ok("sync" in navigator, "navigator.sync exists"); - - navigator.sync.register().then( - function() { - ok(false, "navigator.sync.register() throws without a task name"); - }, function() { - ok(true, "navigator.sync.register() throws without a task name"); - }) - - .then(function() { - return navigator.sync.register(42); - }).then(function() { - ok(false, "navigator.sync.register() throws without a string task name"); - }, function() { - ok(true, "navigator.sync.register() throws without a string task name"); - }) - - .then(function() { - return navigator.sync.register('foobar'); - }).then(function() { - ok(false, "navigator.sync.register() throws without a param dictionary"); - }, function() { - ok(true, "navigator.sync.register() throws without a param dictionary"); - }) - - .then(function() { - return navigator.sync.register('foobar', 42); - }).then(function() { - ok(false, "navigator.sync.register() throws without a real dictionary"); - }, function() { - ok(true, "navigator.sync.register() throws without a real dictionary"); - }) - - .then(function() { - return navigator.sync.register('foobar', {}); - }).then(function() { - ok(false, "navigator.sync.register() throws without a minInterval and wakeUpPage"); - }, function() { - ok(true, "navigator.sync.register() throws without a minInterval and wakeUpPage"); - }) - - .then(function() { - return navigator.sync.register('foobar', { minInterval: 100 }); - }).then(function() { - ok(false, "navigator.sync.register() throws without a wakeUpPage"); - }, function() { - ok(true, "navigator.sync.register() throws without a wakeUpPage"); - }) - - .then(function() { - return navigator.sync.register('foobar', { wakeUpPage: 100 }); - }).then(function() { - ok(false, "navigator.sync.register() throws without a minInterval"); - }, function() { - ok(true, "navigator.sync.register() throws without a minInterval"); - }) - - .then(function() { - runTests(); - }); -} - -function genericError(name, val) { - ok(false, "Promise from " + name + " rejected with value: " + val); -} - -function test_register() { - navigator.sync.register('foobar', { minInterval: 5, wakeUpPage:'/' }).then( - function() { - ok(true, "navigator.sync.register() worked!"); - runTests(); - }, genericError.bind(null, 'register')); -} - -function test_unregister() { - navigator.sync.unregister('foobar').then( - function() { - ok(true, "navigator.sync.unregister() worked!"); - runTests(); - }, genericError.bind(null, 'unregister')); -} - -function test_unregisterDuplicate() { - navigator.sync.unregister('foobar').then( - genericError.bind(null, 'unregisterDuplicate'), - function(error) { - ok(true, "navigator.sync.unregister() should throw if the task doesn't exist."); - ok(error, "UnknownTaskError", "Duplicate unregistration error is correct"); - runTests(); - }); -} - -function test_registrationEmpty() { - navigator.sync.registration('bar').then( - function(results) { - is(results, null, "navigator.sync.registration() should return null."); - runTests(); - }, - genericError.bind(null, 'registrationEmpty')); -} - -function test_registration() { - navigator.sync.registration('foobar').then( - function(results) { - is(results.task, 'foobar', "navigator.sync.registration().task is correct"); - ok("lastSync" in results, "navigator.sync.registration().lastSync is correct"); - is(results.oneShot, true, "navigator.sync.registration().oneShot is correct"); - is(results.minInterval, 5, "navigator.sync.registration().minInterval is correct"); - ok("wakeUpPage" in results, "navigator.sync.registration().wakeUpPage is correct"); - ok("wifiOnly" in results, "navigator.sync.registration().wifiOnly is correct"); - ok("data" in results, "navigator.sync.registration().data is correct"); - ok(!("app" in results), "navigator.sync.registrations().app is correct"); - runTests(); - }, - genericError.bind(null, 'registration')); -} - -function test_registrationsEmpty() { - navigator.sync.registrations().then( - function(results) { - is(results.length, 0, "navigator.sync.registrations() should return an empty array."); - runTests(); - }, - genericError.bind(null, 'registrationEmpty')); -} - -function test_registrations() { - navigator.sync.registrations().then( - function(results) { - is(results.length, 1, "navigator.sync.registrations() should not return an empty array."); - is(results[0].task, 'foobar', "navigator.sync.registrations()[0].task is correct"); - ok("lastSync" in results[0], "navigator.sync.registrations()[0].lastSync is correct"); - is(results[0].oneShot, true, "navigator.sync.registrations()[0].oneShot is correct"); - is(results[0].minInterval, 5, "navigator.sync.registrations()[0].minInterval is correct"); - ok("wakeUpPage" in results[0], "navigator.sync.registration()[0].wakeUpPage is correct"); - ok("wifiOnly" in results[0], "navigator.sync.registrations()[0].wifiOnly is correct"); - ok("data" in results[0], "navigator.sync.registrations()[0].data is correct"); - ok(!("app" in results[0]), "navigator.sync.registrations()[0].app is correct"); - runTests(); - }, - genericError.bind(null, 'registrations')); -} - -function test_managerRegistrationsEmpty() { - navigator.syncManager.registrations().then( - function(results) { - is(results.length, 0, "navigator.syncManager.registrations() should return an empty array."); - runTests(); - }, - genericError.bind(null, 'managerRegistrationsEmpty')); -} - -function test_managerRegistrations(state, overwrittenMinInterval) { - navigator.syncManager.registrations().then( - function(results) { - is(results.length, 1, "navigator.sync.registrations() should not return an empty array."); - is(results[0].task, 'foobar', "navigator.sync.registrations()[0].task is correct"); - ok("lastSync" in results[0], "navigator.sync.registrations()[0].lastSync is correct"); - is(results[0].oneShot, true, "navigator.sync.registrations()[0].oneShot is correct"); - is(results[0].minInterval, 5, "navigator.sync.registrations()[0].minInterval is correct"); - ok("wakeUpPage" in results[0], "navigator.sync.registration()[0].wakeUpPage is correct"); - ok("wifiOnly" in results[0], "navigator.sync.registrations()[0].wifiOnly is correct"); - ok("data" in results[0], "navigator.sync.registrations()[0].data is correct"); - ok("app" in results[0], "navigator.sync.registrations()[0].app is correct"); - ok("manifestURL" in results[0].app, "navigator.sync.registrations()[0].app.manifestURL is correct"); - is(results[0].app.origin, 'http://mochi.test:8888', "navigator.sync.registrations()[0].app.origin is correct"); - is(results[0].app.isInBrowserElement, false, "navigator.sync.registrations()[0].app.isInBrowserElement is correct"); - is(results[0].state, state, "navigator.sync.registrations()[0].state is correct"); - is(results[0].overwrittenMinInterval, overwrittenMinInterval, "navigator.sync.registrations()[0].overwrittenMinInterval is correct"); - ok("setPolicy" in results[0], "navigator.sync.registrations()[0].setPolicy is correct"); - ok("runNow" in results[0], "navigator.sync.registrations()[0].runNow is correct"); - runTests(); - }, - genericError.bind(null, 'managerRegistrations')); -} - -function test_managerSetPolicy(state, overwrittenMinInterval) { - navigator.syncManager.registrations().then( - function(results) { - results[0].setPolicy(state, overwrittenMinInterval).then( - function() { - ok(state, results[0].state, "State matches"); - ok(overwrittenMinInterval, results[0].overwrittenMinInterval, "OverwrittenMinInterval matches"); - runTests(); - }, genericError.bind(null, 'managerSetPolicy')); - }).catch(genericError.bind(null, 'managerSetPolicy_catch')); -} diff --git a/dom/requestsync/tests/file_app.sjs b/dom/requestsync/tests/file_app.sjs deleted file mode 100644 index 25c0377881..0000000000 --- a/dom/requestsync/tests/file_app.sjs +++ /dev/null @@ -1,52 +0,0 @@ -var gBasePath = "tests/dom/requestsync/tests/"; -var gTemplate = "file_app.template.webapp"; - -function handleRequest(request, response) { - var query = getQuery(request); - - var testToken = ''; - if ('testToken' in query) { - testToken = query.testToken; - } - - var template = gBasePath + gTemplate; - response.setHeader("Content-Type", "application/x-web-app-manifest+json", false); - response.write(readTemplate(template).replace(/TESTTOKEN/g, testToken)); -} - -// Copy-pasted incantations. There ought to be a better way to synchronously read -// a file into a string, but I guess we're trying to discourage that. -function readTemplate(path) { - var file = Components.classes["@mozilla.org/file/directory_service;1"]. - getService(Components.interfaces.nsIProperties). - get("CurWorkD", Components.interfaces.nsILocalFile); - var fis = Components.classes['@mozilla.org/network/file-input-stream;1']. - createInstance(Components.interfaces.nsIFileInputStream); - var cis = Components.classes["@mozilla.org/intl/converter-input-stream;1"]. - createInstance(Components.interfaces.nsIConverterInputStream); - var split = path.split("/"); - for(var i = 0; i < split.length; ++i) { - file.append(split[i]); - } - fis.init(file, -1, -1, false); - cis.init(fis, "UTF-8", 0, 0); - - var data = ""; - let str = {}; - let read = 0; - do { - read = cis.readString(0xffffffff, str); // read as much as we can and put it in str.value - data += str.value; - } while (read != 0); - cis.close(); - return data; -} - -function getQuery(request) { - var query = {}; - request.queryString.split('&').forEach(function (val) { - var [name, value] = val.split('='); - query[name] = unescape(value); - }); - return query; -} diff --git a/dom/requestsync/tests/file_app.template.webapp b/dom/requestsync/tests/file_app.template.webapp deleted file mode 100644 index 49a6158b9b..0000000000 --- a/dom/requestsync/tests/file_app.template.webapp +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "Really Rapid Release (hosted)", - "description": "Updated even faster than Firefox, just to annoy slashdotters.", - "launch_path": "/tests/dom/requestsync/tests/TESTTOKEN", - "icons": { "128": "default_icon" } -} diff --git a/dom/requestsync/tests/file_basic_app.html b/dom/requestsync/tests/file_basic_app.html deleted file mode 100644 index 28af6a481e..0000000000 --- a/dom/requestsync/tests/file_basic_app.html +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - -
- - - diff --git a/dom/requestsync/tests/file_interface.html b/dom/requestsync/tests/file_interface.html deleted file mode 100644 index fbc40f2300..0000000000 --- a/dom/requestsync/tests/file_interface.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - -
- - - diff --git a/dom/requestsync/tests/mochitest.ini b/dom/requestsync/tests/mochitest.ini deleted file mode 100644 index 1a3018f365..0000000000 --- a/dom/requestsync/tests/mochitest.ini +++ /dev/null @@ -1,25 +0,0 @@ -[DEFAULT] -support-files = - file_app.template.webapp - file_app.sjs - file_basic_app.html - common_app.js - common_basic.js - system_message_chrome_script.js - -[test_webidl.html] -skip-if = os == "android" || toolkit == "gonk" -[test_minInterval.html] -skip-if = os == "android" || toolkit == "gonk" -[test_basic.html] -skip-if = os == "android" || toolkit == "gonk" -[test_basic_app.html] -skip-if = buildapp != 'mulet' || e10s # mozapps -[test_wakeUp.html] -run-if = buildapp == 'b2g' && toolkit == 'gonk' -[test_runNow.html] -run-if = buildapp == 'b2g' && toolkit == 'gonk' -[test_promise.html] -skip-if = os == "android" || toolkit == "gonk" -[test_bug1151082.html] -skip-if = os == "android" || toolkit == "gonk" diff --git a/dom/requestsync/tests/system_message_chrome_script.js b/dom/requestsync/tests/system_message_chrome_script.js deleted file mode 100644 index b00d744ac1..0000000000 --- a/dom/requestsync/tests/system_message_chrome_script.js +++ /dev/null @@ -1,18 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ -'use strict'; - -var { classes: Cc, interfaces: Ci } = Components; - -const systemMessenger = Cc["@mozilla.org/system-message-internal;1"] - .getService(Ci.nsISystemMessagesInternal); -const ioService = Cc["@mozilla.org/network/io-service;1"] - .getService(Ci.nsIIOService); - -addMessageListener("trigger-register-page", function(aData) { - systemMessenger.registerPage(aData.type, - ioService.newURI(aData.pageURL, null, null), - ioService.newURI(aData.manifestURL, null, null)); - sendAsyncMessage("page-registered"); -}); diff --git a/dom/requestsync/tests/test_basic.html b/dom/requestsync/tests/test_basic.html deleted file mode 100644 index 455fcdf1be..0000000000 --- a/dom/requestsync/tests/test_basic.html +++ /dev/null @@ -1,77 +0,0 @@ - - - - - Test for RequestSync basic use - - - - - - - - diff --git a/dom/requestsync/tests/test_basic_app.html b/dom/requestsync/tests/test_basic_app.html deleted file mode 100644 index 06350cc19d..0000000000 --- a/dom/requestsync/tests/test_basic_app.html +++ /dev/null @@ -1,130 +0,0 @@ - - - - - Test for requestSync - basic operations in app - - - - - -
- - - diff --git a/dom/requestsync/tests/test_bug1151082.html b/dom/requestsync/tests/test_bug1151082.html deleted file mode 100644 index 61fd820cab..0000000000 --- a/dom/requestsync/tests/test_bug1151082.html +++ /dev/null @@ -1,77 +0,0 @@ - - - - - Test for RequestSync bug 1151082 - - - - - - - - diff --git a/dom/requestsync/tests/test_minInterval.html b/dom/requestsync/tests/test_minInterval.html deleted file mode 100644 index dbb6d666de..0000000000 --- a/dom/requestsync/tests/test_minInterval.html +++ /dev/null @@ -1,69 +0,0 @@ - - - - - Test for RequestSync minInterval pref - - - - - - - diff --git a/dom/requestsync/tests/test_promise.html b/dom/requestsync/tests/test_promise.html deleted file mode 100644 index 8277eadaa6..0000000000 --- a/dom/requestsync/tests/test_promise.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - Test for requestSync - promise - - - - - -
- - - diff --git a/dom/requestsync/tests/test_runNow.html b/dom/requestsync/tests/test_runNow.html deleted file mode 100644 index 056d5e1eb9..0000000000 --- a/dom/requestsync/tests/test_runNow.html +++ /dev/null @@ -1,125 +0,0 @@ - - - - - Test for requestSync - runNow - - - - - -
- - - diff --git a/dom/requestsync/tests/test_wakeUp.html b/dom/requestsync/tests/test_wakeUp.html deleted file mode 100644 index 434deeea56..0000000000 --- a/dom/requestsync/tests/test_wakeUp.html +++ /dev/null @@ -1,187 +0,0 @@ - - - - - Test for requestSync - wakeUp - - - - - -
- - - diff --git a/dom/requestsync/tests/test_webidl.html b/dom/requestsync/tests/test_webidl.html deleted file mode 100644 index 3d0dda21ec..0000000000 --- a/dom/requestsync/tests/test_webidl.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - - Test for RequestSync interfaces - - - - - - - diff --git a/dom/security/nsCSPParser.cpp b/dom/security/nsCSPParser.cpp index 16050726db..2a6574155a 100644 --- a/dom/security/nsCSPParser.cpp +++ b/dom/security/nsCSPParser.cpp @@ -578,7 +578,8 @@ nsCSPParser::keywordSource() } if (CSP_IsKeyword(mCurToken, CSP_UNSAFE_INLINE)) { - nsCOMPtr doc = do_QueryReferent(mCSPContext->GetLoadingContext()); + nsWeakPtr ctx = mCSPContext->GetLoadingContext(); + nsCOMPtr doc = do_QueryReferent(ctx); if (doc) { doc->SetHasUnsafeInlineCSP(true); } @@ -597,7 +598,8 @@ nsCSPParser::keywordSource() } if (CSP_IsKeyword(mCurToken, CSP_UNSAFE_EVAL)) { - nsCOMPtr doc = do_QueryReferent(mCSPContext->GetLoadingContext()); + nsWeakPtr ctx = mCSPContext->GetLoadingContext(); + nsCOMPtr doc = do_QueryReferent(ctx); if (doc) { doc->SetHasUnsafeEvalCSP(true); } diff --git a/dom/tests/mochitest/general/test_interfaces.html b/dom/tests/mochitest/general/test_interfaces.html index 0b518b9809..842a0caa39 100644 --- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -1300,12 +1300,6 @@ var interfaceNamesInGlobalScope = "SVGZoomAndPan", // IMPORTANT: Do not change this list without review from a DOM peer! "SVGZoomEvent", -// IMPORTANT: Do not change this list without review from a DOM peer! - {name: "RequestSyncManager", b2g: true, permission: ["requestsync-manager"] }, -// IMPORTANT: Do not change this list without review from a DOM peer! - {name: "RequestSyncApp", b2g: true, permission: ["requestsync-manager"] }, -// IMPORTANT: Do not change this list without review from a DOM peer! - {name: "RequestSyncTask", b2g: true, permission: ["requestsync-manager"] }, // IMPORTANT: Do not change this list without review from a DOM peer! {name: "Telephony", b2g: true}, // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/webidl/RequestSyncManager.webidl b/dom/webidl/RequestSyncManager.webidl deleted file mode 100644 index ba6b83de3c..0000000000 --- a/dom/webidl/RequestSyncManager.webidl +++ /dev/null @@ -1,56 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -[AvailableIn=CertifiedApps, - Pref="dom.requestSync.enabled", - CheckAnyPermissions="requestsync-manager", - JSImplementation="@mozilla.org/dom/request-sync-task-app;1"] -interface RequestSyncApp { - readonly attribute USVString origin; - readonly attribute USVString manifestURL; - readonly attribute boolean isInBrowserElement; -}; - -enum RequestSyncTaskPolicyState { "enabled", "disabled", "wifiOnly" }; - -// Like a normal task, but with info about the app. -[AvailableIn=CertifiedApps, - Pref="dom.requestSync.enabled", - CheckAnyPermissions="requestsync-manager", - JSImplementation="@mozilla.org/dom/request-sync-task-manager;1"] -interface RequestSyncTask { - // This object describes the app that is owning the task. - readonly attribute RequestSyncApp app; - - // Using setPolicy it's possible to owerwrite the state and the minInterval. - readonly attribute RequestSyncTaskPolicyState state; - readonly attribute long overwrittenMinInterval; - - // These attributes are taken from the configuration of the task: - - readonly attribute USVString task; - readonly attribute DOMTimeStamp lastSync; - readonly attribute USVString wakeUpPage; - readonly attribute boolean oneShot; - readonly attribute long minInterval; - readonly attribute boolean wifiOnly; - readonly attribute any data; - - Promise setPolicy(RequestSyncTaskPolicyState aState, - optional long ovewrittenMinInterval); - - Promise runNow(); -}; - -[NavigatorProperty="syncManager", - AvailableIn=CertifiedApps, - Pref="dom.requestSync.enabled", - CheckAnyPermissions="requestsync-manager", - JSImplementation="@mozilla.org/dom/request-sync-manager;1"] -// This interface will be used only by the B2G SystemApp -interface RequestSyncManager { - Promise> registrations(); -}; diff --git a/dom/webidl/RequestSyncScheduler.webidl b/dom/webidl/RequestSyncScheduler.webidl deleted file mode 100644 index 1bd33ac12f..0000000000 --- a/dom/webidl/RequestSyncScheduler.webidl +++ /dev/null @@ -1,38 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -// This is the dictionary for the creation of a new task. -dictionary RequestTaskParams { - required USVString wakeUpPage; - boolean oneShot = true; - required long minInterval; // in seconds >= dom.requestSync.minInterval or 100 secs - boolean wifiOnly = true; - any data = null; -}; - - -// This is the dictionary you can have back from registration{s}(). -dictionary RequestTaskFull : RequestTaskParams { - USVString task = ""; - - // Last synchonization date.. maybe it's useful to know. - DOMTimeStamp lastSync; -}; - -[NavigatorProperty="sync", - AvailableIn=CertifiedApps, - Pref="dom.requestSync.enabled", - JSImplementation="@mozilla.org/dom/request-sync-scheduler;1"] -interface RequestSyncScheduler { - - Promise register(USVString task, - optional RequestTaskParams params); - Promise unregister(USVString task); - - // Useful methods to get registrations - Promise> registrations(); - Promise registration(USVString task); -}; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index 62cad6488a..5b5ec55cb7 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -396,8 +396,6 @@ WEBIDL_FILES = [ 'Range.webidl', 'Rect.webidl', 'Request.webidl', - 'RequestSyncManager.webidl', - 'RequestSyncScheduler.webidl', 'ResourceStats.webidl', 'ResourceStatsManager.webidl', 'Response.webidl', diff --git a/editor/libeditor/PlaceholderTxn.cpp b/editor/libeditor/PlaceholderTxn.cpp index 3250e5b568..28f45ce91f 100644 --- a/editor/libeditor/PlaceholderTxn.cpp +++ b/editor/libeditor/PlaceholderTxn.cpp @@ -32,14 +32,14 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(PlaceholderTxn) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PlaceholderTxn, EditAggregateTxn) - tmp->mStartSel->DoUnlink(); - tmp->mEndSel.DoUnlink(); + ImplCycleCollectionUnlink(*tmp->mStartSel); + NS_IMPL_CYCLE_COLLECTION_UNLINK(mEndSel); NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PlaceholderTxn, EditAggregateTxn) - tmp->mStartSel->DoTraverse(cb); - tmp->mEndSel.DoTraverse(cb); + ImplCycleCollectionTraverse(cb, *tmp->mStartSel, "mStartSel", 0); + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEndSel); NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PlaceholderTxn) diff --git a/editor/libeditor/nsEditor.cpp b/editor/libeditor/nsEditor.cpp index 71a6eaaa72..575be62448 100644 --- a/editor/libeditor/nsEditor.cpp +++ b/editor/libeditor/nsEditor.cpp @@ -176,14 +176,9 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsEditor) NS_IMPL_CYCLE_COLLECTION_UNLINK(mEditorObservers) NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocStateListeners) NS_IMPL_CYCLE_COLLECTION_UNLINK(mEventTarget) - - if (tmp->mEventListener) { - nsEditorEventListener* listener = - reinterpret_cast(tmp->mEventListener.get()); - listener->Disconnect(); - tmp->mEventListener = nullptr; - } - + NS_IMPL_CYCLE_COLLECTION_UNLINK(mEventListener) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mSavedSel); + NS_IMPL_CYCLE_COLLECTION_UNLINK(mRangeUpdater); NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsEditor) @@ -202,6 +197,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsEditor) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocStateListeners) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEventTarget) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEventListener) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSavedSel); + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRangeUpdater); NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsEditor) @@ -3261,13 +3258,6 @@ nsEditor::GetLeftmostChild(nsINode *aCurrentNode, return nullptr; } -bool -nsEditor::IsBlockNode(nsIDOMNode* aNode) -{ - nsCOMPtr node = do_QueryInterface(aNode); - return IsBlockNode(node); -} - bool nsEditor::IsBlockNode(nsINode* aNode) { @@ -3363,13 +3353,6 @@ nsEditor::IsDescendantOfRoot(nsINode* inNode) return nsContentUtils::ContentIsDescendantOf(inNode, root); } -bool -nsEditor::IsDescendantOfEditorRoot(nsIDOMNode* aNode) -{ - nsCOMPtr node = do_QueryInterface(aNode); - return IsDescendantOfEditorRoot(node); -} - bool nsEditor::IsDescendantOfEditorRoot(nsINode* aNode) { @@ -3664,13 +3647,15 @@ nsEditor::GetChildAt(nsIDOMNode *aParent, int32_t aOffset) // assuming that aParentOrNode is the node itself if it's a text node, or // the node's parent otherwise. // -nsCOMPtr +nsIContent* nsEditor::GetNodeAtRangeOffsetPoint(nsIDOMNode* aParentOrNode, int32_t aOffset) { - if (IsTextNode(aParentOrNode)) { - return aParentOrNode; + nsCOMPtr parentOrNode = do_QueryInterface(aParentOrNode); + NS_ENSURE_TRUE(parentOrNode || !aParentOrNode, nullptr); + if (parentOrNode->GetAsText()) { + return parentOrNode->AsContent(); } - return GetChildAt(aParentOrNode, aOffset); + return parentOrNode->GetChildAt(aOffset); } @@ -3687,7 +3672,9 @@ nsEditor::GetStartNodeAndOffset(Selection* aSelection, nsCOMPtr startNode; nsresult rv = GetStartNodeAndOffset(aSelection, getter_AddRefs(startNode), outStartOffset); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_FAILED(rv)) { + return rv; + } if (startNode) { NS_ADDREF(*outStartNode = startNode->AsDOMNode()); @@ -3708,7 +3695,9 @@ nsEditor::GetStartNodeAndOffset(Selection* aSelection, nsINode** aStartNode, *aStartNode = nullptr; *aStartOffset = 0; - NS_ENSURE_TRUE(aSelection->RangeCount(), NS_ERROR_FAILURE); + if (!aSelection->RangeCount()) { + return NS_ERROR_FAILURE; + } const nsRange* range = aSelection->GetRangeAt(0); NS_ENSURE_TRUE(range, NS_ERROR_FAILURE); diff --git a/editor/libeditor/nsEditor.h b/editor/libeditor/nsEditor.h index ad6b2c75d0..c373d04ddb 100644 --- a/editor/libeditor/nsEditor.h +++ b/editor/libeditor/nsEditor.h @@ -143,6 +143,11 @@ class nsEditor : public nsIEditor, public nsIPhonetic { public: + typedef mozilla::ErrorResult ErrorResult; + typedef mozilla::dom::Element Element; + typedef mozilla::dom::Selection Selection; + typedef mozilla::dom::Text Text; + template using OwningNonNull = mozilla::OwningNonNull; enum IterDirection { @@ -199,36 +204,33 @@ public: int32_t* aInOutOffset, nsIDocument* aDoc); nsresult InsertTextIntoTextNodeImpl(const nsAString& aStringToInsert, - mozilla::dom::Text& aTextNode, - int32_t aOffset, + Text& aTextNode, int32_t aOffset, bool aSuppressIME = false); NS_IMETHOD DeleteSelectionImpl(EDirection aAction, EStripWrappers aStripWrappers); - already_AddRefed - DeleteSelectionAndCreateElement(nsIAtom& aTag); + already_AddRefed DeleteSelectionAndCreateElement(nsIAtom& aTag); /* helper routines for node/parent manipulations */ nsresult DeleteNode(nsINode* aNode); nsresult InsertNode(nsIContent& aNode, nsINode& aParent, int32_t aPosition); enum ECloneAttributes { eDontCloneAttributes, eCloneAttributes }; - already_AddRefed ReplaceContainer( - mozilla::dom::Element* aOldContainer, - nsIAtom* aNodeType, - nsIAtom* aAttribute = nullptr, - const nsAString* aValue = nullptr, - ECloneAttributes aCloneAttributes = eDontCloneAttributes); - void CloneAttributes(mozilla::dom::Element* aDest, - mozilla::dom::Element* aSource); + already_AddRefed ReplaceContainer(Element* aOldContainer, + nsIAtom* aNodeType, + nsIAtom* aAttribute = nullptr, + const nsAString* aValue = nullptr, + ECloneAttributes aCloneAttributes + = eDontCloneAttributes); + void CloneAttributes(Element* aDest, Element* aSource); nsresult RemoveContainer(nsIContent* aNode); - already_AddRefed InsertContainerAbove( - nsIContent* aNode, - nsIAtom* aNodeType, - nsIAtom* aAttribute = nullptr, - const nsAString* aValue = nullptr); + already_AddRefed InsertContainerAbove(nsIContent* aNode, + nsIAtom* aNodeType, + nsIAtom* aAttribute = nullptr, + const nsAString* aValue = + nullptr); nsIContent* SplitNode(nsIContent& aNode, int32_t aOffset, - mozilla::ErrorResult& aResult); + ErrorResult& aResult); nsresult JoinNodes(nsINode& aLeftNode, nsINode& aRightNode); nsresult MoveNode(nsIContent* aNode, nsINode* aParent, int32_t aOffset); @@ -236,7 +238,7 @@ public: Arguments: nsIAtom* aTag - tag you want */ - already_AddRefed CreateHTMLContent(nsIAtom* aTag); + already_AddRefed CreateHTMLContent(nsIAtom* aTag); // IME event handlers virtual nsresult BeginIMEComposition(mozilla::WidgetCompositionEvent* aEvent); @@ -253,15 +255,14 @@ protected: * returns null. */ already_AddRefed - CreateTxnForSetAttribute(mozilla::dom::Element& aElement, - nsIAtom& aAttribute, const nsAString& aValue); + CreateTxnForSetAttribute(Element& aElement, nsIAtom& aAttribute, + const nsAString& aValue); /** Create a transaction for removing aAttribute on aElement. Never returns * null. */ already_AddRefed - CreateTxnForRemoveAttribute(mozilla::dom::Element& aElement, - nsIAtom& aAttribute); + CreateTxnForRemoveAttribute(Element& aElement, nsIAtom& aAttribute); /** create a transaction for creating a new child node of aParent of type aTag. */ @@ -270,9 +271,8 @@ protected: nsINode& aParent, int32_t aPosition); - already_AddRefed CreateNode(nsIAtom* aTag, - nsINode* aParent, - int32_t aPosition); + already_AddRefed CreateNode(nsIAtom* aTag, nsINode* aParent, + int32_t aPosition); /** create a transaction for inserting aNode as a child of aParent. */ @@ -302,8 +302,8 @@ protected: * returns null. */ already_AddRefed - CreateTxnForInsertText(const nsAString& aStringToInsert, - mozilla::dom::Text& aTextNode, int32_t aOffset); + CreateTxnForInsertText(const nsAString& aStringToInsert, Text& aTextNode, + int32_t aOffset); // Never returns null. already_AddRefed @@ -365,7 +365,7 @@ protected: NS_IMETHOD NotifyDocumentListeners(TDocumentListenerNotification aNotificationType); /** make the given selection span the entire document */ - virtual nsresult SelectEntireDocument(mozilla::dom::Selection* aSelection); + virtual nsresult SelectEntireDocument(Selection* aSelection); /** helper method for scrolling the selection into view after * an edit operation. aScrollToAnchor should be true if you @@ -379,8 +379,6 @@ protected: */ NS_IMETHOD ScrollSelectionIntoView(bool aScrollToAnchor); - // Convenience method; forwards to IsBlockNode(nsINode*). - bool IsBlockNode(nsIDOMNode* aNode); // stub. see comment in source. virtual bool IsBlockNode(nsINode* aNode); @@ -431,8 +429,8 @@ public: /** routines for managing the preservation of selection across * various editor actions */ bool ArePreservingSelection(); - void PreserveSelectionAcrossActions(mozilla::dom::Selection* aSel); - nsresult RestorePreservedSelection(mozilla::dom::Selection* aSel); + void PreserveSelectionAcrossActions(Selection* aSel); + nsresult RestorePreservedSelection(Selection* aSel); void StopPreservingSelection(); /** @@ -557,7 +555,6 @@ public: /** returns true if aNode is a descendant of our root node */ bool IsDescendantOfRoot(nsIDOMNode* inNode); bool IsDescendantOfRoot(nsINode* inNode); - bool IsDescendantOfEditorRoot(nsIDOMNode* aNode); bool IsDescendantOfEditorRoot(nsINode* aNode); /** returns true if aNode is a container */ @@ -601,24 +598,25 @@ public: static bool IsTextNode(nsINode *aNode); static nsCOMPtr GetChildAt(nsIDOMNode *aParent, int32_t aOffset); - static nsCOMPtr GetNodeAtRangeOffsetPoint(nsIDOMNode* aParentOrNode, int32_t aOffset); + static nsIContent* GetNodeAtRangeOffsetPoint(nsIDOMNode* aParentOrNode, + int32_t aOffset); - static nsresult GetStartNodeAndOffset(mozilla::dom::Selection* aSelection, + static nsresult GetStartNodeAndOffset(Selection* aSelection, nsIDOMNode** outStartNode, int32_t* outStartOffset); - static nsresult GetStartNodeAndOffset(mozilla::dom::Selection* aSelection, + static nsresult GetStartNodeAndOffset(Selection* aSelection, nsINode** aStartNode, int32_t* aStartOffset); - static nsresult GetEndNodeAndOffset(mozilla::dom::Selection* aSelection, + static nsresult GetEndNodeAndOffset(Selection* aSelection, nsIDOMNode** outEndNode, int32_t* outEndOffset); - static nsresult GetEndNodeAndOffset(mozilla::dom::Selection* aSelection, + static nsresult GetEndNodeAndOffset(Selection* aSelection, nsINode** aEndNode, int32_t* aEndOffset); #if DEBUG_JOE static void DumpNode(nsIDOMNode *aNode, int32_t indent=0); #endif - mozilla::dom::Selection* GetSelection(int16_t aSelectionType = + Selection* GetSelection(int16_t aSelectionType = nsISelectionController::SELECTION_NORMAL); // Helpers to add a node to the selection. @@ -653,7 +651,7 @@ public: virtual nsresult HandleKeyPressEvent(nsIDOMKeyEvent* aKeyEvent); nsresult HandleInlineSpellCheck(EditAction action, - mozilla::dom::Selection* aSelection, + Selection* aSelection, nsIDOMNode *previousSelectedNode, int32_t previousSelectedOffset, nsIDOMNode *aStartNode, @@ -664,15 +662,15 @@ public: virtual already_AddRefed GetDOMEventTarget() = 0; // Fast non-refcounting editor root element accessor - mozilla::dom::Element *GetRoot(); + Element* GetRoot(); // Likewise, but gets the editor's root instead, which is different for HTML // editors - virtual mozilla::dom::Element* GetEditorRoot(); + virtual Element* GetEditorRoot(); // Likewise, but gets the text control element instead of the root for // plaintext editors - mozilla::dom::Element* GetExposedRoot(); + Element* GetExposedRoot(); // Accessor methods to flags bool IsPlaintextEditor() const @@ -835,8 +833,8 @@ protected: nsCOMPtr mInlineSpellChecker; RefPtr mTxnMgr; - nsCOMPtr mRootElement; // cached root node - RefPtr mIMETextNode; // current IME text node + nsCOMPtr mRootElement; // cached root node + RefPtr mIMETextNode; // current IME text node nsCOMPtr mEventTarget; // The form field as an event receiver nsCOMPtr mEventListener; nsWeakPtr mSelConWeak; // weak reference to the nsISelectionController @@ -851,11 +849,11 @@ protected: // various listeners // Listens to all low level actions on the doc - nsTArray> mActionListeners; + nsTArray> mActionListeners; // Just notify once per high level change - nsTArray> mEditorObservers; + nsTArray> mEditorObservers; // Listen to overall doc state (dirty or not, just created, etc) - nsTArray> mDocStateListeners; + nsTArray> mDocStateListeners; nsSelectionState mSavedSel; // cached selection for nsAutoSelectionReset nsRangeUpdater mRangeUpdater; // utility class object for maintaining preserved ranges diff --git a/editor/libeditor/nsEditorEventListener.cpp b/editor/libeditor/nsEditorEventListener.cpp index e07431e538..f5f1a00a5d 100644 --- a/editor/libeditor/nsEditorEventListener.cpp +++ b/editor/libeditor/nsEditorEventListener.cpp @@ -324,7 +324,11 @@ nsEditorEventListener::GetFocusedRootContent() nsIDocument* composedDoc = focusedContent->GetComposedDoc(); NS_ENSURE_TRUE(composedDoc, nullptr); - return composedDoc->HasFlag(NODE_IS_EDITABLE) ? nullptr : focusedContent; + if (composedDoc->HasFlag(NODE_IS_EDITABLE)) { + return nullptr; + } + + return focusedContent; } bool @@ -1073,6 +1077,11 @@ nsEditorEventListener::Focus(nsIDOMEvent* aEvent) // Spell check a textarea the first time that it is focused. SpellCheckIfNeeded(); + if (!mEditor) { + // In e10s, this can cause us to flush notifications, which can destroy + // the node we're about to focus. + return NS_OK; + } nsCOMPtr target; aEvent->GetTarget(getter_AddRefs(target)); diff --git a/editor/libeditor/nsHTMLAbsPosition.cpp b/editor/libeditor/nsHTMLAbsPosition.cpp index 248772dcf5..28ff360bdd 100644 --- a/editor/libeditor/nsHTMLAbsPosition.cpp +++ b/editor/libeditor/nsHTMLAbsPosition.cpp @@ -83,17 +83,14 @@ nsHTMLEditor::AbsolutePositionSelection(bool aEnabled) NS_IMETHODIMP nsHTMLEditor::GetAbsolutelyPositionedSelectionContainer(nsIDOMElement **_retval) { - nsCOMPtr element; - nsresult res = GetSelectionContainer(getter_AddRefs(element)); - NS_ENSURE_SUCCESS(res, res); - nsAutoString positionStr; - nsCOMPtr node = do_QueryInterface(element); + nsCOMPtr node = GetSelectionContainer(); nsCOMPtr resultNode; while (!resultNode && node && !node->IsHTMLElement(nsGkAtoms::html)) { - res = mHTMLCSSUtils->GetComputedProperty(*node, *nsGkAtoms::position, - positionStr); + nsresult res = + mHTMLCSSUtils->GetComputedProperty(*node, *nsGkAtoms::position, + positionStr); NS_ENSURE_SUCCESS(res, res); if (positionStr.EqualsLiteral("absolute")) resultNode = GetAsDOMNode(node); @@ -102,9 +99,8 @@ nsHTMLEditor::GetAbsolutelyPositionedSelectionContainer(nsIDOMElement **_retval) } } - element = do_QueryInterface(resultNode ); - *_retval = element; - NS_IF_ADDREF(*_retval); + nsCOMPtr element = do_QueryInterface(resultNode); + element.forget(_retval); return NS_OK; } @@ -504,7 +500,7 @@ nsHTMLEditor::AbsolutelyPositionElement(nsIDOMElement* aElement, AddPositioningOffset(x, y); SnapToGrid(x, y); - SetElementPosition(aElement, x, y); + SetElementPosition(*element, x, y); // we may need to create a br if the positioned element is alone in its // container @@ -583,13 +579,19 @@ nsHTMLEditor::SetElementPosition(nsIDOMElement *aElement, int32_t aX, int32_t aY { nsCOMPtr element = do_QueryInterface(aElement); NS_ENSURE_STATE(element); - nsAutoEditBatch batchIt(this); - mHTMLCSSUtils->SetCSSPropertyPixels(*element, *nsGkAtoms::left, aX); - mHTMLCSSUtils->SetCSSPropertyPixels(*element, *nsGkAtoms::top, aY); + SetElementPosition(*element, aX, aY); return NS_OK; } +void +nsHTMLEditor::SetElementPosition(dom::Element& aElement, int32_t aX, int32_t aY) +{ + nsAutoEditBatch batchIt(this); + mHTMLCSSUtils->SetCSSPropertyPixels(aElement, *nsGkAtoms::left, aX); + mHTMLCSSUtils->SetCSSPropertyPixels(aElement, *nsGkAtoms::top, aY); +} + // self-explanatory NS_IMETHODIMP nsHTMLEditor::GetPositionedElement(nsIDOMElement ** aReturn) diff --git a/editor/libeditor/nsHTMLAnonymousUtils.cpp b/editor/libeditor/nsHTMLAnonymousUtils.cpp index 7d9e991f64..039ce40a60 100644 --- a/editor/libeditor/nsHTMLAnonymousUtils.cpp +++ b/editor/libeditor/nsHTMLAnonymousUtils.cpp @@ -148,8 +148,8 @@ nsHTMLEditor::CreateAnonymousElement(const nsAString & aTag, nsIDOMNode * aPare NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED); // Create a new node through the element factory - nsCOMPtr newContent = - CreateHTMLContent(nsCOMPtr(NS_Atomize(aTag))); + nsCOMPtr tagAtom = NS_Atomize(aTag); + nsCOMPtr newContent = CreateHTMLContent(tagAtom); NS_ENSURE_STATE(newContent); nsCOMPtr newElement = do_QueryInterface(newContent); diff --git a/editor/libeditor/nsHTMLDataTransfer.cpp b/editor/libeditor/nsHTMLDataTransfer.cpp index cea880433f..b4bb8a9210 100644 --- a/editor/libeditor/nsHTMLDataTransfer.cpp +++ b/editor/libeditor/nsHTMLDataTransfer.cpp @@ -344,8 +344,7 @@ nsHTMLEditor::DoInsertHTMLWithContext(const nsAString & aInputString, if (aClearStyle) { // pasting does not inherit local inline styles - nsCOMPtr tmpNode = - do_QueryInterface(selection->GetAnchorNode()); + nsCOMPtr tmpNode = selection->GetAnchorNode(); int32_t tmpOffset = static_cast(selection->AnchorOffset()); rv = ClearStyle(address_of(tmpNode), &tmpOffset, nullptr, nullptr); NS_ENSURE_SUCCESS(rv, rv); @@ -382,8 +381,8 @@ nsHTMLEditor::DoInsertHTMLWithContext(const nsAString & aInputString, NS_ENSURE_TRUE(parentNode, NS_ERROR_FAILURE); // Adjust position based on the first node we are going to insert. - NormalizeEOLInsertPosition(GetAsDOMNode(nodeList[0]), - address_of(parentNode), &offsetOfNewNode); + NormalizeEOLInsertPosition(nodeList[0], address_of(parentNode), + &offsetOfNewNode); // if there are any invisible br's after our insertion point, remove them. // this is because if there is a br at end of what we paste, it will make @@ -457,7 +456,9 @@ nsHTMLEditor::DoInsertHTMLWithContext(const nsAString & aInputString, nsCOMPtr parentBlock, lastInsertNode, insertedContextParent; int32_t listCount = nodeList.Length(); int32_t j; - if (IsBlockNode(parentNode)) + nsCOMPtr parentNodeNode = do_QueryInterface(parentNode); + NS_ENSURE_STATE(parentNodeNode || !parentNode); + if (IsBlockNode(parentNodeNode)) parentBlock = parentNode; else parentBlock = GetBlockNodeParent(parentNode); diff --git a/editor/libeditor/nsHTMLEditRules.cpp b/editor/libeditor/nsHTMLEditRules.cpp index 00798466d4..803d6710ca 100644 --- a/editor/libeditor/nsHTMLEditRules.cpp +++ b/editor/libeditor/nsHTMLEditRules.cpp @@ -75,14 +75,12 @@ enum * first some helpful functors we will use ********************************************************/ -static bool IsBlockNode(nsIDOMNode* node) +static bool IsBlockNode(const nsINode& node) { - bool isBlock (false); - nsHTMLEditor::NodeIsBlockStatic(node, &isBlock); - return isBlock; + return nsHTMLEditor::NodeIsBlockStatic(&node); } -static bool IsInlineNode(nsIDOMNode* node) +static bool IsInlineNode(const nsINode& node) { return !IsBlockNode(node); } @@ -135,7 +133,7 @@ class nsEmptyEditableFunctor : public nsBoolDomIterFunctor { if (mHTMLEditor->IsEditable(aNode) && (nsHTMLEditUtils::IsListItem(aNode) || - nsHTMLEditUtils::IsTableCellOrCaption(GetAsDOMNode(aNode)))) { + nsHTMLEditUtils::IsTableCellOrCaption(*aNode))) { bool bIsEmptyNode; nsresult res = mHTMLEditor->IsEmptyNode(aNode, &bIsEmptyNode, false, false); NS_ENSURE_SUCCESS(res, false); @@ -234,8 +232,13 @@ nsHTMLEditRules::~nsHTMLEditRules() NS_IMPL_ADDREF_INHERITED(nsHTMLEditRules, nsTextEditRules) NS_IMPL_RELEASE_INHERITED(nsHTMLEditRules, nsTextEditRules) -NS_IMPL_QUERY_INTERFACE_INHERITED(nsHTMLEditRules, nsTextEditRules, nsIEditActionListener) +NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLEditRules) + NS_INTERFACE_TABLE_INHERITED(nsHTMLEditRules, nsIEditActionListener) +NS_INTERFACE_TABLE_TAIL_INHERITING(nsTextEditRules) +NS_IMPL_CYCLE_COLLECTION_INHERITED(nsHTMLEditRules, nsTextEditRules, + mDocChangeRange, mUtilRange, mNewBlock, + mRangeItem) /******************************************************** * Public methods @@ -307,64 +310,66 @@ NS_IMETHODIMP nsHTMLEditRules::BeforeEdit(EditAction action, nsIEditor::EDirection aDirection) { - if (mLockRulesSniffing) return NS_OK; + if (mLockRulesSniffing) { + return NS_OK; + } - nsAutoLockRulesSniffing lockIt((nsTextEditRules*)this); + NS_ENSURE_STATE(mHTMLEditor); + nsCOMPtr kungFuDeathGrip(mHTMLEditor); + + nsAutoLockRulesSniffing lockIt(this); mDidExplicitlySetInterline = false; - if (!mActionNesting++) - { - // clear our flag about if just deleted a range + if (!mActionNesting) { + mActionNesting++; + + // Clear our flag about if just deleted a range mDidRangedDelete = false; - // remember where our selection was before edit action took place: + // Remember where our selection was before edit action took place: - // get selection - NS_ENSURE_STATE(mHTMLEditor); + // Get selection RefPtr selection = mHTMLEditor->GetSelection(); - // get the selection location - NS_ENSURE_STATE(selection->RangeCount()); + // Get the selection location + if (!selection->RangeCount()) { + return NS_ERROR_UNEXPECTED; + } mRangeItem->startNode = selection->GetRangeAt(0)->GetStartParent(); mRangeItem->startOffset = selection->GetRangeAt(0)->StartOffset(); mRangeItem->endNode = selection->GetRangeAt(0)->GetEndParent(); mRangeItem->endOffset = selection->GetRangeAt(0)->EndOffset(); - nsCOMPtr selStartNode = GetAsDOMNode(mRangeItem->startNode); - nsCOMPtr selEndNode = GetAsDOMNode(mRangeItem->endNode); + nsCOMPtr selStartNode = mRangeItem->startNode; + nsCOMPtr selEndNode = mRangeItem->endNode; - // register this range with range updater to track this as we perturb the doc - NS_ENSURE_STATE(mHTMLEditor); + // Register with range updater to track this as we perturb the doc (mHTMLEditor->mRangeUpdater).RegisterRangeItem(mRangeItem); - // clear deletion state bool + // Clear deletion state bool mDidDeleteSelection = false; - // clear out mDocChangeRange and mUtilRange - if(mDocChangeRange) - { - // clear out our accounting of what changed + // Clear out mDocChangeRange and mUtilRange + if (mDocChangeRange) { + // Clear out our accounting of what changed mDocChangeRange->Reset(); } - if(mUtilRange) - { - // ditto for mUtilRange. + if (mUtilRange) { + // Ditto for mUtilRange. mUtilRange->Reset(); } - // remember current inline styles for deletion and normal insertion operations + // Remember current inline styles for deletion and normal insertion ops if (action == EditAction::insertText || action == EditAction::insertIMEText || action == EditAction::deleteSelection || IsStyleCachePreservingAction(action)) { - nsCOMPtr selNode = selStartNode; - if (aDirection == nsIEditor::eNext) - selNode = selEndNode; - nsresult res = CacheInlineStyles(selNode); - NS_ENSURE_SUCCESS(res, res); + nsCOMPtr selNode = + aDirection == nsIEditor::eNext ? selEndNode : selStartNode; + nsresult rv = CacheInlineStyles(GetAsDOMNode(selNode)); + NS_ENSURE_SUCCESS(rv, rv); } // Stabilize the document against contenteditable count changes - NS_ENSURE_STATE(mHTMLEditor); nsCOMPtr doc = mHTMLEditor->GetDOMDocument(); NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED); nsCOMPtr htmlDoc = do_QueryInterface(doc); @@ -374,9 +379,9 @@ nsHTMLEditRules::BeforeEdit(EditAction action, mRestoreContentEditableCount = true; } - // check that selection is in subtree defined by body node + // Check that selection is in subtree defined by body node ConfirmSelectionInBody(); - // let rules remember the top level action + // Let rules remember the top level action mTheAction = action; } return NS_OK; @@ -387,24 +392,27 @@ NS_IMETHODIMP nsHTMLEditRules::AfterEdit(EditAction action, nsIEditor::EDirection aDirection) { - if (mLockRulesSniffing) return NS_OK; + if (mLockRulesSniffing) { + return NS_OK; + } + + NS_ENSURE_STATE(mHTMLEditor); + nsCOMPtr kungFuDeathGrip(mHTMLEditor); nsAutoLockRulesSniffing lockIt(this); - NS_PRECONDITION(mActionNesting>0, "bad action nesting!"); - nsresult res = NS_OK; - if (!--mActionNesting) - { - // do all the tricky stuff - res = AfterEditInner(action, aDirection); + MOZ_ASSERT(mActionNesting > 0); + nsresult rv = NS_OK; + mActionNesting--; + if (!mActionNesting) { + // Do all the tricky stuff + rv = AfterEditInner(action, aDirection); - // free up selectionState range item - NS_ENSURE_STATE(mHTMLEditor); + // Free up selectionState range item (mHTMLEditor->mRangeUpdater).DropRangeItem(mRangeItem); // Reset the contenteditable count to its previous value if (mRestoreContentEditableCount) { - NS_ENSURE_STATE(mHTMLEditor); nsCOMPtr doc = mHTMLEditor->GetDOMDocument(); NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED); nsCOMPtr htmlDoc = do_QueryInterface(doc); @@ -416,7 +424,9 @@ nsHTMLEditRules::AfterEdit(EditAction action, } } - return res; + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; } @@ -496,6 +506,8 @@ nsHTMLEditRules::AfterEditInner(EditAction action, // also do this for original selection endpoints. NS_ENSURE_STATE(mHTMLEditor); + NS_ENSURE_STATE(mRangeItem->startNode); + NS_ENSURE_STATE(mRangeItem->endNode); nsWSRunObject(mHTMLEditor, mRangeItem->startNode, mRangeItem->startOffset).AdjustWhitespace(); // we only need to handle old selection endpoint if it was different from start @@ -556,10 +568,10 @@ nsHTMLEditRules::AfterEditInner(EditAction action, if (!mDidExplicitlySetInterline) { - res = CheckInterlinePosition(selection); + CheckInterlinePosition(*selection); } - return res; + return NS_OK; } @@ -626,7 +638,7 @@ nsHTMLEditRules::WillDoAction(Selection* aSelection, return WillLoadHTML(aSelection, aCancel); case EditAction::insertBreak: UndefineCaretBidiLevel(aSelection); - return WillInsertBreak(aSelection, aCancel, aHandled); + return WillInsertBreak(*aSelection, aCancel, aHandled); case EditAction::deleteSelection: return WillDeleteSelection(aSelection, info->collapsedAction, info->stripWrappers, aCancel, aHandled); @@ -636,22 +648,24 @@ nsHTMLEditRules::WillDoAction(Selection* aSelection, case EditAction::indent: return WillIndent(aSelection, aCancel, aHandled); case EditAction::outdent: - return WillOutdent(aSelection, aCancel, aHandled); + return WillOutdent(*aSelection, aCancel, aHandled); case EditAction::setAbsolutePosition: - return WillAbsolutePosition(aSelection, aCancel, aHandled); + return WillAbsolutePosition(*aSelection, aCancel, aHandled); case EditAction::removeAbsolutePosition: return WillRemoveAbsolutePosition(aSelection, aCancel, aHandled); case EditAction::align: - return WillAlign(aSelection, info->alignType, aCancel, aHandled); + return WillAlign(*aSelection, *info->alignType, aCancel, aHandled); case EditAction::makeBasicBlock: - return WillMakeBasicBlock(aSelection, info->blockType, aCancel, aHandled); + return WillMakeBasicBlock(*aSelection, *info->blockType, aCancel, + aHandled); case EditAction::removeList: return WillRemoveList(aSelection, info->bOrdered, aCancel, aHandled); case EditAction::makeDefListItem: return WillMakeDefListItem(aSelection, info->blockType, info->entireList, aCancel, aHandled); case EditAction::insertElement: - return WillInsert(aSelection, aCancel); + WillInsert(*aSelection, aCancel); + return NS_OK; case EditAction::decreaseZIndex: return WillRelativeChangeZIndex(aSelection, -1, aCancel, aHandled); case EditAction::increaseZIndex: @@ -783,165 +797,139 @@ nsHTMLEditRules::GetListItemState(bool *aMixed, bool *aLI, bool *aDT, bool *aDD) } nsresult -nsHTMLEditRules::GetAlignment(bool *aMixed, nsIHTMLEditor::EAlignment *aAlign) +nsHTMLEditRules::GetAlignment(bool* aMixed, nsIHTMLEditor::EAlignment* aAlign) { - // for now, just return first alignment. we'll lie about - // if it's mixed. This is for efficiency - // given that our current ui doesn't care if it's mixed. - // cmanske: NOT TRUE! We would like to pay attention to mixed state - // in Format | Align submenu! + MOZ_ASSERT(aMixed && aAlign); - // this routine assumes that alignment is done ONLY via divs + NS_ENSURE_STATE(mHTMLEditor); + nsCOMPtr kungFuDeathGrip(mHTMLEditor); - // default alignment is left - NS_ENSURE_TRUE(aMixed && aAlign, NS_ERROR_NULL_POINTER); + // For now, just return first alignment. We'll lie about if it's mixed. + // This is for efficiency given that our current ui doesn't care if it's + // mixed. + // cmanske: NOT TRUE! We would like to pay attention to mixed state in Format + // | Align submenu! + + // This routine assumes that alignment is done ONLY via divs + + // Default alignment is left *aMixed = false; *aAlign = nsIHTMLEditor::eLeft; - // get selection - NS_ENSURE_STATE(mHTMLEditor); - RefPtr selection = mHTMLEditor->GetSelection(); - NS_ENSURE_STATE(selection); + // Get selection + NS_ENSURE_STATE(mHTMLEditor->GetSelection()); + OwningNonNull selection = *mHTMLEditor->GetSelection(); - // get selection location - NS_ENSURE_STATE(mHTMLEditor); - nsCOMPtr rootElem = mHTMLEditor->GetRoot(); - NS_ENSURE_TRUE(rootElem, NS_ERROR_FAILURE); + // Get selection location + NS_ENSURE_TRUE(mHTMLEditor->GetRoot(), NS_ERROR_FAILURE); + OwningNonNull root = *mHTMLEditor->GetRoot(); - int32_t offset, rootOffset; - nsCOMPtr parent = nsEditor::GetNodeLocation(rootElem, &rootOffset); - NS_ENSURE_STATE(mHTMLEditor); - nsresult res = mHTMLEditor->GetStartNodeAndOffset(selection, - getter_AddRefs(parent), - &offset); - NS_ENSURE_SUCCESS(res, res); + int32_t rootOffset = root->GetParentNode() ? + root->GetParentNode()->IndexOf(root) : -1; - // is the selection collapsed? + NS_ENSURE_STATE(selection->GetRangeAt(0) && + selection->GetRangeAt(0)->GetStartParent()); + OwningNonNull parent = *selection->GetRangeAt(0)->GetStartParent(); + int32_t offset = selection->GetRangeAt(0)->StartOffset(); + + // Is the selection collapsed? nsCOMPtr nodeToExamine; - if (selection->Collapsed()) { - // if it is, we want to look at 'parent' and its ancestors - // for divs with alignment on them - nodeToExamine = parent; - } - else if (!mHTMLEditor) { - return NS_ERROR_UNEXPECTED; - } - else if (mHTMLEditor->IsTextNode(parent)) - { - // if we are in a text node, then that is the node of interest + if (selection->Collapsed() || parent->GetAsText()) { + // If selection is collapsed, we want to look at 'parent' and its ancestors + // for divs with alignment on them. If we are in a text node, then that is + // the node of interest. nodeToExamine = parent; } else if (parent->IsHTMLElement(nsGkAtoms::html) && offset == rootOffset) { - // if we have selected the body, let's look at the first editable node - NS_ENSURE_STATE(mHTMLEditor); + // If we have selected the body, let's look at the first editable node nodeToExamine = mHTMLEditor->GetNextNode(parent, offset, true); - } - else - { + } else { nsTArray> arrayOfRanges; - GetPromotedRanges(*selection, arrayOfRanges, EditAction::align); + GetPromotedRanges(selection, arrayOfRanges, EditAction::align); - // use these ranges to construct a list of nodes to act on. + // Use these ranges to construct a list of nodes to act on. nsTArray> arrayOfNodes; - res = GetNodesForOperation(arrayOfRanges, arrayOfNodes, - EditAction::align, TouchContent::no); - NS_ENSURE_SUCCESS(res, res); + nsresult rv = GetNodesForOperation(arrayOfRanges, arrayOfNodes, + EditAction::align, TouchContent::no); + NS_ENSURE_SUCCESS(rv, rv); nodeToExamine = arrayOfNodes.SafeElementAt(0); } NS_ENSURE_TRUE(nodeToExamine, NS_ERROR_NULL_POINTER); NS_NAMED_LITERAL_STRING(typeAttrName, "align"); - nsIAtom *dummyProperty = nullptr; - NS_ENSURE_STATE(mHTMLEditor); nsCOMPtr blockParent = mHTMLEditor->GetBlock(*nodeToExamine); NS_ENSURE_TRUE(blockParent, NS_ERROR_FAILURE); - NS_ENSURE_STATE(mHTMLEditor); - if (mHTMLEditor->IsCSSEnabled()) - { - NS_ENSURE_STATE(mHTMLEditor); - if (mHTMLEditor->mHTMLCSSUtils->IsCSSEditableProperty(blockParent, - dummyProperty, - &typeAttrName)) { - // we are in CSS mode and we know how to align this element with CSS - nsAutoString value; - // let's get the value(s) of text-align or margin-left/margin-right - NS_ENSURE_STATE(mHTMLEditor); - mHTMLEditor->mHTMLCSSUtils->GetCSSEquivalentToHTMLInlineStyleSet( - blockParent, dummyProperty, &typeAttrName, value, - nsHTMLCSSUtils::eComputed); - if (value.EqualsLiteral("center") || - value.EqualsLiteral("-moz-center") || - value.EqualsLiteral("auto auto")) - { - *aAlign = nsIHTMLEditor::eCenter; - return NS_OK; - } - if (value.EqualsLiteral("right") || - value.EqualsLiteral("-moz-right") || - value.EqualsLiteral("auto 0px")) - { - *aAlign = nsIHTMLEditor::eRight; - return NS_OK; - } - if (value.EqualsLiteral("justify")) - { - *aAlign = nsIHTMLEditor::eJustify; - return NS_OK; - } - *aAlign = nsIHTMLEditor::eLeft; + if (mHTMLEditor->IsCSSEnabled() && + mHTMLEditor->mHTMLCSSUtils->IsCSSEditableProperty(blockParent, nullptr, + &typeAttrName)) { + // We are in CSS mode and we know how to align this element with CSS + nsAutoString value; + // Let's get the value(s) of text-align or margin-left/margin-right + mHTMLEditor->mHTMLCSSUtils->GetCSSEquivalentToHTMLInlineStyleSet( + blockParent, nullptr, &typeAttrName, value, nsHTMLCSSUtils::eComputed); + if (value.EqualsLiteral("center") || + value.EqualsLiteral("-moz-center") || + value.EqualsLiteral("auto auto")) { + *aAlign = nsIHTMLEditor::eCenter; return NS_OK; } + if (value.EqualsLiteral("right") || + value.EqualsLiteral("-moz-right") || + value.EqualsLiteral("auto 0px")) { + *aAlign = nsIHTMLEditor::eRight; + return NS_OK; + } + if (value.EqualsLiteral("justify")) { + *aAlign = nsIHTMLEditor::eJustify; + return NS_OK; + } + *aAlign = nsIHTMLEditor::eLeft; + return NS_OK; } - // check up the ladder for divs with alignment + // Check up the ladder for divs with alignment bool isFirstNodeToExamine = true; - while (nodeToExamine) - { - if (!isFirstNodeToExamine && nsHTMLEditUtils::IsTable(nodeToExamine)) - { - // the node to examine is a table and this is not the first node - // we examine; let's break here to materialize the 'inline-block' - // behaviour of html tables regarding to text alignment + for (; nodeToExamine; nodeToExamine = nodeToExamine->GetParentNode()) { + if (!isFirstNodeToExamine && + nodeToExamine->IsHTMLElement(nsGkAtoms::table)) { + // The node to examine is a table and this is not the first node we + // examine; let's break here to materialize the 'inline-block' behaviour + // of html tables regarding to text alignment return NS_OK; } if (nsHTMLEditUtils::SupportsAlignAttr(GetAsDOMNode(nodeToExamine))) { - // check for alignment - nsCOMPtr elem = do_QueryInterface(nodeToExamine); - if (elem) - { - nsAutoString typeAttrVal; - res = elem->GetAttribute(NS_LITERAL_STRING("align"), typeAttrVal); - ToLowerCase(typeAttrVal); - if (NS_SUCCEEDED(res) && typeAttrVal.Length()) - { - if (typeAttrVal.EqualsLiteral("center")) - *aAlign = nsIHTMLEditor::eCenter; - else if (typeAttrVal.EqualsLiteral("right")) - *aAlign = nsIHTMLEditor::eRight; - else if (typeAttrVal.EqualsLiteral("justify")) - *aAlign = nsIHTMLEditor::eJustify; - else - *aAlign = nsIHTMLEditor::eLeft; - return res; + // Check for alignment + nsAutoString typeAttrVal; + nodeToExamine->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::align, + typeAttrVal); + ToLowerCase(typeAttrVal); + if (!typeAttrVal.IsEmpty()) { + if (typeAttrVal.EqualsLiteral("center")) { + *aAlign = nsIHTMLEditor::eCenter; + } else if (typeAttrVal.EqualsLiteral("right")) { + *aAlign = nsIHTMLEditor::eRight; + } else if (typeAttrVal.EqualsLiteral("justify")) { + *aAlign = nsIHTMLEditor::eJustify; + } else { + *aAlign = nsIHTMLEditor::eLeft; } + return NS_OK; } } isFirstNodeToExamine = false; - nodeToExamine = nodeToExamine->GetParentNode(); } return NS_OK; } -static nsIAtom* MarginPropertyAtomForIndent(nsHTMLCSSUtils* aHTMLCSSUtils, - nsIDOMNode* aNode) { - nsCOMPtr node = do_QueryInterface(aNode); - NS_ENSURE_TRUE(node || !aNode, nsGkAtoms::marginLeft); +static nsIAtom& MarginPropertyAtomForIndent(nsHTMLCSSUtils& aHTMLCSSUtils, + nsINode& aNode) +{ nsAutoString direction; - aHTMLCSSUtils->GetComputedProperty(*node, *nsGkAtoms::direction, direction); + aHTMLCSSUtils.GetComputedProperty(aNode, *nsGkAtoms::direction, direction); return direction.EqualsLiteral("rtl") ? - nsGkAtoms::marginRight : nsGkAtoms::marginLeft; + *nsGkAtoms::marginRight : *nsGkAtoms::marginLeft; } nsresult @@ -974,14 +962,13 @@ nsHTMLEditRules::GetIndentState(bool *aCanIndent, bool *aCanOutdent) else if (useCSS) { // we are in CSS mode, indentation is done using the margin-left (or margin-right) property NS_ENSURE_STATE(mHTMLEditor); - nsIAtom* marginProperty = - MarginPropertyAtomForIndent(mHTMLEditor->mHTMLCSSUtils, - GetAsDOMNode(curNode)); + nsIAtom& marginProperty = + MarginPropertyAtomForIndent(*mHTMLEditor->mHTMLCSSUtils, curNode); nsAutoString value; // retrieve its specified value NS_ENSURE_STATE(mHTMLEditor); mHTMLEditor->mHTMLCSSUtils->GetSpecifiedProperty(*curNode, - *marginProperty, value); + marginProperty, value); float f; nsCOMPtr unit; // get its number part and its unit @@ -1068,8 +1055,7 @@ nsHTMLEditRules::GetParagraphState(bool *aMixed, nsAString &outFormat) auto& curNode = arrayOfNodes[i]; nsAutoString format; // if it is a known format node we have it easy - if (IsBlockNode(GetAsDOMNode(curNode)) && - !nsHTMLEditUtils::IsFormatNode(curNode)) { + if (IsBlockNode(curNode) && !nsHTMLEditUtils::IsFormatNode(curNode)) { // arrayOfNodes.RemoveObject(curNode); res = AppendInnerFormatNodes(arrayOfNodes, curNode); NS_ENSURE_SUCCESS(res, res); @@ -1102,7 +1088,7 @@ nsHTMLEditRules::GetParagraphState(bool *aMixed, nsAString &outFormat) // if it is a known format node we have it easy if (nsHTMLEditUtils::IsFormatNode(curNode)) { GetFormatString(GetAsDOMNode(curNode), format); - } else if (IsBlockNode(GetAsDOMNode(curNode))) { + } else if (IsBlockNode(curNode)) { // this is a div or some other non-format block. // we should ignore it. Its children were appended to this list // by AppendInnerFormatNodes() call above. We will get needed @@ -1161,7 +1147,7 @@ nsHTMLEditRules::AppendInnerFormatNodes(nsTArray>& aArray for (nsIContent* child = aNode->GetFirstChild(); child; child = child->GetNextSibling()) { - bool isBlock = IsBlockNode(child->AsDOMNode()); + bool isBlock = IsBlockNode(*child); bool isFormat = nsHTMLEditUtils::IsFormatNode(child); if (isBlock && !isFormat) { // if it's a div, etc, recurse @@ -1197,54 +1183,46 @@ nsHTMLEditRules::GetFormatString(nsIDOMNode *aNode, nsAString &outFormat) * Protected rules methods ********************************************************/ -nsresult -nsHTMLEditRules::WillInsert(Selection* aSelection, bool* aCancel) +void +nsHTMLEditRules::WillInsert(Selection& aSelection, bool* aCancel) { - nsresult res = nsTextEditRules::WillInsert(aSelection, aCancel); - NS_ENSURE_SUCCESS(res, res); + MOZ_ASSERT(aCancel); - // Adjust selection to prevent insertion after a moz-BR. - // this next only works for collapsed selections right now, - // because selection is a pain to work with when not collapsed. - // (no good way to extend start or end of selection), so we ignore - // those types of selections. - if (!aSelection->Collapsed()) { - return NS_OK; + nsTextEditRules::WillInsert(aSelection, aCancel); + + NS_ENSURE_TRUE_VOID(mHTMLEditor); + nsCOMPtr kungFuDeathGrip(mHTMLEditor); + + // Adjust selection to prevent insertion after a moz-BR. This next only + // works for collapsed selections right now, because selection is a pain to + // work with when not collapsed. (no good way to extend start or end of + // selection), so we ignore those types of selections. + if (!aSelection.Collapsed()) { + return; } - // if we are after a mozBR in the same block, then move selection - // to be before it - nsCOMPtr selNode, priorNode; - int32_t selOffset; - // get the (collapsed) selection location - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(selNode), - &selOffset); - NS_ENSURE_SUCCESS(res, res); - // get prior node - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->GetPriorHTMLNode(selNode, selOffset, - address_of(priorNode)); - if (NS_SUCCEEDED(res) && priorNode && nsTextEditUtils::IsMozBR(priorNode)) - { - nsCOMPtr block1, block2; - if (IsBlockNode(selNode)) { - block1 = selNode; - } - else { - NS_ENSURE_STATE(mHTMLEditor); - block1 = mHTMLEditor->GetBlockNodeParent(selNode); - } - NS_ENSURE_STATE(mHTMLEditor); - block2 = mHTMLEditor->GetBlockNodeParent(priorNode); + // If we are after a mozBR in the same block, then move selection to be + // before it + NS_ENSURE_TRUE_VOID(aSelection.GetRangeAt(0) && + aSelection.GetRangeAt(0)->GetStartParent()); + OwningNonNull selNode = *aSelection.GetRangeAt(0)->GetStartParent(); + int32_t selOffset = aSelection.GetRangeAt(0)->StartOffset(); + + // Get prior node + nsCOMPtr priorNode = mHTMLEditor->GetPriorHTMLNode(selNode, + selOffset); + if (priorNode && nsTextEditUtils::IsMozBR(priorNode)) { + nsCOMPtr block1 = mHTMLEditor->GetBlock(selNode); + nsCOMPtr block2 = mHTMLEditor->GetBlockNodeParent(priorNode); if (block1 && block1 == block2) { - // if we are here then the selection is right after a mozBR - // that is in the same block as the selection. We need to move - // the selection start to be before the mozBR. - selNode = nsEditor::GetNodeLocation(priorNode, &selOffset); - res = aSelection->Collapse(selNode,selOffset); - NS_ENSURE_SUCCESS(res, res); + // If we are here then the selection is right after a mozBR that is in + // the same block as the selection. We need to move the selection start + // to be before the mozBR. + selNode = priorNode->GetParentNode(); + selOffset = selNode->IndexOf(priorNode); + nsresult res = aSelection.Collapse(selNode, selOffset); + NS_ENSURE_SUCCESS_VOID(res); } } @@ -1252,16 +1230,14 @@ nsHTMLEditRules::WillInsert(Selection* aSelection, bool* aCancel) (mTheAction == EditAction::insertText || mTheAction == EditAction::insertIMEText || mTheAction == EditAction::deleteSelection)) { - res = ReapplyCachedStyles(); - NS_ENSURE_SUCCESS(res, res); + nsresult res = ReapplyCachedStyles(); + NS_ENSURE_SUCCESS_VOID(res); } // For most actions we want to clear the cached styles, but there are // exceptions if (!IsStyleCachePreservingAction(mTheAction)) { ClearCachedStyles(); } - - return NS_OK; } nsresult @@ -1298,8 +1274,7 @@ nsHTMLEditRules::WillInsertText(EditAction aAction, NS_ENSURE_SUCCESS(res, res); } - res = WillInsert(aSelection, aCancel); - NS_ENSURE_SUCCESS(res, res); + WillInsert(*aSelection, aCancel); // initialize out param // we want to ignore result of WillInsert() *aCancel = false; @@ -1307,11 +1282,10 @@ nsHTMLEditRules::WillInsertText(EditAction aAction, // we need to get the doc NS_ENSURE_STATE(mHTMLEditor); nsCOMPtr doc = mHTMLEditor->GetDocument(); - nsCOMPtr domDoc = mHTMLEditor->GetDOMDocument(); - NS_ENSURE_TRUE(doc && domDoc, NS_ERROR_NOT_INITIALIZED); + NS_ENSURE_STATE(doc); // for every property that is set, insert a new inline style node - res = CreateStyleForInsertText(aSelection, domDoc); + res = CreateStyleForInsertText(*aSelection, *doc); NS_ENSURE_SUCCESS(res, res); // get the (collapsed) selection location @@ -1516,116 +1490,96 @@ nsHTMLEditRules::WillLoadHTML(Selection* aSelection, bool* aCancel) } nsresult -nsHTMLEditRules::WillInsertBreak(Selection* aSelection, - bool* aCancel, bool* aHandled) +nsHTMLEditRules::WillInsertBreak(Selection& aSelection, bool* aCancel, + bool* aHandled) { - if (!aSelection || !aCancel || !aHandled) { - return NS_ERROR_NULL_POINTER; - } - // initialize out params + MOZ_ASSERT(aCancel && aHandled); *aCancel = false; *aHandled = false; - // if the selection isn't collapsed, delete it. - nsresult res = NS_OK; - if (!aSelection->Collapsed()) { - NS_ENSURE_STATE(mHTMLEditor); + NS_ENSURE_STATE(mHTMLEditor); + nsCOMPtr kungFuDeathGrip(mHTMLEditor); + + // If the selection isn't collapsed, delete it. + nsresult res; + if (!aSelection.Collapsed()) { res = mHTMLEditor->DeleteSelection(nsIEditor::eNone, nsIEditor::eStrip); NS_ENSURE_SUCCESS(res, res); } - res = WillInsert(aSelection, aCancel); - NS_ENSURE_SUCCESS(res, res); + WillInsert(aSelection, aCancel); - // initialize out param - // we want to ignore result of WillInsert() + // Initialize out param. We want to ignore result of WillInsert(). *aCancel = false; - // split any mailcites in the way. - // should we abort this if we encounter table cell boundaries? + // Split any mailcites in the way. Should we abort this if we encounter + // table cell boundaries? if (IsMailEditor()) { - res = SplitMailCites(aSelection, aHandled); + res = SplitMailCites(&aSelection, aHandled); NS_ENSURE_SUCCESS(res, res); if (*aHandled) { return NS_OK; } } - // smart splitting rules - nsCOMPtr node; - int32_t offset; + // Smart splitting rules + NS_ENSURE_TRUE(aSelection.GetRangeAt(0) && + aSelection.GetRangeAt(0)->GetStartParent(), + NS_ERROR_FAILURE); + OwningNonNull node = *aSelection.GetRangeAt(0)->GetStartParent(); + int32_t offset = aSelection.GetRangeAt(0)->StartOffset(); - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(node), - &offset); - NS_ENSURE_SUCCESS(res, res); - NS_ENSURE_TRUE(node, NS_ERROR_FAILURE); - - // do nothing if the node is read-only - NS_ENSURE_STATE(mHTMLEditor); + // Do nothing if the node is read-only if (!mHTMLEditor->IsModifiableNode(node)) { *aCancel = true; return NS_OK; } - // identify the block - nsCOMPtr blockParent; - if (IsBlockNode(node)) { - blockParent = node; - } else { - NS_ENSURE_STATE(mHTMLEditor); - blockParent = mHTMLEditor->GetBlockNodeParent(node); - } + // Identify the block + nsCOMPtr blockParent = mHTMLEditor->GetBlock(node); NS_ENSURE_TRUE(blockParent, NS_ERROR_FAILURE); - // if the active editing host is an inline element, or if the active editing + // If the active editing host is an inline element, or if the active editing // host is the block parent itself, just append a br. - NS_ENSURE_STATE(mHTMLEditor); - nsCOMPtr hostContent = mHTMLEditor->GetActiveEditingHost(); - nsCOMPtr hostNode = do_QueryInterface(hostContent); - if (!nsEditorUtils::IsDescendantOf(blockParent, hostNode)) { + nsCOMPtr host = mHTMLEditor->GetActiveEditingHost(); + if (!nsEditorUtils::IsDescendantOf(blockParent, host)) { res = StandardBreakImpl(node, offset, aSelection); NS_ENSURE_SUCCESS(res, res); *aHandled = true; return NS_OK; } - // if block is empty, populate with br. (for example, imagine a div that - // contains the word "text". the user selects "text" and types return. - // "text" is deleted leaving an empty block. we want to put in one br to - // make block have a line. then code further below will put in a second br.) + // If block is empty, populate with br. (For example, imagine a div that + // contains the word "text". The user selects "text" and types return. + // "Text" is deleted leaving an empty block. We want to put in one br to + // make block have a line. Then code further below will put in a second br.) bool isEmpty; - IsEmptyBlock(blockParent, &isEmpty); + IsEmptyBlock(*blockParent, &isEmpty); if (isEmpty) { - uint32_t blockLen; - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->GetLengthOfDOMNode(blockParent, blockLen); - NS_ENSURE_SUCCESS(res, res); - nsCOMPtr brNode; - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->CreateBR(blockParent, blockLen, address_of(brNode)); - NS_ENSURE_SUCCESS(res, res); + nsCOMPtr br = mHTMLEditor->CreateBR(blockParent, + blockParent->Length()); + NS_ENSURE_STATE(br); } - nsCOMPtr listItem = IsInListItem(blockParent); - if (listItem && listItem != hostNode) { - ReturnInListItem(aSelection, listItem, node, offset); + nsCOMPtr listItem = IsInListItem(blockParent); + if (listItem && listItem != host) { + ReturnInListItem(aSelection, *listItem, node, offset); *aHandled = true; return NS_OK; - } else if (nsHTMLEditUtils::IsHeader(blockParent)) { - // headers: close (or split) header - ReturnInHeader(aSelection, blockParent, node, offset); + } else if (nsHTMLEditUtils::IsHeader(*blockParent)) { + // Headers: close (or split) header + ReturnInHeader(aSelection, *blockParent, node, offset); *aHandled = true; return NS_OK; - } else if (nsHTMLEditUtils::IsParagraph(blockParent)) { - // paragraphs: special rules to look for
s - res = ReturnInParagraph(aSelection, blockParent, node, offset, - aCancel, aHandled); + } else if (blockParent->IsHTMLElement(nsGkAtoms::p)) { + // Paragraphs: special rules to look for
s + res = ReturnInParagraph(&aSelection, GetAsDOMNode(blockParent), + GetAsDOMNode(node), offset, aCancel, aHandled); NS_ENSURE_SUCCESS(res, res); - // fall through, we may not have handled it in ReturnInParagraph() + // Fall through, we may not have handled it in ReturnInParagraph() } - // if not already handled then do the standard thing + // If not already handled then do the standard thing if (!(*aHandled)) { *aHandled = true; return StandardBreakImpl(node, offset, aSelection); @@ -1634,86 +1588,79 @@ nsHTMLEditRules::WillInsertBreak(Selection* aSelection, } nsresult -nsHTMLEditRules::StandardBreakImpl(nsIDOMNode* aNode, int32_t aOffset, - Selection* aSelection) +nsHTMLEditRules::StandardBreakImpl(nsINode& aNode, int32_t aOffset, + Selection& aSelection) { - nsCOMPtr brNode; + NS_ENSURE_STATE(mHTMLEditor); + nsCOMPtr kungFuDeathGrip(mHTMLEditor); + + nsCOMPtr brNode; bool bAfterBlock = false; bool bBeforeBlock = false; - nsresult res = NS_OK; - nsCOMPtr node(aNode); + nsCOMPtr node = &aNode; + nsresult res; if (IsPlaintextEditor()) { - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->CreateBR(node, aOffset, address_of(brNode)); + brNode = mHTMLEditor->CreateBR(node, aOffset); + NS_ENSURE_STATE(brNode); } else { - NS_ENSURE_STATE(mHTMLEditor); nsWSRunObject wsObj(mHTMLEditor, node, aOffset); int32_t visOffset = 0; WSType wsType; - nsCOMPtr node_(do_QueryInterface(node)), visNode; - wsObj.PriorVisibleNode(node_, aOffset, address_of(visNode), + nsCOMPtr visNode; + wsObj.PriorVisibleNode(node, aOffset, address_of(visNode), &visOffset, &wsType); if (wsType & WSType::block) { bAfterBlock = true; } - wsObj.NextVisibleNode(node_, aOffset, address_of(visNode), + wsObj.NextVisibleNode(node, aOffset, address_of(visNode), &visOffset, &wsType); if (wsType & WSType::block) { bBeforeBlock = true; } - NS_ENSURE_STATE(mHTMLEditor); - nsCOMPtr linkNode; - if (mHTMLEditor->IsInLink(node, address_of(linkNode))) { - // split the link - nsCOMPtr linkParent; - res = linkNode->GetParentNode(getter_AddRefs(linkParent)); - NS_ENSURE_SUCCESS(res, res); - NS_ENSURE_STATE(mHTMLEditor); - nsCOMPtr linkNodeContent = do_QueryInterface(linkNode); - NS_ENSURE_STATE(linkNodeContent || !linkNode); - aOffset = mHTMLEditor->SplitNodeDeep(*linkNodeContent, - *node_->AsContent(), aOffset, nsHTMLEditor::EmptyContainers::no); + nsCOMPtr linkDOMNode; + if (mHTMLEditor->IsInLink(GetAsDOMNode(node), address_of(linkDOMNode))) { + // Split the link + nsCOMPtr linkNode = do_QueryInterface(linkDOMNode); + NS_ENSURE_STATE(linkNode || !linkDOMNode); + nsCOMPtr linkParent = linkNode->GetParentNode(); + aOffset = mHTMLEditor->SplitNodeDeep(*linkNode, *node->AsContent(), + aOffset, + nsHTMLEditor::EmptyContainers::no); NS_ENSURE_STATE(aOffset != -1); node = linkParent; } - node_ = do_QueryInterface(node); - nsCOMPtr br = - wsObj.InsertBreak(address_of(node_), &aOffset, nsIEditor::eNone); - node = GetAsDOMNode(node_); - brNode = GetAsDOMNode(br); + brNode = wsObj.InsertBreak(address_of(node), &aOffset, nsIEditor::eNone); NS_ENSURE_TRUE(brNode, NS_ERROR_FAILURE); } - NS_ENSURE_SUCCESS(res, res); - node = nsEditor::GetNodeLocation(brNode, &aOffset); + node = brNode->GetParentNode(); NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER); + int32_t offset = node->IndexOf(brNode); if (bAfterBlock && bBeforeBlock) { - // we just placed a br between block boundaries. This is the one case + // We just placed a br between block boundaries. This is the one case // where we want the selection to be before the br we just placed, as the // br will be on a new line, rather than at end of prior line. - aSelection->SetInterlinePosition(true); - res = aSelection->Collapse(node, aOffset); + aSelection.SetInterlinePosition(true); + res = aSelection.Collapse(node, offset); + NS_ENSURE_SUCCESS(res, res); } else { - NS_ENSURE_STATE(mHTMLEditor); - nsWSRunObject wsObj(mHTMLEditor, node, aOffset+1); + nsWSRunObject wsObj(mHTMLEditor, node, offset + 1); nsCOMPtr secondBR; int32_t visOffset = 0; WSType wsType; - nsCOMPtr node_(do_QueryInterface(node)); - wsObj.NextVisibleNode(node_, aOffset+1, address_of(secondBR), + wsObj.NextVisibleNode(node, offset + 1, address_of(secondBR), &visOffset, &wsType); if (wsType == WSType::br) { - // the next thing after the break we inserted is another break. Move - // the 2nd break to be the first breaks sibling. This will prevent them + // The next thing after the break we inserted is another break. Move the + // second break to be the first break's sibling. This will prevent them // from being in different inline nodes, which would break // SetInterlinePosition(). It will also assure that if the user clicks - // away and then clicks back on their new blank line, they will still - // get the style from the line above. - int32_t brOffset; - nsCOMPtr brParent = nsEditor::GetNodeLocation(GetAsDOMNode(secondBR), &brOffset); - if (brParent != node || brOffset != aOffset + 1) { - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->MoveNode(secondBR->AsContent(), node_, aOffset + 1); + // away and then clicks back on their new blank line, they will still get + // the style from the line above. + nsCOMPtr brParent = secondBR->GetParentNode(); + int32_t brOffset = brParent ? brParent->IndexOf(secondBR) : -1; + if (brParent != node || brOffset != offset + 1) { + res = mHTMLEditor->MoveNode(secondBR->AsContent(), node, offset + 1); NS_ENSURE_SUCCESS(res, res); } } @@ -1724,16 +1671,16 @@ nsHTMLEditRules::StandardBreakImpl(nsIDOMNode* aNode, int32_t aOffset, // An exception to this is if the break has a next sibling that is a block // node. Then we stick to the left to avoid an uber caret. - nsCOMPtr siblingNode; - brNode->GetNextSibling(getter_AddRefs(siblingNode)); - if (siblingNode && IsBlockNode(siblingNode)) { - aSelection->SetInterlinePosition(false); + nsCOMPtr siblingNode = brNode->GetNextSibling(); + if (siblingNode && IsBlockNode(*siblingNode)) { + aSelection.SetInterlinePosition(false); } else { - aSelection->SetInterlinePosition(true); + aSelection.SetInterlinePosition(true); } - res = aSelection->Collapse(node, aOffset+1); + res = aSelection.Collapse(node, offset + 1); + NS_ENSURE_SUCCESS(res, res); } - return res; + return NS_OK; } nsresult @@ -1801,7 +1748,7 @@ nsHTMLEditRules::SplitMailCites(Selection* aSelection, bool* aHandled) // We need to examine the content both before the br we just added and also // just after it. If we don't have another br or block boundary adjacent, // then we will need a 2nd br added to achieve blank line that user expects. - if (IsInlineNode(GetAsDOMNode(citeNode))) { + if (IsInlineNode(*citeNode)) { NS_ENSURE_STATE(mHTMLEditor); nsWSRunObject wsObj(mHTMLEditor, selNode, newOffset); nsCOMPtr visNode; @@ -2021,6 +1968,9 @@ nsHTMLEditRules::WillDeleteSelection(Selection* aSelection, DeprecatedAbs(eo - so)); *aHandled = true; NS_ENSURE_SUCCESS(res, res); + + DeleteNodeIfCollapsedText(nodeAsText); + res = InsertBRIfNeeded(aSelection); NS_ENSURE_SUCCESS(res, res); @@ -2219,7 +2169,9 @@ nsHTMLEditRules::WillDeleteSelection(Selection* aSelection, NS_ENSURE_STATE(mHTMLEditor); nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, address_of(selPointNode), &selPointOffset); - res = JoinBlocks(GetAsDOMNode(leftNode), GetAsDOMNode(rightNode), + NS_ENSURE_STATE(leftNode && leftNode->IsContent() && + rightNode && rightNode->IsContent()); + res = JoinBlocks(*leftNode->AsContent(), *rightNode->AsContent(), aCancel); *aHandled = true; NS_ENSURE_SUCCESS(res, res); @@ -2269,7 +2221,8 @@ nsHTMLEditRules::WillDeleteSelection(Selection* aSelection, NS_ENSURE_STATE(mHTMLEditor); nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, address_of(selPointNode), &selPointOffset); - res = JoinBlocks(GetAsDOMNode(leftNode), GetAsDOMNode(rightNode), + NS_ENSURE_STATE(leftNode->IsContent() && rightNode->IsContent()); + res = JoinBlocks(*leftNode->AsContent(), *rightNode->AsContent(), aCancel); *aHandled = true; NS_ENSURE_SUCCESS(res, res); @@ -2281,7 +2234,7 @@ nsHTMLEditRules::WillDeleteSelection(Selection* aSelection, // Else we have a non-collapsed selection. First adjust the selection. - res = ExpandSelectionForDeletion(aSelection); + res = ExpandSelectionForDeletion(*aSelection); NS_ENSURE_SUCCESS(res, res); // Remember that we did a ranged delete for the benefit of AfterEditInner(). @@ -2455,13 +2408,24 @@ nsHTMLEditRules::WillDeleteSelection(Selection* aSelection, } if (join) { - res = JoinBlocks(GetAsDOMNode(leftParent), GetAsDOMNode(rightParent), - aCancel); + res = JoinBlocks(*leftParent, *rightParent, aCancel); NS_ENSURE_SUCCESS(res, res); } } } } + + // We might have left only collapsed whitespace in the start/end nodes + { + nsAutoTrackDOMPoint startTracker(mHTMLEditor->mRangeUpdater, + address_of(startNode), &startOffset); + nsAutoTrackDOMPoint endTracker(mHTMLEditor->mRangeUpdater, + address_of(endNode), &endOffset); + + DeleteNodeIfCollapsedText(*startNode); + DeleteNodeIfCollapsedText(*endNode); + } + // If we're joining blocks: if deleting forward the selection should be // collapsed to the end of the selection, if deleting backward the selection // should be collapsed to the beginning of the selection. But if we're not @@ -2479,6 +2443,28 @@ nsHTMLEditRules::WillDeleteSelection(Selection* aSelection, return NS_OK; } +/** + * If aNode is a text node that contains only collapsed whitespace, delete it. + * It doesn't serve any useful purpose, and we don't want it to confuse code + * that doesn't correctly skip over it. + * + * If deleting the node fails (like if it's not editable), the caller should + * proceed as usual, so don't return any errors. + */ +void +nsHTMLEditRules::DeleteNodeIfCollapsedText(nsINode& aNode) +{ + if (!aNode.GetAsText()) { + return; + } + bool empty; + nsresult res = mHTMLEditor->IsVisTextNode(aNode.AsContent(), &empty, false); + NS_ENSURE_SUCCESS_VOID(res); + if (empty) { + mHTMLEditor->DeleteNode(&aNode); + } +} + /***************************************************************************************************** * InsertBRIfNeeded: determines if a br is needed for current selection to not be spastic. @@ -2498,7 +2484,7 @@ nsHTMLEditRules::InsertBRIfNeeded(Selection* aSelection) NS_ENSURE_TRUE(node, NS_ERROR_FAILURE); // inline elements don't need any br - if (!IsBlockNode(GetAsDOMNode(node))) { + if (!IsBlockNode(*node)) { return NS_OK; } @@ -2551,209 +2537,180 @@ nsHTMLEditRules::GetGoodSelPointForNode(nsINode& aNode, } -/***************************************************************************************************** -* JoinBlocks: this method is used to join two block elements. The right element is always joined -* to the left element. If the elements are the same type and not nested within each other, -* JoinNodesSmart is called (example, joining two list items together into one). If the elements -* are not the same type, or one is a descendant of the other, we instead destroy the right block -* placing its children into leftblock. DTD containment rules are followed throughout. -* nsCOMPtr *aLeftBlock pointer to the left block -* nsCOMPtr *aRightBlock pointer to the right block; will have contents moved to left block -* bool *aCanceled return TRUE if we had to cancel operation -*/ +/** + * This method is used to join two block elements. The right element is always + * joined to the left element. If the elements are the same type and not + * nested within each other, JoinNodesSmart is called (example, joining two + * list items together into one). If the elements are not the same type, or + * one is a descendant of the other, we instead destroy the right block placing + * its children into leftblock. DTD containment rules are followed throughout. + */ nsresult -nsHTMLEditRules::JoinBlocks(nsIDOMNode *aLeftNode, - nsIDOMNode *aRightNode, - bool *aCanceled) +nsHTMLEditRules::JoinBlocks(nsIContent& aLeftNode, nsIContent& aRightNode, + bool* aCanceled) { - NS_ENSURE_ARG_POINTER(aLeftNode && aRightNode); + MOZ_ASSERT(aCanceled); - nsCOMPtr aLeftBlock, aRightBlock; + NS_ENSURE_STATE(mHTMLEditor); + nsCOMPtr kungFuDeathGrip(mHTMLEditor); - if (IsBlockNode(aLeftNode)) { - aLeftBlock = aLeftNode; - } else if (aLeftNode) { - NS_ENSURE_STATE(mHTMLEditor); - aLeftBlock = mHTMLEditor->GetBlockNodeParent(aLeftNode); - } + nsCOMPtr leftBlock = mHTMLEditor->GetBlock(aLeftNode); + nsCOMPtr rightBlock = mHTMLEditor->GetBlock(aRightNode); - if (IsBlockNode(aRightNode)) { - aRightBlock = aRightNode; - } else if (aRightNode) { - NS_ENSURE_STATE(mHTMLEditor); - aRightBlock = mHTMLEditor->GetBlockNodeParent(aRightNode); - } + // Sanity checks + NS_ENSURE_TRUE(leftBlock && rightBlock, NS_ERROR_NULL_POINTER); + NS_ENSURE_STATE(leftBlock != rightBlock); - // sanity checks - NS_ENSURE_TRUE(aLeftBlock && aRightBlock, NS_ERROR_NULL_POINTER); - NS_ENSURE_STATE(aLeftBlock != aRightBlock); - - if (nsHTMLEditUtils::IsTableElement(aLeftBlock) || - nsHTMLEditUtils::IsTableElement(aRightBlock)) { - // do not try to merge table elements + if (nsHTMLEditUtils::IsTableElement(leftBlock) || + nsHTMLEditUtils::IsTableElement(rightBlock)) { + // Do not try to merge table elements *aCanceled = true; return NS_OK; } - // make sure we don't try to move thing's into HR's, which look like blocks but aren't containers - if (nsHTMLEditUtils::IsHR(aLeftBlock)) { - NS_ENSURE_STATE(mHTMLEditor); - nsCOMPtr realLeft = mHTMLEditor->GetBlockNodeParent(aLeftBlock); - aLeftBlock = realLeft; + // Make sure we don't try to move things into HR's, which look like blocks + // but aren't containers + if (leftBlock->IsHTMLElement(nsGkAtoms::hr)) { + leftBlock = mHTMLEditor->GetBlockNodeParent(leftBlock); } - if (nsHTMLEditUtils::IsHR(aRightBlock)) { - NS_ENSURE_STATE(mHTMLEditor); - nsCOMPtr realRight = mHTMLEditor->GetBlockNodeParent(aRightBlock); - aRightBlock = realRight; + if (rightBlock->IsHTMLElement(nsGkAtoms::hr)) { + rightBlock = mHTMLEditor->GetBlockNodeParent(rightBlock); } - NS_ENSURE_STATE(aLeftBlock && aRightBlock); + NS_ENSURE_STATE(leftBlock && rightBlock); - // bail if both blocks the same - if (aLeftBlock == aRightBlock) { + // Bail if both blocks the same + if (leftBlock == rightBlock) { *aCanceled = true; return NS_OK; } // Joining a list item to its parent is a NOP. - if (nsHTMLEditUtils::IsList(aLeftBlock) && - nsHTMLEditUtils::IsListItem(aRightBlock)) { - nsCOMPtr rightParent; - aRightBlock->GetParentNode(getter_AddRefs(rightParent)); - if (rightParent == aLeftBlock) { - return NS_OK; - } + if (nsHTMLEditUtils::IsList(leftBlock) && + nsHTMLEditUtils::IsListItem(rightBlock) && + rightBlock->GetParentNode() == leftBlock) { + return NS_OK; } - // special rule here: if we are trying to join list items, and they are in different lists, - // join the lists instead. - bool bMergeLists = false; + // Special rule here: if we are trying to join list items, and they are in + // different lists, join the lists instead. + bool mergeLists = false; nsIAtom* existingList = nsGkAtoms::_empty; - int32_t theOffset; - nsCOMPtr leftList, rightList; - if (nsHTMLEditUtils::IsListItem(aLeftBlock) && - nsHTMLEditUtils::IsListItem(aRightBlock)) { - aLeftBlock->GetParentNode(getter_AddRefs(leftList)); - aRightBlock->GetParentNode(getter_AddRefs(rightList)); - if (leftList && rightList && (leftList!=rightList)) - { - // there are some special complications if the lists are descendants of - // the other lists' items. Note that it is ok for them to be descendants - // of the other lists themselves, which is the usual case for sublists - // in our impllementation. - if (!nsEditorUtils::IsDescendantOf(leftList, aRightBlock, &theOffset) && - !nsEditorUtils::IsDescendantOf(rightList, aLeftBlock, &theOffset)) - { - aLeftBlock = leftList; - aRightBlock = rightList; - bMergeLists = true; - NS_ENSURE_STATE(mHTMLEditor); - existingList = mHTMLEditor->GetTag(leftList); - } + int32_t offset; + nsCOMPtr leftList, rightList; + if (nsHTMLEditUtils::IsListItem(leftBlock) && + nsHTMLEditUtils::IsListItem(rightBlock)) { + leftList = leftBlock->GetParentElement(); + rightList = rightBlock->GetParentElement(); + if (leftList && rightList && leftList != rightList && + !nsEditorUtils::IsDescendantOf(leftList, rightBlock, &offset) && + !nsEditorUtils::IsDescendantOf(rightList, leftBlock, &offset)) { + // There are some special complications if the lists are descendants of + // the other lists' items. Note that it is okay for them to be + // descendants of the other lists themselves, which is the usual case for + // sublists in our implementation. + leftBlock = leftList; + rightBlock = rightList; + mergeLists = true; + existingList = leftList->NodeInfo()->NameAtom(); } } - NS_ENSURE_STATE(mHTMLEditor); nsAutoTxnsConserveSelection dontSpazMySelection(mHTMLEditor); nsresult res = NS_OK; - int32_t rightOffset = 0; - int32_t leftOffset = -1; + int32_t rightOffset = 0; + int32_t leftOffset = -1; - // theOffset below is where you find yourself in aRightBlock when you traverse upwards - // from aLeftBlock - if (nsEditorUtils::IsDescendantOf(aLeftBlock, aRightBlock, &rightOffset)) { - // tricky case. left block is inside right block. - // Do ws adjustment. This just destroys non-visible ws at boundaries we will be joining. + // offset below is where you find yourself in rightBlock when you traverse + // upwards from leftBlock + if (nsEditorUtils::IsDescendantOf(leftBlock, rightBlock, &rightOffset)) { + // Tricky case. Left block is inside right block. Do ws adjustment. This + // just destroys non-visible ws at boundaries we will be joining. rightOffset++; - NS_ENSURE_STATE(mHTMLEditor); - nsCOMPtr leftBlock(do_QueryInterface(aLeftBlock)); res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor, nsWSRunObject::kBlockEnd, leftBlock); NS_ENSURE_SUCCESS(res, res); { + // We can't just track rightBlock because it's an Element. + nsCOMPtr trackingRightBlock(rightBlock); nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, - address_of(aRightBlock), &rightOffset); - nsCOMPtr rightBlock(do_QueryInterface(aRightBlock)); + address_of(trackingRightBlock), + &rightOffset); res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor, nsWSRunObject::kAfterBlock, rightBlock, rightOffset); NS_ENSURE_SUCCESS(res, res); - } - // Do br adjustment. - nsCOMPtr brNode; - res = CheckForInvisibleBR(aLeftBlock, kBlockEnd, address_of(brNode)); - NS_ENSURE_SUCCESS(res, res); - if (bMergeLists) - { - // idea here is to take all children in rightList that are past - // theOffset, and pull them into leftlist. - nsCOMPtr parent(do_QueryInterface(rightList)); - NS_ENSURE_TRUE(parent, NS_ERROR_NULL_POINTER); - - nsIContent *child = parent->GetChildAt(theOffset); - nsCOMPtr leftList_ = do_QueryInterface(leftList); - NS_ENSURE_STATE(leftList_); - while (child) - { - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->MoveNode(child, leftList_, -1); - NS_ENSURE_SUCCESS(res, res); - - child = parent->GetChildAt(rightOffset); + if (trackingRightBlock->IsElement()) { + rightBlock = trackingRightBlock->AsElement(); + } else { + NS_ENSURE_STATE(trackingRightBlock->GetParentElement()); + rightBlock = trackingRightBlock->GetParentElement(); } } - else - { - res = MoveBlock(aLeftBlock, aRightBlock, leftOffset, rightOffset); + // Do br adjustment. + nsCOMPtr brNode = + CheckForInvisibleBR(*leftBlock, BRLocation::blockEnd); + if (mergeLists) { + // The idea here is to take all children in rightList that are past + // offset, and pull them into leftlist. + for (nsCOMPtr child = rightList->GetChildAt(offset); + child; child = rightList->GetChildAt(rightOffset)) { + res = mHTMLEditor->MoveNode(child, leftList, -1); + NS_ENSURE_SUCCESS(res, res); + } + } else { + res = MoveBlock(*leftBlock, *rightBlock, leftOffset, rightOffset); } - NS_ENSURE_STATE(mHTMLEditor); - if (brNode) mHTMLEditor->DeleteNode(brNode); - // theOffset below is where you find yourself in aLeftBlock when you traverse upwards - // from aRightBlock - } else if (nsEditorUtils::IsDescendantOf(aRightBlock, aLeftBlock, &leftOffset)) { - // tricky case. right block is inside left block. - // Do ws adjustment. This just destroys non-visible ws at boundaries we will be joining. - NS_ENSURE_STATE(mHTMLEditor); - nsCOMPtr rightBlock(do_QueryInterface(aRightBlock)); + if (brNode) { + mHTMLEditor->DeleteNode(brNode); + } + // Offset below is where you find yourself in leftBlock when you traverse + // upwards from rightBlock + } else if (nsEditorUtils::IsDescendantOf(rightBlock, leftBlock, + &leftOffset)) { + // Tricky case. Right block is inside left block. Do ws adjustment. This + // just destroys non-visible ws at boundaries we will be joining. res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor, nsWSRunObject::kBlockStart, rightBlock); NS_ENSURE_SUCCESS(res, res); - NS_ENSURE_STATE(mHTMLEditor); { + // We can't just track leftBlock because it's an Element, so track + // something else. + nsCOMPtr trackingLeftBlock(leftBlock); nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, - address_of(aLeftBlock), &leftOffset); - nsCOMPtr leftBlock(do_QueryInterface(aLeftBlock)); + address_of(trackingLeftBlock), &leftOffset); res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor, nsWSRunObject::kBeforeBlock, leftBlock, leftOffset); NS_ENSURE_SUCCESS(res, res); + if (trackingLeftBlock->IsElement()) { + leftBlock = trackingLeftBlock->AsElement(); + } else { + NS_ENSURE_STATE(trackingLeftBlock->GetParentElement()); + leftBlock = trackingLeftBlock->GetParentElement(); + } } // Do br adjustment. - nsCOMPtr brNode; - res = CheckForInvisibleBR(aLeftBlock, kBeforeBlock, address_of(brNode), - leftOffset); - NS_ENSURE_SUCCESS(res, res); - if (bMergeLists) - { - res = MoveContents(rightList, leftList, &leftOffset); - } - else - { + nsCOMPtr brNode = + CheckForInvisibleBR(*leftBlock, BRLocation::beforeBlock, leftOffset); + if (mergeLists) { + res = MoveContents(*rightList, *leftList, &leftOffset); + } else { // Left block is a parent of right block, and the parent of the previous // visible content. Right block is a child and contains the contents we // want to move. int32_t previousContentOffset; - nsCOMPtr previousContentParent; + nsCOMPtr previousContentParent; - if (aLeftNode == aLeftBlock) { + if (&aLeftNode == leftBlock) { // We are working with valid HTML, aLeftNode is a block node, and is - // therefore allowed to contain aRightBlock. This is the simple case, - // we will simply move the content in aRightBlock out of its block. - previousContentParent = aLeftBlock; + // therefore allowed to contain rightBlock. This is the simple case, + // we will simply move the content in rightBlock out of its block. + previousContentParent = leftBlock; previousContentOffset = leftOffset; } else { // We try to work as well as possible with HTML that's already invalid. @@ -2766,8 +2723,9 @@ nsHTMLEditRules::JoinBlocks(nsIDOMNode *aLeftNode, // unexpected position. (see bug 200416) The new idea is to make the // moving content a sibling, next to the previous visible content. - previousContentParent = - nsEditor::GetNodeLocation(aLeftNode, &previousContentOffset); + previousContentParent = aLeftNode.GetParentNode(); + previousContentOffset = previousContentParent ? + previousContentParent->IndexOf(&aLeftNode) : -1; // We want to move our content just after the previous visible node. previousContentOffset++; @@ -2776,170 +2734,156 @@ nsHTMLEditRules::JoinBlocks(nsIDOMNode *aLeftNode, // Because we don't want the moving content to receive the style of the // previous content, we split the previous content's style. - NS_ENSURE_STATE(mHTMLEditor); - nsCOMPtr editorRoot = mHTMLEditor->GetEditorRoot(); - if (!editorRoot || aLeftNode != editorRoot->AsDOMNode()) { - nsCOMPtr splittedPreviousContent; - NS_ENSURE_STATE(mHTMLEditor); + nsCOMPtr editorRoot = mHTMLEditor->GetEditorRoot(); + if (!editorRoot || &aLeftNode != editorRoot) { + nsCOMPtr splittedPreviousContent; res = mHTMLEditor->SplitStyleAbovePoint(address_of(previousContentParent), &previousContentOffset, nullptr, nullptr, nullptr, - address_of(splittedPreviousContent)); + getter_AddRefs(splittedPreviousContent)); NS_ENSURE_SUCCESS(res, res); if (splittedPreviousContent) { - previousContentParent = - nsEditor::GetNodeLocation(splittedPreviousContent, - &previousContentOffset); + previousContentParent = splittedPreviousContent->GetParentNode(); + previousContentOffset = previousContentParent ? + previousContentParent->IndexOf(splittedPreviousContent) : -1; } } - res = MoveBlock(previousContentParent, aRightBlock, - previousContentOffset, rightOffset); - } - NS_ENSURE_STATE(mHTMLEditor); - if (brNode) mHTMLEditor->DeleteNode(brNode); - } - else - { - // normal case. blocks are siblings, or at least close enough to siblings. An example - // of the latter is a

paragraph

  • one
  • two
  • three
. The first - // li and the p are not true siblings, but we still want to join them if you backspace - // from li into p. + NS_ENSURE_TRUE(previousContentParent, NS_ERROR_NULL_POINTER); - // adjust whitespace at block boundaries - NS_ENSURE_STATE(mHTMLEditor); - nsCOMPtr leftBlock(do_QueryInterface(aLeftBlock)); - nsCOMPtr rightBlock(do_QueryInterface(aRightBlock)); + res = MoveBlock(*previousContentParent->AsElement(), *rightBlock, + previousContentOffset, rightOffset); + NS_ENSURE_SUCCESS(res, res); + } + if (brNode) { + mHTMLEditor->DeleteNode(brNode); + } + } else { + // Normal case. Blocks are siblings, or at least close enough. An example + // of the latter is

paragraph

  • one
  • two
  • three
. The + // first li and the p are not true siblings, but we still want to join them + // if you backspace from li into p. + + // Adjust whitespace at block boundaries res = nsWSRunObject::PrepareToJoinBlocks(mHTMLEditor, leftBlock, rightBlock); NS_ENSURE_SUCCESS(res, res); // Do br adjustment. - nsCOMPtr brNode; - res = CheckForInvisibleBR(aLeftBlock, kBlockEnd, address_of(brNode)); - NS_ENSURE_SUCCESS(res, res); - NS_ENSURE_STATE(mHTMLEditor); - if (bMergeLists || mHTMLEditor->NodesSameType(aLeftBlock, aRightBlock)) { - // nodes are same type. merge them. + nsCOMPtr brNode = + CheckForInvisibleBR(*leftBlock, BRLocation::blockEnd); + if (mergeLists || leftBlock->NodeInfo()->NameAtom() == + rightBlock->NodeInfo()->NameAtom()) { + // Nodes are same type. merge them. ::DOMPoint pt = JoinNodesSmart(*leftBlock, *rightBlock); - if (pt.node && bMergeLists) { - nsCOMPtr newBlock; - res = ConvertListType(aRightBlock, address_of(newBlock), + if (pt.node && mergeLists) { + nsCOMPtr newBlock; + res = ConvertListType(rightBlock, getter_AddRefs(newBlock), existingList, nsGkAtoms::li); } + } else { + // Nodes are dissimilar types. + res = MoveBlock(*leftBlock, *rightBlock, leftOffset, rightOffset); + NS_ENSURE_SUCCESS(res, res); } - else - { - // nodes are disimilar types. - res = MoveBlock(aLeftBlock, aRightBlock, leftOffset, rightOffset); - } - if (NS_SUCCEEDED(res) && brNode) - { - NS_ENSURE_STATE(mHTMLEditor); + if (brNode) { res = mHTMLEditor->DeleteNode(brNode); + NS_ENSURE_SUCCESS(res, res); } } - return res; + return NS_OK; } -/***************************************************************************************************** -* MoveBlock: this method is used to move the content from rightBlock into leftBlock -* Note that the "block" might merely be inline nodes between
s, or between blocks, etc. -* DTD containment rules are followed throughout. -* nsIDOMNode *aLeftBlock parent to receive moved content -* nsIDOMNode *aRightBlock parent to provide moved content -* int32_t aLeftOffset offset in aLeftBlock to move content to -* int32_t aRightOffset offset in aRightBlock to move content from -*/ +/** + * Moves the content from aRightBlock starting from aRightOffset into + * aLeftBlock at aLeftOffset. Note that the "block" might merely be inline + * nodes between
s, or between blocks, etc. DTD containment rules are + * followed throughout. + */ nsresult -nsHTMLEditRules::MoveBlock(nsIDOMNode *aLeftBlock, nsIDOMNode *aRightBlock, int32_t aLeftOffset, int32_t aRightOffset) +nsHTMLEditRules::MoveBlock(Element& aLeftBlock, Element& aRightBlock, + int32_t aLeftOffset, int32_t aRightOffset) { nsTArray> arrayOfNodes; // GetNodesFromPoint is the workhorse that figures out what we wnat to move. - nsresult res = GetNodesFromPoint(::DOMPoint(aRightBlock,aRightOffset), + nsresult res = GetNodesFromPoint(::DOMPoint(&aRightBlock, aRightOffset), EditAction::makeList, arrayOfNodes, - TouchContent::no); + TouchContent::yes); NS_ENSURE_SUCCESS(res, res); - for (auto& curNode : arrayOfNodes) { + for (uint32_t i = 0; i < arrayOfNodes.Length(); i++) { // get the node to act on - if (IsBlockNode(GetAsDOMNode(curNode))) { + if (IsBlockNode(arrayOfNodes[i])) { // For block nodes, move their contents only, then delete block. - res = MoveContents(GetAsDOMNode(curNode), aLeftBlock, &aLeftOffset); + res = MoveContents(*arrayOfNodes[i]->AsElement(), aLeftBlock, + &aLeftOffset); NS_ENSURE_SUCCESS(res, res); NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->DeleteNode(curNode); - } - else - { - // otherwise move the content as is, checking against the dtd. - res = MoveNodeSmart(GetAsDOMNode(curNode), aLeftBlock, &aLeftOffset); + res = mHTMLEditor->DeleteNode(arrayOfNodes[i]); + } else { + // Otherwise move the content as is, checking against the DTD. + res = MoveNodeSmart(*arrayOfNodes[i]->AsContent(), aLeftBlock, + &aLeftOffset); } } - return res; + + // XXX We're only checking return value of the last iteration + NS_ENSURE_SUCCESS(res, res); + return NS_OK; } -/***************************************************************************************************** -* MoveNodeSmart: this method is used to move node aSource to (aDest,aOffset). -* DTD containment rules are followed throughout. aOffset is updated to point _after_ -* inserted content. -* nsIDOMNode *aSource the selection. -* nsIDOMNode *aDest parent to receive moved content -* int32_t *aOffset offset in aDest to move content to -*/ +/** + * This method is used to move node aNode to (aDestElement, aInOutDestOffset). + * DTD containment rules are followed throughout. aInOutDestOffset is updated + * to point _after_ inserted content. + */ nsresult -nsHTMLEditRules::MoveNodeSmart(nsIDOMNode *aSource, nsIDOMNode *aDest, int32_t *aOffset) +nsHTMLEditRules::MoveNodeSmart(nsIContent& aNode, Element& aDestElement, + int32_t* aInOutDestOffset) { - nsCOMPtr source = do_QueryInterface(aSource); - nsCOMPtr dest = do_QueryInterface(aDest); - NS_ENSURE_TRUE(source && dest && aOffset, NS_ERROR_NULL_POINTER); + MOZ_ASSERT(aInOutDestOffset); - nsresult res; - // check if this node can go into the destination node NS_ENSURE_STATE(mHTMLEditor); - if (mHTMLEditor->CanContain(*dest, *source)) { - // if it can, move it there - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->MoveNode(source, dest, *aOffset); + nsCOMPtr kungFuDeathGrip(mHTMLEditor); + nsresult res; + + // Check if this node can go into the destination node + if (mHTMLEditor->CanContain(aDestElement, aNode)) { + // If it can, move it there + res = mHTMLEditor->MoveNode(&aNode, &aDestElement, *aInOutDestOffset); NS_ENSURE_SUCCESS(res, res); - if (*aOffset != -1) ++(*aOffset); - } - else - { - // if it can't, move its children, and then delete it. - res = MoveContents(aSource, aDest, aOffset); - NS_ENSURE_SUCCESS(res, res); - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->DeleteNode(aSource); + if (*aInOutDestOffset != -1) { + (*aInOutDestOffset)++; + } + } else { + // If it can't, move its children (if any), and then delete it. + if (aNode.IsElement()) { + res = MoveContents(*aNode.AsElement(), aDestElement, aInOutDestOffset); + NS_ENSURE_SUCCESS(res, res); + } + + res = mHTMLEditor->DeleteNode(&aNode); NS_ENSURE_SUCCESS(res, res); } return NS_OK; } -/***************************************************************************************************** -* MoveContents: this method is used to move node the _contents_ of aSource to (aDest,aOffset). -* DTD containment rules are followed throughout. aOffset is updated to point _after_ -* inserted content. aSource is deleted. -* nsIDOMNode *aSource the selection. -* nsIDOMNode *aDest parent to receive moved content -* int32_t *aOffset offset in aDest to move content to -*/ +/** + * Moves the _contents_ of aElement to (aDestElement, aInOutDestOffset). DTD + * containment rules are followed throughout. aInOutDestOffset is updated to + * point _after_ inserted content. + */ nsresult -nsHTMLEditRules::MoveContents(nsIDOMNode *aSource, nsIDOMNode *aDest, int32_t *aOffset) +nsHTMLEditRules::MoveContents(Element& aElement, Element& aDestElement, + int32_t* aInOutDestOffset) { - NS_ENSURE_TRUE(aSource && aDest && aOffset, NS_ERROR_NULL_POINTER); - if (aSource == aDest) return NS_ERROR_ILLEGAL_VALUE; - NS_ENSURE_STATE(mHTMLEditor); - NS_ASSERTION(!mHTMLEditor->IsTextNode(aSource), "#text does not have contents"); + MOZ_ASSERT(aInOutDestOffset); - nsCOMPtr child; - nsAutoString tag; - nsresult res; - aSource->GetFirstChild(getter_AddRefs(child)); - while (child) - { - res = MoveNodeSmart(child, aDest, aOffset); + NS_ENSURE_TRUE(&aElement != &aDestElement, NS_ERROR_ILLEGAL_VALUE); + + while (aElement.GetFirstChild()) { + nsresult res = MoveNodeSmart(*aElement.GetFirstChild(), aDestElement, + aInOutDestOffset); NS_ENSURE_SUCCESS(res, res); - aSource->GetFirstChild(getter_AddRefs(child)); } return NS_OK; } @@ -3017,8 +2961,7 @@ nsHTMLEditRules::WillMakeList(Selection* aSelection, } OwningNonNull listType = NS_Atomize(*aListType); - nsresult res = WillInsert(aSelection, aCancel); - NS_ENSURE_SUCCESS(res, res); + WillInsert(*aSelection, aCancel); // initialize out param // we want to ignore result of WillInsert() @@ -3043,7 +2986,7 @@ nsHTMLEditRules::WillMakeList(Selection* aSelection, *aHandled = true; - res = NormalizeSelection(aSelection); + nsresult res = NormalizeSelection(aSelection); NS_ENSURE_SUCCESS(res, res); NS_ENSURE_STATE(mHTMLEditor); nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor); @@ -3058,7 +3001,7 @@ nsHTMLEditRules::WillMakeList(Selection* aSelection, for (auto& curNode : arrayOfNodes) { // if curNode is not a Break or empty inline, we're done if (!nsTextEditUtils::IsBreak(curNode) && - !IsEmptyInline(GetAsDOMNode(curNode))) { + !IsEmptyInline(curNode)) { bOnlyBreaks = false; break; } @@ -3101,7 +3044,7 @@ nsHTMLEditRules::WillMakeList(Selection* aSelection, NS_ENSURE_STATE(theListItem); // remember our new block for postprocessing - mNewBlock = GetAsDOMNode(theListItem); + mNewBlock = theListItem; // put selection in new list item res = aSelection->Collapse(theListItem, 0); // to prevent selection resetter from overriding us @@ -3124,9 +3067,9 @@ nsHTMLEditRules::WillMakeList(Selection* aSelection, for (uint32_t i = 0; i < listCount; i++) { // here's where we actually figure out what to do - nsCOMPtr newBlock; + nsCOMPtr newBlock; NS_ENSURE_STATE(arrayOfNodes[i]->IsContent()); - nsCOMPtr curNode = arrayOfNodes[i]->AsContent(); + OwningNonNull curNode = *arrayOfNodes[i]->AsContent(); int32_t offset; curParent = nsEditor::GetNodeLocation(curNode, &offset); @@ -3143,7 +3086,7 @@ nsHTMLEditRules::WillMakeList(Selection* aSelection, NS_ENSURE_SUCCESS(res, res); prevListItem = 0; continue; - } else if (IsEmptyInline(GetAsDOMNode(curNode))) { + } else if (IsEmptyInline(curNode)) { // if curNode is an empty inline container, delete it NS_ENSURE_STATE(mHTMLEditor); res = mHTMLEditor->DeleteNode(curNode); @@ -3161,18 +3104,18 @@ nsHTMLEditRules::WillMakeList(Selection* aSelection, NS_ENSURE_STATE(mHTMLEditor); res = mHTMLEditor->MoveNode(curNode, curList, -1); NS_ENSURE_SUCCESS(res, res); - res = ConvertListType(GetAsDOMNode(curNode), address_of(newBlock), + res = ConvertListType(curNode->AsElement(), getter_AddRefs(newBlock), listType, itemType); NS_ENSURE_SUCCESS(res, res); NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->RemoveBlockContainer(newBlock); + res = mHTMLEditor->RemoveBlockContainer(*newBlock); NS_ENSURE_SUCCESS(res, res); } else { // replace list with new list type - res = ConvertListType(GetAsDOMNode(curNode), address_of(newBlock), + res = ConvertListType(curNode->AsElement(), getter_AddRefs(newBlock), listType, itemType); NS_ENSURE_SUCCESS(res, res); - curList = do_QueryInterface(newBlock); + curList = newBlock; } prevListItem = 0; continue; @@ -3185,9 +3128,12 @@ nsHTMLEditRules::WillMakeList(Selection* aSelection, // split the old list and make a new list of correct type. if (!curList || nsEditorUtils::IsDescendantOf(curNode, curList)) { NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->SplitNode(curParent->AsDOMNode(), offset, - getter_AddRefs(newBlock)); - NS_ENSURE_SUCCESS(res, res); + NS_ENSURE_STATE(curParent->IsContent()); + ErrorResult rv; + nsCOMPtr splitNode = + mHTMLEditor->SplitNode(*curParent->AsContent(), offset, rv); + NS_ENSURE_TRUE(!rv.Failed(), rv.StealNSResult()); + newBlock = splitNode ? splitNode->AsElement() : nullptr; int32_t offset; nsCOMPtr parent = nsEditor::GetNodeLocation(curParent, &offset); @@ -3203,9 +3149,8 @@ nsHTMLEditRules::WillMakeList(Selection* aSelection, NS_ENSURE_STATE(mHTMLEditor); if (!curNode->IsHTMLElement(itemType)) { NS_ENSURE_STATE(mHTMLEditor); - newBlock = dont_AddRef(GetAsDOMNode( - mHTMLEditor->ReplaceContainer(curNode->AsElement(), - itemType).take())); + newBlock = mHTMLEditor->ReplaceContainer(curNode->AsElement(), + itemType); NS_ENSURE_STATE(newBlock); } } else { @@ -3222,9 +3167,8 @@ nsHTMLEditRules::WillMakeList(Selection* aSelection, NS_ENSURE_STATE(mHTMLEditor); if (!curNode->IsHTMLElement(itemType)) { NS_ENSURE_STATE(mHTMLEditor); - newBlock = dont_AddRef(GetAsDOMNode( - mHTMLEditor->ReplaceContainer(curNode->AsElement(), - itemType).take())); + newBlock = mHTMLEditor->ReplaceContainer(curNode->AsElement(), + itemType); NS_ENSURE_STATE(newBlock); } } @@ -3262,7 +3206,7 @@ nsHTMLEditRules::WillMakeList(Selection* aSelection, curList = mHTMLEditor->CreateNode(listType, curParent, offset); NS_ENSURE_SUCCESS(res, res); // remember our new block for postprocessing - mNewBlock = GetAsDOMNode(curList); + mNewBlock = curList; // curList is now the correct thing to put curNode in prevListItem = 0; } @@ -3270,7 +3214,7 @@ nsHTMLEditRules::WillMakeList(Selection* aSelection, // if curNode isn't a list item, we must wrap it in one nsCOMPtr listItem; if (!nsHTMLEditUtils::IsListItem(curNode)) { - if (IsInlineNode(GetAsDOMNode(curNode)) && prevListItem) { + if (IsInlineNode(curNode) && prevListItem) { // this is a continuation of some inline nodes that belong together in // the same list item. use prevListItem NS_ENSURE_STATE(mHTMLEditor); @@ -3288,7 +3232,7 @@ nsHTMLEditRules::WillMakeList(Selection* aSelection, listItem = mHTMLEditor->InsertContainerAbove(curNode, itemType); NS_ENSURE_STATE(listItem); } - if (IsInlineNode(GetAsDOMNode(curNode))) { + if (IsInlineNode(curNode)) { prevListItem = listItem; } else { prevListItem = nullptr; @@ -3365,7 +3309,7 @@ nsHTMLEditRules::WillRemoveList(Selection* aSelection, } else if (nsHTMLEditUtils::IsList(curNode)) // node is a list, move list items out { - res = RemoveListStructure(GetAsDOMNode(curNode)); + res = RemoveListStructure(*curNode->AsElement()); NS_ENSURE_SUCCESS(res, res); } } @@ -3386,155 +3330,131 @@ nsHTMLEditRules::WillMakeDefListItem(Selection* aSelection, } nsresult -nsHTMLEditRules::WillMakeBasicBlock(Selection* aSelection, - const nsAString *aBlockType, - bool *aCancel, - bool *aHandled) +nsHTMLEditRules::WillMakeBasicBlock(Selection& aSelection, + const nsAString& aBlockType, + bool* aCancel, + bool* aHandled) { - OwningNonNull blockType = NS_Atomize(*aBlockType); - if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; } - // initialize out param + MOZ_ASSERT(aCancel && aHandled); + + NS_ENSURE_STATE(mHTMLEditor); + nsCOMPtr kungFuDeathGrip(mHTMLEditor); + + OwningNonNull blockType = NS_Atomize(aBlockType); + + WillInsert(aSelection, aCancel); + // We want to ignore result of WillInsert() *aCancel = false; *aHandled = false; - nsresult res = WillInsert(aSelection, aCancel); + nsresult res = NormalizeSelection(&aSelection); NS_ENSURE_SUCCESS(res, res); - // initialize out param - // we want to ignore result of WillInsert() - *aCancel = false; - res = NormalizeSelection(aSelection); - NS_ENSURE_SUCCESS(res, res); - NS_ENSURE_STATE(mHTMLEditor); - nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor); - NS_ENSURE_STATE(mHTMLEditor); + nsAutoSelectionReset selectionResetter(&aSelection, mHTMLEditor); nsAutoTxnsConserveSelection dontSpazMySelection(mHTMLEditor); *aHandled = true; - nsString tString(*aBlockType); - // contruct a list of nodes to act on. + // Contruct a list of nodes to act on. nsTArray> arrayOfNodes; - res = GetNodesFromSelection(*aSelection, EditAction::makeBasicBlock, + res = GetNodesFromSelection(aSelection, EditAction::makeBasicBlock, arrayOfNodes); NS_ENSURE_SUCCESS(res, res); // Remove all non-editable nodes. Leave them be. - int32_t listCount = arrayOfNodes.Length(); - int32_t i; - for (i=listCount-1; i>=0; i--) - { - NS_ENSURE_STATE(mHTMLEditor); + for (int32_t i = arrayOfNodes.Length() - 1; i >= 0; i--) { if (!mHTMLEditor->IsEditable(arrayOfNodes[i])) { arrayOfNodes.RemoveElementAt(i); } } - // reset list count - listCount = arrayOfNodes.Length(); + // If nothing visible in list, make an empty block + if (ListIsEmptyLine(arrayOfNodes)) { + // Get selection location + NS_ENSURE_STATE(aSelection.GetRangeAt(0) && + aSelection.GetRangeAt(0)->GetStartParent()); + OwningNonNull parent = + *aSelection.GetRangeAt(0)->GetStartParent(); + int32_t offset = aSelection.GetRangeAt(0)->StartOffset(); - // if nothing visible in list, make an empty block - if (ListIsEmptyLine(arrayOfNodes)) - { - nsCOMPtr theBlock; - - // get selection location - NS_ENSURE_STATE(aSelection->RangeCount()); - nsCOMPtr parent = aSelection->GetRangeAt(0)->GetStartParent(); - int32_t offset = aSelection->GetRangeAt(0)->StartOffset(); - NS_ENSURE_STATE(parent); - if (tString.EqualsLiteral("normal") || - tString.IsEmpty() ) // we are removing blocks (going to "body text") - { - NS_ENSURE_STATE(mHTMLEditor); - nsCOMPtr curBlock = mHTMLEditor->GetBlock(*parent); - NS_ENSURE_TRUE(curBlock, NS_ERROR_NULL_POINTER); - nsCOMPtr curBlockPar = - GetAsDOMNode(curBlock->GetParentNode()); - if (nsHTMLEditUtils::IsFormatNode(curBlock)) - { - // if the first editable node after selection is a br, consume it. Otherwise - // it gets pushed into a following block after the split, which is visually bad. - nsCOMPtr brNode; - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->GetNextHTMLNode(parent->AsDOMNode(), offset, - address_of(brNode)); - NS_ENSURE_SUCCESS(res, res); - if (brNode && nsTextEditUtils::IsBreak(brNode)) - { - NS_ENSURE_STATE(mHTMLEditor); + if (blockType == nsGkAtoms::normal || + blockType == nsGkAtoms::_empty) { + // We are removing blocks (going to "body text") + NS_ENSURE_TRUE(mHTMLEditor->GetBlock(parent), NS_ERROR_NULL_POINTER); + OwningNonNull curBlock = *mHTMLEditor->GetBlock(parent); + if (nsHTMLEditUtils::IsFormatNode(curBlock)) { + // If the first editable node after selection is a br, consume it. + // Otherwise it gets pushed into a following block after the split, + // which is visually bad. + nsCOMPtr brNode = + mHTMLEditor->GetNextHTMLNode(parent, offset); + if (brNode && brNode->IsHTMLElement(nsGkAtoms::br)) { res = mHTMLEditor->DeleteNode(brNode); NS_ENSURE_SUCCESS(res, res); } - // do the splits! - NS_ENSURE_STATE(mHTMLEditor); - offset = mHTMLEditor->SplitNodeDeep(*curBlock, *parent->AsContent(), + // Do the splits! + offset = mHTMLEditor->SplitNodeDeep(curBlock, *parent->AsContent(), offset, nsHTMLEditor::EmptyContainers::no); NS_ENSURE_STATE(offset != -1); - // put a br at the split point - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->CreateBR(curBlockPar, offset, address_of(brNode)); - NS_ENSURE_SUCCESS(res, res); - // put selection at the split point - res = aSelection->Collapse(curBlockPar, offset); - selectionResetter.Abort(); // to prevent selection reseter from overriding us. + // Put a br at the split point + brNode = mHTMLEditor->CreateBR(curBlock->GetParentNode(), offset); + NS_ENSURE_STATE(brNode); + // Put selection at the split point + res = aSelection.Collapse(curBlock->GetParentNode(), offset); + // To prevent selection resetter from overriding us. + selectionResetter.Abort(); *aHandled = true; + NS_ENSURE_SUCCESS(res, res); } - // else nothing to do! - } - else // we are making a block - { - // consume a br, if needed - NS_ENSURE_STATE(mHTMLEditor); + // Else nothing to do! + } else { + // We are making a block. Consume a br, if needed. nsCOMPtr brNode = mHTMLEditor->GetNextHTMLNode(parent, offset, true); - NS_ENSURE_SUCCESS(res, res); - if (brNode && nsTextEditUtils::IsBreak(brNode)) - { - NS_ENSURE_STATE(mHTMLEditor); + if (brNode && brNode->IsHTMLElement(nsGkAtoms::br)) { res = mHTMLEditor->DeleteNode(brNode); NS_ENSURE_SUCCESS(res, res); - // we don't need to act on this node any more + // We don't need to act on this node any more arrayOfNodes.RemoveElement(brNode); } - // make sure we can put a block here + // Make sure we can put a block here res = SplitAsNeeded(blockType, parent, offset); NS_ENSURE_SUCCESS(res, res); - NS_ENSURE_STATE(mHTMLEditor); - theBlock = dont_AddRef(GetAsDOMNode( - mHTMLEditor->CreateNode(blockType, parent, offset).take())); - NS_ENSURE_STATE(theBlock); - // remember our new block for postprocessing - mNewBlock = theBlock; - // delete anything that was in the list of nodes + nsCOMPtr block = + mHTMLEditor->CreateNode(blockType, parent, offset); + NS_ENSURE_STATE(block); + // Remember our new block for postprocessing + mNewBlock = block; + // Delete anything that was in the list of nodes while (!arrayOfNodes.IsEmpty()) { OwningNonNull curNode = arrayOfNodes[0]; - NS_ENSURE_STATE(mHTMLEditor); res = mHTMLEditor->DeleteNode(curNode); NS_ENSURE_SUCCESS(res, res); arrayOfNodes.RemoveElementAt(0); } - // put selection in new block - res = aSelection->Collapse(theBlock,0); - selectionResetter.Abort(); // to prevent selection reseter from overriding us. + // Put selection in new block + res = aSelection.Collapse(block, 0); + // To prevent selection resetter from overriding us. + selectionResetter.Abort(); *aHandled = true; + NS_ENSURE_SUCCESS(res, res); } - return res; + return NS_OK; } - else - { - // Ok, now go through all the nodes and make the right kind of blocks, - // or whatever is approriate. Wohoo! - // Note: blockquote is handled a little differently - if (tString.EqualsLiteral("blockquote")) { - res = MakeBlockquote(arrayOfNodes); - } else if (tString.EqualsLiteral("normal") || tString.IsEmpty()) { - res = RemoveBlockStyle(arrayOfNodes); - } else { - res = ApplyBlockStyle(arrayOfNodes, *blockType); - } - return res; + // Okay, now go through all the nodes and make the right kind of blocks, or + // whatever is approriate. Woohoo! Note: blockquote is handled a little + // differently. + if (blockType == nsGkAtoms::blockquote) { + res = MakeBlockquote(arrayOfNodes); + NS_ENSURE_SUCCESS(res, res); + } else if (blockType == nsGkAtoms::normal || + blockType == nsGkAtoms::_empty) { + res = RemoveBlockStyle(arrayOfNodes); + NS_ENSURE_SUCCESS(res, res); + } else { + res = ApplyBlockStyle(arrayOfNodes, blockType); + NS_ENSURE_SUCCESS(res, res); } - return res; + return NS_OK; } nsresult @@ -3547,12 +3467,12 @@ nsHTMLEditRules::DidMakeBasicBlock(Selection* aSelection, return NS_OK; } - nsCOMPtr parent; - int32_t offset; - nsresult res = nsEditor::GetStartNodeAndOffset(aSelection, getter_AddRefs(parent), &offset); + NS_ENSURE_STATE(aSelection->GetRangeAt(0) && + aSelection->GetRangeAt(0)->GetStartParent()); + nsresult res = + InsertMozBRIfNeeded(*aSelection->GetRangeAt(0)->GetStartParent()); NS_ENSURE_SUCCESS(res, res); - res = InsertMozBRIfNeeded(parent); - return res; + return NS_OK; } nsresult @@ -3576,15 +3496,14 @@ nsHTMLEditRules::WillCSSIndent(Selection* aSelection, { if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; } - nsresult res = WillInsert(aSelection, aCancel); - NS_ENSURE_SUCCESS(res, res); + WillInsert(*aSelection, aCancel); // initialize out param // we want to ignore result of WillInsert() *aCancel = false; *aHandled = true; - res = NormalizeSelection(aSelection); + nsresult res = NormalizeSelection(aSelection); NS_ENSURE_SUCCESS(res, res); NS_ENSURE_STATE(mHTMLEditor); nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor); @@ -3637,8 +3556,8 @@ nsHTMLEditRules::WillCSSIndent(Selection* aSelection, parent, offset); NS_ENSURE_STATE(theBlock); // remember our new block for postprocessing - mNewBlock = theBlock->AsDOMNode(); - RelativeChangeIndentationOfElementNode(theBlock->AsDOMNode(), +1); + mNewBlock = theBlock; + ChangeIndentation(*theBlock, Change::plus); // delete anything that was in the list of nodes while (!arrayOfNodes.IsEmpty()) { OwningNonNull curNode = arrayOfNodes[0]; @@ -3729,7 +3648,7 @@ nsHTMLEditRules::WillCSSIndent(Selection* aSelection, NS_ENSURE_STATE(curList); // curList is now the correct thing to put curNode in // remember our new block for postprocessing - mNewBlock = curList->AsDOMNode(); + mNewBlock = curList; } // tuck the node into the end of the active list uint32_t listLen = curList->Length(); @@ -3740,8 +3659,8 @@ nsHTMLEditRules::WillCSSIndent(Selection* aSelection, else // not a list item { - if (IsBlockNode(curNode->AsDOMNode())) { - RelativeChangeIndentationOfElementNode(curNode->AsDOMNode(), +1); + if (curNode && IsBlockNode(*curNode)) { + ChangeIndentation(*curNode->AsElement(), Change::plus); curQuote = nullptr; } else { @@ -3758,9 +3677,9 @@ nsHTMLEditRules::WillCSSIndent(Selection* aSelection, curQuote = mHTMLEditor->CreateNode(nsGkAtoms::div, curParent, offset); NS_ENSURE_STATE(curQuote); - RelativeChangeIndentationOfElementNode(curQuote->AsDOMNode(), +1); + ChangeIndentation(*curQuote, Change::plus); // remember our new block for postprocessing - mNewBlock = curQuote->AsDOMNode(); + mNewBlock = curQuote; // curQuote is now the correct thing to put curNode in } @@ -3780,15 +3699,14 @@ nsHTMLEditRules::WillHTMLIndent(Selection* aSelection, bool* aCancel, bool* aHandled) { if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; } - nsresult res = WillInsert(aSelection, aCancel); - NS_ENSURE_SUCCESS(res, res); + WillInsert(*aSelection, aCancel); // initialize out param // we want to ignore result of WillInsert() *aCancel = false; *aHandled = true; - res = NormalizeSelection(aSelection); + nsresult res = NormalizeSelection(aSelection); NS_ENSURE_SUCCESS(res, res); NS_ENSURE_STATE(mHTMLEditor); nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor); @@ -3823,7 +3741,7 @@ nsHTMLEditRules::WillHTMLIndent(Selection* aSelection, parent, offset); NS_ENSURE_STATE(theBlock); // remember our new block for postprocessing - mNewBlock = theBlock->AsDOMNode(); + mNewBlock = theBlock; // delete anything that was in the list of nodes while (!arrayOfNodes.IsEmpty()) { OwningNonNull curNode = arrayOfNodes[0]; @@ -3913,7 +3831,7 @@ nsHTMLEditRules::WillHTMLIndent(Selection* aSelection, NS_ENSURE_STATE(curList); // curList is now the correct thing to put curNode in // remember our new block for postprocessing - mNewBlock = curList->AsDOMNode(); + mNewBlock = curList; } // tuck the node into the end of the active list NS_ENSURE_STATE(mHTMLEditor); @@ -3990,7 +3908,7 @@ nsHTMLEditRules::WillHTMLIndent(Selection* aSelection, offset); NS_ENSURE_STATE(curQuote); // remember our new block for postprocessing - mNewBlock = curQuote->AsDOMNode(); + mNewBlock = curQuote; // curQuote is now the correct thing to put curNode in } @@ -4008,282 +3926,260 @@ nsHTMLEditRules::WillHTMLIndent(Selection* aSelection, nsresult -nsHTMLEditRules::WillOutdent(Selection* aSelection, +nsHTMLEditRules::WillOutdent(Selection& aSelection, bool* aCancel, bool* aHandled) { - if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; } - // initialize out param + MOZ_ASSERT(aCancel && aHandled); *aCancel = false; *aHandled = true; - nsresult res = NS_OK; - nsCOMPtr rememberedLeftBQ, rememberedRightBQ; + nsCOMPtr rememberedLeftBQ, rememberedRightBQ; NS_ENSURE_STATE(mHTMLEditor); + nsCOMPtr kungFuDeathGrip(mHTMLEditor); bool useCSS = mHTMLEditor->IsCSSEnabled(); - res = NormalizeSelection(aSelection); + nsresult res = NormalizeSelection(&aSelection); NS_ENSURE_SUCCESS(res, res); - // some scoping for selection resetting - we may need to tweak it - { - NS_ENSURE_STATE(mHTMLEditor); - nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor); - // convert the selection ranges into "promoted" selection ranges: - // this basically just expands the range to include the immediate - // block parent, and then further expands to include any ancestors - // whose children are all in the range + // Some scoping for selection resetting - we may need to tweak it + { + nsAutoSelectionReset selectionResetter(&aSelection, mHTMLEditor); + + // Convert the selection ranges into "promoted" selection ranges: this + // basically just expands the range to include the immediate block parent, + // and then further expands to include any ancestors whose children are all + // in the range nsTArray> arrayOfNodes; - res = GetNodesFromSelection(*aSelection, EditAction::outdent, + res = GetNodesFromSelection(aSelection, EditAction::outdent, arrayOfNodes); NS_ENSURE_SUCCESS(res, res); - // Ok, now go through all the nodes and remove a level of blockquoting, + // Okay, now go through all the nodes and remove a level of blockquoting, // or whatever is appropriate. Wohoo! - nsCOMPtr curBlockQuote, firstBQChild, lastBQChild; + nsCOMPtr curBlockQuote; + nsCOMPtr firstBQChild, lastBQChild; bool curBlockQuoteIsIndentedWithCSS = false; - for (auto& curNode : arrayOfNodes) { - // here's where we actually figure out what to do + for (uint32_t i = 0; i < arrayOfNodes.Length(); i++) { + if (!arrayOfNodes[i]->IsContent()) { + continue; + } + OwningNonNull curNode = *arrayOfNodes[i]->AsContent(); + + // Here's where we actually figure out what to do nsCOMPtr curParent = curNode->GetParentNode(); int32_t offset = curParent ? curParent->IndexOf(curNode) : -1; - // is it a blockquote? + // Is it a blockquote? if (curNode->IsHTMLElement(nsGkAtoms::blockquote)) { - // if it is a blockquote, remove it. - // So we need to finish up dealng with any curBlockQuote first. - if (curBlockQuote) - { - res = OutdentPartOfBlock(curBlockQuote, firstBQChild, lastBQChild, + // If it is a blockquote, remove it. So we need to finish up dealng + // with any curBlockQuote first. + if (curBlockQuote) { + res = OutdentPartOfBlock(*curBlockQuote, *firstBQChild, *lastBQChild, curBlockQuoteIsIndentedWithCSS, - address_of(rememberedLeftBQ), - address_of(rememberedRightBQ)); + getter_AddRefs(rememberedLeftBQ), + getter_AddRefs(rememberedRightBQ)); NS_ENSURE_SUCCESS(res, res); - curBlockQuote = 0; firstBQChild = 0; lastBQChild = 0; + curBlockQuote = nullptr; + firstBQChild = nullptr; + lastBQChild = nullptr; curBlockQuoteIsIndentedWithCSS = false; } - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->RemoveBlockContainer(GetAsDOMNode(curNode)); + res = mHTMLEditor->RemoveBlockContainer(curNode); NS_ENSURE_SUCCESS(res, res); continue; } - // is it a block with a 'margin' property? - if (useCSS && IsBlockNode(GetAsDOMNode(curNode))) { - NS_ENSURE_STATE(mHTMLEditor); - nsIAtom* marginProperty = - MarginPropertyAtomForIndent(mHTMLEditor->mHTMLCSSUtils, - GetAsDOMNode(curNode)); + // Is it a block with a 'margin' property? + if (useCSS && IsBlockNode(curNode)) { + nsIAtom& marginProperty = + MarginPropertyAtomForIndent(*mHTMLEditor->mHTMLCSSUtils, curNode); nsAutoString value; - NS_ENSURE_STATE(mHTMLEditor); - mHTMLEditor->mHTMLCSSUtils->GetSpecifiedProperty(*curNode, - *marginProperty, + mHTMLEditor->mHTMLCSSUtils->GetSpecifiedProperty(curNode, + marginProperty, value); float f; nsCOMPtr unit; NS_ENSURE_STATE(mHTMLEditor); mHTMLEditor->mHTMLCSSUtils->ParseLength(value, &f, getter_AddRefs(unit)); - if (f > 0) - { - RelativeChangeIndentationOfElementNode(GetAsDOMNode(curNode), -1); + if (f > 0) { + ChangeIndentation(*curNode->AsElement(), Change::minus); continue; } } - // is it a list item? - if (nsHTMLEditUtils::IsListItem(curNode)) - { - // if it is a list item, that means we are not outdenting whole list. - // So we need to finish up dealing with any curBlockQuote, and then - // pop this list item. - if (curBlockQuote) - { - res = OutdentPartOfBlock(curBlockQuote, firstBQChild, lastBQChild, + // Is it a list item? + if (nsHTMLEditUtils::IsListItem(curNode)) { + // If it is a list item, that means we are not outdenting whole list. + // So we need to finish up dealing with any curBlockQuote, and then pop + // this list item. + if (curBlockQuote) { + res = OutdentPartOfBlock(*curBlockQuote, *firstBQChild, *lastBQChild, curBlockQuoteIsIndentedWithCSS, - address_of(rememberedLeftBQ), - address_of(rememberedRightBQ)); + getter_AddRefs(rememberedLeftBQ), + getter_AddRefs(rememberedRightBQ)); NS_ENSURE_SUCCESS(res, res); - curBlockQuote = 0; firstBQChild = 0; lastBQChild = 0; + curBlockQuote = nullptr; + firstBQChild = nullptr; + lastBQChild = nullptr; curBlockQuoteIsIndentedWithCSS = false; } - bool bOutOfList; - res = PopListItem(GetAsDOMNode(curNode), &bOutOfList); + bool unused; + res = PopListItem(GetAsDOMNode(curNode), &unused); NS_ENSURE_SUCCESS(res, res); continue; } - // do we have a blockquote that we are already committed to removing? - if (curBlockQuote) - { - // if so, is this node a descendant? - if (nsEditorUtils::IsDescendantOf(GetAsDOMNode(curNode), - curBlockQuote)) { - lastBQChild = GetAsDOMNode(curNode); - continue; // then we don't need to do anything different for this node - } - else - { - // otherwise, we have progressed beyond end of curBlockQuote, - // so lets handle it now. We need to remove the portion of + // Do we have a blockquote that we are already committed to removing? + if (curBlockQuote) { + // If so, is this node a descendant? + if (nsEditorUtils::IsDescendantOf(curNode, curBlockQuote)) { + lastBQChild = curNode; + // Then we don't need to do anything different for this node + continue; + } else { + // Otherwise, we have progressed beyond end of curBlockQuote, so + // let's handle it now. We need to remove the portion of // curBlockQuote that contains [firstBQChild - lastBQChild]. - res = OutdentPartOfBlock(curBlockQuote, firstBQChild, lastBQChild, + res = OutdentPartOfBlock(*curBlockQuote, *firstBQChild, + *lastBQChild, curBlockQuoteIsIndentedWithCSS, - address_of(rememberedLeftBQ), - address_of(rememberedRightBQ)); + getter_AddRefs(rememberedLeftBQ), + getter_AddRefs(rememberedRightBQ)); NS_ENSURE_SUCCESS(res, res); - curBlockQuote = 0; firstBQChild = 0; lastBQChild = 0; + curBlockQuote = nullptr; + firstBQChild = nullptr; + lastBQChild = nullptr; curBlockQuoteIsIndentedWithCSS = false; - // fall out and handle curNode + // Fall out and handle curNode } } - // are we inside a blockquote? - nsCOMPtr n = curNode; + // Are we inside a blockquote? + OwningNonNull n = curNode; curBlockQuoteIsIndentedWithCSS = false; - // keep looking up the hierarchy as long as we don't hit the body or the + // Keep looking up the hierarchy as long as we don't hit the body or the // active editing host or a table element (other than an entire table) - while (!n->IsHTMLElement(nsGkAtoms::body) && mHTMLEditor && + while (!n->IsHTMLElement(nsGkAtoms::body) && mHTMLEditor->IsDescendantOfEditorRoot(n) && (n->IsHTMLElement(nsGkAtoms::table) || !nsHTMLEditUtils::IsTableElement(n))) { if (!n->GetParentNode()) { break; } - n = n->GetParentNode(); + n = *n->GetParentNode(); if (n->IsHTMLElement(nsGkAtoms::blockquote)) { - // if so, remember it, and remember first node we are taking out of it. - curBlockQuote = GetAsDOMNode(n); - firstBQChild = GetAsDOMNode(curNode); - lastBQChild = GetAsDOMNode(curNode); + // If so, remember it and the first node we are taking out of it. + curBlockQuote = n->AsElement(); + firstBQChild = curNode; + lastBQChild = curNode; break; - } - else if (useCSS) - { - NS_ENSURE_STATE(mHTMLEditor); - nsIAtom* marginProperty = - MarginPropertyAtomForIndent(mHTMLEditor->mHTMLCSSUtils, - GetAsDOMNode(curNode)); + } else if (useCSS) { + nsIAtom& marginProperty = + MarginPropertyAtomForIndent(*mHTMLEditor->mHTMLCSSUtils, curNode); nsAutoString value; - NS_ENSURE_STATE(mHTMLEditor); - mHTMLEditor->mHTMLCSSUtils->GetSpecifiedProperty(*n, *marginProperty, + mHTMLEditor->mHTMLCSSUtils->GetSpecifiedProperty(*n, marginProperty, value); float f; nsCOMPtr unit; - NS_ENSURE_STATE(mHTMLEditor); mHTMLEditor->mHTMLCSSUtils->ParseLength(value, &f, getter_AddRefs(unit)); - if (f > 0 && !(nsHTMLEditUtils::IsList(curParent) && nsHTMLEditUtils::IsList(curNode))) - { - curBlockQuote = GetAsDOMNode(n); - firstBQChild = GetAsDOMNode(curNode); - lastBQChild = GetAsDOMNode(curNode); + if (f > 0 && !(nsHTMLEditUtils::IsList(curParent) && + nsHTMLEditUtils::IsList(curNode))) { + curBlockQuote = n->AsElement(); + firstBQChild = curNode; + lastBQChild = curNode; curBlockQuoteIsIndentedWithCSS = true; break; } } } - if (!curBlockQuote) - { - // could not find an enclosing blockquote for this node. handle list cases. - if (nsHTMLEditUtils::IsList(curParent)) // move node out of list - { - if (nsHTMLEditUtils::IsList(curNode)) // just unwrap this sublist - { - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->RemoveBlockContainer(GetAsDOMNode(curNode)); + if (!curBlockQuote) { + // Couldn't find enclosing blockquote. Handle list cases. + if (nsHTMLEditUtils::IsList(curParent)) { + // Move node out of list + if (nsHTMLEditUtils::IsList(curNode)) { + // Just unwrap this sublist + res = mHTMLEditor->RemoveBlockContainer(curNode); NS_ENSURE_SUCCESS(res, res); } // handled list item case above - } - else if (nsHTMLEditUtils::IsList(curNode)) // node is a list, but parent is non-list: move list items out - { + } else if (nsHTMLEditUtils::IsList(curNode)) { + // node is a list, but parent is non-list: move list items out nsCOMPtr child = curNode->GetLastChild(); - while (child) - { - if (nsHTMLEditUtils::IsListItem(child)) - { - bool bOutOfList; - res = PopListItem(GetAsDOMNode(child), &bOutOfList); + while (child) { + if (nsHTMLEditUtils::IsListItem(child)) { + bool unused; + res = PopListItem(GetAsDOMNode(child), &unused); NS_ENSURE_SUCCESS(res, res); - } - else if (nsHTMLEditUtils::IsList(child)) - { - // We have an embedded list, so move it out from under the - // parent list. Be sure to put it after the parent list - // because this loop iterates backwards through the parent's - // list of children. + } else if (nsHTMLEditUtils::IsList(child)) { + // We have an embedded list, so move it out from under the parent + // list. Be sure to put it after the parent list because this + // loop iterates backwards through the parent's list of children. - NS_ENSURE_STATE(mHTMLEditor); res = mHTMLEditor->MoveNode(child, curParent, offset + 1); NS_ENSURE_SUCCESS(res, res); - } - else - { - // delete any non- list items for now - NS_ENSURE_STATE(mHTMLEditor); + } else { + // Delete any non-list items for now res = mHTMLEditor->DeleteNode(child); NS_ENSURE_SUCCESS(res, res); } child = curNode->GetLastChild(); } - // delete the now-empty list - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->RemoveBlockContainer(GetAsDOMNode(curNode)); + // Delete the now-empty list + res = mHTMLEditor->RemoveBlockContainer(curNode); NS_ENSURE_SUCCESS(res, res); - } - else if (useCSS) { - nsCOMPtr element; + } else if (useCSS) { + nsCOMPtr element; nsCOMPtr textNode = do_QueryInterface(curNode); - if (textNode) { + if (curNode->GetAsText()) { // We want to outdent the parent of text nodes - nsCOMPtr parent; - textNode->GetParentNode(getter_AddRefs(parent)); - element = do_QueryInterface(parent); - } else { - element = do_QueryInterface(curNode); + element = curNode->GetParentElement(); + } else if (curNode->IsElement()) { + element = curNode->AsElement(); } if (element) { - RelativeChangeIndentationOfElementNode(element, -1); + ChangeIndentation(*element, Change::minus); } } } } - if (curBlockQuote) - { - // we have a blockquote we haven't finished handling - res = OutdentPartOfBlock(curBlockQuote, firstBQChild, lastBQChild, + if (curBlockQuote) { + // We have a blockquote we haven't finished handling + res = OutdentPartOfBlock(*curBlockQuote, *firstBQChild, *lastBQChild, curBlockQuoteIsIndentedWithCSS, - address_of(rememberedLeftBQ), - address_of(rememberedRightBQ)); + getter_AddRefs(rememberedLeftBQ), + getter_AddRefs(rememberedRightBQ)); NS_ENSURE_SUCCESS(res, res); } } - // make sure selection didn't stick to last piece of content in old bq - // (only a problem for collapsed selections) + // Make sure selection didn't stick to last piece of content in old bq (only + // a problem for collapsed selections) if (rememberedLeftBQ || rememberedRightBQ) { - if (aSelection->Collapsed()) { - // push selection past end of rememberedLeftBQ - nsCOMPtr sNode; - int32_t sOffset; - NS_ENSURE_STATE(mHTMLEditor); - mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(sNode), &sOffset); + if (aSelection.Collapsed()) { + // Push selection past end of rememberedLeftBQ + NS_ENSURE_TRUE(aSelection.GetRangeAt(0), NS_OK); + nsCOMPtr startNode = aSelection.GetRangeAt(0)->GetStartParent(); + int32_t startOffset = aSelection.GetRangeAt(0)->StartOffset(); if (rememberedLeftBQ && - ((sNode == rememberedLeftBQ) || nsEditorUtils::IsDescendantOf(sNode, rememberedLeftBQ))) - { - // selection is inside rememberedLeftBQ - push it past it. - sNode = nsEditor::GetNodeLocation(rememberedLeftBQ, &sOffset); - sOffset++; - aSelection->Collapse(sNode, sOffset); + (startNode == rememberedLeftBQ || + nsEditorUtils::IsDescendantOf(startNode, rememberedLeftBQ))) { + // Selection is inside rememberedLeftBQ - push it past it. + startNode = rememberedLeftBQ->GetParentNode(); + startOffset = startNode ? 1 + startNode->IndexOf(rememberedLeftBQ) : 0; + aSelection.Collapse(startNode, startOffset); } - // and pull selection before beginning of rememberedRightBQ - NS_ENSURE_STATE(mHTMLEditor); - mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(sNode), &sOffset); + // And pull selection before beginning of rememberedRightBQ + startNode = aSelection.GetRangeAt(0)->GetStartParent(); + startOffset = aSelection.GetRangeAt(0)->StartOffset(); if (rememberedRightBQ && - ((sNode == rememberedRightBQ) || nsEditorUtils::IsDescendantOf(sNode, rememberedRightBQ))) - { - // selection is inside rememberedRightBQ - push it before it. - sNode = nsEditor::GetNodeLocation(rememberedRightBQ, &sOffset); - aSelection->Collapse(sNode, sOffset); + (startNode == rememberedRightBQ || + nsEditorUtils::IsDescendantOf(startNode, rememberedRightBQ))) { + // Selection is inside rememberedRightBQ - push it before it. + startNode = rememberedRightBQ->GetParentNode(); + startOffset = startNode ? startNode->IndexOf(rememberedRightBQ) : -1; + aSelection.Collapse(startNode, startOffset); } } return NS_OK; } - return res; + return NS_OK; } @@ -4295,124 +4191,97 @@ nsHTMLEditRules::RemovePartOfBlock(Element& aBlock, nsIContent& aStartChild, nsIContent& aEndChild) { - nsresult res = SplitBlock(aBlock.AsDOMNode(), aStartChild.AsDOMNode(), - aEndChild.AsDOMNode()); - NS_ENSURE_SUCCESS(res, res); + SplitBlock(aBlock, aStartChild, aEndChild); // Get rid of part of blockquote we are outdenting NS_ENSURE_STATE(mHTMLEditor); - return mHTMLEditor->RemoveBlockContainer(aBlock.AsDOMNode()); -} - -nsresult -nsHTMLEditRules::SplitBlock(nsIDOMNode *aBlock, - nsIDOMNode *aStartChild, - nsIDOMNode *aEndChild, - nsCOMPtr *aLeftNode, - nsCOMPtr *aRightNode, - nsCOMPtr *aMiddleNode) -{ - NS_ENSURE_TRUE(aBlock && aStartChild && aEndChild, NS_ERROR_NULL_POINTER); - - nsCOMPtr leftNode, rightNode; - int32_t startOffset, endOffset; - - // get split point location - nsCOMPtr startParent = nsEditor::GetNodeLocation(aStartChild, &startOffset); - - // do the splits! - nsCOMPtr block = do_QueryInterface(aBlock); - NS_ENSURE_STATE(block || !aBlock); - nsCOMPtr startParentContent = do_QueryInterface(startParent); - NS_ENSURE_STATE(startParentContent || !startParent); - NS_ENSURE_STATE(mHTMLEditor); - mHTMLEditor->SplitNodeDeep(*block, *startParentContent, startOffset, - nsHTMLEditor::EmptyContainers::no, - getter_AddRefs(leftNode), - getter_AddRefs(rightNode)); - if (rightNode) { - aBlock = GetAsDOMNode(rightNode); - } - - // remember left portion of block if caller requested - if (aLeftNode) - *aLeftNode = GetAsDOMNode(leftNode); - - // get split point location - nsCOMPtr endParent = nsEditor::GetNodeLocation(aEndChild, &endOffset); - endOffset++; // want to be after lastBQChild - - // do the splits! - nsCOMPtr endParentContent = do_QueryInterface(endParent); - NS_ENSURE_STATE(endParentContent || !endParent); - NS_ENSURE_STATE(mHTMLEditor); - mHTMLEditor->SplitNodeDeep(*block, *endParentContent, endOffset, - nsHTMLEditor::EmptyContainers::no, - getter_AddRefs(leftNode), - getter_AddRefs(rightNode)); - if (leftNode) { - aBlock = GetAsDOMNode(leftNode); - } - - // remember right portion of block if caller requested - if (aRightNode) - *aRightNode = GetAsDOMNode(rightNode); - - if (aMiddleNode) - *aMiddleNode = aBlock; + nsresult res = mHTMLEditor->RemoveBlockContainer(aBlock); + NS_ENSURE_SUCCESS(res, res); return NS_OK; } -nsresult -nsHTMLEditRules::OutdentPartOfBlock(nsIDOMNode *aBlock, - nsIDOMNode *aStartChild, - nsIDOMNode *aEndChild, - bool aIsBlockIndentedWithCSS, - nsCOMPtr *aLeftNode, - nsCOMPtr *aRightNode) +void +nsHTMLEditRules::SplitBlock(Element& aBlock, + nsIContent& aStartChild, + nsIContent& aEndChild, + nsIContent** aOutLeftNode, + nsIContent** aOutRightNode, + nsIContent** aOutMiddleNode) { - nsCOMPtr middleNode; - nsresult res = SplitBlock(aBlock, aStartChild, aEndChild, - aLeftNode, - aRightNode, - address_of(middleNode)); - NS_ENSURE_SUCCESS(res, res); - if (aIsBlockIndentedWithCSS) { - res = RelativeChangeIndentationOfElementNode(middleNode, -1); - } else { - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->RemoveBlockContainer(middleNode); + // aStartChild and aEndChild must be exclusive descendants of aBlock + MOZ_ASSERT(nsEditorUtils::IsDescendantOf(&aStartChild, &aBlock) && + nsEditorUtils::IsDescendantOf(&aEndChild, &aBlock)); + NS_ENSURE_TRUE_VOID(mHTMLEditor); + nsCOMPtr kungFuDeathGrip(mHTMLEditor); + + // Get split point location + OwningNonNull startParent = *aStartChild.GetParent(); + int32_t startOffset = startParent->IndexOf(&aStartChild); + + // Do the splits! + nsCOMPtr newMiddleNode1; + mHTMLEditor->SplitNodeDeep(aBlock, startParent, startOffset, + nsHTMLEditor::EmptyContainers::no, + aOutLeftNode, getter_AddRefs(newMiddleNode1)); + + // Get split point location + OwningNonNull endParent = *aEndChild.GetParent(); + // +1 because we want to be after the child + int32_t endOffset = 1 + endParent->IndexOf(&aEndChild); + + // Do the splits! + nsCOMPtr newMiddleNode2; + mHTMLEditor->SplitNodeDeep(aBlock, endParent, endOffset, + nsHTMLEditor::EmptyContainers::no, + getter_AddRefs(newMiddleNode2), aOutRightNode); + + if (aOutMiddleNode) { + if (newMiddleNode2) { + newMiddleNode2.forget(aOutMiddleNode); + } else { + newMiddleNode1.forget(aOutMiddleNode); + } } - return res; +} + +nsresult +nsHTMLEditRules::OutdentPartOfBlock(Element& aBlock, + nsIContent& aStartChild, + nsIContent& aEndChild, + bool aIsBlockIndentedWithCSS, + nsIContent** aOutLeftNode, + nsIContent** aOutRightNode) +{ + MOZ_ASSERT(aOutLeftNode && aOutRightNode); + + nsCOMPtr middleNode; + SplitBlock(aBlock, aStartChild, aEndChild, aOutLeftNode, aOutRightNode, + getter_AddRefs(middleNode)); + + NS_ENSURE_STATE(middleNode); + + if (!aIsBlockIndentedWithCSS) { + NS_ENSURE_STATE(mHTMLEditor); + nsresult res = + mHTMLEditor->RemoveBlockContainer(*middleNode); + NS_ENSURE_SUCCESS(res, res); + } else if (middleNode->IsElement()) { + // We do nothing if middleNode isn't an element + nsresult res = ChangeIndentation(*middleNode->AsElement(), Change::minus); + NS_ENSURE_SUCCESS(res, res); + } + + return NS_OK; } /////////////////////////////////////////////////////////////////////////// // ConvertListType: convert list type and list item type. // // -nsresult -nsHTMLEditRules::ConvertListType(nsIDOMNode* aList, - nsCOMPtr* outList, - nsIAtom* aListType, - nsIAtom* aItemType) -{ - MOZ_ASSERT(aListType); - MOZ_ASSERT(aItemType); - - NS_ENSURE_TRUE(aList && outList, NS_ERROR_NULL_POINTER); - nsCOMPtr list = do_QueryInterface(aList); - NS_ENSURE_STATE(list); - - nsCOMPtr outNode; - nsresult rv = ConvertListType(list, getter_AddRefs(outNode), aListType, aItemType); - *outList = outNode ? outNode->AsDOMNode() : nullptr; - return rv; -} - nsresult nsHTMLEditRules::ConvertListType(Element* aList, - dom::Element** aOutList, + Element** aOutList, nsIAtom* aListType, nsIAtom* aItemType) { @@ -4461,19 +4330,16 @@ nsHTMLEditRules::ConvertListType(Element* aList, // // nsresult -nsHTMLEditRules::CreateStyleForInsertText(Selection* aSelection, - nsIDOMDocument *aDoc) +nsHTMLEditRules::CreateStyleForInsertText(Selection& aSelection, + nsIDocument& aDoc) { - MOZ_ASSERT(aSelection && aDoc && mHTMLEditor->mTypeInState); + MOZ_ASSERT(mHTMLEditor->mTypeInState); + nsresult res; bool weDidSomething = false; - nsCOMPtr node, tmp; - int32_t offset; - NS_ENSURE_STATE(mHTMLEditor); - nsresult res = mHTMLEditor->GetStartNodeAndOffset(aSelection, - getter_AddRefs(node), - &offset); - NS_ENSURE_SUCCESS(res, res); + NS_ENSURE_STATE(aSelection.GetRangeAt(0)); + nsCOMPtr node = aSelection.GetRangeAt(0)->GetStartParent(); + int32_t offset = aSelection.GetRangeAt(0)->StartOffset(); // next examine our present style and make sure default styles are either // present or explicitly overridden. If neither, add the default style to @@ -4506,9 +4372,8 @@ nsHTMLEditRules::CreateStyleForInsertText(Selection* aSelection, } } - nsCOMPtr rootElement; - res = aDoc->GetDocumentElement(getter_AddRefs(rootElement)); - NS_ENSURE_SUCCESS(res, res); + nsCOMPtr rootElement = aDoc.GetRootElement(); + NS_ENSURE_STATE(rootElement); // process clearing any styles first nsAutoPtr item(mHTMLEditor->mTypeInState->TakeClearProperty()); @@ -4528,27 +4393,19 @@ nsHTMLEditRules::CreateStyleForInsertText(Selection* aSelection, if (item || relFontSize) { // we have at least one style to add; make a new text node to insert style // nodes above. - if (mHTMLEditor->IsTextNode(node)) { + if (RefPtr text = node->GetAsText()) { // if we are in a text node, split it NS_ENSURE_STATE(mHTMLEditor); - nsCOMPtr content = do_QueryInterface(node); - NS_ENSURE_STATE(content || !node); - offset = mHTMLEditor->SplitNodeDeep(*content, *content, offset); + offset = mHTMLEditor->SplitNodeDeep(*text, *text, offset); NS_ENSURE_STATE(offset != -1); - node->GetParentNode(getter_AddRefs(tmp)); - node = tmp; + node = node->GetParentNode(); } if (!mHTMLEditor->IsContainer(node)) { return NS_OK; } - nsCOMPtr newNode; - nsCOMPtr nodeAsText; - res = aDoc->CreateTextNode(EmptyString(), getter_AddRefs(nodeAsText)); - NS_ENSURE_SUCCESS(res, res); - NS_ENSURE_TRUE(nodeAsText, NS_ERROR_NULL_POINTER); - newNode = do_QueryInterface(nodeAsText); + OwningNonNull newNode = aDoc.CreateTextNode(EmptyString()); NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->InsertNode(newNode, node, offset); + res = mHTMLEditor->InsertNode(newNode, *node, offset); NS_ENSURE_SUCCESS(res, res); node = newNode; offset = 0; @@ -4556,183 +4413,163 @@ nsHTMLEditRules::CreateStyleForInsertText(Selection* aSelection, if (relFontSize) { // dir indicated bigger versus smaller. 1 = bigger, -1 = smaller - int32_t dir = relFontSize > 0 ? 1 : -1; + nsHTMLEditor::FontSize dir = relFontSize > 0 ? + nsHTMLEditor::FontSize::incr : nsHTMLEditor::FontSize::decr; for (int32_t j = 0; j < DeprecatedAbs(relFontSize); j++) { NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->RelativeFontChangeOnTextNode(dir, nodeAsText, - 0, -1); + res = mHTMLEditor->RelativeFontChangeOnTextNode(dir, newNode, 0, -1); NS_ENSURE_SUCCESS(res, res); } } while (item) { NS_ENSURE_STATE(mHTMLEditor); - nsCOMPtr content = do_QueryInterface(node); - NS_ENSURE_STATE(content || !node); - res = mHTMLEditor->SetInlinePropertyOnNode(*content, *item->tag, - &item->attr, item->value); + res = mHTMLEditor->SetInlinePropertyOnNode(*node->AsContent(), + *item->tag, &item->attr, + item->value); NS_ENSURE_SUCCESS(res, res); item = mHTMLEditor->mTypeInState->TakeSetProperty(); } } if (weDidSomething) { - return aSelection->Collapse(node, offset); + return aSelection.Collapse(node, offset); } return NS_OK; } -/////////////////////////////////////////////////////////////////////////// -// IsEmptyBlock: figure out if aNode is (or is inside) an empty block. -// A block can have children and still be considered empty, -// if the children are empty or non-editable. -// +/** + * Figure out if aNode is (or is inside) an empty block. A block can have + * children and still be considered empty, if the children are empty or + * non-editable. + */ nsresult -nsHTMLEditRules::IsEmptyBlock(nsIDOMNode *aNode, - bool *outIsEmptyBlock, - bool aMozBRDoesntCount, - bool aListItemsNotEmpty) +nsHTMLEditRules::IsEmptyBlock(Element& aNode, + bool* aOutIsEmptyBlock, + MozBRCounts aMozBRCounts) { - NS_ENSURE_TRUE(aNode && outIsEmptyBlock, NS_ERROR_NULL_POINTER); - *outIsEmptyBlock = true; + MOZ_ASSERT(aOutIsEmptyBlock); + *aOutIsEmptyBlock = true; -// nsresult res = NS_OK; - nsCOMPtr nodeToTest; - if (IsBlockNode(aNode)) nodeToTest = do_QueryInterface(aNode); -// else nsCOMPtr block; -// looks like I forgot to finish this. Wonder what I was going to do? + NS_ENSURE_TRUE(IsBlockNode(aNode), NS_ERROR_NULL_POINTER); - NS_ENSURE_TRUE(nodeToTest, NS_ERROR_NULL_POINTER); - return mHTMLEditor->IsEmptyNode(nodeToTest, outIsEmptyBlock, - aMozBRDoesntCount, aListItemsNotEmpty); + return mHTMLEditor->IsEmptyNode(aNode.AsDOMNode(), aOutIsEmptyBlock, + aMozBRCounts == MozBRCounts::yes ? false + : true); } nsresult -nsHTMLEditRules::WillAlign(Selection* aSelection, - const nsAString *alignType, - bool *aCancel, - bool *aHandled) +nsHTMLEditRules::WillAlign(Selection& aSelection, + const nsAString& aAlignType, + bool* aCancel, + bool* aHandled) { - if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; } + MOZ_ASSERT(aCancel && aHandled); - nsresult res = WillInsert(aSelection, aCancel); - NS_ENSURE_SUCCESS(res, res); + NS_ENSURE_STATE(mHTMLEditor); + nsCOMPtr kungFuDeathGrip(mHTMLEditor); - // initialize out param - // we want to ignore result of WillInsert() + WillInsert(aSelection, aCancel); + + // Initialize out param. We want to ignore result of WillInsert(). *aCancel = false; *aHandled = false; - res = NormalizeSelection(aSelection); - NS_ENSURE_SUCCESS(res, res); - nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor); + nsresult rv = NormalizeSelection(&aSelection); + NS_ENSURE_SUCCESS(rv, rv); + nsAutoSelectionReset selectionResetter(&aSelection, mHTMLEditor); - // convert the selection ranges into "promoted" selection ranges: - // this basically just expands the range to include the immediate - // block parent, and then further expands to include any ancestors - // whose children are all in the range + // Convert the selection ranges into "promoted" selection ranges: This + // basically just expands the range to include the immediate block parent, + // and then further expands to include any ancestors whose children are all + // in the range *aHandled = true; nsTArray> nodeArray; - res = GetNodesFromSelection(*aSelection, EditAction::align, nodeArray); - NS_ENSURE_SUCCESS(res, res); + rv = GetNodesFromSelection(aSelection, EditAction::align, nodeArray); + NS_ENSURE_SUCCESS(rv, rv); - // if we don't have any nodes, or we have only a single br, then we are - // creating an empty alignment div. We have to do some different things for these. - bool emptyDiv = false; - int32_t listCount = nodeArray.Length(); - if (!listCount) emptyDiv = true; - if (listCount == 1) - { - OwningNonNull theNode = nodeArray[0]; + // If we don't have any nodes, or we have only a single br, then we are + // creating an empty alignment div. We have to do some different things for + // these. + bool emptyDiv = nodeArray.IsEmpty(); + if (nodeArray.Length() == 1) { + OwningNonNull node = nodeArray[0]; - if (nsHTMLEditUtils::SupportsAlignAttr(GetAsDOMNode(theNode))) { - // the node is a table element, an horiz rule, a paragraph, a div - // or a section header; in HTML 4, it can directly carry the ALIGN - // attribute and we don't need to make a div! If we are in CSS mode, - // all the work is done in AlignBlock - nsCOMPtr theElem = do_QueryInterface(theNode); - res = AlignBlock(theElem, alignType, true); - NS_ENSURE_SUCCESS(res, res); + if (nsHTMLEditUtils::SupportsAlignAttr(GetAsDOMNode(node))) { + // The node is a table element, an hr, a paragraph, a div or a section + // header; in HTML 4, it can directly carry the ALIGN attribute and we + // don't need to make a div! If we are in CSS mode, all the work is done + // in AlignBlock + rv = AlignBlock(*node->AsElement(), aAlignType, ContentsOnly::yes); + NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } - if (nsTextEditUtils::IsBreak(theNode)) - { - // The special case emptyDiv code (below) that consumes BRs can - // cause tables to split if the start node of the selection is - // not in a table cell or caption, for example parent is a . - // Avoid this unnecessary splitting if possible by leaving emptyDiv - // FALSE so that we fall through to the normal case alignment code. + if (nsTextEditUtils::IsBreak(node)) { + // The special case emptyDiv code (below) that consumes BRs can cause + // tables to split if the start node of the selection is not in a table + // cell or caption, for example parent is a . Avoid this unnecessary + // splitting if possible by leaving emptyDiv FALSE so that we fall + // through to the normal case alignment code. // - // XXX: It seems a little error prone for the emptyDiv special - // case code to assume that the start node of the selection - // is the parent of the single node in the nodeArray, as - // the paragraph above points out. Do we rely on the selection - // start node because of the fact that nodeArray can be empty? - // We should probably revisit this issue. - kin + // XXX: It seems a little error prone for the emptyDiv special case code + // to assume that the start node of the selection is the parent of the + // single node in the nodeArray, as the paragraph above points out. Do we + // rely on the selection start node because of the fact that nodeArray + // can be empty? We should probably revisit this issue. - kin - nsCOMPtr parent; - int32_t offset; - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(parent), &offset); + NS_ENSURE_STATE(aSelection.GetRangeAt(0) && + aSelection.GetRangeAt(0)->GetStartParent()); + OwningNonNull parent = + *aSelection.GetRangeAt(0)->GetStartParent(); - if (!nsHTMLEditUtils::IsTableElement(parent) || nsHTMLEditUtils::IsTableCellOrCaption(parent)) - emptyDiv = true; + emptyDiv = !nsHTMLEditUtils::IsTableElement(parent) || + nsHTMLEditUtils::IsTableCellOrCaption(parent); } } - if (emptyDiv) - { - nsCOMPtr brNode, sib; - NS_NAMED_LITERAL_STRING(divType, "div"); - - NS_ENSURE_STATE(aSelection->GetRangeAt(0)); - nsCOMPtr parent = aSelection->GetRangeAt(0)->GetStartParent(); - int32_t offset = aSelection->GetRangeAt(0)->StartOffset(); + if (emptyDiv) { + nsCOMPtr parent = + aSelection.GetRangeAt(0) ? aSelection.GetRangeAt(0)->GetStartParent() + : nullptr; NS_ENSURE_STATE(parent); + int32_t offset = aSelection.GetRangeAt(0)->StartOffset(); - res = SplitAsNeeded(*nsGkAtoms::div, parent, offset); - NS_ENSURE_SUCCESS(res, res); - // consume a trailing br, if any. This is to keep an alignment from + rv = SplitAsNeeded(*nsGkAtoms::div, parent, offset); + NS_ENSURE_SUCCESS(rv, rv); + // Consume a trailing br, if any. This is to keep an alignment from // creating extra lines, if possible. - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->GetNextHTMLNode(GetAsDOMNode(parent), offset, - address_of(brNode)); - NS_ENSURE_SUCCESS(res, res); - if (brNode && nsTextEditUtils::IsBreak(brNode)) - { - // making use of html structure... if next node after where - // we are putting our div is not a block, then the br we - // found is in same block we are, so its safe to consume it. - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->GetNextHTMLSibling(GetAsDOMNode(parent), offset, - address_of(sib)); - NS_ENSURE_SUCCESS(res, res); - if (!IsBlockNode(sib)) - { - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->DeleteNode(brNode); - NS_ENSURE_SUCCESS(res, res); + nsCOMPtr brContent = + mHTMLEditor->GetNextHTMLNode(parent, offset); + if (brContent && nsTextEditUtils::IsBreak(brContent)) { + // Making use of html structure... if next node after where we are + // putting our div is not a block, then the br we found is in same block + // we are, so it's safe to consume it. + nsCOMPtr sibling = mHTMLEditor->GetNextHTMLSibling(parent, + offset); + if (sibling && !IsBlockNode(*sibling)) { + rv = mHTMLEditor->DeleteNode(brContent); + NS_ENSURE_SUCCESS(rv, rv); } } - NS_ENSURE_STATE(mHTMLEditor); - nsCOMPtr theDiv = mHTMLEditor->CreateNode(nsGkAtoms::div, parent, - offset); - NS_ENSURE_STATE(theDiv); - // remember our new block for postprocessing - mNewBlock = GetAsDOMNode(theDiv); - // set up the alignment on the div, using HTML or CSS - nsCOMPtr divElem = do_QueryInterface(theDiv); - res = AlignBlock(divElem, alignType, true); - NS_ENSURE_SUCCESS(res, res); + nsCOMPtr div = mHTMLEditor->CreateNode(nsGkAtoms::div, parent, + offset); + NS_ENSURE_STATE(div); + // Remember our new block for postprocessing + mNewBlock = div; + // Set up the alignment on the div, using HTML or CSS + rv = AlignBlock(*div, aAlignType, ContentsOnly::yes); + NS_ENSURE_SUCCESS(rv, rv); *aHandled = true; - // put in a moz-br so that it won't get deleted - res = CreateMozBR(GetAsDOMNode(theDiv), 0); - NS_ENSURE_SUCCESS(res, res); - res = aSelection->Collapse(theDiv, 0); - selectionResetter.Abort(); // don't reset our selection in this case. - return res; + // Put in a moz-br so that it won't get deleted + rv = CreateMozBR(div->AsDOMNode(), 0); + NS_ENSURE_SUCCESS(rv, rv); + rv = aSelection.Collapse(div, 0); + // Don't reset our selection in this case. + selectionResetter.Abort(); + NS_ENSURE_SUCCESS(rv, rv); + return NS_OK; } // Next we detect all the transitions in the array, where a transition @@ -4741,109 +4578,97 @@ nsHTMLEditRules::WillAlign(Selection* aSelection, nsTArray transitionList; MakeTransitionList(nodeArray, transitionList); - // Ok, now go through all the nodes and give them an align attrib or put them in a div, - // or whatever is appropriate. Wohoo! + // Okay, now go through all the nodes and give them an align attrib or put + // them in a div, or whatever is appropriate. Woohoo! - nsCOMPtr curParent; nsCOMPtr curDiv; bool useCSS = mHTMLEditor->IsCSSEnabled(); - for (int32_t i = 0; i < listCount; ++i) { - // here's where we actually figure out what to do - nsCOMPtr curNode = nodeArray[i]->AsDOMNode(); - nsCOMPtr curContent = do_QueryInterface(curNode); - NS_ENSURE_STATE(curContent); + for (size_t i = 0; i < nodeArray.Length(); i++) { + auto& curNode = nodeArray[i]; + // Here's where we actually figure out what to do // Ignore all non-editable nodes. Leave them be. - if (!mHTMLEditor->IsEditable(curNode)) continue; - - curParent = curContent->GetParentNode(); - int32_t offset = curParent ? curParent->IndexOf(curContent) : -1; - - // the node is a table element, an horiz rule, a paragraph, a div - // or a section header; in HTML 4, it can directly carry the ALIGN - // attribute and we don't need to nest it, just set the alignment. - // In CSS, assign the corresponding CSS styles in AlignBlock - if (nsHTMLEditUtils::SupportsAlignAttr(curNode)) - { - nsCOMPtr curElem = do_QueryInterface(curNode); - res = AlignBlock(curElem, alignType, false); - NS_ENSURE_SUCCESS(res, res); - // clear out curDiv so that we don't put nodes after this one into it - curDiv = 0; + if (!mHTMLEditor->IsEditable(curNode)) { continue; } - // Skip insignificant formatting text nodes to prevent - // unnecessary structure splitting! + // The node is a table element, an hr, a paragraph, a div or a section + // header; in HTML 4, it can directly carry the ALIGN attribute and we + // don't need to nest it, just set the alignment. In CSS, assign the + // corresponding CSS styles in AlignBlock + if (nsHTMLEditUtils::SupportsAlignAttr(GetAsDOMNode(curNode))) { + rv = AlignBlock(*curNode->AsElement(), aAlignType, ContentsOnly::no); + NS_ENSURE_SUCCESS(rv, rv); + // Clear out curDiv so that we don't put nodes after this one into it + curDiv = nullptr; + continue; + } + + nsCOMPtr curParent = curNode->GetParentNode(); + int32_t offset = curParent ? curParent->IndexOf(curNode) : -1; + + // Skip insignificant formatting text nodes to prevent unnecessary + // structure splitting! bool isEmptyTextNode = false; - if (nsEditor::IsTextNode(curNode) && - ((nsHTMLEditUtils::IsTableElement(curParent) && - !nsHTMLEditUtils::IsTableCellOrCaption(GetAsDOMNode(curParent))) || - nsHTMLEditUtils::IsList(curParent) || - (NS_SUCCEEDED(mHTMLEditor->IsEmptyNode(curNode, &isEmptyTextNode)) && isEmptyTextNode))) + if (curNode->GetAsText() && + ((nsHTMLEditUtils::IsTableElement(curParent) && + !nsHTMLEditUtils::IsTableCellOrCaption(*curParent)) || + nsHTMLEditUtils::IsList(curParent) || + (NS_SUCCEEDED(mHTMLEditor->IsEmptyNode(curNode, &isEmptyTextNode)) && + isEmptyTextNode))) { continue; - - // if it's a list item, or a list - // inside a list, forget any "current" div, and instead put divs inside - // the appropriate block (td, li, etc) - if ( nsHTMLEditUtils::IsListItem(curNode) - || nsHTMLEditUtils::IsList(curNode)) - { - res = RemoveAlignment(curNode, *alignType, true); - NS_ENSURE_SUCCESS(res, res); - if (useCSS) { - nsCOMPtr curElem = do_QueryInterface(curNode); - NS_NAMED_LITERAL_STRING(attrName, "align"); - int32_t count; - mHTMLEditor->mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(curNode, nullptr, - &attrName, alignType, - &count, false); - curDiv = 0; - continue; - } - else if (nsHTMLEditUtils::IsList(curParent)) { - // if we don't use CSS, add a contraint to list element : they have - // to be inside another list, ie >= second level of nesting - res = AlignInnerBlocks(*curContent, alignType); - NS_ENSURE_SUCCESS(res, res); - curDiv = 0; - continue; - } - // clear out curDiv so that we don't put nodes after this one into it } - // need to make a div to put things in if we haven't already, - // or if this node doesn't go in div we used earlier. - if (!curDiv || transitionList[i]) - { + // If it's a list item, or a list inside a list, forget any "current" div, + // and instead put divs inside the appropriate block (td, li, etc) + if (nsHTMLEditUtils::IsListItem(curNode) || + nsHTMLEditUtils::IsList(curNode)) { + rv = RemoveAlignment(GetAsDOMNode(curNode), aAlignType, true); + NS_ENSURE_SUCCESS(rv, rv); + if (useCSS) { + mHTMLEditor->mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle( + curNode->AsElement(), nullptr, &NS_LITERAL_STRING("align"), + &aAlignType, false); + curDiv = nullptr; + continue; + } else if (nsHTMLEditUtils::IsList(curParent)) { + // If we don't use CSS, add a contraint to list element: they have to + // be inside another list, i.e., >= second level of nesting + rv = AlignInnerBlocks(*curNode, &aAlignType); + NS_ENSURE_SUCCESS(rv, rv); + curDiv = nullptr; + continue; + } + // Clear out curDiv so that we don't put nodes after this one into it + } + + // Need to make a div to put things in if we haven't already, or if this + // node doesn't go in div we used earlier. + if (!curDiv || transitionList[i]) { // First, check that our element can contain a div. if (!mEditor->CanContainTag(*curParent, *nsGkAtoms::div)) { - return NS_OK; // cancelled + // Cancelled + return NS_OK; } - res = SplitAsNeeded(*nsGkAtoms::div, curParent, offset); - NS_ENSURE_SUCCESS(res, res); - NS_ENSURE_STATE(mHTMLEditor); + rv = SplitAsNeeded(*nsGkAtoms::div, curParent, offset); + NS_ENSURE_SUCCESS(rv, rv); curDiv = mHTMLEditor->CreateNode(nsGkAtoms::div, curParent, offset); NS_ENSURE_STATE(curDiv); - // remember our new block for postprocessing - mNewBlock = GetAsDOMNode(curDiv); - // set up the alignment on the div - nsCOMPtr divElem = do_QueryInterface(curDiv); - res = AlignBlock(divElem, alignType, true); - //nsAutoString attr(NS_LITERAL_STRING("align")); - //res = mHTMLEditor->SetAttribute(divElem, attr, *alignType); - //NS_ENSURE_SUCCESS(res, res); - // curDiv is now the correct thing to put curNode in + // Remember our new block for postprocessing + mNewBlock = curDiv; + // Set up the alignment on the div + rv = AlignBlock(*curDiv, aAlignType, ContentsOnly::yes); } - // tuck the node into the end of the active div - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->MoveNode(curContent, curDiv, -1); - NS_ENSURE_SUCCESS(res, res); + NS_ENSURE_STATE(curNode->IsContent()); + + // Tuck the node into the end of the active div + rv = mHTMLEditor->MoveNode(curNode->AsContent(), curDiv, -1); + NS_ENSURE_SUCCESS(rv, rv); } - return res; + return NS_OK; } @@ -4950,7 +4775,7 @@ nsHTMLEditRules::CheckForEmptyBlock(nsINode* aStartNode, bool* aHandled) { // If the editing host is an inline element, bail out early. - if (IsInlineNode(GetAsDOMNode(aBodyNode))) { + if (aBodyNode && IsInlineNode(*aBodyNode)) { return NS_OK; } NS_ENSURE_STATE(mHTMLEditor); @@ -5042,55 +4867,39 @@ nsHTMLEditRules::CheckForEmptyBlock(nsINode* aStartNode, return NS_OK; } -nsresult -nsHTMLEditRules::CheckForInvisibleBR(nsIDOMNode *aBlock, - BRLocation aWhere, - nsCOMPtr *outBRNode, +Element* +nsHTMLEditRules::CheckForInvisibleBR(Element& aBlock, BRLocation aWhere, int32_t aOffset) { - nsCOMPtr block = do_QueryInterface(aBlock); - NS_ENSURE_TRUE(block && outBRNode, NS_ERROR_NULL_POINTER); - *outBRNode = nullptr; - - nsCOMPtr testNode; + nsCOMPtr testNode; int32_t testOffset = 0; - bool runTest = false; - if (aWhere == kBlockEnd) - { - nsCOMPtr rightmostNode = - // no block crossing - GetAsDOMNode(mHTMLEditor->GetRightmostChild(block, true)); + if (aWhere == BRLocation::blockEnd) { + // No block crossing + nsCOMPtr rightmostNode = + mHTMLEditor->GetRightmostChild(&aBlock, true); - if (rightmostNode) - { - int32_t nodeOffset; - nsCOMPtr nodeParent = nsEditor::GetNodeLocation(rightmostNode, - &nodeOffset); - runTest = true; - testNode = nodeParent; - // use offset + 1, because we want the last node included in our - // evaluation - testOffset = nodeOffset + 1; + if (!rightmostNode) { + return nullptr; } - } - else if (aOffset) - { - runTest = true; - testNode = aBlock; - // we'll check everything to the left of the input position + + testNode = rightmostNode->GetParentNode(); + // Use offset + 1, so last node is included in our evaluation + testOffset = testNode->IndexOf(rightmostNode) + 1; + } else if (aOffset) { + testNode = &aBlock; + // We'll check everything to the left of the input position testOffset = aOffset; + } else { + return nullptr; } - if (runTest) - { - nsWSRunObject wsTester(mHTMLEditor, testNode, testOffset); - if (WSType::br == wsTester.mStartReason) { - *outBRNode = GetAsDOMNode(wsTester.mStartReasonNode); - } + nsWSRunObject wsTester(mHTMLEditor, testNode, testOffset); + if (WSType::br == wsTester.mStartReason) { + return wsTester.mStartReasonNode->AsElement(); } - return NS_OK; + return nullptr; } @@ -5122,180 +4931,138 @@ nsHTMLEditRules::GetInnerContent(nsINode& aNode, } } -/////////////////////////////////////////////////////////////////////////// -// ExpandSelectionForDeletion: this promotes our selection to include blocks -// that have all their children selected. -// +/** + * Promotes selection to include blocks that have all their children selected. + */ nsresult -nsHTMLEditRules::ExpandSelectionForDeletion(Selection* aSelection) +nsHTMLEditRules::ExpandSelectionForDeletion(Selection& aSelection) { - NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER); - - // don't need to touch collapsed selections - if (aSelection->Collapsed()) { + // Don't need to touch collapsed selections + if (aSelection.Collapsed()) { return NS_OK; } - int32_t rangeCount; - nsresult res = aSelection->GetRangeCount(&rangeCount); - NS_ENSURE_SUCCESS(res, res); + // We don't need to mess with cell selections, and we assume multirange + // selections are those. + if (aSelection.RangeCount() != 1) { + return NS_OK; + } - // we don't need to mess with cell selections, and we assume multirange selections are those. - if (rangeCount != 1) return NS_OK; + // Find current sel start and end + NS_ENSURE_TRUE(aSelection.GetRangeAt(0), NS_ERROR_NULL_POINTER); + OwningNonNull range = *aSelection.GetRangeAt(0); - // find current sel start and end - RefPtr range = aSelection->GetRangeAt(0); - NS_ENSURE_TRUE(range, NS_ERROR_NULL_POINTER); - nsCOMPtr selStartNode, selEndNode, selCommon; - int32_t selStartOffset, selEndOffset; + nsCOMPtr selStartNode = range->GetStartParent(); + int32_t selStartOffset = range->StartOffset(); + nsCOMPtr selEndNode = range->GetEndParent(); + int32_t selEndOffset = range->EndOffset(); - res = range->GetStartContainer(getter_AddRefs(selStartNode)); - NS_ENSURE_SUCCESS(res, res); - res = range->GetStartOffset(&selStartOffset); - NS_ENSURE_SUCCESS(res, res); - res = range->GetEndContainer(getter_AddRefs(selEndNode)); - NS_ENSURE_SUCCESS(res, res); - res = range->GetEndOffset(&selEndOffset); - NS_ENSURE_SUCCESS(res, res); - - // find current selection common block parent - res = range->GetCommonAncestorContainer(getter_AddRefs(selCommon)); - NS_ENSURE_SUCCESS(res, res); - if (!IsBlockNode(selCommon)) - selCommon = nsHTMLEditor::GetBlockNodeParent(selCommon); + // Find current selection common block parent + nsCOMPtr selCommon = + nsHTMLEditor::GetBlock(*range->GetCommonAncestor()); NS_ENSURE_STATE(selCommon); - // set up for loops and cache our root element - bool stillLooking = true; - nsCOMPtr firstBRParent; + // Set up for loops and cache our root element + nsCOMPtr firstBRParent; nsCOMPtr unused; - int32_t visOffset=0, firstBROffset=0; + int32_t visOffset = 0, firstBROffset = 0; WSType wsType; - nsCOMPtr rootContent = mHTMLEditor->GetActiveEditingHost(); - nsCOMPtr rootElement = do_QueryInterface(rootContent); - NS_ENSURE_TRUE(rootElement, NS_ERROR_FAILURE); + nsCOMPtr root = mHTMLEditor->GetActiveEditingHost(); + NS_ENSURE_TRUE(root, NS_ERROR_FAILURE); - // find previous visible thingy before start of selection - if ((selStartNode!=selCommon) && (selStartNode!=rootElement)) - { - while (stillLooking) - { + // Find previous visible thingy before start of selection + if (selStartNode != selCommon && selStartNode != root) { + while (true) { nsWSRunObject wsObj(mHTMLEditor, selStartNode, selStartOffset); - nsCOMPtr selStartNode_(do_QueryInterface(selStartNode)); - wsObj.PriorVisibleNode(selStartNode_, selStartOffset, address_of(unused), + wsObj.PriorVisibleNode(selStartNode, selStartOffset, address_of(unused), &visOffset, &wsType); - if (wsType == WSType::thisBlock) { - // we want to keep looking up. But stop if we are crossing table element - // boundaries, or if we hit the root. - if (nsHTMLEditUtils::IsTableElement(wsObj.mStartReasonNode) || - selCommon == GetAsDOMNode(wsObj.mStartReasonNode) || - rootElement == GetAsDOMNode(wsObj.mStartReasonNode)) { - stillLooking = false; - } - else - { - selStartNode = nsEditor::GetNodeLocation(GetAsDOMNode(wsObj.mStartReasonNode), - &selStartOffset); - } + if (wsType != WSType::thisBlock) { + break; } - else - { - stillLooking = false; + // We want to keep looking up. But stop if we are crossing table + // element boundaries, or if we hit the root. + if (nsHTMLEditUtils::IsTableElement(wsObj.mStartReasonNode) || + selCommon == wsObj.mStartReasonNode || + root == wsObj.mStartReasonNode) { + break; } + selStartNode = wsObj.mStartReasonNode->GetParentNode(); + selStartOffset = selStartNode ? + selStartNode->IndexOf(wsObj.mStartReasonNode) : -1; } } - stillLooking = true; - // find next visible thingy after end of selection - if ((selEndNode!=selCommon) && (selEndNode!=rootElement)) - { - while (stillLooking) - { + // Find next visible thingy after end of selection + if (selEndNode != selCommon && selEndNode != root) { + while (true) { nsWSRunObject wsObj(mHTMLEditor, selEndNode, selEndOffset); - nsCOMPtr selEndNode_(do_QueryInterface(selEndNode)); - wsObj.NextVisibleNode(selEndNode_, selEndOffset, address_of(unused), + wsObj.NextVisibleNode(selEndNode, selEndOffset, address_of(unused), &visOffset, &wsType); if (wsType == WSType::br) { - if (mHTMLEditor->IsVisBreak(wsObj.mEndReasonNode)) - { - stillLooking = false; + if (mHTMLEditor->IsVisBreak(wsObj.mEndReasonNode)) { + break; } - else - { - if (!firstBRParent) - { - firstBRParent = selEndNode; - firstBROffset = selEndOffset; - } - selEndNode = nsEditor::GetNodeLocation(GetAsDOMNode(wsObj.mEndReasonNode), &selEndOffset); - ++selEndOffset; + if (!firstBRParent) { + firstBRParent = selEndNode; + firstBROffset = selEndOffset; } + selEndNode = wsObj.mEndReasonNode->GetParentNode(); + selEndOffset = selEndNode + ? selEndNode->IndexOf(wsObj.mEndReasonNode) + 1 : 0; } else if (wsType == WSType::thisBlock) { - // we want to keep looking up. But stop if we are crossing table element - // boundaries, or if we hit the root. + // We want to keep looking up. But stop if we are crossing table + // element boundaries, or if we hit the root. if (nsHTMLEditUtils::IsTableElement(wsObj.mEndReasonNode) || - selCommon == GetAsDOMNode(wsObj.mEndReasonNode) || - rootElement == GetAsDOMNode(wsObj.mEndReasonNode)) { - stillLooking = false; + selCommon == wsObj.mEndReasonNode || + root == wsObj.mEndReasonNode) { + break; } - else - { - selEndNode = nsEditor::GetNodeLocation(GetAsDOMNode(wsObj.mEndReasonNode), &selEndOffset); - ++selEndOffset; - } - } - else - { - stillLooking = false; + selEndNode = wsObj.mEndReasonNode->GetParentNode(); + selEndOffset = 1 + selEndNode->IndexOf(wsObj.mEndReasonNode); + } else { + break; } } } - // now set the selection to the new range - aSelection->Collapse(selStartNode, selStartOffset); + // Now set the selection to the new range + aSelection.Collapse(selStartNode, selStartOffset); - // expand selection endpoint only if we didnt pass a br, - // or if we really needed to pass that br (ie, its block is now - // totally selected) + // Expand selection endpoint only if we didn't pass a br, or if we really + // needed to pass that br (i.e., its block is now totally selected) + nsresult res; bool doEndExpansion = true; - if (firstBRParent) - { - // find block node containing br - nsCOMPtr brBlock = firstBRParent; - if (!IsBlockNode(brBlock)) - brBlock = nsHTMLEditor::GetBlockNodeParent(brBlock); - bool nodeBefore=false, nodeAfter=false; + if (firstBRParent) { + // Find block node containing br + nsCOMPtr brBlock = nsHTMLEditor::GetBlock(*firstBRParent); + bool nodeBefore = false, nodeAfter = false; - // create a range that represents expanded selection - nsCOMPtr node = do_QueryInterface(selStartNode); - NS_ENSURE_STATE(node); - RefPtr range = new nsRange(node); + // Create a range that represents expanded selection + RefPtr range = new nsRange(selStartNode); res = range->SetStart(selStartNode, selStartOffset); NS_ENSURE_SUCCESS(res, res); res = range->SetEnd(selEndNode, selEndOffset); NS_ENSURE_SUCCESS(res, res); - // check if block is entirely inside range - nsCOMPtr brContentBlock = do_QueryInterface(brBlock); - if (brContentBlock) { - res = nsRange::CompareNodeToRange(brContentBlock, range, &nodeBefore, - &nodeAfter); + // Check if block is entirely inside range + if (brBlock) { + nsRange::CompareNodeToRange(brBlock, range, &nodeBefore, &nodeAfter); } - // if block isn't contained, forgo grabbing the br in the expanded selection - if (nodeBefore || nodeAfter) + // If block isn't contained, forgo grabbing the br in expanded selection + if (nodeBefore || nodeAfter) { doEndExpansion = false; + } } - if (doEndExpansion) - { - res = aSelection->Extend(selEndNode, selEndOffset); - } - else - { - // only expand to just before br - res = aSelection->Extend(firstBRParent, firstBROffset); + if (doEndExpansion) { + res = aSelection.Extend(selEndNode, selEndOffset); + NS_ENSURE_SUCCESS(res, res); + } else { + // Only expand to just before br + res = aSelection.Extend(firstBRParent, firstBROffset); + NS_ENSURE_SUCCESS(res, res); } - return res; + return NS_OK; } @@ -5527,8 +5294,8 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode* aNode, mHTMLEditor->GetPriorHTMLNode(node, offset, true); while (priorNode && priorNode->GetParentNode() && - mHTMLEditor && !mHTMLEditor->IsVisBreak(priorNode->AsDOMNode()) && - !IsBlockNode(priorNode->AsDOMNode())) { + mHTMLEditor && !mHTMLEditor->IsVisBreak(priorNode) && + !IsBlockNode(*priorNode)) { offset = priorNode->GetParentNode()->IndexOf(priorNode); node = priorNode->GetParentNode(); NS_ENSURE_TRUE(mHTMLEditor, /* void */); @@ -5599,14 +5366,34 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode* aNode, nsCOMPtr nextNode = mHTMLEditor->GetNextHTMLNode(node, offset, true); - while (nextNode && !IsBlockNode(nextNode->AsDOMNode()) && - nextNode->GetParentNode()) { + while (nextNode && !IsBlockNode(*nextNode) && nextNode->GetParentNode()) { offset = 1 + nextNode->GetParentNode()->IndexOf(nextNode); node = nextNode->GetParentNode(); NS_ENSURE_TRUE(mHTMLEditor, /* void */); - if (mHTMLEditor->IsVisBreak(nextNode->AsDOMNode())) { + if (mHTMLEditor->IsVisBreak(nextNode)) { break; } + + // Check for newlines in pre-formatted text nodes. + bool isPRE; + mHTMLEditor->IsPreformatted(nextNode->AsDOMNode(), &isPRE); + if (isPRE) { + nsCOMPtr textNode = do_QueryInterface(nextNode); + if (textNode) { + nsAutoString tempString; + textNode->GetData(tempString); + int32_t newlinePos = tempString.FindChar(nsCRT::LF); + if (newlinePos >= 0) { + if ((uint32_t)newlinePos + 1 == tempString.Length()) { + // No need for special processing if the newline is at the end. + break; + } + *outNode = nextNode->AsDOMNode(); + *outOffset = newlinePos + 1; + return; + } + } + } NS_ENSURE_TRUE(mHTMLEditor, /* void */); nextNode = mHTMLEditor->GetNextHTMLNode(node, offset, true); } @@ -5769,6 +5556,38 @@ nsHTMLEditRules::GetNodesForOperation(nsTArray>& aArrayOfRanges, int32_t rangeCount = aArrayOfRanges.Length(); nsresult res = NS_OK; + if (aTouchContent == TouchContent::yes) { + // Split text nodes. This is necessary, since GetPromotedPoint() may return a + // range ending in a text node in case where part of a pre-formatted + // elements needs to be moved. + for (int32_t i = 0; i < rangeCount; i++) { + RefPtr r = aArrayOfRanges[i]; + nsCOMPtr endParent = do_QueryInterface(r->GetEndParent()); + if (!mHTMLEditor->IsTextNode(endParent)) { + continue; + } + nsCOMPtr textNode = do_QueryInterface(endParent); + if (textNode) { + int32_t offset = r->EndOffset(); + nsAutoString tempString; + textNode->GetData(tempString); + + if (0 < offset && offset < (int32_t)(tempString.Length())) { + // Split the text node. + nsCOMPtr tempNode; + res = mHTMLEditor->SplitNode(endParent->AsDOMNode(), offset, + getter_AddRefs(tempNode)); + NS_ENSURE_SUCCESS(res, res); + + // Correct the range. + // The new end parent becomes the parent node of the text. + nsCOMPtr newParent = endParent->GetParent(); + r->SetEnd(newParent, newParent->IndexOf(endParent)); + } + } + } + } + // Bust up any inlines that cross our range endpoints, but only if we are // allowed to touch content. @@ -5863,9 +5682,8 @@ nsHTMLEditRules::GetNodesForOperation(nsTArray>& aArrayOfRanges, aOperationType == EditAction::outdent) { for (int32_t i = aOutArrayOfNodes.Length() - 1; i >= 0; i--) { OwningNonNull node = aOutArrayOfNodes[i]; - if (aTouchContent == TouchContent::yes && - IsInlineNode(GetAsDOMNode(node)) && mHTMLEditor->IsContainer(node) && - !mHTMLEditor->IsTextNode(node)) { + if (aTouchContent == TouchContent::yes && IsInlineNode(node) && + mHTMLEditor->IsContainer(node) && !mHTMLEditor->IsTextNode(node)) { nsTArray> arrayOfInlines; res = BustUpInlinesAtBRs(*node->AsContent(), arrayOfInlines); NS_ENSURE_SUCCESS(res, res); @@ -6081,8 +5899,7 @@ nsHTMLEditRules::BustUpInlinesAtRangeEndpoints(nsRangeStore &item) { bool isCollapsed = ((item.startNode == item.endNode) && (item.startOffset == item.endOffset)); - nsCOMPtr endInline = - do_QueryInterface(GetHighestInlineParent(GetAsDOMNode(item.endNode))); + nsCOMPtr endInline = GetHighestInlineParent(*item.endNode); // if we have inline parents above range endpoints, split them if (endInline && !isCollapsed) @@ -6100,8 +5917,7 @@ nsHTMLEditRules::BustUpInlinesAtRangeEndpoints(nsRangeStore &item) item.endOffset = resultEndOffset; } - nsCOMPtr startInline = - do_QueryInterface(GetHighestInlineParent(GetAsDOMNode(item.startNode))); + nsCOMPtr startInline = GetHighestInlineParent(*item.startNode); if (startInline) { @@ -6184,19 +6000,18 @@ nsHTMLEditRules::BustUpInlinesAtBRs(nsIContent& aNode, } -nsCOMPtr -nsHTMLEditRules::GetHighestInlineParent(nsIDOMNode* aNode) +nsIContent* +nsHTMLEditRules::GetHighestInlineParent(nsINode& aNode) { - NS_ENSURE_TRUE(aNode, nullptr); - if (IsBlockNode(aNode)) return nullptr; - nsCOMPtr inlineNode, node=aNode; - - while (node && IsInlineNode(node)) - { - inlineNode = node; - inlineNode->GetParentNode(getter_AddRefs(node)); + if (!aNode.IsContent() || IsBlockNode(aNode)) { + return nullptr; } - return inlineNode; + OwningNonNull node = *aNode.AsContent(); + + while (node->GetParent() && IsInlineNode(*node->GetParent())) { + node = *node->GetParent(); + } + return node; } @@ -6291,14 +6106,6 @@ nsHTMLEditRules::MakeTransitionList(nsTArray>& aNodeArray // Also stops on the active editor host (contenteditable). // Also test if aNode is an li itself. // -already_AddRefed -nsHTMLEditRules::IsInListItem(nsIDOMNode* aNode) -{ - nsCOMPtr node = do_QueryInterface(aNode); - nsCOMPtr retval = do_QueryInterface(IsInListItem(node)); - return retval.forget(); -} - Element* nsHTMLEditRules::IsInListItem(nsINode* aNode) { @@ -6319,101 +6126,85 @@ nsHTMLEditRules::IsInListItem(nsINode* aNode) } -/////////////////////////////////////////////////////////////////////////// -// ReturnInHeader: do the right thing for returns pressed in headers -// +/** + * ReturnInHeader: do the right thing for returns pressed in headers + */ nsresult -nsHTMLEditRules::ReturnInHeader(Selection* aSelection, - nsIDOMNode *aHeader, - nsIDOMNode *aNode, +nsHTMLEditRules::ReturnInHeader(Selection& aSelection, + Element& aHeader, + nsINode& aNode, int32_t aOffset) { - nsCOMPtr header = do_QueryInterface(aHeader); - nsCOMPtr node = do_QueryInterface(aNode); - NS_ENSURE_TRUE(aSelection && header && node, NS_ERROR_NULL_POINTER); - - // remeber where the header is - int32_t offset; - nsCOMPtr headerParent = nsEditor::GetNodeLocation(aHeader, &offset); - - // get ws code to adjust any ws NS_ENSURE_STATE(mHTMLEditor); + nsCOMPtr kungFuDeathGrip(mHTMLEditor); + + // Remember where the header is + nsCOMPtr headerParent = aHeader.GetParentNode(); + int32_t offset = headerParent ? headerParent->IndexOf(&aHeader) : -1; + + // Get ws code to adjust any ws + nsCOMPtr node = &aNode; nsresult res = nsWSRunObject::PrepareToSplitAcrossBlocks(mHTMLEditor, address_of(node), &aOffset); NS_ENSURE_SUCCESS(res, res); - // split the header + // Split the header NS_ENSURE_STATE(node->IsContent()); - NS_ENSURE_STATE(mHTMLEditor); - mHTMLEditor->SplitNodeDeep(*header, *node->AsContent(), aOffset); + mHTMLEditor->SplitNodeDeep(aHeader, *node->AsContent(), aOffset); - // if the leftand heading is empty, put a mozbr in it - nsCOMPtr prevItem; - NS_ENSURE_STATE(mHTMLEditor); - mHTMLEditor->GetPriorHTMLSibling(aHeader, address_of(prevItem)); - if (prevItem && nsHTMLEditUtils::IsHeader(prevItem)) - { - bool bIsEmptyNode; - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->IsEmptyNode(prevItem, &bIsEmptyNode); + // If the left-hand heading is empty, put a mozbr in it + nsCOMPtr prevItem = mHTMLEditor->GetPriorHTMLSibling(&aHeader); + if (prevItem && nsHTMLEditUtils::IsHeader(*prevItem)) { + bool isEmptyNode; + res = mHTMLEditor->IsEmptyNode(prevItem, &isEmptyNode); NS_ENSURE_SUCCESS(res, res); - if (bIsEmptyNode) { - res = CreateMozBR(prevItem, 0); + if (isEmptyNode) { + res = CreateMozBR(prevItem->AsDOMNode(), 0); NS_ENSURE_SUCCESS(res, res); } } - // if the new (righthand) header node is empty, delete it + // If the new (righthand) header node is empty, delete it bool isEmpty; - res = IsEmptyBlock(aHeader, &isEmpty, true); + res = IsEmptyBlock(aHeader, &isEmpty, MozBRCounts::no); NS_ENSURE_SUCCESS(res, res); - if (isEmpty) - { - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->DeleteNode(aHeader); + if (isEmpty) { + res = mHTMLEditor->DeleteNode(&aHeader); NS_ENSURE_SUCCESS(res, res); - // layout tells the caret to blink in a weird place - // if we don't place a break after the header. - nsCOMPtr sibling; - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->GetNextHTMLSibling(headerParent, offset+1, address_of(sibling)); - NS_ENSURE_SUCCESS(res, res); - if (!sibling || !nsTextEditUtils::IsBreak(sibling)) - { + // Layout tells the caret to blink in a weird place if we don't place a + // break after the header. + nsCOMPtr sibling = + mHTMLEditor->GetNextHTMLSibling(headerParent, offset + 1); + if (!sibling || !sibling->IsHTMLElement(nsGkAtoms::br)) { ClearCachedStyles(); - NS_ENSURE_STATE(mHTMLEditor); mHTMLEditor->mTypeInState->ClearAllProps(); - // create a paragraph - NS_NAMED_LITERAL_STRING(pType, "p"); - nsCOMPtr pNode; - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->CreateNode(pType, headerParent, offset+1, getter_AddRefs(pNode)); - NS_ENSURE_SUCCESS(res, res); + // Create a paragraph + nsCOMPtr pNode = + mHTMLEditor->CreateNode(nsGkAtoms::p, headerParent, offset + 1); + NS_ENSURE_STATE(pNode); - // append a
to it - nsCOMPtr brNode; - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->CreateBR(pNode, 0, address_of(brNode)); - NS_ENSURE_SUCCESS(res, res); + // Append a
to it + nsCOMPtr brNode = mHTMLEditor->CreateBR(pNode, 0); + NS_ENSURE_STATE(brNode); - // set selection to before the break - res = aSelection->Collapse(pNode, 0); - } - else - { - headerParent = nsEditor::GetNodeLocation(sibling, &offset); - // put selection after break - res = aSelection->Collapse(headerParent,offset+1); + // Set selection to before the break + res = aSelection.Collapse(pNode, 0); + NS_ENSURE_SUCCESS(res, res); + } else { + headerParent = sibling->GetParentNode(); + offset = headerParent ? headerParent->IndexOf(sibling) : -1; + // Put selection after break + res = aSelection.Collapse(headerParent, offset + 1); + NS_ENSURE_SUCCESS(res, res); } + } else { + // Put selection at front of righthand heading + res = aSelection.Collapse(&aHeader, 0); + NS_ENSURE_SUCCESS(res, res); } - else - { - // put selection at front of righthand heading - res = aSelection->Collapse(aHeader,0); - } - return res; + return NS_OK; } /////////////////////////////////////////////////////////////////////////// @@ -6427,7 +6218,8 @@ nsHTMLEditRules::ReturnInParagraph(Selection* aSelection, bool* aCancel, bool* aHandled) { - if (!aSelection || !aPara || !aNode || !aCancel || !aHandled) { + nsCOMPtr node = do_QueryInterface(aNode); + if (!aSelection || !aPara || !node || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; } *aCancel = false; @@ -6435,21 +6227,21 @@ nsHTMLEditRules::ReturnInParagraph(Selection* aSelection, nsresult res; int32_t offset; - nsCOMPtr parent = nsEditor::GetNodeLocation(aNode, &offset); + nsCOMPtr parent = nsEditor::GetNodeLocation(node, &offset); NS_ENSURE_STATE(mHTMLEditor); bool doesCRCreateNewP = mHTMLEditor->GetReturnInParagraphCreatesNewParagraph(); bool newBRneeded = false; bool newSelNode = false; - nsCOMPtr sibling; + nsCOMPtr sibling; nsCOMPtr selNode = aNode; int32_t selOffset = aOffset; NS_ENSURE_STATE(mHTMLEditor); if (aNode == aPara && doesCRCreateNewP) { // we are at the edges of the block, newBRneeded not needed! - sibling = aNode; + sibling = node->AsContent(); } else if (mHTMLEditor->IsTextNode(aNode)) { nsCOMPtr textNode = do_QueryInterface(aNode); uint32_t strLength; @@ -6460,9 +6252,9 @@ nsHTMLEditRules::ReturnInParagraph(Selection* aSelection, if (!aOffset) { // is there a BR prior to it? NS_ENSURE_STATE(mHTMLEditor); - mHTMLEditor->GetPriorHTMLSibling(aNode, address_of(sibling)); + sibling = mHTMLEditor->GetPriorHTMLSibling(node); if (!sibling || !mHTMLEditor || !mHTMLEditor->IsVisBreak(sibling) || - nsTextEditUtils::HasMozAttr(sibling)) { + nsTextEditUtils::HasMozAttr(GetAsDOMNode(sibling))) { NS_ENSURE_STATE(mHTMLEditor); newBRneeded = true; } @@ -6470,9 +6262,9 @@ nsHTMLEditRules::ReturnInParagraph(Selection* aSelection, // we're at the end of text node... // is there a BR after to it? NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->GetNextHTMLSibling(aNode, address_of(sibling)); + sibling = mHTMLEditor->GetNextHTMLSibling(node); if (!sibling || !mHTMLEditor || !mHTMLEditor->IsVisBreak(sibling) || - nsTextEditUtils::HasMozAttr(sibling)) { + nsTextEditUtils::HasMozAttr(GetAsDOMNode(sibling))) { NS_ENSURE_STATE(mHTMLEditor); newBRneeded = true; offset++; @@ -6491,22 +6283,20 @@ nsHTMLEditRules::ReturnInParagraph(Selection* aSelection, } else { // not in a text node. // is there a BR prior to it? - nsCOMPtr nearNode; + nsCOMPtr nearNode; NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->GetPriorHTMLNode(aNode, aOffset, address_of(nearNode)); - NS_ENSURE_SUCCESS(res, res); + nearNode = mHTMLEditor->GetPriorHTMLNode(node, aOffset); NS_ENSURE_STATE(mHTMLEditor); if (!nearNode || !mHTMLEditor->IsVisBreak(nearNode) || - nsTextEditUtils::HasMozAttr(nearNode)) { + nsTextEditUtils::HasMozAttr(GetAsDOMNode(nearNode))) { // is there a BR after it? NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->GetNextHTMLNode(aNode, aOffset, address_of(nearNode)); - NS_ENSURE_SUCCESS(res, res); + nearNode = mHTMLEditor->GetNextHTMLNode(node, aOffset); NS_ENSURE_STATE(mHTMLEditor); if (!nearNode || !mHTMLEditor->IsVisBreak(nearNode) || - nsTextEditUtils::HasMozAttr(nearNode)) { + nsTextEditUtils::HasMozAttr(GetAsDOMNode(nearNode))) { newBRneeded = true; - parent = aNode; + parent = node; offset = aOffset; newSelNode = true; } @@ -6519,13 +6309,11 @@ nsHTMLEditRules::ReturnInParagraph(Selection* aSelection, // if CR does not create a new P, default to BR creation NS_ENSURE_TRUE(doesCRCreateNewP, NS_OK); - nsCOMPtr brNode; NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->CreateBR(parent, offset, address_of(brNode)); - sibling = brNode; + sibling = mHTMLEditor->CreateBR(parent, offset); if (newSelNode) { // We split the parent after the br we've just inserted. - selNode = parent; + selNode = GetAsDOMNode(parent); selOffset = offset + 1; } } @@ -6538,7 +6326,7 @@ nsHTMLEditRules::ReturnInParagraph(Selection* aSelection, // nsresult nsHTMLEditRules::SplitParagraph(nsIDOMNode *aPara, - nsIDOMNode *aBRNode, + nsIContent* aBRNode, Selection* aSelection, nsCOMPtr *aSelNode, int32_t *aOffset) @@ -6579,9 +6367,9 @@ nsHTMLEditRules::SplitParagraph(nsIDOMNode *aPara, NS_ENSURE_SUCCESS(res, res); // check both halves of para to see if we need mozBR - res = InsertMozBRIfNeeded(GetAsDOMNode(leftPara)); + res = InsertMozBRIfNeeded(*leftPara); NS_ENSURE_SUCCESS(res, res); - res = InsertMozBRIfNeeded(GetAsDOMNode(rightPara)); + res = InsertMozBRIfNeeded(*rightPara); NS_ENSURE_SUCCESS(res, res); // selection to beginning of right hand para; @@ -6590,11 +6378,9 @@ nsHTMLEditRules::SplitParagraph(nsIDOMNode *aPara, NS_ENSURE_STATE(mHTMLEditor && rightParaNode); nsCOMPtr child = GetAsDOMNode(mHTMLEditor->GetLeftmostChild(rightParaNode, true)); - NS_ENSURE_STATE(mHTMLEditor); - if (mHTMLEditor->IsTextNode(child) || !mHTMLEditor || + if (mHTMLEditor->IsTextNode(child) || mHTMLEditor->IsContainer(child)) { - NS_ENSURE_STATE(mHTMLEditor); aSelection->Collapse(child,0); } else @@ -6607,178 +6393,160 @@ nsHTMLEditRules::SplitParagraph(nsIDOMNode *aPara, } -/////////////////////////////////////////////////////////////////////////// -// ReturnInListItem: do the right thing for returns pressed in list items -// +/** + * ReturnInListItem: do the right thing for returns pressed in list items + */ nsresult -nsHTMLEditRules::ReturnInListItem(Selection* aSelection, - nsIDOMNode *aListItem, - nsIDOMNode *aNode, +nsHTMLEditRules::ReturnInListItem(Selection& aSelection, + Element& aListItem, + nsINode& aNode, int32_t aOffset) { - nsCOMPtr listItem = do_QueryInterface(aListItem); - NS_ENSURE_TRUE(aSelection && listItem && aNode, NS_ERROR_NULL_POINTER); - nsresult res = NS_OK; + MOZ_ASSERT(nsHTMLEditUtils::IsListItem(&aListItem)); - nsCOMPtr listitem; - - // sanity check - NS_PRECONDITION(true == nsHTMLEditUtils::IsListItem(aListItem), - "expected a list item and didn't get one"); - - // get the listitem parent and the active editing host. NS_ENSURE_STATE(mHTMLEditor); - nsIContent* rootContent = mHTMLEditor->GetActiveEditingHost(); - nsCOMPtr rootNode = do_QueryInterface(rootContent); - nsCOMPtr list = listItem->GetParentNode(); - int32_t itemOffset = list ? list->IndexOf(listItem) : -1; + nsCOMPtr kungFuDeathGrip(mHTMLEditor); - // if we are in an empty listitem, then we want to pop up out of the list - // but only if prefs says it's ok and if the parent isn't the active editing host. + // Get the item parent and the active editing host. + nsCOMPtr root = mHTMLEditor->GetActiveEditingHost(); + + nsCOMPtr list = aListItem.GetParentElement(); + int32_t itemOffset = list ? list->IndexOf(&aListItem) : -1; + + // If we are in an empty item, then we want to pop up out of the list, but + // only if prefs say it's okay and if the parent isn't the active editing + // host. bool isEmpty; - res = IsEmptyBlock(aListItem, &isEmpty, true, false); + nsresult res = IsEmptyBlock(aListItem, &isEmpty, MozBRCounts::no); NS_ENSURE_SUCCESS(res, res); - if (isEmpty && (rootNode != GetAsDOMNode(list)) && - mReturnInEmptyLIKillsList) { - // get the list offset now -- before we might eventually split the list + if (isEmpty && root != list && mReturnInEmptyLIKillsList) { + // Get the list offset now -- before we might eventually split the list nsCOMPtr listParent = list->GetParentNode(); int32_t offset = listParent ? listParent->IndexOf(list) : -1; - // are we the last list item in the list? - bool bIsLast; - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->IsLastEditableChild(aListItem, &bIsLast); + // Are we the last list item in the list? + bool isLast; + res = mHTMLEditor->IsLastEditableChild(aListItem.AsDOMNode(), &isLast); NS_ENSURE_SUCCESS(res, res); - if (!bIsLast) - { - // we need to split the list! - nsCOMPtr tempNode; - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->SplitNode(GetAsDOMNode(list), itemOffset, - getter_AddRefs(tempNode)); - NS_ENSURE_SUCCESS(res, res); + if (!isLast) { + // We need to split the list! + ErrorResult rv; + mHTMLEditor->SplitNode(*list, itemOffset, rv); + NS_ENSURE_TRUE(!rv.Failed(), rv.StealNSResult()); } - // are we in a sublist? + // Are we in a sublist? if (nsHTMLEditUtils::IsList(listParent)) { - // if so, move this list item out of this list and into the grandparent list - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->MoveNode(listItem, listParent, offset + 1); + // If so, move item out of this list and into the grandparent list + res = mHTMLEditor->MoveNode(&aListItem, listParent, offset + 1); NS_ENSURE_SUCCESS(res, res); - res = aSelection->Collapse(aListItem,0); - } - else - { - // otherwise kill this listitem - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->DeleteNode(aListItem); - NS_ENSURE_SUCCESS(res, res); - - // time to insert a paragraph - NS_NAMED_LITERAL_STRING(pType, "p"); - nsCOMPtr pNode; - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->CreateNode(pType, GetAsDOMNode(listParent), - offset + 1, getter_AddRefs(pNode)); - NS_ENSURE_SUCCESS(res, res); - - // append a
to it - nsCOMPtr brNode; - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->CreateBR(pNode, 0, address_of(brNode)); - NS_ENSURE_SUCCESS(res, res); - - // set selection to before the break - res = aSelection->Collapse(pNode, 0); - } - return res; - } - - // else we want a new list item at the same list level. - // get ws code to adjust any ws - nsCOMPtr selNode(do_QueryInterface(aNode)); - NS_ENSURE_STATE(mHTMLEditor); - res = nsWSRunObject::PrepareToSplitAcrossBlocks(mHTMLEditor, address_of(selNode), &aOffset); - NS_ENSURE_SUCCESS(res, res); - // now split list item - NS_ENSURE_STATE(mHTMLEditor); - NS_ENSURE_STATE(selNode->IsContent()); - mHTMLEditor->SplitNodeDeep(*listItem, *selNode->AsContent(), aOffset); - // hack: until I can change the damaged doc range code back to being - // extra inclusive, I have to manually detect certain list items that - // may be left empty. - nsCOMPtr prevItem; - NS_ENSURE_STATE(mHTMLEditor); - mHTMLEditor->GetPriorHTMLSibling(aListItem, address_of(prevItem)); - - if (prevItem && nsHTMLEditUtils::IsListItem(prevItem)) - { - bool bIsEmptyNode; - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->IsEmptyNode(prevItem, &bIsEmptyNode); - NS_ENSURE_SUCCESS(res, res); - if (bIsEmptyNode) { - res = CreateMozBR(prevItem, 0); + res = aSelection.Collapse(&aListItem, 0); NS_ENSURE_SUCCESS(res, res); } else { - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->IsEmptyNode(aListItem, &bIsEmptyNode, true); + // Otherwise kill this item + res = mHTMLEditor->DeleteNode(&aListItem); NS_ENSURE_SUCCESS(res, res); - if (bIsEmptyNode) - { - nsCOMPtr nodeAtom = nsEditor::GetTag(aListItem); + + // Time to insert a paragraph + nsCOMPtr pNode = + mHTMLEditor->CreateNode(nsGkAtoms::p, listParent, offset + 1); + NS_ENSURE_STATE(pNode); + + // Append a
to it + nsCOMPtr brNode = mHTMLEditor->CreateBR(pNode, 0); + NS_ENSURE_STATE(brNode); + + // Set selection to before the break + res = aSelection.Collapse(pNode, 0); + NS_ENSURE_SUCCESS(res, res); + } + return NS_OK; + } + + // Else we want a new list item at the same list level. Get ws code to + // adjust any ws. + nsCOMPtr selNode = &aNode; + res = nsWSRunObject::PrepareToSplitAcrossBlocks(mHTMLEditor, + address_of(selNode), + &aOffset); + NS_ENSURE_SUCCESS(res, res); + // Now split list item + NS_ENSURE_STATE(selNode->IsContent()); + mHTMLEditor->SplitNodeDeep(aListItem, *selNode->AsContent(), aOffset); + + // Hack: until I can change the damaged doc range code back to being + // extra-inclusive, I have to manually detect certain list items that may be + // left empty. + nsCOMPtr prevItem = mHTMLEditor->GetPriorHTMLSibling(&aListItem); + if (prevItem && nsHTMLEditUtils::IsListItem(prevItem)) { + bool isEmptyNode; + res = mHTMLEditor->IsEmptyNode(prevItem, &isEmptyNode); + NS_ENSURE_SUCCESS(res, res); + if (isEmptyNode) { + res = CreateMozBR(prevItem->AsDOMNode(), 0); + NS_ENSURE_SUCCESS(res, res); + } else { + res = mHTMLEditor->IsEmptyNode(&aListItem, &isEmptyNode, true); + NS_ENSURE_SUCCESS(res, res); + if (isEmptyNode) { + nsCOMPtr nodeAtom = aListItem.NodeInfo()->NameAtom(); if (nodeAtom == nsGkAtoms::dd || nodeAtom == nsGkAtoms::dt) { - int32_t itemOffset; - nsCOMPtr list = nsEditor::GetNodeLocation(aListItem, &itemOffset); + nsCOMPtr list = aListItem.GetParentNode(); + int32_t itemOffset = list ? list->IndexOf(&aListItem) : -1; - nsAutoString listTag(nodeAtom == nsGkAtoms::dt - ? NS_LITERAL_STRING("dd") : NS_LITERAL_STRING("dt")); - nsCOMPtr newListItem; - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->CreateNode(listTag, list, itemOffset+1, getter_AddRefs(newListItem)); + nsIAtom* listAtom = nodeAtom == nsGkAtoms::dt ? nsGkAtoms::dd + : nsGkAtoms::dt; + nsCOMPtr newListItem = + mHTMLEditor->CreateNode(listAtom, list, itemOffset + 1); + NS_ENSURE_STATE(newListItem); + res = mEditor->DeleteNode(&aListItem); NS_ENSURE_SUCCESS(res, res); - res = mEditor->DeleteNode(aListItem); + res = aSelection.Collapse(newListItem, 0); NS_ENSURE_SUCCESS(res, res); - return aSelection->Collapse(newListItem, 0); + + return NS_OK; } - nsCOMPtr brNode; - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->CopyLastEditableChildStyles(prevItem, aListItem, getter_AddRefs(brNode)); + nsCOMPtr brNode; + res = mHTMLEditor->CopyLastEditableChildStyles(GetAsDOMNode(prevItem), + GetAsDOMNode(&aListItem), getter_AddRefs(brNode)); NS_ENSURE_SUCCESS(res, res); - if (brNode) - { - int32_t offset; - nsCOMPtr brParent = nsEditor::GetNodeLocation(brNode, &offset); - return aSelection->Collapse(brParent, offset); + if (brNode) { + nsCOMPtr brParent = brNode->GetParentNode(); + int32_t offset = brParent ? brParent->IndexOf(brNode) : -1; + res = aSelection.Collapse(brParent, offset); + NS_ENSURE_SUCCESS(res, res); + + return NS_OK; } - } - else - { - NS_ENSURE_STATE(mHTMLEditor); - nsWSRunObject wsObj(mHTMLEditor, aListItem, 0); - nsCOMPtr visNode_; + } else { + nsWSRunObject wsObj(mHTMLEditor, &aListItem, 0); + nsCOMPtr visNode; int32_t visOffset = 0; WSType wsType; - nsCOMPtr aListItem_(do_QueryInterface(aListItem)); - wsObj.NextVisibleNode(aListItem_, 0, address_of(visNode_), + wsObj.NextVisibleNode(&aListItem, 0, address_of(visNode), &visOffset, &wsType); - nsCOMPtr visNode(GetAsDOMNode(visNode_)); if (wsType == WSType::special || wsType == WSType::br || - nsHTMLEditUtils::IsHR(visNode)) { - int32_t offset; - nsCOMPtr parent = nsEditor::GetNodeLocation(visNode, &offset); - return aSelection->Collapse(parent, offset); - } - else - { - return aSelection->Collapse(visNode, visOffset); + visNode->IsHTMLElement(nsGkAtoms::hr)) { + nsCOMPtr parent = visNode->GetParentNode(); + int32_t offset = parent ? parent->IndexOf(visNode) : -1; + res = aSelection.Collapse(parent, offset); + NS_ENSURE_SUCCESS(res, res); + + return NS_OK; + } else { + res = aSelection.Collapse(visNode, visOffset); + NS_ENSURE_SUCCESS(res, res); + + return NS_OK; } } } } - res = aSelection->Collapse(aListItem,0); - return res; + res = aSelection.Collapse(&aListItem, 0); + NS_ENSURE_SUCCESS(res, res); + + return NS_OK; } @@ -6835,7 +6603,7 @@ nsHTMLEditRules::MakeBlockquote(nsTArray>& aNodeArray) offset); NS_ENSURE_STATE(curBlock); // remember our new block for postprocessing - mNewBlock = curBlock->AsDOMNode(); + mNewBlock = curBlock; // note: doesn't matter if we set mNewBlock multiple times. } @@ -6872,7 +6640,7 @@ nsHTMLEditRules::RemoveBlockStyle(nsTArray>& aNodeArray) firstNode = lastNode = curBlock = nullptr; } // Remove current block - res = mHTMLEditor->RemoveBlockContainer(curNode->AsDOMNode()); + res = mHTMLEditor->RemoveBlockContainer(*curNode->AsContent()); NS_ENSURE_SUCCESS(res, res); } else if (curNode->IsAnyOfHTMLElements(nsGkAtoms::table, nsGkAtoms::tr, @@ -6893,7 +6661,7 @@ nsHTMLEditRules::RemoveBlockStyle(nsTArray>& aNodeArray) GetChildNodesForOperation(*curNode, childArray); res = RemoveBlockStyle(childArray); NS_ENSURE_SUCCESS(res, res); - } else if (IsInlineNode(GetAsDOMNode(curNode))) { + } else if (IsInlineNode(curNode)) { if (curBlock) { // If so, is this node a descendant? if (nsEditorUtils::IsDescendantOf(curNode, curBlock)) { @@ -7007,7 +6775,7 @@ nsHTMLEditRules::ApplyBlockStyle(nsTArray>& aNodeArray, mHTMLEditor->CreateNode(&aBlockTag, curParent, offset); NS_ENSURE_STATE(theBlock); // Remember our new block for postprocessing - mNewBlock = theBlock->AsDOMNode(); + mNewBlock = theBlock; } } else if (curNode->IsHTMLElement(nsGkAtoms::br)) { // If the node is a break, we honor it by putting further nodes in a new @@ -7025,12 +6793,12 @@ nsHTMLEditRules::ApplyBlockStyle(nsTArray>& aNodeArray, curBlock = mHTMLEditor->CreateNode(&aBlockTag, curParent, offset); NS_ENSURE_STATE(curBlock); // Remember our new block for postprocessing - mNewBlock = curBlock->AsDOMNode(); + mNewBlock = curBlock; // Note: doesn't matter if we set mNewBlock multiple times. res = mHTMLEditor->MoveNode(curNode->AsContent(), curBlock, -1); NS_ENSURE_SUCCESS(res, res); } - } else if (IsInlineNode(GetAsDOMNode(curNode))) { + } else if (IsInlineNode(curNode)) { // If curNode is inline, pull it into curBlock. Note: it's assumed that // consecutive inline nodes in aNodeArray are actually members of the // same block parent. This happens to be true now as a side effect of @@ -7050,7 +6818,7 @@ nsHTMLEditRules::ApplyBlockStyle(nsTArray>& aNodeArray, curBlock = mHTMLEditor->CreateNode(&aBlockTag, curParent, offset); NS_ENSURE_STATE(curBlock); // Remember our new block for postprocessing - mNewBlock = curBlock->AsDOMNode(); + mNewBlock = curBlock; // Note: doesn't matter if we set mNewBlock multiple times. } @@ -7070,6 +6838,18 @@ nsHTMLEditRules::ApplyBlockStyle(nsTArray>& aNodeArray, // SplitAsNeeded: Given a tag name, split inOutParent up to the point where we // can insert the tag. Adjust inOutParent and inOutOffset to // point to new location for tag. +nsresult +nsHTMLEditRules::SplitAsNeeded(nsIAtom& aTag, + OwningNonNull& aInOutParent, + int32_t& aInOutOffset) +{ + // XXX Is there a better way to do this? + nsCOMPtr parent = aInOutParent.forget(); + nsresult res = SplitAsNeeded(aTag, parent, aInOutOffset); + aInOutParent = parent.forget(); + return res; +} + nsresult nsHTMLEditRules::SplitAsNeeded(nsIAtom& aTag, nsCOMPtr& inOutParent, @@ -7374,7 +7154,7 @@ nsHTMLEditRules::PinSelectionToNewBlock(Selection* aSelection) NS_ENSURE_SUCCESS(res, res); res = range->SetEnd(selNode, selOffset); NS_ENSURE_SUCCESS(res, res); - nsCOMPtr block (do_QueryInterface(mNewBlock)); + nsCOMPtr block = mNewBlock.get(); NS_ENSURE_TRUE(block, NS_ERROR_NO_INTERFACE); bool nodeBefore, nodeAfter; res = nsRange::CompareNodeToRange(block, range, &nodeBefore, &nodeAfter); @@ -7385,15 +7165,13 @@ nsHTMLEditRules::PinSelectionToNewBlock(Selection* aSelection) else if (nodeBefore) { // selection is after block. put at end of block. - nsCOMPtr tmp = mNewBlock; + nsCOMPtr tmp = GetAsDOMNode(mNewBlock); NS_ENSURE_STATE(mHTMLEditor); tmp = GetAsDOMNode(mHTMLEditor->GetLastEditableChild(*block)); uint32_t endPoint; - NS_ENSURE_STATE(mHTMLEditor); - if (mHTMLEditor->IsTextNode(tmp) || !mHTMLEditor || + if (mHTMLEditor->IsTextNode(tmp) || mHTMLEditor->IsContainer(tmp)) { - NS_ENSURE_STATE(mHTMLEditor); res = nsEditor::GetLengthOfDOMNode(tmp, endPoint); NS_ENSURE_SUCCESS(res, res); } @@ -7407,63 +7185,58 @@ nsHTMLEditRules::PinSelectionToNewBlock(Selection* aSelection) else { // selection is before block. put at start of block. - nsCOMPtr tmp = mNewBlock; + nsCOMPtr tmp = GetAsDOMNode(mNewBlock); NS_ENSURE_STATE(mHTMLEditor); tmp = GetAsDOMNode(mHTMLEditor->GetFirstEditableChild(*block)); int32_t offset; - if (!(mHTMLEditor->IsTextNode(tmp) || !mHTMLEditor || - mHTMLEditor->IsContainer(tmp))) + if (mHTMLEditor->IsTextNode(tmp) || + mHTMLEditor->IsContainer(tmp)) { tmp = nsEditor::GetNodeLocation(tmp, &offset); } - NS_ENSURE_STATE(mHTMLEditor); return aSelection->Collapse(tmp, 0); } } -nsresult -nsHTMLEditRules::CheckInterlinePosition(Selection* aSelection) +void +nsHTMLEditRules::CheckInterlinePosition(Selection& aSelection) { - NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER); - - // if the selection isn't collapsed, do nothing. - if (!aSelection->Collapsed()) { - return NS_OK; + // If the selection isn't collapsed, do nothing. + if (!aSelection.Collapsed()) { + return; } - // get the (collapsed) selection location - nsCOMPtr selNode, node; - int32_t selOffset; - NS_ENSURE_STATE(mHTMLEditor); - nsresult res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(selNode), &selOffset); - NS_ENSURE_SUCCESS(res, res); + NS_ENSURE_TRUE_VOID(mHTMLEditor); + nsCOMPtr kungFuDeathGrip(mHTMLEditor); + + // Get the (collapsed) selection location + NS_ENSURE_TRUE_VOID(aSelection.GetRangeAt(0) && + aSelection.GetRangeAt(0)->GetStartParent()); + OwningNonNull selNode = *aSelection.GetRangeAt(0)->GetStartParent(); + int32_t selOffset = aSelection.GetRangeAt(0)->StartOffset(); // First, let's check to see if we are after a
. We take care of this - // special-case first so that we don't accidentally fall through into one - // of the other conditionals. - NS_ENSURE_STATE(mHTMLEditor); - mHTMLEditor->GetPriorHTMLNode(selNode, selOffset, address_of(node), true); - if (node && nsTextEditUtils::IsBreak(node)) - { - aSelection->SetInterlinePosition(true); - return NS_OK; + // special-case first so that we don't accidentally fall through into one of + // the other conditionals. + nsCOMPtr node = + mHTMLEditor->GetPriorHTMLNode(selNode, selOffset, true); + if (node && node->IsHTMLElement(nsGkAtoms::br)) { + aSelection.SetInterlinePosition(true); + return; } - // are we after a block? If so try set caret to following content - NS_ENSURE_STATE(mHTMLEditor); - mHTMLEditor->GetPriorHTMLSibling(selNode, selOffset, address_of(node)); - if (node && IsBlockNode(node)) - { - aSelection->SetInterlinePosition(true); - return NS_OK; + // Are we after a block? If so try set caret to following content + node = mHTMLEditor->GetPriorHTMLSibling(selNode, selOffset); + if (node && IsBlockNode(*node)) { + aSelection.SetInterlinePosition(true); + return; } - // are we before a block? If so try set caret to prior content - NS_ENSURE_STATE(mHTMLEditor); - mHTMLEditor->GetNextHTMLSibling(selNode, selOffset, address_of(node)); - if (node && IsBlockNode(node)) - aSelection->SetInterlinePosition(false); - return NS_OK; + // Are we before a block? If so try set caret to prior content + node = mHTMLEditor->GetNextHTMLSibling(selNode, selOffset); + if (node && IsBlockNode(*node)) { + aSelection.SetInterlinePosition(false); + } } nsresult @@ -7908,20 +7681,19 @@ nsHTMLEditRules::SelectionEndpointInNode(nsINode* aNode, bool* aResult) return NS_OK; } -/////////////////////////////////////////////////////////////////////////// -// IsEmptyInline: return true if aNode is an empty inline container -// -// +/** + * IsEmptyInline: Return true if aNode is an empty inline container + */ bool -nsHTMLEditRules::IsEmptyInline(nsIDOMNode *aNode) +nsHTMLEditRules::IsEmptyInline(nsINode& aNode) { - if (aNode && IsInlineNode(aNode) && mHTMLEditor && - mHTMLEditor->IsContainer(aNode)) - { - bool bEmpty; - NS_ENSURE_TRUE(mHTMLEditor, false); - mHTMLEditor->IsEmptyNode(aNode, &bEmpty); - return bEmpty; + NS_ENSURE_TRUE(mHTMLEditor, false); + nsCOMPtr kungFuDeathGrip(mHTMLEditor); + + if (IsInlineNode(aNode) && mHTMLEditor->IsContainer(&aNode)) { + bool isEmpty = true; + mHTMLEditor->IsEmptyNode(&aNode, &isEmpty); + return isEmpty; } return false; } @@ -7950,7 +7722,7 @@ nsHTMLEditRules::ListIsEmptyLine(nsTArray>& aArrayOfNodes return false; } brCount++; - } else if (IsEmptyInline(GetAsDOMNode(node))) { + } else if (IsEmptyInline(node)) { // Empty inline, keep looking } else { return false; @@ -8013,7 +7785,7 @@ nsHTMLEditRules::PopListItem(nsIDOMNode *aListItem, bool *aOutOfList) if (!nsHTMLEditUtils::IsList(curParPar) && nsHTMLEditUtils::IsListItem(listItem)) { NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->RemoveBlockContainer(GetAsDOMNode(listItem)); + res = mHTMLEditor->RemoveBlockContainer(*listItem); NS_ENSURE_SUCCESS(res, res); *aOutOfList = true; } @@ -8021,46 +7793,37 @@ nsHTMLEditRules::PopListItem(nsIDOMNode *aListItem, bool *aOutOfList) } nsresult -nsHTMLEditRules::RemoveListStructure(nsIDOMNode *aList) +nsHTMLEditRules::RemoveListStructure(Element& aList) { - NS_ENSURE_ARG_POINTER(aList); - + NS_ENSURE_STATE(mHTMLEditor); + nsCOMPtr kungFuDeathGrip(mHTMLEditor); nsresult res; - nsCOMPtr child; - aList->GetFirstChild(getter_AddRefs(child)); + while (aList.GetFirstChild()) { + OwningNonNull child = *aList.GetFirstChild(); - while (child) - { - if (nsHTMLEditUtils::IsListItem(child)) - { - bool bOutOfList; - do - { - res = PopListItem(child, &bOutOfList); + if (nsHTMLEditUtils::IsListItem(child)) { + bool isOutOfList; + // Keep popping it out until it's not in a list anymore + do { + res = PopListItem(child->AsDOMNode(), &isOutOfList); NS_ENSURE_SUCCESS(res, res); - } while (!bOutOfList); // keep popping it out until it's not in a list anymore - } - else if (nsHTMLEditUtils::IsList(child)) - { - res = RemoveListStructure(child); + } while (!isOutOfList); + } else if (nsHTMLEditUtils::IsList(child)) { + res = RemoveListStructure(*child->AsElement()); NS_ENSURE_SUCCESS(res, res); - } - else - { - // delete any non- list items for now - NS_ENSURE_STATE(mHTMLEditor); + } else { + // Delete any non-list items for now res = mHTMLEditor->DeleteNode(child); NS_ENSURE_SUCCESS(res, res); } - aList->GetFirstChild(getter_AddRefs(child)); } - // delete the now-empty list - NS_ENSURE_STATE(mHTMLEditor); + + // Delete the now-empty list res = mHTMLEditor->RemoveBlockContainer(aList); NS_ENSURE_SUCCESS(res, res); - return res; + return NS_OK; } @@ -8084,7 +7847,10 @@ nsHTMLEditRules::ConfirmSelectionInBody() nsresult res = mHTMLEditor->GetStartNodeAndOffset(selection, getter_AddRefs(selNode), &selOffset); - NS_ENSURE_SUCCESS(res, res); + if (NS_FAILED(res)) { + return res; + } + temp = selNode; // check that selNode is inside body @@ -8193,20 +7959,21 @@ nsHTMLEditRules::UpdateDocChangeRange(nsRange* aRange) } nsresult -nsHTMLEditRules::InsertMozBRIfNeeded(nsIDOMNode *aNode) +nsHTMLEditRules::InsertMozBRIfNeeded(nsINode& aNode) { - NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER); - if (!IsBlockNode(aNode)) return NS_OK; + if (!IsBlockNode(aNode)) { + return NS_OK; + } bool isEmpty; NS_ENSURE_STATE(mHTMLEditor); - nsresult res = mHTMLEditor->IsEmptyNode(aNode, &isEmpty); + nsresult res = mHTMLEditor->IsEmptyNode(&aNode, &isEmpty); NS_ENSURE_SUCCESS(res, res); if (!isEmpty) { return NS_OK; } - return CreateMozBR(aNode, 0); + return CreateMozBR(aNode.AsDOMNode(), 0); } NS_IMETHODIMP @@ -8598,34 +8365,35 @@ nsHTMLEditRules::MakeSureElemStartsOrEndsOnCR(nsIDOMNode *aNode) } nsresult -nsHTMLEditRules::AlignBlock(nsIDOMElement * aElement, const nsAString * aAlignType, bool aContentsOnly) +nsHTMLEditRules::AlignBlock(Element& aElement, const nsAString& aAlignType, + ContentsOnly aContentsOnly) { - NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER); - - nsCOMPtr node = do_QueryInterface(aElement); - bool isBlock = IsBlockNode(node); - if (!isBlock && !nsHTMLEditUtils::IsHR(node)) { - // we deal only with blocks; early way out + if (!IsBlockNode(aElement) && !aElement.IsHTMLElement(nsGkAtoms::hr)) { + // We deal only with blocks; early way out return NS_OK; } - nsresult res = RemoveAlignment(node, *aAlignType, aContentsOnly); + NS_ENSURE_STATE(mHTMLEditor); + nsCOMPtr kungFuDeathGrip(mHTMLEditor); + + nsresult res = RemoveAlignment(aElement.AsDOMNode(), aAlignType, + aContentsOnly == ContentsOnly::yes); NS_ENSURE_SUCCESS(res, res); NS_NAMED_LITERAL_STRING(attr, "align"); - NS_ENSURE_STATE(mHTMLEditor); if (mHTMLEditor->IsCSSEnabled()) { - // let's use CSS alignment; we use margin-left and margin-right for tables + // Let's use CSS alignment; we use margin-left and margin-right for tables // and text-align for other block-level elements - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->SetAttributeOrEquivalent(aElement, attr, *aAlignType, false); + res = mHTMLEditor->SetAttributeOrEquivalent( + static_cast(aElement.AsDOMNode()), attr, aAlignType, + false); NS_ENSURE_SUCCESS(res, res); - } - else { + } else { // HTML case; this code is supposed to be called ONLY if the element // supports the align attribute but we'll never know... - if (nsHTMLEditUtils::SupportsAlignAttr(node)) { - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->SetAttribute(aElement, attr, *aAlignType); + if (nsHTMLEditUtils::SupportsAlignAttr(aElement.AsDOMNode())) { + res = + mHTMLEditor->SetAttribute(static_cast(aElement.AsDOMNode()), + attr, aAlignType); NS_ENSURE_SUCCESS(res, res); } } @@ -8633,88 +8401,69 @@ nsHTMLEditRules::AlignBlock(nsIDOMElement * aElement, const nsAString * aAlignTy } nsresult -nsHTMLEditRules::RelativeChangeIndentationOfElementNode(nsIDOMNode *aNode, int8_t aRelativeChange) +nsHTMLEditRules::ChangeIndentation(Element& aElement, Change aChange) { - NS_ENSURE_ARG_POINTER(aNode); - - if (aRelativeChange != 1 && aRelativeChange != -1) { - return NS_ERROR_ILLEGAL_VALUE; - } - - nsCOMPtr element = do_QueryInterface(aNode); - if (!element) { - return NS_OK; - } - NS_ENSURE_STATE(mHTMLEditor); - nsIAtom* marginProperty = - MarginPropertyAtomForIndent(mHTMLEditor->mHTMLCSSUtils, - GetAsDOMNode(element)); + nsCOMPtr kungFuDeathGrip(mHTMLEditor); + + nsIAtom& marginProperty = + MarginPropertyAtomForIndent(*mHTMLEditor->mHTMLCSSUtils, aElement); nsAutoString value; - NS_ENSURE_STATE(mHTMLEditor); - mHTMLEditor->mHTMLCSSUtils->GetSpecifiedProperty(*element, *marginProperty, + mHTMLEditor->mHTMLCSSUtils->GetSpecifiedProperty(aElement, marginProperty, value); float f; nsCOMPtr unit; - NS_ENSURE_STATE(mHTMLEditor); mHTMLEditor->mHTMLCSSUtils->ParseLength(value, &f, getter_AddRefs(unit)); if (0 == f) { nsAutoString defaultLengthUnit; - NS_ENSURE_STATE(mHTMLEditor); mHTMLEditor->mHTMLCSSUtils->GetDefaultLengthUnit(defaultLengthUnit); unit = NS_Atomize(defaultLengthUnit); } + int8_t multiplier = aChange == Change::plus ? +1 : -1; if (nsGkAtoms::in == unit) { - f += NS_EDITOR_INDENT_INCREMENT_IN * aRelativeChange; + f += NS_EDITOR_INDENT_INCREMENT_IN * multiplier; } else if (nsGkAtoms::cm == unit) { - f += NS_EDITOR_INDENT_INCREMENT_CM * aRelativeChange; + f += NS_EDITOR_INDENT_INCREMENT_CM * multiplier; } else if (nsGkAtoms::mm == unit) { - f += NS_EDITOR_INDENT_INCREMENT_MM * aRelativeChange; + f += NS_EDITOR_INDENT_INCREMENT_MM * multiplier; } else if (nsGkAtoms::pt == unit) { - f += NS_EDITOR_INDENT_INCREMENT_PT * aRelativeChange; + f += NS_EDITOR_INDENT_INCREMENT_PT * multiplier; } else if (nsGkAtoms::pc == unit) { - f += NS_EDITOR_INDENT_INCREMENT_PC * aRelativeChange; + f += NS_EDITOR_INDENT_INCREMENT_PC * multiplier; } else if (nsGkAtoms::em == unit) { - f += NS_EDITOR_INDENT_INCREMENT_EM * aRelativeChange; + f += NS_EDITOR_INDENT_INCREMENT_EM * multiplier; } else if (nsGkAtoms::ex == unit) { - f += NS_EDITOR_INDENT_INCREMENT_EX * aRelativeChange; + f += NS_EDITOR_INDENT_INCREMENT_EX * multiplier; } else if (nsGkAtoms::px == unit) { - f += NS_EDITOR_INDENT_INCREMENT_PX * aRelativeChange; + f += NS_EDITOR_INDENT_INCREMENT_PX * multiplier; } else if (nsGkAtoms::percentage == unit) { - f += NS_EDITOR_INDENT_INCREMENT_PERCENT * aRelativeChange; + f += NS_EDITOR_INDENT_INCREMENT_PERCENT * multiplier; } if (0 < f) { nsAutoString newValue; newValue.AppendFloat(f); newValue.Append(nsDependentAtomString(unit)); - NS_ENSURE_STATE(mHTMLEditor); - mHTMLEditor->mHTMLCSSUtils->SetCSSProperty(*element, *marginProperty, + mHTMLEditor->mHTMLCSSUtils->SetCSSProperty(aElement, marginProperty, newValue); return NS_OK; } - NS_ENSURE_STATE(mHTMLEditor); - mHTMLEditor->mHTMLCSSUtils->RemoveCSSProperty(*element, *marginProperty, + mHTMLEditor->mHTMLCSSUtils->RemoveCSSProperty(aElement, marginProperty, value); - // remove unnecessary DIV blocks: - // we could skip this section but that would cause a FAIL in - // editor/libeditor/tests/browserscope/richtext.html, which expects - // to unapply a CSS "indent" (
) by - // removing the DIV container instead of just removing the CSS property. - nsCOMPtr node = do_QueryInterface(aNode); - if (!node || !node->IsHTMLElement(nsGkAtoms::div) || - !mHTMLEditor || - node == mHTMLEditor->GetActiveEditingHost() || - !mHTMLEditor->IsDescendantOfEditorRoot(node) || - nsHTMLEditor::HasAttributes(node)) { - NS_ENSURE_STATE(mHTMLEditor); + // Remove unnecessary divs + if (!aElement.IsHTMLElement(nsGkAtoms::div) || + &aElement == mHTMLEditor->GetActiveEditingHost() || + !mHTMLEditor->IsDescendantOfEditorRoot(&aElement) || + nsHTMLEditor::HasAttributes(&aElement)) { return NS_OK; } - NS_ENSURE_STATE(mHTMLEditor); - return mHTMLEditor->RemoveContainer(node); + nsresult res = mHTMLEditor->RemoveContainer(&aElement); + NS_ENSURE_SUCCESS(res, res); + + return NS_OK; } // @@ -8722,112 +8471,105 @@ nsHTMLEditRules::RelativeChangeIndentationOfElementNode(nsIDOMNode *aNode, int8_ // nsresult -nsHTMLEditRules::WillAbsolutePosition(Selection* aSelection, +nsHTMLEditRules::WillAbsolutePosition(Selection& aSelection, bool* aCancel, bool* aHandled) { - if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; } - nsresult res = WillInsert(aSelection, aCancel); - NS_ENSURE_SUCCESS(res, res); + MOZ_ASSERT(aCancel && aHandled); + NS_ENSURE_STATE(mHTMLEditor); + nsCOMPtr kungFuDeathGrip(mHTMLEditor); - // initialize out param - // we want to ignore result of WillInsert() + WillInsert(aSelection, aCancel); + + // We want to ignore result of WillInsert() *aCancel = false; *aHandled = true; - nsCOMPtr focusElement; - NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->GetSelectionContainer(getter_AddRefs(focusElement)); - if (focusElement) { - nsCOMPtr node = do_QueryInterface(focusElement); - if (nsHTMLEditUtils::IsImage(node)) { - mNewBlock = node; - return NS_OK; - } + nsCOMPtr focusElement = mHTMLEditor->GetSelectionContainer(); + if (focusElement && nsHTMLEditUtils::IsImage(focusElement)) { + mNewBlock = focusElement; + return NS_OK; } - res = NormalizeSelection(aSelection); + nsresult res = NormalizeSelection(&aSelection); NS_ENSURE_SUCCESS(res, res); - NS_ENSURE_STATE(mHTMLEditor); - nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor); + nsAutoSelectionReset selectionResetter(&aSelection, mHTMLEditor); - // convert the selection ranges into "promoted" selection ranges: - // this basically just expands the range to include the immediate - // block parent, and then further expands to include any ancestors - // whose children are all in the range + // Convert the selection ranges into "promoted" selection ranges: this + // basically just expands the range to include the immediate block parent, + // and then further expands to include any ancestors whose children are all + // in the range. nsTArray> arrayOfRanges; - GetPromotedRanges(*aSelection, arrayOfRanges, + GetPromotedRanges(aSelection, arrayOfRanges, EditAction::setAbsolutePosition); - // use these ranges to contruct a list of nodes to act on. + // Use these ranges to contruct a list of nodes to act on. nsTArray> arrayOfNodes; res = GetNodesForOperation(arrayOfRanges, arrayOfNodes, EditAction::setAbsolutePosition); NS_ENSURE_SUCCESS(res, res); - // if nothing visible in list, make an empty block - if (ListIsEmptyLine(arrayOfNodes)) - { - // get selection location - NS_ENSURE_STATE(aSelection->RangeCount()); - nsCOMPtr parent = aSelection->GetRangeAt(0)->GetStartParent(); - int32_t offset = aSelection->GetRangeAt(0)->StartOffset(); - NS_ENSURE_STATE(parent); + // If nothing visible in list, make an empty block + if (ListIsEmptyLine(arrayOfNodes)) { + // Get selection location + NS_ENSURE_STATE(aSelection.GetRangeAt(0) && + aSelection.GetRangeAt(0)->GetStartParent()); + OwningNonNull parent = + *aSelection.GetRangeAt(0)->GetStartParent(); + int32_t offset = aSelection.GetRangeAt(0)->StartOffset(); - // make sure we can put a block here + // Make sure we can put a block here res = SplitAsNeeded(*nsGkAtoms::div, parent, offset); NS_ENSURE_SUCCESS(res, res); - NS_ENSURE_STATE(mHTMLEditor); - nsCOMPtr thePositionedDiv = + nsCOMPtr positionedDiv = mHTMLEditor->CreateNode(nsGkAtoms::div, parent, offset); - NS_ENSURE_STATE(thePositionedDiv); - // remember our new block for postprocessing - mNewBlock = thePositionedDiv->AsDOMNode(); - // delete anything that was in the list of nodes + NS_ENSURE_STATE(positionedDiv); + // Remember our new block for postprocessing + mNewBlock = positionedDiv; + // Delete anything that was in the list of nodes while (!arrayOfNodes.IsEmpty()) { OwningNonNull curNode = arrayOfNodes[0]; - NS_ENSURE_STATE(mHTMLEditor); res = mHTMLEditor->DeleteNode(curNode); NS_ENSURE_SUCCESS(res, res); arrayOfNodes.RemoveElementAt(0); } - // put selection in new block - res = aSelection->Collapse(thePositionedDiv,0); - selectionResetter.Abort(); // to prevent selection reseter from overriding us. + // Put selection in new block + res = aSelection.Collapse(positionedDiv, 0); + // Prevent selection resetter from overriding us. + selectionResetter.Abort(); *aHandled = true; - return res; + NS_ENSURE_SUCCESS(res, res); + return NS_OK; } - // Ok, now go through all the nodes and put them in a blockquote, - // or whatever is appropriate. Wohoo! - nsCOMPtr curParent; - nsCOMPtr indentedLI, sibling; - nsCOMPtr curList, curPositionedDiv; + // Okay, now go through all the nodes and put them in a blockquote, or + // whatever is appropriate. Woohoo! + nsCOMPtr curList, curPositionedDiv, indentedLI; for (uint32_t i = 0; i < arrayOfNodes.Length(); i++) { - // here's where we actually figure out what to do + // Here's where we actually figure out what to do NS_ENSURE_STATE(arrayOfNodes[i]->IsContent()); - nsCOMPtr curNode = arrayOfNodes[i]->AsContent(); + OwningNonNull curNode = *arrayOfNodes[i]->AsContent(); // Ignore all non-editable nodes. Leave them be. - NS_ENSURE_STATE(mHTMLEditor); - if (!mHTMLEditor->IsEditable(curNode)) continue; + if (!mHTMLEditor->IsEditable(curNode)) { + continue; + } - curParent = curNode->GetParentNode(); + nsCOMPtr sibling; + + nsCOMPtr curParent = curNode->GetParentNode(); int32_t offset = curParent ? curParent->IndexOf(curNode) : -1; - // some logic for putting list items into nested lists... - if (nsHTMLEditUtils::IsList(curParent)) - { - // check to see if curList is still appropriate. Which it is if - // curNode is still right after it in the same list. - if (curList) - { - NS_ENSURE_STATE(mHTMLEditor); - sibling = GetAsDOMNode(mHTMLEditor->GetPriorHTMLSibling(curNode)); + // Some logic for putting list items into nested lists... + if (nsHTMLEditUtils::IsList(curParent)) { + // Check to see if curList is still appropriate. Which it is if curNode + // is still right after it in the same list. + if (curList) { + sibling = mHTMLEditor->GetPriorHTMLSibling(curNode); } - if (!curList || (sibling && sibling != GetAsDOMNode(curList))) { - // create a new nested list of correct type + if (!curList || (sibling && sibling != curList)) { + // Create a new nested list of correct type res = SplitAsNeeded(*curParent->NodeInfo()->NameAtom(), curParent, offset); NS_ENSURE_SUCCESS(res, res); @@ -8835,53 +8577,42 @@ nsHTMLEditRules::WillAbsolutePosition(Selection* aSelection, nsCOMPtr curParentParent = curParent->GetParentNode(); int32_t parentOffset = curParentParent ? curParentParent->IndexOf(curParent) : -1; - NS_ENSURE_STATE(mHTMLEditor); curPositionedDiv = mHTMLEditor->CreateNode(nsGkAtoms::div, curParentParent, parentOffset); - mNewBlock = GetAsDOMNode(curPositionedDiv); + mNewBlock = curPositionedDiv; } - NS_ENSURE_STATE(mHTMLEditor); curList = mHTMLEditor->CreateNode(curParent->NodeInfo()->NameAtom(), curPositionedDiv, -1); NS_ENSURE_STATE(curList); - // curList is now the correct thing to put curNode in - // remember our new block for postprocessing - // mNewBlock = curList; + // curList is now the correct thing to put curNode in. Remember our + // new block for postprocessing. } - // tuck the node into the end of the active list - NS_ENSURE_STATE(mHTMLEditor); + // Tuck the node into the end of the active list res = mHTMLEditor->MoveNode(curNode, curList, -1); NS_ENSURE_SUCCESS(res, res); - // forget curPositionedDiv, if any - // curPositionedDiv = nullptr; - } - - else // not a list item, use blockquote? - { - // if we are inside a list item, we don't want to blockquote, we want - // to sublist the list item. We may have several nodes listed in the - // array of nodes to act on, that are in the same list item. Since - // we only want to indent that li once, we must keep track of the most - // recent indented list item, and not indent it if we find another node - // to act on that is still inside the same li. + } else { + // Not a list item, use blockquote? If we are inside a list item, we + // don't want to blockquote, we want to sublist the list item. We may + // have several nodes listed in the array of nodes to act on, that are in + // the same list item. Since we only want to indent that li once, we + // must keep track of the most recent indented list item, and not indent + // it if we find another node to act on that is still inside the same li. nsCOMPtr listItem = IsInListItem(curNode); if (listItem) { - if (indentedLI == GetAsDOMNode(listItem)) { - // already indented this list item + if (indentedLI == listItem) { + // Already indented this list item continue; } curParent = listItem->GetParentNode(); offset = curParent ? curParent->IndexOf(listItem) : -1; - // check to see if curList is still appropriate. Which it is if + // Check to see if curList is still appropriate. Which it is if // curNode is still right after it in the same list. - if (curList) - { - NS_ENSURE_STATE(mHTMLEditor); - sibling = GetAsDOMNode(mHTMLEditor->GetPriorHTMLSibling(curNode)); + if (curList) { + sibling = mHTMLEditor->GetPriorHTMLSibling(curNode); } - if (!curList || (sibling && sibling != GetAsDOMNode(curList))) { - // create a new nested list of correct type + if (!curList || (sibling && sibling != curList)) { + // Create a new nested list of correct type res = SplitAsNeeded(*curParent->NodeInfo()->NameAtom(), curParent, offset); NS_ENSURE_SUCCESS(res, res); @@ -8889,57 +8620,48 @@ nsHTMLEditRules::WillAbsolutePosition(Selection* aSelection, nsCOMPtr curParentParent = curParent->GetParentNode(); int32_t parentOffset = curParentParent ? curParentParent->IndexOf(curParent) : -1; - NS_ENSURE_STATE(mHTMLEditor); curPositionedDiv = mHTMLEditor->CreateNode(nsGkAtoms::div, curParentParent, parentOffset); - mNewBlock = GetAsDOMNode(curPositionedDiv); + mNewBlock = curPositionedDiv; } - NS_ENSURE_STATE(mHTMLEditor); curList = mHTMLEditor->CreateNode(curParent->NodeInfo()->NameAtom(), curPositionedDiv, -1); NS_ENSURE_STATE(curList); } - NS_ENSURE_STATE(mHTMLEditor); res = mHTMLEditor->MoveNode(listItem, curList, -1); NS_ENSURE_SUCCESS(res, res); - // remember we indented this li - indentedLI = GetAsDOMNode(listItem); - } + // Remember we indented this li + indentedLI = listItem; + } else { + // Need to make a div to put things in if we haven't already - else - { - // need to make a div to put things in if we haven't already - - if (!curPositionedDiv) - { + if (!curPositionedDiv) { if (curNode->IsHTMLElement(nsGkAtoms::div)) { curPositionedDiv = curNode->AsElement(); - mNewBlock = GetAsDOMNode(curPositionedDiv); + mNewBlock = curPositionedDiv; curList = nullptr; continue; } res = SplitAsNeeded(*nsGkAtoms::div, curParent, offset); NS_ENSURE_SUCCESS(res, res); - NS_ENSURE_STATE(mHTMLEditor); curPositionedDiv = mHTMLEditor->CreateNode(nsGkAtoms::div, curParent, offset); NS_ENSURE_STATE(curPositionedDiv); - // remember our new block for postprocessing - mNewBlock = GetAsDOMNode(curPositionedDiv); + // Remember our new block for postprocessing + mNewBlock = curPositionedDiv; // curPositionedDiv is now the correct thing to put curNode in } - // tuck the node into the end of the active blockquote - NS_ENSURE_STATE(mHTMLEditor); + // Tuck the node into the end of the active blockquote res = mHTMLEditor->MoveNode(curNode, curPositionedDiv, -1); NS_ENSURE_SUCCESS(res, res); - // forget curList, if any + // Forget curList, if any curList = nullptr; } } } - return res; + return NS_OK; } nsresult @@ -8947,7 +8669,8 @@ nsHTMLEditRules::DidAbsolutePosition() { NS_ENSURE_STATE(mHTMLEditor); nsCOMPtr absPosHTMLEditor = mHTMLEditor; - nsCOMPtr elt = do_QueryInterface(mNewBlock); + nsCOMPtr elt = + static_cast(GetAsDOMNode(mNewBlock)); return absPosHTMLEditor->AbsolutelyPositionElement(elt, true); } @@ -8955,8 +8678,7 @@ nsresult nsHTMLEditRules::WillRemoveAbsolutePosition(Selection* aSelection, bool* aCancel, bool* aHandled) { if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; } - nsresult res = WillInsert(aSelection, aCancel); - NS_ENSURE_SUCCESS(res, res); + WillInsert(*aSelection, aCancel); // initialize out param // we want to ignore aCancel from WillInsert() @@ -8965,7 +8687,8 @@ nsHTMLEditRules::WillRemoveAbsolutePosition(Selection* aSelection, nsCOMPtr elt; NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->GetAbsolutelyPositionedSelectionContainer(getter_AddRefs(elt)); + nsresult res = + mHTMLEditor->GetAbsolutelyPositionedSelectionContainer(getter_AddRefs(elt)); NS_ENSURE_SUCCESS(res, res); NS_ENSURE_STATE(mHTMLEditor); @@ -8983,8 +8706,7 @@ nsHTMLEditRules::WillRelativeChangeZIndex(Selection* aSelection, bool * aHandled) { if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; } - nsresult res = WillInsert(aSelection, aCancel); - NS_ENSURE_SUCCESS(res, res); + WillInsert(*aSelection, aCancel); // initialize out param // we want to ignore aCancel from WillInsert() @@ -8993,7 +8715,8 @@ nsHTMLEditRules::WillRelativeChangeZIndex(Selection* aSelection, nsCOMPtr elt; NS_ENSURE_STATE(mHTMLEditor); - res = mHTMLEditor->GetAbsolutelyPositionedSelectionContainer(getter_AddRefs(elt)); + nsresult res = + mHTMLEditor->GetAbsolutelyPositionedSelectionContainer(getter_AddRefs(elt)); NS_ENSURE_SUCCESS(res, res); NS_ENSURE_STATE(mHTMLEditor); diff --git a/editor/libeditor/nsHTMLEditRules.h b/editor/libeditor/nsHTMLEditRules.h index 3811eef6e9..505b36358a 100644 --- a/editor/libeditor/nsHTMLEditRules.h +++ b/editor/libeditor/nsHTMLEditRules.h @@ -64,6 +64,7 @@ class nsHTMLEditRules : public nsTextEditRules, public nsIEditActionListener public: NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHTMLEditRules, nsTextEditRules) nsHTMLEditRules(); @@ -74,10 +75,10 @@ public: nsIEditor::EDirection aDirection) override; NS_IMETHOD AfterEdit(EditAction action, nsIEditor::EDirection aDirection) override; - NS_IMETHOD WillDoAction(mozilla::dom::Selection* aSelection, nsRulesInfo* aInfo, + NS_IMETHOD WillDoAction(Selection* aSelection, nsRulesInfo* aInfo, bool* aCancel, bool* aHandled) override; - NS_IMETHOD DidDoAction(mozilla::dom::Selection* aSelection, - nsRulesInfo* aInfo, nsresult aResult) override; + NS_IMETHOD DidDoAction(Selection* aSelection, nsRulesInfo* aInfo, + nsresult aResult) override; NS_IMETHOD DocumentModified() override; nsresult GetListState(bool *aMixed, bool *aOL, bool *aUL, bool *aDL); @@ -105,6 +106,7 @@ public: NS_IMETHOD DidDeleteText(nsIDOMCharacterData *aTextNode, int32_t aOffset, int32_t aLength, nsresult aResult) override; NS_IMETHOD WillDeleteSelection(nsISelection *aSelection) override; NS_IMETHOD DidDeleteSelection(nsISelection *aSelection) override; + void DeleteNodeIfCollapsedText(nsINode& aNode); protected: virtual ~nsHTMLEditRules(); @@ -115,208 +117,189 @@ protected: kEnd }; - enum BRLocation - { - kBeforeBlock, - kBlockEnd - }; - void InitFields(); // nsHTMLEditRules implementation methods - nsresult WillInsert(mozilla::dom::Selection* aSelection, bool* aCancel); + void WillInsert(Selection& aSelection, bool* aCancel); nsresult WillInsertText( EditAction aAction, - mozilla::dom::Selection* aSelection, + Selection* aSelection, bool *aCancel, bool *aHandled, const nsAString *inString, nsAString *outString, int32_t aMaxLength); - nsresult WillLoadHTML(mozilla::dom::Selection* aSelection, bool* aCancel); - nsresult WillInsertBreak(mozilla::dom::Selection* aSelection, - bool* aCancel, bool* aHandled); - nsresult StandardBreakImpl(nsIDOMNode* aNode, int32_t aOffset, - mozilla::dom::Selection* aSelection); - nsresult DidInsertBreak(mozilla::dom::Selection* aSelection, - nsresult aResult); - nsresult SplitMailCites(mozilla::dom::Selection* aSelection, bool* aHandled); - nsresult WillDeleteSelection(mozilla::dom::Selection* aSelection, + nsresult WillLoadHTML(Selection* aSelection, bool* aCancel); + nsresult WillInsertBreak(Selection& aSelection, bool* aCancel, + bool* aHandled); + nsresult StandardBreakImpl(nsINode& aNode, int32_t aOffset, + Selection& aSelection); + nsresult DidInsertBreak(Selection* aSelection, nsresult aResult); + nsresult SplitMailCites(Selection* aSelection, bool* aHandled); + nsresult WillDeleteSelection(Selection* aSelection, nsIEditor::EDirection aAction, nsIEditor::EStripWrappers aStripWrappers, bool* aCancel, bool* aHandled); - nsresult DidDeleteSelection(mozilla::dom::Selection* aSelection, + nsresult DidDeleteSelection(Selection* aSelection, nsIEditor::EDirection aDir, nsresult aResult); - nsresult InsertBRIfNeeded(mozilla::dom::Selection* aSelection); + nsresult InsertBRIfNeeded(Selection* aSelection); ::DOMPoint GetGoodSelPointForNode(nsINode& aNode, nsIEditor::EDirection aAction); - nsresult JoinBlocks(nsIDOMNode *aLeftNode, nsIDOMNode *aRightNode, bool *aCanceled); - nsresult MoveBlock(nsIDOMNode *aLeft, nsIDOMNode *aRight, int32_t aLeftOffset, int32_t aRightOffset); - nsresult MoveNodeSmart(nsIDOMNode *aSource, nsIDOMNode *aDest, int32_t *aOffset); - nsresult MoveContents(nsIDOMNode *aSource, nsIDOMNode *aDest, int32_t *aOffset); + nsresult JoinBlocks(nsIContent& aLeftNode, nsIContent& aRightNode, + bool* aCanceled); + nsresult MoveBlock(Element& aLeftBlock, Element& aRightBlock, + int32_t aLeftOffset, int32_t aRightOffset); + nsresult MoveNodeSmart(nsIContent& aNode, Element& aDestElement, + int32_t* aOffset); + nsresult MoveContents(Element& aElement, Element& aDestElement, + int32_t* aOffset); nsresult DeleteNonTableElements(nsINode* aNode); - nsresult WillMakeList(mozilla::dom::Selection* aSelection, + nsresult WillMakeList(Selection* aSelection, const nsAString* aListType, bool aEntireList, const nsAString* aBulletType, bool* aCancel, bool* aHandled, const nsAString* aItemType = nullptr); - nsresult WillRemoveList(mozilla::dom::Selection* aSelection, - bool aOrdered, bool* aCancel, bool* aHandled); - nsresult WillIndent(mozilla::dom::Selection* aSelection, - bool* aCancel, bool* aHandled); - nsresult WillCSSIndent(mozilla::dom::Selection* aSelection, - bool* aCancel, bool* aHandled); - nsresult WillHTMLIndent(mozilla::dom::Selection* aSelection, - bool* aCancel, bool* aHandled); - nsresult WillOutdent(mozilla::dom::Selection* aSelection, - bool* aCancel, bool* aHandled); - nsresult WillAlign(mozilla::dom::Selection* aSelection, - const nsAString* alignType, + nsresult WillRemoveList(Selection* aSelection, bool aOrdered, bool* aCancel, + bool* aHandled); + nsresult WillIndent(Selection* aSelection, bool* aCancel, bool* aHandled); + nsresult WillCSSIndent(Selection* aSelection, bool* aCancel, bool* aHandled); + nsresult WillHTMLIndent(Selection* aSelection, bool* aCancel, + bool* aHandled); + nsresult WillOutdent(Selection& aSelection, bool* aCancel, bool* aHandled); + nsresult WillAlign(Selection& aSelection, const nsAString& aAlignType, bool* aCancel, bool* aHandled); - nsresult WillAbsolutePosition(mozilla::dom::Selection* aSelection, - bool* aCancel, bool* aHandled); - nsresult WillRemoveAbsolutePosition(mozilla::dom::Selection* aSelection, - bool* aCancel, bool* aHandled); - nsresult WillRelativeChangeZIndex(mozilla::dom::Selection* aSelection, - int32_t aChange, + nsresult WillAbsolutePosition(Selection& aSelection, bool* aCancel, + bool* aHandled); + nsresult WillRemoveAbsolutePosition(Selection* aSelection, bool* aCancel, + bool* aHandled); + nsresult WillRelativeChangeZIndex(Selection* aSelection, int32_t aChange, bool* aCancel, bool* aHandled); - nsresult WillMakeDefListItem(mozilla::dom::Selection* aSelection, + nsresult WillMakeDefListItem(Selection* aSelection, const nsAString* aBlockType, bool aEntireList, bool* aCancel, bool* aHandled); - nsresult WillMakeBasicBlock(mozilla::dom::Selection* aSelection, - const nsAString* aBlockType, + nsresult WillMakeBasicBlock(Selection& aSelection, + const nsAString& aBlockType, bool* aCancel, bool* aHandled); - nsresult DidMakeBasicBlock(mozilla::dom::Selection* aSelection, - nsRulesInfo* aInfo, nsresult aResult); + nsresult DidMakeBasicBlock(Selection* aSelection, nsRulesInfo* aInfo, + nsresult aResult); nsresult DidAbsolutePosition(); nsresult AlignInnerBlocks(nsINode& aNode, const nsAString* alignType); nsresult AlignBlockContents(nsIDOMNode *aNode, const nsAString *alignType); - nsresult AppendInnerFormatNodes(nsTArray>& aArray, + nsresult AppendInnerFormatNodes(nsTArray>& aArray, nsINode* aNode); nsresult GetFormatString(nsIDOMNode *aNode, nsAString &outFormat); enum class Lists { no, yes }; enum class Tables { no, yes }; void GetInnerContent(nsINode& aNode, - nsTArray>& aOutArrayOfNodes, + nsTArray>& aOutArrayOfNodes, int32_t* aIndex, Lists aLists = Lists::yes, Tables aTables = Tables::yes); - already_AddRefed IsInListItem(nsIDOMNode* aNode); - mozilla::dom::Element* IsInListItem(nsINode* aNode); - nsresult ReturnInHeader(mozilla::dom::Selection* aSelection, - nsIDOMNode* aHeader, nsIDOMNode* aTextNode, - int32_t aOffset); - nsresult ReturnInParagraph(mozilla::dom::Selection* aSelection, - nsIDOMNode* aHeader, nsIDOMNode* aTextNode, - int32_t aOffset, bool* aCancel, bool* aHandled); + Element* IsInListItem(nsINode* aNode); + nsresult ReturnInHeader(Selection& aSelection, Element& aHeader, + nsINode& aNode, int32_t aOffset); + nsresult ReturnInParagraph(Selection* aSelection, nsIDOMNode* aHeader, + nsIDOMNode* aTextNode, int32_t aOffset, + bool* aCancel, bool* aHandled); nsresult SplitParagraph(nsIDOMNode *aPara, - nsIDOMNode *aBRNode, - mozilla::dom::Selection* aSelection, + nsIContent* aBRNode, + Selection* aSelection, nsCOMPtr *aSelNode, int32_t *aOffset); - nsresult ReturnInListItem(mozilla::dom::Selection* aSelection, - nsIDOMNode* aHeader, nsIDOMNode* aTextNode, - int32_t aOffset); + nsresult ReturnInListItem(Selection& aSelection, Element& aHeader, + nsINode& aNode, int32_t aOffset); nsresult AfterEditInner(EditAction action, nsIEditor::EDirection aDirection); - nsresult RemovePartOfBlock(mozilla::dom::Element& aBlock, - nsIContent& aStartChild, + nsresult RemovePartOfBlock(Element& aBlock, nsIContent& aStartChild, nsIContent& aEndChild); - nsresult SplitBlock(nsIDOMNode *aBlock, - nsIDOMNode *aStartChild, - nsIDOMNode *aEndChild, - nsCOMPtr *aLeftNode = 0, - nsCOMPtr *aRightNode = 0, - nsCOMPtr *aMiddleNode = 0); - nsresult OutdentPartOfBlock(nsIDOMNode *aBlock, - nsIDOMNode *aStartChild, - nsIDOMNode *aEndChild, + void SplitBlock(Element& aBlock, + nsIContent& aStartChild, + nsIContent& aEndChild, + nsIContent** aOutLeftNode = nullptr, + nsIContent** aOutRightNode = nullptr, + nsIContent** aOutMiddleNode = nullptr); + nsresult OutdentPartOfBlock(Element& aBlock, + nsIContent& aStartChild, + nsIContent& aEndChild, bool aIsBlockIndentedWithCSS, - nsCOMPtr *aLeftNode = 0, - nsCOMPtr *aRightNode = 0); + nsIContent** aOutLeftNode, + nsIContent** aOutRightNode); - nsresult ConvertListType(nsIDOMNode* aList, - nsCOMPtr* outList, - nsIAtom* aListType, - nsIAtom* aItemType); - nsresult ConvertListType(mozilla::dom::Element* aList, - mozilla::dom::Element** aOutList, - nsIAtom* aListType, - nsIAtom* aItemType); + nsresult ConvertListType(Element* aList, Element** aOutList, + nsIAtom* aListType, nsIAtom* aItemType); - nsresult CreateStyleForInsertText(mozilla::dom::Selection* aSelection, - nsIDOMDocument* aDoc); - nsresult IsEmptyBlock(nsIDOMNode *aNode, - bool *outIsEmptyBlock, - bool aMozBRDoesntCount = false, - bool aListItemsNotEmpty = false); - nsresult CheckForEmptyBlock(nsINode* aStartNode, - mozilla::dom::Element* aBodyNode, - mozilla::dom::Selection* aSelection, - nsIEditor::EDirection aAction, - bool* aHandled); - nsresult CheckForInvisibleBR(nsIDOMNode *aBlock, nsHTMLEditRules::BRLocation aWhere, - nsCOMPtr *outBRNode, int32_t aOffset=0); - nsresult ExpandSelectionForDeletion(mozilla::dom::Selection* aSelection); + nsresult CreateStyleForInsertText(Selection& aSelection, nsIDocument& aDoc); + enum class MozBRCounts { yes, no }; + nsresult IsEmptyBlock(Element& aNode, bool* aOutIsEmptyBlock, + MozBRCounts aMozBRCounts = MozBRCounts::yes); + nsresult CheckForEmptyBlock(nsINode* aStartNode, Element* aBodyNode, + Selection* aSelection, + nsIEditor::EDirection aAction, bool* aHandled); + enum class BRLocation { beforeBlock, blockEnd }; + Element* CheckForInvisibleBR(Element& aBlock, BRLocation aWhere, + int32_t aOffset = 0); + nsresult ExpandSelectionForDeletion(Selection& aSelection); bool IsFirstNode(nsIDOMNode *aNode); bool IsLastNode(nsIDOMNode *aNode); - nsresult NormalizeSelection(mozilla::dom::Selection* aSelection); + nsresult NormalizeSelection(Selection* aSelection); void GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode* aNode, int32_t aOffset, EditAction actionID, nsCOMPtr* outNode, int32_t* outOffset); - void GetPromotedRanges(mozilla::dom::Selection& aSelection, + void GetPromotedRanges(Selection& aSelection, nsTArray>& outArrayOfRanges, EditAction inOperationType); void PromoteRange(nsRange& aRange, EditAction inOperationType); enum class TouchContent { no, yes }; nsresult GetNodesForOperation(nsTArray>& aArrayOfRanges, - nsTArray>& aOutArrayOfNodes, + nsTArray>& aOutArrayOfNodes, EditAction aOperationType, TouchContent aTouchContent = TouchContent::yes); void GetChildNodesForOperation(nsINode& aNode, - nsTArray>& outArrayOfNodes); + nsTArray>& outArrayOfNodes); nsresult GetNodesFromPoint(::DOMPoint aPoint, EditAction aOperation, - nsTArray>& outArrayOfNodes, + nsTArray>& outArrayOfNodes, TouchContent aTouchContent); - nsresult GetNodesFromSelection(mozilla::dom::Selection& aSelection, + nsresult GetNodesFromSelection(Selection& aSelection, EditAction aOperation, - nsTArray>& outArrayOfNodes, + nsTArray>& outArrayOfNodes, TouchContent aTouchContent = TouchContent::yes); enum class EntireList { no, yes }; - nsresult GetListActionNodes(nsTArray>& aOutArrayOfNodes, + nsresult GetListActionNodes(nsTArray>& aOutArrayOfNodes, EntireList aEntireList, TouchContent aTouchContent = TouchContent::yes); - void GetDefinitionListItemTypes(mozilla::dom::Element* aElement, bool* aDT, bool* aDD); + void GetDefinitionListItemTypes(Element* aElement, bool* aDT, bool* aDD); nsresult GetParagraphFormatNodes( - nsTArray>& outArrayOfNodes, + nsTArray>& outArrayOfNodes, TouchContent aTouchContent = TouchContent::yes); - void LookInsideDivBQandList(nsTArray>& aNodeArray); + void LookInsideDivBQandList(nsTArray>& aNodeArray); nsresult BustUpInlinesAtRangeEndpoints(nsRangeStore &inRange); nsresult BustUpInlinesAtBRs(nsIContent& aNode, - nsTArray>& aOutArrayOfNodes); - nsCOMPtr GetHighestInlineParent(nsIDOMNode* aNode); - void MakeTransitionList(nsTArray>& aNodeArray, + nsTArray>& aOutArrayOfNodes); + nsIContent* GetHighestInlineParent(nsINode& aNode); + void MakeTransitionList(nsTArray>& aNodeArray, nsTArray& aTransitionArray); - nsresult RemoveBlockStyle(nsTArray>& aNodeArray); - nsresult ApplyBlockStyle(nsTArray>& aNodeArray, + nsresult RemoveBlockStyle(nsTArray>& aNodeArray); + nsresult ApplyBlockStyle(nsTArray>& aNodeArray, nsIAtom& aBlockTag); - nsresult MakeBlockquote(nsTArray>& aNodeArray); + nsresult MakeBlockquote(nsTArray>& aNodeArray); + nsresult SplitAsNeeded(nsIAtom& aTag, OwningNonNull& inOutParent, + int32_t& inOutOffset); nsresult SplitAsNeeded(nsIAtom& aTag, nsCOMPtr& inOutParent, int32_t& inOutOffset); nsresult AddTerminatingBR(nsIDOMNode *aBlock); ::DOMPoint JoinNodesSmart(nsIContent& aNodeLeft, nsIContent& aNodeRight); - mozilla::dom::Element* GetTopEnclosingMailCite(nsINode& aNode); + Element* GetTopEnclosingMailCite(nsINode& aNode); nsresult PopListItem(nsIDOMNode *aListItem, bool *aOutOfList); - nsresult RemoveListStructure(nsIDOMNode *aList); + nsresult RemoveListStructure(Element& aList); nsresult CacheInlineStyles(nsIDOMNode *aNode); nsresult ReapplyCachedStyles(); void ClearCachedStyles(); void AdjustSpecialBreaks(); - nsresult AdjustWhitespace(mozilla::dom::Selection* aSelection); - nsresult PinSelectionToNewBlock(mozilla::dom::Selection* aSelection); - nsresult CheckInterlinePosition(mozilla::dom::Selection* aSelection); - nsresult AdjustSelection(mozilla::dom::Selection* aSelection, + nsresult AdjustWhitespace(Selection* aSelection); + nsresult PinSelectionToNewBlock(Selection* aSelection); + void CheckInterlinePosition(Selection& aSelection); + nsresult AdjustSelection(Selection* aSelection, nsIEditor::EDirection aAction); nsresult FindNearSelectableNode(nsIDOMNode *aSelNode, int32_t aSelOffset, @@ -335,13 +318,16 @@ protected: nsresult SelectionEndpointInNode(nsINode *aNode, bool *aResult); nsresult UpdateDocChangeRange(nsRange* aRange); nsresult ConfirmSelectionInBody(); - nsresult InsertMozBRIfNeeded(nsIDOMNode *aNode); - bool IsEmptyInline(nsIDOMNode *aNode); - bool ListIsEmptyLine(nsTArray>& arrayOfNodes); + nsresult InsertMozBRIfNeeded(nsINode& aNode); + bool IsEmptyInline(nsINode& aNode); + bool ListIsEmptyLine(nsTArray>& arrayOfNodes); nsresult RemoveAlignment(nsIDOMNode * aNode, const nsAString & aAlignType, bool aChildrenOnly); nsresult MakeSureElemStartsOrEndsOnCR(nsIDOMNode *aNode, bool aStarts); - nsresult AlignBlock(nsIDOMElement * aElement, const nsAString * aAlignType, bool aContentsOnly); - nsresult RelativeChangeIndentationOfElementNode(nsIDOMNode *aNode, int8_t aRelativeChange); + enum class ContentsOnly { no, yes }; + nsresult AlignBlock(Element& aElement, + const nsAString& aAlignType, ContentsOnly aContentsOnly); + enum class Change { minus, plus }; + nsresult ChangeIndentation(Element& aElement, Change aChange); void DocumentModifiedWorker(); // data members @@ -355,7 +341,7 @@ protected: bool mRestoreContentEditableCount; RefPtr mUtilRange; uint32_t mJoinOffset; // need to remember an int across willJoin/didJoin... - nsCOMPtr mNewBlock; + nsCOMPtr mNewBlock; RefPtr mRangeItem; StyleCache mCachedStyles[SIZE_STYLE_TABLE]; }; diff --git a/editor/libeditor/nsHTMLEditUtils.cpp b/editor/libeditor/nsHTMLEditUtils.cpp index ccc320bcc1..33f9fb25ce 100644 --- a/editor/libeditor/nsHTMLEditUtils.cpp +++ b/editor/libeditor/nsHTMLEditUtils.cpp @@ -259,16 +259,13 @@ nsHTMLEditUtils::IsTableCell(nsINode* aNode) /////////////////////////////////////////////////////////////////////////// -// IsTableCell: true if node an html td or th +// IsTableCellOrCaption: true if node an html td or th or caption // bool -nsHTMLEditUtils::IsTableCellOrCaption(nsIDOMNode* aNode) +nsHTMLEditUtils::IsTableCellOrCaption(nsINode& aNode) { - NS_PRECONDITION(aNode, "null parent passed to nsHTMLEditUtils::IsTableCell"); - nsCOMPtr nodeAtom = nsEditor::GetTag(aNode); - return (nodeAtom == nsGkAtoms::td) - || (nodeAtom == nsGkAtoms::th) - || (nodeAtom == nsGkAtoms::caption); + return aNode.IsAnyOfHTMLElements(nsGkAtoms::td, nsGkAtoms::th, + nsGkAtoms::caption); } diff --git a/editor/libeditor/nsHTMLEditUtils.h b/editor/libeditor/nsHTMLEditUtils.h index d1b7e2d6c0..231e308ac2 100644 --- a/editor/libeditor/nsHTMLEditUtils.h +++ b/editor/libeditor/nsHTMLEditUtils.h @@ -35,7 +35,7 @@ public: static bool IsTableElementButNotTable(nsIDOMNode *aNode); static bool IsTableCell(nsINode* node); static bool IsTableCell(nsIDOMNode *aNode); - static bool IsTableCellOrCaption(nsIDOMNode *aNode); + static bool IsTableCellOrCaption(nsINode& aNode); static bool IsList(nsINode* aNode); static bool IsList(nsIDOMNode *aNode); static bool IsOrderedList(nsIDOMNode *aNode); diff --git a/editor/libeditor/nsHTMLEditor.cpp b/editor/libeditor/nsHTMLEditor.cpp index 46f08c3e9b..0b996e97e3 100644 --- a/editor/libeditor/nsHTMLEditor.cpp +++ b/editor/libeditor/nsHTMLEditor.cpp @@ -1000,14 +1000,6 @@ nsHTMLEditor::IsVisBreak(nsINode* aNode) return true; } -bool -nsHTMLEditor::IsVisBreak(nsIDOMNode* aNode) -{ - nsCOMPtr node = do_QueryInterface(aNode); - NS_ENSURE_TRUE(node, false); - return IsVisBreak(node); -} - NS_IMETHODIMP nsHTMLEditor::GetIsDocumentEditable(bool *aIsDocumentEditable) { @@ -1136,7 +1128,7 @@ nsHTMLEditor::TabInTable(bool inIsShift, bool* outHandled) return NS_OK; } -already_AddRefed +Element* nsHTMLEditor::CreateBR(nsINode* aNode, int32_t aOffset, EDirection aSelect) { nsCOMPtr parent = GetAsDOMNode(aNode); @@ -1145,7 +1137,7 @@ nsHTMLEditor::CreateBR(nsINode* aNode, int32_t aOffset, EDirection aSelect) // We assume everything is fine if the br is not null, irrespective of retval CreateBRImpl(address_of(parent), &offset, address_of(outBRNode), aSelect); nsCOMPtr ret = do_QueryInterface(outBRNode); - return ret.forget(); + return ret; } NS_IMETHODIMP nsHTMLEditor::CreateBR(nsIDOMNode *aNode, int32_t aOffset, nsCOMPtr *outBRNode, EDirection aSelect) @@ -1419,7 +1411,7 @@ nsHTMLEditor::RebuildDocumentFromSource(const nsAString& aSourceString) } void -nsHTMLEditor::NormalizeEOLInsertPosition(nsIDOMNode *firstNodeToInsert, +nsHTMLEditor::NormalizeEOLInsertPosition(nsINode* firstNodeToInsert, nsCOMPtr *insertParentNode, int32_t *insertOffset) { @@ -1499,7 +1491,8 @@ nsHTMLEditor::InsertElementAtSelection(nsIDOMElement* aElement, bool aDeleteSele nsresult res = NS_ERROR_NOT_INITIALIZED; - NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER); + nsCOMPtr element = do_QueryInterface(aElement); + NS_ENSURE_TRUE(element, NS_ERROR_NULL_POINTER); nsCOMPtr node = do_QueryInterface(aElement); @@ -1523,7 +1516,7 @@ nsHTMLEditor::InsertElementAtSelection(nsIDOMElement* aElement, bool aDeleteSele { if (aDeleteSelection) { - if (!IsBlockNode(aElement)) { + if (!IsBlockNode(element)) { // E.g., inserting an image. In this case we don't need to delete any // inline wrappers before we do the insertion. Otherwise we let // DeleteSelectionAndPrepareToCreateNode do the deletion for us, which @@ -1558,7 +1551,8 @@ nsHTMLEditor::InsertElementAtSelection(nsIDOMElement* aElement, bool aDeleteSele if (NS_SUCCEEDED(res) && NS_SUCCEEDED(selection->GetAnchorOffset(&offsetForInsert)) && parentSelectedNode) { // Adjust position based on the node we are going to insert. - NormalizeEOLInsertPosition(node, address_of(parentSelectedNode), &offsetForInsert); + NormalizeEOLInsertPosition(element, address_of(parentSelectedNode), + &offsetForInsert); res = InsertNodeAtPoint(node, address_of(parentSelectedNode), &offsetForInsert, false); NS_ENSURE_SUCCESS(res, res); @@ -1659,10 +1653,12 @@ nsHTMLEditor::InsertNodeAtPoint(nsIDOMNode *aNode, NS_IMETHODIMP nsHTMLEditor::SelectElement(nsIDOMElement* aElement) { + nsCOMPtr element = do_QueryInterface(aElement); + NS_ENSURE_STATE(element || !aElement); nsresult res = NS_ERROR_NULL_POINTER; // Must be sure that element is contained in the document body - if (IsDescendantOfEditorRoot(aElement)) { + if (IsDescendantOfEditorRoot(element)) { RefPtr selection = GetSelection(); NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER); nsCOMPtrparent; @@ -1685,10 +1681,12 @@ nsHTMLEditor::SelectElement(nsIDOMElement* aElement) NS_IMETHODIMP nsHTMLEditor::SetCaretAfterElement(nsIDOMElement* aElement) { + nsCOMPtr element = do_QueryInterface(aElement); + NS_ENSURE_STATE(element || !aElement); nsresult res = NS_ERROR_NULL_POINTER; // Be sure the element is contained in the document body - if (aElement && IsDescendantOfEditorRoot(aElement)) { + if (aElement && IsDescendantOfEditorRoot(element)) { RefPtr selection = GetSelection(); NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER); nsCOMPtrparent; @@ -2555,8 +2553,8 @@ nsHTMLEditor::CreateElementWithDefaults(const nsAString& aTagName) // the transaction system // New call to use instead to get proper HTML element, bug 39919 - nsCOMPtr newElement = - CreateHTMLContent(nsCOMPtr(NS_Atomize(realTagName))); + nsCOMPtr realTagAtom = NS_Atomize(realTagName); + nsCOMPtr newElement = CreateHTMLContent(realTagAtom); if (!newElement) { return nullptr; } @@ -3809,95 +3807,79 @@ nsHTMLEditor::SetSelectionAtDocumentStart(Selection* aSelection) } -/////////////////////////////////////////////////////////////////////////// -// RemoveBlockContainer: remove inNode, reparenting its children into their -// the parent of inNode. In addition, INSERT ANY BR's NEEDED -// TO PRESERVE IDENTITY OF REMOVED BLOCK. -// +/** + * Remove aNode, reparenting any children into the parent of aNode. In + * addition, insert any br's needed to preserve identity of removed block. + */ nsresult -nsHTMLEditor::RemoveBlockContainer(nsIDOMNode *inNode) +nsHTMLEditor::RemoveBlockContainer(nsIContent& aNode) { - nsCOMPtr node = do_QueryInterface(inNode); - NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER); - nsresult res; - nsCOMPtr sibling, child, unused; + // Two possibilities: the container could be empty of editable content. If + // that is the case, we need to compare what is before and after aNode to + // determine if we need a br. + // + // Or it could be not empty, in which case we have to compare previous + // sibling and first child to determine if we need a leading br, and compare + // following sibling and last child to determine if we need a trailing br. - // Two possibilities: the container cold be empty of editable content. - // If that is the case, we need to compare what is before and after inNode - // to determine if we need a br. - // Or it could not be empty, in which case we have to compare previous - // sibling and first child to determine if we need a leading br, - // and compare following sibling and last child to determine if we need a - // trailing br. + nsCOMPtr child = GetFirstEditableChild(aNode); - child = GetAsDOMNode(GetFirstEditableChild(*node)); - - if (child) // the case of inNode not being empty - { - // we need a br at start unless: - // 1) previous sibling of inNode is a block, OR - // 2) previous sibling of inNode is a br, OR - // 3) first child of inNode is a block OR + if (child) { + // The case of aNode not being empty. We need a br at start unless: + // 1) previous sibling of aNode is a block, OR + // 2) previous sibling of aNode is a br, OR + // 3) first child of aNode is a block OR // 4) either is null - res = GetPriorHTMLSibling(inNode, address_of(sibling)); - NS_ENSURE_SUCCESS(res, res); - if (sibling && !IsBlockNode(sibling) && !nsTextEditUtils::IsBreak(sibling)) - { - if (!IsBlockNode(child)) { - // insert br node - res = CreateBR(inNode, 0, address_of(unused)); - NS_ENSURE_SUCCESS(res, res); - } + nsCOMPtr sibling = GetPriorHTMLSibling(&aNode); + if (sibling && !IsBlockNode(sibling) && + !sibling->IsHTMLElement(nsGkAtoms::br) && !IsBlockNode(child)) { + // Insert br node + nsCOMPtr br = CreateBR(&aNode, 0); + NS_ENSURE_STATE(br); } - // we need a br at end unless: - // 1) following sibling of inNode is a block, OR - // 2) last child of inNode is a block, OR - // 3) last child of inNode is a block OR + // We need a br at end unless: + // 1) following sibling of aNode is a block, OR + // 2) last child of aNode is a block, OR + // 3) last child of aNode is a br OR // 4) either is null - res = GetNextHTMLSibling(inNode, address_of(sibling)); - NS_ENSURE_SUCCESS(res, res); - if (sibling && !IsBlockNode(sibling)) - { - child = GetAsDOMNode(GetLastEditableChild(*node)); - if (child && !IsBlockNode(child) && !nsTextEditUtils::IsBreak(child)) - { - // insert br node - uint32_t len; - res = GetLengthOfDOMNode(inNode, len); - NS_ENSURE_SUCCESS(res, res); - res = CreateBR(inNode, (int32_t)len, address_of(unused)); - NS_ENSURE_SUCCESS(res, res); + sibling = GetNextHTMLSibling(&aNode); + if (sibling && !IsBlockNode(sibling)) { + child = GetLastEditableChild(aNode); + MOZ_ASSERT(child, "aNode has first editable child but not last?"); + if (!IsBlockNode(child) && !child->IsHTMLElement(nsGkAtoms::br)) { + // Insert br node + nsCOMPtr br = CreateBR(&aNode, aNode.Length()); + NS_ENSURE_STATE(br); } } - } - else // the case of inNode being empty - { - // we need a br at start unless: - // 1) previous sibling of inNode is a block, OR - // 2) previous sibling of inNode is a br, OR - // 3) following sibling of inNode is a block, OR - // 4) following sibling of inNode is a br OR + } else { + // The case of aNode being empty. We need a br at start unless: + // 1) previous sibling of aNode is a block, OR + // 2) previous sibling of aNode is a br, OR + // 3) following sibling of aNode is a block, OR + // 4) following sibling of aNode is a br OR // 5) either is null - res = GetPriorHTMLSibling(inNode, address_of(sibling)); - NS_ENSURE_SUCCESS(res, res); - if (sibling && !IsBlockNode(sibling) && !nsTextEditUtils::IsBreak(sibling)) - { - res = GetNextHTMLSibling(inNode, address_of(sibling)); - NS_ENSURE_SUCCESS(res, res); - if (sibling && !IsBlockNode(sibling) && !nsTextEditUtils::IsBreak(sibling)) - { - // insert br node - res = CreateBR(inNode, 0, address_of(unused)); - NS_ENSURE_SUCCESS(res, res); + nsCOMPtr sibling = GetPriorHTMLSibling(&aNode); + if (sibling && !IsBlockNode(sibling) && + !sibling->IsHTMLElement(nsGkAtoms::br)) { + sibling = GetNextHTMLSibling(&aNode); + if (sibling && !IsBlockNode(sibling) && + !sibling->IsHTMLElement(nsGkAtoms::br)) { + // Insert br node + nsCOMPtr br = CreateBR(&aNode, 0); + NS_ENSURE_STATE(br); } } } - // now remove container - return RemoveContainer(node); + // Now remove container + nsresult res = RemoveContainer(&aNode); + NS_ENSURE_SUCCESS(res, res); + + return NS_OK; } @@ -4746,7 +4728,7 @@ nsHTMLEditor::AreNodesSameType(nsIContent* aNode1, nsIContent* aNode2) nsresult nsHTMLEditor::CopyLastEditableChildStyles(nsIDOMNode * aPreviousBlock, nsIDOMNode * aNewBlock, - nsIDOMNode **aOutBrNode) + Element** aOutBrNode) { nsCOMPtr newBlock = do_QueryInterface(aNewBlock); NS_ENSURE_STATE(newBlock || !aNewBlock); @@ -4800,7 +4782,7 @@ nsHTMLEditor::CopyLastEditableChildStyles(nsIDOMNode * aPreviousBlock, nsIDOMNod childElement = childElement->GetParentElement(); } if (deepestStyle) { - *aOutBrNode = GetAsDOMNode(CreateBR(deepestStyle, 0).take()); + *aOutBrNode = CreateBR(deepestStyle, 0); NS_ENSURE_STATE(*aOutBrNode); } return NS_OK; @@ -4850,89 +4832,74 @@ nsHTMLEditor::EndUpdateViewBatch() } NS_IMETHODIMP -nsHTMLEditor::GetSelectionContainer(nsIDOMElement ** aReturn) +nsHTMLEditor::GetSelectionContainer(nsIDOMElement** aReturn) { - RefPtr selection = GetSelection(); - // if we don't get the selection, just skip this - if (!selection) { - return NS_ERROR_FAILURE; - } + nsCOMPtr container = + static_cast(GetAsDOMNode(GetSelectionContainer())); + NS_ENSURE_TRUE(container, NS_ERROR_FAILURE); + container.forget(aReturn); + return NS_OK; +} - nsCOMPtr focusNode; +Element* +nsHTMLEditor::GetSelectionContainer() +{ + // If we don't get the selection, just skip this + NS_ENSURE_TRUE(GetSelection(), nullptr); + + OwningNonNull selection = *GetSelection(); + + nsCOMPtr focusNode; - nsresult res; if (selection->Collapsed()) { - res = selection->GetFocusNode(getter_AddRefs(focusNode)); - NS_ENSURE_SUCCESS(res, res); + focusNode = selection->GetFocusNode(); } else { - - int32_t rangeCount; - res = selection->GetRangeCount(&rangeCount); - NS_ENSURE_SUCCESS(res, res); + int32_t rangeCount = selection->RangeCount(); if (rangeCount == 1) { - RefPtr range = selection->GetRangeAt(0); - NS_ENSURE_TRUE(range, NS_ERROR_NULL_POINTER); - nsCOMPtr startContainer, endContainer; - res = range->GetStartContainer(getter_AddRefs(startContainer)); - NS_ENSURE_SUCCESS(res, res); - res = range->GetEndContainer(getter_AddRefs(endContainer)); - NS_ENSURE_SUCCESS(res, res); - int32_t startOffset, endOffset; - res = range->GetStartOffset(&startOffset); - NS_ENSURE_SUCCESS(res, res); - res = range->GetEndOffset(&endOffset); - NS_ENSURE_SUCCESS(res, res); + nsCOMPtr startContainer = range->GetStartParent(); + int32_t startOffset = range->StartOffset(); + nsCOMPtr endContainer = range->GetEndParent(); + int32_t endOffset = range->EndOffset(); - nsCOMPtr focusElement; if (startContainer == endContainer && startOffset + 1 == endOffset) { - res = GetSelectedElement(EmptyString(), getter_AddRefs(focusElement)); - NS_ENSURE_SUCCESS(res, res); - if (focusElement) + nsCOMPtr focusElement; + nsresult res = GetSelectedElement(EmptyString(), + getter_AddRefs(focusElement)); + NS_ENSURE_SUCCESS(res, nullptr); + if (focusElement) { focusNode = do_QueryInterface(focusElement); + } } if (!focusNode) { - res = range->GetCommonAncestorContainer(getter_AddRefs(focusNode)); - NS_ENSURE_SUCCESS(res, res); + focusNode = range->GetCommonAncestor(); } - } - else { - int32_t i; - RefPtr range; - for (i = 0; i < rangeCount; i++) - { - range = selection->GetRangeAt(i); - NS_ENSURE_STATE(range); - nsCOMPtr startContainer; - res = range->GetStartContainer(getter_AddRefs(startContainer)); - if (NS_FAILED(res)) continue; - if (!focusNode) + } else { + for (int32_t i = 0; i < rangeCount; i++) { + RefPtr range = selection->GetRangeAt(i); + + nsCOMPtr startContainer = range->GetStartParent(); + if (!focusNode) { focusNode = startContainer; - else if (focusNode != startContainer) { - res = startContainer->GetParentNode(getter_AddRefs(focusNode)); - NS_ENSURE_SUCCESS(res, res); + } else if (focusNode != startContainer) { + focusNode = startContainer->GetParentNode(); break; } } } } - if (focusNode) { - uint16_t nodeType; - focusNode->GetNodeType(&nodeType); - if (nsIDOMNode::TEXT_NODE == nodeType) { - nsCOMPtr parent; - res = focusNode->GetParentNode(getter_AddRefs(parent)); - NS_ENSURE_SUCCESS(res, res); - focusNode = parent; - } + if (focusNode && focusNode->GetAsText()) { + focusNode = focusNode->GetParentNode(); } - nsCOMPtr focusElement = do_QueryInterface(focusNode); - focusElement.forget(aReturn); - return NS_OK; + if (focusNode && focusNode->IsElement()) { + return focusNode->AsElement(); + } + + return nullptr; } NS_IMETHODIMP diff --git a/editor/libeditor/nsHTMLEditor.h b/editor/libeditor/nsHTMLEditor.h index f41279e7df..ba1b602b4d 100644 --- a/editor/libeditor/nsHTMLEditor.h +++ b/editor/libeditor/nsHTMLEditor.h @@ -101,6 +101,7 @@ public: nsHTMLEditor(); bool GetReturnInParagraphCreatesNewParagraph(); + Element* GetSelectionContainer(); /* ------------ nsPlaintextEditor overrides -------------- */ NS_IMETHOD GetIsDocumentEditable(bool *aIsDocumentEditable) override; @@ -110,7 +111,7 @@ public: virtual already_AddRefed GetFocusedContentForIME() override; virtual bool IsActiveInDOMWindow() override; virtual already_AddRefed GetDOMEventTarget() override; - virtual mozilla::dom::Element* GetEditorRoot() override; + virtual Element* GetEditorRoot() override; virtual already_AddRefed FindSelectionRoot(nsINode *aNode) override; virtual bool IsAcceptableInputEvent(nsIDOMEvent* aEvent) override; virtual already_AddRefed GetInputEventTargetContent() override; @@ -143,7 +144,7 @@ public: /* ------------ nsIHTMLEditor methods -------------- */ nsresult CopyLastEditableChildStyles(nsIDOMNode *aPreviousBlock, nsIDOMNode *aNewBlock, - nsIDOMNode **aOutBrNode); + Element** aOutBrNode); nsresult LoadHTML(const nsAString &aInputString); @@ -232,9 +233,9 @@ public: nsresult SetHTMLBackgroundColor(const nsAString& aColor); /* ------------ Block methods moved from nsEditor -------------- */ - static mozilla::dom::Element* GetBlockNodeParent(nsINode* aNode); + static Element* GetBlockNodeParent(nsINode* aNode); static nsIDOMNode* GetBlockNodeParent(nsIDOMNode* aNode); - static mozilla::dom::Element* GetBlock(nsINode& aNode); + static Element* GetBlock(nsINode& aNode); void IsNextCharInNodeWhitespace(nsIContent* aContent, int32_t aOffset, @@ -298,7 +299,7 @@ public: virtual bool IsContainer(nsIDOMNode* aNode) override; /** make the given selection span the entire document */ - virtual nsresult SelectEntireDocument(mozilla::dom::Selection* aSelection) override; + virtual nsresult SelectEntireDocument(Selection* aSelection) override; NS_IMETHOD SetAttributeOrEquivalent(nsIDOMElement * aElement, const nsAString & aAttribute, @@ -350,8 +351,8 @@ public: // This will stop at a table, however, since we don't want to // "drill down" into nested tables. // aSelection is optional -- if null, we get current seletion - void CollapseSelectionToDeepestNonTableFirstChild( - mozilla::dom::Selection* aSelection, nsINode* aNode); + void CollapseSelectionToDeepestNonTableFirstChild(Selection* aSelection, + nsINode* aNode); /** * aNode must be a non-null text node. @@ -395,7 +396,7 @@ public: return mCSSAware && mHTMLCSSUtils && mHTMLCSSUtils->IsCSSPrefChecked(); } - static bool HasAttributes(mozilla::dom::Element* aElement) + static bool HasAttributes(Element* aElement) { MOZ_ASSERT(aElement); uint32_t attrCount = aElement->GetAttrCount(); @@ -426,8 +427,8 @@ protected: // key event helpers NS_IMETHOD TabInTable(bool inIsShift, bool *outHandled); - already_AddRefed CreateBR(nsINode* aNode, - int32_t aOffset, EDirection aSelect = eNone); + Element* CreateBR(nsINode* aNode, int32_t aOffset, + EDirection aSelect = eNone); NS_IMETHOD CreateBR(nsIDOMNode *aNode, int32_t aOffset, nsCOMPtr *outBRNode, nsIEditor::EDirection aSelect = nsIEditor::eNone) override; @@ -449,8 +450,7 @@ protected: // Move all contents from aCellToMerge into aTargetCell (append at end) NS_IMETHOD MergeCells(nsCOMPtr aTargetCell, nsCOMPtr aCellToMerge, bool aDeleteCellToMerge); - nsresult DeleteTable2(nsIDOMElement* aTable, - mozilla::dom::Selection* aSelection); + nsresult DeleteTable2(nsIDOMElement* aTable, Selection* aSelection); NS_IMETHOD SetColSpan(nsIDOMElement *aCell, int32_t aColSpan); NS_IMETHOD SetRowSpan(nsIDOMElement *aCell, int32_t aRowSpan); @@ -463,17 +463,17 @@ protected: bool AllCellsInRowSelected(nsIDOMElement *aTable, int32_t aRowIndex, int32_t aNumberOfColumns); bool AllCellsInColumnSelected(nsIDOMElement *aTable, int32_t aColIndex, int32_t aNumberOfRows); - bool IsEmptyCell(mozilla::dom::Element* aCell); + bool IsEmptyCell(Element* aCell); // Most insert methods need to get the same basic context data // Any of the pointers may be null if you don't need that datum (for more efficiency) // Input: *aCell is a known cell, // if null, cell is obtained from the anchor node of the selection // Returns NS_EDITOR_ELEMENT_NOT_FOUND if cell is not found even if aCell is null - nsresult GetCellContext(mozilla::dom::Selection** aSelection, - nsIDOMElement** aTable, nsIDOMElement** aCell, - nsIDOMNode** aCellParent, int32_t* aCellOffset, - int32_t* aRowIndex, int32_t* aColIndex); + nsresult GetCellContext(Selection** aSelection, nsIDOMElement** aTable, + nsIDOMElement** aCell, nsIDOMNode** aCellParent, + int32_t* aCellOffset, int32_t* aRowIndex, + int32_t* aColIndex); NS_IMETHOD GetCellSpansAt(nsIDOMElement* aTable, int32_t aRowIndex, int32_t aColIndex, int32_t& aActualRowSpan, int32_t& aActualColSpan); @@ -492,11 +492,11 @@ protected: // Fallback method: Call this after using ClearSelection() and you // failed to set selection to some other content in the document - nsresult SetSelectionAtDocumentStart(mozilla::dom::Selection* aSelection); + nsresult SetSelectionAtDocumentStart(Selection* aSelection); // End of Table Editing utilities - static mozilla::dom::Element* GetEnclosingTable(nsINode* aNode); + static Element* GetEnclosingTable(nsINode* aNode); static nsIDOMNode* GetEnclosingTable(nsIDOMNode *aNode); /** content-based query returns true if effects aNode @@ -597,7 +597,7 @@ protected: mozilla::dom::DocumentFragment** aFragment, bool aTrustedInput); void CreateListOfNodesToPaste(mozilla::dom::DocumentFragment& aFragment, - nsTArray>& outNodeList, + nsTArray>& outNodeList, nsINode* aStartNode, int32_t aStartOffset, nsINode* aEndNode, @@ -606,25 +606,24 @@ protected: nsIDOMNode *aNode); enum class StartOrEnd { start, end }; void GetListAndTableParents(StartOrEnd aStartOrEnd, - nsTArray>& aNodeList, - nsTArray>& outArray); - int32_t DiscoverPartialListsAndTables(nsTArray>& aPasteNodes, - nsTArray>& aListsAndTables); + nsTArray>& aNodeList, + nsTArray>& outArray); + int32_t DiscoverPartialListsAndTables(nsTArray>& aPasteNodes, + nsTArray>& aListsAndTables); nsINode* ScanForListAndTableStructure(StartOrEnd aStartOrEnd, - nsTArray>& aNodes, - mozilla::dom::Element& aListOrTable); + nsTArray>& aNodes, + Element& aListOrTable); void ReplaceOrphanedStructure(StartOrEnd aStartOrEnd, - nsTArray>& aNodeArray, - nsTArray>& aListAndTableArray, + nsTArray>& aNodeArray, + nsTArray>& aListAndTableArray, int32_t aHighWaterMark); /* small utility routine to test if a break node is visible to user */ bool IsVisBreak(nsINode* aNode); - bool IsVisBreak(nsIDOMNode *aNode); /* utility routine to possibly adjust the insertion position when inserting a block level element */ - void NormalizeEOLInsertPosition(nsIDOMNode *firstNodeToInsert, + void NormalizeEOLInsertPosition(nsINode* firstNodeToInsert, nsCOMPtr *insertParentNode, int32_t *insertOffset); @@ -640,15 +639,15 @@ protected: nsresult RelativeFontChange(FontSize aDir); /* helper routines for font size changing */ - nsresult RelativeFontChangeOnTextNode( int32_t aSizeChange, - nsIDOMCharacterData *aTextNode, - int32_t aStartOffset, - int32_t aEndOffset); + nsresult RelativeFontChangeOnTextNode(FontSize aDir, + Text& aTextNode, + int32_t aStartOffset, + int32_t aEndOffset); nsresult RelativeFontChangeOnNode(int32_t aSizeChange, nsIContent* aNode); nsresult RelativeFontChangeHelper(int32_t aSizeChange, nsINode* aNode); /* helper routines for inline style */ - nsresult SetInlinePropertyOnTextNode(mozilla::dom::Text& aData, + nsresult SetInlinePropertyOnTextNode(Text& aData, int32_t aStartOffset, int32_t aEndOffset, nsIAtom& aProperty, @@ -659,22 +658,17 @@ protected: const nsAString* aAttribute, const nsAString& aValue); - nsresult PromoteInlineRange(nsRange* aRange); - nsresult PromoteRangeIfStartsOrEndsInNamedAnchor(nsRange* aRange); + nsresult PromoteInlineRange(nsRange& aRange); + nsresult PromoteRangeIfStartsOrEndsInNamedAnchor(nsRange& aRange); nsresult SplitStyleAboveRange(nsRange* aRange, nsIAtom *aProperty, const nsAString *aAttribute); - nsresult SplitStyleAbovePoint(nsCOMPtr *aNode, - int32_t *aOffset, - nsIAtom *aProperty, - const nsAString *aAttribute, - nsCOMPtr *outLeftNode = nullptr, - nsCOMPtr *outRightNode = nullptr); + nsresult SplitStyleAbovePoint(nsCOMPtr* aNode, int32_t* aOffset, + nsIAtom* aProperty, + const nsAString* aAttribute, + nsIContent** aOutLeftNode = nullptr, + nsIContent** aOutRightNode = nullptr); nsresult ApplyDefaultProperties(); - nsresult RemoveStyleInside(nsIDOMNode *aNode, - nsIAtom *aProperty, - const nsAString *aAttribute, - const bool aChildrenOnly = false); nsresult RemoveStyleInside(nsIContent& aNode, nsIAtom* aProperty, const nsAString* aAttribute, @@ -682,14 +676,12 @@ protected: nsresult RemoveInlinePropertyImpl(nsIAtom* aProperty, const nsAString* aAttribute); - bool NodeIsProperty(nsIDOMNode *aNode); - bool HasAttr(nsIDOMNode *aNode, const nsAString *aAttribute); - bool IsAtFrontOfNode(nsIDOMNode *aNode, int32_t aOffset); - bool IsAtEndOfNode(nsIDOMNode *aNode, int32_t aOffset); - bool IsOnlyAttribute(nsIDOMNode *aElement, const nsAString *aAttribute); + bool NodeIsProperty(nsINode& aNode); + bool IsAtFrontOfNode(nsINode& aNode, int32_t aOffset); + bool IsAtEndOfNode(nsINode& aNode, int32_t aOffset); bool IsOnlyAttribute(const nsIContent* aElement, const nsAString& aAttribute); - nsresult RemoveBlockContainer(nsIDOMNode *inNode); + nsresult RemoveBlockContainer(nsIContent& aNode); nsIContent* GetPriorHTMLSibling(nsINode* aNode); nsresult GetPriorHTMLSibling(nsIDOMNode *inNode, nsCOMPtr *outNode); @@ -729,8 +721,8 @@ protected: bool* aAll, nsAString* outValue, bool aCheckDefaults = true); - bool HasStyleOrIdOrClass(mozilla::dom::Element* aElement); - nsresult RemoveElementIfNoStyleOrIdOrClass(mozilla::dom::Element& aElement); + bool HasStyleOrIdOrClass(Element* aElement); + nsresult RemoveElementIfNoStyleOrIdOrClass(Element& aElement); // Whether the outer window of the DOM event target has focus or not. bool OurWindowHasFocus(); @@ -756,13 +748,15 @@ protected: bool aTrustedInput, bool aClearStyle = true); - nsresult ClearStyle(nsCOMPtr* aNode, int32_t* aOffset, + nsresult ClearStyle(nsCOMPtr* aNode, int32_t* aOffset, nsIAtom* aProperty, const nsAString* aAttribute); + void SetElementPosition(Element& aElement, int32_t aX, int32_t aY); + // Data members protected: - nsTArray> mContentFilters; + nsTArray> mContentFilters; RefPtr mTypeInState; @@ -790,7 +784,7 @@ protected: void RemoveListenerAndDeleteRef(const nsAString& aEvent, nsIDOMEventListener* aListener, bool aUseCapture, - mozilla::dom::Element* aElement, + Element* aElement, nsIContent* aParentContent, nsIPresShell* aShell); void DeleteRefToAnonymousNode(nsIDOMElement* aElement, @@ -836,27 +830,27 @@ protected: /* RESIZING */ - nsCOMPtr mTopLeftHandle; - nsCOMPtr mTopHandle; - nsCOMPtr mTopRightHandle; - nsCOMPtr mLeftHandle; - nsCOMPtr mRightHandle; - nsCOMPtr mBottomLeftHandle; - nsCOMPtr mBottomHandle; - nsCOMPtr mBottomRightHandle; + nsCOMPtr mTopLeftHandle; + nsCOMPtr mTopHandle; + nsCOMPtr mTopRightHandle; + nsCOMPtr mLeftHandle; + nsCOMPtr mRightHandle; + nsCOMPtr mBottomLeftHandle; + nsCOMPtr mBottomHandle; + nsCOMPtr mBottomRightHandle; - nsCOMPtr mActivatedHandle; + nsCOMPtr mActivatedHandle; - nsCOMPtr mResizingShadow; - nsCOMPtr mResizingInfo; + nsCOMPtr mResizingShadow; + nsCOMPtr mResizingInfo; - nsCOMPtr mResizedObject; + nsCOMPtr mResizedObject; nsCOMPtr mMouseMotionListenerP; nsCOMPtr mSelectionListenerP; nsCOMPtr mResizeEventListenerP; - nsTArray> mObjectResizeEventListeners; + nsTArray> mObjectResizeEventListeners; int32_t mOriginalX; int32_t mOriginalY; @@ -881,18 +875,17 @@ protected: nsresult SetAllResizersPosition(); - already_AddRefed - CreateResizer(int16_t aLocation, nsIDOMNode* aParentNode); + already_AddRefed CreateResizer(int16_t aLocation, + nsIDOMNode* aParentNode); void SetAnonymousElementPosition(int32_t aX, int32_t aY, nsIDOMElement *aResizer); - already_AddRefed - CreateShadow(nsIDOMNode* aParentNode, nsIDOMElement* aOriginalObject); - nsresult SetShadowPosition(mozilla::dom::Element* aShadow, - mozilla::dom::Element* aOriginalObject, + already_AddRefed CreateShadow(nsIDOMNode* aParentNode, + nsIDOMElement* aOriginalObject); + nsresult SetShadowPosition(Element* aShadow, Element* aOriginalObject, int32_t aOriginalObjectX, int32_t aOriginalObjectY); - already_AddRefed CreateResizingInfo(nsIDOMNode* aParentNode); + already_AddRefed CreateResizingInfo(nsIDOMNode* aParentNode); nsresult SetResizingInfoPosition(int32_t aX, int32_t aY, int32_t aW, int32_t aH); @@ -920,13 +913,13 @@ protected: int32_t mPositionedObjectBorderLeft; int32_t mPositionedObjectBorderTop; - nsCOMPtr mAbsolutelyPositionedObject; - nsCOMPtr mGrabber; - nsCOMPtr mPositioningShadow; + nsCOMPtr mAbsolutelyPositionedObject; + nsCOMPtr mGrabber; + nsCOMPtr mPositioningShadow; int32_t mGridSize; - already_AddRefed CreateGrabber(nsINode* aParentNode); + already_AddRefed CreateGrabber(nsINode* aParentNode); nsresult StartMoving(nsIDOMElement * aHandle); nsresult SetFinalPosition(int32_t aX, int32_t aY); void AddPositioningOffset(int32_t & aX, int32_t & aY); @@ -975,9 +968,9 @@ private: void DoContentInserted(nsIDocument* aDocument, nsIContent* aContainer, nsIContent* aChild, int32_t aIndexInContainer, InsertedOrAppended aInsertedOrAppended); - already_AddRefed GetElementOrParentByTagName( + already_AddRefed GetElementOrParentByTagName( const nsAString& aTagName, nsINode* aNode); - already_AddRefed CreateElementWithDefaults( + already_AddRefed CreateElementWithDefaults( const nsAString& aTagName); }; #endif //nsHTMLEditor_h__ diff --git a/editor/libeditor/nsHTMLEditorStyle.cpp b/editor/libeditor/nsHTMLEditorStyle.cpp index f55dcc8d1d..847d06b097 100644 --- a/editor/libeditor/nsHTMLEditorStyle.cpp +++ b/editor/libeditor/nsHTMLEditorStyle.cpp @@ -25,9 +25,7 @@ #include "nsIAtom.h" #include "nsIContent.h" #include "nsIContentIterator.h" -#include "nsIDOMCharacterData.h" #include "nsIDOMElement.h" -#include "nsIDOMNode.h" #include "nsIEditor.h" #include "nsIEditorIMESupport.h" #include "nsNameSpaceManager.h" @@ -145,7 +143,7 @@ nsHTMLEditor::SetInlineProperty(nsIAtom* aProperty, // Adjust range to include any ancestors whose children are entirely // selected - res = PromoteInlineRange(range); + res = PromoteInlineRange(*range); NS_ENSURE_SUCCESS(res, res); // Check for easy case: both range endpoints in same text node @@ -523,29 +521,25 @@ nsHTMLEditor::SplitStyleAboveRange(nsRange* inRange, nsIAtom* aProperty, { NS_ENSURE_TRUE(inRange, NS_ERROR_NULL_POINTER); nsresult res; - nsCOMPtr startNode, endNode, origStartNode; - int32_t startOffset, endOffset; - res = inRange->GetStartContainer(getter_AddRefs(startNode)); - NS_ENSURE_SUCCESS(res, res); - res = inRange->GetStartOffset(&startOffset); - NS_ENSURE_SUCCESS(res, res); - res = inRange->GetEndContainer(getter_AddRefs(endNode)); - NS_ENSURE_SUCCESS(res, res); - res = inRange->GetEndOffset(&endOffset); - NS_ENSURE_SUCCESS(res, res); + nsCOMPtr startNode = inRange->GetStartParent(); + int32_t startOffset = inRange->StartOffset(); + nsCOMPtr endNode = inRange->GetEndParent(); + int32_t endOffset = inRange->EndOffset(); - origStartNode = startNode; + nsCOMPtr origStartNode = startNode; // split any matching style nodes above the start of range { nsAutoTrackDOMPoint tracker(mRangeUpdater, address_of(endNode), &endOffset); - res = SplitStyleAbovePoint(address_of(startNode), &startOffset, aProperty, aAttribute); + res = SplitStyleAbovePoint(address_of(startNode), &startOffset, aProperty, + aAttribute); NS_ENSURE_SUCCESS(res, res); } // second verse, same as the first... - res = SplitStyleAbovePoint(address_of(endNode), &endOffset, aProperty, aAttribute); + res = SplitStyleAbovePoint(address_of(endNode), &endOffset, aProperty, + aAttribute); NS_ENSURE_SUCCESS(res, res); // reset the range @@ -555,30 +549,32 @@ nsHTMLEditor::SplitStyleAboveRange(nsRange* inRange, nsIAtom* aProperty, return res; } -nsresult nsHTMLEditor::SplitStyleAbovePoint(nsCOMPtr *aNode, - int32_t *aOffset, - nsIAtom *aProperty, // null here means we split all properties - const nsAString *aAttribute, - nsCOMPtr *outLeftNode, - nsCOMPtr *outRightNode) +nsresult +nsHTMLEditor::SplitStyleAbovePoint(nsCOMPtr* aNode, + int32_t* aOffset, + // null here means we split all properties + nsIAtom* aProperty, + const nsAString* aAttribute, + nsIContent** aOutLeftNode, + nsIContent** aOutRightNode) { NS_ENSURE_TRUE(aNode && *aNode && aOffset, NS_ERROR_NULL_POINTER); - if (outLeftNode) *outLeftNode = nullptr; - if (outRightNode) *outRightNode = nullptr; - // split any matching style nodes above the node/offset - nsCOMPtr node = do_QueryInterface(*aNode); - NS_ENSURE_STATE(node); - int32_t offset; + NS_ENSURE_TRUE((*aNode)->IsContent(), NS_OK); + + // Split any matching style nodes above the node/offset + OwningNonNull node = *(*aNode)->AsContent(); bool useCSS = IsCSSEnabled(); bool isSet; - while (node && !IsBlockNode(node) && node->GetParentNode() && - IsEditable(node->GetParentNode())) { + while (!IsBlockNode(node) && node->GetParent() && + IsEditable(node->GetParent())) { isSet = false; - if (useCSS && mHTMLCSSUtils->IsCSSEditableProperty(node, aProperty, aAttribute)) { - // the HTML style defined by aProperty/aAttribute has a CSS equivalence - // in this implementation for the node; let's check if it carries those css styles + if (useCSS && mHTMLCSSUtils->IsCSSEditableProperty(node, aProperty, + aAttribute)) { + // The HTML style defined by aProperty/aAttribute has a CSS equivalence + // in this implementation for the node; let's check if it carries those + // CSS styles nsAutoString firstValue; mHTMLCSSUtils->IsCSSEquivalentToHTMLInlineStyleSet(GetAsDOMNode(node), aProperty, aAttribute, isSet, firstValue, nsHTMLCSSUtils::eSpecified); @@ -588,41 +584,34 @@ nsresult nsHTMLEditor::SplitStyleAbovePoint(nsCOMPtr *aNode, // node is href - test if really outLeftContent, outRightContent; - nsCOMPtr nodeParam = do_QueryInterface(*aNode); - NS_ENSURE_STATE(nodeParam || !*aNode); - offset = SplitNodeDeep(*node, *nodeParam, *aOffset, EmptyContainers::yes, - getter_AddRefs(outLeftContent), - getter_AddRefs(outRightContent)); + // Found a style node we need to split + int32_t offset = SplitNodeDeep(*node, *(*aNode)->AsContent(), *aOffset, + EmptyContainers::yes, aOutLeftNode, + aOutRightNode); NS_ENSURE_TRUE(offset != -1, NS_ERROR_FAILURE); // reset startNode/startOffset - *aNode = GetAsDOMNode(node->GetParent()); + *aNode = node->GetParent(); *aOffset = offset; - if (outLeftNode) { - *outLeftNode = GetAsDOMNode(outLeftContent); - } - if (outRightNode) { - *outRightNode = GetAsDOMNode(outRightContent); - } } node = node->GetParent(); } + return NS_OK; } nsresult -nsHTMLEditor::ClearStyle(nsCOMPtr* aNode, int32_t* aOffset, +nsHTMLEditor::ClearStyle(nsCOMPtr* aNode, int32_t* aOffset, nsIAtom* aProperty, const nsAString* aAttribute) { - nsCOMPtr leftNode, rightNode, tmp; - nsresult res = SplitStyleAbovePoint(aNode, aOffset, aProperty, aAttribute, - address_of(leftNode), - address_of(rightNode)); + nsCOMPtr leftNode, rightNode; + nsresult res = SplitStyleAbovePoint(aNode, aOffset, aProperty, + aAttribute, getter_AddRefs(leftNode), + getter_AddRefs(rightNode)); NS_ENSURE_SUCCESS(res, res); + if (leftNode) { bool bIsEmptyNode; IsEmptyNode(leftNode, &bIsEmptyNode, false, true); @@ -633,10 +622,7 @@ nsHTMLEditor::ClearStyle(nsCOMPtr* aNode, int32_t* aOffset, } } if (rightNode) { - nsCOMPtr rightNode_ = do_QueryInterface(rightNode); - NS_ENSURE_STATE(rightNode_); - nsCOMPtr secondSplitParent = - GetAsDOMNode(GetLeftmostChild(rightNode_)); + nsCOMPtr secondSplitParent = GetLeftmostChild(rightNode); // don't try to split non-containers (br's, images, hr's, etc) if (!secondSplitParent) { secondSplitParent = rightNode; @@ -648,21 +634,18 @@ nsHTMLEditor::ClearStyle(nsCOMPtr* aNode, int32_t* aOffset, NS_ENSURE_STATE(savedBR); } - secondSplitParent->GetParentNode(getter_AddRefs(tmp)); - secondSplitParent = tmp; + secondSplitParent = secondSplitParent->GetParentNode(); } *aOffset = 0; res = SplitStyleAbovePoint(address_of(secondSplitParent), aOffset, aProperty, aAttribute, - address_of(leftNode), address_of(rightNode)); + getter_AddRefs(leftNode), + getter_AddRefs(rightNode)); NS_ENSURE_SUCCESS(res, res); // should be impossible to not get a new leftnode here - nsCOMPtr leftNode_ = do_QueryInterface(leftNode); - NS_ENSURE_TRUE(leftNode_, NS_ERROR_FAILURE); - nsCOMPtr newSelParent = GetLeftmostChild(leftNode_); + nsCOMPtr newSelParent = GetLeftmostChild(leftNode); if (!newSelParent) { - newSelParent = do_QueryInterface(leftNode); - NS_ENSURE_STATE(newSelParent); + newSelParent = leftNode; } // If rightNode starts with a br, suck it out of right node and into // leftNode. This is so we you don't revert back to the previous style @@ -688,27 +671,22 @@ nsHTMLEditor::ClearStyle(nsCOMPtr* aNode, int32_t* aOffset, // selection. nsAutoTrackDOMPoint tracker(mRangeUpdater, address_of(newSelParent), &newSelOffset); - res = RemoveStyleInside(leftNode, aProperty, aAttribute); + res = RemoveStyleInside(*leftNode, aProperty, aAttribute); NS_ENSURE_SUCCESS(res, res); } // reset our node offset values to the resulting new sel point - *aNode = GetAsDOMNode(newSelParent); + *aNode = newSelParent; *aOffset = newSelOffset; } return NS_OK; } -bool nsHTMLEditor::NodeIsProperty(nsIDOMNode *aNode) +bool +nsHTMLEditor::NodeIsProperty(nsINode& aNode) { - NS_ENSURE_TRUE(aNode, false); - if (!IsContainer(aNode)) return false; - if (!IsEditable(aNode)) return false; - if (IsBlockNode(aNode)) return false; - if (NodeIsType(aNode, nsGkAtoms::a)) { - return false; - } - return true; + return IsContainer(&aNode) && IsEditable(&aNode) && !IsBlockNode(&aNode) && + !aNode.IsHTMLElement(nsGkAtoms::a); } nsresult nsHTMLEditor::ApplyDefaultProperties() @@ -725,26 +703,13 @@ nsresult nsHTMLEditor::ApplyDefaultProperties() return res; } -nsresult nsHTMLEditor::RemoveStyleInside(nsIDOMNode *aNode, - // null here means remove all properties - nsIAtom *aProperty, - const nsAString *aAttribute, - const bool aChildrenOnly) -{ - NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER); - nsCOMPtr content = do_QueryInterface(aNode); - NS_ENSURE_STATE(content); - - return RemoveStyleInside(*content, aProperty, aAttribute, aChildrenOnly); -} - nsresult nsHTMLEditor::RemoveStyleInside(nsIContent& aNode, nsIAtom* aProperty, const nsAString* aAttribute, const bool aChildrenOnly /* = false */) { - if (aNode.NodeType() == nsIDOMNode::TEXT_NODE) { + if (aNode.GetAsText()) { return NS_OK; } @@ -768,7 +733,7 @@ nsHTMLEditor::RemoveStyleInside(nsIContent& aNode, // and for named anchors (aProperty == nsGkAtoms::name && nsHTMLEditUtils::IsNamedAnchor(&aNode)) || // or node is any prop and we asked for that - (!aProperty && NodeIsProperty(aNode.AsDOMNode())) + (!aProperty && NodeIsProperty(aNode)) ) ) { nsresult res; @@ -849,17 +814,6 @@ nsHTMLEditor::RemoveStyleInside(nsIContent& aNode, return NS_OK; } -bool nsHTMLEditor::IsOnlyAttribute(nsIDOMNode *aNode, - const nsAString *aAttribute) -{ - NS_ENSURE_TRUE(aNode && aAttribute, false); // ooops - - nsCOMPtr content = do_QueryInterface(aNode); - NS_ENSURE_TRUE(content, false); // ooops - - return IsOnlyAttribute(content, *aAttribute); -} - bool nsHTMLEditor::IsOnlyAttribute(const nsIContent* aContent, const nsAString& aAttribute) @@ -887,166 +841,117 @@ nsHTMLEditor::IsOnlyAttribute(const nsIContent* aContent, return true; } -bool nsHTMLEditor::HasAttr(nsIDOMNode* aNode, - const nsAString* aAttribute) -{ - NS_ENSURE_TRUE(aNode, false); - if (!aAttribute || aAttribute->IsEmpty()) { - // everybody has the 'null' attribute - return true; - } - - // get element - nsCOMPtr element = do_QueryInterface(aNode); - NS_ENSURE_TRUE(element, false); - - nsCOMPtr atom = NS_Atomize(*aAttribute); - NS_ENSURE_TRUE(atom, false); - - return element->HasAttr(kNameSpaceID_None, atom); -} - - nsresult -nsHTMLEditor::PromoteRangeIfStartsOrEndsInNamedAnchor(nsRange* inRange) +nsHTMLEditor::PromoteRangeIfStartsOrEndsInNamedAnchor(nsRange& aRange) { - NS_ENSURE_TRUE(inRange, NS_ERROR_NULL_POINTER); - nsresult res; - nsCOMPtr startNode, endNode, parent, tmp; - int32_t startOffset, endOffset, tmpOffset; + // We assume that is not nested. + nsCOMPtr startNode = aRange.GetStartParent(); + int32_t startOffset = aRange.StartOffset(); + nsCOMPtr endNode = aRange.GetEndParent(); + int32_t endOffset = aRange.EndOffset(); - res = inRange->GetStartContainer(getter_AddRefs(startNode)); - NS_ENSURE_SUCCESS(res, res); - res = inRange->GetStartOffset(&startOffset); - NS_ENSURE_SUCCESS(res, res); - res = inRange->GetEndContainer(getter_AddRefs(endNode)); - NS_ENSURE_SUCCESS(res, res); - res = inRange->GetEndOffset(&endOffset); - NS_ENSURE_SUCCESS(res, res); + nsCOMPtr parent = startNode; - tmp = startNode; - while ( tmp && - !nsTextEditUtils::IsBody(tmp) && - !nsHTMLEditUtils::IsNamedAnchor(tmp)) - { - parent = GetNodeLocation(tmp, &tmpOffset); - tmp = parent; + while (parent && !parent->IsHTMLElement(nsGkAtoms::body) && + !nsHTMLEditUtils::IsNamedAnchor(parent)) { + parent = parent->GetParentNode(); } - NS_ENSURE_TRUE(tmp, NS_ERROR_NULL_POINTER); - if (nsHTMLEditUtils::IsNamedAnchor(tmp)) - { - parent = GetNodeLocation(tmp, &tmpOffset); - startNode = parent; - startOffset = tmpOffset; + NS_ENSURE_TRUE(parent, NS_ERROR_NULL_POINTER); + + if (nsHTMLEditUtils::IsNamedAnchor(parent)) { + startNode = parent->GetParentNode(); + startOffset = startNode ? startNode->IndexOf(parent) : -1; } - tmp = endNode; - while ( tmp && - !nsTextEditUtils::IsBody(tmp) && - !nsHTMLEditUtils::IsNamedAnchor(tmp)) - { - parent = GetNodeLocation(tmp, &tmpOffset); - tmp = parent; + parent = endNode; + while (parent && !parent->IsHTMLElement(nsGkAtoms::body) && + !nsHTMLEditUtils::IsNamedAnchor(parent)) { + parent = parent->GetParentNode(); } - NS_ENSURE_TRUE(tmp, NS_ERROR_NULL_POINTER); - if (nsHTMLEditUtils::IsNamedAnchor(tmp)) - { - parent = GetNodeLocation(tmp, &tmpOffset); - endNode = parent; - endOffset = tmpOffset + 1; + NS_ENSURE_TRUE(parent, NS_ERROR_NULL_POINTER); + + if (nsHTMLEditUtils::IsNamedAnchor(parent)) { + endNode = parent->GetParentNode(); + endOffset = endNode ? endNode->IndexOf(parent) + 1 : 0; } - res = inRange->SetStart(startNode, startOffset); + nsresult res = aRange.SetStart(startNode, startOffset); NS_ENSURE_SUCCESS(res, res); - res = inRange->SetEnd(endNode, endOffset); - return res; + res = aRange.SetEnd(endNode, endOffset); + NS_ENSURE_SUCCESS(res, res); + + return NS_OK; } nsresult -nsHTMLEditor::PromoteInlineRange(nsRange* inRange) +nsHTMLEditor::PromoteInlineRange(nsRange& aRange) { - NS_ENSURE_TRUE(inRange, NS_ERROR_NULL_POINTER); - nsresult res; - nsCOMPtr startNode, endNode, parent; - int32_t startOffset, endOffset; + nsCOMPtr startNode = aRange.GetStartParent(); + int32_t startOffset = aRange.StartOffset(); + nsCOMPtr endNode = aRange.GetEndParent(); + int32_t endOffset = aRange.EndOffset(); - res = inRange->GetStartContainer(getter_AddRefs(startNode)); - NS_ENSURE_SUCCESS(res, res); - res = inRange->GetStartOffset(&startOffset); - NS_ENSURE_SUCCESS(res, res); - res = inRange->GetEndContainer(getter_AddRefs(endNode)); - NS_ENSURE_SUCCESS(res, res); - res = inRange->GetEndOffset(&endOffset); - NS_ENSURE_SUCCESS(res, res); - - while ( startNode && - !nsTextEditUtils::IsBody(startNode) && - IsEditable(startNode) && - IsAtFrontOfNode(startNode, startOffset) ) - { - parent = GetNodeLocation(startNode, &startOffset); + while (startNode && !startNode->IsHTMLElement(nsGkAtoms::body) && + IsEditable(startNode) && IsAtFrontOfNode(*startNode, startOffset)) { + nsCOMPtr parent = startNode->GetParentNode(); + NS_ENSURE_TRUE(parent, NS_ERROR_NULL_POINTER); + startOffset = parent->IndexOf(startNode); startNode = parent; } - NS_ENSURE_TRUE(startNode, NS_ERROR_NULL_POINTER); - while ( endNode && - !nsTextEditUtils::IsBody(endNode) && - IsEditable(endNode) && - IsAtEndOfNode(endNode, endOffset) ) - { - parent = GetNodeLocation(endNode, &endOffset); + while (endNode && !endNode->IsHTMLElement(nsGkAtoms::body) && + IsEditable(endNode) && IsAtEndOfNode(*endNode, endOffset)) { + nsCOMPtr parent = endNode->GetParentNode(); + NS_ENSURE_TRUE(parent, NS_ERROR_NULL_POINTER); + // We are AFTER this node + endOffset = 1 + parent->IndexOf(endNode); endNode = parent; - endOffset++; // we are AFTER this node } - NS_ENSURE_TRUE(endNode, NS_ERROR_NULL_POINTER); - res = inRange->SetStart(startNode, startOffset); + nsresult res = aRange.SetStart(startNode, startOffset); NS_ENSURE_SUCCESS(res, res); - res = inRange->SetEnd(endNode, endOffset); - return res; + res = aRange.SetEnd(endNode, endOffset); + NS_ENSURE_SUCCESS(res, res); + + return NS_OK; } -bool nsHTMLEditor::IsAtFrontOfNode(nsIDOMNode *aNode, int32_t aOffset) +bool +nsHTMLEditor::IsAtFrontOfNode(nsINode& aNode, int32_t aOffset) { - nsCOMPtr node = do_QueryInterface(aNode); - NS_ENSURE_TRUE(node, false); if (!aOffset) { return true; } - if (IsTextNode(aNode)) - { + if (IsTextNode(&aNode)) { return false; } - else - { - nsCOMPtr firstNode = GetFirstEditableChild(*node); - NS_ENSURE_TRUE(firstNode, true); - int32_t offset = node->IndexOf(firstNode); - if (offset < aOffset) return false; - return true; + + nsCOMPtr firstNode = GetFirstEditableChild(aNode); + NS_ENSURE_TRUE(firstNode, true); + if (aNode.IndexOf(firstNode) < aOffset) { + return false; } + return true; } -bool nsHTMLEditor::IsAtEndOfNode(nsIDOMNode *aNode, int32_t aOffset) +bool +nsHTMLEditor::IsAtEndOfNode(nsINode& aNode, int32_t aOffset) { - nsCOMPtr node = do_QueryInterface(aNode); - NS_ENSURE_TRUE(node, false); - uint32_t len = node->Length(); - if (aOffset == (int32_t)len) return true; + if (aOffset == (int32_t)aNode.Length()) { + return true; + } - if (IsTextNode(aNode)) - { + if (IsTextNode(&aNode)) { return false; } - else - { - nsCOMPtr lastNode = GetLastEditableChild(*node); - NS_ENSURE_TRUE(lastNode, true); - int32_t offset = node->IndexOf(lastNode); - if (offset < aOffset) return true; - return false; + + nsCOMPtr lastNode = GetLastEditableChild(aNode); + NS_ENSURE_TRUE(lastNode, true); + if (aNode.IndexOf(lastNode) < aOffset) { + return true; } + return false; } @@ -1321,7 +1226,7 @@ nsHTMLEditor::RemoveInlinePropertyImpl(nsIAtom* aProperty, // Loop through the ranges in the selection uint32_t rangeCount = selection->RangeCount(); for (uint32_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) { - RefPtr range = selection->GetRangeAt(rangeIdx); + OwningNonNull range = *selection->GetRangeAt(rangeIdx); if (aProperty == nsGkAtoms::name) { // Promote range if it starts or end in a named anchor and we want to // remove named anchors @@ -1368,21 +1273,21 @@ nsHTMLEditor::RemoveInlinePropertyImpl(nsIAtom* aProperty, // Not the easy case. Range not contained in single text node. nsCOMPtr iter = NS_NewContentSubtreeIterator(); - nsTArray> arrayOfNodes; + nsTArray> arrayOfNodes; // Iterate range and build up array for (iter->Init(range); !iter->IsDone(); iter->Next()) { nsCOMPtr node = iter->GetCurrentNode(); NS_ENSURE_TRUE(node, NS_ERROR_FAILURE); - if (IsEditable(node)) { - arrayOfNodes.AppendElement(node); + if (IsEditable(node) && node->IsContent()) { + arrayOfNodes.AppendElement(*node->AsContent()); } } // Loop through the list, remove the property on each node for (auto& node : arrayOfNodes) { - res = RemoveStyleInside(GetAsDOMNode(node), aProperty, aAttribute); + res = RemoveStyleInside(node, aProperty, aAttribute); NS_ENSURE_SUCCESS(res, res); if (IsCSSEnabled() && mHTMLCSSUtils->IsCSSEditableProperty(node, aProperty, @@ -1397,8 +1302,7 @@ nsHTMLEditor::RemoveInlinePropertyImpl(nsIAtom* aProperty, // "inverting" the style mHTMLCSSUtils->IsCSSInvertible(*aProperty, aAttribute)) { NS_NAMED_LITERAL_STRING(value, "-moz-editor-invert-value"); - SetInlinePropertyOnNode(*node->AsContent(), *aProperty, - aAttribute, value); + SetInlinePropertyOnNode(node, *aProperty, aAttribute, value); } } } @@ -1467,16 +1371,16 @@ nsHTMLEditor::RelativeFontChange(FontSize aDir) RefPtr range = selection->GetRangeAt(rangeIdx); // Adjust range to include any ancestors with entirely selected children - nsresult res = PromoteInlineRange(range); + nsresult res = PromoteInlineRange(*range); NS_ENSURE_SUCCESS(res, res); // Check for easy case: both range endpoints in same text node nsCOMPtr startNode = range->GetStartParent(); nsCOMPtr endNode = range->GetEndParent(); if (startNode == endNode && IsTextNode(startNode)) { - res = RelativeFontChangeOnTextNode(aDir == FontSize::incr ? +1 : -1, - static_cast(startNode->AsDOMNode()), - range->StartOffset(), range->EndOffset()); + res = RelativeFontChangeOnTextNode(aDir, *startNode->GetAsText(), + range->StartOffset(), + range->EndOffset()); NS_ENSURE_SUCCESS(res, res); } else { // Not the easy case. Range not contained in single text node. There @@ -1516,15 +1420,14 @@ nsHTMLEditor::RelativeFontChange(FontSize aDir) // to be separately handled (they do if they are text nodes, due to how // the subtree iterator works - it will not have reported them). if (IsTextNode(startNode) && IsEditable(startNode)) { - res = RelativeFontChangeOnTextNode(aDir == FontSize::incr ? +1 : -1, - static_cast(startNode->AsDOMNode()), - range->StartOffset(), startNode->Length()); + res = RelativeFontChangeOnTextNode(aDir, *startNode->GetAsText(), + range->StartOffset(), + startNode->Length()); NS_ENSURE_SUCCESS(res, res); } if (IsTextNode(endNode) && IsEditable(endNode)) { - res = RelativeFontChangeOnTextNode(aDir == FontSize::incr ? +1 : -1, - static_cast(endNode->AsDOMNode()), - 0, range->EndOffset()); + res = RelativeFontChangeOnTextNode(aDir, *endNode->GetAsText(), 0, + range->EndOffset()); NS_ENSURE_SUCCESS(res, res); } } @@ -1534,68 +1437,61 @@ nsHTMLEditor::RelativeFontChange(FontSize aDir) } nsresult -nsHTMLEditor::RelativeFontChangeOnTextNode( int32_t aSizeChange, - nsIDOMCharacterData *aTextNode, - int32_t aStartOffset, - int32_t aEndOffset) +nsHTMLEditor::RelativeFontChangeOnTextNode(FontSize aDir, + Text& aTextNode, + int32_t aStartOffset, + int32_t aEndOffset) { - // Can only change font size by + or - 1 - if ( !( (aSizeChange==1) || (aSizeChange==-1) ) ) - return NS_ERROR_ILLEGAL_VALUE; - nsCOMPtr textNode = do_QueryInterface(aTextNode); - NS_ENSURE_TRUE(textNode, NS_ERROR_NULL_POINTER); - - // don't need to do anything if no characters actually selected - if (aStartOffset == aEndOffset) return NS_OK; - - if (!textNode->GetParentNode() || - !CanContainTag(*textNode->GetParentNode(), *nsGkAtoms::big)) { + // Don't need to do anything if no characters actually selected + if (aStartOffset == aEndOffset) { return NS_OK; } - nsCOMPtr tmp; - nsCOMPtr node = do_QueryInterface(aTextNode); - NS_ENSURE_STATE(node); + if (!aTextNode.GetParentNode() || + !CanContainTag(*aTextNode.GetParentNode(), *nsGkAtoms::big)) { + return NS_OK; + } - // do we need to split the text node? - uint32_t textLen; - aTextNode->GetLength(&textLen); + OwningNonNull node = aTextNode; + + // Do we need to split the text node? // -1 is a magic value meaning to the end of node - if (aEndOffset == -1) aEndOffset = textLen; - - nsresult res = NS_OK; - if ( (uint32_t)aEndOffset != textLen ) - { - // we need to split off back of text node - res = SplitNode(GetAsDOMNode(node), aEndOffset, getter_AddRefs(tmp)); - NS_ENSURE_SUCCESS(res, res); - // remember left node - node = do_QueryInterface(tmp); - } - if ( aStartOffset ) - { - // we need to split off front of text node - res = SplitNode(GetAsDOMNode(node), aStartOffset, getter_AddRefs(tmp)); - NS_ENSURE_SUCCESS(res, res); + if (aEndOffset == -1) { + aEndOffset = aTextNode.Length(); } - // look for siblings that are correct type of node - nsIAtom* nodeType = aSizeChange == 1 ? nsGkAtoms::big : nsGkAtoms::small; + ErrorResult rv; + if ((uint32_t)aEndOffset != aTextNode.Length()) { + // We need to split off back of text node + node = SplitNode(node, aEndOffset, rv); + NS_ENSURE_TRUE(!rv.Failed(), rv.StealNSResult()); + } + if (aStartOffset) { + // We need to split off front of text node + SplitNode(node, aStartOffset, rv); + NS_ENSURE_TRUE(!rv.Failed(), rv.StealNSResult()); + } + + // Look for siblings that are correct type of node + nsIAtom* nodeType = aDir == FontSize::incr ? nsGkAtoms::big + : nsGkAtoms::small; nsCOMPtr sibling = GetPriorHTMLSibling(node); if (sibling && sibling->IsHTMLElement(nodeType)) { - // previous sib is already right kind of inline node; slide this over into it - res = MoveNode(node, sibling, -1); - return res; + // Previous sib is already right kind of inline node; slide this over + nsresult res = MoveNode(node, sibling, -1); + NS_ENSURE_SUCCESS(res, res); + return NS_OK; } sibling = GetNextHTMLSibling(node); if (sibling && sibling->IsHTMLElement(nodeType)) { - // following sib is already right kind of inline node; slide this over into it - res = MoveNode(node, sibling, 0); - return res; + // Following sib is already right kind of inline node; slide this over + nsresult res = MoveNode(node, sibling, 0); + NS_ENSURE_SUCCESS(res, res); + return NS_OK; } - // else reparent the node inside font node with appropriate relative size + // Else reparent the node inside font node with appropriate relative size nsCOMPtr newElement = InsertContainerAbove(node, nodeType); NS_ENSURE_STATE(newElement); diff --git a/editor/libeditor/nsPlaintextEditor.cpp b/editor/libeditor/nsPlaintextEditor.cpp index ac74806435..0e530c7cde 100644 --- a/editor/libeditor/nsPlaintextEditor.cpp +++ b/editor/libeditor/nsPlaintextEditor.cpp @@ -436,7 +436,7 @@ nsPlaintextEditor::TypedText(const nsAString& aString, ETypingAction aAction) } } -already_AddRefed +Element* nsPlaintextEditor::CreateBRImpl(nsCOMPtr* aInOutParent, int32_t* aInOutOffset, EDirection aSelect) @@ -447,7 +447,7 @@ nsPlaintextEditor::CreateBRImpl(nsCOMPtr* aInOutParent, CreateBRImpl(address_of(parent), aInOutOffset, address_of(br), aSelect); *aInOutParent = do_QueryInterface(parent); nsCOMPtr ret(do_QueryInterface(br)); - return ret.forget(); + return ret; } nsresult diff --git a/editor/libeditor/nsPlaintextEditor.h b/editor/libeditor/nsPlaintextEditor.h index 6975aeedd9..1578196c11 100644 --- a/editor/libeditor/nsPlaintextEditor.h +++ b/editor/libeditor/nsPlaintextEditor.h @@ -120,7 +120,7 @@ public: NS_IMETHOD EndOperation() override; /** make the given selection span the entire document */ - virtual nsresult SelectEntireDocument(mozilla::dom::Selection* aSelection) override; + virtual nsresult SelectEntireDocument(Selection* aSelection) override; virtual nsresult HandleKeyPressEvent(nsIDOMKeyEvent* aKeyEvent) override; @@ -153,7 +153,7 @@ public: * If done, also update aAction to what's actually left to do after the * extension. */ - nsresult ExtendSelectionForDelete(mozilla::dom::Selection* aSelection, + nsresult ExtendSelectionForDelete(Selection* aSelection, nsIEditor::EDirection *aAction); // Return true if the data is safe to insert as the source and destination @@ -180,9 +180,8 @@ protected: // key event helpers NS_IMETHOD CreateBR(nsIDOMNode *aNode, int32_t aOffset, nsCOMPtr *outBRNode, EDirection aSelect = eNone); - already_AddRefed - CreateBRImpl(nsCOMPtr* aInOutParent, int32_t* aInOutOffset, - EDirection aSelect); + Element* CreateBRImpl(nsCOMPtr* aInOutParent, int32_t* aInOutOffset, + EDirection aSelect); nsresult CreateBRImpl(nsCOMPtr* aInOutParent, int32_t* aInOutOffset, nsCOMPtr* outBRNode, diff --git a/editor/libeditor/nsSelectionState.cpp b/editor/libeditor/nsSelectionState.cpp index 1f3c5047f0..9f57f57a4d 100644 --- a/editor/libeditor/nsSelectionState.cpp +++ b/editor/libeditor/nsSelectionState.cpp @@ -35,21 +35,6 @@ nsSelectionState::~nsSelectionState() MakeEmpty(); } -void -nsSelectionState::DoTraverse(nsCycleCollectionTraversalCallback &cb) -{ - for (uint32_t i = 0, iEnd = mArray.Length(); i < iEnd; ++i) - { - nsRangeStore* item = mArray[i]; - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, - "selection state mArray[i].startNode"); - cb.NoteXPCOMChild(item->startNode); - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, - "selection state mArray[i].endNode"); - cb.NoteXPCOMChild(item->endNode); - } -} - void nsSelectionState::SaveSelection(Selection* aSel) { @@ -652,6 +637,10 @@ nsRangeStore::~nsRangeStore() { } +NS_IMPL_CYCLE_COLLECTION(nsRangeStore, startNode, endNode) +NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsRangeStore, AddRef) +NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsRangeStore, Release) + void nsRangeStore::StoreRange(nsRange* aRange) { diff --git a/editor/libeditor/nsSelectionState.h b/editor/libeditor/nsSelectionState.h index 12b17e1407..891e0d85d9 100644 --- a/editor/libeditor/nsSelectionState.h +++ b/editor/libeditor/nsSelectionState.h @@ -41,7 +41,8 @@ public: void StoreRange(nsRange* aRange); already_AddRefed GetRange(); - NS_INLINE_DECL_REFCOUNTING(nsRangeStore) + NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsRangeStore) + NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsRangeStore) nsCOMPtr startNode; int32_t startOffset; @@ -56,21 +57,38 @@ class nsSelectionState nsSelectionState(); ~nsSelectionState(); - void DoTraverse(nsCycleCollectionTraversalCallback &cb); - void DoUnlink() { MakeEmpty(); } - void SaveSelection(mozilla::dom::Selection *aSel); nsresult RestoreSelection(mozilla::dom::Selection* aSel); bool IsCollapsed(); bool IsEqual(nsSelectionState *aSelState); void MakeEmpty(); bool IsEmpty(); - protected: + private: nsTArray > mArray; friend class nsRangeUpdater; + friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback&, + nsSelectionState&, + const char*, + uint32_t); + friend void ImplCycleCollectionUnlink(nsSelectionState&); }; +inline void +ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, + nsSelectionState& aField, + const char* aName, + uint32_t aFlags = 0) +{ + ImplCycleCollectionTraverse(aCallback, aField.mArray, aName, aFlags); +} + +inline void +ImplCycleCollectionUnlink(nsSelectionState& aField) +{ + ImplCycleCollectionUnlink(aField.mArray); +} + class nsRangeUpdater { public: @@ -120,11 +138,31 @@ class nsRangeUpdater void WillMoveNode(); void DidMoveNode(nsINode* aOldParent, int32_t aOldOffset, nsINode* aNewParent, int32_t aNewOffset); - protected: + private: + friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback&, + nsRangeUpdater&, + const char*, + uint32_t); + friend void ImplCycleCollectionUnlink(nsRangeUpdater& aField); + nsTArray > mArray; bool mLock; }; +inline void +ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, + nsRangeUpdater& aField, + const char* aName, + uint32_t aFlags = 0) +{ + ImplCycleCollectionTraverse(aCallback, aField.mArray, aName, aFlags); +} + +inline void +ImplCycleCollectionUnlink(nsRangeUpdater& aField) +{ + ImplCycleCollectionUnlink(aField.mArray); +} /*************************************************************************** * helper class for using nsSelectionState. stack based class for doing diff --git a/editor/libeditor/nsTextEditRules.cpp b/editor/libeditor/nsTextEditRules.cpp index 2b63424815..d38b144d5f 100644 --- a/editor/libeditor/nsTextEditRules.cpp +++ b/editor/libeditor/nsTextEditRules.cpp @@ -285,7 +285,8 @@ nsTextEditRules::WillDoAction(Selection* aSelection, case EditAction::insertElement: // i had thought this would be html rules only. but we put pre elements // into plaintext mail when doing quoting for reply! doh! - return WillInsert(aSelection, aCancel); + WillInsert(*aSelection, aCancel); + return NS_OK; default: return NS_ERROR_FAILURE; } @@ -345,25 +346,25 @@ nsTextEditRules::DocumentIsEmpty(bool *aDocumentIsEmpty) ********************************************************/ -nsresult -nsTextEditRules::WillInsert(Selection* aSelection, bool* aCancel) +void +nsTextEditRules::WillInsert(Selection& aSelection, bool* aCancel) { - NS_ENSURE_TRUE(aSelection && aCancel, NS_ERROR_NULL_POINTER); + MOZ_ASSERT(aCancel); - CANCEL_OPERATION_IF_READONLY_OR_DISABLED + if (IsReadonly() || IsDisabled()) { + *aCancel = true; + return; + } // initialize out param *aCancel = false; // check for the magic content node and delete it if it exists - if (mBogusNode) - { - NS_ENSURE_STATE(mEditor); + if (mBogusNode) { + NS_ENSURE_TRUE_VOID(mEditor); mEditor->DeleteNode(mBogusNode); mBogusNode = nullptr; } - - return NS_OK; } nsresult @@ -412,8 +413,7 @@ nsTextEditRules::WillInsertBreak(Selection* aSelection, NS_ENSURE_SUCCESS(res, res); } - res = WillInsert(aSelection, aCancel); - NS_ENSURE_SUCCESS(res, res); + WillInsert(*aSelection, aCancel); // initialize out param // we want to ignore result of WillInsert() *aCancel = false; @@ -643,8 +643,7 @@ nsTextEditRules::WillInsertText(EditAction aAction, NS_ENSURE_SUCCESS(res, res); } - res = WillInsert(aSelection, aCancel); - NS_ENSURE_SUCCESS(res, res); + WillInsert(*aSelection, aCancel); // initialize out param // we want to ignore result of WillInsert() *aCancel = false; diff --git a/editor/libeditor/nsTextEditRules.h b/editor/libeditor/nsTextEditRules.h index c39c489c61..e3fdf06582 100644 --- a/editor/libeditor/nsTextEditRules.h +++ b/editor/libeditor/nsTextEditRules.h @@ -39,6 +39,11 @@ class Selection; class nsTextEditRules : public nsIEditRules, public nsITimerCallback { public: + typedef mozilla::dom::Element Element; + typedef mozilla::dom::Selection Selection; + typedef mozilla::dom::Text Text; + template using OwningNonNull = mozilla::OwningNonNull; + NS_DECL_NSITIMERCALLBACK NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsTextEditRules, nsIEditRules) @@ -53,10 +58,10 @@ public: nsIEditor::EDirection aDirection) override; NS_IMETHOD AfterEdit(EditAction action, nsIEditor::EDirection aDirection) override; - NS_IMETHOD WillDoAction(mozilla::dom::Selection* aSelection, - nsRulesInfo* aInfo, bool* aCancel, bool* aHandled) override; - NS_IMETHOD DidDoAction(mozilla::dom::Selection* aSelection, - nsRulesInfo* aInfo, nsresult aResult) override; + NS_IMETHOD WillDoAction(Selection* aSelection, nsRulesInfo* aInfo, + bool* aCancel, bool* aHandled) override; + NS_IMETHOD DidDoAction(Selection* aSelection, nsRulesInfo* aInfo, + nsresult aResult) override; NS_IMETHOD DocumentIsEmpty(bool *aDocumentIsEmpty) override; NS_IMETHOD DocumentModified() override; @@ -108,49 +113,43 @@ protected: // nsTextEditRules implementation methods nsresult WillInsertText( EditAction aAction, - mozilla::dom::Selection* aSelection, + Selection* aSelection, bool *aCancel, bool *aHandled, const nsAString *inString, nsAString *outString, int32_t aMaxLength); - nsresult DidInsertText(mozilla::dom::Selection* aSelection, - nsresult aResult); + nsresult DidInsertText(Selection* aSelection, nsresult aResult); nsresult GetTopEnclosingPre(nsIDOMNode *aNode, nsIDOMNode** aOutPreNode); - nsresult WillInsertBreak(mozilla::dom::Selection* aSelection, bool* aCancel, + nsresult WillInsertBreak(Selection* aSelection, bool* aCancel, bool *aHandled, int32_t aMaxLength); - nsresult DidInsertBreak(mozilla::dom::Selection* aSelection, - nsresult aResult); + nsresult DidInsertBreak(Selection* aSelection, nsresult aResult); - nsresult WillInsert(mozilla::dom::Selection* aSelection, bool* aCancel); - nsresult DidInsert(mozilla::dom::Selection* aSelection, nsresult aResult); + void WillInsert(Selection& aSelection, bool* aCancel); + nsresult DidInsert(Selection* aSelection, nsresult aResult); - nsresult WillDeleteSelection(mozilla::dom::Selection* aSelection, + nsresult WillDeleteSelection(Selection* aSelection, nsIEditor::EDirection aCollapsedAction, bool *aCancel, bool *aHandled); - nsresult DidDeleteSelection(mozilla::dom::Selection* aSelection, + nsresult DidDeleteSelection(Selection* aSelection, nsIEditor::EDirection aCollapsedAction, nsresult aResult); - nsresult WillSetTextProperty(mozilla::dom::Selection* aSelection, - bool* aCancel, bool* aHandled); - nsresult DidSetTextProperty(mozilla::dom::Selection* aSelection, - nsresult aResult); + nsresult WillSetTextProperty(Selection* aSelection, bool* aCancel, + bool* aHandled); + nsresult DidSetTextProperty(Selection* aSelection, nsresult aResult); - nsresult WillRemoveTextProperty(mozilla::dom::Selection* aSelection, - bool* aCancel, bool* aHandled); - nsresult DidRemoveTextProperty(mozilla::dom::Selection* aSelection, - nsresult aResult); + nsresult WillRemoveTextProperty(Selection* aSelection, bool* aCancel, + bool* aHandled); + nsresult DidRemoveTextProperty(Selection* aSelection, nsresult aResult); - nsresult WillUndo(mozilla::dom::Selection* aSelection, bool* aCancel, - bool* aHandled); - nsresult DidUndo(mozilla::dom::Selection* aSelection, nsresult aResult); + nsresult WillUndo(Selection* aSelection, bool* aCancel, bool* aHandled); + nsresult DidUndo(Selection* aSelection, nsresult aResult); - nsresult WillRedo(mozilla::dom::Selection* aSelection, bool* aCancel, - bool* aHandled); - nsresult DidRedo(mozilla::dom::Selection* aSelection, nsresult aResult); + nsresult WillRedo(Selection* aSelection, bool* aCancel, bool* aHandled); + nsresult DidRedo(Selection* aSelection, nsresult aResult); /** called prior to nsIEditor::OutputToString * @param aSelection @@ -159,13 +158,13 @@ protected: * @param aOutCancel if set to true, the caller should cancel the operation * and use aOutText as the result. */ - nsresult WillOutputText(mozilla::dom::Selection* aSelection, + nsresult WillOutputText(Selection* aSelection, const nsAString *aInFormat, nsAString *aOutText, bool *aOutCancel, bool *aHandled); - nsresult DidOutputText(mozilla::dom::Selection* aSelection, nsresult aResult); + nsresult DidOutputText(Selection* aSelection, nsresult aResult); // helper functions @@ -177,11 +176,11 @@ protected: nsresult CreateTrailingBRIfNeeded(); /** creates a bogus text node if the document has no editable content */ - nsresult CreateBogusNodeIfNeeded(mozilla::dom::Selection* aSelection); + nsresult CreateBogusNodeIfNeeded(Selection* aSelection); /** returns a truncated insertion string if insertion would place us over aMaxLength */ - nsresult TruncateInsertionIfNeeded(mozilla::dom::Selection* aSelection, + nsresult TruncateInsertionIfNeeded(Selection* aSelection, const nsAString *aInString, nsAString *aOutString, int32_t aMaxLength, @@ -193,9 +192,9 @@ protected: nsresult CreateMozBR(nsIDOMNode* inParent, int32_t inOffset, nsIDOMNode** outBRNode = nullptr); - void UndefineCaretBidiLevel(mozilla::dom::Selection* aSelection); + void UndefineCaretBidiLevel(Selection* aSelection); - nsresult CheckBidiLevelForDeletion(mozilla::dom::Selection* aSelection, + nsresult CheckBidiLevelForDeletion(Selection* aSelection, nsIDOMNode *aSelNode, int32_t aSelOffset, nsIEditor::EDirection aAction, @@ -203,7 +202,7 @@ protected: nsresult HideLastPWInput(); - nsresult CollapseSelectionToTrailingBRIfNeeded(mozilla::dom::Selection* aSelection); + nsresult CollapseSelectionToTrailingBRIfNeeded(Selection* aSelection); bool IsPasswordEditor() const { diff --git a/editor/libeditor/nsWSRunObject.cpp b/editor/libeditor/nsWSRunObject.cpp index 8c4ce5e634..fcbd6c3f68 100644 --- a/editor/libeditor/nsWSRunObject.cpp +++ b/editor/libeditor/nsWSRunObject.cpp @@ -193,7 +193,7 @@ nsWSRunObject::PrepareToSplitAcrossBlocks(nsHTMLEditor* aHTMLEd, // public instance methods //-------------------------------------------------------------------------------------------- -already_AddRefed +Element* nsWSRunObject::InsertBreak(nsCOMPtr* aInOutParent, int32_t* aInOutOffset, nsIEditor::EDirection aSelect) @@ -602,7 +602,7 @@ nsWSRunObject::AdjustWhitespace() // protected methods //-------------------------------------------------------------------------------------------- -already_AddRefed +nsINode* nsWSRunObject::GetWSBoundingParent() { NS_ENSURE_TRUE(mNode, nullptr); @@ -614,7 +614,7 @@ nsWSRunObject::GetWSBoundingParent() } wsBoundingParent = parent; } - return wsBoundingParent.forget(); + return wsBoundingParent; } nsresult @@ -1763,7 +1763,7 @@ nsWSRunObject::CheckTrailingNBSPOfRun(WSFragment *aRun) rightCheck = true; } if ((aRun->mRightType & WSType::block) && - IsBlockNode(nsCOMPtr(GetWSBoundingParent()))) { + IsBlockNode(GetWSBoundingParent())) { // We are at a block boundary. Insert a
. Why? Well, first note // that the br will have no visible effect since it is up against a // block boundary. |foo

bar| renders like |foo

bar| and diff --git a/editor/libeditor/nsWSRunObject.h b/editor/libeditor/nsWSRunObject.h index f4bd19965f..ba26665c85 100644 --- a/editor/libeditor/nsWSRunObject.h +++ b/editor/libeditor/nsWSRunObject.h @@ -203,9 +203,9 @@ class MOZ_STACK_CLASS nsWSRunObject // and makes any needed adjustments to ws around that point. // example of fixup: normalws after {aInOutParent,aInOutOffset} // needs to begin with nbsp. - already_AddRefed - InsertBreak(nsCOMPtr* aInOutParent, int32_t* aInOutOffset, - nsIEditor::EDirection aSelect); + mozilla::dom::Element* InsertBreak(nsCOMPtr* aInOutParent, + int32_t* aInOutOffset, + nsIEditor::EDirection aSelect); // InsertText inserts a string at {aInOutParent,aInOutOffset} and makes any // needed adjustments to ws around that point. Example of fixup: @@ -304,7 +304,7 @@ class MOZ_STACK_CLASS nsWSRunObject * closest block within the DOM subtree we're editing, or if none is * found, the (inline) root of the editable subtree. */ - already_AddRefed GetWSBoundingParent(); + nsINode* GetWSBoundingParent(); nsresult GetWSNodes(); void GetRuns(); diff --git a/editor/libeditor/tests/mochitest.ini b/editor/libeditor/tests/mochitest.ini index 9d1cd82fbd..4cc6ceb8b2 100644 --- a/editor/libeditor/tests/mochitest.ini +++ b/editor/libeditor/tests/mochitest.ini @@ -128,6 +128,7 @@ skip-if = toolkit == 'android' [test_bug757371.html] [test_bug757771.html] [test_bug767684.html] +[test_bug772796.html] [test_bug773262.html] [test_bug780035.html] [test_bug787432.html] @@ -162,5 +163,6 @@ skip-if = toolkit == 'android' [test_bug1186799.html] [test_bug1181130-1.html] [test_bug1181130-2.html] -[test_bug1352799.html] [test_backspace_vs.html] +[test_bug1258085.html] +[test_bug1352799.html] diff --git a/editor/libeditor/tests/test_bug1258085.html b/editor/libeditor/tests/test_bug1258085.html new file mode 100644 index 0000000000..342f068ee2 --- /dev/null +++ b/editor/libeditor/tests/test_bug1258085.html @@ -0,0 +1,66 @@ + +Test for Bug 1186799 + + + +

+ diff --git a/editor/libeditor/tests/test_bug772796.html b/editor/libeditor/tests/test_bug772796.html new file mode 100644 index 0000000000..9a15dccd27 --- /dev/null +++ b/editor/libeditor/tests/test_bug772796.html @@ -0,0 +1,223 @@ + + + + + + Test for Bug 772796 + + + + + + +
Mozilla Bug 772796 +

+ + +
+ +
+
+  
+
+
+ + diff --git a/embedding/components/printingui/unixshared/nsPrintingPromptService.cpp b/embedding/components/printingui/unixshared/nsPrintingPromptService.cpp index 4363a9cb71..75cc4bc440 100644 --- a/embedding/components/printingui/unixshared/nsPrintingPromptService.cpp +++ b/embedding/components/printingui/unixshared/nsPrintingPromptService.cpp @@ -198,8 +198,6 @@ nsPrintingPromptService::DoDialog(mozIDOMWindowProxy *aParent, if (!mWatcher) return NS_ERROR_FAILURE; - nsresult rv = NS_OK; - // get a parent, if at all possible // (though we'd rather this didn't fail, it's OK if it does. so there's // no failure or null check.) @@ -213,8 +211,10 @@ nsPrintingPromptService::DoDialog(mozIDOMWindowProxy *aParent, // create a nsISupportsArray of the parameters // being passed to the window nsCOMPtr array; - NS_NewISupportsArray(getter_AddRefs(array)); - if (!array) return NS_ERROR_FAILURE; + nsresult rv = NS_NewISupportsArray(getter_AddRefs(array)); + if (NS_FAILED(rv)) { + return NS_ERROR_FAILURE; + } nsCOMPtr psSupports(do_QueryInterface(aPS)); NS_ASSERTION(psSupports, "PrintSettings must be a supports"); diff --git a/embedding/components/printingui/win/nsPrintDialogUtil.cpp b/embedding/components/printingui/win/nsPrintDialogUtil.cpp index 6931f183e2..4857f7a5a7 100644 --- a/embedding/components/printingui/win/nsPrintDialogUtil.cpp +++ b/embedding/components/printingui/win/nsPrintDialogUtil.cpp @@ -55,6 +55,8 @@ WIN_LIBS= \ // This is for extending the dialog #include +#include "nsWindowsHelpers.h" + // Default labels for the radio buttons static const char* kAsLaidOutOnScreenStr = "As &laid out on the screen"; static const char* kTheSelectedFrameStr = "The selected &frame"; @@ -462,79 +464,71 @@ static UINT CALLBACK PrintHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM // This function assumes that aPrintName has already been converted from // unicode // -HGLOBAL CreateGlobalDevModeAndInit(const nsXPIDLString& aPrintName, nsIPrintSettings* aPS) +static nsReturnRef +CreateGlobalDevModeAndInit(const nsXPIDLString& aPrintName, + nsIPrintSettings* aPS) { - HGLOBAL hGlobalDevMode = nullptr; - - HANDLE hPrinter = nullptr; + nsHPRINTER hPrinter = nullptr; // const cast kludge for silly Win32 api's LPWSTR printName = const_cast(static_cast(aPrintName.get())); BOOL status = ::OpenPrinterW(printName, &hPrinter, nullptr); - if (status) { - - LPDEVMODEW pNewDevMode; - DWORD dwNeeded, dwRet; - - // Get the buffer size - dwNeeded = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, nullptr, nullptr, 0); - if (dwNeeded == 0) { - return nullptr; - } - - // Allocate a buffer of the correct size. - pNewDevMode = (LPDEVMODEW)::HeapAlloc (::GetProcessHeap(), HEAP_ZERO_MEMORY, dwNeeded); - if (!pNewDevMode) return nullptr; - - hGlobalDevMode = (HGLOBAL)::GlobalAlloc(GHND, dwNeeded); - if (!hGlobalDevMode) { - ::HeapFree(::GetProcessHeap(), 0, pNewDevMode); - return nullptr; - } - - dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, pNewDevMode, nullptr, DM_OUT_BUFFER); - - if (dwRet != IDOK) { - ::HeapFree(::GetProcessHeap(), 0, pNewDevMode); - ::GlobalFree(hGlobalDevMode); - ::ClosePrinter(hPrinter); - return nullptr; - } - - // Lock memory and copy contents from DEVMODE (current printer) - // to Global Memory DEVMODE - LPDEVMODEW devMode = (DEVMODEW *)::GlobalLock(hGlobalDevMode); - if (devMode) { - memcpy(devMode, pNewDevMode, dwNeeded); - // Initialize values from the PrintSettings - nsCOMPtr psWin = do_QueryInterface(aPS); - MOZ_ASSERT(psWin); - psWin->CopyToNative(devMode); - - // Sets back the changes we made to the DevMode into the Printer Driver - dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, devMode, devMode, DM_IN_BUFFER | DM_OUT_BUFFER); - if (dwRet != IDOK) { - ::GlobalUnlock(hGlobalDevMode); - ::GlobalFree(hGlobalDevMode); - ::HeapFree(::GetProcessHeap(), 0, pNewDevMode); - ::ClosePrinter(hPrinter); - return nullptr; - } - - ::GlobalUnlock(hGlobalDevMode); - } else { - ::GlobalFree(hGlobalDevMode); - hGlobalDevMode = nullptr; - } - - ::HeapFree(::GetProcessHeap(), 0, pNewDevMode); - - ::ClosePrinter(hPrinter); - - } else { - return nullptr; + if (!status) { + return nsReturnRef(); } - return hGlobalDevMode; + // Make sure hPrinter is closed on all paths + nsAutoPrinter autoPrinter(hPrinter); + + // Get the buffer size + DWORD dwNeeded = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, nullptr, + nullptr, 0); + if (dwNeeded == 0) { + return nsReturnRef(); + } + + // Allocate a buffer of the correct size. + nsAutoDevMode newDevMode((LPDEVMODEW)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, + dwNeeded)); + if (!newDevMode) { + return nsReturnRef(); + } + + nsHGLOBAL hDevMode = ::GlobalAlloc(GHND, dwNeeded); + nsAutoGlobalMem globalDevMode(hDevMode); + if (!hDevMode) { + return nsReturnRef(); + } + + DWORD dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, newDevMode, + nullptr, DM_OUT_BUFFER); + if (dwRet != IDOK) { + return nsReturnRef(); + } + + // Lock memory and copy contents from DEVMODE (current printer) + // to Global Memory DEVMODE + LPDEVMODEW devMode = (DEVMODEW *)::GlobalLock(hDevMode); + if (!devMode) { + return nsReturnRef(); + } + + memcpy(devMode, newDevMode.get(), dwNeeded); + // Initialize values from the PrintSettings + nsCOMPtr psWin = do_QueryInterface(aPS); + MOZ_ASSERT(psWin); + psWin->CopyToNative(devMode); + + // Sets back the changes we made to the DevMode into the Printer Driver + dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, devMode, devMode, + DM_IN_BUFFER | DM_OUT_BUFFER); + if (dwRet != IDOK) { + ::GlobalUnlock(hDevMode); + return nsReturnRef(); + } + + ::GlobalUnlock(hDevMode); + + return globalDevMode.out(); } //------------------------------------------------------------------ @@ -576,9 +570,6 @@ ShowNativePrintDialog(HWND aHWnd, gDialogWasExtended = false; - HGLOBAL hGlobalDevMode = nullptr; - HGLOBAL hDevNames = nullptr; - // Get the Print Name to be used nsXPIDLString printerName; aPrintSettings->GetPrinterName(getter_Copies(printerName)); @@ -588,7 +579,8 @@ ShowNativePrintDialog(HWND aHWnd, GetDefaultPrinterNameFromGlobalPrinters(printerName); } else { HANDLE hPrinter = nullptr; - if(!::OpenPrinterW(const_cast(static_cast(printerName.get())), &hPrinter, nullptr)) { + if(!::OpenPrinterW(const_cast(static_cast(printerName.get())), + &hPrinter, nullptr)) { // If the last used printer is not found, we should use default printer. GetDefaultPrinterNameFromGlobalPrinters(printerName); } else { @@ -599,15 +591,15 @@ ShowNativePrintDialog(HWND aHWnd, // Now create a DEVNAMES struct so the the dialog is initialized correctly. uint32_t len = printerName.Length(); - hDevNames = (HGLOBAL)::GlobalAlloc(GHND, sizeof(wchar_t) * (len + 1) + - sizeof(DEVNAMES)); + nsHGLOBAL hDevNames = ::GlobalAlloc(GHND, sizeof(wchar_t) * (len + 1) + + sizeof(DEVNAMES)); + nsAutoGlobalMem autoDevNames(hDevNames); if (!hDevNames) { return NS_ERROR_OUT_OF_MEMORY; } DEVNAMES* pDevNames = (DEVNAMES*)::GlobalLock(hDevNames); if (!pDevNames) { - ::GlobalFree(hDevNames); return NS_ERROR_FAILURE; } pDevNames->wDriverOffset = sizeof(DEVNAMES)/sizeof(wchar_t); @@ -621,10 +613,8 @@ ShowNativePrintDialog(HWND aHWnd, // Create a Moveable Memory Object that holds a new DevMode // from the Printer Name // The PRINTDLG.hDevMode requires that it be a moveable memory object - // NOTE: We only need to free hGlobalDevMode when the dialog is cancelled - // When the user prints, it comes back in the printdlg struct and - // is used and cleaned up later - hGlobalDevMode = CreateGlobalDevModeAndInit(printerName, aPrintSettings); + // NOTE: autoDevMode is automatically freed when any error occurred + nsAutoGlobalMem autoDevMode(CreateGlobalDevModeAndInit(printerName, aPrintSettings)); // Prepare to Display the Print Dialog PRINTDLGW prntdlg; @@ -632,7 +622,7 @@ ShowNativePrintDialog(HWND aHWnd, prntdlg.lStructSize = sizeof(prntdlg); prntdlg.hwndOwner = aHWnd; - prntdlg.hDevMode = hGlobalDevMode; + prntdlg.hDevMode = autoDevMode.get(); prntdlg.hDevNames = hDevNames; prntdlg.hDC = nullptr; prntdlg.Flags = PD_ALLPAGES | PD_RETURNIC | @@ -682,13 +672,11 @@ ShowNativePrintDialog(HWND aHWnd, NS_ENSURE_TRUE(aPrintSettings && prntdlg.hDevMode, NS_ERROR_FAILURE); if (prntdlg.hDevNames == nullptr) { - ::GlobalFree(hGlobalDevMode); return NS_ERROR_FAILURE; } // Lock the deviceNames and check for nullptr DEVNAMES *devnames = (DEVNAMES *)::GlobalLock(prntdlg.hDevNames); if (devnames == nullptr) { - ::GlobalFree(hGlobalDevMode); return NS_ERROR_FAILURE; } @@ -716,7 +704,6 @@ ShowNativePrintDialog(HWND aHWnd, nsCOMPtr psWin(do_QueryInterface(aPrintSettings)); if (!psWin) { - ::GlobalFree(hGlobalDevMode); return NS_ERROR_FAILURE; } @@ -772,7 +759,6 @@ ShowNativePrintDialog(HWND aHWnd, // Transfer the settings from the native data to the PrintSettings LPDEVMODEW devMode = (LPDEVMODEW)::GlobalLock(prntdlg.hDevMode); if (!devMode || !prntdlg.hDC) { - ::GlobalFree(hGlobalDevMode); return NS_ERROR_FAILURE; } psWin->SetDevMode(devMode); // copies DevMode @@ -805,7 +791,6 @@ ShowNativePrintDialog(HWND aHWnd, } else { ::SetFocus(aHWnd); aPrintSettings->SetIsCancelled(true); - if (hGlobalDevMode) ::GlobalFree(hGlobalDevMode); return NS_ERROR_ABORT; } diff --git a/embedding/components/printingui/win/nsPrintDialogUtil.h b/embedding/components/printingui/win/nsPrintDialogUtil.h index 83173cc342..ada3da239b 100644 --- a/embedding/components/printingui/win/nsPrintDialogUtil.h +++ b/embedding/components/printingui/win/nsPrintDialogUtil.h @@ -9,6 +9,4 @@ nsresult NativeShowPrintDialog(HWND aHWnd, nsIWebBrowserPrint* aWebBrowserPrint, nsIPrintSettings* aPrintSettings); -HGLOBAL CreateGlobalDevModeAndInit(const nsXPIDLString& aPrintName, nsIPrintSettings* aPS); - #endif /* nsFlyOwnDialog_h___ */ diff --git a/embedding/components/printingui/win/nsPrintingPromptService.cpp b/embedding/components/printingui/win/nsPrintingPromptService.cpp index 37db149399..93cf062610 100644 --- a/embedding/components/printingui/win/nsPrintingPromptService.cpp +++ b/embedding/components/printingui/win/nsPrintingPromptService.cpp @@ -248,8 +248,6 @@ nsPrintingPromptService::DoDialog(mozIDOMWindowProxy *aParent, if (!mWatcher) return NS_ERROR_FAILURE; - nsresult rv = NS_OK; - // get a parent, if at all possible // (though we'd rather this didn't fail, it's OK if it does. so there's // no failure or null check.) @@ -263,8 +261,10 @@ nsPrintingPromptService::DoDialog(mozIDOMWindowProxy *aParent, // create a nsISupportsArray of the parameters // being passed to the window nsCOMPtr array; - NS_NewISupportsArray(getter_AddRefs(array)); - if (!array) return NS_ERROR_FAILURE; + nsresult rv = NS_NewISupportsArray(getter_AddRefs(array)); + if (NS_FAILED(rv)) { + return NS_ERROR_FAILURE; + } nsCOMPtr psSupports(do_QueryInterface(aPS)); NS_ASSERTION(psSupports, "PrintSettings must be a supports"); diff --git a/gfx/layers/AtomicRefCountedWithFinalize.h b/gfx/layers/AtomicRefCountedWithFinalize.h index 67ee252744..f6476106c6 100644 --- a/gfx/layers/AtomicRefCountedWithFinalize.h +++ b/gfx/layers/AtomicRefCountedWithFinalize.h @@ -151,7 +151,6 @@ private: delete derived; } else { mMessageLoopToPostDestructionTo->PostTask( - FROM_HERE, NewRunnableFunction(&DestroyToBeCalledOnMainThread, derived)); } } diff --git a/gfx/layers/apz/public/GeckoContentController.h b/gfx/layers/apz/public/GeckoContentController.h index 6d8023fe9f..b6bd6334c6 100644 --- a/gfx/layers/apz/public/GeckoContentController.h +++ b/gfx/layers/apz/public/GeckoContentController.h @@ -14,9 +14,10 @@ #include "nsISupportsImpl.h" #include "ThreadSafeRefcountingWithMainThreadDestruction.h" -class Task; - namespace mozilla { + +class Runnable; + namespace layers { class GeckoContentController @@ -36,14 +37,6 @@ public: */ virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) = 0; - /** - * Acknowledges the recipt of a scroll offset update for the scrollable - * frame with the given scroll id. This is used to maintain consistency - * between APZ and other sources of scroll changes. - */ - virtual void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId, - const uint32_t& aScrollGeneration) = 0; - /** * Requests handling of a double tap. |aPoint| is in CSS pixels, relative to * the current scroll offset. This should eventually round-trip back to @@ -77,7 +70,7 @@ public: * in the future. * This method must always be called on the controller thread. */ - virtual void PostDelayedTask(Task* aTask, int aDelayMs) = 0; + virtual void PostDelayedTask(already_AddRefed aRunnable, int aDelayMs) = 0; /** * APZ uses |FrameMetrics::mCompositionBounds| for hit testing. Sometimes, diff --git a/gfx/layers/apz/src/AsyncPanZoomAnimation.h b/gfx/layers/apz/src/AsyncPanZoomAnimation.h index a227029a63..039c0684e1 100644 --- a/gfx/layers/apz/src/AsyncPanZoomAnimation.h +++ b/gfx/layers/apz/src/AsyncPanZoomAnimation.h @@ -46,7 +46,7 @@ public: * Get the deferred tasks in |mDeferredTasks| and place them in |aTasks|. See * |mDeferredTasks| for more information. Clears |mDeferredTasks|. */ - nsTArray TakeDeferredTasks() { + nsTArray> TakeDeferredTasks() { return Move(mDeferredTasks); } @@ -71,7 +71,7 @@ protected: * Derived classes can add tasks here in Sample(), and the APZC can call * ExecuteDeferredTasks() to execute them. */ - nsTArray mDeferredTasks; + nsTArray> mDeferredTasks; }; } // namespace layers diff --git a/gfx/layers/apz/src/AsyncPanZoomController.cpp b/gfx/layers/apz/src/AsyncPanZoomController.cpp index ffad278ce5..e8108566e2 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.cpp +++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp @@ -23,7 +23,6 @@ #include "UnitTransforms.h" // for TransformTo #include "base/message_loop.h" // for MessageLoop #include "base/task.h" // for NewRunnableMethod, etc -#include "base/tracked.h" // for FROM_HERE #include "gfxPrefs.h" // for gfxPrefs #include "gfxTypes.h" // for gfxFloat #include "LayersLogging.h" // for print_stderr @@ -3060,7 +3059,7 @@ AsyncPanZoomController::RequestContentRepaint(const FrameMetrics& aFrameMetrics, } bool AsyncPanZoomController::UpdateAnimation(const TimeStamp& aSampleTime, - nsTArray* aOutDeferredTasks) + nsTArray>* aOutDeferredTasks) { APZThreadUtils::AssertOnCompositorThread(); @@ -3161,7 +3160,7 @@ bool AsyncPanZoomController::AdvanceAnimations(const TimeStamp& aSampleTime) // responsibility to schedule a composite. mAsyncTransformAppliedToContent = false; bool requestAnimationFrame = false; - nsTArray deferredTasks; + nsTArray> deferredTasks; { ReentrantMonitorAutoEnter lock(mMonitor); @@ -3185,7 +3184,7 @@ bool AsyncPanZoomController::AdvanceAnimations(const TimeStamp& aSampleTime) // the tree lock. for (uint32_t i = 0; i < deferredTasks.Length(); ++i) { deferredTasks[i]->Run(); - delete deferredTasks[i]; + deferredTasks[i] = nullptr; } // One of the deferred tasks may have started a new animation. In this case, @@ -3456,9 +3455,6 @@ void AsyncPanZoomController::NotifyLayersUpdated(const ScrollMetadata& aScrollMe CancelAnimation(); mScrollMetadata = aScrollMetadata; - if (scrollOffsetUpdated) { - AcknowledgeScrollUpdate(); - } mExpectedGeckoMetrics = aLayerMetrics; ShareCompositorFrameMetrics(); @@ -3532,7 +3528,6 @@ void AsyncPanZoomController::NotifyLayersUpdated(const ScrollMetadata& aScrollMe // correct this we need to update mExpectedGeckoMetrics to be the // last thing we know was painted by Gecko. mFrameMetrics.CopyScrollInfoFrom(aLayerMetrics); - AcknowledgeScrollUpdate(); mExpectedGeckoMetrics = aLayerMetrics; // Cancel the animation (which might also trigger a repaint request) @@ -3564,7 +3559,7 @@ void AsyncPanZoomController::NotifyLayersUpdated(const ScrollMetadata& aScrollMe // See comment on the similar code in the |if (scrollOffsetUpdated)| block // above. mFrameMetrics.CopySmoothScrollInfoFrom(aLayerMetrics); - AcknowledgeScrollUpdate(); + needContentRepaint = true; mExpectedGeckoMetrics = aLayerMetrics; SmoothScrollTo(mFrameMetrics.GetSmoothScrollOffset()); @@ -3576,21 +3571,6 @@ void AsyncPanZoomController::NotifyLayersUpdated(const ScrollMetadata& aScrollMe UpdateSharedCompositorFrameMetrics(); } -void -AsyncPanZoomController::AcknowledgeScrollUpdate() const -{ - // Once layout issues a scroll offset update, it becomes impervious to - // scroll offset updates from APZ until we acknowledge the update it sent. - // This prevents APZ updates from clobbering scroll updates from other - // more "legitimate" sources like content scripts. - RefPtr controller = GetGeckoContentController(); - if (controller) { - APZC_LOG("%p sending scroll update acknowledgement with gen %u\n", this, mFrameMetrics.GetScrollGeneration()); - controller->AcknowledgeScrollUpdate(mFrameMetrics.GetScrollId(), - mFrameMetrics.GetScrollGeneration()); - } -} - const FrameMetrics& AsyncPanZoomController::GetFrameMetrics() const { mMonitor.AssertCurrentThreadIn(); return mFrameMetrics; @@ -3869,12 +3849,13 @@ AsyncPanZoomController::GetZoomConstraints() const } -void AsyncPanZoomController::PostDelayedTask(Task* aTask, int aDelayMs) { +void AsyncPanZoomController::PostDelayedTask(already_AddRefed aTask, int aDelayMs) { APZThreadUtils::AssertOnControllerThread(); RefPtr controller = GetGeckoContentController(); if (controller) { - controller->PostDelayedTask(aTask, aDelayMs); + controller->PostDelayedTask(Move(aTask), aDelayMs); } + // XXX khuey what is supposed to happen if there's no controller? We were leaking tasks ... } bool AsyncPanZoomController::Matches(const ScrollableLayerGuid& aGuid) diff --git a/gfx/layers/apz/src/AsyncPanZoomController.h b/gfx/layers/apz/src/AsyncPanZoomController.h index b822c0a5d2..01e806569b 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.h +++ b/gfx/layers/apz/src/AsyncPanZoomController.h @@ -146,7 +146,7 @@ public: * Schedules a runnable to run on the controller/UI thread at some time * in the future. */ - void PostDelayedTask(Task* aTask, int aDelayMs); + void PostDelayedTask(already_AddRefed aTask, int aDelayMs); // -------------------------------------------------------------------------- // These methods must only be called on the compositor thread. @@ -162,7 +162,7 @@ public: bool AdvanceAnimations(const TimeStamp& aSampleTime); bool UpdateAnimation(const TimeStamp& aSampleTime, - nsTArray* aOutDeferredTasks); + nsTArray>* aOutDeferredTasks); /** * A shadow layer update has arrived. |aScrollMetdata| is the new ScrollMetadata @@ -896,8 +896,6 @@ private: // Returns whether overscroll is allowed during an event. bool AllowScrollHandoffInCurrentBlock() const; - void AcknowledgeScrollUpdate() const; - /* =================================================================== * The functions and members in this section are used to make ancestor chains * out of APZC instances. These chains can only be walked or manipulated diff --git a/gfx/layers/apz/src/GestureEventListener.cpp b/gfx/layers/apz/src/GestureEventListener.cpp index 30766ba8fa..a655dc0e35 100644 --- a/gfx/layers/apz/src/GestureEventListener.cpp +++ b/gfx/layers/apz/src/GestureEventListener.cpp @@ -497,11 +497,12 @@ void GestureEventListener::CancelLongTapTimeoutTask() void GestureEventListener::CreateLongTapTimeoutTask() { - mLongTapTimeoutTask = + RefPtr task = NewRunnableMethod(this, &GestureEventListener::HandleInputTimeoutLongTap); + mLongTapTimeoutTask = task; mAsyncPanZoomController->PostDelayedTask( - mLongTapTimeoutTask, + task.forget(), gfxPrefs::UiClickHoldContextMenusDelay()); } @@ -523,12 +524,13 @@ void GestureEventListener::CreateMaxTapTimeoutTask() mLastTapInput = mLastTouchInput; TouchBlockState* block = mAsyncPanZoomController->GetInputQueue()->CurrentTouchBlock(); - mMaxTapTimeoutTask = + RefPtr task = NewRunnableMethod(this, &GestureEventListener::HandleInputTimeoutMaxTap, block->IsDuringFastFling()); + mMaxTapTimeoutTask = task; mAsyncPanZoomController->PostDelayedTask( - mMaxTapTimeoutTask, + task.forget(), MAX_TAP_TIME); } diff --git a/gfx/layers/apz/src/GestureEventListener.h b/gfx/layers/apz/src/GestureEventListener.h index 0a4fa0891c..1c89820ff1 100644 --- a/gfx/layers/apz/src/GestureEventListener.h +++ b/gfx/layers/apz/src/GestureEventListener.h @@ -14,9 +14,10 @@ #include "nsISupportsImpl.h" #include "nsTArray.h" // for nsTArray -class CancelableTask; - namespace mozilla { + +class CancelableRunnable; + namespace layers { class AsyncPanZoomController; @@ -214,7 +215,7 @@ private: * CancelLongTapTimeoutTask: Cancel the mLongTapTimeoutTask and also set * it to null. */ - CancelableTask *mLongTapTimeoutTask; + RefPtr mLongTapTimeoutTask; void CancelLongTapTimeoutTask(); void CreateLongTapTimeoutTask(); @@ -227,7 +228,7 @@ private: * CancelMaxTapTimeoutTask: Cancel the mMaxTapTimeoutTask and also set * it to null. */ - CancelableTask *mMaxTapTimeoutTask; + RefPtr mMaxTapTimeoutTask; void CancelMaxTapTimeoutTask(); void CreateMaxTapTimeoutTask(); }; diff --git a/gfx/layers/apz/test/gtest/APZTestCommon.h b/gfx/layers/apz/test/gtest/APZTestCommon.h index dfb4dd5875..e338b18edf 100644 --- a/gfx/layers/apz/test/gtest/APZTestCommon.h +++ b/gfx/layers/apz/test/gtest/APZTestCommon.h @@ -41,8 +41,6 @@ using ::testing::AtMost; using ::testing::MockFunction; using ::testing::InSequence; -class Task; - template class ScopedGfxPref { public: @@ -76,7 +74,10 @@ public: MOCK_METHOD3(HandleDoubleTap, void(const CSSPoint&, Modifiers, const ScrollableLayerGuid&)); MOCK_METHOD3(HandleSingleTap, void(const CSSPoint&, Modifiers, const ScrollableLayerGuid&)); MOCK_METHOD4(HandleLongTap, void(const CSSPoint&, Modifiers, const ScrollableLayerGuid&, uint64_t)); - MOCK_METHOD2(PostDelayedTask, void(Task* aTask, int aDelayMs)); + // Can't use the macros with already_AddRefed :( + void PostDelayedTask(already_AddRefed aTask, int aDelayMs) { + RefPtr task = aTask; + } MOCK_METHOD3(NotifyAPZStateChange, void(const ScrollableLayerGuid& aGuid, APZStateChange aChange, int aArg)); MOCK_METHOD0(NotifyFlushComplete, void()); }; @@ -104,7 +105,8 @@ public: mTime = target; } - void PostDelayedTask(Task* aTask, int aDelayMs) { + void PostDelayedTask(already_AddRefed aTask, int aDelayMs) { + RefPtr task = aTask; TimeStamp runAtTime = mTime + TimeDuration::FromMilliseconds(aDelayMs); int insIndex = mTaskQueue.Length(); while (insIndex > 0) { @@ -113,7 +115,7 @@ public: } insIndex--; } - mTaskQueue.InsertElementAt(insIndex, std::make_pair(aTask, runAtTime)); + mTaskQueue.InsertElementAt(insIndex, std::make_pair(task, runAtTime)); } // Run all the tasks in the queue, returning the number of tasks @@ -122,7 +124,7 @@ public: // in the queue after this function is called. Only when the return // value is 0 is the queue guaranteed to be empty. int RunThroughDelayedTasks() { - nsTArray> runQueue; + nsTArray, TimeStamp>> runQueue; runQueue.SwapElements(mTaskQueue); int numTasks = runQueue.Length(); for (int i = 0; i < numTasks; i++) { @@ -131,25 +133,25 @@ public: // Deleting the task is important in order to release the reference to // the callee object. - delete runQueue[i].first; + runQueue[i].first = nullptr; } return numTasks; } private: void RunNextDelayedTask() { - std::pair next = mTaskQueue[0]; + std::pair, TimeStamp> next = mTaskQueue[0]; mTaskQueue.RemoveElementAt(0); mTime = next.second; next.first->Run(); // Deleting the task is important in order to release the reference to // the callee object. - delete next.first; + next.first = nullptr; } // The following array is sorted by timestamp (tasks are inserted in order by // timestamp). - nsTArray> mTaskQueue; + nsTArray, TimeStamp>> mTaskQueue; TimeStamp mTime; }; diff --git a/gfx/layers/apz/util/APZCCallbackHelper.cpp b/gfx/layers/apz/util/APZCCallbackHelper.cpp index e591980366..dd857c7ecf 100644 --- a/gfx/layers/apz/util/APZCCallbackHelper.cpp +++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp @@ -126,9 +126,9 @@ ScrollFrame(nsIContent* aContent, // Scroll the window to the desired spot nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aMetrics.GetScrollId()); if (sf) { + sf->ResetScrollInfoIfGeneration(aMetrics.GetScrollGeneration()); sf->SetScrollableByAPZ(!aMetrics.IsScrollInfoLayer()); } - bool scrollUpdated = false; CSSPoint apzScrollOffset = aMetrics.GetScrollOffset(); CSSPoint actualScrollOffset = ScrollFrameTo(sf, apzScrollOffset, scrollUpdated); @@ -332,54 +332,6 @@ APZCCallbackHelper::InitializeRootDisplayport(nsIPresShell* aPresShell) } } -class AcknowledgeScrollUpdateEvent : public Runnable -{ - typedef mozilla::layers::FrameMetrics::ViewID ViewID; - -public: - AcknowledgeScrollUpdateEvent(const ViewID& aScrollId, const uint32_t& aScrollGeneration) - : mScrollId(aScrollId) - , mScrollGeneration(aScrollGeneration) - { - } - - NS_IMETHOD Run() override { - MOZ_ASSERT(NS_IsMainThread()); - - nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(mScrollId); - if (sf) { - sf->ResetScrollInfoIfGeneration(mScrollGeneration); - } - - // Since the APZ and content are in sync, we need to clear any callback transform - // that might have been set on the last repaint request (which might have failed - // due to the inflight scroll update that this message is acknowledging). - nsCOMPtr content = nsLayoutUtils::FindContentFor(mScrollId); - if (content) { - content->SetProperty(nsGkAtoms::apzCallbackTransform, new CSSPoint(), - nsINode::DeleteProperty); - } - - return NS_OK; - } - -protected: - ViewID mScrollId; - uint32_t mScrollGeneration; -}; - -void -APZCCallbackHelper::AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId, - const uint32_t& aScrollGeneration) -{ - nsCOMPtr r1 = new AcknowledgeScrollUpdateEvent(aScrollId, aScrollGeneration); - if (!NS_IsMainThread()) { - NS_DispatchToMainThread(r1); - } else { - r1->Run(); - } -} - nsIPresShell* APZCCallbackHelper::GetRootContentDocumentPresShellForContent(nsIContent* aContent) { diff --git a/gfx/layers/apz/util/APZCCallbackHelper.h b/gfx/layers/apz/util/APZCCallbackHelper.h index 3060e3ee3b..c421957823 100644 --- a/gfx/layers/apz/util/APZCCallbackHelper.h +++ b/gfx/layers/apz/util/APZCCallbackHelper.h @@ -66,11 +66,6 @@ public: given presShell. */ static void InitializeRootDisplayport(nsIPresShell* aPresShell); - /* Tell layout that we received the scroll offset update for the given view ID, so - that it accepts future scroll offset updates from APZ. */ - static void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId, - const uint32_t& aScrollGeneration); - /* Get the pres shell associated with the root content document enclosing |aContent|. */ static nsIPresShell* GetRootContentDocumentPresShellForContent(nsIContent* aContent); diff --git a/gfx/layers/apz/util/APZThreadUtils.cpp b/gfx/layers/apz/util/APZThreadUtils.cpp index c60b158d82..96fbc53aca 100644 --- a/gfx/layers/apz/util/APZThreadUtils.cpp +++ b/gfx/layers/apz/util/APZThreadUtils.cpp @@ -53,44 +53,43 @@ APZThreadUtils::AssertOnCompositorThread() } /*static*/ void -APZThreadUtils::RunOnControllerThread(Task* aTask) +APZThreadUtils::RunOnControllerThread(already_AddRefed aTask) { + RefPtr task = aTask; + #ifdef MOZ_ANDROID_APZ // This is needed while nsWindow::ConfigureAPZControllerThread is not propper // implemented. if (AndroidBridge::IsJavaUiThread()) { - aTask->Run(); - delete aTask; + task->Run(); } else { - AndroidBridge::Bridge()->PostTaskToUiThread(aTask, 0); + AndroidBridge::Bridge()->PostTaskToUiThread(task.forget(), 0); } #else if (!sControllerThread) { // Could happen on startup NS_WARNING("Dropping task posted to controller thread"); - delete aTask; return; } if (sControllerThread == MessageLoop::current()) { - aTask->Run(); - delete aTask; + task->Run(); } else { - sControllerThread->PostTask(FROM_HERE, aTask); + sControllerThread->PostTask(task.forget()); } #endif } /*static*/ void -APZThreadUtils::RunDelayedTaskOnCurrentThread(Task* aTask, +APZThreadUtils::RunDelayedTaskOnCurrentThread(already_AddRefed aTask, const TimeDuration& aDelay) { if (MessageLoop* messageLoop = MessageLoop::current()) { - messageLoop->PostDelayedTask(FROM_HERE, aTask, aDelay.ToMilliseconds()); + messageLoop->PostDelayedTask(Move(aTask), aDelay.ToMilliseconds()); } else { #ifdef MOZ_ANDROID_APZ // Fennec does not have a MessageLoop::current() on the controller thread. - AndroidBridge::Bridge()->PostTaskToUiThread(aTask, aDelay.ToMilliseconds()); + AndroidBridge::Bridge()->PostTaskToUiThread(Move(aTask), aDelay.ToMilliseconds()); #else // Other platforms should. MOZ_RELEASE_ASSERT(false, "This non-Fennec platform should have a MessageLoop::current()"); diff --git a/gfx/layers/apz/util/APZThreadUtils.h b/gfx/layers/apz/util/APZThreadUtils.h index 8fdbb1e809..0accd19afc 100644 --- a/gfx/layers/apz/util/APZThreadUtils.h +++ b/gfx/layers/apz/util/APZThreadUtils.h @@ -10,9 +10,10 @@ #include "mozilla/TimeStamp.h" // for TimeDuration #include "nsITimer.h" -class Task; - namespace mozilla { + +class Runnable; + namespace layers { class APZThreadUtils @@ -50,12 +51,12 @@ public: * this function is called from the controller thread itself then the task is * run immediately without getting queued. */ - static void RunOnControllerThread(Task* aTask); + static void RunOnControllerThread(already_AddRefed aTask); /** * Runs the given task on the current thread after a delay of |aDelay|. */ - static void RunDelayedTaskOnCurrentThread(Task* aTask, + static void RunDelayedTaskOnCurrentThread(already_AddRefed aTask, const TimeDuration& aDelay); /** diff --git a/gfx/layers/apz/util/ActiveElementManager.cpp b/gfx/layers/apz/util/ActiveElementManager.cpp index 83e5db0e50..436fa0436c 100644 --- a/gfx/layers/apz/util/ActiveElementManager.cpp +++ b/gfx/layers/apz/util/ActiveElementManager.cpp @@ -94,10 +94,10 @@ ActiveElementManager::TriggerElementActivation() // bug properly should make this unnecessary. MOZ_ASSERT(mSetActiveTask == nullptr); - mSetActiveTask = NewRunnableMethod( + RefPtr task = NewRunnableMethod( this, &ActiveElementManager::SetActiveTask, mTarget); - MessageLoop::current()->PostDelayedTask( - FROM_HERE, mSetActiveTask, sActivationDelayMs); + mSetActiveTask = task; + MessageLoop::current()->PostDelayedTask(task.forget(), sActivationDelayMs); AEM_LOG("Scheduling mSetActiveTask %p\n", mSetActiveTask); } } @@ -209,7 +209,7 @@ ActiveElementManager::ResetTouchBlockState() } void -ActiveElementManager::SetActiveTask(dom::Element* aTarget) +ActiveElementManager::SetActiveTask(const nsCOMPtr& aTarget) { AEM_LOG("mSetActiveTask %p running\n", mSetActiveTask); diff --git a/gfx/layers/apz/util/ActiveElementManager.h b/gfx/layers/apz/util/ActiveElementManager.h index 184a71df2d..83d0cb29fa 100644 --- a/gfx/layers/apz/util/ActiveElementManager.h +++ b/gfx/layers/apz/util/ActiveElementManager.h @@ -9,9 +9,10 @@ #include "nsCOMPtr.h" #include "nsISupportsImpl.h" -class CancelableTask; - namespace mozilla { + +class CancelableRunnable; + namespace dom { class Element; class EventTarget; @@ -82,7 +83,7 @@ private: /** * A task for calling SetActive() after a timeout. */ - CancelableTask* mSetActiveTask; + RefPtr mSetActiveTask; /** * See ActiveElementUsesStyle() documentation. */ @@ -93,7 +94,7 @@ private: void SetActive(dom::Element* aTarget); void ResetActive(); void ResetTouchBlockState(); - void SetActiveTask(dom::Element* aTarget); + void SetActiveTask(const nsCOMPtr& aTarget); void CancelTask(); }; diff --git a/gfx/layers/apz/util/ChromeProcessController.cpp b/gfx/layers/apz/util/ChromeProcessController.cpp index 6b553730e1..ee7aab2375 100644 --- a/gfx/layers/apz/util/ChromeProcessController.cpp +++ b/gfx/layers/apz/util/ChromeProcessController.cpp @@ -37,7 +37,6 @@ ChromeProcessController::ChromeProcessController(nsIWidget* aWidget, MOZ_ASSERT(aAPZCTreeManager); mUILoop->PostTask( - FROM_HERE, NewRunnableMethod(this, &ChromeProcessController::InitializeRoot)); } @@ -63,16 +62,9 @@ ChromeProcessController::RequestContentRepaint(const FrameMetrics& aFrameMetrics } void -ChromeProcessController::PostDelayedTask(Task* aTask, int aDelayMs) +ChromeProcessController::PostDelayedTask(already_AddRefed aTask, int aDelayMs) { - MessageLoop::current()->PostDelayedTask(FROM_HERE, aTask, aDelayMs); -} - -void -ChromeProcessController::AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId, - const uint32_t& aScrollGeneration) -{ - APZCCallbackHelper::AcknowledgeScrollUpdate(aScrollId, aScrollGeneration); + MessageLoop::current()->PostDelayedTask(Move(aTask), aDelayMs); } void @@ -80,7 +72,6 @@ ChromeProcessController::Destroy() { if (MessageLoop::current() != mUILoop) { mUILoop->PostTask( - FROM_HERE, NewRunnableMethod(this, &ChromeProcessController::Destroy)); return; } @@ -131,7 +122,6 @@ ChromeProcessController::HandleDoubleTap(const mozilla::CSSPoint& aPoint, { if (MessageLoop::current() != mUILoop) { mUILoop->PostTask( - FROM_HERE, NewRunnableMethod(this, &ChromeProcessController::HandleDoubleTap, aPoint, aModifiers, aGuid)); return; @@ -169,7 +159,6 @@ ChromeProcessController::HandleSingleTap(const CSSPoint& aPoint, { if (MessageLoop::current() != mUILoop) { mUILoop->PostTask( - FROM_HERE, NewRunnableMethod(this, &ChromeProcessController::HandleSingleTap, aPoint, aModifiers, aGuid)); return; @@ -185,7 +174,6 @@ ChromeProcessController::HandleLongTap(const mozilla::CSSPoint& aPoint, Modifier { if (MessageLoop::current() != mUILoop) { mUILoop->PostTask( - FROM_HERE, NewRunnableMethod(this, &ChromeProcessController::HandleLongTap, aPoint, aModifiers, aGuid, aInputBlockId)); return; @@ -202,7 +190,6 @@ ChromeProcessController::NotifyAPZStateChange(const ScrollableLayerGuid& aGuid, { if (MessageLoop::current() != mUILoop) { mUILoop->PostTask( - FROM_HERE, NewRunnableMethod(this, &ChromeProcessController::NotifyAPZStateChange, aGuid, aChange, aArg)); return; @@ -216,7 +203,6 @@ ChromeProcessController::NotifyMozMouseScrollEvent(const FrameMetrics::ViewID& a { if (MessageLoop::current() != mUILoop) { mUILoop->PostTask( - FROM_HERE, NewRunnableMethod(this, &ChromeProcessController::NotifyMozMouseScrollEvent, aScrollId, aEvent)); return; } diff --git a/gfx/layers/apz/util/ChromeProcessController.h b/gfx/layers/apz/util/ChromeProcessController.h index 47b3d3535b..f9dcd6d8ca 100644 --- a/gfx/layers/apz/util/ChromeProcessController.h +++ b/gfx/layers/apz/util/ChromeProcessController.h @@ -39,10 +39,7 @@ public: // GeckoContentController interface virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) override; - virtual void PostDelayedTask(Task* aTask, int aDelayMs) override; - virtual void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId, - const uint32_t& aScrollGeneration) override; - + virtual void PostDelayedTask(already_AddRefed aTask, int aDelayMs) override; virtual void HandleDoubleTap(const mozilla::CSSPoint& aPoint, Modifiers aModifiers, const ScrollableLayerGuid& aGuid) override; virtual void HandleSingleTap(const mozilla::CSSPoint& aPoint, Modifiers aModifiers, diff --git a/gfx/layers/client/CompositableClient.cpp b/gfx/layers/client/CompositableClient.cpp index 6e875ab21c..352366b799 100644 --- a/gfx/layers/client/CompositableClient.cpp +++ b/gfx/layers/client/CompositableClient.cpp @@ -64,10 +64,10 @@ RemoveTextureFromCompositableTracker::ReleaseTextureClient() mTextureClient->GetAllocator() && !mTextureClient->GetAllocator()->UsesImageBridge()) { - TextureClientReleaseTask* task = new TextureClientReleaseTask(mTextureClient); + RefPtr task = new TextureClientReleaseTask(mTextureClient); RefPtr allocator = mTextureClient->GetAllocator(); mTextureClient = nullptr; - allocator->AsClientAllocator()->GetMessageLoop()->PostTask(FROM_HERE, task); + allocator->AsClientAllocator()->GetMessageLoop()->PostTask(task.forget()); } else { mTextureClient = nullptr; } diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp index 51ac5dbe34..52ab0a5eb5 100644 --- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -257,15 +257,14 @@ DeallocateTextureClient(TextureDeallocParams params) bool done = false; ReentrantMonitor barrier("DeallocateTextureClient"); ReentrantMonitorAutoEnter autoMon(barrier); - ipdlMsgLoop->PostTask(FROM_HERE, - NewRunnableFunction(DeallocateTextureClientSyncProxy, - params, &barrier, &done)); + ipdlMsgLoop->PostTask(NewRunnableFunction(DeallocateTextureClientSyncProxy, + params, &barrier, &done)); while (!done) { barrier.Wait(); } } else { - ipdlMsgLoop->PostTask(FROM_HERE, - NewRunnableFunction(DeallocateTextureClient, params)); + ipdlMsgLoop->PostTask(NewRunnableFunction(DeallocateTextureClient, + params)); } // The work has been forwarded to the IPDL thread, we are done. return; diff --git a/gfx/layers/client/TextureClient.h b/gfx/layers/client/TextureClient.h index f4d2cbf58b..ecab6a6c70 100644 --- a/gfx/layers/client/TextureClient.h +++ b/gfx/layers/client/TextureClient.h @@ -659,16 +659,17 @@ public: /** * Task that releases TextureClient pointer on a specified thread. */ -class TextureClientReleaseTask : public Task +class TextureClientReleaseTask : public Runnable { public: explicit TextureClientReleaseTask(TextureClient* aClient) : mTextureClient(aClient) { } - virtual void Run() override + NS_IMETHOD Run() override { mTextureClient = nullptr; + return NS_OK; } private: diff --git a/gfx/layers/client/TextureClientRecycleAllocator.cpp b/gfx/layers/client/TextureClientRecycleAllocator.cpp index db025845f6..34a49656ce 100644 --- a/gfx/layers/client/TextureClientRecycleAllocator.cpp +++ b/gfx/layers/client/TextureClientRecycleAllocator.cpp @@ -93,7 +93,7 @@ TextureClientRecycleAllocator::SetMaxPoolSize(uint32_t aMax) mMaxPooledSize = aMax; } -class TextureClientRecycleTask : public Task +class TextureClientRecycleTask : public Runnable { public: explicit TextureClientRecycleTask(TextureClient* aClient, TextureFlags aFlags) @@ -101,9 +101,10 @@ public: , mFlags(aFlags) {} - virtual void Run() override + NS_IMETHOD Run() override { mTextureClient->RecycleTexture(mFlags); + return NS_OK; } private: @@ -146,7 +147,7 @@ TextureClientRecycleAllocator::CreateOrRecycle(ITextureClientAllocationHelper& a if (!mPooledClients.empty()) { textureHolder = mPooledClients.top(); mPooledClients.pop(); - Task* task = nullptr; + RefPtr task; // If a pooled TextureClient is not compatible, release it. if (!aHelper.IsCompatible(textureHolder->GetTextureClient())) { // Release TextureClient. @@ -156,7 +157,7 @@ TextureClientRecycleAllocator::CreateOrRecycle(ITextureClientAllocationHelper& a } else { task = new TextureClientRecycleTask(textureHolder->GetTextureClient(), aHelper.mTextureFlags); } - mSurfaceAllocator->GetMessageLoop()->PostTask(FROM_HERE, task); + mSurfaceAllocator->GetMessageLoop()->PostTask(task.forget()); } } diff --git a/gfx/layers/ipc/APZChild.cpp b/gfx/layers/ipc/APZChild.cpp index 6efdaef95a..952d4f16dd 100644 --- a/gfx/layers/ipc/APZChild.cpp +++ b/gfx/layers/ipc/APZChild.cpp @@ -99,14 +99,6 @@ APZChild::RecvUpdateFrame(const FrameMetrics& aFrameMetrics) return mBrowser->UpdateFrame(aFrameMetrics); } -bool -APZChild::RecvAcknowledgeScrollUpdate(const ViewID& aScrollId, - const uint32_t& aScrollGeneration) -{ - APZCCallbackHelper::AcknowledgeScrollUpdate(aScrollId, aScrollGeneration); - return true; -} - bool APZChild::RecvHandleDoubleTap(const CSSPoint& aPoint, const Modifiers& aModifiers, diff --git a/gfx/layers/ipc/APZChild.h b/gfx/layers/ipc/APZChild.h index 4faefd96a3..348cab6cea 100644 --- a/gfx/layers/ipc/APZChild.h +++ b/gfx/layers/ipc/APZChild.h @@ -28,9 +28,6 @@ public: virtual bool RecvUpdateFrame(const FrameMetrics& frame) override; - virtual bool RecvAcknowledgeScrollUpdate(const ViewID& aScrollId, - const uint32_t& aScrollGeneration) override; - virtual bool RecvHandleDoubleTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid) override; diff --git a/gfx/layers/ipc/CompositorBridgeChild.cpp b/gfx/layers/ipc/CompositorBridgeChild.cpp index 8e0826d46e..a76d819939 100644 --- a/gfx/layers/ipc/CompositorBridgeChild.cpp +++ b/gfx/layers/ipc/CompositorBridgeChild.cpp @@ -10,7 +10,6 @@ #include "ClientLayerManager.h" // for ClientLayerManager #include "base/message_loop.h" // for MessageLoop #include "base/task.h" // for NewRunnableMethod, etc -#include "base/tracked.h" // for FROM_HERE #include "mozilla/layers/LayerTransactionChild.h" #include "mozilla/layers/PLayerTransactionChild.h" #include "mozilla/mozalloc.h" // for operator new, etc @@ -46,8 +45,8 @@ CompositorBridgeChild::CompositorBridgeChild(ClientLayerManager *aLayerManager) CompositorBridgeChild::~CompositorBridgeChild() { - XRE_GetIOMessageLoop()->PostTask(FROM_HERE, - new DeleteTask(GetTransport())); + RefPtr> task = new DeleteTask(GetTransport()); + XRE_GetIOMessageLoop()->PostTask(task.forget()); if (mCanSend) { gfxCriticalError() << "CompositorBridgeChild was not deinitialized"; @@ -111,7 +110,7 @@ CompositorBridgeChild::Destroy() // handle compositor desctruction. // From now on we can't send any message message. - MessageLoop::current()->PostTask(FROM_HERE, + MessageLoop::current()->PostTask( NewRunnableFunction(DeferredDestroyCompositor, mCompositorBridgeParent, selfRef)); } diff --git a/gfx/layers/ipc/CompositorBridgeParent.cpp b/gfx/layers/ipc/CompositorBridgeParent.cpp index 82db271424..4783c89e42 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CompositorBridgeParent.cpp @@ -15,7 +15,6 @@ #include "base/process.h" // for ProcessId #include "base/task.h" // for CancelableTask, etc #include "base/thread.h" // for Thread -#include "base/tracked.h" // for FROM_HERE #include "gfxContext.h" // for gfxContext #include "gfxPlatform.h" // for gfxPlatform #ifdef MOZ_WIDGET_GTK @@ -362,10 +361,10 @@ CompositorVsyncScheduler::SetDisplay(bool aDisplayEnable) if (!CompositorBridgeParent::IsInCompositorThread()) { MOZ_ASSERT(NS_IsMainThread()); MonitorAutoLock lock(mSetDisplayMonitor); - mSetDisplayTask = NewRunnableMethod(this, - &CompositorVsyncScheduler::SetDisplay, - aDisplayEnable); - ScheduleTask(mSetDisplayTask, 0); + RefPtr task = + NewRunnableMethod(this, &CompositorVsyncScheduler::SetDisplay, aDisplayEnable); + mSetDisplayTask = task; + ScheduleTask(task.forget(), 0); return; } else { MonitorAutoLock lock(mSetDisplayMonitor); @@ -427,10 +426,11 @@ CompositorVsyncScheduler::PostCompositeTask(TimeStamp aCompositeTimestamp) // can be called from the compositor or vsync thread MonitorAutoLock lock(mCurrentCompositeTaskMonitor); if (mCurrentCompositeTask == nullptr) { - mCurrentCompositeTask = NewRunnableMethod(this, - &CompositorVsyncScheduler::Composite, - aCompositeTimestamp); - ScheduleTask(mCurrentCompositeTask, 0); + RefPtr task = + NewRunnableMethod(this, &CompositorVsyncScheduler::Composite, + aCompositeTimestamp); + mCurrentCompositeTask = task; + ScheduleTask(task.forget(), 0); } } @@ -480,9 +480,10 @@ CompositorVsyncScheduler::SetNeedsComposite() { if (!CompositorBridgeParent::IsInCompositorThread()) { MonitorAutoLock lock(mSetNeedsCompositeMonitor); - mSetNeedsCompositeTask = NewRunnableMethod(this, - &CompositorVsyncScheduler::SetNeedsComposite); - ScheduleTask(mSetNeedsCompositeTask, 0); + RefPtr task = + NewRunnableMethod(this, &CompositorVsyncScheduler::SetNeedsComposite); + mSetNeedsCompositeTask = task; + ScheduleTask(task.forget(), 0); return; } else { MonitorAutoLock lock(mSetNeedsCompositeMonitor); @@ -659,11 +660,12 @@ MessageLoop* CompositorBridgeParent::CompositorLoop() } void -CompositorVsyncScheduler::ScheduleTask(CancelableTask* aTask, int aTime) +CompositorVsyncScheduler::ScheduleTask(already_AddRefed aTask, + int aTime) { MOZ_ASSERT(CompositorBridgeParent::CompositorLoop()); MOZ_ASSERT(aTime >= 0); - CompositorBridgeParent::CompositorLoop()->PostDelayedTask(FROM_HERE, aTask, aTime); + CompositorBridgeParent::CompositorLoop()->PostDelayedTask(Move(aTask), aTime); } void @@ -714,10 +716,10 @@ CompositorBridgeParent::CompositorBridgeParent(nsIWidget* aWidget, // can destroy this instance is initialized on the compositor thread after // this task has been processed. MOZ_ASSERT(CompositorLoop()); - CompositorLoop()->PostTask(FROM_HERE, NewRunnableFunction(&AddCompositor, - this, &mCompositorID)); + CompositorLoop()->PostTask(NewRunnableFunction(&AddCompositor, + this, &mCompositorID)); - CompositorLoop()->PostTask(FROM_HERE, NewRunnableFunction(SetThreadPriority)); + CompositorLoop()->PostTask(NewRunnableFunction(SetThreadPriority)); { // scope lock @@ -980,25 +982,22 @@ CompositorBridgeParent::ActorDestroy(ActorDestroyReason why) // We must keep the compositor parent alive untill the code handling message // reception is finished on this thread. mSelfRef = this; - MessageLoop::current()->PostTask(FROM_HERE, - NewRunnableMethod(this,&CompositorBridgeParent::DeferredDestroy)); + MessageLoop::current()->PostTask(NewRunnableMethod(this,&CompositorBridgeParent::DeferredDestroy)); } void CompositorBridgeParent::ScheduleRenderOnCompositorThread() { - CancelableTask *renderTask = NewRunnableMethod(this, &CompositorBridgeParent::ScheduleComposition); MOZ_ASSERT(CompositorLoop()); - CompositorLoop()->PostTask(FROM_HERE, renderTask); + CompositorLoop()->PostTask(NewRunnableMethod(this, &CompositorBridgeParent::ScheduleComposition)); } void CompositorBridgeParent::InvalidateOnCompositorThread() { - CancelableTask *renderTask = NewRunnableMethod(this, &CompositorBridgeParent::Invalidate); MOZ_ASSERT(CompositorLoop()); - CompositorLoop()->PostTask(FROM_HERE, renderTask); + CompositorLoop()->PostTask(NewRunnableMethod(this, &CompositorBridgeParent::Invalidate)); } void @@ -1088,10 +1087,8 @@ CompositorBridgeParent::SchedulePauseOnCompositorThread() { MonitorAutoLock lock(mPauseCompositionMonitor); - CancelableTask *pauseTask = NewRunnableMethod(this, - &CompositorBridgeParent::PauseComposition); MOZ_ASSERT(CompositorLoop()); - CompositorLoop()->PostTask(FROM_HERE, pauseTask); + CompositorLoop()->PostTask(NewRunnableMethod(this, &CompositorBridgeParent::PauseComposition)); // Wait until the pause has actually been processed by the compositor thread lock.Wait(); @@ -1102,10 +1099,8 @@ CompositorBridgeParent::ScheduleResumeOnCompositorThread() { MonitorAutoLock lock(mResumeCompositionMonitor); - CancelableTask *resumeTask = - NewRunnableMethod(this, &CompositorBridgeParent::ResumeComposition); MOZ_ASSERT(CompositorLoop()); - CompositorLoop()->PostTask(FROM_HERE, resumeTask); + CompositorLoop()->PostTask(NewRunnableMethod(this, &CompositorBridgeParent::ResumeComposition)); // Wait until the resume has actually been processed by the compositor thread lock.Wait(); @@ -1118,10 +1113,8 @@ CompositorBridgeParent::ScheduleResumeOnCompositorThread(int width, int height) { MonitorAutoLock lock(mResumeCompositionMonitor); - CancelableTask *resumeTask = - NewRunnableMethod(this, &CompositorBridgeParent::ResumeCompositionAndResize, width, height); MOZ_ASSERT(CompositorLoop()); - CompositorLoop()->PostTask(FROM_HERE, resumeTask); + CompositorLoop()->PostTask(NewRunnableMethod(this, &CompositorBridgeParent::ResumeCompositionAndResize, width, height)); // Wait until the resume has actually been processed by the compositor thread lock.Wait(); @@ -1130,12 +1123,12 @@ CompositorBridgeParent::ScheduleResumeOnCompositorThread(int width, int height) } void -CompositorBridgeParent::ScheduleTask(CancelableTask* task, int time) +CompositorBridgeParent::ScheduleTask(already_AddRefed task, int time) { if (time == 0) { - MessageLoop::current()->PostTask(FROM_HERE, task); + MessageLoop::current()->PostTask(Move(task)); } else { - MessageLoop::current()->PostDelayedTask(FROM_HERE, task, time); + MessageLoop::current()->PostDelayedTask(Move(task), time); } } @@ -1372,8 +1365,9 @@ CompositorBridgeParent::ScheduleRotationOnCompositorThread(const TargetConfig& a if (mForceCompositionTask != nullptr) { mForceCompositionTask->Cancel(); } - mForceCompositionTask = NewRunnableMethod(this, &CompositorBridgeParent::ForceComposition); - ScheduleTask(mForceCompositionTask, gfxPrefs::OrientationSyncMillis()); + RefPtr task = NewRunnableMethod(this, &CompositorBridgeParent::ForceComposition); + mForceCompositionTask = task; + ScheduleTask(task.forget(), gfxPrefs::OrientationSyncMillis()); } } @@ -1528,7 +1522,7 @@ CompositorBridgeParent::GetAPZTestData(const LayerTransactionParent* aLayerTree, *aOutData = sIndirectLayerTrees[mRootLayerTreeID].mApzTestData; } -class NotifyAPZConfirmedTargetTask : public Task +class NotifyAPZConfirmedTargetTask : public Runnable { public: explicit NotifyAPZConfirmedTargetTask(const RefPtr& aAPZCTM, @@ -1540,8 +1534,9 @@ public: { } - virtual void Run() override { + NS_IMETHOD Run() override { mAPZCTM->SetTargetAPZC(mInputBlockId, mTargets); + return NS_OK; } private: @@ -1558,8 +1553,10 @@ CompositorBridgeParent::SetConfirmedTargetAPZC(const LayerTransactionParent* aLa if (!mApzcTreeManager) { return; } - APZThreadUtils::RunOnControllerThread(new NotifyAPZConfirmedTargetTask( - mApzcTreeManager, aInputBlockId, aTargets)); + RefPtr task = + new NotifyAPZConfirmedTargetTask(mApzcTreeManager, aInputBlockId, aTargets); + APZThreadUtils::RunOnControllerThread(task.forget()); + } void @@ -1776,8 +1773,7 @@ CompositorBridgeParent::DeallocateLayerTreeId(uint64_t aId) gfxCriticalError() << "Attempting to post to a invalid Compositor Loop"; return; } - CompositorLoop()->PostTask(FROM_HERE, - NewRunnableFunction(&EraseLayerState, aId)); + CompositorLoop()->PostTask(NewRunnableFunction(&EraseLayerState, aId)); } /* static */ void @@ -1827,8 +1823,7 @@ CompositorBridgeParent::SetControllerForLayerTree(uint64_t aLayersId, { // This ref is adopted by UpdateControllerForLayersId(). aController->AddRef(); - CompositorLoop()->PostTask(FROM_HERE, - NewRunnableFunction(&UpdateControllerForLayersId, + CompositorLoop()->PostTask(NewRunnableFunction(&UpdateControllerForLayersId, aLayersId, aController)); } @@ -1871,7 +1866,7 @@ CompositorBridgeParent::PostInsertVsyncProfilerMarker(TimeStamp aVsyncTimestamp) { // Called in the vsync thread if (profiler_is_active() && sCompositorThreadHolder) { - CompositorLoop()->PostTask(FROM_HERE, + CompositorLoop()->PostTask( NewRunnableFunction(InsertVsyncProfilerMarker, aVsyncTimestamp)); } } @@ -2111,7 +2106,7 @@ CompositorBridgeParent::ResetCompositor(const nsTArray& aBackendH { MonitorAutoLock lock(mResetCompositorMonitor); - CompositorLoop()->PostTask(FROM_HERE, + CompositorLoop()->PostTask( NewRunnableMethod(this, &CompositorBridgeParent::ResetCompositorTask, aBackendHints, @@ -2221,7 +2216,6 @@ CompositorBridgeParent::Create(Transport* aTransport, ProcessId aOtherPid, Gecko cpcp->mSelfRef = cpcp; CompositorLoop()->PostTask( - FROM_HERE, NewRunnableFunction(OpenCompositor, cpcp.get(), aTransport, aOtherPid, XRE_GetIOMessageLoop())); // The return value is just compared to null for success checking, @@ -2284,7 +2278,7 @@ CrossProcessCompositorBridgeParent::ActorDestroy(ActorDestroyReason aWhy) // We must keep this object alive untill the code handling message // reception is finished on this thread. - MessageLoop::current()->PostTask(FROM_HERE, + MessageLoop::current()->PostTask( NewRunnableMethod(this, &CrossProcessCompositorBridgeParent::DeferredDestroy)); } @@ -2529,10 +2523,8 @@ CompositorBridgeParent::UpdatePluginWindowState(uint64_t aId) void CompositorBridgeParent::ScheduleShowAllPluginWindows() { - CancelableTask *pluginTask = - NewRunnableMethod(this, &CompositorBridgeParent::ShowAllPluginWindows); MOZ_ASSERT(CompositorLoop()); - CompositorLoop()->PostTask(FROM_HERE, pluginTask); + CompositorLoop()->PostTask(NewRunnableMethod(this, &CompositorBridgeParent::ShowAllPluginWindows)); } void @@ -2546,10 +2538,8 @@ CompositorBridgeParent::ShowAllPluginWindows() void CompositorBridgeParent::ScheduleHideAllPluginWindows() { - CancelableTask *pluginTask = - NewRunnableMethod(this, &CompositorBridgeParent::HideAllPluginWindows); MOZ_ASSERT(CompositorLoop()); - CompositorLoop()->PostTask(FROM_HERE, pluginTask); + CompositorLoop()->PostTask(NewRunnableMethod(this, &CompositorBridgeParent::HideAllPluginWindows)); } void @@ -2742,8 +2732,8 @@ CrossProcessCompositorBridgeParent::~CrossProcessCompositorBridgeParent() { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(XRE_GetIOMessageLoop()); - XRE_GetIOMessageLoop()->PostTask(FROM_HERE, - new DeleteTask(mTransport)); + RefPtr> task = new DeleteTask(mTransport); + XRE_GetIOMessageLoop()->PostTask(task.forget()); } IToplevelProtocol* diff --git a/gfx/layers/ipc/CompositorBridgeParent.h b/gfx/layers/ipc/CompositorBridgeParent.h index aa8a898b36..c2841dee98 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.h +++ b/gfx/layers/ipc/CompositorBridgeParent.h @@ -39,11 +39,13 @@ #include "ThreadSafeRefcountingWithMainThreadDestruction.h" #include "mozilla/VsyncDispatcher.h" -class CancelableTask; class MessageLoop; class nsIWidget; namespace mozilla { + +class CancelableRunnable; + namespace gfx { class DrawTarget; } // namespace gfx @@ -126,7 +128,7 @@ public: void SetNeedsComposite(); void OnForceComposeToTarget(); - void ScheduleTask(CancelableTask*, int); + void ScheduleTask(already_AddRefed, int); void ResumeComposition(); void ComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr); void PostCompositeTask(TimeStamp aCompositeTimestamp); @@ -193,16 +195,16 @@ private: RefPtr mVsyncObserver; mozilla::Monitor mCurrentCompositeTaskMonitor; - CancelableTask* mCurrentCompositeTask; + RefPtr mCurrentCompositeTask; mozilla::Monitor mSetNeedsCompositeMonitor; - CancelableTask* mSetNeedsCompositeTask; + RefPtr mSetNeedsCompositeTask; #ifdef MOZ_WIDGET_GONK #if ANDROID_VERSION >= 19 bool mDisplayEnabled; mozilla::Monitor mSetDisplayMonitor; - CancelableTask* mSetDisplayTask; + RefPtr mSetDisplayTask; #endif #endif }; @@ -524,7 +526,7 @@ protected: TextureFactoryIdentifier* aTextureFactoryIdentifier, bool* aSuccess) override; virtual bool DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers) override; - virtual void ScheduleTask(CancelableTask*, int); + virtual void ScheduleTask(already_AddRefed, int); void CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr); void SetEGLSurfaceSize(int width, int height); @@ -586,7 +588,7 @@ protected: const uint64_t mRootLayerTreeID; bool mOverrideComposeReadiness; - CancelableTask* mForceCompositionTask; + RefPtr mForceCompositionTask; RefPtr mApzcTreeManager; diff --git a/gfx/layers/ipc/ImageBridgeChild.cpp b/gfx/layers/ipc/ImageBridgeChild.cpp index 76d5aec382..eae77d0be3 100644 --- a/gfx/layers/ipc/ImageBridgeChild.cpp +++ b/gfx/layers/ipc/ImageBridgeChild.cpp @@ -14,7 +14,6 @@ #include "base/process.h" // for ProcessId #include "base/task.h" // for NewRunnableFunction, etc #include "base/thread.h" // for Thread -#include "base/tracked.h" // for FROM_HERE #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc #include "mozilla/Monitor.h" // for Monitor, MonitorAutoLock #include "mozilla/ReentrantMonitor.h" // for ReentrantMonitor, etc @@ -354,8 +353,9 @@ ImageBridgeChild::~ImageBridgeChild() { MOZ_ASSERT(NS_IsMainThread()); - XRE_GetIOMessageLoop()->PostTask(FROM_HERE, - new DeleteTask(GetTransport())); + RefPtr> task = new DeleteTask(GetTransport()); + + XRE_GetIOMessageLoop()->PostTask(task.forget()); delete mTxn; } @@ -437,8 +437,7 @@ ConnectImageBridgeInChildProcess(Transport* aTransport, #ifdef MOZ_NUWA_PROCESS if (IsNuwaProcess()) { sImageBridgeChildThread - ->message_loop()->PostTask(FROM_HERE, - NewRunnableFunction(NuwaMarkCurrentThread, + ->message_loop()->PostTask(NewRunnableFunction(NuwaMarkCurrentThread, (void (*)(void *))nullptr, (void *)nullptr)); } @@ -481,7 +480,6 @@ void ImageBridgeChild::DispatchReleaseImageClient(ImageClient* aClient, } sImageBridgeChildSingleton->GetMessageLoop()->PostTask( - FROM_HERE, NewRunnableFunction(&ReleaseImageClientNow, aClient, aChild)); } @@ -510,7 +508,6 @@ void ImageBridgeChild::DispatchReleaseCanvasClient(CanvasClient* aClient) } sImageBridgeChildSingleton->GetMessageLoop()->PostTask( - FROM_HERE, NewRunnableFunction(&ReleaseCanvasClientNow, aClient)); } @@ -539,7 +536,6 @@ void ImageBridgeChild::DispatchReleaseTextureClient(TextureClient* aClient) } sImageBridgeChildSingleton->GetMessageLoop()->PostTask( - FROM_HERE, NewRunnableFunction(&ReleaseTextureClientNow, aClient)); } @@ -575,7 +571,6 @@ void ImageBridgeChild::DispatchImageClientUpdate(ImageClient* aClient, return; } sImageBridgeChildSingleton->GetMessageLoop()->PostTask( - FROM_HERE, NewRunnableFunction(&UpdateImageClientNow, aClient, RefPtr(aContainer))); } @@ -605,7 +600,6 @@ void ImageBridgeChild::UpdateAsyncCanvasRenderer(AsyncCanvasRenderer* aWrapper) bool done = false; sImageBridgeChildSingleton->GetMessageLoop()->PostTask( - FROM_HERE, NewRunnableFunction(&UpdateAsyncCanvasRendererSync, aWrapper, &barrier, &done)); // should stop the thread until the CanvasClient has been created on @@ -696,7 +690,6 @@ void ImageBridgeChild::FlushAllImages(ImageClient* aClient, waiter->IncrementWaitCount(); #endif sImageBridgeChildSingleton->GetMessageLoop()->PostTask( - FROM_HERE, NewRunnableFunction(&FlushAllImagesSync, aClient, aContainer, waiter, &barrier, &done)); while (!done) { @@ -790,11 +783,9 @@ ImageBridgeChild::StartUpInChildProcess(Transport* aTransport, sImageBridgeChildSingleton = new ImageBridgeChild(); sImageBridgeChildSingleton->GetMessageLoop()->PostTask( - FROM_HERE, NewRunnableFunction(ConnectImageBridgeInChildProcess, aTransport, aOtherPid)); sImageBridgeChildSingleton->GetMessageLoop()->PostTask( - FROM_HERE, NewRunnableFunction(CallSendImageBridgeThreadId, sImageBridgeChildSingleton.get())); @@ -815,7 +806,7 @@ void ImageBridgeChild::ShutDown() ReentrantMonitorAutoEnter autoMon(barrier); bool done = false; - sImageBridgeChildSingleton->GetMessageLoop()->PostTask(FROM_HERE, + sImageBridgeChildSingleton->GetMessageLoop()->PostTask( NewRunnableFunction(&ImageBridgeShutdownStep1, &barrier, &done)); while (!done) { barrier.Wait(); @@ -827,7 +818,7 @@ void ImageBridgeChild::ShutDown() ReentrantMonitorAutoEnter autoMon(barrier); bool done = false; - sImageBridgeChildSingleton->GetMessageLoop()->PostTask(FROM_HERE, + sImageBridgeChildSingleton->GetMessageLoop()->PostTask( NewRunnableFunction(&ImageBridgeShutdownStep2, &barrier, &done)); while (!done) { barrier.Wait(); @@ -854,7 +845,6 @@ bool ImageBridgeChild::StartUpOnThread(Thread* aThread) CompositorBridgeParent::CompositorLoop(), nullptr, base::GetCurrentProcId()); sImageBridgeChildSingleton->ConnectAsync(sImageBridgeParentSingleton); sImageBridgeChildSingleton->GetMessageLoop()->PostTask( - FROM_HERE, NewRunnableFunction(CallSendImageBridgeThreadId, sImageBridgeChildSingleton.get())); return true; @@ -876,8 +866,8 @@ MessageLoop * ImageBridgeChild::GetMessageLoop() const void ImageBridgeChild::ConnectAsync(ImageBridgeParent* aParent) { - GetMessageLoop()->PostTask(FROM_HERE, NewRunnableFunction(&ConnectImageBridge, - this, aParent)); + GetMessageLoop()->PostTask(NewRunnableFunction(&ConnectImageBridge, + this, aParent)); } void @@ -900,7 +890,7 @@ ImageBridgeChild::CreateImageClient(CompositableType aType, bool done = false; RefPtr result = nullptr; - GetMessageLoop()->PostTask(FROM_HERE, + GetMessageLoop()->PostTask( NewRunnableFunction(&CreateImageClientSync, &result, &barrier, aType, aImageContainer, &done)); // should stop the thread until the ImageClient has been created on @@ -940,8 +930,7 @@ ImageBridgeChild::CreateCanvasClient(CanvasClient::CanvasClientType aType, bool done = false; RefPtr result = nullptr; - GetMessageLoop()->PostTask(FROM_HERE, - NewRunnableFunction(&CreateCanvasClientSync, + GetMessageLoop()->PostTask(NewRunnableFunction(&CreateCanvasClientSync, &barrier, aType, aFlag, &result, &done)); // should stop the thread until the CanvasClient has been created on the // other thread @@ -1040,8 +1029,7 @@ ImageBridgeChild::DispatchAllocShmemInternal(size_t aSize, }; bool done = false; - GetMessageLoop()->PostTask(FROM_HERE, - NewRunnableFunction(&ProxyAllocShmemNow, + GetMessageLoop()->PostTask(NewRunnableFunction(&ProxyAllocShmemNow, ¶ms, &barrier, &done)); @@ -1077,8 +1065,7 @@ ImageBridgeChild::DeallocShmem(ipc::Shmem& aShmem) ReentrantMonitorAutoEnter autoMon(barrier); bool done = false; - GetMessageLoop()->PostTask(FROM_HERE, - NewRunnableFunction(&ProxyDeallocShmemNow, + GetMessageLoop()->PostTask(NewRunnableFunction(&ProxyDeallocShmemNow, this, &aShmem, &barrier, diff --git a/gfx/layers/ipc/ImageBridgeParent.cpp b/gfx/layers/ipc/ImageBridgeParent.cpp index 4aade51385..a066389fb1 100644 --- a/gfx/layers/ipc/ImageBridgeParent.cpp +++ b/gfx/layers/ipc/ImageBridgeParent.cpp @@ -10,7 +10,6 @@ #include "base/message_loop.h" // for MessageLoop #include "base/process.h" // for ProcessId #include "base/task.h" // for CancelableTask, DeleteTask, etc -#include "base/tracked.h" // for FROM_HERE #include "mozilla/gfx/Point.h" // for IntSize #include "mozilla/Hal.h" // for hal::SetCurrentThreadPriority() #include "mozilla/HalTypes.h" // for hal::THREAD_PRIORITY_COMPOSITOR @@ -83,8 +82,8 @@ ImageBridgeParent::~ImageBridgeParent() if (mTransport) { MOZ_ASSERT(XRE_GetIOMessageLoop()); - XRE_GetIOMessageLoop()->PostTask(FROM_HERE, - new DeleteTask(mTransport)); + RefPtr> task(new DeleteTask(mTransport)); + XRE_GetIOMessageLoop()->PostTask(task.forget()); } nsTArray parents; @@ -108,7 +107,6 @@ ImageBridgeParent::ActorDestroy(ActorDestroyReason aWhy) } MessageLoop::current()->PostTask( - FROM_HERE, NewRunnableMethod(this, &ImageBridgeParent::DeferredDestroy)); // It is very important that this method gets called at shutdown (be it a clean @@ -211,8 +209,7 @@ ImageBridgeParent::Create(Transport* aTransport, ProcessId aChildProcessId, Geck aProcessHost->AssociateActor(); } - loop->PostTask(FROM_HERE, - NewRunnableFunction(ConnectImageBridgeInParentProcess, + loop->PostTask(NewRunnableFunction(ConnectImageBridgeInParentProcess, bridge.get(), aTransport, aChildProcessId)); return bridge.get(); } diff --git a/gfx/layers/ipc/PAPZ.ipdl b/gfx/layers/ipc/PAPZ.ipdl index 5c555e86ee..5f0bc62c67 100644 --- a/gfx/layers/ipc/PAPZ.ipdl +++ b/gfx/layers/ipc/PAPZ.ipdl @@ -91,7 +91,6 @@ child: // The following methods correspond to functions on the GeckoContentController // interface in gfx/layers/apz/public/GeckoContentController.h. Refer to documentation // in that file for these functions. - async AcknowledgeScrollUpdate(ViewID aScrollId, uint32_t aScrollGeneration); async HandleDoubleTap(CSSPoint aPoint, Modifiers aModifiers, ScrollableLayerGuid aGuid); async HandleSingleTap(CSSPoint aPoint, Modifiers aModifiers, ScrollableLayerGuid aGuid, bool aCallTakeFocusForClickFromTap); async HandleLongTap(CSSPoint point, Modifiers aModifiers, ScrollableLayerGuid aGuid, uint64_t aInputBlockId); diff --git a/gfx/layers/ipc/RemoteContentController.cpp b/gfx/layers/ipc/RemoteContentController.cpp index edbbeb8acd..180ca065e3 100644 --- a/gfx/layers/ipc/RemoteContentController.cpp +++ b/gfx/layers/ipc/RemoteContentController.cpp @@ -50,24 +50,6 @@ RemoteContentController::RequestContentRepaint(const FrameMetrics& aFrameMetrics } } -void -RemoteContentController::AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId, - const uint32_t& aScrollGeneration) -{ - if (MessageLoop::current() != mUILoop) { - // We have to send this message from the "UI thread" (main - // thread). - mUILoop->PostTask( - FROM_HERE, - NewRunnableMethod(this, &RemoteContentController::AcknowledgeScrollUpdate, - aScrollId, aScrollGeneration)); - return; - } - if (CanSend()) { - Unused << SendAcknowledgeScrollUpdate(aScrollId, aScrollGeneration); - } -} - void RemoteContentController::HandleDoubleTap(const CSSPoint& aPoint, Modifiers aModifiers, @@ -77,7 +59,6 @@ RemoteContentController::HandleDoubleTap(const CSSPoint& aPoint, // We have to send this message from the "UI thread" (main // thread). mUILoop->PostTask( - FROM_HERE, NewRunnableMethod(this, &RemoteContentController::HandleDoubleTap, aPoint, aModifiers, aGuid)); return; @@ -97,7 +78,6 @@ RemoteContentController::HandleSingleTap(const CSSPoint& aPoint, // We have to send this message from the "UI thread" (main // thread). mUILoop->PostTask( - FROM_HERE, NewRunnableMethod(this, &RemoteContentController::HandleSingleTap, aPoint, aModifiers, aGuid)); return; @@ -131,7 +111,6 @@ RemoteContentController::HandleLongTap(const CSSPoint& aPoint, // We have to send this message from the "UI thread" (main // thread). mUILoop->PostTask( - FROM_HERE, NewRunnableMethod(this, &RemoteContentController::HandleLongTap, aPoint, aModifiers, aGuid, aInputBlockId)); return; @@ -143,13 +122,13 @@ RemoteContentController::HandleLongTap(const CSSPoint& aPoint, } void -RemoteContentController::PostDelayedTask(Task* aTask, int aDelayMs) +RemoteContentController::PostDelayedTask(already_AddRefed aTask, int aDelayMs) { #ifdef MOZ_ANDROID_APZ - AndroidBridge::Bridge()->PostTaskToUiThread(aTask, aDelayMs); + AndroidBridge::Bridge()->PostTaskToUiThread(Move(aTask), aDelayMs); #else (MessageLoop::current() ? MessageLoop::current() : mUILoop)-> - PostDelayedTask(FROM_HERE, aTask, aDelayMs); + PostDelayedTask(Move(aTask), aDelayMs); #endif } @@ -172,7 +151,6 @@ RemoteContentController::NotifyAPZStateChange(const ScrollableLayerGuid& aGuid, { if (MessageLoop::current() != mUILoop) { mUILoop->PostTask( - FROM_HERE, NewRunnableMethod(this, &RemoteContentController::NotifyAPZStateChange, aGuid, aChange, aArg)); return; @@ -188,7 +166,6 @@ RemoteContentController::NotifyMozMouseScrollEvent(const FrameMetrics::ViewID& a { if (MessageLoop::current() != mUILoop) { mUILoop->PostTask( - FROM_HERE, NewRunnableMethod(this, &RemoteContentController::NotifyMozMouseScrollEvent, aScrollId, aEvent)); return; diff --git a/gfx/layers/ipc/RemoteContentController.h b/gfx/layers/ipc/RemoteContentController.h index 56000da0eb..5ae595a7cb 100644 --- a/gfx/layers/ipc/RemoteContentController.h +++ b/gfx/layers/ipc/RemoteContentController.h @@ -42,9 +42,6 @@ public: // Needs to be called on the main thread. virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) override; - virtual void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId, - const uint32_t& aScrollGeneration) override; - virtual void HandleDoubleTap(const CSSPoint& aPoint, Modifiers aModifiers, const ScrollableLayerGuid& aGuid) override; @@ -58,7 +55,7 @@ public: const ScrollableLayerGuid& aGuid, uint64_t aInputBlockId) override; - virtual void PostDelayedTask(Task* aTask, int aDelayMs) override; + virtual void PostDelayedTask(already_AddRefed aTask, int aDelayMs) override; virtual bool GetTouchSensitiveRegion(CSSRect* aOutRegion) override; diff --git a/gfx/layers/ipc/SharedBufferManagerChild.cpp b/gfx/layers/ipc/SharedBufferManagerChild.cpp index ed65e5e238..84333507f6 100644 --- a/gfx/layers/ipc/SharedBufferManagerChild.cpp +++ b/gfx/layers/ipc/SharedBufferManagerChild.cpp @@ -7,7 +7,6 @@ #include "base/task.h" // for NewRunnableFunction, etc #include "base/thread.h" // for Thread -#include "base/tracked.h" // for FROM_HERE #include "mozilla/gfx/Logging.h" // for gfxDebug #include "mozilla/layers/SharedBufferManagerChild.h" #include "mozilla/layers/SharedBufferManagerParent.h" @@ -107,8 +106,7 @@ ConnectSharedBufferManagerInChildProcess(mozilla::ipc::Transport* aTransport, #ifdef MOZ_NUWA_PROCESS if (IsNuwaProcess()) { SharedBufferManagerChild::sSharedBufferManagerChildThread - ->message_loop()->PostTask(FROM_HERE, - NewRunnableFunction(NuwaMarkCurrentThread, + ->message_loop()->PostTask(NewRunnableFunction(NuwaMarkCurrentThread, (void (*)(void *))nullptr, (void *)nullptr)); } @@ -128,7 +126,6 @@ SharedBufferManagerChild::StartUpInChildProcess(Transport* aTransport, sSharedBufferManagerChildSingleton = new SharedBufferManagerChild(); sSharedBufferManagerChildSingleton->GetMessageLoop()->PostTask( - FROM_HERE, NewRunnableFunction(ConnectSharedBufferManagerInChildProcess, aTransport, aOtherPid)); @@ -183,7 +180,7 @@ SharedBufferManagerChild::DestroyManager() ReentrantMonitorAutoEnter autoMon(barrier); bool done = false; - sSharedBufferManagerChildSingleton->GetMessageLoop()->PostTask(FROM_HERE, + sSharedBufferManagerChildSingleton->GetMessageLoop()->PostTask( NewRunnableFunction(&DeleteSharedBufferManagerSync, &barrier, &done)); while (!done) { barrier.Wait(); @@ -202,8 +199,8 @@ SharedBufferManagerChild::GetMessageLoop() const void SharedBufferManagerChild::ConnectAsync(SharedBufferManagerParent* aParent) { - GetMessageLoop()->PostTask(FROM_HERE, NewRunnableFunction(&ConnectSharedBufferManager, - this, aParent)); + GetMessageLoop()->PostTask(NewRunnableFunction(&ConnectSharedBufferManager, + this, aParent)); } // dispatched function @@ -250,7 +247,6 @@ SharedBufferManagerChild::AllocGrallocBuffer(const gfx::IntSize& aSize, bool done = false; GetMessageLoop()->PostTask( - FROM_HERE, NewRunnableFunction(&AllocGrallocBufferSync, GrallocParam(aSize, aFormat, aUsage, aBuffer), &barrier, &done)); @@ -305,8 +301,7 @@ SharedBufferManagerChild::DeallocGrallocBuffer(const mozilla::layers::MaybeMagic return SharedBufferManagerChild::DeallocGrallocBufferNow(aBuffer); } - GetMessageLoop()->PostTask(FROM_HERE, NewRunnableFunction(&DeallocGrallocBufferSync, - aBuffer)); + GetMessageLoop()->PostTask(NewRunnableFunction(&DeallocGrallocBufferSync, aBuffer)); } void diff --git a/gfx/layers/ipc/SharedBufferManagerParent.cpp b/gfx/layers/ipc/SharedBufferManagerParent.cpp index 88f873973d..be8c1a3125 100644 --- a/gfx/layers/ipc/SharedBufferManagerParent.cpp +++ b/gfx/layers/ipc/SharedBufferManagerParent.cpp @@ -8,7 +8,6 @@ #include "base/message_loop.h" // for MessageLoop #include "base/process.h" // for ProcessId #include "base/task.h" // for CancelableTask, DeleteTask, etc -#include "base/tracked.h" // for FROM_HERE #include "base/thread.h" #include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc #include "mozilla/ipc/ProtocolUtils.h" @@ -115,13 +114,13 @@ void InitGralloc() { /** * Task that deletes SharedBufferManagerParent on a specified thread. */ -class DeleteSharedBufferManagerParentTask : public Task +class DeleteSharedBufferManagerParentTask : public Runnable { public: explicit DeleteSharedBufferManagerParentTask(UniquePtr aSharedBufferManager) : mSharedBufferManager(Move(aSharedBufferManager)) { } - virtual void Run() override {} + NS_IMETHOD Run() override { return NS_OK; } private: UniquePtr mSharedBufferManager; }; @@ -155,8 +154,8 @@ SharedBufferManagerParent::~SharedBufferManagerParent() { MonitorAutoLock lock(*sManagerMonitor.get()); if (mTransport) { - XRE_GetIOMessageLoop()->PostTask(FROM_HERE, - new DeleteTask(mTransport)); + RefPtr> task = new DeleteTask(mTransport); + XRE_GetIOMessageLoop()->PostTask(task.forget()); } sManagers.erase(mOwner); delete mThread; @@ -170,9 +169,9 @@ SharedBufferManagerParent::ActorDestroy(ActorDestroyReason aWhy) #ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC mBuffers.clear(); #endif - DeleteSharedBufferManagerParentTask* task = + RefPtr task = new DeleteSharedBufferManagerParentTask(UniquePtr(this)); - mMainMessageLoop->PostTask(FROM_HERE, task); + mMainMessageLoop->PostTask(task.forget()); } static void @@ -195,8 +194,7 @@ PSharedBufferManagerParent* SharedBufferManagerParent::Create(Transport* aTransp if (!thread->IsRunning()) { thread->Start(); } - thread->message_loop()->PostTask(FROM_HERE, - NewRunnableFunction(ConnectSharedBufferManagerInParentProcess, + thread->message_loop()->PostTask(NewRunnableFunction(ConnectSharedBufferManagerInParentProcess, manager, aTransport, aOtherPid)); return manager; } @@ -297,7 +295,7 @@ void SharedBufferManagerParent::DropGrallocBuffer(ProcessId id, mozilla::layers: if (PlatformThread::CurrentId() == mgr->mThread->thread_id()) { MOZ_CRASH("GFX: SharedBufferManagerParent::DropGrallocBuffer should not be called on SharedBufferManagerParent thread"); } else { - mgr->mThread->message_loop()->PostTask(FROM_HERE, + mgr->mThread->message_loop()->PostTask( NewRunnableFunction(&DropGrallocBufferSync, mgr, aDesc)); } return; diff --git a/gfx/thebes/SoftwareVsyncSource.cpp b/gfx/thebes/SoftwareVsyncSource.cpp index 4a02f3f8e7..ccc6b59a14 100644 --- a/gfx/thebes/SoftwareVsyncSource.cpp +++ b/gfx/thebes/SoftwareVsyncSource.cpp @@ -23,8 +23,7 @@ SoftwareVsyncSource::~SoftwareVsyncSource() } SoftwareDisplay::SoftwareDisplay() - : mCurrentVsyncTask(nullptr) - , mVsyncEnabled(false) + : mVsyncEnabled(false) { // Mimic 60 fps MOZ_ASSERT(NS_IsMainThread()); @@ -46,7 +45,7 @@ SoftwareDisplay::EnableVsync() } mVsyncEnabled = true; - mVsyncThread->message_loop()->PostTask(FROM_HERE, + mVsyncThread->message_loop()->PostTask( NewRunnableMethod(this, &SoftwareDisplay::EnableVsync)); return; } @@ -65,7 +64,7 @@ SoftwareDisplay::DisableVsync() } mVsyncEnabled = false; - mVsyncThread->message_loop()->PostTask(FROM_HERE, + mVsyncThread->message_loop()->PostTask( NewRunnableMethod(this, &SoftwareDisplay::DisableVsync)); return; } @@ -133,8 +132,9 @@ SoftwareDisplay::ScheduleNextVsync(mozilla::TimeStamp aVsyncTimestamp) &SoftwareDisplay::NotifyVsync, nextVsync); - mVsyncThread->message_loop()->PostDelayedTask(FROM_HERE, - mCurrentVsyncTask, + RefPtr addrefedTask = mCurrentVsyncTask; + mVsyncThread->message_loop()->PostDelayedTask( + addrefedTask.forget(), delay.ToMilliseconds()); } diff --git a/gfx/thebes/SoftwareVsyncSource.h b/gfx/thebes/SoftwareVsyncSource.h index 5aaa53dd09..74e524abe4 100644 --- a/gfx/thebes/SoftwareVsyncSource.h +++ b/gfx/thebes/SoftwareVsyncSource.h @@ -14,8 +14,6 @@ #include "nsISupportsImpl.h" #include "VsyncSource.h" -class CancelableTask; - class SoftwareDisplay final : public mozilla::gfx::VsyncSource::Display { NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SoftwareDisplay) @@ -38,7 +36,7 @@ private: mozilla::TimeDuration mVsyncRate; // Use a chromium thread because nsITimers* fire on the main thread base::Thread* mVsyncThread; - CancelableTask* mCurrentVsyncTask; // only access on vsync thread + RefPtr mCurrentVsyncTask; // only access on vsync thread bool mVsyncEnabled; // Only access on main thread }; // SoftwareDisplay diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 826cb84488..a59480f485 100644 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -2669,9 +2669,8 @@ public: mVsyncEnabled = true; } - CancelableTask* vsyncStart = NewRunnableMethod(this, - &D3DVsyncDisplay::VBlankLoop); - mVsyncThread->message_loop()->PostTask(FROM_HERE, vsyncStart); + mVsyncThread->message_loop()->PostTask( + NewRunnableMethod(this, &D3DVsyncDisplay::VBlankLoop)); } virtual void DisableVsync() override @@ -2708,7 +2707,7 @@ public: delay = mozilla::TimeDuration::FromMilliseconds(0); } - mVsyncThread->message_loop()->PostDelayedTask(FROM_HERE, + mVsyncThread->message_loop()->PostDelayedTask( NewRunnableMethod(this, &D3DVsyncDisplay::VBlankLoop), delay.ToMilliseconds()); } diff --git a/gfx/vr/ipc/VRManagerChild.cpp b/gfx/vr/ipc/VRManagerChild.cpp index b229ef3ee6..c8476969de 100644 --- a/gfx/vr/ipc/VRManagerChild.cpp +++ b/gfx/vr/ipc/VRManagerChild.cpp @@ -38,8 +38,8 @@ VRManagerChild::~VRManagerChild() Transport* trans = GetTransport(); if (trans) { MOZ_ASSERT(XRE_GetIOMessageLoop()); - XRE_GetIOMessageLoop()->PostTask(FROM_HERE, - new DeleteTask(trans)); + RefPtr> task = new DeleteTask(trans); + XRE_GetIOMessageLoop()->PostTask(task.forget()); } } @@ -109,7 +109,7 @@ VRManagerChild::Destroy() // The DeferredDestroyVRManager task takes ownership of // the VRManagerChild and will release it when it runs. - MessageLoop::current()->PostTask(FROM_HERE, + MessageLoop::current()->PostTask( NewRunnableFunction(DeferredDestroy, selfRef)); } diff --git a/gfx/vr/ipc/VRManagerParent.cpp b/gfx/vr/ipc/VRManagerParent.cpp index 49143dbcee..b68baa817d 100644 --- a/gfx/vr/ipc/VRManagerParent.cpp +++ b/gfx/vr/ipc/VRManagerParent.cpp @@ -44,8 +44,8 @@ VRManagerParent::~VRManagerParent() Transport* trans = GetTransport(); if (trans) { MOZ_ASSERT(XRE_GetIOMessageLoop()); - XRE_GetIOMessageLoop()->PostTask(FROM_HERE, - new DeleteTask(trans)); + RefPtr> task = new DeleteTask(trans); + XRE_GetIOMessageLoop()->PostTask(task.forget()); } MOZ_COUNT_DTOR(VRManagerParent); } @@ -79,8 +79,7 @@ VRManagerParent::CreateCrossProcess(Transport* aTransport, ProcessId aChildProce MessageLoop* loop = mozilla::layers::CompositorBridgeParent::CompositorLoop(); RefPtr vmp = new VRManagerParent(loop, aTransport, aChildProcessId); vmp->mSelfRef = vmp; - loop->PostTask(FROM_HERE, - NewRunnableFunction(ConnectVRManagerInParentProcess, + loop->PostTask(NewRunnableFunction(ConnectVRManagerInParentProcess, vmp.get(), aTransport, aChildProcessId)); return vmp.get(); } @@ -98,8 +97,7 @@ VRManagerParent::CreateSameProcess() RefPtr vmp = new VRManagerParent(loop, nullptr, base::GetCurrentProcId()); vmp->mCompositorThreadHolder = layers::GetCompositorThreadHolder(); vmp->mSelfRef = vmp; - loop->PostTask(FROM_HERE, - NewRunnableFunction(RegisterVRManagerInCompositorThread, vmp.get())); + loop->PostTask(NewRunnableFunction(RegisterVRManagerInCompositorThread, vmp.get())); return vmp.get(); } @@ -115,7 +113,6 @@ VRManagerParent::ActorDestroy(ActorDestroyReason why) { UnregisterFromManager(); MessageLoop::current()->PostTask( - FROM_HERE, NewRunnableMethod(this, &VRManagerParent::DeferredDestroy)); } diff --git a/image/DecodePool.cpp b/image/DecodePool.cpp index 259ad06642..7aebb0d453 100644 --- a/image/DecodePool.cpp +++ b/image/DecodePool.cpp @@ -388,19 +388,18 @@ DecodePool::Observe(nsISupports*, const char* aTopic, const char16_t*) { MOZ_ASSERT(strcmp(aTopic, "xpcom-shutdown-threads") == 0, "Unexpected topic"); - nsCOMArray threads; + nsTArray> threads; nsCOMPtr ioThread; { MutexAutoLock lock(mMutex); - threads.AppendElements(mThreads); - mThreads.Clear(); + threads.SwapElements(mThreads); ioThread.swap(mIOThread); } mImpl->RequestShutdown(); - for (int32_t i = 0 ; i < threads.Count() ; ++i) { + for (uint32_t i = 0 ; i < threads.Length() ; ++i) { threads[i]->Shutdown(); } diff --git a/image/DecodePool.h b/image/DecodePool.h index cf04d3f8c4..2bd0c0d77c 100644 --- a/image/DecodePool.h +++ b/image/DecodePool.h @@ -95,9 +95,9 @@ private: RefPtr mImpl; // mMutex protects mThreads and mIOThread. - Mutex mMutex; - nsCOMArray mThreads; - nsCOMPtr mIOThread; + Mutex mMutex; + nsTArray> mThreads; + nsCOMPtr mIOThread; }; } // namespace image diff --git a/ipc/chromium/moz.build b/ipc/chromium/moz.build index 5c99785a14..7c90cb6ad8 100644 --- a/ipc/chromium/moz.build +++ b/ipc/chromium/moz.build @@ -26,8 +26,6 @@ UNIFIED_SOURCES += [ 'src/base/thread.cc', 'src/base/time.cc', 'src/base/timer.cc', - 'src/base/tracked.cc', - 'src/base/tracked_objects.cc', 'src/chrome/common/child_process.cc', 'src/chrome/common/child_process_host.cc', 'src/chrome/common/child_process_info.cc', diff --git a/ipc/chromium/src/base/message_loop.cc b/ipc/chromium/src/base/message_loop.cc index fab5a5a6d0..02ca8e79d0 100644 --- a/ipc/chromium/src/base/message_loop.cc +++ b/ipc/chromium/src/base/message_loop.cc @@ -41,6 +41,9 @@ using base::Time; using base::TimeDelta; using base::TimeTicks; +using mozilla::Move; +using mozilla::Runnable; + static base::ThreadLocalPointer& get_tls_ptr() { static base::ThreadLocalPointer tls_ptr; return tls_ptr; @@ -203,12 +206,6 @@ void MessageLoop::Run() { RunHandler(); } -void MessageLoop::RunAllPending() { - AutoRunState save_state(this); - state_->quit_received = true; // Means run until we would otherwise block. - RunHandler(); -} - // Runs the loop in two different SEH modes: // enable_SEH_restoration_ = false : any unhandled exception goes to the last // one that calls SetUnhandledExceptionFilter(). @@ -246,10 +243,10 @@ bool MessageLoop::ProcessNextDelayedNonNestableTask() { if (deferred_non_nestable_work_queue_.empty()) return false; - Task* task = deferred_non_nestable_work_queue_.front().task; + RefPtr task = deferred_non_nestable_work_queue_.front().task.forget(); deferred_non_nestable_work_queue_.pop(); - RunTask(task); + RunTask(task.forget()); return true; } @@ -264,53 +261,24 @@ void MessageLoop::Quit() { } } -void MessageLoop::PostTask( - const tracked_objects::Location& from_here, Task* task) { - PostTask_Helper(from_here, task, 0, true); +void MessageLoop::PostTask(already_AddRefed task) { + PostTask_Helper(Move(task), 0); } -void MessageLoop::PostDelayedTask( - const tracked_objects::Location& from_here, Task* task, int delay_ms) { - PostTask_Helper(from_here, task, delay_ms, true); +void MessageLoop::PostDelayedTask(already_AddRefed task, int delay_ms) { + PostTask_Helper(Move(task), delay_ms); } -void MessageLoop::PostNonNestableTask( - const tracked_objects::Location& from_here, Task* task) { - PostTask_Helper(from_here, task, 0, false); -} - -void MessageLoop::PostNonNestableDelayedTask( - const tracked_objects::Location& from_here, Task* task, int delay_ms) { - PostTask_Helper(from_here, task, delay_ms, false); -} - -void MessageLoop::PostIdleTask( - const tracked_objects::Location& from_here, Task* task) { +void MessageLoop::PostIdleTask(already_AddRefed task) { DCHECK(current() == this); -#ifdef MOZ_TASK_TRACER - task = mozilla::tasktracer::CreateTracedTask(task); - (static_cast(task))->DispatchTask(); -#endif - - task->SetBirthPlace(from_here); - PendingTask pending_task(task, false); - deferred_non_nestable_work_queue_.push(pending_task); + PendingTask pending_task(Move(task), false); + deferred_non_nestable_work_queue_.push(Move(pending_task)); } // Possibly called on a background thread! -void MessageLoop::PostTask_Helper( - const tracked_objects::Location& from_here, Task* task, int delay_ms, - bool nestable) { - -#ifdef MOZ_TASK_TRACER - task = mozilla::tasktracer::CreateTracedTask(task); - (static_cast(task))->DispatchTask(delay_ms); -#endif - - task->SetBirthPlace(from_here); - - PendingTask pending_task(task, nestable); +void MessageLoop::PostTask_Helper(already_AddRefed task, int delay_ms) { + PendingTask pending_task(Move(task), true); if (delay_ms > 0) { pending_task.delayed_run_time = @@ -326,7 +294,7 @@ void MessageLoop::PostTask_Helper( RefPtr pump; { AutoLock locked(incoming_queue_lock_); - incoming_queue_.push(pending_task); + incoming_queue_.push(Move(pending_task)); pump = pump_; } // Since the incoming_queue_ may contain a task that destroys this message @@ -358,20 +326,21 @@ bool MessageLoop::NestableTasksAllowed() const { //------------------------------------------------------------------------------ -void MessageLoop::RunTask(Task* task) { +void MessageLoop::RunTask(already_AddRefed aTask) { DCHECK(nestable_tasks_allowed_); // Execute the task and assume the worst: It is probably not reentrant. nestable_tasks_allowed_ = false; + RefPtr task = aTask; task->Run(); - delete task; + task = nullptr; nestable_tasks_allowed_ = true; } -bool MessageLoop::DeferOrRunPendingTask(const PendingTask& pending_task) { +bool MessageLoop::DeferOrRunPendingTask(PendingTask&& pending_task) { if (pending_task.nestable || state_->run_depth <= run_depth_base_) { - RunTask(pending_task.task); + RunTask(pending_task.task.forget()); // Show that we ran a task (Note: a new one might arrive as a // consequence!). return true; @@ -379,7 +348,7 @@ bool MessageLoop::DeferOrRunPendingTask(const PendingTask& pending_task) { // We couldn't run the task now because we're in a nested message loop // and the task isn't nestable. - deferred_non_nestable_work_queue_.push(pending_task); + deferred_non_nestable_work_queue_.push(Move(pending_task)); return false; } @@ -390,7 +359,7 @@ void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) { // delayed_run_time value. PendingTask new_pending_task(pending_task); new_pending_task.sequence_num = next_sequence_num_++; - delayed_work_queue_.push(new_pending_task); + delayed_work_queue_.push(Move(new_pending_task)); } void MessageLoop::ReloadWorkQueue() { @@ -412,27 +381,14 @@ void MessageLoop::ReloadWorkQueue() { } bool MessageLoop::DeletePendingTasks() { -#ifdef DEBUG - if (!work_queue_.empty()) { - Task* task = work_queue_.front().task; - tracked_objects::Location loc = task->GetBirthPlace(); - printf("Unexpected task! %s:%s:%d\n", - loc.function_name(), loc.file_name(), loc.line_number()); - } -#endif - MOZ_ASSERT(work_queue_.empty()); bool did_work = !deferred_non_nestable_work_queue_.empty(); while (!deferred_non_nestable_work_queue_.empty()) { - Task* task = deferred_non_nestable_work_queue_.front().task; deferred_non_nestable_work_queue_.pop(); - delete task; } did_work |= !delayed_work_queue_.empty(); while (!delayed_work_queue_.empty()) { - Task* task = delayed_work_queue_.top().task; delayed_work_queue_.pop(); - delete task; } return did_work; } @@ -450,15 +406,16 @@ bool MessageLoop::DoWork() { // Execute oldest task. do { - PendingTask pending_task = work_queue_.front(); + PendingTask pending_task = Move(work_queue_.front()); work_queue_.pop(); if (!pending_task.delayed_run_time.is_null()) { + // NB: Don't move, because we use this later! AddToDelayedWorkQueue(pending_task); // If we changed the topmost task, then it is time to re-schedule. if (delayed_work_queue_.top().task == pending_task.task) pump_->ScheduleDelayedWork(pending_task.delayed_run_time); } else { - if (DeferOrRunPendingTask(pending_task)) + if (DeferOrRunPendingTask(Move(pending_task))) return true; } } while (!work_queue_.empty()); @@ -485,7 +442,7 @@ bool MessageLoop::DoDelayedWork(TimeTicks* next_delayed_work_time) { if (!delayed_work_queue_.empty()) *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time; - return DeferOrRunPendingTask(pending_task); + return DeferOrRunPendingTask(Move(pending_task)); } bool MessageLoop::DoIdleWork() { diff --git a/ipc/chromium/src/base/message_loop.h b/ipc/chromium/src/base/message_loop.h index 775771e343..37dcfcb0de 100644 --- a/ipc/chromium/src/base/message_loop.h +++ b/ipc/chromium/src/base/message_loop.h @@ -111,58 +111,16 @@ public: // NOTE: These methods may be called on any thread. The Task will be invoked // on the thread that executes MessageLoop::Run(). - void PostTask( - const tracked_objects::Location& from_here, Task* task); + void PostTask(already_AddRefed task); - void PostDelayedTask( - const tracked_objects::Location& from_here, Task* task, int delay_ms); - - void PostNonNestableTask( - const tracked_objects::Location& from_here, Task* task); - - void PostNonNestableDelayedTask( - const tracked_objects::Location& from_here, Task* task, int delay_ms); + void PostDelayedTask(already_AddRefed task, int delay_ms); // PostIdleTask is not thread safe and should be called on this thread - void PostIdleTask( - const tracked_objects::Location& from_here, Task* task); - - // A variant on PostTask that deletes the given object. This is useful - // if the object needs to live until the next run of the MessageLoop (for - // example, deleting a RenderProcessHost from within an IPC callback is not - // good). - // - // NOTE: This method may be called on any thread. The object will be deleted - // on the thread that executes MessageLoop::Run(). If this is not the same - // as the thread that calls PostDelayedTask(FROM_HERE, ), then T MUST inherit - // from RefCountedThreadSafe! - template - void DeleteSoon(const tracked_objects::Location& from_here, T* object) { - PostNonNestableTask(from_here, new DeleteTask(object)); - } - - // A variant on PostTask that releases the given reference counted object - // (by calling its Release method). This is useful if the object needs to - // live until the next run of the MessageLoop, or if the object needs to be - // released on a particular thread. - // - // NOTE: This method may be called on any thread. The object will be - // released (and thus possibly deleted) on the thread that executes - // MessageLoop::Run(). If this is not the same as the thread that calls - // PostDelayedTask(FROM_HERE, ), then T MUST inherit from - // RefCountedThreadSafe! - template - void ReleaseSoon(const tracked_objects::Location& from_here, T* object) { - PostNonNestableTask(from_here, new ReleaseTask(object)); - } + void PostIdleTask(already_AddRefed task); // Run the message loop. void Run(); - // Process all pending tasks, windows messages, etc., but don't wait/sleep. - // Return as soon as all items that can be run are taken care of. - void RunAllPending(); - // Signals the Run method to return after it is done processing all pending // messages. This method may only be called on the same thread that called // Run, and Run must still be on the call stack. @@ -176,10 +134,11 @@ public: // Invokes Quit on the current MessageLoop when run. Useful to schedule an // arbitrary MessageLoop to Quit. - class QuitTask : public Task { + class QuitTask : public mozilla::Runnable { public: - virtual void Run() override { + NS_IMETHOD Run() override { MessageLoop::current()->Quit(); + return NS_OK; } }; @@ -321,15 +280,38 @@ public: // This structure is copied around by value. struct PendingTask { - Task* task; // The task to run. + RefPtr task; // The task to run. base::TimeTicks delayed_run_time; // The time when the task should be run. int sequence_num; // Secondary sort key for run time. bool nestable; // OK to dispatch from a nested loop. - PendingTask(Task* aTask, bool aNestable) + PendingTask(already_AddRefed aTask, bool aNestable) : task(aTask), sequence_num(0), nestable(aNestable) { } + PendingTask(PendingTask&& aOther) + : task(aOther.task.forget()), + delayed_run_time(aOther.delayed_run_time), + sequence_num(aOther.sequence_num), + nestable(aOther.nestable) { + } + + // std::priority_queue::top is dumb, so we have to have this. + PendingTask(const PendingTask& aOther) + : task(aOther.task), + delayed_run_time(aOther.delayed_run_time), + sequence_num(aOther.sequence_num), + nestable(aOther.nestable) { + } + PendingTask& operator=(const PendingTask& aOther) + { + task = aOther.task; + delayed_run_time = aOther.delayed_run_time; + sequence_num = aOther.sequence_num; + nestable = aOther.nestable; + return *this; + } + // Used to support sorting. bool operator<(const PendingTask& other) const; }; @@ -371,14 +353,14 @@ public: // appended to the list work_queue_. Such re-entrancy generally happens when // an unrequested message pump (typical of a native dialog) is executing in // the context of a task. - bool QueueOrRunTask(Task* new_task); + bool QueueOrRunTask(already_AddRefed new_task); // Runs the specified task and deletes it. - void RunTask(Task* task); + void RunTask(already_AddRefed task); // Calls RunTask or queues the pending_task on the deferred task list if it // cannot be run right now. Returns true if the task was run. - bool DeferOrRunPendingTask(const PendingTask& pending_task); + bool DeferOrRunPendingTask(PendingTask&& pending_task); // Adds the pending task to delayed_work_queue_. void AddToDelayedWorkQueue(const PendingTask& pending_task); @@ -394,8 +376,7 @@ public: bool DeletePendingTasks(); // Post a task to our incomming queue. - void PostTask_Helper(const tracked_objects::Location& from_here, Task* task, - int delay_ms, bool nestable); + void PostTask_Helper(already_AddRefed task, int delay_ms); // base::MessagePump::Delegate methods: virtual bool DoWork() override; diff --git a/ipc/chromium/src/base/object_watcher.cc b/ipc/chromium/src/base/object_watcher.cc index 1fd29139d7..4768cb41a9 100644 --- a/ipc/chromium/src/base/object_watcher.cc +++ b/ipc/chromium/src/base/object_watcher.cc @@ -10,7 +10,8 @@ namespace base { //----------------------------------------------------------------------------- -struct ObjectWatcher::Watch : public Task { +class ObjectWatcher::Watch : public mozilla::Runnable { +public: ObjectWatcher* watcher; // The associated ObjectWatcher instance HANDLE object; // The object being watched HANDLE wait_object; // Returned by RegisterWaitForSingleObject @@ -18,16 +19,18 @@ struct ObjectWatcher::Watch : public Task { Delegate* delegate; // Delegate to notify when signaled bool did_signal; // DoneWaiting was called - virtual void Run() { + NS_IMETHOD Run() override { // The watcher may have already been torn down, in which case we need to // just get out of dodge. if (!watcher) - return; + return NS_OK; DCHECK(did_signal); watcher->StopWatching(); delegate->OnObjectSignaled(object); + + return NS_OK; } }; @@ -46,7 +49,7 @@ bool ObjectWatcher::StartWatching(HANDLE object, Delegate* delegate) { return false; } - Watch* watch = new Watch; + RefPtr watch = new Watch; watch->watcher = this; watch->object = object; watch->origin_loop = MessageLoop::current(); @@ -58,13 +61,12 @@ bool ObjectWatcher::StartWatching(HANDLE object, Delegate* delegate) { DWORD wait_flags = WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE; if (!RegisterWaitForSingleObject(&watch->wait_object, object, DoneWaiting, - watch, INFINITE, wait_flags)) { + watch.get(), INFINITE, wait_flags)) { NOTREACHED() << "RegisterWaitForSingleObject failed: " << GetLastError(); - delete watch; return false; } - watch_ = watch; + watch_ = watch.forget(); // We need to know if the current message loop is going away so we can // prevent the wait thread from trying to access a dead message loop. @@ -95,12 +97,6 @@ bool ObjectWatcher::StopWatching() { // anything once it is run. watch_->watcher = NULL; - // If DoneWaiting was called, then the watch would have been posted as a - // task, and will therefore be deleted by the MessageLoop. Otherwise, we - // need to take care to delete it here. - if (!watch_->did_signal) - delete watch_; - watch_ = NULL; MessageLoop::current()->RemoveDestructionObserver(this); @@ -119,6 +115,7 @@ void CALLBACK ObjectWatcher::DoneWaiting(void* param, BOOLEAN timed_out) { DCHECK(!timed_out); Watch* watch = static_cast(param); + RefPtr addrefedWatch = watch; // Record that we ran this function. watch->did_signal = true; @@ -126,7 +123,7 @@ void CALLBACK ObjectWatcher::DoneWaiting(void* param, BOOLEAN timed_out) { // We rely on the locking in PostTask() to ensure that a memory barrier is // provided, which in turn ensures our change to did_signal can be observed // on the target thread. - watch->origin_loop->PostTask(FROM_HERE, watch); + watch->origin_loop->PostTask(addrefedWatch.forget()); } void ObjectWatcher::WillDestroyCurrentMessageLoop() { diff --git a/ipc/chromium/src/base/object_watcher.h b/ipc/chromium/src/base/object_watcher.h index 36b647f255..a1c4202c38 100644 --- a/ipc/chromium/src/base/object_watcher.h +++ b/ipc/chromium/src/base/object_watcher.h @@ -83,8 +83,8 @@ class ObjectWatcher : public MessageLoop::DestructionObserver { virtual void WillDestroyCurrentMessageLoop(); // Internal state. - struct Watch; - Watch* watch_; + class Watch; + RefPtr watch_; DISALLOW_COPY_AND_ASSIGN(ObjectWatcher); }; diff --git a/ipc/chromium/src/base/task.h b/ipc/chromium/src/base/task.h index c8af4ae834..b00451cf94 100644 --- a/ipc/chromium/src/base/task.h +++ b/ipc/chromium/src/base/task.h @@ -7,11 +7,11 @@ #define BASE_TASK_H_ #include "base/revocable_store.h" -#include "base/tracked.h" #include "base/tuple.h" #include "mozilla/IndexSequence.h" #include "mozilla/Tuple.h" #include "nsISupportsImpl.h" +#include "nsThreadUtils.h" // Helper functions so that we can call a function a pass it arguments that come // from a Tuple. @@ -55,26 +55,6 @@ void DispatchTupleToFunction(Function function, mozilla::Tuple& arg) function, arg); } -// Task ------------------------------------------------------------------------ -// -// A task is a generic runnable thingy, usually used for running code on a -// different thread or for scheduling future tasks off of the message loop. - -class Task : public tracked_objects::Tracked { - public: - Task() {} - virtual ~Task() {} - - // Tasks are automatically deleted after Run is called. - virtual void Run() = 0; -}; - -class CancelableTask : public Task { - public: - // Not all tasks support cancellation. - virtual void Cancel() = 0; -}; - // Scoped Factories ------------------------------------------------------------ // // These scoped factory objects can be used by non-refcounted objects to safely @@ -110,7 +90,7 @@ class CancelableTask : public Task { // // // The factories are not thread safe, so always invoke on // // |MessageLoop::current()|. -// MessageLoop::current()->PostDelayedTask(FROM_HERE, +// MessageLoop::current()->PostDelayedTask( // some_method_factory_.NewRunnableMethod(&MyClass::SomeMethod), // kSomeMethodDelayMS); // } @@ -132,9 +112,10 @@ class ScopedTaskFactory : public RevocableStore { public: explicit TaskWrapper(RevocableStore* store) : revocable_(store) { } - virtual void Run() { + NS_IMETHOD Run() override { if (!revocable_.revoked()) TaskType::Run(); + return NS_OK; } ~TaskWrapper() { @@ -162,19 +143,20 @@ class ScopedRunnableMethodFactory : public RevocableStore { explicit ScopedRunnableMethodFactory(T* object) : object_(object) { } template - inline Task* NewRunnableMethod(Method method, Elements&&... elements) { + inline already_AddRefed + NewRunnableMethod(Method method, Elements&&... elements) { typedef mozilla::Tuple::Type...> ArgsTuple; typedef RunnableMethod Runnable; typedef typename ScopedTaskFactory::TaskWrapper TaskWrapper; - TaskWrapper* task = new TaskWrapper(this); + RefPtr task = new TaskWrapper(this); task->Init(object_, method, mozilla::MakeTuple(mozilla::Forward(elements)...)); - return task; + return task.forget(); } protected: template - class RunnableMethod : public Task { + class RunnableMethod : public mozilla::Runnable { public: RunnableMethod() { } @@ -184,7 +166,10 @@ class ScopedRunnableMethodFactory : public RevocableStore { params_ = mozilla::Forward(params); } - virtual void Run() { DispatchTupleToMethod(obj_, meth_, params_); } + NS_IMETHOD Run() override { + DispatchTupleToMethod(obj_, meth_, params_); + return NS_OK; + } private: T* MOZ_UNSAFE_REF("The validity of this pointer must be enforced by " @@ -205,33 +190,17 @@ class ScopedRunnableMethodFactory : public RevocableStore { // Task to delete an object template -class DeleteTask : public CancelableTask { +class DeleteTask : public mozilla::CancelableRunnable { public: explicit DeleteTask(T* obj) : obj_(obj) { } - virtual void Run() { + NS_IMETHOD Run() override { delete obj_; + return NS_OK; } - virtual void Cancel() { - obj_ = NULL; - } - private: - T* MOZ_UNSAFE_REF("The validity of this pointer must be enforced by " - "external factors.") obj_; -}; - -// Task to Release() an object -template -class ReleaseTask : public CancelableTask { - public: - explicit ReleaseTask(T* obj) : obj_(obj) { - } - virtual void Run() { - if (obj_) - obj_->Release(); - } - virtual void Cancel() { + virtual nsresult Cancel() override { obj_ = NULL; + return NS_OK; } private: T* MOZ_UNSAFE_REF("The validity of this pointer must be enforced by " @@ -291,13 +260,13 @@ struct RunnableMethodTraits { // R T::MyFunction([A[, B]]) // // Usage: -// PostTask(FROM_HERE, NewRunnableMethod(object, &Object::method[, a[, b]]) -// PostTask(FROM_HERE, NewRunnableFunction(&function[, a[, b]]) +// PostTask(NewRunnableMethod(object, &Object::method[, a[, b]]) +// PostTask(NewRunnableFunction(&function[, a[, b]]) // RunnableMethod and NewRunnableMethod implementation ------------------------- template -class RunnableMethod : public CancelableTask, +class RunnableMethod : public mozilla::CancelableRunnable, public RunnableMethodTraits { public: RunnableMethod(T* obj, Method meth, Params&& params) @@ -308,13 +277,15 @@ class RunnableMethod : public CancelableTask, ReleaseCallee(); } - virtual void Run() { + NS_IMETHOD Run() override { if (obj_) DispatchTupleToMethod(obj_, meth_, params_); + return NS_OK; } - virtual void Cancel() { + virtual nsresult Cancel() override { ReleaseCallee(); + return NS_OK; } private: @@ -333,16 +304,19 @@ class RunnableMethod : public CancelableTask, }; template -inline CancelableTask* NewRunnableMethod(T* object, Method method, Args&&... args) { +inline already_AddRefed +NewRunnableMethod(T* object, Method method, Args&&... args) { typedef mozilla::Tuple::Type...> ArgsTuple; - return new RunnableMethod( - object, method, mozilla::MakeTuple(mozilla::Forward(args)...)); + RefPtr t = + new RunnableMethod(object, method, + mozilla::MakeTuple(mozilla::Forward(args)...)); + return t.forget(); } // RunnableFunction and NewRunnableFunction implementation --------------------- template -class RunnableFunction : public CancelableTask { +class RunnableFunction : public mozilla::CancelableRunnable { public: RunnableFunction(Function function, Params&& params) : function_(function), params_(mozilla::Forward(params)) { @@ -351,13 +325,15 @@ class RunnableFunction : public CancelableTask { ~RunnableFunction() { } - virtual void Run() { + NS_IMETHOD Run() override { if (function_) DispatchTupleToFunction(function_, params_); + return NS_OK; } - virtual void Cancel() { + virtual nsresult Cancel() override { function_ = nullptr; + return NS_OK; } Function function_; @@ -365,10 +341,13 @@ class RunnableFunction : public CancelableTask { }; template -inline CancelableTask* NewRunnableFunction(Function function, Args&&... args) { +inline already_AddRefed +NewRunnableFunction(Function function, Args&&... args) { typedef mozilla::Tuple::Type...> ArgsTuple; - return new RunnableFunction( - function, mozilla::MakeTuple(mozilla::Forward(args)...)); + RefPtr t = + new RunnableFunction(function, + mozilla::MakeTuple(mozilla::Forward(args)...)); + return t.forget(); } #endif // BASE_TASK_H_ diff --git a/ipc/chromium/src/base/thread.cc b/ipc/chromium/src/base/thread.cc index 4fd28117ae..e56b3288af 100644 --- a/ipc/chromium/src/base/thread.cc +++ b/ipc/chromium/src/base/thread.cc @@ -18,11 +18,12 @@ namespace base { // This task is used to trigger the message loop to exit. -class ThreadQuitTask : public Task { +class ThreadQuitTask : public mozilla::Runnable { public: - virtual void Run() { + NS_IMETHOD Run() override { MessageLoop::current()->Quit(); Thread::SetThreadWasQuitProperly(true); + return NS_OK; } }; @@ -113,8 +114,10 @@ void Thread::Stop() { DCHECK_NE(thread_id_, PlatformThread::CurrentId()); // StopSoon may have already been called. - if (message_loop_) - message_loop_->PostTask(FROM_HERE, new ThreadQuitTask()); + if (message_loop_) { + RefPtr task = new ThreadQuitTask(); + message_loop_->PostTask(task.forget()); + } // Wait for the thread to exit. It should already have terminated but make // sure this assumption is valid. @@ -143,7 +146,8 @@ void Thread::StopSoon() { // to someone calling Quit() on our message loop directly. DCHECK(message_loop_); - message_loop_->PostTask(FROM_HERE, new ThreadQuitTask()); + RefPtr task = new ThreadQuitTask(); + message_loop_->PostTask(task.forget()); } void Thread::ThreadMain() { diff --git a/ipc/chromium/src/base/timer.cc b/ipc/chromium/src/base/timer.cc index 280760681d..b1f360ef69 100644 --- a/ipc/chromium/src/base/timer.cc +++ b/ipc/chromium/src/base/timer.cc @@ -20,8 +20,9 @@ void BaseTimer_Helper::InitiateDelayedTask(TimerTask* timer_task) { delayed_task_ = timer_task; delayed_task_->timer_ = this; + RefPtr addrefedTask = timer_task; MessageLoop::current()->PostDelayedTask( - FROM_HERE, timer_task, + addrefedTask.forget(), static_cast(timer_task->delay_.InMilliseconds())); } diff --git a/ipc/chromium/src/base/timer.h b/ipc/chromium/src/base/timer.h index 59822c7566..09f3489a1c 100644 --- a/ipc/chromium/src/base/timer.h +++ b/ipc/chromium/src/base/timer.h @@ -69,7 +69,7 @@ class BaseTimer_Helper { // Returns true if the timer is running (i.e., not stopped). bool IsRunning() const { - return delayed_task_ != NULL; + return !!delayed_task_; } // Returns the current delay for this timer. May only call this method when @@ -80,10 +80,10 @@ class BaseTimer_Helper { } protected: - BaseTimer_Helper() : delayed_task_(NULL) {} + BaseTimer_Helper() {} // We have access to the timer_ member so we can orphan this task. - class TimerTask : public Task { + class TimerTask : public mozilla::Runnable { public: explicit TimerTask(TimeDelta delay) : delay_(delay) { // timer_ is set in InitiateDelayedTask. @@ -100,7 +100,7 @@ class BaseTimer_Helper { // orphaning delayed_task_ if it is non-null. void InitiateDelayedTask(TimerTask* timer_task); - TimerTask* delayed_task_; + RefPtr delayed_task_; DISALLOW_COPY_AND_ASSIGN(BaseTimer_Helper); }; @@ -129,7 +129,7 @@ class BaseTimer : public BaseTimer_Helper { // Call this method to reset the timer delay of an already running timer. void Reset() { DCHECK(IsRunning()); - InitiateDelayedTask(static_cast(delayed_task_)->Clone()); + InitiateDelayedTask(static_cast(delayed_task_.get())->Clone()); } private: @@ -150,14 +150,15 @@ class BaseTimer : public BaseTimer_Helper { ClearBaseTimer(); } - virtual void Run() { + NS_IMETHOD Run() override { if (!timer_) // timer_ is null if we were orphaned. - return; + return NS_OK; if (kIsRepeating) ResetBaseTimer(); else ClearBaseTimer(); DispatchToMethod(receiver_, method_, Tuple0()); + return NS_OK; } TimerTask* Clone() const { diff --git a/ipc/chromium/src/base/tracked.cc b/ipc/chromium/src/base/tracked.cc deleted file mode 100644 index 12d2616530..0000000000 --- a/ipc/chromium/src/base/tracked.cc +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/tracked.h" - -#include "base/string_util.h" -#include "base/tracked_objects.h" - -using base::Time; - -namespace tracked_objects { - -//------------------------------------------------------------------------------ -void Location::Write(bool display_filename, bool display_function_name, - std::string* output) const { - StringAppendF(output, "%s[%d] ", - display_filename ? file_name_ : "line", - line_number_); - - if (display_function_name) { - WriteFunctionName(output); - output->push_back(' '); - } -} - -void Location::WriteFunctionName(std::string* output) const { - // Translate "<" to "<" for HTML safety. - // TODO(jar): Support ASCII or html for logging in ASCII. - for (const char *p = function_name_; *p; p++) { - switch (*p) { - case '<': - output->append("<"); - break; - - case '>': - output->append(">"); - break; - - default: - output->push_back(*p); - break; - } - } -} - -//------------------------------------------------------------------------------ - -#ifndef TRACK_ALL_TASK_OBJECTS - -Tracked::Tracked() {} -Tracked::~Tracked() {} -void Tracked::SetBirthPlace(const Location& from_here) {} -bool Tracked::MissingBirthplace() const { return false; } -void Tracked::ResetBirthTime() {} - -#else - -Tracked::Tracked() : tracked_births_(NULL), tracked_birth_time_(Time::Now()) { - if (!ThreadData::IsActive()) - return; - SetBirthPlace(Location("NoFunctionName", "NeedToSetBirthPlace", -1)); -} - -Tracked::~Tracked() { - if (!ThreadData::IsActive() || !tracked_births_) - return; - ThreadData::current()->TallyADeath(*tracked_births_, - Time::Now() - tracked_birth_time_); -} - -void Tracked::SetBirthPlace(const Location& from_here) { - if (!ThreadData::IsActive()) - return; - if (tracked_births_) - tracked_births_->ForgetBirth(); - ThreadData* current_thread_data = ThreadData::current(); - if (!current_thread_data) - return; // Shutdown started, and this thread wasn't registered. - tracked_births_ = current_thread_data->FindLifetime(from_here); - tracked_births_->RecordBirth(); -} - -Location Tracked::GetBirthPlace() const { - if (tracked_births_) { - return tracked_births_->location(); - } - return Location(); -} - -void Tracked::ResetBirthTime() { - tracked_birth_time_ = Time::Now(); -} - -bool Tracked::MissingBirthplace() const { - return -1 == tracked_births_->location().line_number(); -} - -#endif // NDEBUG - -} // namespace tracked_objects diff --git a/ipc/chromium/src/base/tracked.h b/ipc/chromium/src/base/tracked.h deleted file mode 100644 index 8117618b29..0000000000 --- a/ipc/chromium/src/base/tracked.h +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -//------------------------------------------------------------------------------ -// Tracked is the base class for all tracked objects. During construction, it -// registers the fact that an instance was created, and at destruction time, it -// records that event. The instance may be tagged with a name, which is refered -// to as its Location. The Location is a file and line number, most -// typically indicated where the object was constructed. In some cases, as the -// object's significance is refined (for example, a Task object is augmented to -// do additonal things), its Location may be redefined to that later location. - -// Tracking includes (for each instance) recording the birth thread, death -// thread, and duration of life (from construction to destruction). All this -// data is accumulated and filtered for review at about:objects. - -#ifndef BASE_TRACKED_H_ -#define BASE_TRACKED_H_ - -#include - -#include "base/time.h" - -#ifndef NDEBUG -#ifndef TRACK_ALL_TASK_OBJECTS -#define TRACK_ALL_TASK_OBJECTS -#endif // TRACK_ALL_TASK_OBJECTS -#endif // NDEBUG - -namespace tracked_objects { - -//------------------------------------------------------------------------------ -// Location provides basic info where of an object was constructed, or was -// significantly brought to life. - -class Location { - public: - // Constructor should be called with a long-lived char*, such as __FILE__. - // It assumes the provided value will persist as a global constant, and it - // will not make a copy of it. - Location(const char* aFunctionName, const char* aFilename, int aLineNumber) - : function_name_(aFunctionName), - file_name_(aFilename), - line_number_(aLineNumber) { } - - // Provide a default constructor for easy of debugging. - Location() - : function_name_("Unknown"), - file_name_("Unknown"), - line_number_(-1) { } - - // Comparison operator for insertion into a std::map<> hash tables. - // All we need is *some* (any) hashing distinction. Strings should already - // be unique, so we don't bother with strcmp or such. - // Use line number as the primary key (because it is fast, and usually gets us - // a difference), and then pointers as secondary keys (just to get some - // distinctions). - bool operator < (const Location& other) const { - if (line_number_ != other.line_number_) - return line_number_ < other.line_number_; - if (file_name_ != other.file_name_) - return file_name_ < other.file_name_; - return function_name_ < other.function_name_; - } - - const char* function_name() const { return function_name_; } - const char* file_name() const { return file_name_; } - int line_number() const { return line_number_; } - - void Write(bool display_filename, bool display_function_name, - std::string* output) const; - - // Write function_name_ in HTML with '<' and '>' properly encoded. - void WriteFunctionName(std::string* output) const; - - private: - const char* const function_name_; - const char* const file_name_; - const int line_number_; -}; - - -//------------------------------------------------------------------------------ -// Define a macro to record the current source location. - -#define FROM_HERE tracked_objects::Location(__FUNCTION__, __FILE__, __LINE__) - - -//------------------------------------------------------------------------------ - - -class Births; - -class Tracked { - public: - Tracked(); - virtual ~Tracked(); - - // Used to record the FROM_HERE location of a caller. - void SetBirthPlace(const Location& from_here); - Location GetBirthPlace() const; - - // When a task sits around a long time, such as in a timer, or object watcher, - // this method should be called when the task becomes active, and its - // significant lifetime begins (and its waiting to be woken up has passed). - void ResetBirthTime(); - - bool MissingBirthplace() const; - - private: -#ifdef TRACK_ALL_TASK_OBJECTS - - // Pointer to instance were counts of objects with the same birth location - // (on the same thread) are stored. - Births* tracked_births_; - // The time this object was constructed. If its life consisted of a long - // waiting period, and then it became active, then this value is generally - // reset before the object begins it active life. - base::Time tracked_birth_time_; - -#endif // TRACK_ALL_TASK_OBJECTS - - DISALLOW_COPY_AND_ASSIGN(Tracked); -}; - -} // namespace tracked_objects - -#endif // BASE_TRACKED_H_ diff --git a/ipc/chromium/src/base/tracked_objects.cc b/ipc/chromium/src/base/tracked_objects.cc deleted file mode 100644 index 8d249fd7a8..0000000000 --- a/ipc/chromium/src/base/tracked_objects.cc +++ /dev/null @@ -1,758 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/tracked_objects.h" - -#include -#if defined(OS_WIN) -#include -#endif - -#include "base/string_util.h" - -using base::TimeDelta; -using mozilla::StaticMutexAutoLock; - -namespace tracked_objects { - -// A TLS slot to the TrackRegistry for the current thread. -// static -TLSSlot ThreadData::tls_index_(base::LINKER_INITIALIZED); - -//------------------------------------------------------------------------------ -// Death data tallies durations when a death takes place. - -void DeathData::RecordDeath(const TimeDelta& duration) { - ++count_; - life_duration_ += duration; - int64_t milliseconds = duration.InMilliseconds(); - square_duration_ += milliseconds * milliseconds; -} - -int DeathData::AverageMsDuration() const { - return static_cast(life_duration_.InMilliseconds() / count_); -} - -double DeathData::StandardDeviation() const { - double average = AverageMsDuration(); - double variance = static_cast(square_duration_)/count_ - - average * average; - return sqrt(variance); -} - - -void DeathData::AddDeathData(const DeathData& other) { - count_ += other.count_; - life_duration_ += other.life_duration_; - square_duration_ += other.square_duration_; -} - -void DeathData::Write(std::string* output) const { - if (!count_) - return; - if (1 == count_) - StringAppendF(output, "(1)Life in %dms ", AverageMsDuration()); - else - StringAppendF(output, "(%d)Lives %dms/life ", count_, AverageMsDuration()); -} - -void DeathData::Clear() { - count_ = 0; - life_duration_ = TimeDelta(); - square_duration_ = 0; -} - -//------------------------------------------------------------------------------ - -BirthOnThread::BirthOnThread(const Location& location) - : location_(location), - birth_thread_(ThreadData::current()) { } - -//------------------------------------------------------------------------------ -Births::Births(const Location& location) - : BirthOnThread(location), - birth_count_(0) { } - -//------------------------------------------------------------------------------ -// ThreadData maintains the central data for all births and death. - -// static -ThreadData* ThreadData::first_ = NULL; -// static -mozilla::StaticMutex ThreadData::list_lock_; - -// static -ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED; - -ThreadData::ThreadData() : next_(NULL), message_loop_(MessageLoop::current()) {} - -// static -ThreadData* ThreadData::current() { - if (!tls_index_.initialized()) - return NULL; - - ThreadData* registry = static_cast(tls_index_.Get()); - if (!registry) { - // We have to create a new registry for ThreadData. - bool too_late_to_create = false; - { - registry = new ThreadData; - StaticMutexAutoLock lock(list_lock_); - // Use lock to insure we have most recent status. - if (!IsActive()) { - too_late_to_create = true; - } else { - // Use lock to insert into list. - registry->next_ = first_; - first_ = registry; - } - } // Release lock. - if (too_late_to_create) { - delete registry; - registry = NULL; - } else { - tls_index_.Set(registry); - } - } - return registry; -} - -Births* ThreadData::FindLifetime(const Location& location) { - if (!message_loop_) // In case message loop wasn't yet around... - message_loop_ = MessageLoop::current(); // Find it now. - - BirthMap::iterator it = birth_map_.find(location); - if (it != birth_map_.end()) - return it->second; - Births* tracker = new Births(location); - - // Lock since the map may get relocated now, and other threads sometimes - // snapshot it (but they lock before copying it). - AutoLock lock(lock_); - birth_map_[location] = tracker; - return tracker; -} - -void ThreadData::TallyADeath(const Births& lifetimes, - const TimeDelta& duration) { - if (!message_loop_) // In case message loop wasn't yet around... - message_loop_ = MessageLoop::current(); // Find it now. - - DeathMap::iterator it = death_map_.find(&lifetimes); - if (it != death_map_.end()) { - it->second.RecordDeath(duration); - return; - } - - AutoLock lock(lock_); // Lock since the map may get relocated now. - death_map_[&lifetimes].RecordDeath(duration); -} - -// static -ThreadData* ThreadData::first() { - StaticMutexAutoLock lock(list_lock_); - return first_; -} - -const std::string ThreadData::ThreadName() const { - if (message_loop_) - return message_loop_->thread_name(); - return "ThreadWithoutMessageLoop"; -} - -// This may be called from another thread. -void ThreadData::SnapshotBirthMap(BirthMap *output) const { - AutoLock lock(*const_cast(&lock_)); - for (BirthMap::const_iterator it = birth_map_.begin(); - it != birth_map_.end(); ++it) - (*output)[it->first] = it->second; -} - -// This may be called from another thread. -void ThreadData::SnapshotDeathMap(DeathMap *output) const { - AutoLock lock(*const_cast(&lock_)); - for (DeathMap::const_iterator it = death_map_.begin(); - it != death_map_.end(); ++it) - (*output)[it->first] = it->second; -} - -#ifdef OS_WIN -void ThreadData::RunOnAllThreads(void (*function)()) { - ThreadData* list = first(); // Get existing list. - - std::vector message_loops; - for (ThreadData* it = list; it; it = it->next()) { - if (current() != it && it->message_loop()) - message_loops.push_back(it->message_loop()); - } - - ThreadSafeDownCounter* counter = - new ThreadSafeDownCounter(message_loops.size() + 1); // Extra one for us! - - HANDLE completion_handle = CreateEventW(NULL, false, false, NULL); - // Tell all other threads to run. - for (size_t i = 0; i < message_loops.size(); ++i) - message_loops[i]->PostTask(FROM_HERE, - new RunTheStatic(function, completion_handle, counter)); - - // Also run Task on our thread. - RunTheStatic local_task(function, completion_handle, counter); - local_task.Run(); - - WaitForSingleObject(completion_handle, INFINITE); - int ret_val = CloseHandle(completion_handle); - DCHECK(ret_val); -} -#endif - -// static -bool ThreadData::StartTracking(bool status) { -#ifndef TRACK_ALL_TASK_OBJECTS - return false; // Not compiled in. -#else - if (!status) { - StaticMutexAutoLock lock(list_lock_); - DCHECK(status_ == ACTIVE || status_ == SHUTDOWN); - status_ = SHUTDOWN; - return true; - } - StaticMutexAutoLock lock(list_lock_); - DCHECK(status_ == UNINITIALIZED); - CHECK(tls_index_.Initialize(NULL)); - status_ = ACTIVE; - return true; -#endif -} - -// static -bool ThreadData::IsActive() { - return status_ == ACTIVE; -} - -#ifdef OS_WIN -// static -void ThreadData::ShutdownMultiThreadTracking() { - // Using lock, guarantee that no new ThreadData instances will be created. - if (!StartTracking(false)) - return; - - RunOnAllThreads(ShutdownDisablingFurtherTracking); - - // Now the *only* threads that might change the database are the threads with - // no messages loops. They might still be adding data to their birth records, - // but since no objects are deleted on those threads, there will be no further - // access to to cross-thread data. - // We could do a cleanup on all threads except for the ones without - // MessageLoops, but we won't bother doing cleanup (destruction of data) yet. - return; -} -#endif - -// static -void ThreadData::ShutdownSingleThreadedCleanup() { - // We must be single threaded... but be careful anyway. - if (!StartTracking(false)) - return; - ThreadData* thread_data_list; - { - StaticMutexAutoLock lock(list_lock_); - thread_data_list = first_; - first_ = NULL; - } - - while (thread_data_list) { - ThreadData* next_thread_data = thread_data_list; - thread_data_list = thread_data_list->next(); - - for (BirthMap::iterator it = next_thread_data->birth_map_.begin(); - next_thread_data->birth_map_.end() != it; ++it) - delete it->second; // Delete the Birth Records. - next_thread_data->birth_map_.clear(); - next_thread_data->death_map_.clear(); - delete next_thread_data; // Includes all Death Records. - } - - CHECK(tls_index_.initialized()); - tls_index_.Free(); - DCHECK(!tls_index_.initialized()); - status_ = UNINITIALIZED; -} - -// static -void ThreadData::ShutdownDisablingFurtherTracking() { - // Redundantly set status SHUTDOWN on this thread. - if (!StartTracking(false)) - return; -} - - -//------------------------------------------------------------------------------ - -ThreadData::ThreadSafeDownCounter::ThreadSafeDownCounter(size_t count) - : remaining_count_(count) { - DCHECK(remaining_count_ > 0); -} - -bool ThreadData::ThreadSafeDownCounter::LastCaller() { - { - AutoLock lock(lock_); - if (--remaining_count_) - return false; - } // Release lock, so we can delete everything in this instance. - delete this; - return true; -} - -//------------------------------------------------------------------------------ -#ifdef OS_WIN -ThreadData::RunTheStatic::RunTheStatic(FunctionPointer function, - HANDLE completion_handle, - ThreadSafeDownCounter* counter) - : function_(function), - completion_handle_(completion_handle), - counter_(counter) { -} - -void ThreadData::RunTheStatic::Run() { - function_(); - if (counter_->LastCaller()) - SetEvent(completion_handle_); -} -#endif - -//------------------------------------------------------------------------------ -// Individual 3-tuple of birth (place and thread) along with death thread, and -// the accumulated stats for instances (DeathData). - -Snapshot::Snapshot(const BirthOnThread& birth_on_thread, - const ThreadData& death_thread, - const DeathData& death_data) - : birth_(&birth_on_thread), - death_thread_(&death_thread), - death_data_(death_data) { -} - -Snapshot::Snapshot(const BirthOnThread& birth_on_thread, int count) - : birth_(&birth_on_thread), - death_thread_(NULL), - death_data_(DeathData(count)) { -} - -const std::string Snapshot::DeathThreadName() const { - if (death_thread_) - return death_thread_->ThreadName(); - return "Still_Alive"; -} - -void Snapshot::Write(std::string* output) const { - death_data_.Write(output); - StringAppendF(output, "%s->%s ", - birth_->birth_thread()->ThreadName().c_str(), - death_thread_->ThreadName().c_str()); - birth_->location().Write(true, true, output); -} - -void Snapshot::Add(const Snapshot& other) { - death_data_.AddDeathData(other.death_data_); -} - -//------------------------------------------------------------------------------ -// DataCollector - -DataCollector::DataCollector() { - DCHECK(ThreadData::IsActive()); - - ThreadData* my_list = ThreadData::current()->first(); - - count_of_contributing_threads_ = 0; - for (ThreadData* thread_data = my_list; - thread_data; - thread_data = thread_data->next()) { - ++count_of_contributing_threads_; - } - - // Gather data serially. A different constructor could be used to do in - // parallel, and then invoke an OnCompletion task. - for (ThreadData* thread_data = my_list; - thread_data; - thread_data = thread_data->next()) { - Append(*thread_data); - } -} - -void DataCollector::Append(const ThreadData& thread_data) { - // Get copy of data (which is done under ThreadData's lock). - ThreadData::BirthMap birth_map; - thread_data.SnapshotBirthMap(&birth_map); - ThreadData::DeathMap death_map; - thread_data.SnapshotDeathMap(&death_map); - - // Use our lock to protect our accumulation activity. - AutoLock lock(accumulation_lock_); - - DCHECK(count_of_contributing_threads_); - - for (ThreadData::DeathMap::const_iterator it = death_map.begin(); - it != death_map.end(); ++it) { - collection_.push_back(Snapshot(*it->first, thread_data, it->second)); - global_birth_count_[it->first] -= it->first->birth_count(); - } - - for (ThreadData::BirthMap::const_iterator it = birth_map.begin(); - it != birth_map.end(); ++it) { - global_birth_count_[it->second] += it->second->birth_count(); - } - - --count_of_contributing_threads_; -} - -DataCollector::Collection* DataCollector::collection() { - DCHECK(!count_of_contributing_threads_); - return &collection_; -} - -void DataCollector::AddListOfLivingObjects() { - DCHECK(!count_of_contributing_threads_); - for (BirthCount::iterator it = global_birth_count_.begin(); - it != global_birth_count_.end(); ++it) { - if (it->second > 0) - collection_.push_back(Snapshot(*it->first, it->second)); - } -} - -//------------------------------------------------------------------------------ -// Aggregation - -void Aggregation::AddDeathSnapshot(const Snapshot& snapshot) { - AddBirth(snapshot.birth()); - death_threads_[snapshot.death_thread()]++; - AddDeathData(snapshot.death_data()); -} - -void Aggregation::AddBirths(const Births& births) { - AddBirth(births); - birth_count_ += births.birth_count(); -} -void Aggregation::AddBirth(const BirthOnThread& birth) { - AddBirthPlace(birth.location()); - birth_threads_[birth.birth_thread()]++; -} - -void Aggregation::AddBirthPlace(const Location& location) { - locations_[location]++; - birth_files_[location.file_name()]++; -} - -void Aggregation::Write(std::string* output) const { - if (locations_.size() == 1) { - locations_.begin()->first.Write(true, true, output); - } else { - StringAppendF(output, "%d Locations. ", locations_.size()); - if (birth_files_.size() > 1) - StringAppendF(output, "%d Files. ", birth_files_.size()); - else - StringAppendF(output, "All born in %s. ", - birth_files_.begin()->first.c_str()); - } - - if (birth_threads_.size() > 1) - StringAppendF(output, "%d BirthingThreads. ", birth_threads_.size()); - else - StringAppendF(output, "All born on %s. ", - birth_threads_.begin()->first->ThreadName().c_str()); - - if (death_threads_.size() > 1) { - StringAppendF(output, "%d DeathThreads. ", death_threads_.size()); - } else { - if (death_threads_.begin()->first) - StringAppendF(output, "All deleted on %s. ", - death_threads_.begin()->first->ThreadName().c_str()); - else - output->append("All these objects are still alive."); - } - - if (birth_count_ > 1) - StringAppendF(output, "Births=%d ", birth_count_); - - DeathData::Write(output); -} - -void Aggregation::Clear() { - birth_count_ = 0; - birth_files_.clear(); - locations_.clear(); - birth_threads_.clear(); - DeathData::Clear(); - death_threads_.clear(); -} - -//------------------------------------------------------------------------------ -// Comparison object for sorting. - -Comparator::Comparator() - : selector_(NIL), - tiebreaker_(NULL), - combined_selectors_(0), - use_tiebreaker_for_sort_only_(false) {} - -void Comparator::Clear() { - if (tiebreaker_) { - tiebreaker_->Clear(); - delete tiebreaker_; - tiebreaker_ = NULL; - } - use_tiebreaker_for_sort_only_ = false; - selector_ = NIL; -} - -void Comparator::Sort(DataCollector::Collection* collection) const { - std::sort(collection->begin(), collection->end(), *this); -} - - -bool Comparator::operator()(const Snapshot& left, - const Snapshot& right) const { - switch (selector_) { - case BIRTH_THREAD: - if (left.birth_thread() != right.birth_thread() && - left.birth_thread()->ThreadName() != - right.birth_thread()->ThreadName()) - return left.birth_thread()->ThreadName() < - right.birth_thread()->ThreadName(); - break; - - case DEATH_THREAD: - if (left.death_thread() != right.death_thread() && - left.DeathThreadName() != - right.DeathThreadName()) { - if (!left.death_thread()) - return true; - if (!right.death_thread()) - return false; - return left.DeathThreadName() < - right.DeathThreadName(); - } - break; - - case BIRTH_FILE: - if (left.location().file_name() != right.location().file_name()) { - int comp = strcmp(left.location().file_name(), - right.location().file_name()); - if (comp) - return 0 > comp; - } - break; - - case BIRTH_FUNCTION: - if (left.location().function_name() != right.location().function_name()) { - int comp = strcmp(left.location().function_name(), - right.location().function_name()); - if (comp) - return 0 > comp; - } - break; - - case BIRTH_LINE: - if (left.location().line_number() != right.location().line_number()) - return left.location().line_number() < - right.location().line_number(); - break; - - case COUNT: - if (left.count() != right.count()) - return left.count() > right.count(); // Sort large at front of vector. - break; - - case AVERAGE_DURATION: - if (left.AverageMsDuration() != right.AverageMsDuration()) - return left.AverageMsDuration() > right.AverageMsDuration(); - break; - - default: - break; - } - if (tiebreaker_) - return tiebreaker_->operator()(left, right); - return false; -} - -bool Comparator::Equivalent(const Snapshot& left, - const Snapshot& right) const { - switch (selector_) { - case BIRTH_THREAD: - if (left.birth_thread() != right.birth_thread() && - left.birth_thread()->ThreadName() != - right.birth_thread()->ThreadName()) - return false; - break; - - case DEATH_THREAD: - if (left.death_thread() != right.death_thread() && - left.DeathThreadName() != right.DeathThreadName()) - return false; - break; - - case BIRTH_FILE: - if (left.location().file_name() != right.location().file_name()) { - int comp = strcmp(left.location().file_name(), - right.location().file_name()); - if (comp) - return false; - } - break; - - case BIRTH_FUNCTION: - if (left.location().function_name() != right.location().function_name()) { - int comp = strcmp(left.location().function_name(), - right.location().function_name()); - if (comp) - return false; - } - break; - - case COUNT: - if (left.count() != right.count()) - return false; - break; - - case AVERAGE_DURATION: - if (left.life_duration() != right.life_duration()) - return false; - break; - - default: - break; - } - if (tiebreaker_ && !use_tiebreaker_for_sort_only_) - return tiebreaker_->Equivalent(left, right); - return true; -} - -bool Comparator::Acceptable(const Snapshot& sample) const { - if (required_.size()) { - switch (selector_) { - case BIRTH_THREAD: - if (sample.birth_thread()->ThreadName().find(required_) == - std::string::npos) - return false; - break; - - case DEATH_THREAD: - if (sample.DeathThreadName().find(required_) == std::string::npos) - return false; - break; - - case BIRTH_FILE: - if (!strstr(sample.location().file_name(), required_.c_str())) - return false; - break; - - case BIRTH_FUNCTION: - if (!strstr(sample.location().function_name(), required_.c_str())) - return false; - break; - - default: - break; - } - } - if (tiebreaker_ && !use_tiebreaker_for_sort_only_) - return tiebreaker_->Acceptable(sample); - return true; -} - -void Comparator::SetTiebreaker(Selector selector, const std::string required) { - if (selector == selector_ || NIL == selector) - return; - combined_selectors_ |= selector; - if (NIL == selector_) { - selector_ = selector; - if (required.size()) - required_ = required; - return; - } - if (tiebreaker_) { - if (use_tiebreaker_for_sort_only_) { - Comparator* temp = new Comparator; - temp->tiebreaker_ = tiebreaker_; - tiebreaker_ = temp; - } - } else { - tiebreaker_ = new Comparator; - DCHECK(!use_tiebreaker_for_sort_only_); - } - tiebreaker_->SetTiebreaker(selector, required); -} - -bool Comparator::IsGroupedBy(Selector selector) const { - return 0 != (selector & combined_selectors_); -} - -void Comparator::SetSubgroupTiebreaker(Selector selector) { - if (selector == selector_ || NIL == selector) - return; - if (!tiebreaker_) { - use_tiebreaker_for_sort_only_ = true; - tiebreaker_ = new Comparator; - tiebreaker_->SetTiebreaker(selector, ""); - } else { - tiebreaker_->SetSubgroupTiebreaker(selector); - } -} - -bool Comparator::WriteSortGrouping(const Snapshot& sample, - std::string* output) const { - bool wrote_data = false; - switch (selector_) { - case BIRTH_THREAD: - StringAppendF(output, "All new on %s ", - sample.birth_thread()->ThreadName().c_str()); - wrote_data = true; - break; - - case DEATH_THREAD: - if (sample.death_thread()) - StringAppendF(output, "All deleted on %s ", - sample.DeathThreadName().c_str()); - else - output->append("All still alive "); - wrote_data = true; - break; - - case BIRTH_FILE: - StringAppendF(output, "All born in %s ", - sample.location().file_name()); - break; - - case BIRTH_FUNCTION: - output->append("All born in "); - sample.location().WriteFunctionName(output); - output->push_back(' '); - break; - - default: - break; - } - if (tiebreaker_ && !use_tiebreaker_for_sort_only_) { - wrote_data |= tiebreaker_->WriteSortGrouping(sample, output); - } - return wrote_data; -} - -void Comparator::WriteSnapshot(const Snapshot& sample, - std::string* output) const { - sample.death_data().Write(output); - if (!(combined_selectors_ & BIRTH_THREAD) || - !(combined_selectors_ & DEATH_THREAD)) - StringAppendF(output, "%s->%s ", - (combined_selectors_ & BIRTH_THREAD) ? "*" : - sample.birth().birth_thread()->ThreadName().c_str(), - (combined_selectors_ & DEATH_THREAD) ? "*" : - sample.DeathThreadName().c_str()); - sample.birth().location().Write(!(combined_selectors_ & BIRTH_FILE), - !(combined_selectors_ & BIRTH_FUNCTION), - output); -} - -} // namespace tracked_objects diff --git a/ipc/chromium/src/base/tracked_objects.h b/ipc/chromium/src/base/tracked_objects.h deleted file mode 100644 index 796d3c9b23..0000000000 --- a/ipc/chromium/src/base/tracked_objects.h +++ /dev/null @@ -1,499 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_TRACKED_OBJECTS_H_ -#define BASE_TRACKED_OBJECTS_H_ - -//------------------------------------------------------------------------------ -#include -#include -#include - -#include "base/lock.h" -#include "mozilla/StaticMutex.h" -#include "base/message_loop.h" -#include "base/thread_local_storage.h" -#include "base/tracked.h" - - -namespace tracked_objects { - -//------------------------------------------------------------------------------ -// For a specific thread, and a specific birth place, the collection of all -// death info (with tallies for each death thread, to prevent access conflicts). -class ThreadData; -class BirthOnThread { - public: - explicit BirthOnThread(const Location& location); - - const Location location() const { return location_; } - const ThreadData* birth_thread() const { return birth_thread_; } - - private: - // File/lineno of birth. This defines the essence of the type, as the context - // of the birth (construction) often tell what the item is for. This field - // is const, and hence safe to access from any thread. - const Location location_; - - // The thread that records births into this object. Only this thread is - // allowed to access birth_count_ (which changes over time). - const ThreadData* birth_thread_; // The thread this birth took place on. - - DISALLOW_COPY_AND_ASSIGN(BirthOnThread); -}; - -//------------------------------------------------------------------------------ -// A class for accumulating counts of births (without bothering with a map<>). - -class Births: public BirthOnThread { - public: - explicit Births(const Location& location); - - int birth_count() const { return birth_count_; } - - // When we have a birth we update the count for this BirhPLace. - void RecordBirth() { ++birth_count_; } - - // When a birthplace is changed (updated), we need to decrement the counter - // for the old instance. - void ForgetBirth() { --birth_count_; } // We corrected a birth place. - - private: - // The number of births on this thread for our location_. - int birth_count_; - - DISALLOW_COPY_AND_ASSIGN(Births); -}; - -//------------------------------------------------------------------------------ -// Basic info summarizing multiple destructions of an object with a single -// birthplace (fixed Location). Used both on specific threads, and also used -// in snapshots when integrating assembled data. - -class DeathData { - public: - // Default initializer. - DeathData() : count_(0), square_duration_(0) {} - - // When deaths have not yet taken place, and we gather data from all the - // threads, we create DeathData stats that tally the number of births without - // a corrosponding death. - explicit DeathData(int count) : count_(count), square_duration_(0) {} - - void RecordDeath(const base::TimeDelta& duration); - - // Metrics accessors. - int count() const { return count_; } - base::TimeDelta life_duration() const { return life_duration_; } - int64_t square_duration() const { return square_duration_; } - int AverageMsDuration() const; - double StandardDeviation() const; - - // Accumulate metrics from other into this. - void AddDeathData(const DeathData& other); - - // Simple print of internal state. - void Write(std::string* output) const; - - void Clear(); - - private: - int count_; // Number of destructions. - base::TimeDelta life_duration_; // Sum of all lifetime durations. - int64_t square_duration_; // Sum of squares in milliseconds. -}; - -//------------------------------------------------------------------------------ -// A temporary collection of data that can be sorted and summarized. It is -// gathered (carefully) from many threads. Instances are held in arrays and -// processed, filtered, and rendered. -// The source of this data was collected on many threads, and is asynchronously -// changing. The data in this instance is not asynchronously changing. - -class Snapshot { - public: - // When snapshotting a full life cycle set (birth-to-death), use this: - Snapshot(const BirthOnThread& birth_on_thread, const ThreadData& death_thread, - const DeathData& death_data); - - // When snapshotting a birth, with no death yet, use this: - Snapshot(const BirthOnThread& birth_on_thread, int count); - - - const ThreadData* birth_thread() const { return birth_->birth_thread(); } - const Location location() const { return birth_->location(); } - const BirthOnThread& birth() const { return *birth_; } - const ThreadData* death_thread() const {return death_thread_; } - const DeathData& death_data() const { return death_data_; } - const std::string DeathThreadName() const; - - int count() const { return death_data_.count(); } - base::TimeDelta life_duration() const { return death_data_.life_duration(); } - int64_t square_duration() const { return death_data_.square_duration(); } - int AverageMsDuration() const { return death_data_.AverageMsDuration(); } - - void Write(std::string* output) const; - - void Add(const Snapshot& other); - - private: - const BirthOnThread* birth_; // Includes Location and birth_thread. - const ThreadData* death_thread_; - DeathData death_data_; -}; -//------------------------------------------------------------------------------ -// DataCollector is a container class for Snapshot and BirthOnThread count -// items. It protects the gathering under locks, so that it could be called via -// Posttask on any threads, such as all the target threads in parallel. - -class DataCollector { - public: - typedef std::vector Collection; - - // Construct with a list of how many threads should contribute. This helps us - // determine (in the async case) when we are done with all contributions. - DataCollector(); - - // Add all stats from the indicated thread into our arrays. This function is - // mutex protected, and *could* be called from any threads (although current - // implementation serialized calls to Append). - void Append(const ThreadData& thread_data); - - // After the accumulation phase, the following access is to process data. - Collection* collection(); - - // After collection of death data is complete, we can add entries for all the - // remaining living objects. - void AddListOfLivingObjects(); - - private: - // This instance may be provided to several threads to contribute data. The - // following counter tracks how many more threads will contribute. When it is - // zero, then all asynchronous contributions are complete, and locked access - // is no longer needed. - int count_of_contributing_threads_; - - // The array that we collect data into. - Collection collection_; - - // The total number of births recorded at each location for which we have not - // seen a death count. - typedef std::map BirthCount; - BirthCount global_birth_count_; - - Lock accumulation_lock_; // Protects access during accumulation phase. - - DISALLOW_COPY_AND_ASSIGN(DataCollector); -}; - -//------------------------------------------------------------------------------ -// Aggregation contains summaries (totals and subtotals) of groups of Snapshot -// instances to provide printing of these collections on a single line. - -class Aggregation: public DeathData { - public: - Aggregation() : birth_count_(0) {} - - void AddDeathSnapshot(const Snapshot& snapshot); - void AddBirths(const Births& births); - void AddBirth(const BirthOnThread& birth); - void AddBirthPlace(const Location& location); - void Write(std::string* output) const; - void Clear(); - - private: - int birth_count_; - std::map birth_files_; - std::map locations_; - std::map birth_threads_; - DeathData death_data_; - std::map death_threads_; - - DISALLOW_COPY_AND_ASSIGN(Aggregation); -}; - -//------------------------------------------------------------------------------ -// Comparator does the comparison of Snapshot instances. It is -// used to order the instances in a vector. It orders them into groups (for -// aggregation), and can also order instances within the groups (for detailed -// rendering of the instances). - -class Comparator { - public: - enum Selector { - NIL = 0, - BIRTH_THREAD = 1, - DEATH_THREAD = 2, - BIRTH_FILE = 4, - BIRTH_FUNCTION = 8, - BIRTH_LINE = 16, - COUNT = 32, - AVERAGE_DURATION = 64, - TOTAL_DURATION = 128 - }; - - explicit Comparator(); - - // Reset the comparator to a NIL selector. Reset() and recursively delete any - // tiebreaker_ entries. NOTE: We can't use a standard destructor, because - // the sort algorithm makes copies of this object, and then deletes them, - // which would cause problems (either we'd make expensive deep copies, or we'd - // do more thna one delete on a tiebreaker_. - void Clear(); - - // The less() operator for sorting the array via std::sort(). - bool operator()(const Snapshot& left, const Snapshot& right) const; - - void Sort(DataCollector::Collection* collection) const; - - // Check to see if the items are sort equivalents (should be aggregated). - bool Equivalent(const Snapshot& left, const Snapshot& right) const; - - // Check to see if all required fields are present in the given sample. - bool Acceptable(const Snapshot& sample) const; - - // A comparator can be refined by specifying what to do if the selected basis - // for comparison is insufficient to establish an ordering. This call adds - // the indicated attribute as the new "least significant" basis of comparison. - void SetTiebreaker(Selector selector, const std::string required); - - // Indicate if this instance is set up to sort by the given Selector, thereby - // putting that information in the SortGrouping, so it is not needed in each - // printed line. - bool IsGroupedBy(Selector selector) const; - - // Using the tiebreakers as set above, we mostly get an ordering, which - // equivalent groups. If those groups are displayed (rather than just being - // aggregated, then the following is used to order them (within the group). - void SetSubgroupTiebreaker(Selector selector); - - // Output a header line that can be used to indicated what items will be - // collected in the group. It lists all (potentially) tested attributes and - // their values (in the sample item). - bool WriteSortGrouping(const Snapshot& sample, std::string* output) const; - - // Output a sample, with SortGroup details not displayed. - void WriteSnapshot(const Snapshot& sample, std::string* output) const; - - private: - // The selector directs this instance to compare based on the specified - // members of the tested elements. - enum Selector selector_; - - // For filtering into acceptable and unacceptable snapshot instance, the - // following is required to be a substring of the selector_ field. - std::string required_; - - // If this instance can't decide on an ordering, we can consult a tie-breaker - // which may have a different basis of comparison. - Comparator* tiebreaker_; - - // We or together all the selectors we sort on (not counting sub-group - // selectors), so that we can tell if we've decided to group on any given - // criteria. - int combined_selectors_; - - // Some tiebreakrs are for subgroup ordering, and not for basic ordering (in - // preparation for aggregation). The subgroup tiebreakers are not consulted - // when deciding if two items are in equivalent groups. This flag tells us - // to ignore the tiebreaker when doing Equivalent() testing. - bool use_tiebreaker_for_sort_only_; -}; - - -//------------------------------------------------------------------------------ -// For each thread, we have a ThreadData that stores all tracking info generated -// on this thread. This prevents the need for locking as data accumulates. - -class ThreadData { - public: - typedef std::map BirthMap; - typedef std::map DeathMap; - - ThreadData(); - - // Using Thread Local Store, find the current instance for collecting data. - // If an instance does not exist, construct one (and remember it for use on - // this thread. - // If shutdown has already started, and we don't yet have an instance, then - // return null. - static ThreadData* current(); - - // In this thread's data, find a place to record a new birth. - Births* FindLifetime(const Location& location); - - // Find a place to record a death on this thread. - void TallyADeath(const Births& lifetimes, const base::TimeDelta& duration); - - // (Thread safe) Get start of list of instances. - static ThreadData* first(); - // Iterate through the null terminated list of instances. - ThreadData* next() const { return next_; } - - MessageLoop* message_loop() const { return message_loop_; } - const std::string ThreadName() const; - - // Using our lock, make a copy of the specified maps. These calls may arrive - // from non-local threads. - void SnapshotBirthMap(BirthMap *output) const; - void SnapshotDeathMap(DeathMap *output) const; - - static void RunOnAllThreads(void (*Func)()); - - // Set internal status_ to either become ACTIVE, or later, to be SHUTDOWN, - // based on argument being true or false respectively. - // IF tracking is not compiled in, this function will return false. - static bool StartTracking(bool status); - static bool IsActive(); - -#ifdef OS_WIN - // WARNING: ONLY call this function when all MessageLoops are still intact for - // all registered threads. IF you call it later, you will crash. - // Note: You don't need to call it at all, and you can wait till you are - // single threaded (again) to do the cleanup via - // ShutdownSingleThreadedCleanup(). - // Start the teardown (shutdown) process in a multi-thread mode by disabling - // further additions to thread database on all threads. First it makes a - // local (locked) change to prevent any more threads from registering. Then - // it Posts a Task to all registered threads to be sure they are aware that no - // more accumulation can take place. - static void ShutdownMultiThreadTracking(); -#endif - - // WARNING: ONLY call this function when you are running single threaded - // (again) and all message loops and threads have terminated. Until that - // point some threads may still attempt to write into our data structures. - // Delete recursively all data structures, starting with the list of - // ThreadData instances. - static void ShutdownSingleThreadedCleanup(); - - private: - // Current allowable states of the tracking system. The states always - // proceed towards SHUTDOWN, and never go backwards. - enum Status { - UNINITIALIZED, - ACTIVE, - SHUTDOWN - }; - - // A class used to count down which is accessed by several threads. This is - // used to make sure RunOnAllThreads() actually runs a task on the expected - // count of threads. - class ThreadSafeDownCounter { - public: - // Constructor sets the count, once and for all. - explicit ThreadSafeDownCounter(size_t count); - - // Decrement the count, and return true if we hit zero. Also delete this - // instance automatically when we hit zero. - bool LastCaller(); - - private: - size_t remaining_count_; - Lock lock_; // protect access to remaining_count_. - }; - -#ifdef OS_WIN - // A Task class that runs a static method supplied, and checks to see if this - // is the last tasks instance (on last thread) that will run the method. - // IF this is the last run, then the supplied event is signalled. - class RunTheStatic : public Task { - public: - typedef void (*FunctionPointer)(); - RunTheStatic(FunctionPointer function, - HANDLE completion_handle, - ThreadSafeDownCounter* counter); - // Run the supplied static method, and optionally set the event. - void Run(); - - private: - FunctionPointer function_; - HANDLE completion_handle_; - // Make sure enough tasks are called before completion is signaled. - ThreadSafeDownCounter* counter_; - - DISALLOW_COPY_AND_ASSIGN(RunTheStatic); - }; -#endif - - // Each registered thread is called to set status_ to SHUTDOWN. - // This is done redundantly on every registered thread because it is not - // protected by a mutex. Running on all threads guarantees we get the - // notification into the memory cache of all possible threads. - static void ShutdownDisablingFurtherTracking(); - - // We use thread local store to identify which ThreadData to interact with. - static TLSSlot tls_index_ ; - - // Link to the most recently created instance (starts a null terminated list). - static ThreadData* first_; - // Protection for access to first_. - static mozilla::StaticMutex list_lock_; - - - // We set status_ to SHUTDOWN when we shut down the tracking service. This - // setting is redundantly established by all participating - // threads so that we are *guaranteed* (without locking) that all threads - // can "see" the status and avoid additional calls into the service. - static Status status_; - - // Link to next instance (null terminated list). Used to globally track all - // registered instances (corresponds to all registered threads where we keep - // data). - ThreadData* next_; - - // The message loop where tasks needing to access this instance's private data - // should be directed. Since some threads have no message loop, some - // instances have data that can't be (safely) modified externally. - MessageLoop* message_loop_; - - // A map used on each thread to keep track of Births on this thread. - // This map should only be accessed on the thread it was constructed on. - // When a snapshot is needed, this structure can be locked in place for the - // duration of the snapshotting activity. - BirthMap birth_map_; - - // Similar to birth_map_, this records informations about death of tracked - // instances (i.e., when a tracked instance was destroyed on this thread). - DeathMap death_map_; - - // Lock to protect *some* access to BirthMap and DeathMap. We only use - // locking protection when we are growing the maps, or using an iterator. We - // only do writes to members from this thread, so the updates of values are - // atomic. Folks can read from other threads, and get (via races) new or old - // data, but that is considered acceptable errors (mis-information). - Lock lock_; - - DISALLOW_COPY_AND_ASSIGN(ThreadData); -}; - - -//------------------------------------------------------------------------------ -// Provide simple way to to start global tracking, and to tear down tracking -// when done. Note that construction and destruction of this object must be -// done when running in single threaded mode (before spawning a lot of threads -// for construction, and after shutting down all the threads for destruction). - -class AutoTracking { - public: - AutoTracking() { ThreadData::StartTracking(true); } - - ~AutoTracking() { -#ifndef NDEBUG // Don't call these in a Release build: they just waste time. - // The following should ONLY be called when in single threaded mode. It is - // unsafe to do this cleanup if other threads are still active. - // It is also very unnecessary, so I'm only doing this in debug to satisfy - // purify (if we need to!). - ThreadData::ShutdownSingleThreadedCleanup(); -#endif - } - - private: - DISALLOW_COPY_AND_ASSIGN(AutoTracking); -}; - - -} // namespace tracked_objects - -#endif // BASE_TRACKED_OBJECTS_H_ diff --git a/ipc/chromium/src/base/waitable_event_watcher.h b/ipc/chromium/src/base/waitable_event_watcher.h index c295795b7c..904ff0ab2b 100644 --- a/ipc/chromium/src/base/waitable_event_watcher.h +++ b/ipc/chromium/src/base/waitable_event_watcher.h @@ -144,7 +144,7 @@ class WaitableEventWatcher MessageLoop* message_loop_; RefPtr cancel_flag_; AsyncWaiter* waiter_; - AsyncCallbackTask* callback_task_; + RefPtr callback_task_; RefPtr kernel_; #endif }; diff --git a/ipc/chromium/src/base/waitable_event_watcher_posix.cc b/ipc/chromium/src/base/waitable_event_watcher_posix.cc index 74ada90c58..856bef8856 100644 --- a/ipc/chromium/src/base/waitable_event_watcher_posix.cc +++ b/ipc/chromium/src/base/waitable_event_watcher_posix.cc @@ -59,7 +59,8 @@ class Flag final { // ----------------------------------------------------------------------------- class AsyncWaiter final : public WaitableEvent::Waiter { public: - AsyncWaiter(MessageLoop* message_loop, Task* task, Flag* flag) + AsyncWaiter(MessageLoop* message_loop, + already_AddRefed task, Flag* flag) : message_loop_(message_loop), cb_task_(task), flag_(flag) { } @@ -68,9 +69,9 @@ class AsyncWaiter final : public WaitableEvent::Waiter { if (flag_->value()) { // If the callback has been canceled, we don't enqueue the task, we just // delete it instead. - delete cb_task_; + cb_task_ = nullptr; } else { - message_loop_->PostTask(FROM_HERE, cb_task_); + message_loop_->PostTask(cb_task_.forget()); } // We are removed from the wait-list by the WaitableEvent itself. It only @@ -89,7 +90,7 @@ class AsyncWaiter final : public WaitableEvent::Waiter { private: MessageLoop *const message_loop_; - Task *const cb_task_; + RefPtr cb_task_; RefPtr flag_; }; @@ -98,7 +99,7 @@ class AsyncWaiter final : public WaitableEvent::Waiter { // this by posting this task, which calls the delegate and keeps track of when // the event is canceled. // ----------------------------------------------------------------------------- -class AsyncCallbackTask : public Task { +class AsyncCallbackTask : public mozilla::Runnable { public: AsyncCallbackTask(Flag* flag, WaitableEventWatcher::Delegate* delegate, WaitableEvent* event) @@ -107,7 +108,7 @@ class AsyncCallbackTask : public Task { event_(event) { } - void Run() { + NS_IMETHOD Run() override { // Runs in MessageLoop thread. if (!flag_->value()) { // This is to let the WaitableEventWatcher know that the event has occured @@ -116,6 +117,7 @@ class AsyncCallbackTask : public Task { delegate_->OnWaitableEventSignaled(event_); } + return NS_OK; // We are deleted by the MessageLoop } @@ -128,8 +130,7 @@ class AsyncCallbackTask : public Task { WaitableEventWatcher::WaitableEventWatcher() : event_(NULL), message_loop_(NULL), - cancel_flag_(NULL), - callback_task_(NULL) { + cancel_flag_(NULL) { } WaitableEventWatcher::~WaitableEventWatcher() { @@ -172,7 +173,8 @@ bool WaitableEventWatcher::StartWatching // No hairpinning - we can't call the delegate directly here. We have to // enqueue a task on the MessageLoop as normal. - current_ml->PostTask(FROM_HERE, callback_task_); + RefPtr addrefedTask = callback_task_; + current_ml->PostTask(addrefedTask.forget()); return true; } @@ -181,7 +183,8 @@ bool WaitableEventWatcher::StartWatching event_ = event; kernel_ = kernel; - waiter_ = new AsyncWaiter(current_ml, callback_task_, cancel_flag_); + RefPtr addrefedTask = callback_task_; + waiter_ = new AsyncWaiter(current_ml, addrefedTask.forget(), cancel_flag_); event->Enqueue(waiter_); return true; @@ -239,7 +242,7 @@ void WaitableEventWatcher::StopWatching() { // have been enqueued with the MessageLoop because the waiter was never // signaled) delete waiter_; - delete callback_task_; + callback_task_ = nullptr; cancel_flag_ = NULL; return; } diff --git a/ipc/chromium/src/base/win_util.cc b/ipc/chromium/src/base/win_util.cc index 2878b3c81a..5c49aac13e 100644 --- a/ipc/chromium/src/base/win_util.cc +++ b/ipc/chromium/src/base/win_util.cc @@ -10,7 +10,6 @@ #include "base/logging.h" #include "base/singleton.h" #include "base/string_util.h" -#include "base/tracked.h" namespace win_util { diff --git a/ipc/chromium/src/base/win_util.h b/ipc/chromium/src/base/win_util.h index 6188182d02..860b99362a 100644 --- a/ipc/chromium/src/base/win_util.h +++ b/ipc/chromium/src/base/win_util.h @@ -10,8 +10,6 @@ #include -#include "base/tracked.h" - namespace win_util { // Uses the last Win32 error to generate a human readable message string. diff --git a/ipc/chromium/src/chrome/common/child_process_host.cc b/ipc/chromium/src/chrome/common/child_process_host.cc index c6e302ee1f..5465080bbd 100644 --- a/ipc/chromium/src/chrome/common/child_process_host.cc +++ b/ipc/chromium/src/chrome/common/child_process_host.cc @@ -27,16 +27,17 @@ typedef std::list ChildProcessList; // The NotificationTask is used to notify about plugin process connection/ // disconnection. It is needed because the notifications in the // NotificationService must happen in the main thread. -class ChildNotificationTask : public Task { +class ChildNotificationTask : public mozilla::Runnable { public: ChildNotificationTask( NotificationType notification_type, ChildProcessInfo* info) : notification_type_(notification_type), info_(*info) { } - virtual void Run() { + NS_IMETHOD Run() { NotificationService::current()-> Notify(notification_type_, NotificationService::AllSources(), Details(&info_)); + return NS_OK; } private: @@ -129,8 +130,8 @@ void ChildProcessHost::Notify(NotificationType type) { loop = mozilla::ipc::ProcessChild::message_loop(); if (!loop) loop = MessageLoop::current(); - loop->PostTask( - FROM_HERE, new ChildNotificationTask(type, this)); + RefPtr task = new ChildNotificationTask(type, this); + loop->PostTask(task.forget()); } void ChildProcessHost::OnWaitableEventSignaled(base::WaitableEvent *event) { diff --git a/ipc/chromium/src/chrome/common/child_thread.cc b/ipc/chromium/src/chrome/common/child_thread.cc index 5469db0ede..4948c9ec77 100644 --- a/ipc/chromium/src/chrome/common/child_thread.cc +++ b/ipc/chromium/src/chrome/common/child_thread.cc @@ -33,15 +33,15 @@ bool ChildThread::Run() { bool r = StartWithOptions(options_); #ifdef MOZ_NUWA_PROCESS if (IsNuwaProcess()) { - message_loop()->PostTask(FROM_HERE, - NewRunnableFunction(&ChildThread::MarkThread)); + message_loop()->PostTask(NewRunnableFunction(&ChildThread::MarkThread)); } #endif return r; } void ChildThread::OnChannelError() { - owner_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask()); + RefPtr task = new MessageLoop::QuitTask(); + owner_loop_->PostTask(task.forget()); } #ifdef MOZ_NUWA_PROCESS @@ -87,7 +87,8 @@ void ChildThread::CleanUp() { void ChildThread::OnProcessFinalRelease() { if (!check_with_browser_before_shutdown_) { - owner_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask()); + RefPtr task = new MessageLoop::QuitTask(); + owner_loop_->PostTask(task.forget()); return; } } diff --git a/ipc/chromium/src/chrome/common/ipc_channel_win.cc b/ipc/chromium/src/chrome/common/ipc_channel_win.cc index 488fbfc646..bfd45071ac 100644 --- a/ipc/chromium/src/chrome/common/ipc_channel_win.cc +++ b/ipc/chromium/src/chrome/common/ipc_channel_win.cc @@ -265,7 +265,7 @@ bool Channel::ChannelImpl::Connect() { // Complete setup asynchronously. By not setting input_state_.is_pending // to true, we indicate to OnIOCompleted that this is the special // initialization signal. - MessageLoopForIO::current()->PostTask(FROM_HERE, factory_.NewRunnableMethod( + MessageLoopForIO::current()->PostTask(factory_.NewRunnableMethod( &Channel::ChannelImpl::OnIOCompleted, &input_state_.context, 0, 0)); } diff --git a/ipc/chromium/src/chrome/common/process_watcher_posix_sigchld.cc b/ipc/chromium/src/chrome/common/process_watcher_posix_sigchld.cc index 9e398dcb04..b04ad97867 100644 --- a/ipc/chromium/src/chrome/common/process_watcher_posix_sigchld.cc +++ b/ipc/chromium/src/chrome/common/process_watcher_posix_sigchld.cc @@ -77,7 +77,7 @@ private: // Fear the reaper class ChildGrimReaper : public ChildReaper, - public Task + public mozilla::Runnable { public: explicit ChildGrimReaper(pid_t process) : ChildReaper(process) @@ -91,11 +91,13 @@ public: } // @override - virtual void Run() + NS_IMETHOD Run() { // we may have already been signaled by the time this runs if (process_) KillProcess(); + + return NS_OK; } private: @@ -200,11 +202,11 @@ ProcessWatcher::EnsureProcessTerminated(base::ProcessHandle process, MessageLoopForIO* loop = MessageLoopForIO::current(); if (force) { - ChildGrimReaper* reaper = new ChildGrimReaper(process); + RefPtr reaper = new ChildGrimReaper(process); loop->CatchSignal(SIGCHLD, reaper, reaper); // |loop| takes ownership of |reaper| - loop->PostDelayedTask(FROM_HERE, reaper, kMaxWaitMs); + loop->PostDelayedTask(reaper.forget(), kMaxWaitMs); } else { ChildLaxReaper* reaper = new ChildLaxReaper(process); diff --git a/ipc/chromium/src/chrome/common/process_watcher_win.cc b/ipc/chromium/src/chrome/common/process_watcher_win.cc index 364f83d356..80618193ff 100644 --- a/ipc/chromium/src/chrome/common/process_watcher_win.cc +++ b/ipc/chromium/src/chrome/common/process_watcher_win.cc @@ -14,7 +14,8 @@ static const int kWaitInterval = 2000; namespace { -class TimerExpiredTask : public Task, public base::ObjectWatcher::Delegate { +class TimerExpiredTask : public mozilla::Runnable, + public base::ObjectWatcher::Delegate { public: explicit TimerExpiredTask(base::ProcessHandle process) : process_(process) { watcher_.StartWatching(process_, this); @@ -29,9 +30,10 @@ class TimerExpiredTask : public Task, public base::ObjectWatcher::Delegate { // Task --------------------------------------------------------------------- - virtual void Run() { + NS_IMETHOD Run() override { if (process_) KillProcess(); + return NS_OK; } // MessageLoop::Watcher ----------------------------------------------------- @@ -85,7 +87,8 @@ void ProcessWatcher::EnsureProcessTerminated(base::ProcessHandle process return; } - MessageLoop::current()->PostDelayedTask(FROM_HERE, - new TimerExpiredTask(process), + RefPtr task = new TimerExpiredTask(process); + + MessageLoop::current()->PostDelayedTask(task.forget(), kWaitInterval); } diff --git a/ipc/glue/BackgroundImpl.cpp b/ipc/glue/BackgroundImpl.cpp index 00645a535d..3b7235613f 100644 --- a/ipc/glue/BackgroundImpl.cpp +++ b/ipc/glue/BackgroundImpl.cpp @@ -448,8 +448,10 @@ private: // This class is reference counted. ~ChildImpl() { - XRE_GetIOMessageLoop()->PostTask(FROM_HERE, - new DeleteTask(GetTransport())); + RefPtr> task = + new DeleteTask(GetTransport()); + XRE_GetIOMessageLoop()->PostTask(task.forget()); + AssertActorDestroyed(); } @@ -1287,8 +1289,8 @@ ParentImpl::MainThreadActorDestroy() MOZ_ASSERT_IF(!mIsOtherProcessActor, !mTransport); if (mTransport) { - XRE_GetIOMessageLoop()->PostTask(FROM_HERE, - new DeleteTask(mTransport)); + RefPtr> task = new DeleteTask(mTransport); + XRE_GetIOMessageLoop()->PostTask(task.forget()); mTransport = nullptr; } diff --git a/ipc/glue/GeckoChildProcessHost.cpp b/ipc/glue/GeckoChildProcessHost.cpp index 9ada6a376a..dce2d30ccd 100644 --- a/ipc/glue/GeckoChildProcessHost.cpp +++ b/ipc/glue/GeckoChildProcessHost.cpp @@ -351,8 +351,7 @@ GeckoChildProcessHost::SyncLaunch(std::vector aExtraOpts, int aTime MessageLoop* ioLoop = XRE_GetIOMessageLoop(); NS_ASSERTION(MessageLoop::current() != ioLoop, "sync launch from the IO thread NYI"); - ioLoop->PostTask(FROM_HERE, - NewRunnableMethod(this, + ioLoop->PostTask(NewRunnableMethod(this, &GeckoChildProcessHost::RunPerformAsyncLaunch, aExtraOpts, arch)); @@ -366,8 +365,7 @@ GeckoChildProcessHost::AsyncLaunch(std::vector aExtraOpts, PrepareLaunch(); MessageLoop* ioLoop = XRE_GetIOMessageLoop(); - ioLoop->PostTask(FROM_HERE, - NewRunnableMethod(this, + ioLoop->PostTask(NewRunnableMethod(this, &GeckoChildProcessHost::RunPerformAsyncLaunch, aExtraOpts, arch)); @@ -425,8 +423,7 @@ GeckoChildProcessHost::LaunchAndWaitForProcessHandle(StringVector aExtraOpts) PrepareLaunch(); MessageLoop* ioLoop = XRE_GetIOMessageLoop(); - ioLoop->PostTask(FROM_HERE, - NewRunnableMethod(this, + ioLoop->PostTask(NewRunnableMethod(this, &GeckoChildProcessHost::RunPerformAsyncLaunch, aExtraOpts, base::GetCurrentProcessArchitecture())); @@ -480,8 +477,7 @@ void DelayedDeleteSubprocess(GeckoChildProcessHost* aSubprocess) { XRE_GetIOMessageLoop() - ->PostTask(FROM_HERE, - new DeleteTask(aSubprocess)); + ->PostTask(mozilla::MakeAndAddRef>(aSubprocess)); } } @@ -491,8 +487,7 @@ GeckoChildProcessHost::DissociateActor() { if (!--mAssociatedActors) { MessageLoop::current()-> - PostTask(FROM_HERE, - NewRunnableFunction(DelayedDeleteSubprocess, this)); + PostTask(NewRunnableFunction(DelayedDeleteSubprocess, this)); } } diff --git a/ipc/glue/MessageChannel.cpp b/ipc/glue/MessageChannel.cpp index 24ca3406c9..e5d8d49e5d 100644 --- a/ipc/glue/MessageChannel.cpp +++ b/ipc/glue/MessageChannel.cpp @@ -694,7 +694,6 @@ MessageChannel::Open(MessageChannel *aTargetChan, MessageLoop *aTargetLoop, Side MonitorAutoLock lock(*mMonitor); mChannelState = ChannelOpening; aTargetLoop->PostTask( - FROM_HERE, NewRunnableMethod(aTargetChan, &MessageChannel::OnOpenAsSlave, this, oppSide)); while (ChannelOpening == mChannelState) @@ -983,7 +982,8 @@ MessageChannel::OnMessageReceivedFromLink(Message&& aMsg) if (!compress) { // If we compressed away the previous message, we'll re-use // its pending task. - mWorkerLoop->PostTask(FROM_HERE, new DequeueTask(mDequeueOneTask)); + RefPtr task = new DequeueTask(mDequeueOneTask); + mWorkerLoop->PostTask(task.forget()); } } } @@ -1805,14 +1805,16 @@ MessageChannel::EnqueuePendingMessages() MaybeUndeferIncall(); for (size_t i = 0; i < mDeferred.size(); ++i) { - mWorkerLoop->PostTask(FROM_HERE, new DequeueTask(mDequeueOneTask)); + RefPtr task = new DequeueTask(mDequeueOneTask); + mWorkerLoop->PostTask(task.forget()); } // XXX performance tuning knob: could process all or k pending // messages here, rather than enqueuing for later processing for (size_t i = 0; i < mPending.size(); ++i) { - mWorkerLoop->PostTask(FROM_HERE, new DequeueTask(mDequeueOneTask)); + RefPtr task = new DequeueTask(mDequeueOneTask); + mWorkerLoop->PostTask(task.forget()); } } @@ -1920,7 +1922,8 @@ MessageChannel::OnChannelConnected(int32_t peer_id) MOZ_RELEASE_ASSERT(!mPeerPidSet); mPeerPidSet = true; mPeerPid = peer_id; - mWorkerLoop->PostTask(FROM_HERE, new DequeueTask(mOnChannelConnectedTask)); + RefPtr task = new DequeueTask(mOnChannelConnectedTask); + mWorkerLoop->PostTask(task.forget()); } void @@ -2089,8 +2092,9 @@ MessageChannel::OnNotifyMaybeChannelError() if (IsOnCxxStack()) { mChannelErrorTask = NewRunnableMethod(this, &MessageChannel::OnNotifyMaybeChannelError); + RefPtr task = mChannelErrorTask; // 10 ms delay is completely arbitrary - mWorkerLoop->PostDelayedTask(FROM_HERE, mChannelErrorTask, 10); + mWorkerLoop->PostDelayedTask(task.forget(), 10); return; } @@ -2108,7 +2112,8 @@ MessageChannel::PostErrorNotifyTask() // This must be the last code that runs on this thread! mChannelErrorTask = NewRunnableMethod(this, &MessageChannel::OnNotifyMaybeChannelError); - mWorkerLoop->PostTask(FROM_HERE, mChannelErrorTask); + RefPtr task = mChannelErrorTask; + mWorkerLoop->PostTask(task.forget()); } // Special async message. @@ -2303,7 +2308,8 @@ MessageChannel::EndTimeout() // OnMaybeDequeueOne. But during the timeout, that function will skip // some messages. Now they're ready to be processed, so we enqueue more // tasks. - mWorkerLoop->PostTask(FROM_HERE, new DequeueTask(mDequeueOneTask)); + RefPtr task = new DequeueTask(mDequeueOneTask); + mWorkerLoop->PostTask(task.forget()); } } diff --git a/ipc/glue/MessageChannel.h b/ipc/glue/MessageChannel.h index 5f0aa6bbed..d73a0c28fc 100644 --- a/ipc/glue/MessageChannel.h +++ b/ipc/glue/MessageChannel.h @@ -461,16 +461,17 @@ class MessageChannel : HasResultCodes typedef std::deque MessageQueue; typedef std::map MessageMap; + // XXXkhuey this can almost certainly die. // All dequeuing tasks require a single point of cancellation, // which is handled via a reference-counted task. class RefCountedTask { public: - explicit RefCountedTask(CancelableTask* aTask) + explicit RefCountedTask(already_AddRefed aTask) : mTask(aTask) { } private: - ~RefCountedTask() { delete mTask; } + ~RefCountedTask() { } public: void Run() { mTask->Run(); } void Cancel() { mTask->Cancel(); } @@ -478,18 +479,21 @@ class MessageChannel : HasResultCodes NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefCountedTask) private: - CancelableTask* mTask; + RefPtr mTask; }; // Wrap an existing task which can be cancelled at any time // without the wrapper's knowledge. - class DequeueTask : public Task + class DequeueTask : public Runnable { public: explicit DequeueTask(RefCountedTask* aTask) : mTask(aTask) { } - void Run() override { mTask->Run(); } + NS_IMETHOD Run() override { + mTask->Run(); + return NS_OK; + } private: RefPtr mTask; @@ -502,7 +506,7 @@ class MessageChannel : HasResultCodes Side mSide; MessageLink* mLink; MessageLoop* mWorkerLoop; // thread where work is done - CancelableTask* mChannelErrorTask; // NotifyMaybeChannelError runnable + RefPtr mChannelErrorTask; // NotifyMaybeChannelError runnable // id() of mWorkerLoop. This persists even after mWorkerLoop is cleared // during channel shutdown. diff --git a/ipc/glue/MessageLink.cpp b/ipc/glue/MessageLink.cpp index eb8f9a17f6..2288854615 100644 --- a/ipc/glue/MessageLink.cpp +++ b/ipc/glue/MessageLink.cpp @@ -132,14 +132,12 @@ ProcessLink::Open(mozilla::ipc::Transport* aTransport, MessageLoop *aIOLoop, Sid // we start polling our pipe and processing outgoing // messages. mIOLoop->PostTask( - FROM_HERE, NewRunnableMethod(this, &ProcessLink::OnChannelOpened)); } else { // Transport::Connect() has already been called. Take // over the channel from the previous listener and process // any queued messages. mIOLoop->PostTask( - FROM_HERE, NewRunnableMethod(this, &ProcessLink::OnTakeConnectedChannel)); } @@ -168,7 +166,6 @@ ProcessLink::EchoMessage(Message *msg) mChan->mMonitor->AssertCurrentThreadOwns(); mIOLoop->PostTask( - FROM_HERE, NewRunnableMethod(this, &ProcessLink::OnEchoMessage, msg)); // OnEchoMessage takes ownership of |msg| } @@ -216,7 +213,6 @@ ProcessLink::SendMessage(Message *msg) #endif mIOLoop->PostTask( - FROM_HERE, NewRunnableMethod(mTransport, &Transport::Send, msg)); } @@ -226,8 +222,7 @@ ProcessLink::SendClose() mChan->AssertWorkerThread(); mChan->mMonitor->AssertCurrentThreadOwns(); - mIOLoop->PostTask( - FROM_HERE, NewRunnableMethod(this, &ProcessLink::OnCloseChannel)); + mIOLoop->PostTask(NewRunnableMethod(this, &ProcessLink::OnCloseChannel)); } ThreadLink::ThreadLink(MessageChannel *aChan, MessageChannel *aTargetChan) diff --git a/js/xpconnect/src/XPCMaps.h b/js/xpconnect/src/XPCMaps.h index 1272ceb4dc..66a64b46ad 100644 --- a/js/xpconnect/src/XPCMaps.h +++ b/js/xpconnect/src/XPCMaps.h @@ -465,7 +465,10 @@ public: inline nsIXPCFunctionThisTranslator* Find(REFNSIID iid) { auto entry = static_cast(mTable.Search(&iid)); - return entry ? entry->value : nullptr; + if (!entry) { + return nullptr; + } + return entry->value; } inline nsIXPCFunctionThisTranslator* Add(REFNSIID iid, diff --git a/js/xpconnect/src/XPCVariant.cpp b/js/xpconnect/src/XPCVariant.cpp index 32b605ed9b..a70f26505e 100644 --- a/js/xpconnect/src/XPCVariant.cpp +++ b/js/xpconnect/src/XPCVariant.cpp @@ -262,17 +262,27 @@ bool XPCVariant::InitializeData(JSContext* cx) RootedValue val(cx, GetJSVal()); - if (val.isInt32()) - return NS_SUCCEEDED(mData.SetFromInt32(val.toInt32())); - if (val.isDouble()) - return NS_SUCCEEDED(mData.SetFromDouble(val.toDouble())); - if (val.isBoolean()) - return NS_SUCCEEDED(mData.SetFromBool(val.toBoolean())); + if (val.isInt32()) { + mData.SetFromInt32(val.toInt32()); + return true; + } + if (val.isDouble()) { + mData.SetFromDouble(val.toDouble()); + return true; + } + if (val.isBoolean()) { + mData.SetFromBool(val.toBoolean()); + return true; + } // We can't represent symbol on C++ side, so pretend it is void. - if (val.isUndefined() || val.isSymbol()) - return NS_SUCCEEDED(mData.SetToVoid()); - if (val.isNull()) - return NS_SUCCEEDED(mData.SetToEmpty()); + if (val.isUndefined() || val.isSymbol()) { + mData.SetToVoid(); + return true; + } + if (val.isNull()) { + mData.SetToEmpty(); + return true; + } if (val.isString()) { JSString* str = val.toString(); if (!str) @@ -282,8 +292,7 @@ bool XPCVariant::InitializeData(JSContext* cx) "Why do we already have data?"); size_t length = JS_GetStringLength(str); - if (!NS_SUCCEEDED(mData.AllocateWStringWithSize(length))) - return false; + mData.AllocateWStringWithSize(length); mozilla::Range destChars(mData.u.wstr.mWStringValue, length); if (!JS_CopyStringChars(cx, destChars, str)) @@ -301,8 +310,10 @@ bool XPCVariant::InitializeData(JSContext* cx) // Let's see if it is a xpcJSID. const nsID* id = xpc_JSObjectToID(cx, jsobj); - if (id) - return NS_SUCCEEDED(mData.SetFromID(*id)); + if (id) { + mData.SetFromID(*id); + return true; + } // Let's see if it is a js array object. @@ -347,9 +358,12 @@ bool XPCVariant::InitializeData(JSContext* cx) nsCOMPtr wrapper; const nsIID& iid = NS_GET_IID(nsISupports); - return NS_SUCCEEDED(xpc->WrapJS(cx, jsobj, - iid, getter_AddRefs(wrapper))) && - NS_SUCCEEDED(mData.SetFromInterface(iid, wrapper)); + if (NS_FAILED(xpc->WrapJS(cx, jsobj, iid, getter_AddRefs(wrapper)))) { + return false; + } + + mData.SetFromInterface(iid, wrapper); + return true; } NS_IMETHODIMP diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index 1410a5861d..6ae5f98f31 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -1388,7 +1388,8 @@ AttachContainerRecurse(nsIDocShell* aShell) viewer->GetPresContext(getter_AddRefs(pc)); if (pc) { pc->SetContainer(static_cast(aShell)); - pc->SetLinkHandler(nsCOMPtr(do_QueryInterface(aShell))); + nsCOMPtr handler = do_QueryInterface(aShell); + pc->SetLinkHandler(handler); } nsCOMPtr presShell; viewer->GetPresShell(getter_AddRefs(presShell)); @@ -1403,7 +1404,8 @@ AttachContainerRecurse(nsIDocShell* aShell) for (int32_t i = 0; i < childCount; ++i) { nsCOMPtr childItem; aShell->GetChildAt(i, getter_AddRefs(childItem)); - AttachContainerRecurse(nsCOMPtr(do_QueryInterface(childItem))); + nsCOMPtr shell = do_QueryInterface(childItem); + AttachContainerRecurse(shell); } } @@ -1431,7 +1433,8 @@ nsDocumentViewer::Open(nsISupports *aState, nsISHEntry *aSHEntry) int32_t itemIndex = 0; while (NS_SUCCEEDED(aSHEntry->ChildShellAt(itemIndex++, getter_AddRefs(item))) && item) { - AttachContainerRecurse(nsCOMPtr(do_QueryInterface(item))); + nsCOMPtr shell = do_QueryInterface(item); + AttachContainerRecurse(shell); } } @@ -1560,7 +1563,8 @@ DetachContainerRecurse(nsIDocShell *aShell) for (int32_t i = 0; i < childCount; ++i) { nsCOMPtr childItem; aShell->GetChildAt(i, getter_AddRefs(childItem)); - DetachContainerRecurse(nsCOMPtr(do_QueryInterface(childItem))); + nsCOMPtr shell = do_QueryInterface(childItem); + DetachContainerRecurse(shell); } } @@ -1676,7 +1680,8 @@ nsDocumentViewer::Destroy() int32_t itemIndex = 0; while (NS_SUCCEEDED(shEntry->ChildShellAt(itemIndex++, getter_AddRefs(item))) && item) { - DetachContainerRecurse(nsCOMPtr(do_QueryInterface(item))); + nsCOMPtr shell = do_QueryInterface(item); + DetachContainerRecurse(shell); } return NS_OK; diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index ed727b7c7a..029fed7ccd 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -6451,7 +6451,8 @@ nsIPresShell::SetPointerCapturingContent(uint32_t aPointerId, nsIContent* aConte { PointerCaptureInfo* pointerCaptureInfo = nullptr; gPointerCaptureList->Get(aPointerId, &pointerCaptureInfo); - nsIContent* content = pointerCaptureInfo ? pointerCaptureInfo->mOverrideContent : nullptr; + nsIContent* content = pointerCaptureInfo ? + pointerCaptureInfo->mOverrideContent.get() : nullptr; if (!content && (nsIDOMMouseEvent::MOZ_SOURCE_MOUSE == GetPointerType(aPointerId))) { SetCapturingContent(aContent, CAPTURE_PREVENTDRAG); diff --git a/layout/build/nsLayoutStatics.cpp b/layout/build/nsLayoutStatics.cpp index 568e2ad5fb..94ec289339 100644 --- a/layout/build/nsLayoutStatics.cpp +++ b/layout/build/nsLayoutStatics.cpp @@ -66,7 +66,6 @@ #include "ActiveLayerTracker.h" #include "CounterStyleManager.h" #include "FrameLayerBuilder.h" -#include "mozilla/dom/RequestSyncWifiService.h" #include "AnimationCommon.h" #include "LayerAnimationInfo.h" @@ -304,10 +303,6 @@ nsLayoutStatics::Initialize() ServiceWorkerRegistrar::Initialize(); -#ifdef MOZ_B2G - RequestSyncWifiService::Init(); -#endif - #ifdef DEBUG nsStyleContext::Initialize(); mozilla::LayerAnimationInfo::Initialize(); diff --git a/layout/generic/nsPluginFrame.h b/layout/generic/nsPluginFrame.h index 660f37280a..7dacc82182 100644 --- a/layout/generic/nsPluginFrame.h +++ b/layout/generic/nsPluginFrame.h @@ -191,7 +191,12 @@ public: */ static void EndSwapDocShells(nsISupports* aSupports, void*); - nsIWidget* GetWidget() override { return mInnerView ? mWidget : nullptr; } + nsIWidget* GetWidget() override { + if (!mInnerView) { + return nullptr; + } + return mWidget; + } /** * Adjust the plugin's idea of its size, using aSize as its new size. diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index 7e1ffec1bd..871a52e106 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -2395,7 +2395,7 @@ BuildTextRunsScanner::SetupBreakSinksForTextRun(gfxTextRun* aTextRun, // We should only use a language for hyphenation if it was specified // explicitly. nsIAtom* hyphenationLanguage = - styleFont->mExplicitLanguage ? styleFont->mLanguage : nullptr; + styleFont->mExplicitLanguage ? styleFont->mLanguage.get() : nullptr; // We keep this pointed at the skip-chars data for the current mappedFlow. // This lets us cheaply check whether the flow has compressed initial // whitespace... diff --git a/layout/generic/nsTextRunTransformations.cpp b/layout/generic/nsTextRunTransformations.cpp index 2f3b4757fc..3080301123 100644 --- a/layout/generic/nsTextRunTransformations.cpp +++ b/layout/generic/nsTextRunTransformations.cpp @@ -322,7 +322,7 @@ nsCaseTransformTextRunFactory::TransformString( forceNonFullWidth = charStyle->mForceNonFullWidth; nsIAtom* newLang = charStyle->mExplicitLanguage - ? charStyle->mLanguage : nullptr; + ? charStyle->mLanguage.get() : nullptr; if (lang != newLang) { lang = newLang; languageSpecificCasing = GetCasingFor(lang); diff --git a/layout/inspector/inDOMUtils.cpp b/layout/inspector/inDOMUtils.cpp index b12882d6f1..e22d12e78c 100644 --- a/layout/inspector/inDOMUtils.cpp +++ b/layout/inspector/inDOMUtils.cpp @@ -245,8 +245,10 @@ inDOMUtils::GetCSSStyleRules(nsIDOMElement *aElement, } nsCOMPtr rules; - NS_NewISupportsArray(getter_AddRefs(rules)); - if (!rules) return NS_ERROR_OUT_OF_MEMORY; + nsresult rv = NS_NewISupportsArray(getter_AddRefs(rules)); + if (NS_FAILED(rv)) { + return NS_ERROR_OUT_OF_MEMORY; + } for ( ; !ruleNode->IsRoot(); ruleNode = ruleNode->GetParent()) { RefPtr decl = do_QueryObject(ruleNode->GetRule()); diff --git a/layout/style/CSS.cpp b/layout/style/CSS.cpp index 55a426de39..49cb267a83 100644 --- a/layout/style/CSS.cpp +++ b/layout/style/CSS.cpp @@ -39,8 +39,8 @@ GetParsingInfo(const GlobalObject& aGlobal, return NS_ERROR_FAILURE; } - aInfo.mDocURI = nsCOMPtr(doc->GetDocumentURI()); - aInfo.mBaseURI = nsCOMPtr(doc->GetBaseURI()); + aInfo.mDocURI = nsCOMPtr(doc->GetDocumentURI()).get(); + aInfo.mBaseURI = nsCOMPtr(doc->GetBaseURI()).get(); aInfo.mPrincipal = win->GetPrincipal(); return NS_OK; } diff --git a/media/mtransport/test/mtransport_test_utils.h b/media/mtransport/test/mtransport_test_utils.h index 5ae620c1e5..81c16ff837 100644 --- a/media/mtransport/test/mtransport_test_utils.h +++ b/media/mtransport/test/mtransport_test_utils.h @@ -33,7 +33,7 @@ class MtransportTestUtils { MOZ_ASSERT(NS_SUCCEEDED(rv)); } - nsCOMPtr sts_target() { return sts_target_; } + nsIEventTarget* sts_target() { return sts_target_; } private: nsCOMPtr sts_target_; diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h index 63de8cd370..c33ea3809c 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h @@ -330,7 +330,7 @@ public: } // Get the STS thread - nsCOMPtr GetSTSThread() { + nsIEventTarget* GetSTSThread() { PC_AUTO_ENTER_API_CALL_NO_CHECK(); return mSTSThread; } diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 8ba299db95..7440bc3bfb 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -5453,9 +5453,6 @@ pref("browser.addon-watch.ignore", "[\"mochikit@mozilla.org\",\"special-powers@m // the percentage of time addons are allowed to use without being labeled slow pref("browser.addon-watch.percentage-limit", 5); -// RequestSync API is disabled by default. -pref("dom.requestSync.enabled", false); - // Search service settings pref("browser.search.log", false); pref("browser.search.update", true); diff --git a/netwerk/test/moz.build b/netwerk/test/moz.build index dabd8fb240..b58a321bae 100644 --- a/netwerk/test/moz.build +++ b/netwerk/test/moz.build @@ -55,6 +55,11 @@ RESOURCE_FILES += [ USE_LIBS += ['static:js'] +if CONFIG['ENABLE_INTL_API'] and CONFIG['MOZ_ICU_DATA_ARCHIVE']: + # The ICU libraries linked into libmozjs will not include the ICU data, + # so link it directly. + USE_LIBS += ['icudata'] + CXXFLAGS += CONFIG['TK_CFLAGS'] include('/ipc/chromium/chromium-config.mozbuild') diff --git a/toolkit/xre/nsEmbedFunctions.cpp b/toolkit/xre/nsEmbedFunctions.cpp index 57475bac97..1416f3b038 100644 --- a/toolkit/xre/nsEmbedFunctions.cpp +++ b/toolkit/xre/nsEmbedFunctions.cpp @@ -792,7 +792,8 @@ XRE_RunAppShell() bool couldNest = loop->NestableTasksAllowed(); loop->SetNestableTasksAllowed(true); - loop->PostTask(FROM_HERE, new MessageLoop::QuitTask()); + RefPtr task = new MessageLoop::QuitTask(); + loop->PostTask(task.forget()); loop->Run(); loop->SetNestableTasksAllowed(couldNest); diff --git a/widget/nsBaseWidget.cpp b/widget/nsBaseWidget.cpp index 63c70a883c..f6ec839ab1 100644 --- a/widget/nsBaseWidget.cpp +++ b/widget/nsBaseWidget.cpp @@ -1104,7 +1104,7 @@ nsBaseWidget::ProcessUntransformedAPZEvent(WidgetInputEvent* aEvent, return status; } -class DispatchWheelEventOnMainThread : public Task +class DispatchWheelEventOnMainThread : public Runnable { public: DispatchWheelEventOnMainThread(const ScrollWheelInput& aWheelInput, @@ -1120,11 +1120,11 @@ public: { } - void Run() + NS_IMETHOD Run() override { WidgetWheelEvent wheelEvent = mWheelInput.ToWidgetWheelEvent(mWidget); mWidget->ProcessUntransformedAPZEvent(&wheelEvent, mGuid, mInputBlockId, mAPZResult); - return; + return NS_OK; } private: @@ -1135,7 +1135,7 @@ private: ScrollableLayerGuid mGuid; }; -class DispatchWheelInputOnControllerThread : public Task +class DispatchWheelInputOnControllerThread : public Runnable { public: DispatchWheelInputOnControllerThread(const WidgetWheelEvent& aWheelEvent, @@ -1149,15 +1149,15 @@ public: { } - void Run() + NS_IMETHOD Run() override { mAPZResult = mAPZC->ReceiveInputEvent(mWheelInput, &mGuid, &mInputBlockId); if (mAPZResult == nsEventStatus_eConsumeNoDefault) { - return; + return NS_OK; } - mMainMessageLoop->PostTask(FROM_HERE, - new DispatchWheelEventOnMainThread(mWheelInput, mWidget, mAPZResult, mInputBlockId, mGuid)); - return; + RefPtr r = new DispatchWheelEventOnMainThread(mWheelInput, mWidget, mAPZResult, mInputBlockId, mGuid); + mMainMessageLoop->PostTask(r.forget()); + return NS_OK; } private: @@ -1187,7 +1187,8 @@ nsBaseWidget::DispatchInputEvent(WidgetInputEvent* aEvent) } else { WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent(); if (wheelEvent) { - APZThreadUtils::RunOnControllerThread(new DispatchWheelInputOnControllerThread(*wheelEvent, mAPZC, this)); + RefPtr r = new DispatchWheelInputOnControllerThread(*wheelEvent, mAPZC, this); + APZThreadUtils::RunOnControllerThread(r.forget()); return nsEventStatus_eConsumeDoDefault; } MOZ_CRASH(); diff --git a/xpcom/base/CycleCollectedJSRuntime.cpp b/xpcom/base/CycleCollectedJSRuntime.cpp index 950f37b5cf..434d8bcbd4 100644 --- a/xpcom/base/CycleCollectedJSRuntime.cpp +++ b/xpcom/base/CycleCollectedJSRuntime.cpp @@ -468,6 +468,9 @@ CycleCollectedJSRuntime::~CycleCollectedJSRuntime() // Clear mPendingException first, since it might be cycle collected. mPendingException = nullptr; + MOZ_ASSERT(mDebuggerPromiseMicroTaskQueue.empty()); + MOZ_ASSERT(mPromiseMicroTaskQueue.empty()); + JS_DestroyRuntime(mJSRuntime); mJSRuntime = nullptr; nsCycleCollector_forgetJSRuntime(); diff --git a/xpcom/base/OwningNonNull.h b/xpcom/base/OwningNonNull.h index 3c9ed0636b..45143faf5c 100644 --- a/xpcom/base/OwningNonNull.h +++ b/xpcom/base/OwningNonNull.h @@ -31,6 +31,12 @@ public: init(aValue); } + template + MOZ_IMPLICIT OwningNonNull(const OwningNonNull& aValue) + { + init(aValue); + } + // This is no worse than get() in terms of const handling. operator T&() const { @@ -71,8 +77,17 @@ public: return *this; } + template OwningNonNull& - operator=(already_AddRefed&& aValue) + operator=(already_AddRefed&& aValue) + { + init(aValue); + return *this; + } + + template + OwningNonNull& + operator=(const OwningNonNull& aValue) { init(aValue); return *this; @@ -89,6 +104,16 @@ public: return mPtr.forget(); } + template + void + forget(U** aOther) + { +#ifdef DEBUG + mInited = false; +#endif + mPtr.forget(aOther); + } + // Make us work with smart pointer helpers that expect a get(). T* get() const { diff --git a/xpcom/base/nsDumpUtils.cpp b/xpcom/base/nsDumpUtils.cpp index 160a1df61a..b9d9eb4f5c 100644 --- a/xpcom/base/nsDumpUtils.cpp +++ b/xpcom/base/nsDumpUtils.cpp @@ -75,7 +75,6 @@ FdWatcher::Init() os->AddObserver(this, "xpcom-shutdown", /* ownsWeak = */ false); XRE_GetIOMessageLoop()->PostTask( - FROM_HERE, NewRunnableMethod(this, &FdWatcher::StartWatching)); } diff --git a/xpcom/base/nsDumpUtils.h b/xpcom/base/nsDumpUtils.h index 56c58f7eec..46951f59f8 100644 --- a/xpcom/base/nsDumpUtils.h +++ b/xpcom/base/nsDumpUtils.h @@ -90,7 +90,6 @@ public: MOZ_ASSERT(!strcmp(aTopic, "xpcom-shutdown")); XRE_GetIOMessageLoop()->PostTask( - FROM_HERE, NewRunnableMethod(this, &FdWatcher::StopWatching)); return NS_OK; diff --git a/xpcom/base/nsMessageLoop.cpp b/xpcom/base/nsMessageLoop.cpp index ad4fb68bef..a725ead823 100644 --- a/xpcom/base/nsMessageLoop.cpp +++ b/xpcom/base/nsMessageLoop.cpp @@ -28,13 +28,13 @@ namespace { * Run(). Tread lightly. */ class MessageLoopIdleTask - : public Task + : public Runnable , public SupportsWeakPtr { public: MOZ_DECLARE_WEAKREFERENCE_TYPENAME(MessageLoopIdleTask) MessageLoopIdleTask(nsIRunnable* aTask, uint32_t aEnsureRunsAfterMS); - virtual void Run(); + NS_IMETHOD Run() override; private: nsresult Init(uint32_t aEnsureRunsAfterMS); @@ -102,7 +102,7 @@ MessageLoopIdleTask::Init(uint32_t aEnsureRunsAfterMS) nsITimer::TYPE_ONE_SHOT); } -/* virtual */ void +NS_IMETHODIMP MessageLoopIdleTask::Run() { // Null out our pointers because if Run() was called by the timer, this @@ -118,6 +118,8 @@ MessageLoopIdleTask::Run() mTask->Run(); mTask = nullptr; } + + return NS_OK; } MessageLoopTimerCallback::MessageLoopTimerCallback(MessageLoopIdleTask* aTask) @@ -150,8 +152,10 @@ nsMessageLoop::PostIdleTask(nsIRunnable* aTask, uint32_t aEnsureRunsAfterMS) { // The message loop owns MessageLoopIdleTask and deletes it after calling // Run(). Be careful... - MessageLoop::current()->PostIdleTask(FROM_HERE, - new MessageLoopIdleTask(aTask, aEnsureRunsAfterMS)); + RefPtr idle = + new MessageLoopIdleTask(aTask, aEnsureRunsAfterMS); + MessageLoop::current()->PostIdleTask(idle.forget()); + return NS_OK; } diff --git a/xpcom/base/nsWindowsHelpers.h b/xpcom/base/nsWindowsHelpers.h index 552e74f474..66505b3458 100644 --- a/xpcom/base/nsWindowsHelpers.h +++ b/xpcom/base/nsWindowsHelpers.h @@ -10,6 +10,7 @@ #include #include "nsAutoRef.h" #include "nscore.h" +#include "mozilla/Assertions.h" // ---------------------------------------------------------------------------- // Critical Section helper class @@ -211,6 +212,91 @@ public: } }; + +// HGLOBAL is just a typedef of HANDLE which nsSimpleRef has a specialization of, +// that means having a nsAutoRefTraits specialization for HGLOBAL is useless. +// Therefore we create a wrapper class for HGLOBAL to make nsAutoRefTraits and +// nsAutoRef work as intention. +class nsHGLOBAL { +public: + nsHGLOBAL(HGLOBAL hGlobal) : m_hGlobal(hGlobal) + { + } + + operator HGLOBAL() const + { + return m_hGlobal; + } + +private: + HGLOBAL m_hGlobal; +}; + + +template<> +class nsAutoRefTraits +{ +public: + typedef nsHGLOBAL RawRef; + static RawRef Void() + { + return nullptr; + } + + static void Release(RawRef hGlobal) + { + ::GlobalFree(hGlobal); + } +}; + + +// Because Printer's HANDLE uses ClosePrinter and we already have nsAutoRef +// which uses CloseHandle so we need to create a wrapper class for HANDLE to have +// another specialization for nsAutoRefTraits. +class nsHPRINTER { +public: + nsHPRINTER(HANDLE hPrinter) : m_hPrinter(hPrinter) + { + } + + operator HANDLE() const + { + return m_hPrinter; + } + + HANDLE* operator&() + { + return &m_hPrinter; + } + +private: + HANDLE m_hPrinter; +}; + + +// winspool.h header has AddMonitor macro, it conflicts with AddMonitor member +// function in TaskbarPreview.cpp and TaskbarTabPreview.cpp. Beside, we only +// need ClosePrinter here for Release function, so having its prototype is enough. +extern "C" BOOL WINAPI ClosePrinter(HANDLE hPrinter); + + +template<> +class nsAutoRefTraits +{ +public: + typedef nsHPRINTER RawRef; + static RawRef Void() + { + return nullptr; + } + + static void Release(RawRef hPrinter) + { + ::ClosePrinter(hPrinter); + } +}; + + typedef nsAutoRef nsAutoRegKey; typedef nsAutoRef nsAutoHDC; typedef nsAutoRef nsAutoBrush; @@ -220,33 +306,62 @@ typedef nsAutoRef nsAutoServiceHandle; typedef nsAutoRef nsAutoHandle; typedef nsAutoRef nsModuleHandle; typedef nsAutoRef nsAutoDevMode; +typedef nsAutoRef nsAutoGlobalMem; +typedef nsAutoRef nsAutoPrinter; namespace { +// Construct a path "\". return false if the output buffer +// is too small. +// Note: If the system path cannot be found, or doesn't fit in the output buffer +// with the module name, we will just ignore the system path and output the +// module name alone; +// this may mean using a normal search path wherever the output is used. +bool inline +ConstructSystem32Path(LPCWSTR aModule, WCHAR* aSystemPath, UINT aSize) +{ + MOZ_ASSERT(aSystemPath); + + size_t fileLen = wcslen(aModule); + if (fileLen >= aSize) { + // The module name alone cannot even fit! + return false; + } + + size_t systemDirLen = GetSystemDirectoryW(aSystemPath, aSize); + + if (systemDirLen) { + if (systemDirLen < aSize - fileLen) { + // Make the system directory path terminate with a slash. + if (aSystemPath[systemDirLen - 1] != L'\\') { + if (systemDirLen + 1 < aSize - fileLen) { + aSystemPath[systemDirLen] = L'\\'; + ++systemDirLen; + // No need to re-nullptr terminate. + } else { + // Couldn't fit the system path with added slash. + systemDirLen = 0; + } + } + } else { + // Couldn't fit the system path. + systemDirLen = 0; + } + } + + MOZ_ASSERT(systemDirLen + fileLen < aSize); + + wcsncpy(aSystemPath + systemDirLen, aModule, fileLen); + aSystemPath[systemDirLen + fileLen] = L'\0'; + return true; +} + HMODULE inline LoadLibrarySystem32(LPCWSTR aModule) { - WCHAR systemPath[MAX_PATH + 1] = { L'\0' }; - - // If GetSystemPath fails we accept that we'll load the DLLs from the - // normal search path. - GetSystemDirectoryW(systemPath, MAX_PATH + 1); - size_t systemDirLen = wcslen(systemPath); - - // Make the system directory path terminate with a slash - if (systemDirLen && systemPath[systemDirLen - 1] != L'\\') { - systemPath[systemDirLen] = L'\\'; - ++systemDirLen; - // No need to re-nullptr terminate - } - - size_t fileLen = wcslen(aModule); - wcsncpy(systemPath + systemDirLen, aModule, - MAX_PATH - systemDirLen); - if (systemDirLen + fileLen <= MAX_PATH) { - systemPath[systemDirLen + fileLen] = L'\0'; - } else { - systemPath[MAX_PATH] = L'\0'; + WCHAR systemPath[MAX_PATH + 1]; + if (!ConstructSystem32Path(aModule, systemPath, MAX_PATH + 1)) { + return NULL; } return LoadLibraryW(systemPath); } diff --git a/xpcom/build/XPCOMInit.cpp b/xpcom/build/XPCOMInit.cpp index cf1dc9126d..86bcbafadb 100644 --- a/xpcom/build/XPCOMInit.cpp +++ b/xpcom/build/XPCOMInit.cpp @@ -186,23 +186,23 @@ extern nsresult CreateAnonTempFileRemover(); NS_GENERIC_FACTORY_CONSTRUCTOR(nsProcess) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsIDImpl) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsStringImpl) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsCStringImpl) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRBoolImpl) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRUint8Impl) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRUint16Impl) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRUint32Impl) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRUint64Impl) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRTimeImpl) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsCharImpl) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRInt16Impl) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRInt32Impl) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRInt64Impl) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsFloatImpl) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsDoubleImpl) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsVoidImpl) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsInterfacePointerImpl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsID) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsString) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsCString) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRBool) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRUint8) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRUint16) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRUint32) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRUint64) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRTime) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsChar) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRInt16) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRInt32) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRInt64) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsFloat) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsDouble) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsVoid) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsInterfacePointer) NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsConsoleService, Init) NS_GENERIC_FACTORY_CONSTRUCTOR(nsAtomService) diff --git a/xpcom/build/XPCOMModule.inc b/xpcom/build/XPCOMModule.inc index 52d7497dfa..205e30d577 100644 --- a/xpcom/build/XPCOMModule.inc +++ b/xpcom/build/XPCOMModule.inc @@ -25,7 +25,7 @@ COMPONENT(TIMER, nsTimerImplConstructor) #define COMPONENT_SUPPORTS(TYPE, Type) \ - COMPONENT(SUPPORTS_##TYPE, nsSupports##Type##ImplConstructor) + COMPONENT(SUPPORTS_##TYPE, nsSupports##Type##Constructor) COMPONENT_SUPPORTS(ID, ID) COMPONENT_SUPPORTS(STRING, String) diff --git a/xpcom/components/nsComponentManager.cpp b/xpcom/components/nsComponentManager.cpp index 2b536c0fef..031fe0ec5f 100644 --- a/xpcom/components/nsComponentManager.cpp +++ b/xpcom/components/nsComponentManager.cpp @@ -1744,7 +1744,7 @@ nsComponentManagerImpl::EnumerateCIDs(nsISimpleEnumerator** aEnumerator) nsCOMArray array; for (auto iter = mFactories.Iter(); !iter.Done(); iter.Next()) { const nsID& id = iter.Key(); - nsCOMPtr wrapper = new nsSupportsIDImpl(); + nsCOMPtr wrapper = new nsSupportsID(); wrapper->SetData(&id); array.AppendObject(wrapper); } diff --git a/xpcom/ds/Tokenizer.h b/xpcom/ds/Tokenizer.h index 831b96b3fb..0dda3f4563 100644 --- a/xpcom/ds/Tokenizer.h +++ b/xpcom/ds/Tokenizer.h @@ -209,10 +209,11 @@ public: /** * These are shortcuts to obtain the value immediately when the token type matches. */ - bool ReadChar(char* aValue); - bool ReadChar(bool (*aClassifier)(const char aChar), char* aValue); - bool ReadWord(nsACString& aValue); - bool ReadWord(nsDependentCSubstring& aValue); + MOZ_MUST_USE bool ReadChar(char* aValue); + MOZ_MUST_USE bool ReadChar(bool (*aClassifier)(const char aChar), + char* aValue); + MOZ_MUST_USE bool ReadWord(nsACString& aValue); + MOZ_MUST_USE bool ReadWord(nsDependentCSubstring& aValue); /** * This is an integer read helper. It returns false and doesn't move the read @@ -223,7 +224,7 @@ public: * and the cursor is moved forward. */ template - bool ReadInteger(T* aValue) + MOZ_MUST_USE bool ReadInteger(T* aValue) { MOZ_RELEASE_ASSERT(aValue); @@ -299,8 +300,12 @@ public: * Calling Rollback() after ReadUntil() will return the read cursor to the * position it had before ReadUntil was called. */ - bool ReadUntil(Token const& aToken, nsDependentCSubstring& aResult, ClaimInclusion aInclude = EXCLUDE_LAST); - bool ReadUntil(Token const& aToken, nsACString& aResult, ClaimInclusion aInclude = EXCLUDE_LAST); + MOZ_MUST_USE bool + ReadUntil(Token const& aToken, nsDependentCSubstring& aResult, + ClaimInclusion aInclude = EXCLUDE_LAST); + MOZ_MUST_USE bool + ReadUntil(Token const& aToken, nsACString& aResult, + ClaimInclusion aInclude = EXCLUDE_LAST); protected: // false if we have already read the EOF token. diff --git a/xpcom/ds/nsCheapSets.h b/xpcom/ds/nsCheapSets.h index 1401bc5f1a..d75e60d20a 100644 --- a/xpcom/ds/nsCheapSets.h +++ b/xpcom/ds/nsCheapSets.h @@ -51,7 +51,7 @@ public: mState = ZERO; } - nsresult Put(const KeyType aVal); + void Put(const KeyType aVal); void Remove(const KeyType aVal); @@ -119,14 +119,14 @@ private: }; template -nsresult +void nsCheapSet::Put(const KeyType aVal) { switch (mState) { case ZERO: new (GetSingleEntry()) EntryType(EntryType::KeyToPointer(aVal)); mState = ONE; - return NS_OK; + return; case ONE: { nsTHashtable* table = new nsTHashtable(); EntryType* entry = GetSingleEntry(); @@ -139,10 +139,10 @@ nsCheapSet::Put(const KeyType aVal) case MANY: mUnion.table->PutEntry(aVal); - return NS_OK; + return; default: NS_NOTREACHED("bogus state"); - return NS_OK; + return; } } diff --git a/xpcom/ds/nsISupportsArray.idl b/xpcom/ds/nsISupportsArray.idl index f8b90de7a4..f0fc0e851d 100644 --- a/xpcom/ds/nsISupportsArray.idl +++ b/xpcom/ds/nsISupportsArray.idl @@ -81,7 +81,7 @@ interface nsISupportsArray : nsICollection { %{C++ // Construct and return a default implementation of nsISupportsArray: -extern nsresult +extern MOZ_MUST_USE nsresult NS_NewISupportsArray(nsISupportsArray** aInstancePtrResult); %} diff --git a/xpcom/ds/nsObserverList.cpp b/xpcom/ds/nsObserverList.cpp index e58f79a404..fef8831b8c 100644 --- a/xpcom/ds/nsObserverList.cpp +++ b/xpcom/ds/nsObserverList.cpp @@ -59,12 +59,11 @@ nsObserverList::RemoveObserver(nsIObserver* anObserver) return NS_OK; } -nsresult +void nsObserverList::GetObserverList(nsISimpleEnumerator** anEnumerator) { RefPtr e(new nsObserverEnumerator(this)); e.forget(anEnumerator); - return NS_OK; } void diff --git a/xpcom/ds/nsObserverList.h b/xpcom/ds/nsObserverList.h index c69025a9f9..90a685ea60 100644 --- a/xpcom/ds/nsObserverList.h +++ b/xpcom/ds/nsObserverList.h @@ -56,13 +56,13 @@ public: MOZ_COUNT_DTOR(nsObserverList); } - nsresult AddObserver(nsIObserver* aObserver, bool aOwnsWeak); - nsresult RemoveObserver(nsIObserver* aObserver); + MOZ_MUST_USE nsresult AddObserver(nsIObserver* aObserver, bool aOwnsWeak); + MOZ_MUST_USE nsresult RemoveObserver(nsIObserver* aObserver); void NotifyObservers(nsISupports* aSubject, const char* aTopic, const char16_t* aSomeData); - nsresult GetObserverList(nsISimpleEnumerator** aEnumerator); + void GetObserverList(nsISimpleEnumerator** aEnumerator); // Fill an array with the observers of this category. // The array is filled in last-added-first order. diff --git a/xpcom/ds/nsObserverService.cpp b/xpcom/ds/nsObserverService.cpp index e40aa27fbf..42bcff58be 100644 --- a/xpcom/ds/nsObserverService.cpp +++ b/xpcom/ds/nsObserverService.cpp @@ -283,7 +283,8 @@ nsObserverService::EnumerateObservers(const char* aTopic, return NS_NewEmptyEnumerator(anEnumerator); } - return observerList->GetObserverList(anEnumerator); + observerList->GetObserverList(anEnumerator); + return NS_OK; } // Enumerate observers of aTopic and call Observe on each. diff --git a/xpcom/ds/nsObserverService.h b/xpcom/ds/nsObserverService.h index ccae54e704..fa0d9b9d81 100644 --- a/xpcom/ds/nsObserverService.h +++ b/xpcom/ds/nsObserverService.h @@ -34,8 +34,8 @@ public: void Shutdown(); - static nsresult Create(nsISupports* aOuter, const nsIID& aIID, - void** aInstancePtr); + static MOZ_MUST_USE nsresult Create(nsISupports* aOuter, const nsIID& aIID, + void** aInstancePtr); // Unmark any strongly held observers implemented in JS so the cycle // collector will not traverse them. diff --git a/xpcom/ds/nsPersistentProperties.h b/xpcom/ds/nsPersistentProperties.h index c11a676e7a..f9fe037ee0 100644 --- a/xpcom/ds/nsPersistentProperties.h +++ b/xpcom/ds/nsPersistentProperties.h @@ -25,7 +25,8 @@ public: NS_DECL_NSIPROPERTIES NS_DECL_NSIPERSISTENTPROPERTIES - static nsresult Create(nsISupports* aOuter, REFNSIID aIID, void** aResult); + static MOZ_MUST_USE nsresult + Create(nsISupports* aOuter, REFNSIID aIID, void** aResult); private: ~nsPersistentProperties(); diff --git a/xpcom/ds/nsStringEnumerator.cpp b/xpcom/ds/nsStringEnumerator.cpp index a6a4d5311f..bdcd53e1a8 100644 --- a/xpcom/ds/nsStringEnumerator.cpp +++ b/xpcom/ds/nsStringEnumerator.cpp @@ -118,7 +118,7 @@ NS_IMETHODIMP nsStringEnumerator::GetNext(nsISupports** aResult) { if (mIsUnicode) { - nsSupportsStringImpl* stringImpl = new nsSupportsStringImpl(); + nsSupportsString* stringImpl = new nsSupportsString(); if (!stringImpl) { return NS_ERROR_OUT_OF_MEMORY; } @@ -126,7 +126,7 @@ nsStringEnumerator::GetNext(nsISupports** aResult) stringImpl->SetData(mArray->ElementAt(mIndex++)); *aResult = stringImpl; } else { - nsSupportsCStringImpl* cstringImpl = new nsSupportsCStringImpl(); + nsSupportsCString* cstringImpl = new nsSupportsCString(); if (!cstringImpl) { return NS_ERROR_OUT_OF_MEMORY; } diff --git a/xpcom/ds/nsStringEnumerator.h b/xpcom/ds/nsStringEnumerator.h index 88f0e64970..226afd7f43 100644 --- a/xpcom/ds/nsStringEnumerator.h +++ b/xpcom/ds/nsStringEnumerator.h @@ -43,15 +43,15 @@ // InternalMethod(enumerator); // NS_RELEASE(enumerator); // -nsresult +MOZ_MUST_USE nsresult NS_NewStringEnumerator(nsIStringEnumerator** aResult, const nsTArray* aArray, nsISupports* aOwner); -nsresult +MOZ_MUST_USE nsresult NS_NewUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, const nsTArray* aArray); -nsresult +MOZ_MUST_USE nsresult NS_NewStringEnumerator(nsIStringEnumerator** aResult, const nsTArray* aArray); @@ -64,11 +64,11 @@ NS_NewStringEnumerator(nsIStringEnumerator** aResult, // nsTArray* array = new nsTArray; // array->AppendString("abcd"); // NS_NewAdoptingStringEnumerator(&result, array); -nsresult +MOZ_MUST_USE nsresult NS_NewAdoptingStringEnumerator(nsIStringEnumerator** aResult, nsTArray* aArray); -nsresult +MOZ_MUST_USE nsresult NS_NewAdoptingUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, nsTArray* aArray); @@ -85,7 +85,7 @@ NS_NewAdoptingUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, // return NS_NewStringEnumerator(aResult, mCategoryList, this); // } // -nsresult +MOZ_MUST_USE nsresult NS_NewUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, const nsTArray* aArray, nsISupports* aOwner); diff --git a/xpcom/ds/nsSupportsArray.cpp b/xpcom/ds/nsSupportsArray.cpp index f20dd614e9..eb75fc33ba 100644 --- a/xpcom/ds/nsSupportsArray.cpp +++ b/xpcom/ds/nsSupportsArray.cpp @@ -602,9 +602,6 @@ NS_IMETHODIMP nsSupportsArray::Enumerate(nsIEnumerator** aResult) { nsSupportsArrayEnumerator* e = new nsSupportsArrayEnumerator(this); - if (!e) { - return NS_ERROR_OUT_OF_MEMORY; - } *aResult = e; NS_ADDREF(e); return NS_OK; diff --git a/xpcom/ds/nsSupportsArray.h b/xpcom/ds/nsSupportsArray.h index 0eb322ff3f..d6b3161cae 100644 --- a/xpcom/ds/nsSupportsArray.h +++ b/xpcom/ds/nsSupportsArray.h @@ -20,7 +20,9 @@ class nsSupportsArray final : public nsISupportsArray public: nsSupportsArray(void); - static nsresult Create(nsISupports* aOuter, REFNSIID aIID, void** aResult); + + static MOZ_MUST_USE nsresult + Create(nsISupports* aOuter, REFNSIID aIID, void** aResult); NS_DECL_THREADSAFE_ISUPPORTS @@ -33,7 +35,8 @@ public: return NS_OK; } NS_IMETHOD GetElementAt(uint32_t aIndex, nsISupports** aResult) override; - NS_IMETHOD QueryElementAt(uint32_t aIndex, const nsIID& aIID, void** aResult) override + MOZ_MUST_USE NS_IMETHOD + QueryElementAt(uint32_t aIndex, const nsIID& aIID, void** aResult) override { if (aIndex < mCount) { nsISupports* element = mArray[aIndex]; @@ -43,18 +46,19 @@ public: } return NS_ERROR_FAILURE; } - NS_IMETHOD SetElementAt(uint32_t aIndex, nsISupports* aValue) override + MOZ_MUST_USE NS_IMETHOD + SetElementAt(uint32_t aIndex, nsISupports* aValue) override { return ReplaceElementAt(aValue, aIndex) ? NS_OK : NS_ERROR_FAILURE; } - NS_IMETHOD AppendElement(nsISupports* aElement) override + MOZ_MUST_USE NS_IMETHOD AppendElement(nsISupports* aElement) override { // XXX Invalid cast of bool to nsresult (bug 778110) return (nsresult)InsertElementAt(aElement, mCount)/* ? NS_OK : NS_ERROR_FAILURE*/; } // XXX this is badly named - should be RemoveFirstElement - NS_IMETHOD RemoveElement(nsISupports* aElement) override; - NS_IMETHOD_(bool) MoveElement(int32_t aFrom, int32_t aTo) override; + MOZ_MUST_USE NS_IMETHOD RemoveElement(nsISupports* aElement) override; + MOZ_MUST_USE NS_IMETHOD_(bool) MoveElement(int32_t aFrom, int32_t aTo) override; NS_IMETHOD Enumerate(nsIEnumerator** aResult) override; NS_IMETHOD Clear(void) override; @@ -85,41 +89,48 @@ public: return NS_OK; } - NS_IMETHOD_(bool) InsertElementAt(nsISupports* aElement, uint32_t aIndex) override; + MOZ_MUST_USE NS_IMETHOD_(bool) + InsertElementAt(nsISupports* aElement, uint32_t aIndex) override; - NS_IMETHOD_(bool) ReplaceElementAt(nsISupports* aElement, uint32_t aIndex) override; + MOZ_MUST_USE NS_IMETHOD_(bool) + ReplaceElementAt(nsISupports* aElement, uint32_t aIndex) override; - NS_IMETHOD_(bool) RemoveElementAt(uint32_t aIndex) override + MOZ_MUST_USE NS_IMETHOD_(bool) + RemoveElementAt(uint32_t aIndex) override { return RemoveElementsAt(aIndex, 1); } - NS_IMETHOD_(bool) RemoveLastElement(const nsISupports* aElement) override; + MOZ_MUST_USE NS_IMETHOD_(bool) + RemoveLastElement(const nsISupports* aElement) override; - NS_IMETHOD DeleteLastElement(nsISupports* aElement) override + MOZ_MUST_USE NS_IMETHOD DeleteLastElement(nsISupports* aElement) override { return (RemoveLastElement(aElement) ? NS_OK : NS_ERROR_FAILURE); } - NS_IMETHOD DeleteElementAt(uint32_t aIndex) override + MOZ_MUST_USE NS_IMETHOD DeleteElementAt(uint32_t aIndex) override { return (RemoveElementAt(aIndex) ? NS_OK : NS_ERROR_FAILURE); } - NS_IMETHOD_(bool) AppendElements(nsISupportsArray* aElements) override + MOZ_MUST_USE NS_IMETHOD_(bool) + AppendElements(nsISupportsArray* aElements) override { return InsertElementsAt(aElements, mCount); } NS_IMETHOD Compact(void) override; - NS_IMETHOD Clone(nsISupportsArray** aResult) override; + MOZ_MUST_USE NS_IMETHOD Clone(nsISupportsArray** aResult) override; - NS_IMETHOD_(bool) InsertElementsAt(nsISupportsArray* aOther, - uint32_t aIndex) override; + MOZ_MUST_USE NS_IMETHOD_(bool) + InsertElementsAt(nsISupportsArray* aOther, uint32_t aIndex) override; - NS_IMETHOD_(bool) RemoveElementsAt(uint32_t aIndex, uint32_t aCount) override; + MOZ_MUST_USE NS_IMETHOD_(bool) + RemoveElementsAt(uint32_t aIndex, uint32_t aCount) override; - NS_IMETHOD_(bool) SizeTo(int32_t aSize) override; + MOZ_MUST_USE NS_IMETHOD_(bool) + SizeTo(int32_t aSize) override; protected: void DeleteArray(void); diff --git a/xpcom/ds/nsSupportsPrimitives.cpp b/xpcom/ds/nsSupportsPrimitives.cpp index a3901a44c5..b93130ad6c 100644 --- a/xpcom/ds/nsSupportsPrimitives.cpp +++ b/xpcom/ds/nsSupportsPrimitives.cpp @@ -27,15 +27,15 @@ DataToString(const char* aFormat, T aData) /***************************************************************************/ -NS_IMPL_ISUPPORTS(nsSupportsIDImpl, nsISupportsID, nsISupportsPrimitive) +NS_IMPL_ISUPPORTS(nsSupportsID, nsISupportsID, nsISupportsPrimitive) -nsSupportsIDImpl::nsSupportsIDImpl() +nsSupportsID::nsSupportsID() : mData(nullptr) { } NS_IMETHODIMP -nsSupportsIDImpl::GetType(uint16_t* aType) +nsSupportsID::GetType(uint16_t* aType) { NS_ASSERTION(aType, "Bad pointer"); *aType = TYPE_ID; @@ -43,7 +43,7 @@ nsSupportsIDImpl::GetType(uint16_t* aType) } NS_IMETHODIMP -nsSupportsIDImpl::GetData(nsID** aData) +nsSupportsID::GetData(nsID** aData) { NS_ASSERTION(aData, "Bad pointer"); @@ -57,7 +57,7 @@ nsSupportsIDImpl::GetData(nsID** aData) } NS_IMETHODIMP -nsSupportsIDImpl::SetData(const nsID* aData) +nsSupportsID::SetData(const nsID* aData) { if (mData) { free(mData); @@ -73,7 +73,7 @@ nsSupportsIDImpl::SetData(const nsID* aData) } NS_IMETHODIMP -nsSupportsIDImpl::ToString(char** aResult) +nsSupportsID::ToString(char** aResult) { NS_ASSERTION(aResult, "Bad pointer"); @@ -88,14 +88,14 @@ nsSupportsIDImpl::ToString(char** aResult) } /***************************************************************************** - * nsSupportsCStringImpl + * nsSupportsCString *****************************************************************************/ -NS_IMPL_ISUPPORTS(nsSupportsCStringImpl, nsISupportsCString, +NS_IMPL_ISUPPORTS(nsSupportsCString, nsISupportsCString, nsISupportsPrimitive) NS_IMETHODIMP -nsSupportsCStringImpl::GetType(uint16_t* aType) +nsSupportsCString::GetType(uint16_t* aType) { NS_ASSERTION(aType, "Bad pointer"); *aType = TYPE_CSTRING; @@ -103,14 +103,14 @@ nsSupportsCStringImpl::GetType(uint16_t* aType) } NS_IMETHODIMP -nsSupportsCStringImpl::GetData(nsACString& aData) +nsSupportsCString::GetData(nsACString& aData) { aData = mData; return NS_OK; } NS_IMETHODIMP -nsSupportsCStringImpl::ToString(char** aResult) +nsSupportsCString::ToString(char** aResult) { *aResult = ToNewCString(mData); if (!*aResult) { @@ -121,7 +121,7 @@ nsSupportsCStringImpl::ToString(char** aResult) } NS_IMETHODIMP -nsSupportsCStringImpl::SetData(const nsACString& aData) +nsSupportsCString::SetData(const nsACString& aData) { bool ok = mData.Assign(aData, mozilla::fallible); if (!ok) { @@ -132,14 +132,14 @@ nsSupportsCStringImpl::SetData(const nsACString& aData) } /***************************************************************************** - * nsSupportsStringImpl + * nsSupportsString *****************************************************************************/ -NS_IMPL_ISUPPORTS(nsSupportsStringImpl, nsISupportsString, +NS_IMPL_ISUPPORTS(nsSupportsString, nsISupportsString, nsISupportsPrimitive) NS_IMETHODIMP -nsSupportsStringImpl::GetType(uint16_t* aType) +nsSupportsString::GetType(uint16_t* aType) { NS_ASSERTION(aType, "Bad pointer"); *aType = TYPE_STRING; @@ -147,14 +147,14 @@ nsSupportsStringImpl::GetType(uint16_t* aType) } NS_IMETHODIMP -nsSupportsStringImpl::GetData(nsAString& aData) +nsSupportsString::GetData(nsAString& aData) { aData = mData; return NS_OK; } NS_IMETHODIMP -nsSupportsStringImpl::ToString(char16_t** aResult) +nsSupportsString::ToString(char16_t** aResult) { *aResult = ToNewUnicode(mData); if (!*aResult) { @@ -165,7 +165,7 @@ nsSupportsStringImpl::ToString(char16_t** aResult) } NS_IMETHODIMP -nsSupportsStringImpl::SetData(const nsAString& aData) +nsSupportsString::SetData(const nsAString& aData) { bool ok = mData.Assign(aData, mozilla::fallible); if (!ok) { @@ -177,16 +177,16 @@ nsSupportsStringImpl::SetData(const nsAString& aData) /***************************************************************************/ -NS_IMPL_ISUPPORTS(nsSupportsPRBoolImpl, nsISupportsPRBool, +NS_IMPL_ISUPPORTS(nsSupportsPRBool, nsISupportsPRBool, nsISupportsPrimitive) -nsSupportsPRBoolImpl::nsSupportsPRBoolImpl() +nsSupportsPRBool::nsSupportsPRBool() : mData(false) { } NS_IMETHODIMP -nsSupportsPRBoolImpl::GetType(uint16_t* aType) +nsSupportsPRBool::GetType(uint16_t* aType) { NS_ASSERTION(aType, "Bad pointer"); *aType = TYPE_PRBOOL; @@ -194,7 +194,7 @@ nsSupportsPRBoolImpl::GetType(uint16_t* aType) } NS_IMETHODIMP -nsSupportsPRBoolImpl::GetData(bool* aData) +nsSupportsPRBool::GetData(bool* aData) { NS_ASSERTION(aData, "Bad pointer"); *aData = mData; @@ -202,14 +202,14 @@ nsSupportsPRBoolImpl::GetData(bool* aData) } NS_IMETHODIMP -nsSupportsPRBoolImpl::SetData(bool aData) +nsSupportsPRBool::SetData(bool aData) { mData = aData; return NS_OK; } NS_IMETHODIMP -nsSupportsPRBoolImpl::ToString(char** aResult) +nsSupportsPRBool::ToString(char** aResult) { NS_ASSERTION(aResult, "Bad pointer"); const char* str = mData ? "true" : "false"; @@ -220,16 +220,16 @@ nsSupportsPRBoolImpl::ToString(char** aResult) /***************************************************************************/ -NS_IMPL_ISUPPORTS(nsSupportsPRUint8Impl, nsISupportsPRUint8, +NS_IMPL_ISUPPORTS(nsSupportsPRUint8, nsISupportsPRUint8, nsISupportsPrimitive) -nsSupportsPRUint8Impl::nsSupportsPRUint8Impl() +nsSupportsPRUint8::nsSupportsPRUint8() : mData(0) { } NS_IMETHODIMP -nsSupportsPRUint8Impl::GetType(uint16_t* aType) +nsSupportsPRUint8::GetType(uint16_t* aType) { NS_ASSERTION(aType, "Bad pointer"); *aType = TYPE_PRUINT8; @@ -237,7 +237,7 @@ nsSupportsPRUint8Impl::GetType(uint16_t* aType) } NS_IMETHODIMP -nsSupportsPRUint8Impl::GetData(uint8_t* aData) +nsSupportsPRUint8::GetData(uint8_t* aData) { NS_ASSERTION(aData, "Bad pointer"); *aData = mData; @@ -245,14 +245,14 @@ nsSupportsPRUint8Impl::GetData(uint8_t* aData) } NS_IMETHODIMP -nsSupportsPRUint8Impl::SetData(uint8_t aData) +nsSupportsPRUint8::SetData(uint8_t aData) { mData = aData; return NS_OK; } NS_IMETHODIMP -nsSupportsPRUint8Impl::ToString(char** aResult) +nsSupportsPRUint8::ToString(char** aResult) { NS_ASSERTION(aResult, "Bad pointer"); *aResult = DataToString("%u", static_cast(mData)); @@ -261,16 +261,16 @@ nsSupportsPRUint8Impl::ToString(char** aResult) /***************************************************************************/ -NS_IMPL_ISUPPORTS(nsSupportsPRUint16Impl, nsISupportsPRUint16, +NS_IMPL_ISUPPORTS(nsSupportsPRUint16, nsISupportsPRUint16, nsISupportsPrimitive) -nsSupportsPRUint16Impl::nsSupportsPRUint16Impl() +nsSupportsPRUint16::nsSupportsPRUint16() : mData(0) { } NS_IMETHODIMP -nsSupportsPRUint16Impl::GetType(uint16_t* aType) +nsSupportsPRUint16::GetType(uint16_t* aType) { NS_ASSERTION(aType, "Bad pointer"); *aType = TYPE_PRUINT16; @@ -278,7 +278,7 @@ nsSupportsPRUint16Impl::GetType(uint16_t* aType) } NS_IMETHODIMP -nsSupportsPRUint16Impl::GetData(uint16_t* aData) +nsSupportsPRUint16::GetData(uint16_t* aData) { NS_ASSERTION(aData, "Bad pointer"); *aData = mData; @@ -286,14 +286,14 @@ nsSupportsPRUint16Impl::GetData(uint16_t* aData) } NS_IMETHODIMP -nsSupportsPRUint16Impl::SetData(uint16_t aData) +nsSupportsPRUint16::SetData(uint16_t aData) { mData = aData; return NS_OK; } NS_IMETHODIMP -nsSupportsPRUint16Impl::ToString(char** aResult) +nsSupportsPRUint16::ToString(char** aResult) { NS_ASSERTION(aResult, "Bad pointer"); *aResult = DataToString("%u", static_cast(mData)); @@ -302,16 +302,16 @@ nsSupportsPRUint16Impl::ToString(char** aResult) /***************************************************************************/ -NS_IMPL_ISUPPORTS(nsSupportsPRUint32Impl, nsISupportsPRUint32, +NS_IMPL_ISUPPORTS(nsSupportsPRUint32, nsISupportsPRUint32, nsISupportsPrimitive) -nsSupportsPRUint32Impl::nsSupportsPRUint32Impl() +nsSupportsPRUint32::nsSupportsPRUint32() : mData(0) { } NS_IMETHODIMP -nsSupportsPRUint32Impl::GetType(uint16_t* aType) +nsSupportsPRUint32::GetType(uint16_t* aType) { NS_ASSERTION(aType, "Bad pointer"); *aType = TYPE_PRUINT32; @@ -319,7 +319,7 @@ nsSupportsPRUint32Impl::GetType(uint16_t* aType) } NS_IMETHODIMP -nsSupportsPRUint32Impl::GetData(uint32_t* aData) +nsSupportsPRUint32::GetData(uint32_t* aData) { NS_ASSERTION(aData, "Bad pointer"); *aData = mData; @@ -327,14 +327,14 @@ nsSupportsPRUint32Impl::GetData(uint32_t* aData) } NS_IMETHODIMP -nsSupportsPRUint32Impl::SetData(uint32_t aData) +nsSupportsPRUint32::SetData(uint32_t aData) { mData = aData; return NS_OK; } NS_IMETHODIMP -nsSupportsPRUint32Impl::ToString(char** aResult) +nsSupportsPRUint32::ToString(char** aResult) { NS_ASSERTION(aResult, "Bad pointer"); *aResult = DataToString("%u", mData); @@ -343,16 +343,16 @@ nsSupportsPRUint32Impl::ToString(char** aResult) /***************************************************************************/ -NS_IMPL_ISUPPORTS(nsSupportsPRUint64Impl, nsISupportsPRUint64, +NS_IMPL_ISUPPORTS(nsSupportsPRUint64, nsISupportsPRUint64, nsISupportsPrimitive) -nsSupportsPRUint64Impl::nsSupportsPRUint64Impl() +nsSupportsPRUint64::nsSupportsPRUint64() : mData(0) { } NS_IMETHODIMP -nsSupportsPRUint64Impl::GetType(uint16_t* aType) +nsSupportsPRUint64::GetType(uint16_t* aType) { NS_ASSERTION(aType, "Bad pointer"); *aType = TYPE_PRUINT64; @@ -360,7 +360,7 @@ nsSupportsPRUint64Impl::GetType(uint16_t* aType) } NS_IMETHODIMP -nsSupportsPRUint64Impl::GetData(uint64_t* aData) +nsSupportsPRUint64::GetData(uint64_t* aData) { NS_ASSERTION(aData, "Bad pointer"); *aData = mData; @@ -368,14 +368,14 @@ nsSupportsPRUint64Impl::GetData(uint64_t* aData) } NS_IMETHODIMP -nsSupportsPRUint64Impl::SetData(uint64_t aData) +nsSupportsPRUint64::SetData(uint64_t aData) { mData = aData; return NS_OK; } NS_IMETHODIMP -nsSupportsPRUint64Impl::ToString(char** aResult) +nsSupportsPRUint64::ToString(char** aResult) { NS_ASSERTION(aResult, "Bad pointer"); *aResult = DataToString("%llu", mData); @@ -384,16 +384,16 @@ nsSupportsPRUint64Impl::ToString(char** aResult) /***************************************************************************/ -NS_IMPL_ISUPPORTS(nsSupportsPRTimeImpl, nsISupportsPRTime, +NS_IMPL_ISUPPORTS(nsSupportsPRTime, nsISupportsPRTime, nsISupportsPrimitive) -nsSupportsPRTimeImpl::nsSupportsPRTimeImpl() +nsSupportsPRTime::nsSupportsPRTime() : mData(0) { } NS_IMETHODIMP -nsSupportsPRTimeImpl::GetType(uint16_t* aType) +nsSupportsPRTime::GetType(uint16_t* aType) { NS_ASSERTION(aType, "Bad pointer"); *aType = TYPE_PRTIME; @@ -401,7 +401,7 @@ nsSupportsPRTimeImpl::GetType(uint16_t* aType) } NS_IMETHODIMP -nsSupportsPRTimeImpl::GetData(PRTime* aData) +nsSupportsPRTime::GetData(PRTime* aData) { NS_ASSERTION(aData, "Bad pointer"); *aData = mData; @@ -409,14 +409,14 @@ nsSupportsPRTimeImpl::GetData(PRTime* aData) } NS_IMETHODIMP -nsSupportsPRTimeImpl::SetData(PRTime aData) +nsSupportsPRTime::SetData(PRTime aData) { mData = aData; return NS_OK; } NS_IMETHODIMP -nsSupportsPRTimeImpl::ToString(char** aResult) +nsSupportsPRTime::ToString(char** aResult) { NS_ASSERTION(aResult, "Bad pointer"); *aResult = DataToString("%" PRIu64, mData); @@ -425,16 +425,16 @@ nsSupportsPRTimeImpl::ToString(char** aResult) /***************************************************************************/ -NS_IMPL_ISUPPORTS(nsSupportsCharImpl, nsISupportsChar, +NS_IMPL_ISUPPORTS(nsSupportsChar, nsISupportsChar, nsISupportsPrimitive) -nsSupportsCharImpl::nsSupportsCharImpl() +nsSupportsChar::nsSupportsChar() : mData(0) { } NS_IMETHODIMP -nsSupportsCharImpl::GetType(uint16_t* aType) +nsSupportsChar::GetType(uint16_t* aType) { NS_ASSERTION(aType, "Bad pointer"); *aType = TYPE_CHAR; @@ -442,7 +442,7 @@ nsSupportsCharImpl::GetType(uint16_t* aType) } NS_IMETHODIMP -nsSupportsCharImpl::GetData(char* aData) +nsSupportsChar::GetData(char* aData) { NS_ASSERTION(aData, "Bad pointer"); *aData = mData; @@ -450,14 +450,14 @@ nsSupportsCharImpl::GetData(char* aData) } NS_IMETHODIMP -nsSupportsCharImpl::SetData(char aData) +nsSupportsChar::SetData(char aData) { mData = aData; return NS_OK; } NS_IMETHODIMP -nsSupportsCharImpl::ToString(char** aResult) +nsSupportsChar::ToString(char** aResult) { NS_ASSERTION(aResult, "Bad pointer"); *aResult = static_cast(moz_xmalloc(2 * sizeof(char))); @@ -469,16 +469,16 @@ nsSupportsCharImpl::ToString(char** aResult) /***************************************************************************/ -NS_IMPL_ISUPPORTS(nsSupportsPRInt16Impl, nsISupportsPRInt16, +NS_IMPL_ISUPPORTS(nsSupportsPRInt16, nsISupportsPRInt16, nsISupportsPrimitive) -nsSupportsPRInt16Impl::nsSupportsPRInt16Impl() +nsSupportsPRInt16::nsSupportsPRInt16() : mData(0) { } NS_IMETHODIMP -nsSupportsPRInt16Impl::GetType(uint16_t* aType) +nsSupportsPRInt16::GetType(uint16_t* aType) { NS_ASSERTION(aType, "Bad pointer"); *aType = TYPE_PRINT16; @@ -486,7 +486,7 @@ nsSupportsPRInt16Impl::GetType(uint16_t* aType) } NS_IMETHODIMP -nsSupportsPRInt16Impl::GetData(int16_t* aData) +nsSupportsPRInt16::GetData(int16_t* aData) { NS_ASSERTION(aData, "Bad pointer"); *aData = mData; @@ -494,14 +494,14 @@ nsSupportsPRInt16Impl::GetData(int16_t* aData) } NS_IMETHODIMP -nsSupportsPRInt16Impl::SetData(int16_t aData) +nsSupportsPRInt16::SetData(int16_t aData) { mData = aData; return NS_OK; } NS_IMETHODIMP -nsSupportsPRInt16Impl::ToString(char** aResult) +nsSupportsPRInt16::ToString(char** aResult) { NS_ASSERTION(aResult, "Bad pointer"); *aResult = DataToString("%d", static_cast(mData)); @@ -510,16 +510,16 @@ nsSupportsPRInt16Impl::ToString(char** aResult) /***************************************************************************/ -NS_IMPL_ISUPPORTS(nsSupportsPRInt32Impl, nsISupportsPRInt32, +NS_IMPL_ISUPPORTS(nsSupportsPRInt32, nsISupportsPRInt32, nsISupportsPrimitive) -nsSupportsPRInt32Impl::nsSupportsPRInt32Impl() +nsSupportsPRInt32::nsSupportsPRInt32() : mData(0) { } NS_IMETHODIMP -nsSupportsPRInt32Impl::GetType(uint16_t* aType) +nsSupportsPRInt32::GetType(uint16_t* aType) { NS_ASSERTION(aType, "Bad pointer"); *aType = TYPE_PRINT32; @@ -527,7 +527,7 @@ nsSupportsPRInt32Impl::GetType(uint16_t* aType) } NS_IMETHODIMP -nsSupportsPRInt32Impl::GetData(int32_t* aData) +nsSupportsPRInt32::GetData(int32_t* aData) { NS_ASSERTION(aData, "Bad pointer"); *aData = mData; @@ -535,14 +535,14 @@ nsSupportsPRInt32Impl::GetData(int32_t* aData) } NS_IMETHODIMP -nsSupportsPRInt32Impl::SetData(int32_t aData) +nsSupportsPRInt32::SetData(int32_t aData) { mData = aData; return NS_OK; } NS_IMETHODIMP -nsSupportsPRInt32Impl::ToString(char** aResult) +nsSupportsPRInt32::ToString(char** aResult) { NS_ASSERTION(aResult, "Bad pointer"); *aResult = DataToString("%d", mData); @@ -551,16 +551,16 @@ nsSupportsPRInt32Impl::ToString(char** aResult) /***************************************************************************/ -NS_IMPL_ISUPPORTS(nsSupportsPRInt64Impl, nsISupportsPRInt64, +NS_IMPL_ISUPPORTS(nsSupportsPRInt64, nsISupportsPRInt64, nsISupportsPrimitive) -nsSupportsPRInt64Impl::nsSupportsPRInt64Impl() +nsSupportsPRInt64::nsSupportsPRInt64() : mData(0) { } NS_IMETHODIMP -nsSupportsPRInt64Impl::GetType(uint16_t* aType) +nsSupportsPRInt64::GetType(uint16_t* aType) { NS_ASSERTION(aType, "Bad pointer"); *aType = TYPE_PRINT64; @@ -568,7 +568,7 @@ nsSupportsPRInt64Impl::GetType(uint16_t* aType) } NS_IMETHODIMP -nsSupportsPRInt64Impl::GetData(int64_t* aData) +nsSupportsPRInt64::GetData(int64_t* aData) { NS_ASSERTION(aData, "Bad pointer"); *aData = mData; @@ -576,14 +576,14 @@ nsSupportsPRInt64Impl::GetData(int64_t* aData) } NS_IMETHODIMP -nsSupportsPRInt64Impl::SetData(int64_t aData) +nsSupportsPRInt64::SetData(int64_t aData) { mData = aData; return NS_OK; } NS_IMETHODIMP -nsSupportsPRInt64Impl::ToString(char** aResult) +nsSupportsPRInt64::ToString(char** aResult) { NS_ASSERTION(aResult, "Bad pointer"); *aResult = DataToString("%" PRId64, mData); @@ -592,16 +592,16 @@ nsSupportsPRInt64Impl::ToString(char** aResult) /***************************************************************************/ -NS_IMPL_ISUPPORTS(nsSupportsFloatImpl, nsISupportsFloat, +NS_IMPL_ISUPPORTS(nsSupportsFloat, nsISupportsFloat, nsISupportsPrimitive) -nsSupportsFloatImpl::nsSupportsFloatImpl() +nsSupportsFloat::nsSupportsFloat() : mData(float(0.0)) { } NS_IMETHODIMP -nsSupportsFloatImpl::GetType(uint16_t* aType) +nsSupportsFloat::GetType(uint16_t* aType) { NS_ASSERTION(aType, "Bad pointer"); *aType = TYPE_FLOAT; @@ -609,7 +609,7 @@ nsSupportsFloatImpl::GetType(uint16_t* aType) } NS_IMETHODIMP -nsSupportsFloatImpl::GetData(float* aData) +nsSupportsFloat::GetData(float* aData) { NS_ASSERTION(aData, "Bad pointer"); *aData = mData; @@ -617,14 +617,14 @@ nsSupportsFloatImpl::GetData(float* aData) } NS_IMETHODIMP -nsSupportsFloatImpl::SetData(float aData) +nsSupportsFloat::SetData(float aData) { mData = aData; return NS_OK; } NS_IMETHODIMP -nsSupportsFloatImpl::ToString(char** aResult) +nsSupportsFloat::ToString(char** aResult) { NS_ASSERTION(aResult, "Bad pointer"); *aResult = DataToString("%f", static_cast(mData)); @@ -633,16 +633,16 @@ nsSupportsFloatImpl::ToString(char** aResult) /***************************************************************************/ -NS_IMPL_ISUPPORTS(nsSupportsDoubleImpl, nsISupportsDouble, +NS_IMPL_ISUPPORTS(nsSupportsDouble, nsISupportsDouble, nsISupportsPrimitive) -nsSupportsDoubleImpl::nsSupportsDoubleImpl() +nsSupportsDouble::nsSupportsDouble() : mData(double(0.0)) { } NS_IMETHODIMP -nsSupportsDoubleImpl::GetType(uint16_t* aType) +nsSupportsDouble::GetType(uint16_t* aType) { NS_ASSERTION(aType, "Bad pointer"); *aType = TYPE_DOUBLE; @@ -650,7 +650,7 @@ nsSupportsDoubleImpl::GetType(uint16_t* aType) } NS_IMETHODIMP -nsSupportsDoubleImpl::GetData(double* aData) +nsSupportsDouble::GetData(double* aData) { NS_ASSERTION(aData, "Bad pointer"); *aData = mData; @@ -658,14 +658,14 @@ nsSupportsDoubleImpl::GetData(double* aData) } NS_IMETHODIMP -nsSupportsDoubleImpl::SetData(double aData) +nsSupportsDouble::SetData(double aData) { mData = aData; return NS_OK; } NS_IMETHODIMP -nsSupportsDoubleImpl::ToString(char** aResult) +nsSupportsDouble::ToString(char** aResult) { NS_ASSERTION(aResult, "Bad pointer"); *aResult = DataToString("%f", mData); @@ -675,16 +675,16 @@ nsSupportsDoubleImpl::ToString(char** aResult) /***************************************************************************/ -NS_IMPL_ISUPPORTS(nsSupportsVoidImpl, nsISupportsVoid, +NS_IMPL_ISUPPORTS(nsSupportsVoid, nsISupportsVoid, nsISupportsPrimitive) -nsSupportsVoidImpl::nsSupportsVoidImpl() +nsSupportsVoid::nsSupportsVoid() : mData(nullptr) { } NS_IMETHODIMP -nsSupportsVoidImpl::GetType(uint16_t* aType) +nsSupportsVoid::GetType(uint16_t* aType) { NS_ASSERTION(aType, "Bad pointer"); *aType = TYPE_VOID; @@ -692,7 +692,7 @@ nsSupportsVoidImpl::GetType(uint16_t* aType) } NS_IMETHODIMP -nsSupportsVoidImpl::GetData(void** aData) +nsSupportsVoid::GetData(void** aData) { NS_ASSERTION(aData, "Bad pointer"); *aData = mData; @@ -700,14 +700,14 @@ nsSupportsVoidImpl::GetData(void** aData) } NS_IMETHODIMP -nsSupportsVoidImpl::SetData(void* aData) +nsSupportsVoid::SetData(void* aData) { mData = aData; return NS_OK; } NS_IMETHODIMP -nsSupportsVoidImpl::ToString(char** aResult) +nsSupportsVoid::ToString(char** aResult) { NS_ASSERTION(aResult, "Bad pointer"); static const char str[] = "[raw data]"; @@ -718,16 +718,16 @@ nsSupportsVoidImpl::ToString(char** aResult) /***************************************************************************/ -NS_IMPL_ISUPPORTS(nsSupportsInterfacePointerImpl, +NS_IMPL_ISUPPORTS(nsSupportsInterfacePointer, nsISupportsInterfacePointer, nsISupportsPrimitive) -nsSupportsInterfacePointerImpl::nsSupportsInterfacePointerImpl() +nsSupportsInterfacePointer::nsSupportsInterfacePointer() : mIID(nullptr) { } -nsSupportsInterfacePointerImpl::~nsSupportsInterfacePointerImpl() +nsSupportsInterfacePointer::~nsSupportsInterfacePointer() { if (mIID) { free(mIID); @@ -735,7 +735,7 @@ nsSupportsInterfacePointerImpl::~nsSupportsInterfacePointerImpl() } NS_IMETHODIMP -nsSupportsInterfacePointerImpl::GetType(uint16_t* aType) +nsSupportsInterfacePointer::GetType(uint16_t* aType) { NS_ASSERTION(aType, "Bad pointer"); *aType = TYPE_INTERFACE_POINTER; @@ -743,7 +743,7 @@ nsSupportsInterfacePointerImpl::GetType(uint16_t* aType) } NS_IMETHODIMP -nsSupportsInterfacePointerImpl::GetData(nsISupports** aData) +nsSupportsInterfacePointer::GetData(nsISupports** aData) { NS_ASSERTION(aData, "Bad pointer"); *aData = mData; @@ -752,14 +752,14 @@ nsSupportsInterfacePointerImpl::GetData(nsISupports** aData) } NS_IMETHODIMP -nsSupportsInterfacePointerImpl::SetData(nsISupports* aData) +nsSupportsInterfacePointer::SetData(nsISupports* aData) { mData = aData; return NS_OK; } NS_IMETHODIMP -nsSupportsInterfacePointerImpl::GetDataIID(nsID** aIID) +nsSupportsInterfacePointer::GetDataIID(nsID** aIID) { NS_ASSERTION(aIID, "Bad pointer"); @@ -773,7 +773,7 @@ nsSupportsInterfacePointerImpl::GetDataIID(nsID** aIID) } NS_IMETHODIMP -nsSupportsInterfacePointerImpl::SetDataIID(const nsID* aIID) +nsSupportsInterfacePointer::SetDataIID(const nsID* aIID) { if (mIID) { free(mIID); @@ -789,7 +789,7 @@ nsSupportsInterfacePointerImpl::SetDataIID(const nsID* aIID) } NS_IMETHODIMP -nsSupportsInterfacePointerImpl::ToString(char** aResult) +nsSupportsInterfacePointer::ToString(char** aResult) { NS_ASSERTION(aResult, "Bad pointer"); diff --git a/xpcom/ds/nsSupportsPrimitives.h b/xpcom/ds/nsSupportsPrimitives.h index 61d4d50df4..17ed0f47f4 100644 --- a/xpcom/ds/nsSupportsPrimitives.h +++ b/xpcom/ds/nsSupportsPrimitives.h @@ -13,289 +13,289 @@ #include "nsCOMPtr.h" #include "nsString.h" -class nsSupportsIDImpl final : public nsISupportsID +class nsSupportsID final : public nsISupportsID { public: NS_DECL_ISUPPORTS NS_DECL_NSISUPPORTSPRIMITIVE NS_DECL_NSISUPPORTSID - nsSupportsIDImpl(); + nsSupportsID(); private: - ~nsSupportsIDImpl() {} + ~nsSupportsID() {} nsID* mData; }; /***************************************************************************/ -class nsSupportsCStringImpl final : public nsISupportsCString +class nsSupportsCString final : public nsISupportsCString { public: NS_DECL_ISUPPORTS NS_DECL_NSISUPPORTSPRIMITIVE NS_DECL_NSISUPPORTSCSTRING - nsSupportsCStringImpl() {} + nsSupportsCString() {} private: - ~nsSupportsCStringImpl() {} + ~nsSupportsCString() {} nsCString mData; }; /***************************************************************************/ -class nsSupportsStringImpl final : public nsISupportsString +class nsSupportsString final : public nsISupportsString { public: NS_DECL_ISUPPORTS NS_DECL_NSISUPPORTSPRIMITIVE NS_DECL_NSISUPPORTSSTRING - nsSupportsStringImpl() {} + nsSupportsString() {} private: - ~nsSupportsStringImpl() {} + ~nsSupportsString() {} nsString mData; }; /***************************************************************************/ -class nsSupportsPRBoolImpl final : public nsISupportsPRBool +class nsSupportsPRBool final : public nsISupportsPRBool { public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSISUPPORTSPRIMITIVE NS_DECL_NSISUPPORTSPRBOOL - nsSupportsPRBoolImpl(); + nsSupportsPRBool(); private: - ~nsSupportsPRBoolImpl() {} + ~nsSupportsPRBool() {} bool mData; }; /***************************************************************************/ -class nsSupportsPRUint8Impl final : public nsISupportsPRUint8 +class nsSupportsPRUint8 final : public nsISupportsPRUint8 { public: NS_DECL_ISUPPORTS NS_DECL_NSISUPPORTSPRIMITIVE NS_DECL_NSISUPPORTSPRUINT8 - nsSupportsPRUint8Impl(); + nsSupportsPRUint8(); private: - ~nsSupportsPRUint8Impl() {} + ~nsSupportsPRUint8() {} uint8_t mData; }; /***************************************************************************/ -class nsSupportsPRUint16Impl final : public nsISupportsPRUint16 +class nsSupportsPRUint16 final : public nsISupportsPRUint16 { public: NS_DECL_ISUPPORTS NS_DECL_NSISUPPORTSPRIMITIVE NS_DECL_NSISUPPORTSPRUINT16 - nsSupportsPRUint16Impl(); + nsSupportsPRUint16(); private: - ~nsSupportsPRUint16Impl() {} + ~nsSupportsPRUint16() {} uint16_t mData; }; /***************************************************************************/ -class nsSupportsPRUint32Impl final : public nsISupportsPRUint32 +class nsSupportsPRUint32 final : public nsISupportsPRUint32 { public: NS_DECL_ISUPPORTS NS_DECL_NSISUPPORTSPRIMITIVE NS_DECL_NSISUPPORTSPRUINT32 - nsSupportsPRUint32Impl(); + nsSupportsPRUint32(); private: - ~nsSupportsPRUint32Impl() {} + ~nsSupportsPRUint32() {} uint32_t mData; }; /***************************************************************************/ -class nsSupportsPRUint64Impl final : public nsISupportsPRUint64 +class nsSupportsPRUint64 final : public nsISupportsPRUint64 { public: NS_DECL_ISUPPORTS NS_DECL_NSISUPPORTSPRIMITIVE NS_DECL_NSISUPPORTSPRUINT64 - nsSupportsPRUint64Impl(); + nsSupportsPRUint64(); private: - ~nsSupportsPRUint64Impl() {} + ~nsSupportsPRUint64() {} uint64_t mData; }; /***************************************************************************/ -class nsSupportsPRTimeImpl final : public nsISupportsPRTime +class nsSupportsPRTime final : public nsISupportsPRTime { public: NS_DECL_ISUPPORTS NS_DECL_NSISUPPORTSPRIMITIVE NS_DECL_NSISUPPORTSPRTIME - nsSupportsPRTimeImpl(); + nsSupportsPRTime(); private: - ~nsSupportsPRTimeImpl() {} + ~nsSupportsPRTime() {} PRTime mData; }; /***************************************************************************/ -class nsSupportsCharImpl final : public nsISupportsChar +class nsSupportsChar final : public nsISupportsChar { public: NS_DECL_ISUPPORTS NS_DECL_NSISUPPORTSPRIMITIVE NS_DECL_NSISUPPORTSCHAR - nsSupportsCharImpl(); + nsSupportsChar(); private: - ~nsSupportsCharImpl() {} + ~nsSupportsChar() {} char mData; }; /***************************************************************************/ -class nsSupportsPRInt16Impl final : public nsISupportsPRInt16 +class nsSupportsPRInt16 final : public nsISupportsPRInt16 { public: NS_DECL_ISUPPORTS NS_DECL_NSISUPPORTSPRIMITIVE NS_DECL_NSISUPPORTSPRINT16 - nsSupportsPRInt16Impl(); + nsSupportsPRInt16(); private: - ~nsSupportsPRInt16Impl() {} + ~nsSupportsPRInt16() {} int16_t mData; }; /***************************************************************************/ -class nsSupportsPRInt32Impl final : public nsISupportsPRInt32 +class nsSupportsPRInt32 final : public nsISupportsPRInt32 { public: NS_DECL_ISUPPORTS NS_DECL_NSISUPPORTSPRIMITIVE NS_DECL_NSISUPPORTSPRINT32 - nsSupportsPRInt32Impl(); + nsSupportsPRInt32(); private: - ~nsSupportsPRInt32Impl() {} + ~nsSupportsPRInt32() {} int32_t mData; }; /***************************************************************************/ -class nsSupportsPRInt64Impl final : public nsISupportsPRInt64 +class nsSupportsPRInt64 final : public nsISupportsPRInt64 { public: NS_DECL_ISUPPORTS NS_DECL_NSISUPPORTSPRIMITIVE NS_DECL_NSISUPPORTSPRINT64 - nsSupportsPRInt64Impl(); + nsSupportsPRInt64(); private: - ~nsSupportsPRInt64Impl() {} + ~nsSupportsPRInt64() {} int64_t mData; }; /***************************************************************************/ -class nsSupportsFloatImpl final : public nsISupportsFloat +class nsSupportsFloat final : public nsISupportsFloat { public: NS_DECL_ISUPPORTS NS_DECL_NSISUPPORTSPRIMITIVE NS_DECL_NSISUPPORTSFLOAT - nsSupportsFloatImpl(); + nsSupportsFloat(); private: - ~nsSupportsFloatImpl() {} + ~nsSupportsFloat() {} float mData; }; /***************************************************************************/ -class nsSupportsDoubleImpl final : public nsISupportsDouble +class nsSupportsDouble final : public nsISupportsDouble { public: NS_DECL_ISUPPORTS NS_DECL_NSISUPPORTSPRIMITIVE NS_DECL_NSISUPPORTSDOUBLE - nsSupportsDoubleImpl(); + nsSupportsDouble(); private: - ~nsSupportsDoubleImpl() {} + ~nsSupportsDouble() {} double mData; }; /***************************************************************************/ -class nsSupportsVoidImpl final : public nsISupportsVoid +class nsSupportsVoid final : public nsISupportsVoid { public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSISUPPORTSPRIMITIVE NS_DECL_NSISUPPORTSVOID - nsSupportsVoidImpl(); + nsSupportsVoid(); private: - ~nsSupportsVoidImpl() {} + ~nsSupportsVoid() {} void* mData; }; /***************************************************************************/ -class nsSupportsInterfacePointerImpl final : public nsISupportsInterfacePointer +class nsSupportsInterfacePointer final : public nsISupportsInterfacePointer { public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSISUPPORTSPRIMITIVE NS_DECL_NSISUPPORTSINTERFACEPOINTER - nsSupportsInterfacePointerImpl(); + nsSupportsInterfacePointer(); private: - ~nsSupportsInterfacePointerImpl(); + ~nsSupportsInterfacePointer(); nsCOMPtr mData; nsID* mIID; diff --git a/xpcom/ds/nsVariant.cpp b/xpcom/ds/nsVariant.cpp index 6c762758f2..02ed452c81 100644 --- a/xpcom/ds/nsVariant.cpp +++ b/xpcom/ds/nsVariant.cpp @@ -1201,8 +1201,7 @@ nsDiscriminatedUnion::ConvertToArray(uint16_t* aType, nsIID* aIID, Cleanup() #define DATA_SETTER_EPILOGUE(type_) \ - mType = nsIDataType::type_; \ - return NS_OK + mType = nsIDataType::type_; #define DATA_SETTER(type_, member_, value_) \ DATA_SETTER_PROLOGUE; \ @@ -1341,13 +1340,16 @@ nsDiscriminatedUnion::SetFromVariant(nsIVariant* aValue) CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_ARRAY) case nsIDataType::VTYPE_VOID: - rv = SetToVoid(); + SetToVoid(); + rv = NS_OK; break; case nsIDataType::VTYPE_EMPTY_ARRAY: - rv = SetToEmptyArray(); + SetToEmptyArray(); + rv = NS_OK; break; case nsIDataType::VTYPE_EMPTY: - rv = SetToEmpty(); + SetToEmpty(); + rv = NS_OK; break; default: NS_ERROR("bad type in variant!"); @@ -1357,113 +1359,105 @@ nsDiscriminatedUnion::SetFromVariant(nsIVariant* aValue) return rv; } -nsresult +void nsDiscriminatedUnion::SetFromInt8(uint8_t aValue) { DATA_SETTER_WITH_CAST(VTYPE_INT8, mInt8Value, (uint8_t), aValue); } -nsresult +void nsDiscriminatedUnion::SetFromInt16(int16_t aValue) { DATA_SETTER(VTYPE_INT16, mInt16Value, aValue); } -nsresult +void nsDiscriminatedUnion::SetFromInt32(int32_t aValue) { DATA_SETTER(VTYPE_INT32, mInt32Value, aValue); } -nsresult +void nsDiscriminatedUnion::SetFromInt64(int64_t aValue) { DATA_SETTER(VTYPE_INT64, mInt64Value, aValue); } -nsresult +void nsDiscriminatedUnion::SetFromUint8(uint8_t aValue) { DATA_SETTER(VTYPE_UINT8, mUint8Value, aValue); } -nsresult +void nsDiscriminatedUnion::SetFromUint16(uint16_t aValue) { DATA_SETTER(VTYPE_UINT16, mUint16Value, aValue); } -nsresult +void nsDiscriminatedUnion::SetFromUint32(uint32_t aValue) { DATA_SETTER(VTYPE_UINT32, mUint32Value, aValue); } -nsresult +void nsDiscriminatedUnion::SetFromUint64(uint64_t aValue) { DATA_SETTER(VTYPE_UINT64, mUint64Value, aValue); } -nsresult +void nsDiscriminatedUnion::SetFromFloat(float aValue) { DATA_SETTER(VTYPE_FLOAT, mFloatValue, aValue); } -nsresult +void nsDiscriminatedUnion::SetFromDouble(double aValue) { DATA_SETTER(VTYPE_DOUBLE, mDoubleValue, aValue); } -nsresult +void nsDiscriminatedUnion::SetFromBool(bool aValue) { DATA_SETTER(VTYPE_BOOL, mBoolValue, aValue); } -nsresult +void nsDiscriminatedUnion::SetFromChar(char aValue) { DATA_SETTER(VTYPE_CHAR, mCharValue, aValue); } -nsresult +void nsDiscriminatedUnion::SetFromWChar(char16_t aValue) { DATA_SETTER(VTYPE_WCHAR, mWCharValue, aValue); } -nsresult +void nsDiscriminatedUnion::SetFromID(const nsID& aValue) { DATA_SETTER(VTYPE_ID, mIDValue, aValue); } -nsresult +void nsDiscriminatedUnion::SetFromAString(const nsAString& aValue) { DATA_SETTER_PROLOGUE; - if (!(u.mAStringValue = new nsString(aValue))) { - return NS_ERROR_OUT_OF_MEMORY; - } + u.mAStringValue = new nsString(aValue); DATA_SETTER_EPILOGUE(VTYPE_ASTRING); } -nsresult +void nsDiscriminatedUnion::SetFromDOMString(const nsAString& aValue) { DATA_SETTER_PROLOGUE; - if (!(u.mAStringValue = new nsString(aValue))) { - return NS_ERROR_OUT_OF_MEMORY; - } + u.mAStringValue = new nsString(aValue); DATA_SETTER_EPILOGUE(VTYPE_DOMSTRING); } -nsresult +void nsDiscriminatedUnion::SetFromACString(const nsACString& aValue) { DATA_SETTER_PROLOGUE; - if (!(u.mCStringValue = new nsCString(aValue))) { - return NS_ERROR_OUT_OF_MEMORY; - } + u.mCStringValue = new nsCString(aValue); DATA_SETTER_EPILOGUE(VTYPE_CSTRING); } -nsresult +void nsDiscriminatedUnion::SetFromAUTF8String(const nsAUTF8String& aValue) { DATA_SETTER_PROLOGUE; - if (!(u.mUTF8StringValue = new nsUTF8String(aValue))) { - return NS_ERROR_OUT_OF_MEMORY; - } + u.mUTF8StringValue = new nsUTF8String(aValue); DATA_SETTER_EPILOGUE(VTYPE_UTF8STRING); } @@ -1485,12 +1479,12 @@ nsDiscriminatedUnion::SetFromWString(const char16_t* aValue) } return SetFromWStringWithSize(NS_strlen(aValue), aValue); } -nsresult +void nsDiscriminatedUnion::SetFromISupports(nsISupports* aValue) { return SetFromInterface(NS_GET_IID(nsISupports), aValue); } -nsresult +void nsDiscriminatedUnion::SetFromInterface(const nsIID& aIID, nsISupports* aValue) { DATA_SETTER_PROLOGUE; @@ -1517,6 +1511,7 @@ nsDiscriminatedUnion::SetFromArray(uint16_t aType, const nsIID* aIID, return rv; } DATA_SETTER_EPILOGUE(VTYPE_ARRAY); + return NS_OK; } nsresult nsDiscriminatedUnion::SetFromStringWithSize(uint32_t aSize, @@ -1532,6 +1527,7 @@ nsDiscriminatedUnion::SetFromStringWithSize(uint32_t aSize, } u.str.mStringLength = aSize; DATA_SETTER_EPILOGUE(VTYPE_STRING_SIZE_IS); + return NS_OK; } nsresult nsDiscriminatedUnion::SetFromWStringWithSize(uint32_t aSize, @@ -1547,32 +1543,30 @@ nsDiscriminatedUnion::SetFromWStringWithSize(uint32_t aSize, } u.wstr.mWStringLength = aSize; DATA_SETTER_EPILOGUE(VTYPE_WSTRING_SIZE_IS); + return NS_OK; } -nsresult +void nsDiscriminatedUnion::AllocateWStringWithSize(uint32_t aSize) { DATA_SETTER_PROLOGUE; - if (!(u.wstr.mWStringValue = - (char16_t*)NS_Alloc((aSize + 1) * sizeof(char16_t)))) { - return NS_ERROR_OUT_OF_MEMORY; - } + u.wstr.mWStringValue = (char16_t*)moz_xmalloc((aSize + 1) * sizeof(char16_t)); u.wstr.mWStringValue[aSize] = '\0'; u.wstr.mWStringLength = aSize; DATA_SETTER_EPILOGUE(VTYPE_WSTRING_SIZE_IS); } -nsresult +void nsDiscriminatedUnion::SetToVoid() { DATA_SETTER_PROLOGUE; DATA_SETTER_EPILOGUE(VTYPE_VOID); } -nsresult +void nsDiscriminatedUnion::SetToEmpty() { DATA_SETTER_PROLOGUE; DATA_SETTER_EPILOGUE(VTYPE_EMPTY); } -nsresult +void nsDiscriminatedUnion::SetToEmptyArray() { DATA_SETTER_PROLOGUE; @@ -1921,7 +1915,8 @@ nsVariantBase::SetAsInt8(uint8_t aValue) if (!mWritable) { return NS_ERROR_OBJECT_IS_IMMUTABLE; } - return mData.SetFromInt8(aValue); + mData.SetFromInt8(aValue); + return NS_OK; } NS_IMETHODIMP @@ -1930,7 +1925,8 @@ nsVariantBase::SetAsInt16(int16_t aValue) if (!mWritable) { return NS_ERROR_OBJECT_IS_IMMUTABLE; } - return mData.SetFromInt16(aValue); + mData.SetFromInt16(aValue); + return NS_OK; } NS_IMETHODIMP @@ -1939,7 +1935,8 @@ nsVariantBase::SetAsInt32(int32_t aValue) if (!mWritable) { return NS_ERROR_OBJECT_IS_IMMUTABLE; } - return mData.SetFromInt32(aValue); + mData.SetFromInt32(aValue); + return NS_OK; } NS_IMETHODIMP @@ -1948,7 +1945,8 @@ nsVariantBase::SetAsInt64(int64_t aValue) if (!mWritable) { return NS_ERROR_OBJECT_IS_IMMUTABLE; } - return mData.SetFromInt64(aValue); + mData.SetFromInt64(aValue); + return NS_OK; } NS_IMETHODIMP @@ -1957,7 +1955,8 @@ nsVariantBase::SetAsUint8(uint8_t aValue) if (!mWritable) { return NS_ERROR_OBJECT_IS_IMMUTABLE; } - return mData.SetFromUint8(aValue); + mData.SetFromUint8(aValue); + return NS_OK; } NS_IMETHODIMP @@ -1966,7 +1965,8 @@ nsVariantBase::SetAsUint16(uint16_t aValue) if (!mWritable) { return NS_ERROR_OBJECT_IS_IMMUTABLE; } - return mData.SetFromUint16(aValue); + mData.SetFromUint16(aValue); + return NS_OK; } NS_IMETHODIMP @@ -1975,7 +1975,8 @@ nsVariantBase::SetAsUint32(uint32_t aValue) if (!mWritable) { return NS_ERROR_OBJECT_IS_IMMUTABLE; } - return mData.SetFromUint32(aValue); + mData.SetFromUint32(aValue); + return NS_OK; } NS_IMETHODIMP @@ -1984,7 +1985,8 @@ nsVariantBase::SetAsUint64(uint64_t aValue) if (!mWritable) { return NS_ERROR_OBJECT_IS_IMMUTABLE; } - return mData.SetFromUint64(aValue); + mData.SetFromUint64(aValue); + return NS_OK; } NS_IMETHODIMP @@ -1993,7 +1995,8 @@ nsVariantBase::SetAsFloat(float aValue) if (!mWritable) { return NS_ERROR_OBJECT_IS_IMMUTABLE; } - return mData.SetFromFloat(aValue); + mData.SetFromFloat(aValue); + return NS_OK; } NS_IMETHODIMP @@ -2002,7 +2005,8 @@ nsVariantBase::SetAsDouble(double aValue) if (!mWritable) { return NS_ERROR_OBJECT_IS_IMMUTABLE; } - return mData.SetFromDouble(aValue); + mData.SetFromDouble(aValue); + return NS_OK; } NS_IMETHODIMP @@ -2011,7 +2015,8 @@ nsVariantBase::SetAsBool(bool aValue) if (!mWritable) { return NS_ERROR_OBJECT_IS_IMMUTABLE; } - return mData.SetFromBool(aValue); + mData.SetFromBool(aValue); + return NS_OK; } NS_IMETHODIMP @@ -2020,7 +2025,8 @@ nsVariantBase::SetAsChar(char aValue) if (!mWritable) { return NS_ERROR_OBJECT_IS_IMMUTABLE; } - return mData.SetFromChar(aValue); + mData.SetFromChar(aValue); + return NS_OK; } NS_IMETHODIMP @@ -2029,7 +2035,8 @@ nsVariantBase::SetAsWChar(char16_t aValue) if (!mWritable) { return NS_ERROR_OBJECT_IS_IMMUTABLE; } - return mData.SetFromWChar(aValue); + mData.SetFromWChar(aValue); + return NS_OK; } NS_IMETHODIMP @@ -2038,7 +2045,8 @@ nsVariantBase::SetAsID(const nsID& aValue) if (!mWritable) { return NS_ERROR_OBJECT_IS_IMMUTABLE; } - return mData.SetFromID(aValue); + mData.SetFromID(aValue); + return NS_OK; } NS_IMETHODIMP @@ -2047,7 +2055,8 @@ nsVariantBase::SetAsAString(const nsAString& aValue) if (!mWritable) { return NS_ERROR_OBJECT_IS_IMMUTABLE; } - return mData.SetFromAString(aValue); + mData.SetFromAString(aValue); + return NS_OK; } NS_IMETHODIMP @@ -2057,7 +2066,8 @@ nsVariantBase::SetAsDOMString(const nsAString& aValue) return NS_ERROR_OBJECT_IS_IMMUTABLE; } - return mData.SetFromDOMString(aValue); + mData.SetFromDOMString(aValue); + return NS_OK; } NS_IMETHODIMP @@ -2066,7 +2076,8 @@ nsVariantBase::SetAsACString(const nsACString& aValue) if (!mWritable) { return NS_ERROR_OBJECT_IS_IMMUTABLE; } - return mData.SetFromACString(aValue); + mData.SetFromACString(aValue); + return NS_OK; } NS_IMETHODIMP @@ -2075,7 +2086,8 @@ nsVariantBase::SetAsAUTF8String(const nsAUTF8String& aValue) if (!mWritable) { return NS_ERROR_OBJECT_IS_IMMUTABLE; } - return mData.SetFromAUTF8String(aValue); + mData.SetFromAUTF8String(aValue); + return NS_OK; } NS_IMETHODIMP @@ -2102,7 +2114,8 @@ nsVariantBase::SetAsISupports(nsISupports* aValue) if (!mWritable) { return NS_ERROR_OBJECT_IS_IMMUTABLE; } - return mData.SetFromISupports(aValue); + mData.SetFromISupports(aValue); + return NS_OK; } NS_IMETHODIMP @@ -2111,7 +2124,8 @@ nsVariantBase::SetAsInterface(const nsIID& aIID, void* aInterface) if (!mWritable) { return NS_ERROR_OBJECT_IS_IMMUTABLE; } - return mData.SetFromInterface(aIID, (nsISupports*)aInterface); + mData.SetFromInterface(aIID, (nsISupports*)aInterface); + return NS_OK; } NS_IMETHODIMP @@ -2148,7 +2162,8 @@ nsVariantBase::SetAsVoid() if (!mWritable) { return NS_ERROR_OBJECT_IS_IMMUTABLE; } - return mData.SetToVoid(); + mData.SetToVoid(); + return NS_OK; } NS_IMETHODIMP @@ -2157,7 +2172,8 @@ nsVariantBase::SetAsEmpty() if (!mWritable) { return NS_ERROR_OBJECT_IS_IMMUTABLE; } - return mData.SetToEmpty(); + mData.SetToEmpty(); + return NS_OK; } NS_IMETHODIMP @@ -2166,7 +2182,8 @@ nsVariantBase::SetAsEmptyArray() if (!mWritable) { return NS_ERROR_OBJECT_IS_IMMUTABLE; } - return mData.SetToEmptyArray(); + mData.SetToEmptyArray(); + return NS_OK; } NS_IMETHODIMP diff --git a/xpcom/ds/nsVariant.h b/xpcom/ds/nsVariant.h index 0029cd3b7f..5be2d18eee 100644 --- a/xpcom/ds/nsVariant.h +++ b/xpcom/ds/nsVariant.h @@ -43,79 +43,82 @@ public: uint16_t GetType() const { return mType; } - nsresult ConvertToInt8(uint8_t* aResult) const; - nsresult ConvertToInt16(int16_t* aResult) const; - nsresult ConvertToInt32(int32_t* aResult) const; - nsresult ConvertToInt64(int64_t* aResult) const; - nsresult ConvertToUint8(uint8_t* aResult) const; - nsresult ConvertToUint16(uint16_t* aResult) const; - nsresult ConvertToUint32(uint32_t* aResult) const; - nsresult ConvertToUint64(uint64_t* aResult) const; - nsresult ConvertToFloat(float* aResult) const; - nsresult ConvertToDouble(double* aResult) const; - nsresult ConvertToBool(bool* aResult) const; - nsresult ConvertToChar(char* aResult) const; - nsresult ConvertToWChar(char16_t* aResult) const; + MOZ_MUST_USE nsresult ConvertToInt8(uint8_t* aResult) const; + MOZ_MUST_USE nsresult ConvertToInt16(int16_t* aResult) const; + MOZ_MUST_USE nsresult ConvertToInt32(int32_t* aResult) const; + MOZ_MUST_USE nsresult ConvertToInt64(int64_t* aResult) const; + MOZ_MUST_USE nsresult ConvertToUint8(uint8_t* aResult) const; + MOZ_MUST_USE nsresult ConvertToUint16(uint16_t* aResult) const; + MOZ_MUST_USE nsresult ConvertToUint32(uint32_t* aResult) const; + MOZ_MUST_USE nsresult ConvertToUint64(uint64_t* aResult) const; + MOZ_MUST_USE nsresult ConvertToFloat(float* aResult) const; + MOZ_MUST_USE nsresult ConvertToDouble(double* aResult) const; + MOZ_MUST_USE nsresult ConvertToBool(bool* aResult) const; + MOZ_MUST_USE nsresult ConvertToChar(char* aResult) const; + MOZ_MUST_USE nsresult ConvertToWChar(char16_t* aResult) const; - nsresult ConvertToID(nsID* aResult) const; + MOZ_MUST_USE nsresult ConvertToID(nsID* aResult) const; - nsresult ConvertToAString(nsAString& aResult) const; - nsresult ConvertToAUTF8String(nsAUTF8String& aResult) const; - nsresult ConvertToACString(nsACString& aResult) const; - nsresult ConvertToString(char** aResult) const; - nsresult ConvertToWString(char16_t** aResult) const; - nsresult ConvertToStringWithSize(uint32_t* aSize, char** aStr) const; - nsresult ConvertToWStringWithSize(uint32_t* aSize, char16_t** aStr) const; + MOZ_MUST_USE nsresult ConvertToAString(nsAString& aResult) const; + MOZ_MUST_USE nsresult ConvertToAUTF8String(nsAUTF8String& aResult) const; + MOZ_MUST_USE nsresult ConvertToACString(nsACString& aResult) const; + MOZ_MUST_USE nsresult ConvertToString(char** aResult) const; + MOZ_MUST_USE nsresult ConvertToWString(char16_t** aResult) const; + MOZ_MUST_USE nsresult ConvertToStringWithSize(uint32_t* aSize, char** aStr) const; + MOZ_MUST_USE nsresult ConvertToWStringWithSize(uint32_t* aSize, char16_t** aStr) const; - nsresult ConvertToISupports(nsISupports** aResult) const; - nsresult ConvertToInterface(nsIID** aIID, void** aInterface) const; - nsresult ConvertToArray(uint16_t* aType, nsIID* aIID, - uint32_t* aCount, void** aPtr) const; + MOZ_MUST_USE nsresult ConvertToISupports(nsISupports** aResult) const; + MOZ_MUST_USE nsresult ConvertToInterface(nsIID** aIID, void** aInterface) const; + MOZ_MUST_USE nsresult ConvertToArray(uint16_t* aType, nsIID* aIID, + uint32_t* aCount, void** aPtr) const; - nsresult SetFromVariant(nsIVariant* aValue); + MOZ_MUST_USE nsresult SetFromVariant(nsIVariant* aValue); - nsresult SetFromInt8(uint8_t aValue); - nsresult SetFromInt16(int16_t aValue); - nsresult SetFromInt32(int32_t aValue); - nsresult SetFromInt64(int64_t aValue); - nsresult SetFromUint8(uint8_t aValue); - nsresult SetFromUint16(uint16_t aValue); - nsresult SetFromUint32(uint32_t aValue); - nsresult SetFromUint64(uint64_t aValue); - nsresult SetFromFloat(float aValue); - nsresult SetFromDouble(double aValue); - nsresult SetFromBool(bool aValue); - nsresult SetFromChar(char aValue); - nsresult SetFromWChar(char16_t aValue); - nsresult SetFromID(const nsID& aValue); - nsresult SetFromAString(const nsAString& aValue); - nsresult SetFromDOMString(const nsAString& aValue); - nsresult SetFromAUTF8String(const nsAUTF8String& aValue); - nsresult SetFromACString(const nsACString& aValue); - nsresult SetFromString(const char* aValue); - nsresult SetFromWString(const char16_t* aValue); - nsresult SetFromISupports(nsISupports* aValue); - nsresult SetFromInterface(const nsIID& aIID, nsISupports* aValue); - nsresult SetFromArray(uint16_t aType, const nsIID* aIID, uint32_t aCount, - void* aValue); - nsresult SetFromStringWithSize(uint32_t aSize, const char* aValue); - nsresult SetFromWStringWithSize(uint32_t aSize, const char16_t* aValue); + void SetFromInt8(uint8_t aValue); + void SetFromInt16(int16_t aValue); + void SetFromInt32(int32_t aValue); + void SetFromInt64(int64_t aValue); + void SetFromUint8(uint8_t aValue); + void SetFromUint16(uint16_t aValue); + void SetFromUint32(uint32_t aValue); + void SetFromUint64(uint64_t aValue); + void SetFromFloat(float aValue); + void SetFromDouble(double aValue); + void SetFromBool(bool aValue); + void SetFromChar(char aValue); + void SetFromWChar(char16_t aValue); + void SetFromID(const nsID& aValue); + void SetFromAString(const nsAString& aValue); + void SetFromDOMString(const nsAString& aValue); + void SetFromAUTF8String(const nsAUTF8String& aValue); + void SetFromACString(const nsACString& aValue); + MOZ_MUST_USE nsresult SetFromString(const char* aValue); + MOZ_MUST_USE nsresult SetFromWString(const char16_t* aValue); + void SetFromISupports(nsISupports* aValue); + void SetFromInterface(const nsIID& aIID, nsISupports* aValue); + MOZ_MUST_USE nsresult SetFromArray(uint16_t aType, const nsIID* aIID, + uint32_t aCount, void* aValue); + MOZ_MUST_USE nsresult SetFromStringWithSize(uint32_t aSize, + const char* aValue); + MOZ_MUST_USE nsresult SetFromWStringWithSize(uint32_t aSize, + const char16_t* aValue); // Like SetFromWStringWithSize, but leaves the string uninitialized. It does // does write the null-terminator. - nsresult AllocateWStringWithSize(uint32_t aSize); + void AllocateWStringWithSize(uint32_t aSize); - nsresult SetToVoid(); - nsresult SetToEmpty(); - nsresult SetToEmptyArray(); + void SetToVoid(); + void SetToEmpty(); + void SetToEmptyArray(); void Traverse(nsCycleCollectionTraversalCallback& aCb) const; private: - nsresult ToManageableNumber(nsDiscriminatedUnion* aOutData) const; + MOZ_MUST_USE nsresult + ToManageableNumber(nsDiscriminatedUnion* aOutData) const; void FreeArray(); - bool String2ID(nsID* aPid) const; - nsresult ToString(nsACString& aOutString) const; + MOZ_MUST_USE bool String2ID(nsID* aPid) const; + MOZ_MUST_USE nsresult ToString(nsACString& aOutString) const; public: union diff --git a/xpcom/ds/nsWindowsRegKey.cpp b/xpcom/ds/nsWindowsRegKey.cpp index f75b51b8cc..535a48af4d 100644 --- a/xpcom/ds/nsWindowsRegKey.cpp +++ b/xpcom/ds/nsWindowsRegKey.cpp @@ -556,12 +556,11 @@ nsWindowsRegKey::IsWatching(bool* aResult) //----------------------------------------------------------------------------- -nsresult +void NS_NewWindowsRegKey(nsIWindowsRegKey** aResult) { RefPtr key = new nsWindowsRegKey(); key.forget(aResult); - return NS_OK; } //----------------------------------------------------------------------------- @@ -575,9 +574,6 @@ nsWindowsRegKeyConstructor(nsISupports* aDelegate, const nsIID& aIID, } nsCOMPtr key; - nsresult rv = NS_NewWindowsRegKey(getter_AddRefs(key)); - if (NS_SUCCEEDED(rv)) { - rv = key->QueryInterface(aIID, aResult); - } - return rv; + NS_NewWindowsRegKey(getter_AddRefs(key)); + return key->QueryInterface(aIID, aResult); } diff --git a/xpcom/ds/nsWindowsRegKey.h b/xpcom/ds/nsWindowsRegKey.h index 4bffad75e1..d7930579ae 100644 --- a/xpcom/ds/nsWindowsRegKey.h +++ b/xpcom/ds/nsWindowsRegKey.h @@ -21,7 +21,7 @@ * This function may be used to instantiate a windows registry key object prior * to XPCOM being initialized. */ -extern "C" nsresult NS_NewWindowsRegKey(nsIWindowsRegKey** aResult); +extern "C" void NS_NewWindowsRegKey(nsIWindowsRegKey** aResult); //----------------------------------------------------------------------------- @@ -32,8 +32,9 @@ extern "C" nsresult NS_NewWindowsRegKey(nsIWindowsRegKey** aResult); { 0xa53bc624, 0xd577, 0x4839, \ { 0xb8, 0xec, 0xbb, 0x50, 0x40, 0xa5, 0x2f, 0xf4 } } -extern nsresult nsWindowsRegKeyConstructor(nsISupports* aOuter, - const nsIID& aIID, void** aResult); +extern MOZ_MUST_USE nsresult nsWindowsRegKeyConstructor(nsISupports* aOuter, + const nsIID& aIID, + void** aResult); #endif // IMPL_LIBXUL diff --git a/xpcom/glue/nsCOMPtr.h b/xpcom/glue/nsCOMPtr.h index 2d5583fccb..f74898456c 100644 --- a/xpcom/glue/nsCOMPtr.h +++ b/xpcom/glue/nsCOMPtr.h @@ -726,7 +726,21 @@ public: // // Prefer the implicit use of this operator to calling |get()|, except where // necessary to resolve ambiguity. - operator T*() const { return get(); } + operator T*() const +#ifdef MOZ_HAVE_REF_QUALIFIERS + & +#endif + { return get(); } + +#ifdef MOZ_HAVE_REF_QUALIFIERS + // Don't allow implicit conversion of temporary nsCOMPtr to raw pointer, + // because the refcount might be one and the pointer will immediately become + // invalid. + operator T*() const && = delete; + + // Needed to avoid the deleted operator above + explicit operator bool() const { return !!mRawPtr; } +#endif T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { diff --git a/xpcom/reflect/xptinfo/xptiInterfaceInfoManager.cpp b/xpcom/reflect/xptinfo/xptiInterfaceInfoManager.cpp index 9793ed4280..b3e1b1c275 100644 --- a/xpcom/reflect/xptinfo/xptiInterfaceInfoManager.cpp +++ b/xpcom/reflect/xptinfo/xptiInterfaceInfoManager.cpp @@ -275,9 +275,10 @@ NS_IMETHODIMP XPTInterfaceInfoManager::EnumerateInterfacesWhoseNamesStartWith(const char *prefix, nsIEnumerator **_retval) { nsCOMPtr array; - NS_NewISupportsArray(getter_AddRefs(array)); - if (!array) - return NS_ERROR_UNEXPECTED; + nsresult rv = NS_NewISupportsArray(getter_AddRefs(array)); + if (NS_FAILED(rv)) { + return rv; + } ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor); uint32_t length = static_cast(strlen(prefix)); diff --git a/xpcom/tests/TestCOMPtr.cpp b/xpcom/tests/TestCOMPtr.cpp index 0fed0e43f9..bedcd43b62 100644 --- a/xpcom/tests/TestCOMPtr.cpp +++ b/xpcom/tests/TestCOMPtr.cpp @@ -380,16 +380,6 @@ main() else printf("foo1p == foo2p\n"); - printf("\n### Test 7.5: can you compare a |nsCOMPtr| with NULL, 0, nullptr [!=]?\n"); - if ( foo1p != 0 ) - printf("foo1p != 0\n"); - if ( 0 != foo1p ) - printf("0 != foo1p\n"); - if ( foo1p == 0 ) - printf("foo1p == 0\n"); - if ( 0 == foo1p ) - printf("0 == foo1p\n"); - IFoo* raw_foo2p = foo2p.get(); @@ -429,33 +419,27 @@ main() else printf("foo1p is NULL\n"); - printf("\n### Test 13: numeric pointer test?\n"); - if ( foo1p == 0 ) - printf("foo1p is NULL\n"); - else - printf("foo1p is not NULL\n"); - #if 0 if ( foo1p == 1 ) printf("foo1p allowed compare with in\n"); #endif - printf("\n### Test 14: how about when two |nsCOMPtr|s referring to the same object go out of scope?\n"); + printf("\n### Test 13: how about when two |nsCOMPtr|s referring to the same object go out of scope?\n"); } { - printf("\n### Test 15,16 ...setup...\n"); + printf("\n### Test 14,15 ...setup...\n"); IFoo* raw_foo1p = new IFoo; raw_foo1p->AddRef(); IFoo* raw_foo2p = new IFoo; raw_foo2p->AddRef(); - printf("\n### Test 15: what if I don't want to |AddRef| when I construct?\n"); + printf("\n### Test 14: what if I don't want to |AddRef| when I construct?\n"); nsCOMPtr foo1p( dont_AddRef(raw_foo1p) ); //nsCOMPtr foo1p = dont_AddRef(raw_foo1p); - printf("\n### Test 16: what if I don't want to |AddRef| when I assign in?\n"); + printf("\n### Test 15: what if I don't want to |AddRef| when I assign in?\n"); nsCOMPtr foo2p; foo2p = dont_AddRef(raw_foo2p); } @@ -467,76 +451,76 @@ main() { - printf("\n### setup for Test 17\n"); + printf("\n### setup for Test 16\n"); nsCOMPtr foop; - printf("### Test 17: basic parameter behavior?\n"); + printf("### Test 16: basic parameter behavior?\n"); CreateIFoo( nsGetterAddRefs(foop) ); } + printf("### End Test 16\n"); + + + { + printf("\n### setup for Test 17\n"); + nsCOMPtr foop; + printf("### Test 17: basic parameter behavior, using the short form?\n"); + CreateIFoo( getter_AddRefs(foop) ); + } printf("### End Test 17\n"); { - printf("\n### setup for Test 18\n"); + printf("\n### setup for Test 18, 19\n"); nsCOMPtr foop; - printf("### Test 18: basic parameter behavior, using the short form?\n"); - CreateIFoo( getter_AddRefs(foop) ); - } - printf("### End Test 18\n"); - - - { - printf("\n### setup for Test 19, 20\n"); - nsCOMPtr foop; - printf("### Test 19: reference parameter behavior?\n"); + printf("### Test 18: reference parameter behavior?\n"); set_a_IFoo(address_of(foop)); - printf("### Test 20: return value behavior?\n"); + printf("### Test 19: return value behavior?\n"); foop = return_a_IFoo(); } - printf("### End Test 19, 20\n"); + printf("### End Test 18, 19\n"); { - printf("\n### setup for Test 21\n"); + printf("\n### setup for Test 20\n"); nsCOMPtr fooP; - printf("### Test 21: is |QueryInterface| called on assigning in a raw pointer?\n"); + printf("### Test 20: is |QueryInterface| called on assigning in a raw pointer?\n"); fooP = do_QueryInterface(new IFoo); } - printf("### End Test 21\n"); + printf("### End Test 20\n"); { - printf("\n### setup for Test 22\n"); + printf("\n### setup for Test 21\n"); nsCOMPtr fooP; fooP = do_QueryInterface(new IFoo); nsCOMPtr foo2P; - printf("### Test 22: is |QueryInterface| _not_ called when assigning in a smart-pointer of the same type?\n"); + printf("### Test 21: is |QueryInterface| _not_ called when assigning in a smart-pointer of the same type?\n"); foo2P = fooP; } - printf("### End Test 22\n"); + printf("### End Test 21\n"); { - printf("\n### setup for Test 23\n"); + printf("\n### setup for Test 22\n"); nsCOMPtr barP( do_QueryInterface(new IBar) ); - printf("### Test 23: is |QueryInterface| called when assigning in a smart-pointer of a different type?\n"); + printf("### Test 22: is |QueryInterface| called when assigning in a smart-pointer of a different type?\n"); nsCOMPtr fooP( do_QueryInterface(barP) ); if ( fooP ) printf("an IBar* is an IFoo*\n"); } - printf("### End Test 23\n"); + printf("### End Test 22\n"); { - printf("\n### setup for Test 24\n"); + printf("\n### setup for Test 23\n"); nsCOMPtr fooP( do_QueryInterface(new IFoo) ); - printf("### Test 24: does |forget| avoid an AddRef/Release when assigning to another nsCOMPtr?\n"); + printf("### Test 23: does |forget| avoid an AddRef/Release when assigning to another nsCOMPtr?\n"); nsCOMPtr fooP2( fooP.forget() ); } - printf("### End Test 24\n"); + printf("### End Test 23\n"); { nsCOMPtr fooP; @@ -554,7 +538,7 @@ main() } - printf("\n### Test 25: will a static |nsCOMPtr| |Release| before program termination?\n"); + printf("\n### Test 24: will a static |nsCOMPtr| |Release| before program termination?\n"); gFoop = do_QueryInterface(new IFoo); printf("<(GetRegDirectory(regPath, "core", "component.manifest"))); - XRE_AddManifestLocation(NS_COMPONENT_LOCATION, - nsCOMPtr(GetRegDirectory(regPath, "extension", "extComponent.manifest"))); - XRE_AddJarManifestLocation(NS_COMPONENT_LOCATION, - nsCOMPtr(GetRegDirectory(regPath, "extension2.jar", nullptr))); + nsCOMPtr file = + GetRegDirectory(regPath, "core", "component.manifest"); + XRE_AddManifestLocation(NS_EXTENSION_LOCATION, file); + file = GetRegDirectory(regPath, "extension", "extComponent.manifest"); + XRE_AddManifestLocation(NS_EXTENSION_LOCATION, file); + file = GetRegDirectory(regPath, "extension2.jar", nullptr); + XRE_AddJarManifestLocation(NS_EXTENSION_LOCATION, file); ScopedXPCOM xpcom("RegistrationOrder"); if (xpcom.failed()) return 1; diff --git a/xpcom/threads/MozPromise.h b/xpcom/threads/MozPromise.h index bf1775a6a3..5e317312d2 100644 --- a/xpcom/threads/MozPromise.h +++ b/xpcom/threads/MozPromise.h @@ -899,7 +899,7 @@ public: } } - bool Exists() { return !!mRequest; } + bool Exists() const { return !!mRequest; } private: RefPtr mRequest;