--- a/dom/interfaces/base/nsITabChild.idl
+++ b/dom/interfaces/base/nsITabChild.idl
@@ -20,11 +20,14 @@ interface nsITabChild : nsISupports
[notxpcom] void sendRequestFocus(in boolean canFocus);
[notxpcom] void sendGetTabCount(out uint32_t tabCount);
[noscript, notxpcom] void enableDisableCommands(in AString action,
in CommandsArrayRef enabledCommands,
in CommandsArrayRef disabledCommands);
+ [notxpcom] void remoteSizeShellTo(in int32_t width, in int32_t height,
+ in int32_t shellItemWidth, in int32_t shellItemHeight);
+
readonly attribute uint64_t tabId;
};
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -153,16 +153,19 @@ parent:
parent:
/**
* When child sends this message, parent should move focus to
* the next or previous focusable element or document.
*/
async MoveFocus(bool forward, bool forDocumentNavigation);
+ async SizeShellTo(int32_t aWidth, int32_t aHeight,
+ int32_t aShellItemWidth, int32_t aShellItemHeight);
+
async Event(RemoteDOMEvent aEvent);
sync SyncMessage(nsString aMessage, ClonedMessageData aData,
CpowEntry[] aCpows, Principal aPrincipal)
returns (StructuredCloneData[] retval);
prio(high) sync RpcMessage(nsString aMessage, ClonedMessageData aData,
CpowEntry[] aCpows, Principal aPrincipal)
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -47,16 +47,17 @@
#include "mozilla/StaticPtr.h"
#include "mozilla/TextEvents.h"
#include "mozilla/TouchEvents.h"
#include "mozilla/unused.h"
#include "mozIApplication.h"
#include "nsContentUtils.h"
#include "nsDocShell.h"
#include "nsEmbedCID.h"
+#include "nsGlobalWindow.h"
#include <algorithm>
#ifdef MOZ_CRASHREPORTER
#include "nsExceptionHandler.h"
#endif
#include "nsFilePickerProxy.h"
#include "mozilla/dom/Element.h"
#include "nsIBaseWindow.h"
#include "nsIBrowserDOMWindow.h"
@@ -937,18 +938,38 @@ TabChild::SetChromeFlags(uint32_t aChrom
NS_IMETHODIMP
TabChild::DestroyBrowserWindow()
{
NS_WARNING("TabChild::DestroyBrowserWindow not supported in TabChild");
return NS_ERROR_NOT_IMPLEMENTED;
}
+static
+void SetOrReset(int32_t& aValue, int32_t aNew)
+{
+ aValue = aValue == aNew ? INT32_MIN : aNew;
+}
+
+void
+TabChild::RemoteSizeShellTo(int32_t aWidth, int32_t aHeight,
+ int32_t aShellItemWidth, int32_t aShellItemHeight)
+{
+ nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation());
+ nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(ourDocShell));
+ int32_t width, height;
+ docShellAsWin->GetSize(&width, &height);
+ SetOrReset(width, aWidth);
+ SetOrReset(height, aHeight);
+
+ Unused << SendSizeShellTo(width, height, aShellItemWidth, aShellItemHeight);
+}
+
NS_IMETHODIMP
-TabChild::SizeBrowserTo(int32_t aCX, int32_t aCY)
+TabChild::SizeBrowserTo(int32_t aWidth, int32_t aHeight)
{
NS_WARNING("TabChild::SizeBrowserTo not supported in TabChild");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
TabChild::ShowAsModal()
@@ -982,19 +1003,35 @@ TabChild::SetStatusWithContext(uint32_t
// mRemoteFrame is a good indicator.
if (mRemoteFrame)
SendSetStatus(aStatusType, nsString(aStatusText));
return NS_OK;
}
NS_IMETHODIMP
TabChild::SetDimensions(uint32_t aFlags, int32_t aX, int32_t aY,
- int32_t aCx, int32_t aCy)
+ int32_t aCx, int32_t aCy)
{
- Unused << PBrowserChild::SendSetDimensions(aFlags, aX, aY, aCx, aCy);
+ // The parent is in charge of the dimension changes. If JS code wants to
+ // change the dimensions (moveTo, screenX, etc.) we send a message to the
+ // parent about the new requested dimension, the parent does the resize/move
+ // then send a message to the child to update itself. For APIs like screenX
+ // this function is called with the current value for the non-changed values.
+ // In a series of calls like window.screenX = 10; window.screenY = 10; for
+ // the second call, since screenX is not yet updated we might accidentally
+ // reset back screeX to it's old value. To avoid this if a parameter did not
+ // change we want the parent to ignore its value. For that we will use a special
+ // value: INT32_MIN;
+ int32_t x, y, cx, cy;
+ GetDimensions(aFlags, &x, &y, &cx, &cy);
+ SetOrReset(x, aX);
+ SetOrReset(y, aY);
+ SetOrReset(cx, aCx);
+ SetOrReset(cy, aCy);
+ Unused << SendSetDimensions(aFlags, x, y, cx, cy);
return NS_OK;
}
NS_IMETHODIMP
TabChild::GetDimensions(uint32_t aFlags, int32_t* aX,
int32_t* aY, int32_t* aCx, int32_t* aCy)
{
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -614,16 +614,47 @@ TabParent::RecvMoveFocus(const bool& aFo
static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_BACKWARD));
nsCOMPtr<nsIDOMElement> frame = do_QueryInterface(mFrameElement);
fm->MoveFocus(nullptr, frame, type, nsIFocusManager::FLAG_BYKEY,
getter_AddRefs(dummy));
}
return true;
}
+static
+void SetOrIgnore(int32_t& aValue, int32_t aNew)
+{
+ aValue = INT32_MIN == aNew ? aValue : aNew;
+}
+
+bool
+TabParent::RecvSizeShellTo(const int32_t& aWidth, const int32_t& aHeight,
+ const int32_t& aShellItemWidth, const int32_t& aShellItemHeight)
+{
+ NS_ENSURE_TRUE(mFrameElement, true);
+
+ nsCOMPtr<nsIDocShell> docShell = mFrameElement->OwnerDoc()->GetDocShell();
+ NS_ENSURE_TRUE(docShell, true);
+
+ nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
+ nsresult rv = docShell->GetTreeOwner(getter_AddRefs(treeOwner));
+ NS_ENSURE_SUCCESS(rv, true);
+
+ int32_t width = mDimensions.width;
+ int32_t height = mDimensions.height;
+ SetOrIgnore(width, aWidth);
+ SetOrIgnore(height, aHeight);
+
+ nsCOMPtr<nsIXULWindow> xulWin(do_GetInterface(treeOwner));
+ NS_ENSURE_TRUE(xulWin, true);
+ xulWin->SizeShellToWithLimit(width, height, aShellItemWidth, aShellItemHeight);
+
+ return true;
+}
+
bool
TabParent::RecvEvent(const RemoteDOMEvent& aEvent)
{
nsCOMPtr<nsIDOMEvent> event = do_QueryInterface(aEvent.mEvent);
NS_ENSURE_TRUE(event, true);
nsCOMPtr<mozilla::dom::EventTarget> target = do_QueryInterface(mFrameElement);
NS_ENSURE_TRUE(target, true);
@@ -809,29 +840,41 @@ TabParent::RecvSetDimensions(const uint3
NS_ENSURE_TRUE(mFrameElement, true);
nsCOMPtr<nsIDocShell> docShell = mFrameElement->OwnerDoc()->GetDocShell();
NS_ENSURE_TRUE(docShell, true);
nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
docShell->GetTreeOwner(getter_AddRefs(treeOwner));
nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = do_QueryInterface(treeOwner);
NS_ENSURE_TRUE(treeOwnerAsWin, true);
+ // We only care about the parameters that actually changed, see more
+ // details in TabChild::SetDimensions.
+ int32_t x, y, cx, cy;
+ treeOwnerAsWin->GetPosition(&x, &y);
+ treeOwnerAsWin->GetSize(&cx, &cy);
+ SetOrIgnore(x, aX);
+ SetOrIgnore(y, aY);
+ SetOrIgnore(cx, aCx);
+ SetOrIgnore(cy, aCy);
+
if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION &&
aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER) {
- treeOwnerAsWin->SetPositionAndSize(aX, aY, aCx, aCy, true);
+ treeOwnerAsWin->SetPositionAndSize(x, y, cx, cy, true);
return true;
}
if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION) {
- treeOwnerAsWin->SetPosition(aX, aY);
+ treeOwnerAsWin->SetPosition(x, y);
+ mUpdatedDimensions = false;
+ UpdatePosition();
return true;
}
if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER) {
- treeOwnerAsWin->SetSize(aCx, aCy, true);
+ treeOwnerAsWin->SetSize(cx, cy, true);
return true;
}
MOZ_ASSERT(false, "Unknown flags!");
return false;
}
nsresult
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -156,16 +156,21 @@ public:
void AddWindowListeners();
void DidRefresh() override;
virtual bool RecvMoveFocus(const bool& aForward,
const bool& aForDocumentNavigation) override;
+ virtual bool RecvSizeShellTo(const int32_t& aWidth,
+ const int32_t& aHeight,
+ const int32_t& aShellItemWidth,
+ const int32_t& aShellItemHeight) override;
+
virtual bool RecvEvent(const RemoteDOMEvent& aEvent) override;
virtual bool RecvReplyKeyEvent(const WidgetKeyboardEvent& aEvent) override;
virtual bool
RecvDispatchAfterKeyboardEvent(const WidgetKeyboardEvent& aEvent) override;
virtual bool RecvBrowserFrameOpenWindow(PBrowserParent* aOpener,
--- a/dom/tests/mochitest/bugs/mochitest.ini
+++ b/dom/tests/mochitest/bugs/mochitest.ini
@@ -155,18 +155,18 @@ skip-if = (buildapp == 'b2g' && toolkit
[test_bug927901.html]
[test_devicemotion_multiple_listeners.html]
skip-if = toolkit == 'android' #bug 775227
[test_domparser_after_blank.html]
[test_errorReporting.html]
[test_onerror_message.html]
[test_protochains.html]
[test_resize_move_windows.html]
-skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #Windows can't change size and position on Android # b2g(Windows can't change size and position on B2G) b2g-debug(Windows can't change size and position on B2G) b2g-desktop(Windows can't change size and position on B2G)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' #Windows can't change size and position on Android # b2g(Windows can't change size and position on B2G) b2g-debug(Windows can't change size and position on B2G) b2g-desktop(Windows can't change size and position on B2G)
[test_sizetocontent_clamp.html]
-skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #Windows can't change size on Android # b2g(Windows can't change size on B2G) b2g-debug(Windows can't change size on B2G) b2g-desktop(Windows can't change size on B2G)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' #Windows can't change size on Android # b2g(Windows can't change size on B2G) b2g-debug(Windows can't change size on B2G) b2g-desktop(Windows can't change size on B2G)
[test_toJSON.html]
[test_window_bar.html]
skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android'
[test_bug1022869.html]
[test_bug1112040.html]
[test_bug1160342_marquee.html]
[test_bug1171215.html]
--- a/dom/tests/mochitest/bugs/test_resize_move_windows.html
+++ b/dom/tests/mochitest/bugs/test_resize_move_windows.html
@@ -232,95 +232,86 @@ function checkChangeIsEnabled(aWindow, a
function outerChangeCondition() {
return aWindow.outerWidth != oWidth && aWindow.outerHeight != oHeight;
}
function outerChangeTest() {
isnot(aWindow.outerWidth, oWidth, "Window outerWidth should have changed");
isnot(aWindow.outerHeight, oHeight, "Window outerHeight should have changed");
-
- aWindow.outerWidth = oWidth;
- aWindow.outerHeight = oHeight;
}
/**
* Size checks.
*/
prevWidth = aWindow.innerWidth;
prevHeight = aWindow.innerHeight;
-
aWindow.innerWidth = getNewWidth(aWindow);
aWindow.innerHeight = getNewHeight(aWindow);
hitEventLoop(sizeChangeCondition, sizeChangeTest, hits)
.then(function() {
aWindow.resizeTo(getNewWidth(aWindow), getNewHeight(aWindow));
- })
- .then(function() {
return hitEventLoop(sizeChangeCondition, sizeChangeTest, hits);
})
.then(function () {
aWindow.resizeBy(getNewWidth(aWindow) - aWindow.innerWidth,
getNewHeight(aWindow) - aWindow.innerHeight);
- })
- .then(function() {
return hitEventLoop(sizeChangeCondition, sizeChangeTest, hits);
})
- .then(function () {
- prevWidth = aWindow.innerWidth = getNewWidth(aWindow);
- prevHeight = aWindow.innerHeight = getNewHeight(aWindow);
+ .then(function() {
aWindow.sizeToContent();
- })
- .then(function() {
- hitEventLoop(sizeChangeCondition, sizeChangeTest, hits);
+ return hitEventLoop(sizeChangeCondition, sizeChangeTest, hits);
})
.then(function() {
/**
* Position checks.
*/
prevX = aWindow.screenX;
prevY = aWindow.screenY;
aWindow.screenX = getNewX(aWindow);
aWindow.screenY = getNewY(aWindow);
- })
- .then(function() {
return hitEventLoop(posChangeCondition, posChangeTest, hits);
})
.then(function() {
prevX = aWindow.screenX;
prevY = aWindow.screenY;
aWindow.moveTo(getNewX(aWindow), getNewY(aWindow));
- })
- .then(function() {
return hitEventLoop(posChangeCondition, posChangeTest, hits);
})
.then(function() {
prevX = aWindow.screenX;
prevY = aWindow.screenY;
aWindow.moveBy(getNewX(aWindow) - aWindow.screenX,
getNewY(aWindow) - aWindow.screenY);
- })
- .then(function() {
return hitEventLoop(posChangeCondition, posChangeTest, hits);
})
.then(function() {
/**
* Outer width/height checks.
*/
oWidth = aWindow.outerWidth;
oHeight = aWindow.outerHeight;
aWindow.outerWidth = oWidth * 2;
aWindow.outerHeight = oHeight * 2;
+ return hitEventLoop(outerChangeCondition, outerChangeTest, hits);
})
.then(function() {
+ let origWidth = oWidth;
+ let origHeight = oHeight;
+
+ oWidth = aWindow.outerWidth;
+ oHeight = aWindow.outerHeight;
+
+ aWindow.outerWidth = origWidth;
+ aWindow.outerHeight = origHeight;
return hitEventLoop(outerChangeCondition, outerChangeTest, hits);
})
.then(aNext);
}
SpecialPowers.pushPrefEnv({"set": [["dom.disable_window_move_resize", false]]}, function() {
SimpleTest.waitForFocus(function() {
if (screen.width <= 200 || screen.height <= 200) {
--- a/dom/tests/mochitest/bugs/test_sizetocontent_clamp.html
+++ b/dom/tests/mochitest/bugs/test_sizetocontent_clamp.html
@@ -30,35 +30,34 @@ var epsilon = navigator.platform.indexO
// Windows 8 has a minimum 122 pixel inner window width due to
// outer window chrome.
var isWin8 = (navigator.userAgent.indexOf("Windows NT 6.2") != -1);
var innerWidthMin = (isWin8 ? 120 : 100);
var innerWidthMax = (isWin8 ? 125 : 100);
+var isExecuted = false;
+
function test() {
var w = window.open('data:text/html,null', null, 'width=300,height=300');
- var nbResize = 0;
SimpleTest.waitForFocus(function() {
w.onresize = function() {
- nbResize++;
- if (nbResize == 1) {
+ if (w.innerWidth > 300 - epsilon || isExecuted) {
return;
}
+ isExecuted = true;
+
ok(w.innerWidth + epsilon >= innerWidthMin && w.innerWidth - epsilon <= innerWidthMax,
- "innerWidth should be between " + innerWidthMin + " and " + innerWidthMax);
+ "innerWidth should be between " + innerWidthMin + " and " + innerWidthMax + " but it was: " + w.innerWidth);
ok(w.innerHeight + epsilon >= 100 && w.innerHeight - epsilon <= 100,
- "innerHeight should be around 100");
-
- // It's not clear why 2 events are coming...
- is(nbResize, 2, "We should get 2 events.");
+ "innerHeight should be around 100" + " but it was: " + w.innerHeight);
w.close();
SimpleTest.waitForFocus(function() {
SimpleTest.finish();
});
};
w.sizeToContent();
--- a/embedding/browser/nsDocShellTreeOwner.cpp
+++ b/embedding/browser/nsDocShellTreeOwner.cpp
@@ -52,16 +52,17 @@
#include "nsIStringBundle.h"
#include "nsPIDOMWindow.h"
#include "nsPIWindowRoot.h"
#include "nsIDOMWindowCollection.h"
#include "nsIWindowWatcher.h"
#include "nsPIWindowWatcher.h"
#include "nsIPrompt.h"
#include "nsITabParent.h"
+#include "nsITabChild.h"
#include "nsRect.h"
#include "nsIWebBrowserChromeFocus.h"
#include "nsIContent.h"
#include "imgIContainer.h"
#include "nsContextMenuInfo.h"
#include "nsPresContext.h"
#include "nsViewManager.h"
#include "nsView.h"
@@ -450,16 +451,30 @@ nsDocShellTreeOwner::SizeShellTo(nsIDocS
NS_ENSURE_STATE(mTreeOwner || webBrowserChrome);
if (mTreeOwner) {
return mTreeOwner->SizeShellTo(aShellItem, aCX, aCY);
}
if (aShellItem == mWebBrowser->mDocShell) {
+ nsCOMPtr<nsITabChild> tabChild = do_QueryInterface(webBrowserChrome);
+ if (tabChild) {
+ // The XUL window to resize is in the parent process, but there we
+ // won't be able to get aShellItem to do the hack in nsXULWindow::SizeShellTo,
+ // so let's send the width and height of aShellItem too.
+ nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(aShellItem));
+ NS_ENSURE_TRUE(shellAsWin, NS_ERROR_FAILURE);
+
+ int32_t width = 0;
+ int32_t height = 0;
+ shellAsWin->GetSize(&width, &height);
+ tabChild->RemoteSizeShellTo(aCX, aCY, width, height);
+ return NS_OK;
+ }
return webBrowserChrome->SizeBrowserTo(aCX, aCY);
}
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(aShellItem));
NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
nsCOMPtr<nsIDOMDocument> domDocument;
webNav->GetDocument(getter_AddRefs(domDocument));
@@ -573,17 +588,18 @@ nsDocShellTreeOwner::GetDevicePixelsPerD
*aScale = 1.0;
return NS_OK;
}
NS_IMETHODIMP
nsDocShellTreeOwner::SetPositionDesktopPix(int32_t aX, int32_t aY)
{
if (mWebBrowser) {
- return mWebBrowser->SetPositionDesktopPix(aX, aY);
+ nsresult rv = mWebBrowser->SetPositionDesktopPix(aX, aY);
+ NS_ENSURE_SUCCESS(rv, rv);
}
double scale = 1.0;
GetDevicePixelsPerDesktopPixel(&scale);
return SetPosition(NSToIntRound(aX * scale), NSToIntRound(aY * scale));
}
NS_IMETHODIMP
--- a/xpfe/appshell/nsIXULWindow.idl
+++ b/xpfe/appshell/nsIXULWindow.idl
@@ -13,17 +13,17 @@
* notification through the global observer service.
*/
interface nsIDocShell;
interface nsIDocShellTreeItem;
interface nsIXULBrowserWindow;
interface nsITabParent;
-[scriptable, uuid(d6d7a014-e28d-4c9d-8727-1cf6d870619b)]
+[scriptable, uuid(0d2760ac-636e-4b80-a8ec-11385bc47f0e)]
interface nsIXULWindow : nsISupports
{
/**
* The docshell owning the XUL for this window.
*/
readonly attribute nsIDocShell docShell;
/**
@@ -129,9 +129,12 @@ interface nsIXULWindow : nsISupports
/**
* Back-door method to force application of chrome flags at a particular
* time. Do NOT call this unless you know what you're doing! In particular,
* calling this when this XUL window doesn't yet have a document in its
* docshell could cause problems.
*/
[noscript] void applyChromeFlags();
+
+ [noscript, notxpcom] void sizeShellToWithLimit(in int32_t aCx, in int32_t aCy,
+ in int32_t shellItemCx, in int32_t shellItemCy);
};
--- a/xpfe/appshell/nsXULWindow.cpp
+++ b/xpfe/appshell/nsXULWindow.cpp
@@ -1810,32 +1810,17 @@ NS_IMETHODIMP nsXULWindow::SizeShellTo(n
nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(aShellItem));
NS_ENSURE_TRUE(shellAsWin, NS_ERROR_FAILURE);
int32_t width = 0;
int32_t height = 0;
shellAsWin->GetSize(&width, &height);
- int32_t widthDelta = aCX - width;
- int32_t heightDelta = aCY - height;
-
- if (widthDelta || heightDelta) {
- int32_t winCX = 0;
- int32_t winCY = 0;
-
- GetSize(&winCX, &winCY);
- // There's no point in trying to make the window smaller than the
- // desired docshell size --- that's not likely to work. This whole
- // function assumes that the outer docshell is adding some constant
- // "border" chrome to aShellItem.
- winCX = std::max(winCX + widthDelta, aCX);
- winCY = std::max(winCY + heightDelta, aCY);
- SetSize(winCX, winCY, true);
- }
+ SizeShellToWithLimit(aCX, aCY, width, height);
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::ExitModalLoop(nsresult aStatus)
{
if (mContinueModalLoop)
EnableParent(true);
@@ -2191,16 +2176,37 @@ NS_IMETHODIMP nsXULWindow::GetXULBrowser
}
NS_IMETHODIMP nsXULWindow::SetXULBrowserWindow(nsIXULBrowserWindow * aXULBrowserWindow)
{
mXULBrowserWindow = aXULBrowserWindow;
return NS_OK;
}
+void nsXULWindow::SizeShellToWithLimit(int32_t aCX, int32_t aCY,
+ int32_t shellItemCx, int32_t shellItemCy)
+{
+ int32_t widthDelta = aCX - shellItemCx;
+ int32_t heightDelta = aCY - shellItemCy;
+
+ if (widthDelta || heightDelta) {
+ int32_t winCX = 0;
+ int32_t winCY = 0;
+
+ GetSize(&winCX, &winCY);
+ // There's no point in trying to make the window smaller than the
+ // desired docshell size --- that's not likely to work. This whole
+ // function assumes that the outer docshell is adding some constant
+ // "border" chrome to aShellItem.
+ winCX = std::max(winCX + widthDelta, aCX);
+ winCY = std::max(winCY + heightDelta, aCY);
+ SetSize(winCX, winCY, true);
+ }
+}
+
//*****************************************************************************
//*** nsContentShellInfo: Object Management
//*****************************************************************************
nsContentShellInfo::nsContentShellInfo(const nsAString& aID,
nsIWeakReference* aContentShell)
: id(aID),
child(aContentShell)