Skip to content

Commit

Permalink
Bug 1873330 - Part 5: Add UserActivation::Modifiers parameters for wi…
Browse files Browse the repository at this point in the history
…ndow.open-related functions. r=smaug

Pass UserActivation::Modifiers from nsGlobalWindowOuter::OpenInternal
to nsPIWindowWatcher.openWindowWithRemoteTab, through the following interfaces
and protocol:
  * nsPIWindowWatcher.openWindow2
  * nsIWindowProvider.provideWindow
  * PContent.CreateWindow or PContent.CreateWindowInDifferentProcess
  * nsPIWindowWatcher.openWindowWithRemoteTab

Differential Revision: https://phabricator.services.mozilla.com/D197863
  • Loading branch information
arai-a committed Jan 11, 2024
1 parent da72302 commit f38e7a2
Show file tree
Hide file tree
Showing 14 changed files with 124 additions and 61 deletions.
9 changes: 7 additions & 2 deletions dom/base/UserActivation.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
#include "nsWrapperCache.h"
#include "nsPIDOMWindow.h"

namespace IPC {
template <class P>
struct ParamTraits;
} // namespace IPC

namespace mozilla::dom {

class UserActivation final : public nsISupports, public nsWrapperCache {
Expand Down Expand Up @@ -62,8 +67,6 @@ class UserActivation final : public nsISupports, public nsWrapperCache {

static constexpr Modifiers None() { return Modifiers(0); }

uint8_t GetRawData() const { return mModifiers; }

void SetShift() { mModifiers |= Shift; }
void SetMeta() { mModifiers |= Meta; }
void SetControl() { mModifiers |= Control; }
Expand All @@ -78,6 +81,8 @@ class UserActivation final : public nsISupports, public nsWrapperCache {
uint8_t mModifiers = 0;

friend class StateAndModifiers;
template <class P>
friend struct IPC::ParamTraits;
};

// State and Modifiers encoded into single data, for WindowContext field.
Expand Down
8 changes: 6 additions & 2 deletions dom/base/nsGlobalWindowOuter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include "mozilla/dom/Timeout.h"
#include "mozilla/dom/TimeoutHandler.h"
#include "mozilla/dom/TimeoutManager.h"
#include "mozilla/dom/UserActivation.h"
#include "mozilla/dom/WindowContext.h"
#include "mozilla/dom/WindowFeatures.h" // WindowFeatures
#include "mozilla/dom/WindowProxyHolder.h"
Expand Down Expand Up @@ -6795,6 +6796,9 @@ nsresult nsGlobalWindowOuter::OpenInternal(

if (NS_FAILED(rv)) return rv;

UserActivation::Modifiers modifiers;
mBrowsingContext->GetUserActivationModifiersForPopup(&modifiers);

PopupBlocker::PopupControlState abuseLevel =
PopupBlocker::GetPopupControlState();
if (checkForPopup) {
Expand Down Expand Up @@ -6863,7 +6867,7 @@ nsresult nsGlobalWindowOuter::OpenInternal(
if (!aCalledNoScript) {
// We asserted at the top of this function that aNavigate is true for
// !aCalledNoScript.
rv = pwwatch->OpenWindow2(this, url, name, options,
rv = pwwatch->OpenWindow2(this, url, name, options, modifiers,
/* aCalledFromScript = */ true, aDialog,
aNavigate, argv, isPopupSpamWindow,
forceNoOpener, forceNoReferrer, wwPrintKind,
Expand All @@ -6883,7 +6887,7 @@ nsresult nsGlobalWindowOuter::OpenInternal(
nojsapi.emplace();
}

rv = pwwatch->OpenWindow2(this, url, name, options,
rv = pwwatch->OpenWindow2(this, url, name, options, modifiers,
/* aCalledFromScript = */ false, aDialog,
aNavigate, aExtraArgument, isPopupSpamWindow,
forceNoOpener, forceNoReferrer, wwPrintKind,
Expand Down
11 changes: 7 additions & 4 deletions dom/ipc/BrowserChild.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
#include "mozilla/dom/PointerEventHandler.h"
#include "mozilla/dom/SessionStoreUtils.h"
#include "mozilla/dom/SessionStoreChild.h"
#include "mozilla/dom/UserActivation.h"
#include "mozilla/dom/WindowGlobalChild.h"
#include "mozilla/dom/WindowProxyHolder.h"
#include "mozilla/gfx/CrossProcessPaint.h"
Expand Down Expand Up @@ -649,8 +650,10 @@ NS_IMETHODIMP
BrowserChild::ProvideWindow(nsIOpenWindowInfo* aOpenWindowInfo,
uint32_t aChromeFlags, bool aCalledFromJS,
nsIURI* aURI, const nsAString& aName,
const nsACString& aFeatures, bool aForceNoOpener,
bool aForceNoReferrer, bool aIsPopupRequested,
const nsACString& aFeatures,
const UserActivation::Modifiers& aModifiers,
bool aForceNoOpener, bool aForceNoReferrer,
bool aIsPopupRequested,
nsDocShellLoadState* aLoadState, bool* aWindowIsNew,
BrowsingContext** aReturn) {
*aReturn = nullptr;
Expand Down Expand Up @@ -682,8 +685,8 @@ BrowserChild::ProvideWindow(nsIOpenWindowInfo* aOpenWindowInfo,
ContentChild* cc = ContentChild::GetSingleton();
return cc->ProvideWindowCommon(
WrapNotNull(this), aOpenWindowInfo, aChromeFlags, aCalledFromJS, aURI,
aName, aFeatures, aForceNoOpener, aForceNoReferrer, aIsPopupRequested,
aLoadState, aWindowIsNew, aReturn);
aName, aFeatures, aModifiers, aForceNoOpener, aForceNoReferrer,
aIsPopupRequested, aLoadState, aWindowIsNew, aReturn);
}

void BrowserChild::DestroyWindow() {
Expand Down
10 changes: 6 additions & 4 deletions dom/ipc/ContentChild.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
#include "mozilla/dom/ServiceWorkerManager.h"
#include "mozilla/dom/SessionStorageManager.h"
#include "mozilla/dom/URLClassifierChild.h"
#include "mozilla/dom/UserActivation.h"
#include "mozilla/dom/WindowGlobalChild.h"
#include "mozilla/dom/WorkerDebugger.h"
#include "mozilla/dom/WorkerDebuggerManager.h"
Expand Down Expand Up @@ -964,7 +965,8 @@ static nsresult GetCreateWindowParams(nsIOpenWindowInfo* aOpenWindowInfo,
nsresult ContentChild::ProvideWindowCommon(
NotNull<BrowserChild*> aTabOpener, nsIOpenWindowInfo* aOpenWindowInfo,
uint32_t aChromeFlags, bool aCalledFromJS, nsIURI* aURI,
const nsAString& aName, const nsACString& aFeatures, bool aForceNoOpener,
const nsAString& aName, const nsACString& aFeatures,
const UserActivation::Modifiers& aModifiers, bool aForceNoOpener,
bool aForceNoReferrer, bool aIsPopupRequested,
nsDocShellLoadState* aLoadState, bool* aWindowIsNew,
BrowsingContext** aReturn) {
Expand Down Expand Up @@ -1032,8 +1034,8 @@ nsresult ContentChild::ProvideWindowCommon(
MOZ_DIAGNOSTIC_ASSERT(!nsContentUtils::IsSpecialName(name));

Unused << SendCreateWindowInDifferentProcess(
aTabOpener, parent, aChromeFlags, aCalledFromJS, aURI, features, name,
triggeringPrincipal, csp, referrerInfo,
aTabOpener, parent, aChromeFlags, aCalledFromJS, aURI, features,
aModifiers, name, triggeringPrincipal, csp, referrerInfo,
aOpenWindowInfo->GetOriginAttributes());

// We return NS_ERROR_ABORT, so that the caller knows that we've abandoned
Expand Down Expand Up @@ -1235,7 +1237,7 @@ nsresult ContentChild::ProvideWindowCommon(
SendCreateWindow(aTabOpener, parent, newChild, aChromeFlags, aCalledFromJS,
aOpenWindowInfo->GetIsForPrinting(),
aOpenWindowInfo->GetIsForWindowDotPrint(), aURI, features,
triggeringPrincipal, csp, referrerInfo,
aModifiers, triggeringPrincipal, csp, referrerInfo,
aOpenWindowInfo->GetOriginAttributes(), std::move(resolve),
std::move(reject));

Expand Down
4 changes: 3 additions & 1 deletion dom/ipc/ContentChild.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "mozilla/Atomics.h"
#include "mozilla/dom/BlobImpl.h"
#include "mozilla/dom/GetFilesHelper.h"
#include "mozilla/dom/UserActivation.h"
#include "mozilla/dom/PContentChild.h"
#include "mozilla/dom/ProcessActor.h"
#include "mozilla/dom/RemoteType.h"
Expand Down Expand Up @@ -106,7 +107,8 @@ class ContentChild final : public PContentChild,
MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult ProvideWindowCommon(
NotNull<BrowserChild*> aTabOpener, nsIOpenWindowInfo* aOpenWindowInfo,
uint32_t aChromeFlags, bool aCalledFromJS, nsIURI* aURI,
const nsAString& aName, const nsACString& aFeatures, bool aForceNoOpener,
const nsAString& aName, const nsACString& aFeatures,
const UserActivation::Modifiers& aModifiers, bool aForceNoOpener,
bool aForceNoReferrer, bool aIsPopupRequested,
nsDocShellLoadState* aLoadState, bool* aWindowIsNew,
BrowsingContext** aReturn);
Expand Down
23 changes: 13 additions & 10 deletions dom/ipc/ContentParent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@
#include "mozilla/dom/SessionHistoryEntry.h"
#include "mozilla/dom/SessionStorageManager.h"
#include "mozilla/dom/StorageIPC.h"
#include "mozilla/dom/UserActivation.h"
#include "mozilla/dom/URLClassifierParent.h"
#include "mozilla/dom/WindowGlobalParent.h"
#include "mozilla/dom/ipc/SharedMap.h"
Expand Down Expand Up @@ -5534,6 +5535,7 @@ mozilla::ipc::IPCResult ContentParent::CommonCreateWindow(
const uint32_t& aChromeFlags, const bool& aCalledFromJS,
const bool& aForPrinting, const bool& aForWindowDotPrint,
nsIURI* aURIToLoad, const nsACString& aFeatures,
const UserActivation::Modifiers& aModifiers,
BrowserParent* aNextRemoteBrowser, const nsAString& aName,
nsresult& aResult, nsCOMPtr<nsIRemoteTab>& aNewRemoteTab,
bool* aWindowIsNew, int32_t& aOpenLocation,
Expand Down Expand Up @@ -5694,8 +5696,8 @@ mozilla::ipc::IPCResult ContentParent::CommonCreateWindow(
features.Tokenize(aFeatures);

aResult = pwwatch->OpenWindowWithRemoteTab(
thisBrowserHost, features, aCalledFromJS, aParent.FullZoom(), openInfo,
getter_AddRefs(aNewRemoteTab));
thisBrowserHost, features, aModifiers, aCalledFromJS, aParent.FullZoom(),
openInfo, getter_AddRefs(aNewRemoteTab));
if (NS_WARN_IF(NS_FAILED(aResult))) {
return IPC_OK();
}
Expand Down Expand Up @@ -5760,9 +5762,9 @@ mozilla::ipc::IPCResult ContentParent::RecvCreateWindow(
PBrowserParent* aNewTab, const uint32_t& aChromeFlags,
const bool& aCalledFromJS, const bool& aForPrinting,
const bool& aForPrintPreview, nsIURI* aURIToLoad,
const nsACString& aFeatures, nsIPrincipal* aTriggeringPrincipal,
nsIContentSecurityPolicy* aCsp, nsIReferrerInfo* aReferrerInfo,
const OriginAttributes& aOriginAttributes,
const nsACString& aFeatures, const UserActivation::Modifiers& aModifiers,
nsIPrincipal* aTriggeringPrincipal, nsIContentSecurityPolicy* aCsp,
nsIReferrerInfo* aReferrerInfo, const OriginAttributes& aOriginAttributes,
CreateWindowResolver&& aResolve) {
if (!aTriggeringPrincipal) {
return IPC_FAIL(this, "No principal");
Expand Down Expand Up @@ -5845,7 +5847,7 @@ mozilla::ipc::IPCResult ContentParent::RecvCreateWindow(
int32_t openLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW;
mozilla::ipc::IPCResult ipcResult = CommonCreateWindow(
aThisTab, *parent, newBCOpenerId != 0, aChromeFlags, aCalledFromJS,
aForPrinting, aForPrintPreview, aURIToLoad, aFeatures, newTab,
aForPrinting, aForPrintPreview, aURIToLoad, aFeatures, aModifiers, newTab,
VoidString(), rv, newRemoteTab, &cwi.windowOpened(), openLocation,
aTriggeringPrincipal, aReferrerInfo, /* aLoadUri = */ false, aCsp,
aOriginAttributes);
Expand Down Expand Up @@ -5882,9 +5884,10 @@ mozilla::ipc::IPCResult ContentParent::RecvCreateWindow(
mozilla::ipc::IPCResult ContentParent::RecvCreateWindowInDifferentProcess(
PBrowserParent* aThisTab, const MaybeDiscarded<BrowsingContext>& aParent,
const uint32_t& aChromeFlags, const bool& aCalledFromJS, nsIURI* aURIToLoad,
const nsACString& aFeatures, const nsAString& aName,
nsIPrincipal* aTriggeringPrincipal, nsIContentSecurityPolicy* aCsp,
nsIReferrerInfo* aReferrerInfo, const OriginAttributes& aOriginAttributes) {
const nsACString& aFeatures, const UserActivation::Modifiers& aModifiers,
const nsAString& aName, nsIPrincipal* aTriggeringPrincipal,
nsIContentSecurityPolicy* aCsp, nsIReferrerInfo* aReferrerInfo,
const OriginAttributes& aOriginAttributes) {
MOZ_DIAGNOSTIC_ASSERT(!nsContentUtils::IsSpecialName(aName));

// Don't continue to try to create a new window if we've been fully discarded.
Expand Down Expand Up @@ -5926,7 +5929,7 @@ mozilla::ipc::IPCResult ContentParent::RecvCreateWindowInDifferentProcess(
mozilla::ipc::IPCResult ipcResult = CommonCreateWindow(
aThisTab, *parent, /* aSetOpener = */ false, aChromeFlags, aCalledFromJS,
/* aForPrinting = */ false,
/* aForPrintPreview = */ false, aURIToLoad, aFeatures,
/* aForPrintPreview = */ false, aURIToLoad, aFeatures, aModifiers,
/* aNextRemoteBrowser = */ nullptr, aName, rv, newRemoteTab, &windowIsNew,
openLocation, aTriggeringPrincipal, aReferrerInfo,
/* aLoadUri = */ true, aCsp, aOriginAttributes);
Expand Down
6 changes: 5 additions & 1 deletion dom/ipc/ContentParent.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "mozilla/dom/RemoteType.h"
#include "mozilla/dom/JSProcessActorParent.h"
#include "mozilla/dom/ProcessActor.h"
#include "mozilla/dom/UserActivation.h"
#include "mozilla/gfx/gfxVarReceiver.h"
#include "mozilla/gfx/GPUProcessListener.h"
#include "mozilla/ipc/BackgroundUtils.h"
Expand Down Expand Up @@ -492,14 +493,16 @@ class ContentParent final : public PContentParent,
const uint32_t& aChromeFlags, const bool& aCalledFromJS,
const bool& aForPrinting, const bool& aForWindowDotPrint,
nsIURI* aURIToLoad, const nsACString& aFeatures,
const UserActivation::Modifiers& aModifiers,
nsIPrincipal* aTriggeringPrincipal, nsIContentSecurityPolicy* aCsp,
nsIReferrerInfo* aReferrerInfo, const OriginAttributes& aOriginAttributes,
CreateWindowResolver&& aResolve);

mozilla::ipc::IPCResult RecvCreateWindowInDifferentProcess(
PBrowserParent* aThisTab, const MaybeDiscarded<BrowsingContext>& aParent,
const uint32_t& aChromeFlags, const bool& aCalledFromJS,
nsIURI* aURIToLoad, const nsACString& aFeatures, const nsAString& aName,
nsIURI* aURIToLoad, const nsACString& aFeatures,
const UserActivation::Modifiers& aModifiers, const nsAString& aName,
nsIPrincipal* aTriggeringPrincipal, nsIContentSecurityPolicy* aCsp,
nsIReferrerInfo* aReferrerInfo,
const OriginAttributes& aOriginAttributes);
Expand Down Expand Up @@ -717,6 +720,7 @@ class ContentParent final : public PContentParent,
const uint32_t& aChromeFlags, const bool& aCalledFromJS,
const bool& aForPrinting, const bool& aForWindowDotPrint,
nsIURI* aURIToLoad, const nsACString& aFeatures,
const UserActivation::Modifiers& aModifiers,
BrowserParent* aNextRemoteBrowser, const nsAString& aName,
nsresult& aResult, nsCOMPtr<nsIRemoteTab>& aNewRemoteTab,
bool* aWindowIsNew, int32_t& aOpenLocation,
Expand Down
3 changes: 3 additions & 0 deletions dom/ipc/PContent.ipdl
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ using mozilla::dom::Wireframe from "mozilla/dom/DocumentBinding.h";
using mozilla::PerfStats::MetricMask from "mozilla/PerfStats.h";
[RefCounted] using class nsIX509Cert from "nsIX509Cert.h";
using nsIDNSService::ResolverMode from "nsIDNSService.h";
using mozilla::dom::UserActivation::Modifiers from "mozilla/dom/UserActivation.h";

union ChromeRegistryItem
{
Expand Down Expand Up @@ -1528,6 +1529,7 @@ parent:
bool aForWindowDotPrint,
nullable nsIURI aURIToLoad,
nsCString aFeatures,
Modifiers aModifiers,
nullable nsIPrincipal aTriggeringPrincipal,
nullable nsIContentSecurityPolicy aCsp,
nullable nsIReferrerInfo aReferrerInfo,
Expand All @@ -1541,6 +1543,7 @@ parent:
bool aCalledFromJS,
nullable nsIURI aURIToLoad,
nsCString aFeatures,
Modifiers aModifiers,
nsString aName,
nullable nsIPrincipal aTriggeringPrincipal,
nullable nsIContentSecurityPolicy aCsp,
Expand Down
12 changes: 12 additions & 0 deletions ipc/glue/IPCMessageUtilsSpecializations.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "mozilla/Unused.h"
#include "mozilla/Vector.h"
#include "mozilla/dom/ipc/StructuredCloneData.h"
#include "mozilla/dom/UserActivation.h"
#include "nsCSSPropertyID.h"
#include "nsDebug.h"
#include "nsIContentPolicy.h"
Expand Down Expand Up @@ -824,6 +825,17 @@ struct ParamTraits<mozilla::net::LinkHeader> {
};
};

template <>
struct ParamTraits<mozilla::dom::UserActivation::Modifiers> {
typedef mozilla::dom::UserActivation::Modifiers paramType;
static void Write(MessageWriter* aWriter, const paramType& aParam) {
WriteParam(aWriter, aParam.mModifiers);
}
static bool Read(MessageReader* aReader, paramType* aResult) {
return ReadParam(aReader, &aResult->mModifiers);
};
};

} /* namespace IPC */

#endif /* __IPC_GLUE_IPCMESSAGEUTILSSPECIALIZATIONS_H__ */
8 changes: 8 additions & 0 deletions toolkit/components/windowcreator/nsIWindowProvider.idl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "nsISupports.idl"

%{ C++
#include "mozilla/dom/UserActivation.h"
class nsDocShellLoadState;
%}

Expand All @@ -22,6 +23,7 @@ interface mozIDOMWindowProxy;
interface nsIURI;
interface nsIOpenWindowInfo;
native nsDocShellLoadStatePtr(nsDocShellLoadState*);
[ref] native UserActivationModifiersRef(const mozilla::dom::UserActivation::Modifiers);

/**
* The nsIWindowProvider interface exists so that the window watcher's default
Expand Down Expand Up @@ -69,6 +71,11 @@ interface nsIWindowProvider : nsISupports
* the feature string to the window it returns in any way it sees fit.
* See the nsIWindowWatcher interface for details on feature strings.
*
* @param aModifiers The modifiers associated with the user activation,
* or UserActivation::Modifiers::None() if this is not initiated by
* user activation. This is used to determine where the new window is
* located (e.g. new foreground tab, new background tab, new window).
*
* @param aIsPopupRequested True if this window is opened by window.open
* with requesting a popup window. This doesn't necessarily mean
* whether the actual window is shown as minimal popup or not.
Expand Down Expand Up @@ -101,6 +108,7 @@ interface nsIWindowProvider : nsISupports
in nsIURI aURI,
in AString aName,
in AUTF8String aFeatures,
in UserActivationModifiersRef aModifiers,
in boolean aForceNoOpener,
in boolean aForceNoReferrer,
in boolean aIsPopupRequested,
Expand Down
12 changes: 12 additions & 0 deletions toolkit/components/windowwatcher/nsPIWindowWatcher.idl
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "nsISupports.idl"

%{ C++
#include "mozilla/dom/UserActivation.h"
class nsDocShellLoadState;
namespace mozilla::dom {
class WindowFeatures;
Expand All @@ -27,6 +28,7 @@ interface nsIRemoteTab;
interface nsIOpenWindowInfo;
native nsDocShellLoadStatePtr(nsDocShellLoadState*);
[ref] native WindowFeaturesRef(const mozilla::dom::WindowFeatures);
[ref] native UserActivationModifiersRef(const mozilla::dom::UserActivation::Modifiers);

[uuid(d162f9c4-19d5-4723-931f-f1e51bfa9f68)]
interface nsPIWindowWatcher : nsISupports
Expand Down Expand Up @@ -65,6 +67,10 @@ interface nsPIWindowWatcher : nsISupports
with this name already exists, the openWindow call may just load
aUrl in it (if aUrl is not null) and return it.
@param aFeatures window features from JS window.open. can be null.
@param aModifiers The modifiers associated with the user activation,
or UserActivation::Modifiers::None() if this is not initiated by
user activation. This is used to determine where the new window is
located (e.g. new foreground tab, new background tab, new window).
@param aCalledFromScript true if we were called from script.
@param aDialog use dialog defaults (see nsGlobalWindowOuter::OpenInternal)
@param aNavigate true if we should navigate the new window to the
Expand Down Expand Up @@ -95,6 +101,7 @@ interface nsPIWindowWatcher : nsISupports
[noscript]
BrowsingContext openWindow2(in mozIDOMWindowProxy aParent, in ACString aUrl,
in ACString aName, in ACString aFeatures,
in UserActivationModifiersRef aModifiers,
in boolean aCalledFromScript,
in boolean aDialog,
in boolean aNavigate,
Expand All @@ -114,6 +121,10 @@ interface nsPIWindowWatcher : nsISupports
* The nsIRemoteTab that is requesting the new window be opened.
* @param aFeatures
* Window features if called with window.open or similar.
* @param aModifiers
* The modifiers associated with the user activation, or
* UserActivation::Modifiers::None() if this is not initiated by
* user activation.
* @param aCalledFromJS
* True if called via window.open or similar.
* @param aOpenerFullZoom
Expand All @@ -128,6 +139,7 @@ interface nsPIWindowWatcher : nsISupports
*/
nsIRemoteTab openWindowWithRemoteTab(in nsIRemoteTab aOpeningTab,
in WindowFeaturesRef aFeatures,
in UserActivationModifiersRef aModifiers,
in boolean aCalledFromJS,
in float aOpenerFullZoom,
in nsIOpenWindowInfo aOpenWindowInfo);
Expand Down
Loading

0 comments on commit f38e7a2

Please sign in to comment.