зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to mozilla-central. a=merge
This commit is contained in:
Коммит
077738eeba
|
@ -17,7 +17,7 @@
|
|||
class="header"
|
||||
hidden="true"
|
||||
data-category="paneContainers">
|
||||
<label class="header-name" flex="1" data-l10n-id="containers-header"/>
|
||||
<html:h1 data-l10n-id="containers-header"/>
|
||||
</hbox>
|
||||
|
||||
<!-- Containers -->
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
class="subcategory"
|
||||
hidden="true"
|
||||
data-category="paneHome">
|
||||
<label class="header-name" data-l10n-id="pane-home-title" flex="1"/>
|
||||
<html:h1 style="-moz-box-flex: 1;" data-l10n-id="pane-home-title"/>
|
||||
<button id="restoreDefaultHomePageBtn"
|
||||
class="homepage-button check-home-page-controlled"
|
||||
data-preference-related="browser.startup.homepage"
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
class="subcategory"
|
||||
hidden="true"
|
||||
data-category="paneGeneral">
|
||||
<label class="header-name" flex="1" data-l10n-id="pane-general-title"/>
|
||||
<html:h1 data-l10n-id="pane-general-title"/>
|
||||
</hbox>
|
||||
|
||||
<!-- Startup -->
|
||||
|
@ -139,7 +139,7 @@
|
|||
class="subcategory"
|
||||
hidden="true"
|
||||
data-category="paneGeneral">
|
||||
<label class="header-name" flex="1" data-l10n-id="language-and-appearance-header"/>
|
||||
<html:h1 data-l10n-id="language-and-appearance-header"/>
|
||||
</hbox>
|
||||
|
||||
<!-- Fonts and Colors -->
|
||||
|
@ -354,7 +354,7 @@
|
|||
class="subcategory"
|
||||
hidden="true"
|
||||
data-category="paneGeneral">
|
||||
<label class="header-name" flex="1" data-l10n-id="files-and-applications-title"/>
|
||||
<html:h1 data-l10n-id="files-and-applications-title"/>
|
||||
</hbox>
|
||||
|
||||
<!--Downloads-->
|
||||
|
@ -436,7 +436,7 @@
|
|||
class="subcategory"
|
||||
hidden="true"
|
||||
data-category="paneGeneral">
|
||||
<label class="header-name" flex="1" data-l10n-id="update-application-title"/>
|
||||
<html:h1 data-l10n-id="update-application-title"/>
|
||||
</hbox>
|
||||
|
||||
<!-- Update -->
|
||||
|
@ -582,7 +582,7 @@
|
|||
class="subcategory"
|
||||
hidden="true"
|
||||
data-category="paneGeneral">
|
||||
<label class="header-name" flex="1" data-l10n-id="performance-title"/>
|
||||
<html:h1 data-l10n-id="performance-title"/>
|
||||
</hbox>
|
||||
|
||||
<!-- Performance -->
|
||||
|
@ -628,7 +628,7 @@
|
|||
class="subcategory"
|
||||
hidden="true"
|
||||
data-category="paneGeneral">
|
||||
<label class="header-name" flex="1" data-l10n-id="browsing-title"/>
|
||||
<html:h1 data-l10n-id="browsing-title"/>
|
||||
</hbox>
|
||||
|
||||
<!-- Browsing -->
|
||||
|
@ -667,7 +667,7 @@
|
|||
class="subcategory"
|
||||
hidden="true"
|
||||
data-category="paneGeneral">
|
||||
<label class="header-name" flex="1" data-l10n-id="network-settings-title"/>
|
||||
<html:h1 data-l10n-id="network-settings-title"/>
|
||||
</hbox>
|
||||
|
||||
<!-- Network Settings-->
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
class="subcategory"
|
||||
hidden="true"
|
||||
data-category="panePrivacy">
|
||||
<label class="header-name" flex="1" data-l10n-id="privacy-header"/>
|
||||
<html:h1 data-l10n-id="privacy-header"/>
|
||||
</hbox>
|
||||
|
||||
<!-- Tracking / Content Blocking -->
|
||||
|
@ -440,7 +440,7 @@
|
|||
class="subcategory"
|
||||
hidden="true"
|
||||
data-category="panePrivacy">
|
||||
<label class="header-name" flex="1" data-l10n-id="permissions-header"/>
|
||||
<html:h1 data-l10n-id="permissions-header"/>
|
||||
</hbox>
|
||||
|
||||
<!-- Permissions -->
|
||||
|
@ -671,7 +671,7 @@
|
|||
class="subcategory"
|
||||
hidden="true"
|
||||
data-category="panePrivacy">
|
||||
<label class="header-name" flex="1" data-l10n-id="collection-header"/>
|
||||
<html:h1 data-l10n-id="collection-header"/>
|
||||
</hbox>
|
||||
|
||||
<groupbox id="dataCollectionGroup" data-category="panePrivacy" hidden="true">
|
||||
|
@ -750,7 +750,7 @@
|
|||
class="subcategory"
|
||||
hidden="true"
|
||||
data-category="panePrivacy">
|
||||
<label class="header-name" flex="1" data-l10n-id="security-header"/>
|
||||
<html:h1 data-l10n-id="security-header"/>
|
||||
</hbox>
|
||||
|
||||
<!-- addons, forgery (phishing) UI Security -->
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
class="subcategory"
|
||||
hidden="true"
|
||||
data-category="paneSearch">
|
||||
<label class="header-name" flex="1" data-l10n-id="pane-search-title" />
|
||||
<html:h1 data-l10n-id="pane-search-title"/>
|
||||
</hbox>
|
||||
|
||||
<groupbox id="searchbarGroup" data-category="paneSearch">
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
hidden="true"
|
||||
data-hidden-from-search="true"
|
||||
data-category="paneSearchResults">
|
||||
<label class="header-name" flex="1" data-l10n-id="search-results-header" />
|
||||
<html:h1 data-l10n-id="search-results-header"/>
|
||||
</hbox>
|
||||
|
||||
<groupbox id="no-results-message"
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
class="subcategory"
|
||||
hidden="true"
|
||||
data-category="paneSync">
|
||||
<label class="header-name" flex="1" data-l10n-id="pane-sync-title" />
|
||||
<html:h1 data-l10n-id="pane-sync-title"/>
|
||||
</hbox>
|
||||
|
||||
<deck id="weavePrefsDeck" data-category="paneSync" hidden="true"
|
||||
|
|
|
@ -28,16 +28,19 @@ groupbox[data-category] {
|
|||
margin: 0 0 32px;
|
||||
}
|
||||
|
||||
html|h1 {
|
||||
margin: 0 0 8px;
|
||||
font-size: 1.46em;
|
||||
font-weight: 300;
|
||||
line-height: 1.3em;
|
||||
}
|
||||
|
||||
html|h2 {
|
||||
margin: 16px 0 4px;
|
||||
font-size: 1.14em;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.header-name {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
description.indent,
|
||||
.indent > description {
|
||||
color: #737373;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* 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 "BrowsingContext.h"
|
||||
#include "mozilla/dom/BrowsingContext.h"
|
||||
|
||||
#include "mozilla/dom/ChromeBrowsingContext.h"
|
||||
#include "mozilla/dom/BrowsingContextBinding.h"
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* 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 BrowsingContext_h
|
||||
#define BrowsingContext_h
|
||||
#ifndef mozilla_dom_BrowsingContext_h
|
||||
#define mozilla_dom_BrowsingContext_h
|
||||
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
|
@ -112,8 +112,8 @@ class BrowsingContext : public nsWrapperCache,
|
|||
nsTArray<RefPtr<BrowsingContext>>& aBrowsingContexts);
|
||||
|
||||
nsISupports* GetParentObject() const;
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(BrowsingContext)
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(BrowsingContext)
|
||||
|
@ -143,4 +143,5 @@ class BrowsingContext : public nsWrapperCache,
|
|||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
#endif
|
||||
|
||||
#endif // !defined(mozilla_dom_BrowsingContext_h)
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
* 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 "ChromeBrowsingContext.h"
|
||||
#include "mozilla/dom/ChromeBrowsingContext.h"
|
||||
#include "mozilla/dom/WindowGlobalParent.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -56,5 +57,53 @@ ChromeBrowsingContext::ChromeBrowsingContext(BrowsingContext* aParent,
|
|||
return static_cast<const ChromeBrowsingContext*>(aContext);
|
||||
}
|
||||
|
||||
void ChromeBrowsingContext::GetWindowGlobals(
|
||||
nsTArray<RefPtr<WindowGlobalParent>>& aWindows) {
|
||||
aWindows.SetCapacity(mWindowGlobals.Count());
|
||||
for (auto iter = mWindowGlobals.Iter(); !iter.Done(); iter.Next()) {
|
||||
aWindows.AppendElement(iter.Get()->GetKey());
|
||||
}
|
||||
}
|
||||
|
||||
void ChromeBrowsingContext::RegisterWindowGlobal(WindowGlobalParent* aGlobal) {
|
||||
MOZ_ASSERT(!mWindowGlobals.Contains(aGlobal), "Global already registered!");
|
||||
mWindowGlobals.PutEntry(aGlobal);
|
||||
}
|
||||
|
||||
void ChromeBrowsingContext::UnregisterWindowGlobal(
|
||||
WindowGlobalParent* aGlobal) {
|
||||
MOZ_ASSERT(mWindowGlobals.Contains(aGlobal), "Global not registered!");
|
||||
mWindowGlobals.RemoveEntry(aGlobal);
|
||||
|
||||
// Our current window global should be in our mWindowGlobals set. If it's not
|
||||
// anymore, clear that reference.
|
||||
if (aGlobal == mCurrentWindowGlobal) {
|
||||
mCurrentWindowGlobal = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void ChromeBrowsingContext::SetCurrentWindowGlobal(
|
||||
WindowGlobalParent* aGlobal) {
|
||||
MOZ_ASSERT(mWindowGlobals.Contains(aGlobal), "Global not registered!");
|
||||
|
||||
// TODO: This should probably assert that the processes match.
|
||||
mCurrentWindowGlobal = aGlobal;
|
||||
}
|
||||
|
||||
JSObject* ChromeBrowsingContext::WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) {
|
||||
return ChromeBrowsingContext_Binding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
void ChromeBrowsingContext::Traverse(nsCycleCollectionTraversalCallback& cb) {
|
||||
ChromeBrowsingContext* tmp = this;
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindowGlobals);
|
||||
}
|
||||
|
||||
void ChromeBrowsingContext::Unlink() {
|
||||
ChromeBrowsingContext* tmp = this;
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindowGlobals);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -4,19 +4,23 @@
|
|||
* 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 ChromeBrowsingContext_h
|
||||
#define ChromeBrowsingContext_h
|
||||
#ifndef mozilla_dom_ChromeBrowsingContext_h
|
||||
#define mozilla_dom_ChromeBrowsingContext_h
|
||||
|
||||
#include "mozilla/dom/BrowsingContext.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
|
||||
class nsIDocShell;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class WindowGlobalParent;
|
||||
|
||||
// ChromeBrowsingContext is a BrowsingContext living in the parent
|
||||
// process, with whatever extra data that a BrowsingContext in the
|
||||
// parent needs.
|
||||
|
@ -31,9 +35,24 @@ class ChromeBrowsingContext final : public BrowsingContext {
|
|||
return mProcessId == aProcessId;
|
||||
}
|
||||
|
||||
void GetWindowGlobals(nsTArray<RefPtr<WindowGlobalParent>>& aWindows);
|
||||
|
||||
// Called by WindowGlobalParent to register and unregister window globals.
|
||||
void RegisterWindowGlobal(WindowGlobalParent* aGlobal);
|
||||
void UnregisterWindowGlobal(WindowGlobalParent* aGlobal);
|
||||
|
||||
// The current active WindowGlobal.
|
||||
WindowGlobalParent* GetCurrentWindowGlobal() const {
|
||||
return mCurrentWindowGlobal;
|
||||
}
|
||||
void SetCurrentWindowGlobal(WindowGlobalParent* aGlobal);
|
||||
|
||||
JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
protected:
|
||||
void Traverse(nsCycleCollectionTraversalCallback& cb) {}
|
||||
void Unlink() {}
|
||||
void Traverse(nsCycleCollectionTraversalCallback& cb);
|
||||
void Unlink();
|
||||
|
||||
using Type = BrowsingContext::Type;
|
||||
ChromeBrowsingContext(BrowsingContext* aParent, BrowsingContext* aOpener,
|
||||
|
@ -46,8 +65,13 @@ class ChromeBrowsingContext final : public BrowsingContext {
|
|||
// XXX(farre): Store a ContentParent pointer here rather than mProcessId?
|
||||
// Indicates which process owns the docshell.
|
||||
uint64_t mProcessId;
|
||||
|
||||
// All live window globals within this browsing context.
|
||||
nsTHashtable<nsRefPtrHashKey<WindowGlobalParent>> mWindowGlobals;
|
||||
RefPtr<WindowGlobalParent> mCurrentWindowGlobal;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
#endif
|
||||
|
||||
#endif // !defined(mozilla_dom_ChromeBrowsingContext_h)
|
||||
|
|
|
@ -3193,6 +3193,22 @@ nsDocShell::SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner) {
|
|||
}
|
||||
}
|
||||
|
||||
// If we're in the content process and have had a TreeOwner set on us, extract
|
||||
// our TabChild actor. If we've already had our TabChild set, assert that it
|
||||
// hasn't changed.
|
||||
if (mTreeOwner && XRE_IsContentProcess()) {
|
||||
nsCOMPtr<nsITabChild> newTabChild = do_GetInterface(mTreeOwner);
|
||||
MOZ_ASSERT(newTabChild, "No TabChild actor for tree owner in Content!");
|
||||
|
||||
if (mTabChild) {
|
||||
nsCOMPtr<nsITabChild> oldTabChild = do_QueryReferent(mTabChild);
|
||||
MOZ_RELEASE_ASSERT(oldTabChild == newTabChild,
|
||||
"Cannot cahnge TabChild during nsDocShell lifetime!");
|
||||
} else {
|
||||
mTabChild = do_GetWeakReference(newTabChild);
|
||||
}
|
||||
}
|
||||
|
||||
// Our tree owner has changed. Recompute scriptability.
|
||||
//
|
||||
// Note that this is near-redundant with the recomputation in
|
||||
|
@ -5045,6 +5061,8 @@ nsDocShell::Destroy() {
|
|||
|
||||
SetTreeOwner(nullptr);
|
||||
|
||||
mTabChild = nullptr;
|
||||
|
||||
mOnePermittedSandboxedNavigator = nullptr;
|
||||
|
||||
// required to break ref cycle
|
||||
|
@ -13321,8 +13339,7 @@ nsDocShell::GetScriptableTabChild(nsITabChild** aTabChild) {
|
|||
}
|
||||
|
||||
already_AddRefed<nsITabChild> nsDocShell::GetTabChild() {
|
||||
nsCOMPtr<nsIDocShellTreeOwner> owner(mTreeOwner);
|
||||
nsCOMPtr<nsITabChild> tc = do_GetInterface(owner);
|
||||
nsCOMPtr<nsITabChild> tc = do_QueryReferent(mTabChild);
|
||||
return tc.forget();
|
||||
}
|
||||
|
||||
|
|
|
@ -921,6 +921,9 @@ class nsDocShell final : public nsDocLoader,
|
|||
nsCOMPtr<nsICommandManager> mCommandManager;
|
||||
RefPtr<mozilla::dom::BrowsingContext> mBrowsingContext;
|
||||
|
||||
// Weak reference to our TabChild actor.
|
||||
nsWeakPtr mTabChild;
|
||||
|
||||
// Dimensions of the docshell
|
||||
nsIntRect mBounds;
|
||||
|
||||
|
|
|
@ -235,6 +235,7 @@
|
|||
#include "mozilla/HangAnnotations.h"
|
||||
#include "mozilla/Encoding.h"
|
||||
#include "nsXULElement.h"
|
||||
#include "mozilla/RecordReplay.h"
|
||||
|
||||
#include "nsIBidiKeyboard.h"
|
||||
|
||||
|
@ -10096,6 +10097,12 @@ static const uint64_t kIdBits = 64 - kIdProcessBits;
|
|||
MOZ_RELEASE_ASSERT(id < (uint64_t(1) << kIdBits));
|
||||
uint64_t bits = id & ((uint64_t(1) << kIdBits) - 1);
|
||||
|
||||
// Set the high bit for middleman processes so it doesn't conflict with the
|
||||
// content process's generated IDs.
|
||||
if (recordreplay::IsMiddleman()) {
|
||||
bits |= uint64_t(1) << (kIdBits - 1);
|
||||
}
|
||||
|
||||
return (processBits << kIdBits) | bits;
|
||||
}
|
||||
|
||||
|
|
|
@ -271,6 +271,8 @@
|
|||
|
||||
#include "mozilla/DocLoadingTimelineMarker.h"
|
||||
|
||||
#include "mozilla/dom/WindowGlobalChild.h"
|
||||
|
||||
#include "nsISpeculativeConnect.h"
|
||||
|
||||
#include "mozilla/MediaManager.h"
|
||||
|
@ -2897,6 +2899,13 @@ void nsIDocument::SetDocumentURI(nsIURI* aURI) {
|
|||
if (!equalBases) {
|
||||
RefreshLinkHrefs();
|
||||
}
|
||||
|
||||
// Tell our WindowGlobalParent that the document's URI has been changed.
|
||||
nsPIDOMWindowInner* inner = GetInnerWindow();
|
||||
WindowGlobalChild* wgc = inner ? inner->GetWindowGlobalChild() : nullptr;
|
||||
if (wgc) {
|
||||
Unused << wgc->SendUpdateDocumentURI(mDocumentURI);
|
||||
}
|
||||
}
|
||||
|
||||
static void GetFormattedTimeString(PRTime aTime,
|
||||
|
|
|
@ -100,6 +100,7 @@
|
|||
#include "mozilla/dom/PromiseNativeHandler.h"
|
||||
#include "mozilla/dom/ParentSHistory.h"
|
||||
#include "mozilla/dom/ChildSHistory.h"
|
||||
#include "mozilla/dom/ChromeBrowsingContext.h"
|
||||
|
||||
#include "mozilla/dom/HTMLBodyElement.h"
|
||||
|
||||
|
@ -3022,6 +3023,16 @@ already_AddRefed<nsILoadContext> nsFrameLoader::LoadContext() {
|
|||
return loadContext.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<BrowsingContext> nsFrameLoader::GetBrowsingContext() {
|
||||
RefPtr<BrowsingContext> browsingContext;
|
||||
if (IsRemoteFrame() && (mRemoteBrowser || TryRemoteBrowser())) {
|
||||
browsingContext = mRemoteBrowser->GetBrowsingContext();
|
||||
} else if (GetDocShell(IgnoreErrors())) {
|
||||
browsingContext = nsDocShell::Cast(mDocShell)->GetBrowsingContext();
|
||||
}
|
||||
return browsingContext.forget();
|
||||
}
|
||||
|
||||
void nsFrameLoader::InitializeBrowserAPI() {
|
||||
if (!OwnerIsMozBrowserFrame()) {
|
||||
return;
|
||||
|
|
|
@ -48,6 +48,7 @@ namespace mozilla {
|
|||
class OriginAttributes;
|
||||
|
||||
namespace dom {
|
||||
class BrowsingContext;
|
||||
class ChromeMessageSender;
|
||||
class ContentParent;
|
||||
class InProcessTabChildMessageManager;
|
||||
|
@ -123,6 +124,8 @@ class nsFrameLoader final : public nsStubMutationObserver,
|
|||
|
||||
already_AddRefed<nsILoadContext> LoadContext();
|
||||
|
||||
already_AddRefed<mozilla::dom::BrowsingContext> GetBrowsingContext();
|
||||
|
||||
/**
|
||||
* Start loading the frame. This method figures out what to load
|
||||
* from the owner content in the frame loader.
|
||||
|
|
|
@ -260,6 +260,8 @@
|
|||
#include "mozilla/dom/ClientSource.h"
|
||||
#include "mozilla/dom/ClientState.h"
|
||||
|
||||
#include "mozilla/dom/WindowGlobalChild.h"
|
||||
|
||||
// Apple system headers seem to have a check() macro. <sigh>
|
||||
#ifdef check
|
||||
class nsIScriptTimeoutHandler;
|
||||
|
@ -1266,6 +1268,11 @@ void nsGlobalWindowInner::FreeInnerObjects(bool aForDocumentOpen) {
|
|||
}
|
||||
}
|
||||
|
||||
if (mWindowGlobalChild && !mWindowGlobalChild->IsClosed()) {
|
||||
mWindowGlobalChild->Send__delete__(mWindowGlobalChild);
|
||||
}
|
||||
mWindowGlobalChild = nullptr;
|
||||
|
||||
mIntlUtils = nullptr;
|
||||
}
|
||||
|
||||
|
@ -1635,6 +1642,15 @@ void nsGlobalWindowInner::InnerSetNewDocument(JSContext* aCx,
|
|||
// out of sync.
|
||||
ClearDocumentDependentSlots(aCx);
|
||||
|
||||
// FIXME: Currently, devtools can crete a fallback webextension window global
|
||||
// in the content process which does not have a corresponding TabChild actor.
|
||||
// This means we have no actor to be our parent. (Bug 1498293)
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mWindowGlobalChild,
|
||||
"Shouldn't have created WindowGlobalChild yet!");
|
||||
if (XRE_IsParentProcess() || mTabChild) {
|
||||
mWindowGlobalChild = WindowGlobalChild::Create(this);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
mLastOpenedURI = aDocument->GetDocumentURI();
|
||||
#endif
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
#include "mozilla/intl/LocaleService.h"
|
||||
#include "WindowDestroyedEvent.h"
|
||||
#include "nsDocShellLoadState.h"
|
||||
#include "mozilla/dom/WindowGlobalChild.h"
|
||||
|
||||
// Helper Classes
|
||||
#include "nsJSUtils.h"
|
||||
|
@ -1962,6 +1963,10 @@ nsresult nsGlobalWindowOuter::SetNewDocument(nsIDocument* aDocument,
|
|||
newInnerWindow->MigrateStateForDocumentOpen(currentInner);
|
||||
}
|
||||
|
||||
// Tell the WindowGlobalParent that it should become the current window global
|
||||
// for our BrowsingContext if it isn't already.
|
||||
mInnerWindow->GetWindowGlobalChild()->SendBecomeCurrentWindowGlobal();
|
||||
|
||||
// We no longer need the old inner window. Start its destruction if
|
||||
// its not being reused and clear our reference.
|
||||
if (doomCurrentInner) {
|
||||
|
|
|
@ -68,6 +68,7 @@ class ServiceWorker;
|
|||
class ServiceWorkerDescriptor;
|
||||
class Timeout;
|
||||
class TimeoutManager;
|
||||
class WindowGlobalChild;
|
||||
class CustomElementRegistry;
|
||||
enum class CallerType : uint32_t;
|
||||
} // namespace dom
|
||||
|
@ -378,6 +379,10 @@ class nsPIDOMWindowInner : public mozIDOMWindow {
|
|||
return mDoc;
|
||||
}
|
||||
|
||||
mozilla::dom::WindowGlobalChild* GetWindowGlobalChild() {
|
||||
return mWindowGlobalChild;
|
||||
}
|
||||
|
||||
virtual PopupControlState GetPopupControlState() const = 0;
|
||||
|
||||
// Determine if the window is suspended or frozen. Outer windows
|
||||
|
@ -695,6 +700,12 @@ class nsPIDOMWindowInner : public mozIDOMWindow {
|
|||
// also set as permissions, but it could happen that we need to access them
|
||||
// synchronously in this context, and for this, we need a copy here.
|
||||
nsTArray<nsCString> mStorageAccessGranted;
|
||||
|
||||
// The WindowGlobalChild actor for this window.
|
||||
//
|
||||
// This will be non-null during the full lifetime of the window, initialized
|
||||
// during SetNewDocument, and cleared during FreeInnerObjects.
|
||||
RefPtr<mozilla::dom::WindowGlobalChild> mWindowGlobalChild;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsPIDOMWindowInner, NS_PIDOMWINDOWINNER_IID)
|
||||
|
|
|
@ -17,3 +17,10 @@ interface BrowsingContext {
|
|||
|
||||
readonly attribute BrowsingContext? opener;
|
||||
};
|
||||
|
||||
[Exposed=Window, ChromeOnly]
|
||||
interface ChromeBrowsingContext : BrowsingContext {
|
||||
sequence<WindowGlobalParent> getWindowGlobals();
|
||||
|
||||
readonly attribute WindowGlobalParent? currentWindowGlobal;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
interface Principal;
|
||||
interface URI;
|
||||
interface nsIDocShell;
|
||||
|
||||
[Exposed=Window, ChromeOnly]
|
||||
interface WindowGlobalParent {
|
||||
readonly attribute boolean isClosed;
|
||||
readonly attribute boolean isInProcess;
|
||||
readonly attribute ChromeBrowsingContext browsingContext;
|
||||
|
||||
readonly attribute boolean isCurrentGlobal;
|
||||
|
||||
readonly attribute unsigned long long innerWindowId;
|
||||
readonly attribute unsigned long long outerWindowId;
|
||||
|
||||
readonly attribute FrameLoader? rootFrameLoader; // Embedded (browser) only
|
||||
|
||||
readonly attribute WindowGlobalChild? childActor; // in-process only
|
||||
|
||||
// Information about the currently loaded document.
|
||||
readonly attribute Principal documentPrincipal;
|
||||
readonly attribute URI? documentURI;
|
||||
|
||||
static WindowGlobalParent? getByInnerWindowId(unsigned long long innerWindowId);
|
||||
};
|
||||
|
||||
[Exposed=Window, ChromeOnly]
|
||||
interface WindowGlobalChild {
|
||||
readonly attribute boolean isClosed;
|
||||
readonly attribute boolean isInProcess;
|
||||
readonly attribute BrowsingContext browsingContext;
|
||||
|
||||
readonly attribute boolean isCurrentGlobal;
|
||||
|
||||
readonly attribute unsigned long long innerWindowId;
|
||||
readonly attribute unsigned long long outerWindowId;
|
||||
|
||||
readonly attribute WindowGlobalParent? parentActor; // in-process only
|
||||
|
||||
static WindowGlobalChild? getByInnerWindowId(unsigned long long innerWIndowId);
|
||||
};
|
|
@ -54,6 +54,7 @@ WEBIDL_FILES = [
|
|||
'TelemetryStopwatch.webidl',
|
||||
'WebExtensionContentScript.webidl',
|
||||
'WebExtensionPolicy.webidl',
|
||||
'WindowGlobalActors.webidl',
|
||||
'XULFrameElement.webidl',
|
||||
'XULMenuElement.webidl',
|
||||
'XULScrollElement.webidl',
|
||||
|
|
|
@ -890,9 +890,6 @@ nsresult ContentChild::ProvideWindowCommon(
|
|||
TabContext newTabContext = aTabOpener ? *aTabOpener : TabContext();
|
||||
RefPtr<TabChild> newChild =
|
||||
new TabChild(this, tabId, tabGroup, newTabContext, aChromeFlags);
|
||||
if (NS_FAILED(newChild->Init(aParent))) {
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
|
||||
if (aTabOpener) {
|
||||
MOZ_ASSERT(ipcContext->type() == IPCTabContext::TPopupIPCTabContext);
|
||||
|
@ -908,6 +905,12 @@ nsresult ContentChild::ProvideWindowCommon(
|
|||
RefPtr<TabChild>(newChild).forget().take(), tabId, TabId(0), *ipcContext,
|
||||
aChromeFlags, GetID(), IsForBrowser());
|
||||
|
||||
// Now that |newChild| has had its IPC link established, call |Init| to set it
|
||||
// up.
|
||||
if (NS_FAILED(newChild->Init(aParent))) {
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> parentTopInnerWindow;
|
||||
if (aParent) {
|
||||
nsCOMPtr<nsPIDOMWindowOuter> parentTopWindow =
|
||||
|
@ -2952,6 +2955,13 @@ uint64_t NextWindowID() {
|
|||
MOZ_RELEASE_ASSERT(windowID < (uint64_t(1) << kWindowIDWindowBits));
|
||||
uint64_t windowBits = windowID & ((uint64_t(1) << kWindowIDWindowBits) - 1);
|
||||
|
||||
// Make sure that the middleman process doesn't generate WindowIDs which
|
||||
// conflict with the process it's wrapping (which shares a ContentParentID
|
||||
// with it).
|
||||
if (recordreplay::IsMiddleman()) {
|
||||
windowBits |= uint64_t(1) << (kWindowIDWindowBits - 1);
|
||||
}
|
||||
|
||||
return (processBits << kWindowIDWindowBits) | windowBits;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@ using CSSSize from "Units.h";
|
|||
using mozilla::LayoutDeviceIntPoint from "Units.h";
|
||||
using hal::ScreenOrientation from "mozilla/HalScreenConfiguration.h";
|
||||
using mozilla::gfx::SurfaceFormat from "mozilla/gfx/Types.h";
|
||||
using refcounted class nsIPrincipal from "mozilla/dom/PermissionMessageUtils.h";
|
||||
using mozilla::dom::BrowsingContextId from "mozilla/dom/ipc/IdType.h";
|
||||
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -183,5 +185,13 @@ struct PerformanceInfo
|
|||
CategoryDispatch[] items;
|
||||
};
|
||||
|
||||
struct WindowGlobalInit
|
||||
{
|
||||
nsIPrincipal principal;
|
||||
BrowsingContextId browsingContextId;
|
||||
uint64_t innerWindowId;
|
||||
uint64_t outerWindowId;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -18,6 +18,7 @@ include protocol PParentToChildStream;
|
|||
include protocol PFileDescriptorSet;
|
||||
include protocol PIPCBlobInputStream;
|
||||
include protocol PPaymentRequest;
|
||||
include protocol PWindowGlobal;
|
||||
|
||||
include DOMTypes;
|
||||
include IPCBlob;
|
||||
|
@ -86,6 +87,7 @@ using class mozilla::NativeEventData from "ipc/nsGUIEventIPC.h";
|
|||
using mozilla::FontRange from "ipc/nsGUIEventIPC.h";
|
||||
using mozilla::a11y::IAccessibleHolder from "mozilla/a11y/IPCTypes.h";
|
||||
using mozilla::OriginAttributes from "mozilla/ipc/BackgroundUtils.h";
|
||||
using mozilla::dom::BrowsingContextId from "mozilla/dom/ipc/IdType.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -118,6 +120,7 @@ nested(upto inside_cpow) sync protocol PBrowser
|
|||
manages PIndexedDBPermissionRequest;
|
||||
manages PPluginWidget;
|
||||
manages PPaymentRequest;
|
||||
manages PWindowGlobal;
|
||||
|
||||
both:
|
||||
async AsyncMessage(nsString aMessage, CpowEntry[] aCpows,
|
||||
|
@ -144,6 +147,12 @@ parent:
|
|||
|
||||
async PPaymentRequest();
|
||||
|
||||
/**
|
||||
* Construct a new WindowGlobal actor for a window global in the given
|
||||
* BrowsingContext and with the given principal.
|
||||
*/
|
||||
async PWindowGlobal(WindowGlobalInit init);
|
||||
|
||||
/**
|
||||
* Sends an NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW to be adopted by the
|
||||
* widget's shareable window on the chrome side. Only used on Windows.
|
||||
|
@ -579,6 +588,8 @@ parent:
|
|||
sync SetPrefersReducedMotionOverrideForTest(bool aValue);
|
||||
sync ResetPrefersReducedMotionOverrideForTest();
|
||||
|
||||
async RootBrowsingContext(BrowsingContextId aId);
|
||||
|
||||
child:
|
||||
/**
|
||||
* Notify the remote browser that it has been Show()n on this
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
|
||||
/* 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 protocol PBrowser;
|
||||
include protocol PInProcess;
|
||||
|
||||
include DOMTypes;
|
||||
|
||||
using refcounted class nsIURI from "mozilla/ipc/URIUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/**
|
||||
* A PWindowGlobal actor has a lifetime matching that of a single Window Global,
|
||||
* specifically a |nsGlobalWindowInner|. These actors will form a parent/child
|
||||
* link either between the chrome/content process, or will be in-process, for
|
||||
* documents which are loaded in the chrome process.
|
||||
*/
|
||||
async protocol PWindowGlobal
|
||||
{
|
||||
manager PBrowser or PInProcess;
|
||||
|
||||
parent:
|
||||
/// Update the URI of the document in this WindowGlobal.
|
||||
async UpdateDocumentURI(nsIURI aUri);
|
||||
|
||||
/// Notify the parent that this PWindowGlobal is now the current global.
|
||||
async BecomeCurrentWindowGlobal();
|
||||
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -122,6 +122,7 @@
|
|||
#include "mozilla/Telemetry.h"
|
||||
#include "nsDocShellLoadState.h"
|
||||
#include "nsWebBrowser.h"
|
||||
#include "mozilla/dom/WindowGlobalChild.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "mozilla/plugins/PluginWidgetChild.h"
|
||||
|
@ -537,6 +538,11 @@ nsresult TabChild::Init(mozIDOMWindowProxy* aParent) {
|
|||
loadContext->SetRemoteTabs(mChromeFlags &
|
||||
nsIWebBrowserChrome::CHROME_REMOTE_WINDOW);
|
||||
|
||||
// Send our browsing context to the parent process.
|
||||
RefPtr<BrowsingContext> browsingContext =
|
||||
nsDocShell::Cast(docShell)->GetBrowsingContext();
|
||||
SendRootBrowsingContext(BrowsingContextId(browsingContext->Id()));
|
||||
|
||||
// Few lines before, baseWindow->Create() will end up creating a new
|
||||
// window root in nsGlobalWindow::SetDocShell.
|
||||
// Then this chrome event handler, will be inherited to inner windows.
|
||||
|
@ -3137,6 +3143,17 @@ bool TabChild::DeallocPPaymentRequestChild(PPaymentRequestChild* actor) {
|
|||
return true;
|
||||
}
|
||||
|
||||
PWindowGlobalChild* TabChild::AllocPWindowGlobalChild(const WindowGlobalInit&) {
|
||||
MOZ_CRASH("We should never be manually allocating PWindowGlobalChild actors");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool TabChild::DeallocPWindowGlobalChild(PWindowGlobalChild* aActor) {
|
||||
// This reference was added in WindowGlobalChild::Create.
|
||||
static_cast<WindowGlobalChild*>(aActor)->Release();
|
||||
return true;
|
||||
}
|
||||
|
||||
ScreenIntSize TabChild::GetInnerSize() {
|
||||
LayoutDeviceIntSize innerSize =
|
||||
RoundedToInt(mUnscaledInnerSize * mPuppetWidget->GetDefaultScale());
|
||||
|
|
|
@ -657,6 +657,11 @@ class TabChild final : public TabChildBase,
|
|||
protected:
|
||||
virtual ~TabChild();
|
||||
|
||||
virtual PWindowGlobalChild* AllocPWindowGlobalChild(
|
||||
const WindowGlobalInit& aInit) override;
|
||||
|
||||
virtual bool DeallocPWindowGlobalChild(PWindowGlobalChild* aActor) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvDestroy() override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvSetDocShellIsActive(
|
||||
|
|
|
@ -100,6 +100,8 @@
|
|||
#include "ProcessPriorityManager.h"
|
||||
#include "nsString.h"
|
||||
#include "IHistory.h"
|
||||
#include "mozilla/dom/WindowGlobalParent.h"
|
||||
#include "mozilla/dom/ChromeBrowsingContext.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "mozilla/plugins/PluginWidgetParent.h"
|
||||
|
@ -988,6 +990,24 @@ bool TabParent::DeallocPIndexedDBPermissionRequestParent(
|
|||
aActor);
|
||||
}
|
||||
|
||||
IPCResult TabParent::RecvPWindowGlobalConstructor(
|
||||
PWindowGlobalParent* aActor, const WindowGlobalInit& aInit) {
|
||||
static_cast<WindowGlobalParent*>(aActor)->Init(aInit);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
PWindowGlobalParent* TabParent::AllocPWindowGlobalParent(
|
||||
const WindowGlobalInit& aInit) {
|
||||
// Reference freed in DeallocPWindowGlobalParent.
|
||||
return do_AddRef(new WindowGlobalParent(aInit, /* inproc */ false)).take();
|
||||
}
|
||||
|
||||
bool TabParent::DeallocPWindowGlobalParent(PWindowGlobalParent* aActor) {
|
||||
// Free reference from AllocPWindowGlobalParent.
|
||||
static_cast<WindowGlobalParent*>(aActor)->Release();
|
||||
return true;
|
||||
}
|
||||
|
||||
void TabParent::SendMouseEvent(const nsAString& aType, float aX, float aY,
|
||||
int32_t aButton, int32_t aClickCount,
|
||||
int32_t aModifiers,
|
||||
|
@ -3371,6 +3391,14 @@ mozilla::ipc::IPCResult TabParent::RecvGetSystemFont(nsCString* aFontName) {
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult TabParent::RecvRootBrowsingContext(
|
||||
const BrowsingContextId& aId) {
|
||||
MOZ_ASSERT(!mBrowsingContext, "May only set browsing context once!");
|
||||
mBrowsingContext = ChromeBrowsingContext::Get(aId);
|
||||
MOZ_ASSERT(mBrowsingContext, "Invalid ID!");
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FakeChannel::OnAuthAvailable(nsISupports* aContext,
|
||||
nsIAuthInformation* aAuthInfo) {
|
||||
|
|
|
@ -67,6 +67,7 @@ class DataSourceSurface;
|
|||
|
||||
namespace dom {
|
||||
|
||||
class ChromeBrowsingContext;
|
||||
class ClonedMessageData;
|
||||
class nsIContentParent;
|
||||
class Element;
|
||||
|
@ -125,6 +126,8 @@ class TabParent final : public PBrowserParent,
|
|||
|
||||
nsIXULBrowserWindow* GetXULBrowserWindow();
|
||||
|
||||
ChromeBrowsingContext* GetBrowsingContext() { return mBrowsingContext; }
|
||||
|
||||
void Destroy();
|
||||
|
||||
void RemoveWindowListeners();
|
||||
|
@ -305,6 +308,14 @@ class TabParent final : public PBrowserParent,
|
|||
*/
|
||||
a11y::DocAccessibleParent* GetTopLevelDocAccessible() const;
|
||||
|
||||
virtual PWindowGlobalParent* AllocPWindowGlobalParent(
|
||||
const WindowGlobalInit& aInit) override;
|
||||
|
||||
virtual bool DeallocPWindowGlobalParent(PWindowGlobalParent* aActor) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvPWindowGlobalConstructor(
|
||||
PWindowGlobalParent* aActor, const WindowGlobalInit& aInit) override;
|
||||
|
||||
void LoadURL(nsIURI* aURI);
|
||||
|
||||
void InitRendering();
|
||||
|
@ -576,6 +587,9 @@ class TabParent final : public PBrowserParent,
|
|||
virtual mozilla::ipc::IPCResult RecvShowCanvasPermissionPrompt(
|
||||
const nsCString& aFirstPartyURI) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvRootBrowsingContext(
|
||||
const BrowsingContextId& aId) override;
|
||||
|
||||
mozilla::ipc::IPCResult RecvSetSystemFont(
|
||||
const nsCString& aFontName) override;
|
||||
mozilla::ipc::IPCResult RecvGetSystemFont(nsCString* aFontName) override;
|
||||
|
@ -653,6 +667,9 @@ class TabParent final : public PBrowserParent,
|
|||
// dispatch message manager messages during this time.
|
||||
RefPtr<nsFrameLoader> mFrameLoader;
|
||||
|
||||
// The root browsing context loaded in this TabParent.
|
||||
RefPtr<ChromeBrowsingContext> mBrowsingContext;
|
||||
|
||||
TabId mTabId;
|
||||
|
||||
// When loading a new tab or window via window.open, the child is
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
|
||||
/* 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 "mozilla/dom/WindowGlobalChild.h"
|
||||
#include "mozilla/ipc/InProcessChild.h"
|
||||
#include "mozilla/dom/BrowsingContext.h"
|
||||
#include "mozilla/dom/WindowGlobalActorsBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
typedef nsRefPtrHashtable<nsUint64HashKey, WindowGlobalChild> WGCByIdMap;
|
||||
static StaticAutoPtr<WGCByIdMap> gWindowGlobalChildById;
|
||||
|
||||
WindowGlobalChild::WindowGlobalChild(nsGlobalWindowInner* aWindow,
|
||||
dom::BrowsingContext* aBrowsingContext)
|
||||
: mWindowGlobal(aWindow)
|
||||
, mBrowsingContext(aBrowsingContext)
|
||||
, mInnerWindowId(aWindow->WindowID())
|
||||
, mOuterWindowId(aWindow->GetOuterWindow()->WindowID())
|
||||
, mIPCClosed(true)
|
||||
{
|
||||
}
|
||||
|
||||
already_AddRefed<WindowGlobalChild>
|
||||
WindowGlobalChild::Create(nsGlobalWindowInner* aWindow)
|
||||
{
|
||||
nsCOMPtr<nsIPrincipal> principal = aWindow->GetPrincipal();
|
||||
MOZ_ASSERT(principal);
|
||||
|
||||
RefPtr<nsDocShell> docshell = nsDocShell::Cast(aWindow->GetDocShell());
|
||||
MOZ_ASSERT(docshell);
|
||||
|
||||
// Initalize our WindowGlobalChild object.
|
||||
RefPtr<dom::BrowsingContext> bc = docshell->GetBrowsingContext();
|
||||
RefPtr<WindowGlobalChild> wgc = new WindowGlobalChild(aWindow, bc);
|
||||
|
||||
WindowGlobalInit init(principal,
|
||||
BrowsingContextId(wgc->BrowsingContext()->Id()),
|
||||
wgc->mInnerWindowId,
|
||||
wgc->mOuterWindowId);
|
||||
|
||||
// Send the link constructor over PInProcessChild or PBrowser.
|
||||
if (XRE_IsParentProcess()) {
|
||||
InProcessChild* ipc = InProcessChild::Singleton();
|
||||
if (!ipc) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Note: ref is released in DeallocPWindowGlobalChild
|
||||
ipc->SendPWindowGlobalConstructor(do_AddRef(wgc).take(), init);
|
||||
} else {
|
||||
RefPtr<TabChild> tabChild = TabChild::GetFrom(static_cast<mozIDOMWindow*>(aWindow));
|
||||
MOZ_ASSERT(tabChild);
|
||||
|
||||
// Note: ref is released in DeallocPWindowGlobalChild
|
||||
tabChild->SendPWindowGlobalConstructor(do_AddRef(wgc).take(), init);
|
||||
}
|
||||
wgc->mIPCClosed = false;
|
||||
|
||||
// Register this WindowGlobal in the gWindowGlobalParentsById map.
|
||||
if (!gWindowGlobalChildById) {
|
||||
gWindowGlobalChildById = new WGCByIdMap();
|
||||
ClearOnShutdown(&gWindowGlobalChildById);
|
||||
}
|
||||
auto entry = gWindowGlobalChildById->LookupForAdd(wgc->mInnerWindowId);
|
||||
MOZ_RELEASE_ASSERT(!entry, "Duplicate WindowGlobalChild entry for ID!");
|
||||
entry.OrInsert([&] { return wgc; });
|
||||
|
||||
return wgc.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<WindowGlobalChild>
|
||||
WindowGlobalChild::GetByInnerWindowId(uint64_t aInnerWindowId)
|
||||
{
|
||||
if (!gWindowGlobalChildById) {
|
||||
return nullptr;
|
||||
}
|
||||
return gWindowGlobalChildById->Get(aInnerWindowId);
|
||||
}
|
||||
|
||||
bool
|
||||
WindowGlobalChild::IsCurrentGlobal()
|
||||
{
|
||||
return !mIPCClosed && mWindowGlobal->IsCurrentInnerWindow();
|
||||
}
|
||||
|
||||
already_AddRefed<WindowGlobalParent>
|
||||
WindowGlobalChild::GetParentActor()
|
||||
{
|
||||
if (mIPCClosed) {
|
||||
return nullptr;
|
||||
}
|
||||
IProtocol* otherSide = InProcessChild::ParentActorFor(this);
|
||||
return do_AddRef(static_cast<WindowGlobalParent*>(otherSide));
|
||||
}
|
||||
|
||||
void
|
||||
WindowGlobalChild::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
mIPCClosed = true;
|
||||
gWindowGlobalChildById->Remove(mInnerWindowId);
|
||||
}
|
||||
|
||||
WindowGlobalChild::~WindowGlobalChild()
|
||||
{
|
||||
MOZ_ASSERT(!gWindowGlobalChildById ||
|
||||
!gWindowGlobalChildById->Contains(mInnerWindowId));
|
||||
}
|
||||
|
||||
JSObject*
|
||||
WindowGlobalChild::WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return WindowGlobalChild_Binding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
nsISupports*
|
||||
WindowGlobalChild::GetParentObject()
|
||||
{
|
||||
return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WindowGlobalChild,
|
||||
mWindowGlobal,
|
||||
mBrowsingContext)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WindowGlobalChild, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WindowGlobalChild, Release)
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,87 @@
|
|||
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
|
||||
/* 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_WindowGlobalChild_h
|
||||
#define mozilla_dom_WindowGlobalChild_h
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/dom/PWindowGlobalChild.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
class nsGlobalWindowInner;
|
||||
class nsDocShell;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class BrowsingContext;
|
||||
class WindowGlobalParent;
|
||||
|
||||
/**
|
||||
* Actor for a single nsGlobalWindowInner. This actor is used to communicate
|
||||
* information to the parent process asynchronously.
|
||||
*/
|
||||
class WindowGlobalChild : public nsWrapperCache
|
||||
, public PWindowGlobalChild
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WindowGlobalChild)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WindowGlobalChild)
|
||||
|
||||
static already_AddRefed<WindowGlobalChild>
|
||||
GetByInnerWindowId(uint64_t aInnerWindowId);
|
||||
|
||||
static already_AddRefed<WindowGlobalChild>
|
||||
GetByInnerWindowId(const GlobalObject& aGlobal, uint64_t aInnerWindowId) {
|
||||
return GetByInnerWindowId(aInnerWindowId);
|
||||
}
|
||||
|
||||
dom::BrowsingContext* BrowsingContext() { return mBrowsingContext; }
|
||||
nsGlobalWindowInner* WindowGlobal() { return mWindowGlobal; }
|
||||
|
||||
// Has this actor been shut down
|
||||
bool IsClosed() { return mIPCClosed; }
|
||||
|
||||
// Check if this actor is managed by PInProcess, as-in the document is loaded
|
||||
// in the chrome process.
|
||||
bool IsInProcess() { return XRE_IsParentProcess(); }
|
||||
|
||||
// The Window ID for this WindowGlobal
|
||||
uint64_t InnerWindowId() { return mInnerWindowId; }
|
||||
uint64_t OuterWindowId() { return mOuterWindowId; }
|
||||
|
||||
bool IsCurrentGlobal();
|
||||
|
||||
// Get the other side of this actor if it is an in-process actor. Returns
|
||||
// |nullptr| if the actor has been torn down, or is not in-process.
|
||||
already_AddRefed<WindowGlobalParent> GetParentActor();
|
||||
|
||||
// Create and initialize the WindowGlobalChild object.
|
||||
static already_AddRefed<WindowGlobalChild>
|
||||
Create(nsGlobalWindowInner* aWindow);
|
||||
|
||||
nsISupports* GetParentObject();
|
||||
JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
protected:
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
private:
|
||||
WindowGlobalChild(nsGlobalWindowInner* aWindow, dom::BrowsingContext* aBc);
|
||||
~WindowGlobalChild();
|
||||
|
||||
RefPtr<nsGlobalWindowInner> mWindowGlobal;
|
||||
RefPtr<dom::BrowsingContext> mBrowsingContext;
|
||||
uint64_t mInnerWindowId;
|
||||
uint64_t mOuterWindowId;
|
||||
bool mIPCClosed;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // !defined(mozilla_dom_WindowGlobalChild_h)
|
|
@ -0,0 +1,175 @@
|
|||
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
|
||||
/* 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 "mozilla/dom/WindowGlobalParent.h"
|
||||
#include "mozilla/ipc/InProcessParent.h"
|
||||
#include "mozilla/dom/ChromeBrowsingContext.h"
|
||||
#include "mozilla/dom/WindowGlobalActorsBinding.h"
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
typedef nsRefPtrHashtable<nsUint64HashKey, WindowGlobalParent> WGPByIdMap;
|
||||
static StaticAutoPtr<WGPByIdMap> gWindowGlobalParentsById;
|
||||
|
||||
WindowGlobalParent::WindowGlobalParent(const WindowGlobalInit& aInit,
|
||||
bool aInProcess)
|
||||
: mDocumentPrincipal(aInit.principal())
|
||||
, mInnerWindowId(aInit.innerWindowId())
|
||||
, mOuterWindowId(aInit.outerWindowId())
|
||||
, mInProcess(aInProcess)
|
||||
, mIPCClosed(true) // Closed until WGP::Init
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess(), "Parent process only");
|
||||
MOZ_RELEASE_ASSERT(mDocumentPrincipal, "Must have a valid principal");
|
||||
|
||||
// NOTE: mBrowsingContext initialized in Init()
|
||||
MOZ_RELEASE_ASSERT(aInit.browsingContextId() != 0,
|
||||
"Must be made in BrowsingContext");
|
||||
}
|
||||
|
||||
void
|
||||
WindowGlobalParent::Init(const WindowGlobalInit& aInit)
|
||||
{
|
||||
MOZ_ASSERT(Manager(), "Should have a manager!");
|
||||
MOZ_ASSERT(!mFrameLoader, "Cannot Init() a WindowGlobalParent twice!");
|
||||
|
||||
MOZ_ASSERT(mIPCClosed, "IPC shouldn't be open yet");
|
||||
mIPCClosed = false;
|
||||
|
||||
// Register this WindowGlobal in the gWindowGlobalParentsById map.
|
||||
if (!gWindowGlobalParentsById) {
|
||||
gWindowGlobalParentsById = new WGPByIdMap();
|
||||
ClearOnShutdown(&gWindowGlobalParentsById);
|
||||
}
|
||||
auto entry = gWindowGlobalParentsById->LookupForAdd(mInnerWindowId);
|
||||
MOZ_RELEASE_ASSERT(!entry, "Duplicate WindowGlobalParent entry for ID!");
|
||||
entry.OrInsert([&] { return this; });
|
||||
|
||||
// Determine which content process the window global is coming from.
|
||||
ContentParentId processId(0);
|
||||
if (!mInProcess) {
|
||||
processId = static_cast<ContentParent*>(Manager()->Manager())->ChildID();
|
||||
}
|
||||
|
||||
mBrowsingContext = ChromeBrowsingContext::Get(aInit.browsingContextId());
|
||||
MOZ_ASSERT(mBrowsingContext);
|
||||
|
||||
// XXX(nika): This won't be the case soon, but for now this is a good
|
||||
// assertion as we can't switch processes. We should relax this eventually.
|
||||
MOZ_ASSERT(mBrowsingContext->IsOwnedByProcess(processId));
|
||||
|
||||
// Attach ourself to the browsing context.
|
||||
mBrowsingContext->RegisterWindowGlobal(this);
|
||||
|
||||
// Determine what toplevel frame element our WindowGlobalParent is being
|
||||
// embedded in.
|
||||
RefPtr<Element> frameElement;
|
||||
if (mInProcess) {
|
||||
// In the in-process case, we can get it from the other side's
|
||||
// WindowGlobalChild.
|
||||
MOZ_ASSERT(Manager()->GetProtocolTypeId() == PInProcessMsgStart);
|
||||
RefPtr<WindowGlobalChild> otherSide = GetChildActor();
|
||||
if (otherSide && otherSide->WindowGlobal()) {
|
||||
// Get the toplevel window from the other side.
|
||||
RefPtr<nsDocShell> docShell = nsDocShell::Cast(otherSide->WindowGlobal()->GetDocShell());
|
||||
if (docShell) {
|
||||
docShell->GetTopFrameElement(getter_AddRefs(frameElement));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// In the cross-process case, we can get the frame element from our manager.
|
||||
MOZ_ASSERT(Manager()->GetProtocolTypeId() == PBrowserMsgStart);
|
||||
frameElement = static_cast<TabParent*>(Manager())->GetOwnerElement();
|
||||
}
|
||||
|
||||
// Extract the nsFrameLoader from the current frame element. We may not have a
|
||||
// nsFrameLoader if we are a chrome document.
|
||||
nsCOMPtr<nsIFrameLoaderOwner> flOwner = do_QueryInterface(frameElement);
|
||||
if (flOwner) {
|
||||
mFrameLoader = flOwner->GetFrameLoader();
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<WindowGlobalParent>
|
||||
WindowGlobalParent::GetByInnerWindowId(uint64_t aInnerWindowId)
|
||||
{
|
||||
if (!gWindowGlobalParentsById) {
|
||||
return nullptr;
|
||||
}
|
||||
return gWindowGlobalParentsById->Get(aInnerWindowId);
|
||||
}
|
||||
|
||||
already_AddRefed<WindowGlobalChild>
|
||||
WindowGlobalParent::GetChildActor()
|
||||
{
|
||||
if (mIPCClosed) {
|
||||
return nullptr;
|
||||
}
|
||||
IProtocol* otherSide = InProcessParent::ChildActorFor(this);
|
||||
return do_AddRef(static_cast<WindowGlobalChild*>(otherSide));
|
||||
}
|
||||
|
||||
IPCResult
|
||||
WindowGlobalParent::RecvUpdateDocumentURI(nsIURI* aURI)
|
||||
{
|
||||
// XXX(nika): Assert that the URI change was one which makes sense (either
|
||||
// about:blank -> a real URI, or a legal push/popstate URI change?)
|
||||
mDocumentURI = aURI;
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult
|
||||
WindowGlobalParent::RecvBecomeCurrentWindowGlobal()
|
||||
{
|
||||
mBrowsingContext->SetCurrentWindowGlobal(this);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
bool
|
||||
WindowGlobalParent::IsCurrentGlobal()
|
||||
{
|
||||
return !mIPCClosed && mBrowsingContext->GetCurrentWindowGlobal() == this;
|
||||
}
|
||||
|
||||
void
|
||||
WindowGlobalParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
mIPCClosed = true;
|
||||
gWindowGlobalParentsById->Remove(mInnerWindowId);
|
||||
mBrowsingContext->UnregisterWindowGlobal(this);
|
||||
}
|
||||
|
||||
WindowGlobalParent::~WindowGlobalParent()
|
||||
{
|
||||
MOZ_ASSERT(!gWindowGlobalParentsById ||
|
||||
!gWindowGlobalParentsById->Contains(mInnerWindowId));
|
||||
}
|
||||
|
||||
JSObject*
|
||||
WindowGlobalParent::WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return WindowGlobalParent_Binding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
nsISupports*
|
||||
WindowGlobalParent::GetParentObject()
|
||||
{
|
||||
return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WindowGlobalParent,
|
||||
mFrameLoader,
|
||||
mBrowsingContext)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WindowGlobalParent, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WindowGlobalParent, Release)
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,113 @@
|
|||
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
|
||||
/* 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_WindowGlobalParent_h
|
||||
#define mozilla_dom_WindowGlobalParent_h
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/dom/PWindowGlobalParent.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
class nsIPrincipal;
|
||||
class nsIURI;
|
||||
class nsFrameLoader;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class ChromeBrowsingContext;
|
||||
class WindowGlobalChild;
|
||||
|
||||
/**
|
||||
* A handle in the parent process to a specific nsGlobalWindowInner object.
|
||||
*/
|
||||
class WindowGlobalParent final : public nsWrapperCache
|
||||
, public PWindowGlobalParent
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WindowGlobalParent)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WindowGlobalParent)
|
||||
|
||||
static already_AddRefed<WindowGlobalParent>
|
||||
GetByInnerWindowId(uint64_t aInnerWindowId);
|
||||
|
||||
static already_AddRefed<WindowGlobalParent>
|
||||
GetByInnerWindowId(const GlobalObject& aGlobal, uint64_t aInnerWindowId) {
|
||||
return GetByInnerWindowId(aInnerWindowId);
|
||||
}
|
||||
|
||||
// Has this actor been shut down
|
||||
bool IsClosed() { return mIPCClosed; }
|
||||
|
||||
// Check if this actor is managed by PInProcess, as-in the document is loaded
|
||||
// in-process.
|
||||
bool IsInProcess() { return mInProcess; }
|
||||
|
||||
// Get the other side of this actor if it is an in-process actor. Returns
|
||||
// |nullptr| if the actor has been torn down, or is not in-process.
|
||||
already_AddRefed<WindowGlobalChild> GetChildActor();
|
||||
|
||||
// The principal of this WindowGlobal. This value will not change over the
|
||||
// lifetime of the WindowGlobal object, even to reflect changes in
|
||||
// |document.domain|.
|
||||
nsIPrincipal* DocumentPrincipal() { return mDocumentPrincipal; }
|
||||
|
||||
// The BrowsingContext which this WindowGlobal has been loaded into.
|
||||
ChromeBrowsingContext* BrowsingContext() { return mBrowsingContext; }
|
||||
|
||||
// Get the root nsFrameLoader object for the tree of BrowsingContext nodes
|
||||
// which this WindowGlobal is a part of. This will be the nsFrameLoader
|
||||
// holding the TabParent for remote tabs, and the root content frameloader for
|
||||
// non-remote tabs.
|
||||
nsFrameLoader* GetRootFrameLoader() { return mFrameLoader; }
|
||||
|
||||
// The current URI which loaded in the document.
|
||||
nsIURI* GetDocumentURI() { return mDocumentURI; }
|
||||
|
||||
// Window IDs for inner/outer windows.
|
||||
uint64_t OuterWindowId() { return mOuterWindowId; }
|
||||
uint64_t InnerWindowId() { return mInnerWindowId; }
|
||||
|
||||
bool IsCurrentGlobal();
|
||||
|
||||
// Create a WindowGlobalParent from over IPC. This method should not be called
|
||||
// from outside of the IPC constructors.
|
||||
WindowGlobalParent(const WindowGlobalInit& aInit, bool aInProcess);
|
||||
|
||||
// Initialize the mFrameLoader fields for a created WindowGlobalParent. Must
|
||||
// be called after setting the Manager actor.
|
||||
void Init(const WindowGlobalInit& aInit);
|
||||
|
||||
nsISupports* GetParentObject();
|
||||
JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
protected:
|
||||
// IPC messages
|
||||
mozilla::ipc::IPCResult RecvUpdateDocumentURI(nsIURI* aURI) override;
|
||||
mozilla::ipc::IPCResult RecvBecomeCurrentWindowGlobal() override;
|
||||
|
||||
void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
private:
|
||||
~WindowGlobalParent();
|
||||
|
||||
// NOTE: This document principal doesn't reflect possible |document.domain|
|
||||
// mutations which may have been made in the actual document.
|
||||
nsCOMPtr<nsIPrincipal> mDocumentPrincipal;
|
||||
nsCOMPtr<nsIURI> mDocumentURI;
|
||||
RefPtr<nsFrameLoader> mFrameLoader;
|
||||
RefPtr<ChromeBrowsingContext> mBrowsingContext;
|
||||
uint64_t mInnerWindowId;
|
||||
uint64_t mOuterWindowId;
|
||||
bool mInProcess;
|
||||
bool mIPCClosed;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // !defined(mozilla_dom_WindowGlobalParent_h)
|
|
@ -49,6 +49,8 @@ EXPORTS.mozilla.dom += [
|
|||
'TabParent.h',
|
||||
'URLClassifierChild.h',
|
||||
'URLClassifierParent.h',
|
||||
'WindowGlobalChild.h',
|
||||
'WindowGlobalParent.h',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
|
@ -83,6 +85,8 @@ UNIFIED_SOURCES += [
|
|||
'TabMessageUtils.cpp',
|
||||
'TabParent.cpp',
|
||||
'URLClassifierParent.cpp',
|
||||
'WindowGlobalChild.cpp',
|
||||
'WindowGlobalParent.cpp',
|
||||
]
|
||||
|
||||
# ContentChild.cpp cannot be compiled in unified mode on linux due to Time conflict
|
||||
|
@ -110,6 +114,7 @@ IPDL_SOURCES += [
|
|||
'PURLClassifier.ipdl',
|
||||
'PURLClassifierInfo.ipdlh',
|
||||
'PURLClassifierLocal.ipdl',
|
||||
'PWindowGlobal.ipdl',
|
||||
'ServiceWorkerConfiguration.ipdlh',
|
||||
]
|
||||
|
||||
|
|
|
@ -33,6 +33,12 @@ interface FrameLoader {
|
|||
*/
|
||||
readonly attribute LoadContext loadContext;
|
||||
|
||||
/**
|
||||
* Get the root BrowsingContext within the frame.
|
||||
* This may be null immediately after creating a remote frame.
|
||||
*/
|
||||
readonly attribute BrowsingContext? browsingContext;
|
||||
|
||||
/**
|
||||
* Get the ParentSHistory for the nsFrameLoader. May return null if this
|
||||
* frameloader is not for a toplevel frame.
|
||||
|
|
|
@ -35,6 +35,7 @@ bool AnimationFrameRetainedBuffer::InsertInternal(RefPtr<imgFrame>&& aFrame) {
|
|||
MOZ_ASSERT(!mSizeKnown);
|
||||
MOZ_ASSERT(mFrames.Length() < mThreshold);
|
||||
|
||||
++mSize;
|
||||
mFrames.AppendElement(std::move(aFrame));
|
||||
MOZ_ASSERT(mSize == mFrames.Length());
|
||||
return mSize < mThreshold;
|
||||
|
@ -140,20 +141,32 @@ AnimationFrameDiscardingQueue::AnimationFrameDiscardingQueue(
|
|||
AnimationFrameRetainedBuffer&& aQueue)
|
||||
: AnimationFrameBuffer(aQueue),
|
||||
mInsertIndex(aQueue.mFrames.Length()),
|
||||
mFirstFrame(std::move(aQueue.mFrames[0])) {
|
||||
mFirstFrame(aQueue.mFrames[0]) {
|
||||
MOZ_ASSERT(!mSizeKnown);
|
||||
MOZ_ASSERT(!mRedecodeError);
|
||||
MOZ_ASSERT(mInsertIndex > 0);
|
||||
MOZ_ASSERT(mGetIndex > 0);
|
||||
mMayDiscard = true;
|
||||
|
||||
for (size_t i = aQueue.mGetIndex; i < mInsertIndex; ++i) {
|
||||
// We avoided moving aQueue.mFrames[0] for mFirstFrame above because it is
|
||||
// possible the animation was reset back to the beginning, and then we crossed
|
||||
// the threshold without advancing further. That would mean mGetIndex is 0.
|
||||
for (size_t i = mGetIndex; i < mInsertIndex; ++i) {
|
||||
MOZ_ASSERT(aQueue.mFrames[i]);
|
||||
mDisplay.push_back(std::move(aQueue.mFrames[i]));
|
||||
}
|
||||
}
|
||||
|
||||
bool AnimationFrameDiscardingQueue::InsertInternal(RefPtr<imgFrame>&& aFrame) {
|
||||
if (mInsertIndex == mSize) {
|
||||
if (mSizeKnown) {
|
||||
// We produced more frames on a subsequent decode than on the first pass.
|
||||
mRedecodeError = true;
|
||||
mPending = 0;
|
||||
return true;
|
||||
}
|
||||
++mSize;
|
||||
}
|
||||
|
||||
// Even though we don't use redecoded first frames for display purposes, we
|
||||
// will still use them for recycling, so we still need to insert it.
|
||||
mDisplay.push_back(std::move(aFrame));
|
||||
|
@ -174,7 +187,6 @@ bool AnimationFrameDiscardingQueue::ResetInternal() {
|
|||
bool AnimationFrameDiscardingQueue::MarkComplete(
|
||||
const gfx::IntRect& aFirstFrameRefreshArea) {
|
||||
if (NS_WARN_IF(mInsertIndex != mSize)) {
|
||||
MOZ_ASSERT(mSizeKnown);
|
||||
mRedecodeError = true;
|
||||
mPending = 0;
|
||||
}
|
||||
|
@ -296,6 +308,10 @@ AnimationFrameRecyclingQueue::AnimationFrameRecyclingQueue(
|
|||
// recycling but none of the frames were marked as recyclable. We will incur
|
||||
// the extra allocation cost for a few more frames.
|
||||
mRecycling = true;
|
||||
|
||||
// Until we reach the end of the animation, set the first frame refresh area
|
||||
// to match that of the full area of the first frame.
|
||||
mFirstFrameRefreshArea = mFirstFrame->GetRect();
|
||||
}
|
||||
|
||||
void AnimationFrameRecyclingQueue::AddSizeOfExcludingThis(
|
||||
|
@ -370,7 +386,20 @@ void AnimationFrameRecyclingQueue::AdvanceInternal() {
|
|||
}
|
||||
|
||||
bool AnimationFrameRecyclingQueue::ResetInternal() {
|
||||
mRecycle.clear();
|
||||
// We should save any display frames that we can to save on at least the
|
||||
// allocation. The first frame refresh area is guaranteed to be the aggregate
|
||||
// dirty rect or the entire frame, and so the bare minimum area we can
|
||||
// recycle. We don't need to worry about updating the dirty rect for the
|
||||
// existing mRecycle entries, because that will happen in RecycleFrame when
|
||||
// we try to pull out a frame to redecode the first frame.
|
||||
for (RefPtr<imgFrame>& frame : mDisplay) {
|
||||
if (frame->ShouldRecycle()) {
|
||||
RecycleEntry newEntry(mFirstFrameRefreshArea);
|
||||
newEntry.mFrame = std::move(frame);
|
||||
mRecycle.push_back(std::move(newEntry));
|
||||
}
|
||||
}
|
||||
|
||||
return AnimationFrameDiscardingQueue::ResetInternal();
|
||||
}
|
||||
|
||||
|
@ -382,8 +411,6 @@ RawAccessFrameRef AnimationFrameRecyclingQueue::RecycleFrame(
|
|||
// area. We know that all of the frames still in the recycling queue
|
||||
// need to take into account the same dirty rect because they are also
|
||||
// frames which cross the boundary.
|
||||
MOZ_ASSERT(mSizeKnown);
|
||||
MOZ_ASSERT(!mFirstFrameRefreshArea.IsEmpty());
|
||||
for (RecycleEntry& entry : mRecycle) {
|
||||
MOZ_ASSERT(mFirstFrameRefreshArea.Contains(entry.mDirtyRect));
|
||||
entry.mDirtyRect = mFirstFrameRefreshArea;
|
||||
|
@ -439,11 +466,10 @@ bool AnimationFrameRecyclingQueue::MarkComplete(
|
|||
bool continueDecoding =
|
||||
AnimationFrameDiscardingQueue::MarkComplete(aFirstFrameRefreshArea);
|
||||
|
||||
MOZ_ASSERT_IF(!mRedecodeError, mFirstFrameRefreshArea.IsEmpty() ||
|
||||
mFirstFrameRefreshArea.IsEqualEdges(
|
||||
aFirstFrameRefreshArea));
|
||||
|
||||
mFirstFrameRefreshArea = aFirstFrameRefreshArea;
|
||||
// If we encounter a redecode error, just make the first frame refresh area to
|
||||
// be the full frame, because we don't really know what we can safely recycle.
|
||||
mFirstFrameRefreshArea = mRedecodeError ? mFirstFrame->GetRect()
|
||||
: aFirstFrameRefreshArea;
|
||||
return continueDecoding;
|
||||
}
|
||||
|
||||
|
|
|
@ -189,10 +189,6 @@ class AnimationFrameBuffer {
|
|||
MOZ_ASSERT(aFrame);
|
||||
|
||||
--mPending;
|
||||
if (!mSizeKnown) {
|
||||
++mSize;
|
||||
}
|
||||
|
||||
bool retain = InsertInternal(std::move(aFrame));
|
||||
|
||||
if (mAdvance > 0 && mSize > 1) {
|
||||
|
|
|
@ -289,6 +289,16 @@ bool AnimationSurfaceProvider::CheckForNewFrameAtYield() {
|
|||
// Append the new frame to the list.
|
||||
AnimationFrameBuffer::InsertStatus status =
|
||||
mFrames->Insert(std::move(frame));
|
||||
|
||||
// If we hit a redecode error, then we actually want to stop. This happens
|
||||
// when we tried to insert more frames than we originally had (e.g. the
|
||||
// original decoder attempt hit an OOM error sooner than we did). Better to
|
||||
// stop the animation than to get out of sync with FrameAnimator.
|
||||
if (mFrames->HasRedecodeError()) {
|
||||
mDecoder = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (status) {
|
||||
case AnimationFrameBuffer::InsertStatus::DISCARD_CONTINUE:
|
||||
continueDecoding = true;
|
||||
|
@ -353,6 +363,13 @@ bool AnimationSurfaceProvider::CheckForNewFrameAtTerminalState() {
|
|||
// Append the new frame to the list.
|
||||
AnimationFrameBuffer::InsertStatus status =
|
||||
mFrames->Insert(std::move(frame));
|
||||
|
||||
// If we hit a redecode error, then we actually want to stop. This will be
|
||||
// fully handled in FinishDecoding.
|
||||
if (mFrames->HasRedecodeError()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (status) {
|
||||
case AnimationFrameBuffer::InsertStatus::DISCARD_CONTINUE:
|
||||
case AnimationFrameBuffer::InsertStatus::DISCARD_YIELD:
|
||||
|
|
|
@ -146,7 +146,8 @@ VerifyMarkComplete(AnimationFrameBuffer& aQueue,
|
|||
if (aQueue.IsRecycling() && !aQueue.SizeKnown()) {
|
||||
const AnimationFrameRecyclingQueue& queue =
|
||||
*static_cast<AnimationFrameRecyclingQueue*>(&aQueue);
|
||||
EXPECT_TRUE(queue.FirstFrameRefreshArea().IsEmpty());
|
||||
EXPECT_EQ(queue.FirstFrame()->GetRect(),
|
||||
queue.FirstFrameRefreshArea());
|
||||
}
|
||||
|
||||
bool keepDecoding = aQueue.MarkComplete(aRefreshArea);
|
||||
|
@ -194,12 +195,6 @@ VerifyReset(AnimationFrameBuffer& aQueue,
|
|||
EXPECT_EQ(aFirstFrame, queue.FirstFrame());
|
||||
EXPECT_EQ(nullptr, aQueue.Get(0, false));
|
||||
}
|
||||
|
||||
if (aQueue.IsRecycling()) {
|
||||
const AnimationFrameRecyclingQueue& queue =
|
||||
*static_cast<AnimationFrameRecyclingQueue*>(&aQueue);
|
||||
EXPECT_EQ(size_t(0), queue.Recycle().size());
|
||||
}
|
||||
}
|
||||
|
||||
class ImageAnimationFrameBuffer : public ::testing::Test
|
||||
|
@ -635,6 +630,104 @@ TEST_F(ImageAnimationFrameBuffer, DiscardingReset)
|
|||
TestDiscardingQueueReset(buffer, firstFrame, kThreshold, kBatch, kStartFrame);
|
||||
}
|
||||
|
||||
TEST_F(ImageAnimationFrameBuffer, ResetBeforeDiscardingThreshold)
|
||||
{
|
||||
const size_t kThreshold = 3;
|
||||
const size_t kBatch = 1;
|
||||
const size_t kStartFrame = 0;
|
||||
|
||||
// Get the starting buffer to just before the point where we need to switch
|
||||
// to a discarding buffer, reset the animation so advancing points at the
|
||||
// first frame, and insert the last frame to cross the threshold.
|
||||
AnimationFrameRetainedBuffer retained(kThreshold, kBatch, kStartFrame);
|
||||
VerifyInsert(retained, AnimationFrameBuffer::InsertStatus::CONTINUE);
|
||||
VerifyInsertAndAdvance(retained, 1, AnimationFrameBuffer::InsertStatus::YIELD);
|
||||
bool restartDecoder = retained.Reset();
|
||||
EXPECT_FALSE(restartDecoder);
|
||||
VerifyInsert(retained, AnimationFrameBuffer::InsertStatus::DISCARD_YIELD);
|
||||
|
||||
const imgFrame* firstFrame = retained.Frames()[0].get();
|
||||
EXPECT_TRUE(firstFrame != nullptr);
|
||||
AnimationFrameDiscardingQueue buffer(std::move(retained));
|
||||
const imgFrame* displayFirstFrame = buffer.Get(0, true);
|
||||
const imgFrame* advanceFirstFrame = buffer.Get(0, false);
|
||||
EXPECT_EQ(firstFrame, displayFirstFrame);
|
||||
EXPECT_EQ(firstFrame, advanceFirstFrame);
|
||||
}
|
||||
|
||||
TEST_F(ImageAnimationFrameBuffer, DiscardingTooFewFrames)
|
||||
{
|
||||
const size_t kThreshold = 3;
|
||||
const size_t kBatch = 1;
|
||||
const size_t kStartFrame = 0;
|
||||
|
||||
// First get us to a discarding buffer state.
|
||||
AnimationFrameRetainedBuffer retained(kThreshold, kBatch, kStartFrame);
|
||||
VerifyInsert(retained, AnimationFrameBuffer::InsertStatus::CONTINUE);
|
||||
VerifyInsertAndAdvance(retained, 1, AnimationFrameBuffer::InsertStatus::YIELD);
|
||||
VerifyInsert(retained, AnimationFrameBuffer::InsertStatus::DISCARD_YIELD);
|
||||
|
||||
// Insert one more frame.
|
||||
AnimationFrameDiscardingQueue buffer(std::move(retained));
|
||||
VerifyAdvance(buffer, 2, true);
|
||||
VerifyInsert(buffer, AnimationFrameBuffer::InsertStatus::YIELD);
|
||||
|
||||
// Mark it as complete.
|
||||
bool restartDecoder = buffer.MarkComplete(IntRect(0, 0, 1, 1));
|
||||
EXPECT_FALSE(restartDecoder);
|
||||
EXPECT_FALSE(buffer.HasRedecodeError());
|
||||
|
||||
// Insert one fewer frame than before.
|
||||
VerifyAdvance(buffer, 3, true);
|
||||
VerifyInsertAndAdvance(buffer, 0, AnimationFrameBuffer::InsertStatus::YIELD);
|
||||
VerifyInsertAndAdvance(buffer, 1, AnimationFrameBuffer::InsertStatus::YIELD);
|
||||
VerifyInsertAndAdvance(buffer, 2, AnimationFrameBuffer::InsertStatus::YIELD);
|
||||
|
||||
// When we mark it as complete, it should fail due to too few frames.
|
||||
restartDecoder = buffer.MarkComplete(IntRect(0, 0, 1, 1));
|
||||
EXPECT_TRUE(buffer.HasRedecodeError());
|
||||
EXPECT_EQ(size_t(0), buffer.PendingDecode());
|
||||
EXPECT_EQ(size_t(4), buffer.Size());
|
||||
}
|
||||
|
||||
TEST_F(ImageAnimationFrameBuffer, DiscardingTooManyFrames)
|
||||
{
|
||||
const size_t kThreshold = 3;
|
||||
const size_t kBatch = 1;
|
||||
const size_t kStartFrame = 0;
|
||||
|
||||
// First get us to a discarding buffer state.
|
||||
AnimationFrameRetainedBuffer retained(kThreshold, kBatch, kStartFrame);
|
||||
VerifyInsert(retained, AnimationFrameBuffer::InsertStatus::CONTINUE);
|
||||
VerifyInsertAndAdvance(retained, 1, AnimationFrameBuffer::InsertStatus::YIELD);
|
||||
VerifyInsert(retained, AnimationFrameBuffer::InsertStatus::DISCARD_YIELD);
|
||||
|
||||
// Insert one more frame.
|
||||
AnimationFrameDiscardingQueue buffer(std::move(retained));
|
||||
VerifyAdvance(buffer, 2, true);
|
||||
VerifyInsert(buffer, AnimationFrameBuffer::InsertStatus::YIELD);
|
||||
|
||||
// Mark it as complete.
|
||||
bool restartDecoder = buffer.MarkComplete(IntRect(0, 0, 1, 1));
|
||||
EXPECT_FALSE(restartDecoder);
|
||||
EXPECT_FALSE(buffer.HasRedecodeError());
|
||||
|
||||
// Advance and insert to get us back to the end on the redecode.
|
||||
VerifyAdvance(buffer, 3, true);
|
||||
VerifyInsertAndAdvance(buffer, 0, AnimationFrameBuffer::InsertStatus::YIELD);
|
||||
VerifyInsertAndAdvance(buffer, 1, AnimationFrameBuffer::InsertStatus::YIELD);
|
||||
VerifyInsertAndAdvance(buffer, 2, AnimationFrameBuffer::InsertStatus::YIELD);
|
||||
VerifyInsertAndAdvance(buffer, 3, AnimationFrameBuffer::InsertStatus::YIELD);
|
||||
|
||||
// Attempt to insert a 5th frame, it should fail.
|
||||
RefPtr<imgFrame> frame = CreateEmptyFrame();
|
||||
AnimationFrameBuffer::InsertStatus status = buffer.Insert(std::move(frame));
|
||||
EXPECT_EQ(AnimationFrameBuffer::InsertStatus::YIELD, status);
|
||||
EXPECT_TRUE(buffer.HasRedecodeError());
|
||||
EXPECT_EQ(size_t(0), buffer.PendingDecode());
|
||||
EXPECT_EQ(size_t(4), buffer.Size());
|
||||
}
|
||||
|
||||
TEST_F(ImageAnimationFrameBuffer, RecyclingReset)
|
||||
{
|
||||
const size_t kThreshold = 8;
|
||||
|
@ -647,6 +740,60 @@ TEST_F(ImageAnimationFrameBuffer, RecyclingReset)
|
|||
TestDiscardingQueueReset(buffer, firstFrame, kThreshold, kBatch, kStartFrame);
|
||||
}
|
||||
|
||||
TEST_F(ImageAnimationFrameBuffer, RecyclingResetBeforeComplete)
|
||||
{
|
||||
const size_t kThreshold = 3;
|
||||
const size_t kBatch = 1;
|
||||
const size_t kStartFrame = 0;
|
||||
const IntSize kImageSize(100, 100);
|
||||
const IntRect kImageRect(IntPoint(0, 0), kImageSize);
|
||||
AnimationFrameRetainedBuffer retained(kThreshold, kBatch, kStartFrame);
|
||||
|
||||
// Get the starting buffer to just before the point where we need to switch
|
||||
// to a discarding buffer, reset the animation so advancing points at the
|
||||
// first frame, and insert the last frame to cross the threshold.
|
||||
RefPtr<imgFrame> frame;
|
||||
frame = CreateEmptyFrame(kImageSize, kImageRect, false);
|
||||
AnimationFrameBuffer::InsertStatus status = retained.Insert(std::move(frame));
|
||||
EXPECT_EQ(AnimationFrameBuffer::InsertStatus::CONTINUE, status);
|
||||
|
||||
frame = CreateEmptyFrame(kImageSize, IntRect(IntPoint(10, 10), IntSize(1, 1)), false);
|
||||
status = retained.Insert(std::move(frame));
|
||||
EXPECT_EQ(AnimationFrameBuffer::InsertStatus::YIELD, status);
|
||||
|
||||
VerifyAdvance(retained, 1, true);
|
||||
|
||||
frame = CreateEmptyFrame(kImageSize, IntRect(IntPoint(20, 10), IntSize(1, 1)), false);
|
||||
status = retained.Insert(std::move(frame));
|
||||
EXPECT_EQ(AnimationFrameBuffer::InsertStatus::DISCARD_YIELD, status);
|
||||
|
||||
AnimationFrameRecyclingQueue buffer(std::move(retained));
|
||||
bool restartDecoding = buffer.Reset();
|
||||
EXPECT_TRUE(restartDecoding);
|
||||
|
||||
// None of the buffers were recyclable.
|
||||
EXPECT_TRUE(buffer.Recycle().empty());
|
||||
|
||||
// Reinsert the first two frames as recyclable and reset again.
|
||||
frame = CreateEmptyFrame(kImageSize, kImageRect, true);
|
||||
status = buffer.Insert(std::move(frame));
|
||||
EXPECT_EQ(AnimationFrameBuffer::InsertStatus::CONTINUE, status);
|
||||
|
||||
frame = CreateEmptyFrame(kImageSize, IntRect(IntPoint(10, 10), IntSize(1, 1)), true);
|
||||
status = buffer.Insert(std::move(frame));
|
||||
EXPECT_EQ(AnimationFrameBuffer::InsertStatus::YIELD, status);
|
||||
|
||||
restartDecoding = buffer.Reset();
|
||||
EXPECT_TRUE(restartDecoding);
|
||||
|
||||
// Now both buffers should have been saved and the dirty rect replaced with
|
||||
// the full image rect since we don't know the first frame refresh area yet.
|
||||
EXPECT_EQ(size_t(2), buffer.Recycle().size());
|
||||
for (const auto& entry : buffer.Recycle()) {
|
||||
EXPECT_EQ(kImageRect, entry.mDirtyRect);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ImageAnimationFrameBuffer, RecyclingRect)
|
||||
{
|
||||
const size_t kThreshold = 5;
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/* -*- 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 "mozilla/ipc/InProcessChild.h"
|
||||
#include "mozilla/dom/WindowGlobalChild.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
PWindowGlobalChild*
|
||||
InProcessChild::AllocPWindowGlobalChild(const WindowGlobalInit& aInit)
|
||||
{
|
||||
MOZ_ASSERT_UNREACHABLE("PWindowGlobalChild should not be created manually");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
InProcessChild::DeallocPWindowGlobalChild(PWindowGlobalChild* aActor)
|
||||
{
|
||||
// Free IPC-held reference
|
||||
static_cast<WindowGlobalChild*>(aActor)->Release();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,66 @@
|
|||
/* -*- 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_ipc_InProcessChild_h
|
||||
#define mozilla_ipc_InProcessChild_h
|
||||
|
||||
#include "mozilla/ipc/PInProcessChild.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class PWindowGlobalParent;
|
||||
class PWindowGlobalChild;
|
||||
} // namespace dom
|
||||
|
||||
namespace ipc {
|
||||
|
||||
class InProcessParent;
|
||||
|
||||
/**
|
||||
* The `InProcessChild` class represents the child half of a main-thread to
|
||||
* main-thread actor.
|
||||
*
|
||||
* The `PInProcess` actor should be used as an alternate manager to `PContent`
|
||||
* for async actors which want to communicate uniformly between Content->Chrome
|
||||
* and Chrome->Chrome situations.
|
||||
*/
|
||||
class InProcessChild : public PInProcessChild
|
||||
{
|
||||
public:
|
||||
friend class InProcessParent;
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(InProcessChild)
|
||||
|
||||
// Get the singleton instance of this actor.
|
||||
static InProcessChild* Singleton();
|
||||
|
||||
// Get the parent side of the in-process child actor |aActor|. If |aActor| is
|
||||
// not an in-process actor, or is not connected, this method will return
|
||||
// |nullptr|.
|
||||
static IProtocol* ParentActorFor(IProtocol* aActor);
|
||||
|
||||
protected:
|
||||
virtual mozilla::dom::PWindowGlobalChild*
|
||||
AllocPWindowGlobalChild(const WindowGlobalInit& aInit) override;
|
||||
|
||||
virtual bool
|
||||
DeallocPWindowGlobalChild(mozilla::dom::PWindowGlobalChild* aActor) override;
|
||||
|
||||
private:
|
||||
// NOTE: PInProcess lifecycle management is declared as staic methods and
|
||||
// state on InProcessParent, and implemented in InProcessImpl.cpp.
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
virtual void DeallocPInProcessChild() override;
|
||||
~InProcessChild() = default;
|
||||
|
||||
static StaticRefPtr<InProcessChild> sSingleton;
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // defined(mozilla_ipc_InProcessChild_h)
|
|
@ -0,0 +1,212 @@
|
|||
/* -*- 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 "mozilla/ipc/InProcessParent.h"
|
||||
#include "mozilla/ipc/InProcessChild.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "mozilla/Services.h"
|
||||
|
||||
// This file contains the implementation of core InProcess lifecycle management
|
||||
// facilities.
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
StaticRefPtr<InProcessParent> InProcessParent::sSingleton;
|
||||
StaticRefPtr<InProcessChild> InProcessChild::sSingleton;
|
||||
bool InProcessParent::sShutdown = false;
|
||||
|
||||
|
||||
//////////////////////////////////////////
|
||||
// InProcess actor lifecycle management //
|
||||
//////////////////////////////////////////
|
||||
|
||||
/* static */ InProcessChild*
|
||||
InProcessChild::Singleton() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!sSingleton) {
|
||||
InProcessParent::Startup();
|
||||
}
|
||||
return sSingleton;
|
||||
}
|
||||
|
||||
/* static */ InProcessParent*
|
||||
InProcessParent::Singleton() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!sSingleton) {
|
||||
InProcessParent::Startup();
|
||||
}
|
||||
return sSingleton;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
InProcessParent::Startup()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (sShutdown) {
|
||||
NS_WARNING("Could not get in-process actor while shutting down!");
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (!obs) {
|
||||
sShutdown = true;
|
||||
NS_WARNING("Failed to get nsIObserverService for in-process actor");
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<InProcessParent> parent = new InProcessParent();
|
||||
RefPtr<InProcessChild> child = new InProcessChild();
|
||||
|
||||
// Observe the shutdown event to close & clean up after ourselves.
|
||||
nsresult rv = obs->AddObserver(parent, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Link the two actors
|
||||
if (!child->OpenOnSameThread(parent->GetIPCChannel(), ChildSide)) {
|
||||
MOZ_CRASH("Failed to open InProcessChild!");
|
||||
}
|
||||
|
||||
parent->SetOtherProcessId(base::GetCurrentProcId());
|
||||
|
||||
// Create references held by the IPC layer which will be freed in
|
||||
// DeallocPInProcess{Parent,Child}.
|
||||
parent.get()->AddRef();
|
||||
child.get()->AddRef();
|
||||
|
||||
// Stash global references to fetch the other side of the reference.
|
||||
InProcessParent::sSingleton = parent.forget();
|
||||
InProcessChild::sSingleton = child.forget();
|
||||
}
|
||||
|
||||
|
||||
/* static */ void
|
||||
InProcessParent::Shutdown()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!sSingleton || sShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
sShutdown = true;
|
||||
|
||||
RefPtr<InProcessParent> parent = sSingleton;
|
||||
InProcessParent::sSingleton = nullptr;
|
||||
InProcessChild::sSingleton = nullptr;
|
||||
|
||||
// Calling `Close` on the actor will cause the `Dealloc` methods to be called,
|
||||
// freeing the remaining references.
|
||||
parent->Close();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
InProcessParent::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
|
||||
{
|
||||
MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID));
|
||||
InProcessParent::Shutdown();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
InProcessParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
InProcessParent::Shutdown();
|
||||
}
|
||||
|
||||
void
|
||||
InProcessChild::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
InProcessParent::Shutdown();
|
||||
}
|
||||
|
||||
void
|
||||
InProcessParent::DeallocPInProcessParent()
|
||||
{
|
||||
MOZ_ASSERT(!InProcessParent::sSingleton);
|
||||
Release(); // Release the reference taken in InProcessParent::Startup.
|
||||
}
|
||||
|
||||
void
|
||||
InProcessChild::DeallocPInProcessChild()
|
||||
{
|
||||
MOZ_ASSERT(!InProcessChild::sSingleton);
|
||||
Release(); // Release the reference taken in InProcessParent::Startup.
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
// In-Process Actor Utilities //
|
||||
////////////////////////////////
|
||||
|
||||
// Helper method for implementing ParentActorFor and ChildActorFor.
|
||||
static IProtocol*
|
||||
GetOtherInProcessActor(IProtocol* aActor)
|
||||
{
|
||||
MOZ_ASSERT(aActor->GetSide() != UnknownSide, "bad unknown side");
|
||||
|
||||
// Discover the manager of aActor which is PInProcess.
|
||||
IProtocol* current = aActor;
|
||||
while (current) {
|
||||
if (current->GetProtocolTypeId() == PInProcessMsgStart) {
|
||||
break; // Found the correct actor.
|
||||
}
|
||||
current = current->Manager();
|
||||
}
|
||||
if (!current) {
|
||||
return nullptr; // Not a PInProcess actor, return |nullptr|
|
||||
}
|
||||
|
||||
MOZ_ASSERT(current->GetSide() == aActor->GetSide(), "side changed?");
|
||||
MOZ_ASSERT_IF(aActor->GetSide() == ParentSide,
|
||||
current == InProcessParent::Singleton());
|
||||
MOZ_ASSERT_IF(aActor->GetSide() == ChildSide,
|
||||
current == InProcessChild::Singleton());
|
||||
|
||||
// Check whether this is InProcessParent or InProcessChild, and get the other
|
||||
// side's toplevel actor.
|
||||
IProtocol* otherRoot = nullptr;
|
||||
if (aActor->GetSide() == ParentSide) {
|
||||
otherRoot = InProcessChild::Singleton();
|
||||
} else {
|
||||
otherRoot = InProcessParent::Singleton();
|
||||
}
|
||||
if (NS_WARN_IF(!otherRoot)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Look up the actor on the other side, and return it.
|
||||
IProtocol* otherActor = otherRoot->Lookup(aActor->Id());
|
||||
if (otherActor) {
|
||||
MOZ_ASSERT(otherActor->GetSide() != UnknownSide, "bad unknown side");
|
||||
MOZ_ASSERT(otherActor->GetSide() != aActor->GetSide(), "Wrong side!");
|
||||
MOZ_ASSERT(otherActor->GetProtocolTypeId() == aActor->GetProtocolTypeId(),
|
||||
"Wrong type of protocol!");
|
||||
}
|
||||
|
||||
return otherActor;
|
||||
}
|
||||
|
||||
/* static */ IProtocol*
|
||||
InProcessParent::ChildActorFor(IProtocol* aActor)
|
||||
{
|
||||
MOZ_ASSERT(aActor && aActor->GetSide() == ParentSide);
|
||||
return GetOtherInProcessActor(aActor);
|
||||
}
|
||||
|
||||
/* static */ IProtocol*
|
||||
InProcessChild::ParentActorFor(IProtocol* aActor)
|
||||
{
|
||||
MOZ_ASSERT(aActor && aActor->GetSide() == ChildSide);
|
||||
return GetOtherInProcessActor(aActor);
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,41 @@
|
|||
/* -*- 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 "mozilla/ipc/InProcessParent.h"
|
||||
#include "mozilla/dom/WindowGlobalParent.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
NS_IMPL_ISUPPORTS(InProcessParent, nsIObserver)
|
||||
|
||||
IPCResult
|
||||
InProcessParent::RecvPWindowGlobalConstructor(PWindowGlobalParent* aActor,
|
||||
const WindowGlobalInit& aInit)
|
||||
{
|
||||
static_cast<WindowGlobalParent*>(aActor)->Init(aInit);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
PWindowGlobalParent*
|
||||
InProcessParent::AllocPWindowGlobalParent(const WindowGlobalInit& aInit)
|
||||
{
|
||||
// Reference freed in DeallocPWindowGlobalParent.
|
||||
return do_AddRef(new WindowGlobalParent(aInit, /* inproc */ true)).take();
|
||||
}
|
||||
|
||||
bool
|
||||
InProcessParent::DeallocPWindowGlobalParent(PWindowGlobalParent* aActor)
|
||||
{
|
||||
// Free IPC-held reference.
|
||||
static_cast<WindowGlobalParent*>(aActor)->Release();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,76 @@
|
|||
/* -*- 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_ipc_InProcessParent_h
|
||||
#define mozilla_ipc_InProcessParent_h
|
||||
|
||||
#include "mozilla/ipc/PInProcessParent.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class PWindowGlobalParent;
|
||||
class PWindowGlobalChild;
|
||||
} // namespace dom
|
||||
|
||||
namespace ipc {
|
||||
|
||||
class InProcessChild;
|
||||
|
||||
/**
|
||||
* The `InProcessParent` class represents the parent half of a main-thread to
|
||||
* main-thread actor.
|
||||
*
|
||||
* The `PInProcess` actor should be used as an alternate manager to `PContent`
|
||||
* for async actors which want to communicate uniformly between Content->Chrome
|
||||
* and Chrome->Chrome situations.
|
||||
*/
|
||||
class InProcessParent : public nsIObserver
|
||||
, public PInProcessParent
|
||||
{
|
||||
public:
|
||||
friend class InProcessChild;
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
// Get the singleton instance of this actor.
|
||||
static InProcessParent* Singleton();
|
||||
|
||||
// Get the child side of the in-process child actor |aActor|. If |aActor| is
|
||||
// not an in-process actor, or is not connected, this method will return
|
||||
// |nullptr|.
|
||||
static IProtocol* ChildActorFor(IProtocol* aActor);
|
||||
|
||||
protected:
|
||||
virtual mozilla::dom::PWindowGlobalParent*
|
||||
AllocPWindowGlobalParent(const WindowGlobalInit& aInit) override;
|
||||
|
||||
virtual bool
|
||||
DeallocPWindowGlobalParent(mozilla::dom::PWindowGlobalParent* aActor) override;
|
||||
|
||||
virtual IPCResult
|
||||
RecvPWindowGlobalConstructor(mozilla::dom::PWindowGlobalParent* aActor,
|
||||
const WindowGlobalInit& aInit) override;
|
||||
|
||||
private:
|
||||
// Lifecycle management is implemented in InProcessImpl.cpp
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
virtual void DeallocPInProcessParent() override;
|
||||
~InProcessParent() = default;
|
||||
|
||||
static void Startup();
|
||||
static void Shutdown();
|
||||
|
||||
static StaticRefPtr<InProcessParent> sSingleton;
|
||||
static bool sShutdown;
|
||||
};
|
||||
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // defined(mozilla_ipc_InProcessParent_h)
|
|
@ -584,7 +584,8 @@ MessageChannel::MessageChannel(const char* aName, IToplevelProtocol* aListener)
|
|||
mPeerPidSet(false),
|
||||
mPeerPid(-1),
|
||||
mIsPostponingSends(false),
|
||||
mBuildIDsConfirmedMatch(false) {
|
||||
mBuildIDsConfirmedMatch(false),
|
||||
mIsSameThreadChannel(false) {
|
||||
MOZ_COUNT_CTOR(ipc::MessageChannel);
|
||||
|
||||
#ifdef OS_WIN
|
||||
|
@ -901,6 +902,38 @@ void MessageChannel::CommonThreadOpenInit(MessageChannel* aTargetChan,
|
|||
mSide = aSide;
|
||||
}
|
||||
|
||||
bool MessageChannel::OpenOnSameThread(MessageChannel* aTargetChan,
|
||||
mozilla::ipc::Side aSide) {
|
||||
CommonThreadOpenInit(aTargetChan, aSide);
|
||||
|
||||
Side oppSide = UnknownSide;
|
||||
switch (aSide) {
|
||||
case ChildSide:
|
||||
oppSide = ParentSide;
|
||||
break;
|
||||
case ParentSide:
|
||||
oppSide = ChildSide;
|
||||
break;
|
||||
case UnknownSide:
|
||||
break;
|
||||
}
|
||||
mIsSameThreadChannel = true;
|
||||
|
||||
// XXX(nika): Avoid setting up a monitor for same thread channels? We
|
||||
// shouldn't need it.
|
||||
mMonitor = new RefCountedMonitor();
|
||||
|
||||
mChannelState = ChannelOpening;
|
||||
aTargetChan->CommonThreadOpenInit(this, oppSide);
|
||||
|
||||
aTargetChan->mIsSameThreadChannel = true;
|
||||
aTargetChan->mMonitor = mMonitor;
|
||||
|
||||
mChannelState = ChannelConnected;
|
||||
aTargetChan->mChannelState = ChannelConnected;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MessageChannel::Echo(Message* aMsg) {
|
||||
UniquePtr<Message> msg(aMsg);
|
||||
AssertWorkerThread();
|
||||
|
@ -1377,6 +1410,8 @@ bool MessageChannel::Send(Message* aMsg, Message* aReply) {
|
|||
// Sanity checks.
|
||||
AssertWorkerThread();
|
||||
mMonitor->AssertNotCurrentThreadOwns();
|
||||
MOZ_RELEASE_ASSERT(!mIsSameThreadChannel,
|
||||
"sync send over same-thread channel will deadlock!");
|
||||
|
||||
#ifdef OS_WIN
|
||||
SyncStackFrame frame(this, false);
|
||||
|
@ -1585,6 +1620,8 @@ bool MessageChannel::Call(Message* aMsg, Message* aReply) {
|
|||
UniquePtr<Message> msg(aMsg);
|
||||
AssertWorkerThread();
|
||||
mMonitor->AssertNotCurrentThreadOwns();
|
||||
MOZ_RELEASE_ASSERT(!mIsSameThreadChannel,
|
||||
"intr call send over same-thread channel will deadlock!");
|
||||
|
||||
#ifdef OS_WIN
|
||||
SyncStackFrame frame(this, true);
|
||||
|
@ -2300,6 +2337,9 @@ bool MessageChannel::WaitForSyncNotify(bool /* aHandleWindowsMessages */) {
|
|||
}
|
||||
#endif
|
||||
|
||||
MOZ_RELEASE_ASSERT(!mIsSameThreadChannel,
|
||||
"Wait on same-thread channel will deadlock!");
|
||||
|
||||
TimeDuration timeout = (kNoTimeout == mTimeoutMs)
|
||||
? TimeDuration::Forever()
|
||||
: TimeDuration::FromMilliseconds(mTimeoutMs);
|
||||
|
@ -2580,6 +2620,10 @@ void MessageChannel::SynchronouslyClose() {
|
|||
AssertWorkerThread();
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
mLink->SendClose();
|
||||
|
||||
MOZ_RELEASE_ASSERT(!mIsSameThreadChannel || ChannelClosed == mChannelState,
|
||||
"same-thread channel failed to synchronously close?");
|
||||
|
||||
while (ChannelClosed != mChannelState) mMonitor->Wait();
|
||||
}
|
||||
|
||||
|
|
|
@ -164,6 +164,15 @@ class MessageChannel : HasResultCodes, MessageLoop::DestructionObserver {
|
|||
bool Open(MessageChannel* aTargetChan, nsIEventTarget* aEventTarget,
|
||||
Side aSide);
|
||||
|
||||
// "Open" a connection to an actor on the current thread.
|
||||
//
|
||||
// Returns true if the transport layer was successfully connected,
|
||||
// i.e., mChannelState == ChannelConnected.
|
||||
//
|
||||
// Same-thread channels may not perform synchronous or blocking message
|
||||
// sends, to avoid deadlocks.
|
||||
bool OpenOnSameThread(MessageChannel* aTargetChan, Side aSide);
|
||||
|
||||
// Close the underlying transport channel.
|
||||
void Close();
|
||||
|
||||
|
@ -530,10 +539,19 @@ class MessageChannel : HasResultCodes, MessageLoop::DestructionObserver {
|
|||
"not on worker thread!");
|
||||
}
|
||||
|
||||
// The "link" thread is either the I/O thread (ProcessLink) or the
|
||||
// other actor's work thread (ThreadLink). In either case, it is
|
||||
// NOT our worker thread.
|
||||
// The "link" thread is either the I/O thread (ProcessLink), the other
|
||||
// actor's work thread (ThreadLink), or the worker thread (same-thread
|
||||
// channels).
|
||||
void AssertLinkThread() const {
|
||||
if (mIsSameThreadChannel) {
|
||||
// If we're a same-thread channel, we have to be on our worker
|
||||
// thread.
|
||||
AssertWorkerThread();
|
||||
return;
|
||||
}
|
||||
|
||||
// If we aren't a same-thread channel, our "link" thread is _not_ our
|
||||
// worker thread!
|
||||
MOZ_ASSERT(mWorkerThread, "Channel hasn't been opened yet");
|
||||
MOZ_RELEASE_ASSERT(mWorkerThread != GetCurrentVirtualThread(),
|
||||
"on worker thread but should not be!");
|
||||
|
@ -827,6 +845,10 @@ class MessageChannel : HasResultCodes, MessageLoop::DestructionObserver {
|
|||
std::vector<UniquePtr<Message>> mPostponedSends;
|
||||
|
||||
bool mBuildIDsConfirmedMatch;
|
||||
|
||||
// If this is true, both ends of this message channel have event targets
|
||||
// on the same thread.
|
||||
bool mIsSameThreadChannel;
|
||||
};
|
||||
|
||||
void CancelCPOWs();
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
|
||||
/* 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 protocol PWindowGlobal;
|
||||
|
||||
include DOMTypes;
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
/**
|
||||
* PInProcess is intended for use as an alternative actor manager to PContent
|
||||
* for async actors which want to be used uniformly in both Content->Chrome and
|
||||
* Chrome->Chrome circumstances.
|
||||
*
|
||||
* `mozilla::ipc::InProcess{Parent, Child}::Singleton()` should be used to get
|
||||
* an instance of this actor.
|
||||
*/
|
||||
async protocol PInProcess
|
||||
{
|
||||
manages PWindowGlobal;
|
||||
|
||||
parent:
|
||||
/**
|
||||
* Construct a new WindowGlobal actor for a window global in the given
|
||||
* BrowsingContext and with the given principal.
|
||||
*/
|
||||
async PWindowGlobal(WindowGlobalInit init);
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
|
@ -627,6 +627,11 @@ bool IToplevelProtocol::OpenWithAsyncPid(mozilla::ipc::Transport* aTransport,
|
|||
return GetIPCChannel()->Open(aTransport, aThread, aSide);
|
||||
}
|
||||
|
||||
bool IToplevelProtocol::OpenOnSameThread(MessageChannel* aChannel, Side aSide) {
|
||||
SetOtherProcessId(base::GetCurrentProcId());
|
||||
return GetIPCChannel()->OpenOnSameThread(aChannel, aSide);
|
||||
}
|
||||
|
||||
void IToplevelProtocol::Close() { GetIPCChannel()->Close(); }
|
||||
|
||||
void IToplevelProtocol::SetReplyTimeoutMs(int32_t aTimeoutMs) {
|
||||
|
@ -637,13 +642,29 @@ bool IToplevelProtocol::IsOnCxxStack() const {
|
|||
return GetIPCChannel()->IsOnCxxStack();
|
||||
}
|
||||
|
||||
int32_t IToplevelProtocol::ToplevelState::NextId() {
|
||||
// Genreate the next ID to use for a shared memory or protocol. Parent and
|
||||
// Child sides of the protocol use different pools, and actors created in the
|
||||
// middleman need to use a distinct pool as well.
|
||||
int32_t tag = 0;
|
||||
if (recordreplay::IsMiddleman()) {
|
||||
tag |= 1 << 0;
|
||||
}
|
||||
if (mProtocol->GetSide() == ParentSide) {
|
||||
tag |= 1 << 1;
|
||||
}
|
||||
|
||||
// Compute the ID to use with the low two bits as our tag, and the remaining
|
||||
// bits as a monotonic.
|
||||
return (++mLastLocalId << 2) | tag;
|
||||
}
|
||||
|
||||
int32_t IToplevelProtocol::ToplevelState::Register(IProtocol* aRouted) {
|
||||
if (aRouted->Id() != kNullActorId && aRouted->Id() != kFreedActorId) {
|
||||
// If there's already an ID, just return that.
|
||||
return aRouted->Id();
|
||||
}
|
||||
int32_t id =
|
||||
mProtocol->GetSide() == ParentSide ? ++mLastRouteId : --mLastRouteId;
|
||||
int32_t id = NextId();
|
||||
mActorMap.AddWithID(aRouted, id);
|
||||
aRouted->SetId(id);
|
||||
|
||||
|
@ -682,8 +703,7 @@ IToplevelProtocol::ToplevelState::ToplevelState(const char* aName,
|
|||
Side aSide)
|
||||
: ProtocolState(),
|
||||
mProtocol(aProtocol),
|
||||
mLastRouteId(aSide == ParentSide ? kFreedActorId : kNullActorId),
|
||||
mLastShmemId(aSide == ParentSide ? kFreedActorId : kNullActorId),
|
||||
mLastLocalId(0),
|
||||
mEventTargetMutex("ProtocolEventTargetMutex"),
|
||||
mChannel(aName, aProtocol) {}
|
||||
|
||||
|
@ -696,8 +716,7 @@ Shmem::SharedMemory* IToplevelProtocol::ToplevelState::CreateSharedMemory(
|
|||
if (!segment) {
|
||||
return nullptr;
|
||||
}
|
||||
int32_t id =
|
||||
mProtocol->GetSide() == ParentSide ? ++mLastShmemId : --mLastShmemId;
|
||||
int32_t id = NextId();
|
||||
Shmem shmem(Shmem::PrivateIPDLCaller(), segment.get(), id);
|
||||
|
||||
base::ProcessId pid =
|
||||
|
|
|
@ -438,11 +438,12 @@ class IToplevelProtocol : public IProtocol {
|
|||
MessageChannel* GetIPCChannel() override;
|
||||
|
||||
private:
|
||||
int32_t NextId();
|
||||
|
||||
IToplevelProtocol* const mProtocol;
|
||||
int32_t mLastLocalId;
|
||||
IDMap<IProtocol*> mActorMap;
|
||||
int32_t mLastRouteId;
|
||||
IDMap<Shmem::SharedMemory*> mShmemMap;
|
||||
Shmem::id_t mLastShmemId;
|
||||
|
||||
Mutex mEventTargetMutex;
|
||||
IDMap<nsCOMPtr<nsIEventTarget>> mEventTargetMap;
|
||||
|
@ -482,6 +483,15 @@ class IToplevelProtocol : public IProtocol {
|
|||
MessageLoop* aThread = nullptr,
|
||||
mozilla::ipc::Side aSide = mozilla::ipc::UnknownSide);
|
||||
|
||||
// Open a toplevel actor such that both ends of the actor's channel are on
|
||||
// the same thread. This method should be called on the thread to perform
|
||||
// the link.
|
||||
//
|
||||
// WARNING: Attempting to send a sync or intr message on the same thread
|
||||
// will crash.
|
||||
bool OpenOnSameThread(MessageChannel* aChannel,
|
||||
mozilla::ipc::Side aSide = mozilla::ipc::UnknownSide);
|
||||
|
||||
void Close();
|
||||
|
||||
void SetReplyTimeoutMs(int32_t aTimeoutMs);
|
||||
|
|
|
@ -27,6 +27,8 @@ EXPORTS.mozilla.ipc += [
|
|||
'FileDescriptorSetParent.h',
|
||||
'FileDescriptorUtils.h',
|
||||
'GeckoChildProcessHost.h',
|
||||
'InProcessChild.h',
|
||||
'InProcessParent.h',
|
||||
'InputStreamUtils.h',
|
||||
'IOThreadChild.h',
|
||||
'IPCStreamAlloc.h',
|
||||
|
@ -147,6 +149,9 @@ UNIFIED_SOURCES += [
|
|||
'CrashReporterMetadataShmem.cpp',
|
||||
'FileDescriptor.cpp',
|
||||
'FileDescriptorUtils.cpp',
|
||||
'InProcessChild.cpp',
|
||||
'InProcessImpl.cpp',
|
||||
'InProcessParent.cpp',
|
||||
'InputStreamUtils.cpp',
|
||||
'IPCMessageUtils.cpp',
|
||||
'IPCStreamChild.cpp',
|
||||
|
@ -208,6 +213,7 @@ IPDL_SOURCES = [
|
|||
'PBackgroundTest.ipdl',
|
||||
'PChildToParentStream.ipdl',
|
||||
'PFileDescriptorSet.ipdl',
|
||||
'PInProcess.ipdl',
|
||||
'PParentToChildStream.ipdl',
|
||||
'ProtocolTypes.ipdlh',
|
||||
'URIParams.ipdlh',
|
||||
|
|
|
@ -3910,13 +3910,31 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
|
|||
|
||||
msgvar, stmts = self.makeMessage(md, errfnSendCtor)
|
||||
sendok, sendstmts = self.sendAsync(md, msgvar)
|
||||
|
||||
warnif = StmtIf(ExprNot(sendok))
|
||||
warnif.addifstmt(_printWarningMessage('Error sending constructor'))
|
||||
|
||||
method.addstmts(
|
||||
# Build our constructor message & verify it.
|
||||
stmts
|
||||
+ self.genVerifyMessage(md.decl.type.verify, md.params,
|
||||
errfnSendCtor, ExprVar('msg__'))
|
||||
|
||||
# Notify the other side about the newly created actor.
|
||||
#
|
||||
# If the MessageChannel is closing, and we haven't been told yet,
|
||||
# this send may fail. This error is ignored to treat it like a
|
||||
# message being lost due to the other side shutting down before
|
||||
# processing it.
|
||||
#
|
||||
# NOTE: We don't free the actor here, as our caller may be
|
||||
# depending on it being alive after calling SendConstructor.
|
||||
+ sendstmts
|
||||
+ self.failCtorIf(md, ExprNot(sendok))
|
||||
+ [StmtReturn(actor.var())])
|
||||
|
||||
# Warn if the message failed to send, and return our newly created
|
||||
# actor.
|
||||
+ [warnif,
|
||||
StmtReturn(actor.var())])
|
||||
|
||||
lbl = CaseLabel(md.pqReplyId())
|
||||
case = StmtBlock()
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
add_task(async function() {
|
||||
const kPrefName_AutoScroll = "general.autoScroll";
|
||||
Services.prefs.setBoolPref(kPrefName_AutoScroll, true);
|
||||
registerCleanupFunction(() => Services.prefs.clearUserPref(kPrefName_AutoScroll));
|
||||
|
||||
const kNoKeyEvents = 0;
|
||||
const kKeyDownEvent = 1;
|
||||
|
@ -61,55 +62,52 @@ add_task(async function() {
|
|||
|
||||
var dataUri = 'data:text/html,<body style="height:10000px;"></body>';
|
||||
|
||||
let loadedPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
BrowserTestUtils.loadURI(gBrowser, dataUri);
|
||||
await loadedPromise;
|
||||
await BrowserTestUtils.withNewTab(dataUri, async function(browser) {
|
||||
info("Loaded data URI in new tab");
|
||||
await SimpleTest.promiseFocus(browser);
|
||||
info("Focused selected browser");
|
||||
|
||||
await SimpleTest.promiseFocus(gBrowser.selectedBrowser);
|
||||
window.addEventListener("keydown", onKey);
|
||||
window.addEventListener("keypress", onKey);
|
||||
window.addEventListener("keyup", onKey);
|
||||
registerCleanupFunction(() => {
|
||||
window.removeEventListener("keydown", onKey);
|
||||
window.removeEventListener("keypress", onKey);
|
||||
window.removeEventListener("keyup", onKey);
|
||||
});
|
||||
|
||||
window.addEventListener("keydown", onKey);
|
||||
window.addEventListener("keypress", onKey);
|
||||
window.addEventListener("keyup", onKey);
|
||||
// Test whether the key events are handled correctly under normal condition
|
||||
expectedKeyEvents = kAllKeyEvents;
|
||||
sendChar("A");
|
||||
|
||||
// Test whether the key events are handled correctly under normal condition
|
||||
expectedKeyEvents = kAllKeyEvents;
|
||||
sendChar("A");
|
||||
// Start autoscrolling by middle button click on the page
|
||||
info("Creating popup shown promise");
|
||||
let shownPromise = BrowserTestUtils.waitForEvent(window, "popupshown", false,
|
||||
event => event.originalTarget.className == "autoscroller");
|
||||
await BrowserTestUtils.synthesizeMouseAtPoint(10, 10, { button: 1 },
|
||||
gBrowser.selectedBrowser);
|
||||
info("Waiting for autoscroll popup to show");
|
||||
await shownPromise;
|
||||
|
||||
// Start autoscrolling by middle button click on the page
|
||||
let shownPromise = BrowserTestUtils.waitForEvent(window, "popupshown", false,
|
||||
event => event.originalTarget.className == "autoscroller");
|
||||
await BrowserTestUtils.synthesizeMouseAtPoint(10, 10, { button: 1 },
|
||||
gBrowser.selectedBrowser);
|
||||
await shownPromise;
|
||||
// Most key events should be eaten by the browser.
|
||||
expectedKeyEvents = kNoKeyEvents;
|
||||
sendChar("A");
|
||||
sendKey("DOWN");
|
||||
sendKey("RETURN");
|
||||
sendKey("RETURN");
|
||||
sendKey("HOME");
|
||||
sendKey("END");
|
||||
sendKey("TAB");
|
||||
sendKey("RETURN");
|
||||
|
||||
// Most key events should be eaten by the browser.
|
||||
expectedKeyEvents = kNoKeyEvents;
|
||||
sendChar("A");
|
||||
sendKey("DOWN");
|
||||
sendKey("RETURN");
|
||||
sendKey("RETURN");
|
||||
sendKey("HOME");
|
||||
sendKey("END");
|
||||
sendKey("TAB");
|
||||
sendKey("RETURN");
|
||||
// Finish autoscrolling by ESC key. Note that only keydown and keypress
|
||||
// events are eaten because keyup event is fired *after* the autoscrolling
|
||||
// is finished.
|
||||
expectedKeyEvents = kKeyUpEvent;
|
||||
sendKey("ESCAPE");
|
||||
|
||||
// Finish autoscrolling by ESC key. Note that only keydown and keypress
|
||||
// events are eaten because keyup event is fired *after* the autoscrolling
|
||||
// is finished.
|
||||
expectedKeyEvents = kKeyUpEvent;
|
||||
sendKey("ESCAPE");
|
||||
|
||||
// Test whether the key events are handled correctly under normal condition
|
||||
expectedKeyEvents = kAllKeyEvents;
|
||||
sendChar("A");
|
||||
|
||||
window.removeEventListener("keydown", onKey);
|
||||
window.removeEventListener("keypress", onKey);
|
||||
window.removeEventListener("keyup", onKey);
|
||||
|
||||
// restore the changed prefs
|
||||
if (Services.prefs.prefHasUserValue(kPrefName_AutoScroll))
|
||||
Services.prefs.clearUserPref(kPrefName_AutoScroll);
|
||||
|
||||
finish();
|
||||
// Test whether the key events are handled correctly under normal condition
|
||||
expectedKeyEvents = kAllKeyEvents;
|
||||
sendChar("A");
|
||||
});
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче