Skip to content

Commit

Permalink
Bug 1353867 - Change WindowProxyHolder's native type to BrowsingConte…
Browse files Browse the repository at this point in the history
…xt. r=bzbarsky

Make the WindowProxyHolder hold a strong reference to a BrowsingContext, as in the future
we might not have a nsPIDOMWindowOuter (if the document is loaded in a different process).

Differential Revision: https://phabricator.services.mozilla.com/D12651

--HG--
extra : moz-landing-system : lando
  • Loading branch information
petervanderbeken committed Dec 31, 2018
1 parent 68a8855 commit 831826f
Show file tree
Hide file tree
Showing 43 changed files with 275 additions and 187 deletions.
38 changes: 37 additions & 1 deletion docshell/base/BrowsingContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@
#include "mozilla/WeakPtr.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIDocShell.h"
#include "nsString.h"
#include "nsTArray.h"
#include "nsWrapperCache.h"

class nsIDocShell;
class nsGlobalWindowOuter;
class nsOuterWindowProxy;

namespace mozilla {

Expand Down Expand Up @@ -80,6 +82,12 @@ class BrowsingContext : public nsWrapperCache,
nsIDocShell* GetDocShell() { return mDocShell; }
void SetDocShell(nsIDocShell* aDocShell);

// Get the outer window object for this BrowsingContext if it is in-process
// and still has a docshell, or null otherwise.
nsPIDOMWindowOuter* GetDOMWindow() const {
return mDocShell ? mDocShell->GetWindow() : nullptr;
}

// Attach the current BrowsingContext to its parent, in both the child and the
// parent process. BrowsingContext objects are created attached by default, so
// this method need only be called when restoring cached BrowsingContext
Expand Down Expand Up @@ -123,6 +131,13 @@ class BrowsingContext : public nsWrapperCache,
JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;

// Return the window proxy object that corresponds to this browsing context.
inline JSObject* GetWindowProxy() const { return mWindowProxy; }
// Set the window proxy object that corresponds to this browsing context.
void SetWindowProxy(JS::Handle<JSObject*> aWindowProxy) {
mWindowProxy = aWindowProxy;
}

MOZ_DECLARE_WEAKREFERENCE_TYPENAME(BrowsingContext)
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(BrowsingContext)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(BrowsingContext)
Expand All @@ -136,6 +151,22 @@ class BrowsingContext : public nsWrapperCache,
Type aType);

private:
friend class ::nsOuterWindowProxy;
friend class ::nsGlobalWindowOuter;
// Update the window proxy object that corresponds to this browsing context.
// This should be called from the window proxy object's objectMoved hook, if
// the object mWindowProxy points to was moved by the JS GC.
void UpdateWindowProxy(JSObject* obj, JSObject* old) {
if (mWindowProxy) {
MOZ_ASSERT(mWindowProxy == old);
mWindowProxy = obj;
}
}
// Clear the window proxy object that corresponds to this browsing context.
// This should be called if the window proxy object is finalized, or it can't
// reach its browsing context anymore.
void ClearWindowProxy() { mWindowProxy = nullptr; }

// Type of BrowsingContent
const Type mType;

Expand All @@ -148,6 +179,11 @@ class BrowsingContext : public nsWrapperCache,
WeakPtr<BrowsingContext> mOpener;
nsCOMPtr<nsIDocShell> mDocShell;
nsString mName;
// This is not a strong reference, but using a JS::Heap for that should be
// fine. The JSObject stored in here should be a proxy with a
// nsOuterWindowProxy handler, which will update the pointer from its
// objectMoved hook and clear it from its finalize hook.
JS::Heap<JSObject*> mWindowProxy;
};

} // namespace dom
Expand Down
4 changes: 0 additions & 4 deletions docshell/base/nsDocShell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13421,10 +13421,6 @@ nsDocShell::GetColorMatrix(uint32_t* aMatrixLen, float** aMatrix) {

bool nsDocShell::IsForceReloading() { return IsForceReloadType(mLoadType); }

BrowsingContext* nsDocShell::GetBrowsingContext() const {
return mBrowsingContext;
}

NS_IMETHODIMP
nsDocShell::GetBrowsingContext(BrowsingContext** aBrowsingContext) {
*aBrowsingContext = do_AddRef(mBrowsingContext).take();
Expand Down
11 changes: 7 additions & 4 deletions docshell/base/nsDocShell.h
Original file line number Diff line number Diff line change
Expand Up @@ -383,10 +383,13 @@ class nsDocShell final : public nsDocLoader,
// shift while triggering reload)
bool IsForceReloading();

/**
* Native getter for a DocShell's BrowsingContext.
*/
mozilla::dom::BrowsingContext* GetBrowsingContext() const;
mozilla::dom::BrowsingContext* GetBrowsingContext() const {
return mBrowsingContext;
}
mozilla::dom::BrowsingContext* GetWindowProxy() {
EnsureScriptEnvironment();
return mBrowsingContext;
}

/**
* Loads the given URI. See comments on nsDocShellLoadState members for more
Expand Down
14 changes: 5 additions & 9 deletions dom/base/InProcessTabChildMessageManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "InProcessTabChildMessageManager.h"
#include "nsContentUtils.h"
#include "nsDocShell.h"
#include "nsIScriptSecurityManager.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIComponentManager.h"
Expand Down Expand Up @@ -77,7 +78,7 @@ nsresult InProcessTabChildMessageManager::DoSendAsyncMessage(
}

InProcessTabChildMessageManager::InProcessTabChildMessageManager(
nsIDocShell* aShell, nsIContent* aOwner, nsFrameMessageManager* aChrome)
nsDocShell* aShell, nsIContent* aOwner, nsFrameMessageManager* aChrome)
: ContentFrameMessageManager(new nsFrameMessageManager(this)),
mDocShell(aShell),
mLoadingScript(false),
Expand Down Expand Up @@ -150,14 +151,10 @@ void InProcessTabChildMessageManager::CacheFrameLoader(

Nullable<WindowProxyHolder> InProcessTabChildMessageManager::GetContent(
ErrorResult& aError) {
nsCOMPtr<nsPIDOMWindowOuter> content;
if (mDocShell) {
content = mDocShell->GetWindow();
}
if (!content) {
if (!mDocShell) {
return nullptr;
}
return WindowProxyHolder(content);
return WindowProxyHolder(mDocShell->GetBrowsingContext());
}

already_AddRefed<nsIEventTarget>
Expand All @@ -171,9 +168,8 @@ uint64_t InProcessTabChildMessageManager::ChromeOuterWindowID() {
return 0;
}

nsCOMPtr<nsIDocShellTreeItem> item = mDocShell;
nsCOMPtr<nsIDocShellTreeItem> root;
nsresult rv = item->GetRootTreeItem(getter_AddRefs(root));
nsresult rv = mDocShell->GetRootTreeItem(getter_AddRefs(root));
if (NS_WARN_IF(NS_FAILED(rv))) {
return 0;
}
Expand Down
11 changes: 5 additions & 6 deletions dom/base/InProcessTabChildMessageManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#include "nsIScriptObjectPrincipal.h"
#include "nsIScriptContext.h"
#include "nsIClassInfo.h"
#include "nsIDocShell.h"
#include "nsDocShell.h"
#include "nsCOMArray.h"
#include "nsIRunnable.h"
#include "nsWeakReference.h"
Expand All @@ -42,12 +42,12 @@ class InProcessTabChildMessageManager final
typedef mozilla::dom::ipc::StructuredCloneData StructuredCloneData;

private:
InProcessTabChildMessageManager(nsIDocShell* aShell, nsIContent* aOwner,
InProcessTabChildMessageManager(nsDocShell* aShell, nsIContent* aOwner,
nsFrameMessageManager* aChrome);

public:
static already_AddRefed<InProcessTabChildMessageManager> Create(
nsIDocShell* aShell, nsIContent* aOwner, nsFrameMessageManager* aChrome) {
nsDocShell* aShell, nsIContent* aOwner, nsFrameMessageManager* aChrome) {
RefPtr<InProcessTabChildMessageManager> mm =
new InProcessTabChildMessageManager(aShell, aOwner, aChrome);

Expand All @@ -68,8 +68,7 @@ class InProcessTabChildMessageManager final
Nullable<WindowProxyHolder> GetContent(ErrorResult& aError) override;
virtual already_AddRefed<nsIDocShell> GetDocShell(
ErrorResult& aError) override {
nsCOMPtr<nsIDocShell> docShell(mDocShell);
return docShell.forget();
return do_AddRef(mDocShell);
}
virtual already_AddRefed<nsIEventTarget> GetTabEventTarget() override;
virtual uint64_t ChromeOuterWindowID() override;
Expand Down Expand Up @@ -120,7 +119,7 @@ class InProcessTabChildMessageManager final
protected:
virtual ~InProcessTabChildMessageManager();

nsCOMPtr<nsIDocShell> mDocShell;
RefPtr<nsDocShell> mDocShell;
bool mLoadingScript;

// Is this the message manager for an in-process <iframe mozbrowser>? This
Expand Down
9 changes: 6 additions & 3 deletions dom/base/PostMessageEvent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "mozilla/dom/UnionConversions.h"
#include "mozilla/EventDispatcher.h"
#include "nsContentUtils.h"
#include "nsDocShell.h"
#include "nsGlobalWindow.h"
#include "nsIPresShell.h"
#include "nsIPrincipal.h"
Expand All @@ -29,7 +30,7 @@
namespace mozilla {
namespace dom {

PostMessageEvent::PostMessageEvent(nsGlobalWindowOuter* aSource,
PostMessageEvent::PostMessageEvent(BrowsingContext* aSource,
const nsAString& aCallerOrigin,
nsGlobalWindowOuter* aTargetWindow,
nsIPrincipal* aProvidedPrincipal,
Expand Down Expand Up @@ -138,7 +139,9 @@ PostMessageEvent::Run() {
RefPtr<MessageEvent> event = new MessageEvent(eventTarget, nullptr, nullptr);

Nullable<WindowProxyOrMessagePortOrServiceWorker> source;
source.SetValue().SetAsWindowProxy() = mSource ? mSource->AsOuter() : nullptr;
if (mSource) {
source.SetValue().SetAsWindowProxy() = mSource;
}

Sequence<OwningNonNull<MessagePort>> ports;
if (!TakeTransferredPortsAsSequence(ports)) {
Expand All @@ -163,7 +166,7 @@ void PostMessageEvent::DispatchError(JSContext* aCx,
init.mOrigin = mCallerOrigin;

if (mSource) {
init.mSource.SetValue().SetAsWindowProxy() = mSource->AsOuter();
init.mSource.SetValue().SetAsWindowProxy() = mSource;
}

RefPtr<Event> event = MessageEvent::Constructor(
Expand Down
6 changes: 4 additions & 2 deletions dom/base/PostMessageEvent.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ class nsIPrincipal;
namespace mozilla {
namespace dom {

class BrowsingContext;

/**
* Class used to represent events generated by calls to Window.postMessage,
* which asynchronously creates and dispatches events.
Expand All @@ -30,7 +32,7 @@ class PostMessageEvent final : public Runnable, public StructuredCloneHolder {
public:
NS_DECL_NSIRUNNABLE

PostMessageEvent(nsGlobalWindowOuter* aSource, const nsAString& aCallerOrigin,
PostMessageEvent(BrowsingContext* aSource, const nsAString& aCallerOrigin,
nsGlobalWindowOuter* aTargetWindow,
nsIPrincipal* aProvidedPrincipal,
nsIDocument* aSourceDocument);
Expand All @@ -43,7 +45,7 @@ class PostMessageEvent final : public Runnable, public StructuredCloneHolder {
void DispatchError(JSContext* aCx, nsGlobalWindowInner* aTargetWindow,
mozilla::dom::EventTarget* aEventTarget);

RefPtr<nsGlobalWindowOuter> mSource;
RefPtr<BrowsingContext> mSource;
nsString mCallerOrigin;
RefPtr<nsGlobalWindowOuter> mTargetWindow;
nsCOMPtr<nsIPrincipal> mProvidedPrincipal;
Expand Down
17 changes: 9 additions & 8 deletions dom/base/WindowNamedPropertiesHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@ namespace mozilla {
namespace dom {

static bool ShouldExposeChildWindow(nsString& aNameBeingResolved,
nsPIDOMWindowOuter* aChild) {
Element* e = aChild->GetFrameElementInternal();
BrowsingContext* aChild) {
nsPIDOMWindowOuter* child = aChild->GetDOMWindow();
Element* e = child->GetFrameElementInternal();
if (e && e->IsInShadowTree()) {
return false;
}

// If we're same-origin with the child, go ahead and expose it.
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aChild);
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(child);
NS_ENSURE_TRUE(sop, false);
if (nsContentUtils::SubjectPrincipal()->Equals(sop->GetPrincipal())) {
return true;
Expand Down Expand Up @@ -100,13 +101,13 @@ bool WindowNamedPropertiesHandler::getOwnPropDescriptor(
// Grab the DOM window.
nsGlobalWindowInner* win = xpc::WindowGlobalOrNull(aProxy);
if (win->Length() > 0) {
nsCOMPtr<nsPIDOMWindowOuter> childWin = win->GetChildWindow(str);
if (childWin && ShouldExposeChildWindow(str, childWin)) {
RefPtr<BrowsingContext> child = win->GetChildWindow(str);
if (child && ShouldExposeChildWindow(str, child)) {
// We found a subframe of the right name. Shadowing via |var foo| in
// global scope is still allowed, since |var| only looks up |own|
// properties. But unqualified shadowing will fail, per-spec.
JS::Rooted<JS::Value> v(aCx);
if (!ToJSValue(aCx, nsGlobalWindowOuter::Cast(childWin), &v)) {
if (!ToJSValue(aCx, WindowProxyHolder(child.forget()), &v)) {
return false;
}
FillPropertyDescriptor(aDesc, aProxy, 0, v);
Expand Down Expand Up @@ -182,8 +183,8 @@ bool WindowNamedPropertiesHandler::ownPropNames(
item->GetName(name);
if (!names.Contains(name)) {
// Make sure we really would expose it from getOwnPropDescriptor.
nsCOMPtr<nsPIDOMWindowOuter> childWin = win->GetChildWindow(name);
if (childWin && ShouldExposeChildWindow(name, childWin)) {
RefPtr<BrowsingContext> child = win->GetChildWindow(name);
if (child && ShouldExposeChildWindow(name, child)) {
names.AppendElement(name);
}
}
Expand Down
36 changes: 18 additions & 18 deletions dom/base/WindowProxyHolder.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#ifndef mozilla_dom_WindowProxyHolder_h__
#define mozilla_dom_WindowProxyHolder_h__

#include "nsPIDOMWindow.h"
#include "mozilla/dom/BrowsingContext.h"

namespace mozilla {
namespace dom {
Expand All @@ -22,43 +22,43 @@ namespace dom {
class WindowProxyHolder {
public:
WindowProxyHolder() = default;
explicit WindowProxyHolder(nsPIDOMWindowOuter* aWin) : mWindow(aWin) {
MOZ_ASSERT(mWindow, "Don't set WindowProxyHolder to null.");
explicit WindowProxyHolder(BrowsingContext* aBC) : mBrowsingContext(aBC) {
MOZ_ASSERT(mBrowsingContext, "Don't set WindowProxyHolder to null.");
}
explicit WindowProxyHolder(already_AddRefed<nsPIDOMWindowOuter>&& aWin)
: mWindow(std::move(aWin)) {
MOZ_ASSERT(mWindow, "Don't set WindowProxyHolder to null.");
explicit WindowProxyHolder(already_AddRefed<BrowsingContext>&& aBC)
: mBrowsingContext(std::move(aBC)) {
MOZ_ASSERT(mBrowsingContext, "Don't set WindowProxyHolder to null.");
}
WindowProxyHolder& operator=(nsPIDOMWindowOuter* aWin) {
mWindow = aWin;
MOZ_ASSERT(mWindow, "Don't set WindowProxyHolder to null.");
WindowProxyHolder& operator=(BrowsingContext* aBC) {
mBrowsingContext = aBC;
MOZ_ASSERT(mBrowsingContext, "Don't set WindowProxyHolder to null.");
return *this;
}
WindowProxyHolder& operator=(already_AddRefed<nsPIDOMWindowOuter>&& aWin) {
mWindow = std::move(aWin);
MOZ_ASSERT(mWindow, "Don't set WindowProxyHolder to null.");
WindowProxyHolder& operator=(already_AddRefed<BrowsingContext>&& aBC) {
mBrowsingContext = std::move(aBC);
MOZ_ASSERT(mBrowsingContext, "Don't set WindowProxyHolder to null.");
return *this;
}

nsPIDOMWindowOuter* get() const {
MOZ_ASSERT(mWindow, "WindowProxyHolder hasn't been initialized.");
return mWindow;
BrowsingContext* get() const {
MOZ_ASSERT(mBrowsingContext, "WindowProxyHolder hasn't been initialized.");
return mBrowsingContext;
}

private:
friend void ImplCycleCollectionUnlink(WindowProxyHolder& aProxy);

nsCOMPtr<nsPIDOMWindowOuter> mWindow;
RefPtr<BrowsingContext> mBrowsingContext;
};

inline void ImplCycleCollectionTraverse(
nsCycleCollectionTraversalCallback& aCallback, WindowProxyHolder& aProxy,
const char* aName, uint32_t aFlags = 0) {
CycleCollectionNoteChild(aCallback, aProxy.get(), "mWindow", aFlags);
CycleCollectionNoteChild(aCallback, aProxy.get(), "mBrowsingContext", aFlags);
}

inline void ImplCycleCollectionUnlink(WindowProxyHolder& aProxy) {
aProxy.mWindow = nullptr;
aProxy.mBrowsingContext = nullptr;
}

} // namespace dom
Expand Down
2 changes: 1 addition & 1 deletion dom/base/nsDocument.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3374,7 +3374,7 @@ Nullable<WindowProxyHolder> nsIDocument::GetDefaultView() const {
if (!win) {
return nullptr;
}
return WindowProxyHolder(win);
return WindowProxyHolder(win->GetBrowsingContext());
}

Element* nsIDocument::GetActiveElement() {
Expand Down
Loading

0 comments on commit 831826f

Please sign in to comment.